From 5d1d1f1e8143e5d8b8e6743f50e88a313bc0a448 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sat, 23 Sep 2017 01:38:01 +0200 Subject: [PATCH 0001/1899] Adding JUnit reports. --- run-tests.bat | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 207efed28..7e792bbd6 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -28,18 +28,23 @@ nvm use 8.5.0 call npm install || goto :error +SET JUNIT_REPORT_STACK=1 +SET FAILED=0 + for %%v in (4.8.4 6.11.3 7.9.0 8.5.0) do ( nvm install %%v nvm use %%v node -e "console.log(process.versions)" - call .\node_modules\.bin\gulp clean.all || goto :error - call .\node_modules\.bin\gulp setup.windows || goto :error - call .\node_modules\.bin\gulp native.test || goto :error -) + SET JUNIT_REPORT_PATH=reports/node%%v/ -if %errorlevel% neq 0 exit /b %errorlevel% + call .\node_modules\.bin\gulp clean.all || SET FAILED=1 + call .\node_modules\.bin\gulp setup.windows || SET FAILED=1 + call .\node_modules\.bin\gulp native.test || SET FAILED=1 +) +if %FAILED% neq 0 exit /b 1 +node merge_kokoro_logs.js goto :EOF :error From 81acd929b771885a0394396c66ce8642b58ff451 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 28 Sep 2017 16:13:07 -0700 Subject: [PATCH 0002/1899] Separate out packages. Upgrade new protobufjs package to Protobuf.js 6.8 --- .gitignore | 3 + packages/grpc-js/index.js | 21 +++ packages/grpc-js/package.json | 23 +++ packages/grpc-native/index.js | 22 +++ packages/grpc-native/package.json | 23 +++ packages/grpc-protobufjs/index.js | 139 ++++++++++++++ packages/grpc-protobufjs/package.json | 22 +++ .../grpc-protobufjs/protobuf_js_5_common.js | 177 ++++++++++++++++++ .../grpc-protobufjs/protobuf_js_6_common.js | 166 ++++++++++++++++ packages/grpc-surface/index.js | 147 +++++++++++++++ packages/grpc-surface/package.json | 21 +++ 11 files changed, 764 insertions(+) create mode 100644 packages/grpc-js/index.js create mode 100644 packages/grpc-js/package.json create mode 100644 packages/grpc-native/index.js create mode 100644 packages/grpc-native/package.json create mode 100644 packages/grpc-protobufjs/index.js create mode 100644 packages/grpc-protobufjs/package.json create mode 100644 packages/grpc-protobufjs/protobuf_js_5_common.js create mode 100644 packages/grpc-protobufjs/protobuf_js_6_common.js create mode 100644 packages/grpc-surface/index.js create mode 100644 packages/grpc-surface/package.json diff --git a/.gitignore b/.gitignore index 583683394..4dc6fc88b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ npm-debug.log yarn-error.log yarn.lock +# Emacs temp files *~ +\#*\# +.\#* packages/grpc-native-core/src/node/ \ No newline at end of file diff --git a/packages/grpc-js/index.js b/packages/grpc-js/index.js new file mode 100644 index 000000000..6079b1b13 --- /dev/null +++ b/packages/grpc-js/index.js @@ -0,0 +1,21 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +module.exports = require('grpc-surface')(require('grpc-js-core')); diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json new file mode 100644 index 000000000..248e84609 --- /dev/null +++ b/packages/grpc-js/package.json @@ -0,0 +1,23 @@ +{ + "name": "grpc-js", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "homepage": "https://grpc.io", + "dependencies": { + "grpc-js-core": "^0.1.0", + "grpc-surface": "^1.0.0" + } +} diff --git a/packages/grpc-native/index.js b/packages/grpc-native/index.js new file mode 100644 index 000000000..86266efed --- /dev/null +++ b/packages/grpc-native/index.js @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +// TODO(mlumish): This should eventually be grpc-native-core instead of grpc +module.exports = require('grpc-surface')(require('grpc')); diff --git a/packages/grpc-native/package.json b/packages/grpc-native/package.json new file mode 100644 index 000000000..7637603ce --- /dev/null +++ b/packages/grpc-native/package.json @@ -0,0 +1,23 @@ +{ + "name": "grpc-native", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "homepage": "https://grpc.io", + "dependencies": { + "grpc": "^1.6.0", + "grpc-surface": "^1.0.0" + } +} diff --git a/packages/grpc-protobufjs/index.js b/packages/grpc-protobufjs/index.js new file mode 100644 index 000000000..5e7ede99c --- /dev/null +++ b/packages/grpc-protobufjs/index.js @@ -0,0 +1,139 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var path = require('path'); + +var _ = require('lodash'); +var ProtoBuf = require('protobufjs'); + +module.exports = function(grpc) { + + let exports = {}; + + const protobuf_js_5_common = require('protobuf_js_5_common')(grpc); + const protobuf_js_6_common = require('protobuf_js_6_common')(grpc); + + /** + * Default options for loading proto files into gRPC + * @alias grpc~defaultLoadOptions + */ + const defaultGrpcOptions = { + convertFieldsToCamelCase: false, + binaryAsBase64: false, + longsAsStrings: true, + enumsAsStrings: true + }; + + /** + * Load a ProtoBuf.js object as a gRPC object. The options object can provide + * the following options: + * - binaryAsBase64: deserialize bytes values as base64 strings instead of + * Buffers. Defaults to false + * - longsAsStrings: deserialize long values as strings instead of objects. + * Defaults to true + * - enumsAsStrings: deserialize enum values as strings instead of numbers. + * Defaults to true + * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6 + * respectively indicate that an object from the corresponding version of + * ProtoBuf.js is provided in the value argument. If the option is 'detect', + * gRPC will guess what the version is based on the structure of the value. + * Defaults to 'detect'. + * @param {Object} value The ProtoBuf.js reflection object to load + * @param {Object=} options Options to apply to the loaded file + * @return {Object} The resulting gRPC object + */ + exports.loadObject = function loadObject(value, options) { + options = _.defaults(options, defaultGrpcOptions); + options = _.defaults(options, {'protobufjsVersion': 'detect'}); + var protobufjsVersion; + if (options.protobufjsVersion === 'detect') { + if (protobuf_js_6_common.isProbablyProtobufJs6(value)) { + protobufjsVersion = 6; + } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) { + protobufjsVersion = 5; + } else { + var error_message = 'Could not detect ProtoBuf.js version. Please ' + + 'specify the version number with the "protobufjs_version" option'; + throw new Error(error_message); + } + } else { + protobufjsVersion = options.protobufjsVersion; + } + switch (protobufjsVersion) { + case 6: return protobuf_js_6_common.loadObject(value, options); + case 5: return protobuf_js_5_common.loadObject(value, options); + default: + throw new Error('Unrecognized protobufjsVersion', protobufjsVersion); + } + }; + + var loadObject = exports.loadObject; + + function applyProtoRoot(filename, root) { + if (_.isString(filename)) { + return filename; + } + filename.root = path.resolve(filename.root) + '/'; + root.resolvePath = function(originPath, importPath, alreadyNormalized) { + return ProtoBuf.util.path.resolve(filename.root, + importPath, + alreadyNormalized); + }; + return filename.file; + } + + /** + * Load a gRPC object from a .proto file. The options object can provide the + * following options: + * - convertFieldsToCamelCase: Load this file with field names in camel case + * instead of their original case + * - binaryAsBase64: deserialize bytes values as base64 strings instead of + * Buffers. Defaults to false + * - longsAsStrings: deserialize long values as strings instead of objects. + * Defaults to true + * - enumsAsStrings: deserialize enum values as strings instead of numbers. + * Defaults to true + * - deprecatedArgumentOrder: Use the beta method argument order for client + * methods, with optional arguments after the callback. Defaults to false. + * This option is only a temporary stopgap measure to smooth an API breakage. + * It is deprecated, and new code should not use it. + * @param {string|{root: string, file: string}} filename The file to load + * @param {string=} format The file format to expect. Must be either 'proto' or + * 'json'. Defaults to 'proto' + * @param {Object=} options Options to apply to the loaded file + * @return {Object} The resulting gRPC object + */ + exports.load = function load(filename, format, options) { + /* Note: format is currently unused, because the API for loading a proto + file or a JSON file is identical in Protobuf.js 6. In the future, there is + still the possibility of adding other formats that would be loaded + differently */ + options = _.defaults(options, defaultGrpcOptions); + options.protobufjs_version = 6; + var root = new ProtoBuf.Root(); + var parse_options = {keepCase: !options.convertFieldsToCamelCase}; + return loadObject(root.loadSync(applyProtoRoot(filename, root), + parse_options), + options); + }; + + return exports; + +}; diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json new file mode 100644 index 000000000..456fdf599 --- /dev/null +++ b/packages/grpc-protobufjs/package.json @@ -0,0 +1,22 @@ +{ + "name": "grpc-protobufjs", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "dependencies": { + "lodash": "^4.17.4", + "protobufjs": "~6.8.0" + } +} diff --git a/packages/grpc-protobufjs/protobuf_js_5_common.js b/packages/grpc-protobufjs/protobuf_js_5_common.js new file mode 100644 index 000000000..141852f6e --- /dev/null +++ b/packages/grpc-protobufjs/protobuf_js_5_common.js @@ -0,0 +1,177 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * @module + * @private + */ + +'use strict'; + +var _ = require('lodash'); + +module.exports = function(grpc) { + + let exports = {}; + + /** + * Get a function that deserializes a specific type of protobuf. + * @param {function()} cls The constructor of the message type to deserialize + * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings + * instead of Buffers. Defaults to false + * @param {bool=} longsAsStrings Deserialize long values as strings instead of + * objects. Defaults to true + * @return {function(Buffer):cls} The deserialization function + */ + exports.deserializeCls = function deserializeCls(cls, options) { + /** + * Deserialize a buffer to a message object + * @param {Buffer} arg_buf The buffer to deserialize + * @return {cls} The resulting object + */ + return function deserialize(arg_buf) { + // Convert to a native object with binary fields as Buffers (first argument) + // and longs as strings (second argument) + return cls.decode(arg_buf).toRaw(options.binaryAsBase64, + options.longsAsStrings); + }; + }; + + var deserializeCls = exports.deserializeCls; + + /** + * Get a function that serializes objects to a buffer by protobuf class. + * @param {function()} Cls The constructor of the message type to serialize + * @return {function(Cls):Buffer} The serialization function + */ + exports.serializeCls = function serializeCls(Cls) { + /** + * Serialize an object to a Buffer + * @param {Object} arg The object to serialize + * @return {Buffer} The serialized object + */ + return function serialize(arg) { + return new Buffer(new Cls(arg).encode().toBuffer()); + }; + }; + + var serializeCls = exports.serializeCls; + + /** + * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. + * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of + * @return {string} The fully qualified name of the value + */ + exports.fullyQualifiedName = function fullyQualifiedName(value) { + if (value === null || value === undefined) { + return ''; + } + var name = value.name; + var parent_name = fullyQualifiedName(value.parent); + if (parent_name !== '') { + name = parent_name + '.' + name; + } + return name; + }; + + var fullyQualifiedName = exports.fullyQualifiedName; + + /** + * Return a map from method names to method attributes for the service. + * @param {ProtoBuf.Reflect.Service} service The service to get attributes for + * @param {Object=} options Options to apply to these attributes + * @return {Object} The attributes map + */ + exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, + options) { + var prefix = '/' + fullyQualifiedName(service) + '/'; + var binaryAsBase64, longsAsStrings; + if (options) { + binaryAsBase64 = options.binaryAsBase64; + longsAsStrings = options.longsAsStrings; + } + /* This slightly awkward construction is used to make sure we only use + lodash@3.10.1-compatible functions. A previous version used + _.fromPairs, which would be cleaner, but was introduced in lodash + version 4 */ + return _.zipObject(_.map(service.children, function(method) { + return _.camelCase(method.name); + }), _.map(service.children, function(method) { + return { + originalName: method.name, + path: prefix + method.name, + requestStream: method.requestStream, + responseStream: method.responseStream, + requestType: method.resolvedRequestType, + responseType: method.resolvedResponseType, + requestSerialize: serializeCls(method.resolvedRequestType.build()), + requestDeserialize: deserializeCls(method.resolvedRequestType.build(), + options), + responseSerialize: serializeCls(method.resolvedResponseType.build()), + responseDeserialize: deserializeCls(method.resolvedResponseType.build(), + options) + }; + })); + }; + + var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; + + /** + * Load a gRPC object from an existing ProtoBuf.Reflect object. + * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. + * @param {Object=} options Options to apply to the loaded object + * @return {Object} The resulting gRPC object + */ + exports.loadObject = function loadObject(value, options) { + var result = {}; + if (!value) { + return value; + } + if (value.hasOwnProperty('ns')) { + return loadObject(value.ns, options); + } + if (value.className === 'Namespace') { + _.each(value.children, function(child) { + result[child.name] = loadObject(child, options); + }); + return result; + } else if (value.className === 'Service') { + return grpc.makeGenericClientConstructor(getProtobufServiceAttrs(value, options), + options); + } else if (value.className === 'Message' || value.className === 'Enum') { + return value.build(); + } else { + return value; + } + }; + + /** + * The primary purpose of this method is to distinguish between reflection + * objects from different versions of ProtoBuf.js. This is just a heuristic, + * checking for properties that are (currently) specific to this version of + * ProtoBuf.js + * @param {Object} obj The object to check + * @return {boolean} Whether the object appears to be a Protobuf.js 5 + * ReflectionObject + */ + exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) { + return _.isArray(obj.children) && (typeof obj.build === 'function'); + }; + + return exports; +}; diff --git a/packages/grpc-protobufjs/protobuf_js_6_common.js b/packages/grpc-protobufjs/protobuf_js_6_common.js new file mode 100644 index 000000000..76241994b --- /dev/null +++ b/packages/grpc-protobufjs/protobuf_js_6_common.js @@ -0,0 +1,166 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * @module + * @private + */ + +'use strict'; + +var _ = require('lodash'); + +module.exports = function(grpc) { + + let exports = {}; + + /** + * Get a function that deserializes a specific type of protobuf. + * @param {function()} cls The constructor of the message type to deserialize + * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings + * instead of Buffers. Defaults to false + * @param {bool=} longsAsStrings Deserialize long values as strings instead of + * objects. Defaults to true + * @return {function(Buffer):cls} The deserialization function + */ + exports.deserializeCls = function deserializeCls(cls, options) { + var conversion_options = { + defaults: true, + bytes: options.binaryAsBase64 ? String : Buffer, + longs: options.longsAsStrings ? String : null, + enums: options.enumsAsStrings ? String : null, + oneofs: true + }; + /** + * Deserialize a buffer to a message object + * @param {Buffer} arg_buf The buffer to deserialize + * @return {cls} The resulting object + */ + return function deserialize(arg_buf) { + return cls.toObject(cls.decode(arg_buf), conversion_options); + }; + }; + + var deserializeCls = exports.deserializeCls; + + /** + * Get a function that serializes objects to a buffer by protobuf class. + * @param {function()} Cls The constructor of the message type to serialize + * @return {function(Cls):Buffer} The serialization function + */ + exports.serializeCls = function serializeCls(cls) { + /** + * Serialize an object to a Buffer + * @param {Object} arg The object to serialize + * @return {Buffer} The serialized object + */ + return function serialize(arg) { + var message = cls.fromObject(arg); + return cls.encode(message).finish(); + }; + }; + + var serializeCls = exports.serializeCls; + + /** + * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. + * @param {ProtoBuf.ReflectionObject} value The value to get the name of + * @return {string} The fully qualified name of the value + */ + exports.fullyQualifiedName = function fullyQualifiedName(value) { + if (value === null || value === undefined) { + return ''; + } + var name = value.name; + var parent_fqn = fullyQualifiedName(value.parent); + if (parent_fqn !== '') { + name = parent_fqn + '.' + name; + } + return name; + }; + + var fullyQualifiedName = exports.fullyQualifiedName; + + /** + * Return a map from method names to method attributes for the service. + * @param {ProtoBuf.Service} service The service to get attributes for + * @param {Object=} options Options to apply to these attributes + * @return {Object} The attributes map + */ + exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, + options) { + var prefix = '/' + fullyQualifiedName(service) + '/'; + service.resolveAll(); + return _.zipObject(_.map(service.methods, function(method) { + return _.camelCase(method.name); + }), _.map(service.methods, function(method) { + return { + originalName: method.name, + path: prefix + method.name, + requestStream: !!method.requestStream, + responseStream: !!method.responseStream, + requestType: method.resolvedRequestType, + responseType: method.resolvedResponseType, + requestSerialize: serializeCls(method.resolvedRequestType), + requestDeserialize: deserializeCls(method.resolvedRequestType, options), + responseSerialize: serializeCls(method.resolvedResponseType), + responseDeserialize: deserializeCls(method.resolvedResponseType, options) + }; + })); + }; + + var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; + + exports.loadObject = function loadObject(value, options) { + var result = {}; + if (!value) { + return value; + } + if (value.hasOwnProperty('methods')) { + // It's a service object + var service_attrs = getProtobufServiceAttrs(value, options); + return grpc..makeGenericClientConstructor(service_attrs); + } + + if (value.hasOwnProperty('nested')) { + // It's a namespace or root object + _.each(value.nested, function(nested, name) { + result[name] = loadObject(nested, options); + }); + return result; + } + + // Otherwise, it's not something we need to change + return value; + }; + + /** + * The primary purpose of this method is to distinguish between reflection + * objects from different versions of ProtoBuf.js. This is just a heuristic, + * checking for properties that are (currently) specific to this version of + * ProtoBuf.js + * @param {Object} obj The object to check + * @return {boolean} Whether the object appears to be a Protobuf.js 6 + * ReflectionObject + */ + exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) { + return (typeof obj.root === 'object') && (typeof obj.resolve === 'function'); + }; + + return exports; +}; diff --git a/packages/grpc-surface/index.js b/packages/grpc-surface/index.js new file mode 100644 index 000000000..6c9cb6a17 --- /dev/null +++ b/packages/grpc-surface/index.js @@ -0,0 +1,147 @@ +/** + * @license + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +const util = require(util); + +const _ = require('lodash'); + +module.exports = function(grpc) { + + let exports = {}; + + const Client = grpc.Client; + + function getDefaultValues(metadata, options) { + var res = {}; + res.metadata = metadata || new grpc.Metadata(); + res.options = options || {}; + return res; + } + + /** + * Map with wrappers for each type of requester function to make it use the old + * argument order with optional arguments after the callback. + * @access private + */ + var deprecated_request_wrap = { + unary: function(makeUnaryRequest) { + return function makeWrappedUnaryRequest(argument, callback, + metadata, options) { + /* jshint validthis: true */ + var opt_args = getDefaultValues(metadata, metadata); + return makeUnaryRequest.call(this, argument, opt_args.metadata, + opt_args.options, callback); + }; + }, + client_stream: function(makeServerStreamRequest) { + return function makeWrappedClientStreamRequest(callback, metadata, + options) { + /* jshint validthis: true */ + var opt_args = getDefaultValues(metadata, options); + return makeServerStreamRequest.call(this, opt_args.metadata, + opt_args.options, callback); + }; + }, + server_stream: _.identity, + bidi: _.identity + }; + + /** + * Map with short names for each of the requester maker functions. Used in + * makeClientConstructor + * @private + */ + const requester_funcs = { + unary: Client.prototype.makeUnaryRequest, + server_stream: Client.prototype.makeServerStreamRequest, + client_stream: Client.prototype.makeClientStreamRequest, + bidi: Client.prototype.makeBidiStreamRequest + }; + + /** + * Creates a constructor for a client with the given methods, as specified in + * the methods argument. The resulting class will have an instance method for + * each method in the service, which is a partial application of one of the + * [Client]{@link grpc.Client} request methods, depending on `requestSerialize` + * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` + * arguments predefined. + * @memberof grpc + * @alias grpc~makeGenericClientConstructor + * @param {grpc~ServiceDefinition} methods An object mapping method names to + * method attributes + * @param {string} serviceName The fully qualified name of the service + * @param {Object} class_options An options object. + * @return {function} New client constructor, which is a subclass of + * {@link grpc.Client}, and has the same arguments as that constructor. + */ + exports.makeClientConstructor = function(methods, serviceName, + class_options) { + if (!class_options) { + class_options = {}; + } + + function ServiceClient(address, credentials, options) { + Client.call(this, address, credentials, options); + } + + util.inherits(ServiceClient, Client); + + _.each(methods, function(attrs, name) { + var method_type; + // TODO(murgatroid99): Verify that we don't need this anymore + if (_.startsWith(name, '$')) { + throw new Error('Method names cannot start with $'); + } + if (attrs.requestStream) { + if (attrs.responseStream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (attrs.responseStream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + var serialize = attrs.requestSerialize; + var deserialize = attrs.responseDeserialize; + var method_func = _.partial(requester_funcs[method_type], attrs.path, + serialize, deserialize); + if (class_options.deprecatedArgumentOrder) { + ServiceClient.prototype[name] = deprecated_request_wrap(method_func); + } else { + ServiceClient.prototype[name] = method_func; + } + // Associate all provided attributes with the method + _.assign(ServiceClient.prototype[name], attrs); + if (attrs.originalName) { + ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; + } + }); + + ServiceClient.service = methods; + + return ServiceClient; + }; + + return Object.assign(exports, grpc); +}; diff --git a/packages/grpc-surface/package.json b/packages/grpc-surface/package.json new file mode 100644 index 000000000..30aa6a875 --- /dev/null +++ b/packages/grpc-surface/package.json @@ -0,0 +1,21 @@ +{ + "name": "grpc-surface", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/grpc/grpc-node.git" + }, + "author": "", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "dependencies": { + "lodash": "^4.17.4" + } +} From 7ae3d85f5bd7709ce8021c978fb56d31a51ef1ec Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 12 Oct 2017 13:40:18 -0700 Subject: [PATCH 0003/1899] Put packages in @grpc scope, add linking scripts --- gulpfile.js | 27 ++++++---- packages/grpc-health-check/package.json | 2 +- packages/grpc-js-core/gulpfile.js | 4 ++ packages/grpc-js-core/package.json | 5 +- packages/grpc-js/gulpfile.js | 49 ++++++++++++++++++ packages/grpc-js/index.js | 2 +- packages/grpc-js/package.json | 6 +-- packages/grpc-native-core/package.json | 6 +-- .../templates/package.json.template | 10 +--- packages/grpc-native/gulpfile.js | 50 +++++++++++++++++++ packages/grpc-native/index.js | 4 +- packages/grpc-native/package.json | 4 +- packages/grpc-protobufjs/package.json | 2 +- packages/grpc-surface/gulpfile.js | 30 +++++++++++ packages/grpc-surface/index.js | 2 +- packages/grpc-surface/package.json | 4 +- 16 files changed, 167 insertions(+), 40 deletions(-) create mode 100644 packages/grpc-js/gulpfile.js create mode 100644 packages/grpc-native/gulpfile.js create mode 100644 packages/grpc-surface/gulpfile.js diff --git a/gulpfile.js b/gulpfile.js index 574356d13..396918b64 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -22,33 +22,38 @@ const help = require('gulp-help'); const gulp = help(_gulp); require('./packages/grpc-health-check/gulpfile'); +require('./packages/grpc-js/gulpfile'); require('./packages/grpc-js-core/gulpfile'); +require('./packages/grpc-native/gulpfile'); require('./packages/grpc-native-core/gulpfile'); +require('./packages/grpc-surface/gulpfile'); require('./test/gulpfile'); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.core.install', 'native.core.install', 'health-check.install']); + ['js.core.install', 'native.core.install', 'health-check.install', + 'js.install', 'native.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'health-check.install']); + ['js.core.install', 'native.core.install.windows', 'health-check.install', + 'js.install', 'native.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); gulp.task('build', 'Build packages', ['js.core.compile', 'native.core.build']); -gulp.task('link.create', 'Initialize npm links to packages', - ['native.core.link.create']); +gulp.task('link.create', 'Initialize npm links', + ['native.core.link.create', 'js.core.link.create', 'surface.link.create', + 'js.link.create', 'native.link.create']); -gulp.task('link.only', 'Link packages together without rebuilding anything', - ['health-check.link.add', 'internal.test.link.add']); +gulp.task('link.only', 'Link packages without rebuilding', + ['js.link.add', 'native.link.add', 'health-check.link.add', 'internal.test.link.add']); -gulp.task('link', 'Link local packages together after building', - ['link.create'], () => { - gulp.start('link.only'); - }); +gulp.task('link', 'Link together packages', ['link.create'], () => { + gulp.start('link.only'); +}); gulp.task('setup', 'One-time setup for a clean repository', ['install.all'], () => { gulp.start('link'); @@ -61,7 +66,7 @@ gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clea gulp.task('clean.all', 'Delete all files created by tasks', ['js.core.clean.all', 'native.core.clean.all', 'health-check.clean.all', - 'internal.test.clean.all']); + 'internal.test.clean.all', 'js.clean.all', 'native.clean.all']); gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', ['native.core.test', 'internal.test.test', 'health-check.test']); diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index 20c4584ef..9a1e2b920 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -1,5 +1,5 @@ { - "name": "grpc-health-check", + "name": "@grpc/health-check", "version": "1.7.0-dev", "author": "Google Inc.", "description": "Health check service for use with gRPC", diff --git a/packages/grpc-js-core/gulpfile.js b/packages/grpc-js-core/gulpfile.js index 79592139a..71407b265 100644 --- a/packages/grpc-js-core/gulpfile.js +++ b/packages/grpc-js-core/gulpfile.js @@ -101,6 +101,10 @@ gulp.task('js.core.install', 'Install native core dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: jsCoreDir, stdio: 'inherit'}); }); +gulp.task('js.core.link.create', 'Create npm link', () => { + return execa('npm', ['link'], {cwd: jsCoreDir, stdio: 'inherit'}); +}); + /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 83fcb0e9a..1f679fd96 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -1,10 +1,9 @@ { - "name": "grpc-js-core", + "name": "@grpc/js-core", "version": "0.1.0", "description": "gRPC Library for Node - pure JS core", "homepage": "https://grpc.io/", "main": "build/src/index.js", - "private": true, "engines": { "node": ">=8.4" }, @@ -26,7 +25,7 @@ "name": "Google Inc." } ], - "_id": "grpc-js-core@0.1.0", + "_id": "@grpc/js-core@0.1.0", "scripts": { "build": "npm run compile", "clean": "gulp clean", diff --git a/packages/grpc-js/gulpfile.js b/packages/grpc-js/gulpfile.js new file mode 100644 index 000000000..147747299 --- /dev/null +++ b/packages/grpc-js/gulpfile.js @@ -0,0 +1,49 @@ +/* + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const _gulp = require('gulp'); +const help = require('gulp-help'); + +// gulp-help monkeypatches tasks to have an additional description parameter +const gulp = help(_gulp); + +const execa = require('execa'); +const path = require('path'); +const del = require('del'); + +const jsDir = __dirname; + +gulp.task('js.clean.links', 'Delete npm links', () => { + del(path.resolve(jsDir, 'node_modules/@grpc/js-core')); + del(path.resolve(jsDir, 'node_modules/@grpc/surface')); +}); + +gulp.task('js.clean.all', 'Delete all files created by tasks', + ['js.clean.links']); + +gulp.task('js.install', 'Install dependencies', () => { + return execa('npm', ['install', '--unsafe-perm'], {cwd: jsDir, stdio: 'inherit'}); +}); + +gulp.task('js.link.create', 'Create npm link', () => { + return execa('npm', ['link'], {cwd: jsDir, stdio: 'inherit'}); +}); + +gulp.task('js.link.add', 'Link local copies of dependencies', () => { + return execa('npm', ['link', '@grpc/js-core'], {cwd: jsDir, stdio: 'inherit'}).then( + execa('npm', ['link', '@grpc/surface'], {cwd: jsDir, stdio: 'inherit'})); +}); diff --git a/packages/grpc-js/index.js b/packages/grpc-js/index.js index 6079b1b13..47b866a42 100644 --- a/packages/grpc-js/index.js +++ b/packages/grpc-js/index.js @@ -18,4 +18,4 @@ 'use strict'; -module.exports = require('grpc-surface')(require('grpc-js-core')); +module.exports = require('@grpc/surface')(require('@grpc/js-core')); diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 248e84609..9aa9ca048 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,5 +1,5 @@ { - "name": "grpc-js", + "name": "@grpc/js", "version": "1.0.0", "description": "", "main": "index.js", @@ -17,7 +17,7 @@ }, "homepage": "https://grpc.io", "dependencies": { - "grpc-js-core": "^0.1.0", - "grpc-surface": "^1.0.0" + "@grpc/js-core": "^0.1.0", + "@grpc/surface": "^0.1.0" } } diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6ad9013b8..64a73a04b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -39,15 +39,11 @@ }, "devDependencies": { "async": "^2.0.1", - "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", - "express": "^4.14.0", "google-auth-library": "^0.9.2", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", - "jsdoc": "^3.3.2", - "minimist": "^1.1.0", - "poisson-process": "^0.2.1" + "jsdoc": "^3.3.2" }, "engines": { "node": ">=4" diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 45f522402..fe9290a8e 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -23,6 +23,7 @@ "scripts": { "lint": "node ./node_modules/jshint/bin/jshint src test index.js --exclude-path=.jshintignore", "test": "./node_modules/.bin/mocha test && npm run-script lint", + "build": "./node_modules/.bin/node-pre-gyp build", "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", "gen_docs": "./node_modules/.bin/jsdoc -c jsdoc_conf.json", "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", @@ -40,18 +41,11 @@ }, "devDependencies": { "async": "^2.0.1", - "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", - "express": "^4.14.0", "google-auth-library": "^0.9.2", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", - "jsdoc": "^3.3.2", - "jshint": "^2.5.0", - "minimist": "^1.1.0", - "mocha": "^3.0.2", - "mocha-jenkins-reporter": "^0.2.3", - "poisson-process": "^0.2.1" + "jsdoc": "^3.3.2" }, "engines": { "node": ">=4" diff --git a/packages/grpc-native/gulpfile.js b/packages/grpc-native/gulpfile.js new file mode 100644 index 000000000..c770a78f2 --- /dev/null +++ b/packages/grpc-native/gulpfile.js @@ -0,0 +1,50 @@ +/* + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const _gulp = require('gulp'); +const help = require('gulp-help'); + +// gulp-help monkeypatches tasks to have an additional description parameter +const gulp = help(_gulp); + +const execa = require('execa'); +const path = require('path'); +const del = require('del'); + +const nativeDir = __dirname; + +gulp.task('native.clean.links', 'Delete npm links', () => { + del(path.resolve(nativeDir, 'node_modules/@grpc/native-core')); + del(path.resolve(nativeDir, 'node_modules/@grpc/surface')); +}); + +gulp.task('native.clean.all', 'Delete all files created by tasks', + ['native.clean.links']); + +gulp.task('native.link.create', 'Create npm link', () => { + return execa('npm', ['link'], {cwd: nativeDir, stdio: 'inherit'}); +}); + +gulp.task('native.install', 'Install dependencies', () => { + return execa('npm', ['install', '--unsafe-perm'], {cwd: nativeDir, stdio: 'inherit'}); +}); + +gulp.task('native.link.add', 'Link local copies of dependencies', () => { + // Note: this should be 'grpc-native-core', when we change that package name + return execa('npm', ['link', 'grpc'], {cwd: nativeDir, stdio: 'inherit'}).then( + execa('npm', ['link', '@grpc/surface'], {cwd: nativeDir, stdio: 'inherit'})); +}); diff --git a/packages/grpc-native/index.js b/packages/grpc-native/index.js index 86266efed..692cf835b 100644 --- a/packages/grpc-native/index.js +++ b/packages/grpc-native/index.js @@ -18,5 +18,5 @@ 'use strict'; -// TODO(mlumish): This should eventually be grpc-native-core instead of grpc -module.exports = require('grpc-surface')(require('grpc')); +// TODO(mlumish): This should eventually be @grpc/native-core instead of grpc +module.exports = require('@grpc/surface')(require('grpc')); diff --git a/packages/grpc-native/package.json b/packages/grpc-native/package.json index 7637603ce..d141a2f96 100644 --- a/packages/grpc-native/package.json +++ b/packages/grpc-native/package.json @@ -1,5 +1,5 @@ { - "name": "grpc-native", + "name": "@grpc/native", "version": "1.0.0", "description": "", "main": "index.js", @@ -18,6 +18,6 @@ "homepage": "https://grpc.io", "dependencies": { "grpc": "^1.6.0", - "grpc-surface": "^1.0.0" + "@grpc/surface": "^0.1.0" } } diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 456fdf599..10c51c121 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,5 +1,5 @@ { - "name": "grpc-protobufjs", + "name": "@grpc/protobufjs", "version": "1.0.0", "description": "", "main": "index.js", diff --git a/packages/grpc-surface/gulpfile.js b/packages/grpc-surface/gulpfile.js new file mode 100644 index 000000000..2be3a5b12 --- /dev/null +++ b/packages/grpc-surface/gulpfile.js @@ -0,0 +1,30 @@ +/* + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const _gulp = require('gulp'); +const help = require('gulp-help'); + +// gulp-help monkeypatches tasks to have an additional description parameter +const gulp = help(_gulp); + +const execa = require('execa'); + +const surfaceDir = __dirname; + +gulp.task('surface.link.create', 'Create npm link', () => { + return execa('npm', ['link'], {cwd: surfaceDir, stdio: 'inherit'}); +}); diff --git a/packages/grpc-surface/index.js b/packages/grpc-surface/index.js index 6c9cb6a17..d8bcef5ec 100644 --- a/packages/grpc-surface/index.js +++ b/packages/grpc-surface/index.js @@ -18,7 +18,7 @@ 'use strict'; -const util = require(util); +const util = require('util'); const _ = require('lodash'); diff --git a/packages/grpc-surface/package.json b/packages/grpc-surface/package.json index 30aa6a875..7abcfd538 100644 --- a/packages/grpc-surface/package.json +++ b/packages/grpc-surface/package.json @@ -1,6 +1,6 @@ { - "name": "grpc-surface", - "version": "1.0.0", + "name": "@grpc/surface", + "version": "0.1.0", "description": "", "main": "index.js", "scripts": { From 6a837a73d811f873f751e16042f646ee070f6f7d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 12 Oct 2017 14:55:40 -0700 Subject: [PATCH 0004/1899] Update grpc/grpc submodule to v1.8.0-dev --- packages/grpc-native-core/binding.gyp | 1 + packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index f35bd6194..1a7bc1e3e 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -101,6 +101,7 @@ '-fprofile-arcs', '-ftest-coverage', '-rdynamic', + '-lstdc++', ], }], ['grpc_alpine=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 8d1dc2199..ebae8a8c9 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 8d1dc21994b2c8d4600db706b60b300c1a5a24a7 +Subproject commit ebae8a8c9f15425da8f07442642ca308f3c6612c diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 90acad8cf..a0437dc5a 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.7.0-dev", + "version": "1.8.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 47efb460e..c70b2425a 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -69,6 +69,7 @@ "binding.gyp" ], "main": "index.js", + "typings": "src/index.d.ts", "license": "Apache-2.0", "jshintConfig": { "bitwise": true, From 27d2f1e8cb6ed77f6e93d1baafbf6f3a02cf8739 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 12 Oct 2017 15:54:30 -0700 Subject: [PATCH 0005/1899] Try to improve a couple of cleanup scripts --- packages/grpc-js/gulpfile.js | 4 ++-- packages/grpc-native/gulpfile.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/gulpfile.js b/packages/grpc-js/gulpfile.js index 147747299..9f30ae10b 100644 --- a/packages/grpc-js/gulpfile.js +++ b/packages/grpc-js/gulpfile.js @@ -28,8 +28,8 @@ const del = require('del'); const jsDir = __dirname; gulp.task('js.clean.links', 'Delete npm links', () => { - del(path.resolve(jsDir, 'node_modules/@grpc/js-core')); - del(path.resolve(jsDir, 'node_modules/@grpc/surface')); + return del([path.resolve(jsDir, 'node_modules/@grpc/js-core'), + path.resolve(jsDir, 'node_modules/@grpc/surface')]); }); gulp.task('js.clean.all', 'Delete all files created by tasks', diff --git a/packages/grpc-native/gulpfile.js b/packages/grpc-native/gulpfile.js index c770a78f2..dcbea4457 100644 --- a/packages/grpc-native/gulpfile.js +++ b/packages/grpc-native/gulpfile.js @@ -28,8 +28,8 @@ const del = require('del'); const nativeDir = __dirname; gulp.task('native.clean.links', 'Delete npm links', () => { - del(path.resolve(nativeDir, 'node_modules/@grpc/native-core')); - del(path.resolve(nativeDir, 'node_modules/@grpc/surface')); + return del([path.resolve(nativeDir, 'node_modules/@grpc/native-core'), + path.resolve(nativeDir, 'node_modules/@grpc/surface')]); }); gulp.task('native.clean.all', 'Delete all files created by tasks', From 1f976921edbeefbf38103f4daa5cea6af7cf79c1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 13 Oct 2017 13:22:39 -0700 Subject: [PATCH 0006/1899] Fix a couple of gulpfile issues, don't create some links for now --- gulpfile.js | 50 +++++++++++++++---------- package.json | 6 ++- packages/grpc-health-check/package.json | 4 +- packages/grpc-js-core/package.json | 8 ++-- packages/grpc-native-core/package.json | 14 +++---- packages/grpc-native/gulpfile.js | 2 +- packages/grpc-protobufjs/package.json | 2 +- 7 files changed, 51 insertions(+), 35 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index dbb0af113..f18e6886a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -21,6 +21,8 @@ const help = require('gulp-help'); // gulp-help monkeypatches tasks to have an additional description parameter const gulp = help(_gulp); +var runSequence = require('run-sequence'); + require('./packages/grpc-health-check/gulpfile'); require('./packages/grpc-js/gulpfile'); require('./packages/grpc-js-core/gulpfile'); @@ -32,34 +34,44 @@ require('./test/gulpfile'); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.core.install', 'native.core.install', 'health-check.install', 'internal.test.install', - 'js.install', 'native.install']); + ['js.core.install', 'native.core.install', 'health-check.install', 'internal.test.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'health-check.install', 'internal.test.install', - 'js.install', 'native.install']); + ['js.core.install', 'native.core.install.windows', 'health-check.install', 'internal.test.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); gulp.task('build', 'Build packages', ['js.core.compile', 'native.core.build']); -gulp.task('link.create', 'Initialize npm links', - ['native.core.link.create', 'js.core.link.create', 'surface.link.create', - 'js.link.create', 'native.link.create']); +gulp.task('core.link.create', 'Initialize npm links to core packages', + ['native.core.link.create', 'js.core.link.create', 'surface.link.create']); + +gulp.task('core.link', 'Add links to core packages without rebuilding', + ['js.link.add', 'native.link.add']); + +gulp.task('surface.link.create', 'Create links to surface packages', + ['js.link.create', 'native.link.create']); -gulp.task('link.only', 'Link packages without rebuilding', - ['js.link.add', 'native.link.add', 'health-check.link.add', 'internal.test.link.add']); +gulp.task('surface.link', 'Link to surface packages', + ['health-check.link.add', 'internal.test.link.add']); -gulp.task('link', 'Link together packages', ['link.create'], () => { - gulp.start('link.only'); +gulp.task('link', 'Link together packages', (callback) => { + /* Currently, the target 'surface.link.create' doesn't work properly, and it + * is also not needed for the existing tests. The comment indicates where it + * belongs in the sequence. See npm/npm#18835 for the primary problem with it. + * This also means that 'core.link' is not needed, and the item + * 'native.core.link.create' should actually be 'core.link.create' + */ + runSequence('native.core.link.create', /* 'core.link', 'surface.link.create', */ 'surface.link', + callback); }); -gulp.task('setup', 'One-time setup for a clean repository', ['install.all'], () => { - gulp.start('link'); +gulp.task('setup', 'One-time setup for a clean repository', (callback) => { + runSequence('install.all', 'link', callback); }); -gulp.task('setup.windows', 'One-time setup for a clean repository for MS Windows', ['install.all.windows'], () => { - gulp.start('link'); +gulp.task('setup.windows', 'One-time setup for a clean repository for MS Windows', (callback) => { + runSequence('install.all.windows', 'link', callback); }); gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clean']); @@ -71,15 +83,15 @@ gulp.task('clean.all', 'Delete all files created by tasks', gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', ['native.core.test', 'internal.test.test', 'health-check.test']); -gulp.task('native.test', 'Run tests of native code', ['build'], () => { - gulp.start('native.test.only'); +gulp.task('native.test', 'Run tests of native code', (callback) => { + runSequence('build', 'native.test.only', callback); }); gulp.task('test.only', 'Run tests without rebuilding anything', ['js.core.test', 'native.test.only']); -gulp.task('test', 'Run all tests', ['build'], () => { - gulp.start('test.only'); +gulp.task('test', 'Run all tests', (callback) => { + runSequence('build', 'test.only', callback); }); gulp.task('doc.gen', 'Generate documentation', ['native.core.doc.gen']); diff --git a/package.json b/package.json index 2e9798ba7..c9217ede9 100644 --- a/package.json +++ b/package.json @@ -35,5 +35,9 @@ { "name": "Google Inc." } - ] + ], + "dependencies": { + "run-sequence": "^2.2.0", + "symlink": "^2.1.0" + } } diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index 9a1e2b920..e049ff49c 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -15,9 +15,9 @@ } ], "dependencies": { - "google-protobuf": "^3.0.0", + "google-protobuf": "^3.4.0", "grpc": "^1.6.0", - "lodash": "^3.9.3" + "lodash": "^3.10.1" }, "files": [ "LICENSE", diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 1f679fd96..6c8b2327d 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -14,10 +14,10 @@ "types": "src/index.ts", "license": "Apache-2.0", "devDependencies": { - "@types/lodash": "^4.14.73", - "@types/mocha": "^2.2.42", - "@types/node": "^8.0.25", - "clang-format": "^1.0.53", + "@types/lodash": "^4.14.77", + "@types/mocha": "^2.2.43", + "@types/node": "^8.0.34", + "clang-format": "^1.0.55", "google-ts-style": "^0.2.0" }, "contributors": [ diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 4a0c220da..bb08ac553 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,15 +29,15 @@ ], "dependencies": { "arguejs": "^0.2.3", - "lodash": "^4.15.0", - "nan": "^2.0.0", - "node-pre-gyp": "^0.6.35", - "protobufjs": "^5.0.0" + "lodash": "^4.17.4", + "nan": "^2.7.0", + "node-pre-gyp": "^0.6.38", + "protobufjs": "^5.0.2" }, "devDependencies": { - "electron-mocha": "^3.1.1", - "google-protobuf": "^3.0.0", - "istanbul": "^0.4.4" + "electron-mocha": "^3.5.0", + "google-protobuf": "^3.4.0", + "istanbul": "^0.4.5" }, "engines": { "node": ">=4" diff --git a/packages/grpc-native/gulpfile.js b/packages/grpc-native/gulpfile.js index dcbea4457..8ea6bd951 100644 --- a/packages/grpc-native/gulpfile.js +++ b/packages/grpc-native/gulpfile.js @@ -28,7 +28,7 @@ const del = require('del'); const nativeDir = __dirname; gulp.task('native.clean.links', 'Delete npm links', () => { - return del([path.resolve(nativeDir, 'node_modules/@grpc/native-core'), + return del([path.resolve(nativeDir, 'node_modules/grpc'), path.resolve(nativeDir, 'node_modules/@grpc/surface')]); }); diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 10c51c121..60b3ddddb 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -17,6 +17,6 @@ }, "dependencies": { "lodash": "^4.17.4", - "protobufjs": "~6.8.0" + "protobufjs": "^6.8.0" } } From d948857c016db4af0b0e949ef005a4ad0277575e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 17 Oct 2017 15:46:43 -0700 Subject: [PATCH 0007/1899] Try not updating npm in tests --- run-tests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/run-tests.sh b/run-tests.sh index 4e276ff4b..c1a76889d 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -48,7 +48,6 @@ do echo "Switching to node version $version" nvm install $version nvm use $version - npm install -g npm set -ex mkdir -p "reports/node$version" From 94eca58f5d00dafe73087270c898785e62b90e98 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 25 Oct 2017 11:30:10 -0700 Subject: [PATCH 0008/1899] try new links --- gulpfile.js | 8 +------- package.json | 1 + packages/grpc-health-check/gulpfile.js | 5 +++-- packages/grpc-js-core/gulpfile.js | 4 ---- packages/grpc-js/gulpfile.js | 9 +++------ packages/grpc-native-core/gulpfile.js | 4 ---- packages/grpc-native/gulpfile.js | 10 +++------- packages/grpc-surface/gulpfile.js | 4 +--- test/gulpfile.js | 11 ++++++++--- util.js | 23 +++++++++++++++++++++++ 10 files changed, 43 insertions(+), 36 deletions(-) create mode 100644 util.js diff --git a/gulpfile.js b/gulpfile.js index f18e6886a..f20531935 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -44,15 +44,9 @@ gulp.task('lint', 'Emit linting errors in source and test files', gulp.task('build', 'Build packages', ['js.core.compile', 'native.core.build']); -gulp.task('core.link.create', 'Initialize npm links to core packages', - ['native.core.link.create', 'js.core.link.create', 'surface.link.create']); - gulp.task('core.link', 'Add links to core packages without rebuilding', ['js.link.add', 'native.link.add']); -gulp.task('surface.link.create', 'Create links to surface packages', - ['js.link.create', 'native.link.create']); - gulp.task('surface.link', 'Link to surface packages', ['health-check.link.add', 'internal.test.link.add']); @@ -63,7 +57,7 @@ gulp.task('link', 'Link together packages', (callback) => { * This also means that 'core.link' is not needed, and the item * 'native.core.link.create' should actually be 'core.link.create' */ - runSequence('native.core.link.create', /* 'core.link', 'surface.link.create', */ 'surface.link', + runSequence('core.link', 'surface.link', callback); }); diff --git a/package.json b/package.json index c9217ede9..3a158bc1c 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "gulp-util": "^3.0.8", "jsdoc": "^3.3.2", "jshint": "^2.9.5", + "make-dir": "^1.1.0", "merge2": "^1.1.0", "mocha": "^3.5.3", "mocha-jenkins-reporter": "^0.3.9", diff --git a/packages/grpc-health-check/gulpfile.js b/packages/grpc-health-check/gulpfile.js index 6e41de5e4..6479baaa2 100644 --- a/packages/grpc-health-check/gulpfile.js +++ b/packages/grpc-health-check/gulpfile.js @@ -21,6 +21,7 @@ const mocha = require('gulp-mocha'); const execa = require('execa'); const path = require('path'); const del = require('del'); +const linkSync = require('../../util').linkSync; const gulp = help(_gulp); @@ -39,8 +40,8 @@ gulp.task('health-check.install', 'Install health check dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); }); -gulp.task('health-check.link.add', 'Link local copy of grpc', ['health-check.install'], () => { - return execa('npm', ['link', 'grpc'], {cwd: healthCheckDir, stdio: 'inherit'}); +gulp.task('health-check.link.add', 'Link local copy of grpc', () => { + linkSync(healthCheckDir, './node_modules/@grpc/native', '../grpc-native'); }); gulp.task('health-check.test', 'Run health check tests', diff --git a/packages/grpc-js-core/gulpfile.js b/packages/grpc-js-core/gulpfile.js index 71407b265..79592139a 100644 --- a/packages/grpc-js-core/gulpfile.js +++ b/packages/grpc-js-core/gulpfile.js @@ -101,10 +101,6 @@ gulp.task('js.core.install', 'Install native core dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: jsCoreDir, stdio: 'inherit'}); }); -gulp.task('js.core.link.create', 'Create npm link', () => { - return execa('npm', ['link'], {cwd: jsCoreDir, stdio: 'inherit'}); -}); - /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ diff --git a/packages/grpc-js/gulpfile.js b/packages/grpc-js/gulpfile.js index 9f30ae10b..d57c396fe 100644 --- a/packages/grpc-js/gulpfile.js +++ b/packages/grpc-js/gulpfile.js @@ -24,6 +24,7 @@ const gulp = help(_gulp); const execa = require('execa'); const path = require('path'); const del = require('del'); +const linkSync = require('../../util').linkSync; const jsDir = __dirname; @@ -39,11 +40,7 @@ gulp.task('js.install', 'Install dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: jsDir, stdio: 'inherit'}); }); -gulp.task('js.link.create', 'Create npm link', () => { - return execa('npm', ['link'], {cwd: jsDir, stdio: 'inherit'}); -}); - gulp.task('js.link.add', 'Link local copies of dependencies', () => { - return execa('npm', ['link', '@grpc/js-core'], {cwd: jsDir, stdio: 'inherit'}).then( - execa('npm', ['link', '@grpc/surface'], {cwd: jsDir, stdio: 'inherit'})); + linkSync(jsDir, './node_modules/@grpc/js-core', '../grpc-js-core'); + linkSync(jsDir, './node_modules/@grpc/surface', '../grpc-surface'); }); diff --git a/packages/grpc-native-core/gulpfile.js b/packages/grpc-native-core/gulpfile.js index 8a714ee62..ecbd1de00 100644 --- a/packages/grpc-native-core/gulpfile.js +++ b/packages/grpc-native-core/gulpfile.js @@ -57,10 +57,6 @@ execa('npm', ['install', '--build-from-source'], )) }); -gulp.task('native.core.link.create', 'Create npm link', () => { - return execa('npm', ['link'], {cwd: nativeCoreDir, stdio: 'inherit'}); -}); - gulp.task('native.core.lint', 'Emits linting errors', () => { return gulp.src([`${nativeCoreDir}/index.js`, `${srcDir}/*.js`, `${testDir}/*.js`]) .pipe(jshint(pkg.jshintConfig)) diff --git a/packages/grpc-native/gulpfile.js b/packages/grpc-native/gulpfile.js index 8ea6bd951..fb9de4975 100644 --- a/packages/grpc-native/gulpfile.js +++ b/packages/grpc-native/gulpfile.js @@ -24,6 +24,7 @@ const gulp = help(_gulp); const execa = require('execa'); const path = require('path'); const del = require('del'); +const linkSync = require('../../util').linkSync; const nativeDir = __dirname; @@ -35,16 +36,11 @@ gulp.task('native.clean.links', 'Delete npm links', () => { gulp.task('native.clean.all', 'Delete all files created by tasks', ['native.clean.links']); -gulp.task('native.link.create', 'Create npm link', () => { - return execa('npm', ['link'], {cwd: nativeDir, stdio: 'inherit'}); -}); - gulp.task('native.install', 'Install dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: nativeDir, stdio: 'inherit'}); }); gulp.task('native.link.add', 'Link local copies of dependencies', () => { - // Note: this should be 'grpc-native-core', when we change that package name - return execa('npm', ['link', 'grpc'], {cwd: nativeDir, stdio: 'inherit'}).then( - execa('npm', ['link', '@grpc/surface'], {cwd: nativeDir, stdio: 'inherit'})); + linkSync(nativeDir, './node_modules/grpc', '../grpc-native-core'); + linkSync(nativeDir, './node_modules/@grpc/surface', '../grpc-surface'); }); diff --git a/packages/grpc-surface/gulpfile.js b/packages/grpc-surface/gulpfile.js index 2be3a5b12..88488fd75 100644 --- a/packages/grpc-surface/gulpfile.js +++ b/packages/grpc-surface/gulpfile.js @@ -25,6 +25,4 @@ const execa = require('execa'); const surfaceDir = __dirname; -gulp.task('surface.link.create', 'Create npm link', () => { - return execa('npm', ['link'], {cwd: surfaceDir, stdio: 'inherit'}); -}); +// more to come diff --git a/test/gulpfile.js b/test/gulpfile.js index 469f8d23f..5303a423e 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -21,6 +21,7 @@ const mocha = require('gulp-mocha'); const execa = require('execa'); const path = require('path'); const del = require('del'); +const linkSync = require('../util').linkSync; // gulp-help monkeypatches tasks to have an additional description parameter const gulp = help(_gulp); @@ -29,7 +30,10 @@ const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); gulp.task('internal.test.clean.links', 'Delete npm links', () => { - return del(path.resolve(testDir, 'node_modules/grpc')); + return del([ + path.resolve(testDir, 'node_modules/@grpc/js'), + path.resolve(testDir, 'node_modules/@grpc/native') + ]); }); gulp.task('internal.test.install', 'Install test dependencies', () => { @@ -39,8 +43,9 @@ gulp.task('internal.test.install', 'Install test dependencies', () => { gulp.task('internal.test.clean.all', 'Delete all files created by tasks', ['internal.test.clean.links']); -gulp.task('internal.test.link.add', 'Link local copies of grpc packages', () => { - return execa('npm', ['link', 'grpc'], {cwd: testDir, stdio: 'inherit'}); +gulp.task('internal.test.link.add', 'Link local copies of dependencies', () => { + linkSync(testDir, './node_modules/@grpc/js', '../packages/grpc-js'); + linkSync(testDir, './node_modules/@grpc/native', '../packages/grpc-native'); }); gulp.task('internal.test.test', 'Run API-level tests', () => { diff --git a/util.js b/util.js new file mode 100644 index 000000000..2b4e1fad4 --- /dev/null +++ b/util.js @@ -0,0 +1,23 @@ +const path = require('path'); +const del = require('del'); +const fs = require('fs'); +const makeDir = require('make-dir'); + +// synchronously link a module +const linkSync = (base, from, to) => { + from = path.resolve(base, from); + to = path.resolve(base, to); + try { + fs.lstatSync(from); + } catch (e) { + console.log('link: deleting', from); + del.sync(from); + } + makeDir.sync(path.dirname(from)); + console.log('link: linking', from, '->', to); + fs.symlinkSync(to, from, 'junction'); +}; + +module.exports = { + linkSync +}; \ No newline at end of file From 9c4203c31784558bb3dd73f2607655b27bbeb205 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 25 Oct 2017 13:16:39 -0700 Subject: [PATCH 0009/1899] correction for tests --- packages/grpc-health-check/gulpfile.js | 2 +- test/gulpfile.js | 2 +- util.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-health-check/gulpfile.js b/packages/grpc-health-check/gulpfile.js index 6479baaa2..93366347f 100644 --- a/packages/grpc-health-check/gulpfile.js +++ b/packages/grpc-health-check/gulpfile.js @@ -41,7 +41,7 @@ gulp.task('health-check.install', 'Install health check dependencies', () => { }); gulp.task('health-check.link.add', 'Link local copy of grpc', () => { - linkSync(healthCheckDir, './node_modules/@grpc/native', '../grpc-native'); + linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); }); gulp.task('health-check.test', 'Run health check tests', diff --git a/test/gulpfile.js b/test/gulpfile.js index 5303a423e..d3da5c0aa 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -45,7 +45,7 @@ gulp.task('internal.test.clean.all', 'Delete all files created by tasks', gulp.task('internal.test.link.add', 'Link local copies of dependencies', () => { linkSync(testDir, './node_modules/@grpc/js', '../packages/grpc-js'); - linkSync(testDir, './node_modules/@grpc/native', '../packages/grpc-native'); + linkSync(testDir, './node_modules/grpc', '../packages/grpc-native-core'); }); gulp.task('internal.test.test', 'Run API-level tests', () => { diff --git a/util.js b/util.js index 2b4e1fad4..d91933474 100644 --- a/util.js +++ b/util.js @@ -9,11 +9,11 @@ const linkSync = (base, from, to) => { to = path.resolve(base, to); try { fs.lstatSync(from); - } catch (e) { console.log('link: deleting', from); del.sync(from); + } catch (e) { + makeDir.sync(path.dirname(from)); } - makeDir.sync(path.dirname(from)); console.log('link: linking', from, '->', to); fs.symlinkSync(to, from, 'junction'); }; From b192adf2a12653744520aea625c7c87fbb493d4c Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 12 Oct 2017 10:51:25 -0700 Subject: [PATCH 0010/1899] test: add requiring fixtures to specify implementation to test --- test/any_grpc.js | 29 ++++++++++++++++++++ test/api/async_test.js | 2 +- test/api/credentials_test.js | 2 +- test/api/math_client_test.js | 2 +- test/api/metadata_test.js | 2 +- test/api/surface_test.js | 2 +- test/fixtures/js_js.js | 2 ++ test/fixtures/js_native.js | 2 ++ test/fixtures/native_js.js | 2 ++ test/fixtures/native_native.js | 2 ++ test/gulpfile.js | 17 +++++++++++- test/interop/interop_client.js | 5 ++-- test/{api => interop}/interop_sanity_test.js | 4 +-- test/interop/interop_server.js | 5 ++-- 14 files changed, 64 insertions(+), 14 deletions(-) create mode 100644 test/any_grpc.js create mode 100644 test/fixtures/js_js.js create mode 100644 test/fixtures/js_native.js create mode 100644 test/fixtures/native_js.js create mode 100644 test/fixtures/native_native.js rename test/{api => interop}/interop_sanity_test.js (96%) diff --git a/test/any_grpc.js b/test/any_grpc.js new file mode 100644 index 000000000..43db28af2 --- /dev/null +++ b/test/any_grpc.js @@ -0,0 +1,29 @@ +module.exports = {}; + +function assignExportsFromGlobal(globalField, exportsField) { + if (global[globalField] === 'js') { + module.exports[exportsField] = require('../packages/grpc-js'); + } else if (global[globalField] === 'native') { + module.exports[exportsField] = require('../packages/grpc-native'); + } else { + throw new Error([ + `Invalid value for global.${globalField}: ${global.globalField}.`, + 'If running from the command line, please --require a fixture first.' + ].join(' ')); + } +} + +// Set 'server' and 'client' fields on this module's exports. +// These don't refer to the portions of the gRPC interface that are +// relevant to an application behaving as a server or a client respectively. +// Instead, they refer to the entire gRPC module as it's visible to the +// application. +// In other words, a test that simulates a gRPC client should treat +// require('any-grpc').client as the value of require('grpc'), and would simply +// not be expected to use server components. +assignExportsFromGlobal('_server_implementation', 'server'); +assignExportsFromGlobal('_client_implementation', 'client'); +// Increase clarity when there's no distinction between client/server +if (module.exports.client === module.exports.server) { + module.exports.all = module.exports.client; +} diff --git a/test/api/async_test.js b/test/api/async_test.js index e899da56b..c66f3782b 100644 --- a/test/api/async_test.js +++ b/test/api/async_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('grpc'); +var grpc = require('../any_grpc').all; var math = grpc.load( __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math; diff --git a/test/api/credentials_test.js b/test/api/credentials_test.js index 968799945..3bf3d5f51 100644 --- a/test/api/credentials_test.js +++ b/test/api/credentials_test.js @@ -22,7 +22,7 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); -var grpc = require('grpc'); +var grpc = require('../any_grpc').all; /** * This is used for testing functions with multiple asynchronous calls that diff --git a/test/api/math_client_test.js b/test/api/math_client_test.js index 09265abf6..1f4f25e6d 100644 --- a/test/api/math_client_test.js +++ b/test/api/math_client_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('grpc'); +var grpc = require('../any_grpc').all; var math = require('./math/math_pb'); var MathClient = require('./math/math_grpc_pb').MathClient; diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js index 5e24f7ac8..7187ee73c 100644 --- a/test/api/metadata_test.js +++ b/test/api/metadata_test.js @@ -18,7 +18,7 @@ 'use strict'; -var Metadata = require('grpc').Metadata; +var Metadata = require('../any_grpc').all.Metadata; var assert = require('assert'); diff --git a/test/api/surface_test.js b/test/api/surface_test.js index b2072fdd8..d54ff7b42 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -21,7 +21,7 @@ var assert = require('assert'); var _ = require('lodash'); -var grpc = require('grpc'); +var grpc = require('../any_grpc').all; var MathClient = grpc.load( __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math.Math; diff --git a/test/fixtures/js_js.js b/test/fixtures/js_js.js new file mode 100644 index 000000000..e0ca3c588 --- /dev/null +++ b/test/fixtures/js_js.js @@ -0,0 +1,2 @@ +global._server_implementation = 'native'; +global._client_implementation = 'js'; \ No newline at end of file diff --git a/test/fixtures/js_native.js b/test/fixtures/js_native.js new file mode 100644 index 000000000..5088df96d --- /dev/null +++ b/test/fixtures/js_native.js @@ -0,0 +1,2 @@ +global._server_implementation = 'js'; +global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_js.js b/test/fixtures/native_js.js new file mode 100644 index 000000000..5088df96d --- /dev/null +++ b/test/fixtures/native_js.js @@ -0,0 +1,2 @@ +global._server_implementation = 'js'; +global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_native.js b/test/fixtures/native_native.js new file mode 100644 index 000000000..5b005e485 --- /dev/null +++ b/test/fixtures/native_native.js @@ -0,0 +1,2 @@ +global._server_implementation = 'native'; +global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/gulpfile.js b/test/gulpfile.js index d3da5c0aa..c020ff767 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -22,6 +22,7 @@ const execa = require('execa'); const path = require('path'); const del = require('del'); const linkSync = require('../util').linkSync; +const merge = require('merge2'); // gulp-help monkeypatches tasks to have an additional description parameter const gulp = help(_gulp); @@ -49,5 +50,19 @@ gulp.task('internal.test.link.add', 'Link local copies of dependencies', () => { }); gulp.task('internal.test.test', 'Run API-level tests', () => { - return gulp.src(`${apiTestDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); + // run mocha tests matching a glob with a pre-required fixture, + // returning the associated gulp stream + const runTestsWithFixture = (glob, fixture) => gulp + .src(glob) + .pipe(mocha({ + reporter: 'mocha-jenkins-reporter', + require: `${testDir}/fixtures/${fixture}.js` + })); + const interopTest = `${testDir}/interop/interop_test.js`; + const tasks = [].concat( + ['native_native'/*, 'js_js'*/] + .map((fixture) => runTestsWithFixture(`${apiTestDir}/*.js`, fixture)), + ['native_native', 'native_js'/*, 'js_native', 'js_js'*/] + .map((fixture) => runTestsWithFixture(interopTest, fixture))) + return merge(tasks); }); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 5fad82bfc..f9122d35d 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -20,10 +20,9 @@ var fs = require('fs'); var path = require('path'); -// TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); +var grpc = require('../any_grpc').client; var testProto = grpc.load({ - root: __dirname + '/../../packages/grpc-native-core/deps/grpc', + root: __dirname + '/../../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var GoogleAuth = require('google-auth-library'); diff --git a/test/api/interop_sanity_test.js b/test/interop/interop_sanity_test.js similarity index 96% rename from test/api/interop_sanity_test.js rename to test/interop/interop_sanity_test.js index b3f65a034..055a5ab75 100644 --- a/test/api/interop_sanity_test.js +++ b/test/interop/interop_sanity_test.js @@ -18,8 +18,8 @@ 'use strict'; -var interop_server = require('../interop/interop_server.js'); -var interop_client = require('../interop/interop_client.js'); +var interop_server = require('./interop_server.js'); +var interop_client = require('./interop_client.js'); var server; diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index 65bb088d3..58ccacd7d 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -22,10 +22,9 @@ var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); -// TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); +var grpc = require('../any_grpc').server; var testProto = grpc.load({ - root: __dirname + '/../../packages/grpc-native-core/deps/grpc', + root: __dirname + '/../../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; From 5c657cf3bda2e71a6713485c849a82022180dac9 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 23 Oct 2017 16:38:01 -0700 Subject: [PATCH 0011/1899] test: run internal tests sequentially --- test/gulpfile.js | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/test/gulpfile.js b/test/gulpfile.js index c020ff767..6d4ac5a0a 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -22,7 +22,6 @@ const execa = require('execa'); const path = require('path'); const del = require('del'); const linkSync = require('../util').linkSync; -const merge = require('merge2'); // gulp-help monkeypatches tasks to have an additional description parameter const gulp = help(_gulp); @@ -52,17 +51,30 @@ gulp.task('internal.test.link.add', 'Link local copies of dependencies', () => { gulp.task('internal.test.test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream - const runTestsWithFixture = (glob, fixture) => gulp - .src(glob) - .pipe(mocha({ - reporter: 'mocha-jenkins-reporter', - require: `${testDir}/fixtures/${fixture}.js` - })); - const interopTest = `${testDir}/interop/interop_test.js`; - const tasks = [].concat( - ['native_native'/*, 'js_js'*/] - .map((fixture) => runTestsWithFixture(`${apiTestDir}/*.js`, fixture)), - ['native_native', 'native_js'/*, 'js_native', 'js_js'*/] - .map((fixture) => runTestsWithFixture(interopTest, fixture))) - return merge(tasks); + const runTestsWithFixture = (glob, fixture) => new Promise((resolve, reject) => { + const server = fixture.split('_')[0]; + const client = fixture.split('_')[1]; + console.log(`Running ${glob} with ${server} server + ${client} client`); + gulp.src(glob) + .pipe(mocha({ + reporter: 'mocha-jenkins-reporter', + require: `${testDir}/fixtures/${fixture}.js` + })) + .resume() // put the stream in flowing mode + .on('end', resolve) + .on('error', reject); + }); + const apiTestGlob = `${apiTestDir}/*.js`; + const interopTestGlob = `${testDir}/interop/interop_sanity_test.js`; + const runTestsArgPairs = [ + [apiTestGlob, 'native_native'], + [apiTestGlob, 'js_js'], + [interopTestGlob, 'native_native'], + [interopTestGlob, 'native_js'], + [interopTestGlob, 'js_native'], + [interopTestGlob, 'js_js'] + ]; + return runTestsArgPairs.reduce((previousPromise, argPair) => { + return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); + }, Promise.resolve()); }); From afca1967cc2518aceed49d9b46a86009e8f9c4f1 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 23 Oct 2017 17:36:42 -0700 Subject: [PATCH 0012/1899] refactor: correct interop test paths --- test/gulpfile.js | 8 ++++---- test/interop/interop_client.js | 2 +- test/interop/interop_server.js | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/gulpfile.js b/test/gulpfile.js index 6d4ac5a0a..6779594d6 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -68,11 +68,11 @@ gulp.task('internal.test.test', 'Run API-level tests', () => { const interopTestGlob = `${testDir}/interop/interop_sanity_test.js`; const runTestsArgPairs = [ [apiTestGlob, 'native_native'], - [apiTestGlob, 'js_js'], + // [apiTestGlob, 'js_js'], [interopTestGlob, 'native_native'], - [interopTestGlob, 'native_js'], - [interopTestGlob, 'js_native'], - [interopTestGlob, 'js_js'] + // [interopTestGlob, 'native_js'], + // [interopTestGlob, 'js_native'], + // [interopTestGlob, 'js_js'] ]; return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index f9122d35d..70597dd5b 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -22,7 +22,7 @@ var fs = require('fs'); var path = require('path'); var grpc = require('../any_grpc').client; var testProto = grpc.load({ - root: __dirname + '/../../../packages/grpc-native-core/deps/grpc', + root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var GoogleAuth = require('google-auth-library'); diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index 58ccacd7d..edec7a9da 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -24,7 +24,7 @@ var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); var grpc = require('../any_grpc').server; var testProto = grpc.load({ - root: __dirname + '/../../../packages/grpc-native-core/deps/grpc', + root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; From 40ce5ec09b20d49e029476615cd0f9a0361d8da7 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 25 Oct 2017 15:52:52 -0700 Subject: [PATCH 0013/1899] test dir don't need links --- gulpfile.js | 2 +- test/gulpfile.js | 15 +-------------- 2 files changed, 2 insertions(+), 15 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index f20531935..d18b37494 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -48,7 +48,7 @@ gulp.task('core.link', 'Add links to core packages without rebuilding', ['js.link.add', 'native.link.add']); gulp.task('surface.link', 'Link to surface packages', - ['health-check.link.add', 'internal.test.link.add']); + ['health-check.link.add']); gulp.task('link', 'Link together packages', (callback) => { /* Currently, the target 'surface.link.create' doesn't work properly, and it diff --git a/test/gulpfile.js b/test/gulpfile.js index 6779594d6..6b2bc15b0 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -29,24 +29,11 @@ const gulp = help(_gulp); const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); -gulp.task('internal.test.clean.links', 'Delete npm links', () => { - return del([ - path.resolve(testDir, 'node_modules/@grpc/js'), - path.resolve(testDir, 'node_modules/@grpc/native') - ]); -}); - gulp.task('internal.test.install', 'Install test dependencies', () => { return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); }); -gulp.task('internal.test.clean.all', 'Delete all files created by tasks', - ['internal.test.clean.links']); - -gulp.task('internal.test.link.add', 'Link local copies of dependencies', () => { - linkSync(testDir, './node_modules/@grpc/js', '../packages/grpc-js'); - linkSync(testDir, './node_modules/grpc', '../packages/grpc-native-core'); -}); +gulp.task('internal.test.clean.all', 'Delete all files created by tasks', () => {}); gulp.task('internal.test.test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, From 689d4d0c619b69fca0fb7af734f2741c8c4bc788 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 25 Oct 2017 16:11:01 -0700 Subject: [PATCH 0014/1899] change grpc refs in math api test --- test/api/math/math_grpc_pb.js | 2 +- test/api/math/math_server.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/math/math_grpc_pb.js b/test/api/math/math_grpc_pb.js index afd08a34a..2a9b4aeb2 100644 --- a/test/api/math/math_grpc_pb.js +++ b/test/api/math/math_grpc_pb.js @@ -16,7 +16,7 @@ // limitations under the License. // 'use strict'; -var grpc = require('grpc'); +var grpc = require('../../any_grpc.js').all; var math_math_pb = require('../math/math_pb.js'); function serialize_DivArgs(arg) { diff --git a/test/api/math/math_server.js b/test/api/math/math_server.js index 05e30f722..934006baf 100644 --- a/test/api/math/math_server.js +++ b/test/api/math/math_server.js @@ -18,7 +18,7 @@ 'use strict'; -var grpc = require('grpc'); +var grpc = require('../../any_grpc.js').all; var grpcMath = require('./math_grpc_pb'); var math = require('./math_pb'); From 6a6b4eb56c9c10432d2664d6db12fc1348fc6e58 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 25 Oct 2017 16:35:08 -0700 Subject: [PATCH 0015/1899] add packageJson to any-grpc --- test/any_grpc.js | 25 +++++++++++++++++++------ test/api/surface_test.js | 4 +++- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/test/any_grpc.js b/test/any_grpc.js index 43db28af2..c36cc62aa 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -1,16 +1,26 @@ -module.exports = {}; +module.exports = { + packageJson: {}, + core: { + packageJson: {} + } +}; function assignExportsFromGlobal(globalField, exportsField) { - if (global[globalField] === 'js') { - module.exports[exportsField] = require('../packages/grpc-js'); - } else if (global[globalField] === 'native') { - module.exports[exportsField] = require('../packages/grpc-native'); - } else { + if (global[globalField] !== 'js' && global[globalField] !== 'native') { throw new Error([ `Invalid value for global.${globalField}: ${global.globalField}.`, 'If running from the command line, please --require a fixture first.' ].join(' ')); } + const impl = global[globalField]; + // (1) set global field. + module.exports[exportsField] = require(`../packages/grpc-${impl}`); + // (2) make package's package.json file accessible thru packageJson path. + module.exports.packageJson[exportsField] = require(`../packages/grpc-${impl}/package.json`); + // (3) make package's underlying core dependency accessible thru core path. + module.exports.core[exportsField] = require(`../packages/grpc-${impl}-core`); + // (4) make (3) x (2) accessible thru core.packageJson path. + module.exports.core.packageJson[exportsField] = require(`../packages/grpc-${impl}-core/package.json`); } // Set 'server' and 'client' fields on this module's exports. @@ -26,4 +36,7 @@ assignExportsFromGlobal('_client_implementation', 'client'); // Increase clarity when there's no distinction between client/server if (module.exports.client === module.exports.server) { module.exports.all = module.exports.client; + module.exports.core.all = module.exports.core.client; + module.exports.packageJson.all = module.exports.packageJson.client; + module.exports.core.packageJson.all = module.exports.core.packageJson.client; } diff --git a/test/api/surface_test.js b/test/api/surface_test.js index d54ff7b42..fae414b89 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -485,10 +485,12 @@ describe('Echo metadata', function() { call.end(); }); it('shows the correct user-agent string', function(done) { - var version = require('grpc/package.json').version; + var version = require('../any_grpc').core.packageJson.all.version; var call = client.unary({}, metadata, function(err, data) { assert.ifError(err); }); call.on('metadata', function(metadata) { + console.log(version); + console.log(metadata.get('user-agent')[0]); assert(_.startsWith(metadata.get('user-agent')[0], 'grpc-node/' + version)); done(); From 00ff2c909ecb573aaac298951ec81b6e9f083edb Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 26 Oct 2017 14:42:02 -0700 Subject: [PATCH 0016/1899] run install in grpc-surface --- gulpfile.js | 4 ++-- packages/grpc-surface/gulpfile.js | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index d18b37494..53ee240ab 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -34,10 +34,10 @@ require('./test/gulpfile'); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.core.install', 'native.core.install', 'health-check.install', 'internal.test.install']); + ['js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'internal.test.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'health-check.install', 'internal.test.install']); + ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'internal.test.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); diff --git a/packages/grpc-surface/gulpfile.js b/packages/grpc-surface/gulpfile.js index 88488fd75..5dfde6848 100644 --- a/packages/grpc-surface/gulpfile.js +++ b/packages/grpc-surface/gulpfile.js @@ -25,4 +25,6 @@ const execa = require('execa'); const surfaceDir = __dirname; -// more to come +gulp.task('surface.install', 'Install surface dependencies', () => { + return execa('npm', ['install', '--unsafe-perm'], {cwd: surfaceDir, stdio: 'inherit'}); +}); From 9fcee9182225e73b53e5a4057a00d0c4dd0c6096 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 1 Nov 2017 09:44:30 -0700 Subject: [PATCH 0017/1899] Fix channel state code and add backoff code --- packages/grpc-js-core/src/channel.ts | 130 +++++++++++++++++++-------- 1 file changed, 94 insertions(+), 36 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 1b7fda5b0..9afe17079 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -15,6 +15,12 @@ import {Metadata, MetadataObject} from './metadata'; const IDLE_TIMEOUT_MS = 300000; +const MIN_CONNECT_TIMEOUT_MS = 20000; +const INITIAL_BACKOFF_MS = 1000; +const BACKOFF_MULTIPLIER = 1.6; +const MAX_BACKOFF_MS = 120000; +const BACKOFF_JITTER = 0.2; + const { HTTP2_HEADER_AUTHORITY, HTTP2_HEADER_CONTENT_TYPE, @@ -37,6 +43,10 @@ export enum ConnectivityState { SHUTDOWN } +function uniformRandom(min:number, max: number) { + return Math.random() * (max - min) + min; +} + // todo: maybe we want an interface for load balancing, but no implementation // for anything complicated @@ -62,49 +72,97 @@ export interface Channel extends EventEmitter { export class Http2Channel extends EventEmitter implements Channel { private connectivityState: ConnectivityState = ConnectivityState.IDLE; - private idleTimerId: NodeJS.Timer|null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ private subChannel: http2.ClientHttp2Session|null; private filterStackFactory: FilterStackFactory; - private transitionToState(newState: ConnectivityState): void { - if (newState !== this.connectivityState) { + private idleTimerId: NodeJS.Timer|null = null; + + private subChannelConnectCallback: ()=>void = () => {}; + private subChannelCloseCallback: ()=>void = () => {}; + + private backoffTimerId: NodeJS.Timer|null = null; + private currentBackoff: number = INITIAL_BACKOFF_MS; + private currentBackoffDeadline: Date; + + private handleStateChange(oldState: ConnectivityState, newState: ConnectivityState): void { + let now: Date = new Date(); + switch(newState) { + case ConnectivityState.CONNECTING: + if (oldState === ConnectivityState.IDLE) { + this.currentBackoff = INITIAL_BACKOFF_MS; + this.currentBackoffDeadline = new Date(now.getTime() + INITIAL_BACKOFF_MS); + } else if (oldState == ConnectivityState.TRANSIENT_FAILURE) { + this.currentBackoff = Math.min(this.currentBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); + let jitterMagnitude: number = BACKOFF_JITTER * this.currentBackoff; + this.currentBackoffDeadline = new Date(now.getTime() + this.currentBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude)); + } + this.startConnecting(); + break; + case ConnectivityState.READY: + this.emit('connect'); + break; + case ConnectivityState.TRANSIENT_FAILURE: + this.subChannel = null; + this.backoffTimerId = setTimeout(() => { + this.transitionToState([ConnectivityState.TRANSIENT_FAILURE], ConnectivityState.CONNECTING); + }, this.currentBackoffDeadline.getTime() - now.getTime()); + break; + case ConnectivityState.IDLE: + case ConnectivityState.SHUTDOWN: + if (this.subChannel !== null) { + this.subChannel.shutdown({graceful: true}); + this.subChannel.removeListener('connect', this.subChannelConnectCallback); + this.subChannel.removeListener('close', this.subChannelCloseCallback); + this.subChannel = null; + } + break; + } + } + + // Transition from any of a set of oldStates to a specific newState + private transitionToState(oldStates: [ConnectivityState], newState: ConnectivityState): void { + if (oldStates.indexOf(this.connectivityState) > -1) { + let oldState: ConnectivityState = this.connectivityState; this.connectivityState = newState; + this.handleStateChange(oldState, newState); this.emit('connectivityStateChanged', newState); } } private startConnecting(): void { - this.transitionToState(ConnectivityState.CONNECTING); + let subChannel: http2.ClientHttp2Session; let secureContext = this.credentials.getSecureContext(); if (secureContext === null) { - this.subChannel = http2.connect(this.address); + subChannel = http2.connect(this.address); } else { - this.subChannel = http2.connect(this.address, {secureContext}); - } - this.subChannel.once('connect', () => { - this.transitionToState(ConnectivityState.READY); - }); - this.subChannel.setTimeout(IDLE_TIMEOUT_MS, () => { - this.goIdle(); - }); - /* TODO(murgatroid99): add connection-level error handling with exponential - * reconnection backoff */ - } - - private goIdle(): void { - if (this.subChannel !== null) { - this.subChannel.shutdown({graceful: true}, () => undefined); - this.subChannel = null; - } - this.transitionToState(ConnectivityState.IDLE); - } - - private kickConnectivityState(): void { - if (this.connectivityState === ConnectivityState.IDLE) { - this.startConnecting(); + subChannel = http2.connect(this.address, {secureContext}); } + this.subChannel = subChannel; + let now = new Date(); + let connectionTimeout: number = Math.max( + this.currentBackoffDeadline.getTime() - now.getTime(), + MIN_CONNECT_TIMEOUT_MS); + let connectionTimerId: NodeJS.Timer = setTimeout(() => { + // This should trigger the 'close' event, which will send us back to TRANSIENT_FAILURE + subChannel.shutdown(); + }, connectionTimeout); + this.subChannelConnectCallback = () => { + // Connection succeeded + clearTimeout(connectionTimerId); + this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.READY); + }; + subChannel.once('connect', this.subChannelConnectCallback); + this.subChannelCloseCallback = () => { + // Connection failed + clearTimeout(connectionTimerId); + /* TODO(murgatroid99): verify that this works for CONNECTING->TRANSITIVE_FAILURE + * see nodejs/node#16645 */ + this.transitionToState([ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE); + }; + subChannel.once('close', this.subChannelCloseCallback); } constructor( @@ -121,6 +179,7 @@ export class Http2Channel extends EventEmitter implements Channel { new CompressionFilterFactory(this), new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this) ]); + this.currentBackoffDeadline = new Date(); } private startHttp2Stream( @@ -158,7 +217,7 @@ export class Http2Channel extends EventEmitter implements Channel { } createStream(methodName: string, metadata: Metadata, options: CallOptions): - CallStream { + CallStream { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } @@ -174,15 +233,11 @@ export class Http2Channel extends EventEmitter implements Channel { } connect(callback: () => void): void { - this.kickConnectivityState(); + this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); if (this.connectivityState === ConnectivityState.READY) { setImmediate(callback); } else { - this.once('connectivityStateChanged', (newState) => { - if (newState === ConnectivityState.READY) { - callback(); - } - }); + this.once('connect', callback); } } @@ -194,7 +249,10 @@ export class Http2Channel extends EventEmitter implements Channel { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } - this.transitionToState(ConnectivityState.SHUTDOWN); + this.transitionToState([ConnectivityState.CONNECTING, + ConnectivityState.READY, + ConnectivityState.TRANSIENT_FAILURE, + ConnectivityState.IDLE], ConnectivityState.SHUTDOWN); if (this.subChannel !== null) { this.subChannel.shutdown({graceful: true}); } From 8ece79c8af220214ad7c34796c47269d166ff6ad Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 2 Nov 2017 10:03:29 -0700 Subject: [PATCH 0018/1899] Changes from PR comments --- packages/grpc-js-core/src/channel.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 9afe17079..a51ae9572 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -77,12 +77,10 @@ export class Http2Channel extends EventEmitter implements Channel { private subChannel: http2.ClientHttp2Session|null; private filterStackFactory: FilterStackFactory; - private idleTimerId: NodeJS.Timer|null = null; - private subChannelConnectCallback: ()=>void = () => {}; private subChannelCloseCallback: ()=>void = () => {}; - private backoffTimerId: NodeJS.Timer|null = null; + private backoffTimerId: NodeJS.Timer; private currentBackoff: number = INITIAL_BACKOFF_MS; private currentBackoffDeadline: Date; @@ -93,7 +91,7 @@ export class Http2Channel extends EventEmitter implements Channel { if (oldState === ConnectivityState.IDLE) { this.currentBackoff = INITIAL_BACKOFF_MS; this.currentBackoffDeadline = new Date(now.getTime() + INITIAL_BACKOFF_MS); - } else if (oldState == ConnectivityState.TRANSIENT_FAILURE) { + } else if (oldState === ConnectivityState.TRANSIENT_FAILURE) { this.currentBackoff = Math.min(this.currentBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); let jitterMagnitude: number = BACKOFF_JITTER * this.currentBackoff; this.currentBackoffDeadline = new Date(now.getTime() + this.currentBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude)); @@ -116,6 +114,7 @@ export class Http2Channel extends EventEmitter implements Channel { this.subChannel.removeListener('connect', this.subChannelConnectCallback); this.subChannel.removeListener('close', this.subChannelCloseCallback); this.subChannel = null; + clearTimeout(this.backoffTimerId); } break; } @@ -180,6 +179,10 @@ export class Http2Channel extends EventEmitter implements Channel { new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this) ]); this.currentBackoffDeadline = new Date(); + /* The only purpose of these lines is to ensure that this.backoffTimerId has + * a value of type NodeJS.Timer. */ + this.backoffTimerId = setTimeout(() => {}, 0); + clearTimeout(this.backoffTimerId); } private startHttp2Stream( @@ -253,8 +256,5 @@ export class Http2Channel extends EventEmitter implements Channel { ConnectivityState.READY, ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.IDLE], ConnectivityState.SHUTDOWN); - if (this.subChannel !== null) { - this.subChannel.shutdown({graceful: true}); - } } } From d91b739cb528cfce4d3423a765d8bce14c3c1624 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 2 Nov 2017 22:57:10 +0100 Subject: [PATCH 0019/1899] Adding support for abseil. --- packages/grpc-native-core/binding.gyp | 3 ++- packages/grpc-native-core/package.json | 1 + packages/grpc-native-core/templates/binding.gyp.template | 3 ++- packages/grpc-native-core/templates/package.json.template | 1 + 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 1a7bc1e3e..c8609a962 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -77,7 +77,8 @@ ], 'include_dirs': [ 'deps/grpc', - 'deps/grpc/include' + 'deps/grpc/include', + 'deps/grpc/third_party/abseil-cpp' ], 'defines': [ 'GPR_BACKWARDS_COMPATIBILITY_MODE', diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 0fb745967..435b6ecd8 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -63,6 +63,7 @@ "deps/grpc/third_party/boringssl/crypto/**/*.{c,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,h}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "binding.gyp" ], "main": "index.js", diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 19f88683f..6e71f28c5 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -74,7 +74,8 @@ ], 'include_dirs': [ 'deps/grpc', - 'deps/grpc/include' + 'deps/grpc/include', + 'deps/grpc/third_party/abseil-cpp' ], 'defines': [ 'GPR_BACKWARDS_COMPATIBILITY_MODE', diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 4a119737a..1be036070 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -65,6 +65,7 @@ "deps/grpc/third_party/boringssl/crypto/**/*.{c,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,h}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "binding.gyp" ], "main": "index.js", From 03525b6a5ea49dd7e3aeae04ff58b23818e7a166 Mon Sep 17 00:00:00 2001 From: "Bernhard K. Weisshuhn" Date: Mon, 6 Nov 2017 15:44:52 +0100 Subject: [PATCH 0020/1899] =?UTF-8?q?Build=20different=20binaries=20for=20?= =?UTF-8?q?different=20libc=E2=80=99s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #81 --- packages/grpc-native-core/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 0fb745967..7eec82614 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -31,7 +31,7 @@ "arguejs": "^0.2.3", "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.6.35", + "node-pre-gyp": "^0.6.39", "protobufjs": "^5.0.0" }, "devDependencies": { @@ -43,10 +43,10 @@ }, "binary": { "module_name": "grpc_node", - "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}", + "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", "host": "https://storage.googleapis.com/", "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", - "package_name": "{node_abi}-{platform}-{arch}.tar.gz" + "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" }, "files": [ "LICENSE", From 44793121715c3f58c1eae694b7495c83a6360876 Mon Sep 17 00:00:00 2001 From: "Bernhard K. Weisshuhn" Date: Tue, 7 Nov 2017 08:31:19 +0100 Subject: [PATCH 0021/1899] Add libc variable to binary paths in package.json template --- packages/grpc-native-core/templates/package.json.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 4a119737a..28ed9463d 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -45,10 +45,10 @@ }, "binary": { "module_name": "grpc_node", - "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}", + "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", "host": "https://storage.googleapis.com/", "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", - "package_name": "{node_abi}-{platform}-{arch}.tar.gz" + "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" }, "files": [ "LICENSE", From 9d9404615ec870dfbfe15055148070ccd700dc5f Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 7 Nov 2017 15:00:23 -0800 Subject: [PATCH 0022/1899] use merged gRPC object in api tests --- test/any_grpc.js | 57 +++---- test/api/async_test.js | 2 +- test/api/credentials_api_test.js | 165 +++++++++++++++++++ test/api/credentials_test.js | 2 +- test/api/file_load_test.js | 40 +++++ test/{interop => api}/interop_sanity_test.js | 4 +- test/api/math/math_grpc_pb.js | 2 +- test/api/math/math_server.js | 2 +- test/api/math_client_test.js | 2 +- test/api/metadata_test.js | 2 +- test/api/surface_test.js | 6 +- test/gulpfile.js | 9 +- test/interop/interop_client.js | 2 +- test/interop/interop_server.js | 2 +- 14 files changed, 245 insertions(+), 52 deletions(-) create mode 100644 test/api/credentials_api_test.js create mode 100644 test/api/file_load_test.js rename test/{interop => api}/interop_sanity_test.js (96%) diff --git a/test/any_grpc.js b/test/any_grpc.js index c36cc62aa..7360ac55b 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -1,11 +1,6 @@ -module.exports = { - packageJson: {}, - core: { - packageJson: {} - } -}; +const _ = require('lodash'); -function assignExportsFromGlobal(globalField, exportsField) { +function getImplementation(globalField) { if (global[globalField] !== 'js' && global[globalField] !== 'native') { throw new Error([ `Invalid value for global.${globalField}: ${global.globalField}.`, @@ -13,30 +8,28 @@ function assignExportsFromGlobal(globalField, exportsField) { ].join(' ')); } const impl = global[globalField]; - // (1) set global field. - module.exports[exportsField] = require(`../packages/grpc-${impl}`); - // (2) make package's package.json file accessible thru packageJson path. - module.exports.packageJson[exportsField] = require(`../packages/grpc-${impl}/package.json`); - // (3) make package's underlying core dependency accessible thru core path. - module.exports.core[exportsField] = require(`../packages/grpc-${impl}-core`); - // (4) make (3) x (2) accessible thru core.packageJson path. - module.exports.core.packageJson[exportsField] = require(`../packages/grpc-${impl}-core/package.json`); + return { + surface: require(`../packages/grpc-${impl}`), + pjson: require(`../packages/grpc-${impl}/package.json`), + core: require(`../packages/grpc-${impl}-core`), + corePjson: require(`../packages/grpc-${impl}-core/package.json`) + }; } -// Set 'server' and 'client' fields on this module's exports. -// These don't refer to the portions of the gRPC interface that are -// relevant to an application behaving as a server or a client respectively. -// Instead, they refer to the entire gRPC module as it's visible to the -// application. -// In other words, a test that simulates a gRPC client should treat -// require('any-grpc').client as the value of require('grpc'), and would simply -// not be expected to use server components. -assignExportsFromGlobal('_server_implementation', 'server'); -assignExportsFromGlobal('_client_implementation', 'client'); -// Increase clarity when there's no distinction between client/server -if (module.exports.client === module.exports.server) { - module.exports.all = module.exports.client; - module.exports.core.all = module.exports.core.client; - module.exports.packageJson.all = module.exports.packageJson.client; - module.exports.core.packageJson.all = module.exports.core.packageJson.client; -} +const clientImpl = getImplementation('_client_implementation'); +const serverImpl = getImplementation('_server_implementation'); + +// We export a "merged" gRPC API by merging client and server specified +// APIs together. Any function that is unspecific to client/server defaults +// to client-side implementation. +// This object also has a test-only field from which details about the +// modules may be read. +module.exports = Object.assign({ + '$implementationInfo': { + client: clientImpl, + server: serverImpl + } +}, clientImpl.surface, _.pick(serverImpl.surface, [ + 'Server', + 'ServerCredentials' +])); diff --git a/test/api/async_test.js b/test/api/async_test.js index c66f3782b..86cd62e21 100644 --- a/test/api/async_test.js +++ b/test/api/async_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('../any_grpc').all; +var grpc = require('../any_grpc'); var math = grpc.load( __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math; diff --git a/test/api/credentials_api_test.js b/test/api/credentials_api_test.js new file mode 100644 index 000000000..e79fca07b --- /dev/null +++ b/test/api/credentials_api_test.js @@ -0,0 +1,165 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); + +var grpc = require('../any_grpc'); + +var key_data, pem_data, ca_data; + +before(function() { + var key_path = path.join(__dirname, '../data/server1.key'); + var pem_path = path.join(__dirname, '../data/server1.pem'); + var ca_path = path.join(__dirname, '../data/ca.pem'); + key_data = fs.readFileSync(key_path); + pem_data = fs.readFileSync(pem_path); + ca_data = fs.readFileSync(ca_path); +}); + +describe('channel credentials', function() { + describe('#createSsl', function() { + it('works with no arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(); + }); + assert.notEqual(creds, null); + }); + it('works with just one Buffer argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data); + }); + assert.notEqual(creds, null); + }); + it('works with 3 Buffer arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); + }); + assert.notEqual(creds, null); + }); + it('works if the first argument is null', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(null, key_data, pem_data); + }); + assert.notEqual(creds, null); + }); + it('fails if the first argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl('test'); + }, TypeError); + }); + it('fails if the second argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, 'test', pem_data); + }, TypeError); + }); + it('fails if the third argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, key_data, 'test'); + }, TypeError); + }); + it('fails if only 1 of the last 2 arguments is provided', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, key_data); + }); + assert.throws(function() { + grpc.credentials.createSsl(null, null, pem_data); + }); + }); + }); +}); + +describe('server credentials', function() { + describe('#createSsl', function() { + it('accepts a buffer and array as the first 2 arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(ca_data, []); + }); + assert.notEqual(creds, null); + }); + it('accepts a boolean as the third argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(ca_data, [], true); + }); + assert.notEqual(creds, null); + }); + it('accepts an object with two buffers in the second argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}]); + }); + assert.notEqual(creds, null); + }); + it('accepts multiple objects in the second argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}, + {private_key: key_data, + cert_chain: pem_data}]); + }); + assert.notEqual(creds, null); + }); + it('fails if the second argument is not an Array', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, 'test'); + }, TypeError); + }); + it('fails if the first argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl('test', []); + }, TypeError); + }); + it('fails if the third argument is a non-boolean value', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, [], 'test'); + }, TypeError); + }); + it('fails if the array elements are not objects', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, 'test'); + }, TypeError); + }); + it('fails if the object does not have a Buffer private_key', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(null, + [{private_key: 'test', + cert_chain: pem_data}]); + }, TypeError); + }); + it('fails if the object does not have a Buffer cert_chain', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: 'test'}]); + }, TypeError); + }); + }); +}); \ No newline at end of file diff --git a/test/api/credentials_test.js b/test/api/credentials_test.js index 3bf3d5f51..e05ec7648 100644 --- a/test/api/credentials_test.js +++ b/test/api/credentials_test.js @@ -22,7 +22,7 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); -var grpc = require('../any_grpc').all; +var grpc = require('../any_grpc'); /** * This is used for testing functions with multiple asynchronous calls that diff --git a/test/api/file_load_test.js b/test/api/file_load_test.js new file mode 100644 index 000000000..c24a11002 --- /dev/null +++ b/test/api/file_load_test.js @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var grpc = require('../any_grpc'); + +describe('File loader', function() { + it('Should load a proto file by default', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.proto'); + }); + }); + it('Should load a proto file with the proto format', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.proto', 'proto'); + }); + }); + it('Should load a json file with the json format', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.json', 'json'); + }); + }); +}); diff --git a/test/interop/interop_sanity_test.js b/test/api/interop_sanity_test.js similarity index 96% rename from test/interop/interop_sanity_test.js rename to test/api/interop_sanity_test.js index 055a5ab75..b3f65a034 100644 --- a/test/interop/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -18,8 +18,8 @@ 'use strict'; -var interop_server = require('./interop_server.js'); -var interop_client = require('./interop_client.js'); +var interop_server = require('../interop/interop_server.js'); +var interop_client = require('../interop/interop_client.js'); var server; diff --git a/test/api/math/math_grpc_pb.js b/test/api/math/math_grpc_pb.js index 2a9b4aeb2..68001847c 100644 --- a/test/api/math/math_grpc_pb.js +++ b/test/api/math/math_grpc_pb.js @@ -16,7 +16,7 @@ // limitations under the License. // 'use strict'; -var grpc = require('../../any_grpc.js').all; +var grpc = require('../../any_grpc.js'); var math_math_pb = require('../math/math_pb.js'); function serialize_DivArgs(arg) { diff --git a/test/api/math/math_server.js b/test/api/math/math_server.js index 934006baf..70ad2dc56 100644 --- a/test/api/math/math_server.js +++ b/test/api/math/math_server.js @@ -18,7 +18,7 @@ 'use strict'; -var grpc = require('../../any_grpc.js').all; +var grpc = require('../../any_grpc.js'); var grpcMath = require('./math_grpc_pb'); var math = require('./math_pb'); diff --git a/test/api/math_client_test.js b/test/api/math_client_test.js index 1f4f25e6d..f4ba09518 100644 --- a/test/api/math_client_test.js +++ b/test/api/math_client_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('../any_grpc').all; +var grpc = require('../any_grpc'); var math = require('./math/math_pb'); var MathClient = require('./math/math_grpc_pb').MathClient; diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js index 7187ee73c..7825383dd 100644 --- a/test/api/metadata_test.js +++ b/test/api/metadata_test.js @@ -18,7 +18,7 @@ 'use strict'; -var Metadata = require('../any_grpc').all.Metadata; +var Metadata = require('../any_grpc').Metadata; var assert = require('assert'); diff --git a/test/api/surface_test.js b/test/api/surface_test.js index fae414b89..83896a4e3 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -21,7 +21,7 @@ var assert = require('assert'); var _ = require('lodash'); -var grpc = require('../any_grpc').all; +var grpc = require('../any_grpc'); var MathClient = grpc.load( __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math.Math; @@ -485,12 +485,10 @@ describe('Echo metadata', function() { call.end(); }); it('shows the correct user-agent string', function(done) { - var version = require('../any_grpc').core.packageJson.all.version; + var version = require('../any_grpc')['$implementationInfo'].server.corePjson.version; var call = client.unary({}, metadata, function(err, data) { assert.ifError(err); }); call.on('metadata', function(metadata) { - console.log(version); - console.log(metadata.get('user-agent')[0]); assert(_.startsWith(metadata.get('user-agent')[0], 'grpc-node/' + version)); done(); diff --git a/test/gulpfile.js b/test/gulpfile.js index 6b2bc15b0..d1d06633f 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -52,14 +52,11 @@ gulp.task('internal.test.test', 'Run API-level tests', () => { .on('error', reject); }); const apiTestGlob = `${apiTestDir}/*.js`; - const interopTestGlob = `${testDir}/interop/interop_sanity_test.js`; const runTestsArgPairs = [ [apiTestGlob, 'native_native'], - // [apiTestGlob, 'js_js'], - [interopTestGlob, 'native_native'], - // [interopTestGlob, 'native_js'], - // [interopTestGlob, 'js_native'], - // [interopTestGlob, 'js_js'] + // [apiTestGlob, 'native_js'], + // [apiTestGlob, 'js_native'], + // [apiTestGlob, 'js_js'] ]; return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 70597dd5b..73b84c38c 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -20,7 +20,7 @@ var fs = require('fs'); var path = require('path'); -var grpc = require('../any_grpc').client; +var grpc = require('../any_grpc')['$implementationInfo'].client.surface; var testProto = grpc.load({ root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index edec7a9da..fe1222dd3 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -22,7 +22,7 @@ var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); -var grpc = require('../any_grpc').server; +var grpc = require('../any_grpc')['$implementationInfo'].server.surface; var testProto = grpc.load({ root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; From d6711c4d24d4ce488f7f1bd25c45e94b17bcc151 Mon Sep 17 00:00:00 2001 From: James Sherwood-Jones Date: Wed, 8 Nov 2017 09:41:55 +0000 Subject: [PATCH 0023/1899] Fixed name of ServerCredentials.createSsl in native docs & types. --- packages/grpc-native-core/index.d.ts | 2 +- packages/grpc-native-core/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index f3a091eb5..0bb5a9f43 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -527,7 +527,7 @@ declare module "grpc" { * Defaults to `false`. * @return The ServerCredentials */ - static createInsecure(rootCerts: Buffer | null, keyCertPairs: KeyCertPair[], checkClientCertificate?: boolean): ServerCredentials; + static createSsl(rootCerts: Buffer | null, keyCertPairs: KeyCertPair[], checkClientCertificate?: boolean): ServerCredentials; } /** diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index af597f708..7810b7bff 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -225,7 +225,7 @@ exports.ServerCredentials = grpc.ServerCredentials; /** * Create SSL server credentials - * @name grpc.ServerCredentials.createInsecure + * @name grpc.ServerCredentials.createSsl * @kind function * @param {?Buffer} rootCerts Root CA certificates for validating client * certificates From 93cfa4b60b7c4c0aff14db291b8e5c3290caf426 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 Nov 2017 09:40:51 -0800 Subject: [PATCH 0024/1899] Update submodule to head, and update templates to match --- packages/grpc-native-core/binding.gyp | 607 +++++++++--------- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 14 +- .../templates/binding.gyp.template | 42 +- .../templates/package.json.template | 16 +- 5 files changed, 323 insertions(+), 358 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index c8609a962..b9149669d 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -63,6 +63,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', ], 'ldflags': [ '-g', @@ -185,6 +186,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -194,6 +196,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Ithird_party/abseil-cpp', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' @@ -598,52 +601,51 @@ 'dependencies': [ ], 'sources': [ - 'deps/grpc/src/core/lib/profiling/basic_timers.c', - 'deps/grpc/src/core/lib/profiling/stap_timers.c', - 'deps/grpc/src/core/lib/support/alloc.c', - 'deps/grpc/src/core/lib/support/arena.c', - 'deps/grpc/src/core/lib/support/atm.c', - 'deps/grpc/src/core/lib/support/avl.c', - 'deps/grpc/src/core/lib/support/backoff.c', - 'deps/grpc/src/core/lib/support/cmdline.c', - 'deps/grpc/src/core/lib/support/cpu_iphone.c', - 'deps/grpc/src/core/lib/support/cpu_linux.c', - 'deps/grpc/src/core/lib/support/cpu_posix.c', - 'deps/grpc/src/core/lib/support/cpu_windows.c', - 'deps/grpc/src/core/lib/support/env_linux.c', - 'deps/grpc/src/core/lib/support/env_posix.c', - 'deps/grpc/src/core/lib/support/env_windows.c', - 'deps/grpc/src/core/lib/support/histogram.c', - 'deps/grpc/src/core/lib/support/host_port.c', - 'deps/grpc/src/core/lib/support/log.c', - 'deps/grpc/src/core/lib/support/log_android.c', - 'deps/grpc/src/core/lib/support/log_linux.c', - 'deps/grpc/src/core/lib/support/log_posix.c', - 'deps/grpc/src/core/lib/support/log_windows.c', - 'deps/grpc/src/core/lib/support/mpscq.c', - 'deps/grpc/src/core/lib/support/murmur_hash.c', - 'deps/grpc/src/core/lib/support/stack_lockfree.c', - 'deps/grpc/src/core/lib/support/string.c', - 'deps/grpc/src/core/lib/support/string_posix.c', - 'deps/grpc/src/core/lib/support/string_util_windows.c', - 'deps/grpc/src/core/lib/support/string_windows.c', - 'deps/grpc/src/core/lib/support/subprocess_posix.c', - 'deps/grpc/src/core/lib/support/subprocess_windows.c', - 'deps/grpc/src/core/lib/support/sync.c', - 'deps/grpc/src/core/lib/support/sync_posix.c', - 'deps/grpc/src/core/lib/support/sync_windows.c', - 'deps/grpc/src/core/lib/support/thd.c', - 'deps/grpc/src/core/lib/support/thd_posix.c', - 'deps/grpc/src/core/lib/support/thd_windows.c', - 'deps/grpc/src/core/lib/support/time.c', - 'deps/grpc/src/core/lib/support/time_posix.c', - 'deps/grpc/src/core/lib/support/time_precise.c', - 'deps/grpc/src/core/lib/support/time_windows.c', - 'deps/grpc/src/core/lib/support/tls_pthread.c', - 'deps/grpc/src/core/lib/support/tmpfile_msys.c', - 'deps/grpc/src/core/lib/support/tmpfile_posix.c', - 'deps/grpc/src/core/lib/support/tmpfile_windows.c', - 'deps/grpc/src/core/lib/support/wrap_memcpy.c', + 'deps/grpc/src/core/lib/profiling/basic_timers.cc', + 'deps/grpc/src/core/lib/profiling/stap_timers.cc', + 'deps/grpc/src/core/lib/support/alloc.cc', + 'deps/grpc/src/core/lib/support/arena.cc', + 'deps/grpc/src/core/lib/support/atm.cc', + 'deps/grpc/src/core/lib/support/avl.cc', + 'deps/grpc/src/core/lib/support/cmdline.cc', + 'deps/grpc/src/core/lib/support/cpu_iphone.cc', + 'deps/grpc/src/core/lib/support/cpu_linux.cc', + 'deps/grpc/src/core/lib/support/cpu_posix.cc', + 'deps/grpc/src/core/lib/support/cpu_windows.cc', + 'deps/grpc/src/core/lib/support/env_linux.cc', + 'deps/grpc/src/core/lib/support/env_posix.cc', + 'deps/grpc/src/core/lib/support/env_windows.cc', + 'deps/grpc/src/core/lib/support/histogram.cc', + 'deps/grpc/src/core/lib/support/host_port.cc', + 'deps/grpc/src/core/lib/support/log.cc', + 'deps/grpc/src/core/lib/support/log_android.cc', + 'deps/grpc/src/core/lib/support/log_linux.cc', + 'deps/grpc/src/core/lib/support/log_posix.cc', + 'deps/grpc/src/core/lib/support/log_windows.cc', + 'deps/grpc/src/core/lib/support/mpscq.cc', + 'deps/grpc/src/core/lib/support/murmur_hash.cc', + 'deps/grpc/src/core/lib/support/stack_lockfree.cc', + 'deps/grpc/src/core/lib/support/string.cc', + 'deps/grpc/src/core/lib/support/string_posix.cc', + 'deps/grpc/src/core/lib/support/string_util_windows.cc', + 'deps/grpc/src/core/lib/support/string_windows.cc', + 'deps/grpc/src/core/lib/support/subprocess_posix.cc', + 'deps/grpc/src/core/lib/support/subprocess_windows.cc', + 'deps/grpc/src/core/lib/support/sync.cc', + 'deps/grpc/src/core/lib/support/sync_posix.cc', + 'deps/grpc/src/core/lib/support/sync_windows.cc', + 'deps/grpc/src/core/lib/support/thd.cc', + 'deps/grpc/src/core/lib/support/thd_posix.cc', + 'deps/grpc/src/core/lib/support/thd_windows.cc', + 'deps/grpc/src/core/lib/support/time.cc', + 'deps/grpc/src/core/lib/support/time_posix.cc', + 'deps/grpc/src/core/lib/support/time_precise.cc', + 'deps/grpc/src/core/lib/support/time_windows.cc', + 'deps/grpc/src/core/lib/support/tls_pthread.cc', + 'deps/grpc/src/core/lib/support/tmpfile_msys.cc', + 'deps/grpc/src/core/lib/support/tmpfile_posix.cc', + 'deps/grpc/src/core/lib/support/tmpfile_windows.cc', + 'deps/grpc/src/core/lib/support/wrap_memcpy.cc', ], 'conditions': [ ['OS == "mac"', { @@ -661,267 +663,256 @@ 'gpr', ], 'sources': [ - 'deps/grpc/src/core/lib/surface/init.c', - 'deps/grpc/src/core/lib/channel/channel_args.c', - 'deps/grpc/src/core/lib/channel/channel_stack.c', - 'deps/grpc/src/core/lib/channel/channel_stack_builder.c', - 'deps/grpc/src/core/lib/channel/connected_channel.c', - 'deps/grpc/src/core/lib/channel/handshaker.c', - 'deps/grpc/src/core/lib/channel/handshaker_factory.c', - 'deps/grpc/src/core/lib/channel/handshaker_registry.c', - 'deps/grpc/src/core/lib/compression/compression.c', - 'deps/grpc/src/core/lib/compression/message_compress.c', - 'deps/grpc/src/core/lib/compression/stream_compression.c', - 'deps/grpc/src/core/lib/compression/stream_compression_gzip.c', - 'deps/grpc/src/core/lib/compression/stream_compression_identity.c', - 'deps/grpc/src/core/lib/debug/stats.c', - 'deps/grpc/src/core/lib/debug/stats_data.c', - 'deps/grpc/src/core/lib/http/format_request.c', - 'deps/grpc/src/core/lib/http/httpcli.c', - 'deps/grpc/src/core/lib/http/parser.c', - 'deps/grpc/src/core/lib/iomgr/call_combiner.c', - 'deps/grpc/src/core/lib/iomgr/closure.c', - 'deps/grpc/src/core/lib/iomgr/combiner.c', - 'deps/grpc/src/core/lib/iomgr/endpoint.c', - 'deps/grpc/src/core/lib/iomgr/endpoint_pair_posix.c', - 'deps/grpc/src/core/lib/iomgr/endpoint_pair_uv.c', - 'deps/grpc/src/core/lib/iomgr/endpoint_pair_windows.c', - 'deps/grpc/src/core/lib/iomgr/error.c', - 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.c', - 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.c', - 'deps/grpc/src/core/lib/iomgr/ev_epollsig_linux.c', - 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.c', - 'deps/grpc/src/core/lib/iomgr/ev_posix.c', - 'deps/grpc/src/core/lib/iomgr/ev_windows.c', - 'deps/grpc/src/core/lib/iomgr/exec_ctx.c', - 'deps/grpc/src/core/lib/iomgr/executor.c', - 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.c', - 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.c', - 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.c', - 'deps/grpc/src/core/lib/iomgr/iocp_windows.c', - 'deps/grpc/src/core/lib/iomgr/iomgr.c', - 'deps/grpc/src/core/lib/iomgr/iomgr_posix.c', - 'deps/grpc/src/core/lib/iomgr/iomgr_uv.c', - 'deps/grpc/src/core/lib/iomgr/iomgr_windows.c', - 'deps/grpc/src/core/lib/iomgr/is_epollexclusive_available.c', - 'deps/grpc/src/core/lib/iomgr/load_file.c', - 'deps/grpc/src/core/lib/iomgr/lockfree_event.c', - 'deps/grpc/src/core/lib/iomgr/network_status_tracker.c', - 'deps/grpc/src/core/lib/iomgr/polling_entity.c', - 'deps/grpc/src/core/lib/iomgr/pollset_set_uv.c', - 'deps/grpc/src/core/lib/iomgr/pollset_set_windows.c', - 'deps/grpc/src/core/lib/iomgr/pollset_uv.c', - 'deps/grpc/src/core/lib/iomgr/pollset_windows.c', - 'deps/grpc/src/core/lib/iomgr/resolve_address_posix.c', - 'deps/grpc/src/core/lib/iomgr/resolve_address_uv.c', - 'deps/grpc/src/core/lib/iomgr/resolve_address_windows.c', - 'deps/grpc/src/core/lib/iomgr/resource_quota.c', - 'deps/grpc/src/core/lib/iomgr/sockaddr_utils.c', - 'deps/grpc/src/core/lib/iomgr/socket_factory_posix.c', - 'deps/grpc/src/core/lib/iomgr/socket_mutator.c', - 'deps/grpc/src/core/lib/iomgr/socket_utils_common_posix.c', - 'deps/grpc/src/core/lib/iomgr/socket_utils_linux.c', - 'deps/grpc/src/core/lib/iomgr/socket_utils_posix.c', - 'deps/grpc/src/core/lib/iomgr/socket_utils_uv.c', - 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.c', - 'deps/grpc/src/core/lib/iomgr/socket_windows.c', - 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.c', - 'deps/grpc/src/core/lib/iomgr/tcp_client_uv.c', - 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.c', - 'deps/grpc/src/core/lib/iomgr/tcp_posix.c', - 'deps/grpc/src/core/lib/iomgr/tcp_server_posix.c', - 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.c', - 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.c', - 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.c', - 'deps/grpc/src/core/lib/iomgr/tcp_server_uv.c', - 'deps/grpc/src/core/lib/iomgr/tcp_server_windows.c', - 'deps/grpc/src/core/lib/iomgr/tcp_uv.c', - 'deps/grpc/src/core/lib/iomgr/tcp_windows.c', - 'deps/grpc/src/core/lib/iomgr/time_averaged_stats.c', - 'deps/grpc/src/core/lib/iomgr/timer_generic.c', - 'deps/grpc/src/core/lib/iomgr/timer_heap.c', - 'deps/grpc/src/core/lib/iomgr/timer_manager.c', - 'deps/grpc/src/core/lib/iomgr/timer_uv.c', - 'deps/grpc/src/core/lib/iomgr/udp_server.c', - 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix.c', - 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.c', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_cv.c', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.c', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.c', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_pipe.c', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_posix.c', - 'deps/grpc/src/core/lib/json/json.c', - 'deps/grpc/src/core/lib/json/json_reader.c', - 'deps/grpc/src/core/lib/json/json_string.c', - 'deps/grpc/src/core/lib/json/json_writer.c', - 'deps/grpc/src/core/lib/slice/b64.c', - 'deps/grpc/src/core/lib/slice/percent_encoding.c', - 'deps/grpc/src/core/lib/slice/slice.c', - 'deps/grpc/src/core/lib/slice/slice_buffer.c', - 'deps/grpc/src/core/lib/slice/slice_hash_table.c', - 'deps/grpc/src/core/lib/slice/slice_intern.c', - 'deps/grpc/src/core/lib/slice/slice_string_helpers.c', - 'deps/grpc/src/core/lib/surface/alarm.c', - 'deps/grpc/src/core/lib/surface/api_trace.c', - 'deps/grpc/src/core/lib/surface/byte_buffer.c', - 'deps/grpc/src/core/lib/surface/byte_buffer_reader.c', - 'deps/grpc/src/core/lib/surface/call.c', - 'deps/grpc/src/core/lib/surface/call_details.c', - 'deps/grpc/src/core/lib/surface/call_log_batch.c', - 'deps/grpc/src/core/lib/surface/channel.c', - 'deps/grpc/src/core/lib/surface/channel_init.c', - 'deps/grpc/src/core/lib/surface/channel_ping.c', - 'deps/grpc/src/core/lib/surface/channel_stack_type.c', - 'deps/grpc/src/core/lib/surface/completion_queue.c', - 'deps/grpc/src/core/lib/surface/completion_queue_factory.c', - 'deps/grpc/src/core/lib/surface/event_string.c', + 'deps/grpc/src/core/lib/surface/init.cc', + 'deps/grpc/src/core/lib/backoff/backoff.cc', + 'deps/grpc/src/core/lib/channel/channel_args.cc', + 'deps/grpc/src/core/lib/channel/channel_stack.cc', + 'deps/grpc/src/core/lib/channel/channel_stack_builder.cc', + 'deps/grpc/src/core/lib/channel/connected_channel.cc', + 'deps/grpc/src/core/lib/channel/handshaker.cc', + 'deps/grpc/src/core/lib/channel/handshaker_factory.cc', + 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', + 'deps/grpc/src/core/lib/compression/compression.cc', + 'deps/grpc/src/core/lib/compression/message_compress.cc', + 'deps/grpc/src/core/lib/compression/stream_compression.cc', + 'deps/grpc/src/core/lib/compression/stream_compression_gzip.cc', + 'deps/grpc/src/core/lib/compression/stream_compression_identity.cc', + 'deps/grpc/src/core/lib/debug/stats.cc', + 'deps/grpc/src/core/lib/debug/stats_data.cc', + 'deps/grpc/src/core/lib/http/format_request.cc', + 'deps/grpc/src/core/lib/http/httpcli.cc', + 'deps/grpc/src/core/lib/http/parser.cc', + 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', + 'deps/grpc/src/core/lib/iomgr/closure.cc', + 'deps/grpc/src/core/lib/iomgr/combiner.cc', + 'deps/grpc/src/core/lib/iomgr/endpoint.cc', + 'deps/grpc/src/core/lib/iomgr/endpoint_pair_posix.cc', + 'deps/grpc/src/core/lib/iomgr/endpoint_pair_uv.cc', + 'deps/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc', + 'deps/grpc/src/core/lib/iomgr/error.cc', + 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc', + 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.cc', + 'deps/grpc/src/core/lib/iomgr/ev_epollsig_linux.cc', + 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.cc', + 'deps/grpc/src/core/lib/iomgr/ev_posix.cc', + 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', + 'deps/grpc/src/core/lib/iomgr/exec_ctx.cc', + 'deps/grpc/src/core/lib/iomgr/executor.cc', + 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', + 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', + 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', + 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_posix.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_uv.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_windows.cc', + 'deps/grpc/src/core/lib/iomgr/is_epollexclusive_available.cc', + 'deps/grpc/src/core/lib/iomgr/load_file.cc', + 'deps/grpc/src/core/lib/iomgr/lockfree_event.cc', + 'deps/grpc/src/core/lib/iomgr/network_status_tracker.cc', + 'deps/grpc/src/core/lib/iomgr/polling_entity.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_set_uv.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_set_windows.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_uv.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_windows.cc', + 'deps/grpc/src/core/lib/iomgr/resolve_address_posix.cc', + 'deps/grpc/src/core/lib/iomgr/resolve_address_uv.cc', + 'deps/grpc/src/core/lib/iomgr/resolve_address_windows.cc', + 'deps/grpc/src/core/lib/iomgr/resource_quota.cc', + 'deps/grpc/src/core/lib/iomgr/sockaddr_utils.cc', + 'deps/grpc/src/core/lib/iomgr/socket_factory_posix.cc', + 'deps/grpc/src/core/lib/iomgr/socket_mutator.cc', + 'deps/grpc/src/core/lib/iomgr/socket_utils_common_posix.cc', + 'deps/grpc/src/core/lib/iomgr/socket_utils_linux.cc', + 'deps/grpc/src/core/lib/iomgr/socket_utils_posix.cc', + 'deps/grpc/src/core/lib/iomgr/socket_utils_uv.cc', + 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.cc', + 'deps/grpc/src/core/lib/iomgr/socket_windows.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_uv.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_posix.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_posix.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_uv.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_windows.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_uv.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_windows.cc', + 'deps/grpc/src/core/lib/iomgr/time_averaged_stats.cc', + 'deps/grpc/src/core/lib/iomgr/timer_generic.cc', + 'deps/grpc/src/core/lib/iomgr/timer_heap.cc', + 'deps/grpc/src/core/lib/iomgr/timer_manager.cc', + 'deps/grpc/src/core/lib/iomgr/timer_uv.cc', + 'deps/grpc/src/core/lib/iomgr/udp_server.cc', + 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix.cc', + 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc', + 'deps/grpc/src/core/lib/iomgr/wakeup_fd_cv.cc', + 'deps/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc', + 'deps/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc', + 'deps/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc', + 'deps/grpc/src/core/lib/iomgr/wakeup_fd_posix.cc', + 'deps/grpc/src/core/lib/json/json.cc', + 'deps/grpc/src/core/lib/json/json_reader.cc', + 'deps/grpc/src/core/lib/json/json_string.cc', + 'deps/grpc/src/core/lib/json/json_writer.cc', + 'deps/grpc/src/core/lib/slice/b64.cc', + 'deps/grpc/src/core/lib/slice/percent_encoding.cc', + 'deps/grpc/src/core/lib/slice/slice.cc', + 'deps/grpc/src/core/lib/slice/slice_buffer.cc', + 'deps/grpc/src/core/lib/slice/slice_hash_table.cc', + 'deps/grpc/src/core/lib/slice/slice_intern.cc', + 'deps/grpc/src/core/lib/slice/slice_string_helpers.cc', + 'deps/grpc/src/core/lib/surface/alarm.cc', + 'deps/grpc/src/core/lib/surface/api_trace.cc', + 'deps/grpc/src/core/lib/surface/byte_buffer.cc', + 'deps/grpc/src/core/lib/surface/byte_buffer_reader.cc', + 'deps/grpc/src/core/lib/surface/call.cc', + 'deps/grpc/src/core/lib/surface/call_details.cc', + 'deps/grpc/src/core/lib/surface/call_log_batch.cc', + 'deps/grpc/src/core/lib/surface/channel.cc', + 'deps/grpc/src/core/lib/surface/channel_init.cc', + 'deps/grpc/src/core/lib/surface/channel_ping.cc', + 'deps/grpc/src/core/lib/surface/channel_stack_type.cc', + 'deps/grpc/src/core/lib/surface/completion_queue.cc', + 'deps/grpc/src/core/lib/surface/completion_queue_factory.cc', + 'deps/grpc/src/core/lib/surface/event_string.cc', 'deps/grpc/src/core/lib/surface/lame_client.cc', - 'deps/grpc/src/core/lib/surface/metadata_array.c', - 'deps/grpc/src/core/lib/surface/server.c', - 'deps/grpc/src/core/lib/surface/validate_metadata.c', - 'deps/grpc/src/core/lib/surface/version.c', - 'deps/grpc/src/core/lib/transport/bdp_estimator.c', - 'deps/grpc/src/core/lib/transport/byte_stream.c', - 'deps/grpc/src/core/lib/transport/connectivity_state.c', - 'deps/grpc/src/core/lib/transport/error_utils.c', - 'deps/grpc/src/core/lib/transport/metadata.c', - 'deps/grpc/src/core/lib/transport/metadata_batch.c', - 'deps/grpc/src/core/lib/transport/pid_controller.c', - 'deps/grpc/src/core/lib/transport/service_config.c', - 'deps/grpc/src/core/lib/transport/static_metadata.c', - 'deps/grpc/src/core/lib/transport/status_conversion.c', - 'deps/grpc/src/core/lib/transport/timeout_encoding.c', - 'deps/grpc/src/core/lib/transport/transport.c', - 'deps/grpc/src/core/lib/transport/transport_op_string.c', - 'deps/grpc/src/core/lib/debug/trace.c', - 'deps/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_decoder.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_encoder.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_plugin.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/flow_control.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_data.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_ping.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_settings.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_table.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/http2_settings.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/huffsyms.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/parsing.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/stream_lists.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/stream_map.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/varint.c', - 'deps/grpc/src/core/ext/transport/chttp2/transport/writing.c', - 'deps/grpc/src/core/ext/transport/chttp2/alpn/alpn.c', - 'deps/grpc/src/core/ext/filters/http/client/http_client_filter.c', - 'deps/grpc/src/core/ext/filters/http/http_filters_plugin.c', - 'deps/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.c', - 'deps/grpc/src/core/ext/filters/http/server/http_server_filter.c', - 'deps/grpc/src/core/lib/http/httpcli_security_connector.c', - 'deps/grpc/src/core/lib/security/context/security_context.c', - 'deps/grpc/src/core/lib/security/credentials/composite/composite_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/credentials.c', - 'deps/grpc/src/core/lib/security/credentials/credentials_metadata.c', - 'deps/grpc/src/core/lib/security/credentials/fake/fake_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/google_default/credentials_generic.c', - 'deps/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/iam/iam_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/jwt/json_token.c', - 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.c', - 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.c', - 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.c', - 'deps/grpc/src/core/lib/security/transport/client_auth_filter.c', - 'deps/grpc/src/core/lib/security/transport/lb_targets_info.c', - 'deps/grpc/src/core/lib/security/transport/secure_endpoint.c', - 'deps/grpc/src/core/lib/security/transport/security_connector.c', - 'deps/grpc/src/core/lib/security/transport/security_handshaker.c', - 'deps/grpc/src/core/lib/security/transport/server_auth_filter.c', - 'deps/grpc/src/core/lib/security/transport/tsi_error.c', - 'deps/grpc/src/core/lib/security/util/json_util.c', - 'deps/grpc/src/core/lib/surface/init_secure.c', - 'deps/grpc/src/core/tsi/fake_transport_security.c', - 'deps/grpc/src/core/tsi/gts_transport_security.c', - 'deps/grpc/src/core/tsi/ssl_transport_security.c', - 'deps/grpc/src/core/tsi/transport_security_grpc.c', - 'deps/grpc/src/core/tsi/transport_security.c', - 'deps/grpc/src/core/tsi/transport_security_adapter.c', - 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.c', - 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.c', - 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.c', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel.c', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.c', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.c', - 'deps/grpc/src/core/ext/filters/client_channel/connector.c', - 'deps/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.c', - 'deps/grpc/src/core/ext/filters/client_channel/http_proxy.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_factory.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.c', - 'deps/grpc/src/core/ext/filters/client_channel/parse_address.c', - 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.c', - 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver_factory.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.c', - 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.c', - 'deps/grpc/src/core/ext/filters/client_channel/subchannel.c', - 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.c', - 'deps/grpc/src/core/ext/filters/client_channel/uri_parser.c', - 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.c', - 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.c', - 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.c', - 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.c', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.c', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.c', - 'deps/grpc/src/core/ext/transport/inproc/inproc_plugin.c', - 'deps/grpc/src/core/ext/transport/inproc/inproc_transport.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.c', + 'deps/grpc/src/core/lib/surface/metadata_array.cc', + 'deps/grpc/src/core/lib/surface/server.cc', + 'deps/grpc/src/core/lib/surface/validate_metadata.cc', + 'deps/grpc/src/core/lib/surface/version.cc', + 'deps/grpc/src/core/lib/transport/bdp_estimator.cc', + 'deps/grpc/src/core/lib/transport/byte_stream.cc', + 'deps/grpc/src/core/lib/transport/connectivity_state.cc', + 'deps/grpc/src/core/lib/transport/error_utils.cc', + 'deps/grpc/src/core/lib/transport/metadata.cc', + 'deps/grpc/src/core/lib/transport/metadata_batch.cc', + 'deps/grpc/src/core/lib/transport/pid_controller.cc', + 'deps/grpc/src/core/lib/transport/service_config.cc', + 'deps/grpc/src/core/lib/transport/static_metadata.cc', + 'deps/grpc/src/core/lib/transport/status_conversion.cc', + 'deps/grpc/src/core/lib/transport/timeout_encoding.cc', + 'deps/grpc/src/core/lib/transport/transport.cc', + 'deps/grpc/src/core/lib/transport/transport_op_string.cc', + 'deps/grpc/src/core/lib/debug/trace.cc', + 'deps/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_decoder.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_encoder.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_ping.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_settings.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_table.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/http2_settings.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/huffsyms.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/parsing.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/stream_lists.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/stream_map.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/varint.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/writing.cc', + 'deps/grpc/src/core/ext/transport/chttp2/alpn/alpn.cc', + 'deps/grpc/src/core/ext/filters/http/client/http_client_filter.cc', + 'deps/grpc/src/core/ext/filters/http/http_filters_plugin.cc', + 'deps/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.cc', + 'deps/grpc/src/core/ext/filters/http/server/http_server_filter.cc', + 'deps/grpc/src/core/lib/http/httpcli_security_connector.cc', + 'deps/grpc/src/core/lib/security/context/security_context.cc', + 'deps/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/credentials_metadata.cc', + 'deps/grpc/src/core/lib/security/credentials/fake/fake_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/google_default/credentials_generic.cc', + 'deps/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/iam/iam_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/jwt/json_token.cc', + 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc', + 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', + 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', + 'deps/grpc/src/core/lib/security/transport/lb_targets_info.cc', + 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', + 'deps/grpc/src/core/lib/security/transport/security_connector.cc', + 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', + 'deps/grpc/src/core/lib/security/transport/server_auth_filter.cc', + 'deps/grpc/src/core/lib/security/transport/tsi_error.cc', + 'deps/grpc/src/core/lib/security/util/json_util.cc', + 'deps/grpc/src/core/lib/surface/init_secure.cc', + 'deps/grpc/src/core/tsi/fake_transport_security.cc', + 'deps/grpc/src/core/tsi/gts_transport_security.cc', + 'deps/grpc/src/core/tsi/ssl_transport_security.cc', + 'deps/grpc/src/core/tsi/transport_security_grpc.cc', + 'deps/grpc/src/core/tsi/transport_security.cc', + 'deps/grpc/src/core/tsi/transport_security_adapter.cc', + 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', + 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', + 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', + 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.cc', + 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc', + 'deps/grpc/src/core/ext/filters/client_channel/connector.cc', + 'deps/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc', + 'deps/grpc/src/core/ext/filters/client_channel/http_proxy.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_factory.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', + 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', + 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver_factory.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', + 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', + 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', + 'deps/grpc/src/core/ext/filters/client_channel/uri_parser.cc', + 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', + 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc', + 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', + 'deps/grpc/src/core/ext/transport/inproc/inproc_plugin.cc', + 'deps/grpc/src/core/ext/transport/inproc/inproc_transport.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'deps/grpc/third_party/nanopb/pb_common.c', 'deps/grpc/third_party/nanopb/pb_decode.c', 'deps/grpc/third_party/nanopb/pb_encode.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.c', - 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.c', - 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_plugin.c', - 'deps/grpc/src/core/ext/census/base_resources.c', - 'deps/grpc/src/core/ext/census/context.c', - 'deps/grpc/src/core/ext/census/gen/census.pb.c', - 'deps/grpc/src/core/ext/census/gen/trace_context.pb.c', - 'deps/grpc/src/core/ext/census/grpc_context.c', - 'deps/grpc/src/core/ext/census/grpc_filter.c', - 'deps/grpc/src/core/ext/census/grpc_plugin.c', - 'deps/grpc/src/core/ext/census/initialize.c', - 'deps/grpc/src/core/ext/census/intrusive_hash_map.c', - 'deps/grpc/src/core/ext/census/mlog.c', - 'deps/grpc/src/core/ext/census/operation.c', - 'deps/grpc/src/core/ext/census/placeholders.c', - 'deps/grpc/src/core/ext/census/resource.c', - 'deps/grpc/src/core/ext/census/trace_context.c', - 'deps/grpc/src/core/ext/census/tracing.c', - 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.c', - 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.c', - 'deps/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.c', - 'deps/grpc/src/core/ext/filters/workarounds/workaround_utils.c', - 'deps/grpc/src/core/plugin_registry/grpc_plugin_registry.c', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', + 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc', + 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc', + 'deps/grpc/src/core/ext/census/grpc_context.cc', + 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', + 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', + 'deps/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc', + 'deps/grpc/src/core/ext/filters/workarounds/workaround_utils.cc', + 'deps/grpc/src/core/plugin_registry/grpc_plugin_registry.cc', ], 'conditions': [ ['OS == "mac"', { @@ -964,17 +955,7 @@ ], "target_name": "grpc_node", "sources": [ - "ext/byte_buffer.cc", - "ext/call.cc", - "ext/call_credentials.cc", - "ext/channel.cc", - "ext/channel_credentials.cc", - "ext/completion_queue.cc", - "ext/node_grpc.cc", - "ext/server.cc", - "ext/server_credentials.cc", - "ext/slice.cc", - "ext/timeval.cc", + "'ext/'+f).join(' ')\")" ], "dependencies": [ "grpc", diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index ebae8a8c9..4d4fab1e6 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit ebae8a8c9f15425da8f07442642ca308f3c6612c +Subproject commit 4d4fab1e60c18e89635ce099b50defede5e3f026 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 435b6ecd8..f1b0d610e 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -56,13 +56,13 @@ "src/*.js", "ext/*.{cc,h}", "deps/grpc/include/grpc/**/*.h", - "deps/grpc/src/core/**/*.{c,h}", - "deps/grpc/src/boringssl/*.{c,h}", - "deps/grpc/third_party/nanopb/*.{c,h}", - "deps/grpc/third_party/zlib/**/*.{c,h}", - "deps/grpc/third_party/boringssl/crypto/**/*.{c,h}", - "deps/grpc/third_party/boringssl/include/**/*.{c,h}", - "deps/grpc/third_party/boringssl/ssl/**/*.{c,h}", + "deps/grpc/src/core/**/*.{c,cc,h}", + "deps/grpc/src/boringssl/*.{c,cc,h}", + "deps/grpc/third_party/nanopb/*.{c,cc,h}", + "deps/grpc/third_party/zlib/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "binding.gyp" ], diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 6e71f28c5..18407998e 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -188,9 +188,8 @@ 'conditions': [ ['OS=="win" or runtime=="electron"', { 'targets': [ - % for module in node_modules: % for lib in libs: - % if lib.name in module.transitive_deps and lib.name == 'boringssl': + % if lib.name == 'boringssl': { 'target_name': '${lib.name}', 'product_prefix': 'lib', @@ -218,7 +217,6 @@ }, % endif % endfor - % endfor ], }], ['OS == "win" and runtime!="electron"', { @@ -254,9 +252,8 @@ ['OS == "win"', { 'targets': [ # Only want to compile zlib under Windows - % for module in node_modules: % for lib in libs: - % if lib.name in module.transitive_deps and lib.name == 'z': + % if lib.name == 'z': { 'target_name': '${lib.name}', 'product_prefix': 'lib', @@ -274,14 +271,14 @@ }, % endif % endfor - % endfor ] }] ], 'targets': [ - % for module in node_modules: + % for core in libs: + % if core.name == 'grpc': % for lib in libs: - % if lib.name in module.transitive_deps and lib.name not in ('boringssl', 'z'): + % if lib.name == core.name or (lib.name in core.transitive_deps and lib.name not in ('boringssl', 'z')): { 'target_name': '${lib.name}', 'product_prefix': 'lib', @@ -306,6 +303,8 @@ }, % endif % endfor + % endif + % endfor { 'include_dirs': [ "'ext/'+f).join(' ')\")" ], "dependencies": [ - % for dep in getattr(module, 'deps', []): - % if dep not in ('boringssl', 'z'): - "${dep}", - % endif - % endfor + "grpc", + "gpr", ] }, - % endfor { "target_name": "action_after_build", "type": "none", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 1be036070..2c52f5b77 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -2,7 +2,7 @@ --- | { "name": "grpc", - "version": "${settings.node_version}", + "version": "${settings.version}", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", @@ -58,13 +58,13 @@ "src/*.js", "ext/*.{cc,h}", "deps/grpc/include/grpc/**/*.h", - "deps/grpc/src/core/**/*.{c,h}", - "deps/grpc/src/boringssl/*.{c,h}", - "deps/grpc/third_party/nanopb/*.{c,h}", - "deps/grpc/third_party/zlib/**/*.{c,h}", - "deps/grpc/third_party/boringssl/crypto/**/*.{c,h}", - "deps/grpc/third_party/boringssl/include/**/*.{c,h}", - "deps/grpc/third_party/boringssl/ssl/**/*.{c,h}", + "deps/grpc/src/core/**/*.{c,cc,h}", + "deps/grpc/src/boringssl/*.{c,cc,h}", + "deps/grpc/third_party/nanopb/*.{c,cc,h}", + "deps/grpc/third_party/zlib/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "binding.gyp" ], From 2c625feb9fd12c4c01602483f199e50b5eac5a90 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 9 Nov 2017 10:50:40 -0800 Subject: [PATCH 0025/1899] use client's user agent; small changes in test gulpfile; add TODO --- test/any_grpc.js | 4 ++++ test/api/surface_test.js | 2 +- test/gulpfile.js | 19 +++++++++---------- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/test/any_grpc.js b/test/any_grpc.js index 7360ac55b..d6d008c29 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -1,3 +1,7 @@ +// TODO: Instead of attempting to expose both implementations of gRPC in +// a single object, the tests should be re-written in a way that makes it clear +// that two separate implementations are being tested against one another. + const _ = require('lodash'); function getImplementation(globalField) { diff --git a/test/api/surface_test.js b/test/api/surface_test.js index 83896a4e3..5fdcbcfb7 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -485,7 +485,7 @@ describe('Echo metadata', function() { call.end(); }); it('shows the correct user-agent string', function(done) { - var version = require('../any_grpc')['$implementationInfo'].server.corePjson.version; + var version = require('../any_grpc')['$implementationInfo'].client.corePjson.version; var call = client.unary({}, metadata, function(err, data) { assert.ifError(err); }); call.on('metadata', function(metadata) { diff --git a/test/gulpfile.js b/test/gulpfile.js index d1d06633f..1c70056e2 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -38,11 +38,11 @@ gulp.task('internal.test.clean.all', 'Delete all files created by tasks', () => gulp.task('internal.test.test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream - const runTestsWithFixture = (glob, fixture) => new Promise((resolve, reject) => { - const server = fixture.split('_')[0]; - const client = fixture.split('_')[1]; - console.log(`Running ${glob} with ${server} server + ${client} client`); - gulp.src(glob) + const apiTestGlob = `${apiTestDir}/*.js`; + const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { + const fixture = `${server}_${client}`; + console.log(`Running ${apiTestGlob} with ${server} server + ${client} client`); + gulp.src(apiTestGlob) .pipe(mocha({ reporter: 'mocha-jenkins-reporter', require: `${testDir}/fixtures/${fixture}.js` @@ -51,12 +51,11 @@ gulp.task('internal.test.test', 'Run API-level tests', () => { .on('end', resolve) .on('error', reject); }); - const apiTestGlob = `${apiTestDir}/*.js`; const runTestsArgPairs = [ - [apiTestGlob, 'native_native'], - // [apiTestGlob, 'native_js'], - // [apiTestGlob, 'js_native'], - // [apiTestGlob, 'js_js'] + ['native', 'native'], + // ['native', 'js'], + // ['js', 'native'], + // ['js', 'js'] ]; return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); From 6be2268e3581d6bbc8488a337b9b1f13fa70a203 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 Nov 2017 11:00:17 -0800 Subject: [PATCH 0026/1899] Update submodule again to get a bugfix --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 4d4fab1e6..3a54b8673 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 4d4fab1e60c18e89635ce099b50defede5e3f026 +Subproject commit 3a54b8673eed472679b11bb463cfcaf50ba6e282 From 1ceb2594014b52bf8c0e940c7c3b15b9bf089621 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 10 Nov 2017 09:28:38 -0800 Subject: [PATCH 0027/1899] Skip a test suite that appears to be triggering a core assertion failure --- packages/grpc-native-core/test/channel_test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/channel_test.js b/packages/grpc-native-core/test/channel_test.js index 373c5ac3c..f9afa0be2 100644 --- a/packages/grpc-native-core/test/channel_test.js +++ b/packages/grpc-native-core/test/channel_test.js @@ -132,7 +132,8 @@ describe('channel', function() { grpc.connectivityState.IDLE); }); }); - describe('watchConnectivityState', function() { + // This suite test appears to be triggering grpc/grpc#12932; skipping for now + describe.skip('watchConnectivityState', function() { var channel; beforeEach(function() { channel = new grpc.Channel('localhost', insecureCreds, {}); From ca50f660b79c44deefe8380100b4f1eefe1c8ca5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 14 Nov 2017 15:56:12 -0800 Subject: [PATCH 0028/1899] Fix a credentials plugin test to match changes in core --- packages/grpc-native-core/deps/grpc | 2 +- test/api/credentials_test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 3a54b8673..638c40c9e 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 3a54b8673eed472679b11bb463cfcaf50ba6e282 +Subproject commit 638c40c9eff83508fb17e8c0962f01fe24492b38 diff --git a/test/api/credentials_test.js b/test/api/credentials_test.js index e05ec7648..729a5a9c9 100644 --- a/test/api/credentials_test.js +++ b/test/api/credentials_test.js @@ -306,7 +306,7 @@ describe('client credentials', function() { done(); }); }); - it('should propagate errors that the updater emits', function(done) { + it('should fail the call if the updater fails', function(done) { var metadataUpdater = function(service_url, callback) { var error = new Error('Authentication error'); error.code = grpc.status.UNAUTHENTICATED; @@ -322,7 +322,7 @@ describe('client credentials', function() { assert.strictEqual(err.message, 'Getting metadata from plugin failed with error: ' + 'Authentication error'); - assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED); + assert.notStrictEqual(err.code, grpc.status.OK); done(); }); }); From 45a3ac256cb5642069b359da72bf1fdbc6e362aa Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 16 Nov 2017 09:51:32 -0800 Subject: [PATCH 0029/1899] Remove now-incorrect assertion in completion queue wrapper --- packages/grpc-native-core/ext/completion_queue.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-native-core/ext/completion_queue.cc b/packages/grpc-native-core/ext/completion_queue.cc index 0cee1a754..7a149532d 100644 --- a/packages/grpc-native-core/ext/completion_queue.cc +++ b/packages/grpc-native-core/ext/completion_queue.cc @@ -64,7 +64,6 @@ grpc_completion_queue *GetCompletionQueue() { return queue; } void CompletionQueueNext() { if (pending_batches == 0) { - GPR_ASSERT(!uv_is_active((uv_handle_t *)&prepare)); uv_prepare_start(&prepare, drain_completion_queue); } pending_batches++; From 452abe73b2da7b38e0b889574e72b3bebdd35bfb Mon Sep 17 00:00:00 2001 From: "Bernhard K. Weisshuhn" Date: Mon, 6 Nov 2017 15:44:52 +0100 Subject: [PATCH 0030/1899] =?UTF-8?q?Build=20different=20binaries=20for=20?= =?UTF-8?q?different=20libc=E2=80=99s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #81 --- packages/grpc-native-core/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f3fb57135..687529e53 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -43,10 +43,10 @@ }, "binary": { "module_name": "grpc_node", - "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}", + "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", "host": "https://storage.googleapis.com/", "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", - "package_name": "{node_abi}-{platform}-{arch}.tar.gz" + "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" }, "files": [ "LICENSE", From d4e12d1dbb87a801a828bda34c1132399f0f430d Mon Sep 17 00:00:00 2001 From: "Bernhard K. Weisshuhn" Date: Tue, 7 Nov 2017 08:31:19 +0100 Subject: [PATCH 0031/1899] Add libc variable to binary paths in package.json template --- packages/grpc-native-core/templates/package.json.template | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index d8a5fb74b..f3d471c52 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -45,10 +45,10 @@ }, "binary": { "module_name": "grpc_node", - "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}", + "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", "host": "https://storage.googleapis.com/", "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", - "package_name": "{node_abi}-{platform}-{arch}.tar.gz" + "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" }, "files": [ "LICENSE", From 2f7201a2853e8fc31729aa9389bd506446fab20c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 17 Nov 2017 10:28:07 -0800 Subject: [PATCH 0032/1899] Update the submodule and unskip previously failing test --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/test/channel_test.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 3a54b8673..5dc3cc1b0 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 3a54b8673eed472679b11bb463cfcaf50ba6e282 +Subproject commit 5dc3cc1b01e908b5635e43a39bd914516c2a0071 diff --git a/packages/grpc-native-core/test/channel_test.js b/packages/grpc-native-core/test/channel_test.js index f9afa0be2..373c5ac3c 100644 --- a/packages/grpc-native-core/test/channel_test.js +++ b/packages/grpc-native-core/test/channel_test.js @@ -132,8 +132,7 @@ describe('channel', function() { grpc.connectivityState.IDLE); }); }); - // This suite test appears to be triggering grpc/grpc#12932; skipping for now - describe.skip('watchConnectivityState', function() { + describe('watchConnectivityState', function() { var channel; beforeEach(function() { channel = new grpc.Channel('localhost', insecureCreds, {}); From 66aeac683d7908f843f117e7981f36d71fde6a9a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 17 Nov 2017 12:36:41 -0800 Subject: [PATCH 0033/1899] Update submodule to master --- packages/grpc-native-core/binding.gyp | 1 - packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b9149669d..27403b5aa 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -683,7 +683,6 @@ 'deps/grpc/src/core/lib/http/httpcli.cc', 'deps/grpc/src/core/lib/http/parser.cc', 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', - 'deps/grpc/src/core/lib/iomgr/closure.cc', 'deps/grpc/src/core/lib/iomgr/combiner.cc', 'deps/grpc/src/core/lib/iomgr/endpoint.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_posix.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 5dc3cc1b0..dbca3d9b7 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 5dc3cc1b01e908b5635e43a39bd914516c2a0071 +Subproject commit dbca3d9b765b8e13ead6327fdd4904fe0fa05c84 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 782d58aca..91498375b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -31,7 +31,7 @@ "arguejs": "^0.2.3", "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.6.39", + "node-pre-gyp": "^0.6.35", "protobufjs": "^5.0.0" }, "devDependencies": { From 087d67441bdbb89cc71bbd097fb5c5a2e809da5e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Nov 2017 13:15:34 -0800 Subject: [PATCH 0034/1899] Add alpine build script and Dockerfile, improve existing build scripts --- .../tools/docker/alpine_artifact/Dockerfile | 2 + .../artifacts/build_all_linux_artifacts.sh | 38 +++++++++++++++++++ .../artifacts/build_artifact_node.bat | 26 +++++++------ .../artifacts/build_artifact_node.sh | 34 ++++++++--------- .../artifacts/build_artifact_node_arm.sh | 36 ++++++++++++++++++ 5 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile create mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh create mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh diff --git a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile new file mode 100644 index 000000000..7898a08df --- /dev/null +++ b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile @@ -0,0 +1,2 @@ +FROM node:8-alpine +RUN apk add --no-cache python curl bash build-base \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh new file mode 100755 index 000000000..9d3332b8f --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source ~/.nvm/nvm.sh + +nvm install 8 +set -ex + +cd $(dirname $0) +tool_dir=$(pwd) +cd $tool_dir/../../.. +base_dir=$(pwd) + +export ARTIFACTS_OUT=$base_dir/artifacts + +rm -rf build || true + +mkdir -p "${ARTIFACTS_OUT}" + +docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact + +$tool_dir/build_artifact_node.sh false + +$tool_dir/build_artifact_node_arm.sh + +docker run -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact bash -c /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh true diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 9563da7db..a33236844 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -12,6 +12,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. +set arch_list=ia32 x64 + set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 @@ -24,21 +26,23 @@ call npm update || goto :error mkdir -p %ARTIFACTS_OUT% -for %%v in (%node_versions%) do ( - call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%1 +for %%a in (%arch_list%) do ( + for %%v in (%node_versions%) do ( + call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%%a -@rem Try again after removing openssl headers - rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q - rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q - call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%1 || goto :error + @rem Try again after removing openssl headers + rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q + rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q + call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error - xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error -) + xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + ) -for %%v in (%electron_versions%) do ( - cmd /V /C "set "HOME=%USERPROFILE%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package --runtime=electron --target=%%v --target_arch=%1 --disturl=https://atom.io/download/electron" || goto :error + for %%v in (%electron_versions%) do ( + cmd /V /C "set "HOME=%USERPROFILE%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package --runtime=electron --target=%%v --target_arch=%%a --disturl=https://atom.io/download/electron" || goto :error - xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + ) ) if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 3b4d0456f..7eaf506d0 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,12 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -NODE_TARGET_ARCH=$1 -NODE_TARGET_OS=$2 -source ~/.nvm/nvm.sh - -nvm use 8 -set -ex +NODE_ALPINE_BUILD=$1 umask 022 @@ -30,24 +25,25 @@ mkdir -p "${ARTIFACTS_OUT}" npm update +arch_list=( ia32 x64 ) + node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 ) -for version in ${node_versions[@]} +for arch in ${arch_list[@]} do - ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$version --target_arch=$NODE_TARGET_ARCH --grpc_alpine=true - cp -r build/stage/* "${ARTIFACTS_OUT}"/ - if [ "$NODE_TARGET_ARCH" == 'x64' ] && [ "$NODE_TARGET_OS" == 'linux' ] - then - # Cross compile for ARM on x64 - CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ LD=arm-linux-gnueabihf-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm + for version in ${node_versions[@]} + do + ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$version --target_arch=$arch --grpc_alpine=$NODE_ALPINE_BUILD cp -r build/stage/* "${ARTIFACTS_OUT}"/ - fi -done + done -for version in ${electron_versions[@]} -do - HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$version --target_arch=$NODE_TARGET_ARCH --disturl=https://atom.io/download/electron - cp -r build/stage/* "${ARTIFACTS_OUT}"/ + for version in ${electron_versions[@]} + do + HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$version --target_arch=$arch --disturl=https://atom.io/download/electron + cp -r build/stage/* "${ARTIFACTS_OUT}"/ + done done + +rm -rf build || true diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh new file mode 100755 index 000000000..b33f8decf --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +source ~/.nvm/nvm.sh + +nvm use 8 +set -ex + +cd $(dirname $0)/../../.. + +rm -rf build || true + +mkdir -p "${ARTIFACTS_OUT}" + +npm update + +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) + +for version in ${node_versions[@]} +do + # Cross compile for ARM on x64 + CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ LD=arm-linux-gnueabihf-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm + cp -r build/stage/* "${ARTIFACTS_OUT}"/ +done From 7652ef74ed658d202b21ea8819c31cae34ed2cbc Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Nov 2017 16:10:56 -0800 Subject: [PATCH 0035/1899] Add more helpful error message for failure to load extension --- .../grpc-native-core/src/grpc_extension.js | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/grpc_extension.js b/packages/grpc-native-core/src/grpc_extension.js index 77476f012..487280ef8 100644 --- a/packages/grpc-native-core/src/grpc_extension.js +++ b/packages/grpc-native-core/src/grpc_extension.js @@ -27,6 +27,26 @@ var binary = require('node-pre-gyp/lib/pre-binding'); var path = require('path'); var binding_path = binary.find(path.resolve(path.join(__dirname, '../package.json'))); -var binding = require(binding_path); +var binding; +try { + binding = require(binding_path); +} catch (e) { + var fs = require('fs'); + var searchPath = path.dirname(path.dirname(binding_path)); + var searchName = path.basename(path.dirname(binding_path)); + var foundNames = fs.readdirSync(searchPath); + if (foundNames.indexOf(searchName) === -1) { + var message = `Failed to load gRPC binary module because it was not installed for the current system +Expected: ${searchName} +Found: [${foundNames.join(', ')}] +This problem can often be fixed by running "npm rebuild" on the current system +Original error: ${e.message}`; + var error = new Error(message); + error.code = e.code; + throw error; + } else { + throw e; + } +} module.exports = binding; From 0ab70b9cb7a4a7cbce5fe0c5366e03d7fc47b3b0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Nov 2017 16:34:34 -0800 Subject: [PATCH 0036/1899] Resolve comments --- .../tools/docker/alpine_artifact/Dockerfile | 2 +- .../artifacts/build_all_linux_artifacts.sh | 4 ++-- .../run_tests/artifacts/build_artifact_node.sh | 17 +++++++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile index 7898a08df..0674654a5 100644 --- a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile +++ b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile @@ -1,2 +1,2 @@ FROM node:8-alpine -RUN apk add --no-cache python curl bash build-base \ No newline at end of file +RUN apk add --no-cache python curl bash build-base diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 9d3332b8f..2d34d4d75 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -31,8 +31,8 @@ mkdir -p "${ARTIFACTS_OUT}" docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact -$tool_dir/build_artifact_node.sh false +$tool_dir/build_artifact_node.sh $tool_dir/build_artifact_node_arm.sh -docker run -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact bash -c /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh true +docker run -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact bash -c /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 7eaf506d0..d8128863e 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,6 +13,23 @@ # See the License for the specific language governing permissions and # limitations under the License. +NODE_ALPINE_BUILD=false + +while true ; do + case $1 in + --with-alpine) + NODE_ALPINE_BUILD=true + ;; + "") + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac + shift || break +done + NODE_ALPINE_BUILD=$1 umask 022 From 02e70cba374734e991648fcd01a7b92bfde20cec Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Nov 2017 16:57:13 -0800 Subject: [PATCH 0037/1899] Improve message wording --- packages/grpc-native-core/src/grpc_extension.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/grpc_extension.js b/packages/grpc-native-core/src/grpc_extension.js index 487280ef8..46e2721d1 100644 --- a/packages/grpc-native-core/src/grpc_extension.js +++ b/packages/grpc-native-core/src/grpc_extension.js @@ -37,7 +37,7 @@ try { var foundNames = fs.readdirSync(searchPath); if (foundNames.indexOf(searchName) === -1) { var message = `Failed to load gRPC binary module because it was not installed for the current system -Expected: ${searchName} +Expected directory: ${searchName} Found: [${foundNames.join(', ')}] This problem can often be fixed by running "npm rebuild" on the current system Original error: ${e.message}`; From 74c6bd51061557a4303f9cadda9da2e847a1ce81 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 30 Nov 2017 12:25:07 -0800 Subject: [PATCH 0038/1899] Update v1.8.x branch to 1.8.0-pre2 --- packages/grpc-native-core/binding.gyp | 7 +++---- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 0e489bd3e..ddb91ec9e 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -63,7 +63,6 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/abseil-cpp', ], 'ldflags': [ '-g', @@ -186,7 +185,6 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/abseil-cpp', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -196,7 +194,6 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/abseil-cpp', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' @@ -615,6 +612,7 @@ 'deps/grpc/src/core/lib/support/env_linux.cc', 'deps/grpc/src/core/lib/support/env_posix.cc', 'deps/grpc/src/core/lib/support/env_windows.cc', + 'deps/grpc/src/core/lib/support/fork.cc', 'deps/grpc/src/core/lib/support/histogram.cc', 'deps/grpc/src/core/lib/support/host_port.cc', 'deps/grpc/src/core/lib/support/log.cc', @@ -624,7 +622,6 @@ 'deps/grpc/src/core/lib/support/log_windows.cc', 'deps/grpc/src/core/lib/support/mpscq.cc', 'deps/grpc/src/core/lib/support/murmur_hash.cc', - 'deps/grpc/src/core/lib/support/stack_lockfree.cc', 'deps/grpc/src/core/lib/support/string.cc', 'deps/grpc/src/core/lib/support/string_posix.cc', 'deps/grpc/src/core/lib/support/string_util_windows.cc', @@ -697,6 +694,8 @@ 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', 'deps/grpc/src/core/lib/iomgr/exec_ctx.cc', 'deps/grpc/src/core/lib/iomgr/executor.cc', + 'deps/grpc/src/core/lib/iomgr/fork_posix.cc', + 'deps/grpc/src/core/lib/iomgr/fork_windows.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index dbca3d9b7..65212e06e 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit dbca3d9b765b8e13ead6327fdd4904fe0fa05c84 +Subproject commit 65212e06ef6f26edeb41411cd8a24d07f0ab6628 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ef5e48f9e..f9a7e7b0f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.8.0-dev", + "version": "1.8.0-pre2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From eba77f295ec2ca5d4857f3c4baef0c44e3262eb4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 30 Nov 2017 12:57:20 -0800 Subject: [PATCH 0039/1899] Update master to 1.9.0-dev --- packages/grpc-native-core/binding.gyp | 7 +++---- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 0e489bd3e..ddb91ec9e 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -63,7 +63,6 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/abseil-cpp', ], 'ldflags': [ '-g', @@ -186,7 +185,6 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/abseil-cpp', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -196,7 +194,6 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/abseil-cpp', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' @@ -615,6 +612,7 @@ 'deps/grpc/src/core/lib/support/env_linux.cc', 'deps/grpc/src/core/lib/support/env_posix.cc', 'deps/grpc/src/core/lib/support/env_windows.cc', + 'deps/grpc/src/core/lib/support/fork.cc', 'deps/grpc/src/core/lib/support/histogram.cc', 'deps/grpc/src/core/lib/support/host_port.cc', 'deps/grpc/src/core/lib/support/log.cc', @@ -624,7 +622,6 @@ 'deps/grpc/src/core/lib/support/log_windows.cc', 'deps/grpc/src/core/lib/support/mpscq.cc', 'deps/grpc/src/core/lib/support/murmur_hash.cc', - 'deps/grpc/src/core/lib/support/stack_lockfree.cc', 'deps/grpc/src/core/lib/support/string.cc', 'deps/grpc/src/core/lib/support/string_posix.cc', 'deps/grpc/src/core/lib/support/string_util_windows.cc', @@ -697,6 +694,8 @@ 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', 'deps/grpc/src/core/lib/iomgr/exec_ctx.cc', 'deps/grpc/src/core/lib/iomgr/executor.cc', + 'deps/grpc/src/core/lib/iomgr/fork_posix.cc', + 'deps/grpc/src/core/lib/iomgr/fork_windows.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index dbca3d9b7..ccd350335 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit dbca3d9b765b8e13ead6327fdd4904fe0fa05c84 +Subproject commit ccd35033545226b9b38ab219c9eb8d0e4325b7c1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ef5e48f9e..f216537a3 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.8.0-dev", + "version": "1.9.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From f900cfb3dd84221722528ce7c73c35d9aead57a7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 30 Nov 2017 14:01:05 -0800 Subject: [PATCH 0040/1899] Update a core header inclusion to stop using extern C --- packages/grpc-native-core/ext/node_grpc.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/grpc-native-core/ext/node_grpc.cc b/packages/grpc-native-core/ext/node_grpc.cc index a0652c282..6ba5f1a1e 100644 --- a/packages/grpc-native-core/ext/node_grpc.cc +++ b/packages/grpc-native-core/ext/node_grpc.cc @@ -28,9 +28,7 @@ #include "grpc/support/time.h" // TODO(murgatroid99): Remove this when the endpoint API becomes public -extern "C" { #include "src/core/lib/iomgr/pollset_uv.h" -} #include "call.h" #include "call_credentials.h" From ed78037353b0fed637dd85df46633d705621708a Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 6 Dec 2017 13:13:11 -0800 Subject: [PATCH 0041/1899] Copy API tests back to grpc-native-core --- .../interop/async_delay_queue.js | 64 + .../interop/interop_client.js | 621 ++++++++ .../interop/interop_server.js | 241 +++ packages/grpc-native-core/package.json | 2 + packages/grpc-native-core/test/async_test.js | 83 + .../test/credentials_api_test.js | 165 ++ .../grpc-native-core/test/credentials_test.js | 452 ++++++ packages/grpc-native-core/test/data/README | 1 + packages/grpc-native-core/test/data/ca.pem | 15 + .../grpc-native-core/test/data/server1.key | 16 + .../grpc-native-core/test/data/server1.pem | 16 + .../grpc-native-core/test/echo_service.proto | 24 + .../grpc-native-core/test/file_load_test.js | 40 + packages/grpc-native-core/test/health_test.js | 103 ++ .../test/interop_sanity_test.js | 94 ++ .../test/math/math_grpc_pb.js | 125 ++ .../grpc-native-core/test/math/math_pb.js | 866 +++++++++++ .../grpc-native-core/test/math/math_server.js | 124 ++ .../grpc-native-core/test/math_client_test.js | 140 ++ .../grpc-native-core/test/metadata_test.js | 178 +++ packages/grpc-native-core/test/numbers.txt | 496 ++++++ packages/grpc-native-core/test/server_test.js | 4 +- .../grpc-native-core/test/surface_test.js | 1379 +++++++++++++++++ .../grpc-native-core/test/test_service.json | 55 + .../grpc-native-core/test/test_service.proto | 37 + 25 files changed, 5339 insertions(+), 2 deletions(-) create mode 100644 packages/grpc-native-core/interop/async_delay_queue.js create mode 100644 packages/grpc-native-core/interop/interop_client.js create mode 100644 packages/grpc-native-core/interop/interop_server.js create mode 100644 packages/grpc-native-core/test/async_test.js create mode 100644 packages/grpc-native-core/test/credentials_api_test.js create mode 100644 packages/grpc-native-core/test/credentials_test.js create mode 100644 packages/grpc-native-core/test/data/README create mode 100644 packages/grpc-native-core/test/data/ca.pem create mode 100644 packages/grpc-native-core/test/data/server1.key create mode 100644 packages/grpc-native-core/test/data/server1.pem create mode 100644 packages/grpc-native-core/test/echo_service.proto create mode 100644 packages/grpc-native-core/test/file_load_test.js create mode 100644 packages/grpc-native-core/test/health_test.js create mode 100644 packages/grpc-native-core/test/interop_sanity_test.js create mode 100644 packages/grpc-native-core/test/math/math_grpc_pb.js create mode 100644 packages/grpc-native-core/test/math/math_pb.js create mode 100644 packages/grpc-native-core/test/math/math_server.js create mode 100644 packages/grpc-native-core/test/math_client_test.js create mode 100644 packages/grpc-native-core/test/metadata_test.js create mode 100644 packages/grpc-native-core/test/numbers.txt create mode 100644 packages/grpc-native-core/test/surface_test.js create mode 100644 packages/grpc-native-core/test/test_service.json create mode 100644 packages/grpc-native-core/test/test_service.proto diff --git a/packages/grpc-native-core/interop/async_delay_queue.js b/packages/grpc-native-core/interop/async_delay_queue.js new file mode 100644 index 000000000..43ac57387 --- /dev/null +++ b/packages/grpc-native-core/interop/async_delay_queue.js @@ -0,0 +1,64 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var _ = require('lodash'); + +/** + * This class represents a queue of callbacks that must happen sequentially, + * each with a specific delay after the previous event. + */ +function AsyncDelayQueue() { + this.queue = []; + + this.callback_pending = false; +} + +/** + * Run the next callback after its corresponding delay, if there are any + * remaining. + */ +AsyncDelayQueue.prototype.runNext = function() { + var next = this.queue.shift(); + var continueCallback = _.bind(this.runNext, this); + if (next) { + this.callback_pending = true; + setTimeout(function() { + next.callback(continueCallback); + }, next.delay); + } else { + this.callback_pending = false; + } +}; + +/** + * Add a callback to be called with a specific delay after now or after the + * current last item in the queue or current pending callback, whichever is + * latest. + * @param {function(function())} callback The callback + * @param {Number} The delay to apply, in milliseconds + */ +AsyncDelayQueue.prototype.add = function(callback, delay) { + this.queue.push({callback: callback, delay: delay}); + if (!this.callback_pending) { + this.runNext(); + } +}; + +module.exports = AsyncDelayQueue; diff --git a/packages/grpc-native-core/interop/interop_client.js b/packages/grpc-native-core/interop/interop_client.js new file mode 100644 index 000000000..3e2cdf9f7 --- /dev/null +++ b/packages/grpc-native-core/interop/interop_client.js @@ -0,0 +1,621 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var grpc = require('..'); +var testProto = grpc.load({ + root: __dirname + '/../deps/grpc', + file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; +var GoogleAuth = require('google-auth-library'); + +var assert = require('assert'); + +var SERVICE_ACCOUNT_EMAIL; +try { + SERVICE_ACCOUNT_EMAIL = require( + process.env.GOOGLE_APPLICATION_CREDENTIALS).client_email; +} catch (e) { + // This will cause the tests to fail if they need that string + SERVICE_ACCOUNT_EMAIL = null; +} + +var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; +var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; + +/** + * Create a buffer filled with size zeroes + * @param {number} size The length of the buffer + * @return {Buffer} The new buffer + */ +function zeroBuffer(size) { + var zeros = new Buffer(size); + zeros.fill(0); + return zeros; +} + +/** + * This is used for testing functions with multiple asynchronous calls that + * can happen in different orders. This should be passed the number of async + * function invocations that can occur last, and each of those should call this + * function's return value + * @param {function()} done The function that should be called when a test is + * complete. + * @param {number} count The number of calls to the resulting function if the + * test passes. + * @return {function()} The function that should be called at the end of each + * sequence of asynchronous functions. + */ +function multiDone(done, count) { + return function() { + count -= 1; + if (count <= 0) { + done(); + } + }; +} + +/** + * Run the empty_unary test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function emptyUnary(client, done) { + client.emptyCall({}, function(err, resp) { + assert.ifError(err); + if (done) { + done(); + } + }); +} + +/** + * Run the large_unary test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function largeUnary(client, done) { + var arg = { + response_type: 'COMPRESSABLE', + response_size: 314159, + payload: { + body: zeroBuffer(271828) + } + }; + client.unaryCall(arg, function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); + assert.strictEqual(resp.payload.body.length, 314159); + if (done) { + done(); + } + }); +} + +/** + * Run the client_streaming test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function clientStreaming(client, done) { + var call = client.streamingInputCall(function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.aggregated_payload_size, 74922); + if (done) { + done(); + } + }); + var payload_sizes = [27182, 8, 1828, 45904]; + for (var i = 0; i < payload_sizes.length; i++) { + call.write({payload: {body: zeroBuffer(payload_sizes[i])}}); + } + call.end(); +} + +/** + * Run the server_streaming test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function serverStreaming(client, done) { + var arg = { + response_type: 'COMPRESSABLE', + response_parameters: [ + {size: 31415}, + {size: 9}, + {size: 2653}, + {size: 58979} + ] + }; + var call = client.streamingOutputCall(arg); + var resp_index = 0; + call.on('data', function(value) { + assert(resp_index < 4); + assert.strictEqual(value.payload.type, 'COMPRESSABLE'); + assert.strictEqual(value.payload.body.length, + arg.response_parameters[resp_index].size); + resp_index += 1; + }); + call.on('end', function() { + assert.strictEqual(resp_index, 4); + if (done) { + done(); + } + }); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + }); +} + +/** + * Run the ping_pong test + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function pingPong(client, done) { + var payload_sizes = [27182, 8, 1828, 45904]; + var response_sizes = [31415, 9, 2653, 58979]; + var call = client.fullDuplexCall(); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); + var index = 0; + call.write({ + response_type: 'COMPRESSABLE', + response_parameters: [ + {size: response_sizes[index]} + ], + payload: {body: zeroBuffer(payload_sizes[index])} + }); + call.on('data', function(response) { + assert.strictEqual(response.payload.type, 'COMPRESSABLE'); + assert.equal(response.payload.body.length, response_sizes[index]); + index += 1; + if (index === 4) { + call.end(); + } else { + call.write({ + response_type: 'COMPRESSABLE', + response_parameters: [ + {size: response_sizes[index]} + ], + payload: {body: zeroBuffer(payload_sizes[index])} + }); + } + }); +} + +/** + * Run the empty_stream test. + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function emptyStream(client, done) { + var call = client.fullDuplexCall(); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + if (done) { + done(); + } + }); + call.on('data', function(value) { + assert.fail(value, null, 'No data should have been received', '!=='); + }); + call.end(); +} + +/** + * Run the cancel_after_begin test. + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function cancelAfterBegin(client, done) { + var call = client.streamingInputCall(function(err, resp) { + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); +} + +/** + * Run the cancel_after_first_response test. + * @param {Client} client The client to test against + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function cancelAfterFirstResponse(client, done) { + var call = client.fullDuplexCall(); + call.write({ + response_type: 'COMPRESSABLE', + response_parameters: [ + {size: 31415} + ], + payload: {body: zeroBuffer(27182)} + }); + call.on('data', function(data) { + call.cancel(); + }); + call.on('error', function(error) { + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); +} + +function timeoutOnSleepingServer(client, done) { + var deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 1); + var call = client.fullDuplexCall({deadline: deadline}); + call.write({ + payload: {body: zeroBuffer(27182)} + }); + call.on('data', function() {}); + call.on('error', function(error) { + + assert(error.code === grpc.status.DEADLINE_EXCEEDED || + error.code === grpc.status.INTERNAL); + done(); + }); +} + +function customMetadata(client, done) { + done = multiDone(done, 5); + var metadata = new grpc.Metadata(); + metadata.set(ECHO_INITIAL_KEY, 'test_initial_metadata_value'); + metadata.set(ECHO_TRAILING_KEY, new Buffer('ababab', 'hex')); + var arg = { + response_type: 'COMPRESSABLE', + response_size: 314159, + payload: { + body: zeroBuffer(271828) + } + }; + var streaming_arg = { + response_parameters: [ + {size: 314159} + ], + payload: { + body: zeroBuffer(271828) + } + }; + var unary = client.unaryCall(arg, metadata, function(err, resp) { + assert.ifError(err); + done(); + }); + unary.on('metadata', function(metadata) { + assert.deepEqual(metadata.get(ECHO_INITIAL_KEY), + ['test_initial_metadata_value']); + done(); + }); + unary.on('status', function(status) { + var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY); + assert(echo_trailer.length > 0); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); + var stream = client.fullDuplexCall(metadata); + stream.on('metadata', function(metadata) { + assert.deepEqual(metadata.get(ECHO_INITIAL_KEY), + ['test_initial_metadata_value']); + done(); + }); + stream.on('data', function() {}); + stream.on('status', function(status) { + var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY); + assert(echo_trailer.length > 0); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); + stream.write(streaming_arg); + stream.end(); +} + +function statusCodeAndMessage(client, done) { + done = multiDone(done, 2); + var arg = { + response_status: { + code: 2, + message: 'test status message' + } + }; + client.unaryCall(arg, function(err, resp) { + assert(err); + assert.strictEqual(err.code, 2); + assert.strictEqual(err.message, 'test status message'); + done(); + }); + var duplex = client.fullDuplexCall(); + duplex.on('data', function() {}); + duplex.on('status', function(status) { + assert(status); + assert.strictEqual(status.code, 2); + assert.strictEqual(status.details, 'test status message'); + done(); + }); + duplex.on('error', function(){}); + duplex.write(arg); + duplex.end(); +} + +// NOTE: the client param to this function is from UnimplementedService +function unimplementedService(client, done) { + client.unimplementedCall({}, function(err, resp) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + done(); + }); +} + +// NOTE: the client param to this function is from TestService +function unimplementedMethod(client, done) { + client.unimplementedCall({}, function(err, resp) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + done(); + }); +} + +/** + * Run one of the authentication tests. + * @param {string} expected_user The expected username in the response + * @param {Client} client The client to test against + * @param {?string} scope The scope to apply to the credentials + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + */ +function authTest(expected_user, scope, client, done) { + var arg = { + response_type: 'COMPRESSABLE', + response_size: 314159, + payload: { + body: zeroBuffer(271828) + }, + fill_username: true, + fill_oauth_scope: true + }; + client.unaryCall(arg, function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); + assert.strictEqual(resp.payload.body.length, 314159); + assert.strictEqual(resp.username, expected_user); + if (scope) { + assert(scope.indexOf(resp.oauth_scope) > -1); + } + if (done) { + done(); + } + }); +} + +function computeEngineCreds(client, done, extra) { + authTest(extra.service_account, null, client, done); +} + +function serviceAccountCreds(client, done, extra) { + authTest(SERVICE_ACCOUNT_EMAIL, extra.oauth_scope, client, done); +} + +function jwtTokenCreds(client, done, extra) { + authTest(SERVICE_ACCOUNT_EMAIL, null, client, done); +} + +function oauth2Test(client, done, extra) { + var arg = { + fill_username: true, + fill_oauth_scope: true + }; + client.unaryCall(arg, function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); + assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); + if (done) { + done(); + } + }); +} + +function perRpcAuthTest(client, done, extra) { + (new GoogleAuth()).getApplicationDefault(function(err, credential) { + assert.ifError(err); + var arg = { + fill_username: true, + fill_oauth_scope: true + }; + var scope = extra.oauth_scope; + if (credential.createScopedRequired() && scope) { + credential = credential.createScoped(scope); + } + var creds = grpc.credentials.createFromGoogleCredential(credential); + client.unaryCall(arg, {credentials: creds}, function(err, resp) { + assert.ifError(err); + assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); + assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); + if (done) { + done(); + } + }); + }); +} + +function getApplicationCreds(scope, callback) { + (new GoogleAuth()).getApplicationDefault(function(err, credential) { + if (err) { + callback(err); + return; + } + if (credential.createScopedRequired() && scope) { + credential = credential.createScoped(scope); + } + callback(null, grpc.credentials.createFromGoogleCredential(credential)); + }); +} + +function getOauth2Creds(scope, callback) { + (new GoogleAuth()).getApplicationDefault(function(err, credential) { + if (err) { + callback(err); + return; + } + credential = credential.createScoped(scope); + credential.getAccessToken(function(err, token) { + if (err) { + callback(err); + return; + } + var updateMd = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.add('authorization', 'Bearer ' + token); + callback(null, metadata); + }; + callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); + }); + }); +} + +/** + * Map from test case names to test functions + */ +var test_cases = { + empty_unary: {run: emptyUnary, + Client: testProto.TestService}, + large_unary: {run: largeUnary, + Client: testProto.TestService}, + client_streaming: {run: clientStreaming, + Client: testProto.TestService}, + server_streaming: {run: serverStreaming, + Client: testProto.TestService}, + ping_pong: {run: pingPong, + Client: testProto.TestService}, + empty_stream: {run: emptyStream, + Client: testProto.TestService}, + cancel_after_begin: {run: cancelAfterBegin, + Client: testProto.TestService}, + cancel_after_first_response: {run: cancelAfterFirstResponse, + Client: testProto.TestService}, + timeout_on_sleeping_server: {run: timeoutOnSleepingServer, + Client: testProto.TestService}, + custom_metadata: {run: customMetadata, + Client: testProto.TestService}, + status_code_and_message: {run: statusCodeAndMessage, + Client: testProto.TestService}, + unimplemented_service: {run: unimplementedService, + Client: testProto.UnimplementedService}, + unimplemented_method: {run: unimplementedMethod, + Client: testProto.TestService}, + compute_engine_creds: {run: computeEngineCreds, + Client: testProto.TestService, + getCreds: getApplicationCreds}, + service_account_creds: {run: serviceAccountCreds, + Client: testProto.TestService, + getCreds: getApplicationCreds}, + jwt_token_creds: {run: jwtTokenCreds, + Client: testProto.TestService, + getCreds: getApplicationCreds}, + oauth2_auth_token: {run: oauth2Test, + Client: testProto.TestService, + getCreds: getOauth2Creds}, + per_rpc_creds: {run: perRpcAuthTest, + Client: testProto.TestService} +}; + +exports.test_cases = test_cases; + +/** + * Execute a single test case. + * @param {string} address The address of the server to connect to, in the + * format 'hostname:port' + * @param {string} host_overrirde The hostname of the server to use as an SSL + * override + * @param {string} test_case The name of the test case to run + * @param {bool} tls Indicates that a secure channel should be used + * @param {function} done Callback to call when the test is completed. Included + * primarily for use with mocha + * @param {object=} extra Extra options for some tests + */ +function runTest(address, host_override, test_case, tls, test_ca, done, extra) { + // TODO(mlumish): enable TLS functionality + var options = {}; + var creds; + if (tls) { + var ca_path; + if (test_ca) { + ca_path = path.join(__dirname, '../test/data/ca.pem'); + var ca_data = fs.readFileSync(ca_path); + creds = grpc.credentials.createSsl(ca_data); + } else { + creds = grpc.credentials.createSsl(); + } + if (host_override) { + options['grpc.ssl_target_name_override'] = host_override; + options['grpc.default_authority'] = host_override; + } + } else { + creds = grpc.credentials.createInsecure(); + } + var test = test_cases[test_case]; + + var execute = function(err, creds) { + assert.ifError(err); + var client = new test.Client(address, creds, options); + test.run(client, done, extra); + }; + + if (test.getCreds) { + test.getCreds(extra.oauth_scope, function(err, new_creds) { + assert.ifError(err); + execute(err, grpc.credentials.combineChannelCredentials( + creds, new_creds)); + }); + } else { + execute(null, creds); + } +} + +if (require.main === module) { + var parseArgs = require('minimist'); + var argv = parseArgs(process.argv, { + string: ['server_host', 'server_host_override', 'server_port', 'test_case', + 'use_tls', 'use_test_ca', 'default_service_account', 'oauth_scope', + 'service_account_key_file'] + }); + var extra_args = { + service_account: argv.default_service_account, + oauth_scope: argv.oauth_scope + }; + runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, + argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', + function () { + console.log('OK:', argv.test_case); + }, extra_args); +} + +/** + * See docs for runTest + */ +exports.runTest = runTest; diff --git a/packages/grpc-native-core/interop/interop_server.js b/packages/grpc-native-core/interop/interop_server.js new file mode 100644 index 000000000..c2341723a --- /dev/null +++ b/packages/grpc-native-core/interop/interop_server.js @@ -0,0 +1,241 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var _ = require('lodash'); +var AsyncDelayQueue = require('./async_delay_queue'); +var grpc = require('..'); +var testProto = grpc.load({ + root: __dirname + '/../deps/grpc', + file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; + +var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; +var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; + +/** + * Create a buffer filled with size zeroes + * @param {number} size The length of the buffer + * @return {Buffer} The new buffer + */ +function zeroBuffer(size) { + var zeros = new Buffer(size); + zeros.fill(0); + return zeros; +} + +/** + * Echos a header metadata item as specified in the interop spec. + * @param {Call} call The call to echo metadata on + */ +function echoHeader(call) { + var echo_initial = call.metadata.get(ECHO_INITIAL_KEY); + if (echo_initial.length > 0) { + var response_metadata = new grpc.Metadata(); + response_metadata.set(ECHO_INITIAL_KEY, echo_initial[0]); + call.sendMetadata(response_metadata); + } +} + +/** + * Gets the trailer metadata that should be echoed when the call is done, + * as specified in the interop spec. + * @param {Call} call The call to get metadata from + * @return {grpc.Metadata} The metadata to send as a trailer + */ +function getEchoTrailer(call) { + var echo_trailer = call.metadata.get(ECHO_TRAILING_KEY); + var response_trailer = new grpc.Metadata(); + if (echo_trailer.length > 0) { + response_trailer.set(ECHO_TRAILING_KEY, echo_trailer[0]); + } + return response_trailer; +} + +function getPayload(payload_type, size) { + var body = zeroBuffer(size); + return {type: payload_type, body: body}; +} + +/** + * Respond to an empty parameter with an empty response. + * NOTE: this currently does not work due to issue #137 + * @param {Call} call Call to handle + * @param {function(Error, Object)} callback Callback to call with result + * or error + */ +function handleEmpty(call, callback) { + echoHeader(call); + callback(null, {}, getEchoTrailer(call)); +} + +/** + * Handle a unary request by sending the requested payload + * @param {Call} call Call to handle + * @param {function(Error, Object)} callback Callback to call with result or + * error + */ +function handleUnary(call, callback) { + echoHeader(call); + var req = call.request; + if (req.response_status) { + var status = req.response_status; + status.metadata = getEchoTrailer(call); + callback(status); + return; + } + var payload = getPayload(req.response_type, req.response_size); + callback(null, {payload: payload}, + getEchoTrailer(call)); +} + +/** + * Respond to a streaming call with the total size of all payloads + * @param {Call} call Call to handle + * @param {function(Error, Object)} callback Callback to call with result or + * error + */ +function handleStreamingInput(call, callback) { + echoHeader(call); + var aggregate_size = 0; + call.on('data', function(value) { + aggregate_size += value.payload.body.length; + }); + call.on('end', function() { + callback(null, {aggregated_payload_size: aggregate_size}, + getEchoTrailer(call)); + }); +} + +/** + * Respond to a payload request with a stream of the requested payloads + * @param {Call} call Call to handle + */ +function handleStreamingOutput(call) { + echoHeader(call); + var delay_queue = new AsyncDelayQueue(); + var req = call.request; + if (req.response_status) { + var status = req.response_status; + status.metadata = getEchoTrailer(call); + call.emit('error', status); + return; + } + _.each(req.response_parameters, function(resp_param) { + delay_queue.add(function(next) { + call.write({payload: getPayload(req.response_type, resp_param.size)}); + next(); + }, resp_param.interval_us); + }); + delay_queue.add(function(next) { + call.end(getEchoTrailer(call)); + next(); + }); +} + +/** + * Respond to a stream of payload requests with a stream of payload responses as + * they arrive. + * @param {Call} call Call to handle + */ +function handleFullDuplex(call) { + echoHeader(call); + var delay_queue = new AsyncDelayQueue(); + call.on('data', function(value) { + if (value.response_status) { + var status = value.response_status; + status.metadata = getEchoTrailer(call); + call.emit('error', status); + return; + } + _.each(value.response_parameters, function(resp_param) { + delay_queue.add(function(next) { + call.write({payload: getPayload(value.response_type, resp_param.size)}); + next(); + }, resp_param.interval_us); + }); + }); + call.on('end', function() { + delay_queue.add(function(next) { + call.end(getEchoTrailer(call)); + next(); + }); + }); +} + +/** + * Respond to a stream of payload requests with a stream of payload responses + * after all requests have arrived + * @param {Call} call Call to handle + */ +function handleHalfDuplex(call) { + call.emit('error', Error('HalfDuplexCall not yet implemented')); +} + +/** + * Get a server object bound to the given port + * @param {string} port Port to which to bind + * @param {boolean} tls Indicates that the bound port should use TLS + * @return {{server: Server, port: number}} Server object bound to the support, + * and port number that the server is bound to + */ +function getServer(port, tls) { + // TODO(mlumish): enable TLS functionality + var options = {}; + var server_creds; + if (tls) { + var key_path = path.join(__dirname, '../test/data/server1.key'); + var pem_path = path.join(__dirname, '../test/data/server1.pem'); + + var key_data = fs.readFileSync(key_path); + var pem_data = fs.readFileSync(pem_path); + server_creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}]); + } else { + server_creds = grpc.ServerCredentials.createInsecure(); + } + var server = new grpc.Server(options); + server.addService(testProto.TestService.service, { + emptyCall: handleEmpty, + unaryCall: handleUnary, + streamingOutputCall: handleStreamingOutput, + streamingInputCall: handleStreamingInput, + fullDuplexCall: handleFullDuplex, + halfDuplexCall: handleHalfDuplex + }); + var port_num = server.bind('0.0.0.0:' + port, server_creds); + return {server: server, port: port_num}; +} + +if (require.main === module) { + var parseArgs = require('minimist'); + var argv = parseArgs(process.argv, { + string: ['port', 'use_tls'] + }); + var server_obj = getServer(argv.port, argv.use_tls === 'true'); + console.log('Server attaching to port ' + argv.port); + server_obj.server.start(); +} + +/** + * See docs for getServer + */ +exports.getServer = getServer; diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f216537a3..62399419f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -36,6 +36,8 @@ }, "devDependencies": { "electron-mocha": "^3.1.1", + "google-auth-library": "^0.12.0", + "google-protobuf": "^3.5.0", "istanbul": "^0.4.4" }, "engines": { diff --git a/packages/grpc-native-core/test/async_test.js b/packages/grpc-native-core/test/async_test.js new file mode 100644 index 000000000..e2f124e59 --- /dev/null +++ b/packages/grpc-native-core/test/async_test.js @@ -0,0 +1,83 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); + +var grpc = require('..'); +var math = grpc.load(__dirname + '/../deps/grpc/src/proto/math/math.proto').math; + + +/** + * Client to use to make requests to a running server. + */ +var math_client; + +/** + * Server to test against + */ +var getServer = require('./math/math_server.js'); + +var server = getServer(); + +describe('Async functionality', function() { + before(function(done) { + var port_num = server.bind('0.0.0.0:0', + grpc.ServerCredentials.createInsecure()); + server.start(); + math_client = new math.Math('localhost:' + port_num, + grpc.credentials.createInsecure()); + done(); + }); + after(function() { + grpc.closeClient(math_client); + server.forceShutdown(); + }); + it('should not hang', function(done) { + var chunkCount=0; + var call = math_client.sum(function handleSumResult(err, value) { + assert.ifError(err); + assert.equal(value.num, chunkCount); + }); + + var path = require('path'); + var fs = require('fs'); + var fileToRead = path.join(__dirname, 'numbers.txt'); + var readStream = fs.createReadStream(fileToRead); + + readStream.once('readable', function () { + readStream.on('data', function (chunk) { + call.write({'num': 1}); + chunkCount += 1; + }); + + readStream.on('end', function () { + call.end(); + }); + + readStream.on('error', function (error) { + }); + }); + + call.on('status', function checkStatus(status) { + assert.strictEqual(status.code, grpc.status.OK); + done(); + }); + }); +}); diff --git a/packages/grpc-native-core/test/credentials_api_test.js b/packages/grpc-native-core/test/credentials_api_test.js new file mode 100644 index 000000000..38a2a1ced --- /dev/null +++ b/packages/grpc-native-core/test/credentials_api_test.js @@ -0,0 +1,165 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); + +var grpc = require('..'); + +var key_data, pem_data, ca_data; + +before(function() { + var key_path = path.join(__dirname, './data/server1.key'); + var pem_path = path.join(__dirname, './data/server1.pem'); + var ca_path = path.join(__dirname, './data/ca.pem'); + key_data = fs.readFileSync(key_path); + pem_data = fs.readFileSync(pem_path); + ca_data = fs.readFileSync(ca_path); +}); + +describe('channel credentials', function() { + describe('#createSsl', function() { + it('works with no arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(); + }); + assert.notEqual(creds, null); + }); + it('works with just one Buffer argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data); + }); + assert.notEqual(creds, null); + }); + it('works with 3 Buffer arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); + }); + assert.notEqual(creds, null); + }); + it('works if the first argument is null', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(null, key_data, pem_data); + }); + assert.notEqual(creds, null); + }); + it('fails if the first argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl('test'); + }, TypeError); + }); + it('fails if the second argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, 'test', pem_data); + }, TypeError); + }); + it('fails if the third argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, key_data, 'test'); + }, TypeError); + }); + it('fails if only 1 of the last 2 arguments is provided', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, key_data); + }); + assert.throws(function() { + grpc.credentials.createSsl(null, null, pem_data); + }); + }); + }); +}); + +describe('server credentials', function() { + describe('#createSsl', function() { + it('accepts a buffer and array as the first 2 arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(ca_data, []); + }); + assert.notEqual(creds, null); + }); + it('accepts a boolean as the third argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(ca_data, [], true); + }); + assert.notEqual(creds, null); + }); + it('accepts an object with two buffers in the second argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}]); + }); + assert.notEqual(creds, null); + }); + it('accepts multiple objects in the second argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}, + {private_key: key_data, + cert_chain: pem_data}]); + }); + assert.notEqual(creds, null); + }); + it('fails if the second argument is not an Array', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, 'test'); + }, TypeError); + }); + it('fails if the first argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl('test', []); + }, TypeError); + }); + it('fails if the third argument is a non-boolean value', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, [], 'test'); + }, TypeError); + }); + it('fails if the array elements are not objects', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, 'test'); + }, TypeError); + }); + it('fails if the object does not have a Buffer private_key', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(null, + [{private_key: 'test', + cert_chain: pem_data}]); + }, TypeError); + }); + it('fails if the object does not have a Buffer cert_chain', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: 'test'}]); + }, TypeError); + }); + }); +}); \ No newline at end of file diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js new file mode 100644 index 000000000..38320d85a --- /dev/null +++ b/packages/grpc-native-core/test/credentials_test.js @@ -0,0 +1,452 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var fs = require('fs'); +var path = require('path'); + +var grpc = require('..'); + +/** + * This is used for testing functions with multiple asynchronous calls that + * can happen in different orders. This should be passed the number of async + * function invocations that can occur last, and each of those should call this + * function's return value + * @param {function()} done The function that should be called when a test is + * complete. + * @param {number} count The number of calls to the resulting function if the + * test passes. + * @return {function()} The function that should be called at the end of each + * sequence of asynchronous functions. + */ +function multiDone(done, count) { + return function() { + count -= 1; + if (count <= 0) { + done(); + } + }; +} + +var fakeSuccessfulGoogleCredentials = { + getRequestMetadata: function(service_url, callback) { + setTimeout(function() { + callback(null, {Authorization: 'success'}); + }, 0); + } +}; + +var fakeFailingGoogleCredentials = { + getRequestMetadata: function(service_url, callback) { + setTimeout(function() { + // Google credentials currently adds string error codes to auth errors + var error = new Error('Authentication failure'); + error.code = 'ENOENT'; + callback(error); + }, 0); + } +}; + +var key_data, pem_data, ca_data; + +before(function() { + var key_path = path.join(__dirname, './data/server1.key'); + var pem_path = path.join(__dirname, './data/server1.pem'); + var ca_path = path.join(__dirname, './data/ca.pem'); + key_data = fs.readFileSync(key_path); + pem_data = fs.readFileSync(pem_path); + ca_data = fs.readFileSync(ca_path); +}); + +describe('channel credentials', function() { + describe('#createSsl', function() { + it('works with no arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(); + }); + assert.notEqual(creds, null); + }); + it('works with just one Buffer argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data); + }); + assert.notEqual(creds, null); + }); + it('works with 3 Buffer arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); + }); + assert.notEqual(creds, null); + }); + it('works if the first argument is null', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(null, key_data, pem_data); + }); + assert.notEqual(creds, null); + }); + it('fails if the first argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl('test'); + }, TypeError); + }); + it('fails if the second argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, 'test', pem_data); + }, TypeError); + }); + it('fails if the third argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, key_data, 'test'); + }, TypeError); + }); + it('fails if only 1 of the last 2 arguments is provided', function() { + assert.throws(function() { + grpc.credentials.createSsl(null, key_data); + }); + assert.throws(function() { + grpc.credentials.createSsl(null, null, pem_data); + }); + }); + }); +}); + +describe('server credentials', function() { + describe('#createSsl', function() { + it('accepts a buffer and array as the first 2 arguments', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(ca_data, []); + }); + assert.notEqual(creds, null); + }); + it('accepts a boolean as the third argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(ca_data, [], true); + }); + assert.notEqual(creds, null); + }); + it('accepts an object with two buffers in the second argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}]); + }); + assert.notEqual(creds, null); + }); + it('accepts multiple objects in the second argument', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}, + {private_key: key_data, + cert_chain: pem_data}]); + }); + assert.notEqual(creds, null); + }); + it('fails if the second argument is not an Array', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, 'test'); + }, TypeError); + }); + it('fails if the first argument is a non-Buffer value', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl('test', []); + }, TypeError); + }); + it('fails if the third argument is a non-boolean value', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, [], 'test'); + }, TypeError); + }); + it('fails if the array elements are not objects', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(ca_data, 'test'); + }, TypeError); + }); + it('fails if the object does not have a Buffer private_key', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(null, + [{private_key: 'test', + cert_chain: pem_data}]); + }, TypeError); + }); + it('fails if the object does not have a Buffer cert_chain', function() { + assert.throws(function() { + grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: 'test'}]); + }, TypeError); + }); + }); +}); + +describe('client credentials', function() { + var Client; + var server; + var port; + var client_ssl_creds; + var client_options = {}; + before(function() { + var proto = grpc.load(__dirname + '/test_service.proto'); + server = new grpc.Server(); + server.addService(proto.TestService.service, { + unary: function(call, cb) { + call.sendMetadata(call.metadata); + cb(null, {}); + }, + clientStream: function(stream, cb){ + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.sendMetadata(stream.metadata); + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.sendMetadata(stream.metadata); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.sendMetadata(stream.metadata); + stream.end(); + }); + } + }); + var creds = grpc.ServerCredentials.createSsl(null, + [{private_key: key_data, + cert_chain: pem_data}]); + port = server.bind('localhost:0', creds); + server.start(); + + Client = proto.TestService; + client_ssl_creds = grpc.credentials.createSsl(ca_data); + var host_override = 'foo.test.google.fr'; + client_options['grpc.ssl_target_name_override'] = host_override; + client_options['grpc.default_authority'] = host_override; + }); + after(function() { + server.forceShutdown(); + }); + it('Should accept SSL creds for a client', function(done) { + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ifError(err); + done(); + }); + }); + it('Should update metadata with SSL creds', function(done) { + var metadataUpdater = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.set('plugin_key', 'plugin_value'); + callback(null, metadata); + }; + var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); + var client = new Client('localhost:' + port, combined_creds, + client_options); + var call = client.unary({}, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + }); + it('Should update metadata for two simultaneous calls', function(done) { + done = multiDone(done, 2); + var metadataUpdater = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.set('plugin_key', 'plugin_value'); + callback(null, metadata); + }; + var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); + var client = new Client('localhost:' + port, combined_creds, + client_options); + var call = client.unary({}, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + var call2 = client.unary({}, function(err, data) { + assert.ifError(err); + }); + call2.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + }); + it('should propagate errors that the updater emits', function(done) { + var metadataUpdater = function(service_url, callback) { + var error = new Error('Authentication error'); + error.code = grpc.status.UNAUTHENTICATED; + callback(error); + }; + var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); + var client = new Client('localhost:' + port, combined_creds, + client_options); + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.message, + 'Getting metadata from plugin failed with error: ' + + 'Authentication error'); + assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED); + done(); + }); + }); + it('should successfully wrap a Google credential', function(done) { + var creds = grpc.credentials.createFromGoogleCredential( + fakeSuccessfulGoogleCredentials); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); + var client = new Client('localhost:' + port, combined_creds, + client_options); + var call = client.unary({}, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('authorization'), ['success']); + done(); + }); + }); + it('Should not add metadata with just SSL credentials', function(done) { + // Tests idempotency of credentials composition + var metadataUpdater = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.set('plugin_key', 'plugin_value'); + callback(null, metadata); + }; + var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); + grpc.credentials.combineChannelCredentials(client_ssl_creds, creds); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + var call = client.unary({}, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), []); + done(); + }); + }); + it('should get an error from a Google credential', function(done) { + var creds = grpc.credentials.createFromGoogleCredential( + fakeFailingGoogleCredentials); + var combined_creds = grpc.credentials.combineChannelCredentials( + client_ssl_creds, creds); + var client = new Client('localhost:' + port, combined_creds, + client_options); + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.message, + 'Getting metadata from plugin failed with error: ' + + 'Authentication failure'); + done(); + }); + }); + describe('Per-rpc creds', function() { + var client; + var updater_creds; + before(function() { + client = new Client('localhost:' + port, client_ssl_creds, + client_options); + var metadataUpdater = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.set('plugin_key', 'plugin_value'); + callback(null, metadata); + }; + updater_creds = grpc.credentials.createFromMetadataGenerator( + metadataUpdater); + }); + it('Should update metadata on a unary call', function(done) { + var call = client.unary({}, {credentials: updater_creds}, + function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + }); + it('should update metadata on a client streaming call', function(done) { + var call = client.clientStream({credentials: updater_creds}, + function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + call.end(); + }); + it('should update metadata on a server streaming call', function(done) { + var call = client.serverStream({}, {credentials: updater_creds}); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + }); + it('should update metadata on a bidi streaming call', function(done) { + var call = client.bidiStream({credentials: updater_creds}); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + done(); + }); + call.end(); + }); + it('should be able to use multiple plugin credentials', function(done) { + var altMetadataUpdater = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.set('other_plugin_key', 'other_plugin_value'); + callback(null, metadata); + }; + var alt_updater_creds = grpc.credentials.createFromMetadataGenerator( + altMetadataUpdater); + var combined_updater = grpc.credentials.combineCallCredentials( + updater_creds, alt_updater_creds); + var call = client.unary({}, {credentials: combined_updater}, + function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); + assert.deepEqual(metadata.get('other_plugin_key'), + ['other_plugin_value']); + done(); + }); + }); + }); +}); diff --git a/packages/grpc-native-core/test/data/README b/packages/grpc-native-core/test/data/README new file mode 100644 index 000000000..888d95b90 --- /dev/null +++ b/packages/grpc-native-core/test/data/README @@ -0,0 +1 @@ +CONFIRMEDTESTKEY diff --git a/packages/grpc-native-core/test/data/ca.pem b/packages/grpc-native-core/test/data/ca.pem new file mode 100644 index 000000000..6c8511a73 --- /dev/null +++ b/packages/grpc-native-core/test/data/ca.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla +Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 +YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT +BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 ++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu +g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd +Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau +sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m +oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG +Dfcog5wrJytaQ6UA0wE= +-----END CERTIFICATE----- diff --git a/packages/grpc-native-core/test/data/server1.key b/packages/grpc-native-core/test/data/server1.key new file mode 100644 index 000000000..143a5b876 --- /dev/null +++ b/packages/grpc-native-core/test/data/server1.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD +M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf +3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY +AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm +V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY +tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p +dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q +K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR +81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff +DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd +aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 +ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 +XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe +F98XJ7tIFfJq +-----END PRIVATE KEY----- diff --git a/packages/grpc-native-core/test/data/server1.pem b/packages/grpc-native-core/test/data/server1.pem new file mode 100644 index 000000000..f3d43fcc5 --- /dev/null +++ b/packages/grpc-native-core/test/data/server1.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 +-----END CERTIFICATE----- diff --git a/packages/grpc-native-core/test/echo_service.proto b/packages/grpc-native-core/test/echo_service.proto new file mode 100644 index 000000000..0b27c8b16 --- /dev/null +++ b/packages/grpc-native-core/test/echo_service.proto @@ -0,0 +1,24 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +message EchoMessage { + string value = 1; + int32 value2 = 2; +} + +service EchoService { + rpc Echo (EchoMessage) returns (EchoMessage); +} diff --git a/packages/grpc-native-core/test/file_load_test.js b/packages/grpc-native-core/test/file_load_test.js new file mode 100644 index 000000000..f6c6f3af6 --- /dev/null +++ b/packages/grpc-native-core/test/file_load_test.js @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var grpc = require('..'); + +describe('File loader', function() { + it('Should load a proto file by default', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.proto'); + }); + }); + it('Should load a proto file with the proto format', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.proto', 'proto'); + }); + }); + it('Should load a json file with the json format', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.json', 'json'); + }); + }); +}); diff --git a/packages/grpc-native-core/test/health_test.js b/packages/grpc-native-core/test/health_test.js new file mode 100644 index 000000000..821036f81 --- /dev/null +++ b/packages/grpc-native-core/test/health_test.js @@ -0,0 +1,103 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); + +var health = require('../../grpc-health-check/health'); + +var health_messages = require('../../grpc-health-check/v1/health_pb'); + +var ServingStatus = health_messages.HealthCheckResponse.ServingStatus; + +var grpc = require('../'); + +describe('Health Checking', function() { + var statusMap = { + '': ServingStatus.SERVING, + 'grpc.test.TestServiceNotServing': ServingStatus.NOT_SERVING, + 'grpc.test.TestServiceServing': ServingStatus.SERVING + }; + var healthServer; + var healthImpl; + var healthClient; + before(function() { + healthServer = new grpc.Server(); + healthImpl = new health.Implementation(statusMap); + healthServer.addService(health.service, healthImpl); + var port_num = healthServer.bind('0.0.0.0:0', + grpc.ServerCredentials.createInsecure()); + healthServer.start(); + healthClient = new health.Client('localhost:' + port_num, + grpc.credentials.createInsecure()); + }); + after(function() { + healthServer.forceShutdown(); + }); + it('should say an enabled service is SERVING', function(done) { + var request = new health_messages.HealthCheckRequest(); + request.setService(''); + healthClient.check(request, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.getStatus(), ServingStatus.SERVING); + done(); + }); + }); + it('should say that a disabled service is NOT_SERVING', function(done) { + var request = new health_messages.HealthCheckRequest(); + request.setService('grpc.test.TestServiceNotServing'); + healthClient.check(request, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.getStatus(), ServingStatus.NOT_SERVING); + done(); + }); + }); + it('should say that an enabled service is SERVING', function(done) { + var request = new health_messages.HealthCheckRequest(); + request.setService('grpc.test.TestServiceServing'); + healthClient.check(request, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.getStatus(), ServingStatus.SERVING); + done(); + }); + }); + it('should get NOT_FOUND if the service is not registered', function(done) { + var request = new health_messages.HealthCheckRequest(); + request.setService('not_registered'); + healthClient.check(request, function(err, response) { + assert(err); + assert.strictEqual(err.code, grpc.status.NOT_FOUND); + done(); + }); + }); + it('should get a different response if the status changes', function(done) { + var request = new health_messages.HealthCheckRequest(); + request.setService('transient'); + healthClient.check(request, function(err, response) { + assert(err); + assert.strictEqual(err.code, grpc.status.NOT_FOUND); + healthImpl.setStatus('transient', ServingStatus.SERVING); + healthClient.check(request, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.getStatus(), ServingStatus.SERVING); + done(); + }); + }); + }); +}); diff --git a/packages/grpc-native-core/test/interop_sanity_test.js b/packages/grpc-native-core/test/interop_sanity_test.js new file mode 100644 index 000000000..b3f65a034 --- /dev/null +++ b/packages/grpc-native-core/test/interop_sanity_test.js @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var interop_server = require('../interop/interop_server.js'); +var interop_client = require('../interop/interop_client.js'); + +var server; + +var port; + +var name_override = 'foo.test.google.fr'; + +describe('Interop tests', function() { + before(function(done) { + var server_obj = interop_server.getServer(0, true); + server = server_obj.server; + server.start(); + port = 'localhost:' + server_obj.port; + done(); + }); + after(function() { + server.forceShutdown(); + }); + // This depends on not using a binary stream + it('should pass empty_unary', function(done) { + interop_client.runTest(port, name_override, 'empty_unary', true, true, + done); + }); + // This fails due to an unknown bug + it('should pass large_unary', function(done) { + interop_client.runTest(port, name_override, 'large_unary', true, true, + done); + }); + it('should pass client_streaming', function(done) { + interop_client.runTest(port, name_override, 'client_streaming', true, true, + done); + }); + it('should pass server_streaming', function(done) { + interop_client.runTest(port, name_override, 'server_streaming', true, true, + done); + }); + it('should pass ping_pong', function(done) { + interop_client.runTest(port, name_override, 'ping_pong', true, true, done); + }); + it('should pass empty_stream', function(done) { + interop_client.runTest(port, name_override, 'empty_stream', true, true, + done); + }); + it('should pass cancel_after_begin', function(done) { + interop_client.runTest(port, name_override, 'cancel_after_begin', true, + true, done); + }); + it('should pass cancel_after_first_response', function(done) { + interop_client.runTest(port, name_override, 'cancel_after_first_response', + true, true, done); + }); + it('should pass timeout_on_sleeping_server', function(done) { + interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', + true, true, done); + }); + it('should pass custom_metadata', function(done) { + interop_client.runTest(port, name_override, 'custom_metadata', + true, true, done); + }); + it('should pass status_code_and_message', function(done) { + interop_client.runTest(port, name_override, 'status_code_and_message', + true, true, done); + }); + it('should pass unimplemented_service', function(done) { + interop_client.runTest(port, name_override, 'unimplemented_service', + true, true, done); + }); + it('should pass unimplemented_method', function(done) { + interop_client.runTest(port, name_override, 'unimplemented_method', + true, true, done); + }); +}); diff --git a/packages/grpc-native-core/test/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js new file mode 100644 index 000000000..afd08a34a --- /dev/null +++ b/packages/grpc-native-core/test/math/math_grpc_pb.js @@ -0,0 +1,125 @@ +// GENERATED CODE -- DO NOT EDIT! + +// Original file comments: +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +'use strict'; +var grpc = require('grpc'); +var math_math_pb = require('../math/math_pb.js'); + +function serialize_DivArgs(arg) { + if (!(arg instanceof math_math_pb.DivArgs)) { + throw new Error('Expected argument of type DivArgs'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_DivArgs(buffer_arg) { + return math_math_pb.DivArgs.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_DivReply(arg) { + if (!(arg instanceof math_math_pb.DivReply)) { + throw new Error('Expected argument of type DivReply'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_DivReply(buffer_arg) { + return math_math_pb.DivReply.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_FibArgs(arg) { + if (!(arg instanceof math_math_pb.FibArgs)) { + throw new Error('Expected argument of type FibArgs'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_FibArgs(buffer_arg) { + return math_math_pb.FibArgs.deserializeBinary(new Uint8Array(buffer_arg)); +} + +function serialize_Num(arg) { + if (!(arg instanceof math_math_pb.Num)) { + throw new Error('Expected argument of type Num'); + } + return new Buffer(arg.serializeBinary()); +} + +function deserialize_Num(buffer_arg) { + return math_math_pb.Num.deserializeBinary(new Uint8Array(buffer_arg)); +} + + +var MathService = exports.MathService = { + // Div divides args.dividend by args.divisor and returns the quotient and + // remainder. + div: { + path: '/math.Math/Div', + requestStream: false, + responseStream: false, + requestType: math_math_pb.DivArgs, + responseType: math_math_pb.DivReply, + requestSerialize: serialize_DivArgs, + requestDeserialize: deserialize_DivArgs, + responseSerialize: serialize_DivReply, + responseDeserialize: deserialize_DivReply, + }, + // DivMany accepts an arbitrary number of division args from the client stream + // and sends back the results in the reply stream. The stream continues until + // the client closes its end; the server does the same after sending all the + // replies. The stream ends immediately if either end aborts. + divMany: { + path: '/math.Math/DivMany', + requestStream: true, + responseStream: true, + requestType: math_math_pb.DivArgs, + responseType: math_math_pb.DivReply, + requestSerialize: serialize_DivArgs, + requestDeserialize: deserialize_DivArgs, + responseSerialize: serialize_DivReply, + responseDeserialize: deserialize_DivReply, + }, + // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib + // generates up to limit numbers; otherwise it continues until the call is + // canceled. Unlike Fib above, Fib has no final FibReply. + fib: { + path: '/math.Math/Fib', + requestStream: false, + responseStream: true, + requestType: math_math_pb.FibArgs, + responseType: math_math_pb.Num, + requestSerialize: serialize_FibArgs, + requestDeserialize: deserialize_FibArgs, + responseSerialize: serialize_Num, + responseDeserialize: deserialize_Num, + }, + // Sum sums a stream of numbers, returning the final result once the stream + // is closed. + sum: { + path: '/math.Math/Sum', + requestStream: true, + responseStream: false, + requestType: math_math_pb.Num, + responseType: math_math_pb.Num, + requestSerialize: serialize_Num, + requestDeserialize: deserialize_Num, + responseSerialize: serialize_Num, + responseDeserialize: deserialize_Num, + }, +}; + +exports.MathClient = grpc.makeGenericClientConstructor(MathService); diff --git a/packages/grpc-native-core/test/math/math_pb.js b/packages/grpc-native-core/test/math/math_pb.js new file mode 100644 index 000000000..ccc05c6e0 --- /dev/null +++ b/packages/grpc-native-core/test/math/math_pb.js @@ -0,0 +1,866 @@ +/** + * @fileoverview + * @enhanceable + * @public + */ +// GENERATED CODE -- DO NOT EDIT! + +var jspb = require('google-protobuf'); +var goog = jspb; +var global = Function('return this')(); + +goog.exportSymbol('proto.math.DivArgs', null, global); +goog.exportSymbol('proto.math.DivReply', null, global); +goog.exportSymbol('proto.math.FibArgs', null, global); +goog.exportSymbol('proto.math.FibReply', null, global); +goog.exportSymbol('proto.math.Num', 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.math.DivArgs = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.math.DivArgs, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.math.DivArgs.displayName = 'proto.math.DivArgs'; +} + + +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_, 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.math.DivArgs.prototype.toObject = function(opt_includeInstance) { + return proto.math.DivArgs.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.math.DivArgs} msg The msg instance to transform. + * @return {!Object} + */ +proto.math.DivArgs.toObject = function(includeInstance, msg) { + var f, obj = { + dividend: msg.getDividend(), + divisor: msg.getDivisor() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.math.DivArgs} + */ +proto.math.DivArgs.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.math.DivArgs; + return proto.math.DivArgs.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.math.DivArgs} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.math.DivArgs} + */ +proto.math.DivArgs.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt64()); + msg.setDividend(value); + break; + case 2: + var value = /** @type {number} */ (reader.readInt64()); + msg.setDivisor(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.math.DivArgs} message + * @param {!jspb.BinaryWriter} writer + */ +proto.math.DivArgs.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.math.DivArgs.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.math.DivArgs.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getDividend(); + if (f !== 0) { + writer.writeInt64( + 1, + f + ); + } + f = this.getDivisor(); + if (f !== 0) { + writer.writeInt64( + 2, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.math.DivArgs} The clone. + */ +proto.math.DivArgs.prototype.cloneMessage = function() { + return /** @type {!proto.math.DivArgs} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int64 dividend = 1; + * @return {number} + */ +proto.math.DivArgs.prototype.getDividend = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.math.DivArgs.prototype.setDividend = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional int64 divisor = 2; + * @return {number} + */ +proto.math.DivArgs.prototype.getDivisor = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.math.DivArgs.prototype.setDivisor = function(value) { + jspb.Message.setField(this, 2, 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.math.DivReply = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.math.DivReply, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.math.DivReply.displayName = 'proto.math.DivReply'; +} + + +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_, 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.math.DivReply.prototype.toObject = function(opt_includeInstance) { + return proto.math.DivReply.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.math.DivReply} msg The msg instance to transform. + * @return {!Object} + */ +proto.math.DivReply.toObject = function(includeInstance, msg) { + var f, obj = { + quotient: msg.getQuotient(), + remainder: msg.getRemainder() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.math.DivReply} + */ +proto.math.DivReply.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.math.DivReply; + return proto.math.DivReply.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.math.DivReply} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.math.DivReply} + */ +proto.math.DivReply.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt64()); + msg.setQuotient(value); + break; + case 2: + var value = /** @type {number} */ (reader.readInt64()); + msg.setRemainder(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.math.DivReply} message + * @param {!jspb.BinaryWriter} writer + */ +proto.math.DivReply.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.math.DivReply.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.math.DivReply.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getQuotient(); + if (f !== 0) { + writer.writeInt64( + 1, + f + ); + } + f = this.getRemainder(); + if (f !== 0) { + writer.writeInt64( + 2, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.math.DivReply} The clone. + */ +proto.math.DivReply.prototype.cloneMessage = function() { + return /** @type {!proto.math.DivReply} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int64 quotient = 1; + * @return {number} + */ +proto.math.DivReply.prototype.getQuotient = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.math.DivReply.prototype.setQuotient = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +/** + * optional int64 remainder = 2; + * @return {number} + */ +proto.math.DivReply.prototype.getRemainder = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); +}; + + +/** @param {number} value */ +proto.math.DivReply.prototype.setRemainder = function(value) { + jspb.Message.setField(this, 2, 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.math.FibArgs = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.math.FibArgs, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.math.FibArgs.displayName = 'proto.math.FibArgs'; +} + + +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_, 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.math.FibArgs.prototype.toObject = function(opt_includeInstance) { + return proto.math.FibArgs.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.math.FibArgs} msg The msg instance to transform. + * @return {!Object} + */ +proto.math.FibArgs.toObject = function(includeInstance, msg) { + var f, obj = { + limit: msg.getLimit() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.math.FibArgs} + */ +proto.math.FibArgs.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.math.FibArgs; + return proto.math.FibArgs.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.math.FibArgs} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.math.FibArgs} + */ +proto.math.FibArgs.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt64()); + msg.setLimit(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.math.FibArgs} message + * @param {!jspb.BinaryWriter} writer + */ +proto.math.FibArgs.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.math.FibArgs.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.math.FibArgs.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getLimit(); + if (f !== 0) { + writer.writeInt64( + 1, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.math.FibArgs} The clone. + */ +proto.math.FibArgs.prototype.cloneMessage = function() { + return /** @type {!proto.math.FibArgs} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int64 limit = 1; + * @return {number} + */ +proto.math.FibArgs.prototype.getLimit = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.math.FibArgs.prototype.setLimit = 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.math.Num = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.math.Num, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.math.Num.displayName = 'proto.math.Num'; +} + + +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_, 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.math.Num.prototype.toObject = function(opt_includeInstance) { + return proto.math.Num.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.math.Num} msg The msg instance to transform. + * @return {!Object} + */ +proto.math.Num.toObject = function(includeInstance, msg) { + var f, obj = { + num: msg.getNum() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.math.Num} + */ +proto.math.Num.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.math.Num; + return proto.math.Num.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.math.Num} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.math.Num} + */ +proto.math.Num.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt64()); + msg.setNum(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.math.Num} message + * @param {!jspb.BinaryWriter} writer + */ +proto.math.Num.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.math.Num.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.math.Num.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getNum(); + if (f !== 0) { + writer.writeInt64( + 1, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.math.Num} The clone. + */ +proto.math.Num.prototype.cloneMessage = function() { + return /** @type {!proto.math.Num} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int64 num = 1; + * @return {number} + */ +proto.math.Num.prototype.getNum = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.math.Num.prototype.setNum = 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.math.FibReply = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.math.FibReply, jspb.Message); +if (goog.DEBUG && !COMPILED) { + proto.math.FibReply.displayName = 'proto.math.FibReply'; +} + + +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_, 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.math.FibReply.prototype.toObject = function(opt_includeInstance) { + return proto.math.FibReply.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.math.FibReply} msg The msg instance to transform. + * @return {!Object} + */ +proto.math.FibReply.toObject = function(includeInstance, msg) { + var f, obj = { + count: msg.getCount() + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.math.FibReply} + */ +proto.math.FibReply.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.math.FibReply; + return proto.math.FibReply.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.math.FibReply} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.math.FibReply} + */ +proto.math.FibReply.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {number} */ (reader.readInt64()); + msg.setCount(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.math.FibReply} message + * @param {!jspb.BinaryWriter} writer + */ +proto.math.FibReply.serializeBinaryToWriter = function(message, writer) { + message.serializeBinaryToWriter(writer); +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.math.FibReply.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.math.FibReply.prototype.serializeBinaryToWriter = function (writer) { + var f = undefined; + f = this.getCount(); + if (f !== 0) { + writer.writeInt64( + 1, + f + ); + } +}; + + +/** + * Creates a deep clone of this proto. No data is shared with the original. + * @return {!proto.math.FibReply} The clone. + */ +proto.math.FibReply.prototype.cloneMessage = function() { + return /** @type {!proto.math.FibReply} */ (jspb.Message.cloneMessage(this)); +}; + + +/** + * optional int64 count = 1; + * @return {number} + */ +proto.math.FibReply.prototype.getCount = function() { + return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); +}; + + +/** @param {number} value */ +proto.math.FibReply.prototype.setCount = function(value) { + jspb.Message.setField(this, 1, value); +}; + + +goog.object.extend(exports, proto.math); diff --git a/packages/grpc-native-core/test/math/math_server.js b/packages/grpc-native-core/test/math/math_server.js new file mode 100644 index 000000000..4291ae18b --- /dev/null +++ b/packages/grpc-native-core/test/math/math_server.js @@ -0,0 +1,124 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var grpc = require('../..'); +var grpcMath = require('./math_grpc_pb'); +var math = require('./math_pb'); + +/** + * Server function for division. Provides the /Math/DivMany and /Math/Div + * functions (Div is just DivMany with only one stream element). For each + * DivArgs parameter, responds with a DivReply with the results of the division + * @param {Object} call The object containing request and cancellation info + * @param {function(Error, *)} cb Response callback + */ +function mathDiv(call, cb) { + var req = call.request; + var divisor = req.getDivisor(); + var dividend = req.getDividend(); + // Unary + is explicit coersion to integer + if (req.getDivisor() === 0) { + cb(new Error('cannot divide by zero')); + } else { + var response = new math.DivReply(); + response.setQuotient(Math.floor(dividend / divisor)); + response.setRemainder(dividend % divisor); + cb(null, response); + } +} + +/** + * Server function for Fibonacci numbers. Provides the /Math/Fib function. Reads + * a single parameter that indicates the number of responses, and then responds + * with a stream of that many Fibonacci numbers. + * @param {stream} stream The stream for sending responses. + */ +function mathFib(stream) { + // Here, call is a standard writable Node object Stream + var previous = 0, current = 1; + for (var i = 0; i < stream.request.getLimit(); i++) { + var response = new math.Num(); + response.setNum(current); + stream.write(response); + var temp = current; + current += previous; + previous = temp; + } + stream.end(); +} + +/** + * Server function for summation. Provides the /Math/Sum function. Reads a + * stream of number parameters, then responds with their sum. + * @param {stream} call The stream of arguments. + * @param {function(Error, *)} cb Response callback + */ +function mathSum(call, cb) { + // Here, call is a standard readable Node object Stream + var sum = 0; + call.on('data', function(data) { + sum += data.getNum(); + }); + call.on('end', function() { + var response = new math.Num(); + response.setNum(sum); + cb(null, response); + }); +} + +function mathDivMany(stream) { + stream.on('data', function(div_args) { + var divisor = div_args.getDivisor(); + var dividend = div_args.getDividend(); + if (divisor === 0) { + stream.emit('error', new Error('cannot divide by zero')); + } else { + var response = new math.DivReply(); + response.setQuotient(Math.floor(dividend / divisor)); + response.setRemainder(dividend % divisor); + stream.write(response); + } + }); + stream.on('end', function() { + stream.end(); + }); +} + +function getMathServer() { + var server = new grpc.Server(); + server.addService(grpcMath.MathService, { + div: mathDiv, + fib: mathFib, + sum: mathSum, + divMany: mathDivMany + }); + return server; +} + +if (require.main === module) { + var server = getMathServer(); + server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); + server.start(); +} + +/** + * See docs for server + */ +module.exports = getMathServer; diff --git a/packages/grpc-native-core/test/math_client_test.js b/packages/grpc-native-core/test/math_client_test.js new file mode 100644 index 000000000..11deda34f --- /dev/null +++ b/packages/grpc-native-core/test/math_client_test.js @@ -0,0 +1,140 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); + +var grpc = require('..'); +var math = require('./math/math_pb'); +var MathClient = require('./math/math_grpc_pb').MathClient; + +/** + * Client to use to make requests to a running server. + */ +var math_client; + +/** + * Server to test against + */ +var getServer = require('./math/math_server.js'); + +var server = getServer(); + +describe('Math client', function() { + before(function(done) { + var port_num = server.bind('0.0.0.0:0', + grpc.ServerCredentials.createInsecure()); + server.start(); + math_client = new MathClient('localhost:' + port_num, + grpc.credentials.createInsecure()); + done(); + }); + after(function() { + server.forceShutdown(); + }); + it('should handle a single request', function(done) { + var arg = new math.DivArgs(); + arg.setDividend(7); + arg.setDivisor(4); + math_client.div(arg, function handleDivResult(err, value) { + assert.ifError(err); + assert.equal(value.getQuotient(), 1); + assert.equal(value.getRemainder(), 3); + done(); + }); + }); + it('should handle an error from a unary request', function(done) { + var arg = new math.DivArgs(); + arg.setDividend(7); + arg.setDivisor(0); + math_client.div(arg, function handleDivResult(err, value) { + assert(err); + done(); + }); + }); + it('should handle a server streaming request', function(done) { + var arg = new math.FibArgs(); + arg.setLimit(7); + var call = math_client.fib(arg); + var expected_results = [1, 1, 2, 3, 5, 8, 13]; + var next_expected = 0; + call.on('data', function checkResponse(value) { + assert.equal(value.getNum(), expected_results[next_expected]); + next_expected += 1; + }); + call.on('status', function checkStatus(status) { + assert.strictEqual(status.code, grpc.status.OK); + done(); + }); + }); + it('should handle a client streaming request', function(done) { + var call = math_client.sum(function handleSumResult(err, value) { + assert.ifError(err); + assert.equal(value.getNum(), 21); + }); + for (var i = 0; i < 7; i++) { + var arg = new math.Num(); + arg.setNum(i); + call.write(arg); + } + call.end(); + call.on('status', function checkStatus(status) { + assert.strictEqual(status.code, grpc.status.OK); + done(); + }); + }); + it('should handle a bidirectional streaming request', function(done) { + function checkResponse(index, value) { + assert.equal(value.getQuotient(), index); + assert.equal(value.getRemainder(), 1); + } + var call = math_client.divMany(); + var response_index = 0; + call.on('data', function(value) { + checkResponse(response_index, value); + response_index += 1; + }); + for (var i = 0; i < 7; i++) { + var arg = new math.DivArgs(); + arg.setDividend(2 * i + 1); + arg.setDivisor(2); + call.write(arg); + } + call.end(); + call.on('status', function checkStatus(status) { + assert.strictEqual(status.code, grpc.status.OK); + done(); + }); + }); + it('should handle an error from a bidi request', function(done) { + var call = math_client.divMany(); + call.on('data', function(value) { + assert.fail(value, undefined, 'Unexpected data response on failing call', + '!='); + }); + var arg = new math.DivArgs(); + arg.setDividend(7); + arg.setDivisor(0); + call.write(arg); + call.end(); + call.on('error', function checkStatus(status) { + done(); + }); + }); +}); diff --git a/packages/grpc-native-core/test/metadata_test.js b/packages/grpc-native-core/test/metadata_test.js new file mode 100644 index 000000000..4ba54e0aa --- /dev/null +++ b/packages/grpc-native-core/test/metadata_test.js @@ -0,0 +1,178 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var Metadata = require('../src/metadata.js'); + +var assert = require('assert'); + +describe('Metadata', function() { + var metadata; + beforeEach(function() { + metadata = new Metadata(); + }); + describe('#set', function() { + it('Only accepts string values for non "-bin" keys', function() { + assert.throws(function() { + metadata.set('key', new Buffer('value')); + }); + assert.doesNotThrow(function() { + metadata.set('key', 'value'); + }); + }); + it('Only accepts Buffer values for "-bin" keys', function() { + assert.throws(function() { + metadata.set('key-bin', 'value'); + }); + assert.doesNotThrow(function() { + metadata.set('key-bin', new Buffer('value')); + }); + }); + it('Rejects invalid keys', function() { + assert.throws(function() { + metadata.set('key$', 'value'); + }); + assert.throws(function() { + metadata.set('', 'value'); + }); + }); + it('Rejects values with non-ASCII characters', function() { + assert.throws(function() { + metadata.set('key', 'résumé'); + }); + }); + it('Saves values that can be retrieved', function() { + metadata.set('key', 'value'); + assert.deepEqual(metadata.get('key'), ['value']); + }); + it('Overwrites previous values', function() { + metadata.set('key', 'value1'); + metadata.set('key', 'value2'); + assert.deepEqual(metadata.get('key'), ['value2']); + }); + it('Normalizes keys', function() { + metadata.set('Key', 'value1'); + assert.deepEqual(metadata.get('key'), ['value1']); + metadata.set('KEY', 'value2'); + assert.deepEqual(metadata.get('key'), ['value2']); + }); + }); + describe('#add', function() { + it('Only accepts string values for non "-bin" keys', function() { + assert.throws(function() { + metadata.add('key', new Buffer('value')); + }); + assert.doesNotThrow(function() { + metadata.add('key', 'value'); + }); + }); + it('Only accepts Buffer values for "-bin" keys', function() { + assert.throws(function() { + metadata.add('key-bin', 'value'); + }); + assert.doesNotThrow(function() { + metadata.add('key-bin', new Buffer('value')); + }); + }); + it('Rejects invalid keys', function() { + assert.throws(function() { + metadata.add('key$', 'value'); + }); + assert.throws(function() { + metadata.add('', 'value'); + }); + }); + it('Saves values that can be retrieved', function() { + metadata.add('key', 'value'); + assert.deepEqual(metadata.get('key'), ['value']); + }); + it('Combines with previous values', function() { + metadata.add('key', 'value1'); + metadata.add('key', 'value2'); + assert.deepEqual(metadata.get('key'), ['value1', 'value2']); + }); + it('Normalizes keys', function() { + metadata.add('Key', 'value1'); + assert.deepEqual(metadata.get('key'), ['value1']); + metadata.add('KEY', 'value2'); + assert.deepEqual(metadata.get('key'), ['value1', 'value2']); + }); + }); + describe('#remove', function() { + it('clears values from a key', function() { + metadata.add('key', 'value'); + metadata.remove('key'); + assert.deepEqual(metadata.get('key'), []); + }); + it('Normalizes keys', function() { + metadata.add('key', 'value'); + metadata.remove('KEY'); + assert.deepEqual(metadata.get('key'), []); + }); + }); + describe('#get', function() { + beforeEach(function() { + metadata.add('key', 'value1'); + metadata.add('key', 'value2'); + metadata.add('key-bin', new Buffer('value')); + }); + it('gets all values associated with a key', function() { + assert.deepEqual(metadata.get('key'), ['value1', 'value2']); + }); + it('Normalizes keys', function() { + assert.deepEqual(metadata.get('KEY'), ['value1', 'value2']); + }); + it('returns an empty list for non-existent keys', function() { + assert.deepEqual(metadata.get('non-existent-key'), []); + }); + it('returns Buffers for "-bin" keys', function() { + assert(metadata.get('key-bin')[0] instanceof Buffer); + }); + }); + describe('#getMap', function() { + it('gets a map of keys to values', function() { + metadata.add('key1', 'value1'); + metadata.add('Key2', 'value2'); + metadata.add('KEY3', 'value3'); + assert.deepEqual(metadata.getMap(), + {key1: 'value1', + key2: 'value2', + key3: 'value3'}); + }); + }); + describe('#clone', function() { + it('retains values from the original', function() { + metadata.add('key', 'value'); + var copy = metadata.clone(); + assert.deepEqual(copy.get('key'), ['value']); + }); + it('Does not see newly added values', function() { + metadata.add('key', 'value1'); + var copy = metadata.clone(); + metadata.add('key', 'value2'); + assert.deepEqual(copy.get('key'), ['value1']); + }); + it('Does not add new values to the original', function() { + metadata.add('key', 'value1'); + var copy = metadata.clone(); + copy.add('key', 'value2'); + assert.deepEqual(metadata.get('key'), ['value1']); + }); + }); +}); diff --git a/packages/grpc-native-core/test/numbers.txt b/packages/grpc-native-core/test/numbers.txt new file mode 100644 index 000000000..4972919b4 --- /dev/null +++ b/packages/grpc-native-core/test/numbers.txt @@ -0,0 +1,496 @@ +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 +1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 diff --git a/packages/grpc-native-core/test/server_test.js b/packages/grpc-native-core/test/server_test.js index c1b941948..454acbda1 100644 --- a/packages/grpc-native-core/test/server_test.js +++ b/packages/grpc-native-core/test/server_test.js @@ -72,8 +72,8 @@ describe('server', function() { }); it('should bind to an unused port with ssl credentials', function() { var port; - var key_path = path.join(__dirname, '../../../test/data/server1.key'); - var pem_path = path.join(__dirname, '../../../test/data/server1.pem'); + var key_path = path.join(__dirname, '../test/data/server1.key'); + var pem_path = path.join(__dirname, '../test/data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); var creds = grpc.ServerCredentials.createSsl(null, diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js new file mode 100644 index 000000000..ce6ede84d --- /dev/null +++ b/packages/grpc-native-core/test/surface_test.js @@ -0,0 +1,1379 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var _ = require('lodash'); + +var grpc = require('..'); + +var MathClient = grpc.load( + __dirname + '/../deps/grpc/src/proto/math/math.proto').math.Math; +var mathServiceAttrs = MathClient.service; + +/** + * This is used for testing functions with multiple asynchronous calls that + * can happen in different orders. This should be passed the number of async + * function invocations that can occur last, and each of those should call this + * function's return value + * @param {function()} done The function that should be called when a test is + * complete. + * @param {number} count The number of calls to the resulting function if the + * test passes. + * @return {function()} The function that should be called at the end of each + * sequence of asynchronous functions. + */ +function multiDone(done, count) { + return function() { + count -= 1; + if (count <= 0) { + done(); + } + }; +} + +var server_insecure_creds = grpc.ServerCredentials.createInsecure(); + +describe('File loader', function() { + it('Should load a proto file by default', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.proto'); + }); + }); + it('Should load a proto file with the proto format', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.proto', 'proto'); + }); + }); + it('Should load a json file with the json format', function() { + assert.doesNotThrow(function() { + grpc.load(__dirname + '/test_service.json', 'json'); + }); + }); +}); +describe('surface Server', function() { + var server; + beforeEach(function() { + server = new grpc.Server(); + }); + afterEach(function() { + server.forceShutdown(); + }); + it('should error if started twice', function() { + server.start(); + assert.throws(function() { + server.start(); + }); + }); + it('should error if a port is bound after the server starts', function() { + server.start(); + assert.throws(function() { + server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); + }); + }); + it('should successfully shutdown if tryShutdown is called', function(done) { + server.start(); + server.tryShutdown(done); + }); +}); +describe('Server.prototype.addService', function() { + var server; + var dummyImpls = { + 'div': function() {}, + 'divMany': function() {}, + 'fib': function() {}, + 'sum': function() {} + }; + beforeEach(function() { + server = new grpc.Server(); + }); + afterEach(function() { + server.forceShutdown(); + }); + it('Should succeed with a single service', function() { + assert.doesNotThrow(function() { + server.addService(mathServiceAttrs, dummyImpls); + }); + }); + it('Should fail with conflicting method names', function() { + server.addService(mathServiceAttrs, dummyImpls); + assert.throws(function() { + server.addService(mathServiceAttrs, dummyImpls); + }); + }); + it('Should allow method names as originally written', function() { + var altDummyImpls = { + 'Div': function() {}, + 'DivMany': function() {}, + 'Fib': function() {}, + 'Sum': function() {} + }; + assert.doesNotThrow(function() { + server.addService(mathServiceAttrs, altDummyImpls); + }); + }); + it('Should have a conflict between name variations', function() { + /* This is really testing that both name variations are actually used, + by checking that the method actually gets registered, for the + corresponding function, in both cases */ + var altDummyImpls = { + 'Div': function() {}, + 'DivMany': function() {}, + 'Fib': function() {}, + 'Sum': function() {} + }; + server.addProtoService(mathServiceAttrs, altDummyImpls); + assert.throws(function() { + server.addProtoService(mathServiceAttrs, dummyImpls); + }); + }); + it('Should fail if the server has been started', function() { + server.start(); + assert.throws(function() { + server.addService(mathServiceAttrs, dummyImpls); + }); + }); + describe('Default handlers', function() { + var client; + beforeEach(function() { + server.addService(mathServiceAttrs, {}); + var port = server.bind('localhost:0', server_insecure_creds); + client = new MathClient('localhost:' + port, + grpc.credentials.createInsecure()); + server.start(); + }); + it('should respond to a unary call with UNIMPLEMENTED', function(done) { + client.div({divisor: 4, dividend: 3}, function(error, response) { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + }); + }); + it('should respond to a client stream with UNIMPLEMENTED', function(done) { + var call = client.sum(function(error, respones) { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + }); + call.end(); + }); + it('should respond to a server stream with UNIMPLEMENTED', function(done) { + var call = client.fib({limit: 5}); + call.on('data', function(value) { + assert.fail('No messages expected'); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + done(); + }); + call.on('error', function(status) { /* Do nothing */ }); + }); + it('should respond to a bidi call with UNIMPLEMENTED', function(done) { + var call = client.divMany(); + call.on('data', function(value) { + assert.fail('No messages expected'); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + done(); + }); + call.on('error', function(status) { /* Do nothing */ }); + call.end(); + }); + }); +}); +describe('Client constructor building', function() { + var illegal_service_attrs = { + $method : { + path: '/illegal/$method', + requestStream: false, + responseStream: false, + requestSerialize: _.identity, + requestDeserialize: _.identity, + responseSerialize: _.identity, + responseDeserialize: _.identity + } + }; + it('Should reject method names starting with $', function() { + assert.throws(function() { + grpc.makeGenericClientConstructor(illegal_service_attrs); + }, /\$/); + }); + it('Should add aliases for original names', function() { + var Client = grpc.makeGenericClientConstructor(mathServiceAttrs); + assert.strictEqual(Client.prototype.add, Client.prototype.Add); + }); +}); +describe('waitForClientReady', function() { + var server; + var port; + var Client = MathClient; + var client; + before(function() { + server = new grpc.Server(); + port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); + server.start(); + }); + beforeEach(function() { + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + }); + after(function() { + server.forceShutdown(); + }); + it('should complete when called alone', function(done) { + grpc.waitForClientReady(client, Infinity, function(error) { + assert.ifError(error); + done(); + }); + }); + it('should complete when a call is initiated', function(done) { + grpc.waitForClientReady(client, Infinity, function(error) { + assert.ifError(error); + done(); + }); + var call = client.div({}, function(err, response) {}); + call.cancel(); + }); + it('should complete if called more than once', function(done) { + done = multiDone(done, 2); + grpc.waitForClientReady(client, Infinity, function(error) { + assert.ifError(error); + done(); + }); + grpc.waitForClientReady(client, Infinity, function(error) { + assert.ifError(error); + done(); + }); + }); + it('should complete if called when already ready', function(done) { + grpc.waitForClientReady(client, Infinity, function(error) { + assert.ifError(error); + grpc.waitForClientReady(client, Infinity, function(error) { + assert.ifError(error); + done(); + }); + }); + }); + it('should time out if the server does not exist', function(done) { + var bad_client = new Client('nonexistent_hostname', + grpc.credentials.createInsecure()); + var deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + grpc.waitForClientReady(bad_client, deadline, function(error) { + assert(error); + done(); + }); + }); +}); +describe('Echo service', function() { + var server; + var client; + before(function() { + var Client = grpc.load(__dirname + '/echo_service.proto').EchoService; + server = new grpc.Server(); + server.addService(Client.service, { + echo: function(call, callback) { + callback(null, call.request); + } + }); + var port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('should echo the recieved message directly', function(done) { + client.echo({value: 'test value', value2: 3}, function(error, response) { + assert.ifError(error); + assert.deepEqual(response, {value: 'test value', value2: 3}); + done(); + }); + }); + it('Should convert an undefined argument to default values', function(done) { + client.echo(undefined, function(error, response) { + assert.ifError(error); + assert.deepEqual(response, {value: '', value2: 0}); + done(); + }); + }); +}); +describe('Generic client and server', function() { + function toString(val) { + return val.toString(); + } + function toBuffer(str) { + return new Buffer(str); + } + var string_service_attrs = { + 'capitalize' : { + path: '/string/capitalize', + requestStream: false, + responseStream: false, + requestSerialize: toBuffer, + requestDeserialize: toString, + responseSerialize: toBuffer, + responseDeserialize: toString + } + }; + describe('String client and server', function() { + var client; + var server; + before(function() { + server = new grpc.Server(); + server.addService(string_service_attrs, { + capitalize: function(call, callback) { + callback(null, _.capitalize(call.request)); + } + }); + var port = server.bind('localhost:0', server_insecure_creds); + server.start(); + var Client = grpc.makeGenericClientConstructor(string_service_attrs); + client = new Client('localhost:' + port, + grpc.credentials.createInsecure()); + }); + after(function() { + server.forceShutdown(); + }); + it('Should respond with a capitalized string', function(done) { + client.capitalize('abc', function(err, response) { + assert.ifError(err); + assert.strictEqual(response, 'Abc'); + done(); + }); + }); + }); +}); +describe('Server-side getPeer', function() { + function toString(val) { + return val.toString(); + } + function toBuffer(str) { + return new Buffer(str); + } + var string_service_attrs = { + 'getPeer' : { + path: '/string/getPeer', + requestStream: false, + responseStream: false, + requestSerialize: toBuffer, + requestDeserialize: toString, + responseSerialize: toBuffer, + responseDeserialize: toString + } + }; + var client; + var server; + before(function() { + server = new grpc.Server(); + server.addService(string_service_attrs, { + getPeer: function(call, callback) { + try { + callback(null, call.getPeer()); + } catch (e) { + call.emit('error', e); + } + } + }); + var port = server.bind('localhost:0', server_insecure_creds); + server.start(); + var Client = grpc.makeGenericClientConstructor(string_service_attrs); + client = new Client('localhost:' + port, + grpc.credentials.createInsecure()); + }); + after(function() { + server.forceShutdown(); + }); + it('should respond with a string representing the client', function(done) { + client.getPeer('', function(err, response) { + assert.ifError(err); + // We don't expect a specific value, just that it worked without error + done(); + }); + }); +}); +describe('Echo metadata', function() { + var client; + var server; + var metadata; + before(function() { + var Client = grpc.load(__dirname + '/test_service.proto').TestService; + server = new grpc.Server(); + server.addService(Client.service, { + unary: function(call, cb) { + call.sendMetadata(call.metadata); + cb(null, {}); + }, + clientStream: function(stream, cb){ + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.sendMetadata(stream.metadata); + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.sendMetadata(stream.metadata); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.sendMetadata(stream.metadata); + stream.end(); + }); + } + }); + var port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + metadata = new grpc.Metadata(); + metadata.set('key', 'value'); + }); + after(function() { + server.forceShutdown(); + }); + it('with unary call', function(done) { + var call = client.unary({}, metadata, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + }); + it('with client stream call', function(done) { + var call = client.clientStream(metadata, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + call.end(); + }); + it('with server stream call', function(done) { + var call = client.serverStream({}, metadata); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + }); + it('with bidi stream call', function(done) { + var call = client.bidiStream(metadata); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + call.end(); + }); + it('shows the correct user-agent string', function(done) { + var version = require('../package.json').version; + var call = client.unary({}, metadata, + function(err, data) { assert.ifError(err); }); + call.on('metadata', function(metadata) { + assert(_.startsWith(metadata.get('user-agent')[0], + 'grpc-node/' + version)); + done(); + }); + }); + it('properly handles duplicate values', function(done) { + var dup_metadata = metadata.clone(); + dup_metadata.add('key', 'value2'); + var call = client.unary({}, dup_metadata, + function(err, data) {assert.ifError(err); }); + call.on('metadata', function(resp_metadata) { + // Two arrays are equal iff their symmetric difference is empty + assert.deepEqual(_.xor(dup_metadata.get('key'), resp_metadata.get('key')), + []); + done(); + }); + }); +}); +describe('Client malformed response handling', function() { + var server; + var client; + var badArg = new Buffer([0xFF]); + before(function() { + var Client = grpc.load(__dirname + '/test_service.proto').TestService; + var malformed_test_service = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: _.identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: _.identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: _.identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: _.identity + } + }; + server = new grpc.Server(); + server.addService(malformed_test_service, { + unary: function(call, cb) { + cb(null, badArg); + }, + clientStream: function(stream, cb) { + stream.on('data', function() {/* Ignore requests */}); + stream.on('end', function() { + cb(null, badArg); + }); + }, + serverStream: function(stream) { + stream.write(badArg); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write(badArg); + }); + stream.on('end', function() { + stream.end(); + }); + } + }); + var port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + it('should get an INTERNAL status with a server stream call', function(done) { + var call = client.serverStream({}); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a bidi stream call', function(done) { + var call = client.bidiStream(); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); +}); +describe('Server serialization failure handling', function() { + function serializeFail(obj) { + throw new Error('Serialization failed'); + } + var client; + var server; + before(function() { + var Client = grpc.load(__dirname + '/test_service.proto').TestService; + var malformed_test_service = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + } + }; + server = new grpc.Server(); + server.addService(malformed_test_service, { + unary: function(call, cb) { + cb(null, {}); + }, + clientStream: function(stream, cb) { + stream.on('data', function() {/* Ignore requests */}); + stream.on('end', function() { + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.write({}); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write({}); + }); + stream.on('end', function() { + stream.end(); + }); + } + }); + var port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + it('should get an INTERNAL status with a server stream call', function(done) { + var call = client.serverStream({}); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a bidi stream call', function(done) { + var call = client.bidiStream(); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); +}); +describe('Other conditions', function() { + var Client; + var client; + var server; + var port; + before(function() { + Client = grpc.load(__dirname + '/test_service.proto').TestService; + server = new grpc.Server(); + var trailer_metadata = new grpc.Metadata(); + trailer_metadata.add('trailer-present', 'yes'); + server.addService(Client.service, { + unary: function(call, cb) { + var req = call.request; + if (req.error) { + cb({code: grpc.status.UNKNOWN, + details: 'Requested error'}, null, trailer_metadata); + } else { + cb(null, {count: 1}, trailer_metadata); + } + }, + clientStream: function(stream, cb){ + var count = 0; + var errored; + stream.on('data', function(data) { + if (data.error) { + errored = true; + cb(new Error('Requested error'), null, trailer_metadata); + } else { + count += 1; + } + }); + stream.on('end', function() { + if (!errored) { + cb(null, {count: count}, trailer_metadata); + } + }); + }, + serverStream: function(stream) { + var req = stream.request; + if (req.error) { + var err = {code: grpc.status.UNKNOWN, + details: 'Requested error'}; + err.metadata = trailer_metadata; + stream.emit('error', err); + } else { + for (var i = 0; i < 5; i++) { + stream.write({count: i}); + } + stream.end(trailer_metadata); + } + }, + bidiStream: function(stream) { + var count = 0; + stream.on('data', function(data) { + if (data.error) { + var err = new Error('Requested error'); + err.metadata = trailer_metadata.clone(); + err.metadata.add('count', '' + count); + stream.emit('error', err); + } else { + stream.write({count: count}); + count += 1; + } + }); + stream.on('end', function() { + stream.end(trailer_metadata); + }); + } + }); + port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('channel.getTarget should be available', function() { + assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(), + 'string'); + }); + it('client should be able to pause and resume a stream', function(done) { + var call = client.bidiStream(); + call.on('data', function(data) { + assert(data.count < 3); + call.pause(); + setTimeout(function() { + call.resume(); + }, 10); + }); + call.on('end', function() { + done(); + }); + call.write({}); + call.write({}); + call.write({}); + call.end(); + }); + describe('Server recieving bad input', function() { + var misbehavingClient; + var badArg = new Buffer([0xFF]); + before(function() { + var test_service_attrs = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + } + }; + var Client = grpc.makeGenericClientConstructor(test_service_attrs, + 'TestService'); + misbehavingClient = new Client('localhost:' + port, + grpc.credentials.createInsecure()); + }); + it('should respond correctly to a unary call', function(done) { + misbehavingClient.unary(badArg, function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + it('should respond correctly to a client stream', function(done) { + var call = misbehavingClient.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); + }); + it('should respond correctly to a server stream', function(done) { + var call = misbehavingClient.serverStream(badArg); + call.on('data', function(data) { + assert.fail(data, null, 'Unexpected data', '==='); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + it('should respond correctly to a bidi stream', function(done) { + var call = misbehavingClient.bidiStream(); + call.on('data', function(data) { + assert.fail(data, null, 'Unexpected data', '==='); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); + }); + }); + describe('Trailing metadata', function() { + it('should be present when a unary call succeeds', function(done) { + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a unary call fails', function(done) { + var call = client.unary({error: true}, function(err, data) { + assert(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a client stream call succeeds', function(done) { + var call = client.clientStream(function(err, data) { + assert.ifError(err); + }); + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a client stream call fails', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + }); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a server stream call succeeds', function(done) { + var call = client.serverStream({error: false}); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a server stream call fails', function(done) { + var call = client.serverStream({error: true}); + call.on('data', function(){}); + call.on('error', function(error) { + assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a bidi stream succeeds', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a bidi stream fails', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', function(){}); + call.on('error', function(error) { + assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + }); + describe('Error object should contain the status', function() { + it('for a unary call', function(done) { + client.unary({error: true}, function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.message, 'Requested error'); + done(); + }); + }); + it('for a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.message, 'Requested error'); + done(); + }); + call.write({error: false}); + call.write({error: true}); + call.end(); + }); + it('for a server stream call', function(done) { + var call = client.serverStream({error: true}); + call.on('data', function(){}); + call.on('error', function(error) { + assert.strictEqual(error.code, grpc.status.UNKNOWN); + assert.strictEqual(error.message, 'Requested error'); + done(); + }); + }); + it('for a bidi stream call', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', function(){}); + call.on('error', function(error) { + assert.strictEqual(error.code, grpc.status.UNKNOWN); + assert.strictEqual(error.message, 'Requested error'); + done(); + }); + }); + }); + describe('call.getPeer should return the peer', function() { + it('for a unary call', function(done) { + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + done(); + }); + assert.strictEqual(typeof call.getPeer(), 'string'); + }); + it('for a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert.ifError(err); + done(); + }); + assert.strictEqual(typeof call.getPeer(), 'string'); + call.write({error: false}); + call.end(); + }); + it('for a server stream call', function(done) { + var call = client.serverStream({error: false}); + assert.strictEqual(typeof call.getPeer(), 'string'); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + done(); + }); + }); + it('for a bidi stream call', function(done) { + var call = client.bidiStream(); + assert.strictEqual(typeof call.getPeer(), 'string'); + call.write({error: false}); + call.end(); + call.on('data', function(){}); + call.on('status', function(status) { + done(); + }); + }); + it('after the call has fully completed', function(done) { + var peer; + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + setImmediate(function() { + assert.strictEqual(peer, call.getPeer()); + done(); + }); + }); + peer = call.getPeer(); + assert.strictEqual(typeof peer, 'string'); + }); + }); +}); +describe('Call propagation', function() { + var proxy; + var proxy_impl; + + var Client; + var client; + var server; + before(function() { + Client = grpc.load(__dirname + '/test_service.proto').TestService; + server = new grpc.Server(); + server.addService(Client.service, { + unary: function(call) {}, + clientStream: function(stream) {}, + serverStream: function(stream) {}, + bidiStream: function(stream) {} + }); + var port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + beforeEach(function() { + proxy = new grpc.Server(); + proxy_impl = { + unary: function(call) {}, + clientStream: function(stream) {}, + serverStream: function(stream) {}, + bidiStream: function(stream) {} + }; + }); + afterEach(function() { + proxy.forceShutdown(); + }); + describe('Cancellation', function() { + it('With a unary call', function(done) { + done = multiDone(done, 2); + var call; + proxy_impl.unary = function(parent, callback) { + client.unary(parent.request, {parent: parent}, function(err, value) { + try { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + } finally { + callback(err, value); + done(); + } + }); + call.cancel(); + }; + proxy.addService(Client.service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.credentials.createInsecure()); + call = proxy_client.unary({}, function(err, value) { done(); }); + }); + it('With a client stream call', function(done) { + done = multiDone(done, 2); + var call; + proxy_impl.clientStream = function(parent, callback) { + client.clientStream({parent: parent}, function(err, value) { + try { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + } finally { + callback(err, value); + done(); + } + }); + call.cancel(); + }; + proxy.addService(Client.service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.credentials.createInsecure()); + call = proxy_client.clientStream(function(err, value) { done(); }); + }); + it('With a server stream call', function(done) { + done = multiDone(done, 2); + var call; + proxy_impl.serverStream = function(parent) { + var child = client.serverStream(parent.request, {parent: parent}); + child.on('data', function() {}); + child.on('error', function(err) { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }; + proxy.addService(Client.service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.credentials.createInsecure()); + call = proxy_client.serverStream({}); + call.on('data', function() {}); + call.on('error', function(err) { + done(); + }); + }); + it('With a bidi stream call', function(done) { + done = multiDone(done, 2); + var call; + proxy_impl.bidiStream = function(parent) { + var child = client.bidiStream({parent: parent}); + child.on('data', function() {}); + child.on('error', function(err) { + assert(err); + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }; + proxy.addService(Client.service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.credentials.createInsecure()); + call = proxy_client.bidiStream(); + call.on('data', function() {}); + call.on('error', function(err) { + done(); + }); + }); + }); + describe('Deadline', function() { + /* jshint bitwise:false */ + var deadline_flags = (grpc.propagate.DEFAULTS & + ~grpc.propagate.CANCELLATION); + it('With a client stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.clientStream = function(parent, callback) { + var options = {parent: parent, propagate_flags: deadline_flags}; + client.clientStream(options, function(err, value) { + try { + assert(err); + assert(err.code === grpc.status.DEADLINE_EXCEEDED || + err.code === grpc.status.INTERNAL); + } finally { + callback(err, value); + done(); + } + }); + }; + proxy.addService(Client.service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.credentials.createInsecure()); + var deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + proxy_client.clientStream({deadline: deadline}, function(err, value) { + done(); + }); + }); + it('With a bidi stream call', function(done) { + done = multiDone(done, 2); + proxy_impl.bidiStream = function(parent) { + var child = client.bidiStream( + {parent: parent, propagate_flags: deadline_flags}); + child.on('data', function() {}); + child.on('error', function(err) { + assert(err); + assert(err.code === grpc.status.DEADLINE_EXCEEDED || + err.code === grpc.status.INTERNAL); + done(); + }); + }; + proxy.addService(Client.service, proxy_impl); + var proxy_port = proxy.bind('localhost:0', server_insecure_creds); + proxy.start(); + var proxy_client = new Client('localhost:' + proxy_port, + grpc.credentials.createInsecure()); + var deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + var call = proxy_client.bidiStream({deadline: deadline}); + call.on('data', function() {}); + call.on('error', function(err) { + done(); + }); + }); + }); +}); +describe('Cancelling surface client', function() { + var client; + var server; + before(function() { + server = new grpc.Server(); + server.addService(mathServiceAttrs, { + 'div': function(stream) {}, + 'divMany': function(stream) {}, + 'fib': function(stream) {}, + 'sum': function(stream) {} + }); + var port = server.bind('localhost:0', server_insecure_creds); + var Client = grpc.makeGenericClientConstructor(mathServiceAttrs); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('Should correctly cancel a unary call', function(done) { + var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should correctly cancel a client stream call', function(done) { + var call = client.sum(function(err, resp) { + assert.strictEqual(err.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should correctly cancel a server stream call', function(done) { + var call = client.fib({'limit': 5}); + call.on('data', function() {}); + call.on('error', function(error) { + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should correctly cancel a bidi stream call', function(done) { + var call = client.divMany(); + call.on('data', function() {}); + call.on('error', function(error) { + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + }); + it('Should be idempotent', function(done) { + var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { + assert.strictEqual(err.code, grpc.status.CANCELLED); + // Call asynchronously to try cancelling after call is fully completed + setImmediate(function() { + assert.doesNotThrow(function() { + call.cancel(); + }); + done(); + }); + }); + call.cancel(); + }); +}); +describe('Client reconnect', function() { + var server; + var Client; + var client; + var port; + beforeEach(function() { + Client = grpc.load(__dirname + '/echo_service.proto').EchoService; + server = new grpc.Server(); + server.addService(Client.service, { + echo: function(call, callback) { + callback(null, call.request); + } + }); + port = server.bind('localhost:0', server_insecure_creds); + client = new Client('localhost:' + port, grpc.credentials.createInsecure()); + server.start(); + }); + afterEach(function() { + server.forceShutdown(); + }); + it('should reconnect after server restart', function(done) { + client.echo({value: 'test value', value2: 3}, function(error, response) { + assert.ifError(error); + assert.deepEqual(response, {value: 'test value', value2: 3}); + server.tryShutdown(function() { + server = new grpc.Server(); + server.addService(Client.service, { + echo: function(call, callback) { + callback(null, call.request); + } + }); + server.bind('localhost:' + port, server_insecure_creds); + server.start(); + + /* We create a new client, that will not throw an error if the server + * is not immediately available. Instead, it will wait for the server + * to be available, then the call will complete. Once this happens, the + * original client should be able to make a new call and connect to the + * restarted server without having the call fail due to connection + * errors. */ + var client2 = new Client('localhost:' + port, + grpc.credentials.createInsecure()); + client2.echo({value: 'test', value2: 3}, function(error, response) { + assert.ifError(error); + client.echo(undefined, function(error, response) { + if (error) { + console.log(error); + } + assert.ifError(error); + assert.deepEqual(response, {value: '', value2: 0}); + done(); + }); + }); + }); + }); + }); +}); diff --git a/packages/grpc-native-core/test/test_service.json b/packages/grpc-native-core/test/test_service.json new file mode 100644 index 000000000..6f952c6ad --- /dev/null +++ b/packages/grpc-native-core/test/test_service.json @@ -0,0 +1,55 @@ +{ + "package": null, + "messages": [ + { + "name": "Request", + "fields": [ + { + "rule": "optional", + "type": "bool", + "name": "error", + "id": 1 + } + ] + }, + { + "name": "Response", + "fields": [ + { + "rule": "optional", + "type": "int32", + "name": "count", + "id": 1 + } + ] + } + ], + "services": [ + { + "name": "TestService", + "options": {}, + "rpc": { + "Unary": { + "request": "Request", + "response": "Response", + "options": {} + }, + "ClientStream": { + "request": "Request", + "response": "Response", + "options": {} + }, + "ServerStream": { + "request": "Request", + "response": "Response", + "options": {} + }, + "BidiStream": { + "request": "Request", + "response": "Response", + "options": {} + } + } + } + ] +} \ No newline at end of file diff --git a/packages/grpc-native-core/test/test_service.proto b/packages/grpc-native-core/test/test_service.proto new file mode 100644 index 000000000..b16dfecca --- /dev/null +++ b/packages/grpc-native-core/test/test_service.proto @@ -0,0 +1,37 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +message Request { + bool error = 1; +} + +message Response { + int32 count = 1; +} + +service TestService { + rpc Unary (Request) returns (Response) { + } + + rpc ClientStream (stream Request) returns (Response) { + } + + rpc ServerStream (Request) returns (stream Response) { + } + + rpc BidiStream (stream Request) returns (stream Response) { + } +} From 11416e9d70aef690d3f5d33f9d42cccf0b5142e1 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 6 Dec 2017 13:48:35 -0800 Subject: [PATCH 0042/1899] missed require change --- packages/grpc-native-core/test/math/math_grpc_pb.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js index afd08a34a..84123d761 100644 --- a/packages/grpc-native-core/test/math/math_grpc_pb.js +++ b/packages/grpc-native-core/test/math/math_grpc_pb.js @@ -16,7 +16,7 @@ // limitations under the License. // 'use strict'; -var grpc = require('grpc'); +var grpc = require('../..'); var math_math_pb = require('../math/math_pb.js'); function serialize_DivArgs(arg) { From dd140c463f282448cc92c07a2119869676e03013 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 7 Dec 2017 10:40:08 -0800 Subject: [PATCH 0043/1899] Revert "Copy API tests back to grpc-native-core" --- .../interop/async_delay_queue.js | 64 - .../interop/interop_client.js | 621 -------- .../interop/interop_server.js | 241 --- packages/grpc-native-core/package.json | 2 - packages/grpc-native-core/test/async_test.js | 83 - .../test/credentials_api_test.js | 165 -- .../grpc-native-core/test/credentials_test.js | 452 ------ packages/grpc-native-core/test/data/README | 1 - packages/grpc-native-core/test/data/ca.pem | 15 - .../grpc-native-core/test/data/server1.key | 16 - .../grpc-native-core/test/data/server1.pem | 16 - .../grpc-native-core/test/echo_service.proto | 24 - .../grpc-native-core/test/file_load_test.js | 40 - packages/grpc-native-core/test/health_test.js | 103 -- .../test/interop_sanity_test.js | 94 -- .../test/math/math_grpc_pb.js | 125 -- .../grpc-native-core/test/math/math_pb.js | 866 ----------- .../grpc-native-core/test/math/math_server.js | 124 -- .../grpc-native-core/test/math_client_test.js | 140 -- .../grpc-native-core/test/metadata_test.js | 178 --- packages/grpc-native-core/test/numbers.txt | 496 ------ packages/grpc-native-core/test/server_test.js | 4 +- .../grpc-native-core/test/surface_test.js | 1379 ----------------- .../grpc-native-core/test/test_service.json | 55 - .../grpc-native-core/test/test_service.proto | 37 - 25 files changed, 2 insertions(+), 5339 deletions(-) delete mode 100644 packages/grpc-native-core/interop/async_delay_queue.js delete mode 100644 packages/grpc-native-core/interop/interop_client.js delete mode 100644 packages/grpc-native-core/interop/interop_server.js delete mode 100644 packages/grpc-native-core/test/async_test.js delete mode 100644 packages/grpc-native-core/test/credentials_api_test.js delete mode 100644 packages/grpc-native-core/test/credentials_test.js delete mode 100644 packages/grpc-native-core/test/data/README delete mode 100644 packages/grpc-native-core/test/data/ca.pem delete mode 100644 packages/grpc-native-core/test/data/server1.key delete mode 100644 packages/grpc-native-core/test/data/server1.pem delete mode 100644 packages/grpc-native-core/test/echo_service.proto delete mode 100644 packages/grpc-native-core/test/file_load_test.js delete mode 100644 packages/grpc-native-core/test/health_test.js delete mode 100644 packages/grpc-native-core/test/interop_sanity_test.js delete mode 100644 packages/grpc-native-core/test/math/math_grpc_pb.js delete mode 100644 packages/grpc-native-core/test/math/math_pb.js delete mode 100644 packages/grpc-native-core/test/math/math_server.js delete mode 100644 packages/grpc-native-core/test/math_client_test.js delete mode 100644 packages/grpc-native-core/test/metadata_test.js delete mode 100644 packages/grpc-native-core/test/numbers.txt delete mode 100644 packages/grpc-native-core/test/surface_test.js delete mode 100644 packages/grpc-native-core/test/test_service.json delete mode 100644 packages/grpc-native-core/test/test_service.proto diff --git a/packages/grpc-native-core/interop/async_delay_queue.js b/packages/grpc-native-core/interop/async_delay_queue.js deleted file mode 100644 index 43ac57387..000000000 --- a/packages/grpc-native-core/interop/async_delay_queue.js +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var _ = require('lodash'); - -/** - * This class represents a queue of callbacks that must happen sequentially, - * each with a specific delay after the previous event. - */ -function AsyncDelayQueue() { - this.queue = []; - - this.callback_pending = false; -} - -/** - * Run the next callback after its corresponding delay, if there are any - * remaining. - */ -AsyncDelayQueue.prototype.runNext = function() { - var next = this.queue.shift(); - var continueCallback = _.bind(this.runNext, this); - if (next) { - this.callback_pending = true; - setTimeout(function() { - next.callback(continueCallback); - }, next.delay); - } else { - this.callback_pending = false; - } -}; - -/** - * Add a callback to be called with a specific delay after now or after the - * current last item in the queue or current pending callback, whichever is - * latest. - * @param {function(function())} callback The callback - * @param {Number} The delay to apply, in milliseconds - */ -AsyncDelayQueue.prototype.add = function(callback, delay) { - this.queue.push({callback: callback, delay: delay}); - if (!this.callback_pending) { - this.runNext(); - } -}; - -module.exports = AsyncDelayQueue; diff --git a/packages/grpc-native-core/interop/interop_client.js b/packages/grpc-native-core/interop/interop_client.js deleted file mode 100644 index 3e2cdf9f7..000000000 --- a/packages/grpc-native-core/interop/interop_client.js +++ /dev/null @@ -1,621 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var grpc = require('..'); -var testProto = grpc.load({ - root: __dirname + '/../deps/grpc', - file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; -var GoogleAuth = require('google-auth-library'); - -var assert = require('assert'); - -var SERVICE_ACCOUNT_EMAIL; -try { - SERVICE_ACCOUNT_EMAIL = require( - process.env.GOOGLE_APPLICATION_CREDENTIALS).client_email; -} catch (e) { - // This will cause the tests to fail if they need that string - SERVICE_ACCOUNT_EMAIL = null; -} - -var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; -var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; - -/** - * Create a buffer filled with size zeroes - * @param {number} size The length of the buffer - * @return {Buffer} The new buffer - */ -function zeroBuffer(size) { - var zeros = new Buffer(size); - zeros.fill(0); - return zeros; -} - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} - -/** - * Run the empty_unary test - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function emptyUnary(client, done) { - client.emptyCall({}, function(err, resp) { - assert.ifError(err); - if (done) { - done(); - } - }); -} - -/** - * Run the large_unary test - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function largeUnary(client, done) { - var arg = { - response_type: 'COMPRESSABLE', - response_size: 314159, - payload: { - body: zeroBuffer(271828) - } - }; - client.unaryCall(arg, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); - assert.strictEqual(resp.payload.body.length, 314159); - if (done) { - done(); - } - }); -} - -/** - * Run the client_streaming test - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function clientStreaming(client, done) { - var call = client.streamingInputCall(function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.aggregated_payload_size, 74922); - if (done) { - done(); - } - }); - var payload_sizes = [27182, 8, 1828, 45904]; - for (var i = 0; i < payload_sizes.length; i++) { - call.write({payload: {body: zeroBuffer(payload_sizes[i])}}); - } - call.end(); -} - -/** - * Run the server_streaming test - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function serverStreaming(client, done) { - var arg = { - response_type: 'COMPRESSABLE', - response_parameters: [ - {size: 31415}, - {size: 9}, - {size: 2653}, - {size: 58979} - ] - }; - var call = client.streamingOutputCall(arg); - var resp_index = 0; - call.on('data', function(value) { - assert(resp_index < 4); - assert.strictEqual(value.payload.type, 'COMPRESSABLE'); - assert.strictEqual(value.payload.body.length, - arg.response_parameters[resp_index].size); - resp_index += 1; - }); - call.on('end', function() { - assert.strictEqual(resp_index, 4); - if (done) { - done(); - } - }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - }); -} - -/** - * Run the ping_pong test - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function pingPong(client, done) { - var payload_sizes = [27182, 8, 1828, 45904]; - var response_sizes = [31415, 9, 2653, 58979]; - var call = client.fullDuplexCall(); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - if (done) { - done(); - } - }); - var index = 0; - call.write({ - response_type: 'COMPRESSABLE', - response_parameters: [ - {size: response_sizes[index]} - ], - payload: {body: zeroBuffer(payload_sizes[index])} - }); - call.on('data', function(response) { - assert.strictEqual(response.payload.type, 'COMPRESSABLE'); - assert.equal(response.payload.body.length, response_sizes[index]); - index += 1; - if (index === 4) { - call.end(); - } else { - call.write({ - response_type: 'COMPRESSABLE', - response_parameters: [ - {size: response_sizes[index]} - ], - payload: {body: zeroBuffer(payload_sizes[index])} - }); - } - }); -} - -/** - * Run the empty_stream test. - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function emptyStream(client, done) { - var call = client.fullDuplexCall(); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - if (done) { - done(); - } - }); - call.on('data', function(value) { - assert.fail(value, null, 'No data should have been received', '!=='); - }); - call.end(); -} - -/** - * Run the cancel_after_begin test. - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function cancelAfterBegin(client, done) { - var call = client.streamingInputCall(function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); -} - -/** - * Run the cancel_after_first_response test. - * @param {Client} client The client to test against - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function cancelAfterFirstResponse(client, done) { - var call = client.fullDuplexCall(); - call.write({ - response_type: 'COMPRESSABLE', - response_parameters: [ - {size: 31415} - ], - payload: {body: zeroBuffer(27182)} - }); - call.on('data', function(data) { - call.cancel(); - }); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.CANCELLED); - done(); - }); -} - -function timeoutOnSleepingServer(client, done) { - var deadline = new Date(); - deadline.setMilliseconds(deadline.getMilliseconds() + 1); - var call = client.fullDuplexCall({deadline: deadline}); - call.write({ - payload: {body: zeroBuffer(27182)} - }); - call.on('data', function() {}); - call.on('error', function(error) { - - assert(error.code === grpc.status.DEADLINE_EXCEEDED || - error.code === grpc.status.INTERNAL); - done(); - }); -} - -function customMetadata(client, done) { - done = multiDone(done, 5); - var metadata = new grpc.Metadata(); - metadata.set(ECHO_INITIAL_KEY, 'test_initial_metadata_value'); - metadata.set(ECHO_TRAILING_KEY, new Buffer('ababab', 'hex')); - var arg = { - response_type: 'COMPRESSABLE', - response_size: 314159, - payload: { - body: zeroBuffer(271828) - } - }; - var streaming_arg = { - response_parameters: [ - {size: 314159} - ], - payload: { - body: zeroBuffer(271828) - } - }; - var unary = client.unaryCall(arg, metadata, function(err, resp) { - assert.ifError(err); - done(); - }); - unary.on('metadata', function(metadata) { - assert.deepEqual(metadata.get(ECHO_INITIAL_KEY), - ['test_initial_metadata_value']); - done(); - }); - unary.on('status', function(status) { - var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY); - assert(echo_trailer.length > 0); - assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); - done(); - }); - var stream = client.fullDuplexCall(metadata); - stream.on('metadata', function(metadata) { - assert.deepEqual(metadata.get(ECHO_INITIAL_KEY), - ['test_initial_metadata_value']); - done(); - }); - stream.on('data', function() {}); - stream.on('status', function(status) { - var echo_trailer = status.metadata.get(ECHO_TRAILING_KEY); - assert(echo_trailer.length > 0); - assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); - done(); - }); - stream.write(streaming_arg); - stream.end(); -} - -function statusCodeAndMessage(client, done) { - done = multiDone(done, 2); - var arg = { - response_status: { - code: 2, - message: 'test status message' - } - }; - client.unaryCall(arg, function(err, resp) { - assert(err); - assert.strictEqual(err.code, 2); - assert.strictEqual(err.message, 'test status message'); - done(); - }); - var duplex = client.fullDuplexCall(); - duplex.on('data', function() {}); - duplex.on('status', function(status) { - assert(status); - assert.strictEqual(status.code, 2); - assert.strictEqual(status.details, 'test status message'); - done(); - }); - duplex.on('error', function(){}); - duplex.write(arg); - duplex.end(); -} - -// NOTE: the client param to this function is from UnimplementedService -function unimplementedService(client, done) { - client.unimplementedCall({}, function(err, resp) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); - done(); - }); -} - -// NOTE: the client param to this function is from TestService -function unimplementedMethod(client, done) { - client.unimplementedCall({}, function(err, resp) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); - done(); - }); -} - -/** - * Run one of the authentication tests. - * @param {string} expected_user The expected username in the response - * @param {Client} client The client to test against - * @param {?string} scope The scope to apply to the credentials - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - */ -function authTest(expected_user, scope, client, done) { - var arg = { - response_type: 'COMPRESSABLE', - response_size: 314159, - payload: { - body: zeroBuffer(271828) - }, - fill_username: true, - fill_oauth_scope: true - }; - client.unaryCall(arg, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.payload.type, 'COMPRESSABLE'); - assert.strictEqual(resp.payload.body.length, 314159); - assert.strictEqual(resp.username, expected_user); - if (scope) { - assert(scope.indexOf(resp.oauth_scope) > -1); - } - if (done) { - done(); - } - }); -} - -function computeEngineCreds(client, done, extra) { - authTest(extra.service_account, null, client, done); -} - -function serviceAccountCreds(client, done, extra) { - authTest(SERVICE_ACCOUNT_EMAIL, extra.oauth_scope, client, done); -} - -function jwtTokenCreds(client, done, extra) { - authTest(SERVICE_ACCOUNT_EMAIL, null, client, done); -} - -function oauth2Test(client, done, extra) { - var arg = { - fill_username: true, - fill_oauth_scope: true - }; - client.unaryCall(arg, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); - assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); - if (done) { - done(); - } - }); -} - -function perRpcAuthTest(client, done, extra) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - assert.ifError(err); - var arg = { - fill_username: true, - fill_oauth_scope: true - }; - var scope = extra.oauth_scope; - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); - } - var creds = grpc.credentials.createFromGoogleCredential(credential); - client.unaryCall(arg, {credentials: creds}, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); - assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); - if (done) { - done(); - } - }); - }); -} - -function getApplicationCreds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); - } - callback(null, grpc.credentials.createFromGoogleCredential(credential)); - }); -} - -function getOauth2Creds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - credential = credential.createScoped(scope); - credential.getAccessToken(function(err, token) { - if (err) { - callback(err); - return; - } - var updateMd = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.add('authorization', 'Bearer ' + token); - callback(null, metadata); - }; - callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); - }); - }); -} - -/** - * Map from test case names to test functions - */ -var test_cases = { - empty_unary: {run: emptyUnary, - Client: testProto.TestService}, - large_unary: {run: largeUnary, - Client: testProto.TestService}, - client_streaming: {run: clientStreaming, - Client: testProto.TestService}, - server_streaming: {run: serverStreaming, - Client: testProto.TestService}, - ping_pong: {run: pingPong, - Client: testProto.TestService}, - empty_stream: {run: emptyStream, - Client: testProto.TestService}, - cancel_after_begin: {run: cancelAfterBegin, - Client: testProto.TestService}, - cancel_after_first_response: {run: cancelAfterFirstResponse, - Client: testProto.TestService}, - timeout_on_sleeping_server: {run: timeoutOnSleepingServer, - Client: testProto.TestService}, - custom_metadata: {run: customMetadata, - Client: testProto.TestService}, - status_code_and_message: {run: statusCodeAndMessage, - Client: testProto.TestService}, - unimplemented_service: {run: unimplementedService, - Client: testProto.UnimplementedService}, - unimplemented_method: {run: unimplementedMethod, - Client: testProto.TestService}, - compute_engine_creds: {run: computeEngineCreds, - Client: testProto.TestService, - getCreds: getApplicationCreds}, - service_account_creds: {run: serviceAccountCreds, - Client: testProto.TestService, - getCreds: getApplicationCreds}, - jwt_token_creds: {run: jwtTokenCreds, - Client: testProto.TestService, - getCreds: getApplicationCreds}, - oauth2_auth_token: {run: oauth2Test, - Client: testProto.TestService, - getCreds: getOauth2Creds}, - per_rpc_creds: {run: perRpcAuthTest, - Client: testProto.TestService} -}; - -exports.test_cases = test_cases; - -/** - * Execute a single test case. - * @param {string} address The address of the server to connect to, in the - * format 'hostname:port' - * @param {string} host_overrirde The hostname of the server to use as an SSL - * override - * @param {string} test_case The name of the test case to run - * @param {bool} tls Indicates that a secure channel should be used - * @param {function} done Callback to call when the test is completed. Included - * primarily for use with mocha - * @param {object=} extra Extra options for some tests - */ -function runTest(address, host_override, test_case, tls, test_ca, done, extra) { - // TODO(mlumish): enable TLS functionality - var options = {}; - var creds; - if (tls) { - var ca_path; - if (test_ca) { - ca_path = path.join(__dirname, '../test/data/ca.pem'); - var ca_data = fs.readFileSync(ca_path); - creds = grpc.credentials.createSsl(ca_data); - } else { - creds = grpc.credentials.createSsl(); - } - if (host_override) { - options['grpc.ssl_target_name_override'] = host_override; - options['grpc.default_authority'] = host_override; - } - } else { - creds = grpc.credentials.createInsecure(); - } - var test = test_cases[test_case]; - - var execute = function(err, creds) { - assert.ifError(err); - var client = new test.Client(address, creds, options); - test.run(client, done, extra); - }; - - if (test.getCreds) { - test.getCreds(extra.oauth_scope, function(err, new_creds) { - assert.ifError(err); - execute(err, grpc.credentials.combineChannelCredentials( - creds, new_creds)); - }); - } else { - execute(null, creds); - } -} - -if (require.main === module) { - var parseArgs = require('minimist'); - var argv = parseArgs(process.argv, { - string: ['server_host', 'server_host_override', 'server_port', 'test_case', - 'use_tls', 'use_test_ca', 'default_service_account', 'oauth_scope', - 'service_account_key_file'] - }); - var extra_args = { - service_account: argv.default_service_account, - oauth_scope: argv.oauth_scope - }; - runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, - argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', - function () { - console.log('OK:', argv.test_case); - }, extra_args); -} - -/** - * See docs for runTest - */ -exports.runTest = runTest; diff --git a/packages/grpc-native-core/interop/interop_server.js b/packages/grpc-native-core/interop/interop_server.js deleted file mode 100644 index c2341723a..000000000 --- a/packages/grpc-native-core/interop/interop_server.js +++ /dev/null @@ -1,241 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var fs = require('fs'); -var path = require('path'); -var _ = require('lodash'); -var AsyncDelayQueue = require('./async_delay_queue'); -var grpc = require('..'); -var testProto = grpc.load({ - root: __dirname + '/../deps/grpc', - file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; - -var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; -var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; - -/** - * Create a buffer filled with size zeroes - * @param {number} size The length of the buffer - * @return {Buffer} The new buffer - */ -function zeroBuffer(size) { - var zeros = new Buffer(size); - zeros.fill(0); - return zeros; -} - -/** - * Echos a header metadata item as specified in the interop spec. - * @param {Call} call The call to echo metadata on - */ -function echoHeader(call) { - var echo_initial = call.metadata.get(ECHO_INITIAL_KEY); - if (echo_initial.length > 0) { - var response_metadata = new grpc.Metadata(); - response_metadata.set(ECHO_INITIAL_KEY, echo_initial[0]); - call.sendMetadata(response_metadata); - } -} - -/** - * Gets the trailer metadata that should be echoed when the call is done, - * as specified in the interop spec. - * @param {Call} call The call to get metadata from - * @return {grpc.Metadata} The metadata to send as a trailer - */ -function getEchoTrailer(call) { - var echo_trailer = call.metadata.get(ECHO_TRAILING_KEY); - var response_trailer = new grpc.Metadata(); - if (echo_trailer.length > 0) { - response_trailer.set(ECHO_TRAILING_KEY, echo_trailer[0]); - } - return response_trailer; -} - -function getPayload(payload_type, size) { - var body = zeroBuffer(size); - return {type: payload_type, body: body}; -} - -/** - * Respond to an empty parameter with an empty response. - * NOTE: this currently does not work due to issue #137 - * @param {Call} call Call to handle - * @param {function(Error, Object)} callback Callback to call with result - * or error - */ -function handleEmpty(call, callback) { - echoHeader(call); - callback(null, {}, getEchoTrailer(call)); -} - -/** - * Handle a unary request by sending the requested payload - * @param {Call} call Call to handle - * @param {function(Error, Object)} callback Callback to call with result or - * error - */ -function handleUnary(call, callback) { - echoHeader(call); - var req = call.request; - if (req.response_status) { - var status = req.response_status; - status.metadata = getEchoTrailer(call); - callback(status); - return; - } - var payload = getPayload(req.response_type, req.response_size); - callback(null, {payload: payload}, - getEchoTrailer(call)); -} - -/** - * Respond to a streaming call with the total size of all payloads - * @param {Call} call Call to handle - * @param {function(Error, Object)} callback Callback to call with result or - * error - */ -function handleStreamingInput(call, callback) { - echoHeader(call); - var aggregate_size = 0; - call.on('data', function(value) { - aggregate_size += value.payload.body.length; - }); - call.on('end', function() { - callback(null, {aggregated_payload_size: aggregate_size}, - getEchoTrailer(call)); - }); -} - -/** - * Respond to a payload request with a stream of the requested payloads - * @param {Call} call Call to handle - */ -function handleStreamingOutput(call) { - echoHeader(call); - var delay_queue = new AsyncDelayQueue(); - var req = call.request; - if (req.response_status) { - var status = req.response_status; - status.metadata = getEchoTrailer(call); - call.emit('error', status); - return; - } - _.each(req.response_parameters, function(resp_param) { - delay_queue.add(function(next) { - call.write({payload: getPayload(req.response_type, resp_param.size)}); - next(); - }, resp_param.interval_us); - }); - delay_queue.add(function(next) { - call.end(getEchoTrailer(call)); - next(); - }); -} - -/** - * Respond to a stream of payload requests with a stream of payload responses as - * they arrive. - * @param {Call} call Call to handle - */ -function handleFullDuplex(call) { - echoHeader(call); - var delay_queue = new AsyncDelayQueue(); - call.on('data', function(value) { - if (value.response_status) { - var status = value.response_status; - status.metadata = getEchoTrailer(call); - call.emit('error', status); - return; - } - _.each(value.response_parameters, function(resp_param) { - delay_queue.add(function(next) { - call.write({payload: getPayload(value.response_type, resp_param.size)}); - next(); - }, resp_param.interval_us); - }); - }); - call.on('end', function() { - delay_queue.add(function(next) { - call.end(getEchoTrailer(call)); - next(); - }); - }); -} - -/** - * Respond to a stream of payload requests with a stream of payload responses - * after all requests have arrived - * @param {Call} call Call to handle - */ -function handleHalfDuplex(call) { - call.emit('error', Error('HalfDuplexCall not yet implemented')); -} - -/** - * Get a server object bound to the given port - * @param {string} port Port to which to bind - * @param {boolean} tls Indicates that the bound port should use TLS - * @return {{server: Server, port: number}} Server object bound to the support, - * and port number that the server is bound to - */ -function getServer(port, tls) { - // TODO(mlumish): enable TLS functionality - var options = {}; - var server_creds; - if (tls) { - var key_path = path.join(__dirname, '../test/data/server1.key'); - var pem_path = path.join(__dirname, '../test/data/server1.pem'); - - var key_data = fs.readFileSync(key_path); - var pem_data = fs.readFileSync(pem_path); - server_creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - } else { - server_creds = grpc.ServerCredentials.createInsecure(); - } - var server = new grpc.Server(options); - server.addService(testProto.TestService.service, { - emptyCall: handleEmpty, - unaryCall: handleUnary, - streamingOutputCall: handleStreamingOutput, - streamingInputCall: handleStreamingInput, - fullDuplexCall: handleFullDuplex, - halfDuplexCall: handleHalfDuplex - }); - var port_num = server.bind('0.0.0.0:' + port, server_creds); - return {server: server, port: port_num}; -} - -if (require.main === module) { - var parseArgs = require('minimist'); - var argv = parseArgs(process.argv, { - string: ['port', 'use_tls'] - }); - var server_obj = getServer(argv.port, argv.use_tls === 'true'); - console.log('Server attaching to port ' + argv.port); - server_obj.server.start(); -} - -/** - * See docs for getServer - */ -exports.getServer = getServer; diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 62399419f..f216537a3 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -36,8 +36,6 @@ }, "devDependencies": { "electron-mocha": "^3.1.1", - "google-auth-library": "^0.12.0", - "google-protobuf": "^3.5.0", "istanbul": "^0.4.4" }, "engines": { diff --git a/packages/grpc-native-core/test/async_test.js b/packages/grpc-native-core/test/async_test.js deleted file mode 100644 index e2f124e59..000000000 --- a/packages/grpc-native-core/test/async_test.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); - -var grpc = require('..'); -var math = grpc.load(__dirname + '/../deps/grpc/src/proto/math/math.proto').math; - - -/** - * Client to use to make requests to a running server. - */ -var math_client; - -/** - * Server to test against - */ -var getServer = require('./math/math_server.js'); - -var server = getServer(); - -describe('Async functionality', function() { - before(function(done) { - var port_num = server.bind('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - server.start(); - math_client = new math.Math('localhost:' + port_num, - grpc.credentials.createInsecure()); - done(); - }); - after(function() { - grpc.closeClient(math_client); - server.forceShutdown(); - }); - it('should not hang', function(done) { - var chunkCount=0; - var call = math_client.sum(function handleSumResult(err, value) { - assert.ifError(err); - assert.equal(value.num, chunkCount); - }); - - var path = require('path'); - var fs = require('fs'); - var fileToRead = path.join(__dirname, 'numbers.txt'); - var readStream = fs.createReadStream(fileToRead); - - readStream.once('readable', function () { - readStream.on('data', function (chunk) { - call.write({'num': 1}); - chunkCount += 1; - }); - - readStream.on('end', function () { - call.end(); - }); - - readStream.on('error', function (error) { - }); - }); - - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); -}); diff --git a/packages/grpc-native-core/test/credentials_api_test.js b/packages/grpc-native-core/test/credentials_api_test.js deleted file mode 100644 index 38a2a1ced..000000000 --- a/packages/grpc-native-core/test/credentials_api_test.js +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var fs = require('fs'); -var path = require('path'); - -var grpc = require('..'); - -var key_data, pem_data, ca_data; - -before(function() { - var key_path = path.join(__dirname, './data/server1.key'); - var pem_path = path.join(__dirname, './data/server1.pem'); - var ca_path = path.join(__dirname, './data/ca.pem'); - key_data = fs.readFileSync(key_path); - pem_data = fs.readFileSync(pem_path); - ca_data = fs.readFileSync(ca_path); -}); - -describe('channel credentials', function() { - describe('#createSsl', function() { - it('works with no arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(); - }); - assert.notEqual(creds, null); - }); - it('works with just one Buffer argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data); - }); - assert.notEqual(creds, null); - }); - it('works with 3 Buffer arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('works if the first argument is null', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(null, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl('test'); - }, TypeError); - }); - it('fails if the second argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, 'test', pem_data); - }, TypeError); - }); - it('fails if the third argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data, 'test'); - }, TypeError); - }); - it('fails if only 1 of the last 2 arguments is provided', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data); - }); - assert.throws(function() { - grpc.credentials.createSsl(null, null, pem_data); - }); - }); - }); -}); - -describe('server credentials', function() { - describe('#createSsl', function() { - it('accepts a buffer and array as the first 2 arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, []); - }); - assert.notEqual(creds, null); - }); - it('accepts a boolean as the third argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, [], true); - }); - assert.notEqual(creds, null); - }); - it('accepts an object with two buffers in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('accepts multiple objects in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}, - {private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('fails if the second argument is not an Array', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl('test', []); - }, TypeError); - }); - it('fails if the third argument is a non-boolean value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, [], 'test'); - }, TypeError); - }); - it('fails if the array elements are not objects', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the object does not have a Buffer private_key', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: 'test', - cert_chain: pem_data}]); - }, TypeError); - }); - it('fails if the object does not have a Buffer cert_chain', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: 'test'}]); - }, TypeError); - }); - }); -}); \ No newline at end of file diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js deleted file mode 100644 index 38320d85a..000000000 --- a/packages/grpc-native-core/test/credentials_test.js +++ /dev/null @@ -1,452 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var fs = require('fs'); -var path = require('path'); - -var grpc = require('..'); - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} - -var fakeSuccessfulGoogleCredentials = { - getRequestMetadata: function(service_url, callback) { - setTimeout(function() { - callback(null, {Authorization: 'success'}); - }, 0); - } -}; - -var fakeFailingGoogleCredentials = { - getRequestMetadata: function(service_url, callback) { - setTimeout(function() { - // Google credentials currently adds string error codes to auth errors - var error = new Error('Authentication failure'); - error.code = 'ENOENT'; - callback(error); - }, 0); - } -}; - -var key_data, pem_data, ca_data; - -before(function() { - var key_path = path.join(__dirname, './data/server1.key'); - var pem_path = path.join(__dirname, './data/server1.pem'); - var ca_path = path.join(__dirname, './data/ca.pem'); - key_data = fs.readFileSync(key_path); - pem_data = fs.readFileSync(pem_path); - ca_data = fs.readFileSync(ca_path); -}); - -describe('channel credentials', function() { - describe('#createSsl', function() { - it('works with no arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(); - }); - assert.notEqual(creds, null); - }); - it('works with just one Buffer argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data); - }); - assert.notEqual(creds, null); - }); - it('works with 3 Buffer arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('works if the first argument is null', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(null, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl('test'); - }, TypeError); - }); - it('fails if the second argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, 'test', pem_data); - }, TypeError); - }); - it('fails if the third argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data, 'test'); - }, TypeError); - }); - it('fails if only 1 of the last 2 arguments is provided', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data); - }); - assert.throws(function() { - grpc.credentials.createSsl(null, null, pem_data); - }); - }); - }); -}); - -describe('server credentials', function() { - describe('#createSsl', function() { - it('accepts a buffer and array as the first 2 arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, []); - }); - assert.notEqual(creds, null); - }); - it('accepts a boolean as the third argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, [], true); - }); - assert.notEqual(creds, null); - }); - it('accepts an object with two buffers in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('accepts multiple objects in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}, - {private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('fails if the second argument is not an Array', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl('test', []); - }, TypeError); - }); - it('fails if the third argument is a non-boolean value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, [], 'test'); - }, TypeError); - }); - it('fails if the array elements are not objects', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the object does not have a Buffer private_key', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: 'test', - cert_chain: pem_data}]); - }, TypeError); - }); - it('fails if the object does not have a Buffer cert_chain', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: 'test'}]); - }, TypeError); - }); - }); -}); - -describe('client credentials', function() { - var Client; - var server; - var port; - var client_ssl_creds; - var client_options = {}; - before(function() { - var proto = grpc.load(__dirname + '/test_service.proto'); - server = new grpc.Server(); - server.addService(proto.TestService.service, { - unary: function(call, cb) { - call.sendMetadata(call.metadata); - cb(null, {}); - }, - clientStream: function(stream, cb){ - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.sendMetadata(stream.metadata); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - stream.end(); - }); - } - }); - var creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - port = server.bind('localhost:0', creds); - server.start(); - - Client = proto.TestService; - client_ssl_creds = grpc.credentials.createSsl(ca_data); - var host_override = 'foo.test.google.fr'; - client_options['grpc.ssl_target_name_override'] = host_override; - client_options['grpc.default_authority'] = host_override; - }); - after(function() { - server.forceShutdown(); - }); - it('Should accept SSL creds for a client', function(done) { - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - client.unary({}, function(err, data) { - assert.ifError(err); - done(); - }); - }); - it('Should update metadata with SSL creds', function(done) { - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('Should update metadata for two simultaneous calls', function(done) { - done = multiDone(done, 2); - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - var call2 = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call2.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('should propagate errors that the updater emits', function(done) { - var metadataUpdater = function(service_url, callback) { - var error = new Error('Authentication error'); - error.code = grpc.status.UNAUTHENTICATED; - callback(error); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.message, - 'Getting metadata from plugin failed with error: ' + - 'Authentication error'); - assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED); - done(); - }); - }); - it('should successfully wrap a Google credential', function(done) { - var creds = grpc.credentials.createFromGoogleCredential( - fakeSuccessfulGoogleCredentials); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('authorization'), ['success']); - done(); - }); - }); - it('Should not add metadata with just SSL credentials', function(done) { - // Tests idempotency of credentials composition - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - grpc.credentials.combineChannelCredentials(client_ssl_creds, creds); - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), []); - done(); - }); - }); - it('should get an error from a Google credential', function(done) { - var creds = grpc.credentials.createFromGoogleCredential( - fakeFailingGoogleCredentials); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.message, - 'Getting metadata from plugin failed with error: ' + - 'Authentication failure'); - done(); - }); - }); - describe('Per-rpc creds', function() { - var client; - var updater_creds; - before(function() { - client = new Client('localhost:' + port, client_ssl_creds, - client_options); - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - updater_creds = grpc.credentials.createFromMetadataGenerator( - metadataUpdater); - }); - it('Should update metadata on a unary call', function(done) { - var call = client.unary({}, {credentials: updater_creds}, - function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('should update metadata on a client streaming call', function(done) { - var call = client.clientStream({credentials: updater_creds}, - function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - call.end(); - }); - it('should update metadata on a server streaming call', function(done) { - var call = client.serverStream({}, {credentials: updater_creds}); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('should update metadata on a bidi streaming call', function(done) { - var call = client.bidiStream({credentials: updater_creds}); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - call.end(); - }); - it('should be able to use multiple plugin credentials', function(done) { - var altMetadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('other_plugin_key', 'other_plugin_value'); - callback(null, metadata); - }; - var alt_updater_creds = grpc.credentials.createFromMetadataGenerator( - altMetadataUpdater); - var combined_updater = grpc.credentials.combineCallCredentials( - updater_creds, alt_updater_creds); - var call = client.unary({}, {credentials: combined_updater}, - function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - assert.deepEqual(metadata.get('other_plugin_key'), - ['other_plugin_value']); - done(); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/data/README b/packages/grpc-native-core/test/data/README deleted file mode 100644 index 888d95b90..000000000 --- a/packages/grpc-native-core/test/data/README +++ /dev/null @@ -1 +0,0 @@ -CONFIRMEDTESTKEY diff --git a/packages/grpc-native-core/test/data/ca.pem b/packages/grpc-native-core/test/data/ca.pem deleted file mode 100644 index 6c8511a73..000000000 --- a/packages/grpc-native-core/test/data/ca.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla -Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 -YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT -BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 -+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu -g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd -Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau -sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m -oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG -Dfcog5wrJytaQ6UA0wE= ------END CERTIFICATE----- diff --git a/packages/grpc-native-core/test/data/server1.key b/packages/grpc-native-core/test/data/server1.key deleted file mode 100644 index 143a5b876..000000000 --- a/packages/grpc-native-core/test/data/server1.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD -M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf -3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY -AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm -V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY -tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p -dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q -K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR -81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff -DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd -aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 -ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 -XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe -F98XJ7tIFfJq ------END PRIVATE KEY----- diff --git a/packages/grpc-native-core/test/data/server1.pem b/packages/grpc-native-core/test/data/server1.pem deleted file mode 100644 index f3d43fcc5..000000000 --- a/packages/grpc-native-core/test/data/server1.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx -MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 -ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco -LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg -zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd -9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw -CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy -em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G -CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 -hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh -y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 ------END CERTIFICATE----- diff --git a/packages/grpc-native-core/test/echo_service.proto b/packages/grpc-native-core/test/echo_service.proto deleted file mode 100644 index 0b27c8b16..000000000 --- a/packages/grpc-native-core/test/echo_service.proto +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -message EchoMessage { - string value = 1; - int32 value2 = 2; -} - -service EchoService { - rpc Echo (EchoMessage) returns (EchoMessage); -} diff --git a/packages/grpc-native-core/test/file_load_test.js b/packages/grpc-native-core/test/file_load_test.js deleted file mode 100644 index f6c6f3af6..000000000 --- a/packages/grpc-native-core/test/file_load_test.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var grpc = require('..'); - -describe('File loader', function() { - it('Should load a proto file by default', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto'); - }); - }); - it('Should load a proto file with the proto format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto', 'proto'); - }); - }); - it('Should load a json file with the json format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.json', 'json'); - }); - }); -}); diff --git a/packages/grpc-native-core/test/health_test.js b/packages/grpc-native-core/test/health_test.js deleted file mode 100644 index 821036f81..000000000 --- a/packages/grpc-native-core/test/health_test.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); - -var health = require('../../grpc-health-check/health'); - -var health_messages = require('../../grpc-health-check/v1/health_pb'); - -var ServingStatus = health_messages.HealthCheckResponse.ServingStatus; - -var grpc = require('../'); - -describe('Health Checking', function() { - var statusMap = { - '': ServingStatus.SERVING, - 'grpc.test.TestServiceNotServing': ServingStatus.NOT_SERVING, - 'grpc.test.TestServiceServing': ServingStatus.SERVING - }; - var healthServer; - var healthImpl; - var healthClient; - before(function() { - healthServer = new grpc.Server(); - healthImpl = new health.Implementation(statusMap); - healthServer.addService(health.service, healthImpl); - var port_num = healthServer.bind('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - healthServer.start(); - healthClient = new health.Client('localhost:' + port_num, - grpc.credentials.createInsecure()); - }); - after(function() { - healthServer.forceShutdown(); - }); - it('should say an enabled service is SERVING', function(done) { - var request = new health_messages.HealthCheckRequest(); - request.setService(''); - healthClient.check(request, function(err, response) { - assert.ifError(err); - assert.strictEqual(response.getStatus(), ServingStatus.SERVING); - done(); - }); - }); - it('should say that a disabled service is NOT_SERVING', function(done) { - var request = new health_messages.HealthCheckRequest(); - request.setService('grpc.test.TestServiceNotServing'); - healthClient.check(request, function(err, response) { - assert.ifError(err); - assert.strictEqual(response.getStatus(), ServingStatus.NOT_SERVING); - done(); - }); - }); - it('should say that an enabled service is SERVING', function(done) { - var request = new health_messages.HealthCheckRequest(); - request.setService('grpc.test.TestServiceServing'); - healthClient.check(request, function(err, response) { - assert.ifError(err); - assert.strictEqual(response.getStatus(), ServingStatus.SERVING); - done(); - }); - }); - it('should get NOT_FOUND if the service is not registered', function(done) { - var request = new health_messages.HealthCheckRequest(); - request.setService('not_registered'); - healthClient.check(request, function(err, response) { - assert(err); - assert.strictEqual(err.code, grpc.status.NOT_FOUND); - done(); - }); - }); - it('should get a different response if the status changes', function(done) { - var request = new health_messages.HealthCheckRequest(); - request.setService('transient'); - healthClient.check(request, function(err, response) { - assert(err); - assert.strictEqual(err.code, grpc.status.NOT_FOUND); - healthImpl.setStatus('transient', ServingStatus.SERVING); - healthClient.check(request, function(err, response) { - assert.ifError(err); - assert.strictEqual(response.getStatus(), ServingStatus.SERVING); - done(); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/interop_sanity_test.js b/packages/grpc-native-core/test/interop_sanity_test.js deleted file mode 100644 index b3f65a034..000000000 --- a/packages/grpc-native-core/test/interop_sanity_test.js +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var interop_server = require('../interop/interop_server.js'); -var interop_client = require('../interop/interop_client.js'); - -var server; - -var port; - -var name_override = 'foo.test.google.fr'; - -describe('Interop tests', function() { - before(function(done) { - var server_obj = interop_server.getServer(0, true); - server = server_obj.server; - server.start(); - port = 'localhost:' + server_obj.port; - done(); - }); - after(function() { - server.forceShutdown(); - }); - // This depends on not using a binary stream - it('should pass empty_unary', function(done) { - interop_client.runTest(port, name_override, 'empty_unary', true, true, - done); - }); - // This fails due to an unknown bug - it('should pass large_unary', function(done) { - interop_client.runTest(port, name_override, 'large_unary', true, true, - done); - }); - it('should pass client_streaming', function(done) { - interop_client.runTest(port, name_override, 'client_streaming', true, true, - done); - }); - it('should pass server_streaming', function(done) { - interop_client.runTest(port, name_override, 'server_streaming', true, true, - done); - }); - it('should pass ping_pong', function(done) { - interop_client.runTest(port, name_override, 'ping_pong', true, true, done); - }); - it('should pass empty_stream', function(done) { - interop_client.runTest(port, name_override, 'empty_stream', true, true, - done); - }); - it('should pass cancel_after_begin', function(done) { - interop_client.runTest(port, name_override, 'cancel_after_begin', true, - true, done); - }); - it('should pass cancel_after_first_response', function(done) { - interop_client.runTest(port, name_override, 'cancel_after_first_response', - true, true, done); - }); - it('should pass timeout_on_sleeping_server', function(done) { - interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', - true, true, done); - }); - it('should pass custom_metadata', function(done) { - interop_client.runTest(port, name_override, 'custom_metadata', - true, true, done); - }); - it('should pass status_code_and_message', function(done) { - interop_client.runTest(port, name_override, 'status_code_and_message', - true, true, done); - }); - it('should pass unimplemented_service', function(done) { - interop_client.runTest(port, name_override, 'unimplemented_service', - true, true, done); - }); - it('should pass unimplemented_method', function(done) { - interop_client.runTest(port, name_override, 'unimplemented_method', - true, true, done); - }); -}); diff --git a/packages/grpc-native-core/test/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js deleted file mode 100644 index 84123d761..000000000 --- a/packages/grpc-native-core/test/math/math_grpc_pb.js +++ /dev/null @@ -1,125 +0,0 @@ -// GENERATED CODE -- DO NOT EDIT! - -// Original file comments: -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -'use strict'; -var grpc = require('../..'); -var math_math_pb = require('../math/math_pb.js'); - -function serialize_DivArgs(arg) { - if (!(arg instanceof math_math_pb.DivArgs)) { - throw new Error('Expected argument of type DivArgs'); - } - return new Buffer(arg.serializeBinary()); -} - -function deserialize_DivArgs(buffer_arg) { - return math_math_pb.DivArgs.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_DivReply(arg) { - if (!(arg instanceof math_math_pb.DivReply)) { - throw new Error('Expected argument of type DivReply'); - } - return new Buffer(arg.serializeBinary()); -} - -function deserialize_DivReply(buffer_arg) { - return math_math_pb.DivReply.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_FibArgs(arg) { - if (!(arg instanceof math_math_pb.FibArgs)) { - throw new Error('Expected argument of type FibArgs'); - } - return new Buffer(arg.serializeBinary()); -} - -function deserialize_FibArgs(buffer_arg) { - return math_math_pb.FibArgs.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_Num(arg) { - if (!(arg instanceof math_math_pb.Num)) { - throw new Error('Expected argument of type Num'); - } - return new Buffer(arg.serializeBinary()); -} - -function deserialize_Num(buffer_arg) { - return math_math_pb.Num.deserializeBinary(new Uint8Array(buffer_arg)); -} - - -var MathService = exports.MathService = { - // Div divides args.dividend by args.divisor and returns the quotient and - // remainder. - div: { - path: '/math.Math/Div', - requestStream: false, - responseStream: false, - requestType: math_math_pb.DivArgs, - responseType: math_math_pb.DivReply, - requestSerialize: serialize_DivArgs, - requestDeserialize: deserialize_DivArgs, - responseSerialize: serialize_DivReply, - responseDeserialize: deserialize_DivReply, - }, - // DivMany accepts an arbitrary number of division args from the client stream - // and sends back the results in the reply stream. The stream continues until - // the client closes its end; the server does the same after sending all the - // replies. The stream ends immediately if either end aborts. - divMany: { - path: '/math.Math/DivMany', - requestStream: true, - responseStream: true, - requestType: math_math_pb.DivArgs, - responseType: math_math_pb.DivReply, - requestSerialize: serialize_DivArgs, - requestDeserialize: deserialize_DivArgs, - responseSerialize: serialize_DivReply, - responseDeserialize: deserialize_DivReply, - }, - // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib - // generates up to limit numbers; otherwise it continues until the call is - // canceled. Unlike Fib above, Fib has no final FibReply. - fib: { - path: '/math.Math/Fib', - requestStream: false, - responseStream: true, - requestType: math_math_pb.FibArgs, - responseType: math_math_pb.Num, - requestSerialize: serialize_FibArgs, - requestDeserialize: deserialize_FibArgs, - responseSerialize: serialize_Num, - responseDeserialize: deserialize_Num, - }, - // Sum sums a stream of numbers, returning the final result once the stream - // is closed. - sum: { - path: '/math.Math/Sum', - requestStream: true, - responseStream: false, - requestType: math_math_pb.Num, - responseType: math_math_pb.Num, - requestSerialize: serialize_Num, - requestDeserialize: deserialize_Num, - responseSerialize: serialize_Num, - responseDeserialize: deserialize_Num, - }, -}; - -exports.MathClient = grpc.makeGenericClientConstructor(MathService); diff --git a/packages/grpc-native-core/test/math/math_pb.js b/packages/grpc-native-core/test/math/math_pb.js deleted file mode 100644 index ccc05c6e0..000000000 --- a/packages/grpc-native-core/test/math/math_pb.js +++ /dev/null @@ -1,866 +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.math.DivArgs', null, global); -goog.exportSymbol('proto.math.DivReply', null, global); -goog.exportSymbol('proto.math.FibArgs', null, global); -goog.exportSymbol('proto.math.FibReply', null, global); -goog.exportSymbol('proto.math.Num', 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.math.DivArgs = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.DivArgs, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.DivArgs.displayName = 'proto.math.DivArgs'; -} - - -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_, 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.math.DivArgs.prototype.toObject = function(opt_includeInstance) { - return proto.math.DivArgs.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.math.DivArgs} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.DivArgs.toObject = function(includeInstance, msg) { - var f, obj = { - dividend: msg.getDividend(), - divisor: msg.getDivisor() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.DivArgs} - */ -proto.math.DivArgs.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.DivArgs; - return proto.math.DivArgs.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.DivArgs} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.DivArgs} - */ -proto.math.DivArgs.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setDividend(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt64()); - msg.setDivisor(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.math.DivArgs} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.DivArgs.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.DivArgs.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.math.DivArgs.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getDividend(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } - f = this.getDivisor(); - if (f !== 0) { - writer.writeInt64( - 2, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.DivArgs} The clone. - */ -proto.math.DivArgs.prototype.cloneMessage = function() { - return /** @type {!proto.math.DivArgs} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 dividend = 1; - * @return {number} - */ -proto.math.DivArgs.prototype.getDividend = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.DivArgs.prototype.setDividend = function(value) { - jspb.Message.setField(this, 1, value); -}; - - -/** - * optional int64 divisor = 2; - * @return {number} - */ -proto.math.DivArgs.prototype.getDivisor = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); -}; - - -/** @param {number} value */ -proto.math.DivArgs.prototype.setDivisor = function(value) { - jspb.Message.setField(this, 2, 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.math.DivReply = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.DivReply, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.DivReply.displayName = 'proto.math.DivReply'; -} - - -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_, 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.math.DivReply.prototype.toObject = function(opt_includeInstance) { - return proto.math.DivReply.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.math.DivReply} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.DivReply.toObject = function(includeInstance, msg) { - var f, obj = { - quotient: msg.getQuotient(), - remainder: msg.getRemainder() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.DivReply} - */ -proto.math.DivReply.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.DivReply; - return proto.math.DivReply.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.DivReply} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.DivReply} - */ -proto.math.DivReply.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setQuotient(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt64()); - msg.setRemainder(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.math.DivReply} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.DivReply.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.DivReply.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.math.DivReply.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getQuotient(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } - f = this.getRemainder(); - if (f !== 0) { - writer.writeInt64( - 2, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.DivReply} The clone. - */ -proto.math.DivReply.prototype.cloneMessage = function() { - return /** @type {!proto.math.DivReply} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 quotient = 1; - * @return {number} - */ -proto.math.DivReply.prototype.getQuotient = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.DivReply.prototype.setQuotient = function(value) { - jspb.Message.setField(this, 1, value); -}; - - -/** - * optional int64 remainder = 2; - * @return {number} - */ -proto.math.DivReply.prototype.getRemainder = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); -}; - - -/** @param {number} value */ -proto.math.DivReply.prototype.setRemainder = function(value) { - jspb.Message.setField(this, 2, 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.math.FibArgs = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.FibArgs, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.FibArgs.displayName = 'proto.math.FibArgs'; -} - - -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_, 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.math.FibArgs.prototype.toObject = function(opt_includeInstance) { - return proto.math.FibArgs.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.math.FibArgs} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.FibArgs.toObject = function(includeInstance, msg) { - var f, obj = { - limit: msg.getLimit() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.FibArgs} - */ -proto.math.FibArgs.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.FibArgs; - return proto.math.FibArgs.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.FibArgs} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.FibArgs} - */ -proto.math.FibArgs.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setLimit(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.math.FibArgs} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.FibArgs.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.FibArgs.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.math.FibArgs.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getLimit(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.FibArgs} The clone. - */ -proto.math.FibArgs.prototype.cloneMessage = function() { - return /** @type {!proto.math.FibArgs} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 limit = 1; - * @return {number} - */ -proto.math.FibArgs.prototype.getLimit = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.FibArgs.prototype.setLimit = 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.math.Num = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.Num, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.Num.displayName = 'proto.math.Num'; -} - - -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_, 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.math.Num.prototype.toObject = function(opt_includeInstance) { - return proto.math.Num.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.math.Num} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.Num.toObject = function(includeInstance, msg) { - var f, obj = { - num: msg.getNum() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.Num} - */ -proto.math.Num.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.Num; - return proto.math.Num.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.Num} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.Num} - */ -proto.math.Num.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setNum(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.math.Num} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.Num.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.Num.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.math.Num.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getNum(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.Num} The clone. - */ -proto.math.Num.prototype.cloneMessage = function() { - return /** @type {!proto.math.Num} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 num = 1; - * @return {number} - */ -proto.math.Num.prototype.getNum = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.Num.prototype.setNum = 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.math.FibReply = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.FibReply, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.FibReply.displayName = 'proto.math.FibReply'; -} - - -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_, 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.math.FibReply.prototype.toObject = function(opt_includeInstance) { - return proto.math.FibReply.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.math.FibReply} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.FibReply.toObject = function(includeInstance, msg) { - var f, obj = { - count: msg.getCount() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.FibReply} - */ -proto.math.FibReply.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.FibReply; - return proto.math.FibReply.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.FibReply} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.FibReply} - */ -proto.math.FibReply.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setCount(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.math.FibReply} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.FibReply.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.FibReply.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.math.FibReply.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getCount(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.FibReply} The clone. - */ -proto.math.FibReply.prototype.cloneMessage = function() { - return /** @type {!proto.math.FibReply} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 count = 1; - * @return {number} - */ -proto.math.FibReply.prototype.getCount = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.FibReply.prototype.setCount = function(value) { - jspb.Message.setField(this, 1, value); -}; - - -goog.object.extend(exports, proto.math); diff --git a/packages/grpc-native-core/test/math/math_server.js b/packages/grpc-native-core/test/math/math_server.js deleted file mode 100644 index 4291ae18b..000000000 --- a/packages/grpc-native-core/test/math/math_server.js +++ /dev/null @@ -1,124 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var grpc = require('../..'); -var grpcMath = require('./math_grpc_pb'); -var math = require('./math_pb'); - -/** - * Server function for division. Provides the /Math/DivMany and /Math/Div - * functions (Div is just DivMany with only one stream element). For each - * DivArgs parameter, responds with a DivReply with the results of the division - * @param {Object} call The object containing request and cancellation info - * @param {function(Error, *)} cb Response callback - */ -function mathDiv(call, cb) { - var req = call.request; - var divisor = req.getDivisor(); - var dividend = req.getDividend(); - // Unary + is explicit coersion to integer - if (req.getDivisor() === 0) { - cb(new Error('cannot divide by zero')); - } else { - var response = new math.DivReply(); - response.setQuotient(Math.floor(dividend / divisor)); - response.setRemainder(dividend % divisor); - cb(null, response); - } -} - -/** - * Server function for Fibonacci numbers. Provides the /Math/Fib function. Reads - * a single parameter that indicates the number of responses, and then responds - * with a stream of that many Fibonacci numbers. - * @param {stream} stream The stream for sending responses. - */ -function mathFib(stream) { - // Here, call is a standard writable Node object Stream - var previous = 0, current = 1; - for (var i = 0; i < stream.request.getLimit(); i++) { - var response = new math.Num(); - response.setNum(current); - stream.write(response); - var temp = current; - current += previous; - previous = temp; - } - stream.end(); -} - -/** - * Server function for summation. Provides the /Math/Sum function. Reads a - * stream of number parameters, then responds with their sum. - * @param {stream} call The stream of arguments. - * @param {function(Error, *)} cb Response callback - */ -function mathSum(call, cb) { - // Here, call is a standard readable Node object Stream - var sum = 0; - call.on('data', function(data) { - sum += data.getNum(); - }); - call.on('end', function() { - var response = new math.Num(); - response.setNum(sum); - cb(null, response); - }); -} - -function mathDivMany(stream) { - stream.on('data', function(div_args) { - var divisor = div_args.getDivisor(); - var dividend = div_args.getDividend(); - if (divisor === 0) { - stream.emit('error', new Error('cannot divide by zero')); - } else { - var response = new math.DivReply(); - response.setQuotient(Math.floor(dividend / divisor)); - response.setRemainder(dividend % divisor); - stream.write(response); - } - }); - stream.on('end', function() { - stream.end(); - }); -} - -function getMathServer() { - var server = new grpc.Server(); - server.addService(grpcMath.MathService, { - div: mathDiv, - fib: mathFib, - sum: mathSum, - divMany: mathDivMany - }); - return server; -} - -if (require.main === module) { - var server = getMathServer(); - server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); - server.start(); -} - -/** - * See docs for server - */ -module.exports = getMathServer; diff --git a/packages/grpc-native-core/test/math_client_test.js b/packages/grpc-native-core/test/math_client_test.js deleted file mode 100644 index 11deda34f..000000000 --- a/packages/grpc-native-core/test/math_client_test.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); - -var grpc = require('..'); -var math = require('./math/math_pb'); -var MathClient = require('./math/math_grpc_pb').MathClient; - -/** - * Client to use to make requests to a running server. - */ -var math_client; - -/** - * Server to test against - */ -var getServer = require('./math/math_server.js'); - -var server = getServer(); - -describe('Math client', function() { - before(function(done) { - var port_num = server.bind('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - server.start(); - math_client = new MathClient('localhost:' + port_num, - grpc.credentials.createInsecure()); - done(); - }); - after(function() { - server.forceShutdown(); - }); - it('should handle a single request', function(done) { - var arg = new math.DivArgs(); - arg.setDividend(7); - arg.setDivisor(4); - math_client.div(arg, function handleDivResult(err, value) { - assert.ifError(err); - assert.equal(value.getQuotient(), 1); - assert.equal(value.getRemainder(), 3); - done(); - }); - }); - it('should handle an error from a unary request', function(done) { - var arg = new math.DivArgs(); - arg.setDividend(7); - arg.setDivisor(0); - math_client.div(arg, function handleDivResult(err, value) { - assert(err); - done(); - }); - }); - it('should handle a server streaming request', function(done) { - var arg = new math.FibArgs(); - arg.setLimit(7); - var call = math_client.fib(arg); - var expected_results = [1, 1, 2, 3, 5, 8, 13]; - var next_expected = 0; - call.on('data', function checkResponse(value) { - assert.equal(value.getNum(), expected_results[next_expected]); - next_expected += 1; - }); - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('should handle a client streaming request', function(done) { - var call = math_client.sum(function handleSumResult(err, value) { - assert.ifError(err); - assert.equal(value.getNum(), 21); - }); - for (var i = 0; i < 7; i++) { - var arg = new math.Num(); - arg.setNum(i); - call.write(arg); - } - call.end(); - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('should handle a bidirectional streaming request', function(done) { - function checkResponse(index, value) { - assert.equal(value.getQuotient(), index); - assert.equal(value.getRemainder(), 1); - } - var call = math_client.divMany(); - var response_index = 0; - call.on('data', function(value) { - checkResponse(response_index, value); - response_index += 1; - }); - for (var i = 0; i < 7; i++) { - var arg = new math.DivArgs(); - arg.setDividend(2 * i + 1); - arg.setDivisor(2); - call.write(arg); - } - call.end(); - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('should handle an error from a bidi request', function(done) { - var call = math_client.divMany(); - call.on('data', function(value) { - assert.fail(value, undefined, 'Unexpected data response on failing call', - '!='); - }); - var arg = new math.DivArgs(); - arg.setDividend(7); - arg.setDivisor(0); - call.write(arg); - call.end(); - call.on('error', function checkStatus(status) { - done(); - }); - }); -}); diff --git a/packages/grpc-native-core/test/metadata_test.js b/packages/grpc-native-core/test/metadata_test.js deleted file mode 100644 index 4ba54e0aa..000000000 --- a/packages/grpc-native-core/test/metadata_test.js +++ /dev/null @@ -1,178 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var Metadata = require('../src/metadata.js'); - -var assert = require('assert'); - -describe('Metadata', function() { - var metadata; - beforeEach(function() { - metadata = new Metadata(); - }); - describe('#set', function() { - it('Only accepts string values for non "-bin" keys', function() { - assert.throws(function() { - metadata.set('key', new Buffer('value')); - }); - assert.doesNotThrow(function() { - metadata.set('key', 'value'); - }); - }); - it('Only accepts Buffer values for "-bin" keys', function() { - assert.throws(function() { - metadata.set('key-bin', 'value'); - }); - assert.doesNotThrow(function() { - metadata.set('key-bin', new Buffer('value')); - }); - }); - it('Rejects invalid keys', function() { - assert.throws(function() { - metadata.set('key$', 'value'); - }); - assert.throws(function() { - metadata.set('', 'value'); - }); - }); - it('Rejects values with non-ASCII characters', function() { - assert.throws(function() { - metadata.set('key', 'résumé'); - }); - }); - it('Saves values that can be retrieved', function() { - metadata.set('key', 'value'); - assert.deepEqual(metadata.get('key'), ['value']); - }); - it('Overwrites previous values', function() { - metadata.set('key', 'value1'); - metadata.set('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value2']); - }); - it('Normalizes keys', function() { - metadata.set('Key', 'value1'); - assert.deepEqual(metadata.get('key'), ['value1']); - metadata.set('KEY', 'value2'); - assert.deepEqual(metadata.get('key'), ['value2']); - }); - }); - describe('#add', function() { - it('Only accepts string values for non "-bin" keys', function() { - assert.throws(function() { - metadata.add('key', new Buffer('value')); - }); - assert.doesNotThrow(function() { - metadata.add('key', 'value'); - }); - }); - it('Only accepts Buffer values for "-bin" keys', function() { - assert.throws(function() { - metadata.add('key-bin', 'value'); - }); - assert.doesNotThrow(function() { - metadata.add('key-bin', new Buffer('value')); - }); - }); - it('Rejects invalid keys', function() { - assert.throws(function() { - metadata.add('key$', 'value'); - }); - assert.throws(function() { - metadata.add('', 'value'); - }); - }); - it('Saves values that can be retrieved', function() { - metadata.add('key', 'value'); - assert.deepEqual(metadata.get('key'), ['value']); - }); - it('Combines with previous values', function() { - metadata.add('key', 'value1'); - metadata.add('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); - }); - it('Normalizes keys', function() { - metadata.add('Key', 'value1'); - assert.deepEqual(metadata.get('key'), ['value1']); - metadata.add('KEY', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); - }); - }); - describe('#remove', function() { - it('clears values from a key', function() { - metadata.add('key', 'value'); - metadata.remove('key'); - assert.deepEqual(metadata.get('key'), []); - }); - it('Normalizes keys', function() { - metadata.add('key', 'value'); - metadata.remove('KEY'); - assert.deepEqual(metadata.get('key'), []); - }); - }); - describe('#get', function() { - beforeEach(function() { - metadata.add('key', 'value1'); - metadata.add('key', 'value2'); - metadata.add('key-bin', new Buffer('value')); - }); - it('gets all values associated with a key', function() { - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); - }); - it('Normalizes keys', function() { - assert.deepEqual(metadata.get('KEY'), ['value1', 'value2']); - }); - it('returns an empty list for non-existent keys', function() { - assert.deepEqual(metadata.get('non-existent-key'), []); - }); - it('returns Buffers for "-bin" keys', function() { - assert(metadata.get('key-bin')[0] instanceof Buffer); - }); - }); - describe('#getMap', function() { - it('gets a map of keys to values', function() { - metadata.add('key1', 'value1'); - metadata.add('Key2', 'value2'); - metadata.add('KEY3', 'value3'); - assert.deepEqual(metadata.getMap(), - {key1: 'value1', - key2: 'value2', - key3: 'value3'}); - }); - }); - describe('#clone', function() { - it('retains values from the original', function() { - metadata.add('key', 'value'); - var copy = metadata.clone(); - assert.deepEqual(copy.get('key'), ['value']); - }); - it('Does not see newly added values', function() { - metadata.add('key', 'value1'); - var copy = metadata.clone(); - metadata.add('key', 'value2'); - assert.deepEqual(copy.get('key'), ['value1']); - }); - it('Does not add new values to the original', function() { - metadata.add('key', 'value1'); - var copy = metadata.clone(); - copy.add('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1']); - }); - }); -}); diff --git a/packages/grpc-native-core/test/numbers.txt b/packages/grpc-native-core/test/numbers.txt deleted file mode 100644 index 4972919b4..000000000 --- a/packages/grpc-native-core/test/numbers.txt +++ /dev/null @@ -1,496 +0,0 @@ -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 diff --git a/packages/grpc-native-core/test/server_test.js b/packages/grpc-native-core/test/server_test.js index 454acbda1..c1b941948 100644 --- a/packages/grpc-native-core/test/server_test.js +++ b/packages/grpc-native-core/test/server_test.js @@ -72,8 +72,8 @@ describe('server', function() { }); it('should bind to an unused port with ssl credentials', function() { var port; - var key_path = path.join(__dirname, '../test/data/server1.key'); - var pem_path = path.join(__dirname, '../test/data/server1.pem'); + var key_path = path.join(__dirname, '../../../test/data/server1.key'); + var pem_path = path.join(__dirname, '../../../test/data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); var creds = grpc.ServerCredentials.createSsl(null, diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js deleted file mode 100644 index ce6ede84d..000000000 --- a/packages/grpc-native-core/test/surface_test.js +++ /dev/null @@ -1,1379 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var _ = require('lodash'); - -var grpc = require('..'); - -var MathClient = grpc.load( - __dirname + '/../deps/grpc/src/proto/math/math.proto').math.Math; -var mathServiceAttrs = MathClient.service; - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} - -var server_insecure_creds = grpc.ServerCredentials.createInsecure(); - -describe('File loader', function() { - it('Should load a proto file by default', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto'); - }); - }); - it('Should load a proto file with the proto format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto', 'proto'); - }); - }); - it('Should load a json file with the json format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.json', 'json'); - }); - }); -}); -describe('surface Server', function() { - var server; - beforeEach(function() { - server = new grpc.Server(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('should error if started twice', function() { - server.start(); - assert.throws(function() { - server.start(); - }); - }); - it('should error if a port is bound after the server starts', function() { - server.start(); - assert.throws(function() { - server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); - }); - }); - it('should successfully shutdown if tryShutdown is called', function(done) { - server.start(); - server.tryShutdown(done); - }); -}); -describe('Server.prototype.addService', function() { - var server; - var dummyImpls = { - 'div': function() {}, - 'divMany': function() {}, - 'fib': function() {}, - 'sum': function() {} - }; - beforeEach(function() { - server = new grpc.Server(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('Should succeed with a single service', function() { - assert.doesNotThrow(function() { - server.addService(mathServiceAttrs, dummyImpls); - }); - }); - it('Should fail with conflicting method names', function() { - server.addService(mathServiceAttrs, dummyImpls); - assert.throws(function() { - server.addService(mathServiceAttrs, dummyImpls); - }); - }); - it('Should allow method names as originally written', function() { - var altDummyImpls = { - 'Div': function() {}, - 'DivMany': function() {}, - 'Fib': function() {}, - 'Sum': function() {} - }; - assert.doesNotThrow(function() { - server.addService(mathServiceAttrs, altDummyImpls); - }); - }); - it('Should have a conflict between name variations', function() { - /* This is really testing that both name variations are actually used, - by checking that the method actually gets registered, for the - corresponding function, in both cases */ - var altDummyImpls = { - 'Div': function() {}, - 'DivMany': function() {}, - 'Fib': function() {}, - 'Sum': function() {} - }; - server.addProtoService(mathServiceAttrs, altDummyImpls); - assert.throws(function() { - server.addProtoService(mathServiceAttrs, dummyImpls); - }); - }); - it('Should fail if the server has been started', function() { - server.start(); - assert.throws(function() { - server.addService(mathServiceAttrs, dummyImpls); - }); - }); - describe('Default handlers', function() { - var client; - beforeEach(function() { - server.addService(mathServiceAttrs, {}); - var port = server.bind('localhost:0', server_insecure_creds); - client = new MathClient('localhost:' + port, - grpc.credentials.createInsecure()); - server.start(); - }); - it('should respond to a unary call with UNIMPLEMENTED', function(done) { - client.div({divisor: 4, dividend: 3}, function(error, response) { - assert(error); - assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); - done(); - }); - }); - it('should respond to a client stream with UNIMPLEMENTED', function(done) { - var call = client.sum(function(error, respones) { - assert(error); - assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); - done(); - }); - call.end(); - }); - it('should respond to a server stream with UNIMPLEMENTED', function(done) { - var call = client.fib({limit: 5}); - call.on('data', function(value) { - assert.fail('No messages expected'); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); - done(); - }); - call.on('error', function(status) { /* Do nothing */ }); - }); - it('should respond to a bidi call with UNIMPLEMENTED', function(done) { - var call = client.divMany(); - call.on('data', function(value) { - assert.fail('No messages expected'); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); - done(); - }); - call.on('error', function(status) { /* Do nothing */ }); - call.end(); - }); - }); -}); -describe('Client constructor building', function() { - var illegal_service_attrs = { - $method : { - path: '/illegal/$method', - requestStream: false, - responseStream: false, - requestSerialize: _.identity, - requestDeserialize: _.identity, - responseSerialize: _.identity, - responseDeserialize: _.identity - } - }; - it('Should reject method names starting with $', function() { - assert.throws(function() { - grpc.makeGenericClientConstructor(illegal_service_attrs); - }, /\$/); - }); - it('Should add aliases for original names', function() { - var Client = grpc.makeGenericClientConstructor(mathServiceAttrs); - assert.strictEqual(Client.prototype.add, Client.prototype.Add); - }); -}); -describe('waitForClientReady', function() { - var server; - var port; - var Client = MathClient; - var client; - before(function() { - server = new grpc.Server(); - port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); - server.start(); - }); - beforeEach(function() { - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('should complete when called alone', function(done) { - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - }); - it('should complete when a call is initiated', function(done) { - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - var call = client.div({}, function(err, response) {}); - call.cancel(); - }); - it('should complete if called more than once', function(done) { - done = multiDone(done, 2); - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - }); - it('should complete if called when already ready', function(done) { - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - }); - }); - it('should time out if the server does not exist', function(done) { - var bad_client = new Client('nonexistent_hostname', - grpc.credentials.createInsecure()); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - grpc.waitForClientReady(bad_client, deadline, function(error) { - assert(error); - done(); - }); - }); -}); -describe('Echo service', function() { - var server; - var client; - before(function() { - var Client = grpc.load(__dirname + '/echo_service.proto').EchoService; - server = new grpc.Server(); - server.addService(Client.service, { - echo: function(call, callback) { - callback(null, call.request); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('should echo the recieved message directly', function(done) { - client.echo({value: 'test value', value2: 3}, function(error, response) { - assert.ifError(error); - assert.deepEqual(response, {value: 'test value', value2: 3}); - done(); - }); - }); - it('Should convert an undefined argument to default values', function(done) { - client.echo(undefined, function(error, response) { - assert.ifError(error); - assert.deepEqual(response, {value: '', value2: 0}); - done(); - }); - }); -}); -describe('Generic client and server', function() { - function toString(val) { - return val.toString(); - } - function toBuffer(str) { - return new Buffer(str); - } - var string_service_attrs = { - 'capitalize' : { - path: '/string/capitalize', - requestStream: false, - responseStream: false, - requestSerialize: toBuffer, - requestDeserialize: toString, - responseSerialize: toBuffer, - responseDeserialize: toString - } - }; - describe('String client and server', function() { - var client; - var server; - before(function() { - server = new grpc.Server(); - server.addService(string_service_attrs, { - capitalize: function(call, callback) { - callback(null, _.capitalize(call.request)); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - server.start(); - var Client = grpc.makeGenericClientConstructor(string_service_attrs); - client = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('Should respond with a capitalized string', function(done) { - client.capitalize('abc', function(err, response) { - assert.ifError(err); - assert.strictEqual(response, 'Abc'); - done(); - }); - }); - }); -}); -describe('Server-side getPeer', function() { - function toString(val) { - return val.toString(); - } - function toBuffer(str) { - return new Buffer(str); - } - var string_service_attrs = { - 'getPeer' : { - path: '/string/getPeer', - requestStream: false, - responseStream: false, - requestSerialize: toBuffer, - requestDeserialize: toString, - responseSerialize: toBuffer, - responseDeserialize: toString - } - }; - var client; - var server; - before(function() { - server = new grpc.Server(); - server.addService(string_service_attrs, { - getPeer: function(call, callback) { - try { - callback(null, call.getPeer()); - } catch (e) { - call.emit('error', e); - } - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - server.start(); - var Client = grpc.makeGenericClientConstructor(string_service_attrs); - client = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('should respond with a string representing the client', function(done) { - client.getPeer('', function(err, response) { - assert.ifError(err); - // We don't expect a specific value, just that it worked without error - done(); - }); - }); -}); -describe('Echo metadata', function() { - var client; - var server; - var metadata; - before(function() { - var Client = grpc.load(__dirname + '/test_service.proto').TestService; - server = new grpc.Server(); - server.addService(Client.service, { - unary: function(call, cb) { - call.sendMetadata(call.metadata); - cb(null, {}); - }, - clientStream: function(stream, cb){ - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.sendMetadata(stream.metadata); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - stream.end(); - }); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - metadata = new grpc.Metadata(); - metadata.set('key', 'value'); - }); - after(function() { - server.forceShutdown(); - }); - it('with unary call', function(done) { - var call = client.unary({}, metadata, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - }); - it('with client stream call', function(done) { - var call = client.clientStream(metadata, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - call.end(); - }); - it('with server stream call', function(done) { - var call = client.serverStream({}, metadata); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - }); - it('with bidi stream call', function(done) { - var call = client.bidiStream(metadata); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - call.end(); - }); - it('shows the correct user-agent string', function(done) { - var version = require('../package.json').version; - var call = client.unary({}, metadata, - function(err, data) { assert.ifError(err); }); - call.on('metadata', function(metadata) { - assert(_.startsWith(metadata.get('user-agent')[0], - 'grpc-node/' + version)); - done(); - }); - }); - it('properly handles duplicate values', function(done) { - var dup_metadata = metadata.clone(); - dup_metadata.add('key', 'value2'); - var call = client.unary({}, dup_metadata, - function(err, data) {assert.ifError(err); }); - call.on('metadata', function(resp_metadata) { - // Two arrays are equal iff their symmetric difference is empty - assert.deepEqual(_.xor(dup_metadata.get('key'), resp_metadata.get('key')), - []); - done(); - }); - }); -}); -describe('Client malformed response handling', function() { - var server; - var client; - var badArg = new Buffer([0xFF]); - before(function() { - var Client = grpc.load(__dirname + '/test_service.proto').TestService; - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity - } - }; - server = new grpc.Server(); - server.addService(malformed_test_service, { - unary: function(call, cb) { - cb(null, badArg); - }, - clientStream: function(stream, cb) { - stream.on('data', function() {/* Ignore requests */}); - stream.on('end', function() { - cb(null, badArg); - }); - }, - serverStream: function(stream) { - stream.write(badArg); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write(badArg); - }); - stream.on('end', function() { - stream.end(); - }); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('should get an INTERNAL status with a unary call', function(done) { - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - it('should get an INTERNAL status with a server stream call', function(done) { - var call = client.serverStream({}); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a bidi stream call', function(done) { - var call = client.bidiStream(); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); -}); -describe('Server serialization failure handling', function() { - function serializeFail(obj) { - throw new Error('Serialization failed'); - } - var client; - var server; - before(function() { - var Client = grpc.load(__dirname + '/test_service.proto').TestService; - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: serializeFail - } - }; - server = new grpc.Server(); - server.addService(malformed_test_service, { - unary: function(call, cb) { - cb(null, {}); - }, - clientStream: function(stream, cb) { - stream.on('data', function() {/* Ignore requests */}); - stream.on('end', function() { - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.write({}); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write({}); - }); - stream.on('end', function() { - stream.end(); - }); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('should get an INTERNAL status with a unary call', function(done) { - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - it('should get an INTERNAL status with a server stream call', function(done) { - var call = client.serverStream({}); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a bidi stream call', function(done) { - var call = client.bidiStream(); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); -}); -describe('Other conditions', function() { - var Client; - var client; - var server; - var port; - before(function() { - Client = grpc.load(__dirname + '/test_service.proto').TestService; - server = new grpc.Server(); - var trailer_metadata = new grpc.Metadata(); - trailer_metadata.add('trailer-present', 'yes'); - server.addService(Client.service, { - unary: function(call, cb) { - var req = call.request; - if (req.error) { - cb({code: grpc.status.UNKNOWN, - details: 'Requested error'}, null, trailer_metadata); - } else { - cb(null, {count: 1}, trailer_metadata); - } - }, - clientStream: function(stream, cb){ - var count = 0; - var errored; - stream.on('data', function(data) { - if (data.error) { - errored = true; - cb(new Error('Requested error'), null, trailer_metadata); - } else { - count += 1; - } - }); - stream.on('end', function() { - if (!errored) { - cb(null, {count: count}, trailer_metadata); - } - }); - }, - serverStream: function(stream) { - var req = stream.request; - if (req.error) { - var err = {code: grpc.status.UNKNOWN, - details: 'Requested error'}; - err.metadata = trailer_metadata; - stream.emit('error', err); - } else { - for (var i = 0; i < 5; i++) { - stream.write({count: i}); - } - stream.end(trailer_metadata); - } - }, - bidiStream: function(stream) { - var count = 0; - stream.on('data', function(data) { - if (data.error) { - var err = new Error('Requested error'); - err.metadata = trailer_metadata.clone(); - err.metadata.add('count', '' + count); - stream.emit('error', err); - } else { - stream.write({count: count}); - count += 1; - } - }); - stream.on('end', function() { - stream.end(trailer_metadata); - }); - } - }); - port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('channel.getTarget should be available', function() { - assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(), - 'string'); - }); - it('client should be able to pause and resume a stream', function(done) { - var call = client.bidiStream(); - call.on('data', function(data) { - assert(data.count < 3); - call.pause(); - setTimeout(function() { - call.resume(); - }, 10); - }); - call.on('end', function() { - done(); - }); - call.write({}); - call.write({}); - call.write({}); - call.end(); - }); - describe('Server recieving bad input', function() { - var misbehavingClient; - var badArg = new Buffer([0xFF]); - before(function() { - var test_service_attrs = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity - } - }; - var Client = grpc.makeGenericClientConstructor(test_service_attrs, - 'TestService'); - misbehavingClient = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - }); - it('should respond correctly to a unary call', function(done) { - misbehavingClient.unary(badArg, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should respond correctly to a client stream', function(done) { - var call = misbehavingClient.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write(badArg); - // TODO(mlumish): Remove call.end() - call.end(); - }); - it('should respond correctly to a server stream', function(done) { - var call = misbehavingClient.serverStream(badArg); - call.on('data', function(data) { - assert.fail(data, null, 'Unexpected data', '==='); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should respond correctly to a bidi stream', function(done) { - var call = misbehavingClient.bidiStream(); - call.on('data', function(data) { - assert.fail(data, null, 'Unexpected data', '==='); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write(badArg); - // TODO(mlumish): Remove call.end() - call.end(); - }); - }); - describe('Trailing metadata', function() { - it('should be present when a unary call succeeds', function(done) { - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a unary call fails', function(done) { - var call = client.unary({error: true}, function(err, data) { - assert(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a client stream call succeeds', function(done) { - var call = client.clientStream(function(err, data) { - assert.ifError(err); - }); - call.write({error: false}); - call.write({error: false}); - call.end(); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a client stream call fails', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - }); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a server stream call succeeds', function(done) { - var call = client.serverStream({error: false}); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a server stream call fails', function(done) { - var call = client.serverStream({error: true}); - call.on('data', function(){}); - call.on('error', function(error) { - assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a bidi stream succeeds', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: false}); - call.end(); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a bidi stream fails', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('data', function(){}); - call.on('error', function(error) { - assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - }); - describe('Error object should contain the status', function() { - it('for a unary call', function(done) { - client.unary({error: true}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.message, 'Requested error'); - done(); - }); - }); - it('for a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.message, 'Requested error'); - done(); - }); - call.write({error: false}); - call.write({error: true}); - call.end(); - }); - it('for a server stream call', function(done) { - var call = client.serverStream({error: true}); - call.on('data', function(){}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.UNKNOWN); - assert.strictEqual(error.message, 'Requested error'); - done(); - }); - }); - it('for a bidi stream call', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('data', function(){}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.UNKNOWN); - assert.strictEqual(error.message, 'Requested error'); - done(); - }); - }); - }); - describe('call.getPeer should return the peer', function() { - it('for a unary call', function(done) { - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); - done(); - }); - assert.strictEqual(typeof call.getPeer(), 'string'); - }); - it('for a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert.ifError(err); - done(); - }); - assert.strictEqual(typeof call.getPeer(), 'string'); - call.write({error: false}); - call.end(); - }); - it('for a server stream call', function(done) { - var call = client.serverStream({error: false}); - assert.strictEqual(typeof call.getPeer(), 'string'); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('for a bidi stream call', function(done) { - var call = client.bidiStream(); - assert.strictEqual(typeof call.getPeer(), 'string'); - call.write({error: false}); - call.end(); - call.on('data', function(){}); - call.on('status', function(status) { - done(); - }); - }); - it('after the call has fully completed', function(done) { - var peer; - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); - setImmediate(function() { - assert.strictEqual(peer, call.getPeer()); - done(); - }); - }); - peer = call.getPeer(); - assert.strictEqual(typeof peer, 'string'); - }); - }); -}); -describe('Call propagation', function() { - var proxy; - var proxy_impl; - - var Client; - var client; - var server; - before(function() { - Client = grpc.load(__dirname + '/test_service.proto').TestService; - server = new grpc.Server(); - server.addService(Client.service, { - unary: function(call) {}, - clientStream: function(stream) {}, - serverStream: function(stream) {}, - bidiStream: function(stream) {} - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - beforeEach(function() { - proxy = new grpc.Server(); - proxy_impl = { - unary: function(call) {}, - clientStream: function(stream) {}, - serverStream: function(stream) {}, - bidiStream: function(stream) {} - }; - }); - afterEach(function() { - proxy.forceShutdown(); - }); - describe('Cancellation', function() { - it('With a unary call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.unary = function(parent, callback) { - client.unary(parent.request, {parent: parent}, function(err, value) { - try { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - } finally { - callback(err, value); - done(); - } - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.unary({}, function(err, value) { done(); }); - }); - it('With a client stream call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.clientStream = function(parent, callback) { - client.clientStream({parent: parent}, function(err, value) { - try { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - } finally { - callback(err, value); - done(); - } - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.clientStream(function(err, value) { done(); }); - }); - it('With a server stream call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.serverStream = function(parent) { - var child = client.serverStream(parent.request, {parent: parent}); - child.on('data', function() {}); - child.on('error', function(err) { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.serverStream({}); - call.on('data', function() {}); - call.on('error', function(err) { - done(); - }); - }); - it('With a bidi stream call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.bidiStream = function(parent) { - var child = client.bidiStream({parent: parent}); - child.on('data', function() {}); - child.on('error', function(err) { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.bidiStream(); - call.on('data', function() {}); - call.on('error', function(err) { - done(); - }); - }); - }); - describe('Deadline', function() { - /* jshint bitwise:false */ - var deadline_flags = (grpc.propagate.DEFAULTS & - ~grpc.propagate.CANCELLATION); - it('With a client stream call', function(done) { - done = multiDone(done, 2); - proxy_impl.clientStream = function(parent, callback) { - var options = {parent: parent, propagate_flags: deadline_flags}; - client.clientStream(options, function(err, value) { - try { - assert(err); - assert(err.code === grpc.status.DEADLINE_EXCEEDED || - err.code === grpc.status.INTERNAL); - } finally { - callback(err, value); - done(); - } - }); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - proxy_client.clientStream({deadline: deadline}, function(err, value) { - done(); - }); - }); - it('With a bidi stream call', function(done) { - done = multiDone(done, 2); - proxy_impl.bidiStream = function(parent) { - var child = client.bidiStream( - {parent: parent, propagate_flags: deadline_flags}); - child.on('data', function() {}); - child.on('error', function(err) { - assert(err); - assert(err.code === grpc.status.DEADLINE_EXCEEDED || - err.code === grpc.status.INTERNAL); - done(); - }); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - var call = proxy_client.bidiStream({deadline: deadline}); - call.on('data', function() {}); - call.on('error', function(err) { - done(); - }); - }); - }); -}); -describe('Cancelling surface client', function() { - var client; - var server; - before(function() { - server = new grpc.Server(); - server.addService(mathServiceAttrs, { - 'div': function(stream) {}, - 'divMany': function(stream) {}, - 'fib': function(stream) {}, - 'sum': function(stream) {} - }); - var port = server.bind('localhost:0', server_insecure_creds); - var Client = grpc.makeGenericClientConstructor(mathServiceAttrs); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('Should correctly cancel a unary call', function(done) { - var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should correctly cancel a client stream call', function(done) { - var call = client.sum(function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should correctly cancel a server stream call', function(done) { - var call = client.fib({'limit': 5}); - call.on('data', function() {}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should correctly cancel a bidi stream call', function(done) { - var call = client.divMany(); - call.on('data', function() {}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should be idempotent', function(done) { - var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - // Call asynchronously to try cancelling after call is fully completed - setImmediate(function() { - assert.doesNotThrow(function() { - call.cancel(); - }); - done(); - }); - }); - call.cancel(); - }); -}); -describe('Client reconnect', function() { - var server; - var Client; - var client; - var port; - beforeEach(function() { - Client = grpc.load(__dirname + '/echo_service.proto').EchoService; - server = new grpc.Server(); - server.addService(Client.service, { - echo: function(call, callback) { - callback(null, call.request); - } - }); - port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('should reconnect after server restart', function(done) { - client.echo({value: 'test value', value2: 3}, function(error, response) { - assert.ifError(error); - assert.deepEqual(response, {value: 'test value', value2: 3}); - server.tryShutdown(function() { - server = new grpc.Server(); - server.addService(Client.service, { - echo: function(call, callback) { - callback(null, call.request); - } - }); - server.bind('localhost:' + port, server_insecure_creds); - server.start(); - - /* We create a new client, that will not throw an error if the server - * is not immediately available. Instead, it will wait for the server - * to be available, then the call will complete. Once this happens, the - * original client should be able to make a new call and connect to the - * restarted server without having the call fail due to connection - * errors. */ - var client2 = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - client2.echo({value: 'test', value2: 3}, function(error, response) { - assert.ifError(error); - client.echo(undefined, function(error, response) { - if (error) { - console.log(error); - } - assert.ifError(error); - assert.deepEqual(response, {value: '', value2: 0}); - done(); - }); - }); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/test_service.json b/packages/grpc-native-core/test/test_service.json deleted file mode 100644 index 6f952c6ad..000000000 --- a/packages/grpc-native-core/test/test_service.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "package": null, - "messages": [ - { - "name": "Request", - "fields": [ - { - "rule": "optional", - "type": "bool", - "name": "error", - "id": 1 - } - ] - }, - { - "name": "Response", - "fields": [ - { - "rule": "optional", - "type": "int32", - "name": "count", - "id": 1 - } - ] - } - ], - "services": [ - { - "name": "TestService", - "options": {}, - "rpc": { - "Unary": { - "request": "Request", - "response": "Response", - "options": {} - }, - "ClientStream": { - "request": "Request", - "response": "Response", - "options": {} - }, - "ServerStream": { - "request": "Request", - "response": "Response", - "options": {} - }, - "BidiStream": { - "request": "Request", - "response": "Response", - "options": {} - } - } - } - ] -} \ No newline at end of file diff --git a/packages/grpc-native-core/test/test_service.proto b/packages/grpc-native-core/test/test_service.proto deleted file mode 100644 index b16dfecca..000000000 --- a/packages/grpc-native-core/test/test_service.proto +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -message Request { - bool error = 1; -} - -message Response { - int32 count = 1; -} - -service TestService { - rpc Unary (Request) returns (Response) { - } - - rpc ClientStream (stream Request) returns (Response) { - } - - rpc ServerStream (Request) returns (stream Response) { - } - - rpc BidiStream (stream Request) returns (stream Response) { - } -} From 58206feb3f68b5ef24f48fd9d8a7c6de79538127 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 7 Dec 2017 14:20:24 -0800 Subject: [PATCH 0044/1899] grpc-js-core: compiler error fixes --- packages/grpc-js-core/src/call-credentials.ts | 10 +++++----- packages/grpc-js-core/src/metadata.ts | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 5b322402f..3be454d5f 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -3,7 +3,7 @@ import {map, reduce} from 'lodash'; import {Metadata} from './metadata'; export type CallMetadataGenerator = - (options: Object, cb: (err: Error|null, metadata?: Metadata) => void) => + (options: {}, cb: (err: Error|null, metadata?: Metadata) => void) => void; /** @@ -15,7 +15,7 @@ export interface CallCredentials { * Asynchronously generates a new Metadata object. * @param options Options used in generating the Metadata object. */ - generateMetadata(options: Object): Promise; + generateMetadata(options: {}): Promise; /** * Creates a new CallCredentials object from properties of both this and * another CallCredentials object. This object's metadata generator will be @@ -28,7 +28,7 @@ export interface CallCredentials { class ComposedCallCredentials implements CallCredentials { constructor(private creds: CallCredentials[]) {} - async generateMetadata(options: Object): Promise { + async generateMetadata(options: {}): Promise { let base: Metadata = new Metadata(); let generated: Metadata[] = await Promise.all( map(this.creds, (cred) => cred.generateMetadata(options))); @@ -46,7 +46,7 @@ class ComposedCallCredentials implements CallCredentials { class SingleCallCredentials implements CallCredentials { constructor(private metadataGenerator: CallMetadataGenerator) {} - async generateMetadata(options: Object): Promise { + async generateMetadata(options: {}): Promise { return new Promise((resolve, reject) => { this.metadataGenerator(options, (err, metadata) => { if (metadata !== undefined) { @@ -64,7 +64,7 @@ class SingleCallCredentials implements CallCredentials { } class EmptyCallCredentials implements CallCredentials { - async generateMetadata(options: Object): Promise { + async generateMetadata(options: {}): Promise { return new Metadata(); } diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index c4bb2568e..9ed69dfcc 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -194,7 +194,7 @@ export class Metadata { values.forEach((value) => { result.add(key, Buffer.from(value, 'base64')); }); - } else { + } else if (values !== undefined) { result.add(key, Buffer.from(values, 'base64')); } } else { @@ -202,7 +202,7 @@ export class Metadata { values.forEach((value) => { result.add(key, value); }); - } else { + } else if (values !== undefined) { result.add(key, values); } } From 09cb531f9beb0001b202623b8462d7a37c346564 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 7 Dec 2017 10:38:32 -0800 Subject: [PATCH 0045/1899] grpc-js-core: prepend protocol before creating URL object from address --- packages/grpc-js-core/src/channel.ts | 13 +++++++------ packages/grpc-js-core/src/client.ts | 2 +- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index a51ae9572..d28d8d592 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -71,6 +71,7 @@ export interface Channel extends EventEmitter { } export class Http2Channel extends EventEmitter implements Channel { + private readonly authority: url.URL; private connectivityState: ConnectivityState = ConnectivityState.IDLE; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ @@ -134,9 +135,9 @@ export class Http2Channel extends EventEmitter implements Channel { let subChannel: http2.ClientHttp2Session; let secureContext = this.credentials.getSecureContext(); if (secureContext === null) { - subChannel = http2.connect(this.address); + subChannel = http2.connect(this.authority); } else { - subChannel = http2.connect(this.address, {secureContext}); + subChannel = http2.connect(this.authority, {secureContext}); } this.subChannel = subChannel; let now = new Date(); @@ -165,14 +166,14 @@ export class Http2Channel extends EventEmitter implements Channel { } constructor( - private readonly address: url.URL, + address: string, public readonly credentials: ChannelCredentials, private readonly options: ChannelOptions) { super(); if (credentials.getSecureContext() === null) { - address.protocol = 'http'; + this.authority = new url.URL(`http://${address}`); } else { - address.protocol = 'https'; + this.authority = new url.URL(`https://${address}`); } this.filterStackFactory = new FilterStackFactory([ new CompressionFilterFactory(this), @@ -193,7 +194,7 @@ export class Http2Channel extends EventEmitter implements Channel { finalMetadata.then( (metadataValue) => { let headers = metadataValue.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = this.address.hostname; + headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname; headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = methodName; diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 59a84d24f..2b040e6be 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -24,7 +24,7 @@ export class Client { } // TODO(murgatroid99): Figure out how to get version number // options['grpc.primary_user_agent'] += 'grpc-node/' + version; - this.channel = new Http2Channel(new URL(address), credentials, options); + this.channel = new Http2Channel(address, credentials, options); } close(): void { From b7eb3d6988510df3c0881a2da2aa5fcc90eb4ff1 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 7 Dec 2017 13:49:58 -0800 Subject: [PATCH 0046/1899] grpc-js-core: various fixes --- packages/grpc-js-core/src/call-stream.ts | 16 +++++++++------- packages/grpc-js-core/src/metadata.ts | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 51c587568..f62e42afa 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -182,9 +182,10 @@ export class Http2CallStream extends Duplex implements CallStream { this.cancelWithStatus(Status.UNKNOWN, error.message); }); }); - stream.on('trailers', (headers) => { + stream.on('trailers', (headers: http2.IncomingHttpHeaders) => { let code: Status = this.mappedStatusCode; - if (headers.hasOwnProperty('grpc-status')) { + let details = ''; + if (typeof headers['grpc-status'] === 'string') { let receivedCode = Number(headers['grpc-status']); if (receivedCode in Status) { code = receivedCode; @@ -193,9 +194,8 @@ export class Http2CallStream extends Duplex implements CallStream { } delete headers['grpc-status']; } - let details = ''; - if (headers.hasOwnProperty('grpc-message')) { - details = decodeURI(headers['grpc-message']); + if (typeof headers['grpc-message'] === 'string') { + details = decodeURI(headers['grpc-message'] as string); } let metadata: Metadata; try { @@ -301,7 +301,7 @@ export class Http2CallStream extends Duplex implements CallStream { } this.endCall({code: code, details: details, metadata: new Metadata()}); }); - stream.on('error', () => { + stream.on('error', (err: Error) => { this.endCall({ code: Status.INTERNAL, details: 'Internal HTTP2 error', @@ -325,7 +325,9 @@ export class Http2CallStream extends Duplex implements CallStream { cancelWithStatus(status: Status, details: string): void { this.endCall({code: status, details: details, metadata: new Metadata()}); - if (this.http2Stream !== null) { + // The http2 stream could already have been destroyed if cancelWithStatus + // is called in response to an internal http2 error. + if (this.http2Stream !== null && !this.http2Stream.destroyed) { /* TODO(murgatroid99): Determine if we want to send different RST_STREAM * codes based on the status code */ this.http2Stream.rstWithCancel(); diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 9ed69dfcc..c2ad6332a 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -166,6 +166,7 @@ export class Metadata { * Creates an OutgoingHttpHeaders object that can be used with the http2 API. */ toHttp2Headers(): http2.OutgoingHttpHeaders { + // NOTE: Node <8.9 formats http2 headers incorrectly. const result: http2.OutgoingHttpHeaders = {}; forOwn(this.internalRepr, (values, key) => { // We assume that the user's interaction with this object is limited to From d90a5d4e61cd2c399bb5fae719e506c143498069 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Dec 2017 13:58:34 -0800 Subject: [PATCH 0047/1899] Update to v1.8.0 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 65212e06e..ada05afd6 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 65212e06ef6f26edeb41411cd8a24d07f0ab6628 +Subproject commit ada05afd62a2e5d405bc1ba1c1cf2d775d1a42ea diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f9a7e7b0f..656ba8980 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.8.0-pre2", + "version": "1.8.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From ad8aa54fd676e728e6ed542c39181f1572ffd91c Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 5 Dec 2017 15:17:29 -0800 Subject: [PATCH 0048/1899] simplify gulp commands in package directories --- gulpfile.js => gulpfile.ts | 63 ++++-- package.json | 9 + packages/grpc-health-check/gulpfile.js | 12 +- packages/grpc-js-core/gulpfile.js | 197 ------------------ packages/grpc-js-core/gulpfile.ts | 76 +++++++ packages/grpc-js-core/package.json | 19 +- packages/grpc-js-core/tsconfig.json | 10 +- packages/grpc-js/{gulpfile.js => gulpfile.ts} | 21 +- packages/grpc-js/package.json | 15 +- packages/grpc-js/{index.js => src/index.ts} | 0 packages/grpc-js/tsconfig.json | 16 ++ packages/grpc-native-core/gulpfile.js | 18 +- packages/grpc-native/gulpfile.js | 10 +- packages/grpc-surface/gulpfile.js | 2 +- test/gulpfile.js | 6 +- tsconfig.json | 7 + 16 files changed, 219 insertions(+), 262 deletions(-) rename gulpfile.js => gulpfile.ts (57%) delete mode 100644 packages/grpc-js-core/gulpfile.js create mode 100644 packages/grpc-js-core/gulpfile.ts rename packages/grpc-js/{gulpfile.js => gulpfile.ts} (65%) rename packages/grpc-js/{index.js => src/index.ts} (100%) create mode 100644 packages/grpc-js/tsconfig.json create mode 100644 tsconfig.json diff --git a/gulpfile.js b/gulpfile.ts similarity index 57% rename from gulpfile.js rename to gulpfile.ts index 53ee240ab..1c116d9ba 100644 --- a/gulpfile.js +++ b/gulpfile.ts @@ -15,26 +15,52 @@ * */ -const _gulp = require('gulp'); -const help = require('gulp-help'); +import * as _gulp from 'gulp'; +import * as help from 'gulp-help'; // gulp-help monkeypatches tasks to have an additional description parameter const gulp = help(_gulp); -var runSequence = require('run-sequence'); +const runSequence = require('run-sequence'); -require('./packages/grpc-health-check/gulpfile'); -require('./packages/grpc-js/gulpfile'); -require('./packages/grpc-js-core/gulpfile'); -require('./packages/grpc-native/gulpfile'); -require('./packages/grpc-native-core/gulpfile'); -require('./packages/grpc-surface/gulpfile'); -require('./test/gulpfile'); +/** + * Require a module at the given path with a patched gulp object that prepends + * the given prefix to each task name. + * @param path The path to require. + * @param prefix The string to use as a prefix. This will be prepended to a task + * name with a '.' separator. + */ +function loadGulpTasksWithPrefix(path: string, prefix: string) { + const gulpTask = gulp.task; + gulp.task = ((taskName: string, ...args: any[]) => { + // Don't create a task for ${prefix}.help + if (taskName === 'help') { + return; + } + // The only array passed to gulp.task must be a list of dependent tasks. + const newArgs = args.map(arg => Array.isArray(arg) ? + arg.map(dep => `${prefix}.${dep}`) : arg); + gulpTask(`${prefix}.${taskName}`, ...newArgs); + }); + const result = require(path); + gulp.task = gulpTask; + return result; +} + +[ + ['./packages/grpc-health-check/gulpfile', 'health-check'], + ['./packages/grpc-js/gulpfile', 'js'], + ['./packages/grpc-js-core/gulpfile', 'js.core'], + ['./packages/grpc-native/gulpfile', 'native'], + ['./packages/grpc-native-core/gulpfile', 'native.core'], + ['./packages/grpc-surface/gulpfile', 'surface'], + ['./test/gulpfile', 'internal.test'] +].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'internal.test.install']); + ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'internal.test.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'internal.test.install']); @@ -42,22 +68,19 @@ gulp.task('install.all.windows', 'Install dependencies for all subdirectory pack gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); -gulp.task('build', 'Build packages', ['js.core.compile', 'native.core.build']); +gulp.task('build', 'Build packages', ['js.compile', 'js.core.compile', 'native.core.build']); -gulp.task('core.link', 'Add links to core packages without rebuilding', +gulp.task('link.core', 'Add links to core packages without rebuilding', ['js.link.add', 'native.link.add']); -gulp.task('surface.link', 'Link to surface packages', +gulp.task('link.surface', 'Link to surface packages', ['health-check.link.add']); gulp.task('link', 'Link together packages', (callback) => { - /* Currently, the target 'surface.link.create' doesn't work properly, and it - * is also not needed for the existing tests. The comment indicates where it - * belongs in the sequence. See npm/npm#18835 for the primary problem with it. - * This also means that 'core.link' is not needed, and the item - * 'native.core.link.create' should actually be 'core.link.create' + /** + * We use workarounds for linking in some modules. See npm/npm#18835 */ - runSequence('core.link', 'surface.link', + runSequence('link.core', 'link.surface', callback); }); diff --git a/package.json b/package.json index 3a158bc1c..cb324a088 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,13 @@ }, "license": "Apache-2.0", "devDependencies": { + "@types/execa": "^0.8.0", + "@types/gulp": "^4.0.5", + "@types/gulp-help": "0.0.34", + "@types/gulp-mocha": "0.0.31", + "@types/ncp": "^2.0.1", "@types/node": "^8.0.32", + "@types/pify": "^3.0.0", "del": "^3.0.0", "execa": "^0.8.0", "gulp": "^3.9.1", @@ -27,7 +33,10 @@ "merge2": "^1.1.0", "mocha": "^3.5.3", "mocha-jenkins-reporter": "^0.3.9", + "ncp": "^2.0.0", + "pify": "^3.0.0", "through2": "^2.0.3", + "ts-node": "^3.3.0", "tslint": "^5.5.0", "typescript": "^2.5.1", "xml2js": "^0.4.19" diff --git a/packages/grpc-health-check/gulpfile.js b/packages/grpc-health-check/gulpfile.js index 93366347f..6fcd18049 100644 --- a/packages/grpc-health-check/gulpfile.js +++ b/packages/grpc-health-check/gulpfile.js @@ -29,22 +29,22 @@ const healthCheckDir = __dirname; const baseDir = path.resolve(healthCheckDir, '..', '..'); const testDir = path.resolve(healthCheckDir, 'test'); -gulp.task('health-check.clean.links', 'Delete npm links', () => { +gulp.task('clean.links', 'Delete npm links', () => { return del(path.resolve(healthCheckDir, 'node_modules/grpc')); }); -gulp.task('health-check.clean.all', 'Delete all code created by tasks', - ['health-check.clean.links']); +gulp.task('clean.all', 'Delete all code created by tasks', + ['clean.links']); -gulp.task('health-check.install', 'Install health check dependencies', () => { +gulp.task('install', 'Install health check dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); }); -gulp.task('health-check.link.add', 'Link local copy of grpc', () => { +gulp.task('link.add', 'Link local copy of grpc', () => { linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); }); -gulp.task('health-check.test', 'Run health check tests', +gulp.task('test', 'Run health check tests', () => { return gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); }); diff --git a/packages/grpc-js-core/gulpfile.js b/packages/grpc-js-core/gulpfile.js deleted file mode 100644 index 79592139a..000000000 --- a/packages/grpc-js-core/gulpfile.js +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -const _gulp = require('gulp'); -const help = require('gulp-help'); - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const del = require('del'); -const mocha = require('gulp-mocha'); -const sourcemaps = require('gulp-sourcemaps'); -const tslint = require('gulp-tslint'); -const typescript = require('gulp-typescript'); -const util = require('gulp-util'); -const merge2 = require('merge2'); -const path = require('path'); -const through = require('through2'); -const execa = require('execa'); - -Error.stackTraceLimit = Infinity; - -const jsCoreDir = __dirname; -const tslintPath = path.resolve(jsCoreDir, 'node_modules/google-ts-style/tslint.json'); -const tsconfigPath = path.resolve(jsCoreDir, 'tsconfig.json'); -const outDir = path.resolve(jsCoreDir, 'build'); -const srcDir = path.resolve(jsCoreDir, 'src'); -const testDir = path.resolve(jsCoreDir, 'test'); - -function onError() {} - -// Coalesces all specified --file parameters into a single array -const files = !util.env.file ? [] : - Array.isArray(util.env.file) ? util.env.file : [util.env.file]; - -// If --dev is passed, override certain ts config options -let tsDevOptions = {}; -if (util.env.dev) { - tsDevOptions = { - allowUnreachableCode: true, - noUnusedParameters: false, - noImplicitAny: false, - noImplicitThis: false, - noEmitOnError: false - }; -} - -/** - * Helper function that creates a gulp task function that opens files in a - * directory that match a certain glob pattern, transpiles them, and writes them - * to an output directory. - * @param {Object} globs - * @param {string=} globs.transpile The glob pattern for files to transpile. - * Defaults to match all *.ts files in baseDir (incl. subdirectories). - * @param {string=} globs.copy The glob pattern for files to transpile. - * Defaults to match all but *.ts files in baseDir (incl. subdirectories). - * @return A gulp task function. - */ -function makeCompileFn(globs) { - const transpileGlob = globs.transpile || `${srcDir}/**/*.ts`; - const copyGlob = globs.copy || '!(**/*)'; - return () => { - const tsProject = typescript.createProject(tsconfigPath, tsDevOptions)(); - const data = gulp.src(transpileGlob, { base: jsCoreDir }) - .pipe(sourcemaps.init()) - .pipe(tsProject) - .on('error', onError); - const dts = data.dts; - const js = data.js; - const jsmap = js.pipe(sourcemaps.write('.', { - includeContent: false, - sourceRoot: '..' - })); - const copy = gulp.src(copyGlob, { base: jsCoreDir }); - return merge2([ - js.pipe(gulp.dest(`${outDir}`)), - dts.pipe(gulp.dest(`${outDir}/types`)), - jsmap.pipe(gulp.dest(`${outDir}`)), - copy.pipe(gulp.dest(`${outDir}`)) - ]); - }; -} - -gulp.task('js.core.install', 'Install native core dependencies', () => { - return execa('npm', ['install', '--unsafe-perm'], {cwd: jsCoreDir, stdio: 'inherit'}); -}); - -/** - * Runs tslint on files in src/, with linting rules defined in tslint.json. - */ -gulp.task('js.core.lint', 'Emits linting errors found in src/ and test/.', () => { - const program = require('tslint').Linter.createProgram(tsconfigPath); - gulp.src([`${srcDir}/**/*.ts`, `${testDir}/**/*.ts`]) - .pipe(tslint({ - configuration: tslintPath, - formatter: 'codeFrame', - program - })) - .pipe(tslint.report()) - .on('warning', onError); -}); - -gulp.task('js.core.clean', 'Deletes transpiled code.', () => { - return del(outDir); -}); - -gulp.task('js.core.clean.all', 'Deletes all files added by targets', - ['js.core.clean']); - -/** - * Transpiles TypeScript files in src/ to JavaScript according to the settings - * found in tsconfig.json. - * Currently, all errors are emitted twice. This is being tracked here: - * https://github.com/ivogabe/gulp-typescript/issues/438 - */ -gulp.task('js.core.compile', 'Transpiles src/.', - makeCompileFn({ transpile: [`${srcDir}/**/*.ts`] })); - -/** - * Transpiles TypeScript files in both src/ and test/. - */ -gulp.task('js.core.test.compile', 'After dep tasks, transpiles test/.', ['js.core.compile'], - makeCompileFn({ transpile: [`${testDir}/**/*.ts`], copy: `${testDir}/**/!(*.ts)` })); - -/** - * Transpiles src/ and test/, and then runs all tests. - */ -gulp.task('js.core.test', 'After dep tasks, runs all tests.', - ['js.core.test.compile'], () => { - return gulp.src(`${outDir}/test/**/*.js`) - .pipe(mocha({reporter: 'mocha-jenkins-reporter'})); - } - ); - -/** - * Transpiles individual files, specified by the --file flag. - */ -gulp.task('js.core.compile.single', 'Transpiles individual files specified by --file.', - makeCompileFn({ - transpile: files.map(f => path.relative('.', f)) - }) - ); - -/** - * Run individual tests, specified by their pre-transpiled source path (as - * supplied through the '--file' flag). This is intended to be used as part of a - * VS Code "Gulp task" launch configuration; setting the "args" field to - * ["test.single", "--file", "${file}"] makes it possible for one to debug the - * currently open TS mocha test file in one step. - */ -gulp.task('js.core.test.single', 'After dep tasks, runs individual files specified ' + - 'by --file.', ['js.core.compile', 'js.core.compile.single'], () => { - // util.env contains CLI arguments for the gulp task. - // Determine the path to the transpiled version of this TS file. - const getTranspiledPath = (file) => { - const dir = path.dirname(path.relative(jsCoreDir, file)); - const basename = path.basename(file, '.ts'); - const result = `${outDir}/${dir}/${basename}.js`; - console.log(result); - return result; - }; - // Construct an instance of Mocha's runner API and feed it the path to the - // transpiled source. - return gulp.src(files.map(getTranspiledPath)) - .pipe(through.obj((file, enc, cb) => { - // Construct a new Mocha runner instance. - const Mocha = require('mocha'); - const runner = new Mocha(); - // Add the path to the test file to debug. - runner.addFile(file.path); - // Run the test suite. - runner.run((failures) => { - if (failures > 0) { - cb(new Error(`Mocha: ${failures} failures in ${file.path}]`)); - } else { - cb(null); - } - }); - })); - } - ); diff --git a/packages/grpc-js-core/gulpfile.ts b/packages/grpc-js-core/gulpfile.ts new file mode 100644 index 000000000..d309f6886 --- /dev/null +++ b/packages/grpc-js-core/gulpfile.ts @@ -0,0 +1,76 @@ +/* + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as _gulp from 'gulp'; +import * as help from 'gulp-help'; + +import * as fs from 'fs'; +import * as mocha from 'gulp-mocha'; +import * as path from 'path'; +import * as execa from 'execa'; +import * as pify from 'pify'; +import { ncp } from 'ncp'; + +// gulp-help monkeypatches tasks to have an additional description parameter +const gulp = help(_gulp); + +const ncpP = pify(ncp); + +Error.stackTraceLimit = Infinity; + +const jsCoreDir = __dirname; +const tslintPath = path.resolve(jsCoreDir, 'node_modules/google-ts-style/tslint.json'); +const tsconfigPath = path.resolve(jsCoreDir, 'tsconfig.json'); +const outDir = path.resolve(jsCoreDir, 'build'); +const srcDir = path.resolve(jsCoreDir, 'src'); +const testDir = path.resolve(jsCoreDir, 'test'); + +const execNpmVerb = (verb: string, ...args: string[]) => + execa('npm', [verb, ...args], {cwd: jsCoreDir, stdio: 'inherit'}); +const execNpmCommand = execNpmVerb.bind(null, 'run'); + +gulp.task('install', 'Install native core dependencies', () => + execNpmVerb('install', '--unsafe-perm')); + +/** + * Runs tslint on files in src/, with linting rules defined in tslint.json. + */ +gulp.task('lint', 'Emits linting errors found in src/ and test/.', () => + execNpmCommand('check')); + +gulp.task('clean', 'Deletes transpiled code.', ['install'], + () => execNpmCommand('clean')); + +gulp.task('clean.all', 'Deletes all files added by targets', ['clean']); + +/** + * Transpiles TypeScript files in src/ to JavaScript according to the settings + * found in tsconfig.json. + */ +gulp.task('compile', 'Transpiles src/.', () => execNpmCommand('compile')); + +gulp.task('copy-test-fixtures', 'Copy test fixtures.', () => { + return ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`); +}); + +/** + * Transpiles src/ and test/, and then runs all tests. + */ +gulp.task('test', 'Runs all tests.', ['copy-test-fixtures'], () => { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter'})); +}); diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 6c8b2327d..d5fdd46c7 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -11,14 +11,15 @@ "author": { "name": "Google Inc." }, - "types": "src/index.ts", + "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { "@types/lodash": "^4.14.77", "@types/mocha": "^2.2.43", - "@types/node": "^8.0.34", + "@types/node": "^8.0.55", "clang-format": "^1.0.55", - "google-ts-style": "^0.2.0" + "gts": "^0.5.1", + "typescript": "^2.6.1" }, "contributors": [ { @@ -28,12 +29,16 @@ "_id": "@grpc/js-core@0.1.0", "scripts": { "build": "npm run compile", - "clean": "gulp clean", - "compile": "gulp js.core.compile", + "clean": "gts clean", + "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "lint": "tslint -c node_modules/google-ts-style/tslint.json -p . -t codeFrame --type-check", - "prepare": "npm run build", - "test": "gulp test" + "prepare": "npm run compile", + "test": "gulp test", + "check": "gts check", + "fix": "gts fix", + "pretest": "npm run compile", + "posttest": "npm run check" }, "dependencies": { "lodash": "^4.17.4" diff --git a/packages/grpc-js-core/tsconfig.json b/packages/grpc-js-core/tsconfig.json index 62024719e..c47ad1de0 100644 --- a/packages/grpc-js-core/tsconfig.json +++ b/packages/grpc-js-core/tsconfig.json @@ -1,13 +1,13 @@ { - "extends": "./node_modules/google-ts-style/tsconfig-google.json", + "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { - "lib": [ "es6" ], - "typeRoots": [ - "node_modules/h2-types", "node_modules/@types" - ] + "rootDir": ".", + "outDir": "build" }, "include": [ + "src/*.ts", "src/**/*.ts", + "test/*.ts", "test/**/*.ts" ], "exclude": [ diff --git a/packages/grpc-js/gulpfile.js b/packages/grpc-js/gulpfile.ts similarity index 65% rename from packages/grpc-js/gulpfile.js rename to packages/grpc-js/gulpfile.ts index d57c396fe..7e09725c2 100644 --- a/packages/grpc-js/gulpfile.js +++ b/packages/grpc-js/gulpfile.ts @@ -28,19 +28,26 @@ const linkSync = require('../../util').linkSync; const jsDir = __dirname; -gulp.task('js.clean.links', 'Delete npm links', () => { +const execNpmVerb = (verb: string, ...args: string[]) => + execa('npm', [verb, ...args], {cwd: jsDir, stdio: 'inherit'}); +const execNpmCommand = execNpmVerb.bind(null, 'run'); + +gulp.task('clean.links', 'Delete npm links', () => { return del([path.resolve(jsDir, 'node_modules/@grpc/js-core'), path.resolve(jsDir, 'node_modules/@grpc/surface')]); }); -gulp.task('js.clean.all', 'Delete all files created by tasks', - ['js.clean.links']); +gulp.task('clean.all', 'Delete all files created by tasks', ['clean.links']); -gulp.task('js.install', 'Install dependencies', () => { - return execa('npm', ['install', '--unsafe-perm'], {cwd: jsDir, stdio: 'inherit'}); -}); +/** + * Transpiles TypeScript files in src/ to JavaScript according to the settings + * found in tsconfig.json. + */ +gulp.task('compile', 'Transpiles src/.', () => execNpmCommand('compile')); + +gulp.task('install', 'Install dependencies', () => execNpmVerb('install')); -gulp.task('js.link.add', 'Link local copies of dependencies', () => { +gulp.task('link.add', 'Link local copies of dependencies', () => { linkSync(jsDir, './node_modules/@grpc/js-core', '../grpc-js-core'); linkSync(jsDir, './node_modules/@grpc/surface', '../grpc-surface'); }); diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9aa9ca048..1dbddbb06 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -2,9 +2,16 @@ "name": "@grpc/js", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "build/src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "compile": "tsc -p .", + "test": "echo \"Error: no test specified\" && exit 1", + "check": "gts check", + "clean": "gts clean", + "fix": "gts fix", + "prepare": "npm run compile", + "pretest": "npm run compile", + "posttest": "npm run check" }, "repository": { "type": "git", @@ -19,5 +26,9 @@ "dependencies": { "@grpc/js-core": "^0.1.0", "@grpc/surface": "^0.1.0" + }, + "devDependencies": { + "gts": "^0.5.1", + "typescript": "^2.6.1" } } diff --git a/packages/grpc-js/index.js b/packages/grpc-js/src/index.ts similarity index 100% rename from packages/grpc-js/index.js rename to packages/grpc-js/src/index.ts diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json new file mode 100644 index 000000000..c47ad1de0 --- /dev/null +++ b/packages/grpc-js/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/*.ts", + "src/**/*.ts", + "test/*.ts", + "test/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/packages/grpc-native-core/gulpfile.js b/packages/grpc-native-core/gulpfile.js index ecbd1de00..71a0b0ba7 100644 --- a/packages/grpc-native-core/gulpfile.js +++ b/packages/grpc-native-core/gulpfile.js @@ -35,20 +35,20 @@ const testDir = path.resolve(nativeCoreDir, 'test'); const pkg = require('./package'); const jshintConfig = pkg.jshintConfig; -gulp.task('native.core.clean', 'Delete generated files', () => { +gulp.task('clean', 'Delete generated files', () => { return del([path.resolve(nativeCoreDir, 'build'), path.resolve(nativeCoreDir, 'ext/node')]); }); -gulp.task('native.core.clean.all', 'Delete all files created by tasks', - ['native.core.clean']); +gulp.task('clean.all', 'Delete all files created by tasks', + ['clean']); -gulp.task('native.core.install', 'Install native core dependencies', () => { +gulp.task('install', 'Install native core dependencies', () => { return execa('npm', ['install', '--build-from-source', '--unsafe-perm'], {cwd: nativeCoreDir, stdio: 'inherit'}); }); -gulp.task('native.core.install.windows', 'Install native core dependencies for MS Windows', () => { +gulp.task('install.windows', 'Install native core dependencies for MS Windows', () => { return execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}).catch(() => del(path.resolve(process.env.USERPROFILE, '.node-gyp', process.versions.node, 'include/node/openssl'), { force: true }).then(() => @@ -57,21 +57,21 @@ execa('npm', ['install', '--build-from-source'], )) }); -gulp.task('native.core.lint', 'Emits linting errors', () => { +gulp.task('lint', 'Emits linting errors', () => { return gulp.src([`${nativeCoreDir}/index.js`, `${srcDir}/*.js`, `${testDir}/*.js`]) .pipe(jshint(pkg.jshintConfig)) .pipe(jshint.reporter('default')); }); -gulp.task('native.core.build', 'Build native package', () => { +gulp.task('build', 'Build native package', () => { return execa('npm', ['run', 'build'], {cwd: nativeCoreDir, stdio: 'inherit'}); }); -gulp.task('native.core.test', 'Run all tests', ['native.core.build'], () => { +gulp.task('test', 'Run all tests', ['build'], () => { return gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); }); -gulp.task('native.core.doc.gen', 'Generate docs', (cb) => { +gulp.task('doc.gen', 'Generate docs', (cb) => { var config = require('./jsdoc_conf.json'); gulp.src([`${nativeCoreDir}/README.md`, `${nativeCoreDir}/index.js`, `${srcDir}/*.js`], {read: false}) .pipe(jsdoc(config, cb)); diff --git a/packages/grpc-native/gulpfile.js b/packages/grpc-native/gulpfile.js index fb9de4975..37fd6af92 100644 --- a/packages/grpc-native/gulpfile.js +++ b/packages/grpc-native/gulpfile.js @@ -28,19 +28,19 @@ const linkSync = require('../../util').linkSync; const nativeDir = __dirname; -gulp.task('native.clean.links', 'Delete npm links', () => { +gulp.task('clean.links', 'Delete npm links', () => { return del([path.resolve(nativeDir, 'node_modules/grpc'), path.resolve(nativeDir, 'node_modules/@grpc/surface')]); }); -gulp.task('native.clean.all', 'Delete all files created by tasks', - ['native.clean.links']); +gulp.task('clean.all', 'Delete all files created by tasks', + ['clean.links']); -gulp.task('native.install', 'Install dependencies', () => { +gulp.task('install', 'Install dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: nativeDir, stdio: 'inherit'}); }); -gulp.task('native.link.add', 'Link local copies of dependencies', () => { +gulp.task('link.add', 'Link local copies of dependencies', () => { linkSync(nativeDir, './node_modules/grpc', '../grpc-native-core'); linkSync(nativeDir, './node_modules/@grpc/surface', '../grpc-surface'); }); diff --git a/packages/grpc-surface/gulpfile.js b/packages/grpc-surface/gulpfile.js index 5dfde6848..9089587ad 100644 --- a/packages/grpc-surface/gulpfile.js +++ b/packages/grpc-surface/gulpfile.js @@ -25,6 +25,6 @@ const execa = require('execa'); const surfaceDir = __dirname; -gulp.task('surface.install', 'Install surface dependencies', () => { +gulp.task('install', 'Install surface dependencies', () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: surfaceDir, stdio: 'inherit'}); }); diff --git a/test/gulpfile.js b/test/gulpfile.js index 1c70056e2..70e057962 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -29,13 +29,13 @@ const gulp = help(_gulp); const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); -gulp.task('internal.test.install', 'Install test dependencies', () => { +gulp.task('install', 'Install test dependencies', () => { return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); }); -gulp.task('internal.test.clean.all', 'Delete all files created by tasks', () => {}); +gulp.task('clean.all', 'Delete all files created by tasks', () => {}); -gulp.task('internal.test.test', 'Run API-level tests', () => { +gulp.task('test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream const apiTestGlob = `${apiTestDir}/*.js`; diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..dbc5c8989 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "lib": [ + "es2015" + ] + } +} From c2164913e2de5fdcb24b1d5b896eab4bce47a229 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Dec 2017 11:00:05 -0800 Subject: [PATCH 0049/1899] Add error code name to status error messages --- packages/grpc-native-core/src/client.js | 27 ++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 24af23b8a..519b8d79f 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -53,6 +53,21 @@ var Duplex = stream.Duplex; var util = require('util'); var version = require('../package.json').version; +/** + * Create an Error object from a status object + * @private + * @param {grpc~StatusObject} status The status object + * @return {Error} The resulting Error + */ +function createStatusError(status) { + let statusName = _.invert(constants.status)[status.code]; + let message = `${status.code} ${status.name}: ${status.details}`; + let error = new Error(message); + error.code = status.code; + error.details = status.details; + return error; +} + /** * Initial response metadata sent by the server when it starts processing the * call @@ -252,9 +267,7 @@ function _emitStatusIfDone() { if (status.code === constants.status.OK) { this.push(null); } else { - var error = new Error(status.details); - error.code = status.code; - error.metadata = status.metadata; + var error = createStatusError(status); this.emit('error', error); } this.emit('status', status); @@ -551,9 +564,7 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, } } if (status.code !== constants.status.OK) { - error = new Error(status.details); - error.code = status.code; - error.metadata = status.metadata; + error = new createStatusError(status); args.callback(error); } else { args.callback(null, deserialized); @@ -634,9 +645,7 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, } } if (status.code !== constants.status.OK) { - error = new Error(response.status.details); - error.code = status.code; - error.metadata = status.metadata; + error = createStatusError(status); args.callback(error); } else { args.callback(null, deserialized); From 7edc14bb1a326ea4b31615555a4b8da591d3de64 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Dec 2017 11:35:47 -0800 Subject: [PATCH 0050/1899] Attach the proper fields to the Error object --- packages/grpc-native-core/src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 519b8d79f..1e873d2cd 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -64,7 +64,7 @@ function createStatusError(status) { let message = `${status.code} ${status.name}: ${status.details}`; let error = new Error(message); error.code = status.code; - error.details = status.details; + error.metadata = status.metadata; return error; } From 98864a343bd6d1f340e90b9746e85fea8a2ac4bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Wed, 8 Nov 2017 15:16:39 +0100 Subject: [PATCH 0051/1899] Fix index.d.ts error: Type 'Message' is not generic. --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 0bb5a9f43..6eae5f58e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -66,7 +66,7 @@ declare module "grpc" { * - Anything else becomes the relevant reflection object that ProtoBuf.js would create */ export interface GrpcObject { - [name: string]: GrpcObject | typeof Client | Message; + [name: string]: GrpcObject | typeof Client | Message; } /** From b68e5dd73b342c3db4178043da7c66dc1a56f983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Wed, 8 Nov 2017 15:21:06 +0100 Subject: [PATCH 0052/1899] Add generic parameters in index.d.ts to some functions and types --- packages/grpc-native-core/index.d.ts | 84 ++++++++++++++++------------ 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 6eae5f58e..4d90085fd 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1,5 +1,5 @@ declare module "grpc" { - import { Message, Service } from "protobufjs"; + import { Message, Service as ProtobufService } from "protobufjs"; import { Duplex, Readable, Writable } from "stream"; import { SecureContext } from "tls"; @@ -9,7 +9,7 @@ declare module "grpc" { * @param options Options to apply to the loaded file * @return The resulting gRPC object. */ - export function loadObject(value: object, options?: LoadObjectOptions): GrpcObject; + export function loadObject(value: object, options?: LoadObjectOptions): T; /** * Options for loading proto object as gRPC object @@ -76,7 +76,7 @@ declare module "grpc" { * @param options Options to apply to the loaded file * @return The resulting gRPC object */ - export function load(filename: Filename, format?: "proto" | "json", options?: LoadOptions): GrpcObject; + export function load(filename: Filename, format?: "proto" | "json", options?: LoadOptions): T; /** * A filename @@ -132,6 +132,8 @@ declare module "grpc" { */ export function setLogVerbosity(verbosity: logVerbosity): void; + export type Service = ProtobufService; + /** * Server object that stores request handlers and delegates incoming requests to those handlers */ @@ -193,7 +195,7 @@ declare module "grpc" { * @param implementation Map of method names to method implementation * for the provided service. */ - addService(service: Service, implementation: { [name: string]: handleCall }): void; + addService(service: Service, implementation: T): void; /** * Add a proto service to the server, with a corresponding implementation @@ -202,7 +204,7 @@ declare module "grpc" { * @param implementation Map of method names to method implementation * for the provided service. */ - addProtoService(service: Service | ServiceDefinition, implementation: { [name: string]: handleCall }): void; + addProtoService(service: Service | ServiceDefinition, implementation: T): void; /** * Binds the server to the given port, with SSL disabled if creds is an @@ -258,17 +260,21 @@ declare module "grpc" { responseDeserialize: deserialize; } - type handleCall = handleUnaryCall | handleClientStreamingCall | handleServerStreamingCall | handleBidiStreamingCall; + type handleCall = + handleUnaryCall | + handleClientStreamingCall | + handleServerStreamingCall | + handleBidiStreamingCall; /** * User-provided method to handle unary requests on a server */ - type handleUnaryCall = (call: ServerUnaryCall, callback: sendUnaryData) => void; + type handleUnaryCall = (call: ServerUnaryCall, callback: sendUnaryData) => void; /** * An EventEmitter. Used for unary calls. */ - export class ServerUnaryCall { + export class ServerUnaryCall { /** * Indicates if the call has been cancelled */ @@ -282,7 +288,7 @@ declare module "grpc" { /** * The request message from the client */ - request: any; + request: T; private constructor(); @@ -302,13 +308,13 @@ declare module "grpc" { /** * User provided method to handle client streaming methods on the server. */ - type handleClientStreamingCall = (call: ServerReadableStream, callback: sendUnaryData) => void; + type handleClientStreamingCall = (call: ServerReadableStream, callback: sendUnaryData) => void; /** * A stream that the server can read from. Used for calls that are streaming * from the client side. */ - export class ServerReadableStream extends Readable { + export class ServerReadableStream extends Readable { /** * Indicates if the call has been cancelled */ @@ -337,13 +343,13 @@ declare module "grpc" { /** * User provided method to handle server streaming methods on the server. */ - type handleServerStreamingCall = (call: ServerWriteableStream) => void; + type handleServerStreamingCall = (call: ServerWriteableStream) => void; /** * A stream that the server can write to. Used for calls that are streaming * from the server side. */ - export class ServerWriteableStream extends Writable { + export class ServerWriteableStream extends Writable { /** * Indicates if the call has been cancelled */ @@ -357,7 +363,7 @@ declare module "grpc" { /** * The request message from the client */ - request: any; + request: T; private constructor(); @@ -377,13 +383,13 @@ declare module "grpc" { /** * User provided method to handle bidirectional streaming calls on the server. */ - type handleBidiStreamingCall = (call: ServerDuplexStream) => void; + type handleBidiStreamingCall = (call: ServerDuplexStream) => void; /** * A stream that the server can read from or write to. Used for calls * with duplex streaming. */ - export class ServerDuplexStream extends Duplex { + export class ServerDuplexStream extends Duplex { private constructor(); /** @@ -417,7 +423,7 @@ declare module "grpc" { * Callback function passed to server handlers that handle methods with * unary responses. */ - type sendUnaryData = (error: ServiceError | null, value: any, trailer?: Metadata, flags?: number) => void; + type sendUnaryData = (error: ServiceError | null, value: T, trailer?: Metadata, flags?: number) => void; /** * A class for storing metadata. Keys are normalized to lowercase ASCII. @@ -941,15 +947,15 @@ declare module "grpc" { * @param callback The callback to for when the response is received * @return An event emitter for stream related events */ - makeUnaryRequest( + makeUnaryRequest( method: string, serialize: serialize, deserialize: deserialize, - argument: any | null, + argument: T | null, metadata: Metadata | null, options: CallOptions | null, - callback: requestCallback, - ): ClientUnaryCall; + callback: requestCallback, + ): ClientUnaryCall; /** * Make a client stream request to the given method, using the given serialize @@ -962,14 +968,14 @@ declare module "grpc" { * @param callback The callback to for when the response is received * @return An event emitter for stream related events */ - makeClientStreamRequest( + makeClientStreamRequest( method: string, serialize: serialize, deserialize: deserialize, metadata: Metadata | null, options: CallOptions | null, - callback: requestCallback, - ): ClientWritableStream; + callback: requestCallback, + ): ClientWritableStream; /** * Make a server stream request to the given method, with the given serialize @@ -983,14 +989,14 @@ declare module "grpc" { * @param options Options map * @return An event emitter for stream related events */ - makeServerStreamRequest( + makeServerStreamRequest( method: string, serialize: serialize, deserialize: deserialize, - argument: any, + argument: R, metadata?: Metadata | null, options?: CallOptions | null, - ): ClientReadableStream; + ): ClientReadableStream; /** * Make a bidirectional stream request with this method on the given channel. @@ -1003,13 +1009,13 @@ declare module "grpc" { * @param options Options map * @return An event emitter for stream related events */ - makeBidiStreamRequest( + makeBidiStreamRequest( method: string, serialize: serialize, deserialize: deserialize, metadata?: Metadata | null, options?: CallOptions | null, - ): ClientDuplexStream; + ): ClientDuplexStream; /** * Close this client. @@ -1081,12 +1087,16 @@ declare module "grpc" { /** * Any client call type */ - type Call = ClientUnaryCall | ClientReadableStream | ClientWritableStream | ClientDuplexStream; + type Call = + ClientUnaryCall | + ClientReadableStream | + ClientWritableStream | + ClientDuplexStream; /** * An EventEmitter. Used for unary calls. */ - export class ClientUnaryCall { + export class ClientUnaryCall { private constructor(); /** @@ -1106,7 +1116,7 @@ declare module "grpc" { * A stream that the client can read from. Used for calls that are streaming * from the server side. */ - export class ClientReadableStream extends Readable { + export class ClientReadableStream extends Readable { private constructor(); /** @@ -1126,7 +1136,7 @@ declare module "grpc" { * A stream that the client can write to. Used for calls that are streaming from * the client side. */ - export class ClientWritableStream extends Writable { + export class ClientWritableStream extends Writable { private constructor(); /** @@ -1138,7 +1148,7 @@ declare module "grpc" { * @param callback Callback for when this chunk of data is flushed * @return As defined for [Writable]{@link external:Writable} */ - write(message: any, flags?: any&writeFlags, callback?: Function): boolean; + write(message: W, flags?: any&writeFlags, callback?: Function): boolean; /** * Cancel the ongoing call. Results in the call ending with a CANCELLED status, @@ -1157,7 +1167,7 @@ declare module "grpc" { * A stream that the client can read from or write to. Used for calls with * duplex streaming. */ - export class ClientDuplexStream extends Duplex { + export class ClientDuplexStream extends Duplex { private constructor(); /** @@ -1169,7 +1179,7 @@ declare module "grpc" { * @param callback Callback for when this chunk of data is flushed * @return As defined for [Writable]{@link external:Writable} */ - write(message: any, flags?: any&writeFlags, callback?: Function): boolean; + write(message: W, flags?: any&writeFlags, callback?: Function): boolean; /** * Cancel the ongoing call. Results in the call ending with a CANCELLED status, @@ -1189,7 +1199,7 @@ declare module "grpc" { * @param error The error, if the call failed * @param value The response value, if the call succeeded */ - export type requestCallback = (error: ServiceError | null, value: any) => void; + export type requestCallback = (error: ServiceError | null, value: T) => void; /** * Return the underlying channel object for the specified client From 71bee4ab418efca772beae3565a1a22ea65b0681 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Wed, 8 Nov 2017 20:51:19 +0100 Subject: [PATCH 0053/1899] Fix the definition of Service Type aliases will not give the correct inferred type in Server.addService() so use an interface here. --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 4d90085fd..edf66167e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -132,7 +132,7 @@ declare module "grpc" { */ export function setLogVerbosity(verbosity: logVerbosity): void; - export type Service = ProtobufService; + export interface Service extends ProtobufService {} /** * Server object that stores request handlers and delegates incoming requests to those handlers From 7d5547b2dd119c4e3e6cbe184ff91a1a6b31f125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 12:54:11 +0100 Subject: [PATCH 0054/1899] Drop Service in favour of ServiceDefinition --- packages/grpc-native-core/index.d.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index edf66167e..abde90cf0 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -132,8 +132,6 @@ declare module "grpc" { */ export function setLogVerbosity(verbosity: logVerbosity): void; - export interface Service extends ProtobufService {} - /** * Server object that stores request handlers and delegates incoming requests to those handlers */ @@ -195,7 +193,10 @@ declare module "grpc" { * @param implementation Map of method names to method implementation * for the provided service. */ - addService(service: Service, implementation: T): void; + addService( + service: ServiceDefinition, + implementation: ImplementationType + ): void; /** * Add a proto service to the server, with a corresponding implementation @@ -204,7 +205,10 @@ declare module "grpc" { * @param implementation Map of method names to method implementation * for the provided service. */ - addProtoService(service: Service | ServiceDefinition, implementation: T): void; + addProtoService( + service: ServiceDefinition, + implementation: ImplementationType + ): void; /** * Binds the server to the given port, with SSL disabled if creds is an @@ -218,11 +222,16 @@ declare module "grpc" { bind(port: string, creds: ServerCredentials): number; } + /** + * A type that servers as a default for an untyped service. + */ + type UntypedServiceImplementation = { [name: string]: handleCall }; + /** * An object that completely defines a service. * @typedef {Object.} grpc~ServiceDefinition */ - export interface ServiceDefinition { + export interface ServiceDefinition { [s: string]: MethodDefinition; } @@ -904,7 +913,7 @@ declare module "grpc" { * has the same arguments as that constructor. */ export function makeGenericClientConstructor( - methods: ServiceDefinition, + methods: ServiceDefinition, serviceName: string, classOptions: GenericClientOptions, ): typeof Client; From 55eec06946f589e450e04e50442afcb6bc12f6c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 12:56:38 +0100 Subject: [PATCH 0055/1899] Make MethodDefinition parametric with request and response types --- packages/grpc-native-core/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index abde90cf0..798f90880 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -232,13 +232,13 @@ declare module "grpc" { * @typedef {Object.} grpc~ServiceDefinition */ export interface ServiceDefinition { - [s: string]: MethodDefinition; + [s: string]: MethodDefinition; } /** * An object that completely defines a service method signature. */ - export interface MethodDefinition { + export interface MethodDefinition { /** * The method's URL path */ From 0cdc2855c2ce5f1bd511467bae94aa82d6938c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 13:06:30 +0100 Subject: [PATCH 0056/1899] Make types 'serialize' and 'deserialize' parametric with their serialization types --- packages/grpc-native-core/index.d.ts | 60 +++++++++++++++------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 798f90880..fbc390b1a 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -168,7 +168,13 @@ declare module "grpc" { * @return True if the handler was set. False if a handler was already * set for that name. */ - register(name: string, handler: handleCall, serialize: serialize, deserialize: deserialize, type: string): boolean; + register( + name: string, + handler: handleCall, + serialize: serialize, + deserialize: deserialize, + type: string + ): boolean; /** * Gracefully shuts down the server. The server will stop receiving new calls, @@ -254,19 +260,19 @@ declare module "grpc" { /** * Serialization function for request values */ - requestSerialize: serialize; + requestSerialize: serialize; /** * Serialization function for response values */ - responseSerialize: serialize; + responseSerialize: serialize; /** * Deserialization function for request data */ - requestDeserialize: deserialize; + requestDeserialize: deserialize; /** * Deserialization function for repsonse data */ - responseDeserialize: deserialize; + responseDeserialize: deserialize; } type handleCall = @@ -419,14 +425,14 @@ declare module "grpc" { * @param data The byte sequence to deserialize * @return The data deserialized as a value */ - type deserialize = (data: Buffer) => any; + type deserialize = (data: Buffer) => T; /** * A serialization function * @param value The value to serialize * @return The value serialized as a byte sequence */ - type serialize = (value: any) => Buffer; + type serialize = (value: T) => Buffer; /** * Callback function passed to server handlers that handle methods with @@ -956,15 +962,15 @@ declare module "grpc" { * @param callback The callback to for when the response is received * @return An event emitter for stream related events */ - makeUnaryRequest( + makeUnaryRequest( method: string, - serialize: serialize, - deserialize: deserialize, - argument: T | null, + serialize: serialize, + deserialize: deserialize, + argument: RequestType | null, metadata: Metadata | null, options: CallOptions | null, - callback: requestCallback, - ): ClientUnaryCall; + callback: requestCallback, + ): ClientUnaryCall; /** * Make a client stream request to the given method, using the given serialize @@ -977,14 +983,14 @@ declare module "grpc" { * @param callback The callback to for when the response is received * @return An event emitter for stream related events */ - makeClientStreamRequest( + makeClientStreamRequest( method: string, - serialize: serialize, - deserialize: deserialize, + serialize: serialize, + deserialize: deserialize, metadata: Metadata | null, options: CallOptions | null, - callback: requestCallback, - ): ClientWritableStream; + callback: requestCallback, + ): ClientWritableStream; /** * Make a server stream request to the given method, with the given serialize @@ -998,14 +1004,14 @@ declare module "grpc" { * @param options Options map * @return An event emitter for stream related events */ - makeServerStreamRequest( + makeServerStreamRequest( method: string, - serialize: serialize, - deserialize: deserialize, - argument: R, + serialize: serialize, + deserialize: deserialize, + argument: RequestType, metadata?: Metadata | null, options?: CallOptions | null, - ): ClientReadableStream; + ): ClientReadableStream; /** * Make a bidirectional stream request with this method on the given channel. @@ -1018,13 +1024,13 @@ declare module "grpc" { * @param options Options map * @return An event emitter for stream related events */ - makeBidiStreamRequest( + makeBidiStreamRequest( method: string, - serialize: serialize, - deserialize: deserialize, + serialize: serialize, + deserialize: deserialize, metadata?: Metadata | null, options?: CallOptions | null, - ): ClientDuplexStream; + ): ClientDuplexStream; /** * Close this client. From d20bf6f49e68684e45be1d5b1955174bc4941f33 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 13:16:35 +0100 Subject: [PATCH 0057/1899] Make type 'handleCall' and related types take a RequestType and ResponseType parameter --- packages/grpc-native-core/index.d.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index fbc390b1a..ce7b4161d 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -170,7 +170,7 @@ declare module "grpc" { */ register( name: string, - handler: handleCall, + handler: handleCall, serialize: serialize, deserialize: deserialize, type: string @@ -275,16 +275,17 @@ declare module "grpc" { responseDeserialize: deserialize; } - type handleCall = - handleUnaryCall | - handleClientStreamingCall | - handleServerStreamingCall | - handleBidiStreamingCall; + type handleCall = + handleUnaryCall | + handleClientStreamingCall | + handleServerStreamingCall | + handleBidiStreamingCall; /** * User-provided method to handle unary requests on a server */ - type handleUnaryCall = (call: ServerUnaryCall, callback: sendUnaryData) => void; + type handleUnaryCall = + (call: ServerUnaryCall, callback: sendUnaryData) => void; /** * An EventEmitter. Used for unary calls. @@ -323,7 +324,8 @@ declare module "grpc" { /** * User provided method to handle client streaming methods on the server. */ - type handleClientStreamingCall = (call: ServerReadableStream, callback: sendUnaryData) => void; + type handleClientStreamingCall = + (call: ServerReadableStream, callback: sendUnaryData) => void; /** * A stream that the server can read from. Used for calls that are streaming @@ -358,7 +360,8 @@ declare module "grpc" { /** * User provided method to handle server streaming methods on the server. */ - type handleServerStreamingCall = (call: ServerWriteableStream) => void; + type handleServerStreamingCall = + (call: ServerWriteableStream) => void; /** * A stream that the server can write to. Used for calls that are streaming From 680d60584a433d8e192194956be4ab292537dc21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 13:22:08 +0100 Subject: [PATCH 0058/1899] Rename all type parameters related to requests/responses 'RequestType' and 'ResponseType' This improves clarity and consistency with the pure Js implementation. --- packages/grpc-native-core/index.d.ts | 29 +++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index ce7b4161d..4493f4b6d 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -290,7 +290,7 @@ declare module "grpc" { /** * An EventEmitter. Used for unary calls. */ - export class ServerUnaryCall { + export class ServerUnaryCall { /** * Indicates if the call has been cancelled */ @@ -304,7 +304,7 @@ declare module "grpc" { /** * The request message from the client */ - request: T; + request: RequestType; private constructor(); @@ -367,7 +367,7 @@ declare module "grpc" { * A stream that the server can write to. Used for calls that are streaming * from the server side. */ - export class ServerWriteableStream extends Writable { + export class ServerWriteableStream extends Writable { /** * Indicates if the call has been cancelled */ @@ -381,7 +381,7 @@ declare module "grpc" { /** * The request message from the client */ - request: T; + request: RequestType; private constructor(); @@ -401,13 +401,14 @@ declare module "grpc" { /** * User provided method to handle bidirectional streaming calls on the server. */ - type handleBidiStreamingCall = (call: ServerDuplexStream) => void; + type handleBidiStreamingCall = + (call: ServerDuplexStream) => void; /** * A stream that the server can read from or write to. Used for calls * with duplex streaming. */ - export class ServerDuplexStream extends Duplex { + export class ServerDuplexStream extends Duplex { private constructor(); /** @@ -441,7 +442,8 @@ declare module "grpc" { * Callback function passed to server handlers that handle methods with * unary responses. */ - type sendUnaryData = (error: ServiceError | null, value: T, trailer?: Metadata, flags?: number) => void; + type sendUnaryData = + (error: ServiceError | null, value: ResponseType, trailer?: Metadata, flags?: number) => void; /** * A class for storing metadata. Keys are normalized to lowercase ASCII. @@ -1134,7 +1136,7 @@ declare module "grpc" { * A stream that the client can read from. Used for calls that are streaming * from the server side. */ - export class ClientReadableStream extends Readable { + export class ClientReadableStream extends Readable { private constructor(); /** @@ -1154,7 +1156,7 @@ declare module "grpc" { * A stream that the client can write to. Used for calls that are streaming from * the client side. */ - export class ClientWritableStream extends Writable { + export class ClientWritableStream extends Writable { private constructor(); /** @@ -1166,7 +1168,7 @@ declare module "grpc" { * @param callback Callback for when this chunk of data is flushed * @return As defined for [Writable]{@link external:Writable} */ - write(message: W, flags?: any&writeFlags, callback?: Function): boolean; + write(message: RequestType, flags?: any&writeFlags, callback?: Function): boolean; /** * Cancel the ongoing call. Results in the call ending with a CANCELLED status, @@ -1185,7 +1187,7 @@ declare module "grpc" { * A stream that the client can read from or write to. Used for calls with * duplex streaming. */ - export class ClientDuplexStream extends Duplex { + export class ClientDuplexStream extends Duplex { private constructor(); /** @@ -1197,7 +1199,7 @@ declare module "grpc" { * @param callback Callback for when this chunk of data is flushed * @return As defined for [Writable]{@link external:Writable} */ - write(message: W, flags?: any&writeFlags, callback?: Function): boolean; + write(message: RequestType, flags?: any&writeFlags, callback?: Function): boolean; /** * Cancel the ongoing call. Results in the call ending with a CANCELLED status, @@ -1217,7 +1219,8 @@ declare module "grpc" { * @param error The error, if the call failed * @param value The response value, if the call succeeded */ - export type requestCallback = (error: ServiceError | null, value: T) => void; + export type requestCallback = + (error: ServiceError | null, value: ResponseType) => void; /** * Return the underlying channel object for the specified client From bf330585d0821e3575af836c9207831601b0afd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 13:24:09 +0100 Subject: [PATCH 0059/1899] Make values in callbacks nullable Values are null in case of errors. --- packages/grpc-native-core/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 4493f4b6d..f548a5f0e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -443,7 +443,7 @@ declare module "grpc" { * unary responses. */ type sendUnaryData = - (error: ServiceError | null, value: ResponseType, trailer?: Metadata, flags?: number) => void; + (error: ServiceError | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void; /** * A class for storing metadata. Keys are normalized to lowercase ASCII. @@ -1220,7 +1220,7 @@ declare module "grpc" { * @param value The response value, if the call succeeded */ export type requestCallback = - (error: ServiceError | null, value: ResponseType) => void; + (error: ServiceError | null, value: ResponseType | null) => void; /** * Return the underlying channel object for the specified client From 9b6537545afc9feb8f6adb33e5d09414db621edf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 9 Nov 2017 13:25:54 +0100 Subject: [PATCH 0060/1899] Remove type parameter from ClientUnaryCall The type parameter is currently not used and also matches the pure Js implementation this way. --- packages/grpc-native-core/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index f548a5f0e..2e844256e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1108,7 +1108,7 @@ declare module "grpc" { * Any client call type */ type Call = - ClientUnaryCall | + ClientUnaryCall | ClientReadableStream | ClientWritableStream | ClientDuplexStream; @@ -1116,7 +1116,7 @@ declare module "grpc" { /** * An EventEmitter. Used for unary calls. */ - export class ClientUnaryCall { + export class ClientUnaryCall { private constructor(); /** From 4ab448e40f0e26008f4a073e7cbb21ed07302492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Tue, 5 Dec 2017 11:29:27 +0100 Subject: [PATCH 0061/1899] Fix typos and whitespace --- packages/grpc-native-core/index.d.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 2e844256e..5431d9c57 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -256,8 +256,8 @@ declare module "grpc" { /** * Indicates whether the method returns a stream of responses */ - responseStream: boolean; - /** + responseStream: boolean; + /** * Serialization function for request values */ requestSerialize: serialize; @@ -777,7 +777,7 @@ declare module "grpc" { * This module contains factory methods for two different credential types: * CallCredentials and ChannelCredentials. ChannelCredentials are things like * SSL credentials that can be used to secure a connection, and are used to - * construct a Client object. CallCredentials genrally modify metadata, so they + * construct a Client object. CallCredentials generally modify metadata, so they * can be attached to an individual method call. * * CallCredentials can be composed with other CallCredentials to create @@ -1233,7 +1233,7 @@ declare module "grpc" { /** * Wait for the client to be ready. The callback will be called when the * client has successfully connected to the server, and it will be called - * with an error if the attempt to connect to the server has unrecoverablly + * with an error if the attempt to connect to the server has unrecoverably * failed or if the deadline expires. This function will make the channel * start connecting if it has not already done so. * @see grpc.Client#waitForReady From 6d21f12cfe18f6ffcfba000f8e9ee0f2eff04bb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Tue, 12 Dec 2017 11:38:09 +0100 Subject: [PATCH 0062/1899] Export UntypedServiceImplementation --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 5431d9c57..c35b63fa5 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -231,7 +231,7 @@ declare module "grpc" { /** * A type that servers as a default for an untyped service. */ - type UntypedServiceImplementation = { [name: string]: handleCall }; + export type UntypedServiceImplementation = { [name: string]: handleCall }; /** * An object that completely defines a service. From 3692053a4e05995cbd20e5ac9533f46821333933 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Thu, 14 Dec 2017 11:40:11 +0100 Subject: [PATCH 0063/1899] Add missing properties to ServerDuplexStream - cancelled: boolean; - metadata: Metadata; --- packages/grpc-native-core/index.d.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index c35b63fa5..65d5aee7e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -409,6 +409,16 @@ declare module "grpc" { * with duplex streaming. */ export class ServerDuplexStream extends Duplex { + /** + * Indicates if the call has been cancelled + */ + cancelled: boolean; + + /** + * The request metadata from the client + */ + metadata: Metadata; + private constructor(); /** @@ -1220,7 +1230,7 @@ declare module "grpc" { * @param value The response value, if the call succeeded */ export type requestCallback = - (error: ServiceError | null, value: ResponseType | null) => void; + (error: ServiceError | null, value: ResponseType | undefined) => void; /** * Return the underlying channel object for the specified client From d060cea5e92a5c141c2981148c856deba7f703ed Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Fri, 15 Dec 2017 18:31:17 -0800 Subject: [PATCH 0064/1899] grpc-js-core: fixing credentials functions --- .../src/call-credentials-filter.ts | 2 +- .../grpc-js-core/src/channel-credentials.ts | 10 ++ packages/grpc-js-core/src/channel.ts | 94 +++++++++++-------- packages/grpc-js-core/src/client.ts | 2 +- packages/grpc-js-core/src/deadline-filter.ts | 32 +++---- 5 files changed, 81 insertions(+), 59 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index 678124592..4633ffe88 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -13,7 +13,7 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { async sendMetadata(metadata: Promise): Promise { // TODO(murgatroid99): pass real options to generateMetadata - let credsMetadata = this.credentials.generateMetadata.bind({}); + let credsMetadata = this.credentials.generateMetadata({}); let resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 0d87d5de1..419e3d17e 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -79,7 +79,14 @@ class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { } } +function verifyIsBufferOrNull(obj: any, friendlyName: string): void { + if (obj && !(obj instanceof Buffer)) { + throw new TypeError(`${friendlyName}, if provided, must be a Buffer.`); + } +} + export namespace ChannelCredentials { + /** * Return a new ChannelCredentials instance with a given set of credentials. * The resulting instance can be used to construct a Channel that communicates @@ -91,6 +98,9 @@ export namespace ChannelCredentials { export function createSsl( rootCerts?: Buffer|null, privateKey?: Buffer|null, certChain?: Buffer|null): ChannelCredentials { + verifyIsBufferOrNull(rootCerts, 'Root certificate'); + verifyIsBufferOrNull(privateKey, 'Private key'); + verifyIsBufferOrNull(certChain, 'Certificate chain'); if (privateKey && !certChain) { throw new Error( 'Private key must be given with accompanying certificate chain'); diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 5cdbf4075..9b28d8c1a 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -1,6 +1,6 @@ import {EventEmitter} from 'events'; import * as http2 from 'http2'; -import {SecureContext} from 'tls'; +import {checkServerIdentity, SecureContext, PeerCertificate} from 'tls'; import * as url from 'url'; import {CallCredentials} from './call-credentials'; @@ -57,7 +57,7 @@ function uniformRandom(min:number, max: number) { export interface Channel extends EventEmitter { createStream(methodName: string, metadata: Metadata, options: CallOptions): CallStream; - connect(callback: () => void): void; + connect(): Promise; getConnectivityState(): ConnectivityState; close(): void; @@ -137,7 +137,19 @@ export class Http2Channel extends EventEmitter implements Channel { if (secureContext === null) { subChannel = http2.connect(this.authority); } else { - subChannel = http2.connect(this.authority, {secureContext}); + const connectionOptions: http2.SecureClientSessionOptions = { + secureContext, + } + // If provided, the value of grpc.ssl_target_name_override should be used + // to override the target hostname when checking server identity. + // This option is used for testing only. + if (this.options['grpc.ssl_target_name_override']) { + const sslTargetNameOverride = this.options['grpc.ssl_target_name_override'] as string; + connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + } + } + subChannel = http2.connect(this.authority, connectionOptions); } this.subChannel = subChannel; let now = new Date(); @@ -190,37 +202,35 @@ export class Http2Channel extends EventEmitter implements Channel { methodName: string, stream: Http2CallStream, metadata: Metadata) { let finalMetadata: Promise = stream.filterStack.sendMetadata(Promise.resolve(metadata)); - this.connect(() => { - finalMetadata.then( - (metadataValue) => { - let headers = metadataValue.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname; - headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; - headers[HTTP2_HEADER_METHOD] = 'POST'; - headers[HTTP2_HEADER_PATH] = methodName; - headers[HTTP2_HEADER_TE] = 'trailers'; - if (stream.getStatus() === null) { - if (this.connectivityState === ConnectivityState.READY) { - const session: http2.ClientHttp2Session = this.subChannel!; - // Prevent the HTTP/2 session from keeping the process alive. - // TODO(kjin): Monitor nodejs/node#17620, which adds unref - // directly to the Http2Session object. - session.socket.unref(); - stream.attachHttp2Stream(session.request(headers)); - } else { - /* In this case, we lost the connection while finalizing - * metadata. That should be very unusual */ - setImmediate(() => { - this.startHttp2Stream(methodName, stream, metadata); - }); - } - } - }, - (error) => { - stream.cancelWithStatus( - Status.UNKNOWN, 'Failed to generate metadata'); - }); - }); + Promise.all([finalMetadata, this.connect()]) + .then(([metadataValue]) => { + let headers = metadataValue.toHttp2Headers(); + headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname; + headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; + headers[HTTP2_HEADER_METHOD] = 'POST'; + headers[HTTP2_HEADER_PATH] = methodName; + headers[HTTP2_HEADER_TE] = 'trailers'; + if (stream.getStatus() === null) { + if (this.connectivityState === ConnectivityState.READY) { + const session: http2.ClientHttp2Session = this.subChannel!; + // Prevent the HTTP/2 session from keeping the process alive. + // TODO(kjin): Monitor nodejs/node#17620, which adds unref + // directly to the Http2Session object. + session.socket.unref(); + stream.attachHttp2Stream(session.request(headers)); + } else { + /* In this case, we lost the connection while finalizing + * metadata. That should be very unusual */ + setImmediate(() => { + this.startHttp2Stream(methodName, stream, metadata); + }); + } + } + }).catch((error: Error & { code: number }) => { + // We assume the error code isn't 0 (Status.OK) + stream.cancelWithStatus(error.code || Status.UNKNOWN, + `Getting metadata from plugin failed with error: ${error.message}`); + }); } createStream(methodName: string, metadata: Metadata, options: CallOptions): @@ -239,13 +249,15 @@ export class Http2Channel extends EventEmitter implements Channel { return stream; } - connect(callback: () => void): void { - this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); - if (this.connectivityState === ConnectivityState.READY) { - setImmediate(callback); - } else { - this.once('connect', callback); - } + connect(): Promise { + return new Promise((resolve) => { + this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); + if (this.connectivityState === ConnectivityState.READY) { + setImmediate(resolve); + } else { + this.once('connect', resolve); + } + }); } getConnectivityState(): ConnectivityState { diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 2b040e6be..13849ab72 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -35,7 +35,7 @@ export class Client { void { let cb: (error: Error|null) => void = once(callback); let callbackCalled = false; - this.channel.connect(() => { + this.channel.connect().then(() => { cb(null); }); if (deadline !== Infinity) { diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index 66b181076..47f89f9ab 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -7,6 +7,18 @@ import {Metadata} from './metadata'; const units: [string, number][] = [['m', 1], ['S', 1000], ['M', 60 * 1000], ['H', 60 * 60 * 1000]]; +function getDeadline(deadline: number) { + let now = (new Date()).getTime(); + let timeoutMs = deadline - now; + for (let [unit, factor] of units) { + let amount = timeoutMs / factor; + if (amount < 1e8) { + return String(Math.ceil(amount)) + unit; + } + } + throw new Error('Deadline is too far in the future'); +} + export class DeadlineFilter extends BaseFilter implements Filter { private deadline: number; constructor( @@ -36,22 +48,10 @@ export class DeadlineFilter extends BaseFilter implements Filter { if (this.deadline === Infinity) { return await metadata; } - let timeoutString: Promise = - new Promise((resolve, reject) => { - this.channel.connect(() => { - let now = (new Date()).getTime(); - let timeoutMs = this.deadline - now; - for (let [unit, factor] of units) { - let amount = timeoutMs / factor; - if (amount < 1e8) { - resolve(String(Math.ceil(amount)) + unit); - return; - } - } - }); - }); - let finalMetadata = await metadata; - finalMetadata.set('grpc-timeout', await timeoutString); + await this.channel.connect(); + const timeoutString = getDeadline(this.deadline); + const finalMetadata = await metadata; + finalMetadata.set('grpc-timeout', timeoutString); return finalMetadata; } } From 6ec30912736032525016e1e989fcea6b4d422983 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 11 Dec 2017 15:31:31 -0800 Subject: [PATCH 0065/1899] grpc-js-core: unref http2 client socket --- packages/grpc-js-core/src/channel.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index d28d8d592..5cdbf4075 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -110,7 +110,7 @@ export class Http2Channel extends EventEmitter implements Channel { break; case ConnectivityState.IDLE: case ConnectivityState.SHUTDOWN: - if (this.subChannel !== null) { + if (this.subChannel) { this.subChannel.shutdown({graceful: true}); this.subChannel.removeListener('connect', this.subChannelConnectCallback); this.subChannel.removeListener('close', this.subChannelCloseCallback); @@ -201,8 +201,11 @@ export class Http2Channel extends EventEmitter implements Channel { headers[HTTP2_HEADER_TE] = 'trailers'; if (stream.getStatus() === null) { if (this.connectivityState === ConnectivityState.READY) { - let session: http2.ClientHttp2Session = - (this.subChannel as http2.ClientHttp2Session); + const session: http2.ClientHttp2Session = this.subChannel!; + // Prevent the HTTP/2 session from keeping the process alive. + // TODO(kjin): Monitor nodejs/node#17620, which adds unref + // directly to the Http2Session object. + session.socket.unref(); stream.attachHttp2Stream(session.request(headers)); } else { /* In this case, we lost the connection while finalizing From ea92b1b16c83125f6b2f1c8767c994cd8fae781b Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 18 Dec 2017 13:33:24 -0800 Subject: [PATCH 0066/1899] grpc-js-core: fixes for interop test --- packages/grpc-js-core/src/call-credentials.ts | 6 ++--- packages/grpc-js-core/src/call-stream.ts | 3 +++ packages/grpc-js-core/src/call.ts | 25 +++++++++++-------- packages/grpc-js-core/src/deadline-filter.ts | 2 +- 4 files changed, 21 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 3be454d5f..278cb163b 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -46,7 +46,7 @@ class ComposedCallCredentials implements CallCredentials { class SingleCallCredentials implements CallCredentials { constructor(private metadataGenerator: CallMetadataGenerator) {} - async generateMetadata(options: {}): Promise { + generateMetadata(options: {}): Promise { return new Promise((resolve, reject) => { this.metadataGenerator(options, (err, metadata) => { if (metadata !== undefined) { @@ -64,8 +64,8 @@ class SingleCallCredentials implements CallCredentials { } class EmptyCallCredentials implements CallCredentials { - async generateMetadata(options: {}): Promise { - return new Metadata(); + generateMetadata(options: {}): Promise { + return Promise.resolve(new Metadata()); } compose(other: CallCredentials): CallCredentials { diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index f62e42afa..3c3b5cfa3 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -282,6 +282,9 @@ export class Http2CallStream extends Duplex implements CallStream { let code: Status; let details = ''; switch (errorCode) { + case http2.constants.NGHTTP2_NO_ERROR: + code = Status.OK; + break; case http2.constants.NGHTTP2_REFUSED_STREAM: code = Status.UNAVAILABLE; break; diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index 81619ee0e..a4ae44790 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -38,6 +38,17 @@ export interface Call extends EventEmitter { event: 'metadata', listener: (metadata: Metadata) => void): this; removeListener(event: 'metadata', listener: (metadata: Metadata) => void): this; + + addListener(event: 'status', listener: (status: StatusObject) => void): this; + emit(event: 'status', status: StatusObject): boolean; + on(event: 'status', listener: (status: StatusObject) => void): this; + once(event: 'status', listener: (status: StatusObject) => void): this; + prependListener(event: 'status', listener: (status: StatusObject) => void): + this; + prependOnceListener( + event: 'status', listener: (status: StatusObject) => void): this; + removeListener(event: 'status', listener: (status: StatusObject) => void): + this; } export interface ClientUnaryCall extends Call {} @@ -48,6 +59,9 @@ export class ClientUnaryCallImpl extends EventEmitter implements Call { call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); }); + call.on('status', (status: StatusObject) => { + this.emit('status', status); + }); } cancel(): void { @@ -70,17 +84,6 @@ export interface ClientReadableStream extends prependListener(event: string, listener: Function): this; prependOnceListener(event: string, listener: Function): this; removeListener(event: string, listener: Function): this; - - addListener(event: 'status', listener: (status: StatusObject) => void): this; - emit(event: 'status', status: StatusObject): boolean; - on(event: 'status', listener: (status: StatusObject) => void): this; - once(event: 'status', listener: (status: StatusObject) => void): this; - prependListener(event: 'status', listener: (status: StatusObject) => void): - this; - prependOnceListener( - event: 'status', listener: (status: StatusObject) => void): this; - removeListener(event: 'status', listener: (status: StatusObject) => void): - this; } export interface ClientWritableStream extends diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index 47f89f9ab..c3ed045bf 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -9,7 +9,7 @@ const units: [string, number][] = function getDeadline(deadline: number) { let now = (new Date()).getTime(); - let timeoutMs = deadline - now; + let timeoutMs = Math.max(deadline - now, 0); for (let [unit, factor] of units) { let amount = timeoutMs / factor; if (amount < 1e8) { From da73a0fff01cdfcbd81cbd4a3eca8d2f03b70445 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 14 Dec 2017 16:10:20 -0800 Subject: [PATCH 0067/1899] grpc-js-core: emit status on client stream calls --- packages/grpc-js-core/src/call.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index ba38a41ca..81619ee0e 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -190,6 +190,9 @@ export class ClientWritableStreamImpl extends Writable implements call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); }); + call.on('status', (status: StatusObject) => { + this.emit('status', status); + }); } cancel(): void { From cc231f1f67a4703d428a5b83fafa36bb035e130f Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 18 Dec 2017 15:24:11 -0800 Subject: [PATCH 0068/1899] grpc-js-core: merge all eventemitter overloads --- packages/grpc-js-core/src/call-stream.ts | 37 ++------- packages/grpc-js-core/src/call.ts | 87 +++++----------------- packages/grpc-js-core/src/client.ts | 14 ++-- packages/grpc-js-core/src/events.ts | 29 ++++++++ packages/grpc-js-core/src/object-stream.ts | 36 ++------- 5 files changed, 65 insertions(+), 138 deletions(-) create mode 100644 packages/grpc-js-core/src/events.ts diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 3c3b5cfa3..4b4980c56 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -3,6 +3,7 @@ import {Duplex} from 'stream'; import {CallCredentials} from './call-credentials'; import {Status} from './constants'; +import {EmitterAugmentation1} from './events'; import {Filter} from './filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; @@ -34,7 +35,7 @@ export interface WriteObject { /** * This interface represents a duplex stream associated with a single gRPC call. */ -export interface CallStream extends ObjectDuplex { +export type CallStream = { cancelWithStatus(status: Status, details: string): void; getPeer(): string; @@ -43,37 +44,9 @@ export interface CallStream extends ObjectDuplex { /* If the return value is null, the call has not ended yet. Otherwise, it has * ended with the specified status */ getStatus(): StatusObject|null; - - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - - addListener(event: 'metadata', listener: (metadata: Metadata) => void): this; - emit(event: 'metadata', metadata: Metadata): boolean; - on(event: 'metadata', listener: (metadata: Metadata) => void): this; - once(event: 'metadata', listener: (metadata: Metadata) => void): this; - prependListener(event: 'metadata', listener: (metadata: Metadata) => void): - this; - prependOnceListener( - event: 'metadata', listener: (metadata: Metadata) => void): this; - removeListener(event: 'metadata', listener: (metadata: Metadata) => void): - this; - - addListener(event: 'status', listener: (status: StatusObject) => void): this; - emit(event: 'status', status: StatusObject): boolean; - on(event: 'status', listener: (status: StatusObject) => void): this; - once(event: 'status', listener: (status: StatusObject) => void): this; - prependListener(event: 'status', listener: (status: StatusObject) => void): - this; - prependOnceListener( - event: 'status', listener: (status: StatusObject) => void): this; - removeListener(event: 'status', listener: (status: StatusObject) => void): - this; -} +} & EmitterAugmentation1<'metadata', Metadata> + & EmitterAugmentation1<'status', StatusObject> + & ObjectDuplex; enum ReadState { NO_DATA, diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index a4ae44790..5abc04799 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -1,4 +1,5 @@ import {EventEmitter} from 'events'; +import {EmitterAugmentation1} from './events'; import {Duplex, Readable, Writable} from 'stream'; import {CallStream, StatusObject, WriteObject} from './call-stream'; @@ -16,44 +17,27 @@ export class ServiceErrorImpl extends Error implements ServiceError { metadata?: Metadata; } -export interface Call extends EventEmitter { +export type Call = { cancel(): void; getPeer(): string; +} & EmitterAugmentation1<'metadata', Metadata> + & EmitterAugmentation1<'status', StatusObject> + & EventEmitter; - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - - addListener(event: 'metadata', listener: (metadata: Metadata) => void): this; - emit(event: 'metadata', metadata: Metadata): boolean; - on(event: 'metadata', listener: (metadata: Metadata) => void): this; - once(event: 'metadata', listener: (metadata: Metadata) => void): this; - prependListener(event: 'metadata', listener: (metadata: Metadata) => void): - this; - prependOnceListener( - event: 'metadata', listener: (metadata: Metadata) => void): this; - removeListener(event: 'metadata', listener: (metadata: Metadata) => void): - this; - - addListener(event: 'status', listener: (status: StatusObject) => void): this; - emit(event: 'status', status: StatusObject): boolean; - on(event: 'status', listener: (status: StatusObject) => void): this; - once(event: 'status', listener: (status: StatusObject) => void): this; - prependListener(event: 'status', listener: (status: StatusObject) => void): - this; - prependOnceListener( - event: 'status', listener: (status: StatusObject) => void): this; - removeListener(event: 'status', listener: (status: StatusObject) => void): - this; -} +export type ClientUnaryCall = Call; + +export type ClientReadableStream = { + deserialize: (chunk: Buffer) => ResponseType; +} & Call & ObjectReadable; + +export type ClientWritableStream = { + serialize: (value: RequestType) => Buffer; +} & Call & ObjectWritable; -export interface ClientUnaryCall extends Call {} +export type ClientDuplexStream = + ClientWritableStream & ClientReadableStream; -export class ClientUnaryCallImpl extends EventEmitter implements Call { +export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { constructor(private readonly call: CallStream) { super(); call.on('metadata', (metadata: Metadata) => { @@ -73,43 +57,6 @@ export class ClientUnaryCallImpl extends EventEmitter implements Call { } } -export interface ClientReadableStream extends - Call, ObjectReadable { - deserialize: (chunk: Buffer) => ResponseType; - - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; -} - -export interface ClientWritableStream extends - Call, ObjectWritable { - serialize: (value: RequestType) => Buffer; - - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; -} - -export interface ClientDuplexStream extends - ClientWritableStream, ClientReadableStream { - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; -} - function setUpReadableStream( stream: ClientReadableStream, call: CallStream, deserialize: (chunk: Buffer) => ResponseType): void { diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 13849ab72..ade3780b2 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -135,7 +135,6 @@ export class Client { method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, callback: UnaryCallback): ClientUnaryCall; - makeUnaryRequest( method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, argument: RequestType, @@ -147,13 +146,14 @@ export class Client { metadata, options, callback)); const call: CallStream = this.channel.createStream(method, metadata, options); - const emitter: ClientUnaryCall = new ClientUnaryCallImpl(call); const message: Buffer = serialize(argument); const writeObj: WriteObject = {message: message}; writeObj.flags = options.flags; call.write(writeObj); call.end(); this.handleUnaryResponse(call, deserialize, callback); + + const emitter: ClientUnaryCall = new ClientUnaryCallImpl(call); return emitter; } @@ -174,7 +174,6 @@ export class Client { method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, callback: UnaryCallback): ClientWritableStream; - makeClientStreamRequest( method: string, serialize: (value: RequestType) => Buffer, deserialize: (value: Buffer) => ResponseType, @@ -187,9 +186,10 @@ export class Client { metadata, options, callback)); const call: CallStream = this.channel.createStream(method, metadata, options); + this.handleUnaryResponse(call, deserialize, callback); + const stream: ClientWritableStream = new ClientWritableStreamImpl(call, serialize); - this.handleUnaryResponse(call, deserialize, callback); return stream; } @@ -233,13 +233,14 @@ export class Client { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: CallStream = this.channel.createStream(method, metadata, options); - const stream: ClientReadableStream = - new ClientReadableStreamImpl(call, deserialize); const message: Buffer = serialize(argument); const writeObj: WriteObject = {message: message}; writeObj.flags = options.flags; call.write(writeObj); call.end(); + + const stream: ClientReadableStream = + new ClientReadableStreamImpl(call, deserialize); return stream; } @@ -259,6 +260,7 @@ export class Client { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: CallStream = this.channel.createStream(method, metadata, options); + const stream: ClientDuplexStream = new ClientDuplexStreamImpl( call, serialize, deserialize); diff --git a/packages/grpc-js-core/src/events.ts b/packages/grpc-js-core/src/events.ts new file mode 100644 index 000000000..591120d10 --- /dev/null +++ b/packages/grpc-js-core/src/events.ts @@ -0,0 +1,29 @@ +export interface EmitterAugmentation0 { + addListener(event: Name, listener: () => void): this; + emit(event: Name): boolean; + on(event: Name, listener: () => void): this; + once(event: Name, listener: () => void): this; + prependListener(event: Name, listener: () => void): this; + prependOnceListener(event: Name, listener: () => void): this; + removeListener(event: Name, listener: () => void): this; +} + +export interface EmitterAugmentation1 { + addListener(event: Name, listener: (arg1: Arg) => void): this; + emit(event: Name, arg1: Arg): boolean; + on(event: Name, listener: (arg1: Arg) => void): this; + once(event: Name, listener: (arg1: Arg) => void): this; + prependListener(event: Name, listener: (arg1: Arg) => void): this; + prependOnceListener(event: Name, listener: (arg1: Arg) => void): this; + removeListener(event: Name, listener: (arg1: Arg) => void): this; +} + +export interface EmitterAugmentation2 { + addListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; + emit(event: Name, arg1: Arg1, arg2: Arg2): boolean; + on(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; + once(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; + prependListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; + prependOnceListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; + removeListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; +} diff --git a/packages/grpc-js-core/src/object-stream.ts b/packages/grpc-js-core/src/object-stream.ts index bed77f042..48988daad 100644 --- a/packages/grpc-js-core/src/object-stream.ts +++ b/packages/grpc-js-core/src/object-stream.ts @@ -1,28 +1,14 @@ import {Duplex, Readable, Writable} from 'stream'; +import {EmitterAugmentation1} from './events'; export interface IntermediateObjectReadable extends Readable { read(size?: number): any&T; } -export interface ObjectReadable extends IntermediateObjectReadable { +export type ObjectReadable = { read(size?: number): T; - - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - - addListener(event: 'data', listener: (chunk: T) => void): this; - emit(event: 'data', chunk: T): boolean; - on(event: 'data', listener: (chunk: T) => void): this; - once(event: 'data', listener: (chunk: T) => void): this; - prependListener(event: 'data', listener: (chunk: T) => void): this; - prependOnceListener(event: 'data', listener: (chunk: T) => void): this; - removeListener(event: 'data', listener: (chunk: T) => void): this; -} +} & EmitterAugmentation1<'data', T> + & IntermediateObjectReadable; export interface IntermediateObjectWritable extends Writable { _write(chunk: any&T, encoding: string, callback: Function): void; @@ -44,8 +30,7 @@ export interface ObjectWritable extends IntermediateObjectWritable { end(chunk: T, encoding?: any, cb?: Function): void; } -export interface ObjectDuplex extends Duplex, ObjectWritable, - ObjectReadable { +export type ObjectDuplex = { read(size?: number): U; _write(chunk: T, encoding: string, callback: Function): void; @@ -54,13 +39,4 @@ export interface ObjectDuplex extends Duplex, ObjectWritable, end(): void; end(chunk: T, cb?: Function): void; end(chunk: T, encoding?: any, cb?: Function): void; - - - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; -} +} & Duplex & ObjectWritable & ObjectReadable; From aea5bf82e5d9dbb37da98342fcfd150f8ac81aef Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 18 Dec 2017 18:20:19 -0800 Subject: [PATCH 0069/1899] grpc-js-core: handle eos headers as trailers --- packages/grpc-js-core/src/call-stream.ts | 136 +++++++++++------- packages/grpc-js-core/src/channel.ts | 5 +- .../src/metadata-status-filter.ts | 36 +++++ packages/grpc-js-core/src/metadata.ts | 2 +- 4 files changed, 125 insertions(+), 54 deletions(-) create mode 100644 packages/grpc-js-core/src/metadata-status-filter.ts diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index f62e42afa..0d90136d8 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -105,6 +105,13 @@ export class Http2CallStream extends Duplex implements CallStream { // Status code mapped from :status. To be used if grpc-status is not received private mappedStatusCode: Status = Status.UNKNOWN; + // Promise objects that are re-assigned to resolving promises when headers + // or trailers received. Processing headers/trailers is asynchronous, so we + // can use these objects to await their completion. This helps us establish + // order of precedence when obtaining the status of the call. + private handlingHeaders = Promise.resolve(); + private handlingTrailers = Promise.resolve(); + // This is populated (non-null) if and only if the call has ended private finalStatus: StatusObject|null = null; @@ -116,6 +123,11 @@ export class Http2CallStream extends Duplex implements CallStream { this.filterStack = filterStackFactory.createFilter(this); } + /** + * On first call, emits a 'status' event with the given StatusObject. + * Subsequent calls are no-ops. + * @param status The status of the call. + */ private endCall(status: StatusObject): void { if (this.finalStatus === null) { this.finalStatus = status; @@ -135,12 +147,46 @@ export class Http2CallStream extends Duplex implements CallStream { return canPush; } + private handleTrailers(headers: http2.IncomingHttpHeaders) { + let code: Status = this.mappedStatusCode; + let details = ''; + let metadata: Metadata; + try { + metadata = Metadata.fromHttp2Headers(headers); + } catch (e) { + metadata = new Metadata(); + } + let status: StatusObject = {code, details, metadata}; + this.handlingTrailers = (async () => { + let finalStatus; + try { + // Attempt to assign final status. + finalStatus = await this.filterStack.receiveTrailers(Promise.resolve(status)); + } catch (error) { + await this.handlingHeaders; + // This is a no-op if the call was already ended when handling headers. + this.endCall({ + code: Status.INTERNAL, + details: 'Failed to process received status', + metadata: new Metadata() + }); + return; + } + // It's possible that headers were received but not fully handled yet. + // Give the headers handler an opportunity to end the call first, + // if an error occurred. + await this.handlingHeaders; + // This is a no-op if the call was already ended when handling headers. + this.endCall(finalStatus); + })(); + } + attachHttp2Stream(stream: http2.ClientHttp2Stream): void { if (this.finalStatus !== null) { stream.rstWithCancel(); } else { this.http2Stream = stream; - stream.on('response', (headers) => { + stream.on('response', (headers, flags) => { switch (headers[HTTP2_HEADER_STATUS]) { // TODO(murgatroid99): handle 100 and 101 case '400': @@ -166,57 +212,27 @@ export class Http2CallStream extends Duplex implements CallStream { } delete headers[HTTP2_HEADER_STATUS]; delete headers[HTTP2_HEADER_CONTENT_TYPE]; - let metadata: Metadata; - try { - metadata = Metadata.fromHttp2Headers(headers); - } catch (e) { - this.cancelWithStatus(Status.UNKNOWN, e.message); - return; - } - this.filterStack.receiveMetadata(Promise.resolve(metadata)) - .then( - (finalMetadata) => { - this.emit('metadata', finalMetadata); - }, - (error) => { - this.cancelWithStatus(Status.UNKNOWN, error.message); - }); - }); - stream.on('trailers', (headers: http2.IncomingHttpHeaders) => { - let code: Status = this.mappedStatusCode; - let details = ''; - if (typeof headers['grpc-status'] === 'string') { - let receivedCode = Number(headers['grpc-status']); - if (receivedCode in Status) { - code = receivedCode; - } else { - code = Status.UNKNOWN; + if (flags & http2.constants.NGHTTP2_FLAG_END_STREAM) { + this.handleTrailers(headers); + } else { + let metadata: Metadata; + try { + metadata = Metadata.fromHttp2Headers(headers); + } catch (error) { + this.endCall({code: Status.UNKNOWN, details: error.message, metadata: new Metadata()}); + return; } - delete headers['grpc-status']; - } - if (typeof headers['grpc-message'] === 'string') { - details = decodeURI(headers['grpc-message'] as string); + this.handlingHeaders = + this.filterStack.receiveMetadata(Promise.resolve(metadata)) + .then((finalMetadata) => { + this.emit('metadata', finalMetadata); + }).catch((error) => { + this.destroyHttp2Stream(); + this.endCall({code: Status.UNKNOWN, details: error.message, metadata: new Metadata()}); + }); } - let metadata: Metadata; - try { - metadata = Metadata.fromHttp2Headers(headers); - } catch (e) { - metadata = new Metadata(); - } - let status: StatusObject = {code, details, metadata}; - this.filterStack.receiveTrailers(Promise.resolve(status)) - .then( - (finalStatus) => { - this.endCall(finalStatus); - }, - (error) => { - this.endCall({ - code: Status.INTERNAL, - details: 'Failed to process received status', - metadata: new Metadata() - }); - }); }); + stream.on('trailers', this.handleTrailers.bind(this)); stream.on('data', (data) => { let readHead = 0; let canPush = true; @@ -278,7 +294,7 @@ export class Http2CallStream extends Duplex implements CallStream { this.unpushedReadMessages.push(null); } }); - stream.on('streamClosed', (errorCode) => { + stream.on('streamClosed', async (errorCode) => { let code: Status; let details = ''; switch (errorCode) { @@ -299,6 +315,13 @@ export class Http2CallStream extends Duplex implements CallStream { default: code = Status.INTERNAL; } + // This guarantees that if trailers were received, the value of the + // 'grpc-status' header takes precedence for emitted status data. + await this.handlingTrailers; + // This is a no-op if trailers were received at all. + // This is OK, because status codes emitted here correspond to more + // catastrophic issues that prevent us from receiving trailers in the + // first place. this.endCall({code: code, details: details, metadata: new Metadata()}); }); stream.on('error', (err: Error) => { @@ -323,8 +346,7 @@ export class Http2CallStream extends Duplex implements CallStream { } } - cancelWithStatus(status: Status, details: string): void { - this.endCall({code: status, details: details, metadata: new Metadata()}); + private destroyHttp2Stream() { // The http2 stream could already have been destroyed if cancelWithStatus // is called in response to an internal http2 error. if (this.http2Stream !== null && !this.http2Stream.destroyed) { @@ -334,6 +356,16 @@ export class Http2CallStream extends Duplex implements CallStream { } } + cancelWithStatus(status: Status, details: string): void { + this.destroyHttp2Stream(); + (async () => { + // If trailers are currently being processed, the call should be ended + // by handleTrailers instead. + await this.handlingTrailers; + this.endCall({code: status, details: details, metadata: new Metadata()}); + })(); + } + getDeadline(): Deadline { return this.options.deadline; } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 5cdbf4075..773185df0 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -12,6 +12,7 @@ import {Status} from './constants'; import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; +import { MetadataStatusFilterFactory } from './metadata-status-filter'; const IDLE_TIMEOUT_MS = 300000; @@ -177,7 +178,9 @@ export class Http2Channel extends EventEmitter implements Channel { } this.filterStackFactory = new FilterStackFactory([ new CompressionFilterFactory(this), - new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this) + new CallCredentialsFilterFactory(this), + new DeadlineFilterFactory(this), + new MetadataStatusFilterFactory(this) ]); this.currentBackoffDeadline = new Date(); /* The only purpose of these lines is to ensure that this.backoffTimerId has diff --git a/packages/grpc-js-core/src/metadata-status-filter.ts b/packages/grpc-js-core/src/metadata-status-filter.ts new file mode 100644 index 000000000..43d42ea64 --- /dev/null +++ b/packages/grpc-js-core/src/metadata-status-filter.ts @@ -0,0 +1,36 @@ +import {CallStream} from './call-stream'; +import {Channel} from './channel'; +import {BaseFilter, Filter, FilterFactory} from './filter'; +import {StatusObject} from './call-stream'; +import {Status} from './constants'; + +export class MetadataStatusFilter extends BaseFilter implements Filter { + async receiveTrailers(status: Promise): Promise { + let { code, details, metadata } = await status; + if (code !== Status.UNKNOWN) { + // we already have a known status, so don't assign a new one. + return { code, details, metadata }; + } + const metadataMap = metadata.getMap(); + if (typeof metadataMap['grpc-status'] === 'string') { + let receivedCode = Number(metadataMap['grpc-status']); + if (receivedCode in Status) { + code = receivedCode; + } + metadata.remove('grpc-status'); + } + if (typeof metadataMap['grpc-message'] === 'string') { + details = decodeURI(metadataMap['grpc-message'] as string); + metadata.remove('grpc-message'); + } + return { code, details, metadata }; + } +} + +export class MetadataStatusFilterFactory implements + FilterFactory { + constructor(private readonly channel: Channel) {} + createFilter(callStream: CallStream): MetadataStatusFilter { + return new MetadataStatusFilter(); + } +} diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index c2ad6332a..dbdb4e914 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -26,7 +26,7 @@ function isLegalKey(key: string): boolean { } function isLegalNonBinaryValue(value: string): boolean { - return !!value.match(/^[ -~]+$/); + return !!value.match(/^[ -~]*$/); } function isBinaryKey(key: string): boolean { From 22438ae67819d44cf8d14d8960fa025e80c0f415 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 20 Dec 2017 14:31:13 -0800 Subject: [PATCH 0070/1899] grpc-js-core: rename streamClosed event to close --- packages/grpc-js-core/src/call-stream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 0d90136d8..bff5b5d9a 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -294,7 +294,7 @@ export class Http2CallStream extends Duplex implements CallStream { this.unpushedReadMessages.push(null); } }); - stream.on('streamClosed', async (errorCode) => { + stream.on('close', async (errorCode) => { let code: Status; let details = ''; switch (errorCode) { From 843d0630377d4e29d0d14304035a4b044259fb4e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 5 Jan 2018 13:09:15 -0800 Subject: [PATCH 0071/1899] Add JS error for missing callback to sever#tryShutdown --- packages/grpc-native-core/ext/server.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-native-core/ext/server.cc b/packages/grpc-native-core/ext/server.cc index c6ab5e189..d5b4763b3 100644 --- a/packages/grpc-native-core/ext/server.cc +++ b/packages/grpc-native-core/ext/server.cc @@ -312,6 +312,9 @@ NAN_METHOD(Server::TryShutdown) { if (!HasInstance(info.This())) { return Nan::ThrowTypeError("tryShutdown can only be called on a Server"); } + if (!info[0]->IsFunction()) { + return Nan::ThrowError("tryShutdown's argument must be a callback"); + } Server *server = ObjectWrap::Unwrap(info.This()); if (server->wrapped_server == NULL) { // Server is already shut down. Call callback immediately. From 7f0b5b96f73af4d1fada52f97c38ed8d988e5f9a Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Mon, 18 Dec 2017 15:24:11 -0800 Subject: [PATCH 0072/1899] grpc-js-core: don't use local emitter vars --- packages/grpc-js-core/src/client.ts | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index ade3780b2..862d212ce 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -152,9 +152,7 @@ export class Client { call.write(writeObj); call.end(); this.handleUnaryResponse(call, deserialize, callback); - - const emitter: ClientUnaryCall = new ClientUnaryCallImpl(call); - return emitter; + return new ClientUnaryCallImpl(call); } makeClientStreamRequest( @@ -187,10 +185,7 @@ export class Client { const call: CallStream = this.channel.createStream(method, metadata, options); this.handleUnaryResponse(call, deserialize, callback); - - const stream: ClientWritableStream = - new ClientWritableStreamImpl(call, serialize); - return stream; + return new ClientWritableStreamImpl(call, serialize); } private checkMetadataAndOptions( @@ -238,10 +233,7 @@ export class Client { writeObj.flags = options.flags; call.write(writeObj); call.end(); - - const stream: ClientReadableStream = - new ClientReadableStreamImpl(call, deserialize); - return stream; + return new ClientReadableStreamImpl(call, deserialize); } makeBidiStreamRequest( @@ -260,10 +252,7 @@ export class Client { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: CallStream = this.channel.createStream(method, metadata, options); - - const stream: ClientDuplexStream = - new ClientDuplexStreamImpl( - call, serialize, deserialize); - return stream; + return new ClientDuplexStreamImpl( + call, serialize, deserialize); } } From a0abff8b8efe5d2d60c8078f036022bb3ee0d88d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Wed, 10 Jan 2018 10:30:51 +0100 Subject: [PATCH 0073/1899] Rename generic parameter to 'RequestType' in ServerReadableStream for consistency --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 65d5aee7e..e2dc66191 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -331,7 +331,7 @@ declare module "grpc" { * A stream that the server can read from. Used for calls that are streaming * from the client side. */ - export class ServerReadableStream extends Readable { + export class ServerReadableStream extends Readable { /** * Indicates if the call has been cancelled */ From 0d19268ef973ffe145068af253689dd0244940b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Wed, 10 Jan 2018 11:08:34 +0100 Subject: [PATCH 0074/1899] Tighten the definition of ServiceDefinition --- packages/grpc-native-core/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index e2dc66191..69c423d8f 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -237,8 +237,8 @@ declare module "grpc" { * An object that completely defines a service. * @typedef {Object.} grpc~ServiceDefinition */ - export interface ServiceDefinition { - [s: string]: MethodDefinition; + export type ServiceDefinition = { + readonly [I in keyof ImplementationType]: MethodDefinition; } /** From 264cc4767a41d7306bf57be78d144ff3f29d1ff7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 10 Jan 2018 14:48:35 -0500 Subject: [PATCH 0075/1899] Update version and submodule to 1.8.4 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index ada05afd6..77ec6c94a 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit ada05afd62a2e5d405bc1ba1c1cf2d775d1a42ea +Subproject commit 77ec6c94ad58bedfdf8f28682914e9893e318be0 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 656ba8980..4a6e7307f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.8.0", + "version": "1.8.4", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 01d66dd0b5c5be0a4d0230f67142d7d3c13ae5a1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 12 Jan 2018 15:11:21 -0500 Subject: [PATCH 0076/1899] Add original details string to errors, update tests --- packages/grpc-native-core/src/client.js | 3 ++- test/api/credentials_test.js | 4 ++-- test/api/surface_test.js | 8 ++++---- test/interop/interop_client.js | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 1e873d2cd..389d06b00 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -61,10 +61,11 @@ var version = require('../package.json').version; */ function createStatusError(status) { let statusName = _.invert(constants.status)[status.code]; - let message = `${status.code} ${status.name}: ${status.details}`; + let message = `${status.code} ${statusName}: ${status.details}`; let error = new Error(message); error.code = status.code; error.metadata = status.metadata; + error.details = status.details; return error; } diff --git a/test/api/credentials_test.js b/test/api/credentials_test.js index e05ec7648..171892675 100644 --- a/test/api/credentials_test.js +++ b/test/api/credentials_test.js @@ -319,7 +319,7 @@ describe('client credentials', function() { client_options); client.unary({}, function(err, data) { assert(err); - assert.strictEqual(err.message, + assert.strictEqual(err.details, 'Getting metadata from plugin failed with error: ' + 'Authentication error'); assert.strictEqual(err.code, grpc.status.UNAUTHENTICATED); @@ -369,7 +369,7 @@ describe('client credentials', function() { client_options); client.unary({}, function(err, data) { assert(err); - assert.strictEqual(err.message, + assert.strictEqual(err.details, 'Getting metadata from plugin failed with error: ' + 'Authentication failure'); done(); diff --git a/test/api/surface_test.js b/test/api/surface_test.js index 5fdcbcfb7..3bffaf8e3 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -981,7 +981,7 @@ describe('Other conditions', function() { client.unary({error: true}, function(err, data) { assert(err); assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.message, 'Requested error'); + assert.strictEqual(err.details, 'Requested error'); done(); }); }); @@ -989,7 +989,7 @@ describe('Other conditions', function() { var call = client.clientStream(function(err, data) { assert(err); assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.message, 'Requested error'); + assert.strictEqual(err.details, 'Requested error'); done(); }); call.write({error: false}); @@ -1001,7 +1001,7 @@ describe('Other conditions', function() { call.on('data', function(){}); call.on('error', function(error) { assert.strictEqual(error.code, grpc.status.UNKNOWN); - assert.strictEqual(error.message, 'Requested error'); + assert.strictEqual(error.details, 'Requested error'); done(); }); }); @@ -1013,7 +1013,7 @@ describe('Other conditions', function() { call.on('data', function(){}); call.on('error', function(error) { assert.strictEqual(error.code, grpc.status.UNKNOWN); - assert.strictEqual(error.message, 'Requested error'); + assert.strictEqual(error.details, 'Requested error'); done(); }); }); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 73b84c38c..83890bca8 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -347,7 +347,7 @@ function statusCodeAndMessage(client, done) { client.unaryCall(arg, function(err, resp) { assert(err); assert.strictEqual(err.code, 2); - assert.strictEqual(err.message, 'test status message'); + assert.strictEqual(err.details, 'test status message'); done(); }); var duplex = client.fullDuplexCall(); From e0bd6b19cc9ec62bab62c777d0aac2554ccdf282 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 Jan 2018 12:22:05 -0500 Subject: [PATCH 0077/1899] Update submodule --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 638c40c9e..e5b7ddd59 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 638c40c9eff83508fb17e8c0962f01fe24492b38 +Subproject commit e5b7ddd59c9a8b7a33820197abb45e12e2b65daf From a7aaf31ef67cf679b1ed61379c5427d26dd380b1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 Jan 2018 12:28:25 -0500 Subject: [PATCH 0078/1899] Generate projects --- packages/grpc-native-core/binding.gyp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index ddb91ec9e..09754efdf 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -63,6 +63,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Wno-deprecated-declarations', ], 'ldflags': [ '-g', @@ -185,6 +186,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Wno-deprecated-declarations', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -194,6 +196,7 @@ '-Wno-long-long', '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', + '-Wno-deprecated-declarations', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' @@ -613,7 +616,6 @@ 'deps/grpc/src/core/lib/support/env_posix.cc', 'deps/grpc/src/core/lib/support/env_windows.cc', 'deps/grpc/src/core/lib/support/fork.cc', - 'deps/grpc/src/core/lib/support/histogram.cc', 'deps/grpc/src/core/lib/support/host_port.cc', 'deps/grpc/src/core/lib/support/log.cc', 'deps/grpc/src/core/lib/support/log_android.cc', From a50ba76838fe97efe665157e3c73637d71f2cf7d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 23 Jan 2018 15:51:59 -0500 Subject: [PATCH 0079/1899] Replace Argue.js usage with inline argument checking --- packages/grpc-native-core/package.json | 1 - packages/grpc-native-core/src/client.js | 119 ++++++++++-------- .../templates/package.json.template | 1 - 3 files changed, 68 insertions(+), 53 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f216537a3..34c043395 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -28,7 +28,6 @@ "node-pre-gyp" ], "dependencies": { - "arguejs": "^0.2.3", "lodash": "^4.15.0", "nan": "^2.0.0", "node-pre-gyp": "^0.6.39", diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 24af23b8a..1c874e868 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -33,7 +33,6 @@ 'use strict'; var _ = require('lodash'); -var arguejs = require('arguejs'); var grpc = require('./grpc_extension'); @@ -500,21 +499,27 @@ exports.Client = Client; Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, argument, metadata, options, callback) { - /* While the arguments are listed in the function signature, those variables - * are not used directly. Instead, ArgueJS processes the arguments - * object. This allows for simple handling of optional arguments in the - * middle of the argument list, and also provides type checking. */ - var args = arguejs({method: String, serialize: Function, - deserialize: Function, - argument: null, metadata: [Metadata, new Metadata()], - options: [Object], callback: Function}, arguments); - var call = getCall(this.$channel, method, args.options); + if (!(metadata instanceof Metadata)) { + callback = options; + options = metadata; + metadata = new Metadata(); + } + if (options instanceof Function) { + callback = options; + options = {}; + } + if (!((metadata instanceof Metadata) && + (options instanceof Object) && + (callback instanceof Function))) { + throw new Error("Argument mismatch in makeUnaryRequest"); + } + var call = getCall(this.$channel, method, options); var emitter = new ClientUnaryCall(call); - metadata = args.metadata.clone(); + metadata = metadata.clone(); var client_batch = {}; - var message = serialize(args.argument); - if (args.options) { - message.grpcWriteFlags = args.options.flags; + var message = serialize(argument); + if (options) { + message.grpcWriteFlags = options.flags; } client_batch[grpc.opType.SEND_INITIAL_METADATA] = @@ -535,7 +540,7 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, if (status.code === constants.status.OK) { if (err) { // Got a batch error, but OK status. Something went wrong - args.callback(err); + callback(err); return; } else { try { @@ -554,9 +559,9 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, error = new Error(status.details); error.code = status.code; error.metadata = status.metadata; - args.callback(error); + callback(error); } else { - args.callback(null, deserialized); + callback(null, deserialized); } emitter.emit('status', status); }); @@ -582,16 +587,22 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, Client.prototype.makeClientStreamRequest = function(method, serialize, deserialize, metadata, options, callback) { - /* While the arguments are listed in the function signature, those variables - * are not used directly. Instead, ArgueJS processes the arguments - * object. This allows for simple handling of optional arguments in the - * middle of the argument list, and also provides type checking. */ - var args = arguejs({method:String, serialize: Function, - deserialize: Function, - metadata: [Metadata, new Metadata()], - options: [Object], callback: Function}, arguments); - var call = getCall(this.$channel, method, args.options); - metadata = args.metadata.clone(); + if (!(metadata instanceof Metadata)) { + callback = options; + options = metadata; + metadata = new Metadata(); + } + if (options instanceof Function) { + callback = options; + options = {}; + } + if (!((metadata instanceof Metadata) && + (options instanceof Object) && + (callback instanceof Function))) { + throw new Error("Argument mismatch in makeClientStreamRequest"); + } + var call = getCall(this.$channel, method, options); + metadata = metadata.clone(); var stream = new ClientWritableStream(call, serialize); var metadata_batch = {}; metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = @@ -618,7 +629,7 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, if (status.code === constants.status.OK) { if (err) { // Got a batch error, but OK status. Something went wrong - args.callback(err); + callback(err); return; } else { try { @@ -637,9 +648,9 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, error = new Error(response.status.details); error.code = status.code; error.metadata = status.metadata; - args.callback(error); + callback(error); } else { - args.callback(null, deserialized); + callback(null, deserialized); } stream.emit('status', status); }); @@ -664,20 +675,23 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, Client.prototype.makeServerStreamRequest = function(method, serialize, deserialize, argument, metadata, options) { - /* While the arguments are listed in the function signature, those variables - * are not used directly. Instead, ArgueJS processes the arguments - * object. */ - var args = arguejs({method:String, serialize: Function, - deserialize: Function, - argument: null, metadata: [Metadata, new Metadata()], - options: [Object]}, arguments); - var call = getCall(this.$channel, method, args.options); - metadata = args.metadata.clone(); + if (!(metadata instanceof Metadata)) { + options = metadata; + metadata = new Metadata(); + } + if (!(options instanceof Object)) { + options = {}; + } + if (!((metadata instanceof Metadata) && (options instanceof Object))) { + throw new Error("Argument mismatch in makeServerStreamRequest"); + } + var call = getCall(this.$channel, method, options); + metadata = metadata.clone(); var stream = new ClientReadableStream(call, deserialize); var start_batch = {}; - var message = serialize(args.argument); - if (args.options) { - message.grpcWriteFlags = args.options.flags; + var message = serialize(argument); + if (options) { + message.grpcWriteFlags = options.flags; } start_batch[grpc.opType.SEND_INITIAL_METADATA] = metadata._getCoreRepresentation(); @@ -722,15 +736,18 @@ Client.prototype.makeServerStreamRequest = function(method, serialize, Client.prototype.makeBidiStreamRequest = function(method, serialize, deserialize, metadata, options) { - /* While the arguments are listed in the function signature, those variables - * are not used directly. Instead, ArgueJS processes the arguments - * object. */ - var args = arguejs({method:String, serialize: Function, - deserialize: Function, - metadata: [Metadata, new Metadata()], - options: [Object]}, arguments); - var call = getCall(this.$channel, method, args.options); - metadata = args.metadata.clone(); + if (!(metadata instanceof Metadata)) { + options = metadata; + metadata = new Metadata(); + } + if (!(options instanceof Object)) { + options = {}; + } + if (!((metadata instanceof Metadata) && (options instanceof Object))) { + throw new Error("Argument mismatch in makeBidiStreamRequest"); + } + var call = getCall(this.$channel, method, options); + metadata = metadata.clone(); var stream = new ClientDuplexStream(call, serialize, deserialize); var start_batch = {}; start_batch[grpc.opType.SEND_INITIAL_METADATA] = diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 1f3d8813e..51df7d81d 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -30,7 +30,6 @@ "node-pre-gyp" ], "dependencies": { - "arguejs": "^0.2.3", "lodash": "^4.15.0", "nan": "^2.0.0", "node-pre-gyp": "^0.6.39", From e3c3c3462f98d6e7903e2f282de184609f33ca44 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 31 Jan 2018 14:28:39 -0800 Subject: [PATCH 0080/1899] Fix TS compiler errors and pin TS to 2.7 --- package.json | 2 +- packages/grpc-js-core/package.json | 2 +- packages/grpc-js-core/src/channel.ts | 4 ++-- packages/grpc-js-core/test/test-call-stream.ts | 10 +++++----- packages/grpc-js-core/test/test-channel-credentials.ts | 2 +- packages/grpc-js/package.json | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index cb324a088..5310e7f5c 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", - "typescript": "^2.5.1", + "typescript": "~2.7.0", "xml2js": "^0.4.19" }, "contributors": [ diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index d5fdd46c7..e0d48bd4b 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -19,7 +19,7 @@ "@types/node": "^8.0.55", "clang-format": "^1.0.55", "gts": "^0.5.1", - "typescript": "^2.6.1" + "typescript": "~2.7.0" }, "contributors": [ { diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 35ca6f6cd..51ec1fa59 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -76,7 +76,7 @@ export class Http2Channel extends EventEmitter implements Channel { private connectivityState: ConnectivityState = ConnectivityState.IDLE; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ - private subChannel: http2.ClientHttp2Session|null; + private subChannel: http2.ClientHttp2Session|null = null; private filterStackFactory: FilterStackFactory; private subChannelConnectCallback: ()=>void = () => {}; @@ -123,7 +123,7 @@ export class Http2Channel extends EventEmitter implements Channel { } // Transition from any of a set of oldStates to a specific newState - private transitionToState(oldStates: [ConnectivityState], newState: ConnectivityState): void { + private transitionToState(oldStates: ConnectivityState[], newState: ConnectivityState): void { if (oldStates.indexOf(this.connectivityState) > -1) { let oldState: ConnectivityState = this.connectivityState; this.connectivityState = newState; diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index e7126d626..91d694dc3 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -38,11 +38,11 @@ class ClientHttp2StreamMock extends stream.Duplex implements http2.ClientHttp2St } bytesRead = 0; dataFrame = 0; - aborted: boolean; - destroyed: boolean; - rstCode: number; - session: http2.Http2Session; - state: http2.StreamState; + aborted: boolean = false; + destroyed: boolean = false; + rstCode: number = 0; + session: http2.Http2Session = {} as any; + state: http2.StreamState = {} as any; priority = mockFunction; rstStream = mockFunction; rstWithNoError = mockFunction; diff --git a/packages/grpc-js-core/test/test-channel-credentials.ts b/packages/grpc-js-core/test/test-channel-credentials.ts index fac881107..15dfbfac0 100644 --- a/packages/grpc-js-core/test/test-channel-credentials.ts +++ b/packages/grpc-js-core/test/test-channel-credentials.ts @@ -8,7 +8,7 @@ import {ChannelCredentials} from '../src/channel-credentials'; import {assert2, mockFunction} from './common'; class CallCredentialsMock implements CallCredentials { - child: CallCredentialsMock; + child: CallCredentialsMock|null = null; constructor(child?: CallCredentialsMock) { if (child) { this.child = child; diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 1dbddbb06..8486c043b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -29,6 +29,6 @@ }, "devDependencies": { "gts": "^0.5.1", - "typescript": "^2.6.1" + "typescript": "~2.7.0" } } From 56d5bbdf21973189f66eac839ffcf4245c0e342c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 31 Jan 2018 15:02:10 -0800 Subject: [PATCH 0081/1899] Bump version to 1.9.0-pre3 --- packages/grpc-native-core/binding.gyp | 84 +++++++++++++------------- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 44 insertions(+), 44 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 09754efdf..4ff3e8cbd 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -601,50 +601,50 @@ 'dependencies': [ ], 'sources': [ + 'deps/grpc/src/core/lib/gpr/alloc.cc', + 'deps/grpc/src/core/lib/gpr/arena.cc', + 'deps/grpc/src/core/lib/gpr/atm.cc', + 'deps/grpc/src/core/lib/gpr/avl.cc', + 'deps/grpc/src/core/lib/gpr/cmdline.cc', + 'deps/grpc/src/core/lib/gpr/cpu_iphone.cc', + 'deps/grpc/src/core/lib/gpr/cpu_linux.cc', + 'deps/grpc/src/core/lib/gpr/cpu_posix.cc', + 'deps/grpc/src/core/lib/gpr/cpu_windows.cc', + 'deps/grpc/src/core/lib/gpr/env_linux.cc', + 'deps/grpc/src/core/lib/gpr/env_posix.cc', + 'deps/grpc/src/core/lib/gpr/env_windows.cc', + 'deps/grpc/src/core/lib/gpr/fork.cc', + 'deps/grpc/src/core/lib/gpr/host_port.cc', + 'deps/grpc/src/core/lib/gpr/log.cc', + 'deps/grpc/src/core/lib/gpr/log_android.cc', + 'deps/grpc/src/core/lib/gpr/log_linux.cc', + 'deps/grpc/src/core/lib/gpr/log_posix.cc', + 'deps/grpc/src/core/lib/gpr/log_windows.cc', + 'deps/grpc/src/core/lib/gpr/mpscq.cc', + 'deps/grpc/src/core/lib/gpr/murmur_hash.cc', + 'deps/grpc/src/core/lib/gpr/string.cc', + 'deps/grpc/src/core/lib/gpr/string_posix.cc', + 'deps/grpc/src/core/lib/gpr/string_util_windows.cc', + 'deps/grpc/src/core/lib/gpr/string_windows.cc', + 'deps/grpc/src/core/lib/gpr/subprocess_posix.cc', + 'deps/grpc/src/core/lib/gpr/subprocess_windows.cc', + 'deps/grpc/src/core/lib/gpr/sync.cc', + 'deps/grpc/src/core/lib/gpr/sync_posix.cc', + 'deps/grpc/src/core/lib/gpr/sync_windows.cc', + 'deps/grpc/src/core/lib/gpr/thd.cc', + 'deps/grpc/src/core/lib/gpr/thd_posix.cc', + 'deps/grpc/src/core/lib/gpr/thd_windows.cc', + 'deps/grpc/src/core/lib/gpr/time.cc', + 'deps/grpc/src/core/lib/gpr/time_posix.cc', + 'deps/grpc/src/core/lib/gpr/time_precise.cc', + 'deps/grpc/src/core/lib/gpr/time_windows.cc', + 'deps/grpc/src/core/lib/gpr/tls_pthread.cc', + 'deps/grpc/src/core/lib/gpr/tmpfile_msys.cc', + 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', + 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', + 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', 'deps/grpc/src/core/lib/profiling/stap_timers.cc', - 'deps/grpc/src/core/lib/support/alloc.cc', - 'deps/grpc/src/core/lib/support/arena.cc', - 'deps/grpc/src/core/lib/support/atm.cc', - 'deps/grpc/src/core/lib/support/avl.cc', - 'deps/grpc/src/core/lib/support/cmdline.cc', - 'deps/grpc/src/core/lib/support/cpu_iphone.cc', - 'deps/grpc/src/core/lib/support/cpu_linux.cc', - 'deps/grpc/src/core/lib/support/cpu_posix.cc', - 'deps/grpc/src/core/lib/support/cpu_windows.cc', - 'deps/grpc/src/core/lib/support/env_linux.cc', - 'deps/grpc/src/core/lib/support/env_posix.cc', - 'deps/grpc/src/core/lib/support/env_windows.cc', - 'deps/grpc/src/core/lib/support/fork.cc', - 'deps/grpc/src/core/lib/support/host_port.cc', - 'deps/grpc/src/core/lib/support/log.cc', - 'deps/grpc/src/core/lib/support/log_android.cc', - 'deps/grpc/src/core/lib/support/log_linux.cc', - 'deps/grpc/src/core/lib/support/log_posix.cc', - 'deps/grpc/src/core/lib/support/log_windows.cc', - 'deps/grpc/src/core/lib/support/mpscq.cc', - 'deps/grpc/src/core/lib/support/murmur_hash.cc', - 'deps/grpc/src/core/lib/support/string.cc', - 'deps/grpc/src/core/lib/support/string_posix.cc', - 'deps/grpc/src/core/lib/support/string_util_windows.cc', - 'deps/grpc/src/core/lib/support/string_windows.cc', - 'deps/grpc/src/core/lib/support/subprocess_posix.cc', - 'deps/grpc/src/core/lib/support/subprocess_windows.cc', - 'deps/grpc/src/core/lib/support/sync.cc', - 'deps/grpc/src/core/lib/support/sync_posix.cc', - 'deps/grpc/src/core/lib/support/sync_windows.cc', - 'deps/grpc/src/core/lib/support/thd.cc', - 'deps/grpc/src/core/lib/support/thd_posix.cc', - 'deps/grpc/src/core/lib/support/thd_windows.cc', - 'deps/grpc/src/core/lib/support/time.cc', - 'deps/grpc/src/core/lib/support/time_posix.cc', - 'deps/grpc/src/core/lib/support/time_precise.cc', - 'deps/grpc/src/core/lib/support/time_windows.cc', - 'deps/grpc/src/core/lib/support/tls_pthread.cc', - 'deps/grpc/src/core/lib/support/tmpfile_msys.cc', - 'deps/grpc/src/core/lib/support/tmpfile_posix.cc', - 'deps/grpc/src/core/lib/support/tmpfile_windows.cc', - 'deps/grpc/src/core/lib/support/wrap_memcpy.cc', ], 'conditions': [ ['OS == "mac"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index e5b7ddd59..1207963d7 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit e5b7ddd59c9a8b7a33820197abb45e12e2b65daf +Subproject commit 1207963d76020e4eee5653421df645daabc52c47 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 34c043395..f2223750f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.9.0-dev", + "version": "1.9.0-pre3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From e87552d918cfe6bb95b6e87fa60e4df635ea6670 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 5 Feb 2018 14:35:20 -0800 Subject: [PATCH 0082/1899] Fix documentation of part of the type signature for server credentials --- packages/grpc-native-core/index.d.ts | 4 ++-- packages/grpc-native-core/index.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 69c423d8f..2934ce922 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -573,12 +573,12 @@ declare module "grpc" { /** * The server's private key */ - privateKey: Buffer; + private_key: Buffer; /** * The server's certificate chain */ - certChain: Buffer; + cert_chain: Buffer; } /** diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 7810b7bff..fa07baebc 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -219,8 +219,8 @@ exports.ServerCredentials = grpc.ServerCredentials; /** * A private key and certificate pair * @typedef {Object} grpc.ServerCredentials~keyCertPair - * @property {Buffer} privateKey The server's private key - * @property {Buffer} certChain The server's certificate chain + * @property {Buffer} private_key The server's private key + * @property {Buffer} cert_chain The server's certificate chain */ /** From c2fd15584fdcdf5a8d438f33985a974c7e45981c Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 19 Dec 2017 11:57:35 -0800 Subject: [PATCH 0083/1899] grpc-js-core: docs for call.ts --- packages/grpc-js-core/src/call.ts | 29 +++++++++++++++++++++-------- packages/grpc-js-core/src/client.ts | 4 ++-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index 5abc04799..87a8d9ae5 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -7,16 +7,17 @@ import {Status} from './constants'; import {Metadata} from './metadata'; import {ObjectReadable, ObjectWritable} from './object-stream'; -export interface ServiceError extends Error { +/** + * A type extending the built-in Error object with additional fields. + */ +export type ServiceError = { code?: number; metadata?: Metadata; -} - -export class ServiceErrorImpl extends Error implements ServiceError { - code?: number; - metadata?: Metadata; -} +} & Error; +/** + * A base type for all user-facing values returned by client-side method calls. + */ export type Call = { cancel(): void; getPeer(): string; @@ -24,16 +25,28 @@ export type Call = { & EmitterAugmentation1<'status', StatusObject> & EventEmitter; +/** + * A type representing the return value of a unary method call. + */ export type ClientUnaryCall = Call; +/** + * A type representing the return value of a server stream method call. + */ export type ClientReadableStream = { deserialize: (chunk: Buffer) => ResponseType; } & Call & ObjectReadable; +/** + * A type representing the return value of a client stream method call. + */ export type ClientWritableStream = { serialize: (value: RequestType) => Buffer; } & Call & ObjectWritable; +/** + * A type representing the return value of a bidirectional stream method call. + */ export type ClientDuplexStream = ClientWritableStream & ClientReadableStream; @@ -78,7 +91,7 @@ function setUpReadableStream( call.on('status', (status: StatusObject) => { stream.emit('status', status); if (status.code !== Status.OK) { - const error = new ServiceErrorImpl(status.details); + const error: ServiceError = new Error(status.details); error.code = status.code; error.metadata = status.metadata; stream.emit('error', error); diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 862d212ce..ecfacccd1 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -1,7 +1,7 @@ import {once} from 'lodash'; import {URL} from 'url'; -import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError, ServiceErrorImpl} from './call'; +import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; import {CallOptions, CallStream, StatusObject, WriteObject} from './call-stream'; import {Channel, ChannelOptions, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; @@ -83,7 +83,7 @@ export class Client { if (status.code === Status.OK) { callback(null, responseMessage as ResponseType); } else { - const error = new ServiceErrorImpl(status.details); + const error: ServiceError = new Error(status.details); error.code = status.code; error.metadata = status.metadata; callback(error); From 5bd0386d8d72488371e280c15c5af2e82b94eab3 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 19 Dec 2017 13:57:41 -0800 Subject: [PATCH 0084/1899] grpc-js-core: support propagation cancellation --- packages/grpc-js-core/src/call-stream.ts | 2 -- packages/grpc-js-core/src/channel.ts | 25 +++++++++++++++++++++++- packages/grpc-js-core/src/client.ts | 4 ++-- packages/grpc-js-core/src/constants.ts | 8 ++++++++ 4 files changed, 34 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 877978a80..3a18d4732 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -19,8 +19,6 @@ export interface CallStreamOptions { flags: number; } -export type CallOptions = Partial; - export interface StatusObject { code: Status; details: string; diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 51ec1fa59..13ccab33d 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -3,16 +3,26 @@ import * as http2 from 'http2'; import {checkServerIdentity, SecureContext, PeerCertificate} from 'tls'; import * as url from 'url'; +import {Call} from './call'; import {CallCredentials} from './call-credentials'; import {CallCredentialsFilterFactory} from './call-credentials-filter'; -import {CallOptions, CallStream, CallStreamOptions, Http2CallStream} from './call-stream'; +import {CallStream, CallStreamOptions, Http2CallStream} from './call-stream'; import {ChannelCredentials} from './channel-credentials'; import {CompressionFilterFactory} from './compression-filter'; +import {EmitterAugmentation0} from './events'; import {Status} from './constants'; import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; import { MetadataStatusFilterFactory } from './metadata-status-filter'; +import { PropagateFlags } from './index'; + +export type CallOptions = { + // Represents a parent server call. + // For our purposes we only need to know of the 'cancelled' event. + parent?: EmitterAugmentation0<'cancelled'> & EventEmitter; + propagate_flags?: number; +} & Partial; const IDLE_TIMEOUT_MS = 300000; @@ -249,6 +259,19 @@ export class Http2Channel extends EventEmitter implements Channel { let stream: Http2CallStream = new Http2CallStream(methodName, finalOptions, this.filterStackFactory); this.startHttp2Stream(methodName, stream, metadata); + + // handle propagation flags + const propagateFlags = typeof options.propagate_flags === 'number' ? + options.propagate_flags : PropagateFlags.DEFAULTS; + if (options.parent) { + // TODO(kjin): Implement other propagation flags. + if (propagateFlags & PropagateFlags.CANCELLATION) { + options.parent.on('cancelled', () => { + stream.cancelWithStatus(Status.CANCELLED, 'Cancellation propagated from parent call'); + }); + } + } + return stream; } diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index ecfacccd1..c14328a91 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -2,8 +2,8 @@ import {once} from 'lodash'; import {URL} from 'url'; import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; -import {CallOptions, CallStream, StatusObject, WriteObject} from './call-stream'; -import {Channel, ChannelOptions, Http2Channel} from './channel'; +import {CallStream, StatusObject, WriteObject} from './call-stream'; +import {CallOptions, Channel, ChannelOptions, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; import {Status} from './constants'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js-core/src/constants.ts b/packages/grpc-js-core/src/constants.ts index a72f3388d..3b18d8701 100644 --- a/packages/grpc-js-core/src/constants.ts +++ b/packages/grpc-js-core/src/constants.ts @@ -17,3 +17,11 @@ export enum Status { DATA_LOSS, UNAUTHENTICATED } + +export enum PropagateFlags { + DEADLINE = 1, + CENSUS_STATS_CONTEXT = 2, + CENSUS_TRACING_CONTEXT = 4, + CANCELLATION = 8, + DEFAULTS = 65535 +} From b31f345c8d984aee633f20e34e3ee5b03b6c86bc Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 25 Jan 2018 11:26:02 -0800 Subject: [PATCH 0085/1899] Revert "grpc-js-core: support propagation cancellation" This reverts commit 8a31711431071084a3ad972b122a27653fe78be2. --- packages/grpc-js-core/src/call-stream.ts | 2 ++ packages/grpc-js-core/src/channel.ts | 25 +----------------------- packages/grpc-js-core/src/client.ts | 4 ++-- packages/grpc-js-core/src/constants.ts | 8 -------- 4 files changed, 5 insertions(+), 34 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 3a18d4732..877978a80 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -19,6 +19,8 @@ export interface CallStreamOptions { flags: number; } +export type CallOptions = Partial; + export interface StatusObject { code: Status; details: string; diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 13ccab33d..51ec1fa59 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -3,26 +3,16 @@ import * as http2 from 'http2'; import {checkServerIdentity, SecureContext, PeerCertificate} from 'tls'; import * as url from 'url'; -import {Call} from './call'; import {CallCredentials} from './call-credentials'; import {CallCredentialsFilterFactory} from './call-credentials-filter'; -import {CallStream, CallStreamOptions, Http2CallStream} from './call-stream'; +import {CallOptions, CallStream, CallStreamOptions, Http2CallStream} from './call-stream'; import {ChannelCredentials} from './channel-credentials'; import {CompressionFilterFactory} from './compression-filter'; -import {EmitterAugmentation0} from './events'; import {Status} from './constants'; import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; import { MetadataStatusFilterFactory } from './metadata-status-filter'; -import { PropagateFlags } from './index'; - -export type CallOptions = { - // Represents a parent server call. - // For our purposes we only need to know of the 'cancelled' event. - parent?: EmitterAugmentation0<'cancelled'> & EventEmitter; - propagate_flags?: number; -} & Partial; const IDLE_TIMEOUT_MS = 300000; @@ -259,19 +249,6 @@ export class Http2Channel extends EventEmitter implements Channel { let stream: Http2CallStream = new Http2CallStream(methodName, finalOptions, this.filterStackFactory); this.startHttp2Stream(methodName, stream, metadata); - - // handle propagation flags - const propagateFlags = typeof options.propagate_flags === 'number' ? - options.propagate_flags : PropagateFlags.DEFAULTS; - if (options.parent) { - // TODO(kjin): Implement other propagation flags. - if (propagateFlags & PropagateFlags.CANCELLATION) { - options.parent.on('cancelled', () => { - stream.cancelWithStatus(Status.CANCELLED, 'Cancellation propagated from parent call'); - }); - } - } - return stream; } diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index c14328a91..ecfacccd1 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -2,8 +2,8 @@ import {once} from 'lodash'; import {URL} from 'url'; import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; -import {CallStream, StatusObject, WriteObject} from './call-stream'; -import {CallOptions, Channel, ChannelOptions, Http2Channel} from './channel'; +import {CallOptions, CallStream, StatusObject, WriteObject} from './call-stream'; +import {Channel, ChannelOptions, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; import {Status} from './constants'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js-core/src/constants.ts b/packages/grpc-js-core/src/constants.ts index 3b18d8701..a72f3388d 100644 --- a/packages/grpc-js-core/src/constants.ts +++ b/packages/grpc-js-core/src/constants.ts @@ -17,11 +17,3 @@ export enum Status { DATA_LOSS, UNAUTHENTICATED } - -export enum PropagateFlags { - DEADLINE = 1, - CENSUS_STATS_CONTEXT = 2, - CENSUS_TRACING_CONTEXT = 4, - CANCELLATION = 8, - DEFAULTS = 65535 -} From bae93fff389a5fffdd7fac3c28a7febea355a0cf Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 19 Dec 2017 15:33:36 -0800 Subject: [PATCH 0086/1899] grpc-js-core: split incoming headers on comma for metadata --- packages/grpc-js-core/src/metadata.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index dbdb4e914..84e9160eb 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -181,6 +181,11 @@ export class Metadata { }); return result; } + + // For compatibility with the other Metadata implementation + private _getCoreRepresentation() { + return this.internalRepr; + } /** * Returns a new Metadata object based fields in a given IncomingHttpHeaders @@ -196,7 +201,8 @@ export class Metadata { result.add(key, Buffer.from(value, 'base64')); }); } else if (values !== undefined) { - result.add(key, Buffer.from(values, 'base64')); + values.split(',').map(v => v.trim()).forEach(v => + result.add(key, Buffer.from(v, 'base64'))); } } else { if (Array.isArray(values)) { @@ -204,7 +210,8 @@ export class Metadata { result.add(key, value); }); } else if (values !== undefined) { - result.add(key, values); + values.split(',').map(v => v.trim()).forEach(v => + result.add(key, v)); } } }); From e351cfe8c4934e13ee4dbc2b274d594739340eba Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 19 Dec 2017 16:35:05 -0800 Subject: [PATCH 0087/1899] grpc-js-core: add user-agent --- packages/grpc-js-core/src/channel.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 51ec1fa59..cd88e44d7 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -14,6 +14,8 @@ import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; import { MetadataStatusFilterFactory } from './metadata-status-filter'; +const { version: clientVersion } = require('../../package'); + const IDLE_TIMEOUT_MS = 300000; const MIN_CONNECT_TIMEOUT_MS = 20000; @@ -28,7 +30,8 @@ const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_SCHEME, - HTTP2_HEADER_TE + HTTP2_HEADER_TE, + HTTP2_HEADER_USER_AGENT } = http2.constants; /** @@ -209,6 +212,7 @@ export class Http2Channel extends EventEmitter implements Channel { .then(([metadataValue]) => { let headers = metadataValue.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname; + headers[HTTP2_HEADER_USER_AGENT] = `grpc-node/${clientVersion}`; headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = methodName; From b8bfc0fcd6181614893d8e54408647e89f96c7ac Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 20 Dec 2017 14:31:13 -0800 Subject: [PATCH 0088/1899] grpc-js-core: keep up-to-date with node-master --- packages/grpc-js-core/src/channel.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index cd88e44d7..6f6b72de0 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -115,7 +115,7 @@ export class Http2Channel extends EventEmitter implements Channel { case ConnectivityState.IDLE: case ConnectivityState.SHUTDOWN: if (this.subChannel) { - this.subChannel.shutdown({graceful: true}); + (this.subChannel as any).close({graceful: true}); this.subChannel.removeListener('connect', this.subChannelConnectCallback); this.subChannel.removeListener('close', this.subChannelCloseCallback); this.subChannel = null; @@ -153,7 +153,7 @@ export class Http2Channel extends EventEmitter implements Channel { return checkServerIdentity(sslTargetNameOverride, cert); } } - subChannel = http2.connect(this.authority, connectionOptions); + subChannel = http2.connect(this.authority, connectionOptions) as typeof subChannel; } this.subChannel = subChannel; let now = new Date(); @@ -162,7 +162,7 @@ export class Http2Channel extends EventEmitter implements Channel { MIN_CONNECT_TIMEOUT_MS); let connectionTimerId: NodeJS.Timer = setTimeout(() => { // This should trigger the 'close' event, which will send us back to TRANSIENT_FAILURE - subChannel.shutdown(); + (subChannel as any).close(); }, connectionTimeout); this.subChannelConnectCallback = () => { // Connection succeeded @@ -221,9 +221,7 @@ export class Http2Channel extends EventEmitter implements Channel { if (this.connectivityState === ConnectivityState.READY) { const session: http2.ClientHttp2Session = this.subChannel!; // Prevent the HTTP/2 session from keeping the process alive. - // TODO(kjin): Monitor nodejs/node#17620, which adds unref - // directly to the Http2Session object. - session.socket.unref(); + (session as any).unref(); stream.attachHttp2Stream(session.request(headers)); } else { /* In this case, we lost the connection while finalizing From 6b6443d215873a7704bb28a39463519077dd5e06 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Fri, 22 Dec 2017 14:49:51 -0800 Subject: [PATCH 0089/1899] grpc-js-core: clone local metadata before applying filters --- packages/grpc-js-core/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 6f6b72de0..16294b2ea 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -207,7 +207,7 @@ export class Http2Channel extends EventEmitter implements Channel { private startHttp2Stream( methodName: string, stream: Http2CallStream, metadata: Metadata) { let finalMetadata: Promise = - stream.filterStack.sendMetadata(Promise.resolve(metadata)); + stream.filterStack.sendMetadata(Promise.resolve(metadata.clone())); Promise.all([finalMetadata, this.connect()]) .then(([metadataValue]) => { let headers = metadataValue.toHttp2Headers(); From 1d1aa273f009383d43523a9d83ff7a7f47789a4b Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Fri, 22 Dec 2017 15:30:17 -0800 Subject: [PATCH 0090/1899] grpc-js-core: clear deadline timers --- packages/grpc-js-core/src/client.ts | 6 +++++- packages/grpc-js-core/src/deadline-filter.ts | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index ecfacccd1..f3a1de268 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -35,7 +35,11 @@ export class Client { void { let cb: (error: Error|null) => void = once(callback); let callbackCalled = false; + let timer: NodeJS.Timer | null = null; this.channel.connect().then(() => { + if (timer) { + clearTimeout(timer); + } cb(null); }); if (deadline !== Infinity) { @@ -49,7 +53,7 @@ export class Client { if (timeout < 0) { timeout = 0; } - setTimeout(() => { + timer = setTimeout(() => { cb(new Error('Failed to connect before the deadline')); }, timeout); } diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index c3ed045bf..428ed8a95 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -20,6 +20,7 @@ function getDeadline(deadline: number) { } export class DeadlineFilter extends BaseFilter implements Filter { + private timer: NodeJS.Timer | null = null; private deadline: number; constructor( private readonly channel: Http2Channel, @@ -37,10 +38,11 @@ export class DeadlineFilter extends BaseFilter implements Filter { timeout = 0; } if (this.deadline !== Infinity) { - setTimeout(() => { + this.timer = setTimeout(() => { callStream.cancelWithStatus( Status.DEADLINE_EXCEEDED, 'Deadline exceeded'); }, timeout); + callStream.on('status', () => clearTimeout(this.timer as NodeJS.Timer)); } } From 063e11162ea5cf635cc2cd70a5dc5909a3032611 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Fri, 22 Dec 2017 15:30:37 -0800 Subject: [PATCH 0091/1899] grpc-js-core: change rstStream to close --- packages/grpc-js-core/src/call-stream.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 877978a80..3fc9c12ef 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -9,7 +9,7 @@ import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; import {ObjectDuplex} from './object-stream'; -const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE} = http2.constants; +const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = http2.constants; export type Deadline = Date | number; @@ -156,7 +156,7 @@ export class Http2CallStream extends Duplex implements CallStream { attachHttp2Stream(stream: http2.ClientHttp2Stream): void { if (this.finalStatus !== null) { - stream.rstWithCancel(); + (stream as any).close(NGHTTP2_CANCEL); } else { this.http2Stream = stream; stream.on('response', (headers, flags) => { @@ -328,7 +328,7 @@ export class Http2CallStream extends Duplex implements CallStream { if (this.http2Stream !== null && !this.http2Stream.destroyed) { /* TODO(murgatroid99): Determine if we want to send different RST_STREAM * codes based on the status code */ - this.http2Stream.rstWithCancel(); + (this.http2Stream as any).close(NGHTTP2_CANCEL); } } From 5e00d18362373ab9c7f000716db80b7d950c49d8 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 31 Jan 2018 13:55:14 -0800 Subject: [PATCH 0092/1899] address comments --- packages/grpc-js-core/src/call.ts | 12 +++++------- packages/grpc-js-core/src/channel.ts | 23 ++++++++++++++++++----- packages/grpc-js-core/src/client.ts | 13 ++----------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index 87a8d9ae5..af305b244 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -6,14 +6,12 @@ import {CallStream, StatusObject, WriteObject} from './call-stream'; import {Status} from './constants'; import {Metadata} from './metadata'; import {ObjectReadable, ObjectWritable} from './object-stream'; +import * as _ from 'lodash'; /** * A type extending the built-in Error object with additional fields. */ -export type ServiceError = { - code?: number; - metadata?: Metadata; -} & Error; +export type ServiceError = StatusObject & Error; /** * A base type for all user-facing values returned by client-side method calls. @@ -91,9 +89,9 @@ function setUpReadableStream( call.on('status', (status: StatusObject) => { stream.emit('status', status); if (status.code !== Status.OK) { - const error: ServiceError = new Error(status.details); - error.code = status.code; - error.metadata = status.metadata; + const statusName = _.invert(Status)[status.code]; + const message: string = `${status.code} ${statusName}: ${status.details}`; + const error: ServiceError = Object.assign(new Error(status.details), status); stream.emit('error', error); } }); diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 16294b2ea..bc5d95d72 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -37,7 +37,12 @@ const { /** * An interface that contains options used when initializing a Channel instance. */ -export interface ChannelOptions { [index: string]: string|number; } +export interface ChannelOptions { + 'grpc.ssl_target_name_override': string; + 'grpc.primary_user_agent': string; + 'grpc.secondary_user_agent': string; + [key: string]: string | number; +} export enum ConnectivityState { CONNECTING, @@ -75,6 +80,7 @@ export interface Channel extends EventEmitter { } export class Http2Channel extends EventEmitter implements Channel { + private readonly userAgent: string; private readonly authority: url.URL; private connectivityState: ConnectivityState = ConnectivityState.IDLE; /* For now, we have up to one subchannel, which will exist as long as we are @@ -148,12 +154,12 @@ export class Http2Channel extends EventEmitter implements Channel { // to override the target hostname when checking server identity. // This option is used for testing only. if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = this.options['grpc.ssl_target_name_override'] as string; + const sslTargetNameOverride = this.options['grpc.ssl_target_name_override']!; connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate): Error | undefined => { return checkServerIdentity(sslTargetNameOverride, cert); } } - subChannel = http2.connect(this.authority, connectionOptions) as typeof subChannel; + subChannel = http2.connect(this.authority, connectionOptions); } this.subChannel = subChannel; let now = new Date(); @@ -184,7 +190,7 @@ export class Http2Channel extends EventEmitter implements Channel { constructor( address: string, public readonly credentials: ChannelCredentials, - private readonly options: ChannelOptions) { + private readonly options: Partial) { super(); if (credentials.getSecureContext() === null) { this.authority = new url.URL(`http://${address}`); @@ -202,6 +208,13 @@ export class Http2Channel extends EventEmitter implements Channel { * a value of type NodeJS.Timer. */ this.backoffTimerId = setTimeout(() => {}, 0); clearTimeout(this.backoffTimerId); + + // Build user-agent string. + this.userAgent = [ + options['grpc.primary_user_agent'], + `grpc-node-js/${clientVersion}`, + options['grpc.secondary_user_agent'] + ].filter(e => e).join(' '); // remove falsey values first } private startHttp2Stream( @@ -212,7 +225,7 @@ export class Http2Channel extends EventEmitter implements Channel { .then(([metadataValue]) => { let headers = metadataValue.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname; - headers[HTTP2_HEADER_USER_AGENT] = `grpc-node/${clientVersion}`; + headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = methodName; diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index f3a1de268..5f9c670bd 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -16,14 +16,7 @@ export class Client { private readonly channel: Channel; constructor( address: string, credentials: ChannelCredentials, - options: ChannelOptions = {}) { - if (options['grpc.primary_user_agent']) { - options['grpc.primary_user_agent'] += ' '; - } else { - options['grpc.primary_user_agent'] = ''; - } - // TODO(murgatroid99): Figure out how to get version number - // options['grpc.primary_user_agent'] += 'grpc-node/' + version; + options: Partial = {}) { this.channel = new Http2Channel(address, credentials, options); } @@ -87,9 +80,7 @@ export class Client { if (status.code === Status.OK) { callback(null, responseMessage as ResponseType); } else { - const error: ServiceError = new Error(status.details); - error.code = status.code; - error.metadata = status.metadata; + const error: ServiceError = Object.assign(new Error(status.details), status); callback(error); } }); From 2f77364fe5dcfcd774e05f0a3a3dc2e6402db0a0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Feb 2018 09:48:24 -0800 Subject: [PATCH 0093/1899] Update version to 1.9.0 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 1207963d7..9b075f1cc 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 1207963d76020e4eee5653421df645daabc52c47 +Subproject commit 9b075f1cc060a28306ca9f98227e01f86f7a3b91 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f2223750f..ec5beb037 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.9.0-pre3", + "version": "1.9.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 51c8503c0107a3b17eef749abaa677e8ad8e0450 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Feb 2018 10:21:18 -0800 Subject: [PATCH 0094/1899] Improve module load error message when the directory does not exist --- .../grpc-native-core/src/grpc_extension.js | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/src/grpc_extension.js b/packages/grpc-native-core/src/grpc_extension.js index 46e2721d1..0ef399d17 100644 --- a/packages/grpc-native-core/src/grpc_extension.js +++ b/packages/grpc-native-core/src/grpc_extension.js @@ -31,17 +31,27 @@ var binding; try { binding = require(binding_path); } catch (e) { - var fs = require('fs'); - var searchPath = path.dirname(path.dirname(binding_path)); - var searchName = path.basename(path.dirname(binding_path)); - var foundNames = fs.readdirSync(searchPath); + let fs = require('fs'); + let searchPath = path.dirname(path.dirname(binding_path)); + let searchName = path.basename(path.dirname(binding_path)); + let foundNames; + try { + foundNames = fs.readdirSync(searchPath); + } catch (readDirError) { + let message = `The gRPC binary module was not installed +This may be fixed by running "npm rebuild" +Original error: ${e.message}`; + let error = new Error(message); + error.code = e.code; + throw error; + } if (foundNames.indexOf(searchName) === -1) { - var message = `Failed to load gRPC binary module because it was not installed for the current system + let message = `Failed to load gRPC binary module because it was not installed for the current system Expected directory: ${searchName} Found: [${foundNames.join(', ')}] This problem can often be fixed by running "npm rebuild" on the current system Original error: ${e.message}`; - var error = new Error(message); + let error = new Error(message); error.code = e.code; throw error; } else { From b7f122bb6cc236196ed6968e63f1185eabf43858 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Feb 2018 11:35:20 -0800 Subject: [PATCH 0095/1899] Merge two lines of the error message --- packages/grpc-native-core/src/grpc_extension.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/grpc_extension.js b/packages/grpc-native-core/src/grpc_extension.js index 0ef399d17..9a023b7c3 100644 --- a/packages/grpc-native-core/src/grpc_extension.js +++ b/packages/grpc-native-core/src/grpc_extension.js @@ -38,8 +38,7 @@ try { try { foundNames = fs.readdirSync(searchPath); } catch (readDirError) { - let message = `The gRPC binary module was not installed -This may be fixed by running "npm rebuild" + let message = `The gRPC binary module was not installed. This may be fixed by running "npm rebuild" Original error: ${e.message}`; let error = new Error(message); error.code = e.code; From 2f649e5d059efd8277b44dca0540c3d4a2a67a4a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 9 Feb 2018 11:12:27 -0800 Subject: [PATCH 0096/1899] Fix usage of Protobuf.js Message type in TS file --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 2934ce922..73a685cd4 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -66,7 +66,7 @@ declare module "grpc" { * - Anything else becomes the relevant reflection object that ProtoBuf.js would create */ export interface GrpcObject { - [name: string]: GrpcObject | typeof Client | Message; + [name: string]: GrpcObject | typeof Client | Message; } /** From ca2704912c083249cc490d0a055dd59f831895aa Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 12 Feb 2018 16:57:48 -0800 Subject: [PATCH 0097/1899] Fix handling of undefined values for optional call arguments --- packages/grpc-native-core/src/client.js | 36 ++++++-- test/api/surface_test.js | 110 ++++++++++++++++++++++++ 2 files changed, 138 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index b9de0ab54..a917cbc9a 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -513,13 +513,23 @@ exports.Client = Client; Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, argument, metadata, options, callback) { - if (!(metadata instanceof Metadata)) { + if (options instanceof Function) { callback = options; - options = metadata; + if (metadata instanceof Metadata) { + options = {}; + } else { + options = metadata; + metadata = new Metadata(); + } + } else if (metadata instanceof Function) { + callback = metadata; metadata = new Metadata(); + options = {}; } - if (options instanceof Function) { - callback = options; + if (!metadata) { + metadata = new Metadata(); + } + if (!options) { options = {}; } if (!((metadata instanceof Metadata) && @@ -599,13 +609,23 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, Client.prototype.makeClientStreamRequest = function(method, serialize, deserialize, metadata, options, callback) { - if (!(metadata instanceof Metadata)) { + if (options instanceof Function) { callback = options; - options = metadata; + if (metadata instanceof Metadata) { + options = {}; + } else { + options = metadata; + metadata = new Metadata(); + } + } else if (metadata instanceof Function) { + callback = metadata; metadata = new Metadata(); + options = {}; } - if (options instanceof Function) { - callback = options; + if (!metadata) { + metadata = new Metadata(); + } + if (!options) { options = {}; } if (!((metadata instanceof Metadata) && diff --git a/test/api/surface_test.js b/test/api/surface_test.js index 3bffaf8e3..928024350 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -506,6 +506,116 @@ describe('Echo metadata', function() { done(); }); }); + describe('Call argument handling', function() { + describe('Unary call', function() { + it('Should handle undefined options', function(done) { + var call = client.unary({}, metadata, undefined, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + }); + it('Should handle two undefined arguments', function(done) { + var call = client.unary({}, undefined, undefined, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + done(); + }); + }); + it('Should handle one undefined argument', function(done) { + var call = client.unary({}, undefined, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + done(); + }); + }); + }); + describe('Client stream call', function() { + it('Should handle undefined options', function(done) { + var call = client.clientStream(metadata, undefined, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + call.end(); + }); + it('Should handle two undefined arguments', function(done) { + var call = client.clientStream(undefined, undefined, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + done(); + }); + call.end(); + }); + it('Should handle one undefined argument', function(done) { + var call = client.clientStream(undefined, function(err, data) { + assert.ifError(err); + }); + call.on('metadata', function(metadata) { + done(); + }); + call.end(); + }); + }); + describe('Server stream call', function() { + it('Should handle undefined options', function(done) { + var call = client.serverStream({}, metadata, undefined); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + }); + it('Should handle two undefined arguments', function(done) { + var call = client.serverStream({}, undefined, undefined); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + done(); + }); + }); + it('Should handle one undefined argument', function(done) { + var call = client.serverStream({}, undefined); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + done(); + }); + }); + }); + describe('Bidi stream call', function() { + it('Should handle undefined options', function(done) { + var call = client.bidiStream(metadata, undefined); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + assert.deepEqual(metadata.get('key'), ['value']); + done(); + }); + call.end(); + }); + it('Should handle two undefined arguments', function(done) { + var call = client.bidiStream(undefined, undefined); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + done(); + }); + call.end(); + }); + it('Should handle one undefined argument', function(done) { + var call = client.bidiStream(undefined); + call.on('data', function() {}); + call.on('metadata', function(metadata) { + done(); + }); + call.end(); + }); + }); + }); }); describe('Client malformed response handling', function() { var server; From 8108cc606e6d86a3f3e46507d0069231f0a593ee Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 13 Feb 2018 16:43:44 -0500 Subject: [PATCH 0098/1899] grpc-js-core: update type definitions --- packages/grpc-js-core/package.json | 2 +- packages/grpc-js-core/src/call-stream.ts | 4 ++-- packages/grpc-js-core/src/channel.ts | 6 +++--- packages/grpc-js-core/test/test-call-stream.ts | 3 +++ 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index e0d48bd4b..ffdc2b4a4 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -16,7 +16,7 @@ "devDependencies": { "@types/lodash": "^4.14.77", "@types/mocha": "^2.2.43", - "@types/node": "^8.0.55", + "@types/node": "^9.4.6", "clang-format": "^1.0.55", "gts": "^0.5.1", "typescript": "~2.7.0" diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 3fc9c12ef..849d685fb 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -156,7 +156,7 @@ export class Http2CallStream extends Duplex implements CallStream { attachHttp2Stream(stream: http2.ClientHttp2Stream): void { if (this.finalStatus !== null) { - (stream as any).close(NGHTTP2_CANCEL); + stream.close(NGHTTP2_CANCEL); } else { this.http2Stream = stream; stream.on('response', (headers, flags) => { @@ -328,7 +328,7 @@ export class Http2CallStream extends Duplex implements CallStream { if (this.http2Stream !== null && !this.http2Stream.destroyed) { /* TODO(murgatroid99): Determine if we want to send different RST_STREAM * codes based on the status code */ - (this.http2Stream as any).close(NGHTTP2_CANCEL); + this.http2Stream.close(NGHTTP2_CANCEL); } } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index bc5d95d72..193ae9a55 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -121,7 +121,7 @@ export class Http2Channel extends EventEmitter implements Channel { case ConnectivityState.IDLE: case ConnectivityState.SHUTDOWN: if (this.subChannel) { - (this.subChannel as any).close({graceful: true}); + this.subChannel.close(); this.subChannel.removeListener('connect', this.subChannelConnectCallback); this.subChannel.removeListener('close', this.subChannelCloseCallback); this.subChannel = null; @@ -168,7 +168,7 @@ export class Http2Channel extends EventEmitter implements Channel { MIN_CONNECT_TIMEOUT_MS); let connectionTimerId: NodeJS.Timer = setTimeout(() => { // This should trigger the 'close' event, which will send us back to TRANSIENT_FAILURE - (subChannel as any).close(); + subChannel.close(); }, connectionTimeout); this.subChannelConnectCallback = () => { // Connection succeeded @@ -234,7 +234,7 @@ export class Http2Channel extends EventEmitter implements Channel { if (this.connectivityState === ConnectivityState.READY) { const session: http2.ClientHttp2Session = this.subChannel!; // Prevent the HTTP/2 session from keeping the process alive. - (session as any).unref(); + session.unref(); stream.attachHttp2Stream(session.request(headers)); } else { /* In this case, we lost the connection while finalizing diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index 91d694dc3..0e142e40c 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -39,10 +39,13 @@ class ClientHttp2StreamMock extends stream.Duplex implements http2.ClientHttp2St bytesRead = 0; dataFrame = 0; aborted: boolean = false; + closed: boolean = false; destroyed: boolean = false; + pending: boolean = false; rstCode: number = 0; session: http2.Http2Session = {} as any; state: http2.StreamState = {} as any; + close = mockFunction; priority = mockFunction; rstStream = mockFunction; rstWithNoError = mockFunction; From d6c5c4f9da506c2634724ccd032259e26ba4dceb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 13 Feb 2018 17:50:16 -0800 Subject: [PATCH 0099/1899] Update version to 1.9.1 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 9b075f1cc..d45132a2e 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 9b075f1cc060a28306ca9f98227e01f86f7a3b91 +Subproject commit d45132a2e9246b11ddd0b70c07160076d5cbbb12 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ec5beb037..28718ad06 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.9.0", + "version": "1.9.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From ba404dce91254978fccdde0fa5ac316ac21981d4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Feb 2018 18:20:05 -0800 Subject: [PATCH 0100/1899] Update core on master --- packages/grpc-native-core/binding.gyp | 86 ++++++++++++-------------- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 09754efdf..b106b22e1 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -601,50 +601,46 @@ 'dependencies': [ ], 'sources': [ + 'deps/grpc/src/core/lib/gpr/alloc.cc', + 'deps/grpc/src/core/lib/gpr/arena.cc', + 'deps/grpc/src/core/lib/gpr/atm.cc', + 'deps/grpc/src/core/lib/gpr/cpu_iphone.cc', + 'deps/grpc/src/core/lib/gpr/cpu_linux.cc', + 'deps/grpc/src/core/lib/gpr/cpu_posix.cc', + 'deps/grpc/src/core/lib/gpr/cpu_windows.cc', + 'deps/grpc/src/core/lib/gpr/env_linux.cc', + 'deps/grpc/src/core/lib/gpr/env_posix.cc', + 'deps/grpc/src/core/lib/gpr/env_windows.cc', + 'deps/grpc/src/core/lib/gpr/fork.cc', + 'deps/grpc/src/core/lib/gpr/host_port.cc', + 'deps/grpc/src/core/lib/gpr/log.cc', + 'deps/grpc/src/core/lib/gpr/log_android.cc', + 'deps/grpc/src/core/lib/gpr/log_linux.cc', + 'deps/grpc/src/core/lib/gpr/log_posix.cc', + 'deps/grpc/src/core/lib/gpr/log_windows.cc', + 'deps/grpc/src/core/lib/gpr/mpscq.cc', + 'deps/grpc/src/core/lib/gpr/murmur_hash.cc', + 'deps/grpc/src/core/lib/gpr/string.cc', + 'deps/grpc/src/core/lib/gpr/string_posix.cc', + 'deps/grpc/src/core/lib/gpr/string_util_windows.cc', + 'deps/grpc/src/core/lib/gpr/string_windows.cc', + 'deps/grpc/src/core/lib/gpr/sync.cc', + 'deps/grpc/src/core/lib/gpr/sync_posix.cc', + 'deps/grpc/src/core/lib/gpr/sync_windows.cc', + 'deps/grpc/src/core/lib/gpr/thd.cc', + 'deps/grpc/src/core/lib/gpr/thd_posix.cc', + 'deps/grpc/src/core/lib/gpr/thd_windows.cc', + 'deps/grpc/src/core/lib/gpr/time.cc', + 'deps/grpc/src/core/lib/gpr/time_posix.cc', + 'deps/grpc/src/core/lib/gpr/time_precise.cc', + 'deps/grpc/src/core/lib/gpr/time_windows.cc', + 'deps/grpc/src/core/lib/gpr/tls_pthread.cc', + 'deps/grpc/src/core/lib/gpr/tmpfile_msys.cc', + 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', + 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', + 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', 'deps/grpc/src/core/lib/profiling/stap_timers.cc', - 'deps/grpc/src/core/lib/support/alloc.cc', - 'deps/grpc/src/core/lib/support/arena.cc', - 'deps/grpc/src/core/lib/support/atm.cc', - 'deps/grpc/src/core/lib/support/avl.cc', - 'deps/grpc/src/core/lib/support/cmdline.cc', - 'deps/grpc/src/core/lib/support/cpu_iphone.cc', - 'deps/grpc/src/core/lib/support/cpu_linux.cc', - 'deps/grpc/src/core/lib/support/cpu_posix.cc', - 'deps/grpc/src/core/lib/support/cpu_windows.cc', - 'deps/grpc/src/core/lib/support/env_linux.cc', - 'deps/grpc/src/core/lib/support/env_posix.cc', - 'deps/grpc/src/core/lib/support/env_windows.cc', - 'deps/grpc/src/core/lib/support/fork.cc', - 'deps/grpc/src/core/lib/support/host_port.cc', - 'deps/grpc/src/core/lib/support/log.cc', - 'deps/grpc/src/core/lib/support/log_android.cc', - 'deps/grpc/src/core/lib/support/log_linux.cc', - 'deps/grpc/src/core/lib/support/log_posix.cc', - 'deps/grpc/src/core/lib/support/log_windows.cc', - 'deps/grpc/src/core/lib/support/mpscq.cc', - 'deps/grpc/src/core/lib/support/murmur_hash.cc', - 'deps/grpc/src/core/lib/support/string.cc', - 'deps/grpc/src/core/lib/support/string_posix.cc', - 'deps/grpc/src/core/lib/support/string_util_windows.cc', - 'deps/grpc/src/core/lib/support/string_windows.cc', - 'deps/grpc/src/core/lib/support/subprocess_posix.cc', - 'deps/grpc/src/core/lib/support/subprocess_windows.cc', - 'deps/grpc/src/core/lib/support/sync.cc', - 'deps/grpc/src/core/lib/support/sync_posix.cc', - 'deps/grpc/src/core/lib/support/sync_windows.cc', - 'deps/grpc/src/core/lib/support/thd.cc', - 'deps/grpc/src/core/lib/support/thd_posix.cc', - 'deps/grpc/src/core/lib/support/thd_windows.cc', - 'deps/grpc/src/core/lib/support/time.cc', - 'deps/grpc/src/core/lib/support/time_posix.cc', - 'deps/grpc/src/core/lib/support/time_precise.cc', - 'deps/grpc/src/core/lib/support/time_windows.cc', - 'deps/grpc/src/core/lib/support/tls_pthread.cc', - 'deps/grpc/src/core/lib/support/tmpfile_msys.cc', - 'deps/grpc/src/core/lib/support/tmpfile_posix.cc', - 'deps/grpc/src/core/lib/support/tmpfile_windows.cc', - 'deps/grpc/src/core/lib/support/wrap_memcpy.cc', ], 'conditions': [ ['OS == "mac"', { @@ -663,6 +659,7 @@ ], 'sources': [ 'deps/grpc/src/core/lib/surface/init.cc', + 'deps/grpc/src/core/lib/avl/avl.cc', 'deps/grpc/src/core/lib/backoff/backoff.cc', 'deps/grpc/src/core/lib/channel/channel_args.cc', 'deps/grpc/src/core/lib/channel/channel_stack.cc', @@ -672,6 +669,7 @@ 'deps/grpc/src/core/lib/channel/handshaker_factory.cc', 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', 'deps/grpc/src/core/lib/compression/compression.cc', + 'deps/grpc/src/core/lib/compression/compression_internal.cc', 'deps/grpc/src/core/lib/compression/message_compress.cc', 'deps/grpc/src/core/lib/compression/stream_compression.cc', 'deps/grpc/src/core/lib/compression/stream_compression_gzip.cc', @@ -764,7 +762,6 @@ 'deps/grpc/src/core/lib/slice/slice_hash_table.cc', 'deps/grpc/src/core/lib/slice/slice_intern.cc', 'deps/grpc/src/core/lib/slice/slice_string_helpers.cc', - 'deps/grpc/src/core/lib/surface/alarm.cc', 'deps/grpc/src/core/lib/surface/api_trace.cc', 'deps/grpc/src/core/lib/surface/byte_buffer.cc', 'deps/grpc/src/core/lib/surface/byte_buffer_reader.cc', @@ -849,8 +846,8 @@ 'deps/grpc/src/core/lib/security/transport/tsi_error.cc', 'deps/grpc/src/core/lib/security/util/json_util.cc', 'deps/grpc/src/core/lib/surface/init_secure.cc', + 'deps/grpc/src/core/tsi/alts_transport_security.cc', 'deps/grpc/src/core/tsi/fake_transport_security.cc', - 'deps/grpc/src/core/tsi/gts_transport_security.cc', 'deps/grpc/src/core/tsi/ssl_transport_security.cc', 'deps/grpc/src/core/tsi/transport_security_grpc.cc', 'deps/grpc/src/core/tsi/transport_security.cc', @@ -872,7 +869,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.cc', 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index e5b7ddd59..34e8e0a64 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit e5b7ddd59c9a8b7a33820197abb45e12e2b65daf +Subproject commit 34e8e0a6400d8b529125a3b83ec1facf71acf99b diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 34c043395..44b029d66 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.9.0-dev", + "version": "1.10.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 512453846638b95d5ef4af2c963c4dbdc363d377 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Feb 2018 09:56:03 -0800 Subject: [PATCH 0101/1899] Regenerate build file with updated BoringSSL submodule --- packages/grpc-native-core/binding.gyp | 181 ++++++++++---------------- 1 file changed, 66 insertions(+), 115 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b106b22e1..85f0618ef 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -219,9 +219,6 @@ ], 'sources': [ 'deps/grpc/src/boringssl/err_data.c', - 'deps/grpc/third_party/boringssl/crypto/aes/aes.c', - 'deps/grpc/third_party/boringssl/crypto/aes/key_wrap.c', - 'deps/grpc/third_party/boringssl/crypto/aes/mode_wrappers.c', 'deps/grpc/third_party/boringssl/crypto/asn1/a_bitstr.c', 'deps/grpc/third_party/boringssl/crypto/asn1/a_bool.c', 'deps/grpc/third_party/boringssl/crypto/asn1/a_d2i_fp.c', @@ -245,7 +242,6 @@ 'deps/grpc/third_party/boringssl/crypto/asn1/f_enum.c', 'deps/grpc/third_party/boringssl/crypto/asn1/f_int.c', 'deps/grpc/third_party/boringssl/crypto/asn1/f_string.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/t_bitst.c', 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_dec.c', 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_enc.c', 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_fre.c', @@ -253,8 +249,6 @@ 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_typ.c', 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_utl.c', 'deps/grpc/third_party/boringssl/crypto/asn1/time_support.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/x_bignum.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/x_long.c', 'deps/grpc/third_party/boringssl/crypto/base64/base64.c', 'deps/grpc/third_party/boringssl/crypto/bio/bio.c', 'deps/grpc/third_party/boringssl/crypto/bio/bio_mem.c', @@ -266,44 +260,25 @@ 'deps/grpc/third_party/boringssl/crypto/bio/printf.c', 'deps/grpc/third_party/boringssl/crypto/bio/socket.c', 'deps/grpc/third_party/boringssl/crypto/bio/socket_helper.c', - 'deps/grpc/third_party/boringssl/crypto/bn/add.c', - 'deps/grpc/third_party/boringssl/crypto/bn/asm/x86_64-gcc.c', - 'deps/grpc/third_party/boringssl/crypto/bn/bn.c', - 'deps/grpc/third_party/boringssl/crypto/bn/bn_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/bn/cmp.c', - 'deps/grpc/third_party/boringssl/crypto/bn/convert.c', - 'deps/grpc/third_party/boringssl/crypto/bn/ctx.c', - 'deps/grpc/third_party/boringssl/crypto/bn/div.c', - 'deps/grpc/third_party/boringssl/crypto/bn/exponentiation.c', - 'deps/grpc/third_party/boringssl/crypto/bn/gcd.c', - 'deps/grpc/third_party/boringssl/crypto/bn/generic.c', - 'deps/grpc/third_party/boringssl/crypto/bn/kronecker.c', - 'deps/grpc/third_party/boringssl/crypto/bn/montgomery.c', - 'deps/grpc/third_party/boringssl/crypto/bn/montgomery_inv.c', - 'deps/grpc/third_party/boringssl/crypto/bn/mul.c', - 'deps/grpc/third_party/boringssl/crypto/bn/prime.c', - 'deps/grpc/third_party/boringssl/crypto/bn/random.c', - 'deps/grpc/third_party/boringssl/crypto/bn/rsaz_exp.c', - 'deps/grpc/third_party/boringssl/crypto/bn/shift.c', - 'deps/grpc/third_party/boringssl/crypto/bn/sqrt.c', + 'deps/grpc/third_party/boringssl/crypto/bn_extra/bn_asn1.c', + 'deps/grpc/third_party/boringssl/crypto/bn_extra/convert.c', 'deps/grpc/third_party/boringssl/crypto/buf/buf.c', 'deps/grpc/third_party/boringssl/crypto/bytestring/asn1_compat.c', 'deps/grpc/third_party/boringssl/crypto/bytestring/ber.c', 'deps/grpc/third_party/boringssl/crypto/bytestring/cbb.c', 'deps/grpc/third_party/boringssl/crypto/bytestring/cbs.c', 'deps/grpc/third_party/boringssl/crypto/chacha/chacha.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/aead.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/cipher.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/derive_key.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_aes.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_chacha20poly1305.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_des.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_null.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_rc2.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_rc4.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_ssl3.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/e_tls.c', - 'deps/grpc/third_party/boringssl/crypto/cipher/tls_cbc.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/cipher_extra.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/derive_key.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesctrhmac.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesgcmsiv.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_chacha20poly1305.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_null.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_rc2.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_rc4.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_ssl3.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_tls.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/tls_cbc.c', 'deps/grpc/third_party/boringssl/crypto/cmac/cmac.c', 'deps/grpc/third_party/boringssl/crypto/conf/conf.c', 'deps/grpc/third_party/boringssl/crypto/cpu-aarch64-linux.c', @@ -315,29 +290,16 @@ 'deps/grpc/third_party/boringssl/crypto/curve25519/curve25519.c', 'deps/grpc/third_party/boringssl/crypto/curve25519/spake25519.c', 'deps/grpc/third_party/boringssl/crypto/curve25519/x25519-x86_64.c', - 'deps/grpc/third_party/boringssl/crypto/des/des.c', 'deps/grpc/third_party/boringssl/crypto/dh/check.c', 'deps/grpc/third_party/boringssl/crypto/dh/dh.c', 'deps/grpc/third_party/boringssl/crypto/dh/dh_asn1.c', 'deps/grpc/third_party/boringssl/crypto/dh/params.c', - 'deps/grpc/third_party/boringssl/crypto/digest/digest.c', - 'deps/grpc/third_party/boringssl/crypto/digest/digests.c', + 'deps/grpc/third_party/boringssl/crypto/digest_extra/digest_extra.c', 'deps/grpc/third_party/boringssl/crypto/dsa/dsa.c', 'deps/grpc/third_party/boringssl/crypto/dsa/dsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/ec/ec.c', - 'deps/grpc/third_party/boringssl/crypto/ec/ec_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/ec/ec_key.c', - 'deps/grpc/third_party/boringssl/crypto/ec/ec_montgomery.c', - 'deps/grpc/third_party/boringssl/crypto/ec/oct.c', - 'deps/grpc/third_party/boringssl/crypto/ec/p224-64.c', - 'deps/grpc/third_party/boringssl/crypto/ec/p256-64.c', - 'deps/grpc/third_party/boringssl/crypto/ec/p256-x86_64.c', - 'deps/grpc/third_party/boringssl/crypto/ec/simple.c', - 'deps/grpc/third_party/boringssl/crypto/ec/util-64.c', - 'deps/grpc/third_party/boringssl/crypto/ec/wnaf.c', + 'deps/grpc/third_party/boringssl/crypto/ec_extra/ec_asn1.c', 'deps/grpc/third_party/boringssl/crypto/ecdh/ecdh.c', - 'deps/grpc/third_party/boringssl/crypto/ecdsa/ecdsa.c', - 'deps/grpc/third_party/boringssl/crypto/ecdsa/ecdsa_asn1.c', + 'deps/grpc/third_party/boringssl/crypto/ecdsa_extra/ecdsa_asn1.c', 'deps/grpc/third_party/boringssl/crypto/engine/engine.c', 'deps/grpc/third_party/boringssl/crypto/err/err.c', 'deps/grpc/third_party/boringssl/crypto/evp/digestsign.c', @@ -347,24 +309,20 @@ 'deps/grpc/third_party/boringssl/crypto/evp/p_dsa_asn1.c', 'deps/grpc/third_party/boringssl/crypto/evp/p_ec.c', 'deps/grpc/third_party/boringssl/crypto/evp/p_ec_asn1.c', + 'deps/grpc/third_party/boringssl/crypto/evp/p_ed25519.c', + 'deps/grpc/third_party/boringssl/crypto/evp/p_ed25519_asn1.c', 'deps/grpc/third_party/boringssl/crypto/evp/p_rsa.c', 'deps/grpc/third_party/boringssl/crypto/evp/p_rsa_asn1.c', 'deps/grpc/third_party/boringssl/crypto/evp/pbkdf.c', 'deps/grpc/third_party/boringssl/crypto/evp/print.c', + 'deps/grpc/third_party/boringssl/crypto/evp/scrypt.c', 'deps/grpc/third_party/boringssl/crypto/evp/sign.c', 'deps/grpc/third_party/boringssl/crypto/ex_data.c', + 'deps/grpc/third_party/boringssl/crypto/fipsmodule/bcm.c', + 'deps/grpc/third_party/boringssl/crypto/fipsmodule/is_fips.c', 'deps/grpc/third_party/boringssl/crypto/hkdf/hkdf.c', - 'deps/grpc/third_party/boringssl/crypto/hmac/hmac.c', 'deps/grpc/third_party/boringssl/crypto/lhash/lhash.c', - 'deps/grpc/third_party/boringssl/crypto/md4/md4.c', - 'deps/grpc/third_party/boringssl/crypto/md5/md5.c', 'deps/grpc/third_party/boringssl/crypto/mem.c', - 'deps/grpc/third_party/boringssl/crypto/modes/cbc.c', - 'deps/grpc/third_party/boringssl/crypto/modes/cfb.c', - 'deps/grpc/third_party/boringssl/crypto/modes/ctr.c', - 'deps/grpc/third_party/boringssl/crypto/modes/gcm.c', - 'deps/grpc/third_party/boringssl/crypto/modes/ofb.c', - 'deps/grpc/third_party/boringssl/crypto/modes/polyval.c', 'deps/grpc/third_party/boringssl/crypto/obj/obj.c', 'deps/grpc/third_party/boringssl/crypto/obj/obj_xref.c', 'deps/grpc/third_party/boringssl/crypto/pem/pem_all.c', @@ -375,30 +333,24 @@ 'deps/grpc/third_party/boringssl/crypto/pem/pem_pkey.c', 'deps/grpc/third_party/boringssl/crypto/pem/pem_x509.c', 'deps/grpc/third_party/boringssl/crypto/pem/pem_xaux.c', + 'deps/grpc/third_party/boringssl/crypto/pkcs7/pkcs7.c', + 'deps/grpc/third_party/boringssl/crypto/pkcs7/pkcs7_x509.c', 'deps/grpc/third_party/boringssl/crypto/pkcs8/p5_pbev2.c', - 'deps/grpc/third_party/boringssl/crypto/pkcs8/p8_pkey.c', 'deps/grpc/third_party/boringssl/crypto/pkcs8/pkcs8.c', + 'deps/grpc/third_party/boringssl/crypto/pkcs8/pkcs8_x509.c', 'deps/grpc/third_party/boringssl/crypto/poly1305/poly1305.c', 'deps/grpc/third_party/boringssl/crypto/poly1305/poly1305_arm.c', 'deps/grpc/third_party/boringssl/crypto/poly1305/poly1305_vec.c', 'deps/grpc/third_party/boringssl/crypto/pool/pool.c', - 'deps/grpc/third_party/boringssl/crypto/rand/deterministic.c', - 'deps/grpc/third_party/boringssl/crypto/rand/fuchsia.c', - 'deps/grpc/third_party/boringssl/crypto/rand/rand.c', - 'deps/grpc/third_party/boringssl/crypto/rand/urandom.c', - 'deps/grpc/third_party/boringssl/crypto/rand/windows.c', + 'deps/grpc/third_party/boringssl/crypto/rand_extra/deterministic.c', + 'deps/grpc/third_party/boringssl/crypto/rand_extra/forkunsafe.c', + 'deps/grpc/third_party/boringssl/crypto/rand_extra/fuchsia.c', + 'deps/grpc/third_party/boringssl/crypto/rand_extra/rand_extra.c', + 'deps/grpc/third_party/boringssl/crypto/rand_extra/windows.c', 'deps/grpc/third_party/boringssl/crypto/rc4/rc4.c', 'deps/grpc/third_party/boringssl/crypto/refcount_c11.c', 'deps/grpc/third_party/boringssl/crypto/refcount_lock.c', - 'deps/grpc/third_party/boringssl/crypto/rsa/blinding.c', - 'deps/grpc/third_party/boringssl/crypto/rsa/padding.c', - 'deps/grpc/third_party/boringssl/crypto/rsa/rsa.c', - 'deps/grpc/third_party/boringssl/crypto/rsa/rsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/rsa/rsa_impl.c', - 'deps/grpc/third_party/boringssl/crypto/sha/sha1-altivec.c', - 'deps/grpc/third_party/boringssl/crypto/sha/sha1.c', - 'deps/grpc/third_party/boringssl/crypto/sha/sha256.c', - 'deps/grpc/third_party/boringssl/crypto/sha/sha512.c', + 'deps/grpc/third_party/boringssl/crypto/rsa_extra/rsa_asn1.c', 'deps/grpc/third_party/boringssl/crypto/stack/stack.c', 'deps/grpc/third_party/boringssl/crypto/thread.c', 'deps/grpc/third_party/boringssl/crypto/thread_none.c', @@ -413,7 +365,6 @@ 'deps/grpc/third_party/boringssl/crypto/x509/by_dir.c', 'deps/grpc/third_party/boringssl/crypto/x509/by_file.c', 'deps/grpc/third_party/boringssl/crypto/x509/i2d_pr.c', - 'deps/grpc/third_party/boringssl/crypto/x509/pkcs7.c', 'deps/grpc/third_party/boringssl/crypto/x509/rsa_pss.c', 'deps/grpc/third_party/boringssl/crypto/x509/t_crl.c', 'deps/grpc/third_party/boringssl/crypto/x509/t_req.c', @@ -439,7 +390,6 @@ 'deps/grpc/third_party/boringssl/crypto/x509/x509name.c', 'deps/grpc/third_party/boringssl/crypto/x509/x509rset.c', 'deps/grpc/third_party/boringssl/crypto/x509/x509spki.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509type.c', 'deps/grpc/third_party/boringssl/crypto/x509/x_algor.c', 'deps/grpc/third_party/boringssl/crypto/x509/x_all.c', 'deps/grpc/third_party/boringssl/crypto/x509/x_attrib.c', @@ -487,41 +437,42 @@ 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_skey.c', 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_sxnet.c', 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_utl.c', - 'deps/grpc/third_party/boringssl/ssl/bio_ssl.c', - 'deps/grpc/third_party/boringssl/ssl/custom_extensions.c', - 'deps/grpc/third_party/boringssl/ssl/d1_both.c', - 'deps/grpc/third_party/boringssl/ssl/d1_lib.c', - 'deps/grpc/third_party/boringssl/ssl/d1_pkt.c', - 'deps/grpc/third_party/boringssl/ssl/d1_srtp.c', - 'deps/grpc/third_party/boringssl/ssl/dtls_method.c', - 'deps/grpc/third_party/boringssl/ssl/dtls_record.c', - 'deps/grpc/third_party/boringssl/ssl/handshake_client.c', - 'deps/grpc/third_party/boringssl/ssl/handshake_server.c', - 'deps/grpc/third_party/boringssl/ssl/s3_both.c', - 'deps/grpc/third_party/boringssl/ssl/s3_lib.c', - 'deps/grpc/third_party/boringssl/ssl/s3_pkt.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_aead_ctx.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_asn1.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_buffer.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_cert.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_cipher.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_ecdh.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_file.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_lib.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_privkey.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_privkey_cc.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_session.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_stat.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_transcript.c', - 'deps/grpc/third_party/boringssl/ssl/ssl_x509.c', - 'deps/grpc/third_party/boringssl/ssl/t1_enc.c', - 'deps/grpc/third_party/boringssl/ssl/t1_lib.c', - 'deps/grpc/third_party/boringssl/ssl/tls13_both.c', - 'deps/grpc/third_party/boringssl/ssl/tls13_client.c', - 'deps/grpc/third_party/boringssl/ssl/tls13_enc.c', - 'deps/grpc/third_party/boringssl/ssl/tls13_server.c', - 'deps/grpc/third_party/boringssl/ssl/tls_method.c', - 'deps/grpc/third_party/boringssl/ssl/tls_record.c', + 'deps/grpc/third_party/boringssl/ssl/bio_ssl.cc', + 'deps/grpc/third_party/boringssl/ssl/custom_extensions.cc', + 'deps/grpc/third_party/boringssl/ssl/d1_both.cc', + 'deps/grpc/third_party/boringssl/ssl/d1_lib.cc', + 'deps/grpc/third_party/boringssl/ssl/d1_pkt.cc', + 'deps/grpc/third_party/boringssl/ssl/d1_srtp.cc', + 'deps/grpc/third_party/boringssl/ssl/dtls_method.cc', + 'deps/grpc/third_party/boringssl/ssl/dtls_record.cc', + 'deps/grpc/third_party/boringssl/ssl/handshake.cc', + 'deps/grpc/third_party/boringssl/ssl/handshake_client.cc', + 'deps/grpc/third_party/boringssl/ssl/handshake_server.cc', + 'deps/grpc/third_party/boringssl/ssl/s3_both.cc', + 'deps/grpc/third_party/boringssl/ssl/s3_lib.cc', + 'deps/grpc/third_party/boringssl/ssl/s3_pkt.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_aead_ctx.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_asn1.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_buffer.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_cert.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_cipher.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_file.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_key_share.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_lib.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_privkey.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_session.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_stat.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_transcript.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_versions.cc', + 'deps/grpc/third_party/boringssl/ssl/ssl_x509.cc', + 'deps/grpc/third_party/boringssl/ssl/t1_enc.cc', + 'deps/grpc/third_party/boringssl/ssl/t1_lib.cc', + 'deps/grpc/third_party/boringssl/ssl/tls13_both.cc', + 'deps/grpc/third_party/boringssl/ssl/tls13_client.cc', + 'deps/grpc/third_party/boringssl/ssl/tls13_enc.cc', + 'deps/grpc/third_party/boringssl/ssl/tls13_server.cc', + 'deps/grpc/third_party/boringssl/ssl/tls_method.cc', + 'deps/grpc/third_party/boringssl/ssl/tls_record.cc', ], 'conditions': [ ['OS == "mac"', { From 082e2235bf2c197d8e629f51bd8bec14f99f2d2b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 21 Feb 2018 13:58:23 -0800 Subject: [PATCH 0102/1899] Implement new design of protobuf loader package --- gulpfile.ts | 13 +- packages/grpc-protobufjs/gulpfile.ts | 60 ++++++ packages/grpc-protobufjs/index.js | 139 -------------- packages/grpc-protobufjs/package.json | 23 ++- .../grpc-protobufjs/protobuf_js_5_common.js | 177 ------------------ .../grpc-protobufjs/protobuf_js_6_common.js | 166 ---------------- packages/grpc-protobufjs/src/index.ts | 160 ++++++++++++++++ 7 files changed, 247 insertions(+), 491 deletions(-) create mode 100644 packages/grpc-protobufjs/gulpfile.ts delete mode 100644 packages/grpc-protobufjs/index.js delete mode 100644 packages/grpc-protobufjs/protobuf_js_5_common.js delete mode 100644 packages/grpc-protobufjs/protobuf_js_6_common.js create mode 100644 packages/grpc-protobufjs/src/index.ts diff --git a/gulpfile.ts b/gulpfile.ts index 1c116d9ba..969fb894c 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -54,21 +54,22 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { ['./packages/grpc-native/gulpfile', 'native'], ['./packages/grpc-native-core/gulpfile', 'native.core'], ['./packages/grpc-surface/gulpfile', 'surface'], - ['./test/gulpfile', 'internal.test'] + ['./packages/grpc-protobufjs/gulpfile', 'protobuf'], + ['./test/gulpfile', 'internal.test'], ].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'internal.test.install']); + ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'internal.test.install']); + ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); -gulp.task('build', 'Build packages', ['js.compile', 'js.core.compile', 'native.core.build']); +gulp.task('build', 'Build packages', ['js.compile', 'js.core.compile', 'native.core.build', 'protobuf.compile']); gulp.task('link.core', 'Add links to core packages without rebuilding', ['js.link.add', 'native.link.add']); @@ -91,11 +92,11 @@ gulp.task('setup.windows', 'One-time setup for a clean repository for MS Windows runSequence('install.all.windows', 'link', callback); }); -gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clean']); +gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clean', 'protobuf.clean']); gulp.task('clean.all', 'Delete all files created by tasks', ['js.core.clean.all', 'native.core.clean.all', 'health-check.clean.all', - 'internal.test.clean.all', 'js.clean.all', 'native.clean.all']); + 'internal.test.clean.all', 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', ['native.core.test', 'internal.test.test', 'health-check.test']); diff --git a/packages/grpc-protobufjs/gulpfile.ts b/packages/grpc-protobufjs/gulpfile.ts new file mode 100644 index 000000000..550ce3648 --- /dev/null +++ b/packages/grpc-protobufjs/gulpfile.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as _gulp from 'gulp'; +import * as help from 'gulp-help'; + +import * as fs from 'fs'; +import * as mocha from 'gulp-mocha'; +import * as path from 'path'; +import * as execa from 'execa'; + +// gulp-help monkeypatches tasks to have an additional description parameter +const gulp = help(_gulp); + +Error.stackTraceLimit = Infinity; + +const protojsDir = __dirname; +const tslintPath = path.resolve(protojsDir, 'node_modules/google-ts-style/tslint.json'); +const tsconfigPath = path.resolve(protojsDir, 'tsconfig.json'); +const outDir = path.resolve(protojsDir, 'build'); +const srcDir = path.resolve(protojsDir, 'src'); +const testDir = path.resolve(protojsDir, 'test'); + +const execNpmVerb = (verb: string, ...args: string[]) => + execa('npm', [verb, ...args], {cwd: protojsDir, stdio: 'inherit'}); +const execNpmCommand = execNpmVerb.bind(null, 'run'); + +gulp.task('install', 'Install native core dependencies', () => + execNpmVerb('install', '--unsafe-perm')); + +/** + * Runs tslint on files in src/, with linting rules defined in tslint.json. + */ +gulp.task('lint', 'Emits linting errors found in src/ and test/.', () => + execNpmCommand('check')); + +gulp.task('clean', 'Deletes transpiled code.', ['install'], + () => execNpmCommand('clean')); + +gulp.task('clean.all', 'Deletes all files added by targets', ['clean']); + +/** + * Transpiles TypeScript files in src/ to JavaScript according to the settings + * found in tsconfig.json. + */ +gulp.task('compile', 'Transpiles src/.', () => execNpmCommand('compile')); diff --git a/packages/grpc-protobufjs/index.js b/packages/grpc-protobufjs/index.js deleted file mode 100644 index 5e7ede99c..000000000 --- a/packages/grpc-protobufjs/index.js +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var path = require('path'); - -var _ = require('lodash'); -var ProtoBuf = require('protobufjs'); - -module.exports = function(grpc) { - - let exports = {}; - - const protobuf_js_5_common = require('protobuf_js_5_common')(grpc); - const protobuf_js_6_common = require('protobuf_js_6_common')(grpc); - - /** - * Default options for loading proto files into gRPC - * @alias grpc~defaultLoadOptions - */ - const defaultGrpcOptions = { - convertFieldsToCamelCase: false, - binaryAsBase64: false, - longsAsStrings: true, - enumsAsStrings: true - }; - - /** - * Load a ProtoBuf.js object as a gRPC object. The options object can provide - * the following options: - * - binaryAsBase64: deserialize bytes values as base64 strings instead of - * Buffers. Defaults to false - * - longsAsStrings: deserialize long values as strings instead of objects. - * Defaults to true - * - enumsAsStrings: deserialize enum values as strings instead of numbers. - * Defaults to true - * - protobufjsVersion: Available values are 5, 6, and 'detect'. 5 and 6 - * respectively indicate that an object from the corresponding version of - * ProtoBuf.js is provided in the value argument. If the option is 'detect', - * gRPC will guess what the version is based on the structure of the value. - * Defaults to 'detect'. - * @param {Object} value The ProtoBuf.js reflection object to load - * @param {Object=} options Options to apply to the loaded file - * @return {Object} The resulting gRPC object - */ - exports.loadObject = function loadObject(value, options) { - options = _.defaults(options, defaultGrpcOptions); - options = _.defaults(options, {'protobufjsVersion': 'detect'}); - var protobufjsVersion; - if (options.protobufjsVersion === 'detect') { - if (protobuf_js_6_common.isProbablyProtobufJs6(value)) { - protobufjsVersion = 6; - } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) { - protobufjsVersion = 5; - } else { - var error_message = 'Could not detect ProtoBuf.js version. Please ' + - 'specify the version number with the "protobufjs_version" option'; - throw new Error(error_message); - } - } else { - protobufjsVersion = options.protobufjsVersion; - } - switch (protobufjsVersion) { - case 6: return protobuf_js_6_common.loadObject(value, options); - case 5: return protobuf_js_5_common.loadObject(value, options); - default: - throw new Error('Unrecognized protobufjsVersion', protobufjsVersion); - } - }; - - var loadObject = exports.loadObject; - - function applyProtoRoot(filename, root) { - if (_.isString(filename)) { - return filename; - } - filename.root = path.resolve(filename.root) + '/'; - root.resolvePath = function(originPath, importPath, alreadyNormalized) { - return ProtoBuf.util.path.resolve(filename.root, - importPath, - alreadyNormalized); - }; - return filename.file; - } - - /** - * Load a gRPC object from a .proto file. The options object can provide the - * following options: - * - convertFieldsToCamelCase: Load this file with field names in camel case - * instead of their original case - * - binaryAsBase64: deserialize bytes values as base64 strings instead of - * Buffers. Defaults to false - * - longsAsStrings: deserialize long values as strings instead of objects. - * Defaults to true - * - enumsAsStrings: deserialize enum values as strings instead of numbers. - * Defaults to true - * - deprecatedArgumentOrder: Use the beta method argument order for client - * methods, with optional arguments after the callback. Defaults to false. - * This option is only a temporary stopgap measure to smooth an API breakage. - * It is deprecated, and new code should not use it. - * @param {string|{root: string, file: string}} filename The file to load - * @param {string=} format The file format to expect. Must be either 'proto' or - * 'json'. Defaults to 'proto' - * @param {Object=} options Options to apply to the loaded file - * @return {Object} The resulting gRPC object - */ - exports.load = function load(filename, format, options) { - /* Note: format is currently unused, because the API for loading a proto - file or a JSON file is identical in Protobuf.js 6. In the future, there is - still the possibility of adding other formats that would be loaded - differently */ - options = _.defaults(options, defaultGrpcOptions); - options.protobufjs_version = 6; - var root = new ProtoBuf.Root(); - var parse_options = {keepCase: !options.convertFieldsToCamelCase}; - return loadObject(root.loadSync(applyProtoRoot(filename, root), - parse_options), - options); - }; - - return exports; - -}; diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 60b3ddddb..13eb7c012 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -2,9 +2,19 @@ "name": "@grpc/protobufjs", "version": "1.0.0", "description": "", - "main": "index.js", + "main": "build/src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "build": "npm run compile", + "clean": "gts clean", + "compile": "tsc -p .", + "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", + "lint": "tslint -c node_modules/google-ts-style/tslint.json -p . -t codeFrame --type-check", + "prepare": "npm run compile", + "test": "gulp test", + "check": "gts check", + "fix": "gts fix", + "pretest": "npm run compile", + "posttest": "npm run check" }, "repository": { "type": "git", @@ -15,8 +25,15 @@ "bugs": { "url": "https://github.com/grpc/grpc-node/issues" }, + "files": [ + "build/src/*.js" + ], "dependencies": { + "@types/node": "^9.4.6", + "clang-format": "^1.2.2", + "gts": "^0.5.3", "lodash": "^4.17.4", - "protobufjs": "^6.8.0" + "protobufjs": "^6.8.5", + "typescript": "~2.7.2" } } diff --git a/packages/grpc-protobufjs/protobuf_js_5_common.js b/packages/grpc-protobufjs/protobuf_js_5_common.js deleted file mode 100644 index 141852f6e..000000000 --- a/packages/grpc-protobufjs/protobuf_js_5_common.js +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * @module - * @private - */ - -'use strict'; - -var _ = require('lodash'); - -module.exports = function(grpc) { - - let exports = {}; - - /** - * Get a function that deserializes a specific type of protobuf. - * @param {function()} cls The constructor of the message type to deserialize - * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings - * instead of Buffers. Defaults to false - * @param {bool=} longsAsStrings Deserialize long values as strings instead of - * objects. Defaults to true - * @return {function(Buffer):cls} The deserialization function - */ - exports.deserializeCls = function deserializeCls(cls, options) { - /** - * Deserialize a buffer to a message object - * @param {Buffer} arg_buf The buffer to deserialize - * @return {cls} The resulting object - */ - return function deserialize(arg_buf) { - // Convert to a native object with binary fields as Buffers (first argument) - // and longs as strings (second argument) - return cls.decode(arg_buf).toRaw(options.binaryAsBase64, - options.longsAsStrings); - }; - }; - - var deserializeCls = exports.deserializeCls; - - /** - * Get a function that serializes objects to a buffer by protobuf class. - * @param {function()} Cls The constructor of the message type to serialize - * @return {function(Cls):Buffer} The serialization function - */ - exports.serializeCls = function serializeCls(Cls) { - /** - * Serialize an object to a Buffer - * @param {Object} arg The object to serialize - * @return {Buffer} The serialized object - */ - return function serialize(arg) { - return new Buffer(new Cls(arg).encode().toBuffer()); - }; - }; - - var serializeCls = exports.serializeCls; - - /** - * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. - * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of - * @return {string} The fully qualified name of the value - */ - exports.fullyQualifiedName = function fullyQualifiedName(value) { - if (value === null || value === undefined) { - return ''; - } - var name = value.name; - var parent_name = fullyQualifiedName(value.parent); - if (parent_name !== '') { - name = parent_name + '.' + name; - } - return name; - }; - - var fullyQualifiedName = exports.fullyQualifiedName; - - /** - * Return a map from method names to method attributes for the service. - * @param {ProtoBuf.Reflect.Service} service The service to get attributes for - * @param {Object=} options Options to apply to these attributes - * @return {Object} The attributes map - */ - exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, - options) { - var prefix = '/' + fullyQualifiedName(service) + '/'; - var binaryAsBase64, longsAsStrings; - if (options) { - binaryAsBase64 = options.binaryAsBase64; - longsAsStrings = options.longsAsStrings; - } - /* This slightly awkward construction is used to make sure we only use - lodash@3.10.1-compatible functions. A previous version used - _.fromPairs, which would be cleaner, but was introduced in lodash - version 4 */ - return _.zipObject(_.map(service.children, function(method) { - return _.camelCase(method.name); - }), _.map(service.children, function(method) { - return { - originalName: method.name, - path: prefix + method.name, - requestStream: method.requestStream, - responseStream: method.responseStream, - requestType: method.resolvedRequestType, - responseType: method.resolvedResponseType, - requestSerialize: serializeCls(method.resolvedRequestType.build()), - requestDeserialize: deserializeCls(method.resolvedRequestType.build(), - options), - responseSerialize: serializeCls(method.resolvedResponseType.build()), - responseDeserialize: deserializeCls(method.resolvedResponseType.build(), - options) - }; - })); - }; - - var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; - - /** - * Load a gRPC object from an existing ProtoBuf.Reflect object. - * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. - * @param {Object=} options Options to apply to the loaded object - * @return {Object} The resulting gRPC object - */ - exports.loadObject = function loadObject(value, options) { - var result = {}; - if (!value) { - return value; - } - if (value.hasOwnProperty('ns')) { - return loadObject(value.ns, options); - } - if (value.className === 'Namespace') { - _.each(value.children, function(child) { - result[child.name] = loadObject(child, options); - }); - return result; - } else if (value.className === 'Service') { - return grpc.makeGenericClientConstructor(getProtobufServiceAttrs(value, options), - options); - } else if (value.className === 'Message' || value.className === 'Enum') { - return value.build(); - } else { - return value; - } - }; - - /** - * The primary purpose of this method is to distinguish between reflection - * objects from different versions of ProtoBuf.js. This is just a heuristic, - * checking for properties that are (currently) specific to this version of - * ProtoBuf.js - * @param {Object} obj The object to check - * @return {boolean} Whether the object appears to be a Protobuf.js 5 - * ReflectionObject - */ - exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) { - return _.isArray(obj.children) && (typeof obj.build === 'function'); - }; - - return exports; -}; diff --git a/packages/grpc-protobufjs/protobuf_js_6_common.js b/packages/grpc-protobufjs/protobuf_js_6_common.js deleted file mode 100644 index 76241994b..000000000 --- a/packages/grpc-protobufjs/protobuf_js_6_common.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * @module - * @private - */ - -'use strict'; - -var _ = require('lodash'); - -module.exports = function(grpc) { - - let exports = {}; - - /** - * Get a function that deserializes a specific type of protobuf. - * @param {function()} cls The constructor of the message type to deserialize - * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings - * instead of Buffers. Defaults to false - * @param {bool=} longsAsStrings Deserialize long values as strings instead of - * objects. Defaults to true - * @return {function(Buffer):cls} The deserialization function - */ - exports.deserializeCls = function deserializeCls(cls, options) { - var conversion_options = { - defaults: true, - bytes: options.binaryAsBase64 ? String : Buffer, - longs: options.longsAsStrings ? String : null, - enums: options.enumsAsStrings ? String : null, - oneofs: true - }; - /** - * Deserialize a buffer to a message object - * @param {Buffer} arg_buf The buffer to deserialize - * @return {cls} The resulting object - */ - return function deserialize(arg_buf) { - return cls.toObject(cls.decode(arg_buf), conversion_options); - }; - }; - - var deserializeCls = exports.deserializeCls; - - /** - * Get a function that serializes objects to a buffer by protobuf class. - * @param {function()} Cls The constructor of the message type to serialize - * @return {function(Cls):Buffer} The serialization function - */ - exports.serializeCls = function serializeCls(cls) { - /** - * Serialize an object to a Buffer - * @param {Object} arg The object to serialize - * @return {Buffer} The serialized object - */ - return function serialize(arg) { - var message = cls.fromObject(arg); - return cls.encode(message).finish(); - }; - }; - - var serializeCls = exports.serializeCls; - - /** - * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. - * @param {ProtoBuf.ReflectionObject} value The value to get the name of - * @return {string} The fully qualified name of the value - */ - exports.fullyQualifiedName = function fullyQualifiedName(value) { - if (value === null || value === undefined) { - return ''; - } - var name = value.name; - var parent_fqn = fullyQualifiedName(value.parent); - if (parent_fqn !== '') { - name = parent_fqn + '.' + name; - } - return name; - }; - - var fullyQualifiedName = exports.fullyQualifiedName; - - /** - * Return a map from method names to method attributes for the service. - * @param {ProtoBuf.Service} service The service to get attributes for - * @param {Object=} options Options to apply to these attributes - * @return {Object} The attributes map - */ - exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, - options) { - var prefix = '/' + fullyQualifiedName(service) + '/'; - service.resolveAll(); - return _.zipObject(_.map(service.methods, function(method) { - return _.camelCase(method.name); - }), _.map(service.methods, function(method) { - return { - originalName: method.name, - path: prefix + method.name, - requestStream: !!method.requestStream, - responseStream: !!method.responseStream, - requestType: method.resolvedRequestType, - responseType: method.resolvedResponseType, - requestSerialize: serializeCls(method.resolvedRequestType), - requestDeserialize: deserializeCls(method.resolvedRequestType, options), - responseSerialize: serializeCls(method.resolvedResponseType), - responseDeserialize: deserializeCls(method.resolvedResponseType, options) - }; - })); - }; - - var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; - - exports.loadObject = function loadObject(value, options) { - var result = {}; - if (!value) { - return value; - } - if (value.hasOwnProperty('methods')) { - // It's a service object - var service_attrs = getProtobufServiceAttrs(value, options); - return grpc..makeGenericClientConstructor(service_attrs); - } - - if (value.hasOwnProperty('nested')) { - // It's a namespace or root object - _.each(value.nested, function(nested, name) { - result[name] = loadObject(nested, options); - }); - return result; - } - - // Otherwise, it's not something we need to change - return value; - }; - - /** - * The primary purpose of this method is to distinguish between reflection - * objects from different versions of ProtoBuf.js. This is just a heuristic, - * checking for properties that are (currently) specific to this version of - * ProtoBuf.js - * @param {Object} obj The object to check - * @return {boolean} Whether the object appears to be a Protobuf.js 6 - * ReflectionObject - */ - exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) { - return (typeof obj.root === 'object') && (typeof obj.resolve === 'function'); - }; - - return exports; -}; diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts new file mode 100644 index 000000000..9b1ee2900 --- /dev/null +++ b/packages/grpc-protobufjs/src/index.ts @@ -0,0 +1,160 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +import * as Protobuf from 'protobufjs'; +import * as fs from 'fs'; +import * as path from 'path'; + +export interface Serialize { + (value: T): Buffer; +} + +export interface Deserialize { + (bytes: Buffer): T; +} + +export interface MethodDefinition { + path: string; + requestStream: boolean; + responseStream: boolean; + requestSerialize: Serialize; + responseSerialize: Serialize; + requestDeserialize: Deserialize; + responseDeserialize: Deserialize; +} + +export interface ServiceDefinition { + [index: string]: MethodDefinition; +} + +export interface PackageDefinition { + [index: string]: ServiceDefinition; +} + +export type Options = Protobuf.IParseOptions & Protobuf.IConversionOptions & { + include?: string[]; +}; + +function joinName(baseName: string, name: string): string { + if (baseName === '') { + return name; + } else { + return baseName + '.' + name; + } +} + +function getAllServices(obj: Protobuf.NamespaceBase, parentName: string): Array<[string, Protobuf.Service]> { + const objName = joinName(parentName, obj.name); + if (obj.hasOwnProperty('methods')) { + return [[objName, obj as Protobuf.Service]]; + } else { + return obj.nestedArray.map((child) => { + if (child.hasOwnProperty('nested')) { + return getAllServices(child as Protobuf.NamespaceBase, objName); + } else { + return []; + } + }).reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + } +} + +function createDeserializer(cls: Protobuf.Type, options: Options): Deserialize { + return function deserialize(argBuf: Buffer): object { + return cls.toObject(cls.decode(argBuf), options); + }; +} + +function createSerializer(cls: Protobuf.Type): Serialize { + return function serialize(arg: object): Buffer { + const message = cls.fromObject(arg); + return cls.encode(message).finish() as Buffer; + }; +} + +function createMethodDefinition(method: Protobuf.Method, serviceName: string, options: Options): MethodDefinition { + return { + path: '/' + serviceName + '/' + method.name, + requestStream: !!method.requestStream, + responseStream: !!method.responseStream, + requestSerialize: createSerializer(method.resolvedRequestType as Protobuf.Type), + requestDeserialize: createDeserializer(method.resolvedRequestType as Protobuf.Type, options), + responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), + responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options) + }; +} + +function createServiceDefinition(service: Protobuf.Service, name: string, options: Options): ServiceDefinition { + const def: ServiceDefinition = {}; + for (const method of service.methodsArray) { + def[method.name] = createMethodDefinition(method, name, options); + } + return def; +} + +function createPackageDefinition(root: Protobuf.Root, options: Options): PackageDefinition { + const def: PackageDefinition = {}; + for (const [name, service] of getAllServices(root, '')) { + def[name] = createServiceDefinition(service, name, options); + } + return def; +} + +/** + * Load a .proto file with the specified options. + * @param filename The file path to load. Can be an absolute path or relative to + * an include path. + * @param options.keepCase Preserve field names. The default is to change them + * to camel case. + * @param options.longs The type that should be used to represent `long` values. + * Valid options are `Number` and `String`. Defaults to a `Long` object type + * from a library. + * @param options.enums The type that should be used to represent `enum` values. + * The only valid option is `String`. Defaults to the numeric value. + * @param options.bytes The type that should be used to represent `bytes` + * values. Valid options are `Array` and `String`. The default is to use + * `Buffer`. + * @param options.defaults Set default values on output objects. Defaults to + * `false`. + * @param options.arrays Set empty arrays for missing array values even if + * `defaults` is `false`. Defaults to `false`. + * @param options.objects Set empty objects for missing object values even if + * `defaults` is `false`. Defaults to `false`. + * @param options.oneofs Set virtual oneof properties to the present field's + * name + * @param options.include Paths to search for imported `.proto` files. + */ +export async function load(filename: string, options: Options): Promise { + const root: Protobuf.Root = new Protobuf.Root(); + if (options.include !== undefined) { + root.resolvePath = (origin: string, target: string) => { + for (const directory of options.include as string[]) { + const fullPath: string = path.join(directory, target); + try { + fs.accessSync(fullPath, fs.constants.R_OK); + return fullPath; + } catch (err) { + continue; + } + } + return null; + }; + } + return root.load(filename, options).then((loadedRoot) => { + loadedRoot.resolveAll(); + return createPackageDefinition(root, options); + }, error => { throw error; }); +} From d3a2282be10e72b802c0d692bd80b4839afab95f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 21 Feb 2018 14:12:50 -0800 Subject: [PATCH 0103/1899] Add missing tsconfig file --- packages/grpc-protobufjs/tsconfig.json | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 packages/grpc-protobufjs/tsconfig.json diff --git a/packages/grpc-protobufjs/tsconfig.json b/packages/grpc-protobufjs/tsconfig.json new file mode 100644 index 000000000..9218530ce --- /dev/null +++ b/packages/grpc-protobufjs/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/*.ts", + "src/**/*.ts" + ], + "exclude": [ + "node_modules" + ] +} From bda109e6551ab06c56e5b2a5de9971ece32c9fc3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 21 Feb 2018 16:12:02 -0800 Subject: [PATCH 0104/1899] Add package definition loader function to native package --- packages/grpc-native-core/index.js | 23 +++++++++++++++++++++++ packages/grpc-native-core/src/common.js | 5 +++++ 2 files changed, 28 insertions(+) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 7810b7bff..f0337845d 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -146,6 +146,29 @@ exports.load = function load(filename, format, options) { return loadObject(builder.ns, options); }; +/** + * Load a gRPC package definition as a gRPC object hierarchy + * @param packageDef grpc~PackageDefinition The package definition object + * @return {Object} The resulting gRPC object + */ +exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { + const result = {}; + for (const serviceFqn in packageDef) { + const service = packageDef[serviceFqn]; + const nameComponents = serviceFqn.split('.'); + const serviceName = nameComponents[-1]; + let current = result; + for (const package in nameComponents.slice(0, -1)) { + if (!current[package]) { + current[package] = {}; + } + current = current[package]; + } + current[serviceName] = client.makeClientConstructor(service, serviceName, {}); + } + return result; +}; + var log_template = _.template( '{severity} {timestamp}\t{file}:{line}]\t{message}', {interpolate: /{([\s\S]+?)}/g}); diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 5882cf1c6..b9c5ee3fc 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -170,3 +170,8 @@ exports.defaultGrpcOptions = { * An object that completely defines a service. * @typedef {Object.} grpc~ServiceDefinition */ + +/** + * An object that defines a package hierarchy with multiple services + * @typedef {Object.} grpc~PackageDefinition + */ From a5de87448413309692e234d11a23d4b9987eb5d9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 21 Feb 2018 16:32:42 -0800 Subject: [PATCH 0105/1899] Address comments --- packages/grpc-protobufjs/src/index.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index 9b1ee2900..22083f986 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -38,7 +38,7 @@ export interface MethodDefinition { } export interface ServiceDefinition { - [index: string]: MethodDefinition; + [index: string]: MethodDefinition; } export interface PackageDefinition { @@ -137,9 +137,12 @@ function createPackageDefinition(root: Protobuf.Root, options: Options): Package * name * @param options.include Paths to search for imported `.proto` files. */ -export async function load(filename: string, options: Options): Promise { +export function load(filename: string, options: Options): Promise { const root: Protobuf.Root = new Protobuf.Root(); - if (options.include !== undefined) { + if (!!options.include) { + if (!(options.include instanceof Array)) { + return Promise.reject(new Error('The include option must be an array')); + } root.resolvePath = (origin: string, target: string) => { for (const directory of options.include as string[]) { const fullPath: string = path.join(directory, target); @@ -156,5 +159,5 @@ export async function load(filename: string, options: Options): Promise { loadedRoot.resolveAll(); return createPackageDefinition(root, options); - }, error => { throw error; }); + }); } From c74057796360bd4a209374c0c6319d04ff4d8dbb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 22 Feb 2018 11:39:14 -0800 Subject: [PATCH 0106/1899] Update version to v1.10.0-pre1 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 85f0618ef..6a2d69fec 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -788,10 +788,10 @@ 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', + 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/lb_targets_info.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', - 'deps/grpc/src/core/lib/security/transport/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', 'deps/grpc/src/core/lib/security/transport/server_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/tsi_error.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 34e8e0a64..756acb78f 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 34e8e0a6400d8b529125a3b83ec1facf71acf99b +Subproject commit 756acb78f6ac8a6f6533a55a09590b8e598d112b diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 44b029d66..6d36ab8b6 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.0-dev", + "version": "1.10.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 00d93a50eff24037b5483c6c97e02a9eaa053463 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 23 Feb 2018 12:24:22 -0800 Subject: [PATCH 0107/1899] Update Windows test to force using TLS/1.2 https://githubengineering.com/crypto-removal-notice/ broke the windows test. Forcing Powershell to update to TLS/1.2. --- install-nvm-windows.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/install-nvm-windows.ps1 b/install-nvm-windows.ps1 index 709a1ec2d..b3794055f 100644 --- a/install-nvm-windows.ps1 +++ b/install-nvm-windows.ps1 @@ -15,6 +15,9 @@ # We're going to store nvm-windows in the .\nvm directory. $env:NVM_HOME = (Get-Item -Path ".\" -Verbose).FullName + "\nvm" +# Switching to TLS/1.2 - see https://githubengineering.com/crypto-removal-notice/ +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + # Downloading and unpacking nvm-windows Invoke-WebRequest -Uri https://github.com/coreybutler/nvm-windows/releases/download/1.1.5/nvm-noinstall.zip -OutFile nvm-noinstall.zip Add-Type -AssemblyName System.IO.Compression.FileSystem From b8fc270fc1519bf53f7b6edf8a6cec1109cae7c4 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 23 Feb 2018 12:24:22 -0800 Subject: [PATCH 0108/1899] Update Windows test to force using TLS/1.2 https://githubengineering.com/crypto-removal-notice/ broke the windows test. Forcing Powershell to update to TLS/1.2. --- install-nvm-windows.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/install-nvm-windows.ps1 b/install-nvm-windows.ps1 index 709a1ec2d..b3794055f 100644 --- a/install-nvm-windows.ps1 +++ b/install-nvm-windows.ps1 @@ -15,6 +15,9 @@ # We're going to store nvm-windows in the .\nvm directory. $env:NVM_HOME = (Get-Item -Path ".\" -Verbose).FullName + "\nvm" +# Switching to TLS/1.2 - see https://githubengineering.com/crypto-removal-notice/ +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + # Downloading and unpacking nvm-windows Invoke-WebRequest -Uri https://github.com/coreybutler/nvm-windows/releases/download/1.1.5/nvm-noinstall.zip -OutFile nvm-noinstall.zip Add-Type -AssemblyName System.IO.Compression.FileSystem From 264d0aee568889ede5d5d3069c4638ba49e22806 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 26 Feb 2018 13:57:53 -0800 Subject: [PATCH 0109/1899] Add macro definition to gyp file --- packages/grpc-native-core/binding.gyp | 1 + packages/grpc-native-core/templates/binding.gyp.template | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 85f0618ef..aa4d4be65 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -82,6 +82,7 @@ 'deps/grpc/third_party/abseil-cpp' ], 'defines': [ + 'PB_FIELD_16BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV' diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 57c9b6e7f..e5eebfed5 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -78,6 +78,7 @@ 'deps/grpc/third_party/abseil-cpp' ], 'defines': [ + 'PB_FIELD_16BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV' From ea704f94391c76562aa5a74565ce917c26ab6720 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 27 Feb 2018 10:09:25 -0800 Subject: [PATCH 0110/1899] Fix a couple of issues with the package loader function --- packages/grpc-native-core/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index f0337845d..202efa4a8 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -156,13 +156,13 @@ exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { for (const serviceFqn in packageDef) { const service = packageDef[serviceFqn]; const nameComponents = serviceFqn.split('.'); - const serviceName = nameComponents[-1]; + const serviceName = nameComponents[nameComponents.length-1]; let current = result; - for (const package in nameComponents.slice(0, -1)) { - if (!current[package]) { - current[package] = {}; + for (const packageName in nameComponents.slice(0, -1)) { + if (!current[packageName]) { + current[packageName] = {}; } - current = current[package]; + current = current[packageName]; } current[serviceName] = client.makeClientConstructor(service, serviceName, {}); } From 5bae2500770cfe638f245923acc73e1beae4deea Mon Sep 17 00:00:00 2001 From: David Vroom Duke Date: Mon, 12 Feb 2018 17:16:24 -0800 Subject: [PATCH 0111/1899] Implement client interceptors for grpc-native-core A NodeJS implementation of client-side interceptors, as described in the proposal: https://github.com/grpc/proposal/pull/14 --- packages/grpc-native-core/index.js | 7 + packages/grpc-native-core/src/client.js | 577 +++--- .../src/client_interceptors.js | 1343 +++++++++++++ packages/grpc-native-core/src/common.js | 158 ++ packages/grpc-native-core/src/constants.js | 14 + .../test/client_interceptors_test.js | 1705 +++++++++++++++++ .../grpc-native-core/test/echo_service.proto | 34 + 7 files changed, 3494 insertions(+), 344 deletions(-) create mode 100644 packages/grpc-native-core/src/client_interceptors.js create mode 100644 packages/grpc-native-core/test/client_interceptors_test.js create mode 100644 packages/grpc-native-core/test/echo_service.proto diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index c994c35d5..4e4289fa1 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -223,6 +223,8 @@ exports.writeFlags = constants.writeFlags; exports.logVerbosity = constants.logVerbosity; +exports.methodTypes = constants.methodTypes; + exports.credentials = require('./src/credentials.js'); /** @@ -266,6 +268,11 @@ exports.getClientChannel = client.getClientChannel; exports.waitForClientReady = client.waitForClientReady; +exports.StatusBuilder = client.StatusBuilder; +exports.ListenerBuilder = client.ListenerBuilder; +exports.RequesterBuilder = client.RequesterBuilder; +exports.InterceptingCall = client.InterceptingCall; + /** * @memberof grpc * @alias grpc.closeClient diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index a917cbc9a..79868df46 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -34,6 +34,7 @@ var _ = require('lodash'); +var client_interceptors = require('./client_interceptors'); var grpc = require('./grpc_extension'); var common = require('./common'); @@ -49,25 +50,10 @@ var stream = require('stream'); var Readable = stream.Readable; var Writable = stream.Writable; var Duplex = stream.Duplex; +var methodTypes = constants.methodTypes; var util = require('util'); var version = require('../package.json').version; -/** - * Create an Error object from a status object - * @private - * @param {grpc~StatusObject} status The status object - * @return {Error} The resulting Error - */ -function createStatusError(status) { - let statusName = _.invert(constants.status)[status.code]; - let message = `${status.code} ${statusName}: ${status.details}`; - let error = new Error(message); - error.code = status.code; - error.metadata = status.metadata; - error.details = status.details; - return error; -} - /** * Initial response metadata sent by the server when it starts processing the * call @@ -107,18 +93,15 @@ util.inherits(ClientWritableStream, Writable); * grpc~ClientWritableStream#metadata * @borrows grpc~ClientUnaryCall#event:status as * grpc~ClientWritableStream#status - * @param {grpc.internal~Call} call The call object to send data with - * @param {grpc~serialize=} [serialize=identity] Serialization - * function for writes. + * @param {InterceptingCall} call Exposes gRPC request operations, processed by + * an interceptor stack. */ -function ClientWritableStream(call, serialize) { +function ClientWritableStream(call) { Writable.call(this, {objectMode: true}); this.call = call; - this.serialize = common.wrapIgnoreNull(serialize); + var self = this; this.on('finish', function() { - var batch = {}; - batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - call.startBatch(batch, function() {}); + self.call.halfClose(); }); } @@ -145,8 +128,6 @@ function ClientWritableStream(call, serialize) { */ function _write(chunk, encoding, callback) { /* jshint validthis: true */ - var batch = {}; - var message; var self = this; if (this.writeFailed) { /* Once a write fails, just call the callback immediately to let the caller @@ -154,26 +135,7 @@ function _write(chunk, encoding, callback) { setImmediate(callback); return; } - try { - message = this.serialize(chunk); - } catch (e) { - /* Sending this error to the server and emitting it immediately on the - client may put the call in a slightly weird state on the client side, - but passing an object that causes a serialization failure is a misuse - of the API anyway, so that's OK. The primary purpose here is to give the - programmer a useful error and to stop the stream properly */ - this.call.cancelWithStatus(constants.status.INTERNAL, - 'Serialization failure'); - callback(e); - return; - } - if (_.isFinite(encoding)) { - /* Attach the encoding if it is a finite number. This is the closest we - * can get to checking that it is valid flags */ - message.grpcWriteFlags = encoding; - } - batch[grpc.opType.SEND_MESSAGE] = message; - this.call.startBatch(batch, function(err, event) { + var outerCallback = function(err, event) { if (err) { /* Assume that the call is complete and that writing failed because a status was received. In that case, set a flag to discard all future @@ -181,7 +143,12 @@ function _write(chunk, encoding, callback) { self.writeFailed = true; } callback(); - }); + }; + var context = { + encoding: encoding, + callback: outerCallback + }; + this.call.sendMessageWithContext(context, chunk); } ClientWritableStream.prototype._write = _write; @@ -199,16 +166,14 @@ util.inherits(ClientReadableStream, Readable); * grpc~ClientReadableStream#metadata * @borrows grpc~ClientUnaryCall#event:status as * grpc~ClientReadableStream#status - * @param {grpc.internal~Call} call The call object to read data with - * @param {grpc~deserialize=} [deserialize=identity] - * Deserialization function for reads + * @param {InterceptingCall} call Exposes gRPC request operations, processed by + * an interceptor stack. */ -function ClientReadableStream(call, deserialize) { +function ClientReadableStream(call) { Readable.call(this, {objectMode: true}); this.call = call; this.finished = false; this.reading = false; - this.deserialize = common.wrapIgnoreNull(deserialize); /* Status generated from reading messages from the server. Overrides the * status from the server if not OK */ this.read_status = null; @@ -267,7 +232,7 @@ function _emitStatusIfDone() { if (status.code === constants.status.OK) { this.push(null); } else { - var error = createStatusError(status); + var error = common.createStatusError(status); this.emit('error', error); } this.emit('status', status); @@ -283,48 +248,15 @@ ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone; */ function _read(size) { /* jshint validthis: true */ - var self = this; - /** - * Callback to be called when a READ event is received. Pushes the data onto - * the read queue and starts reading again if applicable - * @param {grpc.Event} event READ event object - */ - function readCallback(err, event) { - if (err) { - // Something has gone wrong. Stop reading and wait for status - self.finished = true; - self._readsDone(); - return; - } - var data = event.read; - var deserialized; - try { - deserialized = self.deserialize(data); - } catch (e) { - self._readsDone({code: constants.status.INTERNAL, - details: 'Failed to parse server response'}); - return; - } - if (data === null) { - self._readsDone(); - return; - } - if (self.push(deserialized) && data !== null) { - var read_batch = {}; - read_batch[grpc.opType.RECV_MESSAGE] = true; - self.call.startBatch(read_batch, readCallback); - } else { - self.reading = false; - } - } - if (self.finished) { - self.push(null); + if (this.finished) { + this.push(null); } else { - if (!self.reading) { - self.reading = true; - var read_batch = {}; - read_batch[grpc.opType.RECV_MESSAGE] = true; - self.call.startBatch(read_batch, readCallback); + if (!this.reading) { + this.reading = true; + var context = { + stream: this + }; + this.call.recvMessageWithContext(context); } } } @@ -345,26 +277,20 @@ util.inherits(ClientDuplexStream, Duplex); * grpc~ClientDuplexStream#metadata * @borrows grpc~ClientUnaryCall#event:status as * grpc~ClientDuplexStream#status - * @param {grpc.internal~Call} call Call object to proxy - * @param {grpc~serialize=} [serialize=identity] Serialization - * function for requests - * @param {grpc~deserialize=} [deserialize=identity] - * Deserialization function for responses + * @param {InterceptingCall} call Exposes gRPC request operations, processed by + * an interceptor stack. */ -function ClientDuplexStream(call, serialize, deserialize) { +function ClientDuplexStream(call) { Duplex.call(this, {objectMode: true}); - this.serialize = common.wrapIgnoreNull(serialize); - this.deserialize = common.wrapIgnoreNull(deserialize); this.call = call; /* Status generated from reading messages from the server. Overrides the * status from the server if not OK */ this.read_status = null; /* Status received from the server. */ this.received_status = null; + var self = this; this.on('finish', function() { - var batch = {}; - batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - call.startBatch(batch, function() {}); + self.call.halfClose(); }); } @@ -429,45 +355,17 @@ ClientDuplexStream.prototype.getPeer = getPeer; * should be used to make this particular call. */ -/** - * Get a call object built with the provided options. - * @access private - * @param {grpc.Client~CallOptions=} options Options object. - */ -function getCall(channel, method, options) { - var deadline; - var host; - var parent; - var propagate_flags; - var credentials; - if (options) { - deadline = options.deadline; - host = options.host; - parent = _.get(options, 'parent.call'); - propagate_flags = options.propagate_flags; - credentials = options.credentials; - } - if (deadline === undefined) { - deadline = Infinity; - } - var call = new grpc.Call(channel, method, deadline, host, - parent, propagate_flags); - if (credentials) { - call.setCredentials(credentials); - } - return call; -} - /** * A generic gRPC client. Primarily useful as a base class for generated clients * @memberof grpc * @constructor * @param {string} address Server address to connect to - * @param {grpc.credentials~ChannelCredentials} credentials Credentials to use to connect to - * the server + * @param {grpc.credentials~ChannelCredentials} credentials Credentials to use + * to connect to the server * @param {Object} options Options to apply to channel creation */ function Client(address, credentials, options) { + var self = this; if (!options) { options = {}; } @@ -480,9 +378,27 @@ function Client(address, credentials, options) { options['grpc.primary_user_agent'] = ''; } options['grpc.primary_user_agent'] += 'grpc-node/' + version; + + // Resolve interceptor options and assign interceptors to each method + var interceptor_providers = options.interceptor_providers || []; + var interceptors = options.interceptors || []; + if (interceptor_providers.length && interceptors.length) { + throw new client_interceptors.InterceptorConfigurationError( + 'Both interceptors and interceptor_providers were passed as options ' + + 'to the client constructor. Only one of these is allowed.'); + } + _.each(self.$method_definitions, function(method_definition, method_name) { + self[method_name].interceptors = client_interceptors + .resolveInterceptorProviders(interceptor_providers, method_definition) + .concat(interceptors); + }); + + // Exclude interceptor options which have already been consumed + var channel_options = _.omit(options, + ['interceptors', 'interceptor_providers']); /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ - this.$channel = new grpc.Channel(address, credentials, options); + this.$channel = new grpc.Channel(address, credentials, channel_options); } exports.Client = Client; @@ -497,7 +413,7 @@ exports.Client = Client; /** * Make a unary request to the given method, using the given serialize * and deserialize functions, with the given argument. - * @param {string} method The name of the method to request + * @param {string} path The path of the method to request * @param {grpc~serialize} serialize The serialization function for * inputs * @param {grpc~deserialize} deserialize The deserialization @@ -506,11 +422,11 @@ exports.Client = Client; * serialize * @param {grpc.Metadata=} metadata Metadata to add to the call * @param {grpc.Client~CallOptions=} options Options map - * @param {grpc.Client~requestCallback} callback The callback to + * @param {grpc.Client~requestCallback} callback The callback * for when the response is received * @return {grpc~ClientUnaryCall} An event emitter for stream related events */ -Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, +Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, argument, metadata, options, callback) { if (options instanceof Function) { @@ -533,67 +449,50 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, options = {}; } if (!((metadata instanceof Metadata) && - (options instanceof Object) && - (callback instanceof Function))) { - throw new Error("Argument mismatch in makeUnaryRequest"); + (options instanceof Object) && + (callback instanceof Function))) { + throw new Error('Argument mismatch in makeUnaryRequest'); } - var call = getCall(this.$channel, method, options); - var emitter = new ClientUnaryCall(call); + + var method_name = this.$method_names[path]; + var constructor_interceptors = this[method_name] ? + this[method_name].interceptors : + null; + var method_definition = options.method_definition = { + path: path, + requestStream: false, + responseStream: false, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + metadata = metadata.clone(); - var client_batch = {}; - var message = serialize(argument); - if (options) { - message.grpcWriteFlags = options.flags; - } - client_batch[grpc.opType.SEND_INITIAL_METADATA] = - metadata._getCoreRepresentation(); - client_batch[grpc.opType.SEND_MESSAGE] = message; - client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - client_batch[grpc.opType.RECV_MESSAGE] = true; - client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(client_batch, function(err, response) { - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - var status = response.status; - var error; - var deserialized; - emitter.emit('metadata', Metadata._fromCoreRepresentation( - response.metadata)); - if (status.code === constants.status.OK) { - if (err) { - // Got a batch error, but OK status. Something went wrong - callback(err); - return; - } else { - try { - deserialized = deserialize(response.read); - } catch (e) { - /* Change status to indicate bad server response. This will result - * in passing an error to the callback */ - status = { - code: constants.status.INTERNAL, - details: 'Failed to parse server response' - }; - } - } - } - if (status.code !== constants.status.OK) { - error = new createStatusError(status); - callback(error); - } else { - callback(null, deserialized); - } - emitter.emit('status', status); - }); + var intercepting_call = client_interceptors.getInterceptingCall( + method_definition, + options, + constructor_interceptors, + this.$channel, + callback + ); + var emitter = new ClientUnaryCall(intercepting_call); + var last_listener = client_interceptors.getLastListener( + method_definition, + emitter, + callback + ); + + intercepting_call.start(metadata, last_listener); + intercepting_call.sendMessage(argument); + intercepting_call.halfClose(); + return emitter; }; /** * Make a client stream request to the given method, using the given serialize * and deserialize functions, with the given argument. - * @param {string} method The name of the method to request + * @param {string} path The path of the method to request * @param {grpc~serialize} serialize The serialization function for * inputs * @param {grpc~deserialize} deserialize The deserialization @@ -601,14 +500,14 @@ Client.prototype.makeUnaryRequest = function(method, serialize, deserialize, * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to * the call * @param {grpc.Client~CallOptions=} options Options map - * @param {grpc.Client~requestCallback} callback The callback to for when the + * @param {grpc.Client~requestCallback} callback The callback for when the * response is received * @return {grpc~ClientWritableStream} An event emitter for stream related * events */ -Client.prototype.makeClientStreamRequest = function(method, serialize, - deserialize, metadata, - options, callback) { +Client.prototype.makeClientStreamRequest = function(path, serialize, + deserialize, metadata, + options, callback) { if (options instanceof Function) { callback = options; if (metadata instanceof Metadata) { @@ -629,68 +528,48 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, options = {}; } if (!((metadata instanceof Metadata) && - (options instanceof Object) && - (callback instanceof Function))) { - throw new Error("Argument mismatch in makeClientStreamRequest"); + (options instanceof Object) && + (callback instanceof Function))) { + throw new Error('Argument mismatch in makeClientStreamRequest'); } - var call = getCall(this.$channel, method, options); + + var method_name = this.$method_names[path]; + var constructor_interceptors = this[method_name] ? + this[method_name].interceptors : + null; + var method_definition = options.method_definition = { + path: path, + requestStream: true, + responseStream: false, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + metadata = metadata.clone(); - var stream = new ClientWritableStream(call, serialize); - var metadata_batch = {}; - metadata_batch[grpc.opType.SEND_INITIAL_METADATA] = - metadata._getCoreRepresentation(); - metadata_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - call.startBatch(metadata_batch, function(err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - stream.emit('metadata', Metadata._fromCoreRepresentation( - response.metadata)); - }); - var client_batch = {}; - client_batch[grpc.opType.RECV_MESSAGE] = true; - client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(client_batch, function(err, response) { - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - var status = response.status; - var error; - var deserialized; - if (status.code === constants.status.OK) { - if (err) { - // Got a batch error, but OK status. Something went wrong - callback(err); - return; - } else { - try { - deserialized = deserialize(response.read); - } catch (e) { - /* Change status to indicate bad server response. This will result - * in passing an error to the callback */ - status = { - code: constants.status.INTERNAL, - details: 'Failed to parse server response' - }; - } - } - } - if (status.code !== constants.status.OK) { - error = createStatusError(status); - callback(error); - } else { - callback(null, deserialized); - } - stream.emit('status', status); - }); - return stream; + + var intercepting_call = client_interceptors.getInterceptingCall( + method_definition, + options, + constructor_interceptors, + this.$channel, + callback + ); + var emitter = new ClientWritableStream(intercepting_call); + var last_listener = client_interceptors.getLastListener( + method_definition, + emitter, + callback + ); + + intercepting_call.start(metadata, last_listener); + + return emitter; }; /** * Make a server stream request to the given method, with the given serialize * and deserialize function, using the given argument - * @param {string} method The name of the method to request + * @param {string} path The path of the method to request * @param {grpc~serialize} serialize The serialization function for inputs * @param {grpc~deserialize} deserialize The deserialization * function for outputs @@ -702,7 +581,7 @@ Client.prototype.makeClientStreamRequest = function(method, serialize, * @return {grpc~ClientReadableStream} An event emitter for stream related * events */ -Client.prototype.makeServerStreamRequest = function(method, serialize, +Client.prototype.makeServerStreamRequest = function(path, serialize, deserialize, argument, metadata, options) { if (!(metadata instanceof Metadata)) { @@ -713,48 +592,47 @@ Client.prototype.makeServerStreamRequest = function(method, serialize, options = {}; } if (!((metadata instanceof Metadata) && (options instanceof Object))) { - throw new Error("Argument mismatch in makeServerStreamRequest"); + throw new Error('Argument mismatch in makeServerStreamRequest'); } - var call = getCall(this.$channel, method, options); + + var method_name = this.$method_names[path]; + var constructor_interceptors = this[method_name] ? + this[method_name].interceptors : + null; + var method_definition = options.method_definition = { + path: path, + requestStream: false, + responseStream: true, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + metadata = metadata.clone(); - var stream = new ClientReadableStream(call, deserialize); - var start_batch = {}; - var message = serialize(argument); - if (options) { - message.grpcWriteFlags = options.flags; - } - start_batch[grpc.opType.SEND_INITIAL_METADATA] = - metadata._getCoreRepresentation(); - start_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - start_batch[grpc.opType.SEND_MESSAGE] = message; - start_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - call.startBatch(start_batch, function(err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - stream.emit('metadata', Metadata._fromCoreRepresentation( - response.metadata)); - }); - var status_batch = {}; - status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(status_batch, function(err, response) { - if (err) { - stream.emit('error', err); - return; - } - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - stream._receiveStatus(response.status); - }); - return stream; -}; + var emitter = new ClientReadableStream(); + var intercepting_call = client_interceptors.getInterceptingCall( + method_definition, + options, + constructor_interceptors, + this.$channel, + emitter + ); + emitter.call = intercepting_call; + var last_listener = client_interceptors.getLastListener( + method_definition, + emitter + ); + + intercepting_call.start(metadata, last_listener); + intercepting_call.sendMessage(argument); + intercepting_call.halfClose(); + + return emitter; +}; /** * Make a bidirectional stream request with this method on the given channel. - * @param {string} method The name of the method to request + * @param {string} path The path of the method to request * @param {grpc~serialize} serialize The serialization function for inputs * @param {grpc~deserialize} deserialize The deserialization * function for outputs @@ -763,7 +641,7 @@ Client.prototype.makeServerStreamRequest = function(method, serialize, * @param {grpc.Client~CallOptions=} options Options map * @return {grpc~ClientDuplexStream} An event emitter for stream related events */ -Client.prototype.makeBidiStreamRequest = function(method, serialize, +Client.prototype.makeBidiStreamRequest = function(path, serialize, deserialize, metadata, options) { if (!(metadata instanceof Metadata)) { @@ -774,36 +652,40 @@ Client.prototype.makeBidiStreamRequest = function(method, serialize, options = {}; } if (!((metadata instanceof Metadata) && (options instanceof Object))) { - throw new Error("Argument mismatch in makeBidiStreamRequest"); + throw new Error('Argument mismatch in makeBidiStreamRequest'); } - var call = getCall(this.$channel, method, options); + + var method_name = this.$method_names[path]; + var constructor_interceptors = this[method_name] ? + this[method_name].interceptors : + null; + var method_definition = options.method_definition = { + path: path, + requestStream: true, + responseStream: true, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + metadata = metadata.clone(); - var stream = new ClientDuplexStream(call, serialize, deserialize); - var start_batch = {}; - start_batch[grpc.opType.SEND_INITIAL_METADATA] = - metadata._getCoreRepresentation(); - start_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - call.startBatch(start_batch, function(err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - stream.emit('metadata', Metadata._fromCoreRepresentation( - response.metadata)); - }); - var status_batch = {}; - status_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(status_batch, function(err, response) { - if (err) { - stream.emit('error', err); - return; - } - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - stream._receiveStatus(response.status); - }); - return stream; + + var emitter = new ClientDuplexStream(); + var intercepting_call = client_interceptors.getInterceptingCall( + method_definition, + options, + constructor_interceptors, + this.$channel, + emitter + ); + emitter.call = intercepting_call; + var last_listener = client_interceptors.getLastListener( + method_definition, + emitter + ); + + intercepting_call.start(metadata, last_listener); + + return emitter; }; /** @@ -859,10 +741,10 @@ Client.prototype.waitForReady = function(deadline, callback) { * @private */ var requester_funcs = { - unary: Client.prototype.makeUnaryRequest, - server_stream: Client.prototype.makeServerStreamRequest, - client_stream: Client.prototype.makeClientStreamRequest, - bidi: Client.prototype.makeBidiStreamRequest + [methodTypes.UNARY]: Client.prototype.makeUnaryRequest, + [methodTypes.CLIENT_STREAMING]: Client.prototype.makeClientStreamRequest, + [methodTypes.SERVER_STREAMING]: Client.prototype.makeServerStreamRequest, + [methodTypes.BIDI_STREAMING]: Client.prototype.makeBidiStreamRequest }; function getDefaultValues(metadata, options) { @@ -878,7 +760,7 @@ function getDefaultValues(metadata, options) { * @access private */ var deprecated_request_wrap = { - unary: function(makeUnaryRequest) { + [methodTypes.UNARY]: function(makeUnaryRequest) { return function makeWrappedUnaryRequest(argument, callback, metadata, options) { /* jshint validthis: true */ @@ -887,7 +769,7 @@ var deprecated_request_wrap = { opt_args.options, callback); }; }, - client_stream: function(makeServerStreamRequest) { + [methodTypes.CLIENT_STREAMING]: function(makeServerStreamRequest) { return function makeWrappedClientStreamRequest(callback, metadata, options) { /* jshint validthis: true */ @@ -896,8 +778,8 @@ var deprecated_request_wrap = { opt_args.options, callback); }; }, - server_stream: _.identity, - bidi: _.identity + [methodTypes.SERVER_STREAMING]: _.identity, + [methodTypes.BIDI_STREAMING]: _.identity }; /** @@ -932,38 +814,29 @@ exports.makeClientConstructor = function(methods, serviceName, } util.inherits(ServiceClient, Client); + ServiceClient.prototype.$method_definitions = methods; + ServiceClient.prototype.$method_names = {}; _.each(methods, function(attrs, name) { - var method_type; if (_.startsWith(name, '$')) { throw new Error('Method names cannot start with $'); } - if (attrs.requestStream) { - if (attrs.responseStream) { - method_type = 'bidi'; - } else { - method_type = 'client_stream'; - } - } else { - if (attrs.responseStream) { - method_type = 'server_stream'; - } else { - method_type = 'unary'; - } - } - var serialize = attrs.requestSerialize; - var deserialize = attrs.responseDeserialize; + var method_type = common.getMethodType(attrs); var method_func = _.partial(requester_funcs[method_type], attrs.path, - serialize, deserialize); + attrs.requestSerialize, + attrs.responseDeserialize); if (class_options.deprecatedArgumentOrder) { - ServiceClient.prototype[name] = deprecated_request_wrap(method_func); + ServiceClient.prototype[name] = + deprecated_request_wrap[method_type](method_func); } else { ServiceClient.prototype[name] = method_func; } + ServiceClient.prototype.$method_names[attrs.path] = name; // Associate all provided attributes with the method _.assign(ServiceClient.prototype[name], attrs); if (attrs.originalName) { - ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; + ServiceClient.prototype[attrs.originalName] = + ServiceClient.prototype[name]; } }); @@ -984,6 +857,17 @@ exports.getClientChannel = function(client) { return Client.prototype.getChannel.call(client); }; +/** + * Gets a map of client method names to interceptor stacks. + * @param {grpc.Client} client + * @returns {Object.} + */ +exports.getClientInterceptors = function(client) { + return _.mapValues(client.$method_definitions, function(def, name) { + return client[name].interceptors; + }); +}; + /** * Wait for the client to be ready. The callback will be called when the * client has successfully connected to the server, and it will be called @@ -1002,3 +886,8 @@ exports.getClientChannel = function(client) { exports.waitForClientReady = function(client, deadline, callback) { Client.prototype.waitForReady.call(client, deadline, callback); }; + +exports.StatusBuilder = client_interceptors.StatusBuilder; +exports.ListenerBuilder = client_interceptors.ListenerBuilder; +exports.RequesterBuilder = client_interceptors.RequesterBuilder; +exports.InterceptingCall = client_interceptors.InterceptingCall; diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js new file mode 100644 index 000000000..cf7171fa4 --- /dev/null +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -0,0 +1,1343 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/** + * Client Interceptors + * + * This module describes the interceptor framework for clients. + * An interceptor is a function which takes an options object and a nextCall + * function and returns an InterceptingCall: + * + * ``` + * var interceptor = function(options, nextCall) { + * return new InterceptingCall(nextCall(options)); + * } + * ``` + * + * The interceptor function must return an InterceptingCall object. Returning + * `new InterceptingCall(nextCall(options))` will satisfy the contract (but + * provide no interceptor functionality). `nextCall` is a function which will + * generate the next interceptor in the chain. + * + * To implement interceptor functionality, create a requester and pass it to + * the InterceptingCall constructor: + * + * `return new InterceptingCall(nextCall(options), requester);` + * + * A requester is a POJO with zero or more of the following methods: + * + * `start(metadata, listener, next)` + * * To continue, call next(metadata, listener). Listeners are described + * * below. + * + * `sendMessage(message, next)` + * * To continue, call next(message). + * + * `halfClose(next)` + * * To continue, call next(). + * + * `cancel(message, next)` + * * To continue, call next(). + * + * A listener is a POJO with one or more of the following methods: + * + * `onReceiveMetadata(metadata, next)` + * * To continue, call next(metadata) + * + * `onReceiveMessage(message, next)` + * * To continue, call next(message) + * + * `onReceiveStatus(status, next)` + * * To continue, call next(status) + * + * A listener is provided by the requester's `start` method. The provided + * listener implements all the inbound interceptor methods, which can be called + * to short-circuit the gRPC call. + * + * Three usage patterns are supported for listeners: + * 1) Pass the listener along without modification: `next(metadata, listener)`. + * In this case the interceptor declines to intercept any inbound operations. + * 2) Create a new listener with one or more inbound interceptor methods and + * pass it to `next`. In this case the interceptor will fire on the inbound + * operations implemented in the new listener. + * 3) Make direct inbound calls to the provided listener's methods. This + * short-circuits the interceptor stack. + * + * Do not modify the listener passed in. Either pass it along unmodified, + * ignore it, or call methods on it to short-circuit the call. + * + * To intercept errors, implement the `onReceiveStatus` method and test for + * `status.code !== grpc.status.OK`. + * + * To intercept trailers, examine `status.metadata` in the `onReceiveStatus` + * method. + * + * This is a trivial implementation of all interceptor methods: + * var interceptor = function(options, nextCall) { + * return new InterceptingCall(nextCall(options), { + * start: function(metadata, listener, next) { + * next(metadata, { + * onReceiveMetadata: function (metadata, next) { + * next(metadata); + * }, + * onReceiveMessage: function (message, next) { + * next(message); + * }, + * onReceiveStatus: function (status, next) { + * next(status); + * }, + * }); + * }, + * sendMessage: function(message, next) { + * next(message); + * }, + * halfClose: function(next) { + * next(); + * }, + * cancel: function(message, next) { + * next(); + * } + * }); + * }; + * + * This is an interceptor with a single method: + * var interceptor = function(options, nextCall) { + * return new InterceptingCall(nextCall(options), { + * sendMessage: function(message, next) { + * next(message); + * } + * }); + * }; + * + * Builders are provided for convenience: StatusBuilder, ListenerBuilder, + * and RequesterBuilder + * + * gRPC client operations use this mapping to interceptor methods: + * + * grpc.opType.SEND_INITIAL_METADATA -> start + * grpc.opType.SEND_MESSAGE -> sendMessage + * grpc.opType.SEND_CLOSE_FROM_CLIENT -> halfClose + * grpc.opType.RECV_INITIAL_METADATA -> onReceiveMetadata + * grpc.opType.RECV_MESSAGE -> onReceiveMessage + * grpc.opType.RECV_STATUS_ON_CLIENT -> onReceiveStatus + * + * @module + */ + +'use strict'; + +var _ = require('lodash'); +var grpc = require('./grpc_extension'); +var Metadata = require('./metadata'); +var constants = require('./constants'); +var common = require('./common'); +var methodTypes = constants.methodTypes; +var EventEmitter = require('events').EventEmitter; + +/** + * A custom error thrown when interceptor configuration fails. + * @param {string} message The error message + * @param {object=} extra + * @constructor + */ +var InterceptorConfigurationError = + function InterceptorConfigurationError(message, extra) { + Error.captureStackTrace(this, this.constructor); + this.name = this.constructor.name; + this.message = message; + this.extra = extra; + }; + +require('util').inherits(InterceptorConfigurationError, Error); + +/** + * A builder for gRPC status objects. + * @constructor + */ +function StatusBuilder() { + this.code = null; + this.details = null; + this.metadata = null; +} + +/** + * Adds a status code to the builder. + * @param {number} code The status code. + * @return {StatusBuilder} + */ +StatusBuilder.prototype.withCode = function(code) { + this.code = code; + return this; +}; + +/** + * Adds details to the builder. + * @param {string} details A status message. + * @return {StatusBuilder} + */ +StatusBuilder.prototype.withDetails = function(details) { + this.details = details; + return this; +}; + +/** + * Adds metadata to the builder. + * @param {Metadata} metadata The gRPC status metadata. + * @return {StatusBuilder} + */ +StatusBuilder.prototype.withMetadata = function(metadata) { + this.metadata = metadata; + return this; +}; + +/** + * Builds the status object. + * @return {grpc~StatusObject} A gRPC status. + */ +StatusBuilder.prototype.build = function() { + var status = {}; + if (this.code !== undefined) { + status.code = this.code; + } + if (this.details) { + status.details = this.details; + } + if (this.metadata) { + status.metadata = this.metadata; + } + return status; +}; + +/** + * A builder for listener interceptors. + * @constructor + */ +function ListenerBuilder() { + this.metadata = null; + this.message = null; + this.status = null; +} + +/** + * Adds an onReceiveMetadata method to the builder. + * @param {MetadataListener} on_receive_metadata A listener method for + * receiving metadata. + * @return {ListenerBuilder} + */ +ListenerBuilder.prototype.withOnReceiveMetadata = + function(on_receive_metadata) { + this.metadata = on_receive_metadata; + return this; + }; + +/** + * Adds an onReceiveMessage method to the builder. + * @param {MessageListener} on_receive_message A listener method for receiving + * messages. + * @return {ListenerBuilder} + */ +ListenerBuilder.prototype.withOnReceiveMessage = function(on_receive_message) { + this.message = on_receive_message; + return this; +}; + +/** + * Adds an onReceiveStatus method to the builder. + * @param {StatusListener} on_receive_status A listener method for receiving + * status. + * @return {ListenerBuilder} + */ +ListenerBuilder.prototype.withOnReceiveStatus = function(on_receive_status) { + this.status = on_receive_status; + return this; +}; + +/** + * Builds the call listener. + * @return {grpc~Listener} + */ +ListenerBuilder.prototype.build = function() { + var self = this; + var listener = {}; + listener.onReceiveMetadata = self.metadata; + listener.onReceiveMessage = self.message; + listener.onReceiveStatus = self.status; + return listener; +}; + +/** + * A builder for the outbound methods of an interceptor. + * @constructor + */ +function RequesterBuilder() { + this.start = null; + this.message = null; + this.half_close = null; + this.cancel = null; +} + +/** + * Add a metadata requester to the builder. + * @param {MetadataRequester} start A requester method for handling metadata. + * @return {RequesterBuilder} + */ +RequesterBuilder.prototype.withStart = function(start) { + this.start = start; + return this; +}; + +/** + * Add a message requester to the builder. + * @param {MessageRequester} send_message A requester method for handling + * messages. + * @return {RequesterBuilder} + */ +RequesterBuilder.prototype.withSendMessage = function(send_message) { + this.message = send_message; + return this; +}; + +/** + * Add a close requester to the builder. + * @param {CloseRequester} half_close A requester method for handling client + * close. + * @return {RequesterBuilder} + */ +RequesterBuilder.prototype.withHalfClose = function(half_close) { + this.half_close = half_close; + return this; +}; + +/** + * Add a cancel requester to the builder. + * @param {CancelRequester} cancel A requester method for handling `cancel` + * @return {RequesterBuilder} + */ +RequesterBuilder.prototype.withCancel = function(cancel) { + this.cancel = cancel; + return this; +}; + +/** + * Builds the requester's interceptor methods. + * @return {grpc~Requester} + */ +RequesterBuilder.prototype.build = function() { + var requester = {}; + requester.start = this.start; + requester.sendMessage = this.message; + requester.halfClose = this.half_close; + requester.cancel = this.cancel; + return requester; +}; + +/** + * Transforms a list of interceptor providers into interceptors. + * @param {InterceptorProvider[]} providers + * @param {grpc~MethodDefinition} method_definition + * @return {null|Interceptor[]} + */ +var resolveInterceptorProviders = function(providers, method_definition) { + if (!_.isArray(providers)) { + return null; + } + var interceptors = []; + for (var i = 0; i < providers.length; i++) { + var provider = providers[i]; + var interceptor = provider(method_definition); + if (interceptor) { + interceptors.push(interceptor); + } + } + return interceptors; +}; + +/** + * Resolves interceptor options at call invocation time + * @param {grpc.Client~CallOptions} options The call options passed to a gRPC + * call. + * @param {Interceptor[]} [options.interceptors] + * @param {InterceptorProvider[]} [options.interceptor_providers] + * @param {grpc~MethodDefinition} method_definition + * @return {null|function[]} + */ +var resolveInterceptorOptions = function(options, method_definition) { + var provided = resolveInterceptorProviders(options.interceptor_providers, + method_definition); + if (_.isArray(options.interceptors) && _.isArray(provided)) { + throw new InterceptorConfigurationError( + 'Both interceptors and interceptor_providers were passed as options ' + + 'to the call invocation. Only one of these is allowed.'); + } + if (_.isArray(options.interceptors)) { + return options.interceptors; + } + if (_.isArray(provided)) { + return provided; + } + return null; +}; + +/** + * A chainable gRPC call proxy which will delegate to an optional requester + * object. By default, interceptor methods will chain to next_call. If a + * requester is provided which implements an interceptor method, that + * requester method will be executed as part of the chain. + * @param {InterceptingCall|null} next_call The next call in the chain + * @param {grpc~Requester=} requester Interceptor methods to handle request + * operations. + * @constructor + */ +function InterceptingCall(next_call, requester) { + this.next_call = next_call; + this.requester = requester; +} + +/** + * Get the next method in the chain or a no-op function if we are at the end + * of the chain + * @param {string} method_name + * @return {function} The next method in the chain + * @private + */ +InterceptingCall.prototype._getNextCall = function(method_name) { + return this.next_call ? + this.next_call[method_name].bind(this.next_call) : + function(){}; +}; + +/** + * Call the next method in the chain. This will either be on the next + * InterceptingCall (next_call), or the requester if the requester + * implements the method. + * @param {string} method_name The name of the interceptor method + * @param {array=} args Payload arguments for the operation + * @param {function=} next The next InterceptingCall's method + * @return {null} + * @private + */ +InterceptingCall.prototype._callNext = function(method_name, args, next) { + var args_array = args || []; + var next_call = next ? next : this._getNextCall(method_name); + if (this.requester && this.requester[method_name]) { + // Avoid using expensive `apply` calls + var num_args = args_array.length; + switch (num_args) { + case 0: + return this.requester[method_name](next_call); + case 1: + return this.requester[method_name](args_array[0], next_call); + case 2: + return this.requester[method_name](args_array[0], args_array[1], + next_call); + } + } else { + return next_call(args_array[0], args_array[1]); + } +}; + +/** + * Starts a call through the outbound interceptor chain and adds an element to + * the reciprocal inbound listener chain. + * @param {grpc.Metadata} metadata The outgoing metadata. + * @param {grpc~Listener} listener An intercepting listener for inbound + * operations. + */ +InterceptingCall.prototype.start = function(metadata, listener) { + var self = this; + + // If the listener provided is an InterceptingListener, use it. Otherwise, we + // must be at the end of the listener chain, and any listener operations + // should be terminated in an EndListener. + var next_listener = _getInterceptingListener(listener, new EndListener()); + + // Build the next method in the interceptor chain + var next = function(metadata, current_listener) { + // If there is a next call in the chain, run it. Otherwise do nothing. + if (self.next_call) { + // Wire together any listener provided with the next listener + var listener = _getInterceptingListener(current_listener, next_listener); + self.next_call.start(metadata, listener); + } + }; + this._callNext('start', [metadata, next_listener], next); +}; + +/** + * Pass a message through the interceptor chain. + * @param {jspb.Message} message + */ +InterceptingCall.prototype.sendMessage = function(message) { + this._callNext('sendMessage', [message]); +}; + +/** + * Run a close operation through the interceptor chain + */ +InterceptingCall.prototype.halfClose = function() { + this._callNext('halfClose'); +}; + +/** + * Run a cancel operation through the interceptor chain + */ +InterceptingCall.prototype.cancel = function() { + this._callNext('cancel'); +}; + +/** + * Run a cancelWithStatus operation through the interceptor chain. + * @param {grpc~StatusObject} status + * @param {string} message + */ +InterceptingCall.prototype.cancelWithStatus = function(status, message) { + this._callNext('cancelWithStatus', [status, message]); +}; + +/** + * Pass a getPeer call down to the base gRPC call (should not be intercepted) + * @return {object} + */ +InterceptingCall.prototype.getPeer = function() { + return this._callNext('getPeer'); +}; + +/** + * For streaming calls, we need to transparently pass the stream's context + * through the interceptor chain. Passes the context between InterceptingCalls + * but hides it from any requester implementations. + * @param {object} context Carries objects needed for streaming operations. + * @param {jspb.Message} message The message to send. + */ +InterceptingCall.prototype.sendMessageWithContext = function(context, message) { + var next = this.next_call ? + this.next_call.sendMessageWithContext.bind(this.next_call, context) : + context; + this._callNext('sendMessage', [message], next); +}; + +/** + * For receiving streaming messages, we need to seed the base interceptor with + * the streaming context to create a RECV_MESSAGE batch. + * @param {object} context Carries objects needed for streaming operations + */ +InterceptingCall.prototype.recvMessageWithContext = function(context) { + this._callNext('recvMessageWithContext', [context]); +}; + +/** + * A chain-able listener object which will delegate to a custom listener when + * appropriate. + * @param {InterceptingListener|null} next_listener The next + * InterceptingListener in the chain + * @param {grpc~Listener=} delegate A custom listener object which may implement + * specific operations + * @constructor + */ +function InterceptingListener(next_listener, delegate) { + this.delegate = delegate || {}; + this.next_listener = next_listener; +} + +/** + * Get the next method in the chain or a no-op function if we are at the end + * of the chain. + * @param {string} method_name The name of the listener method. + * @return {function} The next method in the chain + * @private + */ +InterceptingListener.prototype._getNextListener = function(method_name) { + return this.next_listener ? + this.next_listener[method_name].bind(this.next_listener) : + function(){}; +}; + +/** + * Call the next method in the chain. This will either be on the next + * InterceptingListener (next_listener), or the requester if the requester + * implements the method. + * @param {string} method_name The name of the interceptor method + * @param {array=} args Payload arguments for the operation + * @param {function=} next The next InterceptingListener's method + * @return {null} + * @private + */ +InterceptingListener.prototype._callNext = function(method_name, args, next) { + var args_array = args || []; + var next_listener = next ? next : this._getNextListener(method_name); + if (this.delegate && this.delegate[method_name]) { + // Avoid using expensive `apply` calls + var num_args = args_array.length; + switch (num_args) { + case 0: + return this.delegate[method_name](next_listener); + case 1: + return this.delegate[method_name](args_array[0], next_listener); + case 2: + return this.delegate[method_name](args_array[0], args_array[1], + next_listener); + } + } else { + return next_listener(args_array[0], args_array[1]); + } +}; +/** + * Inbound metadata receiver. + * @param {Metadata} metadata + */ +InterceptingListener.prototype.onReceiveMetadata = function(metadata) { + this._callNext('onReceiveMetadata', [metadata]); +}; + +/** + * Inbound message receiver. + * @param {jspb.Message} message + */ +InterceptingListener.prototype.onReceiveMessage = function(message) { + this._callNext('onReceiveMessage', [message]); +}; + +/** + * When intercepting streaming message, we need to pass the streaming context + * transparently along the chain. Hides the context from the delegate listener + * methods. + * @param {object} context Carries objects needed for streaming operations. + * @param {jspb.Message} message The message received. + */ +InterceptingListener.prototype.recvMessageWithContext = function(context, + message) { + var fallback = this.next_listener.recvMessageWithContext; + var next_method = this.next_listener ? + fallback.bind(this.next_listener, context) : + context; + if (this.delegate.onReceiveMessage) { + this.delegate.onReceiveMessage(message, next_method, context); + } else { + next_method(message); + } +}; + +/** + * Inbound status receiver. + * @param {grpc~StatusObject} status + */ +InterceptingListener.prototype.onReceiveStatus = function(status) { + this._callNext('onReceiveStatus', [status]); +}; + +/** + * A dead-end listener used to terminate a call chain. Used when an interceptor + * creates a branch chain, when the branch returns the listener chain will + * terminate here. + * @constructor + */ +function EndListener() {} +EndListener.prototype.onReceiveMetadata = function(){}; +EndListener.prototype.onReceiveMessage = function(){}; +EndListener.prototype.onReceiveStatus = function(){}; +EndListener.prototype.recvMessageWithContext = function(){}; + +/** + * Produces a callback triggered by streaming response messages. + * @private + * @param {EventEmitter} emitter + * @param {grpc.internal~Call} call + * @param {grpc~Listener} listener + * @param {grpc~deserialize} deserialize + * @return {Function} + */ +function _getStreamReadCallback(emitter, call, listener, deserialize) { + return function (err, response) { + if (err) { + // Something has gone wrong. Stop reading and wait for status + emitter.finished = true; + emitter._readsDone(); + return; + } + var data = response.read; + var deserialized; + try { + deserialized = deserialize(data); + } catch (e) { + emitter._readsDone({ + code: constants.status.INTERNAL, + details: 'Failed to parse server response' + }); + return; + } + if (data === null) { + emitter._readsDone(); + return; + } + var context = { + call: call, + listener: listener + }; + listener.recvMessageWithContext(context, deserialized); + }; +} + +/** + * Produces an interceptor which will start gRPC batches for unary calls. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {grpc.Channel} channel + * @param {EventEmitter} emitter + * @param {function} callback + * @return {Interceptor} + */ +function _getUnaryInterceptor(method_definition, channel, emitter, callback) { + var serialize = method_definition.requestSerialize; + var deserialize = method_definition.responseDeserialize; + return function (options) { + var call = common.getCall(channel, method_definition.path, options); + var first_listener; + return new InterceptingCall(null, { + start: function (metadata, listener) { + var batch = { + [grpc.opType.SEND_INITIAL_METADATA]: + metadata._getCoreRepresentation(), + }; + first_listener = listener; + call.startBatch(batch, function () {}); + }, + sendMessage: function(message) { + var batch = { + [grpc.opType.SEND_MESSAGE]: serialize(message), + }; + call.startBatch(batch, function () {}); + }, + halfClose: function() { + var batch = { + [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true, + [grpc.opType.RECV_INITIAL_METADATA]: true, + [grpc.opType.RECV_MESSAGE]: true, + [grpc.opType.RECV_STATUS_ON_CLIENT]: true + }; + call.startBatch(batch, function (err, response) { + response.status.metadata = Metadata._fromCoreRepresentation( + response.status.metadata); + var status = response.status; + var deserialized; + if (status.code === constants.status.OK) { + if (err) { + // Got a batch error, but OK status. Something went wrong + callback(err); + return; + } else { + try { + deserialized = deserialize(response.read); + } catch (e) { + /* Change status to indicate bad server response. This + * will result in passing an error to the callback */ + status = { + code: constants.status.INTERNAL, + details: 'Failed to parse server response' + }; + } + } + } + response.metadata = + Metadata._fromCoreRepresentation(response.metadata); + first_listener.onReceiveMetadata(response.metadata); + first_listener.onReceiveMessage(deserialized); + first_listener.onReceiveStatus(status); + }); + } + }); + }; +} + +/** + * Produces an interceptor which will start gRPC batches for client streaming + * calls. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {grpc.Channel} channel + * @param {EventEmitter} emitter + * @param {function} callback + * @return {Interceptor} + */ +function _getClientStreamingInterceptor(method_definition, channel, emitter, + callback) { + var serialize = common.wrapIgnoreNull(method_definition.requestSerialize); + var deserialize = method_definition.responseDeserialize; + return function (options) { + var first_listener; + var call = common.getCall(channel, method_definition.path, options); + var final_requester = {}; + final_requester.start = function (metadata, listener) { + var metadata_batch = { + [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), + [grpc.opType.RECV_INITIAL_METADATA]: true + }; + first_listener = listener; + call.startBatch(metadata_batch, function (err, response) { + if (err) { + // The call has stopped for some reason. A non-OK status will arrive + // in the other batch. + return; + } + response.metadata = Metadata._fromCoreRepresentation(response.metadata); + listener.onReceiveMetadata(response.metadata); + }); + var recv_batch = {}; + recv_batch[grpc.opType.RECV_MESSAGE] = true; + recv_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; + call.startBatch(recv_batch, function (err, response) { + response.status.metadata = Metadata._fromCoreRepresentation( + response.status.metadata); + var status = response.status; + var deserialized; + if (status.code === constants.status.OK) { + if (err) { + // Got a batch error, but OK status. Something went wrong + callback(err); + return; + } else { + try { + deserialized = deserialize(response.read); + } catch (e) { + /* Change status to indicate bad server response. This will result + * in passing an error to the callback */ + status = { + code: constants.status.INTERNAL, + details: 'Failed to parse server response' + }; + } + } + } + listener.onReceiveMessage(deserialized); + listener.onReceiveStatus(status); + }); + }; + final_requester.sendMessage = function (chunk, context) { + var message; + var callback = (context && context.callback) ? + context.callback : + function () { }; + var encoding = (context && context.encoding) ? + context.encoding : + ''; + try { + message = serialize(chunk); + } catch (e) { + /* Sending this error to the server and emitting it immediately on the + client may put the call in a slightly weird state on the client side, + but passing an object that causes a serialization failure is a misuse + of the API anyway, so that's OK. The primary purpose here is to give + the programmer a useful error and to stop the stream properly */ + call.cancelWithStatus(constants.status.INTERNAL, + 'Serialization failure'); + callback(e); + return; + } + if (_.isFinite(encoding)) { + /* Attach the encoding if it is a finite number. This is the closest we + * can get to checking that it is valid flags */ + message.grpcWriteFlags = encoding; + } + var batch = { + [grpc.opType.SEND_MESSAGE]: message + }; + call.startBatch(batch, function (err, event) { + callback(err, event); + }); + }; + final_requester.halfClose = function () { + var batch = { + [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true + }; + call.startBatch(batch, function () { }); + }; + return new InterceptingCall(null, final_requester); + }; +} + +/** + * Produces an interceptor which will start gRPC batches for server streaming + * calls. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {grpc.Channel} channel + * @param {EventEmitter} emitter + * @return {Interceptor} + */ +function _getServerStreamingInterceptor(method_definition, channel, emitter) { + var deserialize = common.wrapIgnoreNull( + method_definition.responseDeserialize); + var serialize = method_definition.requestSerialize; + return function (options) { + var first_listener; + var call = common.getCall(channel, method_definition.path, options); + var final_requester = {}; + final_requester.start = function(metadata, listener) { + first_listener = listener; + metadata = metadata.clone(); + var metadata_batch = { + [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), + [grpc.opType.RECV_INITIAL_METADATA]: true, + }; + call.startBatch(metadata_batch, function(err, response) { + if (err) { + // The call has stopped for some reason. A non-OK status will arrive + // in the other batch. + return; + } + first_listener.onReceiveMetadata( + Metadata._fromCoreRepresentation(response.metadata)); + }); + var status_batch = { + [grpc.opType.RECV_STATUS_ON_CLIENT]: true + }; + call.startBatch(status_batch, function(err, response) { + if (err) { + emitter.emit('error', err); + return; + } + response.status.metadata = Metadata._fromCoreRepresentation( + response.status.metadata); + first_listener.onReceiveStatus(response.status); + }); + }; + final_requester.sendMessage = function(argument) { + var message = serialize(argument); + if (options) { + message.grpcWriteFlags = options.flags; + } + var send_batch = { + [grpc.opType.SEND_MESSAGE]: message + }; + call.startBatch(send_batch, function(err, response) { + if (err) { + // The call has stopped for some reason. A non-OK status will arrive + // in the other batch. + return; + } + }); + }; + final_requester.halfClose = function() { + var batch = { + [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true + }; + call.startBatch(batch, function() {}); + }; + final_requester.recvMessageWithContext = function(context) { + var recv_batch = { + [grpc.opType.RECV_MESSAGE]: true + }; + call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, + first_listener, deserialize)); + }; + return new InterceptingCall(null, final_requester); + }; +} + +/** + * Produces an interceptor which will start gRPC batches for bi-directional + * calls. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {grpc.Channel} channel + * @param {EventEmitter} emitter + * @return {Interceptor} + */ +function _getBidiStreamingInterceptor(method_definition, channel, emitter) { + var serialize = common.wrapIgnoreNull(method_definition.requestSerialize); + var deserialize = common.wrapIgnoreNull( + method_definition.responseDeserialize); + return function (options) { + var first_listener; + var call = common.getCall(channel, method_definition.path, options); + var final_requester = {}; + final_requester.start = function (metadata, listener) { + var metadata_batch = { + [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), + [grpc.opType.RECV_INITIAL_METADATA]: true + }; + first_listener = listener; + call.startBatch(metadata_batch, function (err, response) { + if (err) { + // The call has stopped for some reason. A non-OK status will arrive + // in the other batch. + return; + } + response.metadata = Metadata._fromCoreRepresentation(response.metadata); + listener.onReceiveMetadata(response.metadata); + }); + var recv_batch = {}; + recv_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; + call.startBatch(recv_batch, function (err, response) { + var status = response.status; + if (status.code === constants.status.OK) { + if (err) { + emitter.emit('error', err); + return; + } + } + response.status.metadata = Metadata._fromCoreRepresentation( + response.status.metadata); + listener.onReceiveStatus(status); + }); + }; + final_requester.sendMessage = function (chunk, context) { + var message; + var callback = (context && context.callback) ? + context.callback : + function() {}; + var encoding = (context && context.encoding) ? + context.encoding : + ''; + try { + message = serialize(chunk); + } catch (e) { + /* Sending this error to the server and emitting it immediately on the + client may put the call in a slightly weird state on the client side, + but passing an object that causes a serialization failure is a misuse + of the API anyway, so that's OK. The primary purpose here is to give + the programmer a useful error and to stop the stream properly */ + call.cancelWithStatus(constants.status.INTERNAL, + 'Serialization failure'); + callback(e); + return; + } + if (_.isFinite(encoding)) { + /* Attach the encoding if it is a finite number. This is the closest we + * can get to checking that it is valid flags */ + message.grpcWriteFlags = encoding; + } + var batch = { + [grpc.opType.SEND_MESSAGE]: message + }; + call.startBatch(batch, function (err, event) { + callback(err, event); + }); + }; + final_requester.halfClose = function () { + var batch = { + [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true + }; + call.startBatch(batch, function () { }); + }; + final_requester.recvMessageWithContext = function(context) { + var recv_batch = { + [grpc.opType.RECV_MESSAGE]: true + }; + call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, + first_listener, deserialize)); + }; + return new InterceptingCall(null, final_requester); + }; +} + +/** + * Produces a listener for responding to callers of unary RPCs. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {EventEmitter} emitter + * @param {function} callback + * @return {grpc~Listener} + */ +function _getUnaryListener(method_definition, emitter, callback) { + var resultMessage; + return { + onReceiveMetadata: function (metadata) { + emitter.emit('metadata', metadata); + }, + onReceiveMessage: function (message) { + resultMessage = message; + }, + onReceiveStatus: function (status) { + if (status.code !== constants.status.OK) { + var error = common.createStatusError(status); + callback(error); + } else { + callback(null, resultMessage); + } + emitter.emit('status', status); + } + }; +} + +/** + * Produces a listener for responding to callers of client streaming RPCs. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {EventEmitter} emitter + * @param {function} callback + * @return {grpc~Listener} + */ +function _getClientStreamingListener(method_definition, emitter, callback) { + var resultMessage; + return { + onReceiveMetadata: function (metadata) { + emitter.emit('metadata', metadata); + }, + onReceiveMessage: function (message) { + resultMessage = message; + }, + onReceiveStatus: function (status) { + if (status.code !== constants.status.OK) { + var error = common.createStatusError(status); + callback(error); + } else { + callback(null, resultMessage); + } + emitter.emit('status', status); + } + }; +} + +/** + * Produces a listener for responding to callers of server streaming RPCs. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {EventEmitter} emitter + * @return {grpc~Listener} + */ +function _getServerStreamingListener(method_definition, emitter) { + var deserialize = common.wrapIgnoreNull( + method_definition.responseDeserialize); + return { + onReceiveMetadata: function (metadata) { + emitter.emit('metadata', metadata); + }, + onReceiveMessage: function(message, next, context) { + if (emitter.push(message) && message !== null) { + var call = context.call; + var listener = context.listener; + var read_batch = {}; + read_batch[grpc.opType.RECV_MESSAGE] = true; + call.startBatch(read_batch, _getStreamReadCallback(emitter, call, + listener, deserialize)); + } else { + emitter.reading = false; + } + }, + onReceiveStatus: function (status) { + emitter._receiveStatus(status); + } + }; +} + +/** + * Produces a listener for responding to callers of bi-directional RPCs. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {EventEmitter} emitter + * @return {grpc~Listener} + */ +function _getBidiStreamingListener(method_definition, emitter) { + var deserialize = common.wrapIgnoreNull( + method_definition.responseDeserialize); + return { + onReceiveMetadata: function (metadata) { + emitter.emit('metadata', metadata); + }, + onReceiveMessage: function(message, next, context) { + if (emitter.push(message) && message !== null) { + var call = context.call; + var listener = context.listener; + var read_batch = {}; + read_batch[grpc.opType.RECV_MESSAGE] = true; + call.startBatch(read_batch, _getStreamReadCallback(emitter, call, + listener, deserialize)); + } else { + emitter.reading = false; + } + }, + onReceiveStatus: function (status) { + emitter._receiveStatus(status); + } + }; +} + +var interceptorGenerators = { + [methodTypes.UNARY]: _getUnaryInterceptor, + [methodTypes.CLIENT_STREAMING]: _getClientStreamingInterceptor, + [methodTypes.SERVER_STREAMING]: _getServerStreamingInterceptor, + [methodTypes.BIDI_STREAMING]: _getBidiStreamingInterceptor +}; + +var listenerGenerators = { + [methodTypes.UNARY]: _getUnaryListener, + [methodTypes.CLIENT_STREAMING]: _getClientStreamingListener, + [methodTypes.SERVER_STREAMING]: _getServerStreamingListener, + [methodTypes.BIDI_STREAMING]: _getBidiStreamingListener +}; + +/** + * Creates the last listener in an interceptor stack. + * @param {grpc~MethodDefinition} method_definition + * @param {EventEmitter} emitter + * @param {function=} callback + * @return {grpc~Listener} + */ +function getLastListener(method_definition, emitter, callback) { + if (emitter instanceof Function) { + callback = emitter; + callback = function() {}; + } + if (!(callback instanceof Function)) { + callback = function() {}; + } + if (!((emitter instanceof EventEmitter) && + (callback instanceof Function))) { + throw new Error('Argument mismatch in getLastListener'); + } + var method_type = common.getMethodType(method_definition); + var generator = listenerGenerators[method_type]; + return generator(method_definition, emitter, callback); +} + +/** + * + * @param {grpc~MethodDefinition} method_definition + * @param {grpc.Client~CallOptions} options + * @param {Interceptor[]} constructor_interceptors + * @param {grpc.Channel} channel + * @param {function|EventEmitter} responder + */ +function getInterceptingCall(method_definition, options, + constructor_interceptors, channel, responder) { + var interceptors = _processInterceptorLayers( + options, + constructor_interceptors, + method_definition + ); + var last_interceptor = _getLastInterceptor(method_definition, channel, + responder); + var all_interceptors = interceptors.concat(last_interceptor); + return _buildChain(all_interceptors, options); +} + +/** + * Creates the last interceptor in an interceptor stack. + * @private + * @param {grpc~MethodDefinition} method_definition + * @param {grpc.Channel} channel + * @param {function|EventEmitter} responder + * @return {Interceptor} + */ +function _getLastInterceptor(method_definition, channel, responder) { + var callback = (responder instanceof Function) ? responder : function() {}; + var emitter = (responder instanceof EventEmitter) ? responder : + new EventEmitter(); + var method_type = common.getMethodType(method_definition); + var generator = interceptorGenerators[method_type]; + return generator(method_definition, channel, emitter, callback); +} + +/** + * Chain a list of interceptors together and return the first InterceptingCall. + * @private + * @param {Interceptor[]} interceptors An interceptor stack. + * @param {grpc.Client~CallOptions} options Call options. + * @return {InterceptingCall} + */ +function _buildChain(interceptors, options) { + var next = function(interceptors) { + if (interceptors.length === 0) { + return function (options) {}; + } + var head_interceptor = interceptors[0]; + var rest_interceptors = interceptors.slice(1); + return function (options) { + return head_interceptor(options, next(rest_interceptors)); + }; + }; + var chain = next(interceptors)(options); + return new InterceptingCall(chain); +} + +/** + * Process call options and the interceptor override layers to get the final set + * of interceptors. + * @private + * @param {grpc.Client~CallOptions} call_options The options passed to the gRPC + * call. + * @param {Interceptor[]} constructor_interceptors Interceptors passed to the + * client constructor. + * @param {grpc~MethodDefinition} method_definition Details of the RPC method. + * @return {Interceptor[]|null} The final set of interceptors. + */ +function _processInterceptorLayers(call_options, + constructor_interceptors, + method_definition) { + var calltime_interceptors = resolveInterceptorOptions(call_options, + method_definition); + var interceptor_overrides = [ + calltime_interceptors, + constructor_interceptors + ]; + return _resolveInterceptorOverrides(interceptor_overrides); +} + +/** + * Wraps a plain listener object in an InterceptingListener if it isn't an + * InterceptingListener already. + * @param {InterceptingListener|object|null} current_listener + * @param {InterceptingListener|EndListener} next_listener + * @return {InterceptingListener|null} + * @private + */ +function _getInterceptingListener(current_listener, next_listener) { + if (!_isInterceptingListener(current_listener)) { + return new InterceptingListener(next_listener, current_listener); + } + return current_listener; +} + +/** + * Test if the listener exists and is an InterceptingListener. + * @param listener + * @return {boolean} + * @private + */ +function _isInterceptingListener(listener) { + return listener && listener.constructor.name === 'InterceptingListener'; +} + +/** + * Chooses the first valid array of interceptors or returns null. + * @param {Interceptor[][]} interceptor_lists A list of interceptor lists in + * descending override priority order. + * @return {Interceptor[]|null} The resulting interceptors + * @private + */ +function _resolveInterceptorOverrides(interceptor_lists) { + for (var i = 0; i < interceptor_lists.length; i++) { + var interceptor_list = interceptor_lists[i]; + if (_.isArray(interceptor_list)) { + return interceptor_list; + } + } + return null; +} + +exports.resolveInterceptorProviders = resolveInterceptorProviders; + +exports.InterceptingCall = InterceptingCall; +exports.ListenerBuilder = ListenerBuilder; +exports.RequesterBuilder = RequesterBuilder; +exports.StatusBuilder = StatusBuilder; + +exports.InterceptorConfigurationError = InterceptorConfigurationError; + +exports.getInterceptingCall = getInterceptingCall; +exports.getLastListener = getLastListener; diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index b9c5ee3fc..d21760bf2 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -19,6 +19,8 @@ 'use strict'; var _ = require('lodash'); +var constants = require('./constants'); +var grpc = require('./grpc_extension'); /** * Wrap a function to pass null-like values through without calling it. If no @@ -75,6 +77,73 @@ exports.defaultGrpcOptions = { deprecatedArgumentOrder: false }; +/** + * Create an Error object from a status object + * @param {grpc~StatusObject} status The status object + * @return {Error} The resulting Error + */ +exports.createStatusError = function(status) { + let statusName = _.invert(constants.status)[status.code]; + let message = `${status.code} ${statusName}: ${status.details}`; + let error = new Error(message); + error.code = status.code; + error.metadata = status.metadata; + error.details = status.details; + return error; +}; + +/** + * Get a method's type from its definition + * @param {grpc~MethodDefinition} method_definition + * @return {number} + */ +exports.getMethodType = function(method_definition) { + if (method_definition.requestStream) { + if (method_definition.responseStream) { + return constants.methodTypes.BIDI_STREAMING; + } else { + return constants.methodTypes.CLIENT_STREAMING; + } + } else { + if (method_definition.responseStream) { + return constants.methodTypes.SERVER_STREAMING; + } else { + return constants.methodTypes.UNARY; + } + } +}; + +/** + * Get a call object built with the provided options. + * @param {grpc.Channel} channel + * @param {string} path + * @param {grpc.Client~CallOptions=} options Options object. + */ +exports.getCall = function(channel, path, options) { + var deadline; + var host; + var parent; + var propagate_flags; + var credentials; + if (options) { + deadline = options.deadline; + host = options.host; + parent = _.get(options, 'parent.call'); + propagate_flags = options.propagate_flags; + credentials = options.credentials; + } + if (deadline === undefined) { + deadline = Infinity; + } + var call = new grpc.Call(channel, path, deadline, host, + parent, propagate_flags); + if (credentials) { + call.setCredentials(credentials); + } + return call; +}; + + // JSDoc definitions that are used in multiple other modules /** @@ -166,6 +235,71 @@ exports.defaultGrpcOptions = { * function for repsonse data */ +/** + * @function MetadataListener + * @param {grpc.Metadata} metadata The response metadata. + * @param {function} next Passes metadata to the next interceptor. + */ + +/** + * @function MessageListener + * @param {jspb.Message} message The response message. + * @param {function} next Passes a message to the next interceptor. + */ + +/** + * @function StatusListener + * @param {grpc~StatusObject} status The response status. + * @param {function} next Passes a status to the next interceptor. + */ + +/** + * A set of interceptor functions triggered by responses + * @typedef {object} grpc~Listener + * @property {MetadataListener=} onReceiveMetadata A function triggered by + * response metadata. + * @property {MessageListener=} onReceiveMessage A function triggered by a + * response message. + * @property {StatusListener=} onReceiveStatus A function triggered by a + * response status. + */ + +/** + * @function MetadataRequester + * @param {grpc.Metadata} metadata The request metadata. + * @param {grpc~Listener} listener A listener wired to the previous layers + * in the interceptor stack. + * @param {function} next Passes metadata and a listener to the next + * interceptor. + */ + +/** + * @function MessageRequester + * @param {jspb.Message} message The request message. + * @param {function} next Passes a message to the next interceptor. + */ + +/** + * @function CloseRequester + * @param {function} next Calls the next interceptor. + */ + +/** + * @function CancelRequester + * @param {function} next Calls the next interceptor. + */ + +/** + * @typedef {object} grpc~Requester + * @param {MetadataRequester=} start A function triggered when the call begins. + * @param {MessageRequester=} sendMessage A function triggered by the request + * message. + * @param {CloseRequester=} halfClose A function triggered when the client + * closes the call. + * @param {CancelRequester=} cancel A function triggered when the call is + * cancelled. + */ + /** * An object that completely defines a service. * @typedef {Object.} grpc~ServiceDefinition @@ -175,3 +309,27 @@ exports.defaultGrpcOptions = { * An object that defines a package hierarchy with multiple services * @typedef {Object.} grpc~PackageDefinition */ + +/** + * A function for dynamically assigning an interceptor to a call. + * @function InterceptorProvider + * @param {grpc~MethodDefinition} method_definition The method to provide + * an interceptor for. + * @return {Interceptor|null} The interceptor to provide or nothing + */ + +/** + * A function which can modify call options and produce methods to intercept + * RPC operations. + * @function Interceptor + * @param {object} options The grpc call options + * @param {NextCall} nextCall + * @return {InterceptingCall} + */ + +/** + * A function which produces the next InterceptingCall. + * @function NextCall + * @param {object} options The grpc call options + * @return {InterceptingCall|null} + */ diff --git a/packages/grpc-native-core/src/constants.js b/packages/grpc-native-core/src/constants.js index b91d4214a..e9df9a318 100644 --- a/packages/grpc-native-core/src/constants.js +++ b/packages/grpc-native-core/src/constants.js @@ -235,3 +235,17 @@ exports.logVerbosity = { INFO: 1, ERROR: 2 }; + +/** + * Method types: the supported RPC types + * @memberof grpc + * @alias grpc.methodTypes + * @readonly + * @enum {number} + */ +exports.methodTypes = { + UNARY: 0, + CLIENT_STREAMING: 1, + SERVER_STREAMING: 2, + BIDI_STREAMING: 3 +}; diff --git a/packages/grpc-native-core/test/client_interceptors_test.js b/packages/grpc-native-core/test/client_interceptors_test.js new file mode 100644 index 000000000..c07811d9d --- /dev/null +++ b/packages/grpc-native-core/test/client_interceptors_test.js @@ -0,0 +1,1705 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var _ = require('lodash'); +var assert = require('assert'); +var grpc = require('..'); +var grpc_client = require('../src/client.js'); +var Metadata = require('../src/metadata'); + +var insecureCreds = grpc.credentials.createInsecure(); + +var echo_proto = grpc.load(__dirname + '/echo_service.proto'); +var echo_service = echo_proto.EchoService.service; + +var StatusBuilder = grpc_client.StatusBuilder; +var ListenerBuilder = grpc_client.ListenerBuilder; +var InterceptingCall = grpc_client.InterceptingCall; +var RequesterBuilder = grpc_client.RequesterBuilder; + +var CallRegistry = function(done, expectation, is_ordered, is_verbose) { + this.call_map = {}; + this.call_array = []; + this.done = done; + this.expectation = expectation; + this.expectation_is_array = _.isArray(this.expectation); + this.is_ordered = is_ordered; + this.is_verbose = is_verbose; + if (is_verbose) { + console.log('Expectation: ', expectation); + } +}; + +CallRegistry.prototype.addCall = function(call_name) { + if (this.expectation_is_array) { + this.call_array.push(call_name); + if (this.is_verbose) { + console.log(this.call_array); + } + } else { + if (!this.call_map[call_name]) { + this.call_map[call_name] = 0; + } + this.call_map[call_name]++; + if (this.is_verbose) { + console.log(this.call_map); + } + } + this.maybeCallDone(); +}; + +CallRegistry.prototype.maybeCallDone = function() { + if (this.expectation_is_array) { + if (this.is_ordered) { + if (this.expectation && _.isEqual(this.expectation, this.call_array)) { + this.done(); + } + } else { + var intersection = _.intersectionWith(this.expectation, this.call_array, + _.isEqual); + if (intersection.length === this.expectation.length) { + this.done(); + } + } + } else if (this.expectation && _.isEqual(this.expectation, this.call_map)) { + this.done(); + } +}; + +describe('Client interceptors', function() { + var echo_server; + var echo_port; + var client; + + function startServer() { + echo_server = new grpc.Server(); + echo_server.addService(echo_service, { + echo: function(call, callback) { + call.sendMetadata(call.metadata); + if (call.request.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + status.metadata = call.metadata; + callback(status, null); + return; + } + callback(null, call.request); + }, + echoClientStream: function(call, callback){ + call.sendMetadata(call.metadata); + var payload; + var err = null; + call.on('data', function(data) { + if (data.value === 'error') { + err = { + code: 2, + message: 'test status message' + }; + err.metadata = call.metadata; + return; + } + payload = data; + }); + call.on('end', function() { + callback(err, payload, call.metadata); + }); + }, + echoServerStream: function(call) { + call.sendMetadata(call.metadata); + if (call.request.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + status.metadata = call.metadata; + call.emit('error', status); + return; + } + call.write(call.request); + call.end(call.metadata); + }, + echoBidiStream: function(call) { + call.sendMetadata(call.metadata); + call.on('data', function(data) { + if (data.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + call.emit('error', status); + return; + } + call.write(data); + }); + call.on('end', function() { + call.end(call.metadata); + }); + } + }); + var server_credentials = grpc.ServerCredentials.createInsecure(); + echo_port = echo_server.bind('localhost:0', server_credentials); + echo_server.start(); + } + + function stopServer() { + echo_server.forceShutdown(); + } + + function resetClient() { + var EchoClient = grpc_client.makeClientConstructor(echo_service); + client = new EchoClient('localhost:' + echo_port, insecureCreds); + } + + before(function() { + startServer(); + }); + beforeEach(function() { + resetClient(); + }); + after(function() { + stopServer(); + }); + describe('pass calls through when no interceptors provided', function() { + it('with unary call', function(done) { + var expected_value = 'foo'; + var message = {value: expected_value}; + client.echo(message, function(err, response) { + assert.strictEqual(response.value, expected_value); + done(); + }); + assert(_.isEqual(grpc_client.getClientInterceptors(client), { + echo: [], + echoClientStream: [], + echoServerStream: [], + echoBidiStream: [] + })); + }); + }); + + describe('execute downstream interceptors when a new call is made outbound', + function() { + var registry; + var options; + before(function() { + var stored_listener; + var stored_metadata; + var interceptor_a = function (options, nextCall) { + options.call_number = 1; + registry.addCall('construct a ' + options.call_number); + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + registry.addCall('start a ' + options.call_number); + stored_listener = listener; + stored_metadata = metadata; + next(metadata, listener); + }, + sendMessage: function (message, next) { + registry.addCall('send a ' + options.call_number); + var options2 = _.clone(options); + options2.call_number = 2; + var second_call = nextCall(options2); + second_call.start(stored_metadata); + second_call.sendMessage(message); + second_call.halfClose(); + next(message); + }, + halfClose: function (next) { + registry.addCall('close a ' + options.call_number); + next(); + } + }); + }; + + var interceptor_b = function (options, nextCall) { + registry.addCall('construct b ' + options.call_number); + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + registry.addCall('start b ' + options.call_number); + next(metadata, listener); + }, + sendMessage: function (message, next) { + registry.addCall('send b ' + options.call_number); + next(message); + }, + halfClose: function (next) { + registry.addCall('close b ' + options.call_number); + next(); + } + }); + }; + options = { + interceptors: [interceptor_a, interceptor_b] + }; + }); + var expected_calls = [ + 'construct a 1', + 'construct b 1', + 'start a 1', + 'start b 1', + 'send a 1', + 'construct b 2', + 'start b 2', + 'send b 2', + 'close b 2', + 'send b 1', + 'close a 1', + 'close b 1', + 'response' + ]; + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + client.echo(message, options, function(err, response){ + if (!err) { + registry.addCall('response'); + } + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, false); + var message = {}; + message.value = 'foo'; + var stream = client.echoClientStream(options, function(err, response) { + if (!err) { + registry.addCall('response'); + } + }); + stream.write(message); + stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoServerStream(message, options); + stream.on('data', function(data) { + registry.addCall('response'); + }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry( done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoBidiStream(options); + stream.on('data', function(data) { + registry.addCall('response'); + }); + stream.write(message); + stream.end(); + }); + }); + + + describe('execute downstream interceptors when a new call is made inbound', + function() { + var registry; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + next(metadata, { + onReceiveMetadata: function () { }, + onReceiveMessage: function (message, next) { + registry.addCall('interceptor_a'); + var second_call = nextCall(options); + second_call.start(metadata, listener); + second_call.sendMessage(message); + second_call.halfClose(); + }, + onReceiveStatus: function () { } + }); + } + }); + }; + + var interceptor_b = function (options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + next(metadata, { + onReceiveMessage: function (message, next) { + registry.addCall('interceptor_b'); + next(message); + } + }); + } + }); + }; + + options = { + interceptors: [interceptor_a, interceptor_b] + }; + + }); + var expected_calls = ['interceptor_b', 'interceptor_a', + 'interceptor_b', 'response']; + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + client.echo(message, options, function(err) { + if (!err) { + registry.addCall('response'); + } + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoClientStream(options, function(err, response) { + if (!err) { + registry.addCall('response'); + } + }); + stream.write(message); + stream.end(); + }); + }); + + it('will delay operations and short circuit unary requests', function(done) { + var registry = new CallRegistry(done, ['foo_miss', 'foo_hit', 'bar_miss', + 'foo_hit_done', 'foo_miss_done', 'bar_miss_done']); + var cache = {}; + var _getCachedResponse = function(value) { + return cache[value]; + }; + var _store = function(key, value) { + cache[key] = value; + }; + + var interceptor = function(options, nextCall) { + var savedMetadata; + var startNext; + var storedListener; + var storedMessage; + var messageNext; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + savedMetadata = metadata; + storedListener = listener; + startNext = next; + }) + .withSendMessage(function(message, next) { + storedMessage = message; + messageNext = next; + }) + .withHalfClose(function(next) { + var cachedValue = _getCachedResponse(storedMessage.value); + if (cachedValue) { + var cachedMessage = {}; + cachedMessage.value = cachedValue; + registry.addCall(storedMessage.value + '_hit'); + storedListener.onReceiveMetadata(new Metadata()); + storedListener.onReceiveMessage(cachedMessage); + storedListener.onReceiveStatus( + (new StatusBuilder()).withCode(grpc.status.OK).build()); + } else { + registry.addCall(storedMessage.value + '_miss'); + var newListener = (new ListenerBuilder()).withOnReceiveMessage( + function(message, next) { + _store(storedMessage.value, message.value); + next(message); + }).build(); + startNext(savedMetadata, newListener); + messageNext(storedMessage); + next(); + } + }) + .withCancel(function(message, next) { + next(); + }).build(); + + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [interceptor] + }; + + var foo_message = {}; + foo_message.value = 'foo'; + client.echo(foo_message, options, function(err, response){ + assert.equal(response.value, 'foo'); + registry.addCall('foo_miss_done'); + client.echo(foo_message, options, function(err, response){ + assert.equal(response.value, 'foo'); + registry.addCall('foo_hit_done'); + }); + }); + + var bar_message = {}; + bar_message.value = 'bar'; + client.echo(bar_message, options, function(err, response) { + assert.equal(response.value, 'bar'); + registry.addCall('bar_miss_done'); + }); + }); + + it('can retry failed messages and handle eventual success', function(done) { + var registry = new CallRegistry(done, + ['retry_foo_1', 'retry_foo_2', 'retry_foo_3', 'foo_result', + 'retry_bar_1', 'bar_result']); + var maxRetries = 3; + var retry_interceptor = function(options, nextCall) { + var savedMetadata; + var savedSendMessage; + var savedReceiveMessage; + var savedMessageNext; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + savedMetadata = metadata; + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + savedReceiveMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function(status, next) { + var retries = 0; + var retry = function(message, metadata) { + retries++; + var newCall = nextCall(options); + var receivedMessage; + newCall.start(metadata, { + onReceiveMessage: function(message) { + receivedMessage = message; + }, + onReceiveStatus: function(status) { + registry.addCall('retry_' + savedMetadata.get('name') + + '_' + retries); + if (status.code !== grpc.status.OK) { + if (retries <= maxRetries) { + retry(message, metadata); + } else { + savedMessageNext(receivedMessage); + next(status); + } + } else { + registry.addCall('success_call'); + var new_status = (new StatusBuilder()) + .withCode(grpc.status.OK).build(); + savedMessageNext(receivedMessage); + next(new_status); + } + } + }); + newCall.sendMessage(message); + newCall.halfClose(); + }; + if (status.code !== grpc.status.OK) { + // Change the message we're sending only for test purposes + // so the server will respond without error + var newMessage = (savedMetadata.get('name')[0] === 'bar') ? + {value: 'bar'} : savedSendMessage; + retry(newMessage, savedMetadata); + } else { + savedMessageNext(savedReceiveMessage); + next(status); + } + } + ).build(); + next(metadata, new_listener); + }) + .withSendMessage(function(message, next) { + savedSendMessage = message; + next(message); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [retry_interceptor] + }; + + // Make a call which the server will return a non-OK status for + var foo_message = {value: 'error'}; + var foo_metadata = new Metadata(); + foo_metadata.set('name', 'foo'); + client.echo(foo_message, foo_metadata, options, function(err, response) { + assert.strictEqual(err.code, 2); + registry.addCall('foo_result'); + }); + + // Make a call which will fail the first time and succeed on the first + // retry + var bar_message = {value: 'error'}; + var bar_metadata = new Metadata(); + bar_metadata.set('name', 'bar'); + client.echo(bar_message, bar_metadata, options, function(err, response) { + assert.strictEqual(response.value, 'bar'); + registry.addCall('bar_result'); + }); + }); + + it('can retry and preserve interceptor order on success', function(done) { + var registry = new CallRegistry(done, + ['interceptor_c', 'retry_interceptor', 'fail_call', 'interceptor_c', + 'success_call', 'interceptor_a', 'result'], true); + var interceptor_a = function(options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + registry.addCall('interceptor_a'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var retry_interceptor = function(options, nextCall) { + var savedMetadata; + var savedMessage; + var savedMessageNext; + var sendMessageNext; + var originalMessage; + var startNext; + var originalListener; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + startNext = next; + savedMetadata = metadata; + originalListener = listener; + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + savedMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function(status, next) { + var retries = 0; + var maxRetries = 1; + var receivedMessage; + var retry = function(message, metadata) { + retries++; + var new_call = nextCall(options); + new_call.start(metadata, { + onReceiveMessage: function(message) { + receivedMessage = message; + }, + onReceiveStatus: function(status) { + if (status.code !== grpc.status.OK) { + if (retries <= maxRetries) { + retry(message, metadata); + } else { + savedMessageNext(receivedMessage); + next(status); + } + } else { + registry.addCall('success_call'); + var new_status = (new StatusBuilder()) + .withCode(grpc.status.OK).build(); + savedMessageNext(receivedMessage); + next(new_status); + } + } + }); + new_call.sendMessage(message); + new_call.halfClose(); + }; + registry.addCall('retry_interceptor'); + if (status.code !== grpc.status.OK) { + registry.addCall('fail_call'); + var newMessage = {value: 'foo'}; + retry(newMessage, savedMetadata); + } else { + savedMessageNext(savedMessage); + next(status); + } + }).build(); + next(metadata, new_listener); + }) + .withSendMessage(function(message, next) { + sendMessageNext = next; + originalMessage = message; + next(message); + }) + .build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var interceptor_c = function(options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + registry.addCall('interceptor_c'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [interceptor_a, retry_interceptor, interceptor_c] + }; + + var message = {value: 'error'}; + client.echo(message, options, function(err, response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('result'); + }); + }); + + describe('handle interceptor errors', function (doneOuter) { + var options; + before(function () { + var foo_interceptor = function (options, nextCall) { + var savedListener; + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + savedListener = listener; + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + savedListener.onReceiveMetadata(new Metadata()); + savedListener.onReceiveMessage({ value: 'failed' }); + var error_status = (new StatusBuilder()) + .withCode(16) + .withDetails('Error in foo interceptor') + .build(); + savedListener.onReceiveStatus(error_status); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + it('with unary call', function(done) { + var message = {}; + client.echo(message, options, function(err, response) { + assert.strictEqual(err.code, 16); + assert.strictEqual(err.message, + '16 UNAUTHENTICATED: Error in foo interceptor'); + done(); + doneOuter(); + }); + }); + }); + + describe('implement fallbacks for streaming RPCs', function() { + + var options; + before(function () { + var fallback_response = { value: 'fallback' }; + var savedMessage; + var savedMessageNext; + var interceptor = function (options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function (message, next) { + savedMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function (status, next) { + if (status.code !== grpc.status.OK) { + savedMessageNext(fallback_response); + next((new StatusBuilder()).withCode(grpc.status.OK)); + } else { + savedMessageNext(savedMessage); + next(status); + } + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + options = { + interceptors: [interceptor] + }; + }); + it('with client streaming call', function (done) { + var registry = new CallRegistry(done, ['foo_result', 'fallback_result']); + var stream = client.echoClientStream(options, function (err, response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('foo_result'); + }); + stream.write({ value: 'foo' }); + stream.end(); + + stream = client.echoClientStream(options, function(err, response) { + assert.strictEqual(response.value, 'fallback'); + registry.addCall('fallback_result'); + }); + stream.write({value: 'error'}); + stream.end(); + }); + }); + + describe('allows the call options to be modified for downstream interceptors', + function() { + var done; + var options; + var method_name; + var method_path_last; + before(function() { + var interceptor_a = function (options, nextCall) { + options.deadline = 10; + return new InterceptingCall(nextCall(options)); + }; + var interceptor_b = function (options, nextCall) { + assert.equal(options.method_definition.path, '/EchoService/' + + method_path_last); + assert.equal(options.deadline, 10); + done(); + return new InterceptingCall(nextCall(options)); + }; + + options = { + interceptors: [interceptor_a, interceptor_b], + deadline: 100 + }; + }); + + it('with unary call', function(cb) { + done = cb; + var metadata = new Metadata(); + var message = {}; + method_name = 'echo'; + method_path_last = 'Echo'; + + client.echo(message, metadata, options, function(){}); + }); + + it('with client streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + method_name = 'echoClientStream'; + method_path_last = 'EchoClientStream'; + + client.echoClientStream(metadata, options, function() {}); + }); + + it('with server streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + var message = {}; + method_name = 'echoServerStream'; + method_path_last = 'EchoServerStream'; + + client.echoServerStream(message, metadata, options); + }); + + it('with bidi streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + method_name = 'echoBidiStream'; + method_path_last = 'EchoBidiStream'; + + client.echoBidiStream(metadata, options); + }); + }); + + describe('pass accurate MethodDefinitions', function() { + var registry; + var initial_value = 'broken'; + var expected_value = 'working'; + var options; + before(function() { + var interceptor = function (options, nextCall) { + registry.addCall({ + path: options.method_definition.path, + requestStream: options.method_definition.requestStream, + responseStream: options.method_definition.responseStream + }); + var outbound = (new RequesterBuilder()) + .withSendMessage(function (message, next) { + message.value = expected_value; + next(message); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [interceptor] }; + }); + + it('with unary call', function(done) { + var unary_definition = { + path: '/EchoService/Echo', + requestStream: false, + responseStream: false + }; + registry = new CallRegistry(done, [ + unary_definition, + 'result_unary' + ]); + + var metadata = new Metadata(); + + var message = {value: initial_value}; + + client.echo(message, metadata, options, function(err, response){ + assert.equal(response.value, expected_value); + registry.addCall('result_unary'); + }); + + }); + it('with client streaming call', function(done) { + + var client_stream_definition = { + path: '/EchoService/EchoClientStream', + requestStream: true, + responseStream: false + }; + registry = new CallRegistry(done, [ + client_stream_definition, + 'result_client_stream' + ], false, true); + var metadata = new Metadata(); + var message = {value: initial_value}; + var client_stream = client.echoClientStream(metadata, options, + function(err, response) { + assert.strictEqual(response.value, expected_value); + registry.addCall('result_client_stream'); + }); + client_stream.write(message); + client_stream.end(); + + }); + it('with server streaming call', function(done) { + var server_stream_definition = { + path: '/EchoService/EchoServerStream', + responseStream: true, + requestStream: false, + }; + registry = new CallRegistry(done, [ + server_stream_definition, + 'result_server_stream' + ]); + + var metadata = new Metadata(); + var message = {value: initial_value}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function(data) { + assert.strictEqual(data.value, expected_value); + registry.addCall('result_server_stream'); + }); + + }); + it('with bidi streaming call', function(done) { + var bidi_stream_definition = { + path: '/EchoService/EchoBidiStream', + requestStream: true, + responseStream: true + }; + registry = new CallRegistry(done, [ + bidi_stream_definition, + 'result_bidi_stream' + ]); + + var metadata = new Metadata(); + var message = {value: initial_value}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(data) { + assert.strictEqual(data.value, expected_value); + registry.addCall('result_bidi_stream'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + it('uses interceptors passed to the client constructor', function(done) { + var registry = new CallRegistry(done, { + 'constructor_interceptor_a_echo': 1, + 'constructor_interceptor_b_echoServerStream': 1, + 'invocation_interceptor': 1, + 'result_unary': 1, + 'result_stream': 1, + 'result_invocation': 1 + }); + + var constructor_interceptor_a = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + registry.addCall('constructor_interceptor_a_' + + client.$method_names[options.method_definition.path]); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var constructor_interceptor_b = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + registry.addCall('constructor_interceptor_b_' + + client.$method_names[options.method_definition.path]); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var invocation_interceptor = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + registry.addCall('invocation_interceptor'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + + var interceptor_providers = [ + function(method_definition) { + if (!method_definition.requestStream && + !method_definition.responseStream) { + return constructor_interceptor_a; + } + }, + function(method_definition) { + if (!method_definition.requestStream && + method_definition.responseStream) { + return constructor_interceptor_b; + } + } + ]; + var constructor_options = { + interceptor_providers: interceptor_providers + }; + var IntClient = grpc_client.makeClientConstructor(echo_service); + var int_client = new IntClient('localhost:' + echo_port, insecureCreds, + constructor_options); + var message = {}; + int_client.echo(message, function() { + registry.addCall('result_unary'); + }); + var stream = int_client.echoServerStream(message); + stream.on('data', function() { + registry.addCall('result_stream'); + }); + + var options = { interceptors: [invocation_interceptor] }; + int_client.echo(message, options, function() { + registry.addCall('result_invocation'); + }); + + assert(_.isEqual(grpc_client.getClientInterceptors(int_client), { + echo: [constructor_interceptor_a], + echoClientStream: [], + echoServerStream: [constructor_interceptor_b], + echoBidiStream: [] + })); + }); + + it('will reject conflicting interceptor options at invocation', + function(done) { + try { + client.echo('message', { + interceptors: [], + interceptor_providers: [] + }, function () {}); + } catch (e) { + assert.equal(e.name, 'InterceptorConfigurationError'); + done(); + } + }); + + it('will resolve interceptor providers at invocation', function(done) { + var constructor_interceptor = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function() { + assert(false); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var invocation_interceptor = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function() { + done(); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var constructor_interceptor_providers = [ + function() { + return constructor_interceptor; + } + ]; + var invocation_interceptor_providers = [ + function() { + return invocation_interceptor; + } + ]; + var constructor_options = { + interceptor_providers: constructor_interceptor_providers + }; + var IntClient = grpc_client.makeClientConstructor(echo_service); + var int_client = new IntClient('localhost:' + echo_port, insecureCreds, + constructor_options); + var message = {}; + var options = { interceptor_providers: invocation_interceptor_providers }; + int_client.echo(message, options, function() {}); + }); + + describe('trigger a stack of interceptors in nested order', function() { + var registry; + var expected_calls = ['constructA', 'constructB', 'outboundA', 'outboundB', + 'inboundB', 'inboundA']; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + registry.addCall('constructA'); + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('outboundA'); + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + registry.addCall('inboundA'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + var interceptor_b = function (options, nextCall) { + registry.addCall('constructB'); + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('outboundB'); + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + registry.addCall('inboundB'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [interceptor_a, interceptor_b] }; + }); + var metadata = new Metadata(); + var message = {}; + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + client.echo(message, metadata, options, function(){}); + }); + + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var client_stream = client.echoClientStream(metadata, options, + function() {}); + client_stream.write(message); + client_stream.end(); + }); + + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var stream = client.echoServerStream(message, metadata, options); + stream.on('data', function() {}); + }); + + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(){}); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger interceptors horizontally', function() { + var expected_calls = [ + 'interceptor_a_start', + 'interceptor_b_start', + 'interceptor_a_send', + 'interceptor_b_send' + ]; + var registry; + var options; + var metadata = new Metadata(); + var message = {}; + + before(function() { + var interceptor_a = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('interceptor_a_start'); + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + registry.addCall('interceptor_a_send'); + next(message); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + var interceptor_b = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('interceptor_b_start'); + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + registry.addCall('interceptor_b_send'); + next(message); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [interceptor_a, interceptor_b] }; + }); + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + client.echo(message, metadata, options, function(){}); + }); + + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var client_stream = client.echoClientStream(metadata, options, + function() {}); + client_stream.write(message); + client_stream.end(); + }); + + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var stream = client.echoServerStream(message, metadata, options); + stream.on('data', function() {}); + }); + + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(){}); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when sending metadata', function() { + var registry; + + var message = {}; + var key_names = ['original', 'foo', 'bar']; + var keys = { + original: 'originalkey', + foo: 'fookey', + bar: 'barkey' + }; + var values = { + original: 'originalvalue', + foo: 'foovalue', + bar: 'barvalue' + }; + var expected_calls = ['foo', 'bar', 'response']; + var options; + before(function () { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + metadata.add(keys.foo, values.foo); + registry.addCall('foo'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var bar_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + metadata.add(keys.bar, values.bar); + registry.addCall('bar'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor, bar_interceptor] }; + }); + + it('with unary call', function (done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + + var unary_call = client.echo(message, metadata, options, function () {}); + unary_call.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + + var client_stream = client.echoClientStream(metadata, options, + function () { + }); + client_stream.write(message); + client_stream.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + client_stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + server_stream.on('data', function() { }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function(metadata) { + var has_expected_values = _.every(key_names, function(key_name) { + return _.isEqual(metadata.get(keys[key_name]),[values[key_name]]); + }); + assert(has_expected_values); + bidi_stream.end(); + registry.addCall('response'); + }); + bidi_stream.on('data', function() { }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when sending messages', function() { + var registry; + var originalValue = 'foo'; + var expectedValue = 'bar'; + var options; + var metadata = new Metadata(); + var expected_calls = ['messageIntercepted', 'response']; + + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withSendMessage(function (message, next) { + assert.strictEqual(message.value, originalValue); + registry.addCall('messageIntercepted'); + next({ value: expectedValue }); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + + client.echo(message, metadata, options, function (err, response) { + assert.strictEqual(response.value, expectedValue); + registry.addCall('response'); + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var client_stream = client.echoClientStream(metadata, options, + function (err, response) { + assert.strictEqual(response.value, expectedValue); + registry.addCall('response'); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + registry.addCall('response'); + }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(data) { + assert.strictEqual(data.value, expectedValue); + registry.addCall('response'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when client closes the call', function() { + var registry; + var expected_calls = [ + 'response', 'halfClose' + ]; + var message = {}; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withHalfClose(function (next) { + registry.addCall('halfClose'); + next(); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + it('with unary call', function (done) { + registry = new CallRegistry(done, expected_calls); + client.echo(message, options, function (err, response) { + if (!err) { + registry.addCall('response'); + } + }); + }); + it('with client streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var client_stream = client.echoClientStream(options, + function (err, response) { }); + client_stream.write(message, function (err) { + if (!err) { + registry.addCall('response'); + } + }); + client_stream.end(); + }); + it('with server streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var server_stream = client.echoServerStream(message, options); + server_stream.on('data', function (data) { + registry.addCall('response'); + }); + }); + it('with bidi streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var bidi_stream = client.echoBidiStream(options); + bidi_stream.on('data', function (data) { + registry.addCall('response'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when the stream is canceled', function() { + var done; + var message = {}; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withCancel(function (next) { + done(); + next(); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(cb) { + done = cb; + var stream = client.echo(message, options, function() {}); + stream.cancel(); + }); + + it('with client streaming call', function(cb) { + done = cb; + var stream = client.echoClientStream(options, function() {}); + stream.cancel(); + }); + it('with server streaming call', function(cb) { + done = cb; + var stream = client.echoServerStream(message, options); + stream.cancel(); + }); + it('with bidi streaming call', function(cb) { + done = cb; + var stream = client.echoBidiStream(options); + stream.cancel(); + }); + }); + + describe('trigger when receiving metadata', function() { + var message = {}; + var expectedKey = 'foo'; + var expectedValue = 'bar'; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveMetadata( + function (metadata, next) { + metadata.add(expectedKey, expectedValue); + next(metadata); + }).build(); + next(metadata, new_listener); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(done) { + var metadata = new Metadata(); + var unary_call = client.echo(message, metadata, options, function () {}); + unary_call.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + }); + it('with client streaming call', function(done) { + var metadata = new Metadata(); + var client_stream = client.echoClientStream(metadata, options, + function () {}); + client_stream.write(message); + client_stream.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + client_stream.end(); + }); + it('with server streaming call', function(done) { + var metadata = new Metadata(); + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + server_stream.on('data', function() { }); + }); + it('with bidi streaming call', function(done) { + var metadata = new Metadata(); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function(metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + bidi_stream.end(); + done(); + }); + bidi_stream.on('data', function() { }); + bidi_stream.write(message); + }); + }); + + describe('trigger when sending messages', function() { + var originalValue = 'foo'; + var expectedValue = 'bar'; + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + if (!message) { + next(message); + return; + } + assert.strictEqual(message.value, originalValue); + message.value = expectedValue; + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function (done) { + var message = { value: originalValue }; + client.echo(message, metadata, options, function (err, response) { + assert.strictEqual(response.value, expectedValue); + done(); + }); + }); + it('with client streaming call', function (done) { + var message = { value: originalValue }; + var client_stream = client.echoClientStream(metadata, options, + function (err, response) { + assert.strictEqual(response.value, expectedValue); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with server streaming call', function (done) { + var message = { value: originalValue }; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + done(); + }); + }); + it('with bidi streaming call', function (done) { + var message = { value: originalValue }; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when receiving status', function() { + var expectedStatus = 'foo'; + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveStatus( + function (status, next) { + assert.strictEqual(status.code, 2); + assert.strictEqual(status.details, 'test status message'); + var new_status = { + code: 1, + details: expectedStatus, + metadata: {} + }; + next(new_status); + }).build(); + next(metadata, new_listener); + }).build(); + return new grpc_client.InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + it('with unary call', function (done) { + var message = { value: 'error' }; + var unary_call = client.echo(message, metadata, options, function () { + }); + unary_call.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + }); + it('with client streaming call', function (done) { + var message = { value: 'error' }; + var client_stream = client.echoClientStream(metadata, options, + function () { + }); + client_stream.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + + it('with server streaming call', function(done) { + var message = {value: 'error'}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('error', function (err) { + }); + server_stream.on('data', function (data) { + }); + server_stream.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + }); + + it('with bidi streaming call', function(done) { + var message = {value: 'error'}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('error', function(err) {}); + bidi_stream.on('data', function(data) {}); + bidi_stream.on('status', function(status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + describe('delay streaming headers', function() { + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var startNext; + var startListener; + var startMetadata; + var methods = { + start: function (metadata, listener, next) { + startNext = next; + startListener = listener; + startMetadata = metadata; + }, + sendMessage: function (message, next) { + startMetadata.set('fromMessage', message.value); + startNext(startMetadata, startListener); + next(message); + } + }; + return new grpc_client.InterceptingCall(nextCall(options), methods); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with client streaming call', function (done) { + var message = { value: 'foo' }; + var client_stream = client.echoClientStream(metadata, options, + function () { }); + client_stream.on('metadata', function (metadata) { + assert.equal(metadata.get('fromMessage'), 'foo'); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with bidi streaming call', function (done) { + var message = { value: 'foo' }; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function (metadata) { + assert.equal(metadata.get('fromMessage'), 'foo'); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); +}); diff --git a/packages/grpc-native-core/test/echo_service.proto b/packages/grpc-native-core/test/echo_service.proto new file mode 100644 index 000000000..414b421ec --- /dev/null +++ b/packages/grpc-native-core/test/echo_service.proto @@ -0,0 +1,34 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +message EchoMessage { + string value = 1; + int32 value2 = 2; +} + +service EchoService { + rpc Echo (EchoMessage) returns (EchoMessage); + + rpc EchoClientStream (stream EchoMessage) returns (EchoMessage); + + rpc EchoServerStream (EchoMessage) returns (stream EchoMessage); + + rpc EchoBidiStream (stream EchoMessage) returns (stream EchoMessage); +} From 6bfb5de33718b014a269a5e410b395dbb3b412ff Mon Sep 17 00:00:00 2001 From: David Vroom Duke Date: Fri, 23 Feb 2018 11:02:45 -0800 Subject: [PATCH 0112/1899] Pass cancel and getPeer to underlying call --- .../src/client_interceptors.js | 126 +++++++++++------- packages/grpc-native-core/src/common.js | 8 ++ 2 files changed, 83 insertions(+), 51 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index cf7171fa4..ca9340dc1 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -707,59 +707,65 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { return function (options) { var call = common.getCall(channel, method_definition.path, options); var first_listener; - return new InterceptingCall(null, { - start: function (metadata, listener) { - var batch = { - [grpc.opType.SEND_INITIAL_METADATA]: - metadata._getCoreRepresentation(), - }; - first_listener = listener; - call.startBatch(batch, function () {}); - }, - sendMessage: function(message) { - var batch = { - [grpc.opType.SEND_MESSAGE]: serialize(message), - }; - call.startBatch(batch, function () {}); - }, - halfClose: function() { - var batch = { - [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true, - [grpc.opType.RECV_INITIAL_METADATA]: true, - [grpc.opType.RECV_MESSAGE]: true, - [grpc.opType.RECV_STATUS_ON_CLIENT]: true - }; - call.startBatch(batch, function (err, response) { - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - var status = response.status; - var deserialized; - if (status.code === constants.status.OK) { - if (err) { - // Got a batch error, but OK status. Something went wrong - callback(err); - return; - } else { - try { - deserialized = deserialize(response.read); - } catch (e) { - /* Change status to indicate bad server response. This - * will result in passing an error to the callback */ - status = { - code: constants.status.INTERNAL, - details: 'Failed to parse server response' - }; - } + var final_requester = {}; + final_requester.start = function (metadata, listener) { + var batch = { + [grpc.opType.SEND_INITIAL_METADATA]: + metadata._getCoreRepresentation(), + }; + first_listener = listener; + call.startBatch(batch, function () { }); + }; + final_requester.sendMessage = function (message) { + var batch = { + [grpc.opType.SEND_MESSAGE]: serialize(message), + }; + call.startBatch(batch, function () { }); + }; + final_requester.halfClose = function () { + var batch = { + [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true, + [grpc.opType.RECV_INITIAL_METADATA]: true, + [grpc.opType.RECV_MESSAGE]: true, + [grpc.opType.RECV_STATUS_ON_CLIENT]: true + }; + call.startBatch(batch, function (err, response) { + response.status.metadata = Metadata._fromCoreRepresentation( + response.status.metadata); + var status = response.status; + var deserialized; + if (status.code === constants.status.OK) { + if (err) { + // Got a batch error, but OK status. Something went wrong + callback(err); + return; + } else { + try { + deserialized = deserialize(response.read); + } catch (e) { + /* Change status to indicate bad server response. This + * will result in passing an error to the callback */ + status = { + code: constants.status.INTERNAL, + details: 'Failed to parse server response' + }; } } - response.metadata = - Metadata._fromCoreRepresentation(response.metadata); - first_listener.onReceiveMetadata(response.metadata); - first_listener.onReceiveMessage(deserialized); - first_listener.onReceiveStatus(status); - }); - } - }); + } + response.metadata = + Metadata._fromCoreRepresentation(response.metadata); + first_listener.onReceiveMetadata(response.metadata); + first_listener.onReceiveMessage(deserialized); + first_listener.onReceiveStatus(status); + }); + }; + final_requester.cancel = function () { + call.cancel(); + }; + final_requester.getPeer = function () { + return call.getPeer(); + }; + return new InterceptingCall(null, final_requester); }; } @@ -865,6 +871,12 @@ function _getClientStreamingInterceptor(method_definition, channel, emitter, }; call.startBatch(batch, function () { }); }; + final_requester.cancel = function () { + call.cancel(); + }; + final_requester.getPeer = function() { + return call.getPeer(); + }; return new InterceptingCall(null, final_requester); }; } @@ -944,6 +956,12 @@ function _getServerStreamingInterceptor(method_definition, channel, emitter) { call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, first_listener, deserialize)); }; + final_requester.cancel = function() { + call.cancel(); + }; + final_requester.getPeer = function() { + return call.getPeer(); + }; return new InterceptingCall(null, final_requester); }; } @@ -1041,6 +1059,12 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, first_listener, deserialize)); }; + final_requester.cancel = function() { + call.cancel(); + }; + final_requester.getPeer = function() { + return call.getPeer(); + }; return new InterceptingCall(null, final_requester); }; } diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index d21760bf2..5e53ebe80 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -289,6 +289,12 @@ exports.getCall = function(channel, path, options) { * @param {function} next Calls the next interceptor. */ +/** + * @function GetPeerRequester + * @param {function} next Calls the next interceptor. + * @return {string} + */ + /** * @typedef {object} grpc~Requester * @param {MetadataRequester=} start A function triggered when the call begins. @@ -298,6 +304,8 @@ exports.getCall = function(channel, path, options) { * closes the call. * @param {CancelRequester=} cancel A function triggered when the call is * cancelled. + * @param {GetPeerRequester=} getPeer A function triggered when the endpoint is + * requested. */ /** From 4c502ed6aed6be910e7ecf0383821b2a88ffd5bc Mon Sep 17 00:00:00 2001 From: David Vroom Duke Date: Sun, 25 Feb 2018 23:39:13 -0800 Subject: [PATCH 0113/1899] Enforce order of operations for synchronous requests --- .../src/client_interceptors.js | 132 +++++++++++++++--- .../test/client_interceptors_test.js | 90 ++++++++++++ 2 files changed, 202 insertions(+), 20 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index ca9340dc1..e5de547c1 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -652,16 +652,22 @@ EndListener.prototype.onReceiveMessage = function(){}; EndListener.prototype.onReceiveStatus = function(){}; EndListener.prototype.recvMessageWithContext = function(){}; +var OP_DEPENDENCIES = { + [grpc.opType.SEND_MESSAGE]: [grpc.opType.SEND_INITIAL_METADATA], + [grpc.opType.SEND_CLOSE_FROM_CLIENT]: [grpc.opType.SEND_MESSAGE], + [grpc.opType.RECV_MESSAGE]: [grpc.opType.SEND_INITIAL_METADATA] +}; + /** * Produces a callback triggered by streaming response messages. * @private * @param {EventEmitter} emitter * @param {grpc.internal~Call} call - * @param {grpc~Listener} listener + * @param {function} get_listener Returns a grpc~Listener. * @param {grpc~deserialize} deserialize * @return {Function} */ -function _getStreamReadCallback(emitter, call, listener, deserialize) { +function _getStreamReadCallback(emitter, call, get_listener, deserialize) { return function (err, response) { if (err) { // Something has gone wrong. Stop reading and wait for status @@ -684,6 +690,7 @@ function _getStreamReadCallback(emitter, call, listener, deserialize) { emitter._readsDone(); return; } + var listener = get_listener(); var context = { call: call, listener: listener @@ -692,6 +699,66 @@ function _getStreamReadCallback(emitter, call, listener, deserialize) { }; } +/** + * Tests whether a batch can be started. + * @private + * @param {number[]} batch_ops The operations in the batch we are checking. + * @param {number[]} completed_ops Previously completed operations. + * @return {boolean} + */ +function _areBatchRequirementsMet(batch_ops, completed_ops) { + var dependencies = _.flatMap(batch_ops, function(op) { + return OP_DEPENDENCIES[op] || []; + }); + var dependencies_met = _.intersection(dependencies, + batch_ops.concat(completed_ops)); + return _.isEqual(dependencies_met.sort(), dependencies.sort()); +} + +/** + * Enforces the order of operations for synchronous requests. If a batch's + * operations cannot be started because required operations have not started + * yet, the batch is deferred until requirements are met. + * @private + * @param {grpc.Client~Call} call + * @param {object} batch + * @param {object} batch_state + * @param {number[]} [batch_state.completed_ops] The ops already sent. + * @param {object} [batch_state.deferred_batches] Batches to be sent after + * their dependencies are fulfilled. + * @param {function} callback + * @return {object} + */ +function _startBatchIfReady(call, batch, batch_state, callback) { + var completed_ops = batch_state.completed_ops; + var deferred_batches = batch_state.deferred_batches; + var batch_ops = _.map(_.keys(batch), Number); + if (_areBatchRequirementsMet(batch_ops, completed_ops)) { + // Dependencies are met, start the batch and any deferred batches whose + // dependencies are met as a result. + call.startBatch(batch, callback); + completed_ops = _.union(completed_ops, batch_ops); + deferred_batches = _.flatMap(deferred_batches, function(deferred_batch) { + var deferred_batch_ops = _.map(_.keys(deferred_batch), Number); + if (_areBatchRequirementsMet(deferred_batch_ops, completed_ops)) { + call.startBatch(deferred_batch.batch, deferred_batch.callback); + return []; + } + return [deferred_batch]; + }); + } else { + // Dependencies are not met, defer the batch + deferred_batches = deferred_batches.concat({ + batch: batch, + callback: callback + }); + } + return { + completed_ops: completed_ops, + deferred_batches: deferred_batches + }; +} + /** * Produces an interceptor which will start gRPC batches for unary calls. * @private @@ -708,19 +775,25 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { var call = common.getCall(channel, method_definition.path, options); var first_listener; var final_requester = {}; + var batch_state = { + completed_ops: [], + deferred_batches: [] + }; final_requester.start = function (metadata, listener) { var batch = { [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), }; first_listener = listener; - call.startBatch(batch, function () { }); + batch_state = _startBatchIfReady(call, batch, batch_state, + function() {}); }; final_requester.sendMessage = function (message) { var batch = { [grpc.opType.SEND_MESSAGE]: serialize(message), }; - call.startBatch(batch, function () { }); + batch_state = _startBatchIfReady(call, batch, batch_state, + function() {}); }; final_requester.halfClose = function () { var batch = { @@ -729,7 +802,7 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { [grpc.opType.RECV_MESSAGE]: true, [grpc.opType.RECV_STATUS_ON_CLIENT]: true }; - call.startBatch(batch, function (err, response) { + var callback = function (err, response) { response.status.metadata = Metadata._fromCoreRepresentation( response.status.metadata); var status = response.status; @@ -757,7 +830,8 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { first_listener.onReceiveMetadata(response.metadata); first_listener.onReceiveMessage(deserialized); first_listener.onReceiveStatus(status); - }); + }; + batch_state = _startBatchIfReady(call, batch, batch_state, callback); }; final_requester.cancel = function () { call.cancel(); @@ -895,17 +969,24 @@ function _getServerStreamingInterceptor(method_definition, channel, emitter) { method_definition.responseDeserialize); var serialize = method_definition.requestSerialize; return function (options) { - var first_listener; + var batch_state = { + completed_ops: [], + deferred_batches: [] + }; var call = common.getCall(channel, method_definition.path, options); var final_requester = {}; + var first_listener; + var get_listener = function() { + return first_listener; + }; final_requester.start = function(metadata, listener) { first_listener = listener; metadata = metadata.clone(); var metadata_batch = { [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), - [grpc.opType.RECV_INITIAL_METADATA]: true, + [grpc.opType.RECV_INITIAL_METADATA]: true }; - call.startBatch(metadata_batch, function(err, response) { + var callback = function(err, response) { if (err) { // The call has stopped for some reason. A non-OK status will arrive // in the other batch. @@ -913,7 +994,9 @@ function _getServerStreamingInterceptor(method_definition, channel, emitter) { } first_listener.onReceiveMetadata( Metadata._fromCoreRepresentation(response.metadata)); - }); + }; + batch_state = _startBatchIfReady(call, metadata_batch, batch_state, + callback); var status_batch = { [grpc.opType.RECV_STATUS_ON_CLIENT]: true }; @@ -935,26 +1018,28 @@ function _getServerStreamingInterceptor(method_definition, channel, emitter) { var send_batch = { [grpc.opType.SEND_MESSAGE]: message }; - call.startBatch(send_batch, function(err, response) { + var callback = function(err, response) { if (err) { // The call has stopped for some reason. A non-OK status will arrive // in the other batch. return; } - }); + }; + batch_state = _startBatchIfReady(call, send_batch, batch_state, callback); }; final_requester.halfClose = function() { var batch = { [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true }; - call.startBatch(batch, function() {}); + batch_state = _startBatchIfReady(call, batch, batch_state, function() {}); }; final_requester.recvMessageWithContext = function(context) { var recv_batch = { [grpc.opType.RECV_MESSAGE]: true }; - call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, - first_listener, deserialize)); + var callback = _getStreamReadCallback(emitter, call, + get_listener, deserialize); + batch_state = _startBatchIfReady(call, recv_batch, batch_state, callback); }; final_requester.cancel = function() { call.cancel(); @@ -981,6 +1066,9 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { method_definition.responseDeserialize); return function (options) { var first_listener; + var get_listener = function() { + return first_listener; + }; var call = common.getCall(channel, method_definition.path, options); var final_requester = {}; final_requester.start = function (metadata, listener) { @@ -1057,7 +1145,7 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { [grpc.opType.RECV_MESSAGE]: true }; call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, - first_listener, deserialize)); + get_listener, deserialize)); }; final_requester.cancel = function() { call.cancel(); @@ -1144,11 +1232,13 @@ function _getServerStreamingListener(method_definition, emitter) { onReceiveMessage: function(message, next, context) { if (emitter.push(message) && message !== null) { var call = context.call; - var listener = context.listener; + var get_listener = function() { + return context.listener; + }; var read_batch = {}; read_batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(read_batch, _getStreamReadCallback(emitter, call, - listener, deserialize)); + get_listener, deserialize)); } else { emitter.reading = false; } @@ -1176,11 +1266,13 @@ function _getBidiStreamingListener(method_definition, emitter) { onReceiveMessage: function(message, next, context) { if (emitter.push(message) && message !== null) { var call = context.call; - var listener = context.listener; + var get_listener = function() { + return context.listener; + }; var read_batch = {}; read_batch[grpc.opType.RECV_MESSAGE] = true; call.startBatch(read_batch, _getStreamReadCallback(emitter, call, - listener, deserialize)); + get_listener, deserialize)); } else { emitter.reading = false; } diff --git a/packages/grpc-native-core/test/client_interceptors_test.js b/packages/grpc-native-core/test/client_interceptors_test.js index c07811d9d..b14ec1569 100644 --- a/packages/grpc-native-core/test/client_interceptors_test.js +++ b/packages/grpc-native-core/test/client_interceptors_test.js @@ -1702,4 +1702,94 @@ describe('Client interceptors', function() { bidi_stream.end(); }); }); + + describe('order of operations enforced for async interceptors', function() { + it('with unary call', function(done) { + var expected_calls = [ + 'close_b', + 'message_b', + 'start_b', + 'done' + ]; + var registry = new CallRegistry(done, expected_calls, true); + var message = {value: 'foo'}; + var interceptor_a = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + setTimeout(function() { next(metadata, listener); }, 50); + }, + sendMessage: function(message, next) { + setTimeout(function () { next(message); }, 10); + } + }); + }; + var interceptor_b = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + registry.addCall('start_b'); + next(metadata, listener); + }, + sendMessage: function(message, next) { + registry.addCall('message_b'); + next(message); + }, + halfClose: function(next) { + registry.addCall('close_b'); + next(); + } + }); + }; + var options = { + interceptors: [interceptor_a, interceptor_b] + }; + client.echo(message, options, function(err, response) { + assert.strictEqual(err, null); + registry.addCall('done'); + }); + }); + it('with serverStreaming call', function(done) { + var expected_calls = [ + 'close_b', + 'message_b', + 'start_b', + 'done' + ]; + var registry = new CallRegistry(done, expected_calls, true); + var message = {value: 'foo'}; + var interceptor_a = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + setTimeout(function() { next(metadata, listener); }, 50); + }, + sendMessage: function(message, next) { + setTimeout(function () { next(message); }, 10); + } + }); + }; + var interceptor_b = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + registry.addCall('start_b'); + next(metadata, listener); + }, + sendMessage: function(message, next) { + registry.addCall('message_b'); + next(message); + }, + halfClose: function(next) { + registry.addCall('close_b'); + next(); + } + }); + }; + var options = { + interceptors: [interceptor_a, interceptor_b] + }; + var stream = client.echoServerStream(message, options); + stream.on('data', function(response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('done'); + }); + }); + }); }); From 40c445d03a4eb7464493c966002f97120d7404c2 Mon Sep 17 00:00:00 2001 From: David Vroom Duke Date: Wed, 28 Feb 2018 09:44:48 -0800 Subject: [PATCH 0114/1899] Move getCall definition --- .../src/client_interceptors.js | 38 +++++++++++++++++-- packages/grpc-native-core/src/common.js | 32 ---------------- 2 files changed, 34 insertions(+), 36 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index e5de547c1..01023a52b 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -652,6 +652,36 @@ EndListener.prototype.onReceiveMessage = function(){}; EndListener.prototype.onReceiveStatus = function(){}; EndListener.prototype.recvMessageWithContext = function(){}; +/** + * Get a call object built with the provided options. + * @param {grpc.Channel} channel + * @param {string} path + * @param {grpc.Client~CallOptions=} options Options object. + */ +function getCall(channel, path, options) { + var deadline; + var host; + var parent; + var propagate_flags; + var credentials; + if (options) { + deadline = options.deadline; + host = options.host; + parent = _.get(options, 'parent.call'); + propagate_flags = options.propagate_flags; + credentials = options.credentials; + } + if (deadline === undefined) { + deadline = Infinity; + } + var call = new grpc.Call(channel, path, deadline, host, + parent, propagate_flags); + if (credentials) { + call.setCredentials(credentials); + } + return call; +} + var OP_DEPENDENCIES = { [grpc.opType.SEND_MESSAGE]: [grpc.opType.SEND_INITIAL_METADATA], [grpc.opType.SEND_CLOSE_FROM_CLIENT]: [grpc.opType.SEND_MESSAGE], @@ -772,7 +802,7 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { var serialize = method_definition.requestSerialize; var deserialize = method_definition.responseDeserialize; return function (options) { - var call = common.getCall(channel, method_definition.path, options); + var call = getCall(channel, method_definition.path, options); var first_listener; var final_requester = {}; var batch_state = { @@ -859,7 +889,7 @@ function _getClientStreamingInterceptor(method_definition, channel, emitter, var deserialize = method_definition.responseDeserialize; return function (options) { var first_listener; - var call = common.getCall(channel, method_definition.path, options); + var call = getCall(channel, method_definition.path, options); var final_requester = {}; final_requester.start = function (metadata, listener) { var metadata_batch = { @@ -973,7 +1003,7 @@ function _getServerStreamingInterceptor(method_definition, channel, emitter) { completed_ops: [], deferred_batches: [] }; - var call = common.getCall(channel, method_definition.path, options); + var call = getCall(channel, method_definition.path, options); var final_requester = {}; var first_listener; var get_listener = function() { @@ -1069,7 +1099,7 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { var get_listener = function() { return first_listener; }; - var call = common.getCall(channel, method_definition.path, options); + var call = getCall(channel, method_definition.path, options); var final_requester = {}; final_requester.start = function (metadata, listener) { var metadata_batch = { diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 5e53ebe80..0c35296a8 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -20,7 +20,6 @@ var _ = require('lodash'); var constants = require('./constants'); -var grpc = require('./grpc_extension'); /** * Wrap a function to pass null-like values through without calling it. If no @@ -113,37 +112,6 @@ exports.getMethodType = function(method_definition) { } }; -/** - * Get a call object built with the provided options. - * @param {grpc.Channel} channel - * @param {string} path - * @param {grpc.Client~CallOptions=} options Options object. - */ -exports.getCall = function(channel, path, options) { - var deadline; - var host; - var parent; - var propagate_flags; - var credentials; - if (options) { - deadline = options.deadline; - host = options.host; - parent = _.get(options, 'parent.call'); - propagate_flags = options.propagate_flags; - credentials = options.credentials; - } - if (deadline === undefined) { - deadline = Infinity; - } - var call = new grpc.Call(channel, path, deadline, host, - parent, propagate_flags); - if (credentials) { - call.setCredentials(credentials); - } - return call; -}; - - // JSDoc definitions that are used in multiple other modules /** From 2c09a6ab54d1576922360100457b0c6c1b896e09 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 28 Feb 2018 12:13:15 -0800 Subject: [PATCH 0115/1899] grpc-protobufjs: add d.ts to package --- packages/grpc-protobufjs/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 13eb7c012..a6fecc1bf 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/protobufjs", - "version": "1.0.0", + "version": "0.1.0", "description": "", "main": "build/src/index.js", "scripts": { @@ -26,6 +26,7 @@ "url": "https://github.com/grpc/grpc-node/issues" }, "files": [ + "build/src/*.d.ts", "build/src/*.js" ], "dependencies": { From 6e569b76f1f3545fa7b55d3de57c735155af89f1 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 28 Feb 2018 13:34:22 -0800 Subject: [PATCH 0116/1899] Revert 2c625fe^..b192adf Revert "use client's user agent; small changes in test gulpfile; add TODO" This reverts commit 2c625feb9fd12c4c01602483f199e50b5eac5a90. Revert "use merged gRPC object in api tests" This reverts commit 9d9404615ec870dfbfe15055148070ccd700dc5f. Revert "add packageJson to any-grpc" This reverts commit 6a6b4eb56c9c10432d2664d6db12fc1348fc6e58. Revert "change grpc refs in math api test" This reverts commit 689d4d0c619b69fca0fb7af734f2741c8c4bc788. Revert "test: add requiring fixtures to specify implementation to test" This reverts commit b192adf2a12653744520aea625c7c87fbb493d4c. --- test/any_grpc.js | 39 -------- test/api/async_test.js | 2 +- test/api/credentials_api_test.js | 165 ------------------------------- test/api/credentials_test.js | 2 +- test/api/file_load_test.js | 40 -------- test/api/math/math_grpc_pb.js | 2 +- test/api/math/math_server.js | 2 +- test/api/math_client_test.js | 2 +- test/api/metadata_test.js | 2 +- test/api/surface_test.js | 4 +- test/fixtures/js_js.js | 2 - test/fixtures/js_native.js | 2 - test/fixtures/native_js.js | 2 - test/fixtures/native_native.js | 2 - test/gulpfile.js | 25 +---- test/interop/interop_client.js | 3 +- test/interop/interop_server.js | 3 +- 17 files changed, 13 insertions(+), 286 deletions(-) delete mode 100644 test/any_grpc.js delete mode 100644 test/api/credentials_api_test.js delete mode 100644 test/api/file_load_test.js delete mode 100644 test/fixtures/js_js.js delete mode 100644 test/fixtures/js_native.js delete mode 100644 test/fixtures/native_js.js delete mode 100644 test/fixtures/native_native.js diff --git a/test/any_grpc.js b/test/any_grpc.js deleted file mode 100644 index d6d008c29..000000000 --- a/test/any_grpc.js +++ /dev/null @@ -1,39 +0,0 @@ -// TODO: Instead of attempting to expose both implementations of gRPC in -// a single object, the tests should be re-written in a way that makes it clear -// that two separate implementations are being tested against one another. - -const _ = require('lodash'); - -function getImplementation(globalField) { - if (global[globalField] !== 'js' && global[globalField] !== 'native') { - throw new Error([ - `Invalid value for global.${globalField}: ${global.globalField}.`, - 'If running from the command line, please --require a fixture first.' - ].join(' ')); - } - const impl = global[globalField]; - return { - surface: require(`../packages/grpc-${impl}`), - pjson: require(`../packages/grpc-${impl}/package.json`), - core: require(`../packages/grpc-${impl}-core`), - corePjson: require(`../packages/grpc-${impl}-core/package.json`) - }; -} - -const clientImpl = getImplementation('_client_implementation'); -const serverImpl = getImplementation('_server_implementation'); - -// We export a "merged" gRPC API by merging client and server specified -// APIs together. Any function that is unspecific to client/server defaults -// to client-side implementation. -// This object also has a test-only field from which details about the -// modules may be read. -module.exports = Object.assign({ - '$implementationInfo': { - client: clientImpl, - server: serverImpl - } -}, clientImpl.surface, _.pick(serverImpl.surface, [ - 'Server', - 'ServerCredentials' -])); diff --git a/test/api/async_test.js b/test/api/async_test.js index 86cd62e21..e899da56b 100644 --- a/test/api/async_test.js +++ b/test/api/async_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('../any_grpc'); +var grpc = require('grpc'); var math = grpc.load( __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math; diff --git a/test/api/credentials_api_test.js b/test/api/credentials_api_test.js deleted file mode 100644 index e79fca07b..000000000 --- a/test/api/credentials_api_test.js +++ /dev/null @@ -1,165 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var fs = require('fs'); -var path = require('path'); - -var grpc = require('../any_grpc'); - -var key_data, pem_data, ca_data; - -before(function() { - var key_path = path.join(__dirname, '../data/server1.key'); - var pem_path = path.join(__dirname, '../data/server1.pem'); - var ca_path = path.join(__dirname, '../data/ca.pem'); - key_data = fs.readFileSync(key_path); - pem_data = fs.readFileSync(pem_path); - ca_data = fs.readFileSync(ca_path); -}); - -describe('channel credentials', function() { - describe('#createSsl', function() { - it('works with no arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(); - }); - assert.notEqual(creds, null); - }); - it('works with just one Buffer argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data); - }); - assert.notEqual(creds, null); - }); - it('works with 3 Buffer arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('works if the first argument is null', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(null, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl('test'); - }, TypeError); - }); - it('fails if the second argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, 'test', pem_data); - }, TypeError); - }); - it('fails if the third argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data, 'test'); - }, TypeError); - }); - it('fails if only 1 of the last 2 arguments is provided', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data); - }); - assert.throws(function() { - grpc.credentials.createSsl(null, null, pem_data); - }); - }); - }); -}); - -describe('server credentials', function() { - describe('#createSsl', function() { - it('accepts a buffer and array as the first 2 arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, []); - }); - assert.notEqual(creds, null); - }); - it('accepts a boolean as the third argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, [], true); - }); - assert.notEqual(creds, null); - }); - it('accepts an object with two buffers in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('accepts multiple objects in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}, - {private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('fails if the second argument is not an Array', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl('test', []); - }, TypeError); - }); - it('fails if the third argument is a non-boolean value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, [], 'test'); - }, TypeError); - }); - it('fails if the array elements are not objects', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the object does not have a Buffer private_key', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: 'test', - cert_chain: pem_data}]); - }, TypeError); - }); - it('fails if the object does not have a Buffer cert_chain', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: 'test'}]); - }, TypeError); - }); - }); -}); \ No newline at end of file diff --git a/test/api/credentials_test.js b/test/api/credentials_test.js index f9bdefaf3..2f101134e 100644 --- a/test/api/credentials_test.js +++ b/test/api/credentials_test.js @@ -22,7 +22,7 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); -var grpc = require('../any_grpc'); +var grpc = require('grpc'); /** * This is used for testing functions with multiple asynchronous calls that diff --git a/test/api/file_load_test.js b/test/api/file_load_test.js deleted file mode 100644 index c24a11002..000000000 --- a/test/api/file_load_test.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var grpc = require('../any_grpc'); - -describe('File loader', function() { - it('Should load a proto file by default', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto'); - }); - }); - it('Should load a proto file with the proto format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto', 'proto'); - }); - }); - it('Should load a json file with the json format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.json', 'json'); - }); - }); -}); diff --git a/test/api/math/math_grpc_pb.js b/test/api/math/math_grpc_pb.js index 68001847c..afd08a34a 100644 --- a/test/api/math/math_grpc_pb.js +++ b/test/api/math/math_grpc_pb.js @@ -16,7 +16,7 @@ // limitations under the License. // 'use strict'; -var grpc = require('../../any_grpc.js'); +var grpc = require('grpc'); var math_math_pb = require('../math/math_pb.js'); function serialize_DivArgs(arg) { diff --git a/test/api/math/math_server.js b/test/api/math/math_server.js index 70ad2dc56..05e30f722 100644 --- a/test/api/math/math_server.js +++ b/test/api/math/math_server.js @@ -18,7 +18,7 @@ 'use strict'; -var grpc = require('../../any_grpc.js'); +var grpc = require('grpc'); var grpcMath = require('./math_grpc_pb'); var math = require('./math_pb'); diff --git a/test/api/math_client_test.js b/test/api/math_client_test.js index f4ba09518..09265abf6 100644 --- a/test/api/math_client_test.js +++ b/test/api/math_client_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('../any_grpc'); +var grpc = require('grpc'); var math = require('./math/math_pb'); var MathClient = require('./math/math_grpc_pb').MathClient; diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js index 7825383dd..5e24f7ac8 100644 --- a/test/api/metadata_test.js +++ b/test/api/metadata_test.js @@ -18,7 +18,7 @@ 'use strict'; -var Metadata = require('../any_grpc').Metadata; +var Metadata = require('grpc').Metadata; var assert = require('assert'); diff --git a/test/api/surface_test.js b/test/api/surface_test.js index 928024350..2a1bf5bf4 100644 --- a/test/api/surface_test.js +++ b/test/api/surface_test.js @@ -21,7 +21,7 @@ var assert = require('assert'); var _ = require('lodash'); -var grpc = require('../any_grpc'); +var grpc = require('grpc'); var MathClient = grpc.load( __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math.Math; @@ -485,7 +485,7 @@ describe('Echo metadata', function() { call.end(); }); it('shows the correct user-agent string', function(done) { - var version = require('../any_grpc')['$implementationInfo'].client.corePjson.version; + var version = require('grpc/package.json').version; var call = client.unary({}, metadata, function(err, data) { assert.ifError(err); }); call.on('metadata', function(metadata) { diff --git a/test/fixtures/js_js.js b/test/fixtures/js_js.js deleted file mode 100644 index e0ca3c588..000000000 --- a/test/fixtures/js_js.js +++ /dev/null @@ -1,2 +0,0 @@ -global._server_implementation = 'native'; -global._client_implementation = 'js'; \ No newline at end of file diff --git a/test/fixtures/js_native.js b/test/fixtures/js_native.js deleted file mode 100644 index 5088df96d..000000000 --- a/test/fixtures/js_native.js +++ /dev/null @@ -1,2 +0,0 @@ -global._server_implementation = 'js'; -global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_js.js b/test/fixtures/native_js.js deleted file mode 100644 index 5088df96d..000000000 --- a/test/fixtures/native_js.js +++ /dev/null @@ -1,2 +0,0 @@ -global._server_implementation = 'js'; -global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_native.js b/test/fixtures/native_native.js deleted file mode 100644 index 5b005e485..000000000 --- a/test/fixtures/native_native.js +++ /dev/null @@ -1,2 +0,0 @@ -global._server_implementation = 'native'; -global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/gulpfile.js b/test/gulpfile.js index 70e057962..25e5e7b6b 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -36,28 +36,5 @@ gulp.task('install', 'Install test dependencies', () => { gulp.task('clean.all', 'Delete all files created by tasks', () => {}); gulp.task('test', 'Run API-level tests', () => { - // run mocha tests matching a glob with a pre-required fixture, - // returning the associated gulp stream - const apiTestGlob = `${apiTestDir}/*.js`; - const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { - const fixture = `${server}_${client}`; - console.log(`Running ${apiTestGlob} with ${server} server + ${client} client`); - gulp.src(apiTestGlob) - .pipe(mocha({ - reporter: 'mocha-jenkins-reporter', - require: `${testDir}/fixtures/${fixture}.js` - })) - .resume() // put the stream in flowing mode - .on('end', resolve) - .on('error', reject); - }); - const runTestsArgPairs = [ - ['native', 'native'], - // ['native', 'js'], - // ['js', 'native'], - // ['js', 'js'] - ]; - return runTestsArgPairs.reduce((previousPromise, argPair) => { - return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); - }, Promise.resolve()); + return gulp.src(`${apiTestDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); }); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 83890bca8..66a46a442 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -20,7 +20,8 @@ var fs = require('fs'); var path = require('path'); -var grpc = require('../any_grpc')['$implementationInfo'].client.surface; +// TODO(murgatroid99): use multiple grpc implementations +var grpc = require('grpc'); var testProto = grpc.load({ root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index fe1222dd3..65bb088d3 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -22,7 +22,8 @@ var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); -var grpc = require('../any_grpc')['$implementationInfo'].server.surface; +// TODO(murgatroid99): use multiple grpc implementations +var grpc = require('grpc'); var testProto = grpc.load({ root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; From 98341acc7eba62bd151a7b3c06ac1b2d697d6db2 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 28 Feb 2018 14:30:26 -0800 Subject: [PATCH 0117/1899] grpc-native: move api tests verbatim to grpc-native-core --- .../interop/async_delay_queue.js | 0 .../interop/interop_client.js | 0 .../interop/interop_server.js | 0 .../grpc-native-core/test}/async_test.js | 0 .../test}/credentials_test.js | 0 .../grpc-native-core/test}/data/README | 0 .../grpc-native-core/test}/data/ca.pem | 0 .../grpc-native-core/test}/data/server1.key | 0 .../grpc-native-core/test}/data/server1.pem | 0 .../test}/interop_sanity_test.js | 0 .../test}/math/math_grpc_pb.js | 0 .../grpc-native-core/test}/math/math_pb.js | 0 .../test}/math/math_server.js | 0 .../test}/math_client_test.js | 0 .../grpc-native-core/test}/metadata_test.js | 0 .../grpc-native-core/test}/numbers.txt | 0 .../grpc-native-core/test}/surface_test.js | 0 .../grpc-native-core/test}/test_service.json | 0 .../grpc-native-core/test}/test_service.proto | 0 test/api/echo_service.proto | 24 ---------- test/api/test_messages.proto | 45 ------------------- 21 files changed, 69 deletions(-) rename {test => packages/grpc-native-core}/interop/async_delay_queue.js (100%) rename {test => packages/grpc-native-core}/interop/interop_client.js (100%) rename {test => packages/grpc-native-core}/interop/interop_server.js (100%) rename {test/api => packages/grpc-native-core/test}/async_test.js (100%) rename {test/api => packages/grpc-native-core/test}/credentials_test.js (100%) rename {test => packages/grpc-native-core/test}/data/README (100%) rename {test => packages/grpc-native-core/test}/data/ca.pem (100%) rename {test => packages/grpc-native-core/test}/data/server1.key (100%) rename {test => packages/grpc-native-core/test}/data/server1.pem (100%) rename {test/api => packages/grpc-native-core/test}/interop_sanity_test.js (100%) rename {test/api => packages/grpc-native-core/test}/math/math_grpc_pb.js (100%) rename {test/api => packages/grpc-native-core/test}/math/math_pb.js (100%) rename {test/api => packages/grpc-native-core/test}/math/math_server.js (100%) rename {test/api => packages/grpc-native-core/test}/math_client_test.js (100%) rename {test/api => packages/grpc-native-core/test}/metadata_test.js (100%) rename {test/api => packages/grpc-native-core/test}/numbers.txt (100%) rename {test/api => packages/grpc-native-core/test}/surface_test.js (100%) rename {test/api => packages/grpc-native-core/test}/test_service.json (100%) rename {test/api => packages/grpc-native-core/test}/test_service.proto (100%) delete mode 100644 test/api/echo_service.proto delete mode 100644 test/api/test_messages.proto diff --git a/test/interop/async_delay_queue.js b/packages/grpc-native-core/interop/async_delay_queue.js similarity index 100% rename from test/interop/async_delay_queue.js rename to packages/grpc-native-core/interop/async_delay_queue.js diff --git a/test/interop/interop_client.js b/packages/grpc-native-core/interop/interop_client.js similarity index 100% rename from test/interop/interop_client.js rename to packages/grpc-native-core/interop/interop_client.js diff --git a/test/interop/interop_server.js b/packages/grpc-native-core/interop/interop_server.js similarity index 100% rename from test/interop/interop_server.js rename to packages/grpc-native-core/interop/interop_server.js diff --git a/test/api/async_test.js b/packages/grpc-native-core/test/async_test.js similarity index 100% rename from test/api/async_test.js rename to packages/grpc-native-core/test/async_test.js diff --git a/test/api/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js similarity index 100% rename from test/api/credentials_test.js rename to packages/grpc-native-core/test/credentials_test.js diff --git a/test/data/README b/packages/grpc-native-core/test/data/README similarity index 100% rename from test/data/README rename to packages/grpc-native-core/test/data/README diff --git a/test/data/ca.pem b/packages/grpc-native-core/test/data/ca.pem similarity index 100% rename from test/data/ca.pem rename to packages/grpc-native-core/test/data/ca.pem diff --git a/test/data/server1.key b/packages/grpc-native-core/test/data/server1.key similarity index 100% rename from test/data/server1.key rename to packages/grpc-native-core/test/data/server1.key diff --git a/test/data/server1.pem b/packages/grpc-native-core/test/data/server1.pem similarity index 100% rename from test/data/server1.pem rename to packages/grpc-native-core/test/data/server1.pem diff --git a/test/api/interop_sanity_test.js b/packages/grpc-native-core/test/interop_sanity_test.js similarity index 100% rename from test/api/interop_sanity_test.js rename to packages/grpc-native-core/test/interop_sanity_test.js diff --git a/test/api/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js similarity index 100% rename from test/api/math/math_grpc_pb.js rename to packages/grpc-native-core/test/math/math_grpc_pb.js diff --git a/test/api/math/math_pb.js b/packages/grpc-native-core/test/math/math_pb.js similarity index 100% rename from test/api/math/math_pb.js rename to packages/grpc-native-core/test/math/math_pb.js diff --git a/test/api/math/math_server.js b/packages/grpc-native-core/test/math/math_server.js similarity index 100% rename from test/api/math/math_server.js rename to packages/grpc-native-core/test/math/math_server.js diff --git a/test/api/math_client_test.js b/packages/grpc-native-core/test/math_client_test.js similarity index 100% rename from test/api/math_client_test.js rename to packages/grpc-native-core/test/math_client_test.js diff --git a/test/api/metadata_test.js b/packages/grpc-native-core/test/metadata_test.js similarity index 100% rename from test/api/metadata_test.js rename to packages/grpc-native-core/test/metadata_test.js diff --git a/test/api/numbers.txt b/packages/grpc-native-core/test/numbers.txt similarity index 100% rename from test/api/numbers.txt rename to packages/grpc-native-core/test/numbers.txt diff --git a/test/api/surface_test.js b/packages/grpc-native-core/test/surface_test.js similarity index 100% rename from test/api/surface_test.js rename to packages/grpc-native-core/test/surface_test.js diff --git a/test/api/test_service.json b/packages/grpc-native-core/test/test_service.json similarity index 100% rename from test/api/test_service.json rename to packages/grpc-native-core/test/test_service.json diff --git a/test/api/test_service.proto b/packages/grpc-native-core/test/test_service.proto similarity index 100% rename from test/api/test_service.proto rename to packages/grpc-native-core/test/test_service.proto diff --git a/test/api/echo_service.proto b/test/api/echo_service.proto deleted file mode 100644 index 0b27c8b16..000000000 --- a/test/api/echo_service.proto +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -message EchoMessage { - string value = 1; - int32 value2 = 2; -} - -service EchoService { - rpc Echo (EchoMessage) returns (EchoMessage); -} diff --git a/test/api/test_messages.proto b/test/api/test_messages.proto deleted file mode 100644 index da1ef5658..000000000 --- a/test/api/test_messages.proto +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -message LongValues { - int64 int_64 = 1; - uint64 uint_64 = 2; - sint64 sint_64 = 3; - fixed64 fixed_64 = 4; - sfixed64 sfixed_64 = 5; -} - -message SequenceValues { - bytes bytes_field = 1; - repeated int32 repeated_field = 2; -} - -message OneOfValues { - oneof oneof_choice { - int32 int_choice = 1; - string string_choice = 2; - } -} - -enum TestEnum { - ZERO = 0; - ONE = 1; - TWO = 2; -} - -message EnumValues { - TestEnum enum_value = 1; -} From 41305f595cc965fef614488a2c76b43acb9d6f99 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 28 Feb 2018 14:27:31 -0800 Subject: [PATCH 0118/1899] grpc-native: fix test paths --- packages/grpc-native-core/interop/interop_client.js | 6 +++--- packages/grpc-native-core/interop/interop_server.js | 8 ++++---- packages/grpc-native-core/test/async_test.js | 4 ++-- packages/grpc-native-core/test/credentials_test.js | 8 ++++---- packages/grpc-native-core/test/math/math_grpc_pb.js | 4 ++-- packages/grpc-native-core/test/math/math_server.js | 2 +- packages/grpc-native-core/test/math_client_test.js | 2 +- packages/grpc-native-core/test/metadata_test.js | 2 +- packages/grpc-native-core/test/server_test.js | 4 ++-- packages/grpc-native-core/test/surface_test.js | 6 +++--- 10 files changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/grpc-native-core/interop/interop_client.js b/packages/grpc-native-core/interop/interop_client.js index 66a46a442..8d1c1dd3c 100644 --- a/packages/grpc-native-core/interop/interop_client.js +++ b/packages/grpc-native-core/interop/interop_client.js @@ -21,9 +21,9 @@ var fs = require('fs'); var path = require('path'); // TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); +var grpc = require('..'); var testProto = grpc.load({ - root: __dirname + '/../../packages/grpc-native-core/deps/grpc', + root: __dirname + '/../deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var GoogleAuth = require('google-auth-library'); @@ -566,7 +566,7 @@ function runTest(address, host_override, test_case, tls, test_ca, done, extra) { if (tls) { var ca_path; if (test_ca) { - ca_path = path.join(__dirname, '../data/ca.pem'); + ca_path = path.join(__dirname, '../test/data/ca.pem'); var ca_data = fs.readFileSync(ca_path); creds = grpc.credentials.createSsl(ca_data); } else { diff --git a/packages/grpc-native-core/interop/interop_server.js b/packages/grpc-native-core/interop/interop_server.js index 65bb088d3..6e38aeb9f 100644 --- a/packages/grpc-native-core/interop/interop_server.js +++ b/packages/grpc-native-core/interop/interop_server.js @@ -23,9 +23,9 @@ var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); // TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); +var grpc = require('..'); var testProto = grpc.load({ - root: __dirname + '/../../packages/grpc-native-core/deps/grpc', + root: __dirname + '/../deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; @@ -202,8 +202,8 @@ function getServer(port, tls) { var options = {}; var server_creds; if (tls) { - var key_path = path.join(__dirname, '../data/server1.key'); - var pem_path = path.join(__dirname, '../data/server1.pem'); + var key_path = path.join(__dirname, '../test/data/server1.key'); + var pem_path = path.join(__dirname, '../test/data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); diff --git a/packages/grpc-native-core/test/async_test.js b/packages/grpc-native-core/test/async_test.js index e899da56b..786e50bfd 100644 --- a/packages/grpc-native-core/test/async_test.js +++ b/packages/grpc-native-core/test/async_test.js @@ -20,9 +20,9 @@ var assert = require('assert'); -var grpc = require('grpc'); +var grpc = require('..'); var math = grpc.load( - __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math; + __dirname + '/../deps/grpc/src/proto/math/math.proto').math; /** diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index 2f101134e..58dddb508 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -22,7 +22,7 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); -var grpc = require('grpc'); +var grpc = require('..'); /** * This is used for testing functions with multiple asynchronous calls that @@ -67,9 +67,9 @@ var fakeFailingGoogleCredentials = { var key_data, pem_data, ca_data; before(function() { - var key_path = path.join(__dirname, '../data/server1.key'); - var pem_path = path.join(__dirname, '../data/server1.pem'); - var ca_path = path.join(__dirname, '../data/ca.pem'); + var key_path = path.join(__dirname, '/data/server1.key'); + var pem_path = path.join(__dirname, '/data/server1.pem'); + var ca_path = path.join(__dirname, '/data/ca.pem'); key_data = fs.readFileSync(key_path); pem_data = fs.readFileSync(pem_path); ca_data = fs.readFileSync(ca_path); diff --git a/packages/grpc-native-core/test/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js index afd08a34a..82105c0f5 100644 --- a/packages/grpc-native-core/test/math/math_grpc_pb.js +++ b/packages/grpc-native-core/test/math/math_grpc_pb.js @@ -16,8 +16,8 @@ // limitations under the License. // 'use strict'; -var grpc = require('grpc'); -var math_math_pb = require('../math/math_pb.js'); +var grpc = require('../..'); +var math_math_pb = require('./math_pb.js'); function serialize_DivArgs(arg) { if (!(arg instanceof math_math_pb.DivArgs)) { diff --git a/packages/grpc-native-core/test/math/math_server.js b/packages/grpc-native-core/test/math/math_server.js index 05e30f722..4291ae18b 100644 --- a/packages/grpc-native-core/test/math/math_server.js +++ b/packages/grpc-native-core/test/math/math_server.js @@ -18,7 +18,7 @@ 'use strict'; -var grpc = require('grpc'); +var grpc = require('../..'); var grpcMath = require('./math_grpc_pb'); var math = require('./math_pb'); diff --git a/packages/grpc-native-core/test/math_client_test.js b/packages/grpc-native-core/test/math_client_test.js index 09265abf6..11deda34f 100644 --- a/packages/grpc-native-core/test/math_client_test.js +++ b/packages/grpc-native-core/test/math_client_test.js @@ -20,7 +20,7 @@ var assert = require('assert'); -var grpc = require('grpc'); +var grpc = require('..'); var math = require('./math/math_pb'); var MathClient = require('./math/math_grpc_pb').MathClient; diff --git a/packages/grpc-native-core/test/metadata_test.js b/packages/grpc-native-core/test/metadata_test.js index 5e24f7ac8..6063b31fd 100644 --- a/packages/grpc-native-core/test/metadata_test.js +++ b/packages/grpc-native-core/test/metadata_test.js @@ -18,7 +18,7 @@ 'use strict'; -var Metadata = require('grpc').Metadata; +var Metadata = require('..').Metadata; var assert = require('assert'); diff --git a/packages/grpc-native-core/test/server_test.js b/packages/grpc-native-core/test/server_test.js index c1b941948..5351c138a 100644 --- a/packages/grpc-native-core/test/server_test.js +++ b/packages/grpc-native-core/test/server_test.js @@ -72,8 +72,8 @@ describe('server', function() { }); it('should bind to an unused port with ssl credentials', function() { var port; - var key_path = path.join(__dirname, '../../../test/data/server1.key'); - var pem_path = path.join(__dirname, '../../../test/data/server1.pem'); + var key_path = path.join(__dirname, '/data/server1.key'); + var pem_path = path.join(__dirname, '/data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); var creds = grpc.ServerCredentials.createSsl(null, diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 2a1bf5bf4..361797382 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -21,10 +21,10 @@ var assert = require('assert'); var _ = require('lodash'); -var grpc = require('grpc'); +var grpc = require('..'); var MathClient = grpc.load( - __dirname + '/../../packages/grpc-native-core/deps/grpc/src/proto/math/math.proto').math.Math; + __dirname + '/../deps/grpc/src/proto/math/math.proto').math.Math; var mathServiceAttrs = MathClient.service; /** @@ -485,7 +485,7 @@ describe('Echo metadata', function() { call.end(); }); it('shows the correct user-agent string', function(done) { - var version = require('grpc/package.json').version; + var version = require('../package.json').version; var call = client.unary({}, metadata, function(err, data) { assert.ifError(err); }); call.on('metadata', function(metadata) { From a35fad015d49ffff2ac39cf3a3cdc3067c66226f Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 28 Feb 2018 14:31:57 -0800 Subject: [PATCH 0119/1899] build: update build files --- gulpfile.ts | 9 +++--- packages/grpc-native-core/package.json | 10 ++++++- test/gulpfile.js | 40 -------------------------- test/package.json | 26 ----------------- 4 files changed, 13 insertions(+), 72 deletions(-) delete mode 100644 test/gulpfile.js delete mode 100644 test/package.json diff --git a/gulpfile.ts b/gulpfile.ts index 969fb894c..46ddfa933 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -55,16 +55,15 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { ['./packages/grpc-native-core/gulpfile', 'native.core'], ['./packages/grpc-surface/gulpfile', 'surface'], ['./packages/grpc-protobufjs/gulpfile', 'protobuf'], - ['./test/gulpfile', 'internal.test'], ].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); + ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'protobuf.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); + ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'protobuf.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); @@ -96,10 +95,10 @@ gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clea gulp.task('clean.all', 'Delete all files created by tasks', ['js.core.clean.all', 'native.core.clean.all', 'health-check.clean.all', - 'internal.test.clean.all', 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); + 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', - ['native.core.test', 'internal.test.test', 'health-check.test']); + ['native.core.test', 'health-check.test']); gulp.task('native.test', 'Run tests of native code', (callback) => { runSequence('build', 'native.test.only', callback); diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 44b029d66..4aa346355 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -34,8 +34,16 @@ "protobufjs": "^5.0.0" }, "devDependencies": { + "async": "^2.0.1", + "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", - "istanbul": "^0.4.4" + "express": "^4.14.0", + "google-auth-library": "^0.9.2", + "google-protobuf": "^3.0.0", + "istanbul": "^0.4.4", + "lodash": "^4.17.4", + "minimist": "^1.1.0", + "poisson-process": "^0.2.1" }, "engines": { "node": ">=4" diff --git a/test/gulpfile.js b/test/gulpfile.js deleted file mode 100644 index 25e5e7b6b..000000000 --- a/test/gulpfile.js +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -const _gulp = require('gulp'); -const help = require('gulp-help'); -const mocha = require('gulp-mocha'); -const execa = require('execa'); -const path = require('path'); -const del = require('del'); -const linkSync = require('../util').linkSync; - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const testDir = __dirname; -const apiTestDir = path.resolve(testDir, 'api'); - -gulp.task('install', 'Install test dependencies', () => { - return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); -}); - -gulp.task('clean.all', 'Delete all files created by tasks', () => {}); - -gulp.task('test', 'Run API-level tests', () => { - return gulp.src(`${apiTestDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); -}); diff --git a/test/package.json b/test/package.json deleted file mode 100644 index e3aa0eebd..000000000 --- a/test/package.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "grpc-node-test", - "version": "0.1.0", - "description": "Dummy package for the grpc-node repository tests", - "private": true, - "keywords": [], - "author": { - "name": "Google Inc." - }, - "license": "Apache-2.0", - "contributors": [ - { - "name": "Google Inc." - } - ], - "dependencies": { - "async": "^2.0.1", - "body-parser": "^1.15.2", - "express": "^4.14.0", - "google-auth-library": "^0.9.2", - "google-protobuf": "^3.0.0", - "lodash": "^4.17.4", - "minimist": "^1.1.0", - "poisson-process": "^0.2.1" - } -} From b88260045ae975d1d968c32cf313f72d3ba35517 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 1 Mar 2018 09:53:23 -0800 Subject: [PATCH 0120/1899] move interop tests back --- .../grpc-native-core/test/interop_sanity_test.js | 4 ++-- test/data/README | 1 + test/data/ca.pem | 15 +++++++++++++++ test/data/server1.key | 16 ++++++++++++++++ test/data/server1.pem | 16 ++++++++++++++++ .../interop/async_delay_queue.js | 0 .../interop/interop_client.js | 7 +++---- .../interop/interop_server.js | 9 ++++----- 8 files changed, 57 insertions(+), 11 deletions(-) create mode 100644 test/data/README create mode 100644 test/data/ca.pem create mode 100644 test/data/server1.key create mode 100644 test/data/server1.pem rename {packages/grpc-native-core => test}/interop/async_delay_queue.js (100%) rename {packages/grpc-native-core => test}/interop/interop_client.js (99%) rename {packages/grpc-native-core => test}/interop/interop_server.js (96%) diff --git a/packages/grpc-native-core/test/interop_sanity_test.js b/packages/grpc-native-core/test/interop_sanity_test.js index b3f65a034..bc4c539a3 100644 --- a/packages/grpc-native-core/test/interop_sanity_test.js +++ b/packages/grpc-native-core/test/interop_sanity_test.js @@ -18,8 +18,8 @@ 'use strict'; -var interop_server = require('../interop/interop_server.js'); -var interop_client = require('../interop/interop_client.js'); +var interop_server = require('../../../test/interop/interop_server.js'); +var interop_client = require('../../../test/interop/interop_client.js'); var server; diff --git a/test/data/README b/test/data/README new file mode 100644 index 000000000..888d95b90 --- /dev/null +++ b/test/data/README @@ -0,0 +1 @@ +CONFIRMEDTESTKEY diff --git a/test/data/ca.pem b/test/data/ca.pem new file mode 100644 index 000000000..6c8511a73 --- /dev/null +++ b/test/data/ca.pem @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla +Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 +YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT +BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 ++L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu +g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd +Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau +sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m +oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG +Dfcog5wrJytaQ6UA0wE= +-----END CERTIFICATE----- diff --git a/test/data/server1.key b/test/data/server1.key new file mode 100644 index 000000000..143a5b876 --- /dev/null +++ b/test/data/server1.key @@ -0,0 +1,16 @@ +-----BEGIN PRIVATE KEY----- +MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD +M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf +3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY +AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm +V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY +tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p +dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q +K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR +81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff +DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd +aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 +ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 +XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe +F98XJ7tIFfJq +-----END PRIVATE KEY----- diff --git a/test/data/server1.pem b/test/data/server1.pem new file mode 100644 index 000000000..f3d43fcc5 --- /dev/null +++ b/test/data/server1.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET +MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ +dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx +MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV +BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 +ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco +LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg +zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd +9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw +CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy +em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G +CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 +hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh +y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 +-----END CERTIFICATE----- diff --git a/packages/grpc-native-core/interop/async_delay_queue.js b/test/interop/async_delay_queue.js similarity index 100% rename from packages/grpc-native-core/interop/async_delay_queue.js rename to test/interop/async_delay_queue.js diff --git a/packages/grpc-native-core/interop/interop_client.js b/test/interop/interop_client.js similarity index 99% rename from packages/grpc-native-core/interop/interop_client.js rename to test/interop/interop_client.js index 8d1c1dd3c..11a535d5b 100644 --- a/packages/grpc-native-core/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -20,10 +20,9 @@ var fs = require('fs'); var path = require('path'); -// TODO(murgatroid99): use multiple grpc implementations -var grpc = require('..'); +var grpc = require('../../packages/grpc-native-core'); var testProto = grpc.load({ - root: __dirname + '/../deps/grpc', + root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var GoogleAuth = require('google-auth-library'); @@ -566,7 +565,7 @@ function runTest(address, host_override, test_case, tls, test_ca, done, extra) { if (tls) { var ca_path; if (test_ca) { - ca_path = path.join(__dirname, '../test/data/ca.pem'); + ca_path = path.join(__dirname, '../data/ca.pem'); var ca_data = fs.readFileSync(ca_path); creds = grpc.credentials.createSsl(ca_data); } else { diff --git a/packages/grpc-native-core/interop/interop_server.js b/test/interop/interop_server.js similarity index 96% rename from packages/grpc-native-core/interop/interop_server.js rename to test/interop/interop_server.js index 6e38aeb9f..6682bbab3 100644 --- a/packages/grpc-native-core/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -22,10 +22,9 @@ var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); -// TODO(murgatroid99): use multiple grpc implementations -var grpc = require('..'); +var grpc = require('../../packages/grpc-native-core'); var testProto = grpc.load({ - root: __dirname + '/../deps/grpc', + root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; @@ -202,8 +201,8 @@ function getServer(port, tls) { var options = {}; var server_creds; if (tls) { - var key_path = path.join(__dirname, '../test/data/server1.key'); - var pem_path = path.join(__dirname, '../test/data/server1.pem'); + var key_path = path.join(__dirname, '../data/server1.key'); + var pem_path = path.join(__dirname, '../data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); From d3d91e1c3692320034b606e8542d2b1f751aa086 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 1 Mar 2018 11:34:17 -0800 Subject: [PATCH 0121/1899] recover fixtures Revert "build: update build files" This reverts commit a35fad015d49ffff2ac39cf3a3cdc3067c66226f. --- gulpfile.ts | 9 +++-- .../test/interop_sanity_test.js | 1 + test/any_grpc.js | 39 +++++++++++++++++++ test/fixtures/js_js.js | 2 + test/fixtures/js_native.js | 2 + test/fixtures/native_js.js | 2 + test/fixtures/native_native.js | 2 + test/gulpfile.js | 38 ++++++++++++++++++ test/interop/interop_client.js | 2 +- test/interop/interop_server.js | 2 +- test/package.json | 20 ++++++++++ 11 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 test/any_grpc.js create mode 100644 test/fixtures/js_js.js create mode 100644 test/fixtures/js_native.js create mode 100644 test/fixtures/native_js.js create mode 100644 test/fixtures/native_native.js create mode 100644 test/gulpfile.js create mode 100644 test/package.json diff --git a/gulpfile.ts b/gulpfile.ts index 46ddfa933..969fb894c 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -55,15 +55,16 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { ['./packages/grpc-native-core/gulpfile', 'native.core'], ['./packages/grpc-surface/gulpfile', 'surface'], ['./packages/grpc-protobufjs/gulpfile', 'protobuf'], + ['./test/gulpfile', 'internal.test'], ].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'protobuf.install']); + ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'protobuf.install']); + ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); @@ -95,10 +96,10 @@ gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clea gulp.task('clean.all', 'Delete all files created by tasks', ['js.core.clean.all', 'native.core.clean.all', 'health-check.clean.all', - 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); + 'internal.test.clean.all', 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', - ['native.core.test', 'health-check.test']); + ['native.core.test', 'internal.test.test', 'health-check.test']); gulp.task('native.test', 'Run tests of native code', (callback) => { runSequence('build', 'native.test.only', callback); diff --git a/packages/grpc-native-core/test/interop_sanity_test.js b/packages/grpc-native-core/test/interop_sanity_test.js index bc4c539a3..0c4130739 100644 --- a/packages/grpc-native-core/test/interop_sanity_test.js +++ b/packages/grpc-native-core/test/interop_sanity_test.js @@ -18,6 +18,7 @@ 'use strict'; +require('../../../test/fixtures/native_native.js'); var interop_server = require('../../../test/interop/interop_server.js'); var interop_client = require('../../../test/interop/interop_client.js'); diff --git a/test/any_grpc.js b/test/any_grpc.js new file mode 100644 index 000000000..d6d008c29 --- /dev/null +++ b/test/any_grpc.js @@ -0,0 +1,39 @@ +// TODO: Instead of attempting to expose both implementations of gRPC in +// a single object, the tests should be re-written in a way that makes it clear +// that two separate implementations are being tested against one another. + +const _ = require('lodash'); + +function getImplementation(globalField) { + if (global[globalField] !== 'js' && global[globalField] !== 'native') { + throw new Error([ + `Invalid value for global.${globalField}: ${global.globalField}.`, + 'If running from the command line, please --require a fixture first.' + ].join(' ')); + } + const impl = global[globalField]; + return { + surface: require(`../packages/grpc-${impl}`), + pjson: require(`../packages/grpc-${impl}/package.json`), + core: require(`../packages/grpc-${impl}-core`), + corePjson: require(`../packages/grpc-${impl}-core/package.json`) + }; +} + +const clientImpl = getImplementation('_client_implementation'); +const serverImpl = getImplementation('_server_implementation'); + +// We export a "merged" gRPC API by merging client and server specified +// APIs together. Any function that is unspecific to client/server defaults +// to client-side implementation. +// This object also has a test-only field from which details about the +// modules may be read. +module.exports = Object.assign({ + '$implementationInfo': { + client: clientImpl, + server: serverImpl + } +}, clientImpl.surface, _.pick(serverImpl.surface, [ + 'Server', + 'ServerCredentials' +])); diff --git a/test/fixtures/js_js.js b/test/fixtures/js_js.js new file mode 100644 index 000000000..e0ca3c588 --- /dev/null +++ b/test/fixtures/js_js.js @@ -0,0 +1,2 @@ +global._server_implementation = 'native'; +global._client_implementation = 'js'; \ No newline at end of file diff --git a/test/fixtures/js_native.js b/test/fixtures/js_native.js new file mode 100644 index 000000000..5088df96d --- /dev/null +++ b/test/fixtures/js_native.js @@ -0,0 +1,2 @@ +global._server_implementation = 'js'; +global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_js.js b/test/fixtures/native_js.js new file mode 100644 index 000000000..5088df96d --- /dev/null +++ b/test/fixtures/native_js.js @@ -0,0 +1,2 @@ +global._server_implementation = 'js'; +global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_native.js b/test/fixtures/native_native.js new file mode 100644 index 000000000..5b005e485 --- /dev/null +++ b/test/fixtures/native_native.js @@ -0,0 +1,2 @@ +global._server_implementation = 'native'; +global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/gulpfile.js b/test/gulpfile.js new file mode 100644 index 000000000..41c4b33c5 --- /dev/null +++ b/test/gulpfile.js @@ -0,0 +1,38 @@ +/* + * Copyright 2017 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const _gulp = require('gulp'); +const help = require('gulp-help'); +const mocha = require('gulp-mocha'); +const execa = require('execa'); +const path = require('path'); +const del = require('del'); +const linkSync = require('../util').linkSync; + +// gulp-help monkeypatches tasks to have an additional description parameter +const gulp = help(_gulp); + +const testDir = __dirname; +const apiTestDir = path.resolve(testDir, 'api'); + +gulp.task('install', 'Install test dependencies', () => { + return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); +}); + +gulp.task('clean.all', 'Delete all files created by tasks', () => {}); + +gulp.task('test', 'Run API-level tests', () => {}); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 11a535d5b..83890bca8 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -20,7 +20,7 @@ var fs = require('fs'); var path = require('path'); -var grpc = require('../../packages/grpc-native-core'); +var grpc = require('../any_grpc')['$implementationInfo'].client.surface; var testProto = grpc.load({ root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index 6682bbab3..fe1222dd3 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -22,7 +22,7 @@ var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); -var grpc = require('../../packages/grpc-native-core'); +var grpc = require('../any_grpc')['$implementationInfo'].server.surface; var testProto = grpc.load({ root: __dirname + '/../../packages/grpc-native-core/deps/grpc', file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; diff --git a/test/package.json b/test/package.json new file mode 100644 index 000000000..306e3f739 --- /dev/null +++ b/test/package.json @@ -0,0 +1,20 @@ +{ + "name": "grpc-node-test", + "version": "0.1.0", + "description": "Dummy package for the grpc-node repository tests", + "private": true, + "keywords": [], + "author": { + "name": "Google Inc." + }, + "license": "Apache-2.0", + "contributors": [ + { + "name": "Google Inc." + } + ], + "dependencies": { + "google-auth-library": "^0.9.2", + "lodash": "^4.17.4" + } +} From aa50d30d1d42997d3c819d16694e4e80bddedf10 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sat, 3 Mar 2018 00:38:36 +0100 Subject: [PATCH 0122/1899] Building arm64 binaries. --- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index b33f8decf..049182f8c 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -31,6 +31,8 @@ node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) for version in ${node_versions[@]} do # Cross compile for ARM on x64 + # Requires debian or ubuntu packages "g++-aarch64-linux-gnu" and "g++-arm-linux-gnueabihf". CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ LD=arm-linux-gnueabihf-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm + CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ LD=aarch64-linux-gnu-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm64 cp -r build/stage/* "${ARTIFACTS_OUT}"/ done From 1c50149dea70817989b2b020e87818077b10f810 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 5 Mar 2018 04:06:06 +0100 Subject: [PATCH 0123/1899] Adding electron 1.8 support. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index a33236844..430af8f68 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -16,7 +16,7 @@ set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index d8128863e..6b85fa475 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -46,7 +46,7 @@ arch_list=( ia32 x64 ) node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 ) for arch in ${arch_list[@]} do From b12efa8013778ec27584f70882ac890c651e6f2b Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 5 Mar 2018 20:22:47 +0100 Subject: [PATCH 0124/1899] Updating template to match new testing package structure. --- kokoro.sh | 2 ++ .../grpc-native-core/templates/package.json.template | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/kokoro.sh b/kokoro.sh index 3e51749c1..23789226e 100755 --- a/kokoro.sh +++ b/kokoro.sh @@ -20,4 +20,6 @@ cd $(dirname $0) git submodule update --init git submodule foreach --recursive git submodule update --init +./packages/grpc-native-core/tools/buildgen/generate_projects.sh + ./run-tests.sh diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 51df7d81d..359cd500c 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -36,8 +36,16 @@ "protobufjs": "^5.0.0" }, "devDependencies": { + "async": "^2.0.1", + "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", - "istanbul": "^0.4.4" + "express": "^4.14.0", + "google-auth-library": "^0.9.2", + "google-protobuf": "^3.0.0", + "istanbul": "^0.4.4", + "lodash": "^4.17.4", + "minimist": "^1.1.0", + "poisson-process": "^0.2.1" }, "engines": { "node": ">=4" From 232ff022ab24939bbef2ca48d097688ebe259be1 Mon Sep 17 00:00:00 2001 From: Mohamad mehdi Kharatizadeh Date: Tue, 6 Mar 2018 01:32:55 +0330 Subject: [PATCH 0125/1899] stronger checking for functions in client.js checking for functions simply by instanceof would render library usesless in vm or REPL contexts. because if client is created in another V8 context, typeof would still return "function" but instanceof Function would fail and return false for functions and arrow functions. thus it would be impossible to create client before starting a REPL context. --- packages/grpc-native-core/src/client.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 79868df46..e5ce8a3e1 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -429,7 +429,7 @@ exports.Client = Client; Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, argument, metadata, options, callback) { - if (options instanceof Function) { + if (_.isFunction(options)) { callback = options; if (metadata instanceof Metadata) { options = {}; @@ -437,7 +437,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, options = metadata; metadata = new Metadata(); } - } else if (metadata instanceof Function) { + } else if (_.isFunction(metadata)) { callback = metadata; metadata = new Metadata(); options = {}; @@ -450,7 +450,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, } if (!((metadata instanceof Metadata) && (options instanceof Object) && - (callback instanceof Function))) { + (_.isFunction(callback)))) { throw new Error('Argument mismatch in makeUnaryRequest'); } @@ -508,7 +508,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, Client.prototype.makeClientStreamRequest = function(path, serialize, deserialize, metadata, options, callback) { - if (options instanceof Function) { + if (_.isFunction(options)) { callback = options; if (metadata instanceof Metadata) { options = {}; @@ -516,7 +516,7 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, options = metadata; metadata = new Metadata(); } - } else if (metadata instanceof Function) { + } else if (_.isFunction(metadata)) { callback = metadata; metadata = new Metadata(); options = {}; @@ -529,7 +529,7 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, } if (!((metadata instanceof Metadata) && (options instanceof Object) && - (callback instanceof Function))) { + (_.isFunction(callback)))) { throw new Error('Argument mismatch in makeClientStreamRequest'); } From c29d7db6edc4ca752942317c90c64e42da4f2427 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 28 Feb 2018 11:29:36 -0800 Subject: [PATCH 0126/1899] grpc-js: add mCC and loadPackageDefinition --- packages/grpc-js-core/src/client.ts | 20 ++- packages/grpc-js-core/src/index.ts | 45 +++++- packages/grpc-js-core/src/make-client.ts | 178 +++++++++++++++++++++++ 3 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 packages/grpc-js-core/src/make-client.ts diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 5f9c670bd..74de1d3f9 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -8,20 +8,24 @@ import {ChannelCredentials} from './channel-credentials'; import {Status} from './constants'; import {Metadata} from './metadata'; +// This symbol must be exported (for now). +// See: https://github.com/Microsoft/TypeScript/issues/20080 +export const kChannel = Symbol(); + export interface UnaryCallback { (err: ServiceError|null, value?: ResponseType): void; } export class Client { - private readonly channel: Channel; + private readonly [kChannel]: Channel; constructor( address: string, credentials: ChannelCredentials, options: Partial = {}) { - this.channel = new Http2Channel(address, credentials, options); + this[kChannel] = new Http2Channel(address, credentials, options); } close(): void { - this.channel.close(); + this[kChannel].close(); } waitForReady(deadline: Date|number, callback: (error: Error|null) => void): @@ -29,7 +33,7 @@ export class Client { let cb: (error: Error|null) => void = once(callback); let callbackCalled = false; let timer: NodeJS.Timer | null = null; - this.channel.connect().then(() => { + this[kChannel].connect().then(() => { if (timer) { clearTimeout(timer); } @@ -140,7 +144,7 @@ export class Client { this.checkOptionalUnaryResponseArguments( metadata, options, callback)); const call: CallStream = - this.channel.createStream(method, metadata, options); + this[kChannel].createStream(method, metadata, options); const message: Buffer = serialize(argument); const writeObj: WriteObject = {message: message}; writeObj.flags = options.flags; @@ -178,7 +182,7 @@ export class Client { this.checkOptionalUnaryResponseArguments( metadata, options, callback)); const call: CallStream = - this.channel.createStream(method, metadata, options); + this[kChannel].createStream(method, metadata, options); this.handleUnaryResponse(call, deserialize, callback); return new ClientWritableStreamImpl(call, serialize); } @@ -222,7 +226,7 @@ export class Client { options?: CallOptions): ClientReadableStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: CallStream = - this.channel.createStream(method, metadata, options); + this[kChannel].createStream(method, metadata, options); const message: Buffer = serialize(argument); const writeObj: WriteObject = {message: message}; writeObj.flags = options.flags; @@ -246,7 +250,7 @@ export class Client { options?: CallOptions): ClientDuplexStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: CallStream = - this.channel.createStream(method, metadata, options); + this[kChannel].createStream(method, metadata, options); return new ClientDuplexStreamImpl( call, serialize, deserialize); } diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index be03f1bb1..b26c390b1 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -1,5 +1,40 @@ -export * from './call-credentials'; -export * from './channel-credentials'; -export * from './client'; -export * from './constants'; -export * from './metadata'; + +import { CallCredentials } from './call-credentials'; +import { ChannelCredentials } from './channel-credentials'; +import { Client } from './client'; +import { Status} from './constants'; +import { makeClientConstructor, loadPackageDefinition } from './make-client'; +import { Metadata } from './metadata'; + +const notImplementedFn = () => { throw new Error('Not implemented'); }; + +// Metadata +export { Metadata }; + +// Client credentials + +export const credentials = { + createSsl: ChannelCredentials.createSsl, + createFromMetadataGenerator: CallCredentials.createFromMetadataGenerator, + createFromGoogleCredential: notImplementedFn /*TODO*/, + combineChannelCredentials: (first: ChannelCredentials, ...additional: CallCredentials[]) => additional.reduce((acc, other) => acc.compose(other), first), + combineCallCredentials: (first: CallCredentials, ...additional: CallCredentials[]) => additional.reduce((acc, other) => acc.compose(other), first), + createInsecure: ChannelCredentials.createInsecure +}; + +// Constants + +export { + Status as status + // TODO: Other constants as well +}; + +// Client + +export { + Client, + loadPackageDefinition, + makeClientConstructor, + makeClientConstructor as makeGenericClientConstructor +}; +export const closeClient = (client: Client) => client.close(); diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts new file mode 100644 index 000000000..4249c5c7e --- /dev/null +++ b/packages/grpc-js-core/src/make-client.ts @@ -0,0 +1,178 @@ +import { Metadata } from "./metadata"; +import { Client, UnaryCallback } from "./client"; +import { CallOptions } from "./call-stream"; +import * as _ from 'lodash'; + +export interface ClientClassOptions { + deprecatedArgumentOrder?: boolean; +} + +export interface Serialize { + (value: T): Buffer; +} + +export interface Deserialize { + (bytes: Buffer): T; +} + +export interface MethodDefinition { + path: string; + requestStream: boolean; + responseStream: boolean; + requestSerialize: Serialize; + responseSerialize: Serialize; + requestDeserialize: Deserialize; + responseDeserialize: Deserialize; + originalName: string; +} + +export interface ServiceDefinition { + [index: string]: MethodDefinition; +} + +export interface PackageDefinition { + [index: string]: ServiceDefinition; +} + +function getDefaultValues(metadata?: Metadata, options?: T): { + metadata: Metadata; + options: Partial; +} { + return { + metadata: metadata || new Metadata(), + options: options || {} + }; +} + +/** + * Map with wrappers for each type of requester function to make it use the old + * argument order with optional arguments after the callback. + * @access private + */ +const deprecated_request_wrap = { + unary: (makeUnaryRequest: Function) => { + return function makeWrappedUnaryRequest( + this: Client, argument: RequestType, + callback: UnaryCallback, metadata?: Metadata, + options?: CallOptions) { + const opt_args = getDefaultValues(metadata, options); + return makeUnaryRequest.call(this, argument, opt_args.metadata, + opt_args.options, callback); + }; + }, + client_stream: (makeServerStreamRequest: Function) => { + return function makeWrappedClientStreamRequest( + this: Client, callback: UnaryCallback, + metadata?: Metadata, options?: CallOptions) { + const opt_args = getDefaultValues(metadata, options); + return makeServerStreamRequest.call(this, opt_args.metadata, + opt_args.options, callback); + }; + }, + server_stream: (f: Function) => f, + bidi: (f: Function) => f +}; + +/** + * Map with short names for each of the requester maker functions. Used in + * makeClientConstructor + * @private + */ +const requester_funcs = { + unary: Client.prototype.makeUnaryRequest, + server_stream: Client.prototype.makeServerStreamRequest, + client_stream: Client.prototype.makeClientStreamRequest, + bidi: Client.prototype.makeBidiStreamRequest +}; + +export type ServiceClientConstructor = typeof Client & { + service: ServiceDefinition; +}; + +/** + * Creates a constructor for a client with the given methods, as specified in + * the methods argument. The resulting class will have an instance method for + * each method in the service, which is a partial application of one of the + * [Client]{@link grpc.Client} request methods, depending on `requestSerialize` + * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` + * arguments predefined. + * @param methods An object mapping method names to + * method attributes + * @param serviceName The fully qualified name of the service + * @param classOptions An options object. + * @return New client constructor, which is a subclass of + * {@link grpc.Client}, and has the same arguments as that constructor. + */ +export function makeClientConstructor( + methods: ServiceDefinition, serviceName: string, + classOptions: ClientClassOptions): ServiceClientConstructor { + if (!classOptions) { + classOptions = {}; + } + + class ServiceClient extends Client { + static service: ServiceDefinition; + [methodName: string]: Function; + } + + _.each(methods, (attrs, name) => { + let method_type: keyof typeof requester_funcs; + // TODO(murgatroid99): Verify that we don't need this anymore + if (_.startsWith(name, '$')) { + throw new Error('Method names cannot start with $'); + } + if (attrs.requestStream) { + if (attrs.responseStream) { + method_type = 'bidi'; + } else { + method_type = 'client_stream'; + } + } else { + if (attrs.responseStream) { + method_type = 'server_stream'; + } else { + method_type = 'unary'; + } + } + const serialize = attrs.requestSerialize; + const deserialize = attrs.responseDeserialize; + const method_func = _.partial(requester_funcs[method_type], attrs.path, + serialize, deserialize); + if (classOptions.deprecatedArgumentOrder) { + ServiceClient.prototype[name] = deprecated_request_wrap[method_type](method_func); + } else { + ServiceClient.prototype[name] = method_func; + } + // Associate all provided attributes with the method + _.assign(ServiceClient.prototype[name], attrs); + if (attrs.originalName) { + ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; + } + }); + + ServiceClient.service = methods; + + return ServiceClient; +}; + +export type GrpcObject = { + [index: string]: GrpcObject | ServiceClientConstructor; +}; + +export function loadPackageDefinition(packageDef: PackageDefinition) { + const result: GrpcObject = {}; + for (const serviceFqn in packageDef) { + const service = packageDef[serviceFqn]; + const nameComponents = serviceFqn.split('.'); + const serviceName = nameComponents[nameComponents.length-1]; + let current = result; + for (const packageName in nameComponents.slice(0, -1)) { + if (!current[packageName]) { + current[packageName] = {}; + } + current = current[packageName] as GrpcObject; + } + current[serviceName] = makeClientConstructor(service, serviceName, {}); + } + return result; +} From a01738602205088c60e0b9430c759835ad8f0338 Mon Sep 17 00:00:00 2001 From: theogravity Date: Tue, 6 Mar 2018 15:01:03 -0800 Subject: [PATCH 0127/1899] Add UNIMPLEMENTED details when an RPC method is not impl. --- packages/grpc-native-core/src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index cee852e9a..ec5a80675 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -773,7 +773,7 @@ Server.prototype.start = function() { (new Metadata())._getCoreRepresentation(); batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { code: constants.status.UNIMPLEMENTED, - details: '', + details: 'RPC method not implemented ' + method, metadata: {} }; batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; From a3dc724d3974f045821a04b2382d04272975175f Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 6 Mar 2018 15:06:25 -0800 Subject: [PATCH 0128/1899] address comment and use camelCase --- packages/grpc-js-core/src/make-client.ts | 55 ++++-------------------- 1 file changed, 9 insertions(+), 46 deletions(-) diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index 4249c5c7e..120a457ca 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -3,10 +3,6 @@ import { Client, UnaryCallback } from "./client"; import { CallOptions } from "./call-stream"; import * as _ from 'lodash'; -export interface ClientClassOptions { - deprecatedArgumentOrder?: boolean; -} - export interface Serialize { (value: T): Buffer; } @@ -44,41 +40,12 @@ function getDefaultValues(metadata?: Metadata, options?: T): { }; } -/** - * Map with wrappers for each type of requester function to make it use the old - * argument order with optional arguments after the callback. - * @access private - */ -const deprecated_request_wrap = { - unary: (makeUnaryRequest: Function) => { - return function makeWrappedUnaryRequest( - this: Client, argument: RequestType, - callback: UnaryCallback, metadata?: Metadata, - options?: CallOptions) { - const opt_args = getDefaultValues(metadata, options); - return makeUnaryRequest.call(this, argument, opt_args.metadata, - opt_args.options, callback); - }; - }, - client_stream: (makeServerStreamRequest: Function) => { - return function makeWrappedClientStreamRequest( - this: Client, callback: UnaryCallback, - metadata?: Metadata, options?: CallOptions) { - const opt_args = getDefaultValues(metadata, options); - return makeServerStreamRequest.call(this, opt_args.metadata, - opt_args.options, callback); - }; - }, - server_stream: (f: Function) => f, - bidi: (f: Function) => f -}; - /** * Map with short names for each of the requester maker functions. Used in * makeClientConstructor * @private */ -const requester_funcs = { +const requesterFuncs = { unary: Client.prototype.makeUnaryRequest, server_stream: Client.prototype.makeServerStreamRequest, client_stream: Client.prototype.makeClientStreamRequest, @@ -105,7 +72,7 @@ export type ServiceClientConstructor = typeof Client & { */ export function makeClientConstructor( methods: ServiceDefinition, serviceName: string, - classOptions: ClientClassOptions): ServiceClientConstructor { + classOptions?: {}): ServiceClientConstructor { if (!classOptions) { classOptions = {}; } @@ -116,33 +83,29 @@ export function makeClientConstructor( } _.each(methods, (attrs, name) => { - let method_type: keyof typeof requester_funcs; + let methodType: keyof typeof requesterFuncs; // TODO(murgatroid99): Verify that we don't need this anymore if (_.startsWith(name, '$')) { throw new Error('Method names cannot start with $'); } if (attrs.requestStream) { if (attrs.responseStream) { - method_type = 'bidi'; + methodType = 'bidi'; } else { - method_type = 'client_stream'; + methodType = 'client_stream'; } } else { if (attrs.responseStream) { - method_type = 'server_stream'; + methodType = 'server_stream'; } else { - method_type = 'unary'; + methodType = 'unary'; } } const serialize = attrs.requestSerialize; const deserialize = attrs.responseDeserialize; - const method_func = _.partial(requester_funcs[method_type], attrs.path, + const methodFunc = _.partial(requesterFuncs[methodType], attrs.path, serialize, deserialize); - if (classOptions.deprecatedArgumentOrder) { - ServiceClient.prototype[name] = deprecated_request_wrap[method_type](method_func); - } else { - ServiceClient.prototype[name] = method_func; - } + ServiceClient.prototype[name] = methodFunc; // Associate all provided attributes with the method _.assign(ServiceClient.prototype[name], attrs); if (attrs.originalName) { From 921d5ee08042db461ef4e35b0a1dc34f0aec2ded Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 6 Mar 2018 17:46:39 -0800 Subject: [PATCH 0129/1899] changes to ServiceClient interface --- packages/grpc-js-core/src/make-client.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index 120a457ca..ea176a5fa 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -2,6 +2,8 @@ import { Metadata } from "./metadata"; import { Client, UnaryCallback } from "./client"; import { CallOptions } from "./call-stream"; import * as _ from 'lodash'; +import { ChannelCredentials } from "./channel-credentials"; +import { ChannelOptions } from "./channel"; export interface Serialize { (value: T): Buffer; @@ -19,7 +21,7 @@ export interface MethodDefinition { responseSerialize: Serialize; requestDeserialize: Deserialize; responseDeserialize: Deserialize; - originalName: string; + originalName?: string; } export interface ServiceDefinition { @@ -52,7 +54,13 @@ const requesterFuncs = { bidi: Client.prototype.makeBidiStreamRequest }; -export type ServiceClientConstructor = typeof Client & { +export interface ServiceClient extends Client { + [methodName: string]: Function; +} + +export interface ServiceClientConstructor { + new(address: string, credentials: ChannelCredentials, + options?: Partial): ServiceClient; service: ServiceDefinition; }; @@ -77,7 +85,7 @@ export function makeClientConstructor( classOptions = {}; } - class ServiceClient extends Client { + class ServiceClientImpl extends Client implements ServiceClient { static service: ServiceDefinition; [methodName: string]: Function; } @@ -105,17 +113,17 @@ export function makeClientConstructor( const deserialize = attrs.responseDeserialize; const methodFunc = _.partial(requesterFuncs[methodType], attrs.path, serialize, deserialize); - ServiceClient.prototype[name] = methodFunc; + ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method - _.assign(ServiceClient.prototype[name], attrs); + _.assign(ServiceClientImpl.prototype[name], attrs); if (attrs.originalName) { - ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; + ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; } }); - ServiceClient.service = methods; + ServiceClientImpl.service = methods; - return ServiceClient; + return ServiceClientImpl; }; export type GrpcObject = { From 7e0e74213fd73d50df344732470866165f6ad5e0 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 7 Mar 2018 15:02:37 -0800 Subject: [PATCH 0130/1899] Add client libraries integration test package --- test/client-libraries-integration/.gitignore | 1 + test/client-libraries-integration/init.sh | 13 ++++++++++++ .../client-libraries-integration/package.json | 9 +++++++++ .../repositories.json | 20 +++++++++++++++++++ .../use-grpc-js.js | 18 +++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 test/client-libraries-integration/.gitignore create mode 100755 test/client-libraries-integration/init.sh create mode 100644 test/client-libraries-integration/package.json create mode 100644 test/client-libraries-integration/repositories.json create mode 100644 test/client-libraries-integration/use-grpc-js.js diff --git a/test/client-libraries-integration/.gitignore b/test/client-libraries-integration/.gitignore new file mode 100644 index 000000000..5fe2e3660 --- /dev/null +++ b/test/client-libraries-integration/.gitignore @@ -0,0 +1 @@ +nodejs-*/ \ No newline at end of file diff --git a/test/client-libraries-integration/init.sh b/test/client-libraries-integration/init.sh new file mode 100755 index 000000000..c5834a772 --- /dev/null +++ b/test/client-libraries-integration/init.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +npm install + +for dir in $(node -p "require('./repositories.json').join('\n')"); do + if [ ! -d $dir ]; then + git clone https://github.com/googleapis/$dir + fi + pushd $dir + npm install + popd + node --require ./use-grpc-js.js $(npm bin)/_mocha --timeout 60000 $dir/system-test/*.js +done diff --git a/test/client-libraries-integration/package.json b/test/client-libraries-integration/package.json new file mode 100644 index 000000000..ea639a064 --- /dev/null +++ b/test/client-libraries-integration/package.json @@ -0,0 +1,9 @@ +{ + "name": "grpc-client-libraries-integration", + "version": "0.0.1", + "description": "", + "dependencies": { + "mocha": "^5.0.4", + "shimmer": "^1.2.0" + } +} diff --git a/test/client-libraries-integration/repositories.json b/test/client-libraries-integration/repositories.json new file mode 100644 index 000000000..31a937e9d --- /dev/null +++ b/test/client-libraries-integration/repositories.json @@ -0,0 +1,20 @@ +[ + "nodejs-datastore", + "nodejs-language", + "nodejs-storage", + "nodejs-translate", + "nodejs-logging", + "nodejs-video-intelligence", + "nodejs-dlp", + "nodejs-firestore", + "nodejs-pubsub", + "nodejs-spanner", + "nodejs-speech", + "nodejs-vision", + "nodejs-bigquery", + "nodejs-monitoring", + "nodejs-bigtable", + "nodejs-dns", + "nodejs-resource", + "nodejs-compute" +] \ No newline at end of file diff --git a/test/client-libraries-integration/use-grpc-js.js b/test/client-libraries-integration/use-grpc-js.js new file mode 100644 index 000000000..05273944e --- /dev/null +++ b/test/client-libraries-integration/use-grpc-js.js @@ -0,0 +1,18 @@ +const Module = require('module'); +const shimmer = require('shimmer'); + +const grpcImpl = require('../../packages/grpc-js-core'); +const grpcPJson = require('../../packages/grpc-js-core/package'); + +shimmer.wrap(Module, '_load', (moduleLoad) => { + return function Module_load(path, parent) { + if (path === 'grpc') { + return grpcImpl; + } else if (path.startsWith('grpc/package')) { + return grpcPJson; + } else { + const result = moduleLoad.apply(this, arguments); + return result; + } + }; +}); From 5e0d34a7b79f8f8d5d5f5459d4a42e398d2cc6d7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Mar 2018 16:42:01 -0800 Subject: [PATCH 0131/1899] Make interop tests use new proto loader, run them with pure js client --- packages/grpc-js-core/src/channel.ts | 11 ++- packages/grpc-js-core/src/make-client.ts | 2 +- packages/grpc-native-core/index.js | 2 +- packages/grpc-protobufjs/package.json | 3 +- packages/grpc-protobufjs/src/index.ts | 57 +++++++++----- test/any_grpc.js | 26 ++----- test/api/interop_sanity_test.js | 94 ++++++++++++++++++++++++ test/fixtures/native_js.js | 4 +- test/gulpfile.js | 27 ++++++- test/interop/interop_client.js | 14 +++- test/interop/interop_server.js | 14 +++- 11 files changed, 201 insertions(+), 53 deletions(-) create mode 100644 test/api/interop_sanity_test.js diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 193ae9a55..8fcce521f 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -158,6 +158,7 @@ export class Http2Channel extends EventEmitter implements Channel { connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate): Error | undefined => { return checkServerIdentity(sslTargetNameOverride, cert); } + connectionOptions.servername = sslTargetNameOverride; } subChannel = http2.connect(this.authority, connectionOptions); } @@ -224,7 +225,14 @@ export class Http2Channel extends EventEmitter implements Channel { Promise.all([finalMetadata, this.connect()]) .then(([metadataValue]) => { let headers = metadataValue.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = this.authority.hostname; + let host: string; + // TODO(murgatroid99): Add more centralized handling of channel options + if (this.options['grpc.default_authority']) { + host = this.options['grpc.default_authority'] as string; + } else { + host = this.authority.hostname; + } + headers[HTTP2_HEADER_AUTHORITY] = host; headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; headers[HTTP2_HEADER_METHOD] = 'POST'; @@ -234,6 +242,7 @@ export class Http2Channel extends EventEmitter implements Channel { if (this.connectivityState === ConnectivityState.READY) { const session: http2.ClientHttp2Session = this.subChannel!; // Prevent the HTTP/2 session from keeping the process alive. + // Note: this function is only available in Node 9 session.unref(); stream.attachHttp2Stream(session.request(headers)); } else { diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index ea176a5fa..bc3299e80 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -137,7 +137,7 @@ export function loadPackageDefinition(packageDef: PackageDefinition) { const nameComponents = serviceFqn.split('.'); const serviceName = nameComponents[nameComponents.length-1]; let current = result; - for (const packageName in nameComponents.slice(0, -1)) { + for (const packageName of nameComponents.slice(0, -1)) { if (!current[packageName]) { current[packageName] = {}; } diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 4e4289fa1..30a6ff3c2 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -158,7 +158,7 @@ exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { const nameComponents = serviceFqn.split('.'); const serviceName = nameComponents[nameComponents.length-1]; let current = result; - for (const packageName in nameComponents.slice(0, -1)) { + for (const packageName of nameComponents.slice(0, -1)) { if (!current[packageName]) { current[packageName] = {}; } diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index a6fecc1bf..bcf53e5f9 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -30,10 +30,11 @@ "build/src/*.js" ], "dependencies": { + "@types/lodash": "^4.14.104", "@types/node": "^9.4.6", "clang-format": "^1.2.2", "gts": "^0.5.3", - "lodash": "^4.17.4", + "lodash": "^4.17.5", "protobufjs": "^6.8.5", "typescript": "~2.7.2" } diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index 22083f986..85c2c9413 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -18,6 +18,7 @@ import * as Protobuf from 'protobufjs'; import * as fs from 'fs'; import * as path from 'path'; +import * as _ from 'lodash'; export interface Serialize { (value: T): Buffer; @@ -35,6 +36,7 @@ export interface MethodDefinition { responseSerialize: Serialize; requestDeserialize: Deserialize; responseDeserialize: Deserialize; + originalName?: string; } export interface ServiceDefinition { @@ -88,12 +90,14 @@ function createSerializer(cls: Protobuf.Type): Serialize { function createMethodDefinition(method: Protobuf.Method, serviceName: string, options: Options): MethodDefinition { return { path: '/' + serviceName + '/' + method.name, - requestStream: !!method.requestStream, - responseStream: !!method.responseStream, - requestSerialize: createSerializer(method.resolvedRequestType as Protobuf.Type), - requestDeserialize: createDeserializer(method.resolvedRequestType as Protobuf.Type, options), - responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), - responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options) + requestStream: !!method.requestStream, + responseStream: !!method.responseStream, + requestSerialize: createSerializer(method.resolvedRequestType as Protobuf.Type), + requestDeserialize: createDeserializer(method.resolvedRequestType as Protobuf.Type, options), + responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), + responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options), + // TODO(murgatroid99): Find a better way to handle this + originalName: _.camelCase(method.name) }; } @@ -113,6 +117,21 @@ function createPackageDefinition(root: Protobuf.Root, options: Options): Package return def; } +function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { + root.resolvePath = (origin: string, target: string) => { + for (const directory of includePaths) { + const fullPath: string = path.join(directory, target); + try { + fs.accessSync(fullPath, fs.constants.R_OK); + return fullPath; + } catch (err) { + continue; + } + } + return null; + }; +} + /** * Load a .proto file with the specified options. * @param filename The file path to load. Can be an absolute path or relative to @@ -143,21 +162,23 @@ export function load(filename: string, options: Options): Promise { - for (const directory of options.include as string[]) { - const fullPath: string = path.join(directory, target); - try { - fs.accessSync(fullPath, fs.constants.R_OK); - return fullPath; - } catch (err) { - continue; - } - } - return null; - }; + addIncludePathResolver(root, options.include as string[]); } return root.load(filename, options).then((loadedRoot) => { loadedRoot.resolveAll(); return createPackageDefinition(root, options); }); } + +export function loadSync(filename: string, options: Options): PackageDefinition { + const root: Protobuf.Root = new Protobuf.Root(); + if (!!options.include) { + if (!(options.include instanceof Array)) { + throw new Error('The include option must be an array'); + } + addIncludePathResolver(root, options.include as string[]); + } + const loadedRoot = root.loadSync(filename, options); + loadedRoot.resolveAll(); + return createPackageDefinition(root, options); +} diff --git a/test/any_grpc.js b/test/any_grpc.js index d6d008c29..a434d41b4 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -11,29 +11,15 @@ function getImplementation(globalField) { 'If running from the command line, please --require a fixture first.' ].join(' ')); } + console.error(globalField, global[globalField]); const impl = global[globalField]; - return { - surface: require(`../packages/grpc-${impl}`), - pjson: require(`../packages/grpc-${impl}/package.json`), - core: require(`../packages/grpc-${impl}-core`), - corePjson: require(`../packages/grpc-${impl}-core/package.json`) - }; + return require(`../packages/grpc-${impl}-core`); } const clientImpl = getImplementation('_client_implementation'); const serverImpl = getImplementation('_server_implementation'); -// We export a "merged" gRPC API by merging client and server specified -// APIs together. Any function that is unspecific to client/server defaults -// to client-side implementation. -// This object also has a test-only field from which details about the -// modules may be read. -module.exports = Object.assign({ - '$implementationInfo': { - client: clientImpl, - server: serverImpl - } -}, clientImpl.surface, _.pick(serverImpl.surface, [ - 'Server', - 'ServerCredentials' -])); +module.exports = { + client: clientImpl, + server: serverImpl +}; diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js new file mode 100644 index 000000000..b3f65a034 --- /dev/null +++ b/test/api/interop_sanity_test.js @@ -0,0 +1,94 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var interop_server = require('../interop/interop_server.js'); +var interop_client = require('../interop/interop_client.js'); + +var server; + +var port; + +var name_override = 'foo.test.google.fr'; + +describe('Interop tests', function() { + before(function(done) { + var server_obj = interop_server.getServer(0, true); + server = server_obj.server; + server.start(); + port = 'localhost:' + server_obj.port; + done(); + }); + after(function() { + server.forceShutdown(); + }); + // This depends on not using a binary stream + it('should pass empty_unary', function(done) { + interop_client.runTest(port, name_override, 'empty_unary', true, true, + done); + }); + // This fails due to an unknown bug + it('should pass large_unary', function(done) { + interop_client.runTest(port, name_override, 'large_unary', true, true, + done); + }); + it('should pass client_streaming', function(done) { + interop_client.runTest(port, name_override, 'client_streaming', true, true, + done); + }); + it('should pass server_streaming', function(done) { + interop_client.runTest(port, name_override, 'server_streaming', true, true, + done); + }); + it('should pass ping_pong', function(done) { + interop_client.runTest(port, name_override, 'ping_pong', true, true, done); + }); + it('should pass empty_stream', function(done) { + interop_client.runTest(port, name_override, 'empty_stream', true, true, + done); + }); + it('should pass cancel_after_begin', function(done) { + interop_client.runTest(port, name_override, 'cancel_after_begin', true, + true, done); + }); + it('should pass cancel_after_first_response', function(done) { + interop_client.runTest(port, name_override, 'cancel_after_first_response', + true, true, done); + }); + it('should pass timeout_on_sleeping_server', function(done) { + interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', + true, true, done); + }); + it('should pass custom_metadata', function(done) { + interop_client.runTest(port, name_override, 'custom_metadata', + true, true, done); + }); + it('should pass status_code_and_message', function(done) { + interop_client.runTest(port, name_override, 'status_code_and_message', + true, true, done); + }); + it('should pass unimplemented_service', function(done) { + interop_client.runTest(port, name_override, 'unimplemented_service', + true, true, done); + }); + it('should pass unimplemented_method', function(done) { + interop_client.runTest(port, name_override, 'unimplemented_method', + true, true, done); + }); +}); diff --git a/test/fixtures/native_js.js b/test/fixtures/native_js.js index 5088df96d..3da4106ec 100644 --- a/test/fixtures/native_js.js +++ b/test/fixtures/native_js.js @@ -1,2 +1,2 @@ -global._server_implementation = 'js'; -global._client_implementation = 'native'; \ No newline at end of file +global._server_implementation = 'native'; +global._client_implementation = 'js'; diff --git a/test/gulpfile.js b/test/gulpfile.js index 41c4b33c5..61ff16586 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -35,4 +35,29 @@ gulp.task('install', 'Install test dependencies', () => { gulp.task('clean.all', 'Delete all files created by tasks', () => {}); -gulp.task('test', 'Run API-level tests', () => {}); +gulp.task('test', 'Run API-level tests', () => { + // run mocha tests matching a glob with a pre-required fixture, + // returning the associated gulp stream + const apiTestGlob = `${apiTestDir}/*.js`; + const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { + const fixture = `${server}_${client}`; + console.log(`Running ${apiTestGlob} with ${server} server + ${client} client`); + gulp.src(apiTestGlob) + .pipe(mocha({ + reporter: 'mocha-jenkins-reporter', + require: `${testDir}/fixtures/${fixture}.js` + })) + .resume() // put the stream in flowing mode + .on('end', resolve) + .on('error', reject); + }); + const runTestsArgPairs = [ + ['native', 'native'], + ['native', 'js'], + // ['js', 'native'], + // ['js', 'js'] + ]; + return runTestsArgPairs.reduce((previousPromise, argPair) => { + return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); + }, Promise.resolve()); +}); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 83890bca8..da3f6c333 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -20,12 +20,18 @@ var fs = require('fs'); var path = require('path'); -var grpc = require('../any_grpc')['$implementationInfo'].client.surface; -var testProto = grpc.load({ - root: __dirname + '/../../packages/grpc-native-core/deps/grpc', - file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; +var grpc = require('../any_grpc').client; +var protoLoader = require('../../packages/grpc-protobufjs'); var GoogleAuth = require('google-auth-library'); +var protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/test.proto', + {keepCase: true, + defaults: true, + enums: String, + include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +var testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; + var assert = require('assert'); var SERVICE_ACCOUNT_EMAIL; diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index fe1222dd3..a0b80cc99 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -22,10 +22,16 @@ var fs = require('fs'); var path = require('path'); var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); -var grpc = require('../any_grpc')['$implementationInfo'].server.surface; -var testProto = grpc.load({ - root: __dirname + '/../../packages/grpc-native-core/deps/grpc', - file: 'src/proto/grpc/testing/test.proto'}).grpc.testing; +var grpc = require('../any_grpc').server; +// TODO(murgatroid99): do this import more cleanly +var protoLoader = require('../../packages/grpc-protobufjs'); +var protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/test.proto', + {keepCase: true, + defaults: true, + enums: String, + include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +var testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; From 73c1c6d6635db6c39375fd862f4f5b69c55295b9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Mar 2018 17:09:14 -0800 Subject: [PATCH 0132/1899] Add new option to option list --- packages/grpc-js-core/src/channel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 8fcce521f..22a9c5860 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -41,6 +41,7 @@ export interface ChannelOptions { 'grpc.ssl_target_name_override': string; 'grpc.primary_user_agent': string; 'grpc.secondary_user_agent': string; + 'grpc.default_authority': string; [key: string]: string | number; } From dbd1feb5739b010e48316fe40a0a9f97e44d6997 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Mar 2018 18:00:48 -0800 Subject: [PATCH 0133/1899] Remove internal tests from main test script for now --- gulpfile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gulpfile.ts b/gulpfile.ts index 969fb894c..a49fac2ce 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -99,7 +99,7 @@ gulp.task('clean.all', 'Delete all files created by tasks', 'internal.test.clean.all', 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', - ['native.core.test', 'internal.test.test', 'health-check.test']); + ['native.core.test', 'health-check.test']); gulp.task('native.test', 'Run tests of native code', (callback) => { runSequence('build', 'native.test.only', callback); From 3b61fb6d99d842584a34a58abef8978823588d6e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 8 Mar 2018 18:15:31 -0800 Subject: [PATCH 0134/1899] Remove now-duplicate interop sanity test file --- .../test/interop_sanity_test.js | 95 ------------------- 1 file changed, 95 deletions(-) delete mode 100644 packages/grpc-native-core/test/interop_sanity_test.js diff --git a/packages/grpc-native-core/test/interop_sanity_test.js b/packages/grpc-native-core/test/interop_sanity_test.js deleted file mode 100644 index 0c4130739..000000000 --- a/packages/grpc-native-core/test/interop_sanity_test.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -require('../../../test/fixtures/native_native.js'); -var interop_server = require('../../../test/interop/interop_server.js'); -var interop_client = require('../../../test/interop/interop_client.js'); - -var server; - -var port; - -var name_override = 'foo.test.google.fr'; - -describe('Interop tests', function() { - before(function(done) { - var server_obj = interop_server.getServer(0, true); - server = server_obj.server; - server.start(); - port = 'localhost:' + server_obj.port; - done(); - }); - after(function() { - server.forceShutdown(); - }); - // This depends on not using a binary stream - it('should pass empty_unary', function(done) { - interop_client.runTest(port, name_override, 'empty_unary', true, true, - done); - }); - // This fails due to an unknown bug - it('should pass large_unary', function(done) { - interop_client.runTest(port, name_override, 'large_unary', true, true, - done); - }); - it('should pass client_streaming', function(done) { - interop_client.runTest(port, name_override, 'client_streaming', true, true, - done); - }); - it('should pass server_streaming', function(done) { - interop_client.runTest(port, name_override, 'server_streaming', true, true, - done); - }); - it('should pass ping_pong', function(done) { - interop_client.runTest(port, name_override, 'ping_pong', true, true, done); - }); - it('should pass empty_stream', function(done) { - interop_client.runTest(port, name_override, 'empty_stream', true, true, - done); - }); - it('should pass cancel_after_begin', function(done) { - interop_client.runTest(port, name_override, 'cancel_after_begin', true, - true, done); - }); - it('should pass cancel_after_first_response', function(done) { - interop_client.runTest(port, name_override, 'cancel_after_first_response', - true, true, done); - }); - it('should pass timeout_on_sleeping_server', function(done) { - interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', - true, true, done); - }); - it('should pass custom_metadata', function(done) { - interop_client.runTest(port, name_override, 'custom_metadata', - true, true, done); - }); - it('should pass status_code_and_message', function(done) { - interop_client.runTest(port, name_override, 'status_code_and_message', - true, true, done); - }); - it('should pass unimplemented_service', function(done) { - interop_client.runTest(port, name_override, 'unimplemented_service', - true, true, done); - }); - it('should pass unimplemented_method', function(done) { - interop_client.runTest(port, name_override, 'unimplemented_method', - true, true, done); - }); -}); From 2573548de8c7102a7384883fa17555ed6ac7e941 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 9 Mar 2018 10:44:52 -0800 Subject: [PATCH 0135/1899] Update to v1.10.0 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 756acb78f..474c59506 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 756acb78f6ac8a6f6533a55a09590b8e598d112b +Subproject commit 474c5950686e3962bd339c93d27e369bf64f568f diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6d36ab8b6..e3bb175d3 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.0-pre1", + "version": "1.10.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 122787f951626d9b9f3ea536d0613259e5b6891b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 12 Mar 2018 13:36:48 -0700 Subject: [PATCH 0136/1899] Fix js_js fixture --- test/fixtures/js_js.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/fixtures/js_js.js b/test/fixtures/js_js.js index e0ca3c588..7d72dc495 100644 --- a/test/fixtures/js_js.js +++ b/test/fixtures/js_js.js @@ -1,2 +1,2 @@ -global._server_implementation = 'native'; -global._client_implementation = 'js'; \ No newline at end of file +global._server_implementation = 'js'; +global._client_implementation = 'js'; From 03fb2cbb040da0757b6b32a4fdefbeed2e2ff788 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 12 Mar 2018 21:22:01 +0100 Subject: [PATCH 0137/1899] Adding builds to our CI. --- kokoro.bat => test/kokoro.bat | 3 +++ kokoro.sh => test/kokoro.sh | 6 +++++- test/kokoro/linux.cfg | 2 +- test/kokoro/macos.cfg | 2 +- test/kokoro/windows.cfg | 2 +- tools/release/kokoro.bat | 28 ++++++++++++++++++++++++ tools/release/kokoro.sh | 37 ++++++++++++++++++++++++++++++++ tools/release/kokoro/linux.cfg | 25 +++++++++++++++++++++ tools/release/kokoro/macos.cfg | 25 +++++++++++++++++++++ tools/release/kokoro/windows.cfg | 25 +++++++++++++++++++++ 10 files changed, 151 insertions(+), 4 deletions(-) rename kokoro.bat => test/kokoro.bat (95%) rename kokoro.sh => test/kokoro.sh (86%) create mode 100644 tools/release/kokoro.bat create mode 100755 tools/release/kokoro.sh create mode 100644 tools/release/kokoro/linux.cfg create mode 100644 tools/release/kokoro/macos.cfg create mode 100644 tools/release/kokoro/windows.cfg diff --git a/kokoro.bat b/test/kokoro.bat similarity index 95% rename from kokoro.bat rename to test/kokoro.bat index fc5fd8b22..47a31e370 100644 --- a/kokoro.bat +++ b/test/kokoro.bat @@ -15,8 +15,11 @@ @echo "Starting Windows test" cd /d %~dp0 +cd .. git submodule update --init git submodule foreach --recursive git submodule update --init +call tools\release\kokoro.bat + .\run-tests.bat diff --git a/kokoro.sh b/test/kokoro.sh similarity index 86% rename from kokoro.sh rename to test/kokoro.sh index 3e51749c1..dbc6c8db9 100755 --- a/kokoro.sh +++ b/test/kokoro.sh @@ -14,10 +14,14 @@ # limitations under the License. set -e -cd $(dirname $0) +cd $(dirname $0)/.. # Install gRPC and its submodules. git submodule update --init git submodule foreach --recursive git submodule update --init +./packages/grpc-native-core/tools/buildgen/generate_projects.sh + +./tools/release/kokoro.sh + ./run-tests.sh diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index c6b2c88f6..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/kokoro.sh" +build_file: "grpc-node/test/kokoro.sh" timeout_mins: 60 action { define_artifacts { diff --git a/test/kokoro/macos.cfg b/test/kokoro/macos.cfg index c6b2c88f6..f40e6db43 100644 --- a/test/kokoro/macos.cfg +++ b/test/kokoro/macos.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/kokoro.sh" +build_file: "grpc-node/test/kokoro.sh" timeout_mins: 60 action { define_artifacts { diff --git a/test/kokoro/windows.cfg b/test/kokoro/windows.cfg index e4a4524bd..2b9d09060 100644 --- a/test/kokoro/windows.cfg +++ b/test/kokoro/windows.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/kokoro.bat" +build_file: "grpc-node/test/kokoro.bat" timeout_mins: 60 diff --git a/tools/release/kokoro.bat b/tools/release/kokoro.bat new file mode 100644 index 000000000..e86e01bd7 --- /dev/null +++ b/tools/release/kokoro.bat @@ -0,0 +1,28 @@ +@rem Copyright 2018 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + +@echo "Starting Windows build" + +cd /d %~dp0 +cd ..\.. + +git submodule update --init +git submodule foreach --recursive git submodule update --init + +set ARTIFACTS_OUT=artifacts +cd packages\grpc-native-core +call tools\run_tests\artifacts\build_artifact_node.bat +cd ..\.. + +move packages\grpc-native-core\artifacts . diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh new file mode 100755 index 000000000..7282c7371 --- /dev/null +++ b/tools/release/kokoro.sh @@ -0,0 +1,37 @@ +#!/bin/sh +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -e +cd $(dirname $0)/../.. +base_dir=$(pwd) + +# Install gRPC and its submodules. +git submodule update --init +git submodule foreach --recursive git submodule update --init + +./packages/grpc-native-core/tools/buildgen/generate_projects.sh + +OS=`uname` + +case $OS in +Linux) + ./packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh + mv packages/grpc-native-core/artifacts . + ;; +Darwin) + export ARTIFACTS_OUT=$(base_dir)/artifacts + ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh + ;; +esac diff --git a/tools/release/kokoro/linux.cfg b/tools/release/kokoro/linux.cfg new file mode 100644 index 000000000..80bc144f2 --- /dev/null +++ b/tools/release/kokoro/linux.cfg @@ -0,0 +1,25 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos.cfg b/tools/release/kokoro/macos.cfg new file mode 100644 index 000000000..80bc144f2 --- /dev/null +++ b/tools/release/kokoro/macos.cfg @@ -0,0 +1,25 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows.cfg b/tools/release/kokoro/windows.cfg new file mode 100644 index 000000000..925126e50 --- /dev/null +++ b/tools/release/kokoro/windows.cfg @@ -0,0 +1,25 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro.bat" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} From 50c5b06479a14f0af661eb83bd19f7dd79ebf21f Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 12 Mar 2018 22:57:35 +0100 Subject: [PATCH 0138/1899] Splitting build and test jobs. --- test/kokoro/linux-build.cfg | 19 +++++++++++++++++++ test/kokoro/macos-build.cfg | 19 +++++++++++++++++++ test/kokoro/windows-build.cfg | 19 +++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 test/kokoro/linux-build.cfg create mode 100644 test/kokoro/macos-build.cfg create mode 100644 test/kokoro/windows-build.cfg diff --git a/test/kokoro/linux-build.cfg b/test/kokoro/linux-build.cfg new file mode 100644 index 000000000..b5e6d6e63 --- /dev/null +++ b/test/kokoro/linux-build.cfg @@ -0,0 +1,19 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro.sh" +timeout_mins: 60 diff --git a/test/kokoro/macos-build.cfg b/test/kokoro/macos-build.cfg new file mode 100644 index 000000000..b5e6d6e63 --- /dev/null +++ b/test/kokoro/macos-build.cfg @@ -0,0 +1,19 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro.sh" +timeout_mins: 60 diff --git a/test/kokoro/windows-build.cfg b/test/kokoro/windows-build.cfg new file mode 100644 index 000000000..1885ef39f --- /dev/null +++ b/test/kokoro/windows-build.cfg @@ -0,0 +1,19 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro.bat" +timeout_mins: 60 From 64e3e9d764862a2151a03230e340a9422257b30c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 12 Mar 2018 23:23:23 +0100 Subject: [PATCH 0139/1899] Don't do release build tests in the normal tests. --- test/kokoro.bat | 2 -- test/kokoro.sh | 2 -- 2 files changed, 4 deletions(-) diff --git a/test/kokoro.bat b/test/kokoro.bat index 47a31e370..1f0fabfcf 100644 --- a/test/kokoro.bat +++ b/test/kokoro.bat @@ -20,6 +20,4 @@ cd .. git submodule update --init git submodule foreach --recursive git submodule update --init -call tools\release\kokoro.bat - .\run-tests.bat diff --git a/test/kokoro.sh b/test/kokoro.sh index dbc6c8db9..c4b9373b4 100755 --- a/test/kokoro.sh +++ b/test/kokoro.sh @@ -22,6 +22,4 @@ git submodule foreach --recursive git submodule update --init ./packages/grpc-native-core/tools/buildgen/generate_projects.sh -./tools/release/kokoro.sh - ./run-tests.sh From 8857ccae3422bf9e5440bcb84a7e112c70746cb8 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 13 Mar 2018 01:06:53 +0100 Subject: [PATCH 0140/1899] Enabling debug mode, removing nvm references, installing deps, and increasing timeouts. --- .../run_tests/artifacts/build_all_linux_artifacts.sh | 3 --- .../tools/run_tests/artifacts/build_artifact_node.sh | 3 +++ .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 3 --- .../tools/run_tests/artifacts/build_package_node.sh | 3 --- tools/release/kokoro.sh | 8 +++++--- tools/release/kokoro/linux.cfg | 2 +- tools/release/kokoro/macos.cfg | 2 +- tools/release/kokoro/windows.cfg | 2 +- 8 files changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 2d34d4d75..25fb545f7 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -13,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -source ~/.nvm/nvm.sh - -nvm install 8 set -ex cd $(dirname $0) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index d8128863e..734d7182f 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. + +set -ex + NODE_ALPINE_BUILD=false while true ; do diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index b33f8decf..8c0202ca1 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -13,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -source ~/.nvm/nvm.sh - -nvm use 8 set -ex cd $(dirname $0)/../../.. diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh index 2860f68bc..412d0be23 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh @@ -13,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -source ~/.nvm/nvm.sh - -nvm use 8 set -ex cd $(dirname $0)/../../.. diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 7282c7371..32303b2ed 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -13,7 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -set -e +set -ex cd $(dirname $0)/../.. base_dir=$(pwd) @@ -21,17 +21,19 @@ base_dir=$(pwd) git submodule update --init git submodule foreach --recursive git submodule update --init +pip install mako ./packages/grpc-native-core/tools/buildgen/generate_projects.sh OS=`uname` case $OS in Linux) + sudo apt-get update + sudo apt-get install -y linux-libc-dev:i386 g++-aarch64-linux-gnu g++-arm-linux-gnueabihf ./packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh mv packages/grpc-native-core/artifacts . ;; Darwin) - export ARTIFACTS_OUT=$(base_dir)/artifacts - ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh + ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh ;; esac diff --git a/tools/release/kokoro/linux.cfg b/tools/release/kokoro/linux.cfg index 80bc144f2..b3348f8d3 100644 --- a/tools/release/kokoro/linux.cfg +++ b/tools/release/kokoro/linux.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/tools/release/kokoro.sh" -timeout_mins: 60 +timeout_mins: 180 action { define_artifacts { regex: "github/grpc-node/artifacts/**", diff --git a/tools/release/kokoro/macos.cfg b/tools/release/kokoro/macos.cfg index 80bc144f2..73a539fae 100644 --- a/tools/release/kokoro/macos.cfg +++ b/tools/release/kokoro/macos.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/tools/release/kokoro.sh" -timeout_mins: 60 +timeout_mins: 120 action { define_artifacts { regex: "github/grpc-node/artifacts/**", diff --git a/tools/release/kokoro/windows.cfg b/tools/release/kokoro/windows.cfg index 925126e50..1ba6123f3 100644 --- a/tools/release/kokoro/windows.cfg +++ b/tools/release/kokoro/windows.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/tools/release/kokoro.bat" -timeout_mins: 60 +timeout_mins: 120 action { define_artifacts { regex: "github/grpc-node/artifacts/**", From 8b8a4437e237619cad60005691aa0239eb0c86c0 Mon Sep 17 00:00:00 2001 From: David Vroom Duke Date: Tue, 13 Mar 2018 14:39:08 -0700 Subject: [PATCH 0141/1899] Improve performance of batch operation serializer --- packages/grpc-native-core/src/client_interceptors.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 01023a52b..4f45b7529 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -740,9 +740,14 @@ function _areBatchRequirementsMet(batch_ops, completed_ops) { var dependencies = _.flatMap(batch_ops, function(op) { return OP_DEPENDENCIES[op] || []; }); - var dependencies_met = _.intersection(dependencies, - batch_ops.concat(completed_ops)); - return _.isEqual(dependencies_met.sort(), dependencies.sort()); + for (var i = 0; i < dependencies.length; i++) { + var required_dep = dependencies[i]; + if (batch_ops.indexOf(required_dep) === -1 && + completed_ops.indexOf(required_dep) === -1) { + return false; + } + } + return true; } /** From fcf472e7cb965194a52e36b2635508368c9c5f1a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 13 Mar 2018 22:22:31 +0100 Subject: [PATCH 0142/1899] Adding JOBS environment variable to speed builds up, and reducing scope of Alpine Linux builds. --- .../artifacts/build_all_linux_artifacts.sh | 3 ++- .../run_tests/artifacts/build_artifact_node.bat | 2 ++ .../run_tests/artifacts/build_artifact_node.sh | 17 ++++++----------- run-tests.bat | 1 + run-tests.sh | 1 + tools/release/kokoro.sh | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 25fb545f7..59f62a2fb 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -21,6 +21,7 @@ cd $tool_dir/../../.. base_dir=$(pwd) export ARTIFACTS_OUT=$base_dir/artifacts +export JOBS=8 rm -rf build || true @@ -32,4 +33,4 @@ $tool_dir/build_artifact_node.sh $tool_dir/build_artifact_node_arm.sh -docker run -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact bash -c /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine +docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index a33236844..41177f907 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -20,6 +20,8 @@ set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm +set JOBS=8 + del /f /q BUILD || rmdir build /s /q call npm update || goto :error diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 734d7182f..e00eb6a06 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -16,12 +16,15 @@ set -ex -NODE_ALPINE_BUILD=false +arch_list=( ia32 x64 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 ) while true ; do case $1 in --with-alpine) - NODE_ALPINE_BUILD=true + arch_list=( x64 ) + electron_versions=( ) ;; "") ;; @@ -33,8 +36,6 @@ while true ; do shift || break done -NODE_ALPINE_BUILD=$1 - umask 022 cd $(dirname $0)/../../.. @@ -45,17 +46,11 @@ mkdir -p "${ARTIFACTS_OUT}" npm update -arch_list=( ia32 x64 ) - -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) - -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 ) - for arch in ${arch_list[@]} do for version in ${node_versions[@]} do - ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$version --target_arch=$arch --grpc_alpine=$NODE_ALPINE_BUILD + ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$version --target_arch=$arch cp -r build/stage/* "${ARTIFACTS_OUT}"/ done diff --git a/run-tests.bat b/run-tests.bat index 92c2b2993..bd9a83a99 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -20,6 +20,7 @@ PowerShell -Command .\install-nvm-windows.ps1 SET NVM_HOME=%ROOT%nvm SET NVM_SYMLINK=%ROOT%nvm\nodejs SET PATH=%NVM_HOME%;%NVM_SYMLINK%;%PATH% +SET JOBS=8 nvm version diff --git a/run-tests.sh b/run-tests.sh index c1a76889d..5df881864 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -38,6 +38,7 @@ set -ex npm install --unsafe-perm mkdir -p reports +export JOBS=8 # TODO(mlumish): Add electron tests diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 32303b2ed..e5b578f72 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -34,6 +34,6 @@ Linux) mv packages/grpc-native-core/artifacts . ;; Darwin) - ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh + JOBS=8 ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh ;; esac From 2d0540f9df68fbc3a5162b068c985c484a92056b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 13 Mar 2018 17:20:11 -0700 Subject: [PATCH 0143/1899] Update to newest version of node-pre-gyp --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e3bb175d3..f19bf5d93 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -30,7 +30,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.6.39", + "node-pre-gyp": "^0.9.0", "protobufjs": "^5.0.0" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 51df7d81d..83d3e76da 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -32,7 +32,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.6.39", + "node-pre-gyp": "^0.9.0", "protobufjs": "^5.0.0" }, "devDependencies": { From 5fe868208cd942b2356a50d81e380ca525d81c4e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 5 Mar 2018 04:06:06 +0100 Subject: [PATCH 0144/1899] Adding electron 1.8 support. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 41177f907..e84dd8963 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -16,7 +16,7 @@ set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index e00eb6a06..006370daa 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -18,7 +18,7 @@ set -ex arch_list=( ia32 x64 ) node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 ) while true ; do case $1 in From 691834cafe4848bb267399cd825d69186b546bf4 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 10:37:50 -0700 Subject: [PATCH 0145/1899] grpc-js: fix failing unit test --- .../grpc-js-core/test/test-call-stream.ts | 40 +++++++++++-------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index 0e142e40c..3699fffb7 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -103,16 +103,16 @@ describe('CallStream', () => { assert2.afterMustCallsSatisfied(done); }); - it('should end a call with an error if a stream was closed', (done) => { + describe('should end a call with an error if a stream was closed', () => { const c = http2.constants; const s = Status; const errorCodeMapping = { - [c.NGHTTP2_NO_ERROR]: s.INTERNAL, + [c.NGHTTP2_NO_ERROR]: s.OK, [c.NGHTTP2_PROTOCOL_ERROR]: s.INTERNAL, [c.NGHTTP2_INTERNAL_ERROR]: s.INTERNAL, [c.NGHTTP2_FLOW_CONTROL_ERROR]: s.INTERNAL, [c.NGHTTP2_SETTINGS_TIMEOUT]: s.INTERNAL, - [c.NGHTTP2_STREAM_CLOSED]: null, + [c.NGHTTP2_STREAM_CLOSED]: s.INTERNAL, [c.NGHTTP2_FRAME_SIZE_ERROR]: s.INTERNAL, [c.NGHTTP2_REFUSED_STREAM]: s.UNAVAILABLE, [c.NGHTTP2_CANCEL]: s.CANCELLED, @@ -121,21 +121,27 @@ describe('CallStream', () => { [c.NGHTTP2_ENHANCE_YOUR_CALM]: s.RESOURCE_EXHAUSTED, [c.NGHTTP2_INADEQUATE_SECURITY]: s.PERMISSION_DENIED }; - forOwn(errorCodeMapping, (value: Status | null, key) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); - callStream.attachHttp2Stream(http2Stream); - if (value !== null) { - callStream.once('status', assert2.mustCall((status) => { - assert.strictEqual(status.code, value); - })); - } - http2Stream.emit('streamClosed', Number(key)); + const keys = Object.keys(errorCodeMapping).map(key => Number(key)); + keys.forEach((key) => { + const value = errorCodeMapping[key]; + it(`for error code ${key}`, () => new Promise((resolve, reject) => { + const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [] + }); + callStream.attachHttp2Stream(http2Stream); + callStream.once('status', (status) => { + try { + assert.strictEqual(status.code, value); + resolve(); + } catch (e) { + reject(e); + } + }); + http2Stream.emit('close', Number(key)); + })); }); - assert2.afterMustCallsSatisfied(done); }); it('should have functioning getters', (done) => { From e92224ba7b6a1ec17afcd5a6963c8ba03a27ba17 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 09:51:32 -0700 Subject: [PATCH 0146/1899] grpc-js: add google credentials implementation --- packages/grpc-js-core/src/call-credentials.ts | 40 +++++----- .../grpc-js-core/src/channel-credentials.ts | 33 ++++---- packages/grpc-js-core/src/client.ts | 4 + packages/grpc-js-core/src/index.ts | 78 +++++++++++++++---- packages/grpc-js-core/src/make-client.ts | 7 +- 5 files changed, 110 insertions(+), 52 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 278cb163b..f0ad0980b 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -2,33 +2,33 @@ import {map, reduce} from 'lodash'; import {Metadata} from './metadata'; -export type CallMetadataGenerator = - (options: {}, cb: (err: Error|null, metadata?: Metadata) => void) => +export type CallMetadataGenerator = + (options: T, cb: (err: Error|null, metadata?: Metadata) => void) => void; /** * A class that represents a generic method of adding authentication-related * metadata on a per-request basis. */ -export interface CallCredentials { +export interface CallCredentials { /** * Asynchronously generates a new Metadata object. * @param options Options used in generating the Metadata object. */ - generateMetadata(options: {}): Promise; + generateMetadata(options: T): Promise; /** * Creates a new CallCredentials object from properties of both this and * another CallCredentials object. This object's metadata generator will be * called first. * @param callCredentials The other CallCredentials object. */ - compose(callCredentials: CallCredentials): CallCredentials; + compose(callCredentials: CallCredentials): CallCredentials; } -class ComposedCallCredentials implements CallCredentials { - constructor(private creds: CallCredentials[]) {} +class ComposedCallCredentials implements CallCredentials { + constructor(private creds: CallCredentials[]) {} - async generateMetadata(options: {}): Promise { + async generateMetadata(options: T): Promise { let base: Metadata = new Metadata(); let generated: Metadata[] = await Promise.all( map(this.creds, (cred) => cred.generateMetadata(options))); @@ -38,15 +38,15 @@ class ComposedCallCredentials implements CallCredentials { return base; } - compose(other: CallCredentials): CallCredentials { - return new ComposedCallCredentials(this.creds.concat([other])); + compose(other: CallCredentials): CallCredentials { + return new ComposedCallCredentials([...this.creds, other]); } } -class SingleCallCredentials implements CallCredentials { - constructor(private metadataGenerator: CallMetadataGenerator) {} +class SingleCallCredentials implements CallCredentials { + constructor(private metadataGenerator: CallMetadataGenerator) {} - generateMetadata(options: {}): Promise { + generateMetadata(options: T): Promise { return new Promise((resolve, reject) => { this.metadataGenerator(options, (err, metadata) => { if (metadata !== undefined) { @@ -58,17 +58,17 @@ class SingleCallCredentials implements CallCredentials { }); } - compose(other: CallCredentials): CallCredentials { - return new ComposedCallCredentials([this, other]); + compose(other: CallCredentials): CallCredentials { + return new ComposedCallCredentials([this, other]); } } -class EmptyCallCredentials implements CallCredentials { +class EmptyCallCredentials implements CallCredentials<{}> { generateMetadata(options: {}): Promise { return Promise.resolve(new Metadata()); } - compose(other: CallCredentials): CallCredentials { + compose(other: CallCredentials): CallCredentials { return other; } } @@ -81,12 +81,12 @@ export namespace CallCredentials { * generates a Metadata object based on these options, which is passed back * to the caller via a supplied (err, metadata) callback. */ - export function createFromMetadataGenerator( - metadataGenerator: CallMetadataGenerator): CallCredentials { + export function createFromMetadataGenerator( + metadataGenerator: CallMetadataGenerator): CallCredentials { return new SingleCallCredentials(metadataGenerator); } - export function createEmpty(): CallCredentials { + export function createEmpty(): CallCredentials<{}> { return new EmptyCallCredentials(); } } diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 419e3d17e..98986ff49 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -7,19 +7,19 @@ import {CallCredentials} from './call-credentials'; * as a set of per-call credentials, which are applied to every method call made * over a channel initialized with an instance of this class. */ -export interface ChannelCredentials { +export interface ChannelCredentials { /** * Returns a copy of this object with the included set of per-call credentials * expanded to include callCredentials. * @param callCredentials A CallCredentials object to associate with this * instance. */ - compose(callCredentials: CallCredentials): ChannelCredentials; + compose(callCredentials: CallCredentials): ChannelCredentials; /** * Gets the set of per-call credentials associated with this instance. */ - getCallCredentials(): CallCredentials; + getCallCredentials(): CallCredentials; /** * Gets a SecureContext object generated from input parameters if this @@ -29,28 +29,28 @@ export interface ChannelCredentials { getSecureContext(): SecureContext|null; } -abstract class ChannelCredentialsImpl implements ChannelCredentials { - protected callCredentials: CallCredentials; +abstract class ChannelCredentialsImpl implements ChannelCredentials { + protected callCredentials: CallCredentials; - protected constructor(callCredentials?: CallCredentials) { + protected constructor(callCredentials?: CallCredentials) { this.callCredentials = callCredentials || CallCredentials.createEmpty(); } - abstract compose(callCredentials: CallCredentials): ChannelCredentialsImpl; + abstract compose(callCredentials: CallCredentials): ChannelCredentialsImpl; - getCallCredentials(): CallCredentials { + getCallCredentials(): CallCredentials { return this.callCredentials; } abstract getSecureContext(): SecureContext|null; } -class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { - constructor(callCredentials?: CallCredentials) { +class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { + constructor(callCredentials?: CallCredentials) { super(callCredentials); } - compose(callCredentials: CallCredentials): ChannelCredentialsImpl { + compose(callCredentials: CallCredentials): ChannelCredentialsImpl { throw new Error('Cannot compose insecure credentials'); } @@ -59,15 +59,15 @@ class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { } } -class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { +class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { secureContext: SecureContext; - constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { + constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { super(callCredentials); this.secureContext = secureContext; } - compose(callCredentials: CallCredentials): ChannelCredentialsImpl { + compose(callCredentials: CallCredentials): ChannelCredentialsImpl { const combinedCallCredentials = this.callCredentials.compose(callCredentials); return new SecureChannelCredentialsImpl( @@ -86,7 +86,6 @@ function verifyIsBufferOrNull(obj: any, friendlyName: string): void { } export namespace ChannelCredentials { - /** * Return a new ChannelCredentials instance with a given set of credentials. * The resulting instance can be used to construct a Channel that communicates @@ -97,7 +96,7 @@ export namespace ChannelCredentials { */ export function createSsl( rootCerts?: Buffer|null, privateKey?: Buffer|null, - certChain?: Buffer|null): ChannelCredentials { + certChain?: Buffer|null): ChannelCredentials<{}> { verifyIsBufferOrNull(rootCerts, 'Root certificate'); verifyIsBufferOrNull(privateKey, 'Private key'); verifyIsBufferOrNull(certChain, 'Certificate chain'); @@ -120,7 +119,7 @@ export namespace ChannelCredentials { /** * Return a new ChannelCredentials instance with no credentials. */ - export function createInsecure(): ChannelCredentials { + export function createInsecure(): ChannelCredentials<{}> { return new InsecureChannelCredentialsImpl(); } } diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 74de1d3f9..25fa7bc8c 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -16,6 +16,10 @@ export interface UnaryCallback { (err: ServiceError|null, value?: ResponseType): void; } +/** + * A generic gRPC client. Primarily useful as a base class for all generated + * clients. + */ export class Client { private readonly [kChannel]: Channel; constructor( diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index b26c390b1..7cd935623 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -5,31 +5,76 @@ import { Client } from './client'; import { Status} from './constants'; import { makeClientConstructor, loadPackageDefinition } from './make-client'; import { Metadata } from './metadata'; +import { IncomingHttpHeaders } from 'http'; -const notImplementedFn = () => { throw new Error('Not implemented'); }; +export interface OAuth2Client { + getRequestMetadata: (url: string) => Promise<{ Authorization: string }>; +} -// Metadata -export { Metadata }; +export type GoogleCallCredentials = CallCredentials<{ service_url: string }>; -// Client credentials +/**** Client Credentials ****/ -export const credentials = { - createSsl: ChannelCredentials.createSsl, - createFromMetadataGenerator: CallCredentials.createFromMetadataGenerator, - createFromGoogleCredential: notImplementedFn /*TODO*/, - combineChannelCredentials: (first: ChannelCredentials, ...additional: CallCredentials[]) => additional.reduce((acc, other) => acc.compose(other), first), - combineCallCredentials: (first: CallCredentials, ...additional: CallCredentials[]) => additional.reduce((acc, other) => acc.compose(other), first), - createInsecure: ChannelCredentials.createInsecure -}; +// Using assign only copies enumerable properties, which is what we want +export const credentials = Object.assign({ + /** + * Create a gRPC credential from a Google credential object. + * @param googleCredentials The authentication client to use. + * @return The resulting CallCredentials object. + */ + createFromGoogleCredential: (googleCredentials: OAuth2Client): GoogleCallCredentials => { + return CallCredentials.createFromMetadataGenerator(async (options, callback) => { + let header; + try { + header = await googleCredentials.getRequestMetadata(options.service_url); + } catch (err) { + callback(err); + return; + } + const metadata = new Metadata(); + metadata.add('authorization', header.Authorization); + callback(null, metadata); + }); + }, + + /** + * Combine a ChannelCredentials with any number of CallCredentials into a + * single ChannelCredentials object. + * @param channelCredentials The ChannelCredentials object. + * @param callCredentials Any number of CallCredentials objects. + * @return The resulting ChannelCredentials object. + */ + combineChannelCredentials: ( + channelCredentials: ChannelCredentials, + ...callCredentials: CallCredentials[]): ChannelCredentials => { + return callCredentials.reduce((acc, other) => acc.compose(other), channelCredentials); + }, + + /** + * Combine any number of CallCredentials into a single CallCredentials object. + * @param first The first CallCredentials object. + * @param additional Any number of additional CallCredentials objects. + * @return The resulting CallCredentials object. + */ + combineCallCredentials: ( + first: CallCredentials, + ...additional: CallCredentials[]): CallCredentials => { + return additional.reduce((acc, other) => acc.compose(other), first); + } +}, ChannelCredentials, CallCredentials); -// Constants +/**** Metadata ****/ + +export { Metadata }; + +/**** Constants ****/ export { Status as status // TODO: Other constants as well }; -// Client +/**** Client ****/ export { Client, @@ -37,4 +82,9 @@ export { makeClientConstructor, makeClientConstructor as makeGenericClientConstructor }; + +/** + * Close a Client object. + * @param client The client to close. + */ export const closeClient = (client: Client) => client.close(); diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index bc3299e80..f5433f57d 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -130,7 +130,12 @@ export type GrpcObject = { [index: string]: GrpcObject | ServiceClientConstructor; }; -export function loadPackageDefinition(packageDef: PackageDefinition) { +/** + * Load a gRPC package definition as a gRPC object hierarchy. + * @param packageDef The package definition object. + * @return The resulting gRPC object. + */ +export function loadPackageDefinition(packageDef: PackageDefinition): GrpcObject { const result: GrpcObject = {}; for (const serviceFqn in packageDef) { const service = packageDef[serviceFqn]; From 42ddabe398c3b720f89df20082fcecce113fb2df Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 12:31:14 -0700 Subject: [PATCH 0147/1899] Remove generics from credentials --- packages/grpc-js-core/src/call-credentials.ts | 44 ++++++++++--------- .../grpc-js-core/src/channel-credentials.ts | 33 +++++++------- packages/grpc-js-core/src/index.ts | 39 ++++++++-------- 3 files changed, 58 insertions(+), 58 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index f0ad0980b..888e4c625 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -2,33 +2,35 @@ import {map, reduce} from 'lodash'; import {Metadata} from './metadata'; -export type CallMetadataGenerator = - (options: T, cb: (err: Error|null, metadata?: Metadata) => void) => +export type CallMetadataOptions = { service_url?: string; }; + +export type CallMetadataGenerator = + (options: CallMetadataOptions, cb: (err: Error|null, metadata?: Metadata) => void) => void; /** * A class that represents a generic method of adding authentication-related * metadata on a per-request basis. */ -export interface CallCredentials { +export interface CallCredentials { /** * Asynchronously generates a new Metadata object. * @param options Options used in generating the Metadata object. */ - generateMetadata(options: T): Promise; + generateMetadata(options: CallMetadataOptions): Promise; /** * Creates a new CallCredentials object from properties of both this and * another CallCredentials object. This object's metadata generator will be * called first. * @param callCredentials The other CallCredentials object. */ - compose(callCredentials: CallCredentials): CallCredentials; + compose(callCredentials: CallCredentials): CallCredentials; } -class ComposedCallCredentials implements CallCredentials { - constructor(private creds: CallCredentials[]) {} +class ComposedCallCredentials implements CallCredentials { + constructor(private creds: CallCredentials[]) {} - async generateMetadata(options: T): Promise { + async generateMetadata(options: CallMetadataOptions): Promise { let base: Metadata = new Metadata(); let generated: Metadata[] = await Promise.all( map(this.creds, (cred) => cred.generateMetadata(options))); @@ -38,15 +40,15 @@ class ComposedCallCredentials implements CallCredentials { return base; } - compose(other: CallCredentials): CallCredentials { - return new ComposedCallCredentials([...this.creds, other]); + compose(other: CallCredentials): CallCredentials { + return new ComposedCallCredentials(this.creds.concat([other])); } } -class SingleCallCredentials implements CallCredentials { - constructor(private metadataGenerator: CallMetadataGenerator) {} +class SingleCallCredentials implements CallCredentials { + constructor(private metadataGenerator: CallMetadataGenerator) {} - generateMetadata(options: T): Promise { + generateMetadata(options: CallMetadataOptions): Promise { return new Promise((resolve, reject) => { this.metadataGenerator(options, (err, metadata) => { if (metadata !== undefined) { @@ -58,17 +60,17 @@ class SingleCallCredentials implements CallCredentials { }); } - compose(other: CallCredentials): CallCredentials { - return new ComposedCallCredentials([this, other]); + compose(other: CallCredentials): CallCredentials { + return new ComposedCallCredentials([this, other]); } } -class EmptyCallCredentials implements CallCredentials<{}> { - generateMetadata(options: {}): Promise { +class EmptyCallCredentials implements CallCredentials { + generateMetadata(options: CallMetadataOptions): Promise { return Promise.resolve(new Metadata()); } - compose(other: CallCredentials): CallCredentials { + compose(other: CallCredentials): CallCredentials { return other; } } @@ -81,12 +83,12 @@ export namespace CallCredentials { * generates a Metadata object based on these options, which is passed back * to the caller via a supplied (err, metadata) callback. */ - export function createFromMetadataGenerator( - metadataGenerator: CallMetadataGenerator): CallCredentials { + export function createFromMetadataGenerator( + metadataGenerator: CallMetadataGenerator): CallCredentials { return new SingleCallCredentials(metadataGenerator); } - export function createEmpty(): CallCredentials<{}> { + export function createEmpty(): CallCredentials { return new EmptyCallCredentials(); } } diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 98986ff49..419e3d17e 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -7,19 +7,19 @@ import {CallCredentials} from './call-credentials'; * as a set of per-call credentials, which are applied to every method call made * over a channel initialized with an instance of this class. */ -export interface ChannelCredentials { +export interface ChannelCredentials { /** * Returns a copy of this object with the included set of per-call credentials * expanded to include callCredentials. * @param callCredentials A CallCredentials object to associate with this * instance. */ - compose(callCredentials: CallCredentials): ChannelCredentials; + compose(callCredentials: CallCredentials): ChannelCredentials; /** * Gets the set of per-call credentials associated with this instance. */ - getCallCredentials(): CallCredentials; + getCallCredentials(): CallCredentials; /** * Gets a SecureContext object generated from input parameters if this @@ -29,28 +29,28 @@ export interface ChannelCredentials { getSecureContext(): SecureContext|null; } -abstract class ChannelCredentialsImpl implements ChannelCredentials { - protected callCredentials: CallCredentials; +abstract class ChannelCredentialsImpl implements ChannelCredentials { + protected callCredentials: CallCredentials; - protected constructor(callCredentials?: CallCredentials) { + protected constructor(callCredentials?: CallCredentials) { this.callCredentials = callCredentials || CallCredentials.createEmpty(); } - abstract compose(callCredentials: CallCredentials): ChannelCredentialsImpl; + abstract compose(callCredentials: CallCredentials): ChannelCredentialsImpl; - getCallCredentials(): CallCredentials { + getCallCredentials(): CallCredentials { return this.callCredentials; } abstract getSecureContext(): SecureContext|null; } -class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { - constructor(callCredentials?: CallCredentials) { +class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { + constructor(callCredentials?: CallCredentials) { super(callCredentials); } - compose(callCredentials: CallCredentials): ChannelCredentialsImpl { + compose(callCredentials: CallCredentials): ChannelCredentialsImpl { throw new Error('Cannot compose insecure credentials'); } @@ -59,15 +59,15 @@ class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { } } -class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { +class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { secureContext: SecureContext; - constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { + constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { super(callCredentials); this.secureContext = secureContext; } - compose(callCredentials: CallCredentials): ChannelCredentialsImpl { + compose(callCredentials: CallCredentials): ChannelCredentialsImpl { const combinedCallCredentials = this.callCredentials.compose(callCredentials); return new SecureChannelCredentialsImpl( @@ -86,6 +86,7 @@ function verifyIsBufferOrNull(obj: any, friendlyName: string): void { } export namespace ChannelCredentials { + /** * Return a new ChannelCredentials instance with a given set of credentials. * The resulting instance can be used to construct a Channel that communicates @@ -96,7 +97,7 @@ export namespace ChannelCredentials { */ export function createSsl( rootCerts?: Buffer|null, privateKey?: Buffer|null, - certChain?: Buffer|null): ChannelCredentials<{}> { + certChain?: Buffer|null): ChannelCredentials { verifyIsBufferOrNull(rootCerts, 'Root certificate'); verifyIsBufferOrNull(privateKey, 'Private key'); verifyIsBufferOrNull(certChain, 'Certificate chain'); @@ -119,7 +120,7 @@ export namespace ChannelCredentials { /** * Return a new ChannelCredentials instance with no credentials. */ - export function createInsecure(): ChannelCredentials<{}> { + export function createInsecure(): ChannelCredentials { return new InsecureChannelCredentialsImpl(); } } diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 7cd935623..4809647fb 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -8,11 +8,9 @@ import { Metadata } from './metadata'; import { IncomingHttpHeaders } from 'http'; export interface OAuth2Client { - getRequestMetadata: (url: string) => Promise<{ Authorization: string }>; + getRequestMetadata: (url: string, callback: (err: Error|null, headers?: { Authorization: string }) => void) => void; } -export type GoogleCallCredentials = CallCredentials<{ service_url: string }>; - /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want @@ -22,18 +20,17 @@ export const credentials = Object.assign({ * @param googleCredentials The authentication client to use. * @return The resulting CallCredentials object. */ - createFromGoogleCredential: (googleCredentials: OAuth2Client): GoogleCallCredentials => { - return CallCredentials.createFromMetadataGenerator(async (options, callback) => { - let header; - try { - header = await googleCredentials.getRequestMetadata(options.service_url); - } catch (err) { - callback(err); - return; - } - const metadata = new Metadata(); - metadata.add('authorization', header.Authorization); - callback(null, metadata); + createFromGoogleCredential: (googleCredentials: OAuth2Client): CallCredentials => { + return CallCredentials.createFromMetadataGenerator((options, callback) => { + googleCredentials.getRequestMetadata(options.service_url!, (err, headers) => { + if (err) { + callback(err); + return; + } + const metadata = new Metadata(); + metadata.add('authorization', headers!.Authorization); + callback(null, metadata); + }); }); }, @@ -44,9 +41,9 @@ export const credentials = Object.assign({ * @param callCredentials Any number of CallCredentials objects. * @return The resulting ChannelCredentials object. */ - combineChannelCredentials: ( - channelCredentials: ChannelCredentials, - ...callCredentials: CallCredentials[]): ChannelCredentials => { + combineChannelCredentials: ( + channelCredentials: ChannelCredentials, + ...callCredentials: CallCredentials[]): ChannelCredentials => { return callCredentials.reduce((acc, other) => acc.compose(other), channelCredentials); }, @@ -56,9 +53,9 @@ export const credentials = Object.assign({ * @param additional Any number of additional CallCredentials objects. * @return The resulting CallCredentials object. */ - combineCallCredentials: ( - first: CallCredentials, - ...additional: CallCredentials[]): CallCredentials => { + combineCallCredentials: ( + first: CallCredentials, + ...additional: CallCredentials[]): CallCredentials => { return additional.reduce((acc, other) => acc.compose(other), first); } }, ChannelCredentials, CallCredentials); From 205f237928174154f247228796784dd3ab6ad532 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 14 Mar 2018 14:01:11 -0700 Subject: [PATCH 0148/1899] Don't handle already-finished call in channel --- packages/grpc-js-core/src/channel.ts | 26 ++++++++++++-------------- test/any_grpc.js | 1 - 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 22a9c5860..a4d040236 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -239,20 +239,18 @@ export class Http2Channel extends EventEmitter implements Channel { headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = methodName; headers[HTTP2_HEADER_TE] = 'trailers'; - if (stream.getStatus() === null) { - if (this.connectivityState === ConnectivityState.READY) { - const session: http2.ClientHttp2Session = this.subChannel!; - // Prevent the HTTP/2 session from keeping the process alive. - // Note: this function is only available in Node 9 - session.unref(); - stream.attachHttp2Stream(session.request(headers)); - } else { - /* In this case, we lost the connection while finalizing - * metadata. That should be very unusual */ - setImmediate(() => { - this.startHttp2Stream(methodName, stream, metadata); - }); - } + if (this.connectivityState === ConnectivityState.READY) { + const session: http2.ClientHttp2Session = this.subChannel!; + // Prevent the HTTP/2 session from keeping the process alive. + // Note: this function is only available in Node 9 + session.unref(); + stream.attachHttp2Stream(session.request(headers)); + } else { + /* In this case, we lost the connection while finalizing + * metadata. That should be very unusual */ + setImmediate(() => { + this.startHttp2Stream(methodName, stream, metadata); + }); } }).catch((error: Error & { code: number }) => { // We assume the error code isn't 0 (Status.OK) diff --git a/test/any_grpc.js b/test/any_grpc.js index a434d41b4..250f00981 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -11,7 +11,6 @@ function getImplementation(globalField) { 'If running from the command line, please --require a fixture first.' ].join(' ')); } - console.error(globalField, global[globalField]); const impl = global[globalField]; return require(`../packages/grpc-${impl}-core`); } From 3b324909b72974db8b1f62bb06f19f2eb3055944 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 13:17:06 -0700 Subject: [PATCH 0149/1899] Restore stream_closed error code test --- packages/grpc-js-core/src/call-stream.ts | 3 -- .../grpc-js-core/test/test-call-stream.ts | 40 ++++++++++--------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 849d685fb..3a403d681 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -271,9 +271,6 @@ export class Http2CallStream extends Duplex implements CallStream { let code: Status; let details = ''; switch (errorCode) { - case http2.constants.NGHTTP2_NO_ERROR: - code = Status.OK; - break; case http2.constants.NGHTTP2_REFUSED_STREAM: code = Status.UNAVAILABLE; break; diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index 3699fffb7..fb8f5b029 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -107,12 +107,12 @@ describe('CallStream', () => { const c = http2.constants; const s = Status; const errorCodeMapping = { - [c.NGHTTP2_NO_ERROR]: s.OK, + [c.NGHTTP2_NO_ERROR]: s.INTERNAL, [c.NGHTTP2_PROTOCOL_ERROR]: s.INTERNAL, [c.NGHTTP2_INTERNAL_ERROR]: s.INTERNAL, [c.NGHTTP2_FLOW_CONTROL_ERROR]: s.INTERNAL, [c.NGHTTP2_SETTINGS_TIMEOUT]: s.INTERNAL, - [c.NGHTTP2_STREAM_CLOSED]: s.INTERNAL, + [c.NGHTTP2_STREAM_CLOSED]: null, [c.NGHTTP2_FRAME_SIZE_ERROR]: s.INTERNAL, [c.NGHTTP2_REFUSED_STREAM]: s.UNAVAILABLE, [c.NGHTTP2_CANCEL]: s.CANCELLED, @@ -124,23 +124,27 @@ describe('CallStream', () => { const keys = Object.keys(errorCodeMapping).map(key => Number(key)); keys.forEach((key) => { const value = errorCodeMapping[key]; - it(`for error code ${key}`, () => new Promise((resolve, reject) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); - callStream.attachHttp2Stream(http2Stream); - callStream.once('status', (status) => { - try { - assert.strictEqual(status.code, value); - resolve(); - } catch (e) { - reject(e); - } + // A null value indicates: behavior isn't specified, so skip this test. + let maybeSkip = (fn: typeof it) => value ? fn : fn.skip; + maybeSkip(it)(`for error code ${key}`, () => { + return new Promise((resolve, reject) => { + const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [] + }); + callStream.attachHttp2Stream(http2Stream); + callStream.once('status', (status) => { + try { + assert.strictEqual(status.code, value); + resolve(); + } catch (e) { + reject(e); + } + }); + http2Stream.emit('close', Number(key)); }); - http2Stream.emit('close', Number(key)); - })); + }); }); }); From adf8bf5cf4ae69d88b00c53855aca8bc53124a8e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 14 Mar 2018 22:40:30 +0100 Subject: [PATCH 0150/1899] Creating a 1.10.1-pre1 release flag, and enabling us to generate out of band releases. --- packages/grpc-native-core/build.yaml | 3 +++ packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- packages/grpc-native-core/tools/buildgen/generate_projects.sh | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 packages/grpc-native-core/build.yaml diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml new file mode 100644 index 000000000..9adadb7de --- /dev/null +++ b/packages/grpc-native-core/build.yaml @@ -0,0 +1,3 @@ +settings: + '#': Temporary override; remove when unnecessary + node_version: 1.10.1-pre1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e3bb175d3..bdc3470c6 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.0", + "version": "1.10.1-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 51df7d81d..740fcef5a 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -2,7 +2,7 @@ --- | { "name": "grpc", - "version": "${settings.version}", + "version": "${settings.get('node_version', settings.version)}", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", diff --git a/packages/grpc-native-core/tools/buildgen/generate_projects.sh b/packages/grpc-native-core/tools/buildgen/generate_projects.sh index 41a228da9..d68c467f1 100755 --- a/packages/grpc-native-core/tools/buildgen/generate_projects.sh +++ b/packages/grpc-native-core/tools/buildgen/generate_projects.sh @@ -18,4 +18,4 @@ set -e cd `dirname $0`/../.. root=`pwd` -./deps/grpc/tools/buildgen/generate_projects.sh --base=$root --templates `find templates -type f` +./deps/grpc/tools/buildgen/generate_projects.sh $root/build.yaml --base=$root --templates `find templates -type f` From 04d7704fa71c882cf085a37d5e96d098174d9c7f Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 16:08:16 -0700 Subject: [PATCH 0151/1899] Fix call credentials test and use dummy service_url --- .../src/call-credentials-filter.ts | 4 +- packages/grpc-js-core/src/call-credentials.ts | 2 +- packages/grpc-js-core/src/index.ts | 2 +- .../test/test-call-credentials.ts | 39 +++++++------------ 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index 4633ffe88..e432935b8 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -12,8 +12,8 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { } async sendMetadata(metadata: Promise): Promise { - // TODO(murgatroid99): pass real options to generateMetadata - let credsMetadata = this.credentials.generateMetadata({}); + // TODO(kjin): pass real service URL to generateMetadata + let credsMetadata = this.credentials.generateMetadata({ service_url: '' }); let resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 888e4c625..0c0f6d535 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -2,7 +2,7 @@ import {map, reduce} from 'lodash'; import {Metadata} from './metadata'; -export type CallMetadataOptions = { service_url?: string; }; +export type CallMetadataOptions = { service_url: string; }; export type CallMetadataGenerator = (options: CallMetadataOptions, cb: (err: Error|null, metadata?: Metadata) => void) => diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 4809647fb..5a3f60251 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -22,7 +22,7 @@ export const credentials = Object.assign({ */ createFromGoogleCredential: (googleCredentials: OAuth2Client): CallCredentials => { return CallCredentials.createFromMetadataGenerator((options, callback) => { - googleCredentials.getRequestMetadata(options.service_url!, (err, headers) => { + googleCredentials.getRequestMetadata(options.service_url, (err, headers) => { if (err) { callback(err); return; diff --git a/packages/grpc-js-core/test/test-call-credentials.ts b/packages/grpc-js-core/test/test-call-credentials.ts index ab516ed9b..64cfe140e 100644 --- a/packages/grpc-js-core/test/test-call-credentials.ts +++ b/packages/grpc-js-core/test/test-call-credentials.ts @@ -5,18 +5,6 @@ import {Metadata} from '../src/metadata'; // Metadata generators -function makeGenerator(props: Array): CallMetadataGenerator { - return (options: {[propName: string]: string}, cb) => { - const metadata: Metadata = new Metadata(); - props.forEach((prop) => { - if (options[prop]) { - metadata.add(prop, options[prop]); - } - }); - cb(null, metadata); - }; -} - function makeAfterMsElapsedGenerator(ms: number): CallMetadataGenerator { return (options, cb) => { const metadata = new Metadata(); @@ -25,7 +13,11 @@ function makeAfterMsElapsedGenerator(ms: number): CallMetadataGenerator { }; } -const generateFromName: CallMetadataGenerator = makeGenerator(['name']); +const generateFromServiceURL: CallMetadataGenerator = (options, cb) => { + const metadata: Metadata = new Metadata(); + metadata.add('service_url', options.service_url); + cb(null, metadata); +}; const generateWithError: CallMetadataGenerator = (options, cb) => cb(new Error()); @@ -35,16 +27,16 @@ describe('CallCredentials', () => { describe('createFromMetadataGenerator', () => { it('should accept a metadata generator', () => { assert.doesNotThrow( - () => CallCredentials.createFromMetadataGenerator(generateFromName)); + () => CallCredentials.createFromMetadataGenerator(generateFromServiceURL)); }); }); describe('compose', () => { it('should accept a CallCredentials object and return a new object', () => { const callCredentials1 = - CallCredentials.createFromMetadataGenerator(generateFromName); + CallCredentials.createFromMetadataGenerator(generateFromServiceURL); const callCredentials2 = - CallCredentials.createFromMetadataGenerator(generateFromName); + CallCredentials.createFromMetadataGenerator(generateFromServiceURL); const combinedCredentials = callCredentials1.compose(callCredentials2); assert.notEqual(combinedCredentials, callCredentials1); assert.notEqual(combinedCredentials, callCredentials2); @@ -52,9 +44,9 @@ describe('CallCredentials', () => { it('should be chainable', () => { const callCredentials1 = - CallCredentials.createFromMetadataGenerator(generateFromName); + CallCredentials.createFromMetadataGenerator(generateFromServiceURL); const callCredentials2 = - CallCredentials.createFromMetadataGenerator(generateFromName); + CallCredentials.createFromMetadataGenerator(generateFromServiceURL); assert.doesNotThrow(() => { callCredentials1.compose(callCredentials2) .compose(callCredentials2) @@ -67,14 +59,14 @@ describe('CallCredentials', () => { it('should call the function passed to createFromMetadataGenerator', async () => { const callCredentials = - CallCredentials.createFromMetadataGenerator(generateFromName); + CallCredentials.createFromMetadataGenerator(generateFromServiceURL); let metadata: Metadata; try { - metadata = await callCredentials.generateMetadata({name: 'foo'}); + metadata = await callCredentials.generateMetadata({service_url: 'foo'}); } catch (err) { throw err; } - assert.deepEqual(metadata.get('name'), ['foo']); + assert.deepEqual(metadata.get('service_url'), ['foo']); }); it('should emit an error if the associated metadataGenerator does', @@ -83,7 +75,7 @@ describe('CallCredentials', () => { CallCredentials.createFromMetadataGenerator(generateWithError); let metadata: Metadata|null = null; try { - metadata = await callCredentials.generateMetadata({}); + metadata = await callCredentials.generateMetadata({service_url: ''}); } catch (err) { assert.ok(err instanceof Error); } @@ -115,13 +107,12 @@ describe('CallCredentials', () => { expected: ['150', '200', '50', '100'] } ]; - const options = {}; // Try each test case and make sure the msElapsed field is as expected await Promise.all(testCases.map(async (testCase) => { const {credentials, expected} = testCase; let metadata: Metadata; try { - metadata = await credentials.generateMetadata(options); + metadata = await credentials.generateMetadata({service_url: ''}); } catch (err) { throw err; } From 83178b9a34ea581c5b35f5b477bb75e8137d408a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 15 Mar 2018 21:24:07 +0100 Subject: [PATCH 0152/1899] Grabbing artifacts. --- test/kokoro/windows.cfg | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/kokoro/windows.cfg b/test/kokoro/windows.cfg index 2b9d09060..c440966f7 100644 --- a/test/kokoro/windows.cfg +++ b/test/kokoro/windows.cfg @@ -17,3 +17,8 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/test/kokoro.bat" timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/reports/**/sponge_log.xml" + } +} From e2b3f31a678fa949a97183089d14695e243e4e1c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 15 Mar 2018 22:33:38 +0100 Subject: [PATCH 0153/1899] Fixing various issues with the windows junit report. --- run-tests.bat | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 08daf7963..6359dde08 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -35,18 +35,19 @@ SET FAILED=0 for %%v in (4.8.4 6.11.3 7.9.0 8.5.0) do ( nvm install %%v nvm use %%v - npm install -g npm + call npm install -g npm node -e "console.log(process.versions)" - SET JUNIT_REPORT_PATH=reports/node%%v/ + mkdir reports\node%%v + SET JUNIT_REPORT_PATH=reports/node%%v call .\node_modules\.bin\gulp clean.all || SET FAILED=1 call .\node_modules\.bin\gulp setup.windows || SET FAILED=1 call .\node_modules\.bin\gulp native.test || SET FAILED=1 ) -if %FAILED% neq 0 exit /b 1 node merge_kokoro_logs.js +if %FAILED% neq 0 exit /b 1 goto :EOF :error From 87c91ca4884e021d334c326e10e69ae566ff31e3 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Mar 2018 01:25:19 +0100 Subject: [PATCH 0154/1899] Changing to the powershell version of nvm for better support. --- install-nvm-windows.ps1 | 29 ----------------------------- run-tests.bat | 16 ++++++---------- 2 files changed, 6 insertions(+), 39 deletions(-) delete mode 100644 install-nvm-windows.ps1 diff --git a/install-nvm-windows.ps1 b/install-nvm-windows.ps1 deleted file mode 100644 index b3794055f..000000000 --- a/install-nvm-windows.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# We're going to store nvm-windows in the .\nvm directory. -$env:NVM_HOME = (Get-Item -Path ".\" -Verbose).FullName + "\nvm" - -# Switching to TLS/1.2 - see https://githubengineering.com/crypto-removal-notice/ -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - -# Downloading and unpacking nvm-windows -Invoke-WebRequest -Uri https://github.com/coreybutler/nvm-windows/releases/download/1.1.5/nvm-noinstall.zip -OutFile nvm-noinstall.zip -Add-Type -AssemblyName System.IO.Compression.FileSystem -[System.IO.Compression.ZipFile]::ExtractToDirectory("nvm-noinstall.zip", "nvm") - -$env:Path = $env:NVM_HOME + ";" + $env:Path -Out-File -Encoding "OEM" nvm\settings.txt -nvm root $env:NVM_HOME -"%*" | Out-File -Encoding "OEM" nvm\elevate.cmd diff --git a/run-tests.bat b/run-tests.bat index 6359dde08..f2924aea4 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -15,26 +15,22 @@ SET ROOT=%~dp0 cd /d %~dp0 -PowerShell -Command .\install-nvm-windows.ps1 +powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" -SET NVM_HOME=%ROOT%nvm -SET NVM_SYMLINK=%ROOT%nvm\nodejs -SET PATH=%NVM_HOME%;%NVM_SYMLINK%;%PATH% +SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% SET JOBS=8 -nvm version +call nvm version -nvm install 8.5.0 -nvm use 8.5.0 +call nvm install 8 call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4.8.4 6.11.3 7.9.0 8.5.0) do ( - nvm install %%v - nvm use %%v +for %%v in (4 6 7 8) do ( + call nvm install %%v call npm install -g npm node -e "console.log(process.versions)" From 6c35ad046c8384292bfb0929ce3b23dd29e3f901 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Mar 2018 01:33:46 +0100 Subject: [PATCH 0155/1899] Debugging info. --- run-tests.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index f2924aea4..159145320 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -15,6 +15,8 @@ SET ROOT=%~dp0 cd /d %~dp0 +powershell -c "Get-Host" +powershell -c "$PSVersionTable" powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% From 4ed3d5452c11c6dfc5bb537a59af4f55ec36495e Mon Sep 17 00:00:00 2001 From: Olivier Boucher Date: Fri, 16 Mar 2018 11:20:20 -0400 Subject: [PATCH 0156/1899] Added a 1MB maxBuffer since the default 200kb is too small on larger proto codebases --- packages/grpc-tools/bin/protoc_plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/bin/protoc_plugin.js b/packages/grpc-tools/bin/protoc_plugin.js index fbdafff7d..19fcc740b 100755 --- a/packages/grpc-tools/bin/protoc_plugin.js +++ b/packages/grpc-tools/bin/protoc_plugin.js @@ -32,7 +32,7 @@ var exe_ext = process.platform === 'win32' ? '.exe' : ''; var plugin = path.resolve(__dirname, 'grpc_node_plugin' + exe_ext); -var child_process = execFile(plugin, process.argv.slice(2), {encoding: 'buffer'}, function(error, stdout, stderr) { +var child_process = execFile(plugin, process.argv.slice(2), {encoding: 'buffer', maxBuffer: 1024 * 1000}, function(error, stdout, stderr) { if (error) { throw error; } From 08b39b5991e69e70788412b982b3a2572e1cd5b0 Mon Sep 17 00:00:00 2001 From: Colby Blair Date: Fri, 16 Mar 2018 09:58:53 -0600 Subject: [PATCH 0157/1899] FIX-MISSING-FILE adding error handling for missing files on load --- package.json | 2 +- packages/grpc-native-core/index.js | 5 +++++ packages/grpc-native-core/package.json | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 5310e7f5c..8cab5dcb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc-js-repository", - "version": "0.1.0", + "version": "0.1.1", "description": "Dummy package for the grpc-node repository", "private": true, "keywords": [], diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 30a6ff3c2..b7deb73b7 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -143,6 +143,11 @@ exports.load = function load(filename, format, options) { } finally { ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal; } + + if (!builder) { + throw new Error('Could not load file "' + filename + '"'); + } + return loadObject(builder.ns, options); }; diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 3eaa3a83f..a3e3ce2be 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.0-dev", + "version": "1.10.1-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From cc02d6550ada6dd2f89620d2e296b4288012ce68 Mon Sep 17 00:00:00 2001 From: Colby Blair Date: Fri, 16 Mar 2018 10:38:18 -0600 Subject: [PATCH 0158/1899] FIX-MISSING-FILE revert package versions bumps --- package.json | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 8cab5dcb9..5310e7f5c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "grpc-js-repository", - "version": "0.1.1", + "version": "0.1.0", "description": "Dummy package for the grpc-node repository", "private": true, "keywords": [], diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index a3e3ce2be..3eaa3a83f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.1-dev", + "version": "1.10.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 7aaeafceb4c4b24fa170d75aab0075cb5a45995c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Mar 2018 18:59:56 +0100 Subject: [PATCH 0159/1899] Checking node version during tests to see if nvm worked properly. --- run-tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-tests.sh b/run-tests.sh index 5df881864..1444158bd 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -53,6 +53,8 @@ do mkdir -p "reports/node$version" + node -e 'process.exit(process.version.startsWith("v'$version'") ? 0 : -1)' + # Install dependencies and link packages together. ./node_modules/.bin/gulp clean.all ./node_modules/.bin/gulp setup From bccd79e71ed8823036ae8ece520bcd8311fcc16e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Mar 2018 20:17:22 +0100 Subject: [PATCH 0160/1899] Windows portion. --- run-tests.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index 6359dde08..547899e75 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -41,6 +41,8 @@ for %%v in (4.8.4 6.11.3 7.9.0 8.5.0) do ( mkdir reports\node%%v SET JUNIT_REPORT_PATH=reports/node%%v + node -e "process.exit(process.version.startsWith('v%%v') ? 0 : -1)" || goto :error + call .\node_modules\.bin\gulp clean.all || SET FAILED=1 call .\node_modules\.bin\gulp setup.windows || SET FAILED=1 call .\node_modules\.bin\gulp native.test || SET FAILED=1 From d14b38e02233d192f786604baa8a6bf5f5daae8d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Mar 2018 09:40:59 -0700 Subject: [PATCH 0161/1899] Pure JS: Pass real service_url to call credentials --- .../src/call-credentials-filter.ts | 20 ++++++++-- packages/grpc-js-core/src/call-stream.ts | 5 +++ packages/grpc-js-core/src/channel.ts | 38 ++++++++++--------- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index e432935b8..444841b7d 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -7,13 +7,27 @@ import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; export class CallCredentialsFilter extends BaseFilter implements Filter { - constructor(private readonly credentials: CallCredentials) { + private serviceUrl: string; + constructor( + private readonly channel: Http2Channel, + private readonly host: string, + private readonly path: string) { super(); + let splitPath: string[] = path.split('/'); + let serviceName: string = ''; + /* The standard path format is "/{serviceName}/{methodName}", so if we split + * by '/', the first item should be empty and the second should be the + * service name */ + if (splitPath.length >= 2) { + serviceName = splitPath[1]; + } + /* Currently, call credentials are only allowed on HTTPS connections, so we + * can assume that the scheme is "https" */ + this.serviceUrl = `https://${host}/${serviceName}`; } async sendMetadata(metadata: Promise): Promise { - // TODO(kjin): pass real service URL to generateMetadata - let credsMetadata = this.credentials.generateMetadata({ service_url: '' }); + let credsMetadata = this.credentials.generateMetadata({ service_url: serviceUrl }); let resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 3a403d681..00a36a7c3 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -17,6 +17,7 @@ export interface CallStreamOptions { deadline: Deadline; credentials: CallCredentials; flags: number; + host: string; } export type CallOptions = Partial; @@ -355,6 +356,10 @@ export class Http2CallStream extends Duplex implements CallStream { throw new Error('Not yet implemented'); } + getMethod(): string { + return this.methodName; + } + _read(size: number) { if (this.http2Stream === null) { this.pendingRead = true; diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index a4d040236..a041c720d 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -82,7 +82,8 @@ export interface Channel extends EventEmitter { export class Http2Channel extends EventEmitter implements Channel { private readonly userAgent: string; - private readonly authority: url.URL; + private readonly target: url.URL; + private readonly defaultAuthority: string; private connectivityState: ConnectivityState = ConnectivityState.IDLE; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ @@ -146,7 +147,7 @@ export class Http2Channel extends EventEmitter implements Channel { let subChannel: http2.ClientHttp2Session; let secureContext = this.credentials.getSecureContext(); if (secureContext === null) { - subChannel = http2.connect(this.authority); + subChannel = http2.connect(this.target); } else { const connectionOptions: http2.SecureClientSessionOptions = { secureContext, @@ -161,7 +162,7 @@ export class Http2Channel extends EventEmitter implements Channel { } connectionOptions.servername = sslTargetNameOverride; } - subChannel = http2.connect(this.authority, connectionOptions); + subChannel = http2.connect(this.target, connectionOptions); } this.subChannel = subChannel; let now = new Date(); @@ -195,9 +196,15 @@ export class Http2Channel extends EventEmitter implements Channel { private readonly options: Partial) { super(); if (credentials.getSecureContext() === null) { - this.authority = new url.URL(`http://${address}`); + this.target = new url.URL(`http://${address}`); } else { - this.authority = new url.URL(`https://${address}`); + this.target = new url.URL(`https://${address}`); + } + // TODO(murgatroid99): Add more centralized handling of channel options + if (this.options['grpc.default_authority']) { + this.defaultAuthority = this.options['grpc.default_authority']; + } else { + this.defaultAuthority = this.target.host; } this.filterStackFactory = new FilterStackFactory([ new CompressionFilterFactory(this), @@ -220,20 +227,16 @@ export class Http2Channel extends EventEmitter implements Channel { } private startHttp2Stream( - methodName: string, stream: Http2CallStream, metadata: Metadata) { + authority: string, + methodName: string, + stream: Http2CallStream, + metadata: Metadata) { let finalMetadata: Promise = stream.filterStack.sendMetadata(Promise.resolve(metadata.clone())); Promise.all([finalMetadata, this.connect()]) .then(([metadataValue]) => { let headers = metadataValue.toHttp2Headers(); - let host: string; - // TODO(murgatroid99): Add more centralized handling of channel options - if (this.options['grpc.default_authority']) { - host = this.options['grpc.default_authority'] as string; - } else { - host = this.authority.hostname; - } - headers[HTTP2_HEADER_AUTHORITY] = host; + headers[HTTP2_HEADER_AUTHORITY] = authority; headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; headers[HTTP2_HEADER_METHOD] = 'POST'; @@ -249,7 +252,7 @@ export class Http2Channel extends EventEmitter implements Channel { /* In this case, we lost the connection while finalizing * metadata. That should be very unusual */ setImmediate(() => { - this.startHttp2Stream(methodName, stream, metadata); + this.startHttp2Stream(authority, methodName, stream, metadata); }); } }).catch((error: Error & { code: number }) => { @@ -267,11 +270,12 @@ export class Http2Channel extends EventEmitter implements Channel { let finalOptions: CallStreamOptions = { deadline: options.deadline === undefined ? Infinity : options.deadline, credentials: options.credentials || CallCredentials.createEmpty(), - flags: options.flags || 0 + flags: options.flags || 0, + host: options.host || defaultAuthority }; let stream: Http2CallStream = new Http2CallStream(methodName, finalOptions, this.filterStackFactory); - this.startHttp2Stream(methodName, stream, metadata); + this.startHttp2Stream(finalOptions.host, methodName, stream, metadata); return stream; } From ea7af809ed441721a216db4f789dde287495290c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Mar 2018 10:33:19 -0700 Subject: [PATCH 0162/1899] Fix issues reported by gts clean --- packages/grpc-js-core/src/call-credentials-filter.ts | 8 +++++--- packages/grpc-js-core/src/call-stream.ts | 6 ++++++ packages/grpc-js-core/src/channel.ts | 4 ++-- packages/grpc-js-core/test/test-call-stream.ts | 3 ++- 4 files changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index 444841b7d..737594103 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -9,7 +9,7 @@ import {Metadata} from './metadata'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; constructor( - private readonly channel: Http2Channel, + private readonly credentials: CallCredentials, private readonly host: string, private readonly path: string) { super(); @@ -27,7 +27,7 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { } async sendMetadata(metadata: Promise): Promise { - let credsMetadata = this.credentials.generateMetadata({ service_url: serviceUrl }); + let credsMetadata = this.credentials.generateMetadata({ service_url: this.serviceUrl }); let resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; @@ -43,6 +43,8 @@ export class CallCredentialsFilterFactory implements createFilter(callStream: CallStream): CallCredentialsFilter { return new CallCredentialsFilter( - this.credentials.compose(callStream.getCredentials())); + this.credentials.compose(callStream.getCredentials()), + callStream.getHost(), + callStream.getMethod()); } } diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 00a36a7c3..80962008c 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -45,6 +45,8 @@ export type CallStream = { /* If the return value is null, the call has not ended yet. Otherwise, it has * ended with the specified status */ getStatus(): StatusObject|null; + getMethod(): string; + getHost(): string; } & EmitterAugmentation1<'metadata', Metadata> & EmitterAugmentation1<'status', StatusObject> & ObjectDuplex; @@ -360,6 +362,10 @@ export class Http2CallStream extends Duplex implements CallStream { return this.methodName; } + getHost(): string { + return this.options.host; + } + _read(size: number) { if (this.http2Stream === null) { this.pendingRead = true; diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index a041c720d..8e8e38e72 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -202,7 +202,7 @@ export class Http2Channel extends EventEmitter implements Channel { } // TODO(murgatroid99): Add more centralized handling of channel options if (this.options['grpc.default_authority']) { - this.defaultAuthority = this.options['grpc.default_authority']; + this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { this.defaultAuthority = this.target.host; } @@ -271,7 +271,7 @@ export class Http2Channel extends EventEmitter implements Channel { deadline: options.deadline === undefined ? Infinity : options.deadline, credentials: options.credentials || CallCredentials.createEmpty(), flags: options.flags || 0, - host: options.host || defaultAuthority + host: options.host || this.defaultAuthority }; let stream: Http2CallStream = new Http2CallStream(methodName, finalOptions, this.filterStackFactory); diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index fb8f5b029..f3a4f6179 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -77,7 +77,8 @@ describe('CallStream', () => { const callStreamArgs = { deadline: Infinity, credentials: CallCredentials.createEmpty(), - flags: 0 + flags: 0, + host: '' }; const filterStackFactory = new FilterStackFactory([]); const message = 'eat this message'; // 16 bytes From 4e0becaf12918c2eabb867f6ae37583ff2f9db51 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 20 Mar 2018 19:28:44 +0100 Subject: [PATCH 0163/1899] Downgrading node-pre-gyp. Starting probably with https://github.com/mapbox/node-pre-gyp/pull/299, the contents of the tarballs are bloated. Rolling back to 0.7.0. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 3eaa3a83f..0a8d3f82f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -30,7 +30,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.9.0", + "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index b2da4098f..35f55b0ea 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -32,7 +32,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.9.0", + "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, "devDependencies": { From 12713655dcc8a63dc6b001515b2c620e845bd9c2 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 20 Mar 2018 19:28:44 +0100 Subject: [PATCH 0164/1899] Downgrading node-pre-gyp. Starting probably with https://github.com/mapbox/node-pre-gyp/pull/299, the contents of the tarballs are bloated. Rolling back to 0.7.0. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 86f7678b3..b8a390e69 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -30,7 +30,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.9.0", + "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 835ec91ae..98c329bff 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -32,7 +32,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.9.0", + "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, "devDependencies": { From 6c072b18595545b34a740cfb569674aaac7c9954 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 23 Mar 2018 11:18:42 -0700 Subject: [PATCH 0165/1899] Update js and protobuf package names --- packages/grpc-js-core/package.json | 2 +- packages/grpc-protobufjs/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index ffdc2b4a4..df86a9d72 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -1,5 +1,5 @@ { - "name": "@grpc/js-core", + "name": "@grpc/grpc-js", "version": "0.1.0", "description": "gRPC Library for Node - pure JS core", "homepage": "https://grpc.io/", diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index bcf53e5f9..ed02d6a8e 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,5 +1,5 @@ { - "name": "@grpc/protobufjs", + "name": "@grpc/proto-loader", "version": "0.1.0", "description": "", "main": "build/src/index.js", From a0d3d4a22c86cd089bb4e8eaa37fb812623e217e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 23 Mar 2018 11:24:56 -0700 Subject: [PATCH 0166/1899] Remove unused packages --- gulpfile.ts | 17 +--- packages/grpc-js/gulpfile.ts | 53 ----------- packages/grpc-js/package.json | 34 ------- packages/grpc-js/src/index.ts | 21 ----- packages/grpc-js/tsconfig.json | 16 ---- packages/grpc-native/gulpfile.js | 46 --------- packages/grpc-native/index.js | 22 ----- packages/grpc-native/package.json | 23 ----- packages/grpc-surface/gulpfile.js | 30 ------ packages/grpc-surface/index.js | 147 ----------------------------- packages/grpc-surface/package.json | 21 ----- 11 files changed, 5 insertions(+), 425 deletions(-) delete mode 100644 packages/grpc-js/gulpfile.ts delete mode 100644 packages/grpc-js/package.json delete mode 100644 packages/grpc-js/src/index.ts delete mode 100644 packages/grpc-js/tsconfig.json delete mode 100644 packages/grpc-native/gulpfile.js delete mode 100644 packages/grpc-native/index.js delete mode 100644 packages/grpc-native/package.json delete mode 100644 packages/grpc-surface/gulpfile.js delete mode 100644 packages/grpc-surface/index.js delete mode 100644 packages/grpc-surface/package.json diff --git a/gulpfile.ts b/gulpfile.ts index a49fac2ce..388a74f4d 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -49,11 +49,8 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { [ ['./packages/grpc-health-check/gulpfile', 'health-check'], - ['./packages/grpc-js/gulpfile', 'js'], ['./packages/grpc-js-core/gulpfile', 'js.core'], - ['./packages/grpc-native/gulpfile', 'native'], ['./packages/grpc-native-core/gulpfile', 'native.core'], - ['./packages/grpc-surface/gulpfile', 'surface'], ['./packages/grpc-protobufjs/gulpfile', 'protobuf'], ['./test/gulpfile', 'internal.test'], ].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); @@ -61,18 +58,15 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { const root = __dirname; gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.install', 'js.core.install', 'native.core.install', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); + ['js.core.install', 'native.core.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'surface.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); + ['js.core.install', 'native.core.install.windows', 'health-check.install', 'protobuf.install', 'internal.test.install']); gulp.task('lint', 'Emit linting errors in source and test files', ['js.core.lint', 'native.core.lint']); -gulp.task('build', 'Build packages', ['js.compile', 'js.core.compile', 'native.core.build', 'protobuf.compile']); - -gulp.task('link.core', 'Add links to core packages without rebuilding', - ['js.link.add', 'native.link.add']); +gulp.task('build', 'Build packages', ['js.core.compile', 'native.core.build', 'protobuf.compile']); gulp.task('link.surface', 'Link to surface packages', ['health-check.link.add']); @@ -81,8 +75,7 @@ gulp.task('link', 'Link together packages', (callback) => { /** * We use workarounds for linking in some modules. See npm/npm#18835 */ - runSequence('link.core', 'link.surface', - callback); + runSequence('link.surface', callback); }); gulp.task('setup', 'One-time setup for a clean repository', (callback) => { @@ -96,7 +89,7 @@ gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clea gulp.task('clean.all', 'Delete all files created by tasks', ['js.core.clean.all', 'native.core.clean.all', 'health-check.clean.all', - 'internal.test.clean.all', 'js.clean.all', 'native.clean.all', 'protobuf.clean.all']); + 'internal.test.clean.all', 'protobuf.clean.all']); gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', ['native.core.test', 'health-check.test']); diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts deleted file mode 100644 index 7e09725c2..000000000 --- a/packages/grpc-js/gulpfile.ts +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -const _gulp = require('gulp'); -const help = require('gulp-help'); - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const execa = require('execa'); -const path = require('path'); -const del = require('del'); -const linkSync = require('../../util').linkSync; - -const jsDir = __dirname; - -const execNpmVerb = (verb: string, ...args: string[]) => - execa('npm', [verb, ...args], {cwd: jsDir, stdio: 'inherit'}); -const execNpmCommand = execNpmVerb.bind(null, 'run'); - -gulp.task('clean.links', 'Delete npm links', () => { - return del([path.resolve(jsDir, 'node_modules/@grpc/js-core'), - path.resolve(jsDir, 'node_modules/@grpc/surface')]); -}); - -gulp.task('clean.all', 'Delete all files created by tasks', ['clean.links']); - -/** - * Transpiles TypeScript files in src/ to JavaScript according to the settings - * found in tsconfig.json. - */ -gulp.task('compile', 'Transpiles src/.', () => execNpmCommand('compile')); - -gulp.task('install', 'Install dependencies', () => execNpmVerb('install')); - -gulp.task('link.add', 'Link local copies of dependencies', () => { - linkSync(jsDir, './node_modules/@grpc/js-core', '../grpc-js-core'); - linkSync(jsDir, './node_modules/@grpc/surface', '../grpc-surface'); -}); diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json deleted file mode 100644 index 8486c043b..000000000 --- a/packages/grpc-js/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "@grpc/js", - "version": "1.0.0", - "description": "", - "main": "build/src/index.js", - "scripts": { - "compile": "tsc -p .", - "test": "echo \"Error: no test specified\" && exit 1", - "check": "gts check", - "clean": "gts clean", - "fix": "gts fix", - "prepare": "npm run compile", - "pretest": "npm run compile", - "posttest": "npm run check" - }, - "repository": { - "type": "git", - "url": "https://github.com/grpc/grpc-node.git" - }, - "author": "", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/grpc/grpc-node/issues" - }, - "homepage": "https://grpc.io", - "dependencies": { - "@grpc/js-core": "^0.1.0", - "@grpc/surface": "^0.1.0" - }, - "devDependencies": { - "gts": "^0.5.1", - "typescript": "~2.7.0" - } -} diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts deleted file mode 100644 index 47b866a42..000000000 --- a/packages/grpc-js/src/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -module.exports = require('@grpc/surface')(require('@grpc/js-core')); diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json deleted file mode 100644 index c47ad1de0..000000000 --- a/packages/grpc-js/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "extends": "./node_modules/gts/tsconfig-google.json", - "compilerOptions": { - "rootDir": ".", - "outDir": "build" - }, - "include": [ - "src/*.ts", - "src/**/*.ts", - "test/*.ts", - "test/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/packages/grpc-native/gulpfile.js b/packages/grpc-native/gulpfile.js deleted file mode 100644 index 37fd6af92..000000000 --- a/packages/grpc-native/gulpfile.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -const _gulp = require('gulp'); -const help = require('gulp-help'); - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const execa = require('execa'); -const path = require('path'); -const del = require('del'); -const linkSync = require('../../util').linkSync; - -const nativeDir = __dirname; - -gulp.task('clean.links', 'Delete npm links', () => { - return del([path.resolve(nativeDir, 'node_modules/grpc'), - path.resolve(nativeDir, 'node_modules/@grpc/surface')]); -}); - -gulp.task('clean.all', 'Delete all files created by tasks', - ['clean.links']); - -gulp.task('install', 'Install dependencies', () => { - return execa('npm', ['install', '--unsafe-perm'], {cwd: nativeDir, stdio: 'inherit'}); -}); - -gulp.task('link.add', 'Link local copies of dependencies', () => { - linkSync(nativeDir, './node_modules/grpc', '../grpc-native-core'); - linkSync(nativeDir, './node_modules/@grpc/surface', '../grpc-surface'); -}); diff --git a/packages/grpc-native/index.js b/packages/grpc-native/index.js deleted file mode 100644 index 692cf835b..000000000 --- a/packages/grpc-native/index.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -// TODO(mlumish): This should eventually be @grpc/native-core instead of grpc -module.exports = require('@grpc/surface')(require('grpc')); diff --git a/packages/grpc-native/package.json b/packages/grpc-native/package.json deleted file mode 100644 index d141a2f96..000000000 --- a/packages/grpc-native/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "@grpc/native", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/grpc/grpc-node.git" - }, - "author": "", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/grpc/grpc-node/issues" - }, - "homepage": "https://grpc.io", - "dependencies": { - "grpc": "^1.6.0", - "@grpc/surface": "^0.1.0" - } -} diff --git a/packages/grpc-surface/gulpfile.js b/packages/grpc-surface/gulpfile.js deleted file mode 100644 index 9089587ad..000000000 --- a/packages/grpc-surface/gulpfile.js +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -const _gulp = require('gulp'); -const help = require('gulp-help'); - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const execa = require('execa'); - -const surfaceDir = __dirname; - -gulp.task('install', 'Install surface dependencies', () => { - return execa('npm', ['install', '--unsafe-perm'], {cwd: surfaceDir, stdio: 'inherit'}); -}); diff --git a/packages/grpc-surface/index.js b/packages/grpc-surface/index.js deleted file mode 100644 index d8bcef5ec..000000000 --- a/packages/grpc-surface/index.js +++ /dev/null @@ -1,147 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -const util = require('util'); - -const _ = require('lodash'); - -module.exports = function(grpc) { - - let exports = {}; - - const Client = grpc.Client; - - function getDefaultValues(metadata, options) { - var res = {}; - res.metadata = metadata || new grpc.Metadata(); - res.options = options || {}; - return res; - } - - /** - * Map with wrappers for each type of requester function to make it use the old - * argument order with optional arguments after the callback. - * @access private - */ - var deprecated_request_wrap = { - unary: function(makeUnaryRequest) { - return function makeWrappedUnaryRequest(argument, callback, - metadata, options) { - /* jshint validthis: true */ - var opt_args = getDefaultValues(metadata, metadata); - return makeUnaryRequest.call(this, argument, opt_args.metadata, - opt_args.options, callback); - }; - }, - client_stream: function(makeServerStreamRequest) { - return function makeWrappedClientStreamRequest(callback, metadata, - options) { - /* jshint validthis: true */ - var opt_args = getDefaultValues(metadata, options); - return makeServerStreamRequest.call(this, opt_args.metadata, - opt_args.options, callback); - }; - }, - server_stream: _.identity, - bidi: _.identity - }; - - /** - * Map with short names for each of the requester maker functions. Used in - * makeClientConstructor - * @private - */ - const requester_funcs = { - unary: Client.prototype.makeUnaryRequest, - server_stream: Client.prototype.makeServerStreamRequest, - client_stream: Client.prototype.makeClientStreamRequest, - bidi: Client.prototype.makeBidiStreamRequest - }; - - /** - * Creates a constructor for a client with the given methods, as specified in - * the methods argument. The resulting class will have an instance method for - * each method in the service, which is a partial application of one of the - * [Client]{@link grpc.Client} request methods, depending on `requestSerialize` - * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` - * arguments predefined. - * @memberof grpc - * @alias grpc~makeGenericClientConstructor - * @param {grpc~ServiceDefinition} methods An object mapping method names to - * method attributes - * @param {string} serviceName The fully qualified name of the service - * @param {Object} class_options An options object. - * @return {function} New client constructor, which is a subclass of - * {@link grpc.Client}, and has the same arguments as that constructor. - */ - exports.makeClientConstructor = function(methods, serviceName, - class_options) { - if (!class_options) { - class_options = {}; - } - - function ServiceClient(address, credentials, options) { - Client.call(this, address, credentials, options); - } - - util.inherits(ServiceClient, Client); - - _.each(methods, function(attrs, name) { - var method_type; - // TODO(murgatroid99): Verify that we don't need this anymore - if (_.startsWith(name, '$')) { - throw new Error('Method names cannot start with $'); - } - if (attrs.requestStream) { - if (attrs.responseStream) { - method_type = 'bidi'; - } else { - method_type = 'client_stream'; - } - } else { - if (attrs.responseStream) { - method_type = 'server_stream'; - } else { - method_type = 'unary'; - } - } - var serialize = attrs.requestSerialize; - var deserialize = attrs.responseDeserialize; - var method_func = _.partial(requester_funcs[method_type], attrs.path, - serialize, deserialize); - if (class_options.deprecatedArgumentOrder) { - ServiceClient.prototype[name] = deprecated_request_wrap(method_func); - } else { - ServiceClient.prototype[name] = method_func; - } - // Associate all provided attributes with the method - _.assign(ServiceClient.prototype[name], attrs); - if (attrs.originalName) { - ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; - } - }); - - ServiceClient.service = methods; - - return ServiceClient; - }; - - return Object.assign(exports, grpc); -}; diff --git a/packages/grpc-surface/package.json b/packages/grpc-surface/package.json deleted file mode 100644 index 7abcfd538..000000000 --- a/packages/grpc-surface/package.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "@grpc/surface", - "version": "0.1.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "https://github.com/grpc/grpc-node.git" - }, - "author": "", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/grpc/grpc-node/issues" - }, - "dependencies": { - "lodash": "^4.17.4" - } -} From fe752be0c1f02be11ae2feb53b4e730fee9d9d42 Mon Sep 17 00:00:00 2001 From: Olivier Boucher Date: Mon, 26 Mar 2018 09:40:20 -0400 Subject: [PATCH 0167/1899] Update maxBuffer limit to 100Mib --- packages/grpc-tools/bin/protoc_plugin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/bin/protoc_plugin.js b/packages/grpc-tools/bin/protoc_plugin.js index 19fcc740b..22aa03d87 100755 --- a/packages/grpc-tools/bin/protoc_plugin.js +++ b/packages/grpc-tools/bin/protoc_plugin.js @@ -32,7 +32,7 @@ var exe_ext = process.platform === 'win32' ? '.exe' : ''; var plugin = path.resolve(__dirname, 'grpc_node_plugin' + exe_ext); -var child_process = execFile(plugin, process.argv.slice(2), {encoding: 'buffer', maxBuffer: 1024 * 1000}, function(error, stdout, stderr) { +var child_process = execFile(plugin, process.argv.slice(2), {encoding: 'buffer', maxBuffer: 1024 * 1024 * 100}, function(error, stdout, stderr) { if (error) { throw error; } From a5fb87af8713a6c3678cf7546a2f682d9278f60e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 28 Mar 2018 06:56:01 +0200 Subject: [PATCH 0168/1899] Hide symbols. Fixes #240. --- packages/grpc-native-core/binding.gyp | 3 +++ packages/grpc-native-core/templates/binding.gyp.template | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index aa4d4be65..8de8a228a 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -64,6 +64,7 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-Wno-deprecated-declarations', + '-fvisibility=hidden', ], 'ldflags': [ '-g', @@ -188,6 +189,7 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-Wno-deprecated-declarations', + '-fvisibility=hidden', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', @@ -198,6 +200,7 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-Wno-deprecated-declarations', + '-fvisibility=hidden', '-stdlib=libc++', '-std=c++11', '-Wno-error=deprecated-declarations' diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index e5eebfed5..11eb8e606 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -58,7 +58,7 @@ % for arg, prop in [('CPPFLAGS', 'cflags'), ('LDFLAGS', 'ldflags')]: % if defaults['global'].get(arg, None) is not None: '${prop}': [ - % for item in defaults['global'].get(arg).split(): + % for item in defaults['global'].get(arg).split() + (['-fvisibility=hidden'] if arg == 'CPPFLAGS' else []): '${item}', % endfor ], @@ -169,12 +169,12 @@ 'xcode_settings': { % if defaults['global'].get('CPPFLAGS', None) is not None: 'OTHER_CFLAGS': [ - % for item in defaults['global'].get('CPPFLAGS').split(): + % for item in defaults['global'].get('CPPFLAGS').split() + ['-fvisibility=hidden']: '${item}', % endfor ], 'OTHER_CPLUSPLUSFLAGS': [ - % for item in defaults['global'].get('CPPFLAGS').split(): + % for item in defaults['global'].get('CPPFLAGS').split() + ['-fvisibility=hidden']: '${item}', % endfor '-stdlib=libc++', From f5ff760bd3ba6d5ad917d8861a406281124ced66 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 28 Mar 2018 12:52:34 -0700 Subject: [PATCH 0169/1899] Add README files for new packages --- README.md | 6 ++++++ packages/grpc-js-core/README.md | 20 ++++++++++++++++++++ packages/grpc-protobufjs/README.md | 16 ++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 packages/grpc-js-core/README.md create mode 100644 packages/grpc-protobufjs/README.md diff --git a/README.md b/README.md index bd8826a83..9bcebd569 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,12 @@ This library implements the core functionality of gRPC purely in JavaScript, wit ## Other Packages +### gRPC Protobuf Loader + +Directory: [`packages/grpc-protobufjs`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-protobufjs) + +This library loads `.proto` files into objects that can be passed to the gRPC libraries. + ### gRPC Tools Directory: `packages/grpc-tools` diff --git a/packages/grpc-js-core/README.md b/packages/grpc-js-core/README.md new file mode 100644 index 000000000..054986ca0 --- /dev/null +++ b/packages/grpc-js-core/README.md @@ -0,0 +1,20 @@ +# Pure JavaScript gRPC Client + +## Installation + +Node 9.x or greater is required. + +```sh +npm install @grpc/grpc-js +``` + +## Features + + - Unary and streaming calls + - Cancellation + - Deadlines + - TLS channel credentials + - Call credentials (for auth) + - Simple reconnection + +This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package. diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md new file mode 100644 index 000000000..bf2f7f5c0 --- /dev/null +++ b/packages/grpc-protobufjs/README.md @@ -0,0 +1,16 @@ +# gRPC Protobuf Loader + +## Installation + +```sh +npm install @grpc/proto-loader +``` + +## Usage + +```js +const protoLoader = require('@grpc/proto-loader') +protoLoader.load(protoFile, options).then(packageDefinition => { + package = grpcLibrary.loadPackageDefinition(packageDefinition); +}); +``` From 704cd150851ef2118a315fccdff85f8efb740fb0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 28 Mar 2018 13:15:06 -0700 Subject: [PATCH 0170/1899] Upgrade to v1.10.1 --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 9adadb7de..7f11bfc00 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': Temporary override; remove when unnecessary - node_version: 1.10.1-pre1 + node_version: 1.10.1 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 474c59506..c06c4b1f1 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 474c5950686e3962bd339c93d27e369bf64f568f +Subproject commit c06c4b1f1b28bfbf150377252ba99fed0906a10f diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 86f7678b3..012e53b7f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.1-pre1", + "version": "1.10.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From b85cba6bb7832c15ee0402220f2b3c6b929f782a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 28 Mar 2018 13:30:45 -0700 Subject: [PATCH 0171/1899] Address comments --- packages/grpc-protobufjs/README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md index bf2f7f5c0..972d5d631 100644 --- a/packages/grpc-protobufjs/README.md +++ b/packages/grpc-protobufjs/README.md @@ -9,8 +9,11 @@ npm install @grpc/proto-loader ## Usage ```js -const protoLoader = require('@grpc/proto-loader') +const protoLoader = require('@grpc/proto-loader'); +const grpcLibrary = require('grpc'); +// OR +const grpcLibrary = require('@grpc/grpc-js'); protoLoader.load(protoFile, options).then(packageDefinition => { - package = grpcLibrary.loadPackageDefinition(packageDefinition); + const package = grpcLibrary.loadPackageDefinition(packageDefinition); }); ``` From 67dfef8ef335e91d0fb8dc02740b45c5d5cc28ca Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 20 Mar 2018 19:28:44 +0100 Subject: [PATCH 0172/1899] Downgrading node-pre-gyp. Starting probably with https://github.com/mapbox/node-pre-gyp/pull/299, the contents of the tarballs are bloated. Rolling back to 0.7.0. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 012e53b7f..555fea89b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -30,7 +30,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.9.0", + "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 835ec91ae..98c329bff 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -32,7 +32,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.9.0", + "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, "devDependencies": { From 0210f160ed78fd0419e8a3e3263d8ebc8097ad08 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 2 Apr 2018 14:35:46 -0700 Subject: [PATCH 0173/1899] Fix object lifetime and memory management problems in server code --- .../ext/channel_credentials.cc | 19 ++-- packages/grpc-native-core/ext/server.cc | 96 +++++++------------ packages/grpc-native-core/ext/server.h | 4 +- .../ext/server_credentials.cc | 24 ++--- packages/grpc-native-core/ext/util.h | 52 ++++++++++ 5 files changed, 110 insertions(+), 85 deletions(-) create mode 100644 packages/grpc-native-core/ext/util.h diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 9e87fb61b..da67f35ad 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -21,6 +21,7 @@ #include "call.h" #include "call_credentials.h" #include "channel_credentials.h" +#include "util.h" #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "grpc/support/log.h" @@ -120,33 +121,35 @@ NAN_METHOD(ChannelCredentials::New) { } NAN_METHOD(ChannelCredentials::CreateSsl) { - char *root_certs = NULL; - grpc_ssl_pem_key_cert_pair key_cert_pair = {NULL, NULL}; + StringOrNull root_certs; + StringOrNull private_key; + StringOrNull cert_chain; if (::node::Buffer::HasInstance(info[0])) { - root_certs = ::node::Buffer::Data(info[0]); + root_certs.assign(info[0]); } else if (!(info[0]->IsNull() || info[0]->IsUndefined())) { return Nan::ThrowTypeError("createSsl's first argument must be a Buffer"); } if (::node::Buffer::HasInstance(info[1])) { - key_cert_pair.private_key = ::node::Buffer::Data(info[1]); + private_key.assign(info[1]); } else if (!(info[1]->IsNull() || info[1]->IsUndefined())) { return Nan::ThrowTypeError( "createSSl's second argument must be a Buffer if provided"); } if (::node::Buffer::HasInstance(info[2])) { - key_cert_pair.cert_chain = ::node::Buffer::Data(info[2]); + cert_chain.assign(info[2]); } else if (!(info[2]->IsNull() || info[2]->IsUndefined())) { return Nan::ThrowTypeError( "createSSl's third argument must be a Buffer if provided"); } - if ((key_cert_pair.private_key == NULL) != - (key_cert_pair.cert_chain == NULL)) { + grpc_ssl_pem_key_cert_pair key_cert_pair = {private_key.get(), + cert_chain.get()}; + if (private_key.isAssigned() != cert_chain.isAssigned()) { return Nan::ThrowError( "createSsl's second and third arguments must be" " provided or omitted together"); } grpc_channel_credentials *creds = grpc_ssl_credentials_create( - root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair, + root_certs.get(), private_key.isAssigned() ? &key_cert_pair : NULL, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); diff --git a/packages/grpc-native-core/ext/server.cc b/packages/grpc-native-core/ext/server.cc index d5b4763b3..aa56b5e59 100644 --- a/packages/grpc-native-core/ext/server.cc +++ b/packages/grpc-native-core/ext/server.cc @@ -62,28 +62,31 @@ using v8::Value; Nan::Callback *Server::constructor; Persistent Server::fun_tpl; -static Callback *shutdown_callback = NULL; +static Persistent shutdown_cb; class ServerShutdownOp : public Op { public: - ServerShutdownOp(grpc_server *server) : server(server) {} + ServerShutdownOp(Server *server) : server(server) {} ~ServerShutdownOp() {} - Local GetNodeValue() const { return Nan::Null(); } + Local GetNodeValue() const { + EscapableHandleScope scope; + return scope.Escape(server->handle()); + } bool ParseOp(Local value, grpc_op *out) { return true; } bool IsFinalOp() { return false; } void OnComplete(bool success) { - /* Because cancel_all_calls was called, we assume that shutdown_and_notify - completes successfully */ - grpc_server_destroy(server); + if (success) { + server->FinishShutdown(); + } } - grpc_server *server; + Server *server; protected: - std::string GetTypeString() const { return "shutdown"; } + std::string GetTypeString() const { return "try_shutdown"; } }; class NewCallOp : public Op { @@ -131,35 +134,17 @@ class NewCallOp : public Op { std::string GetTypeString() const { return "new_call"; } }; -class TryShutdownOp : public Op { - public: - TryShutdownOp(Server *server, Local server_value) : server(server) { - server_persist.Reset(server_value); - } - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(Nan::New(server_persist)); - } - bool ParseOp(Local value, grpc_op *out) { return true; } - bool IsFinalOp() { return false; } - void OnComplete(bool success) { - if (success) { - server->DestroyWrappedServer(); - } +NAN_METHOD(ShutdownCallback) { + HandleScope scope; + if (!info[0]->IsNull()) { + return Nan::ThrowError("forceShutdown failed somehow"); } +} - protected: - std::string GetTypeString() const { return "try_shutdown"; } - - private: - Server *server; - Nan::Persistent> - server_persist; -}; - -Server::Server(grpc_server *server) : wrapped_server(server) {} +Server::Server(grpc_server *server) : + wrapped_server(server), is_shutdown(false) {} -Server::~Server() { this->ShutdownServer(); } +Server::~Server() { grpc_server_destroy(this->wrapped_server); } void Server::Init(Local exports) { HandleScope scope; @@ -175,6 +160,9 @@ void Server::Init(Local exports) { Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set(exports, Nan::New("Server").ToLocalChecked(), ctr); constructor = new Callback(ctr); + Local shutdown_tpl = + Nan::New(ShutdownCallback); + shutdown_cb.Reset(Nan::GetFunction(shutdown_tpl).ToLocalChecked()); } bool Server::HasInstance(Local val) { @@ -182,40 +170,25 @@ bool Server::HasInstance(Local val) { return Nan::New(fun_tpl)->HasInstance(val); } -void Server::DestroyWrappedServer() { - if (this->wrapped_server != NULL) { - grpc_server_destroy(this->wrapped_server); - this->wrapped_server = NULL; - } -} - -NAN_METHOD(ServerShutdownCallback) { - if (!info[0]->IsNull()) { - return Nan::ThrowError("forceShutdown failed somehow"); - } +void Server::FinishShutdown() { + is_shutdown = true; + running_self_ref.Reset(); } void Server::ShutdownServer() { Nan::HandleScope scope; - if (this->wrapped_server != NULL) { - if (shutdown_callback == NULL) { - Local callback_tpl = - Nan::New(ServerShutdownCallback); - shutdown_callback = - new Callback(Nan::GetFunction(callback_tpl).ToLocalChecked()); - } - - ServerShutdownOp *op = new ServerShutdownOp(this->wrapped_server); + if (!this->is_shutdown) { + Callback *shutdown_callback = + new Callback(Nan::New(shutdown_cb)); + ServerShutdownOp *op = new ServerShutdownOp(this); unique_ptr ops(new OpVec()); ops->push_back(unique_ptr(op)); grpc_server_shutdown_and_notify( this->wrapped_server, GetCompletionQueue(), - new struct tag(new Callback(**shutdown_callback), ops.release(), NULL, - Nan::Null())); + new struct tag(shutdown_callback, ops.release(), NULL, Nan::Null())); grpc_server_cancel_all_calls(this->wrapped_server); CompletionQueueNext(); - this->wrapped_server = NULL; } } @@ -304,6 +277,7 @@ NAN_METHOD(Server::Start) { return Nan::ThrowTypeError("start can only be called on a Server"); } Server *server = ObjectWrap::Unwrap(info.This()); + server->running_self_ref.Reset(info.This()); grpc_server_start(server->wrapped_server); } @@ -316,13 +290,7 @@ NAN_METHOD(Server::TryShutdown) { return Nan::ThrowError("tryShutdown's argument must be a callback"); } Server *server = ObjectWrap::Unwrap(info.This()); - if (server->wrapped_server == NULL) { - // Server is already shut down. Call callback immediately. - Nan::Callback callback(info[0].As()); - callback.Call(0, {}); - return; - } - TryShutdownOp *op = new TryShutdownOp(server, info.This()); + ServerShutdownOp *op = new ServerShutdownOp(server); unique_ptr ops(new OpVec()); ops->push_back(unique_ptr(op)); grpc_server_shutdown_and_notify( diff --git a/packages/grpc-native-core/ext/server.h b/packages/grpc-native-core/ext/server.h index 66b3ac526..188e7054c 100644 --- a/packages/grpc-native-core/ext/server.h +++ b/packages/grpc-native-core/ext/server.h @@ -38,7 +38,7 @@ class Server : public Nan::ObjectWrap { JavaScript constructor */ static bool HasInstance(v8::Local val); - void DestroyWrappedServer(); + void FinishShutdown(); private: explicit Server(grpc_server *server); @@ -58,9 +58,11 @@ class Server : public Nan::ObjectWrap { static NAN_METHOD(ForceShutdown); static Nan::Callback *constructor; static Nan::Persistent fun_tpl; + Nan::Persistent running_self_ref; grpc_server *wrapped_server; grpc_completion_queue *shutdown_queue; + bool is_shutdown; }; } // namespace node diff --git a/packages/grpc-native-core/ext/server_credentials.cc b/packages/grpc-native-core/ext/server_credentials.cc index b7fa47884..7172a1656 100644 --- a/packages/grpc-native-core/ext/server_credentials.cc +++ b/packages/grpc-native-core/ext/server_credentials.cc @@ -16,12 +16,14 @@ * */ +#include #include #include "grpc/grpc.h" #include "grpc/grpc_security.h" #include "grpc/support/log.h" #include "server_credentials.h" +#include "util.h" namespace grpc { namespace node { @@ -119,9 +121,9 @@ NAN_METHOD(ServerCredentials::New) { NAN_METHOD(ServerCredentials::CreateSsl) { Nan::HandleScope scope; - char *root_certs = NULL; + StringOrNull root_certs; if (::node::Buffer::HasInstance(info[0])) { - root_certs = ::node::Buffer::Data(info[0]); + root_certs.assign(info[0]); } else if (!(info[0]->IsNull() || info[0]->IsUndefined())) { return Nan::ThrowTypeError( "createSSl's first argument must be a Buffer if provided"); @@ -145,36 +147,34 @@ NAN_METHOD(ServerCredentials::CreateSsl) { } Local pair_list = Local::Cast(info[1]); uint32_t key_cert_pair_count = pair_list->Length(); - grpc_ssl_pem_key_cert_pair *key_cert_pairs = - new grpc_ssl_pem_key_cert_pair[key_cert_pair_count]; - + grpc_ssl_pem_key_cert_pair key_cert_pairs[key_cert_pair_count]; + StringOrNull key_strings[key_cert_pair_count]; + StringOrNull cert_strings[key_cert_pair_count]; Local key_key = Nan::New("private_key").ToLocalChecked(); Local cert_key = Nan::New("cert_chain").ToLocalChecked(); for (uint32_t i = 0; i < key_cert_pair_count; i++) { Local pair_val = Nan::Get(pair_list, i).ToLocalChecked(); if (!pair_val->IsObject()) { - delete[] key_cert_pairs; return Nan::ThrowTypeError("Key/cert pairs must be objects"); } Local pair_obj = Nan::To(pair_val).ToLocalChecked(); Local maybe_key = Nan::Get(pair_obj, key_key).ToLocalChecked(); Local maybe_cert = Nan::Get(pair_obj, cert_key).ToLocalChecked(); if (!::node::Buffer::HasInstance(maybe_key)) { - delete[] key_cert_pairs; return Nan::ThrowTypeError("private_key must be a Buffer"); } if (!::node::Buffer::HasInstance(maybe_cert)) { - delete[] key_cert_pairs; return Nan::ThrowTypeError("cert_chain must be a Buffer"); } - key_cert_pairs[i].private_key = ::node::Buffer::Data(maybe_key); - key_cert_pairs[i].cert_chain = ::node::Buffer::Data(maybe_cert); + key_strings[i].assign(maybe_key); + cert_strings[i].assign(maybe_cert); + key_cert_pairs[i].private_key = key_strings[i].get(); + key_cert_pairs[i].cert_chain = cert_strings[i].get(); } grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex( - root_certs, key_cert_pairs, key_cert_pair_count, + root_certs.get(), key_cert_pairs, key_cert_pair_count, client_certificate_request, NULL); - delete[] key_cert_pairs; if (creds == NULL) { info.GetReturnValue().SetNull(); } else { diff --git a/packages/grpc-native-core/ext/util.h b/packages/grpc-native-core/ext/util.h new file mode 100644 index 000000000..c481922aa --- /dev/null +++ b/packages/grpc-native-core/ext/util.h @@ -0,0 +1,52 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef NET_GRPC_NODE_UTIL_H_ +#define NET_GRPC_NODE_UTIL_H_ + +#include +#include + +#include + +namespace grpc { +namespace node { + +class StringOrNull { + public: + StringOrNull() : assigned(false) { } + void assign(v8::Local buffer) { + str_ = std::string(::node::Buffer::Data(buffer), + ::node::Buffer::Length(buffer)); + assigned = true; + } + const char * get() { + return assigned ? str_.c_str() : NULL; + } + bool isAssigned() { + return assigned; + } + private: + std::string str_; + bool assigned; +}; + +} // namespace node +} // namespace grpc + +#endif // NET_GRPC_NODE_UTIL_H_ From 4ba954a3eb4d74a51c32d6db3b5c02453a842f30 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 3 Apr 2018 02:00:25 +0200 Subject: [PATCH 0174/1899] Build failures on Windows should be noticed. --- tools/release/kokoro.bat | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/release/kokoro.bat b/tools/release/kokoro.bat index e86e01bd7..2726d338a 100644 --- a/tools/release/kokoro.bat +++ b/tools/release/kokoro.bat @@ -22,7 +22,11 @@ git submodule foreach --recursive git submodule update --init set ARTIFACTS_OUT=artifacts cd packages\grpc-native-core -call tools\run_tests\artifacts\build_artifact_node.bat +call tools\run_tests\artifacts\build_artifact_node.bat || goto :error cd ..\.. move packages\grpc-native-core\artifacts . +goto :EOF + +:error +exit /b 1 From 265c8fcfc8360dae2611e88b8a53be136b802dbb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 2 Apr 2018 18:27:29 -0700 Subject: [PATCH 0175/1899] Fix incorrect C++ usage --- packages/grpc-native-core/ext/server_credentials.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/ext/server_credentials.cc b/packages/grpc-native-core/ext/server_credentials.cc index 7172a1656..256a6aaf0 100644 --- a/packages/grpc-native-core/ext/server_credentials.cc +++ b/packages/grpc-native-core/ext/server_credentials.cc @@ -16,6 +16,8 @@ * */ +#include + #include #include @@ -148,8 +150,8 @@ NAN_METHOD(ServerCredentials::CreateSsl) { Local pair_list = Local::Cast(info[1]); uint32_t key_cert_pair_count = pair_list->Length(); grpc_ssl_pem_key_cert_pair key_cert_pairs[key_cert_pair_count]; - StringOrNull key_strings[key_cert_pair_count]; - StringOrNull cert_strings[key_cert_pair_count]; + std::vector key_strings(key_cert_pair_count); + std::vector cert_strings(key_cert_pair_count); Local key_key = Nan::New("private_key").ToLocalChecked(); Local cert_key = Nan::New("cert_chain").ToLocalChecked(); From 05007312a74c82bfe812bf6777e763590e3bbd77 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 3 Apr 2018 09:50:36 -0700 Subject: [PATCH 0176/1899] Replace another variable length stack array with a vector --- packages/grpc-native-core/ext/server_credentials.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/ext/server_credentials.cc b/packages/grpc-native-core/ext/server_credentials.cc index 256a6aaf0..1ce86632c 100644 --- a/packages/grpc-native-core/ext/server_credentials.cc +++ b/packages/grpc-native-core/ext/server_credentials.cc @@ -149,7 +149,7 @@ NAN_METHOD(ServerCredentials::CreateSsl) { } Local pair_list = Local::Cast(info[1]); uint32_t key_cert_pair_count = pair_list->Length(); - grpc_ssl_pem_key_cert_pair key_cert_pairs[key_cert_pair_count]; + std::vector key_cert_pairs(key_cert_pair_count); std::vector key_strings(key_cert_pair_count); std::vector cert_strings(key_cert_pair_count); Local key_key = Nan::New("private_key").ToLocalChecked(); @@ -175,7 +175,7 @@ NAN_METHOD(ServerCredentials::CreateSsl) { key_cert_pairs[i].cert_chain = cert_strings[i].get(); } grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex( - root_certs.get(), key_cert_pairs, key_cert_pair_count, + root_certs.get(), key_cert_pairs.data(), key_cert_pair_count, client_certificate_request, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); From c41a6813ae115ca5c5d544867a9db54dc2c81eca Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 3 Apr 2018 10:57:04 -0700 Subject: [PATCH 0177/1899] Start server after adding server ports --- packages/grpc-native-core/ext/server.h | 1 - packages/grpc-native-core/test/server_test.js | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/ext/server.h b/packages/grpc-native-core/ext/server.h index 188e7054c..6637e0898 100644 --- a/packages/grpc-native-core/ext/server.h +++ b/packages/grpc-native-core/ext/server.h @@ -61,7 +61,6 @@ class Server : public Nan::ObjectWrap { Nan::Persistent running_self_ref; grpc_server *wrapped_server; - grpc_completion_queue *shutdown_queue; bool is_shutdown; }; diff --git a/packages/grpc-native-core/test/server_test.js b/packages/grpc-native-core/test/server_test.js index 5351c138a..b06236efb 100644 --- a/packages/grpc-native-core/test/server_test.js +++ b/packages/grpc-native-core/test/server_test.js @@ -62,6 +62,10 @@ describe('server', function() { before(function() { server = new grpc.Server(); }); + after(function() { + server.start(); + server.forceShutdown(); + }); it('should bind to an unused port', function() { var port; assert.doesNotThrow(function() { @@ -85,12 +89,6 @@ describe('server', function() { assert(port > 0); }); }); - describe('addSecureHttp2Port', function() { - var server; - before(function() { - server = new grpc.Server(); - }); - }); describe('start', function() { var server; before(function() { From 4bfa1430efe486883e97eb693c2bf9ee85c26b42 Mon Sep 17 00:00:00 2001 From: Ali Ijaz Sheikh Date: Tue, 20 Mar 2018 16:48:20 -0700 Subject: [PATCH 0178/1899] fix: avoid using deprecated Nan APIs Starting with Nan 2.9.x certain Nan::Callback::Call APIs are deprecated. Instead there are mechanisms in place that allow native modules to preserve async context across async calls. --- packages/grpc-native-core/ext/call.cc | 11 ++++++++--- packages/grpc-native-core/ext/call.h | 1 + packages/grpc-native-core/ext/call_credentials.cc | 9 ++++----- packages/grpc-native-core/ext/call_credentials.h | 15 +++++++++++++++ packages/grpc-native-core/ext/node_grpc.cc | 4 +++- packages/grpc-native-core/package.json | 2 +- 6 files changed, 32 insertions(+), 10 deletions(-) diff --git a/packages/grpc-native-core/ext/call.cc b/packages/grpc-native-core/ext/call.cc index 26095a78f..f73a70d25 100644 --- a/packages/grpc-native-core/ext/call.cc +++ b/packages/grpc-native-core/ext/call.cc @@ -446,13 +446,18 @@ class ServerCloseResponseOp : public Op { }; tag::tag(Callback *callback, OpVec *ops, Call *call, Local call_value) - : callback(callback), ops(ops), call(call) { + : callback(callback), + async_resource(NULL), + ops(ops), + call(call) { HandleScope scope; + async_resource = new Nan::AsyncResource("grpc:tag"); // Needs handle scope. call_persist.Reset(call_value); } tag::~tag() { delete callback; + delete async_resource; delete ops; } @@ -468,10 +473,10 @@ void CompleteTag(void *tag, const char *error_message) { Nan::Set(tag_obj, op_ptr->GetOpType(), op_ptr->GetNodeValue()); } Local argv[] = {Nan::Null(), tag_obj}; - callback->Call(2, argv); + callback->Call(2, argv, tag_struct->async_resource); } else { Local argv[] = {Nan::Error(error_message)}; - callback->Call(1, argv); + callback->Call(1, argv, tag_struct->async_resource); } bool success = (error_message == NULL); bool is_final_op = false; diff --git a/packages/grpc-native-core/ext/call.h b/packages/grpc-native-core/ext/call.h index 50248c0bc..5bf83a42a 100644 --- a/packages/grpc-native-core/ext/call.h +++ b/packages/grpc-native-core/ext/call.h @@ -103,6 +103,7 @@ struct tag { v8::Local call_value); ~tag(); Nan::Callback *callback; + Nan::AsyncResource *async_resource; OpVec *ops; Call *call; Nan::Persistent> diff --git a/packages/grpc-native-core/ext/call_credentials.cc b/packages/grpc-native-core/ext/call_credentials.cc index 2b1cb35f2..a4f8bb2ce 100644 --- a/packages/grpc-native-core/ext/call_credentials.cc +++ b/packages/grpc-native-core/ext/call_credentials.cc @@ -233,7 +233,7 @@ NAUV_WORK_CB(SendPluginCallback) { // Get Local from Nan::Callback* **plugin_callback}; Nan::Callback *callback = state->callback; - callback->Call(argc, argv); + callback->Call(argc, argv, data->async_resource); delete data; } } @@ -245,11 +245,10 @@ int plugin_get_metadata( grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX], size_t *num_creds_md, grpc_status_code *status, const char **error_details) { + HandleScope scope; plugin_state *p_state = reinterpret_cast(state); - plugin_callback_data *data = new plugin_callback_data; - data->service_url = context.service_url; - data->cb = cb; - data->user_data = user_data; + plugin_callback_data *data = + new plugin_callback_data(context.service_url, cb, user_data); uv_mutex_lock(&p_state->plugin_mutex); p_state->pending_callbacks->push(data); diff --git a/packages/grpc-native-core/ext/call_credentials.h b/packages/grpc-native-core/ext/call_credentials.h index 323eb4f26..9eb893403 100644 --- a/packages/grpc-native-core/ext/call_credentials.h +++ b/packages/grpc-native-core/ext/call_credentials.h @@ -62,9 +62,24 @@ class CallCredentials : public Nan::ObjectWrap { /* Auth metadata plugin functionality */ typedef struct plugin_callback_data { + plugin_callback_data(const char *service_url_, + grpc_credentials_plugin_metadata_cb cb_, + void *user_data_) + : service_url(service_url_), + cb(cb_), + user_data(user_data_), + async_resource(NULL) { + Nan::HandleScope scope; + async_resource = new Nan::AsyncResource("grpc:plugin_callback_data"); + } + ~plugin_callback_data() { + delete async_resource; + } + const char *service_url; grpc_credentials_plugin_metadata_cb cb; void *user_data; + Nan::AsyncResource *async_resource; } plugin_callback_data; typedef struct plugin_state { diff --git a/packages/grpc-native-core/ext/node_grpc.cc b/packages/grpc-native-core/ext/node_grpc.cc index 6ba5f1a1e..1ecd952d7 100644 --- a/packages/grpc-native-core/ext/node_grpc.cc +++ b/packages/grpc-native-core/ext/node_grpc.cc @@ -57,6 +57,7 @@ typedef struct log_args { typedef struct logger_state { Nan::Callback *callback; + Nan::AsyncResource *async_resource; std::queue *pending_args; uv_mutex_t mutex; uv_async_t async; @@ -202,7 +203,7 @@ NAUV_WORK_CB(LogMessagesCallback) { .ToLocalChecked(); const int argc = 5; Local argv[argc] = {file, line, severity, message, timestamp}; - grpc_logger_state.callback->Call(argc, argv); + grpc_logger_state.callback->Call(argc, argv, grpc_logger_state.async_resource); delete[] arg->core_args.message; delete arg; } @@ -252,6 +253,7 @@ NAN_METHOD(SetDefaultLoggerCallback) { grpc_logger_state.logger_set = true; } grpc_logger_state.callback = new Nan::Callback(info[0].As()); + grpc_logger_state.async_resource = new Nan::AsyncResource("grpc:logger"); } NAN_METHOD(SetLogVerbosity) { diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 0a8d3f82f..4b378eb1f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,7 +29,7 @@ ], "dependencies": { "lodash": "^4.15.0", - "nan": "^2.0.0", + "nan": "^2.10.0", "node-pre-gyp": "0.7.0", "protobufjs": "^5.0.0" }, From 434e6c45c13c51b6f859293bf0ae4f4612430e86 Mon Sep 17 00:00:00 2001 From: Kelly Campbell Date: Tue, 3 Apr 2018 19:58:42 -0400 Subject: [PATCH 0179/1899] Update error msg for Protobuf.js detection from 'protobufjs_version' to 'protobufjsVersion' --- packages/grpc-native-core/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index b7deb73b7..7f67422cd 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -81,7 +81,7 @@ exports.loadObject = function loadObject(value, options) { protobufjsVersion = 5; } else { var error_message = 'Could not detect ProtoBuf.js version. Please ' + - 'specify the version number with the "protobufjs_version" option'; + 'specify the version number with the "protobufjsVersion" option'; throw new Error(error_message); } } else { From 4f9ce64f8b5d508afc70f07fc2ad8f2f19a794b5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 3 Apr 2018 13:40:27 -0700 Subject: [PATCH 0180/1899] Update master to v1.11.0-dev --- packages/grpc-native-core/binding.gyp | 99 ++++++++++++++++++++------ packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 78 insertions(+), 25 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 8de8a228a..d2a415116 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -40,6 +40,7 @@ 'Release': { 'cflags': [ '-O2', + '-Wframe-larger-than=16384', ], 'defines': [ 'NDEBUG', @@ -291,7 +292,6 @@ 'deps/grpc/third_party/boringssl/crypto/cpu-intel.c', 'deps/grpc/third_party/boringssl/crypto/cpu-ppc64le.c', 'deps/grpc/third_party/boringssl/crypto/crypto.c', - 'deps/grpc/third_party/boringssl/crypto/curve25519/curve25519.c', 'deps/grpc/third_party/boringssl/crypto/curve25519/spake25519.c', 'deps/grpc/third_party/boringssl/crypto/curve25519/x25519-x86_64.c', 'deps/grpc/third_party/boringssl/crypto/dh/check.c', @@ -477,6 +477,7 @@ 'deps/grpc/third_party/boringssl/ssl/tls13_server.cc', 'deps/grpc/third_party/boringssl/ssl/tls_method.cc', 'deps/grpc/third_party/boringssl/ssl/tls_record.cc', + 'deps/grpc/third_party/boringssl/third_party/fiat/curve25519.c', ], 'conditions': [ ['OS == "mac"', { @@ -582,9 +583,6 @@ 'deps/grpc/src/core/lib/gpr/sync.cc', 'deps/grpc/src/core/lib/gpr/sync_posix.cc', 'deps/grpc/src/core/lib/gpr/sync_windows.cc', - 'deps/grpc/src/core/lib/gpr/thd.cc', - 'deps/grpc/src/core/lib/gpr/thd_posix.cc', - 'deps/grpc/src/core/lib/gpr/thd_windows.cc', 'deps/grpc/src/core/lib/gpr/time.cc', 'deps/grpc/src/core/lib/gpr/time_posix.cc', 'deps/grpc/src/core/lib/gpr/time_precise.cc', @@ -594,6 +592,8 @@ 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', + 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', + 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', 'deps/grpc/src/core/lib/profiling/stap_timers.cc', ], @@ -619,10 +619,13 @@ 'deps/grpc/src/core/lib/channel/channel_args.cc', 'deps/grpc/src/core/lib/channel/channel_stack.cc', 'deps/grpc/src/core/lib/channel/channel_stack_builder.cc', + 'deps/grpc/src/core/lib/channel/channel_trace.cc', + 'deps/grpc/src/core/lib/channel/channel_trace_registry.cc', 'deps/grpc/src/core/lib/channel/connected_channel.cc', 'deps/grpc/src/core/lib/channel/handshaker.cc', 'deps/grpc/src/core/lib/channel/handshaker_factory.cc', 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', + 'deps/grpc/src/core/lib/channel/status_util.cc', 'deps/grpc/src/core/lib/compression/compression.cc', 'deps/grpc/src/core/lib/compression/compression_internal.cc', 'deps/grpc/src/core/lib/compression/message_compress.cc', @@ -656,6 +659,8 @@ 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', 'deps/grpc/src/core/lib/iomgr/iomgr.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_internal.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_posix.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_uv.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_windows.cc', @@ -664,12 +669,16 @@ 'deps/grpc/src/core/lib/iomgr/lockfree_event.cc', 'deps/grpc/src/core/lib/iomgr/network_status_tracker.cc', 'deps/grpc/src/core/lib/iomgr/polling_entity.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_set_uv.cc', + 'deps/grpc/src/core/lib/iomgr/pollset.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_custom.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_set.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_set_custom.cc', 'deps/grpc/src/core/lib/iomgr/pollset_set_windows.cc', 'deps/grpc/src/core/lib/iomgr/pollset_uv.cc', 'deps/grpc/src/core/lib/iomgr/pollset_windows.cc', + 'deps/grpc/src/core/lib/iomgr/resolve_address.cc', + 'deps/grpc/src/core/lib/iomgr/resolve_address_custom.cc', 'deps/grpc/src/core/lib/iomgr/resolve_address_posix.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address_uv.cc', 'deps/grpc/src/core/lib/iomgr/resolve_address_windows.cc', 'deps/grpc/src/core/lib/iomgr/resource_quota.cc', 'deps/grpc/src/core/lib/iomgr/sockaddr_utils.cc', @@ -681,19 +690,24 @@ 'deps/grpc/src/core/lib/iomgr/socket_utils_uv.cc', 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.cc', 'deps/grpc/src/core/lib/iomgr/socket_windows.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client_uv.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_posix.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_posix.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_uv.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_windows.cc', 'deps/grpc/src/core/lib/iomgr/tcp_uv.cc', 'deps/grpc/src/core/lib/iomgr/tcp_windows.cc', 'deps/grpc/src/core/lib/iomgr/time_averaged_stats.cc', + 'deps/grpc/src/core/lib/iomgr/timer.cc', + 'deps/grpc/src/core/lib/iomgr/timer_custom.cc', 'deps/grpc/src/core/lib/iomgr/timer_generic.cc', 'deps/grpc/src/core/lib/iomgr/timer_heap.cc', 'deps/grpc/src/core/lib/iomgr/timer_manager.cc', @@ -714,7 +728,6 @@ 'deps/grpc/src/core/lib/slice/percent_encoding.cc', 'deps/grpc/src/core/lib/slice/slice.cc', 'deps/grpc/src/core/lib/slice/slice_buffer.cc', - 'deps/grpc/src/core/lib/slice/slice_hash_table.cc', 'deps/grpc/src/core/lib/slice/slice_intern.cc', 'deps/grpc/src/core/lib/slice/slice_string_helpers.cc', 'deps/grpc/src/core/lib/surface/api_trace.cc', @@ -745,6 +758,7 @@ 'deps/grpc/src/core/lib/transport/service_config.cc', 'deps/grpc/src/core/lib/transport/static_metadata.cc', 'deps/grpc/src/core/lib/transport/status_conversion.cc', + 'deps/grpc/src/core/lib/transport/status_metadata.cc', 'deps/grpc/src/core/lib/transport/timeout_encoding.cc', 'deps/grpc/src/core/lib/transport/transport.cc', 'deps/grpc/src/core/lib/transport/transport_op_string.cc', @@ -779,6 +793,7 @@ 'deps/grpc/src/core/ext/filters/http/server/http_server_filter.cc', 'deps/grpc/src/core/lib/http/httpcli_security_connector.cc', 'deps/grpc/src/core/lib/security/context/security_context.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/credentials.cc', 'deps/grpc/src/core/lib/security/credentials/credentials_metadata.cc', @@ -792,23 +807,56 @@ 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', + 'deps/grpc/src/core/lib/security/security_connector/alts_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', - 'deps/grpc/src/core/lib/security/transport/lb_targets_info.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', - 'deps/grpc/src/core/lib/security/transport/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', 'deps/grpc/src/core/lib/security/transport/server_auth_filter.cc', + 'deps/grpc/src/core/lib/security/transport/target_authority_table.cc', 'deps/grpc/src/core/lib/security/transport/tsi_error.cc', 'deps/grpc/src/core/lib/security/util/json_util.cc', 'deps/grpc/src/core/lib/surface/init_secure.cc', - 'deps/grpc/src/core/tsi/alts_transport_security.cc', - 'deps/grpc/src/core/tsi/fake_transport_security.cc', - 'deps/grpc/src/core/tsi/ssl_transport_security.cc', - 'deps/grpc/src/core/tsi/transport_security_grpc.cc', + 'deps/grpc/src/core/tsi/alts/crypt/aes_gcm.cc', + 'deps/grpc/src/core/tsi/alts/crypt/gsec.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/alts_counter.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/alts_crypter.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/alts_frame_protector.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', + 'deps/grpc/src/core/tsi/alts/frame_protector/frame_handler.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_event.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', + 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', + 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', + 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc', + 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc', + 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', + 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_utils.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/altscontext.pb.c', + 'deps/grpc/src/core/tsi/alts/handshaker/handshaker.pb.c', + 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common.pb.c', + 'deps/grpc/third_party/nanopb/pb_common.c', + 'deps/grpc/third_party/nanopb/pb_decode.c', + 'deps/grpc/third_party/nanopb/pb_encode.c', 'deps/grpc/src/core/tsi/transport_security.cc', 'deps/grpc/src/core/tsi/transport_security_adapter.cc', - 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/authority.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', @@ -820,6 +868,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/method_params.cc', 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', @@ -830,11 +879,17 @@ 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', 'deps/grpc/src/core/ext/filters/client_channel/uri_parser.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', + 'deps/grpc/src/core/tsi/alts_transport_security.cc', + 'deps/grpc/src/core/tsi/fake_transport_security.cc', + 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', + 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc', + 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc', + 'deps/grpc/src/core/tsi/ssl_transport_security.cc', + 'deps/grpc/src/core/tsi/transport_security_grpc.cc', + 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc', 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', 'deps/grpc/src/core/ext/transport/inproc/inproc_plugin.cc', 'deps/grpc/src/core/ext/transport/inproc/inproc_transport.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc', @@ -843,9 +898,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', - 'deps/grpc/third_party/nanopb/pb_common.c', - 'deps/grpc/third_party/nanopb/pb_decode.c', - 'deps/grpc/third_party/nanopb/pb_encode.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', @@ -861,6 +913,7 @@ 'deps/grpc/src/core/ext/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', + 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', 'deps/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc', 'deps/grpc/src/core/ext/filters/workarounds/workaround_utils.cc', 'deps/grpc/src/core/plugin_registry/grpc_plugin_registry.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 34e8e0a64..98c1017fd 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 34e8e0a6400d8b529125a3b83ec1facf71acf99b +Subproject commit 98c1017fd9f155aad13c3b86e8f17a456c9512e8 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 0a8d3f82f..db5fb5a0c 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.10.0-dev", + "version": "1.11.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From f453180d3e9a18628fa79124d5463f9ae8f31d34 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 5 Apr 2018 00:45:39 +0200 Subject: [PATCH 0181/1899] Removing zdefs. --- packages/grpc-native-core/binding.gyp | 1 - packages/grpc-native-core/templates/binding.gyp.template | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 8de8a228a..d90ecaba3 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -879,7 +879,6 @@ ], 'cflags': [ '-pthread', - '-zdefs', '-Wno-error=deprecated-declarations' ], "conditions": [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 11eb8e606..85ddbe655 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -312,7 +312,6 @@ ], 'cflags': [ '-pthread', - '-zdefs', '-Wno-error=deprecated-declarations' ], "conditions": [ From 0e05c902f112ef445b9d21b6dd6c9722459a9cca Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 5 Apr 2018 01:41:23 +0200 Subject: [PATCH 0182/1899] Adding more environment details. --- run-tests.bat | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index 81de8d25d..3f3aa4f1e 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -17,6 +17,10 @@ cd /d %~dp0 powershell -c "Get-Host" powershell -c "$PSVersionTable" +powershell -c "[System.Environment]::OSVersion" +powershell -c "Get-WmiObject -Class Win32_ComputerSystem" +powershell -c "(Get-WmiObject -Class Win32_ComputerSystem).SystemType" + powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% From 48817ceaeafc121d767def8f059c2bff9125a5a6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 5 Apr 2018 14:21:12 -0700 Subject: [PATCH 0183/1899] Improve proto-loader package.json and documentation to prepare to publish it --- packages/grpc-protobufjs/README.md | 34 ++++++++++++++++++++++++++- packages/grpc-protobufjs/package.json | 18 ++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md index 972d5d631..4e57faf4c 100644 --- a/packages/grpc-protobufjs/README.md +++ b/packages/grpc-protobufjs/README.md @@ -1,5 +1,7 @@ # gRPC Protobuf Loader +A utility package for loading `.proto` files for use with gRPC, using the latest Protobuf.js package. + ## Installation ```sh @@ -13,7 +15,37 @@ const protoLoader = require('@grpc/proto-loader'); const grpcLibrary = require('grpc'); // OR const grpcLibrary = require('@grpc/grpc-js'); -protoLoader.load(protoFile, options).then(packageDefinition => { + +protoLoader.load(protoFileName, options).then(packageDefinition => { const package = grpcLibrary.loadPackageDefinition(packageDefinition); }); +// OR +const packageDefinition = protoLoader.loadSync(protoFileName, options); +const package = grpcLibrary.loadPackageDefinition(packageDefinition); +``` + +The options parameter is an object that can have the following optional properties: + +| Field name | Valid values | Description +|------------|--------------|------------ +| `keepCase` | `true` or `false` | Preserve field names. The default is to change them to camel case. +| `longs` | `String` or `Number` | The type to use to represent `long` values. Defaults to a `Long` object type. +| `enums` | `String` | The type to use to represent `enum` values. Defaults to the numeric value. +| `bytes` | `Array` or `String` | The type to use to represent `bytes` values. Defaults to `Buffer`. +| `defaults` | `true` or `false` | Set default values on output objects. Defaults to `false`. +| `arrays` | `true` or `false` | Set empty arrays for missing array values even if `defaults` is `false` Defaults to `false`. +| `objects` | `true` or `false` | Set empty objects for missing object values even if `defaults` is `false` Defaults to `false`. +| `oneofs` | `true` or `false` | Set virtual oneof properties to the present field's name. Defaults to `false`. +| `include` | An array of strings | A list of search paths for imported `.proto` files. + +The following options object closely approximates the existing behavior of `grpc.load`: + +```js +const options = { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +} ``` diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index ed02d6a8e..e15c31f0f 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,8 +1,17 @@ { "name": "@grpc/proto-loader", "version": "0.1.0", - "description": "", + "author": "Google Inc.", + "contributors": [ + { + "name": "Michael Lumish", + "email": "mlumish@google.com" + } + ], + "description": "gRPC utility library for loading .proto files", + "homepage": "https://grpc.io/", "main": "build/src/index.js", + "typings": "build/src/index.d.ts", "scripts": { "build": "npm run compile", "clean": "gts clean", @@ -20,7 +29,6 @@ "type": "git", "url": "https://github.com/grpc/grpc-node.git" }, - "author": "", "license": "Apache-2.0", "bugs": { "url": "https://github.com/grpc/grpc-node/issues" @@ -32,10 +40,12 @@ "dependencies": { "@types/lodash": "^4.14.104", "@types/node": "^9.4.6", + "lodash": "^4.17.5", + "protobufjs": "^6.8.5" + }, + "devDependencies": { "clang-format": "^1.2.2", "gts": "^0.5.3", - "lodash": "^4.17.5", - "protobufjs": "^6.8.5", "typescript": "~2.7.2" } } From d73cd4a33551486ae7fa93a55a691fbbf07b4252 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 5 Apr 2018 12:01:03 -0700 Subject: [PATCH 0184/1899] Update v1.11.x branch to v1.11.0-pre1 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 98c1017fd..b240aae4f 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 98c1017fd9f155aad13c3b86e8f17a456c9512e8 +Subproject commit b240aae4f5eab828bf50993614f00e196cfc8f34 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index db5fb5a0c..41ded0b1b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.0-dev", + "version": "1.11.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 55106fa154cd73d9b81fdc3062fa2f0d07e544de Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 6 Apr 2018 11:57:44 -0700 Subject: [PATCH 0185/1899] Update v1.11.x to v1.11.0-pre1 for real this time with bugfixes --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 98c1017fd..1834a6287 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 98c1017fd9f155aad13c3b86e8f17a456c9512e8 +Subproject commit 1834a628782ec867279622644a5953987aa96d38 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index db5fb5a0c..41ded0b1b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.0-dev", + "version": "1.11.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From f05768f48fd9059dfcbd4ceb9a93f436f9420502 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 6 Apr 2018 11:58:59 -0700 Subject: [PATCH 0186/1899] Point master back at submodule master branch --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index b240aae4f..cc4fe1b3c 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit b240aae4f5eab828bf50993614f00e196cfc8f34 +Subproject commit cc4fe1b3cd5fea5c240e749e1f1f52f5aaab91a2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 41ded0b1b..2c05a7dd6 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.0-pre1", + "version": "1.12.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 6c1f4bc621cb8810872fbd6b2b010b1d9e869d7f Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 13:15:38 -0700 Subject: [PATCH 0187/1899] client lib integration changes --- test/client-libraries-integration/.gitignore | 2 +- test/client-libraries-integration/init.sh | 8 +- .../libs/.gitkeep | 0 .../client-libraries-integration/package.json | 2 + .../repositories.json | 18 +-- .../use-grpc-js.js | 105 +++++++++++++++--- 6 files changed, 106 insertions(+), 29 deletions(-) create mode 100644 test/client-libraries-integration/libs/.gitkeep diff --git a/test/client-libraries-integration/.gitignore b/test/client-libraries-integration/.gitignore index 5fe2e3660..611c25ccf 100644 --- a/test/client-libraries-integration/.gitignore +++ b/test/client-libraries-integration/.gitignore @@ -1 +1 @@ -nodejs-*/ \ No newline at end of file +libs/nodejs-*/ \ No newline at end of file diff --git a/test/client-libraries-integration/init.sh b/test/client-libraries-integration/init.sh index c5834a772..d892cdc9f 100755 --- a/test/client-libraries-integration/init.sh +++ b/test/client-libraries-integration/init.sh @@ -3,11 +3,13 @@ npm install for dir in $(node -p "require('./repositories.json').join('\n')"); do + pushd libs if [ ! -d $dir ]; then git clone https://github.com/googleapis/$dir + pushd $dir + npm install + popd fi - pushd $dir - npm install popd - node --require ./use-grpc-js.js $(npm bin)/_mocha --timeout 60000 $dir/system-test/*.js + SMOKE_TEST_PROJECT=$GCLOUD_PROJECT node --require ./use-grpc-js.js $(npm bin)/_mocha --timeout 60000 libs/$dir/system-test/*.js done diff --git a/test/client-libraries-integration/libs/.gitkeep b/test/client-libraries-integration/libs/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test/client-libraries-integration/package.json b/test/client-libraries-integration/package.json index ea639a064..69e024757 100644 --- a/test/client-libraries-integration/package.json +++ b/test/client-libraries-integration/package.json @@ -3,6 +3,8 @@ "version": "0.0.1", "description": "", "dependencies": { + "dot-prop": "^4.2.0", + "google-proto-files": "^0.15.1", "mocha": "^5.0.4", "shimmer": "^1.2.0" } diff --git a/test/client-libraries-integration/repositories.json b/test/client-libraries-integration/repositories.json index 31a937e9d..3333f58bb 100644 --- a/test/client-libraries-integration/repositories.json +++ b/test/client-libraries-integration/repositories.json @@ -1,20 +1,14 @@ [ + "nodejs-bigtable", "nodejs-datastore", - "nodejs-language", - "nodejs-storage", - "nodejs-translate", - "nodejs-logging", - "nodejs-video-intelligence", "nodejs-dlp", "nodejs-firestore", + "nodejs-language", + "nodejs-logging", + "nodejs-monitoring", "nodejs-pubsub", "nodejs-spanner", "nodejs-speech", - "nodejs-vision", - "nodejs-bigquery", - "nodejs-monitoring", - "nodejs-bigtable", - "nodejs-dns", - "nodejs-resource", - "nodejs-compute" + "nodejs-video-intelligence", + "nodejs-vision" ] \ No newline at end of file diff --git a/test/client-libraries-integration/use-grpc-js.js b/test/client-libraries-integration/use-grpc-js.js index 05273944e..a6e5093ed 100644 --- a/test/client-libraries-integration/use-grpc-js.js +++ b/test/client-libraries-integration/use-grpc-js.js @@ -1,18 +1,97 @@ +require('source-map-support/register'); const Module = require('module'); const shimmer = require('shimmer'); -const grpcImpl = require('../../packages/grpc-js-core'); const grpcPJson = require('../../packages/grpc-js-core/package'); +const grpcImpl = require('../../packages/grpc-js-core'); +const grpcProtobuf = require('../../packages/grpc-protobufjs'); + +if (!process.env.USE_GRPC_NATIVE) { + shimmer.wrap(Module, '_load', (moduleLoad) => { + return function Module_load(moduleName, parent) { + if (moduleName === 'grpc') { + // load grpc-js when grpc is requested. + return grpcImpl; + } else if (moduleName.startsWith('grpc/package')) { + // load grpc-js's package.json when grpc's package.json is requested. + return grpcPJson; + } else { + const result = moduleLoad.apply(this, arguments); + // monkeypatch google-gax and @google-cloud/common-grpc to avoid all + // references to grpc.load and grpc.loadObject, implementing functions + // on top of the new API for loading proto files. + if (moduleName === 'google-gax') { + if (!result.grpc.prototype.load.__wrapped) { + shimmer.wrap(result.grpc.prototype, 'load', (gaxLoad) => { + return function (filename, format, options) { + if (Array.isArray(filename)) { + options = filename[2]; + filename = filename[0]; + } + const packageDef = grpcProtobuf.loadSync(filename.file, { + keepCase: false, + defaults: true, + enums: String, + include: [filename.root] + }); + return grpcImpl.loadPackageDefinition(packageDef); + } + }); + } + if (!result.grpc.prototype.loadProto.__wrapped) { + shimmer.wrap(result.grpc.prototype, 'loadProto', (gaxLoadProto) => { + const path = require('path'); + const googleProtoFilesDir = require('google-proto-files')('..'); + + return function (protoPath, filename) { + const packageDef = grpcProtobuf.loadSync(filename, { + keepCase: false, + defaults: true, + enums: String, + include: [protoPath, googleProtoFilesDir] + }); + return grpcImpl.loadPackageDefinition(packageDef); + }; + }); + } + } else if (moduleName === '@google-cloud/common-grpc') { + if (!result.Service.prototype.loadProtoFile_.__wrapped) { + shimmer.wrap(result.Service.prototype, 'loadProtoFile_', (commonLoad) => { + const dotProp = require('dot-prop'); + // loadProtoFile_ uses a module-scope cache of loaded proto + // objects which isn't referenced anywhere else + const protoObjectCache = {}; + + return function (protoConfig, config) { + if (typeof protoConfig === 'string') { + protoConfig = { path: protoConfig }; + } + + const protoObjectCacheKey = [ + config.protosDir, + protoConfig.path, + protoConfig.service, + ].join('$'); + + if (!protoObjectCache[protoObjectCacheKey]) { + const services = grpcProtobuf.loadSync(protoConfig.path, { + keepCase: false, + bytes: 'string', + defaults: true, + enums: String, + include: [config.protosDir] + }); + const service = dotProp.get(services.google, protoConfig.service); + protoObjectCache[protoObjectCacheKey] = service; + } -shimmer.wrap(Module, '_load', (moduleLoad) => { - return function Module_load(path, parent) { - if (path === 'grpc') { - return grpcImpl; - } else if (path.startsWith('grpc/package')) { - return grpcPJson; - } else { - const result = moduleLoad.apply(this, arguments); - return result; - } - }; -}); + return protoObjectCache[protoObjectCacheKey]; + } + }); + } + } + return result; + } + }; + }); +} From 37a811b630e1cf86aef6a84ddade26aa2c6c8b77 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 5 Apr 2018 00:45:39 +0200 Subject: [PATCH 0188/1899] Removing zdefs. --- packages/grpc-native-core/binding.gyp | 1 - packages/grpc-native-core/templates/binding.gyp.template | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index d2a415116..a7cbb8b72 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -932,7 +932,6 @@ ], 'cflags': [ '-pthread', - '-zdefs', '-Wno-error=deprecated-declarations' ], "conditions": [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 11eb8e606..85ddbe655 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -312,7 +312,6 @@ ], 'cflags': [ '-pthread', - '-zdefs', '-Wno-error=deprecated-declarations' ], "conditions": [ From b20e2a2c63a3c88705e47a612345cbc0f541253b Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 10 Apr 2018 00:08:43 +0200 Subject: [PATCH 0189/1899] Workarounding node-gyp issue. --- run-tests.bat | 6 +++++- run-tests.sh | 5 ++++- tools/release/kokoro.bat | 3 +++ tools/release/kokoro.sh | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 3f3aa4f1e..5aeaa700c 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -29,15 +29,19 @@ SET JOBS=8 call nvm version call nvm install 8 +call nvm use 8 call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4 6 7 8) do ( +for %%v in (4 6 7 8 9) do ( call nvm install %%v + call nvm use %%v call npm install -g npm + @rem https://github.com/mapbox/node-pre-gyp/issues/362 + call npm install -g node-gyp node -e "console.log(process.versions)" mkdir reports\node%%v diff --git a/run-tests.sh b/run-tests.sh index 1444158bd..bfc0ff71d 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="4 5 6 7 8" + node_versions="4 5 6 7 8 9" fi set +ex @@ -51,6 +51,9 @@ do nvm use $version set -ex + # https://github.com/mapbox/node-pre-gyp/issues/362 + npm install -g node-gyp + mkdir -p "reports/node$version" node -e 'process.exit(process.version.startsWith("v'$version'") ? 0 : -1)' diff --git a/tools/release/kokoro.bat b/tools/release/kokoro.bat index e86e01bd7..edfa7d4e0 100644 --- a/tools/release/kokoro.bat +++ b/tools/release/kokoro.bat @@ -14,6 +14,9 @@ @echo "Starting Windows build" +@rem https://github.com/mapbox/node-pre-gyp/issues/362 +call npm install -g node-gyp + cd /d %~dp0 cd ..\.. diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index e5b578f72..b89504a94 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + set -ex cd $(dirname $0)/../.. base_dir=$(pwd) From 27cc80adac93f0cd5128ddf28a9d5ca82a8fa13d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 11 Apr 2018 13:29:49 -0700 Subject: [PATCH 0190/1899] Add note about @grpc/grpc-js alpha status --- packages/grpc-js-core/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js-core/README.md b/packages/grpc-js-core/README.md index 054986ca0..9393ffc14 100644 --- a/packages/grpc-js-core/README.md +++ b/packages/grpc-js-core/README.md @@ -1,5 +1,7 @@ # Pure JavaScript gRPC Client +**Note: This is an alpha-level release. Some APIs may not yet be present and there may be bugs. Please report any that you encounter** + ## Installation Node 9.x or greater is required. From 2bab8dc02bbfaa17b81043e1557db67fe03ad40b Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Mar 2018 01:25:19 +0100 Subject: [PATCH 0191/1899] Changing to the powershell version of nvm for better support. --- install-nvm-windows.ps1 | 29 ----------------------------- run-tests.bat | 16 ++++++---------- 2 files changed, 6 insertions(+), 39 deletions(-) delete mode 100644 install-nvm-windows.ps1 diff --git a/install-nvm-windows.ps1 b/install-nvm-windows.ps1 deleted file mode 100644 index b3794055f..000000000 --- a/install-nvm-windows.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# We're going to store nvm-windows in the .\nvm directory. -$env:NVM_HOME = (Get-Item -Path ".\" -Verbose).FullName + "\nvm" - -# Switching to TLS/1.2 - see https://githubengineering.com/crypto-removal-notice/ -[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - -# Downloading and unpacking nvm-windows -Invoke-WebRequest -Uri https://github.com/coreybutler/nvm-windows/releases/download/1.1.5/nvm-noinstall.zip -OutFile nvm-noinstall.zip -Add-Type -AssemblyName System.IO.Compression.FileSystem -[System.IO.Compression.ZipFile]::ExtractToDirectory("nvm-noinstall.zip", "nvm") - -$env:Path = $env:NVM_HOME + ";" + $env:Path -Out-File -Encoding "OEM" nvm\settings.txt -nvm root $env:NVM_HOME -"%*" | Out-File -Encoding "OEM" nvm\elevate.cmd diff --git a/run-tests.bat b/run-tests.bat index 547899e75..baf21778a 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -15,26 +15,22 @@ SET ROOT=%~dp0 cd /d %~dp0 -PowerShell -Command .\install-nvm-windows.ps1 +powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" -SET NVM_HOME=%ROOT%nvm -SET NVM_SYMLINK=%ROOT%nvm\nodejs -SET PATH=%NVM_HOME%;%NVM_SYMLINK%;%PATH% +SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% SET JOBS=8 -nvm version +call nvm version -nvm install 8.5.0 -nvm use 8.5.0 +call nvm install 8 call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4.8.4 6.11.3 7.9.0 8.5.0) do ( - nvm install %%v - nvm use %%v +for %%v in (4 6 7 8) do ( + call nvm install %%v call npm install -g npm node -e "console.log(process.versions)" From dc071f906bd818039c98e95acf26a853e99d8ee4 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Mar 2018 01:33:46 +0100 Subject: [PATCH 0192/1899] Debugging info. --- run-tests.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index baf21778a..81de8d25d 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -15,6 +15,8 @@ SET ROOT=%~dp0 cd /d %~dp0 +powershell -c "Get-Host" +powershell -c "$PSVersionTable" powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% From 8c92bdbc33443762e308e744f2e25bc882e1438c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 5 Apr 2018 01:41:23 +0200 Subject: [PATCH 0193/1899] Adding more environment details. --- run-tests.bat | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index 81de8d25d..3f3aa4f1e 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -17,6 +17,10 @@ cd /d %~dp0 powershell -c "Get-Host" powershell -c "$PSVersionTable" +powershell -c "[System.Environment]::OSVersion" +powershell -c "Get-WmiObject -Class Win32_ComputerSystem" +powershell -c "(Get-WmiObject -Class Win32_ComputerSystem).SystemType" + powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% From aaf8696d4289312bbde74a85b2f9fc216b32eb42 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 10 Apr 2018 00:08:43 +0200 Subject: [PATCH 0194/1899] Workarounding node-gyp issue. --- run-tests.bat | 6 +++++- run-tests.sh | 5 ++++- tools/release/kokoro.bat | 3 +++ tools/release/kokoro.sh | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 3f3aa4f1e..5aeaa700c 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -29,15 +29,19 @@ SET JOBS=8 call nvm version call nvm install 8 +call nvm use 8 call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4 6 7 8) do ( +for %%v in (4 6 7 8 9) do ( call nvm install %%v + call nvm use %%v call npm install -g npm + @rem https://github.com/mapbox/node-pre-gyp/issues/362 + call npm install -g node-gyp node -e "console.log(process.versions)" mkdir reports\node%%v diff --git a/run-tests.sh b/run-tests.sh index 1444158bd..bfc0ff71d 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="4 5 6 7 8" + node_versions="4 5 6 7 8 9" fi set +ex @@ -51,6 +51,9 @@ do nvm use $version set -ex + # https://github.com/mapbox/node-pre-gyp/issues/362 + npm install -g node-gyp + mkdir -p "reports/node$version" node -e 'process.exit(process.version.startsWith("v'$version'") ? 0 : -1)' diff --git a/tools/release/kokoro.bat b/tools/release/kokoro.bat index 2726d338a..1fde63b58 100644 --- a/tools/release/kokoro.bat +++ b/tools/release/kokoro.bat @@ -14,6 +14,9 @@ @echo "Starting Windows build" +@rem https://github.com/mapbox/node-pre-gyp/issues/362 +call npm install -g node-gyp + cd /d %~dp0 cd ..\.. diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index e5b578f72..b89504a94 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + set -ex cd $(dirname $0)/../.. base_dir=$(pwd) From 94906e41223bce2303d81f7896313ad1afc8ac38 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 11 Apr 2018 14:49:49 -0700 Subject: [PATCH 0195/1899] client library integration: adjust options --- packages/grpc-protobufjs/src/index.ts | 4 +-- .../use-grpc-js.js | 25 +++++++++++++++---- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index 85c2c9413..aa58fe6a8 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -97,14 +97,14 @@ function createMethodDefinition(method: Protobuf.Method, serviceName: string, op responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options), // TODO(murgatroid99): Find a better way to handle this - originalName: _.camelCase(method.name) + originalName: method.name }; } function createServiceDefinition(service: Protobuf.Service, name: string, options: Options): ServiceDefinition { const def: ServiceDefinition = {}; for (const method of service.methodsArray) { - def[method.name] = createMethodDefinition(method, name, options); + def[_.camelCase(method.name)] = createMethodDefinition(method, name, options); } return def; } diff --git a/test/client-libraries-integration/use-grpc-js.js b/test/client-libraries-integration/use-grpc-js.js index a6e5093ed..68c6597d5 100644 --- a/test/client-libraries-integration/use-grpc-js.js +++ b/test/client-libraries-integration/use-grpc-js.js @@ -28,10 +28,19 @@ if (!process.env.USE_GRPC_NATIVE) { options = filename[2]; filename = filename[0]; } + options = Object.assign({ + convertFieldsToCamelCase: true, // gax load uses hardcoded convertFieldsToCamelCase = true if it's not specified. + binaryAsBase64: false, // gRPC default option + longsAsStrings: true, // gRPC default option + enumsAsStrings: true, // gRPC default option + }, options); const packageDef = grpcProtobuf.loadSync(filename.file, { - keepCase: false, + keepCase: !options.convertFieldsToCamelCase, defaults: true, - enums: String, + bytes: options.binaryAsBase64 ? String : Buffer, + longs: options.longsAsString ? String : null, + enums: options.enumsAsStrings ? String : null, + oneofs: true, include: [filename.root] }); return grpcImpl.loadPackageDefinition(packageDef); @@ -42,12 +51,16 @@ if (!process.env.USE_GRPC_NATIVE) { shimmer.wrap(result.grpc.prototype, 'loadProto', (gaxLoadProto) => { const path = require('path'); const googleProtoFilesDir = require('google-proto-files')('..'); - return function (protoPath, filename) { + // loadProto does not accept options, so the options passed + // here correspond to defaultGrpcOptions. const packageDef = grpcProtobuf.loadSync(filename, { keepCase: false, defaults: true, + bytes: Buffer, + longs: String, enums: String, + oneofs: true, include: [protoPath, googleProtoFilesDir] }); return grpcImpl.loadPackageDefinition(packageDef); @@ -75,10 +88,12 @@ if (!process.env.USE_GRPC_NATIVE) { if (!protoObjectCache[protoObjectCacheKey]) { const services = grpcProtobuf.loadSync(protoConfig.path, { - keepCase: false, - bytes: 'string', + keepCase: false, // loadProtoFile_ uses hardcoded convertFieldsToCamelCase = true defaults: true, + bytes: String, // loadProtoFile_ uses hardcoded binaryAsBase64 = true + longs: String, enums: String, + oneofs: true, include: [config.protosDir] }); const service = dotProp.get(services.google, protoConfig.service); From a07b03ab5c98eb4be9396c5effaf239a7a2c895a Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 14 Mar 2018 11:27:43 -0700 Subject: [PATCH 0196/1899] test: enable ci for node 9 --- package.json | 2 ++ packages/grpc-js-core/gulpfile.ts | 9 +++++++-- run-tests.bat | 2 +- run-tests.sh | 2 +- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 5310e7f5c..fb6262141 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@types/ncp": "^2.0.1", "@types/node": "^8.0.32", "@types/pify": "^3.0.0", + "@types/semver": "^5.5.0", "del": "^3.0.0", "execa": "^0.8.0", "gulp": "^3.9.1", @@ -35,6 +36,7 @@ "mocha-jenkins-reporter": "^0.3.9", "ncp": "^2.0.0", "pify": "^3.0.0", + "semver": "^5.5.0", "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", diff --git a/packages/grpc-js-core/gulpfile.ts b/packages/grpc-js-core/gulpfile.ts index d309f6886..fcce74cd5 100644 --- a/packages/grpc-js-core/gulpfile.ts +++ b/packages/grpc-js-core/gulpfile.ts @@ -23,6 +23,7 @@ import * as mocha from 'gulp-mocha'; import * as path from 'path'; import * as execa from 'execa'; import * as pify from 'pify'; +import * as semver from 'semver'; import { ncp } from 'ncp'; // gulp-help monkeypatches tasks to have an additional description parameter @@ -71,6 +72,10 @@ gulp.task('copy-test-fixtures', 'Copy test fixtures.', () => { * Transpiles src/ and test/, and then runs all tests. */ gulp.task('test', 'Runs all tests.', ['copy-test-fixtures'], () => { - return gulp.src(`${outDir}/test/**/*.js`) - .pipe(mocha({reporter: 'mocha-jenkins-reporter'})); + if (semver.satisfies(process.version, '>=9.4')) { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter'})); + } else { + console.log(`Skipping grpc-js tests for Node ${process.version}`); + } }); diff --git a/run-tests.bat b/run-tests.bat index 5aeaa700c..5c91eda15 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -51,7 +51,7 @@ for %%v in (4 6 7 8 9) do ( call .\node_modules\.bin\gulp clean.all || SET FAILED=1 call .\node_modules\.bin\gulp setup.windows || SET FAILED=1 - call .\node_modules\.bin\gulp native.test || SET FAILED=1 + call .\node_modules\.bin\gulp test || SET FAILED=1 ) node merge_kokoro_logs.js diff --git a/run-tests.sh b/run-tests.sh index bfc0ff71d..300a25274 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -63,7 +63,7 @@ do ./node_modules/.bin/gulp setup # Rebuild libraries and run tests. - JUNIT_REPORT_PATH="reports/node$version/" JUNIT_REPORT_STACK=1 ./node_modules/.bin/gulp native.test || FAILED="true" + JUNIT_REPORT_PATH="reports/node$version/" JUNIT_REPORT_STACK=1 ./node_modules/.bin/gulp test || FAILED="true" done set +ex From c28016f9e77920ab0ab8f7f7ad24511c160a8658 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Wed, 11 Apr 2018 15:19:43 -0700 Subject: [PATCH 0197/1899] revert camelcase change --- packages/grpc-protobufjs/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index aa58fe6a8..85c2c9413 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -97,14 +97,14 @@ function createMethodDefinition(method: Protobuf.Method, serviceName: string, op responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options), // TODO(murgatroid99): Find a better way to handle this - originalName: method.name + originalName: _.camelCase(method.name) }; } function createServiceDefinition(service: Protobuf.Service, name: string, options: Options): ServiceDefinition { const def: ServiceDefinition = {}; for (const method of service.methodsArray) { - def[_.camelCase(method.name)] = createMethodDefinition(method, name, options); + def[method.name] = createMethodDefinition(method, name, options); } return def; } From c0f7afec327ab2523bd9970a280da7f49c5fccce Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 12 Apr 2018 11:59:34 -0700 Subject: [PATCH 0198/1899] js: only listen for channel connect event once --- packages/grpc-js-core/src/call.ts | 2 +- packages/grpc-js-core/src/channel.ts | 40 +++++++++++++++++++++++----- packages/grpc-js-core/src/client.ts | 6 +++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index af305b244..4344dfeb5 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -87,13 +87,13 @@ function setUpReadableStream( stream.push(null); }); call.on('status', (status: StatusObject) => { - stream.emit('status', status); if (status.code !== Status.OK) { const statusName = _.invert(Status)[status.code]; const message: string = `${status.code} ${statusName}: ${status.details}`; const error: ServiceError = Object.assign(new Error(status.details), status); stream.emit('error', error); } + stream.emit('status', status); }); call.pause(); } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 8e8e38e72..e710b733e 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -85,6 +85,8 @@ export class Http2Channel extends EventEmitter implements Channel { private readonly target: url.URL; private readonly defaultAuthority: string; private connectivityState: ConnectivityState = ConnectivityState.IDLE; + // Helper Promise object only used in the implementation of connect(). + private connecting: Promise|null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ private subChannel: http2.ClientHttp2Session|null = null; @@ -127,6 +129,7 @@ export class Http2Channel extends EventEmitter implements Channel { this.subChannel.removeListener('connect', this.subChannelConnectCallback); this.subChannel.removeListener('close', this.subChannelCloseCallback); this.subChannel = null; + this.emit('shutdown'); clearTimeout(this.backoffTimerId); } break; @@ -279,15 +282,38 @@ export class Http2Channel extends EventEmitter implements Channel { return stream; } + /** + * Attempts to connect, returning a Promise that resolves when the connection + * is successful, or rejects if the channel is shut down. + */ connect(): Promise { - return new Promise((resolve) => { - this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); - if (this.connectivityState === ConnectivityState.READY) { - setImmediate(resolve); - } else { - this.once('connect', resolve); + if (this.connectivityState === ConnectivityState.READY) { + return Promise.resolve(); + } else if (this.connectivityState === ConnectivityState.SHUTDOWN) { + return Promise.reject(new Error('Channel has been shut down')); + } else { + // In effect, this.connecting is only assigned upon the first attempt to + // transition from IDLE to CONNECTING, so this condition could have also + // been (connectivityState === IDLE). + if (!this.connecting) { + this.connecting = new Promise((resolve, reject) => { + this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); + const onConnect = () => { + this.connecting = null; + this.removeListener('shutdown', onShutdown); + resolve(); + }; + const onShutdown = () => { + this.connecting = null; + this.removeListener('connect', onConnect); + reject(new Error('Channel has been shut down')); + }; + this.once('connect', onConnect); + this.once('shutdown', onShutdown); + }); } - }); + return this.connecting; + } } getConnectivityState(): ConnectivityState { diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 25fa7bc8c..b120fcc7b 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -42,6 +42,12 @@ export class Client { clearTimeout(timer); } cb(null); + }, (err: Error) => { + // Rejection occurs if channel is shut down first. + if (timer) { + clearTimeout(timer); + } + cb(err); }); if (deadline !== Infinity) { let timeout: number; From eabda8118a5e9d4a74ccd29ee4f07eb0c765364f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 13 Apr 2018 10:29:11 -0700 Subject: [PATCH 0199/1899] Switch grpc submodule to v1.10.x --- packages/grpc-native-core/binding.gyp | 95 ++++++-------------------- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 24 insertions(+), 76 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index a7cbb8b72..8c55d9635 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -40,7 +40,6 @@ 'Release': { 'cflags': [ '-O2', - '-Wframe-larger-than=16384', ], 'defines': [ 'NDEBUG', @@ -583,6 +582,9 @@ 'deps/grpc/src/core/lib/gpr/sync.cc', 'deps/grpc/src/core/lib/gpr/sync_posix.cc', 'deps/grpc/src/core/lib/gpr/sync_windows.cc', + 'deps/grpc/src/core/lib/gpr/thd.cc', + 'deps/grpc/src/core/lib/gpr/thd_posix.cc', + 'deps/grpc/src/core/lib/gpr/thd_windows.cc', 'deps/grpc/src/core/lib/gpr/time.cc', 'deps/grpc/src/core/lib/gpr/time_posix.cc', 'deps/grpc/src/core/lib/gpr/time_precise.cc', @@ -592,8 +594,6 @@ 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', - 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', - 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', 'deps/grpc/src/core/lib/profiling/stap_timers.cc', ], @@ -619,13 +619,10 @@ 'deps/grpc/src/core/lib/channel/channel_args.cc', 'deps/grpc/src/core/lib/channel/channel_stack.cc', 'deps/grpc/src/core/lib/channel/channel_stack_builder.cc', - 'deps/grpc/src/core/lib/channel/channel_trace.cc', - 'deps/grpc/src/core/lib/channel/channel_trace_registry.cc', 'deps/grpc/src/core/lib/channel/connected_channel.cc', 'deps/grpc/src/core/lib/channel/handshaker.cc', 'deps/grpc/src/core/lib/channel/handshaker_factory.cc', 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', - 'deps/grpc/src/core/lib/channel/status_util.cc', 'deps/grpc/src/core/lib/compression/compression.cc', 'deps/grpc/src/core/lib/compression/compression_internal.cc', 'deps/grpc/src/core/lib/compression/message_compress.cc', @@ -659,8 +656,6 @@ 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', 'deps/grpc/src/core/lib/iomgr/iomgr.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_internal.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_posix.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_uv.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_windows.cc', @@ -669,16 +664,12 @@ 'deps/grpc/src/core/lib/iomgr/lockfree_event.cc', 'deps/grpc/src/core/lib/iomgr/network_status_tracker.cc', 'deps/grpc/src/core/lib/iomgr/polling_entity.cc', - 'deps/grpc/src/core/lib/iomgr/pollset.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_custom.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_set.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_set_custom.cc', + 'deps/grpc/src/core/lib/iomgr/pollset_set_uv.cc', 'deps/grpc/src/core/lib/iomgr/pollset_set_windows.cc', 'deps/grpc/src/core/lib/iomgr/pollset_uv.cc', 'deps/grpc/src/core/lib/iomgr/pollset_windows.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address_custom.cc', 'deps/grpc/src/core/lib/iomgr/resolve_address_posix.cc', + 'deps/grpc/src/core/lib/iomgr/resolve_address_uv.cc', 'deps/grpc/src/core/lib/iomgr/resolve_address_windows.cc', 'deps/grpc/src/core/lib/iomgr/resource_quota.cc', 'deps/grpc/src/core/lib/iomgr/sockaddr_utils.cc', @@ -690,24 +681,19 @@ 'deps/grpc/src/core/lib/iomgr/socket_utils_uv.cc', 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.cc', 'deps/grpc/src/core/lib/iomgr/socket_windows.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_uv.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_posix.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_posix.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_server_uv.cc', 'deps/grpc/src/core/lib/iomgr/tcp_server_windows.cc', 'deps/grpc/src/core/lib/iomgr/tcp_uv.cc', 'deps/grpc/src/core/lib/iomgr/tcp_windows.cc', 'deps/grpc/src/core/lib/iomgr/time_averaged_stats.cc', - 'deps/grpc/src/core/lib/iomgr/timer.cc', - 'deps/grpc/src/core/lib/iomgr/timer_custom.cc', 'deps/grpc/src/core/lib/iomgr/timer_generic.cc', 'deps/grpc/src/core/lib/iomgr/timer_heap.cc', 'deps/grpc/src/core/lib/iomgr/timer_manager.cc', @@ -728,6 +714,7 @@ 'deps/grpc/src/core/lib/slice/percent_encoding.cc', 'deps/grpc/src/core/lib/slice/slice.cc', 'deps/grpc/src/core/lib/slice/slice_buffer.cc', + 'deps/grpc/src/core/lib/slice/slice_hash_table.cc', 'deps/grpc/src/core/lib/slice/slice_intern.cc', 'deps/grpc/src/core/lib/slice/slice_string_helpers.cc', 'deps/grpc/src/core/lib/surface/api_trace.cc', @@ -758,7 +745,6 @@ 'deps/grpc/src/core/lib/transport/service_config.cc', 'deps/grpc/src/core/lib/transport/static_metadata.cc', 'deps/grpc/src/core/lib/transport/status_conversion.cc', - 'deps/grpc/src/core/lib/transport/status_metadata.cc', 'deps/grpc/src/core/lib/transport/timeout_encoding.cc', 'deps/grpc/src/core/lib/transport/transport.cc', 'deps/grpc/src/core/lib/transport/transport_op_string.cc', @@ -793,7 +779,6 @@ 'deps/grpc/src/core/ext/filters/http/server/http_server_filter.cc', 'deps/grpc/src/core/lib/http/httpcli_security_connector.cc', 'deps/grpc/src/core/lib/security/context/security_context.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/credentials.cc', 'deps/grpc/src/core/lib/security/credentials/credentials_metadata.cc', @@ -807,56 +792,23 @@ 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', - 'deps/grpc/src/core/lib/security/security_connector/alts_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', + 'deps/grpc/src/core/lib/security/transport/lb_targets_info.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', 'deps/grpc/src/core/lib/security/transport/server_auth_filter.cc', - 'deps/grpc/src/core/lib/security/transport/target_authority_table.cc', 'deps/grpc/src/core/lib/security/transport/tsi_error.cc', 'deps/grpc/src/core/lib/security/util/json_util.cc', 'deps/grpc/src/core/lib/surface/init_secure.cc', - 'deps/grpc/src/core/tsi/alts/crypt/aes_gcm.cc', - 'deps/grpc/src/core/tsi/alts/crypt/gsec.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_counter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_crypter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_frame_protector.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/frame_handler.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_event.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_utils.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/altscontext.pb.c', - 'deps/grpc/src/core/tsi/alts/handshaker/handshaker.pb.c', - 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common.pb.c', - 'deps/grpc/third_party/nanopb/pb_common.c', - 'deps/grpc/third_party/nanopb/pb_decode.c', - 'deps/grpc/third_party/nanopb/pb_encode.c', + 'deps/grpc/src/core/tsi/alts_transport_security.cc', + 'deps/grpc/src/core/tsi/fake_transport_security.cc', + 'deps/grpc/src/core/tsi/ssl_transport_security.cc', + 'deps/grpc/src/core/tsi/transport_security_grpc.cc', 'deps/grpc/src/core/tsi/transport_security.cc', 'deps/grpc/src/core/tsi/transport_security_adapter.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/authority.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', + 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', @@ -868,7 +820,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', - 'deps/grpc/src/core/ext/filters/client_channel/method_params.cc', 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', @@ -879,17 +830,11 @@ 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', 'deps/grpc/src/core/ext/filters/client_channel/uri_parser.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', - 'deps/grpc/src/core/tsi/alts_transport_security.cc', - 'deps/grpc/src/core/tsi/fake_transport_security.cc', - 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', - 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc', - 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc', - 'deps/grpc/src/core/tsi/ssl_transport_security.cc', - 'deps/grpc/src/core/tsi/transport_security_grpc.cc', - 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc', 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', + 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', 'deps/grpc/src/core/ext/transport/inproc/inproc_plugin.cc', 'deps/grpc/src/core/ext/transport/inproc/inproc_transport.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc', @@ -898,6 +843,9 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', + 'deps/grpc/third_party/nanopb/pb_common.c', + 'deps/grpc/third_party/nanopb/pb_decode.c', + 'deps/grpc/third_party/nanopb/pb_encode.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', @@ -913,7 +861,6 @@ 'deps/grpc/src/core/ext/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', - 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', 'deps/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc', 'deps/grpc/src/core/ext/filters/workarounds/workaround_utils.cc', 'deps/grpc/src/core/plugin_registry/grpc_plugin_registry.cc', diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..5703b3c8c 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + 'node_version': 1.11.0-pre2 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 1834a6287..29e71eede 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 1834a628782ec867279622644a5953987aa96d38 +Subproject commit 29e71eede587132278accc184de2e6b2f49ee58d diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 41ded0b1b..c53db2309 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.0-pre1", + "version": "1.11.0-pre2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 9985445a4898f011d934cc4a661df3d76fc8a248 Mon Sep 17 00:00:00 2001 From: Nikos Koumbakis Date: Sun, 15 Apr 2018 20:48:30 +0300 Subject: [PATCH 0200/1899] Update protobufjs version Fixes [ReDoS Vulnerability](https://github.com/dcodeIO/protobuf.js/releases/tag/6.8.6) --- packages/grpc-protobufjs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index ed02d6a8e..76b6a229b 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -35,7 +35,7 @@ "clang-format": "^1.2.2", "gts": "^0.5.3", "lodash": "^4.17.5", - "protobufjs": "^6.8.5", + "protobufjs": "^6.8.6", "typescript": "~2.7.2" } } From dd3eb9e0f81c9d8c834d0dc15acaef0f64824ad9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 17 Apr 2018 14:06:52 -0700 Subject: [PATCH 0201/1899] Add unimplemented errors for several API functions --- packages/grpc-js-core/src/index.ts | 45 ++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 5a3f60251..8c9cb32ce 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -85,3 +85,48 @@ export { * @param client The client to close. */ export const closeClient = (client: Client) => client.close(); + +export const waitForClientReady = (client: Client, deadline: Date|number, callback: (error: Error | null) => void) => client.waitForReady(deadline, callback); + +/**** Unimplemented function stubs ****/ + +export const loadObject = (value: any, options: any) => { + throw new Error('Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); +} + +export const load = (filename: any, format: any, options: any) => { + throw new Error('Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); +} + +export const setLogger = (logger: any) => { + throw new Error('Not yet implemented'); +} + +export const setLogVerbosity = (verbosity: any) => { + throw new Error('Not yet implemented'); +} + +export const Server = (options: any) => { + throw new Error('Not yet implemented'); +} + +export const ServerCredentials = { + createSsl: (rootCerts: any, keyCertPairs: any, checkClientCertificate: any) => { + throw new Error('Not yet implemented'); + }, + createInsecure: () => { + throw new Error('Not yet implemented'); + } +} + +export const getClientChannel = (client: any) => { + throw new Error('Not available in this library'); +} + +export const StatusBuilder = () => { throw new Error('Not yet implemented'); } + +export const ListenerBuilder = () => { throw new Error('Not yet implemented'); } + +export const InterceptorBuilder = () => { throw new Error('Not yet implemented'); } + +export const InterceptingCall = () => { throw new Error('Not yet implemented'); } From 9112ac194b99224dced664d5d8c9df9d12d1af3a Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Thu, 12 Apr 2018 11:59:34 -0700 Subject: [PATCH 0202/1899] js: only listen for channel connect event once --- packages/grpc-js-core/src/call.ts | 2 +- packages/grpc-js-core/src/channel.ts | 40 +++++++++++++++++++++++----- packages/grpc-js-core/src/client.ts | 6 +++++ 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index af305b244..4344dfeb5 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -87,13 +87,13 @@ function setUpReadableStream( stream.push(null); }); call.on('status', (status: StatusObject) => { - stream.emit('status', status); if (status.code !== Status.OK) { const statusName = _.invert(Status)[status.code]; const message: string = `${status.code} ${statusName}: ${status.details}`; const error: ServiceError = Object.assign(new Error(status.details), status); stream.emit('error', error); } + stream.emit('status', status); }); call.pause(); } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 8e8e38e72..e710b733e 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -85,6 +85,8 @@ export class Http2Channel extends EventEmitter implements Channel { private readonly target: url.URL; private readonly defaultAuthority: string; private connectivityState: ConnectivityState = ConnectivityState.IDLE; + // Helper Promise object only used in the implementation of connect(). + private connecting: Promise|null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ private subChannel: http2.ClientHttp2Session|null = null; @@ -127,6 +129,7 @@ export class Http2Channel extends EventEmitter implements Channel { this.subChannel.removeListener('connect', this.subChannelConnectCallback); this.subChannel.removeListener('close', this.subChannelCloseCallback); this.subChannel = null; + this.emit('shutdown'); clearTimeout(this.backoffTimerId); } break; @@ -279,15 +282,38 @@ export class Http2Channel extends EventEmitter implements Channel { return stream; } + /** + * Attempts to connect, returning a Promise that resolves when the connection + * is successful, or rejects if the channel is shut down. + */ connect(): Promise { - return new Promise((resolve) => { - this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); - if (this.connectivityState === ConnectivityState.READY) { - setImmediate(resolve); - } else { - this.once('connect', resolve); + if (this.connectivityState === ConnectivityState.READY) { + return Promise.resolve(); + } else if (this.connectivityState === ConnectivityState.SHUTDOWN) { + return Promise.reject(new Error('Channel has been shut down')); + } else { + // In effect, this.connecting is only assigned upon the first attempt to + // transition from IDLE to CONNECTING, so this condition could have also + // been (connectivityState === IDLE). + if (!this.connecting) { + this.connecting = new Promise((resolve, reject) => { + this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); + const onConnect = () => { + this.connecting = null; + this.removeListener('shutdown', onShutdown); + resolve(); + }; + const onShutdown = () => { + this.connecting = null; + this.removeListener('connect', onConnect); + reject(new Error('Channel has been shut down')); + }; + this.once('connect', onConnect); + this.once('shutdown', onShutdown); + }); } - }); + return this.connecting; + } } getConnectivityState(): ConnectivityState { diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 25fa7bc8c..b120fcc7b 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -42,6 +42,12 @@ export class Client { clearTimeout(timer); } cb(null); + }, (err: Error) => { + // Rejection occurs if channel is shut down first. + if (timer) { + clearTimeout(timer); + } + cb(err); }); if (deadline !== Infinity) { let timeout: number; From 881b82d50c744cb7798fa60f5165986c3f3a4bbf Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 18 Apr 2018 11:32:46 -0700 Subject: [PATCH 0203/1899] Fix lint errors and formatting --- .../src/call-credentials-filter.ts | 17 +- packages/grpc-js-core/src/call-credentials.ts | 68 ++--- packages/grpc-js-core/src/call-stream.ts | 63 +++-- packages/grpc-js-core/src/call.ts | 38 +-- .../grpc-js-core/src/channel-credentials.ts | 117 ++++---- packages/grpc-js-core/src/channel.ts | 227 ++++++++------- packages/grpc-js-core/src/client.ts | 43 +-- packages/grpc-js-core/src/deadline-filter.ts | 16 +- packages/grpc-js-core/src/events.ts | 6 +- packages/grpc-js-core/src/filter-stack.ts | 2 +- packages/grpc-js-core/src/index.ts | 168 ++++++----- packages/grpc-js-core/src/make-client.ts | 72 +++-- .../src/metadata-status-filter.ts | 13 +- packages/grpc-js-core/src/metadata.ts | 18 +- packages/grpc-js-core/src/object-stream.ts | 7 +- packages/grpc-js-core/test/common.ts | 10 +- .../test/test-call-credentials.ts | 10 +- .../grpc-js-core/test/test-call-stream.ts | 263 +++++++++--------- .../test/test-channel-credentials.ts | 1 + 19 files changed, 604 insertions(+), 555 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index 737594103..f25d70bc6 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -10,11 +10,10 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; constructor( private readonly credentials: CallCredentials, - private readonly host: string, - private readonly path: string) { + private readonly host: string, private readonly path: string) { super(); - let splitPath: string[] = path.split('/'); - let serviceName: string = ''; + const splitPath: string[] = path.split('/'); + let serviceName = ''; /* The standard path format is "/{serviceName}/{methodName}", so if we split * by '/', the first item should be empty and the second should be the * service name */ @@ -27,8 +26,9 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { } async sendMetadata(metadata: Promise): Promise { - let credsMetadata = this.credentials.generateMetadata({ service_url: this.serviceUrl }); - let resultMetadata = await metadata; + const credsMetadata = + this.credentials.generateMetadata({service_url: this.serviceUrl}); + const resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; } @@ -43,8 +43,7 @@ export class CallCredentialsFilterFactory implements createFilter(callStream: CallStream): CallCredentialsFilter { return new CallCredentialsFilter( - this.credentials.compose(callStream.getCredentials()), - callStream.getHost(), - callStream.getMethod()); + this.credentials.compose(callStream.getCredentials()), + callStream.getHost(), callStream.getMethod()); } } diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 0c0f6d535..7d5bd3323 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -2,39 +2,59 @@ import {map, reduce} from 'lodash'; import {Metadata} from './metadata'; -export type CallMetadataOptions = { service_url: string; }; +export type CallMetadataOptions = { + service_url: string; +}; export type CallMetadataGenerator = - (options: CallMetadataOptions, cb: (err: Error|null, metadata?: Metadata) => void) => - void; + (options: CallMetadataOptions, + cb: (err: Error|null, metadata?: Metadata) => void) => void; /** * A class that represents a generic method of adding authentication-related * metadata on a per-request basis. */ -export interface CallCredentials { +export abstract class CallCredentials { /** * Asynchronously generates a new Metadata object. * @param options Options used in generating the Metadata object. */ - generateMetadata(options: CallMetadataOptions): Promise; + abstract generateMetadata(options: CallMetadataOptions): Promise; /** * Creates a new CallCredentials object from properties of both this and * another CallCredentials object. This object's metadata generator will be * called first. * @param callCredentials The other CallCredentials object. */ - compose(callCredentials: CallCredentials): CallCredentials; + abstract compose(callCredentials: CallCredentials): CallCredentials; + + /** + * Creates a new CallCredentials object from a given function that generates + * Metadata objects. + * @param metadataGenerator A function that accepts a set of options, and + * generates a Metadata object based on these options, which is passed back + * to the caller via a supplied (err, metadata) callback. + */ + static createFromMetadataGenerator(metadataGenerator: CallMetadataGenerator): + CallCredentials { + return new SingleCallCredentials(metadataGenerator); + } + + static createEmpty(): CallCredentials { + return new EmptyCallCredentials(); + } } -class ComposedCallCredentials implements CallCredentials { - constructor(private creds: CallCredentials[]) {} +class ComposedCallCredentials extends CallCredentials { + constructor(private creds: CallCredentials[]) { + super(); + } async generateMetadata(options: CallMetadataOptions): Promise { - let base: Metadata = new Metadata(); - let generated: Metadata[] = await Promise.all( + const base: Metadata = new Metadata(); + const generated: Metadata[] = await Promise.all( map(this.creds, (cred) => cred.generateMetadata(options))); - for (let gen of generated) { + for (const gen of generated) { base.merge(gen); } return base; @@ -45,8 +65,10 @@ class ComposedCallCredentials implements CallCredentials { } } -class SingleCallCredentials implements CallCredentials { - constructor(private metadataGenerator: CallMetadataGenerator) {} +class SingleCallCredentials extends CallCredentials { + constructor(private metadataGenerator: CallMetadataGenerator) { + super(); + } generateMetadata(options: CallMetadataOptions): Promise { return new Promise((resolve, reject) => { @@ -65,7 +87,7 @@ class SingleCallCredentials implements CallCredentials { } } -class EmptyCallCredentials implements CallCredentials { +class EmptyCallCredentials extends CallCredentials { generateMetadata(options: CallMetadataOptions): Promise { return Promise.resolve(new Metadata()); } @@ -74,21 +96,3 @@ class EmptyCallCredentials implements CallCredentials { return other; } } - -export namespace CallCredentials { - /** - * Creates a new CallCredentials object from a given function that generates - * Metadata objects. - * @param metadataGenerator A function that accepts a set of options, and - * generates a Metadata object based on these options, which is passed back - * to the caller via a supplied (err, metadata) callback. - */ - export function createFromMetadataGenerator( - metadataGenerator: CallMetadataGenerator): CallCredentials { - return new SingleCallCredentials(metadataGenerator); - } - - export function createEmpty(): CallCredentials { - return new EmptyCallCredentials(); - } -} diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 80962008c..eb6b743e2 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -9,9 +9,10 @@ import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; import {ObjectDuplex} from './object-stream'; -const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = http2.constants; +const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = + http2.constants; -export type Deadline = Date | number; +export type Deadline = Date|number; export interface CallStreamOptions { deadline: Deadline; @@ -36,20 +37,19 @@ export interface WriteObject { /** * This interface represents a duplex stream associated with a single gRPC call. */ -export type CallStream = { - cancelWithStatus(status: Status, details: string): void; - getPeer(): string; +export type CallStream = { + cancelWithStatus(status: Status, details: string): void; getPeer(): string; getDeadline(): Deadline; getCredentials(): CallCredentials; /* If the return value is null, the call has not ended yet. Otherwise, it has * ended with the specified status */ - getStatus(): StatusObject|null; + getStatus(): StatusObject | null; getMethod(): string; getHost(): string; -} & EmitterAugmentation1<'metadata', Metadata> - & EmitterAugmentation1<'status', StatusObject> - & ObjectDuplex; +}&EmitterAugmentation1<'metadata', Metadata>& + EmitterAugmentation1<'status', StatusObject>& + ObjectDuplex; enum ReadState { NO_DATA, @@ -60,7 +60,7 @@ enum ReadState { const emptyBuffer = Buffer.alloc(0); export class Http2CallStream extends Duplex implements CallStream { - public filterStack: Filter; + filterStack: Filter; private statusEmitted = false; private http2Stream: http2.ClientHttp2Stream|null = null; private pendingRead = false; @@ -76,7 +76,7 @@ export class Http2CallStream extends Duplex implements CallStream { private readPartialMessage: Buffer[] = []; private readMessageRemaining = 0; - private unpushedReadMessages: (Buffer|null)[] = []; + private unpushedReadMessages: Array = []; // Status code mapped from :status. To be used if grpc-status is not received private mappedStatusCode: Status = Status.UNKNOWN; @@ -124,20 +124,21 @@ export class Http2CallStream extends Duplex implements CallStream { } private handleTrailers(headers: http2.IncomingHttpHeaders) { - let code: Status = this.mappedStatusCode; - let details = ''; + const code: Status = this.mappedStatusCode; + const details = ''; let metadata: Metadata; try { metadata = Metadata.fromHttp2Headers(headers); } catch (e) { metadata = new Metadata(); } - let status: StatusObject = {code, details, metadata}; + const status: StatusObject = {code, details, metadata}; this.handlingTrailers = (async () => { let finalStatus; try { // Attempt to assign final status. - finalStatus = await this.filterStack.receiveTrailers(Promise.resolve(status)); + finalStatus = + await this.filterStack.receiveTrailers(Promise.resolve(status)); } catch (error) { await this.handlingHeaders; // This is a no-op if the call was already ended when handling headers. @@ -195,17 +196,26 @@ export class Http2CallStream extends Duplex implements CallStream { try { metadata = Metadata.fromHttp2Headers(headers); } catch (error) { - this.endCall({code: Status.UNKNOWN, details: error.message, metadata: new Metadata()}); + this.endCall({ + code: Status.UNKNOWN, + details: error.message, + metadata: new Metadata() + }); return; } this.handlingHeaders = - this.filterStack.receiveMetadata(Promise.resolve(metadata)) - .then((finalMetadata) => { - this.emit('metadata', finalMetadata); - }).catch((error) => { - this.destroyHttp2Stream(); - this.endCall({code: Status.UNKNOWN, details: error.message, metadata: new Metadata()}); - }); + this.filterStack.receiveMetadata(Promise.resolve(metadata)) + .then((finalMetadata) => { + this.emit('metadata', finalMetadata); + }) + .catch((error) => { + this.destroyHttp2Stream(); + this.endCall({ + code: Status.UNKNOWN, + details: error.message, + metadata: new Metadata() + }); + }); } }); stream.on('trailers', this.handleTrailers.bind(this)); @@ -260,6 +270,9 @@ export class Http2CallStream extends Duplex implements CallStream { canPush = this.tryPush(messageBytes, canPush); this.readState = ReadState.NO_DATA; } + break; + default: + throw new Error('This should never happen'); } } }); @@ -298,7 +311,7 @@ export class Http2CallStream extends Duplex implements CallStream { // This is OK, because status codes emitted here correspond to more // catastrophic issues that prevent us from receiving trailers in the // first place. - this.endCall({code: code, details: details, metadata: new Metadata()}); + this.endCall({code, details, metadata: new Metadata()}); }); stream.on('error', (err: Error) => { this.endCall({ @@ -338,7 +351,7 @@ export class Http2CallStream extends Duplex implements CallStream { // If trailers are currently being processed, the call should be ended // by handleTrailers instead. await this.handlingTrailers; - this.endCall({code: status, details: details, metadata: new Metadata()}); + this.endCall({code: status, details, metadata: new Metadata()}); })(); } diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index 4344dfeb5..fc72d358b 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -1,27 +1,25 @@ import {EventEmitter} from 'events'; -import {EmitterAugmentation1} from './events'; +import * as _ from 'lodash'; import {Duplex, Readable, Writable} from 'stream'; import {CallStream, StatusObject, WriteObject} from './call-stream'; import {Status} from './constants'; +import {EmitterAugmentation1} from './events'; import {Metadata} from './metadata'; import {ObjectReadable, ObjectWritable} from './object-stream'; -import * as _ from 'lodash'; /** * A type extending the built-in Error object with additional fields. */ -export type ServiceError = StatusObject & Error; +export type ServiceError = StatusObject&Error; /** * A base type for all user-facing values returned by client-side method calls. */ export type Call = { - cancel(): void; - getPeer(): string; -} & EmitterAugmentation1<'metadata', Metadata> - & EmitterAugmentation1<'status', StatusObject> - & EventEmitter; + cancel(): void; getPeer(): string; +}&EmitterAugmentation1<'metadata', Metadata>& + EmitterAugmentation1<'status', StatusObject>&EventEmitter; /** * A type representing the return value of a unary method call. @@ -33,22 +31,23 @@ export type ClientUnaryCall = Call; */ export type ClientReadableStream = { deserialize: (chunk: Buffer) => ResponseType; -} & Call & ObjectReadable; +}&Call&ObjectReadable; /** * A type representing the return value of a client stream method call. */ export type ClientWritableStream = { serialize: (value: RequestType) => Buffer; -} & Call & ObjectWritable; +}&Call&ObjectWritable; /** * A type representing the return value of a bidirectional stream method call. */ export type ClientDuplexStream = - ClientWritableStream & ClientReadableStream; + ClientWritableStream&ClientReadableStream; -export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { +export class ClientUnaryCallImpl extends EventEmitter implements + ClientUnaryCall { constructor(private readonly call: CallStream) { super(); call.on('metadata', (metadata: Metadata) => { @@ -89,8 +88,9 @@ function setUpReadableStream( call.on('status', (status: StatusObject) => { if (status.code !== Status.OK) { const statusName = _.invert(Status)[status.code]; - const message: string = `${status.code} ${statusName}: ${status.details}`; - const error: ServiceError = Object.assign(new Error(status.details), status); + const message = `${status.code} ${statusName}: ${status.details}`; + const error: ServiceError = + Object.assign(new Error(status.details), status); stream.emit('error', error); } stream.emit('status', status); @@ -102,7 +102,7 @@ export class ClientReadableStreamImpl extends Readable implements ClientReadableStream { constructor( private readonly call: CallStream, - public readonly deserialize: (chunk: Buffer) => ResponseType) { + readonly deserialize: (chunk: Buffer) => ResponseType) { super({objectMode: true}); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); @@ -135,7 +135,7 @@ function tryWrite( cb(e); return; } - const writeObj: WriteObject = {message: message}; + const writeObj: WriteObject = {message}; if (!Number.isNaN(flags)) { writeObj.flags = flags; } @@ -146,7 +146,7 @@ export class ClientWritableStreamImpl extends Writable implements ClientWritableStream { constructor( private readonly call: CallStream, - public readonly serialize: (value: RequestType) => Buffer) { + readonly serialize: (value: RequestType) => Buffer) { super({objectMode: true}); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); @@ -178,8 +178,8 @@ export class ClientDuplexStreamImpl extends Duplex implements ClientDuplexStream { constructor( private readonly call: CallStream, - public readonly serialize: (value: RequestType) => Buffer, - public readonly deserialize: (chunk: Buffer) => ResponseType) { + readonly serialize: (value: RequestType) => Buffer, + readonly deserialize: (chunk: Buffer) => ResponseType) { super({objectMode: true}); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 419e3d17e..5a5c90373 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -2,90 +2,45 @@ import {createSecureContext, SecureContext} from 'tls'; import {CallCredentials} from './call-credentials'; +// tslint:disable-next-line:no-any +function verifyIsBufferOrNull(obj: any, friendlyName: string): void { + if (obj && !(obj instanceof Buffer)) { + throw new TypeError(`${friendlyName}, if provided, must be a Buffer.`); + } +} + /** * A class that contains credentials for communicating over a channel, as well * as a set of per-call credentials, which are applied to every method call made * over a channel initialized with an instance of this class. */ -export interface ChannelCredentials { +export abstract class ChannelCredentials { + protected callCredentials: CallCredentials; + + protected constructor(callCredentials?: CallCredentials) { + this.callCredentials = callCredentials || CallCredentials.createEmpty(); + } /** * Returns a copy of this object with the included set of per-call credentials * expanded to include callCredentials. * @param callCredentials A CallCredentials object to associate with this * instance. */ - compose(callCredentials: CallCredentials): ChannelCredentials; + abstract compose(callCredentials: CallCredentials): ChannelCredentials; /** * Gets the set of per-call credentials associated with this instance. */ - getCallCredentials(): CallCredentials; + getCallCredentials(): CallCredentials { + return this.callCredentials; + } /** * Gets a SecureContext object generated from input parameters if this * instance was created with createSsl, or null if this instance was created * with createInsecure. */ - getSecureContext(): SecureContext|null; -} - -abstract class ChannelCredentialsImpl implements ChannelCredentials { - protected callCredentials: CallCredentials; - - protected constructor(callCredentials?: CallCredentials) { - this.callCredentials = callCredentials || CallCredentials.createEmpty(); - } - - abstract compose(callCredentials: CallCredentials): ChannelCredentialsImpl; - - getCallCredentials(): CallCredentials { - return this.callCredentials; - } - abstract getSecureContext(): SecureContext|null; -} - -class InsecureChannelCredentialsImpl extends ChannelCredentialsImpl { - constructor(callCredentials?: CallCredentials) { - super(callCredentials); - } - - compose(callCredentials: CallCredentials): ChannelCredentialsImpl { - throw new Error('Cannot compose insecure credentials'); - } - - getSecureContext(): SecureContext|null { - return null; - } -} - -class SecureChannelCredentialsImpl extends ChannelCredentialsImpl { - secureContext: SecureContext; - - constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { - super(callCredentials); - this.secureContext = secureContext; - } - - compose(callCredentials: CallCredentials): ChannelCredentialsImpl { - const combinedCallCredentials = - this.callCredentials.compose(callCredentials); - return new SecureChannelCredentialsImpl( - this.secureContext, combinedCallCredentials); - } - - getSecureContext(): SecureContext|null { - return this.secureContext; - } -} - -function verifyIsBufferOrNull(obj: any, friendlyName: string): void { - if (obj && !(obj instanceof Buffer)) { - throw new TypeError(`${friendlyName}, if provided, must be a Buffer.`); - } -} - -export namespace ChannelCredentials { /** * Return a new ChannelCredentials instance with a given set of credentials. @@ -95,7 +50,7 @@ export namespace ChannelCredentials { * @param privateKey The client certificate private key, if available. * @param certChain The client certificate key chain, if available. */ - export function createSsl( + static createSsl( rootCerts?: Buffer|null, privateKey?: Buffer|null, certChain?: Buffer|null): ChannelCredentials { verifyIsBufferOrNull(rootCerts, 'Root certificate'); @@ -120,7 +75,41 @@ export namespace ChannelCredentials { /** * Return a new ChannelCredentials instance with no credentials. */ - export function createInsecure(): ChannelCredentials { + static createInsecure(): ChannelCredentials { return new InsecureChannelCredentialsImpl(); } } + +class InsecureChannelCredentialsImpl extends ChannelCredentials { + constructor(callCredentials?: CallCredentials) { + super(callCredentials); + } + + compose(callCredentials: CallCredentials): ChannelCredentials { + throw new Error('Cannot compose insecure credentials'); + } + + getSecureContext(): SecureContext|null { + return null; + } +} + +class SecureChannelCredentialsImpl extends ChannelCredentials { + secureContext: SecureContext; + + constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { + super(callCredentials); + this.secureContext = secureContext; + } + + compose(callCredentials: CallCredentials): ChannelCredentials { + const combinedCallCredentials = + this.callCredentials.compose(callCredentials); + return new SecureChannelCredentialsImpl( + this.secureContext, combinedCallCredentials); + } + + getSecureContext(): SecureContext|null { + return this.secureContext; + } +} diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index e710b733e..18ab8ec74 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -1,6 +1,6 @@ import {EventEmitter} from 'events'; import * as http2 from 'http2'; -import {checkServerIdentity, SecureContext, PeerCertificate} from 'tls'; +import {checkServerIdentity, PeerCertificate, SecureContext} from 'tls'; import * as url from 'url'; import {CallCredentials} from './call-credentials'; @@ -12,9 +12,9 @@ import {Status} from './constants'; import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; -import { MetadataStatusFilterFactory } from './metadata-status-filter'; +import {MetadataStatusFilterFactory} from './metadata-status-filter'; -const { version: clientVersion } = require('../../package'); +const {version: clientVersion} = require('../../package'); const IDLE_TIMEOUT_MS = 300000; @@ -42,7 +42,7 @@ export interface ChannelOptions { 'grpc.primary_user_agent': string; 'grpc.secondary_user_agent': string; 'grpc.default_authority': string; - [key: string]: string | number; + [key: string]: string|number; } export enum ConnectivityState { @@ -53,7 +53,7 @@ export enum ConnectivityState { SHUTDOWN } -function uniformRandom(min:number, max: number) { +function uniformRandom(min: number, max: number) { return Math.random() * (max - min) + min; } @@ -71,6 +71,7 @@ export interface Channel extends EventEmitter { getConnectivityState(): ConnectivityState; close(): void; + /* tslint:disable:no-any */ addListener(event: string, listener: Function): this; emit(event: string|symbol, ...args: any[]): boolean; on(event: string, listener: Function): this; @@ -78,6 +79,7 @@ export interface Channel extends EventEmitter { prependListener(event: string, listener: Function): this; prependOnceListener(event: string, listener: Function): this; removeListener(event: string, listener: Function): this; + /* tslint:enable:no-any */ } export class Http2Channel extends EventEmitter implements Channel { @@ -92,54 +94,65 @@ export class Http2Channel extends EventEmitter implements Channel { private subChannel: http2.ClientHttp2Session|null = null; private filterStackFactory: FilterStackFactory; - private subChannelConnectCallback: ()=>void = () => {}; - private subChannelCloseCallback: ()=>void = () => {}; + private subChannelConnectCallback: () => void = () => {}; + private subChannelCloseCallback: () => void = () => {}; private backoffTimerId: NodeJS.Timer; private currentBackoff: number = INITIAL_BACKOFF_MS; private currentBackoffDeadline: Date; - private handleStateChange(oldState: ConnectivityState, newState: ConnectivityState): void { - let now: Date = new Date(); - switch(newState) { - case ConnectivityState.CONNECTING: - if (oldState === ConnectivityState.IDLE) { - this.currentBackoff = INITIAL_BACKOFF_MS; - this.currentBackoffDeadline = new Date(now.getTime() + INITIAL_BACKOFF_MS); - } else if (oldState === ConnectivityState.TRANSIENT_FAILURE) { - this.currentBackoff = Math.min(this.currentBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); - let jitterMagnitude: number = BACKOFF_JITTER * this.currentBackoff; - this.currentBackoffDeadline = new Date(now.getTime() + this.currentBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude)); - } - this.startConnecting(); - break; - case ConnectivityState.READY: - this.emit('connect'); - break; - case ConnectivityState.TRANSIENT_FAILURE: - this.subChannel = null; - this.backoffTimerId = setTimeout(() => { - this.transitionToState([ConnectivityState.TRANSIENT_FAILURE], ConnectivityState.CONNECTING); - }, this.currentBackoffDeadline.getTime() - now.getTime()); - break; - case ConnectivityState.IDLE: - case ConnectivityState.SHUTDOWN: - if (this.subChannel) { - this.subChannel.close(); - this.subChannel.removeListener('connect', this.subChannelConnectCallback); - this.subChannel.removeListener('close', this.subChannelCloseCallback); + private handleStateChange( + oldState: ConnectivityState, newState: ConnectivityState): void { + const now: Date = new Date(); + switch (newState) { + case ConnectivityState.CONNECTING: + if (oldState === ConnectivityState.IDLE) { + this.currentBackoff = INITIAL_BACKOFF_MS; + this.currentBackoffDeadline = + new Date(now.getTime() + INITIAL_BACKOFF_MS); + } else if (oldState === ConnectivityState.TRANSIENT_FAILURE) { + this.currentBackoff = Math.min( + this.currentBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); + const jitterMagnitude: number = BACKOFF_JITTER * this.currentBackoff; + this.currentBackoffDeadline = new Date( + now.getTime() + this.currentBackoff + + uniformRandom(-jitterMagnitude, jitterMagnitude)); + } + this.startConnecting(); + break; + case ConnectivityState.READY: + this.emit('connect'); + break; + case ConnectivityState.TRANSIENT_FAILURE: this.subChannel = null; - this.emit('shutdown'); - clearTimeout(this.backoffTimerId); - } - break; + this.backoffTimerId = setTimeout(() => { + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE], + ConnectivityState.CONNECTING); + }, this.currentBackoffDeadline.getTime() - now.getTime()); + break; + case ConnectivityState.IDLE: + case ConnectivityState.SHUTDOWN: + if (this.subChannel) { + this.subChannel.close(); + this.subChannel.removeListener( + 'connect', this.subChannelConnectCallback); + this.subChannel.removeListener('close', this.subChannelCloseCallback); + this.subChannel = null; + this.emit('shutdown'); + clearTimeout(this.backoffTimerId); + } + break; + default: + throw new Error('This should never happen'); } } // Transition from any of a set of oldStates to a specific newState - private transitionToState(oldStates: ConnectivityState[], newState: ConnectivityState): void { + private transitionToState( + oldStates: ConnectivityState[], newState: ConnectivityState): void { if (oldStates.indexOf(this.connectivityState) > -1) { - let oldState: ConnectivityState = this.connectivityState; + const oldState: ConnectivityState = this.connectivityState; this.connectivityState = newState; this.handleStateChange(oldState, newState); this.emit('connectivityStateChanged', newState); @@ -148,54 +161,58 @@ export class Http2Channel extends EventEmitter implements Channel { private startConnecting(): void { let subChannel: http2.ClientHttp2Session; - let secureContext = this.credentials.getSecureContext(); + const secureContext = this.credentials.getSecureContext(); if (secureContext === null) { subChannel = http2.connect(this.target); } else { const connectionOptions: http2.SecureClientSessionOptions = { secureContext, - } + }; // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. // This option is used for testing only. if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = this.options['grpc.ssl_target_name_override']!; - connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate): Error | undefined => { - return checkServerIdentity(sslTargetNameOverride, cert); - } + const sslTargetNameOverride = + this.options['grpc.ssl_target_name_override']!; + connectionOptions.checkServerIdentity = + (host: string, cert: PeerCertificate): Error|undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; connectionOptions.servername = sslTargetNameOverride; } subChannel = http2.connect(this.target, connectionOptions); } this.subChannel = subChannel; - let now = new Date(); - let connectionTimeout: number = Math.max( - this.currentBackoffDeadline.getTime() - now.getTime(), - MIN_CONNECT_TIMEOUT_MS); - let connectionTimerId: NodeJS.Timer = setTimeout(() => { - // This should trigger the 'close' event, which will send us back to TRANSIENT_FAILURE + const now = new Date(); + const connectionTimeout: number = Math.max( + this.currentBackoffDeadline.getTime() - now.getTime(), + MIN_CONNECT_TIMEOUT_MS); + const connectionTimerId: NodeJS.Timer = setTimeout(() => { + // This should trigger the 'close' event, which will send us back to + // TRANSIENT_FAILURE subChannel.close(); }, connectionTimeout); this.subChannelConnectCallback = () => { // Connection succeeded clearTimeout(connectionTimerId); - this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.READY); + this.transitionToState( + [ConnectivityState.CONNECTING], ConnectivityState.READY); }; subChannel.once('connect', this.subChannelConnectCallback); this.subChannelCloseCallback = () => { // Connection failed clearTimeout(connectionTimerId); - /* TODO(murgatroid99): verify that this works for CONNECTING->TRANSITIVE_FAILURE - * see nodejs/node#16645 */ - this.transitionToState([ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE); + /* TODO(murgatroid99): verify that this works for + * CONNECTING->TRANSITIVE_FAILURE see nodejs/node#16645 */ + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE); }; subChannel.once('close', this.subChannelCloseCallback); } constructor( - address: string, - public readonly credentials: ChannelCredentials, + address: string, readonly credentials: ChannelCredentials, private readonly options: Partial) { super(); if (credentials.getSecureContext() === null) { @@ -211,8 +228,7 @@ export class Http2Channel extends EventEmitter implements Channel { } this.filterStackFactory = new FilterStackFactory([ new CompressionFilterFactory(this), - new CallCredentialsFilterFactory(this), - new DeadlineFilterFactory(this), + new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), new MetadataStatusFilterFactory(this) ]); this.currentBackoffDeadline = new Date(); @@ -223,60 +239,60 @@ export class Http2Channel extends EventEmitter implements Channel { // Build user-agent string. this.userAgent = [ - options['grpc.primary_user_agent'], - `grpc-node-js/${clientVersion}`, + options['grpc.primary_user_agent'], `grpc-node-js/${clientVersion}`, options['grpc.secondary_user_agent'] - ].filter(e => e).join(' '); // remove falsey values first + ].filter(e => e).join(' '); // remove falsey values first } private startHttp2Stream( - authority: string, - methodName: string, - stream: Http2CallStream, + authority: string, methodName: string, stream: Http2CallStream, metadata: Metadata) { - let finalMetadata: Promise = + const finalMetadata: Promise = stream.filterStack.sendMetadata(Promise.resolve(metadata.clone())); Promise.all([finalMetadata, this.connect()]) - .then(([metadataValue]) => { - let headers = metadataValue.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = authority; - headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; - headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; - headers[HTTP2_HEADER_METHOD] = 'POST'; - headers[HTTP2_HEADER_PATH] = methodName; - headers[HTTP2_HEADER_TE] = 'trailers'; - if (this.connectivityState === ConnectivityState.READY) { - const session: http2.ClientHttp2Session = this.subChannel!; - // Prevent the HTTP/2 session from keeping the process alive. - // Note: this function is only available in Node 9 - session.unref(); - stream.attachHttp2Stream(session.request(headers)); - } else { - /* In this case, we lost the connection while finalizing - * metadata. That should be very unusual */ - setImmediate(() => { - this.startHttp2Stream(authority, methodName, stream, metadata); - }); - } - }).catch((error: Error & { code: number }) => { - // We assume the error code isn't 0 (Status.OK) - stream.cancelWithStatus(error.code || Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${error.message}`); - }); + .then(([metadataValue]) => { + const headers = metadataValue.toHttp2Headers(); + headers[HTTP2_HEADER_AUTHORITY] = authority; + headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; + headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; + headers[HTTP2_HEADER_METHOD] = 'POST'; + headers[HTTP2_HEADER_PATH] = methodName; + headers[HTTP2_HEADER_TE] = 'trailers'; + if (this.connectivityState === ConnectivityState.READY) { + const session: http2.ClientHttp2Session = this.subChannel!; + // Prevent the HTTP/2 session from keeping the process alive. + // Note: this function is only available in Node 9 + session.unref(); + stream.attachHttp2Stream(session.request(headers)); + } else { + /* In this case, we lost the connection while finalizing + * metadata. That should be very unusual */ + setImmediate(() => { + this.startHttp2Stream(authority, methodName, stream, metadata); + }); + } + }) + .catch((error: Error&{code: number}) => { + // We assume the error code isn't 0 (Status.OK) + stream.cancelWithStatus( + error.code || Status.UNKNOWN, + `Getting metadata from plugin failed with error: ${ + error.message}`); + }); } createStream(methodName: string, metadata: Metadata, options: CallOptions): - CallStream { + CallStream { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } - let finalOptions: CallStreamOptions = { + const finalOptions: CallStreamOptions = { deadline: options.deadline === undefined ? Infinity : options.deadline, credentials: options.credentials || CallCredentials.createEmpty(), flags: options.flags || 0, host: options.host || this.defaultAuthority }; - let stream: Http2CallStream = + const stream: Http2CallStream = new Http2CallStream(methodName, finalOptions, this.filterStackFactory); this.startHttp2Stream(finalOptions.host, methodName, stream, metadata); return stream; @@ -297,7 +313,8 @@ export class Http2Channel extends EventEmitter implements Channel { // been (connectivityState === IDLE). if (!this.connecting) { this.connecting = new Promise((resolve, reject) => { - this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); + this.transitionToState( + [ConnectivityState.IDLE], ConnectivityState.CONNECTING); const onConnect = () => { this.connecting = null; this.removeListener('shutdown', onShutdown); @@ -324,9 +341,11 @@ export class Http2Channel extends EventEmitter implements Channel { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } - this.transitionToState([ConnectivityState.CONNECTING, - ConnectivityState.READY, - ConnectivityState.TRANSIENT_FAILURE, - ConnectivityState.IDLE], ConnectivityState.SHUTDOWN); + this.transitionToState( + [ + ConnectivityState.CONNECTING, ConnectivityState.READY, + ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.IDLE + ], + ConnectivityState.SHUTDOWN); } } diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index b120fcc7b..39ff9fd97 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -21,7 +21,7 @@ export interface UnaryCallback { * clients. */ export class Client { - private readonly [kChannel]: Channel; + private readonly[kChannel]: Channel; constructor( address: string, credentials: ChannelCredentials, options: Partial = {}) { @@ -34,24 +34,26 @@ export class Client { waitForReady(deadline: Date|number, callback: (error: Error|null) => void): void { - let cb: (error: Error|null) => void = once(callback); - let callbackCalled = false; - let timer: NodeJS.Timer | null = null; - this[kChannel].connect().then(() => { - if (timer) { - clearTimeout(timer); - } - cb(null); - }, (err: Error) => { - // Rejection occurs if channel is shut down first. - if (timer) { - clearTimeout(timer); - } - cb(err); - }); + const cb: (error: Error|null) => void = once(callback); + const callbackCalled = false; + let timer: NodeJS.Timer|null = null; + this[kChannel].connect().then( + () => { + if (timer) { + clearTimeout(timer); + } + cb(null); + }, + (err: Error) => { + // Rejection occurs if channel is shut down first. + if (timer) { + clearTimeout(timer); + } + cb(err); + }); if (deadline !== Infinity) { let timeout: number; - let now: number = (new Date).getTime(); + const now: number = (new Date()).getTime(); if (deadline instanceof Date) { timeout = deadline.getTime() - now; } else { @@ -94,7 +96,8 @@ export class Client { if (status.code === Status.OK) { callback(null, responseMessage as ResponseType); } else { - const error: ServiceError = Object.assign(new Error(status.details), status); + const error: ServiceError = + Object.assign(new Error(status.details), status); callback(error); } }); @@ -156,7 +159,7 @@ export class Client { const call: CallStream = this[kChannel].createStream(method, metadata, options); const message: Buffer = serialize(argument); - const writeObj: WriteObject = {message: message}; + const writeObj: WriteObject = {message}; writeObj.flags = options.flags; call.write(writeObj); call.end(); @@ -238,7 +241,7 @@ export class Client { const call: CallStream = this[kChannel].createStream(method, metadata, options); const message: Buffer = serialize(argument); - const writeObj: WriteObject = {message: message}; + const writeObj: WriteObject = {message}; writeObj.flags = options.flags; call.write(writeObj); call.end(); diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index 428ed8a95..2424039e0 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -4,14 +4,14 @@ import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; -const units: [string, number][] = +const units: Array<[string, number]> = [['m', 1], ['S', 1000], ['M', 60 * 1000], ['H', 60 * 60 * 1000]]; function getDeadline(deadline: number) { - let now = (new Date()).getTime(); - let timeoutMs = Math.max(deadline - now, 0); - for (let [unit, factor] of units) { - let amount = timeoutMs / factor; + const now = (new Date()).getTime(); + const timeoutMs = Math.max(deadline - now, 0); + for (const [unit, factor] of units) { + const amount = timeoutMs / factor; if (amount < 1e8) { return String(Math.ceil(amount)) + unit; } @@ -20,19 +20,19 @@ function getDeadline(deadline: number) { } export class DeadlineFilter extends BaseFilter implements Filter { - private timer: NodeJS.Timer | null = null; + private timer: NodeJS.Timer|null = null; private deadline: number; constructor( private readonly channel: Http2Channel, private readonly callStream: CallStream) { super(); - let callDeadline = callStream.getDeadline(); + const callDeadline = callStream.getDeadline(); if (callDeadline instanceof Date) { this.deadline = callDeadline.getTime(); } else { this.deadline = callDeadline; } - let now: number = (new Date()).getTime(); + const now: number = (new Date()).getTime(); let timeout = this.deadline - now; if (timeout < 0) { timeout = 0; diff --git a/packages/grpc-js-core/src/events.ts b/packages/grpc-js-core/src/events.ts index 591120d10..ad96efd57 100644 --- a/packages/grpc-js-core/src/events.ts +++ b/packages/grpc-js-core/src/events.ts @@ -23,7 +23,9 @@ export interface EmitterAugmentation2 { emit(event: Name, arg1: Arg1, arg2: Arg2): boolean; on(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; once(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; - prependListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; - prependOnceListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; + prependListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): + this; + prependOnceListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): + this; removeListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; } diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js-core/src/filter-stack.ts index 7a661692c..66337c3ab 100644 --- a/packages/grpc-js-core/src/filter-stack.ts +++ b/packages/grpc-js-core/src/filter-stack.ts @@ -25,7 +25,7 @@ export class FilterStack implements Filter { } export class FilterStackFactory implements FilterFactory { - constructor(private readonly factories: FilterFactory[]) {} + constructor(private readonly factories: Array>) {} createFilter(callStream: CallStream): FilterStack { return new FilterStack( diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 8c9cb32ce..9b6cea51a 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -1,68 +1,78 @@ -import { CallCredentials } from './call-credentials'; -import { ChannelCredentials } from './channel-credentials'; -import { Client } from './client'; -import { Status} from './constants'; -import { makeClientConstructor, loadPackageDefinition } from './make-client'; -import { Metadata } from './metadata'; -import { IncomingHttpHeaders } from 'http'; +import {IncomingHttpHeaders} from 'http'; + +import {CallCredentials} from './call-credentials'; +import {ChannelCredentials} from './channel-credentials'; +import {Client} from './client'; +import {Status} from './constants'; +import {loadPackageDefinition, makeClientConstructor} from './make-client'; +import {Metadata} from './metadata'; export interface OAuth2Client { - getRequestMetadata: (url: string, callback: (err: Error|null, headers?: { Authorization: string }) => void) => void; + getRequestMetadata: (url: string, callback: (err: Error|null, headers?: { + Authorization: string + }) => void) => void; } /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want -export const credentials = Object.assign({ - /** - * Create a gRPC credential from a Google credential object. - * @param googleCredentials The authentication client to use. - * @return The resulting CallCredentials object. - */ - createFromGoogleCredential: (googleCredentials: OAuth2Client): CallCredentials => { - return CallCredentials.createFromMetadataGenerator((options, callback) => { - googleCredentials.getRequestMetadata(options.service_url, (err, headers) => { - if (err) { - callback(err); - return; - } - const metadata = new Metadata(); - metadata.add('authorization', headers!.Authorization); - callback(null, metadata); - }); - }); - }, - - /** - * Combine a ChannelCredentials with any number of CallCredentials into a - * single ChannelCredentials object. - * @param channelCredentials The ChannelCredentials object. - * @param callCredentials Any number of CallCredentials objects. - * @return The resulting ChannelCredentials object. - */ - combineChannelCredentials: ( - channelCredentials: ChannelCredentials, - ...callCredentials: CallCredentials[]): ChannelCredentials => { - return callCredentials.reduce((acc, other) => acc.compose(other), channelCredentials); - }, - - /** - * Combine any number of CallCredentials into a single CallCredentials object. - * @param first The first CallCredentials object. - * @param additional Any number of additional CallCredentials objects. - * @return The resulting CallCredentials object. - */ - combineCallCredentials: ( - first: CallCredentials, - ...additional: CallCredentials[]): CallCredentials => { - return additional.reduce((acc, other) => acc.compose(other), first); - } -}, ChannelCredentials, CallCredentials); +export const credentials = Object.assign( + { + /** + * Create a gRPC credential from a Google credential object. + * @param googleCredentials The authentication client to use. + * @return The resulting CallCredentials object. + */ + createFromGoogleCredential: (googleCredentials: OAuth2Client): + CallCredentials => { + return CallCredentials.createFromMetadataGenerator( + (options, callback) => { + googleCredentials.getRequestMetadata( + options.service_url, (err, headers) => { + if (err) { + callback(err); + return; + } + const metadata = new Metadata(); + metadata.add('authorization', headers!.Authorization); + callback(null, metadata); + }); + }); + }, + + /** + * Combine a ChannelCredentials with any number of CallCredentials into a + * single ChannelCredentials object. + * @param channelCredentials The ChannelCredentials object. + * @param callCredentials Any number of CallCredentials objects. + * @return The resulting ChannelCredentials object. + */ + combineChannelCredentials: + (channelCredentials: ChannelCredentials, + ...callCredentials: CallCredentials[]): ChannelCredentials => { + return callCredentials.reduce( + (acc, other) => acc.compose(other), channelCredentials); + }, + + /** + * Combine any number of CallCredentials into a single CallCredentials + * object. + * @param first The first CallCredentials object. + * @param additional Any number of additional CallCredentials objects. + * @return The resulting CallCredentials object. + */ + combineCallCredentials: ( + first: CallCredentials, ...additional: CallCredentials[]): + CallCredentials => { + return additional.reduce((acc, other) => acc.compose(other), first); + } + }, + ChannelCredentials, CallCredentials); /**** Metadata ****/ -export { Metadata }; +export {Metadata}; /**** Constants ****/ @@ -86,47 +96,63 @@ export { */ export const closeClient = (client: Client) => client.close(); -export const waitForClientReady = (client: Client, deadline: Date|number, callback: (error: Error | null) => void) => client.waitForReady(deadline, callback); +export const waitForClientReady = + (client: Client, deadline: Date|number, + callback: (error: Error|null) => void) => + client.waitForReady(deadline, callback); /**** Unimplemented function stubs ****/ +/* tslint:disable:no-any variable-name */ + export const loadObject = (value: any, options: any) => { - throw new Error('Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); -} + throw new Error( + 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); +}; export const load = (filename: any, format: any, options: any) => { - throw new Error('Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); -} + throw new Error( + 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); +}; export const setLogger = (logger: any) => { throw new Error('Not yet implemented'); -} +}; export const setLogVerbosity = (verbosity: any) => { throw new Error('Not yet implemented'); -} +}; export const Server = (options: any) => { throw new Error('Not yet implemented'); -} +}; export const ServerCredentials = { - createSsl: (rootCerts: any, keyCertPairs: any, checkClientCertificate: any) => { - throw new Error('Not yet implemented'); - }, + createSsl: + (rootCerts: any, keyCertPairs: any, checkClientCertificate: any) => { + throw new Error('Not yet implemented'); + }, createInsecure: () => { throw new Error('Not yet implemented'); } -} +}; export const getClientChannel = (client: any) => { throw new Error('Not available in this library'); -} +}; -export const StatusBuilder = () => { throw new Error('Not yet implemented'); } +export const StatusBuilder = () => { + throw new Error('Not yet implemented'); +}; -export const ListenerBuilder = () => { throw new Error('Not yet implemented'); } +export const ListenerBuilder = () => { + throw new Error('Not yet implemented'); +}; -export const InterceptorBuilder = () => { throw new Error('Not yet implemented'); } +export const InterceptorBuilder = () => { + throw new Error('Not yet implemented'); +}; -export const InterceptingCall = () => { throw new Error('Not yet implemented'); } +export const InterceptingCall = () => { + throw new Error('Not yet implemented'); +}; diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index f5433f57d..7d82444f0 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -1,17 +1,14 @@ -import { Metadata } from "./metadata"; -import { Client, UnaryCallback } from "./client"; -import { CallOptions } from "./call-stream"; import * as _ from 'lodash'; -import { ChannelCredentials } from "./channel-credentials"; -import { ChannelOptions } from "./channel"; -export interface Serialize { - (value: T): Buffer; -} +import {CallOptions} from './call-stream'; +import {ChannelOptions} from './channel'; +import {ChannelCredentials} from './channel-credentials'; +import {Client, UnaryCallback} from './client'; +import {Metadata} from './metadata'; -export interface Deserialize { - (bytes: Buffer): T; -} +export interface Serialize { (value: T): Buffer; } + +export interface Deserialize { (bytes: Buffer): T; } export interface MethodDefinition { path: string; @@ -28,18 +25,11 @@ export interface ServiceDefinition { [index: string]: MethodDefinition; } -export interface PackageDefinition { - [index: string]: ServiceDefinition; -} +export interface PackageDefinition { [index: string]: ServiceDefinition; } -function getDefaultValues(metadata?: Metadata, options?: T): { - metadata: Metadata; - options: Partial; -} { - return { - metadata: metadata || new Metadata(), - options: options || {} - }; +function getDefaultValues(metadata?: Metadata, options?: T): + {metadata: Metadata; options: Partial;} { + return {metadata: metadata || new Metadata(), options: options || {}}; } /** @@ -60,9 +50,9 @@ export interface ServiceClient extends Client { export interface ServiceClientConstructor { new(address: string, credentials: ChannelCredentials, - options?: Partial): ServiceClient; + options?: Partial): ServiceClient; service: ServiceDefinition; -}; +} /** * Creates a constructor for a client with the given methods, as specified in @@ -111,23 +101,24 @@ export function makeClientConstructor( } const serialize = attrs.requestSerialize; const deserialize = attrs.responseDeserialize; - const methodFunc = _.partial(requesterFuncs[methodType], attrs.path, - serialize, deserialize); + const methodFunc = _.partial( + requesterFuncs[methodType], attrs.path, serialize, deserialize); ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method _.assign(ServiceClientImpl.prototype[name], attrs); if (attrs.originalName) { - ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; + ServiceClientImpl.prototype[attrs.originalName] = + ServiceClientImpl.prototype[name]; } }); ServiceClientImpl.service = methods; return ServiceClientImpl; -}; +} export type GrpcObject = { - [index: string]: GrpcObject | ServiceClientConstructor; + [index: string]: GrpcObject|ServiceClientConstructor; }; /** @@ -135,20 +126,23 @@ export type GrpcObject = { * @param packageDef The package definition object. * @return The resulting gRPC object. */ -export function loadPackageDefinition(packageDef: PackageDefinition): GrpcObject { +export function loadPackageDefinition(packageDef: PackageDefinition): + GrpcObject { const result: GrpcObject = {}; for (const serviceFqn in packageDef) { - const service = packageDef[serviceFqn]; - const nameComponents = serviceFqn.split('.'); - const serviceName = nameComponents[nameComponents.length-1]; - let current = result; - for (const packageName of nameComponents.slice(0, -1)) { - if (!current[packageName]) { - current[packageName] = {}; + if (packageDef.hasOwnProperty(serviceFqn)) { + const service = packageDef[serviceFqn]; + const nameComponents = serviceFqn.split('.'); + const serviceName = nameComponents[nameComponents.length - 1]; + let current = result; + for (const packageName of nameComponents.slice(0, -1)) { + if (!current[packageName]) { + current[packageName] = {}; + } + current = current[packageName] as GrpcObject; } - current = current[packageName] as GrpcObject; + current[serviceName] = makeClientConstructor(service, serviceName, {}); } - current[serviceName] = makeClientConstructor(service, serviceName, {}); } return result; } diff --git a/packages/grpc-js-core/src/metadata-status-filter.ts b/packages/grpc-js-core/src/metadata-status-filter.ts index 43d42ea64..4bb869b7a 100644 --- a/packages/grpc-js-core/src/metadata-status-filter.ts +++ b/packages/grpc-js-core/src/metadata-status-filter.ts @@ -1,19 +1,20 @@ import {CallStream} from './call-stream'; -import {Channel} from './channel'; -import {BaseFilter, Filter, FilterFactory} from './filter'; import {StatusObject} from './call-stream'; +import {Channel} from './channel'; import {Status} from './constants'; +import {BaseFilter, Filter, FilterFactory} from './filter'; export class MetadataStatusFilter extends BaseFilter implements Filter { async receiveTrailers(status: Promise): Promise { - let { code, details, metadata } = await status; + // tslint:disable-next-line:prefer-const + let {code, details, metadata} = await status; if (code !== Status.UNKNOWN) { // we already have a known status, so don't assign a new one. - return { code, details, metadata }; + return {code, details, metadata}; } const metadataMap = metadata.getMap(); if (typeof metadataMap['grpc-status'] === 'string') { - let receivedCode = Number(metadataMap['grpc-status']); + const receivedCode = Number(metadataMap['grpc-status']); if (receivedCode in Status) { code = receivedCode; } @@ -23,7 +24,7 @@ export class MetadataStatusFilter extends BaseFilter implements Filter { details = decodeURI(metadataMap['grpc-message'] as string); metadata.remove('grpc-message'); } - return { code, details, metadata }; + return {code, details, metadata}; } } diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 84e9160eb..3f4b19d02 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -1,9 +1,9 @@ import * as http2 from 'http2'; import {forOwn} from 'lodash'; -export type MetadataValue = string | Buffer; +export type MetadataValue = string|Buffer; -export interface MetadataObject { [key: string]: Array; } +export interface MetadataObject { [key: string]: MetadataValue[]; } function cloneMetadataObject(repr: MetadataObject): MetadataObject { const result: MetadataObject = {}; @@ -113,7 +113,7 @@ export class Metadata { * @param key The key whose value should be retrieved. * @return A list of values associated with the given key. */ - get(key: string): Array { + get(key: string): MetadataValue[] { key = normalizeKey(key); validate(key); if (Object.prototype.hasOwnProperty.call(this.internalRepr, key)) { @@ -144,7 +144,7 @@ export class Metadata { * @return The newly cloned object. */ clone(): Metadata { - let newMetadata = new Metadata(); + const newMetadata = new Metadata(); newMetadata.internalRepr = cloneMetadataObject(this.internalRepr); return newMetadata; } @@ -181,7 +181,7 @@ export class Metadata { }); return result; } - + // For compatibility with the other Metadata implementation private _getCoreRepresentation() { return this.internalRepr; @@ -201,8 +201,9 @@ export class Metadata { result.add(key, Buffer.from(value, 'base64')); }); } else if (values !== undefined) { - values.split(',').map(v => v.trim()).forEach(v => - result.add(key, Buffer.from(v, 'base64'))); + values.split(',') + .map(v => v.trim()) + .forEach(v => result.add(key, Buffer.from(v, 'base64'))); } } else { if (Array.isArray(values)) { @@ -210,8 +211,7 @@ export class Metadata { result.add(key, value); }); } else if (values !== undefined) { - values.split(',').map(v => v.trim()).forEach(v => - result.add(key, v)); + values.split(',').map(v => v.trim()).forEach(v => result.add(key, v)); } } }); diff --git a/packages/grpc-js-core/src/object-stream.ts b/packages/grpc-js-core/src/object-stream.ts index 48988daad..556883c67 100644 --- a/packages/grpc-js-core/src/object-stream.ts +++ b/packages/grpc-js-core/src/object-stream.ts @@ -1,14 +1,15 @@ import {Duplex, Readable, Writable} from 'stream'; import {EmitterAugmentation1} from './events'; +// tslint:disable:no-any + export interface IntermediateObjectReadable extends Readable { read(size?: number): any&T; } export type ObjectReadable = { read(size?: number): T; -} & EmitterAugmentation1<'data', T> - & IntermediateObjectReadable; +}&EmitterAugmentation1<'data', T>&IntermediateObjectReadable; export interface IntermediateObjectWritable extends Writable { _write(chunk: any&T, encoding: string, callback: Function): void; @@ -39,4 +40,4 @@ export type ObjectDuplex = { end(): void; end(chunk: T, cb?: Function): void; end(chunk: T, encoding?: any, cb?: Function): void; -} & Duplex & ObjectWritable & ObjectReadable; +}&Duplex&ObjectWritable&ObjectReadable; diff --git a/packages/grpc-js-core/test/common.ts b/packages/grpc-js-core/test/common.ts index 487ced1f2..c36d6fc47 100644 --- a/packages/grpc-js-core/test/common.ts +++ b/packages/grpc-js-core/test/common.ts @@ -4,6 +4,7 @@ export function mockFunction(): never { throw new Error('Not implemented'); } +// tslint:disable-next-line:no-namespace export namespace assert2 { const toCall = new Map<() => void, number>(); const afterCallsQueue: Array<() => void> = []; @@ -17,7 +18,9 @@ export namespace assert2 { try { return fn(); } catch (e) { - assert.throws(() => {throw e}); + assert.throws(() => { + throw e; + }); throw e; // for type safety only } } @@ -42,7 +45,9 @@ export namespace assert2 { * Wraps a function to keep track of whether it was called or not. * @param fn The function to wrap. */ - export function mustCall(fn: (...args: any[]) => T): (...args: any[]) => T { + // tslint:disable:no-any + export function mustCall(fn: (...args: any[]) => T): + (...args: any[]) => T { const existingValue = toCall.get(fn); if (existingValue !== undefined) { toCall.set(fn, existingValue + 1); @@ -62,6 +67,7 @@ export namespace assert2 { return result; }; } + // tslint:enable:no-any /** * Calls the given function when every function that was wrapped with diff --git a/packages/grpc-js-core/test/test-call-credentials.ts b/packages/grpc-js-core/test/test-call-credentials.ts index 64cfe140e..fffe5a196 100644 --- a/packages/grpc-js-core/test/test-call-credentials.ts +++ b/packages/grpc-js-core/test/test-call-credentials.ts @@ -27,7 +27,8 @@ describe('CallCredentials', () => { describe('createFromMetadataGenerator', () => { it('should accept a metadata generator', () => { assert.doesNotThrow( - () => CallCredentials.createFromMetadataGenerator(generateFromServiceURL)); + () => CallCredentials.createFromMetadataGenerator( + generateFromServiceURL)); }); }); @@ -58,11 +59,12 @@ describe('CallCredentials', () => { describe('generateMetadata', () => { it('should call the function passed to createFromMetadataGenerator', async () => { - const callCredentials = - CallCredentials.createFromMetadataGenerator(generateFromServiceURL); + const callCredentials = CallCredentials.createFromMetadataGenerator( + generateFromServiceURL); let metadata: Metadata; try { - metadata = await callCredentials.generateMetadata({service_url: 'foo'}); + metadata = + await callCredentials.generateMetadata({service_url: 'foo'}); } catch (err) { throw err; } diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index f3a4f6179..aff6ed635 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -1,32 +1,33 @@ import * as assert from 'assert'; -import { CallCredentials } from '../src/call-credentials'; -import { Http2CallStream } from '../src/call-stream'; -import { mockFunction, assert2 } from './common'; -import { Status } from '../src/constants'; -import { EventEmitter } from 'events'; -import { FilterStackFactory } from '../src/filter-stack'; +import {EventEmitter} from 'events'; import * as http2 from 'http2'; -import { forOwn, range } from 'lodash'; -import { Metadata } from '../src/metadata'; +import {forOwn, range} from 'lodash'; import * as stream from 'stream'; +import {CallCredentials} from '../src/call-credentials'; +import {Http2CallStream} from '../src/call-stream'; +import {Status} from '../src/constants'; +import {FilterStackFactory} from '../src/filter-stack'; +import {Metadata} from '../src/metadata'; + +import {assert2, mockFunction} from './common'; + interface DataFrames { - payload: Buffer, - frameLengths: number[] + payload: Buffer; + frameLengths: number[]; } -const { - HTTP2_HEADER_STATUS -} = http2.constants; +const {HTTP2_HEADER_STATUS} = http2.constants; function serialize(data: string): Buffer { const header: Buffer = Buffer.alloc(5); - header.writeUInt8(0, 0); // TODO: Uncompressed only + header.writeUInt8(0, 0); // TODO: Uncompressed only header.writeInt32BE(data.length, 1); return Buffer.concat([header, Buffer.from(data, 'utf8')]); } -class ClientHttp2StreamMock extends stream.Duplex implements http2.ClientHttp2Stream { +class ClientHttp2StreamMock extends stream.Duplex implements + http2.ClientHttp2Stream { constructor(private readonly dataFrames: DataFrames) { super(); } @@ -38,13 +39,15 @@ class ClientHttp2StreamMock extends stream.Duplex implements http2.ClientHttp2St } bytesRead = 0; dataFrame = 0; - aborted: boolean = false; - closed: boolean = false; - destroyed: boolean = false; - pending: boolean = false; - rstCode: number = 0; + aborted = false; + closed = false; + destroyed = false; + pending = false; + rstCode = 0; + // tslint:disable:no-any session: http2.Http2Session = {} as any; state: http2.StreamState = {} as any; + // tslint:enable:no-any close = mockFunction; priority = mockFunction; rstStream = mockFunction; @@ -58,7 +61,7 @@ class ClientHttp2StreamMock extends stream.Duplex implements http2.ClientHttp2St if (this.dataFrame === this.dataFrames.frameLengths.length) { if (this.bytesRead < this.dataFrames.payload.length) { this.push(this.dataFrames.payload.slice( - this.bytesRead, this.dataFrames.payload.length)); + this.bytesRead, this.dataFrames.payload.length)); } this.push(null); return; @@ -66,7 +69,7 @@ class ClientHttp2StreamMock extends stream.Duplex implements http2.ClientHttp2St const from = this.bytesRead; this.bytesRead += this.dataFrames.frameLengths[this.dataFrame++]; this.push(this.dataFrames.payload.slice(from, this.bytesRead)); - }; + } _write(chunk: Buffer, encoding: string, cb: Function) { this.emit('write', chunk); cb(); @@ -81,28 +84,28 @@ describe('CallStream', () => { host: '' }; const filterStackFactory = new FilterStackFactory([]); - const message = 'eat this message'; // 16 bytes + const message = 'eat this message'; // 16 bytes beforeEach(() => { assert2.clearMustCalls(); }); - it('should emit a metadata event when it receives a response event', (done) => { - const responseMetadata = new Metadata(); - responseMetadata.add('key', 'value'); - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); + it('should emit a metadata event when it receives a response event', + (done) => { + const responseMetadata = new Metadata(); + responseMetadata.add('key', 'value'); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); - callStream.once('metadata', assert2.mustCall((metadata) => { - assert.deepStrictEqual(metadata.get('key'), ['value']); - })); - callStream.attachHttp2Stream(http2Stream); - http2Stream.emitResponse(200, responseMetadata); - assert2.afterMustCallsSatisfied(done); - }); + const http2Stream = new ClientHttp2StreamMock( + {payload: Buffer.alloc(0), frameLengths: []}); + callStream.once('metadata', assert2.mustCall((metadata) => { + assert.deepStrictEqual(metadata.get('key'), ['value']); + })); + callStream.attachHttp2Stream(http2Stream); + http2Stream.emitResponse(200, responseMetadata); + assert2.afterMustCallsSatisfied(done); + }); describe('should end a call with an error if a stream was closed', () => { const c = http2.constants; @@ -126,14 +129,13 @@ describe('CallStream', () => { keys.forEach((key) => { const value = errorCodeMapping[key]; // A null value indicates: behavior isn't specified, so skip this test. - let maybeSkip = (fn: typeof it) => value ? fn : fn.skip; + const maybeSkip = (fn: typeof it) => value ? fn : fn.skip; maybeSkip(it)(`for error code ${key}`, () => { return new Promise((resolve, reject) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock( + {payload: Buffer.alloc(0), frameLengths: []}); callStream.attachHttp2Stream(http2Stream); callStream.once('status', (status) => { try { @@ -150,7 +152,8 @@ describe('CallStream', () => { }); it('should have functioning getters', (done) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); assert.strictEqual(callStream.getCredentials(), callStreamArgs.credentials); assert.strictEqual(callStream.getStatus(), null); @@ -166,11 +169,10 @@ describe('CallStream', () => { describe('attachHttp2Stream', () => { it('should handle an empty message', (done) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: serialize(''), - frameLengths: [] - }); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = + new ClientHttp2StreamMock({payload: serialize(''), frameLengths: []}); callStream.once('data', assert2.mustCall((buffer) => { assert.strictEqual(buffer.toString('utf8'), ''); })); @@ -178,65 +180,57 @@ describe('CallStream', () => { assert2.afterMustCallsSatisfied(done); }); - [ - { - description: 'all data is supplied in a single frame', - frameLengths: [] - }, - { - description: 'frames are split along header field delimiters', - frameLengths: [1, 4] - }, - { - description: 'portions of header fields are split between different frames', - frameLengths: [2, 1, 1, 4] - }, - { - description: 'frames are split into bytes', - frameLengths: range(0, 20).map(() => 1) - } - ].forEach((testCase: { description: string, frameLengths: number[] }) => { - it(`should handle a short message where ${testCase.description}`, (done) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: serialize(message), // 21 bytes - frameLengths: testCase.frameLengths - }); - callStream.once('data', assert2.mustCall((buffer) => { - assert.strictEqual(buffer.toString('utf8'), message); - })); - callStream.once('end', assert2.mustCall(() => {})); - callStream.attachHttp2Stream(http2Stream); - assert2.afterMustCallsSatisfied(done); - }); + [{description: 'all data is supplied in a single frame', frameLengths: []}, + { + description: 'frames are split along header field delimiters', + frameLengths: [1, 4] + }, + { + description: + 'portions of header fields are split between different frames', + frameLengths: [2, 1, 1, 4] + }, + { + description: 'frames are split into bytes', + frameLengths: range(0, 20).map(() => 1) + }].forEach((testCase: {description: string, frameLengths: number[]}) => { + it(`should handle a short message where ${testCase.description}`, + (done) => { + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock({ + payload: serialize(message), // 21 bytes + frameLengths: testCase.frameLengths + }); + callStream.once('data', assert2.mustCall((buffer) => { + assert.strictEqual(buffer.toString('utf8'), message); + })); + callStream.once('end', assert2.mustCall(() => {})); + callStream.attachHttp2Stream(http2Stream); + assert2.afterMustCallsSatisfied(done); + }); }); - [ - { - description: 'all data is supplied in a single frame', - frameLengths: [] - }, - { - description: 'frames are split between delimited messages', - frameLengths: [21] - }, - { - description: 'frames are split within messages', - frameLengths: [10, 22] - }, - { - description: 'part of 2nd message\'s header is in first frame', - frameLengths: [24] - }, - { - description: 'frames are split into bytes', - frameLengths: range(0, 41).map(() => 1) - } - ].forEach((testCase: { description: string, frameLengths: number[] }) => { + [{description: 'all data is supplied in a single frame', frameLengths: []}, + { + description: 'frames are split between delimited messages', + frameLengths: [21] + }, + {description: 'frames are split within messages', frameLengths: [10, 22]}, + { + description: 'part of 2nd message\'s header is in first frame', + frameLengths: [24] + }, + { + description: 'frames are split into bytes', + frameLengths: range(0, 41).map(() => 1) + }].forEach((testCase: {description: string, frameLengths: number[]}) => { it(`should handle two messages where ${testCase.description}`, (done) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.concat([serialize(message), serialize(message)]), // 42 bytes + payload: Buffer.concat( + [serialize(message), serialize(message)]), // 42 bytes frameLengths: testCase.frameLengths }); callStream.once('data', assert2.mustCall((buffer) => { @@ -252,11 +246,10 @@ describe('CallStream', () => { }); it('should send buffered writes', (done) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock( + {payload: Buffer.alloc(0), frameLengths: []}); let streamFlushed = false; http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { const dataLength = chunk.readInt32BE(1); @@ -265,9 +258,7 @@ describe('CallStream', () => { assert.strictEqual(encodedMessage, message); streamFlushed = true; })); - callStream.write({ - message: Buffer.from(message) - }, assert2.mustCall(() => { + callStream.write({message: Buffer.from(message)}, assert2.mustCall(() => { // Ensure this is called only after contents are written to http2Stream assert.ok(streamFlushed); })); @@ -276,32 +267,30 @@ describe('CallStream', () => { assert2.afterMustCallsSatisfied(done); }); - it('should cause data chunks in write calls afterward to be written to the given stream', (done) => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); - http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { - const dataLength = chunk.readInt32BE(1); - const encodedMessage = chunk.slice(5).toString('utf8'); - assert.strictEqual(dataLength, message.length); - assert.strictEqual(encodedMessage, message); - })); - callStream.attachHttp2Stream(http2Stream); - callStream.write({ - message: Buffer.from(message) - }, assert2.mustCall(() => {})); - callStream.end(assert2.mustCall(() => {})); - assert2.afterMustCallsSatisfied(done); - }); + it('should cause data chunks in write calls afterward to be written to the given stream', + (done) => { + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock( + {payload: Buffer.alloc(0), frameLengths: []}); + http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { + const dataLength = chunk.readInt32BE(1); + const encodedMessage = chunk.slice(5).toString('utf8'); + assert.strictEqual(dataLength, message.length); + assert.strictEqual(encodedMessage, message); + })); + callStream.attachHttp2Stream(http2Stream); + callStream.write( + {message: Buffer.from(message)}, assert2.mustCall(() => {})); + callStream.end(assert2.mustCall(() => {})); + assert2.afterMustCallsSatisfied(done); + }); it('should handle underlying stream errors', () => { - const callStream = new Http2CallStream('foo', callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [] - }); + const callStream = + new Http2CallStream('foo', callStreamArgs, filterStackFactory); + const http2Stream = new ClientHttp2StreamMock( + {payload: Buffer.alloc(0), frameLengths: []}); callStream.once('status', assert2.mustCall((status) => { assert.strictEqual(status.code, Status.INTERNAL); })); diff --git a/packages/grpc-js-core/test/test-channel-credentials.ts b/packages/grpc-js-core/test/test-channel-credentials.ts index 15dfbfac0..aa9e20330 100644 --- a/packages/grpc-js-core/test/test-channel-credentials.ts +++ b/packages/grpc-js-core/test/test-channel-credentials.ts @@ -32,6 +32,7 @@ class CallCredentialsMock implements CallCredentials { } } +// tslint:disable-next-line:no-any const readFile: (...args: any[]) => Promise = promisify(fs.readFile); // A promise which resolves to loaded files in the form { ca, key, cert } const pFixtures = Promise From cad47e4de8a2d19d6c815922d01094e16d85c100 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 19 Apr 2018 16:10:48 -0700 Subject: [PATCH 0204/1899] Update benchmark code to handle both implementations --- test/package.json | 4 +++- test/performance/benchmark_client.js | 16 +++++++++++----- test/performance/benchmark_client_express.js | 2 +- test/performance/benchmark_server.js | 19 ++++++++++++------- test/performance/benchmark_server_express.js | 4 ++-- test/performance/worker.js | 15 ++++++++++----- 6 files changed, 39 insertions(+), 21 deletions(-) diff --git a/test/package.json b/test/package.json index 306e3f739..764232971 100644 --- a/test/package.json +++ b/test/package.json @@ -14,7 +14,9 @@ } ], "dependencies": { + "express": "^4.16.3", "google-auth-library": "^0.9.2", - "lodash": "^4.17.4" + "lodash": "^4.17.4", + "poisson-process": "^1.0.0" } } diff --git a/test/performance/benchmark_client.js b/test/performance/benchmark_client.js index 974edc01f..7da0003b6 100644 --- a/test/performance/benchmark_client.js +++ b/test/performance/benchmark_client.js @@ -36,10 +36,16 @@ var Histogram = require('./histogram'); var genericService = require('./generic_service'); // TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); -var serviceProto = grpc.load({ - root: __dirname + '/../packages/grpc-native-core/ext/grpc', - file: 'src/proto/grpc/testing/services.proto'}).grpc.testing; +var grpc = require('../any_grpc').client; +var protoLoader = require('../../packages/grpc-protobufjs'); +var protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/services.proto', + {keepCase: true, + defaults: true, + enums: String, + oneofs: true, + include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** * Create a buffer filled with size zeroes @@ -82,7 +88,7 @@ function BenchmarkClient(server_targets, channels, histogram_params, if (security_params) { var ca_path; if (security_params.use_test_ca) { - ca_path = path.join(__dirname, '../test/data/ca.pem'); + ca_path = path.join(__dirname, '../data/ca.pem'); var ca_data = fs.readFileSync(ca_path); creds = grpc.credentials.createSsl(ca_data); } else { diff --git a/test/performance/benchmark_client_express.js b/test/performance/benchmark_client_express.js index 815843fed..f8be6d45e 100644 --- a/test/performance/benchmark_client_express.js +++ b/test/performance/benchmark_client_express.js @@ -60,7 +60,7 @@ function BenchmarkClient(server_targets, channels, histogram_params, protocol = https; this.request = _.bind(https.request, https); if (security_params.use_test_ca) { - ca_path = path.join(__dirname, '../test/data/ca.pem'); + ca_path = path.join(__dirname, '../data/ca.pem'); var ca_data = fs.readFileSync(ca_path); options.ca = ca_data; } diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index a39c5ec6e..0cfa8506e 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -30,11 +30,16 @@ var util = require('util'); var genericService = require('./generic_service'); -// TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); -var serviceProto = grpc.load({ - root: __dirname + '/../packages/grpc-native-core/ext/grpc', - file: 'src/proto/grpc/testing/services.proto'}).grpc.testing; +var grpc = require('../any_grpc').server; +var protoLoader = require('../../packages/grpc-protobufjs'); +var protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/services.proto', + {keepCase: true, + defaults: true, + enums: String, + oneofs: true, + include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** * Create a buffer filled with size zeroes @@ -106,8 +111,8 @@ function BenchmarkServer(host, port, tls, generic, response_size) { var server_creds; var host_override; if (tls) { - var key_path = path.join(__dirname, '../test/data/server1.key'); - var pem_path = path.join(__dirname, '../test/data/server1.pem'); + var key_path = path.join(__dirname, '../data/server1.key'); + var pem_path = path.join(__dirname, '../data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); diff --git a/test/performance/benchmark_server_express.js b/test/performance/benchmark_server_express.js index 73e54091a..657006f95 100644 --- a/test/performance/benchmark_server_express.js +++ b/test/performance/benchmark_server_express.js @@ -47,8 +47,8 @@ function BenchmarkServer(host, port, tls, generic, response_size) { this.input_port = port; if (tls) { var credentials = {}; - var key_path = path.join(__dirname, '../test/data/server1.key'); - var pem_path = path.join(__dirname, '../test/data/server1.pem'); + var key_path = path.join(__dirname, '../data/server1.key'); + var pem_path = path.join(__dirname, '../data/server1.pem'); var key_data = fs.readFileSync(key_path); var pem_data = fs.readFileSync(pem_path); diff --git a/test/performance/worker.js b/test/performance/worker.js index 5a3f114ec..d138536f5 100644 --- a/test/performance/worker.js +++ b/test/performance/worker.js @@ -21,11 +21,16 @@ var console = require('console'); var WorkerServiceImpl = require('./worker_service_impl'); -// TODO(murgatroid99): use multiple grpc implementations -var grpc = require('grpc'); -var serviceProto = grpc.load({ - root: __dirname + '/../packages/grpc-native-core/ext/grpc', - file: 'src/proto/grpc/testing/services.proto'}).grpc.testing; +var grpc = require('../any_grpc').server; +var protoLoader = require('../../packages/grpc-protobufjs'); +var protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/services.proto', + {keepCase: true, + defaults: true, + enums: String, + oneofs: true, + include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; function runServer(port, benchmark_impl) { var server_creds = grpc.ServerCredentials.createInsecure(); From 0b075f18bb4c041f6c188313fea4215269e5ce61 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 20 Apr 2018 14:46:51 -0700 Subject: [PATCH 0205/1899] Add subchannel error handler, copy waitForReady wrapper from 1.11 --- packages/grpc-js-core/src/channel.ts | 1 + packages/grpc-js-core/src/index.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index e710b733e..44dcfae74 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -191,6 +191,7 @@ export class Http2Channel extends EventEmitter implements Channel { ConnectivityState.TRANSIENT_FAILURE); }; subChannel.once('close', this.subChannelCloseCallback); + subChannel.once('error', this.subChannelCloseCallback); } constructor( diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 5a3f60251..95328f9c7 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -85,3 +85,8 @@ export { * @param client The client to close. */ export const closeClient = (client: Client) => client.close(); + +export const waitForClientReady = + (client: Client, deadline: Date|number, + callback: (error: Error|null) => void) => + client.waitForReady(deadline, callback); From 809e9d1edd5bc0fde71c2723b472b272c1b13826 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Fri, 20 Apr 2018 17:23:19 -0700 Subject: [PATCH 0206/1899] Pure JS: emit 'status' before 'end' --- packages/grpc-js-core/src/call.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index 4344dfeb5..b7b079630 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -71,6 +71,7 @@ export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall function setUpReadableStream( stream: ClientReadableStream, call: CallStream, deserialize: (chunk: Buffer) => ResponseType): void { + let statusEmitted = false; call.on('data', (data: Buffer) => { let deserialized: ResponseType; try { @@ -84,7 +85,13 @@ function setUpReadableStream( } }); call.on('end', () => { - stream.push(null); + if (statusEmitted) { + stream.push(null); + } else { + call.once('status', () => { + stream.push(null); + }); + } }); call.on('status', (status: StatusObject) => { if (status.code !== Status.OK) { @@ -94,6 +101,7 @@ function setUpReadableStream( stream.emit('error', error); } stream.emit('status', status); + statusEmitted = true; }); call.pause(); } From 4694b7371c39348bf34fe50cb79136bbf1acd265 Mon Sep 17 00:00:00 2001 From: tassadarliu Date: Mon, 23 Apr 2018 17:28:47 +0800 Subject: [PATCH 0207/1899] typo --- packages/grpc-native-core/ext/channel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index fc085fa01..db6d2b453 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -78,7 +78,7 @@ bool ParseChannelArgs(Local args_val, Local key = Nan::Get(keys, i).ToLocalChecked(); Utf8String key_str(key); if (*key_str == NULL) { - // Key string onversion failed + // Key string conversion failed return false; } Local value = Nan::Get(args_hash, key).ToLocalChecked(); From cf004c30a58ff037232062e82e59f3cd9e68648b Mon Sep 17 00:00:00 2001 From: Nikos Koumbakis Date: Sun, 15 Apr 2018 20:48:30 +0300 Subject: [PATCH 0208/1899] Update protobufjs version Fixes [ReDoS Vulnerability](https://github.com/dcodeIO/protobuf.js/releases/tag/6.8.6) --- packages/grpc-protobufjs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index e15c31f0f..1ed26975b 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -41,7 +41,7 @@ "@types/lodash": "^4.14.104", "@types/node": "^9.4.6", "lodash": "^4.17.5", - "protobufjs": "^6.8.5" + "protobufjs": "^6.8.6" }, "devDependencies": { "clang-format": "^1.2.2", From ff16b66b6f31e517e3b0d177a6e7e26e73eaaf2b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 30 Apr 2018 09:39:56 -0700 Subject: [PATCH 0209/1899] Don't upgrade npm in Windows tests --- run-tests.bat | 1 - 1 file changed, 1 deletion(-) diff --git a/run-tests.bat b/run-tests.bat index 5aeaa700c..9a05432a4 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -39,7 +39,6 @@ SET FAILED=0 for %%v in (4 6 7 8 9) do ( call nvm install %%v call nvm use %%v - call npm install -g npm @rem https://github.com/mapbox/node-pre-gyp/issues/362 call npm install -g node-gyp node -e "console.log(process.versions)" From 5405aa31f46ac25f016bbc8654e87fa685545e7b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 30 Apr 2018 13:04:03 -0700 Subject: [PATCH 0210/1899] Upgrade npm on Node 4 --- run-tests.bat | 3 +++ 1 file changed, 3 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index 9a05432a4..2b460ffa3 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -39,6 +39,9 @@ SET FAILED=0 for %%v in (4 6 7 8 9) do ( call nvm install %%v call nvm use %%v + if "%%v"=="4" ( + npm install -g npm@5 + ) @rem https://github.com/mapbox/node-pre-gyp/issues/362 call npm install -g node-gyp node -e "console.log(process.versions)" From a63f534979a2fdaba7f4111be3aad9348a69e4c5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 30 Apr 2018 13:31:12 -0700 Subject: [PATCH 0211/1899] Change 'include' to 'includeDirs' in proto-loader package --- packages/grpc-protobufjs/README.md | 2 +- packages/grpc-protobufjs/src/index.ts | 18 +++++++++--------- test/interop/interop_client.js | 2 +- test/interop/interop_server.js | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md index 4e57faf4c..307c635c1 100644 --- a/packages/grpc-protobufjs/README.md +++ b/packages/grpc-protobufjs/README.md @@ -36,7 +36,7 @@ The options parameter is an object that can have the following optional properti | `arrays` | `true` or `false` | Set empty arrays for missing array values even if `defaults` is `false` Defaults to `false`. | `objects` | `true` or `false` | Set empty objects for missing object values even if `defaults` is `false` Defaults to `false`. | `oneofs` | `true` or `false` | Set virtual oneof properties to the present field's name. Defaults to `false`. -| `include` | An array of strings | A list of search paths for imported `.proto` files. +| `includeDirs` | An array of strings | A list of search paths for imported `.proto` files. The following options object closely approximates the existing behavior of `grpc.load`: diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index 85c2c9413..5f443f983 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -48,7 +48,7 @@ export interface PackageDefinition { } export type Options = Protobuf.IParseOptions & Protobuf.IConversionOptions & { - include?: string[]; + includeDirs?: string[]; }; function joinName(baseName: string, name: string): string { @@ -154,15 +154,15 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * `defaults` is `false`. Defaults to `false`. * @param options.oneofs Set virtual oneof properties to the present field's * name - * @param options.include Paths to search for imported `.proto` files. + * @param options.includeDirs Paths to search for imported `.proto` files. */ export function load(filename: string, options: Options): Promise { const root: Protobuf.Root = new Protobuf.Root(); - if (!!options.include) { - if (!(options.include instanceof Array)) { - return Promise.reject(new Error('The include option must be an array')); + if (!!options.includeDirs) { + if (!(options.includeDirs instanceof Array)) { + return Promise.reject(new Error('The includeDirs option must be an array')); } - addIncludePathResolver(root, options.include as string[]); + addIncludePathResolver(root, options.includeDirs as string[]); } return root.load(filename, options).then((loadedRoot) => { loadedRoot.resolveAll(); @@ -172,11 +172,11 @@ export function load(filename: string, options: Options): Promise Date: Mon, 30 Apr 2018 14:00:42 -0700 Subject: [PATCH 0212/1899] Bump version to v1.11.0 --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 5703b3c8c..55bf7a486 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - 'node_version': 1.11.0-pre2 + 'node_version': 1.11.0 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index c53db2309..c112e7729 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.0-pre2", + "version": "1.11.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 9d1904fb9a9044c4876e7af00508649eec2f2354 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 1 May 2018 23:32:30 +0200 Subject: [PATCH 0213/1899] Adding initial node 10 support. --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 4 ++-- packages/grpc-native-core/templates/package.json.template | 2 +- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 55bf7a486..4836b2492 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - 'node_version': 1.11.0 + 'node_version': 1.11.1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index c112e7729..78a487b42 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.0", + "version": "1.11.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", @@ -30,7 +30,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "0.7.0", + "node-pre-gyp": "^0.10.0", "protobufjs": "^5.0.0" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 35f55b0ea..33a77dbb5 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -32,7 +32,7 @@ "dependencies": { "lodash": "^4.15.0", "nan": "^2.0.0", - "node-pre-gyp": "0.7.0", + "node-pre-gyp": "^0.10.0", "protobufjs": "^5.0.0" }, "devDependencies": { diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index e84dd8963..31d062f79 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 +set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 006370daa..d9b2c424a 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -17,7 +17,7 @@ set -ex arch_list=( ia32 x64 ) -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 ) electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 ) while true ; do diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 7faf15cca..275b43b21 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -23,7 +23,7 @@ mkdir -p "${ARTIFACTS_OUT}" npm update -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 ) for version in ${node_versions[@]} do From 05221bad2664e8e31b33cc97d8acbf2f1cb0e157 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 1 May 2018 15:21:58 -0700 Subject: [PATCH 0214/1899] Add a missing directory to grpc package.json --- packages/grpc-native-core/package.json | 1 + packages/grpc-native-core/templates/package.json.template | 1 + 2 files changed, 2 insertions(+) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index c112e7729..627386c3f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -71,6 +71,7 @@ "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "binding.gyp" ], diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 35f55b0ea..383eb4ec9 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -73,6 +73,7 @@ "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", + "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "binding.gyp" ], From e35856061ebd28aaee67d30a856634981affc713 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 00:45:04 +0200 Subject: [PATCH 0215/1899] Building with node 10, because otherwise there's a weird issue, and I can't be bothered to understand it. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 7 +++++++ .../tools/run_tests/artifacts/build_artifact_node.sh | 2 ++ .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 3 +++ 3 files changed, 12 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 31d062f79..442b2b047 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -12,6 +12,13 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. +powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" + +SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% + +call nvm install 10 +call nvm use 10 + set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index d9b2c424a..303fd3ec3 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,6 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +nvm install 10 +nvm use 10 set -ex diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 275b43b21..e7e301ed3 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +nvm install 10 +nvm use 10 + set -ex cd $(dirname $0)/../../.. From 5f47953c88ac9671e5e474630b640cf56b28b587 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 01:20:08 +0200 Subject: [PATCH 0216/1899] Installing nvm from kokoro scripts. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 4 ---- tools/release/kokoro.bat | 5 +++-- tools/release/kokoro.sh | 5 +++-- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 442b2b047..2c4ee6f37 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -12,10 +12,6 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. -powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" - -SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% - call nvm install 10 call nvm use 10 diff --git a/tools/release/kokoro.bat b/tools/release/kokoro.bat index 1fde63b58..c55ddbf3d 100644 --- a/tools/release/kokoro.bat +++ b/tools/release/kokoro.bat @@ -14,8 +14,9 @@ @echo "Starting Windows build" -@rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp +powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" + +SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% cd /d %~dp0 cd ..\.. diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index b89504a94..37e61ea76 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -13,8 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" set -ex cd $(dirname $0)/../.. From 582c171da4711441c9a7e92c149f2b784deb4aad Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 01:43:31 +0200 Subject: [PATCH 0217/1899] Shuffling things around a bit better... --- .../tools/run_tests/artifacts/build_artifact_node.bat | 3 --- .../tools/run_tests/artifacts/build_artifact_node.sh | 3 --- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 6 +++--- tools/release/kokoro.bat | 5 +++++ tools/release/kokoro.sh | 5 +++++ 5 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 2c4ee6f37..31d062f79 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -12,9 +12,6 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. -call nvm install 10 -call nvm use 10 - set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 303fd3ec3..3120d6d37 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,9 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -nvm install 10 -nvm use 10 - set -ex arch_list=( ia32 x64 ) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index e7e301ed3..34d9ffacb 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -13,11 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. -nvm install 10 -nvm use 10 - set -ex +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + cd $(dirname $0)/../../.. rm -rf build || true diff --git a/tools/release/kokoro.bat b/tools/release/kokoro.bat index c55ddbf3d..d26f58b3b 100644 --- a/tools/release/kokoro.bat +++ b/tools/release/kokoro.bat @@ -17,6 +17,11 @@ powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% +call nvm install 10 +call nvm use 10 + +call npm install -g npm +call npm install -g node-gyp cd /d %~dp0 cd ..\.. diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 37e61ea76..4b0fe37d1 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -17,6 +17,11 @@ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" +nvm install 10 +nvm use 10 +npm install -g npm +npm install -g node-gyp + set -ex cd $(dirname $0)/../.. base_dir=$(pwd) From 1ef4c902707ac8babe7d77828d42fb4059a38d89 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 23 Apr 2018 03:53:52 +0200 Subject: [PATCH 0218/1899] Let's start building electron 2 binaries. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index e84dd8963..da2efa553 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -16,7 +16,7 @@ set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 006370daa..e27b42d2c 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -18,7 +18,7 @@ set -ex arch_list=( ia32 x64 ) node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 ) while true ; do case $1 in From c94718c007f56bb49a709009be6e2b21cc9a5a67 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 03:41:42 +0200 Subject: [PATCH 0219/1899] Let's double down on installing node 10... --- .../tools/run_tests/artifacts/build_artifact_node.sh | 5 +++++ .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 3120d6d37..d76536fd9 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,6 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +nvm install 10 +nvm use 10 +npm install -g npm +npm install -g node-gyp + set -ex arch_list=( ia32 x64 ) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 34d9ffacb..3ca347f74 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -13,6 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. +nvm install 10 +nvm use 10 +npm install -g npm +npm install -g node-gyp + set -ex # https://github.com/mapbox/node-pre-gyp/issues/362 From 727e54ef1ba9d11e32e2195787d45675bdefdf2a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 04:07:41 +0200 Subject: [PATCH 0220/1899] Right. We need to install nvm into the docker image. --- .../grpc-native-core/tools/docker/alpine_artifact/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile index 0674654a5..1a7ee6ed8 100644 --- a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile +++ b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile @@ -1,2 +1,3 @@ FROM node:8-alpine RUN apk add --no-cache python curl bash build-base +RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash From d46556622de61aef6382222bd0a691135d3ea54a Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 04:11:35 +0200 Subject: [PATCH 0221/1899] More nvm love. --- .../tools/run_tests/artifacts/build_artifact_node.sh | 3 +++ .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index d76536fd9..1dc04d647 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + nvm install 10 nvm use 10 npm install -g npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 3ca347f74..24292c5f2 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + nvm install 10 nvm use 10 npm install -g npm From c5fbaf1b5b7fc2e0d9abd416a2c22a58dc2ff64e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 05:33:08 +0200 Subject: [PATCH 0222/1899] Reverting these... --- .../tools/run_tests/artifacts/build_artifact_node.sh | 8 -------- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 8 -------- 2 files changed, 16 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 2b3452a52..a98c775d2 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -13,14 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -nvm install 10 -nvm use 10 -npm install -g npm -npm install -g node-gyp - set -ex arch_list=( ia32 x64 ) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 24292c5f2..34d9ffacb 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -13,14 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -nvm install 10 -nvm use 10 -npm install -g npm -npm install -g node-gyp - set -ex # https://github.com/mapbox/node-pre-gyp/issues/362 From 30310d79b1bacb0b89fbd9131be39d045d858ad7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 2 May 2018 05:36:19 +0200 Subject: [PATCH 0223/1899] Better this way... --- .../grpc-native-core/tools/docker/alpine_artifact/Dockerfile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile index 1a7ee6ed8..728ccd02d 100644 --- a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile +++ b/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile @@ -1,3 +1,2 @@ -FROM node:8-alpine +FROM node:10-alpine RUN apk add --no-cache python curl bash build-base -RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash From 85c154c5079d1873f831cc8cf9fb99cf50893e4d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 2 May 2018 11:53:43 -0700 Subject: [PATCH 0224/1899] Add loadPackageDefinition and interceptor APIs to .d.ts file --- packages/grpc-native-core/index.d.ts | 208 ++++++++++++++++++++++++++- 1 file changed, 207 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 73a685cd4..13405183a 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -78,6 +78,13 @@ declare module "grpc" { */ export function load(filename: Filename, format?: "proto" | "json", options?: LoadOptions): T; + /** + * Load a gRPC package definition as a gRPC object hierarchy + * @param packageDef The package definition object + * @return The resulting gRPC object + */ + export function loadPackageDefinition(packageDefinition: PackageDefinition): GrpcObject; + /** * A filename */ @@ -235,12 +242,18 @@ declare module "grpc" { /** * An object that completely defines a service. - * @typedef {Object.} grpc~ServiceDefinition */ export type ServiceDefinition = { readonly [I in keyof ImplementationType]: MethodDefinition; } + /** + * An object that defines a package containing multiple services + */ + export type PackageDefinition = { + readonly [fullyQualifiedName: string]: ServiceDefinition; + } + /** * An object that completely defines a service method signature. */ @@ -1259,4 +1272,197 @@ declare module "grpc" { * @param clientObj The client to close */ export function closeClient(clientObj: Client): void; + + /** + * A builder for gRPC status objects + */ + export class StatusBuilder { + constructor() + + /** + * Adds a status code to the builder + * @param code The status code + */ + withCode(code: number): this; + + /** + * Adds details to the builder + * @param details A status message + */ + withDetails(details: string): this; + + /** + * Adds metadata to the builder + * @param metadata The gRPC status metadata + */ + withMetadata(metadata: Metadata): this; + + /** + * Builds the status object + * @return A gRPC status + */ + build(): StatusObject; + } + + export type MetadataListener = (metadata: Metadata, next: function) => void; + + export type MessageListener = (message: any, next: function) => void; + + export type StatusListener = (status: StatusObject, next: function) => void; + + export interface Listener { + onReceiveMetadata?: MetadataListener; + onReceiveMessage?: MessageListener; + onReceiveStatus?: StatusListener; + } + + /** + * A builder for listener interceptors + */ + export class ListenerBuilder { + constructor(); + + /** + * Adds onReceiveMetadata method to the builder + * @param onReceiveMetadata A listener method for receiving metadata + */ + withOnReceiveMetadata(onReceiveMetadata: MetadataListener): this; + + /** + * Adds onReceiveMessage method to the builder + * @param onReceiveMessage A listener method for receiving message + */ + withOnReceiveMessage(onReceiveMessage: MessageListener): this; + + /** + * Adds onReceiveStatus method to the builder + * @param onReceiveStatus A listener method for receiving status + */ + withOnReceiveStatus(onReceiveStatus: StatusListener): this; + + /** + * Builds the call listener + */ + build(): Listener; + } + + export type MetadataRequester = (metadata: Metadata, listener: Listener, next: function) => void; + + export type MessageRequester = (message: any, next: function) => void; + + export type CloseRequester = (next: function) => void; + + export type CancelRequester = (next: function) => void; + + export type GetPeerRequester = (next: function) => string; + + export interface Requester { + start?: MetadataRequester; + sendMessage?: MessageRequester; + halfClose?: CloseRequester; + cancel?: CancelRequester; + getPeer?: GetPeerRequester; + } + + /** + * A builder for the outbound methods of an interceptor + */ + export class RequesterBuilder { + constructor(); + + /** + * Add a metadata requester to the builder + * @param start A requester method for handling metadata + */ + withStart(start: MetadataRequester): this; + + /** + * Add a message requester to the builder. + * @param sendMessage A requester method for handling + * messages. + */ + withSendMessage(sendMessage: MessageRequester): this; + + /** + * Add a close requester to the builder. + * @param halfClose A requester method for handling client + * close. + */ + withHalfClose(halfClose: CloseRequester): this; + + /** + * Add a cancel requester to the builder. + * @param cancel A requester method for handling `cancel` + */ + withCancel(cancel: CancelRequester): this; + + /** + * Builds the requester's interceptor methods. + */ + build(): Requester; + } + + /** + * A chainable gRPC call proxy which will delegate to an optional requester + * object. By default, interceptor methods will chain to nextCall. If a + * requester is provided which implements an interceptor method, that + * requester method will be executed as part of the chain. + * operations. + */ + export class InterceptingCall { + /** + * @param next_Call The next call in the chain + * @param requester Interceptor methods to handle request + */ + constructor(nextCall: InterceptingCall|null, requester?: Requester); + + /** + * Starts a call through the outbound interceptor chain and adds an element to + * the reciprocal inbound listener chain. + */ + start(metadata: Metadata, listener: Listener): void; + + /** + * Pass a message through the interceptor chain. + */ + sendMessage(message: any): void; + + /** + * Run a close operation through the interceptor chain + */ + halfClose(): void; + + /** + * Run a cancel operation through the interceptor chain + */ + cancel(): void; + + /** + * Run a cancelWithStatus operation through the interceptor chain. + * @param status + * @param message + */ + cancelWithStatus(status: StatusObject, message: string): void; + + /** + * Pass a getPeer call down to the base gRPC call (should not be intercepted) + */ + getPeer(): object; + + /** + * For streaming calls, we need to transparently pass the stream's context + * through the interceptor chain. Passes the context between InterceptingCalls + * but hides it from any requester implementations. + * @param context Carries objects needed for streaming operations. + * @param message The message to send. + */ + sendMessageWithContext(context: object, message: any): void; + + /** + * For receiving streaming messages, we need to seed the base interceptor with + * the streaming context to create a RECV_MESSAGE batch. + * @param context Carries objects needed for streaming operations + */ + recvMessageWithContext(context: object): void; + } } From 5233c2d8eb307369b45fe570465996482cc40e39 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Wed, 2 May 2018 15:24:34 -0700 Subject: [PATCH 0225/1899] fix: use capital `F` for `Function` when used as a type --- packages/grpc-native-core/index.d.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 13405183a..be0c0b05d 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -84,7 +84,7 @@ declare module "grpc" { * @return The resulting gRPC object */ export function loadPackageDefinition(packageDefinition: PackageDefinition): GrpcObject; - + /** * A filename */ @@ -1304,11 +1304,11 @@ declare module "grpc" { build(): StatusObject; } - export type MetadataListener = (metadata: Metadata, next: function) => void; + export type MetadataListener = (metadata: Metadata, next: Function) => void; - export type MessageListener = (message: any, next: function) => void; + export type MessageListener = (message: any, next: Function) => void; - export type StatusListener = (status: StatusObject, next: function) => void; + export type StatusListener = (status: StatusObject, next: Function) => void; export interface Listener { onReceiveMetadata?: MetadataListener; @@ -1346,15 +1346,15 @@ declare module "grpc" { build(): Listener; } - export type MetadataRequester = (metadata: Metadata, listener: Listener, next: function) => void; + export type MetadataRequester = (metadata: Metadata, listener: Listener, next: Function) => void; - export type MessageRequester = (message: any, next: function) => void; + export type MessageRequester = (message: any, next: Function) => void; - export type CloseRequester = (next: function) => void; + export type CloseRequester = (next: Function) => void; - export type CancelRequester = (next: function) => void; + export type CancelRequester = (next: Function) => void; - export type GetPeerRequester = (next: function) => string; + export type GetPeerRequester = (next: Function) => string; export interface Requester { start?: MetadataRequester; @@ -1443,7 +1443,7 @@ declare module "grpc" { * @param message */ cancelWithStatus(status: StatusObject, message: string): void; - + /** * Pass a getPeer call down to the base gRPC call (should not be intercepted) */ From ff9ec4bcfdf2252a0d9dd9964433f88aaf3cbbd2 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 3 May 2018 23:01:25 +0200 Subject: [PATCH 0226/1899] Version bump to 1.11.2 --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 4836b2492..092ed0de6 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - 'node_version': 1.11.1 + 'node_version': 1.11.2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e1b7adb9c..fde208c0b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.1", + "version": "1.11.2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 7648d60077f61b3496ef057ad81190e921677841 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 3 May 2018 15:23:58 -0700 Subject: [PATCH 0227/1899] Remove version change in build.yaml --- packages/grpc-native-core/build.yaml | 1 - packages/grpc-native-core/package.json | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 092ed0de6..49e36fdfe 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,2 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - 'node_version': 1.11.2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index fde208c0b..fff630f71 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.11.2", + "version": "1.12.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 2f76ed5e4899d9235d5429eec89bb661e2e743b4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 4 May 2018 10:45:01 -0700 Subject: [PATCH 0228/1899] Bump to v1.12.0-pre1 --- packages/grpc-native-core/binding.gyp | 1 - packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index a7cbb8b72..67f5a2c3b 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -900,7 +900,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index cc4fe1b3c..dbb941b3e 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit cc4fe1b3cd5fea5c240e749e1f1f52f5aaab91a2 +Subproject commit dbb941b3ea39ccd999fa004e032c784f12f16146 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index fff630f71..97f96c668 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.0-dev", + "version": "1.12.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 6ef1e92874bd04d955c7b8dcaf6b4664f5854939 Mon Sep 17 00:00:00 2001 From: Huan LI Date: Sun, 6 May 2018 14:57:12 +0800 Subject: [PATCH 0229/1899] optional value for covenience --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index be0c0b05d..ad63b157a 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1243,7 +1243,7 @@ declare module "grpc" { * @param value The response value, if the call succeeded */ export type requestCallback = - (error: ServiceError | null, value: ResponseType | undefined) => void; + (error: ServiceError | null, value?: ResponseType) => void; /** * Return the underlying channel object for the specified client From 13746e23c2892c6e6f09e9456eb6ce6d40db533b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 7 May 2018 14:40:32 -0700 Subject: [PATCH 0230/1899] Update master submodule --- packages/grpc-native-core/binding.gyp | 1 - packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index a7cbb8b72..67f5a2c3b 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -900,7 +900,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/subchannel_list.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index cc4fe1b3c..aef957950 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit cc4fe1b3cd5fea5c240e749e1f1f52f5aaab91a2 +Subproject commit aef957950aa3390e3516531ca2d783de8fc9333b diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index fff630f71..357c485c7 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.0-dev", + "version": "1.13.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 51ae5318be4d8a49e4aaebc13db41974b25fa2a0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 8 May 2018 08:51:27 -0700 Subject: [PATCH 0231/1899] Interop sanity tests: run clients and server in different processes --- test/api/interop_helper/server.js | 29 +++++++ test/api/interop_sanity_test.js | 135 ++++++++++++++++-------------- 2 files changed, 101 insertions(+), 63 deletions(-) create mode 100644 test/api/interop_helper/server.js diff --git a/test/api/interop_helper/server.js b/test/api/interop_helper/server.js new file mode 100644 index 000000000..7d6536a18 --- /dev/null +++ b/test/api/interop_helper/server.js @@ -0,0 +1,29 @@ +/* + * + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +const interopServer = require('../../interop/interop_server.js'); + +const serverObj = interopServer.getServer(0, true); +serverObj.server.start(); +process.send({port: serverObj.port}); +// The only message from the driver should be to stop the server +process.on('message', (message) => { + serverObj.server.forceShutdown(); +}); diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index b3f65a034..1152b3109 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -18,77 +18,86 @@ 'use strict'; -var interop_server = require('../interop/interop_server.js'); -var interop_client = require('../interop/interop_client.js'); - -var server; +var childProcess = require('child_process'); var port; var name_override = 'foo.test.google.fr'; +var serverProcess; + +const testCases = [ + 'empty_unary', + 'large_unary', + 'client_streaming', + 'server_streaming', + 'ping_pong', + 'empty_stream', + 'cancel_after_begin', + 'cancel_after_first_response', + 'timeout_on_sleeping_server', + 'custom_metadata', + 'status_code_and_message', + 'unimplemented_service', + 'unimplemented_method' +]; + +var childExecArgv = []; + describe('Interop tests', function() { + this.timeout(4000); before(function(done) { - var server_obj = interop_server.getServer(0, true); - server = server_obj.server; - server.start(); - port = 'localhost:' + server_obj.port; - done(); + for (let arg of process.argv) { + if (arg.startsWith('--require=')) { + childExecArgv.push('--require'); + childExecArgv.push(arg.substring('--require='.length)); + } + } + serverProcess = childProcess.fork(`${__dirname}/interop_helper/server.js`, { + execArgv: childExecArgv + }); + serverProcess.on('message', (message) => { + port = message.port; + done(); + }); + serverProcess.on('exit', (code, signal) => { + if (code !== 0) { + if (code !== null) { + throw new Error(`Server exited with error code ${code}`); + } else { + throw new Error(`Server exited with signal ${signal}`); + } + } + }) }); after(function() { - server.forceShutdown(); - }); - // This depends on not using a binary stream - it('should pass empty_unary', function(done) { - interop_client.runTest(port, name_override, 'empty_unary', true, true, - done); - }); - // This fails due to an unknown bug - it('should pass large_unary', function(done) { - interop_client.runTest(port, name_override, 'large_unary', true, true, - done); - }); - it('should pass client_streaming', function(done) { - interop_client.runTest(port, name_override, 'client_streaming', true, true, - done); - }); - it('should pass server_streaming', function(done) { - interop_client.runTest(port, name_override, 'server_streaming', true, true, - done); - }); - it('should pass ping_pong', function(done) { - interop_client.runTest(port, name_override, 'ping_pong', true, true, done); - }); - it('should pass empty_stream', function(done) { - interop_client.runTest(port, name_override, 'empty_stream', true, true, - done); - }); - it('should pass cancel_after_begin', function(done) { - interop_client.runTest(port, name_override, 'cancel_after_begin', true, - true, done); - }); - it('should pass cancel_after_first_response', function(done) { - interop_client.runTest(port, name_override, 'cancel_after_first_response', - true, true, done); - }); - it('should pass timeout_on_sleeping_server', function(done) { - interop_client.runTest(port, name_override, 'timeout_on_sleeping_server', - true, true, done); - }); - it('should pass custom_metadata', function(done) { - interop_client.runTest(port, name_override, 'custom_metadata', - true, true, done); - }); - it('should pass status_code_and_message', function(done) { - interop_client.runTest(port, name_override, 'status_code_and_message', - true, true, done); - }); - it('should pass unimplemented_service', function(done) { - interop_client.runTest(port, name_override, 'unimplemented_service', - true, true, done); - }); - it('should pass unimplemented_method', function(done) { - interop_client.runTest(port, name_override, 'unimplemented_method', - true, true, done); + serverProcess.send({}); }); + for (let testName of testCases) { + it(`should pass ${testName}`, function(done) { + /* We need to run a client process per test to most closely match + * how the main interop test suite works */ + let clientProcess = childProcess.fork(`${__dirname}/../interop/interop_client`, [ + '--server_host=localhost', + `--server_port=${port}`, + `--server_host_override=${name_override}`, + `--test_case=${testName}`, + '--use_tls=true', + '--use_test_ca=true' + ], { + execArgv: childExecArgv + }); + clientProcess.on('exit', (code, signal) => { + if (code === 0) { + done(); + } else { + if (code !== null) { + done(new Error(`Client exited with error code ${code}`)); + } else { + done(new Error(`Client exited with signal ${signal}`)); + } + } + }); + }); + } }); From cb51e1f84f2a20591fb7b3d5f635c877f642c98a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 9 May 2018 10:29:02 -0700 Subject: [PATCH 0232/1899] Stop myself from publishing packages with a mismatched submodule --- packages/grpc-native-core/package.json | 3 ++- packages/grpc-native-core/templates/package.json.template | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 97f96c668..cd632a041 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -22,7 +22,8 @@ "build": "./node_modules/.bin/node-pre-gyp build", "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", - "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library" + "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library", + "prepublish": "git submodule update --init --recursive" }, "bundledDependencies": [ "node-pre-gyp" diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index f285b0a2d..9f8d228b1 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -24,7 +24,8 @@ "build": "./node_modules/.bin/node-pre-gyp build", "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", - "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library" + "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library", + "prepublish": "git submodule update --init --recursive" }, "bundledDependencies": [ "node-pre-gyp" From 758950bfb3a374bf9c27a210a9ec5f0efa06b158 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 9 May 2018 20:18:12 +0200 Subject: [PATCH 0233/1899] Enabling node 10 tests. --- run-tests.bat | 2 +- run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index a91e6d069..0030e2f75 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -36,7 +36,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4 6 7 8 9) do ( +for %%v in (4 6 7 8 9 10) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index bfc0ff71d..eb94fd691 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="4 5 6 7 8 9" + node_versions="4 5 6 7 8 9 10" fi set +ex From afbb9f4a7ff03be6fffebb8abd29b07c0d334e62 Mon Sep 17 00:00:00 2001 From: William Yardley Date: Wed, 9 May 2018 17:00:54 -0700 Subject: [PATCH 0234/1899] Update lodash version to ^4.17.5 (#330) This should resolve warnings related to https://nodesecurity.io/advisories/577 --- packages/grpc-health-check/package.json | 2 +- packages/grpc-js-core/package.json | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index ce179a94b..db1fd61fc 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -17,7 +17,7 @@ "dependencies": { "google-protobuf": "^3.4.0", "grpc": "^1.6.0", - "lodash": "^3.10.1" + "lodash": "^4.17.5" }, "files": [ "LICENSE", diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index df86a9d72..e7ee8ea15 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -14,7 +14,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@types/lodash": "^4.14.77", + "@types/lodash": "^4.14.108", "@types/mocha": "^2.2.43", "@types/node": "^9.4.6", "clang-format": "^1.0.55", diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 357c485c7..f9edabf5b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -28,7 +28,7 @@ "node-pre-gyp" ], "dependencies": { - "lodash": "^4.15.0", + "lodash": "^4.17.5", "nan": "^2.0.0", "node-pre-gyp": "^0.10.0", "protobufjs": "^5.0.0" From 60b59c455c3e4ee8f6392dcc1cec6fd056c97a61 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 May 2018 11:21:25 -0700 Subject: [PATCH 0235/1899] Add coverage reporting for JavaScript and TypeScript files --- gulpfile.ts | 2 +- package.json | 20 +++++++++++++++++--- run-tests.sh | 18 +++++++++++++++--- test/gulpfile.js | 20 ++++++++++++++------ 4 files changed, 47 insertions(+), 13 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index 388a74f4d..dac1421ea 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -102,7 +102,7 @@ gulp.task('test.only', 'Run tests without rebuilding anything', ['js.core.test', 'native.test.only']); gulp.task('test', 'Run all tests', (callback) => { - runSequence('build', 'test.only', callback); + runSequence('build', 'test.only', 'internal.test.test', callback); }); gulp.task('doc.gen', 'Generate documentation', ['native.core.doc.gen']); diff --git a/package.json b/package.json index fb6262141..053f7d29c 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@types/node": "^8.0.32", "@types/pify": "^3.0.0", "@types/semver": "^5.5.0", + "coveralls": "^3.0.1", "del": "^3.0.0", "execa": "^0.8.0", "gulp": "^3.9.1", @@ -35,8 +36,11 @@ "mocha": "^3.5.3", "mocha-jenkins-reporter": "^0.3.9", "ncp": "^2.0.0", + "nyc": "^11.7.2", "pify": "^3.0.0", + "run-sequence": "^2.2.0", "semver": "^5.5.0", + "symlink": "^2.1.0", "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", @@ -48,8 +52,18 @@ "name": "Google Inc." } ], - "dependencies": { - "run-sequence": "^2.2.0", - "symlink": "^2.1.0" + "nyc": { + "include": [ + "packages/grpc-health-check/health.js", + "packages/grpc-js-core/build/src/*", + "packages/grpc-native-core/index.js", + "packages/grpc-native-core/src/*.js", + "packages/grpc-protobufjs/build/src/*" + ], + "cache": true + }, + "scripts": { + "test": "nyc gulp test", + "coverage": "nyc report --reporter=text-lcov | coveralls" } } diff --git a/run-tests.sh b/run-tests.sh index 300a25274..afce89bb4 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -39,6 +39,16 @@ npm install --unsafe-perm mkdir -p reports export JOBS=8 +export JUNIT_REPORT_PATH="reports/node$version/" +export JUNIT_REPORT_STACK=1 + +gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc . +set +x +. grpc-node.rc +set -x +export COVERALLS_REPO_TOKEN +export COVERALLS_SERVICE_NAME=Kokoro +export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID # TODO(mlumish): Add electron tests @@ -62,8 +72,8 @@ do ./node_modules/.bin/gulp clean.all ./node_modules/.bin/gulp setup - # Rebuild libraries and run tests. - JUNIT_REPORT_PATH="reports/node$version/" JUNIT_REPORT_STACK=1 ./node_modules/.bin/gulp test || FAILED="true" + # npm test calls nyc gulp test + npm test || FAILED="true" done set +ex @@ -72,7 +82,9 @@ set -ex node merge_kokoro_logs.js -if [ "$FAILED" != "" ] +if [ "$FAILED" == "" ] then + npm run coverage +else exit 1 fi diff --git a/test/gulpfile.js b/test/gulpfile.js index 61ff16586..b6221ed6a 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -21,6 +21,7 @@ const mocha = require('gulp-mocha'); const execa = require('execa'); const path = require('path'); const del = require('del'); +const semver = require('semver'); const linkSync = require('../util').linkSync; // gulp-help monkeypatches tasks to have an additional description parameter @@ -51,12 +52,19 @@ gulp.task('test', 'Run API-level tests', () => { .on('end', resolve) .on('error', reject); }); - const runTestsArgPairs = [ - ['native', 'native'], - ['native', 'js'], - // ['js', 'native'], - // ['js', 'js'] - ]; + let runTestsArgPairs; + if (semver.satisfies(process.version, '>=9.4')) { + runTestsArgPairs = [ + ['native', 'native'], + ['native', 'js'], + // ['js', 'native'], + // ['js', 'js'] + ]; + } else { + runTestsArgPairs = [ + ['native', 'native'] + ]; + } return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); }, Promise.resolve()); From 9345d4d0b51e699da07a12b6824fbf07c165ca3f Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 11 May 2018 00:16:09 +0200 Subject: [PATCH 0236/1899] Using docker... --- .../run_tests/artifacts/build_all_linux_artifacts.sh | 7 +++++++ tools/release/kokoro.sh | 5 ++--- tools/release/kokoro/Dockerfile | 10 ++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 tools/release/kokoro/Dockerfile diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 59f62a2fb..64d3d8627 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -13,6 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" +nvm install 10 +nvm use 10 +npm install -g npm +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + set -ex cd $(dirname $0) diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 6d211861b..34604c59c 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -38,9 +38,8 @@ OS=`uname` case $OS in Linux) - sudo apt-get update - sudo apt-get install -y linux-libc-dev:i386 g++-aarch64-linux-gnu g++-arm-linux-gnueabihf - ./packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh + docker build -t kokoro-image tools/release/kokoro + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh mv packages/grpc-native-core/artifacts . ;; Darwin) diff --git a/tools/release/kokoro/Dockerfile b/tools/release/kokoro/Dockerfile new file mode 100644 index 000000000..0c31914b2 --- /dev/null +++ b/tools/release/kokoro/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 + +RUN dpkg --add-architecture i386 +RUN apt-get update +RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf docker.io python libc6-dev:i386 lib32stdc++-5-dev + +RUN mkdir /usr/local/nvm +ENV NVM_DIR /usr/local/nvm + +RUN curl curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash From fb177bd0b2f80993607a8c3227b8450ed7f410b3 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 11 May 2018 03:09:07 +0200 Subject: [PATCH 0237/1899] Copying artifacts instead of moving them. --- tools/release/kokoro.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 34604c59c..5a2a63e21 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -40,7 +40,7 @@ case $OS in Linux) docker build -t kokoro-image tools/release/kokoro docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh - mv packages/grpc-native-core/artifacts . + cp -rv packages/grpc-native-core/artifacts . ;; Darwin) JOBS=8 ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh From 53bc63228bfcfce0b6dfe76571fac4d6af4e486e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 11 May 2018 00:16:09 +0200 Subject: [PATCH 0238/1899] Using docker... --- .../run_tests/artifacts/build_all_linux_artifacts.sh | 7 +++++++ tools/release/kokoro.sh | 5 ++--- tools/release/kokoro/Dockerfile | 10 ++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) create mode 100644 tools/release/kokoro/Dockerfile diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 59f62a2fb..64d3d8627 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -13,6 +13,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" +nvm install 10 +nvm use 10 +npm install -g npm +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + set -ex cd $(dirname $0) diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 6d211861b..34604c59c 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -38,9 +38,8 @@ OS=`uname` case $OS in Linux) - sudo apt-get update - sudo apt-get install -y linux-libc-dev:i386 g++-aarch64-linux-gnu g++-arm-linux-gnueabihf - ./packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh + docker build -t kokoro-image tools/release/kokoro + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh mv packages/grpc-native-core/artifacts . ;; Darwin) diff --git a/tools/release/kokoro/Dockerfile b/tools/release/kokoro/Dockerfile new file mode 100644 index 000000000..0c31914b2 --- /dev/null +++ b/tools/release/kokoro/Dockerfile @@ -0,0 +1,10 @@ +FROM ubuntu:16.04 + +RUN dpkg --add-architecture i386 +RUN apt-get update +RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf docker.io python libc6-dev:i386 lib32stdc++-5-dev + +RUN mkdir /usr/local/nvm +ENV NVM_DIR /usr/local/nvm + +RUN curl curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash From 1c5a5dea248a9585b533892ca7137c374020da85 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 11 May 2018 03:09:07 +0200 Subject: [PATCH 0239/1899] Copying artifacts instead of moving them. --- tools/release/kokoro.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 34604c59c..5a2a63e21 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -40,7 +40,7 @@ case $OS in Linux) docker build -t kokoro-image tools/release/kokoro docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh - mv packages/grpc-native-core/artifacts . + cp -rv packages/grpc-native-core/artifacts . ;; Darwin) JOBS=8 ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh From 7093bfc2f3feb9deac6fee112373c19f936ec49f Mon Sep 17 00:00:00 2001 From: William Yardley Date: Wed, 9 May 2018 17:00:54 -0700 Subject: [PATCH 0240/1899] Update lodash version to ^4.17.5 (#330) This should resolve warnings related to https://nodesecurity.io/advisories/577 --- packages/grpc-health-check/package.json | 2 +- packages/grpc-js-core/package.json | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index ce179a94b..db1fd61fc 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -17,7 +17,7 @@ "dependencies": { "google-protobuf": "^3.4.0", "grpc": "^1.6.0", - "lodash": "^3.10.1" + "lodash": "^4.17.5" }, "files": [ "LICENSE", diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index df86a9d72..e7ee8ea15 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -14,7 +14,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@types/lodash": "^4.14.77", + "@types/lodash": "^4.14.108", "@types/mocha": "^2.2.43", "@types/node": "^9.4.6", "clang-format": "^1.0.55", diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 97f96c668..d3ada1668 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -28,7 +28,7 @@ "node-pre-gyp" ], "dependencies": { - "lodash": "^4.15.0", + "lodash": "^4.17.5", "nan": "^2.0.0", "node-pre-gyp": "^0.10.0", "protobufjs": "^5.0.0" From 796a1df0e50c675822b057afa56ca03b07b209c3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 10:59:19 -0700 Subject: [PATCH 0241/1899] Make interop client fail if the test never finishes --- package.json | 6 +++++- test/api/interop_sanity_test.js | 2 +- test/interop/interop_client.js | 8 ++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 053f7d29c..47dda40fa 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,11 @@ "packages/grpc-native-core/src/*.js", "packages/grpc-protobufjs/build/src/*" ], - "cache": true + "cache": true, + "all": true, + "require": [ + "ts-node/register" + ] }, "scripts": { "test": "nyc gulp test", diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 1152b3109..0ff4c28bb 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -68,7 +68,7 @@ describe('Interop tests', function() { throw new Error(`Server exited with signal ${signal}`); } } - }) + }); }); after(function() { serverProcess.send({}); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index fb6026e05..195ef8d47 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -616,8 +616,12 @@ if (require.main === module) { }; runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', - function () { - console.log('OK:', argv.test_case); + function (err) { + if (err) { + throw err; + } else { + console.log('OK:', argv.test_case); + } }, extra_args); } From 09194cb757180938a31c9cd3a4eee92d3b4dff32 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 11:00:15 -0700 Subject: [PATCH 0242/1899] Reference and unreference http2 sessions more dynamically --- packages/grpc-js-core/src/channel.ts | 37 ++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index c03389d88..40b5a93d8 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -82,6 +82,15 @@ export interface Channel extends EventEmitter { /* tslint:enable:no-any */ } +/* This should be a real subchannel class that contains a ClientHttp2Session, + * but for now this serves its purpose */ +type Http2SubChannel = http2.ClientHttp2Session & { + /* Count the number of currently active streams associated with the session. + * The purpose of this is to keep the session reffed if and only if there + * is at least one active stream */ + streamCount?: number; +}; + export class Http2Channel extends EventEmitter implements Channel { private readonly userAgent: string; private readonly target: url.URL; @@ -91,7 +100,7 @@ export class Http2Channel extends EventEmitter implements Channel { private connecting: Promise|null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ - private subChannel: http2.ClientHttp2Session|null = null; + private subChannel: Http2SubChannel|null = null; private filterStackFactory: FilterStackFactory; private subChannelConnectCallback: () => void = () => {}; @@ -160,7 +169,7 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - let subChannel: http2.ClientHttp2Session; + let subChannel: Http2SubChannel; const secureContext = this.credentials.getSecureContext(); if (secureContext === null) { subChannel = http2.connect(this.target); @@ -260,11 +269,25 @@ export class Http2Channel extends EventEmitter implements Channel { headers[HTTP2_HEADER_PATH] = methodName; headers[HTTP2_HEADER_TE] = 'trailers'; if (this.connectivityState === ConnectivityState.READY) { - const session: http2.ClientHttp2Session = this.subChannel!; - // Prevent the HTTP/2 session from keeping the process alive. - // Note: this function is only available in Node 9 - session.unref(); - stream.attachHttp2Stream(session.request(headers)); + const session: Http2SubChannel = this.subChannel!; + let http2Stream = session.request(headers); + /* This is a very ad-hoc reference counting scheme. This should be + * handled by a subchannel class */ + session.ref(); + if (!session.streamCount) { + session.streamCount = 0; + } + session.streamCount += 1; + http2Stream.on('close', () => { + if (!session.streamCount) { + session.streamCount = 0; + } + session.streamCount -= 1; + if (session.streamCount <= 0) { + session.unref(); + } + }); + stream.attachHttp2Stream(http2Stream); } else { /* In this case, we lost the connection while finalizing * metadata. That should be very unusual */ From 4b020981e0edcc07b9cdbe8584e7c8172d133faf Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 11:08:30 -0700 Subject: [PATCH 0243/1899] Fix minor issues with coveralls reporting script --- run-tests.sh | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/run-tests.sh b/run-tests.sh index afce89bb4..03a45cfa2 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -42,13 +42,18 @@ export JOBS=8 export JUNIT_REPORT_PATH="reports/node$version/" export JUNIT_REPORT_STACK=1 -gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc . -set +x -. grpc-node.rc -set -x -export COVERALLS_REPO_TOKEN -export COVERALLS_SERVICE_NAME=Kokoro -export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID +OS=$(uname) + +if [ "$OS" == "Linux" ] +then + gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp + set +x + . /tmp/grpc-node.rc + set -x + export COVERALLS_REPO_TOKEN + export COVERALLS_SERVICE_NAME=Kokoro + export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID +fi # TODO(mlumish): Add electron tests @@ -84,7 +89,10 @@ node merge_kokoro_logs.js if [ "$FAILED" == "" ] then - npm run coverage + if [ "$OS" == "Linux" ] + then + npm run coverage + fi else exit 1 fi From 5686bea87a71520598f0a3e17016b15cfebabe81 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 13:26:05 -0700 Subject: [PATCH 0244/1899] Remove possibly unneeded line from nyc config --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index 47dda40fa..e8d7a1128 100644 --- a/package.json +++ b/package.json @@ -61,10 +61,7 @@ "packages/grpc-protobufjs/build/src/*" ], "cache": true, - "all": true, - "require": [ - "ts-node/register" - ] + "all": true }, "scripts": { "test": "nyc gulp test", From 3ed2e806fd7bf397d2761c80521b0e257d97c0d3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 14:03:11 -0700 Subject: [PATCH 0245/1899] Don't use let in js gulpfiles --- test/gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gulpfile.js b/test/gulpfile.js index b6221ed6a..4c8cf64c7 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -52,7 +52,7 @@ gulp.task('test', 'Run API-level tests', () => { .on('end', resolve) .on('error', reject); }); - let runTestsArgPairs; + var runTestsArgPairs; if (semver.satisfies(process.version, '>=9.4')) { runTestsArgPairs = [ ['native', 'native'], From fc51f0ea480a76b49f1f9c60ea1e7941513dee39 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 14:33:05 -0700 Subject: [PATCH 0246/1899] Some test script fixes --- run-tests.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/run-tests.sh b/run-tests.sh index 03a45cfa2..7eac38147 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -39,7 +39,6 @@ npm install --unsafe-perm mkdir -p reports export JOBS=8 -export JUNIT_REPORT_PATH="reports/node$version/" export JUNIT_REPORT_STACK=1 OS=$(uname) @@ -57,6 +56,8 @@ fi # TODO(mlumish): Add electron tests +FAILED="false" + for version in ${node_versions} do # Install and setup node for the version we want. @@ -66,6 +67,8 @@ do nvm use $version set -ex + export JUNIT_REPORT_PATH="reports/node$version/" + # https://github.com/mapbox/node-pre-gyp/issues/362 npm install -g node-gyp @@ -87,12 +90,12 @@ set -ex node merge_kokoro_logs.js -if [ "$FAILED" == "" ] +if [ "$FAILED" == "true" ] then + exit 1 +else if [ "$OS" == "Linux" ] then npm run coverage fi -else - exit 1 fi From 1f58e0111d31ce90fa58a26d6d007e227edc07d0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 16:03:57 -0700 Subject: [PATCH 0247/1899] Skip cross-implementation tests for Node<6 --- packages/grpc-protobufjs/package.json | 5 ++++- test/gulpfile.js | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 1ed26975b..8890edb81 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.1.0", + "version": "0.2.0", "author": "Google Inc.", "contributors": [ { @@ -47,5 +47,8 @@ "clang-format": "^1.2.2", "gts": "^0.5.3", "typescript": "~2.7.2" + }, + "engines": { + "node": ">=6" } } diff --git a/test/gulpfile.js b/test/gulpfile.js index 4c8cf64c7..2aa1c9c26 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -39,6 +39,10 @@ gulp.task('clean.all', 'Delete all files created by tasks', () => {}); gulp.task('test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream + if (!semver.satisfies(process.version, '>=9.4')) { + console.log(`Skipping cross-implementation tests for Node ${process.version}`); + return; + } const apiTestGlob = `${apiTestDir}/*.js`; const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { const fixture = `${server}_${client}`; From 908be509315f2b78cbe503fbc5fcb95582f49dae Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 May 2018 16:33:15 -0700 Subject: [PATCH 0248/1899] Fix string comparison in run-tests script --- run-tests.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run-tests.sh b/run-tests.sh index 7eac38147..4484d40b1 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -43,7 +43,7 @@ export JUNIT_REPORT_STACK=1 OS=$(uname) -if [ "$OS" == "Linux" ] +if [ "$OS" = "Linux" ] then gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp set +x @@ -90,11 +90,11 @@ set -ex node merge_kokoro_logs.js -if [ "$FAILED" == "true" ] +if [ "$FAILED" = "true" ] then exit 1 else - if [ "$OS" == "Linux" ] + if [ "$OS" = "Linux" ] then npm run coverage fi From 967da8717c97983675305d7ec40c3241d6eda706 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 15 May 2018 11:18:53 -0700 Subject: [PATCH 0249/1899] Update lodash in package.json template --- packages/grpc-native-core/templates/package.json.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index f285b0a2d..c9e4d995d 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -30,7 +30,7 @@ "node-pre-gyp" ], "dependencies": { - "lodash": "^4.15.0", + "lodash": "^4.17.5", "nan": "^2.0.0", "node-pre-gyp": "^0.10.0", "protobufjs": "^5.0.0" From 81d1e83c4facac455c8a8e6a5757f297d62aa667 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 15 May 2018 11:21:13 -0700 Subject: [PATCH 0250/1899] Update version to v1.12.0 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index dbb941b3e..bec3b5ada 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit dbb941b3ea39ccd999fa004e032c784f12f16146 +Subproject commit bec3b5ada2c5e5d782dff0b7b5018df646b65cb0 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index d3ada1668..4ce22acbe 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.0-pre1", + "version": "1.12.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 1b4d66b382e417e36c053e8d0b891425e303690b Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 15 May 2018 18:29:06 -0700 Subject: [PATCH 0251/1899] Revert "Add coverage reporting for JavaScript and TypeScript files" --- gulpfile.ts | 2 +- package.json | 21 +++------------ packages/grpc-js-core/src/channel.ts | 37 +++++---------------------- packages/grpc-protobufjs/package.json | 5 +--- run-tests.sh | 29 +++------------------ test/api/interop_sanity_test.js | 2 +- test/gulpfile.js | 24 +++++------------ test/interop/interop_client.js | 8 ++---- 8 files changed, 24 insertions(+), 104 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index dac1421ea..388a74f4d 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -102,7 +102,7 @@ gulp.task('test.only', 'Run tests without rebuilding anything', ['js.core.test', 'native.test.only']); gulp.task('test', 'Run all tests', (callback) => { - runSequence('build', 'test.only', 'internal.test.test', callback); + runSequence('build', 'test.only', callback); }); gulp.task('doc.gen', 'Generate documentation', ['native.core.doc.gen']); diff --git a/package.json b/package.json index e8d7a1128..fb6262141 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "@types/node": "^8.0.32", "@types/pify": "^3.0.0", "@types/semver": "^5.5.0", - "coveralls": "^3.0.1", "del": "^3.0.0", "execa": "^0.8.0", "gulp": "^3.9.1", @@ -36,11 +35,8 @@ "mocha": "^3.5.3", "mocha-jenkins-reporter": "^0.3.9", "ncp": "^2.0.0", - "nyc": "^11.7.2", "pify": "^3.0.0", - "run-sequence": "^2.2.0", "semver": "^5.5.0", - "symlink": "^2.1.0", "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", @@ -52,19 +48,8 @@ "name": "Google Inc." } ], - "nyc": { - "include": [ - "packages/grpc-health-check/health.js", - "packages/grpc-js-core/build/src/*", - "packages/grpc-native-core/index.js", - "packages/grpc-native-core/src/*.js", - "packages/grpc-protobufjs/build/src/*" - ], - "cache": true, - "all": true - }, - "scripts": { - "test": "nyc gulp test", - "coverage": "nyc report --reporter=text-lcov | coveralls" + "dependencies": { + "run-sequence": "^2.2.0", + "symlink": "^2.1.0" } } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 40b5a93d8..c03389d88 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -82,15 +82,6 @@ export interface Channel extends EventEmitter { /* tslint:enable:no-any */ } -/* This should be a real subchannel class that contains a ClientHttp2Session, - * but for now this serves its purpose */ -type Http2SubChannel = http2.ClientHttp2Session & { - /* Count the number of currently active streams associated with the session. - * The purpose of this is to keep the session reffed if and only if there - * is at least one active stream */ - streamCount?: number; -}; - export class Http2Channel extends EventEmitter implements Channel { private readonly userAgent: string; private readonly target: url.URL; @@ -100,7 +91,7 @@ export class Http2Channel extends EventEmitter implements Channel { private connecting: Promise|null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ - private subChannel: Http2SubChannel|null = null; + private subChannel: http2.ClientHttp2Session|null = null; private filterStackFactory: FilterStackFactory; private subChannelConnectCallback: () => void = () => {}; @@ -169,7 +160,7 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - let subChannel: Http2SubChannel; + let subChannel: http2.ClientHttp2Session; const secureContext = this.credentials.getSecureContext(); if (secureContext === null) { subChannel = http2.connect(this.target); @@ -269,25 +260,11 @@ export class Http2Channel extends EventEmitter implements Channel { headers[HTTP2_HEADER_PATH] = methodName; headers[HTTP2_HEADER_TE] = 'trailers'; if (this.connectivityState === ConnectivityState.READY) { - const session: Http2SubChannel = this.subChannel!; - let http2Stream = session.request(headers); - /* This is a very ad-hoc reference counting scheme. This should be - * handled by a subchannel class */ - session.ref(); - if (!session.streamCount) { - session.streamCount = 0; - } - session.streamCount += 1; - http2Stream.on('close', () => { - if (!session.streamCount) { - session.streamCount = 0; - } - session.streamCount -= 1; - if (session.streamCount <= 0) { - session.unref(); - } - }); - stream.attachHttp2Stream(http2Stream); + const session: http2.ClientHttp2Session = this.subChannel!; + // Prevent the HTTP/2 session from keeping the process alive. + // Note: this function is only available in Node 9 + session.unref(); + stream.attachHttp2Stream(session.request(headers)); } else { /* In this case, we lost the connection while finalizing * metadata. That should be very unusual */ diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 8890edb81..1ed26975b 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.2.0", + "version": "0.1.0", "author": "Google Inc.", "contributors": [ { @@ -47,8 +47,5 @@ "clang-format": "^1.2.2", "gts": "^0.5.3", "typescript": "~2.7.2" - }, - "engines": { - "node": ">=6" } } diff --git a/run-tests.sh b/run-tests.sh index 4484d40b1..300a25274 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -39,25 +39,9 @@ npm install --unsafe-perm mkdir -p reports export JOBS=8 -export JUNIT_REPORT_STACK=1 - -OS=$(uname) - -if [ "$OS" = "Linux" ] -then - gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp - set +x - . /tmp/grpc-node.rc - set -x - export COVERALLS_REPO_TOKEN - export COVERALLS_SERVICE_NAME=Kokoro - export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID -fi # TODO(mlumish): Add electron tests -FAILED="false" - for version in ${node_versions} do # Install and setup node for the version we want. @@ -67,8 +51,6 @@ do nvm use $version set -ex - export JUNIT_REPORT_PATH="reports/node$version/" - # https://github.com/mapbox/node-pre-gyp/issues/362 npm install -g node-gyp @@ -80,8 +62,8 @@ do ./node_modules/.bin/gulp clean.all ./node_modules/.bin/gulp setup - # npm test calls nyc gulp test - npm test || FAILED="true" + # Rebuild libraries and run tests. + JUNIT_REPORT_PATH="reports/node$version/" JUNIT_REPORT_STACK=1 ./node_modules/.bin/gulp test || FAILED="true" done set +ex @@ -90,12 +72,7 @@ set -ex node merge_kokoro_logs.js -if [ "$FAILED" = "true" ] +if [ "$FAILED" != "" ] then exit 1 -else - if [ "$OS" = "Linux" ] - then - npm run coverage - fi fi diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 0ff4c28bb..1152b3109 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -68,7 +68,7 @@ describe('Interop tests', function() { throw new Error(`Server exited with signal ${signal}`); } } - }); + }) }); after(function() { serverProcess.send({}); diff --git a/test/gulpfile.js b/test/gulpfile.js index 2aa1c9c26..61ff16586 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -21,7 +21,6 @@ const mocha = require('gulp-mocha'); const execa = require('execa'); const path = require('path'); const del = require('del'); -const semver = require('semver'); const linkSync = require('../util').linkSync; // gulp-help monkeypatches tasks to have an additional description parameter @@ -39,10 +38,6 @@ gulp.task('clean.all', 'Delete all files created by tasks', () => {}); gulp.task('test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream - if (!semver.satisfies(process.version, '>=9.4')) { - console.log(`Skipping cross-implementation tests for Node ${process.version}`); - return; - } const apiTestGlob = `${apiTestDir}/*.js`; const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { const fixture = `${server}_${client}`; @@ -56,19 +51,12 @@ gulp.task('test', 'Run API-level tests', () => { .on('end', resolve) .on('error', reject); }); - var runTestsArgPairs; - if (semver.satisfies(process.version, '>=9.4')) { - runTestsArgPairs = [ - ['native', 'native'], - ['native', 'js'], - // ['js', 'native'], - // ['js', 'js'] - ]; - } else { - runTestsArgPairs = [ - ['native', 'native'] - ]; - } + const runTestsArgPairs = [ + ['native', 'native'], + ['native', 'js'], + // ['js', 'native'], + // ['js', 'js'] + ]; return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); }, Promise.resolve()); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 195ef8d47..fb6026e05 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -616,12 +616,8 @@ if (require.main === module) { }; runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', - function (err) { - if (err) { - throw err; - } else { - console.log('OK:', argv.test_case); - } + function () { + console.log('OK:', argv.test_case); }, extra_args); } From 29346dc376d3ddc034159766cfa5e914d3c9476e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 16 May 2018 17:14:31 +0200 Subject: [PATCH 0252/1899] Upgrading to protobufjs 5.0.3. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index dfd060c86..801b5faef 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -32,7 +32,7 @@ "lodash": "^4.17.5", "nan": "^2.0.0", "node-pre-gyp": "^0.10.0", - "protobufjs": "^5.0.0" + "protobufjs": "^5.0.3" }, "devDependencies": { "async": "^2.0.1", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 4d112538b..f0ed684ce 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -34,7 +34,7 @@ "lodash": "^4.17.5", "nan": "^2.0.0", "node-pre-gyp": "^0.10.0", - "protobufjs": "^5.0.0" + "protobufjs": "^5.0.3" }, "devDependencies": { "async": "^2.0.1", From 49c354a2233e9410ec80ef93800b0f93decb0140 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 May 2018 14:03:23 -0700 Subject: [PATCH 0253/1899] Revert "Revert "Add coverage reporting for JavaScript and TypeScript files"" --- gulpfile.ts | 2 +- package.json | 21 ++++++++++++--- packages/grpc-js-core/src/channel.ts | 37 ++++++++++++++++++++++----- packages/grpc-protobufjs/package.json | 5 +++- run-tests.sh | 29 ++++++++++++++++++--- test/api/interop_sanity_test.js | 2 +- test/gulpfile.js | 24 ++++++++++++----- test/interop/interop_client.js | 8 ++++-- 8 files changed, 104 insertions(+), 24 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index 388a74f4d..dac1421ea 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -102,7 +102,7 @@ gulp.task('test.only', 'Run tests without rebuilding anything', ['js.core.test', 'native.test.only']); gulp.task('test', 'Run all tests', (callback) => { - runSequence('build', 'test.only', callback); + runSequence('build', 'test.only', 'internal.test.test', callback); }); gulp.task('doc.gen', 'Generate documentation', ['native.core.doc.gen']); diff --git a/package.json b/package.json index fb6262141..e8d7a1128 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@types/node": "^8.0.32", "@types/pify": "^3.0.0", "@types/semver": "^5.5.0", + "coveralls": "^3.0.1", "del": "^3.0.0", "execa": "^0.8.0", "gulp": "^3.9.1", @@ -35,8 +36,11 @@ "mocha": "^3.5.3", "mocha-jenkins-reporter": "^0.3.9", "ncp": "^2.0.0", + "nyc": "^11.7.2", "pify": "^3.0.0", + "run-sequence": "^2.2.0", "semver": "^5.5.0", + "symlink": "^2.1.0", "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", @@ -48,8 +52,19 @@ "name": "Google Inc." } ], - "dependencies": { - "run-sequence": "^2.2.0", - "symlink": "^2.1.0" + "nyc": { + "include": [ + "packages/grpc-health-check/health.js", + "packages/grpc-js-core/build/src/*", + "packages/grpc-native-core/index.js", + "packages/grpc-native-core/src/*.js", + "packages/grpc-protobufjs/build/src/*" + ], + "cache": true, + "all": true + }, + "scripts": { + "test": "nyc gulp test", + "coverage": "nyc report --reporter=text-lcov | coveralls" } } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index c03389d88..40b5a93d8 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -82,6 +82,15 @@ export interface Channel extends EventEmitter { /* tslint:enable:no-any */ } +/* This should be a real subchannel class that contains a ClientHttp2Session, + * but for now this serves its purpose */ +type Http2SubChannel = http2.ClientHttp2Session & { + /* Count the number of currently active streams associated with the session. + * The purpose of this is to keep the session reffed if and only if there + * is at least one active stream */ + streamCount?: number; +}; + export class Http2Channel extends EventEmitter implements Channel { private readonly userAgent: string; private readonly target: url.URL; @@ -91,7 +100,7 @@ export class Http2Channel extends EventEmitter implements Channel { private connecting: Promise|null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ - private subChannel: http2.ClientHttp2Session|null = null; + private subChannel: Http2SubChannel|null = null; private filterStackFactory: FilterStackFactory; private subChannelConnectCallback: () => void = () => {}; @@ -160,7 +169,7 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - let subChannel: http2.ClientHttp2Session; + let subChannel: Http2SubChannel; const secureContext = this.credentials.getSecureContext(); if (secureContext === null) { subChannel = http2.connect(this.target); @@ -260,11 +269,25 @@ export class Http2Channel extends EventEmitter implements Channel { headers[HTTP2_HEADER_PATH] = methodName; headers[HTTP2_HEADER_TE] = 'trailers'; if (this.connectivityState === ConnectivityState.READY) { - const session: http2.ClientHttp2Session = this.subChannel!; - // Prevent the HTTP/2 session from keeping the process alive. - // Note: this function is only available in Node 9 - session.unref(); - stream.attachHttp2Stream(session.request(headers)); + const session: Http2SubChannel = this.subChannel!; + let http2Stream = session.request(headers); + /* This is a very ad-hoc reference counting scheme. This should be + * handled by a subchannel class */ + session.ref(); + if (!session.streamCount) { + session.streamCount = 0; + } + session.streamCount += 1; + http2Stream.on('close', () => { + if (!session.streamCount) { + session.streamCount = 0; + } + session.streamCount -= 1; + if (session.streamCount <= 0) { + session.unref(); + } + }); + stream.attachHttp2Stream(http2Stream); } else { /* In this case, we lost the connection while finalizing * metadata. That should be very unusual */ diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 1ed26975b..8890edb81 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.1.0", + "version": "0.2.0", "author": "Google Inc.", "contributors": [ { @@ -47,5 +47,8 @@ "clang-format": "^1.2.2", "gts": "^0.5.3", "typescript": "~2.7.2" + }, + "engines": { + "node": ">=6" } } diff --git a/run-tests.sh b/run-tests.sh index 300a25274..4484d40b1 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -39,9 +39,25 @@ npm install --unsafe-perm mkdir -p reports export JOBS=8 +export JUNIT_REPORT_STACK=1 + +OS=$(uname) + +if [ "$OS" = "Linux" ] +then + gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp + set +x + . /tmp/grpc-node.rc + set -x + export COVERALLS_REPO_TOKEN + export COVERALLS_SERVICE_NAME=Kokoro + export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID +fi # TODO(mlumish): Add electron tests +FAILED="false" + for version in ${node_versions} do # Install and setup node for the version we want. @@ -51,6 +67,8 @@ do nvm use $version set -ex + export JUNIT_REPORT_PATH="reports/node$version/" + # https://github.com/mapbox/node-pre-gyp/issues/362 npm install -g node-gyp @@ -62,8 +80,8 @@ do ./node_modules/.bin/gulp clean.all ./node_modules/.bin/gulp setup - # Rebuild libraries and run tests. - JUNIT_REPORT_PATH="reports/node$version/" JUNIT_REPORT_STACK=1 ./node_modules/.bin/gulp test || FAILED="true" + # npm test calls nyc gulp test + npm test || FAILED="true" done set +ex @@ -72,7 +90,12 @@ set -ex node merge_kokoro_logs.js -if [ "$FAILED" != "" ] +if [ "$FAILED" = "true" ] then exit 1 +else + if [ "$OS" = "Linux" ] + then + npm run coverage + fi fi diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 1152b3109..0ff4c28bb 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -68,7 +68,7 @@ describe('Interop tests', function() { throw new Error(`Server exited with signal ${signal}`); } } - }) + }); }); after(function() { serverProcess.send({}); diff --git a/test/gulpfile.js b/test/gulpfile.js index 61ff16586..2aa1c9c26 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -21,6 +21,7 @@ const mocha = require('gulp-mocha'); const execa = require('execa'); const path = require('path'); const del = require('del'); +const semver = require('semver'); const linkSync = require('../util').linkSync; // gulp-help monkeypatches tasks to have an additional description parameter @@ -38,6 +39,10 @@ gulp.task('clean.all', 'Delete all files created by tasks', () => {}); gulp.task('test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream + if (!semver.satisfies(process.version, '>=9.4')) { + console.log(`Skipping cross-implementation tests for Node ${process.version}`); + return; + } const apiTestGlob = `${apiTestDir}/*.js`; const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { const fixture = `${server}_${client}`; @@ -51,12 +56,19 @@ gulp.task('test', 'Run API-level tests', () => { .on('end', resolve) .on('error', reject); }); - const runTestsArgPairs = [ - ['native', 'native'], - ['native', 'js'], - // ['js', 'native'], - // ['js', 'js'] - ]; + var runTestsArgPairs; + if (semver.satisfies(process.version, '>=9.4')) { + runTestsArgPairs = [ + ['native', 'native'], + ['native', 'js'], + // ['js', 'native'], + // ['js', 'js'] + ]; + } else { + runTestsArgPairs = [ + ['native', 'native'] + ]; + } return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); }, Promise.resolve()); diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index fb6026e05..195ef8d47 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -616,8 +616,12 @@ if (require.main === module) { }; runTest(argv.server_host + ':' + argv.server_port, argv.server_host_override, argv.test_case, argv.use_tls === 'true', argv.use_test_ca === 'true', - function () { - console.log('OK:', argv.test_case); + function (err) { + if (err) { + throw err; + } else { + console.log('OK:', argv.test_case); + } }, extra_args); } From 5daba7e249f08ef6506328aed9232fb13da66799 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 16 May 2018 14:18:38 -0700 Subject: [PATCH 0254/1899] Skip coverage reporting if token file can't be downloaded --- run-tests.sh | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/run-tests.sh b/run-tests.sh index 4484d40b1..a5195716b 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -43,17 +43,6 @@ export JUNIT_REPORT_STACK=1 OS=$(uname) -if [ "$OS" = "Linux" ] -then - gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp - set +x - . /tmp/grpc-node.rc - set -x - export COVERALLS_REPO_TOKEN - export COVERALLS_SERVICE_NAME=Kokoro - export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID -fi - # TODO(mlumish): Add electron tests FAILED="false" @@ -96,6 +85,14 @@ then else if [ "$OS" = "Linux" ] then + # If we can't download the token file, just skip reporting coverage + gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp || exit 0 + set +x + . /tmp/grpc-node.rc + set -x + export COVERALLS_REPO_TOKEN + export COVERALLS_SERVICE_NAME=Kokoro + export COVERALLS_SERVICE_JOB_ID=$KOKORO_BUILD_ID npm run coverage fi fi From a0c2cf7b2c72b0b22905e34c3f2d6ad8a952f7aa Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 16 May 2018 22:12:01 -0700 Subject: [PATCH 0255/1899] Create issue templates --- .github/ISSUE_TEMPLATE/bug_report.md | 19 +++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..930a2e1d4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,19 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + +**Describe the problem** +A clear and concise description of what the problem is. + +**To Reproduce** +Give very precise steps you've discovered to reproduce your problem. If possible and applicable, provide us with a repository we can clone that contains a reproduction case. Also if possible and applicable, please include a Dockerfile that exhibits the problem if it's specific to a certain environment. Bug reports with no reproduction steps will be closed. + +**Environment (please complete the following information):** + - OS name and version: [e.g. Linux Ubuntu 18.04] + - Node version [e.g. 8.10.0] + - Node installation method [e.g. nvm] + +**Additional context** +Add any other context about the problem here. If possible, attach full logs. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..d032a4e94 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,17 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context about the feature request here. From acb7c2a5adf1ec755b2aa1f535e85e5d66c8e062 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 16 May 2018 22:30:45 -0700 Subject: [PATCH 0256/1899] Adding the package version field. --- .github/ISSUE_TEMPLATE/bug_report.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 930a2e1d4..5329d43de 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -14,6 +14,7 @@ Give very precise steps you've discovered to reproduce your problem. If possible - OS name and version: [e.g. Linux Ubuntu 18.04] - Node version [e.g. 8.10.0] - Node installation method [e.g. nvm] + - Package name and version [e.g. gRPC@1.12.0] **Additional context** Add any other context about the problem here. If possible, attach full logs. From 69add87bd4402482d1b9d5914e8e3beacdb980b6 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 16 May 2018 22:31:36 -0700 Subject: [PATCH 0257/1899] Removing the "please complete..." section. --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5329d43de..1b46929cd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -10,7 +10,7 @@ A clear and concise description of what the problem is. **To Reproduce** Give very precise steps you've discovered to reproduce your problem. If possible and applicable, provide us with a repository we can clone that contains a reproduction case. Also if possible and applicable, please include a Dockerfile that exhibits the problem if it's specific to a certain environment. Bug reports with no reproduction steps will be closed. -**Environment (please complete the following information):** +**Environment** - OS name and version: [e.g. Linux Ubuntu 18.04] - Node version [e.g. 8.10.0] - Node installation method [e.g. nvm] From b89330e1d3c926d4f18edf1514f06a03e02b1df5 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 16 May 2018 22:41:42 -0700 Subject: [PATCH 0258/1899] Adding even more fields, and a few words on logs. --- .github/ISSUE_TEMPLATE/bug_report.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 1b46929cd..5c57be3f7 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -11,10 +11,11 @@ A clear and concise description of what the problem is. Give very precise steps you've discovered to reproduce your problem. If possible and applicable, provide us with a repository we can clone that contains a reproduction case. Also if possible and applicable, please include a Dockerfile that exhibits the problem if it's specific to a certain environment. Bug reports with no reproduction steps will be closed. **Environment** - - OS name and version: [e.g. Linux Ubuntu 18.04] + - OS name, version and architecture: [e.g. Linux Ubuntu 18.04 amd64] - Node version [e.g. 8.10.0] - Node installation method [e.g. nvm] + - If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4] - Package name and version [e.g. gRPC@1.12.0] **Additional context** -Add any other context about the problem here. If possible, attach full logs. +Add any other context about the problem here. If possible, attach full logs. Do not try to omit anything for brevity, but instead include absolutely everything. Please try and set your operating system's locale to English, so that logs contain error messages in the English language. From 4004e2428c8ff305d29c4b53159e5f80ad1375f0 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 16 May 2018 22:43:06 -0700 Subject: [PATCH 0259/1899] Better headings. --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5c57be3f7..9e8a2b1ec 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,10 +4,10 @@ about: Create a report to help us improve --- -**Describe the problem** +**Problem description** A clear and concise description of what the problem is. -**To Reproduce** +**Reproduction steps** Give very precise steps you've discovered to reproduce your problem. If possible and applicable, provide us with a repository we can clone that contains a reproduction case. Also if possible and applicable, please include a Dockerfile that exhibits the problem if it's specific to a certain environment. Bug reports with no reproduction steps will be closed. **Environment** From 6e4ccb111ec80d6af826630178b6e6532afb8ada Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 16 May 2018 22:44:38 -0700 Subject: [PATCH 0260/1899] Actual headings. --- .github/ISSUE_TEMPLATE/bug_report.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 9e8a2b1ec..a5200c9cd 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,18 +4,18 @@ about: Create a report to help us improve --- -**Problem description** +### Problem description A clear and concise description of what the problem is. -**Reproduction steps** +### Reproduction steps Give very precise steps you've discovered to reproduce your problem. If possible and applicable, provide us with a repository we can clone that contains a reproduction case. Also if possible and applicable, please include a Dockerfile that exhibits the problem if it's specific to a certain environment. Bug reports with no reproduction steps will be closed. -**Environment** +### Environment - OS name, version and architecture: [e.g. Linux Ubuntu 18.04 amd64] - Node version [e.g. 8.10.0] - Node installation method [e.g. nvm] - If applicable, compiler version [e.g. clang 3.8.0-2ubuntu4] - Package name and version [e.g. gRPC@1.12.0] -**Additional context** +### Additional context Add any other context about the problem here. If possible, attach full logs. Do not try to omit anything for brevity, but instead include absolutely everything. Please try and set your operating system's locale to English, so that logs contain error messages in the English language. From dd7725d9a3637cdcaa01658fddc359fd08f42b91 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 18 May 2018 02:13:31 +0200 Subject: [PATCH 0261/1899] Using debian:stretch for the release process. --- tools/release/kokoro/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/release/kokoro/Dockerfile b/tools/release/kokoro/Dockerfile index 0c31914b2..7dabff9ad 100644 --- a/tools/release/kokoro/Dockerfile +++ b/tools/release/kokoro/Dockerfile @@ -1,8 +1,9 @@ -FROM ubuntu:16.04 +FROM debian:stretch RUN dpkg --add-architecture i386 RUN apt-get update -RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf docker.io python libc6-dev:i386 lib32stdc++-5-dev +RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf python libc6-dev:i386 lib32stdc++-6-dev +RUN curl -fsSL get.docker.com | bash RUN mkdir /usr/local/nvm ENV NVM_DIR /usr/local/nvm From 2321c1a8fe9ce3af731a4a835f6de86dc8cb9313 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 18 May 2018 02:52:56 +0200 Subject: [PATCH 0262/1899] Bumping to 1.12.1-pre1. --- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..184e37a54 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.12.1-pre1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 801b5faef..a1b69c486 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.0", + "version": "1.12.1-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 968a706a891469bbcc6889c670f5b9f4e8f47cf1 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 18 May 2018 09:22:07 +0200 Subject: [PATCH 0263/1899] Split native and cross compilers into two docker images. --- .../artifacts/build_all_linux_artifacts.sh | 28 +++++++++++++++---- tools/release/{kokoro => cross}/Dockerfile | 0 tools/release/kokoro.sh | 7 +++-- tools/release/native/Dockerfile | 10 +++++++ 4 files changed, 38 insertions(+), 7 deletions(-) rename tools/release/{kokoro => cross}/Dockerfile (100%) create mode 100644 tools/release/native/Dockerfile diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 64d3d8627..2276b3e56 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -20,6 +20,21 @@ npm install -g npm # https://github.com/mapbox/node-pre-gyp/issues/362 npm install -g node-gyp +DO_NATIVE=true +DO_CROSS=true + +while [ $# -gt 0 ] ; do + case $1 in + --native-only) + DO_CROSS=false + ;; + --cross-only) + DO_NATIVE=false + ;; + esac + shift +done + set -ex cd $(dirname $0) @@ -34,10 +49,13 @@ rm -rf build || true mkdir -p "${ARTIFACTS_OUT}" -docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact - -$tool_dir/build_artifact_node.sh +if [ "$DO_NATIVE" = "true" ] ; then + $tool_dir/build_artifact_node.sh +fi -$tool_dir/build_artifact_node_arm.sh +if [ "$DO_CROSS" = "true" ] ; then + $tool_dir/build_artifact_node_arm.sh -docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine + docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact + docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine +fi diff --git a/tools/release/kokoro/Dockerfile b/tools/release/cross/Dockerfile similarity index 100% rename from tools/release/kokoro/Dockerfile rename to tools/release/cross/Dockerfile diff --git a/tools/release/kokoro.sh b/tools/release/kokoro.sh index 5a2a63e21..97677af15 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro.sh @@ -38,8 +38,11 @@ OS=`uname` case $OS in Linux) - docker build -t kokoro-image tools/release/kokoro - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh + docker build -t kokoro-native-image tools/release/native + docker build -t kokoro-cross-image tools/release/cross + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --native-only + cp -rv packages/grpc-native-core/artifacts . + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-cross-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --cross-only cp -rv packages/grpc-native-core/artifacts . ;; Darwin) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile new file mode 100644 index 000000000..35e841ccc --- /dev/null +++ b/tools/release/native/Dockerfile @@ -0,0 +1,10 @@ +FROM debian:jessie + +RUN apt-get update +RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev +RUN curl -fsSL get.docker.com | bash + +RUN mkdir /usr/local/nvm +ENV NVM_DIR /usr/local/nvm + +RUN curl curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash From 1a681addfeb9731acc7d6d225f5b36372d70b5fd Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 18 May 2018 09:47:13 +0200 Subject: [PATCH 0264/1899] Bumping to 1.12.1-pre3. Yes, I did a lot of testing. --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 184e37a54..7903791f9 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.12.1-pre1 + node_version: 1.12.1-pre3 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index a1b69c486..e32e1ceb3 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.1-pre1", + "version": "1.12.1-pre3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 0b84631094ba4d75e9cd9c955d1f2fba065282df Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 May 2018 10:35:50 -0700 Subject: [PATCH 0265/1899] Change bold to headings in feature_request.md For consistency with the bug report template. --- .github/ISSUE_TEMPLATE/feature_request.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index d032a4e94..13a22d907 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,14 +4,14 @@ about: Suggest an idea for this project --- -**Is your feature request related to a problem? Please describe.** +### Is your feature request related to a problem? Please describe. A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -**Describe the solution you'd like** +### Describe the solution you'd like A clear and concise description of what you want to happen. -**Describe alternatives you've considered** +### Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered. -**Additional context** +### Additional context Add any other context about the feature request here. From 7b9ad34d506671c8962f02992cdabfdab97d059f Mon Sep 17 00:00:00 2001 From: Ali Ijaz Sheikh Date: Mon, 21 May 2018 07:44:37 -0700 Subject: [PATCH 0266/1899] chore: add repository to package.json --- packages/grpc-js-core/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index e7ee8ea15..07d2cd717 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "description": "gRPC Library for Node - pure JS core", "homepage": "https://grpc.io/", + "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core" "main": "build/src/index.js", "engines": { "node": ">=8.4" From 1192eed4980362fb7e7da55ca986102158792ddb Mon Sep 17 00:00:00 2001 From: Ali Ijaz Sheikh Date: Mon, 21 May 2018 07:48:16 -0700 Subject: [PATCH 0267/1899] [squash] fix typo --- packages/grpc-js-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 07d2cd717..62d2bc64c 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "description": "gRPC Library for Node - pure JS core", "homepage": "https://grpc.io/", - "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core" + "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", "main": "build/src/index.js", "engines": { "node": ">=8.4" From d8016fa09da7c73b82dd380a90dfd55f52cecd0d Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Tue, 22 May 2018 16:25:45 -0700 Subject: [PATCH 0268/1899] Create template issue for protobufjs specifically. --- .github/ISSUE_TEMPLATE/protobufjs_redos | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/protobufjs_redos diff --git a/.github/ISSUE_TEMPLATE/protobufjs_redos b/.github/ISSUE_TEMPLATE/protobufjs_redos new file mode 100644 index 000000000..a0505c4ec --- /dev/null +++ b/.github/ISSUE_TEMPLATE/protobufjs_redos @@ -0,0 +1,8 @@ +--- +name: ReDoS vulnerability +about: npm audit reports that protobufjs has a ReDoS vulnerability. + +--- +As I ran `npm install`, the tool told me that protobufjs has 1 moderate vulnerability, as described here: https://nodesecurity.io/advisories/605 + +The gRPC team is aware of this, and this issue would be a duplicate of #277. The gRPC package can't upgrade the protobufjs dependency without proceeding with a breaking change, and the fix has been backported to protobufjs 5.0.3 already - it's simply the nodesecurity.io database that is outdated. From b9b7d333d45b39521bf68207e40b7824ac708bc2 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 23 May 2018 01:58:38 +0200 Subject: [PATCH 0269/1899] Bumping to 1.12.1. --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 7903791f9..0bc16b05f 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.12.1-pre3 + node_version: 1.12.1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e32e1ceb3..b71ca430a 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.1-pre3", + "version": "1.12.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From faa1169493851a5ad025ac7e6702c462b7c71615 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 May 2018 17:23:24 -0700 Subject: [PATCH 0270/1899] Update protobufjs_redos Add variants, newlines, changed words slightly. --- .github/ISSUE_TEMPLATE/protobufjs_redos | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/protobufjs_redos b/.github/ISSUE_TEMPLATE/protobufjs_redos index a0505c4ec..149d56d94 100644 --- a/.github/ISSUE_TEMPLATE/protobufjs_redos +++ b/.github/ISSUE_TEMPLATE/protobufjs_redos @@ -3,6 +3,10 @@ name: ReDoS vulnerability about: npm audit reports that protobufjs has a ReDoS vulnerability. --- -As I ran `npm install`, the tool told me that protobufjs has 1 moderate vulnerability, as described here: https://nodesecurity.io/advisories/605 +As I [ran `npm install`]/[ran 'npm audit']/[got a report from Snyk], +the tool told me that protobufjs has 1 moderate vulnerability exported +through the `grpc` package, as described here: https://nodesecurity.io/advisories/605 -The gRPC team is aware of this, and this issue would be a duplicate of #277. The gRPC package can't upgrade the protobufjs dependency without proceeding with a breaking change, and the fix has been backported to protobufjs 5.0.3 already - it's simply the nodesecurity.io database that is outdated. +The gRPC team is aware of this, and this issue is a duplicate of #277. +Upgrading this depdendency would be a breaking change, and the fix has been backported +to protobufjs 5.0.3 already; the [nodesecurity.io]/[Snyk] database is simply outdated. From 0eb9159d5ef2cf45e83053579ddf6d8408cf0f21 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Tue, 22 May 2018 19:51:17 -0700 Subject: [PATCH 0271/1899] Rename protobufjs_redos to protobufjs_redos.md --- .github/ISSUE_TEMPLATE/{protobufjs_redos => protobufjs_redos.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/ISSUE_TEMPLATE/{protobufjs_redos => protobufjs_redos.md} (100%) diff --git a/.github/ISSUE_TEMPLATE/protobufjs_redos b/.github/ISSUE_TEMPLATE/protobufjs_redos.md similarity index 100% rename from .github/ISSUE_TEMPLATE/protobufjs_redos rename to .github/ISSUE_TEMPLATE/protobufjs_redos.md From fb1dfb87ba8ebdabf13f0c81cc7a4cd80f12e741 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 24 May 2018 05:34:25 +0200 Subject: [PATCH 0272/1899] Bumping to 1.12.2. --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 0bc16b05f..3577ac832 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.12.1 + node_version: 1.12.2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index b71ca430a..a9f42aa03 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.1", + "version": "1.12.2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 087a83294de00379e49e1858a8b49ed75bbd35ae Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 24 May 2018 05:42:41 +0200 Subject: [PATCH 0273/1899] Ensuring the presence of node-pre-gyp before publishing. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index b71ca430a..4328c08a8 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -23,7 +23,7 @@ "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library", - "prepublish": "git submodule update --init --recursive" + "prepack": "git submodule update --init --recursive && npm install" }, "bundledDependencies": [ "node-pre-gyp" diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index f0ed684ce..82d6d1076 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -25,7 +25,7 @@ "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library", - "prepublish": "git submodule update --init --recursive" + "prepack": "git submodule update --init --recursive && npm install" }, "bundledDependencies": [ "node-pre-gyp" From eff1f8d8267bfa2155b8201ae30d91aa61f2a4f5 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 25 May 2018 18:48:55 +0200 Subject: [PATCH 0274/1899] Increasing mocha timeout to 5s up from 2s. Our fleet of macos is a bit less powerful than the rest, so we regularly flake tests there due to this timeout. --- packages/grpc-native-core/gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/gulpfile.js b/packages/grpc-native-core/gulpfile.js index 71a0b0ba7..8e32d743a 100644 --- a/packages/grpc-native-core/gulpfile.js +++ b/packages/grpc-native-core/gulpfile.js @@ -68,7 +68,7 @@ gulp.task('build', 'Build native package', () => { }); gulp.task('test', 'Run all tests', ['build'], () => { - return gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); + return gulp.src(`${testDir}/*.js`).pipe(mocha({timeout: 5000, reporter: 'mocha-jenkins-reporter'})); }); gulp.task('doc.gen', 'Generate docs', (cb) => { From 14cf37fdd96bdbef8fe36016097bd1a275424f44 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 30 May 2018 15:56:58 -0700 Subject: [PATCH 0275/1899] Add compression handling on send and receive paths --- packages/grpc-js-core/src/call-stream.ts | 111 ++++++----- packages/grpc-js-core/src/channel.ts | 3 +- .../grpc-js-core/src/compression-filter.ts | 174 +++++++++++++++++- packages/grpc-js-core/src/filter-stack.ts | 13 +- packages/grpc-js-core/src/filter.ts | 14 +- .../grpc-js-core/test/test-call-stream.ts | 8 +- 6 files changed, 273 insertions(+), 50 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index eb6b743e2..10c47a6e5 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -29,6 +29,12 @@ export interface StatusObject { metadata: Metadata; } +export const enum WriteFlags { + BufferHint = 1, + NoCompress = 2, + WriteThrough = 4 +} + export interface WriteObject { message: Buffer; flags?: number; @@ -69,14 +75,18 @@ export class Http2CallStream extends Duplex implements CallStream { private pendingFinalCallback: Function|null = null; private readState: ReadState = ReadState.NO_DATA; - private readCompressFlag = false; + private readCompressFlag: Buffer = Buffer.alloc(1); private readPartialSize: Buffer = Buffer.alloc(4); private readSizeRemaining = 4; private readMessageSize = 0; private readPartialMessage: Buffer[] = []; private readMessageRemaining = 0; + private isReadFilterPending = false; + private canPush = false; + private unpushedReadMessages: Array = []; + private unfilteredReadMessages: Array = []; // Status code mapped from :status. To be used if grpc-status is not received private mappedStatusCode: Status = Status.UNKNOWN; @@ -111,16 +121,49 @@ export class Http2CallStream extends Duplex implements CallStream { } } - private tryPush(messageBytes: Buffer, canPush: boolean): boolean { - if (canPush) { - if (!this.push(messageBytes)) { - canPush = false; + private handleFilterError(error: Error) { + this.cancelWithStatus(Status.INTERNAL, error.message); + } + + private handleFilteredRead(message: Buffer) { + this.isReadFilterPending = false; + if (this.canPush) { + if (!this.push(message)) { + this.canPush = false; (this.http2Stream as http2.ClientHttp2Stream).pause(); } } else { - this.unpushedReadMessages.push(messageBytes); + this.unpushedReadMessages.push(message); + } + if (this.unfilteredReadMessages.length > 0) { + /* nextMessage is guaranteed not to be undefined because + unfilteredReadMessages is non-empty */ + const nextMessage = this.unfilteredReadMessages.shift() as Buffer | null; + this.filterReceivedMessage(nextMessage); + } + } + + private filterReceivedMessage(framedMessage: Buffer | null) { + if (framedMessage === null) { + if (this.canPush) { + this.push(null); + } else { + this.unpushedReadMessages.push(null); + } + return; + } + this.isReadFilterPending = true; + this.filterStack.receiveMessage(Promise.resolve(framedMessage)).then( + this.handleFilteredRead.bind(this), + this.handleFilterError.bind(this)); + } + + private tryPush(messageBytes: Buffer | null): void { + if (this.isReadFilterPending) { + this.unfilteredReadMessages.push(messageBytes); + } else { + this.filterReceivedMessage(messageBytes); } - return canPush; } private handleTrailers(headers: http2.IncomingHttpHeaders) { @@ -219,14 +262,13 @@ export class Http2CallStream extends Duplex implements CallStream { } }); stream.on('trailers', this.handleTrailers.bind(this)); - stream.on('data', (data) => { + stream.on('data', (data: Buffer) => { let readHead = 0; - let canPush = true; let toRead: number; while (readHead < data.length) { switch (this.readState) { case ReadState.NO_DATA: - this.readCompressFlag = (data.readUInt8(readHead) !== 0); + this.readCompressFlag = data.slice(readHead, readHead+1); readHead += 1; this.readState = ReadState.READING_SIZE; this.readPartialSize.fill(0); @@ -249,7 +291,7 @@ export class Http2CallStream extends Duplex implements CallStream { if (this.readMessageRemaining > 0) { this.readState = ReadState.READING_MESSAGE; } else { - canPush = this.tryPush(emptyBuffer, canPush); + this.tryPush(Buffer.concat([this.readCompressFlag, this.readPartialSize])); this.readState = ReadState.NO_DATA; } } @@ -264,10 +306,9 @@ export class Http2CallStream extends Duplex implements CallStream { // readMessageRemaining >=0 here if (this.readMessageRemaining === 0) { // At this point, we have read a full message - const messageBytes = Buffer.concat( - this.readPartialMessage, this.readMessageSize); - // TODO(murgatroid99): Add receive message filters - canPush = this.tryPush(messageBytes, canPush); + const framedMessageBuffers = [this.readCompressFlag, this.readPartialSize].concat(this.readPartialMessage); + const framedMessage = Buffer.concat(framedMessageBuffers, this.readMessageSize + 5); + this.tryPush(framedMessage); this.readState = ReadState.NO_DATA; } break; @@ -277,11 +318,7 @@ export class Http2CallStream extends Duplex implements CallStream { } }); stream.on('end', () => { - if (this.unpushedReadMessages.length === 0) { - this.push(null); - } else { - this.unpushedReadMessages.push(null); - } + this.tryPush(null); }); stream.on('close', async (errorCode) => { let code: Status; @@ -380,13 +417,15 @@ export class Http2CallStream extends Duplex implements CallStream { } _read(size: number) { + this.canPush = true; if (this.http2Stream === null) { this.pendingRead = true; } else { while (this.unpushedReadMessages.length > 0) { const nextMessage = this.unpushedReadMessages.shift(); - const keepPushing = this.push(nextMessage); - if (nextMessage === null || (!keepPushing)) { + this.canPush = this.push(nextMessage); + if (nextMessage === null || (!this.canPush)) { + this.canPush = false; return; } } @@ -397,27 +436,15 @@ export class Http2CallStream extends Duplex implements CallStream { } } - // Encode a message to the wire format - private encodeMessage(message: WriteObject): Buffer { - /* allocUnsafe doesn't initiate the bytes in the buffer. We are explicitly - * overwriting every single byte, so that should be fine */ - const output: Buffer = Buffer.allocUnsafe(message.message.length + 5); - // TODO(murgatroid99): handle compressed flag appropriately - output.writeUInt8(0, 0); - output.writeUInt32BE(message.message.length, 1); - message.message.copy(output, 5); - return output; - } - _write(chunk: WriteObject, encoding: string, cb: Function) { - // TODO(murgatroid99): Add send message filters - const encodedMessage = this.encodeMessage(chunk); - if (this.http2Stream === null) { - this.pendingWrite = encodedMessage; - this.pendingWriteCallback = cb; - } else { - this.http2Stream.write(encodedMessage, cb); - } + this.filterStack.sendMessage(Promise.resolve(chunk)).then((message) => { + if (this.http2Stream === null) { + this.pendingWrite = message.message; + this.pendingWriteCallback = cb; + } else { + this.http2Stream.write(message.message, cb); + } + }, this.handleFilterError.bind(this)); } _final(cb: Function) { diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 40b5a93d8..b1b1e91bf 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -237,9 +237,8 @@ export class Http2Channel extends EventEmitter implements Channel { this.defaultAuthority = this.target.host; } this.filterStackFactory = new FilterStackFactory([ - new CompressionFilterFactory(this), new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), - new MetadataStatusFilterFactory(this) + new MetadataStatusFilterFactory(this), new CompressionFilterFactory(this) ]); this.currentBackoffDeadline = new Date(); /* The only purpose of these lines is to ensure that this.backoffTimerId has diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index 134662dc8..df0e5c9fb 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -1,22 +1,190 @@ -import {CallStream} from './call-stream'; +import {CallStream, WriteObject, WriteFlags} from './call-stream'; import {Channel} from './channel'; import {BaseFilter, Filter, FilterFactory} from './filter'; -import {Metadata} from './metadata'; +import {Metadata, MetadataValue} from './metadata'; +import {Status} from './constants'; +import * as zlib from 'zlib'; + +abstract class CompressionHandler { + protected abstract compressMessage(message: Buffer): Promise; + protected abstract decompressMessage(data: Buffer): Promise; + /** + * @param message Raw uncompressed message bytes + * @param compress Indicates whether the message should be compressed + * @return Framed message, compressed if applicable + */ + async writeMessage(message: Buffer, compress: boolean): Promise { + let messageBuffer = message; + if (compress) { + messageBuffer = await this.compressMessage(messageBuffer); + } + let output = Buffer.allocUnsafe(messageBuffer.length + 5); + output.writeUInt8(compress ? 1 : 0, 0); + output.writeUInt32BE(messageBuffer.length, 1); + messageBuffer.copy(output, 5); + return output; + } + /** + * @param data Framed message, possibly compressed + * @return Uncompressed message + */ + async readMessage(data: Buffer): Promise { + const compressed = data.readUInt8(1) === 1; + let messageBuffer = data.slice(5); + if (compressed) { + messageBuffer = await this.decompressMessage(messageBuffer); + } + return messageBuffer; + } +} + +class IdentityHandler extends CompressionHandler{ + async compressMessage(message: Buffer) { + return message; + } + + async writeMessage(message: Buffer, compress: boolean): Promise { + let output = Buffer.allocUnsafe(message.length + 5); + /* With "identity" compression, messages should always be marked as + * uncompressed */ + output.writeUInt8(0, 0); + output.writeUInt32BE(message.length, 1); + message.copy(output, 5); + return output; + } + + decompressMessage(message: Buffer) : Promise { + return Promise.reject(new Error( + 'Received compressed message but "grpc-encoding" header was identity')); + } +} + +class DeflateHandler extends CompressionHandler { + compressMessage(message: Buffer) { + return new Promise((resolve, reject) => { + zlib.deflate(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }) + }); + } + + decompressMessage(message: Buffer) { + return new Promise((resolve, reject) => { + zlib.inflate(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }) + }); + } +} + +class GzipHandler extends CompressionHandler { + compressMessage(message: Buffer) { + return new Promise((resolve, reject) => { + zlib.gzip(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }) + }); + } + + decompressMessage(message: Buffer) { + return new Promise((resolve, reject) => { + zlib.unzip(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }) + }); + } +} + +class UnknownHandler extends CompressionHandler { + constructor(private readonly compressionName: string) { + super(); + } + compressMessage(message: Buffer): Promise { + return Promise.reject(new Error( + `Received message compressed wth unsupported compression method ${this.compressionName}`)); + } + + decompressMessage(message: Buffer): Promise { + // This should be unreachable + return Promise.reject(new Error( + `Compression method not supported: ${this.compressionName}`)); + } +} + +function getCompressionHandler(compressionName: string): CompressionHandler { + switch (compressionName) { + case 'identity': + return new IdentityHandler(); + case 'deflate': + return new DeflateHandler(); + case 'gzip': + return new GzipHandler(); + default: + return new UnknownHandler(compressionName); + } +} export class CompressionFilter extends BaseFilter implements Filter { + private sendCompression: CompressionHandler = new IdentityHandler(); + private receiveCompression: CompressionHandler = new IdentityHandler(); async sendMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; headers.set('grpc-encoding', 'identity'); - headers.set('grpc-accept-encoding', 'identity'); + headers.set('grpc-accept-encoding', 'identity,deflate,gzip'); return headers; } async receiveMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; + let receiveEncoding: MetadataValue[] = headers.get('grpc-encoding'); + if (receiveEncoding.length > 0) { + const encoding: MetadataValue = receiveEncoding[0]; + if (typeof encoding === 'string') { + this.receiveCompression = getCompressionHandler(encoding); + } + } headers.remove('grpc-encoding'); headers.remove('grpc-accept-encoding'); return headers; } + + async sendMessage(message: Promise): Promise { + + /* This filter is special. The input message is the bare message bytes, + * and the output is a framed and possibly compressed message. For this + * reason, this filter should be at the bottom of the filter stack */ + const resolvedMessage: WriteObject = await message; + const compress = resolvedMessage.flags === undefined ? false : + (resolvedMessage.flags & WriteFlags.NoCompress) === 0; + return { + message: await this.sendCompression.writeMessage(resolvedMessage.message, compress), + flags: resolvedMessage.flags + }; + } + + async receiveMessage(message: Promise) { + /* This filter is also special. The input message is framed and possibly + * compressed, and the output message is deframed and uncompressed. So + * this is another reason that this filter should be at the bottom of the + * filter stack. */ + return await this.receiveCompression.readMessage(await message); + } } export class CompressionFilterFactory implements diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js-core/src/filter-stack.ts index 66337c3ab..9cbfd398a 100644 --- a/packages/grpc-js-core/src/filter-stack.ts +++ b/packages/grpc-js-core/src/filter-stack.ts @@ -1,6 +1,6 @@ import {flow, flowRight, map} from 'lodash'; -import {CallStream, StatusObject} from './call-stream'; +import {CallStream, StatusObject, WriteObject} from './call-stream'; import {Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; @@ -18,6 +18,17 @@ export class FilterStack implements Filter { metadata); } + sendMessage(message: Promise): Promise { + return flow(map( + this.filters, (filter) => filter.sendMessage.bind(filter)))(message); + } + + receiveMessage(message: Promise): Promise { + return flowRight( + map(this.filters, (filter) => filter.receiveMessage.bind(filter)))( + message); + } + receiveTrailers(status: Promise): Promise { return flowRight(map( this.filters, (filter) => filter.receiveTrailers.bind(filter)))(status); diff --git a/packages/grpc-js-core/src/filter.ts b/packages/grpc-js-core/src/filter.ts index bb4e0a930..a2da1760d 100644 --- a/packages/grpc-js-core/src/filter.ts +++ b/packages/grpc-js-core/src/filter.ts @@ -1,4 +1,4 @@ -import {CallStream, StatusObject} from './call-stream'; +import {CallStream, StatusObject, WriteObject} from './call-stream'; import {Metadata} from './metadata'; /** @@ -10,6 +10,10 @@ export interface Filter { receiveMetadata(metadata: Promise): Promise; + sendMessage(message: Promise): Promise; + + receiveMessage(message: Promise): Promise; + receiveTrailers(status: Promise): Promise; } @@ -22,6 +26,14 @@ export abstract class BaseFilter { return await metadata; } + async sendMessage(message: Promise): Promise { + return await message; + } + + async receiveMessage(message: Promise): Promise { + return await message; + } + async receiveTrailers(status: Promise): Promise { return await status; } diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index aff6ed635..decb0e7fb 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -6,11 +6,13 @@ import * as stream from 'stream'; import {CallCredentials} from '../src/call-credentials'; import {Http2CallStream} from '../src/call-stream'; +import {CompressionFilterFactory} from '../src/compression-filter'; import {Status} from '../src/constants'; import {FilterStackFactory} from '../src/filter-stack'; import {Metadata} from '../src/metadata'; import {assert2, mockFunction} from './common'; +import { Channel } from '../src/channel'; interface DataFrames { payload: Buffer; @@ -83,7 +85,11 @@ describe('CallStream', () => { flags: 0, host: '' }; - const filterStackFactory = new FilterStackFactory([]); + /* A CompressionFilter is now necessary to frame and deframe messages. + * Currently the channel is unused, so we can replace it with an empty object, + * but this might break if we start checking channel arguments, in which case + * we will need a more sophisticated fake */ + const filterStackFactory = new FilterStackFactory([new CompressionFilterFactory({})]); const message = 'eat this message'; // 16 bytes beforeEach(() => { From aa9d47da140dbe6aacb9695132ec039976723781 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 30 May 2018 15:57:35 -0700 Subject: [PATCH 0276/1899] Make grpc-js tests run on Node 8.11.2 --- packages/grpc-js-core/gulpfile.ts | 6 ++++-- test/gulpfile.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-core/gulpfile.ts b/packages/grpc-js-core/gulpfile.ts index fcce74cd5..b75350cc2 100644 --- a/packages/grpc-js-core/gulpfile.ts +++ b/packages/grpc-js-core/gulpfile.ts @@ -72,10 +72,12 @@ gulp.task('copy-test-fixtures', 'Copy test fixtures.', () => { * Transpiles src/ and test/, and then runs all tests. */ gulp.task('test', 'Runs all tests.', ['copy-test-fixtures'], () => { - if (semver.satisfies(process.version, '>=9.4')) { + if (semver.satisfies(process.version, '^8.11.2 || >=9.4')) { return gulp.src(`${outDir}/test/**/*.js`) - .pipe(mocha({reporter: 'mocha-jenkins-reporter'})); + .pipe(mocha({reporter: 'mocha-jenkins-reporter', + require: ['ts-node/register']})); } else { console.log(`Skipping grpc-js tests for Node ${process.version}`); + return Promise.resolve(null); } }); diff --git a/test/gulpfile.js b/test/gulpfile.js index 2aa1c9c26..42ff04f0d 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -57,7 +57,7 @@ gulp.task('test', 'Run API-level tests', () => { .on('error', reject); }); var runTestsArgPairs; - if (semver.satisfies(process.version, '>=9.4')) { + if (semver.satisfies(process.version, '^ 8.11.2 || >=9.4')) { runTestsArgPairs = [ ['native', 'native'], ['native', 'js'], From 3edea49bb3b9340a24725fac97b88f069edbf61e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 30 May 2018 15:57:58 -0700 Subject: [PATCH 0277/1899] Compile grpc-js to ES6 to improve debugging --- packages/grpc-js-core/src/index.ts | 24 ++++++++++++++++++++---- packages/grpc-js-core/tsconfig.json | 3 ++- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 9b6cea51a..e8ec58340 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -8,6 +8,24 @@ import {Status} from './constants'; import {loadPackageDefinition, makeClientConstructor} from './make-client'; import {Metadata} from './metadata'; +interface IndexedObject { + [key: string]: any; + [key: number]: any; +} + +function mixin(...sources: IndexedObject[]) { + const result: {[key: string]: Function} = {}; + for(const source of sources) { + for(const propName of Object.getOwnPropertyNames(source)) { + const property: any = source[propName]; + if (typeof property === 'function') { + result[propName] = property; + } + } + } + return result; +} + export interface OAuth2Client { getRequestMetadata: (url: string, callback: (err: Error|null, headers?: { Authorization: string @@ -17,8 +35,7 @@ export interface OAuth2Client { /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want -export const credentials = Object.assign( - { +export const credentials = mixin({ /** * Create a gRPC credential from a Google credential object. * @param googleCredentials The authentication client to use. @@ -67,8 +84,7 @@ export const credentials = Object.assign( CallCredentials => { return additional.reduce((acc, other) => acc.compose(other), first); } - }, - ChannelCredentials, CallCredentials); + }, ChannelCredentials, CallCredentials); /**** Metadata ****/ diff --git a/packages/grpc-js-core/tsconfig.json b/packages/grpc-js-core/tsconfig.json index c47ad1de0..807ef6626 100644 --- a/packages/grpc-js-core/tsconfig.json +++ b/packages/grpc-js-core/tsconfig.json @@ -2,7 +2,8 @@ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "target": "es6" }, "include": [ "src/*.ts", From acfcc9f981cef2da563e156c6d5f9ce034c5e74d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 30 May 2018 16:08:42 -0700 Subject: [PATCH 0278/1899] Format code --- packages/grpc-js-core/src/call-stream.ts | 23 ++-- packages/grpc-js-core/src/channel.ts | 2 +- .../grpc-js-core/src/compression-filter.ts | 113 +++++++++--------- packages/grpc-js-core/src/filter-stack.ts | 9 +- packages/grpc-js-core/src/index.ts | 10 +- packages/grpc-js-core/src/make-client.ts | 12 +- packages/grpc-js-core/src/metadata.ts | 4 +- .../grpc-js-core/test/test-call-stream.ts | 5 +- 8 files changed, 96 insertions(+), 82 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 10c47a6e5..9e362ffe1 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -143,7 +143,7 @@ export class Http2CallStream extends Duplex implements CallStream { } } - private filterReceivedMessage(framedMessage: Buffer | null) { + private filterReceivedMessage(framedMessage: Buffer|null) { if (framedMessage === null) { if (this.canPush) { this.push(null); @@ -153,12 +153,13 @@ export class Http2CallStream extends Duplex implements CallStream { return; } this.isReadFilterPending = true; - this.filterStack.receiveMessage(Promise.resolve(framedMessage)).then( - this.handleFilteredRead.bind(this), - this.handleFilterError.bind(this)); + this.filterStack.receiveMessage(Promise.resolve(framedMessage)) + .then( + this.handleFilteredRead.bind(this), + this.handleFilterError.bind(this)); } - private tryPush(messageBytes: Buffer | null): void { + private tryPush(messageBytes: Buffer|null): void { if (this.isReadFilterPending) { this.unfilteredReadMessages.push(messageBytes); } else { @@ -268,7 +269,7 @@ export class Http2CallStream extends Duplex implements CallStream { while (readHead < data.length) { switch (this.readState) { case ReadState.NO_DATA: - this.readCompressFlag = data.slice(readHead, readHead+1); + this.readCompressFlag = data.slice(readHead, readHead + 1); readHead += 1; this.readState = ReadState.READING_SIZE; this.readPartialSize.fill(0); @@ -291,7 +292,8 @@ export class Http2CallStream extends Duplex implements CallStream { if (this.readMessageRemaining > 0) { this.readState = ReadState.READING_MESSAGE; } else { - this.tryPush(Buffer.concat([this.readCompressFlag, this.readPartialSize])); + this.tryPush(Buffer.concat( + [this.readCompressFlag, this.readPartialSize])); this.readState = ReadState.NO_DATA; } } @@ -306,8 +308,11 @@ export class Http2CallStream extends Duplex implements CallStream { // readMessageRemaining >=0 here if (this.readMessageRemaining === 0) { // At this point, we have read a full message - const framedMessageBuffers = [this.readCompressFlag, this.readPartialSize].concat(this.readPartialMessage); - const framedMessage = Buffer.concat(framedMessageBuffers, this.readMessageSize + 5); + const framedMessageBuffers = [ + this.readCompressFlag, this.readPartialSize + ].concat(this.readPartialMessage); + const framedMessage = Buffer.concat( + framedMessageBuffers, this.readMessageSize + 5); this.tryPush(framedMessage); this.readState = ReadState.NO_DATA; } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index b1b1e91bf..4d013fffe 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -84,7 +84,7 @@ export interface Channel extends EventEmitter { /* This should be a real subchannel class that contains a ClientHttp2Session, * but for now this serves its purpose */ -type Http2SubChannel = http2.ClientHttp2Session & { +type Http2SubChannel = http2.ClientHttp2Session&{ /* Count the number of currently active streams associated with the session. * The purpose of this is to keep the session reffed if and only if there * is at least one active stream */ diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index df0e5c9fb..dd607baeb 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -1,9 +1,10 @@ -import {CallStream, WriteObject, WriteFlags} from './call-stream'; +import * as zlib from 'zlib'; + +import {CallStream, WriteFlags, WriteObject} from './call-stream'; import {Channel} from './channel'; +import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata, MetadataValue} from './metadata'; -import {Status} from './constants'; -import * as zlib from 'zlib'; abstract class CompressionHandler { protected abstract compressMessage(message: Buffer): Promise; @@ -38,7 +39,7 @@ abstract class CompressionHandler { } } -class IdentityHandler extends CompressionHandler{ +class IdentityHandler extends CompressionHandler { async compressMessage(message: Buffer) { return message; } @@ -53,61 +54,57 @@ class IdentityHandler extends CompressionHandler{ return output; } - decompressMessage(message: Buffer) : Promise { + decompressMessage(message: Buffer): Promise { return Promise.reject(new Error( - 'Received compressed message but "grpc-encoding" header was identity')); + 'Received compressed message but "grpc-encoding" header was identity')); } } class DeflateHandler extends CompressionHandler { compressMessage(message: Buffer) { - return new Promise((resolve, reject) => { - zlib.deflate(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - }) - }); + return new Promise( + (resolve, reject) => {zlib.deflate(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + })}); } decompressMessage(message: Buffer) { - return new Promise((resolve, reject) => { - zlib.inflate(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - }) - }); + return new Promise( + (resolve, reject) => {zlib.inflate(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + })}); } } class GzipHandler extends CompressionHandler { compressMessage(message: Buffer) { - return new Promise((resolve, reject) => { - zlib.gzip(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - }) - }); + return new Promise( + (resolve, reject) => {zlib.gzip(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + })}); } decompressMessage(message: Buffer) { - return new Promise((resolve, reject) => { - zlib.unzip(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - }) - }); + return new Promise( + (resolve, reject) => {zlib.unzip(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + })}); } } @@ -117,26 +114,27 @@ class UnknownHandler extends CompressionHandler { } compressMessage(message: Buffer): Promise { return Promise.reject(new Error( - `Received message compressed wth unsupported compression method ${this.compressionName}`)); + `Received message compressed wth unsupported compression method ${ + this.compressionName}`)); } decompressMessage(message: Buffer): Promise { // This should be unreachable - return Promise.reject(new Error( - `Compression method not supported: ${this.compressionName}`)); + return Promise.reject( + new Error(`Compression method not supported: ${this.compressionName}`)); } } function getCompressionHandler(compressionName: string): CompressionHandler { switch (compressionName) { - case 'identity': - return new IdentityHandler(); - case 'deflate': - return new DeflateHandler(); - case 'gzip': - return new GzipHandler(); - default: - return new UnknownHandler(compressionName); + case 'identity': + return new IdentityHandler(); + case 'deflate': + return new DeflateHandler(); + case 'gzip': + return new GzipHandler(); + default: + return new UnknownHandler(compressionName); } } @@ -165,15 +163,16 @@ export class CompressionFilter extends BaseFilter implements Filter { } async sendMessage(message: Promise): Promise { - /* This filter is special. The input message is the bare message bytes, * and the output is a framed and possibly compressed message. For this * reason, this filter should be at the bottom of the filter stack */ const resolvedMessage: WriteObject = await message; - const compress = resolvedMessage.flags === undefined ? false : - (resolvedMessage.flags & WriteFlags.NoCompress) === 0; + const compress = resolvedMessage.flags === undefined ? + false : + (resolvedMessage.flags & WriteFlags.NoCompress) === 0; return { - message: await this.sendCompression.writeMessage(resolvedMessage.message, compress), + message: await this.sendCompression.writeMessage( + resolvedMessage.message, compress), flags: resolvedMessage.flags }; } diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js-core/src/filter-stack.ts index 9cbfd398a..78e844865 100644 --- a/packages/grpc-js-core/src/filter-stack.ts +++ b/packages/grpc-js-core/src/filter-stack.ts @@ -19,14 +19,13 @@ export class FilterStack implements Filter { } sendMessage(message: Promise): Promise { - return flow(map( - this.filters, (filter) => filter.sendMessage.bind(filter)))(message); + return flow(map(this.filters, (filter) => filter.sendMessage.bind(filter)))( + message); } receiveMessage(message: Promise): Promise { - return flowRight( - map(this.filters, (filter) => filter.receiveMessage.bind(filter)))( - message); + return flowRight(map( + this.filters, (filter) => filter.receiveMessage.bind(filter)))(message); } receiveTrailers(status: Promise): Promise { diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index e8ec58340..69e2b0c01 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -15,8 +15,8 @@ interface IndexedObject { function mixin(...sources: IndexedObject[]) { const result: {[key: string]: Function} = {}; - for(const source of sources) { - for(const propName of Object.getOwnPropertyNames(source)) { + for (const source of sources) { + for (const propName of Object.getOwnPropertyNames(source)) { const property: any = source[propName]; if (typeof property === 'function') { result[propName] = property; @@ -35,7 +35,8 @@ export interface OAuth2Client { /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want -export const credentials = mixin({ +export const credentials = mixin( + { /** * Create a gRPC credential from a Google credential object. * @param googleCredentials The authentication client to use. @@ -84,7 +85,8 @@ export const credentials = mixin({ CallCredentials => { return additional.reduce((acc, other) => acc.compose(other), first); } - }, ChannelCredentials, CallCredentials); + }, + ChannelCredentials, CallCredentials); /**** Metadata ****/ diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index 7d82444f0..98f338a2b 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -6,9 +6,13 @@ import {ChannelCredentials} from './channel-credentials'; import {Client, UnaryCallback} from './client'; import {Metadata} from './metadata'; -export interface Serialize { (value: T): Buffer; } +export interface Serialize { + (value: T): Buffer; +} -export interface Deserialize { (bytes: Buffer): T; } +export interface Deserialize { + (bytes: Buffer): T; +} export interface MethodDefinition { path: string; @@ -25,7 +29,9 @@ export interface ServiceDefinition { [index: string]: MethodDefinition; } -export interface PackageDefinition { [index: string]: ServiceDefinition; } +export interface PackageDefinition { + [index: string]: ServiceDefinition; +} function getDefaultValues(metadata?: Metadata, options?: T): {metadata: Metadata; options: Partial;} { diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 3f4b19d02..40e6985bb 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -3,7 +3,9 @@ import {forOwn} from 'lodash'; export type MetadataValue = string|Buffer; -export interface MetadataObject { [key: string]: MetadataValue[]; } +export interface MetadataObject { + [key: string]: MetadataValue[]; +} function cloneMetadataObject(repr: MetadataObject): MetadataObject { const result: MetadataObject = {}; diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index decb0e7fb..b188dbf40 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -6,13 +6,13 @@ import * as stream from 'stream'; import {CallCredentials} from '../src/call-credentials'; import {Http2CallStream} from '../src/call-stream'; +import {Channel} from '../src/channel'; import {CompressionFilterFactory} from '../src/compression-filter'; import {Status} from '../src/constants'; import {FilterStackFactory} from '../src/filter-stack'; import {Metadata} from '../src/metadata'; import {assert2, mockFunction} from './common'; -import { Channel } from '../src/channel'; interface DataFrames { payload: Buffer; @@ -89,7 +89,8 @@ describe('CallStream', () => { * Currently the channel is unused, so we can replace it with an empty object, * but this might break if we start checking channel arguments, in which case * we will need a more sophisticated fake */ - const filterStackFactory = new FilterStackFactory([new CompressionFilterFactory({})]); + const filterStackFactory = + new FilterStackFactory([new CompressionFilterFactory({})]); const message = 'eat this message'; // 16 bytes beforeEach(() => { From 01e0d32722808cc4e4c0e0a823cfc748b0b285bc Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 5 Jun 2018 11:14:58 -0700 Subject: [PATCH 0279/1899] Fix generic client interceptor resolution --- packages/grpc-native-core/src/client.js | 50 ++++++------- .../src/client_interceptors.js | 75 +------------------ 2 files changed, 26 insertions(+), 99 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index e5ce8a3e1..83d7b750d 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -380,19 +380,18 @@ function Client(address, credentials, options) { options['grpc.primary_user_agent'] += 'grpc-node/' + version; // Resolve interceptor options and assign interceptors to each method - var interceptor_providers = options.interceptor_providers || []; - var interceptors = options.interceptors || []; - if (interceptor_providers.length && interceptors.length) { + if (_.isArray(options.interceptor_providers) && _.isArray(options.interceptors)) { throw new client_interceptors.InterceptorConfigurationError( 'Both interceptors and interceptor_providers were passed as options ' + 'to the client constructor. Only one of these is allowed.'); } + self.$interceptors = options.interceptors || []; + self.$interceptor_providers = options.interceptor_providers || []; _.each(self.$method_definitions, function(method_definition, method_name) { self[method_name].interceptors = client_interceptors - .resolveInterceptorProviders(interceptor_providers, method_definition) - .concat(interceptors); + .resolveInterceptorProviders(self.$interceptor_providers, method_definition) + .concat(self.$interceptors); }); - // Exclude interceptor options which have already been consumed var channel_options = _.omit(options, ['interceptors', 'interceptor_providers']); @@ -403,6 +402,21 @@ function Client(address, credentials, options) { exports.Client = Client; +Client.prototype.resolveCallInterceptors = function(method_definition, interceptors, interceptor_providers) { + if (_.isArray(interceptors) && _.isArray(interceptor_providers)) { + throw new client_interceptors.InterceptorConfigurationError( + 'Both interceptors and interceptor_providers were passed as call ' + + 'options. Only one of these is allowed.'); + } + if (_.isArray(interceptors) || _.isArray(interceptor_providers)) { + interceptors = interceptors || []; + interceptor_providers = interceptor_providers || []; + return client_interceptors.resolveInterceptorProviders(interceptor_providers, method_definition).concat(interceptors); + } else { + return client_interceptors.resolveInterceptorProviders(this.$interceptor_providers, method_definition).concat(this.$interceptors); + } +} + /** * @callback grpc.Client~requestCallback * @param {?grpc~ServiceError} error The error, if the call @@ -454,10 +468,6 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, throw new Error('Argument mismatch in makeUnaryRequest'); } - var method_name = this.$method_names[path]; - var constructor_interceptors = this[method_name] ? - this[method_name].interceptors : - null; var method_definition = options.method_definition = { path: path, requestStream: false, @@ -471,7 +481,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, var intercepting_call = client_interceptors.getInterceptingCall( method_definition, options, - constructor_interceptors, + Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), this.$channel, callback ); @@ -533,10 +543,6 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, throw new Error('Argument mismatch in makeClientStreamRequest'); } - var method_name = this.$method_names[path]; - var constructor_interceptors = this[method_name] ? - this[method_name].interceptors : - null; var method_definition = options.method_definition = { path: path, requestStream: true, @@ -550,7 +556,7 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, var intercepting_call = client_interceptors.getInterceptingCall( method_definition, options, - constructor_interceptors, + Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), this.$channel, callback ); @@ -595,10 +601,6 @@ Client.prototype.makeServerStreamRequest = function(path, serialize, throw new Error('Argument mismatch in makeServerStreamRequest'); } - var method_name = this.$method_names[path]; - var constructor_interceptors = this[method_name] ? - this[method_name].interceptors : - null; var method_definition = options.method_definition = { path: path, requestStream: false, @@ -613,7 +615,7 @@ Client.prototype.makeServerStreamRequest = function(path, serialize, var intercepting_call = client_interceptors.getInterceptingCall( method_definition, options, - constructor_interceptors, + Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), this.$channel, emitter ); @@ -655,10 +657,6 @@ Client.prototype.makeBidiStreamRequest = function(path, serialize, throw new Error('Argument mismatch in makeBidiStreamRequest'); } - var method_name = this.$method_names[path]; - var constructor_interceptors = this[method_name] ? - this[method_name].interceptors : - null; var method_definition = options.method_definition = { path: path, requestStream: true, @@ -673,7 +671,7 @@ Client.prototype.makeBidiStreamRequest = function(path, serialize, var intercepting_call = client_interceptors.getInterceptingCall( method_definition, options, - constructor_interceptors, + Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), this.$channel, emitter ); diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 4f45b7529..ddd147218 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -367,32 +367,6 @@ var resolveInterceptorProviders = function(providers, method_definition) { return interceptors; }; -/** - * Resolves interceptor options at call invocation time - * @param {grpc.Client~CallOptions} options The call options passed to a gRPC - * call. - * @param {Interceptor[]} [options.interceptors] - * @param {InterceptorProvider[]} [options.interceptor_providers] - * @param {grpc~MethodDefinition} method_definition - * @return {null|function[]} - */ -var resolveInterceptorOptions = function(options, method_definition) { - var provided = resolveInterceptorProviders(options.interceptor_providers, - method_definition); - if (_.isArray(options.interceptors) && _.isArray(provided)) { - throw new InterceptorConfigurationError( - 'Both interceptors and interceptor_providers were passed as options ' + - 'to the call invocation. Only one of these is allowed.'); - } - if (_.isArray(options.interceptors)) { - return options.interceptors; - } - if (_.isArray(provided)) { - return provided; - } - return null; -}; - /** * A chainable gRPC call proxy which will delegate to an optional requester * object. By default, interceptor methods will chain to next_call. If a @@ -1360,17 +1334,12 @@ function getLastListener(method_definition, emitter, callback) { * * @param {grpc~MethodDefinition} method_definition * @param {grpc.Client~CallOptions} options - * @param {Interceptor[]} constructor_interceptors + * @param {Interceptor[]} interceptors * @param {grpc.Channel} channel * @param {function|EventEmitter} responder */ function getInterceptingCall(method_definition, options, - constructor_interceptors, channel, responder) { - var interceptors = _processInterceptorLayers( - options, - constructor_interceptors, - method_definition - ); + interceptors, channel, responder) { var last_interceptor = _getLastInterceptor(method_definition, channel, responder); var all_interceptors = interceptors.concat(last_interceptor); @@ -1416,29 +1385,6 @@ function _buildChain(interceptors, options) { return new InterceptingCall(chain); } -/** - * Process call options and the interceptor override layers to get the final set - * of interceptors. - * @private - * @param {grpc.Client~CallOptions} call_options The options passed to the gRPC - * call. - * @param {Interceptor[]} constructor_interceptors Interceptors passed to the - * client constructor. - * @param {grpc~MethodDefinition} method_definition Details of the RPC method. - * @return {Interceptor[]|null} The final set of interceptors. - */ -function _processInterceptorLayers(call_options, - constructor_interceptors, - method_definition) { - var calltime_interceptors = resolveInterceptorOptions(call_options, - method_definition); - var interceptor_overrides = [ - calltime_interceptors, - constructor_interceptors - ]; - return _resolveInterceptorOverrides(interceptor_overrides); -} - /** * Wraps a plain listener object in an InterceptingListener if it isn't an * InterceptingListener already. @@ -1464,23 +1410,6 @@ function _isInterceptingListener(listener) { return listener && listener.constructor.name === 'InterceptingListener'; } -/** - * Chooses the first valid array of interceptors or returns null. - * @param {Interceptor[][]} interceptor_lists A list of interceptor lists in - * descending override priority order. - * @return {Interceptor[]|null} The resulting interceptors - * @private - */ -function _resolveInterceptorOverrides(interceptor_lists) { - for (var i = 0; i < interceptor_lists.length; i++) { - var interceptor_list = interceptor_lists[i]; - if (_.isArray(interceptor_list)) { - return interceptor_list; - } - } - return null; -} - exports.resolveInterceptorProviders = resolveInterceptorProviders; exports.InterceptingCall = InterceptingCall; From c4af9cd433fc047de4574bef2990801f7c8e149b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 5 Jun 2018 17:08:21 -0700 Subject: [PATCH 0280/1899] Update grpc submodule on master --- packages/grpc-native-core/binding.gyp | 9 +++++---- packages/grpc-native-core/deps/grpc | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 67f5a2c3b..a67fd7649 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -275,6 +275,7 @@ 'deps/grpc/third_party/boringssl/crypto/chacha/chacha.c', 'deps/grpc/third_party/boringssl/crypto/cipher_extra/cipher_extra.c', 'deps/grpc/third_party/boringssl/crypto/cipher_extra/derive_key.c', + 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesccm.c', 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesctrhmac.c', 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesgcmsiv.c', 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_chacha20poly1305.c', @@ -286,6 +287,7 @@ 'deps/grpc/third_party/boringssl/crypto/cipher_extra/tls_cbc.c', 'deps/grpc/third_party/boringssl/crypto/cmac/cmac.c', 'deps/grpc/third_party/boringssl/crypto/conf/conf.c', + 'deps/grpc/third_party/boringssl/crypto/cpu-aarch64-fuchsia.c', 'deps/grpc/third_party/boringssl/crypto/cpu-aarch64-linux.c', 'deps/grpc/third_party/boringssl/crypto/cpu-arm-linux.c', 'deps/grpc/third_party/boringssl/crypto/cpu-arm.c', @@ -293,7 +295,6 @@ 'deps/grpc/third_party/boringssl/crypto/cpu-ppc64le.c', 'deps/grpc/third_party/boringssl/crypto/crypto.c', 'deps/grpc/third_party/boringssl/crypto/curve25519/spake25519.c', - 'deps/grpc/third_party/boringssl/crypto/curve25519/x25519-x86_64.c', 'deps/grpc/third_party/boringssl/crypto/dh/check.c', 'deps/grpc/third_party/boringssl/crypto/dh/dh.c', 'deps/grpc/third_party/boringssl/crypto/dh/dh_asn1.c', @@ -449,6 +450,7 @@ 'deps/grpc/third_party/boringssl/ssl/d1_srtp.cc', 'deps/grpc/third_party/boringssl/ssl/dtls_method.cc', 'deps/grpc/third_party/boringssl/ssl/dtls_record.cc', + 'deps/grpc/third_party/boringssl/ssl/handoff.cc', 'deps/grpc/third_party/boringssl/ssl/handshake.cc', 'deps/grpc/third_party/boringssl/ssl/handshake_client.cc', 'deps/grpc/third_party/boringssl/ssl/handshake_server.cc', @@ -567,7 +569,6 @@ 'deps/grpc/src/core/lib/gpr/env_linux.cc', 'deps/grpc/src/core/lib/gpr/env_posix.cc', 'deps/grpc/src/core/lib/gpr/env_windows.cc', - 'deps/grpc/src/core/lib/gpr/fork.cc', 'deps/grpc/src/core/lib/gpr/host_port.cc', 'deps/grpc/src/core/lib/gpr/log.cc', 'deps/grpc/src/core/lib/gpr/log_android.cc', @@ -592,6 +593,7 @@ 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', + 'deps/grpc/src/core/lib/gprpp/fork.cc', 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', @@ -620,7 +622,7 @@ 'deps/grpc/src/core/lib/channel/channel_stack.cc', 'deps/grpc/src/core/lib/channel/channel_stack_builder.cc', 'deps/grpc/src/core/lib/channel/channel_trace.cc', - 'deps/grpc/src/core/lib/channel/channel_trace_registry.cc', + 'deps/grpc/src/core/lib/channel/channelz_registry.cc', 'deps/grpc/src/core/lib/channel/connected_channel.cc', 'deps/grpc/src/core/lib/channel/handshaker.cc', 'deps/grpc/src/core/lib/channel/handshaker_factory.cc', @@ -852,7 +854,6 @@ 'deps/grpc/third_party/nanopb/pb_decode.c', 'deps/grpc/third_party/nanopb/pb_encode.c', 'deps/grpc/src/core/tsi/transport_security.cc', - 'deps/grpc/src/core/tsi/transport_security_adapter.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/authority.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index aef957950..6a2aaf096 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit aef957950aa3390e3516531ca2d783de8fc9333b +Subproject commit 6a2aaf096fc8baf1f73d4d531518cdefd3374c76 From 717d9f79f7a7ca31435edfd24ca76196558edf07 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Jun 2018 14:53:20 -0700 Subject: [PATCH 0281/1899] Increase npm retries when downloading packages --- run-tests.bat | 2 ++ run-tests.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index 0f7662124..bf62e6bf5 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -31,6 +31,8 @@ call nvm version call nvm install 8 call nvm use 8 +SET npm_config_fetch_retries=5 + call npm install || goto :error SET JUNIT_REPORT_STACK=1 diff --git a/run-tests.sh b/run-tests.sh index 0e8afbe1d..a9bcab212 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -35,6 +35,8 @@ nvm install lts/* nvm use lts/* set -ex +npm_config_fetch_retries=5 + npm install --unsafe-perm mkdir -p reports From 2ac31223f70479d72e15c1f2cbcd7e2fc70b50ea Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 8 Jun 2018 13:51:58 -0700 Subject: [PATCH 0282/1899] Update version to 1.12.3 --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 3577ac832..addd757b2 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.12.2 + node_version: 1.12.3 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e203fb71e..d57db163c 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.12.2", + "version": "1.12.3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From efa3d430ddf3f5e3f8b47d6ece4b3ce058e88834 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 11 Jun 2018 15:05:47 -0700 Subject: [PATCH 0283/1899] Add deprecation notice to grpc.load --- packages/grpc-native-core/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 7f67422cd..c0d81055f 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -20,6 +20,7 @@ var path = require('path'); var fs = require('fs'); +var util = require('util'); var SSL_ROOTS_PATH = path.resolve(__dirname, 'deps', 'grpc', 'etc', 'roots.pem'); @@ -118,7 +119,7 @@ var loadObject = exports.loadObject; * API breakage. It is deprecated, and new code should not use it. * @return {Object} The resulting gRPC object */ -exports.load = function load(filename, format, options) { +exports.load = util.deprecate(function load(filename, format, options) { options = _.defaults(options, common.defaultGrpcOptions); options.protobufjsVersion = 5; if (!format) { @@ -149,7 +150,7 @@ exports.load = function load(filename, format, options) { } return loadObject(builder.ns, options); -}; +}, 'grpc.load: Use the @grpc/proto-loader module with grpc.loadPackageDefinition instead'); /** * Load a gRPC package definition as a gRPC object hierarchy From abb05f0c1277ed6fe21ceda4674a4c8d41e64d38 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 12 Jun 2018 10:45:48 -0700 Subject: [PATCH 0284/1899] Make Protobuf.js Message type non-generic --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index ad63b157a..7d8cfdc81 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -66,7 +66,7 @@ declare module "grpc" { * - Anything else becomes the relevant reflection object that ProtoBuf.js would create */ export interface GrpcObject { - [name: string]: GrpcObject | typeof Client | Message; + [name: string]: GrpcObject | typeof Client | Message; } /** From 7e11518ee6164028899bd906b54c7f7d36cb2cb1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Jun 2018 16:59:00 -0700 Subject: [PATCH 0285/1899] Update to v1.13.0-pre1 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 6a2aaf096..3137d59be 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 6a2aaf096fc8baf1f73d4d531518cdefd3374c76 +Subproject commit 3137d59be9e476157de78016ab3f23a7d340d78f diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index a77bf6c7c..0a13f36a2 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.13.0-dev", + "version": "1.13.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 6abb43aa44c806fe923a1f610cdb8387468d8db9 Mon Sep 17 00:00:00 2001 From: David Garcia Quintas Date: Wed, 13 Jun 2018 16:34:25 -0700 Subject: [PATCH 0286/1899] Changes needed for the nanopb dep refactoring work --- packages/grpc-native-core/binding.gyp | 5 +++-- packages/grpc-native-core/templates/binding.gyp.template | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index a67fd7649..bf88f9cf6 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -81,10 +81,11 @@ 'include_dirs': [ 'deps/grpc', 'deps/grpc/include', - 'deps/grpc/third_party/abseil-cpp' + 'deps/grpc/third_party/abseil-cpp', + 'deps/grpc/third_party/nanopb' ], 'defines': [ - 'PB_FIELD_16BIT', + 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV' diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 85ddbe655..2146f1666 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -75,10 +75,11 @@ 'include_dirs': [ 'deps/grpc', 'deps/grpc/include', - 'deps/grpc/third_party/abseil-cpp' + 'deps/grpc/third_party/abseil-cpp', + 'deps/grpc/third_party/nanopb' ], 'defines': [ - 'PB_FIELD_16BIT', + 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV' From 91e1837d16a054bac1ca1a03417c93bf216f8dcb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Jun 2018 14:58:04 -0700 Subject: [PATCH 0287/1899] Publish .d.ts files in grpc-js. Also bump the version --- packages/grpc-js-core/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 62d2bc64c..1ea98edfc 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.1.0", + "version": "0.2.0", "description": "gRPC Library for Node - pure JS core", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", @@ -45,6 +45,6 @@ "lodash": "^4.17.4" }, "files": [ - "build/src/*.js" + "build/src/*.{js,d.ts}" ] } From 9fed412727858b81d8dfe11176dc64e9e7f84690 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Jun 2018 12:43:09 -0700 Subject: [PATCH 0288/1899] Update usage of modifed core credentials API --- packages/grpc-native-core/binding.gyp | 10 +++++++++- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/ext/channel_credentials.cc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index bf88f9cf6..e0b893aa8 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -65,6 +65,8 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-Wno-deprecated-declarations', + '-Ithird_party/nanopb', + '-DPB_FIELD_32BIT', '-fvisibility=hidden', ], 'ldflags': [ @@ -191,6 +193,8 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-Wno-deprecated-declarations', + '-Ithird_party/nanopb', + '-DPB_FIELD_32BIT', '-fvisibility=hidden', ], 'OTHER_CPLUSPLUSFLAGS': [ @@ -202,6 +206,8 @@ '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', '-Wno-deprecated-declarations', + '-Ithird_party/nanopb', + '-DPB_FIELD_32BIT', '-fvisibility=hidden', '-stdlib=libc++', '-std=c++11', @@ -623,6 +629,7 @@ 'deps/grpc/src/core/lib/channel/channel_stack.cc', 'deps/grpc/src/core/lib/channel/channel_stack_builder.cc', 'deps/grpc/src/core/lib/channel/channel_trace.cc', + 'deps/grpc/src/core/lib/channel/channelz.cc', 'deps/grpc/src/core/lib/channel/channelz_registry.cc', 'deps/grpc/src/core/lib/channel/connected_channel.cc', 'deps/grpc/src/core/lib/channel/handshaker.cc', @@ -904,6 +911,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', @@ -911,7 +919,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc', 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc', - 'deps/grpc/src/core/ext/census/grpc_context.cc', + 'deps/grpc/src/cpp/ext/filters/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 6a2aaf096..05628719f 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 6a2aaf096fc8baf1f73d4d531518cdefd3374c76 +Subproject commit 05628719f1c8d21969ddb700df05b4c63982b66a diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index da67f35ad..c334d5d03 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -150,7 +150,7 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { } grpc_channel_credentials *creds = grpc_ssl_credentials_create( root_certs.get(), private_key.isAssigned() ? &key_cert_pair : NULL, - NULL); + NULL, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index a77bf6c7c..52f8eac12 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.13.0-dev", + "version": "1.14.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 6e74e6fb0c96467f4124005564e310a7156ce894 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 22 Jun 2018 12:59:10 -0700 Subject: [PATCH 0289/1899] Adding Electron instructions. --- packages/grpc-native-core/README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index 200b2fca3..aa4ac2ecc 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -14,6 +14,26 @@ Install the gRPC NPM package npm install grpc ``` +## ABOUT ELECTRON + +The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC, and use the following instructions instead. + +The best to get gRPC to work with electron is to do this, possibly in your postinstall script in your `package.json` file: + +``` +npm rebuild --target=2.0.0 --runtime=electron --dist-url=https://atom.io/download/electron +``` + +Note that the `2.0.0` above is the electron runtime version number. You will need to update this every time you go on a different version of the runtime. + +If you have more native dependencies than gRPC, and they work better when built from source, you can explicitely specify which extension to build the following way: + +``` +npm rebuild --build-from-source=sqlite3 --target=2.0.0 --runtime=electron --dist-url=https://atom.io/download/electron +``` + +This way, if you depend on both `grpc` and `sqlite3`, only the `sqlite3` package will be rebuilt from source, leaving the `grpc` package to use its precompiled binaries. + ## BUILD FROM SOURCE 1. Clone [the grpc Git Repository](https://github.com/grpc/grpc). 2. Run `npm install --build-from-source` from the repository root. From 50d4a9f2985243c7033393bcc47323270e722769 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 22 Jun 2018 13:00:58 -0700 Subject: [PATCH 0290/1899] Typos. --- packages/grpc-native-core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index aa4ac2ecc..2b9139cab 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -18,7 +18,7 @@ npm install grpc The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC, and use the following instructions instead. -The best to get gRPC to work with electron is to do this, possibly in your postinstall script in your `package.json` file: +The best to get gRPC to work with electron is to do this, possibly in your `postinstall` script of your `package.json` file: ``` npm rebuild --target=2.0.0 --runtime=electron --dist-url=https://atom.io/download/electron From ae0fe677e0bda6d0145afc5c54de83f505aec596 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 22 Jun 2018 13:07:13 -0700 Subject: [PATCH 0291/1899] Delete protobufjs_redos.md --- .github/ISSUE_TEMPLATE/protobufjs_redos.md | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/protobufjs_redos.md diff --git a/.github/ISSUE_TEMPLATE/protobufjs_redos.md b/.github/ISSUE_TEMPLATE/protobufjs_redos.md deleted file mode 100644 index 149d56d94..000000000 --- a/.github/ISSUE_TEMPLATE/protobufjs_redos.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: ReDoS vulnerability -about: npm audit reports that protobufjs has a ReDoS vulnerability. - ---- -As I [ran `npm install`]/[ran 'npm audit']/[got a report from Snyk], -the tool told me that protobufjs has 1 moderate vulnerability exported -through the `grpc` package, as described here: https://nodesecurity.io/advisories/605 - -The gRPC team is aware of this, and this issue is a duplicate of #277. -Upgrading this depdendency would be a breaking change, and the fix has been backported -to protobufjs 5.0.3 already; the [nodesecurity.io]/[Snyk] database is simply outdated. From 98c4710f114ce9950152a7548ac33946f0c12fa0 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 22 Jun 2018 13:29:40 -0700 Subject: [PATCH 0292/1899] Adding a line about silver bullets. --- packages/grpc-native-core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index 2b9139cab..be9d27785 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -16,7 +16,7 @@ npm install grpc ## ABOUT ELECTRON -The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC, and use the following instructions instead. +The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC. Please note that there's not just one way to get native extensions running in electron, and that there's never any silver bullet for anything. The following instructions try to cater about some of the most generic ways, but different edge cases might require different methodologies. The best to get gRPC to work with electron is to do this, possibly in your `postinstall` script of your `package.json` file: From b6be0d955fa71d889358ccc6175a6ed583ce3ba0 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 26 Jun 2018 01:21:35 +0200 Subject: [PATCH 0293/1899] Actually publish for arm32... --- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 34d9ffacb..eee6ff8fd 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -33,6 +33,7 @@ do # Cross compile for ARM on x64 # Requires debian or ubuntu packages "g++-aarch64-linux-gnu" and "g++-arm-linux-gnueabihf". CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ LD=arm-linux-gnueabihf-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm + cp -r build/stage/* "${ARTIFACTS_OUT}"/ CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ LD=aarch64-linux-gnu-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm64 cp -r build/stage/* "${ARTIFACTS_OUT}"/ done From 7d8865003ce428afe163a691d91a11dd2ccb9d9f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 2 Jul 2018 11:21:33 -0700 Subject: [PATCH 0294/1899] Update to v1.13.0 --- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 3137d59be..5d57a8d09 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 3137d59be9e476157de78016ab3f23a7d340d78f +Subproject commit 5d57a8d09a7f7202ba8eaa56b3b88a5da05ad057 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 0a13f36a2..92f2d7911 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.13.0-pre1", + "version": "1.13.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 9a5da0849779ad66a147aa173cd7fa99d54dc231 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 9 Jul 2018 19:09:44 +0200 Subject: [PATCH 0295/1899] Properly create slices from utf8 strings. Fixes #426. --- packages/grpc-native-core/ext/slice.cc | 2 +- .../grpc-native-core/test/surface_test.js | 32 ++++++++++++++++--- .../grpc-native-core/test/test_service.proto | 1 + test/interop/interop_client.js | 6 ++-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/ext/slice.cc b/packages/grpc-native-core/ext/slice.cc index 8806a61a9..49bc05b01 100644 --- a/packages/grpc-native-core/ext/slice.cc +++ b/packages/grpc-native-core/ext/slice.cc @@ -51,7 +51,7 @@ void buffer_destroy_func(void *user_data) { grpc_slice CreateSliceFromString(const Local source) { Nan::HandleScope scope; Nan::Utf8String *utf8_value = new Nan::Utf8String(source); - return grpc_slice_new_with_user_data(**utf8_value, source->Length(), + return grpc_slice_new_with_user_data(**utf8_value, utf8_value->length(), string_destroy_func, utf8_value); } diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 361797382..aa1246200 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -839,8 +839,12 @@ describe('Other conditions', function() { unary: function(call, cb) { var req = call.request; if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } cb({code: grpc.status.UNKNOWN, - details: 'Requested error'}, null, trailer_metadata); + details: message}, null, trailer_metadata); } else { cb(null, {count: 1}, trailer_metadata); } @@ -850,8 +854,12 @@ describe('Other conditions', function() { var errored; stream.on('data', function(data) { if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } errored = true; - cb(new Error('Requested error'), null, trailer_metadata); + cb(new Error(message), null, trailer_metadata); } else { count += 1; } @@ -865,8 +873,12 @@ describe('Other conditions', function() { serverStream: function(stream) { var req = stream.request; if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } var err = {code: grpc.status.UNKNOWN, - details: 'Requested error'}; + details: message}; err.metadata = trailer_metadata; stream.emit('error', err); } else { @@ -880,7 +892,11 @@ describe('Other conditions', function() { var count = 0; stream.on('data', function(data) { if (data.error) { - var err = new Error('Requested error'); + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + var err = new Error(message); err.metadata = trailer_metadata.clone(); err.metadata.add('count', '' + count); stream.emit('error', err); @@ -1127,6 +1143,14 @@ describe('Other conditions', function() { done(); }); }); + it('for a UTF-8 error message', function(done) { + client.unary({error: true, message: '測試字符串'}, function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + done(); + }); + }); }); describe('call.getPeer should return the peer', function() { it('for a unary call', function(done) { diff --git a/packages/grpc-native-core/test/test_service.proto b/packages/grpc-native-core/test/test_service.proto index b16dfecca..a0e49842b 100644 --- a/packages/grpc-native-core/test/test_service.proto +++ b/packages/grpc-native-core/test/test_service.proto @@ -16,6 +16,7 @@ syntax = "proto3"; message Request { bool error = 1; + string message = 2; } message Response { diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 195ef8d47..6bf68901e 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -347,13 +347,13 @@ function statusCodeAndMessage(client, done) { var arg = { response_status: { code: 2, - message: 'test status message' + message: 'test status message - 測試字符串' } }; client.unaryCall(arg, function(err, resp) { assert(err); assert.strictEqual(err.code, 2); - assert.strictEqual(err.details, 'test status message'); + assert.strictEqual(err.details, 'test status message - 測試字符串'); done(); }); var duplex = client.fullDuplexCall(); @@ -361,7 +361,7 @@ function statusCodeAndMessage(client, done) { duplex.on('status', function(status) { assert(status); assert.strictEqual(status.code, 2); - assert.strictEqual(status.details, 'test status message'); + assert.strictEqual(status.details, 'test status message - 測試字符串'); done(); }); duplex.on('error', function(){}); From 9da1bb14c4c58cb34fd855ff0e9b591dbdbecae3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 9 Jul 2018 14:38:43 -0700 Subject: [PATCH 0296/1899] proto loader: make options properly optional. +minor documentation fix --- packages/grpc-protobufjs/README.md | 4 ++-- packages/grpc-protobufjs/package.json | 2 +- packages/grpc-protobufjs/src/index.ts | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md index 307c635c1..651da848f 100644 --- a/packages/grpc-protobufjs/README.md +++ b/packages/grpc-protobufjs/README.md @@ -17,11 +17,11 @@ const grpcLibrary = require('grpc'); const grpcLibrary = require('@grpc/grpc-js'); protoLoader.load(protoFileName, options).then(packageDefinition => { - const package = grpcLibrary.loadPackageDefinition(packageDefinition); + const packageObject = grpcLibrary.loadPackageDefinition(packageDefinition); }); // OR const packageDefinition = protoLoader.loadSync(protoFileName, options); -const package = grpcLibrary.loadPackageDefinition(packageDefinition); +const packageObject = grpcLibrary.loadPackageDefinition(packageDefinition); ``` The options parameter is an object that can have the following optional properties: diff --git a/packages/grpc-protobufjs/package.json b/packages/grpc-protobufjs/package.json index 8890edb81..ebe82a43b 100644 --- a/packages/grpc-protobufjs/package.json +++ b/packages/grpc-protobufjs/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.2.0", + "version": "0.3.0", "author": "Google Inc.", "contributors": [ { diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index 5f443f983..bb7577627 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -156,8 +156,9 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * name * @param options.includeDirs Paths to search for imported `.proto` files. */ -export function load(filename: string, options: Options): Promise { +export function load(filename: string, options?: Options): Promise { const root: Protobuf.Root = new Protobuf.Root(); + options = options || {}; if (!!options.includeDirs) { if (!(options.includeDirs instanceof Array)) { return Promise.reject(new Error('The includeDirs option must be an array')); @@ -166,12 +167,13 @@ export function load(filename: string, options: Options): Promise { loadedRoot.resolveAll(); - return createPackageDefinition(root, options); + return createPackageDefinition(root, options!); }); } -export function loadSync(filename: string, options: Options): PackageDefinition { +export function loadSync(filename: string, options?: Options): PackageDefinition { const root: Protobuf.Root = new Protobuf.Root(); + options = options || {}; if (!!options.includeDirs) { if (!(options.includeDirs instanceof Array)) { throw new Error('The include option must be an array'); @@ -180,5 +182,5 @@ export function loadSync(filename: string, options: Options): PackageDefinition } const loadedRoot = root.loadSync(filename, options); loadedRoot.resolveAll(); - return createPackageDefinition(root, options); + return createPackageDefinition(root, options!); } From 339f4c04332d121e5c4df1c66b18cabb15aba487 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 9 Jul 2018 19:09:44 +0200 Subject: [PATCH 0297/1899] Properly create slices from utf8 strings. Fixes #426. --- packages/grpc-native-core/ext/slice.cc | 2 +- .../grpc-native-core/test/surface_test.js | 32 ++++++++++++++++--- .../grpc-native-core/test/test_service.proto | 1 + test/interop/interop_client.js | 6 ++-- 4 files changed, 33 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/ext/slice.cc b/packages/grpc-native-core/ext/slice.cc index 8806a61a9..49bc05b01 100644 --- a/packages/grpc-native-core/ext/slice.cc +++ b/packages/grpc-native-core/ext/slice.cc @@ -51,7 +51,7 @@ void buffer_destroy_func(void *user_data) { grpc_slice CreateSliceFromString(const Local source) { Nan::HandleScope scope; Nan::Utf8String *utf8_value = new Nan::Utf8String(source); - return grpc_slice_new_with_user_data(**utf8_value, source->Length(), + return grpc_slice_new_with_user_data(**utf8_value, utf8_value->length(), string_destroy_func, utf8_value); } diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 361797382..aa1246200 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -839,8 +839,12 @@ describe('Other conditions', function() { unary: function(call, cb) { var req = call.request; if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } cb({code: grpc.status.UNKNOWN, - details: 'Requested error'}, null, trailer_metadata); + details: message}, null, trailer_metadata); } else { cb(null, {count: 1}, trailer_metadata); } @@ -850,8 +854,12 @@ describe('Other conditions', function() { var errored; stream.on('data', function(data) { if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } errored = true; - cb(new Error('Requested error'), null, trailer_metadata); + cb(new Error(message), null, trailer_metadata); } else { count += 1; } @@ -865,8 +873,12 @@ describe('Other conditions', function() { serverStream: function(stream) { var req = stream.request; if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } var err = {code: grpc.status.UNKNOWN, - details: 'Requested error'}; + details: message}; err.metadata = trailer_metadata; stream.emit('error', err); } else { @@ -880,7 +892,11 @@ describe('Other conditions', function() { var count = 0; stream.on('data', function(data) { if (data.error) { - var err = new Error('Requested error'); + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + var err = new Error(message); err.metadata = trailer_metadata.clone(); err.metadata.add('count', '' + count); stream.emit('error', err); @@ -1127,6 +1143,14 @@ describe('Other conditions', function() { done(); }); }); + it('for a UTF-8 error message', function(done) { + client.unary({error: true, message: '測試字符串'}, function(err, data) { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + done(); + }); + }); }); describe('call.getPeer should return the peer', function() { it('for a unary call', function(done) { diff --git a/packages/grpc-native-core/test/test_service.proto b/packages/grpc-native-core/test/test_service.proto index b16dfecca..a0e49842b 100644 --- a/packages/grpc-native-core/test/test_service.proto +++ b/packages/grpc-native-core/test/test_service.proto @@ -16,6 +16,7 @@ syntax = "proto3"; message Request { bool error = 1; + string message = 2; } message Response { diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 195ef8d47..6bf68901e 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -347,13 +347,13 @@ function statusCodeAndMessage(client, done) { var arg = { response_status: { code: 2, - message: 'test status message' + message: 'test status message - 測試字符串' } }; client.unaryCall(arg, function(err, resp) { assert(err); assert.strictEqual(err.code, 2); - assert.strictEqual(err.details, 'test status message'); + assert.strictEqual(err.details, 'test status message - 測試字符串'); done(); }); var duplex = client.fullDuplexCall(); @@ -361,7 +361,7 @@ function statusCodeAndMessage(client, done) { duplex.on('status', function(status) { assert(status); assert.strictEqual(status.code, 2); - assert.strictEqual(status.details, 'test status message'); + assert.strictEqual(status.details, 'test status message - 測試字符串'); done(); }); duplex.on('error', function(){}); From d7da553a0328adab063ec3b576a66087ec14a3f3 Mon Sep 17 00:00:00 2001 From: Thomas Ladd Date: Fri, 13 Jul 2018 09:54:31 -0500 Subject: [PATCH 0298/1899] grpc-native-core: Update CallOptions type to allow custom options (#433) Allow custom options as a means of passing data per call to client interceptors --- packages/grpc-native-core/index.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 7d8cfdc81..3a59980be 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1116,6 +1116,11 @@ declare module "grpc" { * The credentials that should be used to make this particular call. */ credentials: CallCredentials; + /** + * Additional custom call options. These can be used to pass additional + * data per-call to client interceptors + */ + [key: string]: any; } /** From 2015e3d32c2b01aabbff537ce16ba03d18597c5a Mon Sep 17 00:00:00 2001 From: Tomas Alabes Date: Wed, 18 Jul 2018 15:49:06 -0700 Subject: [PATCH 0299/1899] Updated doc in readme.md Explaining the option to change the location of the precompiled-binaries. Related to #441 and #117. --- packages/grpc-native-core/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index be9d27785..9b605e250 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -51,6 +51,14 @@ This way, if you depend on both `grpc` and `sqlite3`, only the `sqlite3` package To fix this, you will have to delete the folder `C:\Users\\.node-gyp\\include\node\openssl` and retry `npm install` +## CONFIGURE BINARIES' LOCATION + +You can configure the location from which the pre-compiled binaries are downloaded during installation. + +`npm install --grpc_node_binary_host_mirror=https://your-url.com` + +Or defining `grpc_node_binary_host_mirror` in your `.npmrc`. + ## API DOCUMENTATION See the [API Documentation](https://grpc.io/grpc/node/). From 4e551aea7b54a2443b3f2e7e6f9144645ebb3459 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Mon, 12 Mar 2018 22:11:33 -0700 Subject: [PATCH 0300/1899] Add checkServerIdentity callback. --- .../ext/channel_credentials.cc | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index c334d5d03..d56780cf8 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -38,6 +38,8 @@ using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; +using v8::Array; +using v8::Context; using v8::Exception; using v8::External; using v8::Function; @@ -58,6 +60,43 @@ ChannelCredentials::~ChannelCredentials() { grpc_channel_credentials_release(wrapped_credentials); } +struct callback_md { + Nan::Callback *callback; +}; + +static int verify_peer_callback_wrapper(const char* servername, const char* cert, void* userdata) { + Nan::HandleScope scope; + Nan::TryCatch try_catch; + struct callback_md* md = (struct callback_md*)userdata; + + const unsigned argc = 2; + Local argv[argc]; + if (servername == NULL) { + argv[0] = Nan::Null(); + } else { + argv[0] = Nan::New(servername).ToLocalChecked(); + } + if (cert == NULL) { + argv[1] = Nan::Null(); + } else { + argv[1] = Nan::New(cert).ToLocalChecked(); + } + + md->callback->Call(argc, argv); + + if (try_catch.HasCaught()) { + return 1; + } + + return 0; +} + +static void verify_peer_callback_destruct(void *userdata) { + callback_md *md = (callback_md*)userdata; + delete md->callback; + delete md; +} + void ChannelCredentials::Init(Local exports) { HandleScope scope; Local tpl = Nan::New(New); @@ -148,9 +187,42 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { "createSsl's second and third arguments must be" " provided or omitted together"); } + + verify_peer_options verify_options = {NULL, NULL, NULL}; + if (info.Length() >= 4 && info[3]->IsObject()) { + Local context = Nan::New(); + Local object = info[3]->ToObject(); + MaybeLocal maybe_props = object->GetOwnPropertyNames(context); + if (!maybe_props.IsEmpty()) { + Local props = maybe_props.ToLocalChecked(); + for(uint32_t i=0; i < props->Length(); i++) { + Local key = props->Get(i); + Local value = object->Get(key); + + if (key->IsString()) { + Nan::Utf8String keyStr(key->ToString()); + + if (strcmp("checkServerIdentity", (const char*)(*keyStr)) == 0) { + + if (!value->IsFunction()) { + return Nan::ThrowError("Value of checkServerIdentity must be a function."); + } + struct callback_md *md = new struct callback_md; + md->callback = new Callback(Local::Cast(value)); + verify_options.verify_peer_callback = verify_peer_callback_wrapper; + verify_options.verify_peer_callback_userdata = (void*)md; + verify_options.verify_peer_destruct = verify_peer_callback_destruct; + + } + } + // do stuff with key / value + } + } + } + grpc_channel_credentials *creds = grpc_ssl_credentials_create( root_certs.get(), private_key.isAssigned() ? &key_cert_pair : NULL, - NULL, NULL); + &verify_options, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { From 637f961706a806335b7ca020e9ba05bad95f6b4e Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 14:59:26 -0700 Subject: [PATCH 0301/1899] Regenerate project files and add test covering checkServerIdentity callback. --- .../grpc-native-core/test/credentials_test.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index 58dddb508..b3f922fa9 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -260,6 +260,36 @@ describe('client credentials', function() { done(); }); }); + it('Verify callback receives correct arguments', function(done) { + var callback_host, callback_cert; + var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": function(host, cert) { + callback_host = host; + callback_cert = cert; + } + }); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ifError(err); + assert.equal(callback_host, 'foo.test.google.fr'); + assert.equal(callback_cert, pem_data); + done(); + }); + }); + it('Verify callback exception causes connection failure', function(done) { + var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": function(host, cert) { + throw "Verification callback exception"; + } + }); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ok(err, "Should have raised an error"); + done(); + }); + }); it('Should update metadata with SSL creds', function(done) { var metadataUpdater = function(service_url, callback) { var metadata = new grpc.Metadata(); From 15c82e08c8c6bdba5cf7c916e7dc23a6c9fb63c1 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 15:01:57 -0700 Subject: [PATCH 0302/1899] Add type assertion on createSsl's fourth argument. --- packages/grpc-native-core/ext/channel_credentials.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index d56780cf8..64e3df469 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -189,7 +189,11 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { } verify_peer_options verify_options = {NULL, NULL, NULL}; - if (info.Length() >= 4 && info[3]->IsObject()) { + if (!info[3]->IsUndefined()) { + if (!info[3]->IsObject()) { + return Nan::ThrowTypeError("createSsl's fourth argument must be an " + "object"); + } Local context = Nan::New(); Local object = info[3]->ToObject(); MaybeLocal maybe_props = object->GetOwnPropertyNames(context); From e0df40215177940c63f5acc5c55f6b0cbdf93d7a Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 15:11:11 -0700 Subject: [PATCH 0303/1899] Simplify userdata being passed to checkServerIdentity callback. --- .../ext/channel_credentials.cc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 64e3df469..5aaa19b85 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -60,14 +60,10 @@ ChannelCredentials::~ChannelCredentials() { grpc_channel_credentials_release(wrapped_credentials); } -struct callback_md { - Nan::Callback *callback; -}; - static int verify_peer_callback_wrapper(const char* servername, const char* cert, void* userdata) { Nan::HandleScope scope; Nan::TryCatch try_catch; - struct callback_md* md = (struct callback_md*)userdata; + Nan::Callback *callback = (Nan::Callback*)userdata; const unsigned argc = 2; Local argv[argc]; @@ -82,7 +78,7 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert argv[1] = Nan::New(cert).ToLocalChecked(); } - md->callback->Call(argc, argv); + callback->Call(argc, argv); if (try_catch.HasCaught()) { return 1; @@ -92,9 +88,8 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert } static void verify_peer_callback_destruct(void *userdata) { - callback_md *md = (callback_md*)userdata; - delete md->callback; - delete md; + Nan::Callback *callback = (Nan::Callback*)userdata; + delete callback; } void ChannelCredentials::Init(Local exports) { @@ -211,10 +206,9 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { if (!value->IsFunction()) { return Nan::ThrowError("Value of checkServerIdentity must be a function."); } - struct callback_md *md = new struct callback_md; - md->callback = new Callback(Local::Cast(value)); + Nan::Callback *callback = new Callback(Local::Cast(value)); verify_options.verify_peer_callback = verify_peer_callback_wrapper; - verify_options.verify_peer_callback_userdata = (void*)md; + verify_options.verify_peer_callback_userdata = (void*)callback; verify_options.verify_peer_destruct = verify_peer_callback_destruct; } From 0c49a57ff7f61746f0c8fa85bba4f6b30ef18b96 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 16:13:08 -0700 Subject: [PATCH 0304/1899] Simplify getting checkServerIdentity out of the fourth createSsl argument. Add some tests asserting type-checking behavior. --- .../ext/channel_credentials.cc | 36 ++++++------------- .../grpc-native-core/test/credentials_test.js | 19 ++++++++++ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 5aaa19b85..434b6e9be 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -186,35 +186,21 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { verify_peer_options verify_options = {NULL, NULL, NULL}; if (!info[3]->IsUndefined()) { if (!info[3]->IsObject()) { - return Nan::ThrowTypeError("createSsl's fourth argument must be an " - "object"); + return Nan::ThrowTypeError("createSsl's fourth argument must be an object"); } - Local context = Nan::New(); Local object = info[3]->ToObject(); - MaybeLocal maybe_props = object->GetOwnPropertyNames(context); - if (!maybe_props.IsEmpty()) { - Local props = maybe_props.ToLocalChecked(); - for(uint32_t i=0; i < props->Length(); i++) { - Local key = props->Get(i); - Local value = object->Get(key); - if (key->IsString()) { - Nan::Utf8String keyStr(key->ToString()); - - if (strcmp("checkServerIdentity", (const char*)(*keyStr)) == 0) { - - if (!value->IsFunction()) { - return Nan::ThrowError("Value of checkServerIdentity must be a function."); - } - Nan::Callback *callback = new Callback(Local::Cast(value)); - verify_options.verify_peer_callback = verify_peer_callback_wrapper; - verify_options.verify_peer_callback_userdata = (void*)callback; - verify_options.verify_peer_destruct = verify_peer_callback_destruct; - - } - } - // do stuff with key / value + Local checkServerIdentityValue = Nan::Get(object, + Nan::New("checkServerIdentity").ToLocalChecked()).ToLocalChecked(); + if (!checkServerIdentityValue->IsUndefined()) { + if (!checkServerIdentityValue->IsFunction()) { + return Nan::ThrowTypeError("Value of checkServerIdentity must be a function."); } + Nan::Callback *callback = new Callback(Local::Cast( + checkServerIdentityValue)); + verify_options.verify_peer_callback = verify_peer_callback_wrapper; + verify_options.verify_peer_callback_userdata = (void*)callback; + verify_options.verify_peer_destruct = verify_peer_callback_destruct; } } diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index b3f922fa9..542f93f36 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -128,6 +128,25 @@ describe('channel credentials', function() { grpc.credentials.createSsl(null, null, pem_data); }); }); + it('works if the fourth argument is an empty object', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data, null, null, {}); + }); + assert.notEqual(creds, null); + }); + it('fails if the fourth argument is a non-object value', function() { + assert.throws(function() { + grpc.credentials.createSsl(ca_data, null, null, 'test'); + }, TypeError); + }); + it('fails if the checkServerIdentity is a non-function', function() { + assert.throws(function() { + grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": 'test' + }); + }, TypeError); + }); }); }); From e54b50c77bbe774d5fef9cd1a869c93a82b9fd82 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 18:14:38 -0700 Subject: [PATCH 0305/1899] Update credentials.js documentation for verify options and add verify options to typescript definition. --- packages/grpc-native-core/index.d.ts | 22 +++++++++++++++++++- packages/grpc-native-core/src/credentials.js | 15 ++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 3a59980be..eb798a4ee 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -794,6 +794,25 @@ declare module "grpc" { ERROR, } + /** + * A callback that will receive the expected hostname and presented peer + * certificate as parameters. The callback should throw an error to + * indicate that the presented certificate is considered invalid. + */ + export type CheckServerIdentityCallback = (hostname: string, cert: string) => void; + + /** + * Additional peer verification options that can be set when creating + * SSL credentials. + */ + export interface VerifyOptions: { + /** + * If set, this callback will be invoked after the usual hostname verification + * has been performed on the peer certificate. + */ + checkServerIdentity?: CheckServerIdentityCallback; + } + /** * Credentials module * @@ -828,9 +847,10 @@ declare module "grpc" { * @param rootCerts The root certificate data * @param privateKey The client certificate private key, if applicable * @param certChain The client certificate cert chain, if applicable + * @param verifyOptions Additional peer verification options, if desired * @return The SSL Credentials object */ - createSsl(rootCerts?: Buffer, privateKey?: Buffer, certChain?: Buffer): ChannelCredentials; + createSsl(rootCerts?: Buffer, privateKey?: Buffer, certChain?: Buffer, verifyOptions?: VerifyOptions): ChannelCredentials; /** * Create a gRPC credentials object from a metadata generation function. This diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index a23129668..1c461d369 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -78,7 +78,8 @@ var _ = require('lodash'); /** * Create an SSL Credentials object. If using a client-side certificate, both - * the second and third arguments must be passed. + * the second and third arguments must be passed. Additional peer verification + * options can be passed in the fourth argument as described below. * @memberof grpc.credentials * @alias grpc.credentials.createSsl * @kind function @@ -86,6 +87,18 @@ var _ = require('lodash'); * @param {Buffer=} private_key The client certificate private key, if * applicable * @param {Buffer=} cert_chain The client certificate cert chain, if applicable + * @param {Object} verify_options Additional peer verification options. Can + * be undefined, in which case default behavior is preserved. + * Supported options are: "checkServerIdentity": (servername, cert) => {} + * The callback passed to checkServerIdentity will be invoked when the + * channel is opened in order to provide an opportunity to perform + * additional verification of the peer certificate as passed to the + * callback in the second parameter. The expected hostname is passed as + * the first parameter. If the callback considers the peer certificate + * invalid it should throw an error which will cause the handshake to + * be terminated. Note that supplying this callback does not disable + * the usual hostname verification which will also be performed on the + * certificate before this callback is invoked. * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object */ exports.createSsl = ChannelCredentials.createSsl; From ac0718883a8aca63f9be3489a6254dae8ba1f182 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 21 Jun 2018 14:59:32 -0700 Subject: [PATCH 0306/1899] Correct checkServerIdentity behavior to return a verification failure if an error is returned. Clean up documentation and add a test assertion on returned Error. --- .../grpc-native-core/ext/channel_credentials.cc | 8 +++++++- packages/grpc-native-core/index.d.ts | 7 ++++--- packages/grpc-native-core/src/credentials.js | 16 ++++------------ .../grpc-native-core/test/credentials_test.js | 13 +++++++++++++ 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 434b6e9be..6a2a1ddec 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -78,9 +78,15 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert argv[1] = Nan::New(cert).ToLocalChecked(); } - callback->Call(argc, argv); + Local result = callback->Call(argc, argv); + // Catch any exception and return with a distinct status code which indicates this if (try_catch.HasCaught()) { + return 2; + } + + // If the result is an error, return a failure + if (result->IsNativeError()) { return 1; } diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index eb798a4ee..86b76718a 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -796,10 +796,11 @@ declare module "grpc" { /** * A callback that will receive the expected hostname and presented peer - * certificate as parameters. The callback should throw an error to - * indicate that the presented certificate is considered invalid. + * certificate as parameters. The callback should return an error to + * indicate that the presented certificate is considered invalid and + * otherwise returned undefined. */ - export type CheckServerIdentityCallback = (hostname: string, cert: string) => void; + export type CheckServerIdentityCallback = (hostname: string, cert: string) => Error | undefined; /** * Additional peer verification options that can be set when creating diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 1c461d369..0fde6185a 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -87,18 +87,10 @@ var _ = require('lodash'); * @param {Buffer=} private_key The client certificate private key, if * applicable * @param {Buffer=} cert_chain The client certificate cert chain, if applicable - * @param {Object} verify_options Additional peer verification options. Can - * be undefined, in which case default behavior is preserved. - * Supported options are: "checkServerIdentity": (servername, cert) => {} - * The callback passed to checkServerIdentity will be invoked when the - * channel is opened in order to provide an opportunity to perform - * additional verification of the peer certificate as passed to the - * callback in the second parameter. The expected hostname is passed as - * the first parameter. If the callback considers the peer certificate - * invalid it should throw an error which will cause the handshake to - * be terminated. Note that supplying this callback does not disable - * the usual hostname verification which will also be performed on the - * certificate before this callback is invoked. + * @param {Function} verify_options.checkServerIdentity Optional callback + * receiving the expected hostname and peer certificate for additional + * verification. The callback should return an Error if verification + * fails and otherwise return undefined. * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object */ exports.createSsl = ChannelCredentials.createSsl; diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index 542f93f36..f3fc082f7 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -309,6 +309,19 @@ describe('client credentials', function() { done(); }); }); + it('Verify callback returning an Error causes connection failure', function(done) { + var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": function(host, cert) { + return new Error("Verification error"); + } + }); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ok(err, "Should have raised an error"); + done(); + }); + }); it('Should update metadata with SSL creds', function(done) { var metadataUpdater = function(service_url, callback) { var metadata = new grpc.Metadata(); From 44cb04b948fec8a9830e2e52b708374d67c781e6 Mon Sep 17 00:00:00 2001 From: Nathan Perry Date: Thu, 19 Jul 2018 16:10:21 -0400 Subject: [PATCH 0307/1899] properly pass `options` to `getDefaultValues` Fixed call in `deprecated_request_wrap` to properly pass `options` to `getDefaultValues` --- packages/grpc-native-core/src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 83d7b750d..40f143949 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -762,7 +762,7 @@ var deprecated_request_wrap = { return function makeWrappedUnaryRequest(argument, callback, metadata, options) { /* jshint validthis: true */ - var opt_args = getDefaultValues(metadata, metadata); + var opt_args = getDefaultValues(metadata, options); return makeUnaryRequest.call(this, argument, opt_args.metadata, opt_args.options, callback); }; From 34930310d2259f27e8a32ebf7a4651a0ebe53297 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 19 Jul 2018 12:29:57 -0700 Subject: [PATCH 0308/1899] Refactor checkServerIdentity callback to pass in cert as an object with raw DER buffer. --- packages/grpc-native-core/package.json | 1 + packages/grpc-native-core/src/credentials.js | 44 ++++++++++++++++++- .../grpc-native-core/test/credentials_test.js | 12 ++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 52f8eac12..2e11bf4c9 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -44,6 +44,7 @@ "istanbul": "^0.4.4", "lodash": "^4.17.4", "minimist": "^1.1.0", + "node-forge": "^0.7.5", "poisson-process": "^0.2.1" }, "engines": { diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 0fde6185a..28b668b1d 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -76,6 +76,31 @@ var _ = require('lodash'); * @see https://github.com/google/google-auth-library-nodejs */ +const PEM_CERT_HEADER = "-----BEGIN CERTIFICATE-----"; +const PEM_CERT_FOOTER = "-----END CERTIFICATE-----"; + +function wrapCheckServerIdentityCallback(callback) { + return function(hostname, cert) { + // Parse cert from pem to a version that matches the tls.checkServerIdentity + // format. + // https://nodejs.org/api/tls.html#tls_tls_checkserveridentity_hostname_cert + + var pemHeaderIndex = cert.indexOf(PEM_CERT_HEADER); + if (pemHeaderIndex === -1) { + return new Error("Unable to parse certificate PEM."); + } + cert = cert.substring(pemHeaderIndex); + var pemFooterIndex = cert.indexOf(PEM_CERT_FOOTER); + if (pemFooterIndex === -1) { + return new Error("Unable to parse certificate PEM."); + } + cert = cert.substring(PEM_CERT_HEADER.length, pemFooterIndex); + var rawBuffer = new Buffer(cert.replace("\n", "").replace(" ", ""), "base64"); + + return callback(hostname, { raw: rawBuffer }); + } +} + /** * Create an SSL Credentials object. If using a client-side certificate, both * the second and third arguments must be passed. Additional peer verification @@ -93,7 +118,24 @@ var _ = require('lodash'); * fails and otherwise return undefined. * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object */ -exports.createSsl = ChannelCredentials.createSsl; +exports.createSsl = function(root_certs, private_key, cert_chain, verify_options) { + // The checkServerIdentity callback from gRPC core will receive the cert as a PEM. + // To better match the checkServerIdentity callback of Node, we wrap the callback + // to decode the PEM and populate a cert object. + if (verify_options && verify_options.checkServerIdentity) { + if (typeof verify_options.checkServerIdentity !== 'function') { + throw new TypeError("Value of checkServerIdentity must be a function."); + } + // Make a shallow clone of verify_options so our modification of the callback + // isn't reflected to the caller + var updated_verify_options = Object.assign({}, verify_options); + updated_verify_options.checkServerIdentity = wrapCheckServerIdentityCallback( + verify_options.checkServerIdentity); + arguments[3] = updated_verify_options; + } + return ChannelCredentials.createSsl.apply(this, arguments); +} + /** * @callback grpc.credentials~metadataCallback diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index f3fc082f7..74d3edc14 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -21,6 +21,7 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); +var forge = require('node-forge'); var grpc = require('..'); @@ -292,7 +293,16 @@ describe('client credentials', function() { client.unary({}, function(err, data) { assert.ifError(err); assert.equal(callback_host, 'foo.test.google.fr'); - assert.equal(callback_cert, pem_data); + + // The roundabout forge APIs for converting PEM to a node DER Buffer + var expected_der = new Buffer(forge.asn1.toDer( + forge.pki.certificateToAsn1(forge.pki.certificateFromPem(pem_data))) + .getBytes(), 'binary'); + + // Assert the buffers are equal by converting them to hex strings + assert.equal(callback_cert.raw.toString('hex'), expected_der.toString('hex')); + // Documented behavior of callback cert is that raw should be its only property + assert.equal(Object.keys(callback_cert).length, 1); done(); }); }); From 045d938bc82a57ddef8f68a5e1f7c01047dd2bc1 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 19 Jul 2018 14:05:10 -0700 Subject: [PATCH 0309/1899] Update typescript to properly reflect the format of the certificate received by the checkServerIdentity callback. --- packages/grpc-native-core/index.d.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 86b76718a..247970ebd 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -794,13 +794,17 @@ declare module "grpc" { ERROR, } + export interface Certificate { + raw: Buffer; + } + /** * A callback that will receive the expected hostname and presented peer * certificate as parameters. The callback should return an error to * indicate that the presented certificate is considered invalid and * otherwise returned undefined. */ - export type CheckServerIdentityCallback = (hostname: string, cert: string) => Error | undefined; + export type CheckServerIdentityCallback = (hostname: string, cert: Certificate) => Error | undefined; /** * Additional peer verification options that can be set when creating From c04d71521f6faf76e073de7e90718dab37779b8f Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 19 Jul 2018 14:06:51 -0700 Subject: [PATCH 0310/1899] Add some missing descriptions to typescript. --- packages/grpc-native-core/index.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 247970ebd..45d9d9783 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -794,7 +794,13 @@ declare module "grpc" { ERROR, } + /** + * A certificate as received by the checkServerIdentity callback. + */ export interface Certificate { + /** + * The raw certificate in DER form. + */ raw: Buffer; } From c4e3f1b7a083ad4dbeb0e1f2ce9083b17f85f3c6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 19 Jul 2018 15:57:33 -0700 Subject: [PATCH 0311/1899] Add Channel class and Client channel override options to public API --- packages/grpc-native-core/binding.gyp | 3 +- packages/grpc-native-core/ext/call.cc | 84 ++---------- packages/grpc-native-core/ext/call.h | 2 + packages/grpc-native-core/ext/channel.cc | 127 +++++++++++++++++- packages/grpc-native-core/ext/channel.h | 1 + packages/grpc-native-core/index.d.ts | 65 ++++++++- packages/grpc-native-core/index.js | 83 ++++++++++++ packages/grpc-native-core/src/client.js | 26 ++-- .../src/client_interceptors.js | 4 +- packages/grpc-native-core/src/constants.js | 15 +++ .../templates/binding.gyp.template | 3 +- packages/grpc-native-core/test/call_test.js | 82 +++++------ .../grpc-native-core/test/channel_test.js | 4 +- .../grpc-native-core/test/end_to_end_test.js | 8 +- 14 files changed, 353 insertions(+), 154 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index e0b893aa8..b52892ac4 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -90,7 +90,8 @@ 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', - 'GRPC_UV' + 'GRPC_UV', + 'GRPC_NODE_VERSION="1.14.0-dev"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/ext/call.cc b/packages/grpc-native-core/ext/call.cc index f73a70d25..8922bc668 100644 --- a/packages/grpc-native-core/ext/call.cc +++ b/packages/grpc-native-core/ext/call.cc @@ -537,6 +537,8 @@ bool Call::HasInstance(Local val) { return Nan::New(fun_tpl)->HasInstance(val); } +grpc_call *Call::GetWrappedCall() { return this->wrapped_call; } + Local Call::WrapStruct(grpc_call *call) { EscapableHandleScope scope; if (call == NULL) { @@ -575,82 +577,20 @@ NAN_METHOD(Call::New) { */ if (info.IsConstructCall()) { Call *call; - if (info[0]->IsExternal()) { - Local ext = info[0].As(); - // This option is used for wrapping an existing call - grpc_call *call_value = reinterpret_cast(ext->Value()); - call = new Call(call_value); - } else { - if (!Channel::HasInstance(info[0])) { - return Nan::ThrowTypeError("Call's first argument must be a Channel"); - } - if (!info[1]->IsString()) { - return Nan::ThrowTypeError("Call's second argument must be a string"); - } - if (!(info[2]->IsNumber() || info[2]->IsDate())) { - return Nan::ThrowTypeError( - "Call's third argument must be a date or a number"); - } - // These arguments are at the end because they are optional - grpc_call *parent_call = NULL; - if (Call::HasInstance(info[4])) { - Call *parent_obj = - ObjectWrap::Unwrap(Nan::To(info[4]).ToLocalChecked()); - parent_call = parent_obj->wrapped_call; - } else if (!(info[4]->IsUndefined() || info[4]->IsNull())) { - return Nan::ThrowTypeError( - "Call's fifth argument must be another call, if provided"); - } - uint32_t propagate_flags = GRPC_PROPAGATE_DEFAULTS; - if (info[5]->IsUint32()) { - propagate_flags = Nan::To(info[5]).FromJust(); - } else if (!(info[5]->IsUndefined() || info[5]->IsNull())) { - return Nan::ThrowTypeError( - "Call's sixth argument must be propagate flags, if provided"); - } - Local channel_object = Nan::To(info[0]).ToLocalChecked(); - Channel *channel = ObjectWrap::Unwrap(channel_object); - if (channel->GetWrappedChannel() == NULL) { - return Nan::ThrowError("Call cannot be created from a closed channel"); - } - double deadline = Nan::To(info[2]).FromJust(); - grpc_channel *wrapped_channel = channel->GetWrappedChannel(); - grpc_call *wrapped_call; - grpc_slice method = - CreateSliceFromString(Nan::To(info[1]).ToLocalChecked()); - if (info[3]->IsString()) { - grpc_slice *host = new grpc_slice; - *host = - CreateSliceFromString(Nan::To(info[3]).ToLocalChecked()); - wrapped_call = grpc_channel_create_call( - wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), - method, host, MillisecondsToTimespec(deadline), NULL); - delete host; - } else if (info[3]->IsUndefined() || info[3]->IsNull()) { - wrapped_call = grpc_channel_create_call( - wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), - method, NULL, MillisecondsToTimespec(deadline), NULL); - } else { - return Nan::ThrowTypeError("Call's fourth argument must be a string"); - } - grpc_slice_unref(method); - call = new Call(wrapped_call); - Nan::Set(info.This(), Nan::New("channel_").ToLocalChecked(), - channel_object); + if (!info[0]->IsExternal()) { + return Nan::ThrowTypeError( + "Call can only be created with Channel.createCall"); } + Local ext = info[0].As(); + // This option is used for wrapping an existing call + grpc_call *call_value = reinterpret_cast(ext->Value()); + call = new Call(call_value); call->Wrap(info.This()); info.GetReturnValue().Set(info.This()); + return; } else { - const int argc = 4; - Local argv[argc] = {info[0], info[1], info[2], info[3]}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - // There's probably a pending exception - return; - } else { - info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); - } + return Nan::ThrowTypeError( + "Call can only be created with Channel.createCall"); } } diff --git a/packages/grpc-native-core/ext/call.h b/packages/grpc-native-core/ext/call.h index 5bf83a42a..f78822d1c 100644 --- a/packages/grpc-native-core/ext/call.h +++ b/packages/grpc-native-core/ext/call.h @@ -52,6 +52,8 @@ class Call : public Nan::ObjectWrap { /* Wrap a grpc_call struct in a javascript object */ static v8::Local WrapStruct(grpc_call *call); + grpc_call *GetWrappedCall(); + void CompleteBatch(bool is_final_op); private: diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index db6d2b453..6d41c77f9 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -28,6 +28,7 @@ #include "completion_queue.h" #include "grpc/grpc.h" #include "grpc/grpc_security.h" +#include "slice.h" #include "timeval.h" namespace grpc { @@ -56,11 +57,24 @@ using v8::Value; Callback *Channel::constructor; Persistent Channel::fun_tpl; +static const char grpc_node_user_agent[] = "grpc-node/" GRPC_NODE_VERSION; + +void PopulateUserAgentChannelArg(grpc_arg *arg) { + size_t key_len = sizeof(GRPC_ARG_PRIMARY_USER_AGENT_STRING); + size_t val_len = sizeof(grpc_node_user_agent); + arg->key = reinterpret_cast(calloc(key_len, sizeof(char))); + memcpy(arg->key, GRPC_ARG_PRIMARY_USER_AGENT_STRING, key_len); + arg->type = GRPC_ARG_STRING; + arg->value.string = reinterpret_cast(calloc(val_len, sizeof(char))); + memcpy(arg->value.string, grpc_node_user_agent, val_len); + +} + bool ParseChannelArgs(Local args_val, grpc_channel_args **channel_args_ptr) { if (args_val->IsUndefined() || args_val->IsNull()) { - *channel_args_ptr = NULL; - return true; + // Treat null and undefined the same as an empty object + args_val = Nan::New(); } if (!args_val->IsObject()) { *channel_args_ptr = NULL; @@ -72,9 +86,17 @@ bool ParseChannelArgs(Local args_val, Local args_hash = Nan::To(args_val).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked(); channel_args->num_args = keys->Length(); + /* This is an ugly hack to add in the user agent string argument if it wasn't + * passed by the user */ + bool has_user_agent_arg = Nan::HasOwnProperty( + args_hash, Nan::New(GRPC_ARG_PRIMARY_USER_AGENT_STRING).ToLocalChecked() + ).ToChecked(); + if (!has_user_agent_arg) { + channel_args->num_args += 1; + } channel_args->args = reinterpret_cast( calloc(channel_args->num_args, sizeof(grpc_arg))); - for (unsigned int i = 0; i < channel_args->num_args; i++) { + for (unsigned int i = 0; i < keys->Length(); i++) { Local key = Nan::Get(keys, i).ToLocalChecked(); Utf8String key_str(key); if (*key_str == NULL) { @@ -88,10 +110,31 @@ bool ParseChannelArgs(Local args_val, } else if (value->IsString()) { Utf8String val_str(value); channel_args->args[i].type = GRPC_ARG_STRING; - channel_args->args[i].value.string = - reinterpret_cast(calloc(val_str.length() + 1, sizeof(char))); - memcpy(channel_args->args[i].value.string, *val_str, - val_str.length() + 1); + /* Append the grpc-node user agent string after the application user agent + * string, and put the combination at the beginning of the user agent string + */ + if (strcmp(*key_str, GRPC_ARG_PRIMARY_USER_AGENT_STRING) == 0) { + /* val_str.length() is the string length and does not include the + * trailing 0 byte. sizeof(grpc_node_user_agent) is the array length, + * so it does include the trailing 0 byte. */ + size_t val_str_len = val_str.length(); + size_t user_agent_len = sizeof(grpc_node_user_agent); + /* This is the length of the two parts of the string, plus the space in + * between, plus the 0 at the end, which is included in user_agent_len. + */ + channel_args->args[i].value.string = + reinterpret_cast(calloc(val_str_len + user_agent_len + 1, sizeof(char))); + memcpy(channel_args->args[i].value.string, *val_str, + val_str.length()); + channel_args->args[i].value.string[val_str_len] = ' '; + memcpy(channel_args->args[i].value.string + val_str_len + 1, + grpc_node_user_agent, user_agent_len); + } else { + channel_args->args[i].value.string = + reinterpret_cast(calloc(val_str.length() + 1, sizeof(char))); + memcpy(channel_args->args[i].value.string, *val_str, + val_str.length() + 1); + } } else { // The value does not match either of the accepted types return false; @@ -100,6 +143,11 @@ bool ParseChannelArgs(Local args_val, reinterpret_cast(calloc(key_str.length() + 1, sizeof(char))); memcpy(channel_args->args[i].key, *key_str, key_str.length() + 1); } + /* Add a standard user agent string argument if none was provided */ + if (!has_user_agent_arg) { + size_t index = channel_args->num_args - 1; + PopulateUserAgentChannelArg(&channel_args->args[index]); + } return true; } @@ -141,6 +189,7 @@ void Channel::Init(Local exports) { Nan::SetPrototypeMethod(tpl, "getConnectivityState", GetConnectivityState); Nan::SetPrototypeMethod(tpl, "watchConnectivityState", WatchConnectivityState); + Nan::SetPrototypeMethod(tpl, "createCall", CreateCall); fun_tpl.Reset(tpl); Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set(exports, Nan::New("Channel").ToLocalChecked(), ctr); @@ -268,5 +317,69 @@ NAN_METHOD(Channel::WatchConnectivityState) { CompletionQueueNext(); } +NAN_METHOD(Channel::CreateCall) { + /* Arguments: + * 0: Method + * 1: Deadline + * 2: host + * 3: parent Call + * 4: propagation flags + */ + if (!HasInstance(info.This())) { + return Nan::ThrowTypeError( + "createCall can only be called on Channel objects"); + } + if (!info[0]->IsString()){ + return Nan::ThrowTypeError("createCall's first argument must be a string"); + } + if (!(info[1]->IsNumber() || info[1]->IsDate())) { + return Nan::ThrowTypeError( + "createcall's second argument must be a date or a number"); + } + // These arguments are at the end because they are optional + grpc_call *parent_call = NULL; + if (Call::HasInstance(info[3])) { + Call *parent_obj = + ObjectWrap::Unwrap(Nan::To(info[3]).ToLocalChecked()); + parent_call = parent_obj->GetWrappedCall(); + } else if (!(info[3]->IsUndefined() || info[3]->IsNull())) { + return Nan::ThrowTypeError( + "createCall's fourth argument must be another call, if provided"); + } + uint32_t propagate_flags = GRPC_PROPAGATE_DEFAULTS; + if (info[4]->IsUint32()) { + propagate_flags = Nan::To(info[4]).FromJust(); + } else if (!(info[4]->IsUndefined() || info[4]->IsNull())) { + return Nan::ThrowTypeError( + "createCall's fifth argument must be propagate flags, if provided"); + } + Channel *channel = ObjectWrap::Unwrap(info.This()); + grpc_channel *wrapped_channel = channel->GetWrappedChannel(); + if (wrapped_channel == NULL) { + return Nan::ThrowError("Cannot createCall with a closed Channel"); + } + grpc_slice method = + CreateSliceFromString(Nan::To(info[0]).ToLocalChecked()); + double deadline = Nan::To(info[1]).FromJust(); + grpc_call *wrapped_call = NULL; + if (info[2]->IsString()) { + grpc_slice *host = new grpc_slice; + *host = + CreateSliceFromString(Nan::To(info[3]).ToLocalChecked()); + wrapped_call = grpc_channel_create_call( + wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), + method, host, MillisecondsToTimespec(deadline), NULL); + delete host; + } else if (info[2]->IsUndefined() || info[2]->IsNull()) { + wrapped_call = grpc_channel_create_call( + wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), + method, NULL, MillisecondsToTimespec(deadline), NULL); + } else { + return Nan::ThrowTypeError("createCall's third argument must be a string"); + } + grpc_slice_unref(method); + info.GetReturnValue().Set(Call::WrapStruct(wrapped_call)); +} + } // namespace node } // namespace grpc diff --git a/packages/grpc-native-core/ext/channel.h b/packages/grpc-native-core/ext/channel.h index a93dbe9d2..7925cef47 100644 --- a/packages/grpc-native-core/ext/channel.h +++ b/packages/grpc-native-core/ext/channel.h @@ -56,6 +56,7 @@ class Channel : public Nan::ObjectWrap { static NAN_METHOD(GetTarget); static NAN_METHOD(GetConnectivityState); static NAN_METHOD(WatchConnectivityState); + static NAN_METHOD(CreateCall); static Nan::Callback *constructor; static Nan::Persistent fun_tpl; diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 7d8cfdc81..f026cccde 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1083,11 +1083,6 @@ declare module "grpc" { waitForReady(deadline: Deadline, callback: (error: Error | null) => void): void; } - /** - * A gRPC channel. - */ - export type Channel = any; - /** * Options that can be set on a call. */ @@ -1465,4 +1460,62 @@ declare module "grpc" { */ recvMessageWithContext(context: object): void; } -} + export enum connectivityState { + IDLE = 0, + CONNECTING = 1, + READY = 2, + TRANSIENT_FAILURE = 3, + SHUTDOWN = 4 + } + + export class Channel { + /** + * This constructor API is almost identical to the Client constructor, + * except that some of the options for the Client constructor are not valid + * here. + * @param target The address of the server to connect to + * @param credentials Channel credentials to use when connecting + * @param options A map of channel options that will be passed to the core + */ + constructor(target: string, credentials: ChannelCredentials, options: {[key:string]: string|number}); + /** + * Close the channel. This has the same functionality as the existing grpc.Client.prototype.close + */ + close(): void; + /** + * Return the target that this channel connects to + */ + getTarget(): string; + /** + * Get the channel's current connectivity state. + * @param tryToConnect If true, the channel will start connecting if it is + * idle. Otherwise, idle channels will only start connecting when a + * call starts. + */ + getConnectivityState(tryToConnect: boolean): connectivityState; + /** + * Watch for connectivity state changes. + * @param currentState The state to watch for transitions from. This should + * always be populated by calling getConnectivityState immediately + * before. + * @param deadline A deadline for waiting for a state change + * @param callback Called with no error when a state change, or with an + * error if the deadline passes without a state change. + */ + watchConnectivityState(currentState: connectivityState, deadline: Date|number, callback: (error?: Error) => void); + /** + * Create a call object. Call is an opaque type that is used by the Client + * and Server classes. This function is called by the gRPC library when + * starting a request. Implementers should return an instance of Call that + * is returned from calling createCall on an instance of the provided + * Channel class. + * @param method The full method string to request. + * @param deadline The call deadline + * @param host A host string override for making the request + * @param parentCall A server call to propagate some information from + * @param propagateFlags A bitwise combination of elements of grpc.propagate + * that indicates what information to propagate from parentCall. + */ + createCall(method: string, deadline: Date|number, host: string|null, parentCall: Call|null, propagateFlags: number|null): Call; + } +} \ No newline at end of file diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index c0d81055f..06038535d 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -231,6 +231,8 @@ exports.logVerbosity = constants.logVerbosity; exports.methodTypes = constants.methodTypes; +exports.connectivityState = constants.connectivityState; + exports.credentials = require('./src/credentials.js'); /** @@ -289,3 +291,84 @@ exports.closeClient = function closeClient(client_obj) { }; exports.Client = client.Client; + +/** + * @typedef {Object.} grpc~ChannelOptions + */ + +/** + * This constructor API is almost identical to the Client constructor, + * except that some of the options for the Client constructor are not valid + * here. + * @constructor Channel + * @memberof grpc + * @param {string} target The address of the server to connect to + * @param {grpc.ChannelCredentials} credentials Channel credentials to use when connecting + * @param {grpc~ChannelOptions} options A map of channel options that will be passed to the core + */ +exports.Channel = grpc.Channel; + +/** + * Close the channel. This has the same functionality as the existing grpc.Client#close + * @name grpc.Channel#close + * @kind function + */ + +/** + * Return the target that this channel connects to + * @name grpc.Channel#getTarget + * @kind function + * @return {string} The target + */ + +/** + * Get the channel's current connectivity state. + * @name grpc.Channel#getConnectivityState + * @kind function + * @param {boolean} tryToConnect If true, the channel will start connecting if it is + * idle. Otherwise, idle channels will only start connecting when a + * call starts. + * @return {grpc.connectivityState} The current connectivity state + */ + +/** + * @callback grpc.Channel~watchConnectivityStateCallback + * @param {Error?} error + */ + +/** + * Watch for connectivity state changes. + * @name grpc.Channel#watchConnectivityState + * @kind function + * @param {grpc.ConnectivityState} currentState The state to watch for + * transitions from. This should always be populated by calling + * getConnectivityState immediately before. + * @param {grpc~Deadline} deadline A deadline for waiting for a state change + * @param {grpc.Channel~watchConnectivityStateCallback} callback Called with no + * error when the state changes, or with an error if the deadline passes + * without a state change + */ + +/** + * @name grpc~Call + * @kind class + */ + +/** + * Create a call object. Call is an opaque type used by the {@link grpc.Client} + * and {@link grpc.Server} classes. This function is called by the gRPC library + * when starting a request. Implementers should return an instance of Call that + * is returned from calling createCall on an instance of the provided Channel + * class. + * @name grpc.Channel#createCall + * @kind function + * @param {string} method The full method string to request + * @param {grpc~Deadline} deadline The call deadline + * @param {string|null} host A host string override for making the request + * @param {grpc~Call|null} parentCall A server call to propagate some + * information from + * @param {number|null} propagateFlags A bitwise combination of elements of + * {@link grpc.propagate} that indicates what information to propagate + * from parentCall + * @return {grpc~Call} + */ \ No newline at end of file diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 83d7b750d..5c293b20c 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -369,15 +369,6 @@ function Client(address, credentials, options) { if (!options) { options = {}; } - /* Append the grpc-node user agent string after the application user agent - * string, and put the combination at the beginning of the user agent string - */ - if (options['grpc.primary_user_agent']) { - options['grpc.primary_user_agent'] += ' '; - } else { - options['grpc.primary_user_agent'] = ''; - } - options['grpc.primary_user_agent'] += 'grpc-node/' + version; // Resolve interceptor options and assign interceptors to each method if (_.isArray(options.interceptor_providers) && _.isArray(options.interceptors)) { @@ -392,12 +383,23 @@ function Client(address, credentials, options) { .resolveInterceptorProviders(self.$interceptor_providers, method_definition) .concat(self.$interceptors); }); - // Exclude interceptor options which have already been consumed + let channelOverride = options.channelOverride; + let channelFactoryOverride = options.channelFactoryOverride; + // Exclude channel options which have already been consumed var channel_options = _.omit(options, - ['interceptors', 'interceptor_providers']); + ['interceptors', 'interceptor_providers', + 'channelOverride', 'channelFactoryOverride']); /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ - this.$channel = new grpc.Channel(address, credentials, channel_options); + if (channelOverride) { + this.$channel = options.channelOverride; + } else { + if (channelFactoryOverride) { + this.$channel = channelFactoryOverride(address, credentials, channel_options); + } else { + this.$channel = new grpc.Channel(address, credentials, channel_options); + } + } } exports.Client = Client; diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index ddd147218..f240f9d3d 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -648,8 +648,8 @@ function getCall(channel, path, options) { if (deadline === undefined) { deadline = Infinity; } - var call = new grpc.Call(channel, path, deadline, host, - parent, propagate_flags); + var call = channel.createCall(path, deadline, host, + parent, propagate_flags); if (credentials) { call.setCredentials(credentials); } diff --git a/packages/grpc-native-core/src/constants.js b/packages/grpc-native-core/src/constants.js index e9df9a318..0d245fe1b 100644 --- a/packages/grpc-native-core/src/constants.js +++ b/packages/grpc-native-core/src/constants.js @@ -249,3 +249,18 @@ exports.methodTypes = { SERVER_STREAMING: 2, BIDI_STREAMING: 3 }; + +/** + * Connectivity state values + * @memberof grpc + * @alias grpc.connectivityState + * @readonly + * @enum {number} + */ +exports.connectivityState = { + IDLE: 0, + CONNECTING: 1, + READY: 2, + TRANSIENT_FAILURE: 3, + SHUTDOWN: 4 +}; diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 2146f1666..f9abaa7c3 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -82,7 +82,8 @@ 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', - 'GRPC_UV' + 'GRPC_UV', + 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/test/call_test.js b/packages/grpc-native-core/test/call_test.js index b5246c4f3..f2d1a6ca0 100644 --- a/packages/grpc-native-core/test/call_test.js +++ b/packages/grpc-native-core/test/call_test.js @@ -49,60 +49,48 @@ describe('call', function() { after(function() { server.forceShutdown(); }); - describe('constructor', function() { - it('should reject anything less than 3 arguments', function() { + describe('factory', function() { + it('should reject anything less than 2 arguments', function() { assert.throws(function() { - new grpc.Call(); + channel.createCall(); }, TypeError); assert.throws(function() { - new grpc.Call(channel); - }, TypeError); - assert.throws(function() { - new grpc.Call(channel, 'method'); + channel.createCall('method'); }, TypeError); }); - it('should succeed with a Channel, a string, and a date or number', + it('should succeed with a string and a date or number', function() { assert.doesNotThrow(function() { - new grpc.Call(channel, 'method', new Date()); + channel.createCall('method', new Date()); }); assert.doesNotThrow(function() { - new grpc.Call(channel, 'method', 0); + channel.createCall('method', 0); }); }); - it('should accept an optional fourth string parameter', function() { + it('should accept an optional third string parameter', function() { assert.doesNotThrow(function() { - new grpc.Call(channel, 'method', new Date(), 'host_override'); + channel.createCall('method', new Date(), 'host_override'); }); }); it('should fail with a closed channel', function() { var local_channel = new grpc.Channel('hostname', insecureCreds); local_channel.close(); assert.throws(function() { - new grpc.Call(channel, 'method'); + local_channel.createCall('method', 0); }); }); it('should fail with other types', function() { assert.throws(function() { - new grpc.Call({}, 'method', 0); - }, TypeError); - assert.throws(function() { - new grpc.Call(channel, null, 0); + channel.createCall(null, 0); }, TypeError); assert.throws(function() { - new grpc.Call(channel, 'method', 'now'); + channel.createCall('method', 'now'); }, TypeError); }); - it('should succeed without the new keyword', function() { - assert.doesNotThrow(function() { - var call = grpc.Call(channel, 'method', new Date()); - assert(call instanceof grpc.Call); - }); - }); }); describe('deadline', function() { it('should time out immediately with negative deadline', function(done) { - var call = new grpc.Call(channel, 'method', -Infinity); + var call = channel.createCall('method', -Infinity); var batch = {}; batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(batch, function(err, response) { @@ -114,7 +102,7 @@ describe('call', function() { }); describe('startBatch', function() { it('should fail without an object and a function', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { call.startBatch(); }); @@ -126,7 +114,7 @@ describe('call', function() { }); }); it('should succeed with an empty object', function(done) { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.doesNotThrow(function() { call.startBatch({}, function(err) { assert.ifError(err); @@ -137,7 +125,7 @@ describe('call', function() { }); describe('startBatch with metadata', function() { it('should succeed with a map of strings to string arrays', function(done) { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.doesNotThrow(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'], @@ -150,7 +138,7 @@ describe('call', function() { }); }); it('should succeed with a map of strings to buffer arrays', function(done) { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.doesNotThrow(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = { @@ -165,7 +153,7 @@ describe('call', function() { }); }); it('should fail with other parameter types', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = undefined; @@ -190,7 +178,7 @@ describe('call', function() { }); describe('startBatch with message', function() { it('should fail with null argument', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_MESSAGE] = null; @@ -198,7 +186,7 @@ describe('call', function() { }, TypeError); }); it('should fail with numeric argument', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_MESSAGE] = 5; @@ -206,7 +194,7 @@ describe('call', function() { }, TypeError); }); it('should fail with string argument', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_MESSAGE] = 'value'; @@ -216,7 +204,7 @@ describe('call', function() { }); describe('startBatch with status', function() { it('should fail without a code', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { @@ -227,7 +215,7 @@ describe('call', function() { }, TypeError); }); it('should fail without details', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { @@ -238,7 +226,7 @@ describe('call', function() { }, TypeError); }); it('should fail without metadata', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { @@ -249,7 +237,7 @@ describe('call', function() { }, TypeError); }); it('should fail with incorrectly typed code argument', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { @@ -261,7 +249,7 @@ describe('call', function() { }, TypeError); }); it('should fail with incorrectly typed details argument', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { @@ -273,7 +261,7 @@ describe('call', function() { }, TypeError); }); it('should fail with incorrectly typed metadata argument', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.throws(function() { var batch = {}; batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { @@ -287,7 +275,7 @@ describe('call', function() { }); describe('cancel', function() { it('should succeed', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.doesNotThrow(function() { call.cancel(); }); @@ -296,30 +284,30 @@ describe('call', function() { describe('cancelWithStatus', function() { it('should reject anything other than an integer and a string', function() { assert.doesNotThrow(function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); call.cancelWithStatus(1, 'details'); }); assert.throws(function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); call.cancelWithStatus(); }); assert.throws(function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); call.cancelWithStatus(''); }); assert.throws(function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); call.cancelWithStatus(5, {}); }); }); it('should reject the OK status code', function() { assert.throws(function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); call.cancelWithStatus(0, 'details'); }); }); it('should result in the call ending with a status', function(done) { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); var batch = {}; batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(batch, function(err, response) { @@ -332,7 +320,7 @@ describe('call', function() { }); describe('getPeer', function() { it('should return a string', function() { - var call = new grpc.Call(channel, 'method', getDeadline(1)); + var call = channel.createCall('method', getDeadline(1)); assert.strictEqual(typeof call.getPeer(), 'string'); }); }); diff --git a/packages/grpc-native-core/test/channel_test.js b/packages/grpc-native-core/test/channel_test.js index 373c5ac3c..8c95d84ae 100644 --- a/packages/grpc-native-core/test/channel_test.js +++ b/packages/grpc-native-core/test/channel_test.js @@ -19,7 +19,7 @@ 'use strict'; var assert = require('assert'); -var grpc = require('../src/grpc_extension'); +var grpc = require('..'); /** * This is used for testing functions with multiple asynchronous calls that @@ -41,7 +41,7 @@ function multiDone(done, count) { } }; } -var insecureCreds = grpc.ChannelCredentials.createInsecure(); +var insecureCreds = grpc.credentials.createInsecure(); describe('channel', function() { describe('constructor', function() { diff --git a/packages/grpc-native-core/test/end_to_end_test.js b/packages/grpc-native-core/test/end_to_end_test.js index c11dfa93c..7db373d6a 100644 --- a/packages/grpc-native-core/test/end_to_end_test.js +++ b/packages/grpc-native-core/test/end_to_end_test.js @@ -61,7 +61,7 @@ describe('end-to-end', function() { it('should start and end a request without error', function(complete) { var done = multiDone(complete, 2); var status_text = 'xyz'; - var call = new grpc.Call(channel, + var call = channel.createCall( 'dummy_method', Infinity); var client_batch = {}; @@ -111,7 +111,7 @@ describe('end-to-end', function() { it('should successfully send and receive metadata', function(complete) { var done = multiDone(complete, 2); var status_text = 'xyz'; - var call = new grpc.Call(channel, + var call = channel.createCall( 'dummy_method', Infinity); var client_batch = {}; @@ -167,7 +167,7 @@ describe('end-to-end', function() { var reply_text = 'server_response'; var done = multiDone(complete, 2); var status_text = 'success'; - var call = new grpc.Call(channel, + var call = channel.createCall( 'dummy_method', Infinity); var client_batch = {}; @@ -222,7 +222,7 @@ describe('end-to-end', function() { var done = multiDone(complete, 2); var requests = ['req1', 'req2']; var status_text = 'xyz'; - var call = new grpc.Call(channel, + var call = channel.createCall( 'dummy_method', Infinity); var client_batch = {}; From 671b5837e08dd2053a64d2fa5a3195e6292ad498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Vald=C3=A9s=20de=20Le=C3=B3n?= Date: Fri, 20 Jul 2018 11:55:48 +0200 Subject: [PATCH 0312/1899] Replaces `string` type with actual possible values Enhances documentation of the `type` argument for `grpc.Server.register`, leveraging on JSDoc's support for literal enumerations. This keeps developers from having to dig through the source code to find the valid values. --- packages/grpc-native-core/src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index ec5a80675..b238de048 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -802,7 +802,7 @@ Server.prototype.start = function() { * request values and returns a stream of response values * @param {grpc~serialize} serialize Serialization function for responses * @param {grpc~deserialize} deserialize Deserialization function for requests - * @param {string} type The streaming type of method that this handles + * @param {('unary'|'client_stream'|'server_stream'|'bidi')} type The streaming type of method that this handles * @return {boolean} True if the handler was set. False if a handler was already * set for that name. */ From 811f7835b2146e6816db514a4bc0ee6603f31c97 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 20 Jul 2018 15:59:51 +0200 Subject: [PATCH 0313/1899] Proactively adding electron 3 support. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 85daa10b1..eb8f75534 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -16,7 +16,7 @@ set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index a98c775d2..d25bed842 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -17,7 +17,7 @@ set -ex arch_list=( ia32 x64 ) node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 ) while true ; do case $1 in From cc9427dede8f1f6d1bb30899b89afdd8ee0cb45d Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 23 Jul 2018 07:50:15 +0200 Subject: [PATCH 0314/1899] Stop using lodash's template generator. --- packages/grpc-native-core/index.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index c0d81055f..c489517e5 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -175,9 +175,14 @@ exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { return result; }; -var log_template = _.template( - '{severity} {timestamp}\t{file}:{line}]\t{message}', - {interpolate: /{([\s\S]+?)}/g}); +var log_template = function(args) { + var file = args.file; + var line = args.line; + var severity = args.severity; + var message = args.message; + var timestamp = args.timestamp; + return `${severity} ${timestamp}\t${file}:${line}]\t${message}`; +}; /** * Sets the logger function for the gRPC module. For debugging purposes, the C From 36f326281b1298d73c4372f4fb50987377f4624b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 23 Jul 2018 13:49:58 -0700 Subject: [PATCH 0315/1899] Fix a function call --- packages/grpc-native-core/ext/channel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index 6d41c77f9..bd7a63927 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -90,7 +90,7 @@ bool ParseChannelArgs(Local args_val, * passed by the user */ bool has_user_agent_arg = Nan::HasOwnProperty( args_hash, Nan::New(GRPC_ARG_PRIMARY_USER_AGENT_STRING).ToLocalChecked() - ).ToChecked(); + ).FromJust(); if (!has_user_agent_arg) { channel_args->num_args += 1; } From 25f49bee8bcf31d59157b531e999b8060bdbb859 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Mon, 23 Jul 2018 07:50:15 +0200 Subject: [PATCH 0316/1899] Stop using lodash's template generator. --- packages/grpc-native-core/index.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index c0d81055f..c489517e5 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -175,9 +175,14 @@ exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { return result; }; -var log_template = _.template( - '{severity} {timestamp}\t{file}:{line}]\t{message}', - {interpolate: /{([\s\S]+?)}/g}); +var log_template = function(args) { + var file = args.file; + var line = args.line; + var severity = args.severity; + var message = args.message; + var timestamp = args.timestamp; + return `${severity} ${timestamp}\t${file}:${line}]\t${message}`; +}; /** * Sets the logger function for the gRPC module. For debugging purposes, the C From a05ce748c44bc01f60bfecf4314dd966f656ef56 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 24 Jul 2018 20:13:00 +0200 Subject: [PATCH 0317/1899] Reverting the utf8 part of our interop test. --- test/interop/interop_client.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 6bf68901e..195ef8d47 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -347,13 +347,13 @@ function statusCodeAndMessage(client, done) { var arg = { response_status: { code: 2, - message: 'test status message - 測試字符串' + message: 'test status message' } }; client.unaryCall(arg, function(err, resp) { assert(err); assert.strictEqual(err.code, 2); - assert.strictEqual(err.details, 'test status message - 測試字符串'); + assert.strictEqual(err.details, 'test status message'); done(); }); var duplex = client.fullDuplexCall(); @@ -361,7 +361,7 @@ function statusCodeAndMessage(client, done) { duplex.on('status', function(status) { assert(status); assert.strictEqual(status.code, 2); - assert.strictEqual(status.details, 'test status message - 測試字符串'); + assert.strictEqual(status.details, 'test status message'); done(); }); duplex.on('error', function(){}); From 88adf94cb61cc464947c4ff8114319eb40ab9a56 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 24 Jul 2018 22:41:41 +0200 Subject: [PATCH 0318/1899] Bumping to 1.13.1. --- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..39db0640a 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.13.1 \ No newline at end of file diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 92f2d7911..bb2d33cb5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.13.0", + "version": "1.13.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From cc01eed63108fea276725b273ab02a0dc9c860ca Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 25 Jul 2018 21:54:24 +0200 Subject: [PATCH 0319/1899] Changing hosting path. --- packages/grpc-native-core/package.json | 4 ++-- packages/grpc-native-core/templates/package.json.template | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 52f8eac12..6af7e78ca 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -52,8 +52,8 @@ "binary": { "module_name": "grpc_node", "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", - "host": "https://storage.googleapis.com/", - "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", + "host": "https://node-precompiled-binaries.grpc.io/", + "remote_path": "{name}/v{version}", "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" }, "files": [ diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 82d6d1076..fe7fa6979 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -54,8 +54,8 @@ "binary": { "module_name": "grpc_node", "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", - "host": "https://storage.googleapis.com/", - "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", + "host": "https://node-precompiled-binaries.grpc.io/", + "remote_path": "{name}/v{version}", "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" }, "files": [ From d71dd337ef1bdee470dc67d3ca7c1f8d64ef9dbd Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 26 Jul 2018 01:33:16 +0200 Subject: [PATCH 0320/1899] Updating submodule to 1.14.x --- packages/grpc-native-core/binding.gyp | 10 +++++++--- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b52892ac4..88e71c28a 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0-dev"' + 'GRPC_NODE_VERSION="1.14.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -815,10 +815,12 @@ 'deps/grpc/src/core/lib/security/credentials/jwt/json_token.cc', 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc', + 'deps/grpc/src/core/lib/security/credentials/local/local_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', 'deps/grpc/src/core/lib/security/security_connector/alts_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/local_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', @@ -870,6 +872,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', + 'deps/grpc/src/core/ext/filters/client_channel/client_channel_channelz.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc', 'deps/grpc/src/core/ext/filters/client_channel/connector.cc', @@ -891,6 +894,7 @@ 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', 'deps/grpc/src/core/tsi/alts_transport_security.cc', 'deps/grpc/src/core/tsi/fake_transport_security.cc', + 'deps/grpc/src/core/tsi/local_transport_security.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc', @@ -907,6 +911,8 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', @@ -918,8 +924,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc', - 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc', 'deps/grpc/src/cpp/ext/filters/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 05628719f..768e8ea89 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 05628719f1c8d21969ddb700df05b4c63982b66a +Subproject commit 768e8ea89c9d27ea05b86cd83b0bfd18643bce12 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6af7e78ca..4e40a70de 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0-dev", + "version": "1.14.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From c03c275b48d168faf2587d85bf04b97091a5b4d2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 26 Jul 2018 11:33:20 -0700 Subject: [PATCH 0321/1899] Add special_status_message interop test --- test/api/interop_sanity_test.js | 1 + test/interop/interop_client.js | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 0ff4c28bb..27441e964 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -38,6 +38,7 @@ const testCases = [ 'timeout_on_sleeping_server', 'custom_metadata', 'status_code_and_message', + 'special_status_message', 'unimplemented_service', 'unimplemented_method' ]; diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 195ef8d47..447b018a0 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -369,6 +369,22 @@ function statusCodeAndMessage(client, done) { duplex.end(); } +function specialStatusMessage(client, done) { + let expectedMessage = '\t\ntest with whitespace\r\nand Unicode BMP ☺ and non-BMP 😈\t\n'; + let arg = { + response_status: { + code: 2, + message: expectedMessage + } + }; + client.unaryCall(arg, function(err, resp) { + assert(err); + assert.strictEqual(err.code, 2); + assert.strictEqual(err.details, expectedMessage); + done(); + }); +} + // NOTE: the client param to this function is from UnimplementedService function unimplementedService(client, done) { client.unimplementedCall({}, function(err, resp) { @@ -530,6 +546,8 @@ var test_cases = { Client: testProto.TestService}, status_code_and_message: {run: statusCodeAndMessage, Client: testProto.TestService}, + special_status_message: {run: specialStatusMessage, + Client: testProto.TestService}, unimplemented_service: {run: unimplementedService, Client: testProto.UnimplementedService}, unimplemented_method: {run: unimplementedMethod, From 3680966be5a66e8295d50cea75ccee46da998ef9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 27 Jul 2018 15:03:49 -0700 Subject: [PATCH 0322/1899] Don't refer to node-pre-gyp with a relative path --- packages/grpc-native-core/package.json | 8 ++++---- packages/grpc-native-core/templates/package.json.template | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 4e40a70de..cf581ea7a 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -19,10 +19,10 @@ "lib": "src" }, "scripts": { - "build": "./node_modules/.bin/node-pre-gyp build", - "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", - "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", - "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library", + "build": "node-pre-gyp build", + "electron-build": "node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", + "coverage": "istanbul cover ./node_modules/.bin/_mocha test", + "install": "node-pre-gyp install --fallback-to-build --library=static_library", "prepack": "git submodule update --init --recursive && npm install" }, "bundledDependencies": [ diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index fe7fa6979..a6d580a88 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -21,10 +21,10 @@ "lib": "src" }, "scripts": { - "build": "./node_modules/.bin/node-pre-gyp build", - "electron-build": "./node_modules/.bin/node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", - "coverage": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha test", - "install": "./node_modules/.bin/node-pre-gyp install --fallback-to-build --library=static_library", + "build": "node-pre-gyp build", + "electron-build": "node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", + "coverage": "istanbul cover ./node_modules/.bin/_mocha test", + "install": "node-pre-gyp install --fallback-to-build --library=static_library", "prepack": "git submodule update --init --recursive && npm install" }, "bundledDependencies": [ From a750587bb0dc5e036c5c71a436887645e3dfbf40 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 26 Jul 2018 11:14:09 -0700 Subject: [PATCH 0323/1899] Pure js: add simple keepalive logic --- packages/grpc-js-core/package.json | 2 +- packages/grpc-js-core/src/channel.ts | 56 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 1ea98edfc..d37ab364f 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@types/lodash": "^4.14.108", "@types/mocha": "^2.2.43", - "@types/node": "^9.4.6", + "@types/node": "^10.5.4", "clang-format": "^1.0.55", "gts": "^0.5.1", "typescript": "~2.7.0" diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 4d013fffe..862cd865e 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -24,6 +24,9 @@ const BACKOFF_MULTIPLIER = 1.6; const MAX_BACKOFF_MS = 120000; const BACKOFF_JITTER = 0.2; +const KEEPALIVE_TIME_MS = Number.MAX_VALUE; +const KEEPALIVE_TIMEOUT_MS = 20000; + const { HTTP2_HEADER_AUTHORITY, HTTP2_HEADER_CONTENT_TYPE, @@ -110,6 +113,12 @@ export class Http2Channel extends EventEmitter implements Channel { private currentBackoff: number = INITIAL_BACKOFF_MS; private currentBackoffDeadline: Date; + private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; + private keepaliveTimeoutMs: number = KEEPALIVE_TIMEOUT_MS; + private keepaliveIntervalId: NodeJS.Timer; + private keepaliveTimeoutId: NodeJS.Timer; + + private handleStateChange( oldState: ConnectivityState, newState: ConnectivityState): void { const now: Date = new Date(); @@ -134,6 +143,8 @@ export class Http2Channel extends EventEmitter implements Channel { break; case ConnectivityState.TRANSIENT_FAILURE: this.subChannel = null; + /* Stop keepalive pings when the subchannel disconnects */ + this.stopKeepalivePings(); this.backoffTimerId = setTimeout(() => { this.transitionToState( [ConnectivityState.TRANSIENT_FAILURE], @@ -150,6 +161,7 @@ export class Http2Channel extends EventEmitter implements Channel { this.subChannel = null; this.emit('shutdown'); clearTimeout(this.backoffTimerId); + this.stopKeepalivePings(); } break; default: @@ -221,6 +233,32 @@ export class Http2Channel extends EventEmitter implements Channel { subChannel.once('error', this.subChannelCloseCallback); } + private sendPing() { + this.keepaliveTimeoutId = setTimeout(() => { + this.transitionToState([ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE) + }, this.keepaliveTimeoutMs) + this.subChannel!.ping((err: Error | null, duration: number, payload: Buffer) => { + clearTimeout(this.keepaliveTimeoutId); + }); + } + + /* TODO(murgatroid99): refactor subchannels so that keepalives can be handled + * per subchannel */ + private startKeepalivePings() { + this.keepaliveIntervalId = setInterval(() => { + if (this.subChannel) { + this.sendPing(); + } + }, this.keepaliveTimeMs); + this.sendPing(); + } + + private stopKeepalivePings() { + clearInterval(this.keepaliveIntervalId); + clearTimeout(this.keepaliveTimeoutId); + } + constructor( address: string, readonly credentials: ChannelCredentials, private readonly options: Partial) { @@ -240,11 +278,21 @@ export class Http2Channel extends EventEmitter implements Channel { new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), new MetadataStatusFilterFactory(this), new CompressionFilterFactory(this) ]); + if (this.options['grpc.keepalive_time_ms']) { + this.keepaliveTimeMs = this.options['grpc.keepalive_time_ms'] as number; + } + if (this.options['grpc.keepalive_timeout_ms']) { + this.keepaliveTimeoutMs = this.options['grpc.keepalive_timeout_ms'] as number; + } this.currentBackoffDeadline = new Date(); /* The only purpose of these lines is to ensure that this.backoffTimerId has * a value of type NodeJS.Timer. */ this.backoffTimerId = setTimeout(() => {}, 0); clearTimeout(this.backoffTimerId); + this.keepaliveIntervalId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveIntervalId); + this.keepaliveTimeoutId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveTimeoutId); // Build user-agent string. this.userAgent = [ @@ -276,6 +324,11 @@ export class Http2Channel extends EventEmitter implements Channel { if (!session.streamCount) { session.streamCount = 0; } + if (session.streamCount == 0) { + /* Start keepalive pings when we start a stream on an empty + * session */ + this.startKeepalivePings(); + } session.streamCount += 1; http2Stream.on('close', () => { if (!session.streamCount) { @@ -284,6 +337,9 @@ export class Http2Channel extends EventEmitter implements Channel { session.streamCount -= 1; if (session.streamCount <= 0) { session.unref(); + /* Stop keepalive pings when we end the last stream on a + * session */ + this.stopKeepalivePings(); } }); stream.attachHttp2Stream(http2Stream); From 3d3b38163703d41c5c35ca71673899108a5d4539 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 31 Jul 2018 14:48:28 -0700 Subject: [PATCH 0324/1899] Bump grpc to 1.14.0-pre2 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 88e71c28a..b88e6c05b 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0-pre1"' + 'GRPC_NODE_VERSION="1.14.0-pre2"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 768e8ea89..d2867e4a2 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 768e8ea89c9d27ea05b86cd83b0bfd18643bce12 +Subproject commit d2867e4a24b2108e074fa36714caf4eca57399e7 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index cf581ea7a..5d2a82d5e 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0-pre1", + "version": "1.14.0-pre2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 8bbd4752d9aa59bb4012baf8a2b22c7cabf8ae1f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 1 Aug 2018 11:20:42 -0700 Subject: [PATCH 0325/1899] Make default keepalive time fit in a 32-bit integer --- packages/grpc-js-core/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 862cd865e..5fc3b916e 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -24,7 +24,7 @@ const BACKOFF_MULTIPLIER = 1.6; const MAX_BACKOFF_MS = 120000; const BACKOFF_JITTER = 0.2; -const KEEPALIVE_TIME_MS = Number.MAX_VALUE; +const KEEPALIVE_TIME_MS = 1 << 31; const KEEPALIVE_TIMEOUT_MS = 20000; const { From 500642b5ac50979a20276fc2fdf65d912d6d64f4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 3 Aug 2018 13:43:23 -0700 Subject: [PATCH 0326/1899] Create separate subchannel class, fix default keepalive time value --- packages/grpc-js-core/src/channel.ts | 103 ++---------------- packages/grpc-js-core/src/subchannel.ts | 134 ++++++++++++++++++++++++ 2 files changed, 143 insertions(+), 94 deletions(-) create mode 100644 packages/grpc-js-core/src/subchannel.ts diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 5fc3b916e..19ea2080f 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -13,6 +13,7 @@ import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; import {MetadataStatusFilterFactory} from './metadata-status-filter'; +import { Http2SubChannel } from './subchannel'; const {version: clientVersion} = require('../../package'); @@ -24,9 +25,6 @@ const BACKOFF_MULTIPLIER = 1.6; const MAX_BACKOFF_MS = 120000; const BACKOFF_JITTER = 0.2; -const KEEPALIVE_TIME_MS = 1 << 31; -const KEEPALIVE_TIMEOUT_MS = 20000; - const { HTTP2_HEADER_AUTHORITY, HTTP2_HEADER_CONTENT_TYPE, @@ -45,6 +43,8 @@ export interface ChannelOptions { 'grpc.primary_user_agent': string; 'grpc.secondary_user_agent': string; 'grpc.default_authority': string; + 'grpc.keealive_time_ms': number; + 'grpc.keepalive_timeout_ms': number; [key: string]: string|number; } @@ -85,15 +85,6 @@ export interface Channel extends EventEmitter { /* tslint:enable:no-any */ } -/* This should be a real subchannel class that contains a ClientHttp2Session, - * but for now this serves its purpose */ -type Http2SubChannel = http2.ClientHttp2Session&{ - /* Count the number of currently active streams associated with the session. - * The purpose of this is to keep the session reffed if and only if there - * is at least one active stream */ - streamCount?: number; -}; - export class Http2Channel extends EventEmitter implements Channel { private readonly userAgent: string; private readonly target: url.URL; @@ -113,12 +104,6 @@ export class Http2Channel extends EventEmitter implements Channel { private currentBackoff: number = INITIAL_BACKOFF_MS; private currentBackoffDeadline: Date; - private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; - private keepaliveTimeoutMs: number = KEEPALIVE_TIMEOUT_MS; - private keepaliveIntervalId: NodeJS.Timer; - private keepaliveTimeoutId: NodeJS.Timer; - - private handleStateChange( oldState: ConnectivityState, newState: ConnectivityState): void { const now: Date = new Date(); @@ -143,8 +128,6 @@ export class Http2Channel extends EventEmitter implements Channel { break; case ConnectivityState.TRANSIENT_FAILURE: this.subChannel = null; - /* Stop keepalive pings when the subchannel disconnects */ - this.stopKeepalivePings(); this.backoffTimerId = setTimeout(() => { this.transitionToState( [ConnectivityState.TRANSIENT_FAILURE], @@ -161,7 +144,6 @@ export class Http2Channel extends EventEmitter implements Channel { this.subChannel = null; this.emit('shutdown'); clearTimeout(this.backoffTimerId); - this.stopKeepalivePings(); } break; default: @@ -181,14 +163,10 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - let subChannel: Http2SubChannel; const secureContext = this.credentials.getSecureContext(); - if (secureContext === null) { - subChannel = http2.connect(this.target); - } else { - const connectionOptions: http2.SecureClientSessionOptions = { - secureContext, - }; + let connectionOptions: http2.SecureClientSessionOptions = {}; + if (secureContext !== null) { + connectionOptions.secureContext = secureContext; // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. // This option is used for testing only. @@ -201,8 +179,8 @@ export class Http2Channel extends EventEmitter implements Channel { }; connectionOptions.servername = sslTargetNameOverride; } - subChannel = http2.connect(this.target, connectionOptions); } + const subChannel: Http2SubChannel = new Http2SubChannel(this.target, connectionOptions, this.userAgent, this.options); this.subChannel = subChannel; const now = new Date(); const connectionTimeout: number = Math.max( @@ -230,33 +208,6 @@ export class Http2Channel extends EventEmitter implements Channel { ConnectivityState.TRANSIENT_FAILURE); }; subChannel.once('close', this.subChannelCloseCallback); - subChannel.once('error', this.subChannelCloseCallback); - } - - private sendPing() { - this.keepaliveTimeoutId = setTimeout(() => { - this.transitionToState([ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE) - }, this.keepaliveTimeoutMs) - this.subChannel!.ping((err: Error | null, duration: number, payload: Buffer) => { - clearTimeout(this.keepaliveTimeoutId); - }); - } - - /* TODO(murgatroid99): refactor subchannels so that keepalives can be handled - * per subchannel */ - private startKeepalivePings() { - this.keepaliveIntervalId = setInterval(() => { - if (this.subChannel) { - this.sendPing(); - } - }, this.keepaliveTimeMs); - this.sendPing(); - } - - private stopKeepalivePings() { - clearInterval(this.keepaliveIntervalId); - clearTimeout(this.keepaliveTimeoutId); } constructor( @@ -278,21 +229,10 @@ export class Http2Channel extends EventEmitter implements Channel { new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), new MetadataStatusFilterFactory(this), new CompressionFilterFactory(this) ]); - if (this.options['grpc.keepalive_time_ms']) { - this.keepaliveTimeMs = this.options['grpc.keepalive_time_ms'] as number; - } - if (this.options['grpc.keepalive_timeout_ms']) { - this.keepaliveTimeoutMs = this.options['grpc.keepalive_timeout_ms'] as number; - } this.currentBackoffDeadline = new Date(); /* The only purpose of these lines is to ensure that this.backoffTimerId has * a value of type NodeJS.Timer. */ this.backoffTimerId = setTimeout(() => {}, 0); - clearTimeout(this.backoffTimerId); - this.keepaliveIntervalId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveIntervalId); - this.keepaliveTimeoutId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveTimeoutId); // Build user-agent string. this.userAgent = [ @@ -316,33 +256,8 @@ export class Http2Channel extends EventEmitter implements Channel { headers[HTTP2_HEADER_PATH] = methodName; headers[HTTP2_HEADER_TE] = 'trailers'; if (this.connectivityState === ConnectivityState.READY) { - const session: Http2SubChannel = this.subChannel!; - let http2Stream = session.request(headers); - /* This is a very ad-hoc reference counting scheme. This should be - * handled by a subchannel class */ - session.ref(); - if (!session.streamCount) { - session.streamCount = 0; - } - if (session.streamCount == 0) { - /* Start keepalive pings when we start a stream on an empty - * session */ - this.startKeepalivePings(); - } - session.streamCount += 1; - http2Stream.on('close', () => { - if (!session.streamCount) { - session.streamCount = 0; - } - session.streamCount -= 1; - if (session.streamCount <= 0) { - session.unref(); - /* Stop keepalive pings when we end the last stream on a - * session */ - this.stopKeepalivePings(); - } - }); - stream.attachHttp2Stream(http2Stream); + const subChannel: Http2SubChannel = this.subChannel!; + subChannel.startCallStream(metadataValue, stream); } else { /* In this case, we lost the connection while finalizing * metadata. That should be very unusual */ diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts new file mode 100644 index 000000000..717d5d6ff --- /dev/null +++ b/packages/grpc-js-core/src/subchannel.ts @@ -0,0 +1,134 @@ +import * as http2 from 'http2'; +import * as url from 'url'; + +import { EventEmitter } from "events"; +import { Metadata } from "./metadata"; +import { CallStream, CallOptions, Http2CallStream } from "./call-stream"; +import { EmitterAugmentation1, EmitterAugmentation0 } from "./events"; +import { ChannelOptions } from './channel'; + +const { + HTTP2_HEADER_AUTHORITY, + HTTP2_HEADER_CONTENT_TYPE, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_HEADER_SCHEME, + HTTP2_HEADER_TE, + HTTP2_HEADER_USER_AGENT +} = http2.constants; + +/* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't + * have a constant for the max signed 32 bit integer, so this is a simple way + * to calculate it */ +const KEEPALIVE_TIME_MS = ~(1 << 31); +const KEEPALIVE_TIMEOUT_MS = 20000; + +export interface SubChannel extends EventEmitter { + /** + * Attach a call stream to this subchannel's connection to start it + * @param headers The headers to start the stream with + * @param callStream The stream to start + */ + startCallStream(metadata: Metadata, callStream: CallStream): void; + close(): void; +} + +export class Http2SubChannel extends EventEmitter implements SubChannel { + private session: http2.ClientHttp2Session; + private refCount: number = 0; + private userAgent: string; + + private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; + private keepaliveTimeoutMs: number = KEEPALIVE_TIMEOUT_MS; + private keepaliveIntervalId: NodeJS.Timer; + private keepaliveTimeoutId: NodeJS.Timer; + + constructor(target: url.URL, connectionOptions: http2.SecureClientSessionOptions, + userAgent: string, channelArgs: Partial) { + super(); + this.session = http2.connect(target, connectionOptions); + this.session.on('connect', () => { + this.emit('connect'); + }); + this.session.on('close', () => { + this.stopKeepalivePings(); + this.emit('close'); + }); + this.session.on('error', () => { + this.stopKeepalivePings(); + this.emit('close'); + }) + this.userAgent = userAgent; + + if (channelArgs['grpc.keepalive_time_ms']) { + this.keepaliveTimeMs = channelArgs['grpc.keepalive_time_ms'] as number; + } + if (channelArgs['grpc.keepalive_timeout_ms']) { + this.keepaliveTimeoutMs = channelArgs['grpc.keepalive_timeout_ms'] as number; + } + this.keepaliveIntervalId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveIntervalId); + this.keepaliveTimeoutId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveTimeoutId); + } + + private ref() { + if (this.refCount === 0) { + this.session.ref(); + this.startKeepalivePings(); + } + this.refCount += 1; + } + + private unref() { + this.refCount -= 1; + if (this.refCount === 0) { + this.session.unref(); + this.stopKeepalivePings(); + } + } + + private sendPing() { + this.keepaliveTimeoutId = setTimeout(() => { + this.emit('close'); + }, this.keepaliveTimeoutMs); + this.session.ping((err: Error | null, duration: number, payload: Buffer) => { + clearTimeout(this.keepaliveTimeoutId); + }); + } + + /* TODO(murgatroid99): refactor subchannels so that keepalives can be handled + * per subchannel */ + private startKeepalivePings() { + this.keepaliveIntervalId = setInterval(() => { + this.sendPing(); + }, this.keepaliveTimeMs); + this.sendPing(); + } + + private stopKeepalivePings() { + clearInterval(this.keepaliveIntervalId); + clearTimeout(this.keepaliveTimeoutId); + } + + // Prerequisite: this subchannel is connected + startCallStream(metadata: Metadata, callStream: Http2CallStream) { + const headers = metadata.toHttp2Headers(); + headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); + headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; + headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; + headers[HTTP2_HEADER_METHOD] = 'POST'; + headers[HTTP2_HEADER_PATH] = callStream.getMethod(); + headers[HTTP2_HEADER_TE] = 'trailers'; + let http2Stream = this.session.request(headers); + this.ref(); + http2Stream.on('close', () => { + this.unref(); + }); + callStream.attachHttp2Stream(http2Stream); + } + + close() { + this.session.close(); + } +} \ No newline at end of file From 2c0359f230aa2c4e78a4bea0c70fcd7d3d8a011a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 3 Aug 2018 14:28:40 -0700 Subject: [PATCH 0327/1899] Fix spelling error, make narrower cast in dereference --- packages/grpc-js-core/src/channel.ts | 2 +- packages/grpc-js-core/src/subchannel.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 19ea2080f..114dd9b25 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -43,7 +43,7 @@ export interface ChannelOptions { 'grpc.primary_user_agent': string; 'grpc.secondary_user_agent': string; 'grpc.default_authority': string; - 'grpc.keealive_time_ms': number; + 'grpc.keepalive_time_ms': number; 'grpc.keepalive_timeout_ms': number; [key: string]: string|number; } diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts index 717d5d6ff..c0487ab78 100644 --- a/packages/grpc-js-core/src/subchannel.ts +++ b/packages/grpc-js-core/src/subchannel.ts @@ -61,10 +61,10 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { this.userAgent = userAgent; if (channelArgs['grpc.keepalive_time_ms']) { - this.keepaliveTimeMs = channelArgs['grpc.keepalive_time_ms'] as number; + this.keepaliveTimeMs = channelArgs['grpc.keepalive_time_ms']!; } if (channelArgs['grpc.keepalive_timeout_ms']) { - this.keepaliveTimeoutMs = channelArgs['grpc.keepalive_timeout_ms'] as number; + this.keepaliveTimeoutMs = channelArgs['grpc.keepalive_timeout_ms']!; } this.keepaliveIntervalId = setTimeout(() => {}, 0); clearTimeout(this.keepaliveIntervalId); From 446d560fde6bf1a68db4c862e1ca5df46ffd5be6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 6 Aug 2018 10:58:07 -0700 Subject: [PATCH 0328/1899] Fix stream.write type incompatibility --- packages/grpc-js-core/src/call-stream.ts | 6 +++--- packages/grpc-js-core/src/object-stream.ts | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 9e362ffe1..1fbfb0233 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -7,7 +7,7 @@ import {EmitterAugmentation1} from './events'; import {Filter} from './filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; -import {ObjectDuplex} from './object-stream'; +import {ObjectDuplex, WriteCallback} from './object-stream'; const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = http2.constants; @@ -71,7 +71,7 @@ export class Http2CallStream extends Duplex implements CallStream { private http2Stream: http2.ClientHttp2Stream|null = null; private pendingRead = false; private pendingWrite: Buffer|null = null; - private pendingWriteCallback: Function|null = null; + private pendingWriteCallback: WriteCallback | null = null; private pendingFinalCallback: Function|null = null; private readState: ReadState = ReadState.NO_DATA; @@ -441,7 +441,7 @@ export class Http2CallStream extends Duplex implements CallStream { } } - _write(chunk: WriteObject, encoding: string, cb: Function) { + _write(chunk: WriteObject, encoding: string, cb: WriteCallback) { this.filterStack.sendMessage(Promise.resolve(chunk)).then((message) => { if (this.http2Stream === null) { this.pendingWrite = message.message; diff --git a/packages/grpc-js-core/src/object-stream.ts b/packages/grpc-js-core/src/object-stream.ts index 556883c67..dca37e79d 100644 --- a/packages/grpc-js-core/src/object-stream.ts +++ b/packages/grpc-js-core/src/object-stream.ts @@ -3,6 +3,8 @@ import {EmitterAugmentation1} from './events'; // tslint:disable:no-any +export type WriteCallback = (error: Error | null | undefined) => void; + export interface IntermediateObjectReadable extends Readable { read(size?: number): any&T; } @@ -13,8 +15,8 @@ export type ObjectReadable = { export interface IntermediateObjectWritable extends Writable { _write(chunk: any&T, encoding: string, callback: Function): void; - write(chunk: any&T, cb?: Function): boolean; - write(chunk: any&T, encoding?: any, cb?: Function): boolean; + write(chunk: any&T, cb?: WriteCallback): boolean; + write(chunk: any&T, encoding?: any, cb?: WriteCallback): boolean; setDefaultEncoding(encoding: string): this; end(): void; end(chunk: any&T, cb?: Function): void; From 264d8043fe8337579e971d432afb25fe5506ba07 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Aug 2018 14:29:43 -0700 Subject: [PATCH 0329/1899] Update package.json template to match package.json --- packages/grpc-native-core/templates/package.json.template | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 82d6d1076..d1f475b18 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -46,6 +46,7 @@ "istanbul": "^0.4.4", "lodash": "^4.17.4", "minimist": "^1.1.0", + "node-forge": "^0.7.5", "poisson-process": "^0.2.1" }, "engines": { From ac7c1bc2e5ed626f807ee32581328121feca49f6 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Mon, 12 Mar 2018 22:11:33 -0700 Subject: [PATCH 0330/1899] Add checkServerIdentity callback. --- .../ext/channel_credentials.cc | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index c334d5d03..d56780cf8 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -38,6 +38,8 @@ using Nan::ObjectWrap; using Nan::Persistent; using Nan::Utf8String; +using v8::Array; +using v8::Context; using v8::Exception; using v8::External; using v8::Function; @@ -58,6 +60,43 @@ ChannelCredentials::~ChannelCredentials() { grpc_channel_credentials_release(wrapped_credentials); } +struct callback_md { + Nan::Callback *callback; +}; + +static int verify_peer_callback_wrapper(const char* servername, const char* cert, void* userdata) { + Nan::HandleScope scope; + Nan::TryCatch try_catch; + struct callback_md* md = (struct callback_md*)userdata; + + const unsigned argc = 2; + Local argv[argc]; + if (servername == NULL) { + argv[0] = Nan::Null(); + } else { + argv[0] = Nan::New(servername).ToLocalChecked(); + } + if (cert == NULL) { + argv[1] = Nan::Null(); + } else { + argv[1] = Nan::New(cert).ToLocalChecked(); + } + + md->callback->Call(argc, argv); + + if (try_catch.HasCaught()) { + return 1; + } + + return 0; +} + +static void verify_peer_callback_destruct(void *userdata) { + callback_md *md = (callback_md*)userdata; + delete md->callback; + delete md; +} + void ChannelCredentials::Init(Local exports) { HandleScope scope; Local tpl = Nan::New(New); @@ -148,9 +187,42 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { "createSsl's second and third arguments must be" " provided or omitted together"); } + + verify_peer_options verify_options = {NULL, NULL, NULL}; + if (info.Length() >= 4 && info[3]->IsObject()) { + Local context = Nan::New(); + Local object = info[3]->ToObject(); + MaybeLocal maybe_props = object->GetOwnPropertyNames(context); + if (!maybe_props.IsEmpty()) { + Local props = maybe_props.ToLocalChecked(); + for(uint32_t i=0; i < props->Length(); i++) { + Local key = props->Get(i); + Local value = object->Get(key); + + if (key->IsString()) { + Nan::Utf8String keyStr(key->ToString()); + + if (strcmp("checkServerIdentity", (const char*)(*keyStr)) == 0) { + + if (!value->IsFunction()) { + return Nan::ThrowError("Value of checkServerIdentity must be a function."); + } + struct callback_md *md = new struct callback_md; + md->callback = new Callback(Local::Cast(value)); + verify_options.verify_peer_callback = verify_peer_callback_wrapper; + verify_options.verify_peer_callback_userdata = (void*)md; + verify_options.verify_peer_destruct = verify_peer_callback_destruct; + + } + } + // do stuff with key / value + } + } + } + grpc_channel_credentials *creds = grpc_ssl_credentials_create( root_certs.get(), private_key.isAssigned() ? &key_cert_pair : NULL, - NULL, NULL); + &verify_options, NULL); if (creds == NULL) { info.GetReturnValue().SetNull(); } else { From f368e5010260259a21cce9c6665dd71439cf6c25 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 14:59:26 -0700 Subject: [PATCH 0331/1899] Regenerate project files and add test covering checkServerIdentity callback. --- .../grpc-native-core/test/credentials_test.js | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index 58dddb508..b3f922fa9 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -260,6 +260,36 @@ describe('client credentials', function() { done(); }); }); + it('Verify callback receives correct arguments', function(done) { + var callback_host, callback_cert; + var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": function(host, cert) { + callback_host = host; + callback_cert = cert; + } + }); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ifError(err); + assert.equal(callback_host, 'foo.test.google.fr'); + assert.equal(callback_cert, pem_data); + done(); + }); + }); + it('Verify callback exception causes connection failure', function(done) { + var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": function(host, cert) { + throw "Verification callback exception"; + } + }); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ok(err, "Should have raised an error"); + done(); + }); + }); it('Should update metadata with SSL creds', function(done) { var metadataUpdater = function(service_url, callback) { var metadata = new grpc.Metadata(); From b6ad568c09e92c542be1f13686e6885ef61c3fdf Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 15:01:57 -0700 Subject: [PATCH 0332/1899] Add type assertion on createSsl's fourth argument. --- packages/grpc-native-core/ext/channel_credentials.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index d56780cf8..64e3df469 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -189,7 +189,11 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { } verify_peer_options verify_options = {NULL, NULL, NULL}; - if (info.Length() >= 4 && info[3]->IsObject()) { + if (!info[3]->IsUndefined()) { + if (!info[3]->IsObject()) { + return Nan::ThrowTypeError("createSsl's fourth argument must be an " + "object"); + } Local context = Nan::New(); Local object = info[3]->ToObject(); MaybeLocal maybe_props = object->GetOwnPropertyNames(context); From c70df88fc02e79881f45c3fab156f44e29da86ee Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 15:11:11 -0700 Subject: [PATCH 0333/1899] Simplify userdata being passed to checkServerIdentity callback. --- .../ext/channel_credentials.cc | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 64e3df469..5aaa19b85 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -60,14 +60,10 @@ ChannelCredentials::~ChannelCredentials() { grpc_channel_credentials_release(wrapped_credentials); } -struct callback_md { - Nan::Callback *callback; -}; - static int verify_peer_callback_wrapper(const char* servername, const char* cert, void* userdata) { Nan::HandleScope scope; Nan::TryCatch try_catch; - struct callback_md* md = (struct callback_md*)userdata; + Nan::Callback *callback = (Nan::Callback*)userdata; const unsigned argc = 2; Local argv[argc]; @@ -82,7 +78,7 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert argv[1] = Nan::New(cert).ToLocalChecked(); } - md->callback->Call(argc, argv); + callback->Call(argc, argv); if (try_catch.HasCaught()) { return 1; @@ -92,9 +88,8 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert } static void verify_peer_callback_destruct(void *userdata) { - callback_md *md = (callback_md*)userdata; - delete md->callback; - delete md; + Nan::Callback *callback = (Nan::Callback*)userdata; + delete callback; } void ChannelCredentials::Init(Local exports) { @@ -211,10 +206,9 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { if (!value->IsFunction()) { return Nan::ThrowError("Value of checkServerIdentity must be a function."); } - struct callback_md *md = new struct callback_md; - md->callback = new Callback(Local::Cast(value)); + Nan::Callback *callback = new Callback(Local::Cast(value)); verify_options.verify_peer_callback = verify_peer_callback_wrapper; - verify_options.verify_peer_callback_userdata = (void*)md; + verify_options.verify_peer_callback_userdata = (void*)callback; verify_options.verify_peer_destruct = verify_peer_callback_destruct; } From 03c5d98b1e8c0a7e525250f061a522555e114646 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 16:13:08 -0700 Subject: [PATCH 0334/1899] Simplify getting checkServerIdentity out of the fourth createSsl argument. Add some tests asserting type-checking behavior. --- .../ext/channel_credentials.cc | 36 ++++++------------- .../grpc-native-core/test/credentials_test.js | 19 ++++++++++ 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 5aaa19b85..434b6e9be 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -186,35 +186,21 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { verify_peer_options verify_options = {NULL, NULL, NULL}; if (!info[3]->IsUndefined()) { if (!info[3]->IsObject()) { - return Nan::ThrowTypeError("createSsl's fourth argument must be an " - "object"); + return Nan::ThrowTypeError("createSsl's fourth argument must be an object"); } - Local context = Nan::New(); Local object = info[3]->ToObject(); - MaybeLocal maybe_props = object->GetOwnPropertyNames(context); - if (!maybe_props.IsEmpty()) { - Local props = maybe_props.ToLocalChecked(); - for(uint32_t i=0; i < props->Length(); i++) { - Local key = props->Get(i); - Local value = object->Get(key); - if (key->IsString()) { - Nan::Utf8String keyStr(key->ToString()); - - if (strcmp("checkServerIdentity", (const char*)(*keyStr)) == 0) { - - if (!value->IsFunction()) { - return Nan::ThrowError("Value of checkServerIdentity must be a function."); - } - Nan::Callback *callback = new Callback(Local::Cast(value)); - verify_options.verify_peer_callback = verify_peer_callback_wrapper; - verify_options.verify_peer_callback_userdata = (void*)callback; - verify_options.verify_peer_destruct = verify_peer_callback_destruct; - - } - } - // do stuff with key / value + Local checkServerIdentityValue = Nan::Get(object, + Nan::New("checkServerIdentity").ToLocalChecked()).ToLocalChecked(); + if (!checkServerIdentityValue->IsUndefined()) { + if (!checkServerIdentityValue->IsFunction()) { + return Nan::ThrowTypeError("Value of checkServerIdentity must be a function."); } + Nan::Callback *callback = new Callback(Local::Cast( + checkServerIdentityValue)); + verify_options.verify_peer_callback = verify_peer_callback_wrapper; + verify_options.verify_peer_callback_userdata = (void*)callback; + verify_options.verify_peer_destruct = verify_peer_callback_destruct; } } diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index b3f922fa9..542f93f36 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -128,6 +128,25 @@ describe('channel credentials', function() { grpc.credentials.createSsl(null, null, pem_data); }); }); + it('works if the fourth argument is an empty object', function() { + var creds; + assert.doesNotThrow(function() { + creds = grpc.credentials.createSsl(ca_data, null, null, {}); + }); + assert.notEqual(creds, null); + }); + it('fails if the fourth argument is a non-object value', function() { + assert.throws(function() { + grpc.credentials.createSsl(ca_data, null, null, 'test'); + }, TypeError); + }); + it('fails if the checkServerIdentity is a non-function', function() { + assert.throws(function() { + grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": 'test' + }); + }, TypeError); + }); }); }); From a48629fa83baa9276095a0817b079642ebfe13e1 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Wed, 20 Jun 2018 18:14:38 -0700 Subject: [PATCH 0335/1899] Update credentials.js documentation for verify options and add verify options to typescript definition. --- packages/grpc-native-core/index.d.ts | 22 +++++++++++++++++++- packages/grpc-native-core/src/credentials.js | 15 ++++++++++++- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index a704694e7..50e02e405 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -794,6 +794,25 @@ declare module "grpc" { ERROR, } + /** + * A callback that will receive the expected hostname and presented peer + * certificate as parameters. The callback should throw an error to + * indicate that the presented certificate is considered invalid. + */ + export type CheckServerIdentityCallback = (hostname: string, cert: string) => void; + + /** + * Additional peer verification options that can be set when creating + * SSL credentials. + */ + export interface VerifyOptions: { + /** + * If set, this callback will be invoked after the usual hostname verification + * has been performed on the peer certificate. + */ + checkServerIdentity?: CheckServerIdentityCallback; + } + /** * Credentials module * @@ -828,9 +847,10 @@ declare module "grpc" { * @param rootCerts The root certificate data * @param privateKey The client certificate private key, if applicable * @param certChain The client certificate cert chain, if applicable + * @param verifyOptions Additional peer verification options, if desired * @return The SSL Credentials object */ - createSsl(rootCerts?: Buffer, privateKey?: Buffer, certChain?: Buffer): ChannelCredentials; + createSsl(rootCerts?: Buffer, privateKey?: Buffer, certChain?: Buffer, verifyOptions?: VerifyOptions): ChannelCredentials; /** * Create a gRPC credentials object from a metadata generation function. This diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index a23129668..1c461d369 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -78,7 +78,8 @@ var _ = require('lodash'); /** * Create an SSL Credentials object. If using a client-side certificate, both - * the second and third arguments must be passed. + * the second and third arguments must be passed. Additional peer verification + * options can be passed in the fourth argument as described below. * @memberof grpc.credentials * @alias grpc.credentials.createSsl * @kind function @@ -86,6 +87,18 @@ var _ = require('lodash'); * @param {Buffer=} private_key The client certificate private key, if * applicable * @param {Buffer=} cert_chain The client certificate cert chain, if applicable + * @param {Object} verify_options Additional peer verification options. Can + * be undefined, in which case default behavior is preserved. + * Supported options are: "checkServerIdentity": (servername, cert) => {} + * The callback passed to checkServerIdentity will be invoked when the + * channel is opened in order to provide an opportunity to perform + * additional verification of the peer certificate as passed to the + * callback in the second parameter. The expected hostname is passed as + * the first parameter. If the callback considers the peer certificate + * invalid it should throw an error which will cause the handshake to + * be terminated. Note that supplying this callback does not disable + * the usual hostname verification which will also be performed on the + * certificate before this callback is invoked. * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object */ exports.createSsl = ChannelCredentials.createSsl; From 1fd96966d754cabecbdff7ca6f3f3a81b949daf4 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 21 Jun 2018 14:59:32 -0700 Subject: [PATCH 0336/1899] Correct checkServerIdentity behavior to return a verification failure if an error is returned. Clean up documentation and add a test assertion on returned Error. --- .../grpc-native-core/ext/channel_credentials.cc | 8 +++++++- packages/grpc-native-core/index.d.ts | 7 ++++--- packages/grpc-native-core/src/credentials.js | 16 ++++------------ .../grpc-native-core/test/credentials_test.js | 13 +++++++++++++ 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 434b6e9be..6a2a1ddec 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -78,9 +78,15 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert argv[1] = Nan::New(cert).ToLocalChecked(); } - callback->Call(argc, argv); + Local result = callback->Call(argc, argv); + // Catch any exception and return with a distinct status code which indicates this if (try_catch.HasCaught()) { + return 2; + } + + // If the result is an error, return a failure + if (result->IsNativeError()) { return 1; } diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 50e02e405..bb3cd894e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -796,10 +796,11 @@ declare module "grpc" { /** * A callback that will receive the expected hostname and presented peer - * certificate as parameters. The callback should throw an error to - * indicate that the presented certificate is considered invalid. + * certificate as parameters. The callback should return an error to + * indicate that the presented certificate is considered invalid and + * otherwise returned undefined. */ - export type CheckServerIdentityCallback = (hostname: string, cert: string) => void; + export type CheckServerIdentityCallback = (hostname: string, cert: string) => Error | undefined; /** * Additional peer verification options that can be set when creating diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 1c461d369..0fde6185a 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -87,18 +87,10 @@ var _ = require('lodash'); * @param {Buffer=} private_key The client certificate private key, if * applicable * @param {Buffer=} cert_chain The client certificate cert chain, if applicable - * @param {Object} verify_options Additional peer verification options. Can - * be undefined, in which case default behavior is preserved. - * Supported options are: "checkServerIdentity": (servername, cert) => {} - * The callback passed to checkServerIdentity will be invoked when the - * channel is opened in order to provide an opportunity to perform - * additional verification of the peer certificate as passed to the - * callback in the second parameter. The expected hostname is passed as - * the first parameter. If the callback considers the peer certificate - * invalid it should throw an error which will cause the handshake to - * be terminated. Note that supplying this callback does not disable - * the usual hostname verification which will also be performed on the - * certificate before this callback is invoked. + * @param {Function} verify_options.checkServerIdentity Optional callback + * receiving the expected hostname and peer certificate for additional + * verification. The callback should return an Error if verification + * fails and otherwise return undefined. * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object */ exports.createSsl = ChannelCredentials.createSsl; diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index 542f93f36..f3fc082f7 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -309,6 +309,19 @@ describe('client credentials', function() { done(); }); }); + it('Verify callback returning an Error causes connection failure', function(done) { + var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { + "checkServerIdentity": function(host, cert) { + return new Error("Verification error"); + } + }); + var client = new Client('localhost:' + port, client_ssl_creds, + client_options); + client.unary({}, function(err, data) { + assert.ok(err, "Should have raised an error"); + done(); + }); + }); it('Should update metadata with SSL creds', function(done) { var metadataUpdater = function(service_url, callback) { var metadata = new grpc.Metadata(); From 0201c218a6299155b6f988a11a7a76235b40cd40 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 19 Jul 2018 12:29:57 -0700 Subject: [PATCH 0337/1899] Refactor checkServerIdentity callback to pass in cert as an object with raw DER buffer. --- packages/grpc-native-core/package.json | 1 + packages/grpc-native-core/src/credentials.js | 44 ++++++++++++++++++- .../grpc-native-core/test/credentials_test.js | 12 ++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 5d2a82d5e..3e1e647cc 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -44,6 +44,7 @@ "istanbul": "^0.4.4", "lodash": "^4.17.4", "minimist": "^1.1.0", + "node-forge": "^0.7.5", "poisson-process": "^0.2.1" }, "engines": { diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 0fde6185a..28b668b1d 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -76,6 +76,31 @@ var _ = require('lodash'); * @see https://github.com/google/google-auth-library-nodejs */ +const PEM_CERT_HEADER = "-----BEGIN CERTIFICATE-----"; +const PEM_CERT_FOOTER = "-----END CERTIFICATE-----"; + +function wrapCheckServerIdentityCallback(callback) { + return function(hostname, cert) { + // Parse cert from pem to a version that matches the tls.checkServerIdentity + // format. + // https://nodejs.org/api/tls.html#tls_tls_checkserveridentity_hostname_cert + + var pemHeaderIndex = cert.indexOf(PEM_CERT_HEADER); + if (pemHeaderIndex === -1) { + return new Error("Unable to parse certificate PEM."); + } + cert = cert.substring(pemHeaderIndex); + var pemFooterIndex = cert.indexOf(PEM_CERT_FOOTER); + if (pemFooterIndex === -1) { + return new Error("Unable to parse certificate PEM."); + } + cert = cert.substring(PEM_CERT_HEADER.length, pemFooterIndex); + var rawBuffer = new Buffer(cert.replace("\n", "").replace(" ", ""), "base64"); + + return callback(hostname, { raw: rawBuffer }); + } +} + /** * Create an SSL Credentials object. If using a client-side certificate, both * the second and third arguments must be passed. Additional peer verification @@ -93,7 +118,24 @@ var _ = require('lodash'); * fails and otherwise return undefined. * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object */ -exports.createSsl = ChannelCredentials.createSsl; +exports.createSsl = function(root_certs, private_key, cert_chain, verify_options) { + // The checkServerIdentity callback from gRPC core will receive the cert as a PEM. + // To better match the checkServerIdentity callback of Node, we wrap the callback + // to decode the PEM and populate a cert object. + if (verify_options && verify_options.checkServerIdentity) { + if (typeof verify_options.checkServerIdentity !== 'function') { + throw new TypeError("Value of checkServerIdentity must be a function."); + } + // Make a shallow clone of verify_options so our modification of the callback + // isn't reflected to the caller + var updated_verify_options = Object.assign({}, verify_options); + updated_verify_options.checkServerIdentity = wrapCheckServerIdentityCallback( + verify_options.checkServerIdentity); + arguments[3] = updated_verify_options; + } + return ChannelCredentials.createSsl.apply(this, arguments); +} + /** * @callback grpc.credentials~metadataCallback diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index f3fc082f7..74d3edc14 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -21,6 +21,7 @@ var assert = require('assert'); var fs = require('fs'); var path = require('path'); +var forge = require('node-forge'); var grpc = require('..'); @@ -292,7 +293,16 @@ describe('client credentials', function() { client.unary({}, function(err, data) { assert.ifError(err); assert.equal(callback_host, 'foo.test.google.fr'); - assert.equal(callback_cert, pem_data); + + // The roundabout forge APIs for converting PEM to a node DER Buffer + var expected_der = new Buffer(forge.asn1.toDer( + forge.pki.certificateToAsn1(forge.pki.certificateFromPem(pem_data))) + .getBytes(), 'binary'); + + // Assert the buffers are equal by converting them to hex strings + assert.equal(callback_cert.raw.toString('hex'), expected_der.toString('hex')); + // Documented behavior of callback cert is that raw should be its only property + assert.equal(Object.keys(callback_cert).length, 1); done(); }); }); From 51c97b559d86071381f6bc51feef022a82c799b3 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 19 Jul 2018 14:05:10 -0700 Subject: [PATCH 0338/1899] Update typescript to properly reflect the format of the certificate received by the checkServerIdentity callback. --- packages/grpc-native-core/index.d.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index bb3cd894e..4ffa5993d 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -794,13 +794,17 @@ declare module "grpc" { ERROR, } + export interface Certificate { + raw: Buffer; + } + /** * A callback that will receive the expected hostname and presented peer * certificate as parameters. The callback should return an error to * indicate that the presented certificate is considered invalid and * otherwise returned undefined. */ - export type CheckServerIdentityCallback = (hostname: string, cert: string) => Error | undefined; + export type CheckServerIdentityCallback = (hostname: string, cert: Certificate) => Error | undefined; /** * Additional peer verification options that can be set when creating From 5f77bcda1fbdf5edf4490b3713771a0b0a8ccb18 Mon Sep 17 00:00:00 2001 From: Ian Haken Date: Thu, 19 Jul 2018 14:06:51 -0700 Subject: [PATCH 0339/1899] Add some missing descriptions to typescript. --- packages/grpc-native-core/index.d.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 4ffa5993d..ac11056e8 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -794,7 +794,13 @@ declare module "grpc" { ERROR, } + /** + * A certificate as received by the checkServerIdentity callback. + */ export interface Certificate { + /** + * The raw certificate in DER form. + */ raw: Buffer; } From 5b57e43de54c4001a1b721a6d6b47875c15d7c50 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Aug 2018 14:29:43 -0700 Subject: [PATCH 0340/1899] Update package.json template to match package.json --- packages/grpc-native-core/templates/package.json.template | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index a6d580a88..77bcfd132 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -46,6 +46,7 @@ "istanbul": "^0.4.4", "lodash": "^4.17.4", "minimist": "^1.1.0", + "node-forge": "^0.7.5", "poisson-process": "^0.2.1" }, "engines": { From e24ea39cf3bc7ff84f2a2fc1002e265d1cf858ae Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 7 Aug 2018 11:02:35 -0700 Subject: [PATCH 0341/1899] Update to v1.14.0-pre3 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b88e6c05b..f706581a5 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0-pre2"' + 'GRPC_NODE_VERSION="1.14.0-pre3"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..99c3e8180 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.14.0-pre3 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index d2867e4a2..893776fe9 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit d2867e4a24b2108e074fa36714caf4eca57399e7 +Subproject commit 893776fe9caf97aea2a25bfeefd7e4c50a96fd54 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 3e1e647cc..dea0ac862 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0-pre2", + "version": "1.14.0-pre3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 65d2f86aa9d2d797d89e9ef2e8ee25058a337818 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 7 Aug 2018 13:27:15 -0700 Subject: [PATCH 0342/1899] Fix benchmark proto loading --- test/performance/benchmark_client.js | 4 ++-- test/performance/benchmark_server.js | 4 ++-- test/performance/worker.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/performance/benchmark_client.js b/test/performance/benchmark_client.js index 7da0003b6..5424c7424 100644 --- a/test/performance/benchmark_client.js +++ b/test/performance/benchmark_client.js @@ -39,12 +39,12 @@ var genericService = require('./generic_service'); var grpc = require('../any_grpc').client; var protoLoader = require('../../packages/grpc-protobufjs'); var protoPackage = protoLoader.loadSync( - 'src/proto/grpc/testing/services.proto', + 'src/proto/grpc/testing/benchmark_service.proto', {keepCase: true, defaults: true, enums: String, oneofs: true, - include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index 0cfa8506e..e41ca1562 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -33,12 +33,12 @@ var genericService = require('./generic_service'); var grpc = require('../any_grpc').server; var protoLoader = require('../../packages/grpc-protobufjs'); var protoPackage = protoLoader.loadSync( - 'src/proto/grpc/testing/services.proto', + 'src/proto/grpc/testing/benchmark_service.proto', {keepCase: true, defaults: true, enums: String, oneofs: true, - include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** diff --git a/test/performance/worker.js b/test/performance/worker.js index d138536f5..cd868ae10 100644 --- a/test/performance/worker.js +++ b/test/performance/worker.js @@ -24,12 +24,12 @@ var WorkerServiceImpl = require('./worker_service_impl'); var grpc = require('../any_grpc').server; var protoLoader = require('../../packages/grpc-protobufjs'); var protoPackage = protoLoader.loadSync( - 'src/proto/grpc/testing/services.proto', + 'src/proto/grpc/testing/worker_service.proto', {keepCase: true, defaults: true, enums: String, oneofs: true, - include: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; function runServer(port, benchmark_impl) { From 4e2decd6ac0d7d1c16d1de0d5403d14326873bd6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 7 Aug 2018 15:11:39 -0700 Subject: [PATCH 0343/1899] Add package feature comparison document --- PACKAGE-COMPARISON.md | 29 +++++++++++++++++++++++++++++ README.md | 8 +++++++- 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 PACKAGE-COMPARISON.md diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md new file mode 100644 index 000000000..355dc51f7 --- /dev/null +++ b/PACKAGE-COMPARISON.md @@ -0,0 +1,29 @@ +# Feature comparison of `grpc` and `@grpc/grpc-js` packages + +Feature | `grpc` | `@grpc/grpc-js` +--------|--------|---------- +Client | :heavy_check_mark: | :heavy_check_mark: +Server | :heavy_check_mark: | :x: +Unary RPCs | :heavy_check_mark: | :heavy_check_mark: +Streaming RPCs | :heavy_check_mark: | :heavy_check_mark: +Deadlines | :heavy_check_mark: | :heavy_check_mark: +Cancellation | :heavy_check_mark: | :heavy_check_mark: +Automatic Reconnection | :heavy_check_mark: | :heavy_check_mark: +Per-message Compression | :heavy_check_mark: | only for response messages +Channel State | :heavy_check_mark: | :heavy_check_mark: +JWT Access and Service Account Credentials | provided by the [Google Auth Library](https://www.npmjs.com/package/google-auth-library) | provided by the [Google Auth Library](https://www.npmjs.com/package/google-auth-library) +Interceptors | :heavy_check_mark: | :x: +Connection Keepalives | :heavy_check_mark: | :heavy_check_mark: +HTTP Connect Support | :heavy_check_mark: | :x: +Retries | :heavy_check_mark: | :x: +Stats/tracing/monitoring | :heavy_check_mark: | :x: +Load Balancing | :heavy_check_mark: | :x: + +In addition, all channel arguments defined in [this header file](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/grpc_types.h) are handled by the `grpc` library. Of those, the following are handled by the `@grpc/grpc-js` library: + + - `grpc.ssl_target_name_override` + - `grpc.primary_user_agent` + - `grpc.secondary_user_agent` + - `grpc.default_authority` + - `grpc.keepalive_time_ms` + - `grpc.keepalive_timeout_ms` \ No newline at end of file diff --git a/README.md b/README.md index 9bcebd569..a91641399 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,8 @@ ## Implementations +For a comparison of the features available in these two libraries, see [this document](https://github.com/grpc/grpc-node/tree/master/PACKGE-COMPARISON.md) + ### C-based Client and Server Directory: [`packages/grpc-native-core`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-native-core) (see here for installation information) @@ -15,9 +17,11 @@ This is the existing, feature-rich implementation of gRPC using a C++ addon. It Directory: [`packages/grpc-js-core`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core) +npm package: [@grpc/grpc-js](https://www.npmjs.com/package/@grpc/grpc-js) + **This library is currently incomplete and experimental, built on the [experimental http2 Node module](https://nodejs.org/api/http2.html).** -This library implements the core functionality of gRPC purely in JavaScript, without a C++ addon. It works on the latest version of Node.js (with the `--expose-http2` flag set) on all platforms that Node.js runs on. +This library implements the core functionality of gRPC purely in JavaScript, without a C++ addon. It works on the latest version of Node.js on all platforms that Node.js runs on. ## Other Packages @@ -25,6 +29,8 @@ This library implements the core functionality of gRPC purely in JavaScript, wit Directory: [`packages/grpc-protobufjs`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-protobufjs) +npm package: [@grpc/proto-loader](https://www.npmjs.com/package/@grpc/proto-loader) + This library loads `.proto` files into objects that can be passed to the gRPC libraries. ### gRPC Tools From ea0ceae15e766ca765f5de6b406a7e9992ff3b5d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 7 Aug 2018 15:20:20 -0700 Subject: [PATCH 0344/1899] Add table of important non-feature properties --- PACKAGE-COMPARISON.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 355dc51f7..d4203df54 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -19,6 +19,14 @@ Retries | :heavy_check_mark: | :x: Stats/tracing/monitoring | :heavy_check_mark: | :x: Load Balancing | :heavy_check_mark: | :x: +Other Properties | `grpc` | `@grpc/grpc-js` +-----------------|--------|---------------- +Binary Addon | :heavy_check_mark: | :x: +Supported Node Versions | >= 4 | ^8.11.2 or >=9.4 +Supported Electron Versions | All | >= 3 +Supported Platforms | Linux, Windows, MacOS | All +Supported Architectures | x86, x86-64, ARM | All + In addition, all channel arguments defined in [this header file](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/grpc_types.h) are handled by the `grpc` library. Of those, the following are handled by the `@grpc/grpc-js` library: - `grpc.ssl_target_name_override` From ea8f4266bff2da6e43610109557de77678494c62 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 8 Aug 2018 10:14:16 -0700 Subject: [PATCH 0345/1899] Resolve some comments --- PACKAGE-COMPARISON.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index d4203df54..3396eac1f 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -21,11 +21,11 @@ Load Balancing | :heavy_check_mark: | :x: Other Properties | `grpc` | `@grpc/grpc-js` -----------------|--------|---------------- -Binary Addon | :heavy_check_mark: | :x: +Pure JavaScript Code | :x: | :heavy_check_mark: Supported Node Versions | >= 4 | ^8.11.2 or >=9.4 Supported Electron Versions | All | >= 3 Supported Platforms | Linux, Windows, MacOS | All -Supported Architectures | x86, x86-64, ARM | All +Supported Architectures | x86, x86-64, ARM7+ | All In addition, all channel arguments defined in [this header file](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/grpc_types.h) are handled by the `grpc` library. Of those, the following are handled by the `@grpc/grpc-js` library: From 94d1b1264c128a96e8919bf6d160ea5a603de25b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 8 Aug 2018 11:39:51 -0700 Subject: [PATCH 0346/1899] Bump to v1.14.0-pre4 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index f706581a5..cd7aa238e 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0-pre3"' + 'GRPC_NODE_VERSION="1.14.0-pre4"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 99c3e8180..318f6198d 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.14.0-pre3 + node_version: 1.14.0-pre4 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 893776fe9..d8020cb6d 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 893776fe9caf97aea2a25bfeefd7e4c50a96fd54 +Subproject commit d8020cb6daa87f1a3bb3b0c299bc081c4a3de1e8 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index dea0ac862..48c007042 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0-pre3", + "version": "1.14.0-pre4", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 40e5bb4a73893d9fa82854de0089f03f05b83ba5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 Aug 2018 11:42:43 -0700 Subject: [PATCH 0347/1899] Fix typo in typescript definitions file --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index ac11056e8..afae1cdb6 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -816,7 +816,7 @@ declare module "grpc" { * Additional peer verification options that can be set when creating * SSL credentials. */ - export interface VerifyOptions: { + export interface VerifyOptions { /** * If set, this callback will be invoked after the usual hostname verification * has been performed on the peer certificate. From de9832889e5bbfd82bd0720ccb9a1d42357c957e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 Aug 2018 13:17:20 -0700 Subject: [PATCH 0348/1899] Make gulp setup idempotent --- packages/grpc-health-check/gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-health-check/gulpfile.js b/packages/grpc-health-check/gulpfile.js index 6fcd18049..09ac91156 100644 --- a/packages/grpc-health-check/gulpfile.js +++ b/packages/grpc-health-check/gulpfile.js @@ -36,7 +36,7 @@ gulp.task('clean.links', 'Delete npm links', () => { gulp.task('clean.all', 'Delete all code created by tasks', ['clean.links']); -gulp.task('install', 'Install health check dependencies', () => { +gulp.task('install', 'Install health check dependencies', ['clean.links'], () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); }); From 936c38d7e21a819a28d5469afe2e000e036a72bf Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 Aug 2018 15:47:37 -0700 Subject: [PATCH 0349/1899] Update to v1.14.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index cd7aa238e..2fa3ecbb6 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0-pre4"' + 'GRPC_NODE_VERSION="1.14.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 318f6198d..14c49ed90 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.14.0-pre4 + node_version: 1.14.0 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 48c007042..ebf06a7ae 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0-pre4", + "version": "1.14.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From db291906fa470117e0c660700d67243d170b96e6 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Sat, 11 Aug 2018 15:27:56 +0200 Subject: [PATCH 0350/1899] Fix potential segmentation fault. Described in #490. --- packages/grpc-native-core/ext/channel.cc | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index bd7a63927..825260e04 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -270,6 +270,10 @@ NAN_METHOD(Channel::GetTarget) { "getTarget can only be called on Channel objects"); } Channel *channel = ObjectWrap::Unwrap(info.This()); + if (channel->wrapped_channel == NULL) { + return Nan::ThrowError( + "Cannot call getTarget on a closed Channel"); + } info.GetReturnValue().Set( Nan::New(grpc_channel_get_target(channel->wrapped_channel)) .ToLocalChecked()); @@ -281,6 +285,10 @@ NAN_METHOD(Channel::GetConnectivityState) { "getConnectivityState can only be called on Channel objects"); } Channel *channel = ObjectWrap::Unwrap(info.This()); + if (channel->wrapped_channel == NULL) { + return Nan::ThrowError( + "Cannot call getConnectivityState on a closed Channel"); + } int try_to_connect = (int)info[0]->Equals(Nan::True()); info.GetReturnValue().Set(grpc_channel_check_connectivity_state( channel->wrapped_channel, try_to_connect)); @@ -303,12 +311,16 @@ NAN_METHOD(Channel::WatchConnectivityState) { return Nan::ThrowTypeError( "watchConnectivityState's third argument must be a callback"); } + Channel *channel = ObjectWrap::Unwrap(info.This()); + if (channel->wrapped_channel == NULL) { + return Nan::ThrowError( + "Cannot call watchConnectivityState on a closed Channel"); + } grpc_connectivity_state last_state = static_cast( Nan::To(info[0]).FromJust()); double deadline = Nan::To(info[1]).FromJust(); Local callback_func = info[2].As(); Nan::Callback *callback = new Callback(callback_func); - Channel *channel = ObjectWrap::Unwrap(info.This()); unique_ptr ops(new OpVec()); grpc_channel_watch_connectivity_state( channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline), From 6d520c522c6c0e4f6acd11609bf7dc60d13f5523 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Aug 2018 11:41:36 -0700 Subject: [PATCH 0351/1899] Propagate channel closed errors up through waitForReady The errors thrown by `Channel#getConnectivityState` and `Channel#watchConnectivityState` need to be passed to the callback for `Client#waitForReady`. --- packages/grpc-native-core/src/client.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 5c293b20c..3bf838c38 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -720,13 +720,23 @@ Client.prototype.waitForReady = function(deadline, callback) { callback(new Error('Failed to connect before the deadline')); return; } - var new_state = self.$channel.getConnectivityState(true); + var new_state; + try { + new_state = self.$channel.getConnectivityState(true); + } catch (e) { + callback(new Error('The channel has been closed')); + return; + } if (new_state === grpc.connectivityState.READY) { callback(); } else if (new_state === grpc.connectivityState.FATAL_FAILURE) { callback(new Error('Failed to connect to server')); } else { - self.$channel.watchConnectivityState(new_state, deadline, checkState); + try { + self.$channel.watchConnectivityState(new_state, deadline, checkState); + } catch (e) { + callback(new Error('The channel has been closed')); + } } }; /* Force a single round of polling to ensure that the channel state is up From 94f059ae2127802d962b1a01010473df5f3b8d75 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 13 Aug 2018 15:57:21 -0700 Subject: [PATCH 0352/1899] Add checkServerIdentity callback to pure js library --- .../grpc-js-core/src/channel-credentials.ts | 71 ++++++++++++++++--- packages/grpc-js-core/src/channel.ts | 8 +-- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 5a5c90373..07c1d2702 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -1,4 +1,4 @@ -import {createSecureContext, SecureContext} from 'tls'; +import {createSecureContext, SecureContext, TLSSocket, ConnectionOptions, PeerCertificate} from 'tls'; import {CallCredentials} from './call-credentials'; @@ -9,6 +9,36 @@ function verifyIsBufferOrNull(obj: any, friendlyName: string): void { } } +/** + * A certificate as received by the checkServerIdentity callback. + */ +export interface Certificate { + /** + * The raw certificate in DER form. + */ + raw: Buffer; +} + +/** + * A callback that will receive the expected hostname and presented peer + * certificate as parameters. The callback should return an error to + * indicate that the presented certificate is considered invalid and + * otherwise returned undefined. + */ +export type CheckServerIdentityCallback = (hostname: string, cert: Certificate) => Error | undefined; + +/** + * Additional peer verification options that can be set when creating + * SSL credentials. + */ +export interface VerifyOptions { + /** + * If set, this callback will be invoked after the usual hostname verification + * has been performed on the peer certificate. + */ + checkServerIdentity?: CheckServerIdentityCallback; +} + /** * A class that contains credentials for communicating over a channel, as well * as a set of per-call credentials, which are applied to every method call made @@ -40,7 +70,12 @@ export abstract class ChannelCredentials { * instance was created with createSsl, or null if this instance was created * with createInsecure. */ - abstract getSecureContext(): SecureContext|null; + abstract getConnectionOptions(): ConnectionOptions|null; + + /** + * Indicates whether this credentials object creates a secure channel. + */ + abstract isSecure(): boolean; /** * Return a new ChannelCredentials instance with a given set of credentials. @@ -52,7 +87,7 @@ export abstract class ChannelCredentials { */ static createSsl( rootCerts?: Buffer|null, privateKey?: Buffer|null, - certChain?: Buffer|null): ChannelCredentials { + certChain?: Buffer|null, verifyOptions?: VerifyOptions): ChannelCredentials { verifyIsBufferOrNull(rootCerts, 'Root certificate'); verifyIsBufferOrNull(privateKey, 'Private key'); verifyIsBufferOrNull(certChain, 'Certificate chain'); @@ -69,7 +104,15 @@ export abstract class ChannelCredentials { key: privateKey || undefined, cert: certChain || undefined }); - return new SecureChannelCredentialsImpl(secureContext); + let connectionOptions: ConnectionOptions = { + secureContext + }; + if (verifyOptions && verifyOptions.checkServerIdentity) { + connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate) => { + return verifyOptions.checkServerIdentity!(host, {raw: cert.raw}); + } + } + return new SecureChannelCredentialsImpl(connectionOptions); } /** @@ -89,27 +132,33 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { throw new Error('Cannot compose insecure credentials'); } - getSecureContext(): SecureContext|null { + getConnectionOptions(): ConnectionOptions|null { return null; } + isSecure(): boolean { + return false; + } } class SecureChannelCredentialsImpl extends ChannelCredentials { - secureContext: SecureContext; + connectionOptions: ConnectionOptions - constructor(secureContext: SecureContext, callCredentials?: CallCredentials) { + constructor(connectionOptions: ConnectionOptions, callCredentials?: CallCredentials) { super(callCredentials); - this.secureContext = secureContext; + this.connectionOptions = connectionOptions; } compose(callCredentials: CallCredentials): ChannelCredentials { const combinedCallCredentials = this.callCredentials.compose(callCredentials); return new SecureChannelCredentialsImpl( - this.secureContext, combinedCallCredentials); + this.connectionOptions, combinedCallCredentials); } - getSecureContext(): SecureContext|null { - return this.secureContext; + getConnectionOptions(): ConnectionOptions|null { + return this.connectionOptions; + } + isSecure(): boolean { + return true; } } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 114dd9b25..e0b1a2406 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -163,10 +163,8 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - const secureContext = this.credentials.getSecureContext(); - let connectionOptions: http2.SecureClientSessionOptions = {}; - if (secureContext !== null) { - connectionOptions.secureContext = secureContext; + let connectionOptions: http2.SecureClientSessionOptions = this.credentials.getConnectionOptions() || {}; + if (connectionOptions.secureContext !== null) { // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. // This option is used for testing only. @@ -214,7 +212,7 @@ export class Http2Channel extends EventEmitter implements Channel { address: string, readonly credentials: ChannelCredentials, private readonly options: Partial) { super(); - if (credentials.getSecureContext() === null) { + if (credentials.isSecure()) { this.target = new url.URL(`http://${address}`); } else { this.target = new url.URL(`https://${address}`); From ecb84dafb2ceccf08eca683ddeadedc47a6c322c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 13 Aug 2018 17:01:28 -0700 Subject: [PATCH 0353/1899] Fix switched condition in channel code --- packages/grpc-js-core/src/channel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index e0b1a2406..5c1b2d258 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -213,9 +213,9 @@ export class Http2Channel extends EventEmitter implements Channel { private readonly options: Partial) { super(); if (credentials.isSecure()) { - this.target = new url.URL(`http://${address}`); - } else { this.target = new url.URL(`https://${address}`); + } else { + this.target = new url.URL(`http://${address}`); } // TODO(murgatroid99): Add more centralized handling of channel options if (this.options['grpc.default_authority']) { From b4fda0a1537f80b867c41695b6c45b692f915480 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 13 Aug 2018 17:16:36 -0700 Subject: [PATCH 0354/1899] Fix channel credentials tests --- .../grpc-js-core/test/test-channel-credentials.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-core/test/test-channel-credentials.ts b/packages/grpc-js-core/test/test-channel-credentials.ts index aa9e20330..8dcd1c1f3 100644 --- a/packages/grpc-js-core/test/test-channel-credentials.ts +++ b/packages/grpc-js-core/test/test-channel-credentials.ts @@ -48,7 +48,7 @@ describe('ChannelCredentials Implementation', () => { () => { const creds = assert2.noThrowAndReturn( () => ChannelCredentials.createInsecure()); - assert.ok(!creds.getSecureContext()); + assert.ok(!creds.getConnectionOptions()); }); }); @@ -56,28 +56,28 @@ describe('ChannelCredentials Implementation', () => { it('should work when given no arguments', () => { const creds: ChannelCredentials = assert2.noThrowAndReturn(() => ChannelCredentials.createSsl()); - assert.ok(!!creds.getSecureContext()); + assert.ok(!!creds.getConnectionOptions()); }); it('should work with just a CA override', async () => { const {ca} = await pFixtures; const creds = assert2.noThrowAndReturn(() => ChannelCredentials.createSsl(ca)); - assert.ok(!!creds.getSecureContext()); + assert.ok(!!creds.getConnectionOptions()); }); it('should work with just a private key and cert chain', async () => { const {key, cert} = await pFixtures; const creds = assert2.noThrowAndReturn( () => ChannelCredentials.createSsl(null, key, cert)); - assert.ok(!!creds.getSecureContext()); + assert.ok(!!creds.getConnectionOptions()); }); - it('should work with all three parameters specified', async () => { + it('should work with three parameters specified', async () => { const {ca, key, cert} = await pFixtures; const creds = assert2.noThrowAndReturn( () => ChannelCredentials.createSsl(ca, key, cert)); - assert.ok(!!creds.getSecureContext()); + assert.ok(!!creds.getConnectionOptions()); }); it('should throw if just one of private key and cert chain are missing', From 7720d068ca8096099efe2ae8c6681892d9189220 Mon Sep 17 00:00:00 2001 From: Kelvin Jin Date: Tue, 14 Aug 2018 10:00:00 -0700 Subject: [PATCH 0355/1899] Add return type definition to watchConnectivityState --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index afae1cdb6..d47a4feb8 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1538,7 +1538,7 @@ declare module "grpc" { * @param callback Called with no error when a state change, or with an * error if the deadline passes without a state change. */ - watchConnectivityState(currentState: connectivityState, deadline: Date|number, callback: (error?: Error) => void); + watchConnectivityState(currentState: connectivityState, deadline: Date|number, callback: (error?: Error) => void): void; /** * Create a call object. Call is an opaque type that is used by the Client * and Server classes. This function is called by the gRPC library when From 29a24e08991a6a8377c58dd09905dcb93aaabfe5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 15 Aug 2018 11:11:14 -0700 Subject: [PATCH 0356/1899] Bump to version 1.14.1 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 2fa3ecbb6..fee7509d2 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0"' + 'GRPC_NODE_VERSION="1.14.1"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 14c49ed90..ce724c889 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.14.0 + node_version: 1.14.1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ebf06a7ae..6e74520fd 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0", + "version": "1.14.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 0b945cc89ff894dd3b1240cb37ffe981e7147c7e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 15 Aug 2018 13:27:39 -0700 Subject: [PATCH 0357/1899] Pure JS: add warnings for unhandled channel options --- packages/grpc-js-core/src/channel-options.ts | 25 ++++++++++++++++++++ packages/grpc-js-core/src/channel.ts | 21 +++++++--------- packages/grpc-js-core/src/client.ts | 3 ++- packages/grpc-js-core/src/make-client.ts | 2 +- packages/grpc-js-core/src/subchannel.ts | 2 +- 5 files changed, 37 insertions(+), 16 deletions(-) create mode 100644 packages/grpc-js-core/src/channel-options.ts diff --git a/packages/grpc-js-core/src/channel-options.ts b/packages/grpc-js-core/src/channel-options.ts new file mode 100644 index 000000000..434911662 --- /dev/null +++ b/packages/grpc-js-core/src/channel-options.ts @@ -0,0 +1,25 @@ +/** + * An interface that contains options used when initializing a Channel instance. + */ +export interface ChannelOptions { + 'grpc.ssl_target_name_override': string; + 'grpc.primary_user_agent': string; + 'grpc.secondary_user_agent': string; + 'grpc.default_authority': string; + 'grpc.keepalive_time_ms': number; + 'grpc.keepalive_timeout_ms': number; + [key: string]: string|number; +} + +/** + * This is for checking provided options at runtime. This is an object for + * easier membership checking. + */ +export const recognizedOptions = { + 'grpc.ssl_target_name_override': true, + 'grpc.primary_user_agent': true, + 'grpc.secondary_user_agent': true, + 'grpc.default_authority': true, + 'grpc.keepalive_time_ms': true, + 'grpc.keepalive_timeout_ms': true +}; diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 5c1b2d258..a27ef8f29 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -14,6 +14,7 @@ import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; import {MetadataStatusFilterFactory} from './metadata-status-filter'; import { Http2SubChannel } from './subchannel'; +import {ChannelOptions, recognizedOptions} from './channel-options'; const {version: clientVersion} = require('../../package'); @@ -35,19 +36,6 @@ const { HTTP2_HEADER_USER_AGENT } = http2.constants; -/** - * An interface that contains options used when initializing a Channel instance. - */ -export interface ChannelOptions { - 'grpc.ssl_target_name_override': string; - 'grpc.primary_user_agent': string; - 'grpc.secondary_user_agent': string; - 'grpc.default_authority': string; - 'grpc.keepalive_time_ms': number; - 'grpc.keepalive_timeout_ms': number; - [key: string]: string|number; -} - export enum ConnectivityState { CONNECTING, READY, @@ -212,6 +200,13 @@ export class Http2Channel extends EventEmitter implements Channel { address: string, readonly credentials: ChannelCredentials, private readonly options: Partial) { super(); + for (let option in options) { + if (options.hasOwnProperty(option)) { + if (!recognizedOptions.hasOwnProperty(option)) { + console.warn(`Unrecognized channel argument '${option}' will be ignored.`); + } + } + } if (credentials.isSecure()) { this.target = new url.URL(`https://${address}`); } else { diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 39ff9fd97..55f63f16d 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -3,10 +3,11 @@ import {URL} from 'url'; import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; import {CallOptions, CallStream, StatusObject, WriteObject} from './call-stream'; -import {Channel, ChannelOptions, Http2Channel} from './channel'; +import {Channel, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; import {Status} from './constants'; import {Metadata} from './metadata'; +import {ChannelOptions} from './channel-options'; // This symbol must be exported (for now). // See: https://github.com/Microsoft/TypeScript/issues/20080 diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index 98f338a2b..b3165ad8a 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -1,7 +1,7 @@ import * as _ from 'lodash'; import {CallOptions} from './call-stream'; -import {ChannelOptions} from './channel'; +import {ChannelOptions} from './channel-options'; import {ChannelCredentials} from './channel-credentials'; import {Client, UnaryCallback} from './client'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts index c0487ab78..bbce38c97 100644 --- a/packages/grpc-js-core/src/subchannel.ts +++ b/packages/grpc-js-core/src/subchannel.ts @@ -5,7 +5,7 @@ import { EventEmitter } from "events"; import { Metadata } from "./metadata"; import { CallStream, CallOptions, Http2CallStream } from "./call-stream"; import { EmitterAugmentation1, EmitterAugmentation0 } from "./events"; -import { ChannelOptions } from './channel'; +import { ChannelOptions } from './channel-options'; const { HTTP2_HEADER_AUTHORITY, From a703493efe10f3bf61f2d47df9918abe85b408f2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 16 Aug 2018 15:41:06 -0700 Subject: [PATCH 0358/1899] Fix some file includes in package.json --- packages/grpc-native-core/package.json | 3 ++- packages/grpc-native-core/templates/package.json.template | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6e74520fd..9a1142b12 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -67,7 +67,8 @@ "ext/*.{cc,h}", "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", - "deps/grpc/src/boringssl/*.{c,cc,h}", + "deps/grpc/src/boringssl/err_data.c", + "deps/grpc/src/cpp/ext/filters/census/grpc_context.cc", "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 77bcfd132..bd72b72a1 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -69,7 +69,8 @@ "ext/*.{cc,h}", "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", - "deps/grpc/src/boringssl/*.{c,cc,h}", + "deps/grpc/src/boringssl/err_data.c", + "deps/grpc/src/cpp/ext/filters/census/grpc_context.cc", "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", From 128610da3d242ba115f5704f516303f56c88f6f9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 17 Aug 2018 12:40:33 -0700 Subject: [PATCH 0359/1899] Update submodule to 1.15.0-dev --- packages/grpc-native-core/binding.gyp | 15 ++++++++++++--- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b52892ac4..b1947b9fd 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.0-dev"' + 'GRPC_NODE_VERSION="1.15.0-dev"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -815,10 +815,14 @@ 'deps/grpc/src/core/lib/security/credentials/jwt/json_token.cc', 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc', + 'deps/grpc/src/core/lib/security/credentials/local/local_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', 'deps/grpc/src/core/lib/security/security_connector/alts_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_fallback.cc', + 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc', + 'deps/grpc/src/core/lib/security/security_connector/local_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', @@ -870,6 +874,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', + 'deps/grpc/src/core/ext/filters/client_channel/client_channel_channelz.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc', 'deps/grpc/src/core/ext/filters/client_channel/connector.cc', @@ -891,6 +896,7 @@ 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', 'deps/grpc/src/core/tsi/alts_transport_security.cc', 'deps/grpc/src/core/tsi/fake_transport_security.cc', + 'deps/grpc/src/core/tsi/local_transport_security.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc', @@ -907,6 +913,8 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', @@ -914,12 +922,13 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_filter.cc', - 'deps/grpc/src/core/ext/filters/load_reporting/server_load_reporting_plugin.cc', 'deps/grpc/src/cpp/ext/filters/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 05628719f..8ba456362 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 05628719f1c8d21969ddb700df05b4c63982b66a +Subproject commit 8ba45636295019b101c1e9579423d4de41c4c59e diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6c510b1e3..b80b5c3b7 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.0-dev", + "version": "1.15.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 79d96a8e8789a761d017f400abb7d739b1c8bdef Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 17 Aug 2018 15:51:23 -0700 Subject: [PATCH 0360/1899] Remove forced version from local build.yaml --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 - packages/grpc-native-core/package.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 1020ad279..b1947b9fd 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.14.1"' + 'GRPC_NODE_VERSION="1.15.0-dev"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index ce724c889..49e36fdfe 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,2 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.14.1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9a1142b12..9cb0cdaaa 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.14.1", + "version": "1.15.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 89e47c84f791d48b0910b0f2d19299a9d5b28be3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 22 Aug 2018 16:52:24 -0700 Subject: [PATCH 0361/1899] Pure JS: Implement public Channel API --- PACKAGE-COMPARISON.md | 4 +- README.md | 2 +- packages/grpc-js-core/README.md | 9 ++ .../src/call-credentials-filter.ts | 4 +- packages/grpc-js-core/src/call-stream.ts | 24 +++- packages/grpc-js-core/src/call.ts | 22 +-- packages/grpc-js-core/src/channel.ts | 116 ++++++++++++---- packages/grpc-js-core/src/client.ts | 125 +++++++++++------- .../grpc-js-core/src/compression-filter.ts | 4 +- packages/grpc-js-core/src/deadline-filter.ts | 34 +++-- packages/grpc-js-core/src/filter-stack.ts | 4 +- packages/grpc-js-core/src/filter.ts | 4 +- packages/grpc-js-core/src/index.ts | 10 +- packages/grpc-js-core/src/make-client.ts | 2 +- .../src/metadata-status-filter.ts | 4 +- packages/grpc-js-core/src/subchannel.ts | 4 +- .../grpc-js-core/test/test-call-stream.ts | 28 ++-- 17 files changed, 265 insertions(+), 135 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 3396eac1f..2b32adaff 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -34,4 +34,6 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.secondary_user_agent` - `grpc.default_authority` - `grpc.keepalive_time_ms` - - `grpc.keepalive_timeout_ms` \ No newline at end of file + - `grpc.keepalive_timeout_ms` + - `channelOverride` + - `channelFactoryOverride` \ No newline at end of file diff --git a/README.md b/README.md index a91641399..dd9ce9726 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Implementations -For a comparison of the features available in these two libraries, see [this document](https://github.com/grpc/grpc-node/tree/master/PACKGE-COMPARISON.md) +For a comparison of the features available in these two libraries, see [this document](https://github.com/grpc/grpc-node/tree/master/PACKAGE-COMPARISON.md) ### C-based Client and Server diff --git a/packages/grpc-js-core/README.md b/packages/grpc-js-core/README.md index 9393ffc14..647121b82 100644 --- a/packages/grpc-js-core/README.md +++ b/packages/grpc-js-core/README.md @@ -18,5 +18,14 @@ npm install @grpc/grpc-js - TLS channel credentials - Call credentials (for auth) - Simple reconnection + - Channel API This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package. + +## Some Notes on API Guarantees + +The public API of this library follows semantic versioning, with some caveats: + + - Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API. + - The class `Call` is only exposed due to limitations of TypeScript. It should not be considered part of the public API. + - In general, any API that is exposed by this library but is not exposed by the `grpc` library is likely an error and should not be considered part of the public API. diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index f25d70bc6..66515fdda 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -1,7 +1,7 @@ import {promisify} from 'util'; import {CallCredentials} from './call-credentials'; -import {CallStream} from './call-stream'; +import {Call} from './call-stream'; import {Http2Channel} from './channel'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; @@ -41,7 +41,7 @@ export class CallCredentialsFilterFactory implements this.credentials = channel.credentials.getCallCredentials(); } - createFilter(callStream: CallStream): CallCredentialsFilter { + createFilter(callStream: Call): CallCredentialsFilter { return new CallCredentialsFilter( this.credentials.compose(callStream.getCredentials()), callStream.getHost(), callStream.getMethod()); diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 1fbfb0233..87b38c456 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -8,6 +8,8 @@ import {Filter} from './filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; import {ObjectDuplex, WriteCallback} from './object-stream'; +import { Meta } from 'orchestrator'; +import { Channel, Http2Channel } from './channel'; const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = http2.constants; @@ -16,12 +18,12 @@ export type Deadline = Date|number; export interface CallStreamOptions { deadline: Deadline; - credentials: CallCredentials; flags: number; host: string; + parentCall: Call | null; } -export type CallOptions = Partial; +export type PartialCallStreamOptions = Partial; export interface StatusObject { code: Status; @@ -43,11 +45,13 @@ export interface WriteObject { /** * This interface represents a duplex stream associated with a single gRPC call. */ -export type CallStream = { +export type Call = { cancelWithStatus(status: Status, details: string): void; getPeer(): string; + sendMetadata(metadata: Metadata): void; getDeadline(): Deadline; getCredentials(): CallCredentials; + setCredentials(credentials: CallCredentials): void; /* If the return value is null, the call has not ended yet. Otherwise, it has * ended with the specified status */ getStatus(): StatusObject | null; @@ -65,7 +69,8 @@ enum ReadState { const emptyBuffer = Buffer.alloc(0); -export class Http2CallStream extends Duplex implements CallStream { +export class Http2CallStream extends Duplex implements Call { + credentials: CallCredentials = CallCredentials.createEmpty(); filterStack: Filter; private statusEmitted = false; private http2Stream: http2.ClientHttp2Stream|null = null; @@ -103,6 +108,7 @@ export class Http2CallStream extends Duplex implements CallStream { constructor( private readonly methodName: string, + private readonly channel: Http2Channel, private readonly options: CallStreamOptions, filterStackFactory: FilterStackFactory) { super({objectMode: true}); @@ -377,6 +383,10 @@ export class Http2CallStream extends Duplex implements CallStream { } } + sendMetadata(metadata: Metadata): void { + this.channel._startHttp2Stream(this.options.host, this.methodName, this, metadata); + } + private destroyHttp2Stream() { // The http2 stream could already have been destroyed if cancelWithStatus // is called in response to an internal http2 error. @@ -402,7 +412,11 @@ export class Http2CallStream extends Duplex implements CallStream { } getCredentials(): CallCredentials { - return this.options.credentials; + return this.credentials; + } + + setCredentials(credentials: CallCredentials): void { + this.credentials = credentials; } getStatus(): StatusObject|null { diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index fc72d358b..9c864d8cd 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -2,7 +2,7 @@ import {EventEmitter} from 'events'; import * as _ from 'lodash'; import {Duplex, Readable, Writable} from 'stream'; -import {CallStream, StatusObject, WriteObject} from './call-stream'; +import {Call, StatusObject, WriteObject} from './call-stream'; import {Status} from './constants'; import {EmitterAugmentation1} from './events'; import {Metadata} from './metadata'; @@ -16,7 +16,7 @@ export type ServiceError = StatusObject&Error; /** * A base type for all user-facing values returned by client-side method calls. */ -export type Call = { +export type SurfaceCall = { cancel(): void; getPeer(): string; }&EmitterAugmentation1<'metadata', Metadata>& EmitterAugmentation1<'status', StatusObject>&EventEmitter; @@ -24,21 +24,21 @@ export type Call = { /** * A type representing the return value of a unary method call. */ -export type ClientUnaryCall = Call; +export type ClientUnaryCall = SurfaceCall; /** * A type representing the return value of a server stream method call. */ export type ClientReadableStream = { deserialize: (chunk: Buffer) => ResponseType; -}&Call&ObjectReadable; +}&SurfaceCall&ObjectReadable; /** * A type representing the return value of a client stream method call. */ export type ClientWritableStream = { serialize: (value: RequestType) => Buffer; -}&Call&ObjectWritable; +}&SurfaceCall&ObjectWritable; /** * A type representing the return value of a bidirectional stream method call. @@ -48,7 +48,7 @@ export type ClientDuplexStream = export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { - constructor(private readonly call: CallStream) { + constructor(private readonly call: Call) { super(); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); @@ -68,7 +68,7 @@ export class ClientUnaryCallImpl extends EventEmitter implements } function setUpReadableStream( - stream: ClientReadableStream, call: CallStream, + stream: ClientReadableStream, call: Call, deserialize: (chunk: Buffer) => ResponseType): void { call.on('data', (data: Buffer) => { let deserialized: ResponseType; @@ -101,7 +101,7 @@ function setUpReadableStream( export class ClientReadableStreamImpl extends Readable implements ClientReadableStream { constructor( - private readonly call: CallStream, + private readonly call: Call, readonly deserialize: (chunk: Buffer) => ResponseType) { super({objectMode: true}); call.on('metadata', (metadata: Metadata) => { @@ -124,7 +124,7 @@ export class ClientReadableStreamImpl extends Readable implements } function tryWrite( - call: CallStream, serialize: (value: RequestType) => Buffer, + call: Call, serialize: (value: RequestType) => Buffer, chunk: RequestType, encoding: string, cb: Function) { let message: Buffer; const flags: number = Number(encoding); @@ -145,7 +145,7 @@ function tryWrite( export class ClientWritableStreamImpl extends Writable implements ClientWritableStream { constructor( - private readonly call: CallStream, + private readonly call: Call, readonly serialize: (value: RequestType) => Buffer) { super({objectMode: true}); call.on('metadata', (metadata: Metadata) => { @@ -177,7 +177,7 @@ export class ClientWritableStreamImpl extends Writable implements export class ClientDuplexStreamImpl extends Duplex implements ClientDuplexStream { constructor( - private readonly call: CallStream, + private readonly call: Call, readonly serialize: (value: RequestType) => Buffer, readonly deserialize: (chunk: Buffer) => ResponseType) { super({objectMode: true}); diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index a27ef8f29..a14c56568 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -5,7 +5,7 @@ import * as url from 'url'; import {CallCredentials} from './call-credentials'; import {CallCredentialsFilterFactory} from './call-credentials-filter'; -import {CallOptions, CallStream, CallStreamOptions, Http2CallStream} from './call-stream'; +import {PartialCallStreamOptions, Call, CallStreamOptions, Http2CallStream, Deadline} from './call-stream'; import {ChannelCredentials} from './channel-credentials'; import {CompressionFilterFactory} from './compression-filter'; import {Status} from './constants'; @@ -55,22 +55,48 @@ function uniformRandom(min: number, max: number) { * An interface that represents a communication channel to a server specified * by a given address. */ -export interface Channel extends EventEmitter { - createStream(methodName: string, metadata: Metadata, options: CallOptions): - CallStream; - connect(): Promise; - getConnectivityState(): ConnectivityState; +export interface Channel { + /** + * Close the channel. This has the same functionality as the existing grpc.Client.prototype.close + */ close(): void; - - /* tslint:disable:no-any */ - addListener(event: string, listener: Function): this; - emit(event: string|symbol, ...args: any[]): boolean; - on(event: string, listener: Function): this; - once(event: string, listener: Function): this; - prependListener(event: string, listener: Function): this; - prependOnceListener(event: string, listener: Function): this; - removeListener(event: string, listener: Function): this; - /* tslint:enable:no-any */ + /** + * Return the target that this channel connects to + */ + getTarget(): string; + /** + * Get the channel's current connectivity state. This method is here mainly + * because it is in the existing internal Channel class, and there isn't + * another good place to put it. + * @param tryToConnect If true, the channel will start connecting if it is + * idle. Otherwise, idle channels will only start connecting when a + * call starts. + */ + getConnectivityState(tryToConnect: boolean): ConnectivityState; + /** + * Watch for connectivity state changes. This is also here mainly because + * it is in the existing external Channel class. + * @param currentState The state to watch for transitions from. This should + * always be populated by calling getConnectivityState immediately + * before. + * @param deadline A deadline for waiting for a state change + * @param callback Called with no error when a state change, or with an + * error if the deadline passes without a state change. + */ + watchConnectivityState(currentState: ConnectivityState, deadline: Date|number, callback: (error?: Error) => void): void; + /** + * Create a call object. Call is an opaque type that is used by the Client + * class. This function is called by the gRPC library when starting a + * request. Implementers should return an instance of Call that is returned + * from calling createCall on an instance of the provided Channel class. + * @param method The full method string to request. + * @param deadline The call deadline + * @param host A host string override for making the request + * @param parentCall A server call to propagate some information from + * @param propagateFlags A bitwise combination of elements of grpc.propagate + * that indicates what information to propagate from parentCall. + */ + createCall(method: string, deadline: Deadline|null|undefined, host: string|null|undefined, parentCall: Call|null|undefined, propagateFlags: number|null|undefined): Call; } export class Http2Channel extends EventEmitter implements Channel { @@ -234,7 +260,7 @@ export class Http2Channel extends EventEmitter implements Channel { ].filter(e => e).join(' '); // remove falsey values first } - private startHttp2Stream( + _startHttp2Stream( authority: string, methodName: string, stream: Http2CallStream, metadata: Metadata) { const finalMetadata: Promise = @@ -255,7 +281,7 @@ export class Http2Channel extends EventEmitter implements Channel { /* In this case, we lost the connection while finalizing * metadata. That should be very unusual */ setImmediate(() => { - this.startHttp2Stream(authority, methodName, stream, metadata); + this._startHttp2Stream(authority, methodName, stream, metadata); }); } }) @@ -268,20 +294,19 @@ export class Http2Channel extends EventEmitter implements Channel { }); } - createStream(methodName: string, metadata: Metadata, options: CallOptions): - CallStream { + createCall(method: string, deadline: Deadline|null|undefined, host: string|null|undefined, parentCall: Call|null|undefined, propagateFlags: number|null|undefined): + Call { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } const finalOptions: CallStreamOptions = { - deadline: options.deadline === undefined ? Infinity : options.deadline, - credentials: options.credentials || CallCredentials.createEmpty(), - flags: options.flags || 0, - host: options.host || this.defaultAuthority + deadline: (deadline === null || deadline == undefined) ? Infinity : deadline, + flags: propagateFlags || 0, + host: host || this.defaultAuthority, + parentCall: parentCall || null }; const stream: Http2CallStream = - new Http2CallStream(methodName, finalOptions, this.filterStackFactory); - this.startHttp2Stream(finalOptions.host, methodName, stream, metadata); + new Http2CallStream(method, this, finalOptions, this.filterStackFactory); return stream; } @@ -289,7 +314,7 @@ export class Http2Channel extends EventEmitter implements Channel { * Attempts to connect, returning a Promise that resolves when the connection * is successful, or rejects if the channel is shut down. */ - connect(): Promise { + private connect(): Promise { if (this.connectivityState === ConnectivityState.READY) { return Promise.resolve(); } else if (this.connectivityState === ConnectivityState.SHUTDOWN) { @@ -320,10 +345,45 @@ export class Http2Channel extends EventEmitter implements Channel { } } - getConnectivityState(): ConnectivityState { + getConnectivityState(tryToConnect: boolean): ConnectivityState { + if (tryToConnect) { + this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); + } return this.connectivityState; } + watchConnectivityState(currentState: ConnectivityState, deadline: Date|number, callback: (error?: Error)=>void) { + if (this.connectivityState !== currentState) { + /* If the connectivity state is different from the provided currentState, + * we assume that a state change has successfully occurred */ + setImmediate(callback); + } else { + let deadlineMs: number = 0; + if (deadline instanceof Date) { + deadlineMs = deadline.getTime(); + } else { + deadlineMs = deadline; + } + let timeout: number = deadlineMs - Date.now(); + if (timeout < 0) { + timeout = 0; + } + let timeoutId = setTimeout(() => { + this.removeListener('connectivityStateChanged', eventCb); + callback(new Error('Channel state did not change before deadline')); + }, timeout); + let eventCb = () => { + clearTimeout(timeoutId); + callback(); + }; + this.once('connectivityStateChanged', eventCb); + } + } + + getTarget() { + return this.target.toString(); + } + close() { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 55f63f16d..7bfc19bb8 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -2,12 +2,13 @@ import {once} from 'lodash'; import {URL} from 'url'; import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; -import {CallOptions, CallStream, StatusObject, WriteObject} from './call-stream'; -import {Channel, Http2Channel} from './channel'; +import {PartialCallStreamOptions, Call, StatusObject, WriteObject, Deadline} from './call-stream'; +import {Channel, Http2Channel, ConnectivityState} from './channel'; import {ChannelCredentials} from './channel-credentials'; import {Status} from './constants'; import {Metadata} from './metadata'; import {ChannelOptions} from './channel-options'; +import { CallCredentials } from './call-credentials'; // This symbol must be exported (for now). // See: https://github.com/Microsoft/TypeScript/issues/20080 @@ -17,6 +18,19 @@ export interface UnaryCallback { (err: ServiceError|null, value?: ResponseType): void; } +export interface CallOptions { + deadline?: Deadline, + host?: string, + parent?: Call, + propagate_flags?: number, + credentials?: CallCredentials +} + +export type ClientOptions = Partial & { + channelOverride?: Channel, + channelFactoryOverride?: (address: string, credentials: ChannelCredentials, options: ClientOptions) => Channel +}; + /** * A generic gRPC client. Primarily useful as a base class for all generated * clients. @@ -25,52 +39,53 @@ export class Client { private readonly[kChannel]: Channel; constructor( address: string, credentials: ChannelCredentials, - options: Partial = {}) { - this[kChannel] = new Http2Channel(address, credentials, options); + options: ClientOptions = {}) { + if (options.channelOverride) { + this[kChannel] = options.channelOverride; + } else if (options.channelFactoryOverride) { + this[kChannel] = options.channelFactoryOverride(address, credentials, options); + } else { + this[kChannel] = new Http2Channel(address, credentials, options); + } } close(): void { this[kChannel].close(); } - waitForReady(deadline: Date|number, callback: (error: Error|null) => void): - void { - const cb: (error: Error|null) => void = once(callback); - const callbackCalled = false; - let timer: NodeJS.Timer|null = null; - this[kChannel].connect().then( - () => { - if (timer) { - clearTimeout(timer); - } - cb(null); - }, - (err: Error) => { - // Rejection occurs if channel is shut down first. - if (timer) { - clearTimeout(timer); + getChannel(): Channel { + return this[kChannel]; + } + + waitForReady(deadline: Deadline, callback: (error?: Error) => void): + void { + const checkState = (err?: Error) => { + if (err) { + callback(new Error('Failed to connect before the deadline')); + return; + } + var new_state; + try { + new_state = this[kChannel].getConnectivityState(true); + } catch (e) { + callback(new Error('The channel has been closed')); + return; + } + if (new_state === ConnectivityState.READY) { + callback(); + } else { + try { + this[kChannel].watchConnectivityState(new_state, deadline, checkState); + } catch (e) { + callback(new Error('The channel has been closed')); } - cb(err); - }); - if (deadline !== Infinity) { - let timeout: number; - const now: number = (new Date()).getTime(); - if (deadline instanceof Date) { - timeout = deadline.getTime() - now; - } else { - timeout = deadline - now; - } - if (timeout < 0) { - timeout = 0; - } - timer = setTimeout(() => { - cb(new Error('Failed to connect before the deadline')); - }, timeout); - } + } + }; + setImmediate(checkState); } private handleUnaryResponse( - call: CallStream, deserialize: (value: Buffer) => ResponseType, + call: Call, deserialize: (value: Buffer) => ResponseType, callback: UnaryCallback): void { let responseMessage: ResponseType|null = null; call.on('data', (data: Buffer) => { @@ -157,11 +172,14 @@ export class Client { ({metadata, options, callback} = this.checkOptionalUnaryResponseArguments( metadata, options, callback)); - const call: CallStream = - this[kChannel].createStream(method, metadata, options); + const call: Call = + this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + if (options.credentials) { + call.setCredentials(options.credentials); + } const message: Buffer = serialize(argument); const writeObj: WriteObject = {message}; - writeObj.flags = options.flags; + call.sendMetadata(metadata); call.write(writeObj); call.end(); this.handleUnaryResponse(call, deserialize, callback); @@ -195,8 +213,12 @@ export class Client { ({metadata, options, callback} = this.checkOptionalUnaryResponseArguments( metadata, options, callback)); - const call: CallStream = - this[kChannel].createStream(method, metadata, options); + const call: Call = + this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + if (options.credentials) { + call.setCredentials(options.credentials); + } + call.sendMetadata(metadata); this.handleUnaryResponse(call, deserialize, callback); return new ClientWritableStreamImpl(call, serialize); } @@ -239,11 +261,14 @@ export class Client { metadata?: Metadata|CallOptions, options?: CallOptions): ClientReadableStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); - const call: CallStream = - this[kChannel].createStream(method, metadata, options); + const call: Call = + this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + if (options.credentials) { + call.setCredentials(options.credentials); + } const message: Buffer = serialize(argument); const writeObj: WriteObject = {message}; - writeObj.flags = options.flags; + call.sendMetadata(metadata); call.write(writeObj); call.end(); return new ClientReadableStreamImpl(call, deserialize); @@ -263,8 +288,12 @@ export class Client { metadata?: Metadata|CallOptions, options?: CallOptions): ClientDuplexStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); - const call: CallStream = - this[kChannel].createStream(method, metadata, options); + const call: Call = + this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + if (options.credentials) { + call.setCredentials(options.credentials); + } + call.sendMetadata(metadata); return new ClientDuplexStreamImpl( call, serialize, deserialize); } diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index dd607baeb..d694f239d 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -1,6 +1,6 @@ import * as zlib from 'zlib'; -import {CallStream, WriteFlags, WriteObject} from './call-stream'; +import {Call, WriteFlags, WriteObject} from './call-stream'; import {Channel} from './channel'; import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; @@ -189,7 +189,7 @@ export class CompressionFilter extends BaseFilter implements Filter { export class CompressionFilterFactory implements FilterFactory { constructor(private readonly channel: Channel) {} - createFilter(callStream: CallStream): CompressionFilter { + createFilter(callStream: Call): CompressionFilter { return new CompressionFilter(); } } diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index 2424039e0..0e2886089 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -1,5 +1,5 @@ -import {CallStream} from './call-stream'; -import {Channel, Http2Channel} from './channel'; +import {Call} from './call-stream'; +import {Channel, Http2Channel, ConnectivityState} from './channel'; import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; @@ -24,7 +24,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { private deadline: number; constructor( private readonly channel: Http2Channel, - private readonly callStream: CallStream) { + private readonly callStream: Call) { super(); const callDeadline = callStream.getDeadline(); if (callDeadline instanceof Date) { @@ -46,22 +46,34 @@ export class DeadlineFilter extends BaseFilter implements Filter { } } - async sendMetadata(metadata: Promise) { + sendMetadata(metadata: Promise) { if (this.deadline === Infinity) { - return await metadata; + return metadata; } - await this.channel.connect(); - const timeoutString = getDeadline(this.deadline); - const finalMetadata = await metadata; - finalMetadata.set('grpc-timeout', timeoutString); - return finalMetadata; + return new Promise((resolve, reject) => { + if (this.channel.getConnectivityState(false) === ConnectivityState.READY) { + resolve(metadata); + } else { + const handleStateChange = (newState: ConnectivityState) => { + if (newState === ConnectivityState.READY) { + resolve(metadata); + this.channel.removeListener('connectivityStateChanged', handleStateChange); + } + }; + this.channel.on('connectivityStateChanged', handleStateChange); + } + }).then((finalMetadata: Metadata) => { + const timeoutString = getDeadline(this.deadline); + finalMetadata.set('grpc-timeout', timeoutString); + return finalMetadata; + }); } } export class DeadlineFilterFactory implements FilterFactory { constructor(private readonly channel: Http2Channel) {} - createFilter(callStream: CallStream): DeadlineFilter { + createFilter(callStream: Call): DeadlineFilter { return new DeadlineFilter(this.channel, callStream); } } diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js-core/src/filter-stack.ts index 78e844865..360a5cfc5 100644 --- a/packages/grpc-js-core/src/filter-stack.ts +++ b/packages/grpc-js-core/src/filter-stack.ts @@ -1,6 +1,6 @@ import {flow, flowRight, map} from 'lodash'; -import {CallStream, StatusObject, WriteObject} from './call-stream'; +import {Call, StatusObject, WriteObject} from './call-stream'; import {Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; @@ -37,7 +37,7 @@ export class FilterStack implements Filter { export class FilterStackFactory implements FilterFactory { constructor(private readonly factories: Array>) {} - createFilter(callStream: CallStream): FilterStack { + createFilter(callStream: Call): FilterStack { return new FilterStack( map(this.factories, (factory) => factory.createFilter(callStream))); } diff --git a/packages/grpc-js-core/src/filter.ts b/packages/grpc-js-core/src/filter.ts index a2da1760d..28b05df88 100644 --- a/packages/grpc-js-core/src/filter.ts +++ b/packages/grpc-js-core/src/filter.ts @@ -1,4 +1,4 @@ -import {CallStream, StatusObject, WriteObject} from './call-stream'; +import {Call, StatusObject, WriteObject} from './call-stream'; import {Metadata} from './metadata'; /** @@ -40,5 +40,5 @@ export abstract class BaseFilter { } export interface FilterFactory { - createFilter(callStream: CallStream): T; + createFilter(callStream: Call): T; } diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 69e2b0c01..6372f22b3 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -7,6 +7,7 @@ import {Client} from './client'; import {Status} from './constants'; import {loadPackageDefinition, makeClientConstructor} from './make-client'; import {Metadata} from './metadata'; +import { Channel } from './channel'; interface IndexedObject { [key: string]: any; @@ -105,7 +106,8 @@ export { Client, loadPackageDefinition, makeClientConstructor, - makeClientConstructor as makeGenericClientConstructor + makeClientConstructor as makeGenericClientConstructor, + Channel }; /** @@ -116,7 +118,7 @@ export const closeClient = (client: Client) => client.close(); export const waitForClientReady = (client: Client, deadline: Date|number, - callback: (error: Error|null) => void) => + callback: (error?: Error) => void) => client.waitForReady(deadline, callback); /**** Unimplemented function stubs ****/ @@ -155,8 +157,8 @@ export const ServerCredentials = { } }; -export const getClientChannel = (client: any) => { - throw new Error('Not available in this library'); +export const getClientChannel = (client: Client) => { + return Client.prototype.getChannel.call(client); }; export const StatusBuilder = () => { diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index b3165ad8a..fff339f47 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -1,6 +1,6 @@ import * as _ from 'lodash'; -import {CallOptions} from './call-stream'; +import {PartialCallStreamOptions} from './call-stream'; import {ChannelOptions} from './channel-options'; import {ChannelCredentials} from './channel-credentials'; import {Client, UnaryCallback} from './client'; diff --git a/packages/grpc-js-core/src/metadata-status-filter.ts b/packages/grpc-js-core/src/metadata-status-filter.ts index 4bb869b7a..75eabea8b 100644 --- a/packages/grpc-js-core/src/metadata-status-filter.ts +++ b/packages/grpc-js-core/src/metadata-status-filter.ts @@ -1,4 +1,4 @@ -import {CallStream} from './call-stream'; +import {Call} from './call-stream'; import {StatusObject} from './call-stream'; import {Channel} from './channel'; import {Status} from './constants'; @@ -31,7 +31,7 @@ export class MetadataStatusFilter extends BaseFilter implements Filter { export class MetadataStatusFilterFactory implements FilterFactory { constructor(private readonly channel: Channel) {} - createFilter(callStream: CallStream): MetadataStatusFilter { + createFilter(callStream: Call): MetadataStatusFilter { return new MetadataStatusFilter(); } } diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts index bbce38c97..f793aebbf 100644 --- a/packages/grpc-js-core/src/subchannel.ts +++ b/packages/grpc-js-core/src/subchannel.ts @@ -3,7 +3,7 @@ import * as url from 'url'; import { EventEmitter } from "events"; import { Metadata } from "./metadata"; -import { CallStream, CallOptions, Http2CallStream } from "./call-stream"; +import { Call, PartialCallStreamOptions, Http2CallStream } from "./call-stream"; import { EmitterAugmentation1, EmitterAugmentation0 } from "./events"; import { ChannelOptions } from './channel-options'; @@ -29,7 +29,7 @@ export interface SubChannel extends EventEmitter { * @param headers The headers to start the stream with * @param callStream The stream to start */ - startCallStream(metadata: Metadata, callStream: CallStream): void; + startCallStream(metadata: Metadata, callStream: Call): void; close(): void; } diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index b188dbf40..902007fdc 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -6,7 +6,7 @@ import * as stream from 'stream'; import {CallCredentials} from '../src/call-credentials'; import {Http2CallStream} from '../src/call-stream'; -import {Channel} from '../src/channel'; +import {Channel, Http2Channel} from '../src/channel'; import {CompressionFilterFactory} from '../src/compression-filter'; import {Status} from '../src/constants'; import {FilterStackFactory} from '../src/filter-stack'; @@ -81,9 +81,9 @@ class ClientHttp2StreamMock extends stream.Duplex implements describe('CallStream', () => { const callStreamArgs = { deadline: Infinity, - credentials: CallCredentials.createEmpty(), flags: 0, - host: '' + host: '', + parentCall: null }; /* A CompressionFilter is now necessary to frame and deframe messages. * Currently the channel is unused, so we can replace it with an empty object, @@ -102,7 +102,7 @@ describe('CallStream', () => { const responseMetadata = new Metadata(); responseMetadata.add('key', 'value'); const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); @@ -140,7 +140,7 @@ describe('CallStream', () => { maybeSkip(it)(`for error code ${key}`, () => { return new Promise((resolve, reject) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); callStream.attachHttp2Stream(http2Stream); @@ -160,10 +160,12 @@ describe('CallStream', () => { it('should have functioning getters', (done) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); - assert.strictEqual(callStream.getCredentials(), callStreamArgs.credentials); assert.strictEqual(callStream.getStatus(), null); + const credentials = CallCredentials.createEmpty(); + callStream.setCredentials(credentials); + assert.strictEqual(callStream.getCredentials(), credentials); callStream.on('status', assert2.mustCall((status) => { assert.strictEqual(status.code, Status.CANCELLED); assert.strictEqual(status.details, ';)'); @@ -177,7 +179,7 @@ describe('CallStream', () => { describe('attachHttp2Stream', () => { it('should handle an empty message', (done) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({payload: serialize(''), frameLengths: []}); callStream.once('data', assert2.mustCall((buffer) => { @@ -204,7 +206,7 @@ describe('CallStream', () => { it(`should handle a short message where ${testCase.description}`, (done) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ payload: serialize(message), // 21 bytes frameLengths: testCase.frameLengths @@ -234,7 +236,7 @@ describe('CallStream', () => { }].forEach((testCase: {description: string, frameLengths: number[]}) => { it(`should handle two messages where ${testCase.description}`, (done) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.concat( [serialize(message), serialize(message)]), // 42 bytes @@ -254,7 +256,7 @@ describe('CallStream', () => { it('should send buffered writes', (done) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); let streamFlushed = false; @@ -277,7 +279,7 @@ describe('CallStream', () => { it('should cause data chunks in write calls afterward to be written to the given stream', (done) => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { @@ -295,7 +297,7 @@ describe('CallStream', () => { it('should handle underlying stream errors', () => { const callStream = - new Http2CallStream('foo', callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); callStream.once('status', assert2.mustCall((status) => { From 8d37d2321e8931d5150b5d1cc4a49e04aa82c78e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 23 Aug 2018 13:56:59 -0700 Subject: [PATCH 0362/1899] Mark some methods of ChannelCredentials as internal --- .../grpc-js-core/src/call-credentials-filter.ts | 2 +- packages/grpc-js-core/src/channel-credentials.ts | 14 +++++++------- packages/grpc-js-core/src/channel.ts | 4 ++-- .../grpc-js-core/test/test-channel-credentials.ts | 14 +++++++------- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index 66515fdda..c13df8693 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -38,7 +38,7 @@ export class CallCredentialsFilterFactory implements FilterFactory { private readonly credentials: CallCredentials; constructor(channel: Http2Channel) { - this.credentials = channel.credentials.getCallCredentials(); + this.credentials = channel.credentials._getCallCredentials(); } createFilter(callStream: Call): CallCredentialsFilter { diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 07c1d2702..cb29fa648 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -61,7 +61,7 @@ export abstract class ChannelCredentials { /** * Gets the set of per-call credentials associated with this instance. */ - getCallCredentials(): CallCredentials { + _getCallCredentials(): CallCredentials { return this.callCredentials; } @@ -70,12 +70,12 @@ export abstract class ChannelCredentials { * instance was created with createSsl, or null if this instance was created * with createInsecure. */ - abstract getConnectionOptions(): ConnectionOptions|null; + abstract _getConnectionOptions(): ConnectionOptions|null; /** * Indicates whether this credentials object creates a secure channel. */ - abstract isSecure(): boolean; + abstract _isSecure(): boolean; /** * Return a new ChannelCredentials instance with a given set of credentials. @@ -132,10 +132,10 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { throw new Error('Cannot compose insecure credentials'); } - getConnectionOptions(): ConnectionOptions|null { + _getConnectionOptions(): ConnectionOptions|null { return null; } - isSecure(): boolean { + _isSecure(): boolean { return false; } } @@ -155,10 +155,10 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { this.connectionOptions, combinedCallCredentials); } - getConnectionOptions(): ConnectionOptions|null { + _getConnectionOptions(): ConnectionOptions|null { return this.connectionOptions; } - isSecure(): boolean { + _isSecure(): boolean { return true; } } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index a14c56568..41b525625 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -177,7 +177,7 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - let connectionOptions: http2.SecureClientSessionOptions = this.credentials.getConnectionOptions() || {}; + let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; if (connectionOptions.secureContext !== null) { // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. @@ -233,7 +233,7 @@ export class Http2Channel extends EventEmitter implements Channel { } } } - if (credentials.isSecure()) { + if (credentials._isSecure()) { this.target = new url.URL(`https://${address}`); } else { this.target = new url.URL(`http://${address}`); diff --git a/packages/grpc-js-core/test/test-channel-credentials.ts b/packages/grpc-js-core/test/test-channel-credentials.ts index 8dcd1c1f3..f6914ef3e 100644 --- a/packages/grpc-js-core/test/test-channel-credentials.ts +++ b/packages/grpc-js-core/test/test-channel-credentials.ts @@ -48,7 +48,7 @@ describe('ChannelCredentials Implementation', () => { () => { const creds = assert2.noThrowAndReturn( () => ChannelCredentials.createInsecure()); - assert.ok(!creds.getConnectionOptions()); + assert.ok(!creds._getConnectionOptions()); }); }); @@ -56,28 +56,28 @@ describe('ChannelCredentials Implementation', () => { it('should work when given no arguments', () => { const creds: ChannelCredentials = assert2.noThrowAndReturn(() => ChannelCredentials.createSsl()); - assert.ok(!!creds.getConnectionOptions()); + assert.ok(!!creds._getConnectionOptions()); }); it('should work with just a CA override', async () => { const {ca} = await pFixtures; const creds = assert2.noThrowAndReturn(() => ChannelCredentials.createSsl(ca)); - assert.ok(!!creds.getConnectionOptions()); + assert.ok(!!creds._getConnectionOptions()); }); it('should work with just a private key and cert chain', async () => { const {key, cert} = await pFixtures; const creds = assert2.noThrowAndReturn( () => ChannelCredentials.createSsl(null, key, cert)); - assert.ok(!!creds.getConnectionOptions()); + assert.ok(!!creds._getConnectionOptions()); }); it('should work with three parameters specified', async () => { const {ca, key, cert} = await pFixtures; const creds = assert2.noThrowAndReturn( () => ChannelCredentials.createSsl(ca, key, cert)); - assert.ok(!!creds.getConnectionOptions()); + assert.ok(!!creds._getConnectionOptions()); }); it('should throw if just one of private key and cert chain are missing', @@ -97,7 +97,7 @@ describe('ChannelCredentials Implementation', () => { const channelCreds = ChannelCredentials.createSsl(); const callCreds = new CallCredentialsMock(); const composedChannelCreds = channelCreds.compose(callCreds); - assert.strictEqual(composedChannelCreds.getCallCredentials(), callCreds); + assert.strictEqual(composedChannelCreds._getCallCredentials(), callCreds); }); it('should be chainable', () => { @@ -110,7 +110,7 @@ describe('ChannelCredentials Implementation', () => { // Build a mock object that should be an identical copy const composedCallCreds = callCreds1.compose(callCreds2); assert.ok(composedCallCreds.isEqual( - composedChannelCreds.getCallCredentials() as CallCredentialsMock)); + composedChannelCreds._getCallCredentials() as CallCredentialsMock)); }); }); }); From 4edd52fcec27b323a18da68146a9079e6d7c24dc Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 24 Aug 2018 03:45:59 +0200 Subject: [PATCH 0363/1899] Ignoring automated test reports. --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 4dc6fc88b..231a29bd8 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,7 @@ yarn.lock \#*\# .\#* -packages/grpc-native-core/src/node/ \ No newline at end of file +packages/grpc-native-core/src/node/ + +.nyc_output/ +reports/ From 7528efbd320a691e883a0b5d51682de2a704837a Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 25 Aug 2018 11:31:23 -0400 Subject: [PATCH 0364/1899] grpc-js-core: remove use of deprecated Buffer() constructor The Buffer() constructor should not be used. This commit replaces its use in grpc-js-core tests with Buffer.from(). --- packages/grpc-js-core/test/test-metadata.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-core/test/test-metadata.ts b/packages/grpc-js-core/test/test-metadata.ts index 6e2275329..dd2d7c946 100644 --- a/packages/grpc-js-core/test/test-metadata.ts +++ b/packages/grpc-js-core/test/test-metadata.ts @@ -30,7 +30,7 @@ describe('Metadata', () => { describe('set', () => { it('Only accepts string values for non "-bin" keys', () => { assert.throws(() => { - metadata.set('key', new Buffer('value')); + metadata.set('key', Buffer.from('value')); }); assert.doesNotThrow(() => { metadata.set('key', 'value'); @@ -42,7 +42,7 @@ describe('Metadata', () => { metadata.set('key-bin', 'value'); }); assert.doesNotThrow(() => { - metadata.set('key-bin', new Buffer('value')); + metadata.set('key-bin', Buffer.from('value')); }); }); @@ -89,7 +89,7 @@ describe('Metadata', () => { describe('add', () => { it('Only accepts string values for non "-bin" keys', () => { assert.throws(() => { - metadata.add('key', new Buffer('value')); + metadata.add('key', Buffer.from('value')); }); assert.doesNotThrow(() => { metadata.add('key', 'value'); @@ -101,7 +101,7 @@ describe('Metadata', () => { metadata.add('key-bin', 'value'); }); assert.doesNotThrow(() => { - metadata.add('key-bin', new Buffer('value')); + metadata.add('key-bin', Buffer.from('value')); }); }); @@ -151,7 +151,7 @@ describe('Metadata', () => { beforeEach(() => { metadata.add('key', 'value1'); metadata.add('key', 'value2'); - metadata.add('key-bin', new Buffer('value')); + metadata.add('key-bin', Buffer.from('value')); }); it('gets all values associated with a key', () => { From 6573e70ad4360bb890b785d05cfe8c4a338465f0 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 26 Aug 2018 11:50:33 -0400 Subject: [PATCH 0365/1899] grpc-js-core: implement setLogger() and setLogVerbosity() These were missing from the pure JS implementation. This commit adds them. --- packages/grpc-js-core/src/constants.ts | 6 +++ packages/grpc-js-core/src/index.ts | 12 +++-- packages/grpc-js-core/src/logging.ts | 22 ++++++++ packages/grpc-js-core/test/test-logging.ts | 60 ++++++++++++++++++++++ 4 files changed, 95 insertions(+), 5 deletions(-) create mode 100644 packages/grpc-js-core/src/logging.ts create mode 100644 packages/grpc-js-core/test/test-logging.ts diff --git a/packages/grpc-js-core/src/constants.ts b/packages/grpc-js-core/src/constants.ts index a72f3388d..0a0142ec9 100644 --- a/packages/grpc-js-core/src/constants.ts +++ b/packages/grpc-js-core/src/constants.ts @@ -17,3 +17,9 @@ export enum Status { DATA_LOSS, UNAUTHENTICATED } + +export enum LogVerbosity { + DEBUG = 0, + INFO, + ERROR +} diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 6372f22b3..b285c6819 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -4,10 +4,11 @@ import {IncomingHttpHeaders} from 'http'; import {CallCredentials} from './call-credentials'; import {ChannelCredentials} from './channel-credentials'; import {Client} from './client'; -import {Status} from './constants'; +import {LogVerbosity, Status} from './constants'; import {loadPackageDefinition, makeClientConstructor} from './make-client'; import {Metadata} from './metadata'; import { Channel } from './channel'; +import * as logging from './logging'; interface IndexedObject { [key: string]: any; @@ -96,6 +97,7 @@ export {Metadata}; /**** Constants ****/ export { + LogVerbosity as logVerbosity, Status as status // TODO: Other constants as well }; @@ -135,12 +137,12 @@ export const load = (filename: any, format: any, options: any) => { 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); }; -export const setLogger = (logger: any) => { - throw new Error('Not yet implemented'); +export const setLogger = (logger: Partial): void => { + logging.setLogger(logger); }; -export const setLogVerbosity = (verbosity: any) => { - throw new Error('Not yet implemented'); +export const setLogVerbosity = (verbosity: LogVerbosity): void => { + logging.setLoggerVerbosity(verbosity); }; export const Server = (options: any) => { diff --git a/packages/grpc-js-core/src/logging.ts b/packages/grpc-js-core/src/logging.ts new file mode 100644 index 000000000..b5e151c4e --- /dev/null +++ b/packages/grpc-js-core/src/logging.ts @@ -0,0 +1,22 @@ +import {LogVerbosity} from './constants'; + +let _logger: Partial = console; +let _logVerbosity: LogVerbosity = LogVerbosity.DEBUG; + +export const getLogger = (): Partial => { + return _logger; +}; + +export const setLogger = (logger: Partial): void => { + _logger = logger; +}; + +export const setLoggerVerbosity = (verbosity: LogVerbosity): void => { + _logVerbosity = verbosity; +}; + +export const log = (severity: LogVerbosity, ...args: any[]): void => { + if (severity >= _logVerbosity && typeof _logger.error === 'function') { + _logger.error(...args); + } +}; diff --git a/packages/grpc-js-core/test/test-logging.ts b/packages/grpc-js-core/test/test-logging.ts new file mode 100644 index 000000000..c1c0c25b2 --- /dev/null +++ b/packages/grpc-js-core/test/test-logging.ts @@ -0,0 +1,60 @@ +import * as assert from 'assert'; + +import * as grpc from '../src'; +import * as logging from '../src/logging'; + +describe('Logging', () => { + afterEach(function() { + // Ensure that the logger is restored to its defaults after each test. + grpc.setLogger(console); + grpc.setLogVerbosity(grpc.logVerbosity.DEBUG); + }); + + it('logger defaults to console', () => { + assert.strictEqual(logging.getLogger(), console); + }); + + it('sets the logger to a new value', () => { + const logger: Partial = {}; + + logging.setLogger(logger); + assert.strictEqual(logging.getLogger(), logger); + }); + + it('gates logging based on severity', () => { + const output: any[] = []; + const logger: Partial = { + error(...args: any[]): void { + output.push(args); + } + }; + + logging.setLogger(logger); + + // The default verbosity (DEBUG) should log everything. + logging.log(grpc.logVerbosity.DEBUG, 'a', 'b', 'c'); + logging.log(grpc.logVerbosity.INFO, 'd', 'e'); + logging.log(grpc.logVerbosity.ERROR, 'f'); + + // The INFO verbosity should not log DEBUG data. + logging.setLoggerVerbosity(grpc.logVerbosity.INFO); + logging.log(grpc.logVerbosity.DEBUG, 1, 2, 3); + logging.log(grpc.logVerbosity.INFO, 'g'); + logging.log(grpc.logVerbosity.ERROR, 'h', 'i'); + + // The ERROR verbosity should not log DEBUG or INFO data. + logging.setLoggerVerbosity(grpc.logVerbosity.ERROR); + logging.log(grpc.logVerbosity.DEBUG, 4, 5, 6); + logging.log(grpc.logVerbosity.INFO, 7, 8); + logging.log(grpc.logVerbosity.ERROR, 'j', 'k'); + + assert.deepStrictEqual(output, [ + ['a', 'b', 'c'], + ['d', 'e'], + ['f'], + ['g'], + ['h', 'i'], + ['j', 'k'] + ]); + }); +}); From 797bcbaffe4ac392798ab25dfc7585dc0c0ce6ad Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 25 Aug 2018 11:42:02 -0400 Subject: [PATCH 0366/1899] grpc-js-core: simplify regular expression usage This commit moves two regular expressions out of the functions they are used in, and defines them as constants. This commit also switches from match() to test(), as a Boolean result is all that's needed. --- packages/grpc-js-core/src/metadata.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 40e6985bb..de41f02fc 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -1,5 +1,7 @@ import * as http2 from 'http2'; import {forOwn} from 'lodash'; +const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; +const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; export type MetadataValue = string|Buffer; @@ -24,11 +26,11 @@ function cloneMetadataObject(repr: MetadataObject): MetadataObject { } function isLegalKey(key: string): boolean { - return !!key.match(/^[0-9a-z_.-]+$/); + return LEGAL_KEY_REGEX.test(key); } function isLegalNonBinaryValue(value: string): boolean { - return !!value.match(/^[ -~]*$/); + return LEGAL_NON_BINARY_VALUE_REGEX.test(value); } function isBinaryKey(key: string): boolean { From b64ed1c18e5550c5d0dfa01129d68e8c397204f4 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 25 Aug 2018 12:02:15 -0400 Subject: [PATCH 0367/1899] grpc-js-core: add missing space in error message This commit adds a missing space to an error message and updates a test to prevent regressions. --- packages/grpc-js-core/src/metadata.ts | 2 +- packages/grpc-js-core/test/test-metadata.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index de41f02fc..71fe5e09a 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -43,7 +43,7 @@ function normalizeKey(key: string): string { function validate(key: string, value?: MetadataValue): void { if (!isLegalKey(key)) { - throw new Error('Metadata key"' + key + '" contains illegal characters'); + throw new Error('Metadata key "' + key + '" contains illegal characters'); } if (value != null) { if (isBinaryKey(key)) { diff --git a/packages/grpc-js-core/test/test-metadata.ts b/packages/grpc-js-core/test/test-metadata.ts index dd2d7c946..4dff735d8 100644 --- a/packages/grpc-js-core/test/test-metadata.ts +++ b/packages/grpc-js-core/test/test-metadata.ts @@ -52,7 +52,7 @@ describe('Metadata', () => { }); assert.throws(() => { metadata.set('key$', 'value'); - }); + }, /Error: Metadata key "key\$" contains illegal characters/); assert.throws(() => { metadata.set('', 'value'); }); From 2c75b640718d69eef02b857a9eb60d02dcd96ad3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 25 Aug 2018 12:23:08 -0400 Subject: [PATCH 0368/1899] grpc-js-core: remove extra map() calls in fromHttp2Headers() The extra map() calls added an extra loop over the arrays just to trim() a string. This commit moves the trim() into the forEach() and drops the map(). --- packages/grpc-js-core/src/metadata.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 71fe5e09a..e53b18a99 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -205,9 +205,9 @@ export class Metadata { result.add(key, Buffer.from(value, 'base64')); }); } else if (values !== undefined) { - values.split(',') - .map(v => v.trim()) - .forEach(v => result.add(key, Buffer.from(v, 'base64'))); + values.split(',').forEach(v => { + result.add(key, Buffer.from(v.trim(), 'base64')); + }); } } else { if (Array.isArray(values)) { @@ -215,7 +215,7 @@ export class Metadata { result.add(key, value); }); } else if (values !== undefined) { - values.split(',').map(v => v.trim()).forEach(v => result.add(key, v)); + values.split(',').forEach(v => result.add(key, v.trim())); } } }); From dda0d056421ec8c671133b69ab2a257fa0e2efcc Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 29 Aug 2018 01:45:51 +0200 Subject: [PATCH 0369/1899] Updating submodule to the upstream 1.15 branch. --- packages/grpc-native-core/binding.gyp | 4 ++-- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b1947b9fd..4b2791f51 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.15.0-dev"' + 'GRPC_NODE_VERSION="1.15.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -929,7 +929,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'deps/grpc/src/cpp/ext/filters/census/grpc_context.cc', + 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 8ba456362..1e80f2a4b 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 8ba45636295019b101c1e9579423d4de41c4c59e +Subproject commit 1e80f2a4b1ca41e77814306d4f0cf09d45641640 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9cb0cdaaa..d966465c5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.15.0-dev", + "version": "1.15.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 32c435a180a1373376bf81fe98b77c18311fa065 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 30 Aug 2018 11:07:14 -0700 Subject: [PATCH 0370/1899] Add some tests for error cases for both clients --- test/api/error_test.js | 529 +++++++++++++++++++++++++++++++++ test/proto/echo_service.proto | 34 +++ test/proto/test_messages.proto | 45 +++ test/proto/test_service.proto | 38 +++ 4 files changed, 646 insertions(+) create mode 100644 test/api/error_test.js create mode 100644 test/proto/echo_service.proto create mode 100644 test/proto/test_messages.proto create mode 100644 test/proto/test_service.proto diff --git a/test/api/error_test.js b/test/api/error_test.js new file mode 100644 index 000000000..9b5ff5e3f --- /dev/null +++ b/test/api/error_test.js @@ -0,0 +1,529 @@ +const options = { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +}; +const assert = require('assert'); +const _ = require('lodash'); +const anyGrpc = require('../any_grpc'); +const clientGrpc = anyGrpc.client; +const serverGrpc = anyGrpc.server; +const protoLoader = require('../../packages/grpc-protobufjs', options); +const testServiceDef = protoLoader.loadSync(__dirname + '/../proto/test_service.proto'); +const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestService; +const clientInsecureCreds = clientGrpc.credentials.createInsecure(); +const serverInsecureCreds = serverGrpc.ServerCredentials.createInsecure(); + +describe('Client malformed response handling', function() { + var server; + var client; + var badArg = Buffer.from([0xFF]); + before(function() { + var malformed_test_service = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: _.identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: _.identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: _.identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: _.identity + } + }; + server = new serverGrpc.Server(); + server.addService(malformed_test_service, { + unary: function(call, cb) { + cb(null, badArg); + }, + clientStream: function(stream, cb) { + stream.on('data', function() {/* Ignore requests */}); + stream.on('end', function() { + cb(null, badArg); + }); + }, + serverStream: function(stream) { + stream.write(badArg); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write(badArg); + }); + stream.on('end', function() { + stream.end(); + }); + } + }); + var port = server.bind('localhost:0', serverInsecureCreds); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + it('should get an INTERNAL status with a server stream call', function(done) { + var call = client.serverStream({}); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a bidi stream call', function(done) { + var call = client.bidiStream(); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + }); + describe('Server serialization failure handling', function() { + function serializeFail(obj) { + throw new Error('Serialization failed'); + } + var client; + var server; + before(function() { + var malformed_test_service = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + } + }; + server = new serverGrpc.Server(); + server.addService(malformed_test_service, { + unary: function(call, cb) { + cb(null, {}); + }, + clientStream: function(stream, cb) { + stream.on('data', function() {/* Ignore requests */}); + stream.on('end', function() { + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.write({}); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write({}); + }); + stream.on('end', function() { + stream.end(); + }); + } + }); + var port = server.bind('localhost:0', serverInsecureCreds); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + it('should get an INTERNAL status with a server stream call', function(done) { + var call = client.serverStream({}); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should get an INTERNAL status with a bidi stream call', function(done) { + var call = client.bidiStream(); + call.on('data', function(){}); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write({}); + call.end(); + }); + }); + describe('Other conditions', function() { + var Client; + var client; + var server; + var port; + before(function() { + server = new serverGrpc.Server(); + var trailer_metadata = new serverGrpc.Metadata(); + trailer_metadata.add('trailer-present', 'yes'); + server.addService(TestServiceClient.service, { + unary: function(call, cb) { + var req = call.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + cb({code: serverGrpc.status.UNKNOWN, + details: message}, null, trailer_metadata); + } else { + cb(null, {count: 1}, trailer_metadata); + } + }, + clientStream: function(stream, cb){ + var count = 0; + var errored; + stream.on('data', function(data) { + if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + errored = true; + cb(new Error(message), null, trailer_metadata); + } else { + count += 1; + } + }); + stream.on('end', function() { + if (!errored) { + cb(null, {count: count}, trailer_metadata); + } + }); + }, + serverStream: function(stream) { + var req = stream.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + var err = {code: serverGrpc.status.UNKNOWN, + details: message}; + err.metadata = trailer_metadata; + stream.emit('error', err); + } else { + for (var i = 0; i < 5; i++) { + stream.write({count: i}); + } + stream.end(trailer_metadata); + } + }, + bidiStream: function(stream) { + var count = 0; + stream.on('data', function(data) { + if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + var err = new Error(message); + err.metadata = trailer_metadata.clone(); + err.metadata.add('count', '' + count); + stream.emit('error', err); + } else { + stream.write({count: count}); + count += 1; + } + }); + stream.on('end', function() { + stream.end(trailer_metadata); + }); + } + }); + port = server.bind('localhost:0', serverInsecureCreds); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + }); + after(function() { + server.forceShutdown(); + }); + describe('Server recieving bad input', function() { + var misbehavingClient; + var badArg = new Buffer([0xFF]); + before(function() { + var test_service_attrs = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + } + }; + var Client = clientGrpc.makeGenericClientConstructor(test_service_attrs, + 'TestService'); + misbehavingClient = new Client('localhost:' + port, clientInsecureCreds); + }); + it('should respond correctly to a unary call', function(done) { + misbehavingClient.unary(badArg, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should respond correctly to a client stream', function(done) { + var call = misbehavingClient.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); + }); + it('should respond correctly to a server stream', function(done) { + var call = misbehavingClient.serverStream(badArg); + call.on('data', function(data) { + assert.fail(data, null, 'Unexpected data', '==='); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should respond correctly to a bidi stream', function(done) { + var call = misbehavingClient.bidiStream(); + call.on('data', function(data) { + assert.fail(data, null, 'Unexpected data', '==='); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); + }); + }); + describe('Trailing metadata', function() { + it('should be present when a unary call succeeds', function(done) { + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a unary call fails', function(done) { + var call = client.unary({error: true}, function(err, data) { + assert(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a client stream call succeeds', function(done) { + var call = client.clientStream(function(err, data) { + assert.ifError(err); + }); + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a client stream call fails', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + }); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a server stream call succeeds', function(done) { + var call = client.serverStream({error: false}); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, clientGrpc.status.OK); + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a server stream call fails', function(done) { + var call = client.serverStream({error: true}); + call.on('data', function(){}); + call.on('error', function(error) { + assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a bidi stream succeeds', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, clientGrpc.status.OK); + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a bidi stream fails', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', function(){}); + call.on('error', function(error) { + assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + }); + describe('Error object should contain the status', function() { + it('for a unary call', function(done) { + client.unary({error: true}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + }); + it('for a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + call.write({error: false}); + call.write({error: true}); + call.end(); + }); + it('for a server stream call', function(done) { + var call = client.serverStream({error: true}); + call.on('data', function(){}); + call.on('error', function(error) { + assert.strictEqual(error.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + done(); + }); + }); + it('for a bidi stream call', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', function(){}); + call.on('error', function(error) { + assert.strictEqual(error.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + done(); + }); + }); + it('for a UTF-8 error message', function(done) { + client.unary({error: true, message: '測試字符串'}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + done(); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/proto/echo_service.proto b/test/proto/echo_service.proto new file mode 100644 index 000000000..414b421ec --- /dev/null +++ b/test/proto/echo_service.proto @@ -0,0 +1,34 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +message EchoMessage { + string value = 1; + int32 value2 = 2; +} + +service EchoService { + rpc Echo (EchoMessage) returns (EchoMessage); + + rpc EchoClientStream (stream EchoMessage) returns (EchoMessage); + + rpc EchoServerStream (EchoMessage) returns (stream EchoMessage); + + rpc EchoBidiStream (stream EchoMessage) returns (stream EchoMessage); +} diff --git a/test/proto/test_messages.proto b/test/proto/test_messages.proto new file mode 100644 index 000000000..da1ef5658 --- /dev/null +++ b/test/proto/test_messages.proto @@ -0,0 +1,45 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +message LongValues { + int64 int_64 = 1; + uint64 uint_64 = 2; + sint64 sint_64 = 3; + fixed64 fixed_64 = 4; + sfixed64 sfixed_64 = 5; +} + +message SequenceValues { + bytes bytes_field = 1; + repeated int32 repeated_field = 2; +} + +message OneOfValues { + oneof oneof_choice { + int32 int_choice = 1; + string string_choice = 2; + } +} + +enum TestEnum { + ZERO = 0; + ONE = 1; + TWO = 2; +} + +message EnumValues { + TestEnum enum_value = 1; +} diff --git a/test/proto/test_service.proto b/test/proto/test_service.proto new file mode 100644 index 000000000..a0e49842b --- /dev/null +++ b/test/proto/test_service.proto @@ -0,0 +1,38 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +message Request { + bool error = 1; + string message = 2; +} + +message Response { + int32 count = 1; +} + +service TestService { + rpc Unary (Request) returns (Response) { + } + + rpc ClientStream (stream Request) returns (Response) { + } + + rpc ServerStream (Request) returns (stream Response) { + } + + rpc BidiStream (stream Request) returns (stream Response) { + } +} From 2b28598312ed57c7ddbf089c065c82d48e3a4e2f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 31 Aug 2018 14:25:19 -0700 Subject: [PATCH 0371/1899] Native server: don't pass non-integer status codes to core --- packages/grpc-native-core/src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index b238de048..b2b538892 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -52,7 +52,7 @@ function handleError(call, error) { if (error.hasOwnProperty('message')) { status.details = error.message; } - if (error.hasOwnProperty('code')) { + if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { status.code = error.code; if (error.hasOwnProperty('details')) { status.details = error.details; From 46b577a682e9b927e8c15fd1b557be4b74a86519 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 31 Aug 2018 15:12:20 -0700 Subject: [PATCH 0372/1899] Pure js: fix engines field, add runtime check --- packages/grpc-js-core/package.json | 3 ++- packages/grpc-js-core/src/index.ts | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index d37ab364f..62bdd2ab6 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -6,7 +6,7 @@ "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", "main": "build/src/index.js", "engines": { - "node": ">=8.4" + "node": "^8.11.2 || >=9.4" }, "keywords": [], "author": { @@ -20,6 +20,7 @@ "@types/node": "^10.5.4", "clang-format": "^1.0.55", "gts": "^0.5.1", + "semver": "^5.5.0", "typescript": "~2.7.0" }, "contributors": [ diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index b285c6819..11aefc4c5 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -9,6 +9,12 @@ import {loadPackageDefinition, makeClientConstructor} from './make-client'; import {Metadata} from './metadata'; import { Channel } from './channel'; import * as logging from './logging'; +import * as semver from 'semver'; + +const supportedNodeVersions = '^8.11.2 || >=9.4'; +if (!semver.satisfies(process.version, supportedNodeVersions)) { + throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); +} interface IndexedObject { [key: string]: any; From a4583081dd477f9990428f642daae968b79a3627 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 2 Sep 2018 09:08:07 -0400 Subject: [PATCH 0373/1899] grpc-js-core: add StatusBuilder support This commit ports StatusBuilder to TypeScript. --- packages/grpc-js-core/src/index.ts | 5 +- packages/grpc-js-core/src/status-builder.ts | 63 +++++++++++++++++++ .../grpc-js-core/test/test-status-builder.ts | 34 ++++++++++ 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 packages/grpc-js-core/src/status-builder.ts create mode 100644 packages/grpc-js-core/test/test-status-builder.ts diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index b285c6819..b73d45856 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -8,6 +8,7 @@ import {LogVerbosity, Status} from './constants'; import {loadPackageDefinition, makeClientConstructor} from './make-client'; import {Metadata} from './metadata'; import { Channel } from './channel'; +import {StatusBuilder} from './status-builder'; import * as logging from './logging'; interface IndexedObject { @@ -163,9 +164,7 @@ export const getClientChannel = (client: Client) => { return Client.prototype.getChannel.call(client); }; -export const StatusBuilder = () => { - throw new Error('Not yet implemented'); -}; +export {StatusBuilder}; export const ListenerBuilder = () => { throw new Error('Not yet implemented'); diff --git a/packages/grpc-js-core/src/status-builder.ts b/packages/grpc-js-core/src/status-builder.ts new file mode 100644 index 000000000..0ba79bb50 --- /dev/null +++ b/packages/grpc-js-core/src/status-builder.ts @@ -0,0 +1,63 @@ +import {StatusObject} from './call-stream'; +import {Status} from './constants'; +import {Metadata} from './metadata'; + +/** + * A builder for gRPC status objects. + */ +export class StatusBuilder { + private code: Status|null; + private details: string|null; + private metadata: Metadata|null; + + constructor() { + this.code = null; + this.details = null; + this.metadata = null; + } + + /** + * Adds a status code to the builder. + */ + withCode(code: Status): this { + this.code = code; + return this; + } + + /** + * Adds details to the builder. + */ + withDetails(details: string): this { + this.details = details; + return this; + } + + /** + * Adds metadata to the builder. + */ + withMetadata(metadata: Metadata): this { + this.metadata = metadata; + return this; + } + + /** + * Builds the status object. + */ + build(): Partial { + const status: Partial = {}; + + if (this.code !== null) { + status.code = this.code; + } + + if (this.details !== null) { + status.details = this.details; + } + + if (this.metadata !== null) { + status.metadata = this.metadata; + } + + return status; + } +} diff --git a/packages/grpc-js-core/test/test-status-builder.ts b/packages/grpc-js-core/test/test-status-builder.ts new file mode 100644 index 000000000..1aace004a --- /dev/null +++ b/packages/grpc-js-core/test/test-status-builder.ts @@ -0,0 +1,34 @@ +import * as assert from 'assert'; + +import * as grpc from '../src'; +import {StatusBuilder} from '../src/status-builder'; + +describe('StatusBuilder', () => { + it('is exported by the module', () => { + assert.strictEqual(StatusBuilder, grpc.StatusBuilder); + }); + + it('builds a status object', () => { + const builder = new StatusBuilder(); + const metadata = new grpc.Metadata(); + let result; + + assert.deepStrictEqual(builder.build(), {}); + result = builder.withCode(grpc.status.OK); + assert.strictEqual(result, builder); + assert.deepStrictEqual(builder.build(), { code: grpc.status.OK }); + result = builder.withDetails('foobar'); + assert.strictEqual(result, builder); + assert.deepStrictEqual(builder.build(), { + code: grpc.status.OK, + details: 'foobar' + }); + result = builder.withMetadata(metadata); + assert.strictEqual(result, builder); + assert.deepStrictEqual(builder.build(), { + code: grpc.status.OK, + details: 'foobar', + metadata + }); + }); +}); From eecefd324930703c18dad9d4fe27a3602992675c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 1 Sep 2018 11:26:15 -0400 Subject: [PATCH 0374/1899] grpc-js-core: fix lint This commit makes the lint Gulp task pass again. --- .../grpc-js-core/src/channel-credentials.ts | 6 +- packages/grpc-js-core/src/channel.ts | 12 +-- packages/grpc-js-core/src/client.ts | 18 ++--- .../grpc-js-core/src/compression-filter.ts | 74 ++++++++++--------- packages/grpc-js-core/src/index.ts | 6 +- packages/grpc-js-core/src/logging.ts | 1 + packages/grpc-js-core/src/subchannel.ts | 8 +- .../grpc-js-core/test/test-call-stream.ts | 20 ++--- packages/grpc-js-core/test/test-logging.ts | 6 +- 9 files changed, 78 insertions(+), 73 deletions(-) diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index cb29fa648..e123df08f 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -104,13 +104,13 @@ export abstract class ChannelCredentials { key: privateKey || undefined, cert: certChain || undefined }); - let connectionOptions: ConnectionOptions = { + const connectionOptions: ConnectionOptions = { secureContext }; if (verifyOptions && verifyOptions.checkServerIdentity) { connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate) => { return verifyOptions.checkServerIdentity!(host, {raw: cert.raw}); - } + }; } return new SecureChannelCredentialsImpl(connectionOptions); } @@ -141,7 +141,7 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { } class SecureChannelCredentialsImpl extends ChannelCredentials { - connectionOptions: ConnectionOptions + connectionOptions: ConnectionOptions; constructor(connectionOptions: ConnectionOptions, callCredentials?: CallCredentials) { super(callCredentials); diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 41b525625..a8a765916 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -177,7 +177,7 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; + const connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; if (connectionOptions.secureContext !== null) { // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. @@ -226,7 +226,7 @@ export class Http2Channel extends EventEmitter implements Channel { address: string, readonly credentials: ChannelCredentials, private readonly options: Partial) { super(); - for (let option in options) { + for (const option in options) { if (options.hasOwnProperty(option)) { if (!recognizedOptions.hasOwnProperty(option)) { console.warn(`Unrecognized channel argument '${option}' will be ignored.`); @@ -300,7 +300,7 @@ export class Http2Channel extends EventEmitter implements Channel { throw new Error('Channel has been shut down'); } const finalOptions: CallStreamOptions = { - deadline: (deadline === null || deadline == undefined) ? Infinity : deadline, + deadline: (deadline === null || deadline === undefined) ? Infinity : deadline, flags: propagateFlags || 0, host: host || this.defaultAuthority, parentCall: parentCall || null @@ -358,7 +358,7 @@ export class Http2Channel extends EventEmitter implements Channel { * we assume that a state change has successfully occurred */ setImmediate(callback); } else { - let deadlineMs: number = 0; + let deadlineMs = 0; if (deadline instanceof Date) { deadlineMs = deadline.getTime(); } else { @@ -368,11 +368,11 @@ export class Http2Channel extends EventEmitter implements Channel { if (timeout < 0) { timeout = 0; } - let timeoutId = setTimeout(() => { + const timeoutId = setTimeout(() => { this.removeListener('connectivityStateChanged', eventCb); callback(new Error('Channel state did not change before deadline')); }, timeout); - let eventCb = () => { + const eventCb = () => { clearTimeout(timeoutId); callback(); }; diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 7bfc19bb8..85597d965 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -19,11 +19,11 @@ export interface UnaryCallback { } export interface CallOptions { - deadline?: Deadline, - host?: string, - parent?: Call, - propagate_flags?: number, - credentials?: CallCredentials + deadline?: Deadline; + host?: string; + parent?: Call; + propagate_flags?: number; + credentials?: CallCredentials; } export type ClientOptions = Partial & { @@ -64,18 +64,18 @@ export class Client { callback(new Error('Failed to connect before the deadline')); return; } - var new_state; + let newState; try { - new_state = this[kChannel].getConnectivityState(true); + newState = this[kChannel].getConnectivityState(true); } catch (e) { callback(new Error('The channel has been closed')); return; } - if (new_state === ConnectivityState.READY) { + if (newState === ConnectivityState.READY) { callback(); } else { try { - this[kChannel].watchConnectivityState(new_state, deadline, checkState); + this[kChannel].watchConnectivityState(newState, deadline, checkState); } catch (e) { callback(new Error('The channel has been closed')); } diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index d694f239d..11b205985 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -19,7 +19,7 @@ abstract class CompressionHandler { if (compress) { messageBuffer = await this.compressMessage(messageBuffer); } - let output = Buffer.allocUnsafe(messageBuffer.length + 5); + const output = Buffer.allocUnsafe(messageBuffer.length + 5); output.writeUInt8(compress ? 1 : 0, 0); output.writeUInt32BE(messageBuffer.length, 1); messageBuffer.copy(output, 5); @@ -45,7 +45,7 @@ class IdentityHandler extends CompressionHandler { } async writeMessage(message: Buffer, compress: boolean): Promise { - let output = Buffer.allocUnsafe(message.length + 5); + const output = Buffer.allocUnsafe(message.length + 5); /* With "identity" compression, messages should always be marked as * uncompressed */ output.writeUInt8(0, 0); @@ -62,49 +62,53 @@ class IdentityHandler extends CompressionHandler { class DeflateHandler extends CompressionHandler { compressMessage(message: Buffer) { - return new Promise( - (resolve, reject) => {zlib.deflate(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - })}); + return new Promise((resolve, reject) => { + zlib.deflate(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); } decompressMessage(message: Buffer) { - return new Promise( - (resolve, reject) => {zlib.inflate(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - })}); + return new Promise((resolve, reject) => { + zlib.inflate(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); } } class GzipHandler extends CompressionHandler { compressMessage(message: Buffer) { - return new Promise( - (resolve, reject) => {zlib.gzip(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - })}); + return new Promise((resolve, reject) => { + zlib.gzip(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); } decompressMessage(message: Buffer) { - return new Promise( - (resolve, reject) => {zlib.unzip(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); - } - })}); + return new Promise((resolve, reject) => { + zlib.unzip(message, (err, output) => { + if (err) { + reject(err); + } else { + resolve(output); + } + }); + }); } } @@ -150,7 +154,7 @@ export class CompressionFilter extends BaseFilter implements Filter { async receiveMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; - let receiveEncoding: MetadataValue[] = headers.get('grpc-encoding'); + const receiveEncoding: MetadataValue[] = headers.get('grpc-encoding'); if (receiveEncoding.length > 0) { const encoding: MetadataValue = receiveEncoding[0]; if (typeof encoding === 'string') { diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 79318a6d5..713273160 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -18,15 +18,15 @@ if (!semver.satisfies(process.version, supportedNodeVersions)) { } interface IndexedObject { - [key: string]: any; - [key: number]: any; + [key: string]: any; // tslint:disable-line no-any + [key: number]: any; // tslint:disable-line no-any } function mixin(...sources: IndexedObject[]) { const result: {[key: string]: Function} = {}; for (const source of sources) { for (const propName of Object.getOwnPropertyNames(source)) { - const property: any = source[propName]; + const property: any = source[propName]; // tslint:disable-line no-any if (typeof property === 'function') { result[propName] = property; } diff --git a/packages/grpc-js-core/src/logging.ts b/packages/grpc-js-core/src/logging.ts index b5e151c4e..a0e4e8c52 100644 --- a/packages/grpc-js-core/src/logging.ts +++ b/packages/grpc-js-core/src/logging.ts @@ -15,6 +15,7 @@ export const setLoggerVerbosity = (verbosity: LogVerbosity): void => { _logVerbosity = verbosity; }; +// tslint:disable-next-line no-any export const log = (severity: LogVerbosity, ...args: any[]): void => { if (severity >= _logVerbosity && typeof _logger.error === 'function') { _logger.error(...args); diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts index f793aebbf..6182de592 100644 --- a/packages/grpc-js-core/src/subchannel.ts +++ b/packages/grpc-js-core/src/subchannel.ts @@ -35,7 +35,7 @@ export interface SubChannel extends EventEmitter { export class Http2SubChannel extends EventEmitter implements SubChannel { private session: http2.ClientHttp2Session; - private refCount: number = 0; + private refCount = 0; private userAgent: string; private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; @@ -57,7 +57,7 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { this.session.on('error', () => { this.stopKeepalivePings(); this.emit('close'); - }) + }); this.userAgent = userAgent; if (channelArgs['grpc.keepalive_time_ms']) { @@ -120,7 +120,7 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = callStream.getMethod(); headers[HTTP2_HEADER_TE] = 'trailers'; - let http2Stream = this.session.request(headers); + const http2Stream = this.session.request(headers); this.ref(); http2Stream.on('close', () => { this.unref(); @@ -131,4 +131,4 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { close() { this.session.close(); } -} \ No newline at end of file +} diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index 902007fdc..d405dfd06 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -90,7 +90,7 @@ describe('CallStream', () => { * but this might break if we start checking channel arguments, in which case * we will need a more sophisticated fake */ const filterStackFactory = - new FilterStackFactory([new CompressionFilterFactory({})]); + new FilterStackFactory([new CompressionFilterFactory({} as Channel)]); const message = 'eat this message'; // 16 bytes beforeEach(() => { @@ -102,7 +102,7 @@ describe('CallStream', () => { const responseMetadata = new Metadata(); responseMetadata.add('key', 'value'); const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); @@ -140,7 +140,7 @@ describe('CallStream', () => { maybeSkip(it)(`for error code ${key}`, () => { return new Promise((resolve, reject) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); callStream.attachHttp2Stream(http2Stream); @@ -160,7 +160,7 @@ describe('CallStream', () => { it('should have functioning getters', (done) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); assert.strictEqual(callStream.getStatus(), null); const credentials = CallCredentials.createEmpty(); @@ -179,7 +179,7 @@ describe('CallStream', () => { describe('attachHttp2Stream', () => { it('should handle an empty message', (done) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({payload: serialize(''), frameLengths: []}); callStream.once('data', assert2.mustCall((buffer) => { @@ -206,7 +206,7 @@ describe('CallStream', () => { it(`should handle a short message where ${testCase.description}`, (done) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ payload: serialize(message), // 21 bytes frameLengths: testCase.frameLengths @@ -236,7 +236,7 @@ describe('CallStream', () => { }].forEach((testCase: {description: string, frameLengths: number[]}) => { it(`should handle two messages where ${testCase.description}`, (done) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.concat( [serialize(message), serialize(message)]), // 42 bytes @@ -256,7 +256,7 @@ describe('CallStream', () => { it('should send buffered writes', (done) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); let streamFlushed = false; @@ -279,7 +279,7 @@ describe('CallStream', () => { it('should cause data chunks in write calls afterward to be written to the given stream', (done) => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { @@ -297,7 +297,7 @@ describe('CallStream', () => { it('should handle underlying stream errors', () => { const callStream = - new Http2CallStream('foo', {}, callStreamArgs, filterStackFactory); + new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); callStream.once('status', assert2.mustCall((status) => { diff --git a/packages/grpc-js-core/test/test-logging.ts b/packages/grpc-js-core/test/test-logging.ts index c1c0c25b2..46223a52a 100644 --- a/packages/grpc-js-core/test/test-logging.ts +++ b/packages/grpc-js-core/test/test-logging.ts @@ -4,7 +4,7 @@ import * as grpc from '../src'; import * as logging from '../src/logging'; describe('Logging', () => { - afterEach(function() { + afterEach(() => { // Ensure that the logger is restored to its defaults after each test. grpc.setLogger(console); grpc.setLogVerbosity(grpc.logVerbosity.DEBUG); @@ -22,9 +22,9 @@ describe('Logging', () => { }); it('gates logging based on severity', () => { - const output: any[] = []; + const output: Array = []; const logger: Partial = { - error(...args: any[]): void { + error(...args: string[]): void { output.push(args); } }; From 03c261538bdfd3e93b316ebd6828a1b15f95cc0b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 1 Sep 2018 11:34:05 -0400 Subject: [PATCH 0375/1899] grpc-js-core: make gts check pass This commit makes the gts check command pass. --- packages/grpc-js-core/src/call-stream.ts | 11 +-- packages/grpc-js-core/src/call.ts | 4 +- .../grpc-js-core/src/channel-credentials.ts | 22 +++--- packages/grpc-js-core/src/channel.ts | 47 +++++++---- packages/grpc-js-core/src/client.ts | 77 ++++++++++--------- packages/grpc-js-core/src/deadline-filter.ts | 37 +++++---- packages/grpc-js-core/src/index.ts | 12 +-- packages/grpc-js-core/src/make-client.ts | 14 +--- packages/grpc-js-core/src/metadata.ts | 4 +- packages/grpc-js-core/src/object-stream.ts | 2 +- packages/grpc-js-core/src/status-builder.ts | 2 +- packages/grpc-js-core/src/subchannel.ts | 19 ++--- .../grpc-js-core/test/test-call-stream.ts | 44 +++++------ packages/grpc-js-core/test/test-logging.ts | 13 +--- .../grpc-js-core/test/test-status-builder.ts | 15 ++-- 15 files changed, 164 insertions(+), 159 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 87b38c456..3e88df5b9 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -1,15 +1,15 @@ import * as http2 from 'http2'; +import {Meta} from 'orchestrator'; import {Duplex} from 'stream'; import {CallCredentials} from './call-credentials'; +import {Channel, Http2Channel} from './channel'; import {Status} from './constants'; import {EmitterAugmentation1} from './events'; import {Filter} from './filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; import {ObjectDuplex, WriteCallback} from './object-stream'; -import { Meta } from 'orchestrator'; -import { Channel, Http2Channel } from './channel'; const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = http2.constants; @@ -20,7 +20,7 @@ export interface CallStreamOptions { deadline: Deadline; flags: number; host: string; - parentCall: Call | null; + parentCall: Call|null; } export type PartialCallStreamOptions = Partial; @@ -76,7 +76,7 @@ export class Http2CallStream extends Duplex implements Call { private http2Stream: http2.ClientHttp2Stream|null = null; private pendingRead = false; private pendingWrite: Buffer|null = null; - private pendingWriteCallback: WriteCallback | null = null; + private pendingWriteCallback: WriteCallback|null = null; private pendingFinalCallback: Function|null = null; private readState: ReadState = ReadState.NO_DATA; @@ -384,7 +384,8 @@ export class Http2CallStream extends Duplex implements Call { } sendMetadata(metadata: Metadata): void { - this.channel._startHttp2Stream(this.options.host, this.methodName, this, metadata); + this.channel._startHttp2Stream( + this.options.host, this.methodName, this, metadata); } private destroyHttp2Stream() { diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index 9c864d8cd..aab3847b0 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -124,8 +124,8 @@ export class ClientReadableStreamImpl extends Readable implements } function tryWrite( - call: Call, serialize: (value: RequestType) => Buffer, - chunk: RequestType, encoding: string, cb: Function) { + call: Call, serialize: (value: RequestType) => Buffer, chunk: RequestType, + encoding: string, cb: Function) { let message: Buffer; const flags: number = Number(encoding); try { diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index e123df08f..23de17167 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -1,4 +1,4 @@ -import {createSecureContext, SecureContext, TLSSocket, ConnectionOptions, PeerCertificate} from 'tls'; +import {ConnectionOptions, createSecureContext, PeerCertificate, SecureContext, TLSSocket} from 'tls'; import {CallCredentials} from './call-credentials'; @@ -25,7 +25,8 @@ export interface Certificate { * indicate that the presented certificate is considered invalid and * otherwise returned undefined. */ -export type CheckServerIdentityCallback = (hostname: string, cert: Certificate) => Error | undefined; +export type CheckServerIdentityCallback = + (hostname: string, cert: Certificate) => Error|undefined; /** * Additional peer verification options that can be set when creating @@ -87,7 +88,8 @@ export abstract class ChannelCredentials { */ static createSsl( rootCerts?: Buffer|null, privateKey?: Buffer|null, - certChain?: Buffer|null, verifyOptions?: VerifyOptions): ChannelCredentials { + certChain?: Buffer|null, + verifyOptions?: VerifyOptions): ChannelCredentials { verifyIsBufferOrNull(rootCerts, 'Root certificate'); verifyIsBufferOrNull(privateKey, 'Private key'); verifyIsBufferOrNull(certChain, 'Certificate chain'); @@ -104,13 +106,12 @@ export abstract class ChannelCredentials { key: privateKey || undefined, cert: certChain || undefined }); - const connectionOptions: ConnectionOptions = { - secureContext - }; + const connectionOptions: ConnectionOptions = {secureContext}; if (verifyOptions && verifyOptions.checkServerIdentity) { - connectionOptions.checkServerIdentity = (host: string, cert: PeerCertificate) => { - return verifyOptions.checkServerIdentity!(host, {raw: cert.raw}); - }; + connectionOptions.checkServerIdentity = + (host: string, cert: PeerCertificate) => { + return verifyOptions.checkServerIdentity!(host, {raw: cert.raw}); + }; } return new SecureChannelCredentialsImpl(connectionOptions); } @@ -143,7 +144,8 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { class SecureChannelCredentialsImpl extends ChannelCredentials { connectionOptions: ConnectionOptions; - constructor(connectionOptions: ConnectionOptions, callCredentials?: CallCredentials) { + constructor( + connectionOptions: ConnectionOptions, callCredentials?: CallCredentials) { super(callCredentials); this.connectionOptions = connectionOptions; } diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index a8a765916..6bc122e25 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -5,16 +5,16 @@ import * as url from 'url'; import {CallCredentials} from './call-credentials'; import {CallCredentialsFilterFactory} from './call-credentials-filter'; -import {PartialCallStreamOptions, Call, CallStreamOptions, Http2CallStream, Deadline} from './call-stream'; +import {Call, CallStreamOptions, Deadline, Http2CallStream, PartialCallStreamOptions} from './call-stream'; import {ChannelCredentials} from './channel-credentials'; +import {ChannelOptions, recognizedOptions} from './channel-options'; import {CompressionFilterFactory} from './compression-filter'; import {Status} from './constants'; import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata, MetadataObject} from './metadata'; import {MetadataStatusFilterFactory} from './metadata-status-filter'; -import { Http2SubChannel } from './subchannel'; -import {ChannelOptions, recognizedOptions} from './channel-options'; +import {Http2SubChannel} from './subchannel'; const {version: clientVersion} = require('../../package'); @@ -57,7 +57,8 @@ function uniformRandom(min: number, max: number) { */ export interface Channel { /** - * Close the channel. This has the same functionality as the existing grpc.Client.prototype.close + * Close the channel. This has the same functionality as the existing + * grpc.Client.prototype.close */ close(): void; /** @@ -83,7 +84,9 @@ export interface Channel { * @param callback Called with no error when a state change, or with an * error if the deadline passes without a state change. */ - watchConnectivityState(currentState: ConnectivityState, deadline: Date|number, callback: (error?: Error) => void): void; + watchConnectivityState( + currentState: ConnectivityState, deadline: Date|number, + callback: (error?: Error) => void): void; /** * Create a call object. Call is an opaque type that is used by the Client * class. This function is called by the gRPC library when starting a @@ -96,7 +99,10 @@ export interface Channel { * @param propagateFlags A bitwise combination of elements of grpc.propagate * that indicates what information to propagate from parentCall. */ - createCall(method: string, deadline: Deadline|null|undefined, host: string|null|undefined, parentCall: Call|null|undefined, propagateFlags: number|null|undefined): Call; + createCall( + method: string, deadline: Deadline|null|undefined, + host: string|null|undefined, parentCall: Call|null|undefined, + propagateFlags: number|null|undefined): Call; } export class Http2Channel extends EventEmitter implements Channel { @@ -177,7 +183,8 @@ export class Http2Channel extends EventEmitter implements Channel { } private startConnecting(): void { - const connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; + const connectionOptions: http2.SecureClientSessionOptions = + this.credentials._getConnectionOptions() || {}; if (connectionOptions.secureContext !== null) { // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. @@ -192,7 +199,8 @@ export class Http2Channel extends EventEmitter implements Channel { connectionOptions.servername = sslTargetNameOverride; } } - const subChannel: Http2SubChannel = new Http2SubChannel(this.target, connectionOptions, this.userAgent, this.options); + const subChannel: Http2SubChannel = new Http2SubChannel( + this.target, connectionOptions, this.userAgent, this.options); this.subChannel = subChannel; const now = new Date(); const connectionTimeout: number = Math.max( @@ -229,7 +237,8 @@ export class Http2Channel extends EventEmitter implements Channel { for (const option in options) { if (options.hasOwnProperty(option)) { if (!recognizedOptions.hasOwnProperty(option)) { - console.warn(`Unrecognized channel argument '${option}' will be ignored.`); + console.warn( + `Unrecognized channel argument '${option}' will be ignored.`); } } } @@ -294,19 +303,22 @@ export class Http2Channel extends EventEmitter implements Channel { }); } - createCall(method: string, deadline: Deadline|null|undefined, host: string|null|undefined, parentCall: Call|null|undefined, propagateFlags: number|null|undefined): - Call { + createCall( + method: string, deadline: Deadline|null|undefined, + host: string|null|undefined, parentCall: Call|null|undefined, + propagateFlags: number|null|undefined): Call { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } const finalOptions: CallStreamOptions = { - deadline: (deadline === null || deadline === undefined) ? Infinity : deadline, + deadline: (deadline === null || deadline === undefined) ? Infinity : + deadline, flags: propagateFlags || 0, host: host || this.defaultAuthority, parentCall: parentCall || null }; - const stream: Http2CallStream = - new Http2CallStream(method, this, finalOptions, this.filterStackFactory); + const stream: Http2CallStream = new Http2CallStream( + method, this, finalOptions, this.filterStackFactory); return stream; } @@ -347,12 +359,15 @@ export class Http2Channel extends EventEmitter implements Channel { getConnectivityState(tryToConnect: boolean): ConnectivityState { if (tryToConnect) { - this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING); + this.transitionToState( + [ConnectivityState.IDLE], ConnectivityState.CONNECTING); } return this.connectivityState; } - watchConnectivityState(currentState: ConnectivityState, deadline: Date|number, callback: (error?: Error)=>void) { + watchConnectivityState( + currentState: ConnectivityState, deadline: Date|number, + callback: (error?: Error) => void) { if (this.connectivityState !== currentState) { /* If the connectivity state is different from the provided currentState, * we assume that a state change has successfully occurred */ diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 85597d965..220646dcd 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -2,13 +2,13 @@ import {once} from 'lodash'; import {URL} from 'url'; import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; -import {PartialCallStreamOptions, Call, StatusObject, WriteObject, Deadline} from './call-stream'; -import {Channel, Http2Channel, ConnectivityState} from './channel'; +import {CallCredentials} from './call-credentials'; +import {Call, Deadline, PartialCallStreamOptions, StatusObject, WriteObject} from './call-stream'; +import {Channel, ConnectivityState, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; +import {ChannelOptions} from './channel-options'; import {Status} from './constants'; import {Metadata} from './metadata'; -import {ChannelOptions} from './channel-options'; -import { CallCredentials } from './call-credentials'; // This symbol must be exported (for now). // See: https://github.com/Microsoft/TypeScript/issues/20080 @@ -26,9 +26,10 @@ export interface CallOptions { credentials?: CallCredentials; } -export type ClientOptions = Partial & { +export type ClientOptions = Partial&{ channelOverride?: Channel, - channelFactoryOverride?: (address: string, credentials: ChannelCredentials, options: ClientOptions) => Channel + channelFactoryOverride?: (address: string, credentials: ChannelCredentials, + options: ClientOptions) => Channel }; /** @@ -43,7 +44,8 @@ export class Client { if (options.channelOverride) { this[kChannel] = options.channelOverride; } else if (options.channelFactoryOverride) { - this[kChannel] = options.channelFactoryOverride(address, credentials, options); + this[kChannel] = + options.channelFactoryOverride(address, credentials, options); } else { this[kChannel] = new Http2Channel(address, credentials, options); } @@ -57,31 +59,30 @@ export class Client { return this[kChannel]; } - waitForReady(deadline: Deadline, callback: (error?: Error) => void): - void { - const checkState = (err?: Error) => { - if (err) { - callback(new Error('Failed to connect before the deadline')); - return; - } - let newState; + waitForReady(deadline: Deadline, callback: (error?: Error) => void): void { + const checkState = (err?: Error) => { + if (err) { + callback(new Error('Failed to connect before the deadline')); + return; + } + let newState; + try { + newState = this[kChannel].getConnectivityState(true); + } catch (e) { + callback(new Error('The channel has been closed')); + return; + } + if (newState === ConnectivityState.READY) { + callback(); + } else { try { - newState = this[kChannel].getConnectivityState(true); + this[kChannel].watchConnectivityState(newState, deadline, checkState); } catch (e) { callback(new Error('The channel has been closed')); - return; } - if (newState === ConnectivityState.READY) { - callback(); - } else { - try { - this[kChannel].watchConnectivityState(newState, deadline, checkState); - } catch (e) { - callback(new Error('The channel has been closed')); - } - } - }; - setImmediate(checkState); + } + }; + setImmediate(checkState); } private handleUnaryResponse( @@ -172,8 +173,9 @@ export class Client { ({metadata, options, callback} = this.checkOptionalUnaryResponseArguments( metadata, options, callback)); - const call: Call = - this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + const call: Call = this[kChannel].createCall( + method, options.deadline, options.host, options.parent, + options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } @@ -213,8 +215,9 @@ export class Client { ({metadata, options, callback} = this.checkOptionalUnaryResponseArguments( metadata, options, callback)); - const call: Call = - this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + const call: Call = this[kChannel].createCall( + method, options.deadline, options.host, options.parent, + options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } @@ -261,8 +264,9 @@ export class Client { metadata?: Metadata|CallOptions, options?: CallOptions): ClientReadableStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); - const call: Call = - this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + const call: Call = this[kChannel].createCall( + method, options.deadline, options.host, options.parent, + options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } @@ -288,8 +292,9 @@ export class Client { metadata?: Metadata|CallOptions, options?: CallOptions): ClientDuplexStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); - const call: Call = - this[kChannel].createCall(method, options.deadline, options.host, options.parent, options.propagate_flags); + const call: Call = this[kChannel].createCall( + method, options.deadline, options.host, options.parent, + options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index 0e2886089..32174d9e6 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -1,5 +1,5 @@ import {Call} from './call-stream'; -import {Channel, Http2Channel, ConnectivityState} from './channel'; +import {Channel, ConnectivityState, Http2Channel} from './channel'; import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; @@ -51,22 +51,25 @@ export class DeadlineFilter extends BaseFilter implements Filter { return metadata; } return new Promise((resolve, reject) => { - if (this.channel.getConnectivityState(false) === ConnectivityState.READY) { - resolve(metadata); - } else { - const handleStateChange = (newState: ConnectivityState) => { - if (newState === ConnectivityState.READY) { - resolve(metadata); - this.channel.removeListener('connectivityStateChanged', handleStateChange); - } - }; - this.channel.on('connectivityStateChanged', handleStateChange); - } - }).then((finalMetadata: Metadata) => { - const timeoutString = getDeadline(this.deadline); - finalMetadata.set('grpc-timeout', timeoutString); - return finalMetadata; - }); + if (this.channel.getConnectivityState(false) === + ConnectivityState.READY) { + resolve(metadata); + } else { + const handleStateChange = (newState: ConnectivityState) => { + if (newState === ConnectivityState.READY) { + resolve(metadata); + this.channel.removeListener( + 'connectivityStateChanged', handleStateChange); + } + }; + this.channel.on('connectivityStateChanged', handleStateChange); + } + }) + .then((finalMetadata: Metadata) => { + const timeoutString = getDeadline(this.deadline); + finalMetadata.set('grpc-timeout', timeoutString); + return finalMetadata; + }); } } diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 713273160..810508a71 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -1,16 +1,16 @@ import {IncomingHttpHeaders} from 'http'; +import * as semver from 'semver'; import {CallCredentials} from './call-credentials'; +import {Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; import {Client} from './client'; import {LogVerbosity, Status} from './constants'; +import * as logging from './logging'; import {loadPackageDefinition, makeClientConstructor} from './make-client'; import {Metadata} from './metadata'; -import { Channel } from './channel'; import {StatusBuilder} from './status-builder'; -import * as logging from './logging'; -import * as semver from 'semver'; const supportedNodeVersions = '^8.11.2 || >=9.4'; if (!semver.satisfies(process.version, supportedNodeVersions)) { @@ -18,15 +18,15 @@ if (!semver.satisfies(process.version, supportedNodeVersions)) { } interface IndexedObject { - [key: string]: any; // tslint:disable-line no-any - [key: number]: any; // tslint:disable-line no-any + [key: string]: any; // tslint:disable-line no-any + [key: number]: any; // tslint:disable-line no-any } function mixin(...sources: IndexedObject[]) { const result: {[key: string]: Function} = {}; for (const source of sources) { for (const propName of Object.getOwnPropertyNames(source)) { - const property: any = source[propName]; // tslint:disable-line no-any + const property: any = source[propName]; // tslint:disable-line no-any if (typeof property === 'function') { result[propName] = property; } diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index fff339f47..f3d90f81e 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -1,18 +1,14 @@ import * as _ from 'lodash'; import {PartialCallStreamOptions} from './call-stream'; -import {ChannelOptions} from './channel-options'; import {ChannelCredentials} from './channel-credentials'; +import {ChannelOptions} from './channel-options'; import {Client, UnaryCallback} from './client'; import {Metadata} from './metadata'; -export interface Serialize { - (value: T): Buffer; -} +export interface Serialize { (value: T): Buffer; } -export interface Deserialize { - (bytes: Buffer): T; -} +export interface Deserialize { (bytes: Buffer): T; } export interface MethodDefinition { path: string; @@ -29,9 +25,7 @@ export interface ServiceDefinition { [index: string]: MethodDefinition; } -export interface PackageDefinition { - [index: string]: ServiceDefinition; -} +export interface PackageDefinition { [index: string]: ServiceDefinition; } function getDefaultValues(metadata?: Metadata, options?: T): {metadata: Metadata; options: Partial;} { diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index e53b18a99..48cfb6f30 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -5,9 +5,7 @@ const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; export type MetadataValue = string|Buffer; -export interface MetadataObject { - [key: string]: MetadataValue[]; -} +export interface MetadataObject { [key: string]: MetadataValue[]; } function cloneMetadataObject(repr: MetadataObject): MetadataObject { const result: MetadataObject = {}; diff --git a/packages/grpc-js-core/src/object-stream.ts b/packages/grpc-js-core/src/object-stream.ts index dca37e79d..b298ed025 100644 --- a/packages/grpc-js-core/src/object-stream.ts +++ b/packages/grpc-js-core/src/object-stream.ts @@ -3,7 +3,7 @@ import {EmitterAugmentation1} from './events'; // tslint:disable:no-any -export type WriteCallback = (error: Error | null | undefined) => void; +export type WriteCallback = (error: Error|null|undefined) => void; export interface IntermediateObjectReadable extends Readable { read(size?: number): any&T; diff --git a/packages/grpc-js-core/src/status-builder.ts b/packages/grpc-js-core/src/status-builder.ts index 0ba79bb50..dd0859a0e 100644 --- a/packages/grpc-js-core/src/status-builder.ts +++ b/packages/grpc-js-core/src/status-builder.ts @@ -13,7 +13,7 @@ export class StatusBuilder { constructor() { this.code = null; this.details = null; - this.metadata = null; + this.metadata = null; } /** diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts index 6182de592..4d07d8c85 100644 --- a/packages/grpc-js-core/src/subchannel.ts +++ b/packages/grpc-js-core/src/subchannel.ts @@ -1,11 +1,11 @@ +import {EventEmitter} from 'events'; import * as http2 from 'http2'; import * as url from 'url'; -import { EventEmitter } from "events"; -import { Metadata } from "./metadata"; -import { Call, PartialCallStreamOptions, Http2CallStream } from "./call-stream"; -import { EmitterAugmentation1, EmitterAugmentation0 } from "./events"; -import { ChannelOptions } from './channel-options'; +import {Call, Http2CallStream, PartialCallStreamOptions} from './call-stream'; +import {ChannelOptions} from './channel-options'; +import {EmitterAugmentation0, EmitterAugmentation1} from './events'; +import {Metadata} from './metadata'; const { HTTP2_HEADER_AUTHORITY, @@ -43,8 +43,9 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { private keepaliveIntervalId: NodeJS.Timer; private keepaliveTimeoutId: NodeJS.Timer; - constructor(target: url.URL, connectionOptions: http2.SecureClientSessionOptions, - userAgent: string, channelArgs: Partial) { + constructor( + target: url.URL, connectionOptions: http2.SecureClientSessionOptions, + userAgent: string, channelArgs: Partial) { super(); this.session = http2.connect(target, connectionOptions); this.session.on('connect', () => { @@ -92,7 +93,7 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { this.keepaliveTimeoutId = setTimeout(() => { this.emit('close'); }, this.keepaliveTimeoutMs); - this.session.ping((err: Error | null, duration: number, payload: Buffer) => { + this.session.ping((err: Error|null, duration: number, payload: Buffer) => { clearTimeout(this.keepaliveTimeoutId); }); } @@ -127,7 +128,7 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { }); callStream.attachHttp2Stream(http2Stream); } - + close() { this.session.close(); } diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index d405dfd06..e20dfecb1 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -79,12 +79,8 @@ class ClientHttp2StreamMock extends stream.Duplex implements } describe('CallStream', () => { - const callStreamArgs = { - deadline: Infinity, - flags: 0, - host: '', - parentCall: null - }; + const callStreamArgs = + {deadline: Infinity, flags: 0, host: '', parentCall: null}; /* A CompressionFilter is now necessary to frame and deframe messages. * Currently the channel is unused, so we can replace it with an empty object, * but this might break if we start checking channel arguments, in which case @@ -101,8 +97,8 @@ describe('CallStream', () => { (done) => { const responseMetadata = new Metadata(); responseMetadata.add('key', 'value'); - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); @@ -139,8 +135,8 @@ describe('CallStream', () => { const maybeSkip = (fn: typeof it) => value ? fn : fn.skip; maybeSkip(it)(`for error code ${key}`, () => { return new Promise((resolve, reject) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); callStream.attachHttp2Stream(http2Stream); @@ -159,8 +155,8 @@ describe('CallStream', () => { }); it('should have functioning getters', (done) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); assert.strictEqual(callStream.getStatus(), null); const credentials = CallCredentials.createEmpty(); @@ -178,8 +174,8 @@ describe('CallStream', () => { describe('attachHttp2Stream', () => { it('should handle an empty message', (done) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({payload: serialize(''), frameLengths: []}); callStream.once('data', assert2.mustCall((buffer) => { @@ -205,8 +201,8 @@ describe('CallStream', () => { }].forEach((testCase: {description: string, frameLengths: number[]}) => { it(`should handle a short message where ${testCase.description}`, (done) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ payload: serialize(message), // 21 bytes frameLengths: testCase.frameLengths @@ -235,8 +231,8 @@ describe('CallStream', () => { frameLengths: range(0, 41).map(() => 1) }].forEach((testCase: {description: string, frameLengths: number[]}) => { it(`should handle two messages where ${testCase.description}`, (done) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.concat( [serialize(message), serialize(message)]), // 42 bytes @@ -255,8 +251,8 @@ describe('CallStream', () => { }); it('should send buffered writes', (done) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); let streamFlushed = false; @@ -278,8 +274,8 @@ describe('CallStream', () => { it('should cause data chunks in write calls afterward to be written to the given stream', (done) => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { @@ -296,8 +292,8 @@ describe('CallStream', () => { }); it('should handle underlying stream errors', () => { - const callStream = - new Http2CallStream('foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + const callStream = new Http2CallStream( + 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); const http2Stream = new ClientHttp2StreamMock( {payload: Buffer.alloc(0), frameLengths: []}); callStream.once('status', assert2.mustCall((status) => { diff --git a/packages/grpc-js-core/test/test-logging.ts b/packages/grpc-js-core/test/test-logging.ts index 46223a52a..4f8f64a9d 100644 --- a/packages/grpc-js-core/test/test-logging.ts +++ b/packages/grpc-js-core/test/test-logging.ts @@ -22,7 +22,7 @@ describe('Logging', () => { }); it('gates logging based on severity', () => { - const output: Array = []; + const output: Array = []; const logger: Partial = { error(...args: string[]): void { output.push(args); @@ -48,13 +48,8 @@ describe('Logging', () => { logging.log(grpc.logVerbosity.INFO, 7, 8); logging.log(grpc.logVerbosity.ERROR, 'j', 'k'); - assert.deepStrictEqual(output, [ - ['a', 'b', 'c'], - ['d', 'e'], - ['f'], - ['g'], - ['h', 'i'], - ['j', 'k'] - ]); + assert.deepStrictEqual( + output, + [['a', 'b', 'c'], ['d', 'e'], ['f'], ['g'], ['h', 'i'], ['j', 'k']]); }); }); diff --git a/packages/grpc-js-core/test/test-status-builder.ts b/packages/grpc-js-core/test/test-status-builder.ts index 1aace004a..ce27518d8 100644 --- a/packages/grpc-js-core/test/test-status-builder.ts +++ b/packages/grpc-js-core/test/test-status-builder.ts @@ -16,19 +16,14 @@ describe('StatusBuilder', () => { assert.deepStrictEqual(builder.build(), {}); result = builder.withCode(grpc.status.OK); assert.strictEqual(result, builder); - assert.deepStrictEqual(builder.build(), { code: grpc.status.OK }); + assert.deepStrictEqual(builder.build(), {code: grpc.status.OK}); result = builder.withDetails('foobar'); assert.strictEqual(result, builder); - assert.deepStrictEqual(builder.build(), { - code: grpc.status.OK, - details: 'foobar' - }); + assert.deepStrictEqual( + builder.build(), {code: grpc.status.OK, details: 'foobar'}); result = builder.withMetadata(metadata); assert.strictEqual(result, builder); - assert.deepStrictEqual(builder.build(), { - code: grpc.status.OK, - details: 'foobar', - metadata - }); + assert.deepStrictEqual( + builder.build(), {code: grpc.status.OK, details: 'foobar', metadata}); }); }); From a97e81f4221e6e029d5f05d23ca6f7bcd6da1519 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 1 Sep 2018 12:19:12 -0400 Subject: [PATCH 0376/1899] grpc-js-core: remove unused variables This commit removes unused variables reported by temporarily enabling tslint's no-unused-variable rule. Unused function parameters have not been removed. --- packages/grpc-js-core/src/call-credentials-filter.ts | 2 -- packages/grpc-js-core/src/call-credentials.ts | 2 +- packages/grpc-js-core/src/call-stream.ts | 6 +----- packages/grpc-js-core/src/call.ts | 3 --- packages/grpc-js-core/src/channel-credentials.ts | 2 +- packages/grpc-js-core/src/channel.ts | 10 +++------- packages/grpc-js-core/src/client.ts | 5 +---- packages/grpc-js-core/src/compression-filter.ts | 1 - packages/grpc-js-core/src/deadline-filter.ts | 2 +- packages/grpc-js-core/src/index.ts | 2 -- packages/grpc-js-core/src/make-client.ts | 9 +-------- packages/grpc-js-core/src/subchannel.ts | 4 +--- packages/grpc-js-core/test/test-call-stream.ts | 3 +-- 13 files changed, 11 insertions(+), 40 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index c13df8693..95aee5920 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -1,5 +1,3 @@ -import {promisify} from 'util'; - import {CallCredentials} from './call-credentials'; import {Call} from './call-stream'; import {Http2Channel} from './channel'; diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 7d5bd3323..2a9d8195f 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -1,4 +1,4 @@ -import {map, reduce} from 'lodash'; +import {map} from 'lodash'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 3e88df5b9..20eca0235 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -1,9 +1,8 @@ import * as http2 from 'http2'; -import {Meta} from 'orchestrator'; import {Duplex} from 'stream'; import {CallCredentials} from './call-credentials'; -import {Channel, Http2Channel} from './channel'; +import {Http2Channel} from './channel'; import {Status} from './constants'; import {EmitterAugmentation1} from './events'; import {Filter} from './filter'; @@ -67,12 +66,9 @@ enum ReadState { READING_MESSAGE } -const emptyBuffer = Buffer.alloc(0); - export class Http2CallStream extends Duplex implements Call { credentials: CallCredentials = CallCredentials.createEmpty(); filterStack: Filter; - private statusEmitted = false; private http2Stream: http2.ClientHttp2Stream|null = null; private pendingRead = false; private pendingWrite: Buffer|null = null; diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js-core/src/call.ts index aab3847b0..6e6f82aa4 100644 --- a/packages/grpc-js-core/src/call.ts +++ b/packages/grpc-js-core/src/call.ts @@ -1,5 +1,4 @@ import {EventEmitter} from 'events'; -import * as _ from 'lodash'; import {Duplex, Readable, Writable} from 'stream'; import {Call, StatusObject, WriteObject} from './call-stream'; @@ -87,8 +86,6 @@ function setUpReadableStream( }); call.on('status', (status: StatusObject) => { if (status.code !== Status.OK) { - const statusName = _.invert(Status)[status.code]; - const message = `${status.code} ${statusName}: ${status.details}`; const error: ServiceError = Object.assign(new Error(status.details), status); stream.emit('error', error); diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js-core/src/channel-credentials.ts index 23de17167..b2c73efa9 100644 --- a/packages/grpc-js-core/src/channel-credentials.ts +++ b/packages/grpc-js-core/src/channel-credentials.ts @@ -1,4 +1,4 @@ -import {ConnectionOptions, createSecureContext, PeerCertificate, SecureContext, TLSSocket} from 'tls'; +import {ConnectionOptions, createSecureContext, PeerCertificate} from 'tls'; import {CallCredentials} from './call-credentials'; diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js-core/src/channel.ts index 6bc122e25..aeb7d765c 100644 --- a/packages/grpc-js-core/src/channel.ts +++ b/packages/grpc-js-core/src/channel.ts @@ -1,25 +1,22 @@ import {EventEmitter} from 'events'; import * as http2 from 'http2'; -import {checkServerIdentity, PeerCertificate, SecureContext} from 'tls'; +import {checkServerIdentity, PeerCertificate} from 'tls'; import * as url from 'url'; -import {CallCredentials} from './call-credentials'; import {CallCredentialsFilterFactory} from './call-credentials-filter'; -import {Call, CallStreamOptions, Deadline, Http2CallStream, PartialCallStreamOptions} from './call-stream'; +import {Call, CallStreamOptions, Deadline, Http2CallStream} from './call-stream'; import {ChannelCredentials} from './channel-credentials'; import {ChannelOptions, recognizedOptions} from './channel-options'; import {CompressionFilterFactory} from './compression-filter'; import {Status} from './constants'; import {DeadlineFilterFactory} from './deadline-filter'; import {FilterStackFactory} from './filter-stack'; -import {Metadata, MetadataObject} from './metadata'; +import {Metadata} from './metadata'; import {MetadataStatusFilterFactory} from './metadata-status-filter'; import {Http2SubChannel} from './subchannel'; const {version: clientVersion} = require('../../package'); -const IDLE_TIMEOUT_MS = 300000; - const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; const BACKOFF_MULTIPLIER = 1.6; @@ -31,7 +28,6 @@ const { HTTP2_HEADER_CONTENT_TYPE, HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, - HTTP2_HEADER_SCHEME, HTTP2_HEADER_TE, HTTP2_HEADER_USER_AGENT } = http2.constants; diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js-core/src/client.ts index 220646dcd..7381f4da9 100644 --- a/packages/grpc-js-core/src/client.ts +++ b/packages/grpc-js-core/src/client.ts @@ -1,9 +1,6 @@ -import {once} from 'lodash'; -import {URL} from 'url'; - import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; import {CallCredentials} from './call-credentials'; -import {Call, Deadline, PartialCallStreamOptions, StatusObject, WriteObject} from './call-stream'; +import {Call, Deadline, StatusObject, WriteObject} from './call-stream'; import {Channel, ConnectivityState, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; import {ChannelOptions} from './channel-options'; diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index 11b205985..e4ed9604d 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -2,7 +2,6 @@ import * as zlib from 'zlib'; import {Call, WriteFlags, WriteObject} from './call-stream'; import {Channel} from './channel'; -import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata, MetadataValue} from './metadata'; diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js-core/src/deadline-filter.ts index 32174d9e6..fd52ebbcb 100644 --- a/packages/grpc-js-core/src/deadline-filter.ts +++ b/packages/grpc-js-core/src/deadline-filter.ts @@ -1,5 +1,5 @@ import {Call} from './call-stream'; -import {Channel, ConnectivityState, Http2Channel} from './channel'; +import {ConnectivityState, Http2Channel} from './channel'; import {Status} from './constants'; import {BaseFilter, Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js-core/src/index.ts index 810508a71..f7a22a0d7 100644 --- a/packages/grpc-js-core/src/index.ts +++ b/packages/grpc-js-core/src/index.ts @@ -1,5 +1,3 @@ - -import {IncomingHttpHeaders} from 'http'; import * as semver from 'semver'; import {CallCredentials} from './call-credentials'; diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index f3d90f81e..669723d0a 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -1,10 +1,8 @@ import * as _ from 'lodash'; -import {PartialCallStreamOptions} from './call-stream'; import {ChannelCredentials} from './channel-credentials'; import {ChannelOptions} from './channel-options'; -import {Client, UnaryCallback} from './client'; -import {Metadata} from './metadata'; +import {Client} from './client'; export interface Serialize { (value: T): Buffer; } @@ -27,11 +25,6 @@ export interface ServiceDefinition { export interface PackageDefinition { [index: string]: ServiceDefinition; } -function getDefaultValues(metadata?: Metadata, options?: T): - {metadata: Metadata; options: Partial;} { - return {metadata: metadata || new Metadata(), options: options || {}}; -} - /** * Map with short names for each of the requester maker functions. Used in * makeClientConstructor diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js-core/src/subchannel.ts index 4d07d8c85..13612a883 100644 --- a/packages/grpc-js-core/src/subchannel.ts +++ b/packages/grpc-js-core/src/subchannel.ts @@ -2,9 +2,8 @@ import {EventEmitter} from 'events'; import * as http2 from 'http2'; import * as url from 'url'; -import {Call, Http2CallStream, PartialCallStreamOptions} from './call-stream'; +import {Call, Http2CallStream} from './call-stream'; import {ChannelOptions} from './channel-options'; -import {EmitterAugmentation0, EmitterAugmentation1} from './events'; import {Metadata} from './metadata'; const { @@ -12,7 +11,6 @@ const { HTTP2_HEADER_CONTENT_TYPE, HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, - HTTP2_HEADER_SCHEME, HTTP2_HEADER_TE, HTTP2_HEADER_USER_AGENT } = http2.constants; diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index e20dfecb1..33a5991c0 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -1,7 +1,6 @@ import * as assert from 'assert'; -import {EventEmitter} from 'events'; import * as http2 from 'http2'; -import {forOwn, range} from 'lodash'; +import {range} from 'lodash'; import * as stream from 'stream'; import {CallCredentials} from '../src/call-credentials'; From 0781f5df73d4b8b3eaad19d8f979d38709030119 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 2 Sep 2018 14:41:00 -0400 Subject: [PATCH 0377/1899] grpc-js-core: run linter when tests are run This commit runs the js.core.lint job when js.core.test is run to ensure the linting doesn't get stale. --- packages/grpc-js-core/gulpfile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/gulpfile.ts b/packages/grpc-js-core/gulpfile.ts index b75350cc2..72434d5ba 100644 --- a/packages/grpc-js-core/gulpfile.ts +++ b/packages/grpc-js-core/gulpfile.ts @@ -71,7 +71,7 @@ gulp.task('copy-test-fixtures', 'Copy test fixtures.', () => { /** * Transpiles src/ and test/, and then runs all tests. */ -gulp.task('test', 'Runs all tests.', ['copy-test-fixtures'], () => { +gulp.task('test', 'Runs all tests.', ['lint', 'copy-test-fixtures'], () => { if (semver.satisfies(process.version, '^8.11.2 || >=9.4')) { return gulp.src(`${outDir}/test/**/*.js`) .pipe(mocha({reporter: 'mocha-jenkins-reporter', From 4c07ed3d66dddafed3e2e8253236b26c1b99664d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 5 Sep 2018 16:51:36 -0700 Subject: [PATCH 0378/1899] Update pure JS version, README --- packages/grpc-js-core/README.md | 4 ++-- packages/grpc-js-core/package.json | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-core/README.md b/packages/grpc-js-core/README.md index 647121b82..e3918666d 100644 --- a/packages/grpc-js-core/README.md +++ b/packages/grpc-js-core/README.md @@ -1,10 +1,10 @@ # Pure JavaScript gRPC Client -**Note: This is an alpha-level release. Some APIs may not yet be present and there may be bugs. Please report any that you encounter** +**Note: This is an beta-level release. Some APIs may not yet be present and there may be bugs. Please report any that you encounter** ## Installation -Node 9.x or greater is required. +Node 10 is recommended. The exact set of compatible Node versions can be found in the `engines` field of the `package.json` file. ```sh npm install @grpc/grpc-js diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 62bdd2ab6..e8e0fa3d2 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -1,7 +1,7 @@ { "name": "@grpc/grpc-js", - "version": "0.2.0", - "description": "gRPC Library for Node - pure JS core", + "version": "0.3.0", + "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", "main": "build/src/index.js", @@ -28,7 +28,6 @@ "name": "Google Inc." } ], - "_id": "@grpc/js-core@0.1.0", "scripts": { "build": "npm run compile", "clean": "gts clean", From 0c606f4408dff4433ab5987cf9a6a495d0691b87 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 9 Sep 2018 14:57:33 -0400 Subject: [PATCH 0379/1899] grpc-js-core: ignore reserved headers in fromHttp2Headers() Metadata.fromHttp2Headers() throws if any reserved headers are passed. Instead of deleting headers before calling the function, this commit causes the function to ignore reserved headers. --- packages/grpc-js-core/src/call-stream.ts | 3 +-- packages/grpc-js-core/src/metadata.ts | 5 +++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js-core/src/call-stream.ts index 20eca0235..840d7f2bc 100644 --- a/packages/grpc-js-core/src/call-stream.ts +++ b/packages/grpc-js-core/src/call-stream.ts @@ -233,8 +233,7 @@ export class Http2CallStream extends Duplex implements Call { default: this.mappedStatusCode = Status.UNKNOWN; } - delete headers[HTTP2_HEADER_STATUS]; - delete headers[HTTP2_HEADER_CONTENT_TYPE]; + if (flags & http2.constants.NGHTTP2_FLAG_END_STREAM) { this.handleTrailers(headers); } else { diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 48cfb6f30..574b549f4 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -197,6 +197,11 @@ export class Metadata { static fromHttp2Headers(headers: http2.IncomingHttpHeaders): Metadata { const result = new Metadata(); forOwn(headers, (values, key) => { + // Reserved headers (beginning with `:`) are not valid keys. + if (key.charAt(0) === ':') { + return; + } + if (isBinaryKey(key)) { if (Array.isArray(values)) { values.forEach((value) => { From 27338349a16a38a02d1d2ac0f122f18f462e5d21 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 9 Sep 2018 15:42:47 -0400 Subject: [PATCH 0380/1899] grpc-js-core: use Buffer.from in metadata cloning When cloning binary metadata, use Buffer.from() instead of Buffer.prototype.slice(), as the latter creates a new Buffer that shares the same underlying bytes. --- packages/grpc-js-core/src/metadata.ts | 4 +--- packages/grpc-js-core/test/test-metadata.ts | 10 ++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 48cfb6f30..ee4602f87 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -10,11 +10,9 @@ export interface MetadataObject { [key: string]: MetadataValue[]; } function cloneMetadataObject(repr: MetadataObject): MetadataObject { const result: MetadataObject = {}; forOwn(repr, (value, key) => { - // v.slice copies individual buffer values in value. - // TODO(kjin): Is this necessary result[key] = value.map(v => { if (v instanceof Buffer) { - return v.slice(); + return Buffer.from(v); } else { return v; } diff --git a/packages/grpc-js-core/test/test-metadata.ts b/packages/grpc-js-core/test/test-metadata.ts index 4dff735d8..d60bd2146 100644 --- a/packages/grpc-js-core/test/test-metadata.ts +++ b/packages/grpc-js-core/test/test-metadata.ts @@ -202,6 +202,16 @@ describe('Metadata', () => { copy.add('key', 'value2'); assert.deepEqual(metadata.get('key'), ['value1']); }); + + it('Copy cannot modify binary values in the original', () => { + const buf = Buffer.from('value-bin'); + metadata.add('key-bin', buf); + const copy = metadata.clone(); + const copyBuf = copy.get('key-bin')[0] as Buffer; + assert.deepStrictEqual(copyBuf, buf); + copyBuf.fill(0); + assert.notDeepEqual(copyBuf, buf); + }); }); describe('merge', () => { From 4ae503abeef0db5998b4f60b71343e51b9067283 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 10 Sep 2018 17:44:31 -0400 Subject: [PATCH 0381/1899] grpc-js-core: remove use of return await return await isn't typically useful in async functions. --- packages/grpc-js-core/src/compression-filter.ts | 2 +- packages/grpc-js-core/src/filter.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index e4ed9604d..6c874619f 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -185,7 +185,7 @@ export class CompressionFilter extends BaseFilter implements Filter { * compressed, and the output message is deframed and uncompressed. So * this is another reason that this filter should be at the bottom of the * filter stack. */ - return await this.receiveCompression.readMessage(await message); + return this.receiveCompression.readMessage(await message); } } diff --git a/packages/grpc-js-core/src/filter.ts b/packages/grpc-js-core/src/filter.ts index 28b05df88..22c5295c9 100644 --- a/packages/grpc-js-core/src/filter.ts +++ b/packages/grpc-js-core/src/filter.ts @@ -19,23 +19,23 @@ export interface Filter { export abstract class BaseFilter { async sendMetadata(metadata: Promise): Promise { - return await metadata; + return metadata; } async receiveMetadata(metadata: Promise): Promise { - return await metadata; + return metadata; } async sendMessage(message: Promise): Promise { - return await message; + return message; } async receiveMessage(message: Promise): Promise { - return await message; + return message; } async receiveTrailers(status: Promise): Promise { - return await status; + return status; } } From 8436abf2ea3a3526b704a04806423a16fb146ef9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 12 Sep 2018 10:37:36 -0700 Subject: [PATCH 0382/1899] Native: bump to 1.15.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 4b2791f51..f796f1aa8 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.15.0-pre1"' + 'GRPC_NODE_VERSION="1.15.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..edde2d4d8 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.15.0 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index d966465c5..b10f9eb89 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.15.0-pre1", + "version": "1.15.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 73a97f0aff8f0403e2864bda52382af6c95fabfa Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 13 Sep 2018 10:25:23 -0700 Subject: [PATCH 0383/1899] fix: use getRequestHeaders instead of getRequestMetadata --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/src/credentials.js | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9cb0cdaaa..2669ee0e1 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -39,7 +39,7 @@ "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", - "google-auth-library": "^0.9.2", + "google-auth-library": "^2.0.0", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", "lodash": "^4.17.4", diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 28b668b1d..3c05329e2 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -195,16 +195,17 @@ exports.createFromMetadataGenerator = function(metadata_generator) { exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; - google_credential.getRequestMetadata(service_url, function(err, header) { - if (err) { + google_credential.getRequestHeaders(service_url) + .then(function(header) { + var metadata = new Metadata(); + metadata.add('authorization', header.Authorization); + callback(null, metadata); + }) + .catch(function(err) { common.log(constants.logVerbosity.INFO, 'Auth error:' + err); callback(err); return; - } - var metadata = new Metadata(); - metadata.add('authorization', header.Authorization); - callback(null, metadata); - }); + }); }); }; From 2b291ed901b2c6bd26764417e774f55ddeea4296 Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 13 Sep 2018 10:37:58 -0700 Subject: [PATCH 0384/1899] revert package.json change --- packages/grpc-native-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 2669ee0e1..9cb0cdaaa 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -39,7 +39,7 @@ "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", - "google-auth-library": "^2.0.0", + "google-auth-library": "^0.9.2", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", "lodash": "^4.17.4", From 971ddc617ae8b801819f1aaa54e5b31006ebb2cd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 13 Sep 2018 11:31:03 -0700 Subject: [PATCH 0385/1899] Native: fix build instructions to account for move to new repo --- packages/grpc-native-core/README.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index 9b605e250..1dd78c8ce 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -14,6 +14,16 @@ Install the gRPC NPM package npm install grpc ``` +## BUILD FROM SOURCE + +The following command can be used to build from source when installing the package from npm: + +``` +npm install grpc --build-from-source +``` + +The `--build-from-source` option will work even when installing another package that depends on `grpc`. To build only `grpc` from source, you can use the argument `--build-from-source=grpc`. + ## ABOUT ELECTRON The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC. Please note that there's not just one way to get native extensions running in electron, and that there's never any silver bullet for anything. The following instructions try to cater about some of the most generic ways, but different edge cases might require different methodologies. @@ -34,9 +44,12 @@ npm rebuild --build-from-source=sqlite3 --target=2.0.0 --runtime=electron --dist This way, if you depend on both `grpc` and `sqlite3`, only the `sqlite3` package will be rebuilt from source, leaving the `grpc` package to use its precompiled binaries. -## BUILD FROM SOURCE - 1. Clone [the grpc Git Repository](https://github.com/grpc/grpc). - 2. Run `npm install --build-from-source` from the repository root. +## BUILD IN GIT REPOSITORY + + 1. Clone [the grpc-node Git Repository](https://github.com/grpc/grpc-node). + 2. Run `git submodule update --init --recursive` from the repository root. + 3. Run `cd packages/grpc-native-core`. + 4. Run `npm install --build-from-source`. - **Note:** On Windows, this might fail due to [nodejs issue #4932](https://github.com/nodejs/node/issues/4932) in which case, you will see something like the following in `npm install`'s output (towards the very beginning): From 4f39eae38c0ae532ece6dc2cfcd68b710239fba2 Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 13 Sep 2018 11:46:42 -0700 Subject: [PATCH 0386/1899] supporting both old and new versions of google-auth-library --- packages/grpc-native-core/src/credentials.js | 40 ++++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 3c05329e2..5a9dbfd45 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -184,6 +184,30 @@ exports.createFromMetadataGenerator = function(metadata_generator) { }); }; +function getAuthorizationHeaderFromGoogleCredential(google_credential, url, callback) { + // google-auth-library pre-v2.0.0 does not have getRequestHeaders + // but has getRequestMetadata, which is deprecated in v2.0.0 + if (typeof google_credential.getRequestHeaders === 'function') { + google_credential.getRequestHeaders(url) + .then(function(header) { + callback(null, header.Authorization); + }) + .catch(function(err) { + callback(err); + return; + }); + } + else { + google_credential.getRequestMetadata(url, function(err, header) { + if (err) { + callback(err); + return; + } + callback(null, header.Authorization); + }); + } +} + /** * Create a gRPC credential from a Google credential object. * @memberof grpc.credentials @@ -195,16 +219,16 @@ exports.createFromMetadataGenerator = function(metadata_generator) { exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; - google_credential.getRequestHeaders(service_url) - .then(function(header) { + getAuthorizationHeaderFromGoogleCredential(google_credential, service_url, + function(err, authHeader) { + if (err) { + common.log(constants.logVerbosity.INFO, 'Auth error:' + err); + callback(err); + return; + } var metadata = new Metadata(); - metadata.add('authorization', header.Authorization); + metadata.add('authorization', authHeader); callback(null, metadata); - }) - .catch(function(err) { - common.log(constants.logVerbosity.INFO, 'Auth error:' + err); - callback(err); - return; }); }); }; From 10c94a9e1e52411b1d5b135c1284f93f7a69445d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 Sep 2018 16:31:57 -0700 Subject: [PATCH 0387/1899] Fix indentation style --- packages/grpc-native-core/src/credentials.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 5a9dbfd45..50669b0d9 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -196,8 +196,7 @@ function getAuthorizationHeaderFromGoogleCredential(google_credential, url, call callback(err); return; }); - } - else { + } else { google_credential.getRequestMetadata(url, function(err, header) { if (err) { callback(err); From d78c49a648f4672919cca440067a43b7d466304c Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 13 Sep 2018 10:25:23 -0700 Subject: [PATCH 0388/1899] fix: use getRequestHeaders instead of getRequestMetadata --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/src/credentials.js | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index b10f9eb89..e079fdbd0 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -39,7 +39,7 @@ "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", - "google-auth-library": "^0.9.2", + "google-auth-library": "^2.0.0", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", "lodash": "^4.17.4", diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 28b668b1d..3c05329e2 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -195,16 +195,17 @@ exports.createFromMetadataGenerator = function(metadata_generator) { exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; - google_credential.getRequestMetadata(service_url, function(err, header) { - if (err) { + google_credential.getRequestHeaders(service_url) + .then(function(header) { + var metadata = new Metadata(); + metadata.add('authorization', header.Authorization); + callback(null, metadata); + }) + .catch(function(err) { common.log(constants.logVerbosity.INFO, 'Auth error:' + err); callback(err); return; - } - var metadata = new Metadata(); - metadata.add('authorization', header.Authorization); - callback(null, metadata); - }); + }); }); }; From 45185080f2bc4b946d9ebcc86dd7b05f915d17bf Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 13 Sep 2018 10:37:58 -0700 Subject: [PATCH 0389/1899] revert package.json change --- packages/grpc-native-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e079fdbd0..b10f9eb89 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -39,7 +39,7 @@ "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", - "google-auth-library": "^2.0.0", + "google-auth-library": "^0.9.2", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", "lodash": "^4.17.4", From 9eda26c0d797e04453b3736c9c5304b0762a8998 Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 13 Sep 2018 11:46:42 -0700 Subject: [PATCH 0390/1899] supporting both old and new versions of google-auth-library --- packages/grpc-native-core/src/credentials.js | 40 ++++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 3c05329e2..5a9dbfd45 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -184,6 +184,30 @@ exports.createFromMetadataGenerator = function(metadata_generator) { }); }; +function getAuthorizationHeaderFromGoogleCredential(google_credential, url, callback) { + // google-auth-library pre-v2.0.0 does not have getRequestHeaders + // but has getRequestMetadata, which is deprecated in v2.0.0 + if (typeof google_credential.getRequestHeaders === 'function') { + google_credential.getRequestHeaders(url) + .then(function(header) { + callback(null, header.Authorization); + }) + .catch(function(err) { + callback(err); + return; + }); + } + else { + google_credential.getRequestMetadata(url, function(err, header) { + if (err) { + callback(err); + return; + } + callback(null, header.Authorization); + }); + } +} + /** * Create a gRPC credential from a Google credential object. * @memberof grpc.credentials @@ -195,16 +219,16 @@ exports.createFromMetadataGenerator = function(metadata_generator) { exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; - google_credential.getRequestHeaders(service_url) - .then(function(header) { + getAuthorizationHeaderFromGoogleCredential(google_credential, service_url, + function(err, authHeader) { + if (err) { + common.log(constants.logVerbosity.INFO, 'Auth error:' + err); + callback(err); + return; + } var metadata = new Metadata(); - metadata.add('authorization', header.Authorization); + metadata.add('authorization', authHeader); callback(null, metadata); - }) - .catch(function(err) { - common.log(constants.logVerbosity.INFO, 'Auth error:' + err); - callback(err); - return; }); }); }; From ea6d903479998975c7fc20735c7bd06252c525f6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 Sep 2018 16:31:57 -0700 Subject: [PATCH 0391/1899] Fix indentation style --- packages/grpc-native-core/src/credentials.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 5a9dbfd45..50669b0d9 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -196,8 +196,7 @@ function getAuthorizationHeaderFromGoogleCredential(google_credential, url, call callback(err); return; }); - } - else { + } else { google_credential.getRequestMetadata(url, function(err, header) { if (err) { callback(err); From c855a47164a460944e475d4196e540181c8e7ca1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 14 Sep 2018 09:46:40 -0700 Subject: [PATCH 0392/1899] Native: bump to 1.15.1 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index f796f1aa8..fb0f5baed 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.15.0"' + 'GRPC_NODE_VERSION="1.15.1"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index edde2d4d8..1924a0d94 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.15.0 + node_version: 1.15.1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index b10f9eb89..70cb51ef6 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.15.0", + "version": "1.15.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From cd6e2062c8c2390f9e95566d2ef2a20f946cedbd Mon Sep 17 00:00:00 2001 From: Weiran Fang Date: Wed, 19 Sep 2018 17:50:43 -0700 Subject: [PATCH 0393/1899] Add checker for call invocation transformer. --- packages/grpc-native-core/src/client.js | 175 +++++++++++++++++++----- 1 file changed, 141 insertions(+), 34 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index b5436e4ec..6fcc68311 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -480,22 +480,51 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, metadata = metadata.clone(); + var callProperties = { + argument: argument, + metadata: metadata, + call: new ClientUnaryCall(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + callback: callback + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, - callback + methodDefinition, + callOptions, + interceptors, + callProperties.channel, + callProperties.callback ); - var emitter = new ClientUnaryCall(intercepting_call); + + var emitter = callProperties.call; + emitter.call = intercepting_call; + var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter, - callback + callProperties.callback ); - intercepting_call.start(metadata, last_listener); - intercepting_call.sendMessage(argument); + intercepting_call.start(callProperties.metadata, last_listener); + intercepting_call.sendMessage(callProperties.argument); intercepting_call.halfClose(); return emitter; @@ -555,21 +584,49 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, metadata = metadata.clone(); + var callProperties = { + metadata: metadata, + call: new ClientWritableStream(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + callback: callback + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, - callback + methodDefinition, + callOptions, + interceptors, + callProperties.channel, + callProperties.callback ); - var emitter = new ClientWritableStream(intercepting_call); + + var emitter = callProperties.call; + emitter.call = intercepting_call; + var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter, - callback + callProperties.callback ); - intercepting_call.start(metadata, last_listener); + intercepting_call.start(callProperties.metadata, last_listener); return emitter; }; @@ -613,22 +670,47 @@ Client.prototype.makeServerStreamRequest = function(path, serialize, metadata = metadata.clone(); - var emitter = new ClientReadableStream(); + var callProperties = { + argument: argument, + metadata: metadata, + call: new ClientReadableStream(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + + var emitter = callProperties.call; var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, + methodDefinition, + callOptions, + interceptors, + callProperties.channel, emitter ); emitter.call = intercepting_call; var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter ); - intercepting_call.start(metadata, last_listener); - intercepting_call.sendMessage(argument); + intercepting_call.start(callProperties.metadata, last_listener); + intercepting_call.sendMessage(callProperties.argument); intercepting_call.halfClose(); return emitter; @@ -669,21 +751,46 @@ Client.prototype.makeBidiStreamRequest = function(path, serialize, metadata = metadata.clone(); - var emitter = new ClientDuplexStream(); + var callProperties = { + metadata: metadata, + call: new ClientDuplexStream(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + + + var emitter = callProperties.call; var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, + methodDefinition, + callOptions, + interceptors, + callProperties.channel, emitter ); emitter.call = intercepting_call; var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter ); - intercepting_call.start(metadata, last_listener); + intercepting_call.start(callProperties.metadata, last_listener); return emitter; }; From 2d261f03a36191301e43b94f02d42fd87da12fdf Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Sep 2018 10:17:11 -0700 Subject: [PATCH 0394/1899] Copy protoc plugin files into grpc-tools --- packages/grpc-tools/src/config.h | 91 ++++++ packages/grpc-tools/src/config_protobuf.h | 95 ++++++ packages/grpc-tools/src/generator_helpers.h | 277 +++++++++++++++++ packages/grpc-tools/src/node_generator.cc | 278 ++++++++++++++++++ packages/grpc-tools/src/node_generator.h | 37 +++ .../grpc-tools/src/node_generator_helpers.h | 42 +++ packages/grpc-tools/src/node_plugin.cc | 78 +++++ 7 files changed, 898 insertions(+) create mode 100644 packages/grpc-tools/src/config.h create mode 100644 packages/grpc-tools/src/config_protobuf.h create mode 100644 packages/grpc-tools/src/generator_helpers.h create mode 100644 packages/grpc-tools/src/node_generator.cc create mode 100644 packages/grpc-tools/src/node_generator.h create mode 100644 packages/grpc-tools/src/node_generator_helpers.h create mode 100644 packages/grpc-tools/src/node_plugin.cc diff --git a/packages/grpc-tools/src/config.h b/packages/grpc-tools/src/config.h new file mode 100644 index 000000000..cfdc30362 --- /dev/null +++ b/packages/grpc-tools/src/config.h @@ -0,0 +1,91 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef SRC_COMPILER_CONFIG_H +#define SRC_COMPILER_CONFIG_H + +#include + +#ifndef GRPC_CUSTOM_CODEGENERATOR +#include +#define GRPC_CUSTOM_CODEGENERATOR ::google::protobuf::compiler::CodeGenerator +#define GRPC_CUSTOM_GENERATORCONTEXT \ + ::google::protobuf::compiler::GeneratorContext +#endif + +#ifndef GRPC_CUSTOM_PRINTER +#include +#include +#include +#define GRPC_CUSTOM_PRINTER ::google::protobuf::io::Printer +#define GRPC_CUSTOM_CODEDOUTPUTSTREAM ::google::protobuf::io::CodedOutputStream +#define GRPC_CUSTOM_STRINGOUTPUTSTREAM \ + ::google::protobuf::io::StringOutputStream +#endif + +#ifndef GRPC_CUSTOM_PLUGINMAIN +#include +#define GRPC_CUSTOM_PLUGINMAIN ::google::protobuf::compiler::PluginMain +#endif + +#ifndef GRPC_CUSTOM_PARSEGENERATORPARAMETER +#include +#define GRPC_CUSTOM_PARSEGENERATORPARAMETER \ + ::google::protobuf::compiler::ParseGeneratorParameter +#endif + +#ifndef GRPC_CUSTOM_STRING +#include +#define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +namespace protobuf { + +namespace compiler { +typedef GRPC_CUSTOM_CODEGENERATOR CodeGenerator; +typedef GRPC_CUSTOM_GENERATORCONTEXT GeneratorContext; +static inline int PluginMain(int argc, char* argv[], + const CodeGenerator* generator) { + return GRPC_CUSTOM_PLUGINMAIN(argc, argv, generator); +} +static inline void ParseGeneratorParameter( + const string& parameter, std::vector >* options) { + GRPC_CUSTOM_PARSEGENERATORPARAMETER(parameter, options); +} + +} // namespace compiler +namespace io { +typedef GRPC_CUSTOM_PRINTER Printer; +typedef GRPC_CUSTOM_CODEDOUTPUTSTREAM CodedOutputStream; +typedef GRPC_CUSTOM_STRINGOUTPUTSTREAM StringOutputStream; +} // namespace io +} // namespace protobuf +} // namespace grpc + +namespace grpc_cpp_generator { + +static const char* const kCppGeneratorMessageHeaderExt = ".pb.h"; +static const char* const kCppGeneratorServiceHeaderExt = ".grpc.pb.h"; + +} // namespace grpc_cpp_generator + +#endif // SRC_COMPILER_CONFIG_H diff --git a/packages/grpc-tools/src/config_protobuf.h b/packages/grpc-tools/src/config_protobuf.h new file mode 100644 index 000000000..94e593d1e --- /dev/null +++ b/packages/grpc-tools/src/config_protobuf.h @@ -0,0 +1,95 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H +#define GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H + +#define GRPC_OPEN_SOURCE_PROTO + +#ifndef GRPC_CUSTOM_PROTOBUF_INT64 +#include +#define GRPC_CUSTOM_PROTOBUF_INT64 ::google::protobuf::int64 +#endif + +#ifndef GRPC_CUSTOM_MESSAGE +#ifdef GRPC_USE_PROTO_LITE +#include +#define GRPC_CUSTOM_MESSAGE ::google::protobuf::MessageLite +#else +#include +#define GRPC_CUSTOM_MESSAGE ::google::protobuf::Message +#endif +#endif + +#ifndef GRPC_CUSTOM_DESCRIPTOR +#include +#include +#define GRPC_CUSTOM_DESCRIPTOR ::google::protobuf::Descriptor +#define GRPC_CUSTOM_DESCRIPTORPOOL ::google::protobuf::DescriptorPool +#define GRPC_CUSTOM_FIELDDESCRIPTOR ::google::protobuf::FieldDescriptor +#define GRPC_CUSTOM_FILEDESCRIPTOR ::google::protobuf::FileDescriptor +#define GRPC_CUSTOM_FILEDESCRIPTORPROTO ::google::protobuf::FileDescriptorProto +#define GRPC_CUSTOM_METHODDESCRIPTOR ::google::protobuf::MethodDescriptor +#define GRPC_CUSTOM_SERVICEDESCRIPTOR ::google::protobuf::ServiceDescriptor +#define GRPC_CUSTOM_SOURCELOCATION ::google::protobuf::SourceLocation +#endif + +#ifndef GRPC_CUSTOM_DESCRIPTORDATABASE +#include +#define GRPC_CUSTOM_DESCRIPTORDATABASE ::google::protobuf::DescriptorDatabase +#define GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE \ + ::google::protobuf::SimpleDescriptorDatabase +#endif + +#ifndef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM +#include +#include +#define GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM \ + ::google::protobuf::io::ZeroCopyOutputStream +#define GRPC_CUSTOM_ZEROCOPYINPUTSTREAM \ + ::google::protobuf::io::ZeroCopyInputStream +#define GRPC_CUSTOM_CODEDINPUTSTREAM ::google::protobuf::io::CodedInputStream +#endif + +namespace grpc { +namespace protobuf { + +typedef GRPC_CUSTOM_MESSAGE Message; +typedef GRPC_CUSTOM_PROTOBUF_INT64 int64; + +typedef GRPC_CUSTOM_DESCRIPTOR Descriptor; +typedef GRPC_CUSTOM_DESCRIPTORPOOL DescriptorPool; +typedef GRPC_CUSTOM_DESCRIPTORDATABASE DescriptorDatabase; +typedef GRPC_CUSTOM_FIELDDESCRIPTOR FieldDescriptor; +typedef GRPC_CUSTOM_FILEDESCRIPTOR FileDescriptor; +typedef GRPC_CUSTOM_FILEDESCRIPTORPROTO FileDescriptorProto; +typedef GRPC_CUSTOM_METHODDESCRIPTOR MethodDescriptor; +typedef GRPC_CUSTOM_SERVICEDESCRIPTOR ServiceDescriptor; +typedef GRPC_CUSTOM_SIMPLEDESCRIPTORDATABASE SimpleDescriptorDatabase; +typedef GRPC_CUSTOM_SOURCELOCATION SourceLocation; + +namespace io { +typedef GRPC_CUSTOM_ZEROCOPYOUTPUTSTREAM ZeroCopyOutputStream; +typedef GRPC_CUSTOM_ZEROCOPYINPUTSTREAM ZeroCopyInputStream; +typedef GRPC_CUSTOM_CODEDINPUTSTREAM CodedInputStream; +} // namespace io + +} // namespace protobuf +} // namespace grpc + +#endif // GRPCPP_IMPL_CODEGEN_CONFIG_PROTOBUF_H diff --git a/packages/grpc-tools/src/generator_helpers.h b/packages/grpc-tools/src/generator_helpers.h new file mode 100644 index 000000000..747096f06 --- /dev/null +++ b/packages/grpc-tools/src/generator_helpers.h @@ -0,0 +1,277 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H + +#include +#include +#include +#include +#include + +#include "src/compiler/config.h" + +namespace grpc_generator { + +inline bool StripSuffix(grpc::string* filename, const grpc::string& suffix) { + if (filename->length() >= suffix.length()) { + size_t suffix_pos = filename->length() - suffix.length(); + if (filename->compare(suffix_pos, grpc::string::npos, suffix) == 0) { + filename->resize(filename->size() - suffix.size()); + return true; + } + } + + return false; +} + +inline bool StripPrefix(grpc::string* name, const grpc::string& prefix) { + if (name->length() >= prefix.length()) { + if (name->substr(0, prefix.size()) == prefix) { + *name = name->substr(prefix.size()); + return true; + } + } + return false; +} + +inline grpc::string StripProto(grpc::string filename) { + if (!StripSuffix(&filename, ".protodevel")) { + StripSuffix(&filename, ".proto"); + } + return filename; +} + +inline grpc::string StringReplace(grpc::string str, const grpc::string& from, + const grpc::string& to, bool replace_all) { + size_t pos = 0; + + do { + pos = str.find(from, pos); + if (pos == grpc::string::npos) { + break; + } + str.replace(pos, from.length(), to); + pos += to.length(); + } while (replace_all); + + return str; +} + +inline grpc::string StringReplace(grpc::string str, const grpc::string& from, + const grpc::string& to) { + return StringReplace(str, from, to, true); +} + +inline std::vector tokenize(const grpc::string& input, + const grpc::string& delimiters) { + std::vector tokens; + size_t pos, last_pos = 0; + + for (;;) { + bool done = false; + pos = input.find_first_of(delimiters, last_pos); + if (pos == grpc::string::npos) { + done = true; + pos = input.length(); + } + + tokens.push_back(input.substr(last_pos, pos - last_pos)); + if (done) return tokens; + + last_pos = pos + 1; + } +} + +inline grpc::string CapitalizeFirstLetter(grpc::string s) { + if (s.empty()) { + return s; + } + s[0] = ::toupper(s[0]); + return s; +} + +inline grpc::string LowercaseFirstLetter(grpc::string s) { + if (s.empty()) { + return s; + } + s[0] = ::tolower(s[0]); + return s; +} + +inline grpc::string LowerUnderscoreToUpperCamel(grpc::string str) { + std::vector tokens = tokenize(str, "_"); + grpc::string result = ""; + for (unsigned int i = 0; i < tokens.size(); i++) { + result += CapitalizeFirstLetter(tokens[i]); + } + return result; +} + +inline grpc::string FileNameInUpperCamel( + const grpc::protobuf::FileDescriptor* file, bool include_package_path) { + std::vector tokens = tokenize(StripProto(file->name()), "/"); + grpc::string result = ""; + if (include_package_path) { + for (unsigned int i = 0; i < tokens.size() - 1; i++) { + result += tokens[i] + "/"; + } + } + result += LowerUnderscoreToUpperCamel(tokens.back()); + return result; +} + +inline grpc::string FileNameInUpperCamel( + const grpc::protobuf::FileDescriptor* file) { + return FileNameInUpperCamel(file, true); +} + +enum MethodType { + METHODTYPE_NO_STREAMING, + METHODTYPE_CLIENT_STREAMING, + METHODTYPE_SERVER_STREAMING, + METHODTYPE_BIDI_STREAMING +}; + +inline MethodType GetMethodType( + const grpc::protobuf::MethodDescriptor* method) { + if (method->client_streaming()) { + if (method->server_streaming()) { + return METHODTYPE_BIDI_STREAMING; + } else { + return METHODTYPE_CLIENT_STREAMING; + } + } else { + if (method->server_streaming()) { + return METHODTYPE_SERVER_STREAMING; + } else { + return METHODTYPE_NO_STREAMING; + } + } +} + +inline void Split(const grpc::string& s, char delim, + std::vector* append_to) { + std::istringstream iss(s); + grpc::string piece; + while (std::getline(iss, piece)) { + append_to->push_back(piece); + } +} + +enum CommentType { + COMMENTTYPE_LEADING, + COMMENTTYPE_TRAILING, + COMMENTTYPE_LEADING_DETACHED +}; + +// Get all the raw comments and append each line without newline to out. +template +inline void GetComment(const DescriptorType* desc, CommentType type, + std::vector* out) { + grpc::protobuf::SourceLocation location; + if (!desc->GetSourceLocation(&location)) { + return; + } + if (type == COMMENTTYPE_LEADING || type == COMMENTTYPE_TRAILING) { + const grpc::string& comments = type == COMMENTTYPE_LEADING + ? location.leading_comments + : location.trailing_comments; + Split(comments, '\n', out); + } else if (type == COMMENTTYPE_LEADING_DETACHED) { + for (unsigned int i = 0; i < location.leading_detached_comments.size(); + i++) { + Split(location.leading_detached_comments[i], '\n', out); + out->push_back(""); + } + } else { + std::cerr << "Unknown comment type " << type << std::endl; + abort(); + } +} + +// Each raw comment line without newline is appended to out. +// For file level leading and detached leading comments, we return comments +// above syntax line. Return nothing for trailing comments. +template <> +inline void GetComment(const grpc::protobuf::FileDescriptor* desc, + CommentType type, std::vector* out) { + if (type == COMMENTTYPE_TRAILING) { + return; + } + grpc::protobuf::SourceLocation location; + std::vector path; + path.push_back(grpc::protobuf::FileDescriptorProto::kSyntaxFieldNumber); + if (!desc->GetSourceLocation(path, &location)) { + return; + } + if (type == COMMENTTYPE_LEADING) { + Split(location.leading_comments, '\n', out); + } else if (type == COMMENTTYPE_LEADING_DETACHED) { + for (unsigned int i = 0; i < location.leading_detached_comments.size(); + i++) { + Split(location.leading_detached_comments[i], '\n', out); + out->push_back(""); + } + } else { + std::cerr << "Unknown comment type " << type << std::endl; + abort(); + } +} + +// Add prefix and newline to each comment line and concatenate them together. +// Make sure there is a space after the prefix unless the line is empty. +inline grpc::string GenerateCommentsWithPrefix( + const std::vector& in, const grpc::string& prefix) { + std::ostringstream oss; + for (auto it = in.begin(); it != in.end(); it++) { + const grpc::string& elem = *it; + if (elem.empty()) { + oss << prefix << "\n"; + } else if (elem[0] == ' ') { + oss << prefix << elem << "\n"; + } else { + oss << prefix << " " << elem << "\n"; + } + } + return oss.str(); +} + +template +inline grpc::string GetPrefixedComments(const DescriptorType* desc, + bool leading, + const grpc::string& prefix) { + std::vector out; + if (leading) { + grpc_generator::GetComment( + desc, grpc_generator::COMMENTTYPE_LEADING_DETACHED, &out); + std::vector leading; + grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_LEADING, + &leading); + out.insert(out.end(), leading.begin(), leading.end()); + } else { + grpc_generator::GetComment(desc, grpc_generator::COMMENTTYPE_TRAILING, + &out); + } + return GenerateCommentsWithPrefix(out, prefix); +} + +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_GENERATOR_HELPERS_H diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc new file mode 100644 index 000000000..a430628db --- /dev/null +++ b/packages/grpc-tools/src/node_generator.cc @@ -0,0 +1,278 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" +#include "src/compiler/node_generator.h" +#include "src/compiler/node_generator_helpers.h" + +using grpc::protobuf::Descriptor; +using grpc::protobuf::FileDescriptor; +using grpc::protobuf::MethodDescriptor; +using grpc::protobuf::ServiceDescriptor; +using grpc::protobuf::io::Printer; +using grpc::protobuf::io::StringOutputStream; +using std::map; + +namespace grpc_node_generator { +namespace { + +// Returns the alias we assign to the module of the given .proto filename +// when importing. Copied entirely from +// github:google/protobuf/src/google/protobuf/compiler/js/js_generator.cc#L154 +grpc::string ModuleAlias(const grpc::string filename) { + // This scheme could technically cause problems if a file includes any 2 of: + // foo/bar_baz.proto + // foo_bar_baz.proto + // foo_bar/baz.proto + // + // We'll worry about this problem if/when we actually see it. This name isn't + // exposed to users so we can change it later if we need to. + grpc::string basename = grpc_generator::StripProto(filename); + basename = grpc_generator::StringReplace(basename, "-", "$"); + basename = grpc_generator::StringReplace(basename, "/", "_"); + basename = grpc_generator::StringReplace(basename, ".", "_"); + return basename + "_pb"; +} + +// Given a filename like foo/bar/baz.proto, returns the corresponding JavaScript +// message file foo/bar/baz.js +grpc::string GetJSMessageFilename(const grpc::string& filename) { + grpc::string name = filename; + return grpc_generator::StripProto(name) + "_pb.js"; +} + +// Given a filename like foo/bar/baz.proto, returns the root directory +// path ../../ +grpc::string GetRootPath(const grpc::string& from_filename, + const grpc::string& to_filename) { + if (to_filename.find("google/protobuf") == 0) { + // Well-known types (.proto files in the google/protobuf directory) are + // assumed to come from the 'google-protobuf' npm package. We may want to + // generalize this exception later by letting others put generated code in + // their own npm packages. + return "google-protobuf/"; + } + size_t slashes = std::count(from_filename.begin(), from_filename.end(), '/'); + if (slashes == 0) { + return "./"; + } + grpc::string result = ""; + for (size_t i = 0; i < slashes; i++) { + result += "../"; + } + return result; +} + +// Return the relative path to load to_file from the directory containing +// from_file, assuming that both paths are relative to the same directory +grpc::string GetRelativePath(const grpc::string& from_file, + const grpc::string& to_file) { + return GetRootPath(from_file, to_file) + to_file; +} + +/* Finds all message types used in all services in the file, and returns them + * as a map of fully qualified message type name to message descriptor */ +map GetAllMessages( + const FileDescriptor* file) { + map message_types; + for (int service_num = 0; service_num < file->service_count(); + service_num++) { + const ServiceDescriptor* service = file->service(service_num); + for (int method_num = 0; method_num < service->method_count(); + method_num++) { + const MethodDescriptor* method = service->method(method_num); + const Descriptor* input_type = method->input_type(); + const Descriptor* output_type = method->output_type(); + message_types[input_type->full_name()] = input_type; + message_types[output_type->full_name()] = output_type; + } + } + return message_types; +} + +grpc::string MessageIdentifierName(const grpc::string& name) { + return grpc_generator::StringReplace(name, ".", "_"); +} + +grpc::string NodeObjectPath(const Descriptor* descriptor) { + grpc::string module_alias = ModuleAlias(descriptor->file()->name()); + grpc::string name = descriptor->full_name(); + grpc_generator::StripPrefix(&name, descriptor->file()->package() + "."); + return module_alias + "." + name; +} + +// Prints out the message serializer and deserializer functions +void PrintMessageTransformer(const Descriptor* descriptor, Printer* out, + const Parameters& params) { + map template_vars; + grpc::string full_name = descriptor->full_name(); + template_vars["identifier_name"] = MessageIdentifierName(full_name); + template_vars["name"] = full_name; + template_vars["node_name"] = NodeObjectPath(descriptor); + // Print the serializer + out->Print(template_vars, "function serialize_$identifier_name$(arg) {\n"); + out->Indent(); + out->Print(template_vars, "if (!(arg instanceof $node_name$)) {\n"); + out->Indent(); + out->Print(template_vars, + "throw new Error('Expected argument of type $name$');\n"); + out->Outdent(); + out->Print("}\n"); + if (params.minimum_node_version > 5) { + // Node version is > 5, we should use Buffer.from + out->Print("return Buffer.from(arg.serializeBinary());\n"); + } else { + out->Print("return new Buffer(arg.serializeBinary());\n"); + } + out->Outdent(); + out->Print("}\n\n"); + + // Print the deserializer + out->Print(template_vars, + "function deserialize_$identifier_name$(buffer_arg) {\n"); + out->Indent(); + out->Print( + template_vars, + "return $node_name$.deserializeBinary(new Uint8Array(buffer_arg));\n"); + out->Outdent(); + out->Print("}\n\n"); +} + +void PrintMethod(const MethodDescriptor* method, Printer* out) { + const Descriptor* input_type = method->input_type(); + const Descriptor* output_type = method->output_type(); + map vars; + vars["service_name"] = method->service()->full_name(); + vars["name"] = method->name(); + vars["input_type"] = NodeObjectPath(input_type); + vars["input_type_id"] = MessageIdentifierName(input_type->full_name()); + vars["output_type"] = NodeObjectPath(output_type); + vars["output_type_id"] = MessageIdentifierName(output_type->full_name()); + vars["client_stream"] = method->client_streaming() ? "true" : "false"; + vars["server_stream"] = method->server_streaming() ? "true" : "false"; + out->Print("{\n"); + out->Indent(); + out->Print(vars, "path: '/$service_name$/$name$',\n"); + out->Print(vars, "requestStream: $client_stream$,\n"); + out->Print(vars, "responseStream: $server_stream$,\n"); + out->Print(vars, "requestType: $input_type$,\n"); + out->Print(vars, "responseType: $output_type$,\n"); + out->Print(vars, "requestSerialize: serialize_$input_type_id$,\n"); + out->Print(vars, "requestDeserialize: deserialize_$input_type_id$,\n"); + out->Print(vars, "responseSerialize: serialize_$output_type_id$,\n"); + out->Print(vars, "responseDeserialize: deserialize_$output_type_id$,\n"); + out->Outdent(); + out->Print("}"); +} + +// Prints out the service descriptor object +void PrintService(const ServiceDescriptor* service, Printer* out) { + map template_vars; + out->Print(GetNodeComments(service, true).c_str()); + template_vars["name"] = service->name(); + out->Print(template_vars, "var $name$Service = exports.$name$Service = {\n"); + out->Indent(); + for (int i = 0; i < service->method_count(); i++) { + grpc::string method_name = + grpc_generator::LowercaseFirstLetter(service->method(i)->name()); + out->Print(GetNodeComments(service->method(i), true).c_str()); + out->Print("$method_name$: ", "method_name", method_name); + PrintMethod(service->method(i), out); + out->Print(",\n"); + out->Print(GetNodeComments(service->method(i), false).c_str()); + } + out->Outdent(); + out->Print("};\n\n"); + out->Print(template_vars, + "exports.$name$Client = " + "grpc.makeGenericClientConstructor($name$Service);\n"); + out->Print(GetNodeComments(service, false).c_str()); +} + +void PrintImports(const FileDescriptor* file, Printer* out) { + out->Print("var grpc = require('grpc');\n"); + if (file->message_type_count() > 0) { + grpc::string file_path = + GetRelativePath(file->name(), GetJSMessageFilename(file->name())); + out->Print("var $module_alias$ = require('$file_path$');\n", "module_alias", + ModuleAlias(file->name()), "file_path", file_path); + } + + for (int i = 0; i < file->dependency_count(); i++) { + grpc::string file_path = GetRelativePath( + file->name(), GetJSMessageFilename(file->dependency(i)->name())); + out->Print("var $module_alias$ = require('$file_path$');\n", "module_alias", + ModuleAlias(file->dependency(i)->name()), "file_path", + file_path); + } + out->Print("\n"); +} + +void PrintTransformers(const FileDescriptor* file, Printer* out, + const Parameters& params) { + map messages = GetAllMessages(file); + for (std::map::iterator it = + messages.begin(); + it != messages.end(); it++) { + PrintMessageTransformer(it->second, out, params); + } + out->Print("\n"); +} + +void PrintServices(const FileDescriptor* file, Printer* out) { + for (int i = 0; i < file->service_count(); i++) { + PrintService(file->service(i), out); + } +} +} // namespace + +grpc::string GenerateFile(const FileDescriptor* file, + const Parameters& params) { + grpc::string output; + { + StringOutputStream output_stream(&output); + Printer out(&output_stream, '$'); + + if (file->service_count() == 0) { + return output; + } + out.Print("// GENERATED CODE -- DO NOT EDIT!\n\n"); + + grpc::string leading_comments = GetNodeComments(file, true); + if (!leading_comments.empty()) { + out.Print("// Original file comments:\n"); + out.PrintRaw(leading_comments.c_str()); + } + + out.Print("'use strict';\n"); + + PrintImports(file, &out); + + PrintTransformers(file, &out, params); + + PrintServices(file, &out); + + out.Print(GetNodeComments(file, false).c_str()); + } + return output; +} + +} // namespace grpc_node_generator diff --git a/packages/grpc-tools/src/node_generator.h b/packages/grpc-tools/src/node_generator.h new file mode 100644 index 000000000..f3a531597 --- /dev/null +++ b/packages/grpc-tools/src/node_generator.h @@ -0,0 +1,37 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H + +#include "src/compiler/config.h" + +namespace grpc_node_generator { + +// Contains all the parameters that are parsed from the command line. +struct Parameters { + // Sets the earliest version of nodejs that needs to be supported. + int minimum_node_version; +}; + +grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file, + const Parameters& params); + +} // namespace grpc_node_generator + +#endif // GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H diff --git a/packages/grpc-tools/src/node_generator_helpers.h b/packages/grpc-tools/src/node_generator_helpers.h new file mode 100644 index 000000000..82d2d8454 --- /dev/null +++ b/packages/grpc-tools/src/node_generator_helpers.h @@ -0,0 +1,42 @@ +/* + * + * Copyright 2016 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H +#define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H + +#include + +#include "src/compiler/config.h" +#include "src/compiler/generator_helpers.h" + +namespace grpc_node_generator { + +inline grpc::string GetJSServiceFilename(const grpc::string& filename) { + return grpc_generator::StripProto(filename) + "_grpc_pb.js"; +} + +// Get leading or trailing comments in a string. Comment lines start with "// ". +// Leading detached comments are put in in front of leading comments. +template +inline grpc::string GetNodeComments(const DescriptorType* desc, bool leading) { + return grpc_generator::GetPrefixedComments(desc, leading, "//"); +} + +} // namespace grpc_node_generator + +#endif // GRPC_INTERNAL_COMPILER_NODE_GENERATOR_HELPERS_H diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc new file mode 100644 index 000000000..0d19d8e98 --- /dev/null +++ b/packages/grpc-tools/src/node_plugin.cc @@ -0,0 +1,78 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Generates Node gRPC service interface out of Protobuf IDL. + +#include + +#include "src/compiler/config.h" +#include "src/compiler/node_generator.h" +#include "src/compiler/node_generator_helpers.h" + +using grpc_node_generator::GenerateFile; +using grpc_node_generator::GetJSServiceFilename; + +class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { + public: + NodeGrpcGenerator() {} + ~NodeGrpcGenerator() {} + + bool Generate(const grpc::protobuf::FileDescriptor* file, + const grpc::string& parameter, + grpc::protobuf::compiler::GeneratorContext* context, + grpc::string* error) const { + grpc_node_generator::Parameters generator_parameters; + generator_parameters.minimum_node_version = 4; + + if (!parameter.empty()) { + std::vector parameters_list = + grpc_generator::tokenize(parameter, ","); + for (auto parameter_string = parameters_list.begin(); + parameter_string != parameters_list.end(); parameter_string++) { + std::vector param = + grpc_generator::tokenize(*parameter_string, "="); + if (param[0] == "minimum_node_version") { + sscanf(param[1].c_str(), "%d", + &generator_parameters.minimum_node_version); + } else { + *error = grpc::string("Unknown parameter: ") + *parameter_string; + return false; + } + } + } + + grpc::string code = GenerateFile(file, generator_parameters); + if (code.size() == 0) { + return true; + } + + // Get output file name + grpc::string file_name = GetJSServiceFilename(file->name()); + + std::unique_ptr output( + context->Open(file_name)); + grpc::protobuf::io::CodedOutputStream coded_out(output.get()); + coded_out.WriteRaw(code.data(), code.size()); + return true; + } +}; + +int main(int argc, char* argv[]) { + NodeGrpcGenerator generator; + return grpc::protobuf::compiler::PluginMain(argc, argv, &generator); +} From b50fd9b87ca1e0f3e0c49d0ce8198a3ea5a8be09 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Sep 2018 10:27:00 -0700 Subject: [PATCH 0395/1899] Fix include paths in protoc plugin files --- packages/grpc-tools/src/config.h | 2 +- packages/grpc-tools/src/generator_helpers.h | 2 +- packages/grpc-tools/src/node_generator.cc | 8 ++++---- packages/grpc-tools/src/node_generator.h | 2 +- packages/grpc-tools/src/node_generator_helpers.h | 4 ++-- packages/grpc-tools/src/node_plugin.cc | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/grpc-tools/src/config.h b/packages/grpc-tools/src/config.h index cfdc30362..7c7cc5d18 100644 --- a/packages/grpc-tools/src/config.h +++ b/packages/grpc-tools/src/config.h @@ -19,7 +19,7 @@ #ifndef SRC_COMPILER_CONFIG_H #define SRC_COMPILER_CONFIG_H -#include +#include "config_protobuf.h" #ifndef GRPC_CUSTOM_CODEGENERATOR #include diff --git a/packages/grpc-tools/src/generator_helpers.h b/packages/grpc-tools/src/generator_helpers.h index 747096f06..42959a082 100644 --- a/packages/grpc-tools/src/generator_helpers.h +++ b/packages/grpc-tools/src/generator_helpers.h @@ -25,7 +25,7 @@ #include #include -#include "src/compiler/config.h" +#include "config.h" namespace grpc_generator { diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index a430628db..abc72a9f6 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -18,10 +18,10 @@ #include -#include "src/compiler/config.h" -#include "src/compiler/generator_helpers.h" -#include "src/compiler/node_generator.h" -#include "src/compiler/node_generator_helpers.h" +#include "config.h" +#include "generator_helpers.h" +#include "node_generator.h" +#include "node_generator_helpers.h" using grpc::protobuf::Descriptor; using grpc::protobuf::FileDescriptor; diff --git a/packages/grpc-tools/src/node_generator.h b/packages/grpc-tools/src/node_generator.h index f3a531597..6070e8a8c 100644 --- a/packages/grpc-tools/src/node_generator.h +++ b/packages/grpc-tools/src/node_generator.h @@ -19,7 +19,7 @@ #ifndef GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H #define GRPC_INTERNAL_COMPILER_NODE_GENERATOR_H -#include "src/compiler/config.h" +#include "config.h" namespace grpc_node_generator { diff --git a/packages/grpc-tools/src/node_generator_helpers.h b/packages/grpc-tools/src/node_generator_helpers.h index 82d2d8454..191298482 100644 --- a/packages/grpc-tools/src/node_generator_helpers.h +++ b/packages/grpc-tools/src/node_generator_helpers.h @@ -21,8 +21,8 @@ #include -#include "src/compiler/config.h" -#include "src/compiler/generator_helpers.h" +#include "config.h" +#include "generator_helpers.h" namespace grpc_node_generator { diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index 0d19d8e98..d6cd55342 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -20,9 +20,9 @@ #include -#include "src/compiler/config.h" -#include "src/compiler/node_generator.h" -#include "src/compiler/node_generator_helpers.h" +#include "config.h" +#include "node_generator.h" +#include "node_generator_helpers.h" using grpc_node_generator::GenerateFile; using grpc_node_generator::GetJSServiceFilename; From 0646ef4afd49cf65466f5c336ca28dfbe116e09b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Sep 2018 10:32:27 -0700 Subject: [PATCH 0396/1899] Add protobuf submodule for grpc-tools --- .gitmodules | 3 +++ packages/grpc-tools/deps/protobuf | 1 + 2 files changed, 4 insertions(+) create mode 160000 packages/grpc-tools/deps/protobuf diff --git a/.gitmodules b/.gitmodules index 5d82e5297..ef8098be7 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "packages/grpc-native-core/deps/grpc"] path = packages/grpc-native-core/deps/grpc url = https://github.com/grpc/grpc.git +[submodule "packages/grpc-tools/deps/protobuf"] + path = packages/grpc-tools/deps/protobuf + url = https://github.com/protocolbuffers/protobuf diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf new file mode 160000 index 000000000..a6e1cc7e3 --- /dev/null +++ b/packages/grpc-tools/deps/protobuf @@ -0,0 +1 @@ +Subproject commit a6e1cc7e328c45a0cb9856c530c8f6cd23314163 From 8320743f6d0760ea2db171eb2c8c48a5710e6c1d Mon Sep 17 00:00:00 2001 From: Weiran Fang Date: Fri, 21 Sep 2018 09:48:51 -0700 Subject: [PATCH 0397/1899] Retrieve callInvocationTransformer from constructor options. --- packages/grpc-native-core/src/client.js | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 6fcc68311..cc061c52f 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -383,12 +383,16 @@ function Client(address, credentials, options) { .resolveInterceptorProviders(self.$interceptor_providers, method_definition) .concat(self.$interceptors); }); + + this.$callInvocationTransformer = options.callInvocationTransformer; + let channelOverride = options.channelOverride; let channelFactoryOverride = options.channelFactoryOverride; // Exclude channel options which have already been consumed var channel_options = _.omit(options, ['interceptors', 'interceptor_providers', - 'channelOverride', 'channelFactoryOverride']); + 'channelOverride', 'channelFactoryOverride', + 'callInvocationTransformer']); /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ if (channelOverride) { @@ -491,9 +495,8 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; @@ -594,9 +597,8 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; @@ -680,9 +682,8 @@ Client.prototype.makeServerStreamRequest = function(path, serialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; @@ -760,9 +761,8 @@ Client.prototype.makeBidiStreamRequest = function(path, serialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; From 6e87e48607a15b8cc4377ffefeba2e3ae9ec611c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 25 Sep 2018 12:54:13 -0400 Subject: [PATCH 0398/1899] grpc-js-core: delay composing credentials The channel and stream credentials may change between the time a CallCredentialsFilterFactory is created and the time that the metadata is sent. This commit delays composing the credentials until the time metadata is sent. --- .../src/call-credentials-filter.ts | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js-core/src/call-credentials-filter.ts index 95aee5920..b9f1d6bf2 100644 --- a/packages/grpc-js-core/src/call-credentials-filter.ts +++ b/packages/grpc-js-core/src/call-credentials-filter.ts @@ -7,10 +7,11 @@ import {Metadata} from './metadata'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; constructor( - private readonly credentials: CallCredentials, - private readonly host: string, private readonly path: string) { + private readonly channel: Http2Channel, private readonly stream: Call) { super(); - const splitPath: string[] = path.split('/'); + this.channel = channel; + this.stream = stream; + const splitPath: string[] = stream.getMethod().split('/'); let serviceName = ''; /* The standard path format is "/{serviceName}/{methodName}", so if we split * by '/', the first item should be empty and the second should be the @@ -20,12 +21,15 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { } /* Currently, call credentials are only allowed on HTTPS connections, so we * can assume that the scheme is "https" */ - this.serviceUrl = `https://${host}/${serviceName}`; + this.serviceUrl = `https://${stream.getHost()}/${serviceName}`; } async sendMetadata(metadata: Promise): Promise { + const channelCredentials = this.channel.credentials._getCallCredentials(); + const streamCredentials = this.stream.getCredentials(); + const credentials = channelCredentials.compose(streamCredentials); const credsMetadata = - this.credentials.generateMetadata({service_url: this.serviceUrl}); + credentials.generateMetadata({service_url: this.serviceUrl}); const resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; @@ -34,14 +38,12 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { export class CallCredentialsFilterFactory implements FilterFactory { - private readonly credentials: CallCredentials; + private readonly channel: Http2Channel; constructor(channel: Http2Channel) { - this.credentials = channel.credentials._getCallCredentials(); + this.channel = channel; } createFilter(callStream: Call): CallCredentialsFilter { - return new CallCredentialsFilter( - this.credentials.compose(callStream.getCredentials()), - callStream.getHost(), callStream.getMethod()); + return new CallCredentialsFilter(this.channel, callStream); } } From a3e71b3eeb53d24eb3c1f36e264646c0a5843185 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 25 Sep 2018 12:20:53 -0700 Subject: [PATCH 0399/1899] Fix missing property in ClientHttp2StreamMock --- packages/grpc-js-core/test/test-call-stream.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index 33a5991c0..c832bce99 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -43,6 +43,7 @@ class ClientHttp2StreamMock extends stream.Duplex implements aborted = false; closed = false; destroyed = false; + endAfterHeaders = false; pending = false; rstCode = 0; // tslint:disable:no-any From aea253cbec874a848839de8dcef64f5221302482 Mon Sep 17 00:00:00 2001 From: Weiran Fang Date: Wed, 26 Sep 2018 09:44:34 -0700 Subject: [PATCH 0400/1899] Add gitignore'd files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 231a29bd8..23866bfd4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,8 @@ packages/grpc-native-core/src/node/ .nyc_output/ reports/ + +package-lock.json + +# Test generated files +coverage From a1a74ca19a9e51c666125567d287129a76521663 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 26 Sep 2018 09:55:09 -0700 Subject: [PATCH 0401/1899] Add a jsdoc @deprecated for grpc.load. --- packages/grpc-native-core/index.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 3a1c9f79c..b01736b11 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -101,6 +101,8 @@ var loadObject = exports.loadObject; /** * Load a gRPC object from a .proto file. + * @deprecated Use the {@link https://www.npmjs.com/package/@grpc/proto-loader|proto-loader module} + with grpc.loadPackageDefinition instead. * @memberof grpc * @alias grpc.load * @param {string|{root: string, file: string}} filename The file to load @@ -376,4 +378,4 @@ exports.Channel = grpc.Channel; * {@link grpc.propagate} that indicates what information to propagate * from parentCall * @return {grpc~Call} - */ \ No newline at end of file + */ From 41c840d18601596c5c9ac64649bfa4d9fded70d7 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 26 Sep 2018 09:59:10 -0700 Subject: [PATCH 0402/1899] Add a link to protobufjs' documentation. --- packages/grpc-protobufjs/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md index 651da848f..4c986ded2 100644 --- a/packages/grpc-protobufjs/README.md +++ b/packages/grpc-protobufjs/README.md @@ -1,6 +1,8 @@ # gRPC Protobuf Loader A utility package for loading `.proto` files for use with gRPC, using the latest Protobuf.js package. +Please refer to [protobuf.js' documentation](https://github.com/dcodeIO/protobuf.js/blob/master/README.md) +to understands its usage and limitations. ## Installation From 696aafe19dacc3ca292bbb0ec249637cbcf2d66c Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 26 Sep 2018 11:11:34 -0700 Subject: [PATCH 0403/1899] s/usage/features/ --- packages/grpc-protobufjs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-protobufjs/README.md b/packages/grpc-protobufjs/README.md index 4c986ded2..481b86297 100644 --- a/packages/grpc-protobufjs/README.md +++ b/packages/grpc-protobufjs/README.md @@ -2,7 +2,7 @@ A utility package for loading `.proto` files for use with gRPC, using the latest Protobuf.js package. Please refer to [protobuf.js' documentation](https://github.com/dcodeIO/protobuf.js/blob/master/README.md) -to understands its usage and limitations. +to understands its features and limitations. ## Installation From 0203e65f23921439ad96d7061cf2115f24e6f411 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 26 Sep 2018 12:52:12 -0700 Subject: [PATCH 0404/1899] Bump @grpc/grpc-js to 0.3.1 --- packages/grpc-js-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index e8e0fa3d2..60cf09239 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.0", + "version": "0.3.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", From b4367cd3aba812fb26dbce83aa914c3fda79d6f0 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 27 Sep 2018 20:12:43 -0400 Subject: [PATCH 0405/1899] grpc-js-core: update compression flag byte offset The compression flag is written to the first byte, but read from the second byte. Update the read offset to match. --- packages/grpc-js-core/src/compression-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js-core/src/compression-filter.ts index 6c874619f..24d513dc4 100644 --- a/packages/grpc-js-core/src/compression-filter.ts +++ b/packages/grpc-js-core/src/compression-filter.ts @@ -29,7 +29,7 @@ abstract class CompressionHandler { * @return Uncompressed message */ async readMessage(data: Buffer): Promise { - const compressed = data.readUInt8(1) === 1; + const compressed = data.readUInt8(0) === 1; let messageBuffer = data.slice(5); if (compressed) { messageBuffer = await this.decompressMessage(messageBuffer); From 2f6484f63d36a937e355c94a4e89fc6001a064d1 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 28 Sep 2018 11:00:53 -0400 Subject: [PATCH 0406/1899] grpc-js-core: make semver a prod dependency semver is now used in index.ts, meaning that it needs to be included in the "dependencies" section of the package.json, otherwise deployments that use npm i --production will fail. --- packages/grpc-js-core/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 60cf09239..8eb2a2c63 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -20,7 +20,6 @@ "@types/node": "^10.5.4", "clang-format": "^1.0.55", "gts": "^0.5.1", - "semver": "^5.5.0", "typescript": "~2.7.0" }, "contributors": [ @@ -42,7 +41,8 @@ "posttest": "npm run check" }, "dependencies": { - "lodash": "^4.17.4" + "lodash": "^4.17.4", + "semver": "^5.5.0" }, "files": [ "build/src/*.{js,d.ts}" From 5683bc3bbaaa5decbb6141dfef2a18769cbd801c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 28 Sep 2018 13:42:19 -0700 Subject: [PATCH 0407/1899] Bump @grpc/grpc-js to 0.3.2 --- packages/grpc-js-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index 8eb2a2c63..b573a6fbf 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.1", + "version": "0.3.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", From 18c03d7d4b9820f647c538f993f7b379a8adecf5 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Fri, 28 Sep 2018 13:51:13 -0700 Subject: [PATCH 0408/1899] Create lock.yml --- .github/lock.yml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .github/lock.yml diff --git a/.github/lock.yml b/.github/lock.yml new file mode 100644 index 000000000..119e4840b --- /dev/null +++ b/.github/lock.yml @@ -0,0 +1,2 @@ +daysUntilLock: 90 +lockComment: false From 81a413cd84beca6e03c2e0e722113c52e0abb705 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 Oct 2018 15:43:18 -0700 Subject: [PATCH 0409/1899] Native: Use non-deprecated function to call checkServerIdentity cb --- packages/grpc-native-core/ext/channel_credentials.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index 6a2a1ddec..a586b3e61 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -78,7 +78,7 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert argv[1] = Nan::New(cert).ToLocalChecked(); } - Local result = callback->Call(argc, argv); + MaybeLocal result = Nan::Call(*callback, argc, argv); // Catch any exception and return with a distinct status code which indicates this if (try_catch.HasCaught()) { @@ -86,7 +86,7 @@ static int verify_peer_callback_wrapper(const char* servername, const char* cert } // If the result is an error, return a failure - if (result->IsNativeError()) { + if (result.ToLocalChecked()->IsNativeError()) { return 1; } From 0aedb0768ca8986864be60eb8f89536bebcd2e51 Mon Sep 17 00:00:00 2001 From: Max Vorobev Date: Sat, 13 Oct 2018 21:35:49 +0300 Subject: [PATCH 0410/1899] Generate JS file even if no services are defined in proto file; fix #574 --- packages/grpc-tools/src/node_generator.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index abc72a9f6..8fac3a529 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -252,6 +252,7 @@ grpc::string GenerateFile(const FileDescriptor* file, Printer out(&output_stream, '$'); if (file->service_count() == 0) { + output = "// GENERATED CODE -- NO SERVICES IN PROTO"; return output; } out.Print("// GENERATED CODE -- DO NOT EDIT!\n\n"); From 6e7035925dab4b78ad6056ea098fa387abfbaeb0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 17 Oct 2018 13:32:00 -0700 Subject: [PATCH 0411/1899] Bump submodule and version to 1.16.0-pre1 --- packages/grpc-native-core/binding.gyp | 7 ++++--- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 3 +-- packages/grpc-native-core/templates/package.json.template | 1 - 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b1947b9fd..6c0a986dc 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.15.0-dev"' + 'GRPC_NODE_VERSION="1.16.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -648,6 +648,7 @@ 'deps/grpc/src/core/lib/http/format_request.cc', 'deps/grpc/src/core/lib/http/httpcli.cc', 'deps/grpc/src/core/lib/http/parser.cc', + 'deps/grpc/src/core/lib/iomgr/buffer_list.cc', 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', 'deps/grpc/src/core/lib/iomgr/combiner.cc', 'deps/grpc/src/core/lib/iomgr/endpoint.cc', @@ -657,7 +658,6 @@ 'deps/grpc/src/core/lib/iomgr/error.cc', 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.cc', - 'deps/grpc/src/core/lib/iomgr/ev_epollsig_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.cc', 'deps/grpc/src/core/lib/iomgr/ev_posix.cc', 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', @@ -668,6 +668,7 @@ 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', + 'deps/grpc/src/core/lib/iomgr/internal_errqueue.cc', 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', 'deps/grpc/src/core/lib/iomgr/iomgr.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', @@ -929,7 +930,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'deps/grpc/src/cpp/ext/filters/census/grpc_context.cc', + 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 8ba456362..bc9e9ddf9 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 8ba45636295019b101c1e9579423d4de41c4c59e +Subproject commit bc9e9ddf9e04b1a905d51c41b1ffef5b30f2c986 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9cb0cdaaa..efb394eee 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.15.0-dev", + "version": "1.16.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", @@ -68,7 +68,6 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/src/cpp/ext/filters/census/grpc_context.cc", "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index bd72b72a1..b4474a2eb 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -70,7 +70,6 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/src/cpp/ext/filters/census/grpc_context.cc", "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", From 6364d0a92f72afe364b2bdf74f392fc782aa4305 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 17 Oct 2018 15:33:57 -0700 Subject: [PATCH 0412/1899] @grpc/proto-loader: Fix absolute path handling and improve reporting of loading failures --- packages/grpc-protobufjs/src/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/grpc-protobufjs/src/index.ts index bb7577627..099f990ce 100644 --- a/packages/grpc-protobufjs/src/index.ts +++ b/packages/grpc-protobufjs/src/index.ts @@ -119,6 +119,9 @@ function createPackageDefinition(root: Protobuf.Root, options: Options): Package function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { root.resolvePath = (origin: string, target: string) => { + if (path.isAbsolute(target)) { + return target; + } for (const directory of includePaths) { const fullPath: string = path.join(directory, target); try { @@ -128,7 +131,7 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { continue; } } - return null; + throw new Error(`Could not find file ${target}`); }; } From 21d9ea086c9b40d20543be1883940127c944c068 Mon Sep 17 00:00:00 2001 From: Weiran Fang Date: Wed, 19 Sep 2018 17:50:43 -0700 Subject: [PATCH 0413/1899] Add checker for call invocation transformer. --- packages/grpc-native-core/src/client.js | 175 +++++++++++++++++++----- 1 file changed, 141 insertions(+), 34 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index b5436e4ec..6fcc68311 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -480,22 +480,51 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, metadata = metadata.clone(); + var callProperties = { + argument: argument, + metadata: metadata, + call: new ClientUnaryCall(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + callback: callback + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, - callback + methodDefinition, + callOptions, + interceptors, + callProperties.channel, + callProperties.callback ); - var emitter = new ClientUnaryCall(intercepting_call); + + var emitter = callProperties.call; + emitter.call = intercepting_call; + var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter, - callback + callProperties.callback ); - intercepting_call.start(metadata, last_listener); - intercepting_call.sendMessage(argument); + intercepting_call.start(callProperties.metadata, last_listener); + intercepting_call.sendMessage(callProperties.argument); intercepting_call.halfClose(); return emitter; @@ -555,21 +584,49 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, metadata = metadata.clone(); + var callProperties = { + metadata: metadata, + call: new ClientWritableStream(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + callback: callback + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, - callback + methodDefinition, + callOptions, + interceptors, + callProperties.channel, + callProperties.callback ); - var emitter = new ClientWritableStream(intercepting_call); + + var emitter = callProperties.call; + emitter.call = intercepting_call; + var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter, - callback + callProperties.callback ); - intercepting_call.start(metadata, last_listener); + intercepting_call.start(callProperties.metadata, last_listener); return emitter; }; @@ -613,22 +670,47 @@ Client.prototype.makeServerStreamRequest = function(path, serialize, metadata = metadata.clone(); - var emitter = new ClientReadableStream(); + var callProperties = { + argument: argument, + metadata: metadata, + call: new ClientReadableStream(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + + var emitter = callProperties.call; var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, + methodDefinition, + callOptions, + interceptors, + callProperties.channel, emitter ); emitter.call = intercepting_call; var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter ); - intercepting_call.start(metadata, last_listener); - intercepting_call.sendMessage(argument); + intercepting_call.start(callProperties.metadata, last_listener); + intercepting_call.sendMessage(callProperties.argument); intercepting_call.halfClose(); return emitter; @@ -669,21 +751,46 @@ Client.prototype.makeBidiStreamRequest = function(path, serialize, metadata = metadata.clone(); - var emitter = new ClientDuplexStream(); + var callProperties = { + metadata: metadata, + call: new ClientDuplexStream(), + channel: this.$channel, + methodDefinition: method_definition, + callOptions: options, + }; + + // Transform call properties if specified. + var callInvocationTransformer = options.callInvocationTransformer; + if (callInvocationTransformer) { + callProperties = callInvocationTransformer(callProperties); + } + + var callOptions = callProperties.callOptions; + var methodDefinition = callProperties.methodDefinition; + + var interceptors = Client.prototype.resolveCallInterceptors.call( + this, + methodDefinition, + callOptions.interceptors, + callOptions.interceptor_providers + ); + + + var emitter = callProperties.call; var intercepting_call = client_interceptors.getInterceptingCall( - method_definition, - options, - Client.prototype.resolveCallInterceptors.call(this, method_definition, options.interceptors, options.interceptor_providers), - this.$channel, + methodDefinition, + callOptions, + interceptors, + callProperties.channel, emitter ); emitter.call = intercepting_call; var last_listener = client_interceptors.getLastListener( - method_definition, + methodDefinition, emitter ); - intercepting_call.start(metadata, last_listener); + intercepting_call.start(callProperties.metadata, last_listener); return emitter; }; From a8eaafe37366843db3c0c1ec475d6de1524764f3 Mon Sep 17 00:00:00 2001 From: Weiran Fang Date: Fri, 21 Sep 2018 09:48:51 -0700 Subject: [PATCH 0414/1899] Retrieve callInvocationTransformer from constructor options. --- packages/grpc-native-core/src/client.js | 26 ++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 6fcc68311..cc061c52f 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -383,12 +383,16 @@ function Client(address, credentials, options) { .resolveInterceptorProviders(self.$interceptor_providers, method_definition) .concat(self.$interceptors); }); + + this.$callInvocationTransformer = options.callInvocationTransformer; + let channelOverride = options.channelOverride; let channelFactoryOverride = options.channelFactoryOverride; // Exclude channel options which have already been consumed var channel_options = _.omit(options, ['interceptors', 'interceptor_providers', - 'channelOverride', 'channelFactoryOverride']); + 'channelOverride', 'channelFactoryOverride', + 'callInvocationTransformer']); /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ if (channelOverride) { @@ -491,9 +495,8 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; @@ -594,9 +597,8 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; @@ -680,9 +682,8 @@ Client.prototype.makeServerStreamRequest = function(path, serialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; @@ -760,9 +761,8 @@ Client.prototype.makeBidiStreamRequest = function(path, serialize, }; // Transform call properties if specified. - var callInvocationTransformer = options.callInvocationTransformer; - if (callInvocationTransformer) { - callProperties = callInvocationTransformer(callProperties); + if (this.$callInvocationTransformer) { + callProperties = this.$callInvocationTransformer(callProperties); } var callOptions = callProperties.callOptions; From 8821824f7afa2fe76c581fe559c9be74e054ffa0 Mon Sep 17 00:00:00 2001 From: Weiran Fang Date: Wed, 26 Sep 2018 09:44:34 -0700 Subject: [PATCH 0415/1899] Add gitignore'd files --- .gitignore | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 231a29bd8..23866bfd4 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,8 @@ packages/grpc-native-core/src/node/ .nyc_output/ reports/ + +package-lock.json + +# Test generated files +coverage From 5b85f4f2b782e778dbb266e36152da39c78a556d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 19 Oct 2018 11:21:45 -0700 Subject: [PATCH 0416/1899] Native: add Server#bindAsync --- packages/grpc-native-core/src/server.js | 29 ++++++++++++++++++++ packages/grpc-native-core/test/async_test.js | 14 ++++++---- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index b238de048..34c123d1b 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -954,6 +954,7 @@ Server.prototype.addProtoService = util.deprecate(function(service, * "address:port" * @param {grpc.ServerCredentials} creds Server credential object to be used for * SSL. Pass an insecure credentials object for an insecure port. + * @return {number} The bound port number. Negative if binding the port failed. */ Server.prototype.bind = function(port, creds) { if (this.started) { @@ -962,4 +963,32 @@ Server.prototype.bind = function(port, creds) { return this._server.addHttp2Port(port, creds); }; +/** + * Called with the result of attempting to bind a port + * @callback grpc.Server~bindCallback + * @param {Error=} error If non-null, indicates that binding the port failed. + * @param {number} port The bound port number. If binding the port fails, this + * will be negative to match the output of bind. + */ + +/** + * Binds the server to the given port, with SSL disabled if creds is an + * insecure credentials object. Provides the result asynchronously. + * @param {string} port The port that the server should bind on, in the format + * "address:port" + * @param {grpc.ServerCredentials} creds Server credential object to be used for + * SSL. Pass an insecure credentials object for an insecure port. + */ +Server.prototype.bindAsync = function(port, creds, callback) { + /* This can throw. We do not try to catch that error because it indicates an + * incorrect use of the function, which should not be surfaced asynchronously + */ + const result = this.bind(port, creds) + if (result < 0) { + setImmediate(callback, new Error('Failed to bind port'), result); + } else { + setImmediate(callback, null, result); + } +} + exports.Server = Server; diff --git a/packages/grpc-native-core/test/async_test.js b/packages/grpc-native-core/test/async_test.js index 786e50bfd..400baa9e2 100644 --- a/packages/grpc-native-core/test/async_test.js +++ b/packages/grpc-native-core/test/async_test.js @@ -37,14 +37,16 @@ var getServer = require('./math/math_server.js'); var server = getServer(); +let serverCreds = grpc.ServerCredentials.createInsecure(); + describe('Async functionality', function() { before(function(done) { - var port_num = server.bind('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - server.start(); - math_client = new math.Math('localhost:' + port_num, - grpc.credentials.createInsecure()); - done(); + server.bind('0.0.0.0:0', serverCreds, (error, port_num) => { + server.start(); + math_client = new math.Math('localhost:' + port_num, + grpc.credentials.createInsecure()); + done(); + }); }); after(function() { grpc.closeClient(math_client); From 2d62b875f40147a908037372be694c3c89a561c5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 19 Oct 2018 11:54:47 -0700 Subject: [PATCH 0417/1899] Actually use bindAsync in modified test --- packages/grpc-native-core/test/async_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/async_test.js b/packages/grpc-native-core/test/async_test.js index 400baa9e2..119d20ceb 100644 --- a/packages/grpc-native-core/test/async_test.js +++ b/packages/grpc-native-core/test/async_test.js @@ -41,7 +41,7 @@ let serverCreds = grpc.ServerCredentials.createInsecure(); describe('Async functionality', function() { before(function(done) { - server.bind('0.0.0.0:0', serverCreds, (error, port_num) => { + server.bindAsync('0.0.0.0:0', serverCreds, (error, port_num) => { server.start(); math_client = new math.Math('localhost:' + port_num, grpc.credentials.createInsecure()); From 34219900a99473acf8f3e58b1f235c8849298441 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 23 Oct 2018 18:45:22 +0200 Subject: [PATCH 0418/1899] Properly updating submodule to point at 1.16. --- packages/grpc-native-core/binding.gyp | 7 ++++--- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b1947b9fd..6c0a986dc 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.15.0-dev"' + 'GRPC_NODE_VERSION="1.16.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -648,6 +648,7 @@ 'deps/grpc/src/core/lib/http/format_request.cc', 'deps/grpc/src/core/lib/http/httpcli.cc', 'deps/grpc/src/core/lib/http/parser.cc', + 'deps/grpc/src/core/lib/iomgr/buffer_list.cc', 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', 'deps/grpc/src/core/lib/iomgr/combiner.cc', 'deps/grpc/src/core/lib/iomgr/endpoint.cc', @@ -657,7 +658,6 @@ 'deps/grpc/src/core/lib/iomgr/error.cc', 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.cc', - 'deps/grpc/src/core/lib/iomgr/ev_epollsig_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.cc', 'deps/grpc/src/core/lib/iomgr/ev_posix.cc', 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', @@ -668,6 +668,7 @@ 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', + 'deps/grpc/src/core/lib/iomgr/internal_errqueue.cc', 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', 'deps/grpc/src/core/lib/iomgr/iomgr.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', @@ -929,7 +930,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'deps/grpc/src/cpp/ext/filters/census/grpc_context.cc', + 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..92c958cdd 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.16.0-pre1 \ No newline at end of file diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 8ba456362..98457b76f 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 8ba45636295019b101c1e9579423d4de41c4c59e +Subproject commit 98457b76ff43efa2c3edd203c14cd923734d5279 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9cb0cdaaa..73f7698f4 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.15.0-dev", + "version": "1.16.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 14a1f8520c0acc4d72e857e17ead3f91f53becb0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 23 Oct 2018 15:55:47 -0700 Subject: [PATCH 0419/1899] Update grpc submodule to HEAD --- packages/grpc-native-core/binding.gyp | 8 ++++++-- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 6c0a986dc..77db2d420 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.16.0-pre1"' + 'GRPC_NODE_VERSION="1.17.0-dev"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -914,10 +914,14 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc', + 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index bc9e9ddf9..5984e9daf 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit bc9e9ddf9e04b1a905d51c41b1ffef5b30f2c986 +Subproject commit 5984e9daf26123bab25279f74e43d60908f199bf diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index efb394eee..ccb457708 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.16.0-pre1", + "version": "1.17.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 3eb67d8038e5ceb01a0520148e6ebb62786ac564 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Oct 2018 10:38:25 -0700 Subject: [PATCH 0420/1899] Remove use of OPENSSL_NO_THREADS with BoringSSL --- packages/grpc-native-core/binding.gyp | 8 ++------ packages/grpc-native-core/templates/binding.gyp.template | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 6c0a986dc..3e858e187 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,8 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.16.0-pre1"' + 'GRPC_NODE_VERSION="1.16.0-pre1"', + '_XOPEN_SOURCE=500' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -118,11 +119,6 @@ 'GPR_MUSL_LIBC_COMPAT' ] }], - ['OS!="win" and runtime=="electron"', { - "defines": [ - 'OPENSSL_NO_THREADS' - ] - }], # This is the condition for using boringssl ['OS=="win" or runtime=="electron"', { "include_dirs": [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index f9abaa7c3..a9ba85075 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -83,7 +83,8 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"' + 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"', + '_XOPEN_SOURCE=500' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -102,11 +103,6 @@ 'GPR_MUSL_LIBC_COMPAT' ] }], - ['OS!="win" and runtime=="electron"', { - "defines": [ - 'OPENSSL_NO_THREADS' - ] - }], # This is the condition for using boringssl ['OS=="win" or runtime=="electron"', { "include_dirs": [ From b7f7bf0dce62a901326bb01022f122de6ccdab2c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Oct 2018 11:00:25 -0700 Subject: [PATCH 0421/1899] Increase _XOPEN_SOURCE macro to 700 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/templates/binding.gyp.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 3e858e187..60b796263 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -92,7 +92,7 @@ 'GRPC_ARES=0', 'GRPC_UV', 'GRPC_NODE_VERSION="1.16.0-pre1"', - '_XOPEN_SOURCE=500' + '_XOPEN_SOURCE=700' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index a9ba85075..56dc446e0 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -84,7 +84,7 @@ 'GRPC_ARES=0', 'GRPC_UV', 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"', - '_XOPEN_SOURCE=500' + '_XOPEN_SOURCE=700' ], 'conditions': [ ['grpc_gcov=="true"', { From 6a19cf5205cec8d9794b85cdb2175ecd56493ff4 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 24 Oct 2018 11:50:45 -0400 Subject: [PATCH 0422/1899] grpc-js-core: use Map for metadata store In more recent versions of Node, Maps are more performant than POJOs when used as maps. Switching to Maps also eliminates an expensive delete operation, as well as uses of hasOwnProperty(). --- packages/grpc-js-core/src/metadata.ts | 47 +++++++++++---------- packages/grpc-js-core/test/test-metadata.ts | 23 +++++----- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index 05c1e4ec7..df3203fb6 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -4,19 +4,21 @@ const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; export type MetadataValue = string|Buffer; - -export interface MetadataObject { [key: string]: MetadataValue[]; } +export type MetadataObject = Map; function cloneMetadataObject(repr: MetadataObject): MetadataObject { - const result: MetadataObject = {}; - forOwn(repr, (value, key) => { - result[key] = value.map(v => { + const result: MetadataObject = new Map(); + + repr.forEach((value, key) => { + const clonedValue: MetadataValue[] = value.map(v => { if (v instanceof Buffer) { return Buffer.from(v); } else { return v; } }); + + result.set(key, clonedValue); }); return result; } @@ -64,7 +66,7 @@ function validate(key: string, value?: MetadataValue): void { * A class for storing metadata. Keys are normalized to lowercase ASCII. */ export class Metadata { - protected internalRepr: MetadataObject = {}; + protected internalRepr: MetadataObject = new Map(); /** * Sets the given value for the given key by replacing any other values @@ -76,7 +78,7 @@ export class Metadata { set(key: string, value: MetadataValue): void { key = normalizeKey(key); validate(key, value); - this.internalRepr[key] = [value]; + this.internalRepr.set(key, [value]); } /** @@ -89,10 +91,13 @@ export class Metadata { add(key: string, value: MetadataValue): void { key = normalizeKey(key); validate(key, value); - if (!this.internalRepr[key]) { - this.internalRepr[key] = [value]; + + const existingValue: MetadataValue[]|undefined = this.internalRepr.get(key); + + if (existingValue === undefined) { + this.internalRepr.set(key, [value]); } else { - this.internalRepr[key].push(value); + existingValue.push(value); } } @@ -103,9 +108,7 @@ export class Metadata { remove(key: string): void { key = normalizeKey(key); validate(key); - if (Object.prototype.hasOwnProperty.call(this.internalRepr, key)) { - delete this.internalRepr[key]; - } + this.internalRepr.delete(key); } /** @@ -116,11 +119,7 @@ export class Metadata { get(key: string): MetadataValue[] { key = normalizeKey(key); validate(key); - if (Object.prototype.hasOwnProperty.call(this.internalRepr, key)) { - return this.internalRepr[key]; - } else { - return []; - } + return this.internalRepr.get(key) || []; } /** @@ -130,7 +129,8 @@ export class Metadata { */ getMap(): {[key: string]: MetadataValue} { const result: {[key: string]: MetadataValue} = {}; - forOwn(this.internalRepr, (values, key) => { + + this.internalRepr.forEach((values, key) => { if (values.length > 0) { const v = values[0]; result[key] = v instanceof Buffer ? v.slice() : v; @@ -157,8 +157,11 @@ export class Metadata { * @param other A Metadata object. */ merge(other: Metadata): void { - forOwn(other.internalRepr, (values, key) => { - this.internalRepr[key] = (this.internalRepr[key] || []).concat(values); + other.internalRepr.forEach((values, key) => { + const mergedValue: MetadataValue[] = + (this.internalRepr.get(key) || []).concat(values); + + this.internalRepr.set(key, mergedValue); }); } @@ -168,7 +171,7 @@ export class Metadata { toHttp2Headers(): http2.OutgoingHttpHeaders { // NOTE: Node <8.9 formats http2 headers incorrectly. const result: http2.OutgoingHttpHeaders = {}; - forOwn(this.internalRepr, (values, key) => { + this.internalRepr.forEach((values, key) => { // We assume that the user's interaction with this object is limited to // through its public API (i.e. keys and values are already validated). result[key] = values.map((value) => { diff --git a/packages/grpc-js-core/test/test-metadata.ts b/packages/grpc-js-core/test/test-metadata.ts index d60bd2146..f5e4d80cd 100644 --- a/packages/grpc-js-core/test/test-metadata.ts +++ b/packages/grpc-js-core/test/test-metadata.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; import * as http2 from 'http2'; import {range} from 'lodash'; -import {Metadata} from '../src/metadata'; +import {Metadata, MetadataObject, MetadataValue} from '../src/metadata'; class TestMetadata extends Metadata { getInternalRepresentation() { @@ -277,21 +277,24 @@ describe('Metadata', () => { }; const metadataFromHeaders = TestMetadata.fromHttp2Headers(headers); const internalRepr = metadataFromHeaders.getInternalRepresentation(); - assert.deepEqual(internalRepr, { - key1: ['value1'], - key2: ['value2'], - key3: ['value3a', 'value3b'], - 'key-bin': [ - Buffer.from(range(0, 16)), Buffer.from(range(16, 32)), - Buffer.from(range(0, 32)) + const expected: MetadataObject = new Map([ + ['key1', ['value1']], ['key2', ['value2']], + ['key3', ['value3a', 'value3b']], + [ + 'key-bin', + [ + Buffer.from(range(0, 16)), Buffer.from(range(16, 32)), + Buffer.from(range(0, 32)) + ] ] - }); + ]); + assert.deepEqual(internalRepr, expected); }); it('creates an empty Metadata object from empty headers', () => { const metadataFromHeaders = TestMetadata.fromHttp2Headers({}); const internalRepr = metadataFromHeaders.getInternalRepresentation(); - assert.deepEqual(internalRepr, {}); + assert.deepEqual(internalRepr, new Map()); }); }); }); From 2f679031fa4437f2f55ce4d1dbf72030dc5068cf Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 24 Oct 2018 12:00:41 -0400 Subject: [PATCH 0423/1899] grpc-js-core: remove metadata's lodash dependency This removes the only remaining use of lodash in Metadata and improves performance a bit. --- packages/grpc-js-core/src/metadata.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index df3203fb6..b836bb1ab 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -1,5 +1,4 @@ import * as http2 from 'http2'; -import {forOwn} from 'lodash'; const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; @@ -197,12 +196,14 @@ export class Metadata { */ static fromHttp2Headers(headers: http2.IncomingHttpHeaders): Metadata { const result = new Metadata(); - forOwn(headers, (values, key) => { + Object.keys(headers).forEach((key) => { // Reserved headers (beginning with `:`) are not valid keys. if (key.charAt(0) === ':') { return; } + const values = headers[key]; + if (isBinaryKey(key)) { if (Array.isArray(values)) { values.forEach((value) => { From a83c92480195e5eed980204540bd3fb460c8d847 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 24 Oct 2018 12:09:57 -0400 Subject: [PATCH 0424/1899] grpc-js-core: simplify Metadata clone() This commit inlines the only use of cloneMetadataObject(). It also eliminates an extra MetadataObject - the result of cloneMetadataObject() was allocating a new MetadataObject to replace the internal representation of the newly allocated Metadata object in clone(). --- packages/grpc-js-core/src/metadata.ts | 32 ++++++++++++--------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js-core/src/metadata.ts index b836bb1ab..09a6f8832 100644 --- a/packages/grpc-js-core/src/metadata.ts +++ b/packages/grpc-js-core/src/metadata.ts @@ -5,23 +5,6 @@ const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; export type MetadataValue = string|Buffer; export type MetadataObject = Map; -function cloneMetadataObject(repr: MetadataObject): MetadataObject { - const result: MetadataObject = new Map(); - - repr.forEach((value, key) => { - const clonedValue: MetadataValue[] = value.map(v => { - if (v instanceof Buffer) { - return Buffer.from(v); - } else { - return v; - } - }); - - result.set(key, clonedValue); - }); - return result; -} - function isLegalKey(key: string): boolean { return LEGAL_KEY_REGEX.test(key); } @@ -144,7 +127,20 @@ export class Metadata { */ clone(): Metadata { const newMetadata = new Metadata(); - newMetadata.internalRepr = cloneMetadataObject(this.internalRepr); + const newInternalRepr = newMetadata.internalRepr; + + this.internalRepr.forEach((value, key) => { + const clonedValue: MetadataValue[] = value.map(v => { + if (v instanceof Buffer) { + return Buffer.from(v); + } else { + return v; + } + }); + + newInternalRepr.set(key, clonedValue); + }); + return newMetadata; } From 31a0019d99d6984585876a8e26b4f8ab0a87a43e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Oct 2018 12:35:45 -0700 Subject: [PATCH 0425/1899] Set _XOPEN_SOURCE only for BoringSSL --- packages/grpc-native-core/binding.gyp | 6 ++++-- packages/grpc-native-core/templates/binding.gyp.template | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 60b796263..2d4dd4d0c 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,8 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.16.0-pre1"', - '_XOPEN_SOURCE=700' + 'GRPC_NODE_VERSION="1.16.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -224,6 +223,9 @@ 'cflags': [ '-Wno-implicit-fallthrough' ], + 'defines': [ + '_XOPEN_SOURCE=700' + ] 'dependencies': [ ], 'sources': [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 56dc446e0..0a5260253 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -83,8 +83,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"', - '_XOPEN_SOURCE=700' + 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -196,6 +195,9 @@ 'cflags': [ '-Wno-implicit-fallthrough' ], + 'defines': [ + '_XOPEN_SOURCE=700' + ] 'dependencies': [ % for dep in getattr(lib, 'deps', []): '${dep}', From 9b5ed6240b364484c4e53b3cf016b2e290171e6e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Oct 2018 13:40:26 -0700 Subject: [PATCH 0426/1899] Add missing comma in binding.gyp --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/templates/binding.gyp.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 2d4dd4d0c..b11c7611c 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -225,7 +225,7 @@ ], 'defines': [ '_XOPEN_SOURCE=700' - ] + ], 'dependencies': [ ], 'sources': [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 0a5260253..8addf14a4 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -197,7 +197,7 @@ ], 'defines': [ '_XOPEN_SOURCE=700' - ] + ], 'dependencies': [ % for dep in getattr(lib, 'deps', []): '${dep}', From b7042551c311a019b49aa00af659e9c0c3984d95 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 25 Oct 2018 00:28:21 +0200 Subject: [PATCH 0427/1899] Fixing up submodule. --- packages/grpc-native-core/build.yaml | 1 - packages/grpc-native-core/deps/grpc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index b5ab803fc..49e36fdfe 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,2 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.16.0-pre1 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 98457b76f..bc9e9ddf9 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 98457b76ff43efa2c3edd203c14cd923734d5279 +Subproject commit bc9e9ddf9e04b1a905d51c41b1ffef5b30f2c986 From db1c6742729cfb38d29c822d2192ee4e8ad90a8e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 25 Oct 2018 04:09:38 +0200 Subject: [PATCH 0428/1899] Updating head again. --- packages/grpc-native-core/binding.gyp | 9 +++++++-- packages/grpc-native-core/deps/grpc | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 00f27a15f..1556881cb 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -818,11 +818,14 @@ 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', - 'deps/grpc/src/core/lib/security/security_connector/alts_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_fallback.cc', 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc', - 'deps/grpc/src/core/lib/security/security_connector/local_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/local/local_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc', + 'deps/grpc/src/core/lib/security/security_connector/ssl_utils.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', @@ -877,6 +880,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc', 'deps/grpc/src/core/ext/filters/client_channel/connector.cc', + 'deps/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc', 'deps/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'deps/grpc/src/core/ext/filters/client_channel/http_proxy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', @@ -893,6 +897,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', 'deps/grpc/src/core/ext/filters/client_channel/uri_parser.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', + 'deps/grpc/src/core/ext/filters/client_channel/health/health.pb.c', 'deps/grpc/src/core/tsi/alts_transport_security.cc', 'deps/grpc/src/core/tsi/fake_transport_security.cc', 'deps/grpc/src/core/tsi/local_transport_security.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 5984e9daf..4139ff895 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 5984e9daf26123bab25279f74e43d60908f199bf +Subproject commit 4139ff895fd413c730c4383d24d13a17bbeaea90 From 0158f0be56c7e63275ca6a35bae295d91dc9460a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 26 Oct 2018 15:37:01 -0700 Subject: [PATCH 0429/1899] Make clients fail better with malformed responses --- .../src/client_interceptors.js | 27 +++++++++++++++---- .../grpc-native-core/test/surface_test.js | 4 --- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index f240f9d3d..fc371e5ca 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -382,6 +382,8 @@ function InterceptingCall(next_call, requester) { this.requester = requester; } +const emptyNext = function() {}; + /** * Get the next method in the chain or a no-op function if we are at the end * of the chain @@ -392,7 +394,7 @@ function InterceptingCall(next_call, requester) { InterceptingCall.prototype._getNextCall = function(method_name) { return this.next_call ? this.next_call[method_name].bind(this.next_call) : - function(){}; + emptyNext; }; /** @@ -421,6 +423,9 @@ InterceptingCall.prototype._callNext = function(method_name, args, next) { next_call); } } else { + if (next_call === emptyNext) { + throw new Error('Interceptor call chain terminated unexpectedly'); + } return next_call(args_array[0], args_array[1]); } }; @@ -476,11 +481,11 @@ InterceptingCall.prototype.cancel = function() { /** * Run a cancelWithStatus operation through the interceptor chain. - * @param {grpc~StatusObject} status - * @param {string} message + * @param {number} code + * @param {string} details */ -InterceptingCall.prototype.cancelWithStatus = function(status, message) { - this._callNext('cancelWithStatus', [status, message]); +InterceptingCall.prototype.cancelWithStatus = function(code, details) { + this._callNext('cancelWithStatus', [code, details]); }; /** @@ -845,6 +850,9 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { final_requester.cancel = function () { call.cancel(); }; + final_requester.cancelWithStatus = function(code, details) { + call.cancelWithStatus(code, details) + }; final_requester.getPeer = function () { return call.getPeer(); }; @@ -957,6 +965,9 @@ function _getClientStreamingInterceptor(method_definition, channel, emitter, final_requester.cancel = function () { call.cancel(); }; + final_requester.cancelWithStatus = function(code, details) { + call.cancelWithStatus(code, details) + }; final_requester.getPeer = function() { return call.getPeer(); }; @@ -1053,6 +1064,9 @@ function _getServerStreamingInterceptor(method_definition, channel, emitter) { final_requester.cancel = function() { call.cancel(); }; + final_requester.cancelWithStatus = function(code, details) { + call.cancelWithStatus(code, details) + }; final_requester.getPeer = function() { return call.getPeer(); }; @@ -1159,6 +1173,9 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { final_requester.cancel = function() { call.cancel(); }; + final_requester.cancelWithStatus = function(code, details) { + call.cancelWithStatus(code, details) + }; final_requester.getPeer = function() { return call.getPeer(); }; diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index aa1246200..ba0f1d521 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -666,16 +666,12 @@ describe('Client malformed response handling', function() { }, serverStream: function(stream) { stream.write(badArg); - stream.end(); }, bidiStream: function(stream) { stream.on('data', function() { // Ignore requests stream.write(badArg); }); - stream.on('end', function() { - stream.end(); - }); } }); var port = server.bind('localhost:0', server_insecure_creds); From 7ffa49f7e4dd24bb4cfe072d7721c8d62312c61b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 30 Oct 2018 14:16:42 -0400 Subject: [PATCH 0430/1899] grpc-js-core: remove use of flow() and flowRight() This commit replaces combinations of bind(), map(), and flow() with simple for loops. This improves performance, and lessens the dependency on lodash. --- packages/grpc-js-core/src/filter-stack.ts | 48 +++++++++++++++++------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js-core/src/filter-stack.ts index 360a5cfc5..f9cd7d61a 100644 --- a/packages/grpc-js-core/src/filter-stack.ts +++ b/packages/grpc-js-core/src/filter-stack.ts @@ -1,4 +1,4 @@ -import {flow, flowRight, map} from 'lodash'; +import {map} from 'lodash'; import {Call, StatusObject, WriteObject} from './call-stream'; import {Filter, FilterFactory} from './filter'; @@ -8,29 +8,53 @@ export class FilterStack implements Filter { constructor(private readonly filters: Filter[]) {} sendMetadata(metadata: Promise) { - return flow(map( - this.filters, (filter) => filter.sendMetadata.bind(filter)))(metadata); + let result: Promise = metadata; + + for (let i = 0; i < this.filters.length; i++) { + result = this.filters[i].sendMetadata(result); + } + + return result; } receiveMetadata(metadata: Promise) { - return flowRight( - map(this.filters, (filter) => filter.receiveMetadata.bind(filter)))( - metadata); + let result: Promise = metadata; + + for (let i = this.filters.length - 1; i >= 0; i--) { + result = this.filters[i].receiveMetadata(result); + } + + return result; } sendMessage(message: Promise): Promise { - return flow(map(this.filters, (filter) => filter.sendMessage.bind(filter)))( - message); + let result: Promise = message; + + for (let i = 0; i < this.filters.length; i++) { + result = this.filters[i].sendMessage(result); + } + + return result; } receiveMessage(message: Promise): Promise { - return flowRight(map( - this.filters, (filter) => filter.receiveMessage.bind(filter)))(message); + let result: Promise = message; + + for (let i = this.filters.length - 1; i >= 0; i--) { + result = this.filters[i].receiveMessage(result); + } + + return result; } receiveTrailers(status: Promise): Promise { - return flowRight(map( - this.filters, (filter) => filter.receiveTrailers.bind(filter)))(status); + let result: Promise = status; + + for (let i = this.filters.length - 1; i >= 0; i--) { + result = this.filters[i].receiveTrailers(result); + } + + return result; } } From 3e114d00261987527b1dc57e3013c99a1ff154ea Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 30 Oct 2018 16:08:32 -0700 Subject: [PATCH 0431/1899] Update to 1.16.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 - packages/grpc-native-core/package.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 6c0a986dc..312bf5c98 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.16.0-pre1"' + 'GRPC_NODE_VERSION="1.16.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index b5ab803fc..49e36fdfe 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,2 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.16.0-pre1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 73f7698f4..36ae03baf 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.16.0-pre1", + "version": "1.16.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 493ca2fec4e7cc32e074b2271817a4e02e345fd8 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 31 Oct 2018 16:57:01 -0400 Subject: [PATCH 0432/1899] grpc-js-core: remove simple uses of lodash This commit removes lodash as a production dependency. It remains as a devDependency because it's used in tests, but the uses in the src/ directory were easily replaced with vanilla JavaScript. --- packages/grpc-js-core/package.json | 2 +- packages/grpc-js-core/src/call-credentials.ts | 4 +--- packages/grpc-js-core/src/filter-stack.ts | 4 +--- packages/grpc-js-core/src/make-client.ts | 22 +++++++++++++------ 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js-core/package.json index b573a6fbf..166c649d6 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js-core/package.json @@ -20,6 +20,7 @@ "@types/node": "^10.5.4", "clang-format": "^1.0.55", "gts": "^0.5.1", + "lodash": "^4.17.4", "typescript": "~2.7.0" }, "contributors": [ @@ -41,7 +42,6 @@ "posttest": "npm run check" }, "dependencies": { - "lodash": "^4.17.4", "semver": "^5.5.0" }, "files": [ diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js-core/src/call-credentials.ts index 2a9d8195f..212d49b27 100644 --- a/packages/grpc-js-core/src/call-credentials.ts +++ b/packages/grpc-js-core/src/call-credentials.ts @@ -1,5 +1,3 @@ -import {map} from 'lodash'; - import {Metadata} from './metadata'; export type CallMetadataOptions = { @@ -53,7 +51,7 @@ class ComposedCallCredentials extends CallCredentials { async generateMetadata(options: CallMetadataOptions): Promise { const base: Metadata = new Metadata(); const generated: Metadata[] = await Promise.all( - map(this.creds, (cred) => cred.generateMetadata(options))); + this.creds.map((cred) => cred.generateMetadata(options))); for (const gen of generated) { base.merge(gen); } diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js-core/src/filter-stack.ts index f9cd7d61a..92232f4c6 100644 --- a/packages/grpc-js-core/src/filter-stack.ts +++ b/packages/grpc-js-core/src/filter-stack.ts @@ -1,5 +1,3 @@ -import {map} from 'lodash'; - import {Call, StatusObject, WriteObject} from './call-stream'; import {Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; @@ -63,6 +61,6 @@ export class FilterStackFactory implements FilterFactory { createFilter(callStream: Call): FilterStack { return new FilterStack( - map(this.factories, (factory) => factory.createFilter(callStream))); + this.factories.map((factory) => factory.createFilter(callStream))); } } diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js-core/src/make-client.ts index 669723d0a..3b03255f1 100644 --- a/packages/grpc-js-core/src/make-client.ts +++ b/packages/grpc-js-core/src/make-client.ts @@ -1,5 +1,3 @@ -import * as _ from 'lodash'; - import {ChannelCredentials} from './channel-credentials'; import {ChannelOptions} from './channel-options'; import {Client} from './client'; @@ -73,10 +71,11 @@ export function makeClientConstructor( [methodName: string]: Function; } - _.each(methods, (attrs, name) => { + Object.keys(methods).forEach((name) => { + const attrs = methods[name]; let methodType: keyof typeof requesterFuncs; // TODO(murgatroid99): Verify that we don't need this anymore - if (_.startsWith(name, '$')) { + if (typeof name === 'string' && name.charAt(0) === '$') { throw new Error('Method names cannot start with $'); } if (attrs.requestStream) { @@ -94,11 +93,11 @@ export function makeClientConstructor( } const serialize = attrs.requestSerialize; const deserialize = attrs.responseDeserialize; - const methodFunc = _.partial( - requesterFuncs[methodType], attrs.path, serialize, deserialize); + const methodFunc = + partial(requesterFuncs[methodType], attrs.path, serialize, deserialize); ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method - _.assign(ServiceClientImpl.prototype[name], attrs); + Object.assign(ServiceClientImpl.prototype[name], attrs); if (attrs.originalName) { ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; @@ -110,6 +109,15 @@ export function makeClientConstructor( return ServiceClientImpl; } +function partial( + fn: Function, path: string, serialize: Function, + deserialize: Function): Function { + // tslint:disable-next-line:no-any + return function(this: any, ...args: any[]) { + return fn.call(this, path, serialize, deserialize, ...args); + }; +} + export type GrpcObject = { [index: string]: GrpcObject|ServiceClientConstructor; }; From 65bd1421143894b1aa5a3cf6ae09aaecf04f7daf Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 1 Nov 2018 16:56:57 -0400 Subject: [PATCH 0433/1899] grpc-js: rename grpc-js-core to match npm This commit renames grpc-js-core to grpc-js to more closely match the name used on npm. --- README.md | 2 +- gulpfile.ts | 2 +- package.json | 2 +- packages/{grpc-js-core => grpc-js}/README.md | 0 packages/{grpc-js-core => grpc-js}/gulpfile.ts | 0 packages/{grpc-js-core => grpc-js}/package.json | 2 +- .../{grpc-js-core => grpc-js}/src/call-credentials-filter.ts | 0 packages/{grpc-js-core => grpc-js}/src/call-credentials.ts | 0 packages/{grpc-js-core => grpc-js}/src/call-stream.ts | 0 packages/{grpc-js-core => grpc-js}/src/call.ts | 0 packages/{grpc-js-core => grpc-js}/src/channel-credentials.ts | 0 packages/{grpc-js-core => grpc-js}/src/channel-options.ts | 0 packages/{grpc-js-core => grpc-js}/src/channel.ts | 0 packages/{grpc-js-core => grpc-js}/src/client.ts | 0 packages/{grpc-js-core => grpc-js}/src/compression-filter.ts | 0 packages/{grpc-js-core => grpc-js}/src/constants.ts | 0 packages/{grpc-js-core => grpc-js}/src/deadline-filter.ts | 0 packages/{grpc-js-core => grpc-js}/src/events.ts | 0 packages/{grpc-js-core => grpc-js}/src/filter-stack.ts | 0 packages/{grpc-js-core => grpc-js}/src/filter.ts | 0 packages/{grpc-js-core => grpc-js}/src/index.ts | 0 packages/{grpc-js-core => grpc-js}/src/logging.ts | 0 packages/{grpc-js-core => grpc-js}/src/make-client.ts | 0 .../{grpc-js-core => grpc-js}/src/metadata-status-filter.ts | 0 packages/{grpc-js-core => grpc-js}/src/metadata.ts | 0 packages/{grpc-js-core => grpc-js}/src/object-stream.ts | 0 packages/{grpc-js-core => grpc-js}/src/status-builder.ts | 0 packages/{grpc-js-core => grpc-js}/src/subchannel.ts | 0 packages/{grpc-js-core => grpc-js}/test/common.ts | 0 packages/{grpc-js-core => grpc-js}/test/fixtures/README | 0 packages/{grpc-js-core => grpc-js}/test/fixtures/ca.pem | 0 packages/{grpc-js-core => grpc-js}/test/fixtures/server1.key | 0 packages/{grpc-js-core => grpc-js}/test/fixtures/server1.pem | 0 .../{grpc-js-core => grpc-js}/test/test-call-credentials.ts | 0 packages/{grpc-js-core => grpc-js}/test/test-call-stream.ts | 0 .../test/test-channel-credentials.ts | 0 packages/{grpc-js-core => grpc-js}/test/test-logging.ts | 0 packages/{grpc-js-core => grpc-js}/test/test-metadata.ts | 0 .../{grpc-js-core => grpc-js}/test/test-status-builder.ts | 0 packages/{grpc-js-core => grpc-js}/tsconfig.json | 0 test/client-libraries-integration/use-grpc-js.js | 4 ++-- 41 files changed, 6 insertions(+), 6 deletions(-) rename packages/{grpc-js-core => grpc-js}/README.md (100%) rename packages/{grpc-js-core => grpc-js}/gulpfile.ts (100%) rename packages/{grpc-js-core => grpc-js}/package.json (98%) rename packages/{grpc-js-core => grpc-js}/src/call-credentials-filter.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/call-credentials.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/call-stream.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/call.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/channel-credentials.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/channel-options.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/channel.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/client.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/compression-filter.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/constants.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/deadline-filter.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/events.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/filter-stack.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/filter.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/index.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/logging.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/make-client.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/metadata-status-filter.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/metadata.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/object-stream.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/status-builder.ts (100%) rename packages/{grpc-js-core => grpc-js}/src/subchannel.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/common.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/fixtures/README (100%) rename packages/{grpc-js-core => grpc-js}/test/fixtures/ca.pem (100%) rename packages/{grpc-js-core => grpc-js}/test/fixtures/server1.key (100%) rename packages/{grpc-js-core => grpc-js}/test/fixtures/server1.pem (100%) rename packages/{grpc-js-core => grpc-js}/test/test-call-credentials.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/test-call-stream.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/test-channel-credentials.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/test-logging.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/test-metadata.ts (100%) rename packages/{grpc-js-core => grpc-js}/test/test-status-builder.ts (100%) rename packages/{grpc-js-core => grpc-js}/tsconfig.json (100%) diff --git a/README.md b/README.md index dd9ce9726..b39179208 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This is the existing, feature-rich implementation of gRPC using a C++ addon. It ### Pure JavaScript Client -Directory: [`packages/grpc-js-core`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core) +Directory: [`packages/grpc-js`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) npm package: [@grpc/grpc-js](https://www.npmjs.com/package/@grpc/grpc-js) diff --git a/gulpfile.ts b/gulpfile.ts index dac1421ea..fe87389f3 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -49,7 +49,7 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { [ ['./packages/grpc-health-check/gulpfile', 'health-check'], - ['./packages/grpc-js-core/gulpfile', 'js.core'], + ['./packages/grpc-js/gulpfile', 'js.core'], ['./packages/grpc-native-core/gulpfile', 'native.core'], ['./packages/grpc-protobufjs/gulpfile', 'protobuf'], ['./test/gulpfile', 'internal.test'], diff --git a/package.json b/package.json index e8d7a1128..75aaf5e97 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "nyc": { "include": [ "packages/grpc-health-check/health.js", - "packages/grpc-js-core/build/src/*", + "packages/grpc-js/build/src/*", "packages/grpc-native-core/index.js", "packages/grpc-native-core/src/*.js", "packages/grpc-protobufjs/build/src/*" diff --git a/packages/grpc-js-core/README.md b/packages/grpc-js/README.md similarity index 100% rename from packages/grpc-js-core/README.md rename to packages/grpc-js/README.md diff --git a/packages/grpc-js-core/gulpfile.ts b/packages/grpc-js/gulpfile.ts similarity index 100% rename from packages/grpc-js-core/gulpfile.ts rename to packages/grpc-js/gulpfile.ts diff --git a/packages/grpc-js-core/package.json b/packages/grpc-js/package.json similarity index 98% rename from packages/grpc-js-core/package.json rename to packages/grpc-js/package.json index 166c649d6..bf6376bc6 100644 --- a/packages/grpc-js-core/package.json +++ b/packages/grpc-js/package.json @@ -3,7 +3,7 @@ "version": "0.3.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", - "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js-core", + "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", "main": "build/src/index.js", "engines": { "node": "^8.11.2 || >=9.4" diff --git a/packages/grpc-js-core/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts similarity index 100% rename from packages/grpc-js-core/src/call-credentials-filter.ts rename to packages/grpc-js/src/call-credentials-filter.ts diff --git a/packages/grpc-js-core/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts similarity index 100% rename from packages/grpc-js-core/src/call-credentials.ts rename to packages/grpc-js/src/call-credentials.ts diff --git a/packages/grpc-js-core/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts similarity index 100% rename from packages/grpc-js-core/src/call-stream.ts rename to packages/grpc-js/src/call-stream.ts diff --git a/packages/grpc-js-core/src/call.ts b/packages/grpc-js/src/call.ts similarity index 100% rename from packages/grpc-js-core/src/call.ts rename to packages/grpc-js/src/call.ts diff --git a/packages/grpc-js-core/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts similarity index 100% rename from packages/grpc-js-core/src/channel-credentials.ts rename to packages/grpc-js/src/channel-credentials.ts diff --git a/packages/grpc-js-core/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts similarity index 100% rename from packages/grpc-js-core/src/channel-options.ts rename to packages/grpc-js/src/channel-options.ts diff --git a/packages/grpc-js-core/src/channel.ts b/packages/grpc-js/src/channel.ts similarity index 100% rename from packages/grpc-js-core/src/channel.ts rename to packages/grpc-js/src/channel.ts diff --git a/packages/grpc-js-core/src/client.ts b/packages/grpc-js/src/client.ts similarity index 100% rename from packages/grpc-js-core/src/client.ts rename to packages/grpc-js/src/client.ts diff --git a/packages/grpc-js-core/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts similarity index 100% rename from packages/grpc-js-core/src/compression-filter.ts rename to packages/grpc-js/src/compression-filter.ts diff --git a/packages/grpc-js-core/src/constants.ts b/packages/grpc-js/src/constants.ts similarity index 100% rename from packages/grpc-js-core/src/constants.ts rename to packages/grpc-js/src/constants.ts diff --git a/packages/grpc-js-core/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts similarity index 100% rename from packages/grpc-js-core/src/deadline-filter.ts rename to packages/grpc-js/src/deadline-filter.ts diff --git a/packages/grpc-js-core/src/events.ts b/packages/grpc-js/src/events.ts similarity index 100% rename from packages/grpc-js-core/src/events.ts rename to packages/grpc-js/src/events.ts diff --git a/packages/grpc-js-core/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts similarity index 100% rename from packages/grpc-js-core/src/filter-stack.ts rename to packages/grpc-js/src/filter-stack.ts diff --git a/packages/grpc-js-core/src/filter.ts b/packages/grpc-js/src/filter.ts similarity index 100% rename from packages/grpc-js-core/src/filter.ts rename to packages/grpc-js/src/filter.ts diff --git a/packages/grpc-js-core/src/index.ts b/packages/grpc-js/src/index.ts similarity index 100% rename from packages/grpc-js-core/src/index.ts rename to packages/grpc-js/src/index.ts diff --git a/packages/grpc-js-core/src/logging.ts b/packages/grpc-js/src/logging.ts similarity index 100% rename from packages/grpc-js-core/src/logging.ts rename to packages/grpc-js/src/logging.ts diff --git a/packages/grpc-js-core/src/make-client.ts b/packages/grpc-js/src/make-client.ts similarity index 100% rename from packages/grpc-js-core/src/make-client.ts rename to packages/grpc-js/src/make-client.ts diff --git a/packages/grpc-js-core/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts similarity index 100% rename from packages/grpc-js-core/src/metadata-status-filter.ts rename to packages/grpc-js/src/metadata-status-filter.ts diff --git a/packages/grpc-js-core/src/metadata.ts b/packages/grpc-js/src/metadata.ts similarity index 100% rename from packages/grpc-js-core/src/metadata.ts rename to packages/grpc-js/src/metadata.ts diff --git a/packages/grpc-js-core/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts similarity index 100% rename from packages/grpc-js-core/src/object-stream.ts rename to packages/grpc-js/src/object-stream.ts diff --git a/packages/grpc-js-core/src/status-builder.ts b/packages/grpc-js/src/status-builder.ts similarity index 100% rename from packages/grpc-js-core/src/status-builder.ts rename to packages/grpc-js/src/status-builder.ts diff --git a/packages/grpc-js-core/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts similarity index 100% rename from packages/grpc-js-core/src/subchannel.ts rename to packages/grpc-js/src/subchannel.ts diff --git a/packages/grpc-js-core/test/common.ts b/packages/grpc-js/test/common.ts similarity index 100% rename from packages/grpc-js-core/test/common.ts rename to packages/grpc-js/test/common.ts diff --git a/packages/grpc-js-core/test/fixtures/README b/packages/grpc-js/test/fixtures/README similarity index 100% rename from packages/grpc-js-core/test/fixtures/README rename to packages/grpc-js/test/fixtures/README diff --git a/packages/grpc-js-core/test/fixtures/ca.pem b/packages/grpc-js/test/fixtures/ca.pem similarity index 100% rename from packages/grpc-js-core/test/fixtures/ca.pem rename to packages/grpc-js/test/fixtures/ca.pem diff --git a/packages/grpc-js-core/test/fixtures/server1.key b/packages/grpc-js/test/fixtures/server1.key similarity index 100% rename from packages/grpc-js-core/test/fixtures/server1.key rename to packages/grpc-js/test/fixtures/server1.key diff --git a/packages/grpc-js-core/test/fixtures/server1.pem b/packages/grpc-js/test/fixtures/server1.pem similarity index 100% rename from packages/grpc-js-core/test/fixtures/server1.pem rename to packages/grpc-js/test/fixtures/server1.pem diff --git a/packages/grpc-js-core/test/test-call-credentials.ts b/packages/grpc-js/test/test-call-credentials.ts similarity index 100% rename from packages/grpc-js-core/test/test-call-credentials.ts rename to packages/grpc-js/test/test-call-credentials.ts diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts similarity index 100% rename from packages/grpc-js-core/test/test-call-stream.ts rename to packages/grpc-js/test/test-call-stream.ts diff --git a/packages/grpc-js-core/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts similarity index 100% rename from packages/grpc-js-core/test/test-channel-credentials.ts rename to packages/grpc-js/test/test-channel-credentials.ts diff --git a/packages/grpc-js-core/test/test-logging.ts b/packages/grpc-js/test/test-logging.ts similarity index 100% rename from packages/grpc-js-core/test/test-logging.ts rename to packages/grpc-js/test/test-logging.ts diff --git a/packages/grpc-js-core/test/test-metadata.ts b/packages/grpc-js/test/test-metadata.ts similarity index 100% rename from packages/grpc-js-core/test/test-metadata.ts rename to packages/grpc-js/test/test-metadata.ts diff --git a/packages/grpc-js-core/test/test-status-builder.ts b/packages/grpc-js/test/test-status-builder.ts similarity index 100% rename from packages/grpc-js-core/test/test-status-builder.ts rename to packages/grpc-js/test/test-status-builder.ts diff --git a/packages/grpc-js-core/tsconfig.json b/packages/grpc-js/tsconfig.json similarity index 100% rename from packages/grpc-js-core/tsconfig.json rename to packages/grpc-js/tsconfig.json diff --git a/test/client-libraries-integration/use-grpc-js.js b/test/client-libraries-integration/use-grpc-js.js index 68c6597d5..47fcd15d0 100644 --- a/test/client-libraries-integration/use-grpc-js.js +++ b/test/client-libraries-integration/use-grpc-js.js @@ -2,8 +2,8 @@ require('source-map-support/register'); const Module = require('module'); const shimmer = require('shimmer'); -const grpcPJson = require('../../packages/grpc-js-core/package'); -const grpcImpl = require('../../packages/grpc-js-core'); +const grpcPJson = require('../../packages/grpc-js/package'); +const grpcImpl = require('../../packages/grpc-js'); const grpcProtobuf = require('../../packages/grpc-protobufjs'); if (!process.env.USE_GRPC_NATIVE) { From 489305db79ad1a92a6a8534fb25c16511386c6e5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 1 Nov 2018 17:09:28 -0400 Subject: [PATCH 0434/1899] proto-loader: rename grpc-protobufjs to match npm This commit renames grpc-protobufjs to proto-loader to more closely match the name used on npm. --- README.md | 2 +- gulpfile.ts | 2 +- package.json | 2 +- packages/{grpc-protobufjs => proto-loader}/README.md | 0 packages/{grpc-protobufjs => proto-loader}/gulpfile.ts | 0 packages/{grpc-protobufjs => proto-loader}/package.json | 0 packages/{grpc-protobufjs => proto-loader}/src/index.ts | 0 packages/{grpc-protobufjs => proto-loader}/tsconfig.json | 0 test/api/error_test.js | 4 ++-- test/client-libraries-integration/use-grpc-js.js | 2 +- test/interop/interop_client.js | 2 +- test/interop/interop_server.js | 2 +- test/performance/benchmark_client.js | 2 +- test/performance/benchmark_server.js | 2 +- test/performance/worker.js | 2 +- 15 files changed, 11 insertions(+), 11 deletions(-) rename packages/{grpc-protobufjs => proto-loader}/README.md (100%) rename packages/{grpc-protobufjs => proto-loader}/gulpfile.ts (100%) rename packages/{grpc-protobufjs => proto-loader}/package.json (100%) rename packages/{grpc-protobufjs => proto-loader}/src/index.ts (100%) rename packages/{grpc-protobufjs => proto-loader}/tsconfig.json (100%) diff --git a/README.md b/README.md index b39179208..2c295e315 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ This library implements the core functionality of gRPC purely in JavaScript, wit ### gRPC Protobuf Loader -Directory: [`packages/grpc-protobufjs`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-protobufjs) +Directory: [`packages/proto-loader`](https://github.com/grpc/grpc-node/tree/master/packages/proto-loader) npm package: [@grpc/proto-loader](https://www.npmjs.com/package/@grpc/proto-loader) diff --git a/gulpfile.ts b/gulpfile.ts index fe87389f3..89d9e290b 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -51,7 +51,7 @@ function loadGulpTasksWithPrefix(path: string, prefix: string) { ['./packages/grpc-health-check/gulpfile', 'health-check'], ['./packages/grpc-js/gulpfile', 'js.core'], ['./packages/grpc-native-core/gulpfile', 'native.core'], - ['./packages/grpc-protobufjs/gulpfile', 'protobuf'], + ['./packages/proto-loader/gulpfile', 'protobuf'], ['./test/gulpfile', 'internal.test'], ].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); diff --git a/package.json b/package.json index 75aaf5e97..6df12d772 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,7 @@ "packages/grpc-js/build/src/*", "packages/grpc-native-core/index.js", "packages/grpc-native-core/src/*.js", - "packages/grpc-protobufjs/build/src/*" + "packages/proto-loader/build/src/*" ], "cache": true, "all": true diff --git a/packages/grpc-protobufjs/README.md b/packages/proto-loader/README.md similarity index 100% rename from packages/grpc-protobufjs/README.md rename to packages/proto-loader/README.md diff --git a/packages/grpc-protobufjs/gulpfile.ts b/packages/proto-loader/gulpfile.ts similarity index 100% rename from packages/grpc-protobufjs/gulpfile.ts rename to packages/proto-loader/gulpfile.ts diff --git a/packages/grpc-protobufjs/package.json b/packages/proto-loader/package.json similarity index 100% rename from packages/grpc-protobufjs/package.json rename to packages/proto-loader/package.json diff --git a/packages/grpc-protobufjs/src/index.ts b/packages/proto-loader/src/index.ts similarity index 100% rename from packages/grpc-protobufjs/src/index.ts rename to packages/proto-loader/src/index.ts diff --git a/packages/grpc-protobufjs/tsconfig.json b/packages/proto-loader/tsconfig.json similarity index 100% rename from packages/grpc-protobufjs/tsconfig.json rename to packages/proto-loader/tsconfig.json diff --git a/test/api/error_test.js b/test/api/error_test.js index 9b5ff5e3f..d8bf4b751 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -10,7 +10,7 @@ const _ = require('lodash'); const anyGrpc = require('../any_grpc'); const clientGrpc = anyGrpc.client; const serverGrpc = anyGrpc.server; -const protoLoader = require('../../packages/grpc-protobufjs', options); +const protoLoader = require('../../packages/proto-loader', options); const testServiceDef = protoLoader.loadSync(__dirname + '/../proto/test_service.proto'); const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestService; const clientInsecureCreds = clientGrpc.credentials.createInsecure(); @@ -526,4 +526,4 @@ describe('Client malformed response handling', function() { }); }); }); -}); \ No newline at end of file +}); diff --git a/test/client-libraries-integration/use-grpc-js.js b/test/client-libraries-integration/use-grpc-js.js index 47fcd15d0..5eff22f5f 100644 --- a/test/client-libraries-integration/use-grpc-js.js +++ b/test/client-libraries-integration/use-grpc-js.js @@ -4,7 +4,7 @@ const shimmer = require('shimmer'); const grpcPJson = require('../../packages/grpc-js/package'); const grpcImpl = require('../../packages/grpc-js'); -const grpcProtobuf = require('../../packages/grpc-protobufjs'); +const grpcProtobuf = require('../../packages/proto-loader'); if (!process.env.USE_GRPC_NATIVE) { shimmer.wrap(Module, '_load', (moduleLoad) => { diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 447b018a0..a8a6a3e4e 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -21,7 +21,7 @@ var fs = require('fs'); var path = require('path'); var grpc = require('../any_grpc').client; -var protoLoader = require('../../packages/grpc-protobufjs'); +var protoLoader = require('../../packages/proto-loader'); var GoogleAuth = require('google-auth-library'); var protoPackage = protoLoader.loadSync( diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index 323142327..dce85873b 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -24,7 +24,7 @@ var _ = require('lodash'); var AsyncDelayQueue = require('./async_delay_queue'); var grpc = require('../any_grpc').server; // TODO(murgatroid99): do this import more cleanly -var protoLoader = require('../../packages/grpc-protobufjs'); +var protoLoader = require('../../packages/proto-loader'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/test.proto', {keepCase: true, diff --git a/test/performance/benchmark_client.js b/test/performance/benchmark_client.js index 5424c7424..7d103a290 100644 --- a/test/performance/benchmark_client.js +++ b/test/performance/benchmark_client.js @@ -37,7 +37,7 @@ var genericService = require('./generic_service'); // TODO(murgatroid99): use multiple grpc implementations var grpc = require('../any_grpc').client; -var protoLoader = require('../../packages/grpc-protobufjs'); +var protoLoader = require('../../packages/proto-loader'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/benchmark_service.proto', {keepCase: true, diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index e41ca1562..e216f7797 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -31,7 +31,7 @@ var util = require('util'); var genericService = require('./generic_service'); var grpc = require('../any_grpc').server; -var protoLoader = require('../../packages/grpc-protobufjs'); +var protoLoader = require('../../packages/proto-loader'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/benchmark_service.proto', {keepCase: true, diff --git a/test/performance/worker.js b/test/performance/worker.js index cd868ae10..2376ef52d 100644 --- a/test/performance/worker.js +++ b/test/performance/worker.js @@ -22,7 +22,7 @@ var console = require('console'); var WorkerServiceImpl = require('./worker_service_impl'); var grpc = require('../any_grpc').server; -var protoLoader = require('../../packages/grpc-protobufjs'); +var protoLoader = require('../../packages/proto-loader'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/worker_service.proto', {keepCase: true, From c8266e56d0a4149bc9287b3719119111f2c04d91 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 4 Nov 2018 11:20:08 -0500 Subject: [PATCH 0435/1899] squash! grpc-js: rename grpc-js-core to match npm --- test/any_grpc.js | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/test/any_grpc.js b/test/any_grpc.js index 250f00981..7f23e4206 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -5,14 +5,18 @@ const _ = require('lodash'); function getImplementation(globalField) { - if (global[globalField] !== 'js' && global[globalField] !== 'native') { - throw new Error([ - `Invalid value for global.${globalField}: ${global.globalField}.`, - 'If running from the command line, please --require a fixture first.' - ].join(' ')); - } const impl = global[globalField]; - return require(`../packages/grpc-${impl}-core`); + + if (impl === 'js') { + return require(`../packages/grpc-${impl}`); + } else if (impl === 'native') { + return require(`../packages/grpc-${impl}-core`); + } + + throw new Error([ + `Invalid value for global.${globalField}: ${global.globalField}.`, + 'If running from the command line, please --require a fixture first.' + ].join(' ')); } const clientImpl = getImplementation('_client_implementation'); From 7e472e5bf46bbbb0e726d37a640f2fc3e71f6d6d Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 16:39:03 -0800 Subject: [PATCH 0436/1899] refactor: use individual lodash package for proto loader --- packages/proto-loader/package.json | 6 +++--- packages/proto-loader/src/index.ts | 4 ++-- packages/proto-loader/tsconfig.json | 6 +----- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index ebe82a43b..cfd421cba 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -38,12 +38,12 @@ "build/src/*.js" ], "dependencies": { - "@types/lodash": "^4.14.104", - "@types/node": "^9.4.6", - "lodash": "^4.17.5", + "lodash.camelcase": "^4.3.0", "protobufjs": "^6.8.6" }, "devDependencies": { + "@types/lodash.camelcase": "^4.3.4", + "@types/node": "^10.12.5", "clang-format": "^1.2.2", "gts": "^0.5.3", "typescript": "~2.7.2" diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 099f990ce..36ef263d2 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -18,7 +18,7 @@ import * as Protobuf from 'protobufjs'; import * as fs from 'fs'; import * as path from 'path'; -import * as _ from 'lodash'; +import camelCase = require('lodash.camelcase'); export interface Serialize { (value: T): Buffer; @@ -97,7 +97,7 @@ function createMethodDefinition(method: Protobuf.Method, serviceName: string, op responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options), // TODO(murgatroid99): Find a better way to handle this - originalName: _.camelCase(method.name) + originalName: camelCase(method.name) }; } diff --git a/packages/proto-loader/tsconfig.json b/packages/proto-loader/tsconfig.json index 9218530ce..f893d7afb 100644 --- a/packages/proto-loader/tsconfig.json +++ b/packages/proto-loader/tsconfig.json @@ -5,10 +5,6 @@ "outDir": "build" }, "include": [ - "src/*.ts", - "src/**/*.ts" - ], - "exclude": [ - "node_modules" + "src/*.ts" ] } From 5841cd9c5052fab3ec9bf240babe2ff0f46f98af Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 16:43:53 -0800 Subject: [PATCH 0437/1899] refactor: use individual lodash packages for health check --- packages/grpc-health-check/health.js | 7 ++++--- packages/grpc-health-check/package.json | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/grpc-health-check/health.js b/packages/grpc-health-check/health.js index 9b1cfbd05..f55fba196 100644 --- a/packages/grpc-health-check/health.js +++ b/packages/grpc-health-check/health.js @@ -20,13 +20,14 @@ var grpc = require('grpc'); -var _ = require('lodash'); +var _get = require('lodash.get'); +var _clone = require('lodash.clone') var health_messages = require('./v1/health_pb'); var health_service = require('./v1/health_grpc_pb'); function HealthImplementation(statusMap) { - this.statusMap = _.clone(statusMap); + this.statusMap = _clone(statusMap); } HealthImplementation.prototype.setStatus = function(service, status) { @@ -35,7 +36,7 @@ HealthImplementation.prototype.setStatus = function(service, status) { HealthImplementation.prototype.check = function(call, callback){ var service = call.request.getService(); - var status = _.get(this.statusMap, service, null); + var status = _get(this.statusMap, service, null); if (status === null) { // TODO(murgatroid99): Do this without an explicit reference to grpc. callback({code:grpc.status.NOT_FOUND}); diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index db1fd61fc..4ff2e33ab 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -17,7 +17,8 @@ "dependencies": { "google-protobuf": "^3.4.0", "grpc": "^1.6.0", - "lodash": "^4.17.5" + "lodash.clone": "^4.5.0", + "lodash.get": "^4.4.2" }, "files": [ "LICENSE", From 8cd41923f5d2dcb58b1cc0bdfe2b79251b0a93b5 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 16:52:01 -0800 Subject: [PATCH 0438/1899] refactor: drop usage of _.isString --- packages/grpc-native-core/src/metadata.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js index 63bbed76d..2b10bc80f 100644 --- a/packages/grpc-native-core/src/metadata.js +++ b/packages/grpc-native-core/src/metadata.js @@ -51,7 +51,7 @@ function validate(key, value) { throw new Error('keys that end with \'-bin\' must have Buffer values'); } } else { - if (!_.isString(value)) { + if (typeof value !== 'string') { throw new Error( 'keys that don\'t end with \'-bin\' must have String values'); } From e1cf0e6ead74acc3a3ace2aac17a3284c31fb5f9 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 16:54:08 -0800 Subject: [PATCH 0439/1899] refactor: drop usage of _.map --- packages/grpc-native-core/src/client_interceptors.js | 4 ++-- packages/grpc-native-core/src/protobuf_js_5_common.js | 4 ++-- packages/grpc-native-core/src/protobuf_js_6_common.js | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index fc371e5ca..9a992f5e6 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -746,14 +746,14 @@ function _areBatchRequirementsMet(batch_ops, completed_ops) { function _startBatchIfReady(call, batch, batch_state, callback) { var completed_ops = batch_state.completed_ops; var deferred_batches = batch_state.deferred_batches; - var batch_ops = _.map(_.keys(batch), Number); + var batch_ops = _.keys(batch).map(Number); if (_areBatchRequirementsMet(batch_ops, completed_ops)) { // Dependencies are met, start the batch and any deferred batches whose // dependencies are met as a result. call.startBatch(batch, callback); completed_ops = _.union(completed_ops, batch_ops); deferred_batches = _.flatMap(deferred_batches, function(deferred_batch) { - var deferred_batch_ops = _.map(_.keys(deferred_batch), Number); + var deferred_batch_ops = _.keys(deferred_batch).map(Number); if (_areBatchRequirementsMet(deferred_batch_ops, completed_ops)) { call.startBatch(deferred_batch.batch, deferred_batch.callback); return []; diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js index 541965fd0..cf377d2b0 100644 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ b/packages/grpc-native-core/src/protobuf_js_5_common.js @@ -106,9 +106,9 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, lodash@3.10.1-compatible functions. A previous version used _.fromPairs, which would be cleaner, but was introduced in lodash version 4 */ - return _.zipObject(_.map(service.children, function(method) { + return _.zipObject(service.children.map(function(method) { return _.camelCase(method.name); - }), _.map(service.children, function(method) { + }), service.children.map(function(method) { return { originalName: method.name, path: prefix + method.name, diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index 0f0725167..04121ad42 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -103,9 +103,9 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, options) { var prefix = '/' + fullyQualifiedName(service) + '/'; service.resolveAll(); - return _.zipObject(_.map(service.methods, function(method) { + return _.zipObject(service.methods.map(function(method) { return _.camelCase(method.name); - }), _.map(service.methods, function(method) { + }), service.methods.map(function(method) { return { originalName: method.name, path: prefix + method.name, From ea3e8e59978809ee19e7243dda3dfd94cce58d70 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 16:57:24 -0800 Subject: [PATCH 0440/1899] refactor: drop usage of _.isFinite --- packages/grpc-native-core/src/client_interceptors.js | 4 ++-- packages/grpc-native-core/src/credentials.js | 2 +- packages/grpc-native-core/src/server.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index fc371e5ca..4f280fea3 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -944,7 +944,7 @@ function _getClientStreamingInterceptor(method_definition, channel, emitter, callback(e); return; } - if (_.isFinite(encoding)) { + if (Number.isFinite(encoding)) { /* Attach the encoding if it is a finite number. This is the closest we * can get to checking that it is valid flags */ message.grpcWriteFlags = encoding; @@ -1145,7 +1145,7 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { callback(e); return; } - if (_.isFinite(encoding)) { + if (Number.isFinite(encoding)) { /* Attach the encoding if it is a finite number. This is the closest we * can get to checking that it is valid flags */ message.grpcWriteFlags = encoding; diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 50669b0d9..767d5248d 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -170,7 +170,7 @@ exports.createFromMetadataGenerator = function(metadata_generator) { var message = ''; if (error) { message = error.message; - if (error.hasOwnProperty('code') && _.isFinite(error.code)) { + if (error.hasOwnProperty('code') && Number.isFinite(error.code)) { code = error.code; } else { code = constants.status.UNAUTHENTICATED; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index d2c9a5594..9f1715e0b 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -318,7 +318,7 @@ function _write(chunk, encoding, callback) { (new Metadata())._getCoreRepresentation(); this.call.metadataSent = true; } - if (_.isFinite(encoding)) { + if (Number.isFinite(encoding)) { /* Attach the encoding if it is a finite number. This is the closest we * can get to checking that it is valid flags */ message.grpcWriteFlags = encoding; From 261fb51ba93def1e5503cf962c2090d792a29517 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 17:12:34 -0800 Subject: [PATCH 0441/1899] refactor: drop usage of _.startsWith --- packages/grpc-native-core/src/client.js | 2 +- packages/grpc-native-core/test/surface_test.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index cc061c52f..40fbcd49d 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -935,7 +935,7 @@ exports.makeClientConstructor = function(methods, serviceName, ServiceClient.prototype.$method_names = {}; _.each(methods, function(attrs, name) { - if (_.startsWith(name, '$')) { + if (name.indexOf('$') === 0) { throw new Error('Method names cannot start with $'); } var method_type = common.getMethodType(attrs); diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index ba0f1d521..9fe132ceb 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -489,8 +489,8 @@ describe('Echo metadata', function() { var call = client.unary({}, metadata, function(err, data) { assert.ifError(err); }); call.on('metadata', function(metadata) { - assert(_.startsWith(metadata.get('user-agent')[0], - 'grpc-node/' + version)); + assert.strictEqual(0, + metadata.get('user-agent')[0].indexOf('grpc-node/' + version)); done(); }); }); From a58c178119642c07ba7276fc2846d79982b32ce3 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 17:19:27 -0800 Subject: [PATCH 0442/1899] refactor: drop usage of _.isFunction --- packages/grpc-native-core/src/client.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index cc061c52f..15de7b00a 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -449,7 +449,7 @@ Client.prototype.resolveCallInterceptors = function(method_definition, intercept Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, argument, metadata, options, callback) { - if (_.isFunction(options)) { + if (typeof options === 'function') { callback = options; if (metadata instanceof Metadata) { options = {}; @@ -457,7 +457,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, options = metadata; metadata = new Metadata(); } - } else if (_.isFunction(metadata)) { + } else if (typeof metadata === 'function') { callback = metadata; metadata = new Metadata(); options = {}; @@ -470,7 +470,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, } if (!((metadata instanceof Metadata) && (options instanceof Object) && - (_.isFunction(callback)))) { + (typeof callback === 'function'))) { throw new Error('Argument mismatch in makeUnaryRequest'); } @@ -552,7 +552,7 @@ Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, Client.prototype.makeClientStreamRequest = function(path, serialize, deserialize, metadata, options, callback) { - if (_.isFunction(options)) { + if (typeof options === 'function') { callback = options; if (metadata instanceof Metadata) { options = {}; @@ -560,7 +560,7 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, options = metadata; metadata = new Metadata(); } - } else if (_.isFunction(metadata)) { + } else if (typeof metadata === 'function') { callback = metadata; metadata = new Metadata(); options = {}; @@ -573,7 +573,7 @@ Client.prototype.makeClientStreamRequest = function(path, serialize, } if (!((metadata instanceof Metadata) && (options instanceof Object) && - (_.isFunction(callback)))) { + (typeof callback === 'function'))) { throw new Error('Argument mismatch in makeClientStreamRequest'); } From 50ead820a202df8594f868d24851c7629601335c Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 12 Nov 2018 20:47:12 -0800 Subject: [PATCH 0443/1899] refactor: use Array.isArray instead of _.isArray --- packages/grpc-native-core/src/client.js | 6 +++--- packages/grpc-native-core/src/client_interceptors.js | 2 +- packages/grpc-native-core/src/protobuf_js_5_common.js | 2 +- packages/grpc-native-core/test/client_interceptors_test.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 5a7086f31..d82848cd8 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -371,7 +371,7 @@ function Client(address, credentials, options) { } // Resolve interceptor options and assign interceptors to each method - if (_.isArray(options.interceptor_providers) && _.isArray(options.interceptors)) { + if (Array.isArray(options.interceptor_providers) && Array.isArray(options.interceptors)) { throw new client_interceptors.InterceptorConfigurationError( 'Both interceptors and interceptor_providers were passed as options ' + 'to the client constructor. Only one of these is allowed.'); @@ -409,12 +409,12 @@ function Client(address, credentials, options) { exports.Client = Client; Client.prototype.resolveCallInterceptors = function(method_definition, interceptors, interceptor_providers) { - if (_.isArray(interceptors) && _.isArray(interceptor_providers)) { + if (Array.isArray(interceptors) && Array.isArray(interceptor_providers)) { throw new client_interceptors.InterceptorConfigurationError( 'Both interceptors and interceptor_providers were passed as call ' + 'options. Only one of these is allowed.'); } - if (_.isArray(interceptors) || _.isArray(interceptor_providers)) { + if (Array.isArray(interceptors) || Array.isArray(interceptor_providers)) { interceptors = interceptors || []; interceptor_providers = interceptor_providers || []; return client_interceptors.resolveInterceptorProviders(interceptor_providers, method_definition).concat(interceptors); diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 5ef89a5d3..d75026caf 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -353,7 +353,7 @@ RequesterBuilder.prototype.build = function() { * @return {null|Interceptor[]} */ var resolveInterceptorProviders = function(providers, method_definition) { - if (!_.isArray(providers)) { + if (!Array.isArray(providers)) { return null; } var interceptors = []; diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js index cf377d2b0..3be4ef04b 100644 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ b/packages/grpc-native-core/src/protobuf_js_5_common.js @@ -167,5 +167,5 @@ exports.loadObject = function loadObject(value, options) { * ReflectionObject */ exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) { - return _.isArray(obj.children) && (typeof obj.build === 'function'); + return Array.isArray(obj.children) && (typeof obj.build === 'function'); }; diff --git a/packages/grpc-native-core/test/client_interceptors_test.js b/packages/grpc-native-core/test/client_interceptors_test.js index b14ec1569..69cd25d72 100644 --- a/packages/grpc-native-core/test/client_interceptors_test.js +++ b/packages/grpc-native-core/test/client_interceptors_test.js @@ -39,7 +39,7 @@ var CallRegistry = function(done, expectation, is_ordered, is_verbose) { this.call_array = []; this.done = done; this.expectation = expectation; - this.expectation_is_array = _.isArray(this.expectation); + this.expectation_is_array = Array.isArray(this.expectation); this.is_ordered = is_ordered; this.is_verbose = is_verbose; if (is_verbose) { From 7a92e7cd1960b372b1e24b55035cfc68ad72c704 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 12 Nov 2018 22:16:15 -0800 Subject: [PATCH 0444/1899] refactor: drop usage of _.bind --- packages/grpc-native-core/src/server.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 9f1715e0b..ab3a95de2 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -871,14 +871,15 @@ Server.prototype.addService = function(service, implementation) { if (!_.isObject(service) || !_.isObject(implementation)) { throw new Error('addService requires two objects as arguments'); } - if (_.keys(service).length === 0) { + if (Object.keys(service).length === 0) { throw new Error('Cannot add an empty service to a server'); } if (this.started) { throw new Error('Can\'t add a service to a started server.'); } var self = this; - _.forOwn(service, function(attrs, name) { + Object.keys(service).forEach(key => { + const attrs = service[key]; var method_type; if (attrs.requestStream) { if (attrs.responseStream) { @@ -903,10 +904,10 @@ Server.prototype.addService = function(service, implementation) { ' for ' + attrs.path + ' expected but not provided'); impl = defaultHandler[method_type]; } else { - impl = _.bind(implementation[attrs.originalName], implementation); + impl = implementation[attrs.originalName].bind(implementation); } } else { - impl = _.bind(implementation[name], implementation); + impl = implementation[name].bind(implementation); } var serialize = attrs.responseSerialize; var deserialize = attrs.requestDeserialize; From 3bad9ae8f5b01cf98b77882531b951573eaef7c4 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 12 Nov 2018 22:23:48 -0800 Subject: [PATCH 0445/1899] refactor: use Object.assign --- packages/grpc-native-core/index.js | 6 +++--- packages/grpc-native-core/src/server.js | 4 ++-- packages/grpc-native-core/test/common_test.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index b01736b11..096e74590 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -72,8 +72,8 @@ grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii')); * @return {Object} The resulting gRPC object. */ exports.loadObject = function loadObject(value, options) { - options = _.defaults(options, common.defaultGrpcOptions); - options = _.defaults(options, {'protobufjsVersion': 'detect'}); + options = Object.assign(common.defaultGrpcOptions, options); + options = Object.assign({'protobufjsVersion': 'detect'}, options); var protobufjsVersion; if (options.protobufjsVersion === 'detect') { if (protobuf_js_6_common.isProbablyProtobufJs6(value)) { @@ -122,7 +122,7 @@ var loadObject = exports.loadObject; * @return {Object} The resulting gRPC object */ exports.load = util.deprecate(function load(filename, format, options) { - options = _.defaults(options, common.defaultGrpcOptions); + options = Object.assign(common.defaultGrpcOptions, options); options.protobufjsVersion = 5; if (!format) { format = 'proto'; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 9f1715e0b..795b67729 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -932,12 +932,12 @@ Server.prototype.addProtoService = util.deprecate(function(service, var protobuf_js_5_common = require('./protobuf_js_5_common'); var protobuf_js_6_common = require('./protobuf_js_6_common'); if (protobuf_js_5_common.isProbablyProtobufJs5(service)) { - options = _.defaults(service.grpc_options, common.defaultGrpcOptions); + options = Object.assign(common.defaultGrpcOptions, service.grpc_options); this.addService( protobuf_js_5_common.getProtobufServiceAttrs(service, options), implementation); } else if (protobuf_js_6_common.isProbablyProtobufJs6(service)) { - options = _.defaults(service.grpc_options, common.defaultGrpcOptions); + options = Object.assign(common.defaultGrpcOptions, service.grpc_options); this.addService( protobuf_js_6_common.getProtobufServiceAttrs(service, options), implementation); diff --git a/packages/grpc-native-core/test/common_test.js b/packages/grpc-native-core/test/common_test.js index d50c1a276..5251320a1 100644 --- a/packages/grpc-native-core/test/common_test.js +++ b/packages/grpc-native-core/test/common_test.js @@ -81,7 +81,7 @@ describe('Proto message long int serialize and deserialize', function() { neg_value); }); it('should deserialize as a number with the right option set', function() { - var num_options = _.defaults({longsAsStrings: false}, default_options); + var num_options = Object.assign(default_options, {longsAsStrings: false}); var longNumDeserialize = deserializeCls(messages_proto.LongValues, num_options); var serialized = longSerialize({int_64: pos_value}); @@ -95,7 +95,7 @@ describe('Proto message bytes serialize and deserialize', function() { var sequenceSerialize = serializeCls(messages_proto.SequenceValues); var sequenceDeserialize = deserializeCls( messages_proto.SequenceValues, default_options); - var b64_options = _.defaults({binaryAsBase64: true}, default_options); + var b64_options = Object.assign(default_options, {binaryAsBase64: true}); var sequenceBase64Deserialize = deserializeCls( messages_proto.SequenceValues, b64_options); var buffer_val = new Buffer([0x69, 0xb7]); @@ -169,7 +169,7 @@ describe('Proto message enum serialize and deserialize', function() { var enumSerialize = serializeCls(messages_proto.EnumValues); var enumDeserialize = deserializeCls( messages_proto.EnumValues, default_options); - var enumIntOptions = _.defaults({enumsAsStrings: false}, default_options); + var enumIntOptions = Object.assign(default_options, {enumsAsStrings: false}); var enumIntDeserialize = deserializeCls( messages_proto.EnumValues, enumIntOptions); it('Should accept both names and numbers', function() { From 91ca09d6fec37e1c0a81369e8cf9e54cb028ba90 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 12 Nov 2018 22:40:43 -0800 Subject: [PATCH 0446/1899] refactor: drop usage of _.union --- packages/grpc-native-core/src/client_interceptors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 5ef89a5d3..c132e15bd 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -751,7 +751,7 @@ function _startBatchIfReady(call, batch, batch_state, callback) { // Dependencies are met, start the batch and any deferred batches whose // dependencies are met as a result. call.startBatch(batch, callback); - completed_ops = _.union(completed_ops, batch_ops); + completed_ops = Array.from(new Set(completed_ops.concat(batch_ops))); deferred_batches = _.flatMap(deferred_batches, function(deferred_batch) { var deferred_batch_ops = _.keys(deferred_batch).map(Number); if (_areBatchRequirementsMet(deferred_batch_ops, completed_ops)) { From 69882cb5f690b319b7f06ccb1271e220aa00b2fb Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Tue, 13 Nov 2018 10:06:23 -0800 Subject: [PATCH 0447/1899] fixy --- packages/grpc-native-core/src/server.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index ab3a95de2..5cd1b6418 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -871,15 +871,14 @@ Server.prototype.addService = function(service, implementation) { if (!_.isObject(service) || !_.isObject(implementation)) { throw new Error('addService requires two objects as arguments'); } - if (Object.keys(service).length === 0) { + if (_.keys(service).length === 0) { throw new Error('Cannot add an empty service to a server'); } if (this.started) { throw new Error('Can\'t add a service to a started server.'); } var self = this; - Object.keys(service).forEach(key => { - const attrs = service[key]; + _.forOwn(service, function(attrs, name) { var method_type; if (attrs.requestStream) { if (attrs.responseStream) { From d5fc72bd5cf740d8537679b2f49707f684e94a5e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 14 Nov 2018 11:13:15 -0800 Subject: [PATCH 0448/1899] Add missing properties to ClientHttp2StreamMock --- packages/grpc-js/test/test-call-stream.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index c832bce99..194db05c3 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -1,4 +1,5 @@ import * as assert from 'assert'; +import {OutgoingHttpHeaders} from 'http'; import * as http2 from 'http2'; import {range} from 'lodash'; import * as stream from 'stream'; @@ -46,6 +47,9 @@ class ClientHttp2StreamMock extends stream.Duplex implements endAfterHeaders = false; pending = false; rstCode = 0; + readonly sentHeaders: OutgoingHttpHeaders = {}; + readonly sentInfoHeaders?: OutgoingHttpHeaders[] = []; + readonly sentTrailers?: OutgoingHttpHeaders = undefined; // tslint:disable:no-any session: http2.Http2Session = {} as any; state: http2.StreamState = {} as any; @@ -76,6 +80,9 @@ class ClientHttp2StreamMock extends stream.Duplex implements this.emit('write', chunk); cb(); } + sendTrailers(headers: OutgoingHttpHeaders) { + return this; + } } describe('CallStream', () => { From b85a63c7c977c8f8112297e80f455336a8b151ad Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Wed, 14 Nov 2018 16:15:55 -0800 Subject: [PATCH 0449/1899] =?UTF-8?q?=F0=9F=91=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/grpc-native-core/index.js | 6 +++--- packages/grpc-native-core/src/server.js | 4 ++-- packages/grpc-native-core/test/common_test.js | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 096e74590..e6105534f 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -72,8 +72,8 @@ grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii')); * @return {Object} The resulting gRPC object. */ exports.loadObject = function loadObject(value, options) { - options = Object.assign(common.defaultGrpcOptions, options); - options = Object.assign({'protobufjsVersion': 'detect'}, options); + options = Object.assign({}, common.defaultGrpcOptions, options); + options = Object.assign({}, {'protobufjsVersion': 'detect'}, options); var protobufjsVersion; if (options.protobufjsVersion === 'detect') { if (protobuf_js_6_common.isProbablyProtobufJs6(value)) { @@ -122,7 +122,7 @@ var loadObject = exports.loadObject; * @return {Object} The resulting gRPC object */ exports.load = util.deprecate(function load(filename, format, options) { - options = Object.assign(common.defaultGrpcOptions, options); + options = Object.assign({}, common.defaultGrpcOptions, options); options.protobufjsVersion = 5; if (!format) { format = 'proto'; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 795b67729..c4e205bbc 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -932,12 +932,12 @@ Server.prototype.addProtoService = util.deprecate(function(service, var protobuf_js_5_common = require('./protobuf_js_5_common'); var protobuf_js_6_common = require('./protobuf_js_6_common'); if (protobuf_js_5_common.isProbablyProtobufJs5(service)) { - options = Object.assign(common.defaultGrpcOptions, service.grpc_options); + options = Object.assign({}, common.defaultGrpcOptions, service.grpc_options); this.addService( protobuf_js_5_common.getProtobufServiceAttrs(service, options), implementation); } else if (protobuf_js_6_common.isProbablyProtobufJs6(service)) { - options = Object.assign(common.defaultGrpcOptions, service.grpc_options); + options = Object.assign({}, common.defaultGrpcOptions, service.grpc_options); this.addService( protobuf_js_6_common.getProtobufServiceAttrs(service, options), implementation); diff --git a/packages/grpc-native-core/test/common_test.js b/packages/grpc-native-core/test/common_test.js index 5251320a1..404ca2c38 100644 --- a/packages/grpc-native-core/test/common_test.js +++ b/packages/grpc-native-core/test/common_test.js @@ -81,7 +81,7 @@ describe('Proto message long int serialize and deserialize', function() { neg_value); }); it('should deserialize as a number with the right option set', function() { - var num_options = Object.assign(default_options, {longsAsStrings: false}); + var num_options = Object.assign({}, default_options, {longsAsStrings: false}); var longNumDeserialize = deserializeCls(messages_proto.LongValues, num_options); var serialized = longSerialize({int_64: pos_value}); @@ -95,7 +95,7 @@ describe('Proto message bytes serialize and deserialize', function() { var sequenceSerialize = serializeCls(messages_proto.SequenceValues); var sequenceDeserialize = deserializeCls( messages_proto.SequenceValues, default_options); - var b64_options = Object.assign(default_options, {binaryAsBase64: true}); + var b64_options = Object.assign({}, default_options, {binaryAsBase64: true}); var sequenceBase64Deserialize = deserializeCls( messages_proto.SequenceValues, b64_options); var buffer_val = new Buffer([0x69, 0xb7]); @@ -169,7 +169,7 @@ describe('Proto message enum serialize and deserialize', function() { var enumSerialize = serializeCls(messages_proto.EnumValues); var enumDeserialize = deserializeCls( messages_proto.EnumValues, default_options); - var enumIntOptions = Object.assign(default_options, {enumsAsStrings: false}); + var enumIntOptions = Object.assign({}, default_options, {enumsAsStrings: false}); var enumIntDeserialize = deserializeCls( messages_proto.EnumValues, enumIntOptions); it('Should accept both names and numbers', function() { From 9f0de51d8a78dd8ee9e6f1c912f021fee2cc11c2 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Wed, 14 Nov 2018 16:27:17 -0800 Subject: [PATCH 0450/1899] refactor: use Object.keys --- packages/grpc-native-core/src/client_interceptors.js | 4 ++-- packages/grpc-native-core/src/server.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index d75026caf..5ad6f2544 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -746,14 +746,14 @@ function _areBatchRequirementsMet(batch_ops, completed_ops) { function _startBatchIfReady(call, batch, batch_state, callback) { var completed_ops = batch_state.completed_ops; var deferred_batches = batch_state.deferred_batches; - var batch_ops = _.keys(batch).map(Number); + var batch_ops = Object.keys(batch).map(Number); if (_areBatchRequirementsMet(batch_ops, completed_ops)) { // Dependencies are met, start the batch and any deferred batches whose // dependencies are met as a result. call.startBatch(batch, callback); completed_ops = _.union(completed_ops, batch_ops); deferred_batches = _.flatMap(deferred_batches, function(deferred_batch) { - var deferred_batch_ops = _.keys(deferred_batch).map(Number); + var deferred_batch_ops = Object.keys(deferred_batch).map(Number); if (_areBatchRequirementsMet(deferred_batch_ops, completed_ops)) { call.startBatch(deferred_batch.batch, deferred_batch.callback); return []; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 5cd1b6418..d04db756c 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -871,7 +871,7 @@ Server.prototype.addService = function(service, implementation) { if (!_.isObject(service) || !_.isObject(implementation)) { throw new Error('addService requires two objects as arguments'); } - if (_.keys(service).length === 0) { + if (Object.keys(service).length === 0) { throw new Error('Cannot add an empty service to a server'); } if (this.started) { From 98140ecf2c9e6eae2da00998e9260a76323011c5 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Wed, 14 Nov 2018 16:32:26 -0800 Subject: [PATCH 0451/1899] refactor: stop using _.identity --- packages/grpc-native-core/src/client.js | 4 +- packages/grpc-native-core/src/common.js | 2 +- .../grpc-native-core/test/surface_test.js | 48 +++++++++---------- 3 files changed, 27 insertions(+), 27 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index d82848cd8..c37ff1eb0 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -895,8 +895,8 @@ var deprecated_request_wrap = { opt_args.options, callback); }; }, - [methodTypes.SERVER_STREAMING]: _.identity, - [methodTypes.BIDI_STREAMING]: _.identity + [methodTypes.SERVER_STREAMING]: x => x, + [methodTypes.BIDI_STREAMING]: x => x }; /** diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 0c35296a8..95fdb2f2e 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -30,7 +30,7 @@ var constants = require('./constants'); */ exports.wrapIgnoreNull = function wrapIgnoreNull(func) { if (!func) { - return _.identity; + return x => x; } return function(arg) { if (arg === null || arg === undefined) { diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 9fe132ceb..a12d3c3b0 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -204,10 +204,10 @@ describe('Client constructor building', function() { path: '/illegal/$method', requestStream: false, responseStream: false, - requestSerialize: _.identity, - requestDeserialize: _.identity, - responseSerialize: _.identity, - responseDeserialize: _.identity + requestSerialize: x => x, + requestDeserialize: x => x, + responseSerialize: x => x, + responseDeserialize: x => x } }; it('Should reject method names starting with $', function() { @@ -628,29 +628,29 @@ describe('Client malformed response handling', function() { path: '/TestService/Unary', requestStream: false, responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity + requestDeserialize: x => x, + responseSerialize: x => x }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity + requestDeserialize: x => x, + responseSerialize: x => x }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity + requestDeserialize: x => x, + responseSerialize: x => x }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity + requestDeserialize: x => x, + responseSerialize: x => x } }; server = new grpc.Server(); @@ -729,28 +729,28 @@ describe('Server serialization failure handling', function() { path: '/TestService/Unary', requestStream: false, responseStream: false, - requestDeserialize: _.identity, + requestDeserialize: x => x, responseSerialize: serializeFail }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, - requestDeserialize: _.identity, + requestDeserialize: x => x, responseSerialize: serializeFail }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, - requestDeserialize: _.identity, + requestDeserialize: x => x, responseSerialize: serializeFail }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, - requestDeserialize: _.identity, + requestDeserialize: x => x, responseSerialize: serializeFail } }; @@ -943,29 +943,29 @@ describe('Other conditions', function() { path: '/TestService/Unary', requestStream: false, responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestSerialize: x => x, + responseDeserialize: x => x }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestSerialize: x => x, + responseDeserialize: x => x }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestSerialize: x => x, + responseDeserialize: x => x }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestSerialize: x => x, + responseDeserialize: x => x } }; var Client = grpc.makeGenericClientConstructor(test_service_attrs, From 7cba96910ca06e69f082a0165a7caad4274ddd12 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Fri, 9 Nov 2018 17:02:48 -0800 Subject: [PATCH 0452/1899] refactor: drop usage of _.isObject --- packages/grpc-native-core/src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 5cd1b6418..2b05d3dbf 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -868,7 +868,7 @@ var defaultHandler = { * names to method implementation for the provided service. */ Server.prototype.addService = function(service, implementation) { - if (!_.isObject(service) || !_.isObject(implementation)) { + if (typeof service !== 'object' || typeof implementation !== 'object') { throw new Error('addService requires two objects as arguments'); } if (_.keys(service).length === 0) { From 889c2218da24ab924b4e07874218a1b0c6228955 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Wed, 14 Nov 2018 16:43:55 -0800 Subject: [PATCH 0453/1899] checks --- packages/grpc-native-core/src/server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 2b05d3dbf..91377ff9f 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -861,6 +861,10 @@ var defaultHandler = { } }; +function isObject(thing) { + return (typeof thing === 'object' || typeof thing === 'function') && thing !== null; +} + /** * Add a service to the server, with a corresponding implementation. * @param {grpc~ServiceDefinition} service The service descriptor @@ -868,7 +872,7 @@ var defaultHandler = { * names to method implementation for the provided service. */ Server.prototype.addService = function(service, implementation) { - if (typeof service !== 'object' || typeof implementation !== 'object') { + if (!isObject(service) || !isObject(implementation)) { throw new Error('addService requires two objects as arguments'); } if (_.keys(service).length === 0) { From 715b0a556079a21ff5cdf4ee389b8b477f4cd9a0 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Wed, 14 Nov 2018 18:55:57 -0800 Subject: [PATCH 0454/1899] refactor: drop usage of _.zipObject --- packages/grpc-native-core/src/common.js | 14 ++++++++++++++ .../grpc-native-core/src/protobuf_js_5_common.js | 3 ++- .../grpc-native-core/src/protobuf_js_6_common.js | 3 ++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 0c35296a8..197cd7d80 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -112,6 +112,20 @@ exports.getMethodType = function(method_definition) { } }; +/** + * Given an array of property names and an array of values, + * combine the two into an object map. + * Equivalent to _.zipObject. + * @param props {Array} Array of property names + * @param values {Array} Array of property values + * @return {Object} An object with the combined values + */ +exports.zipObject = function(props, values) { + return props.reduce((acc, curr, idx) => { + return Object.assign(acc, { [curr]: values[idx] }); + }, {}); +} + // JSDoc definitions that are used in multiple other modules /** diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js index 3be4ef04b..1e6cc8105 100644 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ b/packages/grpc-native-core/src/protobuf_js_5_common.js @@ -25,6 +25,7 @@ var _ = require('lodash'); var client = require('./client'); +var common = require('./common'); /** * Get a function that deserializes a specific type of protobuf. @@ -106,7 +107,7 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, lodash@3.10.1-compatible functions. A previous version used _.fromPairs, which would be cleaner, but was introduced in lodash version 4 */ - return _.zipObject(service.children.map(function(method) { + return common.zipObject(service.children.map(function(method) { return _.camelCase(method.name); }), service.children.map(function(method) { return { diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index 04121ad42..db3461167 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -25,6 +25,7 @@ var _ = require('lodash'); var client = require('./client'); +var common = require('./common'); /** * Get a function that deserializes a specific type of protobuf. @@ -103,7 +104,7 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, options) { var prefix = '/' + fullyQualifiedName(service) + '/'; service.resolveAll(); - return _.zipObject(service.methods.map(function(method) { + return common.zipObject(service.methods.map(function(method) { return _.camelCase(method.name); }), service.methods.map(function(method) { return { From f50ba3af4bfca3cb05457958a72d231523410938 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 10:41:20 -0800 Subject: [PATCH 0455/1899] Update common.js --- packages/grpc-native-core/src/common.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 197cd7d80..c3c76989b 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -116,6 +116,9 @@ exports.getMethodType = function(method_definition) { * Given an array of property names and an array of values, * combine the two into an object map. * Equivalent to _.zipObject. + * + * @private + * * @param props {Array} Array of property names * @param values {Array} Array of property values * @return {Object} An object with the combined values From f7684457719bb3fa7875d77285a48d8b231c6171 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 12:05:56 -0800 Subject: [PATCH 0456/1899] refactor: replace _.assign with Object.assign --- packages/grpc-native-core/src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index c37ff1eb0..31a1738c6 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -950,7 +950,7 @@ exports.makeClientConstructor = function(methods, serviceName, } ServiceClient.prototype.$method_names[attrs.path] = name; // Associate all provided attributes with the method - _.assign(ServiceClient.prototype[name], attrs); + Object.assign(ServiceClient.prototype[name], attrs); if (attrs.originalName) { ServiceClient.prototype[attrs.originalName] = ServiceClient.prototype[name]; From c415fe03cd33049d3875b39e7eb10b3e635353d1 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 12:28:31 -0800 Subject: [PATCH 0457/1899] refactor: drop usage of _.forOwn --- packages/grpc-native-core/src/metadata.js | 9 ++++++--- packages/grpc-native-core/src/server.js | 3 ++- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js index 2b10bc80f..9d00c7226 100644 --- a/packages/grpc-native-core/src/metadata.js +++ b/packages/grpc-native-core/src/metadata.js @@ -122,7 +122,8 @@ Metadata.prototype.get = function(key) { */ Metadata.prototype.getMap = function() { var result = {}; - _.forOwn(this._internal_repr, function(values, key) { + Object.keys(this._internal_repr).forEach(key => { + const values = this._internal_repr[key]; if(values.length > 0) { result[key] = values[0]; } @@ -136,7 +137,8 @@ Metadata.prototype.getMap = function() { */ Metadata.prototype.clone = function() { var copy = new Metadata(); - _.forOwn(this._internal_repr, function(value, key) { + Object.keys(this._internal_repr).forEach(key => { + const value = this._internal_repr[key]; copy._internal_repr[key] = _.clone(value); }); return copy; @@ -162,7 +164,8 @@ Metadata.prototype._getCoreRepresentation = function() { Metadata._fromCoreRepresentation = function(metadata) { var newMetadata = new Metadata(); if (metadata) { - _.forOwn(metadata, function(value, key) { + Object.keys(metadata).forEach(key => { + const value = metadata[key]; newMetadata._internal_repr[key] = _.clone(value); }); } diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 15b43022c..bc333e4a0 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -878,7 +878,8 @@ Server.prototype.addService = function(service, implementation) { throw new Error('Can\'t add a service to a started server.'); } var self = this; - _.forOwn(service, function(attrs, name) { + Object.keys(service).forEach(name => { + const attrs = service[name]; var method_type; if (attrs.requestStream) { if (attrs.responseStream) { From c06bbf6c48bee1e6178553d59f8d07f445db1425 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 14 Nov 2018 11:13:15 -0800 Subject: [PATCH 0458/1899] Add missing properties to ClientHttp2StreamMock --- packages/grpc-js-core/test/test-call-stream.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js-core/test/test-call-stream.ts b/packages/grpc-js-core/test/test-call-stream.ts index c832bce99..194db05c3 100644 --- a/packages/grpc-js-core/test/test-call-stream.ts +++ b/packages/grpc-js-core/test/test-call-stream.ts @@ -1,4 +1,5 @@ import * as assert from 'assert'; +import {OutgoingHttpHeaders} from 'http'; import * as http2 from 'http2'; import {range} from 'lodash'; import * as stream from 'stream'; @@ -46,6 +47,9 @@ class ClientHttp2StreamMock extends stream.Duplex implements endAfterHeaders = false; pending = false; rstCode = 0; + readonly sentHeaders: OutgoingHttpHeaders = {}; + readonly sentInfoHeaders?: OutgoingHttpHeaders[] = []; + readonly sentTrailers?: OutgoingHttpHeaders = undefined; // tslint:disable:no-any session: http2.Http2Session = {} as any; state: http2.StreamState = {} as any; @@ -76,6 +80,9 @@ class ClientHttp2StreamMock extends stream.Duplex implements this.emit('write', chunk); cb(); } + sendTrailers(headers: OutgoingHttpHeaders) { + return this; + } } describe('CallStream', () => { From cc1d1f49134cdb5c95a04e8e395a6b3ae0c70eaa Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 13:30:19 -0800 Subject: [PATCH 0459/1899] refactor: drop usage of _.flatMap --- .../grpc-native-core/src/client_interceptors.js | 4 ++-- packages/grpc-native-core/src/common.js | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 5ad6f2544..992cb4802 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -716,7 +716,7 @@ function _getStreamReadCallback(emitter, call, get_listener, deserialize) { * @return {boolean} */ function _areBatchRequirementsMet(batch_ops, completed_ops) { - var dependencies = _.flatMap(batch_ops, function(op) { + var dependencies = common.flatMap(batch_ops, function(op) { return OP_DEPENDENCIES[op] || []; }); for (var i = 0; i < dependencies.length; i++) { @@ -752,7 +752,7 @@ function _startBatchIfReady(call, batch, batch_state, callback) { // dependencies are met as a result. call.startBatch(batch, callback); completed_ops = _.union(completed_ops, batch_ops); - deferred_batches = _.flatMap(deferred_batches, function(deferred_batch) { + deferred_batches = common.flatMap(deferred_batches, function(deferred_batch) { var deferred_batch_ops = Object.keys(deferred_batch).map(Number); if (_areBatchRequirementsMet(deferred_batch_ops, completed_ops)) { call.startBatch(deferred_batch.batch, deferred_batch.callback); diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 187dd3ebd..834c5f953 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -112,11 +112,26 @@ exports.getMethodType = function(method_definition) { } }; +/** + * Iterate over a collection of items, and run the given handler. + * Return the results as a flattened array of values. + * + * @private + * + * @param {Array} collection Array of items to process + * @param {Function} handler The function to call on each element in the array + * @return {Array} A flattened array of results. + */ +exports.flatMap = function(collection, handler) { + const mapped = collection.map(handler); + return mapped.reduce((acc, curr) => acc.concat(curr), []); +} + /** * Given an array of property names and an array of values, * combine the two into an object map. * Equivalent to _.zipObject. - * + * * @private * * @param props {Array} Array of property names From 51e7ff0f5c854d84f17bdfb10cde2c1afba8352c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 24 Oct 2018 23:16:10 +0200 Subject: [PATCH 0460/1899] Sprinkling node 11, and removing travis file. --- .travis.yml | 21 ------------------- .../artifacts/build_artifact_node.bat | 2 +- .../artifacts/build_artifact_node.sh | 2 +- .../artifacts/build_artifact_node_arm.sh | 2 +- 4 files changed, 3 insertions(+), 24 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 94bb48a55..000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -language: node_js -node_js: - - "4" - - "5" - - "6" - - "7" - - "8" - - "node" -env: - - CXX=g++-4.8 -addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - g++-4.8 -install: - - npm install - - gulp setup -script: - - gulp native.test diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index eb8f75534..fd80f272b 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 +set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index d25bed842..1faa8c051 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 ) electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 ) while true ; do diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index eee6ff8fd..139d34328 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -26,7 +26,7 @@ mkdir -p "${ARTIFACTS_OUT}" npm update -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 ) for version in ${node_versions[@]} do From d23728c3837300e9615a34cf09ff617111bf59d7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 15 Nov 2018 20:08:30 +0100 Subject: [PATCH 0461/1899] Update to node-pre-gyp 0.12.0. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 36ae03baf..f3987f4cb 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -31,7 +31,7 @@ "dependencies": { "lodash": "^4.17.5", "nan": "^2.0.0", - "node-pre-gyp": "^0.10.0", + "node-pre-gyp": "^0.12.0", "protobufjs": "^5.0.3" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index bd72b72a1..2563912b0 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -33,7 +33,7 @@ "dependencies": { "lodash": "^4.17.5", "nan": "^2.0.0", - "node-pre-gyp": "^0.10.0", + "node-pre-gyp": "^0.12.0", "protobufjs": "^5.0.3" }, "devDependencies": { From b3a78f59de5c12d2c7da6a7c6e31ec5b46c1ae5f Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 15:21:24 -0800 Subject: [PATCH 0462/1899] refactor: drop usage of _.get --- packages/grpc-native-core/src/client_interceptors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 1d0964a67..7066600c2 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -646,7 +646,7 @@ function getCall(channel, path, options) { if (options) { deadline = options.deadline; host = options.host; - parent = _.get(options, 'parent.call'); + parent = options.parent ? options.parent.call : undefined; propagate_flags = options.propagate_flags; credentials = options.credentials; } From ba6c7ca4ceb464835a09fdd3382b6ac5bc44a616 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Nov 2018 00:58:43 +0100 Subject: [PATCH 0463/1899] Removing previous builds before going on with the next one. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index fd80f272b..3b4b084d8 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -38,12 +38,14 @@ for %%a in (%arch_list%) do ( call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + rmdir build /S /Q ) for %%v in (%electron_versions%) do ( cmd /V /C "set "HOME=%USERPROFILE%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package --runtime=electron --target=%%v --target_arch=%%a --disturl=https://atom.io/download/electron" || goto :error xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + rmdir build /S /Q ) ) if %errorlevel% neq 0 exit /b %errorlevel% From 31879f85614fc27f3cb400345055d24c1679e26d Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 17:58:14 -0800 Subject: [PATCH 0464/1899] refactor: drop usage of _.each --- packages/grpc-native-core/src/client.js | 6 ++++-- packages/grpc-native-core/src/protobuf_js_5_common.js | 3 ++- packages/grpc-native-core/src/protobuf_js_6_common.js | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 31a1738c6..d1390742a 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -378,7 +378,8 @@ function Client(address, credentials, options) { } self.$interceptors = options.interceptors || []; self.$interceptor_providers = options.interceptor_providers || []; - _.each(self.$method_definitions, function(method_definition, method_name) { + Object.keys(self.$method_definitions).forEach(method_name => { + const method_definition = self.$method_definitions[method_name]; self[method_name].interceptors = client_interceptors .resolveInterceptorProviders(self.$interceptor_providers, method_definition) .concat(self.$interceptors); @@ -934,7 +935,8 @@ exports.makeClientConstructor = function(methods, serviceName, ServiceClient.prototype.$method_definitions = methods; ServiceClient.prototype.$method_names = {}; - _.each(methods, function(attrs, name) { + Object.keys(methods).forEach(name => { + const attrs = methods[name]; if (name.indexOf('$') === 0) { throw new Error('Method names cannot start with $'); } diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js index 1e6cc8105..6af6c4ac8 100644 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ b/packages/grpc-native-core/src/protobuf_js_5_common.js @@ -144,7 +144,8 @@ exports.loadObject = function loadObject(value, options) { return loadObject(value.ns, options); } if (value.className === 'Namespace') { - _.each(value.children, function(child) { + Object.keys(value.children).forEach(key => { + const child = value.children[key]; result[child.name] = loadObject(child, options); }); return result; diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index db3461167..f68256a9a 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -137,7 +137,8 @@ exports.loadObject = function loadObject(value, options) { if (value.hasOwnProperty('nested')) { // It's a namespace or root object - _.each(value.nested, function(nested, name) { + Object.keys(value.nested).forEach(name => { + const nested = value.nested[name]; result[name] = loadObject(nested, options); }); return result; From 1b57e54e68cb6f047e6fe3e0f26c5fea42f63b9a Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 16:30:26 -0800 Subject: [PATCH 0465/1899] refactor: drop usage of _.partial --- packages/grpc-native-core/src/client.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 31a1738c6..8cfa19fab 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -939,9 +939,11 @@ exports.makeClientConstructor = function(methods, serviceName, throw new Error('Method names cannot start with $'); } var method_type = common.getMethodType(attrs); - var method_func = _.partial(requester_funcs[method_type], attrs.path, - attrs.requestSerialize, - attrs.responseDeserialize); + var method_func = function() { + return requester_funcs[method_type].apply(this, arguments.concat([ + attrs.path, attrs.requestSerialize, attrs.responseDeserialize + ])); + }; if (class_options.deprecatedArgumentOrder) { ServiceClient.prototype[name] = deprecated_request_wrap[method_type](method_func); From b17d034e3942f07300c2b73fdaa35caf40846448 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 18:06:59 -0800 Subject: [PATCH 0466/1899] lefix --- packages/grpc-native-core/src/client.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 8cfa19fab..6a73b21e8 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -940,9 +940,11 @@ exports.makeClientConstructor = function(methods, serviceName, } var method_type = common.getMethodType(attrs); var method_func = function() { - return requester_funcs[method_type].apply(this, arguments.concat([ - attrs.path, attrs.requestSerialize, attrs.responseDeserialize - ])); + return requester_funcs[method_type].apply(this, + [].slice.call(arguments).concat([ + attrs.path, attrs.requestSerialize, attrs.responseDeserialize + ]) + ); }; if (class_options.deprecatedArgumentOrder) { ServiceClient.prototype[name] = From bba0644db5e5de2d12a650d6fcd40fb8190a777b Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 16:43:33 -0800 Subject: [PATCH 0467/1899] refactor: drop usage of _.mapValues --- packages/grpc-native-core/src/client.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 31a1738c6..1e87a75fb 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -980,9 +980,10 @@ exports.getClientChannel = function(client) { * @returns {Object.} */ exports.getClientInterceptors = function(client) { - return _.mapValues(client.$method_definitions, function(def, name) { - return client[name].interceptors; - }); + return Object.keys(client.$method_definitions) + .reduce((acc, key) => { + acc[key] = client[key].interceptors; + }, {}); }; /** From 0c701e8da6e87b78e1f7e167a19218436d57ab35 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 17:44:39 -0800 Subject: [PATCH 0468/1899] oooops --- packages/grpc-native-core/src/client.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 1e87a75fb..7675338a1 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -983,6 +983,7 @@ exports.getClientInterceptors = function(client) { return Object.keys(client.$method_definitions) .reduce((acc, key) => { acc[key] = client[key].interceptors; + return acc; }, {}); }; From 93381c6a0cd1c0d502c7fff10064066ad67ae89c Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 18:10:02 -0800 Subject: [PATCH 0469/1899] eh --- packages/grpc-native-core/src/client.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 7675338a1..803df2d31 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -982,7 +982,9 @@ exports.getClientChannel = function(client) { exports.getClientInterceptors = function(client) { return Object.keys(client.$method_definitions) .reduce((acc, key) => { - acc[key] = client[key].interceptors; + if (typeof key === 'string') { + acc[key] = client[key].interceptors; + } return acc; }, {}); }; From d1b0ce297690ad18e9979ca9a8d73549ff56a60c Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Thu, 15 Nov 2018 19:09:43 -0800 Subject: [PATCH 0470/1899] refactor: drop usage of _.invert --- packages/grpc-native-core/src/common.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 834c5f953..93c92dc34 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -82,7 +82,12 @@ exports.defaultGrpcOptions = { * @return {Error} The resulting Error */ exports.createStatusError = function(status) { - let statusName = _.invert(constants.status)[status.code]; + let inverted = Object.keys(constants.status) + .reduce((acc, key) => { + acc[constants.status[key]] = key; + return acc; + }, {}); + let statusName = inverted[status.code]; let message = `${status.code} ${statusName}: ${status.details}`; let error = new Error(message); error.code = status.code; From 81b49bfe53fdaa2dda1f3c828aef31b57458b5a6 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Nov 2018 19:32:08 +0100 Subject: [PATCH 0471/1899] Bumping to 1.16.1 for release. --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 312bf5c98..8fd7ebed7 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.16.0"' + 'GRPC_NODE_VERSION="1.16.1"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..941ae1028 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.16.1 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f3987f4cb..f4455a2e5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.16.0", + "version": "1.16.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 95071c4d5313e98c0f946842f8fddbc510f512f1 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 16 Nov 2018 22:29:43 +0100 Subject: [PATCH 0472/1899] Adding node 11 tests. --- run-tests.bat | 2 +- run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index bf62e6bf5..a47f07079 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4 6 7 8 9 10) do ( +for %%v in (4 6 7 8 9 10 11) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index a9bcab212..80362dd26 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="4 5 6 7 8 9 10" + node_versions="4 5 6 7 8 9 10 11" fi set +ex From fe3c71b350795840d68bef0b53aa073e3d05f7a5 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 19 Nov 2018 15:06:25 -0800 Subject: [PATCH 0473/1899] Update client.js --- packages/grpc-native-core/src/client.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 6a73b21e8..31ca7a596 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -940,10 +940,9 @@ exports.makeClientConstructor = function(methods, serviceName, } var method_type = common.getMethodType(attrs); var method_func = function() { - return requester_funcs[method_type].apply(this, - [].slice.call(arguments).concat([ - attrs.path, attrs.requestSerialize, attrs.responseDeserialize - ]) + return requester_funcs[method_type].apply(this, + [ attrs.path, attrs.requestSerialize, attrs.responseDeserialize ] + .concat([].slice.call(arguments)) ); }; if (class_options.deprecatedArgumentOrder) { From 5181c11d2dca3a97aca63b35e95c31ceed792d0f Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 19 Nov 2018 16:12:00 -0800 Subject: [PATCH 0474/1899] refactor: drop usage of _.omit --- packages/grpc-native-core/src/client.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 0ae467ac7..4ce670d97 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -390,10 +390,17 @@ function Client(address, credentials, options) { let channelOverride = options.channelOverride; let channelFactoryOverride = options.channelFactoryOverride; // Exclude channel options which have already been consumed - var channel_options = _.omit(options, - ['interceptors', 'interceptor_providers', - 'channelOverride', 'channelFactoryOverride', - 'callInvocationTransformer']); + const ignoredKeys = [ + 'interceptors', 'interceptor_providers', 'channelOverride', + 'channelFactoryOverride', 'callInvocationTransformer' + ]; + var channel_options = Object.getOwnPropertyNames(options) + .reduce((acc, key) => { + if (ignoredKeys.indexOf(key) === -1) { + acc[key] = options[key]; + } + return acc; + }, {}); /* Private fields use $ as a prefix instead of _ because it is an invalid * prefix of a method name */ if (channelOverride) { From afd9c079f477f49d5d6ba774d102b3a1ddb8d104 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Nov 2018 10:55:15 -0800 Subject: [PATCH 0475/1899] Native: lazily load Protobuf.js --- packages/grpc-native-core/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index e6105534f..1dfd688cd 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -26,8 +26,6 @@ var SSL_ROOTS_PATH = path.resolve(__dirname, 'deps', 'grpc', 'etc', 'roots.pem') var _ = require('lodash'); -var ProtoBuf = require('protobufjs'); - var client = require('./src/client.js'); var server = require('./src/server.js'); @@ -122,6 +120,7 @@ var loadObject = exports.loadObject; * @return {Object} The resulting gRPC object */ exports.load = util.deprecate(function load(filename, format, options) { + const ProtoBuf = require('protobufjs'); options = Object.assign({}, common.defaultGrpcOptions, options); options.protobufjsVersion = 5; if (!format) { From 8f8dd7b2d6990fa396df5080b66f4679807910b2 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Tue, 20 Nov 2018 13:41:34 -0800 Subject: [PATCH 0476/1899] refactor: use lodash subpackages --- packages/grpc-native-core/index.js | 2 -- packages/grpc-native-core/package.json | 3 ++- packages/grpc-native-core/src/client.js | 4 +--- packages/grpc-native-core/src/client_interceptors.js | 1 - packages/grpc-native-core/src/common.js | 1 - packages/grpc-native-core/src/credentials.js | 2 -- packages/grpc-native-core/src/metadata.js | 6 +++--- packages/grpc-native-core/src/protobuf_js_5_common.js | 4 ++-- packages/grpc-native-core/src/protobuf_js_6_common.js | 4 ++-- packages/grpc-native-core/src/server.js | 2 -- packages/grpc-native-core/test/common_test.js | 1 - 11 files changed, 10 insertions(+), 20 deletions(-) diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index e6105534f..eff11b967 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -24,8 +24,6 @@ var util = require('util'); var SSL_ROOTS_PATH = path.resolve(__dirname, 'deps', 'grpc', 'etc', 'roots.pem'); -var _ = require('lodash'); - var ProtoBuf = require('protobufjs'); var client = require('./src/client.js'); diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index c81255af4..31fe9a122 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,7 +29,8 @@ "node-pre-gyp" ], "dependencies": { - "lodash": "^4.17.5", + "lodash.camelcase": "^4.3.0", + "lodash.clone": "^4.5.0", "nan": "^2.0.0", "node-pre-gyp": "^0.12.0", "protobufjs": "^5.0.3" diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 1903c243c..1c41bf593 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -32,8 +32,6 @@ 'use strict'; -var _ = require('lodash'); - var client_interceptors = require('./client_interceptors'); var grpc = require('./grpc_extension'); @@ -949,7 +947,7 @@ exports.makeClientConstructor = function(methods, serviceName, } var method_type = common.getMethodType(attrs); var method_func = function() { - return requester_funcs[method_type].apply(this, + return requester_funcs[method_type].apply(this, [ attrs.path, attrs.requestSerialize, attrs.responseDeserialize ] .concat([].slice.call(arguments)) ); diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 410b8b682..2fe373f3b 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -141,7 +141,6 @@ 'use strict'; -var _ = require('lodash'); var grpc = require('./grpc_extension'); var Metadata = require('./metadata'); var constants = require('./constants'); diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 93c92dc34..198c9470d 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -18,7 +18,6 @@ 'use strict'; -var _ = require('lodash'); var constants = require('./constants'); /** diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 767d5248d..2a2c51b9b 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -69,8 +69,6 @@ var common = require('./common.js'); var constants = require('./constants'); -var _ = require('lodash'); - /** * @external GoogleCredential * @see https://github.com/google/google-auth-library-nodejs diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js index 9d00c7226..31c6329e7 100644 --- a/packages/grpc-native-core/src/metadata.js +++ b/packages/grpc-native-core/src/metadata.js @@ -18,7 +18,7 @@ 'use strict'; -var _ = require('lodash'); +var clone = require('lodash.clone'); var grpc = require('./grpc_extension'); @@ -139,7 +139,7 @@ Metadata.prototype.clone = function() { var copy = new Metadata(); Object.keys(this._internal_repr).forEach(key => { const value = this._internal_repr[key]; - copy._internal_repr[key] = _.clone(value); + copy._internal_repr[key] = clone(value); }); return copy; }; @@ -166,7 +166,7 @@ Metadata._fromCoreRepresentation = function(metadata) { if (metadata) { Object.keys(metadata).forEach(key => { const value = metadata[key]; - newMetadata._internal_repr[key] = _.clone(value); + newMetadata._internal_repr[key] = clone(value); }); } return newMetadata; diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js index 6af6c4ac8..81c8ead3c 100644 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ b/packages/grpc-native-core/src/protobuf_js_5_common.js @@ -23,7 +23,7 @@ 'use strict'; -var _ = require('lodash'); +var camelCase = require('lodash.camelcase'); var client = require('./client'); var common = require('./common'); @@ -108,7 +108,7 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, _.fromPairs, which would be cleaner, but was introduced in lodash version 4 */ return common.zipObject(service.children.map(function(method) { - return _.camelCase(method.name); + return camelCase(method.name); }), service.children.map(function(method) { return { originalName: method.name, diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index f68256a9a..af3d4c049 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -23,7 +23,7 @@ 'use strict'; -var _ = require('lodash'); +var camelCase = require('lodash.camelcase'); var client = require('./client'); var common = require('./common'); @@ -105,7 +105,7 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, var prefix = '/' + fullyQualifiedName(service) + '/'; service.resolveAll(); return common.zipObject(service.methods.map(function(method) { - return _.camelCase(method.name); + return camelCase(method.name); }), service.methods.map(function(method) { return { originalName: method.name, diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index c5a00febc..e28e68b82 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -18,8 +18,6 @@ 'use strict'; -var _ = require('lodash'); - var grpc = require('./grpc_extension'); var common = require('./common'); diff --git a/packages/grpc-native-core/test/common_test.js b/packages/grpc-native-core/test/common_test.js index 404ca2c38..4459d7e81 100644 --- a/packages/grpc-native-core/test/common_test.js +++ b/packages/grpc-native-core/test/common_test.js @@ -19,7 +19,6 @@ 'use strict'; var assert = require('assert'); -var _ = require('lodash'); var common = require('../src/common'); var protobuf_js_5_common = require('../src/protobuf_js_5_common'); From cb22d4895bdc31feb81feb7a3d78d6affecc3c03 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Tue, 20 Nov 2018 16:01:44 -0800 Subject: [PATCH 0477/1899] update template too --- packages/grpc-native-core/templates/package.json.template | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 0a86bd400..f9bd974ca 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,7 +31,8 @@ "node-pre-gyp" ], "dependencies": { - "lodash": "^4.17.5", + "lodash.camelcase": "^4.3.0", + "lodash.clone": "^4.5.0", "nan": "^2.0.0", "node-pre-gyp": "^0.12.0", "protobufjs": "^5.0.3" From 4a539303e725db3e86601bd63067599bd1dde45d Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 26 Nov 2018 22:29:26 -0800 Subject: [PATCH 0478/1899] refactor: drop dependency on google-auth-library --- packages/grpc-native-core/package.json | 1 - packages/grpc-native-core/templates/package.json.template | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index c81255af4..3ca17fea8 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -39,7 +39,6 @@ "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", - "google-auth-library": "^0.9.2", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", "lodash": "^4.17.4", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 0a86bd400..9e5619265 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -41,7 +41,6 @@ "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", - "google-auth-library": "^0.9.2", "google-protobuf": "^3.0.0", "istanbul": "^0.4.4", "lodash": "^4.17.4", From 9305468f11118127087c1a99acaa7fa69bd77d10 Mon Sep 17 00:00:00 2001 From: Justin Beckwith Date: Mon, 26 Nov 2018 22:31:26 -0800 Subject: [PATCH 0479/1899] refactor: drop dependency on async --- packages/grpc-native-core/package.json | 1 - packages/grpc-native-core/templates/package.json.template | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index c81255af4..8bc5674b1 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -35,7 +35,6 @@ "protobufjs": "^5.0.3" }, "devDependencies": { - "async": "^2.0.1", "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 0a86bd400..92276e836 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -37,7 +37,6 @@ "protobufjs": "^5.0.3" }, "devDependencies": { - "async": "^2.0.1", "body-parser": "^1.15.2", "electron-mocha": "^3.1.1", "express": "^4.14.0", From 0a8a720c84f5da4c7300fe60cf8b4877fab881b7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 27 Nov 2018 13:51:16 -0800 Subject: [PATCH 0480/1899] Native: update to 1.17.0-pre1 --- packages/grpc-native-core/binding.gyp | 9 ++++----- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 1556881cb..9b4c0e8e8 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.17.0-dev"' + 'GRPC_NODE_VERSION="1.17.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -772,6 +772,7 @@ 'deps/grpc/src/core/lib/transport/timeout_encoding.cc', 'deps/grpc/src/core/lib/transport/transport.cc', 'deps/grpc/src/core/lib/transport/transport_op_string.cc', + 'deps/grpc/src/core/lib/uri/uri_parser.cc', 'deps/grpc/src/core/lib/debug/trace.cc', 'deps/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc', 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_decoder.cc', @@ -844,7 +845,7 @@ 'deps/grpc/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', 'deps/grpc/src/core/tsi/alts/frame_protector/frame_handler.cc', 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_event.cc', + 'deps/grpc/src/core/tsi/alts/handshaker/alts_shared_resource.cc', 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', @@ -886,19 +887,17 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', - 'deps/grpc/src/core/ext/filters/client_channel/method_params.cc', 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', - 'deps/grpc/src/core/ext/filters/client_channel/uri_parser.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', 'deps/grpc/src/core/ext/filters/client_channel/health/health.pb.c', - 'deps/grpc/src/core/tsi/alts_transport_security.cc', 'deps/grpc/src/core/tsi/fake_transport_security.cc', 'deps/grpc/src/core/tsi/local_transport_security.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..34149f497 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.17.0-pre1 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 4139ff895..802d89fa5 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 4139ff895fd413c730c4383d24d13a17bbeaea90 +Subproject commit 802d89fa59f77db60ab9e27d0145f986e62dbcf7 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 8caf09dba..6c0dd8d2b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.17.0-dev", + "version": "1.17.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 0997ccaf0f61ee7bb7042971361c6f7dde2d1df0 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Fri, 30 Nov 2018 13:53:43 +0100 Subject: [PATCH 0481/1899] fix: require package.json directly --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index aeb7d765c..bbadb5c62 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -15,7 +15,7 @@ import {Metadata} from './metadata'; import {MetadataStatusFilterFactory} from './metadata-status-filter'; import {Http2SubChannel} from './subchannel'; -const {version: clientVersion} = require('../../package'); +const {version: clientVersion} = require('../../package.json'); const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; From 9f40dfafea8757989c2704b848c07b28ac696c28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20Wachter?= Date: Wed, 5 Dec 2018 17:46:32 +0100 Subject: [PATCH 0482/1899] Add missing Typescript definition for Server.bindAsync() --- packages/grpc-native-core/index.d.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index d47a4feb8..a72a2dbb8 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -230,9 +230,21 @@ declare module "grpc" { * "address:port" * @param creds Server credential object to be used for SSL. Pass an * insecure credentials object for an insecure port. - * @return The bound port number or 0 if the opreation failed. + * @return The bound port number or 0 if the operation failed. */ bind(port: string, creds: ServerCredentials): number; + + /** + * Binds the server to the given port, with SSL disabled if creds is an + * insecure credentials object. Provides the result asynchronously. + * @param port The port that the server should bind on, in the format "address:port" + * @param creds Server credential object to be used for + * SSL. Pass an insecure credentials object for an insecure port. + * @param callback Called with the result of attempting to bind a port + * - error: If non-null, indicates that binding the port failed. + * - port: The bound port number. If binding the port fails, this will be negative to match the output of bind. + */ + bindAsync(port: string, creds: ServerCredentials, callback: (error: Error | null, port: number) => void): void; } /** From bbd5bd8f7ce059c59bc2d32cc35ca17271528370 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 6 Dec 2018 17:22:14 -0800 Subject: [PATCH 0483/1899] Native: Protobuf.js 6 loadObject: switch to mappable methodsArray --- packages/grpc-native-core/src/protobuf_js_6_common.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index af3d4c049..a08b988e4 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -104,9 +104,9 @@ exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, options) { var prefix = '/' + fullyQualifiedName(service) + '/'; service.resolveAll(); - return common.zipObject(service.methods.map(function(method) { + return common.zipObject(service.methodsArray.map(function(method) { return camelCase(method.name); - }), service.methods.map(function(method) { + }), service.methodsArray.map(function(method) { return { originalName: method.name, path: prefix + method.name, From f45dda46afad06afa308ba4ff5d914d2cdedb2de Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Dec 2018 10:16:16 -0800 Subject: [PATCH 0484/1899] Native: Protobuf.js 6 loadObject: switch to nestedArray --- packages/grpc-native-core/src/protobuf_js_6_common.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index a08b988e4..bbc392ad3 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -135,11 +135,10 @@ exports.loadObject = function loadObject(value, options) { return client.makeClientConstructor(service_attrs); } - if (value.hasOwnProperty('nested')) { + if (value.hasOwnProperty('nestedArray')) { // It's a namespace or root object - Object.keys(value.nested).forEach(name => { - const nested = value.nested[name]; - result[name] = loadObject(nested, options); + value.nestedArray.forEach(nested => { + result[nested.name] = loadObject(nested, options); }); return result; } From da052f467de9ec022caa21e60c7bfaea35469919 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Dec 2018 10:57:21 -0800 Subject: [PATCH 0485/1899] Bump version to 1.17.0-pre2 and bump submodule --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 9b4c0e8e8..a14a5f9c4 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.17.0-pre1"' + 'GRPC_NODE_VERSION="1.17.0-pre2"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 34149f497..adf1bb76d 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.17.0-pre1 + node_version: 1.17.0-pre2 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 802d89fa5..8d4f9c465 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 802d89fa59f77db60ab9e27d0145f986e62dbcf7 +Subproject commit 8d4f9c4654ab4b0c670527599871530e2258e76d diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6c0dd8d2b..19262126d 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.17.0-pre1", + "version": "1.17.0-pre2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From a6ecc7c8c85fc40cc031a9b55a9acd2e858b3b58 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Dec 2018 11:43:02 -0800 Subject: [PATCH 0486/1899] proto loader: Fall back to default path resolution --- packages/proto-loader/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 36ef263d2..1c09fbaa7 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -118,6 +118,7 @@ function createPackageDefinition(root: Protobuf.Root, options: Options): Package } function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { + const originalResolvePath = root.resolvePath; root.resolvePath = (origin: string, target: string) => { if (path.isAbsolute(target)) { return target; @@ -131,7 +132,7 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { continue; } } - throw new Error(`Could not find file ${target}`); + return originalResolvePath(origin, target); }; } From effeba7e78d73032ca35597a084d6ad3db170b1a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 11 Dec 2018 10:53:47 -0800 Subject: [PATCH 0487/1899] Native: Protobuf.js 6: use nested again --- packages/grpc-native-core/src/protobuf_js_6_common.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index bbc392ad3..6fbeeefff 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -135,11 +135,13 @@ exports.loadObject = function loadObject(value, options) { return client.makeClientConstructor(service_attrs); } - if (value.hasOwnProperty('nestedArray')) { + if (value.hasOwnProperty('nested')) { // It's a namespace or root object - value.nestedArray.forEach(nested => { - result[nested.name] = loadObject(nested, options); - }); + if (value.nested !== null && value.nested !== undefined) { + Object.values(value.nested).forEach(nested => { + result[nested.name] = loadObject(nested, options); + }); + } return result; } From b60928ee4ea8acd8d14c82f88b863bda88bff1f5 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 11 Dec 2018 23:37:22 +0100 Subject: [PATCH 0488/1899] Bumping to pre3... --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index a14a5f9c4..ea4436a52 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.17.0-pre2"' + 'GRPC_NODE_VERSION="1.17.0-pre3"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index adf1bb76d..c87865a34 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.17.0-pre2 + node_version: 1.17.0-pre3 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 19262126d..19f043a89 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.17.0-pre2", + "version": "1.17.0-pre3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From f3b22bcbc0a3aa348ed4ff85aefaecb5cbe19f04 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 12 Dec 2018 22:45:52 +0100 Subject: [PATCH 0489/1899] Fix for node 6. --- packages/grpc-native-core/src/protobuf_js_6_common.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js index 6fbeeefff..66cebd617 100644 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ b/packages/grpc-native-core/src/protobuf_js_6_common.js @@ -138,8 +138,9 @@ exports.loadObject = function loadObject(value, options) { if (value.hasOwnProperty('nested')) { // It's a namespace or root object if (value.nested !== null && value.nested !== undefined) { - Object.values(value.nested).forEach(nested => { - result[nested.name] = loadObject(nested, options); + var values = Object.keys(value.nested).map(key => value.nested[key]); + values.forEach(nested => { + result[nested.name] = loadObject(nested, options); }); } return result; From 03a79e5e7e60ecfd13dfb4cda506e0848e45f99c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 12 Dec 2018 22:56:42 +0100 Subject: [PATCH 0490/1899] Bumping to pre4. --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index ea4436a52..34a49d38b 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.17.0-pre3"' + 'GRPC_NODE_VERSION="1.17.0-pre4"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index c87865a34..30fd25f47 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.17.0-pre3 + node_version: 1.17.0-pre4 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 19f043a89..e69394329 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.17.0-pre3", + "version": "1.17.0-pre4", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From d9eee9bdd038ed88a8d1279cd7cd5080ac177ae8 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 13 Dec 2018 20:38:21 +0100 Subject: [PATCH 0491/1899] Bumping to 1.17.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 34a49d38b..dc96bbaf7 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.17.0-pre4"' + 'GRPC_NODE_VERSION="1.17.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 30fd25f47..45d905d30 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.17.0-pre4 + node_version: 1.17.0 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e69394329..994359ec8 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.17.0-pre4", + "version": "1.17.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 93c9ca64b072820b674f31bd8a70709765cd74be Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 17 Dec 2018 15:57:14 -0800 Subject: [PATCH 0492/1899] Update proto-loader to 0.3.1 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index cfd421cba..e9b9e320a 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.3.0", + "version": "0.3.1", "author": "Google Inc.", "contributors": [ { From 2c5fe2dbc36830a5fd9c254e0bf237a6692f3542 Mon Sep 17 00:00:00 2001 From: Yingyu Cheng Date: Tue, 25 Dec 2018 18:45:29 +0800 Subject: [PATCH 0493/1899] bug: set host will always undefined --- packages/grpc-native-core/ext/channel.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index 825260e04..f23dbd58d 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -377,7 +377,7 @@ NAN_METHOD(Channel::CreateCall) { if (info[2]->IsString()) { grpc_slice *host = new grpc_slice; *host = - CreateSliceFromString(Nan::To(info[3]).ToLocalChecked()); + CreateSliceFromString(Nan::To(info[2]).ToLocalChecked()); wrapped_call = grpc_channel_create_call( wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), method, host, MillisecondsToTimespec(deadline), NULL); From a955068d01db2bda320feca07c6922f1e3a2b67f Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 8 Jan 2019 01:18:30 +0100 Subject: [PATCH 0494/1899] Adding build scripts for Electron 4. --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 3b4b084d8..63cc45983 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -16,7 +16,7 @@ set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 1faa8c051..1421ed86b 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -17,7 +17,7 @@ set -ex arch_list=( ia32 x64 ) node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 ) while true ; do case $1 in From d3320d557166b1275f2eccdb65f4ed561b8f85cd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 8 Jan 2019 10:18:43 -0800 Subject: [PATCH 0495/1899] Native: bump to 1.18.0-pre1 --- packages/grpc-native-core/binding.gyp | 6 ++++-- packages/grpc-native-core/build.yaml | 1 - packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index dc96bbaf7..b257a09f3 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.17.0"' + 'GRPC_NODE_VERSION="1.18.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -779,6 +779,7 @@ 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_encoder.cc', 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc', 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc', + 'deps/grpc/src/core/ext/transport/chttp2/transport/context_list.cc', 'deps/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc', 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc', 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc', @@ -885,15 +886,16 @@ 'deps/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'deps/grpc/src/core/ext/filters/client_channel/http_proxy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/request_routing.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc', 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', + 'deps/grpc/src/core/ext/filters/client_channel/server_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 45d905d30..49e36fdfe 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,2 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.17.0 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 8d4f9c465..16d6deee9 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 8d4f9c4654ab4b0c670527599871530e2258e76d +Subproject commit 16d6deee9fc68654dc599a6b21ff860d60f8396d diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 994359ec8..39ee82823 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.17.0", + "version": "1.18.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 579f57c68ad1bb61ab14051238557313d73b433d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 8 Jan 2019 11:02:56 -0800 Subject: [PATCH 0496/1899] Native: add details property to StatusError type --- packages/grpc-native-core/index.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index a72a2dbb8..497b5bb0b 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -567,6 +567,10 @@ declare module "grpc" { * Trailing metadata sent with the status, if applicable */ metadata?: Metadata; + /** + * Original status details string + */ + details?: string; } /** From 6cc3b7536dfe6c9cf2075703acbdbe1b421b4674 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 9 Jan 2019 15:28:57 -0800 Subject: [PATCH 0497/1899] grpc-js: bump to 0.3.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index bf6376bc6..44fc59f0d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.2", + "version": "0.3.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 1a9e7cd7c76e2f9b40bb8d51763db32647a74ab3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Dec 2018 14:17:06 -0800 Subject: [PATCH 0498/1899] Add message type information to package definition output. --- gulpfile.ts | 2 +- packages/proto-loader/gulpfile.ts | 13 +- packages/proto-loader/src/index.ts | 141 +++++++++++++++--- .../proto-loader/test/descriptor_type_test.ts | 53 +++++++ packages/proto-loader/test_protos/enums.proto | 27 ++++ .../proto-loader/test_protos/messages.proto | 28 ++++ packages/proto-loader/tsconfig.json | 3 +- 7 files changed, 245 insertions(+), 22 deletions(-) create mode 100644 packages/proto-loader/test/descriptor_type_test.ts create mode 100644 packages/proto-loader/test_protos/enums.proto create mode 100644 packages/proto-loader/test_protos/messages.proto diff --git a/gulpfile.ts b/gulpfile.ts index 89d9e290b..50b10c033 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -99,7 +99,7 @@ gulp.task('native.test', 'Run tests of native code', (callback) => { }); gulp.task('test.only', 'Run tests without rebuilding anything', - ['js.core.test', 'native.test.only']); + ['js.core.test', 'native.test.only', 'protobuf.test']); gulp.task('test', 'Run all tests', (callback) => { runSequence('build', 'test.only', 'internal.test.test', callback); diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index 550ce3648..e655826eb 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -54,7 +54,16 @@ gulp.task('clean', 'Deletes transpiled code.', ['install'], gulp.task('clean.all', 'Deletes all files added by targets', ['clean']); /** - * Transpiles TypeScript files in src/ to JavaScript according to the settings + * Transpiles TypeScript files in src/ and test/ to JavaScript according to the settings * found in tsconfig.json. */ -gulp.task('compile', 'Transpiles src/.', () => execNpmCommand('compile')); +gulp.task('compile', 'Transpiles src/ and test/.', () => execNpmCommand('compile')); + +/** + * Transpiles src/ and test/, and then runs all tests. + */ +gulp.task('test', 'Runs all tests.', () => { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter', + require: ['ts-node/register']})); +}); diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 1c09fbaa7..9b8704c29 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -16,10 +16,25 @@ * */ import * as Protobuf from 'protobufjs'; +import * as descriptor from 'protobufjs/ext/descriptor'; import * as fs from 'fs'; import * as path from 'path'; import camelCase = require('lodash.camelcase'); +declare module 'protobufjs' { + interface Type { + toDescriptor(protoVersion: string): Protobuf.Message & descriptor.IDescriptorProto; + } + + interface Root { + toDescriptor(protoVersion: string): Protobuf.Message & descriptor.IFileDescriptorSet; + } + + interface Enum { + toDescriptor(protoVersion: string): Protobuf.Message & descriptor.IEnumDescriptorProto; + } +} + export interface Serialize { (value: T): Buffer; } @@ -28,6 +43,20 @@ export interface Deserialize { (bytes: Buffer): T; } +export interface ProtobufTypeDefinition { + format: string; + type: object; + fileDescriptorProtos: Buffer[]; +} + +export interface MessageTypeDefinition extends ProtobufTypeDefinition { + format: 'Protocol Buffer 3 DescriptorProto'; +} + +export interface EnumTypeDefinition extends ProtobufTypeDefinition { + format: 'Protocol Buffer 3 EnumDescriptorProto'; +} + export interface MethodDefinition { path: string; requestStream: boolean; @@ -37,20 +66,33 @@ export interface MethodDefinition { requestDeserialize: Deserialize; responseDeserialize: Deserialize; originalName?: string; + requestType: MessageTypeDefinition; + responseType: MessageTypeDefinition; } export interface ServiceDefinition { [index: string]: MethodDefinition; } +export type AnyDefinition = ServiceDefinition | MessageTypeDefinition | EnumTypeDefinition; + export interface PackageDefinition { - [index: string]: ServiceDefinition; + [index: string]: AnyDefinition; } export type Options = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeDirs?: string[]; }; +const descriptorOptions: Protobuf.IConversionOptions = { + longs: String, + enums: String, + bytes: String, + defaults: true, + oneofs: true, + json: true +}; + function joinName(baseName: string, name: string): string { if (baseName === '') { return name; @@ -59,19 +101,28 @@ function joinName(baseName: string, name: string): string { } } -function getAllServices(obj: Protobuf.NamespaceBase, parentName: string): Array<[string, Protobuf.Service]> { +type HandledReflectionObject = Protobuf.Service | Protobuf.Type | Protobuf.Enum; + +function isHandledReflectionObject(obj: Protobuf.ReflectionObject): obj is HandledReflectionObject { + return obj instanceof Protobuf.Service || obj instanceof Protobuf.Type || obj instanceof Protobuf.Enum; +} + +function isNamespaceBase(obj: Protobuf.ReflectionObject): obj is Protobuf.NamespaceBase { + return obj instanceof Protobuf.Namespace || obj instanceof Protobuf.Root; +} + +function getAllHandledReflectionObjects(obj: Protobuf.ReflectionObject, parentName: string): Array<[string, HandledReflectionObject]> { const objName = joinName(parentName, obj.name); - if (obj.hasOwnProperty('methods')) { - return [[objName, obj as Protobuf.Service]]; + if (isHandledReflectionObject(obj)) { + return [[objName, obj]]; } else { - return obj.nestedArray.map((child) => { - if (child.hasOwnProperty('nested')) { - return getAllServices(child as Protobuf.NamespaceBase, objName); - } else { - return []; - } - }).reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + if (isNamespaceBase(obj) && typeof obj.nested !== undefined) { + return Object.keys(obj.nested!).map((name) => { + return getAllHandledReflectionObjects(obj.nested![name], objName); + }).reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + } } + return []; } function createDeserializer(cls: Protobuf.Type, options: Options): Deserialize { @@ -88,16 +139,22 @@ function createSerializer(cls: Protobuf.Type): Serialize { } function createMethodDefinition(method: Protobuf.Method, serviceName: string, options: Options): MethodDefinition { + /* This is only ever called after the corresponding root.resolveAll(), so we + * can assume that the resolved request and response types are non-null */ + const requestType: Protobuf.Type = method.resolvedRequestType!; + const responseType: Protobuf.Type = method.resolvedResponseType!; return { path: '/' + serviceName + '/' + method.name, requestStream: !!method.requestStream, responseStream: !!method.responseStream, - requestSerialize: createSerializer(method.resolvedRequestType as Protobuf.Type), - requestDeserialize: createDeserializer(method.resolvedRequestType as Protobuf.Type, options), - responseSerialize: createSerializer(method.resolvedResponseType as Protobuf.Type), - responseDeserialize: createDeserializer(method.resolvedResponseType as Protobuf.Type, options), + requestSerialize: createSerializer(requestType), + requestDeserialize: createDeserializer(requestType, options), + responseSerialize: createSerializer(responseType), + responseDeserialize: createDeserializer(responseType, options), // TODO(murgatroid99): Find a better way to handle this - originalName: camelCase(method.name) + originalName: camelCase(method.name), + requestType: createMessageDefinition(requestType), + responseType: createMessageDefinition(responseType) }; } @@ -109,10 +166,58 @@ function createServiceDefinition(service: Protobuf.Service, name: string, option return def; } +const fileDescriptorCache: Map = new Map(); +function getFileDescriptors(root: Protobuf.Root): Buffer[] { + if (fileDescriptorCache.has(root)) { + return fileDescriptorCache.get(root)!; + } else { + const descriptorList: descriptor.IFileDescriptorProto[] = root.toDescriptor('proto3').file; + const bufferList: Buffer[] = descriptorList.map(value => Buffer.from(descriptor.FileDescriptorProto.encode(value).finish())); + fileDescriptorCache.set(root, bufferList); + return bufferList; + } +} + +function createMessageDefinition(message: Protobuf.Type): MessageTypeDefinition { + const messageDescriptor: protobuf.Message = message.toDescriptor('proto3'); + return { + format: 'Protocol Buffer 3 DescriptorProto', + type: messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions), + fileDescriptorProtos: getFileDescriptors(message.root) + }; +} + +function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition { + const enumDescriptor: protobuf.Message = enumType.toDescriptor('proto3'); + return { + format: 'Protocol Buffer 3 EnumDescriptorProto', + type: enumDescriptor.$type.toObject(enumDescriptor, descriptorOptions), + fileDescriptorProtos: getFileDescriptors(enumType.root) + }; +} + +/** + * function createDefinition(obj: Protobuf.Service, name: string, options: Options): ServiceDefinition; + * function createDefinition(obj: Protobuf.Type, name: string, options: Options): MessageTypeDefinition; + * function createDefinition(obj: Protobuf.Enum, name: string, options: Options): EnumTypeDefinition; + */ +function createDefinition(obj: HandledReflectionObject, name: string, options: Options): AnyDefinition { + if (obj instanceof Protobuf.Service) { + return createServiceDefinition(obj, name, options); + } else if (obj instanceof Protobuf.Type) { + return createMessageDefinition(obj); + } else if (obj instanceof Protobuf.Enum) { + return createEnumDefinition(obj); + } else { + throw new Error('Type mismatch in reflection object handling'); + } +} + function createPackageDefinition(root: Protobuf.Root, options: Options): PackageDefinition { const def: PackageDefinition = {}; - for (const [name, service] of getAllServices(root, '')) { - def[name] = createServiceDefinition(service, name, options); + root.resolveAll(); + for (const [name, obj] of getAllHandledReflectionObjects(root, '')) { + def[name] = createDefinition(obj, name, options); } return def; } diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts new file mode 100644 index 000000000..06327e024 --- /dev/null +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -0,0 +1,53 @@ +import * as assert from 'assert'; + +import * as proto_loader from '../src/index'; + +// Relative path from build output directory to test_protos directory +const TEST_PROTO_DIR = `${__dirname}/../../test_protos/`; + +type TypeDefinition = proto_loader.EnumTypeDefinition | proto_loader.MessageTypeDefinition; + +function isTypeObject(obj: proto_loader.AnyDefinition): obj is TypeDefinition { + return 'format' in obj; +} + +describe('Descriptor types', () => { + it('Should be output for each enum', (done) => { + proto_loader.load(`${TEST_PROTO_DIR}/enums.proto`).then((packageDefinition) => { + assert('Enum1' in packageDefinition); + assert(isTypeObject(packageDefinition.Enum1)); + // Need additional check because compiler doesn't understand asserts + if(isTypeObject(packageDefinition.Enum1)) { + const enum1Def: TypeDefinition = packageDefinition.Enum1; + assert.strictEqual(enum1Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); + } + + assert('Enum2' in packageDefinition); + assert(isTypeObject(packageDefinition.Enum2)); + // Need additional check because compiler doesn't understand asserts + if(isTypeObject(packageDefinition.Enum2)) { + const enum2Def: TypeDefinition = packageDefinition.Enum2; + assert.strictEqual(enum2Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); + } + done(); + }, (error) => {done(error);}); + }); + it('Should be output for each message', (done) => { + proto_loader.load(`${TEST_PROTO_DIR}/messages.proto`).then((packageDefinition) => { + assert('LongValues' in packageDefinition); + assert(isTypeObject(packageDefinition.LongValues)); + if(isTypeObject(packageDefinition.LongValues)) { + const longValuesDef: TypeDefinition = packageDefinition.LongValues; + assert.strictEqual(longValuesDef.format, 'Protocol Buffer 3 DescriptorProto'); + } + + assert('SequenceValues' in packageDefinition); + assert(isTypeObject(packageDefinition.SequenceValues)); + if(isTypeObject(packageDefinition.SequenceValues)) { + const sequenceValuesDef: TypeDefinition = packageDefinition.SequenceValues; + assert.strictEqual(sequenceValuesDef.format, 'Protocol Buffer 3 DescriptorProto'); + } + done(); + }, (error) => {done(error);}); + }); +}); \ No newline at end of file diff --git a/packages/proto-loader/test_protos/enums.proto b/packages/proto-loader/test_protos/enums.proto new file mode 100644 index 000000000..58e32532c --- /dev/null +++ b/packages/proto-loader/test_protos/enums.proto @@ -0,0 +1,27 @@ +// Copyright 2019 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +enum Enum1 { + DEFAULT = 0; + VALUE1 = 1; + VALUE2 = 2; +} + +enum Enum2 { + DEFAULT = 0; + ABC = 5; + DEF = 10; +} \ No newline at end of file diff --git a/packages/proto-loader/test_protos/messages.proto b/packages/proto-loader/test_protos/messages.proto new file mode 100644 index 000000000..706274515 --- /dev/null +++ b/packages/proto-loader/test_protos/messages.proto @@ -0,0 +1,28 @@ +// Copyright 2019 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +message LongValues { + int64 int_64 = 1; + uint64 uint_64 = 2; + sint64 sint_64 = 3; + fixed64 fixed_64 = 4; + sfixed64 sfixed_64 = 5; +} + +message SequenceValues { + bytes bytes_field = 1; + repeated int32 repeated_field = 2; +} \ No newline at end of file diff --git a/packages/proto-loader/tsconfig.json b/packages/proto-loader/tsconfig.json index f893d7afb..26f33cd1f 100644 --- a/packages/proto-loader/tsconfig.json +++ b/packages/proto-loader/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "build" }, "include": [ - "src/*.ts" + "src/*.ts", + "test/*.ts" ] } From 0bc3d0b3b640f30656bdb5bb8140f5e6e4914009 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 Jan 2019 14:35:46 -0800 Subject: [PATCH 0499/1899] Skip proto-loader tests for unsupported versions --- packages/proto-loader/gulpfile.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index e655826eb..42ea1313d 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -22,6 +22,7 @@ import * as fs from 'fs'; import * as mocha from 'gulp-mocha'; import * as path from 'path'; import * as execa from 'execa'; +import * as semver from 'semver'; // gulp-help monkeypatches tasks to have an additional description parameter const gulp = help(_gulp); @@ -63,7 +64,12 @@ gulp.task('compile', 'Transpiles src/ and test/.', () => execNpmCommand('compile * Transpiles src/ and test/, and then runs all tests. */ gulp.task('test', 'Runs all tests.', () => { - return gulp.src(`${outDir}/test/**/*.js`) - .pipe(mocha({reporter: 'mocha-jenkins-reporter', - require: ['ts-node/register']})); + if (semver.satisfies(process.version, ">=6")) { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter', + require: ['ts-node/register']})); + } else { + console.log(`Skipping proto-loader tests for Node ${process.version}`); + return Promise.resolve(null); + } }); From e32fec18fec8dbaf132c4a2f017c4879843184b9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 Jan 2019 17:03:03 -0800 Subject: [PATCH 0500/1899] grpc-js: Fix handling of non-service objects in package definitions --- packages/grpc-js/src/make-client.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 3b03255f1..7fcc17d53 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -21,7 +21,13 @@ export interface ServiceDefinition { [index: string]: MethodDefinition; } -export interface PackageDefinition { [index: string]: ServiceDefinition; } +export interface ProtobufTypeDefinition { + format: string; + type: object; + fileDescriptorProtos: Buffer[]; +} + +export interface PackageDefinition { [index: string]: ServiceDefinition | ProtobufTypeDefinition; } /** * Map with short names for each of the requester maker functions. Used in @@ -119,9 +125,13 @@ function partial( } export type GrpcObject = { - [index: string]: GrpcObject|ServiceClientConstructor; + [index: string]: GrpcObject|ServiceClientConstructor|ProtobufTypeDefinition; }; +function isProtobufTypeDefinition(obj: ServiceDefinition | ProtobufTypeDefinition): obj is ProtobufTypeDefinition { + return 'format' in obj; +} + /** * Load a gRPC package definition as a gRPC object hierarchy. * @param packageDef The package definition object. @@ -142,7 +152,11 @@ export function loadPackageDefinition(packageDef: PackageDefinition): } current = current[packageName] as GrpcObject; } - current[serviceName] = makeClientConstructor(service, serviceName, {}); + if (isProtobufTypeDefinition(service)) { + current[serviceName] = service; + } else { + current[serviceName] = makeClientConstructor(service, serviceName, {}); + } } } return result; From f9de2aff7e7361a75f69c85c7421efe406f5596f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 Jan 2019 17:47:47 -0800 Subject: [PATCH 0501/1899] grpc native: Fix handling of non-service objects in package definitions --- packages/grpc-native-core/index.d.ts | 11 ++++++++++- packages/grpc-native-core/index.js | 6 +++++- packages/grpc-native-core/src/common.js | 11 ++++++++++- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 497b5bb0b..808051d06 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -259,11 +259,20 @@ declare module "grpc" { readonly [I in keyof ImplementationType]: MethodDefinition; } + /** + * An object that defines a protobuf type + */ + export interface ProtobufTypeDefinition { + format: string; + type: object; + fileDescriptorProtos: Buffer[]; + } + /** * An object that defines a package containing multiple services */ export type PackageDefinition = { - readonly [fullyQualifiedName: string]: ServiceDefinition; + readonly [fullyQualifiedName: string]: ServiceDefinition | ProtobufTypeDefinition; } /** diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 917479167..9134667a8 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -169,7 +169,11 @@ exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { } current = current[packageName]; } - current[serviceName] = client.makeClientConstructor(service, serviceName, {}); + if (service.hasOwnProperty('format')) { + current[serviceName] = service; + } else { + current[serviceName] = client.makeClientConstructor(service, serviceName, {}); + } } return result; }; diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js index 198c9470d..2d948335f 100644 --- a/packages/grpc-native-core/src/common.js +++ b/packages/grpc-native-core/src/common.js @@ -317,9 +317,18 @@ exports.zipObject = function(props, values) { * @typedef {Object.} grpc~ServiceDefinition */ + /** + * An object that defines a protobuf type + * @typedef {object} grpc~ProtobufTypeDefinition + * @param {string} format The format of the type definition object + * @param {*} type The type definition object + * @param {Buffer[]} fileDescriptorProtos Binary protobuf file + * descriptors for all files loaded to construct this type + */ + /** * An object that defines a package hierarchy with multiple services - * @typedef {Object.} grpc~PackageDefinition + * @typedef {Object.} grpc~PackageDefinition */ /** From 15f877aa45c7c9b7fb8d028b32d89e6a75da253a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 14 Jan 2019 17:51:41 -0800 Subject: [PATCH 0502/1899] Fix lint errors --- packages/grpc-js/src/make-client.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 7fcc17d53..df673aa78 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -27,7 +27,9 @@ export interface ProtobufTypeDefinition { fileDescriptorProtos: Buffer[]; } -export interface PackageDefinition { [index: string]: ServiceDefinition | ProtobufTypeDefinition; } +export interface PackageDefinition { + [index: string]: ServiceDefinition|ProtobufTypeDefinition; +} /** * Map with short names for each of the requester maker functions. Used in @@ -128,7 +130,9 @@ export type GrpcObject = { [index: string]: GrpcObject|ServiceClientConstructor|ProtobufTypeDefinition; }; -function isProtobufTypeDefinition(obj: ServiceDefinition | ProtobufTypeDefinition): obj is ProtobufTypeDefinition { +function isProtobufTypeDefinition( + obj: ServiceDefinition| + ProtobufTypeDefinition): obj is ProtobufTypeDefinition { return 'format' in obj; } From 8e063c10e592cd1ffa51dcea4d6349a4fa42173c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 15 Jan 2019 11:53:48 -0800 Subject: [PATCH 0503/1899] Bump native to 1.18.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b257a09f3..85602dc09 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.18.0-pre1"' + 'GRPC_NODE_VERSION="1.18.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 16d6deee9..007b721f8 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 16d6deee9fc68654dc599a6b21ff860d60f8396d +Subproject commit 007b721f8045ceef4ebf418a2935ab772fbe3708 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 39ee82823..6d62a9e01 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.18.0-pre1", + "version": "1.18.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 5cee1065fba1af4cdaf741f1967b980bf525254b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 17 Jan 2019 09:38:59 -0800 Subject: [PATCH 0504/1899] Bump grpc-js to 0.3.4 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 44fc59f0d..66ff8428e 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.3", + "version": "0.3.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 6d2b6d2dcc4694d25532b0195deff5d96fbaf818 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 17 Jan 2019 10:00:43 -0800 Subject: [PATCH 0505/1899] Bump proto-loader to 0.4.0 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index e9b9e320a..08e5807da 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.3.1", + "version": "0.4.0", "author": "Google Inc.", "contributors": [ { From 3593bb621eb0e6684bbfc0067b9d8e78c1211861 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 18 Jan 2019 00:03:37 +0100 Subject: [PATCH 0506/1899] Splitting node and electron builds. --- .../artifacts/build_all_linux_artifacts.sh | 17 ++++++- .../artifacts/build_artifact_electron.bat | 42 ++++++++++++++++ .../artifacts/build_artifact_electron.sh | 40 ++++++++++++++++ .../artifacts/build_artifact_node.bat | 9 ---- .../artifacts/build_artifact_node.sh | 8 ---- test/kokoro/linux-build-electron.cfg | 19 ++++++++ ...linux-build.cfg => linux-build-nodejs.cfg} | 2 +- test/kokoro/macos-build-electron.cfg | 19 ++++++++ ...macos-build.cfg => macos-build-nodejs.cfg} | 2 +- test/kokoro/windows-build-electron.cfg | 19 ++++++++ ...ows-build.cfg => windows-build-nodejs.cfg} | 2 +- tools/release/kokoro-electron.bat | 42 ++++++++++++++++ tools/release/kokoro-electron.sh | 48 +++++++++++++++++++ .../release/{kokoro.bat => kokoro-nodejs.bat} | 0 tools/release/{kokoro.sh => kokoro-nodejs.sh} | 4 +- tools/release/kokoro/Dockerfile | 10 ---- tools/release/kokoro/linux-electron.cfg | 25 ++++++++++ .../kokoro/{linux.cfg => linux-nodejs.cfg} | 2 +- tools/release/kokoro/macos-electron.cfg | 25 ++++++++++ .../kokoro/{macos.cfg => macos-nodejs.cfg} | 2 +- tools/release/kokoro/windows-electron.cfg | 25 ++++++++++ .../{windows.cfg => windows-nodejs.cfg} | 2 +- 22 files changed, 328 insertions(+), 36 deletions(-) create mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat create mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh create mode 100644 test/kokoro/linux-build-electron.cfg rename test/kokoro/{linux-build.cfg => linux-build-nodejs.cfg} (92%) create mode 100644 test/kokoro/macos-build-electron.cfg rename test/kokoro/{macos-build.cfg => macos-build-nodejs.cfg} (92%) create mode 100644 test/kokoro/windows-build-electron.cfg rename test/kokoro/{windows-build.cfg => windows-build-nodejs.cfg} (92%) create mode 100644 tools/release/kokoro-electron.bat create mode 100755 tools/release/kokoro-electron.sh rename tools/release/{kokoro.bat => kokoro-nodejs.bat} (100%) rename tools/release/{kokoro.sh => kokoro-nodejs.sh} (97%) delete mode 100644 tools/release/kokoro/Dockerfile create mode 100644 tools/release/kokoro/linux-electron.cfg rename tools/release/kokoro/{linux.cfg => linux-nodejs.cfg} (93%) create mode 100644 tools/release/kokoro/macos-electron.cfg rename tools/release/kokoro/{macos.cfg => macos-nodejs.cfg} (93%) create mode 100644 tools/release/kokoro/windows-electron.cfg rename tools/release/kokoro/{windows.cfg => windows-nodejs.cfg} (93%) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 2276b3e56..26df28bdc 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -22,6 +22,8 @@ npm install -g node-gyp DO_NATIVE=true DO_CROSS=true +DO_ELECTRON=true +DO_NODEJS=true while [ $# -gt 0 ] ; do case $1 in @@ -30,6 +32,14 @@ while [ $# -gt 0 ] ; do ;; --cross-only) DO_NATIVE=false + DO_ELECTRON=false + ;; + --electron-only) + DO_NODEJS=false + DO_CROSS=false + ;; + --nodejs-only) + DO_ELECTRON=false ;; esac shift @@ -50,7 +60,12 @@ rm -rf build || true mkdir -p "${ARTIFACTS_OUT}" if [ "$DO_NATIVE" = "true" ] ; then - $tool_dir/build_artifact_node.sh + if [ "$DO_ELECTRON" = "true" ] ; then + $tool_dir/build_artifact_electron.sh + fi + if [ "$DO_NODEJS" = "true" ] ; then + $tool_dir/build_artifact_node.sh + fi fi if [ "$DO_CROSS" = "true" ] ; then diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat new file mode 100644 index 000000000..2fe46fda0 --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -0,0 +1,42 @@ +@rem Copyright 2016 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + +set arch_list=ia32 x64 + +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 + +set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm + +set JOBS=8 + +del /f /q BUILD || rmdir build /s /q + +call npm update || goto :error + +mkdir -p %ARTIFACTS_OUT% + +for %%a in (%arch_list%) do ( + for %%v in (%electron_versions%) do ( + cmd /V /C "set "HOME=%USERPROFILE%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package --runtime=electron --target=%%v --target_arch=%%a --disturl=https://atom.io/download/electron" || goto :error + + xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + rmdir build /S /Q + ) +) +if %errorlevel% neq 0 exit /b %errorlevel% + +goto :EOF + +:error +exit /b 1 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh new file mode 100755 index 000000000..a676c5f85 --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright 2016 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex + +arch_list=( ia32 x64 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 ) + +umask 022 + +cd $(dirname $0)/../../.. + +rm -rf build || true + +mkdir -p "${ARTIFACTS_OUT}" + +npm update + +for arch in ${arch_list[@]} +do + for version in ${electron_versions[@]} + do + HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$version --target_arch=$arch --disturl=https://atom.io/download/electron + cp -r build/stage/* "${ARTIFACTS_OUT}"/ + done +done + +rm -rf build || true diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 63cc45983..1c9064a99 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -16,8 +16,6 @@ set arch_list=ia32 x64 set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 - set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm set JOBS=8 @@ -40,13 +38,6 @@ for %%a in (%arch_list%) do ( xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error rmdir build /S /Q ) - - for %%v in (%electron_versions%) do ( - cmd /V /C "set "HOME=%USERPROFILE%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package --runtime=electron --target=%%v --target_arch=%%a --disturl=https://atom.io/download/electron" || goto :error - - xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error - rmdir build /S /Q - ) ) if %errorlevel% neq 0 exit /b %errorlevel% diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 1421ed86b..7ee81de84 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -17,13 +17,11 @@ set -ex arch_list=( ia32 x64 ) node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 ) while true ; do case $1 in --with-alpine) arch_list=( x64 ) - electron_versions=( ) ;; "") ;; @@ -52,12 +50,6 @@ do ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$version --target_arch=$arch cp -r build/stage/* "${ARTIFACTS_OUT}"/ done - - for version in ${electron_versions[@]} - do - HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$version --target_arch=$arch --disturl=https://atom.io/download/electron - cp -r build/stage/* "${ARTIFACTS_OUT}"/ - done done rm -rf build || true diff --git a/test/kokoro/linux-build-electron.cfg b/test/kokoro/linux-build-electron.cfg new file mode 100644 index 000000000..28c510ba8 --- /dev/null +++ b/test/kokoro/linux-build-electron.cfg @@ -0,0 +1,19 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-electron.sh" +timeout_mins: 60 diff --git a/test/kokoro/linux-build.cfg b/test/kokoro/linux-build-nodejs.cfg similarity index 92% rename from test/kokoro/linux-build.cfg rename to test/kokoro/linux-build-nodejs.cfg index b5e6d6e63..f64966a71 100644 --- a/test/kokoro/linux-build.cfg +++ b/test/kokoro/linux-build-nodejs.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro.sh" +build_file: "grpc-node/tools/release/kokoro-nodejs.sh" timeout_mins: 60 diff --git a/test/kokoro/macos-build-electron.cfg b/test/kokoro/macos-build-electron.cfg new file mode 100644 index 000000000..28c510ba8 --- /dev/null +++ b/test/kokoro/macos-build-electron.cfg @@ -0,0 +1,19 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-electron.sh" +timeout_mins: 60 diff --git a/test/kokoro/macos-build.cfg b/test/kokoro/macos-build-nodejs.cfg similarity index 92% rename from test/kokoro/macos-build.cfg rename to test/kokoro/macos-build-nodejs.cfg index b5e6d6e63..f64966a71 100644 --- a/test/kokoro/macos-build.cfg +++ b/test/kokoro/macos-build-nodejs.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro.sh" +build_file: "grpc-node/tools/release/kokoro-nodejs.sh" timeout_mins: 60 diff --git a/test/kokoro/windows-build-electron.cfg b/test/kokoro/windows-build-electron.cfg new file mode 100644 index 000000000..873b734a9 --- /dev/null +++ b/test/kokoro/windows-build-electron.cfg @@ -0,0 +1,19 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-electron.bat" +timeout_mins: 60 diff --git a/test/kokoro/windows-build.cfg b/test/kokoro/windows-build-nodejs.cfg similarity index 92% rename from test/kokoro/windows-build.cfg rename to test/kokoro/windows-build-nodejs.cfg index 1885ef39f..3e934dee9 100644 --- a/test/kokoro/windows-build.cfg +++ b/test/kokoro/windows-build-nodejs.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro.bat" +build_file: "grpc-node/tools/release/kokoro-nodejs.bat" timeout_mins: 60 diff --git a/tools/release/kokoro-electron.bat b/tools/release/kokoro-electron.bat new file mode 100644 index 000000000..52e2fb1f6 --- /dev/null +++ b/tools/release/kokoro-electron.bat @@ -0,0 +1,42 @@ +@rem Copyright 2018 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + +@echo "Starting Windows build" + +powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" + +SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% +call nvm install 10 +call nvm use 10 + +call npm install -g npm +@rem https://github.com/mapbox/node-pre-gyp/issues/362 +call npm install -g node-gyp + +cd /d %~dp0 +cd ..\.. + +git submodule update --init +git submodule foreach --recursive git submodule update --init + +set ARTIFACTS_OUT=artifacts +cd packages\grpc-native-core +call tools\run_tests\artifacts\build_artifact_electron.bat || goto :error +cd ..\.. + +move packages\grpc-native-core\artifacts . +goto :EOF + +:error +exit /b 1 diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh new file mode 100755 index 000000000..cfb9d153e --- /dev/null +++ b/tools/release/kokoro-electron.sh @@ -0,0 +1,48 @@ +#!/bin/sh +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +nvm install 10 +nvm use 10 +npm install -g npm +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + +set -ex +cd $(dirname $0)/../.. +base_dir=$(pwd) + +# Install gRPC and its submodules. +git submodule update --init +git submodule foreach --recursive git submodule update --init + +pip install mako +./packages/grpc-native-core/tools/buildgen/generate_projects.sh + +OS=`uname` + +case $OS in +Linux) + docker build -t kokoro-native-image tools/release/native + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --native-only --electron-only + cp -rv packages/grpc-native-core/artifacts . + ;; +Darwin) + JOBS=8 ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh + ;; +esac diff --git a/tools/release/kokoro.bat b/tools/release/kokoro-nodejs.bat similarity index 100% rename from tools/release/kokoro.bat rename to tools/release/kokoro-nodejs.bat diff --git a/tools/release/kokoro.sh b/tools/release/kokoro-nodejs.sh similarity index 97% rename from tools/release/kokoro.sh rename to tools/release/kokoro-nodejs.sh index 97677af15..c1f905622 100755 --- a/tools/release/kokoro.sh +++ b/tools/release/kokoro-nodejs.sh @@ -40,9 +40,9 @@ case $OS in Linux) docker build -t kokoro-native-image tools/release/native docker build -t kokoro-cross-image tools/release/cross - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --native-only + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --native-only --nodejs-only cp -rv packages/grpc-native-core/artifacts . - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-cross-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --cross-only + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-cross-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --cross-only --nodejs-only cp -rv packages/grpc-native-core/artifacts . ;; Darwin) diff --git a/tools/release/kokoro/Dockerfile b/tools/release/kokoro/Dockerfile deleted file mode 100644 index 0c31914b2..000000000 --- a/tools/release/kokoro/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM ubuntu:16.04 - -RUN dpkg --add-architecture i386 -RUN apt-get update -RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf docker.io python libc6-dev:i386 lib32stdc++-5-dev - -RUN mkdir /usr/local/nvm -ENV NVM_DIR /usr/local/nvm - -RUN curl curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash diff --git a/tools/release/kokoro/linux-electron.cfg b/tools/release/kokoro/linux-electron.cfg new file mode 100644 index 000000000..45f7e5054 --- /dev/null +++ b/tools/release/kokoro/linux-electron.cfg @@ -0,0 +1,25 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-electron.sh" +timeout_mins: 180 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux.cfg b/tools/release/kokoro/linux-nodejs.cfg similarity index 93% rename from tools/release/kokoro/linux.cfg rename to tools/release/kokoro/linux-nodejs.cfg index b3348f8d3..2a1e37128 100644 --- a/tools/release/kokoro/linux.cfg +++ b/tools/release/kokoro/linux-nodejs.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro.sh" +build_file: "grpc-node/tools/release/kokoro-nodejs.sh" timeout_mins: 180 action { define_artifacts { diff --git a/tools/release/kokoro/macos-electron.cfg b/tools/release/kokoro/macos-electron.cfg new file mode 100644 index 000000000..b0e835b8f --- /dev/null +++ b/tools/release/kokoro/macos-electron.cfg @@ -0,0 +1,25 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-electron.sh" +timeout_mins: 120 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos.cfg b/tools/release/kokoro/macos-nodejs.cfg similarity index 93% rename from tools/release/kokoro/macos.cfg rename to tools/release/kokoro/macos-nodejs.cfg index 73a539fae..7a313cb83 100644 --- a/tools/release/kokoro/macos.cfg +++ b/tools/release/kokoro/macos-nodejs.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro.sh" +build_file: "grpc-node/tools/release/kokoro-nodejs.sh" timeout_mins: 120 action { define_artifacts { diff --git a/tools/release/kokoro/windows-electron.cfg b/tools/release/kokoro/windows-electron.cfg new file mode 100644 index 000000000..14a94b64f --- /dev/null +++ b/tools/release/kokoro/windows-electron.cfg @@ -0,0 +1,25 @@ +# Copyright 2018 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-electron.bat" +timeout_mins: 120 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows.cfg b/tools/release/kokoro/windows-nodejs.cfg similarity index 93% rename from tools/release/kokoro/windows.cfg rename to tools/release/kokoro/windows-nodejs.cfg index 1ba6123f3..f9307d6d1 100644 --- a/tools/release/kokoro/windows.cfg +++ b/tools/release/kokoro/windows-nodejs.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro.bat" +build_file: "grpc-node/tools/release/kokoro-nodejs.bat" timeout_mins: 120 action { define_artifacts { From 62fc714c8df2c2f5f42576936e6d2009cd6fe250 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 23 Jan 2019 16:09:12 -0800 Subject: [PATCH 0507/1899] Update submodule on master --- packages/grpc-native-core/binding.gyp | 9 ++++++--- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 85602dc09..98ad85eb0 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.18.0"' + 'GRPC_NODE_VERSION="1.19.0-dev"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -666,6 +666,8 @@ 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', + 'deps/grpc/src/core/lib/iomgr/grpc_if_nametoindex_posix.cc', + 'deps/grpc/src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc', 'deps/grpc/src/core/lib/iomgr/internal_errqueue.cc', 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', 'deps/grpc/src/core/lib/iomgr/iomgr.cc', @@ -677,7 +679,6 @@ 'deps/grpc/src/core/lib/iomgr/is_epollexclusive_available.cc', 'deps/grpc/src/core/lib/iomgr/load_file.cc', 'deps/grpc/src/core/lib/iomgr/lockfree_event.cc', - 'deps/grpc/src/core/lib/iomgr/network_status_tracker.cc', 'deps/grpc/src/core/lib/iomgr/polling_entity.cc', 'deps/grpc/src/core/lib/iomgr/pollset.cc', 'deps/grpc/src/core/lib/iomgr/pollset_custom.cc', @@ -882,11 +883,13 @@ 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc', 'deps/grpc/src/core/ext/filters/client_channel/connector.cc', + 'deps/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.cc', 'deps/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc', 'deps/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc', 'deps/grpc/src/core/ext/filters/client_channel/http_proxy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', + 'deps/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.cc', 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', @@ -897,7 +900,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', 'deps/grpc/src/core/ext/filters/client_channel/server_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', - 'deps/grpc/src/core/ext/filters/client_channel/subchannel_index.cc', + 'deps/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', 'deps/grpc/src/core/ext/filters/client_channel/health/health.pb.c', 'deps/grpc/src/core/tsi/fake_transport_security.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 007b721f8..4b7da8ab9 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 007b721f8045ceef4ebf418a2935ab772fbe3708 +Subproject commit 4b7da8ab961e57452b1459ce28e5f68398c62845 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6d62a9e01..0cdad4397 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.18.0", + "version": "1.19.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 144a363c0de0a1759ce71a00fcf0190e75845f1c Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 30 Jan 2019 20:03:27 +0100 Subject: [PATCH 0508/1899] Stop testing on node 4 and 5. --- run-tests.bat | 2 +- run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index a47f07079..f48ab4cbe 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (4 6 7 8 9 10 11) do ( +for %%v in (6 7 8 9 10 11) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index 80362dd26..ff1caa2ec 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="4 5 6 7 8 9 10 11" + node_versions="6 7 8 9 10 11" fi set +ex From b9130b239dd2e9921b309cd8c3c5c5129bea0486 Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Wed, 30 Jan 2019 12:18:18 -0800 Subject: [PATCH 0509/1899] fix: use getRequestHeaders if available --- packages/grpc-js/src/index.ts | 36 ++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index f7a22a0d7..1208dc4b6 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -37,6 +37,7 @@ export interface OAuth2Client { getRequestMetadata: (url: string, callback: (err: Error|null, headers?: { Authorization: string }) => void) => void; + getRequestHeaders: (url?: string) => Promise<{Authorization: string}>; } /**** Client Credentials ****/ @@ -49,22 +50,39 @@ export const credentials = mixin( * @param googleCredentials The authentication client to use. * @return The resulting CallCredentials object. */ - createFromGoogleCredential: (googleCredentials: OAuth2Client): - CallCredentials => { - return CallCredentials.createFromMetadataGenerator( - (options, callback) => { + createFromGoogleCredential: ( + googleCredentials: OAuth2Client): CallCredentials => { + return CallCredentials.createFromMetadataGenerator( + (options, callback) => { + // google-auth-library pre-v2.0.0 does not have getRequestHeaders + // but has getRequestMetadata, which is deprecated in v2.0.0 + let getHeaders: Promise<{Authorization: string}>; + if (typeof googleCredentials.getRequestHeaders === 'function') { + getHeaders = + googleCredentials.getRequestHeaders(options.service_url); + } else { + getHeaders = new Promise((resolve, reject) => { googleCredentials.getRequestMetadata( options.service_url, (err, headers) => { if (err) { - callback(err); + reject(err); return; } - const metadata = new Metadata(); - metadata.add('authorization', headers!.Authorization); - callback(null, metadata); + resolve(headers); }); }); - }, + } + getHeaders.then( + headers => { + const metadata = new Metadata(); + metadata.add('authorization', headers.Authorization); + callback(null, metadata); + }, + err => { + callback(err); + }); + }); + }, /** * Combine a ChannelCredentials with any number of CallCredentials into a From 599ba0db334309fc0a06c103bf3e36eca2a72911 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 31 Jan 2019 13:56:39 -0800 Subject: [PATCH 0510/1899] Bump grpc-js to 0.3.5 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 66ff8428e..4d87085f1 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.4", + "version": "0.3.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From a235829bc7722361d2832ba9298077c514ffab8f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 31 Jan 2019 17:33:37 -0800 Subject: [PATCH 0511/1899] Target grpc-js build at a higher ES standard --- packages/grpc-js/tsconfig.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index 807ef6626..fd18bad0d 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -1,9 +1,11 @@ { "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { + "lib": ["es2017"], "rootDir": ".", "outDir": "build", - "target": "es6" + "target": "es2017", + "module": "commonjs" }, "include": [ "src/*.ts", From 511f4249d1f2e4e55c95521cb5ec448788cd3ada Mon Sep 17 00:00:00 2001 From: Shir Brass Date: Sat, 2 Feb 2019 15:17:46 +0200 Subject: [PATCH 0512/1899] removed all the deprecated new Buffer code and replace it with Buffer.from --- packages/grpc-health-check/v1/health_grpc_pb.js | 4 ++-- packages/grpc-native-core/src/credentials.js | 2 +- packages/grpc-native-core/src/protobuf_js_5_common.js | 2 +- packages/grpc-native-core/test/call_test.js | 4 ++-- packages/grpc-native-core/test/common_test.js | 10 +++++----- packages/grpc-native-core/test/credentials_test.js | 2 +- packages/grpc-native-core/test/end_to_end_test.js | 8 ++++---- packages/grpc-native-core/test/math/math_grpc_pb.js | 8 ++++---- packages/grpc-native-core/test/metadata_test.js | 10 +++++----- packages/grpc-native-core/test/surface_test.js | 8 ++++---- packages/grpc-tools/src/node_generator.cc | 7 +------ packages/grpc-tools/src/node_plugin.cc | 2 +- test/api/error_test.js | 2 +- test/interop/interop_client.js | 6 +++--- test/interop/interop_server.js | 4 ++-- test/performance/benchmark_client.js | 4 ++-- test/performance/benchmark_server.js | 4 ++-- 17 files changed, 41 insertions(+), 46 deletions(-) diff --git a/packages/grpc-health-check/v1/health_grpc_pb.js b/packages/grpc-health-check/v1/health_grpc_pb.js index 2a1ac6ff7..63de213e2 100644 --- a/packages/grpc-health-check/v1/health_grpc_pb.js +++ b/packages/grpc-health-check/v1/health_grpc_pb.js @@ -23,7 +23,7 @@ function serialize_HealthCheckRequest(arg) { if (!(arg instanceof v1_health_pb.HealthCheckRequest)) { throw new Error('Expected argument of type HealthCheckRequest'); } - return new Buffer(arg.serializeBinary()); + return Buffer.from(arg.serializeBinary()); } function deserialize_HealthCheckRequest(buffer_arg) { @@ -34,7 +34,7 @@ function serialize_HealthCheckResponse(arg) { if (!(arg instanceof v1_health_pb.HealthCheckResponse)) { throw new Error('Expected argument of type HealthCheckResponse'); } - return new Buffer(arg.serializeBinary()); + return Buffer.from(arg.serializeBinary()); } function deserialize_HealthCheckResponse(buffer_arg) { diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 2a2c51b9b..9542acfdc 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -93,7 +93,7 @@ function wrapCheckServerIdentityCallback(callback) { return new Error("Unable to parse certificate PEM."); } cert = cert.substring(PEM_CERT_HEADER.length, pemFooterIndex); - var rawBuffer = new Buffer(cert.replace("\n", "").replace(" ", ""), "base64"); + var rawBuffer = Buffer.from(cert.replace("\n", "").replace(" ", ""), "base64"); return callback(hostname, { raw: rawBuffer }); } diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js index 81c8ead3c..d9c26e26d 100644 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ b/packages/grpc-native-core/src/protobuf_js_5_common.js @@ -64,7 +64,7 @@ exports.serializeCls = function serializeCls(Cls) { * @return {Buffer} The serialized object */ return function serialize(arg) { - return new Buffer(new Cls(arg).encode().toBuffer()); + return Buffer.from(new Cls(arg).encode().toBuffer()); }; }; diff --git a/packages/grpc-native-core/test/call_test.js b/packages/grpc-native-core/test/call_test.js index f2d1a6ca0..bba4cce01 100644 --- a/packages/grpc-native-core/test/call_test.js +++ b/packages/grpc-native-core/test/call_test.js @@ -142,8 +142,8 @@ describe('call', function() { assert.doesNotThrow(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = { - 'key1-bin': [new Buffer('value1')], - 'key2-bin': [new Buffer('value2')] + 'key1-bin': [Buffer.from('value1')], + 'key2-bin': [Buffer.from('value2')] }; call.startBatch(batch, function(err, resp) { assert.ifError(err); diff --git a/packages/grpc-native-core/test/common_test.js b/packages/grpc-native-core/test/common_test.js index 4459d7e81..15037d630 100644 --- a/packages/grpc-native-core/test/common_test.js +++ b/packages/grpc-native-core/test/common_test.js @@ -97,7 +97,7 @@ describe('Proto message bytes serialize and deserialize', function() { var b64_options = Object.assign({}, default_options, {binaryAsBase64: true}); var sequenceBase64Deserialize = deserializeCls( messages_proto.SequenceValues, b64_options); - var buffer_val = new Buffer([0x69, 0xb7]); + var buffer_val = Buffer.from([0x69, 0xb7]); var base64_val = 'abc='; it('should preserve a buffer', function() { var serialized = sequenceSerialize({bytes_field: buffer_val}); @@ -115,18 +115,18 @@ describe('Proto message bytes serialize and deserialize', function() { assert.strictEqual(deserialized.bytes_field, base64_val); }); it('should serialize a repeated field as packed by default', function() { - var expected_serialize = new Buffer([0x12, 0x01, 0x0a]); + var expected_serialize = Buffer.from([0x12, 0x01, 0x0a]); var serialized = sequenceSerialize({repeated_field: [10]}); assert.strictEqual(expected_serialize.compare(serialized), 0); }); // This tests a bug that was fixed in Protobuf.js 6 it.skip('should deserialize packed or unpacked repeated', function() { var expectedDeserialize = { - bytes_field: new Buffer(''), + bytes_field: Buffer.from(''), repeated_field: [10] }; - var packedSerialized = new Buffer([0x12, 0x01, 0x0a]); - var unpackedSerialized = new Buffer([0x10, 0x0a]); + var packedSerialized = Buffer.from([0x12, 0x01, 0x0a]); + var unpackedSerialized = Buffer.from([0x10, 0x0a]); var packedDeserialized; var unpackedDeserialized; assert.doesNotThrow(function() { diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js index 74d3edc14..1c0fe9a13 100644 --- a/packages/grpc-native-core/test/credentials_test.js +++ b/packages/grpc-native-core/test/credentials_test.js @@ -295,7 +295,7 @@ describe('client credentials', function() { assert.equal(callback_host, 'foo.test.google.fr'); // The roundabout forge APIs for converting PEM to a node DER Buffer - var expected_der = new Buffer(forge.asn1.toDer( + var expected_der = Buffer.from(forge.asn1.toDer( forge.pki.certificateToAsn1(forge.pki.certificateFromPem(pem_data))) .getBytes(), 'binary'); diff --git a/packages/grpc-native-core/test/end_to_end_test.js b/packages/grpc-native-core/test/end_to_end_test.js index 7db373d6a..da6fac6c2 100644 --- a/packages/grpc-native-core/test/end_to_end_test.js +++ b/packages/grpc-native-core/test/end_to_end_test.js @@ -172,7 +172,7 @@ describe('end-to-end', function() { Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; - client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(req_text); + client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(req_text); client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_MESSAGE] = true; @@ -203,7 +203,7 @@ describe('end-to-end', function() { assert(response.send_metadata); assert.strictEqual(response.read.toString(), req_text); var response_batch = {}; - response_batch[grpc.opType.SEND_MESSAGE] = new Buffer(reply_text); + response_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(reply_text); response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { metadata: {}, code: constants.status.OK, @@ -227,7 +227,7 @@ describe('end-to-end', function() { Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; - client_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[0]); + client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[0]); client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; call.startBatch(client_batch, function(err, response) { assert.ifError(err); @@ -237,7 +237,7 @@ describe('end-to-end', function() { metadata: {} }); var req2_batch = {}; - req2_batch[grpc.opType.SEND_MESSAGE] = new Buffer(requests[1]); + req2_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[1]); req2_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; req2_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; call.startBatch(req2_batch, function(err, resp) { diff --git a/packages/grpc-native-core/test/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js index 82105c0f5..1daf04b95 100644 --- a/packages/grpc-native-core/test/math/math_grpc_pb.js +++ b/packages/grpc-native-core/test/math/math_grpc_pb.js @@ -23,7 +23,7 @@ function serialize_DivArgs(arg) { if (!(arg instanceof math_math_pb.DivArgs)) { throw new Error('Expected argument of type DivArgs'); } - return new Buffer(arg.serializeBinary()); + return Buffer.from(arg.serializeBinary()); } function deserialize_DivArgs(buffer_arg) { @@ -34,7 +34,7 @@ function serialize_DivReply(arg) { if (!(arg instanceof math_math_pb.DivReply)) { throw new Error('Expected argument of type DivReply'); } - return new Buffer(arg.serializeBinary()); + return Buffer.from(arg.serializeBinary()); } function deserialize_DivReply(buffer_arg) { @@ -45,7 +45,7 @@ function serialize_FibArgs(arg) { if (!(arg instanceof math_math_pb.FibArgs)) { throw new Error('Expected argument of type FibArgs'); } - return new Buffer(arg.serializeBinary()); + return Buffer.from(arg.serializeBinary()); } function deserialize_FibArgs(buffer_arg) { @@ -56,7 +56,7 @@ function serialize_Num(arg) { if (!(arg instanceof math_math_pb.Num)) { throw new Error('Expected argument of type Num'); } - return new Buffer(arg.serializeBinary()); + return Buffer.from(arg.serializeBinary()); } function deserialize_Num(buffer_arg) { diff --git a/packages/grpc-native-core/test/metadata_test.js b/packages/grpc-native-core/test/metadata_test.js index 6063b31fd..2c1765aa6 100644 --- a/packages/grpc-native-core/test/metadata_test.js +++ b/packages/grpc-native-core/test/metadata_test.js @@ -30,7 +30,7 @@ describe('Metadata', function() { describe('#set', function() { it('Only accepts string values for non "-bin" keys', function() { assert.throws(function() { - metadata.set('key', new Buffer('value')); + metadata.set('key', Buffer.from('value')); }); assert.doesNotThrow(function() { metadata.set('key', 'value'); @@ -41,7 +41,7 @@ describe('Metadata', function() { metadata.set('key-bin', 'value'); }); assert.doesNotThrow(function() { - metadata.set('key-bin', new Buffer('value')); + metadata.set('key-bin', Buffer.from('value')); }); }); it('Rejects invalid keys', function() { @@ -76,7 +76,7 @@ describe('Metadata', function() { describe('#add', function() { it('Only accepts string values for non "-bin" keys', function() { assert.throws(function() { - metadata.add('key', new Buffer('value')); + metadata.add('key', Buffer.from('value')); }); assert.doesNotThrow(function() { metadata.add('key', 'value'); @@ -87,7 +87,7 @@ describe('Metadata', function() { metadata.add('key-bin', 'value'); }); assert.doesNotThrow(function() { - metadata.add('key-bin', new Buffer('value')); + metadata.add('key-bin', Buffer.from('value')); }); }); it('Rejects invalid keys', function() { @@ -130,7 +130,7 @@ describe('Metadata', function() { beforeEach(function() { metadata.add('key', 'value1'); metadata.add('key', 'value2'); - metadata.add('key-bin', new Buffer('value')); + metadata.add('key-bin', Buffer.from('value')); }); it('gets all values associated with a key', function() { assert.deepEqual(metadata.get('key'), ['value1', 'value2']); diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index a12d3c3b0..bc745957a 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -319,7 +319,7 @@ describe('Generic client and server', function() { return val.toString(); } function toBuffer(str) { - return new Buffer(str); + return Buffer.from(str); } var string_service_attrs = { 'capitalize' : { @@ -365,7 +365,7 @@ describe('Server-side getPeer', function() { return val.toString(); } function toBuffer(str) { - return new Buffer(str); + return Buffer.from(str); } var string_service_attrs = { 'getPeer' : { @@ -620,7 +620,7 @@ describe('Echo metadata', function() { describe('Client malformed response handling', function() { var server; var client; - var badArg = new Buffer([0xFF]); + var badArg = Buffer.from([0xFF]); before(function() { var Client = grpc.load(__dirname + '/test_service.proto').TestService; var malformed_test_service = { @@ -936,7 +936,7 @@ describe('Other conditions', function() { }); describe('Server recieving bad input', function() { var misbehavingClient; - var badArg = new Buffer([0xFF]); + var badArg = Buffer.from([0xFF]); before(function() { var test_service_attrs = { unary: { diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index 8fac3a529..c4245405c 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -136,12 +136,7 @@ void PrintMessageTransformer(const Descriptor* descriptor, Printer* out, "throw new Error('Expected argument of type $name$');\n"); out->Outdent(); out->Print("}\n"); - if (params.minimum_node_version > 5) { - // Node version is > 5, we should use Buffer.from - out->Print("return Buffer.from(arg.serializeBinary());\n"); - } else { - out->Print("return new Buffer(arg.serializeBinary());\n"); - } + out->Print("return Buffer.from(arg.serializeBinary());\n"); out->Outdent(); out->Print("}\n\n"); diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index d6cd55342..2a8e949ed 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -37,7 +37,7 @@ class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc::protobuf::compiler::GeneratorContext* context, grpc::string* error) const { grpc_node_generator::Parameters generator_parameters; - generator_parameters.minimum_node_version = 4; + generator_parameters.minimum_node_version = 6; if (!parameter.empty()) { std::vector parameters_list = diff --git a/test/api/error_test.js b/test/api/error_test.js index d8bf4b751..b40ec197a 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -315,7 +315,7 @@ describe('Client malformed response handling', function() { }); describe('Server recieving bad input', function() { var misbehavingClient; - var badArg = new Buffer([0xFF]); + var badArg = Buffer.from([0xFF]); before(function() { var test_service_attrs = { unary: { diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index a8a6a3e4e..d83e99804 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -49,10 +49,10 @@ var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The new buffer + * @return {Buffer} The Buffer.from */ function zeroBuffer(size) { - var zeros = new Buffer(size); + var zeros = Buffer.from(size); zeros.fill(0); return zeros; } @@ -294,7 +294,7 @@ function customMetadata(client, done) { done = multiDone(done, 5); var metadata = new grpc.Metadata(); metadata.set(ECHO_INITIAL_KEY, 'test_initial_metadata_value'); - metadata.set(ECHO_TRAILING_KEY, new Buffer('ababab', 'hex')); + metadata.set(ECHO_TRAILING_KEY, Buffer.from('ababab', 'hex')); var arg = { response_type: 'COMPRESSABLE', response_size: 314159, diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index dce85873b..31ea842c3 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -39,10 +39,10 @@ var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The new buffer + * @return {Buffer} The Buffer.from */ function zeroBuffer(size) { - var zeros = new Buffer(size); + var zeros = Buffer.from(size); zeros.fill(0); return zeros; } diff --git a/test/performance/benchmark_client.js b/test/performance/benchmark_client.js index 7d103a290..541e6fa7d 100644 --- a/test/performance/benchmark_client.js +++ b/test/performance/benchmark_client.js @@ -50,10 +50,10 @@ var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The new buffer + * @return {Buffer} The Buffer.from */ function zeroBuffer(size) { - var zeros = new Buffer(size); + var zeros = Buffer.from(size); zeros.fill(0); return zeros; } diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index e216f7797..00c6e69c5 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -44,10 +44,10 @@ var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The new buffer + * @return {Buffer} The Buffer.from */ function zeroBuffer(size) { - var zeros = new Buffer(size); + var zeros = Buffer.from(size); zeros.fill(0); return zeros; } From b1609a131175e7f41d6e9b3ba02fefa27aaffc96 Mon Sep 17 00:00:00 2001 From: Shir Brass Date: Tue, 5 Feb 2019 17:31:03 +0200 Subject: [PATCH 0513/1899] replace usage of Buffer.from with Buffer.alloc --- packages/grpc-native-core/test/common_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/common_test.js b/packages/grpc-native-core/test/common_test.js index 15037d630..441392b13 100644 --- a/packages/grpc-native-core/test/common_test.js +++ b/packages/grpc-native-core/test/common_test.js @@ -122,7 +122,7 @@ describe('Proto message bytes serialize and deserialize', function() { // This tests a bug that was fixed in Protobuf.js 6 it.skip('should deserialize packed or unpacked repeated', function() { var expectedDeserialize = { - bytes_field: Buffer.from(''), + bytes_field: Buffer.alloc(''), repeated_field: [10] }; var packedSerialized = Buffer.from([0x12, 0x01, 0x0a]); From 90888cae88df1ddac06fa831314b99e0ed47c20c Mon Sep 17 00:00:00 2001 From: Shir Brass Date: Tue, 5 Feb 2019 17:35:02 +0200 Subject: [PATCH 0514/1899] replace usage of Buffer.from with Buffer.alloc --- test/interop/interop_client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index d83e99804..751264f21 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -49,10 +49,10 @@ var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The Buffer.from + * @return {Buffer} The New Buffer */ function zeroBuffer(size) { - var zeros = Buffer.from(size); + var zeros = Buffer.alloc(size); zeros.fill(0); return zeros; } From 6bd43856a8f3fe27f52dd6b9ec01ee9a77158a48 Mon Sep 17 00:00:00 2001 From: Shir Brass Date: Tue, 5 Feb 2019 17:35:42 +0200 Subject: [PATCH 0515/1899] replace usage of Buffer.from with Buffer.alloc --- test/interop/interop_server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index 31ea842c3..a924f20b9 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -39,10 +39,10 @@ var ECHO_TRAILING_KEY = 'x-grpc-test-echo-trailing-bin'; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The Buffer.from + * @return {Buffer} The New Buffer */ function zeroBuffer(size) { - var zeros = Buffer.from(size); + var zeros = Buffer.alloc(size); zeros.fill(0); return zeros; } From 6f0f2e456089c2563d4212b459d233c0684d7aac Mon Sep 17 00:00:00 2001 From: Shir Brass Date: Tue, 5 Feb 2019 17:36:15 +0200 Subject: [PATCH 0516/1899] replace usage of Buffer.from with Buffer.alloc --- test/performance/benchmark_client.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/performance/benchmark_client.js b/test/performance/benchmark_client.js index 541e6fa7d..1b964b25e 100644 --- a/test/performance/benchmark_client.js +++ b/test/performance/benchmark_client.js @@ -50,10 +50,10 @@ var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The Buffer.from + * @return {Buffer} The New Buffer */ function zeroBuffer(size) { - var zeros = Buffer.from(size); + var zeros = Buffer.alloc(size); zeros.fill(0); return zeros; } From c3abd598a507c63bbfb4ddac5824aa2aa5f73508 Mon Sep 17 00:00:00 2001 From: Shir Brass Date: Tue, 5 Feb 2019 17:36:53 +0200 Subject: [PATCH 0517/1899] replace usage of Buffer.from with Buffer.alloc --- test/performance/benchmark_server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index 00c6e69c5..3b5ef625e 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -44,10 +44,10 @@ var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** * Create a buffer filled with size zeroes * @param {number} size The length of the buffer - * @return {Buffer} The Buffer.from + * @return {Buffer} The New Buffer */ function zeroBuffer(size) { - var zeros = Buffer.from(size); + var zeros = Buffer.alloc(size); zeros.fill(0); return zeros; } From c137ca6849051982c866839cc776b04b286e3f83 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 31 Jan 2019 12:53:12 -0800 Subject: [PATCH 0518/1899] Add build files for grpc-tools and tests for those builds --- packages/grpc-tools/CMakeLists.txt | 27 ++++++++++ packages/grpc-tools/build_binaries.ps1 | 47 +++++++++++++++++ packages/grpc-tools/build_binaries.sh | 50 +++++++++++++++++++ .../grpc-tools/linux_32bit.toolchain.cmake | 3 ++ test/kokoro-nodejs-build-test.bat | 5 ++ test/kokoro-nodejs-build-test.sh | 6 +++ test/kokoro/linux-build-nodejs.cfg | 2 +- test/kokoro/macos-build-nodejs.cfg | 2 +- test/kokoro/windows-build-nodejs.cfg | 2 +- 9 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 packages/grpc-tools/CMakeLists.txt create mode 100644 packages/grpc-tools/build_binaries.ps1 create mode 100755 packages/grpc-tools/build_binaries.sh create mode 100644 packages/grpc-tools/linux_32bit.toolchain.cmake create mode 100644 test/kokoro-nodejs-build-test.bat create mode 100644 test/kokoro-nodejs-build-test.sh diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt new file mode 100644 index 000000000..a7d581765 --- /dev/null +++ b/packages/grpc-tools/CMakeLists.txt @@ -0,0 +1,27 @@ +cmake_minimum_required(VERSION 3.10) +if(COMMAND cmake_policy) + cmake_policy(SET CMP0003 NEW) +endif(COMMAND cmake_policy) + +set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/protobuf) +add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake deps/protobuf) + +set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests") +set(protobuf_WITH_ZLIB OFF CACHE BOOL "Build protobuf with zlib.") + +add_executable(grpc_node_plugin + src/node_generator.cc + src/node_plugin.cc +) + + +target_include_directories(grpc_node_plugin + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src + PRIVATE ${PROTOBUF_ROOT_DIR}/include +) + +target_link_libraries(grpc_node_plugin + libprotoc + libprotobuf +) \ No newline at end of file diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 new file mode 100644 index 000000000..7bfd92226 --- /dev/null +++ b/packages/grpc-tools/build_binaries.ps1 @@ -0,0 +1,47 @@ +Install-Module -Name 7Zip4Powershell + +function MkDir-p($Path) { + $FullPath = "\\?\" + $Path + if (-not (Test-Path -Path $FullPath)) { + New-Item -ItemType directory -Path $FullPath | Out-Null + } +} + +$WellKnownProtos = "any","api","compiler/plugin","descriptor","duration","empty","field_mask","source_context","struct","timestamp","type","wrappers" + +$Base = %~dp0 +cd $Base +$ProtobufBase = $Base + "/deps/protobuf" +MkDir-p $Base + "/build/bin" + +$PackageFile = $Base + "/package.json" +$ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-Member -Name version + +$OutDir = $ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion +Mkdir-p $OutDir + +foreach ($Proto in $WellKnownProtos) { + Copy-Item $ProtobufBase + "/src/google/protobuf/" + $Proto + ".proto" -Destination $Base + "/build/bin/google/protobuf/" + $Proto + ".proto" +} + +$ArchList = "ia32","x64" + +foreach ($Arch in $ArchList) { + if ($Arch -eq "x64") { + $Generator = "Visual Studio 14 2015 Win64" + } else { + $Generator = "Visual Studio 14 2015" + } + Remove-Item $Base + "/build/bin/protoc.exe" + Remove-Item $Base + "/build/bin/grpc_node_plugin.exe" + Remove-Item $Base + "CMakeCache.txt" + + Invoke-Expression "cmake ." + Invoke-Expression "cmake --build ." + + Copy-Item $ProtobufBase + "/protoc.exe" -Destination $Base + "/build/bin/protoc.exe" + Copy-Item $Base + "/grpc_node_plugin.exe" -Destination $Base + "/build/bin/grpc_node_plugin.exe" + + Compress-7Zip -Path $Base + "/build" -Format Tar -ArchiveFileName $Base + "/Archive.tar" + Compress-7Zip -Path $Base + "/Archive.tar" -Format GZip -ArchiveFileName $OutDir + "/windows-x64.tar.gz" +} \ No newline at end of file diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh new file mode 100755 index 000000000..60045d175 --- /dev/null +++ b/packages/grpc-tools/build_binaries.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +set -e + +well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers ) + +cd $(dirname $0) +base=$(pwd) +protobuf_base=$base/deps/protobuf + +tools_version=$(jq '.version' < package.json | tr -d '"') + +out_dir=$ARTIFACTS_OUT/grpc-tools/v$tools_version +mkdir -p "$out_dir" + +mkdir -p "$base/build/bin/google/protobuf/compiler" +for proto in "${well_known_protos[@]}"; do + cp "$protobuf_base/src/google/protobuf/$proto.proto" "$base/build/bin/google/protobuf/$proto.proto" +done + +case $(uname -s) in + Linux) + platform=linux + arch_list=( ia32 x64 ) + ;; + Darwin) + platform=darwin + arch_list=( x64 ) + ;; +esac + +for arch in "${arch_list[@]}"; do + case $arch in + ia32) + toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_32bit.toolchain.cmake + ;; + *) + toolchain_flag= + ;; + esac + rm -f $base/build/bin/protoc + rm -f $base/build/bin/grpc_node_plugin + rm -f CMakeCache.txt + cmake $toolchain_flag . && cmake --build . --target clean && cmake --build . -- -j 12 + cp -L $protobuf_base/protoc $base/build/bin/protoc + cp $base/grpc_node_plugin $base/build/bin/ + cd $base/build + tar -czf "$out_dir/$platform-$arch.tar.gz" bin/ + cd $base +done \ No newline at end of file diff --git a/packages/grpc-tools/linux_32bit.toolchain.cmake b/packages/grpc-tools/linux_32bit.toolchain.cmake new file mode 100644 index 000000000..5a1b80f03 --- /dev/null +++ b/packages/grpc-tools/linux_32bit.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "c++ flags") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32" CACHE STRING "c flags") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m32" CACHE STRING "ld flags") \ No newline at end of file diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat new file mode 100644 index 000000000..0ccf27ad2 --- /dev/null +++ b/test/kokoro-nodejs-build-test.bat @@ -0,0 +1,5 @@ +cd /d %~dp0 +cd .. + +call ./tools/release/kokoro-nodejs.bat +powershell -File ./packages/grpc-tools/build_binaries.ps1 \ No newline at end of file diff --git a/test/kokoro-nodejs-build-test.sh b/test/kokoro-nodejs-build-test.sh new file mode 100644 index 000000000..45371794e --- /dev/null +++ b/test/kokoro-nodejs-build-test.sh @@ -0,0 +1,6 @@ +set -e +cd $(dirname $0)/.. +base_dir=$(pwd) + +./tools/release/kokoro-nodejs.sh +ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh \ No newline at end of file diff --git a/test/kokoro/linux-build-nodejs.cfg b/test/kokoro/linux-build-nodejs.cfg index f64966a71..ba2f49f24 100644 --- a/test/kokoro/linux-build-nodejs.cfg +++ b/test/kokoro/linux-build-nodejs.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-nodejs.sh" +build_file: "grpc-node/test/kokoro-nodejs-build-test.sh" timeout_mins: 60 diff --git a/test/kokoro/macos-build-nodejs.cfg b/test/kokoro/macos-build-nodejs.cfg index f64966a71..ba2f49f24 100644 --- a/test/kokoro/macos-build-nodejs.cfg +++ b/test/kokoro/macos-build-nodejs.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-nodejs.sh" +build_file: "grpc-node/test/kokoro-nodejs-build-test.sh" timeout_mins: 60 diff --git a/test/kokoro/windows-build-nodejs.cfg b/test/kokoro/windows-build-nodejs.cfg index 3e934dee9..87f443708 100644 --- a/test/kokoro/windows-build-nodejs.cfg +++ b/test/kokoro/windows-build-nodejs.cfg @@ -15,5 +15,5 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-nodejs.bat" +build_file: "grpc-node/test/kokoro-nodejs-build-test.bat" timeout_mins: 60 From 20d7414b81c5c98f30d4a1297d56f1decb23e427 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Feb 2019 15:07:42 -0800 Subject: [PATCH 0519/1899] Make release script setup more consistent --- packages/grpc-tools/build_binaries.ps1 | 2 +- test/kokoro-nodejs-build-test.bat | 2 +- test/kokoro-nodejs-build-test.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 7bfd92226..77a4064e1 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -17,7 +17,7 @@ MkDir-p $Base + "/build/bin" $PackageFile = $Base + "/package.json" $ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-Member -Name version -$OutDir = $ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion +$OutDir = $Env:ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir foreach ($Proto in $WellKnownProtos) { diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat index 0ccf27ad2..bffa4b895 100644 --- a/test/kokoro-nodejs-build-test.bat +++ b/test/kokoro-nodejs-build-test.bat @@ -2,4 +2,4 @@ cd /d %~dp0 cd .. call ./tools/release/kokoro-nodejs.bat -powershell -File ./packages/grpc-tools/build_binaries.ps1 \ No newline at end of file +call ./tools/release/kokoro-grpc-tools.bat \ No newline at end of file diff --git a/test/kokoro-nodejs-build-test.sh b/test/kokoro-nodejs-build-test.sh index 45371794e..fdb4bc74b 100644 --- a/test/kokoro-nodejs-build-test.sh +++ b/test/kokoro-nodejs-build-test.sh @@ -3,4 +3,4 @@ cd $(dirname $0)/.. base_dir=$(pwd) ./tools/release/kokoro-nodejs.sh -ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh \ No newline at end of file +./tools/release/kokoro-grpc-tools.sh \ No newline at end of file From b9fd1c04fe2359d8fc740d9b5a7025f53ad80dc6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Feb 2019 15:50:47 -0800 Subject: [PATCH 0520/1899] Actually commit grpc-tools kokoro scripts --- tools/release/kokoro-grpc-tools.bat | 5 +++++ tools/release/kokoro-grpc-tools.sh | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 tools/release/kokoro-grpc-tools.bat create mode 100644 tools/release/kokoro-grpc-tools.sh diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat new file mode 100644 index 000000000..cc8109bfd --- /dev/null +++ b/tools/release/kokoro-grpc-tools.bat @@ -0,0 +1,5 @@ +cd /d %~dp0 +cd .. + +set ARTIFACTS_OUT=artifacts +powershell -File ./packages/grpc-tools/build_binaries.ps1 \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh new file mode 100644 index 000000000..252a54d1d --- /dev/null +++ b/tools/release/kokoro-grpc-tools.sh @@ -0,0 +1,5 @@ +set -e +cd $(dirname $0)/.. +base_dir=$(pwd) + +ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh \ No newline at end of file From babc0ae0fa59faf78ac45db373263f3f9a61fbed Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Feb 2019 15:52:56 -0800 Subject: [PATCH 0521/1899] Set execute bits on scripts --- test/kokoro-nodejs-build-test.sh | 0 tools/release/kokoro-grpc-tools.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/kokoro-nodejs-build-test.sh mode change 100644 => 100755 tools/release/kokoro-grpc-tools.sh diff --git a/test/kokoro-nodejs-build-test.sh b/test/kokoro-nodejs-build-test.sh old mode 100644 new mode 100755 diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh old mode 100644 new mode 100755 From 275b2908f9673ebc18c2ff1cfeca653af7001155 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Feb 2019 16:25:14 -0800 Subject: [PATCH 0522/1899] Fix paths in new kokoro scripts --- tools/release/kokoro-grpc-tools.bat | 2 +- tools/release/kokoro-grpc-tools.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat index cc8109bfd..4a85823fb 100644 --- a/tools/release/kokoro-grpc-tools.bat +++ b/tools/release/kokoro-grpc-tools.bat @@ -1,5 +1,5 @@ cd /d %~dp0 -cd .. +cd ../.. set ARTIFACTS_OUT=artifacts powershell -File ./packages/grpc-tools/build_binaries.ps1 \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index 252a54d1d..b4fcb266d 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -1,5 +1,5 @@ set -e -cd $(dirname $0)/.. +cd $(dirname $0)/../.. base_dir=$(pwd) ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh \ No newline at end of file From 35e7a7575a2c16e3c524e4e5ca2a45479fcac004 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Feb 2019 10:57:40 -0800 Subject: [PATCH 0523/1899] Fix build script issues --- packages/grpc-tools/CMakeLists.txt | 3 +++ packages/grpc-tools/build_binaries.ps1 | 22 ++++++++++++---------- tools/release/kokoro-grpc-tools.bat | 2 +- tools/release/kokoro-grpc-tools.sh | 12 +++++++++++- 4 files changed, 27 insertions(+), 12 deletions(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index a7d581765..8d38e4e09 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -3,6 +3,9 @@ if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/protobuf) add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake deps/protobuf) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 77a4064e1..7861ebeb1 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -1,3 +1,5 @@ +Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force +Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 Install-Module -Name 7Zip4Powershell function MkDir-p($Path) { @@ -9,10 +11,10 @@ function MkDir-p($Path) { $WellKnownProtos = "any","api","compiler/plugin","descriptor","duration","empty","field_mask","source_context","struct","timestamp","type","wrappers" -$Base = %~dp0 +$Base = $PSScriptRoot cd $Base $ProtobufBase = $Base + "/deps/protobuf" -MkDir-p $Base + "/build/bin" +MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" $ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-Member -Name version @@ -21,7 +23,7 @@ $OutDir = $Env:ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir foreach ($Proto in $WellKnownProtos) { - Copy-Item $ProtobufBase + "/src/google/protobuf/" + $Proto + ".proto" -Destination $Base + "/build/bin/google/protobuf/" + $Proto + ".proto" + Copy-Item ($ProtobufBase + "/src/google/protobuf/" + $Proto + ".proto") -Destination ($Base + "/build/bin/google/protobuf/" + $Proto + ".proto") } $ArchList = "ia32","x64" @@ -32,16 +34,16 @@ foreach ($Arch in $ArchList) { } else { $Generator = "Visual Studio 14 2015" } - Remove-Item $Base + "/build/bin/protoc.exe" - Remove-Item $Base + "/build/bin/grpc_node_plugin.exe" - Remove-Item $Base + "CMakeCache.txt" + Remove-Item ($Base + "/build/bin/protoc.exe") + Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") + Remove-Item ($Base + "CMakeCache.txt") Invoke-Expression "cmake ." Invoke-Expression "cmake --build ." - Copy-Item $ProtobufBase + "/protoc.exe" -Destination $Base + "/build/bin/protoc.exe" - Copy-Item $Base + "/grpc_node_plugin.exe" -Destination $Base + "/build/bin/grpc_node_plugin.exe" + Copy-Item ($ProtobufBase + "/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") + Copy-Item ($Base + "/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") - Compress-7Zip -Path $Base + "/build" -Format Tar -ArchiveFileName $Base + "/Archive.tar" - Compress-7Zip -Path $Base + "/Archive.tar" -Format GZip -ArchiveFileName $OutDir + "/windows-x64.tar.gz" + Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") + Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/windows-x64.tar.gz") } \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat index 4a85823fb..d62a9e0ab 100644 --- a/tools/release/kokoro-grpc-tools.bat +++ b/tools/release/kokoro-grpc-tools.bat @@ -2,4 +2,4 @@ cd /d %~dp0 cd ../.. set ARTIFACTS_OUT=artifacts -powershell -File ./packages/grpc-tools/build_binaries.ps1 \ No newline at end of file +powershell -File ./packages/grpc-tools/build_binaries.ps1 || exit /b 1 \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index b4fcb266d..c77e3f3c4 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -2,4 +2,14 @@ set -e cd $(dirname $0)/../.. base_dir=$(pwd) -ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh \ No newline at end of file +OS=$(uname) + +case $OS in +Linux) + docker build -t kokoro-native-image tools/release/native + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image -e ARTIFACTS_OUT=$base_dir/artifacts $base_dir/packages/grpc-tools/build_binaries.sh + ;; +Darwin) + ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh + ;; +esac \ No newline at end of file From 4821df409f4f9bc6c58fbe139dde63cee1f1e818 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Feb 2019 11:01:04 -0800 Subject: [PATCH 0524/1899] Disable c++ extensions in grpc-tools --- packages/grpc-tools/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 8d38e4e09..250819010 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -5,6 +5,7 @@ endif(COMMAND cmake_policy) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/protobuf) add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake deps/protobuf) From fc6feb470e4a997093c255335bc4416319a755e7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Feb 2019 12:44:48 -0800 Subject: [PATCH 0525/1899] More Windows script fixes --- packages/grpc-tools/build_binaries.ps1 | 4 ++-- test/kokoro-nodejs-build-test.bat | 9 +++++++-- tools/release/kokoro-grpc-tools.bat | 2 +- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 7861ebeb1..bafb3e43d 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -1,6 +1,6 @@ Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Install-Module -Name 7Zip4Powershell +Install-Module -Force -Name 7Zip4Powershell function MkDir-p($Path) { $FullPath = "\\?\" + $Path @@ -14,7 +14,7 @@ $WellKnownProtos = "any","api","compiler/plugin","descriptor","duration","empty" $Base = $PSScriptRoot cd $Base $ProtobufBase = $Base + "/deps/protobuf" -MkDir-p ($Base + "/build/bin") +MkDir-p ($Base + "/build/bin/google/protobuf/compiler") $PackageFile = $Base + "/package.json" $ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-Member -Name version diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat index bffa4b895..bc9872267 100644 --- a/test/kokoro-nodejs-build-test.bat +++ b/test/kokoro-nodejs-build-test.bat @@ -1,5 +1,10 @@ cd /d %~dp0 cd .. -call ./tools/release/kokoro-nodejs.bat -call ./tools/release/kokoro-grpc-tools.bat \ No newline at end of file +call ./tools/release/kokoro-nodejs.bat || goto :error +call ./tools/release/kokoro-grpc-tools.bat || goto :error + +goto :EOF + +:error +exit /b 1 \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat index d62a9e0ab..38850eee8 100644 --- a/tools/release/kokoro-grpc-tools.bat +++ b/tools/release/kokoro-grpc-tools.bat @@ -1,5 +1,5 @@ cd /d %~dp0 cd ../.. -set ARTIFACTS_OUT=artifacts +set ARTIFACTS_OUT=%cd%/artifacts powershell -File ./packages/grpc-tools/build_binaries.ps1 || exit /b 1 \ No newline at end of file From 27cb1c1b64740ab48d6fe4adb3ad6d6d7fcf6a99 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Feb 2019 14:46:04 -0800 Subject: [PATCH 0526/1899] Fix docker run argument ordering --- tools/release/kokoro-grpc-tools.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index c77e3f3c4..5cf4989fb 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -7,7 +7,7 @@ OS=$(uname) case $OS in Linux) docker build -t kokoro-native-image tools/release/native - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image -e ARTIFACTS_OUT=$base_dir/artifacts $base_dir/packages/grpc-tools/build_binaries.sh + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir -e ARTIFACTS_OUT=$base_dir/artifacts kokoro-native-image $base_dir/packages/grpc-tools/build_binaries.sh ;; Darwin) ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh From 8e39e320344105624831f8d9ea96690d2baae13d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Feb 2019 15:17:31 -0800 Subject: [PATCH 0527/1899] Install new build dependencies in dockerfile --- tools/release/native/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index 35e841ccc..ccc9a69d9 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -1,7 +1,7 @@ FROM debian:jessie RUN apt-get update -RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev +RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev cmake jq RUN curl -fsSL get.docker.com | bash RUN mkdir /usr/local/nvm From 3d4072e806804869d447b1b36c0c7db31dfcd531 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Feb 2019 15:55:25 -0800 Subject: [PATCH 0528/1899] Fix cmake installation --- packages/grpc-tools/CMakeLists.txt | 2 +- tools/release/native/Dockerfile | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 250819010..e3deadde2 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.6) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index ccc9a69d9..4af3c3d06 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -1,10 +1,12 @@ FROM debian:jessie +RUN echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list RUN apt-get update -RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev cmake jq +RUN apt-get -t jessie-backports install cmake +RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq RUN curl -fsSL get.docker.com | bash RUN mkdir /usr/local/nvm ENV NVM_DIR /usr/local/nvm -RUN curl curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash From 2b35fcd154fa07681a47898f7c45c05dd159e448 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 8 Feb 2019 10:49:13 -0800 Subject: [PATCH 0529/1899] Fix new installation line in native Dockerfile --- tools/release/native/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index 4af3c3d06..40665df1c 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -2,7 +2,7 @@ FROM debian:jessie RUN echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list RUN apt-get update -RUN apt-get -t jessie-backports install cmake +RUN apt-get -t jessie-backports install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq RUN curl -fsSL get.docker.com | bash From b94b2eb6649e54a60c1189e76afe395bf6fe0161 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 8 Feb 2019 14:01:46 -0800 Subject: [PATCH 0530/1899] Add kokoro config files for grpc-tools release build jobs --- tools/release/kokoro/linux-grpc-tools.cfg | 25 +++++++++++++++++++++ tools/release/kokoro/macos-grpc-tools.cfg | 25 +++++++++++++++++++++ tools/release/kokoro/windows-grpc-tools.cfg | 25 +++++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 tools/release/kokoro/linux-grpc-tools.cfg create mode 100644 tools/release/kokoro/macos-grpc-tools.cfg create mode 100644 tools/release/kokoro/windows-grpc-tools.cfg diff --git a/tools/release/kokoro/linux-grpc-tools.cfg b/tools/release/kokoro/linux-grpc-tools.cfg new file mode 100644 index 000000000..0925db77b --- /dev/null +++ b/tools/release/kokoro/linux-grpc-tools.cfg @@ -0,0 +1,25 @@ +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-grpc-tools.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos-grpc-tools.cfg b/tools/release/kokoro/macos-grpc-tools.cfg new file mode 100644 index 000000000..d19b56e13 --- /dev/null +++ b/tools/release/kokoro/macos-grpc-tools.cfg @@ -0,0 +1,25 @@ +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-grpc-tools.sh" +timeout_mins: 120 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows-grpc-tools.cfg b/tools/release/kokoro/windows-grpc-tools.cfg new file mode 100644 index 000000000..db649afcf --- /dev/null +++ b/tools/release/kokoro/windows-grpc-tools.cfg @@ -0,0 +1,25 @@ +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/tools/release/kokoro-grpc-tools.bat" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} From 9257ac0ebc7fc3c78a615369d58947eb3df3854a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 11 Feb 2019 13:18:56 -0800 Subject: [PATCH 0531/1899] grpc-tools cleanup and packaging update --- packages/grpc-tools/build_binaries.ps1 | 8 +------ packages/grpc-tools/build_binaries.sh | 7 +------ packages/grpc-tools/copy_well_known_protos.js | 15 +++++++++++++ packages/grpc-tools/package.json | 9 ++++---- packages/grpc-tools/src/node_generator.cc | 13 +++++------- packages/grpc-tools/src/node_generator.h | 9 +------- packages/grpc-tools/src/node_plugin.cc | 21 +------------------ tools/release/kokoro/macos-grpc-tools.cfg | 2 +- 8 files changed, 30 insertions(+), 54 deletions(-) create mode 100644 packages/grpc-tools/copy_well_known_protos.js diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index bafb3e43d..7b8d49b6d 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -9,12 +9,10 @@ function MkDir-p($Path) { } } -$WellKnownProtos = "any","api","compiler/plugin","descriptor","duration","empty","field_mask","source_context","struct","timestamp","type","wrappers" - $Base = $PSScriptRoot cd $Base $ProtobufBase = $Base + "/deps/protobuf" -MkDir-p ($Base + "/build/bin/google/protobuf/compiler") +MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" $ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-Member -Name version @@ -22,10 +20,6 @@ $ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-M $OutDir = $Env:ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir -foreach ($Proto in $WellKnownProtos) { - Copy-Item ($ProtobufBase + "/src/google/protobuf/" + $Proto + ".proto") -Destination ($Base + "/build/bin/google/protobuf/" + $Proto + ".proto") -} - $ArchList = "ia32","x64" foreach ($Arch in $ArchList) { diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index 60045d175..52b19f5c7 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -2,8 +2,6 @@ set -e -well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers ) - cd $(dirname $0) base=$(pwd) protobuf_base=$base/deps/protobuf @@ -13,10 +11,7 @@ tools_version=$(jq '.version' < package.json | tr -d '"') out_dir=$ARTIFACTS_OUT/grpc-tools/v$tools_version mkdir -p "$out_dir" -mkdir -p "$base/build/bin/google/protobuf/compiler" -for proto in "${well_known_protos[@]}"; do - cp "$protobuf_base/src/google/protobuf/$proto.proto" "$base/build/bin/google/protobuf/$proto.proto" -done +mkdir -p "$base/build/bin" case $(uname -s) in Linux) diff --git a/packages/grpc-tools/copy_well_known_protos.js b/packages/grpc-tools/copy_well_known_protos.js new file mode 100644 index 000000000..9233423b5 --- /dev/null +++ b/packages/grpc-tools/copy_well_known_protos.js @@ -0,0 +1,15 @@ +'use strict'; + +const path = require('path'); +const fs = require('fs'); + +const sourceDir = path.join(__dirname, 'deps/protobuf/src/google/protobuf'); +const destDir = path.join(__dirname, 'bin/google/protobuf'); + +fs.mkdirSync(path.join(destDir, 'compiler'), {recursive: true}); + +const wellKnownProtos=['any', 'api', 'compiler/plugin', 'descriptor', 'duration', 'empty', + 'field_mask', 'source_context', 'struct', 'timestamp', 'type', 'wrappers']; +for (const proto of wellKnownProtos) { + fs.copyFileSync(path.join(sourceDir, proto + '.proto'), path.join(destDir, proto + '.proto')); +} \ No newline at end of file diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index c1062c10a..192759e63 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.7.0-pre1", + "version": "1.7.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", @@ -20,13 +20,14 @@ "grpc_tools_node_protoc_plugin": "./bin/protoc_plugin.js" }, "scripts": { - "install": "./node_modules/.bin/node-pre-gyp install" + "install": "./node_modules/.bin/node-pre-gyp install", + "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, "bundledDependencies": ["node-pre-gyp"], "binary": { "module_name": "grpc_tools", - "host": "https://storage.googleapis.com/", - "remote_path": "grpc-precompiled-binaries/node/{name}/v{version}", + "host": "https://node-precompiled-binaries.grpc.io/", + "remote_path": "{name}/v{version}", "package_name": "{platform}-{arch}.tar.gz", "module_path": "bin" }, diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index c4245405c..aa4901145 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -120,8 +120,7 @@ grpc::string NodeObjectPath(const Descriptor* descriptor) { } // Prints out the message serializer and deserializer functions -void PrintMessageTransformer(const Descriptor* descriptor, Printer* out, - const Parameters& params) { +void PrintMessageTransformer(const Descriptor* descriptor, Printer* out) { map template_vars; grpc::string full_name = descriptor->full_name(); template_vars["identifier_name"] = MessageIdentifierName(full_name); @@ -221,13 +220,12 @@ void PrintImports(const FileDescriptor* file, Printer* out) { out->Print("\n"); } -void PrintTransformers(const FileDescriptor* file, Printer* out, - const Parameters& params) { +void PrintTransformers(const FileDescriptor* file, Printer* out) { map messages = GetAllMessages(file); for (std::map::iterator it = messages.begin(); it != messages.end(); it++) { - PrintMessageTransformer(it->second, out, params); + PrintMessageTransformer(it->second, out); } out->Print("\n"); } @@ -239,8 +237,7 @@ void PrintServices(const FileDescriptor* file, Printer* out) { } } // namespace -grpc::string GenerateFile(const FileDescriptor* file, - const Parameters& params) { +grpc::string GenerateFile(const FileDescriptor* file) { grpc::string output; { StringOutputStream output_stream(&output); @@ -262,7 +259,7 @@ grpc::string GenerateFile(const FileDescriptor* file, PrintImports(file, &out); - PrintTransformers(file, &out, params); + PrintTransformers(file, &out); PrintServices(file, &out); diff --git a/packages/grpc-tools/src/node_generator.h b/packages/grpc-tools/src/node_generator.h index 6070e8a8c..ce7b8a3f1 100644 --- a/packages/grpc-tools/src/node_generator.h +++ b/packages/grpc-tools/src/node_generator.h @@ -23,14 +23,7 @@ namespace grpc_node_generator { -// Contains all the parameters that are parsed from the command line. -struct Parameters { - // Sets the earliest version of nodejs that needs to be supported. - int minimum_node_version; -}; - -grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file, - const Parameters& params); +grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file); } // namespace grpc_node_generator diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index 2a8e949ed..20e65e7fc 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -36,27 +36,8 @@ class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { const grpc::string& parameter, grpc::protobuf::compiler::GeneratorContext* context, grpc::string* error) const { - grpc_node_generator::Parameters generator_parameters; - generator_parameters.minimum_node_version = 6; - if (!parameter.empty()) { - std::vector parameters_list = - grpc_generator::tokenize(parameter, ","); - for (auto parameter_string = parameters_list.begin(); - parameter_string != parameters_list.end(); parameter_string++) { - std::vector param = - grpc_generator::tokenize(*parameter_string, "="); - if (param[0] == "minimum_node_version") { - sscanf(param[1].c_str(), "%d", - &generator_parameters.minimum_node_version); - } else { - *error = grpc::string("Unknown parameter: ") + *parameter_string; - return false; - } - } - } - - grpc::string code = GenerateFile(file, generator_parameters); + grpc::string code = GenerateFile(file); if (code.size() == 0) { return true; } diff --git a/tools/release/kokoro/macos-grpc-tools.cfg b/tools/release/kokoro/macos-grpc-tools.cfg index d19b56e13..0925db77b 100644 --- a/tools/release/kokoro/macos-grpc-tools.cfg +++ b/tools/release/kokoro/macos-grpc-tools.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/tools/release/kokoro-grpc-tools.sh" -timeout_mins: 120 +timeout_mins: 60 action { define_artifacts { regex: "github/grpc-node/artifacts/**", From 74308b18901147c380a8586e696a68a065af9f1c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 11 Feb 2019 16:56:28 -0800 Subject: [PATCH 0532/1899] Update submodules in grpc-tools kokoro scripts --- tools/release/kokoro-grpc-tools.bat | 8 +++++++- tools/release/kokoro-grpc-tools.sh | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat index 38850eee8..c6df803be 100644 --- a/tools/release/kokoro-grpc-tools.bat +++ b/tools/release/kokoro-grpc-tools.bat @@ -1,5 +1,11 @@ cd /d %~dp0 cd ../.. +git submodule update --init --recursive + set ARTIFACTS_OUT=%cd%/artifacts -powershell -File ./packages/grpc-tools/build_binaries.ps1 || exit /b 1 \ No newline at end of file +powershell -File ./packages/grpc-tools/build_binaries.ps1 || goto :error +goto :EOF + +:error +exit /b 1 \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index 5cf4989fb..1930a5a64 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -4,6 +4,8 @@ base_dir=$(pwd) OS=$(uname) +git submodule update --init --recursive + case $OS in Linux) docker build -t kokoro-native-image tools/release/native From b2756d2d78b4f1d66cce93d0f76ab891ae1c5d45 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 12 Feb 2019 12:59:40 -0800 Subject: [PATCH 0533/1899] grpc-tools build script fixes part 2 --- packages/grpc-tools/build_binaries.ps1 | 13 ++++++++----- tools/release/kokoro-grpc-tools.bat | 2 ++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 7b8d49b6d..b0d92307e 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -1,3 +1,5 @@ +$ErrorActionPreference = "Stop" + Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 Install-Module -Force -Name 7Zip4Powershell @@ -28,16 +30,17 @@ foreach ($Arch in $ArchList) { } else { $Generator = "Visual Studio 14 2015" } - Remove-Item ($Base + "/build/bin/protoc.exe") - Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") - Remove-Item ($Base + "CMakeCache.txt") - Invoke-Expression "cmake ." - Invoke-Expression "cmake --build ." + & cmake . + & cmake --build . Copy-Item ($ProtobufBase + "/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") Copy-Item ($Base + "/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/windows-x64.tar.gz") + + Remove-Item ($Base + "/build/bin/protoc.exe") + Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") + Remove-Item ($Base + "CMakeCache.txt") } \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat index c6df803be..d0f7a74eb 100644 --- a/tools/release/kokoro-grpc-tools.bat +++ b/tools/release/kokoro-grpc-tools.bat @@ -3,6 +3,8 @@ cd ../.. git submodule update --init --recursive +@rem make sure msys binaries are preferred over cygwin binaries +set PATH=C:\tools\msys64\usr\bin;%PATH% set ARTIFACTS_OUT=%cd%/artifacts powershell -File ./packages/grpc-tools/build_binaries.ps1 || goto :error goto :EOF From 004d8e044a9bef2a67132b62ebe657aa7451d944 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 12 Feb 2019 16:04:29 -0800 Subject: [PATCH 0534/1899] Trying 'cmake.exe' --- packages/grpc-tools/build_binaries.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index b0d92307e..6956b0ec3 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -31,8 +31,8 @@ foreach ($Arch in $ArchList) { $Generator = "Visual Studio 14 2015" } - & cmake . - & cmake --build . + & cmake.exe . + & cmake.exe --build . Copy-Item ($ProtobufBase + "/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") Copy-Item ($Base + "/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") From 464f91a16401ffa51fc61cc5c56da782d8d37afe Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Feb 2019 10:17:35 -0800 Subject: [PATCH 0535/1899] Add env debug output --- packages/grpc-tools/build_binaries.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 6956b0ec3..c0a362cff 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -1,5 +1,8 @@ $ErrorActionPreference = "Stop" +gci env:* +ls Env: + Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 Install-Module -Force -Name 7Zip4Powershell From 8bb3f0a130bc92066753826f4e75da6a448e9d32 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Feb 2019 12:42:42 -0800 Subject: [PATCH 0536/1899] Add cmake to path --- packages/grpc-tools/build_binaries.ps1 | 5 ++--- test/kokoro-nodejs-build-test.bat | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index c0a362cff..34a38b957 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -1,12 +1,11 @@ $ErrorActionPreference = "Stop" -gci env:* -ls Env: - Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 Install-Module -Force -Name 7Zip4Powershell +$env:Path += ";C:\Program Files\CMake\bin" + function MkDir-p($Path) { $FullPath = "\\?\" + $Path if (-not (Test-Path -Path $FullPath)) { diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat index bc9872267..ac109e510 100644 --- a/test/kokoro-nodejs-build-test.bat +++ b/test/kokoro-nodejs-build-test.bat @@ -1,8 +1,8 @@ cd /d %~dp0 cd .. -call ./tools/release/kokoro-nodejs.bat || goto :error call ./tools/release/kokoro-grpc-tools.bat || goto :error +call ./tools/release/kokoro-nodejs.bat || goto :error goto :EOF From 90233c965fa68c38d0d31ff8170d3301d8e48425 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Feb 2019 15:22:48 -0800 Subject: [PATCH 0537/1899] Force plugin to link statically on Windows --- packages/grpc-tools/CMakeLists.txt | 3 +++ packages/grpc-tools/build_binaries.ps1 | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index e3deadde2..85c90dee7 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -18,6 +18,9 @@ add_executable(grpc_node_plugin src/node_plugin.cc ) +if (MSVC) + add_definitions(/MT) +endif (MSVC) target_include_directories(grpc_node_plugin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 34a38b957..f96e4b98b 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -33,8 +33,14 @@ foreach ($Arch in $ArchList) { $Generator = "Visual Studio 14 2015" } - & cmake.exe . - & cmake.exe --build . + & cmake.exe . --config Release + if ($LASTEXITCODE -ne 0) { + throw "cmake failed" + } + & cmake.exe --build . --config Release + if ($LASTEXITCODE -ne 0) { + throw "cmake build failed" + } Copy-Item ($ProtobufBase + "/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") Copy-Item ($Base + "/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") From 35c257c019fa1826ed6d1e877ee8a12f23285ba6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Feb 2019 15:58:48 -0800 Subject: [PATCH 0538/1899] Remove 'Release' config argument --- packages/grpc-tools/CMakeLists.txt | 2 +- packages/grpc-tools/build_binaries.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 85c90dee7..11d6e843d 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -19,7 +19,7 @@ add_executable(grpc_node_plugin ) if (MSVC) - add_definitions(/MT) + add_definitions(/MTd) endif (MSVC) target_include_directories(grpc_node_plugin diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index f96e4b98b..4af43784c 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -33,11 +33,11 @@ foreach ($Arch in $ArchList) { $Generator = "Visual Studio 14 2015" } - & cmake.exe . --config Release + & cmake.exe . if ($LASTEXITCODE -ne 0) { throw "cmake failed" } - & cmake.exe --build . --config Release + & cmake.exe --build . if ($LASTEXITCODE -ne 0) { throw "cmake build failed" } From 9a629f9b76c40baffeed69c61ea2ee6fec8fa039 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Feb 2019 16:22:13 -0800 Subject: [PATCH 0539/1899] Fix directory where we are searching for build output --- packages/grpc-tools/build_binaries.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 4af43784c..b551c8c2e 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -42,8 +42,8 @@ foreach ($Arch in $ArchList) { throw "cmake build failed" } - Copy-Item ($ProtobufBase + "/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") - Copy-Item ($Base + "/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") + Copy-Item ($ProtobufBase + "/Debug/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") + Copy-Item ($Base + "/Debug/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/windows-x64.tar.gz") From d879e21a4216f81b8e23341497853457d349e939 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 13 Feb 2019 16:46:18 -0800 Subject: [PATCH 0540/1899] Fix missing slash in file path --- packages/grpc-tools/build_binaries.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index b551c8c2e..1a99b99a6 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -50,5 +50,5 @@ foreach ($Arch in $ArchList) { Remove-Item ($Base + "/build/bin/protoc.exe") Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") - Remove-Item ($Base + "CMakeCache.txt") + Remove-Item ($Base + "/CMakeCache.txt") } \ No newline at end of file From efe0fb1b8f58eb6a4fc75cec662cf35cbd462d3a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Feb 2019 09:27:48 -0800 Subject: [PATCH 0541/1899] Don't move artifacts directory around --- tools/release/kokoro-nodejs.bat | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/release/kokoro-nodejs.bat b/tools/release/kokoro-nodejs.bat index 054fc72bf..d73a592ab 100644 --- a/tools/release/kokoro-nodejs.bat +++ b/tools/release/kokoro-nodejs.bat @@ -30,12 +30,11 @@ cd ..\.. git submodule update --init git submodule foreach --recursive git submodule update --init -set ARTIFACTS_OUT=artifacts +set ARTIFACTS_OUT=%cd%\artifacts cd packages\grpc-native-core call tools\run_tests\artifacts\build_artifact_node.bat || goto :error cd ..\.. -move packages\grpc-native-core\artifacts . goto :EOF :error From 2499eae233706e0e8c5d0a43a745547c42704a26 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Feb 2019 15:48:10 -0800 Subject: [PATCH 0542/1899] Final fixes for grpc-tools build for real this time --- packages/grpc-tools/build_binaries.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 1a99b99a6..bdb96a7b3 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -19,7 +19,7 @@ $ProtobufBase = $Base + "/deps/protobuf" MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" -$ToolsVersion = (Get-Content $PackageFile) -join "`n" | ConvertFrom-Json | Get-Member -Name version +$ToolsVersion = ((Get-Content $PackageFile) -join "`n" | ConvertFrom-Json).version $OutDir = $Env:ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir @@ -46,7 +46,7 @@ foreach ($Arch in $ArchList) { Copy-Item ($Base + "/Debug/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") - Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/windows-x64.tar.gz") + Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/windows-" + $Arch + ".tar.gz") Remove-Item ($Base + "/build/bin/protoc.exe") Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") From 9686679736614729d37ac7a17457f0c89120a00b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Feb 2019 16:30:55 -0800 Subject: [PATCH 0543/1899] Bump to 1.19.0-pre1 --- packages/grpc-native-core/binding.gyp | 4 ++-- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 98ad85eb0..1c11e1770 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.19.0-dev"' + 'GRPC_NODE_VERSION="1.19.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -632,7 +632,6 @@ 'deps/grpc/src/core/lib/channel/channelz_registry.cc', 'deps/grpc/src/core/lib/channel/connected_channel.cc', 'deps/grpc/src/core/lib/channel/handshaker.cc', - 'deps/grpc/src/core/lib/channel/handshaker_factory.cc', 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', 'deps/grpc/src/core/lib/channel/status_util.cc', 'deps/grpc/src/core/lib/compression/compression.cc', @@ -821,6 +820,7 @@ 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', + 'deps/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc', 'deps/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_fallback.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 4b7da8ab9..801266f7d 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 4b7da8ab961e57452b1459ce28e5f68398c62845 +Subproject commit 801266f7dc84dd7fc7d0f663a4d28762e7cfb1aa diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 0cdad4397..1d9b18b6c 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.19.0-dev", + "version": "1.19.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 4abd2adb58fa8b8762bc3233cb6908627ae14fad Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 19 Feb 2019 15:50:46 -0800 Subject: [PATCH 0544/1899] node-pre-gyp refers to Windows as 'win32' --- packages/grpc-tools/build_binaries.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index bdb96a7b3..c9e8cd0cd 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -46,7 +46,7 @@ foreach ($Arch in $ArchList) { Copy-Item ($Base + "/Debug/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") - Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/windows-" + $Arch + ".tar.gz") + Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/win32-" + $Arch + ".tar.gz") Remove-Item ($Base + "/build/bin/protoc.exe") Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") From 13ad08e9582ec0d70a0121b51a9791a5ba4dfbe9 Mon Sep 17 00:00:00 2001 From: Daniel McNally Date: Wed, 20 Feb 2019 11:28:53 -0500 Subject: [PATCH 0545/1899] Fix grpc-tools install script This allows npm to determine the path to `node-pre-gyp` for the install script from `grpc-tools` rather than specifying the path. This also brings the install script in line with the one used for the `grpc` package. --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 192759e63..f47fc8804 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -20,7 +20,7 @@ "grpc_tools_node_protoc_plugin": "./bin/protoc_plugin.js" }, "scripts": { - "install": "./node_modules/.bin/node-pre-gyp install", + "install": "node-pre-gyp install", "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, "bundledDependencies": ["node-pre-gyp"], From 72ad001d935e5dbbdf554b323fbb2cf9e5f6bd1d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Feb 2019 14:24:42 -0800 Subject: [PATCH 0546/1899] Bump grpc-tools to 1.7.1 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 192759e63..953c1f838 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.7.0", + "version": "1.7.1", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 1aaad25c528ffb6ade086442306cb81540f5a109 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Feb 2019 14:54:15 -0800 Subject: [PATCH 0547/1899] grpc-tools: Force 64 bit Linux build --- packages/grpc-tools/build_binaries.sh | 5 ++++- packages/grpc-tools/linux_64bit.toolchain.cmake | 3 +++ tools/release/kokoro-grpc-tools.sh | 2 ++ 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-tools/linux_64bit.toolchain.cmake diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index 52b19f5c7..2227e9858 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -2,6 +2,8 @@ set -e +uname -a + cd $(dirname $0) base=$(pwd) protobuf_base=$base/deps/protobuf @@ -30,7 +32,7 @@ for arch in "${arch_list[@]}"; do toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_32bit.toolchain.cmake ;; *) - toolchain_flag= + toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake ;; esac rm -f $base/build/bin/protoc @@ -39,6 +41,7 @@ for arch in "${arch_list[@]}"; do cmake $toolchain_flag . && cmake --build . --target clean && cmake --build . -- -j 12 cp -L $protobuf_base/protoc $base/build/bin/protoc cp $base/grpc_node_plugin $base/build/bin/ + file $base/build/bin/* cd $base/build tar -czf "$out_dir/$platform-$arch.tar.gz" bin/ cd $base diff --git a/packages/grpc-tools/linux_64bit.toolchain.cmake b/packages/grpc-tools/linux_64bit.toolchain.cmake new file mode 100644 index 000000000..7a9b79a45 --- /dev/null +++ b/packages/grpc-tools/linux_64bit.toolchain.cmake @@ -0,0 +1,3 @@ +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m64" CACHE STRING "c++ flags") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m64" CACHE STRING "c flags") +set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -m64" CACHE STRING "ld flags") \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index 1930a5a64..065c59514 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -6,6 +6,8 @@ OS=$(uname) git submodule update --init --recursive +uname -a + case $OS in Linux) docker build -t kokoro-native-image tools/release/native From 0a7b53e8e075d8e4662d18ace8c29fa3708cf33e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 21 Feb 2019 10:43:17 -0800 Subject: [PATCH 0548/1899] Clean more thoroughly to ensure cmake reconfigures --- packages/grpc-tools/build_binaries.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index 2227e9858..df6dc2c33 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -35,9 +35,8 @@ for arch in "${arch_list[@]}"; do toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake ;; esac - rm -f $base/build/bin/protoc - rm -f $base/build/bin/grpc_node_plugin - rm -f CMakeCache.txt + git clean -xdf + git submodule foreach --recursive git clean -xdf; cmake $toolchain_flag . && cmake --build . --target clean && cmake --build . -- -j 12 cp -L $protobuf_base/protoc $base/build/bin/protoc cp $base/grpc_node_plugin $base/build/bin/ From 7a5a284b3e5981fc67eb680da05d984ee0765b50 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 21 Feb 2019 11:47:33 -0800 Subject: [PATCH 0549/1899] grpc-tools: Recreate intermediate directory after cleaning --- packages/grpc-tools/build_binaries.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index df6dc2c33..8e284da93 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -10,11 +10,10 @@ protobuf_base=$base/deps/protobuf tools_version=$(jq '.version' < package.json | tr -d '"') +# Note: $ARTIFACTS_OUT should not be in this directory out_dir=$ARTIFACTS_OUT/grpc-tools/v$tools_version mkdir -p "$out_dir" -mkdir -p "$base/build/bin" - case $(uname -s) in Linux) platform=linux @@ -38,6 +37,7 @@ for arch in "${arch_list[@]}"; do git clean -xdf git submodule foreach --recursive git clean -xdf; cmake $toolchain_flag . && cmake --build . --target clean && cmake --build . -- -j 12 + mkdir -p "$base/build/bin" cp -L $protobuf_base/protoc $base/build/bin/protoc cp $base/grpc_node_plugin $base/build/bin/ file $base/build/bin/* From 1ea43b5a403b9da2c8b59408a6d4f8499c6b0eba Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 21 Feb 2019 13:56:06 -0800 Subject: [PATCH 0550/1899] grpc-tools: Clean cmake files explicitly without git --- packages/grpc-tools/build_binaries.sh | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index 8e284da93..fa50f1949 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -34,8 +34,12 @@ for arch in "${arch_list[@]}"; do toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake ;; esac - git clean -xdf - git submodule foreach --recursive git clean -xdf; + rm -f $base/build/bin/protoc + rm -f $base/build/bin/grpc_node_plugin + rm -f $base/CMakeCache.txt + rm -rf $base/CMakeFiles + rm -f $protobuf_base/CMakeCache.txt + rm -rf $protobuf_base/CMakeFiles cmake $toolchain_flag . && cmake --build . --target clean && cmake --build . -- -j 12 mkdir -p "$base/build/bin" cp -L $protobuf_base/protoc $base/build/bin/protoc From 55cc69c4519867ffa968b821ebe200844de714ae Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 26 Feb 2019 17:01:01 -0800 Subject: [PATCH 0551/1899] Bump to v1.19.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 1c11e1770..c6dbe8606 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.19.0-pre1"' + 'GRPC_NODE_VERSION="1.19.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 801266f7d..da76faf2b 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 801266f7dc84dd7fc7d0f663a4d28762e7cfb1aa +Subproject commit da76faf2b882ba1e07bd52379bfb8eba8354155c diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 1d9b18b6c..439cc68a7 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.19.0-pre1", + "version": "1.19.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 42126732f590a65a3f6c6b806b5bb82cb419f0ae Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 27 Feb 2019 10:14:25 -0500 Subject: [PATCH 0552/1899] grpc-js: remove unused EventEmitter interfaces This commit removes the unused EmitterAugmentation0 and EmitterAugmentation2 interfaces. --- packages/grpc-js/src/events.ts | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/packages/grpc-js/src/events.ts b/packages/grpc-js/src/events.ts index ad96efd57..976e9b7b7 100644 --- a/packages/grpc-js/src/events.ts +++ b/packages/grpc-js/src/events.ts @@ -1,13 +1,3 @@ -export interface EmitterAugmentation0 { - addListener(event: Name, listener: () => void): this; - emit(event: Name): boolean; - on(event: Name, listener: () => void): this; - once(event: Name, listener: () => void): this; - prependListener(event: Name, listener: () => void): this; - prependOnceListener(event: Name, listener: () => void): this; - removeListener(event: Name, listener: () => void): this; -} - export interface EmitterAugmentation1 { addListener(event: Name, listener: (arg1: Arg) => void): this; emit(event: Name, arg1: Arg): boolean; @@ -17,15 +7,3 @@ export interface EmitterAugmentation1 { prependOnceListener(event: Name, listener: (arg1: Arg) => void): this; removeListener(event: Name, listener: (arg1: Arg) => void): this; } - -export interface EmitterAugmentation2 { - addListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; - emit(event: Name, arg1: Arg1, arg2: Arg2): boolean; - on(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; - once(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; - prependListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): - this; - prependOnceListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): - this; - removeListener(event: Name, listener: (arg1: Arg1, arg2: Arg2) => void): this; -} From 31a5fc2eb6b51d0279d4edb5a6a7676cf2982a02 Mon Sep 17 00:00:00 2001 From: johnjbarton Date: Fri, 1 Mar 2019 16:17:53 -0800 Subject: [PATCH 0553/1899] Add LICENSE file from project root. Lawyers want to see the LICENSE. --- packages/grpc-js/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4d87085f1..b2ed0573c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -45,6 +45,7 @@ "semver": "^5.5.0" }, "files": [ - "build/src/*.{js,d.ts}" + "build/src/*.{js,d.ts}", + "LICENSE" ] } From a365f66c6a67734675a81f2c8e19fb0d5e53cc9f Mon Sep 17 00:00:00 2001 From: johnjbarton Date: Tue, 5 Mar 2019 08:17:50 -0800 Subject: [PATCH 0554/1899] Add LICENSE from http://www.apache.org/licenses/LICENSE-2.0.txt --- packages/grpc-js/LICENSE | 202 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 packages/grpc-js/LICENSE diff --git a/packages/grpc-js/LICENSE b/packages/grpc-js/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/packages/grpc-js/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From a14e7bcba0f7a4c8b27aabde77094df865ea8f46 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 5 Mar 2019 15:27:37 -0800 Subject: [PATCH 0555/1899] Update typescript version to 3.3 --- packages/grpc-js/package.json | 2 +- packages/proto-loader/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4d87085f1..26115912f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -21,7 +21,7 @@ "clang-format": "^1.0.55", "gts": "^0.5.1", "lodash": "^4.17.4", - "typescript": "~2.7.0" + "typescript": "~3.3.3333" }, "contributors": [ { diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 08e5807da..83a8e7364 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -46,7 +46,7 @@ "@types/node": "^10.12.5", "clang-format": "^1.2.2", "gts": "^0.5.3", - "typescript": "~2.7.2" + "typescript": "~3.3.3333" }, "engines": { "node": ">=6" From 3d597420a4272acdbc53734c5afa781cb3ddfc61 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Mar 2019 10:37:43 -0800 Subject: [PATCH 0556/1899] Add missing license files to package directories --- LICENSE | 2 +- packages/grpc-health-check/LICENSE | 21 ++- packages/grpc-js/LICENSE | 5 +- packages/grpc-native-core/LICENSE | 201 +++++++++++++++++++++++++++++ packages/grpc-tools/LICENSE | 201 +++++++++++++++++++++++++++++ packages/proto-loader/LICENSE | 201 +++++++++++++++++++++++++++++ packages/proto-loader/package.json | 1 + 7 files changed, 625 insertions(+), 7 deletions(-) create mode 100644 packages/grpc-native-core/LICENSE create mode 100644 packages/grpc-tools/LICENSE create mode 100644 packages/proto-loader/LICENSE diff --git a/LICENSE b/LICENSE index 8dada3eda..0c6e1d701 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2019 gRPC authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-health-check/LICENSE b/packages/grpc-health-check/LICENSE index 7750ce4fd..0c6e1d701 100644 --- a/packages/grpc-health-check/LICENSE +++ b/packages/grpc-health-check/LICENSE @@ -1,13 +1,13 @@ - Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. @@ -86,6 +86,7 @@ granted to You under this License for that Work shall terminate as of the date such litigation is filed. + 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: @@ -103,6 +104,7 @@ the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one @@ -120,7 +122,9 @@ You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, @@ -171,7 +175,18 @@ END OF TERMS AND CONDITIONS - Copyright 2015-2017 gRPC authors. + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 gRPC authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-js/LICENSE b/packages/grpc-js/LICENSE index d64569567..0c6e1d701 100644 --- a/packages/grpc-js/LICENSE +++ b/packages/grpc-js/LICENSE @@ -1,4 +1,3 @@ - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -179,7 +178,7 @@ APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" + boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a @@ -187,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright 2019 gRPC authors Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-native-core/LICENSE b/packages/grpc-native-core/LICENSE new file mode 100644 index 000000000..0c6e1d701 --- /dev/null +++ b/packages/grpc-native-core/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 gRPC authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/grpc-tools/LICENSE b/packages/grpc-tools/LICENSE new file mode 100644 index 000000000..0c6e1d701 --- /dev/null +++ b/packages/grpc-tools/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 gRPC authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/proto-loader/LICENSE b/packages/proto-loader/LICENSE new file mode 100644 index 000000000..0c6e1d701 --- /dev/null +++ b/packages/proto-loader/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2019 gRPC authors + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 83a8e7364..e22b31438 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -34,6 +34,7 @@ "url": "https://github.com/grpc/grpc-node/issues" }, "files": [ + "LICENSE", "build/src/*.d.ts", "build/src/*.js" ], From 1395444a04ddd27f77c69ed9121a916b9a270174 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Mar 2019 11:01:44 -0800 Subject: [PATCH 0557/1899] Don't fill in any templates in LICENSE files --- LICENSE | 2 +- packages/grpc-health-check/LICENSE | 2 +- packages/grpc-js/LICENSE | 2 +- packages/grpc-native-core/LICENSE | 2 +- packages/grpc-tools/LICENSE | 2 +- packages/proto-loader/LICENSE | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index 0c6e1d701..8dada3eda 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 gRPC authors + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-health-check/LICENSE b/packages/grpc-health-check/LICENSE index 0c6e1d701..8dada3eda 100644 --- a/packages/grpc-health-check/LICENSE +++ b/packages/grpc-health-check/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 gRPC authors + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-js/LICENSE b/packages/grpc-js/LICENSE index 0c6e1d701..8dada3eda 100644 --- a/packages/grpc-js/LICENSE +++ b/packages/grpc-js/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 gRPC authors + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-native-core/LICENSE b/packages/grpc-native-core/LICENSE index 0c6e1d701..8dada3eda 100644 --- a/packages/grpc-native-core/LICENSE +++ b/packages/grpc-native-core/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 gRPC authors + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/grpc-tools/LICENSE b/packages/grpc-tools/LICENSE index 0c6e1d701..8dada3eda 100644 --- a/packages/grpc-tools/LICENSE +++ b/packages/grpc-tools/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 gRPC authors + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/packages/proto-loader/LICENSE b/packages/proto-loader/LICENSE index 0c6e1d701..8dada3eda 100644 --- a/packages/proto-loader/LICENSE +++ b/packages/proto-loader/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2019 gRPC authors + Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 030f846c3adc0ad35999e3d484aee9bdcac15ec9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Mar 2019 17:31:30 -0800 Subject: [PATCH 0558/1899] grpc-js: call-stream: Don't output messages after status --- packages/grpc-js/src/call-stream.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 840d7f2bc..988717c90 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -128,6 +128,11 @@ export class Http2CallStream extends Duplex implements Call { } private handleFilteredRead(message: Buffer) { + /* If we the call has already ended, we don't want to do anything with + * this message. Dropping it on the floor is correct behavior */ + if (this.finalStatus !== null) { + return; + } this.isReadFilterPending = false; if (this.canPush) { if (!this.push(message)) { @@ -146,6 +151,11 @@ export class Http2CallStream extends Duplex implements Call { } private filterReceivedMessage(framedMessage: Buffer|null) { + /* If we the call has already ended, we don't want to do anything with + * this message. Dropping it on the floor is correct behavior */ + if (this.finalStatus !== null) { + return; + } if (framedMessage === null) { if (this.canPush) { this.push(null); @@ -432,6 +442,12 @@ export class Http2CallStream extends Duplex implements Call { } _read(size: number) { + /* If we have already emitted a status, we should not emit any more + * messages and we should communicate that the stream has ended */ + if (this.finalStatus !== null) { + this.push(null); + return; + } this.canPush = true; if (this.http2Stream === null) { this.pendingRead = true; From d77da2602149f5f3e74d6db4fbf0f8ff5fc4778d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Mar 2019 11:02:20 -0800 Subject: [PATCH 0559/1899] grpc-js: deadline filter: reject promise if call ends --- packages/grpc-js/src/deadline-filter.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index fd52ebbcb..4ca409c11 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -62,7 +62,13 @@ export class DeadlineFilter extends BaseFilter implements Filter { 'connectivityStateChanged', handleStateChange); } }; + const handleStatus = () => { + reject(new Error('Call ended')); + this.channel.removeListener( + 'connectivityStateChanged', handleStateChange); + }; this.channel.on('connectivityStateChanged', handleStateChange); + this.callStream.once('status', handleStatus); } }) .then((finalMetadata: Metadata) => { From b0f06d56c29f12a5037fb2370682e2d8d4750f78 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Mar 2019 11:24:22 -0800 Subject: [PATCH 0560/1899] Properly remove event listener in other handler --- packages/grpc-js/src/deadline-filter.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 4ca409c11..8e21813e6 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -60,6 +60,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { resolve(metadata); this.channel.removeListener( 'connectivityStateChanged', handleStateChange); + this.callStream.removeListener('status', handleStatus); } }; const handleStatus = () => { From 0cf6981eafb7ec1ecd4b9fe3b32b621cb1a5cfab Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Mar 2019 15:41:12 -0800 Subject: [PATCH 0561/1899] Start with http2 sessions unrefed in case no streams are ever created --- packages/grpc-js/src/subchannel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 13612a883..6ec7da207 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -46,6 +46,7 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { userAgent: string, channelArgs: Partial) { super(); this.session = http2.connect(target, connectionOptions); + this.session.unref(); this.session.on('connect', () => { this.emit('connect'); }); From d1bfa92b321b4631e74c19fbaa04522eab6330fb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Mar 2019 17:31:46 -0800 Subject: [PATCH 0562/1899] Bump grpc-js to 0.3.6 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0d6a51f5d..539108059 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.5", + "version": "0.3.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 5baa8a12a54e042fc0bd64902ab82262ecb4ef9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilari=20M=C3=A4kimattila?= Date: Wed, 13 Mar 2019 14:44:09 +0100 Subject: [PATCH 0563/1899] Make node-pre-gyp a regular dependency --- packages/grpc-tools/package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 3315d14a2..07e9894b4 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -23,7 +23,9 @@ "install": "node-pre-gyp install", "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, - "bundledDependencies": ["node-pre-gyp"], + "dependencies": { + "node-pre-gyp": "^0.12.0" + }, "binary": { "module_name": "grpc_tools", "host": "https://node-precompiled-binaries.grpc.io/", From fee09c623fde44184b96eaf9dff851e34037e098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ilari=20M=C3=A4kimattila?= Date: Wed, 13 Mar 2019 17:45:43 +0100 Subject: [PATCH 0564/1899] Restore node-pre-gyp bundled dependency --- packages/grpc-tools/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 07e9894b4..3e6c780c2 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -23,6 +23,7 @@ "install": "node-pre-gyp install", "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, + "bundledDependencies": ["node-pre-gyp"], "dependencies": { "node-pre-gyp": "^0.12.0" }, From 2dd31d0fe886888c593cec18b80611d27cf57b56 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 14 Mar 2019 18:58:17 +0100 Subject: [PATCH 0565/1899] Removing support for Electron 4.0 and adding support for Electron 4.1. --- packages/grpc-native-core/deps/grpc | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index da76faf2b..007b721f8 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit da76faf2b882ba1e07bd52379bfb8eba8354155c +Subproject commit 007b721f8045ceef4ebf418a2935ab772fbe3708 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 2fe46fda0..3123d6032 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.1.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index a676c5f85..aca001478 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.1.0 ) umask 022 From f9f4e63c461f5c6c77d15c3a212cbb9b8a7b474e Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 14 Mar 2019 19:15:16 +0100 Subject: [PATCH 0566/1899] Actually, 3.1 needs building too. --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 3123d6032..1575b7cea 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.1.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index aca001478..7d1281273 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 4.1.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 ) umask 022 From e411999c91bdad40597cde74c4f5d6d5ac699171 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Mar 2019 13:11:51 -0700 Subject: [PATCH 0567/1899] Update top level typescript dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6df12d772..1ec8cc2cc 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", - "typescript": "~2.7.0", + "typescript": "~3.3.3333", "xml2js": "^0.4.19" }, "contributors": [ From 811e95ace0f2743a13f4db9d2a92ceb184eaebb7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Thu, 14 Mar 2019 23:58:21 +0100 Subject: [PATCH 0568/1899] Don't update the submodule. --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 007b721f8..da76faf2b 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 007b721f8045ceef4ebf418a2935ab772fbe3708 +Subproject commit da76faf2b882ba1e07bd52379bfb8eba8354155c From edddfcb8b11dd4f4456281c7e73fd58dd929d40a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Mar 2019 16:44:51 -0700 Subject: [PATCH 0569/1899] Update top level typescript dependency (attempt 2) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6df12d772..1ec8cc2cc 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "through2": "^2.0.3", "ts-node": "^3.3.0", "tslint": "^5.5.0", - "typescript": "~2.7.0", + "typescript": "~3.3.3333", "xml2js": "^0.4.19" }, "contributors": [ From c520d5befafcfa50058c7aad04fc710d30624e7b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Mar 2019 11:32:11 -0700 Subject: [PATCH 0570/1899] Export missing types, fix a couple of incorrect types --- packages/grpc-js/src/client.ts | 11 ++++---- packages/grpc-js/src/index.ts | 47 ++++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 7381f4da9..981d1c870 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -18,7 +18,8 @@ export interface UnaryCallback { export interface CallOptions { deadline?: Deadline; host?: string; - parent?: Call; + /* There should be a parent option here that will accept a server call, + * but the server is not yet implemented so it makes no sense to have it */ propagate_flags?: number; credentials?: CallCredentials; } @@ -171,7 +172,7 @@ export class Client { this.checkOptionalUnaryResponseArguments( metadata, options, callback)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, options.parent, + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); @@ -213,7 +214,7 @@ export class Client { this.checkOptionalUnaryResponseArguments( metadata, options, callback)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, options.parent, + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); @@ -262,7 +263,7 @@ export class Client { options?: CallOptions): ClientReadableStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, options.parent, + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); @@ -290,7 +291,7 @@ export class Client { options?: CallOptions): ClientDuplexStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, options.parent, + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 1208dc4b6..11cf47083 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -1,14 +1,16 @@ import * as semver from 'semver'; import {CallCredentials} from './call-credentials'; -import {Channel} from './channel'; +import {Channel, Http2Channel, ConnectivityState} from './channel'; import {ChannelCredentials} from './channel-credentials'; -import {Client} from './client'; +import {Client, CallOptions} from './client'; import {LogVerbosity, Status} from './constants'; import * as logging from './logging'; -import {loadPackageDefinition, makeClientConstructor} from './make-client'; +import {loadPackageDefinition, makeClientConstructor, Serialize, Deserialize} from './make-client'; import {Metadata} from './metadata'; import {StatusBuilder} from './status-builder'; +import { Deadline, StatusObject } from './call-stream'; +import { ClientUnaryCall, ClientReadableStream, ClientWritableStream, ClientDuplexStream } from './call'; const supportedNodeVersions = '^8.11.2 || >=9.4'; if (!semver.satisfies(process.version, supportedNodeVersions)) { @@ -121,7 +123,8 @@ export {Metadata}; export { LogVerbosity as logVerbosity, - Status as status + Status as status, + ConnectivityState as connectivityState // TODO: Other constants as well }; @@ -132,7 +135,7 @@ export { loadPackageDefinition, makeClientConstructor, makeClientConstructor as makeGenericClientConstructor, - Channel + Http2Channel as Channel }; /** @@ -146,6 +149,40 @@ export const waitForClientReady = callback: (error?: Error) => void) => client.waitForReady(deadline, callback); +/* Interfaces */ + +export { + ChannelCredentials, + CallCredentials, + Deadline, + Serialize as serialize, + Deserialize as deserialize, + ClientUnaryCall, + ClientReadableStream, + ClientWritableStream, + ClientDuplexStream, + CallOptions, + StatusObject +} + +export type Call = + ClientUnaryCall | + ClientReadableStream | + ClientWritableStream | + ClientDuplexStream; + +export type MetadataListener = (metadata: Metadata, next: Function) => void; + +export type MessageListener = (message: any, next: Function) => void; + +export type StatusListener = (status: StatusObject, next: Function) => void; + +export interface Listener { + onReceiveMetadata?: MetadataListener; + onReceiveMessage?: MessageListener; + onReceiveStatus?: StatusListener; +} + /**** Unimplemented function stubs ****/ /* tslint:disable:no-any variable-name */ From e0a472d9dfe12d8279c1a045b8258edc66149cc1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Mar 2019 12:09:19 -0700 Subject: [PATCH 0571/1899] Fix lint errors --- packages/grpc-js/src/client.ts | 12 ++++-------- packages/grpc-js/src/index.ts | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 981d1c870..a9b990416 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -172,8 +172,7 @@ export class Client { this.checkOptionalUnaryResponseArguments( metadata, options, callback)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, null, - options.propagate_flags); + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } @@ -214,8 +213,7 @@ export class Client { this.checkOptionalUnaryResponseArguments( metadata, options, callback)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, null, - options.propagate_flags); + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } @@ -263,8 +261,7 @@ export class Client { options?: CallOptions): ClientReadableStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, null, - options.propagate_flags); + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } @@ -291,8 +288,7 @@ export class Client { options?: CallOptions): ClientDuplexStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); const call: Call = this[kChannel].createCall( - method, options.deadline, options.host, null, - options.propagate_flags); + method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 11cf47083..d1125c385 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -1,16 +1,16 @@ import * as semver from 'semver'; +import {ClientDuplexStream, ClientReadableStream, ClientUnaryCall, ClientWritableStream} from './call'; import {CallCredentials} from './call-credentials'; -import {Channel, Http2Channel, ConnectivityState} from './channel'; +import {Deadline, StatusObject} from './call-stream'; +import {Channel, ConnectivityState, Http2Channel} from './channel'; import {ChannelCredentials} from './channel-credentials'; -import {Client, CallOptions} from './client'; +import {CallOptions, Client} from './client'; import {LogVerbosity, Status} from './constants'; import * as logging from './logging'; -import {loadPackageDefinition, makeClientConstructor, Serialize, Deserialize} from './make-client'; +import {Deserialize, loadPackageDefinition, makeClientConstructor, Serialize} from './make-client'; import {Metadata} from './metadata'; import {StatusBuilder} from './status-builder'; -import { Deadline, StatusObject } from './call-stream'; -import { ClientUnaryCall, ClientReadableStream, ClientWritableStream, ClientDuplexStream } from './call'; const supportedNodeVersions = '^8.11.2 || >=9.4'; if (!semver.satisfies(process.version, supportedNodeVersions)) { @@ -163,16 +163,16 @@ export { ClientDuplexStream, CallOptions, StatusObject -} +}; -export type Call = - ClientUnaryCall | - ClientReadableStream | - ClientWritableStream | - ClientDuplexStream; +/* tslint:disable:no-any */ +export type Call = ClientUnaryCall|ClientReadableStream| + ClientWritableStream|ClientDuplexStream; +/* tslint:enable:no-any */ export type MetadataListener = (metadata: Metadata, next: Function) => void; +// tslint:disable-next-line:no-any export type MessageListener = (message: any, next: Function) => void; export type StatusListener = (status: StatusObject, next: Function) => void; From 94f923360f5a568069ae466c516dc3496826696a Mon Sep 17 00:00:00 2001 From: daikiojm Date: Mon, 18 Mar 2019 09:24:30 +0900 Subject: [PATCH 0572/1899] docs(readme): add packages directory link --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2c295e315..9ff1bcad0 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,7 @@ This library loads `.proto` files into objects that can be passed to the gRPC li ### gRPC Tools -Directory: `packages/grpc-tools` +Directory: [`packages/grpc-tools`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-tools) npm package: [grpc-tools](https://www.npmjs.com/package/grpc-tools) @@ -43,7 +43,7 @@ Distribution of protoc and the gRPC Node protoc plugin for ease of installation ### gRPC Health Check Service -Directory: `packages/grpc-health-check` +Directory: [`packages/grpc-health-check`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-health-check) npm package: [grpc-health-check](https://www.npmjs.com/package/grpc-health-check) From 6bc7184542ce166833bb4ef3502fd3571b1ce79f Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 19 Mar 2019 01:06:57 +0100 Subject: [PATCH 0573/1899] Adding missing license on a bunch of source files. --- packages/grpc-js/src/call-credentials-filter.ts | 17 +++++++++++++++++ packages/grpc-js/src/call-credentials.ts | 17 +++++++++++++++++ packages/grpc-js/src/call-stream.ts | 17 +++++++++++++++++ packages/grpc-js/src/call.ts | 17 +++++++++++++++++ packages/grpc-js/src/channel-credentials.ts | 17 +++++++++++++++++ packages/grpc-js/src/channel-options.ts | 17 +++++++++++++++++ packages/grpc-js/src/channel.ts | 17 +++++++++++++++++ packages/grpc-js/src/client.ts | 17 +++++++++++++++++ packages/grpc-js/src/compression-filter.ts | 17 +++++++++++++++++ packages/grpc-js/src/constants.ts | 17 +++++++++++++++++ packages/grpc-js/src/deadline-filter.ts | 17 +++++++++++++++++ packages/grpc-js/src/events.ts | 17 +++++++++++++++++ packages/grpc-js/src/filter-stack.ts | 17 +++++++++++++++++ packages/grpc-js/src/filter.ts | 17 +++++++++++++++++ packages/grpc-js/src/index.ts | 17 +++++++++++++++++ packages/grpc-js/src/logging.ts | 17 +++++++++++++++++ packages/grpc-js/src/make-client.ts | 17 +++++++++++++++++ packages/grpc-js/src/metadata-status-filter.ts | 17 +++++++++++++++++ packages/grpc-js/src/metadata.ts | 17 +++++++++++++++++ packages/grpc-js/src/object-stream.ts | 17 +++++++++++++++++ packages/grpc-js/src/status-builder.ts | 17 +++++++++++++++++ packages/grpc-js/src/subchannel.ts | 17 +++++++++++++++++ packages/grpc-js/test/common.ts | 17 +++++++++++++++++ packages/grpc-js/test/test-call-credentials.ts | 17 +++++++++++++++++ packages/grpc-js/test/test-call-stream.ts | 17 +++++++++++++++++ .../grpc-js/test/test-channel-credentials.ts | 17 +++++++++++++++++ packages/grpc-js/test/test-logging.ts | 17 +++++++++++++++++ packages/grpc-js/test/test-metadata.ts | 17 +++++++++++++++++ packages/grpc-js/test/test-status-builder.ts | 17 +++++++++++++++++ packages/grpc-native-core/index.d.ts | 17 +++++++++++++++++ packages/grpc-tools/build_binaries.ps1 | 16 ++++++++++++++++ packages/grpc-tools/build_binaries.sh | 13 +++++++++++++ packages/grpc-tools/copy_well_known_protos.js | 17 +++++++++++++++++ .../proto-loader/test/descriptor_type_test.ts | 17 +++++++++++++++++ test/any_grpc.js | 17 +++++++++++++++++ test/api/error_test.js | 17 +++++++++++++++++ test/client-libraries-integration/init.sh | 13 +++++++++++++ .../client-libraries-integration/use-grpc-js.js | 17 +++++++++++++++++ test/fixtures/js_js.js | 17 +++++++++++++++++ test/fixtures/js_native.js | 17 +++++++++++++++++ test/fixtures/native_js.js | 17 +++++++++++++++++ test/fixtures/native_native.js | 17 +++++++++++++++++ test/kokoro-nodejs-build-test.bat | 14 ++++++++++++++ test/kokoro-nodejs-build-test.sh | 15 +++++++++++++++ tools/release/kokoro-grpc-tools.bat | 14 ++++++++++++++ tools/release/kokoro-grpc-tools.sh | 15 +++++++++++++++ util.js | 17 +++++++++++++++++ 47 files changed, 780 insertions(+) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index b9f1d6bf2..10ab4958e 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {CallCredentials} from './call-credentials'; import {Call} from './call-stream'; import {Http2Channel} from './channel'; diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index 212d49b27..24f9bb3aa 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {Metadata} from './metadata'; export type CallMetadataOptions = { diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 988717c90..c987d9320 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as http2 from 'http2'; import {Duplex} from 'stream'; diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index cfe68b273..f0b23a7eb 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {EventEmitter} from 'events'; import {Duplex, Readable, Writable} from 'stream'; diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index b2c73efa9..9f411b212 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {ConnectionOptions, createSecureContext, PeerCertificate} from 'tls'; import {CallCredentials} from './call-credentials'; diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 434911662..54e68f4c3 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + /** * An interface that contains options used when initializing a Channel instance. */ diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index bbadb5c62..52a22e6e6 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {EventEmitter} from 'events'; import * as http2 from 'http2'; import {checkServerIdentity, PeerCertificate} from 'tls'; diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 7381f4da9..5081e2bf3 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; import {CallCredentials} from './call-credentials'; import {Call, Deadline, StatusObject, WriteObject} from './call-stream'; diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 24d513dc4..cf695e5af 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as zlib from 'zlib'; import {Call, WriteFlags, WriteObject} from './call-stream'; diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index 0a0142ec9..92c0ebfa4 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + export enum Status { OK = 0, CANCELLED, diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 8e21813e6..085623efb 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {Call} from './call-stream'; import {ConnectivityState, Http2Channel} from './channel'; import {Status} from './constants'; diff --git a/packages/grpc-js/src/events.ts b/packages/grpc-js/src/events.ts index 976e9b7b7..d534dee3f 100644 --- a/packages/grpc-js/src/events.ts +++ b/packages/grpc-js/src/events.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + export interface EmitterAugmentation1 { addListener(event: Name, listener: (arg1: Arg) => void): this; emit(event: Name, arg1: Arg): boolean; diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 92232f4c6..8c0f1d7c5 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {Call, StatusObject, WriteObject} from './call-stream'; import {Filter, FilterFactory} from './filter'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js/src/filter.ts b/packages/grpc-js/src/filter.ts index 22c5295c9..f0bd99c61 100644 --- a/packages/grpc-js/src/filter.ts +++ b/packages/grpc-js/src/filter.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {Call, StatusObject, WriteObject} from './call-stream'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 1208dc4b6..08ba139a1 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as semver from 'semver'; import {CallCredentials} from './call-credentials'; diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index a0e4e8c52..7579296b4 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {LogVerbosity} from './constants'; let _logger: Partial = console; diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index df673aa78..244604f75 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {ChannelCredentials} from './channel-credentials'; import {ChannelOptions} from './channel-options'; import {Client} from './client'; diff --git a/packages/grpc-js/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts index 75eabea8b..171bd6cbe 100644 --- a/packages/grpc-js/src/metadata-status-filter.ts +++ b/packages/grpc-js/src/metadata-status-filter.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {Call} from './call-stream'; import {StatusObject} from './call-stream'; import {Channel} from './channel'; diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 09a6f8832..4ca87c572 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as http2 from 'http2'; const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index b298ed025..068f7a26e 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {Duplex, Readable, Writable} from 'stream'; import {EmitterAugmentation1} from './events'; diff --git a/packages/grpc-js/src/status-builder.ts b/packages/grpc-js/src/status-builder.ts index dd0859a0e..4cbf24b99 100644 --- a/packages/grpc-js/src/status-builder.ts +++ b/packages/grpc-js/src/status-builder.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {StatusObject} from './call-stream'; import {Status} from './constants'; import {Metadata} from './metadata'; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 6ec7da207..f2e11f7f6 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import {EventEmitter} from 'events'; import * as http2 from 'http2'; import * as url from 'url'; diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index c36d6fc47..1a1908e76 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; export function mockFunction(): never { diff --git a/packages/grpc-js/test/test-call-credentials.ts b/packages/grpc-js/test/test-call-credentials.ts index fffe5a196..e5b1b81a0 100644 --- a/packages/grpc-js/test/test-call-credentials.ts +++ b/packages/grpc-js/test/test-call-credentials.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import {CallCredentials, CallMetadataGenerator} from '../src/call-credentials'; diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index 194db05c3..af6ae43aa 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import {OutgoingHttpHeaders} from 'http'; import * as http2 from 'http2'; diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index f6914ef3e..7ede18075 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import * as fs from 'fs'; import {promisify} from 'util'; diff --git a/packages/grpc-js/test/test-logging.ts b/packages/grpc-js/test/test-logging.ts index 4f8f64a9d..d01c06004 100644 --- a/packages/grpc-js/test/test-logging.ts +++ b/packages/grpc-js/test/test-logging.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import * as grpc from '../src'; diff --git a/packages/grpc-js/test/test-metadata.ts b/packages/grpc-js/test/test-metadata.ts index f5e4d80cd..12d110408 100644 --- a/packages/grpc-js/test/test-metadata.ts +++ b/packages/grpc-js/test/test-metadata.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import * as http2 from 'http2'; import {range} from 'lodash'; diff --git a/packages/grpc-js/test/test-status-builder.ts b/packages/grpc-js/test/test-status-builder.ts index ce27518d8..089652792 100644 --- a/packages/grpc-js/test/test-status-builder.ts +++ b/packages/grpc-js/test/test-status-builder.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import * as grpc from '../src'; diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 808051d06..1a634164e 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + declare module "grpc" { import { Message, Service as ProtobufService } from "protobufjs"; import { Duplex, Readable, Writable } from "stream"; diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index c9e8cd0cd..8c249642e 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -1,3 +1,19 @@ +<# + Copyright 2019 gRPC authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +#> + $ErrorActionPreference = "Stop" Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index fa50f1949..2a4421835 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -1,4 +1,17 @@ #!/bin/bash +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. set -e diff --git a/packages/grpc-tools/copy_well_known_protos.js b/packages/grpc-tools/copy_well_known_protos.js index 9233423b5..d95be29bb 100644 --- a/packages/grpc-tools/copy_well_known_protos.js +++ b/packages/grpc-tools/copy_well_known_protos.js @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + 'use strict'; const path = require('path'); diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 06327e024..ae4db0142 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + import * as assert from 'assert'; import * as proto_loader from '../src/index'; diff --git a/test/any_grpc.js b/test/any_grpc.js index 7f23e4206..59962d590 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + // TODO: Instead of attempting to expose both implementations of gRPC in // a single object, the tests should be re-written in a way that makes it clear // that two separate implementations are being tested against one another. diff --git a/test/api/error_test.js b/test/api/error_test.js index b40ec197a..33965eee4 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + const options = { keepCase: true, longs: String, diff --git a/test/client-libraries-integration/init.sh b/test/client-libraries-integration/init.sh index d892cdc9f..e4814535b 100755 --- a/test/client-libraries-integration/init.sh +++ b/test/client-libraries-integration/init.sh @@ -1,4 +1,17 @@ #!/bin/bash +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. npm install diff --git a/test/client-libraries-integration/use-grpc-js.js b/test/client-libraries-integration/use-grpc-js.js index 5eff22f5f..4f73f92dd 100644 --- a/test/client-libraries-integration/use-grpc-js.js +++ b/test/client-libraries-integration/use-grpc-js.js @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + require('source-map-support/register'); const Module = require('module'); const shimmer = require('shimmer'); diff --git a/test/fixtures/js_js.js b/test/fixtures/js_js.js index 7d72dc495..bb70c450e 100644 --- a/test/fixtures/js_js.js +++ b/test/fixtures/js_js.js @@ -1,2 +1,19 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + global._server_implementation = 'js'; global._client_implementation = 'js'; diff --git a/test/fixtures/js_native.js b/test/fixtures/js_native.js index 5088df96d..88ef5bf64 100644 --- a/test/fixtures/js_native.js +++ b/test/fixtures/js_native.js @@ -1,2 +1,19 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + global._server_implementation = 'js'; global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/fixtures/native_js.js b/test/fixtures/native_js.js index 3da4106ec..89262636a 100644 --- a/test/fixtures/native_js.js +++ b/test/fixtures/native_js.js @@ -1,2 +1,19 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + global._server_implementation = 'native'; global._client_implementation = 'js'; diff --git a/test/fixtures/native_native.js b/test/fixtures/native_native.js index 5b005e485..eb6c0ba80 100644 --- a/test/fixtures/native_native.js +++ b/test/fixtures/native_native.js @@ -1,2 +1,19 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + global._server_implementation = 'native'; global._client_implementation = 'native'; \ No newline at end of file diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat index ac109e510..3f488deee 100644 --- a/test/kokoro-nodejs-build-test.bat +++ b/test/kokoro-nodejs-build-test.bat @@ -1,3 +1,17 @@ +@rem Copyright 2019 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + cd /d %~dp0 cd .. diff --git a/test/kokoro-nodejs-build-test.sh b/test/kokoro-nodejs-build-test.sh index fdb4bc74b..4b0cefca0 100755 --- a/test/kokoro-nodejs-build-test.sh +++ b/test/kokoro-nodejs-build-test.sh @@ -1,3 +1,18 @@ +#!/bin/bash +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + set -e cd $(dirname $0)/.. base_dir=$(pwd) diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat index d0f7a74eb..6b1e2fb48 100644 --- a/tools/release/kokoro-grpc-tools.bat +++ b/tools/release/kokoro-grpc-tools.bat @@ -1,3 +1,17 @@ +@rem Copyright 2019 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + cd /d %~dp0 cd ../.. diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index 065c59514..b672c0cb1 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -1,3 +1,18 @@ +#!/bin/bash +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + set -e cd $(dirname $0)/../.. base_dir=$(pwd) diff --git a/util.js b/util.js index d91933474..cd0464bd9 100644 --- a/util.js +++ b/util.js @@ -1,3 +1,20 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + const path = require('path'); const del = require('del'); const fs = require('fs'); From 1d7ed8167aeb6b77c67d4ac13ed515bec84b3096 Mon Sep 17 00:00:00 2001 From: raunaqrox Date: Wed, 20 Mar 2019 23:09:25 +0530 Subject: [PATCH 0574/1899] isArray instead of instanceof for consistent checking --- packages/proto-loader/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 9b8704c29..a3554f75c 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -269,7 +269,7 @@ export function load(filename: string, options?: Options): Promise Date: Wed, 20 Mar 2019 23:12:02 +0530 Subject: [PATCH 0575/1899] Fix typo in error message --- packages/proto-loader/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index a3554f75c..2e1a2b842 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -285,7 +285,7 @@ export function loadSync(filename: string, options?: Options): PackageDefinition options = options || {}; if (!!options.includeDirs) { if (!(Array.isArray(options.includeDirs))) { - throw new Error('The include option must be an array'); + throw new Error('The includeDirs option must be an array'); } addIncludePathResolver(root, options.includeDirs as string[]); } From fe090a089a6cee9c365b0b38f947c2ebc2d1cfe1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Mar 2019 14:59:16 -0700 Subject: [PATCH 0576/1899] Native: Add initial metadata options --- packages/grpc-native-core/ext/call.cc | 26 ++++++- packages/grpc-native-core/index.d.ts | 27 +++++++ packages/grpc-native-core/src/metadata.js | 78 +++++++++++++++++-- packages/grpc-native-core/test/call_test.js | 16 +++- .../grpc-native-core/test/end_to_end_test.js | 55 ++++++++----- .../grpc-native-core/test/surface_test.js | 13 ++++ 6 files changed, 180 insertions(+), 35 deletions(-) diff --git a/packages/grpc-native-core/ext/call.cc b/packages/grpc-native-core/ext/call.cc index 8922bc668..25370759b 100644 --- a/packages/grpc-native-core/ext/call.cc +++ b/packages/grpc-native-core/ext/call.cc @@ -81,8 +81,13 @@ Local nanErrorWithCode(const char *msg, grpc_call_error code) { return scope.Escape(err); } -bool CreateMetadataArray(Local metadata, grpc_metadata_array *array) { +bool CreateMetadataArray(Local metadata_obj, grpc_metadata_array *array) { HandleScope scope; + Local metadata_value = (Nan::Get(metadata_obj, Nan::New("metadata").ToLocalChecked())).ToLocalChecked(); + if (!metadata_value->IsObject()) { + return false; + } + Local metadata = Nan::To(metadata_value).ToLocalChecked(); Local keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked(); for (unsigned int i = 0; i < keys->Length(); i++) { Local current_key = @@ -159,7 +164,10 @@ Local ParseMetadata(const grpc_metadata_array *metadata_array) { Nan::Set(array, array->Length(), CopyStringFromSlice(elem->value)); } } - return scope.Escape(metadata_object); + Local result = Nan::New(); + Nan::Set(result, Nan::New("metadata").ToLocalChecked(), metadata_object); + Nan::Set(result, Nan::New("flags").ToLocalChecked(), Nan::New(0)); + return scope.Escape(result); } Local Op::GetOpType() const { @@ -185,7 +193,17 @@ class SendMetadataOp : public Op { if (maybe_metadata.IsEmpty()) { return false; } - if (!CreateMetadataArray(maybe_metadata.ToLocalChecked(), &send_metadata)) { + Local metadata_object = maybe_metadata.ToLocalChecked(); + MaybeLocal maybe_flag_value = + Nan::Get(metadata_object, Nan::New("flags").ToLocalChecked()); + if (!maybe_flag_value.IsEmpty()) { + Local flag_value = maybe_flag_value.ToLocalChecked(); + if (flag_value->IsUint32()) { + Maybe maybe_flag = Nan::To(flag_value); + out->flags |= maybe_flag.FromMaybe(0) & GRPC_INITIAL_METADATA_USED_MASK; + } + } + if (!CreateMetadataArray(metadata_object, &send_metadata)) { return false; } out->data.send_initial_metadata.count = send_metadata.count; @@ -225,7 +243,7 @@ class SendMessageOp : public Op { Local flag_value = maybe_flag_value.ToLocalChecked(); if (flag_value->IsUint32()) { Maybe maybe_flag = Nan::To(flag_value); - out->flags = maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK; + out->flags |= maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK; } } send_message = BufferToByteBuffer(value); diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 808051d06..177906541 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -489,10 +489,29 @@ declare module "grpc" { type sendUnaryData = (error: ServiceError | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void; + interface MetadataOptions { + /* Signal that the request is idempotent. Defaults to false */ + idempotentRequest?: boolean; + /* Signal that the call should not return UNAVAILABLE before it has + * started. Defaults to true. */ + waitForReady?: boolean; + /* Signal that the call is cacheable. GRPC is free to use GET verb. + * Defaults to false */ + cacheableRequest?: boolean; + /* Signal that the initial metadata should be corked. Defaults to false. */ + corked?: boolean; + } + /** * A class for storing metadata. Keys are normalized to lowercase ASCII. */ export class Metadata { + /** + * @param options Boolean options for the beginning of the call. + * These options only have any effect when passed at the beginning of + * a client request. + */ + constructor(options?: MetadataOptions); /** * Sets the given value for the given key by replacing any other values * associated with that key. Normalizes the key. @@ -536,6 +555,14 @@ declare module "grpc" { * @return The newly cloned object. */ clone(): Metadata; + + /** + * Set options on the metadata object + * @param options Boolean options for the beginning of the call. + * These options only have any effect when passed at the beginning of + * a client request. + */ + setOptions(options: MetadataOptions); } export type MetadataValue = string | Buffer; diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js index 31c6329e7..ee442953f 100644 --- a/packages/grpc-native-core/src/metadata.js +++ b/packages/grpc-native-core/src/metadata.js @@ -22,18 +22,36 @@ var clone = require('lodash.clone'); var grpc = require('./grpc_extension'); +const IDEMPOTENT_REQUEST_FLAG = 0x10; +const WAIT_FOR_READY_FLAG = 0x20; +const CACHEABLE_REQUEST_FLAG = 0x40; +const WAIT_FOR_READY_EXPLICITLY_SET_FLAG = 0x80; +const CORKED_FLAG = 0x100; + /** * Class for storing metadata. Keys are normalized to lowercase ASCII. * @memberof grpc * @constructor + * @param {Object=} options Boolean options for the beginning of the call. + * These options only have any effect when passed at the beginning of + * a client request. + * @param {boolean=} [options.idempotentRequest=false] Signal that the request + * is idempotent + * @param {boolean=} [options.waitForReady=true] Signal that the call should + * not return UNAVAILABLE before it has started. + * @param {boolean=} [options.cacheableRequest=false] Signal that the call is + * cacheable. GRPC is free to use GET verb. + * @param {boolean=} [options.corked=false] Signal that the initial metadata + * should be corked. * @example * var metadata = new metadata_module.Metadata(); * metadata.set('key1', 'value1'); * metadata.add('key1', 'value2'); * metadata.get('key1') // returns ['value1', 'value2'] */ -function Metadata() { +function Metadata(options) { this._internal_repr = {}; + this.setOptions(options); } function normalizeKey(key) { @@ -141,34 +159,82 @@ Metadata.prototype.clone = function() { const value = this._internal_repr[key]; copy._internal_repr[key] = clone(value); }); + copy.flags = this.flags; return copy; }; +/** + * Set options on the metadata object + * @param {Object} options Boolean options for the beginning of the call. + * These options only have any effect when passed at the beginning of + * a client request. + * @param {boolean=} [options.idempotentRequest=false] Signal that the request + * is idempotent + * @param {boolean=} [options.waitForReady=true] Signal that the call should + * not return UNAVAILABLE before it has started. + * @param {boolean=} [options.cacheableRequest=false] Signal that the call is + * cacheable. GRPC is free to use GET verb. + * @param {boolean=} [options.corked=false] Signal that the initial metadata + * should be corked. + */ +Metadata.prototype.setOptions = function(options) { + let flags = 0; + if (options) { + if (options.idempotentRequest) { + flags |= IDEMPOTENT_REQUEST_FLAG; + } + if (options.hasOwnProperty('waitForReady')) { + flags |= WAIT_FOR_READY_EXPLICITLY_SET_FLAG; + if (options.waitForReady) { + flags |= WAIT_FOR_READY_FLAG; + } + } + if (options.cacheableRequest) { + flags |= CACHEABLE_REQUEST_FLAG; + } + if (options.corked) { + flags |= CORKED_FLAG; + } + } + this.flags = flags; +} + +/** + * Metadata representation as passed to and the native addon + * @typedef {object} grpc~CoreMetadata + * @param {Object.>} metadata The metadata + * @param {number} flags Metadata flags + */ + /** * Gets the metadata in the format used by interal code. Intended for internal * use only. API stability is not guaranteed. * @private - * @return {Object.>} The metadata + * @return {grpc~CoreMetadata} The metadata */ Metadata.prototype._getCoreRepresentation = function() { - return this._internal_repr; + return { + metadata: this._internal_repr, + flags: this.flags + }; }; /** * Creates a Metadata object from a metadata map in the internal format. * Intended for internal use only. API stability is not guaranteed. * @private - * @param {Object.>} The metadata + * @param {grpc~CoreMetadata} metadata The metadata object from core * @return {Metadata} The new Metadata object */ Metadata._fromCoreRepresentation = function(metadata) { var newMetadata = new Metadata(); if (metadata) { - Object.keys(metadata).forEach(key => { - const value = metadata[key]; + Object.keys(metadata.metadata).forEach(key => { + const value = metadata.metadata[key]; newMetadata._internal_repr[key] = clone(value); }); } + newMetadata.flags = metadata.flags; return newMetadata; }; diff --git a/packages/grpc-native-core/test/call_test.js b/packages/grpc-native-core/test/call_test.js index bba4cce01..42fd3d014 100644 --- a/packages/grpc-native-core/test/call_test.js +++ b/packages/grpc-native-core/test/call_test.js @@ -128,8 +128,9 @@ describe('call', function() { var call = channel.createCall('method', getDeadline(1)); assert.doesNotThrow(function() { var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = {'key1': ['value1'], - 'key2': ['value2']}; + batch[grpc.opType.SEND_INITIAL_METADATA] = { + metadata: {'key1': ['value1'], 'key2': ['value2']} + }; call.startBatch(batch, function(err, resp) { assert.ifError(err); assert.deepEqual(resp, {'send_metadata': true}); @@ -142,8 +143,10 @@ describe('call', function() { assert.doesNotThrow(function() { var batch = {}; batch[grpc.opType.SEND_INITIAL_METADATA] = { - 'key1-bin': [Buffer.from('value1')], - 'key2-bin': [Buffer.from('value2')] + metadata: { + 'key1-bin': [Buffer.from('value1')], + 'key2-bin': [Buffer.from('value2')] + } }; call.startBatch(batch, function(err, resp) { assert.ifError(err); @@ -174,6 +177,11 @@ describe('call', function() { batch[grpc.opType.SEND_INITIAL_METADATA] = 5; call.startBatch(batch, function(){}); }, TypeError); + assert.throws(function() { + var batch = {}; + batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + call.startBatch(batch, function(){}); + }, TypeError); }); }); describe('startBatch with message', function() { diff --git a/packages/grpc-native-core/test/end_to_end_test.js b/packages/grpc-native-core/test/end_to_end_test.js index da6fac6c2..ae165b14e 100644 --- a/packages/grpc-native-core/test/end_to_end_test.js +++ b/packages/grpc-native-core/test/end_to_end_test.js @@ -65,7 +65,7 @@ describe('end-to-end', function() { 'dummy_method', Infinity); var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; @@ -74,11 +74,17 @@ describe('end-to-end', function() { assert.deepEqual(response, { send_metadata: true, client_close: true, - metadata: {}, + metadata: { + metadata: {}, + flags: 0 + }, status: { code: constants.status.OK, details: status_text, - metadata: {} + metadata: { + metadata: {}, + flags: 0 + } } }); done(); @@ -90,9 +96,9 @@ describe('end-to-end', function() { var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {}, + metadata: {metadata: {}}, code: constants.status.OK, details: status_text }; @@ -116,7 +122,9 @@ describe('end-to-end', function() { Infinity); var client_batch = {}; client_batch[grpc.opType.SEND_INITIAL_METADATA] = { - client_key: ['client_value'] + metadata: { + client_key: ['client_value'] + } }; client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; @@ -126,10 +134,13 @@ describe('end-to-end', function() { assert.deepEqual(response,{ send_metadata: true, client_close: true, - metadata: {server_key: ['server_value']}, + metadata: {metadata: { + server_key: ['server_value']}, + flags: 0 + }, status: {code: constants.status.OK, details: status_text, - metadata: {}} + metadata: {metadata: {}, flags: 0}} }); done(); }); @@ -137,16 +148,18 @@ describe('end-to-end', function() { server.requestCall(function(err, call_details) { var new_call = call_details.new_call; assert.notEqual(new_call, null); - assert.strictEqual(new_call.metadata.client_key[0], + assert.strictEqual(new_call.metadata.metadata.client_key[0], 'client_value'); var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; server_batch[grpc.opType.SEND_INITIAL_METADATA] = { - server_key: ['server_value'] + metadata: { + server_key: ['server_value'] + } }; server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {}, + metadata: {metadata: {}}, code: constants.status.OK, details: status_text }; @@ -171,7 +184,7 @@ describe('end-to-end', function() { 'dummy_method', Infinity); var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(req_text); client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; @@ -181,12 +194,12 @@ describe('end-to-end', function() { assert.ifError(err); assert(response.send_metadata); assert(response.client_close); - assert.deepEqual(response.metadata, {}); + assert.deepEqual(response.metadata, {metadata: {}, flags: 0}); assert(response.send_message); assert.strictEqual(response.read.toString(), reply_text); assert.deepEqual(response.status, {code: constants.status.OK, details: status_text, - metadata: {}}); + metadata: {metadata: {}, flags: 0}}); done(); }); @@ -196,7 +209,7 @@ describe('end-to-end', function() { var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; server_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); @@ -205,7 +218,7 @@ describe('end-to-end', function() { var response_batch = {}; response_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(reply_text); response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {}, + metadata: {metadata: {}}, code: constants.status.OK, details: status_text }; @@ -226,7 +239,7 @@ describe('end-to-end', function() { 'dummy_method', Infinity); var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[0]); client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; call.startBatch(client_batch, function(err, response) { @@ -234,7 +247,7 @@ describe('end-to-end', function() { assert.deepEqual(response, { send_metadata: true, send_message: true, - metadata: {} + metadata: {metadata: {}, flags: 0} }); var req2_batch = {}; req2_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[1]); @@ -248,7 +261,7 @@ describe('end-to-end', function() { status: { code: constants.status.OK, details: status_text, - metadata: {} + metadata: {metadata: {}, flags: 0} } }); done(); @@ -261,7 +274,7 @@ describe('end-to-end', function() { var server_call = new_call.call; assert.notEqual(server_call, null); var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = {}; + server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; server_batch[grpc.opType.RECV_MESSAGE] = true; server_call.startBatch(server_batch, function(err, response) { assert.ifError(err); @@ -275,7 +288,7 @@ describe('end-to-end', function() { var end_batch = {}; end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {}, + metadata: {metadata: {}}, code: constants.status.OK, details: status_text }; diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index bc745957a..75183d5e4 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -934,6 +934,19 @@ describe('Other conditions', function() { call.write({}); call.end(); }); + it('client should drop a call if not connected with waitForReady off', function(done) { + /* We have to wait for the client to reach the first connection timeout + * and go to TRANSIENT_FAILURE to confirm that the waitForReady option + * makes it end the call instead of continuing to try. A DNS resolution + * failure makes that transition very fast. */ + const disconnectedClient = new Client('nothing.invalid:50051', grpc.credentials.createInsecure()); + const metadata = new grpc.Metadata({waitForReady: false}); + disconnectedClient.unary({}, metadata, (error, value) =>{ + assert(error); + assert.strictEqual(error.code, grpc.status.UNAVAILABLE); + done(); + }); + }); describe('Server recieving bad input', function() { var misbehavingClient; var badArg = Buffer.from([0xFF]); From d4e16720710de693ac54108864bfd7710c1920cc Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Mar 2019 15:16:52 -0700 Subject: [PATCH 0577/1899] JS: Add initial metadata options API compatibility --- PACKAGE-COMPARISON.md | 1 + packages/grpc-js/src/metadata.ts | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 2b32adaff..0015d25c5 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -18,6 +18,7 @@ HTTP Connect Support | :heavy_check_mark: | :x: Retries | :heavy_check_mark: | :x: Stats/tracing/monitoring | :heavy_check_mark: | :x: Load Balancing | :heavy_check_mark: | :x: +Initial Metadata Options | :heavy_check_mark: | :x: Other Properties | `grpc` | `@grpc/grpc-js` -----------------|--------|---------------- diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 09a6f8832..0114e4940 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -44,12 +44,27 @@ function validate(key: string, value?: MetadataValue): void { } } +interface MetadataOptions { + /* Signal that the request is idempotent. Defaults to false */ + idempotentRequest?: boolean; + /* Signal that the call should not return UNAVAILABLE before it has + * started. Defaults to true. */ + waitForReady?: boolean; + /* Signal that the call is cacheable. GRPC is free to use GET verb. + * Defaults to false */ + cacheableRequest?: boolean; + /* Signal that the initial metadata should be corked. Defaults to false. */ + corked?: boolean; +} + /** * A class for storing metadata. Keys are normalized to lowercase ASCII. */ export class Metadata { protected internalRepr: MetadataObject = new Map(); + constructor(private options?: MetadataOptions) {} + /** * Sets the given value for the given key by replacing any other values * associated with that key. Normalizes the key. @@ -160,6 +175,10 @@ export class Metadata { }); } + setOptions(options: MetadataOptions) { + this.options = options; + } + /** * Creates an OutgoingHttpHeaders object that can be used with the http2 API. */ From 9a371ed1964cc53d75b220fde9c1642fe807aa5f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Mar 2019 15:50:28 -0700 Subject: [PATCH 0578/1899] Omit a build warning that v8 headers violate --- packages/grpc-native-core/binding.gyp | 3 ++- packages/grpc-native-core/templates/binding.gyp.template | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index c6dbe8606..f6436be66 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -963,7 +963,8 @@ ], 'cflags': [ '-pthread', - '-Wno-error=deprecated-declarations' + '-Wno-error=deprecated-declarations', + '-Wno-cast-function-type' ], "conditions": [ ['OS=="win" or runtime=="electron"', { diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 8addf14a4..9ec471a65 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -312,7 +312,8 @@ ], 'cflags': [ '-pthread', - '-Wno-error=deprecated-declarations' + '-Wno-error=deprecated-declarations', + '-Wno-cast-function-type' ], "conditions": [ ['OS=="win" or runtime=="electron"', { From fe7b2e821414326cec092a51f964ba777f9c88d5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 20 Mar 2019 16:26:05 -0700 Subject: [PATCH 0579/1899] Native: fix generic Client constructor crashing --- packages/grpc-native-core/src/client.js | 14 ++++++++------ packages/grpc-native-core/test/surface_test.js | 9 ++++++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 1c41bf593..256f8d1cd 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -376,12 +376,14 @@ function Client(address, credentials, options) { } self.$interceptors = options.interceptors || []; self.$interceptor_providers = options.interceptor_providers || []; - Object.keys(self.$method_definitions).forEach(method_name => { - const method_definition = self.$method_definitions[method_name]; - self[method_name].interceptors = client_interceptors - .resolveInterceptorProviders(self.$interceptor_providers, method_definition) - .concat(self.$interceptors); - }); + if (self.$method_definitions) { + Object.keys(self.$method_definitions).forEach(method_name => { + const method_definition = self.$method_definitions[method_name]; + self[method_name].interceptors = client_interceptors + .resolveInterceptorProviders(self.$interceptor_providers, method_definition) + .concat(self.$interceptors); + }); + } this.$callInvocationTransformer = options.callInvocationTransformer; diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index bc745957a..86f834481 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -220,6 +220,13 @@ describe('Client constructor building', function() { assert.strictEqual(Client.prototype.add, Client.prototype.Add); }); }); +describe('Generic client', function() { + it('Should construct without error', function() { + assert.doesNotThrow(() => { + const client = new grpc.Client('localhost: 50051', grpc.credentials.createInsecure()); + }); + }); +}); describe('waitForClientReady', function() { var server; var port; @@ -314,7 +321,7 @@ describe('Echo service', function() { }); }); }); -describe('Generic client and server', function() { +describe('Non-protobuf client and server', function() { function toString(val) { return val.toString(); } From 157e7c69b65d216460cd6400d58ead054f250ed1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 22 Mar 2019 11:48:15 -0700 Subject: [PATCH 0580/1899] Remove other typescript dev dependencies --- packages/grpc-js/package.json | 3 +-- packages/proto-loader/package.json | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4d87085f1..407c47dd7 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -20,8 +20,7 @@ "@types/node": "^10.5.4", "clang-format": "^1.0.55", "gts": "^0.5.1", - "lodash": "^4.17.4", - "typescript": "~2.7.0" + "lodash": "^4.17.4" }, "contributors": [ { diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 08e5807da..e9ecc9ee3 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -45,8 +45,7 @@ "@types/lodash.camelcase": "^4.3.4", "@types/node": "^10.12.5", "clang-format": "^1.2.2", - "gts": "^0.5.3", - "typescript": "~2.7.2" + "gts": "^0.5.3" }, "engines": { "node": ">=6" From 836515f87e18e7b23c931e648c62a71313227e9b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 25 Mar 2019 14:09:25 -0700 Subject: [PATCH 0581/1899] Fix one more incorrect metadata structure --- packages/grpc-native-core/src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index e28e68b82..b79ee6fc3 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -772,7 +772,7 @@ Server.prototype.start = function() { batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { code: constants.status.UNIMPLEMENTED, details: 'RPC method not implemented ' + method, - metadata: {} + metadata: (new Metadata())._getCoreRepresentation() }; batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; call.startBatch(batch, function() {}); From 88035e8df496e3c1e24d0fde7ea7a3a2b72ad858 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 26 Mar 2019 10:56:22 -0700 Subject: [PATCH 0582/1899] Bump grpc-tools to 1.7.2 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 3e6c780c2..0ea9ccba3 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.7.1", + "version": "1.7.2", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 33674bc82610d2b132e981118df07b5841d53a03 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 26 Mar 2019 13:53:22 -0700 Subject: [PATCH 0583/1899] Fix jessie-backports URL --- tools/release/native/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index 40665df1c..c7c58cfe8 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -1,6 +1,6 @@ FROM debian:jessie -RUN echo "deb http://ftp.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list +RUN echo "deb [check-valid-until=no] http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list RUN apt-get update RUN apt-get -t jessie-backports install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq From 7cc18fe40d4a41cd377f705e7ad07aed4acf1ab6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 26 Mar 2019 16:59:17 -0700 Subject: [PATCH 0584/1899] Use new solution for jessie-backports --- tools/release/native/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index c7c58cfe8..02937c1ce 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -1,8 +1,8 @@ FROM debian:jessie -RUN echo "deb [check-valid-until=no] http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list -RUN apt-get update -RUN apt-get -t jessie-backports install -y cmake +RUN echo "deb http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list +RUN apt-get -o Acquire::Check-Valid-Until=false update +RUN apt-get -t jessie-backports -o Acquire::Check-Valid-Until=false install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq RUN curl -fsSL get.docker.com | bash From a5fa8a9540519988a02b384d4ededf613da2afcd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 26 Mar 2019 17:20:45 -0700 Subject: [PATCH 0585/1899] Fix last fix --- tools/release/native/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index 02937c1ce..baa7a192c 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -2,7 +2,7 @@ FROM debian:jessie RUN echo "deb http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list RUN apt-get -o Acquire::Check-Valid-Until=false update -RUN apt-get -t jessie-backports -o Acquire::Check-Valid-Until=false install -y cmake +RUN apt-get -t jessie-backports install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq RUN curl -fsSL get.docker.com | bash From a9985dffdbcc561fb76f14c3b9069085e5b0a57c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 27 Mar 2019 10:26:13 -0700 Subject: [PATCH 0586/1899] Slightly different check-valid-until fix --- tools/release/native/Dockerfile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index baa7a192c..eb9fb098b 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -1,7 +1,8 @@ FROM debian:jessie RUN echo "deb http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list -RUN apt-get -o Acquire::Check-Valid-Until=false update +RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf +RUN apt-get update RUN apt-get -t jessie-backports install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq RUN curl -fsSL get.docker.com | bash From 9d76ffa65ef9595db1ac41acd744c5e312a67166 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 27 Mar 2019 13:03:22 -0700 Subject: [PATCH 0587/1899] Drop jessie-updates from list --- tools/release/native/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index eb9fb098b..bc03bf178 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -2,6 +2,7 @@ FROM debian:jessie RUN echo "deb http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf +RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list RUN apt-get update RUN apt-get -t jessie-backports install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq From 7f85a775d6149adb131d8478efe89e10c1a6679c Mon Sep 17 00:00:00 2001 From: James Roper Date: Fri, 29 Mar 2019 16:03:51 +1100 Subject: [PATCH 0588/1899] Fixed load/loadSync filename parameter type Fixes #805. Changed the type of the filename parameter to the proto-loader load method to match the type of the protobuf.js load method that it is passed to. Signed-off-by: James Roper --- packages/proto-loader/src/index.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 2e1a2b842..f3273635a 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -243,8 +243,8 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { /** * Load a .proto file with the specified options. - * @param filename The file path to load. Can be an absolute path or relative to - * an include path. + * @param filename One or multiple file paths to load. Can be an absolute path + * or relative to an include path. * @param options.keepCase Preserve field names. The default is to change them * to camel case. * @param options.longs The type that should be used to represent `long` values. @@ -265,7 +265,7 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * name * @param options.includeDirs Paths to search for imported `.proto` files. */ -export function load(filename: string, options?: Options): Promise { +export function load(filename: string | string[], options?: Options): Promise { const root: Protobuf.Root = new Protobuf.Root(); options = options || {}; if (!!options.includeDirs) { @@ -280,7 +280,7 @@ export function load(filename: string, options?: Options): Promise Date: Sun, 31 Mar 2019 21:06:52 -0400 Subject: [PATCH 0589/1899] grpc-js: remove experimental text for http2 The http2 module is no longer considered experimental. Fixes: https://github.com/grpc/grpc-node/issues/808 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9ff1bcad0..908835f8d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Directory: [`packages/grpc-js`](https://github.com/grpc/grpc-node/tree/master/pa npm package: [@grpc/grpc-js](https://www.npmjs.com/package/@grpc/grpc-js) -**This library is currently incomplete and experimental, built on the [experimental http2 Node module](https://nodejs.org/api/http2.html).** +**This library is currently incomplete and experimental. It is built on the [http2 Node module](https://nodejs.org/api/http2.html).** This library implements the core functionality of gRPC purely in JavaScript, without a C++ addon. It works on the latest version of Node.js on all platforms that Node.js runs on. From cbff0b46012ce286e1b54c7a05128667b0d72aad Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 31 Mar 2019 22:16:13 -0400 Subject: [PATCH 0590/1899] proto-loader: include Google well known protos This commit ensures that the Google well known protos are available because protobufjs only exposes a subset of them. --- packages/proto-loader/src/index.ts | 17 +++++++++++++++ .../proto-loader/test/descriptor_type_test.ts | 7 ++++++- .../proto-loader/test_protos/well_known.proto | 21 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 packages/proto-loader/test_protos/well_known.proto diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 2e1a2b842..32e85a783 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -293,3 +293,20 @@ export function loadSync(filename: string, options?: Options): PackageDefinition loadedRoot.resolveAll(); return createPackageDefinition(root, options!); } + +// Load Google's well-known proto files that aren't exposed by Protobuf.js. +{ + // Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, + // and wrappers. compiler/plugin is excluded in Protobuf.js and here. + const wellKnownProtos = ['api', 'descriptor', 'source_context', 'type']; + const sourceDir = path.join(path.dirname(require.resolve('protobufjs')), + 'google', 'protobuf'); + + for (const proto of wellKnownProtos) { + const file = path.join(sourceDir, `${proto}.proto`); + const descriptor = Protobuf.loadSync(file).toJSON(); + + // @ts-ignore + Protobuf.common(proto, descriptor.nested.google.nested); + } +} diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index ae4db0142..e550a6135 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -67,4 +67,9 @@ describe('Descriptor types', () => { done(); }, (error) => {done(error);}); }); -}); \ No newline at end of file + + it('Can use well known Google protos', () => { + // This will throw if the well known protos are not available. + proto_loader.loadSync(`${TEST_PROTO_DIR}/well_known.proto`); + }); +}); diff --git a/packages/proto-loader/test_protos/well_known.proto b/packages/proto-loader/test_protos/well_known.proto new file mode 100644 index 000000000..dd70402be --- /dev/null +++ b/packages/proto-loader/test_protos/well_known.proto @@ -0,0 +1,21 @@ +// Copyright 2019 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "google/protobuf/descriptor.proto"; + +extend google.protobuf.FieldOptions { + bool redact = 52000; +} From c5cc74e589dc0f1b2dfeb27ad209a70918f0853a Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 1 Apr 2019 16:29:50 -0400 Subject: [PATCH 0591/1899] proto-loader: fix linting issues This commit makes the linter pass for proto-loader. --- packages/proto-loader/src/index.ts | 118 +++++++++++------- .../proto-loader/test/descriptor_type_test.ts | 86 ++++++++----- 2 files changed, 127 insertions(+), 77 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 32e85a783..a407e0051 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -15,33 +15,34 @@ * limitations under the License. * */ -import * as Protobuf from 'protobufjs'; -import * as descriptor from 'protobufjs/ext/descriptor'; import * as fs from 'fs'; import * as path from 'path'; +import * as Protobuf from 'protobufjs'; +import * as descriptor from 'protobufjs/ext/descriptor'; + import camelCase = require('lodash.camelcase'); declare module 'protobufjs' { interface Type { - toDescriptor(protoVersion: string): Protobuf.Message & descriptor.IDescriptorProto; + toDescriptor(protoVersion: string): Protobuf + .Message&descriptor.IDescriptorProto; } interface Root { - toDescriptor(protoVersion: string): Protobuf.Message & descriptor.IFileDescriptorSet; + toDescriptor(protoVersion: string): Protobuf + .Message&descriptor.IFileDescriptorSet; } interface Enum { - toDescriptor(protoVersion: string): Protobuf.Message & descriptor.IEnumDescriptorProto; + toDescriptor(protoVersion: string): + Protobuf.Message& + descriptor.IEnumDescriptorProto; } } -export interface Serialize { - (value: T): Buffer; -} +export interface Serialize { (value: T): Buffer; } -export interface Deserialize { - (bytes: Buffer): T; -} +export interface Deserialize { (bytes: Buffer): T; } export interface ProtobufTypeDefinition { format: string; @@ -74,13 +75,12 @@ export interface ServiceDefinition { [index: string]: MethodDefinition; } -export type AnyDefinition = ServiceDefinition | MessageTypeDefinition | EnumTypeDefinition; +export type AnyDefinition = + ServiceDefinition|MessageTypeDefinition|EnumTypeDefinition; -export interface PackageDefinition { - [index: string]: AnyDefinition; -} +export interface PackageDefinition { [index: string]: AnyDefinition; } -export type Options = Protobuf.IParseOptions & Protobuf.IConversionOptions & { +export type Options = Protobuf.IParseOptions&Protobuf.IConversionOptions&{ includeDirs?: string[]; }; @@ -101,31 +101,41 @@ function joinName(baseName: string, name: string): string { } } -type HandledReflectionObject = Protobuf.Service | Protobuf.Type | Protobuf.Enum; +type HandledReflectionObject = Protobuf.Service|Protobuf.Type|Protobuf.Enum; -function isHandledReflectionObject(obj: Protobuf.ReflectionObject): obj is HandledReflectionObject { - return obj instanceof Protobuf.Service || obj instanceof Protobuf.Type || obj instanceof Protobuf.Enum; +function isHandledReflectionObject(obj: Protobuf.ReflectionObject): + obj is HandledReflectionObject { + return obj instanceof Protobuf.Service || obj instanceof Protobuf.Type || + obj instanceof Protobuf.Enum; } -function isNamespaceBase(obj: Protobuf.ReflectionObject): obj is Protobuf.NamespaceBase { +function isNamespaceBase(obj: Protobuf.ReflectionObject): + obj is Protobuf.NamespaceBase { return obj instanceof Protobuf.Namespace || obj instanceof Protobuf.Root; } -function getAllHandledReflectionObjects(obj: Protobuf.ReflectionObject, parentName: string): Array<[string, HandledReflectionObject]> { +function getAllHandledReflectionObjects( + obj: Protobuf.ReflectionObject, + parentName: string): Array<[string, HandledReflectionObject]> { const objName = joinName(parentName, obj.name); if (isHandledReflectionObject(obj)) { return [[objName, obj]]; } else { if (isNamespaceBase(obj) && typeof obj.nested !== undefined) { - return Object.keys(obj.nested!).map((name) => { - return getAllHandledReflectionObjects(obj.nested![name], objName); - }).reduce((accumulator, currentValue) => accumulator.concat(currentValue), []); + return Object.keys(obj.nested!) + .map((name) => { + return getAllHandledReflectionObjects(obj.nested![name], objName); + }) + .reduce( + (accumulator, currentValue) => accumulator.concat(currentValue), + []); } } return []; } -function createDeserializer(cls: Protobuf.Type, options: Options): Deserialize { +function createDeserializer( + cls: Protobuf.Type, options: Options): Deserialize { return function deserialize(argBuf: Buffer): object { return cls.toObject(cls.decode(argBuf), options); }; @@ -138,7 +148,9 @@ function createSerializer(cls: Protobuf.Type): Serialize { }; } -function createMethodDefinition(method: Protobuf.Method, serviceName: string, options: Options): MethodDefinition { +function createMethodDefinition( + method: Protobuf.Method, serviceName: string, + options: Options): MethodDefinition { /* This is only ever called after the corresponding root.resolveAll(), so we * can assume that the resolved request and response types are non-null */ const requestType: Protobuf.Type = method.resolvedRequestType!; @@ -158,7 +170,9 @@ function createMethodDefinition(method: Protobuf.Method, serviceName: string, op }; } -function createServiceDefinition(service: Protobuf.Service, name: string, options: Options): ServiceDefinition { +function createServiceDefinition( + service: Protobuf.Service, name: string, + options: Options): ServiceDefinition { const def: ServiceDefinition = {}; for (const method of service.methodsArray) { def[method.name] = createMethodDefinition(method, name, options); @@ -166,29 +180,37 @@ function createServiceDefinition(service: Protobuf.Service, name: string, option return def; } -const fileDescriptorCache: Map = new Map(); +const fileDescriptorCache: Map = + new Map(); function getFileDescriptors(root: Protobuf.Root): Buffer[] { if (fileDescriptorCache.has(root)) { return fileDescriptorCache.get(root)!; } else { - const descriptorList: descriptor.IFileDescriptorProto[] = root.toDescriptor('proto3').file; - const bufferList: Buffer[] = descriptorList.map(value => Buffer.from(descriptor.FileDescriptorProto.encode(value).finish())); + const descriptorList: descriptor.IFileDescriptorProto[] = + root.toDescriptor('proto3').file; + const bufferList: Buffer[] = descriptorList.map( + value => + Buffer.from(descriptor.FileDescriptorProto.encode(value).finish())); fileDescriptorCache.set(root, bufferList); return bufferList; } } -function createMessageDefinition(message: Protobuf.Type): MessageTypeDefinition { - const messageDescriptor: protobuf.Message = message.toDescriptor('proto3'); +function createMessageDefinition(message: Protobuf.Type): + MessageTypeDefinition { + const messageDescriptor: protobuf.Message = + message.toDescriptor('proto3'); return { format: 'Protocol Buffer 3 DescriptorProto', - type: messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions), + type: + messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions), fileDescriptorProtos: getFileDescriptors(message.root) }; } function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition { - const enumDescriptor: protobuf.Message = enumType.toDescriptor('proto3'); + const enumDescriptor: protobuf.Message = + enumType.toDescriptor('proto3'); return { format: 'Protocol Buffer 3 EnumDescriptorProto', type: enumDescriptor.$type.toObject(enumDescriptor, descriptorOptions), @@ -197,11 +219,15 @@ function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition { } /** - * function createDefinition(obj: Protobuf.Service, name: string, options: Options): ServiceDefinition; - * function createDefinition(obj: Protobuf.Type, name: string, options: Options): MessageTypeDefinition; - * function createDefinition(obj: Protobuf.Enum, name: string, options: Options): EnumTypeDefinition; + * function createDefinition(obj: Protobuf.Service, name: string, options: + * Options): ServiceDefinition; function createDefinition(obj: Protobuf.Type, + * name: string, options: Options): MessageTypeDefinition; function + * createDefinition(obj: Protobuf.Enum, name: string, options: Options): + * EnumTypeDefinition; */ -function createDefinition(obj: HandledReflectionObject, name: string, options: Options): AnyDefinition { +function createDefinition( + obj: HandledReflectionObject, name: string, + options: Options): AnyDefinition { if (obj instanceof Protobuf.Service) { return createServiceDefinition(obj, name, options); } else if (obj instanceof Protobuf.Type) { @@ -213,7 +239,8 @@ function createDefinition(obj: HandledReflectionObject, name: string, options: O } } -function createPackageDefinition(root: Protobuf.Root, options: Options): PackageDefinition { +function createPackageDefinition( + root: Protobuf.Root, options: Options): PackageDefinition { const def: PackageDefinition = {}; root.resolveAll(); for (const [name, obj] of getAllHandledReflectionObjects(root, '')) { @@ -265,12 +292,14 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * name * @param options.includeDirs Paths to search for imported `.proto` files. */ -export function load(filename: string, options?: Options): Promise { +export function load( + filename: string, options?: Options): Promise { const root: Protobuf.Root = new Protobuf.Root(); options = options || {}; if (!!options.includeDirs) { if (!(Array.isArray(options.includeDirs))) { - return Promise.reject(new Error('The includeDirs option must be an array')); + return Promise.reject( + new Error('The includeDirs option must be an array')); } addIncludePathResolver(root, options.includeDirs as string[]); } @@ -280,7 +309,8 @@ export function load(filename: string, options?: Options): Promise { it('Should be output for each enum', (done) => { - proto_loader.load(`${TEST_PROTO_DIR}/enums.proto`).then((packageDefinition) => { - assert('Enum1' in packageDefinition); - assert(isTypeObject(packageDefinition.Enum1)); - // Need additional check because compiler doesn't understand asserts - if(isTypeObject(packageDefinition.Enum1)) { - const enum1Def: TypeDefinition = packageDefinition.Enum1; - assert.strictEqual(enum1Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); - } + proto_loader.load(`${TEST_PROTO_DIR}/enums.proto`) + .then( + (packageDefinition) => { + assert('Enum1' in packageDefinition); + assert(isTypeObject(packageDefinition.Enum1)); + // Need additional check because compiler doesn't understand + // asserts + if (isTypeObject(packageDefinition.Enum1)) { + const enum1Def: TypeDefinition = packageDefinition.Enum1; + assert.strictEqual( + enum1Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); + } - assert('Enum2' in packageDefinition); - assert(isTypeObject(packageDefinition.Enum2)); - // Need additional check because compiler doesn't understand asserts - if(isTypeObject(packageDefinition.Enum2)) { - const enum2Def: TypeDefinition = packageDefinition.Enum2; - assert.strictEqual(enum2Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); - } - done(); - }, (error) => {done(error);}); + assert('Enum2' in packageDefinition); + assert(isTypeObject(packageDefinition.Enum2)); + // Need additional check because compiler doesn't understand + // asserts + if (isTypeObject(packageDefinition.Enum2)) { + const enum2Def: TypeDefinition = packageDefinition.Enum2; + assert.strictEqual( + enum2Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); + } + done(); + }, + (error) => { + done(error); + }); }); it('Should be output for each message', (done) => { - proto_loader.load(`${TEST_PROTO_DIR}/messages.proto`).then((packageDefinition) => { - assert('LongValues' in packageDefinition); - assert(isTypeObject(packageDefinition.LongValues)); - if(isTypeObject(packageDefinition.LongValues)) { - const longValuesDef: TypeDefinition = packageDefinition.LongValues; - assert.strictEqual(longValuesDef.format, 'Protocol Buffer 3 DescriptorProto'); - } + proto_loader.load(`${TEST_PROTO_DIR}/messages.proto`) + .then( + (packageDefinition) => { + assert('LongValues' in packageDefinition); + assert(isTypeObject(packageDefinition.LongValues)); + if (isTypeObject(packageDefinition.LongValues)) { + const longValuesDef: TypeDefinition = + packageDefinition.LongValues; + assert.strictEqual( + longValuesDef.format, 'Protocol Buffer 3 DescriptorProto'); + } - assert('SequenceValues' in packageDefinition); - assert(isTypeObject(packageDefinition.SequenceValues)); - if(isTypeObject(packageDefinition.SequenceValues)) { - const sequenceValuesDef: TypeDefinition = packageDefinition.SequenceValues; - assert.strictEqual(sequenceValuesDef.format, 'Protocol Buffer 3 DescriptorProto'); - } - done(); - }, (error) => {done(error);}); + assert('SequenceValues' in packageDefinition); + assert(isTypeObject(packageDefinition.SequenceValues)); + if (isTypeObject(packageDefinition.SequenceValues)) { + const sequenceValuesDef: TypeDefinition = + packageDefinition.SequenceValues; + assert.strictEqual( + sequenceValuesDef.format, + 'Protocol Buffer 3 DescriptorProto'); + } + done(); + }, + (error) => { + done(error); + }); }); it('Can use well known Google protos', () => { From 40eef7af22eea6de78f4ccb55f5b8fb61cdfdea3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 31 Mar 2019 14:44:37 -0400 Subject: [PATCH 0592/1899] grpc-js: add ServerCredentials support This commit adds ServerCredentials to the pure JS implementation. --- packages/grpc-js/src/index.ts | 13 +- packages/grpc-js/src/server-credentials.ts | 108 +++++++++++++++ .../grpc-js/test/test-server-credentials.ts | 126 ++++++++++++++++++ 3 files changed, 238 insertions(+), 9 deletions(-) create mode 100644 packages/grpc-js/src/server-credentials.ts create mode 100644 packages/grpc-js/test/test-server-credentials.ts diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index a55ced9af..49437e4db 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -27,6 +27,7 @@ import {LogVerbosity, Status} from './constants'; import * as logging from './logging'; import {Deserialize, loadPackageDefinition, makeClientConstructor, Serialize} from './make-client'; import {Metadata} from './metadata'; +import {KeyCertPair, ServerCredentials} from './server-credentials'; import {StatusBuilder} from './status-builder'; const supportedNodeVersions = '^8.11.2 || >=9.4'; @@ -226,15 +227,9 @@ export const Server = (options: any) => { throw new Error('Not yet implemented'); }; -export const ServerCredentials = { - createSsl: - (rootCerts: any, keyCertPairs: any, checkClientCertificate: any) => { - throw new Error('Not yet implemented'); - }, - createInsecure: () => { - throw new Error('Not yet implemented'); - } -}; +export {ServerCredentials}; +export {KeyCertPair}; + export const getClientChannel = (client: Client) => { return Client.prototype.getChannel.call(client); diff --git a/packages/grpc-js/src/server-credentials.ts b/packages/grpc-js/src/server-credentials.ts new file mode 100644 index 000000000..9e5dc782d --- /dev/null +++ b/packages/grpc-js/src/server-credentials.ts @@ -0,0 +1,108 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import {SecureServerOptions} from 'http2'; + + +export type KeyCertPair = { + private_key: Buffer, + cert_chain: Buffer +}; + + +export abstract class ServerCredentials { + abstract _isSecure(): boolean; + abstract _getSettings(): SecureServerOptions|null; + + static createInsecure(): ServerCredentials { + return new InsecureServerCredentials(); + } + + static createSsl( + rootCerts: Buffer|null, keyCertPairs: KeyCertPair[], + checkClientCertificate = false): ServerCredentials { + if (rootCerts !== null && !Buffer.isBuffer(rootCerts)) { + throw new TypeError('rootCerts must be null or a Buffer'); + } + + if (!Array.isArray(keyCertPairs)) { + throw new TypeError('keyCertPairs must be an array'); + } + + if (typeof checkClientCertificate !== 'boolean') { + throw new TypeError('checkClientCertificate must be a boolean'); + } + + const cert = []; + const key = []; + + for (let i = 0; i < keyCertPairs.length; i++) { + const pair = keyCertPairs[i]; + + if (pair === null || typeof pair !== 'object') { + throw new TypeError(`keyCertPair[${i}] must be an object`); + } + + if (!Buffer.isBuffer(pair.private_key)) { + throw new TypeError(`keyCertPair[${i}].private_key must be a Buffer`); + } + + if (!Buffer.isBuffer(pair.cert_chain)) { + throw new TypeError(`keyCertPair[${i}].cert_chain must be a Buffer`); + } + + cert.push(pair.cert_chain); + key.push(pair.private_key); + } + + return new SecureServerCredentials({ + ca: rootCerts || undefined, + cert, + key, + requestCert: checkClientCertificate + }); + } +} + + +class InsecureServerCredentials extends ServerCredentials { + _isSecure(): boolean { + return false; + } + + _getSettings(): null { + return null; + } +} + + +class SecureServerCredentials extends ServerCredentials { + private options: SecureServerOptions; + + constructor(options: SecureServerOptions) { + super(); + this.options = options; + } + + _isSecure(): boolean { + return true; + } + + _getSettings(): SecureServerOptions { + return this.options; + } +} diff --git a/packages/grpc-js/test/test-server-credentials.ts b/packages/grpc-js/test/test-server-credentials.ts new file mode 100644 index 000000000..847b647a0 --- /dev/null +++ b/packages/grpc-js/test/test-server-credentials.ts @@ -0,0 +1,126 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any +import * as assert from 'assert'; +import {readFileSync} from 'fs'; +import {join} from 'path'; +import {ServerCredentials} from '../src'; + +const ca = readFileSync(join(__dirname, 'fixtures', 'ca.pem')); +const key = readFileSync(join(__dirname, 'fixtures', 'server1.key')); +const cert = readFileSync(join(__dirname, 'fixtures', 'server1.pem')); + +describe('Server Credentials', () => { + describe('createInsecure', () => { + it('creates insecure credentials', () => { + const creds = ServerCredentials.createInsecure(); + + assert.strictEqual(creds._isSecure(), false); + assert.strictEqual(creds._getSettings(), null); + }); + }); + + describe('createSsl', () => { + it('accepts a buffer and array as the first two arguments', () => { + const creds = ServerCredentials.createSsl(ca, []); + + assert.strictEqual(creds._isSecure(), true); + assert.deepStrictEqual( + creds._getSettings(), {ca, cert: [], key: [], requestCert: false}); + }); + + it('accepts a boolean as the third argument', () => { + const creds = ServerCredentials.createSsl(ca, [], true); + + assert.strictEqual(creds._isSecure(), true); + assert.deepStrictEqual( + creds._getSettings(), {ca, cert: [], key: [], requestCert: true}); + }); + + it('accepts an object with two buffers in the second argument', () => { + const keyCertPairs = [{private_key: key, cert_chain: cert}]; + const creds = ServerCredentials.createSsl(null, keyCertPairs); + + assert.strictEqual(creds._isSecure(), true); + assert.deepStrictEqual( + creds._getSettings(), + {ca: undefined, cert: [cert], key: [key], requestCert: false}); + }); + + it('accepts multiple objects in the second argument', () => { + const keyCertPairs = [ + {private_key: key, cert_chain: cert}, + {private_key: key, cert_chain: cert} + ]; + const creds = ServerCredentials.createSsl(null, keyCertPairs, false); + + assert.strictEqual(creds._isSecure(), true); + assert.deepStrictEqual(creds._getSettings(), { + ca: undefined, + cert: [cert, cert], + key: [key, key], + requestCert: false + }); + }); + + it('fails if the second argument is not an Array', () => { + assert.throws(() => { + ServerCredentials.createSsl(ca, 'test' as any); + }, /TypeError: keyCertPairs must be an array/); + }); + + it('fails if the first argument is a non-Buffer value', () => { + assert.throws(() => { + ServerCredentials.createSsl('test' as any, []); + }, /TypeError: rootCerts must be null or a Buffer/); + }); + + it('fails if the third argument is a non-boolean value', () => { + assert.throws(() => { + ServerCredentials.createSsl(ca, [], 'test' as any); + }, /TypeError: checkClientCertificate must be a boolean/); + }); + + it('fails if the array elements are not objects', () => { + assert.throws(() => { + ServerCredentials.createSsl(ca, ['test'] as any); + }, /TypeError: keyCertPair\[0\] must be an object/); + + assert.throws(() => { + ServerCredentials.createSsl(ca, [null] as any); + }, /TypeError: keyCertPair\[0\] must be an object/); + }); + + it('fails if the object does not have a Buffer private key', () => { + const keyCertPairs: any = [{private_key: 'test', cert_chain: cert}]; + + assert.throws(() => { + ServerCredentials.createSsl(null, keyCertPairs); + }, /TypeError: keyCertPair\[0\].private_key must be a Buffer/); + }); + + it('fails if the object does not have a Buffer cert chain', () => { + const keyCertPairs: any = [{private_key: key, cert_chain: 'test'}]; + + assert.throws(() => { + ServerCredentials.createSsl(null, keyCertPairs); + }, /TypeError: keyCertPair\[0\].cert_chain must be a Buffer/); + }); + }); +}); From 48d33c95c3ed65dd79a2aefae2a380e8d6e3a5c1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 3 Apr 2019 13:03:44 -0700 Subject: [PATCH 0593/1899] Update grpc submodule to fix gcc8 build failures --- packages/grpc-native-core/binding.gyp | 9 +++++---- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index f6436be66..e3849974b 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.19.0"' + 'GRPC_NODE_VERSION="1.21.0-dev"' ], 'conditions': [ ['grpc_gcov=="true"', { @@ -725,7 +725,6 @@ 'deps/grpc/src/core/lib/iomgr/udp_server.cc', 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix.cc', 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_cv.cc', 'deps/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc', 'deps/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc', 'deps/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc', @@ -765,7 +764,6 @@ 'deps/grpc/src/core/lib/transport/metadata.cc', 'deps/grpc/src/core/lib/transport/metadata_batch.cc', 'deps/grpc/src/core/lib/transport/pid_controller.cc', - 'deps/grpc/src/core/lib/transport/service_config.cc', 'deps/grpc/src/core/lib/transport/static_metadata.cc', 'deps/grpc/src/core/lib/transport/status_conversion.cc', 'deps/grpc/src/core/lib/transport/status_metadata.cc', @@ -821,6 +819,7 @@ 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', 'deps/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc', + 'deps/grpc/src/core/lib/security/credentials/tls/spiffe_credentials.cc', 'deps/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_fallback.cc', @@ -829,6 +828,7 @@ 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/ssl_utils.cc', + 'deps/grpc/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', @@ -893,12 +893,13 @@ 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', - 'deps/grpc/src/core/ext/filters/client_channel/request_routing.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolving_lb_policy.cc', 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', 'deps/grpc/src/core/ext/filters/client_channel/server_address.cc', + 'deps/grpc/src/core/ext/filters/client_channel/service_config.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 801266f7d..cb0129702 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 801266f7dc84dd7fc7d0f663a4d28762e7cfb1aa +Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 439cc68a7..f849dde2a 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.19.0", + "version": "1.21.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From b50b9ab929930f529d03bbe9a87bfea9e11fdd47 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 3 Apr 2019 16:23:28 -0700 Subject: [PATCH 0594/1899] v1.20.0-pre1 submodule update and version bump --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index e3849974b..347a55b8d 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.21.0-dev"' + 'GRPC_NODE_VERSION="1.20.0-pre1"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index cb0129702..2f113fd0f 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 +Subproject commit 2f113fd0fc8570ba5ba723b40638eab711cca6e2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f849dde2a..a65726644 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.21.0-dev", + "version": "1.20.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 7b5eae2d2f48b5bcaecb3a69760037c120819541 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 4 Apr 2019 16:56:00 -0700 Subject: [PATCH 0595/1899] Add deadline to new test --- packages/grpc-native-core/test/surface_test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 75183d5e4..2f3f73273 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -941,7 +941,9 @@ describe('Other conditions', function() { * failure makes that transition very fast. */ const disconnectedClient = new Client('nothing.invalid:50051', grpc.credentials.createInsecure()); const metadata = new grpc.Metadata({waitForReady: false}); - disconnectedClient.unary({}, metadata, (error, value) =>{ + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ assert(error); assert.strictEqual(error.code, grpc.status.UNAVAILABLE); done(); From fe7a6a89c86e042a840cc3e80165a38b18c1b396 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 8 Apr 2019 15:16:49 -0700 Subject: [PATCH 0596/1899] Bump to v1.20.0-pre3 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 347a55b8d..be1489504 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.0-pre1"' + 'GRPC_NODE_VERSION="1.20.0-pre3"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 2f113fd0f..1b488f836 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 2f113fd0fc8570ba5ba723b40638eab711cca6e2 +Subproject commit 1b488f8361234dddf1e48369b5dc482495fb3f9b diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index a65726644..483728358 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.20.0-pre1", + "version": "1.20.0-pre3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 1cfe05ba463dd71f609dfc4c8809fef06d46d4ae Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 8 Apr 2019 21:00:57 -0400 Subject: [PATCH 0597/1899] grpc-js: update dependency versions Update grpc-js to the latest version of all dependencies. --- packages/grpc-js/package.json | 8 ++++---- packages/grpc-js/src/make-client.ts | 8 ++++++-- packages/grpc-js/test/test-call-stream.ts | 1 + 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 718ec95ba..f32ce2a71 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -16,10 +16,10 @@ "license": "Apache-2.0", "devDependencies": { "@types/lodash": "^4.14.108", - "@types/mocha": "^2.2.43", - "@types/node": "^10.5.4", + "@types/mocha": "^5.2.6", + "@types/node": "^11.13.2", "clang-format": "^1.0.55", - "gts": "^0.5.1", + "gts": "^0.9.0", "lodash": "^4.17.4" }, "contributors": [ @@ -41,7 +41,7 @@ "posttest": "npm run check" }, "dependencies": { - "semver": "^5.5.0" + "semver": "^6.0.0" }, "files": [ "build/src/*.{js,d.ts}", diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 244604f75..46d83bce1 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -19,9 +19,13 @@ import {ChannelCredentials} from './channel-credentials'; import {ChannelOptions} from './channel-options'; import {Client} from './client'; -export interface Serialize { (value: T): Buffer; } +export interface Serialize { + (value: T): Buffer; +} -export interface Deserialize { (bytes: Buffer): T; } +export interface Deserialize { + (bytes: Buffer): T; +} export interface MethodDefinition { path: string; diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index af6ae43aa..e2c8ff5c0 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -64,6 +64,7 @@ class ClientHttp2StreamMock extends stream.Duplex implements endAfterHeaders = false; pending = false; rstCode = 0; + readonly bufferSize: number = 0; readonly sentHeaders: OutgoingHttpHeaders = {}; readonly sentInfoHeaders?: OutgoingHttpHeaders[] = []; readonly sentTrailers?: OutgoingHttpHeaders = undefined; From a9514ad92c3e37778d7b82c17f1a5dfb7fbad051 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 9 Apr 2019 09:47:08 -0700 Subject: [PATCH 0598/1899] Build grpc-tools with static libc --- packages/grpc-tools/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 11d6e843d..a0d3905ce 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -13,6 +13,8 @@ add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake deps/protobuf) set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests") set(protobuf_WITH_ZLIB OFF CACHE BOOL "Build protobuf with zlib.") +set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++") + add_executable(grpc_node_plugin src/node_generator.cc src/node_plugin.cc From cd4b2ad52489237091ca3c2a56f5e8a162dc28ad Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 9 Apr 2019 10:34:55 -0700 Subject: [PATCH 0599/1899] Bump proto-loader version to 0.5.0 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index ecbfe3b54..fb56a89bf 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.4.0", + "version": "0.5.0", "author": "Google Inc.", "contributors": [ { From 3b8cf357e4ff8458f27f25f463c887550d0e0e50 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 9 Apr 2019 16:03:54 -0700 Subject: [PATCH 0600/1899] Re-add typescript dependency on packages that use it --- packages/grpc-js/package.json | 3 ++- packages/grpc-native-core/deps/grpc | 2 +- packages/proto-loader/package.json | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 718ec95ba..539108059 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -20,7 +20,8 @@ "@types/node": "^10.5.4", "clang-format": "^1.0.55", "gts": "^0.5.1", - "lodash": "^4.17.4" + "lodash": "^4.17.4", + "typescript": "~3.3.3333" }, "contributors": [ { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index cb0129702..1b488f836 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 +Subproject commit 1b488f8361234dddf1e48369b5dc482495fb3f9b diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index fb56a89bf..bbf92af50 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -46,7 +46,8 @@ "@types/lodash.camelcase": "^4.3.4", "@types/node": "^10.12.5", "clang-format": "^1.2.2", - "gts": "^0.5.3" + "gts": "^0.5.3", + "typescript": "~3.3.3333" }, "engines": { "node": ">=6" From 4d54a9397f00cf2c1639e4f1d86582bbf0ccc2e5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 10 Apr 2019 11:03:11 -0700 Subject: [PATCH 0601/1899] Undo submodue change --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 1b488f836..cb0129702 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 1b488f8361234dddf1e48369b5dc482495fb3f9b +Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 From 62e7f0c85a08147d16d5850bdbf6310aa0e4f4f4 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 6 Apr 2019 00:59:48 -0400 Subject: [PATCH 0602/1899] grpc-js: define Server API contract This commit defines the Server API contract, and implements the Server functionality, minus the actual handling of requests. --- packages/grpc-js/package.json | 1 + packages/grpc-js/src/server-call.ts | 148 ++++++++++++++ packages/grpc-js/src/server.ts | 230 +++++++++++++++++++++ packages/grpc-js/test/common.ts | 16 ++ packages/grpc-js/test/fixtures/math.proto | 50 +++++ packages/grpc-js/test/test-server.ts | 231 ++++++++++++++++++++++ 6 files changed, 676 insertions(+) create mode 100644 packages/grpc-js/src/server-call.ts create mode 100644 packages/grpc-js/src/server.ts create mode 100644 packages/grpc-js/test/fixtures/math.proto create mode 100644 packages/grpc-js/test/test-server.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f32ce2a71..5e35c2c2b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,6 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { + "@grpc/proto-loader": "^0.4.0", "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", "@types/node": "^11.13.2", diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts new file mode 100644 index 000000000..57c3d20dd --- /dev/null +++ b/packages/grpc-js/src/server-call.ts @@ -0,0 +1,148 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import {EventEmitter} from 'events'; +import {Duplex, Readable, Writable} from 'stream'; +import {ServiceError} from './call'; +import {Deserialize, Serialize} from './make-client'; +import {Metadata} from './metadata'; + + +export class ServerUnaryCall extends EventEmitter { + cancelled: boolean; + request: RequestType|null; + + constructor(private call: ServerCall, public metadata: Metadata) { + super(); + this.cancelled = false; + this.request = null; // TODO(cjihrig): Read the unary request here. + } + + getPeer(): string { + throw new Error('not implemented yet'); + } + + sendMetadata(responseMetadata: Metadata): void { + throw new Error('not implemented yet'); + } +} + + +export class ServerReadableStream extends Readable { + cancelled: boolean; + + constructor( + private call: ServerCall, public metadata: Metadata, + private deserialize: Deserialize) { + super(); + this.cancelled = false; + } + + getPeer(): string { + throw new Error('not implemented yet'); + } + + sendMetadata(responseMetadata: Metadata): void { + throw new Error('not implemented yet'); + } +} + + +export class ServerWritableStream extends Writable { + cancelled: boolean; + request: RequestType|null; + + constructor( + private call: ServerCall, public metadata: Metadata, + private serialize: Serialize) { + super(); + this.cancelled = false; + this.request = null; // TODO(cjihrig): Read the unary request here. + } + + getPeer(): string { + throw new Error('not implemented yet'); + } + + sendMetadata(responseMetadata: Metadata): void { + throw new Error('not implemented yet'); + } +} + + +export class ServerDuplexStream extends Duplex { + cancelled: boolean; + + constructor( + private call: ServerCall, public metadata: Metadata, + private serialize: Serialize, + private deserialize: Deserialize) { + super(); + this.cancelled = false; + } + + getPeer(): string { + throw new Error('not implemented yet'); + } + + sendMetadata(responseMetadata: Metadata): void { + throw new Error('not implemented yet'); + } +} + + +// Internal class that wraps the HTTP2 request. +export class ServerCall {} + + +// Unary response callback signature. +export type sendUnaryData = + (error: ServiceError|null, value: ResponseType|null, trailer?: Metadata, + flags?: number) => void; + +// User provided handler for unary calls. +export type handleUnaryCall = + (call: ServerUnaryCall, + callback: sendUnaryData) => void; + +// User provided handler for client streaming calls. +export type handleClientStreamingCall = + (call: ServerReadableStream, + callback: sendUnaryData) => void; + +// User provided handler for server streaming calls. +export type handleServerStreamingCall = + (call: ServerWritableStream) => void; + +// User provided handler for bidirectional streaming calls. +export type handleBidiStreamingCall = + (call: ServerDuplexStream) => void; + +export type HandleCall = + handleUnaryCall| + handleClientStreamingCall| + handleServerStreamingCall| + handleBidiStreamingCall; + +export type Handler = { + func: HandleCall; + serialize: Serialize; + deserialize: Deserialize; + type: HandlerType; +}; + +export type HandlerType = 'bidi'|'clientStream'|'serverStream'|'unary'; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts new file mode 100644 index 000000000..decdbe5a4 --- /dev/null +++ b/packages/grpc-js/src/server.ts @@ -0,0 +1,230 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as http2 from 'http2'; +import {AddressInfo, ListenOptions} from 'net'; +import {URL} from 'url'; + +import {ServiceError} from './call'; +import {Status} from './constants'; +import {Deserialize, Serialize, ServiceDefinition} from './make-client'; +import {HandleCall, Handler, HandlerType, sendUnaryData, ServerDuplexStream, ServerReadableStream, ServerUnaryCall, ServerWritableStream} from './server-call'; +import {ServerCredentials} from './server-credentials'; + +function noop(): void {} + +type PartialServiceError = Partial; +const unimplementedStatusResponse: PartialServiceError = { + code: Status.UNIMPLEMENTED, + details: 'The server does not implement this method', +}; + +// tslint:disable:no-any +type UntypedHandleCall = HandleCall; +type UntypedHandler = Handler; +type UntypedServiceImplementation = { + [name: string]: UntypedHandleCall +}; + +const defaultHandler = { + unary(call: ServerUnaryCall, callback: sendUnaryData): void { + callback(unimplementedStatusResponse as ServiceError, null); + }, + clientStream(call: ServerReadableStream, callback: sendUnaryData): + void { + callback(unimplementedStatusResponse as ServiceError, null); + }, + serverStream(call: ServerWritableStream): void { + call.emit('error', unimplementedStatusResponse); + }, + bidi(call: ServerDuplexStream): void { + call.emit('error', unimplementedStatusResponse); + } +}; +// tslint:enable:no-any + +export class Server { + private http2Server: http2.Http2Server|http2.Http2SecureServer|null = null; + private handlers: Map = + new Map(); + private started = false; + + constructor(options?: object) {} + + addProtoService(): void { + throw new Error('Not implemented. Use addService() instead'); + } + + addService(service: ServiceDefinition, implementation: object): void { + if (this.started === true) { + throw new Error('Can\'t add a service to a started server.'); + } + + if (service === null || typeof service !== 'object' || + implementation === null || typeof implementation !== 'object') { + throw new Error('addService() requires two objects as arguments'); + } + + const serviceKeys = Object.keys(service); + + if (serviceKeys.length === 0) { + throw new Error('Cannot add an empty service to a server'); + } + + const implMap: UntypedServiceImplementation = + implementation as UntypedServiceImplementation; + + serviceKeys.forEach((name) => { + const attrs = service[name]; + let methodType: HandlerType; + + if (attrs.requestStream) { + if (attrs.responseStream) { + methodType = 'bidi'; + } else { + methodType = 'clientStream'; + } + } else { + if (attrs.responseStream) { + methodType = 'serverStream'; + } else { + methodType = 'unary'; + } + } + + let implFn = implMap[name]; + let impl; + + if (implFn === undefined && typeof attrs.originalName === 'string') { + implFn = implMap[attrs.originalName]; + } + + if (implFn !== undefined) { + impl = implFn.bind(implementation); + } else { + impl = defaultHandler[methodType]; + } + + const success = this.register( + attrs.path, impl, attrs.responseSerialize, attrs.requestDeserialize, + methodType); + + if (success === false) { + throw new Error(`Method handler for ${attrs.path} already provided.`); + } + }); + } + + bind(port: string, creds: ServerCredentials): void { + throw new Error('Not implemented. Use bindAsync() instead'); + } + + bindAsync( + port: string, creds: ServerCredentials, + callback: (error: Error|null, port: number) => void): void { + if (this.started === true) { + throw new Error('server is already started'); + } + + if (typeof port !== 'string') { + throw new TypeError('port must be a string'); + } + + if (creds === null || typeof creds !== 'object') { + throw new TypeError('creds must be an object'); + } + + if (typeof callback !== 'function') { + throw new TypeError('callback must be a function'); + } + + const url = new URL(`http://${port}`); + const options: ListenOptions = {host: url.hostname, port: +url.port}; + + if (creds._isSecure()) { + this.http2Server = http2.createSecureServer( + creds._getSettings() as http2.SecureServerOptions); + } else { + this.http2Server = http2.createServer(); + } + + // TODO(cjihrig): Set up the handlers, to allow requests to be processed. + + function onError(err: Error): void { + callback(err, -1); + } + + this.http2Server.once('error', onError); + + this.http2Server.listen(options, () => { + const server = + this.http2Server as http2.Http2Server | http2.Http2SecureServer; + const port = (server.address() as AddressInfo).port; + + server.removeListener('error', onError); + callback(null, port); + }); + } + + forceShutdown(): void { + throw new Error('Not yet implemented'); + } + + register( + name: string, handler: HandleCall, + serialize: Serialize, deserialize: Deserialize, + type: string): boolean { + if (this.handlers.has(name)) { + return false; + } + + this.handlers.set( + name, + {func: handler, serialize, deserialize, type: type as HandlerType}); + return true; + } + + start(): void { + if (this.http2Server === null || this.http2Server.listening !== true) { + throw new Error('server must be bound in order to start'); + } + + if (this.started === true) { + throw new Error('server is already started'); + } + + this.started = true; + } + + tryShutdown(callback: (error?: Error) => void): void { + callback = typeof callback === 'function' ? callback : noop; + + if (this.http2Server === null) { + callback(new Error('server is not running')); + return; + } + + this.http2Server.close((err?: Error) => { + this.started = false; + callback(err); + }); + } + + addHttp2Port(): void { + throw new Error('Not yet implemented'); + } +} diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index 1a1908e76..179765960 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -15,8 +15,19 @@ * */ +import * as loader from '@grpc/proto-loader'; import * as assert from 'assert'; +import {GrpcObject, loadPackageDefinition} from '../src/make-client'; + +const protoLoaderOptions = { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +}; + export function mockFunction(): never { throw new Error('Not implemented'); } @@ -100,3 +111,8 @@ export namespace assert2 { } } } + +export function loadProtoFile(file: string): GrpcObject { + const packageDefinition = loader.loadSync(file, protoLoaderOptions); + return loadPackageDefinition(packageDefinition); +} diff --git a/packages/grpc-js/test/fixtures/math.proto b/packages/grpc-js/test/fixtures/math.proto new file mode 100644 index 000000000..ca59a7afe --- /dev/null +++ b/packages/grpc-js/test/fixtures/math.proto @@ -0,0 +1,50 @@ +syntax = "proto3"; + +package math; + +message DivArgs { + int64 dividend = 1; + int64 divisor = 2; +} + +message DivReply { + int64 quotient = 1; + int64 remainder = 2; +} + +message FibArgs { + int64 limit = 1; +} + +message Num { + int64 num = 1; +} + +message FibReply { + int64 count = 1; +} + +service Math { + // Div divides DivArgs.dividend by DivArgs.divisor and returns the quotient + // and remainder. + rpc Div (DivArgs) returns (DivReply) { + } + + // DivMany accepts an arbitrary number of division args from the client stream + // and sends back the results in the reply stream. The stream continues until + // the client closes its end; the server does the same after sending all the + // replies. The stream ends immediately if either end aborts. + rpc DivMany (stream DivArgs) returns (stream DivReply) { + } + + // Fib generates numbers in the Fibonacci sequence. If FibArgs.limit > 0, Fib + // generates up to limit numbers; otherwise it continues until the call is + // canceled. Unlike Fib above, Fib has no final FibReply. + rpc Fib (FibArgs) returns (stream Num) { + } + + // Sum sums a stream of numbers, returning the final result once the stream + // is closed. + rpc Sum (stream Num) returns (Num) { + } +} diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts new file mode 100644 index 000000000..0b2f0524d --- /dev/null +++ b/packages/grpc-js/test/test-server.ts @@ -0,0 +1,231 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any +import * as assert from 'assert'; +import * as fs from 'fs'; +import * as path from 'path'; + +import {ServerCredentials} from '../src'; +import {Server} from '../src/server'; + +import {loadProtoFile} from './common'; + +const ca = fs.readFileSync(path.join(__dirname, 'fixtures', 'ca.pem')); +const key = fs.readFileSync(path.join(__dirname, 'fixtures', 'server1.key')); +const cert = fs.readFileSync(path.join(__dirname, 'fixtures', 'server1.pem')); +function noop(): void {} + + +describe('Server', () => { + describe('constructor', () => { + it('should work with no arguments', () => { + assert.doesNotThrow(() => { + new Server(); // tslint:disable-line:no-unused-expression + }); + }); + + it('should work with an empty object argument', () => { + assert.doesNotThrow(() => { + new Server({}); // tslint:disable-line:no-unused-expression + }); + }); + + it('should be an instance of Server', () => { + const server = new Server(); + + assert(server instanceof Server); + }); + }); + + describe('bindAsync', () => { + it('binds with insecure credentials', (done) => { + const server = new Server(); + + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + assert(typeof port === 'number' && port > 0); + server.tryShutdown(done); + }); + }); + + it('binds with secure credentials', (done) => { + const server = new Server(); + const creds = ServerCredentials.createSsl( + ca, [{private_key: key, cert_chain: cert}], true); + + server.bindAsync('localhost:0', creds, (err, port) => { + assert.ifError(err); + assert(typeof port === 'number' && port > 0); + server.tryShutdown(done); + }); + }); + + it('throws if bind is called after the server is started', () => { + const server = new Server(); + + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + server.start(); + assert.throws(() => { + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), noop); + }, /server is already started/); + }); + }); + + it('throws on invalid inputs', () => { + const server = new Server(); + + assert.throws(() => { + server.bindAsync(null as any, ServerCredentials.createInsecure(), noop); + }, /port must be a string/); + + assert.throws(() => { + server.bindAsync('localhost:0', null as any, noop); + }, /creds must be an object/); + + assert.throws(() => { + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), null as any); + }, /callback must be a function/); + }); + }); + + describe('tryShutdown', () => { + it('calls back with an error if the server is not running', (done) => { + const server = new Server(); + + server.tryShutdown((err) => { + assert(err !== undefined && err.message === 'server is not running'); + done(); + }); + }); + }); + + describe('start', () => { + let server: Server; + + beforeEach((done) => { + server = new Server(); + server.bindAsync('localhost:0', ServerCredentials.createInsecure(), done); + }); + + afterEach((done) => { + server.tryShutdown(done); + }); + + it('starts without error', () => { + assert.doesNotThrow(() => { + server.start(); + }); + }); + + it('throws if started twice', () => { + server.start(); + assert.throws(() => { + server.start(); + }, /server is already started/); + }); + + it('throws if the server is not bound', () => { + const server = new Server(); + + assert.throws(() => { + server.start(); + }, /server must be bound in order to start/); + }); + }); + + describe('addService', () => { + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + const mathServiceAttrs = mathClient.service; + const dummyImpls = {div() {}, divMany() {}, fib() {}, sum() {}}; + const altDummyImpls = {Div() {}, DivMany() {}, Fib() {}, Sum() {}}; + + it('succeeds with a single service', () => { + const server = new Server(); + + assert.doesNotThrow(() => { + server.addService(mathServiceAttrs, dummyImpls); + }); + }); + + it('fails to add an empty service', () => { + const server = new Server(); + + assert.throws(() => { + server.addService({}, dummyImpls); + }, /Cannot add an empty service to a server/); + }); + + it('fails with conflicting method names', () => { + const server = new Server(); + + server.addService(mathServiceAttrs, dummyImpls); + assert.throws(() => { + server.addService(mathServiceAttrs, dummyImpls); + }, /Method handler for .+ already provided/); + }); + + it('supports method names as originally written', () => { + const server = new Server(); + + assert.doesNotThrow(() => { + server.addService(mathServiceAttrs, altDummyImpls); + }); + }); + + it('fails if the server has been started', (done) => { + const server = new Server(); + + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + server.start(); + assert.throws(() => { + server.addService(mathServiceAttrs, dummyImpls); + }, /Can't add a service to a started server\./); + server.tryShutdown(done); + }); + }); + }); + + it('throws when unimplemented methods are called', () => { + const server = new Server(); + + assert.throws(() => { + server.addProtoService(); + }, /Not implemented. Use addService\(\) instead/); + + assert.throws(() => { + server.forceShutdown(); + }, /Not yet implemented/); + + assert.throws(() => { + server.addHttp2Port(); + }, /Not yet implemented/); + + assert.throws(() => { + server.bind('localhost:0', ServerCredentials.createInsecure()); + }, /Not implemented. Use bindAsync\(\) instead/); + }); +}); From ac9615bbf5e49cbdddd9e69ca5a7d9c0c4d2de55 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 10 Apr 2019 16:44:33 -0700 Subject: [PATCH 0603/1899] Bump grpc-tools to 1.7.3 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 0ea9ccba3..a3ab689fb 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.7.2", + "version": "1.7.3", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 4b5391cdff3f79f181b1c3a0aea61dfc863cdbbd Mon Sep 17 00:00:00 2001 From: Jeremy Forsythe Date: Mon, 15 Apr 2019 16:33:03 -0400 Subject: [PATCH 0604/1899] Require @types/protobuf.js at version 5.x as a dependency --- packages/grpc-native-core/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index f849dde2a..22be2040c 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,6 +29,7 @@ "node-pre-gyp" ], "dependencies": { + "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.0.0", From dbb49fa9cf131ef19e915e8aface42507d585312 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 17 Apr 2019 09:31:45 -0700 Subject: [PATCH 0605/1899] Bump to v1.20.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index be1489504..ab1edb321 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.0-pre3"' + 'GRPC_NODE_VERSION="1.20.0"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 1b488f836..9dfbd34f5 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 1b488f8361234dddf1e48369b5dc482495fb3f9b +Subproject commit 9dfbd34f5c0b20bd77658c73c59b9a3e4e8f4e14 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 483728358..30c7f05ba 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.20.0-pre3", + "version": "1.20.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From b84f92d9310fd1fdaa7ffdcdcf596843d43502d7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 24 Apr 2019 00:02:54 +0200 Subject: [PATCH 0606/1899] Adding node 12. --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 2 +- run-tests.bat | 2 +- run-tests.sh | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 30c7f05ba..04323d720 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -32,7 +32,7 @@ "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.12.0", + "node-pre-gyp": "^0.13.0", "protobufjs": "^5.0.3" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 004711678..df17cd55c 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -34,7 +34,7 @@ "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.0.0", - "node-pre-gyp": "^0.12.0", + "node-pre-gyp": "^0.13.0", "protobufjs": "^5.0.3" }, "devDependencies": { diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 1c9064a99..7f862edc6 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 +set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 7ee81de84..42149d442 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 ) while true ; do case $1 in diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index 139d34328..ace0aff96 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -26,7 +26,7 @@ mkdir -p "${ARTIFACTS_OUT}" npm update -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 ) for version in ${node_versions[@]} do diff --git a/run-tests.bat b/run-tests.bat index f48ab4cbe..84a1eba0b 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (6 7 8 9 10 11) do ( +for %%v in (6 7 8 9 10 11 12) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index ff1caa2ec..8b9584205 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="6 7 8 9 10 11" + node_versions="6 7 8 9 10 11 12" fi set +ex From e15f45928376f667ccd14217455f167ef1c51d31 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 23 Apr 2019 16:30:50 -0700 Subject: [PATCH 0607/1899] Native: fix Node 12 compilation errors --- packages/grpc-native-core/ext/channel.cc | 2 +- packages/grpc-native-core/ext/channel_credentials.cc | 2 +- packages/grpc-native-core/ext/server_credentials.cc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index f23dbd58d..14293abdc 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -289,7 +289,7 @@ NAN_METHOD(Channel::GetConnectivityState) { return Nan::ThrowError( "Cannot call getConnectivityState on a closed Channel"); } - int try_to_connect = (int)info[0]->Equals(Nan::True()); + int try_to_connect = (int)info[0]->StrictEquals(Nan::True()); info.GetReturnValue().Set(grpc_channel_check_connectivity_state( channel->wrapped_channel, try_to_connect)); } diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc index a586b3e61..60184b2bf 100644 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ b/packages/grpc-native-core/ext/channel_credentials.cc @@ -194,7 +194,7 @@ NAN_METHOD(ChannelCredentials::CreateSsl) { if (!info[3]->IsObject()) { return Nan::ThrowTypeError("createSsl's fourth argument must be an object"); } - Local object = info[3]->ToObject(); + Local object = Nan::To(info[3]).ToLocalChecked(); Local checkServerIdentityValue = Nan::Get(object, Nan::New("checkServerIdentity").ToLocalChecked()).ToLocalChecked(); diff --git a/packages/grpc-native-core/ext/server_credentials.cc b/packages/grpc-native-core/ext/server_credentials.cc index 1ce86632c..fe26e3a91 100644 --- a/packages/grpc-native-core/ext/server_credentials.cc +++ b/packages/grpc-native-core/ext/server_credentials.cc @@ -66,7 +66,7 @@ void ServerCredentials::Init(Local exports) { Local tpl = Nan::New(New); tpl->SetClassName(Nan::New("ServerCredentials").ToLocalChecked()); tpl->InstanceTemplate()->SetInternalFieldCount(1); - Local ctr = tpl->GetFunction(); + Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); Nan::Set( ctr, Nan::New("createSsl").ToLocalChecked(), Nan::GetFunction(Nan::New(CreateSsl)).ToLocalChecked()); diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 30c7f05ba..4e9bcab3f 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -31,7 +31,7 @@ "dependencies": { "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", - "nan": "^2.0.0", + "nan": "^2.13.2", "node-pre-gyp": "^0.12.0", "protobufjs": "^5.0.3" }, From 29df5c0fc24e241cedc6914e0428b173428524ab Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 23 Apr 2019 16:36:53 -0700 Subject: [PATCH 0608/1899] Fix template --- packages/grpc-native-core/templates/package.json.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 004711678..5d0728cfe 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -33,7 +33,7 @@ "dependencies": { "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", - "nan": "^2.0.0", + "nan": "^2.13.2", "node-pre-gyp": "^0.12.0", "protobufjs": "^5.0.3" }, From 5a6d599605fe341ac4de3bfe4d7cd8ce1917bda9 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 24 Apr 2019 19:00:35 +0200 Subject: [PATCH 0609/1899] Fixing template. --- packages/grpc-native-core/templates/package.json.template | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 004711678..a233eaed8 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,6 +31,7 @@ "node-pre-gyp" ], "dependencies": { + "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.0.0", From df575488052e39c290c0845a2a40db1c767ff6ac Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Apr 2019 16:12:02 -0700 Subject: [PATCH 0610/1899] Update gulp to version 4, rewrite scripts --- gulpfile.ts | 111 ++++++------------ package.json | 6 +- .../{gulpfile.js => gulpfile.ts} | 51 ++++---- packages/grpc-js/gulpfile.ts | 49 ++++---- .../{gulpfile.js => gulpfile.ts} | 69 ++++++----- packages/proto-loader/gulpfile.ts | 44 ++++--- run-tests.bat | 4 +- run-tests.sh | 2 +- test/{gulpfile.js => gulpfile.ts} | 38 +++--- 9 files changed, 184 insertions(+), 190 deletions(-) rename packages/grpc-health-check/{gulpfile.js => gulpfile.ts} (55%) rename packages/grpc-native-core/{gulpfile.js => gulpfile.ts} (65%) rename test/{gulpfile.js => gulpfile.ts} (74%) diff --git a/gulpfile.ts b/gulpfile.ts index 50b10c033..2a4fc9140 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -15,96 +15,55 @@ * */ -import * as _gulp from 'gulp'; -import * as help from 'gulp-help'; - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const runSequence = require('run-sequence'); - -/** - * Require a module at the given path with a patched gulp object that prepends - * the given prefix to each task name. - * @param path The path to require. - * @param prefix The string to use as a prefix. This will be prepended to a task - * name with a '.' separator. - */ -function loadGulpTasksWithPrefix(path: string, prefix: string) { - const gulpTask = gulp.task; - gulp.task = ((taskName: string, ...args: any[]) => { - // Don't create a task for ${prefix}.help - if (taskName === 'help') { - return; - } - // The only array passed to gulp.task must be a list of dependent tasks. - const newArgs = args.map(arg => Array.isArray(arg) ? - arg.map(dep => `${prefix}.${dep}`) : arg); - gulpTask(`${prefix}.${taskName}`, ...newArgs); - }); - const result = require(path); - gulp.task = gulpTask; - return result; -} - -[ - ['./packages/grpc-health-check/gulpfile', 'health-check'], - ['./packages/grpc-js/gulpfile', 'js.core'], - ['./packages/grpc-native-core/gulpfile', 'native.core'], - ['./packages/proto-loader/gulpfile', 'protobuf'], - ['./test/gulpfile', 'internal.test'], -].forEach((args) => loadGulpTasksWithPrefix(args[0], args[1])); +import * as gulp from 'gulp'; +import * as healthCheck from './packages/grpc-health-check/gulpfile'; +import * as jsCore from './packages/grpc-js/gulpfile'; +import * as nativeCore from './packages/grpc-native-core/gulpfile'; +import * as protobuf from './packages/proto-loader/gulpfile'; +import * as internalTest from './test/gulpfile'; const root = __dirname; -gulp.task('install.all', 'Install dependencies for all subdirectory packages', - ['js.core.install', 'native.core.install', 'health-check.install', 'protobuf.install', 'internal.test.install']); +const installAll = gulp.parallel(jsCore.install, nativeCore.install, healthCheck.install, protobuf.install, internalTest.install); -gulp.task('install.all.windows', 'Install dependencies for all subdirectory packages for MS Windows', - ['js.core.install', 'native.core.install.windows', 'health-check.install', 'protobuf.install', 'internal.test.install']); +const installAllWindows = gulp.parallel(jsCore.install, nativeCore.installWindows, healthCheck.install, protobuf.install, internalTest.install); -gulp.task('lint', 'Emit linting errors in source and test files', - ['js.core.lint', 'native.core.lint']); +const lint = gulp.parallel(jsCore.lint, nativeCore.lint); -gulp.task('build', 'Build packages', ['js.core.compile', 'native.core.build', 'protobuf.compile']); +const build = gulp.parallel(jsCore.compile, nativeCore.build, protobuf.compile); -gulp.task('link.surface', 'Link to surface packages', - ['health-check.link.add']); +const link = gulp.series(healthCheck.linkAdd); -gulp.task('link', 'Link together packages', (callback) => { - /** - * We use workarounds for linking in some modules. See npm/npm#18835 - */ - runSequence('link.surface', callback); -}); +const setup = gulp.series(installAll, link); -gulp.task('setup', 'One-time setup for a clean repository', (callback) => { - runSequence('install.all', 'link', callback); -}); -gulp.task('setup.windows', 'One-time setup for a clean repository for MS Windows', (callback) => { - runSequence('install.all.windows', 'link', callback); -}); +const setupWindows = gulp.series(installAllWindows, link); -gulp.task('clean', 'Delete generated files', ['js.core.clean', 'native.core.clean', 'protobuf.clean']); +const clean = gulp.parallel(jsCore.clean, nativeCore.clean, protobuf.clean); -gulp.task('clean.all', 'Delete all files created by tasks', - ['js.core.clean.all', 'native.core.clean.all', 'health-check.clean.all', - 'internal.test.clean.all', 'protobuf.clean.all']); +const cleanAll = gulp.parallel(jsCore.cleanAll, nativeCore.cleanAll, healthCheck.cleanAll, internalTest.cleanAll, protobuf.cleanAll); -gulp.task('native.test.only', 'Run tests of native code without rebuilding anything', - ['native.core.test', 'health-check.test']); +const nativeTestOnly = gulp.parallel(nativeCore.test, healthCheck.test); -gulp.task('native.test', 'Run tests of native code', (callback) => { - runSequence('build', 'native.test.only', callback); -}); +const nativeTest = gulp.series(build, nativeTestOnly); -gulp.task('test.only', 'Run tests without rebuilding anything', - ['js.core.test', 'native.test.only', 'protobuf.test']); +const testOnly = gulp.parallel(jsCore.test, nativeTestOnly, protobuf.test); -gulp.task('test', 'Run all tests', (callback) => { - runSequence('build', 'test.only', 'internal.test.test', callback); -}); +const test = gulp.series(build, testOnly, internalTest.test); -gulp.task('doc.gen', 'Generate documentation', ['native.core.doc.gen']); +const docGen = gulp.series(nativeCore.docGen); -gulp.task('default', ['help']); +export { + installAll, + installAllWindows, + lint, + build, + link, + setup, + setupWindows, + clean, + cleanAll, + nativeTestOnly, + nativeTest, + test, + docGen +}; diff --git a/package.json b/package.json index 1ec8cc2cc..00c647ef3 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,6 @@ "devDependencies": { "@types/execa": "^0.8.0", "@types/gulp": "^4.0.5", - "@types/gulp-help": "0.0.34", "@types/gulp-mocha": "0.0.31", "@types/ncp": "^2.0.1", "@types/node": "^8.0.32", @@ -20,8 +19,7 @@ "coveralls": "^3.0.1", "del": "^3.0.0", "execa": "^0.8.0", - "gulp": "^3.9.1", - "gulp-help": "^1.6.1", + "gulp": "^4.0.1", "gulp-jsdoc3": "^1.0.1", "gulp-jshint": "^2.0.4", "gulp-mocha": "^4.3.1", @@ -42,7 +40,7 @@ "semver": "^5.5.0", "symlink": "^2.1.0", "through2": "^2.0.3", - "ts-node": "^3.3.0", + "ts-node": "^8.1.0", "tslint": "^5.5.0", "typescript": "~3.3.3333", "xml2js": "^0.4.19" diff --git a/packages/grpc-health-check/gulpfile.js b/packages/grpc-health-check/gulpfile.ts similarity index 55% rename from packages/grpc-health-check/gulpfile.js rename to packages/grpc-health-check/gulpfile.ts index 09ac91156..9f436dfdf 100644 --- a/packages/grpc-health-check/gulpfile.js +++ b/packages/grpc-health-check/gulpfile.ts @@ -1,5 +1,5 @@ /* - * Copyright 2017 gRPC authors. + * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,36 +15,41 @@ * */ -const _gulp = require('gulp'); -const help = require('gulp-help'); -const mocha = require('gulp-mocha'); -const execa = require('execa'); -const path = require('path'); -const del = require('del'); -const linkSync = require('../../util').linkSync; - -const gulp = help(_gulp); +import * as gulp from 'gulp'; +import * as mocha from 'gulp-mocha'; +import * as execa from 'execa'; +import * as path from 'path'; +import * as del from 'del'; +import linkSync from '../../util'; const healthCheckDir = __dirname; const baseDir = path.resolve(healthCheckDir, '..', '..'); const testDir = path.resolve(healthCheckDir, 'test'); -gulp.task('clean.links', 'Delete npm links', () => { +const cleanLinks = () => { return del(path.resolve(healthCheckDir, 'node_modules/grpc')); -}); +} -gulp.task('clean.all', 'Delete all code created by tasks', - ['clean.links']); +const cleanAll = gulp.parallel(cleanLinks); -gulp.task('install', 'Install health check dependencies', ['clean.links'], () => { +const runInstall = () => { return execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); -}); +}; -gulp.task('link.add', 'Link local copy of grpc', () => { - linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); -}); +const install = gulp.series(cleanLinks, runInstall); -gulp.task('test', 'Run health check tests', - () => { - return gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); - }); +const linkAdd = () => { + linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); +}; + +const test = () => { + return gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); +}; + +export { + cleanLinks, + cleanAll, + install, + linkAdd, + test +} \ No newline at end of file diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts index 72434d5ba..f06264053 100644 --- a/packages/grpc-js/gulpfile.ts +++ b/packages/grpc-js/gulpfile.ts @@ -15,8 +15,7 @@ * */ -import * as _gulp from 'gulp'; -import * as help from 'gulp-help'; +import * as gulp from 'gulp'; import * as fs from 'fs'; import * as mocha from 'gulp-mocha'; @@ -26,9 +25,6 @@ import * as pify from 'pify'; import * as semver from 'semver'; import { ncp } from 'ncp'; -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - const ncpP = pify(ncp); Error.stackTraceLimit = Infinity; @@ -44,34 +40,36 @@ const execNpmVerb = (verb: string, ...args: string[]) => execa('npm', [verb, ...args], {cwd: jsCoreDir, stdio: 'inherit'}); const execNpmCommand = execNpmVerb.bind(null, 'run'); -gulp.task('install', 'Install native core dependencies', () => - execNpmVerb('install', '--unsafe-perm')); +const install = () => { + execNpmVerb('install', '--unsafe-perm'); +}; /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ -gulp.task('lint', 'Emits linting errors found in src/ and test/.', () => - execNpmCommand('check')); +const lint = () => { + execNpmCommand('check'); +}; -gulp.task('clean', 'Deletes transpiled code.', ['install'], - () => execNpmCommand('clean')); +const clean = () => { + execNpmCommand('clean'); +}; -gulp.task('clean.all', 'Deletes all files added by targets', ['clean']); +const cleanAll = gulp.parallel(clean); /** * Transpiles TypeScript files in src/ to JavaScript according to the settings * found in tsconfig.json. */ -gulp.task('compile', 'Transpiles src/.', () => execNpmCommand('compile')); +const compile = () => { + execNpmCommand('compile'); +} -gulp.task('copy-test-fixtures', 'Copy test fixtures.', () => { +const copyTestFixtures = () => { return ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`); -}); +} -/** - * Transpiles src/ and test/, and then runs all tests. - */ -gulp.task('test', 'Runs all tests.', ['lint', 'copy-test-fixtures'], () => { +const runTests = () => { if (semver.satisfies(process.version, '^8.11.2 || >=9.4')) { return gulp.src(`${outDir}/test/**/*.js`) .pipe(mocha({reporter: 'mocha-jenkins-reporter', @@ -80,4 +78,15 @@ gulp.task('test', 'Runs all tests.', ['lint', 'copy-test-fixtures'], () => { console.log(`Skipping grpc-js tests for Node ${process.version}`); return Promise.resolve(null); } -}); +}; + +const test = gulp.series(install, copyTestFixtures, runTests); + +export { + install, + lint, + clean, + cleanAll, + compile, + test +} \ No newline at end of file diff --git a/packages/grpc-native-core/gulpfile.js b/packages/grpc-native-core/gulpfile.ts similarity index 65% rename from packages/grpc-native-core/gulpfile.js rename to packages/grpc-native-core/gulpfile.ts index 8e32d743a..4828981c6 100644 --- a/packages/grpc-native-core/gulpfile.js +++ b/packages/grpc-native-core/gulpfile.ts @@ -1,5 +1,5 @@ /* - * Copyright 2017 gRPC authors. + * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,13 @@ * */ -const _gulp = require('gulp'); -const help = require('gulp-help'); - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - -const jsdoc = require('gulp-jsdoc3'); -const jshint = require('gulp-jshint'); -const mocha = require('gulp-mocha'); -const execa = require('execa'); -const path = require('path'); -const del = require('del'); + import * as gulp from 'gulp'; + import * as jsdoc from 'gulp-jsdoc3'; + import * as jshint from 'gulp-jshint'; + import * as mocha from 'gulp-mocha'; + import * as execa from 'execa'; + import * as path from 'path'; + import * as del from 'del'; const nativeCoreDir = __dirname; const srcDir = path.resolve(nativeCoreDir, 'src'); @@ -35,44 +30,56 @@ const testDir = path.resolve(nativeCoreDir, 'test'); const pkg = require('./package'); const jshintConfig = pkg.jshintConfig; -gulp.task('clean', 'Delete generated files', () => { +const clean = () => { return del([path.resolve(nativeCoreDir, 'build'), - path.resolve(nativeCoreDir, 'ext/node')]); -}); + path.resolve(nativeCoreDir, 'ext/node')]); +}; -gulp.task('clean.all', 'Delete all files created by tasks', - ['clean']); +const cleanAll = gulp.parallel(clean); -gulp.task('install', 'Install native core dependencies', () => { +const install = () => { return execa('npm', ['install', '--build-from-source', '--unsafe-perm'], {cwd: nativeCoreDir, stdio: 'inherit'}); -}); +}; -gulp.task('install.windows', 'Install native core dependencies for MS Windows', () => { +const installWindows = () => { return execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}).catch(() => del(path.resolve(process.env.USERPROFILE, '.node-gyp', process.versions.node, 'include/node/openssl'), { force: true }).then(() => execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}) - )) -}); + )); +}; -gulp.task('lint', 'Emits linting errors', () => { +const lint = () => { return gulp.src([`${nativeCoreDir}/index.js`, `${srcDir}/*.js`, `${testDir}/*.js`]) .pipe(jshint(pkg.jshintConfig)) .pipe(jshint.reporter('default')); -}); +}; -gulp.task('build', 'Build native package', () => { +const build = () => { return execa('npm', ['run', 'build'], {cwd: nativeCoreDir, stdio: 'inherit'}); -}); +}; -gulp.task('test', 'Run all tests', ['build'], () => { +const runTests = () => { return gulp.src(`${testDir}/*.js`).pipe(mocha({timeout: 5000, reporter: 'mocha-jenkins-reporter'})); -}); +} -gulp.task('doc.gen', 'Generate docs', (cb) => { +const test = gulp.series(build, runTests); + +const docGen = (cb) => { var config = require('./jsdoc_conf.json'); gulp.src([`${nativeCoreDir}/README.md`, `${nativeCoreDir}/index.js`, `${srcDir}/*.js`], {read: false}) .pipe(jsdoc(config, cb)); -}); +}; + +export { + clean, + cleanAll, + install, + installWindows, + lint, + build, + test, + docGen +}; \ No newline at end of file diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index 42ea1313d..21bb7fde2 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -15,8 +15,7 @@ * */ -import * as _gulp from 'gulp'; -import * as help from 'gulp-help'; +import * as gulp from 'gulp'; import * as fs from 'fs'; import * as mocha from 'gulp-mocha'; @@ -24,9 +23,6 @@ import * as path from 'path'; import * as execa from 'execa'; import * as semver from 'semver'; -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); - Error.stackTraceLimit = Infinity; const protojsDir = __dirname; @@ -40,30 +36,37 @@ const execNpmVerb = (verb: string, ...args: string[]) => execa('npm', [verb, ...args], {cwd: protojsDir, stdio: 'inherit'}); const execNpmCommand = execNpmVerb.bind(null, 'run'); -gulp.task('install', 'Install native core dependencies', () => - execNpmVerb('install', '--unsafe-perm')); +const install = () => { + execNpmVerb('install', '--unsafe-perm'); +}; /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ -gulp.task('lint', 'Emits linting errors found in src/ and test/.', () => - execNpmCommand('check')); +const lint = () => { + execNpmCommand('check'); +}; + +const cleanFiles = () => { + execNpmCommand('clean'); +}; -gulp.task('clean', 'Deletes transpiled code.', ['install'], - () => execNpmCommand('clean')); +const clean = gulp.series(install, cleanFiles); -gulp.task('clean.all', 'Deletes all files added by targets', ['clean']); +const cleanAll = gulp.parallel(clean); /** * Transpiles TypeScript files in src/ and test/ to JavaScript according to the settings * found in tsconfig.json. */ -gulp.task('compile', 'Transpiles src/ and test/.', () => execNpmCommand('compile')); +const compile = () => { + execNpmCommand('compile'); +}; /** * Transpiles src/ and test/, and then runs all tests. */ -gulp.task('test', 'Runs all tests.', () => { +const runTests = () => { if (semver.satisfies(process.version, ">=6")) { return gulp.src(`${outDir}/test/**/*.js`) .pipe(mocha({reporter: 'mocha-jenkins-reporter', @@ -72,4 +75,15 @@ gulp.task('test', 'Runs all tests.', () => { console.log(`Skipping proto-loader tests for Node ${process.version}`); return Promise.resolve(null); } -}); +} + +const test = gulp.series(install, runTests); + +export { + install, + lint, + clean, + cleanAll, + compile, + test +} diff --git a/run-tests.bat b/run-tests.bat index f48ab4cbe..d7fb4cbb4 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -53,8 +53,8 @@ for %%v in (6 7 8 9 10 11) do ( node -e "process.exit(process.version.startsWith('v%%v') ? 0 : -1)" || goto :error - call .\node_modules\.bin\gulp clean.all || SET FAILED=1 - call .\node_modules\.bin\gulp setup.windows || SET FAILED=1 + call .\node_modules\.bin\gulp cleanAll || SET FAILED=1 + call .\node_modules\.bin\gulp setupWindows || SET FAILED=1 call .\node_modules\.bin\gulp test || SET FAILED=1 ) diff --git a/run-tests.sh b/run-tests.sh index ff1caa2ec..fb3a27d6e 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -68,7 +68,7 @@ do node -e 'process.exit(process.version.startsWith("v'$version'") ? 0 : -1)' # Install dependencies and link packages together. - ./node_modules/.bin/gulp clean.all + ./node_modules/.bin/gulp cleanAll ./node_modules/.bin/gulp setup # npm test calls nyc gulp test diff --git a/test/gulpfile.js b/test/gulpfile.ts similarity index 74% rename from test/gulpfile.js rename to test/gulpfile.ts index 42ff04f0d..73843354d 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.ts @@ -1,5 +1,5 @@ /* - * Copyright 2017 gRPC authors. + * Copyright 2019 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,28 +15,24 @@ * */ -const _gulp = require('gulp'); -const help = require('gulp-help'); -const mocha = require('gulp-mocha'); -const execa = require('execa'); -const path = require('path'); -const del = require('del'); -const semver = require('semver'); -const linkSync = require('../util').linkSync; - -// gulp-help monkeypatches tasks to have an additional description parameter -const gulp = help(_gulp); +import * as gulp from 'gulp'; +import * as mocha from 'gulp-mocha'; +import * as execa from 'execa'; +import * as path from 'path'; +import * as del from 'del'; +import * as semver from 'semver'; +import linkSync from '../util'; const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); -gulp.task('install', 'Install test dependencies', () => { +const install = () => { return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); -}); +}; -gulp.task('clean.all', 'Delete all files created by tasks', () => {}); +const cleanAll = () => {}; -gulp.task('test', 'Run API-level tests', () => { +const test = () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream if (!semver.satisfies(process.version, '>=9.4')) { @@ -50,7 +46,7 @@ gulp.task('test', 'Run API-level tests', () => { gulp.src(apiTestGlob) .pipe(mocha({ reporter: 'mocha-jenkins-reporter', - require: `${testDir}/fixtures/${fixture}.js` + require: [`${testDir}/fixtures/${fixture}.js`] })) .resume() // put the stream in flowing mode .on('end', resolve) @@ -72,4 +68,10 @@ gulp.task('test', 'Run API-level tests', () => { return runTestsArgPairs.reduce((previousPromise, argPair) => { return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); }, Promise.resolve()); -}); +}; + +export { + install, + cleanAll, + test +}; \ No newline at end of file From 2ef046e96f8009d87b58890a351704ad0f1ef0d7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Apr 2019 16:54:03 -0700 Subject: [PATCH 0611/1899] Properly signal task completion in gulpfiles --- packages/grpc-health-check/gulpfile.ts | 16 ++++------------ packages/grpc-js/gulpfile.ts | 20 +++++--------------- packages/grpc-native-core/gulpfile.ts | 10 ++++------ packages/proto-loader/gulpfile.ts | 18 ++++-------------- test/gulpfile.ts | 2 +- 5 files changed, 18 insertions(+), 48 deletions(-) diff --git a/packages/grpc-health-check/gulpfile.ts b/packages/grpc-health-check/gulpfile.ts index 9f436dfdf..28e21dc66 100644 --- a/packages/grpc-health-check/gulpfile.ts +++ b/packages/grpc-health-check/gulpfile.ts @@ -26,25 +26,17 @@ const healthCheckDir = __dirname; const baseDir = path.resolve(healthCheckDir, '..', '..'); const testDir = path.resolve(healthCheckDir, 'test'); -const cleanLinks = () => { - return del(path.resolve(healthCheckDir, 'node_modules/grpc')); -} +const cleanLinks = () => del(path.resolve(healthCheckDir, 'node_modules/grpc')); const cleanAll = gulp.parallel(cleanLinks); -const runInstall = () => { - return execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); -}; +const runInstall = () => execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); const install = gulp.series(cleanLinks, runInstall); -const linkAdd = () => { - linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); -}; +const linkAdd = () => linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); -const test = () => { - return gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); -}; +const test = () => gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); export { cleanLinks, diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts index f06264053..817b2a365 100644 --- a/packages/grpc-js/gulpfile.ts +++ b/packages/grpc-js/gulpfile.ts @@ -40,20 +40,14 @@ const execNpmVerb = (verb: string, ...args: string[]) => execa('npm', [verb, ...args], {cwd: jsCoreDir, stdio: 'inherit'}); const execNpmCommand = execNpmVerb.bind(null, 'run'); -const install = () => { - execNpmVerb('install', '--unsafe-perm'); -}; +const install = () => execNpmVerb('install', '--unsafe-perm'); /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ -const lint = () => { - execNpmCommand('check'); -}; +const lint = () => execNpmCommand('check'); -const clean = () => { - execNpmCommand('clean'); -}; +const clean = () => execNpmCommand('clean'); const cleanAll = gulp.parallel(clean); @@ -61,13 +55,9 @@ const cleanAll = gulp.parallel(clean); * Transpiles TypeScript files in src/ to JavaScript according to the settings * found in tsconfig.json. */ -const compile = () => { - execNpmCommand('compile'); -} +const compile = () => execNpmCommand('compile'); -const copyTestFixtures = () => { - return ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`); -} +const copyTestFixtures = () => ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`); const runTests = () => { if (semver.satisfies(process.version, '^8.11.2 || >=9.4')) { diff --git a/packages/grpc-native-core/gulpfile.ts b/packages/grpc-native-core/gulpfile.ts index 4828981c6..cfb601d0c 100644 --- a/packages/grpc-native-core/gulpfile.ts +++ b/packages/grpc-native-core/gulpfile.ts @@ -30,10 +30,8 @@ const testDir = path.resolve(nativeCoreDir, 'test'); const pkg = require('./package'); const jshintConfig = pkg.jshintConfig; -const clean = () => { - return del([path.resolve(nativeCoreDir, 'build'), - path.resolve(nativeCoreDir, 'ext/node')]); -}; +const clean = () => del([path.resolve(nativeCoreDir, 'build'), + path.resolve(nativeCoreDir, 'ext/node')]); const cleanAll = gulp.parallel(clean); @@ -69,8 +67,8 @@ const test = gulp.series(build, runTests); const docGen = (cb) => { var config = require('./jsdoc_conf.json'); - gulp.src([`${nativeCoreDir}/README.md`, `${nativeCoreDir}/index.js`, `${srcDir}/*.js`], {read: false}) - .pipe(jsdoc(config, cb)); + return gulp.src([`${nativeCoreDir}/README.md`, `${nativeCoreDir}/index.js`, `${srcDir}/*.js`], {read: false}) + .pipe(jsdoc(config, cb)); }; export { diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index 21bb7fde2..04fd131b6 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -36,22 +36,14 @@ const execNpmVerb = (verb: string, ...args: string[]) => execa('npm', [verb, ...args], {cwd: protojsDir, stdio: 'inherit'}); const execNpmCommand = execNpmVerb.bind(null, 'run'); -const install = () => { - execNpmVerb('install', '--unsafe-perm'); -}; +const install = () => execNpmVerb('install', '--unsafe-perm'); /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ -const lint = () => { - execNpmCommand('check'); -}; +const lint = () => execNpmCommand('check'); -const cleanFiles = () => { - execNpmCommand('clean'); -}; - -const clean = gulp.series(install, cleanFiles); +const clean = () => execNpmCommand('clean'); const cleanAll = gulp.parallel(clean); @@ -59,9 +51,7 @@ const cleanAll = gulp.parallel(clean); * Transpiles TypeScript files in src/ and test/ to JavaScript according to the settings * found in tsconfig.json. */ -const compile = () => { - execNpmCommand('compile'); -}; +const compile = () => execNpmCommand('compile'); /** * Transpiles src/ and test/, and then runs all tests. diff --git a/test/gulpfile.ts b/test/gulpfile.ts index 73843354d..3fde9d9eb 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -30,7 +30,7 @@ const install = () => { return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); }; -const cleanAll = () => {}; +const cleanAll = () => Promise.resolve(); const test = () => { // run mocha tests matching a glob with a pre-required fixture, From 1b64626cbb8f8859b3784ea04165c6988aedcacd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Apr 2019 17:06:23 -0700 Subject: [PATCH 0612/1899] Fix missing clean deps --- packages/grpc-js/gulpfile.ts | 4 +++- packages/proto-loader/gulpfile.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts index 817b2a365..b3b576aa4 100644 --- a/packages/grpc-js/gulpfile.ts +++ b/packages/grpc-js/gulpfile.ts @@ -47,7 +47,9 @@ const install = () => execNpmVerb('install', '--unsafe-perm'); */ const lint = () => execNpmCommand('check'); -const clean = () => execNpmCommand('clean'); +const cleanFiles = () => execNpmCommand('clean'); + +const clean = gulp.series(install, cleanFiles); const cleanAll = gulp.parallel(clean); diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index 04fd131b6..ff8f08552 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -43,7 +43,9 @@ const install = () => execNpmVerb('install', '--unsafe-perm'); */ const lint = () => execNpmCommand('check'); -const clean = () => execNpmCommand('clean'); +const cleanFiles = () => execNpmCommand('clean'); + +const clean = gulp.series(install, cleanFiles); const cleanAll = gulp.parallel(clean); From 4db3ee23313cd4369cffde3942e54467e3b3db42 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Apr 2019 17:32:59 -0700 Subject: [PATCH 0613/1899] Fix bad import --- packages/grpc-health-check/gulpfile.ts | 2 +- test/gulpfile.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-health-check/gulpfile.ts b/packages/grpc-health-check/gulpfile.ts index 28e21dc66..54ac624f2 100644 --- a/packages/grpc-health-check/gulpfile.ts +++ b/packages/grpc-health-check/gulpfile.ts @@ -20,7 +20,7 @@ import * as mocha from 'gulp-mocha'; import * as execa from 'execa'; import * as path from 'path'; import * as del from 'del'; -import linkSync from '../../util'; +import {linkSync} from '../../util'; const healthCheckDir = __dirname; const baseDir = path.resolve(healthCheckDir, '..', '..'); diff --git a/test/gulpfile.ts b/test/gulpfile.ts index 3fde9d9eb..baac14740 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -21,7 +21,7 @@ import * as execa from 'execa'; import * as path from 'path'; import * as del from 'del'; import * as semver from 'semver'; -import linkSync from '../util'; +import {linkSync} from '../util'; const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); From 42d9658283e4a97fbdfa9fc08f4930a7d176cb01 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 24 Apr 2019 17:44:49 -0700 Subject: [PATCH 0614/1899] Fix usage of linkSync --- packages/grpc-health-check/gulpfile.ts | 5 ++++- test/gulpfile.ts | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-health-check/gulpfile.ts b/packages/grpc-health-check/gulpfile.ts index 54ac624f2..c01f133d5 100644 --- a/packages/grpc-health-check/gulpfile.ts +++ b/packages/grpc-health-check/gulpfile.ts @@ -34,7 +34,10 @@ const runInstall = () => execa('npm', ['install', '--unsafe-perm'], {cwd: health const install = gulp.series(cleanLinks, runInstall); -const linkAdd = () => linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); +const linkAdd = (callback) => { + linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); + callback(); +} const test = () => gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); diff --git a/test/gulpfile.ts b/test/gulpfile.ts index baac14740..c903675f5 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -21,7 +21,6 @@ import * as execa from 'execa'; import * as path from 'path'; import * as del from 'del'; import * as semver from 'semver'; -import {linkSync} from '../util'; const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); From 39f5e89ee1ab7fafff66c3361e3033c0d16635dd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 Apr 2019 09:29:54 -0700 Subject: [PATCH 0615/1899] Fix bad return when skipping tests --- test/gulpfile.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/gulpfile.ts b/test/gulpfile.ts index c903675f5..b6904df7e 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -36,7 +36,7 @@ const test = () => { // returning the associated gulp stream if (!semver.satisfies(process.version, '>=9.4')) { console.log(`Skipping cross-implementation tests for Node ${process.version}`); - return; + return Promise.resolve(); } const apiTestGlob = `${apiTestDir}/*.js`; const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { From 29fb20c30d8accdce4fa45c11c4edb447b9b7ad0 Mon Sep 17 00:00:00 2001 From: Jeremy Forsythe Date: Mon, 15 Apr 2019 16:33:03 -0400 Subject: [PATCH 0616/1899] Require @types/protobuf.js at version 5.x as a dependency --- packages/grpc-native-core/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 4e9bcab3f..d6a5c17c7 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,6 +29,7 @@ "node-pre-gyp" ], "dependencies": { + "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", From 85c9a4ef84bc085d28733f839b5200316c3e0b81 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 24 Apr 2019 19:00:35 +0200 Subject: [PATCH 0617/1899] Fixing template. --- packages/grpc-native-core/templates/package.json.template | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 5d0728cfe..88be5321b 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,6 +31,7 @@ "node-pre-gyp" ], "dependencies": { + "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", From e3c82565ef55f328ee35d4d762b290c7de32291b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 25 Apr 2019 18:09:27 -0700 Subject: [PATCH 0618/1899] Update to 1.20.1 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index ab1edb321..bef04a416 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.0"' + 'GRPC_NODE_VERSION="1.20.1"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 9dfbd34f5..7741e806a 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 9dfbd34f5c0b20bd77658c73c59b9a3e4e8f4e14 +Subproject commit 7741e806a213cba63c96234f16d712a8aa101a49 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 404dcec6b..1ccc70b8d 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.20.0", + "version": "1.20.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 37ca72b228878ee14487ab398ee165dd8e588f80 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 26 Apr 2019 17:44:29 -0400 Subject: [PATCH 0619/1899] gitignore Node's bash completion file This file is generated by newer versions of Node, and can show up in multiple locations. --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 23866bfd4..eb5696caf 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,6 @@ package-lock.json # Test generated files coverage + +# Node's bash completion file +.node_bash_completion From 406c1d0a9705674ea7ecb0b7975f64a114a83d89 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 26 Apr 2019 17:54:02 -0400 Subject: [PATCH 0620/1899] grpc-js: don't export private symbol The kChannel symbol was being exported due to a TypeScript issue. That issue has been resolved, so it seems OK to remove the export. --- packages/grpc-js/src/client.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 83f07c4e5..c934e4650 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -24,9 +24,7 @@ import {ChannelOptions} from './channel-options'; import {Status} from './constants'; import {Metadata} from './metadata'; -// This symbol must be exported (for now). -// See: https://github.com/Microsoft/TypeScript/issues/20080 -export const kChannel = Symbol(); +const kChannel = Symbol(); export interface UnaryCallback { (err: ServiceError|null, value?: ResponseType): void; From 3b48603697dbc6c356e899f2d987784cb7d05a86 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 26 Apr 2019 14:57:23 -0700 Subject: [PATCH 0621/1899] Revert "Protobufjs typescript types backport" --- packages/grpc-native-core/package.json | 1 - packages/grpc-native-core/templates/package.json.template | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 1ccc70b8d..2bb7109d7 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,7 +29,6 @@ "node-pre-gyp" ], "dependencies": { - "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 9949797c0..eec6f7cef 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,7 +31,6 @@ "node-pre-gyp" ], "dependencies": { - "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", From 280cfb55077e673e95fe543ab4e59f2f195fd688 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 26 Apr 2019 15:10:09 -0700 Subject: [PATCH 0622/1899] Bump to 1.20.2 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index bef04a416..c4f9f4d3b 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.1"' + 'GRPC_NODE_VERSION="1.20.2"' ], 'conditions': [ ['grpc_gcov=="true"', { diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..d0305f30b 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.20.2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 1ccc70b8d..a46cbe4e5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.20.1", + "version": "1.20.2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 7ca94b569d75dbcf76a803c9cdce29653251d948 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 26 Apr 2019 18:02:34 -0400 Subject: [PATCH 0623/1899] grpc-js: require non-experimental http2 This commit bumps the required semver range to versions of Node that include a non-experimental http2 module. --- PACKAGE-COMPARISON.md | 4 ++-- packages/grpc-js/gulpfile.ts | 2 +- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/index.ts | 2 +- test/gulpfile.js | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 2b32adaff..1fe2848d9 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -22,7 +22,7 @@ Load Balancing | :heavy_check_mark: | :x: Other Properties | `grpc` | `@grpc/grpc-js` -----------------|--------|---------------- Pure JavaScript Code | :x: | :heavy_check_mark: -Supported Node Versions | >= 4 | ^8.11.2 or >=9.4 +Supported Node Versions | >= 4 | ^8.13.0 or >=10.10.0 Supported Electron Versions | All | >= 3 Supported Platforms | Linux, Windows, MacOS | All Supported Architectures | x86, x86-64, ARM7+ | All @@ -36,4 +36,4 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.keepalive_time_ms` - `grpc.keepalive_timeout_ms` - `channelOverride` - - `channelFactoryOverride` \ No newline at end of file + - `channelFactoryOverride` diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts index 72434d5ba..693c94939 100644 --- a/packages/grpc-js/gulpfile.ts +++ b/packages/grpc-js/gulpfile.ts @@ -72,7 +72,7 @@ gulp.task('copy-test-fixtures', 'Copy test fixtures.', () => { * Transpiles src/ and test/, and then runs all tests. */ gulp.task('test', 'Runs all tests.', ['lint', 'copy-test-fixtures'], () => { - if (semver.satisfies(process.version, '^8.11.2 || >=9.4')) { + if (semver.satisfies(process.version, '^8.13.0 || >=10.10.0')) { return gulp.src(`${outDir}/test/**/*.js`) .pipe(mocha({reporter: 'mocha-jenkins-reporter', require: ['ts-node/register']})); diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 78e33f27a..0ced2f552 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -6,7 +6,7 @@ "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", "main": "build/src/index.js", "engines": { - "node": "^8.11.2 || >=9.4" + "node": "^8.13.0 || >=10.10.0" }, "keywords": [], "author": { diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 49437e4db..f78ecdd71 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -30,7 +30,7 @@ import {Metadata} from './metadata'; import {KeyCertPair, ServerCredentials} from './server-credentials'; import {StatusBuilder} from './status-builder'; -const supportedNodeVersions = '^8.11.2 || >=9.4'; +const supportedNodeVersions = '^8.13.0 || >=10.10.0'; if (!semver.satisfies(process.version, supportedNodeVersions)) { throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); } diff --git a/test/gulpfile.js b/test/gulpfile.js index 42ff04f0d..d05ed16c9 100644 --- a/test/gulpfile.js +++ b/test/gulpfile.js @@ -39,7 +39,7 @@ gulp.task('clean.all', 'Delete all files created by tasks', () => {}); gulp.task('test', 'Run API-level tests', () => { // run mocha tests matching a glob with a pre-required fixture, // returning the associated gulp stream - if (!semver.satisfies(process.version, '>=9.4')) { + if (!semver.satisfies(process.version, '>=10.10.0')) { console.log(`Skipping cross-implementation tests for Node ${process.version}`); return; } @@ -57,7 +57,7 @@ gulp.task('test', 'Run API-level tests', () => { .on('error', reject); }); var runTestsArgPairs; - if (semver.satisfies(process.version, '^ 8.11.2 || >=9.4')) { + if (semver.satisfies(process.version, '^8.13.0 || >=10.10.0')) { runTestsArgPairs = [ ['native', 'native'], ['native', 'js'], From 8a183c1f31837a68d7b9830f820dfebc2117f4ae Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 26 Apr 2019 19:33:29 -0400 Subject: [PATCH 0624/1899] grpc-js: rename kChannel symbol This commit renames the kChannel symbol to follow the repo's style conventions for constants (although a symbol may not strictly qualify as a constant). --- packages/grpc-js/src/client.ts | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index c934e4650..a793cf6f5 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -24,7 +24,7 @@ import {ChannelOptions} from './channel-options'; import {Status} from './constants'; import {Metadata} from './metadata'; -const kChannel = Symbol(); +const CHANNEL_SYMBOL = Symbol(); export interface UnaryCallback { (err: ServiceError|null, value?: ResponseType): void; @@ -50,26 +50,26 @@ export type ClientOptions = Partial&{ * clients. */ export class Client { - private readonly[kChannel]: Channel; + private readonly[CHANNEL_SYMBOL]: Channel; constructor( address: string, credentials: ChannelCredentials, options: ClientOptions = {}) { if (options.channelOverride) { - this[kChannel] = options.channelOverride; + this[CHANNEL_SYMBOL] = options.channelOverride; } else if (options.channelFactoryOverride) { - this[kChannel] = + this[CHANNEL_SYMBOL] = options.channelFactoryOverride(address, credentials, options); } else { - this[kChannel] = new Http2Channel(address, credentials, options); + this[CHANNEL_SYMBOL] = new Http2Channel(address, credentials, options); } } close(): void { - this[kChannel].close(); + this[CHANNEL_SYMBOL].close(); } getChannel(): Channel { - return this[kChannel]; + return this[CHANNEL_SYMBOL]; } waitForReady(deadline: Deadline, callback: (error?: Error) => void): void { @@ -80,7 +80,7 @@ export class Client { } let newState; try { - newState = this[kChannel].getConnectivityState(true); + newState = this[CHANNEL_SYMBOL].getConnectivityState(true); } catch (e) { callback(new Error('The channel has been closed')); return; @@ -89,7 +89,8 @@ export class Client { callback(); } else { try { - this[kChannel].watchConnectivityState(newState, deadline, checkState); + this[CHANNEL_SYMBOL].watchConnectivityState( + newState, deadline, checkState); } catch (e) { callback(new Error('The channel has been closed')); } @@ -186,7 +187,7 @@ export class Client { ({metadata, options, callback} = this.checkOptionalUnaryResponseArguments( metadata, options, callback)); - const call: Call = this[kChannel].createCall( + const call: Call = this[CHANNEL_SYMBOL].createCall( method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); @@ -227,7 +228,7 @@ export class Client { ({metadata, options, callback} = this.checkOptionalUnaryResponseArguments( metadata, options, callback)); - const call: Call = this[kChannel].createCall( + const call: Call = this[CHANNEL_SYMBOL].createCall( method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); @@ -275,7 +276,7 @@ export class Client { metadata?: Metadata|CallOptions, options?: CallOptions): ClientReadableStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); - const call: Call = this[kChannel].createCall( + const call: Call = this[CHANNEL_SYMBOL].createCall( method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); @@ -302,7 +303,7 @@ export class Client { metadata?: Metadata|CallOptions, options?: CallOptions): ClientDuplexStream { ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); - const call: Call = this[kChannel].createCall( + const call: Call = this[CHANNEL_SYMBOL].createCall( method, options.deadline, options.host, null, options.propagate_flags); if (options.credentials) { call.setCredentials(options.credentials); From 919d11114585ecef0be47552f6b29020df1cc8b2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 1 May 2019 13:45:55 -0700 Subject: [PATCH 0625/1899] Build Electron 5 artifacts --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 1575b7cea..95ca024d7 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 5.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index 7d1281273..6eb650148 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 5.0.0 ) umask 022 From 32c18a49562d787773e810f15855db03b729bdd1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 2 May 2019 11:06:29 -0700 Subject: [PATCH 0626/1899] Explicitly undefine OPENSSL_THREADS in binding.gyp --- packages/grpc-native-core/binding.gyp | 3 +++ packages/grpc-native-core/templates/binding.gyp.template | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index c4f9f4d3b..07d2d40c2 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -93,6 +93,9 @@ 'GRPC_UV', 'GRPC_NODE_VERSION="1.20.2"' ], + 'defines!': [ + 'OPENSSL_THREADS' + ], 'conditions': [ ['grpc_gcov=="true"', { 'cflags': [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 9ec471a65..bc9041421 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -85,6 +85,9 @@ 'GRPC_UV', 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"' ], + 'defines!': [ + 'OPENSSL_THREADS' + ], 'conditions': [ ['grpc_gcov=="true"', { % for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines'), ('LDFLAGS', 'ldflags')]: From 8f2fac7f70dbf0fb4c89b9da8e049922c35bde0c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 2 May 2019 11:31:22 -0700 Subject: [PATCH 0627/1899] Add some helpful information to the fallback error when loading addon --- packages/grpc-native-core/src/grpc_extension.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/src/grpc_extension.js b/packages/grpc-native-core/src/grpc_extension.js index 9a023b7c3..41ce389bb 100644 --- a/packages/grpc-native-core/src/grpc_extension.js +++ b/packages/grpc-native-core/src/grpc_extension.js @@ -54,6 +54,7 @@ Original error: ${e.message}`; error.code = e.code; throw error; } else { + e.message = `Failed to load ${binding_path}. ${e.message}`; throw e; } } From 7a0a238de9cb5da135cae14abf55cbcc290f4413 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 2 May 2019 12:52:07 -0700 Subject: [PATCH 0628/1899] Update to 1.20.3 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 07d2d40c2..ae64cb4fe 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.2"' + 'GRPC_NODE_VERSION="1.20.3"' ], 'defines!': [ 'OPENSSL_THREADS' diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index d0305f30b..74cb99d9d 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.20.2 + node_version: 1.20.3 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index bdf2f94e2..e14fcea51 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.20.2", + "version": "1.20.3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 6ff835201ac5f4daf4b1966323e4ea7df7c5b12e Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 2 May 2019 12:53:00 -0700 Subject: [PATCH 0629/1899] grpc-js: export more types We (`google-gax`) need these two types exported to switch from C-core gRPC. --- packages/grpc-js/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index f78ecdd71..e9a46dd27 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -248,3 +248,6 @@ export const InterceptorBuilder = () => { export const InterceptingCall = () => { throw new Error('Not yet implemented'); }; + +export { ChannelCredentials } from './channel-credentials'; +export { GrpcObject } from './make-client'; From fc336307c8363e565ebe934bd013f773d8ed5bce Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 2 May 2019 12:56:24 -0700 Subject: [PATCH 0630/1899] gts fix --- packages/grpc-js/src/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e9a46dd27..aebd8397b 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -249,5 +249,4 @@ export const InterceptingCall = () => { throw new Error('Not yet implemented'); }; -export { ChannelCredentials } from './channel-credentials'; -export { GrpcObject } from './make-client'; +export {GrpcObject} from './make-client'; From 0937dc902726adf8fcf74fbb16f7d5a0f5a3f710 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 2 May 2019 16:17:07 -0700 Subject: [PATCH 0631/1899] Update grpc-js to 0.4.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0ced2f552..e0827fbe7 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.3.6", + "version": "0.4.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 293ea935f399b76b223fb0d9086cad26bab01c76 Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Thu, 2 May 2019 16:39:01 -0700 Subject: [PATCH 0632/1899] grpc-js: add ServiceError --- packages/grpc-js/src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index aebd8397b..740cd6367 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -17,7 +17,7 @@ import * as semver from 'semver'; -import {ClientDuplexStream, ClientReadableStream, ClientUnaryCall, ClientWritableStream} from './call'; +import {ClientDuplexStream, ClientReadableStream, ClientUnaryCall, ClientWritableStream, ServiceError} from './call'; import {CallCredentials} from './call-credentials'; import {Deadline, StatusObject} from './call-stream'; import {Channel, ConnectivityState, Http2Channel} from './channel'; @@ -180,7 +180,8 @@ export { ClientWritableStream, ClientDuplexStream, CallOptions, - StatusObject + StatusObject, + ServiceError }; /* tslint:disable:no-any */ From 79544366be6562d85a71589e88f738d3bf6511b6 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 21 Apr 2019 14:29:15 -0400 Subject: [PATCH 0633/1899] grpc-js: support unary and server streaming rpcs This commit adds support for unary and server streaming RPCs. --- packages/grpc-js/src/server-call.ts | 365 +++++++++++- packages/grpc-js/src/server.ts | 118 +++- .../grpc-js/test/fixtures/echo_service.proto | 33 ++ .../grpc-js/test/fixtures/test_service.proto | 41 ++ packages/grpc-js/test/test-server-errors.ts | 522 ++++++++++++++++++ packages/grpc-js/test/test-server.ts | 158 ++++++ 6 files changed, 1202 insertions(+), 35 deletions(-) create mode 100644 packages/grpc-js/test/fixtures/echo_service.proto create mode 100644 packages/grpc-js/test/fixtures/test_service.proto create mode 100644 packages/grpc-js/test/test-server-errors.ts diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 57c3d20dd..68a754b75 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -16,20 +16,74 @@ */ import {EventEmitter} from 'events'; +import * as http2 from 'http2'; import {Duplex, Readable, Writable} from 'stream'; + import {ServiceError} from './call'; +import {Status} from './constants'; import {Deserialize, Serialize} from './make-client'; import {Metadata} from './metadata'; +function noop(): void {} + +export type PartialServiceError = Partial; + +type DeadlineUnitIndexSignature = { + [name: string]: number +}; -export class ServerUnaryCall extends EventEmitter { +const GRPC_ACCEPT_ENCODING_HEADER = 'grpc-accept-encoding'; +const GRPC_ENCODING_HEADER = 'grpc-encoding'; +const GRPC_MESSAGE_HEADER = 'grpc-message'; +const GRPC_STATUS_HEADER = 'grpc-status'; +const GRPC_TIMEOUT_HEADER = 'grpc-timeout'; +const DEADLINE_REGEX = /(\d{1,8})\s*([HMSmun])/; +const deadlineUnitsToMs: DeadlineUnitIndexSignature = { + H: 3600000, + M: 60000, + S: 1000, + m: 1, + u: 0.001, + n: 0.000001 +}; +const defaultResponseHeaders = { + // TODO(cjihrig): Remove these encoding headers from the default response + // once compression is integrated. + [GRPC_ACCEPT_ENCODING_HEADER]: 'identity', + [GRPC_ENCODING_HEADER]: 'identity', + [http2.constants.HTTP2_HEADER_STATUS]: http2.constants.HTTP_STATUS_OK, + [http2.constants.HTTP2_HEADER_CONTENT_TYPE]: 'application/grpc+proto' +}; +const defaultResponseOptions = { + waitForTrailers: true +} as http2.ServerStreamResponseOptions; + + +export type ServerSurfaceCall = { + cancelled: boolean; getPeer(): string; + sendMetadata(responseMetadata: Metadata): void +}; + +export type ServerUnaryCall = + ServerSurfaceCall&{request: RequestType | null}; +export type ServerReadableStream = + ServerSurfaceCall&Readable; +export type ServerWritableStream = + ServerSurfaceCall&Writable&{request: RequestType | null}; +export type ServerDuplexStream = + ServerSurfaceCall&Duplex; + +export class ServerUnaryCallImpl extends EventEmitter + implements ServerUnaryCall { cancelled: boolean; request: RequestType|null; - constructor(private call: ServerCall, public metadata: Metadata) { + constructor( + private call: Http2ServerCallStream, + public metadata: Metadata) { super(); this.cancelled = false; - this.request = null; // TODO(cjihrig): Read the unary request here. + this.request = null; } getPeer(): string { @@ -37,17 +91,20 @@ export class ServerUnaryCall extends EventEmitter { } sendMetadata(responseMetadata: Metadata): void { - throw new Error('not implemented yet'); + this.call.sendMetadata(responseMetadata); } } -export class ServerReadableStream extends Readable { +export class ServerReadableStreamImpl extends + Readable implements ServerReadableStream { cancelled: boolean; + private done = false; constructor( - private call: ServerCall, public metadata: Metadata, - private deserialize: Deserialize) { + private call: Http2ServerCallStream, + public metadata: Metadata, + private _deserialize: Deserialize) { super(); this.cancelled = false; } @@ -57,21 +114,32 @@ export class ServerReadableStream extends Readable { } sendMetadata(responseMetadata: Metadata): void { - throw new Error('not implemented yet'); + this.call.sendMetadata(responseMetadata); + } + + _done(): void { + this.done = true; + this.on('data', noop); } } -export class ServerWritableStream extends Writable { +export class ServerWritableStreamImpl extends + Writable implements ServerWritableStream { cancelled: boolean; request: RequestType|null; constructor( - private call: ServerCall, public metadata: Metadata, - private serialize: Serialize) { - super(); + private call: Http2ServerCallStream, + public metadata: Metadata, private _serialize: Serialize) { + super({objectMode: true}); this.cancelled = false; - this.request = null; // TODO(cjihrig): Read the unary request here. + this.request = null; + + this.on('error', (err) => { + this.call.sendError(err as ServiceError); + this.end(); + }); } getPeer(): string { @@ -79,18 +147,53 @@ export class ServerWritableStream extends Writable { } sendMetadata(responseMetadata: Metadata): void { - throw new Error('not implemented yet'); + this.call.sendMetadata(responseMetadata); + } + + async _write(chunk: ResponseType, encoding: string, callback: Function) { + try { + const response = await this.call.serializeMessage(chunk); + this.call.write(response); + } catch (err) { + err.code = Status.INTERNAL; + this.emit('error', err); + } + + callback(null); + } + + _final(callback: Function): void { + this.call.end(); + callback(null); + } + + // tslint:disable-next-line:no-any + end(metadata?: any) { + if (metadata) { + this.call.status.metadata = metadata; + } + + super.end(); + } + + serialize(input: ResponseType): Buffer|null { + if (input === null || input === undefined) { + return null; + } + + return this._serialize(input); } } -export class ServerDuplexStream extends Duplex { +export class ServerDuplexStreamImpl extends Duplex + implements ServerDuplexStream { cancelled: boolean; constructor( - private call: ServerCall, public metadata: Metadata, - private serialize: Serialize, - private deserialize: Deserialize) { + private call: Http2ServerCallStream, + public metadata: Metadata, private _serialize: Serialize, + private _deserialize: Deserialize) { super(); this.cancelled = false; } @@ -100,15 +203,11 @@ export class ServerDuplexStream extends Duplex { } sendMetadata(responseMetadata: Metadata): void { - throw new Error('not implemented yet'); + this.call.sendMetadata(responseMetadata); } } -// Internal class that wraps the HTTP2 request. -export class ServerCall {} - - // Unary response callback signature. export type sendUnaryData = (error: ServiceError|null, value: ResponseType|null, trailer?: Metadata, @@ -116,12 +215,12 @@ export type sendUnaryData = // User provided handler for unary calls. export type handleUnaryCall = - (call: ServerUnaryCall, + (call: ServerUnaryCall, callback: sendUnaryData) => void; // User provided handler for client streaming calls. export type handleClientStreamingCall = - (call: ServerReadableStream, + (call: ServerReadableStream, callback: sendUnaryData) => void; // User provided handler for server streaming calls. @@ -133,9 +232,9 @@ export type handleBidiStreamingCall = (call: ServerDuplexStream) => void; export type HandleCall = - handleUnaryCall| - handleClientStreamingCall| - handleServerStreamingCall| + handleUnaryCall& + handleClientStreamingCall& + handleServerStreamingCall& handleBidiStreamingCall; export type Handler = { @@ -146,3 +245,213 @@ export type Handler = { }; export type HandlerType = 'bidi'|'clientStream'|'serverStream'|'unary'; + + +// Internal class that wraps the HTTP2 request. +export class Http2ServerCallStream extends + EventEmitter { + cancelled = false; + deadline: NodeJS.Timer|null = null; + status: PartialServiceError = {code: Status.OK, details: 'OK'}; + + constructor( + private stream: http2.ServerHttp2Stream, + private handler: Handler|null) { + super(); + + this.stream.once('error', (err: Error) => { + this.sendError(err as ServiceError, Status.INTERNAL); + }); + + this.stream.once('close', () => { + if (this.stream.rstCode === http2.constants.NGHTTP2_CANCEL) { + this.cancelled = true; + this.emit('cancelled', 'cancelled'); + } + }); + } + + private get _metadataSent(): boolean { + return this.stream.headersSent; + } + + sendMetadata(customMetadata?: Metadata) { + if (this._metadataSent) { + return; + } + + const custom = customMetadata ? customMetadata.toHttp2Headers() : null; + // TODO(cjihrig): Include compression headers. + const headers = Object.assign(defaultResponseHeaders, custom); + + this.stream.respond(headers, defaultResponseOptions); + this.stream.once('wantTrailers', () => { + let trailersToSend = { + [GRPC_STATUS_HEADER]: this.status.code, + [GRPC_MESSAGE_HEADER]: encodeURI(this.status.details as string) + }; + const metadata = this.status.metadata; + + if (metadata) { + trailersToSend = + Object.assign(trailersToSend, metadata.toHttp2Headers()); + } + + this.stream.sendTrailers(trailersToSend); + }); + } + + receiveMetadata(headers: http2.IncomingHttpHeaders) { + const metadata = Metadata.fromHttp2Headers(headers); + + // TODO(cjihrig): Receive compression metadata. + + const timeoutHeader = metadata.get(GRPC_TIMEOUT_HEADER); + + if (timeoutHeader.length > 0) { + const match = timeoutHeader[0].toString().match(DEADLINE_REGEX); + + if (match === null) { + this.sendError( + new Error('Invalid deadline') as ServiceError, Status.OUT_OF_RANGE); + return; + } + + const timeout = (+match[1] * deadlineUnitsToMs[match[2]]) | 0; + + this.deadline = setTimeout(handleExpiredDeadline, timeout, this); + metadata.remove(GRPC_TIMEOUT_HEADER); + } + + return metadata; + } + + receiveUnaryMessage(): Promise { + return new Promise((resolve, reject) => { + const stream = this.stream; + const chunks: Buffer[] = []; + let totalLength = 0; + + stream.on('data', (data: Buffer) => { + chunks.push(data); + totalLength += data.byteLength; + }); + + stream.once('end', async () => { + try { + const requestBytes = Buffer.concat(chunks, totalLength); + + resolve(await this.deserializeMessage(requestBytes)); + } catch (err) { + this.sendError(err, Status.INTERNAL); + resolve(); + } + }); + }); + } + + serializeMessage(value: ResponseType) { + const handler = this.handler as Handler; + const messageBuffer = handler.serialize(value); + + // TODO(cjihrig): Call compression aware serializeMessage(). + const byteLength = messageBuffer.byteLength; + const output = Buffer.allocUnsafe(byteLength + 5); + output.writeUInt8(0, 0); + output.writeUInt32BE(byteLength, 1); + messageBuffer.copy(output, 5); + return output; + } + + async deserializeMessage(bytes: Buffer) { + const handler = this.handler as Handler; + // TODO(cjihrig): Call compression aware deserializeMessage(). + const receivedMessage = bytes.slice(5); + + return handler.deserialize(receivedMessage); + } + + async sendUnaryMessage( + err: ServiceError|null, value: ResponseType|null, metadata?: Metadata, + flags?: number) { + if (err) { + if (metadata) { + err.metadata = metadata; + } + + this.sendError(err); + return; + } + + try { + const response = await this.serializeMessage(value as ResponseType); + + if (metadata) { + this.status.metadata = metadata; + } + + this.end(response); + } catch (err) { + this.sendError(err, Status.INTERNAL); + } + } + + sendError(error: ServiceError, code = Status.UNKNOWN) { + const {status} = this; + + if (error.hasOwnProperty('message')) { + status.details = error.message; + } else { + status.details = 'Unknown Error'; + } + + if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { + status.code = error.code; + + if (error.hasOwnProperty('details')) { + status.details = error.details; + } + } else { + status.code = code; + } + + if (error.hasOwnProperty('metadata')) { + status.metadata = error.metadata; + } + + this.end(); + } + + write(chunk: Buffer) { + if (this.cancelled === true) { + return; + } + + this.sendMetadata(); + return this.stream.write(chunk); + } + + end(payload?: Buffer) { + if (this.cancelled === true) { + return; + } + + if (this.deadline !== null) { + clearTimeout(this.deadline); + this.deadline = null; + } + + this.sendMetadata(); + return this.stream.end(payload); + } +} + +// tslint:disable:no-any +type UntypedServerCall = Http2ServerCallStream; + +function handleExpiredDeadline(call: UntypedServerCall) { + call.sendError( + new Error('Deadline exceeded') as ServiceError, Status.DEADLINE_EXCEEDED); + call.cancelled = true; + call.emit('cancelled', 'deadline'); +} diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index decdbe5a4..567c05e64 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -22,12 +22,12 @@ import {URL} from 'url'; import {ServiceError} from './call'; import {Status} from './constants'; import {Deserialize, Serialize, ServiceDefinition} from './make-client'; -import {HandleCall, Handler, HandlerType, sendUnaryData, ServerDuplexStream, ServerReadableStream, ServerUnaryCall, ServerWritableStream} from './server-call'; +import {Metadata} from './metadata'; +import {HandleCall, Handler, HandlerType, Http2ServerCallStream, PartialServiceError, sendUnaryData, ServerDuplexStream, ServerDuplexStreamImpl, ServerReadableStream, ServerReadableStreamImpl, ServerUnaryCall, ServerUnaryCallImpl, ServerWritableStream, ServerWritableStreamImpl} from './server-call'; import {ServerCredentials} from './server-credentials'; function noop(): void {} -type PartialServiceError = Partial; const unimplementedStatusResponse: PartialServiceError = { code: Status.UNIMPLEMENTED, details: 'The server does not implement this method', @@ -41,10 +41,11 @@ type UntypedServiceImplementation = { }; const defaultHandler = { - unary(call: ServerUnaryCall, callback: sendUnaryData): void { + unary(call: ServerUnaryCall, callback: sendUnaryData): void { callback(unimplementedStatusResponse as ServiceError, null); }, - clientStream(call: ServerReadableStream, callback: sendUnaryData): + clientStream( + call: ServerReadableStream, callback: sendUnaryData): void { callback(unimplementedStatusResponse as ServiceError, null); }, @@ -120,8 +121,8 @@ export class Server { } const success = this.register( - attrs.path, impl, attrs.responseSerialize, attrs.requestDeserialize, - methodType); + attrs.path, impl as UntypedHandleCall, attrs.responseSerialize, + attrs.requestDeserialize, methodType); if (success === false) { throw new Error(`Method handler for ${attrs.path} already provided.`); @@ -162,7 +163,7 @@ export class Server { this.http2Server = http2.createServer(); } - // TODO(cjihrig): Set up the handlers, to allow requests to be processed. + this._setupHandlers(); function onError(err: Error): void { callback(err, -1); @@ -227,4 +228,107 @@ export class Server { addHttp2Port(): void { throw new Error('Not yet implemented'); } + + private _setupHandlers(): void { + if (this.http2Server === null) { + return; + } + + this.http2Server.on( + 'stream', + (stream: http2.ServerHttp2Stream, + headers: http2.IncomingHttpHeaders) => { + if (this.started !== true) { + stream.end(); + return; + } + + try { + const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; + const handler = this.handlers.get(path); + + if (handler === undefined) { + throw unimplementedStatusResponse; + } + + const call = new Http2ServerCallStream(stream, handler); + const metadata: Metadata = + call.receiveMetadata(headers) as Metadata; + + switch (handler.type) { + case 'unary': + handleUnary(call, handler, metadata); + break; + case 'clientStream': + handleClientStreaming(call, handler, metadata); + break; + case 'serverStream': + handleServerStreaming(call, handler, metadata); + break; + case 'bidi': + handleBidiStreaming(call, handler, metadata); + break; + default: + throw new Error(`Unknown handler type: ${handler.type}`); + } + } catch (err) { + const call = new Http2ServerCallStream(stream, null); + call.sendError(err, Status.INTERNAL); + } + }); + } +} + + +async function handleUnary( + call: Http2ServerCallStream, + handler: Handler, + metadata: Metadata): Promise { + const emitter = + new ServerUnaryCallImpl(call, metadata); + const request = await call.receiveUnaryMessage(); + + if (request === undefined || call.cancelled === true) { + return; + } + + emitter.request = request; + handler.func( + emitter, + (err: ServiceError|null, value: ResponseType|null, trailer?: Metadata, + flags?: number) => { + call.sendUnaryMessage(err, value, trailer, flags); + }); +} + + +function handleClientStreaming( + call: Http2ServerCallStream, + handler: Handler, metadata: Metadata): void { + throw new Error('not implemented yet'); +} + + +async function handleServerStreaming( + call: Http2ServerCallStream, + handler: Handler, + metadata: Metadata): Promise { + const request = await call.receiveUnaryMessage(); + + if (request === undefined || call.cancelled === true) { + return; + } + + const stream = new ServerWritableStreamImpl( + call, metadata, handler.serialize); + + stream.request = request; + handler.func(stream); +} + + +function handleBidiStreaming( + call: Http2ServerCallStream, + handler: Handler, metadata: Metadata): void { + throw new Error('not implemented yet'); } diff --git a/packages/grpc-js/test/fixtures/echo_service.proto b/packages/grpc-js/test/fixtures/echo_service.proto new file mode 100644 index 000000000..20b3bfe02 --- /dev/null +++ b/packages/grpc-js/test/fixtures/echo_service.proto @@ -0,0 +1,33 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +message EchoMessage { + string value = 1; + int32 value2 = 2; +} + +service EchoService { + rpc Echo (EchoMessage) returns (EchoMessage); + + rpc EchoClientStream (stream EchoMessage) returns (EchoMessage); + + rpc EchoServerStream (EchoMessage) returns (stream EchoMessage); + + rpc EchoBidiStream (stream EchoMessage) returns (stream EchoMessage); +} diff --git a/packages/grpc-js/test/fixtures/test_service.proto b/packages/grpc-js/test/fixtures/test_service.proto new file mode 100644 index 000000000..db876be98 --- /dev/null +++ b/packages/grpc-js/test/fixtures/test_service.proto @@ -0,0 +1,41 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +message Request { + bool error = 1; + string message = 2; +} + +message Response { + int32 count = 1; +} + +service TestService { + rpc Unary (Request) returns (Response) { + } + + rpc ClientStream (stream Request) returns (Response) { + } + + rpc ServerStream (Request) returns (stream Response) { + } + + rpc BidiStream (stream Request) returns (stream Response) { + } +} diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts new file mode 100644 index 000000000..eabae3aae --- /dev/null +++ b/packages/grpc-js/test/test-server-errors.ts @@ -0,0 +1,522 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any +import * as assert from 'assert'; +import {join} from 'path'; + +import * as grpc from '../src'; +import {ServiceError} from '../src/call'; +import {ServiceClient, ServiceClientConstructor} from '../src/make-client'; +import {Server} from '../src/server'; +import {sendUnaryData, ServerDuplexStream, ServerReadableStream, ServerUnaryCall, ServerWritableStream} from '../src/server-call'; + +import {loadProtoFile} from './common'; + +const protoFile = join(__dirname, 'fixtures', 'test_service.proto'); +const testServiceDef = loadProtoFile(protoFile); +const testServiceClient = + testServiceDef.TestService as ServiceClientConstructor; +const clientInsecureCreds = grpc.credentials.createInsecure(); +const serverInsecureCreds = grpc.ServerCredentials.createInsecure(); + + +describe('Client malformed response handling', () => { + let server: Server; + let client: ServiceClient; + const badArg = Buffer.from([0xFF]); + + before((done) => { + const malformedTestService = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: identity, + responseSerialize: identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: identity, + responseSerialize: identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: identity, + responseSerialize: identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: identity, + responseSerialize: identity + } + } as any; + + server = new Server(); + + server.addService(malformedTestService, { + unary(call: ServerUnaryCall, cb: sendUnaryData) { + cb(null, badArg); + }, + + clientStream( + stream: ServerReadableStream, cb: sendUnaryData) { + stream.on('data', noop); + stream.on('end', () => { + cb(null, badArg); + }); + }, + + serverStream(stream: ServerWritableStream) { + stream.write(badArg); + stream.end(); + }, + + bidiStream(stream: ServerDuplexStream) { + stream.on('data', () => { + // Ignore requests + stream.write(badArg); + }); + + stream.on('end', () => { + stream.end(); + }); + } + }); + + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new testServiceClient(`localhost:${port}`, clientInsecureCreds); + server.start(); + done(); + }); + }); + + after((done) => { + client.close(); + server.tryShutdown(done); + }); + + it('should get an INTERNAL status with a unary call', (done) => { + client.unary({}, (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + + it('should get an INTERNAL status with a server stream call', (done) => { + const call = client.serverStream({}); + + call.on('data', noop); + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); +}); + +describe('Server serialization failure handling', () => { + let client: ServiceClient; + let server: Server; + + before((done) => { + function serializeFail(obj: any) { + throw new Error('Serialization failed'); + } + + const malformedTestService = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: identity, + responseSerialize: serializeFail + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: identity, + responseSerialize: serializeFail + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: identity, + responseSerialize: serializeFail + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: identity, + responseSerialize: serializeFail + } + }; + + server = new Server(); + server.addService(malformedTestService as any, { + unary(call: ServerUnaryCall, cb: sendUnaryData) { + cb(null, {}); + }, + + clientStream( + stream: ServerReadableStream, cb: sendUnaryData) { + stream.on('data', noop); + stream.on('end', () => { + cb(null, {}); + }); + }, + + serverStream(stream: ServerWritableStream) { + stream.write({}); + stream.end(); + }, + + bidiStream(stream: ServerDuplexStream) { + stream.on('data', () => { + // Ignore requests + stream.write({}); + }); + stream.on('end', () => { + stream.end(); + }); + } + }); + + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new testServiceClient(`localhost:${port}`, clientInsecureCreds); + server.start(); + done(); + }); + }); + + after((done) => { + client.close(); + server.tryShutdown(done); + }); + + it('should get an INTERNAL status with a unary call', (done) => { + client.unary({}, (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + + it('should get an INTERNAL status with a server stream call', (done) => { + const call = client.serverStream({}); + + call.on('data', noop); + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); +}); + + +describe('Other conditions', () => { + let client: ServiceClient; + let server: Server; + let port: number; + + before((done) => { + const trailerMetadata = new grpc.Metadata(); + + server = new Server(); + trailerMetadata.add('trailer-present', 'yes'); + + server.addService(testServiceClient.service, { + unary(call: ServerUnaryCall, cb: sendUnaryData) { + const req = call.request; + + if (req.error) { + const details = req.message || 'Requested error'; + + cb({code: grpc.status.UNKNOWN, details} as ServiceError, null, + trailerMetadata); + } else { + cb(null, {count: 1}, trailerMetadata); + } + }, + + clientStream( + stream: ServerReadableStream, cb: sendUnaryData) { + let count = 0; + let errored = false; + + stream.on('data', (data: any) => { + if (data.error) { + const message = data.message || 'Requested error'; + errored = true; + cb(new Error(message) as ServiceError, null, trailerMetadata); + } else { + count++; + } + }); + + stream.on('end', () => { + if (!errored) { + cb(null, {count}, trailerMetadata); + } + }); + }, + + serverStream(stream: ServerWritableStream) { + const req = stream.request; + + if (req.error) { + stream.emit('error', { + code: grpc.status.UNKNOWN, + details: req.message || 'Requested error', + metadata: trailerMetadata + }); + } else { + for (let i = 0; i < 5; i++) { + stream.write({count: i}); + } + + stream.end(trailerMetadata); + } + }, + + bidiStream(stream: ServerDuplexStream) { + let count = 0; + stream.on('data', (data: any) => { + if (data.error) { + const message = data.message || 'Requested error'; + const err = new Error(message) as ServiceError; + + err.metadata = trailerMetadata.clone(); + err.metadata.add('count', '' + count); + stream.emit('error', err); + } else { + stream.write({count}); + count++; + } + }); + + stream.on('end', () => { + stream.end(trailerMetadata); + }); + } + }); + + server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { + assert.ifError(err); + port = _port; + client = new testServiceClient(`localhost:${port}`, clientInsecureCreds); + server.start(); + done(); + }); + }); + + after((done) => { + client.close(); + server.tryShutdown(done); + }); + + describe('Server receiving bad input', () => { + let misbehavingClient: ServiceClient; + const badArg = Buffer.from([0xFF]); + + before(() => { + const testServiceAttrs = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestSerialize: identity, + responseDeserialize: identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestSerialize: identity, + responseDeserialize: identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestSerialize: identity, + responseDeserialize: identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestSerialize: identity, + responseDeserialize: identity + } + } as any; + + const client = + grpc.makeGenericClientConstructor(testServiceAttrs, 'TestService'); + + misbehavingClient = new client(`localhost:${port}`, clientInsecureCreds); + }); + + after(() => { + misbehavingClient.close(); + }); + + it('should respond correctly to a unary call', (done) => { + misbehavingClient.unary(badArg, (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + + it('should respond correctly to a server stream', (done) => { + const call = misbehavingClient.serverStream(badArg); + + call.on('data', (data: any) => { + assert.fail(data); + }); + + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + }); + }); + + describe('Trailing metadata', () => { + it('should be present when a unary call succeeds', (done) => { + let count = 0; + const call = + client.unary({error: false}, (err: ServiceError, data: any) => { + assert.ifError(err); + + count++; + if (count === 2) { + done(); + } + }); + + call.on('status', (status: grpc.StatusObject) => { + assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); + + count++; + if (count === 2) { + done(); + } + }); + }); + + it('should be present when a unary call fails', (done) => { + let count = 0; + const call = + client.unary({error: true}, (err: ServiceError, data: any) => { + assert(err); + + count++; + if (count === 2) { + done(); + } + }); + + call.on('status', (status: grpc.StatusObject) => { + assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); + + count++; + if (count === 2) { + done(); + } + }); + }); + + it('should be present when a server stream call succeeds', (done) => { + const call = client.serverStream({error: false}); + + call.on('data', noop); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.OK); + assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + + it('should be present when a server stream call fails', (done) => { + const call = client.serverStream({error: true}); + + call.on('data', noop); + call.on('error', (error: ServiceError) => { + assert.deepStrictEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + }); + + describe('Error object should contain the status', () => { + it('for a unary call', (done) => { + client.unary({error: true}, (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + }); + + it('for a server stream call', (done) => { + const call = client.serverStream({error: true}); + + call.on('data', noop); + call.on('error', (error: ServiceError) => { + assert.strictEqual(error.code, grpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + done(); + }); + }); + + it('for a UTF-8 error message', (done) => { + client.unary( + {error: true, message: '測試字符串'}, + (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + done(); + }); + }); + }); +}); + + +function identity(arg: any): any { + return arg; +} + + +function noop(): void {} diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 0b2f0524d..f44f5d5dd 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -21,8 +21,12 @@ import * as assert from 'assert'; import * as fs from 'fs'; import * as path from 'path'; +import * as grpc from '../src'; import {ServerCredentials} from '../src'; +import {ServiceError} from '../src/call'; +import {ServiceClient, ServiceClientConstructor} from '../src/make-client'; import {Server} from '../src/server'; +import {sendUnaryData, ServerDuplexStream, ServerReadableStream, ServerUnaryCall, ServerWritableStream} from '../src/server-call'; import {loadProtoFile} from './common'; @@ -228,4 +232,158 @@ describe('Server', () => { server.bind('localhost:0', ServerCredentials.createInsecure()); }, /Not implemented. Use bindAsync\(\) instead/); }); + + describe('Default handlers', () => { + let server: Server; + let client: ServiceClient; + + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + const mathServiceAttrs = mathClient.service; + + beforeEach((done) => { + server = new Server(); + server.addService(mathServiceAttrs, {}); + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, grpc.credentials.createInsecure()); + server.start(); + done(); + }); + }); + + it('should respond to a unary call with UNIMPLEMENTED', (done) => { + client.div( + {divisor: 4, dividend: 3}, (error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + }); + }); + + it('should respond to a server stream with UNIMPLEMENTED', (done) => { + const call = client.fib({limit: 5}); + + call.on('data', (value: any) => { + assert.fail('No messages expected'); + }); + + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + done(); + }); + }); + }); +}); + +describe('Echo service', () => { + let server: Server; + let client: ServiceClient; + + before((done) => { + const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); + const echoService = + loadProtoFile(protoFile).EchoService as ServiceClientConstructor; + + server = new Server(); + server.addService(echoService.service, { + echo(call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, call.request); + } + }); + + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + client = new echoService( + `localhost:${port}`, grpc.credentials.createInsecure()); + server.start(); + done(); + }); + }); + + after((done) => { + client.close(); + server.tryShutdown(done); + }); + + it('should echo the recieved message directly', (done) => { + client.echo( + {value: 'test value', value2: 3}, + (error: ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, {value: 'test value', value2: 3}); + done(); + }); + }); +}); + +describe('Generic client and server', () => { + function toString(val: any) { + return val.toString(); + } + + function toBuffer(str: string) { + return Buffer.from(str); + } + + function capitalize(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1); + } + + const stringServiceAttrs = { + capitalize: { + path: '/string/capitalize', + requestStream: false, + responseStream: false, + requestSerialize: toBuffer, + requestDeserialize: toString, + responseSerialize: toBuffer, + responseDeserialize: toString + } + }; + + describe('String client and server', () => { + let client: ServiceClient; + let server: Server; + + before((done) => { + server = new Server(); + + server.addService(stringServiceAttrs as any, { + capitalize( + call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, capitalize(call.request)); + } + }); + + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + server.start(); + const clientConstr = grpc.makeGenericClientConstructor( + stringServiceAttrs as any, + 'unused_but_lets_appease_typescript_anyway'); + client = new clientConstr( + `localhost:${port}`, grpc.credentials.createInsecure()); + done(); + }); + }); + + after((done) => { + client.close(); + server.tryShutdown(done); + }); + + it('Should respond with a capitalized string', (done) => { + client.capitalize('abc', (err: ServiceError, response: string) => { + assert.ifError(err); + assert.strictEqual(response, 'Abc'); + done(); + }); + }); + }); }); From a6e2edce9addd5052887555336a0f3eb91c1c4c4 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 28 Apr 2019 11:25:31 -0400 Subject: [PATCH 0634/1899] grpc-js: handle http2 backpressure in server This commit adds backpressure handling code to the ServerWritableStream implementation. --- packages/grpc-js/src/server-call.ts | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 68a754b75..c15936a06 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -150,16 +150,23 @@ export class ServerWritableStreamImpl extends this.call.sendMetadata(responseMetadata); } - async _write(chunk: ResponseType, encoding: string, callback: Function) { + async _write( + chunk: ResponseType, encoding: string, + // tslint:disable-next-line:no-any + callback: (...args: any[]) => void) { try { const response = await this.call.serializeMessage(chunk); - this.call.write(response); + + if (!this.call.write(response)) { + this.call.once('drain', callback); + return; + } } catch (err) { err.code = Status.INTERNAL; this.emit('error', err); } - callback(null); + callback(); } _final(callback: Function): void { From c050bf5ad88f3c9404972dd57c406e1d0bf7e57f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 1 May 2019 12:38:57 -0400 Subject: [PATCH 0635/1899] grpc-js: add sendStatus() Based on PR feedback, this commit adds a sendStatus() method to Http2ServerCallStream. All responses will be funnelled through this method. --- packages/grpc-js/src/server-call.ts | 122 +++++++++++++++------------- packages/grpc-js/src/server.ts | 4 +- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index c15936a06..12bc68310 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -20,6 +20,7 @@ import * as http2 from 'http2'; import {Duplex, Readable, Writable} from 'stream'; import {ServiceError} from './call'; +import {StatusObject} from './call-stream'; import {Status} from './constants'; import {Deserialize, Serialize} from './make-client'; import {Metadata} from './metadata'; @@ -170,14 +171,14 @@ export class ServerWritableStreamImpl extends } _final(callback: Function): void { - this.call.end(); + this.call.sendStatus({code: Status.OK, details: 'OK'} as StatusObject); callback(null); } // tslint:disable-next-line:no-any end(metadata?: any) { if (metadata) { - this.call.status.metadata = metadata; + this.call.setMetadata(metadata); } super.end(); @@ -259,15 +260,17 @@ export class Http2ServerCallStream extends EventEmitter { cancelled = false; deadline: NodeJS.Timer|null = null; - status: PartialServiceError = {code: Status.OK, details: 'OK'}; + private metadata: Metadata|null = null; + private wantTrailers = false; constructor( private stream: http2.ServerHttp2Stream, private handler: Handler|null) { super(); - this.stream.once('error', (err: Error) => { - this.sendError(err as ServiceError, Status.INTERNAL); + this.stream.once('error', (err: ServiceError) => { + err.code = Status.INTERNAL; + this.sendError(err as ServiceError); }); this.stream.once('close', () => { @@ -278,6 +281,10 @@ export class Http2ServerCallStream extends }); } + setMetadata(metadata: Metadata): void { + this.metadata = metadata; + } + private get _metadataSent(): boolean { return this.stream.headersSent; } @@ -290,22 +297,7 @@ export class Http2ServerCallStream extends const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. const headers = Object.assign(defaultResponseHeaders, custom); - this.stream.respond(headers, defaultResponseOptions); - this.stream.once('wantTrailers', () => { - let trailersToSend = { - [GRPC_STATUS_HEADER]: this.status.code, - [GRPC_MESSAGE_HEADER]: encodeURI(this.status.details as string) - }; - const metadata = this.status.metadata; - - if (metadata) { - trailersToSend = - Object.assign(trailersToSend, metadata.toHttp2Headers()); - } - - this.stream.sendTrailers(trailersToSend); - }); } receiveMetadata(headers: http2.IncomingHttpHeaders) { @@ -319,8 +311,9 @@ export class Http2ServerCallStream extends const match = timeoutHeader[0].toString().match(DEADLINE_REGEX); if (match === null) { - this.sendError( - new Error('Invalid deadline') as ServiceError, Status.OUT_OF_RANGE); + const err = new Error('Invalid deadline') as ServiceError; + err.code = Status.OUT_OF_RANGE; + this.sendError(err); return; } @@ -350,7 +343,8 @@ export class Http2ServerCallStream extends resolve(await this.deserializeMessage(requestBytes)); } catch (err) { - this.sendError(err, Status.INTERNAL); + err.code = Status.INTERNAL; + this.sendError(err); resolve(); } }); @@ -393,24 +387,54 @@ export class Http2ServerCallStream extends try { const response = await this.serializeMessage(value as ResponseType); - if (metadata) { - this.status.metadata = metadata; - } - - this.end(response); + this.write(response); + this.sendStatus( + {code: Status.OK, details: 'OK', metadata} as StatusObject); } catch (err) { - this.sendError(err, Status.INTERNAL); + err.code = Status.INTERNAL; + this.sendError(err); } } - sendError(error: ServiceError, code = Status.UNKNOWN) { - const {status} = this; + sendStatus(statusObj: StatusObject) { + if (this.cancelled === true) { + return; + } + + if (this.deadline !== null) { + clearTimeout(this.deadline); + this.deadline = null; + } + + if (!this.wantTrailers) { + this.wantTrailers = true; + this.stream.once('wantTrailers', () => { + let trailersToSend = { + [GRPC_STATUS_HEADER]: statusObj.code, + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string) + }; + const metadata = statusObj.metadata || this.metadata; + + if (metadata) { + trailersToSend = + Object.assign(trailersToSend, metadata.toHttp2Headers()); + } - if (error.hasOwnProperty('message')) { - status.details = error.message; - } else { - status.details = 'Unknown Error'; + this.stream.sendTrailers(trailersToSend); + }); + this.sendMetadata(); + this.stream.end(); } + } + + sendError(error: ServiceError) { + const status: StatusObject = { + code: Status.UNKNOWN, + details: error.hasOwnProperty('message') ? error.message : + 'Unknown Error', + metadata: error.hasOwnProperty('metadata') ? error.metadata : + this.metadata as Metadata + }; if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { status.code = error.code; @@ -418,15 +442,9 @@ export class Http2ServerCallStream extends if (error.hasOwnProperty('details')) { status.details = error.details; } - } else { - status.code = code; } - if (error.hasOwnProperty('metadata')) { - status.metadata = error.metadata; - } - - this.end(); + this.sendStatus(status); } write(chunk: Buffer) { @@ -437,28 +455,16 @@ export class Http2ServerCallStream extends this.sendMetadata(); return this.stream.write(chunk); } - - end(payload?: Buffer) { - if (this.cancelled === true) { - return; - } - - if (this.deadline !== null) { - clearTimeout(this.deadline); - this.deadline = null; - } - - this.sendMetadata(); - return this.stream.end(payload); - } } // tslint:disable:no-any type UntypedServerCall = Http2ServerCallStream; function handleExpiredDeadline(call: UntypedServerCall) { - call.sendError( - new Error('Deadline exceeded') as ServiceError, Status.DEADLINE_EXCEEDED); + const err = new Error('Deadline exceeded') as ServiceError; + err.code = Status.DEADLINE_EXCEEDED; + + call.sendError(err); call.cancelled = true; call.emit('cancelled', 'deadline'); } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 567c05e64..32bb52a2e 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -20,6 +20,7 @@ import {AddressInfo, ListenOptions} from 'net'; import {URL} from 'url'; import {ServiceError} from './call'; +import {StatusObject} from './call-stream'; import {Status} from './constants'; import {Deserialize, Serialize, ServiceDefinition} from './make-client'; import {Metadata} from './metadata'; @@ -273,7 +274,8 @@ export class Server { } } catch (err) { const call = new Http2ServerCallStream(stream, null); - call.sendError(err, Status.INTERNAL); + err.code = Status.INTERNAL; + call.sendError(err); } }); } From ec9e82554b9586584a82aac13d66ce847b66172c Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 3 May 2019 11:40:52 -0400 Subject: [PATCH 0636/1899] fixup! grpc-js: support unary and server streaming rpcs --- packages/grpc-js/src/server-call.ts | 86 ++++++++++++----------------- packages/grpc-js/src/server.ts | 8 +-- 2 files changed, 40 insertions(+), 54 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 12bc68310..866b88895 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -100,13 +100,12 @@ export class ServerUnaryCallImpl extends EventEmitter export class ServerReadableStreamImpl extends Readable implements ServerReadableStream { cancelled: boolean; - private done = false; constructor( private call: Http2ServerCallStream, public metadata: Metadata, private _deserialize: Deserialize) { - super(); + super({objectMode: true}); this.cancelled = false; } @@ -117,11 +116,6 @@ export class ServerReadableStreamImpl extends sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } - - _done(): void { - this.done = true; - this.on('data', noop); - } } @@ -129,6 +123,7 @@ export class ServerWritableStreamImpl extends Writable implements ServerWritableStream { cancelled: boolean; request: RequestType|null; + private trailingMetadata: Metadata; constructor( private call: Http2ServerCallStream, @@ -136,6 +131,7 @@ export class ServerWritableStreamImpl extends super({objectMode: true}); this.cancelled = false; this.request = null; + this.trailingMetadata = new Metadata(); this.on('error', (err) => { this.call.sendError(err as ServiceError); @@ -171,14 +167,15 @@ export class ServerWritableStreamImpl extends } _final(callback: Function): void { - this.call.sendStatus({code: Status.OK, details: 'OK'} as StatusObject); + this.call.sendStatus( + {code: Status.OK, details: 'OK', metadata: this.trailingMetadata}); callback(null); } // tslint:disable-next-line:no-any end(metadata?: any) { if (metadata) { - this.call.setMetadata(metadata); + this.trailingMetadata = metadata; } super.end(); @@ -202,7 +199,7 @@ export class ServerDuplexStreamImpl extends Duplex private call: Http2ServerCallStream, public metadata: Metadata, private _serialize: Serialize, private _deserialize: Deserialize) { - super(); + super({objectMode: true}); this.cancelled = false; } @@ -254,23 +251,24 @@ export type Handler = { export type HandlerType = 'bidi'|'clientStream'|'serverStream'|'unary'; +const noopTimer: NodeJS.Timer = setTimeout(() => {}, 0); // Internal class that wraps the HTTP2 request. export class Http2ServerCallStream extends EventEmitter { cancelled = false; - deadline: NodeJS.Timer|null = null; - private metadata: Metadata|null = null; + deadline: NodeJS.Timer = noopTimer; private wantTrailers = false; + private metadataSent = false; constructor( private stream: http2.ServerHttp2Stream, - private handler: Handler|null) { + private handler: Handler) { super(); this.stream.once('error', (err: ServiceError) => { err.code = Status.INTERNAL; - this.sendError(err as ServiceError); + this.sendError(err); }); this.stream.once('close', () => { @@ -279,21 +277,18 @@ export class Http2ServerCallStream extends this.emit('cancelled', 'cancelled'); } }); - } - setMetadata(metadata: Metadata): void { - this.metadata = metadata; - } - - private get _metadataSent(): boolean { - return this.stream.headersSent; + this.stream.on('drain', () => { + this.emit('drain'); + }); } sendMetadata(customMetadata?: Metadata) { - if (this._metadataSent) { + if (this.metadataSent) { return; } + this.metadataSent = true; const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. const headers = Object.assign(defaultResponseHeaders, custom); @@ -352,8 +347,7 @@ export class Http2ServerCallStream extends } serializeMessage(value: ResponseType) { - const handler = this.handler as Handler; - const messageBuffer = handler.serialize(value); + const messageBuffer = this.handler.serialize(value); // TODO(cjihrig): Call compression aware serializeMessage(). const byteLength = messageBuffer.byteLength; @@ -365,31 +359,30 @@ export class Http2ServerCallStream extends } async deserializeMessage(bytes: Buffer) { - const handler = this.handler as Handler; // TODO(cjihrig): Call compression aware deserializeMessage(). const receivedMessage = bytes.slice(5); - return handler.deserialize(receivedMessage); + return this.handler.deserialize(receivedMessage); } async sendUnaryMessage( err: ServiceError|null, value: ResponseType|null, metadata?: Metadata, flags?: number) { - if (err) { - if (metadata) { - err.metadata = metadata; - } + if (!metadata) { + metadata = new Metadata(); + } + if (err) { + err.metadata = metadata; this.sendError(err); return; } try { - const response = await this.serializeMessage(value as ResponseType); + const response = await this.serializeMessage(value!); this.write(response); - this.sendStatus( - {code: Status.OK, details: 'OK', metadata} as StatusObject); + this.sendStatus({code: Status.OK, details: 'OK', metadata}); } catch (err) { err.code = Status.INTERNAL; this.sendError(err); @@ -397,28 +390,21 @@ export class Http2ServerCallStream extends } sendStatus(statusObj: StatusObject) { - if (this.cancelled === true) { + if (this.cancelled) { return; } - if (this.deadline !== null) { - clearTimeout(this.deadline); - this.deadline = null; - } + clearTimeout(this.deadline); if (!this.wantTrailers) { this.wantTrailers = true; this.stream.once('wantTrailers', () => { - let trailersToSend = { - [GRPC_STATUS_HEADER]: statusObj.code, - [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string) - }; - const metadata = statusObj.metadata || this.metadata; - - if (metadata) { - trailersToSend = - Object.assign(trailersToSend, metadata.toHttp2Headers()); - } + const trailersToSend = Object.assign( + { + [GRPC_STATUS_HEADER]: statusObj.code, + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string) + }, + statusObj.metadata.toHttp2Headers()); this.stream.sendTrailers(trailersToSend); }); @@ -433,7 +419,7 @@ export class Http2ServerCallStream extends details: error.hasOwnProperty('message') ? error.message : 'Unknown Error', metadata: error.hasOwnProperty('metadata') ? error.metadata : - this.metadata as Metadata + new Metadata() }; if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { @@ -448,7 +434,7 @@ export class Http2ServerCallStream extends } write(chunk: Buffer) { - if (this.cancelled === true) { + if (this.cancelled) { return; } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 32bb52a2e..050799d40 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -239,7 +239,7 @@ export class Server { 'stream', (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { - if (this.started !== true) { + if (!this.started) { stream.end(); return; } @@ -273,7 +273,7 @@ export class Server { throw new Error(`Unknown handler type: ${handler.type}`); } } catch (err) { - const call = new Http2ServerCallStream(stream, null); + const call = new Http2ServerCallStream(stream, null!); err.code = Status.INTERNAL; call.sendError(err); } @@ -290,7 +290,7 @@ async function handleUnary( new ServerUnaryCallImpl(call, metadata); const request = await call.receiveUnaryMessage(); - if (request === undefined || call.cancelled === true) { + if (request === undefined || call.cancelled) { return; } @@ -317,7 +317,7 @@ async function handleServerStreaming( metadata: Metadata): Promise { const request = await call.receiveUnaryMessage(); - if (request === undefined || call.cancelled === true) { + if (request === undefined || call.cancelled) { return; } From 7009d25593859059d4eadb7648523bb4f6d28390 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 3 May 2019 14:49:49 -0400 Subject: [PATCH 0637/1899] grpc-js: wrestle with typescript handler types This commit is mindless TypeScript busy work. --- packages/grpc-js/src/server-call.ts | 37 +++++++++++++++++++++++++---- packages/grpc-js/src/server.ts | 30 ++++++++++++++--------- 2 files changed, 51 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 866b88895..9528c30c8 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -237,18 +237,45 @@ export type handleBidiStreamingCall = (call: ServerDuplexStream) => void; export type HandleCall = - handleUnaryCall& - handleClientStreamingCall& - handleServerStreamingCall& + handleUnaryCall| + handleClientStreamingCall| + handleServerStreamingCall| handleBidiStreamingCall; -export type Handler = { - func: HandleCall; +export type UnaryHandler = { + func: handleUnaryCall; serialize: Serialize; deserialize: Deserialize; type: HandlerType; }; +export type ClientStreamingHandler = { + func: handleClientStreamingCall; + serialize: Serialize; + deserialize: Deserialize; + type: HandlerType; +}; + +export type ServerStreamingHandler = { + func: handleServerStreamingCall; + serialize: Serialize; + deserialize: Deserialize; + type: HandlerType; +}; + +export type BidiStreamingHandler = { + func: handleBidiStreamingCall; + serialize: Serialize; + deserialize: Deserialize; + type: HandlerType; +}; + +export type Handler = + UnaryHandler| + ClientStreamingHandler| + ServerStreamingHandler| + BidiStreamingHandler; + export type HandlerType = 'bidi'|'clientStream'|'serverStream'|'unary'; const noopTimer: NodeJS.Timer = setTimeout(() => {}, 0); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 050799d40..421c089d6 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -24,7 +24,7 @@ import {StatusObject} from './call-stream'; import {Status} from './constants'; import {Deserialize, Serialize, ServiceDefinition} from './make-client'; import {Metadata} from './metadata'; -import {HandleCall, Handler, HandlerType, Http2ServerCallStream, PartialServiceError, sendUnaryData, ServerDuplexStream, ServerDuplexStreamImpl, ServerReadableStream, ServerReadableStreamImpl, ServerUnaryCall, ServerUnaryCallImpl, ServerWritableStream, ServerWritableStreamImpl} from './server-call'; +import {BidiStreamingHandler, ClientStreamingHandler, HandleCall, Handler, HandlerType, Http2ServerCallStream, PartialServiceError, sendUnaryData, ServerDuplexStream, ServerDuplexStreamImpl, ServerReadableStream, ServerReadableStreamImpl, ServerStreamingHandler, ServerUnaryCall, ServerUnaryCallImpl, ServerWritableStream, ServerWritableStreamImpl, UnaryHandler} from './server-call'; import {ServerCredentials} from './server-credentials'; function noop(): void {} @@ -35,6 +35,10 @@ const unimplementedStatusResponse: PartialServiceError = { }; // tslint:disable:no-any +type UntypedUnaryHandler = UnaryHandler; +type UntypedClientStreamingHandler = ClientStreamingHandler; +type UntypedServerStreamingHandler = ServerStreamingHandler; +type UntypedBidiStreamingHandler = BidiStreamingHandler; type UntypedHandleCall = HandleCall; type UntypedHandler = Handler; type UntypedServiceImplementation = { @@ -195,8 +199,7 @@ export class Server { } this.handlers.set( - name, - {func: handler, serialize, deserialize, type: type as HandlerType}); + name, {func: handler, serialize, deserialize, type} as UntypedHandler); return true; } @@ -258,16 +261,19 @@ export class Server { switch (handler.type) { case 'unary': - handleUnary(call, handler, metadata); + handleUnary(call, handler as UntypedUnaryHandler, metadata); break; case 'clientStream': - handleClientStreaming(call, handler, metadata); + handleClientStreaming( + call, handler as UntypedClientStreamingHandler, metadata); break; case 'serverStream': - handleServerStreaming(call, handler, metadata); + handleServerStreaming( + call, handler as UntypedServerStreamingHandler, metadata); break; case 'bidi': - handleBidiStreaming(call, handler, metadata); + handleBidiStreaming( + call, handler as UntypedBidiStreamingHandler, metadata); break; default: throw new Error(`Unknown handler type: ${handler.type}`); @@ -284,7 +290,7 @@ export class Server { async function handleUnary( call: Http2ServerCallStream, - handler: Handler, + handler: UnaryHandler, metadata: Metadata): Promise { const emitter = new ServerUnaryCallImpl(call, metadata); @@ -306,14 +312,15 @@ async function handleUnary( function handleClientStreaming( call: Http2ServerCallStream, - handler: Handler, metadata: Metadata): void { + handler: ClientStreamingHandler, + metadata: Metadata): void { throw new Error('not implemented yet'); } async function handleServerStreaming( call: Http2ServerCallStream, - handler: Handler, + handler: ServerStreamingHandler, metadata: Metadata): Promise { const request = await call.receiveUnaryMessage(); @@ -331,6 +338,7 @@ async function handleServerStreaming( function handleBidiStreaming( call: Http2ServerCallStream, - handler: Handler, metadata: Metadata): void { + handler: BidiStreamingHandler, + metadata: Metadata): void { throw new Error('not implemented yet'); } From a11bdbb0a2e3f7e57278ca18a2b003af0d98ce9f Mon Sep 17 00:00:00 2001 From: Eva Ogbe Date: Fri, 3 May 2019 15:03:02 -0700 Subject: [PATCH 0638/1899] Native: Remove unused ChannelCredential type definitions Removes: - getCallCredentials - getSecureContext These functions no longer exist, so their presence in the type definitions is invalid. --- packages/grpc-native-core/index.d.ts | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 1a634164e..1f8437f2c 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -963,18 +963,6 @@ declare module "grpc" { * instance. */ compose(callCredentials: CallCredentials): ChannelCredentials; - - /** - * Gets the set of per-call credentials associated with this instance. - */ - getCallCredentials(): CallCredentials; - - /** - * Gets a SecureContext object generated from input parameters if this - * instance was created with createSsl, or null if this instance was created - * with createInsecure. - */ - getSecureContext(): SecureContext | null; } /** @@ -1545,7 +1533,7 @@ declare module "grpc" { TRANSIENT_FAILURE = 3, SHUTDOWN = 4 } - + export class Channel { /** * This constructor API is almost identical to the Client constructor, @@ -1583,8 +1571,8 @@ declare module "grpc" { watchConnectivityState(currentState: connectivityState, deadline: Date|number, callback: (error?: Error) => void): void; /** * Create a call object. Call is an opaque type that is used by the Client - * and Server classes. This function is called by the gRPC library when - * starting a request. Implementers should return an instance of Call that + * and Server classes. This function is called by the gRPC library when + * starting a request. Implementers should return an instance of Call that * is returned from calling createCall on an instance of the provided * Channel class. * @param method The full method string to request. @@ -1595,5 +1583,5 @@ declare module "grpc" { * that indicates what information to propagate from parentCall. */ createCall(method: string, deadline: Date|number, host: string|null, parentCall: Call|null, propagateFlags: number|null): Call; - } -} \ No newline at end of file + } +} From 7aa45eb55e41c6ccf17aaf59d0289a987f981263 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 6 May 2019 13:54:55 -0400 Subject: [PATCH 0639/1899] grpc-js: extract reusable stream decoding logic This commit pulls the stream decoding logic into a separate class so that it can be reused by the server code. --- packages/grpc-js/src/call-stream.ts | 75 ++------------------ packages/grpc-js/src/stream-decoder.ts | 98 ++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 69 deletions(-) create mode 100644 packages/grpc-js/src/stream-decoder.ts diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index c987d9320..7c06c335c 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -26,6 +26,7 @@ import {Filter} from './filter'; import {FilterStackFactory} from './filter-stack'; import {Metadata} from './metadata'; import {ObjectDuplex, WriteCallback} from './object-stream'; +import {StreamDecoder} from './stream-decoder'; const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = http2.constants; @@ -77,12 +78,6 @@ export type Call = { EmitterAugmentation1<'status', StatusObject>& ObjectDuplex; -enum ReadState { - NO_DATA, - READING_SIZE, - READING_MESSAGE -} - export class Http2CallStream extends Duplex implements Call { credentials: CallCredentials = CallCredentials.createEmpty(); filterStack: Filter; @@ -92,13 +87,7 @@ export class Http2CallStream extends Duplex implements Call { private pendingWriteCallback: WriteCallback|null = null; private pendingFinalCallback: Function|null = null; - private readState: ReadState = ReadState.NO_DATA; - private readCompressFlag: Buffer = Buffer.alloc(1); - private readPartialSize: Buffer = Buffer.alloc(4); - private readSizeRemaining = 4; - private readMessageSize = 0; - private readPartialMessage: Buffer[] = []; - private readMessageRemaining = 0; + private decoder = new StreamDecoder(); private isReadFilterPending = false; private canPush = false; @@ -292,62 +281,10 @@ export class Http2CallStream extends Duplex implements Call { }); stream.on('trailers', this.handleTrailers.bind(this)); stream.on('data', (data: Buffer) => { - let readHead = 0; - let toRead: number; - while (readHead < data.length) { - switch (this.readState) { - case ReadState.NO_DATA: - this.readCompressFlag = data.slice(readHead, readHead + 1); - readHead += 1; - this.readState = ReadState.READING_SIZE; - this.readPartialSize.fill(0); - this.readSizeRemaining = 4; - this.readMessageSize = 0; - this.readMessageRemaining = 0; - this.readPartialMessage = []; - break; - case ReadState.READING_SIZE: - toRead = Math.min(data.length - readHead, this.readSizeRemaining); - data.copy( - this.readPartialSize, 4 - this.readSizeRemaining, readHead, - readHead + toRead); - this.readSizeRemaining -= toRead; - readHead += toRead; - // readSizeRemaining >=0 here - if (this.readSizeRemaining === 0) { - this.readMessageSize = this.readPartialSize.readUInt32BE(0); - this.readMessageRemaining = this.readMessageSize; - if (this.readMessageRemaining > 0) { - this.readState = ReadState.READING_MESSAGE; - } else { - this.tryPush(Buffer.concat( - [this.readCompressFlag, this.readPartialSize])); - this.readState = ReadState.NO_DATA; - } - } - break; - case ReadState.READING_MESSAGE: - toRead = - Math.min(data.length - readHead, this.readMessageRemaining); - this.readPartialMessage.push( - data.slice(readHead, readHead + toRead)); - this.readMessageRemaining -= toRead; - readHead += toRead; - // readMessageRemaining >=0 here - if (this.readMessageRemaining === 0) { - // At this point, we have read a full message - const framedMessageBuffers = [ - this.readCompressFlag, this.readPartialSize - ].concat(this.readPartialMessage); - const framedMessage = Buffer.concat( - framedMessageBuffers, this.readMessageSize + 5); - this.tryPush(framedMessage); - this.readState = ReadState.NO_DATA; - } - break; - default: - throw new Error('This should never happen'); - } + const message = this.decoder.write(data); + + if (message !== null) { + this.tryPush(message); } }); stream.on('end', () => { diff --git a/packages/grpc-js/src/stream-decoder.ts b/packages/grpc-js/src/stream-decoder.ts new file mode 100644 index 000000000..3a8e91aec --- /dev/null +++ b/packages/grpc-js/src/stream-decoder.ts @@ -0,0 +1,98 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +enum ReadState { + NO_DATA, + READING_SIZE, + READING_MESSAGE +} + + +export class StreamDecoder { + private readState: ReadState = ReadState.NO_DATA; + private readCompressFlag: Buffer = Buffer.alloc(1); + private readPartialSize: Buffer = Buffer.alloc(4); + private readSizeRemaining = 4; + private readMessageSize = 0; + private readPartialMessage: Buffer[] = []; + private readMessageRemaining = 0; + + + write(data: Buffer): Buffer|null { + let readHead = 0; + let toRead: number; + + while (readHead < data.length) { + switch (this.readState) { + case ReadState.NO_DATA: + this.readCompressFlag = data.slice(readHead, readHead + 1); + readHead += 1; + this.readState = ReadState.READING_SIZE; + this.readPartialSize.fill(0); + this.readSizeRemaining = 4; + this.readMessageSize = 0; + this.readMessageRemaining = 0; + this.readPartialMessage = []; + break; + case ReadState.READING_SIZE: + toRead = Math.min(data.length - readHead, this.readSizeRemaining); + data.copy( + this.readPartialSize, 4 - this.readSizeRemaining, readHead, + readHead + toRead); + this.readSizeRemaining -= toRead; + readHead += toRead; + // readSizeRemaining >=0 here + if (this.readSizeRemaining === 0) { + this.readMessageSize = this.readPartialSize.readUInt32BE(0); + this.readMessageRemaining = this.readMessageSize; + if (this.readMessageRemaining > 0) { + this.readState = ReadState.READING_MESSAGE; + } else { + const message = Buffer.concat( + [this.readCompressFlag, this.readPartialSize], 5); + + this.readState = ReadState.NO_DATA; + return message; + } + } + break; + case ReadState.READING_MESSAGE: + toRead = Math.min(data.length - readHead, this.readMessageRemaining); + this.readPartialMessage.push(data.slice(readHead, readHead + toRead)); + this.readMessageRemaining -= toRead; + readHead += toRead; + // readMessageRemaining >=0 here + if (this.readMessageRemaining === 0) { + // At this point, we have read a full message + const framedMessageBuffers = [ + this.readCompressFlag, this.readPartialSize + ].concat(this.readPartialMessage); + const framedMessage = + Buffer.concat(framedMessageBuffers, this.readMessageSize + 5); + + this.readState = ReadState.NO_DATA; + return framedMessage; + } + break; + default: + throw new Error('Unexpected read state'); + } + } + + return null; + } +} From b8af8c94744ac04ccd4d1ee124419c6567b1b965 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 7 May 2019 14:23:34 -0400 Subject: [PATCH 0640/1899] grpc-js: add client streaming RPC support This commit adds client streaming RPC support. --- packages/grpc-js/src/server-call.ts | 44 ++++++++++ packages/grpc-js/src/server.ts | 17 +++- packages/grpc-js/test/test-server-errors.ts | 97 +++++++++++++++++++++ packages/grpc-js/test/test-server.ts | 10 +++ 4 files changed, 167 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 9528c30c8..0e17ceeca 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -24,6 +24,7 @@ import {StatusObject} from './call-stream'; import {Status} from './constants'; import {Deserialize, Serialize} from './make-client'; import {Metadata} from './metadata'; +import {StreamDecoder} from './stream-decoder'; function noop(): void {} @@ -100,6 +101,7 @@ export class ServerUnaryCallImpl extends EventEmitter export class ServerReadableStreamImpl extends Readable implements ServerReadableStream { cancelled: boolean; + private decoder: StreamDecoder; constructor( private call: Http2ServerCallStream, @@ -107,6 +109,44 @@ export class ServerReadableStreamImpl extends private _deserialize: Deserialize) { super({objectMode: true}); this.cancelled = false; + this.decoder = new StreamDecoder(); + + const http2Stream = this.call._getHttp2Stream(); + + http2Stream.on('data', async (data: Buffer) => { + const message = this.decoder.write(data); + + if (message === null) { + return; + } + + try { + const deserialized = await this.call.deserializeMessage(message); + + if (!this.push(deserialized)) { + http2Stream.pause(); + } + } catch (err) { + err.code = Status.INTERNAL; + this.emit('error', err); + } + }); + + http2Stream.once('end', () => { + this.push(null); + }); + } + + _read(size: number) { + this.call._getHttp2Stream().resume(); + } + + deserialize(input: Buffer): RequestType|null { + if (input === null || input === undefined) { + return null; + } + + return this._deserialize(input); } getPeer(): string { @@ -468,6 +508,10 @@ export class Http2ServerCallStream extends this.sendMetadata(); return this.stream.write(chunk); } + + _getHttp2Stream(): http2.ServerHttp2Stream { + return this.stream; + } } // tslint:disable:no-any diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 421c089d6..68f6e1498 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -314,7 +314,22 @@ function handleClientStreaming( call: Http2ServerCallStream, handler: ClientStreamingHandler, metadata: Metadata): void { - throw new Error('not implemented yet'); + const stream = new ServerReadableStreamImpl( + call, metadata, handler.deserialize); + + function respond( + err: ServiceError|null, value: ResponseType|null, trailer?: Metadata, + flags?: number) { + stream.destroy(); + call.sendUnaryMessage(err, value, trailer, flags); + } + + if (call.cancelled) { + return; + } + + stream.on('error', respond); + handler.func(stream, respond); } diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index eabae3aae..6f352f736 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -126,6 +126,17 @@ describe('Client malformed response handling', () => { }); }); + it('should get an INTERNAL status with a client stream call', (done) => { + const call = client.clientStream((err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + + call.write({}); + call.end(); + }); + it('should get an INTERNAL status with a server stream call', (done) => { const call = client.serverStream({}); @@ -229,6 +240,17 @@ describe('Server serialization failure handling', () => { }); }); + it('should get an INTERNAL status with a client stream call', (done) => { + const call = client.clientStream((err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + + call.write({}); + call.end(); + }); + it('should get an INTERNAL status with a server stream call', (done) => { const call = client.serverStream({}); @@ -397,6 +419,18 @@ describe('Other conditions', () => { }); }); + it('should respond correctly to a client stream', (done) => { + const call = + misbehavingClient.clientStream((err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + + call.write(badArg); + call.end(); + }); + it('should respond correctly to a server stream', (done) => { const call = misbehavingClient.serverStream(badArg); @@ -457,6 +491,56 @@ describe('Other conditions', () => { }); }); + it('should be present when a client stream call succeeds', (done) => { + let count = 0; + const call = client.clientStream((err: ServiceError, data: any) => { + assert.ifError(err); + + count++; + if (count === 2) { + done(); + } + }); + + call.write({error: false}); + call.write({error: false}); + call.end(); + + call.on('status', (status: grpc.StatusObject) => { + assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); + + count++; + if (count === 2) { + done(); + } + }); + }); + + it('should be present when a client stream call fails', (done) => { + let count = 0; + const call = client.clientStream((err: ServiceError, data: any) => { + assert(err); + + count++; + if (count === 2) { + done(); + } + }); + + call.write({error: false}); + call.write({error: true}); + call.end(); + + call.on('status', (status: grpc.StatusObject) => { + assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); + + count++; + if (count === 2) { + done(); + } + }); + }); + it('should be present when a server stream call succeeds', (done) => { const call = client.serverStream({error: false}); @@ -489,6 +573,19 @@ describe('Other conditions', () => { }); }); + it('for a client stream call', (done) => { + const call = client.clientStream((err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + + call.write({error: false}); + call.write({error: true}); + call.end(); + }); + it('for a server stream call', (done) => { const call = client.serverStream({error: true}); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index f44f5d5dd..d310ff072 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -263,6 +263,16 @@ describe('Server', () => { }); }); + it('should respond to a client stream with UNIMPLEMENTED', (done) => { + const call = client.sum((error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + }); + + call.end(); + }); + it('should respond to a server stream with UNIMPLEMENTED', (done) => { const call = client.fib({limit: 5}); From ea963383d14a0cf8d2bc69b2538c247d8559d93e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 17 Apr 2019 09:27:18 -0700 Subject: [PATCH 0641/1899] Native: enable cares support --- packages/grpc-native-core/binding.gyp | 129 +++++++++++++++++- packages/grpc-native-core/deps/grpc | 2 +- .../templates/binding.gyp.template | 57 +++++++- 3 files changed, 181 insertions(+), 7 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index e3849974b..aabdf479d 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -83,13 +83,16 @@ 'include_dirs': [ 'deps/grpc', 'deps/grpc/include', + 'deps/grpc/third_party/address_sorting/include', + 'deps/grpc/third_party/cares', + 'deps/grpc/third_party/cares/cares', 'deps/grpc/third_party/abseil-cpp', - 'deps/grpc/third_party/nanopb' + 'deps/grpc/third_party/nanopb', ], 'defines': [ 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', - 'GRPC_ARES=0', + 'GRPC_ARES=1', 'GRPC_UV', 'GRPC_NODE_VERSION="1.21.0-dev"' ], @@ -558,6 +561,114 @@ }] ], 'targets': [ + { + 'target_name': 'ares', + 'product_prefix': 'lib', + 'type': 'static_library', + 'sources': [ + 'deps/grpc/third_party/cares/cares/ares__close_sockets.c', + 'deps/grpc/third_party/cares/cares/ares__get_hostent.c', + 'deps/grpc/third_party/cares/cares/ares__read_line.c', + 'deps/grpc/third_party/cares/cares/ares__timeval.c', + 'deps/grpc/third_party/cares/cares/ares_cancel.c', + 'deps/grpc/third_party/cares/cares/ares_create_query.c', + 'deps/grpc/third_party/cares/cares/ares_data.c', + 'deps/grpc/third_party/cares/cares/ares_destroy.c', + 'deps/grpc/third_party/cares/cares/ares_expand_name.c', + 'deps/grpc/third_party/cares/cares/ares_expand_string.c', + 'deps/grpc/third_party/cares/cares/ares_fds.c', + 'deps/grpc/third_party/cares/cares/ares_free_hostent.c', + 'deps/grpc/third_party/cares/cares/ares_free_string.c', + 'deps/grpc/third_party/cares/cares/ares_getenv.c', + 'deps/grpc/third_party/cares/cares/ares_gethostbyaddr.c', + 'deps/grpc/third_party/cares/cares/ares_gethostbyname.c', + 'deps/grpc/third_party/cares/cares/ares_getnameinfo.c', + 'deps/grpc/third_party/cares/cares/ares_getopt.c', + 'deps/grpc/third_party/cares/cares/ares_getsock.c', + 'deps/grpc/third_party/cares/cares/ares_init.c', + 'deps/grpc/third_party/cares/cares/ares_library_init.c', + 'deps/grpc/third_party/cares/cares/ares_llist.c', + 'deps/grpc/third_party/cares/cares/ares_mkquery.c', + 'deps/grpc/third_party/cares/cares/ares_nowarn.c', + 'deps/grpc/third_party/cares/cares/ares_options.c', + 'deps/grpc/third_party/cares/cares/ares_parse_a_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_aaaa_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_mx_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_naptr_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_ns_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_ptr_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_soa_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_srv_reply.c', + 'deps/grpc/third_party/cares/cares/ares_parse_txt_reply.c', + 'deps/grpc/third_party/cares/cares/ares_platform.c', + 'deps/grpc/third_party/cares/cares/ares_process.c', + 'deps/grpc/third_party/cares/cares/ares_query.c', + 'deps/grpc/third_party/cares/cares/ares_search.c', + 'deps/grpc/third_party/cares/cares/ares_send.c', + 'deps/grpc/third_party/cares/cares/ares_strcasecmp.c', + 'deps/grpc/third_party/cares/cares/ares_strdup.c', + 'deps/grpc/third_party/cares/cares/ares_strerror.c', + 'deps/grpc/third_party/cares/cares/ares_strsplit.c', + 'deps/grpc/third_party/cares/cares/ares_timeout.c', + 'deps/grpc/third_party/cares/cares/ares_version.c', + 'deps/grpc/third_party/cares/cares/ares_writev.c', + 'deps/grpc/third_party/cares/cares/bitncmp.c', + 'deps/grpc/third_party/cares/cares/inet_net_pton.c', + 'deps/grpc/third_party/cares/cares/inet_ntop.c', + 'deps/grpc/third_party/cares/cares/windows_port.c', + ], + 'defines': [ + '_GNU_SOURCE' + ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + }, + 'include_dirs': [ + 'deps/grpc/third_party/cares/config_darwin' + ], + 'defines': [ + 'HAVE_CONFIG_H' + ] + }], + ['OS == "linux"', { + 'include_dirs': [ + 'deps/grpc/third_party/cares/config_linux' + ], + 'defines': [ + 'HAVE_CONFIG_H' + ] + }], + ['OS == "win"', { + 'include_dirs': [ + 'deps/grpc/third_party/cares/config_windows' + ], + 'defines': [ + 'HAVE_CONFIG_H' + ] + }] + ] + }, + { + 'target_name': 'address_sorting', + 'product_prefix': 'lib', + 'type': 'static_library', + 'dependencies': [ + ], + 'sources': [ + 'deps/grpc/third_party/address_sorting/address_sorting.c', + 'deps/grpc/third_party/address_sorting/address_sorting_posix.c', + 'deps/grpc/third_party/address_sorting/address_sorting_windows.c', + ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + } + }] + ] + }, { 'target_name': 'gpr', 'product_prefix': 'lib', @@ -566,7 +677,6 @@ ], 'sources': [ 'deps/grpc/src/core/lib/gpr/alloc.cc', - 'deps/grpc/src/core/lib/gpr/arena.cc', 'deps/grpc/src/core/lib/gpr/atm.cc', 'deps/grpc/src/core/lib/gpr/cpu_iphone.cc', 'deps/grpc/src/core/lib/gpr/cpu_linux.cc', @@ -599,7 +709,9 @@ 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', + 'deps/grpc/src/core/lib/gprpp/arena.cc', 'deps/grpc/src/core/lib/gprpp/fork.cc', + 'deps/grpc/src/core/lib/gprpp/global_config_env.cc', 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', @@ -635,6 +747,7 @@ 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', 'deps/grpc/src/core/lib/channel/status_util.cc', 'deps/grpc/src/core/lib/compression/compression.cc', + 'deps/grpc/src/core/lib/compression/compression_args.cc', 'deps/grpc/src/core/lib/compression/compression_internal.cc', 'deps/grpc/src/core/lib/compression/message_compress.cc', 'deps/grpc/src/core/lib/compression/stream_compression.cc', @@ -647,12 +760,15 @@ 'deps/grpc/src/core/lib/http/parser.cc', 'deps/grpc/src/core/lib/iomgr/buffer_list.cc', 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', + 'deps/grpc/src/core/lib/iomgr/cfstream_handle.cc', 'deps/grpc/src/core/lib/iomgr/combiner.cc', 'deps/grpc/src/core/lib/iomgr/endpoint.cc', + 'deps/grpc/src/core/lib/iomgr/endpoint_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_posix.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_uv.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc', 'deps/grpc/src/core/lib/iomgr/error.cc', + 'deps/grpc/src/core/lib/iomgr/error_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.cc', @@ -673,6 +789,7 @@ 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_internal.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_posix.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_uv.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_windows.cc', 'deps/grpc/src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -701,6 +818,7 @@ 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.cc', 'deps/grpc/src/core/lib/iomgr/socket_windows.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.cc', @@ -934,10 +1052,13 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', @@ -996,6 +1117,8 @@ "dependencies": [ "grpc", "gpr", + "ares", + "address_sorting" ] }, { diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index cb0129702..a8644bbc7 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 +Subproject commit a8644bbc77ae95f64ef18ac43e52d495273e4bcd diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 9ec471a65..31442b110 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -75,13 +75,16 @@ 'include_dirs': [ 'deps/grpc', 'deps/grpc/include', + 'deps/grpc/third_party/address_sorting/include', + 'deps/grpc/third_party/cares', + 'deps/grpc/third_party/cares/cares', 'deps/grpc/third_party/abseil-cpp', - 'deps/grpc/third_party/nanopb' + 'deps/grpc/third_party/nanopb', ], 'defines': [ 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', - 'GRPC_ARES=0', + 'GRPC_ARES=1', 'GRPC_UV', 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"' ], @@ -276,8 +279,54 @@ }] ], 'targets': [ + % for lib in libs: + % if lib.name == 'ares': + { + 'target_name': '${lib.name}', + 'product_prefix': 'lib', + 'type': 'static_library', + 'sources': [ + % for source in lib.src: + 'deps/grpc/${source}', + % endfor + ], + 'defines': [ + '_GNU_SOURCE' + ], + 'conditions': [ + ['OS == "mac"', { + 'xcode_settings': { + 'MACOSX_DEPLOYMENT_TARGET': '10.9' + }, + 'include_dirs': [ + 'deps/grpc/third_party/cares/config_darwin' + ], + 'defines': [ + 'HAVE_CONFIG_H' + ] + }], + ['OS == "linux"', { + 'include_dirs': [ + 'deps/grpc/third_party/cares/config_linux' + ], + 'defines': [ + 'HAVE_CONFIG_H' + ] + }], + ['OS == "win"', { + 'include_dirs': [ + 'deps/grpc/third_party/cares/config_windows' + ], + 'defines': [ + 'HAVE_CONFIG_H' + ] + }] + ] + }, + % endif + % endfor % for core in libs: - % if core.name == 'grpc': + % if core.name == 'grpc' or core.name == 'address_sorting': % for lib in libs: % if lib.name == core.name or (lib.name in core.transitive_deps and lib.name not in ('boringssl', 'z')): { @@ -344,6 +393,8 @@ "dependencies": [ "grpc", "gpr", + "ares", + "address_sorting" ] }, { From 3eb9e2f48f96ee0bc674c101775523aad53de4f0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 May 2019 16:46:44 -0700 Subject: [PATCH 0642/1899] Add scripts for setting up interop clients and servers --- gulpfile.ts | 2 ++ setup_interop.sh | 3 +++ setup_interop_purejs.sh | 3 +++ 3 files changed, 8 insertions(+) create mode 100755 setup_interop.sh create mode 100755 setup_interop_purejs.sh diff --git a/gulpfile.ts b/gulpfile.ts index 2a4fc9140..6265a3857 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -38,6 +38,8 @@ const setup = gulp.series(installAll, link); const setupWindows = gulp.series(installAllWindows, link); +const setupPureJSInterop = gulp.parallel(jsCore.install, protobuf.install, internalTest.install); + const clean = gulp.parallel(jsCore.clean, nativeCore.clean, protobuf.clean); const cleanAll = gulp.parallel(jsCore.cleanAll, nativeCore.cleanAll, healthCheck.cleanAll, internalTest.cleanAll, protobuf.cleanAll); diff --git a/setup_interop.sh b/setup_interop.sh new file mode 100755 index 000000000..d4aa826bc --- /dev/null +++ b/setup_interop.sh @@ -0,0 +1,3 @@ +npm install -g node-gyp gulp +npm install +gulp setup diff --git a/setup_interop_purejs.sh b/setup_interop_purejs.sh new file mode 100755 index 000000000..ea9cd7ece --- /dev/null +++ b/setup_interop_purejs.sh @@ -0,0 +1,3 @@ +npm install -g gulp +npm install +gulp setupPureJSInterop From 1b0f058e24976cf89ee9c16a938849e6dae85aa9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 May 2019 17:46:25 -0700 Subject: [PATCH 0643/1899] Add #!/bin/sh and copyright notice to new scripts --- setup_interop.sh | 15 +++++++++++++++ setup_interop_purejs.sh | 15 +++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/setup_interop.sh b/setup_interop.sh index d4aa826bc..23a30e90d 100755 --- a/setup_interop.sh +++ b/setup_interop.sh @@ -1,3 +1,18 @@ +#!/bin/sh +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + npm install -g node-gyp gulp npm install gulp setup diff --git a/setup_interop_purejs.sh b/setup_interop_purejs.sh index ea9cd7ece..5b81c346e 100755 --- a/setup_interop_purejs.sh +++ b/setup_interop_purejs.sh @@ -1,3 +1,18 @@ +#!/bin/sh +# Copyright 2019 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + npm install -g gulp npm install gulp setupPureJSInterop From fefc4dbba7ba7a892359e3840bdf2590a4ecd432 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 9 May 2019 16:36:08 -0700 Subject: [PATCH 0644/1899] Add resolver tests --- package.json | 2 +- .../grpc-native-core/test/resolver_test.js | 69 +++++++++++++++++++ run-tests.bat | 1 + 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-native-core/test/resolver_test.js diff --git a/package.json b/package.json index 00c647ef3..e910715a5 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "all": true }, "scripts": { - "test": "nyc gulp test", + "test": "nyc gulp test && GRPC_DNS_RESOLVER=ares nyc gulp nativeTestOnly", "coverage": "nyc report --reporter=text-lcov | coveralls" } } diff --git a/packages/grpc-native-core/test/resolver_test.js b/packages/grpc-native-core/test/resolver_test.js new file mode 100644 index 000000000..ea6324ba7 --- /dev/null +++ b/packages/grpc-native-core/test/resolver_test.js @@ -0,0 +1,69 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +var assert = require('assert'); +var _ = require('lodash'); + +var grpc = require('..'); + +const insecureCreds = grpc.credentials.createInsecure(); + +describe('Name resolver', function() { + let server; + let port; + before(function(done) { + const insecureServerCreds = grpc.ServerCredentials.createInsecure(); + server = new grpc.Server(); + server.bindAsync('localhost:0', insecureServerCreds, (error, portVal) => { + port = portVal; + done(error); + }); + }); + after(function() { + server.forceShutdown(); + }); + it('Should resolve a target to IPv4 addresses', function(done) { + const client = new grpc.Client(`loopback4.unittest.grpc.io:${port}`, insecureCreds); + let deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + client.waitForReady(deadline, (error) => { + assert.ifError(error); + done(); + }); + }); + it('Should resolve a target to IPv6 addresses', function(done) { + const client = new grpc.Client(`loopback6.unittest.grpc.io:${port}`, insecureCreds); + let deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + client.waitForReady(deadline, (error) => { + assert.ifError(error); + done(); + }); + }); + it('Should resolve a target to IPv4 and IPv6 addresses', function(done) { + const client = new grpc.Client(`loopback46.unittest.grpc.io:${port}`, insecureCreds); + let deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + client.waitForReady(deadline, (error) => { + assert.ifError(error); + done(); + }); + }); +}); \ No newline at end of file diff --git a/run-tests.bat b/run-tests.bat index fa2b71833..d2484ae35 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -56,6 +56,7 @@ for %%v in (6 7 8 9 10 11 12) do ( call .\node_modules\.bin\gulp cleanAll || SET FAILED=1 call .\node_modules\.bin\gulp setupWindows || SET FAILED=1 call .\node_modules\.bin\gulp test || SET FAILED=1 + cmd.exe /c "SET GRPC_DNS_RESOLVER=ares& call .\node_modules\.bin\gulp nativeTestOnly" || SET FAILED=1 ) node merge_kokoro_logs.js From 3a5284acbeb07551fb68c428f8dac2bd25453091 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 10 May 2019 10:06:09 -0700 Subject: [PATCH 0645/1899] Actually export the new script in the gulp file --- gulpfile.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/gulpfile.ts b/gulpfile.ts index 6265a3857..4c29137de 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -62,6 +62,7 @@ export { link, setup, setupWindows, + setupPureJSInterop, clean, cleanAll, nativeTestOnly, From fbace6417c0c88aa8b38ae9969a0c23010363c20 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 13 May 2019 12:08:50 -0700 Subject: [PATCH 0646/1899] Use a different invalid DNS name in the test --- packages/grpc-native-core/test/surface_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 2f3f73273..94b60e37c 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -939,7 +939,7 @@ describe('Other conditions', function() { * and go to TRANSIENT_FAILURE to confirm that the waitForReady option * makes it end the call instead of continuing to try. A DNS resolution * failure makes that transition very fast. */ - const disconnectedClient = new Client('nothing.invalid:50051', grpc.credentials.createInsecure()); + const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); const metadata = new grpc.Metadata({waitForReady: false}); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); From d3d50ea57b32622cf980b94d0f5ce30dceb356da Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 13 May 2019 13:28:19 -0700 Subject: [PATCH 0647/1899] Increase test timeout --- packages/grpc-native-core/test/surface_test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index 94b60e37c..d5b7add54 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -939,10 +939,11 @@ describe('Other conditions', function() { * and go to TRANSIENT_FAILURE to confirm that the waitForReady option * makes it end the call instead of continuing to try. A DNS resolution * failure makes that transition very fast. */ + this.timeout(15000); const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); const metadata = new grpc.Metadata({waitForReady: false}); const deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); + deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ assert(error); assert.strictEqual(error.code, grpc.status.UNAVAILABLE); From e0a30907f97f0c53510cffb499290877f990f4e2 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 14 May 2019 15:07:12 -0400 Subject: [PATCH 0648/1899] grpc-js: add setupReadable() to Http2ServerCallStream This commit adds a setupReadable() method to Http2ServerCallStream. This is used to set up the plumbing between the HTTP2 stream and the surface readable/bidi calls. --- packages/grpc-js/src/server-call.ts | 62 +++++++++++++++-------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 0e17ceeca..dc6518067 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -101,7 +101,6 @@ export class ServerUnaryCallImpl extends EventEmitter export class ServerReadableStreamImpl extends Readable implements ServerReadableStream { cancelled: boolean; - private decoder: StreamDecoder; constructor( private call: Http2ServerCallStream, @@ -109,36 +108,11 @@ export class ServerReadableStreamImpl extends private _deserialize: Deserialize) { super({objectMode: true}); this.cancelled = false; - this.decoder = new StreamDecoder(); - - const http2Stream = this.call._getHttp2Stream(); - - http2Stream.on('data', async (data: Buffer) => { - const message = this.decoder.write(data); - - if (message === null) { - return; - } - - try { - const deserialized = await this.call.deserializeMessage(message); - - if (!this.push(deserialized)) { - http2Stream.pause(); - } - } catch (err) { - err.code = Status.INTERNAL; - this.emit('error', err); - } - }); - - http2Stream.once('end', () => { - this.push(null); - }); + this.call.setupReadable(this); } _read(size: number) { - this.call._getHttp2Stream().resume(); + this.call.resume(); } deserialize(input: Buffer): RequestType|null { @@ -509,8 +483,36 @@ export class Http2ServerCallStream extends return this.stream.write(chunk); } - _getHttp2Stream(): http2.ServerHttp2Stream { - return this.stream; + resume() { + this.stream.resume(); + } + + setupReadable(readable: ServerReadableStream| + ServerDuplexStream) { + const decoder = new StreamDecoder(); + + this.stream.on('data', async (data: Buffer) => { + const message = decoder.write(data); + + if (message === null) { + return; + } + + try { + const deserialized = await this.deserializeMessage(message); + + if (!readable.push(deserialized)) { + this.stream.pause(); + } + } catch (err) { + err.code = Status.INTERNAL; + readable.emit('error', err); + } + }); + + this.stream.once('end', () => { + readable.push(null); + }); } } From 4857c63d01ff901e76b158b4fca4cdfe9630ae69 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 15 May 2019 09:08:28 -0400 Subject: [PATCH 0649/1899] grpc-js: simplify ServerReadableStream's deserialize() This commit removes null and undefined checks from deserialize(). --- packages/grpc-js/src/server-call.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index dc6518067..b2da85c8c 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -115,11 +115,7 @@ export class ServerReadableStreamImpl extends this.call.resume(); } - deserialize(input: Buffer): RequestType|null { - if (input === null || input === undefined) { - return null; - } - + deserialize(input: Buffer): RequestType { return this._deserialize(input); } From 15d2e01cdad137513aa44b9beca38e98e6f5863e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 15 May 2019 10:03:14 -0700 Subject: [PATCH 0650/1899] Update with new changes on core repo --- packages/grpc-native-core/binding.gyp | 1 - packages/grpc-native-core/deps/grpc | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 542b1424f..cdd22fec4 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -1061,7 +1061,6 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index a8644bbc7..1e0ec4712 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit a8644bbc77ae95f64ef18ac43e52d495273e4bcd +Subproject commit 1e0ec4712e198740db06eb77ff021e0534dc888a From d601720e6c0144b04a12f6e38a5f78beb9de297b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 15 May 2019 10:55:20 -0700 Subject: [PATCH 0651/1899] Add missing defines, remove incorrect include paths --- packages/grpc-native-core/binding.gyp | 10 +++++----- .../grpc-native-core/templates/binding.gyp.template | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index cdd22fec4..7f496c1a6 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -159,8 +159,7 @@ }], ['OS == "win"', { "include_dirs": [ - "deps/grpc/third_party/zlib", - "deps/grpc/third_party/cares/cares" + "deps/grpc/third_party/zlib" ], "defines": [ '_WIN32_WINNT=0x0600', @@ -180,8 +179,7 @@ ] }, { # OS != "win" 'include_dirs': [ - '<(node_root_dir)/deps/zlib', - '<(node_root_dir)/deps/cares/include' + '<(node_root_dir)/deps/zlib' ] }], ['OS == "mac"', { @@ -621,7 +619,9 @@ 'deps/grpc/third_party/cares/cares/windows_port.c', ], 'defines': [ - '_GNU_SOURCE' + '_GNU_SOURCE', + 'CARES_STATICLIB', + 'CARES_SYMBOL_HIDING' ], 'conditions': [ ['OS == "mac"', { diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 3ed7d7699..c4b66f998 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -143,8 +143,7 @@ }], ['OS == "win"', { "include_dirs": [ - "deps/grpc/third_party/zlib", - "deps/grpc/third_party/cares/cares" + "deps/grpc/third_party/zlib" ], "defines": [ '_WIN32_WINNT=0x0600', @@ -164,8 +163,7 @@ ] }, { # OS != "win" 'include_dirs': [ - '<(node_root_dir)/deps/zlib', - '<(node_root_dir)/deps/cares/include' + '<(node_root_dir)/deps/zlib' ] }], ['OS == "mac"', { @@ -294,7 +292,9 @@ % endfor ], 'defines': [ - '_GNU_SOURCE' + '_GNU_SOURCE', + 'CARES_STATICLIB', + 'CARES_SYMBOL_HIDING' ], 'conditions': [ ['OS == "mac"', { From 4d483a6e667f446a5c7c64bc9e3efebafb756dd6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 15 May 2019 11:21:57 -0700 Subject: [PATCH 0652/1899] Make cares defines global --- packages/grpc-native-core/binding.gyp | 8 ++++---- packages/grpc-native-core/templates/binding.gyp.template | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 7f496c1a6..2ab645ce2 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -94,7 +94,9 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.3"' + 'GRPC_NODE_VERSION="1.20.3"', + 'CARES_STATICLIB', + 'CARES_SYMBOL_HIDING' ], 'defines!': [ 'OPENSSL_THREADS' @@ -619,9 +621,7 @@ 'deps/grpc/third_party/cares/cares/windows_port.c', ], 'defines': [ - '_GNU_SOURCE', - 'CARES_STATICLIB', - 'CARES_SYMBOL_HIDING' + '_GNU_SOURCE' ], 'conditions': [ ['OS == "mac"', { diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index c4b66f998..b41486a4c 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -86,7 +86,9 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"' + 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"', + 'CARES_STATICLIB', + 'CARES_SYMBOL_HIDING' ], 'defines!': [ 'OPENSSL_THREADS' @@ -292,9 +294,7 @@ % endfor ], 'defines': [ - '_GNU_SOURCE', - 'CARES_STATICLIB', - 'CARES_SYMBOL_HIDING' + '_GNU_SOURCE' ], 'conditions': [ ['OS == "mac"', { From 61c8bdf10f936478e01fd17d08914830bed1fd22 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 15 May 2019 15:13:21 -0700 Subject: [PATCH 0653/1899] Handle parse failures when merging test logs --- merge_kokoro_logs.js | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/merge_kokoro_logs.js b/merge_kokoro_logs.js index d8cc98db0..9b8e2d9b1 100644 --- a/merge_kokoro_logs.js +++ b/merge_kokoro_logs.js @@ -25,6 +25,30 @@ const readDir = util.promisify(fs.readdir); const rootDir = __dirname; +// Fake test suite log with a failure if log parsing failed +const parseFailureLog = [ + { + $: { + name: 'Unknown Test Suite', + tests: '1', + failures: '1', + }, + testcase: [ + { + $: { + classname: 'Test Log Parsing', + name: 'Test Log Parsing', + failure: { + $: { + message: "Log parsing failed" + } + } + } + } + ] + } +]; + readDir(rootDir + '/reports') .then((dirNames) => Promise.all(dirNames.map((dirName) => @@ -41,7 +65,12 @@ readDir(rootDir + '/reports') ) .then((objects) => { let merged = objects[0]; - merged.testsuites.testsuite = Array.prototype.concat.apply([], objects.map((obj) => obj.testsuites.testsuite)); + merged.testsuites.testsuite = Array.prototype.concat.apply([], objects.map((obj) => { + if (obj) { + return obj.testsuites.testsuite; + } else { + return parseFailureLog; + }})); let builder = new xml2js.Builder(); let xml = builder.buildObject(merged); let resultName = path.resolve(rootDir, 'reports', dirName, 'sponge_log.xml'); From 1aa11525fdaa4add2555f27a484cbc9558b324e9 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 16 May 2019 11:23:54 -0400 Subject: [PATCH 0654/1899] grpc-js: add bidirectional streaming RPC support This commit adds bidi streaming RPC support to the server. --- packages/grpc-js/src/server-call.ts | 20 +++++- packages/grpc-js/src/server.ts | 9 ++- packages/grpc-js/test/test-server-errors.ts | 72 +++++++++++++++++++++ packages/grpc-js/test/test-server.ts | 16 +++++ 4 files changed, 114 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index b2da85c8c..8ecb91d2e 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -204,13 +204,21 @@ export class ServerWritableStreamImpl extends export class ServerDuplexStreamImpl extends Duplex implements ServerDuplexStream { cancelled: boolean; + private trailingMetadata: Metadata; constructor( private call: Http2ServerCallStream, - public metadata: Metadata, private _serialize: Serialize, - private _deserialize: Deserialize) { + public metadata: Metadata, public serialize: Serialize, + public deserialize: Deserialize) { super({objectMode: true}); this.cancelled = false; + this.trailingMetadata = new Metadata(); + this.call.setupReadable(this); + + this.on('error', (err) => { + this.call.sendError(err as ServiceError); + this.end(); + }); } getPeer(): string { @@ -222,6 +230,14 @@ export class ServerDuplexStreamImpl extends Duplex } } +ServerDuplexStreamImpl.prototype._read = + ServerReadableStreamImpl.prototype._read; +ServerDuplexStreamImpl.prototype._write = + ServerWritableStreamImpl.prototype._write; +ServerDuplexStreamImpl.prototype._final = + ServerWritableStreamImpl.prototype._final; +ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; + // Unary response callback signature. export type sendUnaryData = diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 68f6e1498..8331fe1f0 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -355,5 +355,12 @@ function handleBidiStreaming( call: Http2ServerCallStream, handler: BidiStreamingHandler, metadata: Metadata): void { - throw new Error('not implemented yet'); + const stream = new ServerDuplexStreamImpl( + call, metadata, handler.serialize, handler.deserialize); + + if (call.cancelled) { + return; + } + + handler.func(stream); } diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 6f352f736..76e63a6a4 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -147,6 +147,20 @@ describe('Client malformed response handling', () => { done(); }); }); + + it('should get an INTERNAL status with a bidi stream call', (done) => { + const call = client.bidiStream(); + + call.on('data', noop); + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + + call.write({}); + call.end(); + }); }); describe('Server serialization failure handling', () => { @@ -444,6 +458,23 @@ describe('Other conditions', () => { done(); }); }); + + it('should respond correctly to a bidi stream', (done) => { + const call = misbehavingClient.bidiStream(); + + call.on('data', (data: any) => { + assert.fail(data); + }); + + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + }); + + call.write(badArg); + call.end(); + }); }); describe('Trailing metadata', () => { @@ -561,6 +592,33 @@ describe('Other conditions', () => { done(); }); }); + + it('should be present when a bidi stream succeeds', (done) => { + const call = client.bidiStream(); + + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('data', noop); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.OK); + assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + + it('should be present when a bidi stream fails', (done) => { + const call = client.bidiStream(); + + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', noop); + call.on('error', (error: ServiceError) => { + assert.deepStrictEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); }); describe('Error object should contain the status', () => { @@ -597,6 +655,20 @@ describe('Other conditions', () => { }); }); + it('for a bidi stream call', (done) => { + const call = client.bidiStream(); + + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', noop); + call.on('error', (error: ServiceError) => { + assert.strictEqual(error.code, grpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + done(); + }); + }); + it('for a UTF-8 error message', (done) => { client.unary( {error: true, message: '測試字符串'}, diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index d310ff072..6bb7c1ff7 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -286,6 +286,22 @@ describe('Server', () => { done(); }); }); + + it('should respond to a bidi call with UNIMPLEMENTED', (done) => { + const call = client.divMany(); + + call.on('data', (value: any) => { + assert.fail('No messages expected'); + }); + + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + done(); + }); + + call.end(); + }); }); }); From 643dc6c25cc90fd2c80a284cbbf0b8ca4bb8384a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 16 May 2019 16:04:11 -0700 Subject: [PATCH 0655/1899] Bump proto-loader to 0.5.1 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index bbf92af50..b1c713f43 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.0", + "version": "0.5.1", "author": "Google Inc.", "contributors": [ { From 212439eb83d7f12306c842dbe4194198494ee54b Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 17 May 2019 11:40:29 -0400 Subject: [PATCH 0656/1899] grpc-js: make serdes APIs consistent During initial implementation, the serialize and deserialize APIs of ServerReadableStream, ServerWritableStream, and ServerDuplexStream became inconsistent. This commit brings back consistency. --- packages/grpc-js/src/server-call.ts | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 8ecb91d2e..d52ea3cdd 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -104,8 +104,7 @@ export class ServerReadableStreamImpl extends constructor( private call: Http2ServerCallStream, - public metadata: Metadata, - private _deserialize: Deserialize) { + public metadata: Metadata, public deserialize: Deserialize) { super({objectMode: true}); this.cancelled = false; this.call.setupReadable(this); @@ -115,10 +114,6 @@ export class ServerReadableStreamImpl extends this.call.resume(); } - deserialize(input: Buffer): RequestType { - return this._deserialize(input); - } - getPeer(): string { throw new Error('not implemented yet'); } @@ -137,7 +132,7 @@ export class ServerWritableStreamImpl extends constructor( private call: Http2ServerCallStream, - public metadata: Metadata, private _serialize: Serialize) { + public metadata: Metadata, public serialize: Serialize) { super({objectMode: true}); this.cancelled = false; this.request = null; @@ -190,14 +185,6 @@ export class ServerWritableStreamImpl extends super.end(); } - - serialize(input: ResponseType): Buffer|null { - if (input === null || input === undefined) { - return null; - } - - return this._serialize(input); - } } From a7372e2b1cbab62da58ba7de9ac85e8df5f70e6e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 17 May 2019 12:14:27 -0400 Subject: [PATCH 0657/1899] grpc-js: slight cleanup of server imports/exports This commit removes some unnecessary imports and exports from the server code. --- packages/grpc-js/src/server-call.ts | 4 ---- packages/grpc-js/src/server.ts | 6 +++--- packages/grpc-js/test/test-server.ts | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index d52ea3cdd..197ace5c5 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -26,10 +26,6 @@ import {Deserialize, Serialize} from './make-client'; import {Metadata} from './metadata'; import {StreamDecoder} from './stream-decoder'; -function noop(): void {} - -export type PartialServiceError = Partial; - type DeadlineUnitIndexSignature = { [name: string]: number }; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8331fe1f0..8d4915eb5 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -20,18 +20,18 @@ import {AddressInfo, ListenOptions} from 'net'; import {URL} from 'url'; import {ServiceError} from './call'; -import {StatusObject} from './call-stream'; import {Status} from './constants'; import {Deserialize, Serialize, ServiceDefinition} from './make-client'; import {Metadata} from './metadata'; -import {BidiStreamingHandler, ClientStreamingHandler, HandleCall, Handler, HandlerType, Http2ServerCallStream, PartialServiceError, sendUnaryData, ServerDuplexStream, ServerDuplexStreamImpl, ServerReadableStream, ServerReadableStreamImpl, ServerStreamingHandler, ServerUnaryCall, ServerUnaryCallImpl, ServerWritableStream, ServerWritableStreamImpl, UnaryHandler} from './server-call'; +import {BidiStreamingHandler, ClientStreamingHandler, HandleCall, Handler, HandlerType, Http2ServerCallStream, sendUnaryData, ServerDuplexStream, ServerDuplexStreamImpl, ServerReadableStream, ServerReadableStreamImpl, ServerStreamingHandler, ServerUnaryCall, ServerUnaryCallImpl, ServerWritableStream, ServerWritableStreamImpl, UnaryHandler} from './server-call'; import {ServerCredentials} from './server-credentials'; function noop(): void {} -const unimplementedStatusResponse: PartialServiceError = { +const unimplementedStatusResponse: Partial = { code: Status.UNIMPLEMENTED, details: 'The server does not implement this method', + metadata: new Metadata() }; // tslint:disable:no-any diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 6bb7c1ff7..8a5730cd9 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -26,7 +26,7 @@ import {ServerCredentials} from '../src'; import {ServiceError} from '../src/call'; import {ServiceClient, ServiceClientConstructor} from '../src/make-client'; import {Server} from '../src/server'; -import {sendUnaryData, ServerDuplexStream, ServerReadableStream, ServerUnaryCall, ServerWritableStream} from '../src/server-call'; +import {sendUnaryData, ServerUnaryCall} from '../src/server-call'; import {loadProtoFile} from './common'; From f6689d51a678fdaf5d6b98fc0a6013234927f7a3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 17 May 2019 12:30:42 -0400 Subject: [PATCH 0658/1899] grpc-js: update dependencies This commit resolves issues from `npm outdated`. The gts dependency will be updated separately, as it comes with significant code churn. --- packages/grpc-js/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e0827fbe7..968fbe378 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,14 +15,14 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.4.0", + "@grpc/proto-loader": "^0.5.0", "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", - "@types/node": "^11.13.2", + "@types/node": "^12.0.2", "clang-format": "^1.0.55", "gts": "^0.9.0", "lodash": "^4.17.4", - "typescript": "~3.3.3333" + "typescript": "~3.4.5" }, "contributors": [ { From be6bdb8c3db6f351493fad3f880d47011ab03daa Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 17 May 2019 17:03:04 -0400 Subject: [PATCH 0659/1899] grpc-js: update to gts@1.x.x This commit updates the gts dependency to 1.x.x. --- packages/grpc-js/package.json | 2 +- .../grpc-js/src/call-credentials-filter.ts | 23 +- packages/grpc-js/src/call-credentials.ts | 21 +- packages/grpc-js/src/call-stream.ts | 144 ++++--- packages/grpc-js/src/call.ts | 95 +++-- packages/grpc-js/src/channel-credentials.ts | 57 ++- packages/grpc-js/src/channel-options.ts | 4 +- packages/grpc-js/src/channel.ts | 261 +++++++----- packages/grpc-js/src/client.ts | 331 +++++++++----- packages/grpc-js/src/compression-filter.ts | 43 +- packages/grpc-js/src/constants.ts | 4 +- packages/grpc-js/src/deadline-filter.ts | 89 ++-- packages/grpc-js/src/events.ts | 2 +- packages/grpc-js/src/filter-stack.ts | 9 +- packages/grpc-js/src/filter.ts | 4 +- packages/grpc-js/src/index.ts | 236 +++++----- packages/grpc-js/src/logging.ts | 2 +- packages/grpc-js/src/make-client.ts | 60 ++- .../grpc-js/src/metadata-status-filter.ts | 20 +- packages/grpc-js/src/metadata.ts | 32 +- packages/grpc-js/src/object-stream.ts | 25 +- packages/grpc-js/src/server-call.ts | 250 ++++++----- packages/grpc-js/src/server-credentials.ts | 24 +- packages/grpc-js/src/server.ts | 290 ++++++++----- packages/grpc-js/src/status-builder.ts | 12 +- packages/grpc-js/src/stream-decoder.ts | 26 +- packages/grpc-js/src/subchannel.ts | 25 +- packages/grpc-js/test/common.ts | 13 +- .../grpc-js/test/test-call-credentials.ts | 157 ++++--- packages/grpc-js/test/test-call-stream.ts | 402 +++++++++++------- .../grpc-js/test/test-channel-credentials.ts | 91 ++-- packages/grpc-js/test/test-logging.ts | 15 +- packages/grpc-js/test/test-metadata.ts | 101 +++-- .../grpc-js/test/test-server-credentials.ts | 43 +- packages/grpc-js/test/test-server-errors.ts | 258 +++++------ packages/grpc-js/test/test-server.ts | 228 +++++----- packages/grpc-js/test/test-status-builder.ts | 17 +- packages/grpc-native-core/deps/grpc | 2 +- 38 files changed, 2018 insertions(+), 1400 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 968fbe378..318d826c7 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -20,7 +20,7 @@ "@types/mocha": "^5.2.6", "@types/node": "^12.0.2", "clang-format": "^1.0.55", - "gts": "^0.9.0", + "gts": "^1.0.0", "lodash": "^4.17.4", "typescript": "~3.4.5" }, diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index 10ab4958e..e3d842378 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -15,16 +15,18 @@ * */ -import {CallCredentials} from './call-credentials'; -import {Call} from './call-stream'; -import {Http2Channel} from './channel'; -import {BaseFilter, Filter, FilterFactory} from './filter'; -import {Metadata} from './metadata'; +import { CallCredentials } from './call-credentials'; +import { Call } from './call-stream'; +import { Http2Channel } from './channel'; +import { BaseFilter, Filter, FilterFactory } from './filter'; +import { Metadata } from './metadata'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; constructor( - private readonly channel: Http2Channel, private readonly stream: Call) { + private readonly channel: Http2Channel, + private readonly stream: Call + ) { super(); this.channel = channel; this.stream = stream; @@ -45,16 +47,17 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { const channelCredentials = this.channel.credentials._getCallCredentials(); const streamCredentials = this.stream.getCredentials(); const credentials = channelCredentials.compose(streamCredentials); - const credsMetadata = - credentials.generateMetadata({service_url: this.serviceUrl}); + const credsMetadata = credentials.generateMetadata({ + service_url: this.serviceUrl, + }); const resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); return resultMetadata; } } -export class CallCredentialsFilterFactory implements - FilterFactory { +export class CallCredentialsFilterFactory + implements FilterFactory { private readonly channel: Http2Channel; constructor(channel: Http2Channel) { this.channel = channel; diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index 24f9bb3aa..087a3c72f 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -15,15 +15,16 @@ * */ -import {Metadata} from './metadata'; +import { Metadata } from './metadata'; -export type CallMetadataOptions = { +export interface CallMetadataOptions { service_url: string; -}; +} -export type CallMetadataGenerator = - (options: CallMetadataOptions, - cb: (err: Error|null, metadata?: Metadata) => void) => void; +export type CallMetadataGenerator = ( + options: CallMetadataOptions, + cb: (err: Error | null, metadata?: Metadata) => void +) => void; /** * A class that represents a generic method of adding authentication-related @@ -50,8 +51,9 @@ export abstract class CallCredentials { * generates a Metadata object based on these options, which is passed back * to the caller via a supplied (err, metadata) callback. */ - static createFromMetadataGenerator(metadataGenerator: CallMetadataGenerator): - CallCredentials { + static createFromMetadataGenerator( + metadataGenerator: CallMetadataGenerator + ): CallCredentials { return new SingleCallCredentials(metadataGenerator); } @@ -68,7 +70,8 @@ class ComposedCallCredentials extends CallCredentials { async generateMetadata(options: CallMetadataOptions): Promise { const base: Metadata = new Metadata(); const generated: Metadata[] = await Promise.all( - this.creds.map((cred) => cred.generateMetadata(options))); + this.creds.map(cred => cred.generateMetadata(options)) + ); for (const gen of generated) { base.merge(gen); } diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 7c06c335c..4b76d9010 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -16,28 +16,31 @@ */ import * as http2 from 'http2'; -import {Duplex} from 'stream'; - -import {CallCredentials} from './call-credentials'; -import {Http2Channel} from './channel'; -import {Status} from './constants'; -import {EmitterAugmentation1} from './events'; -import {Filter} from './filter'; -import {FilterStackFactory} from './filter-stack'; -import {Metadata} from './metadata'; -import {ObjectDuplex, WriteCallback} from './object-stream'; -import {StreamDecoder} from './stream-decoder'; - -const {HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, NGHTTP2_CANCEL} = - http2.constants; - -export type Deadline = Date|number; +import { Duplex } from 'stream'; + +import { CallCredentials } from './call-credentials'; +import { Http2Channel } from './channel'; +import { Status } from './constants'; +import { EmitterAugmentation1 } from './events'; +import { Filter } from './filter'; +import { FilterStackFactory } from './filter-stack'; +import { Metadata } from './metadata'; +import { ObjectDuplex, WriteCallback } from './object-stream'; +import { StreamDecoder } from './stream-decoder'; + +const { + HTTP2_HEADER_STATUS, + HTTP2_HEADER_CONTENT_TYPE, + NGHTTP2_CANCEL, +} = http2.constants; + +export type Deadline = Date | number; export interface CallStreamOptions { deadline: Deadline; flags: number; host: string; - parentCall: Call|null; + parentCall: Call | null; } export type PartialCallStreamOptions = Partial; @@ -51,7 +54,7 @@ export interface StatusObject { export const enum WriteFlags { BufferHint = 1, NoCompress = 2, - WriteThrough = 4 + WriteThrough = 4, } export interface WriteObject { @@ -63,7 +66,8 @@ export interface WriteObject { * This interface represents a duplex stream associated with a single gRPC call. */ export type Call = { - cancelWithStatus(status: Status, details: string): void; getPeer(): string; + cancelWithStatus(status: Status, details: string): void; + getPeer(): string; sendMetadata(metadata: Metadata): void; getDeadline(): Deadline; @@ -74,26 +78,26 @@ export type Call = { getStatus(): StatusObject | null; getMethod(): string; getHost(): string; -}&EmitterAugmentation1<'metadata', Metadata>& - EmitterAugmentation1<'status', StatusObject>& - ObjectDuplex; +} & EmitterAugmentation1<'metadata', Metadata> & + EmitterAugmentation1<'status', StatusObject> & + ObjectDuplex; export class Http2CallStream extends Duplex implements Call { credentials: CallCredentials = CallCredentials.createEmpty(); filterStack: Filter; - private http2Stream: http2.ClientHttp2Stream|null = null; + private http2Stream: http2.ClientHttp2Stream | null = null; private pendingRead = false; - private pendingWrite: Buffer|null = null; - private pendingWriteCallback: WriteCallback|null = null; - private pendingFinalCallback: Function|null = null; + private pendingWrite: Buffer | null = null; + private pendingWriteCallback: WriteCallback | null = null; + private pendingFinalCallback: Function | null = null; private decoder = new StreamDecoder(); private isReadFilterPending = false; private canPush = false; - private unpushedReadMessages: Array = []; - private unfilteredReadMessages: Array = []; + private unpushedReadMessages: Array = []; + private unfilteredReadMessages: Array = []; // Status code mapped from :status. To be used if grpc-status is not received private mappedStatusCode: Status = Status.UNKNOWN; @@ -106,14 +110,15 @@ export class Http2CallStream extends Duplex implements Call { private handlingTrailers = Promise.resolve(); // This is populated (non-null) if and only if the call has ended - private finalStatus: StatusObject|null = null; + private finalStatus: StatusObject | null = null; constructor( - private readonly methodName: string, - private readonly channel: Http2Channel, - private readonly options: CallStreamOptions, - filterStackFactory: FilterStackFactory) { - super({objectMode: true}); + private readonly methodName: string, + private readonly channel: Http2Channel, + private readonly options: CallStreamOptions, + filterStackFactory: FilterStackFactory + ) { + super({ objectMode: true }); this.filterStack = filterStackFactory.createFilter(this); } @@ -156,7 +161,7 @@ export class Http2CallStream extends Duplex implements Call { } } - private filterReceivedMessage(framedMessage: Buffer|null) { + private filterReceivedMessage(framedMessage: Buffer | null) { /* If we the call has already ended, we don't want to do anything with * this message. Dropping it on the floor is correct behavior */ if (this.finalStatus !== null) { @@ -171,13 +176,15 @@ export class Http2CallStream extends Duplex implements Call { return; } this.isReadFilterPending = true; - this.filterStack.receiveMessage(Promise.resolve(framedMessage)) - .then( - this.handleFilteredRead.bind(this), - this.handleFilterError.bind(this)); + this.filterStack + .receiveMessage(Promise.resolve(framedMessage)) + .then( + this.handleFilteredRead.bind(this), + this.handleFilterError.bind(this) + ); } - private tryPush(messageBytes: Buffer|null): void { + private tryPush(messageBytes: Buffer | null): void { if (this.isReadFilterPending) { this.unfilteredReadMessages.push(messageBytes); } else { @@ -194,20 +201,21 @@ export class Http2CallStream extends Duplex implements Call { } catch (e) { metadata = new Metadata(); } - const status: StatusObject = {code, details, metadata}; + const status: StatusObject = { code, details, metadata }; this.handlingTrailers = (async () => { let finalStatus; try { // Attempt to assign final status. - finalStatus = - await this.filterStack.receiveTrailers(Promise.resolve(status)); + finalStatus = await this.filterStack.receiveTrailers( + Promise.resolve(status) + ); } catch (error) { await this.handlingHeaders; // This is a no-op if the call was already ended when handling headers. this.endCall({ code: Status.INTERNAL, details: 'Failed to process received status', - metadata: new Metadata() + metadata: new Metadata(), }); return; } @@ -260,23 +268,23 @@ export class Http2CallStream extends Duplex implements Call { this.endCall({ code: Status.UNKNOWN, details: error.message, - metadata: new Metadata() + metadata: new Metadata(), }); return; } - this.handlingHeaders = - this.filterStack.receiveMetadata(Promise.resolve(metadata)) - .then((finalMetadata) => { - this.emit('metadata', finalMetadata); - }) - .catch((error) => { - this.destroyHttp2Stream(); - this.endCall({ - code: Status.UNKNOWN, - details: error.message, - metadata: new Metadata() - }); - }); + this.handlingHeaders = this.filterStack + .receiveMetadata(Promise.resolve(metadata)) + .then(finalMetadata => { + this.emit('metadata', finalMetadata); + }) + .catch(error => { + this.destroyHttp2Stream(); + this.endCall({ + code: Status.UNKNOWN, + details: error.message, + metadata: new Metadata(), + }); + }); } }); stream.on('trailers', this.handleTrailers.bind(this)); @@ -290,7 +298,7 @@ export class Http2CallStream extends Duplex implements Call { stream.on('end', () => { this.tryPush(null); }); - stream.on('close', async (errorCode) => { + stream.on('close', async errorCode => { let code: Status; let details = ''; switch (errorCode) { @@ -318,13 +326,13 @@ export class Http2CallStream extends Duplex implements Call { // This is OK, because status codes emitted here correspond to more // catastrophic issues that prevent us from receiving trailers in the // first place. - this.endCall({code, details, metadata: new Metadata()}); + this.endCall({ code, details, metadata: new Metadata() }); }); stream.on('error', (err: Error) => { this.endCall({ code: Status.INTERNAL, details: 'Internal HTTP2 error', - metadata: new Metadata() + metadata: new Metadata(), }); }); if (!this.pendingRead) { @@ -344,7 +352,11 @@ export class Http2CallStream extends Duplex implements Call { sendMetadata(metadata: Metadata): void { this.channel._startHttp2Stream( - this.options.host, this.methodName, this, metadata); + this.options.host, + this.methodName, + this, + metadata + ); } private destroyHttp2Stream() { @@ -363,7 +375,7 @@ export class Http2CallStream extends Duplex implements Call { // If trailers are currently being processed, the call should be ended // by handleTrailers instead. await this.handlingTrailers; - this.endCall({code: status, details, metadata: new Metadata()}); + this.endCall({ code: status, details, metadata: new Metadata() }); })(); } @@ -379,7 +391,7 @@ export class Http2CallStream extends Duplex implements Call { this.credentials = credentials; } - getStatus(): StatusObject|null { + getStatus(): StatusObject | null { return this.finalStatus; } @@ -409,7 +421,7 @@ export class Http2CallStream extends Duplex implements Call { while (this.unpushedReadMessages.length > 0) { const nextMessage = this.unpushedReadMessages.shift(); this.canPush = this.push(nextMessage); - if (nextMessage === null || (!this.canPush)) { + if (nextMessage === null || !this.canPush) { this.canPush = false; return; } @@ -422,7 +434,7 @@ export class Http2CallStream extends Duplex implements Call { } _write(chunk: WriteObject, encoding: string, cb: WriteCallback) { - this.filterStack.sendMessage(Promise.resolve(chunk)).then((message) => { + this.filterStack.sendMessage(Promise.resolve(chunk)).then(message => { if (this.http2Stream === null) { this.pendingWrite = message.message; this.pendingWriteCallback = cb; diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index f0b23a7eb..2f45b82fd 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -15,27 +15,29 @@ * */ -import {EventEmitter} from 'events'; -import {Duplex, Readable, Writable} from 'stream'; +import { EventEmitter } from 'events'; +import { Duplex, Readable, Writable } from 'stream'; -import {Call, StatusObject, WriteObject} from './call-stream'; -import {Status} from './constants'; -import {EmitterAugmentation1} from './events'; -import {Metadata} from './metadata'; -import {ObjectReadable, ObjectWritable} from './object-stream'; +import { Call, StatusObject, WriteObject } from './call-stream'; +import { Status } from './constants'; +import { EmitterAugmentation1 } from './events'; +import { Metadata } from './metadata'; +import { ObjectReadable, ObjectWritable } from './object-stream'; /** * A type extending the built-in Error object with additional fields. */ -export type ServiceError = StatusObject&Error; +export type ServiceError = StatusObject & Error; /** * A base type for all user-facing values returned by client-side method calls. */ export type SurfaceCall = { - cancel(): void; getPeer(): string; -}&EmitterAugmentation1<'metadata', Metadata>& - EmitterAugmentation1<'status', StatusObject>&EventEmitter; + cancel(): void; + getPeer(): string; +} & EmitterAugmentation1<'metadata', Metadata> & + EmitterAugmentation1<'status', StatusObject> & + EventEmitter; /** * A type representing the return value of a unary method call. @@ -47,23 +49,27 @@ export type ClientUnaryCall = SurfaceCall; */ export type ClientReadableStream = { deserialize: (chunk: Buffer) => ResponseType; -}&SurfaceCall&ObjectReadable; +} & SurfaceCall & + ObjectReadable; /** * A type representing the return value of a client stream method call. */ export type ClientWritableStream = { serialize: (value: RequestType) => Buffer; -}&SurfaceCall&ObjectWritable; +} & SurfaceCall & + ObjectWritable; /** * A type representing the return value of a bidirectional stream method call. */ -export type ClientDuplexStream = - ClientWritableStream&ClientReadableStream; +export type ClientDuplexStream< + RequestType, + ResponseType +> = ClientWritableStream & ClientReadableStream; -export class ClientUnaryCallImpl extends EventEmitter implements - ClientUnaryCall { +export class ClientUnaryCallImpl extends EventEmitter + implements ClientUnaryCall { constructor(private readonly call: Call) { super(); call.on('metadata', (metadata: Metadata) => { @@ -84,8 +90,10 @@ export class ClientUnaryCallImpl extends EventEmitter implements } function setUpReadableStream( - stream: ClientReadableStream, call: Call, - deserialize: (chunk: Buffer) => ResponseType): void { + stream: ClientReadableStream, + call: Call, + deserialize: (chunk: Buffer) => ResponseType +): void { let statusEmitted = false; call.on('data', (data: Buffer) => { let deserialized: ResponseType; @@ -110,8 +118,10 @@ function setUpReadableStream( }); call.on('status', (status: StatusObject) => { if (status.code !== Status.OK) { - const error: ServiceError = - Object.assign(new Error(status.details), status); + const error: ServiceError = Object.assign( + new Error(status.details), + status + ); stream.emit('error', error); } stream.emit('status', status); @@ -120,12 +130,13 @@ function setUpReadableStream( call.pause(); } -export class ClientReadableStreamImpl extends Readable implements - ClientReadableStream { +export class ClientReadableStreamImpl extends Readable + implements ClientReadableStream { constructor( - private readonly call: Call, - readonly deserialize: (chunk: Buffer) => ResponseType) { - super({objectMode: true}); + private readonly call: Call, + readonly deserialize: (chunk: Buffer) => ResponseType + ) { + super({ objectMode: true }); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); }); @@ -146,8 +157,12 @@ export class ClientReadableStreamImpl extends Readable implements } function tryWrite( - call: Call, serialize: (value: RequestType) => Buffer, chunk: RequestType, - encoding: string, cb: Function) { + call: Call, + serialize: (value: RequestType) => Buffer, + chunk: RequestType, + encoding: string, + cb: Function +) { let message: Buffer; const flags: number = Number(encoding); try { @@ -157,19 +172,20 @@ function tryWrite( cb(e); return; } - const writeObj: WriteObject = {message}; + const writeObj: WriteObject = { message }; if (!Number.isNaN(flags)) { writeObj.flags = flags; } call.write(writeObj, cb); } -export class ClientWritableStreamImpl extends Writable implements - ClientWritableStream { +export class ClientWritableStreamImpl extends Writable + implements ClientWritableStream { constructor( - private readonly call: Call, - readonly serialize: (value: RequestType) => Buffer) { - super({objectMode: true}); + private readonly call: Call, + readonly serialize: (value: RequestType) => Buffer + ) { + super({ objectMode: true }); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); }); @@ -197,12 +213,13 @@ export class ClientWritableStreamImpl extends Writable implements } export class ClientDuplexStreamImpl extends Duplex - implements ClientDuplexStream { + implements ClientDuplexStream { constructor( - private readonly call: Call, - readonly serialize: (value: RequestType) => Buffer, - readonly deserialize: (chunk: Buffer) => ResponseType) { - super({objectMode: true}); + private readonly call: Call, + readonly serialize: (value: RequestType) => Buffer, + readonly deserialize: (chunk: Buffer) => ResponseType + ) { + super({ objectMode: true }); call.on('metadata', (metadata: Metadata) => { this.emit('metadata', metadata); }); diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 9f411b212..31320be39 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -15,9 +15,9 @@ * */ -import {ConnectionOptions, createSecureContext, PeerCertificate} from 'tls'; +import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; -import {CallCredentials} from './call-credentials'; +import { CallCredentials } from './call-credentials'; // tslint:disable-next-line:no-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -42,8 +42,10 @@ export interface Certificate { * indicate that the presented certificate is considered invalid and * otherwise returned undefined. */ -export type CheckServerIdentityCallback = - (hostname: string, cert: Certificate) => Error|undefined; +export type CheckServerIdentityCallback = ( + hostname: string, + cert: Certificate +) => Error | undefined; /** * Additional peer verification options that can be set when creating @@ -88,7 +90,7 @@ export abstract class ChannelCredentials { * instance was created with createSsl, or null if this instance was created * with createInsecure. */ - abstract _getConnectionOptions(): ConnectionOptions|null; + abstract _getConnectionOptions(): ConnectionOptions | null; /** * Indicates whether this credentials object creates a secure channel. @@ -104,31 +106,37 @@ export abstract class ChannelCredentials { * @param certChain The client certificate key chain, if available. */ static createSsl( - rootCerts?: Buffer|null, privateKey?: Buffer|null, - certChain?: Buffer|null, - verifyOptions?: VerifyOptions): ChannelCredentials { + rootCerts?: Buffer | null, + privateKey?: Buffer | null, + certChain?: Buffer | null, + verifyOptions?: VerifyOptions + ): ChannelCredentials { verifyIsBufferOrNull(rootCerts, 'Root certificate'); verifyIsBufferOrNull(privateKey, 'Private key'); verifyIsBufferOrNull(certChain, 'Certificate chain'); if (privateKey && !certChain) { throw new Error( - 'Private key must be given with accompanying certificate chain'); + 'Private key must be given with accompanying certificate chain' + ); } if (!privateKey && certChain) { throw new Error( - 'Certificate chain must be given with accompanying private key'); + 'Certificate chain must be given with accompanying private key' + ); } const secureContext = createSecureContext({ ca: rootCerts || undefined, key: privateKey || undefined, - cert: certChain || undefined + cert: certChain || undefined, }); - const connectionOptions: ConnectionOptions = {secureContext}; + const connectionOptions: ConnectionOptions = { secureContext }; if (verifyOptions && verifyOptions.checkServerIdentity) { - connectionOptions.checkServerIdentity = - (host: string, cert: PeerCertificate) => { - return verifyOptions.checkServerIdentity!(host, {raw: cert.raw}); - }; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ) => { + return verifyOptions.checkServerIdentity!(host, { raw: cert.raw }); + }; } return new SecureChannelCredentialsImpl(connectionOptions); } @@ -150,7 +158,7 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { throw new Error('Cannot compose insecure credentials'); } - _getConnectionOptions(): ConnectionOptions|null { + _getConnectionOptions(): ConnectionOptions | null { return null; } _isSecure(): boolean { @@ -162,19 +170,24 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { connectionOptions: ConnectionOptions; constructor( - connectionOptions: ConnectionOptions, callCredentials?: CallCredentials) { + connectionOptions: ConnectionOptions, + callCredentials?: CallCredentials + ) { super(callCredentials); this.connectionOptions = connectionOptions; } compose(callCredentials: CallCredentials): ChannelCredentials { - const combinedCallCredentials = - this.callCredentials.compose(callCredentials); + const combinedCallCredentials = this.callCredentials.compose( + callCredentials + ); return new SecureChannelCredentialsImpl( - this.connectionOptions, combinedCallCredentials); + this.connectionOptions, + combinedCallCredentials + ); } - _getConnectionOptions(): ConnectionOptions|null { + _getConnectionOptions(): ConnectionOptions | null { return this.connectionOptions; } _isSecure(): boolean { diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 54e68f4c3..6b1d42eef 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -25,7 +25,7 @@ export interface ChannelOptions { 'grpc.default_authority': string; 'grpc.keepalive_time_ms': number; 'grpc.keepalive_timeout_ms': number; - [key: string]: string|number; + [key: string]: string | number; } /** @@ -38,5 +38,5 @@ export const recognizedOptions = { 'grpc.secondary_user_agent': true, 'grpc.default_authority': true, 'grpc.keepalive_time_ms': true, - 'grpc.keepalive_timeout_ms': true + 'grpc.keepalive_timeout_ms': true, }; diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 52a22e6e6..a81deec13 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -15,24 +15,29 @@ * */ -import {EventEmitter} from 'events'; +import { EventEmitter } from 'events'; import * as http2 from 'http2'; -import {checkServerIdentity, PeerCertificate} from 'tls'; +import { checkServerIdentity, PeerCertificate } from 'tls'; import * as url from 'url'; -import {CallCredentialsFilterFactory} from './call-credentials-filter'; -import {Call, CallStreamOptions, Deadline, Http2CallStream} from './call-stream'; -import {ChannelCredentials} from './channel-credentials'; -import {ChannelOptions, recognizedOptions} from './channel-options'; -import {CompressionFilterFactory} from './compression-filter'; -import {Status} from './constants'; -import {DeadlineFilterFactory} from './deadline-filter'; -import {FilterStackFactory} from './filter-stack'; -import {Metadata} from './metadata'; -import {MetadataStatusFilterFactory} from './metadata-status-filter'; -import {Http2SubChannel} from './subchannel'; +import { CallCredentialsFilterFactory } from './call-credentials-filter'; +import { + Call, + CallStreamOptions, + Deadline, + Http2CallStream, +} from './call-stream'; +import { ChannelCredentials } from './channel-credentials'; +import { ChannelOptions, recognizedOptions } from './channel-options'; +import { CompressionFilterFactory } from './compression-filter'; +import { Status } from './constants'; +import { DeadlineFilterFactory } from './deadline-filter'; +import { FilterStackFactory } from './filter-stack'; +import { Metadata } from './metadata'; +import { MetadataStatusFilterFactory } from './metadata-status-filter'; +import { Http2SubChannel } from './subchannel'; -const {version: clientVersion} = require('../../package.json'); +const { version: clientVersion } = require('../../package.json'); const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; @@ -46,7 +51,7 @@ const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_TE, - HTTP2_HEADER_USER_AGENT + HTTP2_HEADER_USER_AGENT, } = http2.constants; export enum ConnectivityState { @@ -54,7 +59,7 @@ export enum ConnectivityState { READY, TRANSIENT_FAILURE, IDLE, - SHUTDOWN + SHUTDOWN, } function uniformRandom(min: number, max: number) { @@ -98,8 +103,10 @@ export interface Channel { * error if the deadline passes without a state change. */ watchConnectivityState( - currentState: ConnectivityState, deadline: Date|number, - callback: (error?: Error) => void): void; + currentState: ConnectivityState, + deadline: Date | number, + callback: (error?: Error) => void + ): void; /** * Create a call object. Call is an opaque type that is used by the Client * class. This function is called by the gRPC library when starting a @@ -113,9 +120,12 @@ export interface Channel { * that indicates what information to propagate from parentCall. */ createCall( - method: string, deadline: Deadline|null|undefined, - host: string|null|undefined, parentCall: Call|null|undefined, - propagateFlags: number|null|undefined): Call; + method: string, + deadline: Deadline | null | undefined, + host: string | null | undefined, + parentCall: Call | null | undefined, + propagateFlags: number | null | undefined + ): Call; } export class Http2Channel extends EventEmitter implements Channel { @@ -124,10 +134,10 @@ export class Http2Channel extends EventEmitter implements Channel { private readonly defaultAuthority: string; private connectivityState: ConnectivityState = ConnectivityState.IDLE; // Helper Promise object only used in the implementation of connect(). - private connecting: Promise|null = null; + private connecting: Promise | null = null; /* For now, we have up to one subchannel, which will exist as long as we are * connecting or trying to connect */ - private subChannel: Http2SubChannel|null = null; + private subChannel: Http2SubChannel | null = null; private filterStackFactory: FilterStackFactory; private subChannelConnectCallback: () => void = () => {}; @@ -138,21 +148,28 @@ export class Http2Channel extends EventEmitter implements Channel { private currentBackoffDeadline: Date; private handleStateChange( - oldState: ConnectivityState, newState: ConnectivityState): void { + oldState: ConnectivityState, + newState: ConnectivityState + ): void { const now: Date = new Date(); switch (newState) { case ConnectivityState.CONNECTING: if (oldState === ConnectivityState.IDLE) { this.currentBackoff = INITIAL_BACKOFF_MS; - this.currentBackoffDeadline = - new Date(now.getTime() + INITIAL_BACKOFF_MS); + this.currentBackoffDeadline = new Date( + now.getTime() + INITIAL_BACKOFF_MS + ); } else if (oldState === ConnectivityState.TRANSIENT_FAILURE) { this.currentBackoff = Math.min( - this.currentBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); + this.currentBackoff * BACKOFF_MULTIPLIER, + MAX_BACKOFF_MS + ); const jitterMagnitude: number = BACKOFF_JITTER * this.currentBackoff; this.currentBackoffDeadline = new Date( - now.getTime() + this.currentBackoff + - uniformRandom(-jitterMagnitude, jitterMagnitude)); + now.getTime() + + this.currentBackoff + + uniformRandom(-jitterMagnitude, jitterMagnitude) + ); } this.startConnecting(); break; @@ -163,8 +180,9 @@ export class Http2Channel extends EventEmitter implements Channel { this.subChannel = null; this.backoffTimerId = setTimeout(() => { this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE], - ConnectivityState.CONNECTING); + [ConnectivityState.TRANSIENT_FAILURE], + ConnectivityState.CONNECTING + ); }, this.currentBackoffDeadline.getTime() - now.getTime()); break; case ConnectivityState.IDLE: @@ -172,7 +190,9 @@ export class Http2Channel extends EventEmitter implements Channel { if (this.subChannel) { this.subChannel.close(); this.subChannel.removeListener( - 'connect', this.subChannelConnectCallback); + 'connect', + this.subChannelConnectCallback + ); this.subChannel.removeListener('close', this.subChannelCloseCallback); this.subChannel = null; this.emit('shutdown'); @@ -186,7 +206,9 @@ export class Http2Channel extends EventEmitter implements Channel { // Transition from any of a set of oldStates to a specific newState private transitionToState( - oldStates: ConnectivityState[], newState: ConnectivityState): void { + oldStates: ConnectivityState[], + newState: ConnectivityState + ): void { if (oldStates.indexOf(this.connectivityState) > -1) { const oldState: ConnectivityState = this.connectivityState; this.connectivityState = newState; @@ -197,28 +219,36 @@ export class Http2Channel extends EventEmitter implements Channel { private startConnecting(): void { const connectionOptions: http2.SecureClientSessionOptions = - this.credentials._getConnectionOptions() || {}; + this.credentials._getConnectionOptions() || {}; if (connectionOptions.secureContext !== null) { // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. // This option is used for testing only. if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = - this.options['grpc.ssl_target_name_override']!; - connectionOptions.checkServerIdentity = - (host: string, cert: PeerCertificate): Error|undefined => { - return checkServerIdentity(sslTargetNameOverride, cert); - }; + const sslTargetNameOverride = this.options[ + 'grpc.ssl_target_name_override' + ]!; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; connectionOptions.servername = sslTargetNameOverride; } } const subChannel: Http2SubChannel = new Http2SubChannel( - this.target, connectionOptions, this.userAgent, this.options); + this.target, + connectionOptions, + this.userAgent, + this.options + ); this.subChannel = subChannel; const now = new Date(); const connectionTimeout: number = Math.max( - this.currentBackoffDeadline.getTime() - now.getTime(), - MIN_CONNECT_TIMEOUT_MS); + this.currentBackoffDeadline.getTime() - now.getTime(), + MIN_CONNECT_TIMEOUT_MS + ); const connectionTimerId: NodeJS.Timer = setTimeout(() => { // This should trigger the 'close' event, which will send us back to // TRANSIENT_FAILURE @@ -228,7 +258,9 @@ export class Http2Channel extends EventEmitter implements Channel { // Connection succeeded clearTimeout(connectionTimerId); this.transitionToState( - [ConnectivityState.CONNECTING], ConnectivityState.READY); + [ConnectivityState.CONNECTING], + ConnectivityState.READY + ); }; subChannel.once('connect', this.subChannelConnectCallback); this.subChannelCloseCallback = () => { @@ -237,21 +269,25 @@ export class Http2Channel extends EventEmitter implements Channel { /* TODO(murgatroid99): verify that this works for * CONNECTING->TRANSITIVE_FAILURE see nodejs/node#16645 */ this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE); + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE + ); }; subChannel.once('close', this.subChannelCloseCallback); } constructor( - address: string, readonly credentials: ChannelCredentials, - private readonly options: Partial) { + address: string, + readonly credentials: ChannelCredentials, + private readonly options: Partial + ) { super(); for (const option in options) { if (options.hasOwnProperty(option)) { if (!recognizedOptions.hasOwnProperty(option)) { console.warn( - `Unrecognized channel argument '${option}' will be ignored.`); + `Unrecognized channel argument '${option}' will be ignored.` + ); } } } @@ -267,8 +303,10 @@ export class Http2Channel extends EventEmitter implements Channel { this.defaultAuthority = this.target.host; } this.filterStackFactory = new FilterStackFactory([ - new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), - new MetadataStatusFilterFactory(this), new CompressionFilterFactory(this) + new CallCredentialsFilterFactory(this), + new DeadlineFilterFactory(this), + new MetadataStatusFilterFactory(this), + new CompressionFilterFactory(this), ]); this.currentBackoffDeadline = new Date(); /* The only purpose of these lines is to ensure that this.backoffTimerId has @@ -277,61 +315,75 @@ export class Http2Channel extends EventEmitter implements Channel { // Build user-agent string. this.userAgent = [ - options['grpc.primary_user_agent'], `grpc-node-js/${clientVersion}`, - options['grpc.secondary_user_agent'] - ].filter(e => e).join(' '); // remove falsey values first + options['grpc.primary_user_agent'], + `grpc-node-js/${clientVersion}`, + options['grpc.secondary_user_agent'], + ] + .filter(e => e) + .join(' '); // remove falsey values first } _startHttp2Stream( - authority: string, methodName: string, stream: Http2CallStream, - metadata: Metadata) { - const finalMetadata: Promise = - stream.filterStack.sendMetadata(Promise.resolve(metadata.clone())); + authority: string, + methodName: string, + stream: Http2CallStream, + metadata: Metadata + ) { + const finalMetadata: Promise = stream.filterStack.sendMetadata( + Promise.resolve(metadata.clone()) + ); Promise.all([finalMetadata, this.connect()]) - .then(([metadataValue]) => { - const headers = metadataValue.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = authority; - headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; - headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; - headers[HTTP2_HEADER_METHOD] = 'POST'; - headers[HTTP2_HEADER_PATH] = methodName; - headers[HTTP2_HEADER_TE] = 'trailers'; - if (this.connectivityState === ConnectivityState.READY) { - const subChannel: Http2SubChannel = this.subChannel!; - subChannel.startCallStream(metadataValue, stream); - } else { - /* In this case, we lost the connection while finalizing - * metadata. That should be very unusual */ - setImmediate(() => { - this._startHttp2Stream(authority, methodName, stream, metadata); - }); - } - }) - .catch((error: Error&{code: number}) => { - // We assume the error code isn't 0 (Status.OK) - stream.cancelWithStatus( - error.code || Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${ - error.message}`); - }); + .then(([metadataValue]) => { + const headers = metadataValue.toHttp2Headers(); + headers[HTTP2_HEADER_AUTHORITY] = authority; + headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; + headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; + headers[HTTP2_HEADER_METHOD] = 'POST'; + headers[HTTP2_HEADER_PATH] = methodName; + headers[HTTP2_HEADER_TE] = 'trailers'; + if (this.connectivityState === ConnectivityState.READY) { + const subChannel: Http2SubChannel = this.subChannel!; + subChannel.startCallStream(metadataValue, stream); + } else { + /* In this case, we lost the connection while finalizing + * metadata. That should be very unusual */ + setImmediate(() => { + this._startHttp2Stream(authority, methodName, stream, metadata); + }); + } + }) + .catch((error: Error & { code: number }) => { + // We assume the error code isn't 0 (Status.OK) + stream.cancelWithStatus( + error.code || Status.UNKNOWN, + `Getting metadata from plugin failed with error: ${error.message}` + ); + }); } createCall( - method: string, deadline: Deadline|null|undefined, - host: string|null|undefined, parentCall: Call|null|undefined, - propagateFlags: number|null|undefined): Call { + method: string, + deadline: Deadline | null | undefined, + host: string | null | undefined, + parentCall: Call | null | undefined, + propagateFlags: number | null | undefined + ): Call { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } const finalOptions: CallStreamOptions = { - deadline: (deadline === null || deadline === undefined) ? Infinity : - deadline, + deadline: + deadline === null || deadline === undefined ? Infinity : deadline, flags: propagateFlags || 0, host: host || this.defaultAuthority, - parentCall: parentCall || null + parentCall: parentCall || null, }; const stream: Http2CallStream = new Http2CallStream( - method, this, finalOptions, this.filterStackFactory); + method, + this, + finalOptions, + this.filterStackFactory + ); return stream; } @@ -351,7 +403,9 @@ export class Http2Channel extends EventEmitter implements Channel { if (!this.connecting) { this.connecting = new Promise((resolve, reject) => { this.transitionToState( - [ConnectivityState.IDLE], ConnectivityState.CONNECTING); + [ConnectivityState.IDLE], + ConnectivityState.CONNECTING + ); const onConnect = () => { this.connecting = null; this.removeListener('shutdown', onShutdown); @@ -373,14 +427,18 @@ export class Http2Channel extends EventEmitter implements Channel { getConnectivityState(tryToConnect: boolean): ConnectivityState { if (tryToConnect) { this.transitionToState( - [ConnectivityState.IDLE], ConnectivityState.CONNECTING); + [ConnectivityState.IDLE], + ConnectivityState.CONNECTING + ); } return this.connectivityState; } watchConnectivityState( - currentState: ConnectivityState, deadline: Date|number, - callback: (error?: Error) => void) { + currentState: ConnectivityState, + deadline: Date | number, + callback: (error?: Error) => void + ) { if (this.connectivityState !== currentState) { /* If the connectivity state is different from the provided currentState, * we assume that a state change has successfully occurred */ @@ -417,10 +475,13 @@ export class Http2Channel extends EventEmitter implements Channel { throw new Error('Channel has been shut down'); } this.transitionToState( - [ - ConnectivityState.CONNECTING, ConnectivityState.READY, - ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.IDLE - ], - ConnectivityState.SHUTDOWN); + [ + ConnectivityState.CONNECTING, + ConnectivityState.READY, + ConnectivityState.TRANSIENT_FAILURE, + ConnectivityState.IDLE, + ], + ConnectivityState.SHUTDOWN + ); } } diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index a793cf6f5..5b243c383 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -15,19 +15,29 @@ * */ -import {ClientDuplexStream, ClientDuplexStreamImpl, ClientReadableStream, ClientReadableStreamImpl, ClientUnaryCall, ClientUnaryCallImpl, ClientWritableStream, ClientWritableStreamImpl, ServiceError} from './call'; -import {CallCredentials} from './call-credentials'; -import {Call, Deadline, StatusObject, WriteObject} from './call-stream'; -import {Channel, ConnectivityState, Http2Channel} from './channel'; -import {ChannelCredentials} from './channel-credentials'; -import {ChannelOptions} from './channel-options'; -import {Status} from './constants'; -import {Metadata} from './metadata'; +import { + ClientDuplexStream, + ClientDuplexStreamImpl, + ClientReadableStream, + ClientReadableStreamImpl, + ClientUnaryCall, + ClientUnaryCallImpl, + ClientWritableStream, + ClientWritableStreamImpl, + ServiceError, +} from './call'; +import { CallCredentials } from './call-credentials'; +import { Call, Deadline, StatusObject, WriteObject } from './call-stream'; +import { Channel, ConnectivityState, Http2Channel } from './channel'; +import { ChannelCredentials } from './channel-credentials'; +import { ChannelOptions } from './channel-options'; +import { Status } from './constants'; +import { Metadata } from './metadata'; const CHANNEL_SYMBOL = Symbol(); export interface UnaryCallback { - (err: ServiceError|null, value?: ResponseType): void; + (err: ServiceError | null, value?: ResponseType): void; } export interface CallOptions { @@ -39,10 +49,13 @@ export interface CallOptions { credentials?: CallCredentials; } -export type ClientOptions = Partial&{ - channelOverride?: Channel, - channelFactoryOverride?: (address: string, credentials: ChannelCredentials, - options: ClientOptions) => Channel +export type ClientOptions = Partial & { + channelOverride?: Channel; + channelFactoryOverride?: ( + address: string, + credentials: ChannelCredentials, + options: ClientOptions + ) => Channel; }; /** @@ -50,15 +63,20 @@ export type ClientOptions = Partial&{ * clients. */ export class Client { - private readonly[CHANNEL_SYMBOL]: Channel; + private readonly [CHANNEL_SYMBOL]: Channel; constructor( - address: string, credentials: ChannelCredentials, - options: ClientOptions = {}) { + address: string, + credentials: ChannelCredentials, + options: ClientOptions = {} + ) { if (options.channelOverride) { this[CHANNEL_SYMBOL] = options.channelOverride; } else if (options.channelFactoryOverride) { - this[CHANNEL_SYMBOL] = - options.channelFactoryOverride(address, credentials, options); + this[CHANNEL_SYMBOL] = options.channelFactoryOverride( + address, + credentials, + options + ); } else { this[CHANNEL_SYMBOL] = new Http2Channel(address, credentials, options); } @@ -90,7 +108,10 @@ export class Client { } else { try { this[CHANNEL_SYMBOL].watchConnectivityState( - newState, deadline, checkState); + newState, + deadline, + checkState + ); } catch (e) { callback(new Error('The channel has been closed')); } @@ -100,9 +121,11 @@ export class Client { } private handleUnaryResponse( - call: Call, deserialize: (value: Buffer) => ResponseType, - callback: UnaryCallback): void { - let responseMessage: ResponseType|null = null; + call: Call, + deserialize: (value: Buffer) => ResponseType, + callback: UnaryCallback + ): void { + let responseMessage: ResponseType | null = null; call.on('data', (data: Buffer) => { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -111,7 +134,9 @@ export class Client { responseMessage = deserialize(data); } catch (e) { call.cancelWithStatus( - Status.INTERNAL, 'Failed to parse server response'); + Status.INTERNAL, + 'Failed to parse server response' + ); } }); call.on('end', () => { @@ -127,73 +152,102 @@ export class Client { if (status.code === Status.OK) { callback(null, responseMessage as ResponseType); } else { - const error: ServiceError = - Object.assign(new Error(status.details), status); + const error: ServiceError = Object.assign( + new Error(status.details), + status + ); callback(error); } }); } private checkOptionalUnaryResponseArguments( - arg1: Metadata|CallOptions|UnaryCallback, - arg2?: CallOptions|UnaryCallback, - arg3?: UnaryCallback): { - metadata: Metadata, - options: CallOptions, - callback: UnaryCallback + arg1: Metadata | CallOptions | UnaryCallback, + arg2?: CallOptions | UnaryCallback, + arg3?: UnaryCallback + ): { + metadata: Metadata; + options: CallOptions; + callback: UnaryCallback; } { if (arg1 instanceof Function) { - return {metadata: new Metadata(), options: {}, callback: arg1}; + return { metadata: new Metadata(), options: {}, callback: arg1 }; } else if (arg2 instanceof Function) { if (arg1 instanceof Metadata) { - return {metadata: arg1, options: {}, callback: arg2}; + return { metadata: arg1, options: {}, callback: arg2 }; } else { - return {metadata: new Metadata(), options: arg1, callback: arg2}; + return { metadata: new Metadata(), options: arg1, callback: arg2 }; } } else { - if (!((arg1 instanceof Metadata) && (arg2 instanceof Object) && - (arg3 instanceof Function))) { + if ( + !( + arg1 instanceof Metadata && + arg2 instanceof Object && + arg3 instanceof Function + ) + ) { throw new Error('Incorrect arguments passed'); } - return {metadata: arg1, options: arg2, callback: arg3}; + return { metadata: arg1, options: arg2, callback: arg3 }; } } makeUnaryRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - metadata: Metadata, options: CallOptions, - callback: UnaryCallback): ClientUnaryCall; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + metadata: Metadata, + options: CallOptions, + callback: UnaryCallback + ): ClientUnaryCall; makeUnaryRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - metadata: Metadata, - callback: UnaryCallback): ClientUnaryCall; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + metadata: Metadata, + callback: UnaryCallback + ): ClientUnaryCall; makeUnaryRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - options: CallOptions, - callback: UnaryCallback): ClientUnaryCall; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + options: CallOptions, + callback: UnaryCallback + ): ClientUnaryCall; makeUnaryRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - callback: UnaryCallback): ClientUnaryCall; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + callback: UnaryCallback + ): ClientUnaryCall; makeUnaryRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - metadata: Metadata|CallOptions|UnaryCallback, - options?: CallOptions|UnaryCallback, - callback?: UnaryCallback): ClientUnaryCall { - ({metadata, options, callback} = - this.checkOptionalUnaryResponseArguments( - metadata, options, callback)); + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + metadata: Metadata | CallOptions | UnaryCallback, + options?: CallOptions | UnaryCallback, + callback?: UnaryCallback + ): ClientUnaryCall { + ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< + ResponseType + >(metadata, options, callback)); const call: Call = this[CHANNEL_SYMBOL].createCall( - method, options.deadline, options.host, null, options.propagate_flags); + method, + options.deadline, + options.host, + null, + options.propagate_flags + ); if (options.credentials) { call.setCredentials(options.credentials); } const message: Buffer = serialize(argument); - const writeObj: WriteObject = {message}; + const writeObj: WriteObject = { message }; call.sendMetadata(metadata); call.write(writeObj); call.end(); @@ -202,34 +256,51 @@ export class Client { } makeClientStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, metadata: Metadata, - options: CallOptions, - callback: UnaryCallback): ClientWritableStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + metadata: Metadata, + options: CallOptions, + callback: UnaryCallback + ): ClientWritableStream; makeClientStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, metadata: Metadata, - callback: UnaryCallback): ClientWritableStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + metadata: Metadata, + callback: UnaryCallback + ): ClientWritableStream; makeClientStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, options: CallOptions, - callback: UnaryCallback): ClientWritableStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + options: CallOptions, + callback: UnaryCallback + ): ClientWritableStream; makeClientStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, - callback: UnaryCallback): ClientWritableStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + callback: UnaryCallback + ): ClientWritableStream; makeClientStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, - metadata: Metadata|CallOptions|UnaryCallback, - options?: CallOptions|UnaryCallback, - callback?: UnaryCallback): - ClientWritableStream { - ({metadata, options, callback} = - this.checkOptionalUnaryResponseArguments( - metadata, options, callback)); + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + metadata: Metadata | CallOptions | UnaryCallback, + options?: CallOptions | UnaryCallback, + callback?: UnaryCallback + ): ClientWritableStream { + ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< + ResponseType + >(metadata, options, callback)); const call: Call = this[CHANNEL_SYMBOL].createCall( - method, options.deadline, options.host, null, options.propagate_flags); + method, + options.deadline, + options.host, + null, + options.propagate_flags + ); if (options.credentials) { call.setCredentials(options.credentials); } @@ -239,8 +310,9 @@ export class Client { } private checkMetadataAndOptions( - arg1?: Metadata|CallOptions, - arg2?: CallOptions): {metadata: Metadata, options: CallOptions} { + arg1?: Metadata | CallOptions, + arg2?: CallOptions + ): { metadata: Metadata; options: CallOptions } { let metadata: Metadata; let options: CallOptions; if (arg1 instanceof Metadata) { @@ -258,31 +330,45 @@ export class Client { } metadata = new Metadata(); } - return {metadata, options}; + return { metadata, options }; } makeServerStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - metadata: Metadata, - options?: CallOptions): ClientReadableStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + metadata: Metadata, + options?: CallOptions + ): ClientReadableStream; makeServerStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - options?: CallOptions): ClientReadableStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + options?: CallOptions + ): ClientReadableStream; makeServerStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, argument: RequestType, - metadata?: Metadata|CallOptions, - options?: CallOptions): ClientReadableStream { - ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + argument: RequestType, + metadata?: Metadata | CallOptions, + options?: CallOptions + ): ClientReadableStream { + ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); const call: Call = this[CHANNEL_SYMBOL].createCall( - method, options.deadline, options.host, null, options.propagate_flags); + method, + options.deadline, + options.host, + null, + options.propagate_flags + ); if (options.credentials) { call.setCredentials(options.credentials); } const message: Buffer = serialize(argument); - const writeObj: WriteObject = {message}; + const writeObj: WriteObject = { message }; call.sendMetadata(metadata); call.write(writeObj); call.end(); @@ -290,26 +376,41 @@ export class Client { } makeBidiStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, metadata: Metadata, - options?: CallOptions): ClientDuplexStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + metadata: Metadata, + options?: CallOptions + ): ClientDuplexStream; makeBidiStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, - options?: CallOptions): ClientDuplexStream; + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + options?: CallOptions + ): ClientDuplexStream; makeBidiStreamRequest( - method: string, serialize: (value: RequestType) => Buffer, - deserialize: (value: Buffer) => ResponseType, - metadata?: Metadata|CallOptions, - options?: CallOptions): ClientDuplexStream { - ({metadata, options} = this.checkMetadataAndOptions(metadata, options)); + method: string, + serialize: (value: RequestType) => Buffer, + deserialize: (value: Buffer) => ResponseType, + metadata?: Metadata | CallOptions, + options?: CallOptions + ): ClientDuplexStream { + ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); const call: Call = this[CHANNEL_SYMBOL].createCall( - method, options.deadline, options.host, null, options.propagate_flags); + method, + options.deadline, + options.host, + null, + options.propagate_flags + ); if (options.credentials) { call.setCredentials(options.credentials); } call.sendMetadata(metadata); return new ClientDuplexStreamImpl( - call, serialize, deserialize); + call, + serialize, + deserialize + ); } } diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index cf695e5af..f28568e7c 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -17,10 +17,10 @@ import * as zlib from 'zlib'; -import {Call, WriteFlags, WriteObject} from './call-stream'; -import {Channel} from './channel'; -import {BaseFilter, Filter, FilterFactory} from './filter'; -import {Metadata, MetadataValue} from './metadata'; +import { Call, WriteFlags, WriteObject } from './call-stream'; +import { Channel } from './channel'; +import { BaseFilter, Filter, FilterFactory } from './filter'; +import { Metadata, MetadataValue } from './metadata'; abstract class CompressionHandler { protected abstract compressMessage(message: Buffer): Promise; @@ -71,8 +71,11 @@ class IdentityHandler extends CompressionHandler { } decompressMessage(message: Buffer): Promise { - return Promise.reject(new Error( - 'Received compressed message but "grpc-encoding" header was identity')); + return Promise.reject( + new Error( + 'Received compressed message but "grpc-encoding" header was identity' + ) + ); } } @@ -133,15 +136,20 @@ class UnknownHandler extends CompressionHandler { super(); } compressMessage(message: Buffer): Promise { - return Promise.reject(new Error( + return Promise.reject( + new Error( `Received message compressed wth unsupported compression method ${ - this.compressionName}`)); + this.compressionName + }` + ) + ); } decompressMessage(message: Buffer): Promise { // This should be unreachable return Promise.reject( - new Error(`Compression method not supported: ${this.compressionName}`)); + new Error(`Compression method not supported: ${this.compressionName}`) + ); } } @@ -187,13 +195,16 @@ export class CompressionFilter extends BaseFilter implements Filter { * and the output is a framed and possibly compressed message. For this * reason, this filter should be at the bottom of the filter stack */ const resolvedMessage: WriteObject = await message; - const compress = resolvedMessage.flags === undefined ? - false : - (resolvedMessage.flags & WriteFlags.NoCompress) === 0; + const compress = + resolvedMessage.flags === undefined + ? false + : (resolvedMessage.flags & WriteFlags.NoCompress) === 0; return { message: await this.sendCompression.writeMessage( - resolvedMessage.message, compress), - flags: resolvedMessage.flags + resolvedMessage.message, + compress + ), + flags: resolvedMessage.flags, }; } @@ -206,8 +217,8 @@ export class CompressionFilter extends BaseFilter implements Filter { } } -export class CompressionFilterFactory implements - FilterFactory { +export class CompressionFilterFactory + implements FilterFactory { constructor(private readonly channel: Channel) {} createFilter(callStream: Call): CompressionFilter { return new CompressionFilter(); diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index 92c0ebfa4..5f1992e36 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -32,11 +32,11 @@ export enum Status { INTERNAL, UNAVAILABLE, DATA_LOSS, - UNAUTHENTICATED + UNAUTHENTICATED, } export enum LogVerbosity { DEBUG = 0, INFO, - ERROR + ERROR, } diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 085623efb..fe0d16272 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -15,17 +15,21 @@ * */ -import {Call} from './call-stream'; -import {ConnectivityState, Http2Channel} from './channel'; -import {Status} from './constants'; -import {BaseFilter, Filter, FilterFactory} from './filter'; -import {Metadata} from './metadata'; +import { Call } from './call-stream'; +import { ConnectivityState, Http2Channel } from './channel'; +import { Status } from './constants'; +import { BaseFilter, Filter, FilterFactory } from './filter'; +import { Metadata } from './metadata'; -const units: Array<[string, number]> = - [['m', 1], ['S', 1000], ['M', 60 * 1000], ['H', 60 * 60 * 1000]]; +const units: Array<[string, number]> = [ + ['m', 1], + ['S', 1000], + ['M', 60 * 1000], + ['H', 60 * 60 * 1000], +]; function getDeadline(deadline: number) { - const now = (new Date()).getTime(); + const now = new Date().getTime(); const timeoutMs = Math.max(deadline - now, 0); for (const [unit, factor] of units) { const amount = timeoutMs / factor; @@ -37,11 +41,12 @@ function getDeadline(deadline: number) { } export class DeadlineFilter extends BaseFilter implements Filter { - private timer: NodeJS.Timer|null = null; + private timer: NodeJS.Timer | null = null; private deadline: number; constructor( - private readonly channel: Http2Channel, - private readonly callStream: Call) { + private readonly channel: Http2Channel, + private readonly callStream: Call + ) { super(); const callDeadline = callStream.getDeadline(); if (callDeadline instanceof Date) { @@ -49,7 +54,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { } else { this.deadline = callDeadline; } - const now: number = (new Date()).getTime(); + const now: number = new Date().getTime(); let timeout = this.deadline - now; if (timeout < 0) { timeout = 0; @@ -57,7 +62,9 @@ export class DeadlineFilter extends BaseFilter implements Filter { if (this.deadline !== Infinity) { this.timer = setTimeout(() => { callStream.cancelWithStatus( - Status.DEADLINE_EXCEEDED, 'Deadline exceeded'); + Status.DEADLINE_EXCEEDED, + 'Deadline exceeded' + ); }, timeout); callStream.on('status', () => clearTimeout(this.timer as NodeJS.Timer)); } @@ -68,32 +75,36 @@ export class DeadlineFilter extends BaseFilter implements Filter { return metadata; } return new Promise((resolve, reject) => { - if (this.channel.getConnectivityState(false) === - ConnectivityState.READY) { - resolve(metadata); - } else { - const handleStateChange = (newState: ConnectivityState) => { - if (newState === ConnectivityState.READY) { - resolve(metadata); - this.channel.removeListener( - 'connectivityStateChanged', handleStateChange); - this.callStream.removeListener('status', handleStatus); - } - }; - const handleStatus = () => { - reject(new Error('Call ended')); - this.channel.removeListener( - 'connectivityStateChanged', handleStateChange); - }; - this.channel.on('connectivityStateChanged', handleStateChange); - this.callStream.once('status', handleStatus); - } - }) - .then((finalMetadata: Metadata) => { - const timeoutString = getDeadline(this.deadline); - finalMetadata.set('grpc-timeout', timeoutString); - return finalMetadata; - }); + if ( + this.channel.getConnectivityState(false) === ConnectivityState.READY + ) { + resolve(metadata); + } else { + const handleStateChange = (newState: ConnectivityState) => { + if (newState === ConnectivityState.READY) { + resolve(metadata); + this.channel.removeListener( + 'connectivityStateChanged', + handleStateChange + ); + this.callStream.removeListener('status', handleStatus); + } + }; + const handleStatus = () => { + reject(new Error('Call ended')); + this.channel.removeListener( + 'connectivityStateChanged', + handleStateChange + ); + }; + this.channel.on('connectivityStateChanged', handleStateChange); + this.callStream.once('status', handleStatus); + } + }).then((finalMetadata: Metadata) => { + const timeoutString = getDeadline(this.deadline); + finalMetadata.set('grpc-timeout', timeoutString); + return finalMetadata; + }); } } diff --git a/packages/grpc-js/src/events.ts b/packages/grpc-js/src/events.ts index d534dee3f..7718746d5 100644 --- a/packages/grpc-js/src/events.ts +++ b/packages/grpc-js/src/events.ts @@ -15,7 +15,7 @@ * */ -export interface EmitterAugmentation1 { +export interface EmitterAugmentation1 { addListener(event: Name, listener: (arg1: Arg) => void): this; emit(event: Name, arg1: Arg): boolean; on(event: Name, listener: (arg1: Arg) => void): this; diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 8c0f1d7c5..a15dcf432 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -15,9 +15,9 @@ * */ -import {Call, StatusObject, WriteObject} from './call-stream'; -import {Filter, FilterFactory} from './filter'; -import {Metadata} from './metadata'; +import { Call, StatusObject, WriteObject } from './call-stream'; +import { Filter, FilterFactory } from './filter'; +import { Metadata } from './metadata'; export class FilterStack implements Filter { constructor(private readonly filters: Filter[]) {} @@ -78,6 +78,7 @@ export class FilterStackFactory implements FilterFactory { createFilter(callStream: Call): FilterStack { return new FilterStack( - this.factories.map((factory) => factory.createFilter(callStream))); + this.factories.map(factory => factory.createFilter(callStream)) + ); } } diff --git a/packages/grpc-js/src/filter.ts b/packages/grpc-js/src/filter.ts index f0bd99c61..9d437a674 100644 --- a/packages/grpc-js/src/filter.ts +++ b/packages/grpc-js/src/filter.ts @@ -15,8 +15,8 @@ * */ -import {Call, StatusObject, WriteObject} from './call-stream'; -import {Metadata} from './metadata'; +import { Call, StatusObject, WriteObject } from './call-stream'; +import { Metadata } from './metadata'; /** * Filter classes represent related per-call logic and state that is primarily diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 740cd6367..d54c0a675 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -17,18 +17,29 @@ import * as semver from 'semver'; -import {ClientDuplexStream, ClientReadableStream, ClientUnaryCall, ClientWritableStream, ServiceError} from './call'; -import {CallCredentials} from './call-credentials'; -import {Deadline, StatusObject} from './call-stream'; -import {Channel, ConnectivityState, Http2Channel} from './channel'; -import {ChannelCredentials} from './channel-credentials'; -import {CallOptions, Client} from './client'; -import {LogVerbosity, Status} from './constants'; +import { + ClientDuplexStream, + ClientReadableStream, + ClientUnaryCall, + ClientWritableStream, + ServiceError, +} from './call'; +import { CallCredentials } from './call-credentials'; +import { Deadline, StatusObject } from './call-stream'; +import { Channel, ConnectivityState, Http2Channel } from './channel'; +import { ChannelCredentials } from './channel-credentials'; +import { CallOptions, Client } from './client'; +import { LogVerbosity, Status } from './constants'; import * as logging from './logging'; -import {Deserialize, loadPackageDefinition, makeClientConstructor, Serialize} from './make-client'; -import {Metadata} from './metadata'; -import {KeyCertPair, ServerCredentials} from './server-credentials'; -import {StatusBuilder} from './status-builder'; +import { + Deserialize, + loadPackageDefinition, + makeClientConstructor, + Serialize, +} from './make-client'; +import { Metadata } from './metadata'; +import { KeyCertPair, ServerCredentials } from './server-credentials'; +import { StatusBuilder } from './status-builder'; const supportedNodeVersions = '^8.13.0 || >=10.10.0'; if (!semver.satisfies(process.version, supportedNodeVersions)) { @@ -36,15 +47,15 @@ if (!semver.satisfies(process.version, supportedNodeVersions)) { } interface IndexedObject { - [key: string]: any; // tslint:disable-line no-any - [key: number]: any; // tslint:disable-line no-any + [key: string]: any; // tslint:disable-line no-any + [key: number]: any; // tslint:disable-line no-any } function mixin(...sources: IndexedObject[]) { - const result: {[key: string]: Function} = {}; + const result: { [key: string]: Function } = {}; for (const source of sources) { for (const propName of Object.getOwnPropertyNames(source)) { - const property: any = source[propName]; // tslint:disable-line no-any + const property: any = source[propName]; // tslint:disable-line no-any if (typeof property === 'function') { result[propName] = property; } @@ -54,95 +65,113 @@ function mixin(...sources: IndexedObject[]) { } export interface OAuth2Client { - getRequestMetadata: (url: string, callback: (err: Error|null, headers?: { - Authorization: string - }) => void) => void; - getRequestHeaders: (url?: string) => Promise<{Authorization: string}>; + getRequestMetadata: ( + url: string, + callback: ( + err: Error | null, + headers?: { + Authorization: string; + } + ) => void + ) => void; + getRequestHeaders: (url?: string) => Promise<{ Authorization: string }>; } /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want export const credentials = mixin( - { - /** - * Create a gRPC credential from a Google credential object. - * @param googleCredentials The authentication client to use. - * @return The resulting CallCredentials object. - */ - createFromGoogleCredential: ( - googleCredentials: OAuth2Client): CallCredentials => { - return CallCredentials.createFromMetadataGenerator( - (options, callback) => { - // google-auth-library pre-v2.0.0 does not have getRequestHeaders - // but has getRequestMetadata, which is deprecated in v2.0.0 - let getHeaders: Promise<{Authorization: string}>; - if (typeof googleCredentials.getRequestHeaders === 'function') { - getHeaders = - googleCredentials.getRequestHeaders(options.service_url); - } else { - getHeaders = new Promise((resolve, reject) => { - googleCredentials.getRequestMetadata( - options.service_url, (err, headers) => { - if (err) { - reject(err); - return; - } - resolve(headers); - }); - }); - } - getHeaders.then( - headers => { - const metadata = new Metadata(); - metadata.add('authorization', headers.Authorization); - callback(null, metadata); - }, - err => { - callback(err); - }); + { + /** + * Create a gRPC credential from a Google credential object. + * @param googleCredentials The authentication client to use. + * @return The resulting CallCredentials object. + */ + createFromGoogleCredential: ( + googleCredentials: OAuth2Client + ): CallCredentials => { + return CallCredentials.createFromMetadataGenerator( + (options, callback) => { + // google-auth-library pre-v2.0.0 does not have getRequestHeaders + // but has getRequestMetadata, which is deprecated in v2.0.0 + let getHeaders: Promise<{ Authorization: string }>; + if (typeof googleCredentials.getRequestHeaders === 'function') { + getHeaders = googleCredentials.getRequestHeaders( + options.service_url + ); + } else { + getHeaders = new Promise((resolve, reject) => { + googleCredentials.getRequestMetadata( + options.service_url, + (err, headers) => { + if (err) { + reject(err); + return; + } + resolve(headers); + } + ); }); - }, - - /** - * Combine a ChannelCredentials with any number of CallCredentials into a - * single ChannelCredentials object. - * @param channelCredentials The ChannelCredentials object. - * @param callCredentials Any number of CallCredentials objects. - * @return The resulting ChannelCredentials object. - */ - combineChannelCredentials: - (channelCredentials: ChannelCredentials, - ...callCredentials: CallCredentials[]): ChannelCredentials => { - return callCredentials.reduce( - (acc, other) => acc.compose(other), channelCredentials); - }, - - /** - * Combine any number of CallCredentials into a single CallCredentials - * object. - * @param first The first CallCredentials object. - * @param additional Any number of additional CallCredentials objects. - * @return The resulting CallCredentials object. - */ - combineCallCredentials: ( - first: CallCredentials, ...additional: CallCredentials[]): - CallCredentials => { - return additional.reduce((acc, other) => acc.compose(other), first); } + getHeaders.then( + headers => { + const metadata = new Metadata(); + metadata.add('authorization', headers.Authorization); + callback(null, metadata); + }, + err => { + callback(err); + } + ); + } + ); }, - ChannelCredentials, CallCredentials); + + /** + * Combine a ChannelCredentials with any number of CallCredentials into a + * single ChannelCredentials object. + * @param channelCredentials The ChannelCredentials object. + * @param callCredentials Any number of CallCredentials objects. + * @return The resulting ChannelCredentials object. + */ + combineChannelCredentials: ( + channelCredentials: ChannelCredentials, + ...callCredentials: CallCredentials[] + ): ChannelCredentials => { + return callCredentials.reduce( + (acc, other) => acc.compose(other), + channelCredentials + ); + }, + + /** + * Combine any number of CallCredentials into a single CallCredentials + * object. + * @param first The first CallCredentials object. + * @param additional Any number of additional CallCredentials objects. + * @return The resulting CallCredentials object. + */ + combineCallCredentials: ( + first: CallCredentials, + ...additional: CallCredentials[] + ): CallCredentials => { + return additional.reduce((acc, other) => acc.compose(other), first); + }, + }, + ChannelCredentials, + CallCredentials +); /**** Metadata ****/ -export {Metadata}; +export { Metadata }; /**** Constants ****/ export { LogVerbosity as logVerbosity, Status as status, - ConnectivityState as connectivityState + ConnectivityState as connectivityState, // TODO: Other constants as well }; @@ -153,7 +182,7 @@ export { loadPackageDefinition, makeClientConstructor, makeClientConstructor as makeGenericClientConstructor, - Http2Channel as Channel + Http2Channel as Channel, }; /** @@ -162,10 +191,11 @@ export { */ export const closeClient = (client: Client) => client.close(); -export const waitForClientReady = - (client: Client, deadline: Date|number, - callback: (error?: Error) => void) => - client.waitForReady(deadline, callback); +export const waitForClientReady = ( + client: Client, + deadline: Date | number, + callback: (error?: Error) => void +) => client.waitForReady(deadline, callback); /* Interfaces */ @@ -181,12 +211,15 @@ export { ClientDuplexStream, CallOptions, StatusObject, - ServiceError + ServiceError, }; /* tslint:disable:no-any */ -export type Call = ClientUnaryCall|ClientReadableStream| - ClientWritableStream|ClientDuplexStream; +export type Call = + | ClientUnaryCall + | ClientReadableStream + | ClientWritableStream + | ClientDuplexStream; /* tslint:enable:no-any */ export type MetadataListener = (metadata: Metadata, next: Function) => void; @@ -208,12 +241,14 @@ export interface Listener { export const loadObject = (value: any, options: any) => { throw new Error( - 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); + 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead' + ); }; export const load = (filename: any, format: any, options: any) => { throw new Error( - 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead'); + 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead' + ); }; export const setLogger = (logger: Partial): void => { @@ -228,15 +263,14 @@ export const Server = (options: any) => { throw new Error('Not yet implemented'); }; -export {ServerCredentials}; -export {KeyCertPair}; - +export { ServerCredentials }; +export { KeyCertPair }; export const getClientChannel = (client: Client) => { return Client.prototype.getChannel.call(client); }; -export {StatusBuilder}; +export { StatusBuilder }; export const ListenerBuilder = () => { throw new Error('Not yet implemented'); @@ -250,4 +284,4 @@ export const InterceptingCall = () => { throw new Error('Not yet implemented'); }; -export {GrpcObject} from './make-client'; +export { GrpcObject } from './make-client'; diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 7579296b4..859b3ac51 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -15,7 +15,7 @@ * */ -import {LogVerbosity} from './constants'; +import { LogVerbosity } from './constants'; let _logger: Partial = console; let _logVerbosity: LogVerbosity = LogVerbosity.DEBUG; diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 46d83bce1..f30710e6f 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -15,9 +15,9 @@ * */ -import {ChannelCredentials} from './channel-credentials'; -import {ChannelOptions} from './channel-options'; -import {Client} from './client'; +import { ChannelCredentials } from './channel-credentials'; +import { ChannelOptions } from './channel-options'; +import { Client } from './client'; export interface Serialize { (value: T): Buffer; @@ -49,7 +49,7 @@ export interface ProtobufTypeDefinition { } export interface PackageDefinition { - [index: string]: ServiceDefinition|ProtobufTypeDefinition; + [index: string]: ServiceDefinition | ProtobufTypeDefinition; } /** @@ -61,7 +61,7 @@ const requesterFuncs = { unary: Client.prototype.makeUnaryRequest, server_stream: Client.prototype.makeServerStreamRequest, client_stream: Client.prototype.makeClientStreamRequest, - bidi: Client.prototype.makeBidiStreamRequest + bidi: Client.prototype.makeBidiStreamRequest, }; export interface ServiceClient extends Client { @@ -69,8 +69,11 @@ export interface ServiceClient extends Client { } export interface ServiceClientConstructor { - new(address: string, credentials: ChannelCredentials, - options?: Partial): ServiceClient; + new ( + address: string, + credentials: ChannelCredentials, + options?: Partial + ): ServiceClient; service: ServiceDefinition; } @@ -89,8 +92,10 @@ export interface ServiceClientConstructor { * {@link grpc.Client}, and has the same arguments as that constructor. */ export function makeClientConstructor( - methods: ServiceDefinition, serviceName: string, - classOptions?: {}): ServiceClientConstructor { + methods: ServiceDefinition, + serviceName: string, + classOptions?: {} +): ServiceClientConstructor { if (!classOptions) { classOptions = {}; } @@ -100,7 +105,7 @@ export function makeClientConstructor( [methodName: string]: Function; } - Object.keys(methods).forEach((name) => { + Object.keys(methods).forEach(name => { const attrs = methods[name]; let methodType: keyof typeof requesterFuncs; // TODO(murgatroid99): Verify that we don't need this anymore @@ -122,14 +127,18 @@ export function makeClientConstructor( } const serialize = attrs.requestSerialize; const deserialize = attrs.responseDeserialize; - const methodFunc = - partial(requesterFuncs[methodType], attrs.path, serialize, deserialize); + const methodFunc = partial( + requesterFuncs[methodType], + attrs.path, + serialize, + deserialize + ); ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method Object.assign(ServiceClientImpl.prototype[name], attrs); if (attrs.originalName) { ServiceClientImpl.prototype[attrs.originalName] = - ServiceClientImpl.prototype[name]; + ServiceClientImpl.prototype[name]; } }); @@ -139,21 +148,27 @@ export function makeClientConstructor( } function partial( - fn: Function, path: string, serialize: Function, - deserialize: Function): Function { + fn: Function, + path: string, + serialize: Function, + deserialize: Function +): Function { // tslint:disable-next-line:no-any return function(this: any, ...args: any[]) { return fn.call(this, path, serialize, deserialize, ...args); }; } -export type GrpcObject = { - [index: string]: GrpcObject|ServiceClientConstructor|ProtobufTypeDefinition; -}; +export interface GrpcObject { + [index: string]: + | GrpcObject + | ServiceClientConstructor + | ProtobufTypeDefinition; +} function isProtobufTypeDefinition( - obj: ServiceDefinition| - ProtobufTypeDefinition): obj is ProtobufTypeDefinition { + obj: ServiceDefinition | ProtobufTypeDefinition +): obj is ProtobufTypeDefinition { return 'format' in obj; } @@ -162,8 +177,9 @@ function isProtobufTypeDefinition( * @param packageDef The package definition object. * @return The resulting gRPC object. */ -export function loadPackageDefinition(packageDef: PackageDefinition): - GrpcObject { +export function loadPackageDefinition( + packageDef: PackageDefinition +): GrpcObject { const result: GrpcObject = {}; for (const serviceFqn in packageDef) { if (packageDef.hasOwnProperty(serviceFqn)) { diff --git a/packages/grpc-js/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts index 171bd6cbe..5ca401f73 100644 --- a/packages/grpc-js/src/metadata-status-filter.ts +++ b/packages/grpc-js/src/metadata-status-filter.ts @@ -15,19 +15,19 @@ * */ -import {Call} from './call-stream'; -import {StatusObject} from './call-stream'; -import {Channel} from './channel'; -import {Status} from './constants'; -import {BaseFilter, Filter, FilterFactory} from './filter'; +import { Call } from './call-stream'; +import { StatusObject } from './call-stream'; +import { Channel } from './channel'; +import { Status } from './constants'; +import { BaseFilter, Filter, FilterFactory } from './filter'; export class MetadataStatusFilter extends BaseFilter implements Filter { async receiveTrailers(status: Promise): Promise { // tslint:disable-next-line:prefer-const - let {code, details, metadata} = await status; + let { code, details, metadata } = await status; if (code !== Status.UNKNOWN) { // we already have a known status, so don't assign a new one. - return {code, details, metadata}; + return { code, details, metadata }; } const metadataMap = metadata.getMap(); if (typeof metadataMap['grpc-status'] === 'string') { @@ -41,12 +41,12 @@ export class MetadataStatusFilter extends BaseFilter implements Filter { details = decodeURI(metadataMap['grpc-message'] as string); metadata.remove('grpc-message'); } - return {code, details, metadata}; + return { code, details, metadata }; } } -export class MetadataStatusFilterFactory implements - FilterFactory { +export class MetadataStatusFilterFactory + implements FilterFactory { constructor(private readonly channel: Channel) {} createFilter(callStream: Call): MetadataStatusFilter { return new MetadataStatusFilter(); diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 4ca87c572..68b40bb36 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -19,7 +19,7 @@ import * as http2 from 'http2'; const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; -export type MetadataValue = string|Buffer; +export type MetadataValue = string | Buffer; export type MetadataObject = Map; function isLegalKey(key: string): boolean { @@ -45,17 +45,18 @@ function validate(key: string, value?: MetadataValue): void { if (value != null) { if (isBinaryKey(key)) { if (!(value instanceof Buffer)) { - throw new Error('keys that end with \'-bin\' must have Buffer values'); + throw new Error("keys that end with '-bin' must have Buffer values"); } } else { if (value instanceof Buffer) { throw new Error( - 'keys that don\'t end with \'-bin\' must have String values'); + "keys that don't end with '-bin' must have String values" + ); } if (!isLegalNonBinaryValue(value)) { throw new Error( - 'Metadata string value "' + value + - '" contains illegal characters'); + 'Metadata string value "' + value + '" contains illegal characters' + ); } } } @@ -91,7 +92,9 @@ export class Metadata { key = normalizeKey(key); validate(key, value); - const existingValue: MetadataValue[]|undefined = this.internalRepr.get(key); + const existingValue: MetadataValue[] | undefined = this.internalRepr.get( + key + ); if (existingValue === undefined) { this.internalRepr.set(key, [value]); @@ -126,8 +129,8 @@ export class Metadata { * This reflects the most common way that people will want to see metadata. * @return A key/value mapping of the metadata. */ - getMap(): {[key: string]: MetadataValue} { - const result: {[key: string]: MetadataValue} = {}; + getMap(): { [key: string]: MetadataValue } { + const result: { [key: string]: MetadataValue } = {}; this.internalRepr.forEach((values, key) => { if (values.length > 0) { @@ -170,8 +173,9 @@ export class Metadata { */ merge(other: Metadata): void { other.internalRepr.forEach((values, key) => { - const mergedValue: MetadataValue[] = - (this.internalRepr.get(key) || []).concat(values); + const mergedValue: MetadataValue[] = ( + this.internalRepr.get(key) || [] + ).concat(values); this.internalRepr.set(key, mergedValue); }); @@ -186,7 +190,7 @@ export class Metadata { this.internalRepr.forEach((values, key) => { // We assume that the user's interaction with this object is limited to // through its public API (i.e. keys and values are already validated). - result[key] = values.map((value) => { + result[key] = values.map(value => { if (value instanceof Buffer) { return value.toString('base64'); } else { @@ -209,7 +213,7 @@ export class Metadata { */ static fromHttp2Headers(headers: http2.IncomingHttpHeaders): Metadata { const result = new Metadata(); - Object.keys(headers).forEach((key) => { + Object.keys(headers).forEach(key => { // Reserved headers (beginning with `:`) are not valid keys. if (key.charAt(0) === ':') { return; @@ -219,7 +223,7 @@ export class Metadata { if (isBinaryKey(key)) { if (Array.isArray(values)) { - values.forEach((value) => { + values.forEach(value => { result.add(key, Buffer.from(value, 'base64')); }); } else if (values !== undefined) { @@ -229,7 +233,7 @@ export class Metadata { } } else { if (Array.isArray(values)) { - values.forEach((value) => { + values.forEach(value => { result.add(key, value); }); } else if (values !== undefined) { diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index 068f7a26e..624e547ca 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -15,29 +15,30 @@ * */ -import {Duplex, Readable, Writable} from 'stream'; -import {EmitterAugmentation1} from './events'; +import { Duplex, Readable, Writable } from 'stream'; +import { EmitterAugmentation1 } from './events'; // tslint:disable:no-any -export type WriteCallback = (error: Error|null|undefined) => void; +export type WriteCallback = (error: Error | null | undefined) => void; export interface IntermediateObjectReadable extends Readable { - read(size?: number): any&T; + read(size?: number): any & T; } export type ObjectReadable = { read(size?: number): T; -}&EmitterAugmentation1<'data', T>&IntermediateObjectReadable; +} & EmitterAugmentation1<'data', T> & + IntermediateObjectReadable; export interface IntermediateObjectWritable extends Writable { - _write(chunk: any&T, encoding: string, callback: Function): void; - write(chunk: any&T, cb?: WriteCallback): boolean; - write(chunk: any&T, encoding?: any, cb?: WriteCallback): boolean; + _write(chunk: any & T, encoding: string, callback: Function): void; + write(chunk: any & T, cb?: WriteCallback): boolean; + write(chunk: any & T, encoding?: any, cb?: WriteCallback): boolean; setDefaultEncoding(encoding: string): this; end(): void; - end(chunk: any&T, cb?: Function): void; - end(chunk: any&T, encoding?: any, cb?: Function): void; + end(chunk: any & T, cb?: Function): void; + end(chunk: any & T, encoding?: any, cb?: Function): void; } export interface ObjectWritable extends IntermediateObjectWritable { @@ -59,4 +60,6 @@ export type ObjectDuplex = { end(): void; end(chunk: T, cb?: Function): void; end(chunk: T, encoding?: any, cb?: Function): void; -}&Duplex&ObjectWritable&ObjectReadable; +} & Duplex & + ObjectWritable & + ObjectReadable; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 197ace5c5..6c3f73756 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -15,20 +15,20 @@ * */ -import {EventEmitter} from 'events'; +import { EventEmitter } from 'events'; import * as http2 from 'http2'; -import {Duplex, Readable, Writable} from 'stream'; +import { Duplex, Readable, Writable } from 'stream'; -import {ServiceError} from './call'; -import {StatusObject} from './call-stream'; -import {Status} from './constants'; -import {Deserialize, Serialize} from './make-client'; -import {Metadata} from './metadata'; -import {StreamDecoder} from './stream-decoder'; +import { ServiceError } from './call'; +import { StatusObject } from './call-stream'; +import { Status } from './constants'; +import { Deserialize, Serialize } from './make-client'; +import { Metadata } from './metadata'; +import { StreamDecoder } from './stream-decoder'; -type DeadlineUnitIndexSignature = { - [name: string]: number -}; +interface DeadlineUnitIndexSignature { + [name: string]: number; +} const GRPC_ACCEPT_ENCODING_HEADER = 'grpc-accept-encoding'; const GRPC_ENCODING_HEADER = 'grpc-encoding'; @@ -42,7 +42,7 @@ const deadlineUnitsToMs: DeadlineUnitIndexSignature = { S: 1000, m: 1, u: 0.001, - n: 0.000001 + n: 0.000001, }; const defaultResponseHeaders = { // TODO(cjihrig): Remove these encoding headers from the default response @@ -50,35 +50,41 @@ const defaultResponseHeaders = { [GRPC_ACCEPT_ENCODING_HEADER]: 'identity', [GRPC_ENCODING_HEADER]: 'identity', [http2.constants.HTTP2_HEADER_STATUS]: http2.constants.HTTP_STATUS_OK, - [http2.constants.HTTP2_HEADER_CONTENT_TYPE]: 'application/grpc+proto' + [http2.constants.HTTP2_HEADER_CONTENT_TYPE]: 'application/grpc+proto', }; const defaultResponseOptions = { - waitForTrailers: true + waitForTrailers: true, } as http2.ServerStreamResponseOptions; +export interface ServerSurfaceCall { + cancelled: boolean; + getPeer(): string; + sendMetadata(responseMetadata: Metadata): void; +} -export type ServerSurfaceCall = { - cancelled: boolean; getPeer(): string; - sendMetadata(responseMetadata: Metadata): void +export type ServerUnaryCall = ServerSurfaceCall & { + request: RequestType | null; }; - -export type ServerUnaryCall = - ServerSurfaceCall&{request: RequestType | null}; -export type ServerReadableStream = - ServerSurfaceCall&Readable; -export type ServerWritableStream = - ServerSurfaceCall&Writable&{request: RequestType | null}; -export type ServerDuplexStream = - ServerSurfaceCall&Duplex; +export type ServerReadableStream< + RequestType, + ResponseType +> = ServerSurfaceCall & Readable; +export type ServerWritableStream< + RequestType, + ResponseType +> = ServerSurfaceCall & Writable & { request: RequestType | null }; +export type ServerDuplexStream = ServerSurfaceCall & + Duplex; export class ServerUnaryCallImpl extends EventEmitter - implements ServerUnaryCall { + implements ServerUnaryCall { cancelled: boolean; - request: RequestType|null; + request: RequestType | null; constructor( - private call: Http2ServerCallStream, - public metadata: Metadata) { + private call: Http2ServerCallStream, + public metadata: Metadata + ) { super(); this.cancelled = false; this.request = null; @@ -93,15 +99,17 @@ export class ServerUnaryCallImpl extends EventEmitter } } - -export class ServerReadableStreamImpl extends - Readable implements ServerReadableStream { +export class ServerReadableStreamImpl + extends Readable + implements ServerReadableStream { cancelled: boolean; constructor( - private call: Http2ServerCallStream, - public metadata: Metadata, public deserialize: Deserialize) { - super({objectMode: true}); + private call: Http2ServerCallStream, + public metadata: Metadata, + public deserialize: Deserialize + ) { + super({ objectMode: true }); this.cancelled = false; this.call.setupReadable(this); } @@ -119,22 +127,24 @@ export class ServerReadableStreamImpl extends } } - -export class ServerWritableStreamImpl extends - Writable implements ServerWritableStream { +export class ServerWritableStreamImpl + extends Writable + implements ServerWritableStream { cancelled: boolean; - request: RequestType|null; + request: RequestType | null; private trailingMetadata: Metadata; constructor( - private call: Http2ServerCallStream, - public metadata: Metadata, public serialize: Serialize) { - super({objectMode: true}); + private call: Http2ServerCallStream, + public metadata: Metadata, + public serialize: Serialize + ) { + super({ objectMode: true }); this.cancelled = false; this.request = null; this.trailingMetadata = new Metadata(); - this.on('error', (err) => { + this.on('error', err => { this.call.sendError(err as ServiceError); this.end(); }); @@ -149,9 +159,11 @@ export class ServerWritableStreamImpl extends } async _write( - chunk: ResponseType, encoding: string, - // tslint:disable-next-line:no-any - callback: (...args: any[]) => void) { + chunk: ResponseType, + encoding: string, + // tslint:disable-next-line:no-any + callback: (...args: any[]) => void + ) { try { const response = await this.call.serializeMessage(chunk); @@ -168,8 +180,11 @@ export class ServerWritableStreamImpl extends } _final(callback: Function): void { - this.call.sendStatus( - {code: Status.OK, details: 'OK', metadata: this.trailingMetadata}); + this.call.sendStatus({ + code: Status.OK, + details: 'OK', + metadata: this.trailingMetadata, + }); callback(null); } @@ -183,22 +198,23 @@ export class ServerWritableStreamImpl extends } } - export class ServerDuplexStreamImpl extends Duplex - implements ServerDuplexStream { + implements ServerDuplexStream { cancelled: boolean; private trailingMetadata: Metadata; constructor( - private call: Http2ServerCallStream, - public metadata: Metadata, public serialize: Serialize, - public deserialize: Deserialize) { - super({objectMode: true}); + private call: Http2ServerCallStream, + public metadata: Metadata, + public serialize: Serialize, + public deserialize: Deserialize + ) { + super({ objectMode: true }); this.cancelled = false; this.trailingMetadata = new Metadata(); this.call.setupReadable(this); - this.on('error', (err) => { + this.on('error', err => { this.call.sendError(err as ServiceError); this.end(); }); @@ -214,92 +230,101 @@ export class ServerDuplexStreamImpl extends Duplex } ServerDuplexStreamImpl.prototype._read = - ServerReadableStreamImpl.prototype._read; + ServerReadableStreamImpl.prototype._read; ServerDuplexStreamImpl.prototype._write = - ServerWritableStreamImpl.prototype._write; + ServerWritableStreamImpl.prototype._write; ServerDuplexStreamImpl.prototype._final = - ServerWritableStreamImpl.prototype._final; + ServerWritableStreamImpl.prototype._final; ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; - // Unary response callback signature. -export type sendUnaryData = - (error: ServiceError|null, value: ResponseType|null, trailer?: Metadata, - flags?: number) => void; +export type sendUnaryData = ( + error: ServiceError | null, + value: ResponseType | null, + trailer?: Metadata, + flags?: number +) => void; // User provided handler for unary calls. -export type handleUnaryCall = - (call: ServerUnaryCall, - callback: sendUnaryData) => void; +export type handleUnaryCall = ( + call: ServerUnaryCall, + callback: sendUnaryData +) => void; // User provided handler for client streaming calls. -export type handleClientStreamingCall = - (call: ServerReadableStream, - callback: sendUnaryData) => void; +export type handleClientStreamingCall = ( + call: ServerReadableStream, + callback: sendUnaryData +) => void; // User provided handler for server streaming calls. -export type handleServerStreamingCall = - (call: ServerWritableStream) => void; +export type handleServerStreamingCall = ( + call: ServerWritableStream +) => void; // User provided handler for bidirectional streaming calls. -export type handleBidiStreamingCall = - (call: ServerDuplexStream) => void; +export type handleBidiStreamingCall = ( + call: ServerDuplexStream +) => void; export type HandleCall = - handleUnaryCall| - handleClientStreamingCall| - handleServerStreamingCall| - handleBidiStreamingCall; + | handleUnaryCall + | handleClientStreamingCall + | handleServerStreamingCall + | handleBidiStreamingCall; -export type UnaryHandler = { +export interface UnaryHandler { func: handleUnaryCall; serialize: Serialize; deserialize: Deserialize; type: HandlerType; -}; +} -export type ClientStreamingHandler = { +export interface ClientStreamingHandler { func: handleClientStreamingCall; serialize: Serialize; deserialize: Deserialize; type: HandlerType; -}; +} -export type ServerStreamingHandler = { +export interface ServerStreamingHandler { func: handleServerStreamingCall; serialize: Serialize; deserialize: Deserialize; type: HandlerType; -}; +} -export type BidiStreamingHandler = { +export interface BidiStreamingHandler { func: handleBidiStreamingCall; serialize: Serialize; deserialize: Deserialize; type: HandlerType; -}; +} export type Handler = - UnaryHandler| - ClientStreamingHandler| - ServerStreamingHandler| - BidiStreamingHandler; + | UnaryHandler + | ClientStreamingHandler + | ServerStreamingHandler + | BidiStreamingHandler; -export type HandlerType = 'bidi'|'clientStream'|'serverStream'|'unary'; +export type HandlerType = 'bidi' | 'clientStream' | 'serverStream' | 'unary'; const noopTimer: NodeJS.Timer = setTimeout(() => {}, 0); // Internal class that wraps the HTTP2 request. -export class Http2ServerCallStream extends - EventEmitter { +export class Http2ServerCallStream< + RequestType, + ResponseType +> extends EventEmitter { cancelled = false; deadline: NodeJS.Timer = noopTimer; private wantTrailers = false; private metadataSent = false; constructor( - private stream: http2.ServerHttp2Stream, - private handler: Handler) { + private stream: http2.ServerHttp2Stream, + private handler: Handler + ) { super(); this.stream.once('error', (err: ServiceError) => { @@ -402,8 +427,11 @@ export class Http2ServerCallStream extends } async sendUnaryMessage( - err: ServiceError|null, value: ResponseType|null, metadata?: Metadata, - flags?: number) { + err: ServiceError | null, + value: ResponseType | null, + metadata?: Metadata, + flags?: number + ) { if (!metadata) { metadata = new Metadata(); } @@ -418,7 +446,7 @@ export class Http2ServerCallStream extends const response = await this.serializeMessage(value!); this.write(response); - this.sendStatus({code: Status.OK, details: 'OK', metadata}); + this.sendStatus({ code: Status.OK, details: 'OK', metadata }); } catch (err) { err.code = Status.INTERNAL; this.sendError(err); @@ -436,11 +464,12 @@ export class Http2ServerCallStream extends this.wantTrailers = true; this.stream.once('wantTrailers', () => { const trailersToSend = Object.assign( - { - [GRPC_STATUS_HEADER]: statusObj.code, - [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string) - }, - statusObj.metadata.toHttp2Headers()); + { + [GRPC_STATUS_HEADER]: statusObj.code, + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), + }, + statusObj.metadata.toHttp2Headers() + ); this.stream.sendTrailers(trailersToSend); }); @@ -452,10 +481,12 @@ export class Http2ServerCallStream extends sendError(error: ServiceError) { const status: StatusObject = { code: Status.UNKNOWN, - details: error.hasOwnProperty('message') ? error.message : - 'Unknown Error', - metadata: error.hasOwnProperty('metadata') ? error.metadata : - new Metadata() + details: error.hasOwnProperty('message') + ? error.message + : 'Unknown Error', + metadata: error.hasOwnProperty('metadata') + ? error.metadata + : new Metadata(), }; if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { @@ -482,8 +513,11 @@ export class Http2ServerCallStream extends this.stream.resume(); } - setupReadable(readable: ServerReadableStream| - ServerDuplexStream) { + setupReadable( + readable: + | ServerReadableStream + | ServerDuplexStream + ) { const decoder = new StreamDecoder(); this.stream.on('data', async (data: Buffer) => { diff --git a/packages/grpc-js/src/server-credentials.ts b/packages/grpc-js/src/server-credentials.ts index 9e5dc782d..1fe5f55d5 100644 --- a/packages/grpc-js/src/server-credentials.ts +++ b/packages/grpc-js/src/server-credentials.ts @@ -15,26 +15,26 @@ * */ -import {SecureServerOptions} from 'http2'; - - -export type KeyCertPair = { - private_key: Buffer, - cert_chain: Buffer -}; +import { SecureServerOptions } from 'http2'; +export interface KeyCertPair { + private_key: Buffer; + cert_chain: Buffer; +} export abstract class ServerCredentials { abstract _isSecure(): boolean; - abstract _getSettings(): SecureServerOptions|null; + abstract _getSettings(): SecureServerOptions | null; static createInsecure(): ServerCredentials { return new InsecureServerCredentials(); } static createSsl( - rootCerts: Buffer|null, keyCertPairs: KeyCertPair[], - checkClientCertificate = false): ServerCredentials { + rootCerts: Buffer | null, + keyCertPairs: KeyCertPair[], + checkClientCertificate = false + ): ServerCredentials { if (rootCerts !== null && !Buffer.isBuffer(rootCerts)) { throw new TypeError('rootCerts must be null or a Buffer'); } @@ -73,12 +73,11 @@ export abstract class ServerCredentials { ca: rootCerts || undefined, cert, key, - requestCert: checkClientCertificate + requestCert: checkClientCertificate, }); } } - class InsecureServerCredentials extends ServerCredentials { _isSecure(): boolean { return false; @@ -89,7 +88,6 @@ class InsecureServerCredentials extends ServerCredentials { } } - class SecureServerCredentials extends ServerCredentials { private options: SecureServerOptions; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8d4915eb5..7dd07078a 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -16,22 +16,40 @@ */ import * as http2 from 'http2'; -import {AddressInfo, ListenOptions} from 'net'; -import {URL} from 'url'; - -import {ServiceError} from './call'; -import {Status} from './constants'; -import {Deserialize, Serialize, ServiceDefinition} from './make-client'; -import {Metadata} from './metadata'; -import {BidiStreamingHandler, ClientStreamingHandler, HandleCall, Handler, HandlerType, Http2ServerCallStream, sendUnaryData, ServerDuplexStream, ServerDuplexStreamImpl, ServerReadableStream, ServerReadableStreamImpl, ServerStreamingHandler, ServerUnaryCall, ServerUnaryCallImpl, ServerWritableStream, ServerWritableStreamImpl, UnaryHandler} from './server-call'; -import {ServerCredentials} from './server-credentials'; +import { AddressInfo, ListenOptions } from 'net'; +import { URL } from 'url'; + +import { ServiceError } from './call'; +import { Status } from './constants'; +import { Deserialize, Serialize, ServiceDefinition } from './make-client'; +import { Metadata } from './metadata'; +import { + BidiStreamingHandler, + ClientStreamingHandler, + HandleCall, + Handler, + HandlerType, + Http2ServerCallStream, + sendUnaryData, + ServerDuplexStream, + ServerDuplexStreamImpl, + ServerReadableStream, + ServerReadableStreamImpl, + ServerStreamingHandler, + ServerUnaryCall, + ServerUnaryCallImpl, + ServerWritableStream, + ServerWritableStreamImpl, + UnaryHandler, +} from './server-call'; +import { ServerCredentials } from './server-credentials'; function noop(): void {} const unimplementedStatusResponse: Partial = { code: Status.UNIMPLEMENTED, details: 'The server does not implement this method', - metadata: new Metadata() + metadata: new Metadata(), }; // tslint:disable:no-any @@ -41,32 +59,38 @@ type UntypedServerStreamingHandler = ServerStreamingHandler; type UntypedBidiStreamingHandler = BidiStreamingHandler; type UntypedHandleCall = HandleCall; type UntypedHandler = Handler; -type UntypedServiceImplementation = { - [name: string]: UntypedHandleCall -}; +interface UntypedServiceImplementation { + [name: string]: UntypedHandleCall; +} const defaultHandler = { unary(call: ServerUnaryCall, callback: sendUnaryData): void { callback(unimplementedStatusResponse as ServiceError, null); }, clientStream( - call: ServerReadableStream, callback: sendUnaryData): - void { - callback(unimplementedStatusResponse as ServiceError, null); - }, + call: ServerReadableStream, + callback: sendUnaryData + ): void { + callback(unimplementedStatusResponse as ServiceError, null); + }, serverStream(call: ServerWritableStream): void { call.emit('error', unimplementedStatusResponse); }, bidi(call: ServerDuplexStream): void { call.emit('error', unimplementedStatusResponse); - } + }, }; // tslint:enable:no-any export class Server { - private http2Server: http2.Http2Server|http2.Http2SecureServer|null = null; - private handlers: Map = - new Map(); + private http2Server: + | http2.Http2Server + | http2.Http2SecureServer + | null = null; + private handlers: Map = new Map< + string, + UntypedHandler + >(); private started = false; constructor(options?: object) {} @@ -77,11 +101,15 @@ export class Server { addService(service: ServiceDefinition, implementation: object): void { if (this.started === true) { - throw new Error('Can\'t add a service to a started server.'); + throw new Error("Can't add a service to a started server."); } - if (service === null || typeof service !== 'object' || - implementation === null || typeof implementation !== 'object') { + if ( + service === null || + typeof service !== 'object' || + implementation === null || + typeof implementation !== 'object' + ) { throw new Error('addService() requires two objects as arguments'); } @@ -91,10 +119,9 @@ export class Server { throw new Error('Cannot add an empty service to a server'); } - const implMap: UntypedServiceImplementation = - implementation as UntypedServiceImplementation; + const implMap: UntypedServiceImplementation = implementation as UntypedServiceImplementation; - serviceKeys.forEach((name) => { + serviceKeys.forEach(name => { const attrs = service[name]; let methodType: HandlerType; @@ -126,8 +153,12 @@ export class Server { } const success = this.register( - attrs.path, impl as UntypedHandleCall, attrs.responseSerialize, - attrs.requestDeserialize, methodType); + attrs.path, + impl as UntypedHandleCall, + attrs.responseSerialize, + attrs.requestDeserialize, + methodType + ); if (success === false) { throw new Error(`Method handler for ${attrs.path} already provided.`); @@ -140,8 +171,10 @@ export class Server { } bindAsync( - port: string, creds: ServerCredentials, - callback: (error: Error|null, port: number) => void): void { + port: string, + creds: ServerCredentials, + callback: (error: Error | null, port: number) => void + ): void { if (this.started === true) { throw new Error('server is already started'); } @@ -159,11 +192,12 @@ export class Server { } const url = new URL(`http://${port}`); - const options: ListenOptions = {host: url.hostname, port: +url.port}; + const options: ListenOptions = { host: url.hostname, port: +url.port }; if (creds._isSecure()) { this.http2Server = http2.createSecureServer( - creds._getSettings() as http2.SecureServerOptions); + creds._getSettings() as http2.SecureServerOptions + ); } else { this.http2Server = http2.createServer(); } @@ -177,8 +211,9 @@ export class Server { this.http2Server.once('error', onError); this.http2Server.listen(options, () => { - const server = - this.http2Server as http2.Http2Server | http2.Http2SecureServer; + const server = this.http2Server as + | http2.Http2Server + | http2.Http2SecureServer; const port = (server.address() as AddressInfo).port; server.removeListener('error', onError); @@ -191,15 +226,22 @@ export class Server { } register( - name: string, handler: HandleCall, - serialize: Serialize, deserialize: Deserialize, - type: string): boolean { + name: string, + handler: HandleCall, + serialize: Serialize, + deserialize: Deserialize, + type: string + ): boolean { if (this.handlers.has(name)) { return false; } - this.handlers.set( - name, {func: handler, serialize, deserialize, type} as UntypedHandler); + this.handlers.set(name, { + func: handler, + serialize, + deserialize, + type, + } as UntypedHandler); return true; } @@ -239,61 +281,71 @@ export class Server { } this.http2Server.on( - 'stream', - (stream: http2.ServerHttp2Stream, - headers: http2.IncomingHttpHeaders) => { - if (!this.started) { - stream.end(); - return; + 'stream', + (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { + if (!this.started) { + stream.end(); + return; + } + + try { + const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; + const handler = this.handlers.get(path); + + if (handler === undefined) { + throw unimplementedStatusResponse; } - try { - const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; - const handler = this.handlers.get(path); - - if (handler === undefined) { - throw unimplementedStatusResponse; - } - - const call = new Http2ServerCallStream(stream, handler); - const metadata: Metadata = - call.receiveMetadata(headers) as Metadata; - - switch (handler.type) { - case 'unary': - handleUnary(call, handler as UntypedUnaryHandler, metadata); - break; - case 'clientStream': - handleClientStreaming( - call, handler as UntypedClientStreamingHandler, metadata); - break; - case 'serverStream': - handleServerStreaming( - call, handler as UntypedServerStreamingHandler, metadata); - break; - case 'bidi': - handleBidiStreaming( - call, handler as UntypedBidiStreamingHandler, metadata); - break; - default: - throw new Error(`Unknown handler type: ${handler.type}`); - } - } catch (err) { - const call = new Http2ServerCallStream(stream, null!); - err.code = Status.INTERNAL; - call.sendError(err); + const call = new Http2ServerCallStream(stream, handler); + const metadata: Metadata = call.receiveMetadata(headers) as Metadata; + + switch (handler.type) { + case 'unary': + handleUnary(call, handler as UntypedUnaryHandler, metadata); + break; + case 'clientStream': + handleClientStreaming( + call, + handler as UntypedClientStreamingHandler, + metadata + ); + break; + case 'serverStream': + handleServerStreaming( + call, + handler as UntypedServerStreamingHandler, + metadata + ); + break; + case 'bidi': + handleBidiStreaming( + call, + handler as UntypedBidiStreamingHandler, + metadata + ); + break; + default: + throw new Error(`Unknown handler type: ${handler.type}`); } - }); + } catch (err) { + const call = new Http2ServerCallStream(stream, null!); + err.code = Status.INTERNAL; + call.sendError(err); + } + } + ); } } - async function handleUnary( - call: Http2ServerCallStream, - handler: UnaryHandler, - metadata: Metadata): Promise { - const emitter = - new ServerUnaryCallImpl(call, metadata); + call: Http2ServerCallStream, + handler: UnaryHandler, + metadata: Metadata +): Promise { + const emitter = new ServerUnaryCallImpl( + call, + metadata + ); const request = await call.receiveUnaryMessage(); if (request === undefined || call.cancelled) { @@ -302,24 +354,35 @@ async function handleUnary( emitter.request = request; handler.func( - emitter, - (err: ServiceError|null, value: ResponseType|null, trailer?: Metadata, - flags?: number) => { - call.sendUnaryMessage(err, value, trailer, flags); - }); + emitter, + ( + err: ServiceError | null, + value: ResponseType | null, + trailer?: Metadata, + flags?: number + ) => { + call.sendUnaryMessage(err, value, trailer, flags); + } + ); } - function handleClientStreaming( - call: Http2ServerCallStream, - handler: ClientStreamingHandler, - metadata: Metadata): void { + call: Http2ServerCallStream, + handler: ClientStreamingHandler, + metadata: Metadata +): void { const stream = new ServerReadableStreamImpl( - call, metadata, handler.deserialize); + call, + metadata, + handler.deserialize + ); function respond( - err: ServiceError|null, value: ResponseType|null, trailer?: Metadata, - flags?: number) { + err: ServiceError | null, + value: ResponseType | null, + trailer?: Metadata, + flags?: number + ) { stream.destroy(); call.sendUnaryMessage(err, value, trailer, flags); } @@ -332,11 +395,11 @@ function handleClientStreaming( handler.func(stream, respond); } - async function handleServerStreaming( - call: Http2ServerCallStream, - handler: ServerStreamingHandler, - metadata: Metadata): Promise { + call: Http2ServerCallStream, + handler: ServerStreamingHandler, + metadata: Metadata +): Promise { const request = await call.receiveUnaryMessage(); if (request === undefined || call.cancelled) { @@ -344,19 +407,26 @@ async function handleServerStreaming( } const stream = new ServerWritableStreamImpl( - call, metadata, handler.serialize); + call, + metadata, + handler.serialize + ); stream.request = request; handler.func(stream); } - function handleBidiStreaming( - call: Http2ServerCallStream, - handler: BidiStreamingHandler, - metadata: Metadata): void { + call: Http2ServerCallStream, + handler: BidiStreamingHandler, + metadata: Metadata +): void { const stream = new ServerDuplexStreamImpl( - call, metadata, handler.serialize, handler.deserialize); + call, + metadata, + handler.serialize, + handler.deserialize + ); if (call.cancelled) { return; diff --git a/packages/grpc-js/src/status-builder.ts b/packages/grpc-js/src/status-builder.ts index 4cbf24b99..1109af1ac 100644 --- a/packages/grpc-js/src/status-builder.ts +++ b/packages/grpc-js/src/status-builder.ts @@ -15,17 +15,17 @@ * */ -import {StatusObject} from './call-stream'; -import {Status} from './constants'; -import {Metadata} from './metadata'; +import { StatusObject } from './call-stream'; +import { Status } from './constants'; +import { Metadata } from './metadata'; /** * A builder for gRPC status objects. */ export class StatusBuilder { - private code: Status|null; - private details: string|null; - private metadata: Metadata|null; + private code: Status | null; + private details: string | null; + private metadata: Metadata | null; constructor() { this.code = null; diff --git a/packages/grpc-js/src/stream-decoder.ts b/packages/grpc-js/src/stream-decoder.ts index 3a8e91aec..24881ba0b 100644 --- a/packages/grpc-js/src/stream-decoder.ts +++ b/packages/grpc-js/src/stream-decoder.ts @@ -18,10 +18,9 @@ enum ReadState { NO_DATA, READING_SIZE, - READING_MESSAGE + READING_MESSAGE, } - export class StreamDecoder { private readState: ReadState = ReadState.NO_DATA; private readCompressFlag: Buffer = Buffer.alloc(1); @@ -31,8 +30,7 @@ export class StreamDecoder { private readPartialMessage: Buffer[] = []; private readMessageRemaining = 0; - - write(data: Buffer): Buffer|null { + write(data: Buffer): Buffer | null { let readHead = 0; let toRead: number; @@ -51,8 +49,11 @@ export class StreamDecoder { case ReadState.READING_SIZE: toRead = Math.min(data.length - readHead, this.readSizeRemaining); data.copy( - this.readPartialSize, 4 - this.readSizeRemaining, readHead, - readHead + toRead); + this.readPartialSize, + 4 - this.readSizeRemaining, + readHead, + readHead + toRead + ); this.readSizeRemaining -= toRead; readHead += toRead; // readSizeRemaining >=0 here @@ -63,7 +64,9 @@ export class StreamDecoder { this.readState = ReadState.READING_MESSAGE; } else { const message = Buffer.concat( - [this.readCompressFlag, this.readPartialSize], 5); + [this.readCompressFlag, this.readPartialSize], + 5 + ); this.readState = ReadState.NO_DATA; return message; @@ -79,10 +82,13 @@ export class StreamDecoder { if (this.readMessageRemaining === 0) { // At this point, we have read a full message const framedMessageBuffers = [ - this.readCompressFlag, this.readPartialSize + this.readCompressFlag, + this.readPartialSize, ].concat(this.readPartialMessage); - const framedMessage = - Buffer.concat(framedMessageBuffers, this.readMessageSize + 5); + const framedMessage = Buffer.concat( + framedMessageBuffers, + this.readMessageSize + 5 + ); this.readState = ReadState.NO_DATA; return framedMessage; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index f2e11f7f6..80abf7812 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -15,13 +15,13 @@ * */ -import {EventEmitter} from 'events'; +import { EventEmitter } from 'events'; import * as http2 from 'http2'; import * as url from 'url'; -import {Call, Http2CallStream} from './call-stream'; -import {ChannelOptions} from './channel-options'; -import {Metadata} from './metadata'; +import { Call, Http2CallStream } from './call-stream'; +import { ChannelOptions } from './channel-options'; +import { Metadata } from './metadata'; const { HTTP2_HEADER_AUTHORITY, @@ -29,7 +29,7 @@ const { HTTP2_HEADER_METHOD, HTTP2_HEADER_PATH, HTTP2_HEADER_TE, - HTTP2_HEADER_USER_AGENT + HTTP2_HEADER_USER_AGENT, } = http2.constants; /* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't @@ -59,8 +59,11 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { private keepaliveTimeoutId: NodeJS.Timer; constructor( - target: url.URL, connectionOptions: http2.SecureClientSessionOptions, - userAgent: string, channelArgs: Partial) { + target: url.URL, + connectionOptions: http2.SecureClientSessionOptions, + userAgent: string, + channelArgs: Partial + ) { super(); this.session = http2.connect(target, connectionOptions); this.session.unref(); @@ -109,9 +112,11 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { this.keepaliveTimeoutId = setTimeout(() => { this.emit('close'); }, this.keepaliveTimeoutMs); - this.session.ping((err: Error|null, duration: number, payload: Buffer) => { - clearTimeout(this.keepaliveTimeoutId); - }); + this.session.ping( + (err: Error | null, duration: number, payload: Buffer) => { + clearTimeout(this.keepaliveTimeoutId); + } + ); } /* TODO(murgatroid99): refactor subchannels so that keepalives can be handled diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index 179765960..19d8d2753 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -18,14 +18,14 @@ import * as loader from '@grpc/proto-loader'; import * as assert from 'assert'; -import {GrpcObject, loadPackageDefinition} from '../src/make-client'; +import { GrpcObject, loadPackageDefinition } from '../src/make-client'; const protoLoaderOptions = { keepCase: true, longs: String, enums: String, defaults: true, - oneofs: true + oneofs: true, }; export function mockFunction(): never { @@ -49,7 +49,7 @@ export namespace assert2 { assert.throws(() => { throw e; }); - throw e; // for type safety only + throw e; // for type safety only } } @@ -59,7 +59,7 @@ export namespace assert2 { */ function mustCallsSatisfied(): boolean { let result = true; - toCall.forEach((value) => { + toCall.forEach(value => { result = result && value === 0; }); return result; @@ -74,8 +74,9 @@ export namespace assert2 { * @param fn The function to wrap. */ // tslint:disable:no-any - export function mustCall(fn: (...args: any[]) => T): - (...args: any[]) => T { + export function mustCall( + fn: (...args: any[]) => T + ): (...args: any[]) => T { const existingValue = toCall.get(fn); if (existingValue !== undefined) { toCall.set(fn, existingValue + 1); diff --git a/packages/grpc-js/test/test-call-credentials.ts b/packages/grpc-js/test/test-call-credentials.ts index e5b1b81a0..e952c5a10 100644 --- a/packages/grpc-js/test/test-call-credentials.ts +++ b/packages/grpc-js/test/test-call-credentials.ts @@ -17,8 +17,11 @@ import * as assert from 'assert'; -import {CallCredentials, CallMetadataGenerator} from '../src/call-credentials'; -import {Metadata} from '../src/metadata'; +import { + CallCredentials, + CallMetadataGenerator, +} from '../src/call-credentials'; +import { Metadata } from '../src/metadata'; // Metadata generators @@ -36,107 +39,123 @@ const generateFromServiceURL: CallMetadataGenerator = (options, cb) => { cb(null, metadata); }; const generateWithError: CallMetadataGenerator = (options, cb) => - cb(new Error()); + cb(new Error()); // Tests describe('CallCredentials', () => { describe('createFromMetadataGenerator', () => { it('should accept a metadata generator', () => { - assert.doesNotThrow( - () => CallCredentials.createFromMetadataGenerator( - generateFromServiceURL)); + assert.doesNotThrow(() => + CallCredentials.createFromMetadataGenerator(generateFromServiceURL) + ); }); }); describe('compose', () => { it('should accept a CallCredentials object and return a new object', () => { - const callCredentials1 = - CallCredentials.createFromMetadataGenerator(generateFromServiceURL); - const callCredentials2 = - CallCredentials.createFromMetadataGenerator(generateFromServiceURL); + const callCredentials1 = CallCredentials.createFromMetadataGenerator( + generateFromServiceURL + ); + const callCredentials2 = CallCredentials.createFromMetadataGenerator( + generateFromServiceURL + ); const combinedCredentials = callCredentials1.compose(callCredentials2); - assert.notEqual(combinedCredentials, callCredentials1); - assert.notEqual(combinedCredentials, callCredentials2); + assert.notStrictEqual(combinedCredentials, callCredentials1); + assert.notStrictEqual(combinedCredentials, callCredentials2); }); it('should be chainable', () => { - const callCredentials1 = - CallCredentials.createFromMetadataGenerator(generateFromServiceURL); - const callCredentials2 = - CallCredentials.createFromMetadataGenerator(generateFromServiceURL); + const callCredentials1 = CallCredentials.createFromMetadataGenerator( + generateFromServiceURL + ); + const callCredentials2 = CallCredentials.createFromMetadataGenerator( + generateFromServiceURL + ); assert.doesNotThrow(() => { - callCredentials1.compose(callCredentials2) - .compose(callCredentials2) - .compose(callCredentials2); + callCredentials1 + .compose(callCredentials2) + .compose(callCredentials2) + .compose(callCredentials2); }); }); }); describe('generateMetadata', () => { - it('should call the function passed to createFromMetadataGenerator', - async () => { - const callCredentials = CallCredentials.createFromMetadataGenerator( - generateFromServiceURL); - let metadata: Metadata; - try { - metadata = - await callCredentials.generateMetadata({service_url: 'foo'}); - } catch (err) { - throw err; - } - assert.deepEqual(metadata.get('service_url'), ['foo']); - }); + it('should call the function passed to createFromMetadataGenerator', async () => { + const callCredentials = CallCredentials.createFromMetadataGenerator( + generateFromServiceURL + ); + let metadata: Metadata; + try { + metadata = await callCredentials.generateMetadata({ + service_url: 'foo', + }); + } catch (err) { + throw err; + } + assert.deepStrictEqual(metadata.get('service_url'), ['foo']); + }); - it('should emit an error if the associated metadataGenerator does', - async () => { - const callCredentials = - CallCredentials.createFromMetadataGenerator(generateWithError); - let metadata: Metadata|null = null; - try { - metadata = await callCredentials.generateMetadata({service_url: ''}); - } catch (err) { - assert.ok(err instanceof Error); - } - assert.strictEqual(metadata, null); - }); + it('should emit an error if the associated metadataGenerator does', async () => { + const callCredentials = CallCredentials.createFromMetadataGenerator( + generateWithError + ); + let metadata: Metadata | null = null; + try { + metadata = await callCredentials.generateMetadata({ service_url: '' }); + } catch (err) { + assert.ok(err instanceof Error); + } + assert.strictEqual(metadata, null); + }); it('should combine metadata from multiple generators', async () => { - const [callCreds1, callCreds2, callCreds3, callCreds4] = - [50, 100, 150, 200].map((ms) => { - const generator: CallMetadataGenerator = - makeAfterMsElapsedGenerator(ms); - return CallCredentials.createFromMetadataGenerator(generator); - }); + const [callCreds1, callCreds2, callCreds3, callCreds4] = [ + 50, + 100, + 150, + 200, + ].map(ms => { + const generator: CallMetadataGenerator = makeAfterMsElapsedGenerator( + ms + ); + return CallCredentials.createFromMetadataGenerator(generator); + }); const testCases = [ { - credentials: callCreds1.compose(callCreds2) - .compose(callCreds3) - .compose(callCreds4), - expected: ['50', '100', '150', '200'] + credentials: callCreds1 + .compose(callCreds2) + .compose(callCreds3) + .compose(callCreds4), + expected: ['50', '100', '150', '200'], }, { credentials: callCreds4.compose( - callCreds3.compose(callCreds2.compose(callCreds1))), - expected: ['200', '150', '100', '50'] + callCreds3.compose(callCreds2.compose(callCreds1)) + ), + expected: ['200', '150', '100', '50'], }, { credentials: callCreds3.compose( - callCreds4.compose(callCreds1).compose(callCreds2)), - expected: ['150', '200', '50', '100'] - } + callCreds4.compose(callCreds1).compose(callCreds2) + ), + expected: ['150', '200', '50', '100'], + }, ]; // Try each test case and make sure the msElapsed field is as expected - await Promise.all(testCases.map(async (testCase) => { - const {credentials, expected} = testCase; - let metadata: Metadata; - try { - metadata = await credentials.generateMetadata({service_url: ''}); - } catch (err) { - throw err; - } - assert.deepEqual(metadata.get('msElapsed'), expected); - })); + await Promise.all( + testCases.map(async testCase => { + const { credentials, expected } = testCase; + let metadata: Metadata; + try { + metadata = await credentials.generateMetadata({ service_url: '' }); + } catch (err) { + throw err; + } + assert.deepStrictEqual(metadata.get('msElapsed'), expected); + }) + ); }); }); }); diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index e2c8ff5c0..a5f7908be 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -16,44 +16,44 @@ */ import * as assert from 'assert'; -import {OutgoingHttpHeaders} from 'http'; +import { OutgoingHttpHeaders } from 'http'; import * as http2 from 'http2'; -import {range} from 'lodash'; +import { range } from 'lodash'; import * as stream from 'stream'; -import {CallCredentials} from '../src/call-credentials'; -import {Http2CallStream} from '../src/call-stream'; -import {Channel, Http2Channel} from '../src/channel'; -import {CompressionFilterFactory} from '../src/compression-filter'; -import {Status} from '../src/constants'; -import {FilterStackFactory} from '../src/filter-stack'; -import {Metadata} from '../src/metadata'; +import { CallCredentials } from '../src/call-credentials'; +import { Http2CallStream } from '../src/call-stream'; +import { Channel, Http2Channel } from '../src/channel'; +import { CompressionFilterFactory } from '../src/compression-filter'; +import { Status } from '../src/constants'; +import { FilterStackFactory } from '../src/filter-stack'; +import { Metadata } from '../src/metadata'; -import {assert2, mockFunction} from './common'; +import { assert2, mockFunction } from './common'; interface DataFrames { payload: Buffer; frameLengths: number[]; } -const {HTTP2_HEADER_STATUS} = http2.constants; +const { HTTP2_HEADER_STATUS } = http2.constants; function serialize(data: string): Buffer { const header: Buffer = Buffer.alloc(5); - header.writeUInt8(0, 0); // TODO: Uncompressed only + header.writeUInt8(0, 0); // TODO: Uncompressed only header.writeInt32BE(data.length, 1); return Buffer.concat([header, Buffer.from(data, 'utf8')]); } -class ClientHttp2StreamMock extends stream.Duplex implements - http2.ClientHttp2Stream { +class ClientHttp2StreamMock extends stream.Duplex + implements http2.ClientHttp2Stream { constructor(private readonly dataFrames: DataFrames) { super(); } emitResponse(responseCode: number, metadata?: Metadata) { this.emit('response', { [HTTP2_HEADER_STATUS]: responseCode, - ...metadata ? metadata.toHttp2Headers() : {} + ...(metadata ? metadata.toHttp2Headers() : {}), }); } bytesRead = 0; @@ -84,8 +84,12 @@ class ClientHttp2StreamMock extends stream.Duplex implements _read() { if (this.dataFrame === this.dataFrames.frameLengths.length) { if (this.bytesRead < this.dataFrames.payload.length) { - this.push(this.dataFrames.payload.slice( - this.bytesRead, this.dataFrames.payload.length)); + this.push( + this.dataFrames.payload.slice( + this.bytesRead, + this.dataFrames.payload.length + ) + ); } this.push(null); return; @@ -104,36 +108,49 @@ class ClientHttp2StreamMock extends stream.Duplex implements } describe('CallStream', () => { - const callStreamArgs = - {deadline: Infinity, flags: 0, host: '', parentCall: null}; + const callStreamArgs = { + deadline: Infinity, + flags: 0, + host: '', + parentCall: null, + }; /* A CompressionFilter is now necessary to frame and deframe messages. * Currently the channel is unused, so we can replace it with an empty object, * but this might break if we start checking channel arguments, in which case * we will need a more sophisticated fake */ - const filterStackFactory = - new FilterStackFactory([new CompressionFilterFactory({} as Channel)]); - const message = 'eat this message'; // 16 bytes + const filterStackFactory = new FilterStackFactory([ + new CompressionFilterFactory({} as Channel), + ]); + const message = 'eat this message'; // 16 bytes beforeEach(() => { assert2.clearMustCalls(); }); - it('should emit a metadata event when it receives a response event', - (done) => { - const responseMetadata = new Metadata(); - responseMetadata.add('key', 'value'); - const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + it('should emit a metadata event when it receives a response event', done => { + const responseMetadata = new Metadata(); + responseMetadata.add('key', 'value'); + const callStream = new Http2CallStream( + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); - const http2Stream = new ClientHttp2StreamMock( - {payload: Buffer.alloc(0), frameLengths: []}); - callStream.once('metadata', assert2.mustCall((metadata) => { - assert.deepStrictEqual(metadata.get('key'), ['value']); - })); - callStream.attachHttp2Stream(http2Stream); - http2Stream.emitResponse(200, responseMetadata); - assert2.afterMustCallsSatisfied(done); - }); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [], + }); + callStream.once( + 'metadata', + assert2.mustCall(metadata => { + assert.deepStrictEqual(metadata.get('key'), ['value']); + }) + ); + callStream.attachHttp2Stream(http2Stream); + http2Stream.emitResponse(200, responseMetadata); + assert2.afterMustCallsSatisfied(done); + }); describe('should end a call with an error if a stream was closed', () => { const c = http2.constants; @@ -151,21 +168,27 @@ describe('CallStream', () => { [c.NGHTTP2_COMPRESSION_ERROR]: s.INTERNAL, [c.NGHTTP2_CONNECT_ERROR]: s.INTERNAL, [c.NGHTTP2_ENHANCE_YOUR_CALM]: s.RESOURCE_EXHAUSTED, - [c.NGHTTP2_INADEQUATE_SECURITY]: s.PERMISSION_DENIED + [c.NGHTTP2_INADEQUATE_SECURITY]: s.PERMISSION_DENIED, }; const keys = Object.keys(errorCodeMapping).map(key => Number(key)); - keys.forEach((key) => { + keys.forEach(key => { const value = errorCodeMapping[key]; // A null value indicates: behavior isn't specified, so skip this test. - const maybeSkip = (fn: typeof it) => value ? fn : fn.skip; + const maybeSkip = (fn: typeof it) => (value ? fn : fn.skip); maybeSkip(it)(`for error code ${key}`, () => { return new Promise((resolve, reject) => { const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock( - {payload: Buffer.alloc(0), frameLengths: []}); + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [], + }); callStream.attachHttp2Stream(http2Stream); - callStream.once('status', (status) => { + callStream.once('status', status => { try { assert.strictEqual(status.code, value); resolve(); @@ -179,151 +202,228 @@ describe('CallStream', () => { }); }); - it('should have functioning getters', (done) => { + it('should have functioning getters', done => { const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); assert.strictEqual(callStream.getStatus(), null); const credentials = CallCredentials.createEmpty(); callStream.setCredentials(credentials); assert.strictEqual(callStream.getCredentials(), credentials); - callStream.on('status', assert2.mustCall((status) => { - assert.strictEqual(status.code, Status.CANCELLED); - assert.strictEqual(status.details, ';)'); - assert.strictEqual(callStream.getStatus(), status); - })); + callStream.on( + 'status', + assert2.mustCall(status => { + assert.strictEqual(status.code, Status.CANCELLED); + assert.strictEqual(status.details, ';)'); + assert.strictEqual(callStream.getStatus(), status); + }) + ); callStream.cancelWithStatus(Status.CANCELLED, ';)'); // TODO: getPeer assert2.afterMustCallsSatisfied(done); }); describe('attachHttp2Stream', () => { - it('should handle an empty message', (done) => { + it('should handle an empty message', done => { const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); - const http2Stream = - new ClientHttp2StreamMock({payload: serialize(''), frameLengths: []}); - callStream.once('data', assert2.mustCall((buffer) => { - assert.strictEqual(buffer.toString('utf8'), ''); - })); + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); + const http2Stream = new ClientHttp2StreamMock({ + payload: serialize(''), + frameLengths: [], + }); + callStream.once( + 'data', + assert2.mustCall(buffer => { + assert.strictEqual(buffer.toString('utf8'), ''); + }) + ); callStream.attachHttp2Stream(http2Stream); assert2.afterMustCallsSatisfied(done); }); - [{description: 'all data is supplied in a single frame', frameLengths: []}, - { - description: 'frames are split along header field delimiters', - frameLengths: [1, 4] - }, - { - description: - 'portions of header fields are split between different frames', - frameLengths: [2, 1, 1, 4] - }, - { - description: 'frames are split into bytes', - frameLengths: range(0, 20).map(() => 1) - }].forEach((testCase: {description: string, frameLengths: number[]}) => { - it(`should handle a short message where ${testCase.description}`, - (done) => { - const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock({ - payload: serialize(message), // 21 bytes - frameLengths: testCase.frameLengths - }); - callStream.once('data', assert2.mustCall((buffer) => { - assert.strictEqual(buffer.toString('utf8'), message); - })); - callStream.once('end', assert2.mustCall(() => {})); - callStream.attachHttp2Stream(http2Stream); - assert2.afterMustCallsSatisfied(done); - }); + [ + { + description: 'all data is supplied in a single frame', + frameLengths: [], + }, + { + description: 'frames are split along header field delimiters', + frameLengths: [1, 4], + }, + { + description: + 'portions of header fields are split between different frames', + frameLengths: [2, 1, 1, 4], + }, + { + description: 'frames are split into bytes', + frameLengths: range(0, 20).map(() => 1), + }, + ].forEach((testCase: { description: string; frameLengths: number[] }) => { + it(`should handle a short message where ${ + testCase.description + }`, done => { + const callStream = new Http2CallStream( + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); + const http2Stream = new ClientHttp2StreamMock({ + payload: serialize(message), // 21 bytes + frameLengths: testCase.frameLengths, + }); + callStream.once( + 'data', + assert2.mustCall(buffer => { + assert.strictEqual(buffer.toString('utf8'), message); + }) + ); + callStream.once('end', assert2.mustCall(() => {})); + callStream.attachHttp2Stream(http2Stream); + assert2.afterMustCallsSatisfied(done); + }); }); - [{description: 'all data is supplied in a single frame', frameLengths: []}, - { - description: 'frames are split between delimited messages', - frameLengths: [21] - }, - {description: 'frames are split within messages', frameLengths: [10, 22]}, - { - description: 'part of 2nd message\'s header is in first frame', - frameLengths: [24] - }, - { - description: 'frames are split into bytes', - frameLengths: range(0, 41).map(() => 1) - }].forEach((testCase: {description: string, frameLengths: number[]}) => { - it(`should handle two messages where ${testCase.description}`, (done) => { + [ + { + description: 'all data is supplied in a single frame', + frameLengths: [], + }, + { + description: 'frames are split between delimited messages', + frameLengths: [21], + }, + { + description: 'frames are split within messages', + frameLengths: [10, 22], + }, + { + description: "part of 2nd message's header is in first frame", + frameLengths: [24], + }, + { + description: 'frames are split into bytes', + frameLengths: range(0, 41).map(() => 1), + }, + ].forEach((testCase: { description: string; frameLengths: number[] }) => { + it(`should handle two messages where ${testCase.description}`, done => { const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.concat( - [serialize(message), serialize(message)]), // 42 bytes - frameLengths: testCase.frameLengths + payload: Buffer.concat([serialize(message), serialize(message)]), // 42 bytes + frameLengths: testCase.frameLengths, }); - callStream.once('data', assert2.mustCall((buffer) => { - assert.strictEqual(buffer.toString('utf8'), message); - })); - callStream.once('data', assert2.mustCall((buffer) => { - assert.strictEqual(buffer.toString('utf8'), message); - })); + callStream.once( + 'data', + assert2.mustCall(buffer => { + assert.strictEqual(buffer.toString('utf8'), message); + }) + ); + callStream.once( + 'data', + assert2.mustCall(buffer => { + assert.strictEqual(buffer.toString('utf8'), message); + }) + ); callStream.once('end', assert2.mustCall(() => {})); callStream.attachHttp2Stream(http2Stream); assert2.afterMustCallsSatisfied(done); }); }); - it('should send buffered writes', (done) => { + it('should send buffered writes', done => { const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock( - {payload: Buffer.alloc(0), frameLengths: []}); + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [], + }); let streamFlushed = false; - http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { - const dataLength = chunk.readInt32BE(1); - const encodedMessage = chunk.slice(5).toString('utf8'); - assert.strictEqual(dataLength, message.length); - assert.strictEqual(encodedMessage, message); - streamFlushed = true; - })); - callStream.write({message: Buffer.from(message)}, assert2.mustCall(() => { - // Ensure this is called only after contents are written to http2Stream - assert.ok(streamFlushed); - })); + http2Stream.once( + 'write', + assert2.mustCall((chunk: Buffer) => { + const dataLength = chunk.readInt32BE(1); + const encodedMessage = chunk.slice(5).toString('utf8'); + assert.strictEqual(dataLength, message.length); + assert.strictEqual(encodedMessage, message); + streamFlushed = true; + }) + ); + callStream.write( + { message: Buffer.from(message) }, + assert2.mustCall(() => { + // Ensure this is called only after contents are written to http2Stream + assert.ok(streamFlushed); + }) + ); callStream.end(assert2.mustCall(() => {})); callStream.attachHttp2Stream(http2Stream); assert2.afterMustCallsSatisfied(done); }); - it('should cause data chunks in write calls afterward to be written to the given stream', - (done) => { - const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock( - {payload: Buffer.alloc(0), frameLengths: []}); - http2Stream.once('write', assert2.mustCall((chunk: Buffer) => { - const dataLength = chunk.readInt32BE(1); - const encodedMessage = chunk.slice(5).toString('utf8'); - assert.strictEqual(dataLength, message.length); - assert.strictEqual(encodedMessage, message); - })); - callStream.attachHttp2Stream(http2Stream); - callStream.write( - {message: Buffer.from(message)}, assert2.mustCall(() => {})); - callStream.end(assert2.mustCall(() => {})); - assert2.afterMustCallsSatisfied(done); - }); + it('should cause data chunks in write calls afterward to be written to the given stream', done => { + const callStream = new Http2CallStream( + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [], + }); + http2Stream.once( + 'write', + assert2.mustCall((chunk: Buffer) => { + const dataLength = chunk.readInt32BE(1); + const encodedMessage = chunk.slice(5).toString('utf8'); + assert.strictEqual(dataLength, message.length); + assert.strictEqual(encodedMessage, message); + }) + ); + callStream.attachHttp2Stream(http2Stream); + callStream.write( + { message: Buffer.from(message) }, + assert2.mustCall(() => {}) + ); + callStream.end(assert2.mustCall(() => {})); + assert2.afterMustCallsSatisfied(done); + }); it('should handle underlying stream errors', () => { const callStream = new Http2CallStream( - 'foo', {} as Http2Channel, callStreamArgs, filterStackFactory); - const http2Stream = new ClientHttp2StreamMock( - {payload: Buffer.alloc(0), frameLengths: []}); - callStream.once('status', assert2.mustCall((status) => { - assert.strictEqual(status.code, Status.INTERNAL); - })); + 'foo', + {} as Http2Channel, + callStreamArgs, + filterStackFactory + ); + const http2Stream = new ClientHttp2StreamMock({ + payload: Buffer.alloc(0), + frameLengths: [], + }); + callStream.once( + 'status', + assert2.mustCall(status => { + assert.strictEqual(status.code, Status.INTERNAL); + }) + ); callStream.attachHttp2Stream(http2Stream); http2Stream.emit('error'); }); diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index 7ede18075..c2013da25 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -17,15 +17,15 @@ import * as assert from 'assert'; import * as fs from 'fs'; -import {promisify} from 'util'; +import { promisify } from 'util'; -import {CallCredentials} from '../src/call-credentials'; -import {ChannelCredentials} from '../src/channel-credentials'; +import { CallCredentials } from '../src/call-credentials'; +import { ChannelCredentials } from '../src/channel-credentials'; -import {assert2, mockFunction} from './common'; +import { assert2, mockFunction } from './common'; class CallCredentialsMock implements CallCredentials { - child: CallCredentialsMock|null = null; + child: CallCredentialsMock | null = null; constructor(child?: CallCredentialsMock) { if (child) { this.child = child; @@ -52,61 +52,65 @@ class CallCredentialsMock implements CallCredentials { // tslint:disable-next-line:no-any const readFile: (...args: any[]) => Promise = promisify(fs.readFile); // A promise which resolves to loaded files in the form { ca, key, cert } -const pFixtures = Promise - .all(['ca.pem', 'server1.key', 'server1.pem'].map( - (file) => readFile(`${__dirname}/fixtures/${file}`))) - .then((result) => { - return {ca: result[0], key: result[1], cert: result[2]}; - }); +const pFixtures = Promise.all( + ['ca.pem', 'server1.key', 'server1.pem'].map(file => + readFile(`${__dirname}/fixtures/${file}`) + ) +).then(result => { + return { ca: result[0], key: result[1], cert: result[2] }; +}); describe('ChannelCredentials Implementation', () => { describe('createInsecure', () => { - it('should return a ChannelCredentials object with no associated secure context', - () => { - const creds = assert2.noThrowAndReturn( - () => ChannelCredentials.createInsecure()); - assert.ok(!creds._getConnectionOptions()); - }); + it('should return a ChannelCredentials object with no associated secure context', () => { + const creds = assert2.noThrowAndReturn(() => + ChannelCredentials.createInsecure() + ); + assert.ok(!creds._getConnectionOptions()); + }); }); describe('createSsl', () => { it('should work when given no arguments', () => { - const creds: ChannelCredentials = - assert2.noThrowAndReturn(() => ChannelCredentials.createSsl()); + const creds: ChannelCredentials = assert2.noThrowAndReturn(() => + ChannelCredentials.createSsl() + ); assert.ok(!!creds._getConnectionOptions()); }); it('should work with just a CA override', async () => { - const {ca} = await pFixtures; - const creds = - assert2.noThrowAndReturn(() => ChannelCredentials.createSsl(ca)); + const { ca } = await pFixtures; + const creds = assert2.noThrowAndReturn(() => + ChannelCredentials.createSsl(ca) + ); assert.ok(!!creds._getConnectionOptions()); }); it('should work with just a private key and cert chain', async () => { - const {key, cert} = await pFixtures; - const creds = assert2.noThrowAndReturn( - () => ChannelCredentials.createSsl(null, key, cert)); + const { key, cert } = await pFixtures; + const creds = assert2.noThrowAndReturn(() => + ChannelCredentials.createSsl(null, key, cert) + ); assert.ok(!!creds._getConnectionOptions()); }); it('should work with three parameters specified', async () => { - const {ca, key, cert} = await pFixtures; - const creds = assert2.noThrowAndReturn( - () => ChannelCredentials.createSsl(ca, key, cert)); + const { ca, key, cert } = await pFixtures; + const creds = assert2.noThrowAndReturn(() => + ChannelCredentials.createSsl(ca, key, cert) + ); assert.ok(!!creds._getConnectionOptions()); }); - it('should throw if just one of private key and cert chain are missing', - async () => { - const {ca, key, cert} = await pFixtures; - assert.throws(() => ChannelCredentials.createSsl(ca, key)); - assert.throws(() => ChannelCredentials.createSsl(ca, key, null)); - assert.throws(() => ChannelCredentials.createSsl(ca, null, cert)); - assert.throws(() => ChannelCredentials.createSsl(null, key)); - assert.throws(() => ChannelCredentials.createSsl(null, key, null)); - assert.throws(() => ChannelCredentials.createSsl(null, null, cert)); - }); + it('should throw if just one of private key and cert chain are missing', async () => { + const { ca, key, cert } = await pFixtures; + assert.throws(() => ChannelCredentials.createSsl(ca, key)); + assert.throws(() => ChannelCredentials.createSsl(ca, key, null)); + assert.throws(() => ChannelCredentials.createSsl(ca, null, cert)); + assert.throws(() => ChannelCredentials.createSsl(null, key)); + assert.throws(() => ChannelCredentials.createSsl(null, key, null)); + assert.throws(() => ChannelCredentials.createSsl(null, null, cert)); + }); }); describe('compose', () => { @@ -122,12 +126,15 @@ describe('ChannelCredentials Implementation', () => { const callCreds2 = new CallCredentialsMock(); // Associate both call credentials with channelCreds const composedChannelCreds = ChannelCredentials.createSsl() - .compose(callCreds1) - .compose(callCreds2); + .compose(callCreds1) + .compose(callCreds2); // Build a mock object that should be an identical copy const composedCallCreds = callCreds1.compose(callCreds2); - assert.ok(composedCallCreds.isEqual( - composedChannelCreds._getCallCredentials() as CallCredentialsMock)); + assert.ok( + composedCallCreds.isEqual( + composedChannelCreds._getCallCredentials() as CallCredentialsMock + ) + ); }); }); }); diff --git a/packages/grpc-js/test/test-logging.ts b/packages/grpc-js/test/test-logging.ts index d01c06004..c1601cbc5 100644 --- a/packages/grpc-js/test/test-logging.ts +++ b/packages/grpc-js/test/test-logging.ts @@ -39,11 +39,11 @@ describe('Logging', () => { }); it('gates logging based on severity', () => { - const output: Array = []; + const output: Array = []; const logger: Partial = { error(...args: string[]): void { output.push(args); - } + }, }; logging.setLogger(logger); @@ -65,8 +65,13 @@ describe('Logging', () => { logging.log(grpc.logVerbosity.INFO, 7, 8); logging.log(grpc.logVerbosity.ERROR, 'j', 'k'); - assert.deepStrictEqual( - output, - [['a', 'b', 'c'], ['d', 'e'], ['f'], ['g'], ['h', 'i'], ['j', 'k']]); + assert.deepStrictEqual(output, [ + ['a', 'b', 'c'], + ['d', 'e'], + ['f'], + ['g'], + ['h', 'i'], + ['j', 'k'], + ]); }); }); diff --git a/packages/grpc-js/test/test-metadata.ts b/packages/grpc-js/test/test-metadata.ts index 12d110408..a56798ac8 100644 --- a/packages/grpc-js/test/test-metadata.ts +++ b/packages/grpc-js/test/test-metadata.ts @@ -17,8 +17,8 @@ import * as assert from 'assert'; import * as http2 from 'http2'; -import {range} from 'lodash'; -import {Metadata, MetadataObject, MetadataValue} from '../src/metadata'; +import { range } from 'lodash'; +import { Metadata, MetadataObject, MetadataValue } from '../src/metadata'; class TestMetadata extends Metadata { getInternalRepresentation() { @@ -28,14 +28,15 @@ class TestMetadata extends Metadata { static fromHttp2Headers(headers: http2.IncomingHttpHeaders): TestMetadata { const result = Metadata.fromHttp2Headers(headers) as TestMetadata; result.getInternalRepresentation = - TestMetadata.prototype.getInternalRepresentation; + TestMetadata.prototype.getInternalRepresentation; return result; } } const validKeyChars = '0123456789abcdefghijklmnopqrstuvwxyz_-.'; -const validNonBinValueChars = - range(0x20, 0x7f).map(code => String.fromCharCode(code)).join(''); +const validNonBinValueChars = range(0x20, 0x7f) + .map(code => String.fromCharCode(code)) + .join(''); describe('Metadata', () => { let metadata: TestMetadata; @@ -86,20 +87,20 @@ describe('Metadata', () => { it('Saves values that can be retrieved', () => { metadata.set('key', 'value'); - assert.deepEqual(metadata.get('key'), ['value']); + assert.deepStrictEqual(metadata.get('key'), ['value']); }); it('Overwrites previous values', () => { metadata.set('key', 'value1'); metadata.set('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value2']); + assert.deepStrictEqual(metadata.get('key'), ['value2']); }); it('Normalizes keys', () => { metadata.set('Key', 'value1'); - assert.deepEqual(metadata.get('key'), ['value1']); + assert.deepStrictEqual(metadata.get('key'), ['value1']); metadata.set('KEY', 'value2'); - assert.deepEqual(metadata.get('key'), ['value2']); + assert.deepStrictEqual(metadata.get('key'), ['value2']); }); }); @@ -133,20 +134,20 @@ describe('Metadata', () => { it('Saves values that can be retrieved', () => { metadata.add('key', 'value'); - assert.deepEqual(metadata.get('key'), ['value']); + assert.deepStrictEqual(metadata.get('key'), ['value']); }); it('Combines with previous values', () => { metadata.add('key', 'value1'); metadata.add('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); + assert.deepStrictEqual(metadata.get('key'), ['value1', 'value2']); }); it('Normalizes keys', () => { metadata.add('Key', 'value1'); - assert.deepEqual(metadata.get('key'), ['value1']); + assert.deepStrictEqual(metadata.get('key'), ['value1']); metadata.add('KEY', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); + assert.deepStrictEqual(metadata.get('key'), ['value1', 'value2']); }); }); @@ -154,13 +155,13 @@ describe('Metadata', () => { it('clears values from a key', () => { metadata.add('key', 'value'); metadata.remove('key'); - assert.deepEqual(metadata.get('key'), []); + assert.deepStrictEqual(metadata.get('key'), []); }); it('Normalizes keys', () => { metadata.add('key', 'value'); metadata.remove('KEY'); - assert.deepEqual(metadata.get('key'), []); + assert.deepStrictEqual(metadata.get('key'), []); }); }); @@ -172,15 +173,15 @@ describe('Metadata', () => { }); it('gets all values associated with a key', () => { - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); + assert.deepStrictEqual(metadata.get('key'), ['value1', 'value2']); }); it('Normalizes keys', () => { - assert.deepEqual(metadata.get('KEY'), ['value1', 'value2']); + assert.deepStrictEqual(metadata.get('KEY'), ['value1', 'value2']); }); it('returns an empty list for non-existent keys', () => { - assert.deepEqual(metadata.get('non-existent-key'), []); + assert.deepStrictEqual(metadata.get('non-existent-key'), []); }); it('returns Buffers for "-bin" keys', () => { @@ -194,8 +195,11 @@ describe('Metadata', () => { metadata.add('Key2', 'value2'); metadata.add('KEY3', 'value3a'); metadata.add('KEY3', 'value3b'); - assert.deepEqual( - metadata.getMap(), {key1: 'value1', key2: 'value2', key3: 'value3a'}); + assert.deepStrictEqual(metadata.getMap(), { + key1: 'value1', + key2: 'value2', + key3: 'value3a', + }); }); }); @@ -203,21 +207,21 @@ describe('Metadata', () => { it('retains values from the original', () => { metadata.add('key', 'value'); const copy = metadata.clone(); - assert.deepEqual(copy.get('key'), ['value']); + assert.deepStrictEqual(copy.get('key'), ['value']); }); it('Does not see newly added values', () => { metadata.add('key', 'value1'); const copy = metadata.clone(); metadata.add('key', 'value2'); - assert.deepEqual(copy.get('key'), ['value1']); + assert.deepStrictEqual(copy.get('key'), ['value1']); }); it('Does not add new values to the original', () => { metadata.add('key', 'value1'); const copy = metadata.clone(); copy.add('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1']); + assert.deepStrictEqual(metadata.get('key'), ['value1']); }); it('Copy cannot modify binary values in the original', () => { @@ -227,7 +231,7 @@ describe('Metadata', () => { const copyBuf = copy.get('key-bin')[0] as Buffer; assert.deepStrictEqual(copyBuf, buf); copyBuf.fill(0); - assert.notDeepEqual(copyBuf, buf); + assert.notDeepStrictEqual(copyBuf, buf); }); }); @@ -246,12 +250,15 @@ describe('Metadata', () => { const metadata2IR = metadata2.getInternalRepresentation(); metadata.merge(metadata2); // Ensure metadata2 didn't change - assert.deepEqual(metadata2.getInternalRepresentation(), metadata2IR); - assert.deepEqual(metadata.get('key1'), ['value1', 'value1']); - assert.deepEqual(metadata.get('key2'), ['value2a', 'value2b']); - assert.deepEqual(metadata.get('key3'), ['value3a', 'value3b']); - assert.deepEqual(metadata.get('key4'), ['value4']); - assert.deepEqual(metadata.get('key5'), ['value5a', 'value5b']); + assert.deepStrictEqual( + metadata2.getInternalRepresentation(), + metadata2IR + ); + assert.deepStrictEqual(metadata.get('key1'), ['value1', 'value1']); + assert.deepStrictEqual(metadata.get('key2'), ['value2a', 'value2b']); + assert.deepStrictEqual(metadata.get('key3'), ['value3a', 'value3b']); + assert.deepStrictEqual(metadata.get('key4'), ['value4']); + assert.deepStrictEqual(metadata.get('key5'), ['value5a', 'value5b']); }); }); @@ -265,19 +272,20 @@ describe('Metadata', () => { metadata.add('key-bin', Buffer.from(range(16, 32))); metadata.add('key-bin', Buffer.from(range(0, 32))); const headers = metadata.toHttp2Headers(); - assert.deepEqual(headers, { + assert.deepStrictEqual(headers, { key1: ['value1'], key2: ['value2'], key3: ['value3a', 'value3b'], 'key-bin': [ - 'AAECAwQFBgcICQoLDA0ODw==', 'EBESExQVFhcYGRobHB0eHw==', - 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=' - ] + 'AAECAwQFBgcICQoLDA0ODw==', + 'EBESExQVFhcYGRobHB0eHw==', + 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=', + ], }); }); it('creates an empty header object from empty Metadata', () => { - assert.deepEqual(metadata.toHttp2Headers(), {}); + assert.deepStrictEqual(metadata.toHttp2Headers(), {}); }); }); @@ -288,30 +296,33 @@ describe('Metadata', () => { key2: ['value2'], key3: ['value3a', 'value3b'], 'key-bin': [ - 'AAECAwQFBgcICQoLDA0ODw==', 'EBESExQVFhcYGRobHB0eHw==', - 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=' - ] + 'AAECAwQFBgcICQoLDA0ODw==', + 'EBESExQVFhcYGRobHB0eHw==', + 'AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8=', + ], }; const metadataFromHeaders = TestMetadata.fromHttp2Headers(headers); const internalRepr = metadataFromHeaders.getInternalRepresentation(); const expected: MetadataObject = new Map([ - ['key1', ['value1']], ['key2', ['value2']], + ['key1', ['value1']], + ['key2', ['value2']], ['key3', ['value3a', 'value3b']], [ 'key-bin', [ - Buffer.from(range(0, 16)), Buffer.from(range(16, 32)), - Buffer.from(range(0, 32)) - ] - ] + Buffer.from(range(0, 16)), + Buffer.from(range(16, 32)), + Buffer.from(range(0, 32)), + ], + ], ]); - assert.deepEqual(internalRepr, expected); + assert.deepStrictEqual(internalRepr, expected); }); it('creates an empty Metadata object from empty headers', () => { const metadataFromHeaders = TestMetadata.fromHttp2Headers({}); const internalRepr = metadataFromHeaders.getInternalRepresentation(); - assert.deepEqual(internalRepr, new Map()); + assert.deepStrictEqual(internalRepr, new Map()); }); }); }); diff --git a/packages/grpc-js/test/test-server-credentials.ts b/packages/grpc-js/test/test-server-credentials.ts index 847b647a0..6c8bd877e 100644 --- a/packages/grpc-js/test/test-server-credentials.ts +++ b/packages/grpc-js/test/test-server-credentials.ts @@ -18,9 +18,9 @@ // Allow `any` data type for testing runtime type checking. // tslint:disable no-any import * as assert from 'assert'; -import {readFileSync} from 'fs'; -import {join} from 'path'; -import {ServerCredentials} from '../src'; +import { readFileSync } from 'fs'; +import { join } from 'path'; +import { ServerCredentials } from '../src'; const ca = readFileSync(join(__dirname, 'fixtures', 'ca.pem')); const key = readFileSync(join(__dirname, 'fixtures', 'server1.key')); @@ -41,32 +41,43 @@ describe('Server Credentials', () => { const creds = ServerCredentials.createSsl(ca, []); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual( - creds._getSettings(), {ca, cert: [], key: [], requestCert: false}); + assert.deepStrictEqual(creds._getSettings(), { + ca, + cert: [], + key: [], + requestCert: false, + }); }); it('accepts a boolean as the third argument', () => { const creds = ServerCredentials.createSsl(ca, [], true); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual( - creds._getSettings(), {ca, cert: [], key: [], requestCert: true}); + assert.deepStrictEqual(creds._getSettings(), { + ca, + cert: [], + key: [], + requestCert: true, + }); }); it('accepts an object with two buffers in the second argument', () => { - const keyCertPairs = [{private_key: key, cert_chain: cert}]; + const keyCertPairs = [{ private_key: key, cert_chain: cert }]; const creds = ServerCredentials.createSsl(null, keyCertPairs); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual( - creds._getSettings(), - {ca: undefined, cert: [cert], key: [key], requestCert: false}); + assert.deepStrictEqual(creds._getSettings(), { + ca: undefined, + cert: [cert], + key: [key], + requestCert: false, + }); }); it('accepts multiple objects in the second argument', () => { const keyCertPairs = [ - {private_key: key, cert_chain: cert}, - {private_key: key, cert_chain: cert} + { private_key: key, cert_chain: cert }, + { private_key: key, cert_chain: cert }, ]; const creds = ServerCredentials.createSsl(null, keyCertPairs, false); @@ -75,7 +86,7 @@ describe('Server Credentials', () => { ca: undefined, cert: [cert, cert], key: [key, key], - requestCert: false + requestCert: false, }); }); @@ -108,7 +119,7 @@ describe('Server Credentials', () => { }); it('fails if the object does not have a Buffer private key', () => { - const keyCertPairs: any = [{private_key: 'test', cert_chain: cert}]; + const keyCertPairs: any = [{ private_key: 'test', cert_chain: cert }]; assert.throws(() => { ServerCredentials.createSsl(null, keyCertPairs); @@ -116,7 +127,7 @@ describe('Server Credentials', () => { }); it('fails if the object does not have a Buffer cert chain', () => { - const keyCertPairs: any = [{private_key: key, cert_chain: 'test'}]; + const keyCertPairs: any = [{ private_key: key, cert_chain: 'test' }]; assert.throws(() => { ServerCredentials.createSsl(null, keyCertPairs); diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 76e63a6a4..6faf19ea0 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -18,59 +18,63 @@ // Allow `any` data type for testing runtime type checking. // tslint:disable no-any import * as assert from 'assert'; -import {join} from 'path'; +import { join } from 'path'; import * as grpc from '../src'; -import {ServiceError} from '../src/call'; -import {ServiceClient, ServiceClientConstructor} from '../src/make-client'; -import {Server} from '../src/server'; -import {sendUnaryData, ServerDuplexStream, ServerReadableStream, ServerUnaryCall, ServerWritableStream} from '../src/server-call'; - -import {loadProtoFile} from './common'; +import { ServiceError } from '../src/call'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { Server } from '../src/server'; +import { + sendUnaryData, + ServerDuplexStream, + ServerReadableStream, + ServerUnaryCall, + ServerWritableStream, +} from '../src/server-call'; + +import { loadProtoFile } from './common'; const protoFile = join(__dirname, 'fixtures', 'test_service.proto'); const testServiceDef = loadProtoFile(protoFile); -const testServiceClient = - testServiceDef.TestService as ServiceClientConstructor; +const testServiceClient = testServiceDef.TestService as ServiceClientConstructor; const clientInsecureCreds = grpc.credentials.createInsecure(); const serverInsecureCreds = grpc.ServerCredentials.createInsecure(); - describe('Client malformed response handling', () => { let server: Server; let client: ServiceClient; - const badArg = Buffer.from([0xFF]); + const badArg = Buffer.from([0xff]); - before((done) => { + before(done => { const malformedTestService = { unary: { path: '/TestService/Unary', requestStream: false, responseStream: false, requestDeserialize: identity, - responseSerialize: identity + responseSerialize: identity, }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, requestDeserialize: identity, - responseSerialize: identity + responseSerialize: identity, }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, requestDeserialize: identity, - responseSerialize: identity + responseSerialize: identity, }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, requestDeserialize: identity, - responseSerialize: identity - } + responseSerialize: identity, + }, } as any; server = new Server(); @@ -81,7 +85,9 @@ describe('Client malformed response handling', () => { }, clientStream( - stream: ServerReadableStream, cb: sendUnaryData) { + stream: ServerReadableStream, + cb: sendUnaryData + ) { stream.on('data', noop); stream.on('end', () => { cb(null, badArg); @@ -102,7 +108,7 @@ describe('Client malformed response handling', () => { stream.on('end', () => { stream.end(); }); - } + }, }); server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { @@ -113,12 +119,12 @@ describe('Client malformed response handling', () => { }); }); - after((done) => { + after(done => { client.close(); server.tryShutdown(done); }); - it('should get an INTERNAL status with a unary call', (done) => { + it('should get an INTERNAL status with a unary call', done => { client.unary({}, (err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.INTERNAL); @@ -126,7 +132,7 @@ describe('Client malformed response handling', () => { }); }); - it('should get an INTERNAL status with a client stream call', (done) => { + it('should get an INTERNAL status with a client stream call', done => { const call = client.clientStream((err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.INTERNAL); @@ -137,7 +143,7 @@ describe('Client malformed response handling', () => { call.end(); }); - it('should get an INTERNAL status with a server stream call', (done) => { + it('should get an INTERNAL status with a server stream call', done => { const call = client.serverStream({}); call.on('data', noop); @@ -148,7 +154,7 @@ describe('Client malformed response handling', () => { }); }); - it('should get an INTERNAL status with a bidi stream call', (done) => { + it('should get an INTERNAL status with a bidi stream call', done => { const call = client.bidiStream(); call.on('data', noop); @@ -167,7 +173,7 @@ describe('Server serialization failure handling', () => { let client: ServiceClient; let server: Server; - before((done) => { + before(done => { function serializeFail(obj: any) { throw new Error('Serialization failed'); } @@ -178,29 +184,29 @@ describe('Server serialization failure handling', () => { requestStream: false, responseStream: false, requestDeserialize: identity, - responseSerialize: serializeFail + responseSerialize: serializeFail, }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, requestDeserialize: identity, - responseSerialize: serializeFail + responseSerialize: serializeFail, }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, requestDeserialize: identity, - responseSerialize: serializeFail + responseSerialize: serializeFail, }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, requestDeserialize: identity, - responseSerialize: serializeFail - } + responseSerialize: serializeFail, + }, }; server = new Server(); @@ -210,7 +216,9 @@ describe('Server serialization failure handling', () => { }, clientStream( - stream: ServerReadableStream, cb: sendUnaryData) { + stream: ServerReadableStream, + cb: sendUnaryData + ) { stream.on('data', noop); stream.on('end', () => { cb(null, {}); @@ -230,7 +238,7 @@ describe('Server serialization failure handling', () => { stream.on('end', () => { stream.end(); }); - } + }, }); server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { @@ -241,12 +249,12 @@ describe('Server serialization failure handling', () => { }); }); - after((done) => { + after(done => { client.close(); server.tryShutdown(done); }); - it('should get an INTERNAL status with a unary call', (done) => { + it('should get an INTERNAL status with a unary call', done => { client.unary({}, (err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.INTERNAL); @@ -254,7 +262,7 @@ describe('Server serialization failure handling', () => { }); }); - it('should get an INTERNAL status with a client stream call', (done) => { + it('should get an INTERNAL status with a client stream call', done => { const call = client.clientStream((err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.INTERNAL); @@ -265,7 +273,7 @@ describe('Server serialization failure handling', () => { call.end(); }); - it('should get an INTERNAL status with a server stream call', (done) => { + it('should get an INTERNAL status with a server stream call', done => { const call = client.serverStream({}); call.on('data', noop); @@ -277,13 +285,12 @@ describe('Server serialization failure handling', () => { }); }); - describe('Other conditions', () => { let client: ServiceClient; let server: Server; let port: number; - before((done) => { + before(done => { const trailerMetadata = new grpc.Metadata(); server = new Server(); @@ -296,15 +303,20 @@ describe('Other conditions', () => { if (req.error) { const details = req.message || 'Requested error'; - cb({code: grpc.status.UNKNOWN, details} as ServiceError, null, - trailerMetadata); + cb( + { code: grpc.status.UNKNOWN, details } as ServiceError, + null, + trailerMetadata + ); } else { - cb(null, {count: 1}, trailerMetadata); + cb(null, { count: 1 }, trailerMetadata); } }, clientStream( - stream: ServerReadableStream, cb: sendUnaryData) { + stream: ServerReadableStream, + cb: sendUnaryData + ) { let count = 0; let errored = false; @@ -320,7 +332,7 @@ describe('Other conditions', () => { stream.on('end', () => { if (!errored) { - cb(null, {count}, trailerMetadata); + cb(null, { count }, trailerMetadata); } }); }, @@ -332,11 +344,11 @@ describe('Other conditions', () => { stream.emit('error', { code: grpc.status.UNKNOWN, details: req.message || 'Requested error', - metadata: trailerMetadata + metadata: trailerMetadata, }); } else { for (let i = 0; i < 5; i++) { - stream.write({count: i}); + stream.write({ count: i }); } stream.end(trailerMetadata); @@ -354,7 +366,7 @@ describe('Other conditions', () => { err.metadata.add('count', '' + count); stream.emit('error', err); } else { - stream.write({count}); + stream.write({ count }); count++; } }); @@ -362,7 +374,7 @@ describe('Other conditions', () => { stream.on('end', () => { stream.end(trailerMetadata); }); - } + }, }); server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { @@ -374,14 +386,14 @@ describe('Other conditions', () => { }); }); - after((done) => { + after(done => { client.close(); server.tryShutdown(done); }); describe('Server receiving bad input', () => { let misbehavingClient: ServiceClient; - const badArg = Buffer.from([0xFF]); + const badArg = Buffer.from([0xff]); before(() => { const testServiceAttrs = { @@ -390,33 +402,35 @@ describe('Other conditions', () => { requestStream: false, responseStream: false, requestSerialize: identity, - responseDeserialize: identity + responseDeserialize: identity, }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, requestSerialize: identity, - responseDeserialize: identity + responseDeserialize: identity, }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, requestSerialize: identity, - responseDeserialize: identity + responseDeserialize: identity, }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, requestSerialize: identity, - responseDeserialize: identity - } + responseDeserialize: identity, + }, } as any; - const client = - grpc.makeGenericClientConstructor(testServiceAttrs, 'TestService'); + const client = grpc.makeGenericClientConstructor( + testServiceAttrs, + 'TestService' + ); misbehavingClient = new client(`localhost:${port}`, clientInsecureCreds); }); @@ -425,7 +439,7 @@ describe('Other conditions', () => { misbehavingClient.close(); }); - it('should respond correctly to a unary call', (done) => { + it('should respond correctly to a unary call', done => { misbehavingClient.unary(badArg, (err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.INTERNAL); @@ -433,19 +447,20 @@ describe('Other conditions', () => { }); }); - it('should respond correctly to a client stream', (done) => { - const call = - misbehavingClient.clientStream((err: ServiceError, data: any) => { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); + it('should respond correctly to a client stream', done => { + const call = misbehavingClient.clientStream( + (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.INTERNAL); + done(); + } + ); call.write(badArg); call.end(); }); - it('should respond correctly to a server stream', (done) => { + it('should respond correctly to a server stream', done => { const call = misbehavingClient.serverStream(badArg); call.on('data', (data: any) => { @@ -459,7 +474,7 @@ describe('Other conditions', () => { }); }); - it('should respond correctly to a bidi stream', (done) => { + it('should respond correctly to a bidi stream', done => { const call = misbehavingClient.bidiStream(); call.on('data', (data: any) => { @@ -478,17 +493,19 @@ describe('Other conditions', () => { }); describe('Trailing metadata', () => { - it('should be present when a unary call succeeds', (done) => { + it('should be present when a unary call succeeds', done => { let count = 0; - const call = - client.unary({error: false}, (err: ServiceError, data: any) => { - assert.ifError(err); + const call = client.unary( + { error: false }, + (err: ServiceError, data: any) => { + assert.ifError(err); - count++; - if (count === 2) { - done(); - } - }); + count++; + if (count === 2) { + done(); + } + } + ); call.on('status', (status: grpc.StatusObject) => { assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); @@ -500,17 +517,19 @@ describe('Other conditions', () => { }); }); - it('should be present when a unary call fails', (done) => { + it('should be present when a unary call fails', done => { let count = 0; - const call = - client.unary({error: true}, (err: ServiceError, data: any) => { - assert(err); + const call = client.unary( + { error: true }, + (err: ServiceError, data: any) => { + assert(err); - count++; - if (count === 2) { - done(); - } - }); + count++; + if (count === 2) { + done(); + } + } + ); call.on('status', (status: grpc.StatusObject) => { assert.deepStrictEqual(status.metadata.get('trailer-present'), ['yes']); @@ -522,7 +541,7 @@ describe('Other conditions', () => { }); }); - it('should be present when a client stream call succeeds', (done) => { + it('should be present when a client stream call succeeds', done => { let count = 0; const call = client.clientStream((err: ServiceError, data: any) => { assert.ifError(err); @@ -533,8 +552,8 @@ describe('Other conditions', () => { } }); - call.write({error: false}); - call.write({error: false}); + call.write({ error: false }); + call.write({ error: false }); call.end(); call.on('status', (status: grpc.StatusObject) => { @@ -547,7 +566,7 @@ describe('Other conditions', () => { }); }); - it('should be present when a client stream call fails', (done) => { + it('should be present when a client stream call fails', done => { let count = 0; const call = client.clientStream((err: ServiceError, data: any) => { assert(err); @@ -558,8 +577,8 @@ describe('Other conditions', () => { } }); - call.write({error: false}); - call.write({error: true}); + call.write({ error: false }); + call.write({ error: true }); call.end(); call.on('status', (status: grpc.StatusObject) => { @@ -572,8 +591,8 @@ describe('Other conditions', () => { }); }); - it('should be present when a server stream call succeeds', (done) => { - const call = client.serverStream({error: false}); + it('should be present when a server stream call succeeds', done => { + const call = client.serverStream({ error: false }); call.on('data', noop); call.on('status', (status: grpc.StatusObject) => { @@ -583,8 +602,8 @@ describe('Other conditions', () => { }); }); - it('should be present when a server stream call fails', (done) => { - const call = client.serverStream({error: true}); + it('should be present when a server stream call fails', done => { + const call = client.serverStream({ error: true }); call.on('data', noop); call.on('error', (error: ServiceError) => { @@ -593,11 +612,11 @@ describe('Other conditions', () => { }); }); - it('should be present when a bidi stream succeeds', (done) => { + it('should be present when a bidi stream succeeds', done => { const call = client.bidiStream(); - call.write({error: false}); - call.write({error: false}); + call.write({ error: false }); + call.write({ error: false }); call.end(); call.on('data', noop); call.on('status', (status: grpc.StatusObject) => { @@ -607,11 +626,11 @@ describe('Other conditions', () => { }); }); - it('should be present when a bidi stream fails', (done) => { + it('should be present when a bidi stream fails', done => { const call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); + call.write({ error: false }); + call.write({ error: true }); call.end(); call.on('data', noop); call.on('error', (error: ServiceError) => { @@ -622,8 +641,8 @@ describe('Other conditions', () => { }); describe('Error object should contain the status', () => { - it('for a unary call', (done) => { - client.unary({error: true}, (err: ServiceError, data: any) => { + it('for a unary call', done => { + client.unary({ error: true }, (err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.UNKNOWN); assert.strictEqual(err.details, 'Requested error'); @@ -631,7 +650,7 @@ describe('Other conditions', () => { }); }); - it('for a client stream call', (done) => { + it('for a client stream call', done => { const call = client.clientStream((err: ServiceError, data: any) => { assert(err); assert.strictEqual(err.code, grpc.status.UNKNOWN); @@ -639,13 +658,13 @@ describe('Other conditions', () => { done(); }); - call.write({error: false}); - call.write({error: true}); + call.write({ error: false }); + call.write({ error: true }); call.end(); }); - it('for a server stream call', (done) => { - const call = client.serverStream({error: true}); + it('for a server stream call', done => { + const call = client.serverStream({ error: true }); call.on('data', noop); call.on('error', (error: ServiceError) => { @@ -655,11 +674,11 @@ describe('Other conditions', () => { }); }); - it('for a bidi stream call', (done) => { + it('for a bidi stream call', done => { const call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); + call.write({ error: false }); + call.write({ error: true }); call.end(); call.on('data', noop); call.on('error', (error: ServiceError) => { @@ -669,23 +688,22 @@ describe('Other conditions', () => { }); }); - it('for a UTF-8 error message', (done) => { + it('for a UTF-8 error message', done => { client.unary( - {error: true, message: '測試字符串'}, - (err: ServiceError, data: any) => { - assert(err); - assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.details, '測試字符串'); - done(); - }); + { error: true, message: '測試字符串' }, + (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + done(); + } + ); }); }); }); - function identity(arg: any): any { return arg; } - function noop(): void {} diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 8a5730cd9..0be74e95c 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -22,31 +22,30 @@ import * as fs from 'fs'; import * as path from 'path'; import * as grpc from '../src'; -import {ServerCredentials} from '../src'; -import {ServiceError} from '../src/call'; -import {ServiceClient, ServiceClientConstructor} from '../src/make-client'; -import {Server} from '../src/server'; -import {sendUnaryData, ServerUnaryCall} from '../src/server-call'; +import { ServerCredentials } from '../src'; +import { ServiceError } from '../src/call'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { Server } from '../src/server'; +import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; -import {loadProtoFile} from './common'; +import { loadProtoFile } from './common'; const ca = fs.readFileSync(path.join(__dirname, 'fixtures', 'ca.pem')); const key = fs.readFileSync(path.join(__dirname, 'fixtures', 'server1.key')); const cert = fs.readFileSync(path.join(__dirname, 'fixtures', 'server1.pem')); function noop(): void {} - describe('Server', () => { describe('constructor', () => { it('should work with no arguments', () => { assert.doesNotThrow(() => { - new Server(); // tslint:disable-line:no-unused-expression + new Server(); // tslint:disable-line:no-unused-expression }); }); it('should work with an empty object argument', () => { assert.doesNotThrow(() => { - new Server({}); // tslint:disable-line:no-unused-expression + new Server({}); // tslint:disable-line:no-unused-expression }); }); @@ -58,21 +57,27 @@ describe('Server', () => { }); describe('bindAsync', () => { - it('binds with insecure credentials', (done) => { + it('binds with insecure credentials', done => { const server = new Server(); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - assert(typeof port === 'number' && port > 0); - server.tryShutdown(done); - }); + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + assert(typeof port === 'number' && port > 0); + server.tryShutdown(done); + } + ); }); - it('binds with secure credentials', (done) => { + it('binds with secure credentials', done => { const server = new Server(); const creds = ServerCredentials.createSsl( - ca, [{private_key: key, cert_chain: cert}], true); + ca, + [{ private_key: key, cert_chain: cert }], + true + ); server.bindAsync('localhost:0', creds, (err, port) => { assert.ifError(err); @@ -85,14 +90,20 @@ describe('Server', () => { const server = new Server(); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - server.start(); - assert.throws(() => { - server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), noop); - }, /server is already started/); - }); + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + server.start(); + assert.throws(() => { + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + noop + ); + }, /server is already started/); + } + ); }); it('throws on invalid inputs', () => { @@ -108,16 +119,19 @@ describe('Server', () => { assert.throws(() => { server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), null as any); + 'localhost:0', + ServerCredentials.createInsecure(), + null as any + ); }, /callback must be a function/); }); }); describe('tryShutdown', () => { - it('calls back with an error if the server is not running', (done) => { + it('calls back with an error if the server is not running', done => { const server = new Server(); - server.tryShutdown((err) => { + server.tryShutdown(err => { assert(err !== undefined && err.message === 'server is not running'); done(); }); @@ -127,12 +141,12 @@ describe('Server', () => { describe('start', () => { let server: Server; - beforeEach((done) => { + beforeEach(done => { server = new Server(); server.bindAsync('localhost:0', ServerCredentials.createInsecure(), done); }); - afterEach((done) => { + afterEach(done => { server.tryShutdown(done); }); @@ -162,8 +176,8 @@ describe('Server', () => { const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; const mathServiceAttrs = mathClient.service; - const dummyImpls = {div() {}, divMany() {}, fib() {}, sum() {}}; - const altDummyImpls = {Div() {}, DivMany() {}, Fib() {}, Sum() {}}; + const dummyImpls = { div() {}, divMany() {}, fib() {}, sum() {} }; + const altDummyImpls = { Div() {}, DivMany() {}, Fib() {}, Sum() {} }; it('succeeds with a single service', () => { const server = new Server(); @@ -198,18 +212,21 @@ describe('Server', () => { }); }); - it('fails if the server has been started', (done) => { + it('fails if the server has been started', done => { const server = new Server(); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - server.start(); - assert.throws(() => { - server.addService(mathServiceAttrs, dummyImpls); - }, /Can't add a service to a started server\./); - server.tryShutdown(done); - }); + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + server.start(); + assert.throws(() => { + server.addService(mathServiceAttrs, dummyImpls); + }, /Can't add a service to a started server\./); + server.tryShutdown(done); + } + ); }); }); @@ -241,29 +258,36 @@ describe('Server', () => { const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; const mathServiceAttrs = mathClient.service; - beforeEach((done) => { + beforeEach(done => { server = new Server(); server.addService(mathServiceAttrs, {}); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - client = new mathClient( - `localhost:${port}`, grpc.credentials.createInsecure()); - server.start(); - done(); - }); + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); }); - it('should respond to a unary call with UNIMPLEMENTED', (done) => { + it('should respond to a unary call with UNIMPLEMENTED', done => { client.div( - {divisor: 4, dividend: 3}, (error: ServiceError, response: any) => { - assert(error); - assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); - done(); - }); + { divisor: 4, dividend: 3 }, + (error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + } + ); }); - it('should respond to a client stream with UNIMPLEMENTED', (done) => { + it('should respond to a client stream with UNIMPLEMENTED', done => { const call = client.sum((error: ServiceError, response: any) => { assert(error); assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); @@ -273,8 +297,8 @@ describe('Server', () => { call.end(); }); - it('should respond to a server stream with UNIMPLEMENTED', (done) => { - const call = client.fib({limit: 5}); + it('should respond to a server stream with UNIMPLEMENTED', done => { + const call = client.fib({ limit: 5 }); call.on('data', (value: any) => { assert.fail('No messages expected'); @@ -287,7 +311,7 @@ describe('Server', () => { }); }); - it('should respond to a bidi call with UNIMPLEMENTED', (done) => { + it('should respond to a bidi call with UNIMPLEMENTED', done => { const call = client.divMany(); call.on('data', (value: any) => { @@ -309,41 +333,47 @@ describe('Echo service', () => { let server: Server; let client: ServiceClient; - before((done) => { + before(done => { const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); - const echoService = - loadProtoFile(protoFile).EchoService as ServiceClientConstructor; + const echoService = loadProtoFile(protoFile) + .EchoService as ServiceClientConstructor; server = new Server(); server.addService(echoService.service, { echo(call: ServerUnaryCall, callback: sendUnaryData) { callback(null, call.request); - } + }, }); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - client = new echoService( - `localhost:${port}`, grpc.credentials.createInsecure()); - server.start(); - done(); - }); + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new echoService( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); }); - after((done) => { + after(done => { client.close(); server.tryShutdown(done); }); - it('should echo the recieved message directly', (done) => { + it('should echo the recieved message directly', done => { client.echo( - {value: 'test value', value2: 3}, - (error: ServiceError, response: any) => { - assert.ifError(error); - assert.deepStrictEqual(response, {value: 'test value', value2: 3}); - done(); - }); + { value: 'test value', value2: 3 }, + (error: ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); }); }); @@ -368,43 +398,51 @@ describe('Generic client and server', () => { requestSerialize: toBuffer, requestDeserialize: toString, responseSerialize: toBuffer, - responseDeserialize: toString - } + responseDeserialize: toString, + }, }; describe('String client and server', () => { let client: ServiceClient; let server: Server; - before((done) => { + before(done => { server = new Server(); server.addService(stringServiceAttrs as any, { capitalize( - call: ServerUnaryCall, callback: sendUnaryData) { + call: ServerUnaryCall, + callback: sendUnaryData + ) { callback(null, capitalize(call.request)); - } + }, }); server.bindAsync( - 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { - assert.ifError(err); - server.start(); - const clientConstr = grpc.makeGenericClientConstructor( - stringServiceAttrs as any, - 'unused_but_lets_appease_typescript_anyway'); - client = new clientConstr( - `localhost:${port}`, grpc.credentials.createInsecure()); - done(); - }); + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + server.start(); + const clientConstr = grpc.makeGenericClientConstructor( + stringServiceAttrs as any, + 'unused_but_lets_appease_typescript_anyway' + ); + client = new clientConstr( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + done(); + } + ); }); - after((done) => { + after(done => { client.close(); server.tryShutdown(done); }); - it('Should respond with a capitalized string', (done) => { + it('Should respond with a capitalized string', done => { client.capitalize('abc', (err: ServiceError, response: string) => { assert.ifError(err); assert.strictEqual(response, 'Abc'); diff --git a/packages/grpc-js/test/test-status-builder.ts b/packages/grpc-js/test/test-status-builder.ts index 089652792..7bf12203b 100644 --- a/packages/grpc-js/test/test-status-builder.ts +++ b/packages/grpc-js/test/test-status-builder.ts @@ -18,7 +18,7 @@ import * as assert from 'assert'; import * as grpc from '../src'; -import {StatusBuilder} from '../src/status-builder'; +import { StatusBuilder } from '../src/status-builder'; describe('StatusBuilder', () => { it('is exported by the module', () => { @@ -33,14 +33,19 @@ describe('StatusBuilder', () => { assert.deepStrictEqual(builder.build(), {}); result = builder.withCode(grpc.status.OK); assert.strictEqual(result, builder); - assert.deepStrictEqual(builder.build(), {code: grpc.status.OK}); + assert.deepStrictEqual(builder.build(), { code: grpc.status.OK }); result = builder.withDetails('foobar'); assert.strictEqual(result, builder); - assert.deepStrictEqual( - builder.build(), {code: grpc.status.OK, details: 'foobar'}); + assert.deepStrictEqual(builder.build(), { + code: grpc.status.OK, + details: 'foobar', + }); result = builder.withMetadata(metadata); assert.strictEqual(result, builder); - assert.deepStrictEqual( - builder.build(), {code: grpc.status.OK, details: 'foobar', metadata}); + assert.deepStrictEqual(builder.build(), { + code: grpc.status.OK, + details: 'foobar', + metadata, + }); }); }); diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 7741e806a..cb0129702 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 7741e806a213cba63c96234f16d712a8aa101a49 +Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 From 4e0162cf222318e1123f239a21267074a7a7475d Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sat, 18 May 2019 11:25:06 -0400 Subject: [PATCH 0660/1899] grpc-js: skip gulp tasks based on Node version This commit wraps the grpc-js Gulp tasks in a version check so they only run on supported versions of Node. --- packages/grpc-js/gulpfile.ts | 46 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts index 14ddbfef0..6d8d20943 100644 --- a/packages/grpc-js/gulpfile.ts +++ b/packages/grpc-js/gulpfile.ts @@ -17,7 +17,6 @@ import * as gulp from 'gulp'; -import * as fs from 'fs'; import * as mocha from 'gulp-mocha'; import * as path from 'path'; import * as execa from 'execa'; @@ -30,24 +29,30 @@ const ncpP = pify(ncp); Error.stackTraceLimit = Infinity; const jsCoreDir = __dirname; -const tslintPath = path.resolve(jsCoreDir, 'node_modules/google-ts-style/tslint.json'); -const tsconfigPath = path.resolve(jsCoreDir, 'tsconfig.json'); const outDir = path.resolve(jsCoreDir, 'build'); -const srcDir = path.resolve(jsCoreDir, 'src'); -const testDir = path.resolve(jsCoreDir, 'test'); + +const pkgPath = path.resolve(jsCoreDir, 'package.json'); +const supportedVersionRange = require(pkgPath).engines.node; +const versionNotSupported = () => { + console.log(`Skipping grpc-js task for Node ${process.version}`); + return () => { return Promise.resolve(); }; +}; +const identity = (value: any): any => value; +const checkTask = semver.satisfies(process.version, supportedVersionRange) ? + identity : versionNotSupported; const execNpmVerb = (verb: string, ...args: string[]) => execa('npm', [verb, ...args], {cwd: jsCoreDir, stdio: 'inherit'}); const execNpmCommand = execNpmVerb.bind(null, 'run'); -const install = () => execNpmVerb('install', '--unsafe-perm'); +const install = checkTask(() => execNpmVerb('install', '--unsafe-perm')); /** * Runs tslint on files in src/, with linting rules defined in tslint.json. */ -const lint = () => execNpmCommand('check'); +const lint = checkTask(() => execNpmCommand('check')); -const cleanFiles = () => execNpmCommand('clean'); +const cleanFiles = checkTask(() => execNpmCommand('clean')); const clean = gulp.series(install, cleanFiles); @@ -57,20 +62,15 @@ const cleanAll = gulp.parallel(clean); * Transpiles TypeScript files in src/ to JavaScript according to the settings * found in tsconfig.json. */ -const compile = () => execNpmCommand('compile'); - -const copyTestFixtures = () => ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`); - -const runTests = () => { - if (semver.satisfies(process.version, '^8.13.0 || >=10.10.0')) { - return gulp.src(`${outDir}/test/**/*.js`) - .pipe(mocha({reporter: 'mocha-jenkins-reporter', - require: ['ts-node/register']})); - } else { - console.log(`Skipping grpc-js tests for Node ${process.version}`); - return Promise.resolve(null); - } -}; +const compile = checkTask(() => execNpmCommand('compile')); + +const copyTestFixtures = checkTask(() => ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`)); + +const runTests = checkTask(() => { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter', + require: ['ts-node/register']})); +}); const test = gulp.series(install, copyTestFixtures, runTests); @@ -81,4 +81,4 @@ export { cleanAll, compile, test -} \ No newline at end of file +} From f30a5d8588ac552e4119172e2028dfff6eab162f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 17 May 2019 14:20:17 -0400 Subject: [PATCH 0661/1899] grpc-js: support client cancellation This commit adds client cancellation support and tests for cancellation and deadlines. --- packages/grpc-js/src/server-call.ts | 15 +- .../grpc-js/test/test-server-deadlines.ts | 188 ++++++++++++++++++ 2 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 packages/grpc-js/test/test-server-deadlines.ts diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 6c3f73756..8c295defd 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -56,11 +56,11 @@ const defaultResponseOptions = { waitForTrailers: true, } as http2.ServerStreamResponseOptions; -export interface ServerSurfaceCall { +export type ServerSurfaceCall = { cancelled: boolean; getPeer(): string; sendMetadata(responseMetadata: Metadata): void; -} +} & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { request: RequestType | null; @@ -88,6 +88,7 @@ export class ServerUnaryCallImpl extends EventEmitter super(); this.cancelled = false; this.request = null; + this.call.setupSurfaceCall(this); } getPeer(): string { @@ -111,6 +112,7 @@ export class ServerReadableStreamImpl ) { super({ objectMode: true }); this.cancelled = false; + this.call.setupSurfaceCall(this); this.call.setupReadable(this); } @@ -143,6 +145,7 @@ export class ServerWritableStreamImpl this.cancelled = false; this.request = null; this.trailingMetadata = new Metadata(); + this.call.setupSurfaceCall(this); this.on('error', err => { this.call.sendError(err as ServiceError); @@ -212,6 +215,7 @@ export class ServerDuplexStreamImpl extends Duplex super({ objectMode: true }); this.cancelled = false; this.trailingMetadata = new Metadata(); + this.call.setupSurfaceCall(this); this.call.setupReadable(this); this.on('error', err => { @@ -513,6 +517,13 @@ export class Http2ServerCallStream< this.stream.resume(); } + setupSurfaceCall(call: ServerSurfaceCall) { + this.once('cancelled', reason => { + call.cancelled = true; + call.emit('cancelled', reason); + }); + } + setupReadable( readable: | ServerReadableStream diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts new file mode 100644 index 000000000..ef54ef3fb --- /dev/null +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -0,0 +1,188 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any +import * as assert from 'assert'; +import * as path from 'path'; + +import * as grpc from '../src'; +import { ServerCredentials } from '../src'; +import { ServiceError } from '../src/call'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { Server } from '../src/server'; +import { + sendUnaryData, + ServerUnaryCall, + ServerWritableStream, +} from '../src/server-call'; + +import { loadProtoFile } from './common'; + +const clientInsecureCreds = grpc.credentials.createInsecure(); +const serverInsecureCreds = ServerCredentials.createInsecure(); + +describe('Server deadlines', () => { + let server: Server; + let client: ServiceClient; + + before(done => { + const protoFile = path.join(__dirname, 'fixtures', 'test_service.proto'); + const testServiceDef = loadProtoFile(protoFile); + const testServiceClient = testServiceDef.TestService as ServiceClientConstructor; + + server = new Server(); + server.addService(testServiceClient.service, { + unary(call: ServerUnaryCall, cb: sendUnaryData) { + setTimeout(() => { + cb(null, {}); + }, 2000); + }, + }); + + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new testServiceClient(`localhost:${port}`, clientInsecureCreds); + server.start(); + done(); + }); + }); + + after(done => { + client.close(); + server.tryShutdown(done); + }); + + it('works with deadlines', done => { + const metadata = new grpc.Metadata(); + const { + path, + requestSerialize: serialize, + responseDeserialize: deserialize, + } = client.unary as any; + + metadata.set('grpc-timeout', '100m'); + client.makeUnaryRequest( + path, + serialize, + deserialize, + {}, + metadata, + {}, + (error: any, response: any) => { + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + assert.strictEqual(error.details, 'Deadline exceeded'); + assert.strictEqual(error.message, 'Deadline exceeded'); + done(); + } + ); + }); + + it('rejects invalid deadline', done => { + const metadata = new grpc.Metadata(); + const { + path, + requestSerialize: serialize, + responseDeserialize: deserialize, + } = client.unary as any; + + metadata.set('grpc-timeout', 'Infinity'); + client.makeUnaryRequest( + path, + serialize, + deserialize, + {}, + metadata, + {}, + (error: any, response: any) => { + assert.strictEqual(error.code, grpc.status.OUT_OF_RANGE); + assert.strictEqual(error.details, 'Invalid deadline'); + assert.strictEqual(error.message, 'Invalid deadline'); + done(); + } + ); + }); +}); + +describe('Cancellation', () => { + let server: Server; + let client: ServiceClient; + let inHandler = false; + let cancelledInServer = false; + + before(done => { + const protoFile = path.join(__dirname, 'fixtures', 'test_service.proto'); + const testServiceDef = loadProtoFile(protoFile); + const testServiceClient = testServiceDef.TestService as ServiceClientConstructor; + + server = new Server(); + server.addService(testServiceClient.service, { + serverStream(stream: ServerWritableStream) { + inHandler = true; + stream.on('cancelled', () => { + stream.write({}); + stream.end(); + cancelledInServer = true; + }); + }, + }); + + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new testServiceClient(`localhost:${port}`, clientInsecureCreds); + server.start(); + done(); + }); + }); + + after(done => { + client.close(); + server.tryShutdown(done); + }); + + it('handles requests cancelled by the client', done => { + const call = client.serverStream({}); + + call.on('data', assert.ifError); + call.on('error', (error: ServiceError) => { + assert.strictEqual(error.code, grpc.status.CANCELLED); + assert.strictEqual(error.details, 'Cancelled on client'); + assert.strictEqual(error.message, 'Cancelled on client'); + waitForServerCancel(); + }); + + function waitForHandler() { + if (inHandler === true) { + call.cancel(); + return; + } + + setImmediate(waitForHandler); + } + + function waitForServerCancel() { + if (cancelledInServer === true) { + done(); + return; + } + + setImmediate(waitForServerCancel); + } + + waitForHandler(); + }); +}); From 8f724121a28e54343ee4c8e4fb97126006480b2d Mon Sep 17 00:00:00 2001 From: Dmitry Cheryasov Date: Mon, 20 May 2019 15:36:15 -0500 Subject: [PATCH 0662/1899] Fix a TypeError loading a non-existent proto file. The issue: https://github.com/grpc/grpc-node/issues/876 This is an obvious typo; `typeof` has to return a string `'undefined'`, not a literal `undefined.` --- packages/proto-loader/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 563f58f57..4e17719ef 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -121,7 +121,7 @@ function getAllHandledReflectionObjects( if (isHandledReflectionObject(obj)) { return [[objName, obj]]; } else { - if (isNamespaceBase(obj) && typeof obj.nested !== undefined) { + if (isNamespaceBase(obj) && typeof obj.nested !== 'undefined') { return Object.keys(obj.nested!) .map((name) => { return getAllHandledReflectionObjects(obj.nested![name], objName); From 477c4a4c1823e89f91fd35305d1cf17b1ed648ed Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 28 May 2019 10:36:07 -0700 Subject: [PATCH 0663/1899] grpc-js: Change how filters access connectivity information --- packages/grpc-js/src/channel.ts | 9 ++++-- packages/grpc-js/src/deadline-filter.ts | 40 +++++-------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index a81deec13..9de72287f 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -329,11 +329,14 @@ export class Http2Channel extends EventEmitter implements Channel { stream: Http2CallStream, metadata: Metadata ) { + const connectMetadata: Promise = this.connect().then( + () => new Metadata() + ); const finalMetadata: Promise = stream.filterStack.sendMetadata( - Promise.resolve(metadata.clone()) + connectMetadata ); - Promise.all([finalMetadata, this.connect()]) - .then(([metadataValue]) => { + finalMetadata + .then(metadataValue => { const headers = metadataValue.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = authority; headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index fe0d16272..771cb96ac 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -70,41 +70,17 @@ export class DeadlineFilter extends BaseFilter implements Filter { } } - sendMetadata(metadata: Promise) { + async sendMetadata(metadata: Promise) { if (this.deadline === Infinity) { return metadata; } - return new Promise((resolve, reject) => { - if ( - this.channel.getConnectivityState(false) === ConnectivityState.READY - ) { - resolve(metadata); - } else { - const handleStateChange = (newState: ConnectivityState) => { - if (newState === ConnectivityState.READY) { - resolve(metadata); - this.channel.removeListener( - 'connectivityStateChanged', - handleStateChange - ); - this.callStream.removeListener('status', handleStatus); - } - }; - const handleStatus = () => { - reject(new Error('Call ended')); - this.channel.removeListener( - 'connectivityStateChanged', - handleStateChange - ); - }; - this.channel.on('connectivityStateChanged', handleStateChange); - this.callStream.once('status', handleStatus); - } - }).then((finalMetadata: Metadata) => { - const timeoutString = getDeadline(this.deadline); - finalMetadata.set('grpc-timeout', timeoutString); - return finalMetadata; - }); + /* The input metadata promise depends on the original channel.connect() + * promise, so when it is complete that implies that the channel is + * connected */ + const finalMetadata = await metadata; + const timeoutString = getDeadline(this.deadline); + finalMetadata.set('grpc-timeout', timeoutString); + return finalMetadata; } } From 45f37f1a9eb75aabc81af8266c27793a633bddcb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 28 May 2019 10:53:08 -0700 Subject: [PATCH 0664/1899] Fix missing custom metadata --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 9de72287f..cb8b04cac 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -330,7 +330,7 @@ export class Http2Channel extends EventEmitter implements Channel { metadata: Metadata ) { const connectMetadata: Promise = this.connect().then( - () => new Metadata() + () => metadata ); const finalMetadata: Promise = stream.filterStack.sendMetadata( connectMetadata From ffaade2e6f038982a7c0a32c2c5f7ff6ae5e5fb1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 28 May 2019 16:18:37 -0700 Subject: [PATCH 0665/1899] Update grpc-js to 0.4.1 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 318d826c7..99cf8ad52 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.4.0", + "version": "0.4.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From d7c23b066e767defa47fe25d9ceae2f8b5963223 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 29 May 2019 15:18:33 -0400 Subject: [PATCH 0666/1899] grpc-js: update to typescript@3.5 This commit updates to TypeScript, which is supposed to be faster. Refs: https://devblogs.microsoft.com/typescript/announcing-typescript-3-5/ --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 99cf8ad52..a61578655 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -22,7 +22,7 @@ "clang-format": "^1.0.55", "gts": "^1.0.0", "lodash": "^4.17.4", - "typescript": "~3.4.5" + "typescript": "~3.5.1" }, "contributors": [ { From ea254dfc628fc8eebd2a15bbddd42c87e943e4fd Mon Sep 17 00:00:00 2001 From: cjihrig Date: Wed, 29 May 2019 15:22:18 -0400 Subject: [PATCH 0667/1899] grpc-js: enable incremental compiles This commit enables incremental TypeScript builds. --- packages/grpc-js/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index fd18bad0d..e47c5eea1 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -5,7 +5,8 @@ "rootDir": ".", "outDir": "build", "target": "es2017", - "module": "commonjs" + "module": "commonjs", + "incremental": true }, "include": [ "src/*.ts", From c3041e8b9ac7d7a1de04cb25241aa5e46bcdaa5a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 30 May 2019 18:05:42 -0700 Subject: [PATCH 0668/1899] Test that waitForReady option changes default behavior --- packages/grpc-native-core/test/surface_test.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index d5b7add54..c6f121fd2 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -934,6 +934,19 @@ describe('Other conditions', function() { call.write({}); call.end(); }); + it('client should wait for ready by default', function(done) { + this.timeout(15000); + const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); + const metadata = new grpc.Metadata({waitForReady: false}); + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 10); + disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + + }); it('client should drop a call if not connected with waitForReady off', function(done) { /* We have to wait for the client to reach the first connection timeout * and go to TRANSIENT_FAILURE to confirm that the waitForReady option From f2990d03ced87e6b9abec4477902a9d242a9bb8f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 31 May 2019 12:43:45 -0700 Subject: [PATCH 0669/1899] Make tests actually reflect expected behavior --- packages/grpc-native-core/test/surface_test.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index c6f121fd2..dd936b6cc 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -934,7 +934,7 @@ describe('Other conditions', function() { call.write({}); call.end(); }); - it('client should wait for ready by default', function(done) { + it('client should not wait for ready by default', function(done) { this.timeout(15000); const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); const metadata = new grpc.Metadata({waitForReady: false}); @@ -942,24 +942,24 @@ describe('Other conditions', function() { deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ assert(error); - assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + assert.strictEqual(error.code, grpc.status.UNAVAILABLE); done(); }); }); - it('client should drop a call if not connected with waitForReady off', function(done) { + it('client should wait for a connection with waitForReady on', function(done) { /* We have to wait for the client to reach the first connection timeout * and go to TRANSIENT_FAILURE to confirm that the waitForReady option * makes it end the call instead of continuing to try. A DNS resolution * failure makes that transition very fast. */ this.timeout(15000); const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); - const metadata = new grpc.Metadata({waitForReady: false}); + const metadata = new grpc.Metadata({waitForReady: true}); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ assert(error); - assert.strictEqual(error.code, grpc.status.UNAVAILABLE); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); done(); }); }); From 69d4377dc23814187afb5ecac184831e95b43dc5 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 31 May 2019 16:03:59 -0400 Subject: [PATCH 0670/1899] grpc-js: load semver range from package.json This commit loads the required semver range from the package.json file, instead of hard-coding the string in index.ts. --- packages/grpc-js/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index d54c0a675..e49cfb5d7 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -41,7 +41,7 @@ import { Metadata } from './metadata'; import { KeyCertPair, ServerCredentials } from './server-credentials'; import { StatusBuilder } from './status-builder'; -const supportedNodeVersions = '^8.13.0 || >=10.10.0'; +const supportedNodeVersions = require('../../package.json').engines.node; if (!semver.satisfies(process.version, supportedNodeVersions)) { throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); } From 69ffb0ece861bde839932e1dc70e53d6a0db2b4a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Jun 2019 09:53:59 -0700 Subject: [PATCH 0671/1899] Remove test of default behavior --- packages/grpc-native-core/test/surface_test.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js index dd936b6cc..a4a1aa939 100644 --- a/packages/grpc-native-core/test/surface_test.js +++ b/packages/grpc-native-core/test/surface_test.js @@ -934,19 +934,6 @@ describe('Other conditions', function() { call.write({}); call.end(); }); - it('client should not wait for ready by default', function(done) { - this.timeout(15000); - const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); - const metadata = new grpc.Metadata({waitForReady: false}); - const deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 10); - disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ - assert(error); - assert.strictEqual(error.code, grpc.status.UNAVAILABLE); - done(); - }); - - }); it('client should wait for a connection with waitForReady on', function(done) { /* We have to wait for the client to reach the first connection timeout * and go to TRANSIENT_FAILURE to confirm that the waitForReady option From 92bed740e81478a5882987dc9c2500ab9d07d83b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Jun 2019 14:47:11 -0700 Subject: [PATCH 0672/1899] Fix custom metadata handling bug --- packages/grpc-js/src/channel.ts | 2 +- test/api/metadata_test.js | 101 ++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 test/api/metadata_test.js diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index cb8b04cac..6e7d2cd1d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -330,7 +330,7 @@ export class Http2Channel extends EventEmitter implements Channel { metadata: Metadata ) { const connectMetadata: Promise = this.connect().then( - () => metadata + () => metadata.clone() ); const finalMetadata: Promise = stream.filterStack.sendMetadata( connectMetadata diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js new file mode 100644 index 000000000..3499ebcd6 --- /dev/null +++ b/test/api/metadata_test.js @@ -0,0 +1,101 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const options = { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +}; +const path = require('path'); +const fs = require('fs'); +const assert = require('assert'); +const _ = require('lodash'); +const anyGrpc = require('../any_grpc'); +const clientGrpc = anyGrpc.client; +const serverGrpc = anyGrpc.server; +const protoLoader = require('../../packages/proto-loader', options); +const testServiceDef = protoLoader.loadSync(__dirname + '/../proto/test_service.proto'); +const TestService = serverGrpc.loadPackageDefinition(testServiceDef).TestService.service; +const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestService; + +const keyPath = path.join(__dirname, '../data/server1.key'); +const pemPath = path.join(__dirname, '../data/server1.pem'); +const caPath = path.join(__dirname, '../data/ca.pem'); +const keyData = fs.readFileSync(keyPath); +const pemData = fs.readFileSync(pemPath); +const caData = fs.readFileSync(caPath); + +const clientCreds = clientGrpc.credentials.createSsl(caData); +const dummyCallCreds = clientGrpc.credentials.createFromMetadataGenerator((options, callback) => { + const metadata = new clientGrpc.Metadata(); + metadata.add('authorization', 'test'); + callback(null, metadata); +}); +const combinedClientCreds = clientGrpc.credentials.combineChannelCredentials(clientCreds, dummyCallCreds); +const serverCreds = serverGrpc.ServerCredentials.createSsl(null, [{private_key: keyData, cert_chain: pemData}]); + +const hostOverride = 'foo.test.google.fr'; +const clientOptions = { + 'grpc.ssl_target_name_override': hostOverride, + 'grpc.default_authority': hostOverride +} + +describe('Sending metadata', function() { + let server; + let port; + before(function() { + server = new serverGrpc.Server(); + server.addService(TestService, { + unary: function(call, cb) { + cb(null, {}); + }, + clientStream: function(stream, cb){ + stream.on('data', function(data) {}); + stream.on('end', function() { + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.end(); + }); + } + }); + port = server.bind('localhost:0', serverCreds); + server.start(); + client = new TestServiceClient(`localhost:${port}`, combinedClientCreds, clientOptions); + }); + after(function() { + server.forceShutdown(); + }); + it('Should be able to send the same metadata on two calls with call creds', function(done) { + const metadata = new clientGrpc.Metadata(); + client.unary({}, metadata, (err, data) => { + assert.ifError(err); + client.unary({}, metadata, (err, data) => { + assert.ifError(err); + done(); + }); + }); + }); +}); \ No newline at end of file From afb7b4a60223da88e2b63ef11529058d1387bc94 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Jun 2019 18:21:39 -0700 Subject: [PATCH 0673/1899] Fix dropped messages when multiple arrived in one HTTP/2 frame --- packages/grpc-js/src/call-stream.ts | 4 +-- packages/grpc-js/src/server-call.ts | 35 ++++++++++++++++---------- packages/grpc-js/src/stream-decoder.ts | 9 ++++--- 3 files changed, 29 insertions(+), 19 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 4b76d9010..6ddd4414b 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -289,9 +289,9 @@ export class Http2CallStream extends Duplex implements Call { }); stream.on('trailers', this.handleTrailers.bind(this)); stream.on('data', (data: Buffer) => { - const message = this.decoder.write(data); + const messages = this.decoder.write(data); - if (message !== null) { + for (const message of messages) { this.tryPush(message); } }); diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 8c295defd..47827d498 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -531,22 +531,31 @@ export class Http2ServerCallStream< ) { const decoder = new StreamDecoder(); - this.stream.on('data', async (data: Buffer) => { - const message = decoder.write(data); - - if (message === null) { - return; - } + /* This code here is wrong but getting the client working is the priority + * right now and I'm not going to block that on fixing what is currently + * unused code. If multiple messages come in with a single frame, this will + * keep calling readable.push after it has returned false, which should not + * happen. Independent of that, deserializeMessage is asynchronous, which + * means that incoming messages could be reordered when emitted to the + * application. That effect will become more pronounced when compression + * support is added and deserializeMessage takes longer by an amount of + * time dependent on the size of the message. A system like the one in + * call-stream.ts should be added to buffer incoming messages and + * preserve ordering more strongly */ - try { - const deserialized = await this.deserializeMessage(message); + this.stream.on('data', async (data: Buffer) => { + const messages = decoder.write(data); + for (const message of messages) { + try { + const deserialized = await this.deserializeMessage(message); - if (!readable.push(deserialized)) { - this.stream.pause(); + if (!readable.push(deserialized)) { + this.stream.pause(); + } + } catch (err) { + err.code = Status.INTERNAL; + readable.emit('error', err); } - } catch (err) { - err.code = Status.INTERNAL; - readable.emit('error', err); } }); diff --git a/packages/grpc-js/src/stream-decoder.ts b/packages/grpc-js/src/stream-decoder.ts index 24881ba0b..78803026b 100644 --- a/packages/grpc-js/src/stream-decoder.ts +++ b/packages/grpc-js/src/stream-decoder.ts @@ -30,9 +30,10 @@ export class StreamDecoder { private readPartialMessage: Buffer[] = []; private readMessageRemaining = 0; - write(data: Buffer): Buffer | null { + write(data: Buffer): Buffer[] { let readHead = 0; let toRead: number; + let result: Buffer[] = []; while (readHead < data.length) { switch (this.readState) { @@ -69,7 +70,7 @@ export class StreamDecoder { ); this.readState = ReadState.NO_DATA; - return message; + result.push(message); } } break; @@ -91,7 +92,7 @@ export class StreamDecoder { ); this.readState = ReadState.NO_DATA; - return framedMessage; + result.push(framedMessage); } break; default: @@ -99,6 +100,6 @@ export class StreamDecoder { } } - return null; + return result; } } From a4b3a7fbae80ac54349faa811d79b721cb0b18f3 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Jun 2019 11:53:20 -0400 Subject: [PATCH 0674/1899] grpc-js: reject invalid Content-Type requests This commit implements the following portion of the spec: If Content-Type does not begin with "application/grpc", gRPC servers SHOULD respond with HTTP status of 415 (Unsupported Media Type). This will prevent other HTTP/2 clients from interpreting a gRPC error response, which uses status 200 (OK), as successful. --- packages/grpc-js/src/server.ts | 16 +++++++++++ packages/grpc-js/test/test-server.ts | 43 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 7dd07078a..99498781c 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -288,6 +288,22 @@ export class Server { return; } + const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; + + if ( + typeof contentType !== 'string' || + !contentType.startsWith('application/grpc') + ) { + stream.respond( + { + [http2.constants.HTTP2_HEADER_STATUS]: + http2.constants.HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + }, + { endStream: true } + ); + return; + } + try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; const handler = this.handlers.get(path); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 0be74e95c..fb59739c5 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -19,6 +19,7 @@ // tslint:disable no-any import * as assert from 'assert'; import * as fs from 'fs'; +import * as http2 from 'http2'; import * as path from 'path'; import * as grpc from '../src'; @@ -450,4 +451,46 @@ describe('Generic client and server', () => { }); }); }); + + it('responds with HTTP status of 415 on invalid content-type', done => { + const server = new Server(); + const creds = ServerCredentials.createInsecure(); + + server.bindAsync('localhost:0', creds, (err, port) => { + assert.ifError(err); + const client = http2.connect(`http://localhost:${port}`); + let count = 0; + + function makeRequest(headers: http2.IncomingHttpHeaders) { + const req = client.request(headers); + let statusCode: string; + + req.on('response', headers => { + statusCode = headers[http2.constants.HTTP2_HEADER_STATUS] as string; + assert.strictEqual( + statusCode, + http2.constants.HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE + ); + }); + + req.on('end', () => { + assert(statusCode); + count++; + if (count === 2) { + client.close(); + server.tryShutdown(done); + } + }); + + req.end(); + } + + server.start(); + + // Missing Content-Type header. + makeRequest({ ':path': '/' }); + // Invalid Content-Type header. + makeRequest({ ':path': '/', 'content-type': 'application/not-grpc' }); + }); + }); }); From 93ea51f1167bbeb2bd5a51d44e2d7f616db609c9 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 4 Jun 2019 12:44:41 -0400 Subject: [PATCH 0675/1899] grpc-js: disable http2 server timeout gRPC has its own mechanisms for timing out a request. Furthermore, the default timeout was removed from Node.js Refs: https://github.com/nodejs/node/pull/27558 --- packages/grpc-js/src/server.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 7dd07078a..debff61e1 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -202,6 +202,7 @@ export class Server { this.http2Server = http2.createServer(); } + this.http2Server.setTimeout(0, noop); this._setupHandlers(); function onError(err: Error): void { From f6ea3c31f91d03b8b8ddcd79e411d66d4ba7cb40 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Jun 2019 09:53:07 -0700 Subject: [PATCH 0676/1899] Bump grpc-js to 0.4.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a61578655..dc544be71 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.4.1", + "version": "0.4.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From f6b284513d79a15660f13d2c18b1317c50421160 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 4 Jun 2019 21:09:28 +0200 Subject: [PATCH 0677/1899] Trying to enable C++14. --- packages/grpc-native-core/binding.gyp | 4 ++-- packages/grpc-native-core/templates/binding.gyp.template | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index ae64cb4fe..f1fc3dd66 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -78,7 +78,7 @@ ], 'cflags_cc': [ '-Werror', - '-std=c++11' + '-std=c++1y' ], 'include_dirs': [ 'deps/grpc', @@ -209,7 +209,7 @@ '-DPB_FIELD_32BIT', '-fvisibility=hidden', '-stdlib=libc++', - '-std=c++11', + '-std=c++1y', '-Wno-error=deprecated-declarations' ], }, diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index bc9041421..b5e54ff21 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -70,7 +70,7 @@ ], 'cflags_cc': [ '-Werror', - '-std=c++11' + '-std=c++1y' ], 'include_dirs': [ 'deps/grpc', @@ -178,7 +178,7 @@ '${item}', % endfor '-stdlib=libc++', - '-std=c++11', + '-std=c++1y', '-Wno-error=deprecated-declarations' ], % endif From a2d9ec3ea835df23eccd6b5a8996dbf014f4e7cb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Jun 2019 14:04:43 -0700 Subject: [PATCH 0678/1899] Don't throw if failure is at index 0 --- merge_kokoro_logs.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/merge_kokoro_logs.js b/merge_kokoro_logs.js index 9b8e2d9b1..effd69935 100644 --- a/merge_kokoro_logs.js +++ b/merge_kokoro_logs.js @@ -64,13 +64,16 @@ readDir(rootDir + '/reports') )) ) .then((objects) => { - let merged = objects[0]; - merged.testsuites.testsuite = Array.prototype.concat.apply([], objects.map((obj) => { - if (obj) { - return obj.testsuites.testsuite; - } else { - return parseFailureLog; - }})); + const merged = { + testsuites: { + testsuite: Array.prototype.concat.apply([], objects.map((obj) => { + if (obj) { + return obj.testsuites.testsuite; + } else { + return parseFailureLog; + }})) + } + } let builder = new xml2js.Builder(); let xml = builder.buildObject(merged); let resultName = path.resolve(rootDir, 'reports', dirName, 'sponge_log.xml'); From ffe59e6edd0bee2f09c741d9dd81520816102dda Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 6 Jun 2019 09:33:40 -0400 Subject: [PATCH 0679/1899] grpc-js: fix lint This commit gets `npm run lint` passing again. --- packages/grpc-js/src/channel.ts | 4 ++-- packages/grpc-js/src/stream-decoder.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6e7d2cd1d..68ba66e90 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -329,8 +329,8 @@ export class Http2Channel extends EventEmitter implements Channel { stream: Http2CallStream, metadata: Metadata ) { - const connectMetadata: Promise = this.connect().then( - () => metadata.clone() + const connectMetadata: Promise = this.connect().then(() => + metadata.clone() ); const finalMetadata: Promise = stream.filterStack.sendMetadata( connectMetadata diff --git a/packages/grpc-js/src/stream-decoder.ts b/packages/grpc-js/src/stream-decoder.ts index 78803026b..671ad41ae 100644 --- a/packages/grpc-js/src/stream-decoder.ts +++ b/packages/grpc-js/src/stream-decoder.ts @@ -33,7 +33,7 @@ export class StreamDecoder { write(data: Buffer): Buffer[] { let readHead = 0; let toRead: number; - let result: Buffer[] = []; + const result: Buffer[] = []; while (readHead < data.length) { switch (this.readState) { From 31bcaed6e4d224c1c56a8bba6ebd4196026fc7aa Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 6 Jun 2019 09:39:46 -0400 Subject: [PATCH 0680/1899] grpc-js: destroy connections when session begins When the gRPC server has not been started, incoming connections can be destroyed on session establishment, which happens before a stream is created. --- packages/grpc-js/src/server.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 698e0db3f..6342b5e1e 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -284,11 +284,6 @@ export class Server { this.http2Server.on( 'stream', (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { - if (!this.started) { - stream.end(); - return; - } - const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; if ( @@ -351,6 +346,13 @@ export class Server { } } ); + + this.http2Server.on('session', session => { + if (!this.started) { + session.destroy(); + return; + } + }); } } From 9aeca2f01af3132c904f2098abc77839c45f6dbd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 6 Jun 2019 09:41:44 -0700 Subject: [PATCH 0681/1899] Pure JS: Fixed two bugs with goaway handling --- packages/grpc-js/src/call-stream.ts | 12 ++-- packages/grpc-js/src/subchannel.ts | 4 ++ test/api/connectivity_test.js | 99 +++++++++++++++++++++++++++++ 3 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 test/api/connectivity_test.js diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 6ddd4414b..5cbc8e34e 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -298,10 +298,10 @@ export class Http2CallStream extends Duplex implements Call { stream.on('end', () => { this.tryPush(null); }); - stream.on('close', async errorCode => { + stream.on('close', async () => { let code: Status; let details = ''; - switch (errorCode) { + switch (stream.rstCode) { case http2.constants.NGHTTP2_REFUSED_STREAM: code = Status.UNAVAILABLE; break; @@ -329,11 +329,9 @@ export class Http2CallStream extends Duplex implements Call { this.endCall({ code, details, metadata: new Metadata() }); }); stream.on('error', (err: Error) => { - this.endCall({ - code: Status.INTERNAL, - details: 'Internal HTTP2 error', - metadata: new Metadata(), - }); + /* We need an error handler here to stop "Uncaught Error" exceptions + * from bubbling up. However, errors here should all correspond to + * "close" events, where we will handle the error more granularly */ }); if (!this.pendingRead) { stream.pause(); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 80abf7812..ac681d9f2 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -78,6 +78,10 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { this.stopKeepalivePings(); this.emit('close'); }); + this.session.on('goaway', () => { + this.stopKeepalivePings(); + this.emit('close'); + }); this.userAgent = userAgent; if (channelArgs['grpc.keepalive_time_ms']) { diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js new file mode 100644 index 000000000..eb94e4121 --- /dev/null +++ b/test/api/connectivity_test.js @@ -0,0 +1,99 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const options = { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +}; +const path = require('path'); +const fs = require('fs'); +const assert = require('assert'); +const _ = require('lodash'); +const anyGrpc = require('../any_grpc'); +const clientGrpc = anyGrpc.client; +const serverGrpc = anyGrpc.server; +const protoLoader = require('../../packages/proto-loader', options); +const testServiceDef = protoLoader.loadSync(__dirname + '/../proto/test_service.proto'); +const TestService = serverGrpc.loadPackageDefinition(testServiceDef).TestService.service; +const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestService; + +const clientCreds = clientGrpc.credentials.createInsecure(); +const serverCreds = serverGrpc.ServerCredentials.createInsecure(); + +const serviceImpl = { + unary: function(call, cb) { + cb(null, {}); + }, + clientStream: function(stream, cb){ + stream.on('data', function(data) {}); + stream.on('end', function() { + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function(data) {}); + stream.on('end', function() { + stream.end(); + }); + } +}; + +describe('Reconnection', function() { + let server1; + let server2; + let port; + before(function() { + server1 = new serverGrpc.Server(); + server1.addService(TestService, serviceImpl); + server2 = new serverGrpc.Server(); + server2.addService(TestService, serviceImpl); + port = server1.bind('localhost:0', serverCreds); + server1.start(); + client = new TestServiceClient(`localhost:${port}`, clientCreds); + }); + after(function() { + server1.forceShutdown(); + server2.forceShutdown(); + }); + it('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { + client.unary({}, (err, data) => { + assert.ifError(err); + server1.tryShutdown(() => { + server2.bind(`localhost:${port}`, serverCreds); + server2.start(); + client.unary({}, (err, data) => { + assert.ifError(err); + clearInterval(callInterval); + done(); + }); + }); + let callInterval = setInterval(() => { + client.unary({}, (err, data) => { + if (err) { + assert.strictEqual(err.code, clientGrpc.status.UNAVAILABLE); + } + }); + }, 0); + }); + }); +}); \ No newline at end of file From 1ee218c8bd67a7961ec03d3101d5f4b1dcfa658d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 6 Jun 2019 10:38:28 -0700 Subject: [PATCH 0682/1899] Fix tests for fixed code, also fix another issue --- packages/grpc-js/src/call-stream.ts | 11 ++++++++++- packages/grpc-js/test/test-call-stream.ts | 3 ++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 5cbc8e34e..35b957b3d 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -130,7 +130,16 @@ export class Http2CallStream extends Duplex implements Call { private endCall(status: StatusObject): void { if (this.finalStatus === null) { this.finalStatus = status; - this.emit('status', status); + /* We do this asynchronously to ensure that no async function is in the + * call stack when we return control to the application. If an async + * function is in the call stack, any exception thrown by the application + * (or our tests) will bubble up and turn into promise rejection, which + * will result in an UnhandledPromiseRejectionWarning. Because that is + * a warning, the error will be effectively swallowed and execution will + * continue */ + process.nextTick(() => { + this.emit('status', status); + }); } } diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index a5f7908be..7903de768 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -196,7 +196,8 @@ describe('CallStream', () => { reject(e); } }); - http2Stream.emit('close', Number(key)); + http2Stream.rstCode = Number(key); + http2Stream.emit('close'); }); }); }); From 438bfdd8a2039046889f4fd00abb6aaa4cc68170 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Jun 2019 10:03:44 -0700 Subject: [PATCH 0683/1899] Update grpc-js to 0.4.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index dc544be71..bab300082 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.4.2", + "version": "0.4.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 1780d805dbd3001f0c1cd8e5b70d1b7f7cf46a74 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Jun 2019 13:31:04 -0700 Subject: [PATCH 0684/1899] Update grpc submodule to master --- packages/grpc-native-core/binding.gyp | 1 + packages/grpc-native-core/deps/grpc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 2ab645ce2..c0cd83a4d 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -1063,6 +1063,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 1e0ec4712..bb6a97b0c 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 1e0ec4712e198740db06eb77ff021e0534dc888a +Subproject commit bb6a97b0c8fc11a5c27b03e2058dc383bbfc1e64 From 001146febb4815a132edc600add36056c498cd89 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Jun 2019 13:36:40 -0700 Subject: [PATCH 0685/1899] Update grpc submodule to master --- packages/grpc-native-core/binding.gyp | 14 ++++++++++++-- packages/grpc-native-core/build.yaml | 1 - packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index f1fc3dd66..c27050242 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=0', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.20.3"' + 'GRPC_NODE_VERSION="1.22.0-dev"' ], 'defines!': [ 'OPENSSL_THREADS' @@ -569,7 +569,6 @@ ], 'sources': [ 'deps/grpc/src/core/lib/gpr/alloc.cc', - 'deps/grpc/src/core/lib/gpr/arena.cc', 'deps/grpc/src/core/lib/gpr/atm.cc', 'deps/grpc/src/core/lib/gpr/cpu_iphone.cc', 'deps/grpc/src/core/lib/gpr/cpu_linux.cc', @@ -602,7 +601,9 @@ 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', + 'deps/grpc/src/core/lib/gprpp/arena.cc', 'deps/grpc/src/core/lib/gprpp/fork.cc', + 'deps/grpc/src/core/lib/gprpp/global_config_env.cc', 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', @@ -638,6 +639,7 @@ 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', 'deps/grpc/src/core/lib/channel/status_util.cc', 'deps/grpc/src/core/lib/compression/compression.cc', + 'deps/grpc/src/core/lib/compression/compression_args.cc', 'deps/grpc/src/core/lib/compression/compression_internal.cc', 'deps/grpc/src/core/lib/compression/message_compress.cc', 'deps/grpc/src/core/lib/compression/stream_compression.cc', @@ -650,12 +652,15 @@ 'deps/grpc/src/core/lib/http/parser.cc', 'deps/grpc/src/core/lib/iomgr/buffer_list.cc', 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', + 'deps/grpc/src/core/lib/iomgr/cfstream_handle.cc', 'deps/grpc/src/core/lib/iomgr/combiner.cc', 'deps/grpc/src/core/lib/iomgr/endpoint.cc', + 'deps/grpc/src/core/lib/iomgr/endpoint_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_posix.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_uv.cc', 'deps/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc', 'deps/grpc/src/core/lib/iomgr/error.cc', + 'deps/grpc/src/core/lib/iomgr/error_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.cc', 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.cc', @@ -676,6 +681,7 @@ 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_internal.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_posix.cc', + 'deps/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_uv.cc', 'deps/grpc/src/core/lib/iomgr/iomgr_windows.cc', 'deps/grpc/src/core/lib/iomgr/is_epollexclusive_available.cc', @@ -704,6 +710,7 @@ 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.cc', 'deps/grpc/src/core/lib/iomgr/socket_windows.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client.cc', + 'deps/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_custom.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.cc', 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.cc', @@ -937,12 +944,15 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 74cb99d9d..49e36fdfe 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,2 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.20.3 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index cb0129702..bb6a97b0c 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit cb012970215b8c5141f4fdfdbe850006bd7994d6 +Subproject commit bb6a97b0c8fc11a5c27b03e2058dc383bbfc1e64 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9a1a22c75..ea3e05ed6 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.20.3", + "version": "1.22.0-dev", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From c3d7453a84cc2c42b743f92928af44269d4de542 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Sun, 9 Jun 2019 18:12:24 -0700 Subject: [PATCH 0686/1899] grpc-js: handle multiple messages in single 'data' event This commit adds support for receiving multiple messages in a single 'data' event from the underlying HTTP2 stream. It also handles potential out of order messages due to asynchronous deserialization of messages. --- packages/grpc-js/src/server-call.ts | 114 ++++++++++++++++++++++------ 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 47827d498..23d6b2470 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -117,6 +117,10 @@ export class ServerReadableStreamImpl } _read(size: number) { + if (!this.call.consumeUnpushedMessages(this)) { + return; + } + this.call.resume(); } @@ -324,6 +328,10 @@ export class Http2ServerCallStream< deadline: NodeJS.Timer = noopTimer; private wantTrailers = false; private metadataSent = false; + private canPush = false; + private isPushPending = false; + private bufferedMessages: Array = []; + private messagesToPush: Array = []; constructor( private stream: http2.ServerHttp2Stream, @@ -531,38 +539,98 @@ export class Http2ServerCallStream< ) { const decoder = new StreamDecoder(); - /* This code here is wrong but getting the client working is the priority - * right now and I'm not going to block that on fixing what is currently - * unused code. If multiple messages come in with a single frame, this will - * keep calling readable.push after it has returned false, which should not - * happen. Independent of that, deserializeMessage is asynchronous, which - * means that incoming messages could be reordered when emitted to the - * application. That effect will become more pronounced when compression - * support is added and deserializeMessage takes longer by an amount of - * time dependent on the size of the message. A system like the one in - * call-stream.ts should be added to buffer incoming messages and - * preserve ordering more strongly */ - this.stream.on('data', async (data: Buffer) => { const messages = decoder.write(data); - for (const message of messages) { - try { - const deserialized = await this.deserializeMessage(message); - if (!readable.push(deserialized)) { - this.stream.pause(); - } - } catch (err) { - err.code = Status.INTERNAL; - readable.emit('error', err); - } + for (const message of messages) { + this.pushOrBufferMessage(readable, message); } }); this.stream.once('end', () => { - readable.push(null); + this.pushOrBufferMessage(readable, null); }); } + + consumeUnpushedMessages( + readable: + | ServerReadableStream + | ServerDuplexStream + ): boolean { + this.canPush = true; + + while (this.messagesToPush.length > 0) { + const nextMessage = this.messagesToPush.shift(); + const canPush = readable.push(nextMessage); + + if (nextMessage === null || canPush === false) { + this.canPush = false; + break; + } + } + + return this.canPush; + } + + private pushOrBufferMessage( + readable: + | ServerReadableStream + | ServerDuplexStream, + messageBytes: Buffer | null + ): void { + if (this.isPushPending) { + this.bufferedMessages.push(messageBytes); + } else { + this.pushMessage(readable, messageBytes); + } + } + + private async pushMessage( + readable: + | ServerReadableStream + | ServerDuplexStream, + messageBytes: Buffer | null + ) { + if (messageBytes === null) { + if (this.canPush) { + readable.push(null); + } else { + this.messagesToPush.push(null); + } + + return; + } + + this.isPushPending = true; + + try { + const deserialized = await this.deserializeMessage(messageBytes); + + if (this.canPush) { + if (!readable.push(deserialized)) { + this.canPush = false; + this.stream.pause(); + } + } else { + this.messagesToPush.push(deserialized); + } + } catch (err) { + // Ignore any remaining messages when errors occur. + this.bufferedMessages.length = 0; + + err.code = Status.INTERNAL; + readable.emit('error', err); + } + + this.isPushPending = false; + + if (this.bufferedMessages.length > 0) { + this.pushMessage( + readable, + this.bufferedMessages.shift() as Buffer | null + ); + } + } } // tslint:disable:no-any From 66b3e4eb77242317b90d4ca074badad8e25d7092 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 12 Jun 2019 11:08:32 -0700 Subject: [PATCH 0687/1899] grpc-tools: Add option to generate package definition --- packages/grpc-tools/src/node_generator.cc | 37 +++++++++++++++-------- packages/grpc-tools/src/node_generator.h | 8 ++++- packages/grpc-tools/src/node_plugin.cc | 16 ++++++++-- 3 files changed, 46 insertions(+), 15 deletions(-) diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index aa4901145..720594701 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -178,11 +178,17 @@ void PrintMethod(const MethodDescriptor* method, Printer* out) { } // Prints out the service descriptor object -void PrintService(const ServiceDescriptor* service, Printer* out) { +void PrintService(const ServiceDescriptor* service, Printer* out, + const Parameters& params) { map template_vars; out->Print(GetNodeComments(service, true).c_str()); template_vars["name"] = service->name(); - out->Print(template_vars, "var $name$Service = exports.$name$Service = {\n"); + template_vars["full_name"] = service->full_name(); + if (params.generate_package_definition) { + out->Print(template_vars, "var $name$Service = exports['$full_name$'] = {\n"); + } else { + out->Print(template_vars, "var $name$Service = exports.$name$Service = {\n"); + } out->Indent(); for (int i = 0; i < service->method_count(); i++) { grpc::string method_name = @@ -195,14 +201,19 @@ void PrintService(const ServiceDescriptor* service, Printer* out) { } out->Outdent(); out->Print("};\n\n"); - out->Print(template_vars, - "exports.$name$Client = " - "grpc.makeGenericClientConstructor($name$Service);\n"); + if (!params.generate_package_definition) { + out->Print(template_vars, + "exports.$name$Client = " + "grpc.makeGenericClientConstructor($name$Service);\n"); + } out->Print(GetNodeComments(service, false).c_str()); } -void PrintImports(const FileDescriptor* file, Printer* out) { - out->Print("var grpc = require('grpc');\n"); +void PrintImports(const FileDescriptor* file, Printer* out, + const Parameters& params) { + if (!params.generate_package_definition) { + out->Print("var grpc = require('grpc');\n"); + } if (file->message_type_count() > 0) { grpc::string file_path = GetRelativePath(file->name(), GetJSMessageFilename(file->name())); @@ -230,14 +241,16 @@ void PrintTransformers(const FileDescriptor* file, Printer* out) { out->Print("\n"); } -void PrintServices(const FileDescriptor* file, Printer* out) { +void PrintServices(const FileDescriptor* file, Printer* out, + const Parameters& params) { for (int i = 0; i < file->service_count(); i++) { - PrintService(file->service(i), out); + PrintService(file->service(i), out, params); } } } // namespace -grpc::string GenerateFile(const FileDescriptor* file) { +grpc::string GenerateFile(const FileDescriptor* file, + const Parameters& params) { grpc::string output; { StringOutputStream output_stream(&output); @@ -257,11 +270,11 @@ grpc::string GenerateFile(const FileDescriptor* file) { out.Print("'use strict';\n"); - PrintImports(file, &out); + PrintImports(file, &out, params); PrintTransformers(file, &out); - PrintServices(file, &out); + PrintServices(file, &out, params); out.Print(GetNodeComments(file, false).c_str()); } diff --git a/packages/grpc-tools/src/node_generator.h b/packages/grpc-tools/src/node_generator.h index ce7b8a3f1..c73eca0c1 100644 --- a/packages/grpc-tools/src/node_generator.h +++ b/packages/grpc-tools/src/node_generator.h @@ -23,7 +23,13 @@ namespace grpc_node_generator { -grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file); +struct Parameters { + // Generate a package definition object instead of Client classes + bool generate_package_definition; +}; + +grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file, + const Parameters& params); } // namespace grpc_node_generator diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index 20e65e7fc..a502dca88 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -36,8 +36,20 @@ class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { const grpc::string& parameter, grpc::protobuf::compiler::GeneratorContext* context, grpc::string* error) const { - - grpc::string code = GenerateFile(file); + grpc_node_generator::Parameters generator_parameters; + generator_parameters.generate_package_definition = false; + if (!parameter.empty()) { + std::vector parameters_list = + grpc_generator::tokenize(parameter, ","); + for (auto parameter_string = parameters_list.begin(); + parameter_string != parameters_list.end(); parameter_string++) { + printf("%s", parameter_string); + if (*parameter_string == "generate_package_definition") { + generator_parameters.generate_package_definition = true; + } + } + } + grpc::string code = GenerateFile(file, generator_parameters); if (code.size() == 0) { return true; } From 8c3a49150e6c4c9e74770abfd02116ff227bf871 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 12 Jun 2019 11:36:58 -0700 Subject: [PATCH 0688/1899] Try to fix error reporting in log merging script again --- merge_kokoro_logs.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/merge_kokoro_logs.js b/merge_kokoro_logs.js index effd69935..93f4d9c89 100644 --- a/merge_kokoro_logs.js +++ b/merge_kokoro_logs.js @@ -37,11 +37,11 @@ const parseFailureLog = [ { $: { classname: 'Test Log Parsing', - name: 'Test Log Parsing', - failure: { - $: { - message: "Log parsing failed" - } + name: 'Test Log Parsing' + }, + failure: { + $: { + message: "Log parsing failed" } } } From 6b63ae9f1486e605e33cac1bfd0f771f6bd950b4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 13 Jun 2019 11:54:05 -0700 Subject: [PATCH 0689/1899] Update submodule again --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index bb6a97b0c..64ec7201f 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit bb6a97b0c8fc11a5c27b03e2058dc383bbfc1e64 +Subproject commit 64ec7201fd50c41a67ca3064833309f4e259cf06 From 1451abdd0f49a82b4f59f3e50bd1aa4fd626b516 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 13 Jun 2019 13:48:29 -0700 Subject: [PATCH 0690/1899] Disable test that doesn't work --- packages/grpc-native-core/test/resolver_test.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/resolver_test.js b/packages/grpc-native-core/test/resolver_test.js index ea6324ba7..86beccfd4 100644 --- a/packages/grpc-native-core/test/resolver_test.js +++ b/packages/grpc-native-core/test/resolver_test.js @@ -48,7 +48,10 @@ describe('Name resolver', function() { done(); }); }); - it('Should resolve a target to IPv6 addresses', function(done) { + /* This test doesn't work with the native resolver on Windows on our test + * machines because they don't have IPv6 addresses, so Windows omits IPv6 + * addresses from getaddrinfo results. */ + it.skip('Should resolve a target to IPv6 addresses', function(done) { const client = new grpc.Client(`loopback6.unittest.grpc.io:${port}`, insecureCreds); let deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); From b6fc55f5ea0a2390f33d581a9dfbc3d819ba1d07 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 13 Jun 2019 15:07:54 -0700 Subject: [PATCH 0691/1899] Update grpc-tools to 1.8.0 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index a3ab689fb..8f4947f3e 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.7.3", + "version": "1.8.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From f55b487c360caea932d819f5f7e8a41aa56195fb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 13 Jun 2019 15:50:17 -0700 Subject: [PATCH 0692/1899] Delete another directory in Windows build script --- packages/grpc-native-core/gulpfile.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/gulpfile.ts b/packages/grpc-native-core/gulpfile.ts index cfb601d0c..1d5c5ee2f 100644 --- a/packages/grpc-native-core/gulpfile.ts +++ b/packages/grpc-native-core/gulpfile.ts @@ -44,6 +44,7 @@ const installWindows = () => { return execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}).catch(() => del(path.resolve(process.env.USERPROFILE, '.node-gyp', process.versions.node, 'include/node/openssl'), { force: true }).then(() => +del(path.resolve(process.env.CSIDL_LOCAL_APPDATA, 'node-gyp/cache', process.versions.node, 'include/node/openssl'), { force: true })).then(() => execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}) )); From 0e47c1264765e492ea5039e73d3d2136d8aea22f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 13 Jun 2019 17:04:38 -0700 Subject: [PATCH 0693/1899] Make the same change in the other build script --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 7f862edc6..cd0c0f0eb 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -33,6 +33,8 @@ for %%a in (%arch_list%) do ( @rem Try again after removing openssl headers rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q + rmdir "%CSIDL_LOCAL_APPDATA%\node-gyp\cache\%%v\include\node\openssl" /S /Q + rmdir "%CSIDL_LOCAL_APPDATA%\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error From 7c5f2ce8264a826076b975c6353c4dd429e87990 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 14 Jun 2019 10:06:34 -0700 Subject: [PATCH 0694/1899] Echo commands to see what's going wrong --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index cd0c0f0eb..0d9df7835 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -26,6 +26,8 @@ call npm update || goto :error mkdir -p %ARTIFACTS_OUT% +@echo on + for %%a in (%arch_list%) do ( for %%v in (%node_versions%) do ( call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%%a From c55edf7107be2d0d1489d38e7a72181bdee0dbbe Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 17 Jun 2019 10:30:35 -0700 Subject: [PATCH 0695/1899] Use known-working environment variable --- packages/grpc-native-core/gulpfile.ts | 2 +- .../tools/run_tests/artifacts/build_artifact_node.bat | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/gulpfile.ts b/packages/grpc-native-core/gulpfile.ts index 1d5c5ee2f..dbfc2228d 100644 --- a/packages/grpc-native-core/gulpfile.ts +++ b/packages/grpc-native-core/gulpfile.ts @@ -44,7 +44,7 @@ const installWindows = () => { return execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}).catch(() => del(path.resolve(process.env.USERPROFILE, '.node-gyp', process.versions.node, 'include/node/openssl'), { force: true }).then(() => -del(path.resolve(process.env.CSIDL_LOCAL_APPDATA, 'node-gyp/cache', process.versions.node, 'include/node/openssl'), { force: true })).then(() => +del(path.resolve(process.env.USERPROFILE, 'AppData/node-gyp/cache', process.versions.node, 'include/node/openssl'), { force: true })).then(() => execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}) )); diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 0d9df7835..3a094f1e7 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -26,8 +26,6 @@ call npm update || goto :error mkdir -p %ARTIFACTS_OUT% -@echo on - for %%a in (%arch_list%) do ( for %%v in (%node_versions%) do ( call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%%a @@ -35,8 +33,8 @@ for %%a in (%arch_list%) do ( @rem Try again after removing openssl headers rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q - rmdir "%CSIDL_LOCAL_APPDATA%\node-gyp\cache\%%v\include\node\openssl" /S /Q - rmdir "%CSIDL_LOCAL_APPDATA%\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q + rmdir "%USERPROFILE%\AppData\node-gyp\cache\%%v\include\node\openssl" /S /Q + rmdir "%USERPROFILE%\AppData\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error From 58ce2779a1da14859877cae0ce6cb0c7347e2962 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 17 Jun 2019 14:06:02 -0700 Subject: [PATCH 0696/1899] Forgot the 'Local' directory component --- packages/grpc-native-core/gulpfile.ts | 2 +- .../tools/run_tests/artifacts/build_artifact_node.bat | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/gulpfile.ts b/packages/grpc-native-core/gulpfile.ts index dbfc2228d..6950f06d7 100644 --- a/packages/grpc-native-core/gulpfile.ts +++ b/packages/grpc-native-core/gulpfile.ts @@ -44,7 +44,7 @@ const installWindows = () => { return execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}).catch(() => del(path.resolve(process.env.USERPROFILE, '.node-gyp', process.versions.node, 'include/node/openssl'), { force: true }).then(() => -del(path.resolve(process.env.USERPROFILE, 'AppData/node-gyp/cache', process.versions.node, 'include/node/openssl'), { force: true })).then(() => +del(path.resolve(process.env.USERPROFILE, 'AppData/Local/node-gyp/cache', process.versions.node, 'include/node/openssl'), { force: true })).then(() => execa('npm', ['install', '--build-from-source'], {cwd: nativeCoreDir, stdio: 'inherit'}) )); diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 3a094f1e7..3dcb6c209 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -33,8 +33,8 @@ for %%a in (%arch_list%) do ( @rem Try again after removing openssl headers rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q - rmdir "%USERPROFILE%\AppData\node-gyp\cache\%%v\include\node\openssl" /S /Q - rmdir "%USERPROFILE%\AppData\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q + rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\%%v\include\node\openssl" /S /Q + rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error From b484cc286879beb58863d093607aba7b3b349842 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Jun 2019 10:07:03 -0700 Subject: [PATCH 0697/1899] Use older version of node-gyp --- tools/release/kokoro-nodejs.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/kokoro-nodejs.bat b/tools/release/kokoro-nodejs.bat index d73a592ab..e03d4d970 100644 --- a/tools/release/kokoro-nodejs.bat +++ b/tools/release/kokoro-nodejs.bat @@ -22,7 +22,7 @@ call nvm use 10 call npm install -g npm @rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp +call npm install -g node-gyp@4 cd /d %~dp0 cd ..\.. From 31d6f4362c1ba171f4a329187cd302605185842c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Jun 2019 10:24:40 -0700 Subject: [PATCH 0698/1899] Also use older node-gyp for electron builds --- tools/release/kokoro-electron.bat | 2 +- tools/release/kokoro-electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/release/kokoro-electron.bat b/tools/release/kokoro-electron.bat index 52e2fb1f6..1e0fb3da3 100644 --- a/tools/release/kokoro-electron.bat +++ b/tools/release/kokoro-electron.bat @@ -22,7 +22,7 @@ call nvm use 10 call npm install -g npm @rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp +call npm install -g node-gyp@4 cd /d %~dp0 cd ..\.. diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh index cfb9d153e..ade51215a 100755 --- a/tools/release/kokoro-electron.sh +++ b/tools/release/kokoro-electron.sh @@ -21,7 +21,7 @@ nvm install 10 nvm use 10 npm install -g npm # https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp +npm install -g node-gyp@4 set -ex cd $(dirname $0)/../.. From aed0706bf6a685091d647c48679b7b5cf0891bd9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 19 Jun 2019 09:41:08 -0700 Subject: [PATCH 0699/1899] Maybe node-gyp 3 will do it --- tools/release/kokoro-electron.bat | 2 +- tools/release/kokoro-electron.sh | 2 +- tools/release/kokoro-nodejs.bat | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/release/kokoro-electron.bat b/tools/release/kokoro-electron.bat index 1e0fb3da3..4bc1d0a21 100644 --- a/tools/release/kokoro-electron.bat +++ b/tools/release/kokoro-electron.bat @@ -22,7 +22,7 @@ call nvm use 10 call npm install -g npm @rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp@4 +call npm install -g node-gyp@3 cd /d %~dp0 cd ..\.. diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh index ade51215a..1305c1ae7 100755 --- a/tools/release/kokoro-electron.sh +++ b/tools/release/kokoro-electron.sh @@ -21,7 +21,7 @@ nvm install 10 nvm use 10 npm install -g npm # https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp@4 +npm install -g node-gyp@3 set -ex cd $(dirname $0)/../.. diff --git a/tools/release/kokoro-nodejs.bat b/tools/release/kokoro-nodejs.bat index e03d4d970..0655d2dfb 100644 --- a/tools/release/kokoro-nodejs.bat +++ b/tools/release/kokoro-nodejs.bat @@ -22,7 +22,7 @@ call nvm use 10 call npm install -g npm @rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp@4 +call npm install -g node-gyp@3 cd /d %~dp0 cd ..\.. From 863539c08e9d4fbb6974b17755abb3b4004bc4f6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 19 Jun 2019 15:16:33 -0700 Subject: [PATCH 0700/1899] Skip another test that seems to have trouble with the native resolver --- packages/grpc-native-core/test/resolver_test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/resolver_test.js b/packages/grpc-native-core/test/resolver_test.js index 86beccfd4..e9532857a 100644 --- a/packages/grpc-native-core/test/resolver_test.js +++ b/packages/grpc-native-core/test/resolver_test.js @@ -39,7 +39,8 @@ describe('Name resolver', function() { after(function() { server.forceShutdown(); }); - it('Should resolve a target to IPv4 addresses', function(done) { + // This test also seems to have problems with the native resolver on Windows + it.skip('Should resolve a target to IPv4 addresses', function(done) { const client = new grpc.Client(`loopback4.unittest.grpc.io:${port}`, insecureCreds); let deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); From d18256d25c1aff4d1d19f3b3d934078c0b692b0a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 19 Jun 2019 17:13:32 -0700 Subject: [PATCH 0701/1899] Bump to 1.22.0-pre1 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 11ecbf7f5..06fcb76eb 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -94,7 +94,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.22.0-dev"', + 'GRPC_NODE_VERSION="1.22.0-pre1"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 64ec7201f..35230ef8c 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 64ec7201fd50c41a67ca3064833309f4e259cf06 +Subproject commit 35230ef8cd70d62ab94bee661b7cd641adfa805b diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ea3e05ed6..870f40567 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.22.0-dev", + "version": "1.22.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From c6c7190700976130676cd78e157d0ce0b683e96c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Jun 2019 11:13:44 -0700 Subject: [PATCH 0702/1899] Disable another test --- packages/grpc-native-core/test/resolver_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/test/resolver_test.js b/packages/grpc-native-core/test/resolver_test.js index e9532857a..83a320630 100644 --- a/packages/grpc-native-core/test/resolver_test.js +++ b/packages/grpc-native-core/test/resolver_test.js @@ -61,7 +61,7 @@ describe('Name resolver', function() { done(); }); }); - it('Should resolve a target to IPv4 and IPv6 addresses', function(done) { + it.skip('Should resolve a target to IPv4 and IPv6 addresses', function(done) { const client = new grpc.Client(`loopback46.unittest.grpc.io:${port}`, insecureCreds); let deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 1); From eb3c479e367d3de5eef5b0b0af749feb4d663654 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 24 Jun 2019 12:56:27 -0700 Subject: [PATCH 0703/1899] Connectivity test: ensure all calls end before ending the test --- test/api/connectivity_test.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index eb94e4121..2d5280a32 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -76,6 +76,13 @@ describe('Reconnection', function() { server2.forceShutdown(); }); it('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { + let pendingCalls = 0; + let testDone = false; + function maybeDone() { + if (testDone && pendingCalls == 0) { + done(); + } + }; client.unary({}, (err, data) => { assert.ifError(err); server1.tryShutdown(() => { @@ -84,14 +91,18 @@ describe('Reconnection', function() { client.unary({}, (err, data) => { assert.ifError(err); clearInterval(callInterval); - done(); + testDone = true; + maybeDone(); }); }); let callInterval = setInterval(() => { + pendingCalls += 1; client.unary({}, (err, data) => { + pendingCalls -= 1; if (err) { assert.strictEqual(err.code, clientGrpc.status.UNAVAILABLE); } + maybeDone(); }); }, 0); }); From fbdeae23ead10d3d1e28bd81180feb70c01cfd7c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 24 Jun 2019 13:17:03 -0700 Subject: [PATCH 0704/1899] Use triple equals --- test/api/connectivity_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 2d5280a32..4051777a2 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -79,7 +79,7 @@ describe('Reconnection', function() { let pendingCalls = 0; let testDone = false; function maybeDone() { - if (testDone && pendingCalls == 0) { + if (testDone && pendingCalls === 0) { done(); } }; From 0b4fd1365a57f93eedf4284bbea513fa2e49777f Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 20 Jun 2019 14:30:42 -0400 Subject: [PATCH 0705/1899] grpc-js: expose Server implementation publicly This commit exposes the pure JS Server as public API. --- packages/grpc-js/src/index.ts | 6 ++---- packages/grpc-js/test/test-server-deadlines.ts | 3 +-- packages/grpc-js/test/test-server-errors.ts | 2 +- packages/grpc-js/test/test-server.ts | 3 +-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e49cfb5d7..d846b6c06 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -38,6 +38,7 @@ import { Serialize, } from './make-client'; import { Metadata } from './metadata'; +import { Server } from './server'; import { KeyCertPair, ServerCredentials } from './server-credentials'; import { StatusBuilder } from './status-builder'; @@ -259,10 +260,7 @@ export const setLogVerbosity = (verbosity: LogVerbosity): void => { logging.setLoggerVerbosity(verbosity); }; -export const Server = (options: any) => { - throw new Error('Not yet implemented'); -}; - +export { Server }; export { ServerCredentials }; export { KeyCertPair }; diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts index ef54ef3fb..2a1d3df93 100644 --- a/packages/grpc-js/test/test-server-deadlines.ts +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -21,10 +21,9 @@ import * as assert from 'assert'; import * as path from 'path'; import * as grpc from '../src'; -import { ServerCredentials } from '../src'; +import { Server, ServerCredentials } from '../src'; import { ServiceError } from '../src/call'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; -import { Server } from '../src/server'; import { sendUnaryData, ServerUnaryCall, diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 6faf19ea0..d429330de 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -21,9 +21,9 @@ import * as assert from 'assert'; import { join } from 'path'; import * as grpc from '../src'; +import { Server } from '../src'; import { ServiceError } from '../src/call'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; -import { Server } from '../src/server'; import { sendUnaryData, ServerDuplexStream, diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index fb59739c5..09259481f 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -23,10 +23,9 @@ import * as http2 from 'http2'; import * as path from 'path'; import * as grpc from '../src'; -import { ServerCredentials } from '../src'; +import { Server, ServerCredentials } from '../src'; import { ServiceError } from '../src/call'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; -import { Server } from '../src/server'; import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; import { loadProtoFile } from './common'; From 4399131bf933f4e4a0b3b7d2c24ec6e1773db238 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 20 Jun 2019 14:32:56 -0400 Subject: [PATCH 0706/1899] grpc-js: fix lint This commit makes the linter pass again. --- packages/grpc-js/src/compression-filter.ts | 4 +--- packages/grpc-js/test/test-call-stream.ts | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index f28568e7c..ff2dcbeb2 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -138,9 +138,7 @@ class UnknownHandler extends CompressionHandler { compressMessage(message: Buffer): Promise { return Promise.reject( new Error( - `Received message compressed wth unsupported compression method ${ - this.compressionName - }` + `Received message compressed wth unsupported compression method ${this.compressionName}` ) ); } diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index 7903de768..a85366c78 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -269,9 +269,7 @@ describe('CallStream', () => { frameLengths: range(0, 20).map(() => 1), }, ].forEach((testCase: { description: string; frameLengths: number[] }) => { - it(`should handle a short message where ${ - testCase.description - }`, done => { + it(`should handle a short message where ${testCase.description}`, done => { const callStream = new Http2CallStream( 'foo', {} as Http2Channel, From 22b258bc4ef07f16edc07bbd4c53b0947f71ed64 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Thu, 20 Jun 2019 14:40:19 -0400 Subject: [PATCH 0707/1899] test: enable grpc-js Server interop testing This commit enables interop testing with the grpc-js Server. --- test/gulpfile.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/gulpfile.ts b/test/gulpfile.ts index f5762d3cd..be18c5fab 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -56,8 +56,8 @@ const test = () => { runTestsArgPairs = [ ['native', 'native'], ['native', 'js'], - // ['js', 'native'], - // ['js', 'js'] + ['js', 'native'], + ['js', 'js'] ]; } else { runTestsArgPairs = [ @@ -73,4 +73,4 @@ export { install, cleanAll, test -}; \ No newline at end of file +}; From 0a306fa9831cdb81bb2557de6381086ee898ca1e Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 21 Jun 2019 12:08:35 -0400 Subject: [PATCH 0708/1899] test: move interop tests from bind() to bindAsync() This commit migrates the interop tests from bind() to bindAsync() in order to support the pure JavaScript server, which cannot implement a synchronous bind(). --- test/api/connectivity_test.js | 31 +++++++++++++++---------- test/api/error_test.js | 34 ++++++++++++++++++---------- test/api/interop_helper/server.js | 15 +++++++----- test/api/metadata_test.js | 14 +++++++----- test/interop/interop_server.js | 24 +++++++++++++------- test/performance/benchmark_server.js | 17 ++++++++++---- test/performance/worker.js | 20 +++++++++++----- 7 files changed, 100 insertions(+), 55 deletions(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 4051777a2..a3cd383b5 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -62,14 +62,18 @@ describe('Reconnection', function() { let server1; let server2; let port; - before(function() { + before(function(done) { server1 = new serverGrpc.Server(); server1.addService(TestService, serviceImpl); server2 = new serverGrpc.Server(); server2.addService(TestService, serviceImpl); - port = server1.bind('localhost:0', serverCreds); - server1.start(); - client = new TestServiceClient(`localhost:${port}`, clientCreds); + server1.bindAsync('localhost:0', serverCreds, (err, _port) => { + assert.ifError(err); + server1.start(); + port = _port; + client = new TestServiceClient(`localhost:${port}`, clientCreds); + done(); + }); }); after(function() { server1.forceShutdown(); @@ -78,6 +82,7 @@ describe('Reconnection', function() { it('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { let pendingCalls = 0; let testDone = false; + let callInterval; function maybeDone() { if (testDone && pendingCalls === 0) { done(); @@ -86,16 +91,18 @@ describe('Reconnection', function() { client.unary({}, (err, data) => { assert.ifError(err); server1.tryShutdown(() => { - server2.bind(`localhost:${port}`, serverCreds); - server2.start(); - client.unary({}, (err, data) => { + server2.bindAsync(`localhost:${port}`, serverCreds, (err) => { assert.ifError(err); - clearInterval(callInterval); - testDone = true; - maybeDone(); + server2.start(); + client.unary({}, (err, data) => { + assert.ifError(err); + clearInterval(callInterval); + testDone = true; + maybeDone(); + }); }); }); - let callInterval = setInterval(() => { + callInterval = setInterval(() => { pendingCalls += 1; client.unary({}, (err, data) => { pendingCalls -= 1; @@ -107,4 +114,4 @@ describe('Reconnection', function() { }, 0); }); }); -}); \ No newline at end of file +}); diff --git a/test/api/error_test.js b/test/api/error_test.js index 33965eee4..8c07c6627 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -37,7 +37,7 @@ describe('Client malformed response handling', function() { var server; var client; var badArg = Buffer.from([0xFF]); - before(function() { + before(function(done) { var malformed_test_service = { unary: { path: '/TestService/Unary', @@ -93,9 +93,12 @@ describe('Client malformed response handling', function() { }); } }); - var port = server.bind('localhost:0', serverInsecureCreds); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + done(); + }); }); after(function() { server.forceShutdown(); @@ -141,7 +144,7 @@ describe('Client malformed response handling', function() { } var client; var server; - before(function() { + before(function(done) { var malformed_test_service = { unary: { path: '/TestService/Unary', @@ -197,9 +200,12 @@ describe('Client malformed response handling', function() { }); } }); - var port = server.bind('localhost:0', serverInsecureCreds); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + done(); + }); }); after(function() { server.forceShutdown(); @@ -244,7 +250,7 @@ describe('Client malformed response handling', function() { var client; var server; var port; - before(function() { + before(function(done) { server = new serverGrpc.Server(); var trailer_metadata = new serverGrpc.Metadata(); trailer_metadata.add('trailer-present', 'yes'); @@ -323,9 +329,13 @@ describe('Client malformed response handling', function() { }); } }); - port = server.bind('localhost:0', serverInsecureCreds); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); + server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { + assert.ifError(err); + port = _port; + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + done(); + }); }); after(function() { server.forceShutdown(); diff --git a/test/api/interop_helper/server.js b/test/api/interop_helper/server.js index 7d6536a18..984aa8968 100644 --- a/test/api/interop_helper/server.js +++ b/test/api/interop_helper/server.js @@ -18,12 +18,15 @@ 'use strict'; +const assert = require('assert'); const interopServer = require('../../interop/interop_server.js'); -const serverObj = interopServer.getServer(0, true); -serverObj.server.start(); -process.send({port: serverObj.port}); -// The only message from the driver should be to stop the server -process.on('message', (message) => { - serverObj.server.forceShutdown(); +interopServer.getServer(0, true, (err, serverObj) => { + assert.ifError(err); + serverObj.server.start(); + process.send({port: serverObj.port}); + // The only message from the driver should be to stop the server + process.on('message', (message) => { + serverObj.server.forceShutdown(); + }); }); diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js index 3499ebcd6..16d7216bc 100644 --- a/test/api/metadata_test.js +++ b/test/api/metadata_test.js @@ -58,8 +58,7 @@ const clientOptions = { describe('Sending metadata', function() { let server; - let port; - before(function() { + before(function(done) { server = new serverGrpc.Server(); server.addService(TestService, { unary: function(call, cb) { @@ -81,9 +80,12 @@ describe('Sending metadata', function() { }); } }); - port = server.bind('localhost:0', serverCreds); - server.start(); - client = new TestServiceClient(`localhost:${port}`, combinedClientCreds, clientOptions); + server.bindAsync('localhost:0', serverCreds, (err, port) => { + assert.ifError(err); + server.start(); + client = new TestServiceClient(`localhost:${port}`, combinedClientCreds, clientOptions); + done(); + }); }); after(function() { server.forceShutdown(); @@ -98,4 +100,4 @@ describe('Sending metadata', function() { }); }); }); -}); \ No newline at end of file +}); diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index a924f20b9..1f00af205 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -18,6 +18,7 @@ 'use strict'; +var assert = require('assert'); var fs = require('fs'); var path = require('path'); var _ = require('lodash'); @@ -199,10 +200,10 @@ function handleHalfDuplex(call) { * Get a server object bound to the given port * @param {string} port Port to which to bind * @param {boolean} tls Indicates that the bound port should use TLS - * @return {{server: Server, port: number}} Server object bound to the support, - * and port number that the server is bound to + * @param {function(Error, {{server: Server, port: number}})} callback Callback + * to call with result or error */ -function getServer(port, tls) { +function getServer(port, tls, callback) { // TODO(mlumish): enable TLS functionality var options = {}; var server_creds; @@ -227,8 +228,13 @@ function getServer(port, tls) { fullDuplexCall: handleFullDuplex, halfDuplexCall: handleHalfDuplex }); - var port_num = server.bind('0.0.0.0:' + port, server_creds); - return {server: server, port: port_num}; + server.bindAsync('0.0.0.0:' + port, server_creds, (err, port_num) => { + if (err) { + return callback(err); + } + + callback(null, {server: server, port: port_num}); + }); } if (require.main === module) { @@ -236,9 +242,11 @@ if (require.main === module) { var argv = parseArgs(process.argv, { string: ['port', 'use_tls'] }); - var server_obj = getServer(argv.port, argv.use_tls === 'true'); - console.log('Server attaching to port ' + argv.port); - server_obj.server.start(); + getServer(argv.port, argv.use_tls === 'true', (err, server_obj) => { + assert.ifError(err); + console.log('Server attaching to port ' + argv.port); + server_obj.server.start(); + }); } /** diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index 3b5ef625e..013f81819 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -23,6 +23,7 @@ 'use strict'; +var assert = require('assert'); var fs = require('fs'); var path = require('path'); var EventEmitter = require('events'); @@ -129,7 +130,7 @@ function BenchmarkServer(host, port, tls, generic, response_size) { }; var server = new grpc.Server(options); - this.port = server.bind(host + ':' + port, server_creds); + if (generic) { server.addService(genericService, { unaryCall: makeUnaryGenericCall(response_size), @@ -142,6 +143,9 @@ function BenchmarkServer(host, port, tls, generic, response_size) { }); } this.server = server; + this.host = host; + this.port = port; + this.creds = server_creds; } util.inherits(BenchmarkServer, EventEmitter); @@ -150,10 +154,13 @@ util.inherits(BenchmarkServer, EventEmitter); * Start the benchmark server. */ BenchmarkServer.prototype.start = function() { - this.server.start(); - this.last_wall_time = process.hrtime(); - this.last_usage = process.cpuUsage(); - this.emit('started'); + this.server.bindAsync(this.host + ':' + this.port, this.creds, (err) => { + assert.ifError(err); + this.server.start(); + this.last_wall_time = process.hrtime(); + this.last_usage = process.cpuUsage(); + this.emit('started'); + }); }; /** diff --git a/test/performance/worker.js b/test/performance/worker.js index 2376ef52d..df1fb05a0 100644 --- a/test/performance/worker.js +++ b/test/performance/worker.js @@ -18,6 +18,7 @@ 'use strict'; +var assert = require('assert'); var console = require('console'); var WorkerServiceImpl = require('./worker_service_impl'); @@ -32,16 +33,21 @@ var protoPackage = protoLoader.loadSync( includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; -function runServer(port, benchmark_impl) { +function runServer(port, benchmark_impl, callback) { var server_creds = grpc.ServerCredentials.createInsecure(); var server = new grpc.Server(); server.addService(serviceProto.WorkerService.service, new WorkerServiceImpl(benchmark_impl, server)); var address = '0.0.0.0:' + port; - server.bind(address, server_creds); - server.start(); - console.log('running QPS worker on %s', address); - return server; + server.bindAsync(address, server_creds, (err) => { + if (err) { + return callback(err); + } + + server.start(); + console.log('running QPS worker on %s', address); + callback(null, server); + }); } if (require.main === module) { @@ -50,7 +56,9 @@ if (require.main === module) { var argv = parseArgs(process.argv, { string: ['driver_port', 'benchmark_impl'] }); - runServer(argv.driver_port, argv.benchmark_impl); + runServer(argv.driver_port, argv.benchmark_impl, (err, server) => { + assert.ifError(err); + }); } exports.runServer = runServer; From 00b091a1b1dfb16d9ac22bab718bf80bc4ebf299 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 21 Jun 2019 15:05:58 -0400 Subject: [PATCH 0709/1899] grpc-js: shutdown improvements This commit maintains a Set of all active sessions. This allows tryShutdown() to gracefully stop the server properly (as recommended in the Node HTTP2 documentation). The same Set of sessions also allows forceShutdown() to be implemented. --- packages/grpc-js/src/server.ts | 51 +++++++++++++++++---- packages/grpc-js/test/test-server-errors.ts | 4 +- packages/grpc-js/test/test-server.ts | 15 ------ 3 files changed, 45 insertions(+), 25 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 6342b5e1e..0d92881b2 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -91,6 +91,7 @@ export class Server { string, UntypedHandler >(); + private sessions = new Set(); private started = false; constructor(options?: object) {} @@ -223,7 +224,22 @@ export class Server { } forceShutdown(): void { - throw new Error('Not yet implemented'); + // Close the server if it is still running. + if (this.http2Server && this.http2Server.listening) { + this.http2Server.close(); + } + + this.started = false; + + // Always destroy any available sessions. It's possible that one or more + // tryShutdown() calls are in progress. Don't wait on them to finish. + this.sessions.forEach(session => { + // Cast NGHTTP2_CANCEL to any because TypeScript doesn't seem to + // recognize destroy(code) as a valid signature. + // tslint:disable-next-line:no-any + session.destroy(http2.constants.NGHTTP2_CANCEL as any); + }); + this.sessions.clear(); } register( @@ -259,17 +275,34 @@ export class Server { } tryShutdown(callback: (error?: Error) => void): void { - callback = typeof callback === 'function' ? callback : noop; + let pendingChecks = 0; - if (this.http2Server === null) { - callback(new Error('server is not running')); - return; + function maybeCallback(): void { + pendingChecks--; + + if (pendingChecks === 0) { + callback(); + } + } + + // Close the server if necessary. + this.started = false; + + if (this.http2Server && this.http2Server.listening) { + pendingChecks++; + this.http2Server.close(maybeCallback); } - this.http2Server.close((err?: Error) => { - this.started = false; - callback(err); + // If any sessions are active, close them gracefully. + pendingChecks += this.sessions.size; + this.sessions.forEach(session => { + session.close(maybeCallback); }); + + // If the server is closed and there are no active sessions, just call back. + if (pendingChecks === 0) { + callback(); + } } addHttp2Port(): void { @@ -352,6 +385,8 @@ export class Server { session.destroy(); return; } + + this.sessions.add(session); }); } } diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index d429330de..ffabaac50 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -386,9 +386,9 @@ describe('Other conditions', () => { }); }); - after(done => { + after(() => { client.close(); - server.tryShutdown(done); + server.forceShutdown(); }); describe('Server receiving bad input', () => { diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 09259481f..3e02c3d5f 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -127,17 +127,6 @@ describe('Server', () => { }); }); - describe('tryShutdown', () => { - it('calls back with an error if the server is not running', done => { - const server = new Server(); - - server.tryShutdown(err => { - assert(err !== undefined && err.message === 'server is not running'); - done(); - }); - }); - }); - describe('start', () => { let server: Server; @@ -237,10 +226,6 @@ describe('Server', () => { server.addProtoService(); }, /Not implemented. Use addService\(\) instead/); - assert.throws(() => { - server.forceShutdown(); - }, /Not yet implemented/); - assert.throws(() => { server.addHttp2Port(); }, /Not yet implemented/); From 7c2bb2a237eb25eb13f4aefbdc03a53ca2031236 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Fri, 21 Jun 2019 19:34:45 -0400 Subject: [PATCH 0710/1899] grpc-js: don't overwrite existing error codes This commit causes RPC handlers to default to INTERNAL when an error occurs, but does not overwrite an existing error code. --- packages/grpc-js/src/server.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 0d92881b2..e6d176195 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -374,7 +374,11 @@ export class Server { } } catch (err) { const call = new Http2ServerCallStream(stream, null!); - err.code = Status.INTERNAL; + + if (err.code === undefined) { + err.code = Status.INTERNAL; + } + call.sendError(err); } } From e9946c3f6cc38e73c9c5585816e5856634798294 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Tue, 25 Jun 2019 19:39:45 -0400 Subject: [PATCH 0711/1899] test: make connctivity test more robust The key change here is forcing the final unary call to wait for the server to be ready. The native client was making the RPC, but didn't appear to have a valid connection at the time. --- test/api/connectivity_test.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index a3cd383b5..88d11a0c9 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -76,10 +76,12 @@ describe('Reconnection', function() { }); }); after(function() { + client.close(); server1.forceShutdown(); server2.forceShutdown(); }); it('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { + this.timeout(10000); let pendingCalls = 0; let testDone = false; let callInterval; @@ -94,7 +96,8 @@ describe('Reconnection', function() { server2.bindAsync(`localhost:${port}`, serverCreds, (err) => { assert.ifError(err); server2.start(); - client.unary({}, (err, data) => { + const metadata = new clientGrpc.Metadata({ waitForReady: true }); + client.unary({}, metadata, (err, data) => { assert.ifError(err); clearInterval(callInterval); testDone = true; @@ -103,6 +106,7 @@ describe('Reconnection', function() { }); }); callInterval = setInterval(() => { + assert.strictEqual(testDone, false); pendingCalls += 1; client.unary({}, (err, data) => { pendingCalls -= 1; From 68fbffa47406e1afe08397d0de8af42654985112 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 26 Jun 2019 16:22:01 -0700 Subject: [PATCH 0712/1899] Skip connectivity test to narrow down failures --- test/api/connectivity_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 88d11a0c9..622c96d7c 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -80,7 +80,7 @@ describe('Reconnection', function() { server1.forceShutdown(); server2.forceShutdown(); }); - it('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { + it.skip('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { this.timeout(10000); let pendingCalls = 0; let testDone = false; From e6a8092a6314123b1ccb7ab365852390a42afce6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 27 Jun 2019 11:35:07 -0700 Subject: [PATCH 0713/1899] Bump grpc-js to 0.5.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index bab300082..3ff6ec73c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.4.3", + "version": "0.5.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 69f97495ac19bb3b0f4274b309883735fd62ff20 Mon Sep 17 00:00:00 2001 From: Cosmin Lehene Date: Tue, 2 Jul 2019 14:39:49 -0700 Subject: [PATCH 0714/1899] Fix Channel argument validation error messages --- packages/grpc-native-core/ext/channel.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc index 14293abdc..fa7f84192 100644 --- a/packages/grpc-native-core/ext/channel.cc +++ b/packages/grpc-native-core/ext/channel.cc @@ -207,7 +207,7 @@ NAN_METHOD(Channel::New) { if (info.IsConstructCall()) { if (!info[0]->IsString()) { return Nan::ThrowTypeError( - "Channel expects a string, a credential and an object"); + "Channel's first argument (address) must be a string"); } grpc_channel *wrapped_channel; // Owned by the Channel object @@ -215,7 +215,7 @@ NAN_METHOD(Channel::New) { grpc_channel_credentials *creds; if (!ChannelCredentials::HasInstance(info[1])) { return Nan::ThrowTypeError( - "Channel's second argument must be a ChannelCredentials"); + "Channel's second argument (credentials) must be a ChannelCredentials"); } ChannelCredentials *creds_object = ObjectWrap::Unwrap( Nan::To(info[1]).ToLocalChecked()); @@ -224,7 +224,7 @@ NAN_METHOD(Channel::New) { if (!ParseChannelArgs(info[2], &channel_args_ptr)) { DeallocateChannelArgs(channel_args_ptr); return Nan::ThrowTypeError( - "Channel options must be an object with " + "Channel third argument (options) must be an object with " "string keys and integer or string values"); } if (creds == NULL) { From ec91a169707296179dcad8bcbc653cd10a6dbd18 Mon Sep 17 00:00:00 2001 From: Julien Isorce Date: Sat, 6 Jul 2019 14:07:31 -0700 Subject: [PATCH 0715/1899] Build Electron 4.2 artifacts 4.0 and 4.1 were there but not 4.2 https://github.com/grpc/grpc-node/issues/937 --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 95ca024d7..89e387300 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 5.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index 6eb650148..72c9b36f7 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 5.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 ) umask 022 From 986979bda9e4411dbb08e8a9cb4a3533ebf9276a Mon Sep 17 00:00:00 2001 From: Mike Ajala <10845154+agmt5989@users.noreply.github.com> Date: Sun, 7 Jul 2019 23:59:49 +0100 Subject: [PATCH 0716/1899] Updated README.md Corrected a few typos and semantics in the readme file. --- packages/grpc-native-core/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index 1dd78c8ce..f9b6bc1ae 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -28,7 +28,7 @@ The `--build-from-source` option will work even when installing another package The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC. Please note that there's not just one way to get native extensions running in electron, and that there's never any silver bullet for anything. The following instructions try to cater about some of the most generic ways, but different edge cases might require different methodologies. -The best to get gRPC to work with electron is to do this, possibly in your `postinstall` script of your `package.json` file: +The best way to get gRPC to work with electron is to do this, possibly in the `postinstall` script of your `package.json` file: ``` npm rebuild --target=2.0.0 --runtime=electron --dist-url=https://atom.io/download/electron From aa54122e51ec57b03baadc0695557c542913f71b Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Mon, 8 Jul 2019 20:15:57 +0200 Subject: [PATCH 0717/1899] fix: properly handle http error status codes fix #941 --- packages/grpc-js/src/call-stream.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 35b957b3d..2f2c35b01 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -243,24 +243,24 @@ export class Http2CallStream extends Duplex implements Call { } else { this.http2Stream = stream; stream.on('response', (headers, flags) => { - switch (headers[HTTP2_HEADER_STATUS]) { + switch (headers[':status']) { // TODO(murgatroid99): handle 100 and 101 - case '400': + case 400: this.mappedStatusCode = Status.INTERNAL; break; - case '401': + case 401: this.mappedStatusCode = Status.UNAUTHENTICATED; break; - case '403': + case 403: this.mappedStatusCode = Status.PERMISSION_DENIED; break; - case '404': + case 404: this.mappedStatusCode = Status.UNIMPLEMENTED; break; - case '429': - case '502': - case '503': - case '504': + case 429: + case 502: + case 503: + case 504: this.mappedStatusCode = Status.UNAVAILABLE; break; default: From 3f460716fba3ba37e7acc50c52676c6714ca9138 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 9 Jul 2019 10:52:51 -0700 Subject: [PATCH 0718/1899] Remove check in grpc-js that doesn't appear in grpc --- packages/grpc-js/src/client.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 5b243c383..a092e61d4 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -139,11 +139,6 @@ export class Client { ); } }); - call.on('end', () => { - if (responseMessage == null) { - call.cancelWithStatus(Status.INTERNAL, 'Not enough responses received'); - } - }); call.on('status', (status: StatusObject) => { /* We assume that call emits status after it emits end, and that it * accounts for any cancelWithStatus calls up until it emits status. From 26e30ab136d8ec00106fd8d67844e5df651a4df8 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Tue, 9 Jul 2019 12:39:06 -0700 Subject: [PATCH 0719/1899] Fix 'noImplicitAny' issue with declaration file. The latest release of grpc-node cannot be used in a typescript project that uses -noImplicitAny. This is due to a signature being added without a specified return type. This causes the return type to implicitly be 'any' which TS explicitly disallows. For projects that use strict flags to catch lots of bugs, this prevents usage of this version of grpc entirely. --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 841da737f..718f6bdb4 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -579,7 +579,7 @@ declare module "grpc" { * These options only have any effect when passed at the beginning of * a client request. */ - setOptions(options: MetadataOptions); + setOptions(options: MetadataOptions): void; } export type MetadataValue = string | Buffer; From d223cc394e8eb8064b98bb92601d2a714888f9d5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 9 Jul 2019 15:30:29 -0700 Subject: [PATCH 0720/1899] Bump grpc-js to 0.5.1 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3ff6ec73c..0f10c8f4d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.5.0", + "version": "0.5.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 5b87ceb05c9b2251f271a81a49dd8afa2161598d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 11 Jul 2019 14:30:22 -0700 Subject: [PATCH 0721/1899] Warn instead of failing when constructing metadata from remote end --- packages/grpc-js/src/metadata.ts | 41 ++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index d321b9b0e..72bb70726 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -62,7 +62,7 @@ function validate(key: string, value?: MetadataValue): void { } } -interface MetadataOptions { +export interface MetadataOptions { /* Signal that the request is idempotent. Defaults to false */ idempotentRequest?: boolean; /* Signal that the call should not return UNAVAILABLE before it has @@ -240,24 +240,29 @@ export class Metadata { const values = headers[key]; - if (isBinaryKey(key)) { - if (Array.isArray(values)) { - values.forEach(value => { - result.add(key, Buffer.from(value, 'base64')); - }); - } else if (values !== undefined) { - values.split(',').forEach(v => { - result.add(key, Buffer.from(v.trim(), 'base64')); - }); - } - } else { - if (Array.isArray(values)) { - values.forEach(value => { - result.add(key, value); - }); - } else if (values !== undefined) { - values.split(',').forEach(v => result.add(key, v.trim())); + try { + if (isBinaryKey(key)) { + if (Array.isArray(values)) { + values.forEach(value => { + result.add(key, Buffer.from(value, 'base64')); + }); + } else if (values !== undefined) { + values.split(',').forEach(v => { + result.add(key, Buffer.from(v.trim(), 'base64')); + }); + } + } else { + if (Array.isArray(values)) { + values.forEach(value => { + result.add(key, value); + }); + } else if (values !== undefined) { + values.split(',').forEach(v => result.add(key, v.trim())); + } } + } catch (error) { + error.message = `Failed to add metadata entry ${key}: ${values}. ${error.message}`; + process.emitWarning(error); } }); return result; From 4818d304c9af04995199b3aa742a943979c27cb1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 11 Jul 2019 16:46:53 -0700 Subject: [PATCH 0722/1899] Bump grpc-js to 0.5.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0f10c8f4d..ff18d374e 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.5.1", + "version": "0.5.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 277d9892f894822f486154bd5b456460a20facea Mon Sep 17 00:00:00 2001 From: Bjorn Stromberg Date: Fri, 12 Jul 2019 10:50:50 +0900 Subject: [PATCH 0723/1899] Add @types/semver as devDependency --- packages/grpc-js/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ff18d374e..88978f0a4 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -19,6 +19,7 @@ "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", "@types/node": "^12.0.2", + "@types/semver": "^6.0.1", "clang-format": "^1.0.55", "gts": "^1.0.0", "lodash": "^4.17.4", @@ -43,7 +44,7 @@ "posttest": "npm run check" }, "dependencies": { - "semver": "^6.0.0" + "semver": "^6.2.0" }, "files": [ "build/src/*.{js,d.ts}", From 201dab7fa8309c64c90514cd888678b1ab5eba09 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 Jul 2019 14:15:55 -0700 Subject: [PATCH 0724/1899] Improve server-related types exported by grpc-js --- packages/grpc-js/src/index.ts | 9 ++++++- packages/grpc-js/src/server-call.ts | 37 ++++++++++++++++------------- packages/grpc-js/src/server.ts | 18 +++++++------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index d846b6c06..8c5851bfc 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -38,9 +38,10 @@ import { Serialize, } from './make-client'; import { Metadata } from './metadata'; -import { Server } from './server'; +import { Server, UntypedHandleCall, UntypedServiceImplementation } from './server'; import { KeyCertPair, ServerCredentials } from './server-credentials'; import { StatusBuilder } from './status-builder'; +import { ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream } from './server-call'; const supportedNodeVersions = require('../../package.json').engines.node; if (!semver.satisfies(process.version, supportedNodeVersions)) { @@ -213,6 +214,12 @@ export { CallOptions, StatusObject, ServiceError, + ServerUnaryCall, + ServerReadableStream, + ServerWritableStream, + ServerDuplexStream, + UntypedHandleCall, + UntypedServiceImplementation }; /* tslint:disable:no-any */ diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 23d6b2470..34d13b781 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -18,13 +18,14 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; +import * as util from 'util'; -import { ServiceError } from './call'; import { StatusObject } from './call-stream'; import { Status } from './constants'; import { Deserialize, Serialize } from './make-client'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; +import { ObjectReadable, ObjectWritable } from './object-stream'; interface DeadlineUnitIndexSignature { [name: string]: number; @@ -56,6 +57,10 @@ const defaultResponseOptions = { waitForTrailers: true, } as http2.ServerStreamResponseOptions; +export type ServerStatusResponse = Partial; + +export type ServerErrorResponse = ServerStatusResponse & Error; + export type ServerSurfaceCall = { cancelled: boolean; getPeer(): string; @@ -68,13 +73,13 @@ export type ServerUnaryCall = ServerSurfaceCall & { export type ServerReadableStream< RequestType, ResponseType -> = ServerSurfaceCall & Readable; +> = ServerSurfaceCall & ObjectReadable; export type ServerWritableStream< RequestType, ResponseType -> = ServerSurfaceCall & Writable & { request: RequestType | null }; +> = ServerSurfaceCall & ObjectWritable & { request: RequestType | null }; export type ServerDuplexStream = ServerSurfaceCall & - Duplex; + ObjectReadable & ObjectWritable; export class ServerUnaryCallImpl extends EventEmitter implements ServerUnaryCall { @@ -152,7 +157,7 @@ export class ServerWritableStreamImpl this.call.setupSurfaceCall(this); this.on('error', err => { - this.call.sendError(err as ServiceError); + this.call.sendError(err); this.end(); }); } @@ -223,7 +228,7 @@ export class ServerDuplexStreamImpl extends Duplex this.call.setupReadable(this); this.on('error', err => { - this.call.sendError(err as ServiceError); + this.call.sendError(err); this.end(); }); } @@ -247,7 +252,7 @@ ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; // Unary response callback signature. export type sendUnaryData = ( - error: ServiceError | null, + error: ServerErrorResponse | ServerStatusResponse | null, value: ResponseType | null, trailer?: Metadata, flags?: number @@ -339,7 +344,7 @@ export class Http2ServerCallStream< ) { super(); - this.stream.once('error', (err: ServiceError) => { + this.stream.once('error', (err: ServerErrorResponse) => { err.code = Status.INTERNAL; this.sendError(err); }); @@ -379,7 +384,7 @@ export class Http2ServerCallStream< const match = timeoutHeader[0].toString().match(DEADLINE_REGEX); if (match === null) { - const err = new Error('Invalid deadline') as ServiceError; + const err = new Error('Invalid deadline') as ServerErrorResponse; err.code = Status.OUT_OF_RANGE; this.sendError(err); return; @@ -439,7 +444,7 @@ export class Http2ServerCallStream< } async sendUnaryMessage( - err: ServiceError | null, + err: ServerErrorResponse | ServerStatusResponse | null, value: ResponseType | null, metadata?: Metadata, flags?: number @@ -490,21 +495,21 @@ export class Http2ServerCallStream< } } - sendError(error: ServiceError) { + sendError(error: ServerErrorResponse | ServerStatusResponse) { const status: StatusObject = { code: Status.UNKNOWN, - details: error.hasOwnProperty('message') + details: ('message' in error) ? error.message : 'Unknown Error', - metadata: error.hasOwnProperty('metadata') + metadata: ('metadata' in error && error.metadata !== undefined) ? error.metadata : new Metadata(), }; - if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { + if ('code' in error && util.isNumber(error.code) && Number.isInteger(error.code)) { status.code = error.code; - if (error.hasOwnProperty('details')) { + if ('details' in error && util.isString(error.details)) { status.details = error.details; } } @@ -637,7 +642,7 @@ export class Http2ServerCallStream< type UntypedServerCall = Http2ServerCallStream; function handleExpiredDeadline(call: UntypedServerCall) { - const err = new Error('Deadline exceeded') as ServiceError; + const err = new Error('Deadline exceeded') as ServerErrorResponse; err.code = Status.DEADLINE_EXCEEDED; call.sendError(err); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index e6d176195..a568f9c1d 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -41,6 +41,8 @@ import { ServerWritableStream, ServerWritableStreamImpl, UnaryHandler, + ServerErrorResponse, + ServerStatusResponse, } from './server-call'; import { ServerCredentials } from './server-credentials'; @@ -57,9 +59,9 @@ type UntypedUnaryHandler = UnaryHandler; type UntypedClientStreamingHandler = ClientStreamingHandler; type UntypedServerStreamingHandler = ServerStreamingHandler; type UntypedBidiStreamingHandler = BidiStreamingHandler; -type UntypedHandleCall = HandleCall; +export type UntypedHandleCall = HandleCall; type UntypedHandler = Handler; -interface UntypedServiceImplementation { +export interface UntypedServiceImplementation { [name: string]: UntypedHandleCall; } @@ -100,7 +102,7 @@ export class Server { throw new Error('Not implemented. Use addService() instead'); } - addService(service: ServiceDefinition, implementation: object): void { + addService(service: ServiceDefinition, implementation: UntypedServiceImplementation): void { if (this.started === true) { throw new Error("Can't add a service to a started server."); } @@ -120,8 +122,6 @@ export class Server { throw new Error('Cannot add an empty service to a server'); } - const implMap: UntypedServiceImplementation = implementation as UntypedServiceImplementation; - serviceKeys.forEach(name => { const attrs = service[name]; let methodType: HandlerType; @@ -140,11 +140,11 @@ export class Server { } } - let implFn = implMap[name]; + let implFn = implementation[name]; let impl; if (implFn === undefined && typeof attrs.originalName === 'string') { - implFn = implMap[attrs.originalName]; + implFn = implementation[attrs.originalName]; } if (implFn !== undefined) { @@ -414,7 +414,7 @@ async function handleUnary( handler.func( emitter, ( - err: ServiceError | null, + err: ServerErrorResponse | ServerStatusResponse | null, value: ResponseType | null, trailer?: Metadata, flags?: number @@ -436,7 +436,7 @@ function handleClientStreaming( ); function respond( - err: ServiceError | null, + err: ServerErrorResponse | ServerStatusResponse | null, value: ResponseType | null, trailer?: Metadata, flags?: number From 0dc0b68197f4a1787188a1faaee65289b4813806 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 Jul 2019 14:21:42 -0700 Subject: [PATCH 0725/1899] Fix typo in native types file --- packages/grpc-native-core/index.d.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 718f6bdb4..bba7be727 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -412,13 +412,13 @@ declare module "grpc" { * User provided method to handle server streaming methods on the server. */ type handleServerStreamingCall = - (call: ServerWriteableStream) => void; + (call: ServerWritableStream) => void; /** * A stream that the server can write to. Used for calls that are streaming * from the server side. */ - export class ServerWriteableStream extends Writable { + export class ServerWritableStream extends Writable { /** * Indicates if the call has been cancelled */ @@ -449,6 +449,10 @@ declare module "grpc" { sendMetadata(responseMetadata: Metadata): void; } + /* This typo existed in previous versions of this file, so we provide this + * type alias for backwards compatibility. */ + export type ServerWriteableStream = ServerWritableStream; + /** * User provided method to handle bidirectional streaming calls on the server. */ From acdd2abfc3bd8829563694eca6e1189c79cdde67 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 16 Jul 2019 14:35:06 -0700 Subject: [PATCH 0726/1899] Add resolver and service config handling code --- packages/grpc-js/src/load-balancing-config.ts | 109 ++++++++ packages/grpc-js/src/resolver-dns.ts | 144 ++++++++++ packages/grpc-js/src/resolver.ts | 55 ++++ packages/grpc-js/src/service-config.ts | 259 ++++++++++++++++++ 4 files changed, 567 insertions(+) create mode 100644 packages/grpc-js/src/load-balancing-config.ts create mode 100644 packages/grpc-js/src/resolver-dns.ts create mode 100644 packages/grpc-js/src/resolver.ts create mode 100644 packages/grpc-js/src/service-config.ts diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts new file mode 100644 index 000000000..b4b4594d8 --- /dev/null +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -0,0 +1,109 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* This file is an implementation of gRFC A24: + * https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md */ + +import { isString, isArray } from "util"; + +export interface RoundRobinConfig { +} + +export interface XdsConfig { + balancerName: string; + childPolicy: LoadBalancingConfig[]; + fallbackPolicy: LoadBalancingConfig[]; +} + +export interface GrpcLbConfig { + childPolicy: LoadBalancingConfig[]; +} + +export interface LoadBalancingConfig { + /* Exactly one of these must be set for a config to be valid */ + round_robin?: RoundRobinConfig; + xds?: XdsConfig; + grpclb?: GrpcLbConfig; +} + +/* In these functions we assume the input came from a JSON object. Therefore we + * expect that the prototype is uninteresting and that `in` can be used + * effectively */ + +function validateXdsConfig(xds: any): XdsConfig { + if (!('balancerName' in xds) || !isString(xds.balancerName)) { + throw new Error('Invalid xds config: invalid balancerName'); + } + const xdsConfig: XdsConfig = { + balancerName: xds.balancerName, + childPolicy: [], + fallbackPolicy: [] + }; + if ('childPolicy' in xds) { + if (!isArray(xds.childPolicy)) { + throw new Error('Invalid xds config: invalid childPolicy'); + } + for (const policy of xds.childPolicy) { + xdsConfig.childPolicy.push(validateConfig(policy)); + } + } + if ('fallbackPolicy' in xds) { + if (!isArray(xds.fallbackPolicy)) { + throw new Error('Invalid xds config: invalid fallbackPolicy'); + } + for (const policy of xds.fallbackPolicy) { + xdsConfig.fallbackPolicy.push(validateConfig(policy)); + } + } + return xdsConfig; +} + +function validateGrpcLbConfig(grpclb: any): GrpcLbConfig { + const grpcLbConfig: GrpcLbConfig = { + childPolicy: [] + }; + if ('childPolicy' in grpclb) { + if (!isArray(grpclb.childPolicy)) { + throw new Error('Invalid xds config: invalid childPolicy'); + } + for (const policy of grpclb.childPolicy) { + grpcLbConfig.childPolicy.push(validateConfig(policy)); + } + } + return grpcLbConfig; +} + +export function validateConfig(obj: any): LoadBalancingConfig { + if ('round_robin' in obj) { + if ('xds' in obj || 'grpclb' in obj) { + throw new Error('Multiple load balancing policies configured'); + } + if (obj['round_robin'] instanceof Object) { + return { round_robin: {} } + } + } + if ('xds' in obj) { + if ('grpclb' in obj) { + throw new Error('Multiple load balancing policies configured'); + } + return {xds: validateXdsConfig(obj.xds)}; + } + if ('grpclb' in obj) { + return {grpclb: validateGrpcLbConfig(obj.grpclb)}; + } + throw new Error('No recognized load balancing policy configured'); +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts new file mode 100644 index 000000000..d556aebc1 --- /dev/null +++ b/packages/grpc-js/src/resolver-dns.ts @@ -0,0 +1,144 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Resolver, ResolverListener, registerResolver, registerDefaultResolver } from './resolver'; +import * as dns from 'dns'; +import * as util from 'util'; +import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; + +/* These regular expressions match IP addresses with optional ports in different + * formats. In each case, capture group 1 contains the address, and capture + * group 2 contains the port number, if present */ +const IPv4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/; +const IPv6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i; +const IPv6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i; + +const DNS_REGEX = /^(?:dns:)?(?:\/\/\w+\/)?(\w+)(?::(\d+))?$/; + +const DEFAULT_PORT = '443'; + +const resolve4Promise = util.promisify(dns.resolve4); +const resolve6Promise = util.promisify(dns.resolve6); + +function parseIP(target: string): string | null { + /* These three regular expressions are all mutually exclusive, so we just + * want the first one that matches the target string, if any do. */ + const match = IPv4_REGEX.exec(target) || IPv6_REGEX.exec(target) || IPv6_BRACKET_REGEX.exec(target); + if (match === null) { + return null; + } + const addr = match[1]; + let port: string; + if (match[2]) { + port = match[2]; + } else { + port = DEFAULT_PORT; + } + return `${addr}:${port}`; +} + +function mergeArrays(...arrays: T[][]): T[] { + const result: T[] = []; + for(let i = 0; i array.length)); i++) { + for(let array of arrays) { + if(i < array.length) { + result.push(array[i]); + } + } + } + return result; +} + +class DnsResolver implements Resolver { + ipResult: string | null; + dnsHostname: string | null; + port: string | null; + /* The promise results here contain, in order, the A record, the AAAA record, + * and either the TXT record or an error if TXT resolution failed */ + pendingResultPromise: Promise<[string[], string[], string[][] | Error]> | null = null; + percentage: number; + constructor(private target: string, private listener: ResolverListener) { + this.ipResult = parseIP(target); + const dnsMatch = DNS_REGEX.exec(target); + if (dnsMatch === null) { + this.dnsHostname = null; + this.port = null; + } else { + this.dnsHostname = dnsMatch[1]; + if (dnsMatch[2]) { + this.port = dnsMatch[2]; + } else { + this.port = DEFAULT_PORT; + } + } + this.percentage = Math.random() * 100; + this.startResolution(); + } + + private startResolution() { + if (this.ipResult !== null) { + setImmediate(() => { + this.listener.onSuccessfulResolution([this.ipResult!], null, null); + }); + return; + } + if (this.dnsHostname !== null) { + const hostname: string = this.dnsHostname; + const Aresult = resolve4Promise(hostname); + const AAAAresult = resolve6Promise(hostname); + const TXTresult = new Promise((resolve, reject) => { + dns.resolveTxt(hostname, (err, records) => { + if (err) { + resolve(err); + } else { + resolve(records); + } + }); + }); + this.pendingResultPromise = Promise.all([Aresult, AAAAresult, TXTresult]); + this.pendingResultPromise.then(([Arecord, AAAArecord, TXTrecord]) => { + this.pendingResultPromise = null; + const allAddresses: string[] = mergeArrays(AAAArecord, Arecord); + let serviceConfig: ServiceConfig | null = null; + let serviceConfigError: Error | null = null; + if (TXTrecord instanceof Error) { + serviceConfigError = TXTrecord; + } else { + try { + serviceConfig = extractAndSelectServiceConfig(TXTrecord, this.percentage); + } catch (err) { + serviceConfigError = err; + } + } + this.listener.onSuccessfulResolution(allAddresses, serviceConfig, serviceConfigError); + }, (err) => { + this.pendingResultPromise = null; + this.listener.onError(err); + }); + } + } + + updateResolution() { + if (this.pendingResultPromise === null) { + this.startResolution(); + } + } +} + +export function setup(): void { + registerResolver('dns:', DnsResolver); + registerDefaultResolver(DnsResolver); +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts new file mode 100644 index 000000000..e5519a9bf --- /dev/null +++ b/packages/grpc-js/src/resolver.ts @@ -0,0 +1,55 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ServiceError } from "./call"; +import { ServiceConfig } from "./service-config"; + +export interface ResolverListener { + onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: Error | null): void; + onError(error: ServiceError): void; +} + +export interface Resolver { + updateResolution(): void; +} + +export interface ResolverConstructor { + new(target: string, listener: ResolverListener): Resolver; +} + +const registeredResolvers: {[prefix: string]: ResolverConstructor} = {}; +let defaultResolver: ResolverConstructor | null = null; + +export function registerResolver(prefix: string, resolverClass: ResolverConstructor) { + registeredResolvers[prefix] = resolverClass; +} + +export function registerDefaultResolver(resolverClass: ResolverConstructor) { + defaultResolver = resolverClass; +} + +export function createResolver(target: string, listener: ResolverListener): Resolver { + for (const prefix of Object.keys(registeredResolvers)) { + if (target.startsWith(prefix)) { + return new registeredResolvers[prefix](target, listener); + } + } + if (defaultResolver !== null) { + return new defaultResolver(target, listener); + } + throw new Error('No resolver could be created for the provided target'); +} \ No newline at end of file diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts new file mode 100644 index 000000000..c181f87b6 --- /dev/null +++ b/packages/grpc-js/src/service-config.ts @@ -0,0 +1,259 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/* This file implements gRFC A2 and the service config spec: + * https://github.com/grpc/proposal/blob/master/A2-service-configs-in-dns.md + * https://github.com/grpc/grpc/blob/master/doc/service_config.md */ + +import * as lbconfig from './load-balancing-config'; +import { isString, isArray, isBoolean, isNumber } from 'util'; +import * as os from 'os'; + +export interface MethodConfigName { + service: string; + method?: string; +} + +export interface MethodConfig { + name: MethodConfigName[]; + waitForReady?: boolean; + timeout?: string; + maxRequestBytes?: number; + maxResponseBytes?: number; +} + +export interface ServiceConfig { + loadBalancingPolicy?: string; + loadBalancingConfig: lbconfig.LoadBalancingConfig[] + methodConfig: MethodConfig[]; +} + +export interface ServiceConfigCanaryConfig { + clientLanguage?: string[]; + percentage?: number; + clientHostname?: string[]; + serviceConfig: ServiceConfig; +} + +const TIMEOUT_REGEX = /^\d+(\.\d{1,9})?s$/; + +const CLIENT_LANGUAGE_STRING = 'node'; + +function validateName(obj: any): MethodConfigName { + if (!('service' in obj) || !isString(obj.service)) { + throw new Error('Invalid method config name: invalid service'); + } + const result: MethodConfigName = { + service: obj.service + }; + if ('method' in obj) { + if (isString(obj.method)) { + result.method = obj.method; + } else { + throw new Error('Invalid method config name: invalid method'); + } + } + return result; +} + +function validateMethodConfig(obj: any): MethodConfig { + const result: MethodConfig = { + name: [] + }; + if (!('name' in obj) || !isArray(obj.name)) { + throw new Error('Invalid method config: invalid name array'); + } + for (const name of obj.name) { + result.name.push(validateName(name)); + } + if ('waitForReady' in obj) { + if (!isBoolean(obj.waitForReady)) { + throw new Error('Invalid method config: invalid waitForReady'); + } + result.waitForReady = obj.waitForReady; + } + if ('timeout' in obj) { + if (!isString(obj.timeout) || !TIMEOUT_REGEX.test(obj.timeout)) { + throw new Error('Invalid method config: invalid timeout'); + } + result.timeout = obj.timeout; + } + if ('maxRequestBytes' in obj) { + if (!isNumber(obj.maxRequestBytes)) { + throw new Error('Invalid method config: invalid maxRequestBytes'); + } + result.maxRequestBytes = obj.maxRequestBytes; + } + if ('maxResponseBytes' in obj) { + if (!isNumber(obj.maxResponseBytes)) { + throw new Error('Invalid method config: invalid maxRequestBytes'); + } + result.maxResponseBytes = obj.maxResponseBytes; + } + return result; +} + +function validateServiceConfig(obj: any): ServiceConfig { + const result: ServiceConfig = { + loadBalancingConfig: [], + methodConfig: [] + }; + if ('loadBalancingPolicy' in obj) { + if (isString(obj.loadBalancingPolicy)) { + result.loadBalancingPolicy = obj.loadBalancingPolicy; + } else { + throw new Error('Invalid service config: invalid loadBalancingPolicy'); + } + } + if ('loadBalancingConfig' in obj) { + if (isArray(obj.loadBalancingConfig)) { + for (const config of obj.loadBalancingConfig) { + result.loadBalancingConfig.push(lbconfig.validateConfig(config)); + } + } else { + throw new Error('Invalid service config: invalid loadBalancingConfig'); + } + } + if ('methodConfig' in obj) { + if (isArray(obj.methodConfig)) { + for (const methodConfig of obj.methodConfig) { + result.methodConfig.push(validateMethodConfig(methodConfig)); + } + } + } + // Validate method name uniqueness + const seenMethodNames: MethodConfigName[] = []; + for (const methodConfig of result.methodConfig) { + for (const name of methodConfig.name) { + for (const seenName of seenMethodNames) { + if (name.service === seenName.service && name.method === seenName.method) { + throw new Error(`Invalid service config: duplicate name ${name.service}/${name.method}`); + } + } + seenMethodNames.push(name); + } + } + return result; +} + +function validateCanaryConfig(obj: any): ServiceConfigCanaryConfig { + if (!('serviceConfig' in obj)) { + throw new Error('Invalid service config choice: missing service config'); + } + const result: ServiceConfigCanaryConfig = { + serviceConfig: validateServiceConfig(obj.serviceConfig) + } + if ('clientLanguage' in obj) { + if (isArray(obj.clientLanguage)) { + result.clientLanguage = []; + for (const lang of obj.clientLanguage) { + if (isString(lang)) { + result.clientLanguage.push(lang); + } else { + throw new Error('Invalid service config choice: invalid clientLanguage'); + } + } + } else { + throw new Error('Invalid service config choice: invalid clientLanguage'); + } + } + if ('clientHostname' in obj) { + if (isArray(obj.clientHostname)) { + result.clientHostname = []; + for (const lang of obj.clientHostname) { + if (isString(lang)) { + result.clientHostname.push(lang); + } else { + throw new Error('Invalid service config choice: invalid clientHostname'); + } + } + } else { + throw new Error('Invalid service config choice: invalid clientHostname'); + } + } + if ('percentage' in obj) { + if (isNumber(obj.percentage) && 0 <= obj.percentage && obj.percentage <= 100) { + result.percentage = obj.percentage; + } else { + throw new Error('Invalid service config choice: invalid percentage'); + } + } + // Validate that no unexpected fields are present + const allowedFields = ['clientLanguage', 'percentage', 'clientHostname', 'serviceConfig']; + for (const field in obj) { + if (!allowedFields.includes(field)) { + throw new Error(`Invalid service config choice: unexpected field ${field}`); + } + } + return result; +} + +function validateAndSelectCanaryConfig(obj: any, percentage: number): ServiceConfig { + if (!isArray(obj)) { + throw new Error('Invalid service config list'); + } + for (const config of obj) { + const validatedConfig = validateCanaryConfig(config); + /* For each field, we check if it is present, then only discard the + * config if the field value does not match the current client */ + if (isNumber(validatedConfig.percentage) && percentage > validatedConfig.percentage) { + continue; + } + if (isArray(validatedConfig.clientHostname)) { + let hostnameMatched = false; + for (const hostname of validatedConfig.clientHostname) { + if (hostname === os.hostname()) { + hostnameMatched = true; + } + } + if (!hostnameMatched) { + continue; + } + } + if (isArray(validatedConfig.clientLanguage)) { + let languageMatched = false; + for (const language of validatedConfig.clientLanguage) { + if (language === CLIENT_LANGUAGE_STRING) { + languageMatched = true; + } + } + if (!languageMatched) { + continue; + } + } + return validatedConfig.serviceConfig; + } + throw new Error('No matching service config found'); +} + +/** + * Find the "grpc_config" record among the TXT records, parse its value as JSON, validate its contents, + * and select a service config with selection fields that all match this client. Most of these steps + * can fail with an error; the caller must handle any errors thrown this way. + * @param txtRecord The TXT record array that is output from a successful call to dns.resolveTxt + * @param percentage A number chosen from the range [0, 100) that is used to select which config to use + */ +export function extractAndSelectServiceConfig(txtRecord: string[][], percentage: number): ServiceConfig | null { + for (const record of txtRecord) { + if (record.length > 0 && record[0].startsWith('grpc_config=')) { + const recordString = [record[0].substring('grpc_config='.length)].concat(record.slice(1)).join(''); + const recordJson: any = JSON.parse(recordString); + return validateAndSelectCanaryConfig(recordJson, percentage); + } + } + return null; +} \ No newline at end of file From 80d7057cad4c71139b1544407279fed51908e758 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 29 Jul 2019 13:50:51 -0700 Subject: [PATCH 0727/1899] Use typeof instead of util functions --- packages/grpc-js/src/server-call.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 34d13b781..c9a6b3f75 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -18,7 +18,6 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; -import * as util from 'util'; import { StatusObject } from './call-stream'; import { Status } from './constants'; @@ -506,11 +505,11 @@ export class Http2ServerCallStream< : new Metadata(), }; - if ('code' in error && util.isNumber(error.code) && Number.isInteger(error.code)) { + if ('code' in error && typeof error.code === 'number' && Number.isInteger(error.code)) { status.code = error.code; - if ('details' in error && util.isString(error.details)) { - status.details = error.details; + if ('details' in error && typeof error.details === 'string') { + status.details = error.details!; } } From e2e6d14675721baeb1d7bd50b6baac383104be66 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 30 Jul 2019 10:25:24 -0700 Subject: [PATCH 0728/1899] Set grpc-health-check version to 1.7.0 --- packages/grpc-health-check/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index 4ff2e33ab..d2e1a9a20 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/health-check", - "version": "1.8.0-dev", + "version": "1.7.0", "author": "Google Inc.", "description": "Health check service for use with gRPC", "repository": { From 2e16f16ec472aac320a13b4bd7821ef86163634a Mon Sep 17 00:00:00 2001 From: Esun Kim Date: Tue, 30 Jul 2019 11:01:44 -0700 Subject: [PATCH 0729/1899] Add upb configuration to native-core --- packages/grpc-native-core/binding.gyp | 5 ++++- packages/grpc-native-core/package.json | 8 +++++--- packages/grpc-native-core/templates/binding.gyp.template | 5 ++++- packages/grpc-native-core/templates/package.json.template | 8 +++++--- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 06fcb76eb..6dae2c5b8 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -83,11 +83,14 @@ 'include_dirs': [ 'deps/grpc', 'deps/grpc/include', + 'deps/grpc/src/core/ext/upb-generated', + 'deps/grpc/third_party/abseil-cpp', 'deps/grpc/third_party/address_sorting/include', 'deps/grpc/third_party/cares', 'deps/grpc/third_party/cares/cares', - 'deps/grpc/third_party/abseil-cpp', 'deps/grpc/third_party/nanopb', + 'deps/grpc/third_party/upb', + 'deps/grpc/third_party/upb/generated_for_cmake', ], 'defines': [ 'PB_FIELD_32BIT', diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 870f40567..ad6d2f5b5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -68,13 +68,15 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/nanopb/*.{c,cc,h}", - "deps/grpc/third_party/zlib/**/*.{c,cc,h}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", + "deps/grpc/third_party/nanopb/*.{c,cc,h}", + "deps/grpc/third_party/upb/generated_for_cmake/google/protobuf/*.{c,h}", + "deps/grpc/third_party/upb/upb/*.{c,h}", + "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" ], "main": "index.js", diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 8c145d4aa..cdf1a1a0c 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -75,11 +75,14 @@ 'include_dirs': [ 'deps/grpc', 'deps/grpc/include', + 'deps/grpc/src/core/ext/upb-generated', + 'deps/grpc/third_party/abseil-cpp', 'deps/grpc/third_party/address_sorting/include', 'deps/grpc/third_party/cares', 'deps/grpc/third_party/cares/cares', - 'deps/grpc/third_party/abseil-cpp', 'deps/grpc/third_party/nanopb', + 'deps/grpc/third_party/upb', + 'deps/grpc/third_party/upb/generated_for_cmake', ], 'defines': [ 'PB_FIELD_32BIT', diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 9949797c0..be994bf1b 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -70,13 +70,15 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/nanopb/*.{c,cc,h}", - "deps/grpc/third_party/zlib/**/*.{c,cc,h}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", + "deps/grpc/third_party/nanopb/*.{c,cc,h}", + "deps/grpc/third_party/upb/generated_for_cmake/google/protobuf/*.{c,h}", + "deps/grpc/third_party/upb/upb/*.{c,h}", + "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" ], "main": "index.js", From bb57faeb7bdde73794c9a7173d209ed783d9bad7 Mon Sep 17 00:00:00 2001 From: Esun Kim Date: Tue, 30 Jul 2019 11:34:59 -0700 Subject: [PATCH 0730/1899] Update by code review --- packages/grpc-native-core/package.json | 3 +-- packages/grpc-native-core/templates/package.json.template | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ad6d2f5b5..ed360a399 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -74,8 +74,7 @@ "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", "deps/grpc/third_party/nanopb/*.{c,cc,h}", - "deps/grpc/third_party/upb/generated_for_cmake/google/protobuf/*.{c,h}", - "deps/grpc/third_party/upb/upb/*.{c,h}", + "deps/grpc/third_party/upb/**/*.{c,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" ], diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index be994bf1b..2d9bede7d 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -76,8 +76,7 @@ "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", "deps/grpc/third_party/nanopb/*.{c,cc,h}", - "deps/grpc/third_party/upb/generated_for_cmake/google/protobuf/*.{c,h}", - "deps/grpc/third_party/upb/upb/*.{c,h}", + "deps/grpc/third_party/upb/**/*.{c,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" ], From 49ffe9522e41f3c191467447c261d1e79307fe1c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 30 Jul 2019 12:51:07 -0700 Subject: [PATCH 0731/1899] Revert grpc-health-check name to original name --- packages/grpc-health-check/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index d2e1a9a20..e10de7c10 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -1,5 +1,5 @@ { - "name": "@grpc/health-check", + "name": "grpc-health-check", "version": "1.7.0", "author": "Google Inc.", "description": "Health check service for use with gRPC", From 81c579deae7f49fc75b5941de122504c2103401f Mon Sep 17 00:00:00 2001 From: Erik Silkensen <94125+esilkensen@users.noreply.github.com> Date: Sun, 4 Aug 2019 17:10:38 -0600 Subject: [PATCH 0732/1899] Fix typo in makeServerStreamRequest return type (grpc-native-core) --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index bba7be727..c7dab49dd 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1131,7 +1131,7 @@ declare module "grpc" { argument: RequestType, metadata?: Metadata | null, options?: CallOptions | null, - ): ClientReadableStream; + ): ClientReadableStream; /** * Make a bidirectional stream request with this method on the given channel. From 110461d78abd14e101ccc534f147b165a7025d40 Mon Sep 17 00:00:00 2001 From: Bjorn Stromberg Date: Wed, 17 Jul 2019 10:30:39 +0900 Subject: [PATCH 0733/1899] Add dev-dependencies and fix tests so they exit after running --- package.json | 2 +- packages/grpc-js/package.json | 13 ++++++++++++- packages/grpc-js/test/test-server.ts | 10 ++++++++-- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index e910715a5..11d8e2572 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "through2": "^2.0.3", "ts-node": "^8.1.0", "tslint": "^5.5.0", - "typescript": "~3.3.3333", + "typescript": "^3.5.3", "xml2js": "^0.4.19" }, "contributors": [ diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 88978f0a4..51ff1cfdb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -16,14 +16,25 @@ "license": "Apache-2.0", "devDependencies": { "@grpc/proto-loader": "^0.5.0", + "@types/gulp": "^4.0.6", + "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", + "@types/ncp": "^2.0.1", "@types/node": "^12.0.2", + "@types/pify": "^3.0.2", "@types/semver": "^6.0.1", "clang-format": "^1.0.55", + "execa": "^2.0.3", "gts": "^1.0.0", + "gulp": "^4.0.2", + "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", - "typescript": "~3.5.1" + "mocha-jenkins-reporter": "^0.4.1", + "ncp": "^2.0.0", + "pify": "^4.0.1", + "ts-node": "^8.3.0", + "typescript": "^3.5.3" }, "contributors": [ { diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 3e02c3d5f..434efbbc4 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -86,7 +86,7 @@ describe('Server', () => { }); }); - it('throws if bind is called after the server is started', () => { + it('throws if bind is called after the server is started', done => { const server = new Server(); server.bindAsync( @@ -102,6 +102,7 @@ describe('Server', () => { noop ); }, /server is already started/); + server.tryShutdown(done); } ); }); @@ -243,7 +244,7 @@ describe('Server', () => { const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; const mathServiceAttrs = mathClient.service; - beforeEach(done => { + before(done => { server = new Server(); server.addService(mathServiceAttrs, {}); server.bindAsync( @@ -261,6 +262,11 @@ describe('Server', () => { ); }); + after(done => { + client.close(); + server.tryShutdown(done); + }); + it('should respond to a unary call with UNIMPLEMENTED', done => { client.div( { divisor: 4, dividend: 3 }, From b79229b96491931d911eac80e13308fc5ca251c7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 6 Aug 2019 11:39:01 -0700 Subject: [PATCH 0734/1899] Update native library to 1.23.0-pre1 --- packages/grpc-native-core/binding.gyp | 7 +++++-- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 6dae2c5b8..d50231f94 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -97,7 +97,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.22.0-pre1"', + 'GRPC_NODE_VERSION="1.23.0-pre1"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], @@ -691,7 +691,6 @@ 'deps/grpc/src/core/lib/gpr/env_linux.cc', 'deps/grpc/src/core/lib/gpr/env_posix.cc', 'deps/grpc/src/core/lib/gpr/env_windows.cc', - 'deps/grpc/src/core/lib/gpr/host_port.cc', 'deps/grpc/src/core/lib/gpr/log.cc', 'deps/grpc/src/core/lib/gpr/log_android.cc', 'deps/grpc/src/core/lib/gpr/log_linux.cc', @@ -718,6 +717,7 @@ 'deps/grpc/src/core/lib/gprpp/arena.cc', 'deps/grpc/src/core/lib/gprpp/fork.cc', 'deps/grpc/src/core/lib/gprpp/global_config_env.cc', + 'deps/grpc/src/core/lib/gprpp/host_port.cc', 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', @@ -782,6 +782,8 @@ 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', 'deps/grpc/src/core/lib/iomgr/exec_ctx.cc', 'deps/grpc/src/core/lib/iomgr/executor.cc', + 'deps/grpc/src/core/lib/iomgr/executor/mpmcqueue.cc', + 'deps/grpc/src/core/lib/iomgr/executor/threadpool.cc', 'deps/grpc/src/core/lib/iomgr/fork_posix.cc', 'deps/grpc/src/core/lib/iomgr/fork_windows.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', @@ -1070,6 +1072,7 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', + 'deps/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 35230ef8c..2ae2bb7ab 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 35230ef8cd70d62ab94bee661b7cd641adfa805b +Subproject commit 2ae2bb7abc9565ffed5f23eeb64fd4cd69c1e562 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ed360a399..394779137 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.22.0-pre1", + "version": "1.23.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 43fa9398c7a0d707b5447e3b502fb492486dca93 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 6 Aug 2019 17:24:31 -0700 Subject: [PATCH 0735/1899] Update submodule again --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 2ae2bb7ab..ae91cd038 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 2ae2bb7abc9565ffed5f23eeb64fd4cd69c1e562 +Subproject commit ae91cd03818d6c4e7bc06efc261215338ce65475 From e612cd99346d630761a0952c80a4cd7c7e3c1807 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 6 Aug 2019 10:18:15 -0700 Subject: [PATCH 0736/1899] Add new subchannel and load balancing code --- packages/grpc-js/src/call-credentials.ts | 37 +- packages/grpc-js/src/channel-credentials.ts | 109 ++++-- packages/grpc-js/src/channel-options.ts | 31 +- .../grpc-js/src/load-balancer-pick-first.ts | 198 ++++++++++ packages/grpc-js/src/load-balancer.ts | 107 ++++++ packages/grpc-js/src/picker.ts | 92 +++++ packages/grpc-js/src/resolver-dns.ts | 10 +- packages/grpc-js/src/resolver.ts | 2 +- .../grpc-js/src/resolving-load-balancer.ts | 92 +++++ packages/grpc-js/src/subchannel-pool.ts | 78 ++++ packages/grpc-js/src/subchannel.ts | 339 +++++++++++++----- 11 files changed, 980 insertions(+), 115 deletions(-) create mode 100644 packages/grpc-js/src/load-balancer-pick-first.ts create mode 100644 packages/grpc-js/src/load-balancer.ts create mode 100644 packages/grpc-js/src/picker.ts create mode 100644 packages/grpc-js/src/resolving-load-balancer.ts create mode 100644 packages/grpc-js/src/subchannel-pool.ts diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index 087a3c72f..fd32baffd 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -16,6 +16,7 @@ */ import { Metadata } from './metadata'; +import { Call } from '.'; export interface CallMetadataOptions { service_url: string; @@ -44,6 +45,14 @@ export abstract class CallCredentials { */ abstract compose(callCredentials: CallCredentials): CallCredentials; + /** + * Check whether two call credentials objects are equal. Separate + * SingleCallCredentials with identical metadata generator functions are + * equal. + * @param other The other CallCredentials object to compare with. + */ + abstract _equals(other: CallCredentials): boolean; + /** * Creates a new CallCredentials object from a given function that generates * Metadata objects. @@ -81,6 +90,17 @@ class ComposedCallCredentials extends CallCredentials { compose(other: CallCredentials): CallCredentials { return new ComposedCallCredentials(this.creds.concat([other])); } + + _equals(other: CallCredentials): boolean { + if (this === other) { + return true; + } + if (other instanceof ComposedCallCredentials) { + return this.creds.every((value, index) => value._equals(other.creds[index])); + } else { + return false; + } + } } class SingleCallCredentials extends CallCredentials { @@ -103,7 +123,18 @@ class SingleCallCredentials extends CallCredentials { compose(other: CallCredentials): CallCredentials { return new ComposedCallCredentials([this, other]); } -} + + _equals(other: CallCredentials): boolean { + if (this === other) { + return true; + } + if (other instanceof SingleCallCredentials) { + return this.metadataGenerator === other.metadataGenerator; + } else { + return false; + } + } + } class EmptyCallCredentials extends CallCredentials { generateMetadata(options: CallMetadataOptions): Promise { @@ -113,4 +144,8 @@ class EmptyCallCredentials extends CallCredentials { compose(other: CallCredentials): CallCredentials { return other; } + + _equals(other: CallCredentials): boolean { + return other instanceof EmptyCallCredentials; + } } diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 31320be39..345c99bfe 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -18,6 +18,7 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; +import { Call } from '.'; // tslint:disable-next-line:no-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -47,6 +48,14 @@ export type CheckServerIdentityCallback = ( cert: Certificate ) => Error | undefined; +function bufferOrNullEqual(buf1: Buffer | null, buf2: Buffer | null) { + if (buf1 === null && buf2 === null) { + return true; + } else { + return buf1 !== null && buf2 !== null && buf1.equals(buf2); + } +} + /** * Additional peer verification options that can be set when creating * SSL credentials. @@ -97,6 +106,13 @@ export abstract class ChannelCredentials { */ abstract _isSecure(): boolean; + /** + * Check whether two channel credentials objects are equal. Two secure + * credentials are equal if they were constructed with the same parameters. + * @param other The other ChannelCredentials Object + */ + abstract _equals(other: ChannelCredentials): boolean; + /** * Return a new ChannelCredentials instance with a given set of credentials. * The resulting instance can be used to construct a Channel that communicates @@ -124,21 +140,7 @@ export abstract class ChannelCredentials { 'Certificate chain must be given with accompanying private key' ); } - const secureContext = createSecureContext({ - ca: rootCerts || undefined, - key: privateKey || undefined, - cert: certChain || undefined, - }); - const connectionOptions: ConnectionOptions = { secureContext }; - if (verifyOptions && verifyOptions.checkServerIdentity) { - connectionOptions.checkServerIdentity = ( - host: string, - cert: PeerCertificate - ) => { - return verifyOptions.checkServerIdentity!(host, { raw: cert.raw }); - }; - } - return new SecureChannelCredentialsImpl(connectionOptions); + return new SecureChannelCredentialsImpl(rootCerts || null, privateKey || null, certChain || null, verifyOptions || {}); } /** @@ -164,27 +166,42 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { _isSecure(): boolean { return false; } + _equals(other: ChannelCredentials): boolean { + return other instanceof InsecureChannelCredentialsImpl; + } } class SecureChannelCredentialsImpl extends ChannelCredentials { connectionOptions: ConnectionOptions; constructor( - connectionOptions: ConnectionOptions, - callCredentials?: CallCredentials + private rootCerts: Buffer | null, + private privateKey: Buffer | null, + private certChain: Buffer | null, + private verifyOptions: VerifyOptions ) { - super(callCredentials); - this.connectionOptions = connectionOptions; + super(); + const secureContext = createSecureContext({ + ca: rootCerts || undefined, + key: privateKey || undefined, + cert: certChain || undefined, + }); + this.connectionOptions = { secureContext }; + if (verifyOptions && verifyOptions.checkServerIdentity) { + this.connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ) => { + return verifyOptions.checkServerIdentity!(host, { raw: cert.raw }); + }; + } } compose(callCredentials: CallCredentials): ChannelCredentials { const combinedCallCredentials = this.callCredentials.compose( callCredentials ); - return new SecureChannelCredentialsImpl( - this.connectionOptions, - combinedCallCredentials - ); + return new ComposedChannelCredentialsImpl(this, combinedCallCredentials); } _getConnectionOptions(): ConnectionOptions | null { @@ -193,4 +210,50 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { _isSecure(): boolean { return true; } + _equals(other: ChannelCredentials): boolean { + if (this === other) { + return true; + } + if (other instanceof SecureChannelCredentialsImpl) { + if (!bufferOrNullEqual(this.rootCerts, other.rootCerts)) { + return false; + } + if (!bufferOrNullEqual(this.privateKey, other.privateKey)) { + return false; + } + if (!bufferOrNullEqual(this.certChain, other.certChain)) { + return false; + } + return this.verifyOptions.checkServerIdentity === other.verifyOptions.checkServerIdentity; + } else { + return false; + } + } +} + +class ComposedChannelCredentialsImpl extends ChannelCredentials { + constructor (private channelCredentials: SecureChannelCredentialsImpl, callCreds: CallCredentials) { + super(callCreds); + } + compose(callCredentials: CallCredentials) { + const combinedCallCredentials = this.callCredentials.compose(callCredentials); + return new ComposedChannelCredentialsImpl(this.channelCredentials, combinedCallCredentials); + } + + _getConnectionOptions(): ConnectionOptions | null { + return this.channelCredentials._getConnectionOptions(); + } + _isSecure(): boolean { + return true; + } + _equals(other: ChannelCredentials): boolean { + if (this === other) { + return true; + } + if (other instanceof ComposedChannelCredentialsImpl) { + return this.channelCredentials._equals(other.channelCredentials) && this.callCredentials._equals(other.callCredentials); + } else { + return false; + } + } } diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 6b1d42eef..b54b69cb0 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -19,13 +19,13 @@ * An interface that contains options used when initializing a Channel instance. */ export interface ChannelOptions { - 'grpc.ssl_target_name_override': string; - 'grpc.primary_user_agent': string; - 'grpc.secondary_user_agent': string; - 'grpc.default_authority': string; - 'grpc.keepalive_time_ms': number; - 'grpc.keepalive_timeout_ms': number; - [key: string]: string | number; + 'grpc.ssl_target_name_override'?: string; + 'grpc.primary_user_agent'?: string; + 'grpc.secondary_user_agent'?: string; + 'grpc.default_authority'?: string; + 'grpc.keepalive_time_ms'?: number; + 'grpc.keepalive_timeout_ms'?: number; + [key: string]: string | number | undefined; } /** @@ -40,3 +40,20 @@ export const recognizedOptions = { 'grpc.keepalive_time_ms': true, 'grpc.keepalive_timeout_ms': true, }; + +export function channelOptionsEqual(options1: ChannelOptions, options2: ChannelOptions) { + const keys1 = Object.keys(options1).sort(); + const keys2 = Object.keys(options2).sort(); + if (keys1.length !== keys2.length) { + return false; + } + for (let i = 0; i < keys1.length; i+=1) { + if (keys1[i] !== keys2[i]) { + return false; + } + if (options1[keys1[i]] !== options2[keys2[i]]) { + return false; + } + } + return true; +} diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts new file mode 100644 index 000000000..1fbbf4250 --- /dev/null +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -0,0 +1,198 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType } from './load-balancer'; +import { ConnectivityState } from './channel'; +import { QueuePicker, Picker, PickArgs, CompletePickResult, PickResultType, UnavailablePicker } from './picker'; +import { LoadBalancingConfig } from './load-balancing-config'; +import { Subchannel, SubchannelConnectivityState, ConnectivityStateListener } from './subchannel'; + +const TYPE_NAME = 'pick_first'; + +const CONNECTION_DELAY_INTERVAL_MS = 250; + +class PickFirstPicker implements Picker { + constructor(private subchannel: Subchannel) {} + + pick(pickArgs: PickArgs) : CompletePickResult { + return { + pickResultType: PickResultType.COMPLETE, + subchannel: this.subchannel, + status: null + } + } +} + +export class PickFirstLoadBalancer implements LoadBalancer { + private latestAddressList: string[] = []; + private subchannels: Subchannel[] = []; + private currentState: ConnectivityState = ConnectivityState.IDLE; + private currentSubchannelIndex: number = 0; + private subchannelConnectingCount: number = 0; + private currentPick: Subchannel | null = null; + private subchannelStateListener: ConnectivityStateListener; + private pickedSubchannelStateListener: ConnectivityStateListener; + private connectionDelayTimeout: NodeJS.Timeout; + + constructor(private channelControlHelper: ChannelControlHelper) { + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + this.subchannelStateListener = (subchannel: Subchannel, previousState: SubchannelConnectivityState, newState: SubchannelConnectivityState) => { + if (previousState === SubchannelConnectivityState.CONNECTING) { + this.subchannelConnectingCount -= 1; + } + if (newState === SubchannelConnectivityState.CONNECTING) { + this.subchannelConnectingCount += 1; + } + if (newState === SubchannelConnectivityState.READY) { + this.pickSubchannel(subchannel); + return; + } else { + if (this.currentPick === null) { + if (newState === SubchannelConnectivityState.TRANSIENT_FAILURE || newState === SubchannelConnectivityState.IDLE) { + subchannel.startConnecting(); + } + const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; + if (newLBState !== this.currentState) { + if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { + this.updateState(newLBState, new UnavailablePicker()); + } else { + this.updateState(newLBState, new QueuePicker(this)); + } + } + } + } + }; + this.pickedSubchannelStateListener = (subchannel: Subchannel, previousState: SubchannelConnectivityState, newState: SubchannelConnectivityState) => { + if (newState !== SubchannelConnectivityState.READY) { + subchannel.unref(); + subchannel.removeConnectivityStateListener(this.pickedSubchannelStateListener); + if (this.subchannels.length > 0) { + const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; + if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { + this.updateState(newLBState, new UnavailablePicker()); + } else { + this.updateState(newLBState, new QueuePicker(this)); + } + } else { + this.connectToAddressList(); + this.channelControlHelper.requestReresolution(); + } + } + }; + this.connectionDelayTimeout = setTimeout(() => {}, 0); + clearTimeout(this.connectionDelayTimeout); + } + + private startConnecting(subchannelIndex: number) { + if (this.subchannels[subchannelIndex].getConnectivityState() === SubchannelConnectivityState.IDLE) { + this.subchannels[subchannelIndex].startConnecting(); + } + this.connectionDelayTimeout = setTimeout(() => { + for (const [index, subchannel] of this.subchannels.entries()) { + if (index > subchannelIndex) { + const subchannelState = subchannel.getConnectivityState(); + if (subchannelState === SubchannelConnectivityState.IDLE || subchannelState === SubchannelConnectivityState.CONNECTING) { + this.startConnecting(index); + return; + } + } + } + }, CONNECTION_DELAY_INTERVAL_MS) + } + + private pickSubchannel(subchannel: Subchannel) { + if (this.currentPick !== null) { + this.currentPick.unref(); + this.currentPick.removeConnectivityStateListener(this.pickedSubchannelStateListener); + } + this.currentPick = subchannel; + this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); + subchannel.addConnectivityStateListener(this.pickedSubchannelStateListener); + subchannel.ref(); + this.resetSubchannelList(); + clearTimeout(this.connectionDelayTimeout); + } + + private updateState(newState: ConnectivityState, picker: Picker) { + this.currentState = newState; + this.channelControlHelper.updateState(newState, picker); + } + + private resetSubchannelList() { + for (const subchannel of this.subchannels) { + subchannel.unref(); + subchannel.removeConnectivityStateListener(this.subchannelStateListener); + } + this.currentSubchannelIndex = 0; + this.subchannelConnectingCount = 0; + this.subchannels = []; + } + + private connectToAddressList(): void { + this.resetSubchannelList(); + this.subchannels = this.latestAddressList.map((address) => this.channelControlHelper.createSubchannel(address, {})); + for (const subchannel of this.subchannels) { + subchannel.addConnectivityStateListener(this.subchannelStateListener); + if (subchannel.getConnectivityState() === SubchannelConnectivityState.READY) { + this.pickSubchannel(subchannel); + this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); + this.resetSubchannelList(); + return; + } + } + for (const [index, subchannel] of this.subchannels.entries()) { + const subchannelState = subchannel.getConnectivityState(); + if (subchannelState === SubchannelConnectivityState.IDLE || subchannelState === SubchannelConnectivityState.CONNECTING) { + this.startConnecting(index); + } + } + } + + updateAddressList(addressList: string[], lbConfig?: LoadBalancingConfig): void { + // lbConfig has no useful information for pick first load balancing + this.latestAddressList = addressList; + this.connectToAddressList(); + } + + exitIdle() { + if (this.currentState === ConnectivityState.IDLE) { + if (this.latestAddressList.length > 0) { + this.connectToAddressList(); + } + } + } + + resetBackoff() { + // I'm not actually sure what this is supposed to do + } + + destroy() { + this.resetSubchannelList(); + if (this.currentPick !== null) { + this.currentPick.unref(); + this.currentPick.removeConnectivityStateListener(this.pickedSubchannelStateListener); + } + } + + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup(): void { + registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer); +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts new file mode 100644 index 000000000..02f4ad4b8 --- /dev/null +++ b/packages/grpc-js/src/load-balancer.ts @@ -0,0 +1,107 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ChannelOptions } from "./channel-options"; +import { Subchannel } from "./subchannel"; +import { ConnectivityState } from "./channel"; +import { Picker } from "./picker"; +import { LoadBalancingConfig } from "./load-balancing-config"; + +/** + * A collection of functions associated with a channel that a load balancer + * can call as necessary. + */ +export interface ChannelControlHelper { + /** + * Returns a subchannel connected to the specified address. + * @param subchannelAddress The address to connect to + * @param subchannelArgs Extra channel arguments specified by the load balancer + */ + createSubchannel(subchannelAddress: String, subchannelArgs: ChannelOptions): Subchannel; + /** + * Passes a new subchannel picker up to the channel. This is called if either + * the connectivity state changes or if a different picker is needed for any + * other reason. + * @param connectivityState New connectivity state + * @param picker New picker + */ + updateState(connectivityState: ConnectivityState, picker: Picker): void; + /** + * Request new data from the resolver. + */ + requestReresolution(): void; +} + +/** + * Tracks one or more connected subchannels and determines which subchannel + * each request should use. + */ +export interface LoadBalancer { + /** + * Gives the load balancer a new list of addresses to start connecting to. + * The load balancer will start establishing connections with the new list, + * but will continue using any existing connections until the new connections + * are established + * @param addressList The new list of addresses to connect to + * @param lbConfig The load balancing config object from the service config, + * if one was provided + */ + updateAddressList(addressList: string[], lbConfig?: LoadBalancingConfig): void; + /** + * If the load balancer is currently in the IDLE state, start connecting. + */ + exitIdle(): void; + /** + * If the load balancer is currently in the CONNECTING or TRANSIENT_FAILURE + * state, reset the current connection backoff timeout to its base value and + * transition to CONNECTING if in TRANSIENT_FAILURE. + */ + resetBackoff(): void; + /** + * The load balancer unrefs all of its subchannels and stops calling methods + * of its channel control helper. + */ + destroy(): void; + /** + * Get the type name for this load balancer type. Must be constant across an + * entire load balancer implementation class and must match the name that the + * balancer implementation class was registered with. + */ + getTypeName(): string; +} + +export interface LoadBalancerConstructor { + new(channelControlHelper: ChannelControlHelper): LoadBalancer; +} + +const registeredLoadBalancerTypes: {[name: string]: LoadBalancerConstructor} = {}; + +export function registerLoadBalancerType(typeName: string, loadBalancerType: LoadBalancerConstructor) { + registeredLoadBalancerTypes[typeName] = loadBalancerType; +} + +export function createLoadBalancer(typeName: string, channelControlHelper: ChannelControlHelper): LoadBalancer | null { + if (typeName in registeredLoadBalancerTypes) { + return new registeredLoadBalancerTypes[typeName](channelControlHelper); + } else { + return null; + } +} + +export function isLoadBalancerNameRegistered(typeName: string): boolean { + return typeName in registeredLoadBalancerTypes; +} \ No newline at end of file diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts new file mode 100644 index 000000000..e2def2c46 --- /dev/null +++ b/packages/grpc-js/src/picker.ts @@ -0,0 +1,92 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Subchannel } from "./subchannel"; +import { StatusObject } from "./call-stream"; +import { Metadata } from "./metadata"; +import { Status } from "./constants"; +import { LoadBalancer } from "./load-balancer"; + +export enum PickResultType { + COMPLETE, + QUEUE, + TRANSIENT_FAILURE +} + +export interface PickResult { + pickResultType: PickResultType, + subchannel: Subchannel | null, + status: StatusObject | null +} + +export interface CompletePickResult extends PickResult { + pickResultType: PickResultType.COMPLETE, + subchannel: Subchannel | null, + status: null +} + +export interface QueuePickResult extends PickResult { + pickResultType: PickResultType.QUEUE, + subchannel: null, + status: null +} + +export interface TransientFailurePickResult extends PickResult { + pickResultType: PickResultType.TRANSIENT_FAILURE, + subchannel: null, + status: StatusObject +} + +export interface PickArgs { + metadata: Metadata +} + +export interface Picker { + pick(pickArgs: PickArgs): PickResult; +} + +export class UnavailablePicker implements Picker { + pick(pickArgs: PickArgs): TransientFailurePickResult { + return { + pickResultType: PickResultType.TRANSIENT_FAILURE, + subchannel: null, + status: { + code: Status.UNAVAILABLE, + details: "No connection established", + metadata: new Metadata() + } + }; + } +} + +export class QueuePicker { + private calledExitIdle: boolean = false; + // Constructed with a load balancer. Calls exitIdle on it the first time pick is called + constructor(private loadBalancer: LoadBalancer) {} + + pick(pickArgs: PickArgs): QueuePickResult { + if (!this.calledExitIdle) { + this.loadBalancer.exitIdle(); + this.calledExitIdle = true; + } + return { + pickResultType: PickResultType.QUEUE, + subchannel: null, + status: null + } + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index d556aebc1..f1e9ba8dd 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -18,6 +18,8 @@ import { Resolver, ResolverListener, registerResolver, registerDefaultResolver } import * as dns from 'dns'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; +import { ServiceError } from './call'; +import { Status } from './constants'; /* These regular expressions match IP addresses with optional ports in different * formats. In each case, capture group 1 contains the address, and capture @@ -113,14 +115,16 @@ class DnsResolver implements Resolver { this.pendingResultPromise = null; const allAddresses: string[] = mergeArrays(AAAArecord, Arecord); let serviceConfig: ServiceConfig | null = null; - let serviceConfigError: Error | null = null; + let serviceConfigError: ServiceError | null = null; if (TXTrecord instanceof Error) { - serviceConfigError = TXTrecord; + serviceConfigError = TXTrecord as ServiceError; + serviceConfigError.code = Status.UNAVAILABLE; } else { try { serviceConfig = extractAndSelectServiceConfig(TXTrecord, this.percentage); } catch (err) { - serviceConfigError = err; + serviceConfigError = err as ServiceError; + serviceConfigError.code = Status.UNAVAILABLE; } } this.listener.onSuccessfulResolution(allAddresses, serviceConfig, serviceConfigError); diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index e5519a9bf..10a485376 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -19,7 +19,7 @@ import { ServiceError } from "./call"; import { ServiceConfig } from "./service-config"; export interface ResolverListener { - onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: Error | null): void; + onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null): void; onError(error: ServiceError): void; } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts new file mode 100644 index 000000000..a403a2200 --- /dev/null +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -0,0 +1,92 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ChannelControlHelper, LoadBalancer, isLoadBalancerNameRegistered } from "./load-balancer"; +import { ServiceConfig } from "./service-config"; +import { ConnectivityState } from "./channel"; +import { createResolver, Resolver } from "./resolver"; +import { ServiceError } from "./call"; + +const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; + +export class ResolvingLoadBalancer { + private innerResolver: Resolver; + private innerLoadBalancer: LoadBalancer | null = null; + private pendingReplacementLoadBalancer: LoadBalancer | null = null; + private currentState: ConnectivityState = ConnectivityState.IDLE; + /** + * The service config object from the last successful resolution, if + * available. A value of undefined indicates that there has not yet + * been a successful resolution. A value of null indicates that the last + * successful resolution explicitly provided a null service config. + */ + private previousServiceConfig: ServiceConfig | null | undefined = undefined; + + constructor (private target: string, private channelControlHelper: ChannelControlHelper, private defaultServiceConfig: ServiceConfig | null) { + + this.innerResolver = createResolver(target, { + onSuccessfulResolution: (addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null) => { + let workingServiceConfig: ServiceConfig | null = null; + if (serviceConfig === null) { + if (serviceConfigError === null) { + this.previousServiceConfig = serviceConfig; + workingServiceConfig = this.defaultServiceConfig; + } else { + if (this.defaultServiceConfig === undefined) { + // resolution actually failed + } else { + workingServiceConfig = this.defaultServiceConfig; + } + } + } else { + workingServiceConfig = serviceConfig; + this.previousServiceConfig = serviceConfig; + } + let loadBalancerName: string | null = null; + if (workingServiceConfig === null || workingServiceConfig.loadBalancingConfig.length === 0) { + loadBalancerName = DEFAULT_LOAD_BALANCER_NAME; + } else { + for (const lbConfig of workingServiceConfig.loadBalancingConfig) { + for (const key in lbConfig) { + if (Object.prototype.hasOwnProperty.call(lbConfig, key)) { + if (isLoadBalancerNameRegistered(key)) { + loadBalancerName = key; + break; + } + } + } + if (loadBalancerName !== null) { + break; + } + } + if (loadBalancerName === null) { + // There were load balancing configs but none are supported. This counts as a resolution failure + // TODO: handle error + return; + } + } + }, + onError: (error: ServiceError) => { + this.handleResolutionFailure(error); + } + }); + } + + private handleResolutionFailure(error: ServiceError) { + + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts new file mode 100644 index 000000000..06b958276 --- /dev/null +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ChannelOptions, channelOptionsEqual } from "./channel-options"; +import { Subchannel } from "./subchannel"; +import { ChannelCredentials } from "./channel-credentials"; + +// 10 seconds in milliseconds. This value is arbitrary. +const REF_CHECK_INTERVAL = 10_000; + +export class SubchannelPool { + private pool: {[channelTarget: string]: {[subchannelTarget: string]: {channelArguments: ChannelOptions, channelCredentials: ChannelCredentials, subchannel: Subchannel}[]}} = Object.create(null); + + constructor(private global: boolean) { + if (global) { + setInterval(() => { + for (const channelTarget in this.pool) { + for (const subchannelTarget in this.pool[channelTarget]) { + const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; + /* For each subchannel in the pool, try to unref it if it has + * exactly one ref (which is the ref from the pool itself). If that + * does happen, remove the subchannel from the pool */ + this.pool[channelTarget][subchannelTarget] = subchannelObjArray.filter((value) => !value.subchannel.unrefIfOneRef()); + } + } + /* Currently we do not delete keys with empty values. If that results + * in significant memory usage we should change it. */ + }, REF_CHECK_INTERVAL).unref(); + // Unref because this timer should not keep the event loop running + } + } + + getOrCreateSubchannel(channelTarget: string, subchannelTarget: string, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials): Subchannel { + if (channelTarget in this.pool) { + if (subchannelTarget in this.pool[channelTarget]){ + const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; + for (const subchannelObj of subchannelObjArray) { + if (channelOptionsEqual(channelArguments, subchannelObj.channelArguments) && channelCredentials._equals(subchannelObj.channelCredentials)) { + return subchannelObj.subchannel; + } + } + } + } + // If we get here, no matching subchannel was found + const subchannel = new Subchannel(channelTarget, subchannelTarget, channelArguments, channelCredentials); + if (!(channelTarget in this.pool)) { + this.pool[channelTarget] = Object.create(null); + } + if (!(subchannelTarget in this.pool[channelTarget])) { + this.pool[channelTarget][subchannelTarget] = []; + } + this.pool[channelTarget][subchannelTarget].push({channelArguments, channelCredentials, subchannel}); + if (this.global) { + subchannel.ref(); + } + return subchannel; + } +} + +const globalSubchannelPool = new SubchannelPool(true); + +export function getOrCreateSubchannel(channelTarget: string, subchannelTarget: string, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials): Subchannel { + return globalSubchannelPool.getOrCreateSubchannel(channelTarget, subchannelTarget, channelArguments, channelCredentials); +} \ No newline at end of file diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index ac681d9f2..fce4a83f0 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -15,13 +15,35 @@ * */ -import { EventEmitter } from 'events'; import * as http2 from 'http2'; -import * as url from 'url'; - -import { Call, Http2CallStream } from './call-stream'; -import { ChannelOptions } from './channel-options'; +import { ChannelCredentials } from './channel-credentials'; import { Metadata } from './metadata'; +import { Http2CallStream } from './call-stream'; +import { ChannelOptions } from './channel-options'; +import { PeerCertificate, checkServerIdentity } from 'tls'; + +const { version: clientVersion } = require('../../package.json'); + +const MIN_CONNECT_TIMEOUT_MS = 20000; +const INITIAL_BACKOFF_MS = 1000; +const BACKOFF_MULTIPLIER = 1.6; +const MAX_BACKOFF_MS = 120000; +const BACKOFF_JITTER = 0.2; + +/* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't + * have a constant for the max signed 32 bit integer, so this is a simple way + * to calculate it */ +const KEEPALIVE_TIME_MS = ~(1 << 31); +const KEEPALIVE_TIMEOUT_MS = 20000; + +export enum SubchannelConnectivityState { + READY, + CONNECTING, + TRANSIENT_FAILURE, + IDLE +}; + +export type ConnectivityStateListener = (subchannel: Subchannel, previousState: SubchannelConnectivityState, newState: SubchannelConnectivityState) => void; const { HTTP2_HEADER_AUTHORITY, @@ -32,25 +54,21 @@ const { HTTP2_HEADER_USER_AGENT, } = http2.constants; -/* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't - * have a constant for the max signed 32 bit integer, so this is a simple way - * to calculate it */ -const KEEPALIVE_TIME_MS = ~(1 << 31); -const KEEPALIVE_TIMEOUT_MS = 20000; - -export interface SubChannel extends EventEmitter { - /** - * Attach a call stream to this subchannel's connection to start it - * @param headers The headers to start the stream with - * @param callStream The stream to start - */ - startCallStream(metadata: Metadata, callStream: Call): void; - close(): void; +function uniformRandom(min: number, max: number) { + return Math.random() * (max - min) + min; } -export class Http2SubChannel extends EventEmitter implements SubChannel { - private session: http2.ClientHttp2Session; - private refCount = 0; +export class Subchannel { + private connectivityState: SubchannelConnectivityState = SubchannelConnectivityState.IDLE; + private session: http2.ClientHttp2Session | null = null; + // Indicates that we should continue conection attempts after backoff time ends + private continueConnecting: boolean = false; + private stateListeners: ConnectivityStateListener[] = []; + + private backoffTimerId: NodeJS.Timer; + // The backoff value that will be used the next time we try to connect + private nextBackoff: number = INITIAL_BACKOFF_MS; + private userAgent: string; private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; @@ -58,73 +76,80 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { private keepaliveIntervalId: NodeJS.Timer; private keepaliveTimeoutId: NodeJS.Timer; - constructor( - target: url.URL, - connectionOptions: http2.SecureClientSessionOptions, - userAgent: string, - channelArgs: Partial - ) { - super(); - this.session = http2.connect(target, connectionOptions); - this.session.unref(); - this.session.on('connect', () => { - this.emit('connect'); - }); - this.session.on('close', () => { - this.stopKeepalivePings(); - this.emit('close'); - }); - this.session.on('error', () => { - this.stopKeepalivePings(); - this.emit('close'); - }); - this.session.on('goaway', () => { - this.stopKeepalivePings(); - this.emit('close'); - }); - this.userAgent = userAgent; + /** + * Tracks calls with references to this subchannel + */ + private callRefcount: number = 0; + /** + * Tracks channels and subchannel pools with references to this subchannel + */ + private refcount: number = 0; - if (channelArgs['grpc.keepalive_time_ms']) { - this.keepaliveTimeMs = channelArgs['grpc.keepalive_time_ms']!; - } - if (channelArgs['grpc.keepalive_timeout_ms']) { - this.keepaliveTimeoutMs = channelArgs['grpc.keepalive_timeout_ms']!; - } - this.keepaliveIntervalId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveIntervalId); - this.keepaliveTimeoutId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveTimeoutId); - } + constructor(private channelTarget: string, + private subchannelAddress: string, + private options: ChannelOptions, + private credentials: ChannelCredentials) { + // Build user-agent string. + this.userAgent = [ + options['grpc.primary_user_agent'], + `grpc-node-js/${clientVersion}`, + options['grpc.secondary_user_agent'], + ] + .filter(e => e) + .join(' '); // remove falsey values first - private ref() { - if (this.refCount === 0) { - this.session.ref(); - this.startKeepalivePings(); + /* The only purpose of these lines is to ensure that this.backoffTimerId has + * a value of type NodeJS.Timer. */ + this.backoffTimerId = setTimeout(() => {}, 0); + clearTimeout(this.backoffTimerId); + + if ('grpc.keepalive_time_ms' in options) { + this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; + } + if ('grpc.keepalive_timeout_ms' in options) { + this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; + } + this.keepaliveIntervalId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveIntervalId); + this.keepaliveTimeoutId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveTimeoutId); } - this.refCount += 1; + + /** + * Start a backoff timer with the current nextBackoff timeout + */ + private startBackoff() { + this.backoffTimerId = setTimeout(() => { + + if (this.continueConnecting) { + this.transitionToState([SubchannelConnectivityState.TRANSIENT_FAILURE, SubchannelConnectivityState.CONNECTING], + SubchannelConnectivityState.CONNECTING); + } else { + this.transitionToState([SubchannelConnectivityState.TRANSIENT_FAILURE, SubchannelConnectivityState.CONNECTING], + SubchannelConnectivityState.IDLE); + } + }, this.nextBackoff) + const nextBackoff = Math.min(this.nextBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); + const jitterMagnitude = nextBackoff * BACKOFF_JITTER; + this.nextBackoff = nextBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude); } - private unref() { - this.refCount -= 1; - if (this.refCount === 0) { - this.session.unref(); - this.stopKeepalivePings(); - } + private stopBackoff() { + clearTimeout(this.backoffTimerId); + this.nextBackoff = INITIAL_BACKOFF_MS; } private sendPing() { this.keepaliveTimeoutId = setTimeout(() => { - this.emit('close'); + // Not sure what to do when keepalive pings fail }, this.keepaliveTimeoutMs); - this.session.ping( + this.session!.ping( (err: Error | null, duration: number, payload: Buffer) => { clearTimeout(this.keepaliveTimeoutId); } ); } - /* TODO(murgatroid99): refactor subchannels so that keepalives can be handled - * per subchannel */ private startKeepalivePings() { this.keepaliveIntervalId = setInterval(() => { this.sendPing(); @@ -137,7 +162,133 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { clearTimeout(this.keepaliveTimeoutId); } - // Prerequisite: this subchannel is connected + private startConnectingInternal() { + const connectionOptions: http2.SecureClientSessionOptions = + this.credentials._getConnectionOptions() || {}; + if (connectionOptions.secureContext !== null) { + // If provided, the value of grpc.ssl_target_name_override should be used + // to override the target hostname when checking server identity. + // This option is used for testing only. + if (this.options['grpc.ssl_target_name_override']) { + const sslTargetNameOverride = this.options[ + 'grpc.ssl_target_name_override' + ]!; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; + connectionOptions.servername = sslTargetNameOverride; + } + } + this.session = http2.connect(this.subchannelAddress, connectionOptions); + this.session.unref(); + this.session.once('connect', () => { + this.transitionToState([SubchannelConnectivityState.CONNECTING], SubchannelConnectivityState.READY); + }); + this.session.once('close', () => { + this.transitionToState([SubchannelConnectivityState.CONNECTING, SubchannelConnectivityState.READY], + SubchannelConnectivityState.TRANSIENT_FAILURE); + }); + this.session.once('goaway', () => { + this.transitionToState([SubchannelConnectivityState.CONNECTING, SubchannelConnectivityState.READY], + SubchannelConnectivityState.IDLE); + }); + } + + /** + * Initiate a state transition from any element of oldStates to the new + * state. If the current connectivityState is not in oldStates, do nothing. + * @param oldStates The set of states to transition from + * @param newState The state to transition to + * @returns True if the state changed, false otherwise + */ + private transitionToState( + oldStates: SubchannelConnectivityState[], + newState: SubchannelConnectivityState + ): boolean { + if (oldStates.indexOf(this.connectivityState) === -1) { + return false; + } + let previousState = this.connectivityState; + this.connectivityState = newState; + switch (newState) { + case SubchannelConnectivityState.READY: + this.stopBackoff(); + break; + case SubchannelConnectivityState.CONNECTING: + this.startBackoff(); + this.startConnectingInternal(); + this.continueConnecting = false; + break; + case SubchannelConnectivityState.TRANSIENT_FAILURE: + this.session = null; + break; + case SubchannelConnectivityState.IDLE: + /* Stopping the backoff timer here is probably redundant because we + * should only transition to the IDLE state as a result of the timer + * ending, but we still want to reset the backoff timeout. */ + this.stopBackoff(); + this.session = null; + } + /* We use a shallow copy of the stateListeners array in case a listener + * is removed during this iteration */ + for (const listener of [...this.stateListeners]) { + listener(this, previousState, newState); + } + return true; + } + + private checkBothRefcounts() { + /* If no calls, channels, or subchannel pools have any more references to + * this subchannel, we can be sure it will never be used again. */ + if (this.callRefcount === 0 && this.refcount === 0) { + this.transitionToState([SubchannelConnectivityState.CONNECTING, + SubchannelConnectivityState.IDLE, + SubchannelConnectivityState.READY], + SubchannelConnectivityState.TRANSIENT_FAILURE); + } + } + + private callRef() { + if (this.callRefcount === 0) { + if (this.session) { + this.session.ref(); + } + this.startKeepalivePings(); + } + this.callRefcount += 1; + } + + private callUnref() { + this.callRefcount -= 1; + if (this.callRefcount === 0) { + if (this.session) { + this.session.unref(); + } + this.stopKeepalivePings(); + this.checkBothRefcounts(); + } + } + + ref() { + this.refcount += 1; + } + + unref() { + this.refcount -= 1; + this.checkBothRefcounts(); + } + + unrefIfOneRef(): boolean { + if (this.refcount === 1) { + this.unref(); + return true; + } + return false; + } + startCallStream(metadata: Metadata, callStream: Http2CallStream) { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); @@ -146,15 +297,43 @@ export class Http2SubChannel extends EventEmitter implements SubChannel { headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = callStream.getMethod(); headers[HTTP2_HEADER_TE] = 'trailers'; - const http2Stream = this.session.request(headers); - this.ref(); + const http2Stream = this.session!.request(headers); + this.callRef(); http2Stream.on('close', () => { - this.unref(); + this.callUnref(); }); callStream.attachHttp2Stream(http2Stream); } - close() { - this.session.close(); + startConnecting() { + /* First, try to transition from IDLE to connecting. If that doesn't happen + * because the state is not currently IDLE, check if it is + * TRANSIENT_FAILURE, and if so indicate that it should go back to + * connecting after the backoff timer ends. Otherwise do nothing */ + if (!this.transitionToState([SubchannelConnectivityState.IDLE], SubchannelConnectivityState.CONNECTING)) { + if (this.connectivityState === SubchannelConnectivityState.TRANSIENT_FAILURE) { + this.continueConnecting = true; + } + } } -} + + getConnectivityState() { + return this.connectivityState; + } + + addConnectivityStateListener(listener: ConnectivityStateListener) { + this.stateListeners.push(listener); + } + + removeConnectivityStateListener(listener: ConnectivityStateListener) { + const listenerIndex = this.stateListeners.indexOf(listener); + if (listenerIndex > -1) { + this.stateListeners.splice(listenerIndex, 1); + } + } + + resetBackoff() { + this.nextBackoff = INITIAL_BACKOFF_MS; + this.transitionToState([SubchannelConnectivityState.TRANSIENT_FAILURE], SubchannelConnectivityState.CONNECTING); + } +} \ No newline at end of file From 96d9f2951c84b2b0849315cce5c4a006104be9c5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 13 Aug 2019 10:13:17 -0700 Subject: [PATCH 0737/1899] Add Electron 6 to the artifact build list --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 89e387300..229d0f42d 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index 72c9b36f7..a226a5a98 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 ) umask 022 From fb2e7637c0c56185aa7676d2c1c63a97705d458b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 13 Aug 2019 17:58:54 -0700 Subject: [PATCH 0738/1899] Update channel behavior + related classes --- .../grpc-js/src/call-credentials-filter.ts | 11 +- packages/grpc-js/src/call-stream.ts | 19 +- packages/grpc-js/src/channel.ts | 509 ++++++------------ packages/grpc-js/src/deadline-filter.ts | 6 +- .../grpc-js/src/load-balancer-pick-first.ts | 6 +- packages/grpc-js/src/load-balancer.ts | 9 +- packages/grpc-js/src/metadata.ts | 15 +- packages/grpc-js/src/resolver-dns.ts | 6 +- packages/grpc-js/src/resolver.ts | 10 + .../grpc-js/src/resolving-load-balancer.ts | 138 ++++- packages/grpc-js/src/subchannel-pool.ts | 8 +- 11 files changed, 347 insertions(+), 390 deletions(-) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index e3d842378..a58f10ee1 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -17,14 +17,14 @@ import { CallCredentials } from './call-credentials'; import { Call } from './call-stream'; -import { Http2Channel } from './channel'; +import { Channel } from './channel'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; constructor( - private readonly channel: Http2Channel, + private readonly channel: Channel, private readonly stream: Call ) { super(); @@ -44,9 +44,7 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { } async sendMetadata(metadata: Promise): Promise { - const channelCredentials = this.channel.credentials._getCallCredentials(); - const streamCredentials = this.stream.getCredentials(); - const credentials = channelCredentials.compose(streamCredentials); + const credentials = this.stream.getCredentials(); const credsMetadata = credentials.generateMetadata({ service_url: this.serviceUrl, }); @@ -58,8 +56,7 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { export class CallCredentialsFilterFactory implements FilterFactory { - private readonly channel: Http2Channel; - constructor(channel: Http2Channel) { + constructor(private readonly channel: Channel) { this.channel = channel; } diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 35b957b3d..714586002 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -19,7 +19,6 @@ import * as http2 from 'http2'; import { Duplex } from 'stream'; import { CallCredentials } from './call-credentials'; -import { Http2Channel } from './channel'; import { Status } from './constants'; import { EmitterAugmentation1 } from './events'; import { Filter } from './filter'; @@ -27,6 +26,7 @@ import { FilterStackFactory } from './filter-stack'; import { Metadata } from './metadata'; import { ObjectDuplex, WriteCallback } from './object-stream'; import { StreamDecoder } from './stream-decoder'; +import { ChannelImplementation } from './channel'; const { HTTP2_HEADER_STATUS, @@ -83,7 +83,7 @@ export type Call = { ObjectDuplex; export class Http2CallStream extends Duplex implements Call { - credentials: CallCredentials = CallCredentials.createEmpty(); + credentials: CallCredentials; filterStack: Filter; private http2Stream: http2.ClientHttp2Stream | null = null; private pendingRead = false; @@ -114,12 +114,14 @@ export class Http2CallStream extends Duplex implements Call { constructor( private readonly methodName: string, - private readonly channel: Http2Channel, + private readonly channel: ChannelImplementation, private readonly options: CallStreamOptions, - filterStackFactory: FilterStackFactory + filterStackFactory: FilterStackFactory, + private readonly channelCallCredentials: CallCredentials ) { super({ objectMode: true }); this.filterStack = filterStackFactory.createFilter(this); + this.credentials = channelCallCredentials; } /** @@ -358,12 +360,7 @@ export class Http2CallStream extends Duplex implements Call { } sendMetadata(metadata: Metadata): void { - this.channel._startHttp2Stream( - this.options.host, - this.methodName, - this, - metadata - ); + this.channel._startCallStream(this, metadata); } private destroyHttp2Stream() { @@ -395,7 +392,7 @@ export class Http2CallStream extends Duplex implements Call { } setCredentials(credentials: CallCredentials): void { - this.credentials = credentials; + this.credentials = this.channelCallCredentials.compose(credentials); } getStatus(): StatusObject | null { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 68ba66e90..636750a1f 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -15,44 +15,22 @@ * */ -import { EventEmitter } from 'events'; -import * as http2 from 'http2'; -import { checkServerIdentity, PeerCertificate } from 'tls'; -import * as url from 'url'; - -import { CallCredentialsFilterFactory } from './call-credentials-filter'; -import { - Call, - CallStreamOptions, - Deadline, - Http2CallStream, -} from './call-stream'; -import { ChannelCredentials } from './channel-credentials'; -import { ChannelOptions, recognizedOptions } from './channel-options'; -import { CompressionFilterFactory } from './compression-filter'; -import { Status } from './constants'; -import { DeadlineFilterFactory } from './deadline-filter'; -import { FilterStackFactory } from './filter-stack'; -import { Metadata } from './metadata'; -import { MetadataStatusFilterFactory } from './metadata-status-filter'; -import { Http2SubChannel } from './subchannel'; - -const { version: clientVersion } = require('../../package.json'); - -const MIN_CONNECT_TIMEOUT_MS = 20000; -const INITIAL_BACKOFF_MS = 1000; -const BACKOFF_MULTIPLIER = 1.6; -const MAX_BACKOFF_MS = 120000; -const BACKOFF_JITTER = 0.2; - -const { - HTTP2_HEADER_AUTHORITY, - HTTP2_HEADER_CONTENT_TYPE, - HTTP2_HEADER_METHOD, - HTTP2_HEADER_PATH, - HTTP2_HEADER_TE, - HTTP2_HEADER_USER_AGENT, -} = http2.constants; +import { Deadline, Call, Http2CallStream, CallStreamOptions } from "./call-stream"; +import { ChannelCredentials } from "./channel-credentials"; +import { ChannelOptions } from "./channel-options"; +import { ResolvingLoadBalancer } from "./resolving-load-balancer"; +import { SubchannelPool, getSubchannelPool } from "./subchannel-pool"; +import { ChannelControlHelper } from "./load-balancer"; +import { UnavailablePicker, Picker, PickResultType } from "./picker"; +import { Metadata } from "./metadata"; +import { SubchannelConnectivityState } from "./subchannel"; +import { Status } from "./constants"; +import { FilterStackFactory } from "./filter-stack"; +import { CallCredentialsFilterFactory } from "./call-credentials-filter"; +import { DeadlineFilterFactory } from "./deadline-filter"; +import { MetadataStatusFilterFactory } from "./metadata-status-filter"; +import { CompressionFilterFactory } from "./compression-filter"; +import { getDefaultAuthority } from "./resolver"; export enum ConnectivityState { CONNECTING, @@ -62,13 +40,6 @@ export enum ConnectivityState { SHUTDOWN, } -function uniformRandom(min: number, max: number) { - return Math.random() * (max - min) + min; -} - -// todo: maybe we want an interface for load balancing, but no implementation -// for anything complicated - /** * An interface that represents a communication channel to a server specified * by a given address. @@ -128,240 +99,159 @@ export interface Channel { ): Call; } -export class Http2Channel extends EventEmitter implements Channel { - private readonly userAgent: string; - private readonly target: url.URL; - private readonly defaultAuthority: string; +interface ConnectivityStateWatcher { + currentState: ConnectivityState; + timer: NodeJS.Timeout; + callback: (error?: Error) => void; +} + +export class ChannelImplementation implements Channel { + private resolvingLoadBalancer: ResolvingLoadBalancer; + private subchannelPool: SubchannelPool; private connectivityState: ConnectivityState = ConnectivityState.IDLE; - // Helper Promise object only used in the implementation of connect(). - private connecting: Promise | null = null; - /* For now, we have up to one subchannel, which will exist as long as we are - * connecting or trying to connect */ - private subChannel: Http2SubChannel | null = null; + private currentPicker: Picker = new UnavailablePicker(); + private pickQueue: {callStream: Http2CallStream, callMetadata: Metadata}[] = []; + private connectivityStateWatchers: ConnectivityStateWatcher[] = []; + private defaultAuthority: string; private filterStackFactory: FilterStackFactory; + constructor(private target: string, private readonly credentials: ChannelCredentials, private readonly options: ChannelOptions) { + // TODO: check channel arg for getting a private pool + this.subchannelPool = getSubchannelPool(true); + const channelControlHelper: ChannelControlHelper = { + createSubchannel: (subchannelAddress: string, subchannelArgs: ChannelOptions) => { + return this.subchannelPool.getOrCreateSubchannel(this.target, subchannelAddress, Object.assign({}, this.options, subchannelArgs), this.credentials); + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + this.currentPicker = picker; + const queueCopy = this.pickQueue.slice(); + this.pickQueue = []; + for (const {callStream, callMetadata} of queueCopy) { + this.tryPick(callStream, callMetadata); + } + this.updateState(connectivityState); + }, + requestReresolution: () => { + // This should never be called. + throw new Error('Resolving load balancer should never call requestReresolution'); + } + }; + // TODO: check channel arg for default service config + this.resolvingLoadBalancer = new ResolvingLoadBalancer(target, channelControlHelper, null); + this.filterStackFactory = new FilterStackFactory([ + new CallCredentialsFilterFactory(this), + new DeadlineFilterFactory(this), + new MetadataStatusFilterFactory(this), + new CompressionFilterFactory(this), + ]); + // TODO(murgatroid99): Add more centralized handling of channel options + if (this.options['grpc.default_authority']) { + this.defaultAuthority = this.options['grpc.default_authority'] as string; + } else { + this.defaultAuthority = getDefaultAuthority(target); + } + } - private subChannelConnectCallback: () => void = () => {}; - private subChannelCloseCallback: () => void = () => {}; - - private backoffTimerId: NodeJS.Timer; - private currentBackoff: number = INITIAL_BACKOFF_MS; - private currentBackoffDeadline: Date; - - private handleStateChange( - oldState: ConnectivityState, - newState: ConnectivityState - ): void { - const now: Date = new Date(); - switch (newState) { - case ConnectivityState.CONNECTING: - if (oldState === ConnectivityState.IDLE) { - this.currentBackoff = INITIAL_BACKOFF_MS; - this.currentBackoffDeadline = new Date( - now.getTime() + INITIAL_BACKOFF_MS - ); - } else if (oldState === ConnectivityState.TRANSIENT_FAILURE) { - this.currentBackoff = Math.min( - this.currentBackoff * BACKOFF_MULTIPLIER, - MAX_BACKOFF_MS - ); - const jitterMagnitude: number = BACKOFF_JITTER * this.currentBackoff; - this.currentBackoffDeadline = new Date( - now.getTime() + - this.currentBackoff + - uniformRandom(-jitterMagnitude, jitterMagnitude) - ); + /** + * Check the picker output for the given call and corresponding metadata, + * and take any relevant actions. Should not be called while iterating + * over pickQueue. + * @param callStream + * @param callMetadata + */ + private tryPick(callStream: Http2CallStream, callMetadata: Metadata) { + const pickResult = this.currentPicker.pick({metadata: callMetadata}); + switch(pickResult.pickResultType) { + case PickResultType.COMPLETE: + if (pickResult.subchannel === null) { + // End the call with an error + } else { + /* If the subchannel disconnects between calling pick and getting + * the filter stack metadata, the call will end with an error. */ + callStream.filterStack.sendMetadata(Promise.resolve(new Metadata())).then((finalMetadata) => { + if (pickResult.subchannel!.getConnectivityState() === SubchannelConnectivityState.READY) { + pickResult.subchannel!.startCallStream(callMetadata, callStream); + } else { + callStream.cancelWithStatus(Status.UNAVAILABLE, 'Connection dropped while starting call'); + } + }, + (error: Error & { code: number }) => { + // We assume the error code isn't 0 (Status.OK) + callStream.cancelWithStatus( + error.code || Status.UNKNOWN, + `Getting metadata from plugin failed with error: ${error.message}` + ); + }); } - this.startConnecting(); break; - case ConnectivityState.READY: - this.emit('connect'); + case PickResultType.QUEUE: + this.pickQueue.push({callStream, callMetadata}); break; - case ConnectivityState.TRANSIENT_FAILURE: - this.subChannel = null; - this.backoffTimerId = setTimeout(() => { - this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE], - ConnectivityState.CONNECTING - ); - }, this.currentBackoffDeadline.getTime() - now.getTime()); - break; - case ConnectivityState.IDLE: - case ConnectivityState.SHUTDOWN: - if (this.subChannel) { - this.subChannel.close(); - this.subChannel.removeListener( - 'connect', - this.subChannelConnectCallback - ); - this.subChannel.removeListener('close', this.subChannelCloseCallback); - this.subChannel = null; - this.emit('shutdown'); - clearTimeout(this.backoffTimerId); + case PickResultType.TRANSIENT_FAILURE: + if (callMetadata.getOptions().waitForReady) { + this.pickQueue.push({callStream, callMetadata}); + } else { + callStream.cancelWithStatus(pickResult.status!.code, pickResult.status!.details); } break; - default: - throw new Error('This should never happen'); } } - // Transition from any of a set of oldStates to a specific newState - private transitionToState( - oldStates: ConnectivityState[], - newState: ConnectivityState - ): void { - if (oldStates.indexOf(this.connectivityState) > -1) { - const oldState: ConnectivityState = this.connectivityState; - this.connectivityState = newState; - this.handleStateChange(oldState, newState); - this.emit('connectivityStateChanged', newState); + private removeConnectivityStateWatcher(watcherObject: ConnectivityStateWatcher) { + const watcherIndex = this.connectivityStateWatchers.findIndex((value) => value === watcherObject); + if (watcherIndex >= 0) { + this.connectivityStateWatchers.splice(watcherIndex, 1); } } - private startConnecting(): void { - const connectionOptions: http2.SecureClientSessionOptions = - this.credentials._getConnectionOptions() || {}; - if (connectionOptions.secureContext !== null) { - // If provided, the value of grpc.ssl_target_name_override should be used - // to override the target hostname when checking server identity. - // This option is used for testing only. - if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = this.options[ - 'grpc.ssl_target_name_override' - ]!; - connectionOptions.checkServerIdentity = ( - host: string, - cert: PeerCertificate - ): Error | undefined => { - return checkServerIdentity(sslTargetNameOverride, cert); - }; - connectionOptions.servername = sslTargetNameOverride; + private updateState(newState: ConnectivityState): void { + this.connectivityState = newState; + const watchersCopy = this.connectivityStateWatchers.slice(); + for (const watcherObject of watchersCopy) { + if (newState !== watcherObject.currentState) { + watcherObject.callback(); + clearTimeout(watcherObject.timer); + this.removeConnectivityStateWatcher(watcherObject); } } - const subChannel: Http2SubChannel = new Http2SubChannel( - this.target, - connectionOptions, - this.userAgent, - this.options - ); - this.subChannel = subChannel; - const now = new Date(); - const connectionTimeout: number = Math.max( - this.currentBackoffDeadline.getTime() - now.getTime(), - MIN_CONNECT_TIMEOUT_MS - ); - const connectionTimerId: NodeJS.Timer = setTimeout(() => { - // This should trigger the 'close' event, which will send us back to - // TRANSIENT_FAILURE - subChannel.close(); - }, connectionTimeout); - this.subChannelConnectCallback = () => { - // Connection succeeded - clearTimeout(connectionTimerId); - this.transitionToState( - [ConnectivityState.CONNECTING], - ConnectivityState.READY - ); - }; - subChannel.once('connect', this.subChannelConnectCallback); - this.subChannelCloseCallback = () => { - // Connection failed - clearTimeout(connectionTimerId); - /* TODO(murgatroid99): verify that this works for - * CONNECTING->TRANSITIVE_FAILURE see nodejs/node#16645 */ - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE - ); - }; - subChannel.once('close', this.subChannelCloseCallback); } - constructor( - address: string, - readonly credentials: ChannelCredentials, - private readonly options: Partial - ) { - super(); - for (const option in options) { - if (options.hasOwnProperty(option)) { - if (!recognizedOptions.hasOwnProperty(option)) { - console.warn( - `Unrecognized channel argument '${option}' will be ignored.` - ); - } - } - } - if (credentials._isSecure()) { - this.target = new url.URL(`https://${address}`); - } else { - this.target = new url.URL(`http://${address}`); - } - // TODO(murgatroid99): Add more centralized handling of channel options - if (this.options['grpc.default_authority']) { - this.defaultAuthority = this.options['grpc.default_authority'] as string; - } else { - this.defaultAuthority = this.target.host; - } - this.filterStackFactory = new FilterStackFactory([ - new CallCredentialsFilterFactory(this), - new DeadlineFilterFactory(this), - new MetadataStatusFilterFactory(this), - new CompressionFilterFactory(this), - ]); - this.currentBackoffDeadline = new Date(); - /* The only purpose of these lines is to ensure that this.backoffTimerId has - * a value of type NodeJS.Timer. */ - this.backoffTimerId = setTimeout(() => {}, 0); + _startCallStream(stream: Http2CallStream, metadata: Metadata) { + this.tryPick(stream, metadata); + } - // Build user-agent string. - this.userAgent = [ - options['grpc.primary_user_agent'], - `grpc-node-js/${clientVersion}`, - options['grpc.secondary_user_agent'], - ] - .filter(e => e) - .join(' '); // remove falsey values first + close() { + this.resolvingLoadBalancer.destroy(); + this.updateState(ConnectivityState.SHUTDOWN); } - _startHttp2Stream( - authority: string, - methodName: string, - stream: Http2CallStream, - metadata: Metadata - ) { - const connectMetadata: Promise = this.connect().then(() => - metadata.clone() - ); - const finalMetadata: Promise = stream.filterStack.sendMetadata( - connectMetadata - ); - finalMetadata - .then(metadataValue => { - const headers = metadataValue.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = authority; - headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; - headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; - headers[HTTP2_HEADER_METHOD] = 'POST'; - headers[HTTP2_HEADER_PATH] = methodName; - headers[HTTP2_HEADER_TE] = 'trailers'; - if (this.connectivityState === ConnectivityState.READY) { - const subChannel: Http2SubChannel = this.subChannel!; - subChannel.startCallStream(metadataValue, stream); - } else { - /* In this case, we lost the connection while finalizing - * metadata. That should be very unusual */ - setImmediate(() => { - this._startHttp2Stream(authority, methodName, stream, metadata); - }); - } - }) - .catch((error: Error & { code: number }) => { - // We assume the error code isn't 0 (Status.OK) - stream.cancelWithStatus( - error.code || Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${error.message}` - ); - }); + getTarget() { + return this.target; + } + + getConnectivityState() { + return this.connectivityState; + } + + watchConnectivityState( + currentState: ConnectivityState, + deadline: Date | number, + callback: (error?: Error) => void + ): void { + const deadlineDate: Date = deadline instanceof Date ? deadline : new Date(deadline); + const now = new Date(); + if (deadlineDate <= now) { + process.nextTick(callback, new Error('Deadline passed without connectivity state change')); + return; + } + const watcherObject = { + currentState, + callback, + timer: setTimeout(() => { + this.removeConnectivityStateWatcher(watcherObject); + callback(new Error('Deadline passed without connectivity state change')); + }, deadlineDate.getTime() - now.getTime()) + }; + this.connectivityStateWatchers.push(watcherObject); } createCall( @@ -385,106 +275,9 @@ export class Http2Channel extends EventEmitter implements Channel { method, this, finalOptions, - this.filterStackFactory + this.filterStackFactory, + this.credentials._getCallCredentials() ); return stream; } - - /** - * Attempts to connect, returning a Promise that resolves when the connection - * is successful, or rejects if the channel is shut down. - */ - private connect(): Promise { - if (this.connectivityState === ConnectivityState.READY) { - return Promise.resolve(); - } else if (this.connectivityState === ConnectivityState.SHUTDOWN) { - return Promise.reject(new Error('Channel has been shut down')); - } else { - // In effect, this.connecting is only assigned upon the first attempt to - // transition from IDLE to CONNECTING, so this condition could have also - // been (connectivityState === IDLE). - if (!this.connecting) { - this.connecting = new Promise((resolve, reject) => { - this.transitionToState( - [ConnectivityState.IDLE], - ConnectivityState.CONNECTING - ); - const onConnect = () => { - this.connecting = null; - this.removeListener('shutdown', onShutdown); - resolve(); - }; - const onShutdown = () => { - this.connecting = null; - this.removeListener('connect', onConnect); - reject(new Error('Channel has been shut down')); - }; - this.once('connect', onConnect); - this.once('shutdown', onShutdown); - }); - } - return this.connecting; - } - } - - getConnectivityState(tryToConnect: boolean): ConnectivityState { - if (tryToConnect) { - this.transitionToState( - [ConnectivityState.IDLE], - ConnectivityState.CONNECTING - ); - } - return this.connectivityState; - } - - watchConnectivityState( - currentState: ConnectivityState, - deadline: Date | number, - callback: (error?: Error) => void - ) { - if (this.connectivityState !== currentState) { - /* If the connectivity state is different from the provided currentState, - * we assume that a state change has successfully occurred */ - setImmediate(callback); - } else { - let deadlineMs = 0; - if (deadline instanceof Date) { - deadlineMs = deadline.getTime(); - } else { - deadlineMs = deadline; - } - let timeout: number = deadlineMs - Date.now(); - if (timeout < 0) { - timeout = 0; - } - const timeoutId = setTimeout(() => { - this.removeListener('connectivityStateChanged', eventCb); - callback(new Error('Channel state did not change before deadline')); - }, timeout); - const eventCb = () => { - clearTimeout(timeoutId); - callback(); - }; - this.once('connectivityStateChanged', eventCb); - } - } - - getTarget() { - return this.target.toString(); - } - - close() { - if (this.connectivityState === ConnectivityState.SHUTDOWN) { - throw new Error('Channel has been shut down'); - } - this.transitionToState( - [ - ConnectivityState.CONNECTING, - ConnectivityState.READY, - ConnectivityState.TRANSIENT_FAILURE, - ConnectivityState.IDLE, - ], - ConnectivityState.SHUTDOWN - ); - } -} +} \ No newline at end of file diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 771cb96ac..5c3cf532d 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -16,7 +16,7 @@ */ import { Call } from './call-stream'; -import { ConnectivityState, Http2Channel } from './channel'; +import { ConnectivityState, Channel } from './channel'; import { Status } from './constants'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; @@ -44,7 +44,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { private timer: NodeJS.Timer | null = null; private deadline: number; constructor( - private readonly channel: Http2Channel, + private readonly channel: Channel, private readonly callStream: Call ) { super(); @@ -85,7 +85,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { } export class DeadlineFilterFactory implements FilterFactory { - constructor(private readonly channel: Http2Channel) {} + constructor(private readonly channel: Channel) {} createFilter(callStream: Call): DeadlineFilter { return new DeadlineFilter(this.channel, callStream); diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 1fbbf4250..a07c857ed 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -162,7 +162,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { } } - updateAddressList(addressList: string[], lbConfig?: LoadBalancingConfig): void { + updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void { // lbConfig has no useful information for pick first load balancing this.latestAddressList = addressList; this.connectToAddressList(); @@ -191,6 +191,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { getTypeName(): string { return TYPE_NAME; } + + replaceChannelControlHelper(channelControlHelper: ChannelControlHelper) { + this.channelControlHelper = channelControlHelper; + } } export function setup(): void { diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 02f4ad4b8..14aa3e47b 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -31,7 +31,7 @@ export interface ChannelControlHelper { * @param subchannelAddress The address to connect to * @param subchannelArgs Extra channel arguments specified by the load balancer */ - createSubchannel(subchannelAddress: String, subchannelArgs: ChannelOptions): Subchannel; + createSubchannel(subchannelAddress: string, subchannelArgs: ChannelOptions): Subchannel; /** * Passes a new subchannel picker up to the channel. This is called if either * the connectivity state changes or if a different picker is needed for any @@ -60,7 +60,7 @@ export interface LoadBalancer { * @param lbConfig The load balancing config object from the service config, * if one was provided */ - updateAddressList(addressList: string[], lbConfig?: LoadBalancingConfig): void; + updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void; /** * If the load balancer is currently in the IDLE state, start connecting. */ @@ -82,6 +82,11 @@ export interface LoadBalancer { * balancer implementation class was registered with. */ getTypeName(): string; + /** + * Replace the existing ChannelControlHelper with a new one + * @param channelControlHelper The new ChannelControlHelper to use from now on + */ + replaceChannelControlHelper(channelControlHelper: ChannelControlHelper): void; } export interface LoadBalancerConstructor { diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index d321b9b0e..4f0ed14dc 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -62,7 +62,7 @@ function validate(key: string, value?: MetadataValue): void { } } -interface MetadataOptions { +export interface MetadataOptions { /* Signal that the request is idempotent. Defaults to false */ idempotentRequest?: boolean; /* Signal that the call should not return UNAVAILABLE before it has @@ -80,8 +80,15 @@ interface MetadataOptions { */ export class Metadata { protected internalRepr: MetadataObject = new Map(); + private options: MetadataOptions; - constructor(private options?: MetadataOptions) {} + constructor(options?: MetadataOptions) { + if (options === undefined) { + this.options = {}; + } else { + this.options = options; + } + } /** * Sets the given value for the given key by replacing any other values @@ -200,6 +207,10 @@ export class Metadata { this.options = options; } + getOptions(): MetadataOptions { + return this.options; + } + /** * Creates an OutgoingHttpHeaders object that can be used with the http2 API. */ diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index f1e9ba8dd..52b8893b2 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -20,6 +20,7 @@ import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; import { ServiceError } from './call'; import { Status } from './constants'; +import { URL } from 'url'; /* These regular expressions match IP addresses with optional ports in different * formats. In each case, capture group 1 contains the address, and capture @@ -87,7 +88,6 @@ class DnsResolver implements Resolver { } } this.percentage = Math.random() * 100; - this.startResolution(); } private startResolution() { @@ -140,6 +140,10 @@ class DnsResolver implements Resolver { this.startResolution(); } } + + static getDefaultAuthority(target: string): string { + return new URL(target).hostname; + } } export function setup(): void { diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 10a485376..f28115913 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -29,6 +29,7 @@ export interface Resolver { export interface ResolverConstructor { new(target: string, listener: ResolverListener): Resolver; + getDefaultAuthority(target:string): string; } const registeredResolvers: {[prefix: string]: ResolverConstructor} = {}; @@ -52,4 +53,13 @@ export function createResolver(target: string, listener: ResolverListener): Reso return new defaultResolver(target, listener); } throw new Error('No resolver could be created for the provided target'); +} + +export function getDefaultAuthority(target: string): string { + for (const prefix of Object.keys(registerDefaultResolver)) { + if (target.startsWith(prefix)) { + return registeredResolvers[prefix].getDefaultAuthority(target); + } + } + throw new Error(`Invalid target "${target}"`); } \ No newline at end of file diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index a403a2200..ce863f7f9 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -15,16 +15,23 @@ * */ -import { ChannelControlHelper, LoadBalancer, isLoadBalancerNameRegistered } from "./load-balancer"; +import { ChannelControlHelper, LoadBalancer, isLoadBalancerNameRegistered, createLoadBalancer } from "./load-balancer"; import { ServiceConfig } from "./service-config"; import { ConnectivityState } from "./channel"; import { createResolver, Resolver } from "./resolver"; import { ServiceError } from "./call"; +import { ChannelOptions } from "./channel-options"; +import { Picker, UnavailablePicker, QueuePicker } from "./picker"; +import { LoadBalancingConfig } from "./load-balancing-config"; const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; -export class ResolvingLoadBalancer { +export class ResolvingLoadBalancer implements LoadBalancer { private innerResolver: Resolver; + /** + * Current internal load balancer used for handling calls. + * Invariant: innerLoadBalancer === null => pendingReplacementLoadBalancer === null. + */ private innerLoadBalancer: LoadBalancer | null = null; private pendingReplacementLoadBalancer: LoadBalancer | null = null; private currentState: ConnectivityState = ConnectivityState.IDLE; @@ -36,8 +43,32 @@ export class ResolvingLoadBalancer { */ private previousServiceConfig: ServiceConfig | null | undefined = undefined; - constructor (private target: string, private channelControlHelper: ChannelControlHelper, private defaultServiceConfig: ServiceConfig | null) { + private innerBalancerState: ConnectivityState = ConnectivityState.IDLE; + + /** + * The most recent reported state of the pendingReplacementLoadBalancer. + * Starts at IDLE for type simplicity. This should get updated as soon as the + * pendingReplacementLoadBalancer gets constructed. + */ + private replacementBalancerState: ConnectivityState = ConnectivityState.IDLE; + /** + * The picker associated with the replacementBalancerState. Starts as an + * UnavailablePicker for type simplicity. This should get updated as soon as + * the pendingReplacementLoadBalancer gets constructed. + */ + private replacementBalancerPicker: Picker = new UnavailablePicker(); + /** + * ChannelControlHelper for the innerLoadBalancer. + */ + private readonly innerChannelControlHelper: ChannelControlHelper; + /** + * ChannelControlHelper for the pendingReplacementLoadBalancer. + */ + private readonly replacementChannelControlHelper: ChannelControlHelper; + + constructor (private target: string, private channelControlHelper: ChannelControlHelper, private defaultServiceConfig: ServiceConfig | null) { + this.channelControlHelper.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.innerResolver = createResolver(target, { onSuccessfulResolution: (addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null) => { let workingServiceConfig: ServiceConfig | null = null; @@ -57,14 +88,17 @@ export class ResolvingLoadBalancer { this.previousServiceConfig = serviceConfig; } let loadBalancerName: string | null = null; + let loadBalancingConfig: LoadBalancingConfig | null = null; if (workingServiceConfig === null || workingServiceConfig.loadBalancingConfig.length === 0) { loadBalancerName = DEFAULT_LOAD_BALANCER_NAME; } else { for (const lbConfig of workingServiceConfig.loadBalancingConfig) { + // Iterating through a oneof looking for whichever one is populated for (const key in lbConfig) { if (Object.prototype.hasOwnProperty.call(lbConfig, key)) { if (isLoadBalancerNameRegistered(key)) { loadBalancerName = key; + loadBalancingConfig = lbConfig; break; } } @@ -79,14 +113,112 @@ export class ResolvingLoadBalancer { return; } } + if (this.innerLoadBalancer === null) { + this.innerLoadBalancer = createLoadBalancer(loadBalancerName, this.innerChannelControlHelper)!; + this.innerLoadBalancer.updateAddressList(addressList, loadBalancingConfig); + } else if (this.innerLoadBalancer.getTypeName() === loadBalancerName) { + this.innerLoadBalancer.updateAddressList(addressList, loadBalancingConfig); + } else { + if (this.pendingReplacementLoadBalancer === null || this.pendingReplacementLoadBalancer.getTypeName() !== loadBalancerName) { + if (this.pendingReplacementLoadBalancer !== null) { + this.pendingReplacementLoadBalancer.destroy(); + } + this.pendingReplacementLoadBalancer = createLoadBalancer(loadBalancerName, this.replacementChannelControlHelper)!; + } + this.pendingReplacementLoadBalancer.updateAddressList(addressList, loadBalancingConfig); + } }, onError: (error: ServiceError) => { this.handleResolutionFailure(error); } }); + + this.innerChannelControlHelper = { + createSubchannel: (subchannelAddress: string, subchannelArgs: ChannelOptions) => { + return this.channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + this.innerBalancerState = connectivityState; + if (connectivityState === ConnectivityState.TRANSIENT_FAILURE && this.pendingReplacementLoadBalancer !== null) { + this.switchOverReplacementBalancer(); + } else { + this.channelControlHelper.updateState(connectivityState, picker); + } + }, + requestReresolution: () => { + if (this.pendingReplacementLoadBalancer === null) { + this.innerResolver.updateResolution(); + } + } + } + + this.replacementChannelControlHelper = { + createSubchannel: (subchannelAddress: string, subchannelArgs: ChannelOptions) => { + return this.channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + this.replacementBalancerState = connectivityState; + this.replacementBalancerPicker = picker; + if (connectivityState === ConnectivityState.READY) { + this.switchOverReplacementBalancer(); + } + }, + requestReresolution: () => { + this.innerResolver.updateResolution(); + } + }; + } + + /** + * Stop using the current innerLoadBalancer and replace it with the + * pendingReplacementLoadBalancer. Must only be called if both of + * those are currently not null. + */ + private switchOverReplacementBalancer() { + this.innerLoadBalancer!.destroy(); + this.innerLoadBalancer = this.pendingReplacementLoadBalancer!; + this.innerLoadBalancer.replaceChannelControlHelper(this.innerChannelControlHelper); + this.pendingReplacementLoadBalancer = null; + this.innerBalancerState = this.replacementBalancerState; + this.channelControlHelper.updateState(this.replacementBalancerState, this.replacementBalancerPicker); } private handleResolutionFailure(error: ServiceError) { } + + exitIdle() { + this.innerResolver.updateResolution(); + if (this.innerLoadBalancer !== null) { + this.innerLoadBalancer.exitIdle(); + } + } + + updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null) { + throw new Error('updateAddressList not supported on ResolvingLoadBalancer'); + } + + resetBackoff() { + // TODO + } + + destroy() { + if (this.innerLoadBalancer !== null) { + this.innerLoadBalancer.destroy(); + this.innerLoadBalancer = null; + } + if (this.pendingReplacementLoadBalancer !== null) { + this.pendingReplacementLoadBalancer.destroy(); + this.pendingReplacementLoadBalancer = null; + } + // Go to another state? + } + + getTypeName() { + return 'resolving_load_balancer'; + } + + replaceChannelControlHelper(channelControlHelper: ChannelControlHelper) { + this.channelControlHelper = channelControlHelper; + } } \ No newline at end of file diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 06b958276..55274295f 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -73,6 +73,10 @@ export class SubchannelPool { const globalSubchannelPool = new SubchannelPool(true); -export function getOrCreateSubchannel(channelTarget: string, subchannelTarget: string, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials): Subchannel { - return globalSubchannelPool.getOrCreateSubchannel(channelTarget, subchannelTarget, channelArguments, channelCredentials); +export function getSubchannelPool(global: boolean): SubchannelPool { + if (global) { + return globalSubchannelPool; + } else { + return new SubchannelPool(false); + } } \ No newline at end of file From 84d48a741544e17477f330772bd5b30cd46e2501 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Aug 2019 14:30:20 -0700 Subject: [PATCH 0739/1899] Update version to 1.23.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index d50231f94..f60a6b1e5 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -97,7 +97,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.23.0-pre1"', + 'GRPC_NODE_VERSION="1.23.0"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index ae91cd038..7c0764918 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit ae91cd03818d6c4e7bc06efc261215338ce65475 +Subproject commit 7c0764918b9f33cab507ff483b4be849b0203ec4 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 394779137..e44b68b98 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.23.0-pre1", + "version": "1.23.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 7c07d7615139413f34f8537ab934adceb7be8cd1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 16 Aug 2019 13:02:59 -0700 Subject: [PATCH 0740/1899] Increase timeout for Windows Electron build --- test/kokoro/windows-build-electron.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/windows-build-electron.cfg b/test/kokoro/windows-build-electron.cfg index 873b734a9..7017d0aec 100644 --- a/test/kokoro/windows-build-electron.cfg +++ b/test/kokoro/windows-build-electron.cfg @@ -16,4 +16,4 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/tools/release/kokoro-electron.bat" -timeout_mins: 60 +timeout_mins: 120 From 20874af51c2384e0bc4a3a8ef58a4033be180e59 Mon Sep 17 00:00:00 2001 From: Kelly Campbell Date: Sat, 17 Aug 2019 14:11:48 -0400 Subject: [PATCH 0741/1899] Log internal errors from proto serialization/deserialization --- packages/grpc-native-core/src/server.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index b79ee6fc3..4b0aa3afb 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -55,6 +55,9 @@ function handleError(call, error) { if (error.hasOwnProperty('details')) { status.details = error.details; } + if (status.code == constants.status.INTERNAL) { + common.log(constants.logVerbosity.ERROR, error); + } } if (error.hasOwnProperty('metadata')) { statusMetadata = error.metadata; From 629670bbd3f9be470a7780227ac60b6221f8374d Mon Sep 17 00:00:00 2001 From: David Raynes Date: Mon, 19 Aug 2019 14:12:44 -0400 Subject: [PATCH 0742/1899] Remove deprecated @types/protobufjs module --- packages/grpc-native-core/package.json | 1 - packages/grpc-native-core/templates/package.json.template | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index ed360a399..4605eb2a5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,7 +29,6 @@ "node-pre-gyp" ], "dependencies": { - "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 2d9bede7d..080567c56 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,7 +31,6 @@ "node-pre-gyp" ], "dependencies": { - "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", From 1bec9e2b5d9b3db5d44ffab5f08aa78e896d23d4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 19 Aug 2019 12:46:46 -0700 Subject: [PATCH 0743/1899] Remove @types/protobufjs and bump to 1.23.1 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/package.json | 3 +-- packages/grpc-native-core/templates/package.json.template | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index f60a6b1e5..1a8d20730 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -97,7 +97,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.23.0"', + 'GRPC_NODE_VERSION="1.23.1"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..fa21241b8 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.23.1 \ No newline at end of file diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e44b68b98..816b26782 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.23.0", + "version": "1.23.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", @@ -29,7 +29,6 @@ "node-pre-gyp" ], "dependencies": { - "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 2d9bede7d..080567c56 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,7 +31,6 @@ "node-pre-gyp" ], "dependencies": { - "@types/protobufjs": "^5.0.31", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", From 10a7cc5e3afeddc160280d294b7cb4b23d0634e6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Aug 2019 09:36:58 -0700 Subject: [PATCH 0744/1899] Add MAINTAINERS.md --- MAINTAINERS.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 MAINTAINERS.md diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 000000000..0ef614d9b --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,23 @@ +This page lists all active maintainers of this repository. If you were a +maintainer and would like to add your name to the Emeritus list, please send us a +PR. + +See [GOVERNANCE.md](https://github.com/grpc/grpc-community/blob/master/governance.md) +for governance guidelines and how to become a maintainer. +See [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIBUTING.md) +for general contribution guidelines. + +## Maintainers (in alphabetical order) + - [jiangtaoli2016](https://github.com/jiangtaoli2016), Google Inc. + - [jtattermusch](https://github.com/jtattermusch), Google Inc. + - [kjin](https://github.com/kjin), Google Inc. + - [matt-kwong](https://github.com/matt-kwong), Google Inc. + - [murgatroid99](https://github.com/murgatroid99), Google Inc. + - [nicolasnoble](https://github.com/nicolasnoble), Google Inc. + - [ofrobots](https://github.com/ofrobots), Google Inc. + - [srini100](https://github.com/srini100), Google Inc. + - [WeiranFang](https://github.com/WeiranFang), Google Inc. + - [wenbozhu](https://github.com/wenbozhu), Google Inc. + + ## Emeritus Maintainers (in alphabetical order) + \ No newline at end of file From f5294f7258a3222d114c7a23d993a84ba2e42d9b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Aug 2019 10:11:49 -0700 Subject: [PATCH 0745/1899] Upmerge 1.22 into 1.23 --- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/index.d.ts | 6 ++- packages/grpc-native-core/index.js | 4 +- packages/grpc-native-core/package.json | 2 + packages/grpc-native-core/src/client.js | 50 ++++++++++++++++++- packages/grpc-native-core/src/server.js | 3 +- .../templates/package.json.template | 2 + 7 files changed, 63 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index fa21241b8..ce12f4375 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.23.1 \ No newline at end of file + node_version: 1.23.1 diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index c7dab49dd..f36b6e867 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1,3 +1,5 @@ +import { EventEmitter } from "events"; + /* * Copyright 2019 gRPC authors. * @@ -341,7 +343,7 @@ declare module "grpc" { /** * An EventEmitter. Used for unary calls. */ - export class ServerUnaryCall { + export class ServerUnaryCall extends EventEmitter { /** * Indicates if the call has been cancelled */ @@ -1231,7 +1233,7 @@ declare module "grpc" { /** * An EventEmitter. Used for unary calls. */ - export class ClientUnaryCall { + export class ClientUnaryCall extends EventEmitter { private constructor(); /** diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js index 9134667a8..9534c7d4f 100644 --- a/packages/grpc-native-core/index.js +++ b/packages/grpc-native-core/index.js @@ -312,7 +312,9 @@ exports.Client = client.Client; * @memberof grpc * @param {string} target The address of the server to connect to * @param {grpc.ChannelCredentials} credentials Channel credentials to use when connecting - * @param {grpc~ChannelOptions} options A map of channel options that will be passed to the core + * @param {grpc~ChannelOptions} options A map of channel options that will be passed to the core. + * The available options are listed in + * [this document]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}. */ exports.Channel = grpc.Channel; diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 816b26782..9edc2d96a 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -75,6 +75,8 @@ "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/upb/**/*.{c,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", + "deps/grpc/third_party/address_sorting/**/*.{c,h}", + "deps/grpc/third_party/cares/**/*.{c,h}", "binding.gyp" ], "main": "index.js", diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js index 256f8d1cd..faba6decb 100644 --- a/packages/grpc-native-core/src/client.js +++ b/packages/grpc-native-core/src/client.js @@ -353,6 +353,42 @@ ClientDuplexStream.prototype.getPeer = getPeer; * should be used to make this particular call. */ +/** + * Properties of a call, for use with a {@link grpc.Client~callInvocationTransformer}. + * @typedef {Object} grpc.Client~CallProperties + * @property {*} argument The call argument. Only preset if the method is unary or server streaming. + * @property {grpc.Metadata} metadata The request metadata + * @property {grpc~Call} call The call object that will be returned by the client method + * @property {grpc.Channel} channel The channel that will be used to make a request + * @property {grpc~MethodDefinition} methodDefinition The MethodDefinition object that describes this method + * @property {grpc.Client~CallOptions} options The call options passed when making this request + * @property {grpc.Client~requestCallback} callback The callback that will handle the response. + * Only present if this method is unary or client streaming. + */ + +/** + * Call invocation transformer. Has access to the full call properties before a + * call is processed and can modify most of those properties. Some modifications + * will have no effect or may cause problems. + * @name grpc.Client~callInvocationTransformer + * @function + * @param {grpc.Client~CallProperties} callProperties The original call properties + * @return {grpc.Client~CallProperties} The modified call properties. + */ + +/** + * A function that functionally replaces the Channel constructor. + * @name grpc.Client~channelFactory + * @function + * @param {string} target The address of the server to connect to + * @param {grpc.ChannelCredentials} credentials Channel credentials to use when connecting + * @param {grpc~ChannelOptions} options A map of channel options that will be passed to the core. + * The available options are listed in + * [this document]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}. + * @returns {grpc.Channel} This can either be an actual channel object, or an object with the + * same API. + */ + /** * A generic gRPC client. Primarily useful as a base class for generated clients * @memberof grpc @@ -360,7 +396,19 @@ ClientDuplexStream.prototype.getPeer = getPeer; * @param {string} address Server address to connect to * @param {grpc.credentials~ChannelCredentials} credentials Credentials to use * to connect to the server - * @param {Object} options Options to apply to channel creation + * @param {Object} options Options to apply to channel creation. Any of + * [the channel arguments]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html} + * can be used here in addition to specific client options. + * @param {grpc~Interceptor[]} [options.interceptors] Interceptors to apply to each request + * @param {grpc~InterceptorProvider[]} [options.interceptor_providers] Interceptor providers + * to apply interceptors to each request depending on the method definition. At most + * one of the interceptors and interceptor_providers options may be set. + * @param {grpc.Client~callInvocationTransformer=} options.callInvocationTransformer + * @param {grpc.Channel=} options.channelOverride Channel to use instead of constructing a new one. + * If set, the address, credentials, channel arguments options, and channelFactoryOverride + * option will all be ignored. + * @param {grpc.Client~channelFactory} options.channelFactoryOverride Function to use instead of + * the Channel constructor when creating the Client's channel. */ function Client(address, credentials, options) { var self = this; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index b79ee6fc3..f6ce06992 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -719,7 +719,8 @@ var streamHandlers = { * @memberof grpc * @constructor * @param {Object=} options Options that should be passed to the internal server - * implementation + * implementation. The available options are listed in + * [this document]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}. * @example * var server = new grpc.Server(); * server.addProtoService(protobuf_service_descriptor, service_implementation); diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 080567c56..db054aa46 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -77,6 +77,8 @@ "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/upb/**/*.{c,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", + "deps/grpc/third_party/address_sorting/**/*.{c,h}", + "deps/grpc/third_party/cares/**/*.{c,h}", "binding.gyp" ], "main": "index.js", From 42e9f6df61732bdd3d5accfc3cea2166f6f30ef2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Aug 2019 10:15:08 -0700 Subject: [PATCH 0746/1899] Bump to 1.23.2 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 1a8d20730..894befd84 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -97,7 +97,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.23.1"', + 'GRPC_NODE_VERSION="1.23.2"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index ce12f4375..0197533df 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.23.1 + node_version: 1.23.2 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 9edc2d96a..519a82790 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.23.1", + "version": "1.23.2", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 3e486816ed13fd8e81ce7c39f9889028e1caf762 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Aug 2019 11:10:58 -0700 Subject: [PATCH 0747/1899] Move two people to emeritus list --- MAINTAINERS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 0ef614d9b..c9e0522a1 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -10,8 +10,6 @@ for general contribution guidelines. ## Maintainers (in alphabetical order) - [jiangtaoli2016](https://github.com/jiangtaoli2016), Google Inc. - [jtattermusch](https://github.com/jtattermusch), Google Inc. - - [kjin](https://github.com/kjin), Google Inc. - - [matt-kwong](https://github.com/matt-kwong), Google Inc. - [murgatroid99](https://github.com/murgatroid99), Google Inc. - [nicolasnoble](https://github.com/nicolasnoble), Google Inc. - [ofrobots](https://github.com/ofrobots), Google Inc. @@ -20,4 +18,6 @@ for general contribution guidelines. - [wenbozhu](https://github.com/wenbozhu), Google Inc. ## Emeritus Maintainers (in alphabetical order) + - [kjin](https://github.com/kjin), Google Inc. + - [matt-kwong](https://github.com/matt-kwong), Google Inc. \ No newline at end of file From ccd8c628d96b4e01bfcf8fbc732ee7559d23486b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 20 Aug 2019 17:16:42 -0700 Subject: [PATCH 0748/1899] Install npm 6.10 on Windows --- tools/release/kokoro-electron.bat | 2 +- tools/release/kokoro-nodejs.bat | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/release/kokoro-electron.bat b/tools/release/kokoro-electron.bat index 4bc1d0a21..c27db4806 100644 --- a/tools/release/kokoro-electron.bat +++ b/tools/release/kokoro-electron.bat @@ -20,7 +20,7 @@ SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% call nvm install 10 call nvm use 10 -call npm install -g npm +call npm install -g npm@6.10.x @rem https://github.com/mapbox/node-pre-gyp/issues/362 call npm install -g node-gyp@3 diff --git a/tools/release/kokoro-nodejs.bat b/tools/release/kokoro-nodejs.bat index 0655d2dfb..faa6364ac 100644 --- a/tools/release/kokoro-nodejs.bat +++ b/tools/release/kokoro-nodejs.bat @@ -20,7 +20,7 @@ SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% call nvm install 10 call nvm use 10 -call npm install -g npm +call npm install -g npm@6.10.x @rem https://github.com/mapbox/node-pre-gyp/issues/362 call npm install -g node-gyp@3 From 24a14d7f0469232df9e68a1ecbf3a8f8a60cc311 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 22 Aug 2019 11:35:22 -0700 Subject: [PATCH 0749/1899] Move EventEmitter inside declare module "grpc" --- packages/grpc-native-core/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index f36b6e867..d1406efb7 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1,4 +1,3 @@ -import { EventEmitter } from "events"; /* * Copyright 2019 gRPC authors. @@ -19,6 +18,7 @@ import { EventEmitter } from "events"; declare module "grpc" { import { Message, Service as ProtobufService } from "protobufjs"; + import { EventEmitter } from "events"; import { Duplex, Readable, Writable } from "stream"; import { SecureContext } from "tls"; From d6866a837a898ce15a9a80e3e0beda01f0a21a36 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Thu, 22 Aug 2019 12:46:33 -0700 Subject: [PATCH 0750/1899] Add comment for future additions --- packages/grpc-native-core/index.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index d1406efb7..7977c7273 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -17,6 +17,7 @@ */ declare module "grpc" { + // add imports here, inside the "grpc" module, to keep it as an ambient module import { Message, Service as ProtobufService } from "protobufjs"; import { EventEmitter } from "events"; import { Duplex, Readable, Writable } from "stream"; From d434d132fc91b341f37c8199a15ff6f941d26644 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 22 Aug 2019 13:18:36 -0700 Subject: [PATCH 0751/1899] Duplicate relevant protobufjs type definition --- packages/grpc-native-core/index.d.ts | 41 ++++++++++++++++++- packages/grpc-native-core/package.json | 1 + .../templates/package.json.template | 1 + 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 7977c7273..1f9363113 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -16,13 +16,50 @@ * */ +/// + declare module "grpc" { // add imports here, inside the "grpc" module, to keep it as an ambient module - import { Message, Service as ProtobufService } from "protobufjs"; import { EventEmitter } from "events"; import { Duplex, Readable, Writable } from "stream"; import { SecureContext } from "tls"; + /* The Message interface is copied and slightly modified from @types/protobuf + * version 5.0.31, which was distributed under the following license: + * + * This project is licensed under the MIT license. + * Copyrights are respective of each contributor listed at the beginning of each definition file. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + export interface ProtobufMessage { + $add(key: string, value: any, noAssert?: boolean): ProtobufMessage; + $get(key: string): T; + $set(key: string | {[key: string]: any}, value?: any | boolean, noAssert?: boolean): void; + add(key: string, value: any, noAssert?: boolean): ProtobufMessage; + calculate(): number; + encode(buffer?: ByteBuffer | boolean, noVerify?: boolean): ByteBuffer; + encode64(): string; + encodeAB(): ArrayBuffer; + encodeNB(): Buffer; + encodeHex(): string; + encodeJSON(): string; + encodeDelimited(buffer?: ByteBuffer | boolean, noVerify?: boolean): ByteBuffer; + get(key: string, noAssert?: boolean): T; + set(key: string | {[key: string]: any}, value?: any | boolean, noAssert?: boolean): void; + toArrayBuffer(): ArrayBuffer; + toBase64(): string; + toBuffer(): Buffer; + toHex(): string; + toRaw(binaryAsBase64?: boolean, longsAsStrings?: boolean): {[key: string]: any}; + toString(): string; + [field: string]: any; + } + /** * Load a ProtoBuf.js object as a gRPC object. * @param value The ProtoBuf.js reflection object to load @@ -86,7 +123,7 @@ declare module "grpc" { * - Anything else becomes the relevant reflection object that ProtoBuf.js would create */ export interface GrpcObject { - [name: string]: GrpcObject | typeof Client | Message; + [name: string]: GrpcObject | typeof Client | ProtobufMessage; } /** diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 519a82790..3f691495e 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -29,6 +29,7 @@ "node-pre-gyp" ], "dependencies": { + "@types/bytebuffer": "^5.0.40", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index db054aa46..eaab70671 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -31,6 +31,7 @@ "node-pre-gyp" ], "dependencies": { + "@types/bytebuffer": "^5.0.40", "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", From c12bebd979bf8ec0049f433c285f2a8567c6ec35 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 22 Aug 2019 13:23:38 -0700 Subject: [PATCH 0752/1899] Update to v1.23.3 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 894befd84..2851af483 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -97,7 +97,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.23.2"', + 'GRPC_NODE_VERSION="1.23.3"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 0197533df..d6ebeea62 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.23.2 + node_version: 1.23.3 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 519a82790..3fdac69ac 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.23.2", + "version": "1.23.3", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 01977e6e083098fd2a5d6148819e0312e6e07b7d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Aug 2019 14:16:57 -0700 Subject: [PATCH 0753/1899] Add documentation and error handling --- packages/grpc-js/src/backoff-timeout.ts | 101 ++++++++ packages/grpc-js/src/channel.ts | 12 +- packages/grpc-js/src/client.ts | 4 +- packages/grpc-js/src/index.ts | 14 +- .../grpc-js/src/load-balancer-pick-first.ts | 122 ++++++++-- packages/grpc-js/src/load-balancer.ts | 5 + packages/grpc-js/src/load-balancing-config.ts | 5 +- packages/grpc-js/src/picker.ts | 69 ++++-- packages/grpc-js/src/resolver-dns.ts | 91 +++++++- packages/grpc-js/src/resolver.ts | 74 +++++- .../grpc-js/src/resolving-load-balancer.ts | 123 ++++++++-- packages/grpc-js/src/service-config.ts | 20 +- packages/grpc-js/src/subchannel-pool.ts | 22 ++ packages/grpc-js/src/subchannel.ts | 216 ++++++++++++------ packages/grpc-js/test/test-call-stream.ts | 47 ++-- .../grpc-js/test/test-channel-credentials.ts | 6 +- packages/grpc-native-core/deps/grpc | 2 +- 17 files changed, 759 insertions(+), 174 deletions(-) create mode 100644 packages/grpc-js/src/backoff-timeout.ts diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts new file mode 100644 index 000000000..84956c437 --- /dev/null +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -0,0 +1,101 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const INITIAL_BACKOFF_MS = 1000; +const BACKOFF_MULTIPLIER = 1.6; +const MAX_BACKOFF_MS = 120000; +const BACKOFF_JITTER = 0.2; + +/** + * Get a number uniformly at random in the range [min, max) + * @param min + * @param max + */ +function uniformRandom(min: number, max: number) { + return Math.random() * (max - min) + min; +} + +export interface BackoffOptions { + initialDelay?: number; + multiplier?: number; + jitter?: number; + maxDelay?: number; +} + +export class BackoffTimeout { + private initialDelay: number = INITIAL_BACKOFF_MS; + private multiplier: number = BACKOFF_MULTIPLIER; + private maxDelay: number = MAX_BACKOFF_MS; + private jitter: number = BACKOFF_JITTER; + private nextDelay: number; + private timerId: NodeJS.Timer; + private running: boolean = false; + + constructor(private callback: () => void, options?: BackoffOptions) { + if (options) { + if (options.initialDelay) { + this.initialDelay = options.initialDelay; + } + if (options.multiplier) { + this.multiplier = options.multiplier; + } + if (options.jitter) { + this.jitter = options.jitter; + } + if (options.maxDelay) { + this.maxDelay = options.maxDelay; + } + } + this.nextDelay = this.initialDelay; + this.timerId = setTimeout(() => {}, 0); + clearTimeout(this.timerId); + } + + /** + * Call the callback after the current amount of delay time + */ + runOnce() { + this.running = true; + this.timerId = setTimeout(() => { + this.callback(); + this.running = false; + }, this.nextDelay); + const nextBackoff = Math.min(this.nextDelay * this.multiplier, this.maxDelay); + const jitterMagnitude = nextBackoff * this.jitter; + this.nextDelay = nextBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude); + } + + /** + * Stop the timer. The callback will not be called until `runOnce` is called + * again. + */ + stop() { + clearTimeout(this.timerId); + this.running = false; + } + + /** + * Reset the delay time to its initial value. + */ + reset() { + this.nextDelay = this.initialDelay; + } + + isRunning() { + return this.running; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 636750a1f..331a34f6f 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -23,7 +23,6 @@ import { SubchannelPool, getSubchannelPool } from "./subchannel-pool"; import { ChannelControlHelper } from "./load-balancer"; import { UnavailablePicker, Picker, PickResultType } from "./picker"; import { Metadata } from "./metadata"; -import { SubchannelConnectivityState } from "./subchannel"; import { Status } from "./constants"; import { FilterStackFactory } from "./filter-stack"; import { CallCredentialsFilterFactory } from "./call-credentials-filter"; @@ -31,6 +30,8 @@ import { DeadlineFilterFactory } from "./deadline-filter"; import { MetadataStatusFilterFactory } from "./metadata-status-filter"; import { CompressionFilterFactory } from "./compression-filter"; import { getDefaultAuthority } from "./resolver"; +import { LoadBalancingConfig } from "./load-balancing-config"; +import { ServiceConfig } from "./service-config"; export enum ConnectivityState { CONNECTING, @@ -136,7 +137,11 @@ export class ChannelImplementation implements Channel { } }; // TODO: check channel arg for default service config - this.resolvingLoadBalancer = new ResolvingLoadBalancer(target, channelControlHelper, null); + const defaultServiceConfig: ServiceConfig = { + loadBalancingConfig: [], + methodConfig: [] + } + this.resolvingLoadBalancer = new ResolvingLoadBalancer(target, channelControlHelper, defaultServiceConfig); this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), @@ -163,12 +168,13 @@ export class ChannelImplementation implements Channel { switch(pickResult.pickResultType) { case PickResultType.COMPLETE: if (pickResult.subchannel === null) { + callStream.cancelWithStatus(Status.UNAVAILABLE, "Request dropped by load balancing policy"); // End the call with an error } else { /* If the subchannel disconnects between calling pick and getting * the filter stack metadata, the call will end with an error. */ callStream.filterStack.sendMetadata(Promise.resolve(new Metadata())).then((finalMetadata) => { - if (pickResult.subchannel!.getConnectivityState() === SubchannelConnectivityState.READY) { + if (pickResult.subchannel!.getConnectivityState() === ConnectivityState.READY) { pickResult.subchannel!.startCallStream(callMetadata, callStream); } else { callStream.cancelWithStatus(Status.UNAVAILABLE, 'Connection dropped while starting call'); diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 5b243c383..87c5c5f20 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -28,7 +28,7 @@ import { } from './call'; import { CallCredentials } from './call-credentials'; import { Call, Deadline, StatusObject, WriteObject } from './call-stream'; -import { Channel, ConnectivityState, Http2Channel } from './channel'; +import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; @@ -78,7 +78,7 @@ export class Client { options ); } else { - this[CHANNEL_SYMBOL] = new Http2Channel(address, credentials, options); + this[CHANNEL_SYMBOL] = new ChannelImplementation(address, credentials, options); } } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index d846b6c06..4f55fbeb5 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -26,7 +26,7 @@ import { } from './call'; import { CallCredentials } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; -import { Channel, ConnectivityState, Http2Channel } from './channel'; +import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; import { CallOptions, Client } from './client'; import { LogVerbosity, Status } from './constants'; @@ -183,7 +183,7 @@ export { loadPackageDefinition, makeClientConstructor, makeClientConstructor as makeGenericClientConstructor, - Http2Channel as Channel, + ChannelImplementation as Channel, }; /** @@ -283,3 +283,13 @@ export const InterceptingCall = () => { }; export { GrpcObject } from './make-client'; + +import * as resolver from './resolver'; +import * as load_balancer from './load-balancer'; + +function setup() { + resolver.registerAll(); + load_balancer.registerAll(); +} + +setup(); diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index a07c857ed..37aa4091e 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -19,12 +19,20 @@ import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType } from './ import { ConnectivityState } from './channel'; import { QueuePicker, Picker, PickArgs, CompletePickResult, PickResultType, UnavailablePicker } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; -import { Subchannel, SubchannelConnectivityState, ConnectivityStateListener } from './subchannel'; +import { Subchannel, ConnectivityStateListener } from './subchannel'; const TYPE_NAME = 'pick_first'; +/** + * Delay after starting a connection on a subchannel before starting a + * connection on the next subchannel in the list, for Happy Eyeballs algorithm. + */ const CONNECTION_DELAY_INTERVAL_MS = 250; +/** + * Picker for a `PickFirstLoadBalancer` in the READY state. Always returns the + * picked subchannel. + */ class PickFirstPicker implements Picker { constructor(private subchannel: Subchannel) {} @@ -38,46 +46,94 @@ class PickFirstPicker implements Picker { } export class PickFirstLoadBalancer implements LoadBalancer { + /** + * The list of backend addresses most recently passed to `updateAddressList`. + */ private latestAddressList: string[] = []; + /** + * The list of subchannels this load balancer is currently attempting to + * connect to. + */ private subchannels: Subchannel[] = []; + /** + * The current connectivity state of the load balancer. + */ private currentState: ConnectivityState = ConnectivityState.IDLE; + /** + * The index within the `subchannels` array of the subchannel with the most + * recently started connection attempt. + */ private currentSubchannelIndex: number = 0; + /** + * The number of subchannels in the `subchannels` list currently in the + * CONNECTING state. Used to determine the overall load balancer state. + */ private subchannelConnectingCount: number = 0; + /** + * The currently picked subchannel used for making calls. Populated if + * and only if the load balancer's current state is READY. In that case, + * the subchannel's current state is also READY. + */ private currentPick: Subchannel | null = null; + /** + * Listener callback attached to each subchannel in the `subchannels` list + * while establishing a connection. + */ private subchannelStateListener: ConnectivityStateListener; + /** + * Listener callback attached to the current picked subchannel. + */ private pickedSubchannelStateListener: ConnectivityStateListener; + /** + * Timer reference for the timer tracking when to start + */ private connectionDelayTimeout: NodeJS.Timeout; + private triedAllSubchannels: boolean = false; + + /** + * Load balancer that attempts to connect to each backend in the address list + * in order, and picks the first one that connects, using it for every + * request. + * @param channelControlHelper `ChannelControlHelper` instance provided by + * this load balancer's owner. + */ constructor(private channelControlHelper: ChannelControlHelper) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); - this.subchannelStateListener = (subchannel: Subchannel, previousState: SubchannelConnectivityState, newState: SubchannelConnectivityState) => { - if (previousState === SubchannelConnectivityState.CONNECTING) { + this.subchannelStateListener = (subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState) => { + if (previousState === ConnectivityState.CONNECTING) { this.subchannelConnectingCount -= 1; } - if (newState === SubchannelConnectivityState.CONNECTING) { + if (newState === ConnectivityState.CONNECTING) { this.subchannelConnectingCount += 1; } - if (newState === SubchannelConnectivityState.READY) { + if (newState === ConnectivityState.READY) { this.pickSubchannel(subchannel); return; } else { if (this.currentPick === null) { - if (newState === SubchannelConnectivityState.TRANSIENT_FAILURE || newState === SubchannelConnectivityState.IDLE) { - subchannel.startConnecting(); + if (newState === ConnectivityState.TRANSIENT_FAILURE || newState === ConnectivityState.IDLE) { + process.nextTick(() => { + subchannel.startConnecting(); + }); } - const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; - if (newLBState !== this.currentState) { - if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { - this.updateState(newLBState, new UnavailablePicker()); - } else { - this.updateState(newLBState, new QueuePicker(this)); + if (this.triedAllSubchannels) { + const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; + if (newLBState !== this.currentState) { + if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { + this.updateState(newLBState, new UnavailablePicker()); + } else { + this.updateState(newLBState, new QueuePicker(this)); + } } + } else { + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } } } }; - this.pickedSubchannelStateListener = (subchannel: Subchannel, previousState: SubchannelConnectivityState, newState: SubchannelConnectivityState) => { - if (newState !== SubchannelConnectivityState.READY) { + this.pickedSubchannelStateListener = (subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState) => { + if (newState !== ConnectivityState.READY) { subchannel.unref(); subchannel.removeConnectivityStateListener(this.pickedSubchannelStateListener); if (this.subchannels.length > 0) { @@ -97,20 +153,29 @@ export class PickFirstLoadBalancer implements LoadBalancer { clearTimeout(this.connectionDelayTimeout); } + /** + * Have a single subchannel in the `subchannels` list start connecting. + * @param subchannelIndex The index into the `subchannels` list. + */ private startConnecting(subchannelIndex: number) { - if (this.subchannels[subchannelIndex].getConnectivityState() === SubchannelConnectivityState.IDLE) { - this.subchannels[subchannelIndex].startConnecting(); + clearTimeout(this.connectionDelayTimeout); + this.currentSubchannelIndex = subchannelIndex; + if (this.subchannels[subchannelIndex].getConnectivityState() === ConnectivityState.IDLE) { + process.nextTick(() => { + this.subchannels[subchannelIndex].startConnecting(); + }); } this.connectionDelayTimeout = setTimeout(() => { for (const [index, subchannel] of this.subchannels.entries()) { if (index > subchannelIndex) { const subchannelState = subchannel.getConnectivityState(); - if (subchannelState === SubchannelConnectivityState.IDLE || subchannelState === SubchannelConnectivityState.CONNECTING) { + if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.CONNECTING) { this.startConnecting(index); return; } } } + this.triedAllSubchannels = true; }, CONNECTION_DELAY_INTERVAL_MS) } @@ -134,20 +199,28 @@ export class PickFirstLoadBalancer implements LoadBalancer { private resetSubchannelList() { for (const subchannel of this.subchannels) { - subchannel.unref(); subchannel.removeConnectivityStateListener(this.subchannelStateListener); + subchannel.unref(); } this.currentSubchannelIndex = 0; this.subchannelConnectingCount = 0; this.subchannels = []; + this.triedAllSubchannels = false; } + /** + * Start connecting to the address list most recently passed to + * `updateAddressList`. + */ private connectToAddressList(): void { this.resetSubchannelList(); this.subchannels = this.latestAddressList.map((address) => this.channelControlHelper.createSubchannel(address, {})); + for (const subchannel of this.subchannels) { + subchannel.ref(); + } for (const subchannel of this.subchannels) { subchannel.addConnectivityStateListener(this.subchannelStateListener); - if (subchannel.getConnectivityState() === SubchannelConnectivityState.READY) { + if (subchannel.getConnectivityState() === ConnectivityState.READY) { this.pickSubchannel(subchannel); this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); this.resetSubchannelList(); @@ -156,10 +229,14 @@ export class PickFirstLoadBalancer implements LoadBalancer { } for (const [index, subchannel] of this.subchannels.entries()) { const subchannelState = subchannel.getConnectivityState(); - if (subchannelState === SubchannelConnectivityState.IDLE || subchannelState === SubchannelConnectivityState.CONNECTING) { + if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.CONNECTING) { this.startConnecting(index); + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + return; } } + // If the code reaches this point, every subchannel must be in TRANSIENT_FAILURE + this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker()); } updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void { @@ -177,7 +254,8 @@ export class PickFirstLoadBalancer implements LoadBalancer { } resetBackoff() { - // I'm not actually sure what this is supposed to do + /* The pick first load balancer does not have a connection backoff, so this + * does nothing */ } destroy() { diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 14aa3e47b..7f0ca2ca1 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -20,6 +20,7 @@ import { Subchannel } from "./subchannel"; import { ConnectivityState } from "./channel"; import { Picker } from "./picker"; import { LoadBalancingConfig } from "./load-balancing-config"; +import * as load_balancer_pick_first from './load-balancer-pick-first'; /** * A collection of functions associated with a channel that a load balancer @@ -109,4 +110,8 @@ export function createLoadBalancer(typeName: string, channelControlHelper: Chann export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; +} + +export function registerAll() { + load_balancer_pick_first.setup(); } \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index b4b4594d8..df74cdcb8 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -16,7 +16,10 @@ */ /* This file is an implementation of gRFC A24: - * https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md */ + * https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md. Each + * function here takes an object with unknown structure and returns its + * specific object type if the input has the right structure, and throws an + * error otherwise. */ import { isString, isArray } from "util"; diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index e2def2c46..ebed1df43 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -28,51 +28,84 @@ export enum PickResultType { } export interface PickResult { - pickResultType: PickResultType, - subchannel: Subchannel | null, - status: StatusObject | null + pickResultType: PickResultType; + /** + * The subchannel to use as the transport for the call. Only meaningful if + * `pickResultType` is COMPLETE. If null, indicates that the call should be + * dropped. + */ + subchannel: Subchannel | null; + /** + * The status object to end the call with. Populated if and only if + * `pickResultType` is TRANSIENT_FAILURE. + */ + status: StatusObject | null; } export interface CompletePickResult extends PickResult { - pickResultType: PickResultType.COMPLETE, - subchannel: Subchannel | null, - status: null + pickResultType: PickResultType.COMPLETE; + subchannel: Subchannel | null; + status: null; } export interface QueuePickResult extends PickResult { - pickResultType: PickResultType.QUEUE, - subchannel: null, - status: null + pickResultType: PickResultType.QUEUE; + subchannel: null; + status: null; } export interface TransientFailurePickResult extends PickResult { - pickResultType: PickResultType.TRANSIENT_FAILURE, - subchannel: null, - status: StatusObject + pickResultType: PickResultType.TRANSIENT_FAILURE; + subchannel: null; + status: StatusObject; } export interface PickArgs { - metadata: Metadata + metadata: Metadata; } +/** + * A proxy object representing the momentary state of a load balancer. Picks + * subchannels or returns other information based on that state. Should be + * replaced every time the load balancer changes state. + */ export interface Picker { pick(pickArgs: PickArgs): PickResult; } +/** + * A standard picker representing a load balancer in the TRANSIENT_FAILURE + * state. Always responds to every pick request with an UNAVAILABLE status. + */ export class UnavailablePicker implements Picker { + private status: StatusObject; + constructor(status?: StatusObject) { + if (status !== undefined) { + this.status = status; + } else { + this.status = { + code: Status.UNAVAILABLE, + details: "No connection established", + metadata: new Metadata() + }; + } + } pick(pickArgs: PickArgs): TransientFailurePickResult { return { pickResultType: PickResultType.TRANSIENT_FAILURE, subchannel: null, - status: { - code: Status.UNAVAILABLE, - details: "No connection established", - metadata: new Metadata() - } + status: this.status }; } } +/** + * A standard picker representing a load balancer in the IDLE or CONNECTING + * state. Always responds to every pick request with a QUEUE pick result + * indicating that the pick should be tried again with the next `Picker`. Also + * reports back to the load balancer that a connection should be established + * once any pick is attempted. + */ export class QueuePicker { private calledExitIdle: boolean = false; // Constructed with a load balancer. Calls exitIdle on it the first time pick is called diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 52b8893b2..e0c397c90 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -20,22 +20,49 @@ import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; import { ServiceError } from './call'; import { Status } from './constants'; -import { URL } from 'url'; +import { StatusObject } from './call-stream'; +import { Metadata } from './metadata'; /* These regular expressions match IP addresses with optional ports in different * formats. In each case, capture group 1 contains the address, and capture * group 2 contains the port number, if present */ +/** + * Matches 4 groups of up to 3 digits each, separated by periods, optionally + * followed by a colon and a number. + */ const IPv4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/; +/** + * Matches any number of groups of up to 4 hex digits (case insensitive) + * separated by 1 or more colons. This variant does not match a port number. + */ const IPv6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i; +/** + * Matches the same as the IPv6_REGEX, surrounded by square brackets, and + * optionally followed by a colon and a number. + */ const IPv6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i; +/** + * Matches `[dns:][//authority/]host[:port]`, where `authority` and `host` are + * both arbitrary sequences of alphanumeric characters and `port` is a sequence + * of digits. Group 1 contains the hostname and group 2 contains the port + * number if provided. + */ const DNS_REGEX = /^(?:dns:)?(?:\/\/\w+\/)?(\w+)(?::(\d+))?$/; +/** + * The default TCP port to connect to if not explicitly specified in the target. + */ const DEFAULT_PORT = '443'; const resolve4Promise = util.promisify(dns.resolve4); const resolve6Promise = util.promisify(dns.resolve6); +/** + * Attempt to parse a target string as an IP address + * @param target + * @return An "IP:port" string if parsing was successful, `null` otherwise + */ function parseIP(target: string): string | null { /* These three regular expressions are all mutually exclusive, so we just * want the first one that matches the target string, if any do. */ @@ -53,6 +80,10 @@ function parseIP(target: string): string | null { return `${addr}:${port}`; } +/** + * Merge any number of arrays into a single alternating array + * @param arrays + */ function mergeArrays(...arrays: T[][]): T[] { const result: T[] = []; for(let i = 0; i array.length)); i++) { @@ -65,10 +96,13 @@ function mergeArrays(...arrays: T[][]): T[] { return result; } +/** + * Resolver implementation that handles DNS names and IP addresses. + */ class DnsResolver implements Resolver { - ipResult: string | null; - dnsHostname: string | null; - port: string | null; + private readonly ipResult: string | null; + private readonly dnsHostname: string | null; + private readonly port: string | null; /* The promise results here contain, in order, the A record, the AAAA record, * and either the TXT record or an error if TXT resolution failed */ pendingResultPromise: Promise<[string[], string[], string[][] | Error]> | null = null; @@ -90,6 +124,10 @@ class DnsResolver implements Resolver { this.percentage = Math.random() * 100; } + /** + * If the target is an IP address, just provide that address as a result. + * Otherwise, initiate A, AAAA, and TXT + */ private startResolution() { if (this.ipResult !== null) { setImmediate(() => { @@ -101,6 +139,9 @@ class DnsResolver implements Resolver { const hostname: string = this.dnsHostname; const Aresult = resolve4Promise(hostname); const AAAAresult = resolve6Promise(hostname); + /* We handle the TXT query promise differently than the others because + * the name resolution attempt as a whole is a success even if the TXT + * lookup fails */ const TXTresult = new Promise((resolve, reject) => { dns.resolveTxt(hostname, (err, records) => { if (err) { @@ -113,23 +154,36 @@ class DnsResolver implements Resolver { this.pendingResultPromise = Promise.all([Aresult, AAAAresult, TXTresult]); this.pendingResultPromise.then(([Arecord, AAAArecord, TXTrecord]) => { this.pendingResultPromise = null; + Arecord = Arecord.map((value) => `${value}:${this.port}`); + AAAArecord = AAAArecord.map((value) => `[${value}]:${this.port}`); const allAddresses: string[] = mergeArrays(AAAArecord, Arecord); let serviceConfig: ServiceConfig | null = null; - let serviceConfigError: ServiceError | null = null; + let serviceConfigError: StatusObject | null = null; if (TXTrecord instanceof Error) { - serviceConfigError = TXTrecord as ServiceError; - serviceConfigError.code = Status.UNAVAILABLE; + serviceConfigError = { + code: Status.UNAVAILABLE, + details: 'TXT query failed', + metadata: new Metadata() + }; } else { try { serviceConfig = extractAndSelectServiceConfig(TXTrecord, this.percentage); } catch (err) { - serviceConfigError = err as ServiceError; - serviceConfigError.code = Status.UNAVAILABLE; + serviceConfigError = { + code: Status.UNAVAILABLE, + details: 'Parsing service config failed', + metadata: new Metadata() + }; } } this.listener.onSuccessfulResolution(allAddresses, serviceConfig, serviceConfigError); }, (err) => { this.pendingResultPromise = null; + this.listener.onError({ + code: Status.UNAVAILABLE, + details: 'Name resolution failed', + metadata: new Metadata() + }); this.listener.onError(err); }); } @@ -141,11 +195,28 @@ class DnsResolver implements Resolver { } } + /** + * Get the default authority for the given target. For IP targets, that is + * the IP address. For DNS targets, it is the hostname. + * @param target + */ static getDefaultAuthority(target: string): string { - return new URL(target).hostname; + const ipMatch = IPv4_REGEX.exec(target) || IPv6_REGEX.exec(target) || IPv6_BRACKET_REGEX.exec(target); + if (ipMatch) { + return ipMatch[1]; + } + const dnsMatch = DNS_REGEX.exec(target); + if (dnsMatch) { + return dnsMatch[1]; + } + throw new Error(`Failed to parse target ${target}`); } } +/** + * Set up the DNS resolver class by registering it as the handler for the + * "dns:" prefix and as the default resolver. + */ export function setup(): void { registerResolver('dns:', DnsResolver); registerDefaultResolver(DnsResolver); diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index f28115913..a27782c22 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -17,32 +17,86 @@ import { ServiceError } from "./call"; import { ServiceConfig } from "./service-config"; +import * as resolver_dns from './resolver-dns'; +import { StatusObject } from "./call-stream"; +/** + * A listener object passed to the resolver's constructor that provides name + * resolution updates back to the resolver's owner. + */ export interface ResolverListener { - onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null): void; - onError(error: ServiceError): void; + /** + * Called whenever the resolver has new name resolution results to report + * @param addressList The new list of backend addresses + * @param serviceConfig The new service configuration corresponding to the + * `addressList`. Will be `null` if no service configuration was + * retrieved or if the service configuration was invalid + * @param serviceConfigError If non-`null`, indicates that the retrieved + * service configuration was invalid + */ + onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null): void; + /** + * Called whenever a name resolution attempt fails. + * @param error Describes how resolution failed + */ + onError(error: StatusObject): void; } +/** + * A resolver class that handles one or more of the name syntax schemes defined + * in the [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md) + */ export interface Resolver { + /** + * Indicates that the caller wants new name resolution data. Calling this + * function may eventually result in calling one of the `ResolverListener` + * functions, but that is not guaranteed. Those functions will never be + * called synchronously with the constructor or updateResolution. + */ updateResolution(): void; } + export interface ResolverConstructor { new(target: string, listener: ResolverListener): Resolver; + /** + * Get the default authority for a target. This loosely corresponds to that + * target's hostname. Throws an error if this resolver class cannot parse the + * `target`. + * @param target + */ getDefaultAuthority(target:string): string; } const registeredResolvers: {[prefix: string]: ResolverConstructor} = {}; let defaultResolver: ResolverConstructor | null = null; +/** + * Register a resolver class to handle target names prefixed with the `prefix` + * string. This prefix should correspond to a URI scheme name listed in the + * [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md) + * @param prefix + * @param resolverClass + */ export function registerResolver(prefix: string, resolverClass: ResolverConstructor) { registeredResolvers[prefix] = resolverClass; } +/** + * Register a default resolver to handle target names that do not start with + * any registered prefix. + * @param resolverClass + */ export function registerDefaultResolver(resolverClass: ResolverConstructor) { defaultResolver = resolverClass; } +/** + * Create a name resolver for the specified target, if possible. Throws an + * error if no such name resolver can be created. + * @param target + * @param listener + */ export function createResolver(target: string, listener: ResolverListener): Resolver { for (const prefix of Object.keys(registeredResolvers)) { if (target.startsWith(prefix)) { @@ -52,14 +106,26 @@ export function createResolver(target: string, listener: ResolverListener): Reso if (defaultResolver !== null) { return new defaultResolver(target, listener); } - throw new Error('No resolver could be created for the provided target'); + throw new Error(`No resolver could be created for target ${target}`); } +/** + * Get the default authority for the specified target, if possible. Throws an + * error if no registered name resolver can parse that target string. + * @param target + */ export function getDefaultAuthority(target: string): string { for (const prefix of Object.keys(registerDefaultResolver)) { if (target.startsWith(prefix)) { return registeredResolvers[prefix].getDefaultAuthority(target); } } - throw new Error(`Invalid target "${target}"`); + if (defaultResolver !== null) { + return defaultResolver.getDefaultAuthority(target); + } + throw new Error(`Invalid target ${target}`); +} + +export function registerAll() { + resolver_dns.setup(); } \ No newline at end of file diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index ce863f7f9..6d13f75fc 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -23,17 +23,34 @@ import { ServiceError } from "./call"; import { ChannelOptions } from "./channel-options"; import { Picker, UnavailablePicker, QueuePicker } from "./picker"; import { LoadBalancingConfig } from "./load-balancing-config"; +import { BackoffTimeout } from "./backoff-timeout"; +import { Status } from "./constants"; +import { StatusObject } from "./call-stream"; +import { Metadata } from "./metadata"; const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; export class ResolvingLoadBalancer implements LoadBalancer { + /** + * The resolver class constructed for the target address. + */ private innerResolver: Resolver; /** * Current internal load balancer used for handling calls. * Invariant: innerLoadBalancer === null => pendingReplacementLoadBalancer === null. */ private innerLoadBalancer: LoadBalancer | null = null; + /** + * The load balancer instance that will be used in place of the current + * `innerLoadBalancer` once either that load balancer loses its connection + * or this one establishes a connection. For use when a new name resolution + * result comes in with a different load balancing configuration, and the + * current `innerLoadBalancer` is still connected. + */ private pendingReplacementLoadBalancer: LoadBalancer | null = null; + /** + * This resolving load balancer's current connectivity state. + */ private currentState: ConnectivityState = ConnectivityState.IDLE; /** * The service config object from the last successful resolution, if @@ -42,7 +59,9 @@ export class ResolvingLoadBalancer implements LoadBalancer { * successful resolution explicitly provided a null service config. */ private previousServiceConfig: ServiceConfig | null | undefined = undefined; - + /** + * The most recently reported connectivity state of the `innerLoadBalancer`. + */ private innerBalancerState: ConnectivityState = ConnectivityState.IDLE; /** @@ -67,23 +86,56 @@ export class ResolvingLoadBalancer implements LoadBalancer { */ private readonly replacementChannelControlHelper: ChannelControlHelper; + /** + * The backoff timer for handling name resolution failures. + */ + private readonly backoffTimeout: BackoffTimeout; + + /** + * Wrapper class that behaves like a `LoadBalancer` and also handles name + * resolution internally. + * @param target The address of the backend to connect to. + * @param channelControlHelper `ChannelControlHelper` instance provided by + * this load balancer's owner. + * @param defaultServiceConfig The default service configuration to be used + * if none is provided by the name resolver. A `null` value indicates + * that the default behavior should be the default unconfigured behavior. + * In practice, that means using the "pick first" load balancer + * implmentation + */ constructor (private target: string, private channelControlHelper: ChannelControlHelper, private defaultServiceConfig: ServiceConfig | null) { - this.channelControlHelper.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.innerResolver = createResolver(target, { onSuccessfulResolution: (addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null) => { let workingServiceConfig: ServiceConfig | null = null; + /* This first group of conditionals implements the algorithm described + * in https://github.com/grpc/proposal/blob/master/A21-service-config-error-handling.md + * in the section called "Behavior on receiving a new gRPC Config". + */ if (serviceConfig === null) { + // Step 4 and 5 if (serviceConfigError === null) { + // Step 5 this.previousServiceConfig = serviceConfig; workingServiceConfig = this.defaultServiceConfig; } else { - if (this.defaultServiceConfig === undefined) { - // resolution actually failed + // Step 4 + if (this.previousServiceConfig === undefined) { + // Step 4.ii + if (this.defaultServiceConfig === null) { + // Step 4.ii.b + this.handleResolutionFailure(serviceConfigError); + } else { + // Step 4.ii.a + workingServiceConfig = this.defaultServiceConfig + } } else { - workingServiceConfig = this.defaultServiceConfig; + // Step 4.i + workingServiceConfig = this.previousServiceConfig; } } } else { + // Step 3 workingServiceConfig = serviceConfig; this.previousServiceConfig = serviceConfig; } @@ -109,7 +161,11 @@ export class ResolvingLoadBalancer implements LoadBalancer { } if (loadBalancerName === null) { // There were load balancing configs but none are supported. This counts as a resolution failure - // TODO: handle error + this.handleResolutionFailure({ + code: Status.UNAVAILABLE, + details: 'All load balancer options in service config are not compatible', + metadata: new Metadata() + }); return; } } @@ -128,7 +184,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.pendingReplacementLoadBalancer.updateAddressList(addressList, loadBalancingConfig); } }, - onError: (error: ServiceError) => { + onError: (error: StatusObject) => { this.handleResolutionFailure(error); } }); @@ -139,15 +195,21 @@ export class ResolvingLoadBalancer implements LoadBalancer { }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.innerBalancerState = connectivityState; - if (connectivityState === ConnectivityState.TRANSIENT_FAILURE && this.pendingReplacementLoadBalancer !== null) { + if (connectivityState !== ConnectivityState.READY && this.pendingReplacementLoadBalancer !== null) { this.switchOverReplacementBalancer(); } else { - this.channelControlHelper.updateState(connectivityState, picker); + this.updateState(connectivityState, picker); } }, requestReresolution: () => { if (this.pendingReplacementLoadBalancer === null) { - this.innerResolver.updateResolution(); + /* If the backoffTimeout is running, we're still backing off from + * making resolve requests, so we shouldn't make another one here. + * In that case, the backoff timer callback will call + * updateResolution */ + if (!this.backoffTimeout.isRunning()) { + this.innerResolver.updateResolution(); + } } } } @@ -164,9 +226,28 @@ export class ResolvingLoadBalancer implements LoadBalancer { } }, requestReresolution: () => { - this.innerResolver.updateResolution(); + if (!this.backoffTimeout.isRunning()) { + /* If the backoffTimeout is running, we're still backing off from + * making resolve requests, so we shouldn't make another one here. + * In that case, the backoff timer callback will call + * updateResolution */ + this.innerResolver.updateResolution(); + } } }; + + this.backoffTimeout = new BackoffTimeout(() => { + if (this.innerLoadBalancer === null) { + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + } else { + this.innerResolver.updateResolution(); + } + }); + } + + private updateState(connectivitystate: ConnectivityState, picker: Picker) { + this.currentState = connectivitystate; + this.channelControlHelper.updateState(connectivitystate, picker); } /** @@ -180,11 +261,14 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.innerLoadBalancer.replaceChannelControlHelper(this.innerChannelControlHelper); this.pendingReplacementLoadBalancer = null; this.innerBalancerState = this.replacementBalancerState; - this.channelControlHelper.updateState(this.replacementBalancerState, this.replacementBalancerPicker); + this.updateState(this.replacementBalancerState, this.replacementBalancerPicker); } - private handleResolutionFailure(error: ServiceError) { - + private handleResolutionFailure(error: StatusObject) { + if (this.innerLoadBalancer === null) { + this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error)); + } + this.backoffTimeout.runOnce(); } exitIdle() { @@ -192,6 +276,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { if (this.innerLoadBalancer !== null) { this.innerLoadBalancer.exitIdle(); } + this.channelControlHelper.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null) { @@ -199,7 +284,13 @@ export class ResolvingLoadBalancer implements LoadBalancer { } resetBackoff() { - // TODO + this.backoffTimeout.reset(); + if (this.innerLoadBalancer !== null) { + this.innerLoadBalancer.resetBackoff(); + } + if (this.pendingReplacementLoadBalancer !== null) { + this.pendingReplacementLoadBalancer.resetBackoff(); + } } destroy() { @@ -211,7 +302,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.pendingReplacementLoadBalancer.destroy(); this.pendingReplacementLoadBalancer = null; } - // Go to another state? + this.updateState(ConnectivityState.SHUTDOWN, new UnavailablePicker()); } getTypeName() { diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index c181f87b6..b4f1f6472 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -17,7 +17,10 @@ /* This file implements gRFC A2 and the service config spec: * https://github.com/grpc/proposal/blob/master/A2-service-configs-in-dns.md - * https://github.com/grpc/grpc/blob/master/doc/service_config.md */ + * https://github.com/grpc/grpc/blob/master/doc/service_config.md. Each + * function here takes an object with unknown structure and returns its + * specific object type if the input has the right structure, and throws an + * error otherwise. */ import * as lbconfig from './load-balancing-config'; import { isString, isArray, isBoolean, isNumber } from 'util'; @@ -42,6 +45,7 @@ export interface ServiceConfig { methodConfig: MethodConfig[]; } + export interface ServiceConfigCanaryConfig { clientLanguage?: string[]; percentage?: number; @@ -49,8 +53,16 @@ export interface ServiceConfigCanaryConfig { serviceConfig: ServiceConfig; } +/** + * Recognizes a number with up to 9 digits after the decimal point, followed by + * an "s", representing a number of seconds. + */ const TIMEOUT_REGEX = /^\d+(\.\d{1,9})?s$/; +/** + * Client language name used for determining whether this client matches a + * `ServiceConfigCanaryConfig`'s `clientLanguage` list. + */ const CLIENT_LANGUAGE_STRING = 'node'; function validateName(obj: any): MethodConfigName { @@ -246,11 +258,15 @@ function validateAndSelectCanaryConfig(obj: any, percentage: number): ServiceCon * can fail with an error; the caller must handle any errors thrown this way. * @param txtRecord The TXT record array that is output from a successful call to dns.resolveTxt * @param percentage A number chosen from the range [0, 100) that is used to select which config to use + * @return The service configuration to use, given the percentage value, or null if the service config + * data has a valid format but none of the options match the current client. */ export function extractAndSelectServiceConfig(txtRecord: string[][], percentage: number): ServiceConfig | null { for (const record of txtRecord) { if (record.length > 0 && record[0].startsWith('grpc_config=')) { - const recordString = [record[0].substring('grpc_config='.length)].concat(record.slice(1)).join(''); + /* Treat the list of strings in this record as a single string and remove + * "grpc_config=" from the beginning. The rest should be a JSON string */ + const recordString = record.join('').substring('grpc_config='.length); const recordJson: any = JSON.parse(recordString); return validateAndSelectCanaryConfig(recordJson, percentage); } diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 55274295f..bbefc16cf 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -20,11 +20,21 @@ import { Subchannel } from "./subchannel"; import { ChannelCredentials } from "./channel-credentials"; // 10 seconds in milliseconds. This value is arbitrary. +/** + * The amount of time in between checks for dropping subchannels that have no + * other references + */ const REF_CHECK_INTERVAL = 10_000; export class SubchannelPool { private pool: {[channelTarget: string]: {[subchannelTarget: string]: {channelArguments: ChannelOptions, channelCredentials: ChannelCredentials, subchannel: Subchannel}[]}} = Object.create(null); + /** + * A pool of subchannels use for making connections. Subchannels with the + * exact same parameters will be reused. + * @param global If true, this is the global subchannel pool. Otherwise, it + * is the pool for a single channel. + */ constructor(private global: boolean) { if (global) { setInterval(() => { @@ -44,6 +54,14 @@ export class SubchannelPool { } } + /** + * Get a subchannel if one already exists with exactly matching parameters. + * Otherwise, create and save a subchannel with those parameters. + * @param channelTarget + * @param subchannelTarget + * @param channelArguments + * @param channelCredentials + */ getOrCreateSubchannel(channelTarget: string, subchannelTarget: string, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials): Subchannel { if (channelTarget in this.pool) { if (subchannelTarget in this.pool[channelTarget]){ @@ -73,6 +91,10 @@ export class SubchannelPool { const globalSubchannelPool = new SubchannelPool(true); +/** + * Get either the global subchannel pool, or a new subchannel pool. + * @param global + */ export function getSubchannelPool(global: boolean): SubchannelPool { if (global) { return globalSubchannelPool; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index fce4a83f0..5dae2c221 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -21,6 +21,8 @@ import { Metadata } from './metadata'; import { Http2CallStream } from './call-stream'; import { ChannelOptions } from './channel-options'; import { PeerCertificate, checkServerIdentity } from 'tls'; +import { ConnectivityState } from './channel'; +import { BackoffTimeout } from './backoff-timeout'; const { version: clientVersion } = require('../../package.json'); @@ -36,14 +38,7 @@ const BACKOFF_JITTER = 0.2; const KEEPALIVE_TIME_MS = ~(1 << 31); const KEEPALIVE_TIMEOUT_MS = 20000; -export enum SubchannelConnectivityState { - READY, - CONNECTING, - TRANSIENT_FAILURE, - IDLE -}; - -export type ConnectivityStateListener = (subchannel: Subchannel, previousState: SubchannelConnectivityState, newState: SubchannelConnectivityState) => void; +export type ConnectivityStateListener = (subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState) => void; const { HTTP2_HEADER_AUTHORITY, @@ -54,26 +49,59 @@ const { HTTP2_HEADER_USER_AGENT, } = http2.constants; +/** + * Get a number uniformly at random in the range [min, max) + * @param min + * @param max + */ function uniformRandom(min: number, max: number) { return Math.random() * (max - min) + min; } export class Subchannel { - private connectivityState: SubchannelConnectivityState = SubchannelConnectivityState.IDLE; + /** + * The subchannel's current connectivity state. Invariant: `session` === `null` + * if and only if `connectivityState` is IDLE or TRANSIENT_FAILURE. + */ + private connectivityState: ConnectivityState = ConnectivityState.IDLE; + /** + * The underlying http2 session used to make requests. + */ private session: http2.ClientHttp2Session | null = null; - // Indicates that we should continue conection attempts after backoff time ends + /** + * Indicates that the subchannel should transition from TRANSIENT_FAILURE to + * CONNECTING instead of IDLE when the backoff timeout ends. + */ private continueConnecting: boolean = false; + /** + * A list of listener functions that will be called whenever the connectivity + * state changes. Will be modified by `addConnectivityStateListener` and + * `removeConnectivityStateListener` + */ private stateListeners: ConnectivityStateListener[] = []; - private backoffTimerId: NodeJS.Timer; - // The backoff value that will be used the next time we try to connect - private nextBackoff: number = INITIAL_BACKOFF_MS; + private backoffTimeout: BackoffTimeout; + /** + * The complete user agent string constructed using channel args. + */ private userAgent: string; + /** + * The amount of time in between sending pings + */ private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; + /** + * The amount of time to wait for an acknowledgement after sending a ping + */ private keepaliveTimeoutMs: number = KEEPALIVE_TIMEOUT_MS; + /** + * Timer reference for timeout that indicates when to send the next ping + */ private keepaliveIntervalId: NodeJS.Timer; + /** + * Timer reference tracking when the most recent ping will be considered lost + */ private keepaliveTimeoutId: NodeJS.Timer; /** @@ -85,6 +113,16 @@ export class Subchannel { */ private refcount: number = 0; + /** + * A class representing a connection to a single backend. + * @param channelTarget The target string for the channel as a whole + * @param subchannelAddress The address for the backend that this subchannel + * will connect to + * @param options The channel options, plus any specific subchannel options + * for this subchannel + * @param credentials The channel credentials used to establish this + * connection + */ constructor(private channelTarget: string, private subchannelAddress: string, private options: ChannelOptions, @@ -98,11 +136,6 @@ export class Subchannel { .filter(e => e) .join(' '); // remove falsey values first - /* The only purpose of these lines is to ensure that this.backoffTimerId has - * a value of type NodeJS.Timer. */ - this.backoffTimerId = setTimeout(() => {}, 0); - clearTimeout(this.backoffTimerId); - if ('grpc.keepalive_time_ms' in options) { this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; } @@ -113,35 +146,33 @@ export class Subchannel { clearTimeout(this.keepaliveIntervalId); this.keepaliveTimeoutId = setTimeout(() => {}, 0); clearTimeout(this.keepaliveTimeoutId); + this.backoffTimeout = new BackoffTimeout(() => { + + if (this.continueConnecting) { + this.transitionToState([ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], + ConnectivityState.CONNECTING); + } else { + this.transitionToState([ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], + ConnectivityState.IDLE); + } + }); } /** * Start a backoff timer with the current nextBackoff timeout */ private startBackoff() { - this.backoffTimerId = setTimeout(() => { - - if (this.continueConnecting) { - this.transitionToState([SubchannelConnectivityState.TRANSIENT_FAILURE, SubchannelConnectivityState.CONNECTING], - SubchannelConnectivityState.CONNECTING); - } else { - this.transitionToState([SubchannelConnectivityState.TRANSIENT_FAILURE, SubchannelConnectivityState.CONNECTING], - SubchannelConnectivityState.IDLE); - } - }, this.nextBackoff) - const nextBackoff = Math.min(this.nextBackoff * BACKOFF_MULTIPLIER, MAX_BACKOFF_MS); - const jitterMagnitude = nextBackoff * BACKOFF_JITTER; - this.nextBackoff = nextBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude); + this.backoffTimeout.runOnce(); } private stopBackoff() { - clearTimeout(this.backoffTimerId); - this.nextBackoff = INITIAL_BACKOFF_MS; + this.backoffTimeout.stop(); + this.backoffTimeout.reset(); } private sendPing() { this.keepaliveTimeoutId = setTimeout(() => { - // Not sure what to do when keepalive pings fail + this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); this.session!.ping( (err: Error | null, duration: number, payload: Buffer) => { @@ -164,36 +195,44 @@ export class Subchannel { private startConnectingInternal() { const connectionOptions: http2.SecureClientSessionOptions = - this.credentials._getConnectionOptions() || {}; - if (connectionOptions.secureContext !== null) { - // If provided, the value of grpc.ssl_target_name_override should be used - // to override the target hostname when checking server identity. - // This option is used for testing only. - if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = this.options[ - 'grpc.ssl_target_name_override' - ]!; - connectionOptions.checkServerIdentity = ( - host: string, - cert: PeerCertificate - ): Error | undefined => { - return checkServerIdentity(sslTargetNameOverride, cert); - }; - connectionOptions.servername = sslTargetNameOverride; - } + this.credentials._getConnectionOptions() || {}; + let addressScheme = 'http://'; + if ('secureContext' in connectionOptions) { + addressScheme = 'https://'; + // If provided, the value of grpc.ssl_target_name_override should be used + // to override the target hostname when checking server identity. + // This option is used for testing only. + if (this.options['grpc.ssl_target_name_override']) { + const sslTargetNameOverride = this.options[ + 'grpc.ssl_target_name_override' + ]!; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; + connectionOptions.servername = sslTargetNameOverride; + } else { + connectionOptions.servername = this.channelTarget; } - this.session = http2.connect(this.subchannelAddress, connectionOptions); + } + this.session = http2.connect(addressScheme + this.subchannelAddress, connectionOptions); this.session.unref(); this.session.once('connect', () => { - this.transitionToState([SubchannelConnectivityState.CONNECTING], SubchannelConnectivityState.READY); + this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.READY); }); this.session.once('close', () => { - this.transitionToState([SubchannelConnectivityState.CONNECTING, SubchannelConnectivityState.READY], - SubchannelConnectivityState.TRANSIENT_FAILURE); + this.transitionToState([ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE); }); this.session.once('goaway', () => { - this.transitionToState([SubchannelConnectivityState.CONNECTING, SubchannelConnectivityState.READY], - SubchannelConnectivityState.IDLE); + this.transitionToState([ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.IDLE); + }); + this.session.once('error', (error) => { + /* Do nothing here. Any error should also trigger a close event, which is + * where we want to handle that. */ }); } @@ -205,8 +244,8 @@ export class Subchannel { * @returns True if the state changed, false otherwise */ private transitionToState( - oldStates: SubchannelConnectivityState[], - newState: SubchannelConnectivityState + oldStates: ConnectivityState[], + newState: ConnectivityState ): boolean { if (oldStates.indexOf(this.connectivityState) === -1) { return false; @@ -214,23 +253,25 @@ export class Subchannel { let previousState = this.connectivityState; this.connectivityState = newState; switch (newState) { - case SubchannelConnectivityState.READY: + case ConnectivityState.READY: this.stopBackoff(); break; - case SubchannelConnectivityState.CONNECTING: + case ConnectivityState.CONNECTING: this.startBackoff(); this.startConnectingInternal(); this.continueConnecting = false; break; - case SubchannelConnectivityState.TRANSIENT_FAILURE: + case ConnectivityState.TRANSIENT_FAILURE: this.session = null; + this.stopKeepalivePings(); break; - case SubchannelConnectivityState.IDLE: + case ConnectivityState.IDLE: /* Stopping the backoff timer here is probably redundant because we * should only transition to the IDLE state as a result of the timer * ending, but we still want to reset the backoff timeout. */ this.stopBackoff(); this.session = null; + this.stopKeepalivePings(); } /* We use a shallow copy of the stateListeners array in case a listener * is removed during this iteration */ @@ -240,14 +281,18 @@ export class Subchannel { return true; } + /** + * Check if the subchannel associated with zero calls and with zero channels. + * If so, shut it down. + */ private checkBothRefcounts() { /* If no calls, channels, or subchannel pools have any more references to * this subchannel, we can be sure it will never be used again. */ if (this.callRefcount === 0 && this.refcount === 0) { - this.transitionToState([SubchannelConnectivityState.CONNECTING, - SubchannelConnectivityState.IDLE, - SubchannelConnectivityState.READY], - SubchannelConnectivityState.TRANSIENT_FAILURE); + this.transitionToState([ConnectivityState.CONNECTING, + ConnectivityState.IDLE, + ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE); } } @@ -289,6 +334,13 @@ export class Subchannel { return false; } + /** + * Start a stream on the current session with the given `metadata` as headers + * and then attach it to the `callStream`. Must only be called if the + * subchannel's current connectivity state is READY. + * @param metadata + * @param callStream + */ startCallStream(metadata: Metadata, callStream: Http2CallStream) { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); @@ -305,26 +357,45 @@ export class Subchannel { callStream.attachHttp2Stream(http2Stream); } + /** + * If the subchannel is currently IDLE, start connecting and switch to the + * CONNECTING state. If the subchannel is current in TRANSIENT_FAILURE, + * the next time it would transition to IDLE, start connecting again instead. + * Otherwise, do nothing. + */ startConnecting() { /* First, try to transition from IDLE to connecting. If that doesn't happen * because the state is not currently IDLE, check if it is * TRANSIENT_FAILURE, and if so indicate that it should go back to * connecting after the backoff timer ends. Otherwise do nothing */ - if (!this.transitionToState([SubchannelConnectivityState.IDLE], SubchannelConnectivityState.CONNECTING)) { - if (this.connectivityState === SubchannelConnectivityState.TRANSIENT_FAILURE) { + if (!this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING)) { + if (this.connectivityState === ConnectivityState.TRANSIENT_FAILURE) { this.continueConnecting = true; } } } + /** + * Get the subchannel's current connectivity state. + */ getConnectivityState() { return this.connectivityState; } + /** + * Add a listener function to be called whenever the subchannel's + * connectivity state changes. + * @param listener + */ addConnectivityStateListener(listener: ConnectivityStateListener) { this.stateListeners.push(listener); } + /** + * Remove a listener previously added with `addConnectivityStateListener` + * @param listener A reference to a function previously passed to + * `addConnectivityStateListener` + */ removeConnectivityStateListener(listener: ConnectivityStateListener) { const listenerIndex = this.stateListeners.indexOf(listener); if (listenerIndex > -1) { @@ -332,8 +403,11 @@ export class Subchannel { } } + /** + * Reset the backoff timeout, and immediately start connecting if in backoff. + */ resetBackoff() { - this.nextBackoff = INITIAL_BACKOFF_MS; - this.transitionToState([SubchannelConnectivityState.TRANSIENT_FAILURE], SubchannelConnectivityState.CONNECTING); + this.backoffTimeout.reset(); + this.transitionToState([ConnectivityState.TRANSIENT_FAILURE], ConnectivityState.CONNECTING); } } \ No newline at end of file diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index a85366c78..795f596fd 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -23,7 +23,7 @@ import * as stream from 'stream'; import { CallCredentials } from '../src/call-credentials'; import { Http2CallStream } from '../src/call-stream'; -import { Channel, Http2Channel } from '../src/channel'; +import { Channel, ChannelImplementation } from '../src/channel'; import { CompressionFilterFactory } from '../src/compression-filter'; import { Status } from '../src/constants'; import { FilterStackFactory } from '../src/filter-stack'; @@ -132,9 +132,10 @@ describe('CallStream', () => { responseMetadata.add('key', 'value'); const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ @@ -179,9 +180,10 @@ describe('CallStream', () => { return new Promise((resolve, reject) => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.alloc(0), @@ -206,9 +208,10 @@ describe('CallStream', () => { it('should have functioning getters', done => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); assert.strictEqual(callStream.getStatus(), null); @@ -232,9 +235,10 @@ describe('CallStream', () => { it('should handle an empty message', done => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: serialize(''), @@ -272,9 +276,10 @@ describe('CallStream', () => { it(`should handle a short message where ${testCase.description}`, done => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: serialize(message), // 21 bytes @@ -317,9 +322,10 @@ describe('CallStream', () => { it(`should handle two messages where ${testCase.description}`, done => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.concat([serialize(message), serialize(message)]), // 42 bytes @@ -346,9 +352,10 @@ describe('CallStream', () => { it('should send buffered writes', done => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.alloc(0), @@ -380,9 +387,10 @@ describe('CallStream', () => { it('should cause data chunks in write calls afterward to be written to the given stream', done => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.alloc(0), @@ -409,9 +417,10 @@ describe('CallStream', () => { it('should handle underlying stream errors', () => { const callStream = new Http2CallStream( 'foo', - {} as Http2Channel, + {} as ChannelImplementation, callStreamArgs, - filterStackFactory + filterStackFactory, + CallCredentials.createEmpty() ); const http2Stream = new ClientHttp2StreamMock({ payload: Buffer.alloc(0), diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index c2013da25..d6028f469 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -38,13 +38,13 @@ class CallCredentialsMock implements CallCredentials { return new CallCredentialsMock(callCredentials); } - isEqual(other: CallCredentialsMock): boolean { + _equals(other: CallCredentialsMock): boolean { if (!this.child) { return this === other; } else if (!other || !other.child) { return false; } else { - return this.child.isEqual(other.child); + return this.child._equals(other.child); } } } @@ -131,7 +131,7 @@ describe('ChannelCredentials Implementation', () => { // Build a mock object that should be an identical copy const composedCallCreds = callCreds1.compose(callCreds2); assert.ok( - composedCallCreds.isEqual( + composedCallCreds._equals( composedChannelCreds._getCallCredentials() as CallCredentialsMock ) ); diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 35230ef8c..7c0764918 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 35230ef8cd70d62ab94bee661b7cd641adfa805b +Subproject commit 7c0764918b9f33cab507ff483b4be849b0203ec4 From 5aef347fb9160002fcbc47db9195882424b6c527 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 28 Aug 2019 17:44:30 -0700 Subject: [PATCH 0754/1899] Proceed through pick-first list quickly when subchannel enters TRANSIENT_FAILURE --- .../grpc-js/src/load-balancer-pick-first.ts | 35 +++++++++++++------ 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 37aa4091e..047aad71f 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -117,6 +117,13 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.startConnecting(); }); } + /* If the subchannel we most recently attempted to start connecting + * to goes into TRANSIENT_FAILURE, immediately try to start + * connecting to the next one instead of waiting for the connection + * delay timer. */ + if (subchannel === this.subchannels[this.currentSubchannelIndex] && newState === ConnectivityState.TRANSIENT_FAILURE) { + this.startNextSubchannelConnecting(); + } if (this.triedAllSubchannels) { const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; if (newLBState !== this.currentState) { @@ -153,6 +160,23 @@ export class PickFirstLoadBalancer implements LoadBalancer { clearTimeout(this.connectionDelayTimeout); } + + private startNextSubchannelConnecting() { + if (this.triedAllSubchannels) { + return; + } + for (const [index, subchannel] of this.subchannels.entries()) { + if (index > this.currentSubchannelIndex) { + const subchannelState = subchannel.getConnectivityState(); + if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.CONNECTING) { + this.startConnecting(index); + return; + } + } + } + this.triedAllSubchannels = true; + } + /** * Have a single subchannel in the `subchannels` list start connecting. * @param subchannelIndex The index into the `subchannels` list. @@ -166,16 +190,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { }); } this.connectionDelayTimeout = setTimeout(() => { - for (const [index, subchannel] of this.subchannels.entries()) { - if (index > subchannelIndex) { - const subchannelState = subchannel.getConnectivityState(); - if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.CONNECTING) { - this.startConnecting(index); - return; - } - } - } - this.triedAllSubchannels = true; + this.startNextSubchannelConnecting(); }, CONNECTION_DELAY_INTERVAL_MS) } From b4d848865d025d6935fd747de89e515bf04dae41 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 28 Aug 2019 18:03:57 -0700 Subject: [PATCH 0755/1899] Lint fixes --- packages/grpc-js/src/backoff-timeout.ts | 16 +- packages/grpc-js/src/call-credentials.ts | 6 +- packages/grpc-js/src/channel-credentials.ts | 31 +++- packages/grpc-js/src/channel-options.ts | 7 +- packages/grpc-js/src/channel.ts | 175 ++++++++++++------ packages/grpc-js/src/client.ts | 6 +- packages/grpc-js/src/compression-filter.ts | 4 +- .../grpc-js/src/load-balancer-pick-first.ts | 117 +++++++++--- packages/grpc-js/src/load-balancer.ts | 38 ++-- packages/grpc-js/src/load-balancing-config.ts | 27 +-- packages/grpc-js/src/picker.ts | 26 +-- packages/grpc-js/src/resolver-dns.ts | 123 +++++++----- packages/grpc-js/src/resolver.ts | 43 +++-- .../grpc-js/src/resolving-load-balancer.ts | 143 ++++++++++---- packages/grpc-js/src/service-config.ts | 108 +++++++---- packages/grpc-js/src/subchannel-pool.ts | 73 ++++++-- packages/grpc-js/src/subchannel.ts | 146 +++++++++------ packages/grpc-js/test/test-call-stream.ts | 4 +- 18 files changed, 737 insertions(+), 356 deletions(-) diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts index 84956c437..8cad14f74 100644 --- a/packages/grpc-js/src/backoff-timeout.ts +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -22,8 +22,8 @@ const BACKOFF_JITTER = 0.2; /** * Get a number uniformly at random in the range [min, max) - * @param min - * @param max + * @param min + * @param max */ function uniformRandom(min: number, max: number) { return Math.random() * (max - min) + min; @@ -43,7 +43,7 @@ export class BackoffTimeout { private jitter: number = BACKOFF_JITTER; private nextDelay: number; private timerId: NodeJS.Timer; - private running: boolean = false; + private running = false; constructor(private callback: () => void, options?: BackoffOptions) { if (options) { @@ -74,9 +74,13 @@ export class BackoffTimeout { this.callback(); this.running = false; }, this.nextDelay); - const nextBackoff = Math.min(this.nextDelay * this.multiplier, this.maxDelay); + const nextBackoff = Math.min( + this.nextDelay * this.multiplier, + this.maxDelay + ); const jitterMagnitude = nextBackoff * this.jitter; - this.nextDelay = nextBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude); + this.nextDelay = + nextBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude); } /** @@ -98,4 +102,4 @@ export class BackoffTimeout { isRunning() { return this.running; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index fd32baffd..e38672ae2 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -96,7 +96,9 @@ class ComposedCallCredentials extends CallCredentials { return true; } if (other instanceof ComposedCallCredentials) { - return this.creds.every((value, index) => value._equals(other.creds[index])); + return this.creds.every((value, index) => + value._equals(other.creds[index]) + ); } else { return false; } @@ -134,7 +136,7 @@ class SingleCallCredentials extends CallCredentials { return false; } } - } +} class EmptyCallCredentials extends CallCredentials { generateMetadata(options: CallMetadataOptions): Promise { diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 345c99bfe..c29885fa7 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -140,7 +140,12 @@ export abstract class ChannelCredentials { 'Certificate chain must be given with accompanying private key' ); } - return new SecureChannelCredentialsImpl(rootCerts || null, privateKey || null, certChain || null, verifyOptions || {}); + return new SecureChannelCredentialsImpl( + rootCerts || null, + privateKey || null, + certChain || null, + verifyOptions || {} + ); } /** @@ -224,7 +229,10 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { if (!bufferOrNullEqual(this.certChain, other.certChain)) { return false; } - return this.verifyOptions.checkServerIdentity === other.verifyOptions.checkServerIdentity; + return ( + this.verifyOptions.checkServerIdentity === + other.verifyOptions.checkServerIdentity + ); } else { return false; } @@ -232,12 +240,20 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { } class ComposedChannelCredentialsImpl extends ChannelCredentials { - constructor (private channelCredentials: SecureChannelCredentialsImpl, callCreds: CallCredentials) { + constructor( + private channelCredentials: SecureChannelCredentialsImpl, + callCreds: CallCredentials + ) { super(callCreds); } compose(callCredentials: CallCredentials) { - const combinedCallCredentials = this.callCredentials.compose(callCredentials); - return new ComposedChannelCredentialsImpl(this.channelCredentials, combinedCallCredentials); + const combinedCallCredentials = this.callCredentials.compose( + callCredentials + ); + return new ComposedChannelCredentialsImpl( + this.channelCredentials, + combinedCallCredentials + ); } _getConnectionOptions(): ConnectionOptions | null { @@ -251,7 +267,10 @@ class ComposedChannelCredentialsImpl extends ChannelCredentials { return true; } if (other instanceof ComposedChannelCredentialsImpl) { - return this.channelCredentials._equals(other.channelCredentials) && this.callCredentials._equals(other.callCredentials); + return ( + this.channelCredentials._equals(other.channelCredentials) && + this.callCredentials._equals(other.callCredentials) + ); } else { return false; } diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index b54b69cb0..b71459700 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -41,13 +41,16 @@ export const recognizedOptions = { 'grpc.keepalive_timeout_ms': true, }; -export function channelOptionsEqual(options1: ChannelOptions, options2: ChannelOptions) { +export function channelOptionsEqual( + options1: ChannelOptions, + options2: ChannelOptions +) { const keys1 = Object.keys(options1).sort(); const keys2 = Object.keys(options2).sort(); if (keys1.length !== keys2.length) { return false; } - for (let i = 0; i < keys1.length; i+=1) { + for (let i = 0; i < keys1.length; i += 1) { if (keys1[i] !== keys2[i]) { return false; } diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 331a34f6f..1a2a1db66 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -15,23 +15,28 @@ * */ -import { Deadline, Call, Http2CallStream, CallStreamOptions } from "./call-stream"; -import { ChannelCredentials } from "./channel-credentials"; -import { ChannelOptions } from "./channel-options"; -import { ResolvingLoadBalancer } from "./resolving-load-balancer"; -import { SubchannelPool, getSubchannelPool } from "./subchannel-pool"; -import { ChannelControlHelper } from "./load-balancer"; -import { UnavailablePicker, Picker, PickResultType } from "./picker"; -import { Metadata } from "./metadata"; -import { Status } from "./constants"; -import { FilterStackFactory } from "./filter-stack"; -import { CallCredentialsFilterFactory } from "./call-credentials-filter"; -import { DeadlineFilterFactory } from "./deadline-filter"; -import { MetadataStatusFilterFactory } from "./metadata-status-filter"; -import { CompressionFilterFactory } from "./compression-filter"; -import { getDefaultAuthority } from "./resolver"; -import { LoadBalancingConfig } from "./load-balancing-config"; -import { ServiceConfig } from "./service-config"; +import { + Deadline, + Call, + Http2CallStream, + CallStreamOptions, +} from './call-stream'; +import { ChannelCredentials } from './channel-credentials'; +import { ChannelOptions } from './channel-options'; +import { ResolvingLoadBalancer } from './resolving-load-balancer'; +import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; +import { ChannelControlHelper } from './load-balancer'; +import { UnavailablePicker, Picker, PickResultType } from './picker'; +import { Metadata } from './metadata'; +import { Status } from './constants'; +import { FilterStackFactory } from './filter-stack'; +import { CallCredentialsFilterFactory } from './call-credentials-filter'; +import { DeadlineFilterFactory } from './deadline-filter'; +import { MetadataStatusFilterFactory } from './metadata-status-filter'; +import { CompressionFilterFactory } from './compression-filter'; +import { getDefaultAuthority } from './resolver'; +import { LoadBalancingConfig } from './load-balancing-config'; +import { ServiceConfig } from './service-config'; export enum ConnectivityState { CONNECTING, @@ -111,37 +116,58 @@ export class ChannelImplementation implements Channel { private subchannelPool: SubchannelPool; private connectivityState: ConnectivityState = ConnectivityState.IDLE; private currentPicker: Picker = new UnavailablePicker(); - private pickQueue: {callStream: Http2CallStream, callMetadata: Metadata}[] = []; + private pickQueue: Array<{ + callStream: Http2CallStream; + callMetadata: Metadata; + }> = []; private connectivityStateWatchers: ConnectivityStateWatcher[] = []; private defaultAuthority: string; private filterStackFactory: FilterStackFactory; - constructor(private target: string, private readonly credentials: ChannelCredentials, private readonly options: ChannelOptions) { + constructor( + private target: string, + private readonly credentials: ChannelCredentials, + private readonly options: ChannelOptions + ) { // TODO: check channel arg for getting a private pool this.subchannelPool = getSubchannelPool(true); const channelControlHelper: ChannelControlHelper = { - createSubchannel: (subchannelAddress: string, subchannelArgs: ChannelOptions) => { - return this.subchannelPool.getOrCreateSubchannel(this.target, subchannelAddress, Object.assign({}, this.options, subchannelArgs), this.credentials); + createSubchannel: ( + subchannelAddress: string, + subchannelArgs: ChannelOptions + ) => { + return this.subchannelPool.getOrCreateSubchannel( + this.target, + subchannelAddress, + Object.assign({}, this.options, subchannelArgs), + this.credentials + ); }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.currentPicker = picker; const queueCopy = this.pickQueue.slice(); this.pickQueue = []; - for (const {callStream, callMetadata} of queueCopy) { + for (const { callStream, callMetadata } of queueCopy) { this.tryPick(callStream, callMetadata); } this.updateState(connectivityState); }, requestReresolution: () => { // This should never be called. - throw new Error('Resolving load balancer should never call requestReresolution'); - } + throw new Error( + 'Resolving load balancer should never call requestReresolution' + ); + }, }; // TODO: check channel arg for default service config const defaultServiceConfig: ServiceConfig = { loadBalancingConfig: [], - methodConfig: [] - } - this.resolvingLoadBalancer = new ResolvingLoadBalancer(target, channelControlHelper, defaultServiceConfig); + methodConfig: [], + }; + this.resolvingLoadBalancer = new ResolvingLoadBalancer( + target, + channelControlHelper, + defaultServiceConfig + ); this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), @@ -160,50 +186,79 @@ export class ChannelImplementation implements Channel { * Check the picker output for the given call and corresponding metadata, * and take any relevant actions. Should not be called while iterating * over pickQueue. - * @param callStream - * @param callMetadata + * @param callStream + * @param callMetadata */ private tryPick(callStream: Http2CallStream, callMetadata: Metadata) { - const pickResult = this.currentPicker.pick({metadata: callMetadata}); - switch(pickResult.pickResultType) { + const pickResult = this.currentPicker.pick({ metadata: callMetadata }); + switch (pickResult.pickResultType) { case PickResultType.COMPLETE: if (pickResult.subchannel === null) { - callStream.cancelWithStatus(Status.UNAVAILABLE, "Request dropped by load balancing policy"); + callStream.cancelWithStatus( + Status.UNAVAILABLE, + 'Request dropped by load balancing policy' + ); // End the call with an error } else { /* If the subchannel disconnects between calling pick and getting * the filter stack metadata, the call will end with an error. */ - callStream.filterStack.sendMetadata(Promise.resolve(new Metadata())).then((finalMetadata) => { - if (pickResult.subchannel!.getConnectivityState() === ConnectivityState.READY) { - pickResult.subchannel!.startCallStream(callMetadata, callStream); - } else { - callStream.cancelWithStatus(Status.UNAVAILABLE, 'Connection dropped while starting call'); - } - }, - (error: Error & { code: number }) => { - // We assume the error code isn't 0 (Status.OK) - callStream.cancelWithStatus( - error.code || Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${error.message}` + callStream.filterStack + .sendMetadata(Promise.resolve(new Metadata())) + .then( + finalMetadata => { + if ( + pickResult.subchannel!.getConnectivityState() === + ConnectivityState.READY + ) { + pickResult.subchannel!.startCallStream( + callMetadata, + callStream + ); + } else { + callStream.cancelWithStatus( + Status.UNAVAILABLE, + 'Connection dropped while starting call' + ); + } + }, + (error: Error & { code: number }) => { + // We assume the error code isn't 0 (Status.OK) + callStream.cancelWithStatus( + error.code || Status.UNKNOWN, + `Getting metadata from plugin failed with error: ${ + error.message + }` + ); + } ); - }); } break; case PickResultType.QUEUE: - this.pickQueue.push({callStream, callMetadata}); + this.pickQueue.push({ callStream, callMetadata }); break; case PickResultType.TRANSIENT_FAILURE: if (callMetadata.getOptions().waitForReady) { - this.pickQueue.push({callStream, callMetadata}); + this.pickQueue.push({ callStream, callMetadata }); } else { - callStream.cancelWithStatus(pickResult.status!.code, pickResult.status!.details); + callStream.cancelWithStatus( + pickResult.status!.code, + pickResult.status!.details + ); } break; + default: + throw new Error( + `Invalid state: unknown pickResultType ${pickResult.pickResultType}` + ); } } - private removeConnectivityStateWatcher(watcherObject: ConnectivityStateWatcher) { - const watcherIndex = this.connectivityStateWatchers.findIndex((value) => value === watcherObject); + private removeConnectivityStateWatcher( + watcherObject: ConnectivityStateWatcher + ) { + const watcherIndex = this.connectivityStateWatchers.findIndex( + value => value === watcherObject + ); if (watcherIndex >= 0) { this.connectivityStateWatchers.splice(watcherIndex, 1); } @@ -237,25 +292,31 @@ export class ChannelImplementation implements Channel { getConnectivityState() { return this.connectivityState; } - + watchConnectivityState( currentState: ConnectivityState, deadline: Date | number, callback: (error?: Error) => void ): void { - const deadlineDate: Date = deadline instanceof Date ? deadline : new Date(deadline); + const deadlineDate: Date = + deadline instanceof Date ? deadline : new Date(deadline); const now = new Date(); if (deadlineDate <= now) { - process.nextTick(callback, new Error('Deadline passed without connectivity state change')); + process.nextTick( + callback, + new Error('Deadline passed without connectivity state change') + ); return; } const watcherObject = { - currentState, + currentState, callback, timer: setTimeout(() => { this.removeConnectivityStateWatcher(watcherObject); - callback(new Error('Deadline passed without connectivity state change')); - }, deadlineDate.getTime() - now.getTime()) + callback( + new Error('Deadline passed without connectivity state change') + ); + }, deadlineDate.getTime() - now.getTime()), }; this.connectivityStateWatchers.push(watcherObject); } @@ -286,4 +347,4 @@ export class ChannelImplementation implements Channel { ); return stream; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 87c5c5f20..0e2cffe7f 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -78,7 +78,11 @@ export class Client { options ); } else { - this[CHANNEL_SYMBOL] = new ChannelImplementation(address, credentials, options); + this[CHANNEL_SYMBOL] = new ChannelImplementation( + address, + credentials, + options + ); } } diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index ff2dcbeb2..f28568e7c 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -138,7 +138,9 @@ class UnknownHandler extends CompressionHandler { compressMessage(message: Buffer): Promise { return Promise.reject( new Error( - `Received message compressed wth unsupported compression method ${this.compressionName}` + `Received message compressed wth unsupported compression method ${ + this.compressionName + }` ) ); } diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 047aad71f..c8e220b8c 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -15,9 +15,20 @@ * */ -import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType } from './load-balancer'; +import { + LoadBalancer, + ChannelControlHelper, + registerLoadBalancerType, +} from './load-balancer'; import { ConnectivityState } from './channel'; -import { QueuePicker, Picker, PickArgs, CompletePickResult, PickResultType, UnavailablePicker } from './picker'; +import { + QueuePicker, + Picker, + PickArgs, + CompletePickResult, + PickResultType, + UnavailablePicker, +} from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; import { Subchannel, ConnectivityStateListener } from './subchannel'; @@ -36,12 +47,12 @@ const CONNECTION_DELAY_INTERVAL_MS = 250; class PickFirstPicker implements Picker { constructor(private subchannel: Subchannel) {} - pick(pickArgs: PickArgs) : CompletePickResult { + pick(pickArgs: PickArgs): CompletePickResult { return { pickResultType: PickResultType.COMPLETE, subchannel: this.subchannel, - status: null - } + status: null, + }; } } @@ -63,12 +74,12 @@ export class PickFirstLoadBalancer implements LoadBalancer { * The index within the `subchannels` array of the subchannel with the most * recently started connection attempt. */ - private currentSubchannelIndex: number = 0; + private currentSubchannelIndex = 0; /** * The number of subchannels in the `subchannels` list currently in the * CONNECTING state. Used to determine the overall load balancer state. */ - private subchannelConnectingCount: number = 0; + private subchannelConnectingCount = 0; /** * The currently picked subchannel used for making calls. Populated if * and only if the load balancer's current state is READY. In that case, @@ -85,11 +96,11 @@ export class PickFirstLoadBalancer implements LoadBalancer { */ private pickedSubchannelStateListener: ConnectivityStateListener; /** - * Timer reference for the timer tracking when to start + * Timer reference for the timer tracking when to start */ private connectionDelayTimeout: NodeJS.Timeout; - private triedAllSubchannels: boolean = false; + private triedAllSubchannels = false; /** * Load balancer that attempts to connect to each backend in the address list @@ -100,7 +111,11 @@ export class PickFirstLoadBalancer implements LoadBalancer { */ constructor(private channelControlHelper: ChannelControlHelper) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); - this.subchannelStateListener = (subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState) => { + this.subchannelStateListener = ( + subchannel: Subchannel, + previousState: ConnectivityState, + newState: ConnectivityState + ) => { if (previousState === ConnectivityState.CONNECTING) { this.subchannelConnectingCount -= 1; } @@ -112,7 +127,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { return; } else { if (this.currentPick === null) { - if (newState === ConnectivityState.TRANSIENT_FAILURE || newState === ConnectivityState.IDLE) { + if ( + newState === ConnectivityState.TRANSIENT_FAILURE || + newState === ConnectivityState.IDLE + ) { process.nextTick(() => { subchannel.startConnecting(); }); @@ -121,11 +139,17 @@ export class PickFirstLoadBalancer implements LoadBalancer { * to goes into TRANSIENT_FAILURE, immediately try to start * connecting to the next one instead of waiting for the connection * delay timer. */ - if (subchannel === this.subchannels[this.currentSubchannelIndex] && newState === ConnectivityState.TRANSIENT_FAILURE) { + if ( + subchannel === this.subchannels[this.currentSubchannelIndex] && + newState === ConnectivityState.TRANSIENT_FAILURE + ) { this.startNextSubchannelConnecting(); } if (this.triedAllSubchannels) { - const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; + const newLBState = + this.subchannelConnectingCount > 0 + ? ConnectivityState.CONNECTING + : ConnectivityState.TRANSIENT_FAILURE; if (newLBState !== this.currentState) { if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { this.updateState(newLBState, new UnavailablePicker()); @@ -134,17 +158,29 @@ export class PickFirstLoadBalancer implements LoadBalancer { } } } else { - this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + this.updateState( + ConnectivityState.CONNECTING, + new QueuePicker(this) + ); } } } }; - this.pickedSubchannelStateListener = (subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState) => { + this.pickedSubchannelStateListener = ( + subchannel: Subchannel, + previousState: ConnectivityState, + newState: ConnectivityState + ) => { if (newState !== ConnectivityState.READY) { subchannel.unref(); - subchannel.removeConnectivityStateListener(this.pickedSubchannelStateListener); + subchannel.removeConnectivityStateListener( + this.pickedSubchannelStateListener + ); if (this.subchannels.length > 0) { - const newLBState = this.subchannelConnectingCount > 0 ? ConnectivityState.CONNECTING : ConnectivityState.TRANSIENT_FAILURE; + const newLBState = + this.subchannelConnectingCount > 0 + ? ConnectivityState.CONNECTING + : ConnectivityState.TRANSIENT_FAILURE; if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { this.updateState(newLBState, new UnavailablePicker()); } else { @@ -160,7 +196,6 @@ export class PickFirstLoadBalancer implements LoadBalancer { clearTimeout(this.connectionDelayTimeout); } - private startNextSubchannelConnecting() { if (this.triedAllSubchannels) { return; @@ -168,7 +203,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { for (const [index, subchannel] of this.subchannels.entries()) { if (index > this.currentSubchannelIndex) { const subchannelState = subchannel.getConnectivityState(); - if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.CONNECTING) { + if ( + subchannelState === ConnectivityState.IDLE || + subchannelState === ConnectivityState.CONNECTING + ) { this.startConnecting(index); return; } @@ -184,20 +222,25 @@ export class PickFirstLoadBalancer implements LoadBalancer { private startConnecting(subchannelIndex: number) { clearTimeout(this.connectionDelayTimeout); this.currentSubchannelIndex = subchannelIndex; - if (this.subchannels[subchannelIndex].getConnectivityState() === ConnectivityState.IDLE) { + if ( + this.subchannels[subchannelIndex].getConnectivityState() === + ConnectivityState.IDLE + ) { process.nextTick(() => { this.subchannels[subchannelIndex].startConnecting(); }); } this.connectionDelayTimeout = setTimeout(() => { this.startNextSubchannelConnecting(); - }, CONNECTION_DELAY_INTERVAL_MS) + }, CONNECTION_DELAY_INTERVAL_MS); } private pickSubchannel(subchannel: Subchannel) { if (this.currentPick !== null) { this.currentPick.unref(); - this.currentPick.removeConnectivityStateListener(this.pickedSubchannelStateListener); + this.currentPick.removeConnectivityStateListener( + this.pickedSubchannelStateListener + ); } this.currentPick = subchannel; this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); @@ -229,7 +272,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { */ private connectToAddressList(): void { this.resetSubchannelList(); - this.subchannels = this.latestAddressList.map((address) => this.channelControlHelper.createSubchannel(address, {})); + this.subchannels = this.latestAddressList.map(address => + this.channelControlHelper.createSubchannel(address, {}) + ); for (const subchannel of this.subchannels) { subchannel.ref(); } @@ -237,24 +282,36 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.addConnectivityStateListener(this.subchannelStateListener); if (subchannel.getConnectivityState() === ConnectivityState.READY) { this.pickSubchannel(subchannel); - this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); + this.updateState( + ConnectivityState.READY, + new PickFirstPicker(subchannel) + ); this.resetSubchannelList(); return; } } for (const [index, subchannel] of this.subchannels.entries()) { const subchannelState = subchannel.getConnectivityState(); - if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.CONNECTING) { + if ( + subchannelState === ConnectivityState.IDLE || + subchannelState === ConnectivityState.CONNECTING + ) { this.startConnecting(index); this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); return; } } // If the code reaches this point, every subchannel must be in TRANSIENT_FAILURE - this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker()); + this.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker() + ); } - updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void { + updateAddressList( + addressList: string[], + lbConfig: LoadBalancingConfig | null + ): void { // lbConfig has no useful information for pick first load balancing this.latestAddressList = addressList; this.connectToAddressList(); @@ -277,7 +334,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.resetSubchannelList(); if (this.currentPick !== null) { this.currentPick.unref(); - this.currentPick.removeConnectivityStateListener(this.pickedSubchannelStateListener); + this.currentPick.removeConnectivityStateListener( + this.pickedSubchannelStateListener + ); } } @@ -292,4 +351,4 @@ export class PickFirstLoadBalancer implements LoadBalancer { export function setup(): void { registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 7f0ca2ca1..a74deea73 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -15,11 +15,11 @@ * */ -import { ChannelOptions } from "./channel-options"; -import { Subchannel } from "./subchannel"; -import { ConnectivityState } from "./channel"; -import { Picker } from "./picker"; -import { LoadBalancingConfig } from "./load-balancing-config"; +import { ChannelOptions } from './channel-options'; +import { Subchannel } from './subchannel'; +import { ConnectivityState } from './channel'; +import { Picker } from './picker'; +import { LoadBalancingConfig } from './load-balancing-config'; import * as load_balancer_pick_first from './load-balancer-pick-first'; /** @@ -32,7 +32,10 @@ export interface ChannelControlHelper { * @param subchannelAddress The address to connect to * @param subchannelArgs Extra channel arguments specified by the load balancer */ - createSubchannel(subchannelAddress: string, subchannelArgs: ChannelOptions): Subchannel; + createSubchannel( + subchannelAddress: string, + subchannelArgs: ChannelOptions + ): Subchannel; /** * Passes a new subchannel picker up to the channel. This is called if either * the connectivity state changes or if a different picker is needed for any @@ -61,7 +64,10 @@ export interface LoadBalancer { * @param lbConfig The load balancing config object from the service config, * if one was provided */ - updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void; + updateAddressList( + addressList: string[], + lbConfig: LoadBalancingConfig | null + ): void; /** * If the load balancer is currently in the IDLE state, start connecting. */ @@ -91,16 +97,24 @@ export interface LoadBalancer { } export interface LoadBalancerConstructor { - new(channelControlHelper: ChannelControlHelper): LoadBalancer; + new (channelControlHelper: ChannelControlHelper): LoadBalancer; } -const registeredLoadBalancerTypes: {[name: string]: LoadBalancerConstructor} = {}; +const registeredLoadBalancerTypes: { + [name: string]: LoadBalancerConstructor; +} = {}; -export function registerLoadBalancerType(typeName: string, loadBalancerType: LoadBalancerConstructor) { +export function registerLoadBalancerType( + typeName: string, + loadBalancerType: LoadBalancerConstructor +) { registeredLoadBalancerTypes[typeName] = loadBalancerType; } -export function createLoadBalancer(typeName: string, channelControlHelper: ChannelControlHelper): LoadBalancer | null { +export function createLoadBalancer( + typeName: string, + channelControlHelper: ChannelControlHelper +): LoadBalancer | null { if (typeName in registeredLoadBalancerTypes) { return new registeredLoadBalancerTypes[typeName](channelControlHelper); } else { @@ -114,4 +128,4 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { export function registerAll() { load_balancer_pick_first.setup(); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index df74cdcb8..8607f1fce 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -21,10 +21,11 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ -import { isString, isArray } from "util"; +/* The any type is purposely used here. All functions validate their input at + * runtime */ +/* tslint:disable:no-any */ -export interface RoundRobinConfig { -} +export interface RoundRobinConfig {} export interface XdsConfig { balancerName: string; @@ -48,16 +49,16 @@ export interface LoadBalancingConfig { * effectively */ function validateXdsConfig(xds: any): XdsConfig { - if (!('balancerName' in xds) || !isString(xds.balancerName)) { + if (!('balancerName' in xds) || typeof xds.balancerName !== 'string') { throw new Error('Invalid xds config: invalid balancerName'); } const xdsConfig: XdsConfig = { balancerName: xds.balancerName, childPolicy: [], - fallbackPolicy: [] + fallbackPolicy: [], }; if ('childPolicy' in xds) { - if (!isArray(xds.childPolicy)) { + if (!Array.isArray(xds.childPolicy)) { throw new Error('Invalid xds config: invalid childPolicy'); } for (const policy of xds.childPolicy) { @@ -65,7 +66,7 @@ function validateXdsConfig(xds: any): XdsConfig { } } if ('fallbackPolicy' in xds) { - if (!isArray(xds.fallbackPolicy)) { + if (!Array.isArray(xds.fallbackPolicy)) { throw new Error('Invalid xds config: invalid fallbackPolicy'); } for (const policy of xds.fallbackPolicy) { @@ -77,10 +78,10 @@ function validateXdsConfig(xds: any): XdsConfig { function validateGrpcLbConfig(grpclb: any): GrpcLbConfig { const grpcLbConfig: GrpcLbConfig = { - childPolicy: [] + childPolicy: [], }; if ('childPolicy' in grpclb) { - if (!isArray(grpclb.childPolicy)) { + if (!Array.isArray(grpclb.childPolicy)) { throw new Error('Invalid xds config: invalid childPolicy'); } for (const policy of grpclb.childPolicy) { @@ -96,17 +97,17 @@ export function validateConfig(obj: any): LoadBalancingConfig { throw new Error('Multiple load balancing policies configured'); } if (obj['round_robin'] instanceof Object) { - return { round_robin: {} } + return { round_robin: {} }; } } if ('xds' in obj) { if ('grpclb' in obj) { throw new Error('Multiple load balancing policies configured'); } - return {xds: validateXdsConfig(obj.xds)}; + return { xds: validateXdsConfig(obj.xds) }; } if ('grpclb' in obj) { - return {grpclb: validateGrpcLbConfig(obj.grpclb)}; + return { grpclb: validateGrpcLbConfig(obj.grpclb) }; } throw new Error('No recognized load balancing policy configured'); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index ebed1df43..94b8fbe24 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -15,16 +15,16 @@ * */ -import { Subchannel } from "./subchannel"; -import { StatusObject } from "./call-stream"; -import { Metadata } from "./metadata"; -import { Status } from "./constants"; -import { LoadBalancer } from "./load-balancer"; +import { Subchannel } from './subchannel'; +import { StatusObject } from './call-stream'; +import { Metadata } from './metadata'; +import { Status } from './constants'; +import { LoadBalancer } from './load-balancer'; export enum PickResultType { COMPLETE, QUEUE, - TRANSIENT_FAILURE + TRANSIENT_FAILURE, } export interface PickResult { @@ -85,8 +85,8 @@ export class UnavailablePicker implements Picker { } else { this.status = { code: Status.UNAVAILABLE, - details: "No connection established", - metadata: new Metadata() + details: 'No connection established', + metadata: new Metadata(), }; } } @@ -94,7 +94,7 @@ export class UnavailablePicker implements Picker { return { pickResultType: PickResultType.TRANSIENT_FAILURE, subchannel: null, - status: this.status + status: this.status, }; } } @@ -107,7 +107,7 @@ export class UnavailablePicker implements Picker { * once any pick is attempted. */ export class QueuePicker { - private calledExitIdle: boolean = false; + private calledExitIdle = false; // Constructed with a load balancer. Calls exitIdle on it the first time pick is called constructor(private loadBalancer: LoadBalancer) {} @@ -119,7 +119,7 @@ export class QueuePicker { return { pickResultType: PickResultType.QUEUE, subchannel: null, - status: null - } + status: null, + }; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index e0c397c90..ff91a8f26 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -14,7 +14,12 @@ * limitations under the License. */ -import { Resolver, ResolverListener, registerResolver, registerDefaultResolver } from './resolver'; +import { + Resolver, + ResolverListener, + registerResolver, + registerDefaultResolver, +} from './resolver'; import * as dns from 'dns'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; @@ -30,17 +35,17 @@ import { Metadata } from './metadata'; * Matches 4 groups of up to 3 digits each, separated by periods, optionally * followed by a colon and a number. */ -const IPv4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/; +const IPV4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/; /** * Matches any number of groups of up to 4 hex digits (case insensitive) * separated by 1 or more colons. This variant does not match a port number. */ -const IPv6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i; +const IPV6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i; /** * Matches the same as the IPv6_REGEX, surrounded by square brackets, and * optionally followed by a colon and a number. */ -const IPv6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i; +const IPV6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i; /** * Matches `[dns:][//authority/]host[:port]`, where `authority` and `host` are @@ -60,13 +65,16 @@ const resolve6Promise = util.promisify(dns.resolve6); /** * Attempt to parse a target string as an IP address - * @param target + * @param target * @return An "IP:port" string if parsing was successful, `null` otherwise */ function parseIP(target: string): string | null { /* These three regular expressions are all mutually exclusive, so we just * want the first one that matches the target string, if any do. */ - const match = IPv4_REGEX.exec(target) || IPv6_REGEX.exec(target) || IPv6_BRACKET_REGEX.exec(target); + const match = + IPV4_REGEX.exec(target) || + IPV6_REGEX.exec(target) || + IPV6_BRACKET_REGEX.exec(target); if (match === null) { return null; } @@ -82,13 +90,17 @@ function parseIP(target: string): string | null { /** * Merge any number of arrays into a single alternating array - * @param arrays + * @param arrays */ function mergeArrays(...arrays: T[][]): T[] { const result: T[] = []; - for(let i = 0; i array.length)); i++) { - for(let array of arrays) { - if(i < array.length) { + for ( + let i = 0; + i < Math.max.apply(null, arrays.map(array => array.length)); + i++ + ) { + for (const array of arrays) { + if (i < array.length) { result.push(array[i]); } } @@ -105,7 +117,9 @@ class DnsResolver implements Resolver { private readonly port: string | null; /* The promise results here contain, in order, the A record, the AAAA record, * and either the TXT record or an error if TXT resolution failed */ - pendingResultPromise: Promise<[string[], string[], string[][] | Error]> | null = null; + pendingResultPromise: Promise< + [string[], string[], string[][] | Error] + > | null = null; percentage: number; constructor(private target: string, private listener: ResolverListener) { this.ipResult = parseIP(target); @@ -126,7 +140,7 @@ class DnsResolver implements Resolver { /** * If the target is an IP address, just provide that address as a result. - * Otherwise, initiate A, AAAA, and TXT + * Otherwise, initiate A, AAAA, and TXT */ private startResolution() { if (this.ipResult !== null) { @@ -137,12 +151,12 @@ class DnsResolver implements Resolver { } if (this.dnsHostname !== null) { const hostname: string = this.dnsHostname; - const Aresult = resolve4Promise(hostname); - const AAAAresult = resolve6Promise(hostname); + const aResult = resolve4Promise(hostname); + const aaaaResult = resolve6Promise(hostname); /* We handle the TXT query promise differently than the others because * the name resolution attempt as a whole is a success even if the TXT * lookup fails */ - const TXTresult = new Promise((resolve, reject) => { + const txtResult = new Promise((resolve, reject) => { dns.resolveTxt(hostname, (err, records) => { if (err) { resolve(err); @@ -151,41 +165,51 @@ class DnsResolver implements Resolver { } }); }); - this.pendingResultPromise = Promise.all([Aresult, AAAAresult, TXTresult]); - this.pendingResultPromise.then(([Arecord, AAAArecord, TXTrecord]) => { - this.pendingResultPromise = null; - Arecord = Arecord.map((value) => `${value}:${this.port}`); - AAAArecord = AAAArecord.map((value) => `[${value}]:${this.port}`); - const allAddresses: string[] = mergeArrays(AAAArecord, Arecord); - let serviceConfig: ServiceConfig | null = null; - let serviceConfigError: StatusObject | null = null; - if (TXTrecord instanceof Error) { - serviceConfigError = { - code: Status.UNAVAILABLE, - details: 'TXT query failed', - metadata: new Metadata() - }; - } else { - try { - serviceConfig = extractAndSelectServiceConfig(TXTrecord, this.percentage); - } catch (err) { + this.pendingResultPromise = Promise.all([aResult, aaaaResult, txtResult]); + this.pendingResultPromise.then( + ([aRecord, aaaaRecord, txtRecord]) => { + this.pendingResultPromise = null; + aRecord = aRecord.map(value => `${value}:${this.port}`); + aaaaRecord = aaaaRecord.map(value => `[${value}]:${this.port}`); + const allAddresses: string[] = mergeArrays(aaaaRecord, aRecord); + let serviceConfig: ServiceConfig | null = null; + let serviceConfigError: StatusObject | null = null; + if (txtRecord instanceof Error) { serviceConfigError = { code: Status.UNAVAILABLE, - details: 'Parsing service config failed', - metadata: new Metadata() + details: 'TXT query failed', + metadata: new Metadata(), }; + } else { + try { + serviceConfig = extractAndSelectServiceConfig( + txtRecord, + this.percentage + ); + } catch (err) { + serviceConfigError = { + code: Status.UNAVAILABLE, + details: 'Parsing service config failed', + metadata: new Metadata(), + }; + } } + this.listener.onSuccessfulResolution( + allAddresses, + serviceConfig, + serviceConfigError + ); + }, + err => { + this.pendingResultPromise = null; + this.listener.onError({ + code: Status.UNAVAILABLE, + details: 'Name resolution failed', + metadata: new Metadata(), + }); + this.listener.onError(err); } - this.listener.onSuccessfulResolution(allAddresses, serviceConfig, serviceConfigError); - }, (err) => { - this.pendingResultPromise = null; - this.listener.onError({ - code: Status.UNAVAILABLE, - details: 'Name resolution failed', - metadata: new Metadata() - }); - this.listener.onError(err); - }); + ); } } @@ -198,10 +222,13 @@ class DnsResolver implements Resolver { /** * Get the default authority for the given target. For IP targets, that is * the IP address. For DNS targets, it is the hostname. - * @param target + * @param target */ static getDefaultAuthority(target: string): string { - const ipMatch = IPv4_REGEX.exec(target) || IPv6_REGEX.exec(target) || IPv6_BRACKET_REGEX.exec(target); + const ipMatch = + IPV4_REGEX.exec(target) || + IPV6_REGEX.exec(target) || + IPV6_BRACKET_REGEX.exec(target); if (ipMatch) { return ipMatch[1]; } @@ -220,4 +247,4 @@ class DnsResolver implements Resolver { export function setup(): void { registerResolver('dns:', DnsResolver); registerDefaultResolver(DnsResolver); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index a27782c22..b4c69f3df 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -15,10 +15,10 @@ * */ -import { ServiceError } from "./call"; -import { ServiceConfig } from "./service-config"; +import { ServiceError } from './call'; +import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; -import { StatusObject } from "./call-stream"; +import { StatusObject } from './call-stream'; /** * A listener object passed to the resolver's constructor that provides name @@ -34,7 +34,11 @@ export interface ResolverListener { * @param serviceConfigError If non-`null`, indicates that the retrieved * service configuration was invalid */ - onSuccessfulResolution(addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null): void; + onSuccessfulResolution( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ): void; /** * Called whenever a name resolution attempt fails. * @param error Describes how resolution failed @@ -56,36 +60,38 @@ export interface Resolver { updateResolution(): void; } - export interface ResolverConstructor { - new(target: string, listener: ResolverListener): Resolver; + new (target: string, listener: ResolverListener): Resolver; /** * Get the default authority for a target. This loosely corresponds to that * target's hostname. Throws an error if this resolver class cannot parse the * `target`. * @param target */ - getDefaultAuthority(target:string): string; + getDefaultAuthority(target: string): string; } -const registeredResolvers: {[prefix: string]: ResolverConstructor} = {}; +const registeredResolvers: { [prefix: string]: ResolverConstructor } = {}; let defaultResolver: ResolverConstructor | null = null; /** * Register a resolver class to handle target names prefixed with the `prefix` * string. This prefix should correspond to a URI scheme name listed in the * [gRPC Name Resolution document](https://github.com/grpc/grpc/blob/master/doc/naming.md) - * @param prefix - * @param resolverClass + * @param prefix + * @param resolverClass */ -export function registerResolver(prefix: string, resolverClass: ResolverConstructor) { +export function registerResolver( + prefix: string, + resolverClass: ResolverConstructor +) { registeredResolvers[prefix] = resolverClass; } /** * Register a default resolver to handle target names that do not start with * any registered prefix. - * @param resolverClass + * @param resolverClass */ export function registerDefaultResolver(resolverClass: ResolverConstructor) { defaultResolver = resolverClass; @@ -94,10 +100,13 @@ export function registerDefaultResolver(resolverClass: ResolverConstructor) { /** * Create a name resolver for the specified target, if possible. Throws an * error if no such name resolver can be created. - * @param target - * @param listener + * @param target + * @param listener */ -export function createResolver(target: string, listener: ResolverListener): Resolver { +export function createResolver( + target: string, + listener: ResolverListener +): Resolver { for (const prefix of Object.keys(registeredResolvers)) { if (target.startsWith(prefix)) { return new registeredResolvers[prefix](target, listener); @@ -112,7 +121,7 @@ export function createResolver(target: string, listener: ResolverListener): Reso /** * Get the default authority for the specified target, if possible. Throws an * error if no registered name resolver can parse that target string. - * @param target + * @param target */ export function getDefaultAuthority(target: string): string { for (const prefix of Object.keys(registerDefaultResolver)) { @@ -128,4 +137,4 @@ export function getDefaultAuthority(target: string): string { export function registerAll() { resolver_dns.setup(); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 6d13f75fc..12f1b3b7d 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -15,18 +15,23 @@ * */ -import { ChannelControlHelper, LoadBalancer, isLoadBalancerNameRegistered, createLoadBalancer } from "./load-balancer"; -import { ServiceConfig } from "./service-config"; -import { ConnectivityState } from "./channel"; -import { createResolver, Resolver } from "./resolver"; -import { ServiceError } from "./call"; -import { ChannelOptions } from "./channel-options"; -import { Picker, UnavailablePicker, QueuePicker } from "./picker"; -import { LoadBalancingConfig } from "./load-balancing-config"; -import { BackoffTimeout } from "./backoff-timeout"; -import { Status } from "./constants"; -import { StatusObject } from "./call-stream"; -import { Metadata } from "./metadata"; +import { + ChannelControlHelper, + LoadBalancer, + isLoadBalancerNameRegistered, + createLoadBalancer, +} from './load-balancer'; +import { ServiceConfig } from './service-config'; +import { ConnectivityState } from './channel'; +import { createResolver, Resolver } from './resolver'; +import { ServiceError } from './call'; +import { ChannelOptions } from './channel-options'; +import { Picker, UnavailablePicker, QueuePicker } from './picker'; +import { LoadBalancingConfig } from './load-balancing-config'; +import { BackoffTimeout } from './backoff-timeout'; +import { Status } from './constants'; +import { StatusObject } from './call-stream'; +import { Metadata } from './metadata'; const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; @@ -103,10 +108,18 @@ export class ResolvingLoadBalancer implements LoadBalancer { * In practice, that means using the "pick first" load balancer * implmentation */ - constructor (private target: string, private channelControlHelper: ChannelControlHelper, private defaultServiceConfig: ServiceConfig | null) { + constructor( + private target: string, + private channelControlHelper: ChannelControlHelper, + private defaultServiceConfig: ServiceConfig | null + ) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.innerResolver = createResolver(target, { - onSuccessfulResolution: (addressList: string[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null) => { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: ServiceError | null + ) => { let workingServiceConfig: ServiceConfig | null = null; /* This first group of conditionals implements the algorithm described * in https://github.com/grpc/proposal/blob/master/A21-service-config-error-handling.md @@ -127,7 +140,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.handleResolutionFailure(serviceConfigError); } else { // Step 4.ii.a - workingServiceConfig = this.defaultServiceConfig + workingServiceConfig = this.defaultServiceConfig; } } else { // Step 4.i @@ -141,7 +154,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { } let loadBalancerName: string | null = null; let loadBalancingConfig: LoadBalancingConfig | null = null; - if (workingServiceConfig === null || workingServiceConfig.loadBalancingConfig.length === 0) { + if ( + workingServiceConfig === null || + workingServiceConfig.loadBalancingConfig.length === 0 + ) { loadBalancerName = DEFAULT_LOAD_BALANCER_NAME; } else { for (const lbConfig of workingServiceConfig.loadBalancingConfig) { @@ -163,39 +179,68 @@ export class ResolvingLoadBalancer implements LoadBalancer { // There were load balancing configs but none are supported. This counts as a resolution failure this.handleResolutionFailure({ code: Status.UNAVAILABLE, - details: 'All load balancer options in service config are not compatible', - metadata: new Metadata() + details: + 'All load balancer options in service config are not compatible', + metadata: new Metadata(), }); return; } } if (this.innerLoadBalancer === null) { - this.innerLoadBalancer = createLoadBalancer(loadBalancerName, this.innerChannelControlHelper)!; - this.innerLoadBalancer.updateAddressList(addressList, loadBalancingConfig); + this.innerLoadBalancer = createLoadBalancer( + loadBalancerName, + this.innerChannelControlHelper + )!; + this.innerLoadBalancer.updateAddressList( + addressList, + loadBalancingConfig + ); } else if (this.innerLoadBalancer.getTypeName() === loadBalancerName) { - this.innerLoadBalancer.updateAddressList(addressList, loadBalancingConfig); + this.innerLoadBalancer.updateAddressList( + addressList, + loadBalancingConfig + ); } else { - if (this.pendingReplacementLoadBalancer === null || this.pendingReplacementLoadBalancer.getTypeName() !== loadBalancerName) { + if ( + this.pendingReplacementLoadBalancer === null || + this.pendingReplacementLoadBalancer.getTypeName() !== + loadBalancerName + ) { if (this.pendingReplacementLoadBalancer !== null) { this.pendingReplacementLoadBalancer.destroy(); } - this.pendingReplacementLoadBalancer = createLoadBalancer(loadBalancerName, this.replacementChannelControlHelper)!; + this.pendingReplacementLoadBalancer = createLoadBalancer( + loadBalancerName, + this.replacementChannelControlHelper + )!; } - this.pendingReplacementLoadBalancer.updateAddressList(addressList, loadBalancingConfig); + this.pendingReplacementLoadBalancer.updateAddressList( + addressList, + loadBalancingConfig + ); } }, onError: (error: StatusObject) => { this.handleResolutionFailure(error); - } + }, }); this.innerChannelControlHelper = { - createSubchannel: (subchannelAddress: string, subchannelArgs: ChannelOptions) => { - return this.channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + createSubchannel: ( + subchannelAddress: string, + subchannelArgs: ChannelOptions + ) => { + return this.channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ); }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.innerBalancerState = connectivityState; - if (connectivityState !== ConnectivityState.READY && this.pendingReplacementLoadBalancer !== null) { + if ( + connectivityState !== ConnectivityState.READY && + this.pendingReplacementLoadBalancer !== null + ) { this.switchOverReplacementBalancer(); } else { this.updateState(connectivityState, picker); @@ -211,12 +256,18 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.innerResolver.updateResolution(); } } - } - } + }, + }; this.replacementChannelControlHelper = { - createSubchannel: (subchannelAddress: string, subchannelArgs: ChannelOptions) => { - return this.channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + createSubchannel: ( + subchannelAddress: string, + subchannelArgs: ChannelOptions + ) => { + return this.channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ); }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.replacementBalancerState = connectivityState; @@ -233,7 +284,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { * updateResolution */ this.innerResolver.updateResolution(); } - } + }, }; this.backoffTimeout = new BackoffTimeout(() => { @@ -258,15 +309,23 @@ export class ResolvingLoadBalancer implements LoadBalancer { private switchOverReplacementBalancer() { this.innerLoadBalancer!.destroy(); this.innerLoadBalancer = this.pendingReplacementLoadBalancer!; - this.innerLoadBalancer.replaceChannelControlHelper(this.innerChannelControlHelper); + this.innerLoadBalancer.replaceChannelControlHelper( + this.innerChannelControlHelper + ); this.pendingReplacementLoadBalancer = null; this.innerBalancerState = this.replacementBalancerState; - this.updateState(this.replacementBalancerState, this.replacementBalancerPicker); + this.updateState( + this.replacementBalancerState, + this.replacementBalancerPicker + ); } private handleResolutionFailure(error: StatusObject) { if (this.innerLoadBalancer === null) { - this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error)); + this.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker(error) + ); } this.backoffTimeout.runOnce(); } @@ -276,10 +335,16 @@ export class ResolvingLoadBalancer implements LoadBalancer { if (this.innerLoadBalancer !== null) { this.innerLoadBalancer.exitIdle(); } - this.channelControlHelper.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + this.channelControlHelper.updateState( + ConnectivityState.CONNECTING, + new QueuePicker(this) + ); } - updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null) { + updateAddressList( + addressList: string[], + lbConfig: LoadBalancingConfig | null + ) { throw new Error('updateAddressList not supported on ResolvingLoadBalancer'); } @@ -312,4 +377,4 @@ export class ResolvingLoadBalancer implements LoadBalancer { replaceChannelControlHelper(channelControlHelper: ChannelControlHelper) { this.channelControlHelper = channelControlHelper; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index b4f1f6472..d9b608127 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -22,8 +22,11 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ +/* The any type is purposely used here. All functions validate their input at + * runtime */ +/* tslint:disable:no-any */ + import * as lbconfig from './load-balancing-config'; -import { isString, isArray, isBoolean, isNumber } from 'util'; import * as os from 'os'; export interface MethodConfigName { @@ -41,11 +44,10 @@ export interface MethodConfig { export interface ServiceConfig { loadBalancingPolicy?: string; - loadBalancingConfig: lbconfig.LoadBalancingConfig[] + loadBalancingConfig: lbconfig.LoadBalancingConfig[]; methodConfig: MethodConfig[]; } - export interface ServiceConfigCanaryConfig { clientLanguage?: string[]; percentage?: number; @@ -66,14 +68,14 @@ const TIMEOUT_REGEX = /^\d+(\.\d{1,9})?s$/; const CLIENT_LANGUAGE_STRING = 'node'; function validateName(obj: any): MethodConfigName { - if (!('service' in obj) || !isString(obj.service)) { + if (!('service' in obj) || typeof obj.service !== 'string') { throw new Error('Invalid method config name: invalid service'); } const result: MethodConfigName = { - service: obj.service + service: obj.service, }; if ('method' in obj) { - if (isString(obj.method)) { + if (typeof obj.method === 'string') { result.method = obj.method; } else { throw new Error('Invalid method config name: invalid method'); @@ -84,34 +86,37 @@ function validateName(obj: any): MethodConfigName { function validateMethodConfig(obj: any): MethodConfig { const result: MethodConfig = { - name: [] + name: [], }; - if (!('name' in obj) || !isArray(obj.name)) { + if (!('name' in obj) || !Array.isArray(obj.name)) { throw new Error('Invalid method config: invalid name array'); } for (const name of obj.name) { result.name.push(validateName(name)); } if ('waitForReady' in obj) { - if (!isBoolean(obj.waitForReady)) { + if (typeof obj.waitForReady !== 'boolean') { throw new Error('Invalid method config: invalid waitForReady'); } result.waitForReady = obj.waitForReady; } if ('timeout' in obj) { - if (!isString(obj.timeout) || !TIMEOUT_REGEX.test(obj.timeout)) { + if ( + !(typeof obj.timeout === 'string') || + !TIMEOUT_REGEX.test(obj.timeout) + ) { throw new Error('Invalid method config: invalid timeout'); } result.timeout = obj.timeout; } if ('maxRequestBytes' in obj) { - if (!isNumber(obj.maxRequestBytes)) { + if (typeof obj.maxRequestBytes !== 'number') { throw new Error('Invalid method config: invalid maxRequestBytes'); } result.maxRequestBytes = obj.maxRequestBytes; } if ('maxResponseBytes' in obj) { - if (!isNumber(obj.maxResponseBytes)) { + if (typeof obj.maxResponseBytes !== 'number') { throw new Error('Invalid method config: invalid maxRequestBytes'); } result.maxResponseBytes = obj.maxResponseBytes; @@ -122,17 +127,17 @@ function validateMethodConfig(obj: any): MethodConfig { function validateServiceConfig(obj: any): ServiceConfig { const result: ServiceConfig = { loadBalancingConfig: [], - methodConfig: [] + methodConfig: [], }; if ('loadBalancingPolicy' in obj) { - if (isString(obj.loadBalancingPolicy)) { + if (typeof obj.loadBalancingPolicy === 'string') { result.loadBalancingPolicy = obj.loadBalancingPolicy; } else { throw new Error('Invalid service config: invalid loadBalancingPolicy'); } } if ('loadBalancingConfig' in obj) { - if (isArray(obj.loadBalancingConfig)) { + if (Array.isArray(obj.loadBalancingConfig)) { for (const config of obj.loadBalancingConfig) { result.loadBalancingConfig.push(lbconfig.validateConfig(config)); } @@ -141,7 +146,7 @@ function validateServiceConfig(obj: any): ServiceConfig { } } if ('methodConfig' in obj) { - if (isArray(obj.methodConfig)) { + if (Array.isArray(obj.methodConfig)) { for (const methodConfig of obj.methodConfig) { result.methodConfig.push(validateMethodConfig(methodConfig)); } @@ -152,8 +157,15 @@ function validateServiceConfig(obj: any): ServiceConfig { for (const methodConfig of result.methodConfig) { for (const name of methodConfig.name) { for (const seenName of seenMethodNames) { - if (name.service === seenName.service && name.method === seenName.method) { - throw new Error(`Invalid service config: duplicate name ${name.service}/${name.method}`); + if ( + name.service === seenName.service && + name.method === seenName.method + ) { + throw new Error( + `Invalid service config: duplicate name ${name.service}/${ + name.method + }` + ); } } seenMethodNames.push(name); @@ -167,16 +179,18 @@ function validateCanaryConfig(obj: any): ServiceConfigCanaryConfig { throw new Error('Invalid service config choice: missing service config'); } const result: ServiceConfigCanaryConfig = { - serviceConfig: validateServiceConfig(obj.serviceConfig) - } + serviceConfig: validateServiceConfig(obj.serviceConfig), + }; if ('clientLanguage' in obj) { - if (isArray(obj.clientLanguage)) { + if (Array.isArray(obj.clientLanguage)) { result.clientLanguage = []; for (const lang of obj.clientLanguage) { - if (isString(lang)) { + if (typeof lang === 'string') { result.clientLanguage.push(lang); } else { - throw new Error('Invalid service config choice: invalid clientLanguage'); + throw new Error( + 'Invalid service config choice: invalid clientLanguage' + ); } } } else { @@ -184,13 +198,15 @@ function validateCanaryConfig(obj: any): ServiceConfigCanaryConfig { } } if ('clientHostname' in obj) { - if (isArray(obj.clientHostname)) { + if (Array.isArray(obj.clientHostname)) { result.clientHostname = []; for (const lang of obj.clientHostname) { - if (isString(lang)) { + if (typeof lang === 'string') { result.clientHostname.push(lang); } else { - throw new Error('Invalid service config choice: invalid clientHostname'); + throw new Error( + 'Invalid service config choice: invalid clientHostname' + ); } } } else { @@ -198,34 +214,51 @@ function validateCanaryConfig(obj: any): ServiceConfigCanaryConfig { } } if ('percentage' in obj) { - if (isNumber(obj.percentage) && 0 <= obj.percentage && obj.percentage <= 100) { + if ( + typeof obj.percentage === 'number' && + 0 <= obj.percentage && + obj.percentage <= 100 + ) { result.percentage = obj.percentage; } else { throw new Error('Invalid service config choice: invalid percentage'); } } // Validate that no unexpected fields are present - const allowedFields = ['clientLanguage', 'percentage', 'clientHostname', 'serviceConfig']; + const allowedFields = [ + 'clientLanguage', + 'percentage', + 'clientHostname', + 'serviceConfig', + ]; for (const field in obj) { if (!allowedFields.includes(field)) { - throw new Error(`Invalid service config choice: unexpected field ${field}`); + throw new Error( + `Invalid service config choice: unexpected field ${field}` + ); } } return result; } -function validateAndSelectCanaryConfig(obj: any, percentage: number): ServiceConfig { - if (!isArray(obj)) { +function validateAndSelectCanaryConfig( + obj: any, + percentage: number +): ServiceConfig { + if (!Array.isArray(obj)) { throw new Error('Invalid service config list'); } for (const config of obj) { const validatedConfig = validateCanaryConfig(config); /* For each field, we check if it is present, then only discard the * config if the field value does not match the current client */ - if (isNumber(validatedConfig.percentage) && percentage > validatedConfig.percentage) { + if ( + typeof validatedConfig.percentage === 'number' && + percentage > validatedConfig.percentage + ) { continue; } - if (isArray(validatedConfig.clientHostname)) { + if (Array.isArray(validatedConfig.clientHostname)) { let hostnameMatched = false; for (const hostname of validatedConfig.clientHostname) { if (hostname === os.hostname()) { @@ -236,7 +269,7 @@ function validateAndSelectCanaryConfig(obj: any, percentage: number): ServiceCon continue; } } - if (isArray(validatedConfig.clientLanguage)) { + if (Array.isArray(validatedConfig.clientLanguage)) { let languageMatched = false; for (const language of validatedConfig.clientLanguage) { if (language === CLIENT_LANGUAGE_STRING) { @@ -261,7 +294,10 @@ function validateAndSelectCanaryConfig(obj: any, percentage: number): ServiceCon * @return The service configuration to use, given the percentage value, or null if the service config * data has a valid format but none of the options match the current client. */ -export function extractAndSelectServiceConfig(txtRecord: string[][], percentage: number): ServiceConfig | null { +export function extractAndSelectServiceConfig( + txtRecord: string[][], + percentage: number +): ServiceConfig | null { for (const record of txtRecord) { if (record.length > 0 && record[0].startsWith('grpc_config=')) { /* Treat the list of strings in this record as a single string and remove @@ -272,4 +308,4 @@ export function extractAndSelectServiceConfig(txtRecord: string[][], percentage: } } return null; -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index bbefc16cf..1a5015b6a 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -15,9 +15,9 @@ * */ -import { ChannelOptions, channelOptionsEqual } from "./channel-options"; -import { Subchannel } from "./subchannel"; -import { ChannelCredentials } from "./channel-credentials"; +import { ChannelOptions, channelOptionsEqual } from './channel-options'; +import { Subchannel } from './subchannel'; +import { ChannelCredentials } from './channel-credentials'; // 10 seconds in milliseconds. This value is arbitrary. /** @@ -27,7 +27,15 @@ import { ChannelCredentials } from "./channel-credentials"; const REF_CHECK_INTERVAL = 10_000; export class SubchannelPool { - private pool: {[channelTarget: string]: {[subchannelTarget: string]: {channelArguments: ChannelOptions, channelCredentials: ChannelCredentials, subchannel: Subchannel}[]}} = Object.create(null); + private pool: { + [channelTarget: string]: { + [subchannelTarget: string]: Array<{ + channelArguments: ChannelOptions; + channelCredentials: ChannelCredentials; + subchannel: Subchannel; + }>; + }; + } = Object.create(null); /** * A pool of subchannels use for making connections. Subchannels with the @@ -38,13 +46,24 @@ export class SubchannelPool { constructor(private global: boolean) { if (global) { setInterval(() => { + /* These objects are created with Object.create(null), so they do not + * have a prototype, which means that for (... in ...) loops over them + * do not need to be filtered */ + // tslint:disable-next-line:forin for (const channelTarget in this.pool) { + // tslint:disable-next-line:forin for (const subchannelTarget in this.pool[channelTarget]) { - const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; + const subchannelObjArray = this.pool[channelTarget][ + subchannelTarget + ]; /* For each subchannel in the pool, try to unref it if it has * exactly one ref (which is the ref from the pool itself). If that * does happen, remove the subchannel from the pool */ - this.pool[channelTarget][subchannelTarget] = subchannelObjArray.filter((value) => !value.subchannel.unrefIfOneRef()); + this.pool[channelTarget][ + subchannelTarget + ] = subchannelObjArray.filter( + value => !value.subchannel.unrefIfOneRef() + ); } } /* Currently we do not delete keys with empty values. If that results @@ -57,31 +76,51 @@ export class SubchannelPool { /** * Get a subchannel if one already exists with exactly matching parameters. * Otherwise, create and save a subchannel with those parameters. - * @param channelTarget - * @param subchannelTarget - * @param channelArguments - * @param channelCredentials + * @param channelTarget + * @param subchannelTarget + * @param channelArguments + * @param channelCredentials */ - getOrCreateSubchannel(channelTarget: string, subchannelTarget: string, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials): Subchannel { + getOrCreateSubchannel( + channelTarget: string, + subchannelTarget: string, + channelArguments: ChannelOptions, + channelCredentials: ChannelCredentials + ): Subchannel { if (channelTarget in this.pool) { - if (subchannelTarget in this.pool[channelTarget]){ + if (subchannelTarget in this.pool[channelTarget]) { const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; for (const subchannelObj of subchannelObjArray) { - if (channelOptionsEqual(channelArguments, subchannelObj.channelArguments) && channelCredentials._equals(subchannelObj.channelCredentials)) { + if ( + channelOptionsEqual( + channelArguments, + subchannelObj.channelArguments + ) && + channelCredentials._equals(subchannelObj.channelCredentials) + ) { return subchannelObj.subchannel; } } } } // If we get here, no matching subchannel was found - const subchannel = new Subchannel(channelTarget, subchannelTarget, channelArguments, channelCredentials); + const subchannel = new Subchannel( + channelTarget, + subchannelTarget, + channelArguments, + channelCredentials + ); if (!(channelTarget in this.pool)) { this.pool[channelTarget] = Object.create(null); } if (!(subchannelTarget in this.pool[channelTarget])) { this.pool[channelTarget][subchannelTarget] = []; } - this.pool[channelTarget][subchannelTarget].push({channelArguments, channelCredentials, subchannel}); + this.pool[channelTarget][subchannelTarget].push({ + channelArguments, + channelCredentials, + subchannel, + }); if (this.global) { subchannel.ref(); } @@ -93,7 +132,7 @@ const globalSubchannelPool = new SubchannelPool(true); /** * Get either the global subchannel pool, or a new subchannel pool. - * @param global + * @param global */ export function getSubchannelPool(global: boolean): SubchannelPool { if (global) { @@ -101,4 +140,4 @@ export function getSubchannelPool(global: boolean): SubchannelPool { } else { return new SubchannelPool(false); } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 5dae2c221..2683643b3 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -38,7 +38,11 @@ const BACKOFF_JITTER = 0.2; const KEEPALIVE_TIME_MS = ~(1 << 31); const KEEPALIVE_TIMEOUT_MS = 20000; -export type ConnectivityStateListener = (subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState) => void; +export type ConnectivityStateListener = ( + subchannel: Subchannel, + previousState: ConnectivityState, + newState: ConnectivityState +) => void; const { HTTP2_HEADER_AUTHORITY, @@ -51,8 +55,8 @@ const { /** * Get a number uniformly at random in the range [min, max) - * @param min - * @param max + * @param min + * @param max */ function uniformRandom(min: number, max: number) { return Math.random() * (max - min) + min; @@ -72,7 +76,7 @@ export class Subchannel { * Indicates that the subchannel should transition from TRANSIENT_FAILURE to * CONNECTING instead of IDLE when the backoff timeout ends. */ - private continueConnecting: boolean = false; + private continueConnecting = false; /** * A list of listener functions that will be called whenever the connectivity * state changes. Will be modified by `addConnectivityStateListener` and @@ -107,11 +111,11 @@ export class Subchannel { /** * Tracks calls with references to this subchannel */ - private callRefcount: number = 0; + private callRefcount = 0; /** * Tracks channels and subchannel pools with references to this subchannel */ - private refcount: number = 0; + private refcount = 0; /** * A class representing a connection to a single backend. @@ -123,40 +127,45 @@ export class Subchannel { * @param credentials The channel credentials used to establish this * connection */ - constructor(private channelTarget: string, + constructor( + private channelTarget: string, private subchannelAddress: string, private options: ChannelOptions, - private credentials: ChannelCredentials) { - // Build user-agent string. - this.userAgent = [ - options['grpc.primary_user_agent'], - `grpc-node-js/${clientVersion}`, - options['grpc.secondary_user_agent'], - ] - .filter(e => e) - .join(' '); // remove falsey values first - - if ('grpc.keepalive_time_ms' in options) { - this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; - } - if ('grpc.keepalive_timeout_ms' in options) { - this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; - } - this.keepaliveIntervalId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveIntervalId); - this.keepaliveTimeoutId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveTimeoutId); - this.backoffTimeout = new BackoffTimeout(() => { - - if (this.continueConnecting) { - this.transitionToState([ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], - ConnectivityState.CONNECTING); - } else { - this.transitionToState([ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], - ConnectivityState.IDLE); - } - }); + private credentials: ChannelCredentials + ) { + // Build user-agent string. + this.userAgent = [ + options['grpc.primary_user_agent'], + `grpc-node-js/${clientVersion}`, + options['grpc.secondary_user_agent'], + ] + .filter(e => e) + .join(' '); // remove falsey values first + + if ('grpc.keepalive_time_ms' in options) { + this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; + } + if ('grpc.keepalive_timeout_ms' in options) { + this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; } + this.keepaliveIntervalId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveIntervalId); + this.keepaliveTimeoutId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveTimeoutId); + this.backoffTimeout = new BackoffTimeout(() => { + if (this.continueConnecting) { + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], + ConnectivityState.CONNECTING + ); + } else { + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], + ConnectivityState.IDLE + ); + } + }); + } /** * Start a backoff timer with the current nextBackoff timeout @@ -195,7 +204,7 @@ export class Subchannel { private startConnectingInternal() { const connectionOptions: http2.SecureClientSessionOptions = - this.credentials._getConnectionOptions() || {}; + this.credentials._getConnectionOptions() || {}; let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { addressScheme = 'https://'; @@ -217,20 +226,30 @@ export class Subchannel { connectionOptions.servername = this.channelTarget; } } - this.session = http2.connect(addressScheme + this.subchannelAddress, connectionOptions); + this.session = http2.connect( + addressScheme + this.subchannelAddress, + connectionOptions + ); this.session.unref(); this.session.once('connect', () => { - this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.READY); + this.transitionToState( + [ConnectivityState.CONNECTING], + ConnectivityState.READY + ); }); this.session.once('close', () => { - this.transitionToState([ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE); + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE + ); }); this.session.once('goaway', () => { - this.transitionToState([ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.IDLE); + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.IDLE + ); }); - this.session.once('error', (error) => { + this.session.once('error', error => { /* Do nothing here. Any error should also trigger a close event, which is * where we want to handle that. */ }); @@ -250,7 +269,7 @@ export class Subchannel { if (oldStates.indexOf(this.connectivityState) === -1) { return false; } - let previousState = this.connectivityState; + const previousState = this.connectivityState; this.connectivityState = newState; switch (newState) { case ConnectivityState.READY: @@ -272,6 +291,9 @@ export class Subchannel { this.stopBackoff(); this.session = null; this.stopKeepalivePings(); + break; + default: + throw new Error(`Invalid state: unknown ConnectivityState ${newState}`); } /* We use a shallow copy of the stateListeners array in case a listener * is removed during this iteration */ @@ -289,10 +311,14 @@ export class Subchannel { /* If no calls, channels, or subchannel pools have any more references to * this subchannel, we can be sure it will never be used again. */ if (this.callRefcount === 0 && this.refcount === 0) { - this.transitionToState([ConnectivityState.CONNECTING, - ConnectivityState.IDLE, - ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE); + this.transitionToState( + [ + ConnectivityState.CONNECTING, + ConnectivityState.IDLE, + ConnectivityState.READY, + ], + ConnectivityState.TRANSIENT_FAILURE + ); } } @@ -338,8 +364,8 @@ export class Subchannel { * Start a stream on the current session with the given `metadata` as headers * and then attach it to the `callStream`. Must only be called if the * subchannel's current connectivity state is READY. - * @param metadata - * @param callStream + * @param metadata + * @param callStream */ startCallStream(metadata: Metadata, callStream: Http2CallStream) { const headers = metadata.toHttp2Headers(); @@ -368,7 +394,12 @@ export class Subchannel { * because the state is not currently IDLE, check if it is * TRANSIENT_FAILURE, and if so indicate that it should go back to * connecting after the backoff timer ends. Otherwise do nothing */ - if (!this.transitionToState([ConnectivityState.IDLE], ConnectivityState.CONNECTING)) { + if ( + !this.transitionToState( + [ConnectivityState.IDLE], + ConnectivityState.CONNECTING + ) + ) { if (this.connectivityState === ConnectivityState.TRANSIENT_FAILURE) { this.continueConnecting = true; } @@ -385,7 +416,7 @@ export class Subchannel { /** * Add a listener function to be called whenever the subchannel's * connectivity state changes. - * @param listener + * @param listener */ addConnectivityStateListener(listener: ConnectivityStateListener) { this.stateListeners.push(listener); @@ -408,6 +439,9 @@ export class Subchannel { */ resetBackoff() { this.backoffTimeout.reset(); - this.transitionToState([ConnectivityState.TRANSIENT_FAILURE], ConnectivityState.CONNECTING); + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE], + ConnectivityState.CONNECTING + ); } -} \ No newline at end of file +} diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index 795f596fd..3b4527f50 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -273,7 +273,9 @@ describe('CallStream', () => { frameLengths: range(0, 20).map(() => 1), }, ].forEach((testCase: { description: string; frameLengths: number[] }) => { - it(`should handle a short message where ${testCase.description}`, done => { + it(`should handle a short message where ${ + testCase.description + }`, done => { const callStream = new Http2CallStream( 'foo', {} as ChannelImplementation, From ee4985886d481662ee014d247326576c00dc8041 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 29 Aug 2019 10:36:09 -0700 Subject: [PATCH 0756/1899] Pick first load balancer: don't connect forever without calls --- .../grpc-js/src/load-balancer-pick-first.ts | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index c8e220b8c..d1252507c 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -122,29 +122,21 @@ export class PickFirstLoadBalancer implements LoadBalancer { if (newState === ConnectivityState.CONNECTING) { this.subchannelConnectingCount += 1; } + /* If the subchannel we most recently attempted to start connecting + * to goes into TRANSIENT_FAILURE, immediately try to start + * connecting to the next one instead of waiting for the connection + * delay timer. */ + if ( + subchannel === this.subchannels[this.currentSubchannelIndex] && + newState === ConnectivityState.TRANSIENT_FAILURE + ) { + this.startNextSubchannelConnecting(); + } if (newState === ConnectivityState.READY) { this.pickSubchannel(subchannel); return; } else { if (this.currentPick === null) { - if ( - newState === ConnectivityState.TRANSIENT_FAILURE || - newState === ConnectivityState.IDLE - ) { - process.nextTick(() => { - subchannel.startConnecting(); - }); - } - /* If the subchannel we most recently attempted to start connecting - * to goes into TRANSIENT_FAILURE, immediately try to start - * connecting to the next one instead of waiting for the connection - * delay timer. */ - if ( - subchannel === this.subchannels[this.currentSubchannelIndex] && - newState === ConnectivityState.TRANSIENT_FAILURE - ) { - this.startNextSubchannelConnecting(); - } if (this.triedAllSubchannels) { const newLBState = this.subchannelConnectingCount > 0 @@ -318,6 +310,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { } exitIdle() { + for (const subchannel of this.subchannels) { + subchannel.startConnecting(); + } if (this.currentState === ConnectivityState.IDLE) { if (this.latestAddressList.length > 0) { this.connectToAddressList(); From 889d1d30937c9f6033a4275060ae8bd94302e3e0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 29 Aug 2019 14:11:19 -0700 Subject: [PATCH 0757/1899] Avoid http2 IPv6 handling bug --- packages/grpc-js/src/resolver-dns.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index ff91a8f26..c094407a1 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -21,6 +21,7 @@ import { registerDefaultResolver, } from './resolver'; import * as dns from 'dns'; +import * as semver from 'semver'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; import { ServiceError } from './call'; @@ -60,6 +61,14 @@ const DNS_REGEX = /^(?:dns:)?(?:\/\/\w+\/)?(\w+)(?::(\d+))?$/; */ const DEFAULT_PORT = '443'; +/** + * The range of Node versions in which the Node issue + * https://github.com/nodejs/node/issues/28216 has been fixed. In other + * versions, IPv6 literal addresses cannot be used to establish HTTP/2 + * connections. + */ +const IPV6_SUPPORT_RANGE = '>= 12.6'; + const resolve4Promise = util.promisify(dns.resolve4); const resolve6Promise = util.promisify(dns.resolve6); @@ -152,7 +161,12 @@ class DnsResolver implements Resolver { if (this.dnsHostname !== null) { const hostname: string = this.dnsHostname; const aResult = resolve4Promise(hostname); - const aaaaResult = resolve6Promise(hostname); + let aaaaResult: Promise; + if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { + aaaaResult = resolve6Promise(hostname); + } else { + aaaaResult = Promise.resolve([]); + } /* We handle the TXT query promise differently than the others because * the name resolution attempt as a whole is a success even if the TXT * lookup fails */ From a17c53050a681fe5c48687cac0ab6f02a547e52e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 29 Aug 2019 15:03:27 -0700 Subject: [PATCH 0758/1899] Bump proto-loader to 0.5.2 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index b1c713f43..d9ba9a794 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.1", + "version": "0.5.2", "author": "Google Inc.", "contributors": [ { From 4144558ee6b37a9b7aeb173c168eb0fb2abe1476 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 29 Aug 2019 17:03:00 -0700 Subject: [PATCH 0759/1899] Resolve first comments --- packages/grpc-js/src/channel.ts | 2 +- packages/grpc-js/src/index.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 1a2a1db66..507fb82f6 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -128,7 +128,7 @@ export class ChannelImplementation implements Channel { private readonly credentials: ChannelCredentials, private readonly options: ChannelOptions ) { - // TODO: check channel arg for getting a private pool + // TODO(murgatroid99): check channel arg for getting a private pool this.subchannelPool = getSubchannelPool(true); const channelControlHelper: ChannelControlHelper = { createSubchannel: ( diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 4f55fbeb5..2809f8a73 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -287,9 +287,7 @@ export { GrpcObject } from './make-client'; import * as resolver from './resolver'; import * as load_balancer from './load-balancer'; -function setup() { +(() => { resolver.registerAll(); load_balancer.registerAll(); -} - -setup(); +})(); From 026d681a849880541693ae402a5251518ee88ae5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 29 Aug 2019 17:45:06 -0700 Subject: [PATCH 0760/1899] Fix doubled name resolver errors and added detail --- packages/grpc-js/src/resolver-dns.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index c094407a1..ed35109f3 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -218,10 +218,9 @@ class DnsResolver implements Resolver { this.pendingResultPromise = null; this.listener.onError({ code: Status.UNAVAILABLE, - details: 'Name resolution failed', + details: `Name resolution failed for target ${this.target}`, metadata: new Metadata(), }); - this.listener.onError(err); } ); } From b7656e0644dc6b5f49ddeb507a866cb774146069 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 30 Aug 2019 15:35:34 -0700 Subject: [PATCH 0761/1899] Fix DNS result handling, special case localhost, resolve comment --- packages/grpc-js/src/channel.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 102 ++++++++++++++++++++++----- 2 files changed, 87 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 507fb82f6..fe2bec7c8 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -158,7 +158,7 @@ export class ChannelImplementation implements Channel { ); }, }; - // TODO: check channel arg for default service config + // TODO(murgatroid99): check channel arg for default service config const defaultServiceConfig: ServiceConfig = { loadBalancingConfig: [], methodConfig: [], diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index ed35109f3..3260fa7a4 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -69,15 +69,46 @@ const DEFAULT_PORT = '443'; */ const IPV6_SUPPORT_RANGE = '>= 12.6'; -const resolve4Promise = util.promisify(dns.resolve4); -const resolve6Promise = util.promisify(dns.resolve6); +/** + * Get a promise that always resolves with either the result of the function + * or the error if it failed. + * @param fn + */ +function resolvePromisify( + fn: ( + arg: TArg, + callback: (error: TError | null, result: TResult) => void + ) => void +): (arg: TArg) => Promise { + return arg => + new Promise((resolve, reject) => { + fn(arg, (error, result) => { + if (error) { + resolve(error); + } else { + resolve(result); + } + }); + }); +} + +const resolve4Promise = resolvePromisify< + string, + string[], + NodeJS.ErrnoException +>(dns.resolve4); +const resolve6Promise = resolvePromisify< + string, + string[], + NodeJS.ErrnoException +>(dns.resolve6); /** * Attempt to parse a target string as an IP address * @param target - * @return An "IP:port" string if parsing was successful, `null` otherwise + * @return An "IP:port" string in an array if parsing was successful, `null` otherwise */ -function parseIP(target: string): string | null { +function parseIP(target: string): string[] | null { /* These three regular expressions are all mutually exclusive, so we just * want the first one that matches the target string, if any do. */ const match = @@ -94,7 +125,7 @@ function parseIP(target: string): string | null { } else { port = DEFAULT_PORT; } - return `${addr}:${port}`; + return [`${addr}:${port}`]; } /** @@ -121,15 +152,20 @@ function mergeArrays(...arrays: T[][]): T[] { * Resolver implementation that handles DNS names and IP addresses. */ class DnsResolver implements Resolver { - private readonly ipResult: string | null; + private readonly ipResult: string[] | null; private readonly dnsHostname: string | null; private readonly port: string | null; /* The promise results here contain, in order, the A record, the AAAA record, * and either the TXT record or an error if TXT resolution failed */ - pendingResultPromise: Promise< - [string[], string[], string[][] | Error] + private pendingResultPromise: Promise< + [ + string[] | NodeJS.ErrnoException, + string[] | NodeJS.ErrnoException, + string[][] | NodeJS.ErrnoException + ] > | null = null; - percentage: number; + private percentage: number; + private defaultResolutionError: StatusObject; constructor(private target: string, private listener: ResolverListener) { this.ipResult = parseIP(target); const dnsMatch = DNS_REGEX.exec(target); @@ -143,8 +179,21 @@ class DnsResolver implements Resolver { } else { this.port = DEFAULT_PORT; } + if (this.dnsHostname === 'localhost') { + if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { + this.ipResult = [`::1:${this.port}`, `127.0.0.1:${this.port}`]; + } else { + this.ipResult = [`127.0.0.1:${this.port}`]; + } + } } this.percentage = Math.random() * 100; + + this.defaultResolutionError = { + code: Status.UNAVAILABLE, + details: `Name resolution failed for target ${this.target}`, + metadata: new Metadata(), + }; } /** @@ -154,14 +203,14 @@ class DnsResolver implements Resolver { private startResolution() { if (this.ipResult !== null) { setImmediate(() => { - this.listener.onSuccessfulResolution([this.ipResult!], null, null); + this.listener.onSuccessfulResolution(this.ipResult!, null, null); }); return; } if (this.dnsHostname !== null) { const hostname: string = this.dnsHostname; const aResult = resolve4Promise(hostname); - let aaaaResult: Promise; + let aaaaResult: Promise; if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { aaaaResult = resolve6Promise(hostname); } else { @@ -183,9 +232,34 @@ class DnsResolver implements Resolver { this.pendingResultPromise.then( ([aRecord, aaaaRecord, txtRecord]) => { this.pendingResultPromise = null; + /* dns.resolve4 and resolve6 return an error if there are no + * addresses for that family. If there are addresses for the other + * family we want to use them instead of considering that an overall + * resolution failure. The error code that indicates this situation + * is ENODATA */ + if (aRecord instanceof Error) { + if (aRecord.code === 'ENODATA') { + aRecord = []; + } else { + this.listener.onError(this.defaultResolutionError); + return; + } + } + if (aaaaRecord instanceof Error) { + if (aaaaRecord.code === 'ENODATA') { + aaaaRecord = []; + } else { + this.listener.onError(this.defaultResolutionError); + return; + } + } aRecord = aRecord.map(value => `${value}:${this.port}`); aaaaRecord = aaaaRecord.map(value => `[${value}]:${this.port}`); const allAddresses: string[] = mergeArrays(aaaaRecord, aRecord); + if (allAddresses.length === 0) { + this.listener.onError(this.defaultResolutionError); + return; + } let serviceConfig: ServiceConfig | null = null; let serviceConfigError: StatusObject | null = null; if (txtRecord instanceof Error) { @@ -216,11 +290,7 @@ class DnsResolver implements Resolver { }, err => { this.pendingResultPromise = null; - this.listener.onError({ - code: Status.UNAVAILABLE, - details: `Name resolution failed for target ${this.target}`, - metadata: new Metadata(), - }); + this.listener.onError(this.defaultResolutionError); } ); } From 3f7d640e9e4caa595548c8d98c8a889e4676cc28 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 3 Sep 2019 11:05:54 -0700 Subject: [PATCH 0762/1899] Fix hardcoded IPv6 localhost address --- packages/grpc-js/src/resolver-dns.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 3260fa7a4..3bcae87f6 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -181,7 +181,7 @@ class DnsResolver implements Resolver { } if (this.dnsHostname === 'localhost') { if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - this.ipResult = [`::1:${this.port}`, `127.0.0.1:${this.port}`]; + this.ipResult = [`[::1]:${this.port}`, `127.0.0.1:${this.port}`]; } else { this.ipResult = [`127.0.0.1:${this.port}`]; } From 646019c39488ff1b2bf998e2f17cfa5245be0a61 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 3 Sep 2019 12:14:29 -0700 Subject: [PATCH 0763/1899] Undo submodule change --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 7c0764918..35230ef8c 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 7c0764918b9f33cab507ff483b4be849b0203ec4 +Subproject commit 35230ef8cd70d62ab94bee661b7cd641adfa805b From 4b4addf5b96189561fec523a5d2a9c97943b1699 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 6 Sep 2019 11:10:47 -0700 Subject: [PATCH 0764/1899] Add specific call error for TCP disconnection --- packages/grpc-js/src/call-stream.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 2f2c35b01..b1d5fd964 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -342,6 +342,14 @@ export class Http2CallStream extends Duplex implements Call { * from bubbling up. However, errors here should all correspond to * "close" events, where we will handle the error more granularly */ }); + /* If the underlying TLS or TCP connection closes, we want to end the + * call with an UNAVAILABLE status to match the behavior of the other + * library. In this handler we don't wait for trailers before ending the + * call. This should ensure that this endCall happens sooner than the one + * in the stream.on('close', ...) handler. */ + stream.session.socket.on('close', () => { + this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); + }); if (!this.pendingRead) { stream.pause(); } From ae334976568ffc9c90e14e775662ba86f0c0e030 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 6 Sep 2019 13:21:47 -0700 Subject: [PATCH 0765/1899] Check stream.session.socket before adding event handler --- packages/grpc-js/src/call-stream.ts | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index b1d5fd964..67880212c 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -342,14 +342,20 @@ export class Http2CallStream extends Duplex implements Call { * from bubbling up. However, errors here should all correspond to * "close" events, where we will handle the error more granularly */ }); - /* If the underlying TLS or TCP connection closes, we want to end the - * call with an UNAVAILABLE status to match the behavior of the other - * library. In this handler we don't wait for trailers before ending the - * call. This should ensure that this endCall happens sooner than the one - * in the stream.on('close', ...) handler. */ - stream.session.socket.on('close', () => { - this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); - }); + /* For some reason, stream.session.socket can sometimes be undefined. + * When that happens trying to add this event handler throws an error. + * This check is a stopgap measure to get this working sometimes until + * we understand/eliminate those cases. */ + if (stream.session.socket) { + /* If the underlying TLS or TCP connection closes, we want to end the + * call with an UNAVAILABLE status to match the behavior of the other + * library. In this handler we don't wait for trailers before ending the + * call. This should ensure that this endCall happens sooner than the one + * in the stream.on('close', ...) handler. */ + stream.session.socket.on('close', () => { + this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); + }); + } if (!this.pendingRead) { stream.pause(); } From 049da7e0586dd709c78b6fe6107663d3b30a9f06 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 6 Sep 2019 14:58:42 -0700 Subject: [PATCH 0766/1899] Add session.socket to ClientHttp2StreamMock in tests --- packages/grpc-js/src/call-stream.ts | 22 ++++++++-------------- packages/grpc-js/test/test-call-stream.ts | 3 ++- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 67880212c..d04eb9b67 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -342,20 +342,14 @@ export class Http2CallStream extends Duplex implements Call { * from bubbling up. However, errors here should all correspond to * "close" events, where we will handle the error more granularly */ }); - /* For some reason, stream.session.socket can sometimes be undefined. - * When that happens trying to add this event handler throws an error. - * This check is a stopgap measure to get this working sometimes until - * we understand/eliminate those cases. */ - if (stream.session.socket) { - /* If the underlying TLS or TCP connection closes, we want to end the - * call with an UNAVAILABLE status to match the behavior of the other - * library. In this handler we don't wait for trailers before ending the - * call. This should ensure that this endCall happens sooner than the one - * in the stream.on('close', ...) handler. */ - stream.session.socket.on('close', () => { - this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); - }); - } + /* If the underlying TLS or TCP connection closes, we want to end the + * call with an UNAVAILABLE status to match the behavior of the other + * library. In this handler we don't wait for trailers before ending the + * call. This should ensure that this endCall happens sooner than the one + * in the stream.on('close', ...) handler. */ + stream.session.socket.on('close', () => { + this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); + }); if (!this.pendingRead) { stream.pause(); } diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index a85366c78..e2fa43f3a 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -30,6 +30,7 @@ import { FilterStackFactory } from '../src/filter-stack'; import { Metadata } from '../src/metadata'; import { assert2, mockFunction } from './common'; +import { EventEmitter } from 'events'; interface DataFrames { payload: Buffer; @@ -69,7 +70,7 @@ class ClientHttp2StreamMock extends stream.Duplex readonly sentInfoHeaders?: OutgoingHttpHeaders[] = []; readonly sentTrailers?: OutgoingHttpHeaders = undefined; // tslint:disable:no-any - session: http2.Http2Session = {} as any; + session: http2.Http2Session = {socket: new EventEmitter()} as any; state: http2.StreamState = {} as any; // tslint:enable:no-any close = mockFunction; From c8fe8f0c9c3c44c91b2f861ed052f1b96da5533c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 9 Sep 2019 15:28:16 -0700 Subject: [PATCH 0767/1899] Add logging for (de)serialization errors --- packages/grpc-native-core/src/client_interceptors.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 2fe373f3b..2cf48481d 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -688,6 +688,7 @@ function _getStreamReadCallback(emitter, call, get_listener, deserialize) { try { deserialized = deserialize(data); } catch (e) { + common.log(constants.logVerbosity.ERROR, `Response deserialization failed: ${e.message}`); emitter._readsDone({ code: constants.status.INTERNAL, details: 'Failed to parse server response' @@ -829,6 +830,7 @@ function _getUnaryInterceptor(method_definition, channel, emitter, callback) { try { deserialized = deserialize(response.read); } catch (e) { + common.log(constants.logVerbosity.ERROR, `Response deserialization failed: ${e.message}`); /* Change status to indicate bad server response. This * will result in passing an error to the callback */ status = { @@ -909,6 +911,7 @@ function _getClientStreamingInterceptor(method_definition, channel, emitter, try { deserialized = deserialize(response.read); } catch (e) { + common.log(constants.logVerbosity.ERROR, `Response deserialization failed: ${e.message}`); /* Change status to indicate bad server response. This will result * in passing an error to the callback */ status = { @@ -933,6 +936,7 @@ function _getClientStreamingInterceptor(method_definition, channel, emitter, try { message = serialize(chunk); } catch (e) { + common.log(constants.logVerbosity.ERROR, `Request serialization failed: ${e.message}`); /* Sending this error to the server and emitting it immediately on the client may put the call in a slightly weird state on the client side, but passing an object that causes a serialization failure is a misuse @@ -1134,6 +1138,7 @@ function _getBidiStreamingInterceptor(method_definition, channel, emitter) { try { message = serialize(chunk); } catch (e) { + common.log(constants.logVerbosity.ERROR, `Request serialization failed: ${e.message}`); /* Sending this error to the server and emitting it immediately on the client may put the call in a slightly weird state on the client side, but passing an object that causes a serialization failure is a misuse From 8900aab94e1153542d8b81f62e158e3389adda4f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 10 Sep 2019 12:49:15 -0700 Subject: [PATCH 0768/1899] Bump grpc-js to 0.5.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 51ff1cfdb..893fd46d7 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.5.2", + "version": "0.5.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From a8f219fad5722d708b77f39778622790500fd2ef Mon Sep 17 00:00:00 2001 From: Teju Nareddy Date: Wed, 11 Sep 2019 12:15:49 -0700 Subject: [PATCH 0769/1899] Add documentation for `grpc-health-check` Signed-off-by: Teju Nareddy --- packages/grpc-health-check/README.md | 91 +++++++++++++++++++++++++ packages/grpc-health-check/package.json | 5 +- 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 packages/grpc-health-check/README.md diff --git a/packages/grpc-health-check/README.md b/packages/grpc-health-check/README.md new file mode 100644 index 000000000..6484ac0aa --- /dev/null +++ b/packages/grpc-health-check/README.md @@ -0,0 +1,91 @@ +# grpc-health-check + +Health check client and service for use with gRPC-node. + +## Background + +This package exports both a client and server that adhere to the [gRPC Health Checking Protocol](https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + +By using this package, clients and servers can rely on common proto and service definitions. This means: +- Clients can use the generated stubs to health check _any_ server that adheres to the protocol. +- Servers do not reimplement common logic for publishing health statuses. + +## Installation + +Use the package manager [npm](https://www.npmjs.com/get-npm) to install `grpc-health-check`. + +```bash +npm install grpc-health-check +``` + +## Usage + +### Server + +Any gRPC-node server can use `grpc-health-check` to adhere to the gRPC Health Checking Protocol. +The following shows how this package can be added to a pre-existing gRPC server. + +```javascript 1.8 +// Import package +let health = require('grpc-health-check'); + +// Define service status map. Key is the service name, value is the corresponding status. +// By convention, the empty string "" key represents that status of the entire server. +const statusMap = { + "ServiceFoo": proto.grpc.health.v1.HealthCheckResponse.ServingStatus.SERVING, + "ServiceBar": proto.grpc.health.v1.HealthCheckResponse.ServingStatus.NOT_SERVING, + "": proto.grpc.health.v1.HealthCheckResponse.ServingStatus.NOT_SERVING, +}; + +// Construct the service implementation +let healthImpl = new health.Implementation(statusMap); + +// Add the service and implementation to your pre-existing gRPC-node server +server.addService(health.service, healthImpl); +``` + +Congrats! Your server now allows any client to run a health check against it. + +### Client + +Any gRPC-node client can use `grpc-health-check` to run health checks against other servers that follow the protocol. +The following shows how this package can be used by a pre-existing gRPC client. + +```javascript 1.8 +// Import package +let grpc = require('grpc'); +let health = require('grpc-health-check'); + +// Create the client +let healthClient = new health.Client('localhost:8082', grpc.credentials.createInsecure()); + +// Define the request, which contains the service to health check +// By convention, the empty string "" key represents that status of the entire server. +let request = { + service: "", +}; + +// Define the callback +function callback (error, status) { + if (error) { + console.error(error); + return; + } + + console.log(status); +} + +// Make the request +healthClient.check(request, callback); +``` + +This should print out "NOT_SERVING" if used with the server above. + +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. + +## License +[Apache License 2.0](https://choosealicense.com/licenses/apache-2.0/) diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index e10de7c10..388eb7d81 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -1,8 +1,8 @@ { "name": "grpc-health-check", - "version": "1.7.0", + "version": "1.7.1", "author": "Google Inc.", - "description": "Health check service for use with gRPC", + "description": "Health check client and service for use with gRPC-node", "repository": { "type": "git", "url": "https://github.com/grpc/grpc-node.git" @@ -22,6 +22,7 @@ }, "files": [ "LICENSE", + "README.md", "health.js", "v1" ], From 0e37241a512a88864b9c90e717c8c78f861815e3 Mon Sep 17 00:00:00 2001 From: Teju Nareddy Date: Wed, 11 Sep 2019 13:21:05 -0700 Subject: [PATCH 0770/1899] Omit client code due to bug in package. Will re-add once package is updated. Signed-off-by: Teju Nareddy --- packages/grpc-health-check/README.md | 31 ---------------------------- 1 file changed, 31 deletions(-) diff --git a/packages/grpc-health-check/README.md b/packages/grpc-health-check/README.md index 6484ac0aa..62a88347f 100644 --- a/packages/grpc-health-check/README.md +++ b/packages/grpc-health-check/README.md @@ -49,37 +49,6 @@ Congrats! Your server now allows any client to run a health check against it. ### Client Any gRPC-node client can use `grpc-health-check` to run health checks against other servers that follow the protocol. -The following shows how this package can be used by a pre-existing gRPC client. - -```javascript 1.8 -// Import package -let grpc = require('grpc'); -let health = require('grpc-health-check'); - -// Create the client -let healthClient = new health.Client('localhost:8082', grpc.credentials.createInsecure()); - -// Define the request, which contains the service to health check -// By convention, the empty string "" key represents that status of the entire server. -let request = { - service: "", -}; - -// Define the callback -function callback (error, status) { - if (error) { - console.error(error); - return; - } - - console.log(status); -} - -// Make the request -healthClient.check(request, callback); -``` - -This should print out "NOT_SERVING" if used with the server above. ## Contributing From 9114f34ea3cd8315f3531a9b452a4c02761d4399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?GP=20=E2=9C=85?= Date: Thu, 12 Sep 2019 09:37:00 +0530 Subject: [PATCH 0771/1899] Fix #502 - Make all properties of CallOptions optional --- packages/grpc-native-core/index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index c7dab49dd..924d07303 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -1198,11 +1198,11 @@ declare module "grpc" { * Indicates which properties of a parent call should propagate to this * call. Bitwise combination of flags in `grpc.propagate`. */ - propagate_flags: number; + propagate_flags?: number; /** * The credentials that should be used to make this particular call. */ - credentials: CallCredentials; + credentials?: CallCredentials; /** * Additional custom call options. These can be used to pass additional * data per-call to client interceptors From fc032c0226b4e6375c448c06b3394623e08d7086 Mon Sep 17 00:00:00 2001 From: Bjorn Stromberg Date: Fri, 13 Sep 2019 12:31:33 +0900 Subject: [PATCH 0772/1899] grpc-js: Update gts and apply fixes --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 14 +++++++++----- packages/grpc-js/src/index.ts | 15 ++++++++++++--- packages/grpc-js/src/server-call.ts | 23 ++++++++++++++--------- packages/grpc-js/src/server.ts | 5 ++++- packages/grpc-js/test/test-call-stream.ts | 2 +- 6 files changed, 41 insertions(+), 20 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 893fd46d7..a9c5c2535 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -26,7 +26,7 @@ "@types/semver": "^6.0.1", "clang-format": "^1.0.55", "execa": "^2.0.3", - "gts": "^1.0.0", + "gts": "^1.1.0", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index d04eb9b67..74442e7a6 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -343,12 +343,16 @@ export class Http2CallStream extends Duplex implements Call { * "close" events, where we will handle the error more granularly */ }); /* If the underlying TLS or TCP connection closes, we want to end the - * call with an UNAVAILABLE status to match the behavior of the other - * library. In this handler we don't wait for trailers before ending the - * call. This should ensure that this endCall happens sooner than the one - * in the stream.on('close', ...) handler. */ + * call with an UNAVAILABLE status to match the behavior of the other + * library. In this handler we don't wait for trailers before ending the + * call. This should ensure that this endCall happens sooner than the one + * in the stream.on('close', ...) handler. */ stream.session.socket.on('close', () => { - this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); + this.endCall({ + code: Status.UNAVAILABLE, + details: 'Connection dropped', + metadata: new Metadata(), + }); }); if (!this.pendingRead) { stream.pause(); diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 8c5851bfc..b7ce2e0d5 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -38,10 +38,19 @@ import { Serialize, } from './make-client'; import { Metadata } from './metadata'; -import { Server, UntypedHandleCall, UntypedServiceImplementation } from './server'; +import { + Server, + UntypedHandleCall, + UntypedServiceImplementation, +} from './server'; import { KeyCertPair, ServerCredentials } from './server-credentials'; import { StatusBuilder } from './status-builder'; -import { ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream } from './server-call'; +import { + ServerUnaryCall, + ServerReadableStream, + ServerWritableStream, + ServerDuplexStream, +} from './server-call'; const supportedNodeVersions = require('../../package.json').engines.node; if (!semver.satisfies(process.version, supportedNodeVersions)) { @@ -219,7 +228,7 @@ export { ServerWritableStream, ServerDuplexStream, UntypedHandleCall, - UntypedServiceImplementation + UntypedServiceImplementation, }; /* tslint:disable:no-any */ diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index c9a6b3f75..02353bbe6 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -76,9 +76,11 @@ export type ServerReadableStream< export type ServerWritableStream< RequestType, ResponseType -> = ServerSurfaceCall & ObjectWritable & { request: RequestType | null }; +> = ServerSurfaceCall & + ObjectWritable & { request: RequestType | null }; export type ServerDuplexStream = ServerSurfaceCall & - ObjectReadable & ObjectWritable; + ObjectReadable & + ObjectWritable; export class ServerUnaryCallImpl extends EventEmitter implements ServerUnaryCall { @@ -497,15 +499,18 @@ export class Http2ServerCallStream< sendError(error: ServerErrorResponse | ServerStatusResponse) { const status: StatusObject = { code: Status.UNKNOWN, - details: ('message' in error) - ? error.message - : 'Unknown Error', - metadata: ('metadata' in error && error.metadata !== undefined) - ? error.metadata - : new Metadata(), + details: 'message' in error ? error.message : 'Unknown Error', + metadata: + 'metadata' in error && error.metadata !== undefined + ? error.metadata + : new Metadata(), }; - if ('code' in error && typeof error.code === 'number' && Number.isInteger(error.code)) { + if ( + 'code' in error && + typeof error.code === 'number' && + Number.isInteger(error.code) + ) { status.code = error.code; if ('details' in error && typeof error.details === 'string') { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index a568f9c1d..780b8f865 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -102,7 +102,10 @@ export class Server { throw new Error('Not implemented. Use addService() instead'); } - addService(service: ServiceDefinition, implementation: UntypedServiceImplementation): void { + addService( + service: ServiceDefinition, + implementation: UntypedServiceImplementation + ): void { if (this.started === true) { throw new Error("Can't add a service to a started server."); } diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts index e2fa43f3a..cd51674da 100644 --- a/packages/grpc-js/test/test-call-stream.ts +++ b/packages/grpc-js/test/test-call-stream.ts @@ -70,7 +70,7 @@ class ClientHttp2StreamMock extends stream.Duplex readonly sentInfoHeaders?: OutgoingHttpHeaders[] = []; readonly sentTrailers?: OutgoingHttpHeaders = undefined; // tslint:disable:no-any - session: http2.Http2Session = {socket: new EventEmitter()} as any; + session: http2.Http2Session = { socket: new EventEmitter() } as any; state: http2.StreamState = {} as any; // tslint:enable:no-any close = mockFunction; From 50f69945105e4b635338336ad6a7d8bd172bec33 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Fri, 13 Sep 2019 19:49:42 +0200 Subject: [PATCH 0773/1899] Update master to 1.24. --- packages/grpc-native-core/binding.gyp | 90 +++++++++++++++++--------- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 60 insertions(+), 34 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 6dae2c5b8..b32d9836e 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -60,13 +60,9 @@ '-g', '-Wall', '-Wextra', - '-Werror', - '-Wno-long-long', - '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Wno-deprecated-declarations', - '-Ithird_party/nanopb', - '-DPB_FIELD_32BIT', + '-Ithird_party/upb', + '-Isrc/core/ext/upb-generated', '-fvisibility=hidden', ], 'ldflags': [ @@ -97,7 +93,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.22.0-pre1"', + 'GRPC_NODE_VERSION="1.24.0-pre1"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], @@ -193,26 +189,18 @@ '-g', '-Wall', '-Wextra', - '-Werror', - '-Wno-long-long', - '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Wno-deprecated-declarations', - '-Ithird_party/nanopb', - '-DPB_FIELD_32BIT', + '-Ithird_party/upb', + '-Isrc/core/ext/upb-generated', '-fvisibility=hidden', ], 'OTHER_CPLUSPLUSFLAGS': [ '-g', '-Wall', '-Wextra', - '-Werror', - '-Wno-long-long', - '-Wno-unused-parameter', '-DOSATOMIC_USE_INLINED=1', - '-Wno-deprecated-declarations', - '-Ithird_party/nanopb', - '-DPB_FIELD_32BIT', + '-Ithird_party/upb', + '-Isrc/core/ext/upb-generated', '-fvisibility=hidden', '-stdlib=libc++', '-std=c++1y', @@ -691,7 +679,6 @@ 'deps/grpc/src/core/lib/gpr/env_linux.cc', 'deps/grpc/src/core/lib/gpr/env_posix.cc', 'deps/grpc/src/core/lib/gpr/env_windows.cc', - 'deps/grpc/src/core/lib/gpr/host_port.cc', 'deps/grpc/src/core/lib/gpr/log.cc', 'deps/grpc/src/core/lib/gpr/log_android.cc', 'deps/grpc/src/core/lib/gpr/log_linux.cc', @@ -718,6 +705,7 @@ 'deps/grpc/src/core/lib/gprpp/arena.cc', 'deps/grpc/src/core/lib/gprpp/fork.cc', 'deps/grpc/src/core/lib/gprpp/global_config_env.cc', + 'deps/grpc/src/core/lib/gprpp/host_port.cc', 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', 'deps/grpc/src/core/lib/profiling/basic_timers.cc', @@ -782,6 +770,8 @@ 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', 'deps/grpc/src/core/lib/iomgr/exec_ctx.cc', 'deps/grpc/src/core/lib/iomgr/executor.cc', + 'deps/grpc/src/core/lib/iomgr/executor/mpmcqueue.cc', + 'deps/grpc/src/core/lib/iomgr/executor/threadpool.cc', 'deps/grpc/src/core/lib/iomgr/fork_posix.cc', 'deps/grpc/src/core/lib/iomgr/fork_windows.cc', 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', @@ -952,6 +942,7 @@ 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc', 'deps/grpc/src/core/lib/security/security_connector/ssl_utils.cc', + 'deps/grpc/src/core/lib/security/security_connector/ssl_utils_config.cc', 'deps/grpc/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc', 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', @@ -985,21 +976,23 @@ 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_service_api.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_service_api_util.cc', 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_utils.cc', 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/altscontext.pb.c', - 'deps/grpc/src/core/tsi/alts/handshaker/handshaker.pb.c', - 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common.pb.c', - 'deps/grpc/third_party/nanopb/pb_common.c', - 'deps/grpc/third_party/nanopb/pb_decode.c', - 'deps/grpc/third_party/nanopb/pb_encode.c', + 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c', + 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c', + 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c', + 'deps/grpc/third_party/upb/upb/decode.c', + 'deps/grpc/third_party/upb/upb/encode.c', + 'deps/grpc/third_party/upb/upb/msg.c', + 'deps/grpc/third_party/upb/upb/port.c', + 'deps/grpc/third_party/upb/upb/table.c', + 'deps/grpc/third_party/upb/upb/upb.c', 'deps/grpc/src/core/tsi/transport_security.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/authority.cc', 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', + 'deps/grpc/src/core/ext/filters/client_channel/backend_metric.cc', 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', @@ -1027,7 +1020,20 @@ 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', 'deps/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc', 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', - 'deps/grpc/src/core/ext/filters/client_channel/health/health.pb.c', + 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c', + 'deps/grpc/src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c', + 'deps/grpc/src/core/ext/upb-generated/gogoproto/gogo.upb.c', + 'deps/grpc/src/core/ext/upb-generated/validate/validate.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/api/annotations.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/api/http.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/any.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/duration.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/empty.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/struct.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c', + 'deps/grpc/src/core/ext/upb-generated/google/rpc/status.upb.c', 'deps/grpc/src/core/tsi/fake_transport_security.cc', 'deps/grpc/src/core/tsi/local_transport_security.cc', 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', @@ -1046,14 +1052,32 @@ 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', + 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c', 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/duration.pb.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/google/protobuf/timestamp.pb.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/proto/grpc/lb/v1/load_balancer.pb.c', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cds.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cluster/filter.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/discovery.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/eds.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/endpoint/load_report.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/service/load_stats/v2/lrs.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/address.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/base.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/config_source.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/grpc_service.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/health_check.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/http_uri.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/protocol.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/type/percent.upb.c', + 'deps/grpc/src/core/ext/upb-generated/envoy/type/range.upb.c', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', @@ -1069,7 +1093,9 @@ 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', + 'deps/grpc/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', + 'deps/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc', 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 35230ef8c..f703e1c86 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 35230ef8cd70d62ab94bee661b7cd641adfa805b +Subproject commit f703e1c86c1504d9e48953f8da31f842679b7775 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 4605eb2a5..e9e756bd2 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.22.0-pre1", + "version": "1.24.0-pre1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From a7a9f0de7694de7927f915a5912e92ff5ac93f91 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 16 Sep 2019 15:12:07 -0700 Subject: [PATCH 0774/1899] Switch to dns.lookup --- packages/grpc-js/src/resolver-dns.ts | 88 +++++++++------------------- 1 file changed, 27 insertions(+), 61 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 3bcae87f6..4c3de0213 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -92,16 +92,12 @@ function resolvePromisify( }); } -const resolve4Promise = resolvePromisify< +const resolveTxtPromise = resolvePromisify< string, - string[], + string[][], NodeJS.ErrnoException ->(dns.resolve4); -const resolve6Promise = resolvePromisify< - string, - string[], - NodeJS.ErrnoException ->(dns.resolve6); +>(dns.resolveTxt); +const dnsLookupPromise = util.promisify(dns.lookup); /** * Attempt to parse a target string as an IP address @@ -158,11 +154,7 @@ class DnsResolver implements Resolver { /* The promise results here contain, in order, the A record, the AAAA record, * and either the TXT record or an error if TXT resolution failed */ private pendingResultPromise: Promise< - [ - string[] | NodeJS.ErrnoException, - string[] | NodeJS.ErrnoException, - string[][] | NodeJS.ErrnoException - ] + [{ address: dns.LookupAddress[] }, string[][] | NodeJS.ErrnoException] > | null = null; private percentage: number; private defaultResolutionError: StatusObject; @@ -179,13 +171,6 @@ class DnsResolver implements Resolver { } else { this.port = DEFAULT_PORT; } - if (this.dnsHostname === 'localhost') { - if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - this.ipResult = [`[::1]:${this.port}`, `127.0.0.1:${this.port}`]; - } else { - this.ipResult = [`127.0.0.1:${this.port}`]; - } - } } this.percentage = Math.random() * 100; @@ -209,53 +194,34 @@ class DnsResolver implements Resolver { } if (this.dnsHostname !== null) { const hostname: string = this.dnsHostname; - const aResult = resolve4Promise(hostname); - let aaaaResult: Promise; - if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - aaaaResult = resolve6Promise(hostname); - } else { - aaaaResult = Promise.resolve([]); - } + /* We lookup both address families here and then split them up later + * because when looking up a single family, dns.lookup outputs an error + * if the name exists but there are no records for that family, and that + * error is indistinguishable from other kinds of errors */ + const addressResult = dnsLookupPromise(hostname, { all: true }); /* We handle the TXT query promise differently than the others because * the name resolution attempt as a whole is a success even if the TXT * lookup fails */ - const txtResult = new Promise((resolve, reject) => { - dns.resolveTxt(hostname, (err, records) => { - if (err) { - resolve(err); - } else { - resolve(records); - } - }); - }); - this.pendingResultPromise = Promise.all([aResult, aaaaResult, txtResult]); + const txtResult = resolveTxtPromise(hostname); + this.pendingResultPromise = Promise.all([addressResult, txtResult]); this.pendingResultPromise.then( - ([aRecord, aaaaRecord, txtRecord]) => { + ([addressList, txtRecord]) => { this.pendingResultPromise = null; - /* dns.resolve4 and resolve6 return an error if there are no - * addresses for that family. If there are addresses for the other - * family we want to use them instead of considering that an overall - * resolution failure. The error code that indicates this situation - * is ENODATA */ - if (aRecord instanceof Error) { - if (aRecord.code === 'ENODATA') { - aRecord = []; - } else { - this.listener.onError(this.defaultResolutionError); - return; - } - } - if (aaaaRecord instanceof Error) { - if (aaaaRecord.code === 'ENODATA') { - aaaaRecord = []; - } else { - this.listener.onError(this.defaultResolutionError); - return; - } + const ip4Addresses: string[] = addressList.address + .filter(addr => addr.family === 4) + .map(addr => `${addr.address}:${this.port}`); + let ip6Addresses: string[]; + if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { + ip6Addresses = addressList.address + .filter(addr => addr.family === 6) + .map(addr => `[${addr.address}]:${this.port}`); + } else { + ip6Addresses = []; } - aRecord = aRecord.map(value => `${value}:${this.port}`); - aaaaRecord = aaaaRecord.map(value => `[${value}]:${this.port}`); - const allAddresses: string[] = mergeArrays(aaaaRecord, aRecord); + const allAddresses: string[] = mergeArrays( + ip4Addresses, + ip6Addresses + ); if (allAddresses.length === 0) { this.listener.onError(this.defaultResolutionError); return; From d762dc44384ffd756c307180c09ce9b68052f347 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 16 Sep 2019 15:37:54 -0700 Subject: [PATCH 0775/1899] Use updated type definitions --- packages/grpc-js/src/resolver-dns.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 4c3de0213..94d5c6016 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -154,7 +154,7 @@ class DnsResolver implements Resolver { /* The promise results here contain, in order, the A record, the AAAA record, * and either the TXT record or an error if TXT resolution failed */ private pendingResultPromise: Promise< - [{ address: dns.LookupAddress[] }, string[][] | NodeJS.ErrnoException] + [dns.LookupAddress[], string[][] | NodeJS.ErrnoException] > | null = null; private percentage: number; private defaultResolutionError: StatusObject; @@ -207,12 +207,12 @@ class DnsResolver implements Resolver { this.pendingResultPromise.then( ([addressList, txtRecord]) => { this.pendingResultPromise = null; - const ip4Addresses: string[] = addressList.address + const ip4Addresses: string[] = addressList .filter(addr => addr.family === 4) .map(addr => `${addr.address}:${this.port}`); let ip6Addresses: string[]; if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - ip6Addresses = addressList.address + ip6Addresses = addressList .filter(addr => addr.family === 6) .map(addr => `[${addr.address}]:${this.port}`); } else { From b847e405e80990bf1b73fe30a9f6a9594671ff35 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Tue, 17 Sep 2019 23:07:39 +0200 Subject: [PATCH 0776/1899] Also tweaking local template. --- packages/grpc-native-core/binding.gyp | 2 -- packages/grpc-native-core/templates/binding.gyp.template | 2 -- 2 files changed, 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index b32d9836e..8dda84224 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -69,11 +69,9 @@ '-g', ], 'cflags_c': [ - '-Werror', '-std=c99' ], 'cflags_cc': [ - '-Werror', '-std=c++1y' ], 'include_dirs': [ diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index cdf1a1a0c..1d9f07fc8 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -65,11 +65,9 @@ % endif % endfor 'cflags_c': [ - '-Werror', '-std=c99' ], 'cflags_cc': [ - '-Werror', '-std=c++1y' ], 'include_dirs': [ From 8780f49c0a96dfc5f0b464c55b77038f37c25d0c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 18 Sep 2019 13:47:25 -0700 Subject: [PATCH 0777/1899] Update @types/node to version with modified dns types --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3ff6ec73c..710476b80 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -18,7 +18,7 @@ "@grpc/proto-loader": "^0.5.0", "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", - "@types/node": "^12.0.2", + "@types/node": "^12.7.5", "clang-format": "^1.0.55", "gts": "^1.0.0", "lodash": "^4.17.4", From 9e2aea039956a050882501260b8239c94ad43702 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 19 Sep 2019 14:42:40 -0700 Subject: [PATCH 0778/1899] Revert "Add specific call error for TCP disconnection" --- packages/grpc-js/src/call-stream.ts | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 74442e7a6..2f2c35b01 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -342,18 +342,6 @@ export class Http2CallStream extends Duplex implements Call { * from bubbling up. However, errors here should all correspond to * "close" events, where we will handle the error more granularly */ }); - /* If the underlying TLS or TCP connection closes, we want to end the - * call with an UNAVAILABLE status to match the behavior of the other - * library. In this handler we don't wait for trailers before ending the - * call. This should ensure that this endCall happens sooner than the one - * in the stream.on('close', ...) handler. */ - stream.session.socket.on('close', () => { - this.endCall({ - code: Status.UNAVAILABLE, - details: 'Connection dropped', - metadata: new Metadata(), - }); - }); if (!this.pendingRead) { stream.pause(); } From b003aa14d4a13e1fc1e446ced124649706d9138e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 19 Sep 2019 17:14:38 -0700 Subject: [PATCH 0779/1899] Add function for creating errors from statuses --- packages/grpc-js/src/call.ts | 19 ++++++++++++++----- packages/grpc-js/src/client.ts | 7 ++----- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 2f45b82fd..e6127faac 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -68,6 +68,19 @@ export type ClientDuplexStream< ResponseType > = ClientWritableStream & ClientReadableStream; +/** + * Construct a ServiceError from a StatusObject. This function exists primarily + * as an attempt to make the error stack trace clearly communicate that the + * error is not necessarily a problem in gRPC itself. + * @param status + */ +export function callErrorFromStatus(status: StatusObject): ServiceError { + return Object.assign( + new Error(status.details), + status + ); +} + export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { constructor(private readonly call: Call) { @@ -118,11 +131,7 @@ function setUpReadableStream( }); call.on('status', (status: StatusObject) => { if (status.code !== Status.OK) { - const error: ServiceError = Object.assign( - new Error(status.details), - status - ); - stream.emit('error', error); + stream.emit('error', callErrorFromStatus(status)); } stream.emit('status', status); statusEmitted = true; diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index a092e61d4..fc145942a 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -25,6 +25,7 @@ import { ClientWritableStream, ClientWritableStreamImpl, ServiceError, + callErrorFromStatus, } from './call'; import { CallCredentials } from './call-credentials'; import { Call, Deadline, StatusObject, WriteObject } from './call-stream'; @@ -147,11 +148,7 @@ export class Client { if (status.code === Status.OK) { callback(null, responseMessage as ResponseType); } else { - const error: ServiceError = Object.assign( - new Error(status.details), - status - ); - callback(error); + callback(callErrorFromStatus(status)); } }); } From 96db88a3fb504a8ad9666d4a8a05ab33ac2f6db3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 20 Sep 2019 10:44:13 -0700 Subject: [PATCH 0780/1899] Bump grpc-js to 0.5.4 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a9c5c2535..193a4d769 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.5.3", + "version": "0.5.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 96e3dde23da0f785f77f1b50503665c603d1f59b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 24 Sep 2019 10:25:08 -0700 Subject: [PATCH 0781/1899] Return UNAVAILABLE status on TCP disconnect --- packages/grpc-js/src/call-stream.ts | 16 +++++++++++++- packages/grpc-js/src/subchannel.ts | 33 +++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 714586002..d7176c54e 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -27,6 +27,7 @@ import { Metadata } from './metadata'; import { ObjectDuplex, WriteCallback } from './object-stream'; import { StreamDecoder } from './stream-decoder'; import { ChannelImplementation } from './channel'; +import { Subchannel } from './subchannel'; const { HTTP2_HEADER_STATUS, @@ -112,6 +113,9 @@ export class Http2CallStream extends Duplex implements Call { // This is populated (non-null) if and only if the call has ended private finalStatus: StatusObject | null = null; + private subchannel: Subchannel | null = null; + private disconnectListener: () => void; + constructor( private readonly methodName: string, private readonly channel: ChannelImplementation, @@ -122,6 +126,9 @@ export class Http2CallStream extends Duplex implements Call { super({ objectMode: true }); this.filterStack = filterStackFactory.createFilter(this); this.credentials = channelCallCredentials; + this.disconnectListener = () => { + this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); + }; } /** @@ -142,6 +149,10 @@ export class Http2CallStream extends Duplex implements Call { process.nextTick(() => { this.emit('status', status); }); + if (this.subchannel) { + this.subchannel.callUnref(); + this.subchannel.removeDisconnectListener(this.disconnectListener); + } } } @@ -239,11 +250,14 @@ export class Http2CallStream extends Duplex implements Call { })(); } - attachHttp2Stream(stream: http2.ClientHttp2Stream): void { + attachHttp2Stream(stream: http2.ClientHttp2Stream, subchannel: Subchannel): void { if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { this.http2Stream = stream; + this.subchannel = subchannel; + subchannel.addDisconnectListener(this.disconnectListener); + subchannel.callRef(); stream.on('response', (headers, flags) => { switch (headers[HTTP2_HEADER_STATUS]) { // TODO(murgatroid99): handle 100 and 101 diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 2683643b3..65571586d 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -84,6 +84,13 @@ export class Subchannel { */ private stateListeners: ConnectivityStateListener[] = []; + /** + * A list of listener functions that will be called when the underlying + * socket disconnects. Used for ending active calls with an UNAVAILABLE + * status. + */ + private disconnectListeners: (() => void)[] = []; + private backoffTimeout: BackoffTimeout; /** @@ -274,6 +281,11 @@ export class Subchannel { switch (newState) { case ConnectivityState.READY: this.stopBackoff(); + this.session!.socket.once('close', () => { + for (const listener of this.disconnectListeners) { + listener(); + } + }); break; case ConnectivityState.CONNECTING: this.startBackoff(); @@ -322,7 +334,7 @@ export class Subchannel { } } - private callRef() { + callRef() { if (this.callRefcount === 0) { if (this.session) { this.session.ref(); @@ -332,7 +344,7 @@ export class Subchannel { this.callRefcount += 1; } - private callUnref() { + callUnref() { this.callRefcount -= 1; if (this.callRefcount === 0) { if (this.session) { @@ -376,11 +388,7 @@ export class Subchannel { headers[HTTP2_HEADER_PATH] = callStream.getMethod(); headers[HTTP2_HEADER_TE] = 'trailers'; const http2Stream = this.session!.request(headers); - this.callRef(); - http2Stream.on('close', () => { - this.callUnref(); - }); - callStream.attachHttp2Stream(http2Stream); + callStream.attachHttp2Stream(http2Stream, this); } /** @@ -434,6 +442,17 @@ export class Subchannel { } } + addDisconnectListener(listener: () => void) { + this.disconnectListeners.push(listener); + } + + removeDisconnectListener(listener: () => void) { + const listenerIndex = this.disconnectListeners.indexOf(listener); + if (listenerIndex > -1) { + this.disconnectListeners.splice(listenerIndex, 1); + } + } + /** * Reset the backoff timeout, and immediately start connecting if in backoff. */ From 184870f42a32cd5fb353a345d69b47f6596c4be8 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 24 Sep 2019 10:50:33 -0700 Subject: [PATCH 0782/1899] Bump grpc-js to 0.6.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4dd964ef4..ccb60b9c3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.5.4", + "version": "0.6.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From fba9664f35eb66e48ac9686db4241052d5a04589 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 24 Sep 2019 12:09:57 -0700 Subject: [PATCH 0783/1899] Remove fragile test file --- packages/grpc-js/test/test-call-stream.ts | 441 ---------------------- 1 file changed, 441 deletions(-) delete mode 100644 packages/grpc-js/test/test-call-stream.ts diff --git a/packages/grpc-js/test/test-call-stream.ts b/packages/grpc-js/test/test-call-stream.ts deleted file mode 100644 index 3b4527f50..000000000 --- a/packages/grpc-js/test/test-call-stream.ts +++ /dev/null @@ -1,441 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import * as assert from 'assert'; -import { OutgoingHttpHeaders } from 'http'; -import * as http2 from 'http2'; -import { range } from 'lodash'; -import * as stream from 'stream'; - -import { CallCredentials } from '../src/call-credentials'; -import { Http2CallStream } from '../src/call-stream'; -import { Channel, ChannelImplementation } from '../src/channel'; -import { CompressionFilterFactory } from '../src/compression-filter'; -import { Status } from '../src/constants'; -import { FilterStackFactory } from '../src/filter-stack'; -import { Metadata } from '../src/metadata'; - -import { assert2, mockFunction } from './common'; - -interface DataFrames { - payload: Buffer; - frameLengths: number[]; -} - -const { HTTP2_HEADER_STATUS } = http2.constants; - -function serialize(data: string): Buffer { - const header: Buffer = Buffer.alloc(5); - header.writeUInt8(0, 0); // TODO: Uncompressed only - header.writeInt32BE(data.length, 1); - return Buffer.concat([header, Buffer.from(data, 'utf8')]); -} - -class ClientHttp2StreamMock extends stream.Duplex - implements http2.ClientHttp2Stream { - constructor(private readonly dataFrames: DataFrames) { - super(); - } - emitResponse(responseCode: number, metadata?: Metadata) { - this.emit('response', { - [HTTP2_HEADER_STATUS]: responseCode, - ...(metadata ? metadata.toHttp2Headers() : {}), - }); - } - bytesRead = 0; - dataFrame = 0; - aborted = false; - closed = false; - destroyed = false; - endAfterHeaders = false; - pending = false; - rstCode = 0; - readonly bufferSize: number = 0; - readonly sentHeaders: OutgoingHttpHeaders = {}; - readonly sentInfoHeaders?: OutgoingHttpHeaders[] = []; - readonly sentTrailers?: OutgoingHttpHeaders = undefined; - // tslint:disable:no-any - session: http2.Http2Session = {} as any; - state: http2.StreamState = {} as any; - // tslint:enable:no-any - close = mockFunction; - priority = mockFunction; - rstStream = mockFunction; - rstWithNoError = mockFunction; - rstWithProtocolError = mockFunction; - rstWithCancel = mockFunction; - rstWithRefuse = mockFunction; - rstWithInternalError = mockFunction; - setTimeout = mockFunction; - _read() { - if (this.dataFrame === this.dataFrames.frameLengths.length) { - if (this.bytesRead < this.dataFrames.payload.length) { - this.push( - this.dataFrames.payload.slice( - this.bytesRead, - this.dataFrames.payload.length - ) - ); - } - this.push(null); - return; - } - const from = this.bytesRead; - this.bytesRead += this.dataFrames.frameLengths[this.dataFrame++]; - this.push(this.dataFrames.payload.slice(from, this.bytesRead)); - } - _write(chunk: Buffer, encoding: string, cb: Function) { - this.emit('write', chunk); - cb(); - } - sendTrailers(headers: OutgoingHttpHeaders) { - return this; - } -} - -describe('CallStream', () => { - const callStreamArgs = { - deadline: Infinity, - flags: 0, - host: '', - parentCall: null, - }; - /* A CompressionFilter is now necessary to frame and deframe messages. - * Currently the channel is unused, so we can replace it with an empty object, - * but this might break if we start checking channel arguments, in which case - * we will need a more sophisticated fake */ - const filterStackFactory = new FilterStackFactory([ - new CompressionFilterFactory({} as Channel), - ]); - const message = 'eat this message'; // 16 bytes - - beforeEach(() => { - assert2.clearMustCalls(); - }); - - it('should emit a metadata event when it receives a response event', done => { - const responseMetadata = new Metadata(); - responseMetadata.add('key', 'value'); - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [], - }); - callStream.once( - 'metadata', - assert2.mustCall(metadata => { - assert.deepStrictEqual(metadata.get('key'), ['value']); - }) - ); - callStream.attachHttp2Stream(http2Stream); - http2Stream.emitResponse(200, responseMetadata); - assert2.afterMustCallsSatisfied(done); - }); - - describe('should end a call with an error if a stream was closed', () => { - const c = http2.constants; - const s = Status; - const errorCodeMapping = { - [c.NGHTTP2_NO_ERROR]: s.INTERNAL, - [c.NGHTTP2_PROTOCOL_ERROR]: s.INTERNAL, - [c.NGHTTP2_INTERNAL_ERROR]: s.INTERNAL, - [c.NGHTTP2_FLOW_CONTROL_ERROR]: s.INTERNAL, - [c.NGHTTP2_SETTINGS_TIMEOUT]: s.INTERNAL, - [c.NGHTTP2_STREAM_CLOSED]: null, - [c.NGHTTP2_FRAME_SIZE_ERROR]: s.INTERNAL, - [c.NGHTTP2_REFUSED_STREAM]: s.UNAVAILABLE, - [c.NGHTTP2_CANCEL]: s.CANCELLED, - [c.NGHTTP2_COMPRESSION_ERROR]: s.INTERNAL, - [c.NGHTTP2_CONNECT_ERROR]: s.INTERNAL, - [c.NGHTTP2_ENHANCE_YOUR_CALM]: s.RESOURCE_EXHAUSTED, - [c.NGHTTP2_INADEQUATE_SECURITY]: s.PERMISSION_DENIED, - }; - const keys = Object.keys(errorCodeMapping).map(key => Number(key)); - keys.forEach(key => { - const value = errorCodeMapping[key]; - // A null value indicates: behavior isn't specified, so skip this test. - const maybeSkip = (fn: typeof it) => (value ? fn : fn.skip); - maybeSkip(it)(`for error code ${key}`, () => { - return new Promise((resolve, reject) => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [], - }); - callStream.attachHttp2Stream(http2Stream); - callStream.once('status', status => { - try { - assert.strictEqual(status.code, value); - resolve(); - } catch (e) { - reject(e); - } - }); - http2Stream.rstCode = Number(key); - http2Stream.emit('close'); - }); - }); - }); - }); - - it('should have functioning getters', done => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - assert.strictEqual(callStream.getDeadline(), callStreamArgs.deadline); - assert.strictEqual(callStream.getStatus(), null); - const credentials = CallCredentials.createEmpty(); - callStream.setCredentials(credentials); - assert.strictEqual(callStream.getCredentials(), credentials); - callStream.on( - 'status', - assert2.mustCall(status => { - assert.strictEqual(status.code, Status.CANCELLED); - assert.strictEqual(status.details, ';)'); - assert.strictEqual(callStream.getStatus(), status); - }) - ); - callStream.cancelWithStatus(Status.CANCELLED, ';)'); - // TODO: getPeer - assert2.afterMustCallsSatisfied(done); - }); - - describe('attachHttp2Stream', () => { - it('should handle an empty message', done => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: serialize(''), - frameLengths: [], - }); - callStream.once( - 'data', - assert2.mustCall(buffer => { - assert.strictEqual(buffer.toString('utf8'), ''); - }) - ); - callStream.attachHttp2Stream(http2Stream); - assert2.afterMustCallsSatisfied(done); - }); - - [ - { - description: 'all data is supplied in a single frame', - frameLengths: [], - }, - { - description: 'frames are split along header field delimiters', - frameLengths: [1, 4], - }, - { - description: - 'portions of header fields are split between different frames', - frameLengths: [2, 1, 1, 4], - }, - { - description: 'frames are split into bytes', - frameLengths: range(0, 20).map(() => 1), - }, - ].forEach((testCase: { description: string; frameLengths: number[] }) => { - it(`should handle a short message where ${ - testCase.description - }`, done => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: serialize(message), // 21 bytes - frameLengths: testCase.frameLengths, - }); - callStream.once( - 'data', - assert2.mustCall(buffer => { - assert.strictEqual(buffer.toString('utf8'), message); - }) - ); - callStream.once('end', assert2.mustCall(() => {})); - callStream.attachHttp2Stream(http2Stream); - assert2.afterMustCallsSatisfied(done); - }); - }); - - [ - { - description: 'all data is supplied in a single frame', - frameLengths: [], - }, - { - description: 'frames are split between delimited messages', - frameLengths: [21], - }, - { - description: 'frames are split within messages', - frameLengths: [10, 22], - }, - { - description: "part of 2nd message's header is in first frame", - frameLengths: [24], - }, - { - description: 'frames are split into bytes', - frameLengths: range(0, 41).map(() => 1), - }, - ].forEach((testCase: { description: string; frameLengths: number[] }) => { - it(`should handle two messages where ${testCase.description}`, done => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.concat([serialize(message), serialize(message)]), // 42 bytes - frameLengths: testCase.frameLengths, - }); - callStream.once( - 'data', - assert2.mustCall(buffer => { - assert.strictEqual(buffer.toString('utf8'), message); - }) - ); - callStream.once( - 'data', - assert2.mustCall(buffer => { - assert.strictEqual(buffer.toString('utf8'), message); - }) - ); - callStream.once('end', assert2.mustCall(() => {})); - callStream.attachHttp2Stream(http2Stream); - assert2.afterMustCallsSatisfied(done); - }); - }); - - it('should send buffered writes', done => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [], - }); - let streamFlushed = false; - http2Stream.once( - 'write', - assert2.mustCall((chunk: Buffer) => { - const dataLength = chunk.readInt32BE(1); - const encodedMessage = chunk.slice(5).toString('utf8'); - assert.strictEqual(dataLength, message.length); - assert.strictEqual(encodedMessage, message); - streamFlushed = true; - }) - ); - callStream.write( - { message: Buffer.from(message) }, - assert2.mustCall(() => { - // Ensure this is called only after contents are written to http2Stream - assert.ok(streamFlushed); - }) - ); - callStream.end(assert2.mustCall(() => {})); - callStream.attachHttp2Stream(http2Stream); - assert2.afterMustCallsSatisfied(done); - }); - - it('should cause data chunks in write calls afterward to be written to the given stream', done => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [], - }); - http2Stream.once( - 'write', - assert2.mustCall((chunk: Buffer) => { - const dataLength = chunk.readInt32BE(1); - const encodedMessage = chunk.slice(5).toString('utf8'); - assert.strictEqual(dataLength, message.length); - assert.strictEqual(encodedMessage, message); - }) - ); - callStream.attachHttp2Stream(http2Stream); - callStream.write( - { message: Buffer.from(message) }, - assert2.mustCall(() => {}) - ); - callStream.end(assert2.mustCall(() => {})); - assert2.afterMustCallsSatisfied(done); - }); - - it('should handle underlying stream errors', () => { - const callStream = new Http2CallStream( - 'foo', - {} as ChannelImplementation, - callStreamArgs, - filterStackFactory, - CallCredentials.createEmpty() - ); - const http2Stream = new ClientHttp2StreamMock({ - payload: Buffer.alloc(0), - frameLengths: [], - }); - callStream.once( - 'status', - assert2.mustCall(status => { - assert.strictEqual(status.code, Status.INTERNAL); - }) - ); - callStream.attachHttp2Stream(http2Stream); - http2Stream.emit('error'); - }); - }); -}); From 9238ad07cb24ca6a4e8d92262719126a98970917 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 24 Sep 2019 18:22:38 -0700 Subject: [PATCH 0784/1899] Fix DNS name regex and add tests --- packages/grpc-js/package.json | 3 +- packages/grpc-js/src/resolver-dns.ts | 8 +- packages/grpc-js/test/test-resolver.ts | 125 +++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 6 deletions(-) create mode 100644 packages/grpc-js/test/test-resolver.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ccb60b9c3..0f884d319 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.0", + "version": "0.6.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", @@ -22,7 +22,6 @@ "@types/mocha": "^5.2.6", "@types/node": "^12.7.5", "@types/ncp": "^2.0.1", - "@types/node": "^12.7.5", "@types/pify": "^3.0.2", "@types/semver": "^6.0.1", "clang-format": "^1.0.55", diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 94d5c6016..a8546f1c7 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -50,11 +50,11 @@ const IPV6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+ /** * Matches `[dns:][//authority/]host[:port]`, where `authority` and `host` are - * both arbitrary sequences of alphanumeric characters and `port` is a sequence - * of digits. Group 1 contains the hostname and group 2 contains the port - * number if provided. + * both arbitrary sequences of dot-separated strings of alphanumeric characters + * and `port` is a sequence of digits. Group 1 contains the hostname and group + * 2 contains the port number if provided. */ -const DNS_REGEX = /^(?:dns:)?(?:\/\/\w+\/)?(\w+)(?::(\d+))?$/; +const DNS_REGEX = /^(?:dns:)?(?:\/\/(?:[a-zA-Z0-9-]+\.?)+\/)?((?:[a-zA-Z0-9-]+\.?)+)(?::(\d+))?$/; /** * The default TCP port to connect to if not explicitly specified in the target. diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts new file mode 100644 index 000000000..35c11bf19 --- /dev/null +++ b/packages/grpc-js/test/test-resolver.ts @@ -0,0 +1,125 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any +import * as assert from 'assert'; +import * as resolverManager from '../src/resolver'; +import { ServiceConfig } from '../src/service-config'; +import { StatusObject } from '../src/call-stream'; + +describe('Name Resolver', () => { + describe('DNS Names', () => { + before(() => { + resolverManager.registerAll(); + }); + it('Should resolve localhost properly', done => { + const target = 'localhost:50051'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('127.0.0.1:50051')); + // We would check for the IPv6 address but it needs to be omitted on some Node versions + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should default to port 443', done => { + const target = 'localhost'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('127.0.0.1:443')); + // We would check for the IPv6 address but it needs to be omitted on some Node versions + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a public address', done => { + const target = 'example.com'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.length > 0); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a name with multiple dots', done => { + const target = 'loopback4.unittest.grpc.io'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.length > 0); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a name with a hyphen', done => { + /* TODO(murgatroid99): Find or create a better domain name to test this with. + * This is just the first one I found with a hyphen. */ + const target = 'network-tools.com'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.length > 0); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + }); +}); From 79286616d8de4cc6e88416c54466e5f17a9a7c30 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Tue, 24 Sep 2019 21:58:01 -0400 Subject: [PATCH 0785/1899] grpc-js: fix typo This commit fixes a typo observed in https://github.com/grpc/grpc-node/pull/1015 --- packages/grpc-js/src/compression-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index f28568e7c..34b7574fb 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -138,7 +138,7 @@ class UnknownHandler extends CompressionHandler { compressMessage(message: Buffer): Promise { return Promise.reject( new Error( - `Received message compressed wth unsupported compression method ${ + `Received message compressed with unsupported compression method ${ this.compressionName }` ) From e1ed6eb4488691d1dcd968b20c635880a9a1f7ff Mon Sep 17 00:00:00 2001 From: Bjorn Stromberg Date: Fri, 20 Sep 2019 12:54:42 +0900 Subject: [PATCH 0786/1899] Stop testing EOL versions of node --- run-tests.bat | 2 +- run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index d2484ae35..64396be17 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (6 7 8 9 10 11 12) do ( +for %%v in (8 10 12) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index 01e6741a2..f23475b90 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="6 7 8 9 10 11 12" + node_versions="8 10 12" fi set +ex From d27ca5d725eee68f23d9c7bc714b4a1871b03e6f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Sep 2019 09:27:02 -0700 Subject: [PATCH 0787/1899] Switch to a more reliable domain name with a hyphen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Natan Sągol --- packages/grpc-js/test/test-resolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 35c11bf19..72e0dae49 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -104,7 +104,7 @@ describe('Name Resolver', () => { it('Should resolve a name with a hyphen', done => { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ - const target = 'network-tools.com'; + const target = 'google-analytics.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: string[], From fe601286e614dd8b4f6860e692e5e59ea5a6482e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Sep 2019 10:51:06 -0700 Subject: [PATCH 0788/1899] Undo domain name change --- packages/grpc-js/test/test-resolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 72e0dae49..35c11bf19 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -104,7 +104,7 @@ describe('Name Resolver', () => { it('Should resolve a name with a hyphen', done => { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ - const target = 'google-analytics.com'; + const target = 'network-tools.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: string[], From c44edcbce528f9ca8ba7260194c123d8e6fd13a8 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 25 Sep 2019 13:34:49 -0700 Subject: [PATCH 0789/1899] Bump to 1.24.0 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 8dda84224..0c8148498 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.24.0-pre1"', + 'GRPC_NODE_VERSION="1.24.0"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index f703e1c86..16fba7baa 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit f703e1c86c1504d9e48953f8da31f842679b7775 +Subproject commit 16fba7baa0a35d9028f1cd9827c907be7d97269e diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e9e756bd2..b1cac6688 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.24.0-pre1", + "version": "1.24.0", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 5ab1806b444843f42765cac23f6ba29583520960 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 25 Sep 2019 17:53:05 -0700 Subject: [PATCH 0790/1899] Add UDS resolver --- packages/grpc-js/src/resolver-uds.ts | 57 ++++++++++++++++++++++++++ packages/grpc-js/src/resolver.ts | 2 + packages/grpc-js/test/test-resolver.ts | 36 ++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 packages/grpc-js/src/resolver-uds.ts diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts new file mode 100644 index 000000000..536a018b3 --- /dev/null +++ b/packages/grpc-js/src/resolver-uds.ts @@ -0,0 +1,57 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { + Resolver, + ResolverListener, + registerResolver, + registerDefaultResolver, +} from './resolver'; + +function getUdsName(target: string): string { + /* Due to how this resolver is registered, it should only be constructed + * with strings that start with 'unix:'. Other strings may result in + * nonsensical output. If the string starts with 'unix://' that entire + * prefix needs to be ignored */ + if (target.startsWith('unix://')) { + return target.substring(7); + } else { + return target.substring(5); + } +} + +class UdsResolver implements Resolver { + private addresses: string[] = []; + constructor(target: string, private listener: ResolverListener) { + this.addresses = [getUdsName(target)]; + } + updateResolution(): void { + process.nextTick( + this.listener.onSuccessfulResolution, + this.addresses, + null, + null + ); + } + + static getDefaultAuthority(target: string): string { + return 'localhost'; + } +} + +export function setup() { + registerResolver('unix:', UdsResolver); +} diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index b4c69f3df..512f3c55b 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,6 +18,7 @@ import { ServiceError } from './call'; import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; +import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; /** @@ -137,4 +138,5 @@ export function getDefaultAuthority(target: string): string { export function registerAll() { resolver_dns.setup(); + resolver_uds.setup(); } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 35c11bf19..1513783be 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -121,5 +121,41 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); + it('Should handle a relative Unix Domain Socket name', done => { + const target = 'unix:socket'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('socket')); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should handle an absolute Unix Domain Socket name', done => { + const target = 'unix:///tmp/socket'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('/tmp/socket')); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); }); }); From a064a8b1a8728b33224584bf0d35b51d6cbc5ab4 Mon Sep 17 00:00:00 2001 From: Srini Polavarapu Date: Thu, 26 Sep 2019 14:18:41 -0700 Subject: [PATCH 0791/1899] Add GOVERNANCE.md and CONTRIBUTING.md --- CONTRIBUTING.md | 5 +++++ GOVERNANCE.md | 1 + 2 files changed, 6 insertions(+) create mode 100644 CONTRIBUTING.md create mode 100644 GOVERNANCE.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..aa9b54472 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,5 @@ +# How to contribute + +We definitely welcome patches and contributions to grpc-node! Please read the gRPC +organization's [governance rules](https://github.com/grpc/grpc-community/blob/master/governance.md) +and [contribution guidelines](https://github.com/grpc/grpc-community/blob/master/CONTRIBUTING.md) before proceeding. diff --git a/GOVERNANCE.md b/GOVERNANCE.md new file mode 100644 index 000000000..d6ff26747 --- /dev/null +++ b/GOVERNANCE.md @@ -0,0 +1 @@ +This repository is governed by the gRPC organization's [governance rules](https://github.com/grpc/grpc-community/blob/master/governance.md). From 4fb254ddb6058b2810b82cd6f560f4534ceec1e4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 26 Sep 2019 14:32:54 -0700 Subject: [PATCH 0792/1899] grpc-js: Fix TLS server name handling --- packages/grpc-js/src/call-stream.ts | 2 ++ packages/grpc-js/src/subchannel.ts | 3 ++- packages/grpc-js/test/test-resolver.ts | 32 ++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 53a25f587..a53dbefa8 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -329,9 +329,11 @@ export class Http2CallStream extends Duplex implements Call { switch (stream.rstCode) { case http2.constants.NGHTTP2_REFUSED_STREAM: code = Status.UNAVAILABLE; + details = 'Stream refused by server'; break; case http2.constants.NGHTTP2_CANCEL: code = Status.CANCELLED; + details = 'Call cancelled'; break; case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: code = Status.RESOURCE_EXHAUSTED; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 65571586d..9148746fc 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -23,6 +23,7 @@ import { ChannelOptions } from './channel-options'; import { PeerCertificate, checkServerIdentity } from 'tls'; import { ConnectivityState } from './channel'; import { BackoffTimeout } from './backoff-timeout'; +import { getDefaultAuthority } from './resolver'; const { version: clientVersion } = require('../../package.json'); @@ -230,7 +231,7 @@ export class Subchannel { }; connectionOptions.servername = sslTargetNameOverride; } else { - connectionOptions.servername = this.channelTarget; + connectionOptions.servername = getDefaultAuthority(this.channelTarget); } } this.session = http2.connect( diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 35c11bf19..9df45c906 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -121,5 +121,37 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); + it('Should resolve gRPC interop servers', done => { + let completeCount = 0; + function done2(error?: Error) { + if (error) { + done(error); + } else { + completeCount += 1; + if (completeCount === 2) { + done(); + } + } + } + const target1 = 'grpc-test.sandbox.googleapis.com'; + const target2 = 'grpc-test4.sandbox.googleapis.com'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.length > 0); + done2(); + }, + onError: (error: StatusObject) => { + done2(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver1 = resolverManager.createResolver(target1, listener); + resolver1.updateResolution(); + const resolver2 = resolverManager.createResolver(target1, listener); + resolver2.updateResolution(); + }) }); }); From 06f60656929ec5ce045d65402a7e9ee7c70605a4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 26 Sep 2019 17:06:51 -0700 Subject: [PATCH 0793/1899] Increase resolver test timeout --- packages/grpc-js/test/test-resolver.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 9df45c906..9a0fbec24 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -22,12 +22,14 @@ import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; -describe('Name Resolver', () => { - describe('DNS Names', () => { - before(() => { +describe('Name Resolver', function() { + describe('DNS Names', function() { + // For some reason DNS queries sometimes take a long time on Windows + this.timeout(4000); + before(function() { resolverManager.registerAll(); }); - it('Should resolve localhost properly', done => { + it('Should resolve localhost properly', function(done) { const target = 'localhost:50051'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -46,7 +48,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should default to port 443', done => { + it('Should default to port 443', function(done) { const target = 'localhost'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -65,7 +67,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a public address', done => { + it('Should resolve a public address', function(done) { const target = 'example.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -83,7 +85,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a name with multiple dots', done => { + it('Should resolve a name with multiple dots', function(done) { const target = 'loopback4.unittest.grpc.io'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -101,7 +103,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a name with a hyphen', done => { + it('Should resolve a name with a hyphen', function(done) { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ const target = 'network-tools.com'; @@ -121,7 +123,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve gRPC interop servers', done => { + it('Should resolve gRPC interop servers', function(done) { let completeCount = 0; function done2(error?: Error) { if (error) { From 21e0bfae6798d91a4235eee472f2b71729d71ceb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 26 Sep 2019 18:09:25 -0700 Subject: [PATCH 0794/1899] Bump grpc-js to 0.6.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0f884d319..83ce7e7e4 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.1", + "version": "0.6.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From c7d086bfb40482dccfb1fb74cc1990247d259d7e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 30 Sep 2019 15:03:48 -0700 Subject: [PATCH 0795/1899] Properly use filtered metadata when starting requests --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index fe2bec7c8..9d6f00499 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -211,7 +211,7 @@ export class ChannelImplementation implements Channel { ConnectivityState.READY ) { pickResult.subchannel!.startCallStream( - callMetadata, + finalMetadata, callStream ); } else { From 4e7f4dff1708c53ce9d53429a2694aa17c2b9669 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 30 Sep 2019 15:56:15 -0700 Subject: [PATCH 0796/1899] Also use original call metadata --- packages/grpc-js/src/channel.ts | 2 +- packages/grpc-js/test/test-server-deadlines.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 9d6f00499..e672072ac 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -203,7 +203,7 @@ export class ChannelImplementation implements Channel { /* If the subchannel disconnects between calling pick and getting * the filter stack metadata, the call will end with an error. */ callStream.filterStack - .sendMetadata(Promise.resolve(new Metadata())) + .sendMetadata(Promise.resolve(callMetadata)) .then( finalMetadata => { if ( diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts index 2a1d3df93..dc607917c 100644 --- a/packages/grpc-js/test/test-server-deadlines.ts +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -83,9 +83,9 @@ describe('Server deadlines', () => { metadata, {}, (error: any, response: any) => { + assert(error); assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); assert.strictEqual(error.details, 'Deadline exceeded'); - assert.strictEqual(error.message, 'Deadline exceeded'); done(); } ); @@ -108,9 +108,9 @@ describe('Server deadlines', () => { metadata, {}, (error: any, response: any) => { + assert(error); assert.strictEqual(error.code, grpc.status.OUT_OF_RANGE); assert.strictEqual(error.details, 'Invalid deadline'); - assert.strictEqual(error.message, 'Invalid deadline'); done(); } ); From 1b2c558e535229a39726aa3cf50aaf5498908ff3 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 1 Oct 2019 10:43:49 -0700 Subject: [PATCH 0797/1899] Copy outgoing metadata to avoid modifying it --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index e672072ac..b2fdb6549 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -277,7 +277,7 @@ export class ChannelImplementation implements Channel { } _startCallStream(stream: Http2CallStream, metadata: Metadata) { - this.tryPick(stream, metadata); + this.tryPick(stream, metadata.clone()); } close() { From 093223579435aff79c9d78016c604f74424dd346 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 1 Oct 2019 11:52:50 -0700 Subject: [PATCH 0798/1899] Update grpc-js to 0.6.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 83ce7e7e4..ab6ff30d3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.2", + "version": "0.6.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 1e2a7cb2e3ba6bdeef71cc0e105821f8e68b49c6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 1 Oct 2019 17:20:29 -0700 Subject: [PATCH 0799/1899] Bump submodule to 1.23.1 and library version to 1.23.4 --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 2 +- packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 2851af483..d058186a6 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -97,7 +97,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.23.3"', + 'GRPC_NODE_VERSION="1.23.4"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index d6ebeea62..7d06779b9 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,3 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. - node_version: 1.23.3 + node_version: 1.23.4 diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 7c0764918..6a37b6696 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 7c0764918b9f33cab507ff483b4be849b0203ec4 +Subproject commit 6a37b6696b359cb77d3ff13015234febdf9fd890 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 74b5e77a4..c0945a85b 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.23.3", + "version": "1.23.4", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From 5876f616814625f8000ee29ffa2b3e359cb424ff Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 2 Oct 2019 13:13:43 -0700 Subject: [PATCH 0800/1899] Publish .inc files from abseil and upb --- packages/grpc-native-core/package.json | 4 ++-- packages/grpc-native-core/templates/package.json.template | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index b1cac6688..707228c7d 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -67,13 +67,13 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh,inc}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", "deps/grpc/third_party/nanopb/*.{c,cc,h}", - "deps/grpc/third_party/upb/**/*.{c,h}", + "deps/grpc/third_party/upb/**/*.{c,h,inc}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" ], diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 080567c56..e99437f49 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -69,13 +69,13 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh,inc}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", "deps/grpc/third_party/nanopb/*.{c,cc,h}", - "deps/grpc/third_party/upb/**/*.{c,h}", + "deps/grpc/third_party/upb/**/*.{c,h,inc}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" ], From a23f739e5f3ef51912976d8a6deceb5f2c949434 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 2 Oct 2019 15:18:40 -0700 Subject: [PATCH 0801/1899] grpc-js: exitIdle asynchronously in QueuePicker, only act in exitIdle if IDLE --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/picker.ts | 4 +++- packages/grpc-js/src/resolving-load-balancer.ts | 12 +++++++----- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ab6ff30d3..fac206347 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.3", + "version": "0.6.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 94b8fbe24..d908f0261 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -113,7 +113,9 @@ export class QueuePicker { pick(pickArgs: PickArgs): QueuePickResult { if (!this.calledExitIdle) { - this.loadBalancer.exitIdle(); + process.nextTick(() => { + this.loadBalancer.exitIdle(); + }); this.calledExitIdle = true; } return { diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 12f1b3b7d..16d725395 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -331,14 +331,16 @@ export class ResolvingLoadBalancer implements LoadBalancer { } exitIdle() { - this.innerResolver.updateResolution(); if (this.innerLoadBalancer !== null) { this.innerLoadBalancer.exitIdle(); } - this.channelControlHelper.updateState( - ConnectivityState.CONNECTING, - new QueuePicker(this) - ); + if (this.currentState === ConnectivityState.IDLE) { + this.innerResolver.updateResolution(); + this.updateState( + ConnectivityState.CONNECTING, + new QueuePicker(this) + ); + } } updateAddressList( From 57789c409e64663f0d5f1bf9a9c9f2ad769466b1 Mon Sep 17 00:00:00 2001 From: Esun Kim Date: Fri, 23 Aug 2019 10:30:16 -0700 Subject: [PATCH 0802/1899] Clean up nanopb --- packages/grpc-native-core/binding.gyp | 2 -- packages/grpc-native-core/package.json | 1 - packages/grpc-native-core/templates/binding.gyp.template | 2 -- packages/grpc-native-core/templates/package.json.template | 1 - 4 files changed, 6 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 8dda84224..e4b2f0825 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -82,12 +82,10 @@ 'deps/grpc/third_party/address_sorting/include', 'deps/grpc/third_party/cares', 'deps/grpc/third_party/cares/cares', - 'deps/grpc/third_party/nanopb', 'deps/grpc/third_party/upb', 'deps/grpc/third_party/upb/generated_for_cmake', ], 'defines': [ - 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e9e756bd2..a50f0332e 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -72,7 +72,6 @@ "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", - "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/upb/**/*.{c,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index 1d9f07fc8..bd73397ce 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -78,12 +78,10 @@ 'deps/grpc/third_party/address_sorting/include', 'deps/grpc/third_party/cares', 'deps/grpc/third_party/cares/cares', - 'deps/grpc/third_party/nanopb', 'deps/grpc/third_party/upb', 'deps/grpc/third_party/upb/generated_for_cmake', ], 'defines': [ - 'PB_FIELD_32BIT', 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 080567c56..f62e277da 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -74,7 +74,6 @@ "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", - "deps/grpc/third_party/nanopb/*.{c,cc,h}", "deps/grpc/third_party/upb/**/*.{c,h}", "deps/grpc/third_party/zlib/**/*.{c,cc,h}", "binding.gyp" From 781b13573f7120b30c0ee9f9f8abe05ca2d926f4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 3 Oct 2019 15:17:07 -0700 Subject: [PATCH 0803/1899] Add round robin load balancer implementation --- PACKAGE-COMPARISON.md | 1 + packages/grpc-js/src/channel-options.ts | 2 + packages/grpc-js/src/channel.ts | 7 +- .../grpc-js/src/load-balancer-round-robin.ts | 187 ++++++++++++++++++ packages/grpc-js/src/load-balancer.ts | 2 + packages/grpc-js/src/service-config.ts | 2 +- 6 files changed, 198 insertions(+), 3 deletions(-) create mode 100644 packages/grpc-js/src/load-balancer-round-robin.ts diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 6d748e65a..8a62c9145 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -36,5 +36,6 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.default_authority` - `grpc.keepalive_time_ms` - `grpc.keepalive_timeout_ms` + - `grpc.service_config` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index b71459700..ad905b9fa 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -25,6 +25,7 @@ export interface ChannelOptions { 'grpc.default_authority'?: string; 'grpc.keepalive_time_ms'?: number; 'grpc.keepalive_timeout_ms'?: number; + 'grpc.service_config'?: string; [key: string]: string | number | undefined; } @@ -39,6 +40,7 @@ export const recognizedOptions = { 'grpc.default_authority': true, 'grpc.keepalive_time_ms': true, 'grpc.keepalive_timeout_ms': true, + 'grpc.service_config': true, }; export function channelOptionsEqual( diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index b2fdb6549..c06c39786 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -36,7 +36,7 @@ import { MetadataStatusFilterFactory } from './metadata-status-filter'; import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority } from './resolver'; import { LoadBalancingConfig } from './load-balancing-config'; -import { ServiceConfig } from './service-config'; +import { ServiceConfig, validateServiceConfig } from './service-config'; export enum ConnectivityState { CONNECTING, @@ -159,10 +159,13 @@ export class ChannelImplementation implements Channel { }, }; // TODO(murgatroid99): check channel arg for default service config - const defaultServiceConfig: ServiceConfig = { + let defaultServiceConfig: ServiceConfig = { loadBalancingConfig: [], methodConfig: [], }; + if (options['grpc.service_config']) { + defaultServiceConfig = validateServiceConfig(JSON.parse(options['grpc.service_config']!)); + } this.resolvingLoadBalancer = new ResolvingLoadBalancer( target, channelControlHelper, diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts new file mode 100644 index 000000000..72af705d7 --- /dev/null +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -0,0 +1,187 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + registerLoadBalancerType, +} from './load-balancer'; +import { ConnectivityState } from './channel'; +import { + QueuePicker, + Picker, + PickArgs, + CompletePickResult, + PickResultType, + UnavailablePicker, +} from './picker'; +import { LoadBalancingConfig } from './load-balancing-config'; +import { Subchannel, ConnectivityStateListener } from './subchannel'; + +const TYPE_NAME = 'round_robin'; + +class RoundRobinPicker implements Picker { + constructor(private readonly subchannelList: Subchannel[], private nextIndex = 0) {} + + pick(pickArgs: PickArgs): CompletePickResult { + const pickedSubchannel = this.subchannelList[this.nextIndex]; + this.nextIndex = (this.nextIndex + 1) % this.subchannelList.length; + return { + pickResultType: PickResultType.COMPLETE, + subchannel: pickedSubchannel, + status: null + }; + } + + /** + * Check what the next subchannel returned would be. Used by the load + * balancer implementation to preserve this part of the picker state if + * possible when a subchannel connects or disconnects. + */ + peekNextSubchannel(): Subchannel { + return this.subchannelList[this.nextIndex]; + } +} + +interface ConnectivityStateCounts { + [ConnectivityState.CONNECTING]: number, + [ConnectivityState.IDLE]: number, + [ConnectivityState.READY]: number, + [ConnectivityState.SHUTDOWN]: number, + [ConnectivityState.TRANSIENT_FAILURE]: number +} + +export class RoundRobinLoadBalancer implements LoadBalancer { + + private subchannels: Subchannel[] = []; + + private currentState: ConnectivityState = ConnectivityState.IDLE; + + private subchannelStateListener: ConnectivityStateListener; + + private subchannelStateCounts: ConnectivityStateCounts; + + private currentReadyPicker: RoundRobinPicker | null = null; + + constructor(private channelControlHelper: ChannelControlHelper) { + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + this.subchannelStateCounts = { + [ConnectivityState.CONNECTING]: 0, + [ConnectivityState.IDLE]: 0, + [ConnectivityState.READY]: 0, + [ConnectivityState.SHUTDOWN]: 0, + [ConnectivityState.TRANSIENT_FAILURE]: 0 + }; + this.subchannelStateListener = ( + subchannel: Subchannel, + previousState: ConnectivityState, + newState: ConnectivityState + ) => { + this.subchannelStateCounts[previousState] -= 1; + this.subchannelStateCounts[newState] += 1; + this.calculateAndUpdateState(); + + if (newState === ConnectivityState.TRANSIENT_FAILURE) { + this.channelControlHelper.requestReresolution(); + } + if (newState === ConnectivityState.TRANSIENT_FAILURE || newState === ConnectivityState.IDLE) { + subchannel.startConnecting(); + } + } + } + + private calculateAndUpdateState() { + if (this.subchannelStateCounts[ConnectivityState.READY] > 0) { + const readySubchannels = this.subchannels.filter(subchannel => subchannel.getConnectivityState() === ConnectivityState.READY); + let index: number = 0; + if (this.currentReadyPicker !== null) { + index = readySubchannels.indexOf(this.currentReadyPicker.peekNextSubchannel()); + if (index < 0) { + index = 0; + } + } + this.updateState(ConnectivityState.READY, new RoundRobinPicker(readySubchannels, index)); + } else if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { + this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker()); + } else { + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + } + } + + private updateState(newState: ConnectivityState, picker: Picker) { + if (newState === ConnectivityState.READY) { + this.currentReadyPicker = picker as RoundRobinPicker; + } else { + this.currentReadyPicker = null; + } + this.currentState = newState; + this.channelControlHelper.updateState(newState, picker); + } + + private resetSubchannelList() { + for (const subchannel of this.subchannels) { + subchannel.removeConnectivityStateListener(this.subchannelStateListener); + subchannel.unref(); + } + this.subchannelStateCounts = { + [ConnectivityState.CONNECTING]: 0, + [ConnectivityState.IDLE]: 0, + [ConnectivityState.READY]: 0, + [ConnectivityState.SHUTDOWN]: 0, + [ConnectivityState.TRANSIENT_FAILURE]: 0 + }; + this.subchannels = []; + } + + updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void { + this.resetSubchannelList(); + this.subchannels = addressList.map(address => this.channelControlHelper.createSubchannel(address, {})); + for (const subchannel of this.subchannels) { + const subchannelState = subchannel.getConnectivityState(); + this.subchannelStateCounts[subchannelState] += 1; + if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.TRANSIENT_FAILURE) { + subchannel.startConnecting(); + } + } + this.calculateAndUpdateState(); + } + + exitIdle(): void { + for (const subchannel of this.subchannels) { + subchannel.startConnecting(); + } + } + resetBackoff(): void { + /* The pick first load balancer does not have a connection backoff, so this + * does nothing */ + } + destroy(): void { + this.resetSubchannelList(); + } + getTypeName(): string { + return TYPE_NAME; + } + replaceChannelControlHelper(channelControlHelper: ChannelControlHelper): void { + this.channelControlHelper = channelControlHelper; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer); +} diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index a74deea73..691145214 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -21,6 +21,7 @@ import { ConnectivityState } from './channel'; import { Picker } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; import * as load_balancer_pick_first from './load-balancer-pick-first'; +import * as load_balancer_round_robin from './load-balancer-round-robin'; /** * A collection of functions associated with a channel that a load balancer @@ -128,4 +129,5 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { export function registerAll() { load_balancer_pick_first.setup(); + load_balancer_round_robin.setup(); } diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index d9b608127..fc8cda043 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -124,7 +124,7 @@ function validateMethodConfig(obj: any): MethodConfig { return result; } -function validateServiceConfig(obj: any): ServiceConfig { +export function validateServiceConfig(obj: any): ServiceConfig { const result: ServiceConfig = { loadBalancingConfig: [], methodConfig: [], From 81a1aa17b24cba3f81c0e13f9870503cc358fe1c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 4 Oct 2019 10:21:15 -0700 Subject: [PATCH 0804/1899] Add tracing functionality and a few connectivity state tracers --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 4 ++- .../grpc-js/src/load-balancer-pick-first.ts | 12 +++++++++ packages/grpc-js/src/logging.ts | 27 ++++++++++++++++++- packages/grpc-js/src/resolver-dns.ts | 13 +++++++++ .../grpc-js/src/resolving-load-balancer.ts | 9 +++++++ packages/grpc-js/src/subchannel.ts | 13 +++++++++ 7 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index fac206347..38e104794 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.4", + "version": "0.6.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index b2fdb6549..5fac0ef97 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -28,7 +28,7 @@ import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; import { ChannelControlHelper } from './load-balancer'; import { UnavailablePicker, Picker, PickResultType } from './picker'; import { Metadata } from './metadata'; -import { Status } from './constants'; +import { Status, LogVerbosity } from './constants'; import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; @@ -37,6 +37,7 @@ import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority } from './resolver'; import { LoadBalancingConfig } from './load-balancing-config'; import { ServiceConfig } from './service-config'; +import { trace } from './logging'; export enum ConnectivityState { CONNECTING, @@ -265,6 +266,7 @@ export class ChannelImplementation implements Channel { } private updateState(newState: ConnectivityState): void { + trace(LogVerbosity.DEBUG, 'connectivity_state', this.target + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); this.connectivityState = newState; const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index d1252507c..0771abbe5 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -31,6 +31,14 @@ import { } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; import { Subchannel, ConnectivityStateListener } from './subchannel'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'pick_first'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'pick_first'; @@ -218,6 +226,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.subchannels[subchannelIndex].getConnectivityState() === ConnectivityState.IDLE ) { + trace('Start connecting to subchannel with address ' + this.subchannels[subchannelIndex].getAddress()); process.nextTick(() => { this.subchannels[subchannelIndex].startConnecting(); }); @@ -228,6 +237,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { } private pickSubchannel(subchannel: Subchannel) { + trace('Pick subchannel with address ' + subchannel.getAddress()); if (this.currentPick !== null) { this.currentPick.unref(); this.currentPick.removeConnectivityStateListener( @@ -243,6 +253,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { } private updateState(newState: ConnectivityState, picker: Picker) { + trace(ConnectivityState[this.currentState] + ' -> ' + ConnectivityState[newState]); this.currentState = newState; this.channelControlHelper.updateState(newState, picker); } @@ -264,6 +275,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { */ private connectToAddressList(): void { this.resetSubchannelList(); + trace('Connect to address list ' + this.latestAddressList); this.subchannels = this.latestAddressList.map(address => this.channelControlHelper.createSubchannel(address, {}) ); diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 859b3ac51..31e38e4d6 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -18,7 +18,23 @@ import { LogVerbosity } from './constants'; let _logger: Partial = console; -let _logVerbosity: LogVerbosity = LogVerbosity.DEBUG; +let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; + +if (process.env.GRPC_VERBOSITY) { + switch (process.env.GRPC_VERBOSITY) { + case 'DEBUG': + _logVerbosity = LogVerbosity.DEBUG; + break; + case 'INFO': + _logVerbosity = LogVerbosity.INFO; + break; + case 'ERROR': + _logVerbosity = LogVerbosity.ERROR; + break; + default: + // Ignore any other values + } +} export const getLogger = (): Partial => { return _logger; @@ -38,3 +54,12 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { _logger.error(...args); } }; + +const enabledTracers = process.env.GRPC_TRACE ? process.env.GRPC_TRACE.split(',') : []; +const allEnabled = enabledTracers.includes('all'); + +export function trace(severity: LogVerbosity, tracer: string, text: string): void { + if (allEnabled || enabledTracers.includes(tracer)) { + log(severity, (new Date().toISOString() + ' | ' + tracer + ' | ' + text)); + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index a8546f1c7..a6b0ae164 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -28,6 +28,14 @@ import { ServiceError } from './call'; import { Status } from './constants'; import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'dns_resolver'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} /* These regular expressions match IP addresses with optional ports in different * formats. In each case, capture group 1 contains the address, and capture @@ -159,6 +167,7 @@ class DnsResolver implements Resolver { private percentage: number; private defaultResolutionError: StatusObject; constructor(private target: string, private listener: ResolverListener) { + trace('Resolver constructed for target ' + target); this.ipResult = parseIP(target); const dnsMatch = DNS_REGEX.exec(target); if (dnsMatch === null) { @@ -187,6 +196,7 @@ class DnsResolver implements Resolver { */ private startResolution() { if (this.ipResult !== null) { + trace('Returning IP address for target ' + this.target); setImmediate(() => { this.listener.onSuccessfulResolution(this.ipResult!, null, null); }); @@ -222,6 +232,7 @@ class DnsResolver implements Resolver { ip4Addresses, ip6Addresses ); + trace('Resolved addresses for target ' + this.target + ': ' + allAddresses); if (allAddresses.length === 0) { this.listener.onError(this.defaultResolutionError); return; @@ -255,6 +266,7 @@ class DnsResolver implements Resolver { ); }, err => { + trace('Resolution error for target ' + this.target + ': ' + (err as Error).message); this.pendingResultPromise = null; this.listener.onError(this.defaultResolutionError); } @@ -263,6 +275,7 @@ class DnsResolver implements Resolver { } updateResolution() { + trace('Resolution update requested for target ' + this.target); if (this.pendingResultPromise === null) { this.startResolution(); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 16d725395..f66801151 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -32,6 +32,14 @@ import { BackoffTimeout } from './backoff-timeout'; import { Status } from './constants'; import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'resolving_load_balancer'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; @@ -297,6 +305,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } private updateState(connectivitystate: ConnectivityState, picker: Picker) { + trace(this.target + ' ' + ConnectivityState[this.currentState] + ' -> ' + ConnectivityState[connectivitystate]); this.currentState = connectivitystate; this.channelControlHelper.updateState(connectivitystate, picker); } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 9148746fc..cbf517cb0 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -24,9 +24,17 @@ import { PeerCertificate, checkServerIdentity } from 'tls'; import { ConnectivityState } from './channel'; import { BackoffTimeout } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; const { version: clientVersion } = require('../../package.json'); +const TRACER_NAME = 'subchannel'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; const BACKOFF_MULTIPLIER = 1.6; @@ -277,6 +285,7 @@ export class Subchannel { if (oldStates.indexOf(this.connectivityState) === -1) { return false; } + trace(this.subchannelAddress + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); const previousState = this.connectivityState; this.connectivityState = newState; switch (newState) { @@ -464,4 +473,8 @@ export class Subchannel { ConnectivityState.CONNECTING ); } + + getAddress(): string { + return this.subchannelAddress; + } } From f40d6a61c0ad3690afcf08d8780529d0deff303a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 4 Oct 2019 10:52:34 -0700 Subject: [PATCH 0805/1899] Pick first: go IDLE if all subchannels go IDLE --- .../grpc-js/src/load-balancer-pick-first.ts | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index d1252507c..1488c9815 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -56,6 +56,14 @@ class PickFirstPicker implements Picker { } } +interface ConnectivityStateCounts { + [ConnectivityState.CONNECTING]: number, + [ConnectivityState.IDLE]: number, + [ConnectivityState.READY]: number, + [ConnectivityState.SHUTDOWN]: number, + [ConnectivityState.TRANSIENT_FAILURE]: number +} + export class PickFirstLoadBalancer implements LoadBalancer { /** * The list of backend addresses most recently passed to `updateAddressList`. @@ -75,11 +83,8 @@ export class PickFirstLoadBalancer implements LoadBalancer { * recently started connection attempt. */ private currentSubchannelIndex = 0; - /** - * The number of subchannels in the `subchannels` list currently in the - * CONNECTING state. Used to determine the overall load balancer state. - */ - private subchannelConnectingCount = 0; + + private subchannelStateCounts: ConnectivityStateCounts; /** * The currently picked subchannel used for making calls. Populated if * and only if the load balancer's current state is READY. In that case, @@ -111,17 +116,20 @@ export class PickFirstLoadBalancer implements LoadBalancer { */ constructor(private channelControlHelper: ChannelControlHelper) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + this.subchannelStateCounts = { + [ConnectivityState.CONNECTING]: 0, + [ConnectivityState.IDLE]: 0, + [ConnectivityState.READY]: 0, + [ConnectivityState.SHUTDOWN]: 0, + [ConnectivityState.TRANSIENT_FAILURE]: 0 + }; this.subchannelStateListener = ( subchannel: Subchannel, previousState: ConnectivityState, newState: ConnectivityState ) => { - if (previousState === ConnectivityState.CONNECTING) { - this.subchannelConnectingCount -= 1; - } - if (newState === ConnectivityState.CONNECTING) { - this.subchannelConnectingCount += 1; - } + this.subchannelStateCounts[previousState] -= 1; + this.subchannelStateCounts[newState] += 1; /* If the subchannel we most recently attempted to start connecting * to goes into TRANSIENT_FAILURE, immediately try to start * connecting to the next one instead of waiting for the connection @@ -138,10 +146,14 @@ export class PickFirstLoadBalancer implements LoadBalancer { } else { if (this.currentPick === null) { if (this.triedAllSubchannels) { - const newLBState = - this.subchannelConnectingCount > 0 - ? ConnectivityState.CONNECTING - : ConnectivityState.TRANSIENT_FAILURE; + let newLBState: ConnectivityState; + if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { + newLBState = ConnectivityState.CONNECTING; + } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { + newLBState = ConnectivityState.TRANSIENT_FAILURE; + } else { + newLBState = ConnectivityState.IDLE; + } if (newLBState !== this.currentState) { if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { this.updateState(newLBState, new UnavailablePicker()); @@ -169,10 +181,14 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.pickedSubchannelStateListener ); if (this.subchannels.length > 0) { - const newLBState = - this.subchannelConnectingCount > 0 - ? ConnectivityState.CONNECTING - : ConnectivityState.TRANSIENT_FAILURE; + let newLBState: ConnectivityState; + if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { + newLBState = ConnectivityState.CONNECTING; + } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { + newLBState = ConnectivityState.TRANSIENT_FAILURE; + } else { + newLBState = ConnectivityState.IDLE; + } if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { this.updateState(newLBState, new UnavailablePicker()); } else { @@ -253,7 +269,13 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.unref(); } this.currentSubchannelIndex = 0; - this.subchannelConnectingCount = 0; + this.subchannelStateCounts = { + [ConnectivityState.CONNECTING]: 0, + [ConnectivityState.IDLE]: 0, + [ConnectivityState.READY]: 0, + [ConnectivityState.SHUTDOWN]: 0, + [ConnectivityState.TRANSIENT_FAILURE]: 0 + }; this.subchannels = []; this.triedAllSubchannels = false; } From e480a0a686a4ecf98d1f0ff348c6f1d0027e31f5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 7 Oct 2019 13:44:08 -0700 Subject: [PATCH 0806/1899] grpc-js: pick first: remove reference and go idle after disconnect --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/load-balancer-pick-first.ts | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 38e104794..d80e40701 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.5", + "version": "0.6.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index a12fc8e2b..5d221fc0a 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -184,6 +184,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { newState: ConnectivityState ) => { if (newState !== ConnectivityState.READY) { + this.currentPick = null; subchannel.unref(); subchannel.removeConnectivityStateListener( this.pickedSubchannelStateListener @@ -203,8 +204,11 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.updateState(newLBState, new QueuePicker(this)); } } else { - this.connectToAddressList(); - this.channelControlHelper.requestReresolution(); + /* We don't need to backoff here because this only happens if a + * subchannel successfully connects then disconnects, so it will not + * create a loop of attempting to connect to an unreachable backend + */ + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); } } }; @@ -348,6 +352,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.startConnecting(); } if (this.currentState === ConnectivityState.IDLE) { + this.channelControlHelper.requestReresolution(); if (this.latestAddressList.length > 0) { this.connectToAddressList(); } From 1d7a7f4700b7bc7d32c60e48d9a073eed1824783 Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Tue, 8 Oct 2019 11:33:30 -0600 Subject: [PATCH 0807/1899] grpc-js: export additional api in index.ts --- packages/grpc-js/src/index.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 614ca6c78..b9406fdbd 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -36,6 +36,7 @@ import { loadPackageDefinition, makeClientConstructor, Serialize, + ServiceDefinition } from './make-client'; import { Metadata } from './metadata'; import { @@ -46,6 +47,9 @@ import { import { KeyCertPair, ServerCredentials } from './server-credentials'; import { StatusBuilder } from './status-builder'; import { + handleBidiStreamingCall, + handleServerStreamingCall, + handleUnaryCall, ServerUnaryCall, ServerReadableStream, ServerWritableStream, @@ -227,10 +231,19 @@ export { ServerReadableStream, ServerWritableStream, ServerDuplexStream, + ServiceDefinition, UntypedHandleCall, UntypedServiceImplementation, }; +/**** Server ****/ + +export { + handleBidiStreamingCall, + handleServerStreamingCall, + handleUnaryCall, +}; + /* tslint:disable:no-any */ export type Call = | ClientUnaryCall From 1aac229321d276fbe35ff9004aef8453bc2f84e6 Mon Sep 17 00:00:00 2001 From: Mario Minardi Date: Tue, 8 Oct 2019 11:34:18 -0600 Subject: [PATCH 0808/1899] grpc-js: change signature of MethodDefinition used in ServiceDefinition --- packages/grpc-js/src/make-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index f30710e6f..fc44c6741 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -39,7 +39,7 @@ export interface MethodDefinition { } export interface ServiceDefinition { - [index: string]: MethodDefinition; + [index: string]: MethodDefinition; } export interface ProtobufTypeDefinition { From ee72cd440f203fe9026072b44f08a25a7df55534 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 8 Oct 2019 16:35:42 -0700 Subject: [PATCH 0809/1899] grpc-js: pick-first: fix bad state transition when reconnecting connected LB --- packages/grpc-js/package.json | 2 +- .../grpc-js/src/load-balancer-pick-first.ts | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d80e40701..32f46cedb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.6", + "version": "0.6.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 5d221fc0a..a764a2208 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -312,10 +312,6 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.addConnectivityStateListener(this.subchannelStateListener); if (subchannel.getConnectivityState() === ConnectivityState.READY) { this.pickSubchannel(subchannel); - this.updateState( - ConnectivityState.READY, - new PickFirstPicker(subchannel) - ); this.resetSubchannelList(); return; } @@ -327,15 +323,19 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannelState === ConnectivityState.CONNECTING ) { this.startConnecting(index); - this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + if (this.currentPick === null) { + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + } return; } } // If the code reaches this point, every subchannel must be in TRANSIENT_FAILURE - this.updateState( - ConnectivityState.TRANSIENT_FAILURE, - new UnavailablePicker() - ); + if (this.currentPick === null) { + this.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker() + ); + } } updateAddressList( From f29c983851c355e0f49f4c0076301b510c1cfb4d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 9 Oct 2019 12:46:25 -0700 Subject: [PATCH 0810/1899] Make error message match other library --- packages/grpc-js/src/call.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index e6127faac..5734bc3d0 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -75,8 +75,9 @@ export type ClientDuplexStream< * @param status */ export function callErrorFromStatus(status: StatusObject): ServiceError { + const message = `${status.code} ${Status[status.code]}: ${status.details}`; return Object.assign( - new Error(status.details), + new Error(message), status ); } From 50a3ead062121536305d6fb871bc0da627ae599c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 9 Oct 2019 13:14:30 -0700 Subject: [PATCH 0811/1899] Don't test value of error.message --- packages/grpc-js/test/test-server-deadlines.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts index 2a1d3df93..4e39f7875 100644 --- a/packages/grpc-js/test/test-server-deadlines.ts +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -85,7 +85,6 @@ describe('Server deadlines', () => { (error: any, response: any) => { assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); assert.strictEqual(error.details, 'Deadline exceeded'); - assert.strictEqual(error.message, 'Deadline exceeded'); done(); } ); @@ -110,7 +109,6 @@ describe('Server deadlines', () => { (error: any, response: any) => { assert.strictEqual(error.code, grpc.status.OUT_OF_RANGE); assert.strictEqual(error.details, 'Invalid deadline'); - assert.strictEqual(error.message, 'Invalid deadline'); done(); } ); @@ -160,7 +158,6 @@ describe('Cancellation', () => { call.on('error', (error: ServiceError) => { assert.strictEqual(error.code, grpc.status.CANCELLED); assert.strictEqual(error.details, 'Cancelled on client'); - assert.strictEqual(error.message, 'Cancelled on client'); waitForServerCancel(); }); From ee0554231bf0c42cb92f40089df1d91a8a4ccf42 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 9 Oct 2019 16:42:36 -0700 Subject: [PATCH 0812/1899] Add regression tests for recent failures, move a test --- test/api/interop_extra_test.js | 136 +++++++++++++++++++++++++++++++++ test/api/metadata_test.js | 103 ------------------------- 2 files changed, 136 insertions(+), 103 deletions(-) create mode 100644 test/api/interop_extra_test.js delete mode 100644 test/api/metadata_test.js diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js new file mode 100644 index 000000000..8a3dc52c4 --- /dev/null +++ b/test/api/interop_extra_test.js @@ -0,0 +1,136 @@ +/* + * + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +const assert = require('assert'); +const fs = require('fs'); +const path = require('path'); +const interopServer = require('../interop/interop_server.js'); +const grpc = require('../any_grpc').client; +var protoLoader = require('../../packages/proto-loader'); + +const protoPackage = protoLoader.loadSync( + 'src/proto/grpc/testing/test.proto', + {keepCase: true, + defaults: true, + enums: String, + includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); +const testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; + +function multiDone(done, count) { + return function() { + count -= 1; + if (count <= 0) { + done(); + } + }; +} + +function echoMetadataGenerator(options, callback) { + const metadata = new grpc.Metadata(); + metadata.set('x-grpc-test-echo-initial', 'test_initial_metadata_value'); + console.log('Adding metadata'); + console.log(metadata); + callback(null, metadata); +} + +const credentials = grpc.credentials.createFromMetadataGenerator(echoMetadataGenerator); + +describe('Interop-adjacent tests', function() { + let server; + let client; + before(function(done) { + interopServer.getServer(0, true, (err, serverObj) => { + if (err) { + done(err); + } else { + server = serverObj.server; + server.start(); + const ca_path = path.join(__dirname, '../data/ca.pem'); + const ca_data = fs.readFileSync(ca_path); + const creds = grpc.credentials.createSsl(ca_data); + const options = { + 'grpc.ssl_target_name_override': 'foo.test.google.fr', + 'grpc.default_authority': 'foo.test.google.fr' + }; + client = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + done(); + } + }); + }); + after(function() { + server.forceShutdown(); + }); + it('Should be able to start many concurrent calls', function(done) { + const callCount = 1000; + done = multiDone(done, callCount); + for (let i = 0; i < callCount; i++) { + client.unaryCall({}, (error, result) => { + assert.ifError(error); + done(); + }); + } + }); + it('Should echo metadata from call credentials', function(done) { + done = multiDone(done, 2); + const call = client.unaryCall({}, {credentials}, (error, result) => { + assert.ifError(error); + done(); + }); + call.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + }); + it('Should be able to send the same metadata on two calls with call creds', function(done) { + done = multiDone(done, 5); + const metadata = new grpc.Metadata(); + metadata.set('x-grpc-test-echo-trailing-bin', Buffer.from('ababab', 'hex')); + const call1 = client.unaryCall({}, metadata, {credentials}, (error, result) => { + assert.ifError(error); + const call2 = client.unaryCall({}, metadata, {credentials}, (error, result) => { + assert.ifError(error); + done(); + }); + call2.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + call2.on('status', function(status) { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); + }); + call1.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + call1.on('status', function(status) { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); + }); +}); \ No newline at end of file diff --git a/test/api/metadata_test.js b/test/api/metadata_test.js deleted file mode 100644 index 16d7216bc..000000000 --- a/test/api/metadata_test.js +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -const options = { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true -}; -const path = require('path'); -const fs = require('fs'); -const assert = require('assert'); -const _ = require('lodash'); -const anyGrpc = require('../any_grpc'); -const clientGrpc = anyGrpc.client; -const serverGrpc = anyGrpc.server; -const protoLoader = require('../../packages/proto-loader', options); -const testServiceDef = protoLoader.loadSync(__dirname + '/../proto/test_service.proto'); -const TestService = serverGrpc.loadPackageDefinition(testServiceDef).TestService.service; -const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestService; - -const keyPath = path.join(__dirname, '../data/server1.key'); -const pemPath = path.join(__dirname, '../data/server1.pem'); -const caPath = path.join(__dirname, '../data/ca.pem'); -const keyData = fs.readFileSync(keyPath); -const pemData = fs.readFileSync(pemPath); -const caData = fs.readFileSync(caPath); - -const clientCreds = clientGrpc.credentials.createSsl(caData); -const dummyCallCreds = clientGrpc.credentials.createFromMetadataGenerator((options, callback) => { - const metadata = new clientGrpc.Metadata(); - metadata.add('authorization', 'test'); - callback(null, metadata); -}); -const combinedClientCreds = clientGrpc.credentials.combineChannelCredentials(clientCreds, dummyCallCreds); -const serverCreds = serverGrpc.ServerCredentials.createSsl(null, [{private_key: keyData, cert_chain: pemData}]); - -const hostOverride = 'foo.test.google.fr'; -const clientOptions = { - 'grpc.ssl_target_name_override': hostOverride, - 'grpc.default_authority': hostOverride -} - -describe('Sending metadata', function() { - let server; - before(function(done) { - server = new serverGrpc.Server(); - server.addService(TestService, { - unary: function(call, cb) { - cb(null, {}); - }, - clientStream: function(stream, cb){ - stream.on('data', function(data) {}); - stream.on('end', function() { - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.end(); - }); - } - }); - server.bindAsync('localhost:0', serverCreds, (err, port) => { - assert.ifError(err); - server.start(); - client = new TestServiceClient(`localhost:${port}`, combinedClientCreds, clientOptions); - done(); - }); - }); - after(function() { - server.forceShutdown(); - }); - it('Should be able to send the same metadata on two calls with call creds', function(done) { - const metadata = new clientGrpc.Metadata(); - client.unary({}, metadata, (err, data) => { - assert.ifError(err); - client.unary({}, metadata, (err, data) => { - assert.ifError(err); - done(); - }); - }); - }); -}); From d5931ad232aa0819e575d772f8abcc489a408979 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 10:26:36 -0700 Subject: [PATCH 0813/1899] grpc-js: pick first: resolve address again after trying all addresses --- packages/grpc-js/src/load-balancer-pick-first.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index a764a2208..826938077 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -343,15 +343,20 @@ export class PickFirstLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig | null ): void { // lbConfig has no useful information for pick first load balancing - this.latestAddressList = addressList; - this.connectToAddressList(); + /* To avoid unnecessary churn, we only do something with this address list + * if we're not currently trying to establish a connection, or if the new + * address list is different from the existing one */ + if (this.subchannels.length === 0 || !this.latestAddressList.every((value, index) => addressList[index] === value)) { + this.latestAddressList = addressList; + this.connectToAddressList(); + } } exitIdle() { for (const subchannel of this.subchannels) { subchannel.startConnecting(); } - if (this.currentState === ConnectivityState.IDLE) { + if (this.currentState === ConnectivityState.IDLE || this.triedAllSubchannels) { this.channelControlHelper.requestReresolution(); if (this.latestAddressList.length > 0) { this.connectToAddressList(); From 4250ac66850cc7152ea7e84208d7f84744da618c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 10:34:19 -0700 Subject: [PATCH 0814/1899] Bump grpc-js to 0.6.8 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 32f46cedb..df8599e0b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.7", + "version": "0.6.8", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 2c4798e3d6870ac461d3e6f036fe0dacc212f2da Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 10:48:11 -0700 Subject: [PATCH 0815/1899] Only reconnect to same address list if idle --- packages/grpc-js/src/load-balancer-pick-first.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 826938077..738bae99f 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -356,12 +356,14 @@ export class PickFirstLoadBalancer implements LoadBalancer { for (const subchannel of this.subchannels) { subchannel.startConnecting(); } - if (this.currentState === ConnectivityState.IDLE || this.triedAllSubchannels) { - this.channelControlHelper.requestReresolution(); + if (this.currentState === ConnectivityState.IDLE) { if (this.latestAddressList.length > 0) { this.connectToAddressList(); } } + if (this.currentState === ConnectivityState.IDLE || this.triedAllSubchannels) { + this.channelControlHelper.requestReresolution(); + } } resetBackoff() { From 327eecce3cd097b2aa8340a45178033684864bb8 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 12:45:07 -0700 Subject: [PATCH 0816/1899] grpc-js: Fix handling of established connection drops in subchannel --- packages/grpc-js/src/subchannel.ts | 56 ++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index cbf517cb0..9a207a5f9 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -242,32 +242,50 @@ export class Subchannel { connectionOptions.servername = getDefaultAuthority(this.channelTarget); } } - this.session = http2.connect( + const session = http2.connect( addressScheme + this.subchannelAddress, connectionOptions ); - this.session.unref(); - this.session.once('connect', () => { - this.transitionToState( - [ConnectivityState.CONNECTING], - ConnectivityState.READY - ); + this.session = session; + session.unref(); + /* For all of these events, check if the session at the time of the event + * is the same one currently attached to this subchannel, to ensure that + * old events from previous connection attempts cannot cause invalid state + * transitions. */ + session.once('connect', () => { + if (this.session === session) { + this.transitionToState( + [ConnectivityState.CONNECTING], + ConnectivityState.READY + ); + } }); - this.session.once('close', () => { - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE - ); + session.once('close', () => { + if (this.session === session) { + this.transitionToState( + [ConnectivityState.CONNECTING], + ConnectivityState.TRANSIENT_FAILURE + ); + /* Transitioning directly to IDLE here should be OK because we are not + * doing any backoff, because a connection was established at some + * point */ + this.transitionToState( + [ConnectivityState.READY], + ConnectivityState.IDLE + ); + } }); - this.session.once('goaway', () => { - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.IDLE - ); + session.once('goaway', () => { + if (this.session === session) { + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.IDLE + ); + } }); - this.session.once('error', error => { + session.once('error', error => { /* Do nothing here. Any error should also trigger a close event, which is - * where we want to handle that. */ + * where we want to handle that. */ }); } From e7ca0da40975078e5bed916e0e490b3a3dcbb9a9 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 14:47:10 -0700 Subject: [PATCH 0817/1899] Specify client and server implementation in test description --- test/any_grpc.js | 4 +- test/api/connectivity_test.js | 108 ++-- test/api/error_test.js | 884 ++++++++++++++++---------------- test/api/interop_extra_test.js | 128 ++--- test/api/interop_sanity_test.js | 104 ++-- 5 files changed, 619 insertions(+), 609 deletions(-) diff --git a/test/any_grpc.js b/test/any_grpc.js index 59962d590..0c86321fe 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -41,5 +41,7 @@ const serverImpl = getImplementation('_server_implementation'); module.exports = { client: clientImpl, - server: serverImpl + server: serverImpl, + clientName: global._client_implementation, + serverName: global._server_implementation }; diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 622c96d7c..042c136b7 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -58,64 +58,66 @@ const serviceImpl = { } }; -describe('Reconnection', function() { - let server1; - let server2; - let port; - before(function(done) { - server1 = new serverGrpc.Server(); - server1.addService(TestService, serviceImpl); - server2 = new serverGrpc.Server(); - server2.addService(TestService, serviceImpl); - server1.bindAsync('localhost:0', serverCreds, (err, _port) => { - assert.ifError(err); - server1.start(); - port = _port; - client = new TestServiceClient(`localhost:${port}`, clientCreds); - done(); - }); - }); - after(function() { - client.close(); - server1.forceShutdown(); - server2.forceShutdown(); - }); - it.skip('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { - this.timeout(10000); - let pendingCalls = 0; - let testDone = false; - let callInterval; - function maybeDone() { - if (testDone && pendingCalls === 0) { +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Reconnection', function() { + let server1; + let server2; + let port; + before(function(done) { + server1 = new serverGrpc.Server(); + server1.addService(TestService, serviceImpl); + server2 = new serverGrpc.Server(); + server2.addService(TestService, serviceImpl); + server1.bindAsync('localhost:0', serverCreds, (err, _port) => { + assert.ifError(err); + server1.start(); + port = _port; + client = new TestServiceClient(`localhost:${port}`, clientCreds); done(); - } - }; - client.unary({}, (err, data) => { - assert.ifError(err); - server1.tryShutdown(() => { - server2.bindAsync(`localhost:${port}`, serverCreds, (err) => { - assert.ifError(err); - server2.start(); - const metadata = new clientGrpc.Metadata({ waitForReady: true }); - client.unary({}, metadata, (err, data) => { + }); + }); + after(function() { + client.close(); + server1.forceShutdown(); + server2.forceShutdown(); + }); + it.skip('Should end with either OK or UNAVAILABLE when querying a server that is shutting down', function(done) { + this.timeout(10000); + let pendingCalls = 0; + let testDone = false; + let callInterval; + function maybeDone() { + if (testDone && pendingCalls === 0) { + done(); + } + }; + client.unary({}, (err, data) => { + assert.ifError(err); + server1.tryShutdown(() => { + server2.bindAsync(`localhost:${port}`, serverCreds, (err) => { assert.ifError(err); - clearInterval(callInterval); - testDone = true; - maybeDone(); + server2.start(); + const metadata = new clientGrpc.Metadata({ waitForReady: true }); + client.unary({}, metadata, (err, data) => { + assert.ifError(err); + clearInterval(callInterval); + testDone = true; + maybeDone(); + }); }); }); + callInterval = setInterval(() => { + assert.strictEqual(testDone, false); + pendingCalls += 1; + client.unary({}, (err, data) => { + pendingCalls -= 1; + if (err) { + assert.strictEqual(err.code, clientGrpc.status.UNAVAILABLE); + } + maybeDone(); + }); + }, 0); }); - callInterval = setInterval(() => { - assert.strictEqual(testDone, false); - pendingCalls += 1; - client.unary({}, (err, data) => { - pendingCalls -= 1; - if (err) { - assert.strictEqual(err.code, clientGrpc.status.UNAVAILABLE); - } - maybeDone(); - }); - }, 0); }); }); }); diff --git a/test/api/error_test.js b/test/api/error_test.js index 8c07c6627..23a8d0d8c 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -33,524 +33,526 @@ const TestServiceClient = clientGrpc.loadPackageDefinition(testServiceDef).TestS const clientInsecureCreds = clientGrpc.credentials.createInsecure(); const serverInsecureCreds = serverGrpc.ServerCredentials.createInsecure(); -describe('Client malformed response handling', function() { - var server; - var client; - var badArg = Buffer.from([0xFF]); - before(function(done) { - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: _.identity - } - }; - server = new serverGrpc.Server(); - server.addService(malformed_test_service, { - unary: function(call, cb) { - cb(null, badArg); - }, - clientStream: function(stream, cb) { - stream.on('data', function() {/* Ignore requests */}); - stream.on('end', function() { - cb(null, badArg); - }); - }, - serverStream: function(stream) { - stream.write(badArg); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write(badArg); - }); - stream.on('end', function() { - stream.end(); - }); - } - }); - server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { - assert.ifError(err); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); - done(); - }); - }); - after(function() { - server.forceShutdown(); - }); - it('should get an INTERNAL status with a unary call', function(done) { - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - it('should get an INTERNAL status with a server stream call', function(done) { - var call = client.serverStream({}); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a bidi stream call', function(done) { - var call = client.bidiStream(); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - }); - describe('Server serialization failure handling', function() { - function serializeFail(obj) { - throw new Error('Serialization failed'); - } - var client; - var server; - before(function(done) { - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: serializeFail - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: _.identity, - responseSerialize: serializeFail - } - }; - server = new serverGrpc.Server(); - server.addService(malformed_test_service, { - unary: function(call, cb) { - cb(null, {}); - }, - clientStream: function(stream, cb) { - stream.on('data', function() {/* Ignore requests */}); - stream.on('end', function() { - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.write({}); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write({}); - }); - stream.on('end', function() { - stream.end(); - }); - } - }); - server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { - assert.ifError(err); - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); - done(); - }); - }); - after(function() { - server.forceShutdown(); - }); - it('should get an INTERNAL status with a unary call', function(done) { - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - it('should get an INTERNAL status with a server stream call', function(done) { - var call = client.serverStream({}); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a bidi stream call', function(done) { - var call = client.bidiStream(); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, clientGrpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - }); - describe('Other conditions', function() { - var Client; - var client; - var server; - var port; - before(function(done) { - server = new serverGrpc.Server(); - var trailer_metadata = new serverGrpc.Metadata(); - trailer_metadata.add('trailer-present', 'yes'); - server.addService(TestServiceClient.service, { - unary: function(call, cb) { - var req = call.request; - if (req.error) { - var message = 'Requested error'; - if (req.message) { - message = req.message; - } - cb({code: serverGrpc.status.UNKNOWN, - details: message}, null, trailer_metadata); - } else { - cb(null, {count: 1}, trailer_metadata); - } - }, - clientStream: function(stream, cb){ - var count = 0; - var errored; - stream.on('data', function(data) { - if (data.error) { - var message = 'Requested error'; - if (data.message) { - message = data.message; - } - errored = true; - cb(new Error(message), null, trailer_metadata); - } else { - count += 1; - } - }); - stream.on('end', function() { - if (!errored) { - cb(null, {count: count}, trailer_metadata); - } - }); - }, - serverStream: function(stream) { - var req = stream.request; - if (req.error) { - var message = 'Requested error'; - if (req.message) { - message = req.message; - } - var err = {code: serverGrpc.status.UNKNOWN, - details: message}; - err.metadata = trailer_metadata; - stream.emit('error', err); - } else { - for (var i = 0; i < 5; i++) { - stream.write({count: i}); - } - stream.end(trailer_metadata); - } - }, - bidiStream: function(stream) { - var count = 0; - stream.on('data', function(data) { - if (data.error) { - var message = 'Requested error'; - if (data.message) { - message = data.message; - } - var err = new Error(message); - err.metadata = trailer_metadata.clone(); - err.metadata.add('count', '' + count); - stream.emit('error', err); - } else { - stream.write({count: count}); - count += 1; - } - }); - stream.on('end', function() { - stream.end(trailer_metadata); - }); - } - }); - server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { - assert.ifError(err); - port = _port; - client = new TestServiceClient('localhost:' + port, clientInsecureCreds); - server.start(); - done(); - }); - }); - after(function() { - server.forceShutdown(); - }); - describe('Server recieving bad input', function() { - var misbehavingClient; +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Client malformed response handling', function() { + var server; + var client; var badArg = Buffer.from([0xFF]); - before(function() { - var test_service_attrs = { + before(function(done) { + var malformed_test_service = { unary: { path: '/TestService/Unary', requestStream: false, responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity }, clientStream: { path: '/TestService/ClientStream', requestStream: true, responseStream: false, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity }, serverStream: { path: '/TestService/ServerStream', requestStream: false, responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity }, bidiStream: { path: '/TestService/BidiStream', requestStream: true, responseStream: true, - requestSerialize: _.identity, - responseDeserialize: _.identity + requestDeserialize: _.identity, + responseSerialize: _.identity } }; - var Client = clientGrpc.makeGenericClientConstructor(test_service_attrs, - 'TestService'); - misbehavingClient = new Client('localhost:' + port, clientInsecureCreds); + server = new serverGrpc.Server(); + server.addService(malformed_test_service, { + unary: function(call, cb) { + cb(null, badArg); + }, + clientStream: function(stream, cb) { + stream.on('data', function() {/* Ignore requests */}); + stream.on('end', function() { + cb(null, badArg); + }); + }, + serverStream: function(stream) { + stream.write(badArg); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write(badArg); + }); + stream.on('end', function() { + stream.end(); + }); + } + }); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + done(); + }); + }); + after(function() { + server.forceShutdown(); }); - it('should respond correctly to a unary call', function(done) { - misbehavingClient.unary(badArg, function(err, data) { + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { assert(err); assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); }); - it('should respond correctly to a client stream', function(done) { - var call = misbehavingClient.clientStream(function(err, data) { + it('should get an INTERNAL status with a client stream call', function(done) { + var call = client.clientStream(function(err, data) { assert(err); assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); - call.write(badArg); - // TODO(mlumish): Remove call.end() + call.write({}); call.end(); }); - it('should respond correctly to a server stream', function(done) { - var call = misbehavingClient.serverStream(badArg); - call.on('data', function(data) { - assert.fail(data, null, 'Unexpected data', '==='); - }); + it('should get an INTERNAL status with a server stream call', function(done) { + var call = client.serverStream({}); + call.on('data', function(){}); call.on('error', function(err) { assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); }); - it('should respond correctly to a bidi stream', function(done) { - var call = misbehavingClient.bidiStream(); - call.on('data', function(data) { - assert.fail(data, null, 'Unexpected data', '==='); - }); + it('should get an INTERNAL status with a bidi stream call', function(done) { + var call = client.bidiStream(); + call.on('data', function(){}); call.on('error', function(err) { assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); - call.write(badArg); - // TODO(mlumish): Remove call.end() + call.write({}); call.end(); }); }); - describe('Trailing metadata', function() { - it('should be present when a unary call succeeds', function(done) { - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); + describe('Server serialization failure handling', function() { + function serializeFail(obj) { + throw new Error('Serialization failed'); + } + var client; + var server; + before(function(done) { + var malformed_test_service = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestDeserialize: _.identity, + responseSerialize: serializeFail + } + }; + server = new serverGrpc.Server(); + server.addService(malformed_test_service, { + unary: function(call, cb) { + cb(null, {}); + }, + clientStream: function(stream, cb) { + stream.on('data', function() {/* Ignore requests */}); + stream.on('end', function() { + cb(null, {}); + }); + }, + serverStream: function(stream) { + stream.write({}); + stream.end(); + }, + bidiStream: function(stream) { + stream.on('data', function() { + // Ignore requests + stream.write({}); + }); + stream.on('end', function() { + stream.end(); + }); + } }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + server.bindAsync('localhost:0', serverInsecureCreds, (err, port) => { + assert.ifError(err); + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); done(); }); }); - it('should be present when a unary call fails', function(done) { - var call = client.unary({error: true}, function(err, data) { - assert(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); + after(function() { + server.forceShutdown(); }); - it('should be present when a client stream call succeeds', function(done) { - var call = client.clientStream(function(err, data) { - assert.ifError(err); - }); - call.write({error: false}); - call.write({error: false}); - call.end(); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + it('should get an INTERNAL status with a unary call', function(done) { + client.unary({}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); }); - it('should be present when a client stream call fails', function(done) { + it('should get an INTERNAL status with a client stream call', function(done) { var call = client.clientStream(function(err, data) { assert(err); - }); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a server stream call succeeds', function(done) { - var call = client.serverStream({error: false}); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, clientGrpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); + call.write({}); + call.end(); }); - it('should be present when a server stream call fails', function(done) { - var call = client.serverStream({error: true}); + it('should get an INTERNAL status with a server stream call', function(done) { + var call = client.serverStream({}); call.on('data', function(){}); - call.on('error', function(error) { - assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); }); - it('should be present when a bidi stream succeeds', function(done) { + it('should get an INTERNAL status with a bidi stream call', function(done) { var call = client.bidiStream(); - call.write({error: false}); - call.write({error: false}); - call.end(); call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, clientGrpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); done(); }); - }); - it('should be present when a bidi stream fails', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); + call.write({}); call.end(); - call.on('data', function(){}); - call.on('error', function(error) { - assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); - done(); - }); }); }); - describe('Error object should contain the status', function() { - it('for a unary call', function(done) { - client.unary({error: true}, function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); - assert.strictEqual(err.details, 'Requested error'); - done(); + describe('Other conditions', function() { + var Client; + var client; + var server; + var port; + before(function(done) { + server = new serverGrpc.Server(); + var trailer_metadata = new serverGrpc.Metadata(); + trailer_metadata.add('trailer-present', 'yes'); + server.addService(TestServiceClient.service, { + unary: function(call, cb) { + var req = call.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + cb({code: serverGrpc.status.UNKNOWN, + details: message}, null, trailer_metadata); + } else { + cb(null, {count: 1}, trailer_metadata); + } + }, + clientStream: function(stream, cb){ + var count = 0; + var errored; + stream.on('data', function(data) { + if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + errored = true; + cb(new Error(message), null, trailer_metadata); + } else { + count += 1; + } + }); + stream.on('end', function() { + if (!errored) { + cb(null, {count: count}, trailer_metadata); + } + }); + }, + serverStream: function(stream) { + var req = stream.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + var err = {code: serverGrpc.status.UNKNOWN, + details: message}; + err.metadata = trailer_metadata; + stream.emit('error', err); + } else { + for (var i = 0; i < 5; i++) { + stream.write({count: i}); + } + stream.end(trailer_metadata); + } + }, + bidiStream: function(stream) { + var count = 0; + stream.on('data', function(data) { + if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + var err = new Error(message); + err.metadata = trailer_metadata.clone(); + err.metadata.add('count', '' + count); + stream.emit('error', err); + } else { + stream.write({count: count}); + count += 1; + } + }); + stream.on('end', function() { + stream.end(trailer_metadata); + }); + } }); - }); - it('for a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); - assert.strictEqual(err.details, 'Requested error'); + server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { + assert.ifError(err); + port = _port; + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); done(); }); - call.write({error: false}); - call.write({error: true}); - call.end(); }); - it('for a server stream call', function(done) { - var call = client.serverStream({error: true}); - call.on('data', function(){}); - call.on('error', function(error) { - assert.strictEqual(error.code, clientGrpc.status.UNKNOWN); - assert.strictEqual(error.details, 'Requested error'); - done(); + after(function() { + server.forceShutdown(); + }); + describe('Server recieving bad input', function() { + var misbehavingClient; + var badArg = Buffer.from([0xFF]); + before(function() { + var test_service_attrs = { + unary: { + path: '/TestService/Unary', + requestStream: false, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + clientStream: { + path: '/TestService/ClientStream', + requestStream: true, + responseStream: false, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + serverStream: { + path: '/TestService/ServerStream', + requestStream: false, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + }, + bidiStream: { + path: '/TestService/BidiStream', + requestStream: true, + responseStream: true, + requestSerialize: _.identity, + responseDeserialize: _.identity + } + }; + var Client = clientGrpc.makeGenericClientConstructor(test_service_attrs, + 'TestService'); + misbehavingClient = new Client('localhost:' + port, clientInsecureCreds); + }); + it('should respond correctly to a unary call', function(done) { + misbehavingClient.unary(badArg, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should respond correctly to a client stream', function(done) { + var call = misbehavingClient.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); + }); + it('should respond correctly to a server stream', function(done) { + var call = misbehavingClient.serverStream(badArg); + call.on('data', function(data) { + assert.fail(data, null, 'Unexpected data', '==='); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + }); + it('should respond correctly to a bidi stream', function(done) { + var call = misbehavingClient.bidiStream(); + call.on('data', function(data) { + assert.fail(data, null, 'Unexpected data', '==='); + }); + call.on('error', function(err) { + assert.strictEqual(err.code, clientGrpc.status.INTERNAL); + done(); + }); + call.write(badArg); + // TODO(mlumish): Remove call.end() + call.end(); }); }); - it('for a bidi stream call', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('data', function(){}); - call.on('error', function(error) { - assert.strictEqual(error.code, clientGrpc.status.UNKNOWN); - assert.strictEqual(error.details, 'Requested error'); - done(); + describe('Trailing metadata', function() { + it('should be present when a unary call succeeds', function(done) { + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a unary call fails', function(done) { + var call = client.unary({error: true}, function(err, data) { + assert(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a client stream call succeeds', function(done) { + var call = client.clientStream(function(err, data) { + assert.ifError(err); + }); + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a client stream call fails', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + }); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a server stream call succeeds', function(done) { + var call = client.serverStream({error: false}); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, clientGrpc.status.OK); + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a server stream call fails', function(done) { + var call = client.serverStream({error: true}); + call.on('data', function(){}); + call.on('error', function(error) { + assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a bidi stream succeeds', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: false}); + call.end(); + call.on('data', function(){}); + call.on('status', function(status) { + assert.strictEqual(status.code, clientGrpc.status.OK); + assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); + done(); + }); + }); + it('should be present when a bidi stream fails', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', function(){}); + call.on('error', function(error) { + assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); + done(); + }); }); }); - it('for a UTF-8 error message', function(done) { - client.unary({error: true, message: '測試字符串'}, function(err, data) { - assert(err); - assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); - assert.strictEqual(err.details, '測試字符串'); - done(); + describe('Error object should contain the status', function() { + it('for a unary call', function(done) { + client.unary({error: true}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + }); + it('for a client stream call', function(done) { + var call = client.clientStream(function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + call.write({error: false}); + call.write({error: true}); + call.end(); + }); + it('for a server stream call', function(done) { + var call = client.serverStream({error: true}); + call.on('data', function(){}); + call.on('error', function(error) { + assert.strictEqual(error.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + done(); + }); + }); + it('for a bidi stream call', function(done) { + var call = client.bidiStream(); + call.write({error: false}); + call.write({error: true}); + call.end(); + call.on('data', function(){}); + call.on('error', function(error) { + assert.strictEqual(error.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + done(); + }); + }); + it('for a UTF-8 error message', function(done) { + client.unary({error: true, message: '測試字符串'}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, '測試字符串'); + done(); + }); }); }); - }); -}); + }); +}); \ No newline at end of file diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 8a3dc52c4..d22621fe4 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -52,85 +52,87 @@ function echoMetadataGenerator(options, callback) { const credentials = grpc.credentials.createFromMetadataGenerator(echoMetadataGenerator); -describe('Interop-adjacent tests', function() { - let server; - let client; - before(function(done) { - interopServer.getServer(0, true, (err, serverObj) => { - if (err) { - done(err); - } else { - server = serverObj.server; - server.start(); - const ca_path = path.join(__dirname, '../data/ca.pem'); - const ca_data = fs.readFileSync(ca_path); - const creds = grpc.credentials.createSsl(ca_data); - const options = { - 'grpc.ssl_target_name_override': 'foo.test.google.fr', - 'grpc.default_authority': 'foo.test.google.fr' - }; - client = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); - done(); +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Interop-adjacent tests', function() { + let server; + let client; + before(function(done) { + interopServer.getServer(0, true, (err, serverObj) => { + if (err) { + done(err); + } else { + server = serverObj.server; + server.start(); + const ca_path = path.join(__dirname, '../data/ca.pem'); + const ca_data = fs.readFileSync(ca_path); + const creds = grpc.credentials.createSsl(ca_data); + const options = { + 'grpc.ssl_target_name_override': 'foo.test.google.fr', + 'grpc.default_authority': 'foo.test.google.fr' + }; + client = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + done(); + } + }); + }); + after(function() { + server.forceShutdown(); + }); + it('Should be able to start many concurrent calls', function(done) { + const callCount = 1000; + done = multiDone(done, callCount); + for (let i = 0; i < callCount; i++) { + client.unaryCall({}, (error, result) => { + assert.ifError(error); + done(); + }); } }); - }); - after(function() { - server.forceShutdown(); - }); - it('Should be able to start many concurrent calls', function(done) { - const callCount = 1000; - done = multiDone(done, callCount); - for (let i = 0; i < callCount; i++) { - client.unaryCall({}, (error, result) => { + it('Should echo metadata from call credentials', function(done) { + done = multiDone(done, 2); + const call = client.unaryCall({}, {credentials}, (error, result) => { assert.ifError(error); done(); }); - } - }); - it('Should echo metadata from call credentials', function(done) { - done = multiDone(done, 2); - const call = client.unaryCall({}, {credentials}, (error, result) => { - assert.ifError(error); - done(); - }); - call.on('metadata', (metadata) => { - assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), - ['test_initial_metadata_value']); - done(); + call.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); }); - }); - it('Should be able to send the same metadata on two calls with call creds', function(done) { - done = multiDone(done, 5); - const metadata = new grpc.Metadata(); - metadata.set('x-grpc-test-echo-trailing-bin', Buffer.from('ababab', 'hex')); - const call1 = client.unaryCall({}, metadata, {credentials}, (error, result) => { - assert.ifError(error); - const call2 = client.unaryCall({}, metadata, {credentials}, (error, result) => { + it('Should be able to send the same metadata on two calls with call creds', function(done) { + done = multiDone(done, 5); + const metadata = new grpc.Metadata(); + metadata.set('x-grpc-test-echo-trailing-bin', Buffer.from('ababab', 'hex')); + const call1 = client.unaryCall({}, metadata, {credentials}, (error, result) => { assert.ifError(error); - done(); + const call2 = client.unaryCall({}, metadata, {credentials}, (error, result) => { + assert.ifError(error); + done(); + }); + call2.on('metadata', (metadata) => { + assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), + ['test_initial_metadata_value']); + done(); + }); + call2.on('status', function(status) { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); + done(); + }); }); - call2.on('metadata', (metadata) => { + call1.on('metadata', (metadata) => { assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), - ['test_initial_metadata_value']); + ['test_initial_metadata_value']); done(); }); - call2.on('status', function(status) { + call1.on('status', function(status) { var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); assert(echo_trailer.length === 1); assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); done(); }); }); - call1.on('metadata', (metadata) => { - assert.deepEqual(metadata.get('x-grpc-test-echo-initial'), - ['test_initial_metadata_value']); - done(); - }); - call1.on('status', function(status) { - var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); - assert(echo_trailer.length === 1); - assert.strictEqual(echo_trailer[0].toString('hex'), 'ababab'); - done(); - }); }); }); \ No newline at end of file diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 27441e964..14d6fda17 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -45,60 +45,62 @@ const testCases = [ var childExecArgv = []; -describe('Interop tests', function() { - this.timeout(4000); - before(function(done) { - for (let arg of process.argv) { - if (arg.startsWith('--require=')) { - childExecArgv.push('--require'); - childExecArgv.push(arg.substring('--require='.length)); +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Interop tests', function() { + this.timeout(4000); + before(function(done) { + for (let arg of process.argv) { + if (arg.startsWith('--require=')) { + childExecArgv.push('--require'); + childExecArgv.push(arg.substring('--require='.length)); + } } + serverProcess = childProcess.fork(`${__dirname}/interop_helper/server.js`, { + execArgv: childExecArgv + }); + serverProcess.on('message', (message) => { + port = message.port; + done(); + }); + serverProcess.on('exit', (code, signal) => { + if (code !== 0) { + if (code !== null) { + throw new Error(`Server exited with error code ${code}`); + } else { + throw new Error(`Server exited with signal ${signal}`); } - serverProcess = childProcess.fork(`${__dirname}/interop_helper/server.js`, { - execArgv: childExecArgv + } + }); }); - serverProcess.on('message', (message) => { - port = message.port; - done(); + after(function() { + serverProcess.send({}); }); - serverProcess.on('exit', (code, signal) => { - if (code !== 0) { - if (code !== null) { - throw new Error(`Server exited with error code ${code}`); - } else { - throw new Error(`Server exited with signal ${signal}`); - } + for (let testName of testCases) { + it(`should pass ${testName}`, function(done) { + /* We need to run a client process per test to most closely match + * how the main interop test suite works */ + let clientProcess = childProcess.fork(`${__dirname}/../interop/interop_client`, [ + '--server_host=localhost', + `--server_port=${port}`, + `--server_host_override=${name_override}`, + `--test_case=${testName}`, + '--use_tls=true', + '--use_test_ca=true' + ], { + execArgv: childExecArgv + }); + clientProcess.on('exit', (code, signal) => { + if (code === 0) { + done(); + } else { + if (code !== null) { + done(new Error(`Client exited with error code ${code}`)); + } else { + done(new Error(`Client exited with signal ${signal}`)); } - }); - }); - after(function() { - serverProcess.send({}); - }); - for (let testName of testCases) { - it(`should pass ${testName}`, function(done) { - /* We need to run a client process per test to most closely match - * how the main interop test suite works */ - let clientProcess = childProcess.fork(`${__dirname}/../interop/interop_client`, [ - '--server_host=localhost', - `--server_port=${port}`, - `--server_host_override=${name_override}`, - `--test_case=${testName}`, - '--use_tls=true', - '--use_test_ca=true' - ], { - execArgv: childExecArgv - }); - clientProcess.on('exit', (code, signal) => { - if (code === 0) { - done(); - } else { - if (code !== null) { - done(new Error(`Client exited with error code ${code}`)); - } else { - done(new Error(`Client exited with signal ${signal}`)); - } - } + } + }); }); - }); - } -}); + } + }); +}); \ No newline at end of file From 86d6291925b278efcc4bee91554e95d552d63b2e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 14:48:14 -0700 Subject: [PATCH 0818/1899] 1000 concurrent calls is excessive --- test/api/interop_extra_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index d22621fe4..a4cf98750 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -79,7 +79,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio server.forceShutdown(); }); it('Should be able to start many concurrent calls', function(done) { - const callCount = 1000; + const callCount = 100; done = multiDone(done, callCount); for (let i = 0; i < callCount; i++) { client.unaryCall({}, (error, result) => { From 8a212ba2d943e2f35e5bc471328d20a0e2ac19c5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 10 Oct 2019 15:01:28 -0700 Subject: [PATCH 0819/1899] Fix a couple of references in test files --- test/api/interop_extra_test.js | 3 ++- test/api/interop_sanity_test.js | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index a4cf98750..d0df38e3c 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -22,7 +22,8 @@ const assert = require('assert'); const fs = require('fs'); const path = require('path'); const interopServer = require('../interop/interop_server.js'); -const grpc = require('../any_grpc').client; +const anyGrpc = require('../any_grpc'); +const grpc = anyGrpc.client; var protoLoader = require('../../packages/proto-loader'); const protoPackage = protoLoader.loadSync( diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 14d6fda17..995650e20 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -19,6 +19,7 @@ 'use strict'; var childProcess = require('child_process'); +const anyGrpc = require('../any_grpc'); var port; From d362ccb3f683ff7e47e3c6990affdc730590d86b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 11 Oct 2019 12:49:39 -0700 Subject: [PATCH 0820/1899] grpc-js: Some fixes for how idleness and reresolution are handled --- packages/grpc-js/package.json | 2 +- .../grpc-js/src/load-balancer-pick-first.ts | 35 ++++++--- .../grpc-js/src/resolving-load-balancer.ts | 73 +++++++++++++++---- 3 files changed, 85 insertions(+), 25 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index df8599e0b..4ec6349c2 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.8", + "version": "0.6.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 738bae99f..dfa9d78a7 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -152,6 +152,12 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.pickSubchannel(subchannel); return; } else { + if (this.triedAllSubchannels && this.subchannelStateCounts[ConnectivityState.IDLE] === this.subchannels.length) { + /* If all of the subchannels are IDLE we should go back to a + * basic IDLE state where there is no subchannel list to avoid + * holding unused resources */ + this.resetSubchannelList(); + } if (this.currentPick === null) { if (this.triedAllSubchannels) { let newLBState: ConnectivityState; @@ -190,18 +196,25 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.pickedSubchannelStateListener ); if (this.subchannels.length > 0) { - let newLBState: ConnectivityState; - if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { - newLBState = ConnectivityState.CONNECTING; - } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { - newLBState = ConnectivityState.TRANSIENT_FAILURE; - } else { - newLBState = ConnectivityState.IDLE; - } - if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { - this.updateState(newLBState, new UnavailablePicker()); + if (this.triedAllSubchannels) { + let newLBState: ConnectivityState; + if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { + newLBState = ConnectivityState.CONNECTING; + } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { + newLBState = ConnectivityState.TRANSIENT_FAILURE; + } else { + newLBState = ConnectivityState.IDLE; + } + if (newLBState === ConnectivityState.TRANSIENT_FAILURE) { + this.updateState(newLBState, new UnavailablePicker()); + } else { + this.updateState(newLBState, new QueuePicker(this)); + } } else { - this.updateState(newLBState, new QueuePicker(this)); + this.updateState( + ConnectivityState.CONNECTING, + new QueuePicker(this) + ); } } else { /* We don't need to backoff here because this only happens if a diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index f66801151..838353a90 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -77,6 +77,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { */ private innerBalancerState: ConnectivityState = ConnectivityState.IDLE; + private innerBalancerPicker: Picker = new UnavailablePicker(); + /** * The most recent reported state of the pendingReplacementLoadBalancer. * Starts at IDLE for type simplicity. This should get updated as soon as the @@ -104,6 +106,12 @@ export class ResolvingLoadBalancer implements LoadBalancer { */ private readonly backoffTimeout: BackoffTimeout; + /** + * Indicates whether we should attempt to resolve again after the backoff + * timer runs out. + */ + private continueResolving = false; + /** * Wrapper class that behaves like a `LoadBalancer` and also handles name * resolution internally. @@ -245,12 +253,22 @@ export class ResolvingLoadBalancer implements LoadBalancer { }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.innerBalancerState = connectivityState; + if (connectivityState === ConnectivityState.IDLE) { + picker = new QueuePicker(this); + } + this.innerBalancerPicker = picker; if ( connectivityState !== ConnectivityState.READY && this.pendingReplacementLoadBalancer !== null ) { this.switchOverReplacementBalancer(); } else { + if (connectivityState === ConnectivityState.IDLE) { + if (this.innerLoadBalancer) { + this.innerLoadBalancer.destroy(); + this.innerLoadBalancer = null; + } + } this.updateState(connectivityState, picker); } }, @@ -260,8 +278,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { * making resolve requests, so we shouldn't make another one here. * In that case, the backoff timer callback will call * updateResolution */ - if (!this.backoffTimeout.isRunning()) { - this.innerResolver.updateResolution(); + if (this.backoffTimeout.isRunning()) { + this.continueResolving = true; + } else { + this.updateResolution(); } } }, @@ -278,32 +298,54 @@ export class ResolvingLoadBalancer implements LoadBalancer { ); }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { + if (connectivityState === ConnectivityState.IDLE) { + picker = new QueuePicker(this); + } this.replacementBalancerState = connectivityState; this.replacementBalancerPicker = picker; if (connectivityState === ConnectivityState.READY) { this.switchOverReplacementBalancer(); + } else if (connectivityState === ConnectivityState.IDLE) { + if (this.pendingReplacementLoadBalancer) { + this.pendingReplacementLoadBalancer.destroy(); + this.pendingReplacementLoadBalancer = null; + } } }, requestReresolution: () => { - if (!this.backoffTimeout.isRunning()) { - /* If the backoffTimeout is running, we're still backing off from - * making resolve requests, so we shouldn't make another one here. - * In that case, the backoff timer callback will call - * updateResolution */ - this.innerResolver.updateResolution(); + /* If the backoffTimeout is running, we're still backing off from + * making resolve requests, so we shouldn't make another one here. + * In that case, the backoff timer callback will call + * updateResolution */ + if (this.backoffTimeout.isRunning()) { + this.continueResolving = true; + } else { + this.updateResolution(); } }, }; this.backoffTimeout = new BackoffTimeout(() => { - if (this.innerLoadBalancer === null) { - this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + if (this.continueResolving) { + this.updateResolution(); + this.continueResolving = false; } else { - this.innerResolver.updateResolution(); + if (this.innerLoadBalancer === null) { + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + } else { + this.updateState(this.innerBalancerState, this.innerBalancerPicker); + } } }); } + private updateResolution() { + this.innerResolver.updateResolution(); + if (this.innerLoadBalancer === null || this.innerBalancerState === ConnectivityState.IDLE) { + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + } + } + private updateState(connectivitystate: ConnectivityState, picker: Picker) { trace(this.target + ' ' + ConnectivityState[this.currentState] + ' -> ' + ConnectivityState[connectivitystate]); this.currentState = connectivitystate; @@ -323,6 +365,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { ); this.pendingReplacementLoadBalancer = null; this.innerBalancerState = this.replacementBalancerState; + this.innerBalancerPicker = this.replacementBalancerPicker; this.updateState( this.replacementBalancerState, this.replacementBalancerPicker @@ -330,7 +373,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } private handleResolutionFailure(error: StatusObject) { - if (this.innerLoadBalancer === null) { + if (this.innerLoadBalancer === null || this.innerBalancerState === ConnectivityState.IDLE) { this.updateState( ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error) @@ -344,7 +387,11 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.innerLoadBalancer.exitIdle(); } if (this.currentState === ConnectivityState.IDLE) { - this.innerResolver.updateResolution(); + if (this.backoffTimeout.isRunning()) { + this.continueResolving = true; + } else { + this.updateResolution(); + } this.updateState( ConnectivityState.CONNECTING, new QueuePicker(this) From 029ecbe9b88c1aec1c8d2bbc82d23a04cc93825b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 21 Oct 2019 11:09:50 -0700 Subject: [PATCH 0821/1899] Bump submodule and version --- packages/grpc-native-core/binding.gyp | 2 +- packages/grpc-native-core/build.yaml | 1 + packages/grpc-native-core/deps/grpc | 2 +- packages/grpc-native-core/package.json | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp index 0c8148498..87dba780e 100644 --- a/packages/grpc-native-core/binding.gyp +++ b/packages/grpc-native-core/binding.gyp @@ -91,7 +91,7 @@ 'GPR_BACKWARDS_COMPATIBILITY_MODE', 'GRPC_ARES=1', 'GRPC_UV', - 'GRPC_NODE_VERSION="1.24.0"', + 'GRPC_NODE_VERSION="1.24.1"', 'CARES_STATICLIB', 'CARES_SYMBOL_HIDING' ], diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml index 49e36fdfe..52394dc8a 100644 --- a/packages/grpc-native-core/build.yaml +++ b/packages/grpc-native-core/build.yaml @@ -1,2 +1,3 @@ settings: '#': It's possible to have node_version here as a key to override the core's version. + node_version: 1.24.1 \ No newline at end of file diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index 16fba7baa..85e22ef28 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit 16fba7baa0a35d9028f1cd9827c907be7d97269e +Subproject commit 85e22ef28d55f27e8efb3d5e2e43ca6f59971065 diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index e41e46b2f..63ce5cc8c 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -1,6 +1,6 @@ { "name": "grpc", - "version": "1.24.0", + "version": "1.24.1", "author": "Google Inc.", "description": "gRPC Library for Node", "homepage": "https://grpc.io/", From caa07ef8833c2dd5767b544d8b39532c8d255a12 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 21 Oct 2019 18:04:17 -0700 Subject: [PATCH 0822/1899] Make some filter types synchronous --- packages/grpc-js/src/call-stream.ts | 72 +++++++------------ packages/grpc-js/src/compression-filter.ts | 11 ++- packages/grpc-js/src/filter-stack.ts | 8 +-- packages/grpc-js/src/filter.ts | 10 +-- .../grpc-js/src/metadata-status-filter.ts | 4 +- 5 files changed, 40 insertions(+), 65 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index a53dbefa8..645e9865b 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -103,13 +103,6 @@ export class Http2CallStream extends Duplex implements Call { // Status code mapped from :status. To be used if grpc-status is not received private mappedStatusCode: Status = Status.UNKNOWN; - // Promise objects that are re-assigned to resolving promises when headers - // or trailers received. Processing headers/trailers is asynchronous, so we - // can use these objects to await their completion. This helps us establish - // order of precedence when obtaining the status of the call. - private handlingHeaders = Promise.resolve(); - private handlingTrailers = Promise.resolve(); - // This is populated (non-null) if and only if the call has ended private finalStatus: StatusObject | null = null; @@ -224,30 +217,21 @@ export class Http2CallStream extends Duplex implements Call { metadata = new Metadata(); } const status: StatusObject = { code, details, metadata }; - this.handlingTrailers = (async () => { - let finalStatus; - try { - // Attempt to assign final status. - finalStatus = await this.filterStack.receiveTrailers( - Promise.resolve(status) - ); - } catch (error) { - await this.handlingHeaders; - // This is a no-op if the call was already ended when handling headers. - this.endCall({ - code: Status.INTERNAL, - details: 'Failed to process received status', - metadata: new Metadata(), - }); - return; - } - // It's possible that headers were received but not fully handled yet. - // Give the headers handler an opportunity to end the call first, - // if an error occurred. - await this.handlingHeaders; + let finalStatus; + try { + // Attempt to assign final status. + finalStatus = this.filterStack.receiveTrailers(status); + } catch (error) { // This is a no-op if the call was already ended when handling headers. - this.endCall(finalStatus); - })(); + this.endCall({ + code: Status.INTERNAL, + details: 'Failed to process received status', + metadata: new Metadata(), + }); + return; + } + // This is a no-op if the call was already ended when handling headers. + this.endCall(finalStatus); } attachHttp2Stream(stream: http2.ClientHttp2Stream, subchannel: Subchannel): void { @@ -297,19 +281,17 @@ export class Http2CallStream extends Duplex implements Call { }); return; } - this.handlingHeaders = this.filterStack - .receiveMetadata(Promise.resolve(metadata)) - .then(finalMetadata => { - this.emit('metadata', finalMetadata); - }) - .catch(error => { - this.destroyHttp2Stream(); - this.endCall({ - code: Status.UNKNOWN, - details: error.message, - metadata: new Metadata(), - }); + try { + const finalMetadata = this.filterStack.receiveMetadata(metadata); + this.emit('metadata', finalMetadata); + } catch (error) { + this.destroyHttp2Stream(); + this.endCall({ + code: Status.UNKNOWN, + details: error.message, + metadata: new Metadata(), }); + } } }); stream.on('trailers', this.handleTrailers.bind(this)); @@ -346,9 +328,6 @@ export class Http2CallStream extends Duplex implements Call { default: code = Status.INTERNAL; } - // This guarantees that if trailers were received, the value of the - // 'grpc-status' header takes precedence for emitted status data. - await this.handlingTrailers; // This is a no-op if trailers were received at all. // This is OK, because status codes emitted here correspond to more // catastrophic issues that prevent us from receiving trailers in the @@ -392,9 +371,6 @@ export class Http2CallStream extends Duplex implements Call { cancelWithStatus(status: Status, details: string): void { this.destroyHttp2Stream(); (async () => { - // If trailers are currently being processed, the call should be ended - // by handleTrailers instead. - await this.handlingTrailers; this.endCall({ code: status, details, metadata: new Metadata() }); })(); } diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 34b7574fb..b03a7d060 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -176,18 +176,17 @@ export class CompressionFilter extends BaseFilter implements Filter { return headers; } - async receiveMetadata(metadata: Promise): Promise { - const headers: Metadata = await metadata; - const receiveEncoding: MetadataValue[] = headers.get('grpc-encoding'); + receiveMetadata(metadata: Metadata): Metadata { + const receiveEncoding: MetadataValue[] = metadata.get('grpc-encoding'); if (receiveEncoding.length > 0) { const encoding: MetadataValue = receiveEncoding[0]; if (typeof encoding === 'string') { this.receiveCompression = getCompressionHandler(encoding); } } - headers.remove('grpc-encoding'); - headers.remove('grpc-accept-encoding'); - return headers; + metadata.remove('grpc-encoding'); + metadata.remove('grpc-accept-encoding'); + return metadata; } async sendMessage(message: Promise): Promise { diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index a15dcf432..3b6f16ba4 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -32,8 +32,8 @@ export class FilterStack implements Filter { return result; } - receiveMetadata(metadata: Promise) { - let result: Promise = metadata; + receiveMetadata(metadata: Metadata) { + let result: Metadata = metadata; for (let i = this.filters.length - 1; i >= 0; i--) { result = this.filters[i].receiveMetadata(result); @@ -62,8 +62,8 @@ export class FilterStack implements Filter { return result; } - receiveTrailers(status: Promise): Promise { - let result: Promise = status; + receiveTrailers(status: StatusObject): StatusObject { + let result: StatusObject = status; for (let i = this.filters.length - 1; i >= 0; i--) { result = this.filters[i].receiveTrailers(result); diff --git a/packages/grpc-js/src/filter.ts b/packages/grpc-js/src/filter.ts index 9d437a674..c1e412ae5 100644 --- a/packages/grpc-js/src/filter.ts +++ b/packages/grpc-js/src/filter.ts @@ -25,21 +25,21 @@ import { Metadata } from './metadata'; export interface Filter { sendMetadata(metadata: Promise): Promise; - receiveMetadata(metadata: Promise): Promise; + receiveMetadata(metadata: Metadata): Metadata; sendMessage(message: Promise): Promise; receiveMessage(message: Promise): Promise; - receiveTrailers(status: Promise): Promise; + receiveTrailers(status: StatusObject): StatusObject; } -export abstract class BaseFilter { +export abstract class BaseFilter implements Filter { async sendMetadata(metadata: Promise): Promise { return metadata; } - async receiveMetadata(metadata: Promise): Promise { + receiveMetadata(metadata: Metadata): Metadata { return metadata; } @@ -51,7 +51,7 @@ export abstract class BaseFilter { return message; } - async receiveTrailers(status: Promise): Promise { + receiveTrailers(status: StatusObject): StatusObject { return status; } } diff --git a/packages/grpc-js/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts index 5ca401f73..f3879d7a9 100644 --- a/packages/grpc-js/src/metadata-status-filter.ts +++ b/packages/grpc-js/src/metadata-status-filter.ts @@ -22,9 +22,9 @@ import { Status } from './constants'; import { BaseFilter, Filter, FilterFactory } from './filter'; export class MetadataStatusFilter extends BaseFilter implements Filter { - async receiveTrailers(status: Promise): Promise { + receiveTrailers(status: StatusObject): StatusObject { // tslint:disable-next-line:prefer-const - let { code, details, metadata } = await status; + let { code, details, metadata } = status; if (code !== Status.UNKNOWN) { // we already have a known status, so don't assign a new one. return { code, details, metadata }; From 3144cb6adadbf001b34079d4b4adca082de7e316 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 23 Oct 2019 16:28:00 -0700 Subject: [PATCH 0823/1899] Rework call stream API to work better with interceptor APIs --- packages/grpc-js/src/call-stream.ts | 169 ++++++++++++++++-------- packages/grpc-js/src/call.ts | 73 ++-------- packages/grpc-js/src/client.ts | 165 ++++++++++++++++------- packages/grpc-js/src/deadline-filter.ts | 2 +- 4 files changed, 244 insertions(+), 165 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 645e9865b..50ad7e343 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -16,15 +16,12 @@ */ import * as http2 from 'http2'; -import { Duplex } from 'stream'; import { CallCredentials } from './call-credentials'; import { Status } from './constants'; -import { EmitterAugmentation1 } from './events'; import { Filter } from './filter'; import { FilterStackFactory } from './filter-stack'; import { Metadata } from './metadata'; -import { ObjectDuplex, WriteCallback } from './object-stream'; import { StreamDecoder } from './stream-decoder'; import { ChannelImplementation } from './channel'; import { Subchannel } from './subchannel'; @@ -63,39 +60,84 @@ export interface WriteObject { flags?: number; } -/** - * This interface represents a duplex stream associated with a single gRPC call. - */ +export interface MetadataListener { + (metadata: Metadata, next: (metadata: Metadata) => void): void; +} + +export interface MessageListener { + (message: any, next: (message: any) => void): void; +} + +export interface StatusListener { + (status: StatusObject, next: (status: StatusObject) => void): void; +} + +export interface FullListener { + onReceiveMetadata: MetadataListener; + onReceiveMessage: MessageListener; + onReceiveStatus: StatusListener; +} + +export type Listener = Partial; + +export interface InterceptingListener { + onReceiveMetadata(metadata: Metadata): void; + onReceiveMessage(message: any): void; + onReceiveStatus(status: StatusObject): void; +} + +class InterceptingListenerImpl implements InterceptingListener { + constructor(private listener: FullListener, private nextListener: InterceptingListener) {} + + onReceiveMetadata(metadata: Metadata): void { + const next = this.nextListener.onReceiveMetadata.bind(this.nextListener); + this.listener.onReceiveMetadata(metadata, next); + } + onReceiveMessage(message: any): void { + const next = this.nextListener.onReceiveMessage.bind(this.nextListener); + this.listener.onReceiveMessage(message, next); + } + onReceiveStatus(status: StatusObject): void { + const next = this.nextListener.onReceiveStatus.bind(this.nextListener); + this.listener.onReceiveStatus(status, next); + } +} + +export interface WriteCallback { + (error?: Error | null): void; +} + export type Call = { cancelWithStatus(status: Status, details: string): void; getPeer(): string; - sendMetadata(metadata: Metadata): void; + start(metadata: Metadata, listener: InterceptingListener): void; + write(writeObj: WriteObject, callback: WriteCallback): void; + startRead(): void; + halfClose(): void; getDeadline(): Deadline; getCredentials(): CallCredentials; setCredentials(credentials: CallCredentials): void; - /* If the return value is null, the call has not ended yet. Otherwise, it has - * ended with the specified status */ - getStatus(): StatusObject | null; getMethod(): string; getHost(): string; -} & EmitterAugmentation1<'metadata', Metadata> & - EmitterAugmentation1<'status', StatusObject> & - ObjectDuplex; +} -export class Http2CallStream extends Duplex implements Call { +export class Http2CallStream implements Call { credentials: CallCredentials; filterStack: Filter; private http2Stream: http2.ClientHttp2Stream | null = null; private pendingRead = false; private pendingWrite: Buffer | null = null; private pendingWriteCallback: WriteCallback | null = null; - private pendingFinalCallback: Function | null = null; + private writesClosed = false; private decoder = new StreamDecoder(); private isReadFilterPending = false; private canPush = false; + private readsClosed = false; + + private statusOutput = false; private unpushedReadMessages: Array = []; private unfilteredReadMessages: Array = []; @@ -109,6 +151,8 @@ export class Http2CallStream extends Duplex implements Call { private subchannel: Subchannel | null = null; private disconnectListener: () => void; + private listener: InterceptingListener | null = null; + constructor( private readonly methodName: string, private readonly channel: ChannelImplementation, @@ -116,7 +160,6 @@ export class Http2CallStream extends Duplex implements Call { filterStackFactory: FilterStackFactory, private readonly channelCallCredentials: CallCredentials ) { - super({ objectMode: true }); this.filterStack = filterStackFactory.createFilter(this); this.credentials = channelCallCredentials; this.disconnectListener = () => { @@ -124,14 +167,10 @@ export class Http2CallStream extends Duplex implements Call { }; } - /** - * On first call, emits a 'status' event with the given StatusObject. - * Subsequent calls are no-ops. - * @param status The status of the call. - */ - private endCall(status: StatusObject): void { - if (this.finalStatus === null) { - this.finalStatus = status; + private outputStatus() { + /* Precondition: this.finalStatus !== null */ + if (!this.statusOutput) { + this.statusOutput = true; /* We do this asynchronously to ensure that no async function is in the * call stack when we return control to the application. If an async * function is in the call stack, any exception thrown by the application @@ -140,7 +179,7 @@ export class Http2CallStream extends Duplex implements Call { * a warning, the error will be effectively swallowed and execution will * continue */ process.nextTick(() => { - this.emit('status', status); + this.listener!.onReceiveStatus(this.finalStatus!); }); if (this.subchannel) { this.subchannel.callUnref(); @@ -149,6 +188,35 @@ export class Http2CallStream extends Duplex implements Call { } } + /** + * On first call, emits a 'status' event with the given StatusObject. + * Subsequent calls are no-ops. + * @param status The status of the call. + */ + private endCall(status: StatusObject): void { + /* If the status is OK and a new status comes in (e.g. from a + * deserialization failure), that new status takes priority */ + if (this.finalStatus === null || this.finalStatus.code === Status.OK) { + this.finalStatus = status; + /* Then, if an incoming message is still being handled or the status code + * is OK, hold off on emitting the status until that is done */ + if (this.readsClosed || this.finalStatus.code !== Status.OK) { + this.outputStatus(); + } + } + } + + private push(message: Buffer | null): void { + if (message === null) { + this.readsClosed = true; + if (this.finalStatus) { + this.outputStatus(); + } + } else { + this.listener!.onReceiveMessage(message); + } + } + private handleFilterError(error: Error) { this.cancelWithStatus(Status.INTERNAL, error.message); } @@ -157,14 +225,14 @@ export class Http2CallStream extends Duplex implements Call { /* If we the call has already ended, we don't want to do anything with * this message. Dropping it on the floor is correct behavior */ if (this.finalStatus !== null) { + this.push(null); return; } this.isReadFilterPending = false; if (this.canPush) { - if (!this.push(message)) { - this.canPush = false; - (this.http2Stream as http2.ClientHttp2Stream).pause(); - } + this.push(message) + this.canPush = false; + this.http2Stream!.pause(); } else { this.unpushedReadMessages.push(message); } @@ -180,6 +248,7 @@ export class Http2CallStream extends Duplex implements Call { /* If we the call has already ended, we don't want to do anything with * this message. Dropping it on the floor is correct behavior */ if (this.finalStatus !== null) { + this.push(null); return; } if (framedMessage === null) { @@ -283,7 +352,7 @@ export class Http2CallStream extends Duplex implements Call { } try { const finalMetadata = this.filterStack.receiveMetadata(metadata); - this.emit('metadata', finalMetadata); + this.listener!.onReceiveMetadata(finalMetadata); } catch (error) { this.destroyHttp2Stream(); this.endCall({ @@ -348,13 +417,14 @@ export class Http2CallStream extends Duplex implements Call { } stream.write(this.pendingWrite, this.pendingWriteCallback); } - if (this.pendingFinalCallback) { - stream.end(this.pendingFinalCallback); + if (this.writesClosed) { + stream.end(); } } } - sendMetadata(metadata: Metadata): void { + start(metadata: Metadata, listener: InterceptingListener) { + this.listener = listener; this.channel._startCallStream(this, metadata); } @@ -370,9 +440,7 @@ export class Http2CallStream extends Duplex implements Call { cancelWithStatus(status: Status, details: string): void { this.destroyHttp2Stream(); - (async () => { - this.endCall({ code: status, details, metadata: new Metadata() }); - })(); + this.endCall({ code: status, details, metadata: new Metadata() }); } getDeadline(): Deadline { @@ -403,7 +471,7 @@ export class Http2CallStream extends Duplex implements Call { return this.options.host; } - _read(size: number) { + startRead() { /* If we have already emitted a status, we should not emit any more * messages and we should communicate that the stream has ended */ if (this.finalStatus !== null) { @@ -414,13 +482,11 @@ export class Http2CallStream extends Duplex implements Call { if (this.http2Stream === null) { this.pendingRead = true; } else { - while (this.unpushedReadMessages.length > 0) { - const nextMessage = this.unpushedReadMessages.shift(); - this.canPush = this.push(nextMessage); - if (nextMessage === null || !this.canPush) { - this.canPush = false; - return; - } + if (this.unpushedReadMessages.length > 0) { + const nextMessage: Buffer | null = this.unpushedReadMessages.shift() as Buffer | null; + this.push(nextMessage); + this.canPush = false; + return; } /* Only resume reading from the http2Stream if we don't have any pending * messages to emit, and we haven't gotten the signal to stop pushing @@ -429,8 +495,8 @@ export class Http2CallStream extends Duplex implements Call { } } - _write(chunk: WriteObject, encoding: string, cb: WriteCallback) { - this.filterStack.sendMessage(Promise.resolve(chunk)).then(message => { + write(writeObj: WriteObject, cb: WriteCallback) { + this.filterStack.sendMessage(Promise.resolve(writeObj)).then(message => { if (this.http2Stream === null) { this.pendingWrite = message.message; this.pendingWriteCallback = cb; @@ -440,11 +506,10 @@ export class Http2CallStream extends Duplex implements Call { }, this.handleFilterError.bind(this)); } - _final(cb: Function) { - if (this.http2Stream === null) { - this.pendingFinalCallback = cb; - } else { - this.http2Stream.end(cb); + halfClose() { + this.writesClosed = true; + if (this.http2Stream !== null) { + this.http2Stream.end(); } } -} +} \ No newline at end of file diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 5734bc3d0..8e74e6098 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -22,7 +22,7 @@ import { Call, StatusObject, WriteObject } from './call-stream'; import { Status } from './constants'; import { EmitterAugmentation1 } from './events'; import { Metadata } from './metadata'; -import { ObjectReadable, ObjectWritable } from './object-stream'; +import { ObjectReadable, ObjectWritable, WriteCallback } from './object-stream'; /** * A type extending the built-in Error object with additional fields. @@ -86,12 +86,6 @@ export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { constructor(private readonly call: Call) { super(); - call.on('metadata', (metadata: Metadata) => { - this.emit('metadata', metadata); - }); - call.on('status', (status: StatusObject) => { - this.emit('status', status); - }); } cancel(): void { @@ -103,43 +97,6 @@ export class ClientUnaryCallImpl extends EventEmitter } } -function setUpReadableStream( - stream: ClientReadableStream, - call: Call, - deserialize: (chunk: Buffer) => ResponseType -): void { - let statusEmitted = false; - call.on('data', (data: Buffer) => { - let deserialized: ResponseType; - try { - deserialized = deserialize(data); - } catch (e) { - call.cancelWithStatus(Status.INTERNAL, 'Failed to parse server response'); - return; - } - if (!stream.push(deserialized)) { - call.pause(); - } - }); - call.on('end', () => { - if (statusEmitted) { - stream.push(null); - } else { - call.once('status', () => { - stream.push(null); - }); - } - }); - call.on('status', (status: StatusObject) => { - if (status.code !== Status.OK) { - stream.emit('error', callErrorFromStatus(status)); - } - stream.emit('status', status); - statusEmitted = true; - }); - call.pause(); -} - export class ClientReadableStreamImpl extends Readable implements ClientReadableStream { constructor( @@ -147,10 +104,6 @@ export class ClientReadableStreamImpl extends Readable readonly deserialize: (chunk: Buffer) => ResponseType ) { super({ objectMode: true }); - call.on('metadata', (metadata: Metadata) => { - this.emit('metadata', metadata); - }); - setUpReadableStream(this, call, deserialize); } cancel(): void { @@ -162,7 +115,7 @@ export class ClientReadableStreamImpl extends Readable } _read(_size: number): void { - this.call.resume(); + this.call.startRead(); } } @@ -171,7 +124,7 @@ function tryWrite( serialize: (value: RequestType) => Buffer, chunk: RequestType, encoding: string, - cb: Function + cb: WriteCallback ) { let message: Buffer; const flags: number = Number(encoding); @@ -196,12 +149,6 @@ export class ClientWritableStreamImpl extends Writable readonly serialize: (value: RequestType) => Buffer ) { super({ objectMode: true }); - call.on('metadata', (metadata: Metadata) => { - this.emit('metadata', metadata); - }); - call.on('status', (status: StatusObject) => { - this.emit('status', status); - }); } cancel(): void { @@ -212,12 +159,12 @@ export class ClientWritableStreamImpl extends Writable return this.call.getPeer(); } - _write(chunk: RequestType, encoding: string, cb: Function) { + _write(chunk: RequestType, encoding: string, cb: WriteCallback) { tryWrite(this.call, this.serialize, chunk, encoding, cb); } _final(cb: Function) { - this.call.end(); + this.call.halfClose(); cb(); } } @@ -230,10 +177,6 @@ export class ClientDuplexStreamImpl extends Duplex readonly deserialize: (chunk: Buffer) => ResponseType ) { super({ objectMode: true }); - call.on('metadata', (metadata: Metadata) => { - this.emit('metadata', metadata); - }); - setUpReadableStream(this, call, deserialize); } cancel(): void { @@ -245,15 +188,15 @@ export class ClientDuplexStreamImpl extends Duplex } _read(_size: number): void { - this.call.resume(); + this.call.startRead(); } - _write(chunk: RequestType, encoding: string, cb: Function) { + _write(chunk: RequestType, encoding: string, cb: WriteCallback) { tryWrite(this.call, this.serialize, chunk, encoding, cb); } _final(cb: Function) { - this.call.end(); + this.call.halfClose(); cb(); } } diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index fb3bb6dc9..dc9e2eeb6 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -26,9 +26,10 @@ import { ClientWritableStreamImpl, ServiceError, callErrorFromStatus, + SurfaceCall, } from './call'; import { CallCredentials } from './call-credentials'; -import { Call, Deadline, StatusObject, WriteObject } from './call-stream'; +import { Call, Deadline, StatusObject, WriteObject, InterceptingListener } from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; @@ -125,38 +126,6 @@ export class Client { setImmediate(checkState); } - private handleUnaryResponse( - call: Call, - deserialize: (value: Buffer) => ResponseType, - callback: UnaryCallback - ): void { - let responseMessage: ResponseType | null = null; - call.on('data', (data: Buffer) => { - if (responseMessage != null) { - call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); - } - try { - responseMessage = deserialize(data); - } catch (e) { - call.cancelWithStatus( - Status.INTERNAL, - 'Failed to parse server response' - ); - } - }); - call.on('status', (status: StatusObject) => { - /* We assume that call emits status after it emits end, and that it - * accounts for any cancelWithStatus calls up until it emits status. - * Therefore, considering the above event handlers, status.code should be - * OK if and only if we have a non-null responseMessage */ - if (status.code === Status.OK) { - callback(null, responseMessage as ResponseType); - } else { - callback(callErrorFromStatus(status)); - } - }); - } - private checkOptionalUnaryResponseArguments( arg1: Metadata | CallOptions | UnaryCallback, arg2?: CallOptions | UnaryCallback, @@ -244,11 +213,38 @@ export class Client { } const message: Buffer = serialize(argument); const writeObj: WriteObject = { message }; - call.sendMetadata(metadata); - call.write(writeObj); - call.end(); - this.handleUnaryResponse(call, deserialize, callback); - return new ClientUnaryCallImpl(call); + const emitter = new ClientUnaryCallImpl(call); + let responseMessage: ResponseType | null = null; + call.start(metadata, { + onReceiveMetadata: (metadata) => { + emitter.emit('metadata', metadata); + }, + onReceiveMessage(message: Buffer) { + if (responseMessage != null) { + call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); + } + try { + responseMessage = deserialize(message); + } catch (e) { + call.cancelWithStatus( + Status.INTERNAL, + 'Failed to parse server response' + ); + } + call.startRead(); + }, + onReceiveStatus(status: StatusObject) { + if (status.code === Status.OK) { + callback!(null, responseMessage!); + } else { + callback!(callErrorFromStatus(status)); + } + emitter.emit('status', status); + } + }); + call.write(writeObj, () => {call.halfClose();}); + call.startRead(); + return emitter; } makeClientStreamRequest( @@ -300,9 +296,37 @@ export class Client { if (options.credentials) { call.setCredentials(options.credentials); } - call.sendMetadata(metadata); - this.handleUnaryResponse(call, deserialize, callback); - return new ClientWritableStreamImpl(call, serialize); + const emitter = new ClientWritableStreamImpl(call, serialize); + let responseMessage: ResponseType | null = null; + call.start(metadata, { + onReceiveMetadata: (metadata) => { + emitter.emit('metadata', metadata); + }, + onReceiveMessage(message: Buffer) { + if (responseMessage != null) { + call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); + } + try { + responseMessage = deserialize(message); + } catch (e) { + call.cancelWithStatus( + Status.INTERNAL, + 'Failed to parse server response' + ); + } + call.startRead(); + }, + onReceiveStatus(status: StatusObject) { + if (status.code === Status.OK) { + callback!(null, responseMessage!); + } else { + callback!(callErrorFromStatus(status)); + } + emitter.emit('status', status); + } + }); + call.startRead(); + return emitter; } private checkMetadataAndOptions( @@ -365,10 +389,33 @@ export class Client { } const message: Buffer = serialize(argument); const writeObj: WriteObject = { message }; - call.sendMetadata(metadata); - call.write(writeObj); - call.end(); - return new ClientReadableStreamImpl(call, deserialize); + const stream = new ClientReadableStreamImpl(call, deserialize); + call.start(metadata, { + onReceiveMetadata(metadata: Metadata) { + stream.emit('metadata', metadata); + }, + onReceiveMessage(message: Buffer) { + let deserialized: ResponseType; + try { + deserialized = deserialize(message); + } catch (e) { + call.cancelWithStatus(Status.INTERNAL, 'Failed to parse server response'); + return; + } + if (stream.push(deserialized)) { + call.startRead(); + } + }, + onReceiveStatus(status: StatusObject) { + stream.push(null); + if (status.code !== Status.OK) { + stream.emit('error', callErrorFromStatus(status)); + } + stream.emit('status', status); + } + }); + call.write(writeObj, () => {call.halfClose();}); + return stream; } makeBidiStreamRequest( @@ -402,11 +449,35 @@ export class Client { if (options.credentials) { call.setCredentials(options.credentials); } - call.sendMetadata(metadata); - return new ClientDuplexStreamImpl( + const stream = new ClientDuplexStreamImpl( call, serialize, deserialize ); + call.start(metadata, { + onReceiveMetadata(metadata: Metadata) { + stream.emit('metadata', metadata); + }, + onReceiveMessage(message: Buffer) { + let deserialized: ResponseType; + try { + deserialized = deserialize(message); + } catch (e) { + call.cancelWithStatus(Status.INTERNAL, 'Failed to parse server response'); + return; + } + if (stream.push(deserialized)) { + call.startRead(); + } + }, + onReceiveStatus(status: StatusObject) { + stream.push(null); + if (status.code !== Status.OK) { + stream.emit('error', callErrorFromStatus(status)); + } + stream.emit('status', status); + } + }); + return stream; } } diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 5c3cf532d..f659c8669 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -66,7 +66,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { 'Deadline exceeded' ); }, timeout); - callStream.on('status', () => clearTimeout(this.timer as NodeJS.Timer)); + this.timer.unref(); } } From 20cbfc7e9fd28a174746d181178fc53279c74d9b Mon Sep 17 00:00:00 2001 From: Joram Date: Thu, 24 Oct 2019 11:44:13 +0200 Subject: [PATCH 0824/1899] fix(sub-channels): clear the cleanup interval when all channels are unrefed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Natan Sągol --- packages/grpc-js/src/channel.ts | 4 ++ packages/grpc-js/src/subchannel-pool.ts | 96 ++++++++++++++++++------- 2 files changed, 74 insertions(+), 26 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index ebcf3a223..f046ede94 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -288,6 +288,10 @@ export class ChannelImplementation implements Channel { close() { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); + + if (this.subchannelPool !== undefined) { + this.subchannelPool.forceCleanup(); + } } getTarget() { diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 1a5015b6a..091ab6ca2 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -37,39 +37,81 @@ export class SubchannelPool { }; } = Object.create(null); + /** + * A timer of a task performing a periodic subchannel cleanup. + */ + private cleanupTimer: NodeJS.Timer | undefined; + /** * A pool of subchannels use for making connections. Subchannels with the * exact same parameters will be reused. * @param global If true, this is the global subchannel pool. Otherwise, it * is the pool for a single channel. */ - constructor(private global: boolean) { - if (global) { - setInterval(() => { - /* These objects are created with Object.create(null), so they do not - * have a prototype, which means that for (... in ...) loops over them - * do not need to be filtered */ - // tslint:disable-next-line:forin - for (const channelTarget in this.pool) { - // tslint:disable-next-line:forin - for (const subchannelTarget in this.pool[channelTarget]) { - const subchannelObjArray = this.pool[channelTarget][ - subchannelTarget - ]; - /* For each subchannel in the pool, try to unref it if it has - * exactly one ref (which is the ref from the pool itself). If that - * does happen, remove the subchannel from the pool */ - this.pool[channelTarget][ - subchannelTarget - ] = subchannelObjArray.filter( - value => !value.subchannel.unrefIfOneRef() - ); - } + constructor(private global: boolean) {} + + /** + * Unrefs all unused subchannels. + * + * @returns `true` if all subchannels have been unrefed. `false` otherwise. + */ + unrefUnusedSubchannels(): boolean { + let allSubchannelsUnrefed = true; + + /* These objects are created with Object.create(null), so they do not + * have a prototype, which means that for (... in ...) loops over them + * do not need to be filtered */ + // tslint:disable-next-line:forin + for (const channelTarget in this.pool) { + // tslint:disable-next-line:forin + for (const subchannelTarget in this.pool[channelTarget]) { + const subchannelObjArray = this.pool[channelTarget][ + subchannelTarget + ]; + + const refedSubchannels = subchannelObjArray + .filter(value => !value.subchannel.unrefIfOneRef()); + + if (refedSubchannels.length > 0) { + allSubchannelsUnrefed = false; } - /* Currently we do not delete keys with empty values. If that results - * in significant memory usage we should change it. */ - }, REF_CHECK_INTERVAL).unref(); - // Unref because this timer should not keep the event loop running + + /* For each subchannel in the pool, try to unref it if it has + * exactly one ref (which is the ref from the pool itself). If that + * does happen, remove the subchannel from the pool */ + this.pool[channelTarget][subchannelTarget] = refedSubchannels; + } + } + /* Currently we do not delete keys with empty values. If that results + * in significant memory usage we should change it. */ + + return allSubchannelsUnrefed; + } + + /** + * Ensure that the cleanup task is spawned. + */ + ensureCleanupTask(): void { + if (this.global === true && this.cleanupTimer === undefined) { + this.cleanupTimer = setInterval(() => { + this.unrefUnusedSubchannels(); + }, REF_CHECK_INTERVAL); + + // Unref because this timer should not keep the event loop running. + this.cleanupTimer.unref(); + } + } + + /** + * Unrefs unused subchannels and cancels the cleanup task if all + * subchannels have been unrefed. + */ + forceCleanup(): void { + const allSubchannelsUnrefed = this.unrefUnusedSubchannels(); + + if (allSubchannelsUnrefed && this.cleanupTimer !== undefined) { + clearInterval(this.cleanupTimer); + this.cleanupTimer = undefined; } } @@ -87,6 +129,8 @@ export class SubchannelPool { channelArguments: ChannelOptions, channelCredentials: ChannelCredentials ): Subchannel { + this.ensureCleanupTask(); + if (channelTarget in this.pool) { if (subchannelTarget in this.pool[channelTarget]) { const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; From de364c65a238a895d38a10edabad5f64aad8b851 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 25 Oct 2019 10:45:54 -0700 Subject: [PATCH 0825/1899] Add Electron 7 to the build --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 229d0f42d..208e056a2 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 7.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index a226a5a98..bc2884101 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 7.0.0 ) umask 022 From ae62a73b9fe6ff3aaf42f28128b867b8e8d39971 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 25 Oct 2019 11:10:10 -0700 Subject: [PATCH 0826/1899] Also add Node 13 to the build --- .../tools/run_tests/artifacts/build_artifact_node.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_node.sh | 2 +- .../tools/run_tests/artifacts/build_artifact_node_arm.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat index 3dcb6c209..844d571ca 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 +set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh index 42149d442..4f459dc6a 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 ) while true ; do case $1 in diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh index ace0aff96..a6e414f90 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh @@ -26,7 +26,7 @@ mkdir -p "${ARTIFACTS_OUT}" npm update -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 ) +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 ) for version in ${node_versions[@]} do From 19c2e6fde8995665da75e74d8a691573b9670786 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 25 Oct 2019 11:15:24 -0700 Subject: [PATCH 0827/1899] Fix deprecated method use in call.cc --- packages/grpc-native-core/ext/call.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/ext/call.cc b/packages/grpc-native-core/ext/call.cc index 25370759b..7738af369 100644 --- a/packages/grpc-native-core/ext/call.cc +++ b/packages/grpc-native-core/ext/call.cc @@ -101,7 +101,7 @@ bool CreateMetadataArray(Local metadata_obj, grpc_metadata_array *array) array->metadata = reinterpret_cast( gpr_zalloc(array->capacity * sizeof(grpc_metadata))); for (unsigned int i = 0; i < keys->Length(); i++) { - Local current_key(Nan::To(keys->Get(i)).ToLocalChecked()); + Local current_key(Nan::To(Nan::Get(keys, i).ToLocalChecked()).ToLocalChecked()); Local values = Local::Cast(Nan::Get(metadata, current_key).ToLocalChecked()); grpc_slice key_slice = CreateSliceFromString(current_key); @@ -678,7 +678,7 @@ NAN_METHOD(Call::StartBatch) { default: return Nan::ThrowError("Argument object had an unrecognized key"); } - if (!op->ParseOp(obj->Get(type), &ops[i])) { + if (!op->ParseOp(Nan::Get(obj, type).ToLocalChecked(), &ops[i])) { return Nan::ThrowTypeError("Incorrectly typed arguments to startBatch"); } op_vector->push_back(std::move(op)); From 8fa9da9c0e8795c86ed1810d4008f4f618ceb908 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 25 Oct 2019 14:34:13 -0700 Subject: [PATCH 0828/1899] Update node-pre-gyp dependency to 0.14 --- packages/grpc-native-core/package.json | 2 +- packages/grpc-native-core/templates/package.json.template | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index a7b89549d..6530430e5 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -33,7 +33,7 @@ "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", - "node-pre-gyp": "^0.13.0", + "node-pre-gyp": "^0.14.0", "protobufjs": "^5.0.3" }, "devDependencies": { diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 66478b8ea..91ae513ae 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -35,7 +35,7 @@ "lodash.camelcase": "^4.3.0", "lodash.clone": "^4.5.0", "nan": "^2.13.2", - "node-pre-gyp": "^0.13.0", + "node-pre-gyp": "^0.14.0", "protobufjs": "^5.0.3" }, "devDependencies": { From 8a279f8292e68c068e591cde12f40eb6d870bec2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 25 Oct 2019 14:51:05 -0700 Subject: [PATCH 0829/1899] Also test on Node 13 --- run-tests.bat | 2 +- run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 64396be17..305b2adda 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (8 10 12) do ( +for %%v in (8 10 12 13) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index f23475b90..743f67a96 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="8 10 12" + node_versions="8 10 12 13" fi set +ex From f66c9a19ef9aec009ab0cf7e5e321cb50f42d440 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 28 Oct 2019 09:42:32 -0700 Subject: [PATCH 0830/1899] Don't add Node 13 tests yet --- run-tests.bat | 2 +- run-tests.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 305b2adda..64396be17 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (8 10 12 13) do ( +for %%v in (8 10 12) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index 743f67a96..f23475b90 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -26,7 +26,7 @@ set -ex cd $ROOT if [ ! -n "$node_versions" ] ; then - node_versions="8 10 12 13" + node_versions="8 10 12" fi set +ex From e2bb127bb59b280b8b6b0b7c784dbb0dfc7d1bd7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 28 Oct 2019 10:33:59 -0700 Subject: [PATCH 0831/1899] grpc-js: Close http2 sessions that are dropped by their subchannels --- packages/grpc-js/src/subchannel.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 9a207a5f9..4edce3c10 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -321,6 +321,9 @@ export class Subchannel { this.continueConnecting = false; break; case ConnectivityState.TRANSIENT_FAILURE: + if (this.session) { + this.session.close(); + } this.session = null; this.stopKeepalivePings(); break; @@ -329,6 +332,9 @@ export class Subchannel { * should only transition to the IDLE state as a result of the timer * ending, but we still want to reset the backoff timeout. */ this.stopBackoff(); + if (this.session) { + this.session.close(); + } this.session = null; this.stopKeepalivePings(); break; From 39f11520f38f0902edf00f2c2a2551d665b1f5ad Mon Sep 17 00:00:00 2001 From: imjoey Date: Tue, 29 Oct 2019 14:55:34 +0800 Subject: [PATCH 0832/1899] Fix the default value of waitForReady in doc In my usecase, the default behavious of `waitForReady` for RPC is `false` that not in accord with the doc. After digging into the source codes, probably the doc is incorrect. Signed-off-by: imjoey --- packages/grpc-js/src/metadata.ts | 2 +- packages/grpc-native-core/index.d.ts | 2 +- packages/grpc-native-core/src/metadata.js | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 1537b31a2..67a23960c 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -66,7 +66,7 @@ export interface MetadataOptions { /* Signal that the request is idempotent. Defaults to false */ idempotentRequest?: boolean; /* Signal that the call should not return UNAVAILABLE before it has - * started. Defaults to true. */ + * started. Defaults to false. */ waitForReady?: boolean; /* Signal that the call is cacheable. GRPC is free to use GET verb. * Defaults to false */ diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts index 25815ce64..33956aa11 100644 --- a/packages/grpc-native-core/index.d.ts +++ b/packages/grpc-native-core/index.d.ts @@ -554,7 +554,7 @@ declare module "grpc" { /* Signal that the request is idempotent. Defaults to false */ idempotentRequest?: boolean; /* Signal that the call should not return UNAVAILABLE before it has - * started. Defaults to true. */ + * started. Defaults to false. */ waitForReady?: boolean; /* Signal that the call is cacheable. GRPC is free to use GET verb. * Defaults to false */ diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js index ee442953f..279dee180 100644 --- a/packages/grpc-native-core/src/metadata.js +++ b/packages/grpc-native-core/src/metadata.js @@ -37,7 +37,7 @@ const CORKED_FLAG = 0x100; * a client request. * @param {boolean=} [options.idempotentRequest=false] Signal that the request * is idempotent - * @param {boolean=} [options.waitForReady=true] Signal that the call should + * @param {boolean=} [options.waitForReady=false] Signal that the call should * not return UNAVAILABLE before it has started. * @param {boolean=} [options.cacheableRequest=false] Signal that the call is * cacheable. GRPC is free to use GET verb. @@ -170,7 +170,7 @@ Metadata.prototype.clone = function() { * a client request. * @param {boolean=} [options.idempotentRequest=false] Signal that the request * is idempotent - * @param {boolean=} [options.waitForReady=true] Signal that the call should + * @param {boolean=} [options.waitForReady=false] Signal that the call should * not return UNAVAILABLE before it has started. * @param {boolean=} [options.cacheableRequest=false] Signal that the call is * cacheable. GRPC is free to use GET verb. From f8af7d1dd0f727086974dc1b169fcdcc6413b30c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 30 Oct 2019 09:59:26 -0700 Subject: [PATCH 0833/1899] Bump grpc-js to 0.6.10 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4ec6349c2..d3b4a6baf 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.9", + "version": "0.6.10", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 85575c594d14d45516d2f491c0eb508a1a67d726 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 31 Oct 2019 17:58:54 -0700 Subject: [PATCH 0834/1899] Perform all npm operations sequentially --- gulpfile.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index 4c29137de..6f4b8f329 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -24,13 +24,13 @@ import * as internalTest from './test/gulpfile'; const root = __dirname; -const installAll = gulp.parallel(jsCore.install, nativeCore.install, healthCheck.install, protobuf.install, internalTest.install); +const installAll = gulp.series(jsCore.install, nativeCore.install, healthCheck.install, protobuf.install, internalTest.install); -const installAllWindows = gulp.parallel(jsCore.install, nativeCore.installWindows, healthCheck.install, protobuf.install, internalTest.install); +const installAllWindows = gulp.series(jsCore.install, nativeCore.installWindows, healthCheck.install, protobuf.install, internalTest.install); const lint = gulp.parallel(jsCore.lint, nativeCore.lint); -const build = gulp.parallel(jsCore.compile, nativeCore.build, protobuf.compile); +const build = gulp.series(jsCore.compile, nativeCore.build, protobuf.compile); const link = gulp.series(healthCheck.linkAdd); @@ -38,11 +38,11 @@ const setup = gulp.series(installAll, link); const setupWindows = gulp.series(installAllWindows, link); -const setupPureJSInterop = gulp.parallel(jsCore.install, protobuf.install, internalTest.install); +const setupPureJSInterop = gulp.series(jsCore.install, protobuf.install, internalTest.install); -const clean = gulp.parallel(jsCore.clean, nativeCore.clean, protobuf.clean); +const clean = gulp.series(jsCore.clean, nativeCore.clean, protobuf.clean); -const cleanAll = gulp.parallel(jsCore.cleanAll, nativeCore.cleanAll, healthCheck.cleanAll, internalTest.cleanAll, protobuf.cleanAll); +const cleanAll = gulp.series(jsCore.cleanAll, nativeCore.cleanAll, healthCheck.cleanAll, internalTest.cleanAll, protobuf.cleanAll); const nativeTestOnly = gulp.parallel(nativeCore.test, healthCheck.test); From acbf17d9b7f4158a7feea015205727143abf46d5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 25 Oct 2019 10:26:58 -0700 Subject: [PATCH 0835/1899] Add client interceptors --- packages/grpc-js/src/call-stream.ts | 57 +- packages/grpc-js/src/call.ts | 14 +- packages/grpc-js/src/client-interceptors.ts | 423 +++++ packages/grpc-js/src/client.ts | 149 +- packages/grpc-js/src/index.ts | 32 +- packages/grpc-js/src/make-client.ts | 14 +- packages/grpc-native-core/deps/grpc | 2 +- test/api/client_interceptors_test.js | 1778 +++++++++++++++++++ 8 files changed, 2364 insertions(+), 105 deletions(-) create mode 100644 packages/grpc-js/src/client-interceptors.ts create mode 100644 test/api/client_interceptors_test.js diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 50ad7e343..23823f96b 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -86,20 +86,40 @@ export interface InterceptingListener { onReceiveStatus(status: StatusObject): void; } -class InterceptingListenerImpl implements InterceptingListener { +export function isInterceptingListener(listener: Listener | InterceptingListener): listener is InterceptingListener { + return listener.onReceiveMetadata !== undefined && listener.onReceiveMetadata.length === 1; +} + +export class InterceptingListenerImpl implements InterceptingListener { + private processingMessage = false; + private pendingStatus: StatusObject | null = null; constructor(private listener: FullListener, private nextListener: InterceptingListener) {} onReceiveMetadata(metadata: Metadata): void { - const next = this.nextListener.onReceiveMetadata.bind(this.nextListener); - this.listener.onReceiveMetadata(metadata, next); + this.listener.onReceiveMetadata(metadata, (metadata) => { + this.nextListener.onReceiveMetadata(metadata); + }); } onReceiveMessage(message: any): void { - const next = this.nextListener.onReceiveMessage.bind(this.nextListener); - this.listener.onReceiveMessage(message, next); + /* If this listener processes messages asynchronously, the last message may + * be reordered with respect to the status */ + this.processingMessage = true; + this.listener.onReceiveMessage(message, (msg) => { + this.processingMessage = false; + this.nextListener.onReceiveMessage(msg); + if (this.pendingStatus) { + this.nextListener.onReceiveStatus(this.pendingStatus); + } + }); } onReceiveStatus(status: StatusObject): void { - const next = this.nextListener.onReceiveStatus.bind(this.nextListener); - this.listener.onReceiveStatus(status, next); + this.listener.onReceiveStatus(status, (processedStatus) => { + if (this.processingMessage) { + this.pendingStatus = processedStatus; + } else { + this.nextListener.onReceiveStatus(processedStatus); + } + }); } } @@ -107,11 +127,16 @@ export interface WriteCallback { (error?: Error | null): void; } -export type Call = { +export interface MessageContext { + callback?: WriteCallback; + flags?: number; +} + +export interface Call { cancelWithStatus(status: Status, details: string): void; getPeer(): string; start(metadata: Metadata, listener: InterceptingListener): void; - write(writeObj: WriteObject, callback: WriteCallback): void; + sendMessageWithContext(context: MessageContext, message: any): void; startRead(): void; halfClose(): void; @@ -214,6 +239,13 @@ export class Http2CallStream implements Call { } } else { this.listener!.onReceiveMessage(message); + /* Don't wait for the upper layer to ask for a read before pushing null + * to close out the call, because pushing null doesn't actually push + * another message up to the upper layer */ + if (this.unpushedReadMessages.length > 0 && this.unpushedReadMessages[0] === null) { + this.unpushedReadMessages.shift(); + this.push(null); + } } } @@ -495,7 +527,12 @@ export class Http2CallStream implements Call { } } - write(writeObj: WriteObject, cb: WriteCallback) { + sendMessageWithContext(context: MessageContext, message: Buffer) { + const writeObj: WriteObject = { + message: message, + flags: context.flags + }; + const cb: WriteCallback = context.callback || (() => {}); this.filterStack.sendMessage(Promise.resolve(writeObj)).then(message => { if (this.http2Stream === null) { this.pendingWrite = message.message; diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 8e74e6098..2f9cfdd4f 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -160,7 +160,12 @@ export class ClientWritableStreamImpl extends Writable } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { - tryWrite(this.call, this.serialize, chunk, encoding, cb); + const writeObj: WriteObject = { message: chunk }; + const flags: number = Number(encoding); + if (!Number.isNaN(flags)) { + writeObj.flags = flags; + } + this.call.write(writeObj, cb); } _final(cb: Function) { @@ -192,7 +197,12 @@ export class ClientDuplexStreamImpl extends Duplex } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { - tryWrite(this.call, this.serialize, chunk, encoding, cb); + const writeObj: WriteObject = { message: chunk }; + const flags: number = Number(encoding); + if (!Number.isNaN(flags)) { + writeObj.flags = flags; + } + this.call.write(writeObj, cb); } _final(cb: Function) { diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts new file mode 100644 index 000000000..9703db49a --- /dev/null +++ b/packages/grpc-js/src/client-interceptors.ts @@ -0,0 +1,423 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Metadata } from './metadata'; +import { StatusObject, CallStreamOptions, Listener, MetadataListener, MessageListener, StatusListener, FullListener, InterceptingListener, WriteObject, WriteCallback, InterceptingListenerImpl, isInterceptingListener, MessageContext, Http2CallStream, Deadline, Call } from './call-stream'; +import { Status } from './constants'; +import { Channel } from './channel'; +import { CallOptions } from './client'; +import { CallCredentials } from './call-credentials'; +import { ClientMethodDefinition, Serialize } from './make-client'; + +export class InterceptorConfigurationError extends Error { + constructor(message: string) { + super(message); + this.name = 'InterceptorConfigurationError'; + Error.captureStackTrace(this, InterceptorConfigurationError); + } +} + +export interface MetadataRequester { + (metadata: Metadata, listener: InterceptingListener, next: (metadata: Metadata, listener: InterceptingListener | Listener) => void): void; +} + +export interface MessageRequester { + (message: any, next: (message: any) => void): void; +} + +export interface CloseRequester { + (next: () => void): void; +} + +export interface CancelRequester { + (next: () => void): void; +} + +export interface FullRequester { + start: MetadataRequester; + sendMessage: MessageRequester; + halfClose: CloseRequester; + cancel: CancelRequester; +} + +export type Requester = Partial; + +export class ListenerBuilder { + private metadata: MetadataListener | undefined = undefined; + private message: MessageListener | undefined = undefined; + private status: StatusListener | undefined = undefined; + + withOnReceiveMetadata(onReceiveMetadata: MetadataListener): this { + this.metadata = onReceiveMetadata; + return this; + } + + withOnReceiveMessage(onReceiveMessage: MessageListener): this { + this.message = onReceiveMessage; + return this; + } + + withOnReceiveStatus(onReceiveStatus: StatusListener): this { + this.status = onReceiveStatus; + return this; + } + + build(): Listener { + return { + onReceiveMetadata: this.metadata, + onReceiveMessage: this.message, + onReceiveStatus: this.status + } + } +} + +export class RequesterBuilder { + private start: MetadataRequester | undefined = undefined; + private message: MessageRequester | undefined = undefined; + private halfClose: CloseRequester | undefined = undefined; + private cancel: CancelRequester | undefined = undefined; + + withStart(start: MetadataRequester): this { + this.start = start; + return this; + } + + withSendMessage(sendMessage: MessageRequester): this { + this.message = sendMessage; + return this; + } + + withHalfClose(halfClose: CloseRequester): this { + this.halfClose = halfClose; + return this; + } + + withCancel(cancel: CancelRequester): this { + this.cancel = cancel; + return this; + } + + build(): Requester { + return { + start: this.start, + sendMessage: this.message, + halfClose: this.halfClose, + cancel: this.cancel + }; + } +} + +const defaultListener: FullListener = { + onReceiveMetadata: (metadata, next) => { + next(metadata); + }, + onReceiveMessage: (message, next) => { + next(message); + }, + onReceiveStatus: (status, next) => { + next(status); + } +}; + +const defaultRequester: FullRequester = { + start: (metadata, listener, next) => { + next(metadata, listener); + }, + sendMessage: (message, next) => { + next(message); + }, + halfClose: (next) => { + next(); + }, + cancel: (next) => { + next(); + } +} + +export interface InterceptorOptions extends CallOptions { + method_definition: ClientMethodDefinition; +} + +export interface InterceptingCallInterface { + cancelWithStatus(status: Status, details: string): void; + getPeer(): string; + start(metadata: Metadata, listener: InterceptingListener): void; + sendMessageWithContext(context: MessageContext, message: any): void; + startRead(): void; + halfClose(): void; + + getDeadline(): Deadline; + getCredentials(): CallCredentials; + setCredentials(credentials: CallCredentials): void; + getMethod(): string; + getHost(): string; +} + +export class InterceptingCall implements InterceptingCallInterface { + private requester: FullRequester; + private processingMessage = false; + private pendingHalfClose = false; + constructor(private nextCall: InterceptingCallInterface, requester?: Requester) { + if (requester) { + // Undefined elements overwrite, unset ones do not + this.requester = { + start: requester.start || defaultRequester.start, + sendMessage: requester.sendMessage || defaultRequester.sendMessage, + halfClose: requester.halfClose || defaultRequester.halfClose, + cancel: requester.cancel || defaultRequester.cancel + } + } else { + this.requester = defaultRequester; + } + } + + cancelWithStatus(status: Status, details: string) { + this.requester.cancel(() => { + this.nextCall.cancelWithStatus(status, details); + }); + } + + getPeer() { + return this.nextCall.getPeer(); + } + start(metadata: Metadata, interceptingListener: InterceptingListener): void { + this.requester.start(metadata, interceptingListener, (md, listener) => { + let finalInterceptingListener: InterceptingListener; + if (isInterceptingListener(listener)) { + finalInterceptingListener = listener; + } else { + const fullListener: FullListener = { + onReceiveMetadata: listener.onReceiveMetadata || defaultListener.onReceiveMetadata, + onReceiveMessage: listener.onReceiveMessage || defaultListener.onReceiveMessage, + onReceiveStatus: listener.onReceiveStatus || defaultListener.onReceiveStatus + }; + finalInterceptingListener = new InterceptingListenerImpl(fullListener, interceptingListener); + } + this.nextCall.start(md, finalInterceptingListener); + }); + } + sendMessageWithContext(context: MessageContext, message: any): void { + this.processingMessage = true; + this.requester.sendMessage(message, (finalMessage) => { + this.processingMessage = false; + this.nextCall.sendMessageWithContext(context, finalMessage); + if (this.pendingHalfClose) { + this.nextCall.halfClose(); + } + }) + } + sendMessage(message: any): void { + this.sendMessageWithContext({}, message); + } + startRead(): void { + this.nextCall.startRead(); + } + halfClose(): void { + this.requester.halfClose(() => { + if (this.processingMessage) { + this.pendingHalfClose = true; + } else { + this.nextCall.halfClose(); + } + }); + } + getDeadline(): number | Date { + return this.nextCall.getDeadline(); + } + getCredentials(): CallCredentials { + return this.nextCall.getCredentials(); + } + setCredentials(credentials: CallCredentials): void { + this.nextCall.setCredentials(credentials); + } + getMethod(): string { + return this.nextCall.getHost(); + } + getHost(): string { + return this.nextCall.getHost(); + } +} + +function getCall(channel: Channel, path: string, options: CallOptions): Call { + var deadline; + var host; + var parent; + var propagate_flags; + var credentials; + if (options) { + deadline = options.deadline; + host = options.host; + + propagate_flags = options.propagate_flags; + credentials = options.credentials; + } + if (deadline === undefined) { + deadline = Infinity; + } + var call = channel.createCall(path, deadline, host, + parent, propagate_flags); + if (credentials) { + call.setCredentials(credentials); + } + return call; +} + +class BaseInterceptingCall implements InterceptingCallInterface { + constructor(protected call: Call, protected methodDefinition: ClientMethodDefinition) {} + cancelWithStatus(status: Status, details: string): void { + this.call.cancelWithStatus(status, details); + } + getPeer(): string { + return this.call.getPeer(); + } + getDeadline(): number | Date { + return this.call.getDeadline(); + } + getCredentials(): CallCredentials { + return this.call.getCredentials(); + } + setCredentials(credentials: CallCredentials): void { + this.call.setCredentials(credentials); + } + getMethod(): string { + return this.call.getMethod(); + } + getHost(): string { + return this.call.getHost(); + } + sendMessageWithContext(context: MessageContext, message: any): void { + let serialized: Buffer; + try { + serialized = this.methodDefinition.requestSerialize(message); + this.call.sendMessageWithContext(context, serialized); + } catch (e) { + this.call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); + } + } + start(metadata: Metadata, listener: InterceptingListener): void { + let readError: StatusObject | null = null; + this.call.start(metadata, { + onReceiveMetadata: (metadata) => { + listener.onReceiveMetadata(metadata); + }, + onReceiveMessage: (message) => { + let deserialized: any; + try { + deserialized = this.methodDefinition.responseDeserialize(message); + listener.onReceiveMessage(deserialized); + } catch (e) { + readError = {code: Status.INTERNAL, details: 'Failed to parse server response', metadata: new Metadata()}; + this.call.cancelWithStatus(readError.code, readError.details); + } + }, + onReceiveStatus: (status) => { + if (readError) { + listener.onReceiveStatus(readError); + } else { + listener.onReceiveStatus(status); + } + } + }); + } + startRead() { + this.call.startRead(); + } + halfClose(): void { + this.call.halfClose(); + } +} + +class BaseUnaryInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { + constructor(call: Call, methodDefinition: ClientMethodDefinition) { + super(call, methodDefinition); + } + start(metadata: Metadata, listener: InterceptingListener): void { + super.start(metadata, listener); + this.call.startRead(); + } +} + +class BaseStreamingInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { } + +function getBottomInterceptingCall(channel: Channel, path: string, options: InterceptorOptions, methodDefinition: ClientMethodDefinition) { + const call = getCall(channel, path, options); + if (methodDefinition.responseStream) { + return new BaseStreamingInterceptingCall(call, methodDefinition); + } else { + return new BaseUnaryInterceptingCall(call, methodDefinition); + } +} + +export interface NextCall { + (options: InterceptorOptions): InterceptingCallInterface; +} + +export interface Interceptor { + (options: InterceptorOptions, nextCall: NextCall): InterceptingCall +} + +export interface InterceptorProvider { + (methodDefinition: ClientMethodDefinition): Interceptor; +} + +export interface InterceptorArguments { + clientInterceptors: Interceptor[], + clientInterceptorProviders: InterceptorProvider[], + callInterceptors: Interceptor[], + callInterceptorProviders: InterceptorProvider[] +} + +export function getInterceptingCall(interceptorArgs: InterceptorArguments, methodDefinition: ClientMethodDefinition, options: CallOptions, channel: Channel): InterceptingCallInterface { + if (interceptorArgs.clientInterceptors.length > 0 && interceptorArgs.clientInterceptorProviders.length > 0) { + throw new InterceptorConfigurationError( + 'Both interceptors and interceptor_providers were passed as options ' + + 'to the client constructor. Only one of these is allowed.' + ); + } + if (interceptorArgs.callInterceptors.length > 0 && interceptorArgs.callInterceptorProviders.length > 0) { + throw new InterceptorConfigurationError( + 'Both interceptors and interceptor_providers were passed as call ' + + 'options. Only one of these is allowed.' + ); + } + let interceptors: Interceptor[] = []; + // Interceptors passed to the call override interceptors passed to the client constructor + if (interceptorArgs.callInterceptors.length > 0 || interceptorArgs.callInterceptorProviders.length > 0) { + interceptors = ([] as Interceptor[]).concat( + interceptorArgs.callInterceptors, + interceptorArgs.callInterceptorProviders.map(provider => provider(methodDefinition)) + ).filter(interceptor => interceptor); + // Filter out falsy values when providers return nothing + } else { + interceptors = ([] as Interceptor[]).concat( + interceptorArgs.clientInterceptors, + interceptorArgs.clientInterceptorProviders.map(provider => provider(methodDefinition)) + ).filter(interceptor => interceptor); + // Filter out falsy values when providers return nothing + } + const interceptorOptions = Object.assign({}, options, {method_definition: methodDefinition}); + /* For each interceptor in the list, the nextCall function passed to it is + * based on the next interceptor in the list, using a nextCall function + * constructed with the following interceptor in the list, and so on. The + * initialValue, which is effectively at the end of the list, is a nextCall + * function that invokes getBottomInterceptingCall, which handles + * (de)serialization and also gets the underlying call from the channel */ + const getCall: NextCall = interceptors.reduceRight((previousValue: NextCall, currentValue: Interceptor) => { + return currentOptions => currentValue(currentOptions, previousValue); + }, (finalOptions: InterceptorOptions) => getBottomInterceptingCall(channel, methodDefinition.path, finalOptions, methodDefinition)); + return getCall(interceptorOptions); +} \ No newline at end of file diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index dc9e2eeb6..a7fbfa556 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -35,8 +35,12 @@ import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; +import { ClientMethodDefinition } from './make-client'; +import { getInterceptingCall, Interceptor, InterceptorProvider, InterceptorArguments } from './client-interceptors'; const CHANNEL_SYMBOL = Symbol(); +const INTERCEPTOR_SYMBOL = Symbol(); +const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); export interface UnaryCallback { (err: ServiceError | null, value?: ResponseType): void; @@ -49,6 +53,8 @@ export interface CallOptions { * but the server is not yet implemented so it makes no sense to have it */ propagate_flags?: number; credentials?: CallCredentials; + interceptors?: Interceptor[], + interceptor_providers?: InterceptorProvider[] } export type ClientOptions = Partial & { @@ -58,6 +64,8 @@ export type ClientOptions = Partial & { credentials: ChannelCredentials, options: ClientOptions ) => Channel; + interceptors?: Interceptor[], + interceptor_providers?: InterceptorProvider[] }; /** @@ -66,6 +74,8 @@ export type ClientOptions = Partial & { */ export class Client { private readonly [CHANNEL_SYMBOL]: Channel; + private readonly [INTERCEPTOR_SYMBOL]: Interceptor[]; + private readonly [INTERCEPTOR_PROVIDER_SYMBOL]: InterceptorProvider[]; constructor( address: string, credentials: ChannelCredentials, @@ -86,6 +96,13 @@ export class Client { options ); } + this[INTERCEPTOR_SYMBOL] = options.interceptors || []; + this[INTERCEPTOR_PROVIDER_SYMBOL] = options.interceptor_providers || []; + if (this[INTERCEPTOR_SYMBOL].length > 0 && this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0) { + throw new Error( + 'Both interceptors and interceptor_providers were passed as options ' + + 'to the client constructor. Only one of these is allowed.'); + } } close(): void { @@ -201,36 +218,35 @@ export class Client { ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< ResponseType >(metadata, options, callback)); - const call: Call = this[CHANNEL_SYMBOL].createCall( - method, - options.deadline, - options.host, - null, - options.propagate_flags - ); + const methodDefinition: ClientMethodDefinition = { + path: method, + requestStream: false, + responseStream: false, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + const interceptorArgs: InterceptorArguments = { + clientInterceptors: this[INTERCEPTOR_SYMBOL], + clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], + callInterceptors: options.interceptors || [], + callInterceptorProviders: options.interceptor_providers || [] + }; + const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } - const message: Buffer = serialize(argument); - const writeObj: WriteObject = { message }; + const writeObj: WriteObject = { message: argument }; const emitter = new ClientUnaryCallImpl(call); let responseMessage: ResponseType | null = null; call.start(metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); }, - onReceiveMessage(message: Buffer) { + onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); } - try { - responseMessage = deserialize(message); - } catch (e) { - call.cancelWithStatus( - Status.INTERNAL, - 'Failed to parse server response' - ); - } + responseMessage = message; call.startRead(); }, onReceiveStatus(status: StatusObject) { @@ -286,13 +302,20 @@ export class Client { ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< ResponseType >(metadata, options, callback)); - const call: Call = this[CHANNEL_SYMBOL].createCall( - method, - options.deadline, - options.host, - null, - options.propagate_flags - ); + const methodDefinition: ClientMethodDefinition = { + path: method, + requestStream: true, + responseStream: false, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + const interceptorArgs: InterceptorArguments = { + clientInterceptors: this[INTERCEPTOR_SYMBOL], + clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], + callInterceptors: options.interceptors || [], + callInterceptorProviders: options.interceptor_providers || [] + }; + const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } @@ -302,18 +325,11 @@ export class Client { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); }, - onReceiveMessage(message: Buffer) { + onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); } - try { - responseMessage = deserialize(message); - } catch (e) { - call.cancelWithStatus( - Status.INTERNAL, - 'Failed to parse server response' - ); - } + responseMessage = message; call.startRead(); }, onReceiveStatus(status: StatusObject) { @@ -377,32 +393,31 @@ export class Client { options?: CallOptions ): ClientReadableStream { ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); - const call: Call = this[CHANNEL_SYMBOL].createCall( - method, - options.deadline, - options.host, - null, - options.propagate_flags - ); + const methodDefinition: ClientMethodDefinition = { + path: method, + requestStream: false, + responseStream: true, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + const interceptorArgs: InterceptorArguments = { + clientInterceptors: this[INTERCEPTOR_SYMBOL], + clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], + callInterceptors: options.interceptors || [], + callInterceptorProviders: options.interceptor_providers || [] + }; + const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } - const message: Buffer = serialize(argument); - const writeObj: WriteObject = { message }; + const writeObj: WriteObject = { message: argument }; const stream = new ClientReadableStreamImpl(call, deserialize); call.start(metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); }, - onReceiveMessage(message: Buffer) { - let deserialized: ResponseType; - try { - deserialized = deserialize(message); - } catch (e) { - call.cancelWithStatus(Status.INTERNAL, 'Failed to parse server response'); - return; - } - if (stream.push(deserialized)) { + onReceiveMessage(message: any) { + if (stream.push(message)) { call.startRead(); } }, @@ -439,13 +454,20 @@ export class Client { options?: CallOptions ): ClientDuplexStream { ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); - const call: Call = this[CHANNEL_SYMBOL].createCall( - method, - options.deadline, - options.host, - null, - options.propagate_flags - ); + const methodDefinition: ClientMethodDefinition = { + path: method, + requestStream: true, + responseStream: true, + requestSerialize: serialize, + responseDeserialize: deserialize + }; + const interceptorArgs: InterceptorArguments = { + clientInterceptors: this[INTERCEPTOR_SYMBOL], + clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], + callInterceptors: options.interceptors || [], + callInterceptorProviders: options.interceptor_providers || [] + }; + const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } @@ -459,14 +481,7 @@ export class Client { stream.emit('metadata', metadata); }, onReceiveMessage(message: Buffer) { - let deserialized: ResponseType; - try { - deserialized = deserialize(message); - } catch (e) { - call.cancelWithStatus(Status.INTERNAL, 'Failed to parse server response'); - return; - } - if (stream.push(deserialized)) { + if (stream.push(message)) { call.startRead(); } }, diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index b9406fdbd..271569d84 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -252,19 +252,6 @@ export type Call = | ClientDuplexStream; /* tslint:enable:no-any */ -export type MetadataListener = (metadata: Metadata, next: Function) => void; - -// tslint:disable-next-line:no-any -export type MessageListener = (message: any, next: Function) => void; - -export type StatusListener = (status: StatusObject, next: Function) => void; - -export interface Listener { - onReceiveMetadata?: MetadataListener; - onReceiveMessage?: MessageListener; - onReceiveStatus?: StatusListener; -} - /**** Unimplemented function stubs ****/ /* tslint:disable:no-any variable-name */ @@ -299,17 +286,16 @@ export const getClientChannel = (client: Client) => { export { StatusBuilder }; -export const ListenerBuilder = () => { - throw new Error('Not yet implemented'); -}; - -export const InterceptorBuilder = () => { - throw new Error('Not yet implemented'); -}; +export { Listener } from './call-stream'; -export const InterceptingCall = () => { - throw new Error('Not yet implemented'); -}; +export { + Requester, + ListenerBuilder, + RequesterBuilder, + Interceptor, + InterceptorProvider, + InterceptingCall, + InterceptorConfigurationError } from './client-interceptors'; export { GrpcObject } from './make-client'; diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index fc44c6741..9f0bd76a9 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -27,17 +27,27 @@ export interface Deserialize { (bytes: Buffer): T; } -export interface MethodDefinition { +export interface ClientMethodDefinition { path: string; requestStream: boolean; responseStream: boolean; requestSerialize: Serialize; + responseDeserialize: Deserialize; + originalName?: string; +} + +export interface ServerMethodDefinition { + path: string; + requestStream: boolean; + responseStream: boolean; responseSerialize: Serialize; requestDeserialize: Deserialize; - responseDeserialize: Deserialize; originalName?: string; } +export interface MethodDefinition extends ClientMethodDefinition, ServerMethodDefinition { +} + export interface ServiceDefinition { [index: string]: MethodDefinition; } diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index f703e1c86..e6224f8fd 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit f703e1c86c1504d9e48953f8da31f842679b7775 +Subproject commit e6224f8fd9e4903238cebf22b9d78d09e52c378c diff --git a/test/api/client_interceptors_test.js b/test/api/client_interceptors_test.js new file mode 100644 index 000000000..9922ca975 --- /dev/null +++ b/test/api/client_interceptors_test.js @@ -0,0 +1,1778 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +const options = { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true +}; +var _ = require('lodash'); +var assert = require('assert'); +const anyGrpc = require('../any_grpc'); +const clientGrpc = anyGrpc.client +const serverGrpc = anyGrpc.server; +const protoLoader = require('../../packages/proto-loader'); + +var insecureCreds = clientGrpc.credentials.createInsecure(); + +const echoProtoDef = protoLoader.loadSync(__dirname + '/../proto/echo_service.proto', options); +const EchoClient = clientGrpc.loadPackageDefinition(echoProtoDef).EchoService; +const echo_service = echoProtoDef.EchoService; + +var StatusBuilder = clientGrpc.StatusBuilder; +var ListenerBuilder = clientGrpc.ListenerBuilder; +var InterceptingCall = clientGrpc.InterceptingCall; +var RequesterBuilder = clientGrpc.RequesterBuilder; +const Metadata = clientGrpc.Metadata; + +var CallRegistry = function(done, expectation, is_ordered, is_verbose) { + this.call_map = {}; + this.call_array = []; + this.done = done; + this.expectation = expectation; + this.expectation_is_array = Array.isArray(this.expectation); + this.is_ordered = is_ordered; + this.is_verbose = is_verbose; + if (is_verbose) { + console.log('Expectation: ', expectation); + } +}; + +CallRegistry.prototype.addCall = function(call_name) { + if (this.expectation_is_array) { + this.call_array.push(call_name); + if (this.is_verbose) { + console.log(this.call_array); + } + } else { + if (!this.call_map[call_name]) { + this.call_map[call_name] = 0; + } + this.call_map[call_name]++; + if (this.is_verbose) { + console.log(this.call_map); + } + } + this.maybeCallDone(); +}; + +CallRegistry.prototype.maybeCallDone = function() { + if (this.expectation_is_array) { + if (this.is_ordered) { + if (this.expectation && _.isEqual(this.expectation, this.call_array)) { + this.done(); + } + } else { + var intersection = _.intersectionWith(this.expectation, this.call_array, + _.isEqual); + if (intersection.length === this.expectation.length) { + this.done(); + } + } + } else if (this.expectation && _.isEqual(this.expectation, this.call_map)) { + this.done(); + } +}; + +describe('Client interceptors', function() { + var echo_server; + var echo_port; + var client; + + function startServer() { + echo_server = new serverGrpc.Server(); + echo_server.addService(echo_service, { + echo: function(call, callback) { + call.sendMetadata(call.metadata); + if (call.request.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + status.metadata = call.metadata; + callback(status, null); + return; + } + callback(null, call.request); + }, + echoClientStream: function(call, callback){ + call.sendMetadata(call.metadata); + var payload; + var err = null; + call.on('data', function(data) { + if (data.value === 'error') { + err = { + code: 2, + message: 'test status message' + }; + err.metadata = call.metadata; + return; + } + payload = data; + }); + call.on('end', function() { + callback(err, payload, call.metadata); + }); + }, + echoServerStream: function(call) { + call.sendMetadata(call.metadata); + if (call.request.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + status.metadata = call.metadata; + call.emit('error', status); + return; + } + call.write(call.request); + call.end(call.metadata); + }, + echoBidiStream: function(call) { + call.sendMetadata(call.metadata); + call.on('data', function(data) { + if (data.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + call.emit('error', status); + return; + } + call.write(data); + }); + call.on('end', function() { + call.end(call.metadata); + }); + } + }); + var server_credentials = serverGrpc.ServerCredentials.createInsecure(); + echo_port = echo_server.bind('localhost:0', server_credentials); + echo_server.start(); + } + + function stopServer() { + echo_server.forceShutdown(); + } + + function resetClient() { + client = new EchoClient('localhost:' + echo_port, insecureCreds); + } + + before(function() { + startServer(); + }); + beforeEach(function() { + resetClient(); + }); + after(function() { + stopServer(); + }); + + describe('execute downstream interceptors when a new call is made outbound', + function() { + var registry; + var options; + before(function() { + var stored_listener; + var stored_metadata; + var interceptor_a = function (options, nextCall) { + options.call_number = 1; + registry.addCall('construct a ' + options.call_number); + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + registry.addCall('start a ' + options.call_number); + stored_listener = listener; + stored_metadata = metadata; + next(metadata, listener); + }, + sendMessage: function (message, next) { + registry.addCall('send a ' + options.call_number); + var options2 = _.clone(options); + options2.call_number = 2; + var second_call = nextCall(options2); + second_call.start(stored_metadata); + second_call.sendMessage(message); + second_call.halfClose(); + next(message); + }, + halfClose: function (next) { + registry.addCall('close a ' + options.call_number); + next(); + } + }); + }; + + var interceptor_b = function (options, nextCall) { + registry.addCall('construct b ' + options.call_number); + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + registry.addCall('start b ' + options.call_number); + next(metadata, listener); + }, + sendMessage: function (message, next) { + registry.addCall('send b ' + options.call_number); + next(message); + }, + halfClose: function (next) { + registry.addCall('close b ' + options.call_number); + next(); + } + }); + }; + options = { + interceptors: [interceptor_a, interceptor_b] + }; + }); + var expected_calls = [ + 'construct a 1', + 'construct b 1', + 'start a 1', + 'start b 1', + 'send a 1', + 'construct b 2', + 'start b 2', + 'send b 2', + 'close b 2', + 'send b 1', + 'close a 1', + 'close b 1', + 'response' + ]; + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + client.echo(message, options, function(err, response){ + if (!err) { + registry.addCall('response'); + } + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, false); + var message = {}; + message.value = 'foo'; + var stream = client.echoClientStream(options, function(err, response) { + if (!err) { + registry.addCall('response'); + } + }); + stream.write(message); + stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoServerStream(message, options); + stream.on('data', function(data) { + registry.addCall('response'); + }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry( done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoBidiStream(options); + stream.on('data', function(data) { + registry.addCall('response'); + }); + stream.write(message); + stream.end(); + }); + }); + + + describe('execute downstream interceptors when a new call is made inbound', + function() { + var registry; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + next(metadata, { + onReceiveMetadata: function () { }, + onReceiveMessage: function (message, next) { + registry.addCall('interceptor_a'); + var second_call = nextCall(options); + second_call.start(metadata, listener); + second_call.sendMessage(message); + second_call.halfClose(); + }, + onReceiveStatus: function () { } + }); + } + }); + }; + + var interceptor_b = function (options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + next(metadata, { + onReceiveMessage: function (message, next) { + registry.addCall('interceptor_b'); + next(message); + } + }); + } + }); + }; + + options = { + interceptors: [interceptor_a, interceptor_b] + }; + + }); + var expected_calls = ['interceptor_b', 'interceptor_a', + 'interceptor_b', 'response']; + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + client.echo(message, options, function(err) { + if (!err) { + registry.addCall('response'); + } + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoClientStream(options, function(err, response) { + if (!err) { + registry.addCall('response'); + } + }); + stream.write(message); + stream.end(); + }); + }); + + it.skip('will delay operations and short circuit unary requests', function(done) { + var registry = new CallRegistry(done, ['foo_miss', 'foo_hit', 'bar_miss', + 'foo_hit_done', 'foo_miss_done', 'bar_miss_done']); + var cache = {}; + var _getCachedResponse = function(value) { + return cache[value]; + }; + var _store = function(key, value) { + cache[key] = value; + }; + + var interceptor = function(options, nextCall) { + var savedMetadata; + var startNext; + var storedListener; + var storedMessage; + var messageNext; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + savedMetadata = metadata; + storedListener = listener; + startNext = next; + }) + .withSendMessage(function(message, next) { + storedMessage = message; + messageNext = next; + }) + .withHalfClose(function(next) { + var cachedValue = _getCachedResponse(storedMessage.value); + if (cachedValue) { + var cachedMessage = {}; + cachedMessage.value = cachedValue; + registry.addCall(storedMessage.value + '_hit'); + storedListener.onReceiveMetadata(new Metadata()); + storedListener.onReceiveMessage(cachedMessage); + storedListener.onReceiveStatus( + (new StatusBuilder()).withCode(clientGrpc.status.OK).build()); + } else { + registry.addCall(storedMessage.value + '_miss'); + var newListener = (new ListenerBuilder()).withOnReceiveMessage( + function(message, next) { + _store(storedMessage.value, message.value); + next(message); + }).build(); + startNext(savedMetadata, newListener); + messageNext(storedMessage); + next(); + } + }) + .withCancel(function(message, next) { + next(); + }).build(); + + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [interceptor] + }; + + var foo_message = {}; + foo_message.value = 'foo'; + client.echo(foo_message, options, function(err, response){ + assert.equal(response.value, 'foo'); + registry.addCall('foo_miss_done'); + client.echo(foo_message, options, function(err, response){ + assert.equal(response.value, 'foo'); + registry.addCall('foo_hit_done'); + }); + }); + + var bar_message = {}; + bar_message.value = 'bar'; + client.echo(bar_message, options, function(err, response) { + assert.equal(response.value, 'bar'); + registry.addCall('bar_miss_done'); + }); + }); + + it('can retry failed messages and handle eventual success', function(done) { + var registry = new CallRegistry(done, + ['retry_foo_1', 'retry_foo_2', 'retry_foo_3', 'foo_result', + 'retry_bar_1', 'bar_result']); + var maxRetries = 3; + var retry_interceptor = function(options, nextCall) { + var savedMetadata; + var savedSendMessage; + var savedReceiveMessage; + var savedMessageNext; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + savedMetadata = metadata; + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + savedReceiveMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function(status, next) { + var retries = 0; + var retry = function(message, metadata) { + retries++; + var newCall = nextCall(options); + var receivedMessage; + newCall.start(metadata, { + onReceiveMessage: function(message) { + receivedMessage = message; + }, + onReceiveStatus: function(status) { + registry.addCall('retry_' + savedMetadata.get('name') + + '_' + retries); + if (status.code !== clientGrpc.status.OK) { + if (retries <= maxRetries) { + retry(message, metadata); + } else { + savedMessageNext(receivedMessage); + next(status); + } + } else { + registry.addCall('success_call'); + var new_status = (new StatusBuilder()) + .withCode(clientGrpc.status.OK).build(); + savedMessageNext(receivedMessage); + next(new_status); + } + } + }); + newCall.sendMessage(message); + newCall.halfClose(); + }; + if (status.code !== clientGrpc.status.OK) { + // Change the message we're sending only for test purposes + // so the server will respond without error + var newMessage = (savedMetadata.get('name')[0] === 'bar') ? + {value: 'bar'} : savedSendMessage; + retry(newMessage, savedMetadata); + } else { + savedMessageNext(savedReceiveMessage); + next(status); + } + } + ).build(); + next(metadata, new_listener); + }) + .withSendMessage(function(message, next) { + savedSendMessage = message; + next(message); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [retry_interceptor] + }; + + // Make a call which the server will return a non-OK status for + var foo_message = {value: 'error'}; + var foo_metadata = new Metadata(); + foo_metadata.set('name', 'foo'); + client.echo(foo_message, foo_metadata, options, function(err, response) { + assert.strictEqual(err.code, 2); + registry.addCall('foo_result'); + }); + + // Make a call which will fail the first time and succeed on the first + // retry + var bar_message = {value: 'error'}; + var bar_metadata = new Metadata(); + bar_metadata.set('name', 'bar'); + client.echo(bar_message, bar_metadata, options, function(err, response) { + assert.strictEqual(response.value, 'bar'); + registry.addCall('bar_result'); + }); + }); + + it('can retry and preserve interceptor order on success', function(done) { + var registry = new CallRegistry(done, + ['interceptor_c', 'retry_interceptor', 'fail_call', 'interceptor_c', + 'success_call', 'interceptor_a', 'result'], true); + var interceptor_a = function(options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + registry.addCall('interceptor_a'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var retry_interceptor = function(options, nextCall) { + var savedMetadata; + var savedMessage; + var savedMessageNext; + var sendMessageNext; + var originalMessage; + var startNext; + var originalListener; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + startNext = next; + savedMetadata = metadata; + originalListener = listener; + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + savedMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function(status, next) { + var retries = 0; + var maxRetries = 1; + var receivedMessage; + var retry = function(message, metadata) { + retries++; + var new_call = nextCall(options); + new_call.start(metadata, { + onReceiveMessage: function(message) { + receivedMessage = message; + }, + onReceiveStatus: function(status) { + if (status.code !== clientGrpc.status.OK) { + if (retries <= maxRetries) { + retry(message, metadata); + } else { + savedMessageNext(receivedMessage); + next(status); + } + } else { + registry.addCall('success_call'); + var new_status = (new StatusBuilder()) + .withCode(clientGrpc.status.OK).build(); + savedMessageNext(receivedMessage); + next(new_status); + } + } + }); + new_call.sendMessage(message); + new_call.halfClose(); + }; + registry.addCall('retry_interceptor'); + if (status.code !== clientGrpc.status.OK) { + registry.addCall('fail_call'); + var newMessage = {value: 'foo'}; + retry(newMessage, savedMetadata); + } else { + savedMessageNext(savedMessage); + next(status); + } + }).build(); + next(metadata, new_listener); + }) + .withSendMessage(function(message, next) { + sendMessageNext = next; + originalMessage = message; + next(message); + }) + .build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var interceptor_c = function(options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + registry.addCall('interceptor_c'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [interceptor_a, retry_interceptor, interceptor_c] + }; + + var message = {value: 'error'}; + client.echo(message, options, function(err, response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('result'); + }); + }); + + describe('handle interceptor errors', function (doneOuter) { + var options; + before(function () { + var foo_interceptor = function (options, nextCall) { + var savedListener; + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + savedListener = listener; + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + savedListener.onReceiveMetadata(new Metadata()); + savedListener.onReceiveMessage({ value: 'failed' }); + var error_status = (new StatusBuilder()) + .withCode(16) + .withDetails('Error in foo interceptor') + .build(); + savedListener.onReceiveStatus(error_status); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + it('with unary call', function(done) { + var message = {}; + client.echo(message, options, function(err, response) { + assert.strictEqual(err.code, 16); + assert.strictEqual(err.message, + '16 UNAUTHENTICATED: Error in foo interceptor'); + done(); + doneOuter(); + }); + }); + }); + + describe('implement fallbacks for streaming RPCs', function() { + + var options; + before(function () { + var fallback_response = { value: 'fallback' }; + var savedMessage; + var savedMessageNext; + var interceptor = function (options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function (message, next) { + savedMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function (status, next) { + if (status.code !== clientGrpc.status.OK) { + savedMessageNext(fallback_response); + next((new StatusBuilder()).withCode(clientGrpc.status.OK)); + } else { + savedMessageNext(savedMessage); + next(status); + } + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + options = { + interceptors: [interceptor] + }; + }); + it('with client streaming call', function (done) { + var registry = new CallRegistry(done, ['foo_result', 'fallback_result']); + var stream = client.echoClientStream(options, function (err, response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('foo_result'); + }); + stream.write({ value: 'foo' }); + stream.end(); + + stream = client.echoClientStream(options, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.value, 'fallback'); + registry.addCall('fallback_result'); + }); + stream.write({value: 'error'}); + stream.end(); + }); + }); + + describe('allows the call options to be modified for downstream interceptors', + function() { + var done; + var options; + var method_name; + var method_path_last; + before(function() { + var interceptor_a = function (options, nextCall) { + options.deadline = 10; + return new InterceptingCall(nextCall(options)); + }; + var interceptor_b = function (options, nextCall) { + assert.equal(options.method_definition.path, '/EchoService/' + + method_path_last); + assert.equal(options.deadline, 10); + done(); + return new InterceptingCall(nextCall(options)); + }; + + options = { + interceptors: [interceptor_a, interceptor_b], + deadline: 100 + }; + }); + + it('with unary call', function(cb) { + done = cb; + var metadata = new Metadata(); + var message = {}; + method_name = 'echo'; + method_path_last = 'Echo'; + + client.echo(message, metadata, options, function(){}); + }); + + it('with client streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + method_name = 'echoClientStream'; + method_path_last = 'EchoClientStream'; + + client.echoClientStream(metadata, options, function() {}); + }); + + it('with server streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + var message = {}; + method_name = 'echoServerStream'; + method_path_last = 'EchoServerStream'; + + client.echoServerStream(message, metadata, options); + }); + + it('with bidi streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + method_name = 'echoBidiStream'; + method_path_last = 'EchoBidiStream'; + + client.echoBidiStream(metadata, options); + }); + }); + + describe('pass accurate MethodDefinitions', function() { + var registry; + var initial_value = 'broken'; + var expected_value = 'working'; + var options; + before(function() { + var interceptor = function (options, nextCall) { + registry.addCall({ + path: options.method_definition.path, + requestStream: options.method_definition.requestStream, + responseStream: options.method_definition.responseStream + }); + var outbound = (new RequesterBuilder()) + .withSendMessage(function (message, next) { + message.value = expected_value; + next(message); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [interceptor] }; + }); + + it('with unary call', function(done) { + var unary_definition = { + path: '/EchoService/Echo', + requestStream: false, + responseStream: false + }; + registry = new CallRegistry(done, [ + unary_definition, + 'result_unary' + ]); + + var metadata = new Metadata(); + + var message = {value: initial_value}; + + client.echo(message, metadata, options, function(err, response){ + assert.equal(response.value, expected_value); + registry.addCall('result_unary'); + }); + + }); + it('with client streaming call', function(done) { + + var client_stream_definition = { + path: '/EchoService/EchoClientStream', + requestStream: true, + responseStream: false + }; + registry = new CallRegistry(done, [ + client_stream_definition, + 'result_client_stream' + ], false, true); + var metadata = new Metadata(); + var message = {value: initial_value}; + var client_stream = client.echoClientStream(metadata, options, + function(err, response) { + assert.strictEqual(response.value, expected_value); + registry.addCall('result_client_stream'); + }); + client_stream.write(message); + client_stream.end(); + + }); + it('with server streaming call', function(done) { + var server_stream_definition = { + path: '/EchoService/EchoServerStream', + responseStream: true, + requestStream: false, + }; + registry = new CallRegistry(done, [ + server_stream_definition, + 'result_server_stream' + ]); + + var metadata = new Metadata(); + var message = {value: initial_value}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function(data) { + assert.strictEqual(data.value, expected_value); + registry.addCall('result_server_stream'); + }); + + }); + it('with bidi streaming call', function(done) { + var bidi_stream_definition = { + path: '/EchoService/EchoBidiStream', + requestStream: true, + responseStream: true + }; + registry = new CallRegistry(done, [ + bidi_stream_definition, + 'result_bidi_stream' + ]); + + var metadata = new Metadata(); + var message = {value: initial_value}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(data) { + assert.strictEqual(data.value, expected_value); + registry.addCall('result_bidi_stream'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + it('uses interceptors passed to the client constructor', function(done) { + var registry = new CallRegistry(done, { + 'constructor_interceptor_a_echo': 1, + 'constructor_interceptor_b_echoServerStream': 1, + 'invocation_interceptor': 1, + 'result_unary': 1, + 'result_stream': 1, + 'result_invocation': 1 + }); + + var constructor_interceptor_a = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + registry.addCall('constructor_interceptor_a_echo'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var constructor_interceptor_b = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + registry.addCall('constructor_interceptor_b_echoServerStream'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var invocation_interceptor = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + registry.addCall('invocation_interceptor'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + + var interceptor_providers = [ + function(method_definition) { + if (!method_definition.requestStream && + !method_definition.responseStream) { + return constructor_interceptor_a; + } + }, + function(method_definition) { + if (!method_definition.requestStream && + method_definition.responseStream) { + return constructor_interceptor_b; + } + } + ]; + var constructor_options = { + interceptor_providers: interceptor_providers + }; + var int_client = new EchoClient('localhost:' + echo_port, insecureCreds, + constructor_options); + var message = {}; + int_client.echo(message, function() { + registry.addCall('result_unary'); + }); + var stream = int_client.echoServerStream(message); + stream.on('data', function() { + registry.addCall('result_stream'); + }); + + var options = { interceptors: [invocation_interceptor] }; + int_client.echo(message, options, function() { + registry.addCall('result_invocation'); + }); + }); + + it.skip('will reject conflicting interceptor options at invocation', + function(done) { + try { + client.echo('message', { + interceptors: [], + interceptor_providers: [] + }, function () {}); + } catch (e) { + assert.equal(e.name, 'InterceptorConfigurationError'); + done(); + } + }); + + it('will resolve interceptor providers at invocation', function(done) { + var constructor_interceptor = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function() { + assert(false); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var invocation_interceptor = function(options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function() { + done(); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var constructor_interceptor_providers = [ + function() { + return constructor_interceptor; + } + ]; + var invocation_interceptor_providers = [ + function() { + return invocation_interceptor; + } + ]; + var constructor_options = { + interceptor_providers: constructor_interceptor_providers + }; + var int_client = new EchoClient('localhost:' + echo_port, insecureCreds, + constructor_options); + var message = {}; + var options = { interceptor_providers: invocation_interceptor_providers }; + int_client.echo(message, options, function() {}); + }); + + describe('trigger a stack of interceptors in nested order', function() { + var registry; + var expected_calls = ['constructA', 'constructB', 'outboundA', 'outboundB', + 'inboundB', 'inboundA']; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + registry.addCall('constructA'); + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('outboundA'); + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + registry.addCall('inboundA'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new clientGrpc.InterceptingCall(nextCall(options), + outbound); + }; + var interceptor_b = function (options, nextCall) { + registry.addCall('constructB'); + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('outboundB'); + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + registry.addCall('inboundB'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [interceptor_a, interceptor_b] }; + }); + var metadata = new Metadata(); + var message = {}; + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + client.echo(message, metadata, options, function(){}); + }); + + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var client_stream = client.echoClientStream(metadata, options, + function() {}); + client_stream.write(message); + client_stream.end(); + }); + + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var stream = client.echoServerStream(message, metadata, options); + stream.on('data', function() {}); + }); + + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(){}); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger interceptors horizontally', function() { + var expected_calls = [ + 'interceptor_a_start', + 'interceptor_b_start', + 'interceptor_a_send', + 'interceptor_b_send' + ]; + var registry; + var options; + var metadata = new Metadata(); + var message = {}; + + before(function() { + var interceptor_a = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('interceptor_a_start'); + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + registry.addCall('interceptor_a_send'); + next(message); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + var interceptor_b = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('interceptor_b_start'); + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + registry.addCall('interceptor_b_send'); + next(message); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [interceptor_a, interceptor_b] }; + }); + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + client.echo(message, metadata, options, function(){}); + }); + + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var client_stream = client.echoClientStream(metadata, options, + function() {}); + client_stream.write(message); + client_stream.end(); + }); + + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var stream = client.echoServerStream(message, metadata, options); + stream.on('data', function() {}); + }); + + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(){}); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when sending metadata', function() { + var registry; + + var message = {}; + var key_names = ['original', 'foo', 'bar']; + var keys = { + original: 'originalkey', + foo: 'fookey', + bar: 'barkey' + }; + var values = { + original: 'originalvalue', + foo: 'foovalue', + bar: 'barvalue' + }; + var expected_calls = ['foo', 'bar', 'response']; + var options; + before(function () { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + metadata.add(keys.foo, values.foo); + registry.addCall('foo'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var bar_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + metadata.add(keys.bar, values.bar); + registry.addCall('bar'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor, bar_interceptor] }; + }); + + it('with unary call', function (done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + + var unary_call = client.echo(message, metadata, options, function () {}); + unary_call.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + + var client_stream = client.echoClientStream(metadata, options, + function () { + }); + client_stream.write(message); + client_stream.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + client_stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + server_stream.on('data', function() { }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function(metadata) { + var has_expected_values = _.every(key_names, function(key_name) { + return _.isEqual(metadata.get(keys[key_name]),[values[key_name]]); + }); + assert(has_expected_values); + bidi_stream.end(); + registry.addCall('response'); + }); + bidi_stream.on('data', function() { }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when sending messages', function() { + var registry; + var originalValue = 'foo'; + var expectedValue = 'bar'; + var options; + var metadata = new Metadata(); + var expected_calls = ['messageIntercepted', 'response']; + + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withSendMessage(function (message, next) { + assert.strictEqual(message.value, originalValue); + registry.addCall('messageIntercepted'); + next({ value: expectedValue }); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + + client.echo(message, metadata, options, function (err, response) { + assert.strictEqual(response.value, expectedValue); + registry.addCall('response'); + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var client_stream = client.echoClientStream(metadata, options, + function (err, response) { + assert.strictEqual(response.value, expectedValue); + registry.addCall('response'); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + registry.addCall('response'); + }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(data) { + assert.strictEqual(data.value, expectedValue); + registry.addCall('response'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when client closes the call', function() { + var registry; + var expected_calls = [ + 'response', 'halfClose' + ]; + var message = {}; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withHalfClose(function (next) { + registry.addCall('halfClose'); + next(); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + it('with unary call', function (done) { + registry = new CallRegistry(done, expected_calls); + client.echo(message, options, function (err, response) { + if (!err) { + registry.addCall('response'); + } + }); + }); + it('with client streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var client_stream = client.echoClientStream(options, + function (err, response) { }); + client_stream.write(message, function (err) { + if (!err) { + registry.addCall('response'); + } + }); + client_stream.end(); + }); + it('with server streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var server_stream = client.echoServerStream(message, options); + server_stream.on('data', function (data) { + registry.addCall('response'); + }); + }); + it('with bidi streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var bidi_stream = client.echoBidiStream(options); + bidi_stream.on('data', function (data) { + registry.addCall('response'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when the stream is canceled', function() { + var done; + var message = {}; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withCancel(function (next) { + done(); + next(); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(cb) { + done = cb; + var stream = client.echo(message, options, function() {}); + stream.cancel(); + }); + + it('with client streaming call', function(cb) { + done = cb; + var stream = client.echoClientStream(options, function() {}); + stream.cancel(); + }); + it('with server streaming call', function(cb) { + done = cb; + var stream = client.echoServerStream(message, options); + stream.cancel(); + }); + it('with bidi streaming call', function(cb) { + done = cb; + var stream = client.echoBidiStream(options); + stream.cancel(); + }); + }); + + describe('trigger when receiving metadata', function() { + var message = {}; + var expectedKey = 'foo'; + var expectedValue = 'bar'; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveMetadata( + function (metadata, next) { + metadata.add(expectedKey, expectedValue); + next(metadata); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(done) { + var metadata = new Metadata(); + var unary_call = client.echo(message, metadata, options, function () {}); + unary_call.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + }); + it('with client streaming call', function(done) { + var metadata = new Metadata(); + var client_stream = client.echoClientStream(metadata, options, + function () {}); + client_stream.write(message); + client_stream.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + client_stream.end(); + }); + it('with server streaming call', function(done) { + var metadata = new Metadata(); + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + server_stream.on('data', function() { }); + }); + it('with bidi streaming call', function(done) { + var metadata = new Metadata(); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function(metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + bidi_stream.end(); + done(); + }); + bidi_stream.on('data', function() { }); + bidi_stream.write(message); + }); + }); + + describe('trigger when sending messages', function() { + var originalValue = 'foo'; + var expectedValue = 'bar'; + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + if (!message) { + next(message); + return; + } + assert.strictEqual(message.value, originalValue); + message.value = expectedValue; + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function (done) { + var message = { value: originalValue }; + client.echo(message, metadata, options, function (err, response) { + assert.strictEqual(response.value, expectedValue); + done(); + }); + }); + it('with client streaming call', function (done) { + var message = { value: originalValue }; + var client_stream = client.echoClientStream(metadata, options, + function (err, response) { + assert.strictEqual(response.value, expectedValue); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with server streaming call', function (done) { + var message = { value: originalValue }; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + done(); + }); + }); + it('with bidi streaming call', function (done) { + var message = { value: originalValue }; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe('trigger when receiving status', function() { + var expectedStatus = 'foo'; + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveStatus( + function (status, next) { + assert.strictEqual(status.code, 2); + assert.strictEqual(status.details, 'test status message'); + var new_status = { + code: 1, + details: expectedStatus, + metadata: {} + }; + next(new_status); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + it('with unary call', function (done) { + var message = { value: 'error' }; + var unary_call = client.echo(message, metadata, options, function () { + }); + unary_call.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + }); + it('with client streaming call', function (done) { + var message = { value: 'error' }; + var client_stream = client.echoClientStream(metadata, options, + function () { + }); + client_stream.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + + it('with server streaming call', function(done) { + var message = {value: 'error'}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('error', function (err) { + }); + server_stream.on('data', function (data) { + }); + server_stream.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + }); + + it('with bidi streaming call', function(done) { + var message = {value: 'error'}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('error', function(err) {}); + bidi_stream.on('data', function(data) {}); + bidi_stream.on('status', function(status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + describe('delay streaming headers', function() { + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var startNext; + var startListener; + var startMetadata; + var methods = { + start: function (metadata, listener, next) { + startNext = next; + startListener = listener; + startMetadata = metadata; + }, + sendMessage: function (message, next) { + startMetadata.set('fromMessage', message.value); + startNext(startMetadata, startListener); + next(message); + } + }; + return new InterceptingCall(nextCall(options), methods); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with client streaming call', function (done) { + var message = { value: 'foo' }; + var client_stream = client.echoClientStream(metadata, options, + function () { }); + client_stream.on('metadata', function (metadata) { + assert.equal(metadata.get('fromMessage'), 'foo'); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with bidi streaming call', function (done) { + var message = { value: 'foo' }; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function (metadata) { + assert.equal(metadata.get('fromMessage'), 'foo'); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); + }); + + describe.only('order of operations enforced for async interceptors', function() { + it('with unary call', function(done) { + var expected_calls = [ + 'close_b', + 'message_b', + 'start_b', + 'done' + ]; + var registry = new CallRegistry(done, expected_calls, true, true); + var message = {value: 'foo'}; + var interceptor_a = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + setTimeout(function() { next(metadata, listener); }, 50); + }, + sendMessage: function(message, next) { + setTimeout(function () { next(message); }, 10); + } + }); + }; + var interceptor_b = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + registry.addCall('start_b'); + next(metadata, listener); + }, + sendMessage: function(message, next) { + registry.addCall('message_b'); + next(message); + }, + halfClose: function(next) { + registry.addCall('close_b'); + next(); + } + }); + }; + var options = { + interceptors: [interceptor_a, interceptor_b] + }; + client.echo(message, options, function(err, response) { + assert.strictEqual(err, null); + registry.addCall('done'); + }); + }); + it('with serverStreaming call', function(done) { + var expected_calls = [ + 'close_b', + 'message_b', + 'start_b', + 'done' + ]; + var registry = new CallRegistry(done, expected_calls, true, true); + var message = {value: 'foo'}; + var interceptor_a = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + setTimeout(function() { next(metadata, listener); }, 50); + }, + sendMessage: function(message, next) { + setTimeout(function () { next(message); }, 10); + } + }); + }; + var interceptor_b = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + registry.addCall('start_b'); + next(metadata, listener); + }, + sendMessage: function(message, next) { + registry.addCall('message_b'); + next(message); + }, + halfClose: function(next) { + registry.addCall('close_b'); + next(); + } + }); + }; + var options = { + interceptors: [interceptor_a, interceptor_b] + }; + var stream = client.echoServerStream(message, options); + stream.on('data', function(response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('done'); + }); + }); + }); +}); From 0fe10fd1fb7adf842c3d601e3dbdb90d42cd4631 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 1 Nov 2019 10:34:35 -0700 Subject: [PATCH 0836/1899] proto-loader: Pass file descriptors around instead of caching them separately --- packages/proto-loader/package.json | 2 +- packages/proto-loader/src/index.ts | 63 +++++++++++++----------------- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index d9ba9a794..b6e9766b8 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.2", + "version": "0.5.3", "author": "Google Inc.", "contributors": [ { diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 4e17719ef..69d22928d 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -149,8 +149,8 @@ function createSerializer(cls: Protobuf.Type): Serialize { } function createMethodDefinition( - method: Protobuf.Method, serviceName: string, - options: Options): MethodDefinition { + method: Protobuf.Method, serviceName: string, options: Options, + fileDescriptors: Buffer[]): MethodDefinition { /* This is only ever called after the corresponding root.resolveAll(), so we * can assume that the resolved request and response types are non-null */ const requestType: Protobuf.Type = method.resolvedRequestType!; @@ -165,56 +165,42 @@ function createMethodDefinition( responseDeserialize: createDeserializer(responseType, options), // TODO(murgatroid99): Find a better way to handle this originalName: camelCase(method.name), - requestType: createMessageDefinition(requestType), - responseType: createMessageDefinition(responseType) + requestType: createMessageDefinition(requestType, fileDescriptors), + responseType: createMessageDefinition(responseType, fileDescriptors) }; } function createServiceDefinition( - service: Protobuf.Service, name: string, - options: Options): ServiceDefinition { + service: Protobuf.Service, name: string, options: Options, + fileDescriptors: Buffer[]): ServiceDefinition { const def: ServiceDefinition = {}; for (const method of service.methodsArray) { - def[method.name] = createMethodDefinition(method, name, options); + def[method.name] = + createMethodDefinition(method, name, options, fileDescriptors); } return def; } -const fileDescriptorCache: Map = - new Map(); -function getFileDescriptors(root: Protobuf.Root): Buffer[] { - if (fileDescriptorCache.has(root)) { - return fileDescriptorCache.get(root)!; - } else { - const descriptorList: descriptor.IFileDescriptorProto[] = - root.toDescriptor('proto3').file; - const bufferList: Buffer[] = descriptorList.map( - value => - Buffer.from(descriptor.FileDescriptorProto.encode(value).finish())); - fileDescriptorCache.set(root, bufferList); - return bufferList; - } -} - -function createMessageDefinition(message: Protobuf.Type): - MessageTypeDefinition { +function createMessageDefinition( + message: Protobuf.Type, fileDescriptors: Buffer[]): MessageTypeDefinition { const messageDescriptor: protobuf.Message = message.toDescriptor('proto3'); return { format: 'Protocol Buffer 3 DescriptorProto', type: messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions), - fileDescriptorProtos: getFileDescriptors(message.root) + fileDescriptorProtos: fileDescriptors }; } -function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition { +function createEnumDefinition( + enumType: Protobuf.Enum, fileDescriptors: Buffer[]): EnumTypeDefinition { const enumDescriptor: protobuf.Message = enumType.toDescriptor('proto3'); return { format: 'Protocol Buffer 3 EnumDescriptorProto', type: enumDescriptor.$type.toObject(enumDescriptor, descriptorOptions), - fileDescriptorProtos: getFileDescriptors(enumType.root) + fileDescriptorProtos: fileDescriptors }; } @@ -226,14 +212,14 @@ function createEnumDefinition(enumType: Protobuf.Enum): EnumTypeDefinition { * EnumTypeDefinition; */ function createDefinition( - obj: HandledReflectionObject, name: string, - options: Options): AnyDefinition { + obj: HandledReflectionObject, name: string, options: Options, + fileDescriptors: Buffer[]): AnyDefinition { if (obj instanceof Protobuf.Service) { - return createServiceDefinition(obj, name, options); + return createServiceDefinition(obj, name, options, fileDescriptors); } else if (obj instanceof Protobuf.Type) { - return createMessageDefinition(obj); + return createMessageDefinition(obj, fileDescriptors); } else if (obj instanceof Protobuf.Enum) { - return createEnumDefinition(obj); + return createEnumDefinition(obj, fileDescriptors); } else { throw new Error('Type mismatch in reflection object handling'); } @@ -243,8 +229,13 @@ function createPackageDefinition( root: Protobuf.Root, options: Options): PackageDefinition { const def: PackageDefinition = {}; root.resolveAll(); + const descriptorList: descriptor.IFileDescriptorProto[] = + root.toDescriptor('proto3').file; + const bufferList: Buffer[] = descriptorList.map( + value => + Buffer.from(descriptor.FileDescriptorProto.encode(value).finish())); for (const [name, obj] of getAllHandledReflectionObjects(root, '')) { - def[name] = createDefinition(obj, name, options); + def[name] = createDefinition(obj, name, options, bufferList); } return def; } @@ -293,7 +284,7 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * @param options.includeDirs Paths to search for imported `.proto` files. */ export function load( - filename: string | string[], options?: Options): Promise { + filename: string|string[], options?: Options): Promise { const root: Protobuf.Root = new Protobuf.Root(); options = options || {}; if (!!options.includeDirs) { @@ -310,7 +301,7 @@ export function load( } export function loadSync( - filename: string | string[], options?: Options): PackageDefinition { + filename: string|string[], options?: Options): PackageDefinition { const root: Protobuf.Root = new Protobuf.Root(); options = options || {}; if (!!options.includeDirs) { From 93f8169139fbb4a2114b5b50b09c479e40be82ab Mon Sep 17 00:00:00 2001 From: Joram Date: Tue, 5 Nov 2019 09:59:41 +0100 Subject: [PATCH 0837/1899] refactor: simplify if statements --- packages/grpc-js/src/channel.ts | 4 +--- packages/grpc-js/src/subchannel-pool.ts | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f046ede94..ceb030a01 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -289,9 +289,7 @@ export class ChannelImplementation implements Channel { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); - if (this.subchannelPool !== undefined) { - this.subchannelPool.forceCleanup(); - } + this.subchannelPool.forceCleanup(); } getTarget() { diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 091ab6ca2..16b457d51 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -92,7 +92,7 @@ export class SubchannelPool { * Ensure that the cleanup task is spawned. */ ensureCleanupTask(): void { - if (this.global === true && this.cleanupTimer === undefined) { + if (this.global && this.cleanupTimer === undefined) { this.cleanupTimer = setInterval(() => { this.unrefUnusedSubchannels(); }, REF_CHECK_INTERVAL); From d6b3525fce309648fa84e2e7b60f49873c3c366d Mon Sep 17 00:00:00 2001 From: Sardorbek Pulatov Date: Tue, 5 Nov 2019 16:42:32 +0100 Subject: [PATCH 0838/1899] (doc): add compression documentation part of #402 --- Documentation/compression.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 Documentation/compression.md diff --git a/Documentation/compression.md b/Documentation/compression.md new file mode 100644 index 000000000..67cb12769 --- /dev/null +++ b/Documentation/compression.md @@ -0,0 +1,31 @@ +# Compression + +## Client side +The preferred method for configuring message compression on a client is to pass `options` when the client object is instantiated. + +The two options need to be passed: + +**grpc.default_compression_algorithm** (integer) + +The option keeps the value of a compression algorithm. + +Possible values for this option are: +- `0` - No compression +- `1` - Compress with DEFLATE algorithm +- `2` - Compress with GZIP algorithm +- `3` - Stream compression with GZIP algorithm + +**grpc.default_compression_level** (integer) + +The option keeps the value for the level of compression. + +Possible values for this option are: +- `0` - None +- `1` - Low level +- `2` - Medium level +- `3` - High level + +### Code example +```javascript +client = new ExampleClient("example.com", credentials.createInsecure(), {'grpc.default_compression_algorithm': 2, 'grpc.default_compression_level': 2}); +``` From 307f022fa230969c80d0f8a7b8f7b0ac11793eda Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Tue, 5 Nov 2019 15:57:31 -0800 Subject: [PATCH 0839/1899] Fixing "vector: invalid subscript" issue. --- packages/grpc-native-core/ext/call.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/ext/call.cc b/packages/grpc-native-core/ext/call.cc index 7738af369..b47451a47 100644 --- a/packages/grpc-native-core/ext/call.cc +++ b/packages/grpc-native-core/ext/call.cc @@ -685,7 +685,7 @@ NAN_METHOD(Call::StartBatch) { } Callback *callback = new Callback(callback_func); grpc_call_error error = grpc_call_start_batch( - call->wrapped_call, &ops[0], nops, + call->wrapped_call, ops.data(), nops, new struct tag(callback, op_vector.release(), call, info.This()), NULL); if (error != GRPC_CALL_OK) { return Nan::ThrowError(nanErrorWithCode("startBatch failed", error)); From 7c10ed272c05b2707e6b04cbb3d41bf59ecab9a2 Mon Sep 17 00:00:00 2001 From: Sardorbek Pulatov Date: Wed, 6 Nov 2019 12:15:09 +0100 Subject: [PATCH 0840/1899] CR fixes --- {Documentation => doc}/compression.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename {Documentation => doc}/compression.md (72%) diff --git a/Documentation/compression.md b/doc/compression.md similarity index 72% rename from Documentation/compression.md rename to doc/compression.md index 67cb12769..3510cafb6 100644 --- a/Documentation/compression.md +++ b/doc/compression.md @@ -3,11 +3,11 @@ ## Client side The preferred method for configuring message compression on a client is to pass `options` when the client object is instantiated. -The two options need to be passed: +These two options control compression behavior: -**grpc.default_compression_algorithm** (integer) +**grpc.default_compression_algorithm** (int) -The option keeps the value of a compression algorithm. +Default compression algorithm for the channel. Possible values for this option are: - `0` - No compression @@ -15,9 +15,9 @@ Possible values for this option are: - `2` - Compress with GZIP algorithm - `3` - Stream compression with GZIP algorithm -**grpc.default_compression_level** (integer) +**grpc.default_compression_level** (int) -The option keeps the value for the level of compression. +Default compression level for the channel. Possible values for this option are: - `0` - None From 5f271de8c2206b2473fbfd2d8e0c223e8677533f Mon Sep 17 00:00:00 2001 From: Joram Date: Wed, 6 Nov 2019 15:10:19 +0100 Subject: [PATCH 0841/1899] fix: cancel the cleanup task inside the unrefUnusedSubchannels function --- packages/grpc-js/src/channel.ts | 2 +- packages/grpc-js/src/subchannel-pool.ts | 21 ++++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index ceb030a01..49f57e5c3 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -289,7 +289,7 @@ export class ChannelImplementation implements Channel { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); - this.subchannelPool.forceCleanup(); + this.subchannelPool.unrefUnusedSubchannels(); } getTarget() { diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 16b457d51..68ebbbe59 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -55,7 +55,7 @@ export class SubchannelPool { * * @returns `true` if all subchannels have been unrefed. `false` otherwise. */ - unrefUnusedSubchannels(): boolean { + unrefUnusedSubchannels(): void { let allSubchannelsUnrefed = true; /* These objects are created with Object.create(null), so they do not @@ -85,7 +85,11 @@ export class SubchannelPool { /* Currently we do not delete keys with empty values. If that results * in significant memory usage we should change it. */ - return allSubchannelsUnrefed; + // Cancel the cleanup task if all subchannels have been unrefed. + if (allSubchannelsUnrefed && this.cleanupTimer !== undefined) { + clearInterval(this.cleanupTimer); + this.cleanupTimer = undefined; + } } /** @@ -102,19 +106,6 @@ export class SubchannelPool { } } - /** - * Unrefs unused subchannels and cancels the cleanup task if all - * subchannels have been unrefed. - */ - forceCleanup(): void { - const allSubchannelsUnrefed = this.unrefUnusedSubchannels(); - - if (allSubchannelsUnrefed && this.cleanupTimer !== undefined) { - clearInterval(this.cleanupTimer); - this.cleanupTimer = undefined; - } - } - /** * Get a subchannel if one already exists with exactly matching parameters. * Otherwise, create and save a subchannel with those parameters. From 821c9ab494a13be8102e7c1e5ed730dc44332e6f Mon Sep 17 00:00:00 2001 From: Joram Date: Wed, 6 Nov 2019 15:45:15 +0100 Subject: [PATCH 0842/1899] fix: correct comments --- packages/grpc-js/src/subchannel-pool.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 68ebbbe59..bbc3f1ccf 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -51,9 +51,8 @@ export class SubchannelPool { constructor(private global: boolean) {} /** - * Unrefs all unused subchannels. - * - * @returns `true` if all subchannels have been unrefed. `false` otherwise. + * Unrefs all unused subchannels and cancels the cleanup task if all + * subchannels have been unrefed. */ unrefUnusedSubchannels(): void { let allSubchannelsUnrefed = true; @@ -93,7 +92,7 @@ export class SubchannelPool { } /** - * Ensure that the cleanup task is spawned. + * Ensures that the cleanup task is spawned. */ ensureCleanupTask(): void { if (this.global && this.cleanupTimer === undefined) { From e51a74021654a52903047b2772134c3c84a067f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Wed, 6 Nov 2019 20:32:25 +0100 Subject: [PATCH 0843/1899] refactor: use null instead of undefined to indicate that cleanupTimer is stopped --- packages/grpc-js/src/subchannel-pool.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index bbc3f1ccf..8595f0d79 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -40,7 +40,7 @@ export class SubchannelPool { /** * A timer of a task performing a periodic subchannel cleanup. */ - private cleanupTimer: NodeJS.Timer | undefined; + private cleanupTimer: NodeJS.Timer | null; /** * A pool of subchannels use for making connections. Subchannels with the @@ -85,9 +85,9 @@ export class SubchannelPool { * in significant memory usage we should change it. */ // Cancel the cleanup task if all subchannels have been unrefed. - if (allSubchannelsUnrefed && this.cleanupTimer !== undefined) { + if (allSubchannelsUnrefed && this.cleanupTimer !== null) { clearInterval(this.cleanupTimer); - this.cleanupTimer = undefined; + this.cleanupTimer = null; } } @@ -95,7 +95,7 @@ export class SubchannelPool { * Ensures that the cleanup task is spawned. */ ensureCleanupTask(): void { - if (this.global && this.cleanupTimer === undefined) { + if (this.global && this.cleanupTimer === null) { this.cleanupTimer = setInterval(() => { this.unrefUnusedSubchannels(); }, REF_CHECK_INTERVAL); From 0353dbf819e560539931a483a79a2136a82ddcb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Wed, 6 Nov 2019 20:39:36 +0100 Subject: [PATCH 0844/1899] fix: correctly initialize cleanupTimer --- packages/grpc-js/src/subchannel-pool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 8595f0d79..1b8651cbb 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -40,7 +40,7 @@ export class SubchannelPool { /** * A timer of a task performing a periodic subchannel cleanup. */ - private cleanupTimer: NodeJS.Timer | null; + private cleanupTimer: NodeJS.Timer | null = null; /** * A pool of subchannels use for making connections. Subchannels with the From fef812b2c8708389e13d053be0c9becc0401adcf Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Nov 2019 14:28:44 -0800 Subject: [PATCH 0845/1899] Handle 'too_many_pings' error from server --- packages/grpc-js/src/subchannel.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 4edce3c10..3598a9b9e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -71,6 +71,8 @@ function uniformRandom(min: number, max: number) { return Math.random() * (max - min) + min; } +const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); + export class Subchannel { /** * The subchannel's current connectivity state. Invariant: `session` === `null` @@ -275,8 +277,14 @@ export class Subchannel { ); } }); - session.once('goaway', () => { + session.once('goaway', (errorCode: number, lastStreamID: number, opaqueData: Buffer) => { if (this.session === session) { + /* See the last paragraph of + * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ + if (errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && opaqueData.equals(tooManyPingsData)) { + logging.log(LogVerbosity.ERROR, `Connection to ${this.channelTarget} rejected by server because of excess pings`); + this.keepaliveTimeMs *= 2; + } this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], ConnectivityState.IDLE From 378a55357ce9daecc03b15e342b8a5d9fe577a27 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 6 Nov 2019 16:04:34 -0800 Subject: [PATCH 0846/1899] grpc-js: Bump to 0.6.11 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d3b4a6baf..0dc403971 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.10", + "version": "0.6.11", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 845492f0b3ceced6d6c9097262bc603848a99353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Thu, 7 Nov 2019 20:42:33 +0100 Subject: [PATCH 0847/1899] fix: prevent exceeding timer limitations when backing off --- packages/grpc-js/src/subchannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3598a9b9e..2ef237457 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -283,7 +283,7 @@ export class Subchannel { * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ if (errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && opaqueData.equals(tooManyPingsData)) { logging.log(LogVerbosity.ERROR, `Connection to ${this.channelTarget} rejected by server because of excess pings`); - this.keepaliveTimeMs *= 2; + this.keepaliveTimeMs = Math.min(2 * this.keepaliveTimeMs, KEEPALIVE_TIME_MS); } this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], From a8d6c8751a53cc699dda4a673692e8e420e824ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Thu, 7 Nov 2019 21:48:35 +0100 Subject: [PATCH 0848/1899] style: rename KEEPALIVE_TIME_MS to KEEPALIVE_MAX_TIME_MS --- packages/grpc-js/src/subchannel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 2ef237457..a52c34775 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -44,7 +44,7 @@ const BACKOFF_JITTER = 0.2; /* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't * have a constant for the max signed 32 bit integer, so this is a simple way * to calculate it */ -const KEEPALIVE_TIME_MS = ~(1 << 31); +const KEEPALIVE_MAX_TIME_MS = ~(1 << 31); const KEEPALIVE_TIMEOUT_MS = 20000; export type ConnectivityStateListener = ( @@ -112,7 +112,7 @@ export class Subchannel { /** * The amount of time in between sending pings */ - private keepaliveTimeMs: number = KEEPALIVE_TIME_MS; + private keepaliveTimeMs: number = KEEPALIVE_MAX_TIME_MS; /** * The amount of time to wait for an acknowledgement after sending a ping */ @@ -283,7 +283,7 @@ export class Subchannel { * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ if (errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && opaqueData.equals(tooManyPingsData)) { logging.log(LogVerbosity.ERROR, `Connection to ${this.channelTarget} rejected by server because of excess pings`); - this.keepaliveTimeMs = Math.min(2 * this.keepaliveTimeMs, KEEPALIVE_TIME_MS); + this.keepaliveTimeMs = Math.min(2 * this.keepaliveTimeMs, KEEPALIVE_MAX_TIME_MS); } this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], From 845cfe1bd9d5bdfc45dd49fbbd4d843ef167f38a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Thu, 7 Nov 2019 22:14:24 +0100 Subject: [PATCH 0849/1899] build: add full gts configuration and fix TSLint issues --- packages/grpc-js/prettier.config.js | 5 +++++ .../grpc-js/src/load-balancer-round-robin.ts | 2 +- packages/grpc-js/src/make-client.ts | 1 + packages/grpc-js/src/subchannel.ts | 2 +- packages/grpc-js/test/test-resolver.ts | 18 +++++++++--------- packages/grpc-js/tsconfig.json | 6 ------ packages/grpc-js/tslint.json | 8 ++++++++ 7 files changed, 25 insertions(+), 17 deletions(-) create mode 100644 packages/grpc-js/prettier.config.js create mode 100644 packages/grpc-js/tslint.json diff --git a/packages/grpc-js/prettier.config.js b/packages/grpc-js/prettier.config.js new file mode 100644 index 000000000..92747c8cc --- /dev/null +++ b/packages/grpc-js/prettier.config.js @@ -0,0 +1,5 @@ +module.exports = { + proseWrap: 'always', + singleQuote: true, + trailingComma: 'es5', +}; diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 72af705d7..9faf872fc 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -107,7 +107,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { private calculateAndUpdateState() { if (this.subchannelStateCounts[ConnectivityState.READY] > 0) { const readySubchannels = this.subchannels.filter(subchannel => subchannel.getConnectivityState() === ConnectivityState.READY); - let index: number = 0; + let index = 0; if (this.currentReadyPicker !== null) { index = readySubchannels.indexOf(this.currentReadyPicker.peekNextSubchannel()); if (index < 0) { diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index fc44c6741..5e9d67115 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -39,6 +39,7 @@ export interface MethodDefinition { } export interface ServiceDefinition { + // tslint:disable-next-line no-any [index: string]: MethodDefinition; } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3598a9b9e..12a81c6a9 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -100,7 +100,7 @@ export class Subchannel { * socket disconnects. Used for ending active calls with an UNAVAILABLE * status. */ - private disconnectListeners: (() => void)[] = []; + private disconnectListeners: Array<() => void> = []; private backoffTimeout: BackoffTimeout; diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 790cd4596..aca2152c2 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -22,14 +22,14 @@ import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; -describe('Name Resolver', function() { +describe('Name Resolver', () => { describe('DNS Names', function() { // For some reason DNS queries sometimes take a long time on Windows this.timeout(4000); - before(function() { + before(() => { resolverManager.registerAll(); }); - it('Should resolve localhost properly', function(done) { + it('Should resolve localhost properly', (done) => { const target = 'localhost:50051'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -48,7 +48,7 @@ describe('Name Resolver', function() { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should default to port 443', function(done) { + it('Should default to port 443', (done) => { const target = 'localhost'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -67,7 +67,7 @@ describe('Name Resolver', function() { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a public address', function(done) { + it('Should resolve a public address', (done) => { const target = 'example.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -85,7 +85,7 @@ describe('Name Resolver', function() { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a name with multiple dots', function(done) { + it('Should resolve a name with multiple dots', (done) => { const target = 'loopback4.unittest.grpc.io'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -103,7 +103,7 @@ describe('Name Resolver', function() { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a name with a hyphen', function(done) { + it('Should resolve a name with a hyphen', (done) => { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ const target = 'network-tools.com'; @@ -123,7 +123,7 @@ describe('Name Resolver', function() { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve gRPC interop servers', function(done) { + it('Should resolve gRPC interop servers', (done) => { let completeCount = 0; function done2(error?: Error) { if (error) { @@ -156,7 +156,7 @@ describe('Name Resolver', function() { resolver2.updateResolution(); }) }); - describe('UDS Names', function() { + describe('UDS Names', () => { it('Should handle a relative Unix Domain Socket name', done => { const target = 'unix:socket'; const listener: resolverManager.ResolverListener = { diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index e47c5eea1..f60cbdc02 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -2,19 +2,13 @@ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "lib": ["es2017"], - "rootDir": ".", "outDir": "build", "target": "es2017", "module": "commonjs", "incremental": true }, "include": [ - "src/*.ts", "src/**/*.ts", - "test/*.ts", "test/**/*.ts" - ], - "exclude": [ - "node_modules" ] } diff --git a/packages/grpc-js/tslint.json b/packages/grpc-js/tslint.json new file mode 100644 index 000000000..27872a139 --- /dev/null +++ b/packages/grpc-js/tslint.json @@ -0,0 +1,8 @@ +{ + "extends": "gts/tslint.json", + "linterOptions": { + "exclude": [ + "**/*.json" + ] + } +} From c0f53f223844b8ce2155ebe0fa60d9cc376548d8 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Fri, 18 Oct 2019 22:01:37 +0200 Subject: [PATCH 0850/1899] fix: only unref timers in supported environments fix #1077 --- packages/grpc-js/src/subchannel-pool.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 1b8651cbb..d7bccb22f 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -101,7 +101,7 @@ export class SubchannelPool { }, REF_CHECK_INTERVAL); // Unref because this timer should not keep the event loop running. - this.cleanupTimer.unref(); + this.cleanupTimer.unref && this.cleanupTimer.unref(); } } From 989288c1f03f651fade22b28c57ef10187da863e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 7 Nov 2019 17:22:03 -0800 Subject: [PATCH 0851/1899] grpc-js: Add detail to invalid metadata error --- packages/grpc-js/src/metadata.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 67a23960c..873e5ff53 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -16,6 +16,8 @@ */ import * as http2 from 'http2'; +import { log } from './logging'; +import { LogVerbosity } from './constants'; const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; @@ -272,8 +274,8 @@ export class Metadata { } } } catch (error) { - error.message = `Failed to add metadata entry ${key}: ${values}. ${error.message}`; - process.emitWarning(error); + const message = `Failed to add metadata entry ${key}: ${values}. ${error.message}. For more information see https://github.com/grpc/grpc-node/issues/1173`; + log(LogVerbosity.ERROR, message); } }); return result; From 50067fe9c4b3dd6303d96b57b3c79a27c89acd7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Fri, 8 Nov 2019 08:01:18 +0100 Subject: [PATCH 0852/1899] style(grpc-js): format files using gts --- packages/grpc-js/src/call-stream.ts | 11 ++- packages/grpc-js/src/call.ts | 7 +- packages/grpc-js/src/channel.ts | 18 +++-- packages/grpc-js/src/compression-filter.ts | 4 +- packages/grpc-js/src/index.ts | 8 +-- .../grpc-js/src/load-balancer-pick-first.ts | 53 ++++++++++---- .../grpc-js/src/load-balancer-round-robin.ts | 70 +++++++++++++------ packages/grpc-js/src/logging.ts | 16 +++-- packages/grpc-js/src/resolver-dns.ts | 11 ++- .../grpc-js/src/resolving-load-balancer.ts | 23 ++++-- packages/grpc-js/src/service-config.ts | 4 +- packages/grpc-js/src/subchannel-pool.ts | 9 ++- packages/grpc-js/src/subchannel.ts | 44 ++++++++---- packages/grpc-js/test/test-resolver.ts | 14 ++-- 14 files changed, 194 insertions(+), 98 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index a53dbefa8..d8655cf74 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -127,7 +127,11 @@ export class Http2CallStream extends Duplex implements Call { this.filterStack = filterStackFactory.createFilter(this); this.credentials = channelCallCredentials; this.disconnectListener = () => { - this.endCall({code: Status.UNAVAILABLE, details: 'Connection dropped', metadata: new Metadata()}); + this.endCall({ + code: Status.UNAVAILABLE, + details: 'Connection dropped', + metadata: new Metadata(), + }); }; } @@ -250,7 +254,10 @@ export class Http2CallStream extends Duplex implements Call { })(); } - attachHttp2Stream(stream: http2.ClientHttp2Stream, subchannel: Subchannel): void { + attachHttp2Stream( + stream: http2.ClientHttp2Stream, + subchannel: Subchannel + ): void { if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 5734bc3d0..bc0115f3d 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -72,14 +72,11 @@ export type ClientDuplexStream< * Construct a ServiceError from a StatusObject. This function exists primarily * as an attempt to make the error stack trace clearly communicate that the * error is not necessarily a problem in gRPC itself. - * @param status + * @param status */ export function callErrorFromStatus(status: StatusObject): ServiceError { const message = `${status.code} ${Status[status.code]}: ${status.details}`; - return Object.assign( - new Error(message), - status - ); + return Object.assign(new Error(message), status); } export class ClientUnaryCallImpl extends EventEmitter diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 49f57e5c3..c1ab84595 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -165,7 +165,9 @@ export class ChannelImplementation implements Channel { methodConfig: [], }; if (options['grpc.service_config']) { - defaultServiceConfig = validateServiceConfig(JSON.parse(options['grpc.service_config']!)); + defaultServiceConfig = validateServiceConfig( + JSON.parse(options['grpc.service_config']!) + ); } this.resolvingLoadBalancer = new ResolvingLoadBalancer( target, @@ -229,9 +231,7 @@ export class ChannelImplementation implements Channel { // We assume the error code isn't 0 (Status.OK) callStream.cancelWithStatus( error.code || Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${ - error.message - }` + `Getting metadata from plugin failed with error: ${error.message}` ); } ); @@ -269,7 +269,15 @@ export class ChannelImplementation implements Channel { } private updateState(newState: ConnectivityState): void { - trace(LogVerbosity.DEBUG, 'connectivity_state', this.target + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + trace( + LogVerbosity.DEBUG, + 'connectivity_state', + this.target + + ' ' + + ConnectivityState[this.connectivityState] + + ' -> ' + + ConnectivityState[newState] + ); this.connectivityState = newState; const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 34b7574fb..fb95d9de0 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -138,9 +138,7 @@ class UnknownHandler extends CompressionHandler { compressMessage(message: Buffer): Promise { return Promise.reject( new Error( - `Received message compressed with unsupported compression method ${ - this.compressionName - }` + `Received message compressed with unsupported compression method ${this.compressionName}` ) ); } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index b9406fdbd..9576e39e8 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -36,7 +36,7 @@ import { loadPackageDefinition, makeClientConstructor, Serialize, - ServiceDefinition + ServiceDefinition, } from './make-client'; import { Metadata } from './metadata'; import { @@ -238,11 +238,7 @@ export { /**** Server ****/ -export { - handleBidiStreamingCall, - handleServerStreamingCall, - handleUnaryCall, -}; +export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall }; /* tslint:disable:no-any */ export type Call = diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index dfa9d78a7..a5fbf0fa9 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -65,11 +65,11 @@ class PickFirstPicker implements Picker { } interface ConnectivityStateCounts { - [ConnectivityState.CONNECTING]: number, - [ConnectivityState.IDLE]: number, - [ConnectivityState.READY]: number, - [ConnectivityState.SHUTDOWN]: number, - [ConnectivityState.TRANSIENT_FAILURE]: number + [ConnectivityState.CONNECTING]: number; + [ConnectivityState.IDLE]: number; + [ConnectivityState.READY]: number; + [ConnectivityState.SHUTDOWN]: number; + [ConnectivityState.TRANSIENT_FAILURE]: number; } export class PickFirstLoadBalancer implements LoadBalancer { @@ -129,7 +129,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { [ConnectivityState.IDLE]: 0, [ConnectivityState.READY]: 0, [ConnectivityState.SHUTDOWN]: 0, - [ConnectivityState.TRANSIENT_FAILURE]: 0 + [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannelStateListener = ( subchannel: Subchannel, @@ -152,7 +152,11 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.pickSubchannel(subchannel); return; } else { - if (this.triedAllSubchannels && this.subchannelStateCounts[ConnectivityState.IDLE] === this.subchannels.length) { + if ( + this.triedAllSubchannels && + this.subchannelStateCounts[ConnectivityState.IDLE] === + this.subchannels.length + ) { /* If all of the subchannels are IDLE we should go back to a * basic IDLE state where there is no subchannel list to avoid * holding unused resources */ @@ -163,7 +167,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { let newLBState: ConnectivityState; if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { newLBState = ConnectivityState.CONNECTING; - } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { + } else if ( + this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > + 0 + ) { newLBState = ConnectivityState.TRANSIENT_FAILURE; } else { newLBState = ConnectivityState.IDLE; @@ -200,7 +207,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { let newLBState: ConnectivityState; if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { newLBState = ConnectivityState.CONNECTING; - } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { + } else if ( + this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > + 0 + ) { newLBState = ConnectivityState.TRANSIENT_FAILURE; } else { newLBState = ConnectivityState.IDLE; @@ -259,7 +269,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.subchannels[subchannelIndex].getConnectivityState() === ConnectivityState.IDLE ) { - trace('Start connecting to subchannel with address ' + this.subchannels[subchannelIndex].getAddress()); + trace( + 'Start connecting to subchannel with address ' + + this.subchannels[subchannelIndex].getAddress() + ); process.nextTick(() => { this.subchannels[subchannelIndex].startConnecting(); }); @@ -286,7 +299,11 @@ export class PickFirstLoadBalancer implements LoadBalancer { } private updateState(newState: ConnectivityState, picker: Picker) { - trace(ConnectivityState[this.currentState] + ' -> ' + ConnectivityState[newState]); + trace( + ConnectivityState[this.currentState] + + ' -> ' + + ConnectivityState[newState] + ); this.currentState = newState; this.channelControlHelper.updateState(newState, picker); } @@ -302,7 +319,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { [ConnectivityState.IDLE]: 0, [ConnectivityState.READY]: 0, [ConnectivityState.SHUTDOWN]: 0, - [ConnectivityState.TRANSIENT_FAILURE]: 0 + [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannels = []; this.triedAllSubchannels = false; @@ -359,7 +376,12 @@ export class PickFirstLoadBalancer implements LoadBalancer { /* To avoid unnecessary churn, we only do something with this address list * if we're not currently trying to establish a connection, or if the new * address list is different from the existing one */ - if (this.subchannels.length === 0 || !this.latestAddressList.every((value, index) => addressList[index] === value)) { + if ( + this.subchannels.length === 0 || + !this.latestAddressList.every( + (value, index) => addressList[index] === value + ) + ) { this.latestAddressList = addressList; this.connectToAddressList(); } @@ -374,7 +396,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.connectToAddressList(); } } - if (this.currentState === ConnectivityState.IDLE || this.triedAllSubchannels) { + if ( + this.currentState === ConnectivityState.IDLE || + this.triedAllSubchannels + ) { this.channelControlHelper.requestReresolution(); } } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 9faf872fc..e3eedfe5f 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -35,7 +35,10 @@ import { Subchannel, ConnectivityStateListener } from './subchannel'; const TYPE_NAME = 'round_robin'; class RoundRobinPicker implements Picker { - constructor(private readonly subchannelList: Subchannel[], private nextIndex = 0) {} + constructor( + private readonly subchannelList: Subchannel[], + private nextIndex = 0 + ) {} pick(pickArgs: PickArgs): CompletePickResult { const pickedSubchannel = this.subchannelList[this.nextIndex]; @@ -43,7 +46,7 @@ class RoundRobinPicker implements Picker { return { pickResultType: PickResultType.COMPLETE, subchannel: pickedSubchannel, - status: null + status: null, }; } @@ -58,15 +61,14 @@ class RoundRobinPicker implements Picker { } interface ConnectivityStateCounts { - [ConnectivityState.CONNECTING]: number, - [ConnectivityState.IDLE]: number, - [ConnectivityState.READY]: number, - [ConnectivityState.SHUTDOWN]: number, - [ConnectivityState.TRANSIENT_FAILURE]: number + [ConnectivityState.CONNECTING]: number; + [ConnectivityState.IDLE]: number; + [ConnectivityState.READY]: number; + [ConnectivityState.SHUTDOWN]: number; + [ConnectivityState.TRANSIENT_FAILURE]: number; } export class RoundRobinLoadBalancer implements LoadBalancer { - private subchannels: Subchannel[] = []; private currentState: ConnectivityState = ConnectivityState.IDLE; @@ -84,7 +86,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { [ConnectivityState.IDLE]: 0, [ConnectivityState.READY]: 0, [ConnectivityState.SHUTDOWN]: 0, - [ConnectivityState.TRANSIENT_FAILURE]: 0 + [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannelStateListener = ( subchannel: Subchannel, @@ -98,27 +100,43 @@ export class RoundRobinLoadBalancer implements LoadBalancer { if (newState === ConnectivityState.TRANSIENT_FAILURE) { this.channelControlHelper.requestReresolution(); } - if (newState === ConnectivityState.TRANSIENT_FAILURE || newState === ConnectivityState.IDLE) { + if ( + newState === ConnectivityState.TRANSIENT_FAILURE || + newState === ConnectivityState.IDLE + ) { subchannel.startConnecting(); } - } + }; } private calculateAndUpdateState() { if (this.subchannelStateCounts[ConnectivityState.READY] > 0) { - const readySubchannels = this.subchannels.filter(subchannel => subchannel.getConnectivityState() === ConnectivityState.READY); + const readySubchannels = this.subchannels.filter( + subchannel => + subchannel.getConnectivityState() === ConnectivityState.READY + ); let index = 0; if (this.currentReadyPicker !== null) { - index = readySubchannels.indexOf(this.currentReadyPicker.peekNextSubchannel()); + index = readySubchannels.indexOf( + this.currentReadyPicker.peekNextSubchannel() + ); if (index < 0) { index = 0; } } - this.updateState(ConnectivityState.READY, new RoundRobinPicker(readySubchannels, index)); + this.updateState( + ConnectivityState.READY, + new RoundRobinPicker(readySubchannels, index) + ); } else if (this.subchannelStateCounts[ConnectivityState.CONNECTING] > 0) { this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); - } else if (this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0) { - this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker()); + } else if ( + this.subchannelStateCounts[ConnectivityState.TRANSIENT_FAILURE] > 0 + ) { + this.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker() + ); } else { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); } @@ -144,18 +162,26 @@ export class RoundRobinLoadBalancer implements LoadBalancer { [ConnectivityState.IDLE]: 0, [ConnectivityState.READY]: 0, [ConnectivityState.SHUTDOWN]: 0, - [ConnectivityState.TRANSIENT_FAILURE]: 0 + [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannels = []; } - updateAddressList(addressList: string[], lbConfig: LoadBalancingConfig | null): void { + updateAddressList( + addressList: string[], + lbConfig: LoadBalancingConfig | null + ): void { this.resetSubchannelList(); - this.subchannels = addressList.map(address => this.channelControlHelper.createSubchannel(address, {})); + this.subchannels = addressList.map(address => + this.channelControlHelper.createSubchannel(address, {}) + ); for (const subchannel of this.subchannels) { const subchannelState = subchannel.getConnectivityState(); this.subchannelStateCounts[subchannelState] += 1; - if (subchannelState === ConnectivityState.IDLE || subchannelState === ConnectivityState.TRANSIENT_FAILURE) { + if ( + subchannelState === ConnectivityState.IDLE || + subchannelState === ConnectivityState.TRANSIENT_FAILURE + ) { subchannel.startConnecting(); } } @@ -177,7 +203,9 @@ export class RoundRobinLoadBalancer implements LoadBalancer { getTypeName(): string { return TYPE_NAME; } - replaceChannelControlHelper(channelControlHelper: ChannelControlHelper): void { + replaceChannelControlHelper( + channelControlHelper: ChannelControlHelper + ): void { this.channelControlHelper = channelControlHelper; } } diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 31e38e4d6..13ed2b7e6 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -32,7 +32,7 @@ if (process.env.GRPC_VERBOSITY) { _logVerbosity = LogVerbosity.ERROR; break; default: - // Ignore any other values + // Ignore any other values } } @@ -55,11 +55,17 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { } }; -const enabledTracers = process.env.GRPC_TRACE ? process.env.GRPC_TRACE.split(',') : []; +const enabledTracers = process.env.GRPC_TRACE + ? process.env.GRPC_TRACE.split(',') + : []; const allEnabled = enabledTracers.includes('all'); -export function trace(severity: LogVerbosity, tracer: string, text: string): void { +export function trace( + severity: LogVerbosity, + tracer: string, + text: string +): void { if (allEnabled || enabledTracers.includes(tracer)) { - log(severity, (new Date().toISOString() + ' | ' + tracer + ' | ' + text)); + log(severity, new Date().toISOString() + ' | ' + tracer + ' | ' + text); } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index a6b0ae164..e98bf66b5 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -232,7 +232,9 @@ class DnsResolver implements Resolver { ip4Addresses, ip6Addresses ); - trace('Resolved addresses for target ' + this.target + ': ' + allAddresses); + trace( + 'Resolved addresses for target ' + this.target + ': ' + allAddresses + ); if (allAddresses.length === 0) { this.listener.onError(this.defaultResolutionError); return; @@ -266,7 +268,12 @@ class DnsResolver implements Resolver { ); }, err => { - trace('Resolution error for target ' + this.target + ': ' + (err as Error).message); + trace( + 'Resolution error for target ' + + this.target + + ': ' + + (err as Error).message + ); this.pendingResultPromise = null; this.listener.onError(this.defaultResolutionError); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 838353a90..496e13450 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -341,13 +341,22 @@ export class ResolvingLoadBalancer implements LoadBalancer { private updateResolution() { this.innerResolver.updateResolution(); - if (this.innerLoadBalancer === null || this.innerBalancerState === ConnectivityState.IDLE) { + if ( + this.innerLoadBalancer === null || + this.innerBalancerState === ConnectivityState.IDLE + ) { this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } } private updateState(connectivitystate: ConnectivityState, picker: Picker) { - trace(this.target + ' ' + ConnectivityState[this.currentState] + ' -> ' + ConnectivityState[connectivitystate]); + trace( + this.target + + ' ' + + ConnectivityState[this.currentState] + + ' -> ' + + ConnectivityState[connectivitystate] + ); this.currentState = connectivitystate; this.channelControlHelper.updateState(connectivitystate, picker); } @@ -373,7 +382,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { } private handleResolutionFailure(error: StatusObject) { - if (this.innerLoadBalancer === null || this.innerBalancerState === ConnectivityState.IDLE) { + if ( + this.innerLoadBalancer === null || + this.innerBalancerState === ConnectivityState.IDLE + ) { this.updateState( ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error) @@ -392,10 +404,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } else { this.updateResolution(); } - this.updateState( - ConnectivityState.CONNECTING, - new QueuePicker(this) - ); + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } } diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index fc8cda043..e4631507b 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -162,9 +162,7 @@ export function validateServiceConfig(obj: any): ServiceConfig { name.method === seenName.method ) { throw new Error( - `Invalid service config: duplicate name ${name.service}/${ - name.method - }` + `Invalid service config: duplicate name ${name.service}/${name.method}` ); } } diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 1b8651cbb..009141e39 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -64,12 +64,11 @@ export class SubchannelPool { for (const channelTarget in this.pool) { // tslint:disable-next-line:forin for (const subchannelTarget in this.pool[channelTarget]) { - const subchannelObjArray = this.pool[channelTarget][ - subchannelTarget - ]; + const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; - const refedSubchannels = subchannelObjArray - .filter(value => !value.subchannel.unrefIfOneRef()); + const refedSubchannels = subchannelObjArray.filter( + value => !value.subchannel.unrefIfOneRef() + ); if (refedSubchannels.length > 0) { allSubchannelsUnrefed = false; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3ca2aa3f7..eae178e78 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -277,20 +277,32 @@ export class Subchannel { ); } }); - session.once('goaway', (errorCode: number, lastStreamID: number, opaqueData: Buffer) => { - if (this.session === session) { - /* See the last paragraph of - * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ - if (errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && opaqueData.equals(tooManyPingsData)) { - logging.log(LogVerbosity.ERROR, `Connection to ${this.channelTarget} rejected by server because of excess pings`); - this.keepaliveTimeMs = Math.min(2 * this.keepaliveTimeMs, KEEPALIVE_MAX_TIME_MS); + session.once( + 'goaway', + (errorCode: number, lastStreamID: number, opaqueData: Buffer) => { + if (this.session === session) { + /* See the last paragraph of + * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ + if ( + errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && + opaqueData.equals(tooManyPingsData) + ) { + logging.log( + LogVerbosity.ERROR, + `Connection to ${this.channelTarget} rejected by server because of excess pings` + ); + this.keepaliveTimeMs = Math.min( + 2 * this.keepaliveTimeMs, + KEEPALIVE_MAX_TIME_MS + ); + } + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.IDLE + ); } - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.IDLE - ); } - }); + ); session.once('error', error => { /* Do nothing here. Any error should also trigger a close event, which is * where we want to handle that. */ @@ -311,7 +323,13 @@ export class Subchannel { if (oldStates.indexOf(this.connectivityState) === -1) { return false; } - trace(this.subchannelAddress + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + trace( + this.subchannelAddress + + ' ' + + ConnectivityState[this.connectivityState] + + ' -> ' + + ConnectivityState[newState] + ); const previousState = this.connectivityState; this.connectivityState = newState; switch (newState) { diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index aca2152c2..a5a6a77eb 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -29,7 +29,7 @@ describe('Name Resolver', () => { before(() => { resolverManager.registerAll(); }); - it('Should resolve localhost properly', (done) => { + it('Should resolve localhost properly', done => { const target = 'localhost:50051'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -48,7 +48,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should default to port 443', (done) => { + it('Should default to port 443', done => { const target = 'localhost'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -67,7 +67,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a public address', (done) => { + it('Should resolve a public address', done => { const target = 'example.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -85,7 +85,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a name with multiple dots', (done) => { + it('Should resolve a name with multiple dots', done => { const target = 'loopback4.unittest.grpc.io'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -103,7 +103,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a name with a hyphen', (done) => { + it('Should resolve a name with a hyphen', done => { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ const target = 'network-tools.com'; @@ -123,7 +123,7 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve gRPC interop servers', (done) => { + it('Should resolve gRPC interop servers', done => { let completeCount = 0; function done2(error?: Error) { if (error) { @@ -154,7 +154,7 @@ describe('Name Resolver', () => { resolver1.updateResolution(); const resolver2 = resolverManager.createResolver(target1, listener); resolver2.updateResolution(); - }) + }); }); describe('UDS Names', () => { it('Should handle a relative Unix Domain Socket name', done => { From 8cbda9b03c3416d87d0f4059a7bb0b1c26a2f299 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Natan=20S=C4=85gol?= Date: Fri, 8 Nov 2019 08:09:40 +0100 Subject: [PATCH 0853/1899] build(proto-loader): add full gts configuration and fix reported issues --- packages/proto-loader/package.json | 2 +- packages/proto-loader/prettier.config.js | 5 + packages/proto-loader/src/index.ts | 187 ++++++++++++------ .../proto-loader/test/descriptor_type_test.ts | 115 ++++++----- packages/proto-loader/tsconfig.json | 4 +- packages/proto-loader/tslint.json | 8 + 6 files changed, 199 insertions(+), 122 deletions(-) create mode 100644 packages/proto-loader/prettier.config.js create mode 100644 packages/proto-loader/tslint.json diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index b6e9766b8..c558633f4 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -46,7 +46,7 @@ "@types/lodash.camelcase": "^4.3.4", "@types/node": "^10.12.5", "clang-format": "^1.2.2", - "gts": "^0.5.3", + "gts": "^1.1.0", "typescript": "~3.3.3333" }, "engines": { diff --git a/packages/proto-loader/prettier.config.js b/packages/proto-loader/prettier.config.js new file mode 100644 index 000000000..92747c8cc --- /dev/null +++ b/packages/proto-loader/prettier.config.js @@ -0,0 +1,5 @@ +module.exports = { + proseWrap: 'always', + singleQuote: true, + trailingComma: 'es5', +}; diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 69d22928d..c5533a5e0 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -24,25 +24,34 @@ import camelCase = require('lodash.camelcase'); declare module 'protobufjs' { interface Type { - toDescriptor(protoVersion: string): Protobuf - .Message&descriptor.IDescriptorProto; + toDescriptor( + protoVersion: string + ): Protobuf.Message & + descriptor.IDescriptorProto; } interface Root { - toDescriptor(protoVersion: string): Protobuf - .Message&descriptor.IFileDescriptorSet; + toDescriptor( + protoVersion: string + ): Protobuf.Message & + descriptor.IFileDescriptorSet; } interface Enum { - toDescriptor(protoVersion: string): - Protobuf.Message& - descriptor.IEnumDescriptorProto; + toDescriptor( + protoVersion: string + ): Protobuf.Message & + descriptor.IEnumDescriptorProto; } } -export interface Serialize { (value: T): Buffer; } +export interface Serialize { + (value: T): Buffer; +} -export interface Deserialize { (bytes: Buffer): T; } +export interface Deserialize { + (bytes: Buffer): T; +} export interface ProtobufTypeDefinition { format: string; @@ -76,13 +85,18 @@ export interface ServiceDefinition { } export type AnyDefinition = - ServiceDefinition|MessageTypeDefinition|EnumTypeDefinition; + | ServiceDefinition + | MessageTypeDefinition + | EnumTypeDefinition; -export interface PackageDefinition { [index: string]: AnyDefinition; } +export interface PackageDefinition { + [index: string]: AnyDefinition; +} -export type Options = Protobuf.IParseOptions&Protobuf.IConversionOptions&{ - includeDirs?: string[]; -}; +export type Options = Protobuf.IParseOptions & + Protobuf.IConversionOptions & { + includeDirs?: string[]; + }; const descriptorOptions: Protobuf.IConversionOptions = { longs: String, @@ -90,7 +104,7 @@ const descriptorOptions: Protobuf.IConversionOptions = { bytes: String, defaults: true, oneofs: true, - json: true + json: true, }; function joinName(baseName: string, name: string): string { @@ -101,41 +115,50 @@ function joinName(baseName: string, name: string): string { } } -type HandledReflectionObject = Protobuf.Service|Protobuf.Type|Protobuf.Enum; +type HandledReflectionObject = Protobuf.Service | Protobuf.Type | Protobuf.Enum; -function isHandledReflectionObject(obj: Protobuf.ReflectionObject): - obj is HandledReflectionObject { - return obj instanceof Protobuf.Service || obj instanceof Protobuf.Type || - obj instanceof Protobuf.Enum; +function isHandledReflectionObject( + obj: Protobuf.ReflectionObject +): obj is HandledReflectionObject { + return ( + obj instanceof Protobuf.Service || + obj instanceof Protobuf.Type || + obj instanceof Protobuf.Enum + ); } -function isNamespaceBase(obj: Protobuf.ReflectionObject): - obj is Protobuf.NamespaceBase { +function isNamespaceBase( + obj: Protobuf.ReflectionObject +): obj is Protobuf.NamespaceBase { return obj instanceof Protobuf.Namespace || obj instanceof Protobuf.Root; } function getAllHandledReflectionObjects( - obj: Protobuf.ReflectionObject, - parentName: string): Array<[string, HandledReflectionObject]> { + obj: Protobuf.ReflectionObject, + parentName: string +): Array<[string, HandledReflectionObject]> { const objName = joinName(parentName, obj.name); if (isHandledReflectionObject(obj)) { return [[objName, obj]]; } else { if (isNamespaceBase(obj) && typeof obj.nested !== 'undefined') { return Object.keys(obj.nested!) - .map((name) => { - return getAllHandledReflectionObjects(obj.nested![name], objName); - }) - .reduce( - (accumulator, currentValue) => accumulator.concat(currentValue), - []); + .map(name => { + return getAllHandledReflectionObjects(obj.nested![name], objName); + }) + .reduce( + (accumulator, currentValue) => accumulator.concat(currentValue), + [] + ); } } return []; } function createDeserializer( - cls: Protobuf.Type, options: Options): Deserialize { + cls: Protobuf.Type, + options: Options +): Deserialize { return function deserialize(argBuf: Buffer): object { return cls.toObject(cls.decode(argBuf), options); }; @@ -149,8 +172,11 @@ function createSerializer(cls: Protobuf.Type): Serialize { } function createMethodDefinition( - method: Protobuf.Method, serviceName: string, options: Options, - fileDescriptors: Buffer[]): MethodDefinition { + method: Protobuf.Method, + serviceName: string, + options: Options, + fileDescriptors: Buffer[] +): MethodDefinition { /* This is only ever called after the corresponding root.resolveAll(), so we * can assume that the resolved request and response types are non-null */ const requestType: Protobuf.Type = method.resolvedRequestType!; @@ -166,41 +192,56 @@ function createMethodDefinition( // TODO(murgatroid99): Find a better way to handle this originalName: camelCase(method.name), requestType: createMessageDefinition(requestType, fileDescriptors), - responseType: createMessageDefinition(responseType, fileDescriptors) + responseType: createMessageDefinition(responseType, fileDescriptors), }; } function createServiceDefinition( - service: Protobuf.Service, name: string, options: Options, - fileDescriptors: Buffer[]): ServiceDefinition { + service: Protobuf.Service, + name: string, + options: Options, + fileDescriptors: Buffer[] +): ServiceDefinition { const def: ServiceDefinition = {}; for (const method of service.methodsArray) { - def[method.name] = - createMethodDefinition(method, name, options, fileDescriptors); + def[method.name] = createMethodDefinition( + method, + name, + options, + fileDescriptors + ); } return def; } function createMessageDefinition( - message: Protobuf.Type, fileDescriptors: Buffer[]): MessageTypeDefinition { - const messageDescriptor: protobuf.Message = - message.toDescriptor('proto3'); + message: Protobuf.Type, + fileDescriptors: Buffer[] +): MessageTypeDefinition { + const messageDescriptor: protobuf.Message< + descriptor.IDescriptorProto + > = message.toDescriptor('proto3'); return { format: 'Protocol Buffer 3 DescriptorProto', - type: - messageDescriptor.$type.toObject(messageDescriptor, descriptorOptions), - fileDescriptorProtos: fileDescriptors + type: messageDescriptor.$type.toObject( + messageDescriptor, + descriptorOptions + ), + fileDescriptorProtos: fileDescriptors, }; } function createEnumDefinition( - enumType: Protobuf.Enum, fileDescriptors: Buffer[]): EnumTypeDefinition { - const enumDescriptor: protobuf.Message = - enumType.toDescriptor('proto3'); + enumType: Protobuf.Enum, + fileDescriptors: Buffer[] +): EnumTypeDefinition { + const enumDescriptor: protobuf.Message< + descriptor.IEnumDescriptorProto + > = enumType.toDescriptor('proto3'); return { format: 'Protocol Buffer 3 EnumDescriptorProto', type: enumDescriptor.$type.toObject(enumDescriptor, descriptorOptions), - fileDescriptorProtos: fileDescriptors + fileDescriptorProtos: fileDescriptors, }; } @@ -212,8 +253,11 @@ function createEnumDefinition( * EnumTypeDefinition; */ function createDefinition( - obj: HandledReflectionObject, name: string, options: Options, - fileDescriptors: Buffer[]): AnyDefinition { + obj: HandledReflectionObject, + name: string, + options: Options, + fileDescriptors: Buffer[] +): AnyDefinition { if (obj instanceof Protobuf.Service) { return createServiceDefinition(obj, name, options, fileDescriptors); } else if (obj instanceof Protobuf.Type) { @@ -226,14 +270,17 @@ function createDefinition( } function createPackageDefinition( - root: Protobuf.Root, options: Options): PackageDefinition { + root: Protobuf.Root, + options: Options +): PackageDefinition { const def: PackageDefinition = {}; root.resolveAll(); - const descriptorList: descriptor.IFileDescriptorProto[] = - root.toDescriptor('proto3').file; - const bufferList: Buffer[] = descriptorList.map( - value => - Buffer.from(descriptor.FileDescriptorProto.encode(value).finish())); + const descriptorList: descriptor.IFileDescriptorProto[] = root.toDescriptor( + 'proto3' + ).file; + const bufferList: Buffer[] = descriptorList.map(value => + Buffer.from(descriptor.FileDescriptorProto.encode(value).finish()) + ); for (const [name, obj] of getAllHandledReflectionObjects(root, '')) { def[name] = createDefinition(obj, name, options, bufferList); } @@ -284,28 +331,33 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * @param options.includeDirs Paths to search for imported `.proto` files. */ export function load( - filename: string|string[], options?: Options): Promise { + filename: string | string[], + options?: Options +): Promise { const root: Protobuf.Root = new Protobuf.Root(); options = options || {}; if (!!options.includeDirs) { - if (!(Array.isArray(options.includeDirs))) { + if (!Array.isArray(options.includeDirs)) { return Promise.reject( - new Error('The includeDirs option must be an array')); + new Error('The includeDirs option must be an array') + ); } addIncludePathResolver(root, options.includeDirs as string[]); } - return root.load(filename, options).then((loadedRoot) => { + return root.load(filename, options).then(loadedRoot => { loadedRoot.resolveAll(); return createPackageDefinition(root, options!); }); } export function loadSync( - filename: string|string[], options?: Options): PackageDefinition { + filename: string | string[], + options?: Options +): PackageDefinition { const root: Protobuf.Root = new Protobuf.Root(); options = options || {}; if (!!options.includeDirs) { - if (!(Array.isArray(options.includeDirs))) { + if (!Array.isArray(options.includeDirs)) { throw new Error('The includeDirs option must be an array'); } addIncludePathResolver(root, options.includeDirs as string[]); @@ -321,13 +373,18 @@ export function loadSync( // and wrappers. compiler/plugin is excluded in Protobuf.js and here. const wellKnownProtos = ['api', 'descriptor', 'source_context', 'type']; const sourceDir = path.join( - path.dirname(require.resolve('protobufjs')), 'google', 'protobuf'); + path.dirname(require.resolve('protobufjs')), + 'google', + 'protobuf' + ); for (const proto of wellKnownProtos) { const file = path.join(sourceDir, `${proto}.proto`); const descriptor = Protobuf.loadSync(file).toJSON(); - // @ts-ignore - Protobuf.common(proto, descriptor.nested.google.nested); + Protobuf.common( + proto, + (descriptor.nested!.google as Protobuf.INamespace).nested! + ); } } diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index c59a92133..348c5c8e8 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -23,69 +23,76 @@ import * as proto_loader from '../src/index'; const TEST_PROTO_DIR = `${__dirname}/../../test_protos/`; type TypeDefinition = - proto_loader.EnumTypeDefinition|proto_loader.MessageTypeDefinition; + | proto_loader.EnumTypeDefinition + | proto_loader.MessageTypeDefinition; function isTypeObject(obj: proto_loader.AnyDefinition): obj is TypeDefinition { return 'format' in obj; } describe('Descriptor types', () => { - it('Should be output for each enum', (done) => { - proto_loader.load(`${TEST_PROTO_DIR}/enums.proto`) - .then( - (packageDefinition) => { - assert('Enum1' in packageDefinition); - assert(isTypeObject(packageDefinition.Enum1)); - // Need additional check because compiler doesn't understand - // asserts - if (isTypeObject(packageDefinition.Enum1)) { - const enum1Def: TypeDefinition = packageDefinition.Enum1; - assert.strictEqual( - enum1Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); - } + it('Should be output for each enum', done => { + proto_loader.load(`${TEST_PROTO_DIR}/enums.proto`).then( + packageDefinition => { + assert('Enum1' in packageDefinition); + assert(isTypeObject(packageDefinition.Enum1)); + // Need additional check because compiler doesn't understand + // asserts + if (isTypeObject(packageDefinition.Enum1)) { + const enum1Def: TypeDefinition = packageDefinition.Enum1; + assert.strictEqual( + enum1Def.format, + 'Protocol Buffer 3 EnumDescriptorProto' + ); + } - assert('Enum2' in packageDefinition); - assert(isTypeObject(packageDefinition.Enum2)); - // Need additional check because compiler doesn't understand - // asserts - if (isTypeObject(packageDefinition.Enum2)) { - const enum2Def: TypeDefinition = packageDefinition.Enum2; - assert.strictEqual( - enum2Def.format, 'Protocol Buffer 3 EnumDescriptorProto'); - } - done(); - }, - (error) => { - done(error); - }); + assert('Enum2' in packageDefinition); + assert(isTypeObject(packageDefinition.Enum2)); + // Need additional check because compiler doesn't understand + // asserts + if (isTypeObject(packageDefinition.Enum2)) { + const enum2Def: TypeDefinition = packageDefinition.Enum2; + assert.strictEqual( + enum2Def.format, + 'Protocol Buffer 3 EnumDescriptorProto' + ); + } + done(); + }, + error => { + done(error); + } + ); }); - it('Should be output for each message', (done) => { - proto_loader.load(`${TEST_PROTO_DIR}/messages.proto`) - .then( - (packageDefinition) => { - assert('LongValues' in packageDefinition); - assert(isTypeObject(packageDefinition.LongValues)); - if (isTypeObject(packageDefinition.LongValues)) { - const longValuesDef: TypeDefinition = - packageDefinition.LongValues; - assert.strictEqual( - longValuesDef.format, 'Protocol Buffer 3 DescriptorProto'); - } + it('Should be output for each message', done => { + proto_loader.load(`${TEST_PROTO_DIR}/messages.proto`).then( + packageDefinition => { + assert('LongValues' in packageDefinition); + assert(isTypeObject(packageDefinition.LongValues)); + if (isTypeObject(packageDefinition.LongValues)) { + const longValuesDef: TypeDefinition = packageDefinition.LongValues; + assert.strictEqual( + longValuesDef.format, + 'Protocol Buffer 3 DescriptorProto' + ); + } - assert('SequenceValues' in packageDefinition); - assert(isTypeObject(packageDefinition.SequenceValues)); - if (isTypeObject(packageDefinition.SequenceValues)) { - const sequenceValuesDef: TypeDefinition = - packageDefinition.SequenceValues; - assert.strictEqual( - sequenceValuesDef.format, - 'Protocol Buffer 3 DescriptorProto'); - } - done(); - }, - (error) => { - done(error); - }); + assert('SequenceValues' in packageDefinition); + assert(isTypeObject(packageDefinition.SequenceValues)); + if (isTypeObject(packageDefinition.SequenceValues)) { + const sequenceValuesDef: TypeDefinition = + packageDefinition.SequenceValues; + assert.strictEqual( + sequenceValuesDef.format, + 'Protocol Buffer 3 DescriptorProto' + ); + } + done(); + }, + error => { + done(error); + } + ); }); it('Can use well known Google protos', () => { diff --git a/packages/proto-loader/tsconfig.json b/packages/proto-loader/tsconfig.json index 26f33cd1f..d1646f011 100644 --- a/packages/proto-loader/tsconfig.json +++ b/packages/proto-loader/tsconfig.json @@ -5,7 +5,7 @@ "outDir": "build" }, "include": [ - "src/*.ts", - "test/*.ts" + "src/**/*.ts", + "test/**/*.ts" ] } diff --git a/packages/proto-loader/tslint.json b/packages/proto-loader/tslint.json new file mode 100644 index 000000000..27872a139 --- /dev/null +++ b/packages/proto-loader/tslint.json @@ -0,0 +1,8 @@ +{ + "extends": "gts/tslint.json", + "linterOptions": { + "exclude": [ + "**/*.json" + ] + } +} From e17a526ee03c5aeb21c9e3a9927776da2e42a815 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 8 Nov 2019 11:09:57 -0800 Subject: [PATCH 0854/1899] grpc-js: Publish ts and map files --- packages/grpc-js/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0dc403971..cd498cb94 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -58,7 +58,8 @@ "semver": "^6.2.0" }, "files": [ - "build/src/*.{js,d.ts}", + "src/*.ts", + "build/src/*.{js,d.ts,js.map}", "LICENSE" ] } From 54a95106a651d994bb36c344ce0392ec4570d20c Mon Sep 17 00:00:00 2001 From: Jared Dellitt Date: Sun, 10 Nov 2019 18:00:25 -0600 Subject: [PATCH 0855/1899] Change getDefaultAuthority in resolver to look at the registered resolvers instead of registerDefaultResolver function --- packages/grpc-js/src/resolver-dns.ts | 6 +++++- packages/grpc-js/src/resolver.ts | 2 +- packages/grpc-js/test/test-resolver.ts | 19 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index e98bf66b5..528529c9e 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -140,7 +140,11 @@ function mergeArrays(...arrays: T[][]): T[] { const result: T[] = []; for ( let i = 0; - i < Math.max.apply(null, arrays.map(array => array.length)); + i < + Math.max.apply( + null, + arrays.map(array => array.length) + ); i++ ) { for (const array of arrays) { diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 512f3c55b..3af5da9cd 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -125,7 +125,7 @@ export function createResolver( * @param target */ export function getDefaultAuthority(target: string): string { - for (const prefix of Object.keys(registerDefaultResolver)) { + for (const prefix of Object.keys(registeredResolvers)) { if (target.startsWith(prefix)) { return registeredResolvers[prefix].getDefaultAuthority(target); } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index a5a6a77eb..6e3a6b1b7 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -194,4 +194,23 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); }); + describe('getDefaultAuthority', () => { + class OtherResolver implements resolverManager.Resolver { + updateResolution() { + return []; + } + + static getDefaultAuthority(target: string): string { + return 'other'; + } + } + + it('Should return the correct authority if a different resolver has been registered', () => { + const target = 'other://name'; + resolverManager.registerResolver('other:', OtherResolver); + + const authority = resolverManager.getDefaultAuthority(target); + assert.equal(authority, 'other'); + }); + }); }); From 5c6901abeddadadc432e8b170e918728aeb40eb5 Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Mon, 11 Nov 2019 15:45:13 +0000 Subject: [PATCH 0856/1899] Additional binaries Signed-off-by: Jake Turner --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index 208e056a2..e049c6cb2 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 7.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index bc2884101..accc8c72b 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 7.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 ) umask 022 From 17126e4640bb42a9a34c6ce4aded412f1237c24a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 15:01:47 -0800 Subject: [PATCH 0857/1899] Update to typescript 3.7 --- package.json | 2 +- packages/grpc-js/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 11d8e2572..cfa23507f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "through2": "^2.0.3", "ts-node": "^8.1.0", "tslint": "^5.5.0", - "typescript": "^3.5.3", + "typescript": "^3.7.2", "xml2js": "^0.4.19" }, "contributors": [ diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0dc403971..4c7030e42 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -20,8 +20,8 @@ "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", - "@types/node": "^12.7.5", "@types/ncp": "^2.0.1", + "@types/node": "^12.7.5", "@types/pify": "^3.0.2", "@types/semver": "^6.0.1", "clang-format": "^1.0.55", @@ -34,7 +34,7 @@ "ncp": "^2.0.0", "pify": "^4.0.1", "ts-node": "^8.3.0", - "typescript": "^3.5.3" + "typescript": "^3.7.2" }, "contributors": [ { From 33875dce4a476b736626a937ee6e7f78ec5e34f1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 15:02:24 -0800 Subject: [PATCH 0858/1899] grpc-js: make client interceptors tests pass mostly unmodified --- packages/grpc-js/src/call-stream.ts | 105 +- packages/grpc-js/src/call.ts | 50 +- packages/grpc-js/src/client-interceptors.ts | 57 +- packages/grpc-js/src/client.ts | 44 +- packages/grpc-js/src/server-call.ts | 36 +- packages/grpc-js/src/server.ts | 1 - test/api/client_interceptors_test.js | 3071 ++++++++++--------- 7 files changed, 1770 insertions(+), 1594 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index e3ffb5eb2..7cd6d68f1 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -152,6 +152,7 @@ export class Http2CallStream implements Call { filterStack: Filter; private http2Stream: http2.ClientHttp2Stream | null = null; private pendingRead = false; + private isWriteFilterPending = false; private pendingWrite: Buffer | null = null; private pendingWriteCallback: WriteCallback | null = null; private writesClosed = false; @@ -160,12 +161,16 @@ export class Http2CallStream implements Call { private isReadFilterPending = false; private canPush = false; + /** + * Indicates that an 'end' event has come from the http2 stream, so there + * will be no more data events. + */ private readsClosed = false; private statusOutput = false; - private unpushedReadMessages: Array = []; - private unfilteredReadMessages: Array = []; + private unpushedReadMessages: Buffer[] = []; + private unfilteredReadMessages: Buffer[] = []; // Status code mapped from :status. To be used if grpc-status is not received private mappedStatusCode: Status = Status.UNKNOWN; @@ -200,16 +205,7 @@ export class Http2CallStream implements Call { /* Precondition: this.finalStatus !== null */ if (!this.statusOutput) { this.statusOutput = true; - /* We do this asynchronously to ensure that no async function is in the - * call stack when we return control to the application. If an async - * function is in the call stack, any exception thrown by the application - * (or our tests) will bubble up and turn into promise rejection, which - * will result in an UnhandledPromiseRejectionWarning. Because that is - * a warning, the error will be effectively swallowed and execution will - * continue */ - process.nextTick(() => { - this.listener!.onReceiveStatus(this.finalStatus!); - }); + this.listener!.onReceiveStatus(this.finalStatus!); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -227,32 +223,26 @@ export class Http2CallStream implements Call { * deserialization failure), that new status takes priority */ if (this.finalStatus === null || this.finalStatus.code === Status.OK) { this.finalStatus = status; - /* Then, if an incoming message is still being handled or the status code - * is OK, hold off on emitting the status until that is done */ - if (this.readsClosed || this.finalStatus.code !== Status.OK) { - this.outputStatus(); - } + this.maybeOutputStatus(); } } - private push(message: Buffer | null): void { - if (message === null) { - this.readsClosed = true; - if (this.finalStatus) { + private maybeOutputStatus() { + if (this.finalStatus !== null) { + /* The combination check of readsClosed and that the two message buffer + * arrays are empty checks that there all incoming data has been fully + * processed */ + if (this.finalStatus.code !== Status.OK || (this.readsClosed && this.unpushedReadMessages.length === 0 && this.unfilteredReadMessages.length === 0 && !this.isReadFilterPending)) { this.outputStatus(); } - } else { - this.listener!.onReceiveMessage(message); - /* Don't wait for the upper layer to ask for a read before pushing null - * to close out the call, because pushing null doesn't actually push - * another message up to the upper layer */ - if (this.unpushedReadMessages.length > 0 && this.unpushedReadMessages[0] === null) { - this.unpushedReadMessages.shift(); - this.push(null); - } } } + private push(message: Buffer): void { + this.listener!.onReceiveMessage(message); + this.maybeOutputStatus(); + } + private handleFilterError(error: Error) { this.cancelWithStatus(Status.INTERNAL, error.message); } @@ -261,7 +251,7 @@ export class Http2CallStream implements Call { /* If we the call has already ended, we don't want to do anything with * this message. Dropping it on the floor is correct behavior */ if (this.finalStatus !== null) { - this.push(null); + this.maybeOutputStatus(); return; } this.isReadFilterPending = false; @@ -275,24 +265,16 @@ export class Http2CallStream implements Call { if (this.unfilteredReadMessages.length > 0) { /* nextMessage is guaranteed not to be undefined because unfilteredReadMessages is non-empty */ - const nextMessage = this.unfilteredReadMessages.shift() as Buffer | null; + const nextMessage = this.unfilteredReadMessages.shift()!; this.filterReceivedMessage(nextMessage); } } - private filterReceivedMessage(framedMessage: Buffer | null) { + private filterReceivedMessage(framedMessage: Buffer) { /* If we the call has already ended, we don't want to do anything with * this message. Dropping it on the floor is correct behavior */ if (this.finalStatus !== null) { - this.push(null); - return; - } - if (framedMessage === null) { - if (this.canPush) { - this.push(null); - } else { - this.unpushedReadMessages.push(null); - } + this.maybeOutputStatus(); return; } this.isReadFilterPending = true; @@ -304,7 +286,7 @@ export class Http2CallStream implements Call { ); } - private tryPush(messageBytes: Buffer | null): void { + private tryPush(messageBytes: Buffer): void { if (this.isReadFilterPending) { this.unfilteredReadMessages.push(messageBytes); } else { @@ -411,12 +393,23 @@ export class Http2CallStream implements Call { } }); stream.on('end', () => { - this.tryPush(null); + this.readsClosed = true; + this.maybeOutputStatus(); }); - stream.on('close', async () => { + stream.on('close', () => { let code: Status; let details = ''; switch (stream.rstCode) { + case http2.constants.NGHTTP2_NO_ERROR: + /* If we get a NO_ERROR code and we already have a status, the + * stream completed properly and we just haven't fully processed + * it yet */ + if (this.finalStatus !== null) { + return; + } + code = Status.INTERNAL; + details = `Received RST_STREAM with code ${stream.rstCode}`; + break; case http2.constants.NGHTTP2_REFUSED_STREAM: code = Status.UNAVAILABLE; details = 'Stream refused by server'; @@ -435,6 +428,7 @@ export class Http2CallStream implements Call { break; default: code = Status.INTERNAL; + details = `Received RST_STREAM with code ${stream.rstCode}`; } // This is a no-op if trailers were received at all. // This is OK, because status codes emitted here correspond to more @@ -456,9 +450,7 @@ export class Http2CallStream implements Call { } stream.write(this.pendingWrite, this.pendingWriteCallback); } - if (this.writesClosed) { - stream.end(); - } + this.maybeCloseWrites(); } } @@ -514,7 +506,7 @@ export class Http2CallStream implements Call { /* If we have already emitted a status, we should not emit any more * messages and we should communicate that the stream has ended */ if (this.finalStatus !== null) { - this.push(null); + this.maybeOutputStatus(); return; } this.canPush = true; @@ -522,7 +514,7 @@ export class Http2CallStream implements Call { this.pendingRead = true; } else { if (this.unpushedReadMessages.length > 0) { - const nextMessage: Buffer | null = this.unpushedReadMessages.shift() as Buffer | null; + const nextMessage: Buffer = this.unpushedReadMessages.shift()!; this.push(nextMessage); this.canPush = false; return; @@ -534,26 +526,33 @@ export class Http2CallStream implements Call { } } + private maybeCloseWrites() { + if (this.writesClosed && !this.isWriteFilterPending && this.http2Stream !== null) { + this.http2Stream.end(); + } + } + sendMessageWithContext(context: MessageContext, message: Buffer) { const writeObj: WriteObject = { message: message, flags: context.flags }; const cb: WriteCallback = context.callback || (() => {}); + this.isWriteFilterPending = true; this.filterStack.sendMessage(Promise.resolve(writeObj)).then(message => { + this.isWriteFilterPending = false; if (this.http2Stream === null) { this.pendingWrite = message.message; this.pendingWriteCallback = cb; } else { this.http2Stream.write(message.message, cb); + this.maybeCloseWrites(); } }, this.handleFilterError.bind(this)); } halfClose() { this.writesClosed = true; - if (this.http2Stream !== null) { - this.http2Stream.end(); - } + this.maybeCloseWrites(); } } \ No newline at end of file diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index c5f87a00a..42d0886f5 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -18,11 +18,12 @@ import { EventEmitter } from 'events'; import { Duplex, Readable, Writable } from 'stream'; -import { Call, StatusObject, WriteObject } from './call-stream'; +import { StatusObject, MessageContext } from './call-stream'; import { Status } from './constants'; import { EmitterAugmentation1 } from './events'; import { Metadata } from './metadata'; import { ObjectReadable, ObjectWritable, WriteCallback } from './object-stream'; +import { InterceptingCallInterface } from './client-interceptors'; /** * A type extending the built-in Error object with additional fields. @@ -81,7 +82,7 @@ export function callErrorFromStatus(status: StatusObject): ServiceError { export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { - constructor(private readonly call: Call) { + constructor(private readonly call: InterceptingCallInterface) { super(); } @@ -97,7 +98,7 @@ export class ClientUnaryCallImpl extends EventEmitter export class ClientReadableStreamImpl extends Readable implements ClientReadableStream { constructor( - private readonly call: Call, + private readonly call: InterceptingCallInterface, readonly deserialize: (chunk: Buffer) => ResponseType ) { super({ objectMode: true }); @@ -116,33 +117,10 @@ export class ClientReadableStreamImpl extends Readable } } -function tryWrite( - call: Call, - serialize: (value: RequestType) => Buffer, - chunk: RequestType, - encoding: string, - cb: WriteCallback -) { - let message: Buffer; - const flags: number = Number(encoding); - try { - message = serialize(chunk); - } catch (e) { - call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); - cb(e); - return; - } - const writeObj: WriteObject = { message }; - if (!Number.isNaN(flags)) { - writeObj.flags = flags; - } - call.write(writeObj, cb); -} - export class ClientWritableStreamImpl extends Writable implements ClientWritableStream { constructor( - private readonly call: Call, + private readonly call: InterceptingCallInterface, readonly serialize: (value: RequestType) => Buffer ) { super({ objectMode: true }); @@ -157,12 +135,14 @@ export class ClientWritableStreamImpl extends Writable } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { - const writeObj: WriteObject = { message: chunk }; + const context: MessageContext = { + callback: cb + } const flags: number = Number(encoding); if (!Number.isNaN(flags)) { - writeObj.flags = flags; + context.flags = flags; } - this.call.write(writeObj, cb); + this.call.sendMessageWithContext(context, chunk); } _final(cb: Function) { @@ -174,7 +154,7 @@ export class ClientWritableStreamImpl extends Writable export class ClientDuplexStreamImpl extends Duplex implements ClientDuplexStream { constructor( - private readonly call: Call, + private readonly call: InterceptingCallInterface, readonly serialize: (value: RequestType) => Buffer, readonly deserialize: (chunk: Buffer) => ResponseType ) { @@ -194,12 +174,14 @@ export class ClientDuplexStreamImpl extends Duplex } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { - const writeObj: WriteObject = { message: chunk }; + const context: MessageContext = { + callback: cb + } const flags: number = Number(encoding); if (!Number.isNaN(flags)) { - writeObj.flags = flags; + context.flags = flags; } - this.call.write(writeObj, cb); + this.call.sendMessageWithContext(context, chunk); } _final(cb: Function) { diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 9703db49a..bf93f9beb 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -155,8 +155,9 @@ export interface InterceptorOptions extends CallOptions { export interface InterceptingCallInterface { cancelWithStatus(status: Status, details: string): void; getPeer(): string; - start(metadata: Metadata, listener: InterceptingListener): void; + start(metadata: Metadata, listener?: Partial): void; sendMessageWithContext(context: MessageContext, message: any): void; + sendMessage(message: any): void; startRead(): void; halfClose(): void; @@ -194,18 +195,23 @@ export class InterceptingCall implements InterceptingCallInterface { getPeer() { return this.nextCall.getPeer(); } - start(metadata: Metadata, interceptingListener: InterceptingListener): void { - this.requester.start(metadata, interceptingListener, (md, listener) => { + start(metadata: Metadata, interceptingListener?: Partial): void { + const fullInterceptingListener: InterceptingListener = { + onReceiveMetadata: interceptingListener?.onReceiveMetadata?.bind(interceptingListener) ?? (metadata => {}), + onReceiveMessage: interceptingListener?.onReceiveMessage?.bind(interceptingListener) ?? (message => {}), + onReceiveStatus: interceptingListener?.onReceiveStatus?.bind(interceptingListener) ?? (status => {}) + } + this.requester.start(metadata, fullInterceptingListener, (md, listener) => { let finalInterceptingListener: InterceptingListener; if (isInterceptingListener(listener)) { finalInterceptingListener = listener; } else { const fullListener: FullListener = { - onReceiveMetadata: listener.onReceiveMetadata || defaultListener.onReceiveMetadata, - onReceiveMessage: listener.onReceiveMessage || defaultListener.onReceiveMessage, - onReceiveStatus: listener.onReceiveStatus || defaultListener.onReceiveStatus + onReceiveMetadata: listener.onReceiveMetadata ?? defaultListener.onReceiveMetadata, + onReceiveMessage: listener.onReceiveMessage ?? defaultListener.onReceiveMessage, + onReceiveStatus: listener.onReceiveStatus ?? defaultListener.onReceiveStatus }; - finalInterceptingListener = new InterceptingListenerImpl(fullListener, interceptingListener); + finalInterceptingListener = new InterceptingListenerImpl(fullListener, fullInterceptingListener); } this.nextCall.start(md, finalInterceptingListener); }); @@ -218,7 +224,7 @@ export class InterceptingCall implements InterceptingCallInterface { if (this.pendingHalfClose) { this.nextCall.halfClose(); } - }) + }); } sendMessage(message: any): void { this.sendMessageWithContext({}, message); @@ -308,17 +314,20 @@ class BaseInterceptingCall implements InterceptingCallInterface { this.call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); } } - start(metadata: Metadata, listener: InterceptingListener): void { + sendMessage(message: any) { + this.sendMessageWithContext({}, message); + } + start(metadata: Metadata, interceptingListener?: Partial): void { let readError: StatusObject | null = null; this.call.start(metadata, { onReceiveMetadata: (metadata) => { - listener.onReceiveMetadata(metadata); + interceptingListener?.onReceiveMetadata?.(metadata); }, onReceiveMessage: (message) => { let deserialized: any; try { deserialized = this.methodDefinition.responseDeserialize(message); - listener.onReceiveMessage(deserialized); + interceptingListener?.onReceiveMessage?.(deserialized); } catch (e) { readError = {code: Status.INTERNAL, details: 'Failed to parse server response', metadata: new Metadata()}; this.call.cancelWithStatus(readError.code, readError.details); @@ -326,9 +335,9 @@ class BaseInterceptingCall implements InterceptingCallInterface { }, onReceiveStatus: (status) => { if (readError) { - listener.onReceiveStatus(readError); + interceptingListener?.onReceiveStatus?.(readError); } else { - listener.onReceiveStatus(status); + interceptingListener?.onReceiveStatus?.(status); } } }); @@ -345,8 +354,22 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements Intercep constructor(call: Call, methodDefinition: ClientMethodDefinition) { super(call, methodDefinition); } - start(metadata: Metadata, listener: InterceptingListener): void { - super.start(metadata, listener); + start(metadata: Metadata, listener?: Partial): void { + let receivedMessage = false; + const wrapperListener: InterceptingListener = { + onReceiveMetadata: listener?.onReceiveMetadata?.bind(listener) ?? (metadata => {}), + onReceiveMessage: (message: any) => { + receivedMessage = true; + listener?.onReceiveMessage?.(message); + }, + onReceiveStatus: (status: StatusObject) => { + if (!receivedMessage) { + listener?.onReceiveMessage?.(null); + } + listener?.onReceiveStatus?.(status); + } + } + super.start(metadata, wrapperListener); this.call.startRead(); } } @@ -416,8 +439,8 @@ export function getInterceptingCall(interceptorArgs: InterceptorArguments, metho * initialValue, which is effectively at the end of the list, is a nextCall * function that invokes getBottomInterceptingCall, which handles * (de)serialization and also gets the underlying call from the channel */ - const getCall: NextCall = interceptors.reduceRight((previousValue: NextCall, currentValue: Interceptor) => { - return currentOptions => currentValue(currentOptions, previousValue); + const getCall: NextCall = interceptors.reduceRight((nextCall: NextCall, nextInterceptor: Interceptor) => { + return currentOptions => nextInterceptor(currentOptions, nextCall); }, (finalOptions: InterceptorOptions) => getBottomInterceptingCall(channel, methodDefinition.path, finalOptions, methodDefinition)); return getCall(interceptorOptions); } \ No newline at end of file diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index a7fbfa556..4d5de5afd 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -29,14 +29,14 @@ import { SurfaceCall, } from './call'; import { CallCredentials } from './call-credentials'; -import { Call, Deadline, StatusObject, WriteObject, InterceptingListener } from './call-stream'; +import { Deadline, StatusObject, WriteObject, InterceptingListener } from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; import { ClientMethodDefinition } from './make-client'; -import { getInterceptingCall, Interceptor, InterceptorProvider, InterceptorArguments } from './client-interceptors'; +import { getInterceptingCall, Interceptor, InterceptorProvider, InterceptorArguments, InterceptingCallInterface } from './client-interceptors'; const CHANNEL_SYMBOL = Symbol(); const INTERCEPTOR_SYMBOL = Symbol(); @@ -231,13 +231,13 @@ export class Client { callInterceptors: options.interceptors || [], callInterceptorProviders: options.interceptor_providers || [] }; - const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } - const writeObj: WriteObject = { message: argument }; const emitter = new ClientUnaryCallImpl(call); let responseMessage: ResponseType | null = null; + let receivedStatus = false; call.start(metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -247,9 +247,12 @@ export class Client { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); } responseMessage = message; - call.startRead(); }, onReceiveStatus(status: StatusObject) { + if (receivedStatus) { + return; + } + receivedStatus = true; if (status.code === Status.OK) { callback!(null, responseMessage!); } else { @@ -258,8 +261,8 @@ export class Client { emitter.emit('status', status); } }); - call.write(writeObj, () => {call.halfClose();}); - call.startRead(); + call.sendMessage(argument); + call.halfClose(); return emitter; } @@ -315,12 +318,13 @@ export class Client { callInterceptors: options.interceptors || [], callInterceptorProviders: options.interceptor_providers || [] }; - const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } const emitter = new ClientWritableStreamImpl(call, serialize); let responseMessage: ResponseType | null = null; + let receivedStatus = false; call.start(metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -330,9 +334,12 @@ export class Client { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); } responseMessage = message; - call.startRead(); }, onReceiveStatus(status: StatusObject) { + if (receivedStatus) { + return; + } + receivedStatus = true; if (status.code === Status.OK) { callback!(null, responseMessage!); } else { @@ -341,7 +348,6 @@ export class Client { emitter.emit('status', status); } }); - call.startRead(); return emitter; } @@ -406,12 +412,12 @@ export class Client { callInterceptors: options.interceptors || [], callInterceptorProviders: options.interceptor_providers || [] }; - const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } - const writeObj: WriteObject = { message: argument }; const stream = new ClientReadableStreamImpl(call, deserialize); + let receivedStatus = false; call.start(metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -422,6 +428,10 @@ export class Client { } }, onReceiveStatus(status: StatusObject) { + if (receivedStatus) { + return; + } + receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { stream.emit('error', callErrorFromStatus(status)); @@ -429,7 +439,8 @@ export class Client { stream.emit('status', status); } }); - call.write(writeObj, () => {call.halfClose();}); + call.sendMessage(argument); + call.halfClose(); return stream; } @@ -467,7 +478,7 @@ export class Client { callInterceptors: options.interceptors || [], callInterceptorProviders: options.interceptor_providers || [] }; - const call: Call = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { call.setCredentials(options.credentials); } @@ -476,6 +487,7 @@ export class Client { serialize, deserialize ); + let receivedStatus = false; call.start(metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -486,6 +498,10 @@ export class Client { } }, onReceiveStatus(status: StatusObject) { + if (receivedStatus) { + return; + } + receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { stream.emit('error', callErrorFromStatus(status)); diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 02353bbe6..e92b12ba9 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -351,10 +351,8 @@ export class Http2ServerCallStream< }); this.stream.once('close', () => { - if (this.stream.rstCode === http2.constants.NGHTTP2_CANCEL) { - this.cancelled = true; - this.emit('cancelled', 'cancelled'); - } + this.cancelled = true; + this.emit('cancelled', 'cancelled'); }); this.stream.on('drain', () => { @@ -362,7 +360,20 @@ export class Http2ServerCallStream< }); } + private checkCancelled(): boolean { + /* In some cases the stream can become destroyed before the close event + * fires. That creates a race condition that this check works around */ + if (this.stream.destroyed) { + this.cancelled = true; + } + return this.cancelled; + } + sendMetadata(customMetadata?: Metadata) { + if (this.checkCancelled()) { + return; + } + if (this.metadataSent) { return; } @@ -397,6 +408,13 @@ export class Http2ServerCallStream< metadata.remove(GRPC_TIMEOUT_HEADER); } + // Remove several headers that should not be propagated to the application + metadata.remove(http2.constants.HTTP2_HEADER_ACCEPT_ENCODING); + metadata.remove(http2.constants.HTTP2_HEADER_TE); + metadata.remove(http2.constants.HTTP2_HEADER_CONTENT_TYPE); + metadata.remove('grpc-encoding'); + metadata.remove('grpc-accept-encoding'); + return metadata; } @@ -450,6 +468,9 @@ export class Http2ServerCallStream< metadata?: Metadata, flags?: number ) { + if (this.checkCancelled()) { + return; + } if (!metadata) { metadata = new Metadata(); } @@ -472,7 +493,7 @@ export class Http2ServerCallStream< } sendStatus(statusObj: StatusObject) { - if (this.cancelled) { + if (this.checkCancelled()) { return; } @@ -497,6 +518,9 @@ export class Http2ServerCallStream< } sendError(error: ServerErrorResponse | ServerStatusResponse) { + if (this.checkCancelled()) { + return; + } const status: StatusObject = { code: Status.UNKNOWN, details: 'message' in error ? error.message : 'Unknown Error', @@ -522,7 +546,7 @@ export class Http2ServerCallStream< } write(chunk: Buffer) { - if (this.cancelled) { + if (this.checkCancelled()) { return; } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 780b8f865..90aeea20a 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -346,7 +346,6 @@ export class Server { const call = new Http2ServerCallStream(stream, handler); const metadata: Metadata = call.receiveMetadata(headers) as Metadata; - switch (handler.type) { case 'unary': handleUnary(call, handler as UntypedUnaryHandler, metadata); diff --git a/test/api/client_interceptors_test.js b/test/api/client_interceptors_test.js index 9922ca975..19afd7001 100644 --- a/test/api/client_interceptors_test.js +++ b/test/api/client_interceptors_test.js @@ -93,394 +93,508 @@ CallRegistry.prototype.maybeCallDone = function() { } }; -describe('Client interceptors', function() { - var echo_server; - var echo_port; - var client; - - function startServer() { - echo_server = new serverGrpc.Server(); - echo_server.addService(echo_service, { - echo: function(call, callback) { - call.sendMetadata(call.metadata); - if (call.request.value === 'error') { - var status = { - code: 2, - message: 'test status message' - }; - status.metadata = call.metadata; - callback(status, null); - return; - } - callback(null, call.request); - }, - echoClientStream: function(call, callback){ - call.sendMetadata(call.metadata); - var payload; - var err = null; - call.on('data', function(data) { - if (data.value === 'error') { - err = { +describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + describe('Client interceptors', function() { + var echo_server; + var echo_port; + var client; + + function startServer(done) { + echo_server = new serverGrpc.Server(); + echo_server.addService(echo_service, { + echo: function(call, callback) { + call.sendMetadata(call.metadata); + if (call.request.value === 'error') { + var status = { code: 2, message: 'test status message' }; - err.metadata = call.metadata; + status.metadata = call.metadata; + callback(status, null); return; } - payload = data; - }); - call.on('end', function() { - callback(err, payload, call.metadata); - }); - }, - echoServerStream: function(call) { - call.sendMetadata(call.metadata); - if (call.request.value === 'error') { - var status = { - code: 2, - message: 'test status message' - }; - status.metadata = call.metadata; - call.emit('error', status); - return; - } - call.write(call.request); - call.end(call.metadata); - }, - echoBidiStream: function(call) { - call.sendMetadata(call.metadata); - call.on('data', function(data) { - if (data.value === 'error') { + callback(null, call.request); + }, + echoClientStream: function(call, callback){ + call.sendMetadata(call.metadata); + var payload; + var err = null; + call.on('data', function(data) { + if (data.value === 'error') { + err = { + code: 2, + message: 'test status message' + }; + err.metadata = call.metadata; + return; + } + payload = data; + }); + call.on('end', function() { + callback(err, payload, call.metadata); + }); + }, + echoServerStream: function(call) { + call.sendMetadata(call.metadata); + if (call.request.value === 'error') { var status = { code: 2, message: 'test status message' }; + status.metadata = call.metadata; call.emit('error', status); return; } - call.write(data); - }); - call.on('end', function() { + call.write(call.request); call.end(call.metadata); - }); - } - }); - var server_credentials = serverGrpc.ServerCredentials.createInsecure(); - echo_port = echo_server.bind('localhost:0', server_credentials); - echo_server.start(); - } + }, + echoBidiStream: function(call) { + call.sendMetadata(call.metadata); + call.on('data', function(data) { + if (data.value === 'error') { + var status = { + code: 2, + message: 'test status message' + }; + call.emit('error', status); + return; + } + call.write(data); + }); + call.on('end', function() { + call.end(call.metadata); + }); + } + }); + var server_credentials = serverGrpc.ServerCredentials.createInsecure(); + echo_server.bindAsync('localhost:0', server_credentials, (error, port) => { + assert.ifError(error); + echo_port = port; + echo_server.start(); + done(); + }); + } - function stopServer() { - echo_server.forceShutdown(); - } + function stopServer() { + echo_server.forceShutdown(); + } - function resetClient() { - client = new EchoClient('localhost:' + echo_port, insecureCreds); - } + function resetClient() { + client = new EchoClient('localhost:' + echo_port, insecureCreds); + } - before(function() { - startServer(); - }); - beforeEach(function() { - resetClient(); - }); - after(function() { - stopServer(); - }); + before(function(done) { + startServer(done); + }); + beforeEach(function() { + resetClient(); + }); + after(function() { + stopServer(); + }); - describe('execute downstream interceptors when a new call is made outbound', - function() { - var registry; - var options; - before(function() { - var stored_listener; - var stored_metadata; - var interceptor_a = function (options, nextCall) { - options.call_number = 1; - registry.addCall('construct a ' + options.call_number); - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - registry.addCall('start a ' + options.call_number); - stored_listener = listener; - stored_metadata = metadata; - next(metadata, listener); - }, - sendMessage: function (message, next) { - registry.addCall('send a ' + options.call_number); - var options2 = _.clone(options); - options2.call_number = 2; - var second_call = nextCall(options2); - second_call.start(stored_metadata); - second_call.sendMessage(message); - second_call.halfClose(); - next(message); - }, - halfClose: function (next) { - registry.addCall('close a ' + options.call_number); - next(); + describe('execute downstream interceptors when a new call is made outbound', + function() { + var registry; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + var stored_listener; + var stored_metadata; + options.call_number = 1; + registry.addCall('construct a ' + options.call_number); + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + registry.addCall('start a ' + options.call_number); + stored_listener = listener; + stored_metadata = metadata; + next(metadata, listener); + }, + sendMessage: function (message, next) { + registry.addCall('send a ' + options.call_number); + var options2 = _.clone(options); + options2.call_number = 2; + var second_call = nextCall(options2); + second_call.start(stored_metadata); + second_call.sendMessage(message); + second_call.halfClose(); + next(message); + }, + halfClose: function (next) { + registry.addCall('close a ' + options.call_number); + next(); + } + }); + }; + + var interceptor_b = function (options, nextCall) { + registry.addCall('construct b ' + options.call_number); + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + registry.addCall('start b ' + options.call_number); + next(metadata, listener); + }, + sendMessage: function (message, next) { + registry.addCall('send b ' + options.call_number); + next(message); + }, + halfClose: function (next) { + registry.addCall('close b ' + options.call_number); + next(); + } + }); + }; + options = { + interceptors: [interceptor_a, interceptor_b] + }; + }); + var expected_calls = [ + 'construct a 1', + 'construct b 1', + 'start a 1', + 'start b 1', + 'send a 1', + 'construct b 2', + 'start b 2', + 'send b 2', + 'close b 2', + 'send b 1', + 'close a 1', + 'close b 1', + 'response' + ]; + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + client.echo(message, options, function(err, response){ + if (!err) { + registry.addCall('response'); } }); - }; - - var interceptor_b = function (options, nextCall) { - registry.addCall('construct b ' + options.call_number); - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - registry.addCall('start b ' + options.call_number); - next(metadata, listener); - }, - sendMessage: function (message, next) { - registry.addCall('send b ' + options.call_number); - next(message); - }, - halfClose: function (next) { - registry.addCall('close b ' + options.call_number); - next(); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, false); + var message = {}; + message.value = 'foo'; + var stream = client.echoClientStream(options, function(err, response) { + if (!err) { + registry.addCall('response'); } }); - }; - options = { - interceptors: [interceptor_a, interceptor_b] - }; - }); - var expected_calls = [ - 'construct a 1', - 'construct b 1', - 'start a 1', - 'start b 1', - 'send a 1', - 'construct b 2', - 'start b 2', - 'send b 2', - 'close b 2', - 'send b 1', - 'close a 1', - 'close b 1', - 'response' - ]; - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - client.echo(message, options, function(err, response){ - if (!err) { - registry.addCall('response'); - } + stream.write(message); + stream.end(); }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, false); - var message = {}; - message.value = 'foo'; - var stream = client.echoClientStream(options, function(err, response) { - if (!err) { + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoServerStream(message, options); + stream.on('data', function(data) { registry.addCall('response'); - } - }); - stream.write(message); - stream.end(); - }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - var stream = client.echoServerStream(message, options); - stream.on('data', function(data) { - registry.addCall('response'); + }); }); - }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry( done, expected_calls, true); - var message = {}; - message.value = 'foo'; - var stream = client.echoBidiStream(options); - stream.on('data', function(data) { - registry.addCall('response'); + it('with bidi streaming call', function(done) { + registry = new CallRegistry( done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoBidiStream(options); + stream.on('data', function(data) { + registry.addCall('response'); + }); + stream.write(message); + stream.end(); }); - stream.write(message); - stream.end(); }); - }); - describe('execute downstream interceptors when a new call is made inbound', - function() { - var registry; - var options; - before(function() { - var interceptor_a = function (options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - next(metadata, { - onReceiveMetadata: function () { }, - onReceiveMessage: function (message, next) { - registry.addCall('interceptor_a'); - var second_call = nextCall(options); - second_call.start(metadata, listener); - second_call.sendMessage(message); - second_call.halfClose(); - }, - onReceiveStatus: function () { } - }); - } - }); - }; + describe('execute downstream interceptors when a new call is made inbound', + function() { + var registry; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + next(metadata, { + onReceiveMetadata: function (metadata, next) { }, + onReceiveMessage: function (message, next) { + registry.addCall('interceptor_a'); + var second_call = nextCall(options); + second_call.start(metadata, listener); + second_call.sendMessage(message); + second_call.halfClose(); + }, + onReceiveStatus: function (status, next) { } + }); + } + }); + }; - var interceptor_b = function (options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - next(metadata, { - onReceiveMessage: function (message, next) { - registry.addCall('interceptor_b'); - next(message); - } - }); - } - }); - }; + var interceptor_b = function (options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function (metadata, listener, next) { + next(metadata, { + onReceiveMessage: function (message, next) { + registry.addCall('interceptor_b'); + next(message); + } + }); + } + }); + }; - options = { - interceptors: [interceptor_a, interceptor_b] - }; + options = { + interceptors: [interceptor_a, interceptor_b] + }; - }); - var expected_calls = ['interceptor_b', 'interceptor_a', - 'interceptor_b', 'response']; - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - client.echo(message, options, function(err) { - if (!err) { + }); + var expected_calls = ['interceptor_b', 'interceptor_a', + 'interceptor_b', 'response']; + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + client.echo(message, options, function(err) { + assert.ifError(err); registry.addCall('response'); - } + }); }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - var stream = client.echoClientStream(options, function(err, response) { - if (!err) { + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {}; + message.value = 'foo'; + var stream = client.echoClientStream(options, function(err, response) { + assert.ifError(err); registry.addCall('response'); - } + }); + stream.write(message); + stream.end(); }); - stream.write(message); - stream.end(); }); - }); - it.skip('will delay operations and short circuit unary requests', function(done) { - var registry = new CallRegistry(done, ['foo_miss', 'foo_hit', 'bar_miss', - 'foo_hit_done', 'foo_miss_done', 'bar_miss_done']); - var cache = {}; - var _getCachedResponse = function(value) { - return cache[value]; - }; - var _store = function(key, value) { - cache[key] = value; - }; - - var interceptor = function(options, nextCall) { - var savedMetadata; - var startNext; - var storedListener; - var storedMessage; - var messageNext; - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - savedMetadata = metadata; - storedListener = listener; - startNext = next; - }) - .withSendMessage(function(message, next) { - storedMessage = message; - messageNext = next; - }) - .withHalfClose(function(next) { - var cachedValue = _getCachedResponse(storedMessage.value); - if (cachedValue) { - var cachedMessage = {}; - cachedMessage.value = cachedValue; - registry.addCall(storedMessage.value + '_hit'); - storedListener.onReceiveMetadata(new Metadata()); - storedListener.onReceiveMessage(cachedMessage); - storedListener.onReceiveStatus( - (new StatusBuilder()).withCode(clientGrpc.status.OK).build()); - } else { - registry.addCall(storedMessage.value + '_miss'); - var newListener = (new ListenerBuilder()).withOnReceiveMessage( - function(message, next) { - _store(storedMessage.value, message.value); - next(message); - }).build(); - startNext(savedMetadata, newListener); - messageNext(storedMessage); + it('will delay operations and short circuit unary requests', function(done) { + var registry = new CallRegistry(done, ['foo_miss', 'foo_hit', 'bar_miss', + 'foo_hit_done', 'foo_miss_done', 'bar_miss_done']); + var cache = {}; + var _getCachedResponse = function(value) { + return cache[value]; + }; + var _store = function(key, value) { + cache[key] = value; + }; + + var interceptor = function(options, nextCall) { + var savedMetadata; + var startNext; + var storedListener; + var storedMessage; + var messageNext; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + savedMetadata = metadata; + storedListener = listener; + startNext = next; + }) + .withSendMessage(function(message, next) { + storedMessage = message; + messageNext = next; + }) + .withHalfClose(function(next) { + var cachedValue = _getCachedResponse(storedMessage.value); + if (cachedValue) { + var cachedMessage = {}; + cachedMessage.value = cachedValue; + registry.addCall(storedMessage.value + '_hit'); + storedListener.onReceiveMetadata(new Metadata()); + storedListener.onReceiveMessage(cachedMessage); + storedListener.onReceiveStatus( + (new StatusBuilder()).withCode(clientGrpc.status.OK).build()); + } else { + registry.addCall(storedMessage.value + '_miss'); + var newListener = (new ListenerBuilder()).withOnReceiveMessage( + function(message, next) { + _store(storedMessage.value, message.value); + next(message); + }).build(); + startNext(savedMetadata, newListener); + messageNext(storedMessage); + next(); + } + }) + .withCancel(function(message, next) { next(); - } - }) - .withCancel(function(message, next) { - next(); - }).build(); - - return new InterceptingCall(nextCall(options), requester); - }; - - var options = { - interceptors: [interceptor] - }; - - var foo_message = {}; - foo_message.value = 'foo'; - client.echo(foo_message, options, function(err, response){ - assert.equal(response.value, 'foo'); - registry.addCall('foo_miss_done'); + }).build(); + + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [interceptor] + }; + + var foo_message = {}; + foo_message.value = 'foo'; client.echo(foo_message, options, function(err, response){ assert.equal(response.value, 'foo'); - registry.addCall('foo_hit_done'); + registry.addCall('foo_miss_done'); + client.echo(foo_message, options, function(err, response){ + assert.equal(response.value, 'foo'); + registry.addCall('foo_hit_done'); + }); + }); + + var bar_message = {}; + bar_message.value = 'bar'; + client.echo(bar_message, options, function(err, response) { + assert.equal(response.value, 'bar'); + registry.addCall('bar_miss_done'); }); }); - var bar_message = {}; - bar_message.value = 'bar'; - client.echo(bar_message, options, function(err, response) { - assert.equal(response.value, 'bar'); - registry.addCall('bar_miss_done'); + it('can retry failed messages and handle eventual success', function(done) { + var registry = new CallRegistry(done, + ['retry_foo_1', 'retry_foo_2', 'retry_foo_3', 'foo_result', + 'retry_bar_1', 'bar_result']); + var maxRetries = 3; + var retry_interceptor = function(options, nextCall) { + var savedMetadata; + var savedSendMessage; + var savedReceiveMessage; + var savedMessageNext; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + savedMetadata = metadata; + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + savedReceiveMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function(status, next) { + var retries = 0; + var retry = function(message, metadata) { + retries++; + var newCall = nextCall(options); + var receivedMessage; + newCall.start(metadata, { + onReceiveMessage: function(message) { + receivedMessage = message; + }, + onReceiveStatus: function(status) { + registry.addCall('retry_' + savedMetadata.get('name') + + '_' + retries); + if (status.code !== clientGrpc.status.OK) { + if (retries <= maxRetries) { + retry(message, metadata); + } else { + savedMessageNext(receivedMessage); + next(status); + } + } else { + registry.addCall('success_call'); + var new_status = (new StatusBuilder()) + .withCode(clientGrpc.status.OK).build(); + savedMessageNext(receivedMessage); + next(new_status); + } + } + }); + newCall.sendMessage(message); + newCall.halfClose(); + }; + if (status.code !== clientGrpc.status.OK) { + // Change the message we're sending only for test purposes + // so the server will respond without error + var newMessage = (savedMetadata.get('name')[0] === 'bar') ? + {value: 'bar'} : savedSendMessage; + retry(newMessage, savedMetadata); + } else { + savedMessageNext(savedReceiveMessage); + next(status); + } + } + ).build(); + next(metadata, new_listener); + }) + .withSendMessage(function(message, next) { + savedSendMessage = message; + next(message); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var options = { + interceptors: [retry_interceptor] + }; + + // Make a call which the server will return a non-OK status for + var foo_message = {value: 'error'}; + var foo_metadata = new Metadata(); + foo_metadata.set('name', 'foo'); + client.echo(foo_message, foo_metadata, options, function(err, response) { + assert.strictEqual(err.code, 2); + registry.addCall('foo_result'); + }); + + // Make a call which will fail the first time and succeed on the first + // retry + var bar_message = {value: 'error'}; + var bar_metadata = new Metadata(); + bar_metadata.set('name', 'bar'); + client.echo(bar_message, bar_metadata, options, function(err, response) { + assert.strictEqual(response.value, 'bar'); + registry.addCall('bar_result'); + }); }); - }); - it('can retry failed messages and handle eventual success', function(done) { - var registry = new CallRegistry(done, - ['retry_foo_1', 'retry_foo_2', 'retry_foo_3', 'foo_result', - 'retry_bar_1', 'bar_result']); - var maxRetries = 3; - var retry_interceptor = function(options, nextCall) { - var savedMetadata; - var savedSendMessage; - var savedReceiveMessage; - var savedMessageNext; - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - savedMetadata = metadata; - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - savedReceiveMessage = message; - savedMessageNext = next; - }) - .withOnReceiveStatus(function(status, next) { + it('can retry and preserve interceptor order on success', function(done) { + var registry = new CallRegistry(done, + ['interceptor_c', 'retry_interceptor', 'fail_call', 'interceptor_c', + 'success_call', 'interceptor_a', 'result'], true); + var interceptor_a = function(options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + registry.addCall('interceptor_a'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var retry_interceptor = function(options, nextCall) { + var savedMetadata; + var savedMessage; + var savedMessageNext; + var sendMessageNext; + var originalMessage; + var startNext; + var originalListener; + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + startNext = next; + savedMetadata = metadata; + originalListener = listener; + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + savedMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function(status, next) { var retries = 0; + var maxRetries = 1; + var receivedMessage; var retry = function(message, metadata) { retries++; - var newCall = nextCall(options); - var receivedMessage; - newCall.start(metadata, { + var new_call = nextCall(options); + new_call.start(metadata, { onReceiveMessage: function(message) { receivedMessage = message; }, onReceiveStatus: function(status) { - registry.addCall('retry_' + savedMetadata.get('name') + - '_' + retries); if (status.code !== clientGrpc.status.OK) { if (retries <= maxRetries) { retry(message, metadata); @@ -497,1281 +611,1300 @@ describe('Client interceptors', function() { } } }); - newCall.sendMessage(message); - newCall.halfClose(); + new_call.sendMessage(message); + new_call.halfClose(); }; + registry.addCall('retry_interceptor'); if (status.code !== clientGrpc.status.OK) { - // Change the message we're sending only for test purposes - // so the server will respond without error - var newMessage = (savedMetadata.get('name')[0] === 'bar') ? - {value: 'bar'} : savedSendMessage; + registry.addCall('fail_call'); + var newMessage = {value: 'foo'}; retry(newMessage, savedMetadata); } else { - savedMessageNext(savedReceiveMessage); + savedMessageNext(savedMessage); next(status); } - } - ).build(); - next(metadata, new_listener); - }) - .withSendMessage(function(message, next) { - savedSendMessage = message; - next(message); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var options = { - interceptors: [retry_interceptor] - }; - - // Make a call which the server will return a non-OK status for - var foo_message = {value: 'error'}; - var foo_metadata = new Metadata(); - foo_metadata.set('name', 'foo'); - client.echo(foo_message, foo_metadata, options, function(err, response) { - assert.strictEqual(err.code, 2); - registry.addCall('foo_result'); - }); + }).build(); + next(metadata, new_listener); + }) + .withSendMessage(function(message, next) { + sendMessageNext = next; + originalMessage = message; + next(message); + }) + .build(); + return new InterceptingCall(nextCall(options), requester); + }; + + var interceptor_c = function(options, nextCall) { + var requester = (new RequesterBuilder()) + .withStart(function(metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function(message, next) { + registry.addCall('interceptor_c'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); + }; - // Make a call which will fail the first time and succeed on the first - // retry - var bar_message = {value: 'error'}; - var bar_metadata = new Metadata(); - bar_metadata.set('name', 'bar'); - client.echo(bar_message, bar_metadata, options, function(err, response) { - assert.strictEqual(response.value, 'bar'); - registry.addCall('bar_result'); + var options = { + interceptors: [interceptor_a, retry_interceptor, interceptor_c] + }; + + var message = {value: 'error'}; + client.echo(message, options, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.value, 'foo'); + registry.addCall('result'); + }); }); - }); - it('can retry and preserve interceptor order on success', function(done) { - var registry = new CallRegistry(done, - ['interceptor_c', 'retry_interceptor', 'fail_call', 'interceptor_c', - 'success_call', 'interceptor_a', 'result'], true); - var interceptor_a = function(options, nextCall) { - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - registry.addCall('interceptor_a'); - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var retry_interceptor = function(options, nextCall) { - var savedMetadata; - var savedMessage; - var savedMessageNext; - var sendMessageNext; - var originalMessage; - var startNext; - var originalListener; - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - startNext = next; - savedMetadata = metadata; - originalListener = listener; - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - savedMessage = message; - savedMessageNext = next; + describe('handle interceptor errors', function () { + var options; + before(function () { + var foo_interceptor = function (options, nextCall) { + var savedListener; + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + savedListener = listener; + next(metadata, listener); }) - .withOnReceiveStatus(function(status, next) { - var retries = 0; - var maxRetries = 1; - var receivedMessage; - var retry = function(message, metadata) { - retries++; - var new_call = nextCall(options); - new_call.start(metadata, { - onReceiveMessage: function(message) { - receivedMessage = message; - }, - onReceiveStatus: function(status) { - if (status.code !== clientGrpc.status.OK) { - if (retries <= maxRetries) { - retry(message, metadata); - } else { - savedMessageNext(receivedMessage); - next(status); - } - } else { - registry.addCall('success_call'); - var new_status = (new StatusBuilder()) - .withCode(clientGrpc.status.OK).build(); - savedMessageNext(receivedMessage); - next(new_status); - } - } - }); - new_call.sendMessage(message); - new_call.halfClose(); - }; - registry.addCall('retry_interceptor'); - if (status.code !== clientGrpc.status.OK) { - registry.addCall('fail_call'); - var newMessage = {value: 'foo'}; - retry(newMessage, savedMetadata); - } else { - savedMessageNext(savedMessage); - next(status); - } - }).build(); - next(metadata, new_listener); - }) - .withSendMessage(function(message, next) { - sendMessageNext = next; - originalMessage = message; - next(message); - }) - .build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var interceptor_c = function(options, nextCall) { - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - registry.addCall('interceptor_c'); - next(message); + .withSendMessage(function (message, next) { + savedListener.onReceiveMetadata(new Metadata()); + savedListener.onReceiveMessage({ value: 'failed' }); + var error_status = (new StatusBuilder()) + .withCode(16) + .withDetails('Error in foo interceptor') + .build(); + savedListener.onReceiveStatus(error_status); }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var options = { - interceptors: [interceptor_a, retry_interceptor, interceptor_c] - }; - - var message = {value: 'error'}; - client.echo(message, options, function(err, response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('result'); - }); - }); - - describe('handle interceptor errors', function (doneOuter) { - var options; - before(function () { - var foo_interceptor = function (options, nextCall) { - var savedListener; - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - savedListener = listener; - next(metadata, listener); - }) - .withSendMessage(function (message, next) { - savedListener.onReceiveMetadata(new Metadata()); - savedListener.onReceiveMessage({ value: 'failed' }); - var error_status = (new StatusBuilder()) - .withCode(16) - .withDetails('Error in foo interceptor') - .build(); - savedListener.onReceiveStatus(error_status); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - it('with unary call', function(done) { - var message = {}; - client.echo(message, options, function(err, response) { - assert.strictEqual(err.code, 16); - assert.strictEqual(err.message, - '16 UNAUTHENTICATED: Error in foo interceptor'); - done(); - doneOuter(); - }); - }); - }); - - describe('implement fallbacks for streaming RPCs', function() { - - var options; - before(function () { - var fallback_response = { value: 'fallback' }; - var savedMessage; - var savedMessageNext; - var interceptor = function (options, nextCall) { - var requester = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function (message, next) { - savedMessage = message; - savedMessageNext = next; - }) - .withOnReceiveStatus(function (status, next) { - if (status.code !== clientGrpc.status.OK) { - savedMessageNext(fallback_response); - next((new StatusBuilder()).withCode(clientGrpc.status.OK)); - } else { - savedMessageNext(savedMessage); - next(status); - } - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - options = { - interceptors: [interceptor] - }; - }); - it('with client streaming call', function (done) { - var registry = new CallRegistry(done, ['foo_result', 'fallback_result']); - var stream = client.echoClientStream(options, function (err, response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('foo_result'); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor] }; }); - stream.write({ value: 'foo' }); - stream.end(); - - stream = client.echoClientStream(options, function(err, response) { - assert.ifError(err); - assert.strictEqual(response.value, 'fallback'); - registry.addCall('fallback_result'); + it('with unary call', function(done) { + var message = {}; + client.echo(message, options, function(err, response) { + assert.strictEqual(err.code, 16); + assert.strictEqual(err.message, + '16 UNAUTHENTICATED: Error in foo interceptor'); + done(); + }); }); - stream.write({value: 'error'}); - stream.end(); }); - }); - describe('allows the call options to be modified for downstream interceptors', - function() { - var done; + describe('implement fallbacks for streaming RPCs', function() { + var options; - var method_name; - var method_path_last; - before(function() { - var interceptor_a = function (options, nextCall) { - options.deadline = 10; - return new InterceptingCall(nextCall(options)); - }; - var interceptor_b = function (options, nextCall) { - assert.equal(options.method_definition.path, '/EchoService/' + - method_path_last); - assert.equal(options.deadline, 10); - done(); - return new InterceptingCall(nextCall(options)); + before(function () { + var fallback_response = { value: 'fallback' }; + var interceptor = function (options, nextCall) { + var savedMessage; + var savedMessageNext; + var requester = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()) + .withOnReceiveMessage(function (message, next) { + savedMessage = message; + savedMessageNext = next; + }) + .withOnReceiveStatus(function (status, next) { + if (status.code !== clientGrpc.status.OK) { + savedMessageNext(fallback_response); + next((new StatusBuilder()).withCode(clientGrpc.status.OK).build()); + } else { + savedMessageNext(savedMessage); + next(status); + } + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), requester); }; - options = { - interceptors: [interceptor_a, interceptor_b], - deadline: 100 + interceptors: [interceptor] }; }); + it('with client streaming call', function (done) { + var registry = new CallRegistry(done, ['foo_result', 'fallback_result']); + var stream = client.echoClientStream(options, function (err, response) { + assert.ifError(err); + assert.strictEqual(response.value, 'foo'); + registry.addCall('foo_result'); + }); + stream.write({ value: 'foo' }); + stream.end(); - it('with unary call', function(cb) { - done = cb; - var metadata = new Metadata(); - var message = {}; - method_name = 'echo'; - method_path_last = 'Echo'; - - client.echo(message, metadata, options, function(){}); + stream = client.echoClientStream(options, function(err, response) { + assert.ifError(err); + assert.strictEqual(response.value, 'fallback'); + registry.addCall('fallback_result'); + }); + stream.write({value: 'error'}); + stream.end(); }); + }); - it('with client streaming call', function(cb) { - done = cb; - var metadata = new Metadata(); - method_name = 'echoClientStream'; - method_path_last = 'EchoClientStream'; - - client.echoClientStream(metadata, options, function() {}); - }); + describe('allows the call options to be modified for downstream interceptors', + function() { + var done; + var options; + var method_name; + var method_path_last; + before(function() { + var interceptor_a = function (options, nextCall) { + options.deadline = 10; + return new InterceptingCall(nextCall(options)); + }; + var interceptor_b = function (options, nextCall) { + assert.equal(options.method_definition.path, '/EchoService/' + + method_path_last); + assert.equal(options.deadline, 10); + done(); + return new InterceptingCall(nextCall(options)); + }; - it('with server streaming call', function(cb) { - done = cb; - var metadata = new Metadata(); - var message = {}; - method_name = 'echoServerStream'; - method_path_last = 'EchoServerStream'; + options = { + interceptors: [interceptor_a, interceptor_b], + deadline: 100 + }; + }); - client.echoServerStream(message, metadata, options); - }); + it('with unary call', function(cb) { + done = cb; + var metadata = new Metadata(); + var message = {}; + method_name = 'echo'; + method_path_last = 'Echo'; - it('with bidi streaming call', function(cb) { - done = cb; - var metadata = new Metadata(); - method_name = 'echoBidiStream'; - method_path_last = 'EchoBidiStream'; + client.echo(message, metadata, options, function(){}); + }); - client.echoBidiStream(metadata, options); - }); - }); + it('with client streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + method_name = 'echoClientStream'; + method_path_last = 'EchoClientStream'; - describe('pass accurate MethodDefinitions', function() { - var registry; - var initial_value = 'broken'; - var expected_value = 'working'; - var options; - before(function() { - var interceptor = function (options, nextCall) { - registry.addCall({ - path: options.method_definition.path, - requestStream: options.method_definition.requestStream, - responseStream: options.method_definition.responseStream + client.echoClientStream(metadata, options, function() {}); }); - var outbound = (new RequesterBuilder()) - .withSendMessage(function (message, next) { - message.value = expected_value; - next(message); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [interceptor] }; - }); - it('with unary call', function(done) { - var unary_definition = { - path: '/EchoService/Echo', - requestStream: false, - responseStream: false - }; - registry = new CallRegistry(done, [ - unary_definition, - 'result_unary' - ]); + it('with server streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + var message = {}; + method_name = 'echoServerStream'; + method_path_last = 'EchoServerStream'; - var metadata = new Metadata(); + const stream = client.echoServerStream(message, metadata, options); + stream.on('error', () => {}); + }); - var message = {value: initial_value}; + it('with bidi streaming call', function(cb) { + done = cb; + var metadata = new Metadata(); + method_name = 'echoBidiStream'; + method_path_last = 'EchoBidiStream'; - client.echo(message, metadata, options, function(err, response){ - assert.equal(response.value, expected_value); - registry.addCall('result_unary'); + const stream = client.echoBidiStream(metadata, options); + stream.on('error', () => {}); + }); }); - }); - it('with client streaming call', function(done) { + describe('pass accurate MethodDefinitions', function() { + var registry; + var initial_value = 'broken'; + var expected_value = 'working'; + var options; + before(function() { + var interceptor = function (options, nextCall) { + registry.addCall({ + path: options.method_definition.path, + requestStream: options.method_definition.requestStream, + responseStream: options.method_definition.responseStream + }); + var outbound = (new RequesterBuilder()) + .withSendMessage(function (message, next) { + message.value = expected_value; + next(message); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [interceptor] }; + }); - var client_stream_definition = { - path: '/EchoService/EchoClientStream', - requestStream: true, - responseStream: false - }; - registry = new CallRegistry(done, [ - client_stream_definition, - 'result_client_stream' - ], false, true); - var metadata = new Metadata(); - var message = {value: initial_value}; - var client_stream = client.echoClientStream(metadata, options, - function(err, response) { - assert.strictEqual(response.value, expected_value); - registry.addCall('result_client_stream'); - }); - client_stream.write(message); - client_stream.end(); + it('with unary call', function(done) { + var unary_definition = { + path: '/EchoService/Echo', + requestStream: false, + responseStream: false + }; + registry = new CallRegistry(done, [ + unary_definition, + 'result_unary' + ]); - }); - it('with server streaming call', function(done) { - var server_stream_definition = { - path: '/EchoService/EchoServerStream', - responseStream: true, - requestStream: false, - }; - registry = new CallRegistry(done, [ - server_stream_definition, - 'result_server_stream' - ]); + var metadata = new Metadata(); - var metadata = new Metadata(); - var message = {value: initial_value}; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('data', function(data) { - assert.strictEqual(data.value, expected_value); - registry.addCall('result_server_stream'); - }); + var message = {value: initial_value}; - }); - it('with bidi streaming call', function(done) { - var bidi_stream_definition = { - path: '/EchoService/EchoBidiStream', - requestStream: true, - responseStream: true - }; - registry = new CallRegistry(done, [ - bidi_stream_definition, - 'result_bidi_stream' - ]); + client.echo(message, metadata, options, function(err, response){ + assert.equal(response.value, expected_value); + registry.addCall('result_unary'); + }); - var metadata = new Metadata(); - var message = {value: initial_value}; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(data) { - assert.strictEqual(data.value, expected_value); - registry.addCall('result_bidi_stream'); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); + }); + it('with client streaming call', function(done) { + var client_stream_definition = { + path: '/EchoService/EchoClientStream', + requestStream: true, + responseStream: false + }; + registry = new CallRegistry(done, [ + client_stream_definition, + 'result_client_stream' + ]); + var metadata = new Metadata(); + var message = {value: initial_value}; + var client_stream = client.echoClientStream(metadata, options, + function(err, response) { + assert.strictEqual(response.value, expected_value); + registry.addCall('result_client_stream'); + }); + client_stream.write(message); + client_stream.end(); - it('uses interceptors passed to the client constructor', function(done) { - var registry = new CallRegistry(done, { - 'constructor_interceptor_a_echo': 1, - 'constructor_interceptor_b_echoServerStream': 1, - 'invocation_interceptor': 1, - 'result_unary': 1, - 'result_stream': 1, - 'result_invocation': 1 - }); + }); + it('with server streaming call', function(done) { + var server_stream_definition = { + path: '/EchoService/EchoServerStream', + responseStream: true, + requestStream: false, + }; + registry = new CallRegistry(done, [ + server_stream_definition, + 'result_server_stream' + ]); - var constructor_interceptor_a = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - registry.addCall('constructor_interceptor_a_echo'); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var constructor_interceptor_b = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - registry.addCall('constructor_interceptor_b_echoServerStream'); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var invocation_interceptor = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - registry.addCall('invocation_interceptor'); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - - var interceptor_providers = [ - function(method_definition) { - if (!method_definition.requestStream && - !method_definition.responseStream) { - return constructor_interceptor_a; - } - }, - function(method_definition) { - if (!method_definition.requestStream && - method_definition.responseStream) { - return constructor_interceptor_b; - } - } - ]; - var constructor_options = { - interceptor_providers: interceptor_providers - }; - var int_client = new EchoClient('localhost:' + echo_port, insecureCreds, - constructor_options); - var message = {}; - int_client.echo(message, function() { - registry.addCall('result_unary'); - }); - var stream = int_client.echoServerStream(message); - stream.on('data', function() { - registry.addCall('result_stream'); - }); + var metadata = new Metadata(); + var message = {value: initial_value}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function(data) { + assert.strictEqual(data.value, expected_value); + registry.addCall('result_server_stream'); + }); - var options = { interceptors: [invocation_interceptor] }; - int_client.echo(message, options, function() { - registry.addCall('result_invocation'); - }); - }); + }); + it('with bidi streaming call', function(done) { + var bidi_stream_definition = { + path: '/EchoService/EchoBidiStream', + requestStream: true, + responseStream: true + }; + registry = new CallRegistry(done, [ + bidi_stream_definition, + 'result_bidi_stream' + ]); - it.skip('will reject conflicting interceptor options at invocation', - function(done) { - try { - client.echo('message', { - interceptors: [], - interceptor_providers: [] - }, function () {}); - } catch (e) { - assert.equal(e.name, 'InterceptorConfigurationError'); - done(); - } + var metadata = new Metadata(); + var message = {value: initial_value}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(data) { + assert.strictEqual(data.value, expected_value); + registry.addCall('result_bidi_stream'); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); }); - it('will resolve interceptor providers at invocation', function(done) { - var constructor_interceptor = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function() { - assert(false); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var invocation_interceptor = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function() { - done(); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var constructor_interceptor_providers = [ - function() { - return constructor_interceptor; - } - ]; - var invocation_interceptor_providers = [ - function() { - return invocation_interceptor; - } - ]; - var constructor_options = { - interceptor_providers: constructor_interceptor_providers - }; - var int_client = new EchoClient('localhost:' + echo_port, insecureCreds, - constructor_options); - var message = {}; - var options = { interceptor_providers: invocation_interceptor_providers }; - int_client.echo(message, options, function() {}); - }); + it('uses interceptors passed to the client constructor', function(done) { + var registry = new CallRegistry(done, { + 'constructor_interceptor_a_echo': 1, + 'constructor_interceptor_b_echoServerStream': 1, + 'invocation_interceptor': 1, + 'result_unary': 1, + 'result_stream': 1, + 'result_invocation': 1, + 'status_stream': 1 + }); - describe('trigger a stack of interceptors in nested order', function() { - var registry; - var expected_calls = ['constructA', 'constructB', 'outboundA', 'outboundB', - 'inboundB', 'inboundA']; - var options; - before(function() { - var interceptor_a = function (options, nextCall) { - registry.addCall('constructA'); + var constructor_interceptor_a = function(options, nextCall) { var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('outboundA'); - var new_listener = (new ListenerBuilder()).withOnReceiveMessage( - function (message, next) { - registry.addCall('inboundA'); - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new clientGrpc.InterceptingCall(nextCall(options), - outbound); - }; - var interceptor_b = function (options, nextCall) { - registry.addCall('constructB'); - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('outboundB'); - var new_listener = (new ListenerBuilder()).withOnReceiveMessage( - function (message, next) { - registry.addCall('inboundB'); - next(message); - }).build(); - next(metadata, new_listener); + .withStart(function(metadata, listener, next) { + registry.addCall('constructor_interceptor_a_echo'); + next(metadata, listener); }).build(); - return new InterceptingCall(nextCall(options), - outbound); + return new InterceptingCall(nextCall(options), outbound); }; - options = { interceptors: [interceptor_a, interceptor_b] }; - }); - var metadata = new Metadata(); - var message = {}; - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - client.echo(message, metadata, options, function(){}); - }); - - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var client_stream = client.echoClientStream(metadata, options, - function() {}); - client_stream.write(message); - client_stream.end(); - }); - - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var stream = client.echoServerStream(message, metadata, options); - stream.on('data', function() {}); - }); - - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(){}); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger interceptors horizontally', function() { - var expected_calls = [ - 'interceptor_a_start', - 'interceptor_b_start', - 'interceptor_a_send', - 'interceptor_b_send' - ]; - var registry; - var options; - var metadata = new Metadata(); - var message = {}; - - before(function() { - var interceptor_a = function (options, nextCall) { + var constructor_interceptor_b = function(options, nextCall) { var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('interceptor_a_start'); + .withStart(function(metadata, listener, next) { + registry.addCall('constructor_interceptor_b_echoServerStream'); next(metadata, listener); - }) - .withSendMessage(function (message, next) { - registry.addCall('interceptor_a_send'); - next(message); }).build(); - return new InterceptingCall(nextCall(options), - outbound); + return new InterceptingCall(nextCall(options), outbound); }; - var interceptor_b = function (options, nextCall) { + var invocation_interceptor = function(options, nextCall) { var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('interceptor_b_start'); + .withStart(function(metadata, listener, next) { + registry.addCall('invocation_interceptor'); next(metadata, listener); - }) - .withSendMessage(function (message, next) { - registry.addCall('interceptor_b_send'); - next(message); }).build(); - return new InterceptingCall(nextCall(options), - outbound); + return new InterceptingCall(nextCall(options), outbound); }; - options = { interceptors: [interceptor_a, interceptor_b] }; - }); - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - client.echo(message, metadata, options, function(){}); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var client_stream = client.echoClientStream(metadata, options, - function() {}); - client_stream.write(message); - client_stream.end(); - }); + var interceptor_providers = [ + function(method_definition) { + if (!method_definition.requestStream && + !method_definition.responseStream) { + return constructor_interceptor_a; + } + }, + function(method_definition) { + if (!method_definition.requestStream && + method_definition.responseStream) { + return constructor_interceptor_b; + } + } + ]; + var constructor_options = { + interceptor_providers: interceptor_providers + }; + var int_client = new EchoClient('localhost:' + echo_port, insecureCreds, + constructor_options); + var message = {}; + int_client.echo(message, function(error, response) { + assert.ifError(error); + registry.addCall('result_unary'); + }); + var stream = int_client.echoServerStream(message); + stream.on('data', function() { + registry.addCall('result_stream'); + }); + stream.on('status', (status) => { + registry.addCall('status_stream'); + }); + stream.on('error', (error) => { + assert.ifError(error); + }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var stream = client.echoServerStream(message, metadata, options); - stream.on('data', function() {}); + var options = { interceptors: [invocation_interceptor] }; + int_client.echo(message, options, function() { + registry.addCall('result_invocation'); + }); }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(){}); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); + it.skip('will reject conflicting interceptor options at invocation', + function(done) { + try { + client.echo('message', { + interceptors: [], + interceptor_providers: [] + }, function () {}); + } catch (e) { + assert.equal(e.name, 'InterceptorConfigurationError'); + done(); + } + }); - describe('trigger when sending metadata', function() { - var registry; - - var message = {}; - var key_names = ['original', 'foo', 'bar']; - var keys = { - original: 'originalkey', - foo: 'fookey', - bar: 'barkey' - }; - var values = { - original: 'originalvalue', - foo: 'foovalue', - bar: 'barvalue' - }; - var expected_calls = ['foo', 'bar', 'response']; - var options; - before(function () { - var foo_interceptor = function (options, nextCall) { + it('will resolve interceptor providers at invocation', function(done) { + var constructor_interceptor = function(options, nextCall) { var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - metadata.add(keys.foo, values.foo); - registry.addCall('foo'); - next(metadata, listener); + .withStart(function() { + assert(false); }).build(); return new InterceptingCall(nextCall(options), outbound); }; - var bar_interceptor = function (options, nextCall) { + var invocation_interceptor = function(options, nextCall) { var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - metadata.add(keys.bar, values.bar); - registry.addCall('bar'); - next(metadata, listener); + .withStart(function() { + done(); }).build(); return new InterceptingCall(nextCall(options), outbound); }; - options = { interceptors: [foo_interceptor, bar_interceptor] }; + var constructor_interceptor_providers = [ + function() { + return constructor_interceptor; + } + ]; + var invocation_interceptor_providers = [ + function() { + return invocation_interceptor; + } + ]; + var constructor_options = { + interceptor_providers: constructor_interceptor_providers + }; + var int_client = new EchoClient('localhost:' + echo_port, insecureCreds, + constructor_options); + var message = {}; + var options = { interceptor_providers: invocation_interceptor_providers }; + int_client.echo(message, options, function() {}); }); - it('with unary call', function (done) { - registry = new CallRegistry(done, expected_calls, true); + describe('trigger a stack of interceptors in nested order', function() { + var registry; + var expected_calls = ['constructA', 'constructB', 'outboundA', 'outboundB', + 'inboundB', 'inboundA', 'callDone']; + var options; + before(function() { + var interceptor_a = function (options, nextCall) { + registry.addCall('constructA'); + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('outboundA'); + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + registry.addCall('inboundA'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new clientGrpc.InterceptingCall(nextCall(options), + outbound); + }; + var interceptor_b = function (options, nextCall) { + registry.addCall('constructB'); + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('outboundB'); + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + registry.addCall('inboundB'); + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [interceptor_a, interceptor_b] }; + }); var metadata = new Metadata(); - metadata.add(keys.original, values.original); + var message = {}; - var unary_call = client.echo(message, metadata, options, function () {}); - unary_call.on('metadata', function (metadata) { - var has_expected_values = _.every(key_names, function (key_name) { - return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + client.echo(message, metadata, options, function(error, response){ + assert.ifError(error); + registry.addCall('callDone'); }); - assert(has_expected_values); - registry.addCall('response'); }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - var client_stream = client.echoClientStream(metadata, options, - function () { - }); - client_stream.write(message); - client_stream.on('metadata', function (metadata) { - var has_expected_values = _.every(key_names, function (key_name) { - return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var client_stream = client.echoClientStream(metadata, options, function(error, response) { + assert.ifError(error); + registry.addCall('callDone'); }); - assert(has_expected_values); - registry.addCall('response'); + client_stream.write(message); + client_stream.end(); }); - client_stream.end(); - }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('metadata', function (metadata) { - var has_expected_values = _.every(key_names, function (key_name) { - return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var stream = client.echoServerStream(message, metadata, options); + stream.on('data', function() {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('callDone'); }); - assert(has_expected_values); - registry.addCall('response'); - }); - server_stream.on('data', function() { }); - }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('metadata', function(metadata) { - var has_expected_values = _.every(key_names, function(key_name) { - return _.isEqual(metadata.get(keys[key_name]),[values[key_name]]); + stream.on('error', (error) => { + assert.ifError(error); }); - assert(has_expected_values); - bidi_stream.end(); - registry.addCall('response'); }); - bidi_stream.on('data', function() { }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger when sending messages', function() { - var registry; - var originalValue = 'foo'; - var expectedValue = 'bar'; - var options; - var metadata = new Metadata(); - var expected_calls = ['messageIntercepted', 'response']; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withSendMessage(function (message, next) { - assert.strictEqual(message.value, originalValue); - registry.addCall('messageIntercepted'); - next({ value: expectedValue }); - }).build(); - return new InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(){}); + bidi_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('callDone'); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); }); - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; + describe('trigger interceptors horizontally', function() { + var expected_calls = [ + 'interceptor_a_start', + 'interceptor_b_start', + 'interceptor_a_send', + 'interceptor_b_send', + 'call_end' + ]; + var registry; + var options; + var metadata = new Metadata(); + var message = {}; + + before(function() { + var interceptor_a = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('interceptor_a_start'); + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + registry.addCall('interceptor_a_send'); + next(message); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + var interceptor_b = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + registry.addCall('interceptor_b_start'); + next(metadata, listener); + }) + .withSendMessage(function (message, next) { + registry.addCall('interceptor_b_send'); + next(message); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [interceptor_a, interceptor_b] }; + }); + + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + client.echo(message, metadata, options, function(error, response){ + assert.ifError(error); + registry.addCall('call_end'); + }); + }); - client.echo(message, metadata, options, function (err, response) { - assert.strictEqual(response.value, expectedValue); - registry.addCall('response'); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var client_stream = client.echoClientStream(metadata, options, function(error, response) { + assert.ifError(error); + registry.addCall('call_end'); + }); + client_stream.write(message); + client_stream.end(); }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - var client_stream = client.echoClientStream(metadata, options, - function (err, response) { - assert.strictEqual(response.value, expectedValue); - registry.addCall('response'); + + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var stream = client.echoServerStream(message, metadata, options); + stream.on('data', function() {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('call_end'); + }); + stream.on('error', (error) => { + assert.ifError(error); }); - client_stream.write(message); - client_stream.end(); - }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('data', function (data) { - assert.strictEqual(data.value, expectedValue); - registry.addCall('response'); + }); + + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(){}); + bidi_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('call_end'); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); + bidi_stream.end(); }); }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(data) { - assert.strictEqual(data.value, expectedValue); - registry.addCall('response'); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - describe('trigger when client closes the call', function() { - var registry; - var expected_calls = [ - 'response', 'halfClose' - ]; - var message = {}; - var options; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withHalfClose(function (next) { - registry.addCall('halfClose'); - next(); - }).build(); - return new InterceptingCall(nextCall(options), - outbound); + describe('trigger when sending metadata', function() { + var registry; + + var message = {}; + var key_names = ['original', 'foo', 'bar']; + var keys = { + original: 'originalkey', + foo: 'fookey', + bar: 'barkey' }; - options = { interceptors: [foo_interceptor] }; - }); - it('with unary call', function (done) { - registry = new CallRegistry(done, expected_calls); - client.echo(message, options, function (err, response) { - if (!err) { + var values = { + original: 'originalvalue', + foo: 'foovalue', + bar: 'barvalue' + }; + var expected_calls = ['foo', 'bar', 'response', 'end']; + var options; + before(function () { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + metadata.add(keys.foo, values.foo); + registry.addCall('foo'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + var bar_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + metadata.add(keys.bar, values.bar); + registry.addCall('bar'); + next(metadata, listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor, bar_interceptor] }; + }); + + it('with unary call', function (done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + + var unary_call = client.echo(message, metadata, options, function (error, response) { + assert.ifError(error); + registry.addCall('end'); + }); + unary_call.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); registry.addCall('response'); - } + }); }); - }); - it('with client streaming call', function (done) { - registry = new CallRegistry(done, expected_calls); - var client_stream = client.echoClientStream(options, - function (err, response) { }); - client_stream.write(message, function (err) { - if (!err) { + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + + var client_stream = client.echoClientStream(metadata, options, + function (error, response) { + assert.ifError(error); + registry.addCall('end'); + }); + client_stream.write(message); + client_stream.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); registry.addCall('response'); - } + }); + client_stream.end(); }); - client_stream.end(); - }); - it('with server streaming call', function (done) { - registry = new CallRegistry(done, expected_calls); - var server_stream = client.echoServerStream(message, options); - server_stream.on('data', function (data) { - registry.addCall('response'); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('metadata', function (metadata) { + var has_expected_values = _.every(key_names, function (key_name) { + return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); + }); + assert(has_expected_values); + registry.addCall('response'); + }); + server_stream.on('data', function() { }); + server_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('end'); + }); + server_stream.on('error', (error) => { + assert.ifError(error); + }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var metadata = new Metadata(); + metadata.add(keys.original, values.original); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function(metadata) { + var has_expected_values = _.every(key_names, function(key_name) { + return _.isEqual(metadata.get(keys[key_name]),[values[key_name]]); + }); + assert(has_expected_values); + bidi_stream.end(); + registry.addCall('response'); + }); + bidi_stream.on('data', function() { }); + bidi_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('end'); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); + bidi_stream.end(); }); }); - it('with bidi streaming call', function (done) { - registry = new CallRegistry(done, expected_calls); - var bidi_stream = client.echoBidiStream(options); - bidi_stream.on('data', function (data) { - registry.addCall('response'); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - describe('trigger when the stream is canceled', function() { - var done; - var message = {}; - var options; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withCancel(function (next) { - done(); - next(); - }).build(); - return new InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); + describe('trigger when sending messages', function() { + var registry; + var originalValue = 'foo'; + var expectedValue = 'bar'; + var options; + var metadata = new Metadata(); + var expected_calls = ['messageIntercepted', 'response', 'end']; - it('with unary call', function(cb) { - done = cb; - var stream = client.echo(message, options, function() {}); - stream.cancel(); - }); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withSendMessage(function (message, next) { + assert.strictEqual(message.value, originalValue); + registry.addCall('messageIntercepted'); + next({ value: expectedValue }); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); - it('with client streaming call', function(cb) { - done = cb; - var stream = client.echoClientStream(options, function() {}); - stream.cancel(); - }); - it('with server streaming call', function(cb) { - done = cb; - var stream = client.echoServerStream(message, options); - stream.cancel(); - }); - it('with bidi streaming call', function(cb) { - done = cb; - var stream = client.echoBidiStream(options); - stream.cancel(); - }); - }); + it('with unary call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; - describe('trigger when receiving metadata', function() { - var message = {}; - var expectedKey = 'foo'; - var expectedValue = 'bar'; - var options; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()).withOnReceiveMetadata( - function (metadata, next) { - metadata.add(expectedKey, expectedValue); - next(metadata); - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [foo_interceptor] }; + client.echo(message, metadata, options, function (err, response) { + assert.ifError(err); + assert.strictEqual(response.value, expectedValue); + registry.addCall('response'); + registry.addCall('end'); + }); + }); + it('with client streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true, true); + var message = {value: originalValue}; + var client_stream = client.echoClientStream(metadata, options, + function (err, response) { + assert.ifError(err); + assert.strictEqual(response.value, expectedValue); + registry.addCall('response'); + registry.addCall('end'); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with server streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + registry.addCall('response'); + }); + server_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('end'); + }); + server_stream.on('error', (error) => { + assert.ifError(error); + }); + }); + it('with bidi streaming call', function(done) { + registry = new CallRegistry(done, expected_calls, true); + var message = {value: originalValue}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function(data) { + assert.strictEqual(data.value, expectedValue); + registry.addCall('response'); + }); + bidi_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('end'); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); + bidi_stream.end(); + }); }); - it('with unary call', function(done) { - var metadata = new Metadata(); - var unary_call = client.echo(message, metadata, options, function () {}); - unary_call.on('metadata', function (metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - done(); + describe('trigger when client closes the call', function() { + var registry; + var expected_calls = [ + 'response', 'halfClose', 'end' + ]; + var message = {}; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withHalfClose(function (next) { + registry.addCall('halfClose'); + next(); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; }); - }); - it('with client streaming call', function(done) { - var metadata = new Metadata(); - var client_stream = client.echoClientStream(metadata, options, - function () {}); - client_stream.write(message); - client_stream.on('metadata', function (metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - done(); + it('with unary call', function (done) { + registry = new CallRegistry(done, expected_calls); + client.echo(message, options, function (err, response) { + assert.ifError(err); + registry.addCall('response'); + registry.addCall('end'); + }); }); - client_stream.end(); - }); - it('with server streaming call', function(done) { - var metadata = new Metadata(); - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('metadata', function (metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - done(); + it('with client streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var client_stream = client.echoClientStream(options, + function (err, response) { + assert.ifError(err); + registry.addCall('response'); + registry.addCall('end'); + }); + client_stream.write(message); + client_stream.end(); }); - server_stream.on('data', function() { }); - }); - it('with bidi streaming call', function(done) { - var metadata = new Metadata(); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('metadata', function(metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + it('with server streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var server_stream = client.echoServerStream(message, options); + server_stream.on('data', function (data) { + registry.addCall('response'); + }); + server_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('end'); + }); + server_stream.on('error', (error) => { + assert.ifError(error); + }); + }); + it('with bidi streaming call', function (done) { + registry = new CallRegistry(done, expected_calls); + var bidi_stream = client.echoBidiStream(options); + bidi_stream.on('data', function (data) { + registry.addCall('response'); + }); + bidi_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + registry.addCall('end'); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); bidi_stream.end(); - done(); }); - bidi_stream.on('data', function() { }); - bidi_stream.write(message); }); - }); - describe('trigger when sending messages', function() { - var originalValue = 'foo'; - var expectedValue = 'bar'; - var options; - var metadata = new Metadata(); - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()).withOnReceiveMessage( - function (message, next) { - if (!message) { - next(message); - return; - } - assert.strictEqual(message.value, originalValue); - message.value = expectedValue; - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); + describe('trigger when the stream is canceled', function() { + var done; + var message = {}; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withCancel(function (next) { + done(); + next(); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); - it('with unary call', function (done) { - var message = { value: originalValue }; - client.echo(message, metadata, options, function (err, response) { - assert.strictEqual(response.value, expectedValue); - done(); + it('with unary call', function(cb) { + done = cb; + var stream = client.echo(message, options, function() {}); + stream.cancel(); + }); + + it('with client streaming call', function(cb) { + done = cb; + var stream = client.echoClientStream(options, function() {}); + stream.cancel(); + }); + it('with server streaming call', function(cb) { + done = cb; + var stream = client.echoServerStream(message, options); + stream.on('error', (error) => { + assert.strictEqual(error.code, clientGrpc.status.CANCELLED); + }); + stream.cancel(); + }); + it('with bidi streaming call', function(cb) { + done = cb; + var stream = client.echoBidiStream(options); + stream.on('error', (error) => { + assert.strictEqual(error.code, clientGrpc.status.CANCELLED); + }); + stream.cancel(); }); }); - it('with client streaming call', function (done) { - var message = { value: originalValue }; - var client_stream = client.echoClientStream(metadata, options, - function (err, response) { - assert.strictEqual(response.value, expectedValue); + + describe('trigger when receiving metadata', function() { + var message = {}; + var expectedKey = 'foo'; + var expectedValue = 'bar'; + var options; + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveMetadata( + function (metadata, next) { + metadata.add(expectedKey, expectedValue); + next(metadata); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), outbound); + }; + options = { interceptors: [foo_interceptor] }; + }); + + it('with unary call', function(done) { + var metadata = new Metadata(); + var unary_call = client.echo(message, metadata, options, function () {}); + unary_call.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); done(); }); - client_stream.write(message); - client_stream.end(); - }); - it('with server streaming call', function (done) { - var message = { value: originalValue }; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('data', function (data) { - assert.strictEqual(data.value, expectedValue); - done(); }); - }); - it('with bidi streaming call', function (done) { - var message = { value: originalValue }; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function (data) { - assert.strictEqual(data.value, expectedValue); - done(); + it('with client streaming call', function(done) { + var metadata = new Metadata(); + var client_stream = client.echoClientStream(metadata, options, + function () {}); + client_stream.write(message); + client_stream.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + client_stream.end(); + }); + it('with server streaming call', function(done) { + var metadata = new Metadata(); + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('metadata', function (metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + done(); + }); + server_stream.on('error', (error) => { + assert.ifError(error); + }); + server_stream.on('data', function() { }); + }); + it('with bidi streaming call', function(done) { + var metadata = new Metadata(); + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function(metadata) { + assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); + bidi_stream.end(); + done(); + }); + bidi_stream.on('data', function() { }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }) + bidi_stream.write(message); }); - bidi_stream.write(message); - bidi_stream.end(); }); - }); - describe('trigger when receiving status', function() { - var expectedStatus = 'foo'; - var options; - var metadata = new Metadata(); - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()).withOnReceiveStatus( - function (status, next) { - assert.strictEqual(status.code, 2); - assert.strictEqual(status.details, 'test status message'); - var new_status = { - code: 1, - details: expectedStatus, - metadata: {} - }; - next(new_status); - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - it('with unary call', function (done) { - var message = { value: 'error' }; - var unary_call = client.echo(message, metadata, options, function () { + describe('trigger when sending messages', function() { + var originalValue = 'foo'; + var expectedValue = 'bar'; + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveMessage( + function (message, next) { + if (!message) { + next(message); + return; + } + assert.strictEqual(message.value, originalValue); + message.value = expectedValue; + next(message); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; }); - unary_call.on('status', function (status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); + + it('with unary call', function (done) { + var message = { value: originalValue }; + client.echo(message, metadata, options, function (err, response) { + assert.ifError(err); + assert.strictEqual(response.value, expectedValue); + done(); + }); }); - }); - it('with client streaming call', function (done) { - var message = { value: 'error' }; - var client_stream = client.echoClientStream(metadata, options, - function () { - }); - client_stream.on('status', function (status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); + it('with client streaming call', function (done) { + var message = { value: originalValue }; + var client_stream = client.echoClientStream(metadata, options, + function (err, response) { + assert.ifError(err); + assert.strictEqual(response.value, expectedValue); + done(); + }); + client_stream.write(message); + client_stream.end(); + }); + it('with server streaming call', function (done) { + var message = { value: originalValue }; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + done(); + }); + server_stream.on('error', (error) => { + assert.ifError(error); + }); + }); + it('with bidi streaming call', function (done) { + var message = { value: originalValue }; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('data', function (data) { + assert.strictEqual(data.value, expectedValue); + done(); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); + bidi_stream.end(); }); - client_stream.write(message); - client_stream.end(); }); - it('with server streaming call', function(done) { - var message = {value: 'error'}; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('error', function (err) { + describe('trigger when receiving status', function() { + var expectedStatus = 'foo'; + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var outbound = (new RequesterBuilder()) + .withStart(function (metadata, listener, next) { + var new_listener = (new ListenerBuilder()).withOnReceiveStatus( + function (status, next) { + assert.strictEqual(status.code, 2); + assert.strictEqual(status.details, 'test status message'); + var new_status = { + code: 1, + details: expectedStatus, + metadata: {} + }; + next(new_status); + }).build(); + next(metadata, new_listener); + }).build(); + return new InterceptingCall(nextCall(options), + outbound); + }; + options = { interceptors: [foo_interceptor] }; }); - server_stream.on('data', function (data) { + it('with unary call', function (done) { + var message = { value: 'error' }; + var unary_call = client.echo(message, metadata, options, function () { + }); + unary_call.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); }); - server_stream.on('status', function (status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); + it('with client streaming call', function (done) { + var message = { value: 'error' }; + var client_stream = client.echoClientStream(metadata, options, + function () { + }); + client_stream.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + client_stream.write(message); + client_stream.end(); }); - }); - it('with bidi streaming call', function(done) { - var message = {value: 'error'}; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('error', function(err) {}); - bidi_stream.on('data', function(data) {}); - bidi_stream.on('status', function(status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); + it('with server streaming call', function(done) { + var message = {value: 'error'}; + var server_stream = client.echoServerStream(message, metadata, options); + server_stream.on('error', function (err) { + }); + server_stream.on('data', function (data) { + }); + server_stream.on('status', function (status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - describe('delay streaming headers', function() { - var options; - var metadata = new Metadata(); - before(function() { - var foo_interceptor = function (options, nextCall) { - var startNext; - var startListener; - var startMetadata; - var methods = { - start: function (metadata, listener, next) { - startNext = next; - startListener = listener; - startMetadata = metadata; - }, - sendMessage: function (message, next) { - startMetadata.set('fromMessage', message.value); - startNext(startMetadata, startListener); - next(message); - } - }; - return new InterceptingCall(nextCall(options), methods); - }; - options = { interceptors: [foo_interceptor] }; - }); - it('with client streaming call', function (done) { - var message = { value: 'foo' }; - var client_stream = client.echoClientStream(metadata, options, - function () { }); - client_stream.on('metadata', function (metadata) { - assert.equal(metadata.get('fromMessage'), 'foo'); - done(); + it('with bidi streaming call', function(done) { + var message = {value: 'error'}; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('error', function(err) {}); + bidi_stream.on('data', function(data) {}); + bidi_stream.on('status', function(status) { + assert.strictEqual(status.code, 1); + assert.strictEqual(status.details, expectedStatus); + done(); + }); + bidi_stream.write(message); + bidi_stream.end(); }); - client_stream.write(message); - client_stream.end(); }); - it('with bidi streaming call', function (done) { - var message = { value: 'foo' }; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('metadata', function (metadata) { - assert.equal(metadata.get('fromMessage'), 'foo'); - done(); + describe('delay streaming headers', function() { + var options; + var metadata = new Metadata(); + before(function() { + var foo_interceptor = function (options, nextCall) { + var startNext; + var startListener; + var startMetadata; + var methods = { + start: function (metadata, listener, next) { + startNext = next; + startListener = listener; + startMetadata = metadata; + }, + sendMessage: function (message, next) { + startMetadata.set('fromMessage', message.value); + startNext(startMetadata, startListener); + next(message); + } + }; + return new InterceptingCall(nextCall(options), methods); + }; + options = { interceptors: [foo_interceptor] }; }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - describe.only('order of operations enforced for async interceptors', function() { - it('with unary call', function(done) { - var expected_calls = [ - 'close_b', - 'message_b', - 'start_b', - 'done' - ]; - var registry = new CallRegistry(done, expected_calls, true, true); - var message = {value: 'foo'}; - var interceptor_a = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - setTimeout(function() { next(metadata, listener); }, 50); - }, - sendMessage: function(message, next) { - setTimeout(function () { next(message); }, 10); - } + it('with client streaming call', function (done) { + var message = { value: 'foo' }; + var client_stream = client.echoClientStream(metadata, options, + function (error, response) { + assert.ifError(error); + done(); + }); + client_stream.on('metadata', function (metadata) { + assert.equal(metadata.get('fromMessage'), 'foo'); }); - }; - var interceptor_b = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - registry.addCall('start_b'); - next(metadata, listener); - }, - sendMessage: function(message, next) { - registry.addCall('message_b'); - next(message); - }, - halfClose: function(next) { - registry.addCall('close_b'); - next(); - } + client_stream.write(message); + client_stream.end(); + }); + it('with bidi streaming call', function (done) { + var message = { value: 'foo' }; + var bidi_stream = client.echoBidiStream(metadata, options); + bidi_stream.on('metadata', function (metadata) { + assert.equal(metadata.get('fromMessage'), 'foo'); }); - }; - var options = { - interceptors: [interceptor_a, interceptor_b] - }; - client.echo(message, options, function(err, response) { - assert.strictEqual(err, null); - registry.addCall('done'); + bidi_stream.on('data', () => {}); + bidi_stream.on('status', (status) => { + assert.strictEqual(status.code, clientGrpc.status.OK); + done(); + }); + bidi_stream.on('error', (error) => { + assert.ifError(error); + }); + bidi_stream.write(message); + bidi_stream.end(); }); }); - it('with serverStreaming call', function(done) { - var expected_calls = [ - 'close_b', - 'message_b', - 'start_b', - 'done' - ]; - var registry = new CallRegistry(done, expected_calls, true, true); - var message = {value: 'foo'}; - var interceptor_a = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - setTimeout(function() { next(metadata, listener); }, 50); - }, - sendMessage: function(message, next) { - setTimeout(function () { next(message); }, 10); - } + + describe.skip('order of operations enforced for async interceptors', function() { + it('with unary call', function(done) { + var expected_calls = [ + 'close_b', + 'message_b', + 'start_b', + 'done' + ]; + var registry = new CallRegistry(done, expected_calls, true); + var message = {value: 'foo'}; + var interceptor_a = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + setTimeout(function() { next(metadata, listener); }, 50); + }, + sendMessage: function(message, next) { + setTimeout(function () { next(message); }, 10); + } + }); + }; + var interceptor_b = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + registry.addCall('start_b'); + next(metadata, listener); + }, + sendMessage: function(message, next) { + registry.addCall('message_b'); + next(message); + }, + halfClose: function(next) { + registry.addCall('close_b'); + next(); + } + }); + }; + var options = { + interceptors: [interceptor_a, interceptor_b] + }; + client.echo(message, options, function(err, response) { + assert.strictEqual(err, null); + registry.addCall('done'); }); - }; - var interceptor_b = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - registry.addCall('start_b'); - next(metadata, listener); - }, - sendMessage: function(message, next) { - registry.addCall('message_b'); - next(message); - }, - halfClose: function(next) { - registry.addCall('close_b'); - next(); - } + }); + it('with serverStreaming call', function(done) { + var expected_calls = [ + 'close_b', + 'message_b', + 'start_b', + 'done' + ]; + var registry = new CallRegistry(done, expected_calls, true); + var message = {value: 'foo'}; + var interceptor_a = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + setTimeout(function() { next(metadata, listener); }, 50); + }, + sendMessage: function(message, next) { + setTimeout(function () { next(message); }, 10); + } + }); + }; + var interceptor_b = function(options, nextCall) { + return new InterceptingCall(nextCall(options), { + start: function(metadata, listener, next) { + registry.addCall('start_b'); + next(metadata, listener); + }, + sendMessage: function(message, next) { + registry.addCall('message_b'); + next(message); + }, + halfClose: function(next) { + registry.addCall('close_b'); + next(); + } + }); + }; + var options = { + interceptors: [interceptor_a, interceptor_b] + }; + var stream = client.echoServerStream(message, options); + stream.on('data', function(response) { + assert.strictEqual(response.value, 'foo'); + registry.addCall('done'); }); - }; - var options = { - interceptors: [interceptor_a, interceptor_b] - }; - var stream = client.echoServerStream(message, options); - stream.on('data', function(response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('done'); }); }); }); From f963c5e8cc97d098113157536f234ce9c259eb5a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 15:08:32 -0800 Subject: [PATCH 0859/1899] Remove extra log lines --- test/api/interop_extra_test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index d0df38e3c..abf44b3c3 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -46,8 +46,6 @@ function multiDone(done, count) { function echoMetadataGenerator(options, callback) { const metadata = new grpc.Metadata(); metadata.set('x-grpc-test-echo-initial', 'test_initial_metadata_value'); - console.log('Adding metadata'); - console.log(metadata); callback(null, metadata); } From 0c61981ffc2caa348e6982e247083fd14734333f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 15:09:51 -0800 Subject: [PATCH 0860/1899] grpc-js: all client interceptors tests pass with minor modifications --- test/api/client_interceptors_test.js | 104 +++------------------------ 1 file changed, 9 insertions(+), 95 deletions(-) diff --git a/test/api/client_interceptors_test.js b/test/api/client_interceptors_test.js index 19afd7001..74a7adc47 100644 --- a/test/api/client_interceptors_test.js +++ b/test/api/client_interceptors_test.js @@ -93,7 +93,7 @@ CallRegistry.prototype.maybeCallDone = function() { } }; -describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { describe('Client interceptors', function() { var echo_server; var echo_port; @@ -996,12 +996,16 @@ describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, fu }); }); - it.skip('will reject conflicting interceptor options at invocation', + it('will reject conflicting interceptor options at invocation', function(done) { + const interceptor = (options, nextCall) => { + new InterceptingCall(nextCall(options)); + }; + const interceptorProvider = methodDefinition => interceptor try { client.echo('message', { - interceptors: [], - interceptor_providers: [] + interceptors: [interceptor], + interceptor_providers: [interceptorProvider] }, function () {}); } catch (e) { assert.equal(e.name, 'InterceptorConfigurationError'); @@ -1379,7 +1383,7 @@ describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, fu }); }); it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true, true); + registry = new CallRegistry(done, expected_calls, true); var message = {value: originalValue}; var client_stream = client.echoClientStream(metadata, options, function (err, response) { @@ -1817,95 +1821,5 @@ describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, fu bidi_stream.end(); }); }); - - describe.skip('order of operations enforced for async interceptors', function() { - it('with unary call', function(done) { - var expected_calls = [ - 'close_b', - 'message_b', - 'start_b', - 'done' - ]; - var registry = new CallRegistry(done, expected_calls, true); - var message = {value: 'foo'}; - var interceptor_a = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - setTimeout(function() { next(metadata, listener); }, 50); - }, - sendMessage: function(message, next) { - setTimeout(function () { next(message); }, 10); - } - }); - }; - var interceptor_b = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - registry.addCall('start_b'); - next(metadata, listener); - }, - sendMessage: function(message, next) { - registry.addCall('message_b'); - next(message); - }, - halfClose: function(next) { - registry.addCall('close_b'); - next(); - } - }); - }; - var options = { - interceptors: [interceptor_a, interceptor_b] - }; - client.echo(message, options, function(err, response) { - assert.strictEqual(err, null); - registry.addCall('done'); - }); - }); - it('with serverStreaming call', function(done) { - var expected_calls = [ - 'close_b', - 'message_b', - 'start_b', - 'done' - ]; - var registry = new CallRegistry(done, expected_calls, true); - var message = {value: 'foo'}; - var interceptor_a = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - setTimeout(function() { next(metadata, listener); }, 50); - }, - sendMessage: function(message, next) { - setTimeout(function () { next(message); }, 10); - } - }); - }; - var interceptor_b = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - registry.addCall('start_b'); - next(metadata, listener); - }, - sendMessage: function(message, next) { - registry.addCall('message_b'); - next(message); - }, - halfClose: function(next) { - registry.addCall('close_b'); - next(); - } - }); - }; - var options = { - interceptors: [interceptor_a, interceptor_b] - }; - var stream = client.echoServerStream(message, options); - stream.on('data', function(response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('done'); - }); - }); - }); }); }); From eaae8fb3b6aec6f00e9a62f0c353a76ade419f51 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 16:39:11 -0800 Subject: [PATCH 0861/1899] Simplify test gulpfile and improve test order visibility --- test/gulpfile.ts | 62 +++++++++++++++++++----------------------------- 1 file changed, 25 insertions(+), 37 deletions(-) diff --git a/test/gulpfile.ts b/test/gulpfile.ts index be18c5fab..b5d68dfc6 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -31,43 +31,31 @@ const install = () => { const cleanAll = () => Promise.resolve(); -const test = () => { - // run mocha tests matching a glob with a pre-required fixture, - // returning the associated gulp stream - if (!semver.satisfies(process.version, '>=10.10.0')) { - console.log(`Skipping cross-implementation tests for Node ${process.version}`); - return Promise.resolve(); - } - const apiTestGlob = `${apiTestDir}/*.js`; - const runTestsWithFixture = (server, client) => new Promise((resolve, reject) => { - const fixture = `${server}_${client}`; - console.log(`Running ${apiTestGlob} with ${server} server + ${client} client`); - gulp.src(apiTestGlob) - .pipe(mocha({ - reporter: 'mocha-jenkins-reporter', - require: [`${testDir}/fixtures/${fixture}.js`] - })) - .resume() // put the stream in flowing mode - .on('end', resolve) - .on('error', reject); - }); - var runTestsArgPairs; - if (semver.satisfies(process.version, '^8.13.0 || >=10.10.0')) { - runTestsArgPairs = [ - ['native', 'native'], - ['native', 'js'], - ['js', 'native'], - ['js', 'js'] - ]; - } else { - runTestsArgPairs = [ - ['native', 'native'] - ]; - } - return runTestsArgPairs.reduce((previousPromise, argPair) => { - return previousPromise.then(runTestsWithFixture.bind(null, argPair[0], argPair[1])); - }, Promise.resolve()); -}; +const runTestsWithFixture = (server, client) => () => new Promise((resolve, reject) => { + const fixture = `${server}_${client}`; + gulp.src(`${apiTestDir}/*.js`) + .pipe(mocha({ + reporter: 'mocha-jenkins-reporter', + require: [`${testDir}/fixtures/${fixture}.js`] + })) + .resume() // put the stream in flowing mode + .on('end', resolve) + .on('error', reject); +}); + +const testNativeClientNativeServer = runTestsWithFixture('native', 'native'); +const testJsClientNativeServer = runTestsWithFixture('native', 'js'); +const testNativeClientJsServer = runTestsWithFixture('js', 'native'); +const testJsClientJsServer = runTestsWithFixture('js', 'js'); + +const test = semver.satisfies(process.version, '^8.13.0 || >=10.10.0') ? + gulp.series( + testNativeClientNativeServer, + testJsClientNativeServer, + testNativeClientJsServer, + testJsClientJsServer + ) : + testNativeClientNativeServer; export { install, From b15692fa2a93108631c9e1d645974b420f37a253 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 16:39:38 -0800 Subject: [PATCH 0862/1899] grpc-js: Some cleanup + add some comments --- packages/grpc-js/src/call-stream.ts | 5 +- packages/grpc-js/src/client-interceptors.ts | 80 ++++++++++++--------- packages/grpc-js/src/client.ts | 20 +++--- 3 files changed, 59 insertions(+), 46 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 7cd6d68f1..a13ab8c09 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -80,6 +80,9 @@ export interface FullListener { export type Listener = Partial; +/** + * An object with methods for handling the responses to a call. + */ export interface InterceptingListener { onReceiveMetadata(metadata: Metadata): void; onReceiveMessage(message: any): void; @@ -537,7 +540,7 @@ export class Http2CallStream implements Call { message: message, flags: context.flags }; - const cb: WriteCallback = context.callback || (() => {}); + const cb: WriteCallback = context.callback ?? (() => {}); this.isWriteFilterPending = true; this.filterStack.sendMessage(Promise.resolve(writeObj)).then(message => { this.isWriteFilterPending = false; diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index bf93f9beb..28fb47f51 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -23,6 +23,10 @@ import { CallOptions } from './client'; import { CallCredentials } from './call-credentials'; import { ClientMethodDefinition, Serialize } from './make-client'; +/** + * Error class associated with passing both interceptors and interceptor + * providers to a client constructor or as call options. + */ export class InterceptorConfigurationError extends Error { constructor(message: string) { super(message); @@ -47,6 +51,9 @@ export interface CancelRequester { (next: () => void): void; } +/** + * An object with methods for intercepting and modifying outgoing call operations. + */ export interface FullRequester { start: MetadataRequester; sendMessage: MessageRequester; @@ -121,6 +128,10 @@ export class RequesterBuilder { } } +/** + * A Listener with a default pass-through implementation of each method. Used + * for filling out Listeners with some methods omitted. + */ const defaultListener: FullListener = { onReceiveMetadata: (metadata, next) => { next(metadata); @@ -133,6 +144,10 @@ const defaultListener: FullListener = { } }; +/** + * A Requester with a default pass-through implementation of each method. Used + * for filling out Requesters with some methods omitted. + */ const defaultRequester: FullRequester = { start: (metadata, listener, next) => { next(metadata, listener); @@ -161,25 +176,31 @@ export interface InterceptingCallInterface { startRead(): void; halfClose(): void; - getDeadline(): Deadline; - getCredentials(): CallCredentials; setCredentials(credentials: CallCredentials): void; - getMethod(): string; - getHost(): string; } export class InterceptingCall implements InterceptingCallInterface { + /** + * The requester that this InterceptingCall uses to modify outgoing operations + */ private requester: FullRequester; + /** + * Indicates that a message has been passed to the listener's onReceiveMessage + * method it has not been passed to the corresponding next callback + */ private processingMessage = false; + /** + * Indicates that a status was received but could not be propagated because + * a message was still being processed. + */ private pendingHalfClose = false; constructor(private nextCall: InterceptingCallInterface, requester?: Requester) { if (requester) { - // Undefined elements overwrite, unset ones do not this.requester = { - start: requester.start || defaultRequester.start, - sendMessage: requester.sendMessage || defaultRequester.sendMessage, - halfClose: requester.halfClose || defaultRequester.halfClose, - cancel: requester.cancel || defaultRequester.cancel + start: requester.start ?? defaultRequester.start, + sendMessage: requester.sendMessage ?? defaultRequester.sendMessage, + halfClose: requester.halfClose ?? defaultRequester.halfClose, + cancel: requester.cancel ?? defaultRequester.cancel } } else { this.requester = defaultRequester; @@ -241,21 +262,9 @@ export class InterceptingCall implements InterceptingCallInterface { } }); } - getDeadline(): number | Date { - return this.nextCall.getDeadline(); - } - getCredentials(): CallCredentials { - return this.nextCall.getCredentials(); - } setCredentials(credentials: CallCredentials): void { this.nextCall.setCredentials(credentials); } - getMethod(): string { - return this.nextCall.getHost(); - } - getHost(): string { - return this.nextCall.getHost(); - } } function getCall(channel: Channel, path: string, options: CallOptions): Call { @@ -282,6 +291,10 @@ function getCall(channel: Channel, path: string, options: CallOptions): Call { return call; } +/** + * InterceptingCall implementation that directly owns the underlying Call + * object and handles serialization and deseraizliation. + */ class BaseInterceptingCall implements InterceptingCallInterface { constructor(protected call: Call, protected methodDefinition: ClientMethodDefinition) {} cancelWithStatus(status: Status, details: string): void { @@ -290,21 +303,9 @@ class BaseInterceptingCall implements InterceptingCallInterface { getPeer(): string { return this.call.getPeer(); } - getDeadline(): number | Date { - return this.call.getDeadline(); - } - getCredentials(): CallCredentials { - return this.call.getCredentials(); - } setCredentials(credentials: CallCredentials): void { this.call.setCredentials(credentials); } - getMethod(): string { - return this.call.getMethod(); - } - getHost(): string { - return this.call.getHost(); - } sendMessageWithContext(context: MessageContext, message: any): void { let serialized: Buffer; try { @@ -350,6 +351,10 @@ class BaseInterceptingCall implements InterceptingCallInterface { } } +/** + * BaseInterceptingCall with special-cased behavior for methods with unary + * responses. + */ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { constructor(call: Call, methodDefinition: ClientMethodDefinition) { super(call, methodDefinition); @@ -374,6 +379,10 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements Intercep } } +/** + * BaseInterceptingCall with special-cased behavior for methods with streaming + * responses. + */ class BaseStreamingInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { } function getBottomInterceptingCall(channel: Channel, path: string, options: InterceptorOptions, methodDefinition: ClientMethodDefinition) { @@ -437,8 +446,9 @@ export function getInterceptingCall(interceptorArgs: InterceptorArguments, metho * based on the next interceptor in the list, using a nextCall function * constructed with the following interceptor in the list, and so on. The * initialValue, which is effectively at the end of the list, is a nextCall - * function that invokes getBottomInterceptingCall, which handles - * (de)serialization and also gets the underlying call from the channel */ + * function that invokes getBottomInterceptingCall, the result of which + * handles (de)serialization and also gets the underlying call from the + * channel. */ const getCall: NextCall = interceptors.reduceRight((nextCall: NextCall, nextInterceptor: Interceptor) => { return currentOptions => nextInterceptor(currentOptions, nextCall); }, (finalOptions: InterceptorOptions) => getBottomInterceptingCall(channel, methodDefinition.path, finalOptions, methodDefinition)); diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 4d5de5afd..ddeb87787 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -96,8 +96,8 @@ export class Client { options ); } - this[INTERCEPTOR_SYMBOL] = options.interceptors || []; - this[INTERCEPTOR_PROVIDER_SYMBOL] = options.interceptor_providers || []; + this[INTERCEPTOR_SYMBOL] = options.interceptors ?? []; + this[INTERCEPTOR_PROVIDER_SYMBOL] = options.interceptor_providers ?? []; if (this[INTERCEPTOR_SYMBOL].length > 0 && this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0) { throw new Error( 'Both interceptors and interceptor_providers were passed as options ' + @@ -228,8 +228,8 @@ export class Client { const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors || [], - callInterceptorProviders: options.interceptor_providers || [] + callInterceptors: options.interceptors ?? [], + callInterceptorProviders: options.interceptor_providers ?? [] }; const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { @@ -315,8 +315,8 @@ export class Client { const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors || [], - callInterceptorProviders: options.interceptor_providers || [] + callInterceptors: options.interceptors ?? [], + callInterceptorProviders: options.interceptor_providers ?? [] }; const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { @@ -409,8 +409,8 @@ export class Client { const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors || [], - callInterceptorProviders: options.interceptor_providers || [] + callInterceptors: options.interceptors ?? [], + callInterceptorProviders: options.interceptor_providers ?? [] }; const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { @@ -475,8 +475,8 @@ export class Client { const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors || [], - callInterceptorProviders: options.interceptor_providers || [] + callInterceptors: options.interceptors ?? [], + callInterceptorProviders: options.interceptor_providers ?? [] }; const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); if (options.credentials) { From 42857611579dfd804c1daad81ca11eababcd7cfb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 17:26:40 -0800 Subject: [PATCH 0863/1899] lint and formatting fixes --- packages/grpc-js/src/call-stream.ts | 47 ++-- packages/grpc-js/src/call.ts | 8 +- packages/grpc-js/src/client-interceptors.ts | 245 ++++++++++++++------ packages/grpc-js/src/client.ts | 115 ++++++--- packages/grpc-js/src/index.ts | 15 +- packages/grpc-js/src/make-client.ts | 5 +- 6 files changed, 309 insertions(+), 126 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index a13ab8c09..b6e23bda7 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -65,6 +65,7 @@ export interface MetadataListener { } export interface MessageListener { + // tslint:disable-next-line no-any (message: any, next: (message: any) => void): void; } @@ -85,29 +86,39 @@ export type Listener = Partial; */ export interface InterceptingListener { onReceiveMetadata(metadata: Metadata): void; + // tslint:disable-next-line no-any onReceiveMessage(message: any): void; onReceiveStatus(status: StatusObject): void; } -export function isInterceptingListener(listener: Listener | InterceptingListener): listener is InterceptingListener { - return listener.onReceiveMetadata !== undefined && listener.onReceiveMetadata.length === 1; +export function isInterceptingListener( + listener: Listener | InterceptingListener +): listener is InterceptingListener { + return ( + listener.onReceiveMetadata !== undefined && + listener.onReceiveMetadata.length === 1 + ); } export class InterceptingListenerImpl implements InterceptingListener { private processingMessage = false; private pendingStatus: StatusObject | null = null; - constructor(private listener: FullListener, private nextListener: InterceptingListener) {} + constructor( + private listener: FullListener, + private nextListener: InterceptingListener + ) {} onReceiveMetadata(metadata: Metadata): void { - this.listener.onReceiveMetadata(metadata, (metadata) => { + this.listener.onReceiveMetadata(metadata, metadata => { this.nextListener.onReceiveMetadata(metadata); }); } + // tslint:disable-next-line no-any onReceiveMessage(message: any): void { /* If this listener processes messages asynchronously, the last message may * be reordered with respect to the status */ this.processingMessage = true; - this.listener.onReceiveMessage(message, (msg) => { + this.listener.onReceiveMessage(message, msg => { this.processingMessage = false; this.nextListener.onReceiveMessage(msg); if (this.pendingStatus) { @@ -116,7 +127,7 @@ export class InterceptingListenerImpl implements InterceptingListener { }); } onReceiveStatus(status: StatusObject): void { - this.listener.onReceiveStatus(status, (processedStatus) => { + this.listener.onReceiveStatus(status, processedStatus => { if (this.processingMessage) { this.pendingStatus = processedStatus; } else { @@ -139,7 +150,7 @@ export interface Call { cancelWithStatus(status: Status, details: string): void; getPeer(): string; start(metadata: Metadata, listener: InterceptingListener): void; - sendMessageWithContext(context: MessageContext, message: any): void; + sendMessageWithContext(context: MessageContext, message: Buffer): void; startRead(): void; halfClose(): void; @@ -235,7 +246,13 @@ export class Http2CallStream implements Call { /* The combination check of readsClosed and that the two message buffer * arrays are empty checks that there all incoming data has been fully * processed */ - if (this.finalStatus.code !== Status.OK || (this.readsClosed && this.unpushedReadMessages.length === 0 && this.unfilteredReadMessages.length === 0 && !this.isReadFilterPending)) { + if ( + this.finalStatus.code !== Status.OK || + (this.readsClosed && + this.unpushedReadMessages.length === 0 && + this.unfilteredReadMessages.length === 0 && + !this.isReadFilterPending) + ) { this.outputStatus(); } } @@ -259,7 +276,7 @@ export class Http2CallStream implements Call { } this.isReadFilterPending = false; if (this.canPush) { - this.push(message) + this.push(message); this.canPush = false; this.http2Stream!.pause(); } else { @@ -530,15 +547,19 @@ export class Http2CallStream implements Call { } private maybeCloseWrites() { - if (this.writesClosed && !this.isWriteFilterPending && this.http2Stream !== null) { + if ( + this.writesClosed && + !this.isWriteFilterPending && + this.http2Stream !== null + ) { this.http2Stream.end(); } } sendMessageWithContext(context: MessageContext, message: Buffer) { const writeObj: WriteObject = { - message: message, - flags: context.flags + message, + flags: context.flags, }; const cb: WriteCallback = context.callback ?? (() => {}); this.isWriteFilterPending = true; @@ -558,4 +579,4 @@ export class Http2CallStream implements Call { this.writesClosed = true; this.maybeCloseWrites(); } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 42d0886f5..921e19715 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -136,8 +136,8 @@ export class ClientWritableStreamImpl extends Writable _write(chunk: RequestType, encoding: string, cb: WriteCallback) { const context: MessageContext = { - callback: cb - } + callback: cb, + }; const flags: number = Number(encoding); if (!Number.isNaN(flags)) { context.flags = flags; @@ -175,8 +175,8 @@ export class ClientDuplexStreamImpl extends Duplex _write(chunk: RequestType, encoding: string, cb: WriteCallback) { const context: MessageContext = { - callback: cb - } + callback: cb, + }; const flags: number = Number(encoding); if (!Number.isNaN(flags)) { context.flags = flags; diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 28fb47f51..a06fda1fe 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -16,7 +16,24 @@ */ import { Metadata } from './metadata'; -import { StatusObject, CallStreamOptions, Listener, MetadataListener, MessageListener, StatusListener, FullListener, InterceptingListener, WriteObject, WriteCallback, InterceptingListenerImpl, isInterceptingListener, MessageContext, Http2CallStream, Deadline, Call } from './call-stream'; +import { + StatusObject, + CallStreamOptions, + Listener, + MetadataListener, + MessageListener, + StatusListener, + FullListener, + InterceptingListener, + WriteObject, + WriteCallback, + InterceptingListenerImpl, + isInterceptingListener, + MessageContext, + Http2CallStream, + Deadline, + Call, +} from './call-stream'; import { Status } from './constants'; import { Channel } from './channel'; import { CallOptions } from './client'; @@ -36,10 +53,18 @@ export class InterceptorConfigurationError extends Error { } export interface MetadataRequester { - (metadata: Metadata, listener: InterceptingListener, next: (metadata: Metadata, listener: InterceptingListener | Listener) => void): void; + ( + metadata: Metadata, + listener: InterceptingListener, + next: ( + metadata: Metadata, + listener: InterceptingListener | Listener + ) => void + ): void; } export interface MessageRequester { + // tslint:disable-next-line no-any (message: any, next: (message: any) => void): void; } @@ -87,8 +112,8 @@ export class ListenerBuilder { return { onReceiveMetadata: this.metadata, onReceiveMessage: this.message, - onReceiveStatus: this.status - } + onReceiveStatus: this.status, + }; } } @@ -123,7 +148,7 @@ export class RequesterBuilder { start: this.start, sendMessage: this.message, halfClose: this.halfClose, - cancel: this.cancel + cancel: this.cancel, }; } } @@ -141,7 +166,7 @@ const defaultListener: FullListener = { }, onReceiveStatus: (status, next) => { next(status); - } + }, }; /** @@ -155,15 +180,16 @@ const defaultRequester: FullRequester = { sendMessage: (message, next) => { next(message); }, - halfClose: (next) => { + halfClose: next => { next(); }, - cancel: (next) => { + cancel: next => { next(); - } -} + }, +}; export interface InterceptorOptions extends CallOptions { + // tslint:disable-next-line no-any method_definition: ClientMethodDefinition; } @@ -171,7 +197,9 @@ export interface InterceptingCallInterface { cancelWithStatus(status: Status, details: string): void; getPeer(): string; start(metadata: Metadata, listener?: Partial): void; + // tslint:disable-next-line no-any sendMessageWithContext(context: MessageContext, message: any): void; + // tslint:disable-next-line no-any sendMessage(message: any): void; startRead(): void; halfClose(): void; @@ -194,14 +222,17 @@ export class InterceptingCall implements InterceptingCallInterface { * a message was still being processed. */ private pendingHalfClose = false; - constructor(private nextCall: InterceptingCallInterface, requester?: Requester) { + constructor( + private nextCall: InterceptingCallInterface, + requester?: Requester + ) { if (requester) { this.requester = { start: requester.start ?? defaultRequester.start, sendMessage: requester.sendMessage ?? defaultRequester.sendMessage, halfClose: requester.halfClose ?? defaultRequester.halfClose, - cancel: requester.cancel ?? defaultRequester.cancel - } + cancel: requester.cancel ?? defaultRequester.cancel, + }; } else { this.requester = defaultRequester; } @@ -216,30 +247,46 @@ export class InterceptingCall implements InterceptingCallInterface { getPeer() { return this.nextCall.getPeer(); } - start(metadata: Metadata, interceptingListener?: Partial): void { + start( + metadata: Metadata, + interceptingListener?: Partial + ): void { const fullInterceptingListener: InterceptingListener = { - onReceiveMetadata: interceptingListener?.onReceiveMetadata?.bind(interceptingListener) ?? (metadata => {}), - onReceiveMessage: interceptingListener?.onReceiveMessage?.bind(interceptingListener) ?? (message => {}), - onReceiveStatus: interceptingListener?.onReceiveStatus?.bind(interceptingListener) ?? (status => {}) - } + onReceiveMetadata: + interceptingListener?.onReceiveMetadata?.bind(interceptingListener) ?? + (metadata => {}), + onReceiveMessage: + interceptingListener?.onReceiveMessage?.bind(interceptingListener) ?? + (message => {}), + onReceiveStatus: + interceptingListener?.onReceiveStatus?.bind(interceptingListener) ?? + (status => {}), + }; this.requester.start(metadata, fullInterceptingListener, (md, listener) => { let finalInterceptingListener: InterceptingListener; if (isInterceptingListener(listener)) { finalInterceptingListener = listener; } else { const fullListener: FullListener = { - onReceiveMetadata: listener.onReceiveMetadata ?? defaultListener.onReceiveMetadata, - onReceiveMessage: listener.onReceiveMessage ?? defaultListener.onReceiveMessage, - onReceiveStatus: listener.onReceiveStatus ?? defaultListener.onReceiveStatus + onReceiveMetadata: + listener.onReceiveMetadata ?? defaultListener.onReceiveMetadata, + onReceiveMessage: + listener.onReceiveMessage ?? defaultListener.onReceiveMessage, + onReceiveStatus: + listener.onReceiveStatus ?? defaultListener.onReceiveStatus, }; - finalInterceptingListener = new InterceptingListenerImpl(fullListener, fullInterceptingListener); + finalInterceptingListener = new InterceptingListenerImpl( + fullListener, + fullInterceptingListener + ); } this.nextCall.start(md, finalInterceptingListener); }); } + // tslint:disable-next-line no-any sendMessageWithContext(context: MessageContext, message: any): void { this.processingMessage = true; - this.requester.sendMessage(message, (finalMessage) => { + this.requester.sendMessage(message, finalMessage => { this.processingMessage = false; this.nextCall.sendMessageWithContext(context, finalMessage); if (this.pendingHalfClose) { @@ -247,6 +294,7 @@ export class InterceptingCall implements InterceptingCallInterface { } }); } + // tslint:disable-next-line no-any sendMessage(message: any): void { this.sendMessageWithContext({}, message); } @@ -268,23 +316,22 @@ export class InterceptingCall implements InterceptingCallInterface { } function getCall(channel: Channel, path: string, options: CallOptions): Call { - var deadline; - var host; - var parent; - var propagate_flags; - var credentials; + let deadline; + let host; + const parent = null; + let propagateFlags; + let credentials; if (options) { deadline = options.deadline; host = options.host; - propagate_flags = options.propagate_flags; + propagateFlags = options.propagate_flags; credentials = options.credentials; } if (deadline === undefined) { deadline = Infinity; } - var call = channel.createCall(path, deadline, host, - parent, propagate_flags); + const call = channel.createCall(path, deadline, host, parent, propagateFlags); if (credentials) { call.setCredentials(credentials); } @@ -296,7 +343,11 @@ function getCall(channel: Channel, path: string, options: CallOptions): Call { * object and handles serialization and deseraizliation. */ class BaseInterceptingCall implements InterceptingCallInterface { - constructor(protected call: Call, protected methodDefinition: ClientMethodDefinition) {} + // tslint:disable-next-line no-any + constructor( + protected call: Call, + protected methodDefinition: ClientMethodDefinition + ) {} cancelWithStatus(status: Status, details: string): void { this.call.cancelWithStatus(status, details); } @@ -306,6 +357,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { setCredentials(credentials: CallCredentials): void { this.call.setCredentials(credentials); } + // tslint:disable-next-line no-any sendMessageWithContext(context: MessageContext, message: any): void { let serialized: Buffer; try { @@ -315,32 +367,41 @@ class BaseInterceptingCall implements InterceptingCallInterface { this.call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); } } + // tslint:disable-next-line no-any sendMessage(message: any) { this.sendMessageWithContext({}, message); } - start(metadata: Metadata, interceptingListener?: Partial): void { + start( + metadata: Metadata, + interceptingListener?: Partial + ): void { let readError: StatusObject | null = null; this.call.start(metadata, { - onReceiveMetadata: (metadata) => { + onReceiveMetadata: metadata => { interceptingListener?.onReceiveMetadata?.(metadata); }, - onReceiveMessage: (message) => { + onReceiveMessage: message => { + // tslint:disable-next-line no-any let deserialized: any; try { deserialized = this.methodDefinition.responseDeserialize(message); interceptingListener?.onReceiveMessage?.(deserialized); } catch (e) { - readError = {code: Status.INTERNAL, details: 'Failed to parse server response', metadata: new Metadata()}; + readError = { + code: Status.INTERNAL, + details: 'Failed to parse server response', + metadata: new Metadata(), + }; this.call.cancelWithStatus(readError.code, readError.details); } }, - onReceiveStatus: (status) => { + onReceiveStatus: status => { if (readError) { interceptingListener?.onReceiveStatus?.(readError); } else { interceptingListener?.onReceiveStatus?.(status); } - } + }, }); } startRead() { @@ -355,14 +416,18 @@ class BaseInterceptingCall implements InterceptingCallInterface { * BaseInterceptingCall with special-cased behavior for methods with unary * responses. */ -class BaseUnaryInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { +class BaseUnaryInterceptingCall extends BaseInterceptingCall + implements InterceptingCallInterface { + // tslint:disable-next-line no-any constructor(call: Call, methodDefinition: ClientMethodDefinition) { super(call, methodDefinition); } start(metadata: Metadata, listener?: Partial): void { let receivedMessage = false; const wrapperListener: InterceptingListener = { - onReceiveMetadata: listener?.onReceiveMetadata?.bind(listener) ?? (metadata => {}), + onReceiveMetadata: + listener?.onReceiveMetadata?.bind(listener) ?? (metadata => {}), + // tslint:disable-next-line no-any onReceiveMessage: (message: any) => { receivedMessage = true; listener?.onReceiveMessage?.(message); @@ -372,8 +437,8 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements Intercep listener?.onReceiveMessage?.(null); } listener?.onReceiveStatus?.(status); - } - } + }, + }; super.start(metadata, wrapperListener); this.call.startRead(); } @@ -383,9 +448,16 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements Intercep * BaseInterceptingCall with special-cased behavior for methods with streaming * responses. */ -class BaseStreamingInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { } - -function getBottomInterceptingCall(channel: Channel, path: string, options: InterceptorOptions, methodDefinition: ClientMethodDefinition) { +class BaseStreamingInterceptingCall extends BaseInterceptingCall + implements InterceptingCallInterface {} + +// tslint:disable-next-line no-any +function getBottomInterceptingCall( + channel: Channel, + path: string, + options: InterceptorOptions, + methodDefinition: ClientMethodDefinition +) { const call = getCall(channel, path, options); if (methodDefinition.responseStream) { return new BaseStreamingInterceptingCall(call, methodDefinition); @@ -399,49 +471,75 @@ export interface NextCall { } export interface Interceptor { - (options: InterceptorOptions, nextCall: NextCall): InterceptingCall + (options: InterceptorOptions, nextCall: NextCall): InterceptingCall; } export interface InterceptorProvider { + // tslint:disable-next-line no-any (methodDefinition: ClientMethodDefinition): Interceptor; } export interface InterceptorArguments { - clientInterceptors: Interceptor[], - clientInterceptorProviders: InterceptorProvider[], - callInterceptors: Interceptor[], - callInterceptorProviders: InterceptorProvider[] + clientInterceptors: Interceptor[]; + clientInterceptorProviders: InterceptorProvider[]; + callInterceptors: Interceptor[]; + callInterceptorProviders: InterceptorProvider[]; } -export function getInterceptingCall(interceptorArgs: InterceptorArguments, methodDefinition: ClientMethodDefinition, options: CallOptions, channel: Channel): InterceptingCallInterface { - if (interceptorArgs.clientInterceptors.length > 0 && interceptorArgs.clientInterceptorProviders.length > 0) { +// tslint:disable-next-line no-any +export function getInterceptingCall( + interceptorArgs: InterceptorArguments, + methodDefinition: ClientMethodDefinition, + options: CallOptions, + channel: Channel +): InterceptingCallInterface { + if ( + interceptorArgs.clientInterceptors.length > 0 && + interceptorArgs.clientInterceptorProviders.length > 0 + ) { throw new InterceptorConfigurationError( 'Both interceptors and interceptor_providers were passed as options ' + - 'to the client constructor. Only one of these is allowed.' + 'to the client constructor. Only one of these is allowed.' ); } - if (interceptorArgs.callInterceptors.length > 0 && interceptorArgs.callInterceptorProviders.length > 0) { + if ( + interceptorArgs.callInterceptors.length > 0 && + interceptorArgs.callInterceptorProviders.length > 0 + ) { throw new InterceptorConfigurationError( 'Both interceptors and interceptor_providers were passed as call ' + - 'options. Only one of these is allowed.' + 'options. Only one of these is allowed.' ); } let interceptors: Interceptor[] = []; // Interceptors passed to the call override interceptors passed to the client constructor - if (interceptorArgs.callInterceptors.length > 0 || interceptorArgs.callInterceptorProviders.length > 0) { - interceptors = ([] as Interceptor[]).concat( - interceptorArgs.callInterceptors, - interceptorArgs.callInterceptorProviders.map(provider => provider(methodDefinition)) - ).filter(interceptor => interceptor); + if ( + interceptorArgs.callInterceptors.length > 0 || + interceptorArgs.callInterceptorProviders.length > 0 + ) { + interceptors = ([] as Interceptor[]) + .concat( + interceptorArgs.callInterceptors, + interceptorArgs.callInterceptorProviders.map(provider => + provider(methodDefinition) + ) + ) + .filter(interceptor => interceptor); // Filter out falsy values when providers return nothing } else { - interceptors = ([] as Interceptor[]).concat( - interceptorArgs.clientInterceptors, - interceptorArgs.clientInterceptorProviders.map(provider => provider(methodDefinition)) - ).filter(interceptor => interceptor); + interceptors = ([] as Interceptor[]) + .concat( + interceptorArgs.clientInterceptors, + interceptorArgs.clientInterceptorProviders.map(provider => + provider(methodDefinition) + ) + ) + .filter(interceptor => interceptor); // Filter out falsy values when providers return nothing } - const interceptorOptions = Object.assign({}, options, {method_definition: methodDefinition}); + const interceptorOptions = Object.assign({}, options, { + method_definition: methodDefinition, + }); /* For each interceptor in the list, the nextCall function passed to it is * based on the next interceptor in the list, using a nextCall function * constructed with the following interceptor in the list, and so on. The @@ -449,8 +547,17 @@ export function getInterceptingCall(interceptorArgs: InterceptorArguments, metho * function that invokes getBottomInterceptingCall, the result of which * handles (de)serialization and also gets the underlying call from the * channel. */ - const getCall: NextCall = interceptors.reduceRight((nextCall: NextCall, nextInterceptor: Interceptor) => { - return currentOptions => nextInterceptor(currentOptions, nextCall); - }, (finalOptions: InterceptorOptions) => getBottomInterceptingCall(channel, methodDefinition.path, finalOptions, methodDefinition)); + const getCall: NextCall = interceptors.reduceRight( + (nextCall: NextCall, nextInterceptor: Interceptor) => { + return currentOptions => nextInterceptor(currentOptions, nextCall); + }, + (finalOptions: InterceptorOptions) => + getBottomInterceptingCall( + channel, + methodDefinition.path, + finalOptions, + methodDefinition + ) + ); return getCall(interceptorOptions); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index ddeb87787..1ba7bd326 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -29,14 +29,25 @@ import { SurfaceCall, } from './call'; import { CallCredentials } from './call-credentials'; -import { Deadline, StatusObject, WriteObject, InterceptingListener } from './call-stream'; +import { + Deadline, + StatusObject, + WriteObject, + InterceptingListener, +} from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; import { ClientMethodDefinition } from './make-client'; -import { getInterceptingCall, Interceptor, InterceptorProvider, InterceptorArguments, InterceptingCallInterface } from './client-interceptors'; +import { + getInterceptingCall, + Interceptor, + InterceptorProvider, + InterceptorArguments, + InterceptingCallInterface, +} from './client-interceptors'; const CHANNEL_SYMBOL = Symbol(); const INTERCEPTOR_SYMBOL = Symbol(); @@ -53,8 +64,8 @@ export interface CallOptions { * but the server is not yet implemented so it makes no sense to have it */ propagate_flags?: number; credentials?: CallCredentials; - interceptors?: Interceptor[], - interceptor_providers?: InterceptorProvider[] + interceptors?: Interceptor[]; + interceptor_providers?: InterceptorProvider[]; } export type ClientOptions = Partial & { @@ -64,8 +75,8 @@ export type ClientOptions = Partial & { credentials: ChannelCredentials, options: ClientOptions ) => Channel; - interceptors?: Interceptor[], - interceptor_providers?: InterceptorProvider[] + interceptors?: Interceptor[]; + interceptor_providers?: InterceptorProvider[]; }; /** @@ -98,10 +109,14 @@ export class Client { } this[INTERCEPTOR_SYMBOL] = options.interceptors ?? []; this[INTERCEPTOR_PROVIDER_SYMBOL] = options.interceptor_providers ?? []; - if (this[INTERCEPTOR_SYMBOL].length > 0 && this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0) { + if ( + this[INTERCEPTOR_SYMBOL].length > 0 && + this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0 + ) { throw new Error( 'Both interceptors and interceptor_providers were passed as options ' + - 'to the client constructor. Only one of these is allowed.'); + 'to the client constructor. Only one of these is allowed.' + ); } } @@ -218,20 +233,28 @@ export class Client { ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< ResponseType >(metadata, options, callback)); - const methodDefinition: ClientMethodDefinition = { + const methodDefinition: ClientMethodDefinition< + RequestType, + ResponseType + > = { path: method, requestStream: false, responseStream: false, requestSerialize: serialize, - responseDeserialize: deserialize + responseDeserialize: deserialize, }; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [] + callInterceptorProviders: options.interceptor_providers ?? [], }; - const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall( + interceptorArgs, + methodDefinition, + options, + this[CHANNEL_SYMBOL] + ); if (options.credentials) { call.setCredentials(options.credentials); } @@ -239,9 +262,10 @@ export class Client { let responseMessage: ResponseType | null = null; let receivedStatus = false; call.start(metadata, { - onReceiveMetadata: (metadata) => { + onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, + // tslint:disable-next-line no-any onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -259,7 +283,7 @@ export class Client { callback!(callErrorFromStatus(status)); } emitter.emit('status', status); - } + }, }); call.sendMessage(argument); call.halfClose(); @@ -305,20 +329,28 @@ export class Client { ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< ResponseType >(metadata, options, callback)); - const methodDefinition: ClientMethodDefinition = { + const methodDefinition: ClientMethodDefinition< + RequestType, + ResponseType + > = { path: method, requestStream: true, responseStream: false, requestSerialize: serialize, - responseDeserialize: deserialize + responseDeserialize: deserialize, }; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [] + callInterceptorProviders: options.interceptor_providers ?? [], }; - const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall( + interceptorArgs, + methodDefinition, + options, + this[CHANNEL_SYMBOL] + ); if (options.credentials) { call.setCredentials(options.credentials); } @@ -326,9 +358,10 @@ export class Client { let responseMessage: ResponseType | null = null; let receivedStatus = false; call.start(metadata, { - onReceiveMetadata: (metadata) => { + onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, + // tslint:disable-next-line no-any onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -346,7 +379,7 @@ export class Client { callback!(callErrorFromStatus(status)); } emitter.emit('status', status); - } + }, }); return emitter; } @@ -399,29 +432,41 @@ export class Client { options?: CallOptions ): ClientReadableStream { ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); - const methodDefinition: ClientMethodDefinition = { + const methodDefinition: ClientMethodDefinition< + RequestType, + ResponseType + > = { path: method, requestStream: false, responseStream: true, requestSerialize: serialize, - responseDeserialize: deserialize + responseDeserialize: deserialize, }; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [] + callInterceptorProviders: options.interceptor_providers ?? [], }; - const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall( + interceptorArgs, + methodDefinition, + options, + this[CHANNEL_SYMBOL] + ); if (options.credentials) { call.setCredentials(options.credentials); } - const stream = new ClientReadableStreamImpl(call, deserialize); + const stream = new ClientReadableStreamImpl( + call, + deserialize + ); let receivedStatus = false; call.start(metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); }, + // tslint:disable-next-line no-any onReceiveMessage(message: any) { if (stream.push(message)) { call.startRead(); @@ -437,7 +482,7 @@ export class Client { stream.emit('error', callErrorFromStatus(status)); } stream.emit('status', status); - } + }, }); call.sendMessage(argument); call.halfClose(); @@ -465,20 +510,28 @@ export class Client { options?: CallOptions ): ClientDuplexStream { ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); - const methodDefinition: ClientMethodDefinition = { + const methodDefinition: ClientMethodDefinition< + RequestType, + ResponseType + > = { path: method, requestStream: true, responseStream: true, requestSerialize: serialize, - responseDeserialize: deserialize + responseDeserialize: deserialize, }; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [] + callInterceptorProviders: options.interceptor_providers ?? [], }; - const call: InterceptingCallInterface = getInterceptingCall(interceptorArgs, methodDefinition, options, this[CHANNEL_SYMBOL]); + const call: InterceptingCallInterface = getInterceptingCall( + interceptorArgs, + methodDefinition, + options, + this[CHANNEL_SYMBOL] + ); if (options.credentials) { call.setCredentials(options.credentials); } @@ -507,7 +560,7 @@ export class Client { stream.emit('error', callErrorFromStatus(status)); } stream.emit('status', status); - } + }, }); return stream; } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index f1c22eac0..e38c8c964 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -284,14 +284,15 @@ export { StatusBuilder }; export { Listener } from './call-stream'; -export { - Requester, - ListenerBuilder, - RequesterBuilder, - Interceptor, - InterceptorProvider, +export { + Requester, + ListenerBuilder, + RequesterBuilder, + Interceptor, + InterceptorProvider, InterceptingCall, - InterceptorConfigurationError } from './client-interceptors'; + InterceptorConfigurationError, +} from './client-interceptors'; export { GrpcObject } from './make-client'; diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 0e033d07e..99d40a649 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -45,8 +45,9 @@ export interface ServerMethodDefinition { originalName?: string; } -export interface MethodDefinition extends ClientMethodDefinition, ServerMethodDefinition { -} +export interface MethodDefinition + extends ClientMethodDefinition, + ServerMethodDefinition {} export interface ServiceDefinition { // tslint:disable-next-line no-any From 2d73ed263d9ca76ddac764473814b81b6ba110a7 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 14 Nov 2019 18:14:04 -0800 Subject: [PATCH 0864/1899] Change submodule back to what it is on master --- packages/grpc-native-core/deps/grpc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc index e6224f8fd..f703e1c86 160000 --- a/packages/grpc-native-core/deps/grpc +++ b/packages/grpc-native-core/deps/grpc @@ -1 +1 @@ -Subproject commit e6224f8fd9e4903238cebf22b9d78d09e52c378c +Subproject commit f703e1c86c1504d9e48953f8da31f842679b7775 From 90ce40f91c318b23bcd0e69a421ec9a04efcbf9c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Nov 2019 12:51:43 -0800 Subject: [PATCH 0865/1899] Treat trailers as end of incoming messages --- packages/grpc-js/src/call-stream.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index b6e23bda7..1bc43e140 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -315,6 +315,7 @@ export class Http2CallStream implements Call { } private handleTrailers(headers: http2.IncomingHttpHeaders) { + this.readsClosed = true; const code: Status = this.mappedStatusCode; const details = ''; let metadata: Metadata; From 7f62173246534fc3cdef4532780d55398e34d88e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Nov 2019 13:05:52 -0800 Subject: [PATCH 0866/1899] Fix Channel#getConnectivityState API and behavior --- packages/grpc-js/src/channel.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index c1ab84595..25daa4688 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -304,8 +304,12 @@ export class ChannelImplementation implements Channel { return this.target; } - getConnectivityState() { - return this.connectivityState; + getConnectivityState(tryToConnect: boolean) { + const connectivityState = this.connectivityState; + if (tryToConnect) { + this.resolvingLoadBalancer.exitIdle(); + } + return connectivityState; } watchConnectivityState( From 39627e07dc0007ae11c2cfcdbd675820abf0aedc Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 15 Nov 2019 14:55:03 -0800 Subject: [PATCH 0867/1899] grpc-js: bump to 0.6.12 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index cd498cb94..2d942ba8b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.11", + "version": "0.6.12", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 4409ef8dfdc4a4013ab5ead0a5566ba653ad03af Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 18 Nov 2019 11:25:20 -0800 Subject: [PATCH 0868/1899] Push messages to reader asynchronously. --- packages/grpc-js/src/call-stream.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 1bc43e140..c7def5696 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -259,8 +259,11 @@ export class Http2CallStream implements Call { } private push(message: Buffer): void { - this.listener!.onReceiveMessage(message); - this.maybeOutputStatus(); + this.canPush = false; + process.nextTick(() => { + this.listener!.onReceiveMessage(message); + this.maybeOutputStatus(); + }); } private handleFilterError(error: Error) { @@ -276,9 +279,8 @@ export class Http2CallStream implements Call { } this.isReadFilterPending = false; if (this.canPush) { - this.push(message); - this.canPush = false; this.http2Stream!.pause(); + this.push(message); } else { this.unpushedReadMessages.push(message); } @@ -315,7 +317,6 @@ export class Http2CallStream implements Call { } private handleTrailers(headers: http2.IncomingHttpHeaders) { - this.readsClosed = true; const code: Status = this.mappedStatusCode; const details = ''; let metadata: Metadata; @@ -527,6 +528,7 @@ export class Http2CallStream implements Call { /* If we have already emitted a status, we should not emit any more * messages and we should communicate that the stream has ended */ if (this.finalStatus !== null) { + this.readsClosed = true; this.maybeOutputStatus(); return; } @@ -537,12 +539,10 @@ export class Http2CallStream implements Call { if (this.unpushedReadMessages.length > 0) { const nextMessage: Buffer = this.unpushedReadMessages.shift()!; this.push(nextMessage); - this.canPush = false; return; } /* Only resume reading from the http2Stream if we don't have any pending - * messages to emit, and we haven't gotten the signal to stop pushing - * messages */ + * messages to emit */ this.http2Stream.resume(); } } From 6109391e36bb157ca2ffba2925697560062591a6 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Tue, 19 Nov 2019 14:48:24 -0800 Subject: [PATCH 0869/1899] Fix MacOS failure --- test/kokoro.bat | 3 +-- test/kokoro.sh | 3 +-- tools/release/kokoro-electron.bat | 3 +-- tools/release/kokoro-electron.sh | 3 +-- tools/release/kokoro-nodejs.bat | 3 +-- tools/release/kokoro-nodejs.sh | 3 +-- 6 files changed, 6 insertions(+), 12 deletions(-) diff --git a/test/kokoro.bat b/test/kokoro.bat index 1f0fabfcf..3190c141e 100644 --- a/test/kokoro.bat +++ b/test/kokoro.bat @@ -17,7 +17,6 @@ cd /d %~dp0 cd .. -git submodule update --init -git submodule foreach --recursive git submodule update --init +git submodule update --init --recursive .\run-tests.bat diff --git a/test/kokoro.sh b/test/kokoro.sh index c4b9373b4..d28d18cf8 100755 --- a/test/kokoro.sh +++ b/test/kokoro.sh @@ -17,8 +17,7 @@ set -e cd $(dirname $0)/.. # Install gRPC and its submodules. -git submodule update --init -git submodule foreach --recursive git submodule update --init +git submodule update --init --recursive ./packages/grpc-native-core/tools/buildgen/generate_projects.sh diff --git a/tools/release/kokoro-electron.bat b/tools/release/kokoro-electron.bat index c27db4806..dde9b134c 100644 --- a/tools/release/kokoro-electron.bat +++ b/tools/release/kokoro-electron.bat @@ -27,8 +27,7 @@ call npm install -g node-gyp@3 cd /d %~dp0 cd ..\.. -git submodule update --init -git submodule foreach --recursive git submodule update --init +git submodule update --init --recursive set ARTIFACTS_OUT=artifacts cd packages\grpc-native-core diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh index 1305c1ae7..c0302538b 100755 --- a/tools/release/kokoro-electron.sh +++ b/tools/release/kokoro-electron.sh @@ -28,8 +28,7 @@ cd $(dirname $0)/../.. base_dir=$(pwd) # Install gRPC and its submodules. -git submodule update --init -git submodule foreach --recursive git submodule update --init +git submodule update --init --recursive pip install mako ./packages/grpc-native-core/tools/buildgen/generate_projects.sh diff --git a/tools/release/kokoro-nodejs.bat b/tools/release/kokoro-nodejs.bat index faa6364ac..dd6aecfc5 100644 --- a/tools/release/kokoro-nodejs.bat +++ b/tools/release/kokoro-nodejs.bat @@ -27,8 +27,7 @@ call npm install -g node-gyp@3 cd /d %~dp0 cd ..\.. -git submodule update --init -git submodule foreach --recursive git submodule update --init +git submodule update --init --recursive set ARTIFACTS_OUT=%cd%\artifacts cd packages\grpc-native-core diff --git a/tools/release/kokoro-nodejs.sh b/tools/release/kokoro-nodejs.sh index c1f905622..e3dd3d05e 100755 --- a/tools/release/kokoro-nodejs.sh +++ b/tools/release/kokoro-nodejs.sh @@ -28,8 +28,7 @@ cd $(dirname $0)/../.. base_dir=$(pwd) # Install gRPC and its submodules. -git submodule update --init -git submodule foreach --recursive git submodule update --init +git submodule update --init --recursive pip install mako ./packages/grpc-native-core/tools/buildgen/generate_projects.sh From af8591701789131953880469df67b9bc49d93fd7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 20 Nov 2019 00:42:29 +0100 Subject: [PATCH 0870/1899] Deleting Ruby. --- test/kokoro.sh | 3 +++ tools/release/kokoro-electron.sh | 3 +++ tools/release/kokoro-grpc-tools.sh | 3 +++ tools/release/kokoro-nodejs.sh | 3 +++ 4 files changed, 12 insertions(+) diff --git a/test/kokoro.sh b/test/kokoro.sh index d28d18cf8..38ea41b2e 100755 --- a/test/kokoro.sh +++ b/test/kokoro.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Deleting Ruby. +rm -rf ~/.rvm + set -e cd $(dirname $0)/.. diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh index c0302538b..721b9c97a 100755 --- a/tools/release/kokoro-electron.sh +++ b/tools/release/kokoro-electron.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Deleting Ruby. +rm -rf ~/.rvm + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh index b672c0cb1..267d6cc25 100755 --- a/tools/release/kokoro-grpc-tools.sh +++ b/tools/release/kokoro-grpc-tools.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Deleting Ruby. +rm -rf ~/.rvm + set -e cd $(dirname $0)/../.. base_dir=$(pwd) diff --git a/tools/release/kokoro-nodejs.sh b/tools/release/kokoro-nodejs.sh index e3dd3d05e..7dd89c890 100755 --- a/tools/release/kokoro-nodejs.sh +++ b/tools/release/kokoro-nodejs.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +# Deleting Ruby. +rm -rf ~/.rvm + curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" From dd414b6ddcccf39a33b9a02419606b31190839e4 Mon Sep 17 00:00:00 2001 From: James Sharp Date: Wed, 20 Nov 2019 17:36:05 +0000 Subject: [PATCH 0871/1899] grpc-js: fix error messages truncating at commas --- packages/grpc-js/src/metadata-status-filter.ts | 2 +- packages/grpc-js/src/server-call.ts | 4 +++- packages/grpc-js/test/test-server-errors.ts | 12 ++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts index 5ca401f73..52c276823 100644 --- a/packages/grpc-js/src/metadata-status-filter.ts +++ b/packages/grpc-js/src/metadata-status-filter.ts @@ -38,7 +38,7 @@ export class MetadataStatusFilter extends BaseFilter implements Filter { metadata.remove('grpc-status'); } if (typeof metadataMap['grpc-message'] === 'string') { - details = decodeURI(metadataMap['grpc-message'] as string); + details = decodeURIComponent(metadataMap['grpc-message'] as string); metadata.remove('grpc-message'); } return { code, details, metadata }; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 02353bbe6..b755b5e6b 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -484,7 +484,9 @@ export class Http2ServerCallStream< const trailersToSend = Object.assign( { [GRPC_STATUS_HEADER]: statusObj.code, - [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), + [GRPC_MESSAGE_HEADER]: encodeURIComponent( + statusObj.details as string + ), }, statusObj.metadata.toHttp2Headers() ); diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index ffabaac50..7c611b9bc 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -699,6 +699,18 @@ describe('Other conditions', () => { } ); }); + + it('for an error message with a comma', done => { + client.unary( + { error: true, message: 'an error message, with a comma' }, + (err: ServiceError, data: any) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNKNOWN); + assert.strictEqual(err.details, 'an error message, with a comma'); + done(); + } + ); + }); }); }); From da1c43726afd9db0e3cb87e4b254ee7d693873b7 Mon Sep 17 00:00:00 2001 From: "Nicolas \"Pixel\" Noble" Date: Wed, 20 Nov 2019 19:07:54 +0100 Subject: [PATCH 0872/1899] Further locking down our environment. --- test/kokoro.sh | 2 +- tools/release/kokoro-electron.sh | 2 +- tools/release/kokoro-nodejs.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro.sh b/test/kokoro.sh index 38ea41b2e..667db1127 100755 --- a/test/kokoro.sh +++ b/test/kokoro.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Copyright 2017 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh index 721b9c97a..fd833503b 100755 --- a/tools/release/kokoro-electron.sh +++ b/tools/release/kokoro-electron.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Copyright 2018 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/tools/release/kokoro-nodejs.sh b/tools/release/kokoro-nodejs.sh index 7dd89c890..7ce0a0b64 100755 --- a/tools/release/kokoro-nodejs.sh +++ b/tools/release/kokoro-nodejs.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Copyright 2018 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); From 54c9e51bcb76efdec5ebfa48b9e0e5f819a45ad5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 21 Nov 2019 10:41:09 -0800 Subject: [PATCH 0873/1899] grpc-js: Add more channel args --- PACKAGE-COMPARISON.md | 10 +++++++--- packages/grpc-js/src/channel-options.ts | 8 ++++++++ packages/grpc-js/src/channel.ts | 5 +++-- packages/grpc-js/src/server.ts | 17 ++++++++++++----- packages/grpc-js/src/subchannel.ts | 8 ++++++-- 5 files changed, 36 insertions(+), 12 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 8a62c9145..c741474b3 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -3,7 +3,7 @@ Feature | `grpc` | `@grpc/grpc-js` --------|--------|---------- Client | :heavy_check_mark: | :heavy_check_mark: -Server | :heavy_check_mark: | :x: +Server | :heavy_check_mark: | :heavy_check_mark: Unary RPCs | :heavy_check_mark: | :heavy_check_mark: Streaming RPCs | :heavy_check_mark: | :heavy_check_mark: Deadlines | :heavy_check_mark: | :heavy_check_mark: @@ -17,8 +17,8 @@ Connection Keepalives | :heavy_check_mark: | :heavy_check_mark: HTTP Connect Support | :heavy_check_mark: | :x: Retries | :heavy_check_mark: | :x: Stats/tracing/monitoring | :heavy_check_mark: | :x: -Load Balancing | :heavy_check_mark: | :x: -Initial Metadata Options | :heavy_check_mark: | :x: +Load Balancing | :heavy_check_mark: | Pick first and round robin +Initial Metadata Options | :heavy_check_mark: | only `waitForReady` Other Properties | `grpc` | `@grpc/grpc-js` -----------------|--------|---------------- @@ -37,5 +37,9 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.keepalive_time_ms` - `grpc.keepalive_timeout_ms` - `grpc.service_config` + - `grpc.max_concurrent_streams` + - `grpc.initial_reconnect_backoff_ms` + - `grpc.max_reconnect_backoff_ms` + - `grpc.use_local_subchannel_pool` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index ad905b9fa..9d92b393c 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -26,6 +26,10 @@ export interface ChannelOptions { 'grpc.keepalive_time_ms'?: number; 'grpc.keepalive_timeout_ms'?: number; 'grpc.service_config'?: string; + 'grpc.max_concurrent_streams'?: number; + 'grpc.initial_reconnect_backoff_ms'?: number; + 'grpc.max_reconnect_backoff_ms'?: number; + 'grpc.use_local_subchannel_pool'?: number; [key: string]: string | number | undefined; } @@ -41,6 +45,10 @@ export const recognizedOptions = { 'grpc.keepalive_time_ms': true, 'grpc.keepalive_timeout_ms': true, 'grpc.service_config': true, + 'grpc.max_concurrent_streams': true, + 'grpc.initial_reconnect_backoff_ms': true, + 'grpc.max_reconnect_backoff_ms': true, + 'grpc.use_local_subchannel_pool': true, }; export function channelOptionsEqual( diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 25daa4688..a04332141 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -129,8 +129,9 @@ export class ChannelImplementation implements Channel { private readonly credentials: ChannelCredentials, private readonly options: ChannelOptions ) { - // TODO(murgatroid99): check channel arg for getting a private pool - this.subchannelPool = getSubchannelPool(true); + /* The global boolean parameter to getSubchannelPool has the inverse meaning to what + * the grpc.use_local_subchannel_pool channel option means. */ + this.subchannelPool = getSubchannelPool((options['grpc.use_local_subchannel_pool'] ?? 0) === 0); const channelControlHelper: ChannelControlHelper = { createSubchannel: ( subchannelAddress: string, diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 780b8f865..03fcfaf90 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -45,6 +45,7 @@ import { ServerStatusResponse, } from './server-call'; import { ServerCredentials } from './server-credentials'; +import { ChannelOptions } from './channel-options'; function noop(): void {} @@ -95,8 +96,11 @@ export class Server { >(); private sessions = new Set(); private started = false; + private options: ChannelOptions; - constructor(options?: object) {} + constructor(options?: ChannelOptions) { + this.options = options ?? {}; + } addProtoService(): void { throw new Error('Not implemented. Use addService() instead'); @@ -197,13 +201,16 @@ export class Server { const url = new URL(`http://${port}`); const options: ListenOptions = { host: url.hostname, port: +url.port }; + const serverOptions: http2.ServerOptions = {}; + if ('grpc.max_concurrent_streams' in this.options) { + serverOptions.settings = {maxConcurrentStreams: this.options['grpc.max_concurrent_streams']}; + } if (creds._isSecure()) { - this.http2Server = http2.createSecureServer( - creds._getSettings() as http2.SecureServerOptions - ); + const secureServerOptions = Object.assign(serverOptions, creds._getSettings()!); + this.http2Server = http2.createSecureServer(secureServerOptions); } else { - this.http2Server = http2.createServer(); + this.http2Server = http2.createServer(serverOptions); } this.http2Server.setTimeout(0, noop); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index eae178e78..68df6fb5a 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -22,7 +22,7 @@ import { Http2CallStream } from './call-stream'; import { ChannelOptions } from './channel-options'; import { PeerCertificate, checkServerIdentity } from 'tls'; import { ConnectivityState } from './channel'; -import { BackoffTimeout } from './backoff-timeout'; +import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; import { LogVerbosity } from './constants'; @@ -170,6 +170,10 @@ export class Subchannel { clearTimeout(this.keepaliveIntervalId); this.keepaliveTimeoutId = setTimeout(() => {}, 0); clearTimeout(this.keepaliveTimeoutId); + const backoffOptions: BackoffOptions = { + initialDelay: options['grpc.initial_reconnect_backoff_ms'], + maxDelay: options['grpc.max_reconnect_backoff_ms'] + }; this.backoffTimeout = new BackoffTimeout(() => { if (this.continueConnecting) { this.transitionToState( @@ -182,7 +186,7 @@ export class Subchannel { ConnectivityState.IDLE ); } - }); + }, backoffOptions); } /** From 812db0d198b52c36c6dd78364b9ef1c364857368 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 21 Nov 2019 11:12:41 -0800 Subject: [PATCH 0874/1899] grpc-js: Handle error when starting call on subchannel --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 2d942ba8b..c5574ebe2 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.12", + "version": "0.6.13", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 25daa4688..6a859ed26 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -216,10 +216,17 @@ export class ChannelImplementation implements Channel { pickResult.subchannel!.getConnectivityState() === ConnectivityState.READY ) { - pickResult.subchannel!.startCallStream( - finalMetadata, - callStream - ); + try { + pickResult.subchannel!.startCallStream( + finalMetadata, + callStream + ); + } catch (error) { + callStream.cancelWithStatus( + Status.UNAVAILABLE, + 'Failed to start call on picked subchannel' + ); + } } else { callStream.cancelWithStatus( Status.UNAVAILABLE, From 2dce08dc99fd8ca010dba249c4104ec6e1f75105 Mon Sep 17 00:00:00 2001 From: James Sharp Date: Thu, 21 Nov 2019 21:48:50 +0000 Subject: [PATCH 0875/1899] Only custom-metadata headers should be parsed as comma-separated --- .../grpc-js/src/metadata-status-filter.ts | 2 +- packages/grpc-js/src/metadata.ts | 20 +++++++++++++++---- packages/grpc-js/src/server-call.ts | 4 +--- test/api/error_test.js | 8 ++++++++ 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts index 52c276823..5ca401f73 100644 --- a/packages/grpc-js/src/metadata-status-filter.ts +++ b/packages/grpc-js/src/metadata-status-filter.ts @@ -38,7 +38,7 @@ export class MetadataStatusFilter extends BaseFilter implements Filter { metadata.remove('grpc-status'); } if (typeof metadataMap['grpc-message'] === 'string') { - details = decodeURIComponent(metadataMap['grpc-message'] as string); + details = decodeURI(metadataMap['grpc-message'] as string); metadata.remove('grpc-message'); } return { code, details, metadata }; diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 873e5ff53..4b41aa254 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -36,6 +36,10 @@ function isBinaryKey(key: string): boolean { return key.endsWith('-bin'); } +function isCustomMetadata(key: string): boolean { + return !key.startsWith('grpc-'); +} + function normalizeKey(key: string): string { return key.toLowerCase(); } @@ -260,9 +264,13 @@ export class Metadata { result.add(key, Buffer.from(value, 'base64')); }); } else if (values !== undefined) { - values.split(',').forEach(v => { - result.add(key, Buffer.from(v.trim(), 'base64')); - }); + if (isCustomMetadata(key)) { + values.split(',').forEach(v => { + result.add(key, Buffer.from(v.trim(), 'base64')); + }); + } else { + result.add(key, Buffer.from(values, 'base64')); + } } } else { if (Array.isArray(values)) { @@ -270,7 +278,11 @@ export class Metadata { result.add(key, value); }); } else if (values !== undefined) { - values.split(',').forEach(v => result.add(key, v.trim())); + if (isCustomMetadata(key)) { + values.split(',').forEach(v => result.add(key, v.trim())); + } else { + result.add(key, values); + } } } } catch (error) { diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index b755b5e6b..02353bbe6 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -484,9 +484,7 @@ export class Http2ServerCallStream< const trailersToSend = Object.assign( { [GRPC_STATUS_HEADER]: statusObj.code, - [GRPC_MESSAGE_HEADER]: encodeURIComponent( - statusObj.details as string - ), + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), }, statusObj.metadata.toHttp2Headers() ); diff --git a/test/api/error_test.js b/test/api/error_test.js index 23a8d0d8c..ea3bec911 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -553,6 +553,14 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done(); }); }); + it('for an error message with a comma', function(done) { + client.unary({error: true, message: 'a message, with a comma'}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, 'a message, with a comma'); + done(); + }); + }); }); }); }); \ No newline at end of file From 782d5acdb246488dfd0e3377581ec39c68196e81 Mon Sep 17 00:00:00 2001 From: Benjamin Coe Date: Thu, 21 Nov 2019 14:14:23 -0800 Subject: [PATCH 0876/1899] feat: allow headers other than authorization --- packages/grpc-js/src/index.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 9576e39e8..cc31ff510 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -85,11 +85,11 @@ export interface OAuth2Client { callback: ( err: Error | null, headers?: { - Authorization: string; + [index: string]: string; } ) => void ) => void; - getRequestHeaders: (url?: string) => Promise<{ Authorization: string }>; + getRequestHeaders: (url?: string) => Promise<{ [index: string]: string }>; } /**** Client Credentials ****/ @@ -109,7 +109,7 @@ export const credentials = mixin( (options, callback) => { // google-auth-library pre-v2.0.0 does not have getRequestHeaders // but has getRequestMetadata, which is deprecated in v2.0.0 - let getHeaders: Promise<{ Authorization: string }>; + let getHeaders: Promise<{ [index: string]: string }>; if (typeof googleCredentials.getRequestHeaders === 'function') { getHeaders = googleCredentials.getRequestHeaders( options.service_url @@ -131,7 +131,9 @@ export const credentials = mixin( getHeaders.then( headers => { const metadata = new Metadata(); - metadata.add('authorization', headers.Authorization); + for (const key in headers) { + metadata.add(key, headers[key]); + } callback(null, metadata); }, err => { From c89d4438be4ba26cc79318c276877c6e7db7ff2e Mon Sep 17 00:00:00 2001 From: bcoe Date: Thu, 21 Nov 2019 14:55:01 -0800 Subject: [PATCH 0877/1899] chore: address code review --- packages/grpc-js/src/index.ts | 2 +- packages/grpc-native-core/src/credentials.js | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index cc31ff510..0e4f9cf9d 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -131,7 +131,7 @@ export const credentials = mixin( getHeaders.then( headers => { const metadata = new Metadata(); - for (const key in headers) { + for (const key of Object.keys(headers)) { metadata.add(key, headers[key]); } callback(null, metadata); diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index 9542acfdc..d84f226d3 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -187,20 +187,20 @@ function getAuthorizationHeaderFromGoogleCredential(google_credential, url, call // but has getRequestMetadata, which is deprecated in v2.0.0 if (typeof google_credential.getRequestHeaders === 'function') { google_credential.getRequestHeaders(url) - .then(function(header) { - callback(null, header.Authorization); + .then(function(headers) { + callback(null, headers); }) .catch(function(err) { callback(err); return; }); } else { - google_credential.getRequestMetadata(url, function(err, header) { + google_credential.getRequestMetadata(url, function(err, headers) { if (err) { callback(err); return; } - callback(null, header.Authorization); + callback(null, headers); }); } } @@ -217,14 +217,16 @@ exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; getAuthorizationHeaderFromGoogleCredential(google_credential, service_url, - function(err, authHeader) { + function(err, headers) { if (err) { common.log(constants.logVerbosity.INFO, 'Auth error:' + err); callback(err); return; } var metadata = new Metadata(); - metadata.add('authorization', authHeader); + for (const key of Object.keys(headers)) { + metadata.add(key, headers[key]); + } callback(null, metadata); }); }); From 5ba250a10c2769a980bfa4b14270e1e3557dac91 Mon Sep 17 00:00:00 2001 From: bcoe Date: Thu, 21 Nov 2019 15:13:01 -0800 Subject: [PATCH 0878/1899] chore: address code review --- packages/grpc-native-core/src/credentials.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js index d84f226d3..21523f0b1 100644 --- a/packages/grpc-native-core/src/credentials.js +++ b/packages/grpc-native-core/src/credentials.js @@ -182,7 +182,7 @@ exports.createFromMetadataGenerator = function(metadata_generator) { }); }; -function getAuthorizationHeaderFromGoogleCredential(google_credential, url, callback) { +function getHeadersFromGoogleCredential(google_credential, url, callback) { // google-auth-library pre-v2.0.0 does not have getRequestHeaders // but has getRequestMetadata, which is deprecated in v2.0.0 if (typeof google_credential.getRequestHeaders === 'function') { @@ -216,7 +216,7 @@ function getAuthorizationHeaderFromGoogleCredential(google_credential, url, call exports.createFromGoogleCredential = function(google_credential) { return exports.createFromMetadataGenerator(function(auth_context, callback) { var service_url = auth_context.service_url; - getAuthorizationHeaderFromGoogleCredential(google_credential, service_url, + getHeadersFromGoogleCredential(google_credential, service_url, function(err, headers) { if (err) { common.log(constants.logVerbosity.INFO, 'Auth error:' + err); From ad9e53ada63659da8aba06c40008f08e6723928a Mon Sep 17 00:00:00 2001 From: James Sharp Date: Fri, 22 Nov 2019 12:28:57 +0000 Subject: [PATCH 0879/1899] grpc-js: fix explicit ipv6 addresses not resolving correctly --- packages/grpc-js/src/resolver-dns.ts | 9 ++-- packages/grpc-js/test/test-resolver.ts | 57 ++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 528529c9e..9f91d70ab 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -115,14 +115,15 @@ const dnsLookupPromise = util.promisify(dns.lookup); function parseIP(target: string): string[] | null { /* These three regular expressions are all mutually exclusive, so we just * want the first one that matches the target string, if any do. */ + const ipv4Match = IPV4_REGEX.exec(target); const match = - IPV4_REGEX.exec(target) || - IPV6_REGEX.exec(target) || - IPV6_BRACKET_REGEX.exec(target); + ipv4Match || IPV6_REGEX.exec(target) || IPV6_BRACKET_REGEX.exec(target); if (match === null) { return null; } - const addr = match[1]; + + // ipv6 addresses should be bracketed + const addr = ipv4Match ? match[1] : `[${match[1]}]`; let port: string; if (match[2]) { port = match[2]; diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 6e3a6b1b7..951291a61 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -67,6 +67,63 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); + it('Should correctly represent an ipv4 address', done => { + const target = '1.2.3.4'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('1.2.3.4:443')); + // We would check for the IPv6 address but it needs to be omitted on some Node versions + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should correctly represent an ipv6 address', done => { + const target = '::1'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('[::1]:443')); + // We would check for the IPv6 address but it needs to be omitted on some Node versions + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should correctly represent a bracketed ipv6 address', done => { + const target = '[::1]:50051'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: string[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert(addressList.includes('[::1]:50051')); + // We would check for the IPv6 address but it needs to be omitted on some Node versions + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); it('Should resolve a public address', done => { const target = 'example.com'; const listener: resolverManager.ResolverListener = { From 6b326d70b676056920b6397789e8d11d33d6bea3 Mon Sep 17 00:00:00 2001 From: Sardorbek Pulatov Date: Tue, 26 Nov 2019 13:30:32 +0100 Subject: [PATCH 0880/1899] CR comment fix --- doc/compression.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/compression.md b/doc/compression.md index 3510cafb6..bfe325a08 100644 --- a/doc/compression.md +++ b/doc/compression.md @@ -7,7 +7,7 @@ These two options control compression behavior: **grpc.default_compression_algorithm** (int) -Default compression algorithm for the channel. +Default compression algorithm for the channel, applies to sending messages. Possible values for this option are: - `0` - No compression @@ -17,7 +17,7 @@ Possible values for this option are: **grpc.default_compression_level** (int) -Default compression level for the channel. +Default compression level for the channel, applies to receiving messages. Possible values for this option are: - `0` - None From aff61540bc4b05600400f87f92044f34df0d8459 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 3 Dec 2019 14:08:37 -0800 Subject: [PATCH 0881/1899] Update google-auth-library in interop tests --- test/interop/interop_client.js | 55 +++++++++++++--------------------- test/package.json | 2 +- 2 files changed, 22 insertions(+), 35 deletions(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 751264f21..1380df1f0 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -22,7 +22,7 @@ var fs = require('fs'); var path = require('path'); var grpc = require('../any_grpc').client; var protoLoader = require('../../packages/proto-loader'); -var GoogleAuth = require('google-auth-library'); +var GoogleAuth = require('google-auth-library').GoogleAuth; var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/test.proto', @@ -463,17 +463,14 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { + const auth = new GoogleAuth({scopes: extra.oauth_scope}); + auth.getClient().then(authClient => { assert.ifError(err); var arg = { fill_username: true, fill_oauth_scope: true }; - var scope = extra.oauth_scope; - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); - } - var creds = grpc.credentials.createFromGoogleCredential(credential); + var creds = grpc.credentials.createFromGoogleCredential(authClient); client.unaryCall(arg, {credentials: creds}, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); @@ -482,41 +479,31 @@ function perRpcAuthTest(client, done, extra) { done(); } }); + }, error => { + assert.fail(error); }); } function getApplicationCreds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); - } - callback(null, grpc.credentials.createFromGoogleCredential(credential)); + const auth = new GoogleAuth({scopes: scope}); + auth.getClient().then(client => { + callback(grpc.credentials.createFromGoogleCredential(client)); + }, (error) => { + assert.fail(error); }); } function getOauth2Creds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - credential = credential.createScoped(scope); - credential.getAccessToken(function(err, token) { - if (err) { - callback(err); - return; - } - var updateMd = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.add('authorization', 'Bearer ' + token); - callback(null, metadata); - }; - callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); - }); + const auth = new GoogleAuth({scopes: scope}); + auth.getClient().then(client => client.getAccessToken()).then((token) => { + const updateMd = (service_url, callback) => { + const metadata = new grpc.Metadata(); + metadata.add('authorization', 'Bearer ' + token); + callback(null, metadata); + }; + callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); + }).catch(error => { + assert.fail(error); }); } diff --git a/test/package.json b/test/package.json index 764232971..0d724215b 100644 --- a/test/package.json +++ b/test/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "express": "^4.16.3", - "google-auth-library": "^0.9.2", + "google-auth-library": "^5.5.1", "lodash": "^4.17.4", "poisson-process": "^1.0.0" } From 36cf935e7d8556e49693e606ff59a093d6af4072 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 5 Dec 2019 17:51:25 -0800 Subject: [PATCH 0882/1899] grpc-js: Add support for TLS-related environment variables --- packages/grpc-js/src/channel-credentials.ts | 5 +-- packages/grpc-js/src/server-credentials.ts | 4 ++- packages/grpc-js/src/tls-helpers.ts | 34 +++++++++++++++++++++ 3 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 packages/grpc-js/src/tls-helpers.ts diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index c29885fa7..f42c7e936 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -18,7 +18,7 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; -import { Call } from '.'; +import {CIPHER_SUITES, getDefaultRootsData} from './tls-helpers'; // tslint:disable-next-line:no-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -141,7 +141,7 @@ export abstract class ChannelCredentials { ); } return new SecureChannelCredentialsImpl( - rootCerts || null, + rootCerts || getDefaultRootsData(), privateKey || null, certChain || null, verifyOptions || {} @@ -190,6 +190,7 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { ca: rootCerts || undefined, key: privateKey || undefined, cert: certChain || undefined, + ciphers: CIPHER_SUITES }); this.connectionOptions = { secureContext }; if (verifyOptions && verifyOptions.checkServerIdentity) { diff --git a/packages/grpc-js/src/server-credentials.ts b/packages/grpc-js/src/server-credentials.ts index 1fe5f55d5..b56cb68ab 100644 --- a/packages/grpc-js/src/server-credentials.ts +++ b/packages/grpc-js/src/server-credentials.ts @@ -16,6 +16,7 @@ */ import { SecureServerOptions } from 'http2'; +import {CIPHER_SUITES, getDefaultRootsData} from './tls-helpers'; export interface KeyCertPair { private_key: Buffer; @@ -70,10 +71,11 @@ export abstract class ServerCredentials { } return new SecureServerCredentials({ - ca: rootCerts || undefined, + ca: rootCerts || getDefaultRootsData() || undefined, cert, key, requestCert: checkClientCertificate, + ciphers: CIPHER_SUITES }); } } diff --git a/packages/grpc-js/src/tls-helpers.ts b/packages/grpc-js/src/tls-helpers.ts new file mode 100644 index 000000000..161666edc --- /dev/null +++ b/packages/grpc-js/src/tls-helpers.ts @@ -0,0 +1,34 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; + +export const CIPHER_SUITES: string | undefined = process.env.GRPC_SSL_CIPHER_SUITES; + +const DEFAULT_ROOTS_FILE_PATH = process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH; + +let defaultRootsData: Buffer | null = null; + +export function getDefaultRootsData(): Buffer | null { + if (DEFAULT_ROOTS_FILE_PATH) { + if (defaultRootsData === null) { + defaultRootsData = fs.readFileSync(DEFAULT_ROOTS_FILE_PATH); + } + return defaultRootsData; + } + return null; +} \ No newline at end of file From cf665757d0ed764ecc75fc3b42f9b2dc2f3bca84 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 9 Dec 2019 13:53:04 -0800 Subject: [PATCH 0883/1899] grpc-js: Add low-level call tracers --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 67 +++++++++++++++++++++++++++++ packages/grpc-js/src/channel.ts | 5 +++ packages/grpc-js/src/subchannel.ts | 28 ++++++++++++ 4 files changed, 101 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index c5574ebe2..056f36a78 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.13", + "version": "0.6.14", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index d8655cf74..c2ddc4b76 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -28,6 +28,14 @@ import { ObjectDuplex, WriteCallback } from './object-stream'; import { StreamDecoder } from './stream-decoder'; import { ChannelImplementation } from './channel'; import { Subchannel } from './subchannel'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'call_stream'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const { HTTP2_HEADER_STATUS, @@ -135,6 +143,16 @@ export class Http2CallStream extends Duplex implements Call { }; } + // tslint:disable-next-line:no-any + push(chunk: any, encoding?: string): boolean { + trace( + this.methodName + + 'pushing to reader message of length ' + + (chunk instanceof Buffer ? chunk.length : null) + ); + return super.push(chunk); + } + /** * On first call, emits a 'status' event with the given StatusObject. * Subsequent calls are no-ops. @@ -142,6 +160,14 @@ export class Http2CallStream extends Duplex implements Call { */ private endCall(status: StatusObject): void { if (this.finalStatus === null) { + trace( + this.methodName + + ' ended with status: code=' + + status.code + + ' details="' + + status.details + + '"' + ); this.finalStatus = status; /* We do this asynchronously to ensure that no async function is in the * call stack when we return control to the application. If an async @@ -177,6 +203,11 @@ export class Http2CallStream extends Duplex implements Call { (this.http2Stream as http2.ClientHttp2Stream).pause(); } } else { + trace( + this.methodName + + ' unpushedReadMessages.push message of length ' + + message.length + ); this.unpushedReadMessages.push(message); } if (this.unfilteredReadMessages.length > 0) { @@ -201,6 +232,11 @@ export class Http2CallStream extends Duplex implements Call { } return; } + trace( + this.methodName + + ' filterReceivedMessage of length ' + + framedMessage.length + ); this.isReadFilterPending = true; this.filterStack .receiveMessage(Promise.resolve(framedMessage)) @@ -212,6 +248,11 @@ export class Http2CallStream extends Duplex implements Call { private tryPush(messageBytes: Buffer | null): void { if (this.isReadFilterPending) { + trace( + this.methodName + + ' unfilteredReadMessages.push message of length ' + + (messageBytes && messageBytes.length) + ); this.unfilteredReadMessages.push(messageBytes); } else { this.filterReceivedMessage(messageBytes); @@ -219,6 +260,7 @@ export class Http2CallStream extends Duplex implements Call { } private handleTrailers(headers: http2.IncomingHttpHeaders) { + trace(this.methodName + ' received HTTP/2 trailing headers frame'); const code: Status = this.mappedStatusCode; const details = ''; let metadata: Metadata; @@ -261,11 +303,17 @@ export class Http2CallStream extends Duplex implements Call { if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { + trace( + this.methodName + + ' attachHttp2Stream from subchannel ' + + subchannel.getAddress() + ); this.http2Stream = stream; this.subchannel = subchannel; subchannel.addDisconnectListener(this.disconnectListener); subchannel.callRef(); stream.on('response', (headers, flags) => { + trace(this.methodName + ' received HTTP/2 headers frame'); switch (headers[':status']) { // TODO(murgatroid99): handle 100 and 101 case 400: @@ -321,16 +369,28 @@ export class Http2CallStream extends Duplex implements Call { }); stream.on('trailers', this.handleTrailers.bind(this)); stream.on('data', (data: Buffer) => { + trace( + this.methodName + + ' receive HTTP/2 data frame of length ' + + data.length + ); const messages = this.decoder.write(data); for (const message of messages) { + trace( + this.methodName + ' parsed message of length ' + message.length + ); this.tryPush(message); } }); stream.on('end', () => { + trace(this.methodName + ' received HTTP/2 end of data flag'); this.tryPush(null); }); stream.on('close', async () => { + trace( + this.methodName + ' HTTP/2 stream closed with code ' + stream.rstCode + ); let code: Status; let details = ''; switch (stream.rstCode) { @@ -383,6 +443,7 @@ export class Http2CallStream extends Duplex implements Call { } sendMetadata(metadata: Metadata): void { + trace(this.methodName + ' Sending metadata'); this.channel._startCallStream(this, metadata); } @@ -461,6 +522,11 @@ export class Http2CallStream extends Duplex implements Call { } _write(chunk: WriteObject, encoding: string, cb: WriteCallback) { + trace( + this.methodName + + ' write() called with message of length ' + + chunk.message.length + ); this.filterStack.sendMessage(Promise.resolve(chunk)).then(message => { if (this.http2Stream === null) { this.pendingWrite = message.message; @@ -472,6 +538,7 @@ export class Http2CallStream extends Duplex implements Call { } _final(cb: Function) { + trace(this.methodName + ' end() called'); if (this.http2Stream === null) { this.pendingFinalCallback = cb; } else { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6a859ed26..8e45ccb48 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -357,6 +357,11 @@ export class ChannelImplementation implements Channel { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } + trace( + LogVerbosity.DEBUG, + 'channel', + 'createCall(method="' + method + '", deadline=' + deadline + ')' + ); const finalOptions: CallStreamOptions = { deadline: deadline === null || deadline === undefined ? Infinity : deadline, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index eae178e78..1d02591d7 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -395,6 +395,13 @@ export class Subchannel { } callRef() { + trace( + this.subchannelAddress + + ' callRefcount ' + + this.callRefcount + + ' -> ' + + (this.callRefcount + 1) + ); if (this.callRefcount === 0) { if (this.session) { this.session.ref(); @@ -405,6 +412,13 @@ export class Subchannel { } callUnref() { + trace( + this.subchannelAddress + + ' callRefcount ' + + this.callRefcount + + ' -> ' + + (this.callRefcount - 1) + ); this.callRefcount -= 1; if (this.callRefcount === 0) { if (this.session) { @@ -416,10 +430,24 @@ export class Subchannel { } ref() { + trace( + this.subchannelAddress + + ' callRefcount ' + + this.refcount + + ' -> ' + + (this.refcount + 1) + ); this.refcount += 1; } unref() { + trace( + this.subchannelAddress + + ' callRefcount ' + + this.refcount + + ' -> ' + + (this.refcount - 1) + ); this.refcount -= 1; this.checkBothRefcounts(); } From 8615da0b9cd9abd839c0ce898ae9802d10ec7edc Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 10 Dec 2019 14:09:50 -0800 Subject: [PATCH 0884/1899] grpc-tools: Use PrintRaw when outputting comments --- packages/grpc-tools/src/node_generator.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index 720594701..77a5abfdb 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -181,7 +181,7 @@ void PrintMethod(const MethodDescriptor* method, Printer* out) { void PrintService(const ServiceDescriptor* service, Printer* out, const Parameters& params) { map template_vars; - out->Print(GetNodeComments(service, true).c_str()); + out->PrintRaw(GetNodeComments(service, true).c_str()); template_vars["name"] = service->name(); template_vars["full_name"] = service->full_name(); if (params.generate_package_definition) { @@ -193,11 +193,11 @@ void PrintService(const ServiceDescriptor* service, Printer* out, for (int i = 0; i < service->method_count(); i++) { grpc::string method_name = grpc_generator::LowercaseFirstLetter(service->method(i)->name()); - out->Print(GetNodeComments(service->method(i), true).c_str()); + out->PrintRaw(GetNodeComments(service->method(i), true).c_str()); out->Print("$method_name$: ", "method_name", method_name); PrintMethod(service->method(i), out); out->Print(",\n"); - out->Print(GetNodeComments(service->method(i), false).c_str()); + out->PrintRaw(GetNodeComments(service->method(i), false).c_str()); } out->Outdent(); out->Print("};\n\n"); @@ -206,7 +206,7 @@ void PrintService(const ServiceDescriptor* service, Printer* out, "exports.$name$Client = " "grpc.makeGenericClientConstructor($name$Service);\n"); } - out->Print(GetNodeComments(service, false).c_str()); + out->PrintRaw(GetNodeComments(service, false).c_str()); } void PrintImports(const FileDescriptor* file, Printer* out, @@ -276,7 +276,7 @@ grpc::string GenerateFile(const FileDescriptor* file, PrintServices(file, &out, params); - out.Print(GetNodeComments(file, false).c_str()); + out.PrintRaw(GetNodeComments(file, false).c_str()); } return output; } From 39a056840f9e49ab50c76999997bcb080b468d91 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 11 Dec 2019 11:03:59 -0800 Subject: [PATCH 0885/1899] Revert "Update google-auth-library in interop tests" --- test/interop/interop_client.js | 55 +++++++++++++++++++++------------- test/package.json | 2 +- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 1380df1f0..751264f21 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -22,7 +22,7 @@ var fs = require('fs'); var path = require('path'); var grpc = require('../any_grpc').client; var protoLoader = require('../../packages/proto-loader'); -var GoogleAuth = require('google-auth-library').GoogleAuth; +var GoogleAuth = require('google-auth-library'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/test.proto', @@ -463,14 +463,17 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { - const auth = new GoogleAuth({scopes: extra.oauth_scope}); - auth.getClient().then(authClient => { + (new GoogleAuth()).getApplicationDefault(function(err, credential) { assert.ifError(err); var arg = { fill_username: true, fill_oauth_scope: true }; - var creds = grpc.credentials.createFromGoogleCredential(authClient); + var scope = extra.oauth_scope; + if (credential.createScopedRequired() && scope) { + credential = credential.createScoped(scope); + } + var creds = grpc.credentials.createFromGoogleCredential(credential); client.unaryCall(arg, {credentials: creds}, function(err, resp) { assert.ifError(err); assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); @@ -479,31 +482,41 @@ function perRpcAuthTest(client, done, extra) { done(); } }); - }, error => { - assert.fail(error); }); } function getApplicationCreds(scope, callback) { - const auth = new GoogleAuth({scopes: scope}); - auth.getClient().then(client => { - callback(grpc.credentials.createFromGoogleCredential(client)); - }, (error) => { - assert.fail(error); + (new GoogleAuth()).getApplicationDefault(function(err, credential) { + if (err) { + callback(err); + return; + } + if (credential.createScopedRequired() && scope) { + credential = credential.createScoped(scope); + } + callback(null, grpc.credentials.createFromGoogleCredential(credential)); }); } function getOauth2Creds(scope, callback) { - const auth = new GoogleAuth({scopes: scope}); - auth.getClient().then(client => client.getAccessToken()).then((token) => { - const updateMd = (service_url, callback) => { - const metadata = new grpc.Metadata(); - metadata.add('authorization', 'Bearer ' + token); - callback(null, metadata); - }; - callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); - }).catch(error => { - assert.fail(error); + (new GoogleAuth()).getApplicationDefault(function(err, credential) { + if (err) { + callback(err); + return; + } + credential = credential.createScoped(scope); + credential.getAccessToken(function(err, token) { + if (err) { + callback(err); + return; + } + var updateMd = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.add('authorization', 'Bearer ' + token); + callback(null, metadata); + }; + callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); + }); }); } diff --git a/test/package.json b/test/package.json index 0d724215b..764232971 100644 --- a/test/package.json +++ b/test/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "express": "^4.16.3", - "google-auth-library": "^5.5.1", + "google-auth-library": "^0.9.2", "lodash": "^4.17.4", "poisson-process": "^1.0.0" } From 286a22572cde9ea1bb548673ee3f0a6f662aa36d Mon Sep 17 00:00:00 2001 From: Jake Turner Date: Thu, 12 Dec 2019 14:57:30 +0000 Subject: [PATCH 0886/1899] Publish 7.1.0 binaries Signed-off-by: Jake Turner --- .../tools/run_tests/artifacts/build_artifact_electron.bat | 2 +- .../tools/run_tests/artifacts/build_artifact_electron.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat index e049c6cb2..56fa530b1 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat @@ -14,7 +14,7 @@ set arch_list=ia32 x64 -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 +set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 7.1.0 set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh index accc8c72b..f6d3c9620 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh @@ -16,7 +16,7 @@ set -ex arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 ) +electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 7.1.0 ) umask 022 From 8af2bc83f8015ce3be6793af6643621e63a951af Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 12 Dec 2019 14:17:46 -0800 Subject: [PATCH 0887/1899] Don't test irrelevant parts of output --- .../grpc-js/test/test-server-credentials.ts | 34 ++++++------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js/test/test-server-credentials.ts b/packages/grpc-js/test/test-server-credentials.ts index 6c8bd877e..ec1740f70 100644 --- a/packages/grpc-js/test/test-server-credentials.ts +++ b/packages/grpc-js/test/test-server-credentials.ts @@ -41,24 +41,16 @@ describe('Server Credentials', () => { const creds = ServerCredentials.createSsl(ca, []); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual(creds._getSettings(), { - ca, - cert: [], - key: [], - requestCert: false, - }); + assert.strictEqual(creds._getSettings()?.ca, ca); }); it('accepts a boolean as the third argument', () => { const creds = ServerCredentials.createSsl(ca, [], true); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual(creds._getSettings(), { - ca, - cert: [], - key: [], - requestCert: true, - }); + const settings = creds._getSettings(); + assert.strictEqual(settings?.ca, ca); + assert.strictEqual(settings?.requestCert, true); }); it('accepts an object with two buffers in the second argument', () => { @@ -66,12 +58,9 @@ describe('Server Credentials', () => { const creds = ServerCredentials.createSsl(null, keyCertPairs); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual(creds._getSettings(), { - ca: undefined, - cert: [cert], - key: [key], - requestCert: false, - }); + const settings = creds._getSettings(); + assert.deepStrictEqual(settings?.cert, [cert]); + assert.deepStrictEqual(settings?.key, [key]); }); it('accepts multiple objects in the second argument', () => { @@ -82,12 +71,9 @@ describe('Server Credentials', () => { const creds = ServerCredentials.createSsl(null, keyCertPairs, false); assert.strictEqual(creds._isSecure(), true); - assert.deepStrictEqual(creds._getSettings(), { - ca: undefined, - cert: [cert, cert], - key: [key, key], - requestCert: false, - }); + const settings = creds._getSettings(); + assert.deepStrictEqual(settings?.cert, [cert, cert]); + assert.deepStrictEqual(settings?.key, [key, key]); }); it('fails if the second argument is not an Array', () => { From 992fd21a519dc8207b4b4d07ddf2db48254744c1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 13 Dec 2019 14:12:05 -0800 Subject: [PATCH 0888/1899] grpc-js: Add unique ID number to call trace logs --- packages/grpc-js/src/call-stream.ts | 82 ++++++++++++----------------- packages/grpc-js/src/channel.ts | 23 +++++++- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index c2ddc4b76..c1e9b3b5c 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -33,10 +33,6 @@ import { LogVerbosity } from './constants'; const TRACER_NAME = 'call_stream'; -function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); -} - const { HTTP2_HEADER_STATUS, HTTP2_HEADER_CONTENT_TYPE, @@ -129,7 +125,8 @@ export class Http2CallStream extends Duplex implements Call { private readonly channel: ChannelImplementation, private readonly options: CallStreamOptions, filterStackFactory: FilterStackFactory, - private readonly channelCallCredentials: CallCredentials + private readonly channelCallCredentials: CallCredentials, + private readonly callNumber: number ) { super({ objectMode: true }); this.filterStack = filterStackFactory.createFilter(this); @@ -143,11 +140,18 @@ export class Http2CallStream extends Duplex implements Call { }; } + private trace(text: string): void { + logging.trace( + LogVerbosity.DEBUG, + TRACER_NAME, + '[' + this.callNumber + '] ' + text + ); + } + // tslint:disable-next-line:no-any push(chunk: any, encoding?: string): boolean { - trace( - this.methodName + - 'pushing to reader message of length ' + + this.trace( + 'pushing to reader message of length ' + (chunk instanceof Buffer ? chunk.length : null) ); return super.push(chunk); @@ -160,9 +164,8 @@ export class Http2CallStream extends Duplex implements Call { */ private endCall(status: StatusObject): void { if (this.finalStatus === null) { - trace( - this.methodName + - ' ended with status: code=' + + this.trace( + 'ended with status: code=' + status.code + ' details="' + status.details + @@ -203,10 +206,8 @@ export class Http2CallStream extends Duplex implements Call { (this.http2Stream as http2.ClientHttp2Stream).pause(); } } else { - trace( - this.methodName + - ' unpushedReadMessages.push message of length ' + - message.length + this.trace( + 'unpushedReadMessages.push message of length ' + message.length ); this.unpushedReadMessages.push(message); } @@ -232,11 +233,7 @@ export class Http2CallStream extends Duplex implements Call { } return; } - trace( - this.methodName + - ' filterReceivedMessage of length ' + - framedMessage.length - ); + this.trace('filterReceivedMessage of length ' + framedMessage.length); this.isReadFilterPending = true; this.filterStack .receiveMessage(Promise.resolve(framedMessage)) @@ -248,9 +245,10 @@ export class Http2CallStream extends Duplex implements Call { private tryPush(messageBytes: Buffer | null): void { if (this.isReadFilterPending) { - trace( - this.methodName + - ' unfilteredReadMessages.push message of length ' + + this.trace( + '[' + + this.callNumber + + '] unfilteredReadMessages.push message of length ' + (messageBytes && messageBytes.length) ); this.unfilteredReadMessages.push(messageBytes); @@ -260,7 +258,7 @@ export class Http2CallStream extends Duplex implements Call { } private handleTrailers(headers: http2.IncomingHttpHeaders) { - trace(this.methodName + ' received HTTP/2 trailing headers frame'); + this.trace('received HTTP/2 trailing headers frame'); const code: Status = this.mappedStatusCode; const details = ''; let metadata: Metadata; @@ -303,17 +301,15 @@ export class Http2CallStream extends Duplex implements Call { if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { - trace( - this.methodName + - ' attachHttp2Stream from subchannel ' + - subchannel.getAddress() + this.trace( + 'attachHttp2Stream from subchannel ' + subchannel.getAddress() ); this.http2Stream = stream; this.subchannel = subchannel; subchannel.addDisconnectListener(this.disconnectListener); subchannel.callRef(); stream.on('response', (headers, flags) => { - trace(this.methodName + ' received HTTP/2 headers frame'); + this.trace('received HTTP/2 headers frame'); switch (headers[':status']) { // TODO(murgatroid99): handle 100 and 101 case 400: @@ -369,28 +365,20 @@ export class Http2CallStream extends Duplex implements Call { }); stream.on('trailers', this.handleTrailers.bind(this)); stream.on('data', (data: Buffer) => { - trace( - this.methodName + - ' receive HTTP/2 data frame of length ' + - data.length - ); + this.trace('receive HTTP/2 data frame of length ' + data.length); const messages = this.decoder.write(data); for (const message of messages) { - trace( - this.methodName + ' parsed message of length ' + message.length - ); + this.trace('parsed message of length ' + message.length); this.tryPush(message); } }); stream.on('end', () => { - trace(this.methodName + ' received HTTP/2 end of data flag'); + this.trace('received HTTP/2 end of data flag'); this.tryPush(null); }); stream.on('close', async () => { - trace( - this.methodName + ' HTTP/2 stream closed with code ' + stream.rstCode - ); + this.trace('HTTP/2 stream closed with code ' + stream.rstCode); let code: Status; let details = ''; switch (stream.rstCode) { @@ -437,13 +425,14 @@ export class Http2CallStream extends Duplex implements Call { stream.write(this.pendingWrite, this.pendingWriteCallback); } if (this.pendingFinalCallback) { + this.trace('calling end() on HTTP/2 stream'); stream.end(this.pendingFinalCallback); } } } sendMetadata(metadata: Metadata): void { - trace(this.methodName + ' Sending metadata'); + this.trace('Sending metadata'); this.channel._startCallStream(this, metadata); } @@ -522,11 +511,7 @@ export class Http2CallStream extends Duplex implements Call { } _write(chunk: WriteObject, encoding: string, cb: WriteCallback) { - trace( - this.methodName + - ' write() called with message of length ' + - chunk.message.length - ); + this.trace('write() called with message of length ' + chunk.message.length); this.filterStack.sendMessage(Promise.resolve(chunk)).then(message => { if (this.http2Stream === null) { this.pendingWrite = message.message; @@ -538,10 +523,11 @@ export class Http2CallStream extends Duplex implements Call { } _final(cb: Function) { - trace(this.methodName + ' end() called'); + this.trace('end() called'); if (this.http2Stream === null) { this.pendingFinalCallback = cb; } else { + this.trace('calling end() on HTTP/2 stream'); this.http2Stream.end(cb); } } diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8e45ccb48..a763e20de 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -47,6 +47,17 @@ export enum ConnectivityState { SHUTDOWN, } +let nextCallNumber = 0; + +function getNewCallNumber(): number { + const callNumber = nextCallNumber; + nextCallNumber += 1; + if (nextCallNumber >= Number.MAX_SAFE_INTEGER) { + nextCallNumber = 0; + } + return callNumber; +} + /** * An interface that represents a communication channel to a server specified * by a given address. @@ -357,10 +368,17 @@ export class ChannelImplementation implements Channel { if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } + const callNumber = getNewCallNumber(); trace( LogVerbosity.DEBUG, 'channel', - 'createCall(method="' + method + '", deadline=' + deadline + ')' + this.target + + ' createCall [' + + callNumber + + '] method="' + + method + + '", deadline=' + + deadline ); const finalOptions: CallStreamOptions = { deadline: @@ -374,7 +392,8 @@ export class ChannelImplementation implements Channel { this, finalOptions, this.filterStackFactory, - this.credentials._getCallCredentials() + this.credentials._getCallCredentials(), + callNumber ); return stream; } From aab867baf0cc11a774ac2074d3c0cb1890385232 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 18 Dec 2019 14:19:12 -0800 Subject: [PATCH 0889/1899] grpc-js: Bump to 0.6.15 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 056f36a78..0a4ec9dd3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.14", + "version": "0.6.15", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 3c4442b93e28f88291294b91a1e616c160cff66a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 19 Dec 2019 16:19:01 -0800 Subject: [PATCH 0890/1899] Native: Add log for malformed incoming metadata --- packages/grpc-native-core/src/metadata.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js index 279dee180..c5b988fb5 100644 --- a/packages/grpc-native-core/src/metadata.js +++ b/packages/grpc-native-core/src/metadata.js @@ -22,6 +22,9 @@ var clone = require('lodash.clone'); var grpc = require('./grpc_extension'); +const common = require('./common'); +const logVerbosity = require('./constants').logVerbosity; + const IDEMPOTENT_REQUEST_FLAG = 0x10; const WAIT_FOR_READY_FLAG = 0x20; const CACHEABLE_REQUEST_FLAG = 0x40; @@ -231,6 +234,12 @@ Metadata._fromCoreRepresentation = function(metadata) { if (metadata) { Object.keys(metadata.metadata).forEach(key => { const value = metadata.metadata[key]; + if (!grpc.metadataKeyIsLegal(key)) { + common.log(logVerbosity.ERROR, + "Warning: possibly corrupted metadata key received: " + + key + ": " + value + + ". Please report this at https://github.com/grpc/grpc-node/issues/1173."); + } newMetadata._internal_repr[key] = clone(value); }); } From 79c013e2c9e0d5669dd190d57cf8a5a222695382 Mon Sep 17 00:00:00 2001 From: Jordan Worner Date: Sat, 21 Dec 2019 15:58:06 +0000 Subject: [PATCH 0891/1899] removing printf stops output is unparseable error --- packages/grpc-tools/src/node_plugin.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index a502dca88..4ed110818 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -43,7 +43,6 @@ class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc_generator::tokenize(parameter, ","); for (auto parameter_string = parameters_list.begin(); parameter_string != parameters_list.end(); parameter_string++) { - printf("%s", parameter_string); if (*parameter_string == "generate_package_definition") { generator_parameters.generate_package_definition = true; } From 4ad2273eb61de9c7f8921f8d4df425947a4be93a Mon Sep 17 00:00:00 2001 From: Shahid Date: Thu, 26 Dec 2019 15:21:59 +0530 Subject: [PATCH 0892/1899] Create build_artifact_node_s390x.sh --- .../artifacts/build_artifact_node_s390x.sh | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh new file mode 100644 index 000000000..05ea8b44e --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex + +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + +cd $(dirname $0)/../../.. + +rm -rf build || true + +mkdir -p "${ARTIFACTS_OUT}" + +npm update + +node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 ) + +for version in ${node_versions[@]} +do + # Cross compile for s390x on x64 + # Requires debian or ubuntu packages "g++-s390x-linux-gnu". + CC=s390x-linux-gnu-gcc CXX=s390x-linux-gnu-g++ LD=s390x-linux-gnu-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=s390x + cp -r build/stage/* "${ARTIFACTS_OUT}"/ +done From 4d1e4c9ae7e26b5aa46c71289f88e40d82a491bb Mon Sep 17 00:00:00 2001 From: Shahid Date: Thu, 26 Dec 2019 15:23:22 +0530 Subject: [PATCH 0893/1899] Update build_all_linux_artifacts.sh --- .../tools/run_tests/artifacts/build_all_linux_artifacts.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 26df28bdc..e9aecfe44 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -69,8 +69,13 @@ if [ "$DO_NATIVE" = "true" ] ; then fi if [ "$DO_CROSS" = "true" ] ; then + docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact + + # Cross build for arm $tool_dir/build_artifact_node_arm.sh + docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine - docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact + # Cross build for s390x + $tool_dir/build_artifact_node_s390x.sh docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine fi From ec0093211fab6db3e3dfa6e8ae4a9a8f22fa6b5d Mon Sep 17 00:00:00 2001 From: Shahid Date: Thu, 26 Dec 2019 15:24:46 +0530 Subject: [PATCH 0894/1899] Update Dockerfile --- tools/release/cross/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release/cross/Dockerfile b/tools/release/cross/Dockerfile index 7dabff9ad..1e931250e 100644 --- a/tools/release/cross/Dockerfile +++ b/tools/release/cross/Dockerfile @@ -2,7 +2,7 @@ FROM debian:stretch RUN dpkg --add-architecture i386 RUN apt-get update -RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf python libc6-dev:i386 lib32stdc++-6-dev +RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf g++-s390x-linux-gnu python libc6-dev:i386 lib32stdc++-6-dev RUN curl -fsSL get.docker.com | bash RUN mkdir /usr/local/nvm From a92005a4de064736da287659f781e39e2cc9ee0a Mon Sep 17 00:00:00 2001 From: Shahid Date: Thu, 2 Jan 2020 15:47:56 +0530 Subject: [PATCH 0895/1899] Update build_all_linux_artifacts.sh --- .../artifacts/build_all_linux_artifacts.sh | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index e9aecfe44..e6be79671 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -1,17 +1,4 @@ #!/bin/bash -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm install 10 From da545c9eb34840e87071846712d3035b0b9aefa3 Mon Sep 17 00:00:00 2001 From: Shahid Date: Thu, 2 Jan 2020 15:48:40 +0530 Subject: [PATCH 0896/1899] Update build_artifact_node_s390x.sh --- .../artifacts/build_artifact_node_s390x.sh | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh index 05ea8b44e..818d96632 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh @@ -1,17 +1,4 @@ #!/bin/bash -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. set -ex From a69cb45aa5714e1b13b06e28544926a09727863f Mon Sep 17 00:00:00 2001 From: Shahid Date: Fri, 3 Jan 2020 18:56:49 +0530 Subject: [PATCH 0897/1899] Update build_all_linux_artifacts.sh --- .../artifacts/build_all_linux_artifacts.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index e6be79671..e9aecfe44 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -1,4 +1,17 @@ #!/bin/bash +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm install 10 From e08b9e433106b921f6c59512039494475473d60a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 6 Jan 2020 17:17:30 -0800 Subject: [PATCH 0898/1899] Update grpc-tools to v1.8.1 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 8f4947f3e..2bf3feff9 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.8.0", + "version": "1.8.1", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From f03f1b52f3505b40f4570afea0e836efda8cee8b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 7 Jan 2020 16:25:17 -0800 Subject: [PATCH 0899/1899] Add test for waitForReady on both implementations --- test/api/connectivity_test.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 042c136b7..1cf6d3ffa 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -59,6 +59,29 @@ const serviceImpl = { }; describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { + it('client should not wait for ready by default', function(done) { + this.timeout(15000); + const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', grpc.credentials.createInsecure()); + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 10); + disconnectedClient.unary({}, {deadline: deadline}, (error, value) =>{ + assert(error); + assert.strictEqual(error.code, grpc.status.UNAVAILABLE); + done(); + }); + }); + it('client should wait for a connection with waitForReady on', function(done) { + this.timeout(15000); + const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', grpc.credentials.createInsecure()); + const metadata = new grpc.Metadata({waitForReady: true}); + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 10); + disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); describe('Reconnection', function() { let server1; let server2; From 94cdec3e73aba407c29abc059517307e0a0f5adb Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 7 Jan 2020 17:54:50 -0800 Subject: [PATCH 0900/1899] Fix grpc reference in tests --- test/api/connectivity_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index 1cf6d3ffa..a515f882d 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -61,7 +61,7 @@ const serviceImpl = { describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { it('client should not wait for ready by default', function(done) { this.timeout(15000); - const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', grpc.credentials.createInsecure()); + const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', clientGrpc.credentials.createInsecure()); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, {deadline: deadline}, (error, value) =>{ @@ -72,7 +72,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); it('client should wait for a connection with waitForReady on', function(done) { this.timeout(15000); - const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', grpc.credentials.createInsecure()); + const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', clientGrpc.credentials.createInsecure()); const metadata = new grpc.Metadata({waitForReady: true}); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 10); From e11587c69d05a96110eb1b4c98e731d7e02b65ee Mon Sep 17 00:00:00 2001 From: Shahid Date: Wed, 8 Jan 2020 21:14:50 +0530 Subject: [PATCH 0901/1899] Incorporating review comments --- .../run_tests/artifacts/build_all_linux_artifacts.sh | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index e9aecfe44..1700f393f 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -69,13 +69,9 @@ if [ "$DO_NATIVE" = "true" ] ; then fi if [ "$DO_CROSS" = "true" ] ; then - docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact - - # Cross build for arm $tool_dir/build_artifact_node_arm.sh - docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine - - # Cross build for s390x $tool_dir/build_artifact_node_s390x.sh + + docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine fi From 3a1470ed80451f27f2cb992d19de8c384f65a1b6 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 8 Jan 2020 09:43:10 -0800 Subject: [PATCH 0902/1899] Fix other references --- test/api/connectivity_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index a515f882d..b5d31943d 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -66,19 +66,19 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, {deadline: deadline}, (error, value) =>{ assert(error); - assert.strictEqual(error.code, grpc.status.UNAVAILABLE); + assert.strictEqual(error.code, clientGrpc.status.UNAVAILABLE); done(); }); }); it('client should wait for a connection with waitForReady on', function(done) { this.timeout(15000); const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', clientGrpc.credentials.createInsecure()); - const metadata = new grpc.Metadata({waitForReady: true}); + const metadata = new clientGrpc.Metadata({waitForReady: true}); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ assert(error); - assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + assert.strictEqual(error.code, clientGrpc.status.DEADLINE_EXCEEDED); done(); }); }); From 596232675e2e1bd845bcc3b282bd516f95299de1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 8 Jan 2020 16:32:50 -0800 Subject: [PATCH 0903/1899] Copy options when cloning metadata --- packages/grpc-js/src/metadata.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 4b41aa254..630fb99ad 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -174,7 +174,7 @@ export class Metadata { * @return The newly cloned object. */ clone(): Metadata { - const newMetadata = new Metadata(); + const newMetadata = new Metadata(this.options); const newInternalRepr = newMetadata.internalRepr; this.internalRepr.forEach((value, key) => { From 01a16846985677e1df2116135408b02313f35c71 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 9 Jan 2020 01:49:37 -0800 Subject: [PATCH 0904/1899] Make build_artifact_node_s390x.sh executable. --- .../tools/run_tests/artifacts/build_artifact_node_s390x.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh old mode 100644 new mode 100755 From ec30a63794e69a700439ceef69491dc101ba31d7 Mon Sep 17 00:00:00 2001 From: shahidhs-ibm Date: Thu, 9 Jan 2020 02:47:08 -0800 Subject: [PATCH 0905/1899] Revert "Make build_artifact_node_s390x.sh executable." This reverts commit 01a16846985677e1df2116135408b02313f35c71. --- .../tools/run_tests/artifacts/build_artifact_node_s390x.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh old mode 100755 new mode 100644 From 43d7bc734f7c84bad926894d3cb5487cb4039719 Mon Sep 17 00:00:00 2001 From: shahidhs-ibm Date: Thu, 9 Jan 2020 02:49:31 -0800 Subject: [PATCH 0906/1899] Make build_artifact_node_s390x.sh executable. --- .../tools/run_tests/artifacts/build_artifact_node_s390x.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh old mode 100644 new mode 100755 From a28039cfa588800ba584cb6beb59b4203efb618e Mon Sep 17 00:00:00 2001 From: Esun Kim Date: Thu, 9 Jan 2020 14:54:16 -0800 Subject: [PATCH 0907/1899] Add absl support --- packages/grpc-native-core/package.json | 2 +- .../grpc-native-core/templates/binding.gyp.template | 12 +++++++++--- .../grpc-native-core/templates/package.json.template | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 6530430e5..311054c66 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -68,7 +68,7 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh,inc}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{cc,h,inc}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/packages/grpc-native-core/templates/binding.gyp.template index bd73397ce..c3fa37b4f 100644 --- a/packages/grpc-native-core/templates/binding.gyp.template +++ b/packages/grpc-native-core/templates/binding.gyp.template @@ -20,7 +20,13 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - + <% + def gyp_target_name(lib_name): + if lib_name.startswith("absl/"): + return lib_name.replace("/", "__").replace(":", "__") + else: + return lib_name + %> # Some of this file is built with the help of # https://n8.io/converting-a-c-library-to-gyp/ { @@ -332,12 +338,12 @@ % for lib in libs: % if lib.name == core.name or (lib.name in core.transitive_deps and lib.name not in ('boringssl', 'z')): { - 'target_name': '${lib.name}', + 'target_name': '${gyp_target_name(lib.name)}', 'product_prefix': 'lib', 'type': 'static_library', 'dependencies': [ % for dep in getattr(lib, 'deps', []): - '${dep}', + '${gyp_target_name(dep)}', % endfor ], 'sources': [ diff --git a/packages/grpc-native-core/templates/package.json.template b/packages/grpc-native-core/templates/package.json.template index 91ae513ae..515614db2 100644 --- a/packages/grpc-native-core/templates/package.json.template +++ b/packages/grpc-native-core/templates/package.json.template @@ -70,7 +70,7 @@ "deps/grpc/include/grpc/**/*.h", "deps/grpc/src/core/**/*.{c,cc,h}", "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{h,hh,inc}", + "deps/grpc/third_party/abseil-cpp/absl/**/*.{cc,h,inc}", "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", From 7e1d20fec12136717910037e5b2c02ffcc02c495 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 13 Jan 2020 14:48:38 -0800 Subject: [PATCH 0908/1899] Do not overwrite error 'metadata' if already specified by caller. --- packages/grpc-js/src/server-call.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 02353bbe6..999dad8a1 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -455,7 +455,9 @@ export class Http2ServerCallStream< } if (err) { - err.metadata = metadata; + if (!err.hasOwnProperty('metadata')) { + err.metadata = metadata; + } this.sendError(err); return; } From b52d38f66390a332dc835ae295b98ca983ff7290 Mon Sep 17 00:00:00 2001 From: Cyrus Najmabadi Date: Mon, 13 Jan 2020 15:07:01 -0800 Subject: [PATCH 0909/1899] Add test --- test/api/error_test.js | 128 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/test/api/error_test.js b/test/api/error_test.js index ea3bec911..f7ff621af 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -562,5 +562,131 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); }); - }); + }); + describe('Other conditions', function() { + var client; + var server; + var port; + before(function(done) { + server = new serverGrpc.Server(); + var existing_metadata = new serverGrpc.Metadata(); + existing_metadata.add('existing-metadata', 'yes'); + server.addService(TestServiceClient.service, { + unary: function(call, cb) { + var req = call.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + cb({code: serverGrpc.status.UNKNOWN, + message: message, + metadata: existing_metadata}, null, null); + } else { + cb(null, {count: 1}); + } + }/*, + clientStream: function(stream, cb){ + var count = 0; + var errored; + stream.on('data', function(data) { + if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + errored = true; + cb(new Error(message), null, trailer_metadata); + } else { + count += 1; + } + }); + stream.on('end', function() { + if (!errored) { + cb(null, {count: count}, trailer_metadata); + } + }); + }, + serverStream: function(stream) { + var req = stream.request; + if (req.error) { + var message = 'Requested error'; + if (req.message) { + message = req.message; + } + var err = {code: serverGrpc.status.UNKNOWN, + details: message}; + err.metadata = trailer_metadata; + stream.emit('error', err); + } else { + for (var i = 0; i < 5; i++) { + stream.write({count: i}); + } + stream.end(trailer_metadata); + } + }, + bidiStream: function(stream) { + var count = 0; + stream.on('data', function(data) { + if (data.error) { + var message = 'Requested error'; + if (data.message) { + message = data.message; + } + var err = new Error(message); + err.metadata = trailer_metadata.clone(); + err.metadata.add('count', '' + count); + stream.emit('error', err); + } else { + stream.write({count: count}); + count += 1; + } + }); + stream.on('end', function() { + stream.end(trailer_metadata); + }); + } + */}); + server.bindAsync('localhost:0', serverInsecureCreds, (err, _port) => { + assert.ifError(err); + port = _port; + client = new TestServiceClient('localhost:' + port, clientInsecureCreds); + server.start(); + done(); + }); + }); + after(function() { + server.forceShutdown(); + }); + describe('Existing metadata', function() { + it('should not be present when a unary call succeeds', function(done) { + var call = client.unary({error: false}, function(err, data) { + assert.ifError(err); + }); + call.on('status', function(status) { + assert.true(status.metadata.get('existing-metadata', [])); + done(); + }); + }); + it('should be present when a unary call fails', function(done) { + var call = client.unary({error: true}, function(err, data) { + assert(err); + }); + call.on('status', function(status) { + assert.deepEqual(status.metadata.get('existing-metadata'), ['yes']); + done(); + }); + }); + }); + describe('Error object should contain the status', function() { + it('for a unary call', function(done) { + client.unary({error: true}, function(err, data) { + assert(err); + assert.strictEqual(err.code, clientGrpc.status.UNKNOWN); + assert.strictEqual(err.details, 'Requested error'); + done(); + }); + }); + }); + }); }); \ No newline at end of file From 5b2af32d3c1e8682b8214098139eb920fae24668 Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Mon, 13 Jan 2020 16:51:37 -0800 Subject: [PATCH 0910/1899] Update test/api/error_test.js Co-Authored-By: Michael Lumish --- test/api/error_test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/api/error_test.js b/test/api/error_test.js index f7ff621af..7baa19b60 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -664,7 +664,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert.ifError(err); }); call.on('status', function(status) { - assert.true(status.metadata.get('existing-metadata', [])); + assert.deepStrictEqual(status.metadata.get('existing-metadata'), []); done(); }); }); @@ -689,4 +689,4 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); }); -}); \ No newline at end of file +}); From eecfebb67723c2cb4bf6f6e8246a44532a0e937b Mon Sep 17 00:00:00 2001 From: CyrusNajmabadi Date: Mon, 13 Jan 2020 16:51:43 -0800 Subject: [PATCH 0911/1899] Update test/api/error_test.js Co-Authored-By: Michael Lumish --- test/api/error_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/error_test.js b/test/api/error_test.js index 7baa19b60..a99619fbd 100644 --- a/test/api/error_test.js +++ b/test/api/error_test.js @@ -673,7 +673,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert(err); }); call.on('status', function(status) { - assert.deepEqual(status.metadata.get('existing-metadata'), ['yes']); + assert.deepStrictEqual(status.metadata.get('existing-metadata'), ['yes']); done(); }); }); From 2add1c342d9d61541f57774c6f1345b525156755 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 24 Jan 2020 10:47:44 -0800 Subject: [PATCH 0912/1899] grpc-js: Add HTTP CONNECT support, i.e. egress proxy support --- packages/grpc-js/src/http_proxy.ts | 160 +++++++++++++++++++++++++++ packages/grpc-js/src/resolver-dns.ts | 17 +++ packages/grpc-js/src/subchannel.ts | 19 +++- 3 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js/src/http_proxy.ts diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts new file mode 100644 index 000000000..18a6fd48c --- /dev/null +++ b/packages/grpc-js/src/http_proxy.ts @@ -0,0 +1,160 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { URL, parse } from "url"; +import { log } from "./logging"; +import { LogVerbosity } from "./constants"; +import { parseTarget } from "./resolver-dns"; +import { Socket } from "net"; +import * as http from 'http'; +import * as logging from './logging'; + +const TRACER_NAME = 'proxy'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + +interface ProxyInfo { + address?: string; + creds?: string; +} + +function getProxyInfo(): ProxyInfo { + let proxyEnv: string = ''; + let envVar: string = ''; + /* Prefer using 'grpc_proxy'. Fallback on 'http_proxy' if it is not set. + * Also prefer using 'https_proxy' with fallback on 'http_proxy'. The + * fallback behavior can be removed if there's a demand for it. + */ + if (process.env.grpc_proxy) { + envVar = 'grpc_proxy'; + proxyEnv = process.env.grpc_proxy; + } else if (process.env.https_proxy) { + envVar = 'https_proxy'; + proxyEnv = process.env.https_proxy; + } else if (process.env.http_proxy) { + envVar = 'http_proxy'; + proxyEnv = process.env.http_proxy; + } else { + return {}; + } + let proxyUrl: URL; + try { + proxyUrl = new URL(proxyEnv); + } catch (e) { + log(LogVerbosity.INFO, `cannot parse value of "${envVar}" env var`); + return {}; + } + if (proxyUrl.protocol !== 'http') { + log(LogVerbosity.ERROR, `"${proxyUrl.protocol}" scheme not supported in proxy URI`); + return {}; + } + let userCred: string | null = null; + if (proxyUrl.username) { + if (proxyUrl.password) { + log(LogVerbosity.INFO, 'userinfo found in proxy URI'); + userCred = `${proxyUrl.username}:${proxyUrl.password}`; + } else { + userCred = proxyUrl.username; + } + } + const result: ProxyInfo = { + address: proxyUrl.host + }; + if (userCred) { + result.creds = userCred; + } + trace('Proxy server ' + result.address + ' set by environment variable ' + envVar); + return result; +} + +const PROXY_INFO = getProxyInfo(); + +function getNoProxyHostList(): string[] { + /* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */ + let noProxyStr: string | undefined = process.env.no_grpc_proxy; + let envVar: string = 'no_grpc_proxy'; + if (!noProxyStr) { + noProxyStr = process.env.no_proxy; + envVar = 'no_proxy'; + } + if (noProxyStr) { + trace('No proxy server list set by environment variable ' + envVar); + return noProxyStr.split(','); + } else { + return []; + } +} + +const NO_PROXY_HOSTS = getNoProxyHostList(); + +export function shouldUseProxy(target: string): boolean { + if (!PROXY_INFO.address) { + return false; + } + let serverHost: string; + const parsedTarget = parseTarget(target); + if (parsedTarget) { + serverHost = parsedTarget.host; + } else { + return false; + } + for (const host of NO_PROXY_HOSTS) { + if (host === serverHost) { + trace('Not using proxy for target in no_proxy list: ' + target); + return false; + } + } + return true; +} + +export function getProxiedConnection(target: string, subchannelAddress: string): Promise { + if (!(PROXY_INFO.address && shouldUseProxy(target))) { + return Promise.reject(); + } + trace('Using proxy ' + PROXY_INFO.address + ' to connect to ' + target + ' at ' + subchannelAddress); + const options: http.RequestOptions = { + method: 'CONNECT', + host: PROXY_INFO.address, + path: subchannelAddress + }; + if (PROXY_INFO.creds) { + options.headers = { + 'Proxy-Authorization': 'Basic ' + Buffer.from(PROXY_INFO.creds).toString('base64') + }; + } + return new Promise((resolve, reject) => { + const request = http.request(options); + request.once('connect', (res, socket, head) => { + request.removeAllListeners(); + socket.removeAllListeners(); + if (res.statusCode === http.STATUS_CODES.OK) { + trace('Successfully connected to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); + resolve(socket); + } else { + trace('Failed to connect to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); + reject(); + } + }); + request.once('error', (err) => { + request.removeAllListeners(); + trace('Failed to connect to proxy ' + PROXY_INFO.address); + reject(); + }); + }); +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 9f91d70ab..3100d3f69 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -322,3 +322,20 @@ export function setup(): void { registerResolver('dns:', DnsResolver); registerDefaultResolver(DnsResolver); } + +export interface dnsUrl { + host: string; + port?: string; +} + +export function parseTarget(target: string): dnsUrl | null { + const match = IPV4_REGEX.exec(target) ?? IPV6_REGEX.exec(target) ?? IPV6_BRACKET_REGEX.exec(target) ?? DNS_REGEX.exec(target) + if (match) { + return { + host: match[0], + port: match[1] ?? undefined + }; + } else { + return null; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index b6b282d52..31ca76fa8 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -26,6 +26,8 @@ import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { Socket } from 'net'; +import { shouldUseProxy, getProxiedConnection } from './http_proxy'; const { version: clientVersion } = require('../../package.json'); @@ -224,9 +226,12 @@ export class Subchannel { clearTimeout(this.keepaliveTimeoutId); } - private startConnectingInternal() { + private createSession(socket?: Socket) { const connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; + if (socket) { + connectionOptions.socket = socket; + } let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { addressScheme = 'https://'; @@ -313,6 +318,18 @@ export class Subchannel { }); } + private startConnectingInternal() { + if (shouldUseProxy(this.channelTarget)) { + getProxiedConnection(this.channelTarget, this.subchannelAddress).then((socket) => { + this.createSession(socket); + }, (reason) => { + this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.TRANSIENT_FAILURE); + }); + } else { + this.createSession(); + } + } + /** * Initiate a state transition from any element of oldStates to the new * state. If the current connectivityState is not in oldStates, do nothing. From b9220fdb2da6843c4409e51493406e1a070d847d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Jan 2020 15:31:06 -0800 Subject: [PATCH 0913/1899] Fix capture group numbers in parseTarget --- packages/grpc-js/src/resolver-dns.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 3100d3f69..4078a19ca 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -332,10 +332,10 @@ export function parseTarget(target: string): dnsUrl | null { const match = IPV4_REGEX.exec(target) ?? IPV6_REGEX.exec(target) ?? IPV6_BRACKET_REGEX.exec(target) ?? DNS_REGEX.exec(target) if (match) { return { - host: match[0], - port: match[1] ?? undefined + host: match[1], + port: match[2] ?? undefined }; } else { return null; } -} \ No newline at end of file +} From 57c18382d8769a1c9eee4d0d22006828e32d6899 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Jan 2020 09:42:13 -0800 Subject: [PATCH 0914/1899] grpc-js: Use an object to represent subchannel addresses --- packages/grpc-js/src/channel.ts | 3 +- .../grpc-js/src/load-balancer-pick-first.ts | 6 +- .../grpc-js/src/load-balancer-round-robin.ts | 4 +- packages/grpc-js/src/load-balancer.ts | 6 +- packages/grpc-js/src/resolver-dns.ts | 27 ++++--- packages/grpc-js/src/resolver-uds.ts | 5 +- packages/grpc-js/src/resolver.ts | 3 +- .../grpc-js/src/resolving-load-balancer.ts | 9 ++- packages/grpc-js/src/subchannel-pool.ts | 73 +++++++++---------- packages/grpc-js/src/subchannel.ts | 61 +++++++++++++--- packages/grpc-js/test/test-resolver.ts | 37 +++++----- 11 files changed, 136 insertions(+), 98 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6cf987cb9..a19cc2173 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -38,6 +38,7 @@ import { getDefaultAuthority } from './resolver'; import { LoadBalancingConfig } from './load-balancing-config'; import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace } from './logging'; +import { SubchannelAddress } from './subchannel'; export enum ConnectivityState { CONNECTING, @@ -145,7 +146,7 @@ export class ChannelImplementation implements Channel { this.subchannelPool = getSubchannelPool((options['grpc.use_local_subchannel_pool'] ?? 0) === 0); const channelControlHelper: ChannelControlHelper = { createSubchannel: ( - subchannelAddress: string, + subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions ) => { return this.subchannelPool.getOrCreateSubchannel( diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index a5fbf0fa9..fffb2a2a7 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -30,7 +30,7 @@ import { UnavailablePicker, } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; -import { Subchannel, ConnectivityStateListener } from './subchannel'; +import { Subchannel, ConnectivityStateListener, SubchannelAddress } from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; @@ -76,7 +76,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { /** * The list of backend addresses most recently passed to `updateAddressList`. */ - private latestAddressList: string[] = []; + private latestAddressList: SubchannelAddress[] = []; /** * The list of subchannels this load balancer is currently attempting to * connect to. @@ -369,7 +369,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { } updateAddressList( - addressList: string[], + addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null ): void { // lbConfig has no useful information for pick first load balancing diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index e3eedfe5f..2aeda4300 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -30,7 +30,7 @@ import { UnavailablePicker, } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; -import { Subchannel, ConnectivityStateListener } from './subchannel'; +import { Subchannel, ConnectivityStateListener, SubchannelAddress } from './subchannel'; const TYPE_NAME = 'round_robin'; @@ -168,7 +168,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { } updateAddressList( - addressList: string[], + addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null ): void { this.resetSubchannelList(); diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 691145214..5fa4bdc53 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -16,7 +16,7 @@ */ import { ChannelOptions } from './channel-options'; -import { Subchannel } from './subchannel'; +import { Subchannel, SubchannelAddress } from './subchannel'; import { ConnectivityState } from './channel'; import { Picker } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; @@ -34,7 +34,7 @@ export interface ChannelControlHelper { * @param subchannelArgs Extra channel arguments specified by the load balancer */ createSubchannel( - subchannelAddress: string, + subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions ): Subchannel; /** @@ -66,7 +66,7 @@ export interface LoadBalancer { * if one was provided */ updateAddressList( - addressList: string[], + addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null ): void; /** diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 9f91d70ab..9d357996b 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -30,6 +30,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { SubchannelAddress } from './subchannel'; const TRACER_NAME = 'dns_resolver'; @@ -112,7 +113,7 @@ const dnsLookupPromise = util.promisify(dns.lookup); * @param target * @return An "IP:port" string in an array if parsing was successful, `null` otherwise */ -function parseIP(target: string): string[] | null { +function parseIP(target: string): SubchannelAddress[] | null { /* These three regular expressions are all mutually exclusive, so we just * want the first one that matches the target string, if any do. */ const ipv4Match = IPV4_REGEX.exec(target); @@ -123,14 +124,14 @@ function parseIP(target: string): string[] | null { } // ipv6 addresses should be bracketed - const addr = ipv4Match ? match[1] : `[${match[1]}]`; + const addr = match[1]; let port: string; if (match[2]) { port = match[2]; } else { port = DEFAULT_PORT; } - return [`${addr}:${port}`]; + return [{host: addr, port: +port}]; } /** @@ -161,7 +162,7 @@ function mergeArrays(...arrays: T[][]): T[] { * Resolver implementation that handles DNS names and IP addresses. */ class DnsResolver implements Resolver { - private readonly ipResult: string[] | null; + private readonly ipResult: SubchannelAddress[] | null; private readonly dnsHostname: string | null; private readonly port: string | null; /* The promise results here contain, in order, the A record, the AAAA record, @@ -222,23 +223,21 @@ class DnsResolver implements Resolver { this.pendingResultPromise.then( ([addressList, txtRecord]) => { this.pendingResultPromise = null; - const ip4Addresses: string[] = addressList - .filter(addr => addr.family === 4) - .map(addr => `${addr.address}:${this.port}`); - let ip6Addresses: string[]; + const ip4Addresses: dns.LookupAddress[] = addressList + .filter(addr => addr.family === 4); + let ip6Addresses: dns.LookupAddress[]; if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - ip6Addresses = addressList - .filter(addr => addr.family === 6) - .map(addr => `[${addr.address}]:${this.port}`); + ip6Addresses = addressList.filter(addr => addr.family === 6); } else { ip6Addresses = []; } - const allAddresses: string[] = mergeArrays( + const allAddresses: SubchannelAddress[] = mergeArrays( ip4Addresses, ip6Addresses - ); + ).map(addr => {return {host: addr.address, port: +this.port!};}); + const allAddressesString: string = '[' + allAddresses.map(addr => addr.host + ':' + addr.port).join(',') + ']'; trace( - 'Resolved addresses for target ' + this.target + ': ' + allAddresses + 'Resolved addresses for target ' + this.target + ': ' + allAddressesString ); if (allAddresses.length === 0) { this.listener.onError(this.defaultResolutionError); diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 536a018b3..64c628f34 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -20,6 +20,7 @@ import { registerResolver, registerDefaultResolver, } from './resolver'; +import { SubchannelAddress } from './subchannel'; function getUdsName(target: string): string { /* Due to how this resolver is registered, it should only be constructed @@ -34,9 +35,9 @@ function getUdsName(target: string): string { } class UdsResolver implements Resolver { - private addresses: string[] = []; + private addresses: SubchannelAddress[] = []; constructor(target: string, private listener: ResolverListener) { - this.addresses = [getUdsName(target)]; + this.addresses = [{path: getUdsName(target)}]; } updateResolution(): void { process.nextTick( diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 3af5da9cd..b2be310f0 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -20,6 +20,7 @@ import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; +import { SubchannelAddress } from './subchannel'; /** * A listener object passed to the resolver's constructor that provides name @@ -36,7 +37,7 @@ export interface ResolverListener { * service configuration was invalid */ onSuccessfulResolution( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ): void; diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 496e13450..a9ba0594f 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -34,6 +34,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { SubchannelAddress } from './subchannel'; const TRACER_NAME = 'resolving_load_balancer'; @@ -132,7 +133,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.innerResolver = createResolver(target, { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null ) => { @@ -243,7 +244,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.innerChannelControlHelper = { createSubchannel: ( - subchannelAddress: string, + subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions ) => { return this.channelControlHelper.createSubchannel( @@ -289,7 +290,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.replacementChannelControlHelper = { createSubchannel: ( - subchannelAddress: string, + subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions ) => { return this.channelControlHelper.createSubchannel( @@ -409,7 +410,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } updateAddressList( - addressList: string[], + addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null ) { throw new Error('updateAddressList not supported on ResolvingLoadBalancer'); diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 009141e39..3a49295b0 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -16,7 +16,7 @@ */ import { ChannelOptions, channelOptionsEqual } from './channel-options'; -import { Subchannel } from './subchannel'; +import { Subchannel, SubchannelAddress, subchannelAddressEqual } from './subchannel'; import { ChannelCredentials } from './channel-credentials'; // 10 seconds in milliseconds. This value is arbitrary. @@ -28,13 +28,12 @@ const REF_CHECK_INTERVAL = 10_000; export class SubchannelPool { private pool: { - [channelTarget: string]: { - [subchannelTarget: string]: Array<{ - channelArguments: ChannelOptions; - channelCredentials: ChannelCredentials; - subchannel: Subchannel; - }>; - }; + [channelTarget: string]: Array<{ + subchannelAddress: SubchannelAddress; + channelArguments: ChannelOptions; + channelCredentials: ChannelCredentials; + subchannel: Subchannel; + }>; } = Object.create(null); /** @@ -62,23 +61,20 @@ export class SubchannelPool { * do not need to be filtered */ // tslint:disable-next-line:forin for (const channelTarget in this.pool) { - // tslint:disable-next-line:forin - for (const subchannelTarget in this.pool[channelTarget]) { - const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; + const subchannelObjArray = this.pool[channelTarget]; - const refedSubchannels = subchannelObjArray.filter( - value => !value.subchannel.unrefIfOneRef() - ); + const refedSubchannels = subchannelObjArray.filter( + value => !value.subchannel.unrefIfOneRef() + ); - if (refedSubchannels.length > 0) { - allSubchannelsUnrefed = false; - } - - /* For each subchannel in the pool, try to unref it if it has - * exactly one ref (which is the ref from the pool itself). If that - * does happen, remove the subchannel from the pool */ - this.pool[channelTarget][subchannelTarget] = refedSubchannels; + if (refedSubchannels.length > 0) { + allSubchannelsUnrefed = false; } + + /* For each subchannel in the pool, try to unref it if it has + * exactly one ref (which is the ref from the pool itself). If that + * does happen, remove the subchannel from the pool */ + this.pool[channelTarget] = refedSubchannels; } /* Currently we do not delete keys with empty values. If that results * in significant memory usage we should change it. */ @@ -114,25 +110,24 @@ export class SubchannelPool { */ getOrCreateSubchannel( channelTarget: string, - subchannelTarget: string, + subchannelTarget: SubchannelAddress, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials ): Subchannel { this.ensureCleanupTask(); if (channelTarget in this.pool) { - if (subchannelTarget in this.pool[channelTarget]) { - const subchannelObjArray = this.pool[channelTarget][subchannelTarget]; - for (const subchannelObj of subchannelObjArray) { - if ( - channelOptionsEqual( - channelArguments, - subchannelObj.channelArguments - ) && - channelCredentials._equals(subchannelObj.channelCredentials) - ) { - return subchannelObj.subchannel; - } + const subchannelObjArray = this.pool[channelTarget]; + for (const subchannelObj of subchannelObjArray) { + if ( + subchannelAddressEqual(subchannelTarget, subchannelObj.subchannelAddress) && + channelOptionsEqual( + channelArguments, + subchannelObj.channelArguments + ) && + channelCredentials._equals(subchannelObj.channelCredentials) + ) { + return subchannelObj.subchannel; } } } @@ -144,12 +139,10 @@ export class SubchannelPool { channelCredentials ); if (!(channelTarget in this.pool)) { - this.pool[channelTarget] = Object.create(null); - } - if (!(subchannelTarget in this.pool[channelTarget])) { - this.pool[channelTarget][subchannelTarget] = []; + this.pool[channelTarget] = []; } - this.pool[channelTarget][subchannelTarget].push({ + this.pool[channelTarget].push({ + subchannelAddress: subchannelTarget, channelArguments, channelCredentials, subchannel, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index b6b282d52..2a123f045 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -20,12 +20,13 @@ import { ChannelCredentials } from './channel-credentials'; import { Metadata } from './metadata'; import { Http2CallStream } from './call-stream'; import { ChannelOptions } from './channel-options'; -import { PeerCertificate, checkServerIdentity } from 'tls'; +import { PeerCertificate, checkServerIdentity, TLSSocket } from 'tls'; import { ConnectivityState } from './channel'; import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { SocketConnectOpts } from 'net'; const { version: clientVersion } = require('../../package.json'); @@ -73,6 +74,22 @@ function uniformRandom(min: number, max: number) { const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); +/** + * This represents a single backend address to connect to. This interface is a + * subset of net.SocketConnectOpts, i.e. the options described at + * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener. + * Those are in turn a subset of the options that can be passed to http2.connect. + */ +export interface SubchannelAddress { + port?: number; + host?: string; + path?: string; +} + +export function subchannelAddressEqual(address1: SubchannelAddress, address2: SubchannelAddress) : boolean { + return address1.port === address2.port && address1.host === address2.host && address1.path === address2.path; +} + export class Subchannel { /** * The subchannel's current connectivity state. Invariant: `session` === `null` @@ -135,6 +152,11 @@ export class Subchannel { */ private refcount = 0; + /** + * A string representation of the subchannel address, for logging/tracing + */ + private subchannelAddressString: string; + /** * A class representing a connection to a single backend. * @param channelTarget The target string for the channel as a whole @@ -147,7 +169,7 @@ export class Subchannel { */ constructor( private channelTarget: string, - private subchannelAddress: string, + private subchannelAddress: SubchannelAddress, private options: ChannelOptions, private credentials: ChannelCredentials ) { @@ -187,6 +209,11 @@ export class Subchannel { ); } }, backoffOptions); + if (subchannelAddress.host || subchannelAddress.port) { + this.subchannelAddressString = `${subchannelAddress.host}:${subchannelAddress.port}`; + } else { + this.subchannelAddressString = `${subchannelAddress.path}`; + } } /** @@ -225,10 +252,11 @@ export class Subchannel { } private startConnectingInternal() { - const connectionOptions: http2.SecureClientSessionOptions = + let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { + connectionOptions.protocol = 'https:'; addressScheme = 'https://'; // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. @@ -248,8 +276,21 @@ export class Subchannel { connectionOptions.servername = getDefaultAuthority(this.channelTarget); } } + connectionOptions = Object.assign(connectionOptions, this.subchannelAddress); + /* http2.connect uses the options here: + * https://github.com/nodejs/node/blob/70c32a6d190e2b5d7b9ff9d5b6a459d14e8b7d59/lib/internal/http2/core.js#L3028-L3036 + * The spread operator overides earlier values with later ones, so any port + * or host values in the options will be used rather than any values extracted + * from the first argument. In addition, the path overrides the host and port, + * as documented for plaintext connections here: + * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener + * and for TLS connections here: + * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback. + * The first argument just needs to be parseable as a URL and the scheme + * determines whether the connection will be established over TLS or not. + */ const session = http2.connect( - addressScheme + this.subchannelAddress, + addressScheme + getDefaultAuthority(this.channelTarget), connectionOptions ); this.session = session; @@ -328,7 +369,7 @@ export class Subchannel { return false; } trace( - this.subchannelAddress + + this.subchannelAddressString + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + @@ -400,7 +441,7 @@ export class Subchannel { callRef() { trace( - this.subchannelAddress + + this.subchannelAddressString + ' callRefcount ' + this.callRefcount + ' -> ' + @@ -417,7 +458,7 @@ export class Subchannel { callUnref() { trace( - this.subchannelAddress + + this.subchannelAddressString + ' callRefcount ' + this.callRefcount + ' -> ' + @@ -435,7 +476,7 @@ export class Subchannel { ref() { trace( - this.subchannelAddress + + this.subchannelAddressString + ' callRefcount ' + this.refcount + ' -> ' + @@ -446,7 +487,7 @@ export class Subchannel { unref() { trace( - this.subchannelAddress + + this.subchannelAddressString + ' callRefcount ' + this.refcount + ' -> ' + @@ -557,6 +598,6 @@ export class Subchannel { } getAddress(): string { - return this.subchannelAddress; + return this.subchannelAddressString; } } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 951291a61..fc1585105 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -21,6 +21,7 @@ import * as assert from 'assert'; import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; +import { SubchannelAddress } from '../src/subchannel'; describe('Name Resolver', () => { describe('DNS Names', function() { @@ -33,11 +34,11 @@ describe('Name Resolver', () => { const target = 'localhost:50051'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('127.0.0.1:50051')); + assert(addressList.some(addr => addr.host === '127.0.0.1' && addr.port === 50051)); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -52,11 +53,11 @@ describe('Name Resolver', () => { const target = 'localhost'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('127.0.0.1:443')); + assert(addressList.some(addr => addr.host === '127.0.0.1' && addr.port === 443)); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -71,11 +72,11 @@ describe('Name Resolver', () => { const target = '1.2.3.4'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('1.2.3.4:443')); + assert(addressList.some(addr => addr.host === '1.2.3.4' && addr.port === 443)); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -90,11 +91,11 @@ describe('Name Resolver', () => { const target = '::1'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('[::1]:443')); + assert(addressList.some(addr => addr.host === '::1' && addr.port === 443)); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -109,11 +110,11 @@ describe('Name Resolver', () => { const target = '[::1]:50051'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('[::1]:50051')); + assert(addressList.some(addr => addr.host === '::1' && addr.port === 50051)); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -128,7 +129,7 @@ describe('Name Resolver', () => { const target = 'example.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { @@ -146,7 +147,7 @@ describe('Name Resolver', () => { const target = 'loopback4.unittest.grpc.io'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { @@ -166,7 +167,7 @@ describe('Name Resolver', () => { const target = 'network-tools.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { @@ -196,7 +197,7 @@ describe('Name Resolver', () => { const target2 = 'grpc-test4.sandbox.googleapis.com'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { @@ -218,11 +219,11 @@ describe('Name Resolver', () => { const target = 'unix:socket'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('socket')); + assert(addressList.some(addr => addr.path = 'socket')); done(); }, onError: (error: StatusObject) => { @@ -236,11 +237,11 @@ describe('Name Resolver', () => { const target = 'unix:///tmp/socket'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( - addressList: string[], + addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.includes('/tmp/socket')); + assert(addressList.some(addr => addr.path = '/tmp/socket')); done(); }, onError: (error: StatusObject) => { From c5428c57330d6a5f52e3edd9600f021e5f158123 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Jan 2020 09:56:49 -0800 Subject: [PATCH 0915/1899] lint and formatting fixes --- packages/grpc-js/src/channel-credentials.ts | 4 +-- packages/grpc-js/src/channel.ts | 4 ++- .../grpc-js/src/load-balancer-pick-first.ts | 6 +++- .../grpc-js/src/load-balancer-round-robin.ts | 6 +++- packages/grpc-js/src/resolver-dns.ts | 19 ++++++++---- packages/grpc-js/src/resolver-uds.ts | 2 +- packages/grpc-js/src/server-credentials.ts | 4 +-- packages/grpc-js/src/server.ts | 9 ++++-- packages/grpc-js/src/subchannel-pool.ts | 15 +++++++--- packages/grpc-js/src/subchannel.ts | 18 ++++++++--- packages/grpc-js/src/tls-helpers.ts | 5 ++-- packages/grpc-js/test/test-resolver.ts | 30 ++++++++++++++----- 12 files changed, 89 insertions(+), 33 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index f42c7e936..5d5b87d50 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -18,7 +18,7 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; -import {CIPHER_SUITES, getDefaultRootsData} from './tls-helpers'; +import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; // tslint:disable-next-line:no-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -190,7 +190,7 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { ca: rootCerts || undefined, key: privateKey || undefined, cert: certChain || undefined, - ciphers: CIPHER_SUITES + ciphers: CIPHER_SUITES, }); this.connectionOptions = { secureContext }; if (verifyOptions && verifyOptions.checkServerIdentity) { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index a19cc2173..d43da0e51 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -143,7 +143,9 @@ export class ChannelImplementation implements Channel { ) { /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ - this.subchannelPool = getSubchannelPool((options['grpc.use_local_subchannel_pool'] ?? 0) === 0); + this.subchannelPool = getSubchannelPool( + (options['grpc.use_local_subchannel_pool'] ?? 0) === 0 + ); const channelControlHelper: ChannelControlHelper = { createSubchannel: ( subchannelAddress: SubchannelAddress, diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index fffb2a2a7..52ce8457a 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -30,7 +30,11 @@ import { UnavailablePicker, } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; -import { Subchannel, ConnectivityStateListener, SubchannelAddress } from './subchannel'; +import { + Subchannel, + ConnectivityStateListener, + SubchannelAddress, +} from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 2aeda4300..4956e11e7 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -30,7 +30,11 @@ import { UnavailablePicker, } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; -import { Subchannel, ConnectivityStateListener, SubchannelAddress } from './subchannel'; +import { + Subchannel, + ConnectivityStateListener, + SubchannelAddress, +} from './subchannel'; const TYPE_NAME = 'round_robin'; diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 9d357996b..a5cd028a5 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -131,7 +131,7 @@ function parseIP(target: string): SubchannelAddress[] | null { } else { port = DEFAULT_PORT; } - return [{host: addr, port: +port}]; + return [{ host: addr, port: +port }]; } /** @@ -223,8 +223,9 @@ class DnsResolver implements Resolver { this.pendingResultPromise.then( ([addressList, txtRecord]) => { this.pendingResultPromise = null; - const ip4Addresses: dns.LookupAddress[] = addressList - .filter(addr => addr.family === 4); + const ip4Addresses: dns.LookupAddress[] = addressList.filter( + addr => addr.family === 4 + ); let ip6Addresses: dns.LookupAddress[]; if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { ip6Addresses = addressList.filter(addr => addr.family === 6); @@ -234,10 +235,16 @@ class DnsResolver implements Resolver { const allAddresses: SubchannelAddress[] = mergeArrays( ip4Addresses, ip6Addresses - ).map(addr => {return {host: addr.address, port: +this.port!};}); - const allAddressesString: string = '[' + allAddresses.map(addr => addr.host + ':' + addr.port).join(',') + ']'; + ).map(addr => ({ host: addr.address, port: +this.port! })); + const allAddressesString: string = + '[' + + allAddresses.map(addr => addr.host + ':' + addr.port).join(',') + + ']'; trace( - 'Resolved addresses for target ' + this.target + ': ' + allAddressesString + 'Resolved addresses for target ' + + this.target + + ': ' + + allAddressesString ); if (allAddresses.length === 0) { this.listener.onError(this.defaultResolutionError); diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 64c628f34..91128d2cb 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -37,7 +37,7 @@ function getUdsName(target: string): string { class UdsResolver implements Resolver { private addresses: SubchannelAddress[] = []; constructor(target: string, private listener: ResolverListener) { - this.addresses = [{path: getUdsName(target)}]; + this.addresses = [{ path: getUdsName(target) }]; } updateResolution(): void { process.nextTick( diff --git a/packages/grpc-js/src/server-credentials.ts b/packages/grpc-js/src/server-credentials.ts index b56cb68ab..17ab29805 100644 --- a/packages/grpc-js/src/server-credentials.ts +++ b/packages/grpc-js/src/server-credentials.ts @@ -16,7 +16,7 @@ */ import { SecureServerOptions } from 'http2'; -import {CIPHER_SUITES, getDefaultRootsData} from './tls-helpers'; +import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; export interface KeyCertPair { private_key: Buffer; @@ -75,7 +75,7 @@ export abstract class ServerCredentials { cert, key, requestCert: checkClientCertificate, - ciphers: CIPHER_SUITES + ciphers: CIPHER_SUITES, }); } } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 03fcfaf90..a2db30beb 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -203,11 +203,16 @@ export class Server { const options: ListenOptions = { host: url.hostname, port: +url.port }; const serverOptions: http2.ServerOptions = {}; if ('grpc.max_concurrent_streams' in this.options) { - serverOptions.settings = {maxConcurrentStreams: this.options['grpc.max_concurrent_streams']}; + serverOptions.settings = { + maxConcurrentStreams: this.options['grpc.max_concurrent_streams'], + }; } if (creds._isSecure()) { - const secureServerOptions = Object.assign(serverOptions, creds._getSettings()!); + const secureServerOptions = Object.assign( + serverOptions, + creds._getSettings()! + ); this.http2Server = http2.createSecureServer(secureServerOptions); } else { this.http2Server = http2.createServer(serverOptions); diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 3a49295b0..61a4e13c3 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -16,7 +16,11 @@ */ import { ChannelOptions, channelOptionsEqual } from './channel-options'; -import { Subchannel, SubchannelAddress, subchannelAddressEqual } from './subchannel'; +import { + Subchannel, + SubchannelAddress, + subchannelAddressEqual, +} from './subchannel'; import { ChannelCredentials } from './channel-credentials'; // 10 seconds in milliseconds. This value is arbitrary. @@ -72,8 +76,8 @@ export class SubchannelPool { } /* For each subchannel in the pool, try to unref it if it has - * exactly one ref (which is the ref from the pool itself). If that - * does happen, remove the subchannel from the pool */ + * exactly one ref (which is the ref from the pool itself). If that + * does happen, remove the subchannel from the pool */ this.pool[channelTarget] = refedSubchannels; } /* Currently we do not delete keys with empty values. If that results @@ -120,7 +124,10 @@ export class SubchannelPool { const subchannelObjArray = this.pool[channelTarget]; for (const subchannelObj of subchannelObjArray) { if ( - subchannelAddressEqual(subchannelTarget, subchannelObj.subchannelAddress) && + subchannelAddressEqual( + subchannelTarget, + subchannelObj.subchannelAddress + ) && channelOptionsEqual( channelArguments, subchannelObj.channelArguments diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 2a123f045..ae6f206b9 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -86,8 +86,15 @@ export interface SubchannelAddress { path?: string; } -export function subchannelAddressEqual(address1: SubchannelAddress, address2: SubchannelAddress) : boolean { - return address1.port === address2.port && address1.host === address2.host && address1.path === address2.path; +export function subchannelAddressEqual( + address1: SubchannelAddress, + address2: SubchannelAddress +): boolean { + return ( + address1.port === address2.port && + address1.host === address2.host && + address1.path === address2.path + ); } export class Subchannel { @@ -194,7 +201,7 @@ export class Subchannel { clearTimeout(this.keepaliveTimeoutId); const backoffOptions: BackoffOptions = { initialDelay: options['grpc.initial_reconnect_backoff_ms'], - maxDelay: options['grpc.max_reconnect_backoff_ms'] + maxDelay: options['grpc.max_reconnect_backoff_ms'], }; this.backoffTimeout = new BackoffTimeout(() => { if (this.continueConnecting) { @@ -276,7 +283,10 @@ export class Subchannel { connectionOptions.servername = getDefaultAuthority(this.channelTarget); } } - connectionOptions = Object.assign(connectionOptions, this.subchannelAddress); + connectionOptions = Object.assign( + connectionOptions, + this.subchannelAddress + ); /* http2.connect uses the options here: * https://github.com/nodejs/node/blob/70c32a6d190e2b5d7b9ff9d5b6a459d14e8b7d59/lib/internal/http2/core.js#L3028-L3036 * The spread operator overides earlier values with later ones, so any port diff --git a/packages/grpc-js/src/tls-helpers.ts b/packages/grpc-js/src/tls-helpers.ts index 161666edc..3f7a62e7e 100644 --- a/packages/grpc-js/src/tls-helpers.ts +++ b/packages/grpc-js/src/tls-helpers.ts @@ -17,7 +17,8 @@ import * as fs from 'fs'; -export const CIPHER_SUITES: string | undefined = process.env.GRPC_SSL_CIPHER_SUITES; +export const CIPHER_SUITES: string | undefined = + process.env.GRPC_SSL_CIPHER_SUITES; const DEFAULT_ROOTS_FILE_PATH = process.env.GRPC_DEFAULT_SSL_ROOTS_FILE_PATH; @@ -31,4 +32,4 @@ export function getDefaultRootsData(): Buffer | null { return defaultRootsData; } return null; -} \ No newline at end of file +} diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index fc1585105..38ed50696 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -38,7 +38,11 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.host === '127.0.0.1' && addr.port === 50051)); + assert( + addressList.some( + addr => addr.host === '127.0.0.1' && addr.port === 50051 + ) + ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -57,7 +61,11 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.host === '127.0.0.1' && addr.port === 443)); + assert( + addressList.some( + addr => addr.host === '127.0.0.1' && addr.port === 443 + ) + ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -76,7 +84,11 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.host === '1.2.3.4' && addr.port === 443)); + assert( + addressList.some( + addr => addr.host === '1.2.3.4' && addr.port === 443 + ) + ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -95,7 +107,9 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.host === '::1' && addr.port === 443)); + assert( + addressList.some(addr => addr.host === '::1' && addr.port === 443) + ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -114,7 +128,9 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.host === '::1' && addr.port === 50051)); + assert( + addressList.some(addr => addr.host === '::1' && addr.port === 50051) + ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, @@ -223,7 +239,7 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.path = 'socket')); + assert(addressList.some(addr => (addr.path = 'socket'))); done(); }, onError: (error: StatusObject) => { @@ -241,7 +257,7 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => addr.path = '/tmp/socket')); + assert(addressList.some(addr => (addr.path = '/tmp/socket'))); done(); }, onError: (error: StatusObject) => { From 4f55a83b670c10507d73fb3d81efd65fc1028310 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Jan 2020 10:21:47 -0800 Subject: [PATCH 0916/1899] Remove extraneous line of code --- packages/grpc-js/src/subchannel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index ae6f206b9..b03205c7b 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -263,7 +263,6 @@ export class Subchannel { this.credentials._getConnectionOptions() || {}; let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { - connectionOptions.protocol = 'https:'; addressScheme = 'https://'; // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. From 1fe6432d92d21459cc5699c4c305aff227f59b1f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Jan 2020 16:50:29 -0800 Subject: [PATCH 0917/1899] Differentiate more strongly between TCP and IPC addresses --- packages/grpc-js/src/resolver-dns.ts | 4 +-- packages/grpc-js/src/subchannel.ts | 44 +++++++++++++++++++------- packages/grpc-js/test/test-resolver.ts | 44 +++++++++++++++++++++----- 3 files changed, 71 insertions(+), 21 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index a5cd028a5..6885f351d 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -30,7 +30,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress, TcpSubchannelAddress } from './subchannel'; const TRACER_NAME = 'dns_resolver'; @@ -232,7 +232,7 @@ class DnsResolver implements Resolver { } else { ip6Addresses = []; } - const allAddresses: SubchannelAddress[] = mergeArrays( + const allAddresses: TcpSubchannelAddress[] = mergeArrays( ip4Addresses, ip6Addresses ).map(addr => ({ host: addr.address, port: +this.port! })); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index b03205c7b..06f26892b 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -26,7 +26,7 @@ import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SocketConnectOpts } from 'net'; +import * as net from 'net'; const { version: clientVersion } = require('../../package.json'); @@ -74,27 +74,42 @@ function uniformRandom(min: number, max: number) { const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); +export interface TcpSubchannelAddress { + port: number; + host: string; +} + +export interface IpcSubchannelAddress { + path: string; +} + /** * This represents a single backend address to connect to. This interface is a * subset of net.SocketConnectOpts, i.e. the options described at * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener. * Those are in turn a subset of the options that can be passed to http2.connect. */ -export interface SubchannelAddress { - port?: number; - host?: string; - path?: string; +export type SubchannelAddress = TcpSubchannelAddress | IpcSubchannelAddress; + +export function isTcpSubchannelAddress( + address: SubchannelAddress +): address is TcpSubchannelAddress { + return 'port' in address; } export function subchannelAddressEqual( address1: SubchannelAddress, address2: SubchannelAddress ): boolean { - return ( - address1.port === address2.port && - address1.host === address2.host && - address1.path === address2.path - ); + if (isTcpSubchannelAddress(address1)) { + return ( + isTcpSubchannelAddress(address2) && + address1.host === address2.host && + address1.port === address2.port + ); + } else { + return !isTcpSubchannelAddress(address2) && address1.path === address2.path; + } } export class Subchannel { @@ -216,7 +231,7 @@ export class Subchannel { ); } }, backoffOptions); - if (subchannelAddress.host || subchannelAddress.port) { + if (isTcpSubchannelAddress(subchannelAddress)) { this.subchannelAddressString = `${subchannelAddress.host}:${subchannelAddress.port}`; } else { this.subchannelAddressString = `${subchannelAddress.path}`; @@ -281,6 +296,13 @@ export class Subchannel { } else { connectionOptions.servername = getDefaultAuthority(this.channelTarget); } + } else { + connectionOptions.createConnection = (authority, option) => { + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(this.subchannelAddress as net.NetConnectOpts); + }; } connectionOptions = Object.assign( connectionOptions, diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 38ed50696..ebb4d567f 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -21,7 +21,7 @@ import * as assert from 'assert'; import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; -import { SubchannelAddress } from '../src/subchannel'; +import { SubchannelAddress, isTcpSubchannelAddress } from '../src/subchannel'; describe('Name Resolver', () => { describe('DNS Names', function() { @@ -40,7 +40,10 @@ describe('Name Resolver', () => { ) => { assert( addressList.some( - addr => addr.host === '127.0.0.1' && addr.port === 50051 + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50051 ) ); // We would check for the IPv6 address but it needs to be omitted on some Node versions @@ -63,7 +66,10 @@ describe('Name Resolver', () => { ) => { assert( addressList.some( - addr => addr.host === '127.0.0.1' && addr.port === 443 + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 ) ); // We would check for the IPv6 address but it needs to be omitted on some Node versions @@ -86,7 +92,10 @@ describe('Name Resolver', () => { ) => { assert( addressList.some( - addr => addr.host === '1.2.3.4' && addr.port === 443 + addr => + isTcpSubchannelAddress(addr) && + addr.host === '1.2.3.4' && + addr.port === 443 ) ); // We would check for the IPv6 address but it needs to be omitted on some Node versions @@ -108,7 +117,12 @@ describe('Name Resolver', () => { serviceConfigError: StatusObject | null ) => { assert( - addressList.some(addr => addr.host === '::1' && addr.port === 443) + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); @@ -129,7 +143,12 @@ describe('Name Resolver', () => { serviceConfigError: StatusObject | null ) => { assert( - addressList.some(addr => addr.host === '::1' && addr.port === 50051) + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) ); // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); @@ -239,7 +258,11 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => (addr.path = 'socket'))); + assert( + addressList.some( + addr => !isTcpSubchannelAddress(addr) && addr.path === 'socket' + ) + ); done(); }, onError: (error: StatusObject) => { @@ -257,7 +280,12 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.some(addr => (addr.path = '/tmp/socket'))); + assert( + addressList.some( + addr => + !isTcpSubchannelAddress(addr) && addr.path === '/tmp/socket' + ) + ); done(); }, onError: (error: StatusObject) => { From 0995c9b0e6ad4c9feb459d4e8b76241333a1e919 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 29 Jan 2020 16:56:05 -0800 Subject: [PATCH 0918/1899] Update comment with new information --- packages/grpc-js/src/subchannel.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 06f26892b..bb64bd93d 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -297,6 +297,9 @@ export class Subchannel { connectionOptions.servername = getDefaultAuthority(this.channelTarget); } } else { + /* In all but the most recent versions of Node, http2.connect does not use + * the options when establishing plaintext connections, so we need to + * establish that connection explicitly. */ connectionOptions.createConnection = (authority, option) => { /* net.NetConnectOpts is declared in a way that is more restrictive * than what net.connect will actually accept, so we use the type @@ -316,7 +319,12 @@ export class Subchannel { * as documented for plaintext connections here: * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener * and for TLS connections here: - * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback. + * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback. In + * earlier versions of Node, http2.connect passes these options to + * tls.connect but not net.connect, so in the insecure case we still need + * to set the createConnection option above to create the connection + * explicitly. We cannot do that in the TLS case because http2.connect + * passes necessary additional options to tls.connect. * The first argument just needs to be parseable as a URL and the scheme * determines whether the connection will be established over TLS or not. */ From 630897244e7f7407c617955f9d0e1f28fb6ea69c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Feb 2020 10:44:58 -0800 Subject: [PATCH 0919/1899] grpc-js: Destroy http2 stream when a call ends in any way --- packages/grpc-js/src/call-stream.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index c1e9b3b5c..ee21d19fd 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -163,6 +163,9 @@ export class Http2CallStream extends Duplex implements Call { * @param status The status of the call. */ private endCall(status: StatusObject): void { + /* Once endCall is called, we are definitely not using the http2 stream + * anymore, so we can always safely destroy it here */ + this.destroyHttp2Stream(); if (this.finalStatus === null) { this.trace( 'ended with status: code=' + From 4bc642456b5966bbe85f997dea0e662ccbb8fa5f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 3 Feb 2020 11:14:03 -0800 Subject: [PATCH 0920/1899] grpc-js: Improve tracing around sending data --- packages/grpc-js/src/call-stream.ts | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index c1e9b3b5c..02b7f3434 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -246,9 +246,7 @@ export class Http2CallStream extends Duplex implements Call { private tryPush(messageBytes: Buffer | null): void { if (this.isReadFilterPending) { this.trace( - '[' + - this.callNumber + - '] unfilteredReadMessages.push message of length ' + + 'unfilteredReadMessages.push message of length ' + (messageBytes && messageBytes.length) ); this.unfilteredReadMessages.push(messageBytes); @@ -422,10 +420,15 @@ export class Http2CallStream extends Duplex implements Call { if (!this.pendingWriteCallback) { throw new Error('Invalid state in write handling code'); } + this.trace( + 'sending data chunk of length ' + + this.pendingWrite.length + + ' (deferred)' + ); stream.write(this.pendingWrite, this.pendingWriteCallback); } if (this.pendingFinalCallback) { - this.trace('calling end() on HTTP/2 stream'); + this.trace('calling end() on HTTP/2 stream (deferred)'); stream.end(this.pendingFinalCallback); } } @@ -514,9 +517,13 @@ export class Http2CallStream extends Duplex implements Call { this.trace('write() called with message of length ' + chunk.message.length); this.filterStack.sendMessage(Promise.resolve(chunk)).then(message => { if (this.http2Stream === null) { + this.trace( + 'deferring writing data chunk of length ' + message.message.length + ); this.pendingWrite = message.message; this.pendingWriteCallback = cb; } else { + this.trace('sending data chunk of length ' + message.message.length); this.http2Stream.write(message.message, cb); } }, this.handleFilterError.bind(this)); @@ -525,6 +532,7 @@ export class Http2CallStream extends Duplex implements Call { _final(cb: Function) { this.trace('end() called'); if (this.http2Stream === null) { + this.trace('deferring calling end() on HTTP/2 stream'); this.pendingFinalCallback = cb; } else { this.trace('calling end() on HTTP/2 stream'); From f0e19f1d0d5adef73660bfd840509c5c6eaa0d47 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Feb 2020 10:12:33 -0800 Subject: [PATCH 0921/1899] grpc-js: Different handling for errors when starting streams --- packages/grpc-js/src/channel.ts | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6cf987cb9..96c1dda72 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -142,7 +142,9 @@ export class ChannelImplementation implements Channel { ) { /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ - this.subchannelPool = getSubchannelPool((options['grpc.use_local_subchannel_pool'] ?? 0) === 0); + this.subchannelPool = getSubchannelPool( + (options['grpc.use_local_subchannel_pool'] ?? 0) === 0 + ); const channelControlHelper: ChannelControlHelper = { createSubchannel: ( subchannelAddress: string, @@ -234,16 +236,25 @@ export class ChannelImplementation implements Channel { callStream ); } catch (error) { - callStream.cancelWithStatus( - Status.UNAVAILABLE, - 'Failed to start call on picked subchannel' - ); + /* An error here indicates thaat something when wrong with + * the picked subchannel's http2 stream right before we + * tried to start the stream. We are handling a promise + * result here, so this asynchronous with respect to the + * original tryPick call, so calling it again is not + * recursive. We call tryPick immediately instead of + * queueing this pick again because handling the queue is + * triggered by state changes, and we want to immediately + * check if the state has already changed since the + * previous tryPick call. We do this instead of cancelling + * the stream because the correct behavior may be + * re-queueing instead, based on the logic in the rest of + * tryPick */ + this.tryPick(callStream, callMetadata); } } else { - callStream.cancelWithStatus( - Status.UNAVAILABLE, - 'Connection dropped while starting call' - ); + /* The logic for doing this here is the same as in the catch + * block above */ + this.tryPick(callStream, callMetadata); } }, (error: Error & { code: number }) => { From 3bba39178b979288cbe35be7b15dbf9ad35ada4d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Feb 2020 10:18:00 -0800 Subject: [PATCH 0922/1899] Update grpc-js to 0.6.16 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0a4ec9dd3..dfa8d4830 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.15", + "version": "0.6.16", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 07fbfa0ac9b69b37cecfbe1a3f167c556641e944 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Feb 2020 10:41:01 -0800 Subject: [PATCH 0923/1899] Fix comment typos --- packages/grpc-js/src/channel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 96c1dda72..4d4fb5514 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -236,10 +236,10 @@ export class ChannelImplementation implements Channel { callStream ); } catch (error) { - /* An error here indicates thaat something when wrong with + /* An error here indicates that something went wrong with * the picked subchannel's http2 stream right before we * tried to start the stream. We are handling a promise - * result here, so this asynchronous with respect to the + * result here, so this is asynchronous with respect to the * original tryPick call, so calling it again is not * recursive. We call tryPick immediately instead of * queueing this pick again because handling the queue is From fea6f3dd0b1ba0be305e318d6c9e657e0bf51ace Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Feb 2020 15:57:29 -0800 Subject: [PATCH 0924/1899] Add build script and configs for Kokoro MacOS parallel build --- .../artifacts/build_one_artifact_macos.sh | 56 +++++++++++++++++++ .../kokoro/macos/electron_1.0_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.0_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.1_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.1_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.2_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.2_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.3_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.3_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.4_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.4_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.5_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.5_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.6_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.6_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.7_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.7_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_1.8_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_1.8_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_2.0_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_2.0_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_3.0_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_3.0_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_3.1_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_3.1_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_4.1_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_4.1_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_4.2_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_4.2_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_5.0_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_5.0_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_6.0_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_6.0_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_6.1_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_6.1_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_7.0_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_7.0_x64.cfg | 35 ++++++++++++ .../kokoro/macos/electron_7.1_ia32.cfg | 35 ++++++++++++ .../release/kokoro/macos/electron_7.1_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_10_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_10_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_11_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_11_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_12_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_12_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_13_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_13_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_4_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_4_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_5_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_5_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_6_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_6_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_7_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_7_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_8_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_8_x64.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_9_ia32.cfg | 35 ++++++++++++ tools/release/kokoro/macos/node_9_x64.cfg | 35 ++++++++++++ 59 files changed, 2086 insertions(+) create mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh create mode 100644 tools/release/kokoro/macos/electron_1.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.0_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.1_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.1_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.2_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.2_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.3_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.3_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.4_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.4_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.5_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.5_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.6_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.6_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.7_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.7_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_1.8_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_1.8_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_2.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_2.0_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_3.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_3.0_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_3.1_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_3.1_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_4.1_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_4.1_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_4.2_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_4.2_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_5.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_5.0_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_6.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_6.0_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_6.1_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_6.1_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_7.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_7.0_x64.cfg create mode 100644 tools/release/kokoro/macos/electron_7.1_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_7.1_x64.cfg create mode 100644 tools/release/kokoro/macos/node_10_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_10_x64.cfg create mode 100644 tools/release/kokoro/macos/node_11_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_11_x64.cfg create mode 100644 tools/release/kokoro/macos/node_12_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_12_x64.cfg create mode 100644 tools/release/kokoro/macos/node_13_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_13_x64.cfg create mode 100644 tools/release/kokoro/macos/node_4_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_4_x64.cfg create mode 100644 tools/release/kokoro/macos/node_5_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_5_x64.cfg create mode 100644 tools/release/kokoro/macos/node_6_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_6_x64.cfg create mode 100644 tools/release/kokoro/macos/node_7_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_7_x64.cfg create mode 100644 tools/release/kokoro/macos/node_8_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_8_x64.cfg create mode 100644 tools/release/kokoro/macos/node_9_ia32.cfg create mode 100644 tools/release/kokoro/macos/node_9_x64.cfg diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh new file mode 100755 index 000000000..dbfd2a9c7 --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +nvm install 10 +nvm use 10 +npm install -g npm +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + +set -ex +cd $(dirname $0)/../../../../.. +base_dir=$(pwd) + +cd $base_dir/packages/grpc-native-core + +# Install gRPC and its submodules. +git submodule update --init --recursive + +pip install mako +./tools/buildgen/generate_projects.sh + +export JOBS=8 +export ARTIFACTS_OUT=$base_dir/artifacts + +mkdir -p ${ARTIFACTS_OUT} + +rm -rf build || true + +npm update + +case $RUNTIME in + electron) + HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$VERSION --target_arch=$ARCH --disturl=https://atom.io/download/electron + cp -r build/stage/* "${ARTIFACTS_OUT}"/ + ;; + node) + ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH + cp -r build/stage/* "${ARTIFACTS_OUT}"/ + ;; +esac \ No newline at end of file diff --git a/tools/release/kokoro/macos/electron_1.0_ia32.cfg b/tools/release/kokoro/macos/electron_1.0_ia32.cfg new file mode 100644 index 000000000..c14493f15 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.0_x64.cfg b/tools/release/kokoro/macos/electron_1.0_x64.cfg new file mode 100644 index 000000000..de01b329e --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.1_ia32.cfg b/tools/release/kokoro/macos/electron_1.1_ia32.cfg new file mode 100644 index 000000000..71c370c45 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.1_x64.cfg b/tools/release/kokoro/macos/electron_1.1_x64.cfg new file mode 100644 index 000000000..10f9a525f --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.2_ia32.cfg b/tools/release/kokoro/macos/electron_1.2_ia32.cfg new file mode 100644 index 000000000..3c2136b70 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.2_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.2_x64.cfg b/tools/release/kokoro/macos/electron_1.2_x64.cfg new file mode 100644 index 000000000..06f2ce565 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.2_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.3_ia32.cfg b/tools/release/kokoro/macos/electron_1.3_ia32.cfg new file mode 100644 index 000000000..cdaace0d1 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.3_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.3.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.3_x64.cfg b/tools/release/kokoro/macos/electron_1.3_x64.cfg new file mode 100644 index 000000000..59241ec39 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.3_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.3.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.4_ia32.cfg b/tools/release/kokoro/macos/electron_1.4_ia32.cfg new file mode 100644 index 000000000..f4359b6c2 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.4_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.4.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.4_x64.cfg b/tools/release/kokoro/macos/electron_1.4_x64.cfg new file mode 100644 index 000000000..eadc22a24 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.4_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.4.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.5_ia32.cfg b/tools/release/kokoro/macos/electron_1.5_ia32.cfg new file mode 100644 index 000000000..e70c18c0c --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.5_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.5.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.5_x64.cfg b/tools/release/kokoro/macos/electron_1.5_x64.cfg new file mode 100644 index 000000000..d2382a17d --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.5_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.5.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.6_ia32.cfg b/tools/release/kokoro/macos/electron_1.6_ia32.cfg new file mode 100644 index 000000000..f074428fc --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.6_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.6.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.6_x64.cfg b/tools/release/kokoro/macos/electron_1.6_x64.cfg new file mode 100644 index 000000000..0c93e0d75 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.6_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.6.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.7_ia32.cfg b/tools/release/kokoro/macos/electron_1.7_ia32.cfg new file mode 100644 index 000000000..48d53103c --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.7_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.7.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.7_x64.cfg b/tools/release/kokoro/macos/electron_1.7_x64.cfg new file mode 100644 index 000000000..bdef8d3f4 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.7_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.7.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.8_ia32.cfg b/tools/release/kokoro/macos/electron_1.8_ia32.cfg new file mode 100644 index 000000000..a0455a725 --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.8_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.8.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_1.8_x64.cfg b/tools/release/kokoro/macos/electron_1.8_x64.cfg new file mode 100644 index 000000000..94b3a0cfb --- /dev/null +++ b/tools/release/kokoro/macos/electron_1.8_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.8.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_2.0_ia32.cfg b/tools/release/kokoro/macos/electron_2.0_ia32.cfg new file mode 100644 index 000000000..137d8ec27 --- /dev/null +++ b/tools/release/kokoro/macos/electron_2.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "2.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_2.0_x64.cfg b/tools/release/kokoro/macos/electron_2.0_x64.cfg new file mode 100644 index 000000000..f70f742e6 --- /dev/null +++ b/tools/release/kokoro/macos/electron_2.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "2.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_3.0_ia32.cfg b/tools/release/kokoro/macos/electron_3.0_ia32.cfg new file mode 100644 index 000000000..eee4f3035 --- /dev/null +++ b/tools/release/kokoro/macos/electron_3.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "3.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_3.0_x64.cfg b/tools/release/kokoro/macos/electron_3.0_x64.cfg new file mode 100644 index 000000000..52df13a80 --- /dev/null +++ b/tools/release/kokoro/macos/electron_3.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "3.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_3.1_ia32.cfg b/tools/release/kokoro/macos/electron_3.1_ia32.cfg new file mode 100644 index 000000000..12785e3ba --- /dev/null +++ b/tools/release/kokoro/macos/electron_3.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "3.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_3.1_x64.cfg b/tools/release/kokoro/macos/electron_3.1_x64.cfg new file mode 100644 index 000000000..02d1a8d3b --- /dev/null +++ b/tools/release/kokoro/macos/electron_3.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "3.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_4.1_ia32.cfg b/tools/release/kokoro/macos/electron_4.1_ia32.cfg new file mode 100644 index 000000000..33cf881ec --- /dev/null +++ b/tools/release/kokoro/macos/electron_4.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_4.1_x64.cfg b/tools/release/kokoro/macos/electron_4.1_x64.cfg new file mode 100644 index 000000000..5553bce74 --- /dev/null +++ b/tools/release/kokoro/macos/electron_4.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_4.2_ia32.cfg b/tools/release/kokoro/macos/electron_4.2_ia32.cfg new file mode 100644 index 000000000..41746c211 --- /dev/null +++ b/tools/release/kokoro/macos/electron_4.2_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_4.2_x64.cfg b/tools/release/kokoro/macos/electron_4.2_x64.cfg new file mode 100644 index 000000000..b6cf5a700 --- /dev/null +++ b/tools/release/kokoro/macos/electron_4.2_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_5.0_ia32.cfg b/tools/release/kokoro/macos/electron_5.0_ia32.cfg new file mode 100644 index 000000000..e59cf6a6f --- /dev/null +++ b/tools/release/kokoro/macos/electron_5.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_5.0_x64.cfg b/tools/release/kokoro/macos/electron_5.0_x64.cfg new file mode 100644 index 000000000..47de1345c --- /dev/null +++ b/tools/release/kokoro/macos/electron_5.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_6.0_ia32.cfg b/tools/release/kokoro/macos/electron_6.0_ia32.cfg new file mode 100644 index 000000000..10ca9f5ee --- /dev/null +++ b/tools/release/kokoro/macos/electron_6.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_6.0_x64.cfg b/tools/release/kokoro/macos/electron_6.0_x64.cfg new file mode 100644 index 000000000..312c27d96 --- /dev/null +++ b/tools/release/kokoro/macos/electron_6.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_6.1_ia32.cfg b/tools/release/kokoro/macos/electron_6.1_ia32.cfg new file mode 100644 index 000000000..45ed07c5e --- /dev/null +++ b/tools/release/kokoro/macos/electron_6.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_6.1_x64.cfg b/tools/release/kokoro/macos/electron_6.1_x64.cfg new file mode 100644 index 000000000..e5167655a --- /dev/null +++ b/tools/release/kokoro/macos/electron_6.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_7.0_ia32.cfg b/tools/release/kokoro/macos/electron_7.0_ia32.cfg new file mode 100644 index 000000000..5824649ef --- /dev/null +++ b/tools/release/kokoro/macos/electron_7.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_7.0_x64.cfg b/tools/release/kokoro/macos/electron_7.0_x64.cfg new file mode 100644 index 000000000..38688281b --- /dev/null +++ b/tools/release/kokoro/macos/electron_7.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_7.1_ia32.cfg b/tools/release/kokoro/macos/electron_7.1_ia32.cfg new file mode 100644 index 000000000..4a81c57e7 --- /dev/null +++ b/tools/release/kokoro/macos/electron_7.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_7.1_x64.cfg b/tools/release/kokoro/macos/electron_7.1_x64.cfg new file mode 100644 index 000000000..a8671b176 --- /dev/null +++ b/tools/release/kokoro/macos/electron_7.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_10_ia32.cfg b/tools/release/kokoro/macos/node_10_ia32.cfg new file mode 100644 index 000000000..fd1102df5 --- /dev/null +++ b/tools/release/kokoro/macos/node_10_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_10_x64.cfg b/tools/release/kokoro/macos/node_10_x64.cfg new file mode 100644 index 000000000..ca306e127 --- /dev/null +++ b/tools/release/kokoro/macos/node_10_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_11_ia32.cfg b/tools/release/kokoro/macos/node_11_ia32.cfg new file mode 100644 index 000000000..ecd4f3d03 --- /dev/null +++ b/tools/release/kokoro/macos/node_11_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_11_x64.cfg b/tools/release/kokoro/macos/node_11_x64.cfg new file mode 100644 index 000000000..805423116 --- /dev/null +++ b/tools/release/kokoro/macos/node_11_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_12_ia32.cfg b/tools/release/kokoro/macos/node_12_ia32.cfg new file mode 100644 index 000000000..7bf3a9a39 --- /dev/null +++ b/tools/release/kokoro/macos/node_12_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_12_x64.cfg b/tools/release/kokoro/macos/node_12_x64.cfg new file mode 100644 index 000000000..a4d7c8d01 --- /dev/null +++ b/tools/release/kokoro/macos/node_12_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_13_ia32.cfg b/tools/release/kokoro/macos/node_13_ia32.cfg new file mode 100644 index 000000000..7fe3a4ea5 --- /dev/null +++ b/tools/release/kokoro/macos/node_13_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_13_x64.cfg b/tools/release/kokoro/macos/node_13_x64.cfg new file mode 100644 index 000000000..156eb6cf5 --- /dev/null +++ b/tools/release/kokoro/macos/node_13_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_4_ia32.cfg b/tools/release/kokoro/macos/node_4_ia32.cfg new file mode 100644 index 000000000..1411ea929 --- /dev/null +++ b/tools/release/kokoro/macos/node_4_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_4_x64.cfg b/tools/release/kokoro/macos/node_4_x64.cfg new file mode 100644 index 000000000..8a330ce5c --- /dev/null +++ b/tools/release/kokoro/macos/node_4_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_5_ia32.cfg b/tools/release/kokoro/macos/node_5_ia32.cfg new file mode 100644 index 000000000..f99f3b69e --- /dev/null +++ b/tools/release/kokoro/macos/node_5_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_5_x64.cfg b/tools/release/kokoro/macos/node_5_x64.cfg new file mode 100644 index 000000000..f1436c2f2 --- /dev/null +++ b/tools/release/kokoro/macos/node_5_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_6_ia32.cfg b/tools/release/kokoro/macos/node_6_ia32.cfg new file mode 100644 index 000000000..2381480d0 --- /dev/null +++ b/tools/release/kokoro/macos/node_6_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_6_x64.cfg b/tools/release/kokoro/macos/node_6_x64.cfg new file mode 100644 index 000000000..10b657ee2 --- /dev/null +++ b/tools/release/kokoro/macos/node_6_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_7_ia32.cfg b/tools/release/kokoro/macos/node_7_ia32.cfg new file mode 100644 index 000000000..9841a4a2a --- /dev/null +++ b/tools/release/kokoro/macos/node_7_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_7_x64.cfg b/tools/release/kokoro/macos/node_7_x64.cfg new file mode 100644 index 000000000..a46516bb9 --- /dev/null +++ b/tools/release/kokoro/macos/node_7_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_8_ia32.cfg b/tools/release/kokoro/macos/node_8_ia32.cfg new file mode 100644 index 000000000..4c6f268c0 --- /dev/null +++ b/tools/release/kokoro/macos/node_8_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_8_x64.cfg b/tools/release/kokoro/macos/node_8_x64.cfg new file mode 100644 index 000000000..2034ac8dc --- /dev/null +++ b/tools/release/kokoro/macos/node_8_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_9_ia32.cfg b/tools/release/kokoro/macos/node_9_ia32.cfg new file mode 100644 index 000000000..f51cf728a --- /dev/null +++ b/tools/release/kokoro/macos/node_9_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/node_9_x64.cfg b/tools/release/kokoro/macos/node_9_x64.cfg new file mode 100644 index 000000000..083e1ee85 --- /dev/null +++ b/tools/release/kokoro/macos/node_9_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} From 8d4e334b64c5f70bd904504a6674af0ec1e7529f Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 4 Feb 2020 16:24:34 -0800 Subject: [PATCH 0925/1899] Apparently I need a config for the root job --- tools/release/kokoro/macos.cfg | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tools/release/kokoro/macos.cfg diff --git a/tools/release/kokoro/macos.cfg b/tools/release/kokoro/macos.cfg new file mode 100644 index 000000000..ff22f270f --- /dev/null +++ b/tools/release/kokoro/macos.cfg @@ -0,0 +1,15 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) From d643d105f64645819328566ba9416624a57ddb27 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 5 Feb 2020 09:03:16 -0800 Subject: [PATCH 0926/1899] Adding a build_file field, as this seems necessary --- tools/release/kokoro/macos.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/release/kokoro/macos.cfg b/tools/release/kokoro/macos.cfg index ff22f270f..b52902e56 100644 --- a/tools/release/kokoro/macos.cfg +++ b/tools/release/kokoro/macos.cfg @@ -13,3 +13,5 @@ # limitations under the License. # Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh" From d6ed6facc57b40df2733e3709a1a21e113ca69b6 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Wed, 5 Feb 2020 09:04:35 -0800 Subject: [PATCH 0927/1899] Create workflow.sh --- .../tools/run_tests/artifacts/workflow.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh b/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh new file mode 100644 index 000000000..20c5ec54f --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh @@ -0,0 +1,14 @@ +#!/bin/sh +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. From 7bdc92d8d4da831a7f7b379334774771fee15c1a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 5 Feb 2020 11:34:25 -0800 Subject: [PATCH 0928/1899] Properly handle socket from proxy --- packages/grpc-js/src/subchannel.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 66d14621c..24d7eea7e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -277,9 +277,6 @@ export class Subchannel { private createSession(socket?: net.Socket) { let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; - if (socket) { - connectionOptions.socket = socket; - } let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { addressScheme = 'https://'; @@ -300,15 +297,22 @@ export class Subchannel { } else { connectionOptions.servername = getDefaultAuthority(this.channelTarget); } + if (socket) { + connectionOptions.socket = socket; + } } else { /* In all but the most recent versions of Node, http2.connect does not use * the options when establishing plaintext connections, so we need to * establish that connection explicitly. */ connectionOptions.createConnection = (authority, option) => { - /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ - return net.connect(this.subchannelAddress as net.NetConnectOpts); + if (socket) { + return socket; + } else { + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(this.subchannelAddress); + } }; } connectionOptions = Object.assign( From e4307b44129fb68ac7561fcbc4ef2abd9b60582e Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Thu, 6 Feb 2020 13:08:12 -0800 Subject: [PATCH 0929/1899] Removing unnecessary files. --- tools/release/kokoro/macos.cfg | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 tools/release/kokoro/macos.cfg diff --git a/tools/release/kokoro/macos.cfg b/tools/release/kokoro/macos.cfg deleted file mode 100644 index b52902e56..000000000 --- a/tools/release/kokoro/macos.cfg +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh" From 8a84b3ef8d141c168a2f59b72c6524578a94bd50 Mon Sep 17 00:00:00 2001 From: Nicolas Noble Date: Thu, 6 Feb 2020 13:08:47 -0800 Subject: [PATCH 0930/1899] Delete workflow.sh --- .../tools/run_tests/artifacts/workflow.sh | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh b/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh deleted file mode 100644 index 20c5ec54f..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/workflow.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. From 901438a4d7265a4daba75cc3599c8b0a702f21cf Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Feb 2020 13:01:31 -0800 Subject: [PATCH 0931/1899] Add fan-out configs and scripts for windows and linux --- .../tools/buildgen/gen_build_yaml.py | 115 ++++++++++++++++++ .../tools/buildgen/generate_projects.sh | 11 +- .../artifacts/build_all_linux_artifacts.sh | 5 +- .../artifacts/build_one_artifact.bat | 63 ++++++++++ .../artifacts/build_one_artifact_in_docker.sh | 54 ++++++++ .../artifacts/build_one_artifact_linux.sh | 54 ++++++++ .../artifacts/build_one_artifact_macos.sh | 12 +- .../grpc-native-core}/binding.gyp.template | 0 .../grpc-native-core}/package.json.template | 0 templates/tools/release/kokoro/linux.template | 48 ++++++++ templates/tools/release/kokoro/macos.template | 44 +++++++ .../tools/release/kokoro/windows.template | 44 +++++++ .../release/alpine}/Dockerfile | 0 .../kokoro/linux/electron_1.0_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.0_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.1_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.1_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.2_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.2_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.3_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.3_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.4_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.4_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.5_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.5_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.6_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.6_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.7_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.7_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.8_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_1.8_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_2.0_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_2.0_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_3.0_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_3.0_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_3.1_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_3.1_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_4.1_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_4.1_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_4.2_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_4.2_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_5.0_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_5.0_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_6.0_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_6.0_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_6.1_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_6.1_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_7.0_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_7.0_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_7.1_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/electron_7.1_x64_glibc.cfg | 39 ++++++ .../kokoro/linux/node_10_arm64_glibc.cfg | 39 ++++++ .../kokoro/linux/node_10_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_10_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_10_s390x_glibc.cfg | 39 ++++++ .../kokoro/linux/node_10_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_10_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_11_arm64_glibc.cfg | 39 ++++++ .../kokoro/linux/node_11_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_11_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_11_s390x_glibc.cfg | 39 ++++++ .../kokoro/linux/node_11_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_11_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_12_arm64_glibc.cfg | 39 ++++++ .../kokoro/linux/node_12_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_12_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_12_s390x_glibc.cfg | 39 ++++++ .../kokoro/linux/node_12_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_12_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_13_arm64_glibc.cfg | 39 ++++++ .../kokoro/linux/node_13_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_13_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_13_s390x_glibc.cfg | 39 ++++++ .../kokoro/linux/node_13_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_13_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_4_arm64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_4_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_4_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_4_s390x_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_4_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_4_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_5_arm64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_5_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_5_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_5_s390x_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_5_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_5_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_6_arm64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_6_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_6_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_6_s390x_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_6_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_6_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_7_arm64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_7_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_7_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_7_s390x_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_7_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_7_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_8_arm64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_8_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_8_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_8_s390x_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_8_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_8_x64_musl.cfg | 39 ++++++ .../kokoro/linux/node_9_arm64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_9_arm_glibc.cfg | 39 ++++++ .../kokoro/linux/node_9_ia32_glibc.cfg | 39 ++++++ .../kokoro/linux/node_9_s390x_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_9_x64_glibc.cfg | 39 ++++++ .../release/kokoro/linux/node_9_x64_musl.cfg | 39 ++++++ .../kokoro/windows/electron_1.0_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.0_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.1_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.1_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.2_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.2_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.3_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.3_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.4_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.4_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.5_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.5_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.6_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.6_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.7_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.7_x64.cfg | 35 ++++++ .../kokoro/windows/electron_1.8_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_1.8_x64.cfg | 35 ++++++ .../kokoro/windows/electron_2.0_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_2.0_x64.cfg | 35 ++++++ .../kokoro/windows/electron_3.0_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_3.0_x64.cfg | 35 ++++++ .../kokoro/windows/electron_3.1_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_3.1_x64.cfg | 35 ++++++ .../kokoro/windows/electron_4.1_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_4.1_x64.cfg | 35 ++++++ .../kokoro/windows/electron_4.2_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_4.2_x64.cfg | 35 ++++++ .../kokoro/windows/electron_5.0_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_5.0_x64.cfg | 35 ++++++ .../kokoro/windows/electron_6.0_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_6.0_x64.cfg | 35 ++++++ .../kokoro/windows/electron_6.1_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_6.1_x64.cfg | 35 ++++++ .../kokoro/windows/electron_7.0_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_7.0_x64.cfg | 35 ++++++ .../kokoro/windows/electron_7.1_ia32.cfg | 35 ++++++ .../kokoro/windows/electron_7.1_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_10_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_10_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_11_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_11_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_12_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_12_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_13_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_13_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_4_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_4_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_5_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_5_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_6_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_6_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_7_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_7_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_8_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_8_x64.cfg | 35 ++++++ tools/release/kokoro/windows/node_9_ia32.cfg | 35 ++++++ tools/release/kokoro/windows/node_9_x64.cfg | 35 ++++++ 169 files changed, 6292 insertions(+), 10 deletions(-) create mode 100644 packages/grpc-native-core/tools/buildgen/gen_build_yaml.py create mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat create mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh create mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh rename {packages/grpc-native-core/templates => templates/packages/grpc-native-core}/binding.gyp.template (100%) rename {packages/grpc-native-core/templates => templates/packages/grpc-native-core}/package.json.template (100%) create mode 100644 templates/tools/release/kokoro/linux.template create mode 100644 templates/tools/release/kokoro/macos.template create mode 100644 templates/tools/release/kokoro/windows.template rename {packages/grpc-native-core/tools/docker/alpine_artifact => tools/release/alpine}/Dockerfile (100%) create mode 100644 tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_10_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_10_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_10_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_10_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_10_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_10_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_11_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_11_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_11_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_11_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_11_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_11_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_12_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_12_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_12_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_12_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_12_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_12_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_13_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_13_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_13_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_13_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_13_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_13_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_4_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_4_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_4_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_4_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_4_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_4_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_5_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_5_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_5_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_5_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_5_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_5_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_6_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_6_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_6_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_6_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_6_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_6_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_7_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_7_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_7_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_7_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_7_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_7_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_8_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_8_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_8_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_8_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_8_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_8_x64_musl.cfg create mode 100644 tools/release/kokoro/linux/node_9_arm64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_9_arm_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_9_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_9_s390x_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_9_x64_glibc.cfg create mode 100644 tools/release/kokoro/linux/node_9_x64_musl.cfg create mode 100644 tools/release/kokoro/windows/electron_1.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.1_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.1_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.2_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.2_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.3_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.3_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.4_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.4_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.5_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.5_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.6_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.6_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.7_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.7_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_1.8_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_1.8_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_2.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_2.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_3.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_3.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_3.1_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_3.1_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_4.1_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_4.1_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_4.2_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_4.2_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_5.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_5.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_6.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_6.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_6.1_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_6.1_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_7.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_7.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_7.1_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_7.1_x64.cfg create mode 100644 tools/release/kokoro/windows/node_10_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_10_x64.cfg create mode 100644 tools/release/kokoro/windows/node_11_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_11_x64.cfg create mode 100644 tools/release/kokoro/windows/node_12_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_12_x64.cfg create mode 100644 tools/release/kokoro/windows/node_13_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_13_x64.cfg create mode 100644 tools/release/kokoro/windows/node_4_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_4_x64.cfg create mode 100644 tools/release/kokoro/windows/node_5_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_5_x64.cfg create mode 100644 tools/release/kokoro/windows/node_6_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_6_x64.cfg create mode 100644 tools/release/kokoro/windows/node_7_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_7_x64.cfg create mode 100644 tools/release/kokoro/windows/node_8_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_8_x64.cfg create mode 100644 tools/release/kokoro/windows/node_9_ia32.cfg create mode 100644 tools/release/kokoro/windows/node_9_x64.cfg diff --git a/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py b/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py new file mode 100644 index 000000000..998e48f8f --- /dev/null +++ b/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python2.7 + +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from __future__ import print_function +import re +import os +import sys +import yaml + +node_versions = ["4", "5", "6", "7", "8", "9", "10", "11", "12", "13"] +electron_versions = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "2.0", "3.0", "3.1", "4.1", "4.2", "5.0", "6.0", "6.1", "7.0", "7.1"] + +def gen_linux_configs(): + configs = [] + + node_arches = ["ia32", "x64", "arm", "arm64", "s390x"] + electron_arches = ["ia32", "x64"] + alpine_arches = ["x64"] + + for version in node_versions: + for arch in node_arches: + configs.append({ + "name": "node_{version}_{arch}_glibc".format(version=version, arch=arch), + "runtime": "node", + "version": version, + "arch": arch, + "libc": "glibc" + }) + for arch in alpine_arches: + configs.append({ + "name": "node_{version}_{arch}_musl".format(version=version, arch=arch), + "runtime": "node", + "version": version, + "arch": arch, + "libc": "glibc" + }) + for version in electron_versions: + for arch in electron_arches: + configs.append({ + "name": "electron_{version}_{arch}_glibc".format(version=version, arch=arch), + "runtime": "electron", + "version": version, + "arch": arch, + "libc": "glibc" + }) + return configs + +def gen_mac_configs(): + configs = [] + + node_arches = ["ia32", "x64"] + electron_arches = ["ia32", "x64"] + + for version in node_versions: + for arch in node_arches: + configs.append({ + "name": "node_{version}_{arch}".format(version=version, arch=arch), + "runtime": "node", + "version": version, + "arch": arch + }) + for version in electron_versions: + for arch in electron_arches: + configs.append({ + "name": "electron_{version}_{arch}".format(version=version, arch=arch), + "runtime": "electron", + "version": version, + "arch": arch + }) + return configs + +def gen_windows_configs(): + configs = [] + + node_arches = ["ia32", "x64"] + electron_arches = ["ia32", "x64"] + + for version in node_versions: + for arch in node_arches: + configs.append({ + "name": "node_{version}_{arch}".format(version=version, arch=arch), + "runtime": "node", + "version": version, + "arch": arch + }) + for version in electron_versions: + for arch in electron_arches: + configs.append({ + "name": "electron_{version}_{arch}".format(version=version, arch=arch), + "runtime": "electron", + "version": version, + "arch": arch + }) + return configs + +out = { + "linux_configs": gen_linux_configs(), + "mac_configs": gen_mac_configs(), + "windows_configs": gen_windows_configs() +} + +print(yaml.dump(out)) \ No newline at end of file diff --git a/packages/grpc-native-core/tools/buildgen/generate_projects.sh b/packages/grpc-native-core/tools/buildgen/generate_projects.sh index d68c467f1..6575996a7 100755 --- a/packages/grpc-native-core/tools/buildgen/generate_projects.sh +++ b/packages/grpc-native-core/tools/buildgen/generate_projects.sh @@ -16,6 +16,11 @@ set -e -cd `dirname $0`/../.. -root=`pwd` -./deps/grpc/tools/buildgen/generate_projects.sh $root/build.yaml --base=$root --templates `find templates -type f` +cd $(dirname $0)/../../../.. +root=$(pwd) +native_root=$root/packages/grpc-native-core + +output_file=$(mktemp /tmp/genXXXXXX) +python $(dirname $0)/gen_build_yaml.py > $output_file + +./packages/grpc-native-core/deps/grpc/tools/buildgen/generate_projects.sh $native_root/build.yaml $output_file --base=$root --templates $(find templates -type f) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh index 1700f393f..d2c06fc45 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh @@ -51,6 +51,9 @@ cd $(dirname $0) tool_dir=$(pwd) cd $tool_dir/../../.. base_dir=$(pwd) +cd $base_dir/../.. +root_dir=$(pwd) +cd $base_dir export ARTIFACTS_OUT=$base_dir/artifacts export JOBS=8 @@ -72,6 +75,6 @@ if [ "$DO_CROSS" = "true" ] ; then $tool_dir/build_artifact_node_arm.sh $tool_dir/build_artifact_node_s390x.sh - docker build -t alpine_node_artifact $base_dir/tools/docker/alpine_artifact + docker build -t alpine_node_artifact $root_dir/tools/release/alpine docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine fi diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat new file mode 100644 index 000000000..0a91e5a33 --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat @@ -0,0 +1,63 @@ +@rem Copyright 2016 gRPC authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem http://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. + +@echo "Starting Windows build" + +powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" + +call nvm install 10 +call nvm use 10 + +call npm install -g npm@6.10.x +@rem https://github.com/mapbox/node-pre-gyp/issues/362 +call npm install -g node-gyp@3 + +cd /d %~dp0 +cd ..\..\..\..\.. + +git submodule update --init --recursive + +set ARTIFACTS_OUT=%cd%\artifacts + +cd packages\grpc-native-core + +set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm + +set JOBS=8 + +del /f /q BUILD || rmdir build /s /q + +call npm update || goto :error + +if "%RUNTIME%"=="electron" ( + set "HOME=%USERPROFILE%\electron-gyp" + set "npm_config_disturl=https://atom.io/download/electron" +) + +call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%%a && goto :EOF +@rem Try again after removing openssl headers +rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q +rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q +rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\%%v\include\node\openssl" /S /Q +rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q +call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error + +xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error + +if %errorlevel% neq 0 exit /b %errorlevel% + +goto :EOF + +:error +exit /b 1 \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh new file mode 100644 index 000000000..b8408dc85 --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" + +nvm install 10 +nvm use 10 +npm install -g npm +# https://github.com/mapbox/node-pre-gyp/issues/362 +npm install -g node-gyp + +# $ARCH should only have one of these values if the script is being called in +# an environment with these cross compiler packages installed +case $ARCH in + arm) + export CC=arm-linux-gnueabihf-gcc + export CXX=arm-linux-gnueabihf-g++ + export CXX=arm-linux-gnueabihf-g++ + ;; + arm64) + export CC=aarch64-linux-gnu-gcc + export CXX=aarch64-linux-gnu-g++ + export LD=aarch64-linux-gnu-g++ + ;; + s390x) + export CC=s390x-linux-gnu-gcc + export CXX=s390x-linux-gnu-g++ + export LD=s390x-linux-gnu-g++ + ;; +esac + +case $RUNTIME in + electron) + export HOME=~/.electron-gyp + export npm_config_disturl=https://atom.io/download/electron + ;; +esac + +./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$VERSION --target_arch=$ARCH --runtime=$RUNTIME --target_libc=$LIBC +cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh new file mode 100644 index 000000000..3adf9ba10 --- /dev/null +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Expected environment variables: +# VERSION: the node version to build for +# ARCH: the processor architecture to build for +# RUNTIME: node or electron +# LIBC: the libc to build for, glibc or musl + +set -ex +cd $(dirname $0)/../../../../.. +base_dir=$(pwd) + +export ARTIFACTS_OUT=$base_dir/artifacts + +mkdir -p $ARTIFACTS_OUT + +cd $base_dir/packages/grpc-native-core + +# Install gRPC and its submodules. +git submodule update --init --recursive + +pip install mako +./tools/buildgen/generate_projects.sh + +case $ARCH in + arm|arm64|s390x) + docker build -t artifact-image $base_dir/tools/release/cross + ;; + *) + case $LIBC in + musl) + docker build -t artifact-image $base_dir/tools/release/alpine_artifact + ;; + *) + docker build -t artifact-image $base_dir/tools/release/native + ;; + esac + ;; +esac + +docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir -e ARCH -e VERSION -e RUNTIME -e LIBC -e ARTIFACTS_OUT artifact-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh index dbfd2a9c7..1b2fa40e8 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh @@ -46,11 +46,11 @@ npm update case $RUNTIME in electron) - HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$VERSION --target_arch=$ARCH --disturl=https://atom.io/download/electron - cp -r build/stage/* "${ARTIFACTS_OUT}"/ + export HOME=~/.electron-gyp + export npm_config_disturl=https://atom.io/download/electron ;; node) - ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH - cp -r build/stage/* "${ARTIFACTS_OUT}"/ - ;; -esac \ No newline at end of file +esac + +./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$VERSION --target_arch=$ARCH +cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file diff --git a/packages/grpc-native-core/templates/binding.gyp.template b/templates/packages/grpc-native-core/binding.gyp.template similarity index 100% rename from packages/grpc-native-core/templates/binding.gyp.template rename to templates/packages/grpc-native-core/binding.gyp.template diff --git a/packages/grpc-native-core/templates/package.json.template b/templates/packages/grpc-native-core/package.json.template similarity index 100% rename from packages/grpc-native-core/templates/package.json.template rename to templates/packages/grpc-native-core/package.json.template diff --git a/templates/tools/release/kokoro/linux.template b/templates/tools/release/kokoro/linux.template new file mode 100644 index 000000000..a1cf84c8c --- /dev/null +++ b/templates/tools/release/kokoro/linux.template @@ -0,0 +1,48 @@ +%YAML 1.2 +--- +foreach: linux_configs +output_name: ${selected.name}.cfg +template: | + # Copyright 2020 gRPC authors. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + # Config file for Kokoro (in protobuf text format) + + build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" + env_vars { + key: "RUNTIME" + value: "${selected.runtime}" + } + env_vars { + key: "ARCH" + value: "${selected.arch}" + } + env_vars { + key: "VERSION" + %if selected.runtime == "node": + value: "${selected.version}.0.0" + %else: + value: "${selected.version}.0" + %endif + } + env_vars { + key: "LIBC" + value: "${selected.libc}" + } + action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } + } diff --git a/templates/tools/release/kokoro/macos.template b/templates/tools/release/kokoro/macos.template new file mode 100644 index 000000000..67c0c7ff7 --- /dev/null +++ b/templates/tools/release/kokoro/macos.template @@ -0,0 +1,44 @@ +%YAML 1.2 +--- +foreach: mac_configs +output_name: ${selected.name}.cfg +template: | + # Copyright 2020 gRPC authors. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + # Config file for Kokoro (in protobuf text format) + + build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" + env_vars { + key: "RUNTIME" + value: "${selected.runtime}" + } + env_vars { + key: "ARCH" + value: "${selected.arch}" + } + env_vars { + key: "VERSION" + %if selected.runtime == "node": + value: "${selected.version}.0.0" + %else: + value: "${selected.version}.0" + %endif + } + action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } + } diff --git a/templates/tools/release/kokoro/windows.template b/templates/tools/release/kokoro/windows.template new file mode 100644 index 000000000..a19dcfa1e --- /dev/null +++ b/templates/tools/release/kokoro/windows.template @@ -0,0 +1,44 @@ +%YAML 1.2 +--- +foreach: mac_configs +output_name: ${selected.name}.cfg +template: | + # Copyright 2020 gRPC authors. + # + # Licensed under the Apache License, Version 2.0 (the "License"); + # you may not use this file except in compliance with the License. + # You may obtain a copy of the License at + # + # http://www.apache.org/licenses/LICENSE-2.0 + # + # Unless required by applicable law or agreed to in writing, software + # distributed under the License is distributed on an "AS IS" BASIS, + # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + # See the License for the specific language governing permissions and + # limitations under the License. + + # Config file for Kokoro (in protobuf text format) + + build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" + env_vars { + key: "RUNTIME" + value: "${selected.runtime}" + } + env_vars { + key: "ARCH" + value: "${selected.arch}" + } + env_vars { + key: "VERSION" + %if selected.runtime == "node": + value: "${selected.version}.0.0" + %else: + value: "${selected.version}.0" + %endif + } + action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } + } diff --git a/packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile b/tools/release/alpine/Dockerfile similarity index 100% rename from packages/grpc-native-core/tools/docker/alpine_artifact/Dockerfile rename to tools/release/alpine/Dockerfile diff --git a/tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg new file mode 100644 index 000000000..a68b80ce8 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg new file mode 100644 index 000000000..e5a574ee0 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg new file mode 100644 index 000000000..cac5806c9 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg new file mode 100644 index 000000000..bd7d3a780 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg new file mode 100644 index 000000000..1f3dfacd8 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.2.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg new file mode 100644 index 000000000..950421e4c --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.2.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg new file mode 100644 index 000000000..132f9ce91 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.3.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg new file mode 100644 index 000000000..713d78e3d --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.3.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg new file mode 100644 index 000000000..119a8a6ae --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.4.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg new file mode 100644 index 000000000..35e6575b4 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.4.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg new file mode 100644 index 000000000..2d54d45f8 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.5.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg new file mode 100644 index 000000000..4a78562b2 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.5.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg new file mode 100644 index 000000000..5f66d51e6 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.6.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg new file mode 100644 index 000000000..8660c3fc4 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.6.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg new file mode 100644 index 000000000..c73fb0e88 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.7.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg new file mode 100644 index 000000000..bcc6f4605 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.7.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg new file mode 100644 index 000000000..fd2f2e4d7 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.8.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg new file mode 100644 index 000000000..c4c8eaf52 --- /dev/null +++ b/tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.8.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg new file mode 100644 index 000000000..fb080a0ca --- /dev/null +++ b/tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "2.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg new file mode 100644 index 000000000..8665b79b6 --- /dev/null +++ b/tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "2.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg new file mode 100644 index 000000000..cc5c02d82 --- /dev/null +++ b/tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "3.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg new file mode 100644 index 000000000..537fd3c23 --- /dev/null +++ b/tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "3.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg new file mode 100644 index 000000000..a5ccfb84a --- /dev/null +++ b/tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "3.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg new file mode 100644 index 000000000..aad9b9055 --- /dev/null +++ b/tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "3.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg new file mode 100644 index 000000000..48b8d57d8 --- /dev/null +++ b/tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg new file mode 100644 index 000000000..83a77d5bd --- /dev/null +++ b/tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg new file mode 100644 index 000000000..17b1a4341 --- /dev/null +++ b/tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.2.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg b/tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg new file mode 100644 index 000000000..955c5721e --- /dev/null +++ b/tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.2.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg new file mode 100644 index 000000000..91fbd4a4f --- /dev/null +++ b/tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg new file mode 100644 index 000000000..028389ca7 --- /dev/null +++ b/tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg new file mode 100644 index 000000000..67d6816b8 --- /dev/null +++ b/tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg new file mode 100644 index 000000000..fc9bc06a3 --- /dev/null +++ b/tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg new file mode 100644 index 000000000..8d553f8d7 --- /dev/null +++ b/tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg new file mode 100644 index 000000000..64efd8896 --- /dev/null +++ b/tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg new file mode 100644 index 000000000..b02bc4940 --- /dev/null +++ b/tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg new file mode 100644 index 000000000..0900ddce8 --- /dev/null +++ b/tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg new file mode 100644 index 000000000..15dcb3bd2 --- /dev/null +++ b/tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg new file mode 100644 index 000000000..bc392b71f --- /dev/null +++ b/tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.1.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_10_arm64_glibc.cfg b/tools/release/kokoro/linux/node_10_arm64_glibc.cfg new file mode 100644 index 000000000..da090fff1 --- /dev/null +++ b/tools/release/kokoro/linux/node_10_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_10_arm_glibc.cfg b/tools/release/kokoro/linux/node_10_arm_glibc.cfg new file mode 100644 index 000000000..cc6ad4787 --- /dev/null +++ b/tools/release/kokoro/linux/node_10_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_10_ia32_glibc.cfg b/tools/release/kokoro/linux/node_10_ia32_glibc.cfg new file mode 100644 index 000000000..f7ee19047 --- /dev/null +++ b/tools/release/kokoro/linux/node_10_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_10_s390x_glibc.cfg b/tools/release/kokoro/linux/node_10_s390x_glibc.cfg new file mode 100644 index 000000000..60935df16 --- /dev/null +++ b/tools/release/kokoro/linux/node_10_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_10_x64_glibc.cfg b/tools/release/kokoro/linux/node_10_x64_glibc.cfg new file mode 100644 index 000000000..0572524db --- /dev/null +++ b/tools/release/kokoro/linux/node_10_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_10_x64_musl.cfg b/tools/release/kokoro/linux/node_10_x64_musl.cfg new file mode 100644 index 000000000..0572524db --- /dev/null +++ b/tools/release/kokoro/linux/node_10_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_11_arm64_glibc.cfg b/tools/release/kokoro/linux/node_11_arm64_glibc.cfg new file mode 100644 index 000000000..1a633206d --- /dev/null +++ b/tools/release/kokoro/linux/node_11_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_11_arm_glibc.cfg b/tools/release/kokoro/linux/node_11_arm_glibc.cfg new file mode 100644 index 000000000..2f9af1df7 --- /dev/null +++ b/tools/release/kokoro/linux/node_11_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_11_ia32_glibc.cfg b/tools/release/kokoro/linux/node_11_ia32_glibc.cfg new file mode 100644 index 000000000..94613203b --- /dev/null +++ b/tools/release/kokoro/linux/node_11_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_11_s390x_glibc.cfg b/tools/release/kokoro/linux/node_11_s390x_glibc.cfg new file mode 100644 index 000000000..f17a793f1 --- /dev/null +++ b/tools/release/kokoro/linux/node_11_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_11_x64_glibc.cfg b/tools/release/kokoro/linux/node_11_x64_glibc.cfg new file mode 100644 index 000000000..b2327fc4f --- /dev/null +++ b/tools/release/kokoro/linux/node_11_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_11_x64_musl.cfg b/tools/release/kokoro/linux/node_11_x64_musl.cfg new file mode 100644 index 000000000..b2327fc4f --- /dev/null +++ b/tools/release/kokoro/linux/node_11_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_12_arm64_glibc.cfg b/tools/release/kokoro/linux/node_12_arm64_glibc.cfg new file mode 100644 index 000000000..d7669485d --- /dev/null +++ b/tools/release/kokoro/linux/node_12_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_12_arm_glibc.cfg b/tools/release/kokoro/linux/node_12_arm_glibc.cfg new file mode 100644 index 000000000..92b71d56a --- /dev/null +++ b/tools/release/kokoro/linux/node_12_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_12_ia32_glibc.cfg b/tools/release/kokoro/linux/node_12_ia32_glibc.cfg new file mode 100644 index 000000000..6677c7d94 --- /dev/null +++ b/tools/release/kokoro/linux/node_12_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_12_s390x_glibc.cfg b/tools/release/kokoro/linux/node_12_s390x_glibc.cfg new file mode 100644 index 000000000..ad83ac490 --- /dev/null +++ b/tools/release/kokoro/linux/node_12_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_12_x64_glibc.cfg b/tools/release/kokoro/linux/node_12_x64_glibc.cfg new file mode 100644 index 000000000..d29e134e2 --- /dev/null +++ b/tools/release/kokoro/linux/node_12_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_12_x64_musl.cfg b/tools/release/kokoro/linux/node_12_x64_musl.cfg new file mode 100644 index 000000000..d29e134e2 --- /dev/null +++ b/tools/release/kokoro/linux/node_12_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_13_arm64_glibc.cfg b/tools/release/kokoro/linux/node_13_arm64_glibc.cfg new file mode 100644 index 000000000..b9d7d4f7d --- /dev/null +++ b/tools/release/kokoro/linux/node_13_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_13_arm_glibc.cfg b/tools/release/kokoro/linux/node_13_arm_glibc.cfg new file mode 100644 index 000000000..2f4a95a08 --- /dev/null +++ b/tools/release/kokoro/linux/node_13_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_13_ia32_glibc.cfg b/tools/release/kokoro/linux/node_13_ia32_glibc.cfg new file mode 100644 index 000000000..7fde2284e --- /dev/null +++ b/tools/release/kokoro/linux/node_13_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_13_s390x_glibc.cfg b/tools/release/kokoro/linux/node_13_s390x_glibc.cfg new file mode 100644 index 000000000..dcf25cf68 --- /dev/null +++ b/tools/release/kokoro/linux/node_13_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_13_x64_glibc.cfg b/tools/release/kokoro/linux/node_13_x64_glibc.cfg new file mode 100644 index 000000000..cb102fa97 --- /dev/null +++ b/tools/release/kokoro/linux/node_13_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_13_x64_musl.cfg b/tools/release/kokoro/linux/node_13_x64_musl.cfg new file mode 100644 index 000000000..cb102fa97 --- /dev/null +++ b/tools/release/kokoro/linux/node_13_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_4_arm64_glibc.cfg b/tools/release/kokoro/linux/node_4_arm64_glibc.cfg new file mode 100644 index 000000000..a5478f30b --- /dev/null +++ b/tools/release/kokoro/linux/node_4_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_4_arm_glibc.cfg b/tools/release/kokoro/linux/node_4_arm_glibc.cfg new file mode 100644 index 000000000..82872df34 --- /dev/null +++ b/tools/release/kokoro/linux/node_4_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_4_ia32_glibc.cfg b/tools/release/kokoro/linux/node_4_ia32_glibc.cfg new file mode 100644 index 000000000..685817767 --- /dev/null +++ b/tools/release/kokoro/linux/node_4_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_4_s390x_glibc.cfg b/tools/release/kokoro/linux/node_4_s390x_glibc.cfg new file mode 100644 index 000000000..d599f9e78 --- /dev/null +++ b/tools/release/kokoro/linux/node_4_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_4_x64_glibc.cfg b/tools/release/kokoro/linux/node_4_x64_glibc.cfg new file mode 100644 index 000000000..5184495dd --- /dev/null +++ b/tools/release/kokoro/linux/node_4_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_4_x64_musl.cfg b/tools/release/kokoro/linux/node_4_x64_musl.cfg new file mode 100644 index 000000000..5184495dd --- /dev/null +++ b/tools/release/kokoro/linux/node_4_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_5_arm64_glibc.cfg b/tools/release/kokoro/linux/node_5_arm64_glibc.cfg new file mode 100644 index 000000000..f022ddce3 --- /dev/null +++ b/tools/release/kokoro/linux/node_5_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_5_arm_glibc.cfg b/tools/release/kokoro/linux/node_5_arm_glibc.cfg new file mode 100644 index 000000000..3c317ff4f --- /dev/null +++ b/tools/release/kokoro/linux/node_5_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_5_ia32_glibc.cfg b/tools/release/kokoro/linux/node_5_ia32_glibc.cfg new file mode 100644 index 000000000..e38c38d7b --- /dev/null +++ b/tools/release/kokoro/linux/node_5_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_5_s390x_glibc.cfg b/tools/release/kokoro/linux/node_5_s390x_glibc.cfg new file mode 100644 index 000000000..d1eb5d54a --- /dev/null +++ b/tools/release/kokoro/linux/node_5_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_5_x64_glibc.cfg b/tools/release/kokoro/linux/node_5_x64_glibc.cfg new file mode 100644 index 000000000..404a42095 --- /dev/null +++ b/tools/release/kokoro/linux/node_5_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_5_x64_musl.cfg b/tools/release/kokoro/linux/node_5_x64_musl.cfg new file mode 100644 index 000000000..404a42095 --- /dev/null +++ b/tools/release/kokoro/linux/node_5_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_6_arm64_glibc.cfg b/tools/release/kokoro/linux/node_6_arm64_glibc.cfg new file mode 100644 index 000000000..133d36873 --- /dev/null +++ b/tools/release/kokoro/linux/node_6_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_6_arm_glibc.cfg b/tools/release/kokoro/linux/node_6_arm_glibc.cfg new file mode 100644 index 000000000..17f323288 --- /dev/null +++ b/tools/release/kokoro/linux/node_6_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_6_ia32_glibc.cfg b/tools/release/kokoro/linux/node_6_ia32_glibc.cfg new file mode 100644 index 000000000..350b3702c --- /dev/null +++ b/tools/release/kokoro/linux/node_6_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_6_s390x_glibc.cfg b/tools/release/kokoro/linux/node_6_s390x_glibc.cfg new file mode 100644 index 000000000..279957e1e --- /dev/null +++ b/tools/release/kokoro/linux/node_6_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_6_x64_glibc.cfg b/tools/release/kokoro/linux/node_6_x64_glibc.cfg new file mode 100644 index 000000000..6c8d465b9 --- /dev/null +++ b/tools/release/kokoro/linux/node_6_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_6_x64_musl.cfg b/tools/release/kokoro/linux/node_6_x64_musl.cfg new file mode 100644 index 000000000..6c8d465b9 --- /dev/null +++ b/tools/release/kokoro/linux/node_6_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_7_arm64_glibc.cfg b/tools/release/kokoro/linux/node_7_arm64_glibc.cfg new file mode 100644 index 000000000..0862b1428 --- /dev/null +++ b/tools/release/kokoro/linux/node_7_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_7_arm_glibc.cfg b/tools/release/kokoro/linux/node_7_arm_glibc.cfg new file mode 100644 index 000000000..41ded1638 --- /dev/null +++ b/tools/release/kokoro/linux/node_7_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_7_ia32_glibc.cfg b/tools/release/kokoro/linux/node_7_ia32_glibc.cfg new file mode 100644 index 000000000..33e2a04bd --- /dev/null +++ b/tools/release/kokoro/linux/node_7_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_7_s390x_glibc.cfg b/tools/release/kokoro/linux/node_7_s390x_glibc.cfg new file mode 100644 index 000000000..3e976353a --- /dev/null +++ b/tools/release/kokoro/linux/node_7_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_7_x64_glibc.cfg b/tools/release/kokoro/linux/node_7_x64_glibc.cfg new file mode 100644 index 000000000..6f690f1b9 --- /dev/null +++ b/tools/release/kokoro/linux/node_7_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_7_x64_musl.cfg b/tools/release/kokoro/linux/node_7_x64_musl.cfg new file mode 100644 index 000000000..6f690f1b9 --- /dev/null +++ b/tools/release/kokoro/linux/node_7_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_8_arm64_glibc.cfg b/tools/release/kokoro/linux/node_8_arm64_glibc.cfg new file mode 100644 index 000000000..fba0f0f60 --- /dev/null +++ b/tools/release/kokoro/linux/node_8_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_8_arm_glibc.cfg b/tools/release/kokoro/linux/node_8_arm_glibc.cfg new file mode 100644 index 000000000..017efbc48 --- /dev/null +++ b/tools/release/kokoro/linux/node_8_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_8_ia32_glibc.cfg b/tools/release/kokoro/linux/node_8_ia32_glibc.cfg new file mode 100644 index 000000000..87b02ff59 --- /dev/null +++ b/tools/release/kokoro/linux/node_8_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_8_s390x_glibc.cfg b/tools/release/kokoro/linux/node_8_s390x_glibc.cfg new file mode 100644 index 000000000..f4e8183ad --- /dev/null +++ b/tools/release/kokoro/linux/node_8_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_8_x64_glibc.cfg b/tools/release/kokoro/linux/node_8_x64_glibc.cfg new file mode 100644 index 000000000..d0d2396e9 --- /dev/null +++ b/tools/release/kokoro/linux/node_8_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_8_x64_musl.cfg b/tools/release/kokoro/linux/node_8_x64_musl.cfg new file mode 100644 index 000000000..d0d2396e9 --- /dev/null +++ b/tools/release/kokoro/linux/node_8_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_9_arm64_glibc.cfg b/tools/release/kokoro/linux/node_9_arm64_glibc.cfg new file mode 100644 index 000000000..b2f26d89e --- /dev/null +++ b/tools/release/kokoro/linux/node_9_arm64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm64" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_9_arm_glibc.cfg b/tools/release/kokoro/linux/node_9_arm_glibc.cfg new file mode 100644 index 000000000..051f833f9 --- /dev/null +++ b/tools/release/kokoro/linux/node_9_arm_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "arm" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_9_ia32_glibc.cfg b/tools/release/kokoro/linux/node_9_ia32_glibc.cfg new file mode 100644 index 000000000..0e1f41d86 --- /dev/null +++ b/tools/release/kokoro/linux/node_9_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_9_s390x_glibc.cfg b/tools/release/kokoro/linux/node_9_s390x_glibc.cfg new file mode 100644 index 000000000..fce879525 --- /dev/null +++ b/tools/release/kokoro/linux/node_9_s390x_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "s390x" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_9_x64_glibc.cfg b/tools/release/kokoro/linux/node_9_x64_glibc.cfg new file mode 100644 index 000000000..fc88e10fb --- /dev/null +++ b/tools/release/kokoro/linux/node_9_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/node_9_x64_musl.cfg b/tools/release/kokoro/linux/node_9_x64_musl.cfg new file mode 100644 index 000000000..fc88e10fb --- /dev/null +++ b/tools/release/kokoro/linux/node_9_x64_musl.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.0_ia32.cfg b/tools/release/kokoro/windows/electron_1.0_ia32.cfg new file mode 100644 index 000000000..599cf0990 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.0_x64.cfg b/tools/release/kokoro/windows/electron_1.0_x64.cfg new file mode 100644 index 000000000..eb5e743c2 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.1_ia32.cfg b/tools/release/kokoro/windows/electron_1.1_ia32.cfg new file mode 100644 index 000000000..61f22bc6c --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.1_x64.cfg b/tools/release/kokoro/windows/electron_1.1_x64.cfg new file mode 100644 index 000000000..3d084c48f --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.2_ia32.cfg b/tools/release/kokoro/windows/electron_1.2_ia32.cfg new file mode 100644 index 000000000..cc0ceee15 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.2_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.2_x64.cfg b/tools/release/kokoro/windows/electron_1.2_x64.cfg new file mode 100644 index 000000000..15a3d4fc8 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.2_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.3_ia32.cfg b/tools/release/kokoro/windows/electron_1.3_ia32.cfg new file mode 100644 index 000000000..07588569b --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.3_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.3.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.3_x64.cfg b/tools/release/kokoro/windows/electron_1.3_x64.cfg new file mode 100644 index 000000000..0d3c28154 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.3_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.3.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.4_ia32.cfg b/tools/release/kokoro/windows/electron_1.4_ia32.cfg new file mode 100644 index 000000000..3e9c68475 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.4_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.4.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.4_x64.cfg b/tools/release/kokoro/windows/electron_1.4_x64.cfg new file mode 100644 index 000000000..fd0bea93c --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.4_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.4.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.5_ia32.cfg b/tools/release/kokoro/windows/electron_1.5_ia32.cfg new file mode 100644 index 000000000..a30d9a759 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.5_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.5.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.5_x64.cfg b/tools/release/kokoro/windows/electron_1.5_x64.cfg new file mode 100644 index 000000000..00e9ccb53 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.5_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.5.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.6_ia32.cfg b/tools/release/kokoro/windows/electron_1.6_ia32.cfg new file mode 100644 index 000000000..ed6344b80 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.6_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.6.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.6_x64.cfg b/tools/release/kokoro/windows/electron_1.6_x64.cfg new file mode 100644 index 000000000..846a2889d --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.6_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.6.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.7_ia32.cfg b/tools/release/kokoro/windows/electron_1.7_ia32.cfg new file mode 100644 index 000000000..e90dfeeeb --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.7_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.7.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.7_x64.cfg b/tools/release/kokoro/windows/electron_1.7_x64.cfg new file mode 100644 index 000000000..417b1bccf --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.7_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.7.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.8_ia32.cfg b/tools/release/kokoro/windows/electron_1.8_ia32.cfg new file mode 100644 index 000000000..ff51b7ab8 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.8_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "1.8.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_1.8_x64.cfg b/tools/release/kokoro/windows/electron_1.8_x64.cfg new file mode 100644 index 000000000..1675c9f03 --- /dev/null +++ b/tools/release/kokoro/windows/electron_1.8_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "1.8.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_2.0_ia32.cfg b/tools/release/kokoro/windows/electron_2.0_ia32.cfg new file mode 100644 index 000000000..145f2cf97 --- /dev/null +++ b/tools/release/kokoro/windows/electron_2.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "2.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_2.0_x64.cfg b/tools/release/kokoro/windows/electron_2.0_x64.cfg new file mode 100644 index 000000000..0005d14ff --- /dev/null +++ b/tools/release/kokoro/windows/electron_2.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "2.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_3.0_ia32.cfg b/tools/release/kokoro/windows/electron_3.0_ia32.cfg new file mode 100644 index 000000000..f4a19371f --- /dev/null +++ b/tools/release/kokoro/windows/electron_3.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "3.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_3.0_x64.cfg b/tools/release/kokoro/windows/electron_3.0_x64.cfg new file mode 100644 index 000000000..cb2c38bea --- /dev/null +++ b/tools/release/kokoro/windows/electron_3.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "3.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_3.1_ia32.cfg b/tools/release/kokoro/windows/electron_3.1_ia32.cfg new file mode 100644 index 000000000..92d4ec6d0 --- /dev/null +++ b/tools/release/kokoro/windows/electron_3.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "3.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_3.1_x64.cfg b/tools/release/kokoro/windows/electron_3.1_x64.cfg new file mode 100644 index 000000000..5989e7aa0 --- /dev/null +++ b/tools/release/kokoro/windows/electron_3.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "3.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_4.1_ia32.cfg b/tools/release/kokoro/windows/electron_4.1_ia32.cfg new file mode 100644 index 000000000..67eb4183a --- /dev/null +++ b/tools/release/kokoro/windows/electron_4.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_4.1_x64.cfg b/tools/release/kokoro/windows/electron_4.1_x64.cfg new file mode 100644 index 000000000..70b52b12a --- /dev/null +++ b/tools/release/kokoro/windows/electron_4.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_4.2_ia32.cfg b/tools/release/kokoro/windows/electron_4.2_ia32.cfg new file mode 100644 index 000000000..f447ed311 --- /dev/null +++ b/tools/release/kokoro/windows/electron_4.2_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_4.2_x64.cfg b/tools/release/kokoro/windows/electron_4.2_x64.cfg new file mode 100644 index 000000000..a29112fe5 --- /dev/null +++ b/tools/release/kokoro/windows/electron_4.2_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.2.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_5.0_ia32.cfg b/tools/release/kokoro/windows/electron_5.0_ia32.cfg new file mode 100644 index 000000000..991bdec88 --- /dev/null +++ b/tools/release/kokoro/windows/electron_5.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_5.0_x64.cfg b/tools/release/kokoro/windows/electron_5.0_x64.cfg new file mode 100644 index 000000000..3b7857023 --- /dev/null +++ b/tools/release/kokoro/windows/electron_5.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_6.0_ia32.cfg b/tools/release/kokoro/windows/electron_6.0_ia32.cfg new file mode 100644 index 000000000..f944e7902 --- /dev/null +++ b/tools/release/kokoro/windows/electron_6.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_6.0_x64.cfg b/tools/release/kokoro/windows/electron_6.0_x64.cfg new file mode 100644 index 000000000..5dda672d3 --- /dev/null +++ b/tools/release/kokoro/windows/electron_6.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_6.1_ia32.cfg b/tools/release/kokoro/windows/electron_6.1_ia32.cfg new file mode 100644 index 000000000..b202263ac --- /dev/null +++ b/tools/release/kokoro/windows/electron_6.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_6.1_x64.cfg b/tools/release/kokoro/windows/electron_6.1_x64.cfg new file mode 100644 index 000000000..2352deef8 --- /dev/null +++ b/tools/release/kokoro/windows/electron_6.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_7.0_ia32.cfg b/tools/release/kokoro/windows/electron_7.0_ia32.cfg new file mode 100644 index 000000000..e7c9d1ff0 --- /dev/null +++ b/tools/release/kokoro/windows/electron_7.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_7.0_x64.cfg b/tools/release/kokoro/windows/electron_7.0_x64.cfg new file mode 100644 index 000000000..838143f22 --- /dev/null +++ b/tools/release/kokoro/windows/electron_7.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_7.1_ia32.cfg b/tools/release/kokoro/windows/electron_7.1_ia32.cfg new file mode 100644 index 000000000..bda7d339b --- /dev/null +++ b/tools/release/kokoro/windows/electron_7.1_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_7.1_x64.cfg b/tools/release/kokoro/windows/electron_7.1_x64.cfg new file mode 100644 index 000000000..008cac967 --- /dev/null +++ b/tools/release/kokoro/windows/electron_7.1_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.1.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_10_ia32.cfg b/tools/release/kokoro/windows/node_10_ia32.cfg new file mode 100644 index 000000000..5a2d283c7 --- /dev/null +++ b/tools/release/kokoro/windows/node_10_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_10_x64.cfg b/tools/release/kokoro/windows/node_10_x64.cfg new file mode 100644 index 000000000..c92671de8 --- /dev/null +++ b/tools/release/kokoro/windows/node_10_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "10.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_11_ia32.cfg b/tools/release/kokoro/windows/node_11_ia32.cfg new file mode 100644 index 000000000..507c11cce --- /dev/null +++ b/tools/release/kokoro/windows/node_11_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_11_x64.cfg b/tools/release/kokoro/windows/node_11_x64.cfg new file mode 100644 index 000000000..ec92fe997 --- /dev/null +++ b/tools/release/kokoro/windows/node_11_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "11.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_12_ia32.cfg b/tools/release/kokoro/windows/node_12_ia32.cfg new file mode 100644 index 000000000..d9f1988a4 --- /dev/null +++ b/tools/release/kokoro/windows/node_12_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_12_x64.cfg b/tools/release/kokoro/windows/node_12_x64.cfg new file mode 100644 index 000000000..a2d7c70c8 --- /dev/null +++ b/tools/release/kokoro/windows/node_12_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "12.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_13_ia32.cfg b/tools/release/kokoro/windows/node_13_ia32.cfg new file mode 100644 index 000000000..521893bd1 --- /dev/null +++ b/tools/release/kokoro/windows/node_13_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_13_x64.cfg b/tools/release/kokoro/windows/node_13_x64.cfg new file mode 100644 index 000000000..ae937cc7f --- /dev/null +++ b/tools/release/kokoro/windows/node_13_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "13.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_4_ia32.cfg b/tools/release/kokoro/windows/node_4_ia32.cfg new file mode 100644 index 000000000..88c163c2a --- /dev/null +++ b/tools/release/kokoro/windows/node_4_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_4_x64.cfg b/tools/release/kokoro/windows/node_4_x64.cfg new file mode 100644 index 000000000..66092f441 --- /dev/null +++ b/tools/release/kokoro/windows/node_4_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "4.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_5_ia32.cfg b/tools/release/kokoro/windows/node_5_ia32.cfg new file mode 100644 index 000000000..a883e4245 --- /dev/null +++ b/tools/release/kokoro/windows/node_5_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_5_x64.cfg b/tools/release/kokoro/windows/node_5_x64.cfg new file mode 100644 index 000000000..33099355b --- /dev/null +++ b/tools/release/kokoro/windows/node_5_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "5.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_6_ia32.cfg b/tools/release/kokoro/windows/node_6_ia32.cfg new file mode 100644 index 000000000..651119035 --- /dev/null +++ b/tools/release/kokoro/windows/node_6_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_6_x64.cfg b/tools/release/kokoro/windows/node_6_x64.cfg new file mode 100644 index 000000000..bd50810ce --- /dev/null +++ b/tools/release/kokoro/windows/node_6_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "6.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_7_ia32.cfg b/tools/release/kokoro/windows/node_7_ia32.cfg new file mode 100644 index 000000000..a0900e932 --- /dev/null +++ b/tools/release/kokoro/windows/node_7_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_7_x64.cfg b/tools/release/kokoro/windows/node_7_x64.cfg new file mode 100644 index 000000000..8483b8436 --- /dev/null +++ b/tools/release/kokoro/windows/node_7_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "7.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_8_ia32.cfg b/tools/release/kokoro/windows/node_8_ia32.cfg new file mode 100644 index 000000000..59febe3b3 --- /dev/null +++ b/tools/release/kokoro/windows/node_8_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_8_x64.cfg b/tools/release/kokoro/windows/node_8_x64.cfg new file mode 100644 index 000000000..bf0da19d5 --- /dev/null +++ b/tools/release/kokoro/windows/node_8_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_9_ia32.cfg b/tools/release/kokoro/windows/node_9_ia32.cfg new file mode 100644 index 000000000..bb419d8c6 --- /dev/null +++ b/tools/release/kokoro/windows/node_9_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/node_9_x64.cfg b/tools/release/kokoro/windows/node_9_x64.cfg new file mode 100644 index 000000000..8380f4311 --- /dev/null +++ b/tools/release/kokoro/windows/node_9_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "node" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "9.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} From 64f715d0e4e8e3431b3aac6aa9ed80c7cab8d694 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Feb 2020 13:36:28 -0800 Subject: [PATCH 0932/1899] Add electron 8.0 --- .../tools/buildgen/gen_build_yaml.py | 2 +- .../kokoro/linux/electron_8.0_ia32_glibc.cfg | 39 +++++++++++++++++++ .../kokoro/linux/electron_8.0_x64_glibc.cfg | 39 +++++++++++++++++++ .../kokoro/macos/electron_8.0_ia32.cfg | 35 +++++++++++++++++ .../release/kokoro/macos/electron_8.0_x64.cfg | 35 +++++++++++++++++ .../kokoro/windows/electron_8.0_ia32.cfg | 35 +++++++++++++++++ .../kokoro/windows/electron_8.0_x64.cfg | 35 +++++++++++++++++ 7 files changed, 219 insertions(+), 1 deletion(-) create mode 100644 tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg create mode 100644 tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg create mode 100644 tools/release/kokoro/macos/electron_8.0_ia32.cfg create mode 100644 tools/release/kokoro/macos/electron_8.0_x64.cfg create mode 100644 tools/release/kokoro/windows/electron_8.0_ia32.cfg create mode 100644 tools/release/kokoro/windows/electron_8.0_x64.cfg diff --git a/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py b/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py index 998e48f8f..17e746a68 100644 --- a/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py +++ b/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py @@ -21,7 +21,7 @@ import yaml node_versions = ["4", "5", "6", "7", "8", "9", "10", "11", "12", "13"] -electron_versions = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "2.0", "3.0", "3.1", "4.1", "4.2", "5.0", "6.0", "6.1", "7.0", "7.1"] +electron_versions = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "2.0", "3.0", "3.1", "4.1", "4.2", "5.0", "6.0", "6.1", "7.0", "7.1", "8.0"] def gen_linux_configs(): configs = [] diff --git a/tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg new file mode 100644 index 000000000..b0b86657c --- /dev/null +++ b/tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg new file mode 100644 index 000000000..2e79736fe --- /dev/null +++ b/tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg @@ -0,0 +1,39 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +env_vars { + key: "LIBC" + value: "glibc" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_8.0_ia32.cfg b/tools/release/kokoro/macos/electron_8.0_ia32.cfg new file mode 100644 index 000000000..01b9e92f6 --- /dev/null +++ b/tools/release/kokoro/macos/electron_8.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/macos/electron_8.0_x64.cfg b/tools/release/kokoro/macos/electron_8.0_x64.cfg new file mode 100644 index 000000000..dec384eda --- /dev/null +++ b/tools/release/kokoro/macos/electron_8.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_8.0_ia32.cfg b/tools/release/kokoro/windows/electron_8.0_ia32.cfg new file mode 100644 index 000000000..ca01fd57f --- /dev/null +++ b/tools/release/kokoro/windows/electron_8.0_ia32.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "ia32" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} diff --git a/tools/release/kokoro/windows/electron_8.0_x64.cfg b/tools/release/kokoro/windows/electron_8.0_x64.cfg new file mode 100644 index 000000000..988322a4e --- /dev/null +++ b/tools/release/kokoro/windows/electron_8.0_x64.cfg @@ -0,0 +1,35 @@ +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" +env_vars { + key: "RUNTIME" + value: "electron" +} +env_vars { + key: "ARCH" + value: "x64" +} +env_vars { + key: "VERSION" + value: "8.0.0" +} +action { + define_artifacts { + regex: "github/grpc-node/artifacts/**", + strip_prefix: "github/grpc-node/artifacts" + } +} From 314b07ddc0e7d878624002bf21854bb0765cbc4b Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 7 Feb 2020 13:54:39 -0800 Subject: [PATCH 0933/1899] Fix bad path in generate_projects.sh --- packages/grpc-native-core/tools/buildgen/generate_projects.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/tools/buildgen/generate_projects.sh b/packages/grpc-native-core/tools/buildgen/generate_projects.sh index 6575996a7..448aad44c 100755 --- a/packages/grpc-native-core/tools/buildgen/generate_projects.sh +++ b/packages/grpc-native-core/tools/buildgen/generate_projects.sh @@ -21,6 +21,6 @@ root=$(pwd) native_root=$root/packages/grpc-native-core output_file=$(mktemp /tmp/genXXXXXX) -python $(dirname $0)/gen_build_yaml.py > $output_file +python $native_root/tools/buildgen/gen_build_yaml.py > $output_file -./packages/grpc-native-core/deps/grpc/tools/buildgen/generate_projects.sh $native_root/build.yaml $output_file --base=$root --templates $(find templates -type f) +$native_root/tools/buildgen/generate_projects.sh $native_root/build.yaml $output_file --base=$root --templates $(find templates -type f) From 651274acb56b3a876f8ce05defe6de6336eddeed Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 10 Feb 2020 10:09:34 -0800 Subject: [PATCH 0934/1899] Don't generate_projects in build scripts --- .../tools/run_tests/artifacts/build_one_artifact_linux.sh | 3 --- .../tools/run_tests/artifacts/build_one_artifact_macos.sh | 3 --- 2 files changed, 6 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh index 3adf9ba10..2a1beddc1 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh @@ -32,9 +32,6 @@ cd $base_dir/packages/grpc-native-core # Install gRPC and its submodules. git submodule update --init --recursive -pip install mako -./tools/buildgen/generate_projects.sh - case $ARCH in arm|arm64|s390x) docker build -t artifact-image $base_dir/tools/release/cross diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh index 1b2fa40e8..29157442c 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh @@ -32,9 +32,6 @@ cd $base_dir/packages/grpc-native-core # Install gRPC and its submodules. git submodule update --init --recursive -pip install mako -./tools/buildgen/generate_projects.sh - export JOBS=8 export ARTIFACTS_OUT=$base_dir/artifacts From e51497119437bfdba8fb4f294a08b9557548de93 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 10 Feb 2020 10:45:05 -0800 Subject: [PATCH 0935/1899] Fix generate_projects recursion, remove 'testpackage' command from scripts --- packages/grpc-native-core/tools/buildgen/generate_projects.sh | 2 +- .../tools/run_tests/artifacts/build_one_artifact_in_docker.sh | 2 +- .../tools/run_tests/artifacts/build_one_artifact_macos.sh | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-native-core/tools/buildgen/generate_projects.sh b/packages/grpc-native-core/tools/buildgen/generate_projects.sh index 448aad44c..1a1d7b6fc 100755 --- a/packages/grpc-native-core/tools/buildgen/generate_projects.sh +++ b/packages/grpc-native-core/tools/buildgen/generate_projects.sh @@ -23,4 +23,4 @@ native_root=$root/packages/grpc-native-core output_file=$(mktemp /tmp/genXXXXXX) python $native_root/tools/buildgen/gen_build_yaml.py > $output_file -$native_root/tools/buildgen/generate_projects.sh $native_root/build.yaml $output_file --base=$root --templates $(find templates -type f) +$native_root/deps/grpc/tools/buildgen/generate_projects.sh $native_root/build.yaml $output_file --base=$root --templates $(find templates -type f) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh index b8408dc85..5630444ce 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh @@ -50,5 +50,5 @@ case $RUNTIME in ;; esac -./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$VERSION --target_arch=$ARCH --runtime=$RUNTIME --target_libc=$LIBC +./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH --runtime=$RUNTIME --target_libc=$LIBC cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh index 29157442c..059927568 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh @@ -49,5 +49,5 @@ case $RUNTIME in node) esac -./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$VERSION --target_arch=$ARCH +./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file From 6cbccceeb6f7537a5df4e3b9e59d32bd02460567 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 10 Feb 2020 10:47:52 -0800 Subject: [PATCH 0936/1899] Pass runtime argument in mac build script --- .../tools/run_tests/artifacts/build_one_artifact_macos.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh index 059927568..5ca968362 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh @@ -49,5 +49,5 @@ case $RUNTIME in node) esac -./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH +./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH --runtime=$RUNTIME cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file From 54e81fdd1e12905a6959afdd5516537b7c4ca92a Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 11 Feb 2020 15:20:52 -0800 Subject: [PATCH 0937/1899] Use correct environment variables in new windows build script --- .../tools/run_tests/artifacts/build_one_artifact.bat | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat index 0a91e5a33..9b3829d27 100644 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat @@ -45,13 +45,13 @@ if "%RUNTIME%"=="electron" ( set "npm_config_disturl=https://atom.io/download/electron" ) -call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%%a && goto :EOF +call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%VERSION% --target_arch=%ARCH% && goto :EOF @rem Try again after removing openssl headers -rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q -rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q -rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\%%v\include\node\openssl" /S /Q -rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q -call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error +rmdir "%USERPROFILE%\.node-gyp\%VERSION%\include\node\openssl" /S /Q +rmdir "%USERPROFILE%\.node-gyp\iojs-%VERSION%\include\node\openssl" /S /Q +rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\%VERSION%\include\node\openssl" /S /Q +rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\iojs-%VERSION%\include\node\openssl" /S /Q +call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%VERSION% --target_arch=%ARCH% || goto :error xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error From 3a95e55786974223e2eb51c0681bc3457057cbeb Mon Sep 17 00:00:00 2001 From: Litichevskiy Dmitriy Date: Sun, 16 Feb 2020 23:02:22 +0300 Subject: [PATCH 0938/1899] message parameter was removed from cancel requester description --- packages/grpc-native-core/src/client_interceptors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js index 2cf48481d..75243cc2b 100644 --- a/packages/grpc-native-core/src/client_interceptors.js +++ b/packages/grpc-native-core/src/client_interceptors.js @@ -51,7 +51,7 @@ * `halfClose(next)` * * To continue, call next(). * - * `cancel(message, next)` + * `cancel(next)` * * To continue, call next(). * * A listener is a POJO with one or more of the following methods: @@ -109,7 +109,7 @@ * halfClose: function(next) { * next(); * }, - * cancel: function(message, next) { + * cancel: function(next) { * next(); * } * }); From 439263d4e1719f1e2f247f77c1f97fdb63fc879e Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 18 Feb 2020 17:17:19 -0800 Subject: [PATCH 0939/1899] Fix a trace line, and add a few new ones --- .../grpc-js/src/load-balancer-pick-first.ts | 8 +++++++- .../grpc-js/src/load-balancer-round-robin.ts | 18 ++++++++++++++++++ packages/grpc-js/src/subchannel.ts | 19 ++++++++++++++----- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 52ce8457a..10ef71495 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -34,6 +34,7 @@ import { Subchannel, ConnectivityStateListener, SubchannelAddress, + subchannelAddressToString, } from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; @@ -335,7 +336,12 @@ export class PickFirstLoadBalancer implements LoadBalancer { */ private connectToAddressList(): void { this.resetSubchannelList(); - trace('Connect to address list ' + this.latestAddressList); + trace( + 'Connect to address list ' + + this.latestAddressList.map(address => + subchannelAddressToString(address) + ) + ); this.subchannels = this.latestAddressList.map(address => this.channelControlHelper.createSubchannel(address, {}) ); diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 4956e11e7..465299360 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -34,7 +34,16 @@ import { Subchannel, ConnectivityStateListener, SubchannelAddress, + subchannelAddressToString, } from './subchannel'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'round_robin'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'round_robin'; @@ -147,6 +156,11 @@ export class RoundRobinLoadBalancer implements LoadBalancer { } private updateState(newState: ConnectivityState, picker: Picker) { + trace( + ConnectivityState[this.currentState] + + ' -> ' + + ConnectivityState[newState] + ); if (newState === ConnectivityState.READY) { this.currentReadyPicker = picker as RoundRobinPicker; } else { @@ -176,6 +190,10 @@ export class RoundRobinLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig | null ): void { this.resetSubchannelList(); + trace( + 'Connect to address list ' + + addressList.map(address => subchannelAddressToString(address)) + ); this.subchannels = addressList.map(address => this.channelControlHelper.createSubchannel(address, {}) ); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index bb64bd93d..948bcb471 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -112,6 +112,14 @@ export function subchannelAddressEqual( } } +export function subchannelAddressToString(address: SubchannelAddress): string { + if (isTcpSubchannelAddress(address)) { + return address.host + ':' + address.port; + } else { + return address.path; + } +} + export class Subchannel { /** * The subchannel's current connectivity state. Invariant: `session` === `null` @@ -231,11 +239,7 @@ export class Subchannel { ); } }, backoffOptions); - if (isTcpSubchannelAddress(subchannelAddress)) { - this.subchannelAddressString = `${subchannelAddress.host}:${subchannelAddress.port}`; - } else { - this.subchannelAddressString = `${subchannelAddress.path}`; - } + this.subchannelAddressString = subchannelAddressToString(subchannelAddress); } /** @@ -390,6 +394,11 @@ export class Subchannel { session.once('error', error => { /* Do nothing here. Any error should also trigger a close event, which is * where we want to handle that. */ + trace( + this.subchannelAddressString + + ' connection closed with error ' + + (error as Error).message + ); }); } From c7980f664dbfd4a34e2f102b1647e52b425a8395 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 19 Feb 2020 11:08:45 -0800 Subject: [PATCH 0940/1899] Fix text in a refcount trace log --- packages/grpc-js/src/subchannel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 948bcb471..cc10dd760 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -525,7 +525,7 @@ export class Subchannel { ref() { trace( this.subchannelAddressString + - ' callRefcount ' + + ' refcount ' + this.refcount + ' -> ' + (this.refcount + 1) @@ -536,7 +536,7 @@ export class Subchannel { unref() { trace( this.subchannelAddressString + - ' callRefcount ' + + ' refcount ' + this.refcount + ' -> ' + (this.refcount - 1) From b90dc81b732caa9bfc86298dbd8a46dd158f05ac Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Feb 2020 12:46:59 -0800 Subject: [PATCH 0941/1899] Include method name in UNIMPLEMENTED details string --- packages/grpc-js/src/server.ts | 66 ++++++++++++++++--------- packages/grpc-native-core/src/server.js | 45 ++++++++++------- 2 files changed, 69 insertions(+), 42 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index a2db30beb..9cddb0849 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -49,11 +49,15 @@ import { ChannelOptions } from './channel-options'; function noop(): void {} -const unimplementedStatusResponse: Partial = { - code: Status.UNIMPLEMENTED, - details: 'The server does not implement this method', - metadata: new Metadata(), -}; +function getUnimplementedStatusResponse( + methodName: string +): Partial { + return { + code: Status.UNIMPLEMENTED, + details: `The server does not implement the method ${methodName}`, + metadata: new Metadata(), + }; +} // tslint:disable:no-any type UntypedUnaryHandler = UnaryHandler; @@ -66,23 +70,37 @@ export interface UntypedServiceImplementation { [name: string]: UntypedHandleCall; } -const defaultHandler = { - unary(call: ServerUnaryCall, callback: sendUnaryData): void { - callback(unimplementedStatusResponse as ServiceError, null); - }, - clientStream( - call: ServerReadableStream, - callback: sendUnaryData - ): void { - callback(unimplementedStatusResponse as ServiceError, null); - }, - serverStream(call: ServerWritableStream): void { - call.emit('error', unimplementedStatusResponse); - }, - bidi(call: ServerDuplexStream): void { - call.emit('error', unimplementedStatusResponse); - }, -}; +function getDefaultHandler(handlerType: HandlerType, methodName: string) { + const unimplementedStatusResponse = getUnimplementedStatusResponse( + methodName + ); + switch (handlerType) { + case 'unary': + return ( + call: ServerUnaryCall, + callback: sendUnaryData + ) => { + callback(unimplementedStatusResponse as ServiceError, null); + }; + case 'clientStream': + return ( + call: ServerReadableStream, + callback: sendUnaryData + ) => { + callback(unimplementedStatusResponse as ServiceError, null); + }; + case 'serverStream': + return (call: ServerWritableStream) => { + call.emit('error', unimplementedStatusResponse); + }; + case 'bidi': + return (call: ServerDuplexStream) => { + call.emit('error', unimplementedStatusResponse); + }; + default: + throw new Error(`Invalid handlerType ${handlerType}`); + } +} // tslint:enable:no-any export class Server { @@ -157,7 +175,7 @@ export class Server { if (implFn !== undefined) { impl = implFn.bind(implementation); } else { - impl = defaultHandler[methodType]; + impl = getDefaultHandler(methodType, name); } const success = this.register( @@ -353,7 +371,7 @@ export class Server { const handler = this.handlers.get(path); if (handler === undefined) { - throw unimplementedStatusResponse; + throw getUnimplementedStatusResponse(path); } const call = new Http2ServerCallStream(stream, handler); diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 737e43140..3471f2711 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -843,25 +843,34 @@ Server.prototype.forceShutdown = function() { this._server.forceShutdown(); }; -var unimplementedStatusResponse = { - code: constants.status.UNIMPLEMENTED, - details: 'The server does not implement this method' -}; +function getUnimplementedStatusResponse(methodName) { + return { + code: Status.UNIMPLEMENTED, + details: 'The server does not implement the method' + methodName + } +} -var defaultHandler = { - unary: function(call, callback) { - callback(unimplementedStatusResponse); - }, - client_stream: function(call, callback) { - callback(unimplementedStatusResponse); - }, - server_stream: function(call) { - call.emit('error', unimplementedStatusResponse); - }, - bidi: function(call) { - call.emit('error', unimplementedStatusResponse); +function getDefaultHandler(handlerType, methodName) { + const unimplementedStatusResponse = getUnimplementedStatusResponse(methodName); + switch(handlerType) { + case 'unary': + return (call, callback) => { + callback(unimplementedStatusResponse, null); + }; + case 'clientStream': + return (call,callback) => { + callback(unimplementedStatusResponse, null); + }; + case 'serverStream': + return (call) => { + call.emit('error', unimplementedStatusResponse); + } + case 'bidi': + return (call) => { + call.emit('error', unimplementedStatusResponse); + } } -}; +} function isObject(thing) { return (typeof thing === 'object' || typeof thing === 'function') && thing !== null; @@ -908,7 +917,7 @@ Server.prototype.addService = function(service, implementation) { if (implementation[attrs.originalName] === undefined) { common.log(constants.logVerbosity.ERROR, 'Method handler ' + name + ' for ' + attrs.path + ' expected but not provided'); - impl = defaultHandler[method_type]; + impl = getDefaultHandler(method_type, name); } else { impl = implementation[attrs.originalName].bind(implementation); } From 38bab42f30dca4bb9958c930d3441963b02b326d Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Feb 2020 14:10:13 -0800 Subject: [PATCH 0942/1899] Fix reference to status enum in native impl --- packages/grpc-native-core/src/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 3471f2711..2735d28e5 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -845,7 +845,7 @@ Server.prototype.forceShutdown = function() { function getUnimplementedStatusResponse(methodName) { return { - code: Status.UNIMPLEMENTED, + code: constants.status.UNIMPLEMENTED, details: 'The server does not implement the method' + methodName } } From bc3e6a1adca91f50e57a03f3f5cc5721c53f08fd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Feb 2020 14:51:22 -0800 Subject: [PATCH 0943/1899] grpc-js: Add pick tracing and one error handler --- packages/grpc-js/src/channel.ts | 55 ++++++++++++++++++++++++++++----- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6242fc3c7..e1db479c1 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -37,7 +37,7 @@ import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority } from './resolver'; import { LoadBalancingConfig } from './load-balancing-config'; import { ServiceConfig, validateServiceConfig } from './service-config'; -import { trace } from './logging'; +import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; export enum ConnectivityState { @@ -212,6 +212,18 @@ export class ChannelImplementation implements Channel { */ private tryPick(callStream: Http2CallStream, callMetadata: Metadata) { const pickResult = this.currentPicker.pick({ metadata: callMetadata }); + trace( + LogVerbosity.DEBUG, + 'channel', + 'Pick result: ' + + PickResultType[pickResult.pickResultType] + + ' subchannel: ' + + pickResult.subchannel?.getAddress() + + ' status: ' + + pickResult.status?.code + + ' ' + + pickResult.status?.details + ); switch (pickResult.pickResultType) { case PickResultType.COMPLETE: if (pickResult.subchannel === null) { @@ -221,16 +233,29 @@ export class ChannelImplementation implements Channel { ); // End the call with an error } else { - /* If the subchannel disconnects between calling pick and getting - * the filter stack metadata, the call will end with an error. */ + /* If the subchannel is not in the READY state, that indicates a bug + * somewhere in the load balancer or picker. So, we log an error and + * queue the pick to be tried again later. */ + if ( + pickResult.subchannel!.getConnectivityState() !== + ConnectivityState.READY + ) { + log( + LogVerbosity.ERROR, + 'Error: COMPLETE pick result subchannel ' + + pickResult.subchannel!.getAddress() + + ' has state ' + + ConnectivityState[pickResult.subchannel!.getConnectivityState()] + ); + this.pickQueue.push({ callStream, callMetadata }); + break; + } callStream.filterStack .sendMetadata(Promise.resolve(callMetadata)) .then( finalMetadata => { - if ( - pickResult.subchannel!.getConnectivityState() === - ConnectivityState.READY - ) { + const subchannelState: ConnectivityState = pickResult.subchannel!.getConnectivityState(); + if (subchannelState === ConnectivityState.READY) { try { pickResult.subchannel!.startCallStream( finalMetadata, @@ -250,11 +275,27 @@ export class ChannelImplementation implements Channel { * the stream because the correct behavior may be * re-queueing instead, based on the logic in the rest of * tryPick */ + trace( + LogVerbosity.INFO, + 'channel', + 'Failed to start call on picked subchannel ' + + pickResult.subchannel!.getAddress() + + '. Retrying pick' + ); this.tryPick(callStream, callMetadata); } } else { /* The logic for doing this here is the same as in the catch * block above */ + trace( + LogVerbosity.INFO, + 'channel', + 'Picked subchannel ' + + pickResult.subchannel!.getAddress() + + ' has state ' + + ConnectivityState[subchannelState] + + ' after metadata filters. Retrying pick' + ); this.tryPick(callStream, callMetadata); } }, From 0257c585ea074a5588167bca0d590e49ce9218d0 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Feb 2020 15:06:43 -0800 Subject: [PATCH 0944/1899] Correct handler type name spelling --- packages/grpc-native-core/src/server.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 2735d28e5..81e563474 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -857,11 +857,11 @@ function getDefaultHandler(handlerType, methodName) { return (call, callback) => { callback(unimplementedStatusResponse, null); }; - case 'clientStream': + case 'client_stream': return (call,callback) => { callback(unimplementedStatusResponse, null); }; - case 'serverStream': + case 'server_stream': return (call) => { call.emit('error', unimplementedStatusResponse); } From 4a1dab341bbf278d91cdc2266144e932ca9c6235 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 20 Feb 2020 15:09:06 -0800 Subject: [PATCH 0945/1899] Bump grpc-js to 0.6.17 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index dfa8d4830..d56999bc3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.16", + "version": "0.6.17", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 18869dcb08f34c853f797e83ae09b7ad89126cd4 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 21 Feb 2020 16:39:10 -0800 Subject: [PATCH 0946/1899] Clone metadata going into the metadata filter stack --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d56999bc3..52667831f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.17", + "version": "0.6.18", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index e1db479c1..8420b909e 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -250,8 +250,11 @@ export class ChannelImplementation implements Channel { this.pickQueue.push({ callStream, callMetadata }); break; } + /* We need to clone the callMetadata here because the transparent + * retry code in the promise resolution handler use the same + * callMetadata object, so it needs to stay unmodified */ callStream.filterStack - .sendMetadata(Promise.resolve(callMetadata)) + .sendMetadata(Promise.resolve(callMetadata.clone())) .then( finalMetadata => { const subchannelState: ConnectivityState = pickResult.subchannel!.getConnectivityState(); @@ -280,6 +283,8 @@ export class ChannelImplementation implements Channel { 'channel', 'Failed to start call on picked subchannel ' + pickResult.subchannel!.getAddress() + + ' with error ' + + (error as Error).message + '. Retrying pick' ); this.tryPick(callStream, callMetadata); From 03b70172e04c62a76440d2e889ac76ffa49567ba Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 24 Feb 2020 10:39:48 -0800 Subject: [PATCH 0947/1899] grpc-js: Detect and error on multiple auth headers --- packages/grpc-js/src/call-credentials-filter.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index a58f10ee1..f3fe2f4d4 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -20,6 +20,7 @@ import { Call } from './call-stream'; import { Channel } from './channel'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; +import { Status } from './constants'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; @@ -50,6 +51,12 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { }); const resultMetadata = await metadata; resultMetadata.merge(await credsMetadata); + if (resultMetadata.get('authorization').length > 1) { + this.stream.cancelWithStatus( + Status.INTERNAL, + '"authorization" metadata cannot have multiple values' + ); + } return resultMetadata; } } From 77b86fdbeac030b3386e0b6219dc11a55d8756b1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 26 Feb 2020 17:54:22 -0800 Subject: [PATCH 0948/1899] Simplify getBottomInterceptingCall signature --- packages/grpc-js/src/client-interceptors.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index a06fda1fe..9892959e0 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -454,11 +454,10 @@ class BaseStreamingInterceptingCall extends BaseInterceptingCall // tslint:disable-next-line no-any function getBottomInterceptingCall( channel: Channel, - path: string, options: InterceptorOptions, methodDefinition: ClientMethodDefinition ) { - const call = getCall(channel, path, options); + const call = getCall(channel, methodDefinition.path, options); if (methodDefinition.responseStream) { return new BaseStreamingInterceptingCall(call, methodDefinition); } else { @@ -554,7 +553,6 @@ export function getInterceptingCall( (finalOptions: InterceptorOptions) => getBottomInterceptingCall( channel, - methodDefinition.path, finalOptions, methodDefinition ) From d8cf925b097462f713d8e2ce62fe93d356ef47ba Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 27 Feb 2020 09:50:35 -0800 Subject: [PATCH 0949/1899] Handle OK status differently when processing stream endings --- packages/grpc-js/src/call-stream.ts | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 2d30c2a56..87c0a5a01 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -460,6 +460,13 @@ export class Http2CallStream implements Call { }); stream.on('close', () => { this.trace('HTTP/2 stream closed with code ' + stream.rstCode); + /* If we have a final status with an OK status code, that means that + * we have received all of the messages and we have processed the + * trailers and the call completed successfully, so it doesn't matter + * how the stream ends after that */ + if (this.finalStatus?.code === Status.OK) { + return; + } let code: Status; let details = ''; switch (stream.rstCode) { @@ -532,9 +539,16 @@ export class Http2CallStream implements Call { // The http2 stream could already have been destroyed if cancelWithStatus // is called in response to an internal http2 error. if (this.http2Stream !== null && !this.http2Stream.destroyed) { - /* TODO(murgatroid99): Determine if we want to send different RST_STREAM - * codes based on the status code */ - this.http2Stream.close(NGHTTP2_CANCEL); + /* If the call has ended with an OK status, communicate that when closing + * the stream, partly to avoid a situation in which we detect an error + * RST_STREAM as a result after we have the status */ + let code: number; + if (this.finalStatus?.code === Status.OK) { + code = http2.constants.NGHTTP2_NO_ERROR; + } else { + code = http2.constants.NGHTTP2_CANCEL; + } + this.http2Stream.close(code); } } From 8adad0c9607682df094391f7354347e75342ebf8 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 28 Feb 2020 10:09:54 -0800 Subject: [PATCH 0950/1899] Don't stop handling reads when status is OK --- packages/grpc-js/src/call-stream.ts | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 87c0a5a01..99d1f8dd6 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -296,9 +296,10 @@ export class Http2CallStream implements Call { } private handleFilteredRead(message: Buffer) { - /* If we the call has already ended, we don't want to do anything with - * this message. Dropping it on the floor is correct behavior */ - if (this.finalStatus !== null) { + /* If we the call has already ended with an error, we don't want to do + * anything with this message. Dropping it on the floor is correct + * behavior */ + if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { this.maybeOutputStatus(); return; } @@ -321,9 +322,10 @@ export class Http2CallStream implements Call { } private filterReceivedMessage(framedMessage: Buffer) { - /* If we the call has already ended, we don't want to do anything with - * this message. Dropping it on the floor is correct behavior */ - if (this.finalStatus !== null) { + /* If we the call has already ended with an error, we don't want to do + * anything with this message. Dropping it on the floor is correct + * behavior */ + if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { this.maybeOutputStatus(); return; } @@ -586,9 +588,9 @@ export class Http2CallStream implements Call { } startRead() { - /* If we have already emitted a status, we should not emit any more + /* If the stream has ended with an error, we should not emit any more * messages and we should communicate that the stream has ended */ - if (this.finalStatus !== null) { + if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { this.readsClosed = true; this.maybeOutputStatus(); return; From f345f82851cc34261c0277e4d14c32d52142c7fd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Feb 2020 11:19:07 -0800 Subject: [PATCH 0951/1899] Use optional chaining --- packages/grpc-js/src/subchannel-pool.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index d7bccb22f..9c512934e 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -101,7 +101,8 @@ export class SubchannelPool { }, REF_CHECK_INTERVAL); // Unref because this timer should not keep the event loop running. - this.cleanupTimer.unref && this.cleanupTimer.unref(); + // Call unref only if it exists to address electron/electron#21162 + this.cleanupTimer.unref?.(); } } From fa3c95eaf242e77f4d350ee0e29153ac368b4f33 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 28 Feb 2020 11:20:57 -0800 Subject: [PATCH 0952/1899] Update grpc-js to 0.7.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 93182032f..40e41396f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.6.18", + "version": "0.7.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From b3bef54f3c7014b7d69096380d3e2ffd88d7a408 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 28 Feb 2020 15:41:18 -0800 Subject: [PATCH 0953/1899] Update PACKAGE-COMPARISON doc to cover features added in grpc-js 0.7 --- PACKAGE-COMPARISON.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index c741474b3..7c852ae47 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -12,9 +12,9 @@ Automatic Reconnection | :heavy_check_mark: | :heavy_check_mark: Per-message Compression | :heavy_check_mark: | only for response messages Channel State | :heavy_check_mark: | :heavy_check_mark: JWT Access and Service Account Credentials | provided by the [Google Auth Library](https://www.npmjs.com/package/google-auth-library) | provided by the [Google Auth Library](https://www.npmjs.com/package/google-auth-library) -Interceptors | :heavy_check_mark: | :x: +Interceptors | :heavy_check_mark: | :heavy_check_mark: Connection Keepalives | :heavy_check_mark: | :heavy_check_mark: -HTTP Connect Support | :heavy_check_mark: | :x: +HTTP Connect Support | :heavy_check_mark: | :heavy_check_mark: Retries | :heavy_check_mark: | :x: Stats/tracing/monitoring | :heavy_check_mark: | :x: Load Balancing | :heavy_check_mark: | Pick first and round robin From 8f668c8f2c80e3dc8df6a36f09849817b1059b36 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 2 Mar 2020 14:26:29 -0800 Subject: [PATCH 0954/1899] grpc-js: server calls: Don't try to send an error on stream error --- packages/grpc-js/src/server-call.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 50fbaf13f..efdf1bccb 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -346,8 +346,11 @@ export class Http2ServerCallStream< super(); this.stream.once('error', (err: ServerErrorResponse) => { - err.code = Status.INTERNAL; - this.sendError(err); + /* We need an error handler to avoid uncaught error event exceptions, but + * there is nothing we can reasonably do here. Any error event should + * have a corresponding close event, which handles emitting the cancelled + * event. And the stream is now in a bad state, so we can't reasonably + * expect to be able to send an error over it. */ }); this.stream.once('close', () => { From 4786f4a0058029c8e71f4e9cc22c57e2b9479bc5 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 2 Mar 2020 17:27:46 -0800 Subject: [PATCH 0955/1899] grpc_server_add_(in)secure_port returns 0 on error. Reflect that in bind(Async) --- packages/grpc-js/src/server.ts | 2 +- packages/grpc-native-core/src/server.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index a3274f142..d90a2c979 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -240,7 +240,7 @@ export class Server { this._setupHandlers(); function onError(err: Error): void { - callback(err, -1); + callback(err, 0); } this.http2Server.once('error', onError); diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index 81e563474..e7fd20941 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -970,7 +970,7 @@ Server.prototype.addProtoService = util.deprecate(function(service, * "address:port" * @param {grpc.ServerCredentials} creds Server credential object to be used for * SSL. Pass an insecure credentials object for an insecure port. - * @return {number} The bound port number. Negative if binding the port failed. + * @return {number} The bound port number. Zero if binding the port failed. */ Server.prototype.bind = function(port, creds) { if (this.started) { @@ -984,7 +984,7 @@ Server.prototype.bind = function(port, creds) { * @callback grpc.Server~bindCallback * @param {Error=} error If non-null, indicates that binding the port failed. * @param {number} port The bound port number. If binding the port fails, this - * will be negative to match the output of bind. + * will be zero to match the output of bind. */ /** @@ -1000,7 +1000,7 @@ Server.prototype.bindAsync = function(port, creds, callback) { * incorrect use of the function, which should not be surfaced asynchronously */ const result = this.bind(port, creds) - if (result < 0) { + if (result == 0) { setImmediate(callback, new Error('Failed to bind port'), result); } else { setImmediate(callback, null, result); From f2b740f6ceb190ae3a9ee092895397fa18c1b6c9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Mar 2020 10:15:22 -0800 Subject: [PATCH 0956/1899] grpc-js: Always return IPv6 addresses from DNS resolver --- packages/grpc-js/src/resolver-dns.ts | 16 +---- packages/grpc-js/test/test-resolver.ts | 88 ++++++++++++++++++++++++-- 2 files changed, 83 insertions(+), 21 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 7c51425c2..ebfd16dcf 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -21,7 +21,6 @@ import { registerDefaultResolver, } from './resolver'; import * as dns from 'dns'; -import * as semver from 'semver'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; import { ServiceError } from './call'; @@ -70,14 +69,6 @@ const DNS_REGEX = /^(?:dns:)?(?:\/\/(?:[a-zA-Z0-9-]+\.?)+\/)?((?:[a-zA-Z0-9-]+\. */ const DEFAULT_PORT = '443'; -/** - * The range of Node versions in which the Node issue - * https://github.com/nodejs/node/issues/28216 has been fixed. In other - * versions, IPv6 literal addresses cannot be used to establish HTTP/2 - * connections. - */ -const IPV6_SUPPORT_RANGE = '>= 12.6'; - /** * Get a promise that always resolves with either the result of the function * or the error if it failed. @@ -226,12 +217,7 @@ class DnsResolver implements Resolver { const ip4Addresses: dns.LookupAddress[] = addressList.filter( addr => addr.family === 4 ); - let ip6Addresses: dns.LookupAddress[]; - if (semver.satisfies(process.version, IPV6_SUPPORT_RANGE)) { - ip6Addresses = addressList.filter(addr => addr.family === 6); - } else { - ip6Addresses = []; - } + const ip6Addresses: dns.LookupAddress[] = addressList.filter(addr => addr.family === 6); const allAddresses: TcpSubchannelAddress[] = mergeArrays( ip4Addresses, ip6Addresses diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index ebb4d567f..21007a3da 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -46,7 +46,14 @@ describe('Name Resolver', () => { addr.port === 50051 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) + ); done(); }, onError: (error: StatusObject) => { @@ -72,7 +79,14 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); done(); }, onError: (error: StatusObject) => { @@ -98,7 +112,6 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, onError: (error: StatusObject) => { @@ -124,7 +137,6 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, onError: (error: StatusObject) => { @@ -150,7 +162,6 @@ describe('Name Resolver', () => { addr.port === 50051 ) ); - // We would check for the IPv6 address but it needs to be omitted on some Node versions done(); }, onError: (error: StatusObject) => { @@ -186,7 +197,72 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { - assert(addressList.length > 0); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a DNS name to an IPv6 address', done => { + const target = 'loopback6.unittest.grpc.io'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener); + resolver.updateResolution(); + }); + it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { + const target = 'loopback46.unittest.grpc.io'; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); done(); }, onError: (error: StatusObject) => { From 37cc5596692249b28453490e1d9124e71430171b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Mar 2020 10:52:13 -0800 Subject: [PATCH 0957/1899] grpc-js: Only automatically retry picks on known error --- packages/grpc-js/src/channel.ts | 51 +++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8420b909e..1d555ea2d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -265,29 +265,42 @@ export class ChannelImplementation implements Channel { callStream ); } catch (error) { - /* An error here indicates that something went wrong with - * the picked subchannel's http2 stream right before we - * tried to start the stream. We are handling a promise - * result here, so this is asynchronous with respect to the - * original tryPick call, so calling it again is not - * recursive. We call tryPick immediately instead of - * queueing this pick again because handling the queue is - * triggered by state changes, and we want to immediately - * check if the state has already changed since the - * previous tryPick call. We do this instead of cancelling - * the stream because the correct behavior may be - * re-queueing instead, based on the logic in the rest of - * tryPick */ - trace( - LogVerbosity.INFO, - 'channel', - 'Failed to start call on picked subchannel ' + + if ((error as NodeJS.ErrnoException).code === 'ERR_HTTP2_GOAWAY_SESSION') { + /* An error here indicates that something went wrong with + * the picked subchannel's http2 stream right before we + * tried to start the stream. We are handling a promise + * result here, so this is asynchronous with respect to the + * original tryPick call, so calling it again is not + * recursive. We call tryPick immediately instead of + * queueing this pick again because handling the queue is + * triggered by state changes, and we want to immediately + * check if the state has already changed since the + * previous tryPick call. We do this instead of cancelling + * the stream because the correct behavior may be + * re-queueing instead, based on the logic in the rest of + * tryPick */ + trace( + LogVerbosity.INFO, + 'channel', + 'Failed to start call on picked subchannel ' + pickResult.subchannel!.getAddress() + ' with error ' + (error as Error).message + '. Retrying pick' - ); - this.tryPick(callStream, callMetadata); + ); + this.tryPick(callStream, callMetadata); + } else { + trace( + LogVerbosity.INFO, + 'channel', + 'Failed to start call on picked subchanel ' + + pickResult.subchannel!.getAddress() + + ' with error ' + + (error as Error).message + + '. Ending call' + ); + callStream.cancelWithStatus(Status.INTERNAL, 'Failed to start HTTP/2 stream'); + } } } else { /* The logic for doing this here is the same as in the catch From c1d6bf91bce11208c3269140e34b9c2fa00d4467 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Wed, 4 Mar 2020 17:17:34 -0800 Subject: [PATCH 0958/1899] grpc-js: Use resolver to bind server ports --- packages/grpc-js/src/server.ts | 191 +++++++++++++++++++----- packages/grpc-native-core/src/server.js | 2 +- 2 files changed, 152 insertions(+), 41 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index d90a2c979..8e6af3d3f 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -20,7 +20,7 @@ import { AddressInfo, ListenOptions } from 'net'; import { URL } from 'url'; import { ServiceError } from './call'; -import { Status } from './constants'; +import { Status, LogVerbosity } from './constants'; import { Deserialize, Serialize, ServiceDefinition } from './make-client'; import { Metadata } from './metadata'; import { @@ -46,6 +46,14 @@ import { } from './server-call'; import { ServerCredentials } from './server-credentials'; import { ChannelOptions } from './channel-options'; +import { createResolver, ResolverListener } from './resolver'; +import { log } from './logging'; +import { SubchannelAddress, TcpSubchannelAddress, isTcpSubchannelAddress } from './subchannel'; + +interface BindResult { + port: number; + count: number; +} function noop(): void {} @@ -104,10 +112,8 @@ function getDefaultHandler(handlerType: HandlerType, methodName: string) { // tslint:enable:no-any export class Server { - private http2Server: - | http2.Http2Server - | http2.Http2SecureServer - | null = null; + private http2ServerList: (http2.Http2Server | http2.Http2SecureServer)[] = []; + private handlers: Map = new Map< string, UntypedHandler @@ -217,8 +223,6 @@ export class Server { throw new TypeError('callback must be a function'); } - const url = new URL(`http://${port}`); - const options: ListenOptions = { host: url.hostname, port: +url.port }; const serverOptions: http2.ServerOptions = {}; if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { @@ -226,40 +230,147 @@ export class Server { }; } - if (creds._isSecure()) { - const secureServerOptions = Object.assign( - serverOptions, - creds._getSettings()! - ); - this.http2Server = http2.createSecureServer(secureServerOptions); - } else { - this.http2Server = http2.createServer(serverOptions); + const setupServer = (): http2.Http2Server | http2.Http2SecureServer => { + let http2Server: http2.Http2Server | http2.Http2SecureServer; + if (creds._isSecure()) { + const secureServerOptions = Object.assign( + serverOptions, + creds._getSettings()! + ); + http2Server = http2.createSecureServer(secureServerOptions); + } else { + http2Server = http2.createServer(serverOptions); + } + + http2Server.setTimeout(0, noop); + this._setupHandlers(http2Server); + return http2Server; } - this.http2Server.setTimeout(0, noop); - this._setupHandlers(); + const bindSpecificPort = (addressList: SubchannelAddress[], portNum: number, previousCount: number): Promise => { + if (addressList.length === 0) { + if (previousCount > 0) { + return Promise.resolve({port: portNum, count: previousCount}); + } else { + return Promise.reject(new Error('No addresses bound')); + } + } + return Promise.all(addressList.map(address => { + let addr: SubchannelAddress; + if (isTcpSubchannelAddress(address)) { + addr = { + host: (address as TcpSubchannelAddress).host, + port: portNum + }; + } else { + addr = address + } + + const http2Server = setupServer(); + return new Promise((resolve, reject) => { + function onError(err: Error): void { + resolve(err); + } - function onError(err: Error): void { - callback(err, 0); + http2Server.once('error', onError); + + http2Server.listen(addr, () => { + const boundAddress = http2Server.address()!; + if (typeof boundAddress === 'string') { + resolve(portNum); + } else { + resolve(boundAddress.port); + } + http2Server.removeListener('error', onError); + }); + }) + })).then(results => { + let count = 0; + for (const result of results) { + if (typeof result === 'number') { + count += 1; + if (result !== portNum) { + throw new Error('Invalid state: multiple port numbers added from single address'); + } + } + } + return { + port: portNum, + count: count + previousCount + }; + }); } - this.http2Server.once('error', onError); + const bindWildcardPort = (addressList: SubchannelAddress[]): Promise => { + if (addressList.length === 0) { + return Promise.reject(new Error('No addresses bound')); + } + const address = addressList[0]; + const http2Server = setupServer(); + return new Promise((resolve, reject) => { + function onError(err: Error): void { + resolve(bindWildcardPort(addressList.slice(1))); + } + + http2Server.once('error', onError); - this.http2Server.listen(options, () => { - const server = this.http2Server as - | http2.Http2Server - | http2.Http2SecureServer; - const port = (server.address() as AddressInfo).port; + http2Server.listen(address, () => { + resolve(bindSpecificPort(addressList.slice(1), (http2Server.address() as AddressInfo).port, 1)); + http2Server.removeListener('error', onError); + }); + }); + } - server.removeListener('error', onError); - callback(null, port); - }); + const resolverListener: ResolverListener = { + onSuccessfulResolution: (addressList, serviceConfig, serviceConfigError) => { + if (addressList.length === 0) { + callback(new Error(`No addresses resolved for port ${port}`), 0); + return; + } + let bindResultPromise: Promise; + if (isTcpSubchannelAddress(addressList[0])) { + if (addressList[0].port === 0) { + bindResultPromise = bindWildcardPort(addressList); + } else { + bindResultPromise = bindSpecificPort(addressList, addressList[0].port, 0); + } + } else{ + // Use an arbitrary non-zero port for non-TCP addresses + bindResultPromise = bindSpecificPort(addressList, 1, 0); + } + bindResultPromise.then(bindResult => { + if (bindResult.count === 0) { + const errorString = `No address added out of total ${addressList.length} resolved`; + log(LogVerbosity.ERROR, errorString); + callback(new Error(errorString), 0); + } else { + if (bindResult.count < addressList.length) { + log(LogVerbosity.INFO, `WARNING Only ${bindResult.count} addresses added out of total ${addressList.length} resolved`); + } + callback(null, bindResult.port); + } + }, (error) => { + const errorString = `No address added out of total ${addressList.length} resolved`; + log(LogVerbosity.ERROR, errorString); + callback(new Error(errorString), 0); + }); + }, + onError: (error) => { + callback(new Error(error.details), 0); + } + }; + + const resolver = createResolver(port, resolverListener); + resolver.updateResolution(); } forceShutdown(): void { // Close the server if it is still running. - if (this.http2Server && this.http2Server.listening) { - this.http2Server.close(); + + for (const http2Server of this.http2ServerList) { + if (http2Server.listening) { + http2Server.close(); + } } this.started = false; @@ -296,7 +407,7 @@ export class Server { } start(): void { - if (this.http2Server === null || this.http2Server.listening !== true) { + if (this.http2ServerList.length === 0 || this.http2ServerList.every(http2Server => http2Server.listening !== true)) { throw new Error('server must be bound in order to start'); } @@ -321,9 +432,11 @@ export class Server { // Close the server if necessary. this.started = false; - if (this.http2Server && this.http2Server.listening) { - pendingChecks++; - this.http2Server.close(maybeCallback); + for (const http2Server of this.http2ServerList) { + if (http2Server.listening) { + pendingChecks++; + http2Server.close(maybeCallback); + } } // If any sessions are active, close them gracefully. @@ -331,8 +444,6 @@ export class Server { this.sessions.forEach(session => { session.close(maybeCallback); }); - - // If the server is closed and there are no active sessions, just call back. if (pendingChecks === 0) { callback(); } @@ -342,12 +453,12 @@ export class Server { throw new Error('Not yet implemented'); } - private _setupHandlers(): void { - if (this.http2Server === null) { + private _setupHandlers(http2Server: http2.Http2Server | http2.Http2SecureServer): void { + if (http2Server === null) { return; } - this.http2Server.on( + http2Server.on( 'stream', (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; @@ -416,7 +527,7 @@ export class Server { } ); - this.http2Server.on('session', session => { + http2Server.on('session', session => { if (!this.started) { session.destroy(); return; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js index e7fd20941..d72de018e 100644 --- a/packages/grpc-native-core/src/server.js +++ b/packages/grpc-native-core/src/server.js @@ -1000,7 +1000,7 @@ Server.prototype.bindAsync = function(port, creds, callback) { * incorrect use of the function, which should not be surfaced asynchronously */ const result = this.bind(port, creds) - if (result == 0) { + if (result === 0) { setImmediate(callback, new Error('Failed to bind port'), result); } else { setImmediate(callback, null, result); From 3cbb46b1f78bef6cd75c715769eaac9baf4cbd70 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 5 Mar 2020 12:32:08 -0800 Subject: [PATCH 0959/1899] Don't explicitly reject any promises --- packages/grpc-js/src/server.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8e6af3d3f..fd2af1fc2 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -249,11 +249,7 @@ export class Server { const bindSpecificPort = (addressList: SubchannelAddress[], portNum: number, previousCount: number): Promise => { if (addressList.length === 0) { - if (previousCount > 0) { - return Promise.resolve({port: portNum, count: previousCount}); - } else { - return Promise.reject(new Error('No addresses bound')); - } + return Promise.resolve({port: portNum, count: previousCount}); } return Promise.all(addressList.map(address => { let addr: SubchannelAddress; @@ -303,7 +299,7 @@ export class Server { const bindWildcardPort = (addressList: SubchannelAddress[]): Promise => { if (addressList.length === 0) { - return Promise.reject(new Error('No addresses bound')); + return Promise.resolve({port: 0, count: 0}); } const address = addressList[0]; const http2Server = setupServer(); From 96d4d6acbaa5288f007941d4e360b3af49f5a55c Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 5 Mar 2020 13:01:43 -0800 Subject: [PATCH 0960/1899] Actually add listening http2 servers to server list --- packages/grpc-js/src/server.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index fd2af1fc2..62ed68ab3 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -271,6 +271,7 @@ export class Server { http2Server.once('error', onError); http2Server.listen(addr, () => { + this.http2ServerList.push(http2Server); const boundAddress = http2Server.address()!; if (typeof boundAddress === 'string') { resolve(portNum); @@ -311,6 +312,7 @@ export class Server { http2Server.once('error', onError); http2Server.listen(address, () => { + this.http2ServerList.push(http2Server); resolve(bindSpecificPort(addressList.slice(1), (http2Server.address() as AddressInfo).port, 1)); http2Server.removeListener('error', onError); }); From d02da04c8cdd28a661c7156103c542ad416eced2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 5 Mar 2020 15:19:59 -0800 Subject: [PATCH 0961/1899] Update grpc-js to 0.7.1 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 40e41396f..dfcfa19e3 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.0", + "version": "0.7.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From ca18cca8130ed7ca834c4ef679d0c6423b8461aa Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Tue, 10 Mar 2020 10:47:17 -0700 Subject: [PATCH 0962/1899] grpc-js: tests: skip checking for IPv6 addresses from DNS servers --- packages/grpc-js/test/test-resolver.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 21007a3da..7d7343c05 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -214,7 +214,9 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener); resolver.updateResolution(); }); - it('Should resolve a DNS name to an IPv6 address', done => { + /* TODO(murgatroid99): re-enable this test, once we can get the IPv6 result + * consistently */ + it.skip('Should resolve a DNS name to an IPv6 address', done => { const target = 'loopback6.unittest.grpc.io'; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -255,14 +257,8 @@ describe('Name Resolver', () => { addr.port === 443 ) ); - assert( - addressList.some( - addr => - isTcpSubchannelAddress(addr) && - addr.host === '::1' && - addr.port === 443 - ) - ); + /* TODO(murgatroid99): check for IPv6 result, once we can get that + * consistently */ done(); }, onError: (error: StatusObject) => { From 0c3b93fc3ade319c0739b6542d7b65ee07edae39 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 13 Mar 2020 13:46:09 -0700 Subject: [PATCH 0963/1899] proto-loader: Warn if file not found in imports --- packages/proto-loader/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index c5533a5e0..b29e26f33 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -302,6 +302,7 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { continue; } } + process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); return originalResolvePath(origin, target); }; } From a2a408b7774c3f8c824bd077dd9e347161d066a7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 16 Mar 2020 12:07:35 -0700 Subject: [PATCH 0964/1899] grpc-js: Add callInvocationTransformer option --- packages/grpc-js/src/call.ts | 38 +++---- packages/grpc-js/src/client.ts | 183 +++++++++++++++++++++++---------- 2 files changed, 149 insertions(+), 72 deletions(-) diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 921e19715..61885cd6e 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -34,6 +34,7 @@ export type ServiceError = StatusObject & Error; * A base type for all user-facing values returned by client-side method calls. */ export type SurfaceCall = { + call?: InterceptingCallInterface; cancel(): void; getPeer(): string; } & EmitterAugmentation1<'metadata', Metadata> & @@ -82,56 +83,57 @@ export function callErrorFromStatus(status: StatusObject): ServiceError { export class ClientUnaryCallImpl extends EventEmitter implements ClientUnaryCall { - constructor(private readonly call: InterceptingCallInterface) { + public call?: InterceptingCallInterface; + constructor() { super(); } cancel(): void { - this.call.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); + this.call?.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); } getPeer(): string { - return this.call.getPeer(); + return this.call?.getPeer() ?? ''; } } export class ClientReadableStreamImpl extends Readable implements ClientReadableStream { + public call?: InterceptingCallInterface; constructor( - private readonly call: InterceptingCallInterface, readonly deserialize: (chunk: Buffer) => ResponseType ) { super({ objectMode: true }); } cancel(): void { - this.call.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); + this.call?.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); } getPeer(): string { - return this.call.getPeer(); + return this.call?.getPeer() ?? ''; } _read(_size: number): void { - this.call.startRead(); + this.call?.startRead(); } } export class ClientWritableStreamImpl extends Writable implements ClientWritableStream { + public call?: InterceptingCallInterface; constructor( - private readonly call: InterceptingCallInterface, readonly serialize: (value: RequestType) => Buffer ) { super({ objectMode: true }); } cancel(): void { - this.call.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); + this.call?.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); } getPeer(): string { - return this.call.getPeer(); + return this.call?.getPeer() ?? ''; } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { @@ -142,19 +144,19 @@ export class ClientWritableStreamImpl extends Writable if (!Number.isNaN(flags)) { context.flags = flags; } - this.call.sendMessageWithContext(context, chunk); + this.call?.sendMessageWithContext(context, chunk); } _final(cb: Function) { - this.call.halfClose(); + this.call?.halfClose(); cb(); } } export class ClientDuplexStreamImpl extends Duplex implements ClientDuplexStream { + public call?: InterceptingCallInterface; constructor( - private readonly call: InterceptingCallInterface, readonly serialize: (value: RequestType) => Buffer, readonly deserialize: (chunk: Buffer) => ResponseType ) { @@ -162,15 +164,15 @@ export class ClientDuplexStreamImpl extends Duplex } cancel(): void { - this.call.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); + this.call?.cancelWithStatus(Status.CANCELLED, 'Cancelled on client'); } getPeer(): string { - return this.call.getPeer(); + return this.call?.getPeer() ?? ''; } _read(_size: number): void { - this.call.startRead(); + this.call?.startRead(); } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { @@ -181,11 +183,11 @@ export class ClientDuplexStreamImpl extends Duplex if (!Number.isNaN(flags)) { context.flags = flags; } - this.call.sendMessageWithContext(context, chunk); + this.call?.sendMessageWithContext(context, chunk); } _final(cb: Function) { - this.call.halfClose(); + this.call?.halfClose(); cb(); } } diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 1ba7bd326..77a5571fe 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -40,7 +40,7 @@ import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; -import { ClientMethodDefinition } from './make-client'; +import { ClientMethodDefinition, MethodDefinition } from './make-client'; import { getInterceptingCall, Interceptor, @@ -52,6 +52,7 @@ import { const CHANNEL_SYMBOL = Symbol(); const INTERCEPTOR_SYMBOL = Symbol(); const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); +const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); export interface UnaryCallback { (err: ServiceError | null, value?: ResponseType): void; @@ -68,6 +69,20 @@ export interface CallOptions { interceptor_providers?: InterceptorProvider[]; } +export interface CallProperties { + argument?: RequestType; + metadata: Metadata; + call: SurfaceCall; + channel: Channel; + methodDefinition: ClientMethodDefinition; + callOptions: CallOptions; + callback?: UnaryCallback +} + +export interface CallInvocationTransformer { + (callProperties: CallProperties): CallProperties +} + export type ClientOptions = Partial & { channelOverride?: Channel; channelFactoryOverride?: ( @@ -77,6 +92,7 @@ export type ClientOptions = Partial & { ) => Channel; interceptors?: Interceptor[]; interceptor_providers?: InterceptorProvider[]; + callInvocationTransformer?: CallInvocationTransformer; }; /** @@ -87,6 +103,7 @@ export class Client { private readonly [CHANNEL_SYMBOL]: Channel; private readonly [INTERCEPTOR_SYMBOL]: Interceptor[]; private readonly [INTERCEPTOR_PROVIDER_SYMBOL]: InterceptorProvider[]; + private readonly [CALL_INVOCATION_TRANSFORMER_SYMBOL]?: CallInvocationTransformer; constructor( address: string, credentials: ChannelCredentials, @@ -118,6 +135,7 @@ export class Client { 'to the client constructor. Only one of these is allowed.' ); } + this[CALL_INVOCATION_TRANSFORMER_SYMBOL] = options.callInvocationTransformer; } close(): void { @@ -230,9 +248,9 @@ export class Client { options?: CallOptions | UnaryCallback, callback?: UnaryCallback ): ClientUnaryCall { - ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< + const checkedArguments = this.checkOptionalUnaryResponseArguments< ResponseType - >(metadata, options, callback)); + >(metadata, options, callback); const methodDefinition: ClientMethodDefinition< RequestType, ResponseType @@ -243,25 +261,42 @@ export class Client { requestSerialize: serialize, responseDeserialize: deserialize, }; + let callProperties: CallProperties = { + argument: argument, + metadata: checkedArguments.metadata, + call: new ClientUnaryCallImpl(), + channel: this[CHANNEL_SYMBOL], + methodDefinition: methodDefinition, + callOptions: checkedArguments.options, + callback: checkedArguments.callback + }; + if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + } + const emitter: ClientUnaryCall = callProperties.call; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [], + callInterceptors: callProperties.callOptions.interceptors ?? [], + callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, - methodDefinition, - options, - this[CHANNEL_SYMBOL] + callProperties.methodDefinition, + callProperties.callOptions, + callProperties.channel ); - if (options.credentials) { - call.setCredentials(options.credentials); + /* This needs to happen before the emitter is used. Unfortunately we can't + * enforce this with the type system. We need to construct this emitter + * before calling the CallInvocationTransformer, and we need to create the + * call after that. */ + emitter.call = call; + if (callProperties.callOptions.credentials) { + call.setCredentials(callProperties.callOptions.credentials); } - const emitter = new ClientUnaryCallImpl(call); let responseMessage: ResponseType | null = null; let receivedStatus = false; - call.start(metadata, { + call.start(callProperties.metadata, { onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, @@ -278,9 +313,9 @@ export class Client { } receivedStatus = true; if (status.code === Status.OK) { - callback!(null, responseMessage!); + callProperties.callback!(null, responseMessage!); } else { - callback!(callErrorFromStatus(status)); + callProperties.callback!(callErrorFromStatus(status)); } emitter.emit('status', status); }, @@ -326,9 +361,9 @@ export class Client { options?: CallOptions | UnaryCallback, callback?: UnaryCallback ): ClientWritableStream { - ({ metadata, options, callback } = this.checkOptionalUnaryResponseArguments< + const checkedArguments = this.checkOptionalUnaryResponseArguments< ResponseType - >(metadata, options, callback)); + >(metadata, options, callback); const methodDefinition: ClientMethodDefinition< RequestType, ResponseType @@ -339,25 +374,41 @@ export class Client { requestSerialize: serialize, responseDeserialize: deserialize, }; + let callProperties: CallProperties = { + metadata: checkedArguments.metadata, + call: new ClientWritableStreamImpl(serialize), + channel: this[CHANNEL_SYMBOL], + methodDefinition: methodDefinition, + callOptions: checkedArguments.options, + callback: checkedArguments.callback + }; + if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + } + const emitter: ClientWritableStream = callProperties.call as ClientWritableStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [], + callInterceptors: callProperties.callOptions.interceptors ?? [], + callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, - methodDefinition, - options, - this[CHANNEL_SYMBOL] + callProperties.methodDefinition, + callProperties.callOptions, + callProperties.channel ); - if (options.credentials) { - call.setCredentials(options.credentials); + /* This needs to happen before the emitter is used. Unfortunately we can't + * enforce this with the type system. We need to construct this emitter + * before calling the CallInvocationTransformer, and we need to create the + * call after that. */ + emitter.call = call; + if (callProperties.callOptions.credentials) { + call.setCredentials(callProperties.callOptions.credentials); } - const emitter = new ClientWritableStreamImpl(call, serialize); let responseMessage: ResponseType | null = null; let receivedStatus = false; - call.start(metadata, { + call.start(callProperties.metadata, { onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, @@ -374,9 +425,9 @@ export class Client { } receivedStatus = true; if (status.code === Status.OK) { - callback!(null, responseMessage!); + callProperties.callback!(null, responseMessage!); } else { - callback!(callErrorFromStatus(status)); + callProperties.callback!(callErrorFromStatus(status)); } emitter.emit('status', status); }, @@ -431,7 +482,7 @@ export class Client { metadata?: Metadata | CallOptions, options?: CallOptions ): ClientReadableStream { - ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); + const checkedArguments = this.checkMetadataAndOptions(metadata, options); const methodDefinition: ClientMethodDefinition< RequestType, ResponseType @@ -442,27 +493,40 @@ export class Client { requestSerialize: serialize, responseDeserialize: deserialize, }; + let callProperties: CallProperties = { + argument: argument, + metadata: checkedArguments.metadata, + call: new ClientReadableStreamImpl(deserialize), + channel: this[CHANNEL_SYMBOL], + methodDefinition: methodDefinition, + callOptions: checkedArguments.options + }; + if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + } + const stream: ClientReadableStream = callProperties.call as ClientReadableStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [], + callInterceptors: callProperties.callOptions.interceptors ?? [], + callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, - methodDefinition, - options, - this[CHANNEL_SYMBOL] + callProperties.methodDefinition, + callProperties.callOptions, + callProperties.channel ); - if (options.credentials) { - call.setCredentials(options.credentials); + /* This needs to happen before the emitter is used. Unfortunately we can't + * enforce this with the type system. We need to construct this emitter + * before calling the CallInvocationTransformer, and we need to create the + * call after that. */ + stream.call = call; + if (callProperties.callOptions.credentials) { + call.setCredentials(callProperties.callOptions.credentials); } - const stream = new ClientReadableStreamImpl( - call, - deserialize - ); let receivedStatus = false; - call.start(metadata, { + call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); }, @@ -509,7 +573,7 @@ export class Client { metadata?: Metadata | CallOptions, options?: CallOptions ): ClientDuplexStream { - ({ metadata, options } = this.checkMetadataAndOptions(metadata, options)); + const checkedArguments = this.checkMetadataAndOptions(metadata, options); const methodDefinition: ClientMethodDefinition< RequestType, ResponseType @@ -520,28 +584,39 @@ export class Client { requestSerialize: serialize, responseDeserialize: deserialize, }; + let callProperties: CallProperties = { + metadata: checkedArguments.metadata, + call: new ClientDuplexStreamImpl(serialize, deserialize), + channel: this[CHANNEL_SYMBOL], + methodDefinition: methodDefinition, + callOptions: checkedArguments.options + }; + if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + } + const stream: ClientDuplexStream = callProperties.call as ClientDuplexStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], - callInterceptors: options.interceptors ?? [], - callInterceptorProviders: options.interceptor_providers ?? [], + callInterceptors: callProperties.callOptions.interceptors ?? [], + callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, - methodDefinition, - options, - this[CHANNEL_SYMBOL] + callProperties.methodDefinition, + callProperties.callOptions, + callProperties.channel ); - if (options.credentials) { - call.setCredentials(options.credentials); + /* This needs to happen before the emitter is used. Unfortunately we can't + * enforce this with the type system. We need to construct this emitter + * before calling the CallInvocationTransformer, and we need to create the + * call after that. */ + stream.call = call; + if (callProperties.callOptions.credentials) { + call.setCredentials(callProperties.callOptions.credentials); } - const stream = new ClientDuplexStreamImpl( - call, - serialize, - deserialize - ); let receivedStatus = false; - call.start(metadata, { + call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); }, From 625610209b4b9e8dc2e47a1ca34f1acbcdd128f3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 16 Mar 2020 14:31:51 -0700 Subject: [PATCH 0965/1899] grpc-js: Unref deadline filter timer optionally --- packages/grpc-js/src/deadline-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index f659c8669..9dd548c95 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -66,7 +66,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { 'Deadline exceeded' ); }, timeout); - this.timer.unref(); + this.timer.unref?.(); } } From a99afaf5eb3ea7172dea7c6d0f81f313043a5ee5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 19 Mar 2020 09:42:17 -0700 Subject: [PATCH 0966/1899] grpc-js: Make filter stack handle status in all code paths --- packages/grpc-js/src/call-stream.ts | 19 +++++-- packages/grpc-js/src/channel.ts | 2 - packages/grpc-js/src/deadline-filter.ts | 9 +++- .../grpc-js/src/metadata-status-filter.ts | 54 ------------------- 4 files changed, 24 insertions(+), 60 deletions(-) delete mode 100644 packages/grpc-js/src/metadata-status-filter.ts diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 99d1f8dd6..70c728e02 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -224,7 +224,8 @@ export class Http2CallStream implements Call { /* Precondition: this.finalStatus !== null */ if (!this.statusOutput) { this.statusOutput = true; - this.listener!.onReceiveStatus(this.finalStatus!); + const filteredStatus = this.filterStack.receiveTrailers(this.finalStatus!); + this.listener!.onReceiveStatus(filteredStatus); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -353,14 +354,26 @@ export class Http2CallStream implements Call { private handleTrailers(headers: http2.IncomingHttpHeaders) { this.trace('received HTTP/2 trailing headers frame'); - const code: Status = this.mappedStatusCode; - const details = ''; let metadata: Metadata; try { metadata = Metadata.fromHttp2Headers(headers); } catch (e) { metadata = new Metadata(); } + const metadataMap = metadata.getMap(); + let code: Status = this.mappedStatusCode; + if (code === Status.UNKNOWN && typeof metadataMap['grpc-status'] === 'string') { + const receivedStatus = Number(metadataMap['grpc-status']); + if (receivedStatus in Status) { + code = receivedStatus; + } + metadata.remove('grpc-status'); + } + let details = ''; + if (typeof metadataMap['grpc-message'] === 'string') { + details = decodeURI(metadataMap['grpc-message']); + metadata.remove('grpc-message'); + } const status: StatusObject = { code, details, metadata }; let finalStatus; try { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 1d555ea2d..ad45f654a 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -32,7 +32,6 @@ import { Status, LogVerbosity } from './constants'; import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; -import { MetadataStatusFilterFactory } from './metadata-status-filter'; import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority } from './resolver'; import { LoadBalancingConfig } from './load-balancing-config'; @@ -192,7 +191,6 @@ export class ChannelImplementation implements Channel { this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), - new MetadataStatusFilterFactory(this), new CompressionFilterFactory(this), ]); // TODO(murgatroid99): Add more centralized handling of channel options diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index f659c8669..b5e4cabcb 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -15,7 +15,7 @@ * */ -import { Call } from './call-stream'; +import { Call, StatusObject } from './call-stream'; import { ConnectivityState, Channel } from './channel'; import { Status } from './constants'; import { BaseFilter, Filter, FilterFactory } from './filter'; @@ -82,6 +82,13 @@ export class DeadlineFilter extends BaseFilter implements Filter { finalMetadata.set('grpc-timeout', timeoutString); return finalMetadata; } + + receiveTrailers(status: StatusObject) { + if (this.timer) { + clearTimeout(this.timer); + } + return status; + } } export class DeadlineFilterFactory implements FilterFactory { diff --git a/packages/grpc-js/src/metadata-status-filter.ts b/packages/grpc-js/src/metadata-status-filter.ts deleted file mode 100644 index f3879d7a9..000000000 --- a/packages/grpc-js/src/metadata-status-filter.ts +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Call } from './call-stream'; -import { StatusObject } from './call-stream'; -import { Channel } from './channel'; -import { Status } from './constants'; -import { BaseFilter, Filter, FilterFactory } from './filter'; - -export class MetadataStatusFilter extends BaseFilter implements Filter { - receiveTrailers(status: StatusObject): StatusObject { - // tslint:disable-next-line:prefer-const - let { code, details, metadata } = status; - if (code !== Status.UNKNOWN) { - // we already have a known status, so don't assign a new one. - return { code, details, metadata }; - } - const metadataMap = metadata.getMap(); - if (typeof metadataMap['grpc-status'] === 'string') { - const receivedCode = Number(metadataMap['grpc-status']); - if (receivedCode in Status) { - code = receivedCode; - } - metadata.remove('grpc-status'); - } - if (typeof metadataMap['grpc-message'] === 'string') { - details = decodeURI(metadataMap['grpc-message'] as string); - metadata.remove('grpc-message'); - } - return { code, details, metadata }; - } -} - -export class MetadataStatusFilterFactory - implements FilterFactory { - constructor(private readonly channel: Channel) {} - createFilter(callStream: Call): MetadataStatusFilter { - return new MetadataStatusFilter(); - } -} From d47db25268775d75c2e98fcbbd4cd00386d900de Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 19 Mar 2020 13:00:02 -0700 Subject: [PATCH 0967/1899] grpc-js: Bump to 0.7.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index dfcfa19e3..6f5b1f3ab 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.1", + "version": "0.7.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 881cde4e1f863e8eec4e1e3bcc5bb43e2fa5fe18 Mon Sep 17 00:00:00 2001 From: jiangtaoli2016 Date: Thu, 19 Mar 2020 13:12:09 -0700 Subject: [PATCH 0968/1899] Update test credentials --- test/data/ca.pem | 31 ++++++++++++++++++------------- test/data/server1.key | 40 ++++++++++++++++++++++++++-------------- test/data/server1.pem | 34 ++++++++++++++++++++-------------- 3 files changed, 64 insertions(+), 41 deletions(-) diff --git a/test/data/ca.pem b/test/data/ca.pem index 6c8511a73..49d39cd8e 100644 --- a/test/data/ca.pem +++ b/test/data/ca.pem @@ -1,15 +1,20 @@ -----BEGIN CERTIFICATE----- -MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla -Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 -YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT -BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 -+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu -g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd -Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau -sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m -oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG -Dfcog5wrJytaQ6UA0wE= +MIIDWjCCAkKgAwIBAgIUWrP0VvHcy+LP6UuYNtiL9gBhD5owDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw +MDMxNzE4NTk1MVoXDTMwMDMxNTE4NTk1MVowVjELMAkGA1UEBhMCQVUxEzARBgNV +BAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0 +ZDEPMA0GA1UEAwwGdGVzdGNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAsGL0oXflF0LzoM+Bh+qUU9yhqzw2w8OOX5mu/iNCyUOBrqaHi7mGHx73GD01 +diNzCzvlcQqdNIH6NQSL7DTpBjca66jYT9u73vZe2MDrr1nVbuLvfu9850cdxiUO +Inv5xf8+sTHG0C+a+VAvMhsLiRjsq+lXKRJyk5zkbbsETybqpxoJ+K7CoSy3yc/k +QIY3TipwEtwkKP4hzyo6KiGd/DPexie4nBUInN3bS1BUeNZ5zeaIC2eg3bkeeW7c +qT55b+Yen6CxY0TEkzBK6AKt/WUialKMgT0wbTxRZO7kUCH3Sq6e/wXeFdJ+HvdV +LPlAg5TnMaNpRdQih/8nRFpsdwIDAQABoyAwHjAMBgNVHRMEBTADAQH/MA4GA1Ud +DwEB/wQEAwICBDANBgkqhkiG9w0BAQsFAAOCAQEAkTrKZjBrJXHps/HrjNCFPb5a +THuGPCSsepe1wkKdSp1h4HGRpLoCgcLysCJ5hZhRpHkRihhef+rFHEe60UePQO3S +CVTtdJB4CYWpcNyXOdqefrbJW5QNljxgi6Fhvs7JJkBqdXIkWXtFk2eRgOIP2Eo9 +/OHQHlYnwZFrk6sp4wPyR+A95S0toZBcyDVz7u+hOW0pGK3wviOe9lvRgj/H3Pwt +bewb0l+MhRig0/DVHamyVxrDRbqInU1/GTNCwcZkXKYFWSf92U+kIcTth24Q1gcw +eZiLl5FfrWokUNytFElXob0V0a5/kbhiLc3yWmvWqHTpqCALbVyF+rKJo2f5Kw== -----END CERTIFICATE----- diff --git a/test/data/server1.key b/test/data/server1.key index 143a5b876..086462992 100644 --- a/test/data/server1.key +++ b/test/data/server1.key @@ -1,16 +1,28 @@ -----BEGIN PRIVATE KEY----- -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD -M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf -3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY -AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm -V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY -tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p -dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q -K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR -81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff -DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd -aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 -ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 -XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe -F98XJ7tIFfJq +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDnE443EknxvxBq +6+hvn/t09hl8hx366EBYvZmVM/NC+7igXRAjiJiA/mIaCvL3MS0Iz5hBLxSGICU+ +WproA3GCIFITIwcf/ETyWj/5xpgZ4AKrLrjQmmX8mhwUajfF3UvwMJrCOVqPp67t +PtP+2kBXaqrXdvnvXR41FsIB8V7zIAuIZB6bHQhiGVlc1sgZYsE2EGG9WMmHtS86 +qkAOTjG2XyjmPTGAwhGDpYkYrpzp99IiDh4/Veai81hn0ssQkbry0XRD/Ig3jcHh +23WiriPNJ0JsbgXUSLKRPZObA9VgOLy2aXoN84IMaeK3yy+cwSYG/99w93fUZJte +MXwz4oYZAgMBAAECggEBAIVn2Ncai+4xbH0OLWckabwgyJ4IM9rDc0LIU368O1kU +koais8qP9dujAWgfoh3sGh/YGgKn96VnsZjKHlyMgF+r4TaDJn3k2rlAOWcurGlj +1qaVlsV4HiEzp7pxiDmHhWvp4672Bb6iBG+bsjCUOEk/n9o9KhZzIBluRhtxCmw5 +nw4Do7z00PTvN81260uPWSc04IrytvZUiAIx/5qxD72bij2xJ8t/I9GI8g4FtoVB +8pB6S/hJX1PZhh9VlU6Yk+TOfOVnbebG4W5138LkB835eqk3Zz0qsbc2euoi8Hxi +y1VGwQEmMQ63jXz4c6g+X55ifvUK9Jpn5E8pq+pMd7ECgYEA93lYq+Cr54K4ey5t +sWMa+ye5RqxjzgXj2Kqr55jb54VWG7wp2iGbg8FMlkQwzTJwebzDyCSatguEZLuB +gRGroRnsUOy9vBvhKPOch9bfKIl6qOgzMJB267fBVWx5ybnRbWN/I7RvMQf3k+9y +biCIVnxDLEEYyx7z85/5qxsXg/MCgYEA7wmWKtCTn032Hy9P8OL49T0X6Z8FlkDC +Rk42ygrc/MUbugq9RGUxcCxoImOG9JXUpEtUe31YDm2j+/nbvrjl6/bP2qWs0V7l +dTJl6dABP51pCw8+l4cWgBBX08Lkeen812AAFNrjmDCjX6rHjWHLJcpS18fnRRkP +V1d/AHWX7MMCgYEA6Gsw2guhp0Zf2GCcaNK5DlQab8OL4Hwrpttzo4kuTlwtqNKp +Q9H4al9qfF4Cr1TFya98+EVYf8yFRM3NLNjZpe3gwYf2EerlJj7VLcahw0KKzoN1 +QBENfwgPLRk5sDkx9VhSmcfl/diLroZdpAwtv3vo4nEoxeuGFbKTGx3Qkf0CgYEA +xyR+dcb05Ygm3w4klHQTowQ10s1H80iaUcZBgQuR1ghEtDbUPZHsoR5t1xCB02ys +DgAwLv1bChIvxvH/L6KM8ovZ2LekBX4AviWxoBxJnfz/EVau98B0b1auRN6eSC83 +FRuGldlSOW1z/nSh8ViizSYE5H5HX1qkXEippvFRE88CgYB3Bfu3YQY60ITWIShv +nNkdcbTT9eoP9suaRJjw92Ln+7ZpALYlQMKUZmJ/5uBmLs4RFwUTQruLOPL4yLTH +awADWUzs3IRr1fwn9E+zM8JVyKCnUEM3w4N5UZskGO2klashAd30hWO+knRv/y0r +uGIYs9Ek7YXlXIRVrzMwcsrt1w== -----END PRIVATE KEY----- diff --git a/test/data/server1.pem b/test/data/server1.pem index f3d43fcc5..88244f856 100644 --- a/test/data/server1.pem +++ b/test/data/server1.pem @@ -1,16 +1,22 @@ -----BEGIN CERTIFICATE----- -MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx -MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 -ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco -LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg -zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd -9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw -CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy -em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G -CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 -hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh -y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 +MIIDtDCCApygAwIBAgIUbJfTREJ6k6/+oInWhV1O1j3ZT0IwDQYJKoZIhvcNAQEL +BQAwVjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEPMA0GA1UEAwwGdGVzdGNhMB4XDTIw +MDMxODAzMTA0MloXDTMwMDMxNjAzMTA0MlowZTELMAkGA1UEBhMCVVMxETAPBgNV +BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRUwEwYDVQQKDAxFeGFtcGxl +LCBDby4xGjAYBgNVBAMMESoudGVzdC5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA5xOONxJJ8b8Qauvob5/7dPYZfIcd+uhAWL2ZlTPz +Qvu4oF0QI4iYgP5iGgry9zEtCM+YQS8UhiAlPlqa6ANxgiBSEyMHH/xE8lo/+caY +GeACqy640Jpl/JocFGo3xd1L8DCawjlaj6eu7T7T/tpAV2qq13b5710eNRbCAfFe +8yALiGQemx0IYhlZXNbIGWLBNhBhvVjJh7UvOqpADk4xtl8o5j0xgMIRg6WJGK6c +6ffSIg4eP1XmovNYZ9LLEJG68tF0Q/yIN43B4dt1oq4jzSdCbG4F1EiykT2TmwPV +YDi8tml6DfOCDGnit8svnMEmBv/fcPd31GSbXjF8M+KGGQIDAQABo2swaTAJBgNV +HRMEAjAAMAsGA1UdDwQEAwIF4DBPBgNVHREESDBGghAqLnRlc3QuZ29vZ2xlLmZy +ghh3YXRlcnpvb2kudGVzdC5nb29nbGUuYmWCEioudGVzdC55b3V0dWJlLmNvbYcE +wKgBAzANBgkqhkiG9w0BAQsFAAOCAQEAS8hDQA8PSgipgAml7Q3/djwQ644ghWQv +C2Kb+r30RCY1EyKNhnQnIIh/OUbBZvh0M0iYsy6xqXgfDhCB93AA6j0i5cS8fkhH +Jl4RK0tSkGQ3YNY4NzXwQP/vmUgfkw8VBAZ4Y4GKxppdATjffIW+srbAmdDruIRM +wPeikgOoRrXf0LA1fi4TqxARzeRwenQpayNfGHTvVF9aJkl8HoaMunTAdG5pIVcr +9GKi/gEMpXUJbbVv3U5frX1Wo4CFo+rZWJ/LyCMeb0jciNLxSdMwj/E/ZuExlyeZ +gc9ctPjSMvgSyXEKv6Vwobleeg88V2ZgzenziORoWj4KszG/lbQZvg== -----END CERTIFICATE----- From 91dc475dd509f87bb58f8293dbc14251f1244f3d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 Mar 2020 14:09:20 -0700 Subject: [PATCH 0969/1899] grpc-js: Update some types and type checks for compatibility with grpc-gcp --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 26 ++++++++++++++++++++------ packages/grpc-js/src/client.ts | 4 ++-- packages/grpc-js/src/index.ts | 5 ++++- 4 files changed, 27 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6f5b1f3ab..aa2d6bfd5 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.2", + "version": "0.7.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index ad45f654a..cdbc81a2d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -110,9 +110,9 @@ export interface Channel { */ createCall( method: string, - deadline: Deadline | null | undefined, + deadline: Deadline, host: string | null | undefined, - parentCall: Call | null | undefined, + parentCall: any, propagateFlags: number | null | undefined ): Call; } @@ -140,6 +140,15 @@ export class ChannelImplementation implements Channel { private readonly credentials: ChannelCredentials, private readonly options: ChannelOptions ) { + if (typeof target !== 'string') { + throw new TypeError('Channel target must be a string'); + } + if (!(credentials instanceof ChannelCredentials)) { + throw new TypeError('Channel credentials must be a ChannelCredentials object'); + } + if ((typeof options !== 'object') || !Object.values(options).every(value => typeof value === 'string' || typeof value === 'number')) { + throw new TypeError('Channel options must be an object with string or number values'); + } /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ this.subchannelPool = getSubchannelPool( @@ -430,11 +439,17 @@ export class ChannelImplementation implements Channel { createCall( method: string, - deadline: Deadline | null | undefined, + deadline: Deadline, host: string | null | undefined, - parentCall: Call | null | undefined, + parentCall: any, propagateFlags: number | null | undefined ): Call { + if (typeof method !== 'string') { + throw new TypeError('Channel#createCall: method must be a string'); + } + if (!(typeof deadline === 'number' || deadline instanceof Date)) { + throw new TypeError('Channel#createCall: deadline must be a number or Date'); + } if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); } @@ -451,8 +466,7 @@ export class ChannelImplementation implements Channel { deadline ); const finalOptions: CallStreamOptions = { - deadline: - deadline === null || deadline === undefined ? Infinity : deadline, + deadline: deadline, flags: propagateFlags || 0, host: host || this.defaultAuthority, parentCall: parentCall || null, diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 77a5571fe..54679034e 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -48,6 +48,7 @@ import { InterceptorArguments, InterceptingCallInterface, } from './client-interceptors'; +import { ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream } from './server-call'; const CHANNEL_SYMBOL = Symbol(); const INTERCEPTOR_SYMBOL = Symbol(); @@ -61,8 +62,7 @@ export interface UnaryCallback { export interface CallOptions { deadline?: Deadline; host?: string; - /* There should be a parent option here that will accept a server call, - * but the server is not yet implemented so it makes no sense to have it */ + parent?: ServerUnaryCall | ServerReadableStream | ServerWritableStream | ServerDuplexStream propagate_flags?: number; credentials?: CallCredentials; interceptors?: Interceptor[]; diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index a80b08b99..941174c01 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -28,7 +28,7 @@ import { CallCredentials } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; -import { CallOptions, Client } from './client'; +import { CallOptions, Client, CallInvocationTransformer, CallProperties } from './client'; import { LogVerbosity, Status } from './constants'; import * as logging from './logging'; import { @@ -199,7 +199,10 @@ export { loadPackageDefinition, makeClientConstructor, makeClientConstructor as makeGenericClientConstructor, + CallProperties, + CallInvocationTransformer, ChannelImplementation as Channel, + Channel as ChannelInterface }; /** From 22521ef8a7dd91db10c63e2c1f49624be78a3d4c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 Mar 2020 11:12:40 -0700 Subject: [PATCH 0970/1899] Fix options type check --- packages/grpc-js/src/channel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index cdbc81a2d..9f570c0ff 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -146,8 +146,10 @@ export class ChannelImplementation implements Channel { if (!(credentials instanceof ChannelCredentials)) { throw new TypeError('Channel credentials must be a ChannelCredentials object'); } - if ((typeof options !== 'object') || !Object.values(options).every(value => typeof value === 'string' || typeof value === 'number')) { - throw new TypeError('Channel options must be an object with string or number values'); + if (options) { + if ((typeof options !== 'object') || !Object.values(options).every(value => typeof value === 'string' || typeof value === 'number')) { + throw new TypeError('Channel options must be an object with string or number values'); + } } /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ From a3526e98c84b1a11dbc7087d3e9defdb0cf5785d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 Mar 2020 12:55:24 -0700 Subject: [PATCH 0971/1899] Delete client-specific options before passing them to the channel --- packages/grpc-js/src/client.ts | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 54679034e..8b4b7eead 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -109,10 +109,28 @@ export class Client { credentials: ChannelCredentials, options: ClientOptions = {} ) { + options = Object.assign({}, options); + this[INTERCEPTOR_SYMBOL] = options.interceptors ?? []; + delete options.interceptors; + this[INTERCEPTOR_PROVIDER_SYMBOL] = options.interceptor_providers ?? []; + delete options.interceptor_providers; + if ( + this[INTERCEPTOR_SYMBOL].length > 0 && + this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0 + ) { + throw new Error( + 'Both interceptors and interceptor_providers were passed as options ' + + 'to the client constructor. Only one of these is allowed.' + ); + } + this[CALL_INVOCATION_TRANSFORMER_SYMBOL] = options.callInvocationTransformer; + delete options.callInvocationTransformer; if (options.channelOverride) { this[CHANNEL_SYMBOL] = options.channelOverride; } else if (options.channelFactoryOverride) { - this[CHANNEL_SYMBOL] = options.channelFactoryOverride( + const channelFactoryOverride = options.channelFactoryOverride; + delete options.channelFactoryOverride; + this[CHANNEL_SYMBOL] = channelFactoryOverride( address, credentials, options @@ -124,18 +142,6 @@ export class Client { options ); } - this[INTERCEPTOR_SYMBOL] = options.interceptors ?? []; - this[INTERCEPTOR_PROVIDER_SYMBOL] = options.interceptor_providers ?? []; - if ( - this[INTERCEPTOR_SYMBOL].length > 0 && - this[INTERCEPTOR_PROVIDER_SYMBOL].length > 0 - ) { - throw new Error( - 'Both interceptors and interceptor_providers were passed as options ' + - 'to the client constructor. Only one of these is allowed.' - ); - } - this[CALL_INVOCATION_TRANSFORMER_SYMBOL] = options.callInvocationTransformer; } close(): void { From 80e9342ae4ea6351852de5f3c0d6ebc311591a30 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Mar 2020 09:25:32 -0700 Subject: [PATCH 0972/1899] Make channel options type check exactly match type declaration --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 9f570c0ff..4d07dde03 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -147,7 +147,7 @@ export class ChannelImplementation implements Channel { throw new TypeError('Channel credentials must be a ChannelCredentials object'); } if (options) { - if ((typeof options !== 'object') || !Object.values(options).every(value => typeof value === 'string' || typeof value === 'number')) { + if ((typeof options !== 'object') || !Object.values(options).every(value => typeof value === 'string' || typeof value === 'number' || typeof value === 'undefined')) { throw new TypeError('Channel options must be an object with string or number values'); } } From 25b5a40a6c79c9089e1ebb55b60c81d7bfd85bf3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 26 Mar 2020 09:25:37 -0700 Subject: [PATCH 0973/1899] Use make from homebrew in Mac tests --- .../tools/run_tests/artifacts/build_one_artifact_macos.sh | 2 ++ test/kokoro.sh | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh index 5ca968362..a92f8a2a6 100755 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh +++ b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh @@ -24,6 +24,8 @@ npm install -g npm npm install -g node-gyp set -ex +brew install make +PATH="$(brew --prefix)/opt/make/libexec/gnubin:$PATH" cd $(dirname $0)/../../../../.. base_dir=$(pwd) diff --git a/test/kokoro.sh b/test/kokoro.sh index 667db1127..0caeb1cfc 100755 --- a/test/kokoro.sh +++ b/test/kokoro.sh @@ -19,6 +19,13 @@ rm -rf ~/.rvm set -e cd $(dirname $0)/.. +OS=$(uname) +if [ "$OS" = "Darwin" ] +then + brew install make + PATH="$(brew --prefix)/opt/make/libexec/gnubin:$PATH" +fi + # Install gRPC and its submodules. git submodule update --init --recursive From 2f953e44572662103df81872c7fc27570dc6ca29 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 26 Mar 2020 16:25:13 -0700 Subject: [PATCH 0974/1899] grpc-js: Don't wait for TXT record to return DNS lookup result --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/resolver-dns.ts | 204 +++++++++++++------------ packages/grpc-js/src/server.ts | 2 + packages/grpc-js/test/test-resolver.ts | 43 ++++-- 4 files changed, 137 insertions(+), 114 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index aa2d6bfd5..011fe79b8 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.3", + "version": "0.7.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index ebfd16dcf..4da295e13 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -69,34 +69,7 @@ const DNS_REGEX = /^(?:dns:)?(?:\/\/(?:[a-zA-Z0-9-]+\.?)+\/)?((?:[a-zA-Z0-9-]+\. */ const DEFAULT_PORT = '443'; -/** - * Get a promise that always resolves with either the result of the function - * or the error if it failed. - * @param fn - */ -function resolvePromisify( - fn: ( - arg: TArg, - callback: (error: TError | null, result: TResult) => void - ) => void -): (arg: TArg) => Promise { - return arg => - new Promise((resolve, reject) => { - fn(arg, (error, result) => { - if (error) { - resolve(error); - } else { - resolve(result); - } - }); - }); -} - -const resolveTxtPromise = resolvePromisify< - string, - string[][], - NodeJS.ErrnoException ->(dns.resolveTxt); +const resolveTxtPromise = util.promisify(dns.resolveTxt); const dnsLookupPromise = util.promisify(dns.lookup); /** @@ -156,11 +129,11 @@ class DnsResolver implements Resolver { private readonly ipResult: SubchannelAddress[] | null; private readonly dnsHostname: string | null; private readonly port: string | null; - /* The promise results here contain, in order, the A record, the AAAA record, - * and either the TXT record or an error if TXT resolution failed */ - private pendingResultPromise: Promise< - [dns.LookupAddress[], string[][] | NodeJS.ErrnoException] - > | null = null; + private pendingLookupPromise: Promise | null = null; + private pendingTxtPromise: Promise | null = null; + private latestLookupResult: TcpSubchannelAddress[] | null = null; + private latestServiceConfig: ServiceConfig | null = null; + private latestServiceConfigError: StatusObject | null = null; private percentage: number; private defaultResolutionError: StatusObject; constructor(private target: string, private listener: ResolverListener) { @@ -189,7 +162,7 @@ class DnsResolver implements Resolver { /** * If the target is an IP address, just provide that address as a result. - * Otherwise, initiate A, AAAA, and TXT + * Otherwise, initiate A, AAAA, and TXT lookups */ private startResolution() { if (this.ipResult !== null) { @@ -200,87 +173,116 @@ class DnsResolver implements Resolver { return; } if (this.dnsHostname !== null) { + /* We clear out latestLookupResult here to ensure that it contains the + * latest result since the last time we started resolving. That way, the + * TXT resolution handler can use it, but only if it finishes second. We + * don't clear out any previous service config results because it's + * better to use a service config that's slightly out of date than to + * revert to an effectively blank one. */ + this.latestLookupResult = null; const hostname: string = this.dnsHostname; /* We lookup both address families here and then split them up later * because when looking up a single family, dns.lookup outputs an error * if the name exists but there are no records for that family, and that * error is indistinguishable from other kinds of errors */ - const addressResult = dnsLookupPromise(hostname, { all: true }); - /* We handle the TXT query promise differently than the others because - * the name resolution attempt as a whole is a success even if the TXT - * lookup fails */ - const txtResult = resolveTxtPromise(hostname); - this.pendingResultPromise = Promise.all([addressResult, txtResult]); - this.pendingResultPromise.then( - ([addressList, txtRecord]) => { - this.pendingResultPromise = null; - const ip4Addresses: dns.LookupAddress[] = addressList.filter( - addr => addr.family === 4 - ); - const ip6Addresses: dns.LookupAddress[] = addressList.filter(addr => addr.family === 6); - const allAddresses: TcpSubchannelAddress[] = mergeArrays( - ip4Addresses, - ip6Addresses - ).map(addr => ({ host: addr.address, port: +this.port! })); - const allAddressesString: string = - '[' + - allAddresses.map(addr => addr.host + ':' + addr.port).join(',') + - ']'; - trace( - 'Resolved addresses for target ' + - this.target + - ': ' + - allAddressesString - ); - if (allAddresses.length === 0) { - this.listener.onError(this.defaultResolutionError); - return; - } - let serviceConfig: ServiceConfig | null = null; - let serviceConfigError: StatusObject | null = null; - if (txtRecord instanceof Error) { - serviceConfigError = { + this.pendingLookupPromise = dnsLookupPromise(hostname, { all: true }); + this.pendingLookupPromise.then(addressList => { + this.pendingLookupPromise = null; + const ip4Addresses: dns.LookupAddress[] = addressList.filter( + addr => addr.family === 4 + ); + const ip6Addresses: dns.LookupAddress[] = addressList.filter(addr => addr.family === 6); + this.latestLookupResult = mergeArrays( + ip6Addresses, + ip4Addresses + ).map(addr => ({ host: addr.address, port: +this.port! })); + const allAddressesString: string = + '[' + + this.latestLookupResult.map(addr => addr.host + ':' + addr.port).join(',') + + ']'; + trace( + 'Resolved addresses for target ' + + this.target + + ': ' + + allAddressesString + ); + if (this.latestLookupResult.length === 0) { + this.listener.onError(this.defaultResolutionError); + return; + } + /* If the TXT lookup has not yet finished, both of the last two + * arguments will be null, which is the equivalent of getting an + * empty TXT response. When the TXT lookup does finish, its handler + * can update the service config by using the same address list */ + this.listener.onSuccessfulResolution( + this.latestLookupResult, + this.latestServiceConfig, + this.latestServiceConfigError + ); + }, + err => { + trace( + 'Resolution error for target ' + + this.target + + ': ' + + (err as Error).message + ); + this.pendingLookupPromise = null; + this.listener.onError(this.defaultResolutionError); + }); + /* If there already is a still-pending TXT resolution, we can just use + * that result when it comes in */ + if (this.pendingTxtPromise === null) { + /* We handle the TXT query promise differently than the others because + * the name resolution attempt as a whole is a success even if the TXT + * lookup fails */ + this.pendingTxtPromise = resolveTxtPromise(hostname); + this.pendingTxtPromise.then(txtRecord => { + this.pendingTxtPromise = null; + try { + this.latestServiceConfig = extractAndSelectServiceConfig( + txtRecord, + this.percentage + ); + } catch (err) { + this.latestServiceConfigError = { code: Status.UNAVAILABLE, - details: 'TXT query failed', + details: 'Parsing service config failed', metadata: new Metadata(), }; - } else { - try { - serviceConfig = extractAndSelectServiceConfig( - txtRecord, - this.percentage - ); - } catch (err) { - serviceConfigError = { - code: Status.UNAVAILABLE, - details: 'Parsing service config failed', - metadata: new Metadata(), - }; - } } - this.listener.onSuccessfulResolution( - allAddresses, - serviceConfig, - serviceConfigError - ); - }, - err => { - trace( - 'Resolution error for target ' + - this.target + - ': ' + - (err as Error).message - ); - this.pendingResultPromise = null; - this.listener.onError(this.defaultResolutionError); - } - ); + if (this.latestLookupResult !== null) { + /* We rely here on the assumption that calling this function with + * identical parameters will be essentialy idempotent, and calling + * it with the same address list and a different service config + * should result in a fast and seamless switchover. */ + this.listener.onSuccessfulResolution( + this.latestLookupResult, + this.latestServiceConfig, + this.latestServiceConfigError + ) + } + }, err => { + this.latestServiceConfigError = { + code: Status.UNAVAILABLE, + details: 'TXT query failed', + metadata: new Metadata(), + }; + if (this.latestLookupResult !== null) { + this.listener.onSuccessfulResolution( + this.latestLookupResult, + this.latestServiceConfig, + this.latestServiceConfigError + ) + } + }); + } } } updateResolution() { trace('Resolution update requested for target ' + this.target); - if (this.pendingResultPromise === null) { + if (this.pendingLookupPromise === null) { this.startResolution(); } } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 62ed68ab3..fc48f3cfd 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -321,6 +321,8 @@ export class Server { const resolverListener: ResolverListener = { onSuccessfulResolution: (addressList, serviceConfig, serviceConfigError) => { + // We only want one resolution result. Discard all future results + resolverListener.onSuccessfulResolution = () => {} if (addressList.length === 0) { callback(new Error(`No addresses resolved for port ${port}`), 0); return; diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 7d7343c05..7f4900aa2 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -38,6 +38,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -71,6 +73,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -104,6 +108,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -129,6 +135,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -154,6 +162,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -179,6 +189,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert(addressList.length > 0); done(); }, @@ -197,6 +209,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -224,6 +238,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -249,6 +265,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => @@ -278,6 +296,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert(addressList.length > 0); done(); }, @@ -290,16 +310,6 @@ describe('Name Resolver', () => { }); it('Should resolve gRPC interop servers', done => { let completeCount = 0; - function done2(error?: Error) { - if (error) { - done(error); - } else { - completeCount += 1; - if (completeCount === 2) { - done(); - } - } - } const target1 = 'grpc-test.sandbox.googleapis.com'; const target2 = 'grpc-test4.sandbox.googleapis.com'; const listener: resolverManager.ResolverListener = { @@ -309,10 +319,15 @@ describe('Name Resolver', () => { serviceConfigError: StatusObject | null ) => { assert(addressList.length > 0); - done2(); + completeCount += 1; + if (completeCount === 2) { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + done(); + } }, onError: (error: StatusObject) => { - done2(new Error(`Failed with status ${error.details}`)); + done(new Error(`Failed with status ${error.details}`)); }, }; const resolver1 = resolverManager.createResolver(target1, listener); @@ -330,6 +345,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => !isTcpSubchannelAddress(addr) && addr.path === 'socket' @@ -352,6 +369,8 @@ describe('Name Resolver', () => { serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; assert( addressList.some( addr => From 600bc7e9d2f6bbf6bbcdeba8cf2b58586157ba61 Mon Sep 17 00:00:00 2001 From: Andrei Conache Date: Sun, 29 Mar 2020 15:24:47 +0200 Subject: [PATCH 0975/1899] grpc-js: export InterceptorOptions InterceptorOptions extends CallOptions with the addition of method_definition property --- packages/grpc-js/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 941174c01..87824d5b2 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -294,6 +294,7 @@ export { ListenerBuilder, RequesterBuilder, Interceptor, + InterceptorOptions, InterceptorProvider, InterceptingCall, InterceptorConfigurationError, From 6fda1d46f282d32213cd8a9d34dd9d16314ec29b Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 30 Mar 2020 12:59:24 +0300 Subject: [PATCH 0976/1899] RoundRobinLoadBalancer: Register the state listener --- packages/grpc-js/src/load-balancer-round-robin.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 465299360..863fec774 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -198,6 +198,8 @@ export class RoundRobinLoadBalancer implements LoadBalancer { this.channelControlHelper.createSubchannel(address, {}) ); for (const subchannel of this.subchannels) { + subchannel.ref(); + subchannel.addConnectivityStateListener(this.subchannelStateListener); const subchannelState = subchannel.getConnectivityState(); this.subchannelStateCounts[subchannelState] += 1; if ( From 25d2a07877fe9598d7f54c1b51e846814104bd70 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Mon, 30 Mar 2020 12:58:52 +0300 Subject: [PATCH 0977/1899] PickFirstLoadBalancer: Correctly initialize state counters --- packages/grpc-js/src/load-balancer-pick-first.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 10ef71495..e0e1768cf 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -350,6 +350,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { } for (const subchannel of this.subchannels) { subchannel.addConnectivityStateListener(this.subchannelStateListener); + this.subchannelStateCounts[subchannel.getConnectivityState()] += 1; if (subchannel.getConnectivityState() === ConnectivityState.READY) { this.pickSubchannel(subchannel); this.resetSubchannelList(); From 82ddf3bdb8cce469b63ac2331281aea0f495e587 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 30 Mar 2020 10:40:50 -0700 Subject: [PATCH 0978/1899] Bump proto-loader to 0.5.4 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index c558633f4..746b87926 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.3", + "version": "0.5.4", "author": "Google Inc.", "contributors": [ { From dd88ddc6b10b28fea445731af6609e17ee40f5aa Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 31 Mar 2020 10:25:37 -0700 Subject: [PATCH 0979/1899] grpc-js: Don't time out connection attempts --- packages/grpc-js/src/subchannel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 26c7dce03..d9581ee28 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -230,12 +230,12 @@ export class Subchannel { this.backoffTimeout = new BackoffTimeout(() => { if (this.continueConnecting) { this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], + [ConnectivityState.TRANSIENT_FAILURE], ConnectivityState.CONNECTING ); } else { this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE, ConnectivityState.CONNECTING], + [ConnectivityState.TRANSIENT_FAILURE], ConnectivityState.IDLE ); } From dd54c210ceebda9c86e69f20d6720354b0badbc0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 1 Apr 2020 10:24:20 -0700 Subject: [PATCH 0980/1899] Bump grpc-js to 0.7.5 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 011fe79b8..d9c73cae7 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.4", + "version": "0.7.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 4a057552360bf571b7c91951113b3b8004e61902 Mon Sep 17 00:00:00 2001 From: Satoshi Nakagawa Date: Fri, 3 Apr 2020 10:46:10 +0900 Subject: [PATCH 0981/1899] grpc-js: fix "http:" scheme not supported in proxy URI --- packages/grpc-js/src/http_proxy.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index a3ba0f589..ecff1bb5f 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -61,7 +61,7 @@ function getProxyInfo(): ProxyInfo { log(LogVerbosity.INFO, `cannot parse value of "${envVar}" env var`); return {}; } - if (proxyUrl.protocol !== 'http') { + if (proxyUrl.protocol !== 'http:') { log(LogVerbosity.ERROR, `"${proxyUrl.protocol}" scheme not supported in proxy URI`); return {}; } @@ -159,4 +159,4 @@ export function getProxiedConnection(target: string, subchannelAddress: Subchann reject(); }); }); -} \ No newline at end of file +} From 6afd8ad44372fb4fa025b7968d21e0152e6d00bd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 3 Apr 2020 10:17:05 -0700 Subject: [PATCH 0982/1899] Bump grpc-js to 0.7.6 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d9c73cae7..c866a57f9 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.5", + "version": "0.7.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From ae18f3ce92d6ab34010ff5de7ae931c85dfd1526 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Apr 2020 13:49:54 -0700 Subject: [PATCH 0983/1899] grpc-js: Make some headers conform to what the other library does --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 15 +++++++++++++-- packages/grpc-js/src/compression-filter.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 6 ++++++ packages/grpc-js/src/subchannel.ts | 7 +++++-- 5 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index c866a57f9..7276e8c47 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.6", + "version": "0.7.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 70c728e02..443d5ebf4 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -353,7 +353,11 @@ export class Http2CallStream implements Call { } private handleTrailers(headers: http2.IncomingHttpHeaders) { - this.trace('received HTTP/2 trailing headers frame'); + let headersString = ''; + for (const header of Object.keys(headers)) { + headersString += '\t\t' + header + ': ' + headers[header] + '\n' + } + this.trace('Received server trailers:\n' + headersString); let metadata: Metadata; try { metadata = Metadata.fromHttp2Headers(headers); @@ -366,6 +370,7 @@ export class Http2CallStream implements Call { const receivedStatus = Number(metadataMap['grpc-status']); if (receivedStatus in Status) { code = receivedStatus; + this.trace('received status code ' + receivedStatus + ' from server'); } metadata.remove('grpc-status'); } @@ -373,6 +378,7 @@ export class Http2CallStream implements Call { if (typeof metadataMap['grpc-message'] === 'string') { details = decodeURI(metadataMap['grpc-message']); metadata.remove('grpc-message'); + this.trace('received status details string "' + details + '" from server'); } const status: StatusObject = { code, details, metadata }; let finalStatus; @@ -407,7 +413,11 @@ export class Http2CallStream implements Call { subchannel.addDisconnectListener(this.disconnectListener); subchannel.callRef(); stream.on('response', (headers, flags) => { - this.trace('received HTTP/2 headers frame'); + let headersString = ''; + for (const header of Object.keys(headers)) { + headersString += '\t\t' + header + ': ' + headers[header] + '\n' + } + this.trace('Received server headers:\n' + headersString); switch (headers[':status']) { // TODO(murgatroid99): handle 100 and 101 case 400: @@ -568,6 +578,7 @@ export class Http2CallStream implements Call { } cancelWithStatus(status: Status, details: string): void { + this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); this.destroyHttp2Stream(); this.endCall({ code: status, details, metadata: new Metadata() }); } diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 0949840f4..6f40ee4b8 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -169,8 +169,8 @@ export class CompressionFilter extends BaseFilter implements Filter { private receiveCompression: CompressionHandler = new IdentityHandler(); async sendMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; - headers.set('grpc-encoding', 'identity'); headers.set('grpc-accept-encoding', 'identity,deflate,gzip'); + headers.set('accept-encoding', 'identity,gzip'); return headers; } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 4da295e13..82727a42d 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -298,10 +298,16 @@ class DnsResolver implements Resolver { IPV6_REGEX.exec(target) || IPV6_BRACKET_REGEX.exec(target); if (ipMatch) { + if (ipMatch[2]) { + return ipMatch[1] + ':' + ipMatch[2]; + } return ipMatch[1]; } const dnsMatch = DNS_REGEX.exec(target); if (dnsMatch) { + if (dnsMatch[2]) { + return dnsMatch[1] + ':' + dnsMatch[2]; + } return dnsMatch[1]; } throw new Error(`Failed to parse target ${target}`); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index d9581ee28..64799a496 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -298,8 +298,6 @@ export class Subchannel { return checkServerIdentity(sslTargetNameOverride, cert); }; connectionOptions.servername = sslTargetNameOverride; - } else { - connectionOptions.servername = getDefaultAuthority(this.channelTarget); } if (socket) { connectionOptions.socket = socket; @@ -589,6 +587,11 @@ export class Subchannel { headers[HTTP2_HEADER_PATH] = callStream.getMethod(); headers[HTTP2_HEADER_TE] = 'trailers'; const http2Stream = this.session!.request(headers); + let headersString = ''; + for (const header of Object.keys(headers)) { + headersString += '\t\t' + header + ': ' + headers[header] + '\n' + } + trace('Starting stream with headers\n' + headersString); callStream.attachHttp2Stream(http2Stream, this); } From 9221fdea24cce0547d9bbb7eef664780a6481b7d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Apr 2020 14:37:03 -0700 Subject: [PATCH 0984/1899] grpc-js: Add max message size enforcement --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel-options.ts | 4 + packages/grpc-js/src/channel.ts | 2 + .../grpc-js/src/max-message-size-filter.ts | 81 +++++++++ packages/grpc-js/src/server-call.ts | 31 +++- packages/grpc-js/src/server.ts | 4 +- test/api/interop_extra_test.js | 163 +++++++++++++++++- test/interop/interop_server.js | 8 +- 8 files changed, 288 insertions(+), 7 deletions(-) create mode 100644 packages/grpc-js/src/max-message-size-filter.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7276e8c47..7ecd781b6 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.7", + "version": "0.8.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 9d92b393c..89eb46cf0 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -30,6 +30,8 @@ export interface ChannelOptions { 'grpc.initial_reconnect_backoff_ms'?: number; 'grpc.max_reconnect_backoff_ms'?: number; 'grpc.use_local_subchannel_pool'?: number; + 'grpc.max_send_message_length'?: number; + 'grpc.max_receive_message_length'?: number; [key: string]: string | number | undefined; } @@ -49,6 +51,8 @@ export const recognizedOptions = { 'grpc.initial_reconnect_backoff_ms': true, 'grpc.max_reconnect_backoff_ms': true, 'grpc.use_local_subchannel_pool': true, + 'grpc.max_send_message_length': true, + 'grpc.max_receive_message_length': true, }; export function channelOptionsEqual( diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 4d07dde03..5acb520d7 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -38,6 +38,7 @@ import { LoadBalancingConfig } from './load-balancing-config'; import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; +import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; export enum ConnectivityState { CONNECTING, @@ -202,6 +203,7 @@ export class ChannelImplementation implements Channel { this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), + new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); // TODO(murgatroid99): Add more centralized handling of channel options diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts new file mode 100644 index 000000000..ac304e8f8 --- /dev/null +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { BaseFilter, Filter, FilterFactory } from "./filter"; +import { Call, WriteObject } from "./call-stream"; +import { Status } from "./constants"; +import { ChannelOptions } from "./channel-options"; + +// The default max message size for sending or receiving is 4 MB +const DEFAULT_MAX_MESSAGE_SIZE = 4 * 1024 * 1024; + +export class MaxMessageSizeFilter extends BaseFilter implements Filter { + private maxSendMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; + private maxReceiveMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; + constructor( + private readonly options: ChannelOptions, + private readonly callStream: Call + ) { + super(); + if ('grpc.max_send_message_length' in options) { + this.maxSendMessageSize = options['grpc.max_send_message_length']!; + } + if ('grpc.max_receive_message_length' in options) { + this.maxReceiveMessageSize = options['grpc.max_receive_message_length']!; + } + } + + async sendMessage(message: Promise): Promise { + /* A configured size of -1 means that there is no limit, so skip the check + * entirely */ + if (this.maxSendMessageSize === -1) { + return message; + } else { + const concreteMessage = await message; + if (concreteMessage.message.length > this.maxSendMessageSize) { + this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Failed to send message of size ${concreteMessage.message.length} > max size ${this.maxSendMessageSize}`); + return Promise.reject('Message too large'); + } else { + return concreteMessage; + } + } + } + + async receiveMessage(message: Promise): Promise { + /* A configured size of -1 means that there is no limit, so skip the check + * entirely */ + if (this.maxReceiveMessageSize === -1) { + return message; + } else { + const concreteMessage = await message; + if (concreteMessage.length > this.maxReceiveMessageSize) { + this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Received message of size ${concreteMessage.length} > max size ${this.maxReceiveMessageSize}`); + return Promise.reject('Message too large'); + } else { + return concreteMessage; + } + } + } +} + +export class MaxMessageSizeFilterFactory implements FilterFactory { + constructor(private readonly options: ChannelOptions) {} + + createFilter(callStream: Call): MaxMessageSizeFilter { + return new MaxMessageSizeFilter(this.options, callStream); + } +} diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index efdf1bccb..bbec9ac52 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -25,6 +25,7 @@ import { Deserialize, Serialize } from './make-client'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; import { ObjectReadable, ObjectWritable } from './object-stream'; +import { ChannelOptions } from './channel-options'; interface DeadlineUnitIndexSignature { [name: string]: number; @@ -325,6 +326,9 @@ export type HandlerType = 'bidi' | 'clientStream' | 'serverStream' | 'unary'; const noopTimer: NodeJS.Timer = setTimeout(() => {}, 0); +// The default max message size for sending or receiving is 4 MB +const DEFAULT_MAX_MESSAGE_SIZE = 4 * 1024 * 1024; + // Internal class that wraps the HTTP2 request. export class Http2ServerCallStream< RequestType, @@ -338,10 +342,13 @@ export class Http2ServerCallStream< private isPushPending = false; private bufferedMessages: Array = []; private messagesToPush: Array = []; + private maxSendMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; + private maxReceiveMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; constructor( private stream: http2.ServerHttp2Stream, - private handler: Handler + private handler: Handler, + private options: ChannelOptions ) { super(); @@ -361,6 +368,13 @@ export class Http2ServerCallStream< this.stream.on('drain', () => { this.emit('drain'); }); + + if ('grpc.max_send_message_length' in options) { + this.maxSendMessageSize = options['grpc.max_send_message_length']!; + } + if ('grpc.max_receive_message_length' in options) { + this.maxReceiveMessageSize = options['grpc.max_receive_message_length']!; + } } private checkCancelled(): boolean { @@ -435,6 +449,9 @@ export class Http2ServerCallStream< stream.once('end', async () => { try { const requestBytes = Buffer.concat(chunks, totalLength); + if (this.maxReceiveMessageSize !== -1 && requestBytes.length > this.maxReceiveMessageSize) { + this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Server received message of size ${requestBytes.length} > max size ${this.maxReceiveMessageSize}`); + } resolve(await this.deserializeMessage(requestBytes)); } catch (err) { @@ -550,11 +567,20 @@ export class Http2ServerCallStream< this.sendStatus(status); } + cancelWithStatus(code: Status, details: string) { + this.cancelled = true; + this.sendStatus({code, details, metadata: new Metadata()}); + } + write(chunk: Buffer) { if (this.checkCancelled()) { return; } + if (this.maxSendMessageSize !== -1 && chunk.length > this.maxSendMessageSize) { + this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Server failed to send message of size ${chunk.length} > max size ${this.maxSendMessageSize}`); + } + this.sendMetadata(); return this.stream.write(chunk); } @@ -581,6 +607,9 @@ export class Http2ServerCallStream< const messages = decoder.write(data); for (const message of messages) { + if (this.maxReceiveMessageSize !== -1 && message.length > this.maxReceiveMessageSize) { + this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Server received message of size ${message.length} > max size ${this.maxReceiveMessageSize}`); + } this.pushOrBufferMessage(readable, message); } }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index fc48f3cfd..489224968 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -485,7 +485,7 @@ export class Server { throw getUnimplementedStatusResponse(path); } - const call = new Http2ServerCallStream(stream, handler); + const call = new Http2ServerCallStream(stream, handler, this.options); const metadata: Metadata = call.receiveMetadata(headers) as Metadata; switch (handler.type) { case 'unary': @@ -516,7 +516,7 @@ export class Server { throw new Error(`Unknown handler type: ${handler.type}`); } } catch (err) { - const call = new Http2ServerCallStream(stream, null!); + const call = new Http2ServerCallStream(stream, null!, this.options); if (err.code === undefined) { err.code = Status.INTERNAL; diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index abf44b3c3..81fa3d809 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -55,12 +55,16 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio describe('Interop-adjacent tests', function() { let server; let client; + let port; before(function(done) { + /* The default server has no limits on max message size to make those + * tests easier to write */ interopServer.getServer(0, true, (err, serverObj) => { if (err) { done(err); } else { server = serverObj.server; + port = serverObj.port; server.start(); const ca_path = path.join(__dirname, '../data/ca.pem'); const ca_data = fs.readFileSync(ca_path); @@ -69,9 +73,12 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio 'grpc.ssl_target_name_override': 'foo.test.google.fr', 'grpc.default_authority': 'foo.test.google.fr' }; - client = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + client = new testProto.TestService(`localhost:${port}`, creds, options); done(); } + }, { + 'grpc.max_send_message_length': -1, + 'grpc.max_receive_message_length': -1 }); }); after(function() { @@ -133,5 +140,159 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done(); }); }); + describe.only('max message size', function() { + // Note: the main server has these checks disabled + // A size that is larger than the default limit + const largeMessageSize = 32 * 1024 * 1024; + const largeMessage = Buffer.alloc(largeMessageSize); + it('should get an error when sending a large message', function(done) { + done = multiDone(done, 2); + const unaryMessage = {payload: {body: largeMessage}} + console.log(client.unaryCall.requestSerialize(unaryMessage).length); + client.unaryCall(unaryMessage, (error, result) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + const stream = client.fullDuplexCall(); + stream.write({payload: {body: largeMessage}}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); + }); + it('should get an error when receiving a large message', function(done) { + done = multiDone(done, 2); + client.unaryCall({response_size: largeMessageSize}, (error, result) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + const stream = client.fullDuplexCall(); + stream.write({response_parameters: [{size: largeMessageSize}]}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); + }); + describe('with a client with no message size limits', function() { + let unrestrictedClient; + before(function() { + const ca_path = path.join(__dirname, '../data/ca.pem'); + const ca_data = fs.readFileSync(ca_path); + const creds = grpc.credentials.createSsl(ca_data); + const options = { + 'grpc.ssl_target_name_override': 'foo.test.google.fr', + 'grpc.default_authority': 'foo.test.google.fr', + 'grpc.max_send_message_length': -1, + 'grpc.max_receive_message_length': -1 + }; + unrestrictedClient = new testProto.TestService(`localhost:${port}`, creds, options); + }); + it('should not get an error when sending or receiving a large message', function(done) { + done = multiDone(done, 2); + const unaryRequestMessage = { + response_size: largeMessageSize, + payload: { + body: largeMessage + } + }; + unrestrictedClient.unaryCall(unaryRequestMessage, (error, result) => { + assert.ifError(error); + assert.strictEqual(result.payload.body.length, largeMessageSize); + done(); + }); + const streamingRequestMessage = { + response_parameters: [{size: largeMessageSize}], + payload: {body: largeMessage} + }; + const stream = unrestrictedClient.fullDuplexCall(); + stream.write(streamingRequestMessage); + stream.end(); + stream.on('data', (result) => { + assert.strictEqual(result.payload.body.length, largeMessageSize); + }); + stream.on('status', () => { + done(); + }); + stream.on('error', (error) => { + assert.ifError(error); + }); + }); + }); + describe('with a server with message size limits', function() { + let restrictedServer; + let restrictedServerClient; + before(function(done) { + interopServer.getServer(0, true, (err, serverObj) => { + if (err) { + done(err); + } else { + restrictedServer = serverObj.server; + restrictedServer.start(); + const ca_path = path.join(__dirname, '../data/ca.pem'); + const ca_data = fs.readFileSync(ca_path); + const creds = grpc.credentials.createSsl(ca_data); + const options = { + 'grpc.ssl_target_name_override': 'foo.test.google.fr', + 'grpc.default_authority': 'foo.test.google.fr', + 'grpc.max_send_message_length': -1, + 'grpc.max_receive_message_length': -1 + }; + restrictedServerClient = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + done(); + } + }); + }); + after(function() { + restrictedServer.forceShutdown(); + }); + it('should get an error when sending a large message', function(done) { + done = multiDone(done, 2); + restrictedServerClient.unaryCall({payload: {body: largeMessage}}, (error, result) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + const stream = restrictedServerClient.fullDuplexCall(); + stream.write({payload: {body: largeMessage}}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); + }); + it('should get an error when requesting a large message', function(done) { + done = multiDone(done, 2); + restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { + console.log(result.payload.body.length); + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + const stream = restrictedServerClient.fullDuplexCall(); + stream.write({response_parameters: [{size: largeMessageSize}]}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); + }); + }); + }); }); }); \ No newline at end of file diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index 1f00af205..c77643e86 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -202,10 +202,14 @@ function handleHalfDuplex(call) { * @param {boolean} tls Indicates that the bound port should use TLS * @param {function(Error, {{server: Server, port: number}})} callback Callback * to call with result or error + * @param {object?} options Optional additional options to use when + * constructing the server */ -function getServer(port, tls, callback) { +function getServer(port, tls, callback, options) { // TODO(mlumish): enable TLS functionality - var options = {}; + if (!options) { + options = {}; + } var server_creds; if (tls) { var key_path = path.join(__dirname, '../data/server1.key'); From 6e59160c2c9a467500a09e8a096efd4edf24bf13 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Apr 2020 14:54:16 -0700 Subject: [PATCH 0985/1899] grpc-js: Fix status check when connecting to proxy --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/http_proxy.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7276e8c47..12f060521 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.7", + "version": "0.7.8", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index ecff1bb5f..ab1083fc5 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -58,7 +58,7 @@ function getProxyInfo(): ProxyInfo { try { proxyUrl = new URL(proxyEnv); } catch (e) { - log(LogVerbosity.INFO, `cannot parse value of "${envVar}" env var`); + log(LogVerbosity.ERROR, `cannot parse value of "${envVar}" env var`); return {}; } if (proxyUrl.protocol !== 'http:') { @@ -145,17 +145,17 @@ export function getProxiedConnection(target: string, subchannelAddress: Subchann request.once('connect', (res, socket, head) => { request.removeAllListeners(); socket.removeAllListeners(); - if (res.statusCode === http.STATUS_CODES.OK) { + if (res.statusCode === 200) { trace('Successfully connected to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); resolve(socket); } else { - trace('Failed to connect to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); + log(LogVerbosity.ERROR, 'Failed to connect to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); reject(); } }); request.once('error', (err) => { request.removeAllListeners(); - trace('Failed to connect to proxy ' + PROXY_INFO.address); + log(LogVerbosity.ERROR, 'Failed to connect to proxy ' + PROXY_INFO.address); reject(); }); }); From c62203900ef7f9864b052a63ba0c13ada160c1f9 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 10:12:47 +0200 Subject: [PATCH 0986/1899] grpc-js: adjust ts definitions to equal native-core Export MethodDefinition in index.ts and add generic ImplementationType to ServiceDefinition --- packages/grpc-js/src/index.ts | 2 ++ packages/grpc-js/src/make-client.ts | 5 +++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 941174c01..5e7b8671f 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -35,6 +35,7 @@ import { Deserialize, loadPackageDefinition, makeClientConstructor, + MethodDefinition, Serialize, ServiceDefinition, } from './make-client'; @@ -230,6 +231,7 @@ export { ClientWritableStream, ClientDuplexStream, CallOptions, + MethodDefinition, StatusObject, ServiceError, ServerUnaryCall, diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 99d40a649..e9e5ead9e 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -18,6 +18,7 @@ import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Client } from './client'; +import { UntypedServiceImplementation } from './server'; export interface Serialize { (value: T): Buffer; @@ -49,9 +50,9 @@ export interface MethodDefinition extends ClientMethodDefinition, ServerMethodDefinition {} -export interface ServiceDefinition { +export type ServiceDefinition = { // tslint:disable-next-line no-any - [index: string]: MethodDefinition; + readonly [index in keyof ImplementationType]: MethodDefinition; } export interface ProtobufTypeDefinition { From 75b486b345446993ac6967e7c0572f455adb6935 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 11:37:17 +0200 Subject: [PATCH 0987/1899] gprc-js: remove deprecated tslint Upgrade to gts v2, replace npm lint with check, and specify src path --- packages/grpc-js/package.json | 9 +++++---- packages/grpc-js/tslint.json | 8 -------- 2 files changed, 5 insertions(+), 12 deletions(-) delete mode 100644 packages/grpc-js/tslint.json diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7276e8c47..3128066c0 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -26,7 +26,8 @@ "@types/semver": "^6.0.1", "clang-format": "^1.0.55", "execa": "^2.0.3", - "gts": "^1.1.0", + "google-ts-style": "^0.2.0", + "gts": "^2.0.0-alpha.9", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", @@ -46,11 +47,11 @@ "clean": "gts clean", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "lint": "tslint -c node_modules/google-ts-style/tslint.json -p . -t codeFrame --type-check", + "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", - "check": "gts check", - "fix": "gts fix", + "check": "gts check src/**/*.ts", + "fix": "gts fix src/**/*.ts", "pretest": "npm run compile", "posttest": "npm run check" }, diff --git a/packages/grpc-js/tslint.json b/packages/grpc-js/tslint.json deleted file mode 100644 index 27872a139..000000000 --- a/packages/grpc-js/tslint.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "gts/tslint.json", - "linterOptions": { - "exclude": [ - "**/*.json" - ] - } -} From 16ec0f0f6414687a53e9f05d4621b88162a9f1d7 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 11:52:24 +0200 Subject: [PATCH 0988/1899] grpc-js: allow any for linting globally The any type is purposely used. All functions validate their input at runtime. --- packages/grpc-js/.eslintrc | 7 +++++++ packages/grpc-js/src/call-stream.ts | 3 --- packages/grpc-js/src/channel-credentials.ts | 1 - packages/grpc-js/src/client-interceptors.ts | 17 ----------------- packages/grpc-js/src/client.ts | 3 --- packages/grpc-js/src/index.ts | 10 +++------- packages/grpc-js/src/load-balancing-config.ts | 4 ---- packages/grpc-js/src/logging.ts | 2 -- packages/grpc-js/src/make-client.ts | 2 -- packages/grpc-js/src/object-stream.ts | 2 -- packages/grpc-js/src/server-call.ts | 3 --- packages/grpc-js/src/server.ts | 6 ++---- packages/grpc-js/src/service-config.ts | 4 ---- packages/grpc-js/src/subchannel-pool.ts | 1 - packages/grpc-js/test/common.ts | 1 - .../grpc-js/test/test-channel-credentials.ts | 1 - packages/grpc-js/test/test-resolver.ts | 2 -- .../grpc-js/test/test-server-credentials.ts | 1 - packages/grpc-js/test/test-server-deadlines.ts | 1 - packages/grpc-js/test/test-server-errors.ts | 1 - packages/grpc-js/test/test-server.ts | 5 ++--- 21 files changed, 14 insertions(+), 63 deletions(-) create mode 100644 packages/grpc-js/.eslintrc diff --git a/packages/grpc-js/.eslintrc b/packages/grpc-js/.eslintrc new file mode 100644 index 000000000..46b51a247 --- /dev/null +++ b/packages/grpc-js/.eslintrc @@ -0,0 +1,7 @@ +{ + "root": true, + "extends": "./node_modules/gts", + "rules": { + "@typescript-eslint/no-explicit-any": "off" + } +} diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 443d5ebf4..ee7024c22 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -69,7 +69,6 @@ export interface MetadataListener { } export interface MessageListener { - // tslint:disable-next-line no-any (message: any, next: (message: any) => void): void; } @@ -90,7 +89,6 @@ export type Listener = Partial; */ export interface InterceptingListener { onReceiveMetadata(metadata: Metadata): void; - // tslint:disable-next-line no-any onReceiveMessage(message: any): void; onReceiveStatus(status: StatusObject): void; } @@ -117,7 +115,6 @@ export class InterceptingListenerImpl implements InterceptingListener { this.nextListener.onReceiveMetadata(metadata); }); } - // tslint:disable-next-line no-any onReceiveMessage(message: any): void { /* If this listener processes messages asynchronously, the last message may * be reordered with respect to the status */ diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 5d5b87d50..7eb76a386 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -20,7 +20,6 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; -// tslint:disable-next-line:no-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { if (obj && !(obj instanceof Buffer)) { throw new TypeError(`${friendlyName}, if provided, must be a Buffer.`); diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 9892959e0..c20db534b 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -64,7 +64,6 @@ export interface MetadataRequester { } export interface MessageRequester { - // tslint:disable-next-line no-any (message: any, next: (message: any) => void): void; } @@ -189,7 +188,6 @@ const defaultRequester: FullRequester = { }; export interface InterceptorOptions extends CallOptions { - // tslint:disable-next-line no-any method_definition: ClientMethodDefinition; } @@ -197,9 +195,7 @@ export interface InterceptingCallInterface { cancelWithStatus(status: Status, details: string): void; getPeer(): string; start(metadata: Metadata, listener?: Partial): void; - // tslint:disable-next-line no-any sendMessageWithContext(context: MessageContext, message: any): void; - // tslint:disable-next-line no-any sendMessage(message: any): void; startRead(): void; halfClose(): void; @@ -283,7 +279,6 @@ export class InterceptingCall implements InterceptingCallInterface { this.nextCall.start(md, finalInterceptingListener); }); } - // tslint:disable-next-line no-any sendMessageWithContext(context: MessageContext, message: any): void { this.processingMessage = true; this.requester.sendMessage(message, finalMessage => { @@ -294,7 +289,6 @@ export class InterceptingCall implements InterceptingCallInterface { } }); } - // tslint:disable-next-line no-any sendMessage(message: any): void { this.sendMessageWithContext({}, message); } @@ -343,7 +337,6 @@ function getCall(channel: Channel, path: string, options: CallOptions): Call { * object and handles serialization and deseraizliation. */ class BaseInterceptingCall implements InterceptingCallInterface { - // tslint:disable-next-line no-any constructor( protected call: Call, protected methodDefinition: ClientMethodDefinition @@ -357,7 +350,6 @@ class BaseInterceptingCall implements InterceptingCallInterface { setCredentials(credentials: CallCredentials): void { this.call.setCredentials(credentials); } - // tslint:disable-next-line no-any sendMessageWithContext(context: MessageContext, message: any): void { let serialized: Buffer; try { @@ -367,7 +359,6 @@ class BaseInterceptingCall implements InterceptingCallInterface { this.call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); } } - // tslint:disable-next-line no-any sendMessage(message: any) { this.sendMessageWithContext({}, message); } @@ -381,7 +372,6 @@ class BaseInterceptingCall implements InterceptingCallInterface { interceptingListener?.onReceiveMetadata?.(metadata); }, onReceiveMessage: message => { - // tslint:disable-next-line no-any let deserialized: any; try { deserialized = this.methodDefinition.responseDeserialize(message); @@ -418,7 +408,6 @@ class BaseInterceptingCall implements InterceptingCallInterface { */ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { - // tslint:disable-next-line no-any constructor(call: Call, methodDefinition: ClientMethodDefinition) { super(call, methodDefinition); } @@ -427,7 +416,6 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall const wrapperListener: InterceptingListener = { onReceiveMetadata: listener?.onReceiveMetadata?.bind(listener) ?? (metadata => {}), - // tslint:disable-next-line no-any onReceiveMessage: (message: any) => { receivedMessage = true; listener?.onReceiveMessage?.(message); @@ -450,8 +438,6 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall */ class BaseStreamingInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface {} - -// tslint:disable-next-line no-any function getBottomInterceptingCall( channel: Channel, options: InterceptorOptions, @@ -474,7 +460,6 @@ export interface Interceptor { } export interface InterceptorProvider { - // tslint:disable-next-line no-any (methodDefinition: ClientMethodDefinition): Interceptor; } @@ -484,8 +469,6 @@ export interface InterceptorArguments { callInterceptors: Interceptor[]; callInterceptorProviders: InterceptorProvider[]; } - -// tslint:disable-next-line no-any export function getInterceptingCall( interceptorArgs: InterceptorArguments, methodDefinition: ClientMethodDefinition, diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 8b4b7eead..118375b2b 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -306,7 +306,6 @@ export class Client { onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, - // tslint:disable-next-line no-any onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -418,7 +417,6 @@ export class Client { onReceiveMetadata: metadata => { emitter.emit('metadata', metadata); }, - // tslint:disable-next-line no-any onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -536,7 +534,6 @@ export class Client { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); }, - // tslint:disable-next-line no-any onReceiveMessage(message: any) { if (stream.push(message)) { call.startRead(); diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 941174c01..5c77a3ffd 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -62,15 +62,15 @@ if (!semver.satisfies(process.version, supportedNodeVersions)) { } interface IndexedObject { - [key: string]: any; // tslint:disable-line no-any - [key: number]: any; // tslint:disable-line no-any + [key: string]: any; + [key: number]: any; } function mixin(...sources: IndexedObject[]) { const result: { [key: string]: Function } = {}; for (const source of sources) { for (const propName of Object.getOwnPropertyNames(source)) { - const property: any = source[propName]; // tslint:disable-line no-any + const property: any = source[propName]; if (typeof property === 'function') { result[propName] = property; } @@ -245,18 +245,14 @@ export { export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall }; -/* tslint:disable:no-any */ export type Call = | ClientUnaryCall | ClientReadableStream | ClientWritableStream | ClientDuplexStream; -/* tslint:enable:no-any */ /**** Unimplemented function stubs ****/ -/* tslint:disable:no-any variable-name */ - export const loadObject = (value: any, options: any) => { throw new Error( 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead' diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 8607f1fce..4a895903f 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -21,10 +21,6 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ -/* The any type is purposely used here. All functions validate their input at - * runtime */ -/* tslint:disable:no-any */ - export interface RoundRobinConfig {} export interface XdsConfig { diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 13ed2b7e6..c7a63a476 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -47,8 +47,6 @@ export const setLogger = (logger: Partial): void => { export const setLoggerVerbosity = (verbosity: LogVerbosity): void => { _logVerbosity = verbosity; }; - -// tslint:disable-next-line no-any export const log = (severity: LogVerbosity, ...args: any[]): void => { if (severity >= _logVerbosity && typeof _logger.error === 'function') { _logger.error(...args); diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 99d40a649..f55f49178 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -50,7 +50,6 @@ export interface MethodDefinition ServerMethodDefinition {} export interface ServiceDefinition { - // tslint:disable-next-line no-any [index: string]: MethodDefinition; } @@ -165,7 +164,6 @@ function partial( serialize: Function, deserialize: Function ): Function { - // tslint:disable-next-line:no-any return function(this: any, ...args: any[]) { return fn.call(this, path, serialize, deserialize, ...args); }; diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index 624e547ca..8d29b7860 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -18,8 +18,6 @@ import { Duplex, Readable, Writable } from 'stream'; import { EmitterAugmentation1 } from './events'; -// tslint:disable:no-any - export type WriteCallback = (error: Error | null | undefined) => void; export interface IntermediateObjectReadable extends Readable { diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index efdf1bccb..d6b55ae87 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -174,7 +174,6 @@ export class ServerWritableStreamImpl async _write( chunk: ResponseType, encoding: string, - // tslint:disable-next-line:no-any callback: (...args: any[]) => void ) { try { @@ -201,7 +200,6 @@ export class ServerWritableStreamImpl callback(null); } - // tslint:disable-next-line:no-any end(metadata?: any) { if (metadata) { this.trailingMetadata = metadata; @@ -671,7 +669,6 @@ export class Http2ServerCallStream< } } -// tslint:disable:no-any type UntypedServerCall = Http2ServerCallStream; function handleExpiredDeadline(call: UntypedServerCall) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index fc48f3cfd..c37f69f71 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -67,7 +67,6 @@ function getUnimplementedStatusResponse( }; } -// tslint:disable:no-any type UntypedUnaryHandler = UnaryHandler; type UntypedClientStreamingHandler = ClientStreamingHandler; type UntypedServerStreamingHandler = ServerStreamingHandler; @@ -113,7 +112,7 @@ function getDefaultHandler(handlerType: HandlerType, methodName: string) { export class Server { private http2ServerList: (http2.Http2Server | http2.Http2SecureServer)[] = []; - + private handlers: Map = new Map< string, UntypedHandler @@ -261,7 +260,7 @@ export class Server { } else { addr = address } - + const http2Server = setupServer(); return new Promise((resolve, reject) => { function onError(err: Error): void { @@ -380,7 +379,6 @@ export class Server { this.sessions.forEach(session => { // Cast NGHTTP2_CANCEL to any because TypeScript doesn't seem to // recognize destroy(code) as a valid signature. - // tslint:disable-next-line:no-any session.destroy(http2.constants.NGHTTP2_CANCEL as any); }); this.sessions.clear(); diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index e4631507b..b1b0fdd41 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -22,10 +22,6 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ -/* The any type is purposely used here. All functions validate their input at - * runtime */ -/* tslint:disable:no-any */ - import * as lbconfig from './load-balancing-config'; import * as os from 'os'; diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 0f198afec..634d25756 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -63,7 +63,6 @@ export class SubchannelPool { /* These objects are created with Object.create(null), so they do not * have a prototype, which means that for (... in ...) loops over them * do not need to be filtered */ - // tslint:disable-next-line:forin for (const channelTarget in this.pool) { const subchannelObjArray = this.pool[channelTarget]; diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index 19d8d2753..4f8c5ff81 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -73,7 +73,6 @@ export namespace assert2 { * Wraps a function to keep track of whether it was called or not. * @param fn The function to wrap. */ - // tslint:disable:no-any export function mustCall( fn: (...args: any[]) => T ): (...args: any[]) => T { diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index d6028f469..99966941a 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -49,7 +49,6 @@ class CallCredentialsMock implements CallCredentials { } } -// tslint:disable-next-line:no-any const readFile: (...args: any[]) => Promise = promisify(fs.readFile); // A promise which resolves to loaded files in the form { ca, key, cert } const pFixtures = Promise.all( diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 7f4900aa2..57997c17e 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -15,8 +15,6 @@ * */ -// Allow `any` data type for testing runtime type checking. -// tslint:disable no-any import * as assert from 'assert'; import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; diff --git a/packages/grpc-js/test/test-server-credentials.ts b/packages/grpc-js/test/test-server-credentials.ts index ec1740f70..9cc08b10e 100644 --- a/packages/grpc-js/test/test-server-credentials.ts +++ b/packages/grpc-js/test/test-server-credentials.ts @@ -16,7 +16,6 @@ */ // Allow `any` data type for testing runtime type checking. -// tslint:disable no-any import * as assert from 'assert'; import { readFileSync } from 'fs'; import { join } from 'path'; diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts index c1152309d..107994ba9 100644 --- a/packages/grpc-js/test/test-server-deadlines.ts +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -16,7 +16,6 @@ */ // Allow `any` data type for testing runtime type checking. -// tslint:disable no-any import * as assert from 'assert'; import * as path from 'path'; diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 7c611b9bc..8e9f45209 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -16,7 +16,6 @@ */ // Allow `any` data type for testing runtime type checking. -// tslint:disable no-any import * as assert from 'assert'; import { join } from 'path'; diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 434efbbc4..c8d2e64ad 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -16,7 +16,6 @@ */ // Allow `any` data type for testing runtime type checking. -// tslint:disable no-any import * as assert from 'assert'; import * as fs from 'fs'; import * as http2 from 'http2'; @@ -39,13 +38,13 @@ describe('Server', () => { describe('constructor', () => { it('should work with no arguments', () => { assert.doesNotThrow(() => { - new Server(); // tslint:disable-line:no-unused-expression + new Server(); }); }); it('should work with an empty object argument', () => { assert.doesNotThrow(() => { - new Server({}); // tslint:disable-line:no-unused-expression + new Server({}); }); }); From f4e295cdce2805928afbf4298f8ae35ed972ed3b Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 11:53:13 +0200 Subject: [PATCH 0989/1899] grpc-js: linting fix no-unpublished-import for ts --- packages/grpc-js/.eslintrc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/.eslintrc b/packages/grpc-js/.eslintrc index 46b51a247..6b0cac4ab 100644 --- a/packages/grpc-js/.eslintrc +++ b/packages/grpc-js/.eslintrc @@ -2,6 +2,9 @@ "root": true, "extends": "./node_modules/gts", "rules": { - "@typescript-eslint/no-explicit-any": "off" + "@typescript-eslint/no-explicit-any": "off", + "node/no-unpublished-import": ["error", { + "tryExtensions": [".ts", ".js", ".json", ".node"] + }] } } From b84d2f3b39eb2e51457e372fd5972df77281fbb6 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 11:54:09 +0200 Subject: [PATCH 0990/1899] grpc-js: run gts fix for src --- packages/grpc-js/src/call-credentials.ts | 2 +- packages/grpc-js/src/call-stream.ts | 29 ++- packages/grpc-js/src/call.ts | 12 +- packages/grpc-js/src/channel.ts | 76 +++++--- packages/grpc-js/src/client-interceptors.ts | 36 ++-- packages/grpc-js/src/client.ts | 78 +++++--- packages/grpc-js/src/filter-stack.ts | 2 +- packages/grpc-js/src/http_proxy.ts | 74 ++++++-- packages/grpc-js/src/index.ts | 13 +- .../grpc-js/src/load-balancer-pick-first.ts | 4 +- .../grpc-js/src/load-balancer-round-robin.ts | 6 +- packages/grpc-js/src/make-client.ts | 4 +- packages/grpc-js/src/metadata.ts | 14 +- packages/grpc-js/src/resolver-dns.ts | 171 ++++++++++-------- packages/grpc-js/src/server-call.ts | 6 +- packages/grpc-js/src/server.ts | 161 +++++++++++------ packages/grpc-js/src/subchannel-pool.ts | 2 +- packages/grpc-js/src/subchannel.ts | 26 ++- 18 files changed, 435 insertions(+), 281 deletions(-) diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index e38672ae2..e5d22bf79 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -79,7 +79,7 @@ class ComposedCallCredentials extends CallCredentials { async generateMetadata(options: CallMetadataOptions): Promise { const base: Metadata = new Metadata(); const generated: Metadata[] = await Promise.all( - this.creds.map(cred => cred.generateMetadata(options)) + this.creds.map((cred) => cred.generateMetadata(options)) ); for (const gen of generated) { base.merge(gen); diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index ee7024c22..f40366ca2 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -111,7 +111,7 @@ export class InterceptingListenerImpl implements InterceptingListener { ) {} onReceiveMetadata(metadata: Metadata): void { - this.listener.onReceiveMetadata(metadata, metadata => { + this.listener.onReceiveMetadata(metadata, (metadata) => { this.nextListener.onReceiveMetadata(metadata); }); } @@ -119,7 +119,7 @@ export class InterceptingListenerImpl implements InterceptingListener { /* If this listener processes messages asynchronously, the last message may * be reordered with respect to the status */ this.processingMessage = true; - this.listener.onReceiveMessage(message, msg => { + this.listener.onReceiveMessage(message, (msg) => { this.processingMessage = false; this.nextListener.onReceiveMessage(msg); if (this.pendingStatus) { @@ -128,7 +128,7 @@ export class InterceptingListenerImpl implements InterceptingListener { }); } onReceiveStatus(status: StatusObject): void { - this.listener.onReceiveStatus(status, processedStatus => { + this.listener.onReceiveStatus(status, (processedStatus) => { if (this.processingMessage) { this.pendingStatus = processedStatus; } else { @@ -221,7 +221,9 @@ export class Http2CallStream implements Call { /* Precondition: this.finalStatus !== null */ if (!this.statusOutput) { this.statusOutput = true; - const filteredStatus = this.filterStack.receiveTrailers(this.finalStatus!); + const filteredStatus = this.filterStack.receiveTrailers( + this.finalStatus! + ); this.listener!.onReceiveStatus(filteredStatus); if (this.subchannel) { this.subchannel.callUnref(); @@ -352,7 +354,7 @@ export class Http2CallStream implements Call { private handleTrailers(headers: http2.IncomingHttpHeaders) { let headersString = ''; for (const header of Object.keys(headers)) { - headersString += '\t\t' + header + ': ' + headers[header] + '\n' + headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } this.trace('Received server trailers:\n' + headersString); let metadata: Metadata; @@ -363,7 +365,10 @@ export class Http2CallStream implements Call { } const metadataMap = metadata.getMap(); let code: Status = this.mappedStatusCode; - if (code === Status.UNKNOWN && typeof metadataMap['grpc-status'] === 'string') { + if ( + code === Status.UNKNOWN && + typeof metadataMap['grpc-status'] === 'string' + ) { const receivedStatus = Number(metadataMap['grpc-status']); if (receivedStatus in Status) { code = receivedStatus; @@ -375,7 +380,9 @@ export class Http2CallStream implements Call { if (typeof metadataMap['grpc-message'] === 'string') { details = decodeURI(metadataMap['grpc-message']); metadata.remove('grpc-message'); - this.trace('received status details string "' + details + '" from server'); + this.trace( + 'received status details string "' + details + '" from server' + ); } const status: StatusObject = { code, details, metadata }; let finalStatus; @@ -412,7 +419,7 @@ export class Http2CallStream implements Call { stream.on('response', (headers, flags) => { let headersString = ''; for (const header of Object.keys(headers)) { - headersString += '\t\t' + header + ': ' + headers[header] + '\n' + headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } this.trace('Received server headers:\n' + headersString); switch (headers[':status']) { @@ -575,7 +582,9 @@ export class Http2CallStream implements Call { } cancelWithStatus(status: Status, details: string): void { - this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); + this.trace( + 'cancelWithStatus code: ' + status + ' details: "' + details + '"' + ); this.destroyHttp2Stream(); this.endCall({ code: status, details, metadata: new Metadata() }); } @@ -650,7 +659,7 @@ export class Http2CallStream implements Call { }; const cb: WriteCallback = context.callback ?? (() => {}); this.isWriteFilterPending = true; - this.filterStack.sendMessage(Promise.resolve(writeObj)).then(message => { + this.filterStack.sendMessage(Promise.resolve(writeObj)).then((message) => { this.isWriteFilterPending = false; if (this.http2Stream === null) { this.trace( diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 61885cd6e..0d88ef151 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -100,9 +100,7 @@ export class ClientUnaryCallImpl extends EventEmitter export class ClientReadableStreamImpl extends Readable implements ClientReadableStream { public call?: InterceptingCallInterface; - constructor( - readonly deserialize: (chunk: Buffer) => ResponseType - ) { + constructor(readonly deserialize: (chunk: Buffer) => ResponseType) { super({ objectMode: true }); } @@ -122,9 +120,7 @@ export class ClientReadableStreamImpl extends Readable export class ClientWritableStreamImpl extends Writable implements ClientWritableStream { public call?: InterceptingCallInterface; - constructor( - readonly serialize: (value: RequestType) => Buffer - ) { + constructor(readonly serialize: (value: RequestType) => Buffer) { super({ objectMode: true }); } @@ -140,7 +136,7 @@ export class ClientWritableStreamImpl extends Writable const context: MessageContext = { callback: cb, }; - const flags: number = Number(encoding); + const flags = Number(encoding); if (!Number.isNaN(flags)) { context.flags = flags; } @@ -179,7 +175,7 @@ export class ClientDuplexStreamImpl extends Duplex const context: MessageContext = { callback: cb, }; - const flags: number = Number(encoding); + const flags = Number(encoding); if (!Number.isNaN(flags)) { context.flags = flags; } diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 4d07dde03..a8b9f4ec8 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -144,11 +144,23 @@ export class ChannelImplementation implements Channel { throw new TypeError('Channel target must be a string'); } if (!(credentials instanceof ChannelCredentials)) { - throw new TypeError('Channel credentials must be a ChannelCredentials object'); + throw new TypeError( + 'Channel credentials must be a ChannelCredentials object' + ); } if (options) { - if ((typeof options !== 'object') || !Object.values(options).every(value => typeof value === 'string' || typeof value === 'number' || typeof value === 'undefined')) { - throw new TypeError('Channel options must be an object with string or number values'); + if ( + typeof options !== 'object' || + !Object.values(options).every( + (value) => + typeof value === 'string' || + typeof value === 'number' || + typeof value === 'undefined' + ) + ) { + throw new TypeError( + 'Channel options must be an object with string or number values' + ); } } /* The global boolean parameter to getSubchannelPool has the inverse meaning to what @@ -265,7 +277,7 @@ export class ChannelImplementation implements Channel { callStream.filterStack .sendMetadata(Promise.resolve(callMetadata.clone())) .then( - finalMetadata => { + (finalMetadata) => { const subchannelState: ConnectivityState = pickResult.subchannel!.getConnectivityState(); if (subchannelState === ConnectivityState.READY) { try { @@ -274,28 +286,31 @@ export class ChannelImplementation implements Channel { callStream ); } catch (error) { - if ((error as NodeJS.ErrnoException).code === 'ERR_HTTP2_GOAWAY_SESSION') { + if ( + (error as NodeJS.ErrnoException).code === + 'ERR_HTTP2_GOAWAY_SESSION' + ) { /* An error here indicates that something went wrong with - * the picked subchannel's http2 stream right before we - * tried to start the stream. We are handling a promise - * result here, so this is asynchronous with respect to the - * original tryPick call, so calling it again is not - * recursive. We call tryPick immediately instead of - * queueing this pick again because handling the queue is - * triggered by state changes, and we want to immediately - * check if the state has already changed since the - * previous tryPick call. We do this instead of cancelling - * the stream because the correct behavior may be - * re-queueing instead, based on the logic in the rest of - * tryPick */ + * the picked subchannel's http2 stream right before we + * tried to start the stream. We are handling a promise + * result here, so this is asynchronous with respect to the + * original tryPick call, so calling it again is not + * recursive. We call tryPick immediately instead of + * queueing this pick again because handling the queue is + * triggered by state changes, and we want to immediately + * check if the state has already changed since the + * previous tryPick call. We do this instead of cancelling + * the stream because the correct behavior may be + * re-queueing instead, based on the logic in the rest of + * tryPick */ trace( LogVerbosity.INFO, 'channel', 'Failed to start call on picked subchannel ' + - pickResult.subchannel!.getAddress() + - ' with error ' + - (error as Error).message + - '. Retrying pick' + pickResult.subchannel!.getAddress() + + ' with error ' + + (error as Error).message + + '. Retrying pick' ); this.tryPick(callStream, callMetadata); } else { @@ -303,12 +318,15 @@ export class ChannelImplementation implements Channel { LogVerbosity.INFO, 'channel', 'Failed to start call on picked subchanel ' + - pickResult.subchannel!.getAddress() + - ' with error ' + - (error as Error).message + - '. Ending call' + pickResult.subchannel!.getAddress() + + ' with error ' + + (error as Error).message + + '. Ending call' + ); + callStream.cancelWithStatus( + Status.INTERNAL, + 'Failed to start HTTP/2 stream' ); - callStream.cancelWithStatus(Status.INTERNAL, 'Failed to start HTTP/2 stream'); } } } else { @@ -360,7 +378,7 @@ export class ChannelImplementation implements Channel { watcherObject: ConnectivityStateWatcher ) { const watcherIndex = this.connectivityStateWatchers.findIndex( - value => value === watcherObject + (value) => value === watcherObject ); if (watcherIndex >= 0) { this.connectivityStateWatchers.splice(watcherIndex, 1); @@ -450,7 +468,9 @@ export class ChannelImplementation implements Channel { throw new TypeError('Channel#createCall: method must be a string'); } if (!(typeof deadline === 'number' || deadline instanceof Date)) { - throw new TypeError('Channel#createCall: deadline must be a number or Date'); + throw new TypeError( + 'Channel#createCall: deadline must be a number or Date' + ); } if (this.connectivityState === ConnectivityState.SHUTDOWN) { throw new Error('Channel has been shut down'); diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index c20db534b..72bbdab91 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -179,10 +179,10 @@ const defaultRequester: FullRequester = { sendMessage: (message, next) => { next(message); }, - halfClose: next => { + halfClose: (next) => { next(); }, - cancel: next => { + cancel: (next) => { next(); }, }; @@ -250,13 +250,13 @@ export class InterceptingCall implements InterceptingCallInterface { const fullInterceptingListener: InterceptingListener = { onReceiveMetadata: interceptingListener?.onReceiveMetadata?.bind(interceptingListener) ?? - (metadata => {}), + ((metadata) => {}), onReceiveMessage: interceptingListener?.onReceiveMessage?.bind(interceptingListener) ?? - (message => {}), + ((message) => {}), onReceiveStatus: interceptingListener?.onReceiveStatus?.bind(interceptingListener) ?? - (status => {}), + ((status) => {}), }; this.requester.start(metadata, fullInterceptingListener, (md, listener) => { let finalInterceptingListener: InterceptingListener; @@ -281,7 +281,7 @@ export class InterceptingCall implements InterceptingCallInterface { } sendMessageWithContext(context: MessageContext, message: any): void { this.processingMessage = true; - this.requester.sendMessage(message, finalMessage => { + this.requester.sendMessage(message, (finalMessage) => { this.processingMessage = false; this.nextCall.sendMessageWithContext(context, finalMessage); if (this.pendingHalfClose) { @@ -368,10 +368,10 @@ class BaseInterceptingCall implements InterceptingCallInterface { ): void { let readError: StatusObject | null = null; this.call.start(metadata, { - onReceiveMetadata: metadata => { + onReceiveMetadata: (metadata) => { interceptingListener?.onReceiveMetadata?.(metadata); }, - onReceiveMessage: message => { + onReceiveMessage: (message) => { let deserialized: any; try { deserialized = this.methodDefinition.responseDeserialize(message); @@ -385,7 +385,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { this.call.cancelWithStatus(readError.code, readError.details); } }, - onReceiveStatus: status => { + onReceiveStatus: (status) => { if (readError) { interceptingListener?.onReceiveStatus?.(readError); } else { @@ -415,7 +415,7 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall let receivedMessage = false; const wrapperListener: InterceptingListener = { onReceiveMetadata: - listener?.onReceiveMetadata?.bind(listener) ?? (metadata => {}), + listener?.onReceiveMetadata?.bind(listener) ?? ((metadata) => {}), onReceiveMessage: (message: any) => { receivedMessage = true; listener?.onReceiveMessage?.(message); @@ -502,21 +502,21 @@ export function getInterceptingCall( interceptors = ([] as Interceptor[]) .concat( interceptorArgs.callInterceptors, - interceptorArgs.callInterceptorProviders.map(provider => + interceptorArgs.callInterceptorProviders.map((provider) => provider(methodDefinition) ) ) - .filter(interceptor => interceptor); + .filter((interceptor) => interceptor); // Filter out falsy values when providers return nothing } else { interceptors = ([] as Interceptor[]) .concat( interceptorArgs.clientInterceptors, - interceptorArgs.clientInterceptorProviders.map(provider => + interceptorArgs.clientInterceptorProviders.map((provider) => provider(methodDefinition) ) ) - .filter(interceptor => interceptor); + .filter((interceptor) => interceptor); // Filter out falsy values when providers return nothing } const interceptorOptions = Object.assign({}, options, { @@ -531,14 +531,10 @@ export function getInterceptingCall( * channel. */ const getCall: NextCall = interceptors.reduceRight( (nextCall: NextCall, nextInterceptor: Interceptor) => { - return currentOptions => nextInterceptor(currentOptions, nextCall); + return (currentOptions) => nextInterceptor(currentOptions, nextCall); }, (finalOptions: InterceptorOptions) => - getBottomInterceptingCall( - channel, - finalOptions, - methodDefinition - ) + getBottomInterceptingCall(channel, finalOptions, methodDefinition) ); return getCall(interceptorOptions); } diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 118375b2b..f33de1f72 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -48,7 +48,12 @@ import { InterceptorArguments, InterceptingCallInterface, } from './client-interceptors'; -import { ServerUnaryCall, ServerReadableStream, ServerWritableStream, ServerDuplexStream } from './server-call'; +import { + ServerUnaryCall, + ServerReadableStream, + ServerWritableStream, + ServerDuplexStream, +} from './server-call'; const CHANNEL_SYMBOL = Symbol(); const INTERCEPTOR_SYMBOL = Symbol(); @@ -62,7 +67,11 @@ export interface UnaryCallback { export interface CallOptions { deadline?: Deadline; host?: string; - parent?: ServerUnaryCall | ServerReadableStream | ServerWritableStream | ServerDuplexStream + parent?: + | ServerUnaryCall + | ServerReadableStream + | ServerWritableStream + | ServerDuplexStream; propagate_flags?: number; credentials?: CallCredentials; interceptors?: Interceptor[]; @@ -76,11 +85,11 @@ export interface CallProperties { channel: Channel; methodDefinition: ClientMethodDefinition; callOptions: CallOptions; - callback?: UnaryCallback + callback?: UnaryCallback; } export interface CallInvocationTransformer { - (callProperties: CallProperties): CallProperties + (callProperties: CallProperties): CallProperties; } export type ClientOptions = Partial & { @@ -123,7 +132,8 @@ export class Client { 'to the client constructor. Only one of these is allowed.' ); } - this[CALL_INVOCATION_TRANSFORMER_SYMBOL] = options.callInvocationTransformer; + this[CALL_INVOCATION_TRANSFORMER_SYMBOL] = + options.callInvocationTransformer; delete options.callInvocationTransformer; if (options.channelOverride) { this[CHANNEL_SYMBOL] = options.channelOverride; @@ -274,17 +284,20 @@ export class Client { channel: this[CHANNEL_SYMBOL], methodDefinition: methodDefinition, callOptions: checkedArguments.options, - callback: checkedArguments.callback + callback: checkedArguments.callback, }; if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { - callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!( + callProperties + ) as CallProperties; } const emitter: ClientUnaryCall = callProperties.call; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: callProperties.callOptions.interceptors ?? [], - callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], + callInterceptorProviders: + callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, @@ -303,7 +316,7 @@ export class Client { let responseMessage: ResponseType | null = null; let receivedStatus = false; call.start(callProperties.metadata, { - onReceiveMetadata: metadata => { + onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); }, onReceiveMessage(message: any) { @@ -385,17 +398,22 @@ export class Client { channel: this[CHANNEL_SYMBOL], methodDefinition: methodDefinition, callOptions: checkedArguments.options, - callback: checkedArguments.callback + callback: checkedArguments.callback, }; if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { - callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!( + callProperties + ) as CallProperties; } - const emitter: ClientWritableStream = callProperties.call as ClientWritableStream; + const emitter: ClientWritableStream = callProperties.call as ClientWritableStream< + RequestType + >; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: callProperties.callOptions.interceptors ?? [], - callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], + callInterceptorProviders: + callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, @@ -414,7 +432,7 @@ export class Client { let responseMessage: ResponseType | null = null; let receivedStatus = false; call.start(callProperties.metadata, { - onReceiveMetadata: metadata => { + onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); }, onReceiveMessage(message: any) { @@ -503,17 +521,22 @@ export class Client { call: new ClientReadableStreamImpl(deserialize), channel: this[CHANNEL_SYMBOL], methodDefinition: methodDefinition, - callOptions: checkedArguments.options + callOptions: checkedArguments.options, }; if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { - callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!( + callProperties + ) as CallProperties; } - const stream: ClientReadableStream = callProperties.call as ClientReadableStream; + const stream: ClientReadableStream = callProperties.call as ClientReadableStream< + ResponseType + >; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: callProperties.callOptions.interceptors ?? [], - callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], + callInterceptorProviders: + callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, @@ -589,20 +612,29 @@ export class Client { }; let callProperties: CallProperties = { metadata: checkedArguments.metadata, - call: new ClientDuplexStreamImpl(serialize, deserialize), + call: new ClientDuplexStreamImpl( + serialize, + deserialize + ), channel: this[CHANNEL_SYMBOL], methodDefinition: methodDefinition, - callOptions: checkedArguments.options + callOptions: checkedArguments.options, }; if (this[CALL_INVOCATION_TRANSFORMER_SYMBOL]) { - callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!(callProperties) as CallProperties; + callProperties = this[CALL_INVOCATION_TRANSFORMER_SYMBOL]!( + callProperties + ) as CallProperties; } - const stream: ClientDuplexStream = callProperties.call as ClientDuplexStream; + const stream: ClientDuplexStream< + RequestType, + ResponseType + > = callProperties.call as ClientDuplexStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], callInterceptors: callProperties.callOptions.interceptors ?? [], - callInterceptorProviders: callProperties.callOptions.interceptor_providers ?? [], + callInterceptorProviders: + callProperties.callOptions.interceptor_providers ?? [], }; const call: InterceptingCallInterface = getInterceptingCall( interceptorArgs, diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 3b6f16ba4..a656a4099 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -78,7 +78,7 @@ export class FilterStackFactory implements FilterFactory { createFilter(callStream: Call): FilterStack { return new FilterStack( - this.factories.map(factory => factory.createFilter(callStream)) + this.factories.map((factory) => factory.createFilter(callStream)) ); } } diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index ecff1bb5f..ef52dedac 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -15,14 +15,18 @@ * */ -import { URL, parse } from "url"; -import { log } from "./logging"; -import { LogVerbosity } from "./constants"; -import { parseTarget } from "./resolver-dns"; -import { Socket } from "net"; +import { URL, parse } from 'url'; +import { log } from './logging'; +import { LogVerbosity } from './constants'; +import { parseTarget } from './resolver-dns'; +import { Socket } from 'net'; import * as http from 'http'; import * as logging from './logging'; -import { SubchannelAddress, TcpSubchannelAddress, isTcpSubchannelAddress } from "./subchannel"; +import { + SubchannelAddress, + TcpSubchannelAddress, + isTcpSubchannelAddress, +} from './subchannel'; const TRACER_NAME = 'proxy'; @@ -36,8 +40,8 @@ interface ProxyInfo { } function getProxyInfo(): ProxyInfo { - let proxyEnv: string = ''; - let envVar: string = ''; + let proxyEnv = ''; + let envVar = ''; /* Prefer using 'grpc_proxy'. Fallback on 'http_proxy' if it is not set. * Also prefer using 'https_proxy' with fallback on 'http_proxy'. The * fallback behavior can be removed if there's a demand for it. @@ -62,7 +66,10 @@ function getProxyInfo(): ProxyInfo { return {}; } if (proxyUrl.protocol !== 'http:') { - log(LogVerbosity.ERROR, `"${proxyUrl.protocol}" scheme not supported in proxy URI`); + log( + LogVerbosity.ERROR, + `"${proxyUrl.protocol}" scheme not supported in proxy URI` + ); return {}; } let userCred: string | null = null; @@ -75,12 +82,14 @@ function getProxyInfo(): ProxyInfo { } } const result: ProxyInfo = { - address: proxyUrl.host + address: proxyUrl.host, }; if (userCred) { result.creds = userCred; } - trace('Proxy server ' + result.address + ' set by environment variable ' + envVar); + trace( + 'Proxy server ' + result.address + ' set by environment variable ' + envVar + ); return result; } @@ -89,7 +98,7 @@ const PROXY_INFO = getProxyInfo(); function getNoProxyHostList(): string[] { /* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */ let noProxyStr: string | undefined = process.env.no_grpc_proxy; - let envVar: string = 'no_grpc_proxy'; + let envVar = 'no_grpc_proxy'; if (!noProxyStr) { noProxyStr = process.env.no_proxy; envVar = 'no_proxy'; @@ -124,20 +133,37 @@ export function shouldUseProxy(target: string): boolean { return true; } -export function getProxiedConnection(target: string, subchannelAddress: SubchannelAddress): Promise { - if (!(PROXY_INFO.address && shouldUseProxy(target) && isTcpSubchannelAddress(subchannelAddress))) { +export function getProxiedConnection( + target: string, + subchannelAddress: SubchannelAddress +): Promise { + if ( + !( + PROXY_INFO.address && + shouldUseProxy(target) && + isTcpSubchannelAddress(subchannelAddress) + ) + ) { return Promise.reject(); } const subchannelAddressPathString = `${subchannelAddress.host}:${subchannelAddress.port}`; - trace('Using proxy ' + PROXY_INFO.address + ' to connect to ' + target + ' at ' + subchannelAddress); + trace( + 'Using proxy ' + + PROXY_INFO.address + + ' to connect to ' + + target + + ' at ' + + subchannelAddress + ); const options: http.RequestOptions = { method: 'CONNECT', host: PROXY_INFO.address, - path: subchannelAddressPathString + path: subchannelAddressPathString, }; if (PROXY_INFO.creds) { options.headers = { - 'Proxy-Authorization': 'Basic ' + Buffer.from(PROXY_INFO.creds).toString('base64') + 'Proxy-Authorization': + 'Basic ' + Buffer.from(PROXY_INFO.creds).toString('base64'), }; } return new Promise((resolve, reject) => { @@ -146,10 +172,20 @@ export function getProxiedConnection(target: string, subchannelAddress: Subchann request.removeAllListeners(); socket.removeAllListeners(); if (res.statusCode === http.STATUS_CODES.OK) { - trace('Successfully connected to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); + trace( + 'Successfully connected to ' + + subchannelAddress + + ' through proxy ' + + PROXY_INFO.address + ); resolve(socket); } else { - trace('Failed to connect to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); + trace( + 'Failed to connect to ' + + subchannelAddress + + ' through proxy ' + + PROXY_INFO.address + ); reject(); } }); diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 5c77a3ffd..8324ff4ca 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -28,7 +28,12 @@ import { CallCredentials } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; -import { CallOptions, Client, CallInvocationTransformer, CallProperties } from './client'; +import { + CallOptions, + Client, + CallInvocationTransformer, + CallProperties, +} from './client'; import { LogVerbosity, Status } from './constants'; import * as logging from './logging'; import { @@ -129,14 +134,14 @@ export const credentials = mixin( }); } getHeaders.then( - headers => { + (headers) => { const metadata = new Metadata(); for (const key of Object.keys(headers)) { metadata.add(key, headers[key]); } callback(null, metadata); }, - err => { + (err) => { callback(err); } ); @@ -202,7 +207,7 @@ export { CallProperties, CallInvocationTransformer, ChannelImplementation as Channel, - Channel as ChannelInterface + Channel as ChannelInterface, }; /** diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index e0e1768cf..6b9756fff 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -338,11 +338,11 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.resetSubchannelList(); trace( 'Connect to address list ' + - this.latestAddressList.map(address => + this.latestAddressList.map((address) => subchannelAddressToString(address) ) ); - this.subchannels = this.latestAddressList.map(address => + this.subchannels = this.latestAddressList.map((address) => this.channelControlHelper.createSubchannel(address, {}) ); for (const subchannel of this.subchannels) { diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 863fec774..93c64610c 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -125,7 +125,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { private calculateAndUpdateState() { if (this.subchannelStateCounts[ConnectivityState.READY] > 0) { const readySubchannels = this.subchannels.filter( - subchannel => + (subchannel) => subchannel.getConnectivityState() === ConnectivityState.READY ); let index = 0; @@ -192,9 +192,9 @@ export class RoundRobinLoadBalancer implements LoadBalancer { this.resetSubchannelList(); trace( 'Connect to address list ' + - addressList.map(address => subchannelAddressToString(address)) + addressList.map((address) => subchannelAddressToString(address)) ); - this.subchannels = addressList.map(address => + this.subchannels = addressList.map((address) => this.channelControlHelper.createSubchannel(address, {}) ); for (const subchannel of this.subchannels) { diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index f55f49178..99daef158 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -116,7 +116,7 @@ export function makeClientConstructor( [methodName: string]: Function; } - Object.keys(methods).forEach(name => { + Object.keys(methods).forEach((name) => { const attrs = methods[name]; let methodType: keyof typeof requesterFuncs; // TODO(murgatroid99): Verify that we don't need this anymore @@ -164,7 +164,7 @@ function partial( serialize: Function, deserialize: Function ): Function { - return function(this: any, ...args: any[]) { + return function (this: any, ...args: any[]) { return fn.call(this, path, serialize, deserialize, ...args); }; } diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 630fb99ad..0ffe0af21 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -178,7 +178,7 @@ export class Metadata { const newInternalRepr = newMetadata.internalRepr; this.internalRepr.forEach((value, key) => { - const clonedValue: MetadataValue[] = value.map(v => { + const clonedValue: MetadataValue[] = value.map((v) => { if (v instanceof Buffer) { return Buffer.from(v); } else { @@ -226,7 +226,7 @@ export class Metadata { this.internalRepr.forEach((values, key) => { // We assume that the user's interaction with this object is limited to // through its public API (i.e. keys and values are already validated). - result[key] = values.map(value => { + result[key] = values.map((value) => { if (value instanceof Buffer) { return value.toString('base64'); } else { @@ -249,7 +249,7 @@ export class Metadata { */ static fromHttp2Headers(headers: http2.IncomingHttpHeaders): Metadata { const result = new Metadata(); - Object.keys(headers).forEach(key => { + Object.keys(headers).forEach((key) => { // Reserved headers (beginning with `:`) are not valid keys. if (key.charAt(0) === ':') { return; @@ -260,12 +260,12 @@ export class Metadata { try { if (isBinaryKey(key)) { if (Array.isArray(values)) { - values.forEach(value => { + values.forEach((value) => { result.add(key, Buffer.from(value, 'base64')); }); } else if (values !== undefined) { if (isCustomMetadata(key)) { - values.split(',').forEach(v => { + values.split(',').forEach((v) => { result.add(key, Buffer.from(v.trim(), 'base64')); }); } else { @@ -274,12 +274,12 @@ export class Metadata { } } else { if (Array.isArray(values)) { - values.forEach(value => { + values.forEach((value) => { result.add(key, value); }); } else if (values !== undefined) { if (isCustomMetadata(key)) { - values.split(',').forEach(v => result.add(key, v.trim())); + values.split(',').forEach((v) => result.add(key, v.trim())); } else { result.add(key, values); } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 82727a42d..a42a898f8 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -109,7 +109,7 @@ function mergeArrays(...arrays: T[][]): T[] { i < Math.max.apply( null, - arrays.map(array => array.length) + arrays.map((array) => array.length) ); i++ ) { @@ -186,50 +186,56 @@ class DnsResolver implements Resolver { * if the name exists but there are no records for that family, and that * error is indistinguishable from other kinds of errors */ this.pendingLookupPromise = dnsLookupPromise(hostname, { all: true }); - this.pendingLookupPromise.then(addressList => { - this.pendingLookupPromise = null; - const ip4Addresses: dns.LookupAddress[] = addressList.filter( - addr => addr.family === 4 - ); - const ip6Addresses: dns.LookupAddress[] = addressList.filter(addr => addr.family === 6); - this.latestLookupResult = mergeArrays( - ip6Addresses, - ip4Addresses - ).map(addr => ({ host: addr.address, port: +this.port! })); - const allAddressesString: string = - '[' + - this.latestLookupResult.map(addr => addr.host + ':' + addr.port).join(',') + - ']'; - trace( - 'Resolved addresses for target ' + - this.target + - ': ' + - allAddressesString - ); - if (this.latestLookupResult.length === 0) { + this.pendingLookupPromise.then( + (addressList) => { + this.pendingLookupPromise = null; + const ip4Addresses: dns.LookupAddress[] = addressList.filter( + (addr) => addr.family === 4 + ); + const ip6Addresses: dns.LookupAddress[] = addressList.filter( + (addr) => addr.family === 6 + ); + this.latestLookupResult = mergeArrays( + ip6Addresses, + ip4Addresses + ).map((addr) => ({ host: addr.address, port: +this.port! })); + const allAddressesString: string = + '[' + + this.latestLookupResult + .map((addr) => addr.host + ':' + addr.port) + .join(',') + + ']'; + trace( + 'Resolved addresses for target ' + + this.target + + ': ' + + allAddressesString + ); + if (this.latestLookupResult.length === 0) { + this.listener.onError(this.defaultResolutionError); + return; + } + /* If the TXT lookup has not yet finished, both of the last two + * arguments will be null, which is the equivalent of getting an + * empty TXT response. When the TXT lookup does finish, its handler + * can update the service config by using the same address list */ + this.listener.onSuccessfulResolution( + this.latestLookupResult, + this.latestServiceConfig, + this.latestServiceConfigError + ); + }, + (err) => { + trace( + 'Resolution error for target ' + + this.target + + ': ' + + (err as Error).message + ); + this.pendingLookupPromise = null; this.listener.onError(this.defaultResolutionError); - return; } - /* If the TXT lookup has not yet finished, both of the last two - * arguments will be null, which is the equivalent of getting an - * empty TXT response. When the TXT lookup does finish, its handler - * can update the service config by using the same address list */ - this.listener.onSuccessfulResolution( - this.latestLookupResult, - this.latestServiceConfig, - this.latestServiceConfigError - ); - }, - err => { - trace( - 'Resolution error for target ' + - this.target + - ': ' + - (err as Error).message - ); - this.pendingLookupPromise = null; - this.listener.onError(this.defaultResolutionError); - }); + ); /* If there already is a still-pending TXT resolution, we can just use * that result when it comes in */ if (this.pendingTxtPromise === null) { @@ -237,45 +243,48 @@ class DnsResolver implements Resolver { * the name resolution attempt as a whole is a success even if the TXT * lookup fails */ this.pendingTxtPromise = resolveTxtPromise(hostname); - this.pendingTxtPromise.then(txtRecord => { - this.pendingTxtPromise = null; - try { - this.latestServiceConfig = extractAndSelectServiceConfig( - txtRecord, - this.percentage - ); - } catch (err) { + this.pendingTxtPromise.then( + (txtRecord) => { + this.pendingTxtPromise = null; + try { + this.latestServiceConfig = extractAndSelectServiceConfig( + txtRecord, + this.percentage + ); + } catch (err) { + this.latestServiceConfigError = { + code: Status.UNAVAILABLE, + details: 'Parsing service config failed', + metadata: new Metadata(), + }; + } + if (this.latestLookupResult !== null) { + /* We rely here on the assumption that calling this function with + * identical parameters will be essentialy idempotent, and calling + * it with the same address list and a different service config + * should result in a fast and seamless switchover. */ + this.listener.onSuccessfulResolution( + this.latestLookupResult, + this.latestServiceConfig, + this.latestServiceConfigError + ); + } + }, + (err) => { this.latestServiceConfigError = { code: Status.UNAVAILABLE, - details: 'Parsing service config failed', + details: 'TXT query failed', metadata: new Metadata(), }; + if (this.latestLookupResult !== null) { + this.listener.onSuccessfulResolution( + this.latestLookupResult, + this.latestServiceConfig, + this.latestServiceConfigError + ); + } } - if (this.latestLookupResult !== null) { - /* We rely here on the assumption that calling this function with - * identical parameters will be essentialy idempotent, and calling - * it with the same address list and a different service config - * should result in a fast and seamless switchover. */ - this.listener.onSuccessfulResolution( - this.latestLookupResult, - this.latestServiceConfig, - this.latestServiceConfigError - ) - } - }, err => { - this.latestServiceConfigError = { - code: Status.UNAVAILABLE, - details: 'TXT query failed', - metadata: new Metadata(), - }; - if (this.latestLookupResult !== null) { - this.listener.onSuccessfulResolution( - this.latestLookupResult, - this.latestServiceConfig, - this.latestServiceConfigError - ) - } - }); + ); } } } @@ -329,11 +338,15 @@ export interface dnsUrl { } export function parseTarget(target: string): dnsUrl | null { - const match = IPV4_REGEX.exec(target) ?? IPV6_REGEX.exec(target) ?? IPV6_BRACKET_REGEX.exec(target) ?? DNS_REGEX.exec(target) + const match = + IPV4_REGEX.exec(target) ?? + IPV6_REGEX.exec(target) ?? + IPV6_BRACKET_REGEX.exec(target) ?? + DNS_REGEX.exec(target); if (match) { return { host: match[1], - port: match[2] ?? undefined + port: match[2] ?? undefined, }; } else { return null; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index d6b55ae87..240d8b53f 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -157,7 +157,7 @@ export class ServerWritableStreamImpl this.trailingMetadata = new Metadata(); this.call.setupSurfaceCall(this); - this.on('error', err => { + this.on('error', (err) => { this.call.sendError(err); this.end(); }); @@ -226,7 +226,7 @@ export class ServerDuplexStreamImpl extends Duplex this.call.setupSurfaceCall(this); this.call.setupReadable(this); - this.on('error', err => { + this.on('error', (err) => { this.call.sendError(err); this.end(); }); @@ -562,7 +562,7 @@ export class Http2ServerCallStream< } setupSurfaceCall(call: ServerSurfaceCall) { - this.once('cancelled', reason => { + this.once('cancelled', (reason) => { call.cancelled = true; call.emit('cancelled', reason); }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index c37f69f71..1d851f1ce 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -48,7 +48,11 @@ import { ServerCredentials } from './server-credentials'; import { ChannelOptions } from './channel-options'; import { createResolver, ResolverListener } from './resolver'; import { log } from './logging'; -import { SubchannelAddress, TcpSubchannelAddress, isTcpSubchannelAddress } from './subchannel'; +import { + SubchannelAddress, + TcpSubchannelAddress, + isTcpSubchannelAddress, +} from './subchannel'; interface BindResult { port: number; @@ -152,7 +156,7 @@ export class Server { throw new Error('Cannot add an empty service to a server'); } - serviceKeys.forEach(name => { + serviceKeys.forEach((name) => { const attrs = service[name]; let methodType: HandlerType; @@ -244,62 +248,72 @@ export class Server { http2Server.setTimeout(0, noop); this._setupHandlers(http2Server); return http2Server; - } + }; - const bindSpecificPort = (addressList: SubchannelAddress[], portNum: number, previousCount: number): Promise => { + const bindSpecificPort = ( + addressList: SubchannelAddress[], + portNum: number, + previousCount: number + ): Promise => { if (addressList.length === 0) { - return Promise.resolve({port: portNum, count: previousCount}); + return Promise.resolve({ port: portNum, count: previousCount }); } - return Promise.all(addressList.map(address => { - let addr: SubchannelAddress; - if (isTcpSubchannelAddress(address)) { - addr = { - host: (address as TcpSubchannelAddress).host, - port: portNum - }; - } else { - addr = address - } - - const http2Server = setupServer(); - return new Promise((resolve, reject) => { - function onError(err: Error): void { - resolve(err); + return Promise.all( + addressList.map((address) => { + let addr: SubchannelAddress; + if (isTcpSubchannelAddress(address)) { + addr = { + host: (address as TcpSubchannelAddress).host, + port: portNum, + }; + } else { + addr = address; } - http2Server.once('error', onError); - - http2Server.listen(addr, () => { - this.http2ServerList.push(http2Server); - const boundAddress = http2Server.address()!; - if (typeof boundAddress === 'string') { - resolve(portNum); - } else { - resolve(boundAddress.port); + const http2Server = setupServer(); + return new Promise((resolve, reject) => { + function onError(err: Error): void { + resolve(err); } - http2Server.removeListener('error', onError); + + http2Server.once('error', onError); + + http2Server.listen(addr, () => { + this.http2ServerList.push(http2Server); + const boundAddress = http2Server.address()!; + if (typeof boundAddress === 'string') { + resolve(portNum); + } else { + resolve(boundAddress.port); + } + http2Server.removeListener('error', onError); + }); }); }) - })).then(results => { + ).then((results) => { let count = 0; for (const result of results) { if (typeof result === 'number') { count += 1; if (result !== portNum) { - throw new Error('Invalid state: multiple port numbers added from single address'); + throw new Error( + 'Invalid state: multiple port numbers added from single address' + ); } } } return { port: portNum, - count: count + previousCount + count: count + previousCount, }; }); - } + }; - const bindWildcardPort = (addressList: SubchannelAddress[]): Promise => { + const bindWildcardPort = ( + addressList: SubchannelAddress[] + ): Promise => { if (addressList.length === 0) { - return Promise.resolve({port: 0, count: 0}); + return Promise.resolve({ port: 0, count: 0 }); } const address = addressList[0]; const http2Server = setupServer(); @@ -312,16 +326,26 @@ export class Server { http2Server.listen(address, () => { this.http2ServerList.push(http2Server); - resolve(bindSpecificPort(addressList.slice(1), (http2Server.address() as AddressInfo).port, 1)); + resolve( + bindSpecificPort( + addressList.slice(1), + (http2Server.address() as AddressInfo).port, + 1 + ) + ); http2Server.removeListener('error', onError); }); }); - } + }; const resolverListener: ResolverListener = { - onSuccessfulResolution: (addressList, serviceConfig, serviceConfigError) => { + onSuccessfulResolution: ( + addressList, + serviceConfig, + serviceConfigError + ) => { // We only want one resolution result. Discard all future results - resolverListener.onSuccessfulResolution = () => {} + resolverListener.onSuccessfulResolution = () => {}; if (addressList.length === 0) { callback(new Error(`No addresses resolved for port ${port}`), 0); return; @@ -331,32 +355,42 @@ export class Server { if (addressList[0].port === 0) { bindResultPromise = bindWildcardPort(addressList); } else { - bindResultPromise = bindSpecificPort(addressList, addressList[0].port, 0); + bindResultPromise = bindSpecificPort( + addressList, + addressList[0].port, + 0 + ); } - } else{ + } else { // Use an arbitrary non-zero port for non-TCP addresses bindResultPromise = bindSpecificPort(addressList, 1, 0); } - bindResultPromise.then(bindResult => { - if (bindResult.count === 0) { + bindResultPromise.then( + (bindResult) => { + if (bindResult.count === 0) { + const errorString = `No address added out of total ${addressList.length} resolved`; + log(LogVerbosity.ERROR, errorString); + callback(new Error(errorString), 0); + } else { + if (bindResult.count < addressList.length) { + log( + LogVerbosity.INFO, + `WARNING Only ${bindResult.count} addresses added out of total ${addressList.length} resolved` + ); + } + callback(null, bindResult.port); + } + }, + (error) => { const errorString = `No address added out of total ${addressList.length} resolved`; log(LogVerbosity.ERROR, errorString); callback(new Error(errorString), 0); - } else { - if (bindResult.count < addressList.length) { - log(LogVerbosity.INFO, `WARNING Only ${bindResult.count} addresses added out of total ${addressList.length} resolved`); - } - callback(null, bindResult.port); } - }, (error) => { - const errorString = `No address added out of total ${addressList.length} resolved`; - log(LogVerbosity.ERROR, errorString); - callback(new Error(errorString), 0); - }); + ); }, onError: (error) => { callback(new Error(error.details), 0); - } + }, }; const resolver = createResolver(port, resolverListener); @@ -376,7 +410,7 @@ export class Server { // Always destroy any available sessions. It's possible that one or more // tryShutdown() calls are in progress. Don't wait on them to finish. - this.sessions.forEach(session => { + this.sessions.forEach((session) => { // Cast NGHTTP2_CANCEL to any because TypeScript doesn't seem to // recognize destroy(code) as a valid signature. session.destroy(http2.constants.NGHTTP2_CANCEL as any); @@ -405,7 +439,12 @@ export class Server { } start(): void { - if (this.http2ServerList.length === 0 || this.http2ServerList.every(http2Server => http2Server.listening !== true)) { + if ( + this.http2ServerList.length === 0 || + this.http2ServerList.every( + (http2Server) => http2Server.listening !== true + ) + ) { throw new Error('server must be bound in order to start'); } @@ -439,7 +478,7 @@ export class Server { // If any sessions are active, close them gracefully. pendingChecks += this.sessions.size; - this.sessions.forEach(session => { + this.sessions.forEach((session) => { session.close(maybeCallback); }); if (pendingChecks === 0) { @@ -451,7 +490,9 @@ export class Server { throw new Error('Not yet implemented'); } - private _setupHandlers(http2Server: http2.Http2Server | http2.Http2SecureServer): void { + private _setupHandlers( + http2Server: http2.Http2Server | http2.Http2SecureServer + ): void { if (http2Server === null) { return; } @@ -525,7 +566,7 @@ export class Server { } ); - http2Server.on('session', session => { + http2Server.on('session', (session) => { if (!this.started) { session.destroy(); return; diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 634d25756..9f1437299 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -67,7 +67,7 @@ export class SubchannelPool { const subchannelObjArray = this.pool[channelTarget]; const refedSubchannels = subchannelObjArray.filter( - value => !value.subchannel.unrefIfOneRef() + (value) => !value.subchannel.unrefIfOneRef() ); if (refedSubchannels.length > 0) { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 64799a496..c21e33056 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -210,7 +210,7 @@ export class Subchannel { `grpc-node-js/${clientVersion}`, options['grpc.secondary_user_agent'], ] - .filter(e => e) + .filter((e) => e) .join(' '); // remove falsey values first if ('grpc.keepalive_time_ms' in options) { @@ -311,8 +311,8 @@ export class Subchannel { return socket; } else { /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ return net.connect(this.subchannelAddress); } }; @@ -397,7 +397,7 @@ export class Subchannel { } } ); - session.once('error', error => { + session.once('error', (error) => { /* Do nothing here. Any error should also trigger a close event, which is * where we want to handle that. */ trace( @@ -410,11 +410,17 @@ export class Subchannel { private startConnectingInternal() { if (shouldUseProxy(this.channelTarget)) { - getProxiedConnection(this.channelTarget, this.subchannelAddress).then((socket) => { - this.createSession(socket); - }, (reason) => { - this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.TRANSIENT_FAILURE); - }); + getProxiedConnection(this.channelTarget, this.subchannelAddress).then( + (socket) => { + this.createSession(socket); + }, + (reason) => { + this.transitionToState( + [ConnectivityState.CONNECTING], + ConnectivityState.TRANSIENT_FAILURE + ); + } + ); } else { this.createSession(); } @@ -589,7 +595,7 @@ export class Subchannel { const http2Stream = this.session!.request(headers); let headersString = ''; for (const header of Object.keys(headers)) { - headersString += '\t\t' + header + ': ' + headers[header] + '\n' + headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } trace('Starting stream with headers\n' + headersString); callStream.attachHttp2Stream(http2Stream, this); From c4b92d91a1059ccb7294ab148e44b66d50035a9a Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 12:03:48 +0200 Subject: [PATCH 0991/1899] grpc-js: fix more linting issues --- packages/grpc-js/src/load-balancing-config.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 4a895903f..f2b9f3a79 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -21,7 +21,7 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ -export interface RoundRobinConfig {} +export type RoundRobinConfig = {}; export interface XdsConfig { balancerName: string; diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index a42a898f8..a40d5f980 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -332,6 +332,8 @@ export function setup(): void { registerDefaultResolver(DnsResolver); } +// camelCase needed for compatibility to grpc-native-js package +// eslint-disable-next-line @typescript-eslint/class-name-casing export interface dnsUrl { host: string; port?: string; From f4bacba9c77ef5341d1bb666e0f1b409a0e56d7d Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 12:09:00 +0200 Subject: [PATCH 0992/1899] grpc-js: remove unused imports --- packages/grpc-js/src/call-credentials-filter.ts | 1 - packages/grpc-js/src/call-credentials.ts | 1 - packages/grpc-js/src/channel.ts | 1 - packages/grpc-js/src/client-interceptors.ts | 7 +------ packages/grpc-js/src/client.ts | 9 ++------- packages/grpc-js/src/deadline-filter.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 1 - packages/grpc-js/src/resolver.ts | 1 - packages/grpc-js/src/server.ts | 3 +-- packages/grpc-js/src/subchannel.ts | 2 +- 10 files changed, 6 insertions(+), 22 deletions(-) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index f3fe2f4d4..d39af832b 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -15,7 +15,6 @@ * */ -import { CallCredentials } from './call-credentials'; import { Call } from './call-stream'; import { Channel } from './channel'; import { BaseFilter, Filter, FilterFactory } from './filter'; diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index e5d22bf79..40a26fecc 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -16,7 +16,6 @@ */ import { Metadata } from './metadata'; -import { Call } from '.'; export interface CallMetadataOptions { service_url: string; diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index a8b9f4ec8..abf149266 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -34,7 +34,6 @@ import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority } from './resolver'; -import { LoadBalancingConfig } from './load-balancing-config'; import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 72bbdab91..95ea5deb2 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -18,27 +18,22 @@ import { Metadata } from './metadata'; import { StatusObject, - CallStreamOptions, Listener, MetadataListener, MessageListener, StatusListener, FullListener, InterceptingListener, - WriteObject, - WriteCallback, InterceptingListenerImpl, isInterceptingListener, MessageContext, - Http2CallStream, - Deadline, Call, } from './call-stream'; import { Status } from './constants'; import { Channel } from './channel'; import { CallOptions } from './client'; import { CallCredentials } from './call-credentials'; -import { ClientMethodDefinition, Serialize } from './make-client'; +import { ClientMethodDefinition } from './make-client'; /** * Error class associated with passing both interceptors and interceptor diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index f33de1f72..511c1f4ef 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -29,18 +29,13 @@ import { SurfaceCall, } from './call'; import { CallCredentials } from './call-credentials'; -import { - Deadline, - StatusObject, - WriteObject, - InterceptingListener, -} from './call-stream'; +import { Deadline, StatusObject } from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; -import { ClientMethodDefinition, MethodDefinition } from './make-client'; +import { ClientMethodDefinition } from './make-client'; import { getInterceptingCall, Interceptor, diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 190d815ef..2306bb8f5 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -16,7 +16,7 @@ */ import { Call, StatusObject } from './call-stream'; -import { ConnectivityState, Channel } from './channel'; +import { Channel } from './channel'; import { Status } from './constants'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index a40d5f980..5fef45952 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -23,7 +23,6 @@ import { import * as dns from 'dns'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; -import { ServiceError } from './call'; import { Status } from './constants'; import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index b2be310f0..4c091752e 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -15,7 +15,6 @@ * */ -import { ServiceError } from './call'; import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 1d851f1ce..bcb50637e 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -16,8 +16,7 @@ */ import * as http2 from 'http2'; -import { AddressInfo, ListenOptions } from 'net'; -import { URL } from 'url'; +import { AddressInfo } from 'net'; import { ServiceError } from './call'; import { Status, LogVerbosity } from './constants'; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c21e33056..3f6cfd52c 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -20,7 +20,7 @@ import { ChannelCredentials } from './channel-credentials'; import { Metadata } from './metadata'; import { Http2CallStream } from './call-stream'; import { ChannelOptions } from './channel-options'; -import { PeerCertificate, checkServerIdentity, TLSSocket } from 'tls'; +import { PeerCertificate, checkServerIdentity } from 'tls'; import { ConnectivityState } from './channel'; import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; From 0d927e68723f50627ef9a045b3ce2f13a5796132 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 12:10:39 +0200 Subject: [PATCH 0993/1899] grpc-js: remove tslint disable statements --- packages/grpc-js/src/server.ts | 1 - packages/grpc-js/test/common.ts | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index bcb50637e..af0deefc9 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -111,7 +111,6 @@ function getDefaultHandler(handlerType: HandlerType, methodName: string) { throw new Error(`Invalid handlerType ${handlerType}`); } } -// tslint:enable:no-any export class Server { private http2ServerList: (http2.Http2Server | http2.Http2SecureServer)[] = []; diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index 4f8c5ff81..a3d8b9ba2 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -32,7 +32,6 @@ export function mockFunction(): never { throw new Error('Not implemented'); } -// tslint:disable-next-line:no-namespace export namespace assert2 { const toCall = new Map<() => void, number>(); const afterCallsQueue: Array<() => void> = []; @@ -95,7 +94,6 @@ export namespace assert2 { return result; }; } - // tslint:enable:no-any /** * Calls the given function when every function that was wrapped with From 4bb965d2d864e297941aa1e312b47750d48b586f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Apr 2020 10:45:57 -0700 Subject: [PATCH 0994/1899] Fix default max message length values --- packages/grpc-js/src/constants.ts | 6 +++++ .../grpc-js/src/max-message-size-filter.ts | 9 +++---- packages/grpc-js/src/server-call.ts | 9 +++---- test/api/interop_extra_test.js | 24 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index 5f1992e36..55d934038 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -40,3 +40,9 @@ export enum LogVerbosity { INFO, ERROR, } + +// -1 means unlimited +export const DEFAULT_MAX_SEND_MESSAGE_LENGTH = -1; + +// 4 MB default +export const DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH = 4 * 1024 * 1024; \ No newline at end of file diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts index ac304e8f8..4db942f7c 100644 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -17,15 +17,12 @@ import { BaseFilter, Filter, FilterFactory } from "./filter"; import { Call, WriteObject } from "./call-stream"; -import { Status } from "./constants"; +import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH } from "./constants"; import { ChannelOptions } from "./channel-options"; -// The default max message size for sending or receiving is 4 MB -const DEFAULT_MAX_MESSAGE_SIZE = 4 * 1024 * 1024; - export class MaxMessageSizeFilter extends BaseFilter implements Filter { - private maxSendMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; - private maxReceiveMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; + private maxSendMessageSize: number = DEFAULT_MAX_SEND_MESSAGE_LENGTH; + private maxReceiveMessageSize: number = DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH; constructor( private readonly options: ChannelOptions, private readonly callStream: Call diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index bbec9ac52..6bcb96873 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -20,7 +20,7 @@ import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; import { StatusObject } from './call-stream'; -import { Status } from './constants'; +import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH } from './constants'; import { Deserialize, Serialize } from './make-client'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; @@ -326,9 +326,6 @@ export type HandlerType = 'bidi' | 'clientStream' | 'serverStream' | 'unary'; const noopTimer: NodeJS.Timer = setTimeout(() => {}, 0); -// The default max message size for sending or receiving is 4 MB -const DEFAULT_MAX_MESSAGE_SIZE = 4 * 1024 * 1024; - // Internal class that wraps the HTTP2 request. export class Http2ServerCallStream< RequestType, @@ -342,8 +339,8 @@ export class Http2ServerCallStream< private isPushPending = false; private bufferedMessages: Array = []; private messagesToPush: Array = []; - private maxSendMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; - private maxReceiveMessageSize: number = DEFAULT_MAX_MESSAGE_SIZE; + private maxSendMessageSize: number = DEFAULT_MAX_SEND_MESSAGE_LENGTH; + private maxReceiveMessageSize: number = DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH; constructor( private stream: http2.ServerHttp2Stream, diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 81fa3d809..d55471ad6 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -57,8 +57,12 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio let client; let port; before(function(done) { - /* The default server has no limits on max message size to make those - * tests easier to write */ + /* To make testing max message size enforcement easier, the we explicitly + * remove the limit on the size of messages the server can receive, and + * we expect that the size of messages it can send is unlimited by + * default. On the other side, we explicitly limit the size of messages + * the client can send to 4 MB, and we expect that the size of messages + * it can receive is limited to 4 MB by default */ interopServer.getServer(0, true, (err, serverObj) => { if (err) { done(err); @@ -71,13 +75,13 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio const creds = grpc.credentials.createSsl(ca_data); const options = { 'grpc.ssl_target_name_override': 'foo.test.google.fr', - 'grpc.default_authority': 'foo.test.google.fr' + 'grpc.default_authority': 'foo.test.google.fr', + 'grpc.max_send_message_length': 4*1024*1024 }; client = new testProto.TestService(`localhost:${port}`, creds, options); done(); } }, { - 'grpc.max_send_message_length': -1, 'grpc.max_receive_message_length': -1 }); }); @@ -141,14 +145,12 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); describe.only('max message size', function() { - // Note: the main server has these checks disabled // A size that is larger than the default limit - const largeMessageSize = 32 * 1024 * 1024; + const largeMessageSize = 6 * 1024 * 1024; const largeMessage = Buffer.alloc(largeMessageSize); it('should get an error when sending a large message', function(done) { done = multiDone(done, 2); - const unaryMessage = {payload: {body: largeMessage}} - console.log(client.unaryCall.requestSerialize(unaryMessage).length); + const unaryMessage = {payload: {body: largeMessage}}; client.unaryCall(unaryMessage, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); @@ -228,7 +230,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); }); - describe('with a server with message size limits', function() { + describe('with a server with message size limits and a client without limits', function() { let restrictedServer; let restrictedServerClient; before(function(done) { @@ -244,13 +246,12 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio const options = { 'grpc.ssl_target_name_override': 'foo.test.google.fr', 'grpc.default_authority': 'foo.test.google.fr', - 'grpc.max_send_message_length': -1, 'grpc.max_receive_message_length': -1 }; restrictedServerClient = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); done(); } - }); + }, {'grpc.max_send_message_length': 4 * 1024 * 1024}); }); after(function() { restrictedServer.forceShutdown(); @@ -276,7 +277,6 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio it('should get an error when requesting a large message', function(done) { done = multiDone(done, 2); restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { - console.log(result.payload.body.length); assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); done(); From 226016c7dca96cc56ee5211160b54a5820e1808b Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Thu, 9 Apr 2020 21:44:09 +0200 Subject: [PATCH 0995/1899] grpc-js: make dnsUrl type PascalCase --- packages/grpc-js/src/resolver-dns.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 5fef45952..f359b507b 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -331,14 +331,12 @@ export function setup(): void { registerDefaultResolver(DnsResolver); } -// camelCase needed for compatibility to grpc-native-js package -// eslint-disable-next-line @typescript-eslint/class-name-casing -export interface dnsUrl { +export interface DnsUrl { host: string; port?: string; } -export function parseTarget(target: string): dnsUrl | null { +export function parseTarget(target: string): DnsUrl | null { const match = IPV4_REGEX.exec(target) ?? IPV6_REGEX.exec(target) ?? From f0d02f830dfd93676c2e7a1a99d7f301c91048db Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Apr 2020 16:08:18 -0700 Subject: [PATCH 0996/1899] Get the tests passing --- packages/grpc-js/src/server-call.ts | 23 +++++++++++++++-------- test/api/interop_extra_test.js | 29 +++++++++++++++-------------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 6bcb96873..284e18fca 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -447,7 +447,11 @@ export class Http2ServerCallStream< try { const requestBytes = Buffer.concat(chunks, totalLength); if (this.maxReceiveMessageSize !== -1 && requestBytes.length > this.maxReceiveMessageSize) { - this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Server received message of size ${requestBytes.length} > max size ${this.maxReceiveMessageSize}`); + this.sendError({ + code: Status.RESOURCE_EXHAUSTED, + details: `Server received message of size ${requestBytes.length} > max size ${this.maxReceiveMessageSize}` + }); + resolve(); } resolve(await this.deserializeMessage(requestBytes)); @@ -564,18 +568,17 @@ export class Http2ServerCallStream< this.sendStatus(status); } - cancelWithStatus(code: Status, details: string) { - this.cancelled = true; - this.sendStatus({code, details, metadata: new Metadata()}); - } - write(chunk: Buffer) { if (this.checkCancelled()) { return; } if (this.maxSendMessageSize !== -1 && chunk.length > this.maxSendMessageSize) { - this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Server failed to send message of size ${chunk.length} > max size ${this.maxSendMessageSize}`); + this.sendError({ + code: Status.RESOURCE_EXHAUSTED, + details: `Server failed to send message of size ${chunk.length} > max size ${this.maxSendMessageSize}` + }); + return; } this.sendMetadata(); @@ -605,7 +608,11 @@ export class Http2ServerCallStream< for (const message of messages) { if (this.maxReceiveMessageSize !== -1 && message.length > this.maxReceiveMessageSize) { - this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Server received message of size ${message.length} > max size ${this.maxReceiveMessageSize}`); + this.sendError({ + code: Status.RESOURCE_EXHAUSTED, + details: `Server received message of size ${message.length} > max size ${this.maxReceiveMessageSize}` + }); + return; } this.pushOrBufferMessage(readable, message); } diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index d55471ad6..c8c22feac 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -144,9 +144,9 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done(); }); }); - describe.only('max message size', function() { + describe('max message size', function() { // A size that is larger than the default limit - const largeMessageSize = 6 * 1024 * 1024; + const largeMessageSize = 8 * 1024 * 1024; const largeMessage = Buffer.alloc(largeMessageSize); it('should get an error when sending a large message', function(done) { done = multiDone(done, 2); @@ -257,27 +257,28 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio restrictedServer.forceShutdown(); }); it('should get an error when sending a large message', function(done) { - done = multiDone(done, 2); restrictedServerClient.unaryCall({payload: {body: largeMessage}}, (error, result) => { + console.log(error.message); assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - done(); - }); - const stream = restrictedServerClient.fullDuplexCall(); - stream.write({payload: {body: largeMessage}}); - stream.end(); - stream.on('data', () => {}); - stream.on('status', (status) => { - assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); - done(); - }); - stream.on('error', (error) => { + const stream = restrictedServerClient.fullDuplexCall(); + stream.write({payload: {body: largeMessage}}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + console.log(status.details); + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); }); }); it('should get an error when requesting a large message', function(done) { done = multiDone(done, 2); restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { assert(error); + console.log(error.message); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); done(); }); From 413dcd764bc37d8e039ab7d1e88bff189e862380 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Apr 2020 16:11:15 -0700 Subject: [PATCH 0997/1899] Remove debug logs --- test/api/interop_extra_test.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index c8c22feac..401ec6219 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -258,7 +258,6 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); it('should get an error when sending a large message', function(done) { restrictedServerClient.unaryCall({payload: {body: largeMessage}}, (error, result) => { - console.log(error.message); assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); const stream = restrictedServerClient.fullDuplexCall(); @@ -266,7 +265,6 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio stream.end(); stream.on('data', () => {}); stream.on('status', (status) => { - console.log(status.details); assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); done(); }); @@ -278,7 +276,6 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done = multiDone(done, 2); restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { assert(error); - console.log(error.message); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); done(); }); From 38ebfc8760995c9b1c88ea309b38b42a8946ad92 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Apr 2020 16:15:33 -0700 Subject: [PATCH 0998/1899] Make error messages match core --- packages/grpc-js/src/max-message-size-filter.ts | 4 ++-- packages/grpc-js/src/server-call.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts index 4db942f7c..f820c02e6 100644 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -44,7 +44,7 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } else { const concreteMessage = await message; if (concreteMessage.message.length > this.maxSendMessageSize) { - this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Failed to send message of size ${concreteMessage.message.length} > max size ${this.maxSendMessageSize}`); + this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})`); return Promise.reject('Message too large'); } else { return concreteMessage; @@ -60,7 +60,7 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } else { const concreteMessage = await message; if (concreteMessage.length > this.maxReceiveMessageSize) { - this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Received message of size ${concreteMessage.length} > max size ${this.maxReceiveMessageSize}`); + this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})`); return Promise.reject('Message too large'); } else { return concreteMessage; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 284e18fca..7559bae0d 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -449,7 +449,7 @@ export class Http2ServerCallStream< if (this.maxReceiveMessageSize !== -1 && requestBytes.length > this.maxReceiveMessageSize) { this.sendError({ code: Status.RESOURCE_EXHAUSTED, - details: `Server received message of size ${requestBytes.length} > max size ${this.maxReceiveMessageSize}` + details: `Received message larger than max (${requestBytes.length} vs. ${this.maxReceiveMessageSize})` }); resolve(); } @@ -576,7 +576,7 @@ export class Http2ServerCallStream< if (this.maxSendMessageSize !== -1 && chunk.length > this.maxSendMessageSize) { this.sendError({ code: Status.RESOURCE_EXHAUSTED, - details: `Server failed to send message of size ${chunk.length} > max size ${this.maxSendMessageSize}` + details: `Sent message larger than max (${chunk.length} vs. ${this.maxSendMessageSize})` }); return; } @@ -610,7 +610,7 @@ export class Http2ServerCallStream< if (this.maxReceiveMessageSize !== -1 && message.length > this.maxReceiveMessageSize) { this.sendError({ code: Status.RESOURCE_EXHAUSTED, - details: `Server received message of size ${message.length} > max size ${this.maxReceiveMessageSize}` + details: `Received message larger than max (${message.length} vs. ${this.maxReceiveMessageSize})` }); return; } From 3044a5a4d920e9987b589fcd6f5c514167d63823 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Apr 2020 16:26:21 -0700 Subject: [PATCH 0999/1899] Document newly supported channel args --- PACKAGE-COMPARISON.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 7c852ae47..46c28b02a 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -41,5 +41,7 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.initial_reconnect_backoff_ms` - `grpc.max_reconnect_backoff_ms` - `grpc.use_local_subchannel_pool` + - `grpc.max_send_message_length` + - `grpc.max_receive_message_length` - `channelOverride` - `channelFactoryOverride` From 53f3daa685dc2af6e64bdb00ebfdfed1233d7482 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Fri, 10 Apr 2020 11:03:53 +0200 Subject: [PATCH 1000/1899] Revert "grpc-js: allow any for linting globally" This reverts commit 16ec0f0f6414687a53e9f05d4621b88162a9f1d7 and replaces tslint-disable statements by eslint-disable. --- packages/grpc-js/.eslintrc | 1 - packages/grpc-js/src/call-stream.ts | 3 +++ packages/grpc-js/src/channel-credentials.ts | 1 + packages/grpc-js/src/channel.ts | 4 ++-- packages/grpc-js/src/client-interceptors.ts | 17 +++++++++++++++++ packages/grpc-js/src/client.ts | 7 ++++++- packages/grpc-js/src/index.ts | 10 +++++++--- packages/grpc-js/src/load-balancing-config.ts | 4 ++++ packages/grpc-js/src/logging.ts | 2 ++ packages/grpc-js/src/make-client.ts | 2 ++ packages/grpc-js/src/object-stream.ts | 2 ++ packages/grpc-js/src/server-call.ts | 3 +++ packages/grpc-js/src/server.ts | 2 ++ packages/grpc-js/src/service-config.ts | 4 ++++ packages/grpc-js/src/subchannel-pool.ts | 1 + packages/grpc-js/test/common.ts | 1 + .../grpc-js/test/test-channel-credentials.ts | 1 + packages/grpc-js/test/test-resolver.ts | 2 ++ .../grpc-js/test/test-server-credentials.ts | 1 + packages/grpc-js/test/test-server-deadlines.ts | 1 + packages/grpc-js/test/test-server-errors.ts | 1 + packages/grpc-js/test/test-server.ts | 5 +++-- 22 files changed, 66 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/.eslintrc b/packages/grpc-js/.eslintrc index 6b0cac4ab..7e3583cc1 100644 --- a/packages/grpc-js/.eslintrc +++ b/packages/grpc-js/.eslintrc @@ -2,7 +2,6 @@ "root": true, "extends": "./node_modules/gts", "rules": { - "@typescript-eslint/no-explicit-any": "off", "node/no-unpublished-import": ["error", { "tryExtensions": [".ts", ".js", ".json", ".node"] }] diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index f40366ca2..9ceebdbfb 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -69,6 +69,7 @@ export interface MetadataListener { } export interface MessageListener { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (message: any, next: (message: any) => void): void; } @@ -89,6 +90,7 @@ export type Listener = Partial; */ export interface InterceptingListener { onReceiveMetadata(metadata: Metadata): void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any): void; onReceiveStatus(status: StatusObject): void; } @@ -115,6 +117,7 @@ export class InterceptingListenerImpl implements InterceptingListener { this.nextListener.onReceiveMetadata(metadata); }); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any): void { /* If this listener processes messages asynchronously, the last message may * be reordered with respect to the status */ diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 7eb76a386..e5c9bfda7 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -20,6 +20,7 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; +// eslint-disable-next-line @typescript-eslint/no-explicit-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { if (obj && !(obj instanceof Buffer)) { throw new TypeError(`${friendlyName}, if provided, must be a Buffer.`); diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index abf149266..ca6254c4c 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -111,7 +111,7 @@ export interface Channel { method: string, deadline: Deadline, host: string | null | undefined, - parentCall: any, + parentCall: any, // eslint-disable-line @typescript-eslint/no-explicit-any propagateFlags: number | null | undefined ): Call; } @@ -460,7 +460,7 @@ export class ChannelImplementation implements Channel { method: string, deadline: Deadline, host: string | null | undefined, - parentCall: any, + parentCall: any, // eslint-disable-line @typescript-eslint/no-explicit-any propagateFlags: number | null | undefined ): Call { if (typeof method !== 'string') { diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 95ea5deb2..9b503c52d 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -59,6 +59,7 @@ export interface MetadataRequester { } export interface MessageRequester { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (message: any, next: (message: any) => void): void; } @@ -183,6 +184,7 @@ const defaultRequester: FullRequester = { }; export interface InterceptorOptions extends CallOptions { + // eslint-disable-next-line @typescript-eslint/no-explicit-any method_definition: ClientMethodDefinition; } @@ -190,7 +192,9 @@ export interface InterceptingCallInterface { cancelWithStatus(status: Status, details: string): void; getPeer(): string; start(metadata: Metadata, listener?: Partial): void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessageWithContext(context: MessageContext, message: any): void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessage(message: any): void; startRead(): void; halfClose(): void; @@ -274,6 +278,7 @@ export class InterceptingCall implements InterceptingCallInterface { this.nextCall.start(md, finalInterceptingListener); }); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessageWithContext(context: MessageContext, message: any): void { this.processingMessage = true; this.requester.sendMessage(message, (finalMessage) => { @@ -284,6 +289,7 @@ export class InterceptingCall implements InterceptingCallInterface { } }); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessage(message: any): void { this.sendMessageWithContext({}, message); } @@ -334,6 +340,7 @@ function getCall(channel: Channel, path: string, options: CallOptions): Call { class BaseInterceptingCall implements InterceptingCallInterface { constructor( protected call: Call, + // eslint-disable-next-line @typescript-eslint/no-explicit-any protected methodDefinition: ClientMethodDefinition ) {} cancelWithStatus(status: Status, details: string): void { @@ -345,6 +352,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { setCredentials(credentials: CallCredentials): void { this.call.setCredentials(credentials); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessageWithContext(context: MessageContext, message: any): void { let serialized: Buffer; try { @@ -354,6 +362,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { this.call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); } } + // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessage(message: any) { this.sendMessageWithContext({}, message); } @@ -367,6 +376,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { interceptingListener?.onReceiveMetadata?.(metadata); }, onReceiveMessage: (message) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any let deserialized: any; try { deserialized = this.methodDefinition.responseDeserialize(message); @@ -403,6 +413,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { */ class BaseUnaryInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface { + // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(call: Call, methodDefinition: ClientMethodDefinition) { super(call, methodDefinition); } @@ -411,6 +422,7 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall const wrapperListener: InterceptingListener = { onReceiveMetadata: listener?.onReceiveMetadata?.bind(listener) ?? ((metadata) => {}), + // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage: (message: any) => { receivedMessage = true; listener?.onReceiveMessage?.(message); @@ -433,9 +445,11 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall */ class BaseStreamingInterceptingCall extends BaseInterceptingCall implements InterceptingCallInterface {} + function getBottomInterceptingCall( channel: Channel, options: InterceptorOptions, + // eslint-disable-next-line @typescript-eslint/no-explicit-any methodDefinition: ClientMethodDefinition ) { const call = getCall(channel, methodDefinition.path, options); @@ -455,6 +469,7 @@ export interface Interceptor { } export interface InterceptorProvider { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (methodDefinition: ClientMethodDefinition): Interceptor; } @@ -464,8 +479,10 @@ export interface InterceptorArguments { callInterceptors: Interceptor[]; callInterceptorProviders: InterceptorProvider[]; } + export function getInterceptingCall( interceptorArgs: InterceptorArguments, + // eslint-disable-next-line @typescript-eslint/no-explicit-any methodDefinition: ClientMethodDefinition, options: CallOptions, channel: Channel diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 511c1f4ef..239304748 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -59,6 +59,7 @@ export interface UnaryCallback { (err: ServiceError | null, value?: ResponseType): void; } +/* eslint-disable @typescript-eslint/no-explicit-any */ export interface CallOptions { deadline?: Deadline; host?: string; @@ -72,6 +73,7 @@ export interface CallOptions { interceptors?: Interceptor[]; interceptor_providers?: InterceptorProvider[]; } +/* eslint-enable @typescript-eslint/no-explicit-any */ export interface CallProperties { argument?: RequestType; @@ -84,7 +86,7 @@ export interface CallProperties { } export interface CallInvocationTransformer { - (callProperties: CallProperties): CallProperties; + (callProperties: CallProperties): CallProperties; // eslint-disable-line @typescript-eslint/no-explicit-any } export type ClientOptions = Partial & { @@ -314,6 +316,7 @@ export class Client { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -430,6 +433,7 @@ export class Client { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any) { if (responseMessage != null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); @@ -552,6 +556,7 @@ export class Client { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any) { if (stream.push(message)) { call.startRead(); diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 8324ff4ca..d8f4b1cf4 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -67,15 +67,15 @@ if (!semver.satisfies(process.version, supportedNodeVersions)) { } interface IndexedObject { - [key: string]: any; - [key: number]: any; + [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any + [key: number]: any; // eslint-disable-line @typescript-eslint/no-explicit-any } function mixin(...sources: IndexedObject[]) { const result: { [key: string]: Function } = {}; for (const source of sources) { for (const propName of Object.getOwnPropertyNames(source)) { - const property: any = source[propName]; + const property: any = source[propName]; // eslint-disable-line @typescript-eslint/no-explicit-any if (typeof property === 'function') { result[propName] = property; } @@ -250,14 +250,18 @@ export { export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall }; +/* eslint-disable @typescript-eslint/no-explicit-any */ export type Call = | ClientUnaryCall | ClientReadableStream | ClientWritableStream | ClientDuplexStream; +/* eslint-enable @typescript-eslint/no-explicit-any */ /**** Unimplemented function stubs ****/ +/* eslint-disable @typescript-eslint/no-explicit-any */ + export const loadObject = (value: any, options: any) => { throw new Error( 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead' diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index f2b9f3a79..eef025e60 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -21,6 +21,10 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ +/* The any type is purposely used here. All functions validate their input at + * runtime */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + export type RoundRobinConfig = {}; export interface XdsConfig { diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index c7a63a476..91b4e8f04 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -47,6 +47,8 @@ export const setLogger = (logger: Partial): void => { export const setLoggerVerbosity = (verbosity: LogVerbosity): void => { _logVerbosity = verbosity; }; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any export const log = (severity: LogVerbosity, ...args: any[]): void => { if (severity >= _logVerbosity && typeof _logger.error === 'function') { _logger.error(...args); diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 99daef158..f7e2dacc2 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -50,6 +50,7 @@ export interface MethodDefinition ServerMethodDefinition {} export interface ServiceDefinition { + // eslint-disable-next-line @typescript-eslint/no-explicit-any [index: string]: MethodDefinition; } @@ -164,6 +165,7 @@ function partial( serialize: Function, deserialize: Function ): Function { + // eslint-disable-next-line @typescript-eslint/no-explicit-any return function (this: any, ...args: any[]) { return fn.call(this, path, serialize, deserialize, ...args); }; diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index 8d29b7860..b17058a7a 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -18,6 +18,8 @@ import { Duplex, Readable, Writable } from 'stream'; import { EmitterAugmentation1 } from './events'; +/* eslint-disable @typescript-eslint/no-explicit-any */ + export type WriteCallback = (error: Error | null | undefined) => void; export interface IntermediateObjectReadable extends Readable { diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 240d8b53f..abc37645d 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -174,6 +174,7 @@ export class ServerWritableStreamImpl async _write( chunk: ResponseType, encoding: string, + // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (...args: any[]) => void ) { try { @@ -200,6 +201,7 @@ export class ServerWritableStreamImpl callback(null); } + // eslint-disable-next-line @typescript-eslint/no-explicit-any end(metadata?: any) { if (metadata) { this.trailingMetadata = metadata; @@ -669,6 +671,7 @@ export class Http2ServerCallStream< } } +/* eslint-disable @typescript-eslint/no-explicit-any */ type UntypedServerCall = Http2ServerCallStream; function handleExpiredDeadline(call: UntypedServerCall) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index af0deefc9..5a8bfb554 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -70,6 +70,7 @@ function getUnimplementedStatusResponse( }; } +/* eslint-disable @typescript-eslint/no-explicit-any */ type UntypedUnaryHandler = UnaryHandler; type UntypedClientStreamingHandler = ClientStreamingHandler; type UntypedServerStreamingHandler = ServerStreamingHandler; @@ -411,6 +412,7 @@ export class Server { this.sessions.forEach((session) => { // Cast NGHTTP2_CANCEL to any because TypeScript doesn't seem to // recognize destroy(code) as a valid signature. + // eslint-disable-next-line @typescript-eslint/no-explicit-any session.destroy(http2.constants.NGHTTP2_CANCEL as any); }); this.sessions.clear(); diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index b1b0fdd41..ea5c449a7 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -22,6 +22,10 @@ * specific object type if the input has the right structure, and throws an * error otherwise. */ +/* The any type is purposely used here. All functions validate their input at + * runtime */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import * as lbconfig from './load-balancing-config'; import * as os from 'os'; diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 9f1437299..0d42163d1 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -63,6 +63,7 @@ export class SubchannelPool { /* These objects are created with Object.create(null), so they do not * have a prototype, which means that for (... in ...) loops over them * do not need to be filtered */ + // eslint-disable-disable-next-line:forin for (const channelTarget in this.pool) { const subchannelObjArray = this.pool[channelTarget]; diff --git a/packages/grpc-js/test/common.ts b/packages/grpc-js/test/common.ts index a3d8b9ba2..24cb71650 100644 --- a/packages/grpc-js/test/common.ts +++ b/packages/grpc-js/test/common.ts @@ -72,6 +72,7 @@ export namespace assert2 { * Wraps a function to keep track of whether it was called or not. * @param fn The function to wrap. */ + // tslint:disable:no-any export function mustCall( fn: (...args: any[]) => T ): (...args: any[]) => T { diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index 99966941a..d6028f469 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -49,6 +49,7 @@ class CallCredentialsMock implements CallCredentials { } } +// tslint:disable-next-line:no-any const readFile: (...args: any[]) => Promise = promisify(fs.readFile); // A promise which resolves to loaded files in the form { ca, key, cert } const pFixtures = Promise.all( diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 57997c17e..7f4900aa2 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -15,6 +15,8 @@ * */ +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any import * as assert from 'assert'; import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; diff --git a/packages/grpc-js/test/test-server-credentials.ts b/packages/grpc-js/test/test-server-credentials.ts index 9cc08b10e..ec1740f70 100644 --- a/packages/grpc-js/test/test-server-credentials.ts +++ b/packages/grpc-js/test/test-server-credentials.ts @@ -16,6 +16,7 @@ */ // Allow `any` data type for testing runtime type checking. +// tslint:disable no-any import * as assert from 'assert'; import { readFileSync } from 'fs'; import { join } from 'path'; diff --git a/packages/grpc-js/test/test-server-deadlines.ts b/packages/grpc-js/test/test-server-deadlines.ts index 107994ba9..c1152309d 100644 --- a/packages/grpc-js/test/test-server-deadlines.ts +++ b/packages/grpc-js/test/test-server-deadlines.ts @@ -16,6 +16,7 @@ */ // Allow `any` data type for testing runtime type checking. +// tslint:disable no-any import * as assert from 'assert'; import * as path from 'path'; diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 8e9f45209..7c611b9bc 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -16,6 +16,7 @@ */ // Allow `any` data type for testing runtime type checking. +// tslint:disable no-any import * as assert from 'assert'; import { join } from 'path'; diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index c8d2e64ad..434efbbc4 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -16,6 +16,7 @@ */ // Allow `any` data type for testing runtime type checking. +// tslint:disable no-any import * as assert from 'assert'; import * as fs from 'fs'; import * as http2 from 'http2'; @@ -38,13 +39,13 @@ describe('Server', () => { describe('constructor', () => { it('should work with no arguments', () => { assert.doesNotThrow(() => { - new Server(); + new Server(); // tslint:disable-line:no-unused-expression }); }); it('should work with an empty object argument', () => { assert.doesNotThrow(() => { - new Server({}); + new Server({}); // tslint:disable-line:no-unused-expression }); }); From 490217c0592f0e494bde4253e3fdeb065f5c0dda Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Fri, 10 Apr 2020 11:09:42 +0200 Subject: [PATCH 1001/1899] grpc-js: resolve eslint no-prototype-builtins --- packages/grpc-js/src/make-client.ts | 2 +- packages/grpc-js/src/server-call.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index f7e2dacc2..d23eeae05 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -194,7 +194,7 @@ export function loadPackageDefinition( ): GrpcObject { const result: GrpcObject = {}; for (const serviceFqn in packageDef) { - if (packageDef.hasOwnProperty(serviceFqn)) { + if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) { const service = packageDef[serviceFqn]; const nameComponents = serviceFqn.split('.'); const serviceName = nameComponents[nameComponents.length - 1]; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index abc37645d..f06f07833 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -479,7 +479,7 @@ export class Http2ServerCallStream< } if (err) { - if (!err.hasOwnProperty('metadata')) { + if (!Object.prototype.hasOwnProperty.call(err, 'metadata')) { err.metadata = metadata; } this.sendError(err); From e9172f043aecb48d226ec11c67efce79d8d0a74e Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Fri, 10 Apr 2020 11:12:00 +0200 Subject: [PATCH 1002/1899] grpc-js: resolve eslint error eqeqeq --- packages/grpc-js/src/client.ts | 4 ++-- packages/grpc-js/src/metadata.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 239304748..8ebb2537f 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -318,7 +318,7 @@ export class Client { }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any) { - if (responseMessage != null) { + if (responseMessage !== null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); } responseMessage = message; @@ -435,7 +435,7 @@ export class Client { }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any) { - if (responseMessage != null) { + if (responseMessage !== null) { call.cancelWithStatus(Status.INTERNAL, 'Too many responses received'); } responseMessage = message; diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 0ffe0af21..2da9d5311 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -48,7 +48,7 @@ function validate(key: string, value?: MetadataValue): void { if (!isLegalKey(key)) { throw new Error('Metadata key "' + key + '" contains illegal characters'); } - if (value != null) { + if (value !== null && value !== undefined) { if (isBinaryKey(key)) { if (!(value instanceof Buffer)) { throw new Error("keys that end with '-bin' must have Buffer values"); From ac14e1ac544f19bb96bb7ef3b50a8174a7b6b1c6 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Fri, 10 Apr 2020 11:15:10 +0200 Subject: [PATCH 1003/1899] grpc-js: Resolve eslint node/no-deprecated-api Remove unused imports --- packages/grpc-js/src/http_proxy.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index ef52dedac..eb34a1206 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -15,18 +15,14 @@ * */ -import { URL, parse } from 'url'; +import { URL } from 'url'; import { log } from './logging'; import { LogVerbosity } from './constants'; import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; import * as logging from './logging'; -import { - SubchannelAddress, - TcpSubchannelAddress, - isTcpSubchannelAddress, -} from './subchannel'; +import { SubchannelAddress, isTcpSubchannelAddress } from './subchannel'; const TRACER_NAME = 'proxy'; From 19d960074b1223f918de4f63d1a9e3dc140c5a80 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Apr 2020 10:09:54 -0700 Subject: [PATCH 1004/1899] grpc-js: Add more information to proxy errors --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/http_proxy.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 12f060521..9e888eb54 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.7.8", + "version": "0.7.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index ab1083fc5..00891bad8 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -149,13 +149,13 @@ export function getProxiedConnection(target: string, subchannelAddress: Subchann trace('Successfully connected to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); resolve(socket); } else { - log(LogVerbosity.ERROR, 'Failed to connect to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address); + log(LogVerbosity.ERROR, 'Failed to connect to ' + subchannelAddress + ' through proxy ' + PROXY_INFO.address + ' with status ' + res.statusCode); reject(); } }); request.once('error', (err) => { request.removeAllListeners(); - log(LogVerbosity.ERROR, 'Failed to connect to proxy ' + PROXY_INFO.address); + log(LogVerbosity.ERROR, 'Failed to connect to proxy ' + PROXY_INFO.address + ' with error ' + err.message); reject(); }); }); From f1c1dafae4318096ddd7fc9cc8c097d753dddc32 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Apr 2020 10:15:29 -0700 Subject: [PATCH 1005/1899] grpc-js: Don't include the port in :authority --- packages/grpc-js/src/resolver-dns.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 82727a42d..4da295e13 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -298,16 +298,10 @@ class DnsResolver implements Resolver { IPV6_REGEX.exec(target) || IPV6_BRACKET_REGEX.exec(target); if (ipMatch) { - if (ipMatch[2]) { - return ipMatch[1] + ':' + ipMatch[2]; - } return ipMatch[1]; } const dnsMatch = DNS_REGEX.exec(target); if (dnsMatch) { - if (dnsMatch[2]) { - return dnsMatch[1] + ':' + dnsMatch[2]; - } return dnsMatch[1]; } throw new Error(`Failed to parse target ${target}`); From a4d3f290ebe0baf4a9a9fbd4e0f36607e30d1b9c Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Sat, 11 Apr 2020 16:11:13 +0200 Subject: [PATCH 1006/1899] grpc-js: linter disable no-unused-vars Make prettier happy and move eslint-disable comment --- packages/grpc-js/.eslintrc | 3 ++- packages/grpc-js/src/make-client.ts | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/.eslintrc b/packages/grpc-js/.eslintrc index 7e3583cc1..b18ad0ed2 100644 --- a/packages/grpc-js/.eslintrc +++ b/packages/grpc-js/.eslintrc @@ -4,6 +4,7 @@ "rules": { "node/no-unpublished-import": ["error", { "tryExtensions": [".ts", ".js", ".json", ".node"] - }] + }], + "@typescript-eslint/no-unused-vars": "off" } } diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index b6725a71f..02ef91af2 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -50,12 +50,13 @@ export interface MethodDefinition extends ClientMethodDefinition, ServerMethodDefinition {} +/* eslint-disable @typescript-eslint/no-explicit-any */ export type ServiceDefinition< ImplementationType = UntypedServiceImplementation > = { - // eslint-disable-next-line @typescript-eslint/no-explicit-any readonly [index in keyof ImplementationType]: MethodDefinition; }; +/* eslint-enable @typescript-eslint/no-explicit-any */ export interface ProtobufTypeDefinition { format: string; From ab09c552dea46740f73fc6a4dd7adf1fb2f34e10 Mon Sep 17 00:00:00 2001 From: Aleksei Androsov Date: Sun, 12 Apr 2020 12:38:11 +0300 Subject: [PATCH 1007/1899] Export health-check messages To use in serviceMap const grpcHealthCheck = require('grpc-health-check'); const statusMap = { '': grpcHealthCheck.messages.HealthCheckResponse.ServingStatus.SERVING, }; --- packages/grpc-health-check/health.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-health-check/health.js b/packages/grpc-health-check/health.js index f55fba196..cfa9c8348 100644 --- a/packages/grpc-health-check/health.js +++ b/packages/grpc-health-check/health.js @@ -49,6 +49,7 @@ HealthImplementation.prototype.check = function(call, callback){ module.exports = { Client: health_service.HealthClient, + messages: health_messages, service: health_service.HealthService, Implementation: HealthImplementation }; From 70a92d2fc3cff9715399d00158f047588ab78218 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Sun, 12 Apr 2020 17:20:28 +0200 Subject: [PATCH 1008/1899] grpc-js: resolve node/no-unpublished-require --- packages/grpc-js/src/index.ts | 3 ++- packages/grpc-js/src/subchannel.ts | 2 +- packages/grpc-js/tsconfig.json | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 661e0efd3..e4bb3658e 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -62,7 +62,8 @@ import { ServerDuplexStream, } from './server-call'; -const supportedNodeVersions = require('../../package.json').engines.node; +import { engines as supportedEngines } from '../package.json'; +const supportedNodeVersions = supportedEngines.node; if (!semver.satisfies(process.version, supportedNodeVersions)) { throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3f6cfd52c..3f71720e6 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -29,7 +29,7 @@ import { LogVerbosity } from './constants'; import { shouldUseProxy, getProxiedConnection } from './http_proxy'; import * as net from 'net'; -const { version: clientVersion } = require('../../package.json'); +import { version as clientVersion } from '../package.json'; const TRACER_NAME = 'subchannel'; diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index f60cbdc02..ba675db78 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "build", "target": "es2017", "module": "commonjs", + "resolveJsonModule": true, "incremental": true }, "include": [ From e7b25e307074ec39e80620e21a2b859987908ef0 Mon Sep 17 00:00:00 2001 From: Patrick Remy Date: Sun, 12 Apr 2020 18:04:45 +0200 Subject: [PATCH 1009/1899] gprc-js: upgrade to gts v2.0.0 Remove deprecated google-ts-style --- packages/grpc-js/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 80de1316c..4bd15ef5c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -26,8 +26,7 @@ "@types/semver": "^6.0.1", "clang-format": "^1.0.55", "execa": "^2.0.3", - "google-ts-style": "^0.2.0", - "gts": "^2.0.0-alpha.9", + "gts": "^2.0.0", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", From cba41bc487f1171a0629799ab0f227a5bdcdf59d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Apr 2020 10:37:23 -0700 Subject: [PATCH 1010/1899] grpc-js: Interact with proxies properly --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 17 ++-- packages/grpc-js/src/http_proxy.ts | 124 ++++++++++++++++++----------- packages/grpc-js/src/subchannel.ts | 43 +++++----- 4 files changed, 110 insertions(+), 76 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 684e0c6a9..06aa83855 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.8.0", + "version": "0.8.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index cae7cc811..96397b70d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -38,6 +38,7 @@ import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; +import { mapProxyName } from './http_proxy'; export enum ConnectivityState { CONNECTING, @@ -163,6 +164,14 @@ export class ChannelImplementation implements Channel { ); } } + if (this.options['grpc.default_authority']) { + this.defaultAuthority = this.options['grpc.default_authority'] as string; + } else { + this.defaultAuthority = getDefaultAuthority(target); + } + const proxyMapResult = mapProxyName(target, options); + this.target = proxyMapResult.target; + this.options = Object.assign({}, this.options, proxyMapResult.extraOptions); /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ this.subchannelPool = getSubchannelPool( @@ -207,7 +216,7 @@ export class ChannelImplementation implements Channel { ); } this.resolvingLoadBalancer = new ResolvingLoadBalancer( - target, + this.target, channelControlHelper, defaultServiceConfig ); @@ -217,12 +226,6 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); - // TODO(murgatroid99): Add more centralized handling of channel options - if (this.options['grpc.default_authority']) { - this.defaultAuthority = this.options['grpc.default_authority'] as string; - } else { - this.defaultAuthority = getDefaultAuthority(target); - } } /** diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index c40152de8..e24fba2e8 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -22,7 +22,12 @@ import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; import * as logging from './logging'; -import { SubchannelAddress, isTcpSubchannelAddress } from './subchannel'; +import { + SubchannelAddress, + isTcpSubchannelAddress, + subchannelAddressToString, +} from './subchannel'; +import { ChannelOptions } from './channel-options'; const TRACER_NAME = 'proxy'; @@ -89,8 +94,6 @@ function getProxyInfo(): ProxyInfo { return result; } -const PROXY_INFO = getProxyInfo(); - function getNoProxyHostList(): string[] { /* Prefer using 'no_grpc_proxy'. Fallback on 'no_proxy' if it is not set. */ let noProxyStr: string | undefined = process.env.no_grpc_proxy; @@ -107,62 +110,87 @@ function getNoProxyHostList(): string[] { } } -const NO_PROXY_HOSTS = getNoProxyHostList(); +export interface ProxyMapResult { + target: string; + extraOptions: ChannelOptions; +} -export function shouldUseProxy(target: string): boolean { - if (!PROXY_INFO.address) { - return false; +export function mapProxyName( + target: string, + options: ChannelOptions +): ProxyMapResult { + const noProxyResult: ProxyMapResult = { + target: target, + extraOptions: {}, + }; + const proxyInfo = getProxyInfo(); + if (!proxyInfo.address) { + return noProxyResult; } - let serverHost: string; const parsedTarget = parseTarget(target); - if (parsedTarget) { - serverHost = parsedTarget.host; - } else { - return false; + if (!parsedTarget) { + return noProxyResult; } - for (const host of NO_PROXY_HOSTS) { + const serverHost = parsedTarget.host; + for (const host of getNoProxyHostList()) { if (host === serverHost) { trace('Not using proxy for target in no_proxy list: ' + target); - return false; + return noProxyResult; } } - return true; + const extraOptions: ChannelOptions = { + 'grpc.http_connect_target': target, + }; + if (proxyInfo.creds) { + extraOptions['grpc.http_connect_creds'] = proxyInfo.creds; + } + return { + target: `dns:///${proxyInfo.address}`, + extraOptions: extraOptions, + }; +} + +export interface ProxyConnectionResult { + socket?: Socket; + realTarget?: string; } export function getProxiedConnection( - target: string, - subchannelAddress: SubchannelAddress -): Promise { - if ( - !( - PROXY_INFO.address && - shouldUseProxy(target) && - isTcpSubchannelAddress(subchannelAddress) - ) - ) { - return Promise.reject(); + address: SubchannelAddress, + channelOptions: ChannelOptions +): Promise { + if (!('grpc.http_connect_target' in channelOptions)) { + return Promise.resolve({}); } - const subchannelAddressPathString = `${subchannelAddress.host}:${subchannelAddress.port}`; - trace( - 'Using proxy ' + - PROXY_INFO.address + - ' to connect to ' + - target + - ' at ' + - subchannelAddress - ); + const realTarget = channelOptions['grpc.http_connect_target'] as string; + const parsedTarget = parseTarget(realTarget)!; const options: http.RequestOptions = { method: 'CONNECT', - host: PROXY_INFO.address, - path: subchannelAddressPathString, }; - if (PROXY_INFO.creds) { + // Connect to the subchannel address as a proxy + if (isTcpSubchannelAddress(address)) { + options.host = address.host; + options.port = address.port; + } else { + options.socketPath = address.path; + } + if (parsedTarget.port === undefined) { + options.path = parsedTarget.host; + } else { + options.path = `${parsedTarget.host}:${parsedTarget.port}`; + } + if ('grpc.http_connect_creds' in channelOptions) { options.headers = { 'Proxy-Authorization': - 'Basic ' + Buffer.from(PROXY_INFO.creds).toString('base64'), + 'Basic ' + + Buffer.from( + channelOptions['grpc.http_connect_creds'] as string + ).toString('base64'), }; } - return new Promise((resolve, reject) => { + const proxyAddressString = subchannelAddressToString(address); + trace('Using proxy ' + proxyAddressString + ' to connect to ' + options.path); + return new Promise((resolve, reject) => { const request = http.request(options); request.once('connect', (res, socket, head) => { request.removeAllListeners(); @@ -170,18 +198,21 @@ export function getProxiedConnection( if (res.statusCode === 200) { trace( 'Successfully connected to ' + - subchannelAddress + + options.path + ' through proxy ' + - PROXY_INFO.address + proxyAddressString ); - resolve(socket); + resolve({ + socket, + realTarget, + }); } else { log( LogVerbosity.ERROR, 'Failed to connect to ' + - subchannelAddress + + options.path + ' through proxy ' + - PROXY_INFO.address + + proxyAddressString + ' with status ' + res.statusCode ); @@ -193,11 +224,12 @@ export function getProxiedConnection( log( LogVerbosity.ERROR, 'Failed to connect to proxy ' + - PROXY_INFO.address + + proxyAddressString + ' with error ' + err.message ); reject(); }); + request.end(); }); } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3f71720e6..12747696e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -26,7 +26,7 @@ import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { shouldUseProxy, getProxiedConnection } from './http_proxy'; +import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; import { version as clientVersion } from '../package.json'; @@ -278,7 +278,7 @@ export class Subchannel { clearTimeout(this.keepaliveTimeoutId); } - private createSession(socket?: net.Socket) { + private createSession(proxyConnectionResult: ProxyConnectionResult) { let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; let addressScheme = 'http://'; @@ -299,16 +299,16 @@ export class Subchannel { }; connectionOptions.servername = sslTargetNameOverride; } - if (socket) { - connectionOptions.socket = socket; + if (proxyConnectionResult.socket) { + connectionOptions.socket = proxyConnectionResult.socket; } } else { /* In all but the most recent versions of Node, http2.connect does not use * the options when establishing plaintext connections, so we need to * establish that connection explicitly. */ connectionOptions.createConnection = (authority, option) => { - if (socket) { - return socket; + if (proxyConnectionResult.socket) { + return proxyConnectionResult.socket; } else { /* net.NetConnectOpts is declared in a way that is more restrictive * than what net.connect will actually accept, so we use the type @@ -339,7 +339,10 @@ export class Subchannel { * determines whether the connection will be established over TLS or not. */ const session = http2.connect( - addressScheme + getDefaultAuthority(this.channelTarget), + addressScheme + + getDefaultAuthority( + proxyConnectionResult.realTarget ?? this.channelTarget + ), connectionOptions ); this.session = session; @@ -409,21 +412,17 @@ export class Subchannel { } private startConnectingInternal() { - if (shouldUseProxy(this.channelTarget)) { - getProxiedConnection(this.channelTarget, this.subchannelAddress).then( - (socket) => { - this.createSession(socket); - }, - (reason) => { - this.transitionToState( - [ConnectivityState.CONNECTING], - ConnectivityState.TRANSIENT_FAILURE - ); - } - ); - } else { - this.createSession(); - } + getProxiedConnection(this.subchannelAddress, this.options).then( + (result) => { + this.createSession(result); + }, + (reason) => { + this.transitionToState( + [ConnectivityState.CONNECTING], + ConnectivityState.TRANSIENT_FAILURE + ); + } + ); } /** From e73c96298f593db190fd185470ec7f9ef5c68bc6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Apr 2020 11:32:07 -0700 Subject: [PATCH 1011/1899] Add error on DNS parsing failure, fix proxy DNS name --- packages/grpc-js/src/http_proxy.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index e24fba2e8..2b3fb5d5a 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -145,7 +145,7 @@ export function mapProxyName( extraOptions['grpc.http_connect_creds'] = proxyInfo.creds; } return { - target: `dns:///${proxyInfo.address}`, + target: `dns:${proxyInfo.address}`, extraOptions: extraOptions, }; } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 1f72f80b9..24aa0236e 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -171,7 +171,15 @@ class DnsResolver implements Resolver { }); return; } - if (this.dnsHostname !== null) { + if (this.dnsHostname === null) { + setImmediate(() => { + this.listener.onError({ + code: Status.UNAVAILABLE, + details: `Failed to parse DNS address ${this.target}`, + metadata: new Metadata(), + }); + }); + } else { /* We clear out latestLookupResult here to ensure that it contains the * latest result since the last time we started resolving. That way, the * TXT resolution handler can use it, but only if it finishes second. We From b489935b7cb4273644518004abb950f4a4028862 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Apr 2020 13:58:12 -0700 Subject: [PATCH 1012/1899] grpc-js: Fix how package.json is loaded --- packages/grpc-js/.eslintrc | 3 ++- packages/grpc-js/src/index.ts | 3 +-- packages/grpc-js/src/subchannel.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/.eslintrc b/packages/grpc-js/.eslintrc index b18ad0ed2..64585682c 100644 --- a/packages/grpc-js/.eslintrc +++ b/packages/grpc-js/.eslintrc @@ -5,6 +5,7 @@ "node/no-unpublished-import": ["error", { "tryExtensions": [".ts", ".js", ".json", ".node"] }], - "@typescript-eslint/no-unused-vars": "off" + "@typescript-eslint/no-unused-vars": "off", + "node/no-unpublished-require": "off" } } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e4bb3658e..661e0efd3 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -62,8 +62,7 @@ import { ServerDuplexStream, } from './server-call'; -import { engines as supportedEngines } from '../package.json'; -const supportedNodeVersions = supportedEngines.node; +const supportedNodeVersions = require('../../package.json').engines.node; if (!semver.satisfies(process.version, supportedNodeVersions)) { throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3f71720e6..de69c4869 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -29,7 +29,7 @@ import { LogVerbosity } from './constants'; import { shouldUseProxy, getProxiedConnection } from './http_proxy'; import * as net from 'net'; -import { version as clientVersion } from '../package.json'; +const clientVersion = require('../../package.json').version; const TRACER_NAME = 'subchannel'; From 13cc016e4e59777d398e6735fcbaef398eab5ee8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 15 Apr 2020 18:04:49 -0700 Subject: [PATCH 1013/1899] grpc-js: Use a more structured representation of URIs internally --- packages/grpc-js/src/channel.ts | 20 ++- packages/grpc-js/src/http_proxy.ts | 59 ++++----- packages/grpc-js/src/resolver-dns.ts | 121 ++++-------------- packages/grpc-js/src/resolver-uds.ts | 27 ++-- packages/grpc-js/src/resolver.ts | 49 ++++--- .../grpc-js/src/resolving-load-balancer.ts | 3 +- packages/grpc-js/src/server.ts | 8 +- packages/grpc-js/src/subchannel-pool.ts | 7 +- packages/grpc-js/src/subchannel.ts | 3 +- packages/grpc-js/src/uri-parser.ts | 114 +++++++++++++++++ packages/grpc-js/test/test-resolver.ts | 35 ++--- packages/grpc-js/test/test-uri-parser.ts | 59 +++++++++ 12 files changed, 317 insertions(+), 188 deletions(-) create mode 100644 packages/grpc-js/src/uri-parser.ts create mode 100644 packages/grpc-js/test/test-uri-parser.ts diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 96397b70d..a9a82ac03 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -39,6 +39,7 @@ import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; +import { GrpcUri, parseUri, uriToString } from './uri-parser'; export enum ConnectivityState { CONNECTING, @@ -136,8 +137,9 @@ export class ChannelImplementation implements Channel { private connectivityStateWatchers: ConnectivityStateWatcher[] = []; private defaultAuthority: string; private filterStackFactory: FilterStackFactory; + private target: GrpcUri; constructor( - private target: string, + target: string, private readonly credentials: ChannelCredentials, private readonly options: ChannelOptions ) { @@ -164,14 +166,24 @@ export class ChannelImplementation implements Channel { ); } } + const originalTargetUri = parseUri(target); + if (originalTargetUri === null) { + throw new Error(`Could not parse target name "${target}"`); + } if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { - this.defaultAuthority = getDefaultAuthority(target); + this.defaultAuthority = getDefaultAuthority(originalTargetUri); } - const proxyMapResult = mapProxyName(target, options); + const proxyMapResult = mapProxyName(originalTargetUri, options); this.target = proxyMapResult.target; this.options = Object.assign({}, this.options, proxyMapResult.extraOptions); + + const targetUri = parseUri(target); + if (targetUri === null) { + throw new Error(`Could not parse target name "${target}"`); + } + this.target = targetUri; /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ this.subchannelPool = getSubchannelPool( @@ -422,7 +434,7 @@ export class ChannelImplementation implements Channel { } getTarget() { - return this.target; + return uriToString(this.target); } getConnectivityState(tryToConnect: boolean) { diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 2b3fb5d5a..e5e1ec3a5 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -15,10 +15,8 @@ * */ -import { URL } from 'url'; import { log } from './logging'; import { LogVerbosity } from './constants'; -import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; import * as logging from './logging'; @@ -28,6 +26,7 @@ import { subchannelAddressToString, } from './subchannel'; import { ChannelOptions } from './channel-options'; +import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; const TRACER_NAME = 'proxy'; @@ -59,31 +58,30 @@ function getProxyInfo(): ProxyInfo { } else { return {}; } - let proxyUrl: URL; - try { - proxyUrl = new URL(proxyEnv); - } catch (e) { + const proxyUrl = parseUri(proxyEnv); + if (proxyUrl === null) { log(LogVerbosity.ERROR, `cannot parse value of "${envVar}" env var`); return {}; } - if (proxyUrl.protocol !== 'http:') { + if (proxyUrl.scheme !== 'http') { log( LogVerbosity.ERROR, - `"${proxyUrl.protocol}" scheme not supported in proxy URI` + `"${proxyUrl.scheme}" scheme not supported in proxy URI` ); return {}; } + const splitPath = proxyUrl.path.split('@'); + let host: string; let userCred: string | null = null; - if (proxyUrl.username) { - if (proxyUrl.password) { - log(LogVerbosity.INFO, 'userinfo found in proxy URI'); - userCred = `${proxyUrl.username}:${proxyUrl.password}`; - } else { - userCred = proxyUrl.username; - } + if (splitPath.length === 2) { + log(LogVerbosity.INFO, 'userinfo found in proxy URI'); + userCred = splitPath[0]; + host = splitPath[1]; + } else { + host = proxyUrl.path; } const result: ProxyInfo = { - address: proxyUrl.host, + address: host, }; if (userCred) { result.creds = userCred; @@ -111,12 +109,12 @@ function getNoProxyHostList(): string[] { } export interface ProxyMapResult { - target: string; + target: GrpcUri; extraOptions: ChannelOptions; } export function mapProxyName( - target: string, + target: GrpcUri, options: ChannelOptions ): ProxyMapResult { const noProxyResult: ProxyMapResult = { @@ -127,11 +125,11 @@ export function mapProxyName( if (!proxyInfo.address) { return noProxyResult; } - const parsedTarget = parseTarget(target); - if (!parsedTarget) { + const hostPort = splitHostPort(target.path); + if (!hostPort) { return noProxyResult; } - const serverHost = parsedTarget.host; + const serverHost = hostPort.host; for (const host of getNoProxyHostList()) { if (host === serverHost) { trace('Not using proxy for target in no_proxy list: ' + target); @@ -139,20 +137,20 @@ export function mapProxyName( } } const extraOptions: ChannelOptions = { - 'grpc.http_connect_target': target, + 'grpc.http_connect_target': uriToString(target), }; if (proxyInfo.creds) { extraOptions['grpc.http_connect_creds'] = proxyInfo.creds; } return { - target: `dns:${proxyInfo.address}`, + target: { path: proxyInfo.address }, extraOptions: extraOptions, }; } export interface ProxyConnectionResult { socket?: Socket; - realTarget?: string; + realTarget?: GrpcUri; } export function getProxiedConnection( @@ -163,9 +161,13 @@ export function getProxiedConnection( return Promise.resolve({}); } const realTarget = channelOptions['grpc.http_connect_target'] as string; - const parsedTarget = parseTarget(realTarget)!; + const parsedTarget = parseUri(realTarget); + if (parsedTarget === null) { + return Promise.resolve({}); + } const options: http.RequestOptions = { method: 'CONNECT', + path: parsedTarget.path, }; // Connect to the subchannel address as a proxy if (isTcpSubchannelAddress(address)) { @@ -174,11 +176,6 @@ export function getProxiedConnection( } else { options.socketPath = address.path; } - if (parsedTarget.port === undefined) { - options.path = parsedTarget.host; - } else { - options.path = `${parsedTarget.host}:${parsedTarget.port}`; - } if ('grpc.http_connect_creds' in channelOptions) { options.headers = { 'Proxy-Authorization': @@ -204,7 +201,7 @@ export function getProxiedConnection( ); resolve({ socket, - realTarget, + realTarget: parsedTarget, }); } else { log( diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 24aa0236e..1f97c655f 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -29,6 +29,8 @@ import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; import { SubchannelAddress, TcpSubchannelAddress } from './subchannel'; +import { GrpcUri, uriToString, splitHostPort } from './uri-parser'; +import { isIPv6, isIPv4 } from 'net'; const TRACER_NAME = 'dns_resolver'; @@ -36,67 +38,14 @@ function trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } -/* These regular expressions match IP addresses with optional ports in different - * formats. In each case, capture group 1 contains the address, and capture - * group 2 contains the port number, if present */ -/** - * Matches 4 groups of up to 3 digits each, separated by periods, optionally - * followed by a colon and a number. - */ -const IPV4_REGEX = /^(\d{1,3}(?:\.\d{1,3}){3})(?::(\d+))?$/; -/** - * Matches any number of groups of up to 4 hex digits (case insensitive) - * separated by 1 or more colons. This variant does not match a port number. - */ -const IPV6_REGEX = /^([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)$/i; -/** - * Matches the same as the IPv6_REGEX, surrounded by square brackets, and - * optionally followed by a colon and a number. - */ -const IPV6_BRACKET_REGEX = /^\[([0-9a-f]{0,4}(?::{1,2}[0-9a-f]{0,4})+)\](?::(\d+))?$/i; - -/** - * Matches `[dns:][//authority/]host[:port]`, where `authority` and `host` are - * both arbitrary sequences of dot-separated strings of alphanumeric characters - * and `port` is a sequence of digits. Group 1 contains the hostname and group - * 2 contains the port number if provided. - */ -const DNS_REGEX = /^(?:dns:)?(?:\/\/(?:[a-zA-Z0-9-]+\.?)+\/)?((?:[a-zA-Z0-9-]+\.?)+)(?::(\d+))?$/; - /** * The default TCP port to connect to if not explicitly specified in the target. */ -const DEFAULT_PORT = '443'; +const DEFAULT_PORT = 443; const resolveTxtPromise = util.promisify(dns.resolveTxt); const dnsLookupPromise = util.promisify(dns.lookup); -/** - * Attempt to parse a target string as an IP address - * @param target - * @return An "IP:port" string in an array if parsing was successful, `null` otherwise - */ -function parseIP(target: string): SubchannelAddress[] | null { - /* These three regular expressions are all mutually exclusive, so we just - * want the first one that matches the target string, if any do. */ - const ipv4Match = IPV4_REGEX.exec(target); - const match = - ipv4Match || IPV6_REGEX.exec(target) || IPV6_BRACKET_REGEX.exec(target); - if (match === null) { - return null; - } - - // ipv6 addresses should be bracketed - const addr = match[1]; - let port: string; - if (match[2]) { - port = match[2]; - } else { - port = DEFAULT_PORT; - } - return [{ host: addr, port: +port }]; -} - /** * Merge any number of arrays into a single alternating array * @param arrays @@ -127,7 +76,7 @@ function mergeArrays(...arrays: T[][]): T[] { class DnsResolver implements Resolver { private readonly ipResult: SubchannelAddress[] | null; private readonly dnsHostname: string | null; - private readonly port: string | null; + private readonly port: number | null; private pendingLookupPromise: Promise | null = null; private pendingTxtPromise: Promise | null = null; private latestLookupResult: TcpSubchannelAddress[] | null = null; @@ -135,19 +84,27 @@ class DnsResolver implements Resolver { private latestServiceConfigError: StatusObject | null = null; private percentage: number; private defaultResolutionError: StatusObject; - constructor(private target: string, private listener: ResolverListener) { - trace('Resolver constructed for target ' + target); - this.ipResult = parseIP(target); - const dnsMatch = DNS_REGEX.exec(target); - if (dnsMatch === null) { + constructor(private target: GrpcUri, private listener: ResolverListener) { + trace('Resolver constructed for target ' + uriToString(target)); + const hostPort = splitHostPort(target.path); + if (hostPort === null) { + this.ipResult = null; this.dnsHostname = null; this.port = null; } else { - this.dnsHostname = dnsMatch[1]; - if (dnsMatch[2]) { - this.port = dnsMatch[2]; + if (isIPv4(hostPort.host) || isIPv6(hostPort.host)) { + this.ipResult = [ + { + host: hostPort.host, + port: hostPort.port ?? DEFAULT_PORT, + }, + ]; + this.dnsHostname = null; + this.port = null; } else { - this.port = DEFAULT_PORT; + this.ipResult = null; + this.dnsHostname = hostPort.host; + this.port = hostPort.port ?? DEFAULT_PORT; } } this.percentage = Math.random() * 100; @@ -308,19 +265,13 @@ class DnsResolver implements Resolver { * the IP address. For DNS targets, it is the hostname. * @param target */ - static getDefaultAuthority(target: string): string { - const ipMatch = - IPV4_REGEX.exec(target) || - IPV6_REGEX.exec(target) || - IPV6_BRACKET_REGEX.exec(target); - if (ipMatch) { - return ipMatch[1]; - } - const dnsMatch = DNS_REGEX.exec(target); - if (dnsMatch) { - return dnsMatch[1]; + static getDefaultAuthority(target: GrpcUri): string { + const hostPort = splitHostPort(target.path); + if (hostPort !== null) { + return hostPort.host; + } else { + throw new Error(`Failed to parse target ${target}`); } - throw new Error(`Failed to parse target ${target}`); } } @@ -329,7 +280,7 @@ class DnsResolver implements Resolver { * "dns:" prefix and as the default resolver. */ export function setup(): void { - registerResolver('dns:', DnsResolver); + registerResolver('dns', DnsResolver); registerDefaultResolver(DnsResolver); } @@ -337,19 +288,3 @@ export interface DnsUrl { host: string; port?: string; } - -export function parseTarget(target: string): DnsUrl | null { - const match = - IPV4_REGEX.exec(target) ?? - IPV6_REGEX.exec(target) ?? - IPV6_BRACKET_REGEX.exec(target) ?? - DNS_REGEX.exec(target); - if (match) { - return { - host: match[1], - port: match[2] ?? undefined, - }; - } else { - return null; - } -} diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 91128d2cb..c147f6370 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -21,23 +21,18 @@ import { registerDefaultResolver, } from './resolver'; import { SubchannelAddress } from './subchannel'; - -function getUdsName(target: string): string { - /* Due to how this resolver is registered, it should only be constructed - * with strings that start with 'unix:'. Other strings may result in - * nonsensical output. If the string starts with 'unix://' that entire - * prefix needs to be ignored */ - if (target.startsWith('unix://')) { - return target.substring(7); - } else { - return target.substring(5); - } -} +import { GrpcUri } from './uri-parser'; class UdsResolver implements Resolver { private addresses: SubchannelAddress[] = []; - constructor(target: string, private listener: ResolverListener) { - this.addresses = [{ path: getUdsName(target) }]; + constructor(target: GrpcUri, private listener: ResolverListener) { + let path: string; + if (target.authority === '') { + path = '/' + target.path; + } else { + path = target.path; + } + this.addresses = [{ path }]; } updateResolution(): void { process.nextTick( @@ -48,11 +43,11 @@ class UdsResolver implements Resolver { ); } - static getDefaultAuthority(target: string): string { + static getDefaultAuthority(target: GrpcUri): string { return 'localhost'; } } export function setup() { - registerResolver('unix:', UdsResolver); + registerResolver('unix', UdsResolver); } diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 4c091752e..e75f178ae 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -20,6 +20,7 @@ import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; +import { GrpcUri, uriToString } from './uri-parser'; /** * A listener object passed to the resolver's constructor that provides name @@ -62,17 +63,17 @@ export interface Resolver { } export interface ResolverConstructor { - new (target: string, listener: ResolverListener): Resolver; + new (target: GrpcUri, listener: ResolverListener): Resolver; /** * Get the default authority for a target. This loosely corresponds to that * target's hostname. Throws an error if this resolver class cannot parse the * `target`. * @param target */ - getDefaultAuthority(target: string): string; + getDefaultAuthority(target: GrpcUri): string; } -const registeredResolvers: { [prefix: string]: ResolverConstructor } = {}; +const registeredResolvers: { [scheme: string]: ResolverConstructor } = {}; let defaultResolver: ResolverConstructor | null = null; /** @@ -83,10 +84,10 @@ let defaultResolver: ResolverConstructor | null = null; * @param resolverClass */ export function registerResolver( - prefix: string, + scheme: string, resolverClass: ResolverConstructor ) { - registeredResolvers[prefix] = resolverClass; + registeredResolvers[scheme] = resolverClass; } /** @@ -105,18 +106,24 @@ export function registerDefaultResolver(resolverClass: ResolverConstructor) { * @param listener */ export function createResolver( - target: string, + target: GrpcUri, listener: ResolverListener ): Resolver { - for (const prefix of Object.keys(registeredResolvers)) { - if (target.startsWith(prefix)) { - return new registeredResolvers[prefix](target, listener); + if (target.scheme !== undefined && target.scheme in registeredResolvers) { + return new registeredResolvers[target.scheme](target, listener); + } else { + if (defaultResolver !== null) { + /* If the scheme does not correspond to a registered scheme, we assume + * that the whole thing is the path, and the scheme was pulled out + * incorrectly. For example, it is valid to parse "localhost:80" as + * having a scheme of "localhost" and a path of 80, but that is not + * how the resolver should see it */ + return new defaultResolver({ path: uriToString(target) }, listener); } } - if (defaultResolver !== null) { - return new defaultResolver(target, listener); - } - throw new Error(`No resolver could be created for target ${target}`); + throw new Error( + `No resolver could be created for target ${uriToString(target)}` + ); } /** @@ -124,16 +131,16 @@ export function createResolver( * error if no registered name resolver can parse that target string. * @param target */ -export function getDefaultAuthority(target: string): string { - for (const prefix of Object.keys(registeredResolvers)) { - if (target.startsWith(prefix)) { - return registeredResolvers[prefix].getDefaultAuthority(target); +export function getDefaultAuthority(target: GrpcUri): string { + if (target.scheme !== undefined && target.scheme in registeredResolvers) { + return registeredResolvers[target.scheme].getDefaultAuthority(target); + } else { + if (defaultResolver !== null) { + // See comment in createResolver for why we handle the target like this + return defaultResolver.getDefaultAuthority({ path: uriToString(target) }); } } - if (defaultResolver !== null) { - return defaultResolver.getDefaultAuthority(target); - } - throw new Error(`Invalid target ${target}`); + throw new Error(`Invalid target ${uriToString(target)}`); } export function registerAll() { diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index a9ba0594f..0720e7c02 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -35,6 +35,7 @@ import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; import { SubchannelAddress } from './subchannel'; +import { GrpcUri } from './uri-parser'; const TRACER_NAME = 'resolving_load_balancer'; @@ -126,7 +127,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { * implmentation */ constructor( - private target: string, + private target: GrpcUri, private channelControlHelper: ChannelControlHelper, private defaultServiceConfig: ServiceConfig | null ) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 25656a3b8..95aa68a24 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -52,6 +52,7 @@ import { TcpSubchannelAddress, isTcpSubchannelAddress, } from './subchannel'; +import { parseUri } from './uri-parser'; interface BindResult { port: number; @@ -225,6 +226,11 @@ export class Server { throw new TypeError('callback must be a function'); } + const portUri = parseUri(port); + if (portUri === null) { + throw new Error(`Could not parse port "${port}"`); + } + const serverOptions: http2.ServerOptions = {}; if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { @@ -392,7 +398,7 @@ export class Server { }, }; - const resolver = createResolver(port, resolverListener); + const resolver = createResolver(portUri, resolverListener); resolver.updateResolution(); } diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 0d42163d1..d28e3eac8 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -22,6 +22,7 @@ import { subchannelAddressEqual, } from './subchannel'; import { ChannelCredentials } from './channel-credentials'; +import { GrpcUri, uriToString } from './uri-parser'; // 10 seconds in milliseconds. This value is arbitrary. /** @@ -114,13 +115,13 @@ export class SubchannelPool { * @param channelCredentials */ getOrCreateSubchannel( - channelTarget: string, + channelTargetUri: GrpcUri, subchannelTarget: SubchannelAddress, channelArguments: ChannelOptions, channelCredentials: ChannelCredentials ): Subchannel { this.ensureCleanupTask(); - + const channelTarget = uriToString(channelTargetUri); if (channelTarget in this.pool) { const subchannelObjArray = this.pool[channelTarget]; for (const subchannelObj of subchannelObjArray) { @@ -141,7 +142,7 @@ export class SubchannelPool { } // If we get here, no matching subchannel was found const subchannel = new Subchannel( - channelTarget, + channelTargetUri, subchannelTarget, channelArguments, channelCredentials diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index e332df36d..bbb2937f5 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,6 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; +import { GrpcUri } from './uri-parser'; const clientVersion = require('../../package.json').version; @@ -199,7 +200,7 @@ export class Subchannel { * connection */ constructor( - private channelTarget: string, + private channelTarget: GrpcUri, private subchannelAddress: SubchannelAddress, private options: ChannelOptions, private credentials: ChannelCredentials diff --git a/packages/grpc-js/src/uri-parser.ts b/packages/grpc-js/src/uri-parser.ts new file mode 100644 index 000000000..20c3d53b3 --- /dev/null +++ b/packages/grpc-js/src/uri-parser.ts @@ -0,0 +1,114 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export interface GrpcUri { + scheme?: string; + authority?: string; + path: string; +} + +/* + * The groups correspond to URI parts as follows: + * 1. scheme + * 2. authority + * 3. path + */ +const URI_REGEX = /^(?:([A-Za-z0-9+.-]+):)?(?:\/\/([^/]*)\/)?(.+)$/; + +export function parseUri(uriString: string): GrpcUri | null { + const parsedUri = URI_REGEX.exec(uriString); + if (parsedUri === null) { + return null; + } + return { + scheme: parsedUri[1], + authority: parsedUri[2], + path: parsedUri[3], + }; +} + +export interface HostPort { + host: string; + port?: number; +} + +const NUMBER_REGEX = /^\d+$/; + +export function splitHostPort(path: string): HostPort | null { + if (path.startsWith('[')) { + const hostEnd = path.indexOf(']'); + if (hostEnd === -1) { + return null; + } + const host = path.substring(1, hostEnd); + /* Only an IPv6 address should be in bracketed notation, and an IPv6 + * address should have at least one colon */ + if (host.indexOf(':') === -1) { + return null; + } + if (path.length > hostEnd + 1) { + if (path[hostEnd + 1] === ':') { + const portString = path.substring(hostEnd + 2); + if (NUMBER_REGEX.test(portString)) { + return { + host: host, + port: +portString, + }; + } else { + return null; + } + } else { + return null; + } + } else { + return { + host, + }; + } + } else { + const splitPath = path.split(':'); + /* Exactly one colon means that this is host:port. Zero colons means that + * there is no port. And multiple colons means that this is a bare IPv6 + * address with no port */ + if (splitPath.length === 2) { + if (NUMBER_REGEX.test(splitPath[1])) { + return { + host: splitPath[0], + port: +splitPath[1], + }; + } else { + return null; + } + } else { + return { + host: path, + }; + } + } +} + +export function uriToString(uri: GrpcUri): string { + let result = ''; + if (uri.scheme !== undefined) { + result += uri.scheme + ':'; + } + if (uri.authority !== undefined) { + result += '//' + uri.authority + '/'; + } + result += uri.path; + return result; +} diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 7f4900aa2..465964ae2 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -22,6 +22,7 @@ import * as resolverManager from '../src/resolver'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; import { SubchannelAddress, isTcpSubchannelAddress } from '../src/subchannel'; +import { parseUri, GrpcUri } from '../src/uri-parser'; describe('Name Resolver', () => { describe('DNS Names', function() { @@ -31,7 +32,7 @@ describe('Name Resolver', () => { resolverManager.registerAll(); }); it('Should resolve localhost properly', done => { - const target = 'localhost:50051'; + const target = parseUri('localhost:50051')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -66,7 +67,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should default to port 443', done => { - const target = 'localhost'; + const target = parseUri('localhost')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -101,7 +102,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent an ipv4 address', done => { - const target = '1.2.3.4'; + const target = parseUri('1.2.3.4')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -128,7 +129,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent an ipv6 address', done => { - const target = '::1'; + const target = parseUri('::1')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -155,7 +156,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent a bracketed ipv6 address', done => { - const target = '[::1]:50051'; + const target = parseUri('[::1]:50051')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -182,7 +183,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a public address', done => { - const target = 'example.com'; + const target = parseUri('example.com')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -202,7 +203,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a name with multiple dots', done => { - const target = 'loopback4.unittest.grpc.io'; + const target = parseUri('loopback4.unittest.grpc.io')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -231,7 +232,7 @@ describe('Name Resolver', () => { /* TODO(murgatroid99): re-enable this test, once we can get the IPv6 result * consistently */ it.skip('Should resolve a DNS name to an IPv6 address', done => { - const target = 'loopback6.unittest.grpc.io'; + const target = parseUri('loopback6.unittest.grpc.io')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -258,7 +259,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { - const target = 'loopback46.unittest.grpc.io'; + const target = parseUri('loopback46.unittest.grpc.io')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -289,7 +290,7 @@ describe('Name Resolver', () => { it('Should resolve a name with a hyphen', done => { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ - const target = 'network-tools.com'; + const target = parseUri('network-tools.com')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -310,8 +311,8 @@ describe('Name Resolver', () => { }); it('Should resolve gRPC interop servers', done => { let completeCount = 0; - const target1 = 'grpc-test.sandbox.googleapis.com'; - const target2 = 'grpc-test4.sandbox.googleapis.com'; + const target1 = parseUri('grpc-test.sandbox.googleapis.com')!; + const target2 = parseUri('grpc-test4.sandbox.googleapis.com')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -332,13 +333,13 @@ describe('Name Resolver', () => { }; const resolver1 = resolverManager.createResolver(target1, listener); resolver1.updateResolution(); - const resolver2 = resolverManager.createResolver(target1, listener); + const resolver2 = resolverManager.createResolver(target2, listener); resolver2.updateResolution(); }); }); describe('UDS Names', () => { it('Should handle a relative Unix Domain Socket name', done => { - const target = 'unix:socket'; + const target = parseUri('unix:socket')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -362,7 +363,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should handle an absolute Unix Domain Socket name', done => { - const target = 'unix:///tmp/socket'; + const target = parseUri('unix:///tmp/socket')!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -393,13 +394,13 @@ describe('Name Resolver', () => { return []; } - static getDefaultAuthority(target: string): string { + static getDefaultAuthority(target: GrpcUri): string { return 'other'; } } it('Should return the correct authority if a different resolver has been registered', () => { - const target = 'other://name'; + const target = parseUri('other://name')!; resolverManager.registerResolver('other:', OtherResolver); const authority = resolverManager.getDefaultAuthority(target); diff --git a/packages/grpc-js/test/test-uri-parser.ts b/packages/grpc-js/test/test-uri-parser.ts new file mode 100644 index 000000000..75aa82bfe --- /dev/null +++ b/packages/grpc-js/test/test-uri-parser.ts @@ -0,0 +1,59 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import * as uriParser from '../src/uri-parser'; + +describe('URI Parser', function(){ + describe('parseUri', function() { + const expectationList: {target: string, result: uriParser.GrpcUri | null}[] = [ + {target: 'localhost', result: {scheme: undefined, authority: undefined, path: 'localhost'}}, + /* This looks weird, but it's OK because the resolver selection code will handle it */ + {target: 'localhost:80', result: {scheme: 'localhost', authority: undefined, path: '80'}}, + {target: 'dns:localhost', result: {scheme: 'dns', authority: undefined, path: 'localhost'}}, + {target: 'dns:///localhost', result: {scheme: 'dns', authority: '', path: 'localhost'}}, + {target: 'dns://authority/localhost', result: {scheme: 'dns', authority: 'authority', path: 'localhost'}}, + {target: '//authority/localhost', result: {scheme: undefined, authority: 'authority', path: 'localhost'}}, + // Regression test for https://github.com/grpc/grpc-node/issues/1359 + {target: 'dns:foo-internal.aws-us-east-2.tracing.staging-edge.foo-data.net:443:443', result: {scheme: 'dns', authority: undefined, path: 'foo-internal.aws-us-east-2.tracing.staging-edge.foo-data.net:443:443'}} + ]; + for (const {target, result} of expectationList) { + it (target, function() { + assert.deepStrictEqual(uriParser.parseUri(target), result); + }); + } + }); + + describe('splitHostPort', function() { + const expectationList: {path: string, result: uriParser.HostPort | null}[] = [ + {path: 'localhost', result: {host: 'localhost'}}, + {path: 'localhost:123', result: {host: 'localhost', port: 123}}, + {path: '12345:6789', result: {host: '12345', port: 6789}}, + {path: '[::1]:123', result: {host: '::1', port: 123}}, + {path: '[::1]', result: {host: '::1'}}, + {path: '[', result: null}, + {path: '[123]', result: null}, + // Regression test for https://github.com/grpc/grpc-node/issues/1359 + {path: 'foo-internal.aws-us-east-2.tracing.staging-edge.foo-data.net:443:443', result: {host: 'foo-internal.aws-us-east-2.tracing.staging-edge.foo-data.net:443:443'}} + ]; + for (const {path, result} of expectationList) { + it(path, function() { + assert.deepStrictEqual(uriParser.splitHostPort(path), result); + }); + } + }); +}); \ No newline at end of file From 1cd0ef12f22ed58d8b183931c44679d7eae79f20 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 16 Apr 2020 07:45:29 -0700 Subject: [PATCH 1014/1899] Fix target name in "other" resolver test --- packages/grpc-js/test/test-resolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 465964ae2..160a40d97 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -400,7 +400,7 @@ describe('Name Resolver', () => { } it('Should return the correct authority if a different resolver has been registered', () => { - const target = parseUri('other://name')!; + const target = parseUri('other:name')!; resolverManager.registerResolver('other:', OtherResolver); const authority = resolverManager.getDefaultAuthority(target); From dbe98ad09056e5e1c28793c9d70395d086e01a62 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 16 Apr 2020 08:34:24 -0700 Subject: [PATCH 1015/1899] Fix "other" resovler registration code --- packages/grpc-js/src/resolver-dns.ts | 2 +- packages/grpc-js/test/test-resolver.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 1f97c655f..58cc6dc84 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -270,7 +270,7 @@ class DnsResolver implements Resolver { if (hostPort !== null) { return hostPort.host; } else { - throw new Error(`Failed to parse target ${target}`); + throw new Error(`Failed to parse target ${uriToString(target)}`); } } } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 160a40d97..0ff40ac19 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -401,7 +401,8 @@ describe('Name Resolver', () => { it('Should return the correct authority if a different resolver has been registered', () => { const target = parseUri('other:name')!; - resolverManager.registerResolver('other:', OtherResolver); + console.log(target); + resolverManager.registerResolver('other', OtherResolver); const authority = resolverManager.getDefaultAuthority(target); assert.equal(authority, 'other'); From 2db1aff5ff59e49b6c731e846051573bb926356c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 16 Apr 2020 14:32:25 -0700 Subject: [PATCH 1016/1899] Bump grpc-js to 1.0 and stop calling it "beta" --- README.md | 2 -- packages/grpc-js/README.md | 22 ++++++++++++---------- packages/grpc-js/package.json | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 908835f8d..cc6c10ee4 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,6 @@ Directory: [`packages/grpc-js`](https://github.com/grpc/grpc-node/tree/master/pa npm package: [@grpc/grpc-js](https://www.npmjs.com/package/@grpc/grpc-js) -**This library is currently incomplete and experimental. It is built on the [http2 Node module](https://nodejs.org/api/http2.html).** - This library implements the core functionality of gRPC purely in JavaScript, without a C++ addon. It works on the latest version of Node.js on all platforms that Node.js runs on. ## Other Packages diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index e3918666d..7d51b5b53 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -1,10 +1,8 @@ # Pure JavaScript gRPC Client -**Note: This is an beta-level release. Some APIs may not yet be present and there may be bugs. Please report any that you encounter** - ## Installation -Node 10 is recommended. The exact set of compatible Node versions can be found in the `engines` field of the `package.json` file. +Node 12 is recommended. The exact set of compatible Node versions can be found in the `engines` field of the `package.json` file. ```sh npm install @grpc/grpc-js @@ -12,13 +10,17 @@ npm install @grpc/grpc-js ## Features - - Unary and streaming calls - - Cancellation - - Deadlines - - TLS channel credentials - - Call credentials (for auth) - - Simple reconnection - - Channel API + - Clients + - Automatic reconnection + - Servers + - Streaming + - Metadata + - Partial compression support: clients can decompress response messages + - Pick first and round robin load balancing policies + - Client Interceptors + - Connection Keepalives + - HTTP Connect support (proxies) + This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package. diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 06aa83855..4551d1de8 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "0.8.1", + "version": "1.0.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From a440ebcb3f18ccc4151588f042dbd7629d38c427 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 16 Apr 2020 15:11:10 -0700 Subject: [PATCH 1017/1899] Bump grpc-health-check to 1.8.0 --- packages/grpc-health-check/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-health-check/package.json b/packages/grpc-health-check/package.json index 388eb7d81..e9b836346 100644 --- a/packages/grpc-health-check/package.json +++ b/packages/grpc-health-check/package.json @@ -1,6 +1,6 @@ { "name": "grpc-health-check", - "version": "1.7.1", + "version": "1.8.0", "author": "Google Inc.", "description": "Health check client and service for use with gRPC-node", "repository": { From 4e7b94ab3596179a9d161fbe4abf0f77e9ad2fc3 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Sat, 18 Apr 2020 09:16:41 +0100 Subject: [PATCH 1018/1899] grpc-js: Remove watcher from queue before calling watcher callback. Fixes #1352 In the case where a new watcher is synchronously added to the watcher queue via the watcher callback, this can result in the callback being called multiple times. To support this case, the watcher needs to be move removed from the queue before calling the watcher callback. --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 4d07dde03..2c8906c4d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -381,9 +381,9 @@ export class ChannelImplementation implements Channel { const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { if (newState !== watcherObject.currentState) { - watcherObject.callback(); clearTimeout(watcherObject.timer); this.removeConnectivityStateWatcher(watcherObject); + watcherObject.callback(); } } } From 615a3c65b14e965a1d130a02005807dd122c9091 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Sat, 18 Apr 2020 09:19:45 +0100 Subject: [PATCH 1019/1899] grpc-js: Add test for client.waitForReady. Refs #1352 --- packages/grpc-js/test/test-client.ts | 81 ++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 packages/grpc-js/test/test-client.ts diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts new file mode 100644 index 000000000..e783b715c --- /dev/null +++ b/packages/grpc-js/test/test-client.ts @@ -0,0 +1,81 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// Allow `any` data type for testing runtime type checking. +// tslint:disable no-any +import * as assert from 'assert'; +import * as path from 'path'; + +import * as grpc from '../src'; +import { Server, ServerCredentials } from '../src'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; + +import { loadProtoFile } from './common'; +import { ConnectivityState } from '../src/channel'; + +const clientInsecureCreds = grpc.credentials.createInsecure(); +const serverInsecureCreds = ServerCredentials.createInsecure(); + +describe('Client', () => { + let server: Server; + let client: ServiceClient; + + before(done => { + const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); + const echoService = loadProtoFile(protoFile) + .EchoService as ServiceClientConstructor; + + server = new Server(); + + server.bindAsync( + 'localhost:0', + serverInsecureCreds, + (err, port) => { + assert.ifError(err); + client = new echoService( + `localhost:${port}`, + clientInsecureCreds + ); + server.start(); + done(); + } + ); + }); + + after(done => { + client.close(); + server.tryShutdown(done); + }); + + it('should call the waitForReady callback only once when channel connectivity state is READY', done => { + const deadline = Date.now() + 100; + let calledTimes = 0; + client.waitForReady(deadline, err => { + assert.ifError(err); + assert.equal( + client.getChannel().getConnectivityState(true), + ConnectivityState.READY + ); + calledTimes += 1; + }); + setTimeout(() => { + assert.equal(calledTimes, 1); + done(); + }, deadline - Date.now()); + }); +}); From af7f4f798dbf3b0092386d803ed9bd701cee0578 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sat, 18 Apr 2020 11:04:13 +0200 Subject: [PATCH 1020/1899] grpc-js: initiate tls connection through http proxy --- packages/grpc-js/src/http_proxy.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 2b3fb5d5a..fe0bfb7ed 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -21,6 +21,7 @@ import { LogVerbosity } from './constants'; import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; +import * as tls from 'tls' import * as logging from './logging'; import { SubchannelAddress, @@ -202,9 +203,14 @@ export function getProxiedConnection( ' through proxy ' + proxyAddressString ); - resolve({ - socket, - realTarget, + var cts = tls.connect({ + host: options.host, + socket: socket + }, function () { + resolve({ + socket: cts, + realTarget, + }); }); } else { log( From c650e59563ea1d4942019c5e7024fbc8487b11ac Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sat, 18 Apr 2020 12:56:51 +0200 Subject: [PATCH 1021/1899] grpc-js: always explicitly establish connection --- packages/grpc-js/src/subchannel.ts | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index e332df36d..9622e2806 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -302,21 +302,20 @@ export class Subchannel { if (proxyConnectionResult.socket) { connectionOptions.socket = proxyConnectionResult.socket; } - } else { - /* In all but the most recent versions of Node, http2.connect does not use - * the options when establishing plaintext connections, so we need to - * establish that connection explicitly. */ - connectionOptions.createConnection = (authority, option) => { - if (proxyConnectionResult.socket) { - return proxyConnectionResult.socket; - } else { - /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ - return net.connect(this.subchannelAddress); - } - }; } + /* In all but the most recent versions of Node, http2.connect does not use + * the options when establishing plaintext connections, so we need to + * establish that connection explicitly. */ + connectionOptions.createConnection = (authority, option) => { + if (proxyConnectionResult.socket) { + return proxyConnectionResult.socket; + } else { + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(this.subchannelAddress); + } + }; connectionOptions = Object.assign( connectionOptions, this.subchannelAddress From 5af582e31c4116984ffc70243b76d1cc5d894d35 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sat, 18 Apr 2020 13:59:49 +0200 Subject: [PATCH 1022/1899] grpc-js: pass secureContext through to proxied tls connection --- packages/grpc-js/src/http_proxy.ts | 5 ++++- packages/grpc-js/src/subchannel.ts | 23 ++++++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index fe0bfb7ed..cde1d4213 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -21,6 +21,7 @@ import { LogVerbosity } from './constants'; import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; +import * as http2 from 'http2'; import * as tls from 'tls' import * as logging from './logging'; import { @@ -158,7 +159,8 @@ export interface ProxyConnectionResult { export function getProxiedConnection( address: SubchannelAddress, - channelOptions: ChannelOptions + channelOptions: ChannelOptions, + connectionOptions: http2.SecureClientSessionOptions ): Promise { if (!('grpc.http_connect_target' in channelOptions)) { return Promise.resolve({}); @@ -204,6 +206,7 @@ export function getProxiedConnection( proxyAddressString ); var cts = tls.connect({ + ...connectionOptions, host: options.host, socket: socket }, function () { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 9622e2806..387d69e8b 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -411,7 +411,28 @@ export class Subchannel { } private startConnectingInternal() { - getProxiedConnection(this.subchannelAddress, this.options).then( + let connectionOptions: http2.SecureClientSessionOptions = + this.credentials._getConnectionOptions() || {}; + + if ('secureContext' in connectionOptions) { + // If provided, the value of grpc.ssl_target_name_override should be used + // to override the target hostname when checking server identity. + // This option is used for testing only. + if (this.options['grpc.ssl_target_name_override']) { + const sslTargetNameOverride = this.options[ + 'grpc.ssl_target_name_override' + ]!; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; + connectionOptions.servername = sslTargetNameOverride; + } + } + + getProxiedConnection(this.subchannelAddress, this.options, connectionOptions).then( (result) => { this.createSession(result); }, From 4e61f21c2fe3a7119de16b5e7459b508fd7d8a99 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sat, 18 Apr 2020 17:58:11 +0200 Subject: [PATCH 1023/1899] grpc-js: do not set host when instantiating tls socket --- packages/grpc-js/src/http_proxy.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index cde1d4213..dd5e1bbf8 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -207,7 +207,6 @@ export function getProxiedConnection( ); var cts = tls.connect({ ...connectionOptions, - host: options.host, socket: socket }, function () { resolve({ From 2c5a8b1a3077f36154d36fecb27c78a13aca3d0e Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sat, 18 Apr 2020 18:41:28 +0200 Subject: [PATCH 1024/1899] grpc-js: ensure tls connection is used when requested --- packages/grpc-js/src/http_proxy.ts | 23 ++++++++++++++++------- packages/grpc-js/src/subchannel.ts | 24 ++++++++++++++---------- 2 files changed, 30 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index dd5e1bbf8..666877f00 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -18,11 +18,12 @@ import { URL } from 'url'; import { log } from './logging'; import { LogVerbosity } from './constants'; +import { getDefaultAuthority } from './resolver'; import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; import * as http2 from 'http2'; -import * as tls from 'tls' +import * as tls from 'tls'; import * as logging from './logging'; import { SubchannelAddress, @@ -205,15 +206,23 @@ export function getProxiedConnection( ' through proxy ' + proxyAddressString ); - var cts = tls.connect({ - ...connectionOptions, - socket: socket - }, function () { + // The proxy is connecting to a TLS server, so upgrade + // this socket connection to a TLS connection. + if ('secureContext' in connectionOptions) { + const cts = tls.connect({ + ...connectionOptions, + host: getDefaultAuthority(realTarget), + socket: socket, + }, () => { + resolve({ socket: cts, realTarget }); + } + ); + } else { resolve({ - socket: cts, + socket, realTarget, }); - }); + } } else { log( LogVerbosity.ERROR, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 387d69e8b..729ab3d04 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,6 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; +import * as tls from 'tls'; const clientVersion = require('../../package.json').version; @@ -299,9 +300,6 @@ export class Subchannel { }; connectionOptions.servername = sslTargetNameOverride; } - if (proxyConnectionResult.socket) { - connectionOptions.socket = proxyConnectionResult.socket; - } } /* In all but the most recent versions of Node, http2.connect does not use * the options when establishing plaintext connections, so we need to @@ -309,13 +307,15 @@ export class Subchannel { connectionOptions.createConnection = (authority, option) => { if (proxyConnectionResult.socket) { return proxyConnectionResult.socket; - } else { - /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ - return net.connect(this.subchannelAddress); + } else if ('secureContext' in connectionOptions) { + return tls.connect(this.subchannelAddress); } + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(this.subchannelAddress); }; + connectionOptions = Object.assign( connectionOptions, this.subchannelAddress @@ -411,7 +411,7 @@ export class Subchannel { } private startConnectingInternal() { - let connectionOptions: http2.SecureClientSessionOptions = + const connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; if ('secureContext' in connectionOptions) { @@ -432,7 +432,11 @@ export class Subchannel { } } - getProxiedConnection(this.subchannelAddress, this.options, connectionOptions).then( + getProxiedConnection( + this.subchannelAddress, + this.options, + connectionOptions + ).then( (result) => { this.createSession(result); }, From 11965fb0af6b633bf0be4b914d6571b22a34c803 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sat, 18 Apr 2020 22:34:18 +0200 Subject: [PATCH 1025/1899] grpc-js: dont set createConnection when connecting with TLS and without a proxy --- packages/grpc-js/src/subchannel.ts | 31 +++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 729ab3d04..d1226e967 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -300,21 +300,26 @@ export class Subchannel { }; connectionOptions.servername = sslTargetNameOverride; } - } - /* In all but the most recent versions of Node, http2.connect does not use - * the options when establishing plaintext connections, so we need to - * establish that connection explicitly. */ - connectionOptions.createConnection = (authority, option) => { if (proxyConnectionResult.socket) { - return proxyConnectionResult.socket; - } else if ('secureContext' in connectionOptions) { - return tls.connect(this.subchannelAddress); + connectionOptions.createConnection = (authority, option) => { + return proxyConnectionResult.socket!; + }; } - /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ - return net.connect(this.subchannelAddress); - }; + } else { + /* In all but the most recent versions of Node, http2.connect does not use + * the options when establishing plaintext connections, so we need to + * establish that connection explicitly. */ + connectionOptions.createConnection = (authority, option) => { + if (proxyConnectionResult.socket) { + return proxyConnectionResult.socket; + } + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(this.subchannelAddress); + }; + } + connectionOptions = Object.assign( connectionOptions, From b9e84f499fa687674478885e50b49785ea214712 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sun, 19 Apr 2020 19:58:56 +0200 Subject: [PATCH 1026/1899] grpc-js: commenting working for node issue 32922 --- packages/grpc-js/src/http_proxy.ts | 10 ++++++---- packages/grpc-js/src/subchannel.ts | 14 +++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 666877f00..956eef4ae 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -22,9 +22,9 @@ import { getDefaultAuthority } from './resolver'; import { parseTarget } from './resolver-dns'; import { Socket } from 'net'; import * as http from 'http'; -import * as http2 from 'http2'; import * as tls from 'tls'; import * as logging from './logging'; +import { SecureClientSessionOptions } from 'http2' import { SubchannelAddress, isTcpSubchannelAddress, @@ -161,7 +161,7 @@ export interface ProxyConnectionResult { export function getProxiedConnection( address: SubchannelAddress, channelOptions: ChannelOptions, - connectionOptions: http2.SecureClientSessionOptions + connectionOptions: SecureClientSessionOptions ): Promise { if (!('grpc.http_connect_target' in channelOptions)) { return Promise.resolve({}); @@ -206,9 +206,11 @@ export function getProxiedConnection( ' through proxy ' + proxyAddressString ); - // The proxy is connecting to a TLS server, so upgrade - // this socket connection to a TLS connection. if ('secureContext' in connectionOptions) { + /* The proxy is connecting to a TLS server, so upgrade this socket + * connection to a TLS connection. + * This is a workaround for https://github.com/nodejs/node/issues/32922 + * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ const cts = tls.connect({ ...connectionOptions, host: getDefaultAuthority(realTarget), diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index d1226e967..a48453470 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -312,15 +312,15 @@ export class Subchannel { connectionOptions.createConnection = (authority, option) => { if (proxyConnectionResult.socket) { return proxyConnectionResult.socket; + } else { + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(this.subchannelAddress); } - /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ - return net.connect(this.subchannelAddress); }; } - connectionOptions = Object.assign( connectionOptions, this.subchannelAddress @@ -416,6 +416,10 @@ export class Subchannel { } private startConnectingInternal() { + /* Pass connection options through to the proxy so that it's able to + * upgrade it's connection to support tls if needed. + * This is a workaround for https://github.com/nodejs/node/issues/32922 + * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ const connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; From 48072d5f4f01cc82c1cf06e45b95cc423093fc09 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sun, 19 Apr 2020 20:00:05 +0200 Subject: [PATCH 1027/1899] grpc-js: setting ALPNProtocols option for tls proxy --- packages/grpc-js/src/subchannel.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index a48453470..f44d1b857 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -424,6 +424,7 @@ export class Subchannel { this.credentials._getConnectionOptions() || {}; if ('secureContext' in connectionOptions) { + connectionOptions.ALPNProtocols = ['h2']; // If provided, the value of grpc.ssl_target_name_override should be used // to override the target hostname when checking server identity. // This option is used for testing only. From eef75a5c1b9de00b55cc8b44c44a7b930ac1bc31 Mon Sep 17 00:00:00 2001 From: Tom Kirkpatrick Date: Sun, 19 Apr 2020 20:02:38 +0200 Subject: [PATCH 1028/1899] grpc-js: use tls.ConnectionOptions type for proxy connection options --- packages/grpc-js/src/http_proxy.ts | 3 +-- packages/grpc-js/src/subchannel.ts | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 956eef4ae..708b30c6e 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -24,7 +24,6 @@ import { Socket } from 'net'; import * as http from 'http'; import * as tls from 'tls'; import * as logging from './logging'; -import { SecureClientSessionOptions } from 'http2' import { SubchannelAddress, isTcpSubchannelAddress, @@ -161,7 +160,7 @@ export interface ProxyConnectionResult { export function getProxiedConnection( address: SubchannelAddress, channelOptions: ChannelOptions, - connectionOptions: SecureClientSessionOptions + connectionOptions: tls.ConnectionOptions ): Promise { if (!('grpc.http_connect_target' in channelOptions)) { return Promise.resolve({}); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index f44d1b857..414e797d3 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,7 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; -import * as tls from 'tls'; +import { ConnectionOptions } from 'tls'; const clientVersion = require('../../package.json').version; @@ -420,7 +420,7 @@ export class Subchannel { * upgrade it's connection to support tls if needed. * This is a workaround for https://github.com/nodejs/node/issues/32922 * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ - const connectionOptions: http2.SecureClientSessionOptions = + const connectionOptions: ConnectionOptions = this.credentials._getConnectionOptions() || {}; if ('secureContext' in connectionOptions) { From bbec4514d2750c4b82d044dea597ecd03fd50458 Mon Sep 17 00:00:00 2001 From: Gintautas Miselis Date: Mon, 20 Apr 2020 13:29:35 +0300 Subject: [PATCH 1029/1899] Don't use bundledDependencies --- packages/grpc-native-core/package.json | 3 --- packages/grpc-tools/package.json | 1 - 2 files changed, 4 deletions(-) diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json index 311054c66..83e911d12 100644 --- a/packages/grpc-native-core/package.json +++ b/packages/grpc-native-core/package.json @@ -25,9 +25,6 @@ "install": "node-pre-gyp install --fallback-to-build --library=static_library", "prepack": "git submodule update --init --recursive && npm install" }, - "bundledDependencies": [ - "node-pre-gyp" - ], "dependencies": { "@types/bytebuffer": "^5.0.40", "lodash.camelcase": "^4.3.0", diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 2bf3feff9..298d64d1b 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -23,7 +23,6 @@ "install": "node-pre-gyp install", "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, - "bundledDependencies": ["node-pre-gyp"], "dependencies": { "node-pre-gyp": "^0.12.0" }, From 6e3ab74e640f35bc11f0cbe5301a5a4cc7409fa8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Apr 2020 10:32:19 -0700 Subject: [PATCH 1030/1899] grpc-js: Make request callback type match the other library --- packages/grpc-js/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 661e0efd3..9c3a566e2 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -33,6 +33,7 @@ import { Client, CallInvocationTransformer, CallProperties, + UnaryCallback } from './client'; import { LogVerbosity, Status } from './constants'; import * as logging from './logging'; @@ -209,6 +210,7 @@ export { CallInvocationTransformer, ChannelImplementation as Channel, Channel as ChannelInterface, + UnaryCallback as requestCallback }; /** From 7e381f7f2a6559e8fb3ef403de5b74cb000b6e12 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Mon, 20 Apr 2020 19:12:32 +0100 Subject: [PATCH 1031/1899] grpc-js: Simplify client.waitForReady tests. Refs #1352 No need to add a service to the server to test the client. --- packages/grpc-js/test/test-client.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts index e783b715c..da20c246b 100644 --- a/packages/grpc-js/test/test-client.ts +++ b/packages/grpc-js/test/test-client.ts @@ -15,17 +15,11 @@ * */ -// Allow `any` data type for testing runtime type checking. -// tslint:disable no-any import * as assert from 'assert'; -import * as path from 'path'; import * as grpc from '../src'; import { Server, ServerCredentials } from '../src'; -import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; -import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; - -import { loadProtoFile } from './common'; +import { Client } from '../src'; import { ConnectivityState } from '../src/channel'; const clientInsecureCreds = grpc.credentials.createInsecure(); @@ -33,13 +27,9 @@ const serverInsecureCreds = ServerCredentials.createInsecure(); describe('Client', () => { let server: Server; - let client: ServiceClient; + let client: Client; before(done => { - const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); - const echoService = loadProtoFile(protoFile) - .EchoService as ServiceClientConstructor; - server = new Server(); server.bindAsync( @@ -47,7 +37,7 @@ describe('Client', () => { serverInsecureCreds, (err, port) => { assert.ifError(err); - client = new echoService( + client = new Client( `localhost:${port}`, clientInsecureCreds ); @@ -62,7 +52,7 @@ describe('Client', () => { server.tryShutdown(done); }); - it('should call the waitForReady callback only once when channel connectivity state is READY', done => { + it('should call the waitForReady callback only once, when channel connectivity state is READY', done => { const deadline = Date.now() + 100; let calledTimes = 0; client.waitForReady(deadline, err => { From 98e46260ef0e77a1052a2c51ca468de60e7eb4b1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Apr 2020 11:22:56 -0700 Subject: [PATCH 1032/1899] Fix merge error with proxy fixes --- packages/grpc-js/src/http_proxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 726c84c11..2721055fc 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -213,7 +213,7 @@ export function getProxiedConnection( * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ const cts = tls.connect({ ...connectionOptions, - host: getDefaultAuthority(realTarget), + host: getDefaultAuthority(parsedTarget), socket: socket, }, () => { resolve({ socket: cts, realTarget: parsedTarget }); From 615058036b8a19626bfea1575d609b32af1443a1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Apr 2020 15:08:28 -0700 Subject: [PATCH 1033/1899] grpc-js: Add "Migrating from grpc" README section --- packages/grpc-js/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 7d51b5b53..ed993d2f3 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -21,9 +21,16 @@ npm install @grpc/grpc-js - Connection Keepalives - HTTP Connect support (proxies) - This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package. + ## Migrating from [`grpc`](https://www.npmjs.com/package/grpc) + + `@grpc/grpc-js` is almost a drop-in replacement for `grpc`, but you may need to make a few code changes to use it: + + - If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. + - If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `--generate_package_definitions` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. + - If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead. + ## Some Notes on API Guarantees The public API of this library follows semantic versioning, with some caveats: From 726e7453f5ffc2bfeeb834a76d5c73db35a470c4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Apr 2020 09:18:35 -0700 Subject: [PATCH 1034/1899] grpc-js: Fix proxy + URI parsing bugs --- packages/grpc-js/src/channel.ts | 14 +++++----- packages/grpc-js/src/http_proxy.ts | 33 ++++++++++++++---------- packages/grpc-js/src/resolver-dns.ts | 2 -- packages/grpc-js/src/resolver.ts | 38 +++++++++++++++------------- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index c067a6929..85df3cf36 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -33,7 +33,7 @@ import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; -import { getDefaultAuthority } from './resolver'; +import { getDefaultAuthority, mapUriDefaultScheme } from './resolver'; import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; @@ -170,20 +170,18 @@ export class ChannelImplementation implements Channel { if (originalTargetUri === null) { throw new Error(`Could not parse target name "${target}"`); } + /* This ensures that the target has a scheme that is registered with the + * resolver */ + const defaultSchemeMapResult = mapUriDefaultScheme(originalTargetUri); if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { - this.defaultAuthority = getDefaultAuthority(originalTargetUri); + this.defaultAuthority = getDefaultAuthority(defaultSchemeMapResult); } - const proxyMapResult = mapProxyName(originalTargetUri, options); + const proxyMapResult = mapProxyName(defaultSchemeMapResult, options); this.target = proxyMapResult.target; this.options = Object.assign({}, this.options, proxyMapResult.extraOptions); - const targetUri = parseUri(target); - if (targetUri === null) { - throw new Error(`Could not parse target name "${target}"`); - } - this.target = targetUri; /* The global boolean parameter to getSubchannelPool has the inverse meaning to what * the grpc.use_local_subchannel_pool channel option means. */ this.subchannelPool = getSubchannelPool( diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 2721055fc..18c0e115b 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -29,6 +29,7 @@ import { } from './subchannel'; import { ChannelOptions } from './channel-options'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; +import { URL } from 'url'; const TRACER_NAME = 'proxy'; @@ -60,30 +61,31 @@ function getProxyInfo(): ProxyInfo { } else { return {}; } - const proxyUrl = parseUri(proxyEnv); - if (proxyUrl === null) { + let proxyUrl: URL; + try { + proxyUrl = new URL(proxyEnv); + } catch (e) { log(LogVerbosity.ERROR, `cannot parse value of "${envVar}" env var`); return {}; } - if (proxyUrl.scheme !== 'http') { + if (proxyUrl.protocol !== 'http:') { log( LogVerbosity.ERROR, - `"${proxyUrl.scheme}" scheme not supported in proxy URI` + `"${proxyUrl.protocol}" scheme not supported in proxy URI` ); return {}; } - const splitPath = proxyUrl.path.split('@'); - let host: string; let userCred: string | null = null; - if (splitPath.length === 2) { - log(LogVerbosity.INFO, 'userinfo found in proxy URI'); - userCred = splitPath[0]; - host = splitPath[1]; - } else { - host = proxyUrl.path; + if (proxyUrl.username) { + if (proxyUrl.password) { + log(LogVerbosity.INFO, 'userinfo found in proxy URI'); + userCred = `${proxyUrl.username}:${proxyUrl.password}`; + } else { + userCred = proxyUrl.username; + } } const result: ProxyInfo = { - address: host, + address: proxyUrl.host, }; if (userCred) { result.creds = userCred; @@ -145,7 +147,10 @@ export function mapProxyName( extraOptions['grpc.http_connect_creds'] = proxyInfo.creds; } return { - target: { path: proxyInfo.address }, + target: { + scheme: 'dns', + path: proxyInfo.address + }, extraOptions: extraOptions, }; } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 58cc6dc84..565e2daf4 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -18,7 +18,6 @@ import { Resolver, ResolverListener, registerResolver, - registerDefaultResolver, } from './resolver'; import * as dns from 'dns'; import * as util from 'util'; @@ -281,7 +280,6 @@ class DnsResolver implements Resolver { */ export function setup(): void { registerResolver('dns', DnsResolver); - registerDefaultResolver(DnsResolver); } export interface DnsUrl { diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index e75f178ae..6af996a2e 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -74,7 +74,7 @@ export interface ResolverConstructor { } const registeredResolvers: { [scheme: string]: ResolverConstructor } = {}; -let defaultResolver: ResolverConstructor | null = null; +let defaultScheme: string | null = null; /** * Register a resolver class to handle target names prefixed with the `prefix` @@ -95,8 +95,8 @@ export function registerResolver( * any registered prefix. * @param resolverClass */ -export function registerDefaultResolver(resolverClass: ResolverConstructor) { - defaultResolver = resolverClass; +export function registerDefaultScheme(scheme: string) { + defaultScheme = scheme; } /** @@ -112,18 +112,10 @@ export function createResolver( if (target.scheme !== undefined && target.scheme in registeredResolvers) { return new registeredResolvers[target.scheme](target, listener); } else { - if (defaultResolver !== null) { - /* If the scheme does not correspond to a registered scheme, we assume - * that the whole thing is the path, and the scheme was pulled out - * incorrectly. For example, it is valid to parse "localhost:80" as - * having a scheme of "localhost" and a path of 80, but that is not - * how the resolver should see it */ - return new defaultResolver({ path: uriToString(target) }, listener); - } + throw new Error( + `No resolver could be created for target ${uriToString(target)}` + ); } - throw new Error( - `No resolver could be created for target ${uriToString(target)}` - ); } /** @@ -135,12 +127,22 @@ export function getDefaultAuthority(target: GrpcUri): string { if (target.scheme !== undefined && target.scheme in registeredResolvers) { return registeredResolvers[target.scheme].getDefaultAuthority(target); } else { - if (defaultResolver !== null) { - // See comment in createResolver for why we handle the target like this - return defaultResolver.getDefaultAuthority({ path: uriToString(target) }); + throw new Error(`Invalid target ${uriToString(target)}`); + } +} + +export function mapUriDefaultScheme(target: GrpcUri): GrpcUri { + if (target.scheme === undefined || !(target.scheme in registeredResolvers)) { + if (defaultScheme !== null) { + return { + scheme: defaultScheme, + path: uriToString(target) + }; + } else { + throw new Error(`Invalid target ${uriToString(target)}`); } } - throw new Error(`Invalid target ${uriToString(target)}`); + return target; } export function registerAll() { From ec4eb785fe0f9f38cdc21f3e0b9c453540adff9f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Apr 2020 09:26:51 -0700 Subject: [PATCH 1035/1899] Actually register 'dns' as the default scheme --- packages/grpc-js/src/resolver-dns.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 565e2daf4..1e84fe9bd 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -18,6 +18,7 @@ import { Resolver, ResolverListener, registerResolver, + registerDefaultScheme, } from './resolver'; import * as dns from 'dns'; import * as util from 'util'; @@ -280,6 +281,7 @@ class DnsResolver implements Resolver { */ export function setup(): void { registerResolver('dns', DnsResolver); + registerDefaultScheme('dns'); } export interface DnsUrl { From 23e2353ea05fd3cd738ac5a160d4957c2d547bdf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Apr 2020 09:58:34 -0700 Subject: [PATCH 1036/1899] Update tests and add new ones --- packages/grpc-js/src/channel.ts | 3 +++ packages/grpc-js/src/resolver-uds.ts | 1 - packages/grpc-js/src/resolver.ts | 5 ++-- packages/grpc-js/test/test-resolver.ts | 30 ++++++++++++------------ packages/grpc-js/test/test-uri-parser.ts | 18 ++++++++++++++ 5 files changed, 39 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 85df3cf36..764c7a699 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -173,6 +173,9 @@ export class ChannelImplementation implements Channel { /* This ensures that the target has a scheme that is registered with the * resolver */ const defaultSchemeMapResult = mapUriDefaultScheme(originalTargetUri); + if (defaultSchemeMapResult === null) { + throw new Error(`Could not find a default scheme for target name "${target}"`); + } if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index c147f6370..759cb233e 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -18,7 +18,6 @@ import { Resolver, ResolverListener, registerResolver, - registerDefaultResolver, } from './resolver'; import { SubchannelAddress } from './subchannel'; import { GrpcUri } from './uri-parser'; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 6af996a2e..7d6d1ad5a 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -131,15 +131,16 @@ export function getDefaultAuthority(target: GrpcUri): string { } } -export function mapUriDefaultScheme(target: GrpcUri): GrpcUri { +export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { if (target.scheme === undefined || !(target.scheme in registeredResolvers)) { if (defaultScheme !== null) { return { scheme: defaultScheme, + authority: undefined, path: uriToString(target) }; } else { - throw new Error(`Invalid target ${uriToString(target)}`); + return null; } } return target; diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 0ff40ac19..d525d97d2 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -32,7 +32,7 @@ describe('Name Resolver', () => { resolverManager.registerAll(); }); it('Should resolve localhost properly', done => { - const target = parseUri('localhost:50051')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('localhost:50051')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -67,7 +67,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should default to port 443', done => { - const target = parseUri('localhost')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('localhost')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -102,7 +102,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent an ipv4 address', done => { - const target = parseUri('1.2.3.4')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('1.2.3.4')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -129,7 +129,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent an ipv6 address', done => { - const target = parseUri('::1')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('::1')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -156,7 +156,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should correctly represent a bracketed ipv6 address', done => { - const target = parseUri('[::1]:50051')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('[::1]:50051')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -183,7 +183,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a public address', done => { - const target = parseUri('example.com')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('example.com')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -203,7 +203,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a name with multiple dots', done => { - const target = parseUri('loopback4.unittest.grpc.io')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('loopback4.unittest.grpc.io')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -232,7 +232,7 @@ describe('Name Resolver', () => { /* TODO(murgatroid99): re-enable this test, once we can get the IPv6 result * consistently */ it.skip('Should resolve a DNS name to an IPv6 address', done => { - const target = parseUri('loopback6.unittest.grpc.io')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('loopback6.unittest.grpc.io')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -259,7 +259,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { - const target = parseUri('loopback46.unittest.grpc.io')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('loopback46.unittest.grpc.io')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -290,7 +290,7 @@ describe('Name Resolver', () => { it('Should resolve a name with a hyphen', done => { /* TODO(murgatroid99): Find or create a better domain name to test this with. * This is just the first one I found with a hyphen. */ - const target = parseUri('network-tools.com')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('network-tools.com')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -311,8 +311,8 @@ describe('Name Resolver', () => { }); it('Should resolve gRPC interop servers', done => { let completeCount = 0; - const target1 = parseUri('grpc-test.sandbox.googleapis.com')!; - const target2 = parseUri('grpc-test4.sandbox.googleapis.com')!; + const target1 = resolverManager.mapUriDefaultScheme(parseUri('grpc-test.sandbox.googleapis.com')!)!; + const target2 = resolverManager.mapUriDefaultScheme(parseUri('grpc-test4.sandbox.googleapis.com')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -339,7 +339,7 @@ describe('Name Resolver', () => { }); describe('UDS Names', () => { it('Should handle a relative Unix Domain Socket name', done => { - const target = parseUri('unix:socket')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('unix:socket')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -363,7 +363,7 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); it('Should handle an absolute Unix Domain Socket name', done => { - const target = parseUri('unix:///tmp/socket')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('unix:///tmp/socket')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -400,7 +400,7 @@ describe('Name Resolver', () => { } it('Should return the correct authority if a different resolver has been registered', () => { - const target = parseUri('other:name')!; + const target = resolverManager.mapUriDefaultScheme(parseUri('other:name')!)!; console.log(target); resolverManager.registerResolver('other', OtherResolver); diff --git a/packages/grpc-js/test/test-uri-parser.ts b/packages/grpc-js/test/test-uri-parser.ts index 75aa82bfe..d04cae539 100644 --- a/packages/grpc-js/test/test-uri-parser.ts +++ b/packages/grpc-js/test/test-uri-parser.ts @@ -17,6 +17,7 @@ import * as assert from 'assert'; import * as uriParser from '../src/uri-parser'; +import * as resolver from '../src/resolver'; describe('URI Parser', function(){ describe('parseUri', function() { @@ -37,6 +38,23 @@ describe('URI Parser', function(){ }); } }); + + describe('parseUri + mapUriDefaultScheme', function() { + const expectationList: {target: string, result: uriParser.GrpcUri | null}[] = [ + {target: 'localhost', result: {scheme: 'dns', authority: undefined, path: 'localhost'}}, + {target: 'localhost:80', result: {scheme: 'dns', authority: undefined, path: 'localhost:80'}}, + {target: 'dns:localhost', result: {scheme: 'dns', authority: undefined, path: 'localhost'}}, + {target: 'dns:///localhost', result: {scheme: 'dns', authority: '', path: 'localhost'}}, + {target: 'dns://authority/localhost', result: {scheme: 'dns', authority: 'authority', path: 'localhost'}}, + {target: 'unix:socket', result: {scheme: 'unix', authority: undefined, path: 'socket'}}, + {target: 'bad:path', result: {scheme: 'dns', authority: undefined, path: 'bad:path'}} + ]; + for (const {target, result} of expectationList) { + it(target, function() { + assert.deepStrictEqual(resolver.mapUriDefaultScheme(uriParser.parseUri(target) ?? {path: 'null'}), result); + }) + } + }); describe('splitHostPort', function() { const expectationList: {path: string, result: uriParser.HostPort | null}[] = [ From 0b522b2289e8cde8263d6e60f61b8e4de6ee0ae5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Apr 2020 10:04:40 -0700 Subject: [PATCH 1037/1899] Bump grpc-js to 1.0.1 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4551d1de8..6a3556359 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.0.0", + "version": "1.0.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From b6846f0709509e77523fa34b539c7840b5d5e83f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Apr 2020 10:32:58 -0700 Subject: [PATCH 1038/1899] Update server to handle default schemes --- packages/grpc-js/src/server.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 95aa68a24..c8b8f2b22 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -45,7 +45,7 @@ import { } from './server-call'; import { ServerCredentials } from './server-credentials'; import { ChannelOptions } from './channel-options'; -import { createResolver, ResolverListener } from './resolver'; +import { createResolver, ResolverListener, mapUriDefaultScheme } from './resolver'; import { log } from './logging'; import { SubchannelAddress, @@ -226,10 +226,14 @@ export class Server { throw new TypeError('callback must be a function'); } - const portUri = parseUri(port); - if (portUri === null) { + const initialPortUri = parseUri(port); + if (initialPortUri === null) { throw new Error(`Could not parse port "${port}"`); } + const portUri = mapUriDefaultScheme(initialPortUri); + if (portUri === null) { + throw new Error(`Could not get a default scheme for port "${port}"`); + } const serverOptions: http2.ServerOptions = {}; if ('grpc.max_concurrent_streams' in this.options) { From e0533363ec4882b33d64e7932d75be392e9320d5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Apr 2020 10:55:06 -0700 Subject: [PATCH 1039/1899] Fix "other" resolver test --- packages/grpc-js/test/test-resolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index d525d97d2..d2a85fc47 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -400,9 +400,9 @@ describe('Name Resolver', () => { } it('Should return the correct authority if a different resolver has been registered', () => { + resolverManager.registerResolver('other', OtherResolver); const target = resolverManager.mapUriDefaultScheme(parseUri('other:name')!)!; console.log(target); - resolverManager.registerResolver('other', OtherResolver); const authority = resolverManager.getDefaultAuthority(target); assert.equal(authority, 'other'); From f7deff3d82497686a76678d92c172eba0e5dff2e Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Wed, 22 Apr 2020 19:25:16 +0100 Subject: [PATCH 1040/1899] grpc-tools: add grpc_js grpc_out param This is a minor change to use the pure JavaScript gRPC Client `@grpc/grpc-js` instead of the (now deprecated `grpc` node package). --- packages/grpc-tools/src/node_generator.cc | 3 ++- packages/grpc-tools/src/node_generator.h | 2 ++ packages/grpc-tools/src/node_plugin.cc | 9 ++++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/grpc-tools/src/node_generator.cc b/packages/grpc-tools/src/node_generator.cc index 77a5abfdb..b4aad0e31 100644 --- a/packages/grpc-tools/src/node_generator.cc +++ b/packages/grpc-tools/src/node_generator.cc @@ -212,7 +212,8 @@ void PrintService(const ServiceDescriptor* service, Printer* out, void PrintImports(const FileDescriptor* file, Printer* out, const Parameters& params) { if (!params.generate_package_definition) { - out->Print("var grpc = require('grpc');\n"); + grpc::string package = params.grpc_js ? "@grpc/grpc-js" : "grpc"; + out->Print("var grpc = require('$package$');\n", "package", package); } if (file->message_type_count() > 0) { grpc::string file_path = diff --git a/packages/grpc-tools/src/node_generator.h b/packages/grpc-tools/src/node_generator.h index c73eca0c1..a88d54a93 100644 --- a/packages/grpc-tools/src/node_generator.h +++ b/packages/grpc-tools/src/node_generator.h @@ -26,6 +26,8 @@ namespace grpc_node_generator { struct Parameters { // Generate a package definition object instead of Client classes bool generate_package_definition; + // Use pure JavaScript gRPC Client + bool grpc_js; }; grpc::string GenerateFile(const grpc::protobuf::FileDescriptor* file, diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index 4ed110818..9f83578b2 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -38,13 +38,16 @@ class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { grpc::string* error) const { grpc_node_generator::Parameters generator_parameters; generator_parameters.generate_package_definition = false; + generator_parameters.grpc_js = false; if (!parameter.empty()) { - std::vector parameters_list = - grpc_generator::tokenize(parameter, ","); - for (auto parameter_string = parameters_list.begin(); + std::vector parameters_list = + grpc_generator::tokenize(parameter, ","); + for (auto parameter_string = parameters_list.begin(); parameter_string != parameters_list.end(); parameter_string++) { if (*parameter_string == "generate_package_definition") { generator_parameters.generate_package_definition = true; + } else if (*parameter_string == "grpc_js") { + generator_parameters.grpc_js = true; } } } From 070994a3a6e7b63a682bcd4d27338d2e0e054c2b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 22 Apr 2020 11:47:48 -0700 Subject: [PATCH 1041/1899] grpc-js: Fix the final proxy bugs --- packages/grpc-js/src/channel-credentials.ts | 3 ++- packages/grpc-js/src/http_proxy.ts | 30 ++++++++++++++------- packages/grpc-js/src/subchannel.ts | 9 ++++--- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index e5c9bfda7..675e91628 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -211,7 +211,8 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { } _getConnectionOptions(): ConnectionOptions | null { - return this.connectionOptions; + // Copy to prevent callers from mutating this.connectionOptions + return { ...this.connectionOptions }; } _isSecure(): boolean { return true; diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 18c0e115b..df9ea09f2 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -147,9 +147,9 @@ export function mapProxyName( extraOptions['grpc.http_connect_creds'] = proxyInfo.creds; } return { - target: { + target: { scheme: 'dns', - path: proxyInfo.address + path: proxyInfo.address, }, extraOptions: extraOptions, }; @@ -207,23 +207,33 @@ export function getProxiedConnection( ' through proxy ' + proxyAddressString ); - resolve({ - socket, - realTarget: parsedTarget, - }); if ('secureContext' in connectionOptions) { /* The proxy is connecting to a TLS server, so upgrade this socket * connection to a TLS connection. * This is a workaround for https://github.com/nodejs/node/issues/32922 * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ - const cts = tls.connect({ - ...connectionOptions, - host: getDefaultAuthority(parsedTarget), + const remoteHost = getDefaultAuthority(parsedTarget); + + const cts = tls.connect( + { + host: remoteHost, + servername: remoteHost, socket: socket, - }, () => { + ...connectionOptions, + }, + () => { + trace( + 'Successfully established a TLS connection to ' + + options.path + + ' through proxy ' + + proxyAddressString + ); resolve({ socket: cts, realTarget: parsedTarget }); } ); + cts.on('error', () => { + reject(); + }); } else { resolve({ socket, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 1691ffd29..2af7885ec 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -322,10 +322,11 @@ export class Subchannel { }; } - connectionOptions = Object.assign( - connectionOptions, - this.subchannelAddress - ); + connectionOptions = { + ...connectionOptions, + ...this.subchannelAddress, + }; + /* http2.connect uses the options here: * https://github.com/nodejs/node/blob/70c32a6d190e2b5d7b9ff9d5b6a459d14e8b7d59/lib/internal/http2/core.js#L3028-L3036 * The spread operator overides earlier values with later ones, so any port From 105e91e2eb38b4d0802029afa5eadf6f3fe205ac Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 22 Apr 2020 12:09:34 -0700 Subject: [PATCH 1042/1899] Bump grpc-js to 1.0.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6a3556359..1b5d2e120 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.0.1", + "version": "1.0.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From ebfc5c95942942b58498373f0860111f405ca144 Mon Sep 17 00:00:00 2001 From: Alexander Fenster Date: Wed, 22 Apr 2020 13:58:26 -0700 Subject: [PATCH 1043/1899] fix: make stream.write() synchronous in server-call --- packages/grpc-js/src/server-call.ts | 10 +++--- .../grpc-js/test/fixtures/test_service.proto | 1 + packages/grpc-js/test/test-server-errors.ts | 33 +++++++++++++++++-- 3 files changed, 36 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index e7377b56b..f7f3f1ff0 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -172,14 +172,14 @@ export class ServerWritableStreamImpl this.call.sendMetadata(responseMetadata); } - async _write( + _write( chunk: ResponseType, encoding: string, // eslint-disable-next-line @typescript-eslint/no-explicit-any callback: (...args: any[]) => void ) { try { - const response = await this.call.serializeMessage(chunk); + const response = this.call.serializeMessage(chunk); if (!this.call.write(response)) { this.call.once('drain', callback); @@ -454,7 +454,7 @@ export class Http2ServerCallStream< resolve(); } - resolve(await this.deserializeMessage(requestBytes)); + resolve(this.deserializeMessage(requestBytes)); } catch (err) { err.code = Status.INTERNAL; this.sendError(err); @@ -476,7 +476,7 @@ export class Http2ServerCallStream< return output; } - async deserializeMessage(bytes: Buffer) { + deserializeMessage(bytes: Buffer) { // TODO(cjihrig): Call compression aware deserializeMessage(). const receivedMessage = bytes.slice(5); @@ -505,7 +505,7 @@ export class Http2ServerCallStream< } try { - const response = await this.serializeMessage(value!); + const response = this.serializeMessage(value!); this.write(response); this.sendStatus({ code: Status.OK, details: 'OK', metadata }); diff --git a/packages/grpc-js/test/fixtures/test_service.proto b/packages/grpc-js/test/fixtures/test_service.proto index db876be98..f99393d14 100644 --- a/packages/grpc-js/test/fixtures/test_service.proto +++ b/packages/grpc-js/test/fixtures/test_service.proto @@ -20,6 +20,7 @@ syntax = "proto3"; message Request { bool error = 1; string message = 2; + int32 errorAfter = 3; } message Response { diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 7c611b9bc..91b7c196c 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -347,11 +347,20 @@ describe('Other conditions', () => { metadata: trailerMetadata, }); } else { - for (let i = 0; i < 5; i++) { + for (let i = 1; i <= 5; i++) { stream.write({ count: i }); + if (req.errorAfter && req.errorAfter === i) { + stream.emit('error', { + code: grpc.status.UNKNOWN, + details: req.message || 'Requested error', + metadata: trailerMetadata, + }); + break; + } + } + if (!req.errorAfter) { + stream.end(trailerMetadata); } - - stream.end(trailerMetadata); } }, @@ -712,6 +721,24 @@ describe('Other conditions', () => { ); }); }); + + describe('should handle server stream errors correctly', () => { + it('should emit data for all messages before error', (done) => { + const expectedDataCount = 2; + const call = client.serverStream({ errorAfter: expectedDataCount }); + + let actualDataCount = 0; + call.on('data', () => { + ++actualDataCount; + }); + call.on('error', (error: ServiceError) => { + assert.strictEqual(error.code, grpc.status.UNKNOWN); + assert.strictEqual(error.details, 'Requested error'); + assert.strictEqual(actualDataCount, expectedDataCount); + done(); + }); + }); + }); }); function identity(arg: any): any { From f238bef70dea95a7a520a883b8c2bad83895194f Mon Sep 17 00:00:00 2001 From: Matthew Douglass <5410142+mdouglass@users.noreply.github.com> Date: Wed, 22 Apr 2020 22:02:20 -0700 Subject: [PATCH 1044/1899] Export MetadataValue as part of the public API #1383 Matches native gRPC library --- packages/grpc-js/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e7961cdab..6263a9cb4 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -45,7 +45,7 @@ import { Serialize, ServiceDefinition, } from './make-client'; -import { Metadata } from './metadata'; +import { Metadata, MetadataValue } from './metadata'; import { Server, UntypedHandleCall, @@ -188,7 +188,7 @@ export const credentials = mixin( /**** Metadata ****/ -export { Metadata }; +export { Metadata, MetadataValue }; /**** Constants ****/ From 9da6843ed7354c7f219dd06432ab90502eca0719 Mon Sep 17 00:00:00 2001 From: Matthew Douglass <5410142+mdouglass@users.noreply.github.com> Date: Wed, 22 Apr 2020 22:18:05 -0700 Subject: [PATCH 1045/1899] Expose metadata property from ServerSurfaceCall #1384 --- packages/grpc-js/src/server-call.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index f7f3f1ff0..fc456fda8 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -63,6 +63,7 @@ export type ServerErrorResponse = ServerStatusResponse & Error; export type ServerSurfaceCall = { cancelled: boolean; + readonly metadata: Metadata getPeer(): string; sendMetadata(responseMetadata: Metadata): void; } & EventEmitter; From 9bd0864c31ae198c41966aacb64819acdba037a3 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Thu, 23 Apr 2020 07:32:21 +0100 Subject: [PATCH 1046/1899] grpc-js: fix target in tracing logs --- packages/grpc-js/src/channel.ts | 4 ++-- packages/grpc-js/src/http_proxy.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 12 ++++++------ packages/grpc-js/src/resolving-load-balancer.ts | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 764c7a699..f2a7bc09d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -406,7 +406,7 @@ export class ChannelImplementation implements Channel { trace( LogVerbosity.DEBUG, 'connectivity_state', - this.target + + uriToString(this.target) + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + @@ -496,7 +496,7 @@ export class ChannelImplementation implements Channel { trace( LogVerbosity.DEBUG, 'channel', - this.target + + uriToString(this.target) + ' createCall [' + callNumber + '] method="' + diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index df9ea09f2..7521916a2 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -136,7 +136,7 @@ export function mapProxyName( const serverHost = hostPort.host; for (const host of getNoProxyHostList()) { if (host === serverHost) { - trace('Not using proxy for target in no_proxy list: ' + target); + trace('Not using proxy for target in no_proxy list: ' + uriToString(target)); return noProxyResult; } } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 1e84fe9bd..274d8c34e 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -111,7 +111,7 @@ class DnsResolver implements Resolver { this.defaultResolutionError = { code: Status.UNAVAILABLE, - details: `Name resolution failed for target ${this.target}`, + details: `Name resolution failed for target ${uriToString(this.target)}`, metadata: new Metadata(), }; } @@ -122,7 +122,7 @@ class DnsResolver implements Resolver { */ private startResolution() { if (this.ipResult !== null) { - trace('Returning IP address for target ' + this.target); + trace('Returning IP address for target ' + uriToString(this.target)); setImmediate(() => { this.listener.onSuccessfulResolution(this.ipResult!, null, null); }); @@ -132,7 +132,7 @@ class DnsResolver implements Resolver { setImmediate(() => { this.listener.onError({ code: Status.UNAVAILABLE, - details: `Failed to parse DNS address ${this.target}`, + details: `Failed to parse DNS address ${uriToString(this.target)}`, metadata: new Metadata(), }); }); @@ -171,7 +171,7 @@ class DnsResolver implements Resolver { ']'; trace( 'Resolved addresses for target ' + - this.target + + uriToString(this.target) + ': ' + allAddressesString ); @@ -192,7 +192,7 @@ class DnsResolver implements Resolver { (err) => { trace( 'Resolution error for target ' + - this.target + + uriToString(this.target) + ': ' + (err as Error).message ); @@ -254,7 +254,7 @@ class DnsResolver implements Resolver { } updateResolution() { - trace('Resolution update requested for target ' + this.target); + trace('Resolution update requested for target ' + uriToString(this.target)); if (this.pendingLookupPromise === null) { this.startResolution(); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 0720e7c02..48f1ddd45 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -35,7 +35,7 @@ import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; import { SubchannelAddress } from './subchannel'; -import { GrpcUri } from './uri-parser'; +import { GrpcUri, uriToString } from './uri-parser'; const TRACER_NAME = 'resolving_load_balancer'; @@ -353,7 +353,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { private updateState(connectivitystate: ConnectivityState, picker: Picker) { trace( - this.target + + uriToString(this.target) + ' ' + ConnectivityState[this.currentState] + ' -> ' + From bf98da0e8d1fecefcbd33eb44d70165e0efa2bcb Mon Sep 17 00:00:00 2001 From: Matthew Douglass <5410142+mdouglass@users.noreply.github.com> Date: Thu, 23 Apr 2020 12:00:36 -0700 Subject: [PATCH 1047/1899] Export sendUnaryData as part of the public API #1389 --- packages/grpc-js/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e7961cdab..f525ee2b8 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -57,6 +57,7 @@ import { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall, + sendUnaryData, ServerUnaryCall, ServerReadableStream, ServerWritableStream, @@ -228,6 +229,7 @@ export const waitForClientReady = ( /* Interfaces */ export { + sendUnaryData, ChannelCredentials, CallCredentials, Deadline, From cf0a90f9da50a1c4663d11786dec61ee7db1586a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Apr 2020 14:17:07 -0700 Subject: [PATCH 1048/1899] grpc-js: don't destroyHttp2Stream before saving the status code --- packages/grpc-js/src/call-stream.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 9ceebdbfb..ca3049e7e 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -249,7 +249,6 @@ export class Http2CallStream implements Call { * @param status The status of the call. */ private endCall(status: StatusObject): void { - this.destroyHttp2Stream(); /* If the status is OK and a new status comes in (e.g. from a * deserialization failure), that new status takes priority */ if (this.finalStatus === null || this.finalStatus.code === Status.OK) { @@ -263,6 +262,7 @@ export class Http2CallStream implements Call { this.finalStatus = status; this.maybeOutputStatus(); } + this.destroyHttp2Stream(); } private maybeOutputStatus() { @@ -467,7 +467,6 @@ export class Http2CallStream implements Call { const finalMetadata = this.filterStack.receiveMetadata(metadata); this.listener!.onReceiveMetadata(finalMetadata); } catch (error) { - this.destroyHttp2Stream(); this.endCall({ code: Status.UNKNOWN, details: error.message, @@ -588,7 +587,6 @@ export class Http2CallStream implements Call { this.trace( 'cancelWithStatus code: ' + status + ' details: "' + details + '"' ); - this.destroyHttp2Stream(); this.endCall({ code: status, details, metadata: new Metadata() }); } From f20c8e371bf2a36fa3d125a5b6ce3b5f3454561c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Apr 2020 10:13:17 -0700 Subject: [PATCH 1049/1899] Bump grpc-js to 1.0.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 1b5d2e120..31a3dddae 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.0.2", + "version": "1.0.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 05d7fa38c8774e9d408fab349639bf4c04228081 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Apr 2020 10:40:14 -0700 Subject: [PATCH 1050/1899] grpc-js: Don't try to call listener if it is unset --- packages/grpc-js/src/call-stream.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index ca3049e7e..11f9adc05 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -227,7 +227,7 @@ export class Http2CallStream implements Call { const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! ); - this.listener!.onReceiveStatus(filteredStatus); + this.listener?.onReceiveStatus(filteredStatus); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -289,7 +289,7 @@ export class Http2CallStream implements Call { ); this.canPush = false; process.nextTick(() => { - this.listener!.onReceiveMessage(message); + this.listener?.onReceiveMessage(message); this.maybeOutputStatus(); }); } @@ -465,7 +465,7 @@ export class Http2CallStream implements Call { } try { const finalMetadata = this.filterStack.receiveMetadata(metadata); - this.listener!.onReceiveMetadata(finalMetadata); + this.listener?.onReceiveMetadata(finalMetadata); } catch (error) { this.endCall({ code: Status.UNKNOWN, From 08dd1149518de14159b554347cbb0818db09ae39 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Apr 2020 11:34:26 -0700 Subject: [PATCH 1051/1899] grpc-js: Add attributes argument passed from resolver to load balancer --- packages/grpc-js/src/load-balancer.ts | 3 ++- packages/grpc-js/src/resolver-dns.ts | 11 +++++++---- packages/grpc-js/src/resolver-uds.ts | 3 ++- packages/grpc-js/src/resolver.ts | 3 ++- packages/grpc-js/src/resolving-load-balancer.ts | 12 ++++++++---- 5 files changed, 21 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 5fa4bdc53..b17104676 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -67,7 +67,8 @@ export interface LoadBalancer { */ updateAddressList( addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig | null + lbConfig: LoadBalancingConfig | null, + attributes: {[key: string]: unknown} ): void; /** * If the load balancer is currently in the IDLE state, start connecting. diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 274d8c34e..016f3bd1a 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -124,7 +124,7 @@ class DnsResolver implements Resolver { if (this.ipResult !== null) { trace('Returning IP address for target ' + uriToString(this.target)); setImmediate(() => { - this.listener.onSuccessfulResolution(this.ipResult!, null, null); + this.listener.onSuccessfulResolution(this.ipResult!, null, null, {}); }); return; } @@ -186,7 +186,8 @@ class DnsResolver implements Resolver { this.listener.onSuccessfulResolution( this.latestLookupResult, this.latestServiceConfig, - this.latestServiceConfigError + this.latestServiceConfigError, + {} ); }, (err) => { @@ -230,7 +231,8 @@ class DnsResolver implements Resolver { this.listener.onSuccessfulResolution( this.latestLookupResult, this.latestServiceConfig, - this.latestServiceConfigError + this.latestServiceConfigError, + {} ); } }, @@ -244,7 +246,8 @@ class DnsResolver implements Resolver { this.listener.onSuccessfulResolution( this.latestLookupResult, this.latestServiceConfig, - this.latestServiceConfigError + this.latestServiceConfigError, + {} ); } } diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 759cb233e..0bc929916 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -38,7 +38,8 @@ class UdsResolver implements Resolver { this.listener.onSuccessfulResolution, this.addresses, null, - null + null, + {} ); } diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 7d6d1ad5a..cef0c1f48 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -39,7 +39,8 @@ export interface ResolverListener { onSuccessfulResolution( addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, - serviceConfigError: StatusObject | null + serviceConfigError: StatusObject | null, + attributes: {[key: string]: unknown} ): void; /** * Called whenever a name resolution attempt fails. diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 48f1ddd45..75ea6eaac 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -136,7 +136,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { onSuccessfulResolution: ( addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, - serviceConfigError: ServiceError | null + serviceConfigError: ServiceError | null, + attributes: {[key: string]: unknown} ) => { let workingServiceConfig: ServiceConfig | null = null; /* This first group of conditionals implements the algorithm described @@ -211,12 +212,14 @@ export class ResolvingLoadBalancer implements LoadBalancer { )!; this.innerLoadBalancer.updateAddressList( addressList, - loadBalancingConfig + loadBalancingConfig, + attributes ); } else if (this.innerLoadBalancer.getTypeName() === loadBalancerName) { this.innerLoadBalancer.updateAddressList( addressList, - loadBalancingConfig + loadBalancingConfig, + attributes ); } else { if ( @@ -234,7 +237,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { } this.pendingReplacementLoadBalancer.updateAddressList( addressList, - loadBalancingConfig + loadBalancingConfig, + attributes ); } }, From 3d4a27e6cc3f19ae660a076b63077942721f8441 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Apr 2020 14:00:54 -0700 Subject: [PATCH 1052/1899] Plumb through an extra filter from the load balancer to the call stream --- packages/grpc-js/src/call-stream.ts | 10 +++++++--- packages/grpc-js/src/channel.ts | 3 ++- packages/grpc-js/src/picker.ts | 12 ++++++++++++ packages/grpc-js/src/subchannel.ts | 5 +++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index ca3049e7e..3a8533159 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -19,8 +19,8 @@ import * as http2 from 'http2'; import { CallCredentials } from './call-credentials'; import { Status } from './constants'; -import { Filter } from './filter'; -import { FilterStackFactory } from './filter-stack'; +import { Filter, FilterFactory } from './filter'; +import { FilterStackFactory, FilterStack } from './filter-stack'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; import { ChannelImplementation } from './channel'; @@ -407,8 +407,12 @@ export class Http2CallStream implements Call { attachHttp2Stream( stream: http2.ClientHttp2Stream, - subchannel: Subchannel + subchannel: Subchannel, + extraFilterFactory?: FilterFactory ): void { + if (extraFilterFactory !== undefined) { + this.filterStack = new FilterStack([this.filterStack, extraFilterFactory.createFilter(this)]); + } if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f2a7bc09d..f4df2fce9 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -300,7 +300,8 @@ export class ChannelImplementation implements Channel { try { pickResult.subchannel!.startCallStream( finalMetadata, - callStream + callStream, + pickResult.extraFilterFactory ?? undefined ); } catch (error) { if ( diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index d908f0261..9470f1222 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -20,6 +20,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import { Status } from './constants'; import { LoadBalancer } from './load-balancer'; +import { FilterFactory, Filter } from './filter'; export enum PickResultType { COMPLETE, @@ -40,24 +41,33 @@ export interface PickResult { * `pickResultType` is TRANSIENT_FAILURE. */ status: StatusObject | null; + /** + * Extra FilterFactory (can be multiple encapsulated in a FilterStackFactory) + * provided by the load balancer to be used with the call. For technical + * reasons filters from this factory will not see sendMetadata events. + */ + extraFilterFactory: FilterFactory | null; } export interface CompletePickResult extends PickResult { pickResultType: PickResultType.COMPLETE; subchannel: Subchannel | null; status: null; + extraFilterFactory: FilterFactory | null; } export interface QueuePickResult extends PickResult { pickResultType: PickResultType.QUEUE; subchannel: null; status: null; + extraFilterFactory: null; } export interface TransientFailurePickResult extends PickResult { pickResultType: PickResultType.TRANSIENT_FAILURE; subchannel: null; status: StatusObject; + extraFilterFactory: null; } export interface PickArgs { @@ -95,6 +105,7 @@ export class UnavailablePicker implements Picker { pickResultType: PickResultType.TRANSIENT_FAILURE, subchannel: null, status: this.status, + extraFilterFactory: null }; } } @@ -122,6 +133,7 @@ export class QueuePicker { pickResultType: PickResultType.QUEUE, subchannel: null, status: null, + extraFilterFactory: null }; } } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 2af7885ec..713f0d9ad 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -30,6 +30,7 @@ import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; import { GrpcUri } from './uri-parser'; import { ConnectionOptions } from 'tls'; +import { FilterFactory, Filter } from './filter'; const clientVersion = require('../../package.json').version; @@ -619,7 +620,7 @@ export class Subchannel { * @param metadata * @param callStream */ - startCallStream(metadata: Metadata, callStream: Http2CallStream) { + startCallStream(metadata: Metadata, callStream: Http2CallStream, extraFilterFactory?: FilterFactory) { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; @@ -633,7 +634,7 @@ export class Subchannel { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } trace('Starting stream with headers\n' + headersString); - callStream.attachHttp2Stream(http2Stream, this); + callStream.attachHttp2Stream(http2Stream, this, extraFilterFactory); } /** From 424c9bfe70601cccb0698341b95fa6b6a9d29283 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Apr 2020 10:24:15 -0700 Subject: [PATCH 1053/1899] Add onCallStarted field to Pick object --- packages/grpc-js/src/channel.ts | 3 +++ packages/grpc-js/src/load-balancer-pick-first.ts | 2 ++ packages/grpc-js/src/load-balancer-round-robin.ts | 2 ++ packages/grpc-js/src/picker.ts | 10 ++++++++-- 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f4df2fce9..b240cc439 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -303,6 +303,9 @@ export class ChannelImplementation implements Channel { callStream, pickResult.extraFilterFactory ?? undefined ); + /* If we reach this point, the call stream has started + * successfully */ + pickResult.onCallStarted?.(); } catch (error) { if ( (error as NodeJS.ErrnoException).code === diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 6b9756fff..6289123dc 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -65,6 +65,8 @@ class PickFirstPicker implements Picker { pickResultType: PickResultType.COMPLETE, subchannel: this.subchannel, status: null, + extraFilterFactory: null, + onCallStarted: null }; } } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 93c64610c..512443416 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -60,6 +60,8 @@ class RoundRobinPicker implements Picker { pickResultType: PickResultType.COMPLETE, subchannel: pickedSubchannel, status: null, + extraFilterFactory: null, + onCallStarted: null, }; } diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 9470f1222..306ac3ede 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -47,6 +47,7 @@ export interface PickResult { * reasons filters from this factory will not see sendMetadata events. */ extraFilterFactory: FilterFactory | null; + onCallStarted: (() => void) | null; } export interface CompletePickResult extends PickResult { @@ -54,6 +55,7 @@ export interface CompletePickResult extends PickResult { subchannel: Subchannel | null; status: null; extraFilterFactory: FilterFactory | null; + onCallStarted: (() => void) | null; } export interface QueuePickResult extends PickResult { @@ -61,6 +63,7 @@ export interface QueuePickResult extends PickResult { subchannel: null; status: null; extraFilterFactory: null; + onCallStarted: null; } export interface TransientFailurePickResult extends PickResult { @@ -68,6 +71,7 @@ export interface TransientFailurePickResult extends PickResult { subchannel: null; status: StatusObject; extraFilterFactory: null; + onCallStarted: null; } export interface PickArgs { @@ -105,7 +109,8 @@ export class UnavailablePicker implements Picker { pickResultType: PickResultType.TRANSIENT_FAILURE, subchannel: null, status: this.status, - extraFilterFactory: null + extraFilterFactory: null, + onCallStarted: null }; } } @@ -133,7 +138,8 @@ export class QueuePicker { pickResultType: PickResultType.QUEUE, subchannel: null, status: null, - extraFilterFactory: null + extraFilterFactory: null, + onCallStarted: null }; } } From a2839e7b2d3515995641054e787657b8b442dafa Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Apr 2020 11:56:49 -0700 Subject: [PATCH 1054/1899] gts fix --- packages/grpc-js/src/call-stream.ts | 5 ++++- packages/grpc-js/src/channel.ts | 4 +++- packages/grpc-js/src/load-balancer-pick-first.ts | 2 +- packages/grpc-js/src/load-balancer.ts | 2 +- packages/grpc-js/src/picker.ts | 4 ++-- packages/grpc-js/src/resolver-uds.ts | 6 +----- packages/grpc-js/src/resolver.ts | 4 ++-- packages/grpc-js/src/resolving-load-balancer.ts | 2 +- packages/grpc-js/src/subchannel.ts | 6 +++++- 9 files changed, 20 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 3a8533159..57dc3bde1 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -411,7 +411,10 @@ export class Http2CallStream implements Call { extraFilterFactory?: FilterFactory ): void { if (extraFilterFactory !== undefined) { - this.filterStack = new FilterStack([this.filterStack, extraFilterFactory.createFilter(this)]); + this.filterStack = new FilterStack([ + this.filterStack, + extraFilterFactory.createFilter(this), + ]); } if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index b240cc439..fe85dec04 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -174,7 +174,9 @@ export class ChannelImplementation implements Channel { * resolver */ const defaultSchemeMapResult = mapUriDefaultScheme(originalTargetUri); if (defaultSchemeMapResult === null) { - throw new Error(`Could not find a default scheme for target name "${target}"`); + throw new Error( + `Could not find a default scheme for target name "${target}"` + ); } if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 6289123dc..f38886188 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -66,7 +66,7 @@ class PickFirstPicker implements Picker { subchannel: this.subchannel, status: null, extraFilterFactory: null, - onCallStarted: null + onCallStarted: null, }; } } diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index b17104676..a5a22b56e 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -68,7 +68,7 @@ export interface LoadBalancer { updateAddressList( addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null, - attributes: {[key: string]: unknown} + attributes: { [key: string]: unknown } ): void; /** * If the load balancer is currently in the IDLE state, start connecting. diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 306ac3ede..42eeda821 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -110,7 +110,7 @@ export class UnavailablePicker implements Picker { subchannel: null, status: this.status, extraFilterFactory: null, - onCallStarted: null + onCallStarted: null, }; } } @@ -139,7 +139,7 @@ export class QueuePicker { subchannel: null, status: null, extraFilterFactory: null, - onCallStarted: null + onCallStarted: null, }; } } diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 0bc929916..258569138 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -14,11 +14,7 @@ * limitations under the License. */ -import { - Resolver, - ResolverListener, - registerResolver, -} from './resolver'; +import { Resolver, ResolverListener, registerResolver } from './resolver'; import { SubchannelAddress } from './subchannel'; import { GrpcUri } from './uri-parser'; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index cef0c1f48..16c843517 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -40,7 +40,7 @@ export interface ResolverListener { addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null, - attributes: {[key: string]: unknown} + attributes: { [key: string]: unknown } ): void; /** * Called whenever a name resolution attempt fails. @@ -138,7 +138,7 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { return { scheme: defaultScheme, authority: undefined, - path: uriToString(target) + path: uriToString(target), }; } else { return null; diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 75ea6eaac..f3e2eda3e 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -137,7 +137,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null, - attributes: {[key: string]: unknown} + attributes: { [key: string]: unknown } ) => { let workingServiceConfig: ServiceConfig | null = null; /* This first group of conditionals implements the algorithm described diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 713f0d9ad..ab7b176ce 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -620,7 +620,11 @@ export class Subchannel { * @param metadata * @param callStream */ - startCallStream(metadata: Metadata, callStream: Http2CallStream, extraFilterFactory?: FilterFactory) { + startCallStream( + metadata: Metadata, + callStream: Http2CallStream, + extraFilterFactory?: FilterFactory + ) { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; From 010ef569f7f83007642f3f69e0ce13dee615d680 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Apr 2020 15:35:32 -0700 Subject: [PATCH 1055/1899] grpc-js: Add internal "Google default" channel credentials --- packages/grpc-js/package.json | 1 + packages/grpc-js/src/call-credentials.ts | 70 +++++++++++++++++++++ packages/grpc-js/src/channel-credentials.ts | 9 +++ packages/grpc-js/src/index.ts | 66 ++----------------- 4 files changed, 84 insertions(+), 62 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 31a3dddae..3ca7b8f5c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -55,6 +55,7 @@ "posttest": "npm run check" }, "dependencies": { + "google-auth-library": "^6.0.0", "semver": "^6.2.0" }, "files": [ diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index 40a26fecc..bbc88a895 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -26,6 +26,35 @@ export type CallMetadataGenerator = ( cb: (err: Error | null, metadata?: Metadata) => void ) => void; +// google-auth-library pre-v2.0.0 does not have getRequestHeaders +// but has getRequestMetadata, which is deprecated in v2.0.0 +export interface OldOAuth2Client { + getRequestMetadata: ( + url: string, + callback: ( + err: Error | null, + headers?: { + [index: string]: string; + } + ) => void + ) => void; +} + +export interface CurrentOAuth2Client { + getRequestHeaders: (url?: string) => Promise<{ [index: string]: string }>; +} + +export type OAuth2Client = OldOAuth2Client | CurrentOAuth2Client; + +function isCurrentOauth2Client( + client: OAuth2Client +): client is CurrentOAuth2Client { + return ( + 'getRequestHeaders' in client && + typeof client.getRequestHeaders === 'function' + ); +} + /** * A class that represents a generic method of adding authentication-related * metadata on a per-request basis. @@ -65,6 +94,47 @@ export abstract class CallCredentials { return new SingleCallCredentials(metadataGenerator); } + /** + * Create a gRPC credential from a Google credential object. + * @param googleCredentials The authentication client to use. + * @return The resulting CallCredentials object. + */ + static createFromGoogleCredential( + googleCredentials: OAuth2Client + ): CallCredentials { + return CallCredentials.createFromMetadataGenerator((options, callback) => { + let getHeaders: Promise<{ [index: string]: string }>; + if (isCurrentOauth2Client(googleCredentials)) { + getHeaders = googleCredentials.getRequestHeaders(options.service_url); + } else { + getHeaders = new Promise((resolve, reject) => { + googleCredentials.getRequestMetadata( + options.service_url, + (err, headers) => { + if (err) { + reject(err); + return; + } + resolve(headers); + } + ); + }); + } + getHeaders.then( + (headers) => { + const metadata = new Metadata(); + for (const key of Object.keys(headers)) { + metadata.add(key, headers[key]); + } + callback(null, metadata); + }, + (err) => { + callback(err); + } + ); + }); + } + static createEmpty(): CallCredentials { return new EmptyCallCredentials(); } diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 675e91628..b2b69262c 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -19,6 +19,7 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; +import { GoogleAuth } from 'google-auth-library'; // eslint-disable-next-line @typescript-eslint/no-explicit-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -278,3 +279,11 @@ class ComposedChannelCredentialsImpl extends ChannelCredentials { } } } + +export function createGoogleDefaultCredentials(): ChannelCredentials { + const sslCreds = ChannelCredentials.createSsl(); + const googleAuthCreds = CallCredentials.createFromGoogleCredential( + new GoogleAuth() + ); + return sslCreds.compose(googleAuthCreds); +} diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 2e1d521a8..54a407cda 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -24,7 +24,7 @@ import { ClientWritableStream, ServiceError, } from './call'; -import { CallCredentials } from './call-credentials'; +import { CallCredentials, OAuth2Client } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ConnectivityState, ChannelImplementation } from './channel'; import { ChannelCredentials } from './channel-credentials'; @@ -33,7 +33,7 @@ import { Client, CallInvocationTransformer, CallProperties, - UnaryCallback + UnaryCallback, } from './client'; import { LogVerbosity, Status } from './constants'; import * as logging from './logging'; @@ -87,71 +87,13 @@ function mixin(...sources: IndexedObject[]) { return result; } -export interface OAuth2Client { - getRequestMetadata: ( - url: string, - callback: ( - err: Error | null, - headers?: { - [index: string]: string; - } - ) => void - ) => void; - getRequestHeaders: (url?: string) => Promise<{ [index: string]: string }>; -} +export { OAuth2Client }; /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want export const credentials = mixin( { - /** - * Create a gRPC credential from a Google credential object. - * @param googleCredentials The authentication client to use. - * @return The resulting CallCredentials object. - */ - createFromGoogleCredential: ( - googleCredentials: OAuth2Client - ): CallCredentials => { - return CallCredentials.createFromMetadataGenerator( - (options, callback) => { - // google-auth-library pre-v2.0.0 does not have getRequestHeaders - // but has getRequestMetadata, which is deprecated in v2.0.0 - let getHeaders: Promise<{ [index: string]: string }>; - if (typeof googleCredentials.getRequestHeaders === 'function') { - getHeaders = googleCredentials.getRequestHeaders( - options.service_url - ); - } else { - getHeaders = new Promise((resolve, reject) => { - googleCredentials.getRequestMetadata( - options.service_url, - (err, headers) => { - if (err) { - reject(err); - return; - } - resolve(headers); - } - ); - }); - } - getHeaders.then( - (headers) => { - const metadata = new Metadata(); - for (const key of Object.keys(headers)) { - metadata.add(key, headers[key]); - } - callback(null, metadata); - }, - (err) => { - callback(err); - } - ); - } - ); - }, - /** * Combine a ChannelCredentials with any number of CallCredentials into a * single ChannelCredentials object. @@ -211,7 +153,7 @@ export { CallInvocationTransformer, ChannelImplementation as Channel, Channel as ChannelInterface, - UnaryCallback as requestCallback + UnaryCallback as requestCallback, }; /** From cefb8d1f62857f2884196e747226a27788fa604e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Apr 2020 17:35:20 -0700 Subject: [PATCH 1056/1899] Load 'google-auth-library' lazily to avoid impacting load times --- packages/grpc-js/src/channel-credentials.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index b2b69262c..aadf638b3 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -19,7 +19,7 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; -import { GoogleAuth } from 'google-auth-library'; +import { GoogleAuth as GoogleAuthType } from 'google-auth-library'; // eslint-disable-next-line @typescript-eslint/no-explicit-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -281,6 +281,8 @@ class ComposedChannelCredentialsImpl extends ChannelCredentials { } export function createGoogleDefaultCredentials(): ChannelCredentials { + const GoogleAuth = require('google-auth-library') + .GoogleAuth as typeof GoogleAuthType; const sslCreds = ChannelCredentials.createSsl(); const googleAuthCreds = CallCredentials.createFromGoogleCredential( new GoogleAuth() From 90013c695d2b8a53054641ac79a9062720fcaf39 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 4 May 2020 14:03:17 -0700 Subject: [PATCH 1057/1899] grpc-js: Add ChildLoadBalancerHandler and use it in ResolvingLoadBalancer --- .../src/load-balancer-child-handler.ts | 137 ++++++++ .../grpc-js/src/load-balancer-pick-first.ts | 6 +- .../grpc-js/src/load-balancer-round-robin.ts | 7 +- packages/grpc-js/src/load-balancer.ts | 14 +- packages/grpc-js/src/load-balancing-config.ts | 72 +++- .../grpc-js/src/resolving-load-balancer.ts | 312 +++--------------- 6 files changed, 266 insertions(+), 282 deletions(-) create mode 100644 packages/grpc-js/src/load-balancer-child-handler.ts diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts new file mode 100644 index 000000000..bb1bf0215 --- /dev/null +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -0,0 +1,137 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + createLoadBalancer, +} from './load-balancer'; +import { + SubchannelAddress, + Subchannel, +} from './subchannel'; +import { LoadBalancingConfig } from './load-balancing-config'; +import { ChannelOptions } from './channel-options'; +import { ConnectivityState } from './channel'; +import { Picker } from './picker'; + +const TYPE_NAME = 'child_load_balancer_helper'; + +export class ChildLoadBalancerHandler implements LoadBalancer { + private currentChild: LoadBalancer | null = null; + private pendingChild: LoadBalancer | null = null; + + private ChildPolicyHelper = class { + private child: LoadBalancer | null = null; + constructor(private parent: ChildLoadBalancerHandler) {} + createSubchannel(subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions): Subchannel { + return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + } + updateState(connectivityState: ConnectivityState, picker: Picker): void { + if (this.calledByPendingChild()) { + if (connectivityState !== ConnectivityState.READY) { + return; + } + this.parent.currentChild?.destroy(); + this.parent.currentChild = this.parent.pendingChild; + this.parent.pendingChild = null; + } else if (!this.calledByCurrentChild()) { + return; + } + this.parent.channelControlHelper.updateState(connectivityState, picker); + } + requestReresolution(): void { + const latestChild = this.parent.pendingChild ?? this.parent.currentChild; + if (this.child === latestChild) { + this.parent.channelControlHelper.requestReresolution(); + } + } + setChild(newChild: LoadBalancer) { + this.child = newChild; + } + private calledByPendingChild(): boolean { + return this.child === this.parent.pendingChild; + } + private calledByCurrentChild(): boolean { + return this.child === this.parent.currentChild; + } + } + + constructor(private readonly channelControlHelper: ChannelControlHelper) {} + + /** + * Prerequisites: lbConfig !== null and lbConfig.name is registered + * @param addressList + * @param lbConfig + * @param attributes + */ + updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null, attributes: { [key: string]: unknown; }): void { + if (lbConfig === null) { + return; + } + let childToUpdate: LoadBalancer; + if (this.currentChild === null || this.currentChild.getTypeName() !== lbConfig.name) { + const newHelper = new this.ChildPolicyHelper(this); + const newChild = createLoadBalancer(lbConfig.name, newHelper)!; + newHelper.setChild(newChild); + if (this.currentChild === null) { + this.currentChild = newChild; + childToUpdate = this.currentChild; + } else { + if (this.pendingChild) { + this.pendingChild.destroy(); + } + this.pendingChild = newChild; + childToUpdate = this.pendingChild; + } + } else { + if (this.pendingChild === null) { + childToUpdate = this.currentChild; + } else { + childToUpdate = this.pendingChild; + } + } + childToUpdate.updateAddressList(addressList, lbConfig, attributes); + } + exitIdle(): void { + if (this.currentChild) { + this.currentChild.resetBackoff(); + if (this.pendingChild) { + this.pendingChild.resetBackoff(); + } + } + } + resetBackoff(): void { + if (this.currentChild) { + this.currentChild.resetBackoff(); + if (this.pendingChild) { + this.pendingChild.resetBackoff(); + } + } + } + destroy(): void { + if (this.currentChild) { + this.currentChild.destroy(); + } + if (this.pendingChild) { + this.pendingChild.destroy(); + } + } + getTypeName(): string { + return TYPE_NAME; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index f38886188..a15b0a190 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -129,7 +129,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { * @param channelControlHelper `ChannelControlHelper` instance provided by * this load balancer's owner. */ - constructor(private channelControlHelper: ChannelControlHelper) { + constructor(private readonly channelControlHelper: ChannelControlHelper) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.subchannelStateCounts = { [ConnectivityState.CONNECTING]: 0, @@ -435,10 +435,6 @@ export class PickFirstLoadBalancer implements LoadBalancer { getTypeName(): string { return TYPE_NAME; } - - replaceChannelControlHelper(channelControlHelper: ChannelControlHelper) { - this.channelControlHelper = channelControlHelper; - } } export function setup(): void { diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 512443416..b52751e9a 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -94,7 +94,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { private currentReadyPicker: RoundRobinPicker | null = null; - constructor(private channelControlHelper: ChannelControlHelper) { + constructor(private readonly channelControlHelper: ChannelControlHelper) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.subchannelStateCounts = { [ConnectivityState.CONNECTING]: 0, @@ -229,11 +229,6 @@ export class RoundRobinLoadBalancer implements LoadBalancer { getTypeName(): string { return TYPE_NAME; } - replaceChannelControlHelper( - channelControlHelper: ChannelControlHelper - ): void { - this.channelControlHelper = channelControlHelper; - } } export function setup() { diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index a5a22b56e..160723d5e 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -91,11 +91,6 @@ export interface LoadBalancer { * balancer implementation class was registered with. */ getTypeName(): string; - /** - * Replace the existing ChannelControlHelper with a new one - * @param channelControlHelper The new ChannelControlHelper to use from now on - */ - replaceChannelControlHelper(channelControlHelper: ChannelControlHelper): void; } export interface LoadBalancerConstructor { @@ -128,6 +123,15 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; } +export function getFirstUsableConfig(configs: LoadBalancingConfig[]): LoadBalancingConfig | null { + for (const config of configs) { + if (config.name in registeredLoadBalancerTypes) { + return config; + } + } + return null; +} + export function registerAll() { load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index eef025e60..0c6048f43 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -25,6 +25,8 @@ * runtime */ /* eslint-disable @typescript-eslint/no-explicit-any */ +export type PickFirstConfig = {}; + export type RoundRobinConfig = {}; export interface XdsConfig { @@ -37,13 +39,58 @@ export interface GrpcLbConfig { childPolicy: LoadBalancingConfig[]; } -export interface LoadBalancingConfig { - /* Exactly one of these must be set for a config to be valid */ - round_robin?: RoundRobinConfig; - xds?: XdsConfig; - grpclb?: GrpcLbConfig; +export interface PriorityChild { + config: LoadBalancingConfig[]; +} + +export interface PriorityLbConfig { + children: Map; + priorities: string[]; +} + +export interface PickFirstLoadBalancingConfig { + name: 'pick_first'; + pick_first: PickFirstConfig; +} + +export interface RoundRobinLoadBalancingConfig { + name: 'round_robin'; + round_robin: RoundRobinConfig; +} + +export interface XdsLoadBalancingConfig { + name: 'xds'; + xds: XdsConfig; +} + +export interface GrpcLbLoadBalancingConfig { + name: 'grpclb'; + grpclb: GrpcLbConfig; } +export interface PriorityLoadBalancingConfig { + name: 'priority'; + priority: PriorityLbConfig; +} + +export type LoadBalancingConfig = PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig | XdsLoadBalancingConfig | GrpcLbLoadBalancingConfig | PriorityLoadBalancingConfig; + +export function isRoundRobinLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is RoundRobinLoadBalancingConfig { + return lbconfig.name === 'round_robin'; +} + +export function isXdsLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is XdsLoadBalancingConfig { + return lbconfig.name === 'xds'; +} + +export function isGrpcLbLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is GrpcLbLoadBalancingConfig { + return lbconfig.name === 'grpclb'; +} + +export function isPriorityLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is PriorityLoadBalancingConfig { + return lbconfig.name === 'priority'; +} + /* In these functions we assume the input came from a JSON object. Therefore we * expect that the prototype is uninteresting and that `in` can be used * effectively */ @@ -97,17 +144,26 @@ export function validateConfig(obj: any): LoadBalancingConfig { throw new Error('Multiple load balancing policies configured'); } if (obj['round_robin'] instanceof Object) { - return { round_robin: {} }; + return { + name: 'round_robin', + round_robin: {} + }; } } if ('xds' in obj) { if ('grpclb' in obj) { throw new Error('Multiple load balancing policies configured'); } - return { xds: validateXdsConfig(obj.xds) }; + return { + name: 'xds', + xds: validateXdsConfig(obj.xds) + }; } if ('grpclb' in obj) { - return { grpclb: validateGrpcLbConfig(obj.grpclb) }; + return { + name: 'grpclb', + grpclb: validateGrpcLbConfig(obj.grpclb) + }; } throw new Error('No recognized load balancing policy configured'); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index f3e2eda3e..8766c36a1 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -18,14 +18,12 @@ import { ChannelControlHelper, LoadBalancer, - isLoadBalancerNameRegistered, - createLoadBalancer, + getFirstUsableConfig, } from './load-balancer'; import { ServiceConfig } from './service-config'; import { ConnectivityState } from './channel'; import { createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; -import { ChannelOptions } from './channel-options'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; import { BackoffTimeout } from './backoff-timeout'; @@ -36,6 +34,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; const TRACER_NAME = 'resolving_load_balancer'; @@ -50,19 +49,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { * The resolver class constructed for the target address. */ private innerResolver: Resolver; - /** - * Current internal load balancer used for handling calls. - * Invariant: innerLoadBalancer === null => pendingReplacementLoadBalancer === null. - */ - private innerLoadBalancer: LoadBalancer | null = null; - /** - * The load balancer instance that will be used in place of the current - * `innerLoadBalancer` once either that load balancer loses its connection - * or this one establishes a connection. For use when a new name resolution - * result comes in with a different load balancing configuration, and the - * current `innerLoadBalancer` is still connected. - */ - private pendingReplacementLoadBalancer: LoadBalancer | null = null; + + private childLoadBalancer: ChildLoadBalancerHandler; /** * This resolving load balancer's current connectivity state. */ @@ -74,34 +62,6 @@ export class ResolvingLoadBalancer implements LoadBalancer { * successful resolution explicitly provided a null service config. */ private previousServiceConfig: ServiceConfig | null | undefined = undefined; - /** - * The most recently reported connectivity state of the `innerLoadBalancer`. - */ - private innerBalancerState: ConnectivityState = ConnectivityState.IDLE; - - private innerBalancerPicker: Picker = new UnavailablePicker(); - - /** - * The most recent reported state of the pendingReplacementLoadBalancer. - * Starts at IDLE for type simplicity. This should get updated as soon as the - * pendingReplacementLoadBalancer gets constructed. - */ - private replacementBalancerState: ConnectivityState = ConnectivityState.IDLE; - /** - * The picker associated with the replacementBalancerState. Starts as an - * UnavailablePicker for type simplicity. This should get updated as soon as - * the pendingReplacementLoadBalancer gets constructed. - */ - private replacementBalancerPicker: Picker = new UnavailablePicker(); - - /** - * ChannelControlHelper for the innerLoadBalancer. - */ - private readonly innerChannelControlHelper: ChannelControlHelper; - /** - * ChannelControlHelper for the pendingReplacementLoadBalancer. - */ - private readonly replacementChannelControlHelper: ChannelControlHelper; /** * The backoff timer for handling name resolution failures. @@ -127,11 +87,28 @@ export class ResolvingLoadBalancer implements LoadBalancer { * implmentation */ constructor( - private target: GrpcUri, - private channelControlHelper: ChannelControlHelper, - private defaultServiceConfig: ServiceConfig | null + private readonly target: GrpcUri, + private readonly channelControlHelper: ChannelControlHelper, + private readonly defaultServiceConfig: ServiceConfig | null ) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + this.childLoadBalancer = new ChildLoadBalancerHandler({ + createSubchannel: channelControlHelper.createSubchannel.bind(channelControlHelper), + requestReresolution: () => { + /* If the backoffTimeout is running, we're still backing off from + * making resolve requests, so we shouldn't make another one here. + * In that case, the backoff timer callback will call + * updateResolution */ + if (this.backoffTimeout.isRunning()) { + this.continueResolving = true; + } else { + this.updateResolution(); + } + }, + updateState: (newState: ConnectivityState, picker: Picker) => { + this.updateState(newState, picker); + } + }); this.innerResolver = createResolver(target, { onSuccessfulResolution: ( addressList: SubchannelAddress[], @@ -171,227 +148,64 @@ export class ResolvingLoadBalancer implements LoadBalancer { workingServiceConfig = serviceConfig; this.previousServiceConfig = serviceConfig; } - let loadBalancerName: string | null = null; - let loadBalancingConfig: LoadBalancingConfig | null = null; - if ( - workingServiceConfig === null || - workingServiceConfig.loadBalancingConfig.length === 0 - ) { - loadBalancerName = DEFAULT_LOAD_BALANCER_NAME; - } else { - for (const lbConfig of workingServiceConfig.loadBalancingConfig) { - // Iterating through a oneof looking for whichever one is populated - for (const key in lbConfig) { - if (Object.prototype.hasOwnProperty.call(lbConfig, key)) { - if (isLoadBalancerNameRegistered(key)) { - loadBalancerName = key; - loadBalancingConfig = lbConfig; - break; - } - } - } - if (loadBalancerName !== null) { - break; - } - } - if (loadBalancerName === null) { - // There were load balancing configs but none are supported. This counts as a resolution failure - this.handleResolutionFailure({ - code: Status.UNAVAILABLE, - details: - 'All load balancer options in service config are not compatible', - metadata: new Metadata(), - }); - return; - } + const workingConfigList = workingServiceConfig?.loadBalancingConfig ?? []; + if (workingConfigList.length === 0) { + workingConfigList.push({ + name: 'pick_first', + pick_first: {} + }); } - if (this.innerLoadBalancer === null) { - this.innerLoadBalancer = createLoadBalancer( - loadBalancerName, - this.innerChannelControlHelper - )!; - this.innerLoadBalancer.updateAddressList( - addressList, - loadBalancingConfig, - attributes - ); - } else if (this.innerLoadBalancer.getTypeName() === loadBalancerName) { - this.innerLoadBalancer.updateAddressList( - addressList, - loadBalancingConfig, - attributes - ); - } else { - if ( - this.pendingReplacementLoadBalancer === null || - this.pendingReplacementLoadBalancer.getTypeName() !== - loadBalancerName - ) { - if (this.pendingReplacementLoadBalancer !== null) { - this.pendingReplacementLoadBalancer.destroy(); - } - this.pendingReplacementLoadBalancer = createLoadBalancer( - loadBalancerName, - this.replacementChannelControlHelper - )!; - } - this.pendingReplacementLoadBalancer.updateAddressList( - addressList, - loadBalancingConfig, - attributes - ); + const loadBalancingConfig = getFirstUsableConfig(workingConfigList); + if (loadBalancingConfig === null) { + // There were load balancing configs but none are supported. This counts as a resolution failure + this.handleResolutionFailure({ + code: Status.UNAVAILABLE, + details: + 'All load balancer options in service config are not compatible', + metadata: new Metadata(), + }); + return; } + this.childLoadBalancer.updateAddressList(addressList, loadBalancingConfig, attributes); }, onError: (error: StatusObject) => { this.handleResolutionFailure(error); }, }); - this.innerChannelControlHelper = { - createSubchannel: ( - subchannelAddress: SubchannelAddress, - subchannelArgs: ChannelOptions - ) => { - return this.channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ); - }, - updateState: (connectivityState: ConnectivityState, picker: Picker) => { - this.innerBalancerState = connectivityState; - if (connectivityState === ConnectivityState.IDLE) { - picker = new QueuePicker(this); - } - this.innerBalancerPicker = picker; - if ( - connectivityState !== ConnectivityState.READY && - this.pendingReplacementLoadBalancer !== null - ) { - this.switchOverReplacementBalancer(); - } else { - if (connectivityState === ConnectivityState.IDLE) { - if (this.innerLoadBalancer) { - this.innerLoadBalancer.destroy(); - this.innerLoadBalancer = null; - } - } - this.updateState(connectivityState, picker); - } - }, - requestReresolution: () => { - if (this.pendingReplacementLoadBalancer === null) { - /* If the backoffTimeout is running, we're still backing off from - * making resolve requests, so we shouldn't make another one here. - * In that case, the backoff timer callback will call - * updateResolution */ - if (this.backoffTimeout.isRunning()) { - this.continueResolving = true; - } else { - this.updateResolution(); - } - } - }, - }; - - this.replacementChannelControlHelper = { - createSubchannel: ( - subchannelAddress: SubchannelAddress, - subchannelArgs: ChannelOptions - ) => { - return this.channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ); - }, - updateState: (connectivityState: ConnectivityState, picker: Picker) => { - if (connectivityState === ConnectivityState.IDLE) { - picker = new QueuePicker(this); - } - this.replacementBalancerState = connectivityState; - this.replacementBalancerPicker = picker; - if (connectivityState === ConnectivityState.READY) { - this.switchOverReplacementBalancer(); - } else if (connectivityState === ConnectivityState.IDLE) { - if (this.pendingReplacementLoadBalancer) { - this.pendingReplacementLoadBalancer.destroy(); - this.pendingReplacementLoadBalancer = null; - } - } - }, - requestReresolution: () => { - /* If the backoffTimeout is running, we're still backing off from - * making resolve requests, so we shouldn't make another one here. - * In that case, the backoff timer callback will call - * updateResolution */ - if (this.backoffTimeout.isRunning()) { - this.continueResolving = true; - } else { - this.updateResolution(); - } - }, - }; - this.backoffTimeout = new BackoffTimeout(() => { if (this.continueResolving) { this.updateResolution(); this.continueResolving = false; - } else { - if (this.innerLoadBalancer === null) { - this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); - } else { - this.updateState(this.innerBalancerState, this.innerBalancerPicker); - } } }); } private updateResolution() { this.innerResolver.updateResolution(); - if ( - this.innerLoadBalancer === null || - this.innerBalancerState === ConnectivityState.IDLE - ) { + if (this.currentState === ConnectivityState.IDLE) { this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } } - private updateState(connectivitystate: ConnectivityState, picker: Picker) { + private updateState(connectivityState: ConnectivityState, picker: Picker) { trace( uriToString(this.target) + ' ' + ConnectivityState[this.currentState] + ' -> ' + - ConnectivityState[connectivitystate] - ); - this.currentState = connectivitystate; - this.channelControlHelper.updateState(connectivitystate, picker); - } - - /** - * Stop using the current innerLoadBalancer and replace it with the - * pendingReplacementLoadBalancer. Must only be called if both of - * those are currently not null. - */ - private switchOverReplacementBalancer() { - this.innerLoadBalancer!.destroy(); - this.innerLoadBalancer = this.pendingReplacementLoadBalancer!; - this.innerLoadBalancer.replaceChannelControlHelper( - this.innerChannelControlHelper - ); - this.pendingReplacementLoadBalancer = null; - this.innerBalancerState = this.replacementBalancerState; - this.innerBalancerPicker = this.replacementBalancerPicker; - this.updateState( - this.replacementBalancerState, - this.replacementBalancerPicker + ConnectivityState[connectivityState] ); + // Ensure that this.exitIdle() is called by the picker + if (connectivityState === ConnectivityState.IDLE) { + picker = new QueuePicker(this); + } + this.currentState = connectivityState; + this.channelControlHelper.updateState(connectivityState, picker); } private handleResolutionFailure(error: StatusObject) { - if ( - this.innerLoadBalancer === null || - this.innerBalancerState === ConnectivityState.IDLE - ) { + if (this.currentState === ConnectivityState.IDLE) { this.updateState( ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error) @@ -401,9 +215,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } exitIdle() { - if (this.innerLoadBalancer !== null) { - this.innerLoadBalancer.exitIdle(); - } + this.childLoadBalancer.exitIdle(); if (this.currentState === ConnectivityState.IDLE) { if (this.backoffTimeout.isRunning()) { this.continueResolving = true; @@ -423,31 +235,15 @@ export class ResolvingLoadBalancer implements LoadBalancer { resetBackoff() { this.backoffTimeout.reset(); - if (this.innerLoadBalancer !== null) { - this.innerLoadBalancer.resetBackoff(); - } - if (this.pendingReplacementLoadBalancer !== null) { - this.pendingReplacementLoadBalancer.resetBackoff(); - } + this.childLoadBalancer.resetBackoff(); } destroy() { - if (this.innerLoadBalancer !== null) { - this.innerLoadBalancer.destroy(); - this.innerLoadBalancer = null; - } - if (this.pendingReplacementLoadBalancer !== null) { - this.pendingReplacementLoadBalancer.destroy(); - this.pendingReplacementLoadBalancer = null; - } + this.childLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN, new UnavailablePicker()); } getTypeName() { return 'resolving_load_balancer'; } - - replaceChannelControlHelper(channelControlHelper: ChannelControlHelper) { - this.channelControlHelper = channelControlHelper; - } } From 265b39b6defe1627b68a09058e449702d685cf1b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 4 May 2020 15:06:51 -0700 Subject: [PATCH 1058/1899] Fix state changes when handling resolution failures --- packages/grpc-js/src/resolving-load-balancer.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 8766c36a1..87ece2fdc 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -51,6 +51,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { private innerResolver: Resolver; private childLoadBalancer: ChildLoadBalancerHandler; + private latestChildState: ConnectivityState = ConnectivityState.IDLE; + private latestChildPicker: Picker = new QueuePicker(this); /** * This resolving load balancer's current connectivity state. */ @@ -106,6 +108,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { } }, updateState: (newState: ConnectivityState, picker: Picker) => { + this.latestChildState = newState; + this.latestChildPicker = picker; this.updateState(newState, picker); } }); @@ -177,6 +181,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { if (this.continueResolving) { this.updateResolution(); this.continueResolving = false; + } else { + this.updateState(this.latestChildState, this.latestChildPicker) } }); } @@ -205,7 +211,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } private handleResolutionFailure(error: StatusObject) { - if (this.currentState === ConnectivityState.IDLE) { + if (this.latestChildState === ConnectivityState.IDLE) { this.updateState( ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error) From 6e202e0b53dcb4457fb5957df93c75c882917e26 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 4 May 2020 15:07:45 -0700 Subject: [PATCH 1059/1899] gts fix --- .../src/load-balancer-child-handler.ts | 36 ++++++++++++------- packages/grpc-js/src/load-balancer.ts | 4 ++- packages/grpc-js/src/load-balancing-config.ts | 33 +++++++++++------ .../grpc-js/src/resolving-load-balancer.ts | 19 ++++++---- 4 files changed, 62 insertions(+), 30 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index bb1bf0215..476230d51 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -20,10 +20,7 @@ import { ChannelControlHelper, createLoadBalancer, } from './load-balancer'; -import { - SubchannelAddress, - Subchannel, -} from './subchannel'; +import { SubchannelAddress, Subchannel } from './subchannel'; import { LoadBalancingConfig } from './load-balancing-config'; import { ChannelOptions } from './channel-options'; import { ConnectivityState } from './channel'; @@ -38,8 +35,14 @@ export class ChildLoadBalancerHandler implements LoadBalancer { private ChildPolicyHelper = class { private child: LoadBalancer | null = null; constructor(private parent: ChildLoadBalancerHandler) {} - createSubchannel(subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions): Subchannel { - return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + createSubchannel( + subchannelAddress: SubchannelAddress, + subchannelArgs: ChannelOptions + ): Subchannel { + return this.parent.channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ); } updateState(connectivityState: ConnectivityState, picker: Picker): void { if (this.calledByPendingChild()) { @@ -69,22 +72,29 @@ export class ChildLoadBalancerHandler implements LoadBalancer { private calledByCurrentChild(): boolean { return this.child === this.parent.currentChild; } - } + }; constructor(private readonly channelControlHelper: ChannelControlHelper) {} /** * Prerequisites: lbConfig !== null and lbConfig.name is registered - * @param addressList - * @param lbConfig - * @param attributes + * @param addressList + * @param lbConfig + * @param attributes */ - updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null, attributes: { [key: string]: unknown; }): void { + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig | null, + attributes: { [key: string]: unknown } + ): void { if (lbConfig === null) { return; } let childToUpdate: LoadBalancer; - if (this.currentChild === null || this.currentChild.getTypeName() !== lbConfig.name) { + if ( + this.currentChild === null || + this.currentChild.getTypeName() !== lbConfig.name + ) { const newHelper = new this.ChildPolicyHelper(this); const newChild = createLoadBalancer(lbConfig.name, newHelper)!; newHelper.setChild(newChild); @@ -134,4 +144,4 @@ export class ChildLoadBalancerHandler implements LoadBalancer { getTypeName(): string { return TYPE_NAME; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 160723d5e..1c0282475 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -123,7 +123,9 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; } -export function getFirstUsableConfig(configs: LoadBalancingConfig[]): LoadBalancingConfig | null { +export function getFirstUsableConfig( + configs: LoadBalancingConfig[] +): LoadBalancingConfig | null { for (const config of configs) { if (config.name in registeredLoadBalancerTypes) { return config; diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 0c6048f43..0a06d5f88 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -73,24 +73,37 @@ export interface PriorityLoadBalancingConfig { priority: PriorityLbConfig; } -export type LoadBalancingConfig = PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig | XdsLoadBalancingConfig | GrpcLbLoadBalancingConfig | PriorityLoadBalancingConfig; - -export function isRoundRobinLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is RoundRobinLoadBalancingConfig { +export type LoadBalancingConfig = + | PickFirstLoadBalancingConfig + | RoundRobinLoadBalancingConfig + | XdsLoadBalancingConfig + | GrpcLbLoadBalancingConfig + | PriorityLoadBalancingConfig; + +export function isRoundRobinLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is RoundRobinLoadBalancingConfig { return lbconfig.name === 'round_robin'; } -export function isXdsLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is XdsLoadBalancingConfig { +export function isXdsLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is XdsLoadBalancingConfig { return lbconfig.name === 'xds'; } -export function isGrpcLbLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is GrpcLbLoadBalancingConfig { +export function isGrpcLbLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is GrpcLbLoadBalancingConfig { return lbconfig.name === 'grpclb'; } -export function isPriorityLoadBalancingConfig(lbconfig: LoadBalancingConfig): lbconfig is PriorityLoadBalancingConfig { +export function isPriorityLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is PriorityLoadBalancingConfig { return lbconfig.name === 'priority'; } - + /* In these functions we assume the input came from a JSON object. Therefore we * expect that the prototype is uninteresting and that `in` can be used * effectively */ @@ -146,7 +159,7 @@ export function validateConfig(obj: any): LoadBalancingConfig { if (obj['round_robin'] instanceof Object) { return { name: 'round_robin', - round_robin: {} + round_robin: {}, }; } } @@ -156,13 +169,13 @@ export function validateConfig(obj: any): LoadBalancingConfig { } return { name: 'xds', - xds: validateXdsConfig(obj.xds) + xds: validateXdsConfig(obj.xds), }; } if ('grpclb' in obj) { return { name: 'grpclb', - grpclb: validateGrpcLbConfig(obj.grpclb) + grpclb: validateGrpcLbConfig(obj.grpclb), }; } throw new Error('No recognized load balancing policy configured'); diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 87ece2fdc..fe75944de 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -95,7 +95,9 @@ export class ResolvingLoadBalancer implements LoadBalancer { ) { this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.childLoadBalancer = new ChildLoadBalancerHandler({ - createSubchannel: channelControlHelper.createSubchannel.bind(channelControlHelper), + createSubchannel: channelControlHelper.createSubchannel.bind( + channelControlHelper + ), requestReresolution: () => { /* If the backoffTimeout is running, we're still backing off from * making resolve requests, so we shouldn't make another one here. @@ -111,7 +113,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.latestChildState = newState; this.latestChildPicker = picker; this.updateState(newState, picker); - } + }, }); this.innerResolver = createResolver(target, { onSuccessfulResolution: ( @@ -152,11 +154,12 @@ export class ResolvingLoadBalancer implements LoadBalancer { workingServiceConfig = serviceConfig; this.previousServiceConfig = serviceConfig; } - const workingConfigList = workingServiceConfig?.loadBalancingConfig ?? []; + const workingConfigList = + workingServiceConfig?.loadBalancingConfig ?? []; if (workingConfigList.length === 0) { workingConfigList.push({ name: 'pick_first', - pick_first: {} + pick_first: {}, }); } const loadBalancingConfig = getFirstUsableConfig(workingConfigList); @@ -170,7 +173,11 @@ export class ResolvingLoadBalancer implements LoadBalancer { }); return; } - this.childLoadBalancer.updateAddressList(addressList, loadBalancingConfig, attributes); + this.childLoadBalancer.updateAddressList( + addressList, + loadBalancingConfig, + attributes + ); }, onError: (error: StatusObject) => { this.handleResolutionFailure(error); @@ -182,7 +189,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.updateResolution(); this.continueResolving = false; } else { - this.updateState(this.latestChildState, this.latestChildPicker) + this.updateState(this.latestChildState, this.latestChildPicker); } }); } From 7aa9177fa3a3736e32803c78806ea57ff21070ba Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 5 May 2020 14:29:53 -0700 Subject: [PATCH 1060/1899] Don't allow null load balancing configs --- packages/grpc-js/src/load-balancer-child-handler.ts | 5 +---- packages/grpc-js/src/load-balancer-pick-first.ts | 2 +- packages/grpc-js/src/load-balancer-round-robin.ts | 2 +- packages/grpc-js/src/load-balancer.ts | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 476230d51..158108f0a 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -84,12 +84,9 @@ export class ChildLoadBalancerHandler implements LoadBalancer { */ updateAddressList( addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig | null, + lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (lbConfig === null) { - return; - } let childToUpdate: LoadBalancer; if ( this.currentChild === null || diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index a15b0a190..15fa53668 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -383,7 +383,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { updateAddressList( addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig | null + lbConfig: LoadBalancingConfig ): void { // lbConfig has no useful information for pick first load balancing /* To avoid unnecessary churn, we only do something with this address list diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index b52751e9a..2b7abffbb 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -189,7 +189,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { updateAddressList( addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig | null + lbConfig: LoadBalancingConfig ): void { this.resetSubchannelList(); trace( diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 1c0282475..dc4cf4e33 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -67,7 +67,7 @@ export interface LoadBalancer { */ updateAddressList( addressList: SubchannelAddress[], - lbConfig: LoadBalancingConfig | null, + lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void; /** From 3d8c9af40104de2809c00b540d91f0b999ecbea0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 May 2020 10:30:56 -0700 Subject: [PATCH 1061/1899] grpc-js: Fix pick_first handling of IDLE subchannels. Also stop reporting IDLE on LB creation --- .../grpc-js/src/load-balancer-pick-first.ts | 3 ++- .../grpc-js/src/load-balancer-round-robin.ts | 1 - packages/grpc-js/test/test-client.ts | 23 +++++++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index f38886188..c4f289a96 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -130,7 +130,6 @@ export class PickFirstLoadBalancer implements LoadBalancer { * this load balancer's owner. */ constructor(private channelControlHelper: ChannelControlHelper) { - this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.subchannelStateCounts = { [ConnectivityState.CONNECTING]: 0, [ConnectivityState.IDLE]: 0, @@ -168,6 +167,8 @@ export class PickFirstLoadBalancer implements LoadBalancer { * basic IDLE state where there is no subchannel list to avoid * holding unused resources */ this.resetSubchannelList(); + this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); + return; } if (this.currentPick === null) { if (this.triedAllSubchannels) { diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 512443416..9716d7f03 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -95,7 +95,6 @@ export class RoundRobinLoadBalancer implements LoadBalancer { private currentReadyPicker: RoundRobinPicker | null = null; constructor(private channelControlHelper: ChannelControlHelper) { - this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.subchannelStateCounts = { [ConnectivityState.CONNECTING]: 0, [ConnectivityState.IDLE]: 0, diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts index da20c246b..0d2878cbc 100644 --- a/packages/grpc-js/test/test-client.ts +++ b/packages/grpc-js/test/test-client.ts @@ -69,3 +69,26 @@ describe('Client', () => { }, deadline - Date.now()); }); }); + +describe('Client without a server', () => { + let client: Client; + before(() => { + // Arbitrary target that should not have a running server + client = new Client('localhost:12345', clientInsecureCreds); + }); + after(() => { + client.close(); + }); + it('should fail multiple calls to the nonexistent server', done => { + // Regression test for https://github.com/grpc/grpc-node/issues/1411 + client.makeUnaryRequest('/service/method', x => x, x => x, Buffer.from([]), (error, value) => { + assert(error); + assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); + client.makeUnaryRequest('/service/method', x => x, x => x, Buffer.from([]), (error, value) => { + assert(error); + assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); + done(); + }); + }); + }); +}); \ No newline at end of file From 8c61b166426993e944964c333cccd350e81046c3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 May 2020 10:33:25 -0700 Subject: [PATCH 1062/1899] Bump grpc-js to 1.0.4 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3ca7b8f5c..2ed5a8bfe 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.0.3", + "version": "1.0.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 4ef8abddf240c0d16ecd12be247ceb5d933f3e4b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 May 2020 10:47:35 -0700 Subject: [PATCH 1063/1899] grpc-js: Don't split header values by commas --- packages/grpc-js/src/metadata.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 2da9d5311..4947bf0ad 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -278,11 +278,7 @@ export class Metadata { result.add(key, value); }); } else if (values !== undefined) { - if (isCustomMetadata(key)) { - values.split(',').forEach((v) => result.add(key, v.trim())); - } else { - result.add(key, values); - } + result.add(key, values); } } } catch (error) { From eab63a94ac469d4814b6acf6fd8c87a75aea421f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 May 2020 11:36:17 -0700 Subject: [PATCH 1064/1899] Don't use gts clean in npm clean to avoid errors on Node 8 --- packages/grpc-js/package.json | 3 ++- packages/proto-loader/package.json | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3ca7b8f5c..590e5fef6 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -33,6 +33,7 @@ "mocha-jenkins-reporter": "^0.4.1", "ncp": "^2.0.0", "pify": "^4.0.1", + "rimraf": "^3.0.2", "ts-node": "^8.3.0", "typescript": "^3.7.2" }, @@ -43,7 +44,7 @@ ], "scripts": { "build": "npm run compile", - "clean": "gts clean", + "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "lint": "npm run check", diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 746b87926..022eb41c3 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -14,7 +14,7 @@ "typings": "build/src/index.d.ts", "scripts": { "build": "npm run compile", - "clean": "gts clean", + "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "lint": "tslint -c node_modules/google-ts-style/tslint.json -p . -t codeFrame --type-check", @@ -47,6 +47,7 @@ "@types/node": "^10.12.5", "clang-format": "^1.2.2", "gts": "^1.1.0", + "rimraf": "^3.0.2", "typescript": "~3.3.3333" }, "engines": { From f0fa806bfaff0aa0e2d2a56ee8d9c3ed2a1393ff Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Sun, 10 May 2020 09:16:28 +0100 Subject: [PATCH 1065/1899] grpc-js: Fix README formatting This should fix the heading rendering on npmjs.com --- packages/grpc-js/README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index ed993d2f3..4d0cb5482 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -10,31 +10,31 @@ npm install @grpc/grpc-js ## Features - - Clients - - Automatic reconnection - - Servers - - Streaming - - Metadata - - Partial compression support: clients can decompress response messages - - Pick first and round robin load balancing policies - - Client Interceptors - - Connection Keepalives - - HTTP Connect support (proxies) +- Clients +- Automatic reconnection +- Servers +- Streaming +- Metadata +- Partial compression support: clients can decompress response messages +- Pick first and round robin load balancing policies +- Client Interceptors +- Connection Keepalives +- HTTP Connect support (proxies) This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package. - ## Migrating from [`grpc`](https://www.npmjs.com/package/grpc) +## Migrating from [`grpc`](https://www.npmjs.com/package/grpc) - `@grpc/grpc-js` is almost a drop-in replacement for `grpc`, but you may need to make a few code changes to use it: +`@grpc/grpc-js` is almost a drop-in replacement for `grpc`, but you may need to make a few code changes to use it: - - If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. - - If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `--generate_package_definitions` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. - - If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead. +- If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. +- If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `--generate_package_definitions` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. +- If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead. ## Some Notes on API Guarantees The public API of this library follows semantic versioning, with some caveats: - - Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API. - - The class `Call` is only exposed due to limitations of TypeScript. It should not be considered part of the public API. - - In general, any API that is exposed by this library but is not exposed by the `grpc` library is likely an error and should not be considered part of the public API. +- Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API. +- The class `Call` is only exposed due to limitations of TypeScript. It should not be considered part of the public API. +- In general, any API that is exposed by this library but is not exposed by the `grpc` library is likely an error and should not be considered part of the public API. From e26a3b264cf978071c0ecaa6c3c7415691a9fbfe Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 11 May 2020 10:11:23 -0700 Subject: [PATCH 1066/1899] grpc-js: Add more detailed information to client (de)serialization errors --- packages/grpc-js/src/client-interceptors.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 9b503c52d..fe36ea36d 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -359,7 +359,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { serialized = this.methodDefinition.requestSerialize(message); this.call.sendMessageWithContext(context, serialized); } catch (e) { - this.call.cancelWithStatus(Status.INTERNAL, 'Serialization failure'); + this.call.cancelWithStatus(Status.INTERNAL, `Request message serialization failure: ${e.message}`); } } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -384,7 +384,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { } catch (e) { readError = { code: Status.INTERNAL, - details: 'Failed to parse server response', + details: `Response message parsing error: ${e.message}`, metadata: new Metadata(), }; this.call.cancelWithStatus(readError.code, readError.details); From f98bf7e94070bb0711ca65bfd3ed8e19dfb6debe Mon Sep 17 00:00:00 2001 From: David Walsh <5778036+rhinodavid@users.noreply.github.com> Date: Mon, 11 May 2020 19:38:29 -0600 Subject: [PATCH 1067/1899] Bump protobuf dep to v3.11.4 --- packages/grpc-tools/deps/protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index a6e1cc7e3..d0bfd5221 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit a6e1cc7e328c45a0cb9856c530c8f6cd23314163 +Subproject commit d0bfd5221182da1a7cc280f3337b5e41a89539cf From e4a3fb6338beb864a3191cd69dd4fec56572c614 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 12 May 2020 14:04:57 -0700 Subject: [PATCH 1068/1899] Bump grpc-tools to 1.9.0 and add a README --- packages/grpc-tools/README.md | 22 ++++++++++++++++++++++ packages/grpc-tools/package.json | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-tools/README.md diff --git a/packages/grpc-tools/README.md b/packages/grpc-tools/README.md new file mode 100644 index 000000000..eae786929 --- /dev/null +++ b/packages/grpc-tools/README.md @@ -0,0 +1,22 @@ +# grpc-tools + +This package distributes the Protocol Buffers compiler `protoc` along with the +plugin for generating client and service objects for use with the Node gRPC +libraries. + +## Usage + +This library exports the `grpc_tools_node_protoc` executable, which accepts all +of the same arguments as `protoc` itself. For use with Node, you most likely +want to use CommonJS-style imports. An example of generating code this way can +be found in [this guide](https://developers.google.com/protocol-buffers/docs/reference/javascript-generated#commonjs-imports). +The `grpc_tools_node_protoc` automatically includes the Node gRPC plugin, so +it also accepts the `--grpc_out=[option:]path` argument. The option can be +one of the following: + + - `grpc_js`: Generates code with `require('@grpc/grpc-js')` instead of + `require('grpc')` + - `generate_package_definition`: Generates code that does not `require` any + gRPC library, and instead generates `PackageDefinition` objects that can + be passed to the `loadPackageDefinition` function provided by both the + `grpc` and `@grpc/grpc-js` libraries. \ No newline at end of file diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 298d64d1b..c7bb27945 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.8.1", + "version": "1.9.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From dfacfae2b265d652c82519bbefcfc9fd9e9d4cb9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 12 May 2020 14:52:01 -0700 Subject: [PATCH 1069/1899] Fix package installation in grpc-tools build script --- packages/grpc-tools/build_binaries.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 8c249642e..04919cff3 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -16,6 +16,10 @@ $ErrorActionPreference = "Stop" +<# https://stackoverflow.com/questions/16657778/install-nuget-via-powershell-script/26421187#comment107976901_48216538 #> + +[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls11,Tls12' + Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 Install-Module -Force -Name 7Zip4Powershell From a53bcb3c975010abcd5893c02cd22492286d71a2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 May 2020 12:00:22 -0700 Subject: [PATCH 1070/1899] grpc-js: Add a few basic trace lines to the server --- packages/grpc-js/src/server-call.ts | 15 ++++++++++++++- packages/grpc-js/src/server.ts | 20 ++++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index fc456fda8..74b950577 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -20,12 +20,19 @@ import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; import { StatusObject } from './call-stream'; -import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH } from './constants'; +import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, LogVerbosity } from './constants'; import { Deserialize, Serialize } from './make-client'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; import { ObjectReadable, ObjectWritable } from './object-stream'; import { ChannelOptions } from './channel-options'; +import * as logging from './logging'; + +const TRACER_NAME = 'server_call'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} interface DeadlineUnitIndexSignature { [name: string]: number; @@ -294,6 +301,7 @@ export interface UnaryHandler { serialize: Serialize; deserialize: Deserialize; type: HandlerType; + path: string; } export interface ClientStreamingHandler { @@ -301,6 +309,7 @@ export interface ClientStreamingHandler { serialize: Serialize; deserialize: Deserialize; type: HandlerType; + path: string; } export interface ServerStreamingHandler { @@ -308,6 +317,7 @@ export interface ServerStreamingHandler { serialize: Serialize; deserialize: Deserialize; type: HandlerType; + path: string; } export interface BidiStreamingHandler { @@ -315,6 +325,7 @@ export interface BidiStreamingHandler { serialize: Serialize; deserialize: Deserialize; type: HandlerType; + path: string; } export type Handler = @@ -521,6 +532,8 @@ export class Http2ServerCallStream< return; } + trace('Request to method ' + this.handler?.path + ' ended with status code: ' + Status[statusObj.code] + ' details: ' + statusObj.details); + clearTimeout(this.deadline); if (!this.wantTrailers) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index c8b8f2b22..f5de7958c 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -46,14 +46,21 @@ import { import { ServerCredentials } from './server-credentials'; import { ChannelOptions } from './channel-options'; import { createResolver, ResolverListener, mapUriDefaultScheme } from './resolver'; -import { log } from './logging'; +import * as logging from './logging'; import { SubchannelAddress, TcpSubchannelAddress, isTcpSubchannelAddress, + subchannelAddressToString, } from './subchannel'; import { parseUri } from './uri-parser'; +const TRACER_NAME = 'server'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + interface BindResult { port: number; count: number; @@ -269,6 +276,7 @@ export class Server { } return Promise.all( addressList.map((address) => { + trace('Attempting to bind ' + subchannelAddressToString(address)); let addr: SubchannelAddress; if (isTcpSubchannelAddress(address)) { addr = { @@ -288,6 +296,7 @@ export class Server { http2Server.once('error', onError); http2Server.listen(addr, () => { + trace('Successfully bound ' + subchannelAddressToString(address)); this.http2ServerList.push(http2Server); const boundAddress = http2Server.address()!; if (typeof boundAddress === 'string') { @@ -378,11 +387,11 @@ export class Server { (bindResult) => { if (bindResult.count === 0) { const errorString = `No address added out of total ${addressList.length} resolved`; - log(LogVerbosity.ERROR, errorString); + logging.log(LogVerbosity.ERROR, errorString); callback(new Error(errorString), 0); } else { if (bindResult.count < addressList.length) { - log( + logging.log( LogVerbosity.INFO, `WARNING Only ${bindResult.count} addresses added out of total ${addressList.length} resolved` ); @@ -392,7 +401,7 @@ export class Server { }, (error) => { const errorString = `No address added out of total ${addressList.length} resolved`; - log(LogVerbosity.ERROR, errorString); + logging.log(LogVerbosity.ERROR, errorString); callback(new Error(errorString), 0); } ); @@ -444,6 +453,7 @@ export class Server { serialize, deserialize, type, + path: name, } as UntypedHandler); return true; } @@ -528,9 +538,11 @@ export class Server { try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; + trace('Received call to method ' + path + ' at address ' + http2Server.address()?.toString()); const handler = this.handlers.get(path); if (handler === undefined) { + trace('No handler registered for method ' + path + '. Sending UNIMPLEMENTED status.'); throw getUnimplementedStatusResponse(path); } From 7625c2becdcb84db75a3724ba77765b0a2d23f0b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 May 2020 12:01:07 -0700 Subject: [PATCH 1071/1899] gts fix --- packages/grpc-js/src/server-call.ts | 41 ++++++++++++++++++++++------- packages/grpc-js/src/server.ts | 19 ++++++++++--- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 74b950577..d5e5f822f 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -20,7 +20,12 @@ import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; import { StatusObject } from './call-stream'; -import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, LogVerbosity } from './constants'; +import { + Status, + DEFAULT_MAX_SEND_MESSAGE_LENGTH, + DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, + LogVerbosity, +} from './constants'; import { Deserialize, Serialize } from './make-client'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; @@ -70,7 +75,7 @@ export type ServerErrorResponse = ServerStatusResponse & Error; export type ServerSurfaceCall = { cancelled: boolean; - readonly metadata: Metadata + readonly metadata: Metadata; getPeer(): string; sendMetadata(responseMetadata: Metadata): void; } & EventEmitter; @@ -458,10 +463,13 @@ export class Http2ServerCallStream< stream.once('end', async () => { try { const requestBytes = Buffer.concat(chunks, totalLength); - if (this.maxReceiveMessageSize !== -1 && requestBytes.length > this.maxReceiveMessageSize) { + if ( + this.maxReceiveMessageSize !== -1 && + requestBytes.length > this.maxReceiveMessageSize + ) { this.sendError({ code: Status.RESOURCE_EXHAUSTED, - details: `Received message larger than max (${requestBytes.length} vs. ${this.maxReceiveMessageSize})` + details: `Received message larger than max (${requestBytes.length} vs. ${this.maxReceiveMessageSize})`, }); resolve(); } @@ -532,7 +540,14 @@ export class Http2ServerCallStream< return; } - trace('Request to method ' + this.handler?.path + ' ended with status code: ' + Status[statusObj.code] + ' details: ' + statusObj.details); + trace( + 'Request to method ' + + this.handler?.path + + ' ended with status code: ' + + Status[statusObj.code] + + ' details: ' + + statusObj.details + ); clearTimeout(this.deadline); @@ -587,10 +602,13 @@ export class Http2ServerCallStream< return; } - if (this.maxSendMessageSize !== -1 && chunk.length > this.maxSendMessageSize) { + if ( + this.maxSendMessageSize !== -1 && + chunk.length > this.maxSendMessageSize + ) { this.sendError({ - code: Status.RESOURCE_EXHAUSTED, - details: `Sent message larger than max (${chunk.length} vs. ${this.maxSendMessageSize})` + code: Status.RESOURCE_EXHAUSTED, + details: `Sent message larger than max (${chunk.length} vs. ${this.maxSendMessageSize})`, }); return; } @@ -621,10 +639,13 @@ export class Http2ServerCallStream< const messages = decoder.write(data); for (const message of messages) { - if (this.maxReceiveMessageSize !== -1 && message.length > this.maxReceiveMessageSize) { + if ( + this.maxReceiveMessageSize !== -1 && + message.length > this.maxReceiveMessageSize + ) { this.sendError({ code: Status.RESOURCE_EXHAUSTED, - details: `Received message larger than max (${message.length} vs. ${this.maxReceiveMessageSize})` + details: `Received message larger than max (${message.length} vs. ${this.maxReceiveMessageSize})`, }); return; } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index f5de7958c..a6edee3ba 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -45,7 +45,11 @@ import { } from './server-call'; import { ServerCredentials } from './server-credentials'; import { ChannelOptions } from './channel-options'; -import { createResolver, ResolverListener, mapUriDefaultScheme } from './resolver'; +import { + createResolver, + ResolverListener, + mapUriDefaultScheme, +} from './resolver'; import * as logging from './logging'; import { SubchannelAddress, @@ -538,11 +542,20 @@ export class Server { try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; - trace('Received call to method ' + path + ' at address ' + http2Server.address()?.toString()); + trace( + 'Received call to method ' + + path + + ' at address ' + + http2Server.address()?.toString() + ); const handler = this.handlers.get(path); if (handler === undefined) { - trace('No handler registered for method ' + path + '. Sending UNIMPLEMENTED status.'); + trace( + 'No handler registered for method ' + + path + + '. Sending UNIMPLEMENTED status.' + ); throw getUnimplementedStatusResponse(path); } From 53731f1f13131adc3eb2df2418d49575766f6aff Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 May 2020 14:28:17 -0700 Subject: [PATCH 1072/1899] Remove contents of grpc-native-core directory --- .gitmodules | 3 - packages/grpc-native-core/.jshintignore | 1 - packages/grpc-native-core/.npmignore | 1 - packages/grpc-native-core/LICENSE | 201 -- packages/grpc-native-core/README.md | 81 +- packages/grpc-native-core/binding.gyp | 1164 ----------- packages/grpc-native-core/build.yaml | 2 - packages/grpc-native-core/deps/grpc | 1 - packages/grpc-native-core/ext/byte_buffer.cc | 79 - packages/grpc-native-core/ext/byte_buffer.h | 41 - packages/grpc-native-core/ext/call.cc | 778 ------- packages/grpc-native-core/ext/call.h | 122 -- .../grpc-native-core/ext/call_credentials.cc | 276 --- .../grpc-native-core/ext/call_credentials.h | 110 - packages/grpc-native-core/ext/channel.cc | 397 ---- packages/grpc-native-core/ext/channel.h | 69 - .../ext/channel_credentials.cc | 253 --- .../ext/channel_credentials.h | 64 - .../grpc-native-core/ext/completion_queue.cc | 89 - .../grpc-native-core/ext/completion_queue.h | 34 - packages/grpc-native-core/ext/node_grpc.cc | 318 --- packages/grpc-native-core/ext/server.cc | 313 --- packages/grpc-native-core/ext/server.h | 70 - .../ext/server_credentials.cc | 192 -- .../grpc-native-core/ext/server_credentials.h | 62 - packages/grpc-native-core/ext/slice.cc | 90 - packages/grpc-native-core/ext/slice.h | 38 - packages/grpc-native-core/ext/timeval.cc | 53 - packages/grpc-native-core/ext/timeval.h | 33 - packages/grpc-native-core/ext/util.h | 52 - packages/grpc-native-core/gulpfile.ts | 84 - packages/grpc-native-core/index.d.ts | 1658 --------------- packages/grpc-native-core/index.js | 384 ---- packages/grpc-native-core/jsdoc_conf.json | 16 - packages/grpc-native-core/package.json | 102 - packages/grpc-native-core/src/client.js | 1074 ---------- .../src/client_interceptors.js | 1444 ------------- packages/grpc-native-core/src/common.js | 356 ---- packages/grpc-native-core/src/constants.js | 266 --- packages/grpc-native-core/src/credentials.js | 278 --- .../grpc-native-core/src/grpc_extension.js | 62 - packages/grpc-native-core/src/metadata.js | 250 --- .../src/protobuf_js_5_common.js | 173 -- .../src/protobuf_js_6_common.js | 164 -- packages/grpc-native-core/src/server.js | 1010 ---------- packages/grpc-native-core/test/async_test.js | 86 - packages/grpc-native-core/test/call_test.js | 335 --- .../grpc-native-core/test/channel_test.js | 181 -- .../test/client_interceptors_test.js | 1795 ----------------- packages/grpc-native-core/test/common_test.js | 189 -- .../grpc-native-core/test/credentials_test.js | 524 ----- packages/grpc-native-core/test/data/README | 1 - packages/grpc-native-core/test/data/ca.pem | 15 - .../grpc-native-core/test/data/server1.key | 16 - .../grpc-native-core/test/data/server1.pem | 16 - .../grpc-native-core/test/echo_service.proto | 34 - .../grpc-native-core/test/end_to_end_test.js | 305 --- .../test/math/math_grpc_pb.js | 125 -- .../grpc-native-core/test/math/math_pb.js | 866 -------- .../grpc-native-core/test/math/math_server.js | 124 -- .../grpc-native-core/test/math_client_test.js | 140 -- .../grpc-native-core/test/metadata_test.js | 178 -- packages/grpc-native-core/test/numbers.txt | 496 ----- .../grpc-native-core/test/resolver_test.js | 73 - packages/grpc-native-core/test/server_test.js | 136 -- .../grpc-native-core/test/surface_test.js | 1532 -------------- .../grpc-native-core/test/test_messages.proto | 45 - .../grpc-native-core/test/test_service.json | 55 - .../grpc-native-core/test/test_service.proto | 38 - .../tools/buildgen/gen_build_yaml.py | 115 -- .../tools/buildgen/generate_projects.sh | 26 - .../artifacts/build_all_linux_artifacts.sh | 80 - .../artifacts/build_artifact_electron.bat | 42 - .../artifacts/build_artifact_electron.sh | 40 - .../artifacts/build_artifact_node.bat | 49 - .../artifacts/build_artifact_node.sh | 55 - .../artifacts/build_artifact_node_arm.sh | 39 - .../artifacts/build_artifact_node_s390x.sh | 24 - .../artifacts/build_one_artifact.bat | 63 - .../artifacts/build_one_artifact_in_docker.sh | 54 - .../artifacts/build_one_artifact_linux.sh | 51 - .../artifacts/build_one_artifact_macos.sh | 55 - .../run_tests/artifacts/build_package_node.sh | 81 - 83 files changed, 1 insertion(+), 20386 deletions(-) delete mode 100644 packages/grpc-native-core/.jshintignore delete mode 100644 packages/grpc-native-core/.npmignore delete mode 100644 packages/grpc-native-core/LICENSE delete mode 100644 packages/grpc-native-core/binding.gyp delete mode 100644 packages/grpc-native-core/build.yaml delete mode 160000 packages/grpc-native-core/deps/grpc delete mode 100644 packages/grpc-native-core/ext/byte_buffer.cc delete mode 100644 packages/grpc-native-core/ext/byte_buffer.h delete mode 100644 packages/grpc-native-core/ext/call.cc delete mode 100644 packages/grpc-native-core/ext/call.h delete mode 100644 packages/grpc-native-core/ext/call_credentials.cc delete mode 100644 packages/grpc-native-core/ext/call_credentials.h delete mode 100644 packages/grpc-native-core/ext/channel.cc delete mode 100644 packages/grpc-native-core/ext/channel.h delete mode 100644 packages/grpc-native-core/ext/channel_credentials.cc delete mode 100644 packages/grpc-native-core/ext/channel_credentials.h delete mode 100644 packages/grpc-native-core/ext/completion_queue.cc delete mode 100644 packages/grpc-native-core/ext/completion_queue.h delete mode 100644 packages/grpc-native-core/ext/node_grpc.cc delete mode 100644 packages/grpc-native-core/ext/server.cc delete mode 100644 packages/grpc-native-core/ext/server.h delete mode 100644 packages/grpc-native-core/ext/server_credentials.cc delete mode 100644 packages/grpc-native-core/ext/server_credentials.h delete mode 100644 packages/grpc-native-core/ext/slice.cc delete mode 100644 packages/grpc-native-core/ext/slice.h delete mode 100644 packages/grpc-native-core/ext/timeval.cc delete mode 100644 packages/grpc-native-core/ext/timeval.h delete mode 100644 packages/grpc-native-core/ext/util.h delete mode 100644 packages/grpc-native-core/gulpfile.ts delete mode 100644 packages/grpc-native-core/index.d.ts delete mode 100644 packages/grpc-native-core/index.js delete mode 100644 packages/grpc-native-core/jsdoc_conf.json delete mode 100644 packages/grpc-native-core/package.json delete mode 100644 packages/grpc-native-core/src/client.js delete mode 100644 packages/grpc-native-core/src/client_interceptors.js delete mode 100644 packages/grpc-native-core/src/common.js delete mode 100644 packages/grpc-native-core/src/constants.js delete mode 100644 packages/grpc-native-core/src/credentials.js delete mode 100644 packages/grpc-native-core/src/grpc_extension.js delete mode 100644 packages/grpc-native-core/src/metadata.js delete mode 100644 packages/grpc-native-core/src/protobuf_js_5_common.js delete mode 100644 packages/grpc-native-core/src/protobuf_js_6_common.js delete mode 100644 packages/grpc-native-core/src/server.js delete mode 100644 packages/grpc-native-core/test/async_test.js delete mode 100644 packages/grpc-native-core/test/call_test.js delete mode 100644 packages/grpc-native-core/test/channel_test.js delete mode 100644 packages/grpc-native-core/test/client_interceptors_test.js delete mode 100644 packages/grpc-native-core/test/common_test.js delete mode 100644 packages/grpc-native-core/test/credentials_test.js delete mode 100644 packages/grpc-native-core/test/data/README delete mode 100644 packages/grpc-native-core/test/data/ca.pem delete mode 100644 packages/grpc-native-core/test/data/server1.key delete mode 100644 packages/grpc-native-core/test/data/server1.pem delete mode 100644 packages/grpc-native-core/test/echo_service.proto delete mode 100644 packages/grpc-native-core/test/end_to_end_test.js delete mode 100644 packages/grpc-native-core/test/math/math_grpc_pb.js delete mode 100644 packages/grpc-native-core/test/math/math_pb.js delete mode 100644 packages/grpc-native-core/test/math/math_server.js delete mode 100644 packages/grpc-native-core/test/math_client_test.js delete mode 100644 packages/grpc-native-core/test/metadata_test.js delete mode 100644 packages/grpc-native-core/test/numbers.txt delete mode 100644 packages/grpc-native-core/test/resolver_test.js delete mode 100644 packages/grpc-native-core/test/server_test.js delete mode 100644 packages/grpc-native-core/test/surface_test.js delete mode 100644 packages/grpc-native-core/test/test_messages.proto delete mode 100644 packages/grpc-native-core/test/test_service.json delete mode 100644 packages/grpc-native-core/test/test_service.proto delete mode 100644 packages/grpc-native-core/tools/buildgen/gen_build_yaml.py delete mode 100755 packages/grpc-native-core/tools/buildgen/generate_projects.sh delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh delete mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh delete mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh delete mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat delete mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh delete mode 100644 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh delete mode 100755 packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh diff --git a/.gitmodules b/.gitmodules index ef8098be7..c17c34644 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ -[submodule "packages/grpc-native-core/deps/grpc"] - path = packages/grpc-native-core/deps/grpc - url = https://github.com/grpc/grpc.git [submodule "packages/grpc-tools/deps/protobuf"] path = packages/grpc-tools/deps/protobuf url = https://github.com/protocolbuffers/protobuf diff --git a/packages/grpc-native-core/.jshintignore b/packages/grpc-native-core/.jshintignore deleted file mode 100644 index 0a73e1e2b..000000000 --- a/packages/grpc-native-core/.jshintignore +++ /dev/null @@ -1 +0,0 @@ -**/*_pb.js \ No newline at end of file diff --git a/packages/grpc-native-core/.npmignore b/packages/grpc-native-core/.npmignore deleted file mode 100644 index e66c5e928..000000000 --- a/packages/grpc-native-core/.npmignore +++ /dev/null @@ -1 +0,0 @@ -**/BUILD \ No newline at end of file diff --git a/packages/grpc-native-core/LICENSE b/packages/grpc-native-core/LICENSE deleted file mode 100644 index 8dada3eda..000000000 --- a/packages/grpc-native-core/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/packages/grpc-native-core/README.md b/packages/grpc-native-core/README.md index f9b6bc1ae..3b300e88f 100644 --- a/packages/grpc-native-core/README.md +++ b/packages/grpc-native-core/README.md @@ -1,80 +1 @@ -[![npm](https://img.shields.io/npm/v/grpc.svg)](https://www.npmjs.com/package/grpc) -# Node.js gRPC Library - -## PREREQUISITES -- `node`: This requires `node` to be installed, version `4.0` or above. If you instead have the `nodejs` executable on Debian, you should install the [`nodejs-legacy`](https://packages.debian.org/sid/nodejs-legacy) package. - -- **Note:** If you installed `node` via a package manager and the version is still less than `4.0`, try directly installing it from [nodejs.org](https://nodejs.org). - -## INSTALLATION - -Install the gRPC NPM package - -```sh -npm install grpc -``` - -## BUILD FROM SOURCE - -The following command can be used to build from source when installing the package from npm: - -``` -npm install grpc --build-from-source -``` - -The `--build-from-source` option will work even when installing another package that depends on `grpc`. To build only `grpc` from source, you can use the argument `--build-from-source=grpc`. - -## ABOUT ELECTRON - -The official electron documentation recommends to [build all of your native packages from source](https://electronjs.org/docs/tutorial/using-native-node-modules#modules-that-rely-on-node-pre-gyp). While the reasons behind this are technically good - many native extensions won't be packaged to work properly with electron - the gRPC source code is fairly difficult to build from source due to its complex nature, and we're also providing working electron pre-built binaries. Therefore, we recommend that you do not follow this model for using gRPC with electron. Also, for the same reason, `electron-rebuild` will always build from source. We advise you to not use this tool if you are depending on gRPC. Please note that there's not just one way to get native extensions running in electron, and that there's never any silver bullet for anything. The following instructions try to cater about some of the most generic ways, but different edge cases might require different methodologies. - -The best way to get gRPC to work with electron is to do this, possibly in the `postinstall` script of your `package.json` file: - -``` -npm rebuild --target=2.0.0 --runtime=electron --dist-url=https://atom.io/download/electron -``` - -Note that the `2.0.0` above is the electron runtime version number. You will need to update this every time you go on a different version of the runtime. - -If you have more native dependencies than gRPC, and they work better when built from source, you can explicitely specify which extension to build the following way: - -``` -npm rebuild --build-from-source=sqlite3 --target=2.0.0 --runtime=electron --dist-url=https://atom.io/download/electron -``` - -This way, if you depend on both `grpc` and `sqlite3`, only the `sqlite3` package will be rebuilt from source, leaving the `grpc` package to use its precompiled binaries. - -## BUILD IN GIT REPOSITORY - - 1. Clone [the grpc-node Git Repository](https://github.com/grpc/grpc-node). - 2. Run `git submodule update --init --recursive` from the repository root. - 3. Run `cd packages/grpc-native-core`. - 4. Run `npm install --build-from-source`. - - - **Note:** On Windows, this might fail due to [nodejs issue #4932](https://github.com/nodejs/node/issues/4932) in which case, you will see something like the following in `npm install`'s output (towards the very beginning): - - ``` - .. - Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch. - WINDOWS_BUILD_WARNING - "..\IMPORTANT: Due to https:\github.com\nodejs\node\issues\4932, to build this library on Windows, you must first remove C:\Users\jenkins\.node-gyp\4.4.0\include\node\openssl" - ... - .. - ``` - - To fix this, you will have to delete the folder `C:\Users\\.node-gyp\\include\node\openssl` and retry `npm install` - -## CONFIGURE BINARIES' LOCATION - -You can configure the location from which the pre-compiled binaries are downloaded during installation. - -`npm install --grpc_node_binary_host_mirror=https://your-url.com` - -Or defining `grpc_node_binary_host_mirror` in your `.npmrc`. - -## API DOCUMENTATION - -See the [API Documentation](https://grpc.io/grpc/node/). - -## TESTING -To run the test suite, simply run `npm test` in the install location. +The `grpc` npm pacakge previously lived in this package. It has been removed. It now lives in the [`grpc@1.24.x` branch](https://github.com/grpc/grpc-node/tree/grpc%401.24.x/packages/grpc-native-core) where bugfixes are still being applied. \ No newline at end of file diff --git a/packages/grpc-native-core/binding.gyp b/packages/grpc-native-core/binding.gyp deleted file mode 100644 index e4b2f0825..000000000 --- a/packages/grpc-native-core/binding.gyp +++ /dev/null @@ -1,1164 +0,0 @@ -# GRPC Node gyp file -# This currently builds the Node extension and dependencies -# This file has been automatically generated from a template file. -# Please look at the templates directory instead. -# This file can be regenerated from the template by running -# tools/buildgen/generate_projects.sh - -# Copyright 2015 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Some of this file is built with the help of -# https://n8.io/converting-a-c-library-to-gyp/ -{ - 'variables': { - 'runtime%': 'node', - # Some Node installations use the system installation of OpenSSL, and on - # some systems, the system OpenSSL still does not have ALPN support. This - # will let users recompile gRPC to work without ALPN. - 'grpc_alpn%': 'true', - # Indicates that the library should be built with gcov. - 'grpc_gcov%': 'false', - # Indicates that the library should be built with compatibility for musl - # libc, so that it can run on Alpine Linux. This is only necessary if not - # building on Alpine Linux - 'grpc_alpine%': 'false' - }, - 'target_defaults': { - 'configurations': { - 'Release': { - 'cflags': [ - '-O2', - '-Wframe-larger-than=16384', - ], - 'defines': [ - 'NDEBUG', - ], - }, - 'Debug': { - 'cflags': [ - '-O0', - ], - 'defines': [ - '_DEBUG', - 'DEBUG', - ], - }, - }, - 'cflags': [ - '-g', - '-Wall', - '-Wextra', - '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/upb', - '-Isrc/core/ext/upb-generated', - '-fvisibility=hidden', - ], - 'ldflags': [ - '-g', - ], - 'cflags_c': [ - '-std=c99' - ], - 'cflags_cc': [ - '-std=c++1y' - ], - 'include_dirs': [ - 'deps/grpc', - 'deps/grpc/include', - 'deps/grpc/src/core/ext/upb-generated', - 'deps/grpc/third_party/abseil-cpp', - 'deps/grpc/third_party/address_sorting/include', - 'deps/grpc/third_party/cares', - 'deps/grpc/third_party/cares/cares', - 'deps/grpc/third_party/upb', - 'deps/grpc/third_party/upb/generated_for_cmake', - ], - 'defines': [ - 'GPR_BACKWARDS_COMPATIBILITY_MODE', - 'GRPC_ARES=1', - 'GRPC_UV', - 'GRPC_NODE_VERSION="1.24.0-pre1"', - 'CARES_STATICLIB', - 'CARES_SYMBOL_HIDING' - ], - 'defines!': [ - 'OPENSSL_THREADS' - ], - 'conditions': [ - ['grpc_gcov=="true"', { - 'cflags': [ - '-O0', - '-fprofile-arcs', - '-ftest-coverage', - '-Wno-return-type', - ], - 'defines': [ - '_DEBUG', - 'DEBUG', - 'GPR_GCOV', - ], - 'ldflags': [ - '-fprofile-arcs', - '-ftest-coverage', - '-rdynamic', - '-lstdc++', - ], - }], - ['grpc_alpine=="true"', { - 'defines': [ - 'GPR_MUSL_LIBC_COMPAT' - ] - }], - # This is the condition for using boringssl - ['OS=="win" or runtime=="electron"', { - "include_dirs": [ - "deps/grpc/third_party/boringssl/include" - ], - "defines": [ - 'OPENSSL_NO_ASM' - ] - }, { - 'conditions': [ - ["target_arch=='ia32'", { - "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ] - }], - ["target_arch=='x64'", { - "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ] - }], - ["target_arch=='arm'", { - "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ] - }], - ['grpc_alpn=="true"', { - 'defines': [ - 'TSI_OPENSSL_ALPN_SUPPORT=1' - ], - }, { - 'defines': [ - 'TSI_OPENSSL_ALPN_SUPPORT=0' - ], - }] - ], - 'include_dirs': [ - '<(node_root_dir)/deps/openssl/openssl/include', - ] - }], - ['OS == "win"', { - "include_dirs": [ - "deps/grpc/third_party/zlib" - ], - "defines": [ - '_WIN32_WINNT=0x0600', - 'WIN32_LEAN_AND_MEAN', - '_HAS_EXCEPTIONS=0', - 'UNICODE', - '_UNICODE', - 'NOMINMAX', - ], - "msvs_settings": { - 'VCCLCompilerTool': { - 'RuntimeLibrary': 1, # static debug - } - }, - "libraries": [ - "ws2_32" - ] - }, { # OS != "win" - 'include_dirs': [ - '<(node_root_dir)/deps/zlib' - ] - }], - ['OS == "mac"', { - 'xcode_settings': { - 'OTHER_CFLAGS': [ - '-g', - '-Wall', - '-Wextra', - '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/upb', - '-Isrc/core/ext/upb-generated', - '-fvisibility=hidden', - ], - 'OTHER_CPLUSPLUSFLAGS': [ - '-g', - '-Wall', - '-Wextra', - '-DOSATOMIC_USE_INLINED=1', - '-Ithird_party/upb', - '-Isrc/core/ext/upb-generated', - '-fvisibility=hidden', - '-stdlib=libc++', - '-std=c++1y', - '-Wno-error=deprecated-declarations' - ], - }, - }] - ] - }, - 'conditions': [ - ['OS=="win" or runtime=="electron"', { - 'targets': [ - { - 'target_name': 'boringssl', - 'product_prefix': 'lib', - 'type': 'static_library', - 'cflags': [ - '-Wno-implicit-fallthrough' - ], - 'defines': [ - '_XOPEN_SOURCE=700' - ], - 'dependencies': [ - ], - 'sources': [ - 'deps/grpc/src/boringssl/err_data.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_bitstr.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_bool.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_d2i_fp.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_dup.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_enum.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_gentm.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_i2d_fp.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_int.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_mbstr.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_object.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_octet.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_print.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_strnid.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_time.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_type.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_utctm.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/a_utf8.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/asn1_lib.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/asn1_par.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/asn_pack.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/f_enum.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/f_int.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/f_string.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_dec.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_enc.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_fre.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_new.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_typ.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/tasn_utl.c', - 'deps/grpc/third_party/boringssl/crypto/asn1/time_support.c', - 'deps/grpc/third_party/boringssl/crypto/base64/base64.c', - 'deps/grpc/third_party/boringssl/crypto/bio/bio.c', - 'deps/grpc/third_party/boringssl/crypto/bio/bio_mem.c', - 'deps/grpc/third_party/boringssl/crypto/bio/connect.c', - 'deps/grpc/third_party/boringssl/crypto/bio/fd.c', - 'deps/grpc/third_party/boringssl/crypto/bio/file.c', - 'deps/grpc/third_party/boringssl/crypto/bio/hexdump.c', - 'deps/grpc/third_party/boringssl/crypto/bio/pair.c', - 'deps/grpc/third_party/boringssl/crypto/bio/printf.c', - 'deps/grpc/third_party/boringssl/crypto/bio/socket.c', - 'deps/grpc/third_party/boringssl/crypto/bio/socket_helper.c', - 'deps/grpc/third_party/boringssl/crypto/bn_extra/bn_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/bn_extra/convert.c', - 'deps/grpc/third_party/boringssl/crypto/buf/buf.c', - 'deps/grpc/third_party/boringssl/crypto/bytestring/asn1_compat.c', - 'deps/grpc/third_party/boringssl/crypto/bytestring/ber.c', - 'deps/grpc/third_party/boringssl/crypto/bytestring/cbb.c', - 'deps/grpc/third_party/boringssl/crypto/bytestring/cbs.c', - 'deps/grpc/third_party/boringssl/crypto/chacha/chacha.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/cipher_extra.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/derive_key.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesccm.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesctrhmac.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_aesgcmsiv.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_chacha20poly1305.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_null.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_rc2.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_rc4.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_ssl3.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/e_tls.c', - 'deps/grpc/third_party/boringssl/crypto/cipher_extra/tls_cbc.c', - 'deps/grpc/third_party/boringssl/crypto/cmac/cmac.c', - 'deps/grpc/third_party/boringssl/crypto/conf/conf.c', - 'deps/grpc/third_party/boringssl/crypto/cpu-aarch64-fuchsia.c', - 'deps/grpc/third_party/boringssl/crypto/cpu-aarch64-linux.c', - 'deps/grpc/third_party/boringssl/crypto/cpu-arm-linux.c', - 'deps/grpc/third_party/boringssl/crypto/cpu-arm.c', - 'deps/grpc/third_party/boringssl/crypto/cpu-intel.c', - 'deps/grpc/third_party/boringssl/crypto/cpu-ppc64le.c', - 'deps/grpc/third_party/boringssl/crypto/crypto.c', - 'deps/grpc/third_party/boringssl/crypto/curve25519/spake25519.c', - 'deps/grpc/third_party/boringssl/crypto/dh/check.c', - 'deps/grpc/third_party/boringssl/crypto/dh/dh.c', - 'deps/grpc/third_party/boringssl/crypto/dh/dh_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/dh/params.c', - 'deps/grpc/third_party/boringssl/crypto/digest_extra/digest_extra.c', - 'deps/grpc/third_party/boringssl/crypto/dsa/dsa.c', - 'deps/grpc/third_party/boringssl/crypto/dsa/dsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/ec_extra/ec_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/ecdh/ecdh.c', - 'deps/grpc/third_party/boringssl/crypto/ecdsa_extra/ecdsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/engine/engine.c', - 'deps/grpc/third_party/boringssl/crypto/err/err.c', - 'deps/grpc/third_party/boringssl/crypto/evp/digestsign.c', - 'deps/grpc/third_party/boringssl/crypto/evp/evp.c', - 'deps/grpc/third_party/boringssl/crypto/evp/evp_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/evp/evp_ctx.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_dsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_ec.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_ec_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_ed25519.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_ed25519_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_rsa.c', - 'deps/grpc/third_party/boringssl/crypto/evp/p_rsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/evp/pbkdf.c', - 'deps/grpc/third_party/boringssl/crypto/evp/print.c', - 'deps/grpc/third_party/boringssl/crypto/evp/scrypt.c', - 'deps/grpc/third_party/boringssl/crypto/evp/sign.c', - 'deps/grpc/third_party/boringssl/crypto/ex_data.c', - 'deps/grpc/third_party/boringssl/crypto/fipsmodule/bcm.c', - 'deps/grpc/third_party/boringssl/crypto/fipsmodule/is_fips.c', - 'deps/grpc/third_party/boringssl/crypto/hkdf/hkdf.c', - 'deps/grpc/third_party/boringssl/crypto/lhash/lhash.c', - 'deps/grpc/third_party/boringssl/crypto/mem.c', - 'deps/grpc/third_party/boringssl/crypto/obj/obj.c', - 'deps/grpc/third_party/boringssl/crypto/obj/obj_xref.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_all.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_info.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_lib.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_oth.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_pk8.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_pkey.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_x509.c', - 'deps/grpc/third_party/boringssl/crypto/pem/pem_xaux.c', - 'deps/grpc/third_party/boringssl/crypto/pkcs7/pkcs7.c', - 'deps/grpc/third_party/boringssl/crypto/pkcs7/pkcs7_x509.c', - 'deps/grpc/third_party/boringssl/crypto/pkcs8/p5_pbev2.c', - 'deps/grpc/third_party/boringssl/crypto/pkcs8/pkcs8.c', - 'deps/grpc/third_party/boringssl/crypto/pkcs8/pkcs8_x509.c', - 'deps/grpc/third_party/boringssl/crypto/poly1305/poly1305.c', - 'deps/grpc/third_party/boringssl/crypto/poly1305/poly1305_arm.c', - 'deps/grpc/third_party/boringssl/crypto/poly1305/poly1305_vec.c', - 'deps/grpc/third_party/boringssl/crypto/pool/pool.c', - 'deps/grpc/third_party/boringssl/crypto/rand_extra/deterministic.c', - 'deps/grpc/third_party/boringssl/crypto/rand_extra/forkunsafe.c', - 'deps/grpc/third_party/boringssl/crypto/rand_extra/fuchsia.c', - 'deps/grpc/third_party/boringssl/crypto/rand_extra/rand_extra.c', - 'deps/grpc/third_party/boringssl/crypto/rand_extra/windows.c', - 'deps/grpc/third_party/boringssl/crypto/rc4/rc4.c', - 'deps/grpc/third_party/boringssl/crypto/refcount_c11.c', - 'deps/grpc/third_party/boringssl/crypto/refcount_lock.c', - 'deps/grpc/third_party/boringssl/crypto/rsa_extra/rsa_asn1.c', - 'deps/grpc/third_party/boringssl/crypto/stack/stack.c', - 'deps/grpc/third_party/boringssl/crypto/thread.c', - 'deps/grpc/third_party/boringssl/crypto/thread_none.c', - 'deps/grpc/third_party/boringssl/crypto/thread_pthread.c', - 'deps/grpc/third_party/boringssl/crypto/thread_win.c', - 'deps/grpc/third_party/boringssl/crypto/x509/a_digest.c', - 'deps/grpc/third_party/boringssl/crypto/x509/a_sign.c', - 'deps/grpc/third_party/boringssl/crypto/x509/a_strex.c', - 'deps/grpc/third_party/boringssl/crypto/x509/a_verify.c', - 'deps/grpc/third_party/boringssl/crypto/x509/algorithm.c', - 'deps/grpc/third_party/boringssl/crypto/x509/asn1_gen.c', - 'deps/grpc/third_party/boringssl/crypto/x509/by_dir.c', - 'deps/grpc/third_party/boringssl/crypto/x509/by_file.c', - 'deps/grpc/third_party/boringssl/crypto/x509/i2d_pr.c', - 'deps/grpc/third_party/boringssl/crypto/x509/rsa_pss.c', - 'deps/grpc/third_party/boringssl/crypto/x509/t_crl.c', - 'deps/grpc/third_party/boringssl/crypto/x509/t_req.c', - 'deps/grpc/third_party/boringssl/crypto/x509/t_x509.c', - 'deps/grpc/third_party/boringssl/crypto/x509/t_x509a.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_att.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_cmp.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_d2.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_def.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_ext.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_lu.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_obj.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_r2x.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_req.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_set.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_trs.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_txt.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_v3.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_vfy.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509_vpm.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509cset.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509name.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509rset.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x509spki.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_algor.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_all.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_attrib.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_crl.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_exten.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_info.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_name.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_pkey.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_pubkey.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_req.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_sig.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_spki.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_val.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_x509.c', - 'deps/grpc/third_party/boringssl/crypto/x509/x_x509a.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/pcy_cache.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/pcy_data.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/pcy_lib.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/pcy_map.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/pcy_node.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/pcy_tree.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_akey.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_akeya.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_alt.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_bcons.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_bitst.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_conf.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_cpols.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_crld.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_enum.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_extku.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_genn.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_ia5.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_info.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_int.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_lib.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_ncons.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_pci.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_pcia.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_pcons.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_pku.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_pmaps.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_prn.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_purp.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_skey.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_sxnet.c', - 'deps/grpc/third_party/boringssl/crypto/x509v3/v3_utl.c', - 'deps/grpc/third_party/boringssl/ssl/bio_ssl.cc', - 'deps/grpc/third_party/boringssl/ssl/custom_extensions.cc', - 'deps/grpc/third_party/boringssl/ssl/d1_both.cc', - 'deps/grpc/third_party/boringssl/ssl/d1_lib.cc', - 'deps/grpc/third_party/boringssl/ssl/d1_pkt.cc', - 'deps/grpc/third_party/boringssl/ssl/d1_srtp.cc', - 'deps/grpc/third_party/boringssl/ssl/dtls_method.cc', - 'deps/grpc/third_party/boringssl/ssl/dtls_record.cc', - 'deps/grpc/third_party/boringssl/ssl/handoff.cc', - 'deps/grpc/third_party/boringssl/ssl/handshake.cc', - 'deps/grpc/third_party/boringssl/ssl/handshake_client.cc', - 'deps/grpc/third_party/boringssl/ssl/handshake_server.cc', - 'deps/grpc/third_party/boringssl/ssl/s3_both.cc', - 'deps/grpc/third_party/boringssl/ssl/s3_lib.cc', - 'deps/grpc/third_party/boringssl/ssl/s3_pkt.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_aead_ctx.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_asn1.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_buffer.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_cert.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_cipher.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_file.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_key_share.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_lib.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_privkey.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_session.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_stat.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_transcript.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_versions.cc', - 'deps/grpc/third_party/boringssl/ssl/ssl_x509.cc', - 'deps/grpc/third_party/boringssl/ssl/t1_enc.cc', - 'deps/grpc/third_party/boringssl/ssl/t1_lib.cc', - 'deps/grpc/third_party/boringssl/ssl/tls13_both.cc', - 'deps/grpc/third_party/boringssl/ssl/tls13_client.cc', - 'deps/grpc/third_party/boringssl/ssl/tls13_enc.cc', - 'deps/grpc/third_party/boringssl/ssl/tls13_server.cc', - 'deps/grpc/third_party/boringssl/ssl/tls_method.cc', - 'deps/grpc/third_party/boringssl/ssl/tls_record.cc', - 'deps/grpc/third_party/boringssl/third_party/fiat/curve25519.c', - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - } - }] - ] - }, - ], - }], - ['OS == "win" and runtime!="electron"', { - 'targets': [ - { - # IMPORTANT WINDOWS BUILD INFORMATION - # This library does not build on Windows without modifying the Node - # development packages that node-gyp downloads in order to build. - # Due to https://github.com/nodejs/node/issues/4932, the headers for - # BoringSSL conflict with the OpenSSL headers included by default - # when including the Node headers. The remedy for this is to remove - # the OpenSSL headers, from the downloaded Node development package, - # which is typically located in `.node-gyp` in your home directory. - # - # This is not true of Electron, which does not have OpenSSL headers. - 'target_name': 'WINDOWS_BUILD_WARNING', - 'rules': [ - { - 'rule_name': 'WINDOWS_BUILD_WARNING', - 'extension': 'S', - 'inputs': [ - 'package.json' - ], - 'outputs': [ - 'ignore_this_part' - ], - 'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/'] - } - ] - }, - ] - }], - ['OS == "win"', { - 'targets': [ - # Only want to compile zlib under Windows - { - 'target_name': 'z', - 'product_prefix': 'lib', - 'type': 'static_library', - 'dependencies': [ - ], - 'sources': [ - 'deps/grpc/third_party/zlib/adler32.c', - 'deps/grpc/third_party/zlib/compress.c', - 'deps/grpc/third_party/zlib/crc32.c', - 'deps/grpc/third_party/zlib/deflate.c', - 'deps/grpc/third_party/zlib/gzclose.c', - 'deps/grpc/third_party/zlib/gzlib.c', - 'deps/grpc/third_party/zlib/gzread.c', - 'deps/grpc/third_party/zlib/gzwrite.c', - 'deps/grpc/third_party/zlib/infback.c', - 'deps/grpc/third_party/zlib/inffast.c', - 'deps/grpc/third_party/zlib/inflate.c', - 'deps/grpc/third_party/zlib/inftrees.c', - 'deps/grpc/third_party/zlib/trees.c', - 'deps/grpc/third_party/zlib/uncompr.c', - 'deps/grpc/third_party/zlib/zutil.c', - ] - }, - ] - }] - ], - 'targets': [ - { - 'target_name': 'ares', - 'product_prefix': 'lib', - 'type': 'static_library', - 'sources': [ - 'deps/grpc/third_party/cares/cares/ares__close_sockets.c', - 'deps/grpc/third_party/cares/cares/ares__get_hostent.c', - 'deps/grpc/third_party/cares/cares/ares__read_line.c', - 'deps/grpc/third_party/cares/cares/ares__timeval.c', - 'deps/grpc/third_party/cares/cares/ares_cancel.c', - 'deps/grpc/third_party/cares/cares/ares_create_query.c', - 'deps/grpc/third_party/cares/cares/ares_data.c', - 'deps/grpc/third_party/cares/cares/ares_destroy.c', - 'deps/grpc/third_party/cares/cares/ares_expand_name.c', - 'deps/grpc/third_party/cares/cares/ares_expand_string.c', - 'deps/grpc/third_party/cares/cares/ares_fds.c', - 'deps/grpc/third_party/cares/cares/ares_free_hostent.c', - 'deps/grpc/third_party/cares/cares/ares_free_string.c', - 'deps/grpc/third_party/cares/cares/ares_getenv.c', - 'deps/grpc/third_party/cares/cares/ares_gethostbyaddr.c', - 'deps/grpc/third_party/cares/cares/ares_gethostbyname.c', - 'deps/grpc/third_party/cares/cares/ares_getnameinfo.c', - 'deps/grpc/third_party/cares/cares/ares_getopt.c', - 'deps/grpc/third_party/cares/cares/ares_getsock.c', - 'deps/grpc/third_party/cares/cares/ares_init.c', - 'deps/grpc/third_party/cares/cares/ares_library_init.c', - 'deps/grpc/third_party/cares/cares/ares_llist.c', - 'deps/grpc/third_party/cares/cares/ares_mkquery.c', - 'deps/grpc/third_party/cares/cares/ares_nowarn.c', - 'deps/grpc/third_party/cares/cares/ares_options.c', - 'deps/grpc/third_party/cares/cares/ares_parse_a_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_aaaa_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_mx_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_naptr_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_ns_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_ptr_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_soa_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_srv_reply.c', - 'deps/grpc/third_party/cares/cares/ares_parse_txt_reply.c', - 'deps/grpc/third_party/cares/cares/ares_platform.c', - 'deps/grpc/third_party/cares/cares/ares_process.c', - 'deps/grpc/third_party/cares/cares/ares_query.c', - 'deps/grpc/third_party/cares/cares/ares_search.c', - 'deps/grpc/third_party/cares/cares/ares_send.c', - 'deps/grpc/third_party/cares/cares/ares_strcasecmp.c', - 'deps/grpc/third_party/cares/cares/ares_strdup.c', - 'deps/grpc/third_party/cares/cares/ares_strerror.c', - 'deps/grpc/third_party/cares/cares/ares_strsplit.c', - 'deps/grpc/third_party/cares/cares/ares_timeout.c', - 'deps/grpc/third_party/cares/cares/ares_version.c', - 'deps/grpc/third_party/cares/cares/ares_writev.c', - 'deps/grpc/third_party/cares/cares/bitncmp.c', - 'deps/grpc/third_party/cares/cares/inet_net_pton.c', - 'deps/grpc/third_party/cares/cares/inet_ntop.c', - 'deps/grpc/third_party/cares/cares/windows_port.c', - ], - 'defines': [ - '_GNU_SOURCE' - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - }, - 'include_dirs': [ - 'deps/grpc/third_party/cares/config_darwin' - ], - 'defines': [ - 'HAVE_CONFIG_H' - ] - }], - ['OS == "linux"', { - 'include_dirs': [ - 'deps/grpc/third_party/cares/config_linux' - ], - 'defines': [ - 'HAVE_CONFIG_H' - ] - }], - ['OS == "win"', { - 'include_dirs': [ - 'deps/grpc/third_party/cares/config_windows' - ], - 'defines': [ - 'HAVE_CONFIG_H' - ] - }] - ] - }, - { - 'target_name': 'address_sorting', - 'product_prefix': 'lib', - 'type': 'static_library', - 'dependencies': [ - ], - 'sources': [ - 'deps/grpc/third_party/address_sorting/address_sorting.c', - 'deps/grpc/third_party/address_sorting/address_sorting_posix.c', - 'deps/grpc/third_party/address_sorting/address_sorting_windows.c', - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - } - }] - ] - }, - { - 'target_name': 'gpr', - 'product_prefix': 'lib', - 'type': 'static_library', - 'dependencies': [ - ], - 'sources': [ - 'deps/grpc/src/core/lib/gpr/alloc.cc', - 'deps/grpc/src/core/lib/gpr/atm.cc', - 'deps/grpc/src/core/lib/gpr/cpu_iphone.cc', - 'deps/grpc/src/core/lib/gpr/cpu_linux.cc', - 'deps/grpc/src/core/lib/gpr/cpu_posix.cc', - 'deps/grpc/src/core/lib/gpr/cpu_windows.cc', - 'deps/grpc/src/core/lib/gpr/env_linux.cc', - 'deps/grpc/src/core/lib/gpr/env_posix.cc', - 'deps/grpc/src/core/lib/gpr/env_windows.cc', - 'deps/grpc/src/core/lib/gpr/log.cc', - 'deps/grpc/src/core/lib/gpr/log_android.cc', - 'deps/grpc/src/core/lib/gpr/log_linux.cc', - 'deps/grpc/src/core/lib/gpr/log_posix.cc', - 'deps/grpc/src/core/lib/gpr/log_windows.cc', - 'deps/grpc/src/core/lib/gpr/mpscq.cc', - 'deps/grpc/src/core/lib/gpr/murmur_hash.cc', - 'deps/grpc/src/core/lib/gpr/string.cc', - 'deps/grpc/src/core/lib/gpr/string_posix.cc', - 'deps/grpc/src/core/lib/gpr/string_util_windows.cc', - 'deps/grpc/src/core/lib/gpr/string_windows.cc', - 'deps/grpc/src/core/lib/gpr/sync.cc', - 'deps/grpc/src/core/lib/gpr/sync_posix.cc', - 'deps/grpc/src/core/lib/gpr/sync_windows.cc', - 'deps/grpc/src/core/lib/gpr/time.cc', - 'deps/grpc/src/core/lib/gpr/time_posix.cc', - 'deps/grpc/src/core/lib/gpr/time_precise.cc', - 'deps/grpc/src/core/lib/gpr/time_windows.cc', - 'deps/grpc/src/core/lib/gpr/tls_pthread.cc', - 'deps/grpc/src/core/lib/gpr/tmpfile_msys.cc', - 'deps/grpc/src/core/lib/gpr/tmpfile_posix.cc', - 'deps/grpc/src/core/lib/gpr/tmpfile_windows.cc', - 'deps/grpc/src/core/lib/gpr/wrap_memcpy.cc', - 'deps/grpc/src/core/lib/gprpp/arena.cc', - 'deps/grpc/src/core/lib/gprpp/fork.cc', - 'deps/grpc/src/core/lib/gprpp/global_config_env.cc', - 'deps/grpc/src/core/lib/gprpp/host_port.cc', - 'deps/grpc/src/core/lib/gprpp/thd_posix.cc', - 'deps/grpc/src/core/lib/gprpp/thd_windows.cc', - 'deps/grpc/src/core/lib/profiling/basic_timers.cc', - 'deps/grpc/src/core/lib/profiling/stap_timers.cc', - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - } - }] - ] - }, - { - 'target_name': 'grpc', - 'product_prefix': 'lib', - 'type': 'static_library', - 'dependencies': [ - 'gpr', - ], - 'sources': [ - 'deps/grpc/src/core/lib/surface/init.cc', - 'deps/grpc/src/core/lib/avl/avl.cc', - 'deps/grpc/src/core/lib/backoff/backoff.cc', - 'deps/grpc/src/core/lib/channel/channel_args.cc', - 'deps/grpc/src/core/lib/channel/channel_stack.cc', - 'deps/grpc/src/core/lib/channel/channel_stack_builder.cc', - 'deps/grpc/src/core/lib/channel/channel_trace.cc', - 'deps/grpc/src/core/lib/channel/channelz.cc', - 'deps/grpc/src/core/lib/channel/channelz_registry.cc', - 'deps/grpc/src/core/lib/channel/connected_channel.cc', - 'deps/grpc/src/core/lib/channel/handshaker.cc', - 'deps/grpc/src/core/lib/channel/handshaker_registry.cc', - 'deps/grpc/src/core/lib/channel/status_util.cc', - 'deps/grpc/src/core/lib/compression/compression.cc', - 'deps/grpc/src/core/lib/compression/compression_args.cc', - 'deps/grpc/src/core/lib/compression/compression_internal.cc', - 'deps/grpc/src/core/lib/compression/message_compress.cc', - 'deps/grpc/src/core/lib/compression/stream_compression.cc', - 'deps/grpc/src/core/lib/compression/stream_compression_gzip.cc', - 'deps/grpc/src/core/lib/compression/stream_compression_identity.cc', - 'deps/grpc/src/core/lib/debug/stats.cc', - 'deps/grpc/src/core/lib/debug/stats_data.cc', - 'deps/grpc/src/core/lib/http/format_request.cc', - 'deps/grpc/src/core/lib/http/httpcli.cc', - 'deps/grpc/src/core/lib/http/parser.cc', - 'deps/grpc/src/core/lib/iomgr/buffer_list.cc', - 'deps/grpc/src/core/lib/iomgr/call_combiner.cc', - 'deps/grpc/src/core/lib/iomgr/cfstream_handle.cc', - 'deps/grpc/src/core/lib/iomgr/combiner.cc', - 'deps/grpc/src/core/lib/iomgr/endpoint.cc', - 'deps/grpc/src/core/lib/iomgr/endpoint_cfstream.cc', - 'deps/grpc/src/core/lib/iomgr/endpoint_pair_posix.cc', - 'deps/grpc/src/core/lib/iomgr/endpoint_pair_uv.cc', - 'deps/grpc/src/core/lib/iomgr/endpoint_pair_windows.cc', - 'deps/grpc/src/core/lib/iomgr/error.cc', - 'deps/grpc/src/core/lib/iomgr/error_cfstream.cc', - 'deps/grpc/src/core/lib/iomgr/ev_epoll1_linux.cc', - 'deps/grpc/src/core/lib/iomgr/ev_epollex_linux.cc', - 'deps/grpc/src/core/lib/iomgr/ev_poll_posix.cc', - 'deps/grpc/src/core/lib/iomgr/ev_posix.cc', - 'deps/grpc/src/core/lib/iomgr/ev_windows.cc', - 'deps/grpc/src/core/lib/iomgr/exec_ctx.cc', - 'deps/grpc/src/core/lib/iomgr/executor.cc', - 'deps/grpc/src/core/lib/iomgr/executor/mpmcqueue.cc', - 'deps/grpc/src/core/lib/iomgr/executor/threadpool.cc', - 'deps/grpc/src/core/lib/iomgr/fork_posix.cc', - 'deps/grpc/src/core/lib/iomgr/fork_windows.cc', - 'deps/grpc/src/core/lib/iomgr/gethostname_fallback.cc', - 'deps/grpc/src/core/lib/iomgr/gethostname_host_name_max.cc', - 'deps/grpc/src/core/lib/iomgr/gethostname_sysconf.cc', - 'deps/grpc/src/core/lib/iomgr/grpc_if_nametoindex_posix.cc', - 'deps/grpc/src/core/lib/iomgr/grpc_if_nametoindex_unsupported.cc', - 'deps/grpc/src/core/lib/iomgr/internal_errqueue.cc', - 'deps/grpc/src/core/lib/iomgr/iocp_windows.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_custom.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_internal.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_posix.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_posix_cfstream.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_uv.cc', - 'deps/grpc/src/core/lib/iomgr/iomgr_windows.cc', - 'deps/grpc/src/core/lib/iomgr/is_epollexclusive_available.cc', - 'deps/grpc/src/core/lib/iomgr/load_file.cc', - 'deps/grpc/src/core/lib/iomgr/lockfree_event.cc', - 'deps/grpc/src/core/lib/iomgr/polling_entity.cc', - 'deps/grpc/src/core/lib/iomgr/pollset.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_custom.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_set.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_set_custom.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_set_windows.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_uv.cc', - 'deps/grpc/src/core/lib/iomgr/pollset_windows.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address_custom.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address_posix.cc', - 'deps/grpc/src/core/lib/iomgr/resolve_address_windows.cc', - 'deps/grpc/src/core/lib/iomgr/resource_quota.cc', - 'deps/grpc/src/core/lib/iomgr/sockaddr_utils.cc', - 'deps/grpc/src/core/lib/iomgr/socket_factory_posix.cc', - 'deps/grpc/src/core/lib/iomgr/socket_mutator.cc', - 'deps/grpc/src/core/lib/iomgr/socket_utils_common_posix.cc', - 'deps/grpc/src/core/lib/iomgr/socket_utils_linux.cc', - 'deps/grpc/src/core/lib/iomgr/socket_utils_posix.cc', - 'deps/grpc/src/core/lib/iomgr/socket_utils_uv.cc', - 'deps/grpc/src/core/lib/iomgr/socket_utils_windows.cc', - 'deps/grpc/src/core/lib/iomgr/socket_windows.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client_cfstream.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client_custom.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client_posix.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_client_windows.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_custom.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_posix.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_custom.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_posix.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_common.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_ifaddrs.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_utils_posix_noifaddrs.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_server_windows.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_uv.cc', - 'deps/grpc/src/core/lib/iomgr/tcp_windows.cc', - 'deps/grpc/src/core/lib/iomgr/time_averaged_stats.cc', - 'deps/grpc/src/core/lib/iomgr/timer.cc', - 'deps/grpc/src/core/lib/iomgr/timer_custom.cc', - 'deps/grpc/src/core/lib/iomgr/timer_generic.cc', - 'deps/grpc/src/core/lib/iomgr/timer_heap.cc', - 'deps/grpc/src/core/lib/iomgr/timer_manager.cc', - 'deps/grpc/src/core/lib/iomgr/timer_uv.cc', - 'deps/grpc/src/core/lib/iomgr/udp_server.cc', - 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix.cc', - 'deps/grpc/src/core/lib/iomgr/unix_sockets_posix_noop.cc', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_eventfd.cc', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_nospecial.cc', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_pipe.cc', - 'deps/grpc/src/core/lib/iomgr/wakeup_fd_posix.cc', - 'deps/grpc/src/core/lib/json/json.cc', - 'deps/grpc/src/core/lib/json/json_reader.cc', - 'deps/grpc/src/core/lib/json/json_string.cc', - 'deps/grpc/src/core/lib/json/json_writer.cc', - 'deps/grpc/src/core/lib/slice/b64.cc', - 'deps/grpc/src/core/lib/slice/percent_encoding.cc', - 'deps/grpc/src/core/lib/slice/slice.cc', - 'deps/grpc/src/core/lib/slice/slice_buffer.cc', - 'deps/grpc/src/core/lib/slice/slice_intern.cc', - 'deps/grpc/src/core/lib/slice/slice_string_helpers.cc', - 'deps/grpc/src/core/lib/surface/api_trace.cc', - 'deps/grpc/src/core/lib/surface/byte_buffer.cc', - 'deps/grpc/src/core/lib/surface/byte_buffer_reader.cc', - 'deps/grpc/src/core/lib/surface/call.cc', - 'deps/grpc/src/core/lib/surface/call_details.cc', - 'deps/grpc/src/core/lib/surface/call_log_batch.cc', - 'deps/grpc/src/core/lib/surface/channel.cc', - 'deps/grpc/src/core/lib/surface/channel_init.cc', - 'deps/grpc/src/core/lib/surface/channel_ping.cc', - 'deps/grpc/src/core/lib/surface/channel_stack_type.cc', - 'deps/grpc/src/core/lib/surface/completion_queue.cc', - 'deps/grpc/src/core/lib/surface/completion_queue_factory.cc', - 'deps/grpc/src/core/lib/surface/event_string.cc', - 'deps/grpc/src/core/lib/surface/lame_client.cc', - 'deps/grpc/src/core/lib/surface/metadata_array.cc', - 'deps/grpc/src/core/lib/surface/server.cc', - 'deps/grpc/src/core/lib/surface/validate_metadata.cc', - 'deps/grpc/src/core/lib/surface/version.cc', - 'deps/grpc/src/core/lib/transport/bdp_estimator.cc', - 'deps/grpc/src/core/lib/transport/byte_stream.cc', - 'deps/grpc/src/core/lib/transport/connectivity_state.cc', - 'deps/grpc/src/core/lib/transport/error_utils.cc', - 'deps/grpc/src/core/lib/transport/metadata.cc', - 'deps/grpc/src/core/lib/transport/metadata_batch.cc', - 'deps/grpc/src/core/lib/transport/pid_controller.cc', - 'deps/grpc/src/core/lib/transport/static_metadata.cc', - 'deps/grpc/src/core/lib/transport/status_conversion.cc', - 'deps/grpc/src/core/lib/transport/status_metadata.cc', - 'deps/grpc/src/core/lib/transport/timeout_encoding.cc', - 'deps/grpc/src/core/lib/transport/transport.cc', - 'deps/grpc/src/core/lib/transport/transport_op_string.cc', - 'deps/grpc/src/core/lib/uri/uri_parser.cc', - 'deps/grpc/src/core/lib/debug/trace.cc', - 'deps/grpc/src/core/ext/transport/chttp2/server/secure/server_secure_chttp2.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_decoder.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/bin_encoder.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_plugin.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/chttp2_transport.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/context_list.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/flow_control.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_data.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_goaway.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_ping.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_rst_stream.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_settings.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/frame_window_update.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_encoder.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_parser.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/hpack_table.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/http2_settings.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/huffsyms.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/incoming_metadata.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/parsing.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/stream_lists.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/stream_map.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/varint.cc', - 'deps/grpc/src/core/ext/transport/chttp2/transport/writing.cc', - 'deps/grpc/src/core/ext/transport/chttp2/alpn/alpn.cc', - 'deps/grpc/src/core/ext/filters/http/client/http_client_filter.cc', - 'deps/grpc/src/core/ext/filters/http/http_filters_plugin.cc', - 'deps/grpc/src/core/ext/filters/http/message_compress/message_compress_filter.cc', - 'deps/grpc/src/core/ext/filters/http/server/http_server_filter.cc', - 'deps/grpc/src/core/lib/http/httpcli_security_connector.cc', - 'deps/grpc/src/core/lib/security/context/security_context.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/alts_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/composite/composite_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/credentials_metadata.cc', - 'deps/grpc/src/core/lib/security/credentials/fake/fake_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/google_default/credentials_generic.cc', - 'deps/grpc/src/core/lib/security/credentials/google_default/google_default_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/iam/iam_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/jwt/json_token.cc', - 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/jwt/jwt_verifier.cc', - 'deps/grpc/src/core/lib/security/credentials/local/local_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/oauth2/oauth2_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/plugin/plugin_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/ssl/ssl_credentials.cc', - 'deps/grpc/src/core/lib/security/credentials/tls/grpc_tls_credentials_options.cc', - 'deps/grpc/src/core/lib/security/credentials/tls/spiffe_credentials.cc', - 'deps/grpc/src/core/lib/security/security_connector/alts/alts_security_connector.cc', - 'deps/grpc/src/core/lib/security/security_connector/fake/fake_security_connector.cc', - 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_fallback.cc', - 'deps/grpc/src/core/lib/security/security_connector/load_system_roots_linux.cc', - 'deps/grpc/src/core/lib/security/security_connector/local/local_security_connector.cc', - 'deps/grpc/src/core/lib/security/security_connector/security_connector.cc', - 'deps/grpc/src/core/lib/security/security_connector/ssl/ssl_security_connector.cc', - 'deps/grpc/src/core/lib/security/security_connector/ssl_utils.cc', - 'deps/grpc/src/core/lib/security/security_connector/ssl_utils_config.cc', - 'deps/grpc/src/core/lib/security/security_connector/tls/spiffe_security_connector.cc', - 'deps/grpc/src/core/lib/security/transport/client_auth_filter.cc', - 'deps/grpc/src/core/lib/security/transport/secure_endpoint.cc', - 'deps/grpc/src/core/lib/security/transport/security_handshaker.cc', - 'deps/grpc/src/core/lib/security/transport/server_auth_filter.cc', - 'deps/grpc/src/core/lib/security/transport/target_authority_table.cc', - 'deps/grpc/src/core/lib/security/transport/tsi_error.cc', - 'deps/grpc/src/core/lib/security/util/json_util.cc', - 'deps/grpc/src/core/lib/surface/init_secure.cc', - 'deps/grpc/src/core/tsi/alts/crypt/aes_gcm.cc', - 'deps/grpc/src/core/tsi/alts/crypt/gsec.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_counter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_crypter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_frame_protector.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_record_protocol_crypter_common.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_seal_privacy_integrity_crypter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/alts_unseal_privacy_integrity_crypter.cc', - 'deps/grpc/src/core/tsi/alts/frame_protector/frame_handler.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_handshaker_client.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_shared_resource.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_handshaker.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_privacy_integrity_record_protocol.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.cc', - 'deps/grpc/src/core/tsi/alts/zero_copy_frame_protector/alts_zero_copy_grpc_protector.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_linux.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_no_op.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/check_gcp_environment_windows.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_client_options.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_options.cc', - 'deps/grpc/src/core/lib/security/credentials/alts/grpc_alts_credentials_server_options.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/alts_tsi_utils.cc', - 'deps/grpc/src/core/tsi/alts/handshaker/transport_security_common_api.cc', - 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/gcp/altscontext.upb.c', - 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/gcp/handshaker.upb.c', - 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/gcp/transport_security_common.upb.c', - 'deps/grpc/third_party/upb/upb/decode.c', - 'deps/grpc/third_party/upb/upb/encode.c', - 'deps/grpc/third_party/upb/upb/msg.c', - 'deps/grpc/third_party/upb/upb/port.c', - 'deps/grpc/third_party/upb/upb/table.c', - 'deps/grpc/third_party/upb/upb/upb.c', - 'deps/grpc/src/core/tsi/transport_security.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/insecure/channel_create_posix.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/authority.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/chttp2_connector.cc', - 'deps/grpc/src/core/ext/filters/client_channel/backend_metric.cc', - 'deps/grpc/src/core/ext/filters/client_channel/backup_poller.cc', - 'deps/grpc/src/core/ext/filters/client_channel/channel_connectivity.cc', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel.cc', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel_channelz.cc', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel_factory.cc', - 'deps/grpc/src/core/ext/filters/client_channel/client_channel_plugin.cc', - 'deps/grpc/src/core/ext/filters/client_channel/connector.cc', - 'deps/grpc/src/core/ext/filters/client_channel/global_subchannel_pool.cc', - 'deps/grpc/src/core/ext/filters/client_channel/health/health_check_client.cc', - 'deps/grpc/src/core/ext/filters/client_channel/http_connect_handshaker.cc', - 'deps/grpc/src/core/ext/filters/client_channel/http_proxy.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy_registry.cc', - 'deps/grpc/src/core/ext/filters/client_channel/local_subchannel_pool.cc', - 'deps/grpc/src/core/ext/filters/client_channel/parse_address.cc', - 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper.cc', - 'deps/grpc/src/core/ext/filters/client_channel/proxy_mapper_registry.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver_registry.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver_result_parsing.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolving_lb_policy.cc', - 'deps/grpc/src/core/ext/filters/client_channel/retry_throttle.cc', - 'deps/grpc/src/core/ext/filters/client_channel/server_address.cc', - 'deps/grpc/src/core/ext/filters/client_channel/service_config.cc', - 'deps/grpc/src/core/ext/filters/client_channel/subchannel.cc', - 'deps/grpc/src/core/ext/filters/client_channel/subchannel_pool_interface.cc', - 'deps/grpc/src/core/ext/filters/deadline/deadline_filter.cc', - 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/health/v1/health.upb.c', - 'deps/grpc/src/core/ext/upb-generated/udpa/data/orca/v1/orca_load_report.upb.c', - 'deps/grpc/src/core/ext/upb-generated/gogoproto/gogo.upb.c', - 'deps/grpc/src/core/ext/upb-generated/validate/validate.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/api/annotations.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/api/http.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/any.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/descriptor.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/duration.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/empty.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/struct.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/timestamp.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/protobuf/wrappers.upb.c', - 'deps/grpc/src/core/ext/upb-generated/google/rpc/status.upb.c', - 'deps/grpc/src/core/tsi/fake_transport_security.cc', - 'deps/grpc/src/core/tsi/local_transport_security.cc', - 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_boringssl.cc', - 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_cache.cc', - 'deps/grpc/src/core/tsi/ssl/session_cache/ssl_session_openssl.cc', - 'deps/grpc/src/core/tsi/ssl_transport_security.cc', - 'deps/grpc/src/core/tsi/transport_security_grpc.cc', - 'deps/grpc/src/core/ext/transport/chttp2/server/chttp2_server.cc', - 'deps/grpc/src/core/ext/transport/chttp2/client/secure/secure_channel_create.cc', - 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2.cc', - 'deps/grpc/src/core/ext/transport/chttp2/server/insecure/server_chttp2_posix.cc', - 'deps/grpc/src/core/ext/transport/inproc/inproc_plugin.cc', - 'deps/grpc/src/core/ext/transport/inproc/inproc_transport.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/client_load_reporting_filter.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_channel_secure.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/grpclb_client_stats.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/grpclb/load_balancer_api.cc', - 'deps/grpc/src/core/ext/upb-generated/src/proto/grpc/lb/v1/load_balancer.upb.c', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/fake/fake_resolver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_channel_secure.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_client_stats.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/xds/xds_load_balancer_api.cc', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/auth/cert.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cds.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cluster/circuit_breaker.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cluster/filter.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/cluster/outlier_detection.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/discovery.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/eds.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/endpoint/endpoint.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/endpoint/load_report.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/service/discovery/v2/ads.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/service/load_stats/v2/lrs.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/address.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/base.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/config_source.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/grpc_service.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/health_check.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/http_uri.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/api/v2/core/protocol.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/type/percent.upb.c', - 'deps/grpc/src/core/ext/upb-generated/envoy/type/range.upb.c', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc', - 'deps/grpc/src/core/ext/filters/client_channel/lb_policy/round_robin/round_robin.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/dns_resolver_ares.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_libuv.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_posix.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_ev_driver_windows.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_fallback.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_libuv.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_posix.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/c_ares/grpc_ares_wrapper_windows.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/dns_resolver_selection.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/dns/native/dns_resolver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/sockaddr/sockaddr_resolver.cc', - 'deps/grpc/src/core/ext/filters/client_channel/resolver/xds/xds_resolver.cc', - 'deps/grpc/src/core/ext/filters/census/grpc_context.cc', - 'deps/grpc/src/core/ext/filters/client_idle/client_idle_filter.cc', - 'deps/grpc/src/core/ext/filters/max_age/max_age_filter.cc', - 'deps/grpc/src/core/ext/filters/message_size/message_size_filter.cc', - 'deps/grpc/src/core/ext/filters/http/client_authority_filter.cc', - 'deps/grpc/src/core/ext/filters/workarounds/workaround_cronet_compression_filter.cc', - 'deps/grpc/src/core/ext/filters/workarounds/workaround_utils.cc', - 'deps/grpc/src/core/plugin_registry/grpc_plugin_registry.cc', - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - } - }] - ] - }, - { - 'include_dirs': [ - "'ext/'+f).join(' ')\")" - ], - "dependencies": [ - "grpc", - "gpr", - "ares", - "address_sorting" - ] - }, - { - "target_name": "action_after_build", - "type": "none", - "dependencies": [ "<(module_name)" ], - "copies": [ - { - "files": [ "<(PRODUCT_DIR)/<(module_name).node"], - "destination": "<(module_path)" - } - ] - } - ] -} diff --git a/packages/grpc-native-core/build.yaml b/packages/grpc-native-core/build.yaml deleted file mode 100644 index 49e36fdfe..000000000 --- a/packages/grpc-native-core/build.yaml +++ /dev/null @@ -1,2 +0,0 @@ -settings: - '#': It's possible to have node_version here as a key to override the core's version. diff --git a/packages/grpc-native-core/deps/grpc b/packages/grpc-native-core/deps/grpc deleted file mode 160000 index f703e1c86..000000000 --- a/packages/grpc-native-core/deps/grpc +++ /dev/null @@ -1 +0,0 @@ -Subproject commit f703e1c86c1504d9e48953f8da31f842679b7775 diff --git a/packages/grpc-native-core/ext/byte_buffer.cc b/packages/grpc-native-core/ext/byte_buffer.cc deleted file mode 100644 index 1040f70d7..000000000 --- a/packages/grpc-native-core/ext/byte_buffer.cc +++ /dev/null @@ -1,79 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include -#include -#include "grpc/byte_buffer_reader.h" -#include "grpc/grpc.h" -#include "grpc/slice.h" - -#include "byte_buffer.h" -#include "slice.h" - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::MaybeLocal; - -using v8::Function; -using v8::Local; -using v8::Object; -using v8::Number; -using v8::Value; - -grpc_byte_buffer *BufferToByteBuffer(Local buffer) { - Nan::HandleScope scope; - grpc_slice slice = CreateSliceFromBuffer(buffer); - grpc_byte_buffer *byte_buffer(grpc_raw_byte_buffer_create(&slice, 1)); - grpc_slice_unref(slice); - return byte_buffer; -} - -namespace { -void delete_buffer(char *data, void *hint) { - grpc_slice *slice = static_cast(hint); - grpc_slice_unref(*slice); - delete slice; -} -} - -Local ByteBufferToBuffer(grpc_byte_buffer *buffer) { - Nan::EscapableHandleScope scope; - if (buffer == NULL) { - return scope.Escape(Nan::Null()); - } - grpc_byte_buffer_reader reader; - if (!grpc_byte_buffer_reader_init(&reader, buffer)) { - Nan::ThrowError("Error initializing byte buffer reader."); - return scope.Escape(Nan::Undefined()); - } - grpc_slice *slice = new grpc_slice; - *slice = grpc_byte_buffer_reader_readall(&reader); - grpc_byte_buffer_reader_destroy(&reader); - char *result = reinterpret_cast(GRPC_SLICE_START_PTR(*slice)); - size_t length = GRPC_SLICE_LENGTH(*slice); - Local buf = - Nan::NewBuffer(result, length, delete_buffer, slice).ToLocalChecked(); - return scope.Escape(buf); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/byte_buffer.h b/packages/grpc-native-core/ext/byte_buffer.h deleted file mode 100644 index 622314760..000000000 --- a/packages/grpc-native-core/ext/byte_buffer.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_BYTE_BUFFER_H_ -#define NET_GRPC_NODE_BYTE_BUFFER_H_ - -#include - -#include -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -/* Convert a Node.js Buffer to grpc_byte_buffer. Requires that - ::node::Buffer::HasInstance(buffer) */ -grpc_byte_buffer *BufferToByteBuffer(v8::Local buffer); - -/* Convert a grpc_byte_buffer to a Node.js Buffer */ -v8::Local ByteBufferToBuffer(grpc_byte_buffer *buffer); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_BYTE_BUFFER_H_ diff --git a/packages/grpc-native-core/ext/call.cc b/packages/grpc-native-core/ext/call.cc deleted file mode 100644 index b47451a47..000000000 --- a/packages/grpc-native-core/ext/call.cc +++ /dev/null @@ -1,778 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include - -#include - -#include "byte_buffer.h" -#include "call.h" -#include "call_credentials.h" -#include "channel.h" -#include "completion_queue.h" -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/alloc.h" -#include "grpc/support/log.h" -#include "grpc/support/time.h" -#include "slice.h" -#include "timeval.h" - -using std::unique_ptr; -using std::shared_ptr; -using std::vector; - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::EscapableHandleScope; -using Nan::HandleScope; -using Nan::Maybe; -using Nan::MaybeLocal; -using Nan::ObjectWrap; -using Nan::Persistent; -using Nan::Utf8String; - -using v8::Array; -using v8::Boolean; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Integer; -using v8::Local; -using v8::Number; -using v8::Object; -using v8::ObjectTemplate; -using v8::Uint32; -using v8::String; -using v8::Value; - -Callback *Call::constructor; -Persistent Call::fun_tpl; - -/** - * Helper function for throwing errors with a grpc_call_error value. - * Modified from the answer by Gus Goose to - * http://stackoverflow.com/questions/31794200. - */ -Local nanErrorWithCode(const char *msg, grpc_call_error code) { - EscapableHandleScope scope; - Local err = Nan::Error(msg).As(); - Nan::Set(err, Nan::New("code").ToLocalChecked(), Nan::New(code)); - return scope.Escape(err); -} - -bool CreateMetadataArray(Local metadata_obj, grpc_metadata_array *array) { - HandleScope scope; - Local metadata_value = (Nan::Get(metadata_obj, Nan::New("metadata").ToLocalChecked())).ToLocalChecked(); - if (!metadata_value->IsObject()) { - return false; - } - Local metadata = Nan::To(metadata_value).ToLocalChecked(); - Local keys = Nan::GetOwnPropertyNames(metadata).ToLocalChecked(); - for (unsigned int i = 0; i < keys->Length(); i++) { - Local current_key = - Nan::To(Nan::Get(keys, i).ToLocalChecked()).ToLocalChecked(); - Local value_array = Nan::Get(metadata, current_key).ToLocalChecked(); - if (!value_array->IsArray()) { - return false; - } - array->capacity += Local::Cast(value_array)->Length(); - } - array->metadata = reinterpret_cast( - gpr_zalloc(array->capacity * sizeof(grpc_metadata))); - for (unsigned int i = 0; i < keys->Length(); i++) { - Local current_key(Nan::To(Nan::Get(keys, i).ToLocalChecked()).ToLocalChecked()); - Local values = - Local::Cast(Nan::Get(metadata, current_key).ToLocalChecked()); - grpc_slice key_slice = CreateSliceFromString(current_key); - grpc_slice key_intern_slice = grpc_slice_intern(key_slice); - grpc_slice_unref(key_slice); - for (unsigned int j = 0; j < values->Length(); j++) { - Local value = Nan::Get(values, j).ToLocalChecked(); - grpc_metadata *current = &array->metadata[array->count]; - current->key = key_intern_slice; - // Only allow binary headers for "-bin" keys - if (grpc_is_binary_header(key_intern_slice)) { - if (::node::Buffer::HasInstance(value)) { - current->value = CreateSliceFromBuffer(value); - } else { - return false; - } - } else { - if (value->IsString()) { - Local string_value = Nan::To(value).ToLocalChecked(); - current->value = CreateSliceFromString(string_value); - } else { - return false; - } - } - array->count += 1; - } - } - return true; -} - -void DestroyMetadataArray(grpc_metadata_array *array) { - for (size_t i = 0; i < array->count; i++) { - // Don't unref keys because they are interned - grpc_slice_unref(array->metadata[i].value); - } - grpc_metadata_array_destroy(array); -} - -Local ParseMetadata(const grpc_metadata_array *metadata_array) { - EscapableHandleScope scope; - grpc_metadata *metadata_elements = metadata_array->metadata; - size_t length = metadata_array->count; - Local metadata_object = Nan::New(); - for (unsigned int i = 0; i < length; i++) { - grpc_metadata *elem = &metadata_elements[i]; - // TODO(murgatroid99): Use zero-copy string construction instead - Local key_string = CopyStringFromSlice(elem->key); - Local array; - MaybeLocal maybe_array = Nan::Get(metadata_object, key_string); - if (maybe_array.IsEmpty() || !maybe_array.ToLocalChecked()->IsArray()) { - array = Nan::New(0); - Nan::Set(metadata_object, key_string, array); - } else { - array = Local::Cast(maybe_array.ToLocalChecked()); - } - if (grpc_is_binary_header(elem->key)) { - Nan::Set(array, array->Length(), CreateBufferFromSlice(elem->value)); - } else { - // TODO(murgatroid99): Use zero-copy string construction instead - Nan::Set(array, array->Length(), CopyStringFromSlice(elem->value)); - } - } - Local result = Nan::New(); - Nan::Set(result, Nan::New("metadata").ToLocalChecked(), metadata_object); - Nan::Set(result, Nan::New("flags").ToLocalChecked(), Nan::New(0)); - return scope.Escape(result); -} - -Local Op::GetOpType() const { - EscapableHandleScope scope; - return scope.Escape(Nan::New(GetTypeString()).ToLocalChecked()); -} - -Op::~Op() {} - -class SendMetadataOp : public Op { - public: - SendMetadataOp() { grpc_metadata_array_init(&send_metadata); } - ~SendMetadataOp() { DestroyMetadataArray(&send_metadata); } - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(Nan::True()); - } - bool ParseOp(Local value, grpc_op *out) { - if (!value->IsObject()) { - return false; - } - MaybeLocal maybe_metadata = Nan::To(value); - if (maybe_metadata.IsEmpty()) { - return false; - } - Local metadata_object = maybe_metadata.ToLocalChecked(); - MaybeLocal maybe_flag_value = - Nan::Get(metadata_object, Nan::New("flags").ToLocalChecked()); - if (!maybe_flag_value.IsEmpty()) { - Local flag_value = maybe_flag_value.ToLocalChecked(); - if (flag_value->IsUint32()) { - Maybe maybe_flag = Nan::To(flag_value); - out->flags |= maybe_flag.FromMaybe(0) & GRPC_INITIAL_METADATA_USED_MASK; - } - } - if (!CreateMetadataArray(metadata_object, &send_metadata)) { - return false; - } - out->data.send_initial_metadata.count = send_metadata.count; - out->data.send_initial_metadata.metadata = send_metadata.metadata; - return true; - } - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "send_metadata"; } - - private: - grpc_metadata_array send_metadata; -}; - -class SendMessageOp : public Op { - public: - SendMessageOp() { send_message = NULL; } - ~SendMessageOp() { - if (send_message != NULL) { - grpc_byte_buffer_destroy(send_message); - } - } - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(Nan::True()); - } - bool ParseOp(Local value, grpc_op *out) { - if (!::node::Buffer::HasInstance(value)) { - return false; - } - Local object_value = Nan::To(value).ToLocalChecked(); - MaybeLocal maybe_flag_value = - Nan::Get(object_value, Nan::New("grpcWriteFlags").ToLocalChecked()); - if (!maybe_flag_value.IsEmpty()) { - Local flag_value = maybe_flag_value.ToLocalChecked(); - if (flag_value->IsUint32()) { - Maybe maybe_flag = Nan::To(flag_value); - out->flags |= maybe_flag.FromMaybe(0) & GRPC_WRITE_USED_MASK; - } - } - send_message = BufferToByteBuffer(value); - out->data.send_message.send_message = send_message; - return true; - } - - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "send_message"; } - - private: - grpc_byte_buffer *send_message; -}; - -class SendClientCloseOp : public Op { - public: - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(Nan::True()); - } - - bool ParseOp(Local value, grpc_op *out) { return true; } - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "client_close"; } -}; - -class SendServerStatusOp : public Op { - public: - SendServerStatusOp() { - details = grpc_empty_slice(); - grpc_metadata_array_init(&status_metadata); - } - ~SendServerStatusOp() { - grpc_slice_unref(details); - DestroyMetadataArray(&status_metadata); - } - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(Nan::True()); - } - bool ParseOp(Local value, grpc_op *out) { - if (!value->IsObject()) { - return false; - } - Local server_status = Nan::To(value).ToLocalChecked(); - MaybeLocal maybe_metadata = - Nan::Get(server_status, Nan::New("metadata").ToLocalChecked()); - if (maybe_metadata.IsEmpty()) { - return false; - } - if (!maybe_metadata.ToLocalChecked()->IsObject()) { - return false; - } - Local metadata = - Nan::To(maybe_metadata.ToLocalChecked()).ToLocalChecked(); - MaybeLocal maybe_code = - Nan::Get(server_status, Nan::New("code").ToLocalChecked()); - if (maybe_code.IsEmpty()) { - return false; - } - if (!maybe_code.ToLocalChecked()->IsUint32()) { - return false; - } - uint32_t code = Nan::To(maybe_code.ToLocalChecked()).FromJust(); - MaybeLocal maybe_details = - Nan::Get(server_status, Nan::New("details").ToLocalChecked()); - if (maybe_details.IsEmpty()) { - return false; - } - if (!maybe_details.ToLocalChecked()->IsString()) { - return false; - } - Local details = - Nan::To(maybe_details.ToLocalChecked()).ToLocalChecked(); - if (!CreateMetadataArray(metadata, &status_metadata)) { - return false; - } - out->data.send_status_from_server.trailing_metadata_count = - status_metadata.count; - out->data.send_status_from_server.trailing_metadata = - status_metadata.metadata; - out->data.send_status_from_server.status = - static_cast(code); - this->details = CreateSliceFromString(details); - out->data.send_status_from_server.status_details = &this->details; - return true; - } - bool IsFinalOp() { return true; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "send_status"; } - - private: - grpc_slice details; - grpc_metadata_array status_metadata; -}; - -class GetMetadataOp : public Op { - public: - GetMetadataOp() { grpc_metadata_array_init(&recv_metadata); } - - ~GetMetadataOp() { grpc_metadata_array_destroy(&recv_metadata); } - - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(ParseMetadata(&recv_metadata)); - } - - bool ParseOp(Local value, grpc_op *out) { - out->data.recv_initial_metadata.recv_initial_metadata = &recv_metadata; - return true; - } - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "metadata"; } - - private: - grpc_metadata_array recv_metadata; -}; - -class ReadMessageOp : public Op { - public: - ReadMessageOp() { recv_message = NULL; } - ~ReadMessageOp() { - if (recv_message != NULL) { - grpc_byte_buffer_destroy(recv_message); - } - } - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(ByteBufferToBuffer(recv_message)); - } - - bool ParseOp(Local value, grpc_op *out) { - out->data.recv_message.recv_message = &recv_message; - return true; - } - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "read"; } - - private: - grpc_byte_buffer *recv_message; -}; - -class ClientStatusOp : public Op { - public: - ClientStatusOp() { - grpc_metadata_array_init(&metadata_array); - status_details = grpc_empty_slice(); - } - - ~ClientStatusOp() { - grpc_metadata_array_destroy(&metadata_array); - grpc_slice_unref(status_details); - } - - bool ParseOp(Local value, grpc_op *out) { - out->data.recv_status_on_client.trailing_metadata = &metadata_array; - out->data.recv_status_on_client.status = &status; - out->data.recv_status_on_client.status_details = &status_details; - return true; - } - - Local GetNodeValue() const { - EscapableHandleScope scope; - Local status_obj = Nan::New(); - Nan::Set(status_obj, Nan::New("code").ToLocalChecked(), - Nan::New(status)); - Nan::Set(status_obj, Nan::New("details").ToLocalChecked(), - CopyStringFromSlice(status_details)); - Nan::Set(status_obj, Nan::New("metadata").ToLocalChecked(), - ParseMetadata(&metadata_array)); - return scope.Escape(status_obj); - } - bool IsFinalOp() { return true; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "status"; } - - private: - grpc_metadata_array metadata_array; - grpc_status_code status; - grpc_slice status_details; -}; - -class ServerCloseResponseOp : public Op { - public: - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(Nan::New(cancelled)); - } - - bool ParseOp(Local value, grpc_op *out) { - out->data.recv_close_on_server.cancelled = &cancelled; - return true; - } - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - protected: - std::string GetTypeString() const { return "cancelled"; } - - private: - int cancelled; -}; - -tag::tag(Callback *callback, OpVec *ops, Call *call, Local call_value) - : callback(callback), - async_resource(NULL), - ops(ops), - call(call) { - HandleScope scope; - async_resource = new Nan::AsyncResource("grpc:tag"); // Needs handle scope. - call_persist.Reset(call_value); -} - -tag::~tag() { - delete callback; - delete async_resource; - delete ops; -} - -void CompleteTag(void *tag, const char *error_message) { - HandleScope scope; - struct tag *tag_struct = reinterpret_cast(tag); - Callback *callback = tag_struct->callback; - if (error_message == NULL) { - Local tag_obj = Nan::New(); - for (vector >::iterator it = tag_struct->ops->begin(); - it != tag_struct->ops->end(); ++it) { - Op *op_ptr = it->get(); - Nan::Set(tag_obj, op_ptr->GetOpType(), op_ptr->GetNodeValue()); - } - Local argv[] = {Nan::Null(), tag_obj}; - callback->Call(2, argv, tag_struct->async_resource); - } else { - Local argv[] = {Nan::Error(error_message)}; - callback->Call(1, argv, tag_struct->async_resource); - } - bool success = (error_message == NULL); - bool is_final_op = false; - for (vector >::iterator it = tag_struct->ops->begin(); - it != tag_struct->ops->end(); ++it) { - Op *op_ptr = it->get(); - op_ptr->OnComplete(success); - if (op_ptr->IsFinalOp()) { - is_final_op = true; - } - } - if (tag_struct->call == NULL) { - return; - } - tag_struct->call->CompleteBatch(is_final_op); -} - -void DestroyTag(void *tag) { - struct tag *tag_struct = reinterpret_cast(tag); - delete tag_struct; -} - -void Call::DestroyCall() { - if (this->wrapped_call != NULL) { - grpc_call_unref(this->wrapped_call); - this->wrapped_call = NULL; - } -} - -Call::Call(grpc_call *call) - : wrapped_call(call), pending_batches(0), has_final_op_completed(false) { - peer = grpc_call_get_peer(call); -} - -Call::~Call() { - DestroyCall(); - gpr_free(peer); -} - -void Call::Init(Local exports) { - HandleScope scope; - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("Call").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetPrototypeMethod(tpl, "startBatch", StartBatch); - Nan::SetPrototypeMethod(tpl, "cancel", Cancel); - Nan::SetPrototypeMethod(tpl, "cancelWithStatus", CancelWithStatus); - Nan::SetPrototypeMethod(tpl, "getPeer", GetPeer); - Nan::SetPrototypeMethod(tpl, "setCredentials", SetCredentials); - fun_tpl.Reset(tpl); - Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); - Nan::Set(exports, Nan::New("Call").ToLocalChecked(), ctr); - constructor = new Callback(ctr); -} - -bool Call::HasInstance(Local val) { - HandleScope scope; - return Nan::New(fun_tpl)->HasInstance(val); -} - -grpc_call *Call::GetWrappedCall() { return this->wrapped_call; } - -Local Call::WrapStruct(grpc_call *call) { - EscapableHandleScope scope; - if (call == NULL) { - return scope.Escape(Nan::Null()); - } - const int argc = 1; - Local argv[argc] = { - Nan::New(reinterpret_cast(call))}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - return scope.Escape(Nan::Null()); - } else { - return scope.Escape(maybe_instance.ToLocalChecked()); - } -} - -void Call::CompleteBatch(bool is_final_op) { - if (is_final_op) { - this->has_final_op_completed = true; - } - this->pending_batches--; - if (this->has_final_op_completed && this->pending_batches == 0) { - this->DestroyCall(); - } -} - -NAN_METHOD(Call::New) { - /* Arguments: - * 0: Channel to make the call on - * 1: Method - * 2: Deadline - * 3: host - * 4: parent Call - * 5: propagation flags - */ - if (info.IsConstructCall()) { - Call *call; - if (!info[0]->IsExternal()) { - return Nan::ThrowTypeError( - "Call can only be created with Channel.createCall"); - } - Local ext = info[0].As(); - // This option is used for wrapping an existing call - grpc_call *call_value = reinterpret_cast(ext->Value()); - call = new Call(call_value); - call->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - return; - } else { - return Nan::ThrowTypeError( - "Call can only be created with Channel.createCall"); - } -} - -NAN_METHOD(Call::StartBatch) { - if (!Call::HasInstance(info.This())) { - return Nan::ThrowTypeError("startBatch can only be called on Call objects"); - } - if (!info[0]->IsObject()) { - return Nan::ThrowError("startBatch's first argument must be an object"); - } - if (!info[1]->IsFunction()) { - return Nan::ThrowError("startBatch's second argument must be a callback"); - } - Local callback_func = info[1].As(); - Call *call = ObjectWrap::Unwrap(info.This()); - if (call->wrapped_call == NULL) { - /* This implies that the call has completed and has been destroyed. To - * emulate - * previous behavior, we should call the callback immediately with an error, - * as though the batch had failed in core */ - Local argv[] = { - Nan::Error("The async function failed because the call has completed")}; - Nan::Call(callback_func, Nan::New(), 1, argv); - return; - } - Local obj = Nan::To(info[0]).ToLocalChecked(); - Local keys = Nan::GetOwnPropertyNames(obj).ToLocalChecked(); - size_t nops = keys->Length(); - vector ops(nops); - unique_ptr op_vector(new OpVec()); - for (unsigned int i = 0; i < nops; i++) { - unique_ptr op; - MaybeLocal maybe_key = Nan::Get(keys, i); - if (maybe_key.IsEmpty() || (!maybe_key.ToLocalChecked()->IsUint32())) { - return Nan::ThrowError( - "startBatch's first argument's keys must be integers"); - } - uint32_t type = Nan::To(maybe_key.ToLocalChecked()).FromJust(); - ops[i].op = static_cast(type); - ops[i].flags = 0; - ops[i].reserved = NULL; - switch (type) { - case GRPC_OP_SEND_INITIAL_METADATA: - op.reset(new SendMetadataOp()); - break; - case GRPC_OP_SEND_MESSAGE: - op.reset(new SendMessageOp()); - break; - case GRPC_OP_SEND_CLOSE_FROM_CLIENT: - op.reset(new SendClientCloseOp()); - break; - case GRPC_OP_SEND_STATUS_FROM_SERVER: - op.reset(new SendServerStatusOp()); - break; - case GRPC_OP_RECV_INITIAL_METADATA: - op.reset(new GetMetadataOp()); - break; - case GRPC_OP_RECV_MESSAGE: - op.reset(new ReadMessageOp()); - break; - case GRPC_OP_RECV_STATUS_ON_CLIENT: - op.reset(new ClientStatusOp()); - break; - case GRPC_OP_RECV_CLOSE_ON_SERVER: - op.reset(new ServerCloseResponseOp()); - break; - default: - return Nan::ThrowError("Argument object had an unrecognized key"); - } - if (!op->ParseOp(Nan::Get(obj, type).ToLocalChecked(), &ops[i])) { - return Nan::ThrowTypeError("Incorrectly typed arguments to startBatch"); - } - op_vector->push_back(std::move(op)); - } - Callback *callback = new Callback(callback_func); - grpc_call_error error = grpc_call_start_batch( - call->wrapped_call, ops.data(), nops, - new struct tag(callback, op_vector.release(), call, info.This()), NULL); - if (error != GRPC_CALL_OK) { - return Nan::ThrowError(nanErrorWithCode("startBatch failed", error)); - } - call->pending_batches++; - CompletionQueueNext(); -} - -NAN_METHOD(Call::Cancel) { - if (!Call::HasInstance(info.This())) { - return Nan::ThrowTypeError("cancel can only be called on Call objects"); - } - Call *call = ObjectWrap::Unwrap(info.This()); - if (call->wrapped_call == NULL) { - /* Cancel is supposed to be idempotent. If the call has already finished, - * cancel should just complete silently */ - return; - } - grpc_call_error error = grpc_call_cancel(call->wrapped_call, NULL); - if (error != GRPC_CALL_OK) { - return Nan::ThrowError(nanErrorWithCode("cancel failed", error)); - } -} - -NAN_METHOD(Call::CancelWithStatus) { - Nan::HandleScope scope; - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("cancel can only be called on Call objects"); - } - if (!info[0]->IsUint32()) { - return Nan::ThrowTypeError( - "cancelWithStatus's first argument must be a status code"); - } - if (!info[1]->IsString()) { - return Nan::ThrowTypeError( - "cancelWithStatus's second argument must be a string"); - } - Call *call = ObjectWrap::Unwrap(info.This()); - if (call->wrapped_call == NULL) { - /* Cancel is supposed to be idempotent. If the call has already finished, - * cancel should just complete silently */ - return; - } - grpc_status_code code = - static_cast(Nan::To(info[0]).FromJust()); - if (code == GRPC_STATUS_OK) { - return Nan::ThrowRangeError( - "cancelWithStatus cannot be called with OK status"); - } - Utf8String details(info[1]); - grpc_call_cancel_with_status(call->wrapped_call, code, *details, NULL); -} - -NAN_METHOD(Call::GetPeer) { - Nan::HandleScope scope; - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("getPeer can only be called on Call objects"); - } - Call *call = ObjectWrap::Unwrap(info.This()); - Local peer_value = Nan::New(call->peer).ToLocalChecked(); - info.GetReturnValue().Set(peer_value); -} - -NAN_METHOD(Call::SetCredentials) { - Nan::HandleScope scope; - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError( - "setCredentials can only be called on Call objects"); - } - if (!CallCredentials::HasInstance(info[0])) { - return Nan::ThrowTypeError( - "setCredentials' first argument must be a CallCredentials"); - } - Call *call = ObjectWrap::Unwrap(info.This()); - if (call->wrapped_call == NULL) { - return Nan::ThrowError( - "Cannot set credentials on a call that has already started"); - } - CallCredentials *creds_object = ObjectWrap::Unwrap( - Nan::To(info[0]).ToLocalChecked()); - grpc_call_credentials *creds = creds_object->GetWrappedCredentials(); - grpc_call_error error = GRPC_CALL_ERROR; - if (creds) { - error = grpc_call_set_credentials(call->wrapped_call, creds); - } - info.GetReturnValue().Set(Nan::New(error)); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/call.h b/packages/grpc-native-core/ext/call.h deleted file mode 100644 index f78822d1c..000000000 --- a/packages/grpc-native-core/ext/call.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_CALL_H_ -#define NET_GRPC_NODE_CALL_H_ - -#include -#include - -#include -#include -#include "grpc/grpc.h" -#include "grpc/support/log.h" - -#include "channel.h" - -namespace grpc { -namespace node { - -using std::unique_ptr; -using std::shared_ptr; - -v8::Local nanErrorWithCode(const char *msg, grpc_call_error code); - -v8::Local ParseMetadata(const grpc_metadata_array *metadata_array); - -bool CreateMetadataArray(v8::Local metadata, - grpc_metadata_array *array); - -void DestroyMetadataArray(grpc_metadata_array *array); - -/* Wrapper class for grpc_call structs. */ -class Call : public Nan::ObjectWrap { - public: - static void Init(v8::Local exports); - static bool HasInstance(v8::Local val); - /* Wrap a grpc_call struct in a javascript object */ - static v8::Local WrapStruct(grpc_call *call); - - grpc_call *GetWrappedCall(); - - void CompleteBatch(bool is_final_op); - - private: - explicit Call(grpc_call *call); - ~Call(); - - // Prevent copying - Call(const Call &); - Call &operator=(const Call &); - - void DestroyCall(); - - static NAN_METHOD(New); - static NAN_METHOD(StartBatch); - static NAN_METHOD(Cancel); - static NAN_METHOD(CancelWithStatus); - static NAN_METHOD(GetPeer); - static NAN_METHOD(SetCredentials); - static Nan::Callback *constructor; - // Used for typechecking instances of this javascript class - static Nan::Persistent fun_tpl; - - grpc_call *wrapped_call; - // The number of ops that were started but not completed on this call - int pending_batches; - /* Indicates whether the "final" op on a call has completed. For a client - call, this is GRPC_OP_RECV_STATUS_ON_CLIENT and for a server call, this - is GRPC_OP_SEND_STATUS_FROM_SERVER */ - bool has_final_op_completed; - char *peer; -}; - -class Op { - public: - virtual v8::Local GetNodeValue() const = 0; - virtual bool ParseOp(v8::Local value, grpc_op *out) = 0; - virtual ~Op(); - v8::Local GetOpType() const; - virtual bool IsFinalOp() = 0; - virtual void OnComplete(bool success) = 0; - - protected: - virtual std::string GetTypeString() const = 0; -}; - -typedef std::vector> OpVec; -struct tag { - tag(Nan::Callback *callback, OpVec *ops, Call *call, - v8::Local call_value); - ~tag(); - Nan::Callback *callback; - Nan::AsyncResource *async_resource; - OpVec *ops; - Call *call; - Nan::Persistent> - call_persist; -}; - -void DestroyTag(void *tag); - -void CompleteTag(void *tag, const char *error_message); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_CALL_H_ diff --git a/packages/grpc-native-core/ext/call_credentials.cc b/packages/grpc-native-core/ext/call_credentials.cc deleted file mode 100644 index a4f8bb2ce..000000000 --- a/packages/grpc-native-core/ext/call_credentials.cc +++ /dev/null @@ -1,276 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include - -#include - -#include "call.h" -#include "call_credentials.h" -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/log.h" - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::EscapableHandleScope; -using Nan::HandleScope; -using Nan::Maybe; -using Nan::MaybeLocal; -using Nan::ObjectWrap; -using Nan::Persistent; -using Nan::Utf8String; - -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Integer; -using v8::Local; -using v8::Object; -using v8::ObjectTemplate; -using v8::Value; - -Nan::Callback *CallCredentials::constructor; -Persistent CallCredentials::fun_tpl; - -static Callback *plugin_callback; - -CallCredentials::CallCredentials(grpc_call_credentials *credentials) - : wrapped_credentials(credentials) {} - -CallCredentials::~CallCredentials() { - grpc_call_credentials_release(wrapped_credentials); -} - -void CallCredentials::Init(Local exports) { - HandleScope scope; - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("CallCredentials").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetPrototypeMethod(tpl, "compose", Compose); - fun_tpl.Reset(tpl); - Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); - Nan::Set(ctr, Nan::New("createFromPlugin").ToLocalChecked(), - Nan::GetFunction(Nan::New(CreateFromPlugin)) - .ToLocalChecked()); - Nan::Set(exports, Nan::New("CallCredentials").ToLocalChecked(), ctr); - constructor = new Nan::Callback(ctr); - - Local callback_tpl = - Nan::New(PluginCallback); - plugin_callback = - new Callback(Nan::GetFunction(callback_tpl).ToLocalChecked()); -} - -bool CallCredentials::HasInstance(Local val) { - HandleScope scope; - return Nan::New(fun_tpl)->HasInstance(val); -} - -Local CallCredentials::WrapStruct(grpc_call_credentials *credentials) { - EscapableHandleScope scope; - const int argc = 1; - if (credentials == NULL) { - return scope.Escape(Nan::Null()); - } - Local argv[argc] = { - Nan::New(reinterpret_cast(credentials))}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - return scope.Escape(Nan::Null()); - } else { - return scope.Escape(maybe_instance.ToLocalChecked()); - } -} - -grpc_call_credentials *CallCredentials::GetWrappedCredentials() { - return wrapped_credentials; -} - -NAN_METHOD(CallCredentials::New) { - if (info.IsConstructCall()) { - if (!info[0]->IsExternal()) { - return Nan::ThrowTypeError( - "CallCredentials can only be created with the provided functions"); - } - Local ext = info[0].As(); - grpc_call_credentials *creds_value = - reinterpret_cast(ext->Value()); - CallCredentials *credentials = new CallCredentials(creds_value); - credentials->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - return; - } else { - // This should never be called directly - return Nan::ThrowTypeError( - "CallCredentials can only be created with the provided functions"); - } -} - -NAN_METHOD(CallCredentials::Compose) { - if (!CallCredentials::HasInstance(info.This())) { - return Nan::ThrowTypeError( - "compose can only be called on CallCredentials objects"); - } - if (!CallCredentials::HasInstance(info[0])) { - return Nan::ThrowTypeError( - "compose's first argument must be a CallCredentials object"); - } - CallCredentials *self = ObjectWrap::Unwrap(info.This()); - CallCredentials *other = ObjectWrap::Unwrap( - Nan::To(info[0]).ToLocalChecked()); - grpc_call_credentials *creds = grpc_composite_call_credentials_create( - self->wrapped_credentials, other->wrapped_credentials, NULL); - info.GetReturnValue().Set(WrapStruct(creds)); -} - -NAN_METHOD(CallCredentials::CreateFromPlugin) { - if (!info[0]->IsFunction()) { - return Nan::ThrowTypeError( - "createFromPlugin's argument must be a function"); - } - grpc_metadata_credentials_plugin plugin; - plugin_state *state = new plugin_state; - state->callback = new Nan::Callback(info[0].As()); - state->pending_callbacks = new std::queue(); - uv_mutex_init(&state->plugin_mutex); - uv_async_init(uv_default_loop(), &state->plugin_async, SendPluginCallback); - uv_unref((uv_handle_t *)&state->plugin_async); - - state->plugin_async.data = state; - - plugin.get_metadata = plugin_get_metadata; - plugin.destroy = plugin_destroy_state; - plugin.state = reinterpret_cast(state); - plugin.type = ""; - grpc_call_credentials *creds = - grpc_metadata_credentials_create_from_plugin(plugin, NULL); - info.GetReturnValue().Set(WrapStruct(creds)); -} - -NAN_METHOD(PluginCallback) { - // Arguments: status code, error details, metadata - if (!info[0]->IsUint32()) { - return Nan::ThrowTypeError( - "The callback's first argument must be a status code"); - } - if (!info[1]->IsString()) { - return Nan::ThrowTypeError( - "The callback's second argument must be a string"); - } - if (!info[2]->IsObject()) { - return Nan::ThrowTypeError( - "The callback's third argument must be an object"); - } - if (!info[3]->IsObject()) { - return Nan::ThrowTypeError( - "The callback's fourth argument must be an object"); - } - grpc_status_code code = - static_cast(Nan::To(info[0]).FromJust()); - Utf8String details_utf8_str(info[1]); - char *details = *details_utf8_str; - grpc_metadata_array array; - grpc_metadata_array_init(&array); - Local callback_data = Nan::To(info[3]).ToLocalChecked(); - if (!CreateMetadataArray(Nan::To(info[2]).ToLocalChecked(), &array)) { - return Nan::ThrowError("Failed to parse metadata"); - } - grpc_credentials_plugin_metadata_cb cb = - reinterpret_cast( - Nan::Get(callback_data, Nan::New("cb").ToLocalChecked()) - .ToLocalChecked() - .As() - ->Value()); - void *user_data = - Nan::Get(callback_data, Nan::New("user_data").ToLocalChecked()) - .ToLocalChecked() - .As() - ->Value(); - cb(user_data, array.metadata, array.count, code, details); - DestroyMetadataArray(&array); -} - -NAUV_WORK_CB(SendPluginCallback) { - Nan::HandleScope scope; - plugin_state *state = reinterpret_cast(async->data); - std::queue callbacks; - uv_mutex_lock(&state->plugin_mutex); - state->pending_callbacks->swap(callbacks); - uv_mutex_unlock(&state->plugin_mutex); - while (!callbacks.empty()) { - plugin_callback_data *data = callbacks.front(); - callbacks.pop(); - Local callback_data = Nan::New(); - Nan::Set(callback_data, Nan::New("cb").ToLocalChecked(), - Nan::New(reinterpret_cast(data->cb))); - Nan::Set(callback_data, Nan::New("user_data").ToLocalChecked(), - Nan::New(data->user_data)); - const int argc = 3; - v8::Local argv[argc] = { - Nan::New(data->service_url).ToLocalChecked(), callback_data, - // Get Local from Nan::Callback* - **plugin_callback}; - Nan::Callback *callback = state->callback; - callback->Call(argc, argv, data->async_resource); - delete data; - } -} - -int plugin_get_metadata( - void *state, grpc_auth_metadata_context context, - grpc_credentials_plugin_metadata_cb cb, - void *user_data, - grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX], - size_t *num_creds_md, grpc_status_code *status, - const char **error_details) { - HandleScope scope; - plugin_state *p_state = reinterpret_cast(state); - plugin_callback_data *data = - new plugin_callback_data(context.service_url, cb, user_data); - - uv_mutex_lock(&p_state->plugin_mutex); - p_state->pending_callbacks->push(data); - uv_mutex_unlock(&p_state->plugin_mutex); - - uv_async_send(&p_state->plugin_async); - return 0; // Async processing. -} - -void plugin_uv_close_cb(uv_handle_t *handle) { - uv_async_t *async = reinterpret_cast(handle); - plugin_state *state = reinterpret_cast(async->data); - uv_mutex_destroy(&state->plugin_mutex); - delete state->pending_callbacks; - delete state->callback; - delete state; -} - -void plugin_destroy_state(void *ptr) { - plugin_state *state = reinterpret_cast(ptr); - uv_close((uv_handle_t *)&state->plugin_async, plugin_uv_close_cb); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/call_credentials.h b/packages/grpc-native-core/ext/call_credentials.h deleted file mode 100644 index 9eb893403..000000000 --- a/packages/grpc-native-core/ext/call_credentials.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef GRPC_NODE_CALL_CREDENTIALS_H_ -#define GRPC_NODE_CALL_CREDENTIALS_H_ - -#include - -#include -#include -#include -#include "grpc/grpc_security.h" - -namespace grpc { -namespace node { - -class CallCredentials : public Nan::ObjectWrap { - public: - static void Init(v8::Local exports); - static bool HasInstance(v8::Local val); - /* Wrap a grpc_call_credentials struct in a javascript object */ - static v8::Local WrapStruct(grpc_call_credentials *credentials); - - /* Returns the grpc_call_credentials struct that this object wraps */ - grpc_call_credentials *GetWrappedCredentials(); - - private: - explicit CallCredentials(grpc_call_credentials *credentials); - ~CallCredentials(); - - // Prevent copying - CallCredentials(const CallCredentials &); - CallCredentials &operator=(const CallCredentials &); - - static NAN_METHOD(New); - static NAN_METHOD(CreateSsl); - static NAN_METHOD(CreateFromPlugin); - - static NAN_METHOD(Compose); - static Nan::Callback *constructor; - // Used for typechecking instances of this javascript class - static Nan::Persistent fun_tpl; - - grpc_call_credentials *wrapped_credentials; -}; - -/* Auth metadata plugin functionality */ - -typedef struct plugin_callback_data { - plugin_callback_data(const char *service_url_, - grpc_credentials_plugin_metadata_cb cb_, - void *user_data_) - : service_url(service_url_), - cb(cb_), - user_data(user_data_), - async_resource(NULL) { - Nan::HandleScope scope; - async_resource = new Nan::AsyncResource("grpc:plugin_callback_data"); - } - ~plugin_callback_data() { - delete async_resource; - } - - const char *service_url; - grpc_credentials_plugin_metadata_cb cb; - void *user_data; - Nan::AsyncResource *async_resource; -} plugin_callback_data; - -typedef struct plugin_state { - Nan::Callback *callback; - std::queue *pending_callbacks; - uv_mutex_t plugin_mutex; - // async.data == this - uv_async_t plugin_async; -} plugin_state; - -int plugin_get_metadata( - void *state, grpc_auth_metadata_context context, - grpc_credentials_plugin_metadata_cb cb, - void *user_data, - grpc_metadata creds_md[GRPC_METADATA_CREDENTIALS_PLUGIN_SYNC_MAX], - size_t *num_creds_md, grpc_status_code *status, - const char **error_details); - -void plugin_destroy_state(void *state); - -NAN_METHOD(PluginCallback); - -NAUV_WORK_CB(SendPluginCallback); - -} // namespace node -} // namepsace grpc - -#endif // GRPC_NODE_CALL_CREDENTIALS_H_ diff --git a/packages/grpc-native-core/ext/channel.cc b/packages/grpc-native-core/ext/channel.cc deleted file mode 100644 index fa7f84192..000000000 --- a/packages/grpc-native-core/ext/channel.cc +++ /dev/null @@ -1,397 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include "grpc/support/log.h" - -#include -#include -#include "call.h" -#include "channel.h" -#include "channel_credentials.h" -#include "completion_queue.h" -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "slice.h" -#include "timeval.h" - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::EscapableHandleScope; -using Nan::HandleScope; -using Nan::Maybe; -using Nan::MaybeLocal; -using Nan::ObjectWrap; -using Nan::Persistent; -using Nan::Utf8String; - -using v8::Array; -using v8::Exception; -using v8::Function; -using v8::FunctionTemplate; -using v8::Integer; -using v8::Local; -using v8::Number; -using v8::Object; -using v8::String; -using v8::Value; - -Callback *Channel::constructor; -Persistent Channel::fun_tpl; - -static const char grpc_node_user_agent[] = "grpc-node/" GRPC_NODE_VERSION; - -void PopulateUserAgentChannelArg(grpc_arg *arg) { - size_t key_len = sizeof(GRPC_ARG_PRIMARY_USER_AGENT_STRING); - size_t val_len = sizeof(grpc_node_user_agent); - arg->key = reinterpret_cast(calloc(key_len, sizeof(char))); - memcpy(arg->key, GRPC_ARG_PRIMARY_USER_AGENT_STRING, key_len); - arg->type = GRPC_ARG_STRING; - arg->value.string = reinterpret_cast(calloc(val_len, sizeof(char))); - memcpy(arg->value.string, grpc_node_user_agent, val_len); - -} - -bool ParseChannelArgs(Local args_val, - grpc_channel_args **channel_args_ptr) { - if (args_val->IsUndefined() || args_val->IsNull()) { - // Treat null and undefined the same as an empty object - args_val = Nan::New(); - } - if (!args_val->IsObject()) { - *channel_args_ptr = NULL; - return false; - } - grpc_channel_args *channel_args = - reinterpret_cast(malloc(sizeof(grpc_channel_args))); - *channel_args_ptr = channel_args; - Local args_hash = Nan::To(args_val).ToLocalChecked(); - Local keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked(); - channel_args->num_args = keys->Length(); - /* This is an ugly hack to add in the user agent string argument if it wasn't - * passed by the user */ - bool has_user_agent_arg = Nan::HasOwnProperty( - args_hash, Nan::New(GRPC_ARG_PRIMARY_USER_AGENT_STRING).ToLocalChecked() - ).FromJust(); - if (!has_user_agent_arg) { - channel_args->num_args += 1; - } - channel_args->args = reinterpret_cast( - calloc(channel_args->num_args, sizeof(grpc_arg))); - for (unsigned int i = 0; i < keys->Length(); i++) { - Local key = Nan::Get(keys, i).ToLocalChecked(); - Utf8String key_str(key); - if (*key_str == NULL) { - // Key string conversion failed - return false; - } - Local value = Nan::Get(args_hash, key).ToLocalChecked(); - if (value->IsInt32()) { - channel_args->args[i].type = GRPC_ARG_INTEGER; - channel_args->args[i].value.integer = Nan::To(value).FromJust(); - } else if (value->IsString()) { - Utf8String val_str(value); - channel_args->args[i].type = GRPC_ARG_STRING; - /* Append the grpc-node user agent string after the application user agent - * string, and put the combination at the beginning of the user agent string - */ - if (strcmp(*key_str, GRPC_ARG_PRIMARY_USER_AGENT_STRING) == 0) { - /* val_str.length() is the string length and does not include the - * trailing 0 byte. sizeof(grpc_node_user_agent) is the array length, - * so it does include the trailing 0 byte. */ - size_t val_str_len = val_str.length(); - size_t user_agent_len = sizeof(grpc_node_user_agent); - /* This is the length of the two parts of the string, plus the space in - * between, plus the 0 at the end, which is included in user_agent_len. - */ - channel_args->args[i].value.string = - reinterpret_cast(calloc(val_str_len + user_agent_len + 1, sizeof(char))); - memcpy(channel_args->args[i].value.string, *val_str, - val_str.length()); - channel_args->args[i].value.string[val_str_len] = ' '; - memcpy(channel_args->args[i].value.string + val_str_len + 1, - grpc_node_user_agent, user_agent_len); - } else { - channel_args->args[i].value.string = - reinterpret_cast(calloc(val_str.length() + 1, sizeof(char))); - memcpy(channel_args->args[i].value.string, *val_str, - val_str.length() + 1); - } - } else { - // The value does not match either of the accepted types - return false; - } - channel_args->args[i].key = - reinterpret_cast(calloc(key_str.length() + 1, sizeof(char))); - memcpy(channel_args->args[i].key, *key_str, key_str.length() + 1); - } - /* Add a standard user agent string argument if none was provided */ - if (!has_user_agent_arg) { - size_t index = channel_args->num_args - 1; - PopulateUserAgentChannelArg(&channel_args->args[index]); - } - return true; -} - -void DeallocateChannelArgs(grpc_channel_args *channel_args) { - if (channel_args == NULL) { - return; - } - for (size_t i = 0; i < channel_args->num_args; i++) { - if (channel_args->args[i].key == NULL) { - /* NULL key implies that this argument and all subsequent arguments failed - * to parse */ - break; - } - free(channel_args->args[i].key); - if (channel_args->args[i].type == GRPC_ARG_STRING) { - free(channel_args->args[i].value.string); - } - } - free(channel_args->args); - free(channel_args); -} - -Channel::Channel(grpc_channel *channel) : wrapped_channel(channel) {} - -Channel::~Channel() { - gpr_log(GPR_DEBUG, "Destroying channel"); - if (wrapped_channel != NULL) { - grpc_channel_destroy(wrapped_channel); - } -} - -void Channel::Init(Local exports) { - Nan::HandleScope scope; - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("Channel").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetPrototypeMethod(tpl, "close", Close); - Nan::SetPrototypeMethod(tpl, "getTarget", GetTarget); - Nan::SetPrototypeMethod(tpl, "getConnectivityState", GetConnectivityState); - Nan::SetPrototypeMethod(tpl, "watchConnectivityState", - WatchConnectivityState); - Nan::SetPrototypeMethod(tpl, "createCall", CreateCall); - fun_tpl.Reset(tpl); - Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); - Nan::Set(exports, Nan::New("Channel").ToLocalChecked(), ctr); - constructor = new Callback(ctr); -} - -bool Channel::HasInstance(Local val) { - HandleScope scope; - return Nan::New(fun_tpl)->HasInstance(val); -} - -grpc_channel *Channel::GetWrappedChannel() { return this->wrapped_channel; } - -NAN_METHOD(Channel::New) { - if (info.IsConstructCall()) { - if (!info[0]->IsString()) { - return Nan::ThrowTypeError( - "Channel's first argument (address) must be a string"); - } - grpc_channel *wrapped_channel; - // Owned by the Channel object - Utf8String host(info[0]); - grpc_channel_credentials *creds; - if (!ChannelCredentials::HasInstance(info[1])) { - return Nan::ThrowTypeError( - "Channel's second argument (credentials) must be a ChannelCredentials"); - } - ChannelCredentials *creds_object = ObjectWrap::Unwrap( - Nan::To(info[1]).ToLocalChecked()); - creds = creds_object->GetWrappedCredentials(); - grpc_channel_args *channel_args_ptr = NULL; - if (!ParseChannelArgs(info[2], &channel_args_ptr)) { - DeallocateChannelArgs(channel_args_ptr); - return Nan::ThrowTypeError( - "Channel third argument (options) must be an object with " - "string keys and integer or string values"); - } - if (creds == NULL) { - wrapped_channel = - grpc_insecure_channel_create(*host, channel_args_ptr, NULL); - } else { - wrapped_channel = - grpc_secure_channel_create(creds, *host, channel_args_ptr, NULL); - } - DeallocateChannelArgs(channel_args_ptr); - Channel *channel = new Channel(wrapped_channel); - channel->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - return; - } else { - const int argc = 3; - Local argv[argc] = {info[0], info[1], info[2]}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - // There's probably a pending exception - return; - } else { - info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); - } - } -} - -NAN_METHOD(Channel::Close) { - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("close can only be called on Channel objects"); - } - Channel *channel = ObjectWrap::Unwrap(info.This()); - if (channel->wrapped_channel != NULL) { - grpc_channel_destroy(channel->wrapped_channel); - channel->wrapped_channel = NULL; - } -} - -NAN_METHOD(Channel::GetTarget) { - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError( - "getTarget can only be called on Channel objects"); - } - Channel *channel = ObjectWrap::Unwrap(info.This()); - if (channel->wrapped_channel == NULL) { - return Nan::ThrowError( - "Cannot call getTarget on a closed Channel"); - } - info.GetReturnValue().Set( - Nan::New(grpc_channel_get_target(channel->wrapped_channel)) - .ToLocalChecked()); -} - -NAN_METHOD(Channel::GetConnectivityState) { - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError( - "getConnectivityState can only be called on Channel objects"); - } - Channel *channel = ObjectWrap::Unwrap(info.This()); - if (channel->wrapped_channel == NULL) { - return Nan::ThrowError( - "Cannot call getConnectivityState on a closed Channel"); - } - int try_to_connect = (int)info[0]->StrictEquals(Nan::True()); - info.GetReturnValue().Set(grpc_channel_check_connectivity_state( - channel->wrapped_channel, try_to_connect)); -} - -NAN_METHOD(Channel::WatchConnectivityState) { - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError( - "watchConnectivityState can only be called on Channel objects"); - } - if (!info[0]->IsUint32()) { - return Nan::ThrowTypeError( - "watchConnectivityState's first argument must be a channel state"); - } - if (!(info[1]->IsNumber() || info[1]->IsDate())) { - return Nan::ThrowTypeError( - "watchConnectivityState's second argument must be a date or a number"); - } - if (!info[2]->IsFunction()) { - return Nan::ThrowTypeError( - "watchConnectivityState's third argument must be a callback"); - } - Channel *channel = ObjectWrap::Unwrap(info.This()); - if (channel->wrapped_channel == NULL) { - return Nan::ThrowError( - "Cannot call watchConnectivityState on a closed Channel"); - } - grpc_connectivity_state last_state = static_cast( - Nan::To(info[0]).FromJust()); - double deadline = Nan::To(info[1]).FromJust(); - Local callback_func = info[2].As(); - Nan::Callback *callback = new Callback(callback_func); - unique_ptr ops(new OpVec()); - grpc_channel_watch_connectivity_state( - channel->wrapped_channel, last_state, MillisecondsToTimespec(deadline), - GetCompletionQueue(), - new struct tag(callback, ops.release(), NULL, Nan::Null())); - CompletionQueueNext(); -} - -NAN_METHOD(Channel::CreateCall) { - /* Arguments: - * 0: Method - * 1: Deadline - * 2: host - * 3: parent Call - * 4: propagation flags - */ - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError( - "createCall can only be called on Channel objects"); - } - if (!info[0]->IsString()){ - return Nan::ThrowTypeError("createCall's first argument must be a string"); - } - if (!(info[1]->IsNumber() || info[1]->IsDate())) { - return Nan::ThrowTypeError( - "createcall's second argument must be a date or a number"); - } - // These arguments are at the end because they are optional - grpc_call *parent_call = NULL; - if (Call::HasInstance(info[3])) { - Call *parent_obj = - ObjectWrap::Unwrap(Nan::To(info[3]).ToLocalChecked()); - parent_call = parent_obj->GetWrappedCall(); - } else if (!(info[3]->IsUndefined() || info[3]->IsNull())) { - return Nan::ThrowTypeError( - "createCall's fourth argument must be another call, if provided"); - } - uint32_t propagate_flags = GRPC_PROPAGATE_DEFAULTS; - if (info[4]->IsUint32()) { - propagate_flags = Nan::To(info[4]).FromJust(); - } else if (!(info[4]->IsUndefined() || info[4]->IsNull())) { - return Nan::ThrowTypeError( - "createCall's fifth argument must be propagate flags, if provided"); - } - Channel *channel = ObjectWrap::Unwrap(info.This()); - grpc_channel *wrapped_channel = channel->GetWrappedChannel(); - if (wrapped_channel == NULL) { - return Nan::ThrowError("Cannot createCall with a closed Channel"); - } - grpc_slice method = - CreateSliceFromString(Nan::To(info[0]).ToLocalChecked()); - double deadline = Nan::To(info[1]).FromJust(); - grpc_call *wrapped_call = NULL; - if (info[2]->IsString()) { - grpc_slice *host = new grpc_slice; - *host = - CreateSliceFromString(Nan::To(info[2]).ToLocalChecked()); - wrapped_call = grpc_channel_create_call( - wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), - method, host, MillisecondsToTimespec(deadline), NULL); - delete host; - } else if (info[2]->IsUndefined() || info[2]->IsNull()) { - wrapped_call = grpc_channel_create_call( - wrapped_channel, parent_call, propagate_flags, GetCompletionQueue(), - method, NULL, MillisecondsToTimespec(deadline), NULL); - } else { - return Nan::ThrowTypeError("createCall's third argument must be a string"); - } - grpc_slice_unref(method); - info.GetReturnValue().Set(Call::WrapStruct(wrapped_call)); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/channel.h b/packages/grpc-native-core/ext/channel.h deleted file mode 100644 index 7925cef47..000000000 --- a/packages/grpc-native-core/ext/channel.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_CHANNEL_H_ -#define NET_GRPC_NODE_CHANNEL_H_ - -#include -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -bool ParseChannelArgs(v8::Local args_val, - grpc_channel_args **channel_args_ptr); - -void DeallocateChannelArgs(grpc_channel_args *channel_args); - -/* Wrapper class for grpc_channel structs */ -class Channel : public Nan::ObjectWrap { - public: - static void Init(v8::Local exports); - static bool HasInstance(v8::Local val); - /* This is used to typecheck javascript objects before converting them to - this type */ - static v8::Persistent prototype; - - /* Returns the grpc_channel struct that this object wraps */ - grpc_channel *GetWrappedChannel(); - - private: - explicit Channel(grpc_channel *channel); - ~Channel(); - - // Prevent copying - Channel(const Channel &); - Channel &operator=(const Channel &); - - static NAN_METHOD(New); - static NAN_METHOD(Close); - static NAN_METHOD(GetTarget); - static NAN_METHOD(GetConnectivityState); - static NAN_METHOD(WatchConnectivityState); - static NAN_METHOD(CreateCall); - static Nan::Callback *constructor; - static Nan::Persistent fun_tpl; - - grpc_channel *wrapped_channel; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_CHANNEL_H_ diff --git a/packages/grpc-native-core/ext/channel_credentials.cc b/packages/grpc-native-core/ext/channel_credentials.cc deleted file mode 100644 index 60184b2bf..000000000 --- a/packages/grpc-native-core/ext/channel_credentials.cc +++ /dev/null @@ -1,253 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include "call.h" -#include "call_credentials.h" -#include "channel_credentials.h" -#include "util.h" -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/log.h" - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::EscapableHandleScope; -using Nan::HandleScope; -using Nan::Maybe; -using Nan::MaybeLocal; -using Nan::ObjectWrap; -using Nan::Persistent; -using Nan::Utf8String; - -using v8::Array; -using v8::Context; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Integer; -using v8::Local; -using v8::Object; -using v8::ObjectTemplate; -using v8::Value; - -Nan::Callback *ChannelCredentials::constructor; -Persistent ChannelCredentials::fun_tpl; - -ChannelCredentials::ChannelCredentials(grpc_channel_credentials *credentials) - : wrapped_credentials(credentials) {} - -ChannelCredentials::~ChannelCredentials() { - grpc_channel_credentials_release(wrapped_credentials); -} - -static int verify_peer_callback_wrapper(const char* servername, const char* cert, void* userdata) { - Nan::HandleScope scope; - Nan::TryCatch try_catch; - Nan::Callback *callback = (Nan::Callback*)userdata; - - const unsigned argc = 2; - Local argv[argc]; - if (servername == NULL) { - argv[0] = Nan::Null(); - } else { - argv[0] = Nan::New(servername).ToLocalChecked(); - } - if (cert == NULL) { - argv[1] = Nan::Null(); - } else { - argv[1] = Nan::New(cert).ToLocalChecked(); - } - - MaybeLocal result = Nan::Call(*callback, argc, argv); - - // Catch any exception and return with a distinct status code which indicates this - if (try_catch.HasCaught()) { - return 2; - } - - // If the result is an error, return a failure - if (result.ToLocalChecked()->IsNativeError()) { - return 1; - } - - return 0; -} - -static void verify_peer_callback_destruct(void *userdata) { - Nan::Callback *callback = (Nan::Callback*)userdata; - delete callback; -} - -void ChannelCredentials::Init(Local exports) { - HandleScope scope; - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("ChannelCredentials").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetPrototypeMethod(tpl, "compose", Compose); - fun_tpl.Reset(tpl); - Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); - Nan::Set( - ctr, Nan::New("createSsl").ToLocalChecked(), - Nan::GetFunction(Nan::New(CreateSsl)).ToLocalChecked()); - Nan::Set(ctr, Nan::New("createInsecure").ToLocalChecked(), - Nan::GetFunction(Nan::New(CreateInsecure)) - .ToLocalChecked()); - Nan::Set(exports, Nan::New("ChannelCredentials").ToLocalChecked(), ctr); - constructor = new Nan::Callback(ctr); -} - -bool ChannelCredentials::HasInstance(Local val) { - HandleScope scope; - return Nan::New(fun_tpl)->HasInstance(val); -} - -Local ChannelCredentials::WrapStruct( - grpc_channel_credentials *credentials) { - EscapableHandleScope scope; - const int argc = 1; - Local argv[argc] = { - Nan::New(reinterpret_cast(credentials))}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - return scope.Escape(Nan::Null()); - } else { - return scope.Escape(maybe_instance.ToLocalChecked()); - } -} - -grpc_channel_credentials *ChannelCredentials::GetWrappedCredentials() { - return wrapped_credentials; -} - -NAN_METHOD(ChannelCredentials::New) { - if (info.IsConstructCall()) { - if (!info[0]->IsExternal()) { - return Nan::ThrowTypeError( - "ChannelCredentials can only be created with the provided functions"); - } - Local ext = info[0].As(); - grpc_channel_credentials *creds_value = - reinterpret_cast(ext->Value()); - ChannelCredentials *credentials = new ChannelCredentials(creds_value); - credentials->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - return; - } else { - // This should never be called directly - return Nan::ThrowTypeError( - "ChannelCredentials can only be created with the provided functions"); - } -} - -NAN_METHOD(ChannelCredentials::CreateSsl) { - StringOrNull root_certs; - StringOrNull private_key; - StringOrNull cert_chain; - if (::node::Buffer::HasInstance(info[0])) { - root_certs.assign(info[0]); - } else if (!(info[0]->IsNull() || info[0]->IsUndefined())) { - return Nan::ThrowTypeError("createSsl's first argument must be a Buffer"); - } - if (::node::Buffer::HasInstance(info[1])) { - private_key.assign(info[1]); - } else if (!(info[1]->IsNull() || info[1]->IsUndefined())) { - return Nan::ThrowTypeError( - "createSSl's second argument must be a Buffer if provided"); - } - if (::node::Buffer::HasInstance(info[2])) { - cert_chain.assign(info[2]); - } else if (!(info[2]->IsNull() || info[2]->IsUndefined())) { - return Nan::ThrowTypeError( - "createSSl's third argument must be a Buffer if provided"); - } - grpc_ssl_pem_key_cert_pair key_cert_pair = {private_key.get(), - cert_chain.get()}; - if (private_key.isAssigned() != cert_chain.isAssigned()) { - return Nan::ThrowError( - "createSsl's second and third arguments must be" - " provided or omitted together"); - } - - verify_peer_options verify_options = {NULL, NULL, NULL}; - if (!info[3]->IsUndefined()) { - if (!info[3]->IsObject()) { - return Nan::ThrowTypeError("createSsl's fourth argument must be an object"); - } - Local object = Nan::To(info[3]).ToLocalChecked(); - - Local checkServerIdentityValue = Nan::Get(object, - Nan::New("checkServerIdentity").ToLocalChecked()).ToLocalChecked(); - if (!checkServerIdentityValue->IsUndefined()) { - if (!checkServerIdentityValue->IsFunction()) { - return Nan::ThrowTypeError("Value of checkServerIdentity must be a function."); - } - Nan::Callback *callback = new Callback(Local::Cast( - checkServerIdentityValue)); - verify_options.verify_peer_callback = verify_peer_callback_wrapper; - verify_options.verify_peer_callback_userdata = (void*)callback; - verify_options.verify_peer_destruct = verify_peer_callback_destruct; - } - } - - grpc_channel_credentials *creds = grpc_ssl_credentials_create( - root_certs.get(), private_key.isAssigned() ? &key_cert_pair : NULL, - &verify_options, NULL); - if (creds == NULL) { - info.GetReturnValue().SetNull(); - } else { - info.GetReturnValue().Set(WrapStruct(creds)); - } -} - -NAN_METHOD(ChannelCredentials::Compose) { - if (!ChannelCredentials::HasInstance(info.This())) { - return Nan::ThrowTypeError( - "compose can only be called on ChannelCredentials objects"); - } - if (!CallCredentials::HasInstance(info[0])) { - return Nan::ThrowTypeError( - "compose's first argument must be a CallCredentials object"); - } - ChannelCredentials *self = - ObjectWrap::Unwrap(info.This()); - if (self->wrapped_credentials == NULL) { - return Nan::ThrowTypeError("Cannot compose insecure credential"); - } - CallCredentials *other = ObjectWrap::Unwrap( - Nan::To(info[0]).ToLocalChecked()); - grpc_channel_credentials *creds = grpc_composite_channel_credentials_create( - self->wrapped_credentials, other->GetWrappedCredentials(), NULL); - if (creds == NULL) { - info.GetReturnValue().SetNull(); - } else { - info.GetReturnValue().Set(WrapStruct(creds)); - } -} - -NAN_METHOD(ChannelCredentials::CreateInsecure) { - info.GetReturnValue().Set(WrapStruct(NULL)); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/channel_credentials.h b/packages/grpc-native-core/ext/channel_credentials.h deleted file mode 100644 index 18c14837c..000000000 --- a/packages/grpc-native-core/ext/channel_credentials.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_CHANNEL_CREDENTIALS_H_ -#define NET_GRPC_NODE_CHANNEL_CREDENTIALS_H_ - -#include -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" - -namespace grpc { -namespace node { - -/* Wrapper class for grpc_channel_credentials structs */ -class ChannelCredentials : public Nan::ObjectWrap { - public: - static void Init(v8::Local exports); - static bool HasInstance(v8::Local val); - /* Wrap a grpc_channel_credentials struct in a javascript object */ - static v8::Local WrapStruct(grpc_channel_credentials *credentials); - - /* Returns the grpc_channel_credentials struct that this object wraps */ - grpc_channel_credentials *GetWrappedCredentials(); - - private: - explicit ChannelCredentials(grpc_channel_credentials *credentials); - ~ChannelCredentials(); - - // Prevent copying - ChannelCredentials(const ChannelCredentials &); - ChannelCredentials &operator=(const ChannelCredentials &); - - static NAN_METHOD(New); - static NAN_METHOD(CreateSsl); - static NAN_METHOD(CreateInsecure); - - static NAN_METHOD(Compose); - static Nan::Callback *constructor; - // Used for typechecking instances of this javascript class - static Nan::Persistent fun_tpl; - - grpc_channel_credentials *wrapped_credentials; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_CHANNEL_CREDENTIALS_H_ diff --git a/packages/grpc-native-core/ext/completion_queue.cc b/packages/grpc-native-core/ext/completion_queue.cc deleted file mode 100644 index 7a149532d..000000000 --- a/packages/grpc-native-core/ext/completion_queue.cc +++ /dev/null @@ -1,89 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include - -#include "call.h" -#include "completion_queue.h" - -namespace grpc { -namespace node { - -using v8::Local; -using v8::Object; -using v8::Value; - -grpc_completion_queue *queue; -uv_prepare_t prepare; -int pending_batches; - -static void drain_completion_queue(uv_prepare_t *handle) { - Nan::HandleScope scope; - grpc_event event; - (void)handle; - do { - event = grpc_completion_queue_next(queue, gpr_inf_past(GPR_CLOCK_MONOTONIC), - NULL); - - if (event.type == GRPC_OP_COMPLETE) { - const char *error_message; - if (event.success) { - error_message = NULL; - } else { - error_message = "The async function encountered an error"; - } - CompleteTag(event.tag, error_message); - grpc::node::DestroyTag(event.tag); - pending_batches--; - } - if (pending_batches == 0) { - uv_prepare_stop(&prepare); - } - } while (event.type != GRPC_QUEUE_TIMEOUT); -} - -grpc_completion_queue *GetCompletionQueue() { return queue; } - -void CompletionQueueNext() { - if (pending_batches == 0) { - uv_prepare_start(&prepare, drain_completion_queue); - } - pending_batches++; -} - -void CompletionQueueInit(Local exports) { - queue = grpc_completion_queue_create_for_next(NULL); - uv_prepare_init(uv_default_loop(), &prepare); - pending_batches = 0; -} - -void CompletionQueueForcePoll() { - /* This sets the prepare object to poll on the completion queue the next time - * Node polls for IO. But it doesn't increment the number of pending batches, - * so it will immediately stop polling after that unless there is an - * intervening CompletionQueueNext call */ - if (pending_batches == 0) { - uv_prepare_start(&prepare, drain_completion_queue); - } -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/completion_queue.h b/packages/grpc-native-core/ext/completion_queue.h deleted file mode 100644 index 3a56c3271..000000000 --- a/packages/grpc-native-core/ext/completion_queue.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include - -namespace grpc { -namespace node { - -grpc_completion_queue *GetCompletionQueue(); - -void CompletionQueueNext(); - -void CompletionQueueInit(v8::Local exports); - -void CompletionQueueForcePoll(); - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/node_grpc.cc b/packages/grpc-native-core/ext/node_grpc.cc deleted file mode 100644 index 1ecd952d7..000000000 --- a/packages/grpc-native-core/ext/node_grpc.cc +++ /dev/null @@ -1,318 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include -#include -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/alloc.h" -#include "grpc/support/log.h" -#include "grpc/support/time.h" - -// TODO(murgatroid99): Remove this when the endpoint API becomes public -#include "src/core/lib/iomgr/pollset_uv.h" - -#include "call.h" -#include "call_credentials.h" -#include "channel.h" -#include "channel_credentials.h" -#include "completion_queue.h" -#include "server.h" -#include "server_credentials.h" -#include "slice.h" -#include "timeval.h" - -using grpc::node::CreateSliceFromString; - -using v8::FunctionTemplate; -using v8::Local; -using v8::Value; -using v8::Number; -using v8::Object; -using v8::Uint32; -using v8::String; - -typedef struct log_args { - gpr_log_func_args core_args; - gpr_timespec timestamp; -} log_args; - -typedef struct logger_state { - Nan::Callback *callback; - Nan::AsyncResource *async_resource; - std::queue *pending_args; - uv_mutex_t mutex; - uv_async_t async; - // Indicates that a logger has been set - bool logger_set; -} logger_state; - -logger_state grpc_logger_state; - -static char *pem_root_certs = NULL; - -void InitOpTypeConstants(Local exports) { - Nan::HandleScope scope; - Local op_type = Nan::New(); - Nan::Set(exports, Nan::New("opType").ToLocalChecked(), op_type); - Local SEND_INITIAL_METADATA( - Nan::New(GRPC_OP_SEND_INITIAL_METADATA)); - Nan::Set(op_type, Nan::New("SEND_INITIAL_METADATA").ToLocalChecked(), - SEND_INITIAL_METADATA); - Local SEND_MESSAGE(Nan::New(GRPC_OP_SEND_MESSAGE)); - Nan::Set(op_type, Nan::New("SEND_MESSAGE").ToLocalChecked(), SEND_MESSAGE); - Local SEND_CLOSE_FROM_CLIENT( - Nan::New(GRPC_OP_SEND_CLOSE_FROM_CLIENT)); - Nan::Set(op_type, Nan::New("SEND_CLOSE_FROM_CLIENT").ToLocalChecked(), - SEND_CLOSE_FROM_CLIENT); - Local SEND_STATUS_FROM_SERVER( - Nan::New(GRPC_OP_SEND_STATUS_FROM_SERVER)); - Nan::Set(op_type, Nan::New("SEND_STATUS_FROM_SERVER").ToLocalChecked(), - SEND_STATUS_FROM_SERVER); - Local RECV_INITIAL_METADATA( - Nan::New(GRPC_OP_RECV_INITIAL_METADATA)); - Nan::Set(op_type, Nan::New("RECV_INITIAL_METADATA").ToLocalChecked(), - RECV_INITIAL_METADATA); - Local RECV_MESSAGE(Nan::New(GRPC_OP_RECV_MESSAGE)); - Nan::Set(op_type, Nan::New("RECV_MESSAGE").ToLocalChecked(), RECV_MESSAGE); - Local RECV_STATUS_ON_CLIENT( - Nan::New(GRPC_OP_RECV_STATUS_ON_CLIENT)); - Nan::Set(op_type, Nan::New("RECV_STATUS_ON_CLIENT").ToLocalChecked(), - RECV_STATUS_ON_CLIENT); - Local RECV_CLOSE_ON_SERVER( - Nan::New(GRPC_OP_RECV_CLOSE_ON_SERVER)); - Nan::Set(op_type, Nan::New("RECV_CLOSE_ON_SERVER").ToLocalChecked(), - RECV_CLOSE_ON_SERVER); -} - -void InitConnectivityStateConstants(Local exports) { - Nan::HandleScope scope; - Local channel_state = Nan::New(); - Nan::Set(exports, Nan::New("connectivityState").ToLocalChecked(), - channel_state); - Local IDLE(Nan::New(GRPC_CHANNEL_IDLE)); - Nan::Set(channel_state, Nan::New("IDLE").ToLocalChecked(), IDLE); - Local CONNECTING(Nan::New(GRPC_CHANNEL_CONNECTING)); - Nan::Set(channel_state, Nan::New("CONNECTING").ToLocalChecked(), CONNECTING); - Local READY(Nan::New(GRPC_CHANNEL_READY)); - Nan::Set(channel_state, Nan::New("READY").ToLocalChecked(), READY); - Local TRANSIENT_FAILURE( - Nan::New(GRPC_CHANNEL_TRANSIENT_FAILURE)); - Nan::Set(channel_state, Nan::New("TRANSIENT_FAILURE").ToLocalChecked(), - TRANSIENT_FAILURE); - Local FATAL_FAILURE(Nan::New(GRPC_CHANNEL_SHUTDOWN)); - Nan::Set(channel_state, Nan::New("FATAL_FAILURE").ToLocalChecked(), - FATAL_FAILURE); -} - -NAN_METHOD(MetadataKeyIsLegal) { - if (!info[0]->IsString()) { - return Nan::ThrowTypeError("headerKeyIsLegal's argument must be a string"); - } - Local key = Nan::To(info[0]).ToLocalChecked(); - grpc_slice slice = CreateSliceFromString(key); - info.GetReturnValue().Set(static_cast(grpc_header_key_is_legal(slice))); - grpc_slice_unref(slice); -} - -NAN_METHOD(MetadataNonbinValueIsLegal) { - if (!info[0]->IsString()) { - return Nan::ThrowTypeError( - "metadataNonbinValueIsLegal's argument must be a string"); - } - Local value = Nan::To(info[0]).ToLocalChecked(); - grpc_slice slice = CreateSliceFromString(value); - info.GetReturnValue().Set( - static_cast(grpc_header_nonbin_value_is_legal(slice))); - grpc_slice_unref(slice); -} - -NAN_METHOD(MetadataKeyIsBinary) { - if (!info[0]->IsString()) { - return Nan::ThrowTypeError( - "metadataKeyIsLegal's argument must be a string"); - } - Local key = Nan::To(info[0]).ToLocalChecked(); - grpc_slice slice = CreateSliceFromString(key); - info.GetReturnValue().Set(static_cast(grpc_is_binary_header(slice))); - grpc_slice_unref(slice); -} - -static grpc_ssl_roots_override_result get_ssl_roots_override( - char **pem_root_certs_ptr) { - *pem_root_certs_ptr = pem_root_certs; - if (pem_root_certs == NULL) { - return GRPC_SSL_ROOTS_OVERRIDE_FAIL; - } else { - return GRPC_SSL_ROOTS_OVERRIDE_OK; - } -} - -/* This should only be called once, and only before creating any - *ServerCredentials */ -NAN_METHOD(SetDefaultRootsPem) { - if (!info[0]->IsString()) { - return Nan::ThrowTypeError( - "setDefaultRootsPem's argument must be a string"); - } - Nan::Utf8String utf8_roots(info[0]); - size_t length = static_cast(utf8_roots.length()); - if (length > 0) { - const char *data = *utf8_roots; - pem_root_certs = (char *)gpr_malloc((length + 1) * sizeof(char)); - memcpy(pem_root_certs, data, length + 1); - } -} - -NAUV_WORK_CB(LogMessagesCallback) { - Nan::HandleScope scope; - std::queue args; - uv_mutex_lock(&grpc_logger_state.mutex); - grpc_logger_state.pending_args->swap(args); - uv_mutex_unlock(&grpc_logger_state.mutex); - /* Call the callback with each log message */ - while (!args.empty()) { - log_args *arg = args.front(); - args.pop(); - Local file = Nan::New(arg->core_args.file).ToLocalChecked(); - Local line = Nan::New(arg->core_args.line); - Local severity = - Nan::New(gpr_log_severity_string(arg->core_args.severity)) - .ToLocalChecked(); - Local message = Nan::New(arg->core_args.message).ToLocalChecked(); - Local timestamp = - Nan::New(grpc::node::TimespecToMilliseconds(arg->timestamp)) - .ToLocalChecked(); - const int argc = 5; - Local argv[argc] = {file, line, severity, message, timestamp}; - grpc_logger_state.callback->Call(argc, argv, grpc_logger_state.async_resource); - delete[] arg->core_args.message; - delete arg; - } -} - -void node_log_func(gpr_log_func_args *args) { - // TODO(mlumish): Use the core's log formatter when it becomes available - log_args *args_copy = new log_args; - size_t message_len = strlen(args->message) + 1; - char *message = new char[message_len]; - memcpy(message, args->message, message_len); - memcpy(&args_copy->core_args, args, sizeof(gpr_log_func_args)); - args_copy->core_args.message = message; - args_copy->timestamp = gpr_now(GPR_CLOCK_REALTIME); - - uv_mutex_lock(&grpc_logger_state.mutex); - grpc_logger_state.pending_args->push(args_copy); - uv_mutex_unlock(&grpc_logger_state.mutex); - - uv_async_send(&grpc_logger_state.async); -} - -void init_logger() { - memset(&grpc_logger_state, 0, sizeof(logger_state)); - grpc_logger_state.pending_args = new std::queue(); - uv_mutex_init(&grpc_logger_state.mutex); - uv_async_init(uv_default_loop(), &grpc_logger_state.async, - LogMessagesCallback); - uv_unref((uv_handle_t *)&grpc_logger_state.async); - grpc_logger_state.logger_set = false; - - gpr_log_verbosity_init(); -} - -/* This registers a JavaScript logger for messages from the gRPC core. Because - that handler has to be run in the context of the JavaScript event loop, it - will be run asynchronously. To minimize the problems that could cause for - debugging, we leave core to do its default synchronous logging until a - JavaScript logger is set */ -NAN_METHOD(SetDefaultLoggerCallback) { - if (!info[0]->IsFunction()) { - return Nan::ThrowTypeError( - "setDefaultLoggerCallback's argument must be a function"); - } - if (!grpc_logger_state.logger_set) { - gpr_set_log_function(node_log_func); - grpc_logger_state.logger_set = true; - } - grpc_logger_state.callback = new Nan::Callback(info[0].As()); - grpc_logger_state.async_resource = new Nan::AsyncResource("grpc:logger"); -} - -NAN_METHOD(SetLogVerbosity) { - if (!info[0]->IsUint32()) { - return Nan::ThrowTypeError("setLogVerbosity's argument must be a number"); - } - gpr_log_severity severity = - static_cast(Nan::To(info[0]).FromJust()); - gpr_set_log_verbosity(severity); -} - -NAN_METHOD(ForcePoll) { - grpc::node::CompletionQueueForcePoll(); -} - -void init(Local exports) { - Nan::HandleScope scope; - grpc_init(); - grpc_set_ssl_roots_override_callback(get_ssl_roots_override); - init_logger(); - - InitOpTypeConstants(exports); - InitConnectivityStateConstants(exports); - - grpc_pollset_work_run_loop = 0; - - grpc::node::Call::Init(exports); - grpc::node::CallCredentials::Init(exports); - grpc::node::Channel::Init(exports); - grpc::node::ChannelCredentials::Init(exports); - grpc::node::Server::Init(exports); - grpc::node::ServerCredentials::Init(exports); - - grpc::node::CompletionQueueInit(exports); - - // Attach a few utility functions directly to the module - Nan::Set(exports, Nan::New("metadataKeyIsLegal").ToLocalChecked(), - Nan::GetFunction(Nan::New(MetadataKeyIsLegal)) - .ToLocalChecked()); - Nan::Set( - exports, Nan::New("metadataNonbinValueIsLegal").ToLocalChecked(), - Nan::GetFunction(Nan::New(MetadataNonbinValueIsLegal)) - .ToLocalChecked()); - Nan::Set(exports, Nan::New("metadataKeyIsBinary").ToLocalChecked(), - Nan::GetFunction(Nan::New(MetadataKeyIsBinary)) - .ToLocalChecked()); - Nan::Set(exports, Nan::New("setDefaultRootsPem").ToLocalChecked(), - Nan::GetFunction(Nan::New(SetDefaultRootsPem)) - .ToLocalChecked()); - Nan::Set( - exports, Nan::New("setDefaultLoggerCallback").ToLocalChecked(), - Nan::GetFunction(Nan::New(SetDefaultLoggerCallback)) - .ToLocalChecked()); - Nan::Set(exports, Nan::New("setLogVerbosity").ToLocalChecked(), - Nan::GetFunction(Nan::New(SetLogVerbosity)) - .ToLocalChecked()); - Nan::Set(exports, Nan::New("forcePoll").ToLocalChecked(), - Nan::GetFunction(Nan::New(ForcePoll)) - .ToLocalChecked()); -} - -NODE_MODULE(grpc_node, init) diff --git a/packages/grpc-native-core/ext/server.cc b/packages/grpc-native-core/ext/server.cc deleted file mode 100644 index aa56b5e59..000000000 --- a/packages/grpc-native-core/ext/server.cc +++ /dev/null @@ -1,313 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include "server.h" - -#include -#include - -#include -#include "call.h" -#include "completion_queue.h" -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/log.h" -#include "server_credentials.h" -#include "slice.h" -#include "timeval.h" - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::EscapableHandleScope; -using Nan::HandleScope; -using Nan::Maybe; -using Nan::MaybeLocal; -using Nan::ObjectWrap; -using Nan::Persistent; -using Nan::Utf8String; - -using std::unique_ptr; -using v8::Array; -using v8::Boolean; -using v8::Date; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Local; -using v8::Number; -using v8::Object; -using v8::String; -using v8::Value; - -Nan::Callback *Server::constructor; -Persistent Server::fun_tpl; - -static Persistent shutdown_cb; - -class ServerShutdownOp : public Op { - public: - ServerShutdownOp(Server *server) : server(server) {} - - ~ServerShutdownOp() {} - - Local GetNodeValue() const { - EscapableHandleScope scope; - return scope.Escape(server->handle()); - } - - bool ParseOp(Local value, grpc_op *out) { return true; } - bool IsFinalOp() { return false; } - void OnComplete(bool success) { - if (success) { - server->FinishShutdown(); - } - } - - Server *server; - - protected: - std::string GetTypeString() const { return "try_shutdown"; } -}; - -class NewCallOp : public Op { - public: - NewCallOp() { - call = NULL; - grpc_call_details_init(&details); - grpc_metadata_array_init(&request_metadata); - } - - ~NewCallOp() { - grpc_call_details_destroy(&details); - grpc_metadata_array_destroy(&request_metadata); - } - - Local GetNodeValue() const { - Nan::EscapableHandleScope scope; - if (call == NULL) { - return scope.Escape(Nan::Null()); - } - Local obj = Nan::New(); - Nan::Set(obj, Nan::New("call").ToLocalChecked(), Call::WrapStruct(call)); - // TODO(murgatroid99): Use zero-copy string construction instead - Nan::Set(obj, Nan::New("method").ToLocalChecked(), - CopyStringFromSlice(details.method)); - Nan::Set(obj, Nan::New("host").ToLocalChecked(), - CopyStringFromSlice(details.host)); - Nan::Set(obj, Nan::New("deadline").ToLocalChecked(), - Nan::New(TimespecToMilliseconds(details.deadline)) - .ToLocalChecked()); - Nan::Set(obj, Nan::New("metadata").ToLocalChecked(), - ParseMetadata(&request_metadata)); - return scope.Escape(obj); - } - - bool ParseOp(Local value, grpc_op *out) { return true; } - bool IsFinalOp() { return false; } - void OnComplete(bool success) {} - - grpc_call *call; - grpc_call_details details; - grpc_metadata_array request_metadata; - - protected: - std::string GetTypeString() const { return "new_call"; } -}; - -NAN_METHOD(ShutdownCallback) { - HandleScope scope; - if (!info[0]->IsNull()) { - return Nan::ThrowError("forceShutdown failed somehow"); - } -} - -Server::Server(grpc_server *server) : - wrapped_server(server), is_shutdown(false) {} - -Server::~Server() { grpc_server_destroy(this->wrapped_server); } - -void Server::Init(Local exports) { - HandleScope scope; - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("Server").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - Nan::SetPrototypeMethod(tpl, "requestCall", RequestCall); - Nan::SetPrototypeMethod(tpl, "addHttp2Port", AddHttp2Port); - Nan::SetPrototypeMethod(tpl, "start", Start); - Nan::SetPrototypeMethod(tpl, "tryShutdown", TryShutdown); - Nan::SetPrototypeMethod(tpl, "forceShutdown", ForceShutdown); - fun_tpl.Reset(tpl); - Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); - Nan::Set(exports, Nan::New("Server").ToLocalChecked(), ctr); - constructor = new Callback(ctr); - Local shutdown_tpl = - Nan::New(ShutdownCallback); - shutdown_cb.Reset(Nan::GetFunction(shutdown_tpl).ToLocalChecked()); -} - -bool Server::HasInstance(Local val) { - HandleScope scope; - return Nan::New(fun_tpl)->HasInstance(val); -} - -void Server::FinishShutdown() { - is_shutdown = true; - running_self_ref.Reset(); -} - -void Server::ShutdownServer() { - Nan::HandleScope scope; - if (!this->is_shutdown) { - Callback *shutdown_callback = - new Callback(Nan::New(shutdown_cb)); - ServerShutdownOp *op = new ServerShutdownOp(this); - unique_ptr ops(new OpVec()); - ops->push_back(unique_ptr(op)); - - grpc_server_shutdown_and_notify( - this->wrapped_server, GetCompletionQueue(), - new struct tag(shutdown_callback, ops.release(), NULL, Nan::Null())); - grpc_server_cancel_all_calls(this->wrapped_server); - CompletionQueueNext(); - } -} - -NAN_METHOD(Server::New) { - /* If this is not a constructor call, make a constructor call and return - the result */ - if (!info.IsConstructCall()) { - const int argc = 1; - Local argv[argc] = {info[0]}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - // There's probably a pending exception - return; - } else { - info.GetReturnValue().Set(maybe_instance.ToLocalChecked()); - return; - } - } - grpc_server *wrapped_server; - grpc_completion_queue *queue = GetCompletionQueue(); - grpc_channel_args *channel_args; - if (!ParseChannelArgs(info[0], &channel_args)) { - DeallocateChannelArgs(channel_args); - return Nan::ThrowTypeError( - "Server options must be an object with " - "string keys and integer or string values"); - } - wrapped_server = grpc_server_create(channel_args, NULL); - DeallocateChannelArgs(channel_args); - grpc_server_register_completion_queue(wrapped_server, queue, NULL); - Server *server = new Server(wrapped_server); - server->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); -} - -NAN_METHOD(Server::RequestCall) { - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("requestCall can only be called on a Server"); - } - Server *server = ObjectWrap::Unwrap(info.This()); - NewCallOp *op = new NewCallOp(); - unique_ptr ops(new OpVec()); - ops->push_back(unique_ptr(op)); - grpc_call_error error = grpc_server_request_call( - server->wrapped_server, &op->call, &op->details, &op->request_metadata, - GetCompletionQueue(), GetCompletionQueue(), - new struct tag(new Callback(info[0].As()), ops.release(), NULL, - Nan::Null())); - if (error != GRPC_CALL_OK) { - return Nan::ThrowError(nanErrorWithCode("requestCall failed", error)); - } - CompletionQueueNext(); -} - -NAN_METHOD(Server::AddHttp2Port) { - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("addHttp2Port can only be called on a Server"); - } - if (!info[0]->IsString()) { - return Nan::ThrowTypeError( - "addHttp2Port's first argument must be a String"); - } - if (!ServerCredentials::HasInstance(info[1])) { - return Nan::ThrowTypeError( - "addHttp2Port's second argument must be ServerCredentials"); - } - Server *server = ObjectWrap::Unwrap(info.This()); - ServerCredentials *creds_object = ObjectWrap::Unwrap( - Nan::To(info[1]).ToLocalChecked()); - grpc_server_credentials *creds = creds_object->GetWrappedServerCredentials(); - int port; - if (creds == NULL) { - port = grpc_server_add_insecure_http2_port(server->wrapped_server, - *Utf8String(info[0])); - } else { - port = grpc_server_add_secure_http2_port(server->wrapped_server, - *Utf8String(info[0]), creds); - } - info.GetReturnValue().Set(Nan::New(port)); -} - -NAN_METHOD(Server::Start) { - Nan::HandleScope scope; - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("start can only be called on a Server"); - } - Server *server = ObjectWrap::Unwrap(info.This()); - server->running_self_ref.Reset(info.This()); - grpc_server_start(server->wrapped_server); -} - -NAN_METHOD(Server::TryShutdown) { - Nan::HandleScope scope; - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("tryShutdown can only be called on a Server"); - } - if (!info[0]->IsFunction()) { - return Nan::ThrowError("tryShutdown's argument must be a callback"); - } - Server *server = ObjectWrap::Unwrap(info.This()); - ServerShutdownOp *op = new ServerShutdownOp(server); - unique_ptr ops(new OpVec()); - ops->push_back(unique_ptr(op)); - grpc_server_shutdown_and_notify( - server->wrapped_server, GetCompletionQueue(), - new struct tag(new Nan::Callback(info[0].As()), ops.release(), - NULL, Nan::Null())); - CompletionQueueNext(); -} - -NAN_METHOD(Server::ForceShutdown) { - Nan::HandleScope scope; - if (!HasInstance(info.This())) { - return Nan::ThrowTypeError("forceShutdown can only be called on a Server"); - } - Server *server = ObjectWrap::Unwrap(info.This()); - server->ShutdownServer(); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/server.h b/packages/grpc-native-core/ext/server.h deleted file mode 100644 index 6637e0898..000000000 --- a/packages/grpc-native-core/ext/server.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_SERVER_H_ -#define NET_GRPC_NODE_SERVER_H_ - -#include -#include -#include "grpc/grpc.h" - -namespace grpc { -namespace node { - -/* Wraps grpc_server as a JavaScript object. Provides a constructor - and wrapper methods for grpc_server_create, grpc_server_request_call, - grpc_server_add_http2_port, and grpc_server_start. */ -class Server : public Nan::ObjectWrap { - public: - /* Initializes the Server class and exposes the constructor and - wrapper methods to JavaScript */ - static void Init(v8::Local exports); - /* Tests whether the given value was constructed by this class's - JavaScript constructor */ - static bool HasInstance(v8::Local val); - - void FinishShutdown(); - - private: - explicit Server(grpc_server *server); - ~Server(); - - // Prevent copying - Server(const Server &); - Server &operator=(const Server &); - - void ShutdownServer(); - - static NAN_METHOD(New); - static NAN_METHOD(RequestCall); - static NAN_METHOD(AddHttp2Port); - static NAN_METHOD(Start); - static NAN_METHOD(TryShutdown); - static NAN_METHOD(ForceShutdown); - static Nan::Callback *constructor; - static Nan::Persistent fun_tpl; - Nan::Persistent running_self_ref; - - grpc_server *wrapped_server; - bool is_shutdown; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_SERVER_H_ diff --git a/packages/grpc-native-core/ext/server_credentials.cc b/packages/grpc-native-core/ext/server_credentials.cc deleted file mode 100644 index fe26e3a91..000000000 --- a/packages/grpc-native-core/ext/server_credentials.cc +++ /dev/null @@ -1,192 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include - -#include -#include - -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" -#include "grpc/support/log.h" -#include "server_credentials.h" -#include "util.h" - -namespace grpc { -namespace node { - -using Nan::Callback; -using Nan::EscapableHandleScope; -using Nan::HandleScope; -using Nan::Maybe; -using Nan::MaybeLocal; -using Nan::ObjectWrap; -using Nan::Persistent; -using Nan::Utf8String; - -using v8::Array; -using v8::Exception; -using v8::External; -using v8::Function; -using v8::FunctionTemplate; -using v8::Integer; -using v8::Local; -using v8::Object; -using v8::ObjectTemplate; -using v8::String; -using v8::Value; - -Nan::Callback *ServerCredentials::constructor; -Persistent ServerCredentials::fun_tpl; - -ServerCredentials::ServerCredentials(grpc_server_credentials *credentials) - : wrapped_credentials(credentials) {} - -ServerCredentials::~ServerCredentials() { - grpc_server_credentials_release(wrapped_credentials); -} - -void ServerCredentials::Init(Local exports) { - Nan::HandleScope scope; - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("ServerCredentials").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - Local ctr = Nan::GetFunction(tpl).ToLocalChecked(); - Nan::Set( - ctr, Nan::New("createSsl").ToLocalChecked(), - Nan::GetFunction(Nan::New(CreateSsl)).ToLocalChecked()); - Nan::Set(ctr, Nan::New("createInsecure").ToLocalChecked(), - Nan::GetFunction(Nan::New(CreateInsecure)) - .ToLocalChecked()); - fun_tpl.Reset(tpl); - constructor = new Nan::Callback(ctr); - Nan::Set(exports, Nan::New("ServerCredentials").ToLocalChecked(), ctr); -} - -bool ServerCredentials::HasInstance(Local val) { - Nan::HandleScope scope; - return Nan::New(fun_tpl)->HasInstance(val); -} - -Local ServerCredentials::WrapStruct( - grpc_server_credentials *credentials) { - Nan::EscapableHandleScope scope; - const int argc = 1; - Local argv[argc] = { - Nan::New(reinterpret_cast(credentials))}; - MaybeLocal maybe_instance = - Nan::NewInstance(constructor->GetFunction(), argc, argv); - if (maybe_instance.IsEmpty()) { - return scope.Escape(Nan::Null()); - } else { - return scope.Escape(maybe_instance.ToLocalChecked()); - } -} - -grpc_server_credentials *ServerCredentials::GetWrappedServerCredentials() { - return wrapped_credentials; -} - -NAN_METHOD(ServerCredentials::New) { - if (info.IsConstructCall()) { - if (!info[0]->IsExternal()) { - return Nan::ThrowTypeError( - "ServerCredentials can only be created with the provided functions"); - } - Local ext = info[0].As(); - grpc_server_credentials *creds_value = - reinterpret_cast(ext->Value()); - ServerCredentials *credentials = new ServerCredentials(creds_value); - credentials->Wrap(info.This()); - info.GetReturnValue().Set(info.This()); - } else { - // This should never be called directly - return Nan::ThrowTypeError( - "ServerCredentials can only be created with the provided functions"); - } -} - -NAN_METHOD(ServerCredentials::CreateSsl) { - Nan::HandleScope scope; - StringOrNull root_certs; - if (::node::Buffer::HasInstance(info[0])) { - root_certs.assign(info[0]); - } else if (!(info[0]->IsNull() || info[0]->IsUndefined())) { - return Nan::ThrowTypeError( - "createSSl's first argument must be a Buffer if provided"); - } - if (!info[1]->IsArray()) { - return Nan::ThrowTypeError( - "createSsl's second argument must be a list of objects"); - } - - // Default to not requesting the client certificate - grpc_ssl_client_certificate_request_type client_certificate_request = - GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE; - if (info[2]->IsBoolean()) { - client_certificate_request = - Nan::To(info[2]).FromJust() - ? GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY - : GRPC_SSL_DONT_REQUEST_CLIENT_CERTIFICATE; - } else if (!(info[2]->IsUndefined() || info[2]->IsNull())) { - return Nan::ThrowTypeError( - "createSsl's third argument must be a boolean if provided"); - } - Local pair_list = Local::Cast(info[1]); - uint32_t key_cert_pair_count = pair_list->Length(); - std::vector key_cert_pairs(key_cert_pair_count); - std::vector key_strings(key_cert_pair_count); - std::vector cert_strings(key_cert_pair_count); - Local key_key = Nan::New("private_key").ToLocalChecked(); - Local cert_key = Nan::New("cert_chain").ToLocalChecked(); - - for (uint32_t i = 0; i < key_cert_pair_count; i++) { - Local pair_val = Nan::Get(pair_list, i).ToLocalChecked(); - if (!pair_val->IsObject()) { - return Nan::ThrowTypeError("Key/cert pairs must be objects"); - } - Local pair_obj = Nan::To(pair_val).ToLocalChecked(); - Local maybe_key = Nan::Get(pair_obj, key_key).ToLocalChecked(); - Local maybe_cert = Nan::Get(pair_obj, cert_key).ToLocalChecked(); - if (!::node::Buffer::HasInstance(maybe_key)) { - return Nan::ThrowTypeError("private_key must be a Buffer"); - } - if (!::node::Buffer::HasInstance(maybe_cert)) { - return Nan::ThrowTypeError("cert_chain must be a Buffer"); - } - key_strings[i].assign(maybe_key); - cert_strings[i].assign(maybe_cert); - key_cert_pairs[i].private_key = key_strings[i].get(); - key_cert_pairs[i].cert_chain = cert_strings[i].get(); - } - grpc_server_credentials *creds = grpc_ssl_server_credentials_create_ex( - root_certs.get(), key_cert_pairs.data(), key_cert_pair_count, - client_certificate_request, NULL); - if (creds == NULL) { - info.GetReturnValue().SetNull(); - } else { - info.GetReturnValue().Set(WrapStruct(creds)); - } -} - -NAN_METHOD(ServerCredentials::CreateInsecure) { - info.GetReturnValue().Set(WrapStruct(NULL)); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/server_credentials.h b/packages/grpc-native-core/ext/server_credentials.h deleted file mode 100644 index 59f91481a..000000000 --- a/packages/grpc-native-core/ext/server_credentials.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_SERVER_CREDENTIALS_H_ -#define NET_GRPC_NODE_SERVER_CREDENTIALS_H_ - -#include -#include -#include "grpc/grpc.h" -#include "grpc/grpc_security.h" - -namespace grpc { -namespace node { - -/* Wrapper class for grpc_server_credentials structs */ -class ServerCredentials : public Nan::ObjectWrap { - public: - static void Init(v8::Local exports); - static bool HasInstance(v8::Local val); - /* Wrap a grpc_server_credentials struct in a javascript object */ - static v8::Local WrapStruct(grpc_server_credentials *credentials); - - /* Returns the grpc_server_credentials struct that this object wraps */ - grpc_server_credentials *GetWrappedServerCredentials(); - - private: - explicit ServerCredentials(grpc_server_credentials *credentials); - ~ServerCredentials(); - - // Prevent copying - ServerCredentials(const ServerCredentials &); - ServerCredentials &operator=(const ServerCredentials &); - - static NAN_METHOD(New); - static NAN_METHOD(CreateSsl); - static NAN_METHOD(CreateInsecure); - static Nan::Callback *constructor; - // Used for typechecking instances of this javascript class - static Nan::Persistent fun_tpl; - - grpc_server_credentials *wrapped_credentials; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_SERVER_CREDENTIALS_H_ diff --git a/packages/grpc-native-core/ext/slice.cc b/packages/grpc-native-core/ext/slice.cc deleted file mode 100644 index 49bc05b01..000000000 --- a/packages/grpc-native-core/ext/slice.cc +++ /dev/null @@ -1,90 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include -#include - -#include "slice.h" - -namespace grpc { -namespace node { - -using Nan::Persistent; - -using v8::Local; -using v8::String; -using v8::Value; - -namespace { -void SliceFreeCallback(char *data, void *hint) { - grpc_slice *slice = reinterpret_cast(hint); - grpc_slice_unref(*slice); - delete slice; -} - -void string_destroy_func(void *user_data) { - delete reinterpret_cast(user_data); -} - -void buffer_destroy_func(void *user_data) { - delete reinterpret_cast(user_data); -} -} // namespace - -grpc_slice CreateSliceFromString(const Local source) { - Nan::HandleScope scope; - Nan::Utf8String *utf8_value = new Nan::Utf8String(source); - return grpc_slice_new_with_user_data(**utf8_value, utf8_value->length(), - string_destroy_func, utf8_value); -} - -grpc_slice CreateSliceFromBuffer(const Local source) { - // Prerequisite: ::node::Buffer::HasInstance(source) - Nan::HandleScope scope; - return grpc_slice_new_with_user_data( - ::node::Buffer::Data(source), ::node::Buffer::Length(source), - buffer_destroy_func, new PersistentValue(source)); -} -Local CopyStringFromSlice(const grpc_slice slice) { - Nan::EscapableHandleScope scope; - if (GRPC_SLICE_LENGTH(slice) == 0) { - return scope.Escape(Nan::EmptyString()); - } - return scope.Escape( - Nan::New(const_cast(reinterpret_cast( - GRPC_SLICE_START_PTR(slice))), - GRPC_SLICE_LENGTH(slice)) - .ToLocalChecked()); -} - -Local CreateBufferFromSlice(const grpc_slice slice) { - Nan::EscapableHandleScope scope; - grpc_slice *slice_ptr = new grpc_slice; - *slice_ptr = grpc_slice_ref(slice); - return scope.Escape( - Nan::NewBuffer( - const_cast( - reinterpret_cast(GRPC_SLICE_START_PTR(*slice_ptr))), - GRPC_SLICE_LENGTH(*slice_ptr), SliceFreeCallback, slice_ptr) - .ToLocalChecked()); -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/slice.h b/packages/grpc-native-core/ext/slice.h deleted file mode 100644 index 0a652c575..000000000 --- a/packages/grpc-native-core/ext/slice.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include -#include - -namespace grpc { -namespace node { - -typedef Nan::Persistent> - PersistentValue; - -grpc_slice CreateSliceFromString(const v8::Local source); - -grpc_slice CreateSliceFromBuffer(const v8::Local source); - -v8::Local CopyStringFromSlice(const grpc_slice slice); - -v8::Local CreateBufferFromSlice(const grpc_slice slice); - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/timeval.cc b/packages/grpc-native-core/ext/timeval.cc deleted file mode 100644 index 614258475..000000000 --- a/packages/grpc-native-core/ext/timeval.cc +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include -#include - -#include "grpc/grpc.h" -#include "grpc/support/time.h" -#include "timeval.h" - -namespace grpc { -namespace node { - -gpr_timespec MillisecondsToTimespec(double millis) { - if (millis == std::numeric_limits::infinity()) { - return gpr_inf_future(GPR_CLOCK_REALTIME); - } else if (millis == -std::numeric_limits::infinity()) { - return gpr_inf_past(GPR_CLOCK_REALTIME); - } else { - return gpr_time_from_micros(static_cast(millis * 1000), - GPR_CLOCK_REALTIME); - } -} - -double TimespecToMilliseconds(gpr_timespec timespec) { - timespec = gpr_convert_clock_type(timespec, GPR_CLOCK_REALTIME); - if (gpr_time_cmp(timespec, gpr_inf_future(GPR_CLOCK_REALTIME)) == 0) { - return std::numeric_limits::infinity(); - } else if (gpr_time_cmp(timespec, gpr_inf_past(GPR_CLOCK_REALTIME)) == 0) { - return -std::numeric_limits::infinity(); - } else { - return (static_cast(timespec.tv_sec) * 1000 + - static_cast(timespec.tv_nsec) / 1000000); - } -} - -} // namespace node -} // namespace grpc diff --git a/packages/grpc-native-core/ext/timeval.h b/packages/grpc-native-core/ext/timeval.h deleted file mode 100644 index 17d7f1642..000000000 --- a/packages/grpc-native-core/ext/timeval.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_TIMEVAL_H_ -#define NET_GRPC_NODE_TIMEVAL_H_ - -#include "grpc/support/time.h" - -namespace grpc { -namespace node { - -double TimespecToMilliseconds(gpr_timespec time); -gpr_timespec MillisecondsToTimespec(double millis); - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_TIMEVAL_H_ diff --git a/packages/grpc-native-core/ext/util.h b/packages/grpc-native-core/ext/util.h deleted file mode 100644 index c481922aa..000000000 --- a/packages/grpc-native-core/ext/util.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#ifndef NET_GRPC_NODE_UTIL_H_ -#define NET_GRPC_NODE_UTIL_H_ - -#include -#include - -#include - -namespace grpc { -namespace node { - -class StringOrNull { - public: - StringOrNull() : assigned(false) { } - void assign(v8::Local buffer) { - str_ = std::string(::node::Buffer::Data(buffer), - ::node::Buffer::Length(buffer)); - assigned = true; - } - const char * get() { - return assigned ? str_.c_str() : NULL; - } - bool isAssigned() { - return assigned; - } - private: - std::string str_; - bool assigned; -}; - -} // namespace node -} // namespace grpc - -#endif // NET_GRPC_NODE_UTIL_H_ diff --git a/packages/grpc-native-core/gulpfile.ts b/packages/grpc-native-core/gulpfile.ts deleted file mode 100644 index 6950f06d7..000000000 --- a/packages/grpc-native-core/gulpfile.ts +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - - import * as gulp from 'gulp'; - import * as jsdoc from 'gulp-jsdoc3'; - import * as jshint from 'gulp-jshint'; - import * as mocha from 'gulp-mocha'; - import * as execa from 'execa'; - import * as path from 'path'; - import * as del from 'del'; - -const nativeCoreDir = __dirname; -const srcDir = path.resolve(nativeCoreDir, 'src'); -const testDir = path.resolve(nativeCoreDir, 'test'); - -const pkg = require('./package'); -const jshintConfig = pkg.jshintConfig; - -const clean = () => del([path.resolve(nativeCoreDir, 'build'), - path.resolve(nativeCoreDir, 'ext/node')]); - -const cleanAll = gulp.parallel(clean); - -const install = () => { - return execa('npm', ['install', '--build-from-source', '--unsafe-perm'], - {cwd: nativeCoreDir, stdio: 'inherit'}); -}; - -const installWindows = () => { - return execa('npm', ['install', '--build-from-source'], - {cwd: nativeCoreDir, stdio: 'inherit'}).catch(() => -del(path.resolve(process.env.USERPROFILE, '.node-gyp', process.versions.node, 'include/node/openssl'), { force: true }).then(() => -del(path.resolve(process.env.USERPROFILE, 'AppData/Local/node-gyp/cache', process.versions.node, 'include/node/openssl'), { force: true })).then(() => -execa('npm', ['install', '--build-from-source'], - {cwd: nativeCoreDir, stdio: 'inherit'}) - )); -}; - -const lint = () => { - return gulp.src([`${nativeCoreDir}/index.js`, `${srcDir}/*.js`, `${testDir}/*.js`]) - .pipe(jshint(pkg.jshintConfig)) - .pipe(jshint.reporter('default')); -}; - -const build = () => { - return execa('npm', ['run', 'build'], {cwd: nativeCoreDir, stdio: 'inherit'}); -}; - -const runTests = () => { - return gulp.src(`${testDir}/*.js`).pipe(mocha({timeout: 5000, reporter: 'mocha-jenkins-reporter'})); -} - -const test = gulp.series(build, runTests); - -const docGen = (cb) => { - var config = require('./jsdoc_conf.json'); - return gulp.src([`${nativeCoreDir}/README.md`, `${nativeCoreDir}/index.js`, `${srcDir}/*.js`], {read: false}) - .pipe(jsdoc(config, cb)); -}; - -export { - clean, - cleanAll, - install, - installWindows, - lint, - build, - test, - docGen -}; \ No newline at end of file diff --git a/packages/grpc-native-core/index.d.ts b/packages/grpc-native-core/index.d.ts deleted file mode 100644 index 33956aa11..000000000 --- a/packages/grpc-native-core/index.d.ts +++ /dev/null @@ -1,1658 +0,0 @@ - -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/// - -declare module "grpc" { - // add imports here, inside the "grpc" module, to keep it as an ambient module - import { EventEmitter } from "events"; - import { Duplex, Readable, Writable } from "stream"; - import { SecureContext } from "tls"; - - /* The Message interface is copied and slightly modified from @types/protobuf - * version 5.0.31, which was distributed under the following license: - * - * This project is licensed under the MIT license. - * Copyrights are respective of each contributor listed at the beginning of each definition file. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - export interface ProtobufMessage { - $add(key: string, value: any, noAssert?: boolean): ProtobufMessage; - $get(key: string): T; - $set(key: string | {[key: string]: any}, value?: any | boolean, noAssert?: boolean): void; - add(key: string, value: any, noAssert?: boolean): ProtobufMessage; - calculate(): number; - encode(buffer?: ByteBuffer | boolean, noVerify?: boolean): ByteBuffer; - encode64(): string; - encodeAB(): ArrayBuffer; - encodeNB(): Buffer; - encodeHex(): string; - encodeJSON(): string; - encodeDelimited(buffer?: ByteBuffer | boolean, noVerify?: boolean): ByteBuffer; - get(key: string, noAssert?: boolean): T; - set(key: string | {[key: string]: any}, value?: any | boolean, noAssert?: boolean): void; - toArrayBuffer(): ArrayBuffer; - toBase64(): string; - toBuffer(): Buffer; - toHex(): string; - toRaw(binaryAsBase64?: boolean, longsAsStrings?: boolean): {[key: string]: any}; - toString(): string; - [field: string]: any; - } - - /** - * Load a ProtoBuf.js object as a gRPC object. - * @param value The ProtoBuf.js reflection object to load - * @param options Options to apply to the loaded file - * @return The resulting gRPC object. - */ - export function loadObject(value: object, options?: LoadObjectOptions): T; - - /** - * Options for loading proto object as gRPC object - * @param {(number|string)=} [options.protobufjsVersion='detect'] 5 and 6 - * respectively indicate that an object from the corresponding version of - * Protobuf.js is provided in the value argument. If the option is 'detect', - * gRPC will guess what the version is based on the structure of the value. - */ - export interface LoadObjectOptions { - /** - * Deserialize bytes values as base64 strings instead of Buffers. - * Defaults to `false`. - */ - binaryAsBase64?: boolean; - - /** - * Deserialize long values as strings instead of objects. - * Defaults to `true`. - */ - longsAsStrings?: boolean; - - /** - * Deserialize enum values as strings instead of numbers. Only works with - * Protobuf.js 6 values. - * Defaults to `true`. - */ - enumsAsStrings?: boolean; - - /** - * use the beta method argument order for client methods, with optional - * arguments after the callback. This option is only a temporary stopgap - * measure to smooth an API breakage. It is deprecated, and new code - * should not use it. - * Defaults to `false` - */ - deprecatedArgumentOrder?: boolean; - - /** - * 5 and 6 respectively indicate that an object from the corresponding - * version of Protobuf.js is provided in the value argument. If the option - * is 'detect', gRPC wll guess what the version is based on the structure - * of the value. - */ - protobufjsVersion?: 5 | 6 | "detect"; - } - - /** - * Map from `.proto` file. - * - Namespaces become maps from the names of their direct members to those member objects - * - Service definitions become client constructors for clients for that service. They also - * have a service member that can be used for constructing servers. - * - Message definitions become Message constructors like those that ProtoBuf.js would create - * - Enum definitions become Enum objects like those that ProtoBuf.js would create - * - Anything else becomes the relevant reflection object that ProtoBuf.js would create - */ - export interface GrpcObject { - [name: string]: GrpcObject | typeof Client | ProtobufMessage; - } - - /** - * Load a gRPC object from a .proto file. - * @param filename The file to load - * @param format The file format to expect. Defaults to 'proto' - * @param options Options to apply to the loaded file - * @return The resulting gRPC object - */ - export function load(filename: Filename, format?: "proto" | "json", options?: LoadOptions): T; - - /** - * Load a gRPC package definition as a gRPC object hierarchy - * @param packageDef The package definition object - * @return The resulting gRPC object - */ - export function loadPackageDefinition(packageDefinition: PackageDefinition): GrpcObject; - - /** - * A filename - */ - export type Filename = string | { root: string, file: string }; - - /** - * Options for loading proto file as gRPC object - */ - export interface LoadOptions { - /** - * Load this file with field names in camel case instead of their original case. - * Defaults to `false`. - */ - convertFieldsToCamelCase?: boolean; - - /** - * Deserialize bytes values as base64 strings instead of Buffers. - * Defaults to `false`. - */ - binaryAsBase64?: boolean; - - /** - * Deserialize long values as strings instead of objects. - * Defaults to `true`. - */ - longsAsStrings?: boolean; - - /** - * Use the beta method argument order for client methods, with optional - * arguments after the callback. This option is only a temporary stopgap - * measure to smooth an API breakage. It is deprecated, and new code - * should not use it. - * Defaults to `false` - */ - deprecatedArgumentOrder?: boolean; - } - - /** - * Sets the logger function for the gRPC module. For debugging purposes, the C - * core will log synchronously directly to stdout unless this function is - * called. Note: the output format here is intended to be informational, and - * is not guaranteed to stay the same in the future. - * Logs will be directed to logger.error. - * @param logger A Console-like object. - */ - export function setLogger(logger: Console): void; - - /** - * Sets the logger verbosity for gRPC module logging. The options are members - * of the grpc.logVerbosity map. - * @param verbosity The minimum severity to log - */ - export function setLogVerbosity(verbosity: logVerbosity): void; - - /** - * Server object that stores request handlers and delegates incoming requests to those handlers - */ - export class Server { - /** - * Constructs a server object that stores request handlers and delegates - * incoming requests to those handlers - * @param options Options that should be passed to the internal server - * implementation - * ``` - * var server = new grpc.Server(); - * server.addProtoService(protobuf_service_descriptor, service_implementation); - * server.bind('address:port', server_credential); - * server.start(); - * ``` - */ - constructor(options?: object); - - /** - * Start the server and begin handling requests - */ - start(): void; - - /** - * Registers a handler to handle the named method. Fails if there already is - * a handler for the given method. Returns true on success - * @param name The name of the method that the provided function should - * handle/respond to. - * @param handler Function that takes a stream of - * request values and returns a stream of response values - * @param serialize Serialization function for responses - * @param deserialize Deserialization function for requests - * @param type The streaming type of method that this handles - * @return True if the handler was set. False if a handler was already - * set for that name. - */ - register( - name: string, - handler: handleCall, - serialize: serialize, - deserialize: deserialize, - type: string - ): boolean; - - /** - * Gracefully shuts down the server. The server will stop receiving new calls, - * and any pending calls will complete. The callback will be called when all - * pending calls have completed and the server is fully shut down. This method - * is idempotent with itself and forceShutdown. - * @param {function()} callback The shutdown complete callback - */ - tryShutdown(callback: () => void): void; - - /** - * Forcibly shuts down the server. The server will stop receiving new calls - * and cancel all pending calls. When it returns, the server has shut down. - * This method is idempotent with itself and tryShutdown, and it will trigger - * any outstanding tryShutdown callbacks. - */ - forceShutdown(): void; - - /** - * Add a service to the server, with a corresponding implementation. - * @param service The service descriptor - * @param implementation Map of method names to method implementation - * for the provided service. - */ - addService( - service: ServiceDefinition, - implementation: ImplementationType - ): void; - - /** - * Add a proto service to the server, with a corresponding implementation - * @deprecated Use `Server#addService` instead - * @param service The proto service descriptor - * @param implementation Map of method names to method implementation - * for the provided service. - */ - addProtoService( - service: ServiceDefinition, - implementation: ImplementationType - ): void; - - /** - * Binds the server to the given port, with SSL disabled if creds is an - * insecure credentials object - * @param port The port that the server should bind on, in the format - * "address:port" - * @param creds Server credential object to be used for SSL. Pass an - * insecure credentials object for an insecure port. - * @return The bound port number or 0 if the operation failed. - */ - bind(port: string, creds: ServerCredentials): number; - - /** - * Binds the server to the given port, with SSL disabled if creds is an - * insecure credentials object. Provides the result asynchronously. - * @param port The port that the server should bind on, in the format "address:port" - * @param creds Server credential object to be used for - * SSL. Pass an insecure credentials object for an insecure port. - * @param callback Called with the result of attempting to bind a port - * - error: If non-null, indicates that binding the port failed. - * - port: The bound port number. If binding the port fails, this will be negative to match the output of bind. - */ - bindAsync(port: string, creds: ServerCredentials, callback: (error: Error | null, port: number) => void): void; - } - - /** - * A type that servers as a default for an untyped service. - */ - export type UntypedServiceImplementation = { [name: string]: handleCall }; - - /** - * An object that completely defines a service. - */ - export type ServiceDefinition = { - readonly [I in keyof ImplementationType]: MethodDefinition; - } - - /** - * An object that defines a protobuf type - */ - export interface ProtobufTypeDefinition { - format: string; - type: object; - fileDescriptorProtos: Buffer[]; - } - - /** - * An object that defines a package containing multiple services - */ - export type PackageDefinition = { - readonly [fullyQualifiedName: string]: ServiceDefinition | ProtobufTypeDefinition; - } - - /** - * An object that completely defines a service method signature. - */ - export interface MethodDefinition { - /** - * The method's URL path - */ - path: string; - /** - * Indicates whether the method accepts a stream of requests - */ - requestStream: boolean; - /** - * Indicates whether the method returns a stream of responses - */ - responseStream: boolean; - /** - * Serialization function for request values - */ - requestSerialize: serialize; - /** - * Serialization function for response values - */ - responseSerialize: serialize; - /** - * Deserialization function for request data - */ - requestDeserialize: deserialize; - /** - * Deserialization function for repsonse data - */ - responseDeserialize: deserialize; - } - - type handleCall = - handleUnaryCall | - handleClientStreamingCall | - handleServerStreamingCall | - handleBidiStreamingCall; - - /** - * User-provided method to handle unary requests on a server - */ - type handleUnaryCall = - (call: ServerUnaryCall, callback: sendUnaryData) => void; - - /** - * An EventEmitter. Used for unary calls. - */ - export class ServerUnaryCall extends EventEmitter { - /** - * Indicates if the call has been cancelled - */ - cancelled: boolean; - - /** - * The request metadata from the client - */ - metadata: Metadata; - - /** - * The request message from the client - */ - request: RequestType; - - private constructor(); - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - - /** - * Send the initial metadata for a writable stream. - * @param responseMetadata Metadata to send - */ - sendMetadata(responseMetadata: Metadata): void; - } - - /** - * User provided method to handle client streaming methods on the server. - */ - type handleClientStreamingCall = - (call: ServerReadableStream, callback: sendUnaryData) => void; - - /** - * A stream that the server can read from. Used for calls that are streaming - * from the client side. - */ - export class ServerReadableStream extends Readable { - /** - * Indicates if the call has been cancelled - */ - cancelled: boolean; - - /** - * The request metadata from the client - */ - metadata: Metadata; - - private constructor(); - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - - /** - * Send the initial metadata for a writable stream. - * @param responseMetadata Metadata to send - */ - sendMetadata(responseMetadata: Metadata): void; - } - - /** - * User provided method to handle server streaming methods on the server. - */ - type handleServerStreamingCall = - (call: ServerWritableStream) => void; - - /** - * A stream that the server can write to. Used for calls that are streaming - * from the server side. - */ - export class ServerWritableStream extends Writable { - /** - * Indicates if the call has been cancelled - */ - cancelled: boolean; - - /** - * The request metadata from the client - */ - metadata: Metadata; - - /** - * The request message from the client - */ - request: RequestType; - - private constructor(); - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - - /** - * Send the initial metadata for a writable stream. - * @param responseMetadata Metadata to send - */ - sendMetadata(responseMetadata: Metadata): void; - } - - /* This typo existed in previous versions of this file, so we provide this - * type alias for backwards compatibility. */ - export type ServerWriteableStream = ServerWritableStream; - - /** - * User provided method to handle bidirectional streaming calls on the server. - */ - type handleBidiStreamingCall = - (call: ServerDuplexStream) => void; - - /** - * A stream that the server can read from or write to. Used for calls - * with duplex streaming. - */ - export class ServerDuplexStream extends Duplex { - /** - * Indicates if the call has been cancelled - */ - cancelled: boolean; - - /** - * The request metadata from the client - */ - metadata: Metadata; - - private constructor(); - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - - /** - * Send the initial metadata for a writable stream. - * @param responseMetadata Metadata to send - */ - sendMetadata(responseMetadata: Metadata): void; - } - - /** - * A deserialization function - * @param data The byte sequence to deserialize - * @return The data deserialized as a value - */ - type deserialize = (data: Buffer) => T; - - /** - * A serialization function - * @param value The value to serialize - * @return The value serialized as a byte sequence - */ - type serialize = (value: T) => Buffer; - - /** - * Callback function passed to server handlers that handle methods with - * unary responses. - */ - type sendUnaryData = - (error: ServiceError | null, value: ResponseType | null, trailer?: Metadata, flags?: number) => void; - - interface MetadataOptions { - /* Signal that the request is idempotent. Defaults to false */ - idempotentRequest?: boolean; - /* Signal that the call should not return UNAVAILABLE before it has - * started. Defaults to false. */ - waitForReady?: boolean; - /* Signal that the call is cacheable. GRPC is free to use GET verb. - * Defaults to false */ - cacheableRequest?: boolean; - /* Signal that the initial metadata should be corked. Defaults to false. */ - corked?: boolean; - } - - /** - * A class for storing metadata. Keys are normalized to lowercase ASCII. - */ - export class Metadata { - /** - * @param options Boolean options for the beginning of the call. - * These options only have any effect when passed at the beginning of - * a client request. - */ - constructor(options?: MetadataOptions); - /** - * Sets the given value for the given key by replacing any other values - * associated with that key. Normalizes the key. - * @param key The key to whose value should be set. - * @param value The value to set. Must be a buffer if and only - * if the normalized key ends with '-bin'. - */ - set(key: string, value: MetadataValue): void; - - /** - * Adds the given value for the given key by appending to a list of previous - * values associated with that key. Normalizes the key. - * @param key The key for which a new value should be appended. - * @param value The value to add. Must be a buffer if and only - * if the normalized key ends with '-bin'. - */ - add(key: string, value: MetadataValue): void; - - /** - * Removes the given key and any associated values. Normalizes the key. - * @param key The key whose values should be removed. - */ - remove(key: string): void; - - /** - * Gets a list of all values associated with the key. Normalizes the key. - * @param key The key whose value should be retrieved. - * @return A list of values associated with the given key. - */ - get(key: string): MetadataValue[]; - - /** - * Gets a plain object mapping each key to the first value associated with it. - * This reflects the most common way that people will want to see metadata. - * @return A key/value mapping of the metadata. - */ - getMap(): { [key: string]: MetadataValue }; - - /** - * Clones the metadata object. - * @return The newly cloned object. - */ - clone(): Metadata; - - /** - * Set options on the metadata object - * @param options Boolean options for the beginning of the call. - * These options only have any effect when passed at the beginning of - * a client request. - */ - setOptions(options: MetadataOptions): void; - } - - export type MetadataValue = string | Buffer; - - /** - * Represents the status of a completed request. If `code` is - * `grpc.status.OK`, then the request has completed successfully. - * Otherwise, the request has failed, `details` will contain a description of - * the error. Either way, `metadata` contains the trailing response metadata - * sent by the server when it finishes processing the call. - */ - export interface StatusObject { - /** - * The error code, a key of `grpc.status` - */ - code: status; - /** - * Human-readable description of the status - */ - details: string; - /** - * Trailing metadata sent with the status, if applicable - */ - metadata: Metadata; - } - - /** - * Describes how a request has failed. The member `message` will be the same as - * `details` in `StatusObject`, and `code` and `metadata` are the - * same as in that object. - */ - export interface ServiceError extends Error { - /** - * The error code, a key of {@link grpc.status} that is not `grpc.status.OK` - */ - code?: status; - /** - * Trailing metadata sent with the status, if applicable - */ - metadata?: Metadata; - /** - * Original status details string - */ - details?: string; - } - - /** - * ServerCredentials factories - */ - export class ServerCredentials { - /** - * Create insecure server credentials - * @return The ServerCredentials - */ - static createInsecure(): ServerCredentials; - /** - * Create SSL server credentials - * @param rootCerts Root CA certificates for validating client certificates - * @param keyCertPairs A list of private key and certificate chain pairs to - * be used for authenticating the server - * @param checkClientCertificate Indicates that the server should request - * and verify the client's certificates. - * Defaults to `false`. - * @return The ServerCredentials - */ - static createSsl(rootCerts: Buffer | null, keyCertPairs: KeyCertPair[], checkClientCertificate?: boolean): ServerCredentials; - } - - /** - * A private key and certificate pair - */ - export interface KeyCertPair { - /** - * The server's private key - */ - private_key: Buffer; - - /** - * The server's certificate chain - */ - cert_chain: Buffer; - } - - /** - * Enum of status codes that gRPC can return - */ - export enum status { - /** - * Not an error; returned on success - */ - OK = 0, - /** - * The operation was cancelled (typically by the caller). - */ - CANCELLED = 1, - /** - * Unknown error. An example of where this error may be returned is - * if a status value received from another address space belongs to - * an error-space that is not known in this address space. Also - * errors raised by APIs that do not return enough error information - * may be converted to this error. - */ - UNKNOWN = 2, - /** - * Client specified an invalid argument. Note that this differs - * from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments - * that are problematic regardless of the state of the system - * (e.g., a malformed file name). - */ - INVALID_ARGUMENT = 3, - /** - * Deadline expired before operation could complete. For operations - * that change the state of the system, this error may be returned - * even if the operation has completed successfully. For example, a - * successful response from a server could have been delayed long - * enough for the deadline to expire. - */ - DEADLINE_EXCEEDED = 4, - /** - * Some requested entity (e.g., file or directory) was not found. - */ - NOT_FOUND = 5, - /** - * Some entity that we attempted to create (e.g., file or directory) - * already exists. - */ - ALREADY_EXISTS = 6, - /** - * The caller does not have permission to execute the specified - * operation. PERMISSION_DENIED must not be used for rejections - * caused by exhausting some resource (use RESOURCE_EXHAUSTED - * instead for those errors). PERMISSION_DENIED must not be - * used if the caller can not be identified (use UNAUTHENTICATED - * instead for those errors). - */ - PERMISSION_DENIED = 7, - /** - * Some resource has been exhausted, perhaps a per-user quota, or - * perhaps the entire file system is out of space. - */ - RESOURCE_EXHAUSTED = 8, - /** - * Operation was rejected because the system is not in a state - * required for the operation's execution. For example, directory - * to be deleted may be non-empty, an rmdir operation is applied to - * a non-directory, etc. - * - * A litmus test that may help a service implementor in deciding - * between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: - * - * - Use UNAVAILABLE if the client can retry just the failing call. - * - Use ABORTED if the client should retry at a higher-level - * (e.g., restarting a read-modify-write sequence). - * - Use FAILED_PRECONDITION if the client should not retry until - * the system state has been explicitly fixed. E.g., if an "rmdir" - * fails because the directory is non-empty, FAILED_PRECONDITION - * should be returned since the client should not retry unless - * they have first fixed up the directory by deleting files from it. - * - Use FAILED_PRECONDITION if the client performs conditional - * REST Get/Update/Delete on a resource and the resource on the - * server does not match the condition. E.g., conflicting - * read-modify-write on the same resource. - */ - FAILED_PRECONDITION = 9, - /** - * The operation was aborted, typically due to a concurrency issue - * like sequencer check failures, transaction aborts, etc. - * - * See litmus test above for deciding between FAILED_PRECONDITION, - * ABORTED, and UNAVAILABLE. - */ - ABORTED = 10, - /** - * Operation was attempted past the valid range. E.g., seeking or - * reading past end of file. - * - * Unlike INVALID_ARGUMENT, this error indicates a problem that may - * be fixed if the system state changes. For example, a 32-bit file - * system will generate INVALID_ARGUMENT if asked to read at an - * offset that is not in the range [0,2^32-1], but it will generate - * OUT_OF_RANGE if asked to read from an offset past the current - * file size. - * - * There is a fair bit of overlap between FAILED_PRECONDITION and - * OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific - * error) when it applies so that callers who are iterating through - * a space can easily look for an OUT_OF_RANGE error to detect when - * they are done. - */ - OUT_OF_RANGE = 11, - /** - * Operation is not implemented or not supported/enabled in this service. - */ - UNIMPLEMENTED = 12, - /** - * Internal errors. Means some invariants expected by underlying - * system has been broken. If you see one of these errors, - * something is very broken. - */ - INTERNAL = 13, - /** - * The service is currently unavailable. This is a most likely a - * transient condition and may be corrected by retrying with - * a backoff. - * - * See litmus test above for deciding between FAILED_PRECONDITION, - * ABORTED, and UNAVAILABLE. - */ - UNAVAILABLE = 14, - /** - * Unrecoverable data loss or corruption. - */ - DATA_LOSS = 15, - /** - * The request does not have valid authentication credentials for the - * operation. - */ - UNAUTHENTICATED = 16, - } - - /** - * Propagation flags: these can be bitwise or-ed to form the propagation option - * for calls. - * - * Users are encouraged to write propagation masks as deltas from the default. - * i.e. write `grpc.propagate.DEFAULTS & ~grpc.propagate.DEADLINE` to disable - * deadline propagation. - */ - export enum propagate { - DEADLINE, - CENSUS_STATS_CONTEXT, - CENSUS_TRACING_CONTEXT, - CANCELLATION, - DEFAULTS, - } - - /** - * Call error constants. Call errors almost always indicate bugs in the gRPC - * library, and these error codes are mainly useful for finding those bugs. - */ - export enum callError { - OK, - ERROR, - NOT_ON_SERVER, - NOT_ON_CLIENT, - ALREADY_INVOKED, - NOT_INVOKED, - ALREADY_FINISHED, - TOO_MANY_OPERATIONS, - INVALID_FLAGS, - INVALID_METADATA, - INVALID_MESSAGE, - NOT_SERVER_COMPLETION_QUEUE, - BATCH_TOO_BIG, - PAYLOAD_TYPE_MISMATCH, - } - - /** - * Write flags: these can be bitwise or-ed to form write options that modify - * how data is written. - */ - export enum writeFlags { - /** - * Hint that the write may be buffered and need not go out on the wire - * immediately. GRPC is free to buffer the message until the next non-buffered - * write, or until writes_done, but it need not buffer completely or at all. - */ - BUFFER_HINT = 1, - /** - * Force compression to be disabled for a particular write - */ - NO_COMPRESS, - } - - /** - * Log verbosity constants. Maps setting names to code numbers. - */ - export enum logVerbosity { - DEBUG, - INFO, - ERROR, - } - - /** - * A certificate as received by the checkServerIdentity callback. - */ - export interface Certificate { - /** - * The raw certificate in DER form. - */ - raw: Buffer; - } - - /** - * A callback that will receive the expected hostname and presented peer - * certificate as parameters. The callback should return an error to - * indicate that the presented certificate is considered invalid and - * otherwise returned undefined. - */ - export type CheckServerIdentityCallback = (hostname: string, cert: Certificate) => Error | undefined; - - /** - * Additional peer verification options that can be set when creating - * SSL credentials. - */ - export interface VerifyOptions { - /** - * If set, this callback will be invoked after the usual hostname verification - * has been performed on the peer certificate. - */ - checkServerIdentity?: CheckServerIdentityCallback; - } - - /** - * Credentials module - * - * This module contains factory methods for two different credential types: - * CallCredentials and ChannelCredentials. ChannelCredentials are things like - * SSL credentials that can be used to secure a connection, and are used to - * construct a Client object. CallCredentials generally modify metadata, so they - * can be attached to an individual method call. - * - * CallCredentials can be composed with other CallCredentials to create - * CallCredentials. ChannelCredentials can be composed with CallCredentials - * to create ChannelCredentials. No combined credential can have more than - * one ChannelCredentials. - * - * For example, to create a client secured with SSL that uses Google - * default application credentials to authenticate: - * - * ``` - * var channel_creds = credentials.createSsl(root_certs); - * (new GoogleAuth()).getApplicationDefault(function(err, credential) { - * var call_creds = credentials.createFromGoogleCredential(credential); - * var combined_creds = credentials.combineChannelCredentials( - * channel_creds, call_creds); - * var client = new Client(address, combined_creds); - * }); - * ``` - */ - export const credentials: { - /** - * Create an SSL Credentials object. If using a client-side certificate, both - * the second and third arguments must be passed. - * @param rootCerts The root certificate data - * @param privateKey The client certificate private key, if applicable - * @param certChain The client certificate cert chain, if applicable - * @param verifyOptions Additional peer verification options, if desired - * @return The SSL Credentials object - */ - createSsl(rootCerts?: Buffer, privateKey?: Buffer, certChain?: Buffer, verifyOptions?: VerifyOptions): ChannelCredentials; - - /** - * Create a gRPC credentials object from a metadata generation function. This - * function gets the service URL and a callback as parameters. The error - * passed to the callback can optionally have a 'code' value attached to it, - * which corresponds to a status code that this library uses. - * @param metadataGenerator The function that generates metadata - * @return The credentials object - */ - createFromMetadataGenerator(metadataGenerator: metadataGenerator): CallCredentials; - - /** - * Create a gRPC credential from a Google credential object. - * @param googleCredential The Google credential object to use - * @return The resulting credentials object - */ - createFromGoogleCredential(googleCredential: GoogleOAuth2Client): CallCredentials; - - /** - * Combine a ChannelCredentials with any number of CallCredentials into a single - * ChannelCredentials object. - * @param channelCredential The ChannelCredentials to start with - * @param credentials The CallCredentials to compose - * @return A credentials object that combines all of the input credentials - */ - combineChannelCredentials(channelCredential: ChannelCredentials, ...credentials: CallCredentials[]): ChannelCredentials; - - /** - * Combine any number of CallCredentials into a single CallCredentials object - * @param credentials The CallCredentials to compose - * @return A credentials object that combines all of the input credentials - */ - combineCallCredentials(...credentials: CallCredentials[]): CallCredentials; - - /** - * Create an insecure credentials object. This is used to create a channel that - * does not use SSL. This cannot be composed with anything. - * @return The insecure credentials object - */ - createInsecure(): ChannelCredentials; - }; - - /** - * Metadata generator function. - */ - export type metadataGenerator = (params: { service_url: string }, callback: (error: Error | null, metadata?: Metadata) => void) => void; - - /** - * This cannot be constructed directly. Instead, instances of this class should - * be created using the factory functions in `grpc.credentials` - */ - export interface ChannelCredentials { - /** - * Returns a copy of this object with the included set of per-call credentials - * expanded to include callCredentials. - * @param callCredentials A CallCredentials object to associate with this - * instance. - */ - compose(callCredentials: CallCredentials): ChannelCredentials; - } - - /** - * This cannot be constructed directly. Instead, instances of this class should - * be created using the factory functions in `grpc.credentials` - */ - export interface CallCredentials { - /** - * Asynchronously generates a new Metadata object. - * @param options Options used in generating the Metadata object. - */ - generateMetadata(options: object): Promise; - - /** - * Creates a new CallCredentials object from properties of both this and - * another CallCredentials object. This object's metadata generator will be - * called first. - * @param callCredentials The other CallCredentials object. - */ - compose(callCredentials: CallCredentials): CallCredentials; - } - - /** - * This is the required interface from the OAuth2Client object - * from https://github.com/google/google-auth-library-nodejs lib. - * The definition is copied from `ts/lib/auth/oauth2client.ts` - */ - export interface GoogleOAuth2Client { - getRequestMetadata(optUri: string, metadataCallback: (err: Error, headers: any) => void): void; - } - - /** - * Creates a constructor for a client with the given methods, as specified in - * the methods argument. The resulting class will have an instance method for - * each method in the service, which is a partial application of one of the - * `grpc.Client` request methods, depending on `requestSerialize` - * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` - * arguments predefined. - * @param methods An object mapping method names to method attributes - * @param serviceName The fully qualified name of the service - * @param classOptions An options object. - * @return New client constructor, which is a subclass of `grpc.Client`, and - * has the same arguments as that constructor. - */ - export function makeGenericClientConstructor( - methods: ServiceDefinition, - serviceName: string, - classOptions: GenericClientOptions, - ): typeof Client; - - /** - * Options for generic client constructor. - */ - export interface GenericClientOptions { - /** - * Indicates that the old argument order should be used for methods, with - * optional arguments at the end instead of the callback at the end. This - * option is only a temporary stopgap measure to smooth an API breakage. - * It is deprecated, and new code should not use it. - */ - deprecatedArgumentOrder?: boolean; - } - - /** - * Create a client with the given methods - */ - export class Client { - /** - * A generic gRPC client. Primarily useful as a base class for generated clients - * @param address Server address to connect to - * @param credentials Credentials to use to connect to the server - * @param options Options to apply to channel creation - */ - constructor(address: string, credentials: ChannelCredentials, options?: object) - - /** - * Make a unary request to the given method, using the given serialize - * and deserialize functions, with the given argument. - * @param method The name of the method to request - * @param serialize The serialization function for inputs - * @param deserialize The deserialization function for outputs - * @param argument The argument to the call. Should be serializable with - * serialize - * @param metadata Metadata to add to the call - * @param options Options map - * @param callback The callback to for when the response is received - * @return An event emitter for stream related events - */ - makeUnaryRequest( - method: string, - serialize: serialize, - deserialize: deserialize, - argument: RequestType | null, - metadata: Metadata | null, - options: CallOptions | null, - callback: requestCallback, - ): ClientUnaryCall; - - /** - * Make a client stream request to the given method, using the given serialize - * and deserialize functions, with the given argument. - * @param method The name of the method to request - * @param serialize The serialization function for inputs - * @param deserialize The deserialization function for outputs - * @param metadata Array of metadata key/value pairs to add to the call - * @param options Options map - * @param callback The callback to for when the response is received - * @return An event emitter for stream related events - */ - makeClientStreamRequest( - method: string, - serialize: serialize, - deserialize: deserialize, - metadata: Metadata | null, - options: CallOptions | null, - callback: requestCallback, - ): ClientWritableStream; - - /** - * Make a server stream request to the given method, with the given serialize - * and deserialize function, using the given argument - * @param method The name of the method to request - * @param serialize The serialization function for inputs - * @param deserialize The deserialization function for outputs - * @param argument The argument to the call. Should be serializable with - * serialize - * @param metadata Array of metadata key/value pairs to add to the call - * @param options Options map - * @return An event emitter for stream related events - */ - makeServerStreamRequest( - method: string, - serialize: serialize, - deserialize: deserialize, - argument: RequestType, - metadata?: Metadata | null, - options?: CallOptions | null, - ): ClientReadableStream; - - /** - * Make a bidirectional stream request with this method on the given channel. - * @param method The name of the method to request - * @param serialize The serialization function for inputs - * @param deserialize The deserialization - * function for outputs - * @param metadata Array of metadata key/value - * pairs to add to the call - * @param options Options map - * @return An event emitter for stream related events - */ - makeBidiStreamRequest( - method: string, - serialize: serialize, - deserialize: deserialize, - metadata?: Metadata | null, - options?: CallOptions | null, - ): ClientDuplexStream; - - /** - * Close this client. - */ - close(): void; - - /** - * Return the underlying channel object for the specified client - * @return The channel - */ - getChannel(): Channel; - - /** - * Wait for the client to be ready. The callback will be called when the - * client has successfully connected to the server, and it will be called - * with an error if the attempt to connect to the server has unrecoverablly - * failed or if the deadline expires. This function will make the channel - * start connecting if it has not already done so. - * @param deadline When to stop waiting for a connection. - * @param callback The callback to call when done attempting to connect. - */ - waitForReady(deadline: Deadline, callback: (error: Error | null) => void): void; - } - - /** - * Options that can be set on a call. - */ - export interface CallOptions { - /** - * The deadline for the entire call to complete. - */ - deadline?: Deadline; - /** - * Server hostname to set on the call. Only meaningful if different from - * the server address used to construct the client. - */ - host?: string; - /** - * Parent call. Used in servers when making a call as part of the process - * of handling a call. Used to propagate some information automatically, - * as specified by propagate_flags. - */ - parent?: Call; - /** - * Indicates which properties of a parent call should propagate to this - * call. Bitwise combination of flags in `grpc.propagate`. - */ - propagate_flags?: number; - /** - * The credentials that should be used to make this particular call. - */ - credentials?: CallCredentials; - /** - * Additional custom call options. These can be used to pass additional - * data per-call to client interceptors - */ - [key: string]: any; - } - - /** - * The deadline of an operation. If it is a date, the deadline is reached at - * the date and time specified. If it is a finite number, it is treated as - * a number of milliseconds since the Unix Epoch. If it is Infinity, the - * deadline will never be reached. If it is -Infinity, the deadline has already - * passed. - */ - export type Deadline = number | Date; - - /** - * Any client call type - */ - type Call = - ClientUnaryCall | - ClientReadableStream | - ClientWritableStream | - ClientDuplexStream; - - /** - * An EventEmitter. Used for unary calls. - */ - export class ClientUnaryCall extends EventEmitter { - private constructor(); - - /** - * Cancel the ongoing call. Results in the call ending with a CANCELLED status, - * unless it has already ended with some other status. - */ - cancel(): void; - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - } - - /** - * A stream that the client can read from. Used for calls that are streaming - * from the server side. - */ - export class ClientReadableStream extends Readable { - private constructor(); - - /** - * Cancel the ongoing call. Results in the call ending with a CANCELLED status, - * unless it has already ended with some other status. - */ - cancel(): void; - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - } - - /** - * A stream that the client can write to. Used for calls that are streaming from - * the client side. - */ - export class ClientWritableStream extends Writable { - private constructor(); - - /** - * Write a message to the request stream. If serializing the argument fails, - * the call will be cancelled and the stream will end with an error. - * @param message The message to write. Must be a valid argument to the - * serialize function of the corresponding method - * @param flags Flags to modify how the message is written - * @param callback Callback for when this chunk of data is flushed - * @return As defined for [Writable]{@link external:Writable} - */ - write(message: RequestType, flags?: any&writeFlags, callback?: Function): boolean; - - /** - * Cancel the ongoing call. Results in the call ending with a CANCELLED status, - * unless it has already ended with some other status. - */ - cancel(): void; - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - } - - /** - * A stream that the client can read from or write to. Used for calls with - * duplex streaming. - */ - export class ClientDuplexStream extends Duplex { - private constructor(); - - /** - * Write a message to the request stream. If serializing the argument fails, - * the call will be cancelled and the stream will end with an error. - * @param message The message to write. Must be a valid argument to the - * serialize function of the corresponding method - * @param flags Flags to modify how the message is written - * @param callback Callback for when this chunk of data is flushed - * @return As defined for [Writable]{@link external:Writable} - */ - write(message: RequestType, flags?: any&writeFlags, callback?: Function): boolean; - - /** - * Cancel the ongoing call. Results in the call ending with a CANCELLED status, - * unless it has already ended with some other status. - */ - cancel(): void; - - /** - * Get the endpoint this call/stream is connected to. - * @return The URI of the endpoint - */ - getPeer(): string; - } - - /** - * Client request callback - * @param error The error, if the call failed - * @param value The response value, if the call succeeded - */ - export type requestCallback = - (error: ServiceError | null, value?: ResponseType) => void; - - /** - * Return the underlying channel object for the specified client - * @see grpc.Client#getChannel - * @param client The client - * @return The channel - */ - export function getClientChannel(client: Client): Channel; - - /** - * Wait for the client to be ready. The callback will be called when the - * client has successfully connected to the server, and it will be called - * with an error if the attempt to connect to the server has unrecoverably - * failed or if the deadline expires. This function will make the channel - * start connecting if it has not already done so. - * @see grpc.Client#waitForReady - * @param client The client to wait on - * @param deadline When to stop waiting for a connection. Pass Infinity to - * wait forever. - * @param callback The callback to call when done attempting to connect. - */ - export function waitForClientReady(client: Client, deadline: Deadline, callback: (error: Error | null) => void): void; - - /** - * Close client. - * @param clientObj The client to close - */ - export function closeClient(clientObj: Client): void; - - /** - * A builder for gRPC status objects - */ - export class StatusBuilder { - constructor() - - /** - * Adds a status code to the builder - * @param code The status code - */ - withCode(code: number): this; - - /** - * Adds details to the builder - * @param details A status message - */ - withDetails(details: string): this; - - /** - * Adds metadata to the builder - * @param metadata The gRPC status metadata - */ - withMetadata(metadata: Metadata): this; - - /** - * Builds the status object - * @return A gRPC status - */ - build(): StatusObject; - } - - export type MetadataListener = (metadata: Metadata, next: Function) => void; - - export type MessageListener = (message: any, next: Function) => void; - - export type StatusListener = (status: StatusObject, next: Function) => void; - - export interface Listener { - onReceiveMetadata?: MetadataListener; - onReceiveMessage?: MessageListener; - onReceiveStatus?: StatusListener; - } - - /** - * A builder for listener interceptors - */ - export class ListenerBuilder { - constructor(); - - /** - * Adds onReceiveMetadata method to the builder - * @param onReceiveMetadata A listener method for receiving metadata - */ - withOnReceiveMetadata(onReceiveMetadata: MetadataListener): this; - - /** - * Adds onReceiveMessage method to the builder - * @param onReceiveMessage A listener method for receiving message - */ - withOnReceiveMessage(onReceiveMessage: MessageListener): this; - - /** - * Adds onReceiveStatus method to the builder - * @param onReceiveStatus A listener method for receiving status - */ - withOnReceiveStatus(onReceiveStatus: StatusListener): this; - - /** - * Builds the call listener - */ - build(): Listener; - } - - export type MetadataRequester = (metadata: Metadata, listener: Listener, next: Function) => void; - - export type MessageRequester = (message: any, next: Function) => void; - - export type CloseRequester = (next: Function) => void; - - export type CancelRequester = (next: Function) => void; - - export type GetPeerRequester = (next: Function) => string; - - export interface Requester { - start?: MetadataRequester; - sendMessage?: MessageRequester; - halfClose?: CloseRequester; - cancel?: CancelRequester; - getPeer?: GetPeerRequester; - } - - /** - * A builder for the outbound methods of an interceptor - */ - export class RequesterBuilder { - constructor(); - - /** - * Add a metadata requester to the builder - * @param start A requester method for handling metadata - */ - withStart(start: MetadataRequester): this; - - /** - * Add a message requester to the builder. - * @param sendMessage A requester method for handling - * messages. - */ - withSendMessage(sendMessage: MessageRequester): this; - - /** - * Add a close requester to the builder. - * @param halfClose A requester method for handling client - * close. - */ - withHalfClose(halfClose: CloseRequester): this; - - /** - * Add a cancel requester to the builder. - * @param cancel A requester method for handling `cancel` - */ - withCancel(cancel: CancelRequester): this; - - /** - * Builds the requester's interceptor methods. - */ - build(): Requester; - } - - /** - * A chainable gRPC call proxy which will delegate to an optional requester - * object. By default, interceptor methods will chain to nextCall. If a - * requester is provided which implements an interceptor method, that - * requester method will be executed as part of the chain. - * operations. - */ - export class InterceptingCall { - /** - * @param next_Call The next call in the chain - * @param requester Interceptor methods to handle request - */ - constructor(nextCall: InterceptingCall|null, requester?: Requester); - - /** - * Starts a call through the outbound interceptor chain and adds an element to - * the reciprocal inbound listener chain. - */ - start(metadata: Metadata, listener: Listener): void; - - /** - * Pass a message through the interceptor chain. - */ - sendMessage(message: any): void; - - /** - * Run a close operation through the interceptor chain - */ - halfClose(): void; - - /** - * Run a cancel operation through the interceptor chain - */ - cancel(): void; - - /** - * Run a cancelWithStatus operation through the interceptor chain. - * @param status - * @param message - */ - cancelWithStatus(status: StatusObject, message: string): void; - - /** - * Pass a getPeer call down to the base gRPC call (should not be intercepted) - */ - getPeer(): object; - - /** - * For streaming calls, we need to transparently pass the stream's context - * through the interceptor chain. Passes the context between InterceptingCalls - * but hides it from any requester implementations. - * @param context Carries objects needed for streaming operations. - * @param message The message to send. - */ - sendMessageWithContext(context: object, message: any): void; - - /** - * For receiving streaming messages, we need to seed the base interceptor with - * the streaming context to create a RECV_MESSAGE batch. - * @param context Carries objects needed for streaming operations - */ - recvMessageWithContext(context: object): void; - } - export enum connectivityState { - IDLE = 0, - CONNECTING = 1, - READY = 2, - TRANSIENT_FAILURE = 3, - SHUTDOWN = 4 - } - - export class Channel { - /** - * This constructor API is almost identical to the Client constructor, - * except that some of the options for the Client constructor are not valid - * here. - * @param target The address of the server to connect to - * @param credentials Channel credentials to use when connecting - * @param options A map of channel options that will be passed to the core - */ - constructor(target: string, credentials: ChannelCredentials, options: {[key:string]: string|number}); - /** - * Close the channel. This has the same functionality as the existing grpc.Client.prototype.close - */ - close(): void; - /** - * Return the target that this channel connects to - */ - getTarget(): string; - /** - * Get the channel's current connectivity state. - * @param tryToConnect If true, the channel will start connecting if it is - * idle. Otherwise, idle channels will only start connecting when a - * call starts. - */ - getConnectivityState(tryToConnect: boolean): connectivityState; - /** - * Watch for connectivity state changes. - * @param currentState The state to watch for transitions from. This should - * always be populated by calling getConnectivityState immediately - * before. - * @param deadline A deadline for waiting for a state change - * @param callback Called with no error when a state change, or with an - * error if the deadline passes without a state change. - */ - watchConnectivityState(currentState: connectivityState, deadline: Date|number, callback: (error?: Error) => void): void; - /** - * Create a call object. Call is an opaque type that is used by the Client - * and Server classes. This function is called by the gRPC library when - * starting a request. Implementers should return an instance of Call that - * is returned from calling createCall on an instance of the provided - * Channel class. - * @param method The full method string to request. - * @param deadline The call deadline - * @param host A host string override for making the request - * @param parentCall A server call to propagate some information from - * @param propagateFlags A bitwise combination of elements of grpc.propagate - * that indicates what information to propagate from parentCall. - */ - createCall(method: string, deadline: Date|number, host: string|null, parentCall: Call|null, propagateFlags: number|null): Call; - } -} diff --git a/packages/grpc-native-core/index.js b/packages/grpc-native-core/index.js deleted file mode 100644 index 9534c7d4f..000000000 --- a/packages/grpc-native-core/index.js +++ /dev/null @@ -1,384 +0,0 @@ -/** - * @license - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var path = require('path'); -var fs = require('fs'); -var util = require('util'); - -var SSL_ROOTS_PATH = path.resolve(__dirname, 'deps', 'grpc', 'etc', 'roots.pem'); - -var client = require('./src/client.js'); - -var server = require('./src/server.js'); - -var common = require('./src/common.js'); - -var Metadata = require('./src/metadata.js'); - -var grpc = require('./src/grpc_extension'); - -var protobuf_js_5_common = require('./src/protobuf_js_5_common'); -var protobuf_js_6_common = require('./src/protobuf_js_6_common'); - -var constants = require('./src/constants.js'); - -grpc.setDefaultRootsPem(fs.readFileSync(SSL_ROOTS_PATH, 'ascii')); - -/** - * @namespace grpc - */ - -/** - * Load a ProtoBuf.js object as a gRPC object. - * @memberof grpc - * @alias grpc.loadObject - * @param {Object} value The ProtoBuf.js reflection object to load - * @param {Object=} options Options to apply to the loaded file - * @param {bool=} [options.binaryAsBase64=false] deserialize bytes values as - * base64 strings instead of Buffers - * @param {bool=} [options.longsAsStrings=true] deserialize long values as - * strings instead of objects - * @param {bool=} [options.enumsAsStrings=true] deserialize enum values as - * strings instead of numbers. Only works with Protobuf.js 6 values. - * @param {bool=} [options.deprecatedArgumentOrder=false] use the beta method - * argument order for client methods, with optional arguments after the - * callback. This option is only a temporary stopgap measure to smooth an - * API breakage. It is deprecated, and new code should not use it. - * @param {(number|string)=} [options.protobufjsVersion='detect'] 5 and 6 - * respectively indicate that an object from the corresponding version of - * Protobuf.js is provided in the value argument. If the option is 'detect', - * gRPC will guess what the version is based on the structure of the value. - * @return {Object} The resulting gRPC object. - */ -exports.loadObject = function loadObject(value, options) { - options = Object.assign({}, common.defaultGrpcOptions, options); - options = Object.assign({}, {'protobufjsVersion': 'detect'}, options); - var protobufjsVersion; - if (options.protobufjsVersion === 'detect') { - if (protobuf_js_6_common.isProbablyProtobufJs6(value)) { - protobufjsVersion = 6; - } else if (protobuf_js_5_common.isProbablyProtobufJs5(value)) { - protobufjsVersion = 5; - } else { - var error_message = 'Could not detect ProtoBuf.js version. Please ' + - 'specify the version number with the "protobufjsVersion" option'; - throw new Error(error_message); - } - } else { - protobufjsVersion = options.protobufjsVersion; - } - switch (protobufjsVersion) { - case 6: return protobuf_js_6_common.loadObject(value, options); - case 5: - return protobuf_js_5_common.loadObject(value, options); - default: - throw new Error('Unrecognized protobufjsVersion', protobufjsVersion); - } -}; - -var loadObject = exports.loadObject; - -/** - * Load a gRPC object from a .proto file. - * @deprecated Use the {@link https://www.npmjs.com/package/@grpc/proto-loader|proto-loader module} - with grpc.loadPackageDefinition instead. - * @memberof grpc - * @alias grpc.load - * @param {string|{root: string, file: string}} filename The file to load - * @param {string=} format The file format to expect. Must be either 'proto' or - * 'json'. Defaults to 'proto' - * @param {Object=} options Options to apply to the loaded file - * @param {bool=} [options.convertFieldsToCamelCase=false] Load this file with - * field names in camel case instead of their original case - * @param {bool=} [options.binaryAsBase64=false] deserialize bytes values as - * base64 strings instead of Buffers - * @param {bool=} [options.longsAsStrings=true] deserialize long values as - * strings instead of objects - * @param {bool=} [options.deprecatedArgumentOrder=false] use the beta method - * argument order for client methods, with optional arguments after the - * callback. This option is only a temporary stopgap measure to smooth an - * API breakage. It is deprecated, and new code should not use it. - * @return {Object} The resulting gRPC object - */ -exports.load = util.deprecate(function load(filename, format, options) { - const ProtoBuf = require('protobufjs'); - options = Object.assign({}, common.defaultGrpcOptions, options); - options.protobufjsVersion = 5; - if (!format) { - format = 'proto'; - } - var convertFieldsToCamelCaseOriginal = ProtoBuf.convertFieldsToCamelCase; - if(options && options.hasOwnProperty('convertFieldsToCamelCase')) { - ProtoBuf.convertFieldsToCamelCase = options.convertFieldsToCamelCase; - } - var builder; - try { - switch(format) { - case 'proto': - builder = ProtoBuf.loadProtoFile(filename); - break; - case 'json': - builder = ProtoBuf.loadJsonFile(filename); - break; - default: - throw new Error('Unrecognized format "' + format + '"'); - } - } finally { - ProtoBuf.convertFieldsToCamelCase = convertFieldsToCamelCaseOriginal; - } - - if (!builder) { - throw new Error('Could not load file "' + filename + '"'); - } - - return loadObject(builder.ns, options); -}, 'grpc.load: Use the @grpc/proto-loader module with grpc.loadPackageDefinition instead'); - -/** - * Load a gRPC package definition as a gRPC object hierarchy - * @param packageDef grpc~PackageDefinition The package definition object - * @return {Object} The resulting gRPC object - */ -exports.loadPackageDefinition = function loadPackageDefintion(packageDef) { - const result = {}; - for (const serviceFqn in packageDef) { - const service = packageDef[serviceFqn]; - const nameComponents = serviceFqn.split('.'); - const serviceName = nameComponents[nameComponents.length-1]; - let current = result; - for (const packageName of nameComponents.slice(0, -1)) { - if (!current[packageName]) { - current[packageName] = {}; - } - current = current[packageName]; - } - if (service.hasOwnProperty('format')) { - current[serviceName] = service; - } else { - current[serviceName] = client.makeClientConstructor(service, serviceName, {}); - } - } - return result; -}; - -var log_template = function(args) { - var file = args.file; - var line = args.line; - var severity = args.severity; - var message = args.message; - var timestamp = args.timestamp; - return `${severity} ${timestamp}\t${file}:${line}]\t${message}`; -}; - -/** - * Sets the logger function for the gRPC module. For debugging purposes, the C - * core will log synchronously directly to stdout unless this function is - * called. Note: the output format here is intended to be informational, and - * is not guaranteed to stay the same in the future. - * Logs will be directed to logger.error. - * @memberof grpc - * @alias grpc.setLogger - * @param {Console} logger A Console-like object. - */ -exports.setLogger = function setLogger(logger) { - common.logger = logger; - grpc.setDefaultLoggerCallback(function(file, line, severity, - message, timestamp) { - logger.error(log_template({ - file: path.basename(file), - line: line, - severity: severity, - message: message, - timestamp: timestamp.toISOString() - })); - }); -}; - -/** - * Sets the logger verbosity for gRPC module logging. The options are members - * of the grpc.logVerbosity map. - * @memberof grpc - * @alias grpc.setLogVerbosity - * @param {Number} verbosity The minimum severity to log - */ -exports.setLogVerbosity = function setLogVerbosity(verbosity) { - common.logVerbosity = verbosity; - grpc.setLogVerbosity(verbosity); -}; - -exports.Server = server.Server; - -exports.Metadata = Metadata; - -exports.status = constants.status; - -exports.propagate = constants.propagate; - -exports.callError = constants.callError; - -exports.writeFlags = constants.writeFlags; - -exports.logVerbosity = constants.logVerbosity; - -exports.methodTypes = constants.methodTypes; - -exports.connectivityState = constants.connectivityState; - -exports.credentials = require('./src/credentials.js'); - -/** - * ServerCredentials factories - * @constructor ServerCredentials - * @memberof grpc - */ -exports.ServerCredentials = grpc.ServerCredentials; - -/** - * Create insecure server credentials - * @name grpc.ServerCredentials.createInsecure - * @kind function - * @return {grpc.ServerCredentials} - */ - -/** - * A private key and certificate pair - * @typedef {Object} grpc.ServerCredentials~keyCertPair - * @property {Buffer} private_key The server's private key - * @property {Buffer} cert_chain The server's certificate chain - */ - -/** - * Create SSL server credentials - * @name grpc.ServerCredentials.createSsl - * @kind function - * @param {?Buffer} rootCerts Root CA certificates for validating client - * certificates - * @param {Array} keyCertPairs A list of - * private key and certificate chain pairs to be used for authenticating - * the server - * @param {boolean} [checkClientCertificate=false] Indicates that the server - * should request and verify the client's certificates - * @return {grpc.ServerCredentials} - */ - -exports.makeGenericClientConstructor = client.makeClientConstructor; - -exports.getClientChannel = client.getClientChannel; - -exports.waitForClientReady = client.waitForClientReady; - -exports.StatusBuilder = client.StatusBuilder; -exports.ListenerBuilder = client.ListenerBuilder; -exports.RequesterBuilder = client.RequesterBuilder; -exports.InterceptingCall = client.InterceptingCall; - -/** - * @memberof grpc - * @alias grpc.closeClient - * @param {grpc.Client} client_obj The client to close - */ -exports.closeClient = function closeClient(client_obj) { - client.Client.prototype.close.apply(client_obj); -}; - -exports.Client = client.Client; - -/** - * @typedef {Object.} grpc~ChannelOptions - */ - -/** - * This constructor API is almost identical to the Client constructor, - * except that some of the options for the Client constructor are not valid - * here. - * @constructor Channel - * @memberof grpc - * @param {string} target The address of the server to connect to - * @param {grpc.ChannelCredentials} credentials Channel credentials to use when connecting - * @param {grpc~ChannelOptions} options A map of channel options that will be passed to the core. - * The available options are listed in - * [this document]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}. - */ -exports.Channel = grpc.Channel; - -/** - * Close the channel. This has the same functionality as the existing grpc.Client#close - * @name grpc.Channel#close - * @kind function - */ - -/** - * Return the target that this channel connects to - * @name grpc.Channel#getTarget - * @kind function - * @return {string} The target - */ - -/** - * Get the channel's current connectivity state. - * @name grpc.Channel#getConnectivityState - * @kind function - * @param {boolean} tryToConnect If true, the channel will start connecting if it is - * idle. Otherwise, idle channels will only start connecting when a - * call starts. - * @return {grpc.connectivityState} The current connectivity state - */ - -/** - * @callback grpc.Channel~watchConnectivityStateCallback - * @param {Error?} error - */ - -/** - * Watch for connectivity state changes. - * @name grpc.Channel#watchConnectivityState - * @kind function - * @param {grpc.ConnectivityState} currentState The state to watch for - * transitions from. This should always be populated by calling - * getConnectivityState immediately before. - * @param {grpc~Deadline} deadline A deadline for waiting for a state change - * @param {grpc.Channel~watchConnectivityStateCallback} callback Called with no - * error when the state changes, or with an error if the deadline passes - * without a state change - */ - -/** - * @name grpc~Call - * @kind class - */ - -/** - * Create a call object. Call is an opaque type used by the {@link grpc.Client} - * and {@link grpc.Server} classes. This function is called by the gRPC library - * when starting a request. Implementers should return an instance of Call that - * is returned from calling createCall on an instance of the provided Channel - * class. - * @name grpc.Channel#createCall - * @kind function - * @param {string} method The full method string to request - * @param {grpc~Deadline} deadline The call deadline - * @param {string|null} host A host string override for making the request - * @param {grpc~Call|null} parentCall A server call to propagate some - * information from - * @param {number|null} propagateFlags A bitwise combination of elements of - * {@link grpc.propagate} that indicates what information to propagate - * from parentCall - * @return {grpc~Call} - */ diff --git a/packages/grpc-native-core/jsdoc_conf.json b/packages/grpc-native-core/jsdoc_conf.json deleted file mode 100644 index 92de29900..000000000 --- a/packages/grpc-native-core/jsdoc_conf.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "tags": { - "allowUnknownTags": true - }, - "opts": { - "destination": "docs/gen/native/core" - }, - "plugins": ["plugins/markdown"], - "templates": { - "cleverLinks": false, - "monospaceLinks": false, - "default": { - "outputSourceFiles": true - } - } -} diff --git a/packages/grpc-native-core/package.json b/packages/grpc-native-core/package.json deleted file mode 100644 index 83e911d12..000000000 --- a/packages/grpc-native-core/package.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "name": "grpc", - "version": "1.24.0-pre1", - "author": "Google Inc.", - "description": "gRPC Library for Node", - "homepage": "https://grpc.io/", - "repository": { - "type": "git", - "url": "https://github.com/grpc/grpc-node.git" - }, - "bugs": "https://github.com/grpc/grpc-node/issues", - "contributors": [ - { - "name": "Michael Lumish", - "email": "mlumish@google.com" - } - ], - "directories": { - "lib": "src" - }, - "scripts": { - "build": "node-pre-gyp build", - "electron-build": "node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", - "coverage": "istanbul cover ./node_modules/.bin/_mocha test", - "install": "node-pre-gyp install --fallback-to-build --library=static_library", - "prepack": "git submodule update --init --recursive && npm install" - }, - "dependencies": { - "@types/bytebuffer": "^5.0.40", - "lodash.camelcase": "^4.3.0", - "lodash.clone": "^4.5.0", - "nan": "^2.13.2", - "node-pre-gyp": "^0.14.0", - "protobufjs": "^5.0.3" - }, - "devDependencies": { - "body-parser": "^1.15.2", - "electron-mocha": "^3.1.1", - "express": "^4.14.0", - "google-protobuf": "^3.0.0", - "istanbul": "^0.4.4", - "lodash": "^4.17.4", - "minimist": "^1.1.0", - "node-forge": "^0.7.5", - "poisson-process": "^0.2.1" - }, - "engines": { - "node": ">=4" - }, - "binary": { - "module_name": "grpc_node", - "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", - "host": "https://node-precompiled-binaries.grpc.io/", - "remote_path": "{name}/v{version}", - "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" - }, - "files": [ - "LICENSE", - "README.md", - "deps/grpc/etc/", - "index.js", - "index.d.ts", - "src/*.js", - "ext/*.{cc,h}", - "deps/grpc/include/grpc/**/*.h", - "deps/grpc/src/core/**/*.{c,cc,h}", - "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{cc,h,inc}", - "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", - "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", - "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", - "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", - "deps/grpc/third_party/upb/**/*.{c,h,inc}", - "deps/grpc/third_party/zlib/**/*.{c,cc,h}", - "deps/grpc/third_party/address_sorting/**/*.{c,h}", - "deps/grpc/third_party/cares/**/*.{c,h}", - "binding.gyp" - ], - "main": "index.js", - "typings": "index.d.ts", - "license": "Apache-2.0", - "jshintConfig": { - "bitwise": true, - "curly": true, - "eqeqeq": true, - "esnext": true, - "freeze": true, - "immed": true, - "indent": 2, - "latedef": "nofunc", - "maxlen": 80, - "mocha": true, - "newcap": true, - "node": true, - "noarg": true, - "quotmark": "single", - "strict": true, - "trailing": true, - "undef": true, - "unused": "vars" - } -} diff --git a/packages/grpc-native-core/src/client.js b/packages/grpc-native-core/src/client.js deleted file mode 100644 index faba6decb..000000000 --- a/packages/grpc-native-core/src/client.js +++ /dev/null @@ -1,1074 +0,0 @@ -/** - * @license - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * Client module - * - * This module contains the factory method for creating Client classes, and the - * method calling code for all types of methods. - * - * @example Create a client and call a method on it - * - * var proto_obj = grpc.load(proto_file_path); - * var Client = proto_obj.package.subpackage.ServiceName; - * var client = new Client(server_address, client_credentials); - * var call = client.unaryMethod(arguments, callback); - */ - -'use strict'; - -var client_interceptors = require('./client_interceptors'); -var grpc = require('./grpc_extension'); - -var common = require('./common'); - -var Metadata = require('./metadata'); - -var constants = require('./constants'); - -var EventEmitter = require('events').EventEmitter; - -var stream = require('stream'); - -var Readable = stream.Readable; -var Writable = stream.Writable; -var Duplex = stream.Duplex; -var methodTypes = constants.methodTypes; -var util = require('util'); -var version = require('../package.json').version; - -/** - * Initial response metadata sent by the server when it starts processing the - * call - * @event grpc~ClientUnaryCall#metadata - * @type {grpc.Metadata} - */ - -/** - * Status of the call when it has completed. - * @event grpc~ClientUnaryCall#status - * @type grpc~StatusObject - */ - -util.inherits(ClientUnaryCall, EventEmitter); - -/** - * An EventEmitter. Used for unary calls. - * @constructor grpc~ClientUnaryCall - * @extends external:EventEmitter - * @param {grpc.internal~Call} call The call object associated with the request - */ -function ClientUnaryCall(call) { - EventEmitter.call(this); - this.call = call; -} - -util.inherits(ClientWritableStream, Writable); - -/** - * A stream that the client can write to. Used for calls that are streaming from - * the client side. - * @constructor grpc~ClientWritableStream - * @extends external:Writable - * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientWritableStream#cancel - * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientWritableStream#getPeer - * @borrows grpc~ClientUnaryCall#event:metadata as - * grpc~ClientWritableStream#metadata - * @borrows grpc~ClientUnaryCall#event:status as - * grpc~ClientWritableStream#status - * @param {InterceptingCall} call Exposes gRPC request operations, processed by - * an interceptor stack. - */ -function ClientWritableStream(call) { - Writable.call(this, {objectMode: true}); - this.call = call; - var self = this; - this.on('finish', function() { - self.call.halfClose(); - }); -} - -/** - * Write a message to the request stream. If serializing the argument fails, - * the call will be cancelled and the stream will end with an error. - * @name grpc~ClientWritableStream#write - * @kind function - * @override - * @param {*} message The message to write. Must be a valid argument to the - * serialize function of the corresponding method - * @param {grpc.writeFlags} flags Flags to modify how the message is written - * @param {Function} callback Callback for when this chunk of data is flushed - * @return {boolean} As defined for [Writable]{@link external:Writable} - */ - -/** - * Attempt to write the given chunk. Calls the callback when done. This is an - * implementation of a method needed for implementing stream.Writable. - * @private - * @param {*} chunk The chunk to write - * @param {grpc.writeFlags} encoding Used to pass write flags - * @param {function(Error=)} callback Called when the write is complete - */ -function _write(chunk, encoding, callback) { - /* jshint validthis: true */ - var self = this; - if (this.writeFailed) { - /* Once a write fails, just call the callback immediately to let the caller - flush any pending writes. */ - setImmediate(callback); - return; - } - var outerCallback = function(err, event) { - if (err) { - /* Assume that the call is complete and that writing failed because a - status was received. In that case, set a flag to discard all future - writes */ - self.writeFailed = true; - } - callback(); - }; - var context = { - encoding: encoding, - callback: outerCallback - }; - this.call.sendMessageWithContext(context, chunk); -} - -ClientWritableStream.prototype._write = _write; - -util.inherits(ClientReadableStream, Readable); - -/** - * A stream that the client can read from. Used for calls that are streaming - * from the server side. - * @constructor grpc~ClientReadableStream - * @extends external:Readable - * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientReadableStream#cancel - * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientReadableStream#getPeer - * @borrows grpc~ClientUnaryCall#event:metadata as - * grpc~ClientReadableStream#metadata - * @borrows grpc~ClientUnaryCall#event:status as - * grpc~ClientReadableStream#status - * @param {InterceptingCall} call Exposes gRPC request operations, processed by - * an interceptor stack. - */ -function ClientReadableStream(call) { - Readable.call(this, {objectMode: true}); - this.call = call; - this.finished = false; - this.reading = false; - /* Status generated from reading messages from the server. Overrides the - * status from the server if not OK */ - this.read_status = null; - /* Status received from the server. */ - this.received_status = null; -} - -/** - * Called when all messages from the server have been processed. The status - * parameter indicates that the call should end with that status. status - * defaults to OK if not provided. - * @param {Object!} status The status that the call should end with - * @private - */ -function _readsDone(status) { - /* jshint validthis: true */ - if (!status) { - status = {code: constants.status.OK, details: 'OK'}; - } - if (status.code !== constants.status.OK) { - this.call.cancelWithStatus(status.code, status.details); - } - this.finished = true; - this.read_status = status; - this._emitStatusIfDone(); -} - -ClientReadableStream.prototype._readsDone = _readsDone; - -/** - * Called to indicate that we have received a status from the server. - * @private - */ -function _receiveStatus(status) { - /* jshint validthis: true */ - this.received_status = status; - this._emitStatusIfDone(); -} - -ClientReadableStream.prototype._receiveStatus = _receiveStatus; - -/** - * If we have both processed all incoming messages and received the status from - * the server, emit the status. Otherwise, do nothing. - * @private - */ -function _emitStatusIfDone() { - /* jshint validthis: true */ - var status; - if (this.read_status && this.received_status) { - if (this.read_status.code !== constants.status.OK) { - status = this.read_status; - } else { - status = this.received_status; - } - if (status.code === constants.status.OK) { - this.push(null); - } else { - var error = common.createStatusError(status); - this.emit('error', error); - } - this.emit('status', status); - } -} - -ClientReadableStream.prototype._emitStatusIfDone = _emitStatusIfDone; - -/** - * Read the next object from the stream. - * @private - * @param {*} size Ignored because we use objectMode=true - */ -function _read(size) { - /* jshint validthis: true */ - if (this.finished) { - this.push(null); - } else { - if (!this.reading) { - this.reading = true; - var context = { - stream: this - }; - this.call.recvMessageWithContext(context); - } - } -} - -ClientReadableStream.prototype._read = _read; - -util.inherits(ClientDuplexStream, Duplex); - -/** - * A stream that the client can read from or write to. Used for calls with - * duplex streaming. - * @constructor grpc~ClientDuplexStream - * @extends external:Duplex - * @borrows grpc~ClientUnaryCall#cancel as grpc~ClientDuplexStream#cancel - * @borrows grpc~ClientUnaryCall#getPeer as grpc~ClientDuplexStream#getPeer - * @borrows grpc~ClientWritableStream#write as grpc~ClientDuplexStream#write - * @borrows grpc~ClientUnaryCall#event:metadata as - * grpc~ClientDuplexStream#metadata - * @borrows grpc~ClientUnaryCall#event:status as - * grpc~ClientDuplexStream#status - * @param {InterceptingCall} call Exposes gRPC request operations, processed by - * an interceptor stack. - */ -function ClientDuplexStream(call) { - Duplex.call(this, {objectMode: true}); - this.call = call; - /* Status generated from reading messages from the server. Overrides the - * status from the server if not OK */ - this.read_status = null; - /* Status received from the server. */ - this.received_status = null; - var self = this; - this.on('finish', function() { - self.call.halfClose(); - }); -} - -ClientDuplexStream.prototype._readsDone = _readsDone; -ClientDuplexStream.prototype._receiveStatus = _receiveStatus; -ClientDuplexStream.prototype._emitStatusIfDone = _emitStatusIfDone; -ClientDuplexStream.prototype._read = _read; -ClientDuplexStream.prototype._write = _write; - -/** - * Cancel the ongoing call. Results in the call ending with a CANCELLED status, - * unless it has already ended with some other status. - * @alias grpc~ClientUnaryCall#cancel - */ -function cancel() { - /* jshint validthis: true */ - this.call.cancel(); -} - -ClientUnaryCall.prototype.cancel = cancel; -ClientReadableStream.prototype.cancel = cancel; -ClientWritableStream.prototype.cancel = cancel; -ClientDuplexStream.prototype.cancel = cancel; - -/** - * Get the endpoint this call/stream is connected to. - * @return {string} The URI of the endpoint - * @alias grpc~ClientUnaryCall#getPeer - */ -function getPeer() { - /* jshint validthis: true */ - return this.call.getPeer(); -} - -ClientUnaryCall.prototype.getPeer = getPeer; -ClientReadableStream.prototype.getPeer = getPeer; -ClientWritableStream.prototype.getPeer = getPeer; -ClientDuplexStream.prototype.getPeer = getPeer; - -/** - * Any client call type - * @typedef {(grpc~ClientUnaryCall|grpc~ClientReadableStream| - * grpc~ClientWritableStream|grpc~ClientDuplexStream)} - * grpc.Client~Call - */ - -/** - * Options that can be set on a call. - * @typedef {Object} grpc.Client~CallOptions - * @property {grpc~Deadline} deadline The deadline for the entire call to - * complete. - * @property {string} host Server hostname to set on the call. Only meaningful - * if different from the server address used to construct the client. - * @property {grpc.Client~Call} parent Parent call. Used in servers when - * making a call as part of the process of handling a call. Used to - * propagate some information automatically, as specified by - * propagate_flags. - * @property {number} propagate_flags Indicates which properties of a parent - * call should propagate to this call. Bitwise combination of flags in - * {@link grpc.propagate}. - * @property {grpc.credentials~CallCredentials} credentials The credentials that - * should be used to make this particular call. - */ - -/** - * Properties of a call, for use with a {@link grpc.Client~callInvocationTransformer}. - * @typedef {Object} grpc.Client~CallProperties - * @property {*} argument The call argument. Only preset if the method is unary or server streaming. - * @property {grpc.Metadata} metadata The request metadata - * @property {grpc~Call} call The call object that will be returned by the client method - * @property {grpc.Channel} channel The channel that will be used to make a request - * @property {grpc~MethodDefinition} methodDefinition The MethodDefinition object that describes this method - * @property {grpc.Client~CallOptions} options The call options passed when making this request - * @property {grpc.Client~requestCallback} callback The callback that will handle the response. - * Only present if this method is unary or client streaming. - */ - -/** - * Call invocation transformer. Has access to the full call properties before a - * call is processed and can modify most of those properties. Some modifications - * will have no effect or may cause problems. - * @name grpc.Client~callInvocationTransformer - * @function - * @param {grpc.Client~CallProperties} callProperties The original call properties - * @return {grpc.Client~CallProperties} The modified call properties. - */ - -/** - * A function that functionally replaces the Channel constructor. - * @name grpc.Client~channelFactory - * @function - * @param {string} target The address of the server to connect to - * @param {grpc.ChannelCredentials} credentials Channel credentials to use when connecting - * @param {grpc~ChannelOptions} options A map of channel options that will be passed to the core. - * The available options are listed in - * [this document]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}. - * @returns {grpc.Channel} This can either be an actual channel object, or an object with the - * same API. - */ - -/** - * A generic gRPC client. Primarily useful as a base class for generated clients - * @memberof grpc - * @constructor - * @param {string} address Server address to connect to - * @param {grpc.credentials~ChannelCredentials} credentials Credentials to use - * to connect to the server - * @param {Object} options Options to apply to channel creation. Any of - * [the channel arguments]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html} - * can be used here in addition to specific client options. - * @param {grpc~Interceptor[]} [options.interceptors] Interceptors to apply to each request - * @param {grpc~InterceptorProvider[]} [options.interceptor_providers] Interceptor providers - * to apply interceptors to each request depending on the method definition. At most - * one of the interceptors and interceptor_providers options may be set. - * @param {grpc.Client~callInvocationTransformer=} options.callInvocationTransformer - * @param {grpc.Channel=} options.channelOverride Channel to use instead of constructing a new one. - * If set, the address, credentials, channel arguments options, and channelFactoryOverride - * option will all be ignored. - * @param {grpc.Client~channelFactory} options.channelFactoryOverride Function to use instead of - * the Channel constructor when creating the Client's channel. - */ -function Client(address, credentials, options) { - var self = this; - if (!options) { - options = {}; - } - - // Resolve interceptor options and assign interceptors to each method - if (Array.isArray(options.interceptor_providers) && Array.isArray(options.interceptors)) { - throw new client_interceptors.InterceptorConfigurationError( - 'Both interceptors and interceptor_providers were passed as options ' + - 'to the client constructor. Only one of these is allowed.'); - } - self.$interceptors = options.interceptors || []; - self.$interceptor_providers = options.interceptor_providers || []; - if (self.$method_definitions) { - Object.keys(self.$method_definitions).forEach(method_name => { - const method_definition = self.$method_definitions[method_name]; - self[method_name].interceptors = client_interceptors - .resolveInterceptorProviders(self.$interceptor_providers, method_definition) - .concat(self.$interceptors); - }); - } - - this.$callInvocationTransformer = options.callInvocationTransformer; - - let channelOverride = options.channelOverride; - let channelFactoryOverride = options.channelFactoryOverride; - // Exclude channel options which have already been consumed - const ignoredKeys = [ - 'interceptors', 'interceptor_providers', 'channelOverride', - 'channelFactoryOverride', 'callInvocationTransformer' - ]; - var channel_options = Object.getOwnPropertyNames(options) - .reduce((acc, key) => { - if (ignoredKeys.indexOf(key) === -1) { - acc[key] = options[key]; - } - return acc; - }, {}); - /* Private fields use $ as a prefix instead of _ because it is an invalid - * prefix of a method name */ - if (channelOverride) { - this.$channel = options.channelOverride; - } else { - if (channelFactoryOverride) { - this.$channel = channelFactoryOverride(address, credentials, channel_options); - } else { - this.$channel = new grpc.Channel(address, credentials, channel_options); - } - } -} - -exports.Client = Client; - -Client.prototype.resolveCallInterceptors = function(method_definition, interceptors, interceptor_providers) { - if (Array.isArray(interceptors) && Array.isArray(interceptor_providers)) { - throw new client_interceptors.InterceptorConfigurationError( - 'Both interceptors and interceptor_providers were passed as call ' + - 'options. Only one of these is allowed.'); - } - if (Array.isArray(interceptors) || Array.isArray(interceptor_providers)) { - interceptors = interceptors || []; - interceptor_providers = interceptor_providers || []; - return client_interceptors.resolveInterceptorProviders(interceptor_providers, method_definition).concat(interceptors); - } else { - return client_interceptors.resolveInterceptorProviders(this.$interceptor_providers, method_definition).concat(this.$interceptors); - } -} - -/** - * @callback grpc.Client~requestCallback - * @param {?grpc~ServiceError} error The error, if the call - * failed - * @param {*} value The response value, if the call succeeded - */ - -/** - * Make a unary request to the given method, using the given serialize - * and deserialize functions, with the given argument. - * @param {string} path The path of the method to request - * @param {grpc~serialize} serialize The serialization function for - * inputs - * @param {grpc~deserialize} deserialize The deserialization - * function for outputs - * @param {*} argument The argument to the call. Should be serializable with - * serialize - * @param {grpc.Metadata=} metadata Metadata to add to the call - * @param {grpc.Client~CallOptions=} options Options map - * @param {grpc.Client~requestCallback} callback The callback - * for when the response is received - * @return {grpc~ClientUnaryCall} An event emitter for stream related events - */ -Client.prototype.makeUnaryRequest = function(path, serialize, deserialize, - argument, metadata, options, - callback) { - if (typeof options === 'function') { - callback = options; - if (metadata instanceof Metadata) { - options = {}; - } else { - options = metadata; - metadata = new Metadata(); - } - } else if (typeof metadata === 'function') { - callback = metadata; - metadata = new Metadata(); - options = {}; - } - if (!metadata) { - metadata = new Metadata(); - } - if (!options) { - options = {}; - } - if (!((metadata instanceof Metadata) && - (options instanceof Object) && - (typeof callback === 'function'))) { - throw new Error('Argument mismatch in makeUnaryRequest'); - } - - var method_definition = options.method_definition = { - path: path, - requestStream: false, - responseStream: false, - requestSerialize: serialize, - responseDeserialize: deserialize - }; - - metadata = metadata.clone(); - - var callProperties = { - argument: argument, - metadata: metadata, - call: new ClientUnaryCall(), - channel: this.$channel, - methodDefinition: method_definition, - callOptions: options, - callback: callback - }; - - // Transform call properties if specified. - if (this.$callInvocationTransformer) { - callProperties = this.$callInvocationTransformer(callProperties); - } - - var callOptions = callProperties.callOptions; - var methodDefinition = callProperties.methodDefinition; - - var interceptors = Client.prototype.resolveCallInterceptors.call( - this, - methodDefinition, - callOptions.interceptors, - callOptions.interceptor_providers - ); - - var intercepting_call = client_interceptors.getInterceptingCall( - methodDefinition, - callOptions, - interceptors, - callProperties.channel, - callProperties.callback - ); - - var emitter = callProperties.call; - emitter.call = intercepting_call; - - var last_listener = client_interceptors.getLastListener( - methodDefinition, - emitter, - callProperties.callback - ); - - intercepting_call.start(callProperties.metadata, last_listener); - intercepting_call.sendMessage(callProperties.argument); - intercepting_call.halfClose(); - - return emitter; -}; - -/** - * Make a client stream request to the given method, using the given serialize - * and deserialize functions, with the given argument. - * @param {string} path The path of the method to request - * @param {grpc~serialize} serialize The serialization function for - * inputs - * @param {grpc~deserialize} deserialize The deserialization - * function for outputs - * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to - * the call - * @param {grpc.Client~CallOptions=} options Options map - * @param {grpc.Client~requestCallback} callback The callback for when the - * response is received - * @return {grpc~ClientWritableStream} An event emitter for stream related - * events - */ -Client.prototype.makeClientStreamRequest = function(path, serialize, - deserialize, metadata, - options, callback) { - if (typeof options === 'function') { - callback = options; - if (metadata instanceof Metadata) { - options = {}; - } else { - options = metadata; - metadata = new Metadata(); - } - } else if (typeof metadata === 'function') { - callback = metadata; - metadata = new Metadata(); - options = {}; - } - if (!metadata) { - metadata = new Metadata(); - } - if (!options) { - options = {}; - } - if (!((metadata instanceof Metadata) && - (options instanceof Object) && - (typeof callback === 'function'))) { - throw new Error('Argument mismatch in makeClientStreamRequest'); - } - - var method_definition = options.method_definition = { - path: path, - requestStream: true, - responseStream: false, - requestSerialize: serialize, - responseDeserialize: deserialize - }; - - metadata = metadata.clone(); - - var callProperties = { - metadata: metadata, - call: new ClientWritableStream(), - channel: this.$channel, - methodDefinition: method_definition, - callOptions: options, - callback: callback - }; - - // Transform call properties if specified. - if (this.$callInvocationTransformer) { - callProperties = this.$callInvocationTransformer(callProperties); - } - - var callOptions = callProperties.callOptions; - var methodDefinition = callProperties.methodDefinition; - - var interceptors = Client.prototype.resolveCallInterceptors.call( - this, - methodDefinition, - callOptions.interceptors, - callOptions.interceptor_providers - ); - - var intercepting_call = client_interceptors.getInterceptingCall( - methodDefinition, - callOptions, - interceptors, - callProperties.channel, - callProperties.callback - ); - - var emitter = callProperties.call; - emitter.call = intercepting_call; - - var last_listener = client_interceptors.getLastListener( - methodDefinition, - emitter, - callProperties.callback - ); - - intercepting_call.start(callProperties.metadata, last_listener); - - return emitter; -}; - -/** - * Make a server stream request to the given method, with the given serialize - * and deserialize function, using the given argument - * @param {string} path The path of the method to request - * @param {grpc~serialize} serialize The serialization function for inputs - * @param {grpc~deserialize} deserialize The deserialization - * function for outputs - * @param {*} argument The argument to the call. Should be serializable with - * serialize - * @param {grpc.Metadata=} metadata Array of metadata key/value pairs to add to - * the call - * @param {grpc.Client~CallOptions=} options Options map - * @return {grpc~ClientReadableStream} An event emitter for stream related - * events - */ -Client.prototype.makeServerStreamRequest = function(path, serialize, - deserialize, argument, - metadata, options) { - if (!(metadata instanceof Metadata)) { - options = metadata; - metadata = new Metadata(); - } - if (!(options instanceof Object)) { - options = {}; - } - if (!((metadata instanceof Metadata) && (options instanceof Object))) { - throw new Error('Argument mismatch in makeServerStreamRequest'); - } - - var method_definition = options.method_definition = { - path: path, - requestStream: false, - responseStream: true, - requestSerialize: serialize, - responseDeserialize: deserialize - }; - - metadata = metadata.clone(); - - var callProperties = { - argument: argument, - metadata: metadata, - call: new ClientReadableStream(), - channel: this.$channel, - methodDefinition: method_definition, - callOptions: options, - }; - - // Transform call properties if specified. - if (this.$callInvocationTransformer) { - callProperties = this.$callInvocationTransformer(callProperties); - } - - var callOptions = callProperties.callOptions; - var methodDefinition = callProperties.methodDefinition; - - var interceptors = Client.prototype.resolveCallInterceptors.call( - this, - methodDefinition, - callOptions.interceptors, - callOptions.interceptor_providers - ); - - var emitter = callProperties.call; - var intercepting_call = client_interceptors.getInterceptingCall( - methodDefinition, - callOptions, - interceptors, - callProperties.channel, - emitter - ); - emitter.call = intercepting_call; - var last_listener = client_interceptors.getLastListener( - methodDefinition, - emitter - ); - - intercepting_call.start(callProperties.metadata, last_listener); - intercepting_call.sendMessage(callProperties.argument); - intercepting_call.halfClose(); - - return emitter; -}; - -/** - * Make a bidirectional stream request with this method on the given channel. - * @param {string} path The path of the method to request - * @param {grpc~serialize} serialize The serialization function for inputs - * @param {grpc~deserialize} deserialize The deserialization - * function for outputs - * @param {grpc.Metadata=} metadata Array of metadata key/value - * pairs to add to the call - * @param {grpc.Client~CallOptions=} options Options map - * @return {grpc~ClientDuplexStream} An event emitter for stream related events - */ -Client.prototype.makeBidiStreamRequest = function(path, serialize, - deserialize, metadata, - options) { - if (!(metadata instanceof Metadata)) { - options = metadata; - metadata = new Metadata(); - } - if (!(options instanceof Object)) { - options = {}; - } - if (!((metadata instanceof Metadata) && (options instanceof Object))) { - throw new Error('Argument mismatch in makeBidiStreamRequest'); - } - - var method_definition = options.method_definition = { - path: path, - requestStream: true, - responseStream: true, - requestSerialize: serialize, - responseDeserialize: deserialize - }; - - metadata = metadata.clone(); - - var callProperties = { - metadata: metadata, - call: new ClientDuplexStream(), - channel: this.$channel, - methodDefinition: method_definition, - callOptions: options, - }; - - // Transform call properties if specified. - if (this.$callInvocationTransformer) { - callProperties = this.$callInvocationTransformer(callProperties); - } - - var callOptions = callProperties.callOptions; - var methodDefinition = callProperties.methodDefinition; - - var interceptors = Client.prototype.resolveCallInterceptors.call( - this, - methodDefinition, - callOptions.interceptors, - callOptions.interceptor_providers - ); - - - var emitter = callProperties.call; - var intercepting_call = client_interceptors.getInterceptingCall( - methodDefinition, - callOptions, - interceptors, - callProperties.channel, - emitter - ); - emitter.call = intercepting_call; - var last_listener = client_interceptors.getLastListener( - methodDefinition, - emitter - ); - - intercepting_call.start(callProperties.metadata, last_listener); - - return emitter; -}; - -/** - * Close this client. - */ -Client.prototype.close = function() { - this.$channel.close(); -}; - -/** - * Return the underlying channel object for the specified client - * @return {Channel} The channel - */ -Client.prototype.getChannel = function() { - return this.$channel; -}; - -/** - * Wait for the client to be ready. The callback will be called when the - * client has successfully connected to the server, and it will be called - * with an error if the attempt to connect to the server has unrecoverablly - * failed or if the deadline expires. This function will make the channel - * start connecting if it has not already done so. - * @param {grpc~Deadline} deadline When to stop waiting for a connection. - * @param {function(Error)} callback The callback to call when done attempting - * to connect. - */ -Client.prototype.waitForReady = function(deadline, callback) { - var self = this; - var checkState = function(err) { - if (err) { - callback(new Error('Failed to connect before the deadline')); - return; - } - var new_state; - try { - new_state = self.$channel.getConnectivityState(true); - } catch (e) { - callback(new Error('The channel has been closed')); - return; - } - if (new_state === grpc.connectivityState.READY) { - callback(); - } else if (new_state === grpc.connectivityState.FATAL_FAILURE) { - callback(new Error('Failed to connect to server')); - } else { - try { - self.$channel.watchConnectivityState(new_state, deadline, checkState); - } catch (e) { - callback(new Error('The channel has been closed')); - } - } - }; - /* Force a single round of polling to ensure that the channel state is up - * to date */ - grpc.forcePoll(); - setImmediate(checkState); -}; - -/** - * Map with short names for each of the requester maker functions. Used in - * makeClientConstructor - * @private - */ -var requester_funcs = { - [methodTypes.UNARY]: Client.prototype.makeUnaryRequest, - [methodTypes.CLIENT_STREAMING]: Client.prototype.makeClientStreamRequest, - [methodTypes.SERVER_STREAMING]: Client.prototype.makeServerStreamRequest, - [methodTypes.BIDI_STREAMING]: Client.prototype.makeBidiStreamRequest -}; - -function getDefaultValues(metadata, options) { - var res = {}; - res.metadata = metadata || new Metadata(); - res.options = options || {}; - return res; -} - -/** - * Map with wrappers for each type of requester function to make it use the old - * argument order with optional arguments after the callback. - * @access private - */ -var deprecated_request_wrap = { - [methodTypes.UNARY]: function(makeUnaryRequest) { - return function makeWrappedUnaryRequest(argument, callback, - metadata, options) { - /* jshint validthis: true */ - var opt_args = getDefaultValues(metadata, options); - return makeUnaryRequest.call(this, argument, opt_args.metadata, - opt_args.options, callback); - }; - }, - [methodTypes.CLIENT_STREAMING]: function(makeServerStreamRequest) { - return function makeWrappedClientStreamRequest(callback, metadata, - options) { - /* jshint validthis: true */ - var opt_args = getDefaultValues(metadata, options); - return makeServerStreamRequest.call(this, opt_args.metadata, - opt_args.options, callback); - }; - }, - [methodTypes.SERVER_STREAMING]: x => x, - [methodTypes.BIDI_STREAMING]: x => x -}; - -/** - * Creates a constructor for a client with the given methods, as specified in - * the methods argument. The resulting class will have an instance method for - * each method in the service, which is a partial application of one of the - * [Client]{@link grpc.Client} request methods, depending on `requestSerialize` - * and `responseSerialize`, with the `method`, `serialize`, and `deserialize` - * arguments predefined. - * @memberof grpc - * @alias grpc~makeGenericClientConstructor - * @param {grpc~ServiceDefinition} methods An object mapping method names to - * method attributes - * @param {string} serviceName The fully qualified name of the service - * @param {Object} class_options An options object. - * @param {boolean=} [class_options.deprecatedArgumentOrder=false] Indicates - * that the old argument order should be used for methods, with optional - * arguments at the end instead of the callback at the end. This option - * is only a temporary stopgap measure to smooth an API breakage. - * It is deprecated, and new code should not use it. - * @return {function} New client constructor, which is a subclass of - * {@link grpc.Client}, and has the same arguments as that constructor. - */ -exports.makeClientConstructor = function(methods, serviceName, - class_options) { - if (!class_options) { - class_options = {}; - } - - function ServiceClient(address, credentials, options) { - Client.call(this, address, credentials, options); - } - - util.inherits(ServiceClient, Client); - ServiceClient.prototype.$method_definitions = methods; - ServiceClient.prototype.$method_names = {}; - - Object.keys(methods).forEach(name => { - const attrs = methods[name]; - if (name.indexOf('$') === 0) { - throw new Error('Method names cannot start with $'); - } - var method_type = common.getMethodType(attrs); - var method_func = function() { - return requester_funcs[method_type].apply(this, - [ attrs.path, attrs.requestSerialize, attrs.responseDeserialize ] - .concat([].slice.call(arguments)) - ); - }; - if (class_options.deprecatedArgumentOrder) { - ServiceClient.prototype[name] = - deprecated_request_wrap[method_type](method_func); - } else { - ServiceClient.prototype[name] = method_func; - } - ServiceClient.prototype.$method_names[attrs.path] = name; - // Associate all provided attributes with the method - Object.assign(ServiceClient.prototype[name], attrs); - if (attrs.originalName) { - ServiceClient.prototype[attrs.originalName] = - ServiceClient.prototype[name]; - } - }); - - ServiceClient.service = methods; - - return ServiceClient; -}; - -/** - * Return the underlying channel object for the specified client - * @memberof grpc - * @alias grpc~getClientChannel - * @param {grpc.Client} client The client - * @return {Channel} The channel - * @see grpc.Client#getChannel - */ -exports.getClientChannel = function(client) { - return Client.prototype.getChannel.call(client); -}; - -/** - * Gets a map of client method names to interceptor stacks. - * @param {grpc.Client} client - * @returns {Object.} - */ -exports.getClientInterceptors = function(client) { - return Object.keys(client.$method_definitions) - .reduce((acc, key) => { - if (typeof key === 'string') { - acc[key] = client[key].interceptors; - } - return acc; - }, {}); -}; - -/** - * Wait for the client to be ready. The callback will be called when the - * client has successfully connected to the server, and it will be called - * with an error if the attempt to connect to the server has unrecoverablly - * failed or if the deadline expires. This function will make the channel - * start connecting if it has not already done so. - * @memberof grpc - * @alias grpc~waitForClientReady - * @param {grpc.Client} client The client to wait on - * @param {grpc~Deadline} deadline When to stop waiting for a connection. Pass - * Infinity to wait forever. - * @param {function(Error)} callback The callback to call when done attempting - * to connect. - * @see grpc.Client#waitForReady - */ -exports.waitForClientReady = function(client, deadline, callback) { - Client.prototype.waitForReady.call(client, deadline, callback); -}; - -exports.StatusBuilder = client_interceptors.StatusBuilder; -exports.ListenerBuilder = client_interceptors.ListenerBuilder; -exports.RequesterBuilder = client_interceptors.RequesterBuilder; -exports.InterceptingCall = client_interceptors.InterceptingCall; diff --git a/packages/grpc-native-core/src/client_interceptors.js b/packages/grpc-native-core/src/client_interceptors.js deleted file mode 100644 index 75243cc2b..000000000 --- a/packages/grpc-native-core/src/client_interceptors.js +++ /dev/null @@ -1,1444 +0,0 @@ -/** - * @license - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * Client Interceptors - * - * This module describes the interceptor framework for clients. - * An interceptor is a function which takes an options object and a nextCall - * function and returns an InterceptingCall: - * - * ``` - * var interceptor = function(options, nextCall) { - * return new InterceptingCall(nextCall(options)); - * } - * ``` - * - * The interceptor function must return an InterceptingCall object. Returning - * `new InterceptingCall(nextCall(options))` will satisfy the contract (but - * provide no interceptor functionality). `nextCall` is a function which will - * generate the next interceptor in the chain. - * - * To implement interceptor functionality, create a requester and pass it to - * the InterceptingCall constructor: - * - * `return new InterceptingCall(nextCall(options), requester);` - * - * A requester is a POJO with zero or more of the following methods: - * - * `start(metadata, listener, next)` - * * To continue, call next(metadata, listener). Listeners are described - * * below. - * - * `sendMessage(message, next)` - * * To continue, call next(message). - * - * `halfClose(next)` - * * To continue, call next(). - * - * `cancel(next)` - * * To continue, call next(). - * - * A listener is a POJO with one or more of the following methods: - * - * `onReceiveMetadata(metadata, next)` - * * To continue, call next(metadata) - * - * `onReceiveMessage(message, next)` - * * To continue, call next(message) - * - * `onReceiveStatus(status, next)` - * * To continue, call next(status) - * - * A listener is provided by the requester's `start` method. The provided - * listener implements all the inbound interceptor methods, which can be called - * to short-circuit the gRPC call. - * - * Three usage patterns are supported for listeners: - * 1) Pass the listener along without modification: `next(metadata, listener)`. - * In this case the interceptor declines to intercept any inbound operations. - * 2) Create a new listener with one or more inbound interceptor methods and - * pass it to `next`. In this case the interceptor will fire on the inbound - * operations implemented in the new listener. - * 3) Make direct inbound calls to the provided listener's methods. This - * short-circuits the interceptor stack. - * - * Do not modify the listener passed in. Either pass it along unmodified, - * ignore it, or call methods on it to short-circuit the call. - * - * To intercept errors, implement the `onReceiveStatus` method and test for - * `status.code !== grpc.status.OK`. - * - * To intercept trailers, examine `status.metadata` in the `onReceiveStatus` - * method. - * - * This is a trivial implementation of all interceptor methods: - * var interceptor = function(options, nextCall) { - * return new InterceptingCall(nextCall(options), { - * start: function(metadata, listener, next) { - * next(metadata, { - * onReceiveMetadata: function (metadata, next) { - * next(metadata); - * }, - * onReceiveMessage: function (message, next) { - * next(message); - * }, - * onReceiveStatus: function (status, next) { - * next(status); - * }, - * }); - * }, - * sendMessage: function(message, next) { - * next(message); - * }, - * halfClose: function(next) { - * next(); - * }, - * cancel: function(next) { - * next(); - * } - * }); - * }; - * - * This is an interceptor with a single method: - * var interceptor = function(options, nextCall) { - * return new InterceptingCall(nextCall(options), { - * sendMessage: function(message, next) { - * next(message); - * } - * }); - * }; - * - * Builders are provided for convenience: StatusBuilder, ListenerBuilder, - * and RequesterBuilder - * - * gRPC client operations use this mapping to interceptor methods: - * - * grpc.opType.SEND_INITIAL_METADATA -> start - * grpc.opType.SEND_MESSAGE -> sendMessage - * grpc.opType.SEND_CLOSE_FROM_CLIENT -> halfClose - * grpc.opType.RECV_INITIAL_METADATA -> onReceiveMetadata - * grpc.opType.RECV_MESSAGE -> onReceiveMessage - * grpc.opType.RECV_STATUS_ON_CLIENT -> onReceiveStatus - * - * @module - */ - -'use strict'; - -var grpc = require('./grpc_extension'); -var Metadata = require('./metadata'); -var constants = require('./constants'); -var common = require('./common'); -var methodTypes = constants.methodTypes; -var EventEmitter = require('events').EventEmitter; - -/** - * A custom error thrown when interceptor configuration fails. - * @param {string} message The error message - * @param {object=} extra - * @constructor - */ -var InterceptorConfigurationError = - function InterceptorConfigurationError(message, extra) { - Error.captureStackTrace(this, this.constructor); - this.name = this.constructor.name; - this.message = message; - this.extra = extra; - }; - -require('util').inherits(InterceptorConfigurationError, Error); - -/** - * A builder for gRPC status objects. - * @constructor - */ -function StatusBuilder() { - this.code = null; - this.details = null; - this.metadata = null; -} - -/** - * Adds a status code to the builder. - * @param {number} code The status code. - * @return {StatusBuilder} - */ -StatusBuilder.prototype.withCode = function(code) { - this.code = code; - return this; -}; - -/** - * Adds details to the builder. - * @param {string} details A status message. - * @return {StatusBuilder} - */ -StatusBuilder.prototype.withDetails = function(details) { - this.details = details; - return this; -}; - -/** - * Adds metadata to the builder. - * @param {Metadata} metadata The gRPC status metadata. - * @return {StatusBuilder} - */ -StatusBuilder.prototype.withMetadata = function(metadata) { - this.metadata = metadata; - return this; -}; - -/** - * Builds the status object. - * @return {grpc~StatusObject} A gRPC status. - */ -StatusBuilder.prototype.build = function() { - var status = {}; - if (this.code !== undefined) { - status.code = this.code; - } - if (this.details) { - status.details = this.details; - } - if (this.metadata) { - status.metadata = this.metadata; - } - return status; -}; - -/** - * A builder for listener interceptors. - * @constructor - */ -function ListenerBuilder() { - this.metadata = null; - this.message = null; - this.status = null; -} - -/** - * Adds an onReceiveMetadata method to the builder. - * @param {MetadataListener} on_receive_metadata A listener method for - * receiving metadata. - * @return {ListenerBuilder} - */ -ListenerBuilder.prototype.withOnReceiveMetadata = - function(on_receive_metadata) { - this.metadata = on_receive_metadata; - return this; - }; - -/** - * Adds an onReceiveMessage method to the builder. - * @param {MessageListener} on_receive_message A listener method for receiving - * messages. - * @return {ListenerBuilder} - */ -ListenerBuilder.prototype.withOnReceiveMessage = function(on_receive_message) { - this.message = on_receive_message; - return this; -}; - -/** - * Adds an onReceiveStatus method to the builder. - * @param {StatusListener} on_receive_status A listener method for receiving - * status. - * @return {ListenerBuilder} - */ -ListenerBuilder.prototype.withOnReceiveStatus = function(on_receive_status) { - this.status = on_receive_status; - return this; -}; - -/** - * Builds the call listener. - * @return {grpc~Listener} - */ -ListenerBuilder.prototype.build = function() { - var self = this; - var listener = {}; - listener.onReceiveMetadata = self.metadata; - listener.onReceiveMessage = self.message; - listener.onReceiveStatus = self.status; - return listener; -}; - -/** - * A builder for the outbound methods of an interceptor. - * @constructor - */ -function RequesterBuilder() { - this.start = null; - this.message = null; - this.half_close = null; - this.cancel = null; -} - -/** - * Add a metadata requester to the builder. - * @param {MetadataRequester} start A requester method for handling metadata. - * @return {RequesterBuilder} - */ -RequesterBuilder.prototype.withStart = function(start) { - this.start = start; - return this; -}; - -/** - * Add a message requester to the builder. - * @param {MessageRequester} send_message A requester method for handling - * messages. - * @return {RequesterBuilder} - */ -RequesterBuilder.prototype.withSendMessage = function(send_message) { - this.message = send_message; - return this; -}; - -/** - * Add a close requester to the builder. - * @param {CloseRequester} half_close A requester method for handling client - * close. - * @return {RequesterBuilder} - */ -RequesterBuilder.prototype.withHalfClose = function(half_close) { - this.half_close = half_close; - return this; -}; - -/** - * Add a cancel requester to the builder. - * @param {CancelRequester} cancel A requester method for handling `cancel` - * @return {RequesterBuilder} - */ -RequesterBuilder.prototype.withCancel = function(cancel) { - this.cancel = cancel; - return this; -}; - -/** - * Builds the requester's interceptor methods. - * @return {grpc~Requester} - */ -RequesterBuilder.prototype.build = function() { - var requester = {}; - requester.start = this.start; - requester.sendMessage = this.message; - requester.halfClose = this.half_close; - requester.cancel = this.cancel; - return requester; -}; - -/** - * Transforms a list of interceptor providers into interceptors. - * @param {InterceptorProvider[]} providers - * @param {grpc~MethodDefinition} method_definition - * @return {null|Interceptor[]} - */ -var resolveInterceptorProviders = function(providers, method_definition) { - if (!Array.isArray(providers)) { - return null; - } - var interceptors = []; - for (var i = 0; i < providers.length; i++) { - var provider = providers[i]; - var interceptor = provider(method_definition); - if (interceptor) { - interceptors.push(interceptor); - } - } - return interceptors; -}; - -/** - * A chainable gRPC call proxy which will delegate to an optional requester - * object. By default, interceptor methods will chain to next_call. If a - * requester is provided which implements an interceptor method, that - * requester method will be executed as part of the chain. - * @param {InterceptingCall|null} next_call The next call in the chain - * @param {grpc~Requester=} requester Interceptor methods to handle request - * operations. - * @constructor - */ -function InterceptingCall(next_call, requester) { - this.next_call = next_call; - this.requester = requester; -} - -const emptyNext = function() {}; - -/** - * Get the next method in the chain or a no-op function if we are at the end - * of the chain - * @param {string} method_name - * @return {function} The next method in the chain - * @private - */ -InterceptingCall.prototype._getNextCall = function(method_name) { - return this.next_call ? - this.next_call[method_name].bind(this.next_call) : - emptyNext; -}; - -/** - * Call the next method in the chain. This will either be on the next - * InterceptingCall (next_call), or the requester if the requester - * implements the method. - * @param {string} method_name The name of the interceptor method - * @param {array=} args Payload arguments for the operation - * @param {function=} next The next InterceptingCall's method - * @return {null} - * @private - */ -InterceptingCall.prototype._callNext = function(method_name, args, next) { - var args_array = args || []; - var next_call = next ? next : this._getNextCall(method_name); - if (this.requester && this.requester[method_name]) { - // Avoid using expensive `apply` calls - var num_args = args_array.length; - switch (num_args) { - case 0: - return this.requester[method_name](next_call); - case 1: - return this.requester[method_name](args_array[0], next_call); - case 2: - return this.requester[method_name](args_array[0], args_array[1], - next_call); - } - } else { - if (next_call === emptyNext) { - throw new Error('Interceptor call chain terminated unexpectedly'); - } - return next_call(args_array[0], args_array[1]); - } -}; - -/** - * Starts a call through the outbound interceptor chain and adds an element to - * the reciprocal inbound listener chain. - * @param {grpc.Metadata} metadata The outgoing metadata. - * @param {grpc~Listener} listener An intercepting listener for inbound - * operations. - */ -InterceptingCall.prototype.start = function(metadata, listener) { - var self = this; - - // If the listener provided is an InterceptingListener, use it. Otherwise, we - // must be at the end of the listener chain, and any listener operations - // should be terminated in an EndListener. - var next_listener = _getInterceptingListener(listener, new EndListener()); - - // Build the next method in the interceptor chain - var next = function(metadata, current_listener) { - // If there is a next call in the chain, run it. Otherwise do nothing. - if (self.next_call) { - // Wire together any listener provided with the next listener - var listener = _getInterceptingListener(current_listener, next_listener); - self.next_call.start(metadata, listener); - } - }; - this._callNext('start', [metadata, next_listener], next); -}; - -/** - * Pass a message through the interceptor chain. - * @param {jspb.Message} message - */ -InterceptingCall.prototype.sendMessage = function(message) { - this._callNext('sendMessage', [message]); -}; - -/** - * Run a close operation through the interceptor chain - */ -InterceptingCall.prototype.halfClose = function() { - this._callNext('halfClose'); -}; - -/** - * Run a cancel operation through the interceptor chain - */ -InterceptingCall.prototype.cancel = function() { - this._callNext('cancel'); -}; - -/** - * Run a cancelWithStatus operation through the interceptor chain. - * @param {number} code - * @param {string} details - */ -InterceptingCall.prototype.cancelWithStatus = function(code, details) { - this._callNext('cancelWithStatus', [code, details]); -}; - -/** - * Pass a getPeer call down to the base gRPC call (should not be intercepted) - * @return {object} - */ -InterceptingCall.prototype.getPeer = function() { - return this._callNext('getPeer'); -}; - -/** - * For streaming calls, we need to transparently pass the stream's context - * through the interceptor chain. Passes the context between InterceptingCalls - * but hides it from any requester implementations. - * @param {object} context Carries objects needed for streaming operations. - * @param {jspb.Message} message The message to send. - */ -InterceptingCall.prototype.sendMessageWithContext = function(context, message) { - var next = this.next_call ? - this.next_call.sendMessageWithContext.bind(this.next_call, context) : - context; - this._callNext('sendMessage', [message], next); -}; - -/** - * For receiving streaming messages, we need to seed the base interceptor with - * the streaming context to create a RECV_MESSAGE batch. - * @param {object} context Carries objects needed for streaming operations - */ -InterceptingCall.prototype.recvMessageWithContext = function(context) { - this._callNext('recvMessageWithContext', [context]); -}; - -/** - * A chain-able listener object which will delegate to a custom listener when - * appropriate. - * @param {InterceptingListener|null} next_listener The next - * InterceptingListener in the chain - * @param {grpc~Listener=} delegate A custom listener object which may implement - * specific operations - * @constructor - */ -function InterceptingListener(next_listener, delegate) { - this.delegate = delegate || {}; - this.next_listener = next_listener; -} - -/** - * Get the next method in the chain or a no-op function if we are at the end - * of the chain. - * @param {string} method_name The name of the listener method. - * @return {function} The next method in the chain - * @private - */ -InterceptingListener.prototype._getNextListener = function(method_name) { - return this.next_listener ? - this.next_listener[method_name].bind(this.next_listener) : - function(){}; -}; - -/** - * Call the next method in the chain. This will either be on the next - * InterceptingListener (next_listener), or the requester if the requester - * implements the method. - * @param {string} method_name The name of the interceptor method - * @param {array=} args Payload arguments for the operation - * @param {function=} next The next InterceptingListener's method - * @return {null} - * @private - */ -InterceptingListener.prototype._callNext = function(method_name, args, next) { - var args_array = args || []; - var next_listener = next ? next : this._getNextListener(method_name); - if (this.delegate && this.delegate[method_name]) { - // Avoid using expensive `apply` calls - var num_args = args_array.length; - switch (num_args) { - case 0: - return this.delegate[method_name](next_listener); - case 1: - return this.delegate[method_name](args_array[0], next_listener); - case 2: - return this.delegate[method_name](args_array[0], args_array[1], - next_listener); - } - } else { - return next_listener(args_array[0], args_array[1]); - } -}; -/** - * Inbound metadata receiver. - * @param {Metadata} metadata - */ -InterceptingListener.prototype.onReceiveMetadata = function(metadata) { - this._callNext('onReceiveMetadata', [metadata]); -}; - -/** - * Inbound message receiver. - * @param {jspb.Message} message - */ -InterceptingListener.prototype.onReceiveMessage = function(message) { - this._callNext('onReceiveMessage', [message]); -}; - -/** - * When intercepting streaming message, we need to pass the streaming context - * transparently along the chain. Hides the context from the delegate listener - * methods. - * @param {object} context Carries objects needed for streaming operations. - * @param {jspb.Message} message The message received. - */ -InterceptingListener.prototype.recvMessageWithContext = function(context, - message) { - var fallback = this.next_listener.recvMessageWithContext; - var next_method = this.next_listener ? - fallback.bind(this.next_listener, context) : - context; - if (this.delegate.onReceiveMessage) { - this.delegate.onReceiveMessage(message, next_method, context); - } else { - next_method(message); - } -}; - -/** - * Inbound status receiver. - * @param {grpc~StatusObject} status - */ -InterceptingListener.prototype.onReceiveStatus = function(status) { - this._callNext('onReceiveStatus', [status]); -}; - -/** - * A dead-end listener used to terminate a call chain. Used when an interceptor - * creates a branch chain, when the branch returns the listener chain will - * terminate here. - * @constructor - */ -function EndListener() {} -EndListener.prototype.onReceiveMetadata = function(){}; -EndListener.prototype.onReceiveMessage = function(){}; -EndListener.prototype.onReceiveStatus = function(){}; -EndListener.prototype.recvMessageWithContext = function(){}; - -/** - * Get a call object built with the provided options. - * @param {grpc.Channel} channel - * @param {string} path - * @param {grpc.Client~CallOptions=} options Options object. - */ -function getCall(channel, path, options) { - var deadline; - var host; - var parent; - var propagate_flags; - var credentials; - if (options) { - deadline = options.deadline; - host = options.host; - parent = options.parent ? options.parent.call : undefined; - propagate_flags = options.propagate_flags; - credentials = options.credentials; - } - if (deadline === undefined) { - deadline = Infinity; - } - var call = channel.createCall(path, deadline, host, - parent, propagate_flags); - if (credentials) { - call.setCredentials(credentials); - } - return call; -} - -var OP_DEPENDENCIES = { - [grpc.opType.SEND_MESSAGE]: [grpc.opType.SEND_INITIAL_METADATA], - [grpc.opType.SEND_CLOSE_FROM_CLIENT]: [grpc.opType.SEND_MESSAGE], - [grpc.opType.RECV_MESSAGE]: [grpc.opType.SEND_INITIAL_METADATA] -}; - -/** - * Produces a callback triggered by streaming response messages. - * @private - * @param {EventEmitter} emitter - * @param {grpc.internal~Call} call - * @param {function} get_listener Returns a grpc~Listener. - * @param {grpc~deserialize} deserialize - * @return {Function} - */ -function _getStreamReadCallback(emitter, call, get_listener, deserialize) { - return function (err, response) { - if (err) { - // Something has gone wrong. Stop reading and wait for status - emitter.finished = true; - emitter._readsDone(); - return; - } - var data = response.read; - var deserialized; - try { - deserialized = deserialize(data); - } catch (e) { - common.log(constants.logVerbosity.ERROR, `Response deserialization failed: ${e.message}`); - emitter._readsDone({ - code: constants.status.INTERNAL, - details: 'Failed to parse server response' - }); - return; - } - if (data === null) { - emitter._readsDone(); - return; - } - var listener = get_listener(); - var context = { - call: call, - listener: listener - }; - listener.recvMessageWithContext(context, deserialized); - }; -} - -/** - * Tests whether a batch can be started. - * @private - * @param {number[]} batch_ops The operations in the batch we are checking. - * @param {number[]} completed_ops Previously completed operations. - * @return {boolean} - */ -function _areBatchRequirementsMet(batch_ops, completed_ops) { - var dependencies = common.flatMap(batch_ops, function(op) { - return OP_DEPENDENCIES[op] || []; - }); - for (var i = 0; i < dependencies.length; i++) { - var required_dep = dependencies[i]; - if (batch_ops.indexOf(required_dep) === -1 && - completed_ops.indexOf(required_dep) === -1) { - return false; - } - } - return true; -} - -/** - * Enforces the order of operations for synchronous requests. If a batch's - * operations cannot be started because required operations have not started - * yet, the batch is deferred until requirements are met. - * @private - * @param {grpc.Client~Call} call - * @param {object} batch - * @param {object} batch_state - * @param {number[]} [batch_state.completed_ops] The ops already sent. - * @param {object} [batch_state.deferred_batches] Batches to be sent after - * their dependencies are fulfilled. - * @param {function} callback - * @return {object} - */ -function _startBatchIfReady(call, batch, batch_state, callback) { - var completed_ops = batch_state.completed_ops; - var deferred_batches = batch_state.deferred_batches; - var batch_ops = Object.keys(batch).map(Number); - if (_areBatchRequirementsMet(batch_ops, completed_ops)) { - // Dependencies are met, start the batch and any deferred batches whose - // dependencies are met as a result. - call.startBatch(batch, callback); - completed_ops = Array.from(new Set(completed_ops.concat(batch_ops))); - deferred_batches = common.flatMap(deferred_batches, function(deferred_batch) { - var deferred_batch_ops = Object.keys(deferred_batch).map(Number); - if (_areBatchRequirementsMet(deferred_batch_ops, completed_ops)) { - call.startBatch(deferred_batch.batch, deferred_batch.callback); - return []; - } - return [deferred_batch]; - }); - } else { - // Dependencies are not met, defer the batch - deferred_batches = deferred_batches.concat({ - batch: batch, - callback: callback - }); - } - return { - completed_ops: completed_ops, - deferred_batches: deferred_batches - }; -} - -/** - * Produces an interceptor which will start gRPC batches for unary calls. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {grpc.Channel} channel - * @param {EventEmitter} emitter - * @param {function} callback - * @return {Interceptor} - */ -function _getUnaryInterceptor(method_definition, channel, emitter, callback) { - var serialize = method_definition.requestSerialize; - var deserialize = method_definition.responseDeserialize; - return function (options) { - var call = getCall(channel, method_definition.path, options); - var first_listener; - var final_requester = {}; - var batch_state = { - completed_ops: [], - deferred_batches: [] - }; - final_requester.start = function (metadata, listener) { - var batch = { - [grpc.opType.SEND_INITIAL_METADATA]: - metadata._getCoreRepresentation(), - }; - first_listener = listener; - batch_state = _startBatchIfReady(call, batch, batch_state, - function() {}); - }; - final_requester.sendMessage = function (message) { - var batch = { - [grpc.opType.SEND_MESSAGE]: serialize(message), - }; - batch_state = _startBatchIfReady(call, batch, batch_state, - function() {}); - }; - final_requester.halfClose = function () { - var batch = { - [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true, - [grpc.opType.RECV_INITIAL_METADATA]: true, - [grpc.opType.RECV_MESSAGE]: true, - [grpc.opType.RECV_STATUS_ON_CLIENT]: true - }; - var callback = function (err, response) { - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - var status = response.status; - var deserialized; - if (status.code === constants.status.OK) { - if (err) { - // Got a batch error, but OK status. Something went wrong - callback(err); - return; - } else { - try { - deserialized = deserialize(response.read); - } catch (e) { - common.log(constants.logVerbosity.ERROR, `Response deserialization failed: ${e.message}`); - /* Change status to indicate bad server response. This - * will result in passing an error to the callback */ - status = { - code: constants.status.INTERNAL, - details: 'Failed to parse server response' - }; - } - } - } - response.metadata = - Metadata._fromCoreRepresentation(response.metadata); - first_listener.onReceiveMetadata(response.metadata); - first_listener.onReceiveMessage(deserialized); - first_listener.onReceiveStatus(status); - }; - batch_state = _startBatchIfReady(call, batch, batch_state, callback); - }; - final_requester.cancel = function () { - call.cancel(); - }; - final_requester.cancelWithStatus = function(code, details) { - call.cancelWithStatus(code, details) - }; - final_requester.getPeer = function () { - return call.getPeer(); - }; - return new InterceptingCall(null, final_requester); - }; -} - -/** - * Produces an interceptor which will start gRPC batches for client streaming - * calls. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {grpc.Channel} channel - * @param {EventEmitter} emitter - * @param {function} callback - * @return {Interceptor} - */ -function _getClientStreamingInterceptor(method_definition, channel, emitter, - callback) { - var serialize = common.wrapIgnoreNull(method_definition.requestSerialize); - var deserialize = method_definition.responseDeserialize; - return function (options) { - var first_listener; - var call = getCall(channel, method_definition.path, options); - var final_requester = {}; - final_requester.start = function (metadata, listener) { - var metadata_batch = { - [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), - [grpc.opType.RECV_INITIAL_METADATA]: true - }; - first_listener = listener; - call.startBatch(metadata_batch, function (err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - response.metadata = Metadata._fromCoreRepresentation(response.metadata); - listener.onReceiveMetadata(response.metadata); - }); - var recv_batch = {}; - recv_batch[grpc.opType.RECV_MESSAGE] = true; - recv_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(recv_batch, function (err, response) { - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - var status = response.status; - var deserialized; - if (status.code === constants.status.OK) { - if (err) { - // Got a batch error, but OK status. Something went wrong - callback(err); - return; - } else { - try { - deserialized = deserialize(response.read); - } catch (e) { - common.log(constants.logVerbosity.ERROR, `Response deserialization failed: ${e.message}`); - /* Change status to indicate bad server response. This will result - * in passing an error to the callback */ - status = { - code: constants.status.INTERNAL, - details: 'Failed to parse server response' - }; - } - } - } - listener.onReceiveMessage(deserialized); - listener.onReceiveStatus(status); - }); - }; - final_requester.sendMessage = function (chunk, context) { - var message; - var callback = (context && context.callback) ? - context.callback : - function () { }; - var encoding = (context && context.encoding) ? - context.encoding : - ''; - try { - message = serialize(chunk); - } catch (e) { - common.log(constants.logVerbosity.ERROR, `Request serialization failed: ${e.message}`); - /* Sending this error to the server and emitting it immediately on the - client may put the call in a slightly weird state on the client side, - but passing an object that causes a serialization failure is a misuse - of the API anyway, so that's OK. The primary purpose here is to give - the programmer a useful error and to stop the stream properly */ - call.cancelWithStatus(constants.status.INTERNAL, - 'Serialization failure'); - callback(e); - return; - } - if (Number.isFinite(encoding)) { - /* Attach the encoding if it is a finite number. This is the closest we - * can get to checking that it is valid flags */ - message.grpcWriteFlags = encoding; - } - var batch = { - [grpc.opType.SEND_MESSAGE]: message - }; - call.startBatch(batch, function (err, event) { - callback(err, event); - }); - }; - final_requester.halfClose = function () { - var batch = { - [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true - }; - call.startBatch(batch, function () { }); - }; - final_requester.cancel = function () { - call.cancel(); - }; - final_requester.cancelWithStatus = function(code, details) { - call.cancelWithStatus(code, details) - }; - final_requester.getPeer = function() { - return call.getPeer(); - }; - return new InterceptingCall(null, final_requester); - }; -} - -/** - * Produces an interceptor which will start gRPC batches for server streaming - * calls. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {grpc.Channel} channel - * @param {EventEmitter} emitter - * @return {Interceptor} - */ -function _getServerStreamingInterceptor(method_definition, channel, emitter) { - var deserialize = common.wrapIgnoreNull( - method_definition.responseDeserialize); - var serialize = method_definition.requestSerialize; - return function (options) { - var batch_state = { - completed_ops: [], - deferred_batches: [] - }; - var call = getCall(channel, method_definition.path, options); - var final_requester = {}; - var first_listener; - var get_listener = function() { - return first_listener; - }; - final_requester.start = function(metadata, listener) { - first_listener = listener; - metadata = metadata.clone(); - var metadata_batch = { - [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), - [grpc.opType.RECV_INITIAL_METADATA]: true - }; - var callback = function(err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - first_listener.onReceiveMetadata( - Metadata._fromCoreRepresentation(response.metadata)); - }; - batch_state = _startBatchIfReady(call, metadata_batch, batch_state, - callback); - var status_batch = { - [grpc.opType.RECV_STATUS_ON_CLIENT]: true - }; - call.startBatch(status_batch, function(err, response) { - if (err) { - emitter.emit('error', err); - return; - } - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - first_listener.onReceiveStatus(response.status); - }); - }; - final_requester.sendMessage = function(argument) { - var message = serialize(argument); - if (options) { - message.grpcWriteFlags = options.flags; - } - var send_batch = { - [grpc.opType.SEND_MESSAGE]: message - }; - var callback = function(err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - }; - batch_state = _startBatchIfReady(call, send_batch, batch_state, callback); - }; - final_requester.halfClose = function() { - var batch = { - [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true - }; - batch_state = _startBatchIfReady(call, batch, batch_state, function() {}); - }; - final_requester.recvMessageWithContext = function(context) { - var recv_batch = { - [grpc.opType.RECV_MESSAGE]: true - }; - var callback = _getStreamReadCallback(emitter, call, - get_listener, deserialize); - batch_state = _startBatchIfReady(call, recv_batch, batch_state, callback); - }; - final_requester.cancel = function() { - call.cancel(); - }; - final_requester.cancelWithStatus = function(code, details) { - call.cancelWithStatus(code, details) - }; - final_requester.getPeer = function() { - return call.getPeer(); - }; - return new InterceptingCall(null, final_requester); - }; -} - -/** - * Produces an interceptor which will start gRPC batches for bi-directional - * calls. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {grpc.Channel} channel - * @param {EventEmitter} emitter - * @return {Interceptor} - */ -function _getBidiStreamingInterceptor(method_definition, channel, emitter) { - var serialize = common.wrapIgnoreNull(method_definition.requestSerialize); - var deserialize = common.wrapIgnoreNull( - method_definition.responseDeserialize); - return function (options) { - var first_listener; - var get_listener = function() { - return first_listener; - }; - var call = getCall(channel, method_definition.path, options); - var final_requester = {}; - final_requester.start = function (metadata, listener) { - var metadata_batch = { - [grpc.opType.SEND_INITIAL_METADATA]: metadata._getCoreRepresentation(), - [grpc.opType.RECV_INITIAL_METADATA]: true - }; - first_listener = listener; - call.startBatch(metadata_batch, function (err, response) { - if (err) { - // The call has stopped for some reason. A non-OK status will arrive - // in the other batch. - return; - } - response.metadata = Metadata._fromCoreRepresentation(response.metadata); - listener.onReceiveMetadata(response.metadata); - }); - var recv_batch = {}; - recv_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(recv_batch, function (err, response) { - var status = response.status; - if (status.code === constants.status.OK) { - if (err) { - emitter.emit('error', err); - return; - } - } - response.status.metadata = Metadata._fromCoreRepresentation( - response.status.metadata); - listener.onReceiveStatus(status); - }); - }; - final_requester.sendMessage = function (chunk, context) { - var message; - var callback = (context && context.callback) ? - context.callback : - function() {}; - var encoding = (context && context.encoding) ? - context.encoding : - ''; - try { - message = serialize(chunk); - } catch (e) { - common.log(constants.logVerbosity.ERROR, `Request serialization failed: ${e.message}`); - /* Sending this error to the server and emitting it immediately on the - client may put the call in a slightly weird state on the client side, - but passing an object that causes a serialization failure is a misuse - of the API anyway, so that's OK. The primary purpose here is to give - the programmer a useful error and to stop the stream properly */ - call.cancelWithStatus(constants.status.INTERNAL, - 'Serialization failure'); - callback(e); - return; - } - if (Number.isFinite(encoding)) { - /* Attach the encoding if it is a finite number. This is the closest we - * can get to checking that it is valid flags */ - message.grpcWriteFlags = encoding; - } - var batch = { - [grpc.opType.SEND_MESSAGE]: message - }; - call.startBatch(batch, function (err, event) { - callback(err, event); - }); - }; - final_requester.halfClose = function () { - var batch = { - [grpc.opType.SEND_CLOSE_FROM_CLIENT]: true - }; - call.startBatch(batch, function () { }); - }; - final_requester.recvMessageWithContext = function(context) { - var recv_batch = { - [grpc.opType.RECV_MESSAGE]: true - }; - call.startBatch(recv_batch, _getStreamReadCallback(emitter, call, - get_listener, deserialize)); - }; - final_requester.cancel = function() { - call.cancel(); - }; - final_requester.cancelWithStatus = function(code, details) { - call.cancelWithStatus(code, details) - }; - final_requester.getPeer = function() { - return call.getPeer(); - }; - return new InterceptingCall(null, final_requester); - }; -} - -/** - * Produces a listener for responding to callers of unary RPCs. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {EventEmitter} emitter - * @param {function} callback - * @return {grpc~Listener} - */ -function _getUnaryListener(method_definition, emitter, callback) { - var resultMessage; - return { - onReceiveMetadata: function (metadata) { - emitter.emit('metadata', metadata); - }, - onReceiveMessage: function (message) { - resultMessage = message; - }, - onReceiveStatus: function (status) { - if (status.code !== constants.status.OK) { - var error = common.createStatusError(status); - callback(error); - } else { - callback(null, resultMessage); - } - emitter.emit('status', status); - } - }; -} - -/** - * Produces a listener for responding to callers of client streaming RPCs. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {EventEmitter} emitter - * @param {function} callback - * @return {grpc~Listener} - */ -function _getClientStreamingListener(method_definition, emitter, callback) { - var resultMessage; - return { - onReceiveMetadata: function (metadata) { - emitter.emit('metadata', metadata); - }, - onReceiveMessage: function (message) { - resultMessage = message; - }, - onReceiveStatus: function (status) { - if (status.code !== constants.status.OK) { - var error = common.createStatusError(status); - callback(error); - } else { - callback(null, resultMessage); - } - emitter.emit('status', status); - } - }; -} - -/** - * Produces a listener for responding to callers of server streaming RPCs. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {EventEmitter} emitter - * @return {grpc~Listener} - */ -function _getServerStreamingListener(method_definition, emitter) { - var deserialize = common.wrapIgnoreNull( - method_definition.responseDeserialize); - return { - onReceiveMetadata: function (metadata) { - emitter.emit('metadata', metadata); - }, - onReceiveMessage: function(message, next, context) { - if (emitter.push(message) && message !== null) { - var call = context.call; - var get_listener = function() { - return context.listener; - }; - var read_batch = {}; - read_batch[grpc.opType.RECV_MESSAGE] = true; - call.startBatch(read_batch, _getStreamReadCallback(emitter, call, - get_listener, deserialize)); - } else { - emitter.reading = false; - } - }, - onReceiveStatus: function (status) { - emitter._receiveStatus(status); - } - }; -} - -/** - * Produces a listener for responding to callers of bi-directional RPCs. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {EventEmitter} emitter - * @return {grpc~Listener} - */ -function _getBidiStreamingListener(method_definition, emitter) { - var deserialize = common.wrapIgnoreNull( - method_definition.responseDeserialize); - return { - onReceiveMetadata: function (metadata) { - emitter.emit('metadata', metadata); - }, - onReceiveMessage: function(message, next, context) { - if (emitter.push(message) && message !== null) { - var call = context.call; - var get_listener = function() { - return context.listener; - }; - var read_batch = {}; - read_batch[grpc.opType.RECV_MESSAGE] = true; - call.startBatch(read_batch, _getStreamReadCallback(emitter, call, - get_listener, deserialize)); - } else { - emitter.reading = false; - } - }, - onReceiveStatus: function (status) { - emitter._receiveStatus(status); - } - }; -} - -var interceptorGenerators = { - [methodTypes.UNARY]: _getUnaryInterceptor, - [methodTypes.CLIENT_STREAMING]: _getClientStreamingInterceptor, - [methodTypes.SERVER_STREAMING]: _getServerStreamingInterceptor, - [methodTypes.BIDI_STREAMING]: _getBidiStreamingInterceptor -}; - -var listenerGenerators = { - [methodTypes.UNARY]: _getUnaryListener, - [methodTypes.CLIENT_STREAMING]: _getClientStreamingListener, - [methodTypes.SERVER_STREAMING]: _getServerStreamingListener, - [methodTypes.BIDI_STREAMING]: _getBidiStreamingListener -}; - -/** - * Creates the last listener in an interceptor stack. - * @param {grpc~MethodDefinition} method_definition - * @param {EventEmitter} emitter - * @param {function=} callback - * @return {grpc~Listener} - */ -function getLastListener(method_definition, emitter, callback) { - if (emitter instanceof Function) { - callback = emitter; - callback = function() {}; - } - if (!(callback instanceof Function)) { - callback = function() {}; - } - if (!((emitter instanceof EventEmitter) && - (callback instanceof Function))) { - throw new Error('Argument mismatch in getLastListener'); - } - var method_type = common.getMethodType(method_definition); - var generator = listenerGenerators[method_type]; - return generator(method_definition, emitter, callback); -} - -/** - * - * @param {grpc~MethodDefinition} method_definition - * @param {grpc.Client~CallOptions} options - * @param {Interceptor[]} interceptors - * @param {grpc.Channel} channel - * @param {function|EventEmitter} responder - */ -function getInterceptingCall(method_definition, options, - interceptors, channel, responder) { - var last_interceptor = _getLastInterceptor(method_definition, channel, - responder); - var all_interceptors = interceptors.concat(last_interceptor); - return _buildChain(all_interceptors, options); -} - -/** - * Creates the last interceptor in an interceptor stack. - * @private - * @param {grpc~MethodDefinition} method_definition - * @param {grpc.Channel} channel - * @param {function|EventEmitter} responder - * @return {Interceptor} - */ -function _getLastInterceptor(method_definition, channel, responder) { - var callback = (responder instanceof Function) ? responder : function() {}; - var emitter = (responder instanceof EventEmitter) ? responder : - new EventEmitter(); - var method_type = common.getMethodType(method_definition); - var generator = interceptorGenerators[method_type]; - return generator(method_definition, channel, emitter, callback); -} - -/** - * Chain a list of interceptors together and return the first InterceptingCall. - * @private - * @param {Interceptor[]} interceptors An interceptor stack. - * @param {grpc.Client~CallOptions} options Call options. - * @return {InterceptingCall} - */ -function _buildChain(interceptors, options) { - var next = function(interceptors) { - if (interceptors.length === 0) { - return function (options) {}; - } - var head_interceptor = interceptors[0]; - var rest_interceptors = interceptors.slice(1); - return function (options) { - return head_interceptor(options, next(rest_interceptors)); - }; - }; - var chain = next(interceptors)(options); - return new InterceptingCall(chain); -} - -/** - * Wraps a plain listener object in an InterceptingListener if it isn't an - * InterceptingListener already. - * @param {InterceptingListener|object|null} current_listener - * @param {InterceptingListener|EndListener} next_listener - * @return {InterceptingListener|null} - * @private - */ -function _getInterceptingListener(current_listener, next_listener) { - if (!_isInterceptingListener(current_listener)) { - return new InterceptingListener(next_listener, current_listener); - } - return current_listener; -} - -/** - * Test if the listener exists and is an InterceptingListener. - * @param listener - * @return {boolean} - * @private - */ -function _isInterceptingListener(listener) { - return listener && listener.constructor.name === 'InterceptingListener'; -} - -exports.resolveInterceptorProviders = resolveInterceptorProviders; - -exports.InterceptingCall = InterceptingCall; -exports.ListenerBuilder = ListenerBuilder; -exports.RequesterBuilder = RequesterBuilder; -exports.StatusBuilder = StatusBuilder; - -exports.InterceptorConfigurationError = InterceptorConfigurationError; - -exports.getInterceptingCall = getInterceptingCall; -exports.getLastListener = getLastListener; diff --git a/packages/grpc-native-core/src/common.js b/packages/grpc-native-core/src/common.js deleted file mode 100644 index 2d948335f..000000000 --- a/packages/grpc-native-core/src/common.js +++ /dev/null @@ -1,356 +0,0 @@ -/** - * @license - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var constants = require('./constants'); - -/** - * Wrap a function to pass null-like values through without calling it. If no - * function is given, just uses the identity. - * @private - * @param {?function} func The function to wrap - * @return {function} The wrapped function - */ -exports.wrapIgnoreNull = function wrapIgnoreNull(func) { - if (!func) { - return x => x; - } - return function(arg) { - if (arg === null || arg === undefined) { - return null; - } - return func(arg); - }; -}; - -/** - * The logger object for the gRPC module. Defaults to console. - * @private - */ -exports.logger = console; - -/** - * The current logging verbosity. 0 corresponds to logging everything - * @private - */ -exports.logVerbosity = 0; - -/** - * Log a message if the severity is at least as high as the current verbosity - * @private - * @param {Number} severity A value of the grpc.logVerbosity map - * @param {String} message The message to log - */ -exports.log = function log(severity, message) { - if (severity >= exports.logVerbosity) { - exports.logger.error(message); - } -}; - -/** - * Default options for loading proto files into gRPC - * @alias grpc~defaultLoadOptions - */ -exports.defaultGrpcOptions = { - convertFieldsToCamelCase: false, - binaryAsBase64: false, - longsAsStrings: true, - enumsAsStrings: true, - deprecatedArgumentOrder: false -}; - -/** - * Create an Error object from a status object - * @param {grpc~StatusObject} status The status object - * @return {Error} The resulting Error - */ -exports.createStatusError = function(status) { - let inverted = Object.keys(constants.status) - .reduce((acc, key) => { - acc[constants.status[key]] = key; - return acc; - }, {}); - let statusName = inverted[status.code]; - let message = `${status.code} ${statusName}: ${status.details}`; - let error = new Error(message); - error.code = status.code; - error.metadata = status.metadata; - error.details = status.details; - return error; -}; - -/** - * Get a method's type from its definition - * @param {grpc~MethodDefinition} method_definition - * @return {number} - */ -exports.getMethodType = function(method_definition) { - if (method_definition.requestStream) { - if (method_definition.responseStream) { - return constants.methodTypes.BIDI_STREAMING; - } else { - return constants.methodTypes.CLIENT_STREAMING; - } - } else { - if (method_definition.responseStream) { - return constants.methodTypes.SERVER_STREAMING; - } else { - return constants.methodTypes.UNARY; - } - } -}; - -/** - * Iterate over a collection of items, and run the given handler. - * Return the results as a flattened array of values. - * - * @private - * - * @param {Array} collection Array of items to process - * @param {Function} handler The function to call on each element in the array - * @return {Array} A flattened array of results. - */ -exports.flatMap = function(collection, handler) { - const mapped = collection.map(handler); - return mapped.reduce((acc, curr) => acc.concat(curr), []); -} - -/** - * Given an array of property names and an array of values, - * combine the two into an object map. - * Equivalent to _.zipObject. - * - * @private - * - * @param props {Array} Array of property names - * @param values {Array} Array of property values - * @return {Object} An object with the combined values - */ -exports.zipObject = function(props, values) { - return props.reduce((acc, curr, idx) => { - return Object.assign(acc, { [curr]: values[idx] }); - }, {}); -} - -// JSDoc definitions that are used in multiple other modules - -/** - * Represents the status of a completed request. If `code` is - * {@link grpc.status}.OK, then the request has completed successfully. - * Otherwise, the request has failed, `details` will contain a description of - * the error. Either way, `metadata` contains the trailing response metadata - * sent by the server when it finishes processing the call. - * @typedef {object} grpc~StatusObject - * @property {number} code The error code, a key of {@link grpc.status} - * @property {string} details Human-readable description of the status - * @property {grpc.Metadata} metadata Trailing metadata sent with the status, - * if applicable - */ - -/** - * Describes how a request has failed. The member `message` will be the same as - * `details` in {@link grpc~StatusObject}, and `code` and `metadata` are the - * same as in that object. - * @typedef {Error} grpc~ServiceError - * @property {number} code The error code, a key of {@link grpc.status} that is - * not `grpc.status.OK` - * @property {grpc.Metadata} metadata Trailing metadata sent with the status, - * if applicable - */ - -/** - * The EventEmitter class in the event standard module - * @external EventEmitter - * @see https://nodejs.org/api/events.html#events_class_eventemitter - */ - -/** - * The Readable class in the stream standard module - * @external Readable - * @see https://nodejs.org/api/stream.html#stream_readable_streams - */ - -/** - * The Writable class in the stream standard module - * @external Writable - * @see https://nodejs.org/api/stream.html#stream_writable_streams - */ - -/** - * The Duplex class in the stream standard module - * @external Duplex - * @see https://nodejs.org/api/stream.html#stream_class_stream_duplex - */ - -/** - * A serialization function - * @callback grpc~serialize - * @param {*} value The value to serialize - * @return {Buffer} The value serialized as a byte sequence - */ - -/** - * A deserialization function - * @callback grpc~deserialize - * @param {Buffer} data The byte sequence to deserialize - * @return {*} The data deserialized as a value - */ - -/** - * The deadline of an operation. If it is a date, the deadline is reached at - * the date and time specified. If it is a finite number, it is treated as - * a number of milliseconds since the Unix Epoch. If it is Infinity, the - * deadline will never be reached. If it is -Infinity, the deadline has already - * passed. - * @typedef {(number|Date)} grpc~Deadline - */ - -/** - * An object that completely defines a service method signature. - * @typedef {Object} grpc~MethodDefinition - * @property {string} path The method's URL path - * @property {boolean} requestStream Indicates whether the method accepts - * a stream of requests - * @property {boolean} responseStream Indicates whether the method returns - * a stream of responses - * @property {grpc~serialize} requestSerialize Serialization - * function for request values - * @property {grpc~serialize} responseSerialize Serialization - * function for response values - * @property {grpc~deserialize} requestDeserialize Deserialization - * function for request data - * @property {grpc~deserialize} responseDeserialize Deserialization - * function for repsonse data - */ - -/** - * @function MetadataListener - * @param {grpc.Metadata} metadata The response metadata. - * @param {function} next Passes metadata to the next interceptor. - */ - -/** - * @function MessageListener - * @param {jspb.Message} message The response message. - * @param {function} next Passes a message to the next interceptor. - */ - -/** - * @function StatusListener - * @param {grpc~StatusObject} status The response status. - * @param {function} next Passes a status to the next interceptor. - */ - -/** - * A set of interceptor functions triggered by responses - * @typedef {object} grpc~Listener - * @property {MetadataListener=} onReceiveMetadata A function triggered by - * response metadata. - * @property {MessageListener=} onReceiveMessage A function triggered by a - * response message. - * @property {StatusListener=} onReceiveStatus A function triggered by a - * response status. - */ - -/** - * @function MetadataRequester - * @param {grpc.Metadata} metadata The request metadata. - * @param {grpc~Listener} listener A listener wired to the previous layers - * in the interceptor stack. - * @param {function} next Passes metadata and a listener to the next - * interceptor. - */ - -/** - * @function MessageRequester - * @param {jspb.Message} message The request message. - * @param {function} next Passes a message to the next interceptor. - */ - -/** - * @function CloseRequester - * @param {function} next Calls the next interceptor. - */ - -/** - * @function CancelRequester - * @param {function} next Calls the next interceptor. - */ - -/** - * @function GetPeerRequester - * @param {function} next Calls the next interceptor. - * @return {string} - */ - -/** - * @typedef {object} grpc~Requester - * @param {MetadataRequester=} start A function triggered when the call begins. - * @param {MessageRequester=} sendMessage A function triggered by the request - * message. - * @param {CloseRequester=} halfClose A function triggered when the client - * closes the call. - * @param {CancelRequester=} cancel A function triggered when the call is - * cancelled. - * @param {GetPeerRequester=} getPeer A function triggered when the endpoint is - * requested. - */ - -/** - * An object that completely defines a service. - * @typedef {Object.} grpc~ServiceDefinition - */ - - /** - * An object that defines a protobuf type - * @typedef {object} grpc~ProtobufTypeDefinition - * @param {string} format The format of the type definition object - * @param {*} type The type definition object - * @param {Buffer[]} fileDescriptorProtos Binary protobuf file - * descriptors for all files loaded to construct this type - */ - -/** - * An object that defines a package hierarchy with multiple services - * @typedef {Object.} grpc~PackageDefinition - */ - -/** - * A function for dynamically assigning an interceptor to a call. - * @function InterceptorProvider - * @param {grpc~MethodDefinition} method_definition The method to provide - * an interceptor for. - * @return {Interceptor|null} The interceptor to provide or nothing - */ - -/** - * A function which can modify call options and produce methods to intercept - * RPC operations. - * @function Interceptor - * @param {object} options The grpc call options - * @param {NextCall} nextCall - * @return {InterceptingCall} - */ - -/** - * A function which produces the next InterceptingCall. - * @function NextCall - * @param {object} options The grpc call options - * @return {InterceptingCall|null} - */ diff --git a/packages/grpc-native-core/src/constants.js b/packages/grpc-native-core/src/constants.js deleted file mode 100644 index 0d245fe1b..000000000 --- a/packages/grpc-native-core/src/constants.js +++ /dev/null @@ -1,266 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/* The comments about status codes are copied verbatim (with some formatting - * modifications) from include/grpc/impl/codegen/status.h, for the purpose of - * including them in generated documentation. - */ -/** - * Enum of status codes that gRPC can return - * @memberof grpc - * @alias grpc.status - * @readonly - * @enum {number} - */ -exports.status = { - /** Not an error; returned on success */ - OK: 0, - /** The operation was cancelled (typically by the caller). */ - CANCELLED: 1, - /** - * Unknown error. An example of where this error may be returned is - * if a status value received from another address space belongs to - * an error-space that is not known in this address space. Also - * errors raised by APIs that do not return enough error information - * may be converted to this error. - */ - UNKNOWN: 2, - /** - * Client specified an invalid argument. Note that this differs - * from FAILED_PRECONDITION. INVALID_ARGUMENT indicates arguments - * that are problematic regardless of the state of the system - * (e.g., a malformed file name). - */ - INVALID_ARGUMENT: 3, - /** - * Deadline expired before operation could complete. For operations - * that change the state of the system, this error may be returned - * even if the operation has completed successfully. For example, a - * successful response from a server could have been delayed long - * enough for the deadline to expire. - */ - DEADLINE_EXCEEDED: 4, - /** Some requested entity (e.g., file or directory) was not found. */ - NOT_FOUND: 5, - /** - * Some entity that we attempted to create (e.g., file or directory) - * already exists. - */ - ALREADY_EXISTS: 6, - /** - * The caller does not have permission to execute the specified - * operation. PERMISSION_DENIED must not be used for rejections - * caused by exhausting some resource (use RESOURCE_EXHAUSTED - * instead for those errors). PERMISSION_DENIED must not be - * used if the caller can not be identified (use UNAUTHENTICATED - * instead for those errors). - */ - PERMISSION_DENIED: 7, - /** - * Some resource has been exhausted, perhaps a per-user quota, or - * perhaps the entire file system is out of space. - */ - RESOURCE_EXHAUSTED: 8, - /** - * Operation was rejected because the system is not in a state - * required for the operation's execution. For example, directory - * to be deleted may be non-empty, an rmdir operation is applied to - * a non-directory, etc. - * - * A litmus test that may help a service implementor in deciding - * between FAILED_PRECONDITION, ABORTED, and UNAVAILABLE: - * - * - Use UNAVAILABLE if the client can retry just the failing call. - * - Use ABORTED if the client should retry at a higher-level - * (e.g., restarting a read-modify-write sequence). - * - Use FAILED_PRECONDITION if the client should not retry until - * the system state has been explicitly fixed. E.g., if an "rmdir" - * fails because the directory is non-empty, FAILED_PRECONDITION - * should be returned since the client should not retry unless - * they have first fixed up the directory by deleting files from it. - * - Use FAILED_PRECONDITION if the client performs conditional - * REST Get/Update/Delete on a resource and the resource on the - * server does not match the condition. E.g., conflicting - * read-modify-write on the same resource. - */ - FAILED_PRECONDITION: 9, - /** - * The operation was aborted, typically due to a concurrency issue - * like sequencer check failures, transaction aborts, etc. - * - * See litmus test above for deciding between FAILED_PRECONDITION, - * ABORTED, and UNAVAILABLE. - */ - ABORTED: 10, - /** - * Operation was attempted past the valid range. E.g., seeking or - * reading past end of file. - * - * Unlike INVALID_ARGUMENT, this error indicates a problem that may - * be fixed if the system state changes. For example, a 32-bit file - * system will generate INVALID_ARGUMENT if asked to read at an - * offset that is not in the range [0,2^32-1], but it will generate - * OUT_OF_RANGE if asked to read from an offset past the current - * file size. - * - * There is a fair bit of overlap between FAILED_PRECONDITION and - * OUT_OF_RANGE. We recommend using OUT_OF_RANGE (the more specific - * error) when it applies so that callers who are iterating through - * a space can easily look for an OUT_OF_RANGE error to detect when - * they are done. - */ - OUT_OF_RANGE: 11, - /** Operation is not implemented or not supported/enabled in this service. */ - UNIMPLEMENTED: 12, - /** - * Internal errors. Means some invariants expected by underlying - * system has been broken. If you see one of these errors, - * something is very broken. - */ - INTERNAL: 13, - /** - * The service is currently unavailable. This is a most likely a - * transient condition and may be corrected by retrying with - * a backoff. - * - * See litmus test above for deciding between FAILED_PRECONDITION, - * ABORTED, and UNAVAILABLE. - */ - UNAVAILABLE: 14, - /** Unrecoverable data loss or corruption. */ - DATA_LOSS: 15, - /** - * The request does not have valid authentication credentials for the - * operation. - */ - UNAUTHENTICATED: 16 -}; - -/* The comments about propagation bit flags are copied from - * include/grpc/impl/codegen/propagation_bits.h for the purpose of including - * them in generated documentation. - */ -/** - * Propagation flags: these can be bitwise or-ed to form the propagation option - * for calls. - * - * Users are encouraged to write propagation masks as deltas from the default. - * i.e. write `grpc.propagate.DEFAULTS & ~grpc.propagate.DEADLINE` to disable - * deadline propagation. - * @memberof grpc - * @alias grpc.propagate - * @enum {number} - */ -exports.propagate = { - DEADLINE: 1, - CENSUS_STATS_CONTEXT: 2, - CENSUS_TRACING_CONTEXT: 4, - CANCELLATION: 8, - DEFAULTS: 65535 -}; - -/* Many of the following comments are copied from - * include/grpc/impl/codegen/grpc_types.h - */ -/** - * Call error constants. Call errors almost always indicate bugs in the gRPC - * library, and these error codes are mainly useful for finding those bugs. - * @memberof grpc - * @readonly - * @enum {number} - */ -const callError = { - OK: 0, - ERROR: 1, - NOT_ON_SERVER: 2, - NOT_ON_CLIENT: 3, - ALREADY_INVOKED: 5, - NOT_INVOKED: 6, - ALREADY_FINISHED: 7, - TOO_MANY_OPERATIONS: 8, - INVALID_FLAGS: 9, - INVALID_METADATA: 10, - INVALID_MESSAGE: 11, - NOT_SERVER_COMPLETION_QUEUE: 12, - BATCH_TOO_BIG: 13, - PAYLOAD_TYPE_MISMATCH: 14 -}; - -exports.callError = callError; - -/** - * Write flags: these can be bitwise or-ed to form write options that modify - * how data is written. - * @memberof grpc - * @alias grpc.writeFlags - * @readonly - * @enum {number} - */ -exports.writeFlags = { - /** - * Hint that the write may be buffered and need not go out on the wire - * immediately. GRPC is free to buffer the message until the next non-buffered - * write, or until writes_done, but it need not buffer completely or at all. - */ - BUFFER_HINT: 1, - /** - * Force compression to be disabled for a particular write - */ - NO_COMPRESS: 2 -}; - -/** - * @memberof grpc - * @alias grpc.logVerbosity - * @readonly - * @enum {number} - */ -exports.logVerbosity = { - DEBUG: 0, - INFO: 1, - ERROR: 2 -}; - -/** - * Method types: the supported RPC types - * @memberof grpc - * @alias grpc.methodTypes - * @readonly - * @enum {number} - */ -exports.methodTypes = { - UNARY: 0, - CLIENT_STREAMING: 1, - SERVER_STREAMING: 2, - BIDI_STREAMING: 3 -}; - -/** - * Connectivity state values - * @memberof grpc - * @alias grpc.connectivityState - * @readonly - * @enum {number} - */ -exports.connectivityState = { - IDLE: 0, - CONNECTING: 1, - READY: 2, - TRANSIENT_FAILURE: 3, - SHUTDOWN: 4 -}; diff --git a/packages/grpc-native-core/src/credentials.js b/packages/grpc-native-core/src/credentials.js deleted file mode 100644 index 21523f0b1..000000000 --- a/packages/grpc-native-core/src/credentials.js +++ /dev/null @@ -1,278 +0,0 @@ -/** - * @license - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * Credentials module - * - * This module contains factory methods for two different credential types: - * CallCredentials and ChannelCredentials. ChannelCredentials are things like - * SSL credentials that can be used to secure a connection, and are used to - * construct a Client object. CallCredentials genrally modify metadata, so they - * can be attached to an individual method call. - * - * CallCredentials can be composed with other CallCredentials to create - * CallCredentials. ChannelCredentials can be composed with CallCredentials - * to create ChannelCredentials. No combined credential can have more than - * one ChannelCredentials. - * - * For example, to create a client secured with SSL that uses Google - * default application credentials to authenticate: - * - * @example - * var channel_creds = credentials.createSsl(root_certs); - * (new GoogleAuth()).getApplicationDefault(function(err, credential) { - * var call_creds = credentials.createFromGoogleCredential(credential); - * var combined_creds = credentials.combineChannelCredentials( - * channel_creds, call_creds); - * var client = new Client(address, combined_creds); - * }); - * - * @namespace grpc.credentials - */ - -'use strict'; - -var grpc = require('./grpc_extension'); - -/** - * This cannot be constructed directly. Instead, instances of this class should - * be created using the factory functions in {@link grpc.credentials} - * @constructor grpc.credentials~CallCredentials - */ -var CallCredentials = grpc.CallCredentials; - -/** - * This cannot be constructed directly. Instead, instances of this class should - * be created using the factory functions in {@link grpc.credentials} - * @constructor grpc.credentials~ChannelCredentials - */ -var ChannelCredentials = grpc.ChannelCredentials; - -var Metadata = require('./metadata.js'); - -var common = require('./common.js'); - -var constants = require('./constants'); - -/** - * @external GoogleCredential - * @see https://github.com/google/google-auth-library-nodejs - */ - -const PEM_CERT_HEADER = "-----BEGIN CERTIFICATE-----"; -const PEM_CERT_FOOTER = "-----END CERTIFICATE-----"; - -function wrapCheckServerIdentityCallback(callback) { - return function(hostname, cert) { - // Parse cert from pem to a version that matches the tls.checkServerIdentity - // format. - // https://nodejs.org/api/tls.html#tls_tls_checkserveridentity_hostname_cert - - var pemHeaderIndex = cert.indexOf(PEM_CERT_HEADER); - if (pemHeaderIndex === -1) { - return new Error("Unable to parse certificate PEM."); - } - cert = cert.substring(pemHeaderIndex); - var pemFooterIndex = cert.indexOf(PEM_CERT_FOOTER); - if (pemFooterIndex === -1) { - return new Error("Unable to parse certificate PEM."); - } - cert = cert.substring(PEM_CERT_HEADER.length, pemFooterIndex); - var rawBuffer = Buffer.from(cert.replace("\n", "").replace(" ", ""), "base64"); - - return callback(hostname, { raw: rawBuffer }); - } -} - -/** - * Create an SSL Credentials object. If using a client-side certificate, both - * the second and third arguments must be passed. Additional peer verification - * options can be passed in the fourth argument as described below. - * @memberof grpc.credentials - * @alias grpc.credentials.createSsl - * @kind function - * @param {Buffer=} root_certs The root certificate data - * @param {Buffer=} private_key The client certificate private key, if - * applicable - * @param {Buffer=} cert_chain The client certificate cert chain, if applicable - * @param {Function} verify_options.checkServerIdentity Optional callback - * receiving the expected hostname and peer certificate for additional - * verification. The callback should return an Error if verification - * fails and otherwise return undefined. - * @return {grpc.credentials~ChannelCredentials} The SSL Credentials object - */ -exports.createSsl = function(root_certs, private_key, cert_chain, verify_options) { - // The checkServerIdentity callback from gRPC core will receive the cert as a PEM. - // To better match the checkServerIdentity callback of Node, we wrap the callback - // to decode the PEM and populate a cert object. - if (verify_options && verify_options.checkServerIdentity) { - if (typeof verify_options.checkServerIdentity !== 'function') { - throw new TypeError("Value of checkServerIdentity must be a function."); - } - // Make a shallow clone of verify_options so our modification of the callback - // isn't reflected to the caller - var updated_verify_options = Object.assign({}, verify_options); - updated_verify_options.checkServerIdentity = wrapCheckServerIdentityCallback( - verify_options.checkServerIdentity); - arguments[3] = updated_verify_options; - } - return ChannelCredentials.createSsl.apply(this, arguments); -} - - -/** - * @callback grpc.credentials~metadataCallback - * @param {Error} error The error, if getting metadata failed - * @param {grpc.Metadata} metadata The metadata - */ - -/** - * @callback grpc.credentials~generateMetadata - * @param {Object} params Parameters that can modify metadata generation - * @param {string} params.service_url The URL of the service that the call is - * going to - * @param {grpc.credentials~metadataCallback} callback - */ - -/** - * Create a gRPC credentials object from a metadata generation function. This - * function gets the service URL and a callback as parameters. The error - * passed to the callback can optionally have a 'code' value attached to it, - * which corresponds to a status code that this library uses. - * @memberof grpc.credentials - * @alias grpc.credentials.createFromMetadataGenerator - * @param {grpc.credentials~generateMetadata} metadata_generator The function - * that generates metadata - * @return {grpc.credentials~CallCredentials} The credentials object - */ -exports.createFromMetadataGenerator = function(metadata_generator) { - return CallCredentials.createFromPlugin(function(service_url, cb_data, - callback) { - metadata_generator({service_url: service_url}, function(error, metadata) { - var code = constants.status.OK; - var message = ''; - if (error) { - message = error.message; - if (error.hasOwnProperty('code') && Number.isFinite(error.code)) { - code = error.code; - } else { - code = constants.status.UNAUTHENTICATED; - } - if (!metadata) { - metadata = new Metadata(); - } - } - callback(code, message, metadata._getCoreRepresentation(), cb_data); - }); - }); -}; - -function getHeadersFromGoogleCredential(google_credential, url, callback) { - // google-auth-library pre-v2.0.0 does not have getRequestHeaders - // but has getRequestMetadata, which is deprecated in v2.0.0 - if (typeof google_credential.getRequestHeaders === 'function') { - google_credential.getRequestHeaders(url) - .then(function(headers) { - callback(null, headers); - }) - .catch(function(err) { - callback(err); - return; - }); - } else { - google_credential.getRequestMetadata(url, function(err, headers) { - if (err) { - callback(err); - return; - } - callback(null, headers); - }); - } -} - -/** - * Create a gRPC credential from a Google credential object. - * @memberof grpc.credentials - * @alias grpc.credentials.createFromGoogleCredential - * @param {external:GoogleCredential} google_credential The Google credential - * object to use - * @return {grpc.credentials~CallCredentials} The resulting credentials object - */ -exports.createFromGoogleCredential = function(google_credential) { - return exports.createFromMetadataGenerator(function(auth_context, callback) { - var service_url = auth_context.service_url; - getHeadersFromGoogleCredential(google_credential, service_url, - function(err, headers) { - if (err) { - common.log(constants.logVerbosity.INFO, 'Auth error:' + err); - callback(err); - return; - } - var metadata = new Metadata(); - for (const key of Object.keys(headers)) { - metadata.add(key, headers[key]); - } - callback(null, metadata); - }); - }); -}; - -/** - * Combine a ChannelCredentials with any number of CallCredentials into a single - * ChannelCredentials object. - * @memberof grpc.credentials - * @alias grpc.credentials.combineChannelCredentials - * @param {grpc.credentials~ChannelCredentials} channel_credential The ChannelCredentials to - * start with - * @param {...grpc.credentials~CallCredentials} credentials The CallCredentials to compose - * @return {grpc.credentials~ChannelCredentials} A credentials object that combines all of the - * input credentials - */ -exports.combineChannelCredentials = function(channel_credential) { - var current = channel_credential; - for (var i = 1; i < arguments.length; i++) { - current = current.compose(arguments[i]); - } - return current; -}; - -/** - * Combine any number of CallCredentials into a single CallCredentials object - * @memberof grpc.credentials - * @alias grpc.credentials.combineCallCredentials - * @param {...grpc.credentials~CallCredentials} credentials The CallCredentials to compose - * @return {grpc.credentials~CallCredentials} A credentials object that combines all of the input - * credentials - */ -exports.combineCallCredentials = function() { - var current = arguments[0]; - for (var i = 1; i < arguments.length; i++) { - current = current.compose(arguments[i]); - } - return current; -}; - -/** - * Create an insecure credentials object. This is used to create a channel that - * does not use SSL. This cannot be composed with anything. - * @memberof grpc.credentials - * @alias grpc.credentials.createInsecure - * @kind function - * @return {grpc.credentials~ChannelCredentials} The insecure credentials object - */ -exports.createInsecure = ChannelCredentials.createInsecure; diff --git a/packages/grpc-native-core/src/grpc_extension.js b/packages/grpc-native-core/src/grpc_extension.js deleted file mode 100644 index 41ce389bb..000000000 --- a/packages/grpc-native-core/src/grpc_extension.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * @license - * Copyright 2016 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * @module - * @private - */ - -'use strict'; - -var binary = require('node-pre-gyp/lib/pre-binding'); -var path = require('path'); -var binding_path = - binary.find(path.resolve(path.join(__dirname, '../package.json'))); -var binding; -try { - binding = require(binding_path); -} catch (e) { - let fs = require('fs'); - let searchPath = path.dirname(path.dirname(binding_path)); - let searchName = path.basename(path.dirname(binding_path)); - let foundNames; - try { - foundNames = fs.readdirSync(searchPath); - } catch (readDirError) { - let message = `The gRPC binary module was not installed. This may be fixed by running "npm rebuild" -Original error: ${e.message}`; - let error = new Error(message); - error.code = e.code; - throw error; - } - if (foundNames.indexOf(searchName) === -1) { - let message = `Failed to load gRPC binary module because it was not installed for the current system -Expected directory: ${searchName} -Found: [${foundNames.join(', ')}] -This problem can often be fixed by running "npm rebuild" on the current system -Original error: ${e.message}`; - let error = new Error(message); - error.code = e.code; - throw error; - } else { - e.message = `Failed to load ${binding_path}. ${e.message}`; - throw e; - } -} - -module.exports = binding; diff --git a/packages/grpc-native-core/src/metadata.js b/packages/grpc-native-core/src/metadata.js deleted file mode 100644 index c5b988fb5..000000000 --- a/packages/grpc-native-core/src/metadata.js +++ /dev/null @@ -1,250 +0,0 @@ -/** - * @license - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var clone = require('lodash.clone'); - -var grpc = require('./grpc_extension'); - -const common = require('./common'); -const logVerbosity = require('./constants').logVerbosity; - -const IDEMPOTENT_REQUEST_FLAG = 0x10; -const WAIT_FOR_READY_FLAG = 0x20; -const CACHEABLE_REQUEST_FLAG = 0x40; -const WAIT_FOR_READY_EXPLICITLY_SET_FLAG = 0x80; -const CORKED_FLAG = 0x100; - -/** - * Class for storing metadata. Keys are normalized to lowercase ASCII. - * @memberof grpc - * @constructor - * @param {Object=} options Boolean options for the beginning of the call. - * These options only have any effect when passed at the beginning of - * a client request. - * @param {boolean=} [options.idempotentRequest=false] Signal that the request - * is idempotent - * @param {boolean=} [options.waitForReady=false] Signal that the call should - * not return UNAVAILABLE before it has started. - * @param {boolean=} [options.cacheableRequest=false] Signal that the call is - * cacheable. GRPC is free to use GET verb. - * @param {boolean=} [options.corked=false] Signal that the initial metadata - * should be corked. - * @example - * var metadata = new metadata_module.Metadata(); - * metadata.set('key1', 'value1'); - * metadata.add('key1', 'value2'); - * metadata.get('key1') // returns ['value1', 'value2'] - */ -function Metadata(options) { - this._internal_repr = {}; - this.setOptions(options); -} - -function normalizeKey(key) { - key = key.toLowerCase(); - if (grpc.metadataKeyIsLegal(key)) { - return key; - } else { - throw new Error('Metadata key"' + key + '" contains illegal characters'); - } -} - -function validate(key, value) { - if (grpc.metadataKeyIsBinary(key)) { - if (!(value instanceof Buffer)) { - throw new Error('keys that end with \'-bin\' must have Buffer values'); - } - } else { - if (typeof value !== 'string') { - throw new Error( - 'keys that don\'t end with \'-bin\' must have String values'); - } - if (!grpc.metadataNonbinValueIsLegal(value)) { - throw new Error('Metadata string value "' + value + - '" contains illegal characters'); - } - } -} - -/** - * Sets the given value for the given key, replacing any other values associated - * with that key. Normalizes the key. - * @param {String} key The key to set - * @param {String|Buffer} value The value to set. Must be a buffer if and only - * if the normalized key ends with '-bin' - */ -Metadata.prototype.set = function(key, value) { - key = normalizeKey(key); - validate(key, value); - this._internal_repr[key] = [value]; -}; - -/** - * Adds the given value for the given key. Normalizes the key. - * @param {String} key The key to add to. - * @param {String|Buffer} value The value to add. Must be a buffer if and only - * if the normalized key ends with '-bin' - */ -Metadata.prototype.add = function(key, value) { - key = normalizeKey(key); - validate(key, value); - if (!this._internal_repr[key]) { - this._internal_repr[key] = []; - } - this._internal_repr[key].push(value); -}; - -/** - * Remove the given key and any associated values. Normalizes the key. - * @param {String} key The key to remove - */ -Metadata.prototype.remove = function(key) { - key = normalizeKey(key); - if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) { - delete this._internal_repr[key]; - } -}; - -/** - * Gets a list of all values associated with the key. Normalizes the key. - * @param {String} key The key to get - * @return {Array.} The values associated with that key - */ -Metadata.prototype.get = function(key) { - key = normalizeKey(key); - if (Object.prototype.hasOwnProperty.call(this._internal_repr, key)) { - return this._internal_repr[key]; - } else { - return []; - } -}; - -/** - * Get a map of each key to a single associated value. This reflects the most - * common way that people will want to see metadata. - * @return {Object.} A key/value mapping of the metadata - */ -Metadata.prototype.getMap = function() { - var result = {}; - Object.keys(this._internal_repr).forEach(key => { - const values = this._internal_repr[key]; - if(values.length > 0) { - result[key] = values[0]; - } - }); - return result; -}; - -/** - * Clone the metadata object. - * @return {grpc.Metadata} The new cloned object - */ -Metadata.prototype.clone = function() { - var copy = new Metadata(); - Object.keys(this._internal_repr).forEach(key => { - const value = this._internal_repr[key]; - copy._internal_repr[key] = clone(value); - }); - copy.flags = this.flags; - return copy; -}; - -/** - * Set options on the metadata object - * @param {Object} options Boolean options for the beginning of the call. - * These options only have any effect when passed at the beginning of - * a client request. - * @param {boolean=} [options.idempotentRequest=false] Signal that the request - * is idempotent - * @param {boolean=} [options.waitForReady=false] Signal that the call should - * not return UNAVAILABLE before it has started. - * @param {boolean=} [options.cacheableRequest=false] Signal that the call is - * cacheable. GRPC is free to use GET verb. - * @param {boolean=} [options.corked=false] Signal that the initial metadata - * should be corked. - */ -Metadata.prototype.setOptions = function(options) { - let flags = 0; - if (options) { - if (options.idempotentRequest) { - flags |= IDEMPOTENT_REQUEST_FLAG; - } - if (options.hasOwnProperty('waitForReady')) { - flags |= WAIT_FOR_READY_EXPLICITLY_SET_FLAG; - if (options.waitForReady) { - flags |= WAIT_FOR_READY_FLAG; - } - } - if (options.cacheableRequest) { - flags |= CACHEABLE_REQUEST_FLAG; - } - if (options.corked) { - flags |= CORKED_FLAG; - } - } - this.flags = flags; -} - -/** - * Metadata representation as passed to and the native addon - * @typedef {object} grpc~CoreMetadata - * @param {Object.>} metadata The metadata - * @param {number} flags Metadata flags - */ - -/** - * Gets the metadata in the format used by interal code. Intended for internal - * use only. API stability is not guaranteed. - * @private - * @return {grpc~CoreMetadata} The metadata - */ -Metadata.prototype._getCoreRepresentation = function() { - return { - metadata: this._internal_repr, - flags: this.flags - }; -}; - -/** - * Creates a Metadata object from a metadata map in the internal format. - * Intended for internal use only. API stability is not guaranteed. - * @private - * @param {grpc~CoreMetadata} metadata The metadata object from core - * @return {Metadata} The new Metadata object - */ -Metadata._fromCoreRepresentation = function(metadata) { - var newMetadata = new Metadata(); - if (metadata) { - Object.keys(metadata.metadata).forEach(key => { - const value = metadata.metadata[key]; - if (!grpc.metadataKeyIsLegal(key)) { - common.log(logVerbosity.ERROR, - "Warning: possibly corrupted metadata key received: " + - key + ": " + value + - ". Please report this at https://github.com/grpc/grpc-node/issues/1173."); - } - newMetadata._internal_repr[key] = clone(value); - }); - } - newMetadata.flags = metadata.flags; - return newMetadata; -}; - -module.exports = Metadata; diff --git a/packages/grpc-native-core/src/protobuf_js_5_common.js b/packages/grpc-native-core/src/protobuf_js_5_common.js deleted file mode 100644 index d9c26e26d..000000000 --- a/packages/grpc-native-core/src/protobuf_js_5_common.js +++ /dev/null @@ -1,173 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * @module - * @private - */ - -'use strict'; - -var camelCase = require('lodash.camelcase'); -var client = require('./client'); -var common = require('./common'); - -/** - * Get a function that deserializes a specific type of protobuf. - * @param {function()} cls The constructor of the message type to deserialize - * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings - * instead of Buffers. Defaults to false - * @param {bool=} longsAsStrings Deserialize long values as strings instead of - * objects. Defaults to true - * @return {function(Buffer):cls} The deserialization function - */ -exports.deserializeCls = function deserializeCls(cls, options) { - /** - * Deserialize a buffer to a message object - * @param {Buffer} arg_buf The buffer to deserialize - * @return {cls} The resulting object - */ - return function deserialize(arg_buf) { - // Convert to a native object with binary fields as Buffers (first argument) - // and longs as strings (second argument) - return cls.decode(arg_buf).toRaw(options.binaryAsBase64, - options.longsAsStrings); - }; -}; - -var deserializeCls = exports.deserializeCls; - -/** - * Get a function that serializes objects to a buffer by protobuf class. - * @param {function()} Cls The constructor of the message type to serialize - * @return {function(Cls):Buffer} The serialization function - */ -exports.serializeCls = function serializeCls(Cls) { - /** - * Serialize an object to a Buffer - * @param {Object} arg The object to serialize - * @return {Buffer} The serialized object - */ - return function serialize(arg) { - return Buffer.from(new Cls(arg).encode().toBuffer()); - }; -}; - -var serializeCls = exports.serializeCls; - -/** - * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. - * @param {ProtoBuf.Reflect.Namespace} value The value to get the name of - * @return {string} The fully qualified name of the value - */ -exports.fullyQualifiedName = function fullyQualifiedName(value) { - if (value === null || value === undefined) { - return ''; - } - var name = value.name; - var parent_name = fullyQualifiedName(value.parent); - if (parent_name !== '') { - name = parent_name + '.' + name; - } - return name; -}; - -var fullyQualifiedName = exports.fullyQualifiedName; - -/** - * Return a map from method names to method attributes for the service. - * @param {ProtoBuf.Reflect.Service} service The service to get attributes for - * @param {Object=} options Options to apply to these attributes - * @return {Object} The attributes map - */ -exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, - options) { - var prefix = '/' + fullyQualifiedName(service) + '/'; - var binaryAsBase64, longsAsStrings; - if (options) { - binaryAsBase64 = options.binaryAsBase64; - longsAsStrings = options.longsAsStrings; - } - /* This slightly awkward construction is used to make sure we only use - lodash@3.10.1-compatible functions. A previous version used - _.fromPairs, which would be cleaner, but was introduced in lodash - version 4 */ - return common.zipObject(service.children.map(function(method) { - return camelCase(method.name); - }), service.children.map(function(method) { - return { - originalName: method.name, - path: prefix + method.name, - requestStream: method.requestStream, - responseStream: method.responseStream, - requestType: method.resolvedRequestType, - responseType: method.resolvedResponseType, - requestSerialize: serializeCls(method.resolvedRequestType.build()), - requestDeserialize: deserializeCls(method.resolvedRequestType.build(), - options), - responseSerialize: serializeCls(method.resolvedResponseType.build()), - responseDeserialize: deserializeCls(method.resolvedResponseType.build(), - options) - }; - })); -}; - -var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; - -/** - * Load a gRPC object from an existing ProtoBuf.Reflect object. - * @param {ProtoBuf.Reflect.Namespace} value The ProtoBuf object to load. - * @param {Object=} options Options to apply to the loaded object - * @return {Object} The resulting gRPC object - */ -exports.loadObject = function loadObject(value, options) { - var result = {}; - if (!value) { - return value; - } - if (value.hasOwnProperty('ns')) { - return loadObject(value.ns, options); - } - if (value.className === 'Namespace') { - Object.keys(value.children).forEach(key => { - const child = value.children[key]; - result[child.name] = loadObject(child, options); - }); - return result; - } else if (value.className === 'Service') { - return client.makeClientConstructor(getProtobufServiceAttrs(value, options), - options); - } else if (value.className === 'Message' || value.className === 'Enum') { - return value.build(); - } else { - return value; - } -}; - -/** - * The primary purpose of this method is to distinguish between reflection - * objects from different versions of ProtoBuf.js. This is just a heuristic, - * checking for properties that are (currently) specific to this version of - * ProtoBuf.js - * @param {Object} obj The object to check - * @return {boolean} Whether the object appears to be a Protobuf.js 5 - * ReflectionObject - */ -exports.isProbablyProtobufJs5 = function isProbablyProtobufJs5(obj) { - return Array.isArray(obj.children) && (typeof obj.build === 'function'); -}; diff --git a/packages/grpc-native-core/src/protobuf_js_6_common.js b/packages/grpc-native-core/src/protobuf_js_6_common.js deleted file mode 100644 index 66cebd617..000000000 --- a/packages/grpc-native-core/src/protobuf_js_6_common.js +++ /dev/null @@ -1,164 +0,0 @@ -/** - * @license - * Copyright 2017 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -/** - * @module - * @private - */ - -'use strict'; - -var camelCase = require('lodash.camelcase'); -var client = require('./client'); -var common = require('./common'); - -/** - * Get a function that deserializes a specific type of protobuf. - * @param {function()} cls The constructor of the message type to deserialize - * @param {bool=} binaryAsBase64 Deserialize bytes fields as base64 strings - * instead of Buffers. Defaults to false - * @param {bool=} longsAsStrings Deserialize long values as strings instead of - * objects. Defaults to true - * @return {function(Buffer):cls} The deserialization function - */ -exports.deserializeCls = function deserializeCls(cls, options) { - var conversion_options = { - defaults: true, - bytes: options.binaryAsBase64 ? String : Buffer, - longs: options.longsAsStrings ? String : null, - enums: options.enumsAsStrings ? String : null, - oneofs: true - }; - /** - * Deserialize a buffer to a message object - * @param {Buffer} arg_buf The buffer to deserialize - * @return {cls} The resulting object - */ - return function deserialize(arg_buf) { - return cls.toObject(cls.decode(arg_buf), conversion_options); - }; -}; - -var deserializeCls = exports.deserializeCls; - -/** - * Get a function that serializes objects to a buffer by protobuf class. - * @param {function()} Cls The constructor of the message type to serialize - * @return {function(Cls):Buffer} The serialization function - */ -exports.serializeCls = function serializeCls(cls) { - /** - * Serialize an object to a Buffer - * @param {Object} arg The object to serialize - * @return {Buffer} The serialized object - */ - return function serialize(arg) { - var message = cls.fromObject(arg); - return cls.encode(message).finish(); - }; -}; - -var serializeCls = exports.serializeCls; - -/** - * Get the fully qualified (dotted) name of a ProtoBuf.Reflect value. - * @param {ProtoBuf.ReflectionObject} value The value to get the name of - * @return {string} The fully qualified name of the value - */ -exports.fullyQualifiedName = function fullyQualifiedName(value) { - if (value === null || value === undefined) { - return ''; - } - var name = value.name; - var parent_fqn = fullyQualifiedName(value.parent); - if (parent_fqn !== '') { - name = parent_fqn + '.' + name; - } - return name; -}; - -var fullyQualifiedName = exports.fullyQualifiedName; - -/** - * Return a map from method names to method attributes for the service. - * @param {ProtoBuf.Service} service The service to get attributes for - * @param {Object=} options Options to apply to these attributes - * @return {Object} The attributes map - */ -exports.getProtobufServiceAttrs = function getProtobufServiceAttrs(service, - options) { - var prefix = '/' + fullyQualifiedName(service) + '/'; - service.resolveAll(); - return common.zipObject(service.methodsArray.map(function(method) { - return camelCase(method.name); - }), service.methodsArray.map(function(method) { - return { - originalName: method.name, - path: prefix + method.name, - requestStream: !!method.requestStream, - responseStream: !!method.responseStream, - requestType: method.resolvedRequestType, - responseType: method.resolvedResponseType, - requestSerialize: serializeCls(method.resolvedRequestType), - requestDeserialize: deserializeCls(method.resolvedRequestType, options), - responseSerialize: serializeCls(method.resolvedResponseType), - responseDeserialize: deserializeCls(method.resolvedResponseType, options) - }; - })); -}; - -var getProtobufServiceAttrs = exports.getProtobufServiceAttrs; - -exports.loadObject = function loadObject(value, options) { - var result = {}; - if (!value) { - return value; - } - if (value.hasOwnProperty('methods')) { - // It's a service object - var service_attrs = getProtobufServiceAttrs(value, options); - return client.makeClientConstructor(service_attrs); - } - - if (value.hasOwnProperty('nested')) { - // It's a namespace or root object - if (value.nested !== null && value.nested !== undefined) { - var values = Object.keys(value.nested).map(key => value.nested[key]); - values.forEach(nested => { - result[nested.name] = loadObject(nested, options); - }); - } - return result; - } - - // Otherwise, it's not something we need to change - return value; -}; - -/** - * The primary purpose of this method is to distinguish between reflection - * objects from different versions of ProtoBuf.js. This is just a heuristic, - * checking for properties that are (currently) specific to this version of - * ProtoBuf.js - * @param {Object} obj The object to check - * @return {boolean} Whether the object appears to be a Protobuf.js 6 - * ReflectionObject - */ -exports.isProbablyProtobufJs6 = function isProbablyProtobufJs6(obj) { - return (typeof obj.root === 'object') && (typeof obj.resolve === 'function'); -}; diff --git a/packages/grpc-native-core/src/server.js b/packages/grpc-native-core/src/server.js deleted file mode 100644 index d72de018e..000000000 --- a/packages/grpc-native-core/src/server.js +++ /dev/null @@ -1,1010 +0,0 @@ -/** - * @license - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var grpc = require('./grpc_extension'); - -var common = require('./common'); - -var Metadata = require('./metadata'); - -var constants = require('./constants'); - -var stream = require('stream'); - -var Readable = stream.Readable; -var Writable = stream.Writable; -var Duplex = stream.Duplex; -var util = require('util'); - -var EventEmitter = require('events').EventEmitter; - -/** - * Handle an error on a call by sending it as a status - * @private - * @param {grpc.internal~Call} call The call to send the error on - * @param {(Object|Error)} error The error object - */ -function handleError(call, error) { - var statusMetadata = new Metadata(); - var status = { - code: constants.status.UNKNOWN, - details: 'Unknown Error' - }; - if (error.hasOwnProperty('message')) { - status.details = error.message; - } - if (error.hasOwnProperty('code') && Number.isInteger(error.code)) { - status.code = error.code; - if (error.hasOwnProperty('details')) { - status.details = error.details; - } - if (status.code == constants.status.INTERNAL) { - common.log(constants.logVerbosity.ERROR, error); - } - } - if (error.hasOwnProperty('metadata')) { - statusMetadata = error.metadata; - } - status.metadata = statusMetadata._getCoreRepresentation(); - var error_batch = {}; - if (!call.metadataSent) { - error_batch[grpc.opType.SEND_INITIAL_METADATA] = - (new Metadata())._getCoreRepresentation(); - } - error_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; - call.startBatch(error_batch, function(){}); -} - -/** - * Send a response to a unary or client streaming call. - * @private - * @param {grpc.Call} call The call to respond on - * @param {*} value The value to respond with - * @param {grpc~serialize} serialize Serialization function for the - * response - * @param {grpc.Metadata=} metadata Optional trailing metadata to send with - * status - * @param {number=} [flags=0] Flags for modifying how the message is sent. - */ -function sendUnaryResponse(call, value, serialize, metadata, flags) { - var end_batch = {}; - var statusMetadata = new Metadata(); - var status = { - code: constants.status.OK, - details: 'OK' - }; - if (metadata) { - statusMetadata = metadata; - } - var message; - try { - message = serialize(value); - } catch (e) { - e.code = constants.status.INTERNAL; - handleError(call, e); - return; - } - status.metadata = statusMetadata._getCoreRepresentation(); - if (!call.metadataSent) { - end_batch[grpc.opType.SEND_INITIAL_METADATA] = - (new Metadata())._getCoreRepresentation(); - call.metadataSent = true; - } - message.grpcWriteFlags = flags; - end_batch[grpc.opType.SEND_MESSAGE] = message; - end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = status; - call.startBatch(end_batch, function (){}); -} - -/** - * Initialize a writable stream. This is used for both the writable and duplex - * stream constructors. - * @private - * @param {Writable} stream The stream to set up - * @param {function(*):Buffer=} Serialization function for responses - */ -function setUpWritable(stream, serialize) { - stream.finished = false; - stream.status = { - code : constants.status.OK, - details : 'OK', - metadata : new Metadata() - }; - stream.serialize = common.wrapIgnoreNull(serialize); - function sendStatus() { - var batch = {}; - if (!stream.call.metadataSent) { - stream.call.metadataSent = true; - batch[grpc.opType.SEND_INITIAL_METADATA] = - (new Metadata())._getCoreRepresentation(); - } - - if (stream.status.metadata) { - stream.status.metadata = stream.status.metadata._getCoreRepresentation(); - } - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = stream.status; - stream.call.startBatch(batch, function(){}); - } - stream.on('finish', sendStatus); - /** - * Set the pending status to a given error status. If the error does not have - * code or details properties, the code will be set to grpc.status.UNKNOWN - * and the details will be set to 'Unknown Error'. - * @param {Error} err The error object - */ - function setStatus(err) { - var code = constants.status.UNKNOWN; - var details = 'Unknown Error'; - var metadata = new Metadata(); - if (err.hasOwnProperty('message')) { - details = err.message; - } - if (err.hasOwnProperty('code')) { - code = err.code; - if (err.hasOwnProperty('details')) { - details = err.details; - } - } - if (err.hasOwnProperty('metadata')) { - metadata = err.metadata; - } - stream.status = {code: code, details: details, metadata: metadata}; - } - /** - * Terminate the call. This includes indicating that reads are done, draining - * all pending writes, and sending the given error as a status - * @param {Error} err The error object - * @this GrpcServerStream - */ - function terminateCall(err) { - // Drain readable data - setStatus(err); - stream.end(); - } - stream.on('error', terminateCall); - /** - * Override of Writable#end method that allows for sending metadata with a - * success status. - * @param {Metadata=} metadata Metadata to send with the status - */ - stream.end = function(metadata) { - if (metadata) { - stream.status.metadata = metadata; - } - Writable.prototype.end.call(this); - }; -} - -/** - * Initialize a readable stream. This is used for both the readable and duplex - * stream constructors. - * @private - * @param {Readable} stream The stream to initialize - * @param {grpc~deserialize} deserialize Deserialization function for - * incoming data. - */ -function setUpReadable(stream, deserialize) { - stream.deserialize = common.wrapIgnoreNull(deserialize); - stream.finished = false; - stream.reading = false; - - stream.terminate = function() { - stream.finished = true; - stream.on('data', function() {}); - }; - - stream.on('cancelled', function() { - stream.terminate(); - }); -} - -/** - * Emitted when the call has been cancelled. After this has been emitted, the - * call's `cancelled` property will be set to `true`. - * @event grpc~ServerUnaryCall~cancelled - */ - -util.inherits(ServerUnaryCall, EventEmitter); - -/** - * An EventEmitter. Used for unary calls. - * @constructor grpc~ServerUnaryCall - * @extends external:EventEmitter - * @param {grpc.internal~Call} call The call object associated with the request - * @param {grpc.Metadata} metadata The request metadata from the client - */ -function ServerUnaryCall(call, metadata) { - EventEmitter.call(this); - this.call = call; - /** - * Indicates if the call has been cancelled - * @member {boolean} grpc~ServerUnaryCall#cancelled - */ - this.cancelled = false; - /** - * The request metadata from the client - * @member {grpc.Metadata} grpc~ServerUnaryCall#metadata - */ - this.metadata = metadata; - /** - * The request message from the client - * @member {*} grpc~ServerUnaryCall#request - */ - this.request = undefined; -} - -/** - * Emitted when the call has been cancelled. After this has been emitted, the - * call's `cancelled` property will be set to `true`. - * @event grpc~ServerWritableStream~cancelled - */ - -util.inherits(ServerWritableStream, Writable); - -/** - * A stream that the server can write to. Used for calls that are streaming from - * the server side. - * @constructor grpc~ServerWritableStream - * @extends external:Writable - * @borrows grpc~ServerUnaryCall#sendMetadata as - * grpc~ServerWritableStream#sendMetadata - * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerWritableStream#getPeer - * @param {grpc.internal~Call} call The call object to send data with - * @param {grpc.Metadata} metadata The request metadata from the client - * @param {grpc~serialize} serialize Serialization function for writes - */ -function ServerWritableStream(call, metadata, serialize) { - Writable.call(this, {objectMode: true}); - this.call = call; - - this.finished = false; - setUpWritable(this, serialize); - /** - * Indicates if the call has been cancelled - * @member {boolean} grpc~ServerWritableStream#cancelled - */ - this.cancelled = false; - /** - * The request metadata from the client - * @member {grpc.Metadata} grpc~ServerWritableStream#metadata - */ - this.metadata = metadata; - /** - * The request message from the client - * @member {*} grpc~ServerWritableStream#request - */ - this.request = undefined; -} - -/** - * Start writing a chunk of data. This is an implementation of a method required - * for implementing stream.Writable. - * @private - * @param {Buffer} chunk The chunk of data to write - * @param {string} encoding Used to pass write flags - * @param {function(Error=)} callback Callback to indicate that the write is - * complete - */ -function _write(chunk, encoding, callback) { - /* jshint validthis: true */ - var batch = {}; - var self = this; - var message; - try { - message = this.serialize(chunk); - } catch (e) { - e.code = constants.status.INTERNAL; - callback(e); - return; - } - if (!this.call.metadataSent) { - batch[grpc.opType.SEND_INITIAL_METADATA] = - (new Metadata())._getCoreRepresentation(); - this.call.metadataSent = true; - } - if (Number.isFinite(encoding)) { - /* Attach the encoding if it is a finite number. This is the closest we - * can get to checking that it is valid flags */ - message.grpcWriteFlags = encoding; - } - batch[grpc.opType.SEND_MESSAGE] = message; - this.call.startBatch(batch, function(err, value) { - if (err) { - self.emit('error', err); - return; - } - callback(); - }); -} - -ServerWritableStream.prototype._write = _write; - -/** - * Emitted when the call has been cancelled. After this has been emitted, the - * call's `cancelled` property will be set to `true`. - * @event grpc~ServerReadableStream~cancelled - */ - -util.inherits(ServerReadableStream, Readable); - -/** - * A stream that the server can read from. Used for calls that are streaming - * from the client side. - * @constructor grpc~ServerReadableStream - * @extends external:Readable - * @borrows grpc~ServerUnaryCall#sendMetadata as - * grpc~ServerReadableStream#sendMetadata - * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerReadableStream#getPeer - * @param {grpc.internal~Call} call The call object to read data with - * @param {grpc.Metadata} metadata The request metadata from the client - * @param {grpc~deserialize} deserialize Deserialization function for reads - */ -function ServerReadableStream(call, metadata, deserialize) { - Readable.call(this, {objectMode: true}); - this.call = call; - setUpReadable(this, deserialize); - /** - * Indicates if the call has been cancelled - * @member {boolean} grpc~ServerReadableStream#cancelled - */ - this.cancelled = false; - /** - * The request metadata from the client - * @member {grpc.Metadata} grpc~ServerReadableStream#metadata - */ - this.metadata = metadata; -} - -/** - * Start reading from the gRPC data source. This is an implementation of a - * method required for implementing stream.Readable - * @access private - * @param {number} size Ignored - */ -function _read(size) { - /* jshint validthis: true */ - var self = this; - /** - * Callback to be called when a READ event is received. Pushes the data onto - * the read queue and starts reading again if applicable - * @param {grpc.Event} event READ event object - */ - function readCallback(err, event) { - if (err) { - self.terminate(); - return; - } - if (self.finished) { - self.push(null); - return; - } - var data = event.read; - var deserialized; - try { - deserialized = self.deserialize(data); - } catch (e) { - e.code = constants.status.INTERNAL; - self.emit('error', e); - return; - } - if (self.push(deserialized) && data !== null) { - var read_batch = {}; - read_batch[grpc.opType.RECV_MESSAGE] = true; - self.call.startBatch(read_batch, readCallback); - } else { - self.reading = false; - } - } - if (self.finished) { - self.push(null); - } else { - if (!self.reading) { - self.reading = true; - var batch = {}; - batch[grpc.opType.RECV_MESSAGE] = true; - self.call.startBatch(batch, readCallback); - } - } -} - -ServerReadableStream.prototype._read = _read; - -/** - * Emitted when the call has been cancelled. After this has been emitted, the - * call's `cancelled` property will be set to `true`. - * @event grpc~ServerDuplexStream~cancelled - */ - -util.inherits(ServerDuplexStream, Duplex); - -/** - * A stream that the server can read from or write to. Used for calls with - * duplex streaming. - * @constructor grpc~ServerDuplexStream - * @extends external:Duplex - * @borrows grpc~ServerUnaryCall#sendMetadata as - * grpc~ServerDuplexStream#sendMetadata - * @borrows grpc~ServerUnaryCall#getPeer as grpc~ServerDuplexStream#getPeer - * @param {grpc.internal~Call} call Call object to proxy - * @param {grpc.Metadata} metadata The request metadata from the client - * @param {grpc~serialize} serialize Serialization function for requests - * @param {grpc~deserialize} deserialize Deserialization function for - * responses - */ -function ServerDuplexStream(call, metadata, serialize, deserialize) { - Duplex.call(this, {objectMode: true}); - this.call = call; - setUpWritable(this, serialize); - setUpReadable(this, deserialize); - /** - * Indicates if the call has been cancelled - * @member {boolean} grpc~ServerReadableStream#cancelled - */ - this.cancelled = false; - /** - * The request metadata from the client - * @member {grpc.Metadata} grpc~ServerReadableStream#metadata - */ - this.metadata = metadata; -} - -ServerDuplexStream.prototype._read = _read; -ServerDuplexStream.prototype._write = _write; - -/** - * Send the initial metadata for a writable stream. - * @alias grpc~ServerUnaryCall#sendMetadata - * @param {grpc.Metadata} responseMetadata Metadata to send - */ -function sendMetadata(responseMetadata) { - /* jshint validthis: true */ - var self = this; - if (!this.call.metadataSent) { - this.call.metadataSent = true; - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = - responseMetadata._getCoreRepresentation(); - this.call.startBatch(batch, function(err) { - if (err) { - self.emit('error', err); - return; - } - }); - } -} - -ServerUnaryCall.prototype.sendMetadata = sendMetadata; -ServerWritableStream.prototype.sendMetadata = sendMetadata; -ServerReadableStream.prototype.sendMetadata = sendMetadata; -ServerDuplexStream.prototype.sendMetadata = sendMetadata; - -/** - * Get the endpoint this call/stream is connected to. - * @alias grpc~ServerUnaryCall#getPeer - * @return {string} The URI of the endpoint - */ -function getPeer() { - /* jshint validthis: true */ - return this.call.getPeer(); -} - -ServerUnaryCall.prototype.getPeer = getPeer; -ServerReadableStream.prototype.getPeer = getPeer; -ServerWritableStream.prototype.getPeer = getPeer; -ServerDuplexStream.prototype.getPeer = getPeer; - -/** - * Wait for the client to close, then emit a cancelled event if the client - * cancelled. - * @private - */ -function waitForCancel() { - /* jshint validthis: true */ - var self = this; - var cancel_batch = {}; - cancel_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - self.call.startBatch(cancel_batch, function(err, result) { - if (err) { - self.emit('error', err); - } - if (result.cancelled) { - self.cancelled = true; - self.emit('cancelled'); - } - }); -} - -ServerUnaryCall.prototype.waitForCancel = waitForCancel; -ServerReadableStream.prototype.waitForCancel = waitForCancel; -ServerWritableStream.prototype.waitForCancel = waitForCancel; -ServerDuplexStream.prototype.waitForCancel = waitForCancel; - -/** - * Callback function passed to server handlers that handle methods with unary - * responses. - * @callback grpc.Server~sendUnaryData - * @param {grpc~ServiceError} error An error, if the call failed - * @param {*} value The response value. Must be a valid argument to the - * `responseSerialize` method of the method that is being handled - * @param {grpc.Metadata=} trailer Trailing metadata to send, if applicable - * @param {grpc.writeFlags=} flags Flags to modify writing the response - */ - -/** - * User-provided method to handle unary requests on a server - * @callback grpc.Server~handleUnaryCall - * @param {grpc~ServerUnaryCall} call The call object - * @param {grpc.Server~sendUnaryData} callback The callback to call to respond - * to the request - */ - -/** - * Fully handle a unary call - * @private - * @param {grpc.internal~Call} call The call to handle - * @param {Object} handler Request handler object for the method that was called - * @param {grpc~Server.handleUnaryCall} handler.func The handler function - * @param {grpc~deserialize} handler.deserialize The deserialization function - * for request data - * @param {grpc~serialize} handler.serialize The serialization function for - * response data - * @param {grpc.Metadata} metadata Metadata from the client - */ -function handleUnary(call, handler, metadata) { - var emitter = new ServerUnaryCall(call, metadata); - emitter.on('error', function(error) { - handleError(call, error); - }); - emitter.waitForCancel(); - var batch = {}; - batch[grpc.opType.RECV_MESSAGE] = true; - call.startBatch(batch, function(err, result) { - if (err) { - handleError(call, err); - return; - } - try { - emitter.request = handler.deserialize(result.read); - } catch (e) { - e.code = constants.status.INTERNAL; - handleError(call, e); - return; - } - if (emitter.cancelled) { - return; - } - handler.func(emitter, function sendUnaryData(err, value, trailer, flags) { - if (err) { - if (trailer) { - err.metadata = trailer; - } - handleError(call, err); - } else { - sendUnaryResponse(call, value, handler.serialize, trailer, flags); - } - }); - }); -} - -/** - * User provided method to handle server streaming methods on the server. - * @callback grpc.Server~handleServerStreamingCall - * @param {grpc~ServerWritableStream} call The call object - */ - -/** - * Fully handle a server streaming call - * @private - * @param {grpc.internal~Call} call The call to handle - * @param {Object} handler Request handler object for the method that was called - * @param {grpc~Server.handleServerStreamingCall} handler.func The handler - * function - * @param {grpc~deserialize} handler.deserialize The deserialization function - * for request data - * @param {grpc~serialize} handler.serialize The serialization function for - * response data - * @param {grpc.Metadata} metadata Metadata from the client - */ -function handleServerStreaming(call, handler, metadata) { - var stream = new ServerWritableStream(call, metadata, handler.serialize); - stream.waitForCancel(); - var batch = {}; - batch[grpc.opType.RECV_MESSAGE] = true; - call.startBatch(batch, function(err, result) { - if (err) { - stream.emit('error', err); - return; - } - try { - stream.request = handler.deserialize(result.read); - } catch (e) { - e.code = constants.status.INTERNAL; - stream.emit('error', e); - return; - } - handler.func(stream); - }); -} - -/** - * User provided method to handle client streaming methods on the server. - * @callback grpc.Server~handleClientStreamingCall - * @param {grpc~ServerReadableStream} call The call object - * @param {grpc.Server~sendUnaryData} callback The callback to call to respond - * to the request - */ - -/** - * Fully handle a client streaming call - * @access private - * @param {grpc.internal~Call} call The call to handle - * @param {Object} handler Request handler object for the method that was called - * @param {grpc~Server.handleClientStreamingCall} handler.func The handler - * function - * @param {grpc~deserialize} handler.deserialize The deserialization function - * for request data - * @param {grpc~serialize} handler.serialize The serialization function for - * response data - * @param {grpc.Metadata} metadata Metadata from the client - */ -function handleClientStreaming(call, handler, metadata) { - var stream = new ServerReadableStream(call, metadata, handler.deserialize); - stream.on('error', function(error) { - handleError(call, error); - }); - stream.waitForCancel(); - handler.func(stream, function(err, value, trailer, flags) { - stream.terminate(); - if (err) { - if (trailer) { - err.metadata = trailer; - } - handleError(call, err); - } else { - sendUnaryResponse(call, value, handler.serialize, trailer, flags); - } - }); -} - -/** - * User provided method to handle bidirectional streaming calls on the server. - * @callback grpc.Server~handleBidiStreamingCall - * @param {grpc~ServerDuplexStream} call The call object - */ - -/** - * Fully handle a bidirectional streaming call - * @private - * @param {grpc.internal~Call} call The call to handle - * @param {Object} handler Request handler object for the method that was called - * @param {grpc~Server.handleBidiStreamingCall} handler.func The handler - * function - * @param {grpc~deserialize} handler.deserialize The deserialization function - * for request data - * @param {grpc~serialize} handler.serialize The serialization function for - * response data - * @param {Metadata} metadata Metadata from the client - */ -function handleBidiStreaming(call, handler, metadata) { - var stream = new ServerDuplexStream(call, metadata, handler.serialize, - handler.deserialize); - stream.waitForCancel(); - handler.func(stream); -} - -var streamHandlers = { - unary: handleUnary, - server_stream: handleServerStreaming, - client_stream: handleClientStreaming, - bidi: handleBidiStreaming -}; - -/** - * Constructs a server object that stores request handlers and delegates - * incoming requests to those handlers - * @memberof grpc - * @constructor - * @param {Object=} options Options that should be passed to the internal server - * implementation. The available options are listed in - * [this document]{@link https://grpc.github.io/grpc/core/group__grpc__arg__keys.html}. - * @example - * var server = new grpc.Server(); - * server.addProtoService(protobuf_service_descriptor, service_implementation); - * server.bind('address:port', server_credential); - * server.start(); - */ -function Server(options) { - this.handlers = {}; - var server = new grpc.Server(options); - this._server = server; - this.started = false; -} - -/** - * Start the server and begin handling requests - */ -Server.prototype.start = function() { - if (this.started) { - throw new Error('Server is already running'); - } - var self = this; - this.started = true; - this._server.start(); - /** - * Handles the SERVER_RPC_NEW event. If there is a handler associated with - * the requested method, use that handler to respond to the request. Then - * wait for the next request - * @param {grpc.internal~Event} event The event to handle with tag - * SERVER_RPC_NEW - */ - function handleNewCall(err, event) { - if (err) { - return; - } - var details = event.new_call; - var call = details.call; - var method = details.method; - var metadata = Metadata._fromCoreRepresentation(details.metadata); - if (method === null) { - return; - } - self._server.requestCall(handleNewCall); - var handler; - if (self.handlers.hasOwnProperty(method)) { - handler = self.handlers[method]; - } else { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = - (new Metadata())._getCoreRepresentation(); - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: constants.status.UNIMPLEMENTED, - details: 'RPC method not implemented ' + method, - metadata: (new Metadata())._getCoreRepresentation() - }; - batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - call.startBatch(batch, function() {}); - return; - } - streamHandlers[handler.type](call, handler, metadata); - } - this._server.requestCall(handleNewCall); -}; - -/** - * Unified type for application handlers for all types of calls - * @typedef {(grpc.Server~handleUnaryCall - * |grpc.Server~handleClientStreamingCall - * |grpc.Server~handleServerStreamingCall - * |grpc.Server~handleBidiStreamingCall)} grpc.Server~handleCall - */ - -/** - * Registers a handler to handle the named method. Fails if there already is - * a handler for the given method. Returns true on success - * @param {string} name The name of the method that the provided function should - * handle/respond to. - * @param {grpc.Server~handleCall} handler Function that takes a stream of - * request values and returns a stream of response values - * @param {grpc~serialize} serialize Serialization function for responses - * @param {grpc~deserialize} deserialize Deserialization function for requests - * @param {('unary'|'client_stream'|'server_stream'|'bidi')} type The streaming type of method that this handles - * @return {boolean} True if the handler was set. False if a handler was already - * set for that name. - */ -Server.prototype.register = function(name, handler, serialize, deserialize, - type) { - if (this.handlers.hasOwnProperty(name)) { - return false; - } - this.handlers[name] = { - func: handler, - serialize: serialize, - deserialize: deserialize, - type: type - }; - return true; -}; - -/** - * Gracefully shuts down the server. The server will stop receiving new calls, - * and any pending calls will complete. The callback will be called when all - * pending calls have completed and the server is fully shut down. This method - * is idempotent with itself and forceShutdown. - * @param {function()} callback The shutdown complete callback - */ -Server.prototype.tryShutdown = function(callback) { - this._server.tryShutdown(callback); -}; - -/** - * Forcibly shuts down the server. The server will stop receiving new calls - * and cancel all pending calls. When it returns, the server has shut down. - * This method is idempotent with itself and tryShutdown, and it will trigger - * any outstanding tryShutdown callbacks. - */ -Server.prototype.forceShutdown = function() { - this._server.forceShutdown(); -}; - -function getUnimplementedStatusResponse(methodName) { - return { - code: constants.status.UNIMPLEMENTED, - details: 'The server does not implement the method' + methodName - } -} - -function getDefaultHandler(handlerType, methodName) { - const unimplementedStatusResponse = getUnimplementedStatusResponse(methodName); - switch(handlerType) { - case 'unary': - return (call, callback) => { - callback(unimplementedStatusResponse, null); - }; - case 'client_stream': - return (call,callback) => { - callback(unimplementedStatusResponse, null); - }; - case 'server_stream': - return (call) => { - call.emit('error', unimplementedStatusResponse); - } - case 'bidi': - return (call) => { - call.emit('error', unimplementedStatusResponse); - } - } -} - -function isObject(thing) { - return (typeof thing === 'object' || typeof thing === 'function') && thing !== null; -} - -/** - * Add a service to the server, with a corresponding implementation. - * @param {grpc~ServiceDefinition} service The service descriptor - * @param {Object} implementation Map of method - * names to method implementation for the provided service. - */ -Server.prototype.addService = function(service, implementation) { - if (!isObject(service) || !isObject(implementation)) { - throw new Error('addService requires two objects as arguments'); - } - if (Object.keys(service).length === 0) { - throw new Error('Cannot add an empty service to a server'); - } - if (this.started) { - throw new Error('Can\'t add a service to a started server.'); - } - var self = this; - Object.keys(service).forEach(name => { - const attrs = service[name]; - var method_type; - if (attrs.requestStream) { - if (attrs.responseStream) { - method_type = 'bidi'; - } else { - method_type = 'client_stream'; - } - } else { - if (attrs.responseStream) { - method_type = 'server_stream'; - } else { - method_type = 'unary'; - } - } - var impl; - if (implementation[name] === undefined) { - /* Handle the case where the method is passed with the name exactly as - written in the proto file, instead of using JavaScript function - naming style */ - if (implementation[attrs.originalName] === undefined) { - common.log(constants.logVerbosity.ERROR, 'Method handler ' + name + - ' for ' + attrs.path + ' expected but not provided'); - impl = getDefaultHandler(method_type, name); - } else { - impl = implementation[attrs.originalName].bind(implementation); - } - } else { - impl = implementation[name].bind(implementation); - } - var serialize = attrs.responseSerialize; - var deserialize = attrs.requestDeserialize; - var register_success = self.register(attrs.path, impl, serialize, - deserialize, method_type); - if (!register_success) { - throw new Error('Method handler for ' + attrs.path + - ' already provided.'); - } - }); -}; - -/** - * Add a proto service to the server, with a corresponding implementation - * @deprecated Use {@link grpc.Server#addService} instead - * @param {Protobuf.Reflect.Service} service The proto service descriptor - * @param {Object} implementation Map of method - * names to method implementation for the provided service. - */ -Server.prototype.addProtoService = util.deprecate(function(service, - implementation) { - var options; - var protobuf_js_5_common = require('./protobuf_js_5_common'); - var protobuf_js_6_common = require('./protobuf_js_6_common'); - if (protobuf_js_5_common.isProbablyProtobufJs5(service)) { - options = Object.assign({}, common.defaultGrpcOptions, service.grpc_options); - this.addService( - protobuf_js_5_common.getProtobufServiceAttrs(service, options), - implementation); - } else if (protobuf_js_6_common.isProbablyProtobufJs6(service)) { - options = Object.assign({}, common.defaultGrpcOptions, service.grpc_options); - this.addService( - protobuf_js_6_common.getProtobufServiceAttrs(service, options), - implementation); - } else { - // We assume that this is a service attributes object - this.addService(service, implementation); - } -}, 'Server#addProtoService: Use Server#addService instead'); - -/** - * Binds the server to the given port, with SSL disabled if creds is an - * insecure credentials object - * @param {string} port The port that the server should bind on, in the format - * "address:port" - * @param {grpc.ServerCredentials} creds Server credential object to be used for - * SSL. Pass an insecure credentials object for an insecure port. - * @return {number} The bound port number. Zero if binding the port failed. - */ -Server.prototype.bind = function(port, creds) { - if (this.started) { - throw new Error('Can\'t bind an already running server to an address'); - } - return this._server.addHttp2Port(port, creds); -}; - -/** - * Called with the result of attempting to bind a port - * @callback grpc.Server~bindCallback - * @param {Error=} error If non-null, indicates that binding the port failed. - * @param {number} port The bound port number. If binding the port fails, this - * will be zero to match the output of bind. - */ - -/** - * Binds the server to the given port, with SSL disabled if creds is an - * insecure credentials object. Provides the result asynchronously. - * @param {string} port The port that the server should bind on, in the format - * "address:port" - * @param {grpc.ServerCredentials} creds Server credential object to be used for - * SSL. Pass an insecure credentials object for an insecure port. - */ -Server.prototype.bindAsync = function(port, creds, callback) { - /* This can throw. We do not try to catch that error because it indicates an - * incorrect use of the function, which should not be surfaced asynchronously - */ - const result = this.bind(port, creds) - if (result === 0) { - setImmediate(callback, new Error('Failed to bind port'), result); - } else { - setImmediate(callback, null, result); - } -} - -exports.Server = Server; diff --git a/packages/grpc-native-core/test/async_test.js b/packages/grpc-native-core/test/async_test.js deleted file mode 100644 index 119d20ceb..000000000 --- a/packages/grpc-native-core/test/async_test.js +++ /dev/null @@ -1,86 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); - -var grpc = require('..'); -var math = grpc.load( - __dirname + '/../deps/grpc/src/proto/math/math.proto').math; - - -/** - * Client to use to make requests to a running server. - */ -var math_client; - -/** - * Server to test against - */ -var getServer = require('./math/math_server.js'); - -var server = getServer(); - -let serverCreds = grpc.ServerCredentials.createInsecure(); - -describe('Async functionality', function() { - before(function(done) { - server.bindAsync('0.0.0.0:0', serverCreds, (error, port_num) => { - server.start(); - math_client = new math.Math('localhost:' + port_num, - grpc.credentials.createInsecure()); - done(); - }); - }); - after(function() { - grpc.closeClient(math_client); - server.forceShutdown(); - }); - it('should not hang', function(done) { - var chunkCount=0; - var call = math_client.sum(function handleSumResult(err, value) { - assert.ifError(err); - assert.equal(value.num, chunkCount); - }); - - var path = require('path'); - var fs = require('fs'); - var fileToRead = path.join(__dirname, 'numbers.txt'); - var readStream = fs.createReadStream(fileToRead); - - readStream.once('readable', function () { - readStream.on('data', function (chunk) { - call.write({'num': 1}); - chunkCount += 1; - }); - - readStream.on('end', function () { - call.end(); - }); - - readStream.on('error', function (error) { - }); - }); - - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); -}); diff --git a/packages/grpc-native-core/test/call_test.js b/packages/grpc-native-core/test/call_test.js deleted file mode 100644 index 42fd3d014..000000000 --- a/packages/grpc-native-core/test/call_test.js +++ /dev/null @@ -1,335 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var grpc = require('../src/grpc_extension'); -var constants = require('../src/constants'); - -/** - * Helper function to return an absolute deadline given a relative timeout in - * seconds. - * @param {number} timeout_secs The number of seconds to wait before timing out - * @return {Date} A date timeout_secs in the future - */ -function getDeadline(timeout_secs) { - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + timeout_secs); - return deadline; -} - -var insecureCreds = grpc.ChannelCredentials.createInsecure(); - -describe('call', function() { - var channel; - var server; - before(function() { - server = new grpc.Server(); - var port = server.addHttp2Port('localhost:0', - grpc.ServerCredentials.createInsecure()); - server.start(); - channel = new grpc.Channel('localhost:' + port, insecureCreds); - }); - after(function() { - server.forceShutdown(); - }); - describe('factory', function() { - it('should reject anything less than 2 arguments', function() { - assert.throws(function() { - channel.createCall(); - }, TypeError); - assert.throws(function() { - channel.createCall('method'); - }, TypeError); - }); - it('should succeed with a string and a date or number', - function() { - assert.doesNotThrow(function() { - channel.createCall('method', new Date()); - }); - assert.doesNotThrow(function() { - channel.createCall('method', 0); - }); - }); - it('should accept an optional third string parameter', function() { - assert.doesNotThrow(function() { - channel.createCall('method', new Date(), 'host_override'); - }); - }); - it('should fail with a closed channel', function() { - var local_channel = new grpc.Channel('hostname', insecureCreds); - local_channel.close(); - assert.throws(function() { - local_channel.createCall('method', 0); - }); - }); - it('should fail with other types', function() { - assert.throws(function() { - channel.createCall(null, 0); - }, TypeError); - assert.throws(function() { - channel.createCall('method', 'now'); - }, TypeError); - }); - }); - describe('deadline', function() { - it('should time out immediately with negative deadline', function(done) { - var call = channel.createCall('method', -Infinity); - var batch = {}; - batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(batch, function(err, response) { - assert.strictEqual(response.status.code, - constants.status.DEADLINE_EXCEEDED); - done(); - }); - }); - }); - describe('startBatch', function() { - it('should fail without an object and a function', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - call.startBatch(); - }); - assert.throws(function() { - call.startBatch({}); - }); - assert.throws(function() { - call.startBatch(null, function(){}); - }); - }); - it('should succeed with an empty object', function(done) { - var call = channel.createCall('method', getDeadline(1)); - assert.doesNotThrow(function() { - call.startBatch({}, function(err) { - assert.ifError(err); - done(); - }); - }); - }); - }); - describe('startBatch with metadata', function() { - it('should succeed with a map of strings to string arrays', function(done) { - var call = channel.createCall('method', getDeadline(1)); - assert.doesNotThrow(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = { - metadata: {'key1': ['value1'], 'key2': ['value2']} - }; - call.startBatch(batch, function(err, resp) { - assert.ifError(err); - assert.deepEqual(resp, {'send_metadata': true}); - done(); - }); - }); - }); - it('should succeed with a map of strings to buffer arrays', function(done) { - var call = channel.createCall('method', getDeadline(1)); - assert.doesNotThrow(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = { - metadata: { - 'key1-bin': [Buffer.from('value1')], - 'key2-bin': [Buffer.from('value2')] - } - }; - call.startBatch(batch, function(err, resp) { - assert.ifError(err); - assert.deepEqual(resp, {'send_metadata': true}); - done(); - }); - }); - }); - it('should fail with other parameter types', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = undefined; - call.startBatch(batch, function(){}); - }); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = null; - call.startBatch(batch, function(){}); - }, TypeError); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = 'value'; - call.startBatch(batch, function(){}); - }, TypeError); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = 5; - call.startBatch(batch, function(){}); - }, TypeError); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_INITIAL_METADATA] = {}; - call.startBatch(batch, function(){}); - }, TypeError); - }); - }); - describe('startBatch with message', function() { - it('should fail with null argument', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_MESSAGE] = null; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail with numeric argument', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_MESSAGE] = 5; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail with string argument', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_MESSAGE] = 'value'; - call.startBatch(batch, function(){}); - }, TypeError); - }); - }); - describe('startBatch with status', function() { - it('should fail without a code', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - details: 'details string', - metadata: {} - }; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail without details', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: 0, - metadata: {} - }; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail without metadata', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: 0, - details: 'details string' - }; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail with incorrectly typed code argument', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: 'code string', - details: 'details string', - metadata: {} - }; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail with incorrectly typed details argument', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: 0, - details: 5, - metadata: {} - }; - call.startBatch(batch, function(){}); - }, TypeError); - }); - it('should fail with incorrectly typed metadata argument', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.throws(function() { - var batch = {}; - batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - code: 0, - details: 'details string', - metadata: 'abc' - }; - call.startBatch(batch, function(){}); - }, TypeError); - }); - }); - describe('cancel', function() { - it('should succeed', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.doesNotThrow(function() { - call.cancel(); - }); - }); - }); - describe('cancelWithStatus', function() { - it('should reject anything other than an integer and a string', function() { - assert.doesNotThrow(function() { - var call = channel.createCall('method', getDeadline(1)); - call.cancelWithStatus(1, 'details'); - }); - assert.throws(function() { - var call = channel.createCall('method', getDeadline(1)); - call.cancelWithStatus(); - }); - assert.throws(function() { - var call = channel.createCall('method', getDeadline(1)); - call.cancelWithStatus(''); - }); - assert.throws(function() { - var call = channel.createCall('method', getDeadline(1)); - call.cancelWithStatus(5, {}); - }); - }); - it('should reject the OK status code', function() { - assert.throws(function() { - var call = channel.createCall('method', getDeadline(1)); - call.cancelWithStatus(0, 'details'); - }); - }); - it('should result in the call ending with a status', function(done) { - var call = channel.createCall('method', getDeadline(1)); - var batch = {}; - batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(batch, function(err, response) { - assert.strictEqual(response.status.code, 5); - assert.strictEqual(response.status.details, 'details'); - done(); - }); - call.cancelWithStatus(5, 'details'); - }); - }); - describe('getPeer', function() { - it('should return a string', function() { - var call = channel.createCall('method', getDeadline(1)); - assert.strictEqual(typeof call.getPeer(), 'string'); - }); - }); -}); diff --git a/packages/grpc-native-core/test/channel_test.js b/packages/grpc-native-core/test/channel_test.js deleted file mode 100644 index 8c95d84ae..000000000 --- a/packages/grpc-native-core/test/channel_test.js +++ /dev/null @@ -1,181 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var grpc = require('..'); - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} -var insecureCreds = grpc.credentials.createInsecure(); - -describe('channel', function() { - describe('constructor', function() { - it('should require a string for the first argument', function() { - assert.doesNotThrow(function() { - new grpc.Channel('hostname', insecureCreds); - }); - assert.throws(function() { - new grpc.Channel(); - }, TypeError); - assert.throws(function() { - new grpc.Channel(5); - }); - }); - it('should require a credential for the second argument', function() { - assert.doesNotThrow(function() { - new grpc.Channel('hostname', insecureCreds); - }); - assert.throws(function() { - new grpc.Channel('hostname', 5); - }); - assert.throws(function() { - new grpc.Channel('hostname'); - }); - }); - it('should accept an object for the third argument', function() { - assert.doesNotThrow(function() { - new grpc.Channel('hostname', insecureCreds, {}); - }); - assert.throws(function() { - new grpc.Channel('hostname', insecureCreds, 'abc'); - }); - }); - it('should only accept objects with string or int values', function() { - assert.doesNotThrow(function() { - new grpc.Channel('hostname', insecureCreds,{'key' : 'value'}); - }); - assert.doesNotThrow(function() { - new grpc.Channel('hostname', insecureCreds, {'key' : 5}); - }); - assert.throws(function() { - new grpc.Channel('hostname', insecureCreds, {'key' : null}); - }); - assert.throws(function() { - new grpc.Channel('hostname', insecureCreds, {'key' : new Date()}); - }); - }); - it('should succeed without the new keyword', function() { - assert.doesNotThrow(function() { - var channel = grpc.Channel('hostname', insecureCreds); - assert(channel instanceof grpc.Channel); - }); - }); - }); - describe('close', function() { - var channel; - beforeEach(function() { - channel = new grpc.Channel('hostname', insecureCreds, {}); - }); - it('should succeed silently', function() { - assert.doesNotThrow(function() { - channel.close(); - }); - }); - it('should be idempotent', function() { - assert.doesNotThrow(function() { - channel.close(); - channel.close(); - }); - }); - }); - describe('getTarget', function() { - var channel; - beforeEach(function() { - channel = new grpc.Channel('hostname', insecureCreds, {}); - }); - it('should return a string', function() { - assert.strictEqual(typeof channel.getTarget(), 'string'); - }); - }); - describe('getConnectivityState', function() { - var channel; - beforeEach(function() { - channel = new grpc.Channel('hostname', insecureCreds, {}); - }); - it('should return IDLE for a new channel', function() { - assert.strictEqual(channel.getConnectivityState(), - grpc.connectivityState.IDLE); - }); - }); - describe('watchConnectivityState', function() { - var channel; - beforeEach(function() { - channel = new grpc.Channel('localhost', insecureCreds, {}); - }); - afterEach(function() { - channel.close(); - }); - it('should time out if called alone', function(done) { - var old_state = channel.getConnectivityState(); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - channel.watchConnectivityState(old_state, deadline, function(err, value) { - assert(err); - done(); - }); - }); - it('should complete if a connection attempt is forced', function(done) { - var old_state = channel.getConnectivityState(); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - channel.watchConnectivityState(old_state, deadline, function(err, value) { - assert.ifError(err); - assert.notEqual(value.new_state, old_state); - done(); - }); - channel.getConnectivityState(true); - }); - it('should complete twice if called twice', function(done) { - done = multiDone(done, 2); - var old_state = channel.getConnectivityState(); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - channel.watchConnectivityState(old_state, deadline, function(err, value) { - assert.ifError(err); - assert.notEqual(value.new_state, old_state); - done(); - }); - channel.watchConnectivityState(old_state, deadline, function(err, value) { - assert.ifError(err); - assert.notEqual(value.new_state, old_state); - done(); - }); - channel.getConnectivityState(true); - }); - }); -}); diff --git a/packages/grpc-native-core/test/client_interceptors_test.js b/packages/grpc-native-core/test/client_interceptors_test.js deleted file mode 100644 index 69cd25d72..000000000 --- a/packages/grpc-native-core/test/client_interceptors_test.js +++ /dev/null @@ -1,1795 +0,0 @@ -/** - * @license - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var _ = require('lodash'); -var assert = require('assert'); -var grpc = require('..'); -var grpc_client = require('../src/client.js'); -var Metadata = require('../src/metadata'); - -var insecureCreds = grpc.credentials.createInsecure(); - -var echo_proto = grpc.load(__dirname + '/echo_service.proto'); -var echo_service = echo_proto.EchoService.service; - -var StatusBuilder = grpc_client.StatusBuilder; -var ListenerBuilder = grpc_client.ListenerBuilder; -var InterceptingCall = grpc_client.InterceptingCall; -var RequesterBuilder = grpc_client.RequesterBuilder; - -var CallRegistry = function(done, expectation, is_ordered, is_verbose) { - this.call_map = {}; - this.call_array = []; - this.done = done; - this.expectation = expectation; - this.expectation_is_array = Array.isArray(this.expectation); - this.is_ordered = is_ordered; - this.is_verbose = is_verbose; - if (is_verbose) { - console.log('Expectation: ', expectation); - } -}; - -CallRegistry.prototype.addCall = function(call_name) { - if (this.expectation_is_array) { - this.call_array.push(call_name); - if (this.is_verbose) { - console.log(this.call_array); - } - } else { - if (!this.call_map[call_name]) { - this.call_map[call_name] = 0; - } - this.call_map[call_name]++; - if (this.is_verbose) { - console.log(this.call_map); - } - } - this.maybeCallDone(); -}; - -CallRegistry.prototype.maybeCallDone = function() { - if (this.expectation_is_array) { - if (this.is_ordered) { - if (this.expectation && _.isEqual(this.expectation, this.call_array)) { - this.done(); - } - } else { - var intersection = _.intersectionWith(this.expectation, this.call_array, - _.isEqual); - if (intersection.length === this.expectation.length) { - this.done(); - } - } - } else if (this.expectation && _.isEqual(this.expectation, this.call_map)) { - this.done(); - } -}; - -describe('Client interceptors', function() { - var echo_server; - var echo_port; - var client; - - function startServer() { - echo_server = new grpc.Server(); - echo_server.addService(echo_service, { - echo: function(call, callback) { - call.sendMetadata(call.metadata); - if (call.request.value === 'error') { - var status = { - code: 2, - message: 'test status message' - }; - status.metadata = call.metadata; - callback(status, null); - return; - } - callback(null, call.request); - }, - echoClientStream: function(call, callback){ - call.sendMetadata(call.metadata); - var payload; - var err = null; - call.on('data', function(data) { - if (data.value === 'error') { - err = { - code: 2, - message: 'test status message' - }; - err.metadata = call.metadata; - return; - } - payload = data; - }); - call.on('end', function() { - callback(err, payload, call.metadata); - }); - }, - echoServerStream: function(call) { - call.sendMetadata(call.metadata); - if (call.request.value === 'error') { - var status = { - code: 2, - message: 'test status message' - }; - status.metadata = call.metadata; - call.emit('error', status); - return; - } - call.write(call.request); - call.end(call.metadata); - }, - echoBidiStream: function(call) { - call.sendMetadata(call.metadata); - call.on('data', function(data) { - if (data.value === 'error') { - var status = { - code: 2, - message: 'test status message' - }; - call.emit('error', status); - return; - } - call.write(data); - }); - call.on('end', function() { - call.end(call.metadata); - }); - } - }); - var server_credentials = grpc.ServerCredentials.createInsecure(); - echo_port = echo_server.bind('localhost:0', server_credentials); - echo_server.start(); - } - - function stopServer() { - echo_server.forceShutdown(); - } - - function resetClient() { - var EchoClient = grpc_client.makeClientConstructor(echo_service); - client = new EchoClient('localhost:' + echo_port, insecureCreds); - } - - before(function() { - startServer(); - }); - beforeEach(function() { - resetClient(); - }); - after(function() { - stopServer(); - }); - describe('pass calls through when no interceptors provided', function() { - it('with unary call', function(done) { - var expected_value = 'foo'; - var message = {value: expected_value}; - client.echo(message, function(err, response) { - assert.strictEqual(response.value, expected_value); - done(); - }); - assert(_.isEqual(grpc_client.getClientInterceptors(client), { - echo: [], - echoClientStream: [], - echoServerStream: [], - echoBidiStream: [] - })); - }); - }); - - describe('execute downstream interceptors when a new call is made outbound', - function() { - var registry; - var options; - before(function() { - var stored_listener; - var stored_metadata; - var interceptor_a = function (options, nextCall) { - options.call_number = 1; - registry.addCall('construct a ' + options.call_number); - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - registry.addCall('start a ' + options.call_number); - stored_listener = listener; - stored_metadata = metadata; - next(metadata, listener); - }, - sendMessage: function (message, next) { - registry.addCall('send a ' + options.call_number); - var options2 = _.clone(options); - options2.call_number = 2; - var second_call = nextCall(options2); - second_call.start(stored_metadata); - second_call.sendMessage(message); - second_call.halfClose(); - next(message); - }, - halfClose: function (next) { - registry.addCall('close a ' + options.call_number); - next(); - } - }); - }; - - var interceptor_b = function (options, nextCall) { - registry.addCall('construct b ' + options.call_number); - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - registry.addCall('start b ' + options.call_number); - next(metadata, listener); - }, - sendMessage: function (message, next) { - registry.addCall('send b ' + options.call_number); - next(message); - }, - halfClose: function (next) { - registry.addCall('close b ' + options.call_number); - next(); - } - }); - }; - options = { - interceptors: [interceptor_a, interceptor_b] - }; - }); - var expected_calls = [ - 'construct a 1', - 'construct b 1', - 'start a 1', - 'start b 1', - 'send a 1', - 'construct b 2', - 'start b 2', - 'send b 2', - 'close b 2', - 'send b 1', - 'close a 1', - 'close b 1', - 'response' - ]; - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - client.echo(message, options, function(err, response){ - if (!err) { - registry.addCall('response'); - } - }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, false); - var message = {}; - message.value = 'foo'; - var stream = client.echoClientStream(options, function(err, response) { - if (!err) { - registry.addCall('response'); - } - }); - stream.write(message); - stream.end(); - }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - var stream = client.echoServerStream(message, options); - stream.on('data', function(data) { - registry.addCall('response'); - }); - }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry( done, expected_calls, true); - var message = {}; - message.value = 'foo'; - var stream = client.echoBidiStream(options); - stream.on('data', function(data) { - registry.addCall('response'); - }); - stream.write(message); - stream.end(); - }); - }); - - - describe('execute downstream interceptors when a new call is made inbound', - function() { - var registry; - var options; - before(function() { - var interceptor_a = function (options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - next(metadata, { - onReceiveMetadata: function () { }, - onReceiveMessage: function (message, next) { - registry.addCall('interceptor_a'); - var second_call = nextCall(options); - second_call.start(metadata, listener); - second_call.sendMessage(message); - second_call.halfClose(); - }, - onReceiveStatus: function () { } - }); - } - }); - }; - - var interceptor_b = function (options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function (metadata, listener, next) { - next(metadata, { - onReceiveMessage: function (message, next) { - registry.addCall('interceptor_b'); - next(message); - } - }); - } - }); - }; - - options = { - interceptors: [interceptor_a, interceptor_b] - }; - - }); - var expected_calls = ['interceptor_b', 'interceptor_a', - 'interceptor_b', 'response']; - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - client.echo(message, options, function(err) { - if (!err) { - registry.addCall('response'); - } - }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {}; - message.value = 'foo'; - var stream = client.echoClientStream(options, function(err, response) { - if (!err) { - registry.addCall('response'); - } - }); - stream.write(message); - stream.end(); - }); - }); - - it('will delay operations and short circuit unary requests', function(done) { - var registry = new CallRegistry(done, ['foo_miss', 'foo_hit', 'bar_miss', - 'foo_hit_done', 'foo_miss_done', 'bar_miss_done']); - var cache = {}; - var _getCachedResponse = function(value) { - return cache[value]; - }; - var _store = function(key, value) { - cache[key] = value; - }; - - var interceptor = function(options, nextCall) { - var savedMetadata; - var startNext; - var storedListener; - var storedMessage; - var messageNext; - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - savedMetadata = metadata; - storedListener = listener; - startNext = next; - }) - .withSendMessage(function(message, next) { - storedMessage = message; - messageNext = next; - }) - .withHalfClose(function(next) { - var cachedValue = _getCachedResponse(storedMessage.value); - if (cachedValue) { - var cachedMessage = {}; - cachedMessage.value = cachedValue; - registry.addCall(storedMessage.value + '_hit'); - storedListener.onReceiveMetadata(new Metadata()); - storedListener.onReceiveMessage(cachedMessage); - storedListener.onReceiveStatus( - (new StatusBuilder()).withCode(grpc.status.OK).build()); - } else { - registry.addCall(storedMessage.value + '_miss'); - var newListener = (new ListenerBuilder()).withOnReceiveMessage( - function(message, next) { - _store(storedMessage.value, message.value); - next(message); - }).build(); - startNext(savedMetadata, newListener); - messageNext(storedMessage); - next(); - } - }) - .withCancel(function(message, next) { - next(); - }).build(); - - return new InterceptingCall(nextCall(options), requester); - }; - - var options = { - interceptors: [interceptor] - }; - - var foo_message = {}; - foo_message.value = 'foo'; - client.echo(foo_message, options, function(err, response){ - assert.equal(response.value, 'foo'); - registry.addCall('foo_miss_done'); - client.echo(foo_message, options, function(err, response){ - assert.equal(response.value, 'foo'); - registry.addCall('foo_hit_done'); - }); - }); - - var bar_message = {}; - bar_message.value = 'bar'; - client.echo(bar_message, options, function(err, response) { - assert.equal(response.value, 'bar'); - registry.addCall('bar_miss_done'); - }); - }); - - it('can retry failed messages and handle eventual success', function(done) { - var registry = new CallRegistry(done, - ['retry_foo_1', 'retry_foo_2', 'retry_foo_3', 'foo_result', - 'retry_bar_1', 'bar_result']); - var maxRetries = 3; - var retry_interceptor = function(options, nextCall) { - var savedMetadata; - var savedSendMessage; - var savedReceiveMessage; - var savedMessageNext; - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - savedMetadata = metadata; - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - savedReceiveMessage = message; - savedMessageNext = next; - }) - .withOnReceiveStatus(function(status, next) { - var retries = 0; - var retry = function(message, metadata) { - retries++; - var newCall = nextCall(options); - var receivedMessage; - newCall.start(metadata, { - onReceiveMessage: function(message) { - receivedMessage = message; - }, - onReceiveStatus: function(status) { - registry.addCall('retry_' + savedMetadata.get('name') + - '_' + retries); - if (status.code !== grpc.status.OK) { - if (retries <= maxRetries) { - retry(message, metadata); - } else { - savedMessageNext(receivedMessage); - next(status); - } - } else { - registry.addCall('success_call'); - var new_status = (new StatusBuilder()) - .withCode(grpc.status.OK).build(); - savedMessageNext(receivedMessage); - next(new_status); - } - } - }); - newCall.sendMessage(message); - newCall.halfClose(); - }; - if (status.code !== grpc.status.OK) { - // Change the message we're sending only for test purposes - // so the server will respond without error - var newMessage = (savedMetadata.get('name')[0] === 'bar') ? - {value: 'bar'} : savedSendMessage; - retry(newMessage, savedMetadata); - } else { - savedMessageNext(savedReceiveMessage); - next(status); - } - } - ).build(); - next(metadata, new_listener); - }) - .withSendMessage(function(message, next) { - savedSendMessage = message; - next(message); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var options = { - interceptors: [retry_interceptor] - }; - - // Make a call which the server will return a non-OK status for - var foo_message = {value: 'error'}; - var foo_metadata = new Metadata(); - foo_metadata.set('name', 'foo'); - client.echo(foo_message, foo_metadata, options, function(err, response) { - assert.strictEqual(err.code, 2); - registry.addCall('foo_result'); - }); - - // Make a call which will fail the first time and succeed on the first - // retry - var bar_message = {value: 'error'}; - var bar_metadata = new Metadata(); - bar_metadata.set('name', 'bar'); - client.echo(bar_message, bar_metadata, options, function(err, response) { - assert.strictEqual(response.value, 'bar'); - registry.addCall('bar_result'); - }); - }); - - it('can retry and preserve interceptor order on success', function(done) { - var registry = new CallRegistry(done, - ['interceptor_c', 'retry_interceptor', 'fail_call', 'interceptor_c', - 'success_call', 'interceptor_a', 'result'], true); - var interceptor_a = function(options, nextCall) { - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - registry.addCall('interceptor_a'); - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var retry_interceptor = function(options, nextCall) { - var savedMetadata; - var savedMessage; - var savedMessageNext; - var sendMessageNext; - var originalMessage; - var startNext; - var originalListener; - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - startNext = next; - savedMetadata = metadata; - originalListener = listener; - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - savedMessage = message; - savedMessageNext = next; - }) - .withOnReceiveStatus(function(status, next) { - var retries = 0; - var maxRetries = 1; - var receivedMessage; - var retry = function(message, metadata) { - retries++; - var new_call = nextCall(options); - new_call.start(metadata, { - onReceiveMessage: function(message) { - receivedMessage = message; - }, - onReceiveStatus: function(status) { - if (status.code !== grpc.status.OK) { - if (retries <= maxRetries) { - retry(message, metadata); - } else { - savedMessageNext(receivedMessage); - next(status); - } - } else { - registry.addCall('success_call'); - var new_status = (new StatusBuilder()) - .withCode(grpc.status.OK).build(); - savedMessageNext(receivedMessage); - next(new_status); - } - } - }); - new_call.sendMessage(message); - new_call.halfClose(); - }; - registry.addCall('retry_interceptor'); - if (status.code !== grpc.status.OK) { - registry.addCall('fail_call'); - var newMessage = {value: 'foo'}; - retry(newMessage, savedMetadata); - } else { - savedMessageNext(savedMessage); - next(status); - } - }).build(); - next(metadata, new_listener); - }) - .withSendMessage(function(message, next) { - sendMessageNext = next; - originalMessage = message; - next(message); - }) - .build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var interceptor_c = function(options, nextCall) { - var requester = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function(message, next) { - registry.addCall('interceptor_c'); - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - - var options = { - interceptors: [interceptor_a, retry_interceptor, interceptor_c] - }; - - var message = {value: 'error'}; - client.echo(message, options, function(err, response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('result'); - }); - }); - - describe('handle interceptor errors', function (doneOuter) { - var options; - before(function () { - var foo_interceptor = function (options, nextCall) { - var savedListener; - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - savedListener = listener; - next(metadata, listener); - }) - .withSendMessage(function (message, next) { - savedListener.onReceiveMetadata(new Metadata()); - savedListener.onReceiveMessage({ value: 'failed' }); - var error_status = (new StatusBuilder()) - .withCode(16) - .withDetails('Error in foo interceptor') - .build(); - savedListener.onReceiveStatus(error_status); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - it('with unary call', function(done) { - var message = {}; - client.echo(message, options, function(err, response) { - assert.strictEqual(err.code, 16); - assert.strictEqual(err.message, - '16 UNAUTHENTICATED: Error in foo interceptor'); - done(); - doneOuter(); - }); - }); - }); - - describe('implement fallbacks for streaming RPCs', function() { - - var options; - before(function () { - var fallback_response = { value: 'fallback' }; - var savedMessage; - var savedMessageNext; - var interceptor = function (options, nextCall) { - var requester = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()) - .withOnReceiveMessage(function (message, next) { - savedMessage = message; - savedMessageNext = next; - }) - .withOnReceiveStatus(function (status, next) { - if (status.code !== grpc.status.OK) { - savedMessageNext(fallback_response); - next((new StatusBuilder()).withCode(grpc.status.OK)); - } else { - savedMessageNext(savedMessage); - next(status); - } - }).build(); - next(metadata, new_listener); - }).build(); - return new InterceptingCall(nextCall(options), requester); - }; - options = { - interceptors: [interceptor] - }; - }); - it('with client streaming call', function (done) { - var registry = new CallRegistry(done, ['foo_result', 'fallback_result']); - var stream = client.echoClientStream(options, function (err, response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('foo_result'); - }); - stream.write({ value: 'foo' }); - stream.end(); - - stream = client.echoClientStream(options, function(err, response) { - assert.strictEqual(response.value, 'fallback'); - registry.addCall('fallback_result'); - }); - stream.write({value: 'error'}); - stream.end(); - }); - }); - - describe('allows the call options to be modified for downstream interceptors', - function() { - var done; - var options; - var method_name; - var method_path_last; - before(function() { - var interceptor_a = function (options, nextCall) { - options.deadline = 10; - return new InterceptingCall(nextCall(options)); - }; - var interceptor_b = function (options, nextCall) { - assert.equal(options.method_definition.path, '/EchoService/' + - method_path_last); - assert.equal(options.deadline, 10); - done(); - return new InterceptingCall(nextCall(options)); - }; - - options = { - interceptors: [interceptor_a, interceptor_b], - deadline: 100 - }; - }); - - it('with unary call', function(cb) { - done = cb; - var metadata = new Metadata(); - var message = {}; - method_name = 'echo'; - method_path_last = 'Echo'; - - client.echo(message, metadata, options, function(){}); - }); - - it('with client streaming call', function(cb) { - done = cb; - var metadata = new Metadata(); - method_name = 'echoClientStream'; - method_path_last = 'EchoClientStream'; - - client.echoClientStream(metadata, options, function() {}); - }); - - it('with server streaming call', function(cb) { - done = cb; - var metadata = new Metadata(); - var message = {}; - method_name = 'echoServerStream'; - method_path_last = 'EchoServerStream'; - - client.echoServerStream(message, metadata, options); - }); - - it('with bidi streaming call', function(cb) { - done = cb; - var metadata = new Metadata(); - method_name = 'echoBidiStream'; - method_path_last = 'EchoBidiStream'; - - client.echoBidiStream(metadata, options); - }); - }); - - describe('pass accurate MethodDefinitions', function() { - var registry; - var initial_value = 'broken'; - var expected_value = 'working'; - var options; - before(function() { - var interceptor = function (options, nextCall) { - registry.addCall({ - path: options.method_definition.path, - requestStream: options.method_definition.requestStream, - responseStream: options.method_definition.responseStream - }); - var outbound = (new RequesterBuilder()) - .withSendMessage(function (message, next) { - message.value = expected_value; - next(message); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [interceptor] }; - }); - - it('with unary call', function(done) { - var unary_definition = { - path: '/EchoService/Echo', - requestStream: false, - responseStream: false - }; - registry = new CallRegistry(done, [ - unary_definition, - 'result_unary' - ]); - - var metadata = new Metadata(); - - var message = {value: initial_value}; - - client.echo(message, metadata, options, function(err, response){ - assert.equal(response.value, expected_value); - registry.addCall('result_unary'); - }); - - }); - it('with client streaming call', function(done) { - - var client_stream_definition = { - path: '/EchoService/EchoClientStream', - requestStream: true, - responseStream: false - }; - registry = new CallRegistry(done, [ - client_stream_definition, - 'result_client_stream' - ], false, true); - var metadata = new Metadata(); - var message = {value: initial_value}; - var client_stream = client.echoClientStream(metadata, options, - function(err, response) { - assert.strictEqual(response.value, expected_value); - registry.addCall('result_client_stream'); - }); - client_stream.write(message); - client_stream.end(); - - }); - it('with server streaming call', function(done) { - var server_stream_definition = { - path: '/EchoService/EchoServerStream', - responseStream: true, - requestStream: false, - }; - registry = new CallRegistry(done, [ - server_stream_definition, - 'result_server_stream' - ]); - - var metadata = new Metadata(); - var message = {value: initial_value}; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('data', function(data) { - assert.strictEqual(data.value, expected_value); - registry.addCall('result_server_stream'); - }); - - }); - it('with bidi streaming call', function(done) { - var bidi_stream_definition = { - path: '/EchoService/EchoBidiStream', - requestStream: true, - responseStream: true - }; - registry = new CallRegistry(done, [ - bidi_stream_definition, - 'result_bidi_stream' - ]); - - var metadata = new Metadata(); - var message = {value: initial_value}; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(data) { - assert.strictEqual(data.value, expected_value); - registry.addCall('result_bidi_stream'); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - it('uses interceptors passed to the client constructor', function(done) { - var registry = new CallRegistry(done, { - 'constructor_interceptor_a_echo': 1, - 'constructor_interceptor_b_echoServerStream': 1, - 'invocation_interceptor': 1, - 'result_unary': 1, - 'result_stream': 1, - 'result_invocation': 1 - }); - - var constructor_interceptor_a = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - registry.addCall('constructor_interceptor_a_' + - client.$method_names[options.method_definition.path]); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var constructor_interceptor_b = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - registry.addCall('constructor_interceptor_b_' + - client.$method_names[options.method_definition.path]); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var invocation_interceptor = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function(metadata, listener, next) { - registry.addCall('invocation_interceptor'); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - - var interceptor_providers = [ - function(method_definition) { - if (!method_definition.requestStream && - !method_definition.responseStream) { - return constructor_interceptor_a; - } - }, - function(method_definition) { - if (!method_definition.requestStream && - method_definition.responseStream) { - return constructor_interceptor_b; - } - } - ]; - var constructor_options = { - interceptor_providers: interceptor_providers - }; - var IntClient = grpc_client.makeClientConstructor(echo_service); - var int_client = new IntClient('localhost:' + echo_port, insecureCreds, - constructor_options); - var message = {}; - int_client.echo(message, function() { - registry.addCall('result_unary'); - }); - var stream = int_client.echoServerStream(message); - stream.on('data', function() { - registry.addCall('result_stream'); - }); - - var options = { interceptors: [invocation_interceptor] }; - int_client.echo(message, options, function() { - registry.addCall('result_invocation'); - }); - - assert(_.isEqual(grpc_client.getClientInterceptors(int_client), { - echo: [constructor_interceptor_a], - echoClientStream: [], - echoServerStream: [constructor_interceptor_b], - echoBidiStream: [] - })); - }); - - it('will reject conflicting interceptor options at invocation', - function(done) { - try { - client.echo('message', { - interceptors: [], - interceptor_providers: [] - }, function () {}); - } catch (e) { - assert.equal(e.name, 'InterceptorConfigurationError'); - done(); - } - }); - - it('will resolve interceptor providers at invocation', function(done) { - var constructor_interceptor = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function() { - assert(false); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var invocation_interceptor = function(options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function() { - done(); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var constructor_interceptor_providers = [ - function() { - return constructor_interceptor; - } - ]; - var invocation_interceptor_providers = [ - function() { - return invocation_interceptor; - } - ]; - var constructor_options = { - interceptor_providers: constructor_interceptor_providers - }; - var IntClient = grpc_client.makeClientConstructor(echo_service); - var int_client = new IntClient('localhost:' + echo_port, insecureCreds, - constructor_options); - var message = {}; - var options = { interceptor_providers: invocation_interceptor_providers }; - int_client.echo(message, options, function() {}); - }); - - describe('trigger a stack of interceptors in nested order', function() { - var registry; - var expected_calls = ['constructA', 'constructB', 'outboundA', 'outboundB', - 'inboundB', 'inboundA']; - var options; - before(function() { - var interceptor_a = function (options, nextCall) { - registry.addCall('constructA'); - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('outboundA'); - var new_listener = (new ListenerBuilder()).withOnReceiveMessage( - function (message, next) { - registry.addCall('inboundA'); - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - var interceptor_b = function (options, nextCall) { - registry.addCall('constructB'); - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('outboundB'); - var new_listener = (new ListenerBuilder()).withOnReceiveMessage( - function (message, next) { - registry.addCall('inboundB'); - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [interceptor_a, interceptor_b] }; - }); - var metadata = new Metadata(); - var message = {}; - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - client.echo(message, metadata, options, function(){}); - }); - - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var client_stream = client.echoClientStream(metadata, options, - function() {}); - client_stream.write(message); - client_stream.end(); - }); - - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var stream = client.echoServerStream(message, metadata, options); - stream.on('data', function() {}); - }); - - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(){}); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger interceptors horizontally', function() { - var expected_calls = [ - 'interceptor_a_start', - 'interceptor_b_start', - 'interceptor_a_send', - 'interceptor_b_send' - ]; - var registry; - var options; - var metadata = new Metadata(); - var message = {}; - - before(function() { - var interceptor_a = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('interceptor_a_start'); - next(metadata, listener); - }) - .withSendMessage(function (message, next) { - registry.addCall('interceptor_a_send'); - next(message); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - var interceptor_b = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - registry.addCall('interceptor_b_start'); - next(metadata, listener); - }) - .withSendMessage(function (message, next) { - registry.addCall('interceptor_b_send'); - next(message); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [interceptor_a, interceptor_b] }; - }); - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - client.echo(message, metadata, options, function(){}); - }); - - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var client_stream = client.echoClientStream(metadata, options, - function() {}); - client_stream.write(message); - client_stream.end(); - }); - - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var stream = client.echoServerStream(message, metadata, options); - stream.on('data', function() {}); - }); - - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(){}); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger when sending metadata', function() { - var registry; - - var message = {}; - var key_names = ['original', 'foo', 'bar']; - var keys = { - original: 'originalkey', - foo: 'fookey', - bar: 'barkey' - }; - var values = { - original: 'originalvalue', - foo: 'foovalue', - bar: 'barvalue' - }; - var expected_calls = ['foo', 'bar', 'response']; - var options; - before(function () { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - metadata.add(keys.foo, values.foo); - registry.addCall('foo'); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - var bar_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - metadata.add(keys.bar, values.bar); - registry.addCall('bar'); - next(metadata, listener); - }).build(); - return new InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [foo_interceptor, bar_interceptor] }; - }); - - it('with unary call', function (done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - - var unary_call = client.echo(message, metadata, options, function () {}); - unary_call.on('metadata', function (metadata) { - var has_expected_values = _.every(key_names, function (key_name) { - return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); - }); - assert(has_expected_values); - registry.addCall('response'); - }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - - var client_stream = client.echoClientStream(metadata, options, - function () { - }); - client_stream.write(message); - client_stream.on('metadata', function (metadata) { - var has_expected_values = _.every(key_names, function (key_name) { - return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); - }); - assert(has_expected_values); - registry.addCall('response'); - }); - client_stream.end(); - }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('metadata', function (metadata) { - var has_expected_values = _.every(key_names, function (key_name) { - return _.isEqual(metadata.get(keys[key_name]), [values[key_name]]); - }); - assert(has_expected_values); - registry.addCall('response'); - }); - server_stream.on('data', function() { }); - }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var metadata = new Metadata(); - metadata.add(keys.original, values.original); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('metadata', function(metadata) { - var has_expected_values = _.every(key_names, function(key_name) { - return _.isEqual(metadata.get(keys[key_name]),[values[key_name]]); - }); - assert(has_expected_values); - bidi_stream.end(); - registry.addCall('response'); - }); - bidi_stream.on('data', function() { }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger when sending messages', function() { - var registry; - var originalValue = 'foo'; - var expectedValue = 'bar'; - var options; - var metadata = new Metadata(); - var expected_calls = ['messageIntercepted', 'response']; - - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withSendMessage(function (message, next) { - assert.strictEqual(message.value, originalValue); - registry.addCall('messageIntercepted'); - next({ value: expectedValue }); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - - it('with unary call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - - client.echo(message, metadata, options, function (err, response) { - assert.strictEqual(response.value, expectedValue); - registry.addCall('response'); - }); - }); - it('with client streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - var client_stream = client.echoClientStream(metadata, options, - function (err, response) { - assert.strictEqual(response.value, expectedValue); - registry.addCall('response'); - }); - client_stream.write(message); - client_stream.end(); - }); - it('with server streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('data', function (data) { - assert.strictEqual(data.value, expectedValue); - registry.addCall('response'); - }); - }); - it('with bidi streaming call', function(done) { - registry = new CallRegistry(done, expected_calls, true); - var message = {value: originalValue}; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function(data) { - assert.strictEqual(data.value, expectedValue); - registry.addCall('response'); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger when client closes the call', function() { - var registry; - var expected_calls = [ - 'response', 'halfClose' - ]; - var message = {}; - var options; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withHalfClose(function (next) { - registry.addCall('halfClose'); - next(); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - it('with unary call', function (done) { - registry = new CallRegistry(done, expected_calls); - client.echo(message, options, function (err, response) { - if (!err) { - registry.addCall('response'); - } - }); - }); - it('with client streaming call', function (done) { - registry = new CallRegistry(done, expected_calls); - var client_stream = client.echoClientStream(options, - function (err, response) { }); - client_stream.write(message, function (err) { - if (!err) { - registry.addCall('response'); - } - }); - client_stream.end(); - }); - it('with server streaming call', function (done) { - registry = new CallRegistry(done, expected_calls); - var server_stream = client.echoServerStream(message, options); - server_stream.on('data', function (data) { - registry.addCall('response'); - }); - }); - it('with bidi streaming call', function (done) { - registry = new CallRegistry(done, expected_calls); - var bidi_stream = client.echoBidiStream(options); - bidi_stream.on('data', function (data) { - registry.addCall('response'); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger when the stream is canceled', function() { - var done; - var message = {}; - var options; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withCancel(function (next) { - done(); - next(); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - - it('with unary call', function(cb) { - done = cb; - var stream = client.echo(message, options, function() {}); - stream.cancel(); - }); - - it('with client streaming call', function(cb) { - done = cb; - var stream = client.echoClientStream(options, function() {}); - stream.cancel(); - }); - it('with server streaming call', function(cb) { - done = cb; - var stream = client.echoServerStream(message, options); - stream.cancel(); - }); - it('with bidi streaming call', function(cb) { - done = cb; - var stream = client.echoBidiStream(options); - stream.cancel(); - }); - }); - - describe('trigger when receiving metadata', function() { - var message = {}; - var expectedKey = 'foo'; - var expectedValue = 'bar'; - var options; - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()).withOnReceiveMetadata( - function (metadata, next) { - metadata.add(expectedKey, expectedValue); - next(metadata); - }).build(); - next(metadata, new_listener); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - - it('with unary call', function(done) { - var metadata = new Metadata(); - var unary_call = client.echo(message, metadata, options, function () {}); - unary_call.on('metadata', function (metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - done(); - }); - }); - it('with client streaming call', function(done) { - var metadata = new Metadata(); - var client_stream = client.echoClientStream(metadata, options, - function () {}); - client_stream.write(message); - client_stream.on('metadata', function (metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - done(); - }); - client_stream.end(); - }); - it('with server streaming call', function(done) { - var metadata = new Metadata(); - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('metadata', function (metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - done(); - }); - server_stream.on('data', function() { }); - }); - it('with bidi streaming call', function(done) { - var metadata = new Metadata(); - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('metadata', function(metadata) { - assert.strictEqual(metadata.get(expectedKey)[0], expectedValue); - bidi_stream.end(); - done(); - }); - bidi_stream.on('data', function() { }); - bidi_stream.write(message); - }); - }); - - describe('trigger when sending messages', function() { - var originalValue = 'foo'; - var expectedValue = 'bar'; - var options; - var metadata = new Metadata(); - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()).withOnReceiveMessage( - function (message, next) { - if (!message) { - next(message); - return; - } - assert.strictEqual(message.value, originalValue); - message.value = expectedValue; - next(message); - }).build(); - next(metadata, new_listener); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - - it('with unary call', function (done) { - var message = { value: originalValue }; - client.echo(message, metadata, options, function (err, response) { - assert.strictEqual(response.value, expectedValue); - done(); - }); - }); - it('with client streaming call', function (done) { - var message = { value: originalValue }; - var client_stream = client.echoClientStream(metadata, options, - function (err, response) { - assert.strictEqual(response.value, expectedValue); - done(); - }); - client_stream.write(message); - client_stream.end(); - }); - it('with server streaming call', function (done) { - var message = { value: originalValue }; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('data', function (data) { - assert.strictEqual(data.value, expectedValue); - done(); - }); - }); - it('with bidi streaming call', function (done) { - var message = { value: originalValue }; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('data', function (data) { - assert.strictEqual(data.value, expectedValue); - done(); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('trigger when receiving status', function() { - var expectedStatus = 'foo'; - var options; - var metadata = new Metadata(); - before(function() { - var foo_interceptor = function (options, nextCall) { - var outbound = (new RequesterBuilder()) - .withStart(function (metadata, listener, next) { - var new_listener = (new ListenerBuilder()).withOnReceiveStatus( - function (status, next) { - assert.strictEqual(status.code, 2); - assert.strictEqual(status.details, 'test status message'); - var new_status = { - code: 1, - details: expectedStatus, - metadata: {} - }; - next(new_status); - }).build(); - next(metadata, new_listener); - }).build(); - return new grpc_client.InterceptingCall(nextCall(options), - outbound); - }; - options = { interceptors: [foo_interceptor] }; - }); - it('with unary call', function (done) { - var message = { value: 'error' }; - var unary_call = client.echo(message, metadata, options, function () { - }); - unary_call.on('status', function (status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); - }); - }); - it('with client streaming call', function (done) { - var message = { value: 'error' }; - var client_stream = client.echoClientStream(metadata, options, - function () { - }); - client_stream.on('status', function (status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); - }); - client_stream.write(message); - client_stream.end(); - }); - - it('with server streaming call', function(done) { - var message = {value: 'error'}; - var server_stream = client.echoServerStream(message, metadata, options); - server_stream.on('error', function (err) { - }); - server_stream.on('data', function (data) { - }); - server_stream.on('status', function (status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); - }); - }); - - it('with bidi streaming call', function(done) { - var message = {value: 'error'}; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('error', function(err) {}); - bidi_stream.on('data', function(data) {}); - bidi_stream.on('status', function(status) { - assert.strictEqual(status.code, 1); - assert.strictEqual(status.details, expectedStatus); - done(); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - describe('delay streaming headers', function() { - var options; - var metadata = new Metadata(); - before(function() { - var foo_interceptor = function (options, nextCall) { - var startNext; - var startListener; - var startMetadata; - var methods = { - start: function (metadata, listener, next) { - startNext = next; - startListener = listener; - startMetadata = metadata; - }, - sendMessage: function (message, next) { - startMetadata.set('fromMessage', message.value); - startNext(startMetadata, startListener); - next(message); - } - }; - return new grpc_client.InterceptingCall(nextCall(options), methods); - }; - options = { interceptors: [foo_interceptor] }; - }); - - it('with client streaming call', function (done) { - var message = { value: 'foo' }; - var client_stream = client.echoClientStream(metadata, options, - function () { }); - client_stream.on('metadata', function (metadata) { - assert.equal(metadata.get('fromMessage'), 'foo'); - done(); - }); - client_stream.write(message); - client_stream.end(); - }); - it('with bidi streaming call', function (done) { - var message = { value: 'foo' }; - var bidi_stream = client.echoBidiStream(metadata, options); - bidi_stream.on('metadata', function (metadata) { - assert.equal(metadata.get('fromMessage'), 'foo'); - done(); - }); - bidi_stream.write(message); - bidi_stream.end(); - }); - }); - - describe('order of operations enforced for async interceptors', function() { - it('with unary call', function(done) { - var expected_calls = [ - 'close_b', - 'message_b', - 'start_b', - 'done' - ]; - var registry = new CallRegistry(done, expected_calls, true); - var message = {value: 'foo'}; - var interceptor_a = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - setTimeout(function() { next(metadata, listener); }, 50); - }, - sendMessage: function(message, next) { - setTimeout(function () { next(message); }, 10); - } - }); - }; - var interceptor_b = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - registry.addCall('start_b'); - next(metadata, listener); - }, - sendMessage: function(message, next) { - registry.addCall('message_b'); - next(message); - }, - halfClose: function(next) { - registry.addCall('close_b'); - next(); - } - }); - }; - var options = { - interceptors: [interceptor_a, interceptor_b] - }; - client.echo(message, options, function(err, response) { - assert.strictEqual(err, null); - registry.addCall('done'); - }); - }); - it('with serverStreaming call', function(done) { - var expected_calls = [ - 'close_b', - 'message_b', - 'start_b', - 'done' - ]; - var registry = new CallRegistry(done, expected_calls, true); - var message = {value: 'foo'}; - var interceptor_a = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - setTimeout(function() { next(metadata, listener); }, 50); - }, - sendMessage: function(message, next) { - setTimeout(function () { next(message); }, 10); - } - }); - }; - var interceptor_b = function(options, nextCall) { - return new InterceptingCall(nextCall(options), { - start: function(metadata, listener, next) { - registry.addCall('start_b'); - next(metadata, listener); - }, - sendMessage: function(message, next) { - registry.addCall('message_b'); - next(message); - }, - halfClose: function(next) { - registry.addCall('close_b'); - next(); - } - }); - }; - var options = { - interceptors: [interceptor_a, interceptor_b] - }; - var stream = client.echoServerStream(message, options); - stream.on('data', function(response) { - assert.strictEqual(response.value, 'foo'); - registry.addCall('done'); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/common_test.js b/packages/grpc-native-core/test/common_test.js deleted file mode 100644 index 441392b13..000000000 --- a/packages/grpc-native-core/test/common_test.js +++ /dev/null @@ -1,189 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); - -var common = require('../src/common'); -var protobuf_js_5_common = require('../src/protobuf_js_5_common'); - -var serializeCls = protobuf_js_5_common.serializeCls; -var deserializeCls = protobuf_js_5_common.deserializeCls; - -var ProtoBuf = require('protobufjs'); - -var messages_proto = ProtoBuf.loadProtoFile( - __dirname + '/test_messages.proto').build(); - -var default_options = common.defaultGrpcOptions; - -describe('Proto message long int serialize and deserialize', function() { - var longSerialize = serializeCls(messages_proto.LongValues); - var longDeserialize = deserializeCls(messages_proto.LongValues, - default_options); - var pos_value = '314159265358979'; - var neg_value = '-27182818284590'; - it('should preserve positive int64 values', function() { - var serialized = longSerialize({int_64: pos_value}); - assert.strictEqual(longDeserialize(serialized).int_64.toString(), - pos_value); - }); - it('should preserve negative int64 values', function() { - var serialized = longSerialize({int_64: neg_value}); - assert.strictEqual(longDeserialize(serialized).int_64.toString(), - neg_value); - }); - it('should preserve uint64 values', function() { - var serialized = longSerialize({uint_64: pos_value}); - assert.strictEqual(longDeserialize(serialized).uint_64.toString(), - pos_value); - }); - it('should preserve positive sint64 values', function() { - var serialized = longSerialize({sint_64: pos_value}); - assert.strictEqual(longDeserialize(serialized).sint_64.toString(), - pos_value); - }); - it('should preserve negative sint64 values', function() { - var serialized = longSerialize({sint_64: neg_value}); - assert.strictEqual(longDeserialize(serialized).sint_64.toString(), - neg_value); - }); - it('should preserve fixed64 values', function() { - var serialized = longSerialize({fixed_64: pos_value}); - assert.strictEqual(longDeserialize(serialized).fixed_64.toString(), - pos_value); - }); - it('should preserve positive sfixed64 values', function() { - var serialized = longSerialize({sfixed_64: pos_value}); - assert.strictEqual(longDeserialize(serialized).sfixed_64.toString(), - pos_value); - }); - it('should preserve negative sfixed64 values', function() { - var serialized = longSerialize({sfixed_64: neg_value}); - assert.strictEqual(longDeserialize(serialized).sfixed_64.toString(), - neg_value); - }); - it('should deserialize as a number with the right option set', function() { - var num_options = Object.assign({}, default_options, {longsAsStrings: false}); - var longNumDeserialize = deserializeCls(messages_proto.LongValues, - num_options); - var serialized = longSerialize({int_64: pos_value}); - assert.strictEqual(typeof longDeserialize(serialized).int_64, 'string'); - /* With the longsAsStrings option disabled, long values are represented as - * objects with 3 keys: low, high, and unsigned */ - assert.strictEqual(typeof longNumDeserialize(serialized).int_64, 'object'); - }); -}); -describe('Proto message bytes serialize and deserialize', function() { - var sequenceSerialize = serializeCls(messages_proto.SequenceValues); - var sequenceDeserialize = deserializeCls( - messages_proto.SequenceValues, default_options); - var b64_options = Object.assign({}, default_options, {binaryAsBase64: true}); - var sequenceBase64Deserialize = deserializeCls( - messages_proto.SequenceValues, b64_options); - var buffer_val = Buffer.from([0x69, 0xb7]); - var base64_val = 'abc='; - it('should preserve a buffer', function() { - var serialized = sequenceSerialize({bytes_field: buffer_val}); - var deserialized = sequenceDeserialize(serialized); - assert.strictEqual(deserialized.bytes_field.compare(buffer_val), 0); - }); - it('should accept base64 encoded strings', function() { - var serialized = sequenceSerialize({bytes_field: base64_val}); - var deserialized = sequenceDeserialize(serialized); - assert.strictEqual(deserialized.bytes_field.compare(buffer_val), 0); - }); - it('should output base64 encoded strings with an option set', function() { - var serialized = sequenceSerialize({bytes_field: base64_val}); - var deserialized = sequenceBase64Deserialize(serialized); - assert.strictEqual(deserialized.bytes_field, base64_val); - }); - it('should serialize a repeated field as packed by default', function() { - var expected_serialize = Buffer.from([0x12, 0x01, 0x0a]); - var serialized = sequenceSerialize({repeated_field: [10]}); - assert.strictEqual(expected_serialize.compare(serialized), 0); - }); - // This tests a bug that was fixed in Protobuf.js 6 - it.skip('should deserialize packed or unpacked repeated', function() { - var expectedDeserialize = { - bytes_field: Buffer.alloc(''), - repeated_field: [10] - }; - var packedSerialized = Buffer.from([0x12, 0x01, 0x0a]); - var unpackedSerialized = Buffer.from([0x10, 0x0a]); - var packedDeserialized; - var unpackedDeserialized; - assert.doesNotThrow(function() { - packedDeserialized = sequenceDeserialize(packedSerialized); - }); - assert.doesNotThrow(function() { - unpackedDeserialized = sequenceDeserialize(unpackedSerialized); - }); - assert.deepEqual(packedDeserialized, expectedDeserialize); - assert.deepEqual(unpackedDeserialized, expectedDeserialize); - }); -}); -// This tests a bug that was fixed in Protobuf.js 6 -describe.skip('Proto message oneof serialize and deserialize', function() { - var oneofSerialize = serializeCls(messages_proto.OneOfValues); - var oneofDeserialize = deserializeCls( - messages_proto.OneOfValues, default_options); - it('Should have idempotent round trips', function() { - var test_message = {oneof_choice: 'int_choice', int_choice: 5}; - var serialized1 = oneofSerialize(test_message); - var deserialized1 = oneofDeserialize(serialized1); - assert.equal(deserialized1.int_choice, 5); - var serialized2 = oneofSerialize(deserialized1); - var deserialized2 = oneofDeserialize(serialized2); - assert.deepEqual(deserialized1, deserialized2); - }); - it('Should emit a property indicating which field was chosen', function() { - var test_message1 = {oneof_choice: 'int_choice', int_choice: 5}; - var serialized1 = oneofSerialize(test_message1); - var deserialized1 = oneofDeserialize(serialized1); - assert.equal(deserialized1.oneof_choice, 'int_choice'); - var test_message2 = {oneof_choice: 'string_choice', string_choice: 'abc'}; - var serialized2 = oneofSerialize(test_message2); - var deserialized2 = oneofDeserialize(serialized2); - assert.equal(deserialized2.oneof_choice, 'string_choice'); - }); -}); -describe('Proto message enum serialize and deserialize', function() { - var enumSerialize = serializeCls(messages_proto.EnumValues); - var enumDeserialize = deserializeCls( - messages_proto.EnumValues, default_options); - var enumIntOptions = Object.assign({}, default_options, {enumsAsStrings: false}); - var enumIntDeserialize = deserializeCls( - messages_proto.EnumValues, enumIntOptions); - it('Should accept both names and numbers', function() { - var nameSerialized = enumSerialize({enum_value: 'ONE'}); - var numberSerialized = enumSerialize({enum_value: 1}); - assert.strictEqual(messages_proto.TestEnum.ONE, 1); - assert.deepEqual(enumDeserialize(nameSerialized), - enumDeserialize(numberSerialized)); - }); - // This tests a bug that was fixed in Protobuf.js 6 - it.skip('Should correctly handle the enumsAsStrings option', function() { - var serialized = enumSerialize({enum_value: 'TWO'}); - var nameDeserialized = enumDeserialize(serialized); - var numberDeserialized = enumIntDeserialize(serialized); - assert.deepEqual(nameDeserialized, {enum_value: 'TWO'}); - assert.deepEqual(numberDeserialized, {enum_value: 2}); - }); -}); diff --git a/packages/grpc-native-core/test/credentials_test.js b/packages/grpc-native-core/test/credentials_test.js deleted file mode 100644 index 1c0fe9a13..000000000 --- a/packages/grpc-native-core/test/credentials_test.js +++ /dev/null @@ -1,524 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var fs = require('fs'); -var path = require('path'); -var forge = require('node-forge'); - -var grpc = require('..'); - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} - -var fakeSuccessfulGoogleCredentials = { - getRequestMetadata: function(service_url, callback) { - setTimeout(function() { - callback(null, {Authorization: 'success'}); - }, 0); - } -}; - -var fakeFailingGoogleCredentials = { - getRequestMetadata: function(service_url, callback) { - setTimeout(function() { - // Google credentials currently adds string error codes to auth errors - var error = new Error('Authentication failure'); - error.code = 'ENOENT'; - callback(error); - }, 0); - } -}; - -var key_data, pem_data, ca_data; - -before(function() { - var key_path = path.join(__dirname, '/data/server1.key'); - var pem_path = path.join(__dirname, '/data/server1.pem'); - var ca_path = path.join(__dirname, '/data/ca.pem'); - key_data = fs.readFileSync(key_path); - pem_data = fs.readFileSync(pem_path); - ca_data = fs.readFileSync(ca_path); -}); - -describe('channel credentials', function() { - describe('#createSsl', function() { - it('works with no arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(); - }); - assert.notEqual(creds, null); - }); - it('works with just one Buffer argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data); - }); - assert.notEqual(creds, null); - }); - it('works with 3 Buffer arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('works if the first argument is null', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(null, key_data, pem_data); - }); - assert.notEqual(creds, null); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl('test'); - }, TypeError); - }); - it('fails if the second argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, 'test', pem_data); - }, TypeError); - }); - it('fails if the third argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data, 'test'); - }, TypeError); - }); - it('fails if only 1 of the last 2 arguments is provided', function() { - assert.throws(function() { - grpc.credentials.createSsl(null, key_data); - }); - assert.throws(function() { - grpc.credentials.createSsl(null, null, pem_data); - }); - }); - it('works if the fourth argument is an empty object', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.credentials.createSsl(ca_data, null, null, {}); - }); - assert.notEqual(creds, null); - }); - it('fails if the fourth argument is a non-object value', function() { - assert.throws(function() { - grpc.credentials.createSsl(ca_data, null, null, 'test'); - }, TypeError); - }); - it('fails if the checkServerIdentity is a non-function', function() { - assert.throws(function() { - grpc.credentials.createSsl(ca_data, null, null, { - "checkServerIdentity": 'test' - }); - }, TypeError); - }); - }); -}); - -describe('server credentials', function() { - describe('#createSsl', function() { - it('accepts a buffer and array as the first 2 arguments', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, []); - }); - assert.notEqual(creds, null); - }); - it('accepts a boolean as the third argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(ca_data, [], true); - }); - assert.notEqual(creds, null); - }); - it('accepts an object with two buffers in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('accepts multiple objects in the second argument', function() { - var creds; - assert.doesNotThrow(function() { - creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}, - {private_key: key_data, - cert_chain: pem_data}]); - }); - assert.notEqual(creds, null); - }); - it('fails if the second argument is not an Array', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the first argument is a non-Buffer value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl('test', []); - }, TypeError); - }); - it('fails if the third argument is a non-boolean value', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, [], 'test'); - }, TypeError); - }); - it('fails if the array elements are not objects', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(ca_data, 'test'); - }, TypeError); - }); - it('fails if the object does not have a Buffer private_key', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: 'test', - cert_chain: pem_data}]); - }, TypeError); - }); - it('fails if the object does not have a Buffer cert_chain', function() { - assert.throws(function() { - grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: 'test'}]); - }, TypeError); - }); - }); -}); - -describe('client credentials', function() { - var Client; - var server; - var port; - var client_ssl_creds; - var client_options = {}; - before(function() { - var proto = grpc.load(__dirname + '/test_service.proto'); - server = new grpc.Server(); - server.addService(proto.TestService.service, { - unary: function(call, cb) { - call.sendMetadata(call.metadata); - cb(null, {}); - }, - clientStream: function(stream, cb){ - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.sendMetadata(stream.metadata); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - stream.end(); - }); - } - }); - var creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - port = server.bind('localhost:0', creds); - server.start(); - - Client = proto.TestService; - client_ssl_creds = grpc.credentials.createSsl(ca_data); - var host_override = 'foo.test.google.fr'; - client_options['grpc.ssl_target_name_override'] = host_override; - client_options['grpc.default_authority'] = host_override; - }); - after(function() { - server.forceShutdown(); - }); - it('Should accept SSL creds for a client', function(done) { - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - client.unary({}, function(err, data) { - assert.ifError(err); - done(); - }); - }); - it('Verify callback receives correct arguments', function(done) { - var callback_host, callback_cert; - var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { - "checkServerIdentity": function(host, cert) { - callback_host = host; - callback_cert = cert; - } - }); - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - client.unary({}, function(err, data) { - assert.ifError(err); - assert.equal(callback_host, 'foo.test.google.fr'); - - // The roundabout forge APIs for converting PEM to a node DER Buffer - var expected_der = Buffer.from(forge.asn1.toDer( - forge.pki.certificateToAsn1(forge.pki.certificateFromPem(pem_data))) - .getBytes(), 'binary'); - - // Assert the buffers are equal by converting them to hex strings - assert.equal(callback_cert.raw.toString('hex'), expected_der.toString('hex')); - // Documented behavior of callback cert is that raw should be its only property - assert.equal(Object.keys(callback_cert).length, 1); - done(); - }); - }); - it('Verify callback exception causes connection failure', function(done) { - var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { - "checkServerIdentity": function(host, cert) { - throw "Verification callback exception"; - } - }); - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - client.unary({}, function(err, data) { - assert.ok(err, "Should have raised an error"); - done(); - }); - }); - it('Verify callback returning an Error causes connection failure', function(done) { - var client_ssl_creds = grpc.credentials.createSsl(ca_data, null, null, { - "checkServerIdentity": function(host, cert) { - return new Error("Verification error"); - } - }); - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - client.unary({}, function(err, data) { - assert.ok(err, "Should have raised an error"); - done(); - }); - }); - it('Should update metadata with SSL creds', function(done) { - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('Should update metadata for two simultaneous calls', function(done) { - done = multiDone(done, 2); - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - var call2 = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call2.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('should fail the call if the updater fails', function(done) { - var metadataUpdater = function(service_url, callback) { - var error = new Error('Authentication error'); - error.code = grpc.status.UNAUTHENTICATED; - callback(error); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.details, - 'Getting metadata from plugin failed with error: ' + - 'Authentication error'); - assert.notStrictEqual(err.code, grpc.status.OK); - done(); - }); - }); - it('should successfully wrap a Google credential', function(done) { - var creds = grpc.credentials.createFromGoogleCredential( - fakeSuccessfulGoogleCredentials); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('authorization'), ['success']); - done(); - }); - }); - it('Should not add metadata with just SSL credentials', function(done) { - // Tests idempotency of credentials composition - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater); - grpc.credentials.combineChannelCredentials(client_ssl_creds, creds); - var client = new Client('localhost:' + port, client_ssl_creds, - client_options); - var call = client.unary({}, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), []); - done(); - }); - }); - it('should get an error from a Google credential', function(done) { - var creds = grpc.credentials.createFromGoogleCredential( - fakeFailingGoogleCredentials); - var combined_creds = grpc.credentials.combineChannelCredentials( - client_ssl_creds, creds); - var client = new Client('localhost:' + port, combined_creds, - client_options); - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.details, - 'Getting metadata from plugin failed with error: ' + - 'Authentication failure'); - done(); - }); - }); - describe('Per-rpc creds', function() { - var client; - var updater_creds; - before(function() { - client = new Client('localhost:' + port, client_ssl_creds, - client_options); - var metadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('plugin_key', 'plugin_value'); - callback(null, metadata); - }; - updater_creds = grpc.credentials.createFromMetadataGenerator( - metadataUpdater); - }); - it('Should update metadata on a unary call', function(done) { - var call = client.unary({}, {credentials: updater_creds}, - function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('should update metadata on a client streaming call', function(done) { - var call = client.clientStream({credentials: updater_creds}, - function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - call.end(); - }); - it('should update metadata on a server streaming call', function(done) { - var call = client.serverStream({}, {credentials: updater_creds}); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - }); - it('should update metadata on a bidi streaming call', function(done) { - var call = client.bidiStream({credentials: updater_creds}); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - done(); - }); - call.end(); - }); - it('should be able to use multiple plugin credentials', function(done) { - var altMetadataUpdater = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.set('other_plugin_key', 'other_plugin_value'); - callback(null, metadata); - }; - var alt_updater_creds = grpc.credentials.createFromMetadataGenerator( - altMetadataUpdater); - var combined_updater = grpc.credentials.combineCallCredentials( - updater_creds, alt_updater_creds); - var call = client.unary({}, {credentials: combined_updater}, - function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('plugin_key'), ['plugin_value']); - assert.deepEqual(metadata.get('other_plugin_key'), - ['other_plugin_value']); - done(); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/data/README b/packages/grpc-native-core/test/data/README deleted file mode 100644 index 888d95b90..000000000 --- a/packages/grpc-native-core/test/data/README +++ /dev/null @@ -1 +0,0 @@ -CONFIRMEDTESTKEY diff --git a/packages/grpc-native-core/test/data/ca.pem b/packages/grpc-native-core/test/data/ca.pem deleted file mode 100644 index 6c8511a73..000000000 --- a/packages/grpc-native-core/test/data/ca.pem +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICSjCCAbOgAwIBAgIJAJHGGR4dGioHMA0GCSqGSIb3DQEBCwUAMFYxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQxDzANBgNVBAMTBnRlc3RjYTAeFw0xNDExMTEyMjMxMjla -Fw0yNDExMDgyMjMxMjlaMFYxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 -YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxDzANBgNVBAMT -BnRlc3RjYTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwEDfBV5MYdlHVHJ7 -+L4nxrZy7mBfAVXpOc5vMYztssUI7mL2/iYujiIXM+weZYNTEpLdjyJdu7R5gGUu -g1jSVK/EPHfc74O7AyZU34PNIP4Sh33N+/A5YexrNgJlPY+E3GdVYi4ldWJjgkAd -Qah2PH5ACLrIIC6tRka9hcaBlIECAwEAAaMgMB4wDAYDVR0TBAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADgYEAHzC7jdYlzAVmddi/gdAeKPau -sPBG/C2HCWqHzpCUHcKuvMzDVkY/MP2o6JIW2DBbY64bO/FceExhjcykgaYtCH/m -oIU63+CFOTtR7otyQAWHqXa7q4SbCDlG7DyRFxqG0txPtGvy12lgldA2+RgcigQG -Dfcog5wrJytaQ6UA0wE= ------END CERTIFICATE----- diff --git a/packages/grpc-native-core/test/data/server1.key b/packages/grpc-native-core/test/data/server1.key deleted file mode 100644 index 143a5b876..000000000 --- a/packages/grpc-native-core/test/data/server1.key +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAOHDFScoLCVJpYDD -M4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1BgzkWF+slf -3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd9N8YwbBY -AckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAECgYAn7qGnM2vbjJNBm0VZCkOkTIWm -V10okw7EPJrdL2mkre9NasghNXbE1y5zDshx5Nt3KsazKOxTT8d0Jwh/3KbaN+YY -tTCbKGW0pXDRBhwUHRcuRzScjli8Rih5UOCiZkhefUTcRb6xIhZJuQy71tjaSy0p -dHZRmYyBYO2YEQ8xoQJBAPrJPhMBkzmEYFtyIEqAxQ/o/A6E+E4w8i+KM7nQCK7q -K4JXzyXVAjLfyBZWHGM2uro/fjqPggGD6QH1qXCkI4MCQQDmdKeb2TrKRh5BY1LR -81aJGKcJ2XbcDu6wMZK4oqWbTX2KiYn9GB0woM6nSr/Y6iy1u145YzYxEV/iMwff -DJULAkB8B2MnyzOg0pNFJqBJuH29bKCcHa8gHJzqXhNO5lAlEbMK95p/P2Wi+4Hd -aiEIAF1BF326QJcvYKmwSmrORp85AkAlSNxRJ50OWrfMZnBgzVjDx3xG6KsFQVk2 -ol6VhqL6dFgKUORFUWBvnKSyhjJxurlPEahV6oo6+A+mPhFY8eUvAkAZQyTdupP3 -XEFQKctGz+9+gKkemDp7LBBMEMBXrGTLPhpEfcjv/7KPdnFHYmhYeBTBnuVmTVWe -F98XJ7tIFfJq ------END PRIVATE KEY----- diff --git a/packages/grpc-native-core/test/data/server1.pem b/packages/grpc-native-core/test/data/server1.pem deleted file mode 100644 index f3d43fcc5..000000000 --- a/packages/grpc-native-core/test/data/server1.pem +++ /dev/null @@ -1,16 +0,0 @@ ------BEGIN CERTIFICATE----- -MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET -MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx -MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV -BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50 -ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco -LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg -zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd -9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw -CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy -em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G -CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6 -hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh -y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8 ------END CERTIFICATE----- diff --git a/packages/grpc-native-core/test/echo_service.proto b/packages/grpc-native-core/test/echo_service.proto deleted file mode 100644 index 414b421ec..000000000 --- a/packages/grpc-native-core/test/echo_service.proto +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright 2018 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -syntax = "proto3"; - -message EchoMessage { - string value = 1; - int32 value2 = 2; -} - -service EchoService { - rpc Echo (EchoMessage) returns (EchoMessage); - - rpc EchoClientStream (stream EchoMessage) returns (EchoMessage); - - rpc EchoServerStream (EchoMessage) returns (stream EchoMessage); - - rpc EchoBidiStream (stream EchoMessage) returns (stream EchoMessage); -} diff --git a/packages/grpc-native-core/test/end_to_end_test.js b/packages/grpc-native-core/test/end_to_end_test.js deleted file mode 100644 index ae165b14e..000000000 --- a/packages/grpc-native-core/test/end_to_end_test.js +++ /dev/null @@ -1,305 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var grpc = require('../src/grpc_extension'); -var constants = require('../src/constants'); - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} - -var insecureCreds = grpc.ChannelCredentials.createInsecure(); - -describe('end-to-end', function() { - var server; - var channel; - before(function() { - server = new grpc.Server(); - var port_num = server.addHttp2Port('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - server.start(); - channel = new grpc.Channel('localhost:' + port_num, insecureCreds); - }); - after(function() { - server.forceShutdown(); - }); - it('should start and end a request without error', function(complete) { - var done = multiDone(complete, 2); - var status_text = 'xyz'; - var call = channel.createCall( - 'dummy_method', - Infinity); - var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; - client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(client_batch, function(err, response) { - assert.ifError(err); - assert.deepEqual(response, { - send_metadata: true, - client_close: true, - metadata: { - metadata: {}, - flags: 0 - }, - status: { - code: constants.status.OK, - details: status_text, - metadata: { - metadata: {}, - flags: 0 - } - } - }); - done(); - }); - - server.requestCall(function(err, call_details) { - var new_call = call_details.new_call; - assert.notEqual(new_call, null); - var server_call = new_call.call; - assert.notEqual(server_call, null); - var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; - server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {metadata: {}}, - code: constants.status.OK, - details: status_text - }; - server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - server_call.startBatch(server_batch, function(err, response) { - assert.ifError(err); - assert.deepEqual(response, { - send_metadata: true, - send_status: true, - cancelled: false - }); - done(); - }); - }); - }); - it('should successfully send and receive metadata', function(complete) { - var done = multiDone(complete, 2); - var status_text = 'xyz'; - var call = channel.createCall( - 'dummy_method', - Infinity); - var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = { - metadata: { - client_key: ['client_value'] - } - }; - client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(client_batch, function(err, response) { - assert.ifError(err); - assert.deepEqual(response,{ - send_metadata: true, - client_close: true, - metadata: {metadata: { - server_key: ['server_value']}, - flags: 0 - }, - status: {code: constants.status.OK, - details: status_text, - metadata: {metadata: {}, flags: 0}} - }); - done(); - }); - - server.requestCall(function(err, call_details) { - var new_call = call_details.new_call; - assert.notEqual(new_call, null); - assert.strictEqual(new_call.metadata.metadata.client_key[0], - 'client_value'); - var server_call = new_call.call; - assert.notEqual(server_call, null); - var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = { - metadata: { - server_key: ['server_value'] - } - }; - server_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {metadata: {}}, - code: constants.status.OK, - details: status_text - }; - server_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - server_call.startBatch(server_batch, function(err, response) { - assert.ifError(err); - assert.deepEqual(response, { - send_metadata: true, - send_status: true, - cancelled: false - }); - done(); - }); - }); - }); - it('should send and receive data without error', function(complete) { - var req_text = 'client_request'; - var reply_text = 'server_response'; - var done = multiDone(complete, 2); - var status_text = 'success'; - var call = channel.createCall( - 'dummy_method', - Infinity); - var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; - client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(req_text); - client_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - client_batch[grpc.opType.RECV_MESSAGE] = true; - client_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(client_batch, function(err, response) { - assert.ifError(err); - assert(response.send_metadata); - assert(response.client_close); - assert.deepEqual(response.metadata, {metadata: {}, flags: 0}); - assert(response.send_message); - assert.strictEqual(response.read.toString(), reply_text); - assert.deepEqual(response.status, {code: constants.status.OK, - details: status_text, - metadata: {metadata: {}, flags: 0}}); - done(); - }); - - server.requestCall(function(err, call_details) { - var new_call = call_details.new_call; - assert.notEqual(new_call, null); - var server_call = new_call.call; - assert.notEqual(server_call, null); - var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; - server_batch[grpc.opType.RECV_MESSAGE] = true; - server_call.startBatch(server_batch, function(err, response) { - assert.ifError(err); - assert(response.send_metadata); - assert.strictEqual(response.read.toString(), req_text); - var response_batch = {}; - response_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(reply_text); - response_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {metadata: {}}, - code: constants.status.OK, - details: status_text - }; - response_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - server_call.startBatch(response_batch, function(err, response) { - assert(response.send_status); - assert(!response.cancelled); - done(); - }); - }); - }); - }); - it('should send multiple messages', function(complete) { - var done = multiDone(complete, 2); - var requests = ['req1', 'req2']; - var status_text = 'xyz'; - var call = channel.createCall( - 'dummy_method', - Infinity); - var client_batch = {}; - client_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; - client_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[0]); - client_batch[grpc.opType.RECV_INITIAL_METADATA] = true; - call.startBatch(client_batch, function(err, response) { - assert.ifError(err); - assert.deepEqual(response, { - send_metadata: true, - send_message: true, - metadata: {metadata: {}, flags: 0} - }); - var req2_batch = {}; - req2_batch[grpc.opType.SEND_MESSAGE] = Buffer.from(requests[1]); - req2_batch[grpc.opType.SEND_CLOSE_FROM_CLIENT] = true; - req2_batch[grpc.opType.RECV_STATUS_ON_CLIENT] = true; - call.startBatch(req2_batch, function(err, resp) { - assert.ifError(err); - assert.deepEqual(resp, { - send_message: true, - client_close: true, - status: { - code: constants.status.OK, - details: status_text, - metadata: {metadata: {}, flags: 0} - } - }); - done(); - }); - }); - - server.requestCall(function(err, call_details) { - var new_call = call_details.new_call; - assert.notEqual(new_call, null); - var server_call = new_call.call; - assert.notEqual(server_call, null); - var server_batch = {}; - server_batch[grpc.opType.SEND_INITIAL_METADATA] = {metadata: {}}; - server_batch[grpc.opType.RECV_MESSAGE] = true; - server_call.startBatch(server_batch, function(err, response) { - assert.ifError(err); - assert(response.send_metadata); - assert.strictEqual(response.read.toString(), requests[0]); - var snd_batch = {}; - snd_batch[grpc.opType.RECV_MESSAGE] = true; - server_call.startBatch(snd_batch, function(err, response) { - assert.ifError(err); - assert.strictEqual(response.read.toString(), requests[1]); - var end_batch = {}; - end_batch[grpc.opType.RECV_CLOSE_ON_SERVER] = true; - end_batch[grpc.opType.SEND_STATUS_FROM_SERVER] = { - metadata: {metadata: {}}, - code: constants.status.OK, - details: status_text - }; - server_call.startBatch(end_batch, function(err, response) { - assert.ifError(err); - assert(response.send_status); - assert(!response.cancelled); - done(); - }); - }); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/math/math_grpc_pb.js b/packages/grpc-native-core/test/math/math_grpc_pb.js deleted file mode 100644 index 1daf04b95..000000000 --- a/packages/grpc-native-core/test/math/math_grpc_pb.js +++ /dev/null @@ -1,125 +0,0 @@ -// GENERATED CODE -- DO NOT EDIT! - -// Original file comments: -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// -'use strict'; -var grpc = require('../..'); -var math_math_pb = require('./math_pb.js'); - -function serialize_DivArgs(arg) { - if (!(arg instanceof math_math_pb.DivArgs)) { - throw new Error('Expected argument of type DivArgs'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_DivArgs(buffer_arg) { - return math_math_pb.DivArgs.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_DivReply(arg) { - if (!(arg instanceof math_math_pb.DivReply)) { - throw new Error('Expected argument of type DivReply'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_DivReply(buffer_arg) { - return math_math_pb.DivReply.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_FibArgs(arg) { - if (!(arg instanceof math_math_pb.FibArgs)) { - throw new Error('Expected argument of type FibArgs'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_FibArgs(buffer_arg) { - return math_math_pb.FibArgs.deserializeBinary(new Uint8Array(buffer_arg)); -} - -function serialize_Num(arg) { - if (!(arg instanceof math_math_pb.Num)) { - throw new Error('Expected argument of type Num'); - } - return Buffer.from(arg.serializeBinary()); -} - -function deserialize_Num(buffer_arg) { - return math_math_pb.Num.deserializeBinary(new Uint8Array(buffer_arg)); -} - - -var MathService = exports.MathService = { - // Div divides args.dividend by args.divisor and returns the quotient and - // remainder. - div: { - path: '/math.Math/Div', - requestStream: false, - responseStream: false, - requestType: math_math_pb.DivArgs, - responseType: math_math_pb.DivReply, - requestSerialize: serialize_DivArgs, - requestDeserialize: deserialize_DivArgs, - responseSerialize: serialize_DivReply, - responseDeserialize: deserialize_DivReply, - }, - // DivMany accepts an arbitrary number of division args from the client stream - // and sends back the results in the reply stream. The stream continues until - // the client closes its end; the server does the same after sending all the - // replies. The stream ends immediately if either end aborts. - divMany: { - path: '/math.Math/DivMany', - requestStream: true, - responseStream: true, - requestType: math_math_pb.DivArgs, - responseType: math_math_pb.DivReply, - requestSerialize: serialize_DivArgs, - requestDeserialize: deserialize_DivArgs, - responseSerialize: serialize_DivReply, - responseDeserialize: deserialize_DivReply, - }, - // Fib generates numbers in the Fibonacci sequence. If args.limit > 0, Fib - // generates up to limit numbers; otherwise it continues until the call is - // canceled. Unlike Fib above, Fib has no final FibReply. - fib: { - path: '/math.Math/Fib', - requestStream: false, - responseStream: true, - requestType: math_math_pb.FibArgs, - responseType: math_math_pb.Num, - requestSerialize: serialize_FibArgs, - requestDeserialize: deserialize_FibArgs, - responseSerialize: serialize_Num, - responseDeserialize: deserialize_Num, - }, - // Sum sums a stream of numbers, returning the final result once the stream - // is closed. - sum: { - path: '/math.Math/Sum', - requestStream: true, - responseStream: false, - requestType: math_math_pb.Num, - responseType: math_math_pb.Num, - requestSerialize: serialize_Num, - requestDeserialize: deserialize_Num, - responseSerialize: serialize_Num, - responseDeserialize: deserialize_Num, - }, -}; - -exports.MathClient = grpc.makeGenericClientConstructor(MathService); diff --git a/packages/grpc-native-core/test/math/math_pb.js b/packages/grpc-native-core/test/math/math_pb.js deleted file mode 100644 index ccc05c6e0..000000000 --- a/packages/grpc-native-core/test/math/math_pb.js +++ /dev/null @@ -1,866 +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.math.DivArgs', null, global); -goog.exportSymbol('proto.math.DivReply', null, global); -goog.exportSymbol('proto.math.FibArgs', null, global); -goog.exportSymbol('proto.math.FibReply', null, global); -goog.exportSymbol('proto.math.Num', 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.math.DivArgs = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.DivArgs, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.DivArgs.displayName = 'proto.math.DivArgs'; -} - - -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_, 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.math.DivArgs.prototype.toObject = function(opt_includeInstance) { - return proto.math.DivArgs.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.math.DivArgs} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.DivArgs.toObject = function(includeInstance, msg) { - var f, obj = { - dividend: msg.getDividend(), - divisor: msg.getDivisor() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.DivArgs} - */ -proto.math.DivArgs.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.DivArgs; - return proto.math.DivArgs.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.DivArgs} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.DivArgs} - */ -proto.math.DivArgs.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setDividend(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt64()); - msg.setDivisor(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.math.DivArgs} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.DivArgs.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.DivArgs.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.math.DivArgs.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getDividend(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } - f = this.getDivisor(); - if (f !== 0) { - writer.writeInt64( - 2, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.DivArgs} The clone. - */ -proto.math.DivArgs.prototype.cloneMessage = function() { - return /** @type {!proto.math.DivArgs} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 dividend = 1; - * @return {number} - */ -proto.math.DivArgs.prototype.getDividend = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.DivArgs.prototype.setDividend = function(value) { - jspb.Message.setField(this, 1, value); -}; - - -/** - * optional int64 divisor = 2; - * @return {number} - */ -proto.math.DivArgs.prototype.getDivisor = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); -}; - - -/** @param {number} value */ -proto.math.DivArgs.prototype.setDivisor = function(value) { - jspb.Message.setField(this, 2, 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.math.DivReply = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.DivReply, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.DivReply.displayName = 'proto.math.DivReply'; -} - - -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_, 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.math.DivReply.prototype.toObject = function(opt_includeInstance) { - return proto.math.DivReply.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.math.DivReply} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.DivReply.toObject = function(includeInstance, msg) { - var f, obj = { - quotient: msg.getQuotient(), - remainder: msg.getRemainder() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.DivReply} - */ -proto.math.DivReply.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.DivReply; - return proto.math.DivReply.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.DivReply} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.DivReply} - */ -proto.math.DivReply.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setQuotient(value); - break; - case 2: - var value = /** @type {number} */ (reader.readInt64()); - msg.setRemainder(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.math.DivReply} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.DivReply.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.DivReply.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.math.DivReply.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getQuotient(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } - f = this.getRemainder(); - if (f !== 0) { - writer.writeInt64( - 2, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.DivReply} The clone. - */ -proto.math.DivReply.prototype.cloneMessage = function() { - return /** @type {!proto.math.DivReply} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 quotient = 1; - * @return {number} - */ -proto.math.DivReply.prototype.getQuotient = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.DivReply.prototype.setQuotient = function(value) { - jspb.Message.setField(this, 1, value); -}; - - -/** - * optional int64 remainder = 2; - * @return {number} - */ -proto.math.DivReply.prototype.getRemainder = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 2, 0)); -}; - - -/** @param {number} value */ -proto.math.DivReply.prototype.setRemainder = function(value) { - jspb.Message.setField(this, 2, 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.math.FibArgs = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.FibArgs, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.FibArgs.displayName = 'proto.math.FibArgs'; -} - - -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_, 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.math.FibArgs.prototype.toObject = function(opt_includeInstance) { - return proto.math.FibArgs.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.math.FibArgs} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.FibArgs.toObject = function(includeInstance, msg) { - var f, obj = { - limit: msg.getLimit() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.FibArgs} - */ -proto.math.FibArgs.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.FibArgs; - return proto.math.FibArgs.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.FibArgs} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.FibArgs} - */ -proto.math.FibArgs.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setLimit(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.math.FibArgs} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.FibArgs.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.FibArgs.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.math.FibArgs.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getLimit(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.FibArgs} The clone. - */ -proto.math.FibArgs.prototype.cloneMessage = function() { - return /** @type {!proto.math.FibArgs} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 limit = 1; - * @return {number} - */ -proto.math.FibArgs.prototype.getLimit = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.FibArgs.prototype.setLimit = 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.math.Num = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.Num, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.Num.displayName = 'proto.math.Num'; -} - - -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_, 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.math.Num.prototype.toObject = function(opt_includeInstance) { - return proto.math.Num.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.math.Num} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.Num.toObject = function(includeInstance, msg) { - var f, obj = { - num: msg.getNum() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.Num} - */ -proto.math.Num.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.Num; - return proto.math.Num.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.Num} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.Num} - */ -proto.math.Num.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setNum(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.math.Num} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.Num.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.Num.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.math.Num.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getNum(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.Num} The clone. - */ -proto.math.Num.prototype.cloneMessage = function() { - return /** @type {!proto.math.Num} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 num = 1; - * @return {number} - */ -proto.math.Num.prototype.getNum = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.Num.prototype.setNum = 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.math.FibReply = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); -}; -goog.inherits(proto.math.FibReply, jspb.Message); -if (goog.DEBUG && !COMPILED) { - proto.math.FibReply.displayName = 'proto.math.FibReply'; -} - - -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_, 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.math.FibReply.prototype.toObject = function(opt_includeInstance) { - return proto.math.FibReply.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.math.FibReply} msg The msg instance to transform. - * @return {!Object} - */ -proto.math.FibReply.toObject = function(includeInstance, msg) { - var f, obj = { - count: msg.getCount() - }; - - if (includeInstance) { - obj.$jspbMessageInstance = msg; - } - return obj; -}; -} - - -/** - * Deserializes binary data (in protobuf wire format). - * @param {jspb.ByteSource} bytes The bytes to deserialize. - * @return {!proto.math.FibReply} - */ -proto.math.FibReply.deserializeBinary = function(bytes) { - var reader = new jspb.BinaryReader(bytes); - var msg = new proto.math.FibReply; - return proto.math.FibReply.deserializeBinaryFromReader(msg, reader); -}; - - -/** - * Deserializes binary data (in protobuf wire format) from the - * given reader into the given message object. - * @param {!proto.math.FibReply} msg The message object to deserialize into. - * @param {!jspb.BinaryReader} reader The BinaryReader to use. - * @return {!proto.math.FibReply} - */ -proto.math.FibReply.deserializeBinaryFromReader = function(msg, reader) { - while (reader.nextField()) { - if (reader.isEndGroup()) { - break; - } - var field = reader.getFieldNumber(); - switch (field) { - case 1: - var value = /** @type {number} */ (reader.readInt64()); - msg.setCount(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.math.FibReply} message - * @param {!jspb.BinaryWriter} writer - */ -proto.math.FibReply.serializeBinaryToWriter = function(message, writer) { - message.serializeBinaryToWriter(writer); -}; - - -/** - * Serializes the message to binary data (in protobuf wire format). - * @return {!Uint8Array} - */ -proto.math.FibReply.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.math.FibReply.prototype.serializeBinaryToWriter = function (writer) { - var f = undefined; - f = this.getCount(); - if (f !== 0) { - writer.writeInt64( - 1, - f - ); - } -}; - - -/** - * Creates a deep clone of this proto. No data is shared with the original. - * @return {!proto.math.FibReply} The clone. - */ -proto.math.FibReply.prototype.cloneMessage = function() { - return /** @type {!proto.math.FibReply} */ (jspb.Message.cloneMessage(this)); -}; - - -/** - * optional int64 count = 1; - * @return {number} - */ -proto.math.FibReply.prototype.getCount = function() { - return /** @type {number} */ (jspb.Message.getFieldProto3(this, 1, 0)); -}; - - -/** @param {number} value */ -proto.math.FibReply.prototype.setCount = function(value) { - jspb.Message.setField(this, 1, value); -}; - - -goog.object.extend(exports, proto.math); diff --git a/packages/grpc-native-core/test/math/math_server.js b/packages/grpc-native-core/test/math/math_server.js deleted file mode 100644 index 4291ae18b..000000000 --- a/packages/grpc-native-core/test/math/math_server.js +++ /dev/null @@ -1,124 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var grpc = require('../..'); -var grpcMath = require('./math_grpc_pb'); -var math = require('./math_pb'); - -/** - * Server function for division. Provides the /Math/DivMany and /Math/Div - * functions (Div is just DivMany with only one stream element). For each - * DivArgs parameter, responds with a DivReply with the results of the division - * @param {Object} call The object containing request and cancellation info - * @param {function(Error, *)} cb Response callback - */ -function mathDiv(call, cb) { - var req = call.request; - var divisor = req.getDivisor(); - var dividend = req.getDividend(); - // Unary + is explicit coersion to integer - if (req.getDivisor() === 0) { - cb(new Error('cannot divide by zero')); - } else { - var response = new math.DivReply(); - response.setQuotient(Math.floor(dividend / divisor)); - response.setRemainder(dividend % divisor); - cb(null, response); - } -} - -/** - * Server function for Fibonacci numbers. Provides the /Math/Fib function. Reads - * a single parameter that indicates the number of responses, and then responds - * with a stream of that many Fibonacci numbers. - * @param {stream} stream The stream for sending responses. - */ -function mathFib(stream) { - // Here, call is a standard writable Node object Stream - var previous = 0, current = 1; - for (var i = 0; i < stream.request.getLimit(); i++) { - var response = new math.Num(); - response.setNum(current); - stream.write(response); - var temp = current; - current += previous; - previous = temp; - } - stream.end(); -} - -/** - * Server function for summation. Provides the /Math/Sum function. Reads a - * stream of number parameters, then responds with their sum. - * @param {stream} call The stream of arguments. - * @param {function(Error, *)} cb Response callback - */ -function mathSum(call, cb) { - // Here, call is a standard readable Node object Stream - var sum = 0; - call.on('data', function(data) { - sum += data.getNum(); - }); - call.on('end', function() { - var response = new math.Num(); - response.setNum(sum); - cb(null, response); - }); -} - -function mathDivMany(stream) { - stream.on('data', function(div_args) { - var divisor = div_args.getDivisor(); - var dividend = div_args.getDividend(); - if (divisor === 0) { - stream.emit('error', new Error('cannot divide by zero')); - } else { - var response = new math.DivReply(); - response.setQuotient(Math.floor(dividend / divisor)); - response.setRemainder(dividend % divisor); - stream.write(response); - } - }); - stream.on('end', function() { - stream.end(); - }); -} - -function getMathServer() { - var server = new grpc.Server(); - server.addService(grpcMath.MathService, { - div: mathDiv, - fib: mathFib, - sum: mathSum, - divMany: mathDivMany - }); - return server; -} - -if (require.main === module) { - var server = getMathServer(); - server.bind('0.0.0.0:50051', grpc.ServerCredentials.createInsecure()); - server.start(); -} - -/** - * See docs for server - */ -module.exports = getMathServer; diff --git a/packages/grpc-native-core/test/math_client_test.js b/packages/grpc-native-core/test/math_client_test.js deleted file mode 100644 index 11deda34f..000000000 --- a/packages/grpc-native-core/test/math_client_test.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); - -var grpc = require('..'); -var math = require('./math/math_pb'); -var MathClient = require('./math/math_grpc_pb').MathClient; - -/** - * Client to use to make requests to a running server. - */ -var math_client; - -/** - * Server to test against - */ -var getServer = require('./math/math_server.js'); - -var server = getServer(); - -describe('Math client', function() { - before(function(done) { - var port_num = server.bind('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - server.start(); - math_client = new MathClient('localhost:' + port_num, - grpc.credentials.createInsecure()); - done(); - }); - after(function() { - server.forceShutdown(); - }); - it('should handle a single request', function(done) { - var arg = new math.DivArgs(); - arg.setDividend(7); - arg.setDivisor(4); - math_client.div(arg, function handleDivResult(err, value) { - assert.ifError(err); - assert.equal(value.getQuotient(), 1); - assert.equal(value.getRemainder(), 3); - done(); - }); - }); - it('should handle an error from a unary request', function(done) { - var arg = new math.DivArgs(); - arg.setDividend(7); - arg.setDivisor(0); - math_client.div(arg, function handleDivResult(err, value) { - assert(err); - done(); - }); - }); - it('should handle a server streaming request', function(done) { - var arg = new math.FibArgs(); - arg.setLimit(7); - var call = math_client.fib(arg); - var expected_results = [1, 1, 2, 3, 5, 8, 13]; - var next_expected = 0; - call.on('data', function checkResponse(value) { - assert.equal(value.getNum(), expected_results[next_expected]); - next_expected += 1; - }); - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('should handle a client streaming request', function(done) { - var call = math_client.sum(function handleSumResult(err, value) { - assert.ifError(err); - assert.equal(value.getNum(), 21); - }); - for (var i = 0; i < 7; i++) { - var arg = new math.Num(); - arg.setNum(i); - call.write(arg); - } - call.end(); - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('should handle a bidirectional streaming request', function(done) { - function checkResponse(index, value) { - assert.equal(value.getQuotient(), index); - assert.equal(value.getRemainder(), 1); - } - var call = math_client.divMany(); - var response_index = 0; - call.on('data', function(value) { - checkResponse(response_index, value); - response_index += 1; - }); - for (var i = 0; i < 7; i++) { - var arg = new math.DivArgs(); - arg.setDividend(2 * i + 1); - arg.setDivisor(2); - call.write(arg); - } - call.end(); - call.on('status', function checkStatus(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('should handle an error from a bidi request', function(done) { - var call = math_client.divMany(); - call.on('data', function(value) { - assert.fail(value, undefined, 'Unexpected data response on failing call', - '!='); - }); - var arg = new math.DivArgs(); - arg.setDividend(7); - arg.setDivisor(0); - call.write(arg); - call.end(); - call.on('error', function checkStatus(status) { - done(); - }); - }); -}); diff --git a/packages/grpc-native-core/test/metadata_test.js b/packages/grpc-native-core/test/metadata_test.js deleted file mode 100644 index 2c1765aa6..000000000 --- a/packages/grpc-native-core/test/metadata_test.js +++ /dev/null @@ -1,178 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var Metadata = require('..').Metadata; - -var assert = require('assert'); - -describe('Metadata', function() { - var metadata; - beforeEach(function() { - metadata = new Metadata(); - }); - describe('#set', function() { - it('Only accepts string values for non "-bin" keys', function() { - assert.throws(function() { - metadata.set('key', Buffer.from('value')); - }); - assert.doesNotThrow(function() { - metadata.set('key', 'value'); - }); - }); - it('Only accepts Buffer values for "-bin" keys', function() { - assert.throws(function() { - metadata.set('key-bin', 'value'); - }); - assert.doesNotThrow(function() { - metadata.set('key-bin', Buffer.from('value')); - }); - }); - it('Rejects invalid keys', function() { - assert.throws(function() { - metadata.set('key$', 'value'); - }); - assert.throws(function() { - metadata.set('', 'value'); - }); - }); - it('Rejects values with non-ASCII characters', function() { - assert.throws(function() { - metadata.set('key', 'résumé'); - }); - }); - it('Saves values that can be retrieved', function() { - metadata.set('key', 'value'); - assert.deepEqual(metadata.get('key'), ['value']); - }); - it('Overwrites previous values', function() { - metadata.set('key', 'value1'); - metadata.set('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value2']); - }); - it('Normalizes keys', function() { - metadata.set('Key', 'value1'); - assert.deepEqual(metadata.get('key'), ['value1']); - metadata.set('KEY', 'value2'); - assert.deepEqual(metadata.get('key'), ['value2']); - }); - }); - describe('#add', function() { - it('Only accepts string values for non "-bin" keys', function() { - assert.throws(function() { - metadata.add('key', Buffer.from('value')); - }); - assert.doesNotThrow(function() { - metadata.add('key', 'value'); - }); - }); - it('Only accepts Buffer values for "-bin" keys', function() { - assert.throws(function() { - metadata.add('key-bin', 'value'); - }); - assert.doesNotThrow(function() { - metadata.add('key-bin', Buffer.from('value')); - }); - }); - it('Rejects invalid keys', function() { - assert.throws(function() { - metadata.add('key$', 'value'); - }); - assert.throws(function() { - metadata.add('', 'value'); - }); - }); - it('Saves values that can be retrieved', function() { - metadata.add('key', 'value'); - assert.deepEqual(metadata.get('key'), ['value']); - }); - it('Combines with previous values', function() { - metadata.add('key', 'value1'); - metadata.add('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); - }); - it('Normalizes keys', function() { - metadata.add('Key', 'value1'); - assert.deepEqual(metadata.get('key'), ['value1']); - metadata.add('KEY', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); - }); - }); - describe('#remove', function() { - it('clears values from a key', function() { - metadata.add('key', 'value'); - metadata.remove('key'); - assert.deepEqual(metadata.get('key'), []); - }); - it('Normalizes keys', function() { - metadata.add('key', 'value'); - metadata.remove('KEY'); - assert.deepEqual(metadata.get('key'), []); - }); - }); - describe('#get', function() { - beforeEach(function() { - metadata.add('key', 'value1'); - metadata.add('key', 'value2'); - metadata.add('key-bin', Buffer.from('value')); - }); - it('gets all values associated with a key', function() { - assert.deepEqual(metadata.get('key'), ['value1', 'value2']); - }); - it('Normalizes keys', function() { - assert.deepEqual(metadata.get('KEY'), ['value1', 'value2']); - }); - it('returns an empty list for non-existent keys', function() { - assert.deepEqual(metadata.get('non-existent-key'), []); - }); - it('returns Buffers for "-bin" keys', function() { - assert(metadata.get('key-bin')[0] instanceof Buffer); - }); - }); - describe('#getMap', function() { - it('gets a map of keys to values', function() { - metadata.add('key1', 'value1'); - metadata.add('Key2', 'value2'); - metadata.add('KEY3', 'value3'); - assert.deepEqual(metadata.getMap(), - {key1: 'value1', - key2: 'value2', - key3: 'value3'}); - }); - }); - describe('#clone', function() { - it('retains values from the original', function() { - metadata.add('key', 'value'); - var copy = metadata.clone(); - assert.deepEqual(copy.get('key'), ['value']); - }); - it('Does not see newly added values', function() { - metadata.add('key', 'value1'); - var copy = metadata.clone(); - metadata.add('key', 'value2'); - assert.deepEqual(copy.get('key'), ['value1']); - }); - it('Does not add new values to the original', function() { - metadata.add('key', 'value1'); - var copy = metadata.clone(); - copy.add('key', 'value2'); - assert.deepEqual(metadata.get('key'), ['value1']); - }); - }); -}); diff --git a/packages/grpc-native-core/test/numbers.txt b/packages/grpc-native-core/test/numbers.txt deleted file mode 100644 index 4972919b4..000000000 --- a/packages/grpc-native-core/test/numbers.txt +++ /dev/null @@ -1,496 +0,0 @@ -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 -1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 diff --git a/packages/grpc-native-core/test/resolver_test.js b/packages/grpc-native-core/test/resolver_test.js deleted file mode 100644 index 83a320630..000000000 --- a/packages/grpc-native-core/test/resolver_test.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var _ = require('lodash'); - -var grpc = require('..'); - -const insecureCreds = grpc.credentials.createInsecure(); - -describe('Name resolver', function() { - let server; - let port; - before(function(done) { - const insecureServerCreds = grpc.ServerCredentials.createInsecure(); - server = new grpc.Server(); - server.bindAsync('localhost:0', insecureServerCreds, (error, portVal) => { - port = portVal; - done(error); - }); - }); - after(function() { - server.forceShutdown(); - }); - // This test also seems to have problems with the native resolver on Windows - it.skip('Should resolve a target to IPv4 addresses', function(done) { - const client = new grpc.Client(`loopback4.unittest.grpc.io:${port}`, insecureCreds); - let deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - client.waitForReady(deadline, (error) => { - assert.ifError(error); - done(); - }); - }); - /* This test doesn't work with the native resolver on Windows on our test - * machines because they don't have IPv6 addresses, so Windows omits IPv6 - * addresses from getaddrinfo results. */ - it.skip('Should resolve a target to IPv6 addresses', function(done) { - const client = new grpc.Client(`loopback6.unittest.grpc.io:${port}`, insecureCreds); - let deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - client.waitForReady(deadline, (error) => { - assert.ifError(error); - done(); - }); - }); - it.skip('Should resolve a target to IPv4 and IPv6 addresses', function(done) { - const client = new grpc.Client(`loopback46.unittest.grpc.io:${port}`, insecureCreds); - let deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - client.waitForReady(deadline, (error) => { - assert.ifError(error); - done(); - }); - }); -}); \ No newline at end of file diff --git a/packages/grpc-native-core/test/server_test.js b/packages/grpc-native-core/test/server_test.js deleted file mode 100644 index b06236efb..000000000 --- a/packages/grpc-native-core/test/server_test.js +++ /dev/null @@ -1,136 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var fs = require('fs'); -var path = require('path'); -var grpc = require('../src/grpc_extension'); - -describe('server', function() { - describe('constructor', function() { - it('should work with no arguments', function() { - assert.doesNotThrow(function() { - new grpc.Server(); - }); - }); - it('should work with an empty object argument', function() { - assert.doesNotThrow(function() { - new grpc.Server({}); - }); - }); - it('should work without the new keyword', function() { - var server; - assert.doesNotThrow(function() { - server = grpc.Server(); - }); - assert(server instanceof grpc.Server); - }); - it('should only accept objects with string or int values', function() { - assert.doesNotThrow(function() { - new grpc.Server({'key' : 'value'}); - }); - assert.doesNotThrow(function() { - new grpc.Server({'key' : 5}); - }); - assert.throws(function() { - new grpc.Server({'key' : null}); - }); - assert.throws(function() { - new grpc.Server({'key' : new Date()}); - }); - }); - }); - describe('addHttp2Port', function() { - var server; - before(function() { - server = new grpc.Server(); - }); - after(function() { - server.start(); - server.forceShutdown(); - }); - it('should bind to an unused port', function() { - var port; - assert.doesNotThrow(function() { - port = server.addHttp2Port('0.0.0.0:0', - grpc.ServerCredentials.createInsecure()); - }); - assert(port > 0); - }); - it('should bind to an unused port with ssl credentials', function() { - var port; - var key_path = path.join(__dirname, '/data/server1.key'); - var pem_path = path.join(__dirname, '/data/server1.pem'); - var key_data = fs.readFileSync(key_path); - var pem_data = fs.readFileSync(pem_path); - var creds = grpc.ServerCredentials.createSsl(null, - [{private_key: key_data, - cert_chain: pem_data}]); - assert.doesNotThrow(function() { - port = server.addHttp2Port('0.0.0.0:0', creds); - }); - assert(port > 0); - }); - }); - describe('start', function() { - var server; - before(function() { - server = new grpc.Server(); - server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('should start without error', function() { - assert.doesNotThrow(function() { - server.start(); - }); - }); - }); - describe('shutdown', function() { - var server; - beforeEach(function() { - server = new grpc.Server(); - server.addHttp2Port('0.0.0.0:0', grpc.ServerCredentials.createInsecure()); - server.start(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('tryShutdown should shutdown successfully', function(done) { - server.tryShutdown(done); - }); - it('forceShutdown should shutdown successfully', function() { - server.forceShutdown(); - }); - it('tryShutdown should be idempotent', function(done) { - server.tryShutdown(done); - server.tryShutdown(function() {}); - }); - it('forceShutdown should be idempotent', function() { - server.forceShutdown(); - server.forceShutdown(); - }); - it('forceShutdown should trigger tryShutdown', function(done) { - server.tryShutdown(done); - server.forceShutdown(); - }); - }); -}); diff --git a/packages/grpc-native-core/test/surface_test.js b/packages/grpc-native-core/test/surface_test.js deleted file mode 100644 index 83958274f..000000000 --- a/packages/grpc-native-core/test/surface_test.js +++ /dev/null @@ -1,1532 +0,0 @@ -/* - * - * Copyright 2015 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -'use strict'; - -var assert = require('assert'); -var _ = require('lodash'); - -var grpc = require('..'); - -var MathClient = grpc.load( - __dirname + '/../deps/grpc/src/proto/math/math.proto').math.Math; -var mathServiceAttrs = MathClient.service; - -/** - * This is used for testing functions with multiple asynchronous calls that - * can happen in different orders. This should be passed the number of async - * function invocations that can occur last, and each of those should call this - * function's return value - * @param {function()} done The function that should be called when a test is - * complete. - * @param {number} count The number of calls to the resulting function if the - * test passes. - * @return {function()} The function that should be called at the end of each - * sequence of asynchronous functions. - */ -function multiDone(done, count) { - return function() { - count -= 1; - if (count <= 0) { - done(); - } - }; -} - -var server_insecure_creds = grpc.ServerCredentials.createInsecure(); - -describe('File loader', function() { - it('Should load a proto file by default', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto'); - }); - }); - it('Should load a proto file with the proto format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.proto', 'proto'); - }); - }); - it('Should load a json file with the json format', function() { - assert.doesNotThrow(function() { - grpc.load(__dirname + '/test_service.json', 'json'); - }); - }); -}); -describe('surface Server', function() { - var server; - beforeEach(function() { - server = new grpc.Server(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('should error if started twice', function() { - server.start(); - assert.throws(function() { - server.start(); - }); - }); - it('should error if a port is bound after the server starts', function() { - server.start(); - assert.throws(function() { - server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); - }); - }); - it('should successfully shutdown if tryShutdown is called', function(done) { - server.start(); - server.tryShutdown(done); - }); -}); -describe('Server.prototype.addService', function() { - var server; - var dummyImpls = { - 'div': function() {}, - 'divMany': function() {}, - 'fib': function() {}, - 'sum': function() {} - }; - beforeEach(function() { - server = new grpc.Server(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('Should succeed with a single service', function() { - assert.doesNotThrow(function() { - server.addService(mathServiceAttrs, dummyImpls); - }); - }); - it('Should fail with conflicting method names', function() { - server.addService(mathServiceAttrs, dummyImpls); - assert.throws(function() { - server.addService(mathServiceAttrs, dummyImpls); - }); - }); - it('Should allow method names as originally written', function() { - var altDummyImpls = { - 'Div': function() {}, - 'DivMany': function() {}, - 'Fib': function() {}, - 'Sum': function() {} - }; - assert.doesNotThrow(function() { - server.addService(mathServiceAttrs, altDummyImpls); - }); - }); - it('Should have a conflict between name variations', function() { - /* This is really testing that both name variations are actually used, - by checking that the method actually gets registered, for the - corresponding function, in both cases */ - var altDummyImpls = { - 'Div': function() {}, - 'DivMany': function() {}, - 'Fib': function() {}, - 'Sum': function() {} - }; - server.addProtoService(mathServiceAttrs, altDummyImpls); - assert.throws(function() { - server.addProtoService(mathServiceAttrs, dummyImpls); - }); - }); - it('Should fail if the server has been started', function() { - server.start(); - assert.throws(function() { - server.addService(mathServiceAttrs, dummyImpls); - }); - }); - describe('Default handlers', function() { - var client; - beforeEach(function() { - server.addService(mathServiceAttrs, {}); - var port = server.bind('localhost:0', server_insecure_creds); - client = new MathClient('localhost:' + port, - grpc.credentials.createInsecure()); - server.start(); - }); - it('should respond to a unary call with UNIMPLEMENTED', function(done) { - client.div({divisor: 4, dividend: 3}, function(error, response) { - assert(error); - assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); - done(); - }); - }); - it('should respond to a client stream with UNIMPLEMENTED', function(done) { - var call = client.sum(function(error, respones) { - assert(error); - assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); - done(); - }); - call.end(); - }); - it('should respond to a server stream with UNIMPLEMENTED', function(done) { - var call = client.fib({limit: 5}); - call.on('data', function(value) { - assert.fail('No messages expected'); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); - done(); - }); - call.on('error', function(status) { /* Do nothing */ }); - }); - it('should respond to a bidi call with UNIMPLEMENTED', function(done) { - var call = client.divMany(); - call.on('data', function(value) { - assert.fail('No messages expected'); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); - done(); - }); - call.on('error', function(status) { /* Do nothing */ }); - call.end(); - }); - }); -}); -describe('Client constructor building', function() { - var illegal_service_attrs = { - $method : { - path: '/illegal/$method', - requestStream: false, - responseStream: false, - requestSerialize: x => x, - requestDeserialize: x => x, - responseSerialize: x => x, - responseDeserialize: x => x - } - }; - it('Should reject method names starting with $', function() { - assert.throws(function() { - grpc.makeGenericClientConstructor(illegal_service_attrs); - }, /\$/); - }); - it('Should add aliases for original names', function() { - var Client = grpc.makeGenericClientConstructor(mathServiceAttrs); - assert.strictEqual(Client.prototype.add, Client.prototype.Add); - }); -}); -describe('Generic client', function() { - it('Should construct without error', function() { - assert.doesNotThrow(() => { - const client = new grpc.Client('localhost: 50051', grpc.credentials.createInsecure()); - }); - }); -}); -describe('waitForClientReady', function() { - var server; - var port; - var Client = MathClient; - var client; - before(function() { - server = new grpc.Server(); - port = server.bind('localhost:0', grpc.ServerCredentials.createInsecure()); - server.start(); - }); - beforeEach(function() { - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('should complete when called alone', function(done) { - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - }); - it('should complete when a call is initiated', function(done) { - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - var call = client.div({}, function(err, response) {}); - call.cancel(); - }); - it('should complete if called more than once', function(done) { - done = multiDone(done, 2); - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - }); - it('should complete if called when already ready', function(done) { - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - grpc.waitForClientReady(client, Infinity, function(error) { - assert.ifError(error); - done(); - }); - }); - }); - it('should time out if the server does not exist', function(done) { - var bad_client = new Client('nonexistent_hostname', - grpc.credentials.createInsecure()); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - grpc.waitForClientReady(bad_client, deadline, function(error) { - assert(error); - done(); - }); - }); -}); -describe('Echo service', function() { - var server; - var client; - before(function() { - var Client = grpc.load(__dirname + '/echo_service.proto').EchoService; - server = new grpc.Server(); - server.addService(Client.service, { - echo: function(call, callback) { - callback(null, call.request); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('should echo the recieved message directly', function(done) { - client.echo({value: 'test value', value2: 3}, function(error, response) { - assert.ifError(error); - assert.deepEqual(response, {value: 'test value', value2: 3}); - done(); - }); - }); - it('Should convert an undefined argument to default values', function(done) { - client.echo(undefined, function(error, response) { - assert.ifError(error); - assert.deepEqual(response, {value: '', value2: 0}); - done(); - }); - }); -}); -describe('Non-protobuf client and server', function() { - function toString(val) { - return val.toString(); - } - function toBuffer(str) { - return Buffer.from(str); - } - var string_service_attrs = { - 'capitalize' : { - path: '/string/capitalize', - requestStream: false, - responseStream: false, - requestSerialize: toBuffer, - requestDeserialize: toString, - responseSerialize: toBuffer, - responseDeserialize: toString - } - }; - describe('String client and server', function() { - var client; - var server; - before(function() { - server = new grpc.Server(); - server.addService(string_service_attrs, { - capitalize: function(call, callback) { - callback(null, _.capitalize(call.request)); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - server.start(); - var Client = grpc.makeGenericClientConstructor(string_service_attrs); - client = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('Should respond with a capitalized string', function(done) { - client.capitalize('abc', function(err, response) { - assert.ifError(err); - assert.strictEqual(response, 'Abc'); - done(); - }); - }); - }); -}); -describe('Server-side getPeer', function() { - function toString(val) { - return val.toString(); - } - function toBuffer(str) { - return Buffer.from(str); - } - var string_service_attrs = { - 'getPeer' : { - path: '/string/getPeer', - requestStream: false, - responseStream: false, - requestSerialize: toBuffer, - requestDeserialize: toString, - responseSerialize: toBuffer, - responseDeserialize: toString - } - }; - var client; - var server; - before(function() { - server = new grpc.Server(); - server.addService(string_service_attrs, { - getPeer: function(call, callback) { - try { - callback(null, call.getPeer()); - } catch (e) { - call.emit('error', e); - } - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - server.start(); - var Client = grpc.makeGenericClientConstructor(string_service_attrs); - client = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - }); - after(function() { - server.forceShutdown(); - }); - it('should respond with a string representing the client', function(done) { - client.getPeer('', function(err, response) { - assert.ifError(err); - // We don't expect a specific value, just that it worked without error - done(); - }); - }); -}); -describe('Echo metadata', function() { - var client; - var server; - var metadata; - before(function() { - var Client = grpc.load(__dirname + '/test_service.proto').TestService; - server = new grpc.Server(); - server.addService(Client.service, { - unary: function(call, cb) { - call.sendMetadata(call.metadata); - cb(null, {}); - }, - clientStream: function(stream, cb){ - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.sendMetadata(stream.metadata); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function(data) {}); - stream.on('end', function() { - stream.sendMetadata(stream.metadata); - stream.end(); - }); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - metadata = new grpc.Metadata(); - metadata.set('key', 'value'); - }); - after(function() { - server.forceShutdown(); - }); - it('with unary call', function(done) { - var call = client.unary({}, metadata, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - }); - it('with client stream call', function(done) { - var call = client.clientStream(metadata, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - call.end(); - }); - it('with server stream call', function(done) { - var call = client.serverStream({}, metadata); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - }); - it('with bidi stream call', function(done) { - var call = client.bidiStream(metadata); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - call.end(); - }); - it('shows the correct user-agent string', function(done) { - var version = require('../package.json').version; - var call = client.unary({}, metadata, - function(err, data) { assert.ifError(err); }); - call.on('metadata', function(metadata) { - assert.strictEqual(0, - metadata.get('user-agent')[0].indexOf('grpc-node/' + version)); - done(); - }); - }); - it('properly handles duplicate values', function(done) { - var dup_metadata = metadata.clone(); - dup_metadata.add('key', 'value2'); - var call = client.unary({}, dup_metadata, - function(err, data) {assert.ifError(err); }); - call.on('metadata', function(resp_metadata) { - // Two arrays are equal iff their symmetric difference is empty - assert.deepEqual(_.xor(dup_metadata.get('key'), resp_metadata.get('key')), - []); - done(); - }); - }); - describe('Call argument handling', function() { - describe('Unary call', function() { - it('Should handle undefined options', function(done) { - var call = client.unary({}, metadata, undefined, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - }); - it('Should handle two undefined arguments', function(done) { - var call = client.unary({}, undefined, undefined, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - done(); - }); - }); - it('Should handle one undefined argument', function(done) { - var call = client.unary({}, undefined, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - done(); - }); - }); - }); - describe('Client stream call', function() { - it('Should handle undefined options', function(done) { - var call = client.clientStream(metadata, undefined, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - call.end(); - }); - it('Should handle two undefined arguments', function(done) { - var call = client.clientStream(undefined, undefined, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - done(); - }); - call.end(); - }); - it('Should handle one undefined argument', function(done) { - var call = client.clientStream(undefined, function(err, data) { - assert.ifError(err); - }); - call.on('metadata', function(metadata) { - done(); - }); - call.end(); - }); - }); - describe('Server stream call', function() { - it('Should handle undefined options', function(done) { - var call = client.serverStream({}, metadata, undefined); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - }); - it('Should handle two undefined arguments', function(done) { - var call = client.serverStream({}, undefined, undefined); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - done(); - }); - }); - it('Should handle one undefined argument', function(done) { - var call = client.serverStream({}, undefined); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - done(); - }); - }); - }); - describe('Bidi stream call', function() { - it('Should handle undefined options', function(done) { - var call = client.bidiStream(metadata, undefined); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - assert.deepEqual(metadata.get('key'), ['value']); - done(); - }); - call.end(); - }); - it('Should handle two undefined arguments', function(done) { - var call = client.bidiStream(undefined, undefined); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - done(); - }); - call.end(); - }); - it('Should handle one undefined argument', function(done) { - var call = client.bidiStream(undefined); - call.on('data', function() {}); - call.on('metadata', function(metadata) { - done(); - }); - call.end(); - }); - }); - }); -}); -describe('Client malformed response handling', function() { - var server; - var client; - var badArg = Buffer.from([0xFF]); - before(function() { - var Client = grpc.load(__dirname + '/test_service.proto').TestService; - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: x => x, - responseSerialize: x => x - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: x => x, - responseSerialize: x => x - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: x => x, - responseSerialize: x => x - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: x => x, - responseSerialize: x => x - } - }; - server = new grpc.Server(); - server.addService(malformed_test_service, { - unary: function(call, cb) { - cb(null, badArg); - }, - clientStream: function(stream, cb) { - stream.on('data', function() {/* Ignore requests */}); - stream.on('end', function() { - cb(null, badArg); - }); - }, - serverStream: function(stream) { - stream.write(badArg); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write(badArg); - }); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('should get an INTERNAL status with a unary call', function(done) { - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - it('should get an INTERNAL status with a server stream call', function(done) { - var call = client.serverStream({}); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a bidi stream call', function(done) { - var call = client.bidiStream(); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); -}); -describe('Server serialization failure handling', function() { - function serializeFail(obj) { - throw new Error('Serialization failed'); - } - var client; - var server; - before(function() { - var Client = grpc.load(__dirname + '/test_service.proto').TestService; - var malformed_test_service = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestDeserialize: x => x, - responseSerialize: serializeFail - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestDeserialize: x => x, - responseSerialize: serializeFail - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestDeserialize: x => x, - responseSerialize: serializeFail - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestDeserialize: x => x, - responseSerialize: serializeFail - } - }; - server = new grpc.Server(); - server.addService(malformed_test_service, { - unary: function(call, cb) { - cb(null, {}); - }, - clientStream: function(stream, cb) { - stream.on('data', function() {/* Ignore requests */}); - stream.on('end', function() { - cb(null, {}); - }); - }, - serverStream: function(stream) { - stream.write({}); - stream.end(); - }, - bidiStream: function(stream) { - stream.on('data', function() { - // Ignore requests - stream.write({}); - }); - stream.on('end', function() { - stream.end(); - }); - } - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('should get an INTERNAL status with a unary call', function(done) { - client.unary({}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); - it('should get an INTERNAL status with a server stream call', function(done) { - var call = client.serverStream({}); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should get an INTERNAL status with a bidi stream call', function(done) { - var call = client.bidiStream(); - call.on('data', function(){}); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write({}); - call.end(); - }); -}); -describe('Other conditions', function() { - var Client; - var client; - var server; - var port; - before(function() { - Client = grpc.load(__dirname + '/test_service.proto').TestService; - server = new grpc.Server(); - var trailer_metadata = new grpc.Metadata(); - trailer_metadata.add('trailer-present', 'yes'); - server.addService(Client.service, { - unary: function(call, cb) { - var req = call.request; - if (req.error) { - var message = 'Requested error'; - if (req.message) { - message = req.message; - } - cb({code: grpc.status.UNKNOWN, - details: message}, null, trailer_metadata); - } else { - cb(null, {count: 1}, trailer_metadata); - } - }, - clientStream: function(stream, cb){ - var count = 0; - var errored; - stream.on('data', function(data) { - if (data.error) { - var message = 'Requested error'; - if (data.message) { - message = data.message; - } - errored = true; - cb(new Error(message), null, trailer_metadata); - } else { - count += 1; - } - }); - stream.on('end', function() { - if (!errored) { - cb(null, {count: count}, trailer_metadata); - } - }); - }, - serverStream: function(stream) { - var req = stream.request; - if (req.error) { - var message = 'Requested error'; - if (req.message) { - message = req.message; - } - var err = {code: grpc.status.UNKNOWN, - details: message}; - err.metadata = trailer_metadata; - stream.emit('error', err); - } else { - for (var i = 0; i < 5; i++) { - stream.write({count: i}); - } - stream.end(trailer_metadata); - } - }, - bidiStream: function(stream) { - var count = 0; - stream.on('data', function(data) { - if (data.error) { - var message = 'Requested error'; - if (data.message) { - message = data.message; - } - var err = new Error(message); - err.metadata = trailer_metadata.clone(); - err.metadata.add('count', '' + count); - stream.emit('error', err); - } else { - stream.write({count: count}); - count += 1; - } - }); - stream.on('end', function() { - stream.end(trailer_metadata); - }); - } - }); - port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('channel.getTarget should be available', function() { - assert.strictEqual(typeof grpc.getClientChannel(client).getTarget(), - 'string'); - }); - it('client should be able to pause and resume a stream', function(done) { - var call = client.bidiStream(); - call.on('data', function(data) { - assert(data.count < 3); - call.pause(); - setTimeout(function() { - call.resume(); - }, 10); - }); - call.on('end', function() { - done(); - }); - call.write({}); - call.write({}); - call.write({}); - call.end(); - }); - it('client should wait for a connection with waitForReady on', function(done) { - /* We have to wait for the client to reach the first connection timeout - * and go to TRANSIENT_FAILURE to confirm that the waitForReady option - * makes it end the call instead of continuing to try. A DNS resolution - * failure makes that transition very fast. */ - this.timeout(15000); - const disconnectedClient = new Client('foo.test.google.com:50051', grpc.credentials.createInsecure()); - const metadata = new grpc.Metadata({waitForReady: true}); - const deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 10); - disconnectedClient.unary({}, metadata, {deadline: deadline}, (error, value) =>{ - assert(error); - assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); - done(); - }); - }); - describe('Server recieving bad input', function() { - var misbehavingClient; - var badArg = Buffer.from([0xFF]); - before(function() { - var test_service_attrs = { - unary: { - path: '/TestService/Unary', - requestStream: false, - responseStream: false, - requestSerialize: x => x, - responseDeserialize: x => x - }, - clientStream: { - path: '/TestService/ClientStream', - requestStream: true, - responseStream: false, - requestSerialize: x => x, - responseDeserialize: x => x - }, - serverStream: { - path: '/TestService/ServerStream', - requestStream: false, - responseStream: true, - requestSerialize: x => x, - responseDeserialize: x => x - }, - bidiStream: { - path: '/TestService/BidiStream', - requestStream: true, - responseStream: true, - requestSerialize: x => x, - responseDeserialize: x => x - } - }; - var Client = grpc.makeGenericClientConstructor(test_service_attrs, - 'TestService'); - misbehavingClient = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - }); - it('should respond correctly to a unary call', function(done) { - misbehavingClient.unary(badArg, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should respond correctly to a client stream', function(done) { - var call = misbehavingClient.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write(badArg); - // TODO(mlumish): Remove call.end() - call.end(); - }); - it('should respond correctly to a server stream', function(done) { - var call = misbehavingClient.serverStream(badArg); - call.on('data', function(data) { - assert.fail(data, null, 'Unexpected data', '==='); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - }); - it('should respond correctly to a bidi stream', function(done) { - var call = misbehavingClient.bidiStream(); - call.on('data', function(data) { - assert.fail(data, null, 'Unexpected data', '==='); - }); - call.on('error', function(err) { - assert.strictEqual(err.code, grpc.status.INTERNAL); - done(); - }); - call.write(badArg); - // TODO(mlumish): Remove call.end() - call.end(); - }); - }); - describe('Trailing metadata', function() { - it('should be present when a unary call succeeds', function(done) { - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a unary call fails', function(done) { - var call = client.unary({error: true}, function(err, data) { - assert(err); - }); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a client stream call succeeds', function(done) { - var call = client.clientStream(function(err, data) { - assert.ifError(err); - }); - call.write({error: false}); - call.write({error: false}); - call.end(); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a client stream call fails', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - }); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('status', function(status) { - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a server stream call succeeds', function(done) { - var call = client.serverStream({error: false}); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a server stream call fails', function(done) { - var call = client.serverStream({error: true}); - call.on('data', function(){}); - call.on('error', function(error) { - assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a bidi stream succeeds', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: false}); - call.end(); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - assert.deepEqual(status.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - it('should be present when a bidi stream fails', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('data', function(){}); - call.on('error', function(error) { - assert.deepEqual(error.metadata.get('trailer-present'), ['yes']); - done(); - }); - }); - }); - describe('Error object should contain the status', function() { - it('for a unary call', function(done) { - client.unary({error: true}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.details, 'Requested error'); - done(); - }); - }); - it('for a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.details, 'Requested error'); - done(); - }); - call.write({error: false}); - call.write({error: true}); - call.end(); - }); - it('for a server stream call', function(done) { - var call = client.serverStream({error: true}); - call.on('data', function(){}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.UNKNOWN); - assert.strictEqual(error.details, 'Requested error'); - done(); - }); - }); - it('for a bidi stream call', function(done) { - var call = client.bidiStream(); - call.write({error: false}); - call.write({error: true}); - call.end(); - call.on('data', function(){}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.UNKNOWN); - assert.strictEqual(error.details, 'Requested error'); - done(); - }); - }); - it('for a UTF-8 error message', function(done) { - client.unary({error: true, message: '測試字符串'}, function(err, data) { - assert(err); - assert.strictEqual(err.code, grpc.status.UNKNOWN); - assert.strictEqual(err.details, '測試字符串'); - done(); - }); - }); - }); - describe('call.getPeer should return the peer', function() { - it('for a unary call', function(done) { - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); - done(); - }); - assert.strictEqual(typeof call.getPeer(), 'string'); - }); - it('for a client stream call', function(done) { - var call = client.clientStream(function(err, data) { - assert.ifError(err); - done(); - }); - assert.strictEqual(typeof call.getPeer(), 'string'); - call.write({error: false}); - call.end(); - }); - it('for a server stream call', function(done) { - var call = client.serverStream({error: false}); - assert.strictEqual(typeof call.getPeer(), 'string'); - call.on('data', function(){}); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); - done(); - }); - }); - it('for a bidi stream call', function(done) { - var call = client.bidiStream(); - assert.strictEqual(typeof call.getPeer(), 'string'); - call.write({error: false}); - call.end(); - call.on('data', function(){}); - call.on('status', function(status) { - done(); - }); - }); - it('after the call has fully completed', function(done) { - var peer; - var call = client.unary({error: false}, function(err, data) { - assert.ifError(err); - setImmediate(function() { - assert.strictEqual(peer, call.getPeer()); - done(); - }); - }); - peer = call.getPeer(); - assert.strictEqual(typeof peer, 'string'); - }); - }); -}); -describe('Call propagation', function() { - var proxy; - var proxy_impl; - - var Client; - var client; - var server; - before(function() { - Client = grpc.load(__dirname + '/test_service.proto').TestService; - server = new grpc.Server(); - server.addService(Client.service, { - unary: function(call) {}, - clientStream: function(stream) {}, - serverStream: function(stream) {}, - bidiStream: function(stream) {} - }); - var port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - beforeEach(function() { - proxy = new grpc.Server(); - proxy_impl = { - unary: function(call) {}, - clientStream: function(stream) {}, - serverStream: function(stream) {}, - bidiStream: function(stream) {} - }; - }); - afterEach(function() { - proxy.forceShutdown(); - }); - describe('Cancellation', function() { - it('With a unary call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.unary = function(parent, callback) { - client.unary(parent.request, {parent: parent}, function(err, value) { - try { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - } finally { - callback(err, value); - done(); - } - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.unary({}, function(err, value) { done(); }); - }); - it('With a client stream call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.clientStream = function(parent, callback) { - client.clientStream({parent: parent}, function(err, value) { - try { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - } finally { - callback(err, value); - done(); - } - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.clientStream(function(err, value) { done(); }); - }); - it('With a server stream call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.serverStream = function(parent) { - var child = client.serverStream(parent.request, {parent: parent}); - child.on('data', function() {}); - child.on('error', function(err) { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.serverStream({}); - call.on('data', function() {}); - call.on('error', function(err) { - done(); - }); - }); - it('With a bidi stream call', function(done) { - done = multiDone(done, 2); - var call; - proxy_impl.bidiStream = function(parent) { - var child = client.bidiStream({parent: parent}); - child.on('data', function() {}); - child.on('error', function(err) { - assert(err); - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - call = proxy_client.bidiStream(); - call.on('data', function() {}); - call.on('error', function(err) { - done(); - }); - }); - }); - describe('Deadline', function() { - /* jshint bitwise:false */ - var deadline_flags = (grpc.propagate.DEFAULTS & - ~grpc.propagate.CANCELLATION); - it('With a client stream call', function(done) { - done = multiDone(done, 2); - proxy_impl.clientStream = function(parent, callback) { - var options = {parent: parent, propagate_flags: deadline_flags}; - client.clientStream(options, function(err, value) { - try { - assert(err); - assert(err.code === grpc.status.DEADLINE_EXCEEDED || - err.code === grpc.status.INTERNAL); - } finally { - callback(err, value); - done(); - } - }); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - proxy_client.clientStream({deadline: deadline}, function(err, value) { - done(); - }); - }); - it('With a bidi stream call', function(done) { - done = multiDone(done, 2); - proxy_impl.bidiStream = function(parent) { - var child = client.bidiStream( - {parent: parent, propagate_flags: deadline_flags}); - child.on('data', function() {}); - child.on('error', function(err) { - assert(err); - assert(err.code === grpc.status.DEADLINE_EXCEEDED || - err.code === grpc.status.INTERNAL); - done(); - }); - }; - proxy.addService(Client.service, proxy_impl); - var proxy_port = proxy.bind('localhost:0', server_insecure_creds); - proxy.start(); - var proxy_client = new Client('localhost:' + proxy_port, - grpc.credentials.createInsecure()); - var deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + 1); - var call = proxy_client.bidiStream({deadline: deadline}); - call.on('data', function() {}); - call.on('error', function(err) { - done(); - }); - }); - }); -}); -describe('Cancelling surface client', function() { - var client; - var server; - before(function() { - server = new grpc.Server(); - server.addService(mathServiceAttrs, { - 'div': function(stream) {}, - 'divMany': function(stream) {}, - 'fib': function(stream) {}, - 'sum': function(stream) {} - }); - var port = server.bind('localhost:0', server_insecure_creds); - var Client = grpc.makeGenericClientConstructor(mathServiceAttrs); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - after(function() { - server.forceShutdown(); - }); - it('Should correctly cancel a unary call', function(done) { - var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should correctly cancel a client stream call', function(done) { - var call = client.sum(function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should correctly cancel a server stream call', function(done) { - var call = client.fib({'limit': 5}); - call.on('data', function() {}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should correctly cancel a bidi stream call', function(done) { - var call = client.divMany(); - call.on('data', function() {}); - call.on('error', function(error) { - assert.strictEqual(error.code, grpc.status.CANCELLED); - done(); - }); - call.cancel(); - }); - it('Should be idempotent', function(done) { - var call = client.div({'divisor': 0, 'dividend': 0}, function(err, resp) { - assert.strictEqual(err.code, grpc.status.CANCELLED); - // Call asynchronously to try cancelling after call is fully completed - setImmediate(function() { - assert.doesNotThrow(function() { - call.cancel(); - }); - done(); - }); - }); - call.cancel(); - }); -}); -describe('Client reconnect', function() { - var server; - var Client; - var client; - var port; - beforeEach(function() { - Client = grpc.load(__dirname + '/echo_service.proto').EchoService; - server = new grpc.Server(); - server.addService(Client.service, { - echo: function(call, callback) { - callback(null, call.request); - } - }); - port = server.bind('localhost:0', server_insecure_creds); - client = new Client('localhost:' + port, grpc.credentials.createInsecure()); - server.start(); - }); - afterEach(function() { - server.forceShutdown(); - }); - it('should reconnect after server restart', function(done) { - client.echo({value: 'test value', value2: 3}, function(error, response) { - assert.ifError(error); - assert.deepEqual(response, {value: 'test value', value2: 3}); - server.tryShutdown(function() { - server = new grpc.Server(); - server.addService(Client.service, { - echo: function(call, callback) { - callback(null, call.request); - } - }); - server.bind('localhost:' + port, server_insecure_creds); - server.start(); - - /* We create a new client, that will not throw an error if the server - * is not immediately available. Instead, it will wait for the server - * to be available, then the call will complete. Once this happens, the - * original client should be able to make a new call and connect to the - * restarted server without having the call fail due to connection - * errors. */ - var client2 = new Client('localhost:' + port, - grpc.credentials.createInsecure()); - client2.echo({value: 'test', value2: 3}, function(error, response) { - assert.ifError(error); - client.echo(undefined, function(error, response) { - if (error) { - console.log(error); - } - assert.ifError(error); - assert.deepEqual(response, {value: '', value2: 0}); - done(); - }); - }); - }); - }); - }); -}); diff --git a/packages/grpc-native-core/test/test_messages.proto b/packages/grpc-native-core/test/test_messages.proto deleted file mode 100644 index da1ef5658..000000000 --- a/packages/grpc-native-core/test/test_messages.proto +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -message LongValues { - int64 int_64 = 1; - uint64 uint_64 = 2; - sint64 sint_64 = 3; - fixed64 fixed_64 = 4; - sfixed64 sfixed_64 = 5; -} - -message SequenceValues { - bytes bytes_field = 1; - repeated int32 repeated_field = 2; -} - -message OneOfValues { - oneof oneof_choice { - int32 int_choice = 1; - string string_choice = 2; - } -} - -enum TestEnum { - ZERO = 0; - ONE = 1; - TWO = 2; -} - -message EnumValues { - TestEnum enum_value = 1; -} diff --git a/packages/grpc-native-core/test/test_service.json b/packages/grpc-native-core/test/test_service.json deleted file mode 100644 index 6f952c6ad..000000000 --- a/packages/grpc-native-core/test/test_service.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "package": null, - "messages": [ - { - "name": "Request", - "fields": [ - { - "rule": "optional", - "type": "bool", - "name": "error", - "id": 1 - } - ] - }, - { - "name": "Response", - "fields": [ - { - "rule": "optional", - "type": "int32", - "name": "count", - "id": 1 - } - ] - } - ], - "services": [ - { - "name": "TestService", - "options": {}, - "rpc": { - "Unary": { - "request": "Request", - "response": "Response", - "options": {} - }, - "ClientStream": { - "request": "Request", - "response": "Response", - "options": {} - }, - "ServerStream": { - "request": "Request", - "response": "Response", - "options": {} - }, - "BidiStream": { - "request": "Request", - "response": "Response", - "options": {} - } - } - } - ] -} \ No newline at end of file diff --git a/packages/grpc-native-core/test/test_service.proto b/packages/grpc-native-core/test/test_service.proto deleted file mode 100644 index a0e49842b..000000000 --- a/packages/grpc-native-core/test/test_service.proto +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2015 gRPC authors. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -syntax = "proto3"; - -message Request { - bool error = 1; - string message = 2; -} - -message Response { - int32 count = 1; -} - -service TestService { - rpc Unary (Request) returns (Response) { - } - - rpc ClientStream (stream Request) returns (Response) { - } - - rpc ServerStream (Request) returns (stream Response) { - } - - rpc BidiStream (stream Request) returns (stream Response) { - } -} diff --git a/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py b/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py deleted file mode 100644 index 17e746a68..000000000 --- a/packages/grpc-native-core/tools/buildgen/gen_build_yaml.py +++ /dev/null @@ -1,115 +0,0 @@ -#!/usr/bin/env python2.7 - -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import print_function -import re -import os -import sys -import yaml - -node_versions = ["4", "5", "6", "7", "8", "9", "10", "11", "12", "13"] -electron_versions = ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5", "1.6", "1.7", "1.8", "2.0", "3.0", "3.1", "4.1", "4.2", "5.0", "6.0", "6.1", "7.0", "7.1", "8.0"] - -def gen_linux_configs(): - configs = [] - - node_arches = ["ia32", "x64", "arm", "arm64", "s390x"] - electron_arches = ["ia32", "x64"] - alpine_arches = ["x64"] - - for version in node_versions: - for arch in node_arches: - configs.append({ - "name": "node_{version}_{arch}_glibc".format(version=version, arch=arch), - "runtime": "node", - "version": version, - "arch": arch, - "libc": "glibc" - }) - for arch in alpine_arches: - configs.append({ - "name": "node_{version}_{arch}_musl".format(version=version, arch=arch), - "runtime": "node", - "version": version, - "arch": arch, - "libc": "glibc" - }) - for version in electron_versions: - for arch in electron_arches: - configs.append({ - "name": "electron_{version}_{arch}_glibc".format(version=version, arch=arch), - "runtime": "electron", - "version": version, - "arch": arch, - "libc": "glibc" - }) - return configs - -def gen_mac_configs(): - configs = [] - - node_arches = ["ia32", "x64"] - electron_arches = ["ia32", "x64"] - - for version in node_versions: - for arch in node_arches: - configs.append({ - "name": "node_{version}_{arch}".format(version=version, arch=arch), - "runtime": "node", - "version": version, - "arch": arch - }) - for version in electron_versions: - for arch in electron_arches: - configs.append({ - "name": "electron_{version}_{arch}".format(version=version, arch=arch), - "runtime": "electron", - "version": version, - "arch": arch - }) - return configs - -def gen_windows_configs(): - configs = [] - - node_arches = ["ia32", "x64"] - electron_arches = ["ia32", "x64"] - - for version in node_versions: - for arch in node_arches: - configs.append({ - "name": "node_{version}_{arch}".format(version=version, arch=arch), - "runtime": "node", - "version": version, - "arch": arch - }) - for version in electron_versions: - for arch in electron_arches: - configs.append({ - "name": "electron_{version}_{arch}".format(version=version, arch=arch), - "runtime": "electron", - "version": version, - "arch": arch - }) - return configs - -out = { - "linux_configs": gen_linux_configs(), - "mac_configs": gen_mac_configs(), - "windows_configs": gen_windows_configs() -} - -print(yaml.dump(out)) \ No newline at end of file diff --git a/packages/grpc-native-core/tools/buildgen/generate_projects.sh b/packages/grpc-native-core/tools/buildgen/generate_projects.sh deleted file mode 100755 index 1a1d7b6fc..000000000 --- a/packages/grpc-native-core/tools/buildgen/generate_projects.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/sh -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - - -set -e - -cd $(dirname $0)/../../../.. -root=$(pwd) -native_root=$root/packages/grpc-native-core - -output_file=$(mktemp /tmp/genXXXXXX) -python $native_root/tools/buildgen/gen_build_yaml.py > $output_file - -$native_root/deps/grpc/tools/buildgen/generate_projects.sh $native_root/build.yaml $output_file --base=$root --templates $(find templates -type f) diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh deleted file mode 100755 index d2c06fc45..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh +++ /dev/null @@ -1,80 +0,0 @@ -#!/bin/bash -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" -nvm install 10 -nvm use 10 -npm install -g npm -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp - -DO_NATIVE=true -DO_CROSS=true -DO_ELECTRON=true -DO_NODEJS=true - -while [ $# -gt 0 ] ; do - case $1 in - --native-only) - DO_CROSS=false - ;; - --cross-only) - DO_NATIVE=false - DO_ELECTRON=false - ;; - --electron-only) - DO_NODEJS=false - DO_CROSS=false - ;; - --nodejs-only) - DO_ELECTRON=false - ;; - esac - shift -done - -set -ex - -cd $(dirname $0) -tool_dir=$(pwd) -cd $tool_dir/../../.. -base_dir=$(pwd) -cd $base_dir/../.. -root_dir=$(pwd) -cd $base_dir - -export ARTIFACTS_OUT=$base_dir/artifacts -export JOBS=8 - -rm -rf build || true - -mkdir -p "${ARTIFACTS_OUT}" - -if [ "$DO_NATIVE" = "true" ] ; then - if [ "$DO_ELECTRON" = "true" ] ; then - $tool_dir/build_artifact_electron.sh - fi - if [ "$DO_NODEJS" = "true" ] ; then - $tool_dir/build_artifact_node.sh - fi -fi - -if [ "$DO_CROSS" = "true" ] ; then - $tool_dir/build_artifact_node_arm.sh - $tool_dir/build_artifact_node_s390x.sh - - docker build -t alpine_node_artifact $root_dir/tools/release/alpine - docker run -e JOBS=8 -e ARTIFACTS_OUT=/var/grpc/artifacts -v $base_dir:/var/grpc alpine_node_artifact /var/grpc/tools/run_tests/artifacts/build_artifact_node.sh --with-alpine -fi diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat deleted file mode 100644 index 56fa530b1..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.bat +++ /dev/null @@ -1,42 +0,0 @@ -@rem Copyright 2016 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -set arch_list=ia32 x64 - -set electron_versions=1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 7.1.0 - -set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm - -set JOBS=8 - -del /f /q BUILD || rmdir build /s /q - -call npm update || goto :error - -mkdir -p %ARTIFACTS_OUT% - -for %%a in (%arch_list%) do ( - for %%v in (%electron_versions%) do ( - cmd /V /C "set "HOME=%USERPROFILE%\electron-gyp" && call .\node_modules\.bin\node-pre-gyp.cmd configure rebuild package --runtime=electron --target=%%v --target_arch=%%a --disturl=https://atom.io/download/electron" || goto :error - - xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error - rmdir build /S /Q - ) -) -if %errorlevel% neq 0 exit /b %errorlevel% - -goto :EOF - -:error -exit /b 1 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh deleted file mode 100755 index f6d3c9620..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -# Copyright 2016 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -arch_list=( ia32 x64 ) -electron_versions=( 1.0.0 1.1.0 1.2.0 1.3.0 1.4.0 1.5.0 1.6.0 1.7.0 1.8.0 2.0.0 3.0.0 3.1.0 4.1.0 4.2.0 5.0.0 6.0.0 6.1.0 7.0.0 7.1.0 ) - -umask 022 - -cd $(dirname $0)/../../.. - -rm -rf build || true - -mkdir -p "${ARTIFACTS_OUT}" - -npm update - -for arch in ${arch_list[@]} -do - for version in ${electron_versions[@]} - do - HOME=~/.electron-gyp ./node_modules/.bin/node-pre-gyp configure rebuild package --runtime=electron --target=$version --target_arch=$arch --disturl=https://atom.io/download/electron - cp -r build/stage/* "${ARTIFACTS_OUT}"/ - done -done - -rm -rf build || true diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat deleted file mode 100644 index 844d571ca..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.bat +++ /dev/null @@ -1,49 +0,0 @@ -@rem Copyright 2016 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -set arch_list=ia32 x64 - -set node_versions=4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 - -set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm - -set JOBS=8 - -del /f /q BUILD || rmdir build /s /q - -call npm update || goto :error - -mkdir -p %ARTIFACTS_OUT% - -for %%a in (%arch_list%) do ( - for %%v in (%node_versions%) do ( - call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%%v --target_arch=%%a - - @rem Try again after removing openssl headers - rmdir "%USERPROFILE%\.node-gyp\%%v\include\node\openssl" /S /Q - rmdir "%USERPROFILE%\.node-gyp\iojs-%%v\include\node\openssl" /S /Q - rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\%%v\include\node\openssl" /S /Q - rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\iojs-%%v\include\node\openssl" /S /Q - call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%%v --target_arch=%%a || goto :error - - xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error - rmdir build /S /Q - ) -) -if %errorlevel% neq 0 exit /b %errorlevel% - -goto :EOF - -:error -exit /b 1 diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh deleted file mode 100755 index 4f459dc6a..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# Copyright 2016 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -arch_list=( ia32 x64 ) -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 ) - -while true ; do - case $1 in - --with-alpine) - arch_list=( x64 ) - ;; - "") - ;; - *) - echo "Unknown parameter: $1" - exit 1 - ;; - esac - shift || break -done - -umask 022 - -cd $(dirname $0)/../../.. - -rm -rf build || true - -mkdir -p "${ARTIFACTS_OUT}" - -npm update - -for arch in ${arch_list[@]} -do - for version in ${node_versions[@]} - do - ./node_modules/.bin/node-pre-gyp configure rebuild package --target=$version --target_arch=$arch - cp -r build/stage/* "${ARTIFACTS_OUT}"/ - done -done - -rm -rf build || true diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh deleted file mode 100755 index a6e414f90..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_arm.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/bash -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp - -cd $(dirname $0)/../../.. - -rm -rf build || true - -mkdir -p "${ARTIFACTS_OUT}" - -npm update - -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 ) - -for version in ${node_versions[@]} -do - # Cross compile for ARM on x64 - # Requires debian or ubuntu packages "g++-aarch64-linux-gnu" and "g++-arm-linux-gnueabihf". - CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ LD=arm-linux-gnueabihf-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm - cp -r build/stage/* "${ARTIFACTS_OUT}"/ - CC=aarch64-linux-gnu-gcc CXX=aarch64-linux-gnu-g++ LD=aarch64-linux-gnu-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=arm64 - cp -r build/stage/* "${ARTIFACTS_OUT}"/ -done diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh deleted file mode 100755 index 818d96632..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node_s390x.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/bash - -set -ex - -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp - -cd $(dirname $0)/../../.. - -rm -rf build || true - -mkdir -p "${ARTIFACTS_OUT}" - -npm update - -node_versions=( 4.0.0 5.0.0 6.0.0 7.0.0 8.0.0 9.0.0 10.0.0 11.0.0 12.0.0 13.0.0 ) - -for version in ${node_versions[@]} -do - # Cross compile for s390x on x64 - # Requires debian or ubuntu packages "g++-s390x-linux-gnu". - CC=s390x-linux-gnu-gcc CXX=s390x-linux-gnu-g++ LD=s390x-linux-gnu-g++ ./node_modules/.bin/node-pre-gyp configure rebuild package testpackage --target=$version --target_arch=s390x - cp -r build/stage/* "${ARTIFACTS_OUT}"/ -done diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat deleted file mode 100644 index 9b3829d27..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat +++ /dev/null @@ -1,63 +0,0 @@ -@rem Copyright 2016 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@echo "Starting Windows build" - -powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" - -call nvm install 10 -call nvm use 10 - -call npm install -g npm@6.10.x -@rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp@3 - -cd /d %~dp0 -cd ..\..\..\..\.. - -git submodule update --init --recursive - -set ARTIFACTS_OUT=%cd%\artifacts - -cd packages\grpc-native-core - -set PATH=%PATH%;C:\Program Files\nodejs\;%APPDATA%\npm - -set JOBS=8 - -del /f /q BUILD || rmdir build /s /q - -call npm update || goto :error - -if "%RUNTIME%"=="electron" ( - set "HOME=%USERPROFILE%\electron-gyp" - set "npm_config_disturl=https://atom.io/download/electron" -) - -call .\node_modules\.bin\node-pre-gyp.cmd configure build --target=%VERSION% --target_arch=%ARCH% && goto :EOF -@rem Try again after removing openssl headers -rmdir "%USERPROFILE%\.node-gyp\%VERSION%\include\node\openssl" /S /Q -rmdir "%USERPROFILE%\.node-gyp\iojs-%VERSION%\include\node\openssl" /S /Q -rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\%VERSION%\include\node\openssl" /S /Q -rmdir "%USERPROFILE%\AppData\Local\node-gyp\cache\iojs-%VERSION%\include\node\openssl" /S /Q -call .\node_modules\.bin\node-pre-gyp.cmd build package --target=%VERSION% --target_arch=%ARCH% || goto :error - -xcopy /Y /I /S build\stage\* %ARTIFACTS_OUT%\ || goto :error - -if %errorlevel% neq 0 exit /b %errorlevel% - -goto :EOF - -:error -exit /b 1 \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh deleted file mode 100644 index 5630444ce..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh +++ /dev/null @@ -1,54 +0,0 @@ -#!/bin/bash -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -nvm install 10 -nvm use 10 -npm install -g npm -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp - -# $ARCH should only have one of these values if the script is being called in -# an environment with these cross compiler packages installed -case $ARCH in - arm) - export CC=arm-linux-gnueabihf-gcc - export CXX=arm-linux-gnueabihf-g++ - export CXX=arm-linux-gnueabihf-g++ - ;; - arm64) - export CC=aarch64-linux-gnu-gcc - export CXX=aarch64-linux-gnu-g++ - export LD=aarch64-linux-gnu-g++ - ;; - s390x) - export CC=s390x-linux-gnu-gcc - export CXX=s390x-linux-gnu-g++ - export LD=s390x-linux-gnu-g++ - ;; -esac - -case $RUNTIME in - electron) - export HOME=~/.electron-gyp - export npm_config_disturl=https://atom.io/download/electron - ;; -esac - -./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH --runtime=$RUNTIME --target_libc=$LIBC -cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh deleted file mode 100644 index 2a1beddc1..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/bin/bash -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Expected environment variables: -# VERSION: the node version to build for -# ARCH: the processor architecture to build for -# RUNTIME: node or electron -# LIBC: the libc to build for, glibc or musl - -set -ex -cd $(dirname $0)/../../../../.. -base_dir=$(pwd) - -export ARTIFACTS_OUT=$base_dir/artifacts - -mkdir -p $ARTIFACTS_OUT - -cd $base_dir/packages/grpc-native-core - -# Install gRPC and its submodules. -git submodule update --init --recursive - -case $ARCH in - arm|arm64|s390x) - docker build -t artifact-image $base_dir/tools/release/cross - ;; - *) - case $LIBC in - musl) - docker build -t artifact-image $base_dir/tools/release/alpine_artifact - ;; - *) - docker build -t artifact-image $base_dir/tools/release/native - ;; - esac - ;; -esac - -docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir -e ARCH -e VERSION -e RUNTIME -e LIBC -e ARTIFACTS_OUT artifact-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_in_docker.sh \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh deleted file mode 100755 index a92f8a2a6..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh +++ /dev/null @@ -1,55 +0,0 @@ -#!/bin/bash -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -nvm install 10 -nvm use 10 -npm install -g npm -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp - -set -ex -brew install make -PATH="$(brew --prefix)/opt/make/libexec/gnubin:$PATH" -cd $(dirname $0)/../../../../.. -base_dir=$(pwd) - -cd $base_dir/packages/grpc-native-core - -# Install gRPC and its submodules. -git submodule update --init --recursive - -export JOBS=8 -export ARTIFACTS_OUT=$base_dir/artifacts - -mkdir -p ${ARTIFACTS_OUT} - -rm -rf build || true - -npm update - -case $RUNTIME in - electron) - export HOME=~/.electron-gyp - export npm_config_disturl=https://atom.io/download/electron - ;; - node) -esac - -./node_modules/.bin/node-pre-gyp configure rebuild package --target=$VERSION --target_arch=$ARCH --runtime=$RUNTIME -cp -r build/stage/* "${ARTIFACTS_OUT}"/ \ No newline at end of file diff --git a/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh b/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh deleted file mode 100755 index 412d0be23..000000000 --- a/packages/grpc-native-core/tools/run_tests/artifacts/build_package_node.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash -# Copyright 2016 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -ex - -cd $(dirname $0)/../../.. - -base=$(pwd) - -artifacts=$base/artifacts - -mkdir -p $artifacts -cp -r $EXTERNAL_GIT_ROOT/platform={windows,linux,macos}/artifacts/node_ext_*/* $artifacts/ || true - -npm update -npm pack - -cp grpc-*.tgz $artifacts/grpc.tgz - -mkdir -p bin - -cd $base/src/node/health_check -npm pack -cp grpc-health-check-*.tgz $artifacts/ - -cd $base/src/node/tools -npm update -npm pack -cp grpc-tools-*.tgz $artifacts/ -tools_version=$(npm list | grep -oP '(?<=grpc-tools@)\S+') - -output_dir=$artifacts/grpc-precompiled-binaries/node/grpc-tools/v$tools_version -mkdir -p $output_dir - -well_known_protos=( any api compiler/plugin descriptor duration empty field_mask source_context struct timestamp type wrappers ) - -for arch in {x86,x64}; do - case $arch in - x86) - node_arch=ia32 - ;; - *) - node_arch=$arch - ;; - esac - for plat in {windows,linux,macos}; do - case $plat in - windows) - node_plat=win32 - ;; - macos) - node_plat=darwin - ;; - *) - node_plat=$plat - ;; - esac - rm -r bin/* - input_dir="$EXTERNAL_GIT_ROOT/platform=${plat}/artifacts/protoc_${plat}_${arch}" - cp $input_dir/protoc* bin/ - cp $input_dir/grpc_node_plugin* bin/ - mkdir -p bin/google/protobuf - mkdir -p bin/google/protobuf/compiler # needed for plugin.proto - for proto in "${well_known_protos[@]}"; do - cp $base/third_party/protobuf/src/google/protobuf/$proto.proto bin/google/protobuf/$proto.proto - done - tar -czf $output_dir/$node_plat-$node_arch.tar.gz bin/ - done -done From eb475ec92c9779a2037e8cb18761e8331a56f16b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 May 2020 15:05:47 -0700 Subject: [PATCH 1073/1899] Remove references and unnecessary scripts, copy some protos --- .gitignore | 2 - README.md | 2 +- gulpfile.ts | 31 +- package.json | 4 +- packages/grpc-health-check/gulpfile.ts | 14 +- run-tests.bat | 2 +- templates/tools/release/kokoro/linux.template | 48 --- templates/tools/release/kokoro/macos.template | 44 --- .../tools/release/kokoro/windows.template | 44 --- test-grpc-submodule.sh | 31 -- test/any_grpc.js | 2 +- test/api/interop_extra_test.js | 2 +- test/gulpfile.ts | 8 +- test/interop/interop_client.js | 2 +- test/interop/interop_server.js | 2 +- test/kokoro-nodejs-build-test.bat | 1 - test/kokoro-nodejs-build-test.sh | 1 - test/kokoro.bat | 2 - test/kokoro.sh | 15 - test/kokoro/linux-build-electron.cfg | 19 -- test/kokoro/macos-build-electron.cfg | 19 -- test/kokoro/windows-build-electron.cfg | 19 -- test/package.json | 1 + test/performance/benchmark_client.js | 2 +- test/performance/benchmark_server.js | 2 +- test/performance/worker.js | 2 +- test/proto/src/proto/grpc/core/stats.proto | 38 +++ .../grpc/testing/benchmark_service.proto | 44 +++ .../src/proto/grpc/testing/control.proto | 289 ++++++++++++++++++ test/proto/src/proto/grpc/testing/empty.proto | 28 ++ .../src/proto/grpc/testing/messages.proto | 209 +++++++++++++ .../src/proto/grpc/testing/metrics.proto | 49 +++ .../src/proto/grpc/testing/payloads.proto | 40 +++ test/proto/src/proto/grpc/testing/stats.proto | 83 +++++ test/proto/src/proto/grpc/testing/test.proto | 86 ++++++ .../proto/grpc/testing/worker_service.proto | 45 +++ test/stress/metrics_client.js | 2 +- test/stress/metrics_server.js | 2 +- tools/release/alpine/Dockerfile | 2 - tools/release/cross/Dockerfile | 11 - tools/release/kokoro-electron.bat | 41 --- tools/release/kokoro-electron.sh | 50 --- tools/release/kokoro-nodejs.bat | 40 --- tools/release/kokoro-nodejs.sh | 53 ---- tools/release/kokoro/linux-electron.cfg | 25 -- tools/release/kokoro/linux-nodejs.cfg | 25 -- .../kokoro/linux/electron_1.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.0_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.1_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.1_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.2_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.2_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.3_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.3_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.4_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.4_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.5_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.5_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.6_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.6_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.7_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.7_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_1.8_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_1.8_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_2.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_2.0_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_3.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_3.0_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_3.1_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_3.1_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_4.1_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_4.1_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_4.2_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_4.2_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_5.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_5.0_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_6.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_6.0_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_6.1_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_6.1_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_7.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_7.0_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_7.1_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_7.1_x64_glibc.cfg | 39 --- .../kokoro/linux/electron_8.0_ia32_glibc.cfg | 39 --- .../kokoro/linux/electron_8.0_x64_glibc.cfg | 39 --- .../kokoro/linux/node_10_arm64_glibc.cfg | 39 --- .../kokoro/linux/node_10_arm_glibc.cfg | 39 --- .../kokoro/linux/node_10_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_10_s390x_glibc.cfg | 39 --- .../kokoro/linux/node_10_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_10_x64_musl.cfg | 39 --- .../kokoro/linux/node_11_arm64_glibc.cfg | 39 --- .../kokoro/linux/node_11_arm_glibc.cfg | 39 --- .../kokoro/linux/node_11_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_11_s390x_glibc.cfg | 39 --- .../kokoro/linux/node_11_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_11_x64_musl.cfg | 39 --- .../kokoro/linux/node_12_arm64_glibc.cfg | 39 --- .../kokoro/linux/node_12_arm_glibc.cfg | 39 --- .../kokoro/linux/node_12_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_12_s390x_glibc.cfg | 39 --- .../kokoro/linux/node_12_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_12_x64_musl.cfg | 39 --- .../kokoro/linux/node_13_arm64_glibc.cfg | 39 --- .../kokoro/linux/node_13_arm_glibc.cfg | 39 --- .../kokoro/linux/node_13_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_13_s390x_glibc.cfg | 39 --- .../kokoro/linux/node_13_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_13_x64_musl.cfg | 39 --- .../kokoro/linux/node_4_arm64_glibc.cfg | 39 --- .../release/kokoro/linux/node_4_arm_glibc.cfg | 39 --- .../kokoro/linux/node_4_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_4_s390x_glibc.cfg | 39 --- .../release/kokoro/linux/node_4_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_4_x64_musl.cfg | 39 --- .../kokoro/linux/node_5_arm64_glibc.cfg | 39 --- .../release/kokoro/linux/node_5_arm_glibc.cfg | 39 --- .../kokoro/linux/node_5_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_5_s390x_glibc.cfg | 39 --- .../release/kokoro/linux/node_5_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_5_x64_musl.cfg | 39 --- .../kokoro/linux/node_6_arm64_glibc.cfg | 39 --- .../release/kokoro/linux/node_6_arm_glibc.cfg | 39 --- .../kokoro/linux/node_6_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_6_s390x_glibc.cfg | 39 --- .../release/kokoro/linux/node_6_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_6_x64_musl.cfg | 39 --- .../kokoro/linux/node_7_arm64_glibc.cfg | 39 --- .../release/kokoro/linux/node_7_arm_glibc.cfg | 39 --- .../kokoro/linux/node_7_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_7_s390x_glibc.cfg | 39 --- .../release/kokoro/linux/node_7_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_7_x64_musl.cfg | 39 --- .../kokoro/linux/node_8_arm64_glibc.cfg | 39 --- .../release/kokoro/linux/node_8_arm_glibc.cfg | 39 --- .../kokoro/linux/node_8_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_8_s390x_glibc.cfg | 39 --- .../release/kokoro/linux/node_8_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_8_x64_musl.cfg | 39 --- .../kokoro/linux/node_9_arm64_glibc.cfg | 39 --- .../release/kokoro/linux/node_9_arm_glibc.cfg | 39 --- .../kokoro/linux/node_9_ia32_glibc.cfg | 39 --- .../kokoro/linux/node_9_s390x_glibc.cfg | 39 --- .../release/kokoro/linux/node_9_x64_glibc.cfg | 39 --- .../release/kokoro/linux/node_9_x64_musl.cfg | 39 --- tools/release/kokoro/macos-electron.cfg | 25 -- tools/release/kokoro/macos-nodejs.cfg | 25 -- .../kokoro/macos/electron_1.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.0_x64.cfg | 35 --- .../kokoro/macos/electron_1.1_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.1_x64.cfg | 35 --- .../kokoro/macos/electron_1.2_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.2_x64.cfg | 35 --- .../kokoro/macos/electron_1.3_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.3_x64.cfg | 35 --- .../kokoro/macos/electron_1.4_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.4_x64.cfg | 35 --- .../kokoro/macos/electron_1.5_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.5_x64.cfg | 35 --- .../kokoro/macos/electron_1.6_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.6_x64.cfg | 35 --- .../kokoro/macos/electron_1.7_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.7_x64.cfg | 35 --- .../kokoro/macos/electron_1.8_ia32.cfg | 35 --- .../release/kokoro/macos/electron_1.8_x64.cfg | 35 --- .../kokoro/macos/electron_2.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_2.0_x64.cfg | 35 --- .../kokoro/macos/electron_3.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_3.0_x64.cfg | 35 --- .../kokoro/macos/electron_3.1_ia32.cfg | 35 --- .../release/kokoro/macos/electron_3.1_x64.cfg | 35 --- .../kokoro/macos/electron_4.1_ia32.cfg | 35 --- .../release/kokoro/macos/electron_4.1_x64.cfg | 35 --- .../kokoro/macos/electron_4.2_ia32.cfg | 35 --- .../release/kokoro/macos/electron_4.2_x64.cfg | 35 --- .../kokoro/macos/electron_5.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_5.0_x64.cfg | 35 --- .../kokoro/macos/electron_6.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_6.0_x64.cfg | 35 --- .../kokoro/macos/electron_6.1_ia32.cfg | 35 --- .../release/kokoro/macos/electron_6.1_x64.cfg | 35 --- .../kokoro/macos/electron_7.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_7.0_x64.cfg | 35 --- .../kokoro/macos/electron_7.1_ia32.cfg | 35 --- .../release/kokoro/macos/electron_7.1_x64.cfg | 35 --- .../kokoro/macos/electron_8.0_ia32.cfg | 35 --- .../release/kokoro/macos/electron_8.0_x64.cfg | 35 --- tools/release/kokoro/macos/node_10_ia32.cfg | 35 --- tools/release/kokoro/macos/node_10_x64.cfg | 35 --- tools/release/kokoro/macos/node_11_ia32.cfg | 35 --- tools/release/kokoro/macos/node_11_x64.cfg | 35 --- tools/release/kokoro/macos/node_12_ia32.cfg | 35 --- tools/release/kokoro/macos/node_12_x64.cfg | 35 --- tools/release/kokoro/macos/node_13_ia32.cfg | 35 --- tools/release/kokoro/macos/node_13_x64.cfg | 35 --- tools/release/kokoro/macos/node_4_ia32.cfg | 35 --- tools/release/kokoro/macos/node_4_x64.cfg | 35 --- tools/release/kokoro/macos/node_5_ia32.cfg | 35 --- tools/release/kokoro/macos/node_5_x64.cfg | 35 --- tools/release/kokoro/macos/node_6_ia32.cfg | 35 --- tools/release/kokoro/macos/node_6_x64.cfg | 35 --- tools/release/kokoro/macos/node_7_ia32.cfg | 35 --- tools/release/kokoro/macos/node_7_x64.cfg | 35 --- tools/release/kokoro/macos/node_8_ia32.cfg | 35 --- tools/release/kokoro/macos/node_8_x64.cfg | 35 --- tools/release/kokoro/macos/node_9_ia32.cfg | 35 --- tools/release/kokoro/macos/node_9_x64.cfg | 35 --- tools/release/kokoro/windows-electron.cfg | 25 -- tools/release/kokoro/windows-nodejs.cfg | 25 -- .../kokoro/windows/electron_1.0_ia32.cfg | 35 --- .../kokoro/windows/electron_1.0_x64.cfg | 35 --- .../kokoro/windows/electron_1.1_ia32.cfg | 35 --- .../kokoro/windows/electron_1.1_x64.cfg | 35 --- .../kokoro/windows/electron_1.2_ia32.cfg | 35 --- .../kokoro/windows/electron_1.2_x64.cfg | 35 --- .../kokoro/windows/electron_1.3_ia32.cfg | 35 --- .../kokoro/windows/electron_1.3_x64.cfg | 35 --- .../kokoro/windows/electron_1.4_ia32.cfg | 35 --- .../kokoro/windows/electron_1.4_x64.cfg | 35 --- .../kokoro/windows/electron_1.5_ia32.cfg | 35 --- .../kokoro/windows/electron_1.5_x64.cfg | 35 --- .../kokoro/windows/electron_1.6_ia32.cfg | 35 --- .../kokoro/windows/electron_1.6_x64.cfg | 35 --- .../kokoro/windows/electron_1.7_ia32.cfg | 35 --- .../kokoro/windows/electron_1.7_x64.cfg | 35 --- .../kokoro/windows/electron_1.8_ia32.cfg | 35 --- .../kokoro/windows/electron_1.8_x64.cfg | 35 --- .../kokoro/windows/electron_2.0_ia32.cfg | 35 --- .../kokoro/windows/electron_2.0_x64.cfg | 35 --- .../kokoro/windows/electron_3.0_ia32.cfg | 35 --- .../kokoro/windows/electron_3.0_x64.cfg | 35 --- .../kokoro/windows/electron_3.1_ia32.cfg | 35 --- .../kokoro/windows/electron_3.1_x64.cfg | 35 --- .../kokoro/windows/electron_4.1_ia32.cfg | 35 --- .../kokoro/windows/electron_4.1_x64.cfg | 35 --- .../kokoro/windows/electron_4.2_ia32.cfg | 35 --- .../kokoro/windows/electron_4.2_x64.cfg | 35 --- .../kokoro/windows/electron_5.0_ia32.cfg | 35 --- .../kokoro/windows/electron_5.0_x64.cfg | 35 --- .../kokoro/windows/electron_6.0_ia32.cfg | 35 --- .../kokoro/windows/electron_6.0_x64.cfg | 35 --- .../kokoro/windows/electron_6.1_ia32.cfg | 35 --- .../kokoro/windows/electron_6.1_x64.cfg | 35 --- .../kokoro/windows/electron_7.0_ia32.cfg | 35 --- .../kokoro/windows/electron_7.0_x64.cfg | 35 --- .../kokoro/windows/electron_7.1_ia32.cfg | 35 --- .../kokoro/windows/electron_7.1_x64.cfg | 35 --- .../kokoro/windows/electron_8.0_ia32.cfg | 35 --- .../kokoro/windows/electron_8.0_x64.cfg | 35 --- tools/release/kokoro/windows/node_10_ia32.cfg | 35 --- tools/release/kokoro/windows/node_10_x64.cfg | 35 --- tools/release/kokoro/windows/node_11_ia32.cfg | 35 --- tools/release/kokoro/windows/node_11_x64.cfg | 35 --- tools/release/kokoro/windows/node_12_ia32.cfg | 35 --- tools/release/kokoro/windows/node_12_x64.cfg | 35 --- tools/release/kokoro/windows/node_13_ia32.cfg | 35 --- tools/release/kokoro/windows/node_13_x64.cfg | 35 --- tools/release/kokoro/windows/node_4_ia32.cfg | 35 --- tools/release/kokoro/windows/node_4_x64.cfg | 35 --- tools/release/kokoro/windows/node_5_ia32.cfg | 35 --- tools/release/kokoro/windows/node_5_x64.cfg | 35 --- tools/release/kokoro/windows/node_6_ia32.cfg | 35 --- tools/release/kokoro/windows/node_6_x64.cfg | 35 --- tools/release/kokoro/windows/node_7_ia32.cfg | 35 --- tools/release/kokoro/windows/node_7_x64.cfg | 35 --- tools/release/kokoro/windows/node_8_ia32.cfg | 35 --- tools/release/kokoro/windows/node_8_x64.cfg | 35 --- tools/release/kokoro/windows/node_9_ia32.cfg | 35 --- tools/release/kokoro/windows/node_9_x64.cfg | 35 --- 270 files changed, 935 insertions(+), 8748 deletions(-) delete mode 100644 templates/tools/release/kokoro/linux.template delete mode 100644 templates/tools/release/kokoro/macos.template delete mode 100644 templates/tools/release/kokoro/windows.template delete mode 100755 test-grpc-submodule.sh delete mode 100644 test/kokoro/linux-build-electron.cfg delete mode 100644 test/kokoro/macos-build-electron.cfg delete mode 100644 test/kokoro/windows-build-electron.cfg create mode 100644 test/proto/src/proto/grpc/core/stats.proto create mode 100644 test/proto/src/proto/grpc/testing/benchmark_service.proto create mode 100644 test/proto/src/proto/grpc/testing/control.proto create mode 100644 test/proto/src/proto/grpc/testing/empty.proto create mode 100644 test/proto/src/proto/grpc/testing/messages.proto create mode 100644 test/proto/src/proto/grpc/testing/metrics.proto create mode 100644 test/proto/src/proto/grpc/testing/payloads.proto create mode 100644 test/proto/src/proto/grpc/testing/stats.proto create mode 100644 test/proto/src/proto/grpc/testing/test.proto create mode 100644 test/proto/src/proto/grpc/testing/worker_service.proto delete mode 100644 tools/release/alpine/Dockerfile delete mode 100644 tools/release/cross/Dockerfile delete mode 100644 tools/release/kokoro-electron.bat delete mode 100755 tools/release/kokoro-electron.sh delete mode 100644 tools/release/kokoro-nodejs.bat delete mode 100755 tools/release/kokoro-nodejs.sh delete mode 100644 tools/release/kokoro/linux-electron.cfg delete mode 100644 tools/release/kokoro/linux-nodejs.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_10_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_10_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_10_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_10_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_10_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_10_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_11_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_11_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_11_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_11_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_11_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_11_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_12_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_12_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_12_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_12_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_12_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_12_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_13_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_13_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_13_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_13_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_13_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_13_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_4_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_4_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_4_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_4_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_4_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_4_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_5_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_5_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_5_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_5_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_5_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_5_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_6_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_6_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_6_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_6_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_6_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_6_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_7_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_7_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_7_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_7_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_7_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_7_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_8_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_8_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_8_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_8_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_8_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_8_x64_musl.cfg delete mode 100644 tools/release/kokoro/linux/node_9_arm64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_9_arm_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_9_ia32_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_9_s390x_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_9_x64_glibc.cfg delete mode 100644 tools/release/kokoro/linux/node_9_x64_musl.cfg delete mode 100644 tools/release/kokoro/macos-electron.cfg delete mode 100644 tools/release/kokoro/macos-nodejs.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.1_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.1_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.2_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.2_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.3_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.3_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.4_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.4_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.5_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.5_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.6_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.6_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.7_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.7_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.8_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_1.8_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_2.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_2.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_3.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_3.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_3.1_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_3.1_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_4.1_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_4.1_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_4.2_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_4.2_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_5.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_5.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_6.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_6.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_6.1_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_6.1_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_7.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_7.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_7.1_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_7.1_x64.cfg delete mode 100644 tools/release/kokoro/macos/electron_8.0_ia32.cfg delete mode 100644 tools/release/kokoro/macos/electron_8.0_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_10_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_10_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_11_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_11_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_12_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_12_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_13_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_13_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_4_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_4_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_5_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_5_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_6_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_6_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_7_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_7_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_8_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_8_x64.cfg delete mode 100644 tools/release/kokoro/macos/node_9_ia32.cfg delete mode 100644 tools/release/kokoro/macos/node_9_x64.cfg delete mode 100644 tools/release/kokoro/windows-electron.cfg delete mode 100644 tools/release/kokoro/windows-nodejs.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.1_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.1_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.2_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.2_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.3_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.3_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.4_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.4_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.5_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.5_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.6_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.6_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.7_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.7_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.8_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_1.8_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_2.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_2.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_3.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_3.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_3.1_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_3.1_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_4.1_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_4.1_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_4.2_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_4.2_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_5.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_5.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_6.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_6.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_6.1_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_6.1_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_7.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_7.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_7.1_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_7.1_x64.cfg delete mode 100644 tools/release/kokoro/windows/electron_8.0_ia32.cfg delete mode 100644 tools/release/kokoro/windows/electron_8.0_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_10_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_10_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_11_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_11_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_12_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_12_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_13_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_13_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_4_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_4_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_5_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_5_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_6_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_6_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_7_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_7_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_8_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_8_x64.cfg delete mode 100644 tools/release/kokoro/windows/node_9_ia32.cfg delete mode 100644 tools/release/kokoro/windows/node_9_x64.cfg diff --git a/.gitignore b/.gitignore index eb5696caf..fce837e45 100644 --- a/.gitignore +++ b/.gitignore @@ -11,8 +11,6 @@ yarn.lock \#*\# .\#* -packages/grpc-native-core/src/node/ - .nyc_output/ reports/ diff --git a/README.md b/README.md index cc6c10ee4..159fbab4f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ For a comparison of the features available in these two libraries, see [this doc ### C-based Client and Server -Directory: [`packages/grpc-native-core`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-native-core) (see here for installation information) +Directory: [`packages/grpc-native-core`](https://github.com/grpc/grpc-node/tree/grpc@1.24.x/packages/grpc-native-core) (lives in the `grpc@1.24.x` branch) (see here for installation information) npm package: [grpc](https://www.npmjs.com/package/grpc). diff --git a/gulpfile.ts b/gulpfile.ts index 6f4b8f329..367b4d1ba 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -18,33 +18,24 @@ import * as gulp from 'gulp'; import * as healthCheck from './packages/grpc-health-check/gulpfile'; import * as jsCore from './packages/grpc-js/gulpfile'; -import * as nativeCore from './packages/grpc-native-core/gulpfile'; import * as protobuf from './packages/proto-loader/gulpfile'; import * as internalTest from './test/gulpfile'; -const root = __dirname; +const installAll = gulp.series(jsCore.install, healthCheck.install, protobuf.install, internalTest.install); -const installAll = gulp.series(jsCore.install, nativeCore.install, healthCheck.install, protobuf.install, internalTest.install); +const lint = gulp.parallel(jsCore.lint); -const installAllWindows = gulp.series(jsCore.install, nativeCore.installWindows, healthCheck.install, protobuf.install, internalTest.install); +const build = gulp.series(jsCore.compile, protobuf.compile); -const lint = gulp.parallel(jsCore.lint, nativeCore.lint); - -const build = gulp.series(jsCore.compile, nativeCore.build, protobuf.compile); - -const link = gulp.series(healthCheck.linkAdd); - -const setup = gulp.series(installAll, link); - -const setupWindows = gulp.series(installAllWindows, link); +const setup = gulp.series(installAll); const setupPureJSInterop = gulp.series(jsCore.install, protobuf.install, internalTest.install); -const clean = gulp.series(jsCore.clean, nativeCore.clean, protobuf.clean); +const clean = gulp.series(jsCore.clean, protobuf.clean); -const cleanAll = gulp.series(jsCore.cleanAll, nativeCore.cleanAll, healthCheck.cleanAll, internalTest.cleanAll, protobuf.cleanAll); +const cleanAll = gulp.series(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll); -const nativeTestOnly = gulp.parallel(nativeCore.test, healthCheck.test); +const nativeTestOnly = gulp.parallel(healthCheck.test); const nativeTest = gulp.series(build, nativeTestOnly); @@ -52,21 +43,15 @@ const testOnly = gulp.parallel(jsCore.test, nativeTestOnly, protobuf.test); const test = gulp.series(build, testOnly, internalTest.test); -const docGen = gulp.series(nativeCore.docGen); - export { installAll, - installAllWindows, lint, build, - link, setup, - setupWindows, setupPureJSInterop, clean, cleanAll, nativeTestOnly, nativeTest, - test, - docGen + test }; diff --git a/package.json b/package.json index cfa23507f..70a15fbbf 100644 --- a/package.json +++ b/package.json @@ -54,15 +54,13 @@ "include": [ "packages/grpc-health-check/health.js", "packages/grpc-js/build/src/*", - "packages/grpc-native-core/index.js", - "packages/grpc-native-core/src/*.js", "packages/proto-loader/build/src/*" ], "cache": true, "all": true }, "scripts": { - "test": "nyc gulp test && GRPC_DNS_RESOLVER=ares nyc gulp nativeTestOnly", + "test": "nyc gulp test", "coverage": "nyc report --reporter=text-lcov | coveralls" } } diff --git a/packages/grpc-health-check/gulpfile.ts b/packages/grpc-health-check/gulpfile.ts index c01f133d5..74c571fe0 100644 --- a/packages/grpc-health-check/gulpfile.ts +++ b/packages/grpc-health-check/gulpfile.ts @@ -26,25 +26,13 @@ const healthCheckDir = __dirname; const baseDir = path.resolve(healthCheckDir, '..', '..'); const testDir = path.resolve(healthCheckDir, 'test'); -const cleanLinks = () => del(path.resolve(healthCheckDir, 'node_modules/grpc')); - -const cleanAll = gulp.parallel(cleanLinks); - const runInstall = () => execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); -const install = gulp.series(cleanLinks, runInstall); - -const linkAdd = (callback) => { - linkSync(healthCheckDir, './node_modules/grpc', '../grpc-native-core'); - callback(); -} +const install = gulp.series(runInstall); const test = () => gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); export { - cleanLinks, - cleanAll, install, - linkAdd, test } \ No newline at end of file diff --git a/run-tests.bat b/run-tests.bat index 64396be17..1eebbd4a6 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -54,7 +54,7 @@ for %%v in (8 10 12) do ( node -e "process.exit(process.version.startsWith('v%%v') ? 0 : -1)" || goto :error call .\node_modules\.bin\gulp cleanAll || SET FAILED=1 - call .\node_modules\.bin\gulp setupWindows || SET FAILED=1 + call .\node_modules\.bin\gulp setup || SET FAILED=1 call .\node_modules\.bin\gulp test || SET FAILED=1 cmd.exe /c "SET GRPC_DNS_RESOLVER=ares& call .\node_modules\.bin\gulp nativeTestOnly" || SET FAILED=1 ) diff --git a/templates/tools/release/kokoro/linux.template b/templates/tools/release/kokoro/linux.template deleted file mode 100644 index a1cf84c8c..000000000 --- a/templates/tools/release/kokoro/linux.template +++ /dev/null @@ -1,48 +0,0 @@ -%YAML 1.2 ---- -foreach: linux_configs -output_name: ${selected.name}.cfg -template: | - # Copyright 2020 gRPC authors. - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - - # Config file for Kokoro (in protobuf text format) - - build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" - env_vars { - key: "RUNTIME" - value: "${selected.runtime}" - } - env_vars { - key: "ARCH" - value: "${selected.arch}" - } - env_vars { - key: "VERSION" - %if selected.runtime == "node": - value: "${selected.version}.0.0" - %else: - value: "${selected.version}.0" - %endif - } - env_vars { - key: "LIBC" - value: "${selected.libc}" - } - action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } - } diff --git a/templates/tools/release/kokoro/macos.template b/templates/tools/release/kokoro/macos.template deleted file mode 100644 index 67c0c7ff7..000000000 --- a/templates/tools/release/kokoro/macos.template +++ /dev/null @@ -1,44 +0,0 @@ -%YAML 1.2 ---- -foreach: mac_configs -output_name: ${selected.name}.cfg -template: | - # Copyright 2020 gRPC authors. - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - - # Config file for Kokoro (in protobuf text format) - - build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" - env_vars { - key: "RUNTIME" - value: "${selected.runtime}" - } - env_vars { - key: "ARCH" - value: "${selected.arch}" - } - env_vars { - key: "VERSION" - %if selected.runtime == "node": - value: "${selected.version}.0.0" - %else: - value: "${selected.version}.0" - %endif - } - action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } - } diff --git a/templates/tools/release/kokoro/windows.template b/templates/tools/release/kokoro/windows.template deleted file mode 100644 index a19dcfa1e..000000000 --- a/templates/tools/release/kokoro/windows.template +++ /dev/null @@ -1,44 +0,0 @@ -%YAML 1.2 ---- -foreach: mac_configs -output_name: ${selected.name}.cfg -template: | - # Copyright 2020 gRPC authors. - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - - # Config file for Kokoro (in protobuf text format) - - build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" - env_vars { - key: "RUNTIME" - value: "${selected.runtime}" - } - env_vars { - key: "ARCH" - value: "${selected.arch}" - } - env_vars { - key: "VERSION" - %if selected.runtime == "node": - value: "${selected.version}.0.0" - %else: - value: "${selected.version}.0" - %endif - } - action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } - } diff --git a/test-grpc-submodule.sh b/test-grpc-submodule.sh deleted file mode 100755 index 862b70c21..000000000 --- a/test-grpc-submodule.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/sh -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This script updates the gRPC submodule to a given reference and run tests - -# cd to gRPC-node root directory -cd $(dirname $0) - -cd packages/grpc-native-core/deps/grpc/ - -# PR references are needed to test PRs from grpc/grpc -git fetch --tags --progress https://github.com/grpc/grpc.git +refs/pull/*:refs/remotes/origin/pr/* -git checkout $@ -git submodule update --init -cd ../../../.. - -packages/grpc-native-core/tools/buildgen/generate_projects.sh - -./run-tests.sh diff --git a/test/any_grpc.js b/test/any_grpc.js index 0c86321fe..2f161ff7a 100644 --- a/test/any_grpc.js +++ b/test/any_grpc.js @@ -27,7 +27,7 @@ function getImplementation(globalField) { if (impl === 'js') { return require(`../packages/grpc-${impl}`); } else if (impl === 'native') { - return require(`../packages/grpc-${impl}-core`); + return require('grpc'); } throw new Error([ diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 401ec6219..b798f1a62 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -31,7 +31,7 @@ const protoPackage = protoLoader.loadSync( {keepCase: true, defaults: true, enums: String, - includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../proto/']}); const testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; function multiDone(done, count) { diff --git a/test/gulpfile.ts b/test/gulpfile.ts index b5d68dfc6..d29404a61 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -43,19 +43,15 @@ const runTestsWithFixture = (server, client) => () => new Promise((resolve, reje .on('error', reject); }); -const testNativeClientNativeServer = runTestsWithFixture('native', 'native'); const testJsClientNativeServer = runTestsWithFixture('native', 'js'); const testNativeClientJsServer = runTestsWithFixture('js', 'native'); const testJsClientJsServer = runTestsWithFixture('js', 'js'); -const test = semver.satisfies(process.version, '^8.13.0 || >=10.10.0') ? - gulp.series( - testNativeClientNativeServer, +const test = gulp.series( testJsClientNativeServer, testNativeClientJsServer, testJsClientJsServer - ) : - testNativeClientNativeServer; + ); export { install, diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 751264f21..1c2ec8f3e 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -29,7 +29,7 @@ var protoPackage = protoLoader.loadSync( {keepCase: true, defaults: true, enums: String, - includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../proto/']}); var testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; var assert = require('assert'); diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index c77643e86..cf7ae354e 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -31,7 +31,7 @@ var protoPackage = protoLoader.loadSync( {keepCase: true, defaults: true, enums: String, - includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../proto/']}); var testProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; var ECHO_INITIAL_KEY = 'x-grpc-test-echo-initial'; diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat index 3f488deee..ea45c3f80 100644 --- a/test/kokoro-nodejs-build-test.bat +++ b/test/kokoro-nodejs-build-test.bat @@ -16,7 +16,6 @@ cd /d %~dp0 cd .. call ./tools/release/kokoro-grpc-tools.bat || goto :error -call ./tools/release/kokoro-nodejs.bat || goto :error goto :EOF diff --git a/test/kokoro-nodejs-build-test.sh b/test/kokoro-nodejs-build-test.sh index 4b0cefca0..d3b2a546e 100755 --- a/test/kokoro-nodejs-build-test.sh +++ b/test/kokoro-nodejs-build-test.sh @@ -17,5 +17,4 @@ set -e cd $(dirname $0)/.. base_dir=$(pwd) -./tools/release/kokoro-nodejs.sh ./tools/release/kokoro-grpc-tools.sh \ No newline at end of file diff --git a/test/kokoro.bat b/test/kokoro.bat index 3190c141e..a022a3f00 100644 --- a/test/kokoro.bat +++ b/test/kokoro.bat @@ -17,6 +17,4 @@ cd /d %~dp0 cd .. -git submodule update --init --recursive - .\run-tests.bat diff --git a/test/kokoro.sh b/test/kokoro.sh index 0caeb1cfc..238a28a42 100755 --- a/test/kokoro.sh +++ b/test/kokoro.sh @@ -13,22 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Deleting Ruby. -rm -rf ~/.rvm - set -e cd $(dirname $0)/.. -OS=$(uname) -if [ "$OS" = "Darwin" ] -then - brew install make - PATH="$(brew --prefix)/opt/make/libexec/gnubin:$PATH" -fi - -# Install gRPC and its submodules. -git submodule update --init --recursive - -./packages/grpc-native-core/tools/buildgen/generate_projects.sh - ./run-tests.sh diff --git a/test/kokoro/linux-build-electron.cfg b/test/kokoro/linux-build-electron.cfg deleted file mode 100644 index 28c510ba8..000000000 --- a/test/kokoro/linux-build-electron.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-electron.sh" -timeout_mins: 60 diff --git a/test/kokoro/macos-build-electron.cfg b/test/kokoro/macos-build-electron.cfg deleted file mode 100644 index 28c510ba8..000000000 --- a/test/kokoro/macos-build-electron.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-electron.sh" -timeout_mins: 60 diff --git a/test/kokoro/windows-build-electron.cfg b/test/kokoro/windows-build-electron.cfg deleted file mode 100644 index 7017d0aec..000000000 --- a/test/kokoro/windows-build-electron.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-electron.bat" -timeout_mins: 120 diff --git a/test/package.json b/test/package.json index 764232971..2867bc77e 100644 --- a/test/package.json +++ b/test/package.json @@ -16,6 +16,7 @@ "dependencies": { "express": "^4.16.3", "google-auth-library": "^0.9.2", + "grpc": "^1.24.2", "lodash": "^4.17.4", "poisson-process": "^1.0.0" } diff --git a/test/performance/benchmark_client.js b/test/performance/benchmark_client.js index 1b964b25e..42605a2fd 100644 --- a/test/performance/benchmark_client.js +++ b/test/performance/benchmark_client.js @@ -44,7 +44,7 @@ var protoPackage = protoLoader.loadSync( defaults: true, enums: String, oneofs: true, - includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../proto/']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** diff --git a/test/performance/benchmark_server.js b/test/performance/benchmark_server.js index 013f81819..64128b9d0 100644 --- a/test/performance/benchmark_server.js +++ b/test/performance/benchmark_server.js @@ -39,7 +39,7 @@ var protoPackage = protoLoader.loadSync( defaults: true, enums: String, oneofs: true, - includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../proto']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; /** diff --git a/test/performance/worker.js b/test/performance/worker.js index df1fb05a0..86f17df2a 100644 --- a/test/performance/worker.js +++ b/test/performance/worker.js @@ -30,7 +30,7 @@ var protoPackage = protoLoader.loadSync( defaults: true, enums: String, oneofs: true, - includeDirs: [__dirname + '/../../packages/grpc-native-core/deps/grpc']}); + includeDirs: [__dirname + '/../proto/']}); var serviceProto = grpc.loadPackageDefinition(protoPackage).grpc.testing; function runServer(port, benchmark_impl, callback) { diff --git a/test/proto/src/proto/grpc/core/stats.proto b/test/proto/src/proto/grpc/core/stats.proto new file mode 100644 index 000000000..d853ba4df --- /dev/null +++ b/test/proto/src/proto/grpc/core/stats.proto @@ -0,0 +1,38 @@ +// Copyright 2017 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.core; + +message Bucket { + double start = 1; + uint64 count = 2; +} + +message Histogram { + repeated Bucket buckets = 1; +} + +message Metric { + string name = 1; + oneof value { + uint64 count = 10; + Histogram histogram = 11; + } +} + +message Stats { + repeated Metric metrics = 1; +} diff --git a/test/proto/src/proto/grpc/testing/benchmark_service.proto b/test/proto/src/proto/grpc/testing/benchmark_service.proto new file mode 100644 index 000000000..439183a73 --- /dev/null +++ b/test/proto/src/proto/grpc/testing/benchmark_service.proto @@ -0,0 +1,44 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. +syntax = "proto3"; + +import "src/proto/grpc/testing/messages.proto"; + +package grpc.testing; + +service BenchmarkService { + // One request followed by one response. + // The server returns the client payload as-is. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // Repeated sequence of one request followed by one response. + // Should be called streaming ping-pong + // The server returns the client payload as-is on each response + rpc StreamingCall(stream SimpleRequest) returns (stream SimpleResponse); + + // Single-sided unbounded streaming from client to server + // The server returns the client payload as-is once the client does WritesDone + rpc StreamingFromClient(stream SimpleRequest) returns (SimpleResponse); + + // Single-sided unbounded streaming from server to client + // The server repeatedly returns the client payload as-is + rpc StreamingFromServer(SimpleRequest) returns (stream SimpleResponse); + + // Two-sided unbounded streaming between server to client + // Both sides send the content of their own choice to the other + rpc StreamingBothWays(stream SimpleRequest) returns (stream SimpleResponse); +} diff --git a/test/proto/src/proto/grpc/testing/control.proto b/test/proto/src/proto/grpc/testing/control.proto new file mode 100644 index 000000000..d22cd325d --- /dev/null +++ b/test/proto/src/proto/grpc/testing/control.proto @@ -0,0 +1,289 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +import "src/proto/grpc/testing/payloads.proto"; +import "src/proto/grpc/testing/stats.proto"; + +package grpc.testing; + +enum ClientType { + // Many languages support a basic distinction between using + // sync or async client, and this allows the specification + SYNC_CLIENT = 0; + ASYNC_CLIENT = 1; + OTHER_CLIENT = 2; // used for some language-specific variants + CALLBACK_CLIENT = 3; +} + +enum ServerType { + SYNC_SERVER = 0; + ASYNC_SERVER = 1; + ASYNC_GENERIC_SERVER = 2; + OTHER_SERVER = 3; // used for some language-specific variants + CALLBACK_SERVER = 4; +} + +enum RpcType { + UNARY = 0; + STREAMING = 1; + STREAMING_FROM_CLIENT = 2; + STREAMING_FROM_SERVER = 3; + STREAMING_BOTH_WAYS = 4; +} + +// Parameters of poisson process distribution, which is a good representation +// of activity coming in from independent identical stationary sources. +message PoissonParams { + // The rate of arrivals (a.k.a. lambda parameter of the exp distribution). + double offered_load = 1; +} + +// Once an RPC finishes, immediately start a new one. +// No configuration parameters needed. +message ClosedLoopParams {} + +message LoadParams { + oneof load { + ClosedLoopParams closed_loop = 1; + PoissonParams poisson = 2; + }; +} + +// presence of SecurityParams implies use of TLS +message SecurityParams { + bool use_test_ca = 1; + string server_host_override = 2; + string cred_type = 3; +} + +message ChannelArg { + string name = 1; + oneof value { + string str_value = 2; + int32 int_value = 3; + } +} + +message ClientConfig { + // List of targets to connect to. At least one target needs to be specified. + repeated string server_targets = 1; + ClientType client_type = 2; + SecurityParams security_params = 3; + // How many concurrent RPCs to start for each channel. + // For synchronous client, use a separate thread for each outstanding RPC. + int32 outstanding_rpcs_per_channel = 4; + // Number of independent client channels to create. + // i-th channel will connect to server_target[i % server_targets.size()] + int32 client_channels = 5; + // Only for async client. Number of threads to use to start/manage RPCs. + int32 async_client_threads = 7; + RpcType rpc_type = 8; + // The requested load for the entire client (aggregated over all the threads). + LoadParams load_params = 10; + PayloadConfig payload_config = 11; + HistogramParams histogram_params = 12; + + // Specify the cores we should run the client on, if desired + repeated int32 core_list = 13; + int32 core_limit = 14; + + // If we use an OTHER_CLIENT client_type, this string gives more detail + string other_client_api = 15; + + repeated ChannelArg channel_args = 16; + + // Number of threads that share each completion queue + int32 threads_per_cq = 17; + + // Number of messages on a stream before it gets finished/restarted + int32 messages_per_stream = 18; + + // Use coalescing API when possible. + bool use_coalesce_api = 19; + + // If 0, disabled. Else, specifies the period between gathering latency + // medians in milliseconds. + int32 median_latency_collection_interval_millis = 20; + + // Number of client processes. 0 indicates no restriction. + int32 client_processes = 21; +} + +message ClientStatus { ClientStats stats = 1; } + +// Request current stats +message Mark { + // if true, the stats will be reset after taking their snapshot. + bool reset = 1; +} + +message ClientArgs { + oneof argtype { + ClientConfig setup = 1; + Mark mark = 2; + } +} + +message ServerConfig { + ServerType server_type = 1; + SecurityParams security_params = 2; + // Port on which to listen. Zero means pick unused port. + int32 port = 4; + // Only for async server. Number of threads used to serve the requests. + int32 async_server_threads = 7; + // Specify the number of cores to limit server to, if desired + int32 core_limit = 8; + // payload config, used in generic server. + // Note this must NOT be used in proto (non-generic) servers. For proto servers, + // 'response sizes' must be configured from the 'response_size' field of the + // 'SimpleRequest' objects in RPC requests. + PayloadConfig payload_config = 9; + + // Specify the cores we should run the server on, if desired + repeated int32 core_list = 10; + + // If we use an OTHER_SERVER client_type, this string gives more detail + string other_server_api = 11; + + // Number of threads that share each completion queue + int32 threads_per_cq = 12; + + // c++-only options (for now) -------------------------------- + + // Buffer pool size (no buffer pool specified if unset) + int32 resource_quota_size = 1001; + repeated ChannelArg channel_args = 1002; + + // Number of server processes. 0 indicates no restriction. + int32 server_processes = 21; +} + +message ServerArgs { + oneof argtype { + ServerConfig setup = 1; + Mark mark = 2; + } +} + +message ServerStatus { + ServerStats stats = 1; + // the port bound by the server + int32 port = 2; + // Number of cores available to the server + int32 cores = 3; +} + +message CoreRequest { +} + +message CoreResponse { + // Number of cores available on the server + int32 cores = 1; +} + +message Void { +} + +// A single performance scenario: input to qps_json_driver +message Scenario { + // Human readable name for this scenario + string name = 1; + // Client configuration + ClientConfig client_config = 2; + // Number of clients to start for the test + int32 num_clients = 3; + // Server configuration + ServerConfig server_config = 4; + // Number of servers to start for the test + int32 num_servers = 5; + // Warmup period, in seconds + int32 warmup_seconds = 6; + // Benchmark time, in seconds + int32 benchmark_seconds = 7; + // Number of workers to spawn locally (usually zero) + int32 spawn_local_worker_count = 8; +} + +// A set of scenarios to be run with qps_json_driver +message Scenarios { + repeated Scenario scenarios = 1; +} + +// Basic summary that can be computed from ClientStats and ServerStats +// once the scenario has finished. +message ScenarioResultSummary +{ + // Total number of operations per second over all clients. What is counted as 1 'operation' depends on the benchmark scenarios: + // For unary benchmarks, an operation is processing of a single unary RPC. + // For streaming benchmarks, an operation is processing of a single ping pong of request and response. + double qps = 1; + // QPS per server core. + double qps_per_server_core = 2; + // The total server cpu load based on system time across all server processes, expressed as percentage of a single cpu core. + // For example, 85 implies 85% of a cpu core, 125 implies 125% of a cpu core. Since we are accumulating the cpu load across all the server + // processes, the value could > 100 when there are multiple servers or a single server using multiple threads and cores. + // Same explanation for the total client cpu load below. + double server_system_time = 3; + // The total server cpu load based on user time across all server processes, expressed as percentage of a single cpu core. (85 => 85%, 125 => 125%) + double server_user_time = 4; + // The total client cpu load based on system time across all client processes, expressed as percentage of a single cpu core. (85 => 85%, 125 => 125%) + double client_system_time = 5; + // The total client cpu load based on user time across all client processes, expressed as percentage of a single cpu core. (85 => 85%, 125 => 125%) + double client_user_time = 6; + + // X% latency percentiles (in nanoseconds) + double latency_50 = 7; + double latency_90 = 8; + double latency_95 = 9; + double latency_99 = 10; + double latency_999 = 11; + + // server cpu usage percentage + double server_cpu_usage = 12; + + // Number of requests that succeeded/failed + double successful_requests_per_second = 13; + double failed_requests_per_second = 14; + + // Number of polls called inside completion queue per request + double client_polls_per_request = 15; + double server_polls_per_request = 16; + + // Queries per CPU-sec over all servers or clients + double server_queries_per_cpu_sec = 17; + double client_queries_per_cpu_sec = 18; +} + +// Results of a single benchmark scenario. +message ScenarioResult { + // Inputs used to run the scenario. + Scenario scenario = 1; + // Histograms from all clients merged into one histogram. + HistogramData latencies = 2; + // Client stats for each client + repeated ClientStats client_stats = 3; + // Server stats for each server + repeated ServerStats server_stats = 4; + // Number of cores available to each server + repeated int32 server_cores = 5; + // An after-the-fact computed summary + ScenarioResultSummary summary = 6; + // Information on success or failure of each worker + repeated bool client_success = 7; + repeated bool server_success = 8; + // Number of failed requests (one row per status code seen) + repeated RequestResultCount request_results = 9; +} diff --git a/test/proto/src/proto/grpc/testing/empty.proto b/test/proto/src/proto/grpc/testing/empty.proto new file mode 100644 index 000000000..cb3972062 --- /dev/null +++ b/test/proto/src/proto/grpc/testing/empty.proto @@ -0,0 +1,28 @@ + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +// An empty message that you can re-use to avoid defining duplicated empty +// messages in your project. A typical example is to use it as argument or the +// return value of a service API. For instance: +// +// service Foo { +// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; +// }; +// +message Empty {} diff --git a/test/proto/src/proto/grpc/testing/messages.proto b/test/proto/src/proto/grpc/testing/messages.proto new file mode 100644 index 000000000..5b504f3b3 --- /dev/null +++ b/test/proto/src/proto/grpc/testing/messages.proto @@ -0,0 +1,209 @@ + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Message definitions to be used by integration test service definitions. + +syntax = "proto3"; + +package grpc.testing; + +// TODO(dgq): Go back to using well-known types once +// https://github.com/grpc/grpc/issues/6980 has been fixed. +// import "google/protobuf/wrappers.proto"; +message BoolValue { + // The bool value. + bool value = 1; +} + +// The type of payload that should be returned. +enum PayloadType { + // Compressable text format. + COMPRESSABLE = 0; +} + +// A block of data, to simply increase gRPC message size. +message Payload { + // The type of data in body. + PayloadType type = 1; + // Primary contents of payload. + bytes body = 2; +} + +// A protobuf representation for grpc status. This is used by test +// clients to specify a status that the server should attempt to return. +message EchoStatus { + int32 code = 1; + string message = 2; +} + +// The type of route that a client took to reach a server w.r.t. gRPCLB. +// The server must fill in "fallback" if it detects that the RPC reached +// the server via the "gRPCLB fallback" path, and "backend" if it detects +// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got +// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly +// how this detection is done is context and server dependent. +enum GrpclbRouteType { + // Server didn't detect the route that a client took to reach it. + GRPCLB_ROUTE_TYPE_UNKNOWN = 0; + // Indicates that a client reached a server via gRPCLB fallback. + GRPCLB_ROUTE_TYPE_FALLBACK = 1; + // Indicates that a client reached a server as a gRPCLB-given backend. + GRPCLB_ROUTE_TYPE_BACKEND = 2; +} + +// Unary request. +message SimpleRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, server randomly chooses one from other formats. + PayloadType response_type = 1; + + // Desired payload size in the response from the server. + int32 response_size = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether SimpleResponse should include username. + bool fill_username = 4; + + // Whether SimpleResponse should include OAuth scope. + bool fill_oauth_scope = 5; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue response_compressed = 6; + + // Whether server should return a given status + EchoStatus response_status = 7; + + // Whether the server should expect this request to be compressed. + BoolValue expect_compressed = 8; + + // Whether SimpleResponse should include server_id. + bool fill_server_id = 9; + + // Whether SimpleResponse should include grpclb_route_type. + bool fill_grpclb_route_type = 10; +} + +// Unary response, as configured by the request. +message SimpleResponse { + // Payload to increase message size. + Payload payload = 1; + // The user the request came from, for verifying authentication was + // successful when the client expected it. + string username = 2; + // OAuth scope. + string oauth_scope = 3; + + // Server ID. This must be unique among different server instances, + // but the same across all RPC's made to a particular server instance. + string server_id = 4; + // gRPCLB Path. + GrpclbRouteType grpclb_route_type = 5; + + // Server hostname. + string hostname = 6; +} + +// Client-streaming request. +message StreamingInputCallRequest { + // Optional input payload sent along with the request. + Payload payload = 1; + + // Whether the server should expect this request to be compressed. This field + // is "nullable" in order to interoperate seamlessly with servers not able to + // implement the full compression tests by introspecting the call to verify + // the request's compression status. + BoolValue expect_compressed = 2; + + // Not expecting any payload from the response. +} + +// Client-streaming response. +message StreamingInputCallResponse { + // Aggregated size of payloads received from the client. + int32 aggregated_payload_size = 1; +} + +// Configuration for a particular response. +message ResponseParameters { + // Desired payload sizes in responses from the server. + int32 size = 1; + + // Desired interval between consecutive responses in the response stream in + // microseconds. + int32 interval_us = 2; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue compressed = 3; +} + +// Server-streaming request. +message StreamingOutputCallRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, the payload from each response in the stream + // might be of different types. This is to simulate a mixed type of payload + // stream. + PayloadType response_type = 1; + + // Configuration for each expected response message. + repeated ResponseParameters response_parameters = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether server should return a given status + EchoStatus response_status = 7; +} + +// Server-streaming response, as configured by the request and parameters. +message StreamingOutputCallResponse { + // Payload to increase response size. + Payload payload = 1; +} + +// For reconnect interop test only. +// Client tells server what reconnection parameters it used. +message ReconnectParams { + int32 max_reconnect_backoff_ms = 1; +} + +// For reconnect interop test only. +// Server tells client whether its reconnects are following the spec and the +// reconnect backoffs it saw. +message ReconnectInfo { + bool passed = 1; + repeated int32 backoff_ms = 2; +} + +message LoadBalancerStatsRequest { + // Request stats for the next num_rpcs sent by client. + int32 num_rpcs = 1; + // If num_rpcs have not completed within timeout_sec, return partial results. + int32 timeout_sec = 2; +} + +message LoadBalancerStatsResponse { + // The number of completed RPCs for each peer. + map rpcs_by_peer = 1; + // The number of RPCs that failed to record a remote peer. + int32 num_failures = 2; +} diff --git a/test/proto/src/proto/grpc/testing/metrics.proto b/test/proto/src/proto/grpc/testing/metrics.proto new file mode 100644 index 000000000..90dcba3ab --- /dev/null +++ b/test/proto/src/proto/grpc/testing/metrics.proto @@ -0,0 +1,49 @@ +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Contains the definitions for a metrics service and the type of metrics +// exposed by the service. +// +// Currently, 'Gauge' (i.e a metric that represents the measured value of +// something at an instant of time) is the only metric type supported by the +// service. +syntax = "proto3"; + +package grpc.testing; + +// Response message containing the gauge name and value +message GaugeResponse { + string name = 1; + oneof value { + int64 long_value = 2; + double double_value = 3; + string string_value = 4; + } +} + +// Request message containing the gauge name +message GaugeRequest { + string name = 1; +} + +message EmptyMessage {} + +service MetricsService { + // Returns the values of all the gauges that are currently being maintained by + // the service + rpc GetAllGauges(EmptyMessage) returns (stream GaugeResponse); + + // Returns the value of one gauge + rpc GetGauge(GaugeRequest) returns (GaugeResponse); +} diff --git a/test/proto/src/proto/grpc/testing/payloads.proto b/test/proto/src/proto/grpc/testing/payloads.proto new file mode 100644 index 000000000..76022656e --- /dev/null +++ b/test/proto/src/proto/grpc/testing/payloads.proto @@ -0,0 +1,40 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +message ByteBufferParams { + int32 req_size = 1; + int32 resp_size = 2; +} + +message SimpleProtoParams { + int32 req_size = 1; + int32 resp_size = 2; +} + +message ComplexProtoParams { + // TODO (vpai): Fill this in once the details of complex, representative + // protos are decided +} + +message PayloadConfig { + oneof payload { + ByteBufferParams bytebuf_params = 1; + SimpleProtoParams simple_params = 2; + ComplexProtoParams complex_params = 3; + } +} diff --git a/test/proto/src/proto/grpc/testing/stats.proto b/test/proto/src/proto/grpc/testing/stats.proto new file mode 100644 index 000000000..705a60ab0 --- /dev/null +++ b/test/proto/src/proto/grpc/testing/stats.proto @@ -0,0 +1,83 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +import "src/proto/grpc/core/stats.proto"; + +message ServerStats { + // wall clock time change in seconds since last reset + double time_elapsed = 1; + + // change in user time (in seconds) used by the server since last reset + double time_user = 2; + + // change in server time (in seconds) used by the server process and all + // threads since last reset + double time_system = 3; + + // change in total cpu time of the server (data from proc/stat) + uint64 total_cpu_time = 4; + + // change in idle time of the server (data from proc/stat) + uint64 idle_cpu_time = 5; + + // Number of polls called inside completion queue + uint64 cq_poll_count = 6; + + // Core library stats + grpc.core.Stats core_stats = 7; +} + +// Histogram params based on grpc/support/histogram.c +message HistogramParams { + double resolution = 1; // first bucket is [0, 1 + resolution) + double max_possible = 2; // use enough buckets to allow this value +} + +// Histogram data based on grpc/support/histogram.c +message HistogramData { + repeated uint32 bucket = 1; + double min_seen = 2; + double max_seen = 3; + double sum = 4; + double sum_of_squares = 5; + double count = 6; +} + +message RequestResultCount { + int32 status_code = 1; + int64 count = 2; +} + +message ClientStats { + // Latency histogram. Data points are in nanoseconds. + HistogramData latencies = 1; + + // See ServerStats for details. + double time_elapsed = 2; + double time_user = 3; + double time_system = 4; + + // Number of failed requests (one row per status code seen) + repeated RequestResultCount request_results = 5; + + // Number of polls called inside completion queue + uint64 cq_poll_count = 6; + + // Core library stats + grpc.core.Stats core_stats = 7; +} diff --git a/test/proto/src/proto/grpc/testing/test.proto b/test/proto/src/proto/grpc/testing/test.proto new file mode 100644 index 000000000..be5fd043b --- /dev/null +++ b/test/proto/src/proto/grpc/testing/test.proto @@ -0,0 +1,86 @@ + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. + +syntax = "proto3"; + +import "src/proto/grpc/testing/empty.proto"; +import "src/proto/grpc/testing/messages.proto"; + +package grpc.testing; + +// A simple service to test the various types of RPCs and experiment with +// performance with various types of payload. +service TestService { + // One empty request followed by one empty response. + rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); + + // One request followed by one response. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by one response. Response has cache control + // headers set such that a caching HTTP proxy (such as GFE) can + // satisfy subsequent requests. + rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by a sequence of responses (streamed download). + // The server returns the payload with client desired type and sizes. + rpc StreamingOutputCall(StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by one response (streamed upload). + // The server returns the aggregated size of client payload as the result. + rpc StreamingInputCall(stream StreamingInputCallRequest) + returns (StreamingInputCallResponse); + + // A sequence of requests with each request served by the server immediately. + // As one request could lead to multiple responses, this interface + // demonstrates the idea of full duplexing. + rpc FullDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by a sequence of responses. + // The server buffers all the client requests and then serves them in order. A + // stream of responses are returned to the client when the server starts with + // first request. + rpc HalfDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // The test server will not implement this method. It will be used + // to test the behavior when clients call unimplemented methods. + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A simple service NOT implemented at servers so clients can test for +// that case. +service UnimplementedService { + // A call that no server should implement + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A service used to control reconnect server. +service ReconnectService { + rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty); + rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); +} + +// A service used to obtain stats for verifying LB behavior. +service LoadBalancerStatsService { + // Gets the backend distribution for RPCs sent by a test client. + rpc GetClientStats(LoadBalancerStatsRequest) + returns (LoadBalancerStatsResponse) {} +} diff --git a/test/proto/src/proto/grpc/testing/worker_service.proto b/test/proto/src/proto/grpc/testing/worker_service.proto new file mode 100644 index 000000000..aee817d48 --- /dev/null +++ b/test/proto/src/proto/grpc/testing/worker_service.proto @@ -0,0 +1,45 @@ +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. +syntax = "proto3"; + +import "src/proto/grpc/testing/control.proto"; + +package grpc.testing; + +service WorkerService { + // Start server with specified workload. + // First request sent specifies the ServerConfig followed by ServerStatus + // response. After that, a "Mark" can be sent anytime to request the latest + // stats. Closing the stream will initiate shutdown of the test server + // and once the shutdown has finished, the OK status is sent to terminate + // this RPC. + rpc RunServer(stream ServerArgs) returns (stream ServerStatus); + + // Start client with specified workload. + // First request sent specifies the ClientConfig followed by ClientStatus + // response. After that, a "Mark" can be sent anytime to request the latest + // stats. Closing the stream will initiate shutdown of the test client + // and once the shutdown has finished, the OK status is sent to terminate + // this RPC. + rpc RunClient(stream ClientArgs) returns (stream ClientStatus); + + // Just return the core count - unary call + rpc CoreCount(CoreRequest) returns (CoreResponse); + + // Quit this worker + rpc QuitWorker(Void) returns (Void); +} diff --git a/test/stress/metrics_client.js b/test/stress/metrics_client.js index c0cb3eb8c..a5c94059a 100644 --- a/test/stress/metrics_client.js +++ b/test/stress/metrics_client.js @@ -21,7 +21,7 @@ // TODO(murgatroid99): use multiple grpc implementations var grpc = require('grpc'); -var proto = grpc.load(__dirname + '/../packages/grpc-native-core/ext/grpc/src/proto/grpc/testing/metrics.proto'); +var proto = grpc.load(__dirname + '/../proto/src/proto/grpc/testing/metrics.proto'); var metrics = proto.grpc.testing; function main() { diff --git a/test/stress/metrics_server.js b/test/stress/metrics_server.js index 70848f3bc..d8e39086f 100644 --- a/test/stress/metrics_server.js +++ b/test/stress/metrics_server.js @@ -23,7 +23,7 @@ var _ = require('lodash'); // TODO(murgatroid99): use multiple grpc implementations var grpc = require('grpc'); -var proto = grpc.load(__dirname + '/../packages/grpc-native-core/ext/grpc/src/proto/grpc/testing/metrics.proto'); +var proto = grpc.load(__dirname + '/../proto/src/proto/grpc/testing/metrics.proto'); var metrics = proto.grpc.testing; function getGauge(call, callback) { diff --git a/tools/release/alpine/Dockerfile b/tools/release/alpine/Dockerfile deleted file mode 100644 index 728ccd02d..000000000 --- a/tools/release/alpine/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM node:10-alpine -RUN apk add --no-cache python curl bash build-base diff --git a/tools/release/cross/Dockerfile b/tools/release/cross/Dockerfile deleted file mode 100644 index 1e931250e..000000000 --- a/tools/release/cross/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM debian:stretch - -RUN dpkg --add-architecture i386 -RUN apt-get update -RUN apt-get install -y curl build-essential g++-aarch64-linux-gnu g++-arm-linux-gnueabihf g++-s390x-linux-gnu python libc6-dev:i386 lib32stdc++-6-dev -RUN curl -fsSL get.docker.com | bash - -RUN mkdir /usr/local/nvm -ENV NVM_DIR /usr/local/nvm - -RUN curl curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash diff --git a/tools/release/kokoro-electron.bat b/tools/release/kokoro-electron.bat deleted file mode 100644 index dde9b134c..000000000 --- a/tools/release/kokoro-electron.bat +++ /dev/null @@ -1,41 +0,0 @@ -@rem Copyright 2018 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@echo "Starting Windows build" - -powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" - -SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% -call nvm install 10 -call nvm use 10 - -call npm install -g npm@6.10.x -@rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp@3 - -cd /d %~dp0 -cd ..\.. - -git submodule update --init --recursive - -set ARTIFACTS_OUT=artifacts -cd packages\grpc-native-core -call tools\run_tests\artifacts\build_artifact_electron.bat || goto :error -cd ..\.. - -move packages\grpc-native-core\artifacts . -goto :EOF - -:error -exit /b 1 diff --git a/tools/release/kokoro-electron.sh b/tools/release/kokoro-electron.sh deleted file mode 100755 index fd833503b..000000000 --- a/tools/release/kokoro-electron.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Deleting Ruby. -rm -rf ~/.rvm - -curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -nvm install 10 -nvm use 10 -npm install -g npm -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp@3 - -set -ex -cd $(dirname $0)/../.. -base_dir=$(pwd) - -# Install gRPC and its submodules. -git submodule update --init --recursive - -pip install mako -./packages/grpc-native-core/tools/buildgen/generate_projects.sh - -OS=`uname` - -case $OS in -Linux) - docker build -t kokoro-native-image tools/release/native - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --native-only --electron-only - cp -rv packages/grpc-native-core/artifacts . - ;; -Darwin) - JOBS=8 ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_electron.sh - ;; -esac diff --git a/tools/release/kokoro-nodejs.bat b/tools/release/kokoro-nodejs.bat deleted file mode 100644 index dd6aecfc5..000000000 --- a/tools/release/kokoro-nodejs.bat +++ /dev/null @@ -1,40 +0,0 @@ -@rem Copyright 2018 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -@echo "Starting Windows build" - -powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" - -SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% -call nvm install 10 -call nvm use 10 - -call npm install -g npm@6.10.x -@rem https://github.com/mapbox/node-pre-gyp/issues/362 -call npm install -g node-gyp@3 - -cd /d %~dp0 -cd ..\.. - -git submodule update --init --recursive - -set ARTIFACTS_OUT=%cd%\artifacts -cd packages\grpc-native-core -call tools\run_tests\artifacts\build_artifact_node.bat || goto :error -cd ..\.. - -goto :EOF - -:error -exit /b 1 diff --git a/tools/release/kokoro-nodejs.sh b/tools/release/kokoro-nodejs.sh deleted file mode 100755 index 7ce0a0b64..000000000 --- a/tools/release/kokoro-nodejs.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Deleting Ruby. -rm -rf ~/.rvm - -curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash -export NVM_DIR="$HOME/.nvm" -[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" - -nvm install 10 -nvm use 10 -npm install -g npm -# https://github.com/mapbox/node-pre-gyp/issues/362 -npm install -g node-gyp - -set -ex -cd $(dirname $0)/../.. -base_dir=$(pwd) - -# Install gRPC and its submodules. -git submodule update --init --recursive - -pip install mako -./packages/grpc-native-core/tools/buildgen/generate_projects.sh - -OS=`uname` - -case $OS in -Linux) - docker build -t kokoro-native-image tools/release/native - docker build -t kokoro-cross-image tools/release/cross - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-native-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --native-only --nodejs-only - cp -rv packages/grpc-native-core/artifacts . - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir kokoro-cross-image $base_dir/packages/grpc-native-core/tools/run_tests/artifacts/build_all_linux_artifacts.sh --cross-only --nodejs-only - cp -rv packages/grpc-native-core/artifacts . - ;; -Darwin) - JOBS=8 ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-native-core/tools/run_tests/artifacts/build_artifact_node.sh - ;; -esac diff --git a/tools/release/kokoro/linux-electron.cfg b/tools/release/kokoro/linux-electron.cfg deleted file mode 100644 index 45f7e5054..000000000 --- a/tools/release/kokoro/linux-electron.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-electron.sh" -timeout_mins: 180 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux-nodejs.cfg b/tools/release/kokoro/linux-nodejs.cfg deleted file mode 100644 index 2a1e37128..000000000 --- a/tools/release/kokoro/linux-nodejs.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-nodejs.sh" -timeout_mins: 180 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg deleted file mode 100644 index a68b80ce8..000000000 --- a/tools/release/kokoro/linux/electron_1.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg deleted file mode 100644 index e5a574ee0..000000000 --- a/tools/release/kokoro/linux/electron_1.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg deleted file mode 100644 index cac5806c9..000000000 --- a/tools/release/kokoro/linux/electron_1.1_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg deleted file mode 100644 index bd7d3a780..000000000 --- a/tools/release/kokoro/linux/electron_1.1_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg deleted file mode 100644 index 1f3dfacd8..000000000 --- a/tools/release/kokoro/linux/electron_1.2_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.2.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg deleted file mode 100644 index 950421e4c..000000000 --- a/tools/release/kokoro/linux/electron_1.2_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.2.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg deleted file mode 100644 index 132f9ce91..000000000 --- a/tools/release/kokoro/linux/electron_1.3_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.3.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg deleted file mode 100644 index 713d78e3d..000000000 --- a/tools/release/kokoro/linux/electron_1.3_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.3.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg deleted file mode 100644 index 119a8a6ae..000000000 --- a/tools/release/kokoro/linux/electron_1.4_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.4.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg deleted file mode 100644 index 35e6575b4..000000000 --- a/tools/release/kokoro/linux/electron_1.4_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.4.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg deleted file mode 100644 index 2d54d45f8..000000000 --- a/tools/release/kokoro/linux/electron_1.5_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.5.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg deleted file mode 100644 index 4a78562b2..000000000 --- a/tools/release/kokoro/linux/electron_1.5_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.5.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg deleted file mode 100644 index 5f66d51e6..000000000 --- a/tools/release/kokoro/linux/electron_1.6_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.6.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg deleted file mode 100644 index 8660c3fc4..000000000 --- a/tools/release/kokoro/linux/electron_1.6_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.6.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg deleted file mode 100644 index c73fb0e88..000000000 --- a/tools/release/kokoro/linux/electron_1.7_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.7.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg deleted file mode 100644 index bcc6f4605..000000000 --- a/tools/release/kokoro/linux/electron_1.7_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.7.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg deleted file mode 100644 index fd2f2e4d7..000000000 --- a/tools/release/kokoro/linux/electron_1.8_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.8.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg b/tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg deleted file mode 100644 index c4c8eaf52..000000000 --- a/tools/release/kokoro/linux/electron_1.8_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.8.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg deleted file mode 100644 index fb080a0ca..000000000 --- a/tools/release/kokoro/linux/electron_2.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "2.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg deleted file mode 100644 index 8665b79b6..000000000 --- a/tools/release/kokoro/linux/electron_2.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "2.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg deleted file mode 100644 index cc5c02d82..000000000 --- a/tools/release/kokoro/linux/electron_3.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "3.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg deleted file mode 100644 index 537fd3c23..000000000 --- a/tools/release/kokoro/linux/electron_3.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "3.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg deleted file mode 100644 index a5ccfb84a..000000000 --- a/tools/release/kokoro/linux/electron_3.1_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "3.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg deleted file mode 100644 index aad9b9055..000000000 --- a/tools/release/kokoro/linux/electron_3.1_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "3.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg deleted file mode 100644 index 48b8d57d8..000000000 --- a/tools/release/kokoro/linux/electron_4.1_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg deleted file mode 100644 index 83a77d5bd..000000000 --- a/tools/release/kokoro/linux/electron_4.1_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg deleted file mode 100644 index 17b1a4341..000000000 --- a/tools/release/kokoro/linux/electron_4.2_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.2.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg b/tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg deleted file mode 100644 index 955c5721e..000000000 --- a/tools/release/kokoro/linux/electron_4.2_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.2.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg deleted file mode 100644 index 91fbd4a4f..000000000 --- a/tools/release/kokoro/linux/electron_5.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg deleted file mode 100644 index 028389ca7..000000000 --- a/tools/release/kokoro/linux/electron_5.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg deleted file mode 100644 index 67d6816b8..000000000 --- a/tools/release/kokoro/linux/electron_6.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg deleted file mode 100644 index fc9bc06a3..000000000 --- a/tools/release/kokoro/linux/electron_6.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg deleted file mode 100644 index 8d553f8d7..000000000 --- a/tools/release/kokoro/linux/electron_6.1_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg deleted file mode 100644 index 64efd8896..000000000 --- a/tools/release/kokoro/linux/electron_6.1_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg deleted file mode 100644 index b02bc4940..000000000 --- a/tools/release/kokoro/linux/electron_7.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg deleted file mode 100644 index 0900ddce8..000000000 --- a/tools/release/kokoro/linux/electron_7.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg deleted file mode 100644 index 15dcb3bd2..000000000 --- a/tools/release/kokoro/linux/electron_7.1_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg b/tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg deleted file mode 100644 index bc392b71f..000000000 --- a/tools/release/kokoro/linux/electron_7.1_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.1.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg b/tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg deleted file mode 100644 index b0b86657c..000000000 --- a/tools/release/kokoro/linux/electron_8.0_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg b/tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg deleted file mode 100644 index 2e79736fe..000000000 --- a/tools/release/kokoro/linux/electron_8.0_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_10_arm64_glibc.cfg b/tools/release/kokoro/linux/node_10_arm64_glibc.cfg deleted file mode 100644 index da090fff1..000000000 --- a/tools/release/kokoro/linux/node_10_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_10_arm_glibc.cfg b/tools/release/kokoro/linux/node_10_arm_glibc.cfg deleted file mode 100644 index cc6ad4787..000000000 --- a/tools/release/kokoro/linux/node_10_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_10_ia32_glibc.cfg b/tools/release/kokoro/linux/node_10_ia32_glibc.cfg deleted file mode 100644 index f7ee19047..000000000 --- a/tools/release/kokoro/linux/node_10_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_10_s390x_glibc.cfg b/tools/release/kokoro/linux/node_10_s390x_glibc.cfg deleted file mode 100644 index 60935df16..000000000 --- a/tools/release/kokoro/linux/node_10_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_10_x64_glibc.cfg b/tools/release/kokoro/linux/node_10_x64_glibc.cfg deleted file mode 100644 index 0572524db..000000000 --- a/tools/release/kokoro/linux/node_10_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_10_x64_musl.cfg b/tools/release/kokoro/linux/node_10_x64_musl.cfg deleted file mode 100644 index 0572524db..000000000 --- a/tools/release/kokoro/linux/node_10_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_11_arm64_glibc.cfg b/tools/release/kokoro/linux/node_11_arm64_glibc.cfg deleted file mode 100644 index 1a633206d..000000000 --- a/tools/release/kokoro/linux/node_11_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_11_arm_glibc.cfg b/tools/release/kokoro/linux/node_11_arm_glibc.cfg deleted file mode 100644 index 2f9af1df7..000000000 --- a/tools/release/kokoro/linux/node_11_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_11_ia32_glibc.cfg b/tools/release/kokoro/linux/node_11_ia32_glibc.cfg deleted file mode 100644 index 94613203b..000000000 --- a/tools/release/kokoro/linux/node_11_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_11_s390x_glibc.cfg b/tools/release/kokoro/linux/node_11_s390x_glibc.cfg deleted file mode 100644 index f17a793f1..000000000 --- a/tools/release/kokoro/linux/node_11_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_11_x64_glibc.cfg b/tools/release/kokoro/linux/node_11_x64_glibc.cfg deleted file mode 100644 index b2327fc4f..000000000 --- a/tools/release/kokoro/linux/node_11_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_11_x64_musl.cfg b/tools/release/kokoro/linux/node_11_x64_musl.cfg deleted file mode 100644 index b2327fc4f..000000000 --- a/tools/release/kokoro/linux/node_11_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_12_arm64_glibc.cfg b/tools/release/kokoro/linux/node_12_arm64_glibc.cfg deleted file mode 100644 index d7669485d..000000000 --- a/tools/release/kokoro/linux/node_12_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_12_arm_glibc.cfg b/tools/release/kokoro/linux/node_12_arm_glibc.cfg deleted file mode 100644 index 92b71d56a..000000000 --- a/tools/release/kokoro/linux/node_12_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_12_ia32_glibc.cfg b/tools/release/kokoro/linux/node_12_ia32_glibc.cfg deleted file mode 100644 index 6677c7d94..000000000 --- a/tools/release/kokoro/linux/node_12_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_12_s390x_glibc.cfg b/tools/release/kokoro/linux/node_12_s390x_glibc.cfg deleted file mode 100644 index ad83ac490..000000000 --- a/tools/release/kokoro/linux/node_12_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_12_x64_glibc.cfg b/tools/release/kokoro/linux/node_12_x64_glibc.cfg deleted file mode 100644 index d29e134e2..000000000 --- a/tools/release/kokoro/linux/node_12_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_12_x64_musl.cfg b/tools/release/kokoro/linux/node_12_x64_musl.cfg deleted file mode 100644 index d29e134e2..000000000 --- a/tools/release/kokoro/linux/node_12_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_13_arm64_glibc.cfg b/tools/release/kokoro/linux/node_13_arm64_glibc.cfg deleted file mode 100644 index b9d7d4f7d..000000000 --- a/tools/release/kokoro/linux/node_13_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_13_arm_glibc.cfg b/tools/release/kokoro/linux/node_13_arm_glibc.cfg deleted file mode 100644 index 2f4a95a08..000000000 --- a/tools/release/kokoro/linux/node_13_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_13_ia32_glibc.cfg b/tools/release/kokoro/linux/node_13_ia32_glibc.cfg deleted file mode 100644 index 7fde2284e..000000000 --- a/tools/release/kokoro/linux/node_13_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_13_s390x_glibc.cfg b/tools/release/kokoro/linux/node_13_s390x_glibc.cfg deleted file mode 100644 index dcf25cf68..000000000 --- a/tools/release/kokoro/linux/node_13_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_13_x64_glibc.cfg b/tools/release/kokoro/linux/node_13_x64_glibc.cfg deleted file mode 100644 index cb102fa97..000000000 --- a/tools/release/kokoro/linux/node_13_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_13_x64_musl.cfg b/tools/release/kokoro/linux/node_13_x64_musl.cfg deleted file mode 100644 index cb102fa97..000000000 --- a/tools/release/kokoro/linux/node_13_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_4_arm64_glibc.cfg b/tools/release/kokoro/linux/node_4_arm64_glibc.cfg deleted file mode 100644 index a5478f30b..000000000 --- a/tools/release/kokoro/linux/node_4_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_4_arm_glibc.cfg b/tools/release/kokoro/linux/node_4_arm_glibc.cfg deleted file mode 100644 index 82872df34..000000000 --- a/tools/release/kokoro/linux/node_4_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_4_ia32_glibc.cfg b/tools/release/kokoro/linux/node_4_ia32_glibc.cfg deleted file mode 100644 index 685817767..000000000 --- a/tools/release/kokoro/linux/node_4_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_4_s390x_glibc.cfg b/tools/release/kokoro/linux/node_4_s390x_glibc.cfg deleted file mode 100644 index d599f9e78..000000000 --- a/tools/release/kokoro/linux/node_4_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_4_x64_glibc.cfg b/tools/release/kokoro/linux/node_4_x64_glibc.cfg deleted file mode 100644 index 5184495dd..000000000 --- a/tools/release/kokoro/linux/node_4_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_4_x64_musl.cfg b/tools/release/kokoro/linux/node_4_x64_musl.cfg deleted file mode 100644 index 5184495dd..000000000 --- a/tools/release/kokoro/linux/node_4_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_5_arm64_glibc.cfg b/tools/release/kokoro/linux/node_5_arm64_glibc.cfg deleted file mode 100644 index f022ddce3..000000000 --- a/tools/release/kokoro/linux/node_5_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_5_arm_glibc.cfg b/tools/release/kokoro/linux/node_5_arm_glibc.cfg deleted file mode 100644 index 3c317ff4f..000000000 --- a/tools/release/kokoro/linux/node_5_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_5_ia32_glibc.cfg b/tools/release/kokoro/linux/node_5_ia32_glibc.cfg deleted file mode 100644 index e38c38d7b..000000000 --- a/tools/release/kokoro/linux/node_5_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_5_s390x_glibc.cfg b/tools/release/kokoro/linux/node_5_s390x_glibc.cfg deleted file mode 100644 index d1eb5d54a..000000000 --- a/tools/release/kokoro/linux/node_5_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_5_x64_glibc.cfg b/tools/release/kokoro/linux/node_5_x64_glibc.cfg deleted file mode 100644 index 404a42095..000000000 --- a/tools/release/kokoro/linux/node_5_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_5_x64_musl.cfg b/tools/release/kokoro/linux/node_5_x64_musl.cfg deleted file mode 100644 index 404a42095..000000000 --- a/tools/release/kokoro/linux/node_5_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_6_arm64_glibc.cfg b/tools/release/kokoro/linux/node_6_arm64_glibc.cfg deleted file mode 100644 index 133d36873..000000000 --- a/tools/release/kokoro/linux/node_6_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_6_arm_glibc.cfg b/tools/release/kokoro/linux/node_6_arm_glibc.cfg deleted file mode 100644 index 17f323288..000000000 --- a/tools/release/kokoro/linux/node_6_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_6_ia32_glibc.cfg b/tools/release/kokoro/linux/node_6_ia32_glibc.cfg deleted file mode 100644 index 350b3702c..000000000 --- a/tools/release/kokoro/linux/node_6_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_6_s390x_glibc.cfg b/tools/release/kokoro/linux/node_6_s390x_glibc.cfg deleted file mode 100644 index 279957e1e..000000000 --- a/tools/release/kokoro/linux/node_6_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_6_x64_glibc.cfg b/tools/release/kokoro/linux/node_6_x64_glibc.cfg deleted file mode 100644 index 6c8d465b9..000000000 --- a/tools/release/kokoro/linux/node_6_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_6_x64_musl.cfg b/tools/release/kokoro/linux/node_6_x64_musl.cfg deleted file mode 100644 index 6c8d465b9..000000000 --- a/tools/release/kokoro/linux/node_6_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_7_arm64_glibc.cfg b/tools/release/kokoro/linux/node_7_arm64_glibc.cfg deleted file mode 100644 index 0862b1428..000000000 --- a/tools/release/kokoro/linux/node_7_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_7_arm_glibc.cfg b/tools/release/kokoro/linux/node_7_arm_glibc.cfg deleted file mode 100644 index 41ded1638..000000000 --- a/tools/release/kokoro/linux/node_7_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_7_ia32_glibc.cfg b/tools/release/kokoro/linux/node_7_ia32_glibc.cfg deleted file mode 100644 index 33e2a04bd..000000000 --- a/tools/release/kokoro/linux/node_7_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_7_s390x_glibc.cfg b/tools/release/kokoro/linux/node_7_s390x_glibc.cfg deleted file mode 100644 index 3e976353a..000000000 --- a/tools/release/kokoro/linux/node_7_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_7_x64_glibc.cfg b/tools/release/kokoro/linux/node_7_x64_glibc.cfg deleted file mode 100644 index 6f690f1b9..000000000 --- a/tools/release/kokoro/linux/node_7_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_7_x64_musl.cfg b/tools/release/kokoro/linux/node_7_x64_musl.cfg deleted file mode 100644 index 6f690f1b9..000000000 --- a/tools/release/kokoro/linux/node_7_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_8_arm64_glibc.cfg b/tools/release/kokoro/linux/node_8_arm64_glibc.cfg deleted file mode 100644 index fba0f0f60..000000000 --- a/tools/release/kokoro/linux/node_8_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_8_arm_glibc.cfg b/tools/release/kokoro/linux/node_8_arm_glibc.cfg deleted file mode 100644 index 017efbc48..000000000 --- a/tools/release/kokoro/linux/node_8_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_8_ia32_glibc.cfg b/tools/release/kokoro/linux/node_8_ia32_glibc.cfg deleted file mode 100644 index 87b02ff59..000000000 --- a/tools/release/kokoro/linux/node_8_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_8_s390x_glibc.cfg b/tools/release/kokoro/linux/node_8_s390x_glibc.cfg deleted file mode 100644 index f4e8183ad..000000000 --- a/tools/release/kokoro/linux/node_8_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_8_x64_glibc.cfg b/tools/release/kokoro/linux/node_8_x64_glibc.cfg deleted file mode 100644 index d0d2396e9..000000000 --- a/tools/release/kokoro/linux/node_8_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_8_x64_musl.cfg b/tools/release/kokoro/linux/node_8_x64_musl.cfg deleted file mode 100644 index d0d2396e9..000000000 --- a/tools/release/kokoro/linux/node_8_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_9_arm64_glibc.cfg b/tools/release/kokoro/linux/node_9_arm64_glibc.cfg deleted file mode 100644 index b2f26d89e..000000000 --- a/tools/release/kokoro/linux/node_9_arm64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm64" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_9_arm_glibc.cfg b/tools/release/kokoro/linux/node_9_arm_glibc.cfg deleted file mode 100644 index 051f833f9..000000000 --- a/tools/release/kokoro/linux/node_9_arm_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "arm" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_9_ia32_glibc.cfg b/tools/release/kokoro/linux/node_9_ia32_glibc.cfg deleted file mode 100644 index 0e1f41d86..000000000 --- a/tools/release/kokoro/linux/node_9_ia32_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_9_s390x_glibc.cfg b/tools/release/kokoro/linux/node_9_s390x_glibc.cfg deleted file mode 100644 index fce879525..000000000 --- a/tools/release/kokoro/linux/node_9_s390x_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "s390x" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_9_x64_glibc.cfg b/tools/release/kokoro/linux/node_9_x64_glibc.cfg deleted file mode 100644 index fc88e10fb..000000000 --- a/tools/release/kokoro/linux/node_9_x64_glibc.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/linux/node_9_x64_musl.cfg b/tools/release/kokoro/linux/node_9_x64_musl.cfg deleted file mode 100644 index fc88e10fb..000000000 --- a/tools/release/kokoro/linux/node_9_x64_musl.cfg +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_linux.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -env_vars { - key: "LIBC" - value: "glibc" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos-electron.cfg b/tools/release/kokoro/macos-electron.cfg deleted file mode 100644 index b0e835b8f..000000000 --- a/tools/release/kokoro/macos-electron.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-electron.sh" -timeout_mins: 120 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos-nodejs.cfg b/tools/release/kokoro/macos-nodejs.cfg deleted file mode 100644 index 7a313cb83..000000000 --- a/tools/release/kokoro/macos-nodejs.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-nodejs.sh" -timeout_mins: 120 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.0_ia32.cfg b/tools/release/kokoro/macos/electron_1.0_ia32.cfg deleted file mode 100644 index c14493f15..000000000 --- a/tools/release/kokoro/macos/electron_1.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.0_x64.cfg b/tools/release/kokoro/macos/electron_1.0_x64.cfg deleted file mode 100644 index de01b329e..000000000 --- a/tools/release/kokoro/macos/electron_1.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.1_ia32.cfg b/tools/release/kokoro/macos/electron_1.1_ia32.cfg deleted file mode 100644 index 71c370c45..000000000 --- a/tools/release/kokoro/macos/electron_1.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.1_x64.cfg b/tools/release/kokoro/macos/electron_1.1_x64.cfg deleted file mode 100644 index 10f9a525f..000000000 --- a/tools/release/kokoro/macos/electron_1.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.2_ia32.cfg b/tools/release/kokoro/macos/electron_1.2_ia32.cfg deleted file mode 100644 index 3c2136b70..000000000 --- a/tools/release/kokoro/macos/electron_1.2_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.2_x64.cfg b/tools/release/kokoro/macos/electron_1.2_x64.cfg deleted file mode 100644 index 06f2ce565..000000000 --- a/tools/release/kokoro/macos/electron_1.2_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.3_ia32.cfg b/tools/release/kokoro/macos/electron_1.3_ia32.cfg deleted file mode 100644 index cdaace0d1..000000000 --- a/tools/release/kokoro/macos/electron_1.3_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.3.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.3_x64.cfg b/tools/release/kokoro/macos/electron_1.3_x64.cfg deleted file mode 100644 index 59241ec39..000000000 --- a/tools/release/kokoro/macos/electron_1.3_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.3.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.4_ia32.cfg b/tools/release/kokoro/macos/electron_1.4_ia32.cfg deleted file mode 100644 index f4359b6c2..000000000 --- a/tools/release/kokoro/macos/electron_1.4_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.4.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.4_x64.cfg b/tools/release/kokoro/macos/electron_1.4_x64.cfg deleted file mode 100644 index eadc22a24..000000000 --- a/tools/release/kokoro/macos/electron_1.4_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.4.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.5_ia32.cfg b/tools/release/kokoro/macos/electron_1.5_ia32.cfg deleted file mode 100644 index e70c18c0c..000000000 --- a/tools/release/kokoro/macos/electron_1.5_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.5.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.5_x64.cfg b/tools/release/kokoro/macos/electron_1.5_x64.cfg deleted file mode 100644 index d2382a17d..000000000 --- a/tools/release/kokoro/macos/electron_1.5_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.5.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.6_ia32.cfg b/tools/release/kokoro/macos/electron_1.6_ia32.cfg deleted file mode 100644 index f074428fc..000000000 --- a/tools/release/kokoro/macos/electron_1.6_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.6.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.6_x64.cfg b/tools/release/kokoro/macos/electron_1.6_x64.cfg deleted file mode 100644 index 0c93e0d75..000000000 --- a/tools/release/kokoro/macos/electron_1.6_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.6.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.7_ia32.cfg b/tools/release/kokoro/macos/electron_1.7_ia32.cfg deleted file mode 100644 index 48d53103c..000000000 --- a/tools/release/kokoro/macos/electron_1.7_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.7.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.7_x64.cfg b/tools/release/kokoro/macos/electron_1.7_x64.cfg deleted file mode 100644 index bdef8d3f4..000000000 --- a/tools/release/kokoro/macos/electron_1.7_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.7.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.8_ia32.cfg b/tools/release/kokoro/macos/electron_1.8_ia32.cfg deleted file mode 100644 index a0455a725..000000000 --- a/tools/release/kokoro/macos/electron_1.8_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.8.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_1.8_x64.cfg b/tools/release/kokoro/macos/electron_1.8_x64.cfg deleted file mode 100644 index 94b3a0cfb..000000000 --- a/tools/release/kokoro/macos/electron_1.8_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.8.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_2.0_ia32.cfg b/tools/release/kokoro/macos/electron_2.0_ia32.cfg deleted file mode 100644 index 137d8ec27..000000000 --- a/tools/release/kokoro/macos/electron_2.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "2.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_2.0_x64.cfg b/tools/release/kokoro/macos/electron_2.0_x64.cfg deleted file mode 100644 index f70f742e6..000000000 --- a/tools/release/kokoro/macos/electron_2.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "2.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_3.0_ia32.cfg b/tools/release/kokoro/macos/electron_3.0_ia32.cfg deleted file mode 100644 index eee4f3035..000000000 --- a/tools/release/kokoro/macos/electron_3.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "3.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_3.0_x64.cfg b/tools/release/kokoro/macos/electron_3.0_x64.cfg deleted file mode 100644 index 52df13a80..000000000 --- a/tools/release/kokoro/macos/electron_3.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "3.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_3.1_ia32.cfg b/tools/release/kokoro/macos/electron_3.1_ia32.cfg deleted file mode 100644 index 12785e3ba..000000000 --- a/tools/release/kokoro/macos/electron_3.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "3.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_3.1_x64.cfg b/tools/release/kokoro/macos/electron_3.1_x64.cfg deleted file mode 100644 index 02d1a8d3b..000000000 --- a/tools/release/kokoro/macos/electron_3.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "3.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_4.1_ia32.cfg b/tools/release/kokoro/macos/electron_4.1_ia32.cfg deleted file mode 100644 index 33cf881ec..000000000 --- a/tools/release/kokoro/macos/electron_4.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_4.1_x64.cfg b/tools/release/kokoro/macos/electron_4.1_x64.cfg deleted file mode 100644 index 5553bce74..000000000 --- a/tools/release/kokoro/macos/electron_4.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_4.2_ia32.cfg b/tools/release/kokoro/macos/electron_4.2_ia32.cfg deleted file mode 100644 index 41746c211..000000000 --- a/tools/release/kokoro/macos/electron_4.2_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_4.2_x64.cfg b/tools/release/kokoro/macos/electron_4.2_x64.cfg deleted file mode 100644 index b6cf5a700..000000000 --- a/tools/release/kokoro/macos/electron_4.2_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_5.0_ia32.cfg b/tools/release/kokoro/macos/electron_5.0_ia32.cfg deleted file mode 100644 index e59cf6a6f..000000000 --- a/tools/release/kokoro/macos/electron_5.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_5.0_x64.cfg b/tools/release/kokoro/macos/electron_5.0_x64.cfg deleted file mode 100644 index 47de1345c..000000000 --- a/tools/release/kokoro/macos/electron_5.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_6.0_ia32.cfg b/tools/release/kokoro/macos/electron_6.0_ia32.cfg deleted file mode 100644 index 10ca9f5ee..000000000 --- a/tools/release/kokoro/macos/electron_6.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_6.0_x64.cfg b/tools/release/kokoro/macos/electron_6.0_x64.cfg deleted file mode 100644 index 312c27d96..000000000 --- a/tools/release/kokoro/macos/electron_6.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_6.1_ia32.cfg b/tools/release/kokoro/macos/electron_6.1_ia32.cfg deleted file mode 100644 index 45ed07c5e..000000000 --- a/tools/release/kokoro/macos/electron_6.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_6.1_x64.cfg b/tools/release/kokoro/macos/electron_6.1_x64.cfg deleted file mode 100644 index e5167655a..000000000 --- a/tools/release/kokoro/macos/electron_6.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_7.0_ia32.cfg b/tools/release/kokoro/macos/electron_7.0_ia32.cfg deleted file mode 100644 index 5824649ef..000000000 --- a/tools/release/kokoro/macos/electron_7.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_7.0_x64.cfg b/tools/release/kokoro/macos/electron_7.0_x64.cfg deleted file mode 100644 index 38688281b..000000000 --- a/tools/release/kokoro/macos/electron_7.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_7.1_ia32.cfg b/tools/release/kokoro/macos/electron_7.1_ia32.cfg deleted file mode 100644 index 4a81c57e7..000000000 --- a/tools/release/kokoro/macos/electron_7.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_7.1_x64.cfg b/tools/release/kokoro/macos/electron_7.1_x64.cfg deleted file mode 100644 index a8671b176..000000000 --- a/tools/release/kokoro/macos/electron_7.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_8.0_ia32.cfg b/tools/release/kokoro/macos/electron_8.0_ia32.cfg deleted file mode 100644 index 01b9e92f6..000000000 --- a/tools/release/kokoro/macos/electron_8.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/electron_8.0_x64.cfg b/tools/release/kokoro/macos/electron_8.0_x64.cfg deleted file mode 100644 index dec384eda..000000000 --- a/tools/release/kokoro/macos/electron_8.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_10_ia32.cfg b/tools/release/kokoro/macos/node_10_ia32.cfg deleted file mode 100644 index fd1102df5..000000000 --- a/tools/release/kokoro/macos/node_10_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_10_x64.cfg b/tools/release/kokoro/macos/node_10_x64.cfg deleted file mode 100644 index ca306e127..000000000 --- a/tools/release/kokoro/macos/node_10_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_11_ia32.cfg b/tools/release/kokoro/macos/node_11_ia32.cfg deleted file mode 100644 index ecd4f3d03..000000000 --- a/tools/release/kokoro/macos/node_11_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_11_x64.cfg b/tools/release/kokoro/macos/node_11_x64.cfg deleted file mode 100644 index 805423116..000000000 --- a/tools/release/kokoro/macos/node_11_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_12_ia32.cfg b/tools/release/kokoro/macos/node_12_ia32.cfg deleted file mode 100644 index 7bf3a9a39..000000000 --- a/tools/release/kokoro/macos/node_12_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_12_x64.cfg b/tools/release/kokoro/macos/node_12_x64.cfg deleted file mode 100644 index a4d7c8d01..000000000 --- a/tools/release/kokoro/macos/node_12_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_13_ia32.cfg b/tools/release/kokoro/macos/node_13_ia32.cfg deleted file mode 100644 index 7fe3a4ea5..000000000 --- a/tools/release/kokoro/macos/node_13_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_13_x64.cfg b/tools/release/kokoro/macos/node_13_x64.cfg deleted file mode 100644 index 156eb6cf5..000000000 --- a/tools/release/kokoro/macos/node_13_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_4_ia32.cfg b/tools/release/kokoro/macos/node_4_ia32.cfg deleted file mode 100644 index 1411ea929..000000000 --- a/tools/release/kokoro/macos/node_4_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_4_x64.cfg b/tools/release/kokoro/macos/node_4_x64.cfg deleted file mode 100644 index 8a330ce5c..000000000 --- a/tools/release/kokoro/macos/node_4_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_5_ia32.cfg b/tools/release/kokoro/macos/node_5_ia32.cfg deleted file mode 100644 index f99f3b69e..000000000 --- a/tools/release/kokoro/macos/node_5_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_5_x64.cfg b/tools/release/kokoro/macos/node_5_x64.cfg deleted file mode 100644 index f1436c2f2..000000000 --- a/tools/release/kokoro/macos/node_5_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_6_ia32.cfg b/tools/release/kokoro/macos/node_6_ia32.cfg deleted file mode 100644 index 2381480d0..000000000 --- a/tools/release/kokoro/macos/node_6_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_6_x64.cfg b/tools/release/kokoro/macos/node_6_x64.cfg deleted file mode 100644 index 10b657ee2..000000000 --- a/tools/release/kokoro/macos/node_6_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_7_ia32.cfg b/tools/release/kokoro/macos/node_7_ia32.cfg deleted file mode 100644 index 9841a4a2a..000000000 --- a/tools/release/kokoro/macos/node_7_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_7_x64.cfg b/tools/release/kokoro/macos/node_7_x64.cfg deleted file mode 100644 index a46516bb9..000000000 --- a/tools/release/kokoro/macos/node_7_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_8_ia32.cfg b/tools/release/kokoro/macos/node_8_ia32.cfg deleted file mode 100644 index 4c6f268c0..000000000 --- a/tools/release/kokoro/macos/node_8_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_8_x64.cfg b/tools/release/kokoro/macos/node_8_x64.cfg deleted file mode 100644 index 2034ac8dc..000000000 --- a/tools/release/kokoro/macos/node_8_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_9_ia32.cfg b/tools/release/kokoro/macos/node_9_ia32.cfg deleted file mode 100644 index f51cf728a..000000000 --- a/tools/release/kokoro/macos/node_9_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos/node_9_x64.cfg b/tools/release/kokoro/macos/node_9_x64.cfg deleted file mode 100644 index 083e1ee85..000000000 --- a/tools/release/kokoro/macos/node_9_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact_macos.sh" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows-electron.cfg b/tools/release/kokoro/windows-electron.cfg deleted file mode 100644 index 14a94b64f..000000000 --- a/tools/release/kokoro/windows-electron.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-electron.bat" -timeout_mins: 120 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows-nodejs.cfg b/tools/release/kokoro/windows-nodejs.cfg deleted file mode 100644 index f9307d6d1..000000000 --- a/tools/release/kokoro/windows-nodejs.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-nodejs.bat" -timeout_mins: 120 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.0_ia32.cfg b/tools/release/kokoro/windows/electron_1.0_ia32.cfg deleted file mode 100644 index 599cf0990..000000000 --- a/tools/release/kokoro/windows/electron_1.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.0_x64.cfg b/tools/release/kokoro/windows/electron_1.0_x64.cfg deleted file mode 100644 index eb5e743c2..000000000 --- a/tools/release/kokoro/windows/electron_1.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.1_ia32.cfg b/tools/release/kokoro/windows/electron_1.1_ia32.cfg deleted file mode 100644 index 61f22bc6c..000000000 --- a/tools/release/kokoro/windows/electron_1.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.1_x64.cfg b/tools/release/kokoro/windows/electron_1.1_x64.cfg deleted file mode 100644 index 3d084c48f..000000000 --- a/tools/release/kokoro/windows/electron_1.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.2_ia32.cfg b/tools/release/kokoro/windows/electron_1.2_ia32.cfg deleted file mode 100644 index cc0ceee15..000000000 --- a/tools/release/kokoro/windows/electron_1.2_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.2_x64.cfg b/tools/release/kokoro/windows/electron_1.2_x64.cfg deleted file mode 100644 index 15a3d4fc8..000000000 --- a/tools/release/kokoro/windows/electron_1.2_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.3_ia32.cfg b/tools/release/kokoro/windows/electron_1.3_ia32.cfg deleted file mode 100644 index 07588569b..000000000 --- a/tools/release/kokoro/windows/electron_1.3_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.3.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.3_x64.cfg b/tools/release/kokoro/windows/electron_1.3_x64.cfg deleted file mode 100644 index 0d3c28154..000000000 --- a/tools/release/kokoro/windows/electron_1.3_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.3.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.4_ia32.cfg b/tools/release/kokoro/windows/electron_1.4_ia32.cfg deleted file mode 100644 index 3e9c68475..000000000 --- a/tools/release/kokoro/windows/electron_1.4_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.4.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.4_x64.cfg b/tools/release/kokoro/windows/electron_1.4_x64.cfg deleted file mode 100644 index fd0bea93c..000000000 --- a/tools/release/kokoro/windows/electron_1.4_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.4.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.5_ia32.cfg b/tools/release/kokoro/windows/electron_1.5_ia32.cfg deleted file mode 100644 index a30d9a759..000000000 --- a/tools/release/kokoro/windows/electron_1.5_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.5.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.5_x64.cfg b/tools/release/kokoro/windows/electron_1.5_x64.cfg deleted file mode 100644 index 00e9ccb53..000000000 --- a/tools/release/kokoro/windows/electron_1.5_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.5.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.6_ia32.cfg b/tools/release/kokoro/windows/electron_1.6_ia32.cfg deleted file mode 100644 index ed6344b80..000000000 --- a/tools/release/kokoro/windows/electron_1.6_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.6.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.6_x64.cfg b/tools/release/kokoro/windows/electron_1.6_x64.cfg deleted file mode 100644 index 846a2889d..000000000 --- a/tools/release/kokoro/windows/electron_1.6_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.6.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.7_ia32.cfg b/tools/release/kokoro/windows/electron_1.7_ia32.cfg deleted file mode 100644 index e90dfeeeb..000000000 --- a/tools/release/kokoro/windows/electron_1.7_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.7.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.7_x64.cfg b/tools/release/kokoro/windows/electron_1.7_x64.cfg deleted file mode 100644 index 417b1bccf..000000000 --- a/tools/release/kokoro/windows/electron_1.7_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.7.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.8_ia32.cfg b/tools/release/kokoro/windows/electron_1.8_ia32.cfg deleted file mode 100644 index ff51b7ab8..000000000 --- a/tools/release/kokoro/windows/electron_1.8_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "1.8.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_1.8_x64.cfg b/tools/release/kokoro/windows/electron_1.8_x64.cfg deleted file mode 100644 index 1675c9f03..000000000 --- a/tools/release/kokoro/windows/electron_1.8_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "1.8.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_2.0_ia32.cfg b/tools/release/kokoro/windows/electron_2.0_ia32.cfg deleted file mode 100644 index 145f2cf97..000000000 --- a/tools/release/kokoro/windows/electron_2.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "2.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_2.0_x64.cfg b/tools/release/kokoro/windows/electron_2.0_x64.cfg deleted file mode 100644 index 0005d14ff..000000000 --- a/tools/release/kokoro/windows/electron_2.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "2.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_3.0_ia32.cfg b/tools/release/kokoro/windows/electron_3.0_ia32.cfg deleted file mode 100644 index f4a19371f..000000000 --- a/tools/release/kokoro/windows/electron_3.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "3.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_3.0_x64.cfg b/tools/release/kokoro/windows/electron_3.0_x64.cfg deleted file mode 100644 index cb2c38bea..000000000 --- a/tools/release/kokoro/windows/electron_3.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "3.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_3.1_ia32.cfg b/tools/release/kokoro/windows/electron_3.1_ia32.cfg deleted file mode 100644 index 92d4ec6d0..000000000 --- a/tools/release/kokoro/windows/electron_3.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "3.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_3.1_x64.cfg b/tools/release/kokoro/windows/electron_3.1_x64.cfg deleted file mode 100644 index 5989e7aa0..000000000 --- a/tools/release/kokoro/windows/electron_3.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "3.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_4.1_ia32.cfg b/tools/release/kokoro/windows/electron_4.1_ia32.cfg deleted file mode 100644 index 67eb4183a..000000000 --- a/tools/release/kokoro/windows/electron_4.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_4.1_x64.cfg b/tools/release/kokoro/windows/electron_4.1_x64.cfg deleted file mode 100644 index 70b52b12a..000000000 --- a/tools/release/kokoro/windows/electron_4.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_4.2_ia32.cfg b/tools/release/kokoro/windows/electron_4.2_ia32.cfg deleted file mode 100644 index f447ed311..000000000 --- a/tools/release/kokoro/windows/electron_4.2_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_4.2_x64.cfg b/tools/release/kokoro/windows/electron_4.2_x64.cfg deleted file mode 100644 index a29112fe5..000000000 --- a/tools/release/kokoro/windows/electron_4.2_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.2.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_5.0_ia32.cfg b/tools/release/kokoro/windows/electron_5.0_ia32.cfg deleted file mode 100644 index 991bdec88..000000000 --- a/tools/release/kokoro/windows/electron_5.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_5.0_x64.cfg b/tools/release/kokoro/windows/electron_5.0_x64.cfg deleted file mode 100644 index 3b7857023..000000000 --- a/tools/release/kokoro/windows/electron_5.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_6.0_ia32.cfg b/tools/release/kokoro/windows/electron_6.0_ia32.cfg deleted file mode 100644 index f944e7902..000000000 --- a/tools/release/kokoro/windows/electron_6.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_6.0_x64.cfg b/tools/release/kokoro/windows/electron_6.0_x64.cfg deleted file mode 100644 index 5dda672d3..000000000 --- a/tools/release/kokoro/windows/electron_6.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_6.1_ia32.cfg b/tools/release/kokoro/windows/electron_6.1_ia32.cfg deleted file mode 100644 index b202263ac..000000000 --- a/tools/release/kokoro/windows/electron_6.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_6.1_x64.cfg b/tools/release/kokoro/windows/electron_6.1_x64.cfg deleted file mode 100644 index 2352deef8..000000000 --- a/tools/release/kokoro/windows/electron_6.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_7.0_ia32.cfg b/tools/release/kokoro/windows/electron_7.0_ia32.cfg deleted file mode 100644 index e7c9d1ff0..000000000 --- a/tools/release/kokoro/windows/electron_7.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_7.0_x64.cfg b/tools/release/kokoro/windows/electron_7.0_x64.cfg deleted file mode 100644 index 838143f22..000000000 --- a/tools/release/kokoro/windows/electron_7.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_7.1_ia32.cfg b/tools/release/kokoro/windows/electron_7.1_ia32.cfg deleted file mode 100644 index bda7d339b..000000000 --- a/tools/release/kokoro/windows/electron_7.1_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_7.1_x64.cfg b/tools/release/kokoro/windows/electron_7.1_x64.cfg deleted file mode 100644 index 008cac967..000000000 --- a/tools/release/kokoro/windows/electron_7.1_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.1.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_8.0_ia32.cfg b/tools/release/kokoro/windows/electron_8.0_ia32.cfg deleted file mode 100644 index ca01fd57f..000000000 --- a/tools/release/kokoro/windows/electron_8.0_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/electron_8.0_x64.cfg b/tools/release/kokoro/windows/electron_8.0_x64.cfg deleted file mode 100644 index 988322a4e..000000000 --- a/tools/release/kokoro/windows/electron_8.0_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "electron" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_10_ia32.cfg b/tools/release/kokoro/windows/node_10_ia32.cfg deleted file mode 100644 index 5a2d283c7..000000000 --- a/tools/release/kokoro/windows/node_10_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_10_x64.cfg b/tools/release/kokoro/windows/node_10_x64.cfg deleted file mode 100644 index c92671de8..000000000 --- a/tools/release/kokoro/windows/node_10_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "10.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_11_ia32.cfg b/tools/release/kokoro/windows/node_11_ia32.cfg deleted file mode 100644 index 507c11cce..000000000 --- a/tools/release/kokoro/windows/node_11_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_11_x64.cfg b/tools/release/kokoro/windows/node_11_x64.cfg deleted file mode 100644 index ec92fe997..000000000 --- a/tools/release/kokoro/windows/node_11_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "11.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_12_ia32.cfg b/tools/release/kokoro/windows/node_12_ia32.cfg deleted file mode 100644 index d9f1988a4..000000000 --- a/tools/release/kokoro/windows/node_12_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_12_x64.cfg b/tools/release/kokoro/windows/node_12_x64.cfg deleted file mode 100644 index a2d7c70c8..000000000 --- a/tools/release/kokoro/windows/node_12_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "12.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_13_ia32.cfg b/tools/release/kokoro/windows/node_13_ia32.cfg deleted file mode 100644 index 521893bd1..000000000 --- a/tools/release/kokoro/windows/node_13_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_13_x64.cfg b/tools/release/kokoro/windows/node_13_x64.cfg deleted file mode 100644 index ae937cc7f..000000000 --- a/tools/release/kokoro/windows/node_13_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "13.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_4_ia32.cfg b/tools/release/kokoro/windows/node_4_ia32.cfg deleted file mode 100644 index 88c163c2a..000000000 --- a/tools/release/kokoro/windows/node_4_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_4_x64.cfg b/tools/release/kokoro/windows/node_4_x64.cfg deleted file mode 100644 index 66092f441..000000000 --- a/tools/release/kokoro/windows/node_4_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "4.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_5_ia32.cfg b/tools/release/kokoro/windows/node_5_ia32.cfg deleted file mode 100644 index a883e4245..000000000 --- a/tools/release/kokoro/windows/node_5_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_5_x64.cfg b/tools/release/kokoro/windows/node_5_x64.cfg deleted file mode 100644 index 33099355b..000000000 --- a/tools/release/kokoro/windows/node_5_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "5.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_6_ia32.cfg b/tools/release/kokoro/windows/node_6_ia32.cfg deleted file mode 100644 index 651119035..000000000 --- a/tools/release/kokoro/windows/node_6_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_6_x64.cfg b/tools/release/kokoro/windows/node_6_x64.cfg deleted file mode 100644 index bd50810ce..000000000 --- a/tools/release/kokoro/windows/node_6_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "6.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_7_ia32.cfg b/tools/release/kokoro/windows/node_7_ia32.cfg deleted file mode 100644 index a0900e932..000000000 --- a/tools/release/kokoro/windows/node_7_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_7_x64.cfg b/tools/release/kokoro/windows/node_7_x64.cfg deleted file mode 100644 index 8483b8436..000000000 --- a/tools/release/kokoro/windows/node_7_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "7.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_8_ia32.cfg b/tools/release/kokoro/windows/node_8_ia32.cfg deleted file mode 100644 index 59febe3b3..000000000 --- a/tools/release/kokoro/windows/node_8_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_8_x64.cfg b/tools/release/kokoro/windows/node_8_x64.cfg deleted file mode 100644 index bf0da19d5..000000000 --- a/tools/release/kokoro/windows/node_8_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "8.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_9_ia32.cfg b/tools/release/kokoro/windows/node_9_ia32.cfg deleted file mode 100644 index bb419d8c6..000000000 --- a/tools/release/kokoro/windows/node_9_ia32.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "ia32" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows/node_9_x64.cfg b/tools/release/kokoro/windows/node_9_x64.cfg deleted file mode 100644 index 8380f4311..000000000 --- a/tools/release/kokoro/windows/node_9_x64.cfg +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -build_file: "grpc-node/packages/grpc-native-core/tools/run_tests/artifacts/build_one_artifact.bat" -env_vars { - key: "RUNTIME" - value: "node" -} -env_vars { - key: "ARCH" - value: "x64" -} -env_vars { - key: "VERSION" - value: "9.0.0" -} -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} From 58afa5ed7d9854749d67b40ae66af63292e32725 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 May 2020 15:56:15 -0700 Subject: [PATCH 1074/1899] Rebuild after installing to update grpc binary --- packages/grpc-health-check/gulpfile.ts | 4 +++- test/gulpfile.ts | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/grpc-health-check/gulpfile.ts b/packages/grpc-health-check/gulpfile.ts index 74c571fe0..0ddaa257e 100644 --- a/packages/grpc-health-check/gulpfile.ts +++ b/packages/grpc-health-check/gulpfile.ts @@ -28,7 +28,9 @@ const testDir = path.resolve(healthCheckDir, 'test'); const runInstall = () => execa('npm', ['install', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); -const install = gulp.series(runInstall); +const runRebuild = () => execa('npm', ['rebuild', '--unsafe-perm'], {cwd: healthCheckDir, stdio: 'inherit'}); + +const install = gulp.series(runInstall, runRebuild); const test = () => gulp.src(`${testDir}/*.js`).pipe(mocha({reporter: 'mocha-jenkins-reporter'})); diff --git a/test/gulpfile.ts b/test/gulpfile.ts index d29404a61..05976c173 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -25,10 +25,14 @@ import * as semver from 'semver'; const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); -const install = () => { +const runInstall = () => { return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); }; +const runRebuild = () => execa('npm', ['rebuild', '--unsafe-perm'], {cwd: testDir, stdio: 'inherit'}); + +const install = gulp.series(runInstall, runRebuild); + const cleanAll = () => Promise.resolve(); const runTestsWithFixture = (server, client) => () => new Promise((resolve, reject) => { From 690848648dd2feadbcde7ab47cb359355444f6e2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 09:30:02 -0700 Subject: [PATCH 1075/1899] Delete templates for grpc-native-core directory --- .../grpc-native-core/binding.gyp.template | 420 ------------------ .../grpc-native-core/package.json.template | 107 ----- 2 files changed, 527 deletions(-) delete mode 100644 templates/packages/grpc-native-core/binding.gyp.template delete mode 100644 templates/packages/grpc-native-core/package.json.template diff --git a/templates/packages/grpc-native-core/binding.gyp.template b/templates/packages/grpc-native-core/binding.gyp.template deleted file mode 100644 index c3fa37b4f..000000000 --- a/templates/packages/grpc-native-core/binding.gyp.template +++ /dev/null @@ -1,420 +0,0 @@ -%YAML 1.2 ---- | - # GRPC Node gyp file - # This currently builds the Node extension and dependencies - # This file has been automatically generated from a template file. - # Please look at the templates directory instead. - # This file can be regenerated from the template by running - # tools/buildgen/generate_projects.sh - - # Copyright 2015 gRPC authors. - # - # Licensed under the Apache License, Version 2.0 (the "License"); - # you may not use this file except in compliance with the License. - # You may obtain a copy of the License at - # - # http://www.apache.org/licenses/LICENSE-2.0 - # - # Unless required by applicable law or agreed to in writing, software - # distributed under the License is distributed on an "AS IS" BASIS, - # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - # See the License for the specific language governing permissions and - # limitations under the License. - <% - def gyp_target_name(lib_name): - if lib_name.startswith("absl/"): - return lib_name.replace("/", "__").replace(":", "__") - else: - return lib_name - %> - # Some of this file is built with the help of - # https://n8.io/converting-a-c-library-to-gyp/ - { - 'variables': { - 'runtime%': 'node', - # Some Node installations use the system installation of OpenSSL, and on - # some systems, the system OpenSSL still does not have ALPN support. This - # will let users recompile gRPC to work without ALPN. - 'grpc_alpn%': 'true', - # Indicates that the library should be built with gcov. - 'grpc_gcov%': 'false', - # Indicates that the library should be built with compatibility for musl - # libc, so that it can run on Alpine Linux. This is only necessary if not - # building on Alpine Linux - 'grpc_alpine%': 'false' - }, - 'target_defaults': { - 'configurations': { - % for name, args in configs.iteritems(): - % if name in ['dbg', 'opt']: - '${{'dbg':'Debug', 'opt': 'Release'}[name]}': { - % for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines')]: - % if args.get(arg, None) is not None: - '${prop}': [ - % for item in args.get(arg).split(): - '${item}', - % endfor - ], - % endif - % endfor - }, - % endif - % endfor - }, - % for arg, prop in [('CPPFLAGS', 'cflags'), ('LDFLAGS', 'ldflags')]: - % if defaults['global'].get(arg, None) is not None: - '${prop}': [ - % for item in defaults['global'].get(arg).split() + (['-fvisibility=hidden'] if arg == 'CPPFLAGS' else []): - '${item}', - % endfor - ], - % endif - % endfor - 'cflags_c': [ - '-std=c99' - ], - 'cflags_cc': [ - '-std=c++1y' - ], - 'include_dirs': [ - 'deps/grpc', - 'deps/grpc/include', - 'deps/grpc/src/core/ext/upb-generated', - 'deps/grpc/third_party/abseil-cpp', - 'deps/grpc/third_party/address_sorting/include', - 'deps/grpc/third_party/cares', - 'deps/grpc/third_party/cares/cares', - 'deps/grpc/third_party/upb', - 'deps/grpc/third_party/upb/generated_for_cmake', - ], - 'defines': [ - 'GPR_BACKWARDS_COMPATIBILITY_MODE', - 'GRPC_ARES=1', - 'GRPC_UV', - 'GRPC_NODE_VERSION="${settings.get('node_version', settings.version)}"', - 'CARES_STATICLIB', - 'CARES_SYMBOL_HIDING' - ], - 'defines!': [ - 'OPENSSL_THREADS' - ], - 'conditions': [ - ['grpc_gcov=="true"', { - % for arg, prop in [('CPPFLAGS', 'cflags'), ('DEFINES', 'defines'), ('LDFLAGS', 'ldflags')]: - % if configs['gcov'].get(arg, None) is not None: - '${prop}': [ - % for item in configs['gcov'].get(arg).split(): - '${item}', - % endfor - ], - % endif - % endfor - }], - ['grpc_alpine=="true"', { - 'defines': [ - 'GPR_MUSL_LIBC_COMPAT' - ] - }], - # This is the condition for using boringssl - ['OS=="win" or runtime=="electron"', { - "include_dirs": [ - "deps/grpc/third_party/boringssl/include" - ], - "defines": [ - 'OPENSSL_NO_ASM' - ] - }, { - 'conditions': [ - ["target_arch=='ia32'", { - "include_dirs": [ "<(node_root_dir)/deps/openssl/config/piii" ] - }], - ["target_arch=='x64'", { - "include_dirs": [ "<(node_root_dir)/deps/openssl/config/k8" ] - }], - ["target_arch=='arm'", { - "include_dirs": [ "<(node_root_dir)/deps/openssl/config/arm" ] - }], - ['grpc_alpn=="true"', { - 'defines': [ - 'TSI_OPENSSL_ALPN_SUPPORT=1' - ], - }, { - 'defines': [ - 'TSI_OPENSSL_ALPN_SUPPORT=0' - ], - }] - ], - 'include_dirs': [ - '<(node_root_dir)/deps/openssl/openssl/include', - ] - }], - ['OS == "win"', { - "include_dirs": [ - "deps/grpc/third_party/zlib" - ], - "defines": [ - '_WIN32_WINNT=0x0600', - 'WIN32_LEAN_AND_MEAN', - '_HAS_EXCEPTIONS=0', - 'UNICODE', - '_UNICODE', - 'NOMINMAX', - ], - "msvs_settings": { - 'VCCLCompilerTool': { - 'RuntimeLibrary': 1, # static debug - } - }, - "libraries": [ - "ws2_32" - ] - }, { # OS != "win" - 'include_dirs': [ - '<(node_root_dir)/deps/zlib' - ] - }], - ['OS == "mac"', { - 'xcode_settings': { - % if defaults['global'].get('CPPFLAGS', None) is not None: - 'OTHER_CFLAGS': [ - % for item in defaults['global'].get('CPPFLAGS').split() + ['-fvisibility=hidden']: - '${item}', - % endfor - ], - 'OTHER_CPLUSPLUSFLAGS': [ - % for item in defaults['global'].get('CPPFLAGS').split() + ['-fvisibility=hidden']: - '${item}', - % endfor - '-stdlib=libc++', - '-std=c++1y', - '-Wno-error=deprecated-declarations' - ], - % endif - }, - }] - ] - }, - 'conditions': [ - ['OS=="win" or runtime=="electron"', { - 'targets': [ - % for lib in libs: - % if lib.name == 'boringssl': - { - 'target_name': '${lib.name}', - 'product_prefix': 'lib', - 'type': 'static_library', - 'cflags': [ - '-Wno-implicit-fallthrough' - ], - 'defines': [ - '_XOPEN_SOURCE=700' - ], - 'dependencies': [ - % for dep in getattr(lib, 'deps', []): - '${dep}', - % endfor - ], - 'sources': [ - % for source in lib.src: - 'deps/grpc/${source}', - % endfor - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - } - }] - ] - }, - % endif - % endfor - ], - }], - ['OS == "win" and runtime!="electron"', { - 'targets': [ - { - # IMPORTANT WINDOWS BUILD INFORMATION - # This library does not build on Windows without modifying the Node - # development packages that node-gyp downloads in order to build. - # Due to https://github.com/nodejs/node/issues/4932, the headers for - # BoringSSL conflict with the OpenSSL headers included by default - # when including the Node headers. The remedy for this is to remove - # the OpenSSL headers, from the downloaded Node development package, - # which is typically located in `.node-gyp` in your home directory. - # - # This is not true of Electron, which does not have OpenSSL headers. - 'target_name': 'WINDOWS_BUILD_WARNING', - 'rules': [ - { - 'rule_name': 'WINDOWS_BUILD_WARNING', - 'extension': 'S', - 'inputs': [ - 'package.json' - ], - 'outputs': [ - 'ignore_this_part' - ], - 'action': ['echo', 'IMPORTANT: Due to https://github.com/nodejs/node/issues/4932, to build this library on Windows, you must first remove <(node_root_dir)/include/node/openssl/'] - } - ] - }, - ] - }], - ['OS == "win"', { - 'targets': [ - # Only want to compile zlib under Windows - % for lib in libs: - % if lib.name == 'z': - { - 'target_name': '${lib.name}', - 'product_prefix': 'lib', - 'type': 'static_library', - 'dependencies': [ - % for dep in getattr(lib, 'deps', []): - '${dep}', - % endfor - ], - 'sources': [ - % for source in lib.src: - 'deps/grpc/${source}', - % endfor - ] - }, - % endif - % endfor - ] - }] - ], - 'targets': [ - % for lib in libs: - % if lib.name == 'ares': - { - 'target_name': '${lib.name}', - 'product_prefix': 'lib', - 'type': 'static_library', - 'sources': [ - % for source in lib.src: - 'deps/grpc/${source}', - % endfor - ], - 'defines': [ - '_GNU_SOURCE' - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - }, - 'include_dirs': [ - 'deps/grpc/third_party/cares/config_darwin' - ], - 'defines': [ - 'HAVE_CONFIG_H' - ] - }], - ['OS == "linux"', { - 'include_dirs': [ - 'deps/grpc/third_party/cares/config_linux' - ], - 'defines': [ - 'HAVE_CONFIG_H' - ] - }], - ['OS == "win"', { - 'include_dirs': [ - 'deps/grpc/third_party/cares/config_windows' - ], - 'defines': [ - 'HAVE_CONFIG_H' - ] - }] - ] - }, - % endif - % endfor - % for core in libs: - % if core.name == 'grpc' or core.name == 'address_sorting': - % for lib in libs: - % if lib.name == core.name or (lib.name in core.transitive_deps and lib.name not in ('boringssl', 'z')): - { - 'target_name': '${gyp_target_name(lib.name)}', - 'product_prefix': 'lib', - 'type': 'static_library', - 'dependencies': [ - % for dep in getattr(lib, 'deps', []): - '${gyp_target_name(dep)}', - % endfor - ], - 'sources': [ - % for source in lib.src: - 'deps/grpc/${source}', - % endfor - ], - 'conditions': [ - ['OS == "mac"', { - 'xcode_settings': { - 'MACOSX_DEPLOYMENT_TARGET': '10.9' - } - }] - ] - }, - % endif - % endfor - % endif - % endfor - { - 'include_dirs': [ - "'ext/'+f).join(' ')\")" - ], - "dependencies": [ - "grpc", - "gpr", - "ares", - "address_sorting" - ] - }, - { - "target_name": "action_after_build", - "type": "none", - "dependencies": [ "<(module_name)" ], - "copies": [ - { - "files": [ "<(PRODUCT_DIR)/<(module_name).node"], - "destination": "<(module_path)" - } - ] - } - ] - } diff --git a/templates/packages/grpc-native-core/package.json.template b/templates/packages/grpc-native-core/package.json.template deleted file mode 100644 index 515614db2..000000000 --- a/templates/packages/grpc-native-core/package.json.template +++ /dev/null @@ -1,107 +0,0 @@ -%YAML 1.2 ---- | - { - "name": "grpc", - "version": "${settings.get('node_version', settings.version)}", - "author": "Google Inc.", - "description": "gRPC Library for Node", - "homepage": "https://grpc.io/", - "repository": { - "type": "git", - "url": "https://github.com/grpc/grpc-node.git" - }, - "bugs": "https://github.com/grpc/grpc-node/issues", - "contributors": [ - { - "name": "Michael Lumish", - "email": "mlumish@google.com" - } - ], - "directories": { - "lib": "src" - }, - "scripts": { - "build": "node-pre-gyp build", - "electron-build": "node-pre-gyp configure build --runtime=electron --disturl=https://atom.io/download/atom-shell", - "coverage": "istanbul cover ./node_modules/.bin/_mocha test", - "install": "node-pre-gyp install --fallback-to-build --library=static_library", - "prepack": "git submodule update --init --recursive && npm install" - }, - "bundledDependencies": [ - "node-pre-gyp" - ], - "dependencies": { - "@types/bytebuffer": "^5.0.40", - "lodash.camelcase": "^4.3.0", - "lodash.clone": "^4.5.0", - "nan": "^2.13.2", - "node-pre-gyp": "^0.14.0", - "protobufjs": "^5.0.3" - }, - "devDependencies": { - "body-parser": "^1.15.2", - "electron-mocha": "^3.1.1", - "express": "^4.14.0", - "google-protobuf": "^3.0.0", - "istanbul": "^0.4.4", - "lodash": "^4.17.4", - "minimist": "^1.1.0", - "node-forge": "^0.7.5", - "poisson-process": "^0.2.1" - }, - "engines": { - "node": ">=4" - }, - "binary": { - "module_name": "grpc_node", - "module_path": "src/node/extension_binary/{node_abi}-{platform}-{arch}-{libc}", - "host": "https://node-precompiled-binaries.grpc.io/", - "remote_path": "{name}/v{version}", - "package_name": "{node_abi}-{platform}-{arch}-{libc}.tar.gz" - }, - "files": [ - "LICENSE", - "README.md", - "deps/grpc/etc/", - "index.js", - "index.d.ts", - "src/*.js", - "ext/*.{cc,h}", - "deps/grpc/include/grpc/**/*.h", - "deps/grpc/src/core/**/*.{c,cc,h}", - "deps/grpc/src/boringssl/err_data.c", - "deps/grpc/third_party/abseil-cpp/absl/**/*.{cc,h,inc}", - "deps/grpc/third_party/boringssl/crypto/**/*.{c,cc,h}", - "deps/grpc/third_party/boringssl/include/**/*.{c,cc,h}", - "deps/grpc/third_party/boringssl/ssl/**/*.{c,cc,h}", - "deps/grpc/third_party/boringssl/third_party/**/*.{c,h}", - "deps/grpc/third_party/upb/**/*.{c,h,inc}", - "deps/grpc/third_party/zlib/**/*.{c,cc,h}", - "deps/grpc/third_party/address_sorting/**/*.{c,h}", - "deps/grpc/third_party/cares/**/*.{c,h}", - "binding.gyp" - ], - "main": "index.js", - "typings": "index.d.ts", - "license": "Apache-2.0", - "jshintConfig": { - "bitwise": true, - "curly": true, - "eqeqeq": true, - "esnext": true, - "freeze": true, - "immed": true, - "indent": 2, - "latedef": "nofunc", - "maxlen": 80, - "mocha": true, - "newcap": true, - "node": true, - "noarg": true, - "quotmark": "single", - "strict": true, - "trailing": true, - "undef": true, - "unused": "vars" - } - } From 5e9a3ca738b7c9e6b0a875747abfff404342e3ab Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 11:14:04 -0700 Subject: [PATCH 1076/1899] Add grpc-tools build GitHub Workflow --- .github/workflows/grpc-tools-build.yml | 66 ++++++++++++++++++++++++++ packages/grpc-tools/build_binaries.ps1 | 2 +- packages/grpc-tools/build_binaries.sh | 4 +- 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/grpc-tools-build.yml diff --git a/.github/workflows/grpc-tools-build.yml b/.github/workflows/grpc-tools-build.yml new file mode 100644 index 000000000..1e21cad71 --- /dev/null +++ b/.github/workflows/grpc-tools-build.yml @@ -0,0 +1,66 @@ +name: grpc-tools Build + +on: + push: + branches: + - master + pull-request: + branches: + - master + +jobs: + linux_build: + name: Linux grpc-tools Build + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Build + run: | + docker build -t kokoro-native-image tools/release/native + docker run -v /var/run/docker.sock:/var/run/docker.sock -v $GITHUB_WORKSPACE:$GITHUB_WORKSPACE kokoro-native-image $GITHUB_WORKSPACE/packages/grpc-tools/build_binaries.sh + - uses: actions/upload-artifact@v2 + with: + name: grpc-tools_linux + path: artifacts/ + macos_build: + name: Macos grpc-tools Build + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Build + run: packages/grpc-tools/build_binaries.sh + - uses: actions/upload-artifact@v2 + with: + name: grpc-tools_macos + path: artifacts/ + windows_build: + name: Windows grpc-tools Build + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + with: + submodules: recursive + - name: Build + run: packages/grpc-tools/build_binaries.ps1 + - uses: actions/upload-artifact@v2 + with: + name: grpc-tools_windows + path: artifacts/ + combine_artifacts: + name: Combine grpc-tools artifacts + runs-on: ubuntu-latest + needs: [linux_build, macos_build, windows_build] + steps: + - uses: actions/download-artifact@v2 + - name: Copy + run: | + mkdir artifacts + cp -r ./**/* artifacts/ + - uses: actions/upload-artifact@v2 + with: + name: combined-artifacts + path: artifacts/ diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 8c249642e..139485c14 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -37,7 +37,7 @@ MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" $ToolsVersion = ((Get-Content $PackageFile) -join "`n" | ConvertFrom-Json).version -$OutDir = $Env:ARTIFACTS_OUT + "/grpc-tools/v" + $ToolsVersion +$OutDir = $Base + "/../../artifacts/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir $ArchList = "ia32","x64" diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index 2a4421835..b26946afa 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -23,8 +23,8 @@ protobuf_base=$base/deps/protobuf tools_version=$(jq '.version' < package.json | tr -d '"') -# Note: $ARTIFACTS_OUT should not be in this directory -out_dir=$ARTIFACTS_OUT/grpc-tools/v$tools_version +# Note: artifacts should not be output in the package directory +out_dir=$base/../../artifacts/grpc-tools/v$tools_version mkdir -p "$out_dir" case $(uname -s) in From 8dd73f4635c58f8a0419a566c1c565e64f4bea14 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 11:18:45 -0700 Subject: [PATCH 1077/1899] Remove kokoro build scripts and configs --- test/kokoro-nodejs-build-test.bat | 23 ------------- test/kokoro-nodejs-build-test.sh | 20 ----------- test/kokoro/linux-build-nodejs.cfg | 19 ----------- test/kokoro/macos-build-nodejs.cfg | 19 ----------- test/kokoro/windows-build-nodejs.cfg | 19 ----------- tools/release/kokoro-grpc-tools.bat | 27 --------------- tools/release/kokoro-grpc-tools.sh | 37 --------------------- tools/release/kokoro/linux-grpc-tools.cfg | 25 -------------- tools/release/kokoro/macos-grpc-tools.cfg | 25 -------------- tools/release/kokoro/windows-grpc-tools.cfg | 25 -------------- 10 files changed, 239 deletions(-) delete mode 100644 test/kokoro-nodejs-build-test.bat delete mode 100755 test/kokoro-nodejs-build-test.sh delete mode 100644 test/kokoro/linux-build-nodejs.cfg delete mode 100644 test/kokoro/macos-build-nodejs.cfg delete mode 100644 test/kokoro/windows-build-nodejs.cfg delete mode 100644 tools/release/kokoro-grpc-tools.bat delete mode 100755 tools/release/kokoro-grpc-tools.sh delete mode 100644 tools/release/kokoro/linux-grpc-tools.cfg delete mode 100644 tools/release/kokoro/macos-grpc-tools.cfg delete mode 100644 tools/release/kokoro/windows-grpc-tools.cfg diff --git a/test/kokoro-nodejs-build-test.bat b/test/kokoro-nodejs-build-test.bat deleted file mode 100644 index ea45c3f80..000000000 --- a/test/kokoro-nodejs-build-test.bat +++ /dev/null @@ -1,23 +0,0 @@ -@rem Copyright 2019 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -cd /d %~dp0 -cd .. - -call ./tools/release/kokoro-grpc-tools.bat || goto :error - -goto :EOF - -:error -exit /b 1 \ No newline at end of file diff --git a/test/kokoro-nodejs-build-test.sh b/test/kokoro-nodejs-build-test.sh deleted file mode 100755 index d3b2a546e..000000000 --- a/test/kokoro-nodejs-build-test.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -# Copyright 2019 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -e -cd $(dirname $0)/.. -base_dir=$(pwd) - -./tools/release/kokoro-grpc-tools.sh \ No newline at end of file diff --git a/test/kokoro/linux-build-nodejs.cfg b/test/kokoro/linux-build-nodejs.cfg deleted file mode 100644 index ba2f49f24..000000000 --- a/test/kokoro/linux-build-nodejs.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro-nodejs-build-test.sh" -timeout_mins: 60 diff --git a/test/kokoro/macos-build-nodejs.cfg b/test/kokoro/macos-build-nodejs.cfg deleted file mode 100644 index ba2f49f24..000000000 --- a/test/kokoro/macos-build-nodejs.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro-nodejs-build-test.sh" -timeout_mins: 60 diff --git a/test/kokoro/windows-build-nodejs.cfg b/test/kokoro/windows-build-nodejs.cfg deleted file mode 100644 index 87f443708..000000000 --- a/test/kokoro/windows-build-nodejs.cfg +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright 2018 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro-nodejs-build-test.bat" -timeout_mins: 60 diff --git a/tools/release/kokoro-grpc-tools.bat b/tools/release/kokoro-grpc-tools.bat deleted file mode 100644 index 6b1e2fb48..000000000 --- a/tools/release/kokoro-grpc-tools.bat +++ /dev/null @@ -1,27 +0,0 @@ -@rem Copyright 2019 gRPC authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem http://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. - -cd /d %~dp0 -cd ../.. - -git submodule update --init --recursive - -@rem make sure msys binaries are preferred over cygwin binaries -set PATH=C:\tools\msys64\usr\bin;%PATH% -set ARTIFACTS_OUT=%cd%/artifacts -powershell -File ./packages/grpc-tools/build_binaries.ps1 || goto :error -goto :EOF - -:error -exit /b 1 \ No newline at end of file diff --git a/tools/release/kokoro-grpc-tools.sh b/tools/release/kokoro-grpc-tools.sh deleted file mode 100755 index 267d6cc25..000000000 --- a/tools/release/kokoro-grpc-tools.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/bash -# Copyright 2019 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Deleting Ruby. -rm -rf ~/.rvm - -set -e -cd $(dirname $0)/../.. -base_dir=$(pwd) - -OS=$(uname) - -git submodule update --init --recursive - -uname -a - -case $OS in -Linux) - docker build -t kokoro-native-image tools/release/native - docker run -v /var/run/docker.sock:/var/run/docker.sock -v $base_dir:$base_dir -e ARTIFACTS_OUT=$base_dir/artifacts kokoro-native-image $base_dir/packages/grpc-tools/build_binaries.sh - ;; -Darwin) - ARTIFACTS_OUT=$base_dir/artifacts ./packages/grpc-tools/build_binaries.sh - ;; -esac \ No newline at end of file diff --git a/tools/release/kokoro/linux-grpc-tools.cfg b/tools/release/kokoro/linux-grpc-tools.cfg deleted file mode 100644 index 0925db77b..000000000 --- a/tools/release/kokoro/linux-grpc-tools.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2019 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-grpc-tools.sh" -timeout_mins: 60 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/macos-grpc-tools.cfg b/tools/release/kokoro/macos-grpc-tools.cfg deleted file mode 100644 index 0925db77b..000000000 --- a/tools/release/kokoro/macos-grpc-tools.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2019 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-grpc-tools.sh" -timeout_mins: 60 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} diff --git a/tools/release/kokoro/windows-grpc-tools.cfg b/tools/release/kokoro/windows-grpc-tools.cfg deleted file mode 100644 index db649afcf..000000000 --- a/tools/release/kokoro/windows-grpc-tools.cfg +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright 2019 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/tools/release/kokoro-grpc-tools.bat" -timeout_mins: 60 -action { - define_artifacts { - regex: "github/grpc-node/artifacts/**", - strip_prefix: "github/grpc-node/artifacts" - } -} From f7617255566f8c4cbce6f77315a265c9dd89f248 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 11:24:20 -0700 Subject: [PATCH 1078/1899] My VSCode plugin autocompletes upload-artifact and download-artifact to v1 --- .github/workflows/grpc-tools-build.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/grpc-tools-build.yml b/.github/workflows/grpc-tools-build.yml index 1e21cad71..ac4b5a43c 100644 --- a/.github/workflows/grpc-tools-build.yml +++ b/.github/workflows/grpc-tools-build.yml @@ -20,7 +20,7 @@ jobs: run: | docker build -t kokoro-native-image tools/release/native docker run -v /var/run/docker.sock:/var/run/docker.sock -v $GITHUB_WORKSPACE:$GITHUB_WORKSPACE kokoro-native-image $GITHUB_WORKSPACE/packages/grpc-tools/build_binaries.sh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v1 with: name: grpc-tools_linux path: artifacts/ @@ -33,7 +33,7 @@ jobs: submodules: recursive - name: Build run: packages/grpc-tools/build_binaries.sh - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v1 with: name: grpc-tools_macos path: artifacts/ @@ -46,7 +46,7 @@ jobs: submodules: recursive - name: Build run: packages/grpc-tools/build_binaries.ps1 - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v1 with: name: grpc-tools_windows path: artifacts/ @@ -55,12 +55,12 @@ jobs: runs-on: ubuntu-latest needs: [linux_build, macos_build, windows_build] steps: - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v1 - name: Copy run: | mkdir artifacts cp -r ./**/* artifacts/ - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v1 with: name: combined-artifacts path: artifacts/ From 22bce28eede8174f82cf64593b5c8c8b8bbe563b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 11:34:38 -0700 Subject: [PATCH 1079/1899] Fix trigger condition typo --- .github/workflows/grpc-tools-build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/grpc-tools-build.yml b/.github/workflows/grpc-tools-build.yml index ac4b5a43c..ffcf5b9ce 100644 --- a/.github/workflows/grpc-tools-build.yml +++ b/.github/workflows/grpc-tools-build.yml @@ -4,7 +4,7 @@ on: push: branches: - master - pull-request: + pull_request: branches: - master From 95e49dc6841cd6ba115151bf8d6bd2afe8eeedbe Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 12 May 2020 14:52:01 -0700 Subject: [PATCH 1080/1899] Fix package installation in grpc-tools build script --- packages/grpc-tools/build_binaries.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 139485c14..38a2dcfd8 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -16,6 +16,10 @@ $ErrorActionPreference = "Stop" +<# https://stackoverflow.com/questions/16657778/install-nuget-via-powershell-script/26421187#comment107976901_48216538 #> + +[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]'Tls11,Tls12' + Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force Import-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 Install-Module -Force -Name 7Zip4Powershell From de9d8959b1bd33437fea88add9475ba586fb7bf5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 12:02:55 -0700 Subject: [PATCH 1081/1899] Make PowerShell actually output something of some value --- packages/grpc-tools/build_binaries.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 38a2dcfd8..d03b64a46 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -14,6 +14,8 @@ limitations under the License. #> +Set-PSDebug -trace 2 + $ErrorActionPreference = "Stop" <# https://stackoverflow.com/questions/16657778/install-nuget-via-powershell-script/26421187#comment107976901_48216538 #> From 83590e20b6dacd2242ed9350488ed893cfcda486 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 13:04:59 -0700 Subject: [PATCH 1082/1899] Test PowerShell output --- packages/grpc-tools/build_binaries.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index d03b64a46..81e27e2d2 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -16,6 +16,8 @@ Set-PSDebug -trace 2 +Write-Host "Hello World" + $ErrorActionPreference = "Stop" <# https://stackoverflow.com/questions/16657778/install-nuget-via-powershell-script/26421187#comment107976901_48216538 #> From de5063d4b1924059f1a11c899033e822f7f7b81b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 13:09:50 -0700 Subject: [PATCH 1083/1899] Call the powershell script through cmd --- .github/workflows/grpc-tools-build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/grpc-tools-build.yml b/.github/workflows/grpc-tools-build.yml index ffcf5b9ce..b419744cf 100644 --- a/.github/workflows/grpc-tools-build.yml +++ b/.github/workflows/grpc-tools-build.yml @@ -45,7 +45,8 @@ jobs: with: submodules: recursive - name: Build - run: packages/grpc-tools/build_binaries.ps1 + run: powershell -File ./packages/grpc-tools/build_binaries.ps1 + shell: cmd - uses: actions/upload-artifact@v1 with: name: grpc-tools_windows From 2677d8773c68d7e3083eb7cc5a30583bf4bc3a79 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 13:21:34 -0700 Subject: [PATCH 1084/1899] Change how artifacts directory path is written, remove debug output --- packages/grpc-tools/build_binaries.ps1 | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 81e27e2d2..a44d2971f 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -14,10 +14,6 @@ limitations under the License. #> -Set-PSDebug -trace 2 - -Write-Host "Hello World" - $ErrorActionPreference = "Stop" <# https://stackoverflow.com/questions/16657778/install-nuget-via-powershell-script/26421187#comment107976901_48216538 #> @@ -45,9 +41,12 @@ MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" $ToolsVersion = ((Get-Content $PackageFile) -join "`n" | ConvertFrom-Json).version -$OutDir = $Base + "/../../artifacts/grpc-tools/v" + $ToolsVersion +cd ../.. +$OutDir = $pwd + "/artifacts/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir +cd $Base + $ArchList = "ia32","x64" foreach ($Arch in $ArchList) { From edecb1994b4f6a7a68a9511f8131305346e2196b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 13:31:08 -0700 Subject: [PATCH 1085/1899] Add other debug output --- packages/grpc-tools/build_binaries.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index a44d2971f..90e2070d4 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -39,6 +39,8 @@ $ProtobufBase = $Base + "/deps/protobuf" MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" +Write-Host $PackageFile +Write-Host (Get-Content $PackageFile) -join "`n" $ToolsVersion = ((Get-Content $PackageFile) -join "`n" | ConvertFrom-Json).version cd ../.. From a59934ffa6b2d21fb30473691e19d0c5564230d7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 13:34:08 -0700 Subject: [PATCH 1086/1899] Add more debug output --- packages/grpc-tools/build_binaries.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 90e2070d4..407a70432 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -42,6 +42,7 @@ $PackageFile = $Base + "/package.json" Write-Host $PackageFile Write-Host (Get-Content $PackageFile) -join "`n" $ToolsVersion = ((Get-Content $PackageFile) -join "`n" | ConvertFrom-Json).version +Write-Host $ToolsVersion cd ../.. $OutDir = $pwd + "/artifacts/grpc-tools/v" + $ToolsVersion From a1807ce67a81176e81eda9029ae9393b577b4e85 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 13:37:07 -0700 Subject: [PATCH 1087/1899] Fix use of --- packages/grpc-tools/build_binaries.ps1 | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 407a70432..7f4859c89 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -39,13 +39,10 @@ $ProtobufBase = $Base + "/deps/protobuf" MkDir-p ($Base + "/build/bin") $PackageFile = $Base + "/package.json" -Write-Host $PackageFile -Write-Host (Get-Content $PackageFile) -join "`n" $ToolsVersion = ((Get-Content $PackageFile) -join "`n" | ConvertFrom-Json).version -Write-Host $ToolsVersion cd ../.. -$OutDir = $pwd + "/artifacts/grpc-tools/v" + $ToolsVersion +$OutDir = $pwd.Path + "/artifacts/grpc-tools/v" + $ToolsVersion Mkdir-p $OutDir cd $Base From 5184050d97c4def77dad7500d6700493d34d5555 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 May 2020 14:08:04 -0700 Subject: [PATCH 1088/1899] Add command tracing again --- packages/grpc-tools/build_binaries.ps1 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 7f4859c89..5cc5e45b7 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -47,6 +47,8 @@ Mkdir-p $OutDir cd $Base +Set-PSDebug -trace 2 + $ArchList = "ia32","x64" foreach ($Arch in $ArchList) { From 996e3529fc8e8cbf64296f57c5c00ad600c36719 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 15 May 2020 09:41:47 -0700 Subject: [PATCH 1089/1899] Copy a file that was previously in the grpc submodule --- .../grpc/tools/run_tests/interop/with_nvm.sh | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh diff --git a/packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh b/packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh new file mode 100644 index 000000000..55f4b2b87 --- /dev/null +++ b/packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +# Copyright 2015 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Makes sure NVM is loaded before executing the command passed as an argument +# shellcheck disable=SC1090 +source ~/.nvm/nvm.sh +"$@" From 9b82abae06ff51f8b9b034d323b92be204838846 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 15 May 2020 10:07:45 -0700 Subject: [PATCH 1090/1899] Set arch properly, clean build products differently --- packages/grpc-tools/build_binaries.ps1 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index 5cc5e45b7..bec4f1ac5 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -53,12 +53,12 @@ $ArchList = "ia32","x64" foreach ($Arch in $ArchList) { if ($Arch -eq "x64") { - $Generator = "Visual Studio 14 2015 Win64" + $ArchName = "x64" } else { - $Generator = "Visual Studio 14 2015" + $ArchName = "Win32" } - & cmake.exe . + & cmake.exe . -A $ArchName if ($LASTEXITCODE -ne 0) { throw "cmake failed" } @@ -73,7 +73,5 @@ foreach ($Arch in $ArchList) { Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/win32-" + $Arch + ".tar.gz") - Remove-Item ($Base + "/build/bin/protoc.exe") - Remove-Item ($Base + "/build/bin/grpc_node_plugin.exe") - Remove-Item ($Base + "/CMakeCache.txt") + & git clean -xdf . } \ No newline at end of file From 4c6847fc9fde4a37526bada59fd4cc23b0e94edb Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 15 May 2020 10:38:54 -0700 Subject: [PATCH 1091/1899] Build Windows x86 and x64 separately using a matrix --- .github/workflows/grpc-tools-build.yml | 7 +++- packages/grpc-tools/build_binaries.ps1 | 50 +++++++++++++------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/.github/workflows/grpc-tools-build.yml b/.github/workflows/grpc-tools-build.yml index b419744cf..4f84143a1 100644 --- a/.github/workflows/grpc-tools-build.yml +++ b/.github/workflows/grpc-tools-build.yml @@ -40,6 +40,11 @@ jobs: windows_build: name: Windows grpc-tools Build runs-on: windows-latest + strategy: + matrix: + arch: [ia32, x64] + env: + ARCH: ${{matrix.arch}} steps: - uses: actions/checkout@v2 with: @@ -49,7 +54,7 @@ jobs: shell: cmd - uses: actions/upload-artifact@v1 with: - name: grpc-tools_windows + name: grpc-tools_windows_${{matrix.arch}} path: artifacts/ combine_artifacts: name: Combine grpc-tools artifacts diff --git a/packages/grpc-tools/build_binaries.ps1 b/packages/grpc-tools/build_binaries.ps1 index bec4f1ac5..629aea266 100644 --- a/packages/grpc-tools/build_binaries.ps1 +++ b/packages/grpc-tools/build_binaries.ps1 @@ -49,29 +49,27 @@ cd $Base Set-PSDebug -trace 2 -$ArchList = "ia32","x64" - -foreach ($Arch in $ArchList) { - if ($Arch -eq "x64") { - $ArchName = "x64" - } else { - $ArchName = "Win32" - } - - & cmake.exe . -A $ArchName - if ($LASTEXITCODE -ne 0) { - throw "cmake failed" - } - & cmake.exe --build . - if ($LASTEXITCODE -ne 0) { - throw "cmake build failed" - } - - Copy-Item ($ProtobufBase + "/Debug/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") - Copy-Item ($Base + "/Debug/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") - - Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") - Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/win32-" + $Arch + ".tar.gz") - - & git clean -xdf . -} \ No newline at end of file +$Arch = $Env:ARCH + +if ($Arch -eq "x64") { + $ArchName = "x64" +} else { + $ArchName = "Win32" +} + +& cmake.exe . -A $ArchName +if ($LASTEXITCODE -ne 0) { + throw "cmake failed" +} +& cmake.exe --build . +if ($LASTEXITCODE -ne 0) { + throw "cmake build failed" +} + +Copy-Item ($ProtobufBase + "/Debug/protoc.exe") -Destination ($Base + "/build/bin/protoc.exe") +Copy-Item ($Base + "/Debug/grpc_node_plugin.exe") -Destination ($Base + "/build/bin/grpc_node_plugin.exe") + +Compress-7Zip -Path ($Base + "/build") -Format Tar -ArchiveFileName ($Base + "/Archive.tar") +Compress-7Zip -Path ($Base + "/Archive.tar") -Format GZip -ArchiveFileName ($OutDir + "/win32-" + $Arch + ".tar.gz") + +& git clean -xdf . \ No newline at end of file From e9fad90d5367c2b047d97e3d5cdb6ea414fb0b48 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 15 May 2020 11:03:18 -0700 Subject: [PATCH 1092/1899] Switch back to upload- and download-artifacts v2 --- .github/workflows/grpc-tools-build.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/grpc-tools-build.yml b/.github/workflows/grpc-tools-build.yml index 4f84143a1..f32a688c4 100644 --- a/.github/workflows/grpc-tools-build.yml +++ b/.github/workflows/grpc-tools-build.yml @@ -20,7 +20,7 @@ jobs: run: | docker build -t kokoro-native-image tools/release/native docker run -v /var/run/docker.sock:/var/run/docker.sock -v $GITHUB_WORKSPACE:$GITHUB_WORKSPACE kokoro-native-image $GITHUB_WORKSPACE/packages/grpc-tools/build_binaries.sh - - uses: actions/upload-artifact@v1 + - uses: actions/upload-artifact@v2 with: name: grpc-tools_linux path: artifacts/ @@ -33,7 +33,7 @@ jobs: submodules: recursive - name: Build run: packages/grpc-tools/build_binaries.sh - - uses: actions/upload-artifact@v1 + - uses: actions/upload-artifact@v2 with: name: grpc-tools_macos path: artifacts/ @@ -61,12 +61,12 @@ jobs: runs-on: ubuntu-latest needs: [linux_build, macos_build, windows_build] steps: - - uses: actions/download-artifact@v1 + - uses: actions/download-artifact@v2 - name: Copy run: | mkdir artifacts cp -r ./**/* artifacts/ - - uses: actions/upload-artifact@v1 + - uses: actions/upload-artifact@v2 with: name: combined-artifacts path: artifacts/ From 127541e6a6246a047a36806dc4282f437a755297 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 18 May 2020 08:35:27 -0700 Subject: [PATCH 1093/1899] Set execute permissions on the copied script --- .../deps/grpc/tools/run_tests/interop/with_nvm.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh diff --git a/packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh b/packages/grpc-native-core/deps/grpc/tools/run_tests/interop/with_nvm.sh old mode 100644 new mode 100755 From 4361242eb90959fcf23830ea2c7f985018ba7bf0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 20 May 2020 14:00:05 -0700 Subject: [PATCH 1094/1899] Add priority load balancer --- .../grpc-js/src/load-balancer-priority.ts | 457 ++++++++++++++++++ packages/grpc-js/src/load-balancer.ts | 2 + 2 files changed, 459 insertions(+) create mode 100644 packages/grpc-js/src/load-balancer-priority.ts diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts new file mode 100644 index 000000000..94f7f560b --- /dev/null +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -0,0 +1,457 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + getFirstUsableConfig, + registerLoadBalancerType, +} from './load-balancer'; +import { SubchannelAddress } from './subchannel'; +import { + LoadBalancingConfig, + isPriorityLoadBalancingConfig, +} from './load-balancing-config'; +import { ConnectivityState } from './channel'; +import { Picker, QueuePicker, UnavailablePicker } from './picker'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { ChannelOptions } from './channel-options'; +import { Status } from './constants'; +import { Metadata } from './metadata'; + +const TYPE_NAME = 'priority'; + +const DEFAULT_FAILOVER_TIME_MS = 10_000; +const DEFAULT_RETENTION_INTERVAL_MS = 15 * 60 * 1000; + +export type LocalitySubchannelAddress = SubchannelAddress & { + localityPath: string[]; +}; + +export function isLocalitySubchannelAddress( + address: SubchannelAddress +): address is LocalitySubchannelAddress { + return Array.isArray((address as LocalitySubchannelAddress).localityPath); +} + +interface PriorityChildBalancer { + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void; + exitIdle(): void; + resetBackoff(): void; + deactivate(): void; + maybeReactivate(): void; + cancelFailoverTimer(): void; + isFailoverTimerPending(): boolean; + getConnectivityState(): ConnectivityState; + getPicker(): Picker; + getName(): string; + destroy(): void; +} + +interface UpdateArgs { + subchannelAddress: SubchannelAddress[]; + lbConfig: LoadBalancingConfig; +} + +export class PriorityLoadBalancer implements LoadBalancer { + /** + * Inner class for holding a child priority and managing associated timers. + */ + private PriorityChildImpl = class implements PriorityChildBalancer { + private connectivityState: ConnectivityState = ConnectivityState.IDLE; + private picker: Picker; + private childBalancer: ChildLoadBalancerHandler; + private failoverTimer: NodeJS.Timer | null = null; + private deactivationTimer: NodeJS.Timer | null = null; + constructor(private parent: PriorityLoadBalancer, private name: string) { + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: ( + subchannelAddress: SubchannelAddress, + subchannelArgs: ChannelOptions + ) => { + return this.parent.channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ); + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + this.updateState(connectivityState, picker); + }, + requestReresolution: () => { + this.parent.channelControlHelper.requestReresolution(); + }, + }); + this.picker = new QueuePicker(this.childBalancer); + + this.deactivationTimer = setTimeout(() => {}, 0); + clearTimeout(this.deactivationTimer); + } + + private updateState(connectivityState: ConnectivityState, picker: Picker) { + this.connectivityState = connectivityState; + this.picker = picker; + this.parent.onChildStateChange(this); + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + this.childBalancer.updateAddressList(addressList, lbConfig, attributes); + this.failoverTimer = setTimeout(() => { + this.failoverTimer = null; + this.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker() + ); + }, DEFAULT_FAILOVER_TIME_MS); + } + + exitIdle() { + this.childBalancer.exitIdle(); + } + + resetBackoff() { + this.childBalancer.resetBackoff(); + } + + deactivate() { + if (this.deactivationTimer === null) { + this.deactivationTimer = setTimeout(() => { + this.parent.deleteChild(this); + this.childBalancer.destroy(); + }, DEFAULT_RETENTION_INTERVAL_MS); + } + } + + maybeReactivate() { + if (this.deactivationTimer !== null) { + clearTimeout(this.deactivationTimer); + this.deactivationTimer = null; + } + } + + cancelFailoverTimer() { + if (this.failoverTimer !== null) { + clearTimeout(this.failoverTimer); + this.failoverTimer = null; + } + } + + isFailoverTimerPending() { + return this.failoverTimer !== null; + } + + getConnectivityState() { + return this.connectivityState; + } + + getPicker() { + return this.picker; + } + + getName() { + return this.name; + } + + destroy() { + this.childBalancer.destroy(); + } + }; + // End of inner class PriorityChildImpl + + private children: Map = new Map< + string, + PriorityChildBalancer + >(); + /** + * The priority order of child names from the latest config update. + */ + private priorities: string[] = []; + /** + * The attributes object from the latest update, saved to be passed along to + * each new child as they are created + */ + private latestAttributes: { [key: string]: unknown } = {}; + /** + * The latest load balancing policies and address lists for each child from + * the latest update + */ + private latestUpdates: Map = new Map< + string, + UpdateArgs + >(); + /** + * Current chosen priority that requests are sent to + */ + private currentPriority: number | null = null; + /** + * After an update, this preserves the currently selected child from before + * the update. We continue to use that child until it disconnects, or + * another higher-priority child connects, or it is deleted because it is not + * in the new priority list at all and its retention interval has expired, or + * we try and fail to connect to every child in the new priority list. + */ + private currentChildFromBeforeUpdate: PriorityChildBalancer | null = null; + + constructor(private channelControlHelper: ChannelControlHelper) {} + + private onChildStateChange(child: PriorityChildBalancer) { + const childState = child.getConnectivityState(); + if (child === this.currentChildFromBeforeUpdate) { + if ( + childState === ConnectivityState.READY || + childState === ConnectivityState.IDLE + ) { + this.channelControlHelper.updateState(childState, child.getPicker()); + } else { + this.currentChildFromBeforeUpdate = null; + this.tryNextPriority(true); + } + return; + } + const childPriority = this.priorities.indexOf(child.getName()); + if (childPriority < 0) { + // child is not in the priority list, ignore updates + return; + } + if (this.currentPriority !== null && childPriority > this.currentPriority) { + // child is lower priority than the currently selected child, ignore updates + return; + } + if (childState === ConnectivityState.TRANSIENT_FAILURE) { + /* Report connecting if and only if the currently selected child is the + * one entering TRANSIENT_FAILURE */ + this.tryNextPriority(childPriority === this.currentPriority); + return; + } + if (this.currentPriority === null || childPriority < this.currentPriority) { + /* In this case, either there is no currently selected child or this + * child is higher priority than the currently selected child, so we want + * to switch to it if it is READY or IDLE. */ + if ( + childState === ConnectivityState.READY || + childState === ConnectivityState.IDLE + ) { + this.selectPriority(childPriority); + } + return; + } + /* The currently selected child has updated state to something other than + * TRANSIENT_FAILURE, so we pass that update along */ + this.channelControlHelper.updateState(childState, child.getPicker()); + } + + private deleteChild(child: PriorityChildBalancer) { + if (child === this.currentChildFromBeforeUpdate) { + this.currentChildFromBeforeUpdate = null; + /* If we get to this point, the currentChildFromBeforeUpdate was still in + * use, so we are still trying to connect to the specified priorities */ + this.tryNextPriority(true); + } + } + + /** + * Select the child at the specified priority, and report that child's state + * as this balancer's state until that child disconnects or a higher-priority + * child connects. + * @param priority + */ + private selectPriority(priority: number) { + this.currentPriority = priority; + const chosenChild = this.children.get(this.priorities[priority])!; + this.channelControlHelper.updateState( + chosenChild.getConnectivityState(), + chosenChild.getPicker() + ); + this.currentChildFromBeforeUpdate = null; + // Deactivate each child of lower priority than the chosen child + for (let i = priority + 1; i < this.priorities.length; i++) { + this.children.get(this.priorities[i])?.deactivate(); + } + } + + /** + * Check each child in priority order until we find one to use + * @param reportConnecting Whether we should report a CONNECTING state if we + * stop before picking a specific child. This should be true when we have + * not already selected a child. + */ + private tryNextPriority(reportConnecting: boolean) { + for (const [index, childName] of this.priorities.entries()) { + let child = this.children.get(childName); + /* If the child doesn't already exist, create it and update it. */ + if (child === undefined) { + if (reportConnecting) { + this.channelControlHelper.updateState( + ConnectivityState.CONNECTING, + new QueuePicker(this) + ); + } + child = new this.PriorityChildImpl(this, childName); + this.children.set(childName, child); + const childUpdate = this.latestUpdates.get(childName); + if (childUpdate !== undefined) { + child.updateAddressList( + childUpdate.subchannelAddress, + childUpdate.lbConfig, + this.latestAttributes + ); + } + } + /* We're going to try to use this child, so reactivate it if it has been + * deactivated */ + child.maybeReactivate(); + if ( + child.getConnectivityState() === ConnectivityState.READY || + child.getConnectivityState() === ConnectivityState.IDLE + ) { + this.selectPriority(index); + return; + } + if (child.isFailoverTimerPending()) { + /* This child is still trying to connect. Wait until its failover timer + * has ended to continue to the next one */ + if (reportConnecting) { + this.channelControlHelper.updateState( + ConnectivityState.CONNECTING, + new QueuePicker(this) + ); + } + return; + } + } + this.currentPriority = null; + this.currentChildFromBeforeUpdate = null; + this.channelControlHelper.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: 'No ready priority', + metadata: new Metadata(), + }) + ); + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!isPriorityLoadBalancingConfig(lbConfig)) { + // Reject a config of the wrong type + return; + } + const priorityConfig = lbConfig.priority; + /* For each address, the first element of its localityPath array determines + * which child it belongs to. So we bucket those addresses by that first + * element, and pass along the rest of the localityPath for that child + * to use. */ + const childAddressMap: Map = new Map< + string, + LocalitySubchannelAddress[] + >(); + for (const address of addressList) { + if (!isLocalitySubchannelAddress(address)) { + // Reject address that cannot be prioritized + return; + } + if (address.localityPath.length < 1) { + // Reject address that cannot be prioritized + return; + } + const childName = address.localityPath[0]; + const childAddress: LocalitySubchannelAddress = { + ...address, + localityPath: address.localityPath.slice(1), + }; + let childAddressList = childAddressMap.get(childName); + if (childAddressList === undefined) { + childAddressList = []; + childAddressMap.set(childName, childAddressList); + } + childAddressList.push(childAddress); + } + if (this.currentPriority !== null) { + this.currentChildFromBeforeUpdate = this.children.get( + this.priorities[this.currentPriority] + )!; + this.currentPriority = null; + } + this.latestAttributes = attributes; + this.latestUpdates.clear(); + this.priorities = priorityConfig.priorities; + /* Pair up the new child configs with the corresponding address lists, and + * update all existing children with their new configs */ + for (const [childName, childConfig] of priorityConfig.children.entries()) { + const chosenChildConfig = getFirstUsableConfig(childConfig.config); + if (chosenChildConfig !== null) { + const childAddresses = childAddressMap.get(childName) ?? []; + this.latestUpdates.set(childName, { + subchannelAddress: childAddresses, + lbConfig: chosenChildConfig, + }); + const existingChild = this.children.get(childName); + if (existingChild !== undefined) { + existingChild.updateAddressList( + childAddresses, + chosenChildConfig, + attributes + ); + } + } + } + // Deactivate all children that are no longer in the priority list + for (const [childName, child] of this.children.entries()) { + if (this.priorities.indexOf(childName) < 0) { + child.deactivate(); + } + } + // Only report connecting if there are no existing children + this.tryNextPriority(this.children.size === 0); + } + exitIdle(): void { + if (this.currentPriority !== null) { + this.children.get(this.priorities[this.currentPriority])?.exitIdle(); + } + } + resetBackoff(): void { + for (const child of this.children.values()) { + child.resetBackoff(); + } + } + destroy(): void { + for (const child of this.children.values()) { + child.destroy(); + } + this.children.clear(); + this.currentChildFromBeforeUpdate?.destroy(); + this.currentChildFromBeforeUpdate = null; + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, PriorityLoadBalancer); +} diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index dc4cf4e33..2e91ffc5c 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -22,6 +22,7 @@ import { Picker } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; +import * as load_balancer_priority from './load-balancer-priority'; /** * A collection of functions associated with a channel that a load balancer @@ -137,4 +138,5 @@ export function getFirstUsableConfig( export function registerAll() { load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); + load_balancer_priority.setup(); } From be31009d9a084e7c586a763ae2582dc856f80766 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 21 May 2020 10:04:29 -0700 Subject: [PATCH 1095/1899] Start failover timers when leaving IDLE --- .../grpc-js/src/load-balancer-priority.ts | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts index 94f7f560b..94a4ace76 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -111,22 +111,31 @@ export class PriorityLoadBalancer implements LoadBalancer { this.parent.onChildStateChange(this); } + private startFailoverTimer() { + if (this.failoverTimer === null) { + this.failoverTimer = setTimeout(() => { + this.failoverTimer = null; + this.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker() + ); + }, DEFAULT_FAILOVER_TIME_MS); + } + } + updateAddressList( addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { this.childBalancer.updateAddressList(addressList, lbConfig, attributes); - this.failoverTimer = setTimeout(() => { - this.failoverTimer = null; - this.updateState( - ConnectivityState.TRANSIENT_FAILURE, - new UnavailablePicker() - ); - }, DEFAULT_FAILOVER_TIME_MS); + this.startFailoverTimer(); } exitIdle() { + if (this.connectivityState === ConnectivityState.IDLE) { + this.startFailoverTimer(); + } this.childBalancer.exitIdle(); } @@ -215,6 +224,16 @@ export class PriorityLoadBalancer implements LoadBalancer { constructor(private channelControlHelper: ChannelControlHelper) {} + private updateState(state: ConnectivityState, picker: Picker) { + /* If switching to IDLE, use a QueuePicker attached to this load balancer + * so that when the picker calls exitIdle, that in turn calls exitIdle on + * the PriorityChildImpl, which will start the failover timer. */ + if (state === ConnectivityState.IDLE) { + picker = new QueuePicker(this); + } + this.channelControlHelper.updateState(state, picker); + } + private onChildStateChange(child: PriorityChildBalancer) { const childState = child.getConnectivityState(); if (child === this.currentChildFromBeforeUpdate) { @@ -222,7 +241,7 @@ export class PriorityLoadBalancer implements LoadBalancer { childState === ConnectivityState.READY || childState === ConnectivityState.IDLE ) { - this.channelControlHelper.updateState(childState, child.getPicker()); + this.updateState(childState, child.getPicker()); } else { this.currentChildFromBeforeUpdate = null; this.tryNextPriority(true); @@ -258,7 +277,7 @@ export class PriorityLoadBalancer implements LoadBalancer { } /* The currently selected child has updated state to something other than * TRANSIENT_FAILURE, so we pass that update along */ - this.channelControlHelper.updateState(childState, child.getPicker()); + this.updateState(childState, child.getPicker()); } private deleteChild(child: PriorityChildBalancer) { @@ -279,7 +298,7 @@ export class PriorityLoadBalancer implements LoadBalancer { private selectPriority(priority: number) { this.currentPriority = priority; const chosenChild = this.children.get(this.priorities[priority])!; - this.channelControlHelper.updateState( + this.updateState( chosenChild.getConnectivityState(), chosenChild.getPicker() ); @@ -302,10 +321,7 @@ export class PriorityLoadBalancer implements LoadBalancer { /* If the child doesn't already exist, create it and update it. */ if (child === undefined) { if (reportConnecting) { - this.channelControlHelper.updateState( - ConnectivityState.CONNECTING, - new QueuePicker(this) - ); + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } child = new this.PriorityChildImpl(this, childName); this.children.set(childName, child); @@ -332,17 +348,14 @@ export class PriorityLoadBalancer implements LoadBalancer { /* This child is still trying to connect. Wait until its failover timer * has ended to continue to the next one */ if (reportConnecting) { - this.channelControlHelper.updateState( - ConnectivityState.CONNECTING, - new QueuePicker(this) - ); + this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } return; } } this.currentPriority = null; this.currentChildFromBeforeUpdate = null; - this.channelControlHelper.updateState( + this.updateState( ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({ code: Status.UNAVAILABLE, From c6deb792697ac9971a25c4f4bafe7931bfec215a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 21 May 2020 10:12:08 -0700 Subject: [PATCH 1096/1899] Test header splitting behavior --- packages/grpc-js/test/test-metadata.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/test/test-metadata.ts b/packages/grpc-js/test/test-metadata.ts index a56798ac8..44182ef39 100644 --- a/packages/grpc-js/test/test-metadata.ts +++ b/packages/grpc-js/test/test-metadata.ts @@ -295,6 +295,7 @@ describe('Metadata', () => { key1: 'value1', key2: ['value2'], key3: ['value3a', 'value3b'], + key4: ['part1, part2'], 'key-bin': [ 'AAECAwQFBgcICQoLDA0ODw==', 'EBESExQVFhcYGRobHB0eHw==', @@ -307,6 +308,7 @@ describe('Metadata', () => { ['key1', ['value1']], ['key2', ['value2']], ['key3', ['value3a', 'value3b']], + ['key4', ['part1, part2']], [ 'key-bin', [ From ed5b3ac1cda7c11c1b85ab6db60aad6884e89c25 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 21 May 2020 11:41:44 -0700 Subject: [PATCH 1097/1899] grpc-js: Don't push messages after ending a call --- packages/grpc-js/src/call-stream.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index fcfa8af19..041f9651c 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -289,6 +289,13 @@ export class Http2CallStream implements Call { ); this.canPush = false; process.nextTick(() => { + /* If we have already output the status any later messages should be + * ignored, and can cause out-of-order operation errors higher up in the + * stack. Checking as late as possible here to avoid any race conditions. + */ + if (this.statusOutput) { + return; + } this.listener?.onReceiveMessage(message); this.maybeOutputStatus(); }); From d02cbe432e52ca415eadcb2c83369f3cfdea4ffc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 26 May 2020 10:52:05 -0700 Subject: [PATCH 1098/1899] Move google-auth-library to a peer dependency --- packages/grpc-js/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0212b55f0..11934f12b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -26,6 +26,7 @@ "@types/semver": "^6.0.1", "clang-format": "^1.0.55", "execa": "^2.0.3", + "google-auth-library": "^6.0.0", "gts": "^2.0.0", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", @@ -56,9 +57,11 @@ "posttest": "npm run check" }, "dependencies": { - "google-auth-library": "^6.0.0", "semver": "^6.2.0" }, + "peerDependencies": { + "google-auth-library": "5.x || 6.x" + }, "files": [ "src/*.ts", "build/src/*.{js,d.ts,js.map}", From 2c022924cf28066eea501ff317623d3ce730cb3e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 26 May 2020 15:12:34 -0700 Subject: [PATCH 1099/1899] grpc-js: Properly back off when transitioning through IDLE --- packages/grpc-js/src/subchannel.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index ab7b176ce..b540eb214 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -507,10 +507,6 @@ export class Subchannel { this.stopKeepalivePings(); break; case ConnectivityState.IDLE: - /* Stopping the backoff timer here is probably redundant because we - * should only transition to the IDLE state as a result of the timer - * ending, but we still want to reset the backoff timeout. */ - this.stopBackoff(); if (this.session) { this.session.close(); } From ff36a1de0765d0535a930ff1f82385e16f3dae19 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 27 May 2020 10:21:42 -0700 Subject: [PATCH 1100/1899] grpc-js: transition out of TRANSIENT_FAILURE if backoff timer has ended --- packages/grpc-js/src/subchannel.ts | 34 ++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index ab7b176ce..f56a31d43 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -231,21 +231,25 @@ export class Subchannel { maxDelay: options['grpc.max_reconnect_backoff_ms'], }; this.backoffTimeout = new BackoffTimeout(() => { - if (this.continueConnecting) { - this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE], - ConnectivityState.CONNECTING - ); - } else { - this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE], - ConnectivityState.IDLE - ); - } + this.handleBackoffTimer(); }, backoffOptions); this.subchannelAddressString = subchannelAddressToString(subchannelAddress); } + private handleBackoffTimer() { + if (this.continueConnecting) { + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE], + ConnectivityState.CONNECTING + ); + } else { + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE], + ConnectivityState.IDLE + ); + } + } + /** * Start a backoff timer with the current nextBackoff timeout */ @@ -505,6 +509,14 @@ export class Subchannel { } this.session = null; this.stopKeepalivePings(); + /* If the backoff timer has already ended by the time we get to the + * TRANSIENT_FAILURE state, we want to immediately transition out of + * TRANSIENT_FAILURE as though the backoff timer is ending right now */ + if (!this.backoffTimeout.isRunning()) { + process.nextTick(() => { + this.handleBackoffTimer(); + }); + } break; case ConnectivityState.IDLE: /* Stopping the backoff timer here is probably redundant because we From 807d7d510ff67dcb6f7a9846f58a10b19cfff587 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 28 May 2020 11:48:47 -0700 Subject: [PATCH 1101/1899] grpc-js: Add weighted_target load balancer --- .../src/load-balancer-weighted-target.ts | 327 ++++++++++++++++++ packages/grpc-js/src/load-balancer.ts | 2 + packages/grpc-js/src/load-balancing-config.ts | 23 +- 3 files changed, 351 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js/src/load-balancer-weighted-target.ts diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts new file mode 100644 index 000000000..03d0ec70c --- /dev/null +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -0,0 +1,327 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { LoadBalancer, ChannelControlHelper, getFirstUsableConfig, registerLoadBalancerType } from "./load-balancer"; +import { SubchannelAddress } from "./subchannel"; +import { LoadBalancingConfig, WeightedTarget, isWeightedTargetLoadBalancingConfig } from "./load-balancing-config"; +import { Picker, PickResult, PickArgs, QueuePicker, UnavailablePicker } from "./picker"; +import { ConnectivityState } from "./channel"; +import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; +import { Status } from "./constants"; +import { Metadata } from "./metadata"; + +const TYPE_NAME = 'weighted_target'; + +const DEFAULT_RETENTION_INTERVAL_MS = 15 * 60 * 1000; + +/* These should be imported from load-balancer-priority.ts or factored into + * a separate file */ + +export type LocalitySubchannelAddress = SubchannelAddress & { + localityPath: string[]; +}; + +export function isLocalitySubchannelAddress( + address: SubchannelAddress +): address is LocalitySubchannelAddress { + return Array.isArray((address as LocalitySubchannelAddress).localityPath); +} + +/** + * Represents a picker and a subinterval of a larger interval used for randomly + * selecting an element of a list of these objects. + */ +interface WeightedPicker { + picker: Picker; + /** + * The exclusive end of the interval associated with this element. The start + * of the interval is implicitly the rangeEnd of the previous element in the + * list, or 0 for the first element in the list. + */ + rangeEnd: number; +} + +class WeightedTargetPicker implements Picker { + private rangeTotal: number; + constructor(private readonly pickerList: WeightedPicker[]) { + this.rangeTotal = pickerList[pickerList.length - 1].rangeEnd; + } + pick(pickArgs: PickArgs): PickResult { + // num | 0 is equivalent to floor(num) + const selection = (Math.random() * this.rangeTotal) | 0; + + /* Binary search for the element of the list such that + * pickerList[index - 1].rangeEnd <= selection < pickerList[index].rangeEnd + */ + let mid = 0; + let startIndex = 0; + let endIndex = this.pickerList.length - 1; + let index = 0; + while (endIndex > startIndex) { + mid = ((startIndex + endIndex) / 2) | 0; + if (this.pickerList[mid].rangeEnd > selection) { + endIndex = mid; + } else if (this.pickerList[mid].rangeEnd < selection) { + startIndex = mid + 1; + } else { + // + 1 here because the range is exclusive at the top end + index = mid + 1; + break; + } + } + if (index === 0) { + index = startIndex; + } + + return this.pickerList[index].picker.pick(pickArgs); + } +} + +interface WeightedChild { + updateAddressList(addressList: SubchannelAddress[], lbConfig: WeightedTarget, attributes: { [key: string]: unknown; }): void; + exitIdle(): void; + resetBackoff(): void; + destroy(): void; + deactivate(): void; + maybeReactivate(): void; + getConnectivityState(): ConnectivityState; + getPicker(): Picker; + getWeight(): number; +} + +export class WeightedTargetLoadBalancer implements LoadBalancer { + private WeightedChildImpl = class implements WeightedChild { + private connectivityState: ConnectivityState = ConnectivityState.IDLE; + private picker: Picker; + private childBalancer: ChildLoadBalancerHandler; + private deactivationTimer: NodeJS.Timer | null = null; + private weight: number = 0; + + constructor(private parent: WeightedTargetLoadBalancer, private name: string) { + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddress, subchannelOptions) => { + return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelOptions); + }, + updateState: (connectivityState, picker) => { + this.updateState(connectivityState, picker); + }, + requestReresolution: () => { + this.parent.channelControlHelper.requestReresolution(); + } + }); + + this.picker = new QueuePicker(this.childBalancer); + } + + private updateState(connectivityState: ConnectivityState, picker: Picker) { + this.connectivityState = connectivityState; + this.picker = picker; + this.parent.updateState(); + } + + updateAddressList(addressList: SubchannelAddress[], lbConfig: WeightedTarget, attributes: { [key: string]: unknown; }): void { + this.weight = lbConfig.weight; + const childConfig = getFirstUsableConfig(lbConfig.child_policy); + if (childConfig !== null) { + this.childBalancer.updateAddressList(addressList, childConfig, attributes); + } + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + if (this.deactivationTimer !== null) { + clearTimeout(this.deactivationTimer); + } + } + deactivate(): void { + if (this.deactivationTimer === null) { + this.deactivationTimer = setTimeout(() => { + this.parent.targets.delete(this.name); + this.deactivationTimer = null; + }, DEFAULT_RETENTION_INTERVAL_MS); + } + } + maybeReactivate(): void { + if (this.deactivationTimer !== null) { + clearTimeout(this.deactivationTimer); + this.deactivationTimer = null; + } + } + getConnectivityState(): ConnectivityState { + return this.connectivityState; + } + getPicker(): Picker { + return this.picker; + } + getWeight(): number { + return this.weight; + } + } + // end of WeightedChildImpl + + /** + * Map of target names to target children. Includes current targets and + * previous targets with deactivation timers that have not yet triggered. + */ + private targets: Map = new Map(); + /** + * List of current target names. + */ + private targetList: string[] = []; + + constructor(private channelControlHelper: ChannelControlHelper) {} + + private updateState() { + const pickerList: WeightedPicker[] = []; + let end = 0; + + let connectingCount = 0; + let idleCount = 0; + let transientFailureCount = 0; + for (const targetName of this.targetList) { + const target = this.targets.get(targetName); + if (target === undefined) { + continue; + } + switch (target.getConnectivityState()) { + case ConnectivityState.READY: + end += target.getWeight(); + pickerList.push({ + picker: target.getPicker(), + rangeEnd: end + }); + break; + case ConnectivityState.CONNECTING: + connectingCount += 1; + break; + case ConnectivityState.IDLE: + idleCount += 1; + break; + case ConnectivityState.TRANSIENT_FAILURE: + transientFailureCount += 1; + break; + default: + // Ignore the other possiblity, SHUTDOWN + } + } + + let connectivityState: ConnectivityState; + if (pickerList.length > 0) { + connectivityState = ConnectivityState.READY; + } else if (connectingCount > 0) { + connectivityState = ConnectivityState.CONNECTING; + } else if (idleCount > 0) { + connectivityState = ConnectivityState.IDLE; + } else { + connectivityState = ConnectivityState.TRANSIENT_FAILURE; + } + + let picker: Picker; + switch (connectivityState) { + case ConnectivityState.READY: + picker = new WeightedTargetPicker(pickerList); + break; + case ConnectivityState.CONNECTING: + case ConnectivityState.READY: + picker = new QueuePicker(this); + break; + default: + picker = new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: 'weighted_target: all children report state TRANSIENT_FAILURE', + metadata: new Metadata() + }); + } + this.channelControlHelper.updateState(connectivityState, picker); + } + + updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { + if (!isWeightedTargetLoadBalancingConfig(lbConfig)) { + // Reject a config of the wrong type + return; + } + + /* For each address, the first element of its localityPath array determines + * which child it belongs to. So we bucket those addresses by that first + * element, and pass along the rest of the localityPath for that child + * to use. */ + const childAddressMap = new Map(); + for (const address of addressList) { + if (!isLocalitySubchannelAddress(address)) { + // Reject address that cannot be associated with targets + return; + } + if (address.localityPath.length < 1) { + // Reject address that cannot be associated with targets + return; + } + const childName = address.localityPath[0]; + const childAddress: LocalitySubchannelAddress = { + ...address, + localityPath: address.localityPath.slice(1), + }; + let childAddressList = childAddressMap.get(childName); + if (childAddressList === undefined) { + childAddressList = []; + childAddressMap.set(childName, childAddressList); + } + childAddressList.push(childAddress); + } + + this.targetList = Array.from(lbConfig.weighted_target.targets.keys()); + for (const [targetName, targetConfig] of lbConfig.weighted_target.targets) { + let target = this.targets.get(targetName); + if (target === undefined) { + target = new this.WeightedChildImpl(this, targetName); + this.targets.set(targetName, target); + } else { + target.maybeReactivate(); + } + target.updateAddressList(childAddressMap.get(targetName) ?? [], targetConfig, attributes); + } + + this.updateState(); + } + exitIdle(): void { + for (const targetName of this.targetList) { + this.targets.get(targetName)?.exitIdle(); + } + } + resetBackoff(): void { + for (const targetName of this.targetList) { + this.targets.get(targetName)?.resetBackoff(); + } + } + destroy(): void { + for (const target of this.targets.values()) { + target.destroy(); + } + this.targets.clear(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, WeightedTargetLoadBalancer); +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index dc4cf4e33..9bf50f38a 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -22,6 +22,7 @@ import { Picker } from './picker'; import { LoadBalancingConfig } from './load-balancing-config'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; +import * as load_balancer_weighted_target from './load-balancer-weighted-target'; /** * A collection of functions associated with a channel that a load balancer @@ -137,4 +138,5 @@ export function getFirstUsableConfig( export function registerAll() { load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); + load_balancer_weighted_target.setup(); } diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 0a06d5f88..736e3d42d 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -48,6 +48,15 @@ export interface PriorityLbConfig { priorities: string[]; } +export interface WeightedTarget { + weight: number; + child_policy: LoadBalancingConfig[]; +} + +export interface WeightedTargetLbConfig { + targets: Map; +} + export interface PickFirstLoadBalancingConfig { name: 'pick_first'; pick_first: PickFirstConfig; @@ -73,12 +82,18 @@ export interface PriorityLoadBalancingConfig { priority: PriorityLbConfig; } +export interface WeightedTargetLoadBalancingConfig { + name: 'weighted_target'; + weighted_target: WeightedTargetLbConfig; +} + export type LoadBalancingConfig = | PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig | XdsLoadBalancingConfig | GrpcLbLoadBalancingConfig - | PriorityLoadBalancingConfig; + | PriorityLoadBalancingConfig + | WeightedTargetLoadBalancingConfig; export function isRoundRobinLoadBalancingConfig( lbconfig: LoadBalancingConfig @@ -104,6 +119,12 @@ export function isPriorityLoadBalancingConfig( return lbconfig.name === 'priority'; } +export function isWeightedTargetLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is WeightedTargetLoadBalancingConfig { + return lbconfig.name === 'weighted_target'; +} + /* In these functions we assume the input came from a JSON object. Therefore we * expect that the prototype is uninteresting and that `in` can be used * effectively */ From a61dfb1527d028c6cf14114fe29ff10b3fa20eb4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 28 May 2020 11:52:02 -0700 Subject: [PATCH 1102/1899] Some cleanup and fixes --- packages/grpc-js/src/load-balancer-priority.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts index 94a4ace76..d30707156 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -100,9 +100,6 @@ export class PriorityLoadBalancer implements LoadBalancer { }, }); this.picker = new QueuePicker(this.childBalancer); - - this.deactivationTimer = setTimeout(() => {}, 0); - clearTimeout(this.deactivationTimer); } private updateState(connectivityState: ConnectivityState, picker: Picker) { @@ -415,7 +412,7 @@ export class PriorityLoadBalancer implements LoadBalancer { this.priorities = priorityConfig.priorities; /* Pair up the new child configs with the corresponding address lists, and * update all existing children with their new configs */ - for (const [childName, childConfig] of priorityConfig.children.entries()) { + for (const [childName, childConfig] of priorityConfig.children) { const chosenChildConfig = getFirstUsableConfig(childConfig.config); if (chosenChildConfig !== null) { const childAddresses = childAddressMap.get(childName) ?? []; @@ -434,7 +431,7 @@ export class PriorityLoadBalancer implements LoadBalancer { } } // Deactivate all children that are no longer in the priority list - for (const [childName, child] of this.children.entries()) { + for (const [childName, child] of this.children) { if (this.priorities.indexOf(childName) < 0) { child.deactivate(); } From 4f38f1e92fd08687802f0b59f244576b07eb1d3a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 29 May 2020 12:35:25 -0700 Subject: [PATCH 1103/1899] Deactivate targets that are not in new configs --- packages/grpc-js/src/load-balancer-weighted-target.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts index 03d0ec70c..e9756e6a6 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -299,6 +299,13 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { target.updateAddressList(childAddressMap.get(targetName) ?? [], targetConfig, attributes); } + // Deactivate targets that are not in the new config + for (const [targetName, target] of this.targets) { + if (this.targetList.indexOf(targetName) < 0) { + target.deactivate(); + } + } + this.updateState(); } exitIdle(): void { From d4d4740e97ebfd738517f90e8de8f21c9800656e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 29 May 2020 14:12:45 -0700 Subject: [PATCH 1104/1899] Bump grpc-js to 1.0.5 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0212b55f0..4d81fe9df 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.0.4", + "version": "1.0.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From f7a749da0979efcf9c4f121f80c01390c87519da Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Mon, 1 Jun 2020 21:20:22 +0100 Subject: [PATCH 1105/1899] grpc-js: Add support for grpc.enable_http_proxy channel option --- PACKAGE-COMPARISON.md | 1 + packages/grpc-js/src/channel-options.ts | 2 ++ packages/grpc-js/src/http_proxy.ts | 3 +++ 3 files changed, 6 insertions(+) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 46c28b02a..8bea1fd08 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -43,5 +43,6 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.use_local_subchannel_pool` - `grpc.max_send_message_length` - `grpc.max_receive_message_length` + - `grpc.enable_http_proxy` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 89eb46cf0..8c4756ec7 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -32,6 +32,7 @@ export interface ChannelOptions { 'grpc.use_local_subchannel_pool'?: number; 'grpc.max_send_message_length'?: number; 'grpc.max_receive_message_length'?: number; + 'grpc.enable_http_proxy'?: number; [key: string]: string | number | undefined; } @@ -53,6 +54,7 @@ export const recognizedOptions = { 'grpc.use_local_subchannel_pool': true, 'grpc.max_send_message_length': true, 'grpc.max_receive_message_length': true, + 'grpc.enable_http_proxy': true, }; export function channelOptionsEqual( diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index df9ea09f2..0116145b1 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -125,6 +125,9 @@ export function mapProxyName( target: target, extraOptions: {}, }; + if ((options['grpc.enable_http_proxy'] ?? 1) === 0) { + return noProxyResult; + } const proxyInfo = getProxyInfo(); if (!proxyInfo.address) { return noProxyResult; From 219ca8c5db03d08e1fa5f9db5ba0178e64b2fd44 Mon Sep 17 00:00:00 2001 From: Jonathan Lima Date: Thu, 4 Jun 2020 11:36:51 -0300 Subject: [PATCH 1106/1899] grpc-js: Fix credentials type --- packages/grpc-js/src/index.ts | 93 +++++++++++++++-------------------- 1 file changed, 40 insertions(+), 53 deletions(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 54a407cda..e85268173 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -69,65 +69,52 @@ if (!semver.satisfies(process.version, supportedNodeVersions)) { throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); } -interface IndexedObject { - [key: string]: any; // eslint-disable-line @typescript-eslint/no-explicit-any - [key: number]: any; // eslint-disable-line @typescript-eslint/no-explicit-any -} - -function mixin(...sources: IndexedObject[]) { - const result: { [key: string]: Function } = {}; - for (const source of sources) { - for (const propName of Object.getOwnPropertyNames(source)) { - const property: any = source[propName]; // eslint-disable-line @typescript-eslint/no-explicit-any - if (typeof property === 'function') { - result[propName] = property; - } - } - } - return result; -} - export { OAuth2Client }; /**** Client Credentials ****/ // Using assign only copies enumerable properties, which is what we want -export const credentials = mixin( - { - /** - * Combine a ChannelCredentials with any number of CallCredentials into a - * single ChannelCredentials object. - * @param channelCredentials The ChannelCredentials object. - * @param callCredentials Any number of CallCredentials objects. - * @return The resulting ChannelCredentials object. - */ - combineChannelCredentials: ( - channelCredentials: ChannelCredentials, - ...callCredentials: CallCredentials[] - ): ChannelCredentials => { - return callCredentials.reduce( - (acc, other) => acc.compose(other), - channelCredentials - ); - }, - - /** - * Combine any number of CallCredentials into a single CallCredentials - * object. - * @param first The first CallCredentials object. - * @param additional Any number of additional CallCredentials objects. - * @return The resulting CallCredentials object. - */ - combineCallCredentials: ( - first: CallCredentials, - ...additional: CallCredentials[] - ): CallCredentials => { - return additional.reduce((acc, other) => acc.compose(other), first); - }, +export const credentials = { + /** + * Combine a ChannelCredentials with any number of CallCredentials into a + * single ChannelCredentials object. + * @param channelCredentials The ChannelCredentials object. + * @param callCredentials Any number of CallCredentials objects. + * @return The resulting ChannelCredentials object. + */ + combineChannelCredentials: ( + channelCredentials: ChannelCredentials, + ...callCredentials: CallCredentials[] + ): ChannelCredentials => { + return callCredentials.reduce( + (acc, other) => acc.compose(other), + channelCredentials + ); }, - ChannelCredentials, - CallCredentials -); + + /** + * Combine any number of CallCredentials into a single CallCredentials + * object. + * @param first The first CallCredentials object. + * @param additional Any number of additional CallCredentials objects. + * @return The resulting CallCredentials object. + */ + combineCallCredentials: ( + first: CallCredentials, + ...additional: CallCredentials[] + ): CallCredentials => { + return additional.reduce((acc, other) => acc.compose(other), first); + }, + + // from channel-credentials.ts + createInsecure: ChannelCredentials.createInsecure, + createSsl: ChannelCredentials.createSsl, + + // from call-credentials.ts + createFromMetadataGenerator: CallCredentials.createFromMetadataGenerator, + createFromGoogleCredential: CallCredentials.createFromGoogleCredential, + createEmpty: CallCredentials.createEmpty, +}; /**** Metadata ****/ From 0dca35a8b958f4a2f267994d5289f816eac33e69 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Mon, 8 Jun 2020 20:15:59 +0200 Subject: [PATCH 1107/1899] feat(client): export `ClientOptions` type --- packages/grpc-js/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e85268173..9fc89f2e3 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -31,6 +31,7 @@ import { ChannelCredentials } from './channel-credentials'; import { CallOptions, Client, + ClientOptions, CallInvocationTransformer, CallProperties, UnaryCallback, @@ -133,6 +134,7 @@ export { export { Client, + ClientOptions, loadPackageDefinition, makeClientConstructor, makeClientConstructor as makeGenericClientConstructor, From 6701f19f5e1d16e59202b9dd32b2e5b974f062d6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Jun 2020 14:05:10 -0700 Subject: [PATCH 1108/1899] grpc-js: Consistently set servername connection option to support SNI --- packages/grpc-js/src/subchannel.ts | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 1d48604ad..bda63b6b3 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,7 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; -import { GrpcUri } from './uri-parser'; +import { GrpcUri, parseUri } from './uri-parser'; import { ConnectionOptions } from 'tls'; import { FilterFactory, Filter } from './filter'; @@ -286,6 +286,9 @@ export class Subchannel { } private createSession(proxyConnectionResult: ProxyConnectionResult) { + const targetAuthority = getDefaultAuthority( + proxyConnectionResult.realTarget ?? this.channelTarget + ); let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; let addressScheme = 'http://'; @@ -305,8 +308,16 @@ export class Subchannel { return checkServerIdentity(sslTargetNameOverride, cert); }; connectionOptions.servername = sslTargetNameOverride; + } else { + // We want to always set servername to support SNI + connectionOptions.servername = targetAuthority; } if (proxyConnectionResult.socket) { + /* This is part of the workaround for + * https://github.com/nodejs/node/issues/32922. Without that bug, + * proxyConnectionResult.socket would always be a plaintext socket and + * this would say + * connectionOptions.socket = proxyConnectionResult.socket; */ connectionOptions.createConnection = (authority, option) => { return proxyConnectionResult.socket!; }; @@ -350,10 +361,7 @@ export class Subchannel { * determines whether the connection will be established over TLS or not. */ const session = http2.connect( - addressScheme + - getDefaultAuthority( - proxyConnectionResult.realTarget ?? this.channelTarget - ), + addressScheme + targetAuthority, connectionOptions ); this.session = session; @@ -446,6 +454,18 @@ export class Subchannel { return checkServerIdentity(sslTargetNameOverride, cert); }; connectionOptions.servername = sslTargetNameOverride; + } else { + if ('grpc.http_connect_target' in this.options) { + /* This is more or less how servername will be set in createSession + * if a connection is successfully established through the proxy. + * If the proxy is not used, these connectionOptions are discarded + * anyway */ + connectionOptions.servername = getDefaultAuthority( + parseUri(this.options['grpc.http_connect_target'] as string) ?? { + path: 'localhost', + } + ); + } } } From e3a50ff3ee180c5dda8448d4a31c1f6bd4a2030e Mon Sep 17 00:00:00 2001 From: azban Date: Sat, 6 Jun 2020 14:36:00 -0700 Subject: [PATCH 1109/1899] grpc-js: use lazy singleton for server call deadline to avoid open handles in jest --- packages/grpc-js/src/server-call.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index d5e5f822f..82d885173 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -341,15 +341,13 @@ export type Handler = export type HandlerType = 'bidi' | 'clientStream' | 'serverStream' | 'unary'; -const noopTimer: NodeJS.Timer = setTimeout(() => {}, 0); - // Internal class that wraps the HTTP2 request. export class Http2ServerCallStream< RequestType, ResponseType > extends EventEmitter { cancelled = false; - deadline: NodeJS.Timer = noopTimer; + deadline: NodeJS.Timer = setTimeout(() => {}, 0); private wantTrailers = false; private metadataSent = false; private canPush = false; @@ -389,6 +387,9 @@ export class Http2ServerCallStream< if ('grpc.max_receive_message_length' in options) { this.maxReceiveMessageSize = options['grpc.max_receive_message_length']!; } + + // Clear noop timer + clearTimeout(this.deadline); } private checkCancelled(): boolean { From cb9f96126f2c8f720498a2488af991569a7655a0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Jun 2020 14:44:14 -0700 Subject: [PATCH 1110/1899] grpc-js: server: cull closed sessions from list, check for closed in tryShutdown --- packages/grpc-js/src/server.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index a6edee3ba..22fb3c723 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -500,10 +500,12 @@ export class Server { } } - // If any sessions are active, close them gracefully. pendingChecks += this.sessions.size; this.sessions.forEach((session) => { - session.close(maybeCallback); + if (!session.closed) { + pendingChecks += 1; + session.close(maybeCallback); + } }); if (pendingChecks === 0) { callback(); @@ -608,6 +610,10 @@ export class Server { } this.sessions.add(session); + + session.on('close', () => { + this.sessions.delete(session); + }); }); } } From d9b7b098a7eb3989a23c6782f327230f566cd57f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Jun 2020 16:36:12 -0700 Subject: [PATCH 1111/1899] grpc-js: Export propagate constants for type parity with grpc --- packages/grpc-js/src/constants.ts | 14 +++++++++++++- packages/grpc-js/src/index.ts | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index 55d934038..e760658d0 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -41,8 +41,20 @@ export enum LogVerbosity { ERROR, } +/** + * NOTE: This enum is not currently used in any implemented API in this + * library. It is included only for type parity with the other implementation. + */ +export enum Propagate { + DEADLINE = 1, + CENSUS_STATS_CONTEXT = 2, + CENSUS_TRACING_CONTEXT = 4, + CANCELLATION = 8, + DEFAULTS = 65536, +} + // -1 means unlimited export const DEFAULT_MAX_SEND_MESSAGE_LENGTH = -1; // 4 MB default -export const DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH = 4 * 1024 * 1024; \ No newline at end of file +export const DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH = 4 * 1024 * 1024; diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 9fc89f2e3..f79a369bd 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -36,7 +36,7 @@ import { CallProperties, UnaryCallback, } from './client'; -import { LogVerbosity, Status } from './constants'; +import { LogVerbosity, Status, Propagate } from './constants'; import * as logging from './logging'; import { Deserialize, @@ -127,6 +127,7 @@ export { LogVerbosity as logVerbosity, Status as status, ConnectivityState as connectivityState, + Propagate as propagate, // TODO: Other constants as well }; From 668b5aeb5a9505267b471ca7712d6ab344f7671a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Jun 2020 10:40:53 -0700 Subject: [PATCH 1112/1899] Consolidate LocalitySubchannelAddress definitions --- .../grpc-js/src/load-balancer-weighted-target.ts | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts index e9756e6a6..041459140 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -23,24 +23,12 @@ import { ConnectivityState } from "./channel"; import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; import { Status } from "./constants"; import { Metadata } from "./metadata"; +import { isLocalitySubchannelAddress, LocalitySubchannelAddress } from "./load-balancer-priority"; const TYPE_NAME = 'weighted_target'; const DEFAULT_RETENTION_INTERVAL_MS = 15 * 60 * 1000; -/* These should be imported from load-balancer-priority.ts or factored into - * a separate file */ - -export type LocalitySubchannelAddress = SubchannelAddress & { - localityPath: string[]; -}; - -export function isLocalitySubchannelAddress( - address: SubchannelAddress -): address is LocalitySubchannelAddress { - return Array.isArray((address as LocalitySubchannelAddress).localityPath); -} - /** * Represents a picker and a subinterval of a larger interval used for randomly * selecting an element of a list of these objects. From f4853c13f7efe7a543c9242b3cbb555e30114960 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Jun 2020 11:07:20 -0700 Subject: [PATCH 1113/1899] Don't double count sessions when closing --- packages/grpc-js/src/server.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 22fb3c723..ebd4504d7 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -500,7 +500,6 @@ export class Server { } } - pendingChecks += this.sessions.size; this.sessions.forEach((session) => { if (!session.closed) { pendingChecks += 1; From 353a6e9714a27a9cc249fc2e45ff5f6f6ac9c0d9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Jun 2020 13:30:02 -0700 Subject: [PATCH 1114/1899] Add dependencies for xDS Client --- .gitmodules | 6 ++++++ packages/grpc-js/deps/envoy-api | 1 + packages/grpc-js/deps/udpa | 1 + packages/grpc-js/package.json | 6 ++++-- 4 files changed, 12 insertions(+), 2 deletions(-) create mode 160000 packages/grpc-js/deps/envoy-api create mode 160000 packages/grpc-js/deps/udpa diff --git a/.gitmodules b/.gitmodules index c17c34644..0d99efd55 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "packages/grpc-tools/deps/protobuf"] path = packages/grpc-tools/deps/protobuf url = https://github.com/protocolbuffers/protobuf +[submodule "packages/grpc-js/deps/envoy-api"] + path = packages/grpc-js/deps/envoy-api + url = https://github.com/envoyproxy/data-plane-api.git +[submodule "packages/grpc-js/deps/udpa"] + path = packages/grpc-js/deps/udpa + url = https://github.com/cncf/udpa.git diff --git a/packages/grpc-js/deps/envoy-api b/packages/grpc-js/deps/envoy-api new file mode 160000 index 000000000..50cef8fca --- /dev/null +++ b/packages/grpc-js/deps/envoy-api @@ -0,0 +1 @@ +Subproject commit 50cef8fcab37ba59a61068934d08a3f4c28a681f diff --git a/packages/grpc-js/deps/udpa b/packages/grpc-js/deps/udpa new file mode 160000 index 000000000..3b31d022a --- /dev/null +++ b/packages/grpc-js/deps/udpa @@ -0,0 +1 @@ +Subproject commit 3b31d022a144b334eb2224838e4d6952ab5253aa diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3d17f9a3d..86243b30c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.5.0", + "@grpc/proto-loader": "^0.5.4", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -65,6 +65,8 @@ "files": [ "src/*.ts", "build/src/*.{js,d.ts,js.map}", - "LICENSE" + "LICENSE", + "deps/envoy-api/envoy/**/*.proto", + "deps/udpa/udpa/**/*.proto" ] } From da3fefb58e85f88fe5131875e5b82222bb3fcc69 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Jun 2020 10:21:10 -0700 Subject: [PATCH 1115/1899] proto-loader: Add TypeScript generator --- .../bin/proto-loader-gen-types.ts | 587 ++++++++++++++++++ packages/proto-loader/package.json | 19 +- packages/proto-loader/src/index.ts | 2 + packages/proto-loader/tsconfig.json | 5 +- 4 files changed, 608 insertions(+), 5 deletions(-) create mode 100644 packages/proto-loader/bin/proto-loader-gen-types.ts diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts new file mode 100644 index 000000000..1de198c50 --- /dev/null +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -0,0 +1,587 @@ +#!/usr/bin/env node +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; +import * as path from 'path'; + +import * as mkdirp from 'mkdirp'; +import * as Protobuf from 'protobufjs'; +import * as yargs from 'yargs'; + +import camelCase = require('lodash.camelcase'); + +type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { + includeDirs?: string[]; + grpcLib: string; + outDir: string; +} + +class TextFormatter { + private readonly indentText = ' '; + private indentValue = 0; + private textParts: string[] = []; + constructor() {} + + indent() { + this.indentValue += 1; + } + + unindent() { + this.indentValue -= 1; + } + + writeLine(line: string) { + for (let i = 0; i < this.indentValue; i+=1) { + this.textParts.push(this.indentText); + } + this.textParts.push(line); + this.textParts.push('\n'); + } + + getFullText() { + return this.textParts.join(''); + } +} + +function isNamespaceBase(obj: Protobuf.ReflectionObject): obj is Protobuf.NamespaceBase { + return Array.isArray((obj as Protobuf.NamespaceBase).nestedArray); +} + +function stripLeadingPeriod(name: string) { + return name.startsWith('.') ? name.substring(1) : name; +} + +function getImportPath(to: Protobuf.Type | Protobuf.Enum) { + return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); +} + +function getPath(to: Protobuf.Type | Protobuf.Enum) { + return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.d.ts'; +} + +function getRelativeImportPath(from: Protobuf.Type, to: Protobuf.Type | Protobuf.Enum) { + const depth = stripLeadingPeriod(from.fullName).split('.').length - 1; + let path = ''; + for (let i = 0; i < depth; i++) { + path += '../'; + } + return path + getImportPath(to); +} + +function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum) { + return type.fullName.replace(/\./g, '_'); +} + +function getImportLine(dependency: Protobuf.Type | Protobuf.Enum, from?: Protobuf.Type) { + const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); + const typeInterfaceName = getTypeInterfaceName(dependency); + const importedTypes = dependency instanceof Protobuf.Type ? `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output` : `${dependency.name} as ${typeInterfaceName}`; + return `import { ${importedTypes} } from '${filePath}';` +} + +function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type) { + formatter.writeLine(`export interface ${messageType.name} {`); + formatter.indent(); + for (const field of messageType.fieldsArray) { + const repeatedString = field.repeated ? '[]' : ''; + let type: string; + switch (field.type) { + case 'double': + case 'float': + case 'int32': + case 'uint32': + case 'sint32': + case 'fixed32': + case 'sfixed32': + type = 'number'; + break; + case 'int64': + case 'uint64': + case 'sint64': + case 'fixed64': + case 'sfixed64': + type = 'number | string | Long'; + break; + case 'bool': + type = 'boolean'; + break; + case 'string': + type = 'string'; + break; + case 'bytes': + type = 'Buffer | UInt8Array | String'; + break; + default: + if (field.resolvedType === null) { + throw new Error('Found field with no usable type'); + } + const typeInterfaceName = getTypeInterfaceName(field.resolvedType); + if (field.resolvedType instanceof Protobuf.Type) { + type = typeInterfaceName; + } else { + type = `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; + } + } + formatter.writeLine(`${field.name}?: (${type})${repeatedString};`); + } + for (const oneof of messageType.oneofsArray) { + const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); + formatter.writeLine(`${oneof.name}?: ${typeString};`); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions) { + formatter.writeLine(`export interface ${messageType.name}__Output {`); + formatter.indent(); + for (const field of messageType.fieldsArray) { + const repeatedString = field.repeated ? '[]' : ''; + let fieldGuaranteed = options.defaults || (field.repeated && options.arrays); + let type: string; + switch (field.type) { + case 'double': + case 'float': + case 'int32': + case 'uint32': + case 'sint32': + case 'fixed32': + case 'sfixed32': + type = 'number'; + break; + case 'int64': + case 'uint64': + case 'sint64': + case 'fixed64': + case 'sfixed64': + if (options.longs === Number) { + type = 'number'; + } else if (options.longs === String) { + type = 'string'; + } else { + type = 'Long'; + } + break; + case 'bool': + type = 'boolean'; + break; + case 'string': + type = 'string'; + break; + case 'bytes': + if (options.bytes === Array) { + type = 'Uint8Array'; + } else if (options.bytes === String) { + type = 'String'; + } else { + type = 'Buffer'; + } + break; + default: + if (field.resolvedType === null) { + throw new Error('Found field with no usable type'); + } + const typeInterfaceName = getTypeInterfaceName(field.resolvedType); + if (field.resolvedType instanceof Protobuf.Type) { + fieldGuaranteed = fieldGuaranteed || options.objects; + type = typeInterfaceName + '__Output'; + } else { + if (options.enums == String) { + type = `keyof typeof ${typeInterfaceName}`; + } else { + type = typeInterfaceName; + } + } + } + if (field.partOf) { + fieldGuaranteed = false; + } + const optionalString = fieldGuaranteed ? '' : '?'; + formatter.writeLine(`${field.name}${optionalString}: (${type})${repeatedString};`); + } + if (options.oneofs) { + for (const oneof of messageType.oneofsArray) { + const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); + formatter.writeLine(`${oneof.name}: ${typeString};`); + } + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateMessageInterfaces(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions) { + let usesLong: boolean = false; + let seenDeps: Set = new Set(); + for (const field of messageType.fieldsArray) { + if (field.resolvedType) { + const dependency = field.resolvedType; + if (seenDeps.has(dependency.fullName)) { + continue; + } + seenDeps.add(dependency.fullName); + formatter.writeLine(getImportLine(dependency, messageType)); + } + if (field.type.indexOf('64') >= 0) { + usesLong = true; + } + } + if (usesLong) { + formatter.writeLine("import { Long } from '@grpc/proto-loader';"); + } + formatter.writeLine(''); + + generatePermissiveMessageInterface(formatter, messageType); + formatter.writeLine(''); + generateRestrictedMessageInterface(formatter, messageType, options); +} + +function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum) { + formatter.writeLine(`export enum ${enumType.name} {`); + formatter.indent(); + for (const key of Object.keys(enumType.values)) { + formatter.writeLine(`${key} = ${enumType.values[key]},`); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateMessageAndEnumImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { + for (const nested of namespace.nestedArray) { + if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { + formatter.writeLine(getImportLine(nested)); + } + if (isNamespaceBase(nested)) { + generateMessageAndEnumImports(formatter, nested); + } + } +} + +function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { + formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); + formatter.indent(); + for (const nested of namespace.nestedArray) { + if (nested instanceof Protobuf.Enum || nested instanceof Protobuf.Type) { + formatter.writeLine(`export type ${nested.name} = ${getTypeInterfaceName(nested)};`); + if (nested instanceof Protobuf.Type) { + formatter.writeLine(`export type ${nested.name}__Output = ${getTypeInterfaceName(nested)}__Output;`); + } + } else if (isNamespaceBase(nested)) { + generateMessageAndEnumExports(formatter, nested); + } + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { + formatter.writeLine(`interface ${serviceType.name}Client extends grpc.Client {`); + formatter.indent(); + for (const methodName of Object.keys(serviceType.methods)) { + const method = serviceType.methods[methodName]; + for (const name of [methodName, camelCase(methodName)]) { + const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName); + const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName) + '__Output'; + const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; + if (method.requestStream) { + if (method.responseStream) { + // Bidi streaming + const callType = `grpc.ClientDuplexStream<${requestType}, ${responseType}>`; + formatter.writeLine(`${name}(metadata: grpc.Metadata, options?: grpc.CallOptions): ${callType};`); + formatter.writeLine(`${name}(options?: grpc.CallOptions): ${callType};`); + } else { + // Client streaming + const callType = `grpc.ClientWritableStream<${responseType}>`; + formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + } + } else { + if (method.responseStream) { + // Server streaming + const callType = `grpc.ClientReadableStream<${responseType}>`; + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options?: grpc.CallOptions): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, options?: grpc.CallOptions): ${callType};`); + } else { + // Unary + const callType = 'grpc.ClientUnaryCall'; + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + } + } + } + formatter.writeLine(''); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { + for (const nested of namespace.nestedArray) { + if (nested instanceof Protobuf.Service) { + generateServiceClientInterface(formatter, nested); + } else if (isNamespaceBase(nested)) { + generateAllServiceClientInterfaces(formatter, nested); + } + } +} + +function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject) { + if (nested instanceof Protobuf.Service) { + formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) + } else if (nested instanceof Protobuf.Enum) { + formatter.writeLine(`${nested.name}: EnumTypeDefinition`); + } else if (nested instanceof Protobuf.Type) { + formatter.writeLine(`${nested.name}: MessageTypeDefinition`); + } else if (isNamespaceBase(nested)) { + generateLoadedDefinitionTypes(formatter, nested); + } +} + +function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { + formatter.writeLine(`${namespace.name}: {`); + formatter.indent(); + for (const nested of namespace.nestedArray) { + generateSingleLoadedDefinitionType(formatter, nested); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { + formatter.writeLine(`export interface ${serviceType.name} {`); + formatter.indent(); + for (const methodName of Object.keys(serviceType.methods)) { + const method = serviceType.methods[methodName]; + const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName) + '__Output'; + const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName); + if (method.requestStream) { + if (method.responseStream) { + // Bidi streaming + formatter.writeLine(`${methodName}(call: grpc.ServerDuplexStream<${requestType}, ${responseType}>): void;`); + } else { + // Client streaming + formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}>, callback: grpc.SendUnaryData<${responseType}>): void;`); + } + } else { + if (method.responseStream) { + // Server streaming + formatter.writeLine(`${methodName}(call: grpc.ServerWriteableStream<${requestType}, ${responseType}>): void;`); + } else { + // Unary + formatter.writeLine(`${methodName}(call: grpc.ServerUnaryCall<${requestType}>, callback: grpc.SendUnaryData<${responseType}>): void;`); + } + } + formatter.writeLine(''); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateAllServiceHandlerInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { + formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); + formatter.indent(); + for (const nested of namespace.nestedArray) { + if (nested instanceof Protobuf.Service) { + generateServiceHandlerInterface(formatter, nested); + } else if (isNamespaceBase(nested)) { + generateAllServiceHandlerInterfaces(formatter, nested); + } + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateMasterFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { + formatter.writeLine(`import * as grpc from '${options.grpcLib}';`); + formatter.writeLine("import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); + formatter.writeLine(''); + + generateMessageAndEnumImports(formatter, root); + formatter.writeLine(''); + + generateMessageAndEnumExports(formatter, root, 'messages'); + formatter.writeLine(''); + + generateAllServiceClientInterfaces(formatter, root); + formatter.writeLine(''); + + formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); + formatter.writeLine('type SubtypeConstructor = {'); + formatter.writeLine(' new(args: ConstructorArguments): Subtype;'); + formatter.writeLine('}'); + formatter.writeLine(''); + + formatter.writeLine('export interface ProtoGrpcType {'); + formatter.indent(); + for (const nested of root.nestedArray) { + generateSingleLoadedDefinitionType(formatter, nested); + } + formatter.unindent(); + formatter.writeLine('}'); + formatter.writeLine(''); + + generateAllServiceHandlerInterfaces(formatter, root, 'ServiceHandlers'); +} + +function writeFile(filename: string, contents: string): Promise { + return mkdirp(path.dirname(filename)).then( + () => fs.promises.writeFile(filename, contents) + ); +} + +function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: GeneratorOptions): Promise[] { + const filePromises : Promise[] = []; + for (const nested of namespace.nestedArray) { + const fileFormatter = new TextFormatter(); + if (nested instanceof Protobuf.Type) { + generateMessageInterfaces(fileFormatter, nested, options); + console.log(`Writing ${options.outDir}/${getPath(nested)}`); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + } else if (nested instanceof Protobuf.Enum) { + generateEnumInterface(fileFormatter, nested); + console.log(`Writing ${options.outDir}/${getPath(nested)}`); + filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + } + if (isNamespaceBase(nested)) { + filePromises.push(...generateFilesForNamespace(nested, options)); + } + } + return filePromises; +} + +function writeFilesForRoot(root: Protobuf.Root, masterFileName: string, options: GeneratorOptions): Promise[] { + const filePromises: Promise[] = []; + + const masterFileFormatter = new TextFormatter(); + generateMasterFile(masterFileFormatter, root, options); + console.log(`Writing ${options.outDir}/${masterFileName}`); + filePromises.push(writeFile(`${options.outDir}/${masterFileName}`, masterFileFormatter.getFullText())); + + filePromises.push(...generateFilesForNamespace(root, options)); + + return filePromises; +} + +function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { + const originalResolvePath = root.resolvePath; + root.resolvePath = (origin: string, target: string) => { + if (path.isAbsolute(target)) { + return target; + } + for (const directory of includePaths) { + const fullPath: string = path.join(directory, target); + try { + fs.accessSync(fullPath, fs.constants.R_OK); + return fullPath; + } catch (err) { + continue; + } + } + process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); + return originalResolvePath(origin, target); + }; +} + +async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { + await mkdirp(options.outDir); + for (const filename of protoFiles) { + console.log(`Processing ${filename}`); + const root: Protobuf.Root = new Protobuf.Root(); + options = options || {}; + if (!!options.includeDirs) { + if (!Array.isArray(options.includeDirs)) { + throw new Error('The includeDirs option must be an array'); + } + addIncludePathResolver(root, options.includeDirs as string[]); + } + const loadedRoot = await root.load(filename, options); + root.resolveAll(); + writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.d.ts'), options); + } +} + +function runScript() { + const argv = yargs + .string(['includeDirs', 'grpcLib']) + .normalize(['includeDirs', 'outDir']) + .array('includeDirs') + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs']) +// .choices('longs', ['String', 'Number']) +// .choices('enums', ['String']) +// .choices('bytes', ['Array', 'String']) + .string(['longs', 'enums', 'bytes']) + .middleware(argv => { + if (argv.longs) { + switch (argv.longs) { + case 'String': argv.longsArg = String; + } + } + }) + .coerce('longs', value => { + switch (value) { + case 'String': return String; + case 'Number': return Number; + default: return undefined; + } + }).coerce('enums', value => { + if (value === 'String') { + return String; + } else { + return undefined; + } + }).coerce('bytes', value => { + switch (value) { + case 'Array': return Array; + case 'String': return String; + default: return undefined; + } + }).alias({ + includeDirs: 'I', + outDir: 'O' + }).describe({ + keepCase: 'Preserve the case of field names', + longs: 'The type that should be used to output 64 bit integer values', + enums: 'The type that should be used to output enum fields', + bytes: 'The type that should be used to output bytes fields', + defaults: 'Output default values for omitted fields', + arrays: 'Output default values for omitted repeated fields even if --defaults is not set', + objects: 'Output default values for omitted message fields even if --defaults is not set', + oneofs: 'Output virtual oneof fields set to the present field\'s name', + includeDirs: 'Directories to search for included files', + outDir: 'Directory in which to output files', + grpcLib: 'The gRPC implementation library that these types will be used with' + }).demandOption(['outDir', 'grpcLib']) + .demand(1) + .usage('$0 [options] filenames...') + .epilogue('WARNING: This tool is in alpha. The CLI and generated code are subject to change') + .argv; + console.log(argv); + writeAllFiles(argv._, argv).then(() => { + console.log('Success'); + }, (error) => { + throw error; + }) +} + +if (require.main === module) { + runScript(); +} \ No newline at end of file diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 022eb41c3..423769919 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -36,19 +36,30 @@ "files": [ "LICENSE", "build/src/*.d.ts", - "build/src/*.js" + "build/src/*.js", + "build/bin/*.js" ], + "bin": { + "proto-loader-gen-types": "./build/bin/proto-loader-gen-types.js" + }, "dependencies": { + "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "protobufjs": "^6.8.6" + "long": "^4.0.0", + "mkdirp": "^1.0.4", + "protobufjs": "^6.8.6", + "yargs": "^15.3.1" }, "devDependencies": { "@types/lodash.camelcase": "^4.3.4", - "@types/node": "^10.12.5", + "@types/mkdirp": "^1.0.1", + "@types/mocha": "^7.0.2", + "@types/node": "^10.17.26", + "@types/yargs": "^15.0.5", "clang-format": "^1.2.2", "gts": "^1.1.0", "rimraf": "^3.0.2", - "typescript": "~3.3.3333" + "typescript": "~3.8.3" }, "engines": { "node": ">=6" diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index b29e26f33..45b6f150a 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -20,6 +20,8 @@ import * as path from 'path'; import * as Protobuf from 'protobufjs'; import * as descriptor from 'protobufjs/ext/descriptor'; +export { Long } from 'long'; + import camelCase = require('lodash.camelcase'); declare module 'protobufjs' { diff --git a/packages/proto-loader/tsconfig.json b/packages/proto-loader/tsconfig.json index d1646f011..e46980866 100644 --- a/packages/proto-loader/tsconfig.json +++ b/packages/proto-loader/tsconfig.json @@ -2,9 +2,12 @@ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "lib": ["es2017"], + "target": "es2017" }, "include": [ + "bin/**/*.ts", "src/**/*.ts", "test/**/*.ts" ] From 3d369e9f564ddf1744fb61db9f7ef59ef96774bd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Jun 2020 10:58:42 -0700 Subject: [PATCH 1116/1899] Update to prerelease version, fix copyright date --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- packages/proto-loader/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 1de198c50..4b11cc300 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -1,7 +1,7 @@ #!/usr/bin/env node /** * @license - * Copyright 2018 gRPC authors. + * Copyright 2020 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 423769919..849e01469 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.4", + "version": "0.6.0-pre1", "author": "Google Inc.", "contributors": [ { From 8bfa472df0f748997e5dfebfe0157a68e3da2f35 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Jun 2020 11:22:07 -0700 Subject: [PATCH 1117/1899] Fix a couple of type name errors --- packages/proto-loader/bin/proto-loader-gen-types.ts | 4 ++-- packages/proto-loader/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 4b11cc300..0f3b82e87 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -125,7 +125,7 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp type = 'string'; break; case 'bytes': - type = 'Buffer | UInt8Array | String'; + type = 'Buffer | Uint8Array | string'; break; default: if (field.resolvedType === null) { @@ -188,7 +188,7 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp if (options.bytes === Array) { type = 'Uint8Array'; } else if (options.bytes === String) { - type = 'String'; + type = 'string'; } else { type = 'Buffer'; } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 849e01469..2bf93d42a 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre1", + "version": "0.6.0-pre2", "author": "Google Inc.", "contributors": [ { From e8f7fb5cbd6dfc08393e87e1aba4223e544762e4 Mon Sep 17 00:00:00 2001 From: Ben Sykes Date: Mon, 15 Jun 2020 09:18:44 -0700 Subject: [PATCH 1118/1899] Update node-pre-gyp to pickup fix for #1362 node-pre-gyp 0.12.0 uses needle 2.4.1 which has the bug in it. Even with grpc 1.24.3, which refers to the updated version, it seems npm can decide to use the older version referenced by this package. --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index c7bb27945..67f6af4d0 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -24,7 +24,7 @@ "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, "dependencies": { - "node-pre-gyp": "^0.12.0" + "node-pre-gyp": "^0.15.0" }, "binary": { "module_name": "grpc_tools", From 01dbc34eb1ed96438c6d30236c6341aae1d0e708 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Jun 2020 11:30:51 -0700 Subject: [PATCH 1119/1899] grpc-js: Add port to :authority, leave it out of service_url --- packages/grpc-js/src/call-credentials-filter.ts | 4 +++- packages/grpc-js/src/resolver-dns.ts | 7 +------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index d39af832b..a5459b533 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -20,6 +20,7 @@ import { Channel } from './channel'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; import { Status } from './constants'; +import { splitHostPort } from './uri-parser'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; @@ -38,9 +39,10 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { if (splitPath.length >= 2) { serviceName = splitPath[1]; } + const hostname = splitHostPort(stream.getHost()).host; /* Currently, call credentials are only allowed on HTTPS connections, so we * can assume that the scheme is "https" */ - this.serviceUrl = `https://${stream.getHost()}/${serviceName}`; + this.serviceUrl = `https://${hostname}/${serviceName}`; } async sendMetadata(metadata: Promise): Promise { diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 016f3bd1a..8a7f4f229 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -269,12 +269,7 @@ class DnsResolver implements Resolver { * @param target */ static getDefaultAuthority(target: GrpcUri): string { - const hostPort = splitHostPort(target.path); - if (hostPort !== null) { - return hostPort.host; - } else { - throw new Error(`Failed to parse target ${uriToString(target)}`); - } + return target.path; } } From f97e27f0c05f325d18d86115d3998cc3755bc7df Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Jun 2020 11:40:22 -0700 Subject: [PATCH 1120/1899] Fix possible null reference --- packages/grpc-js/src/call-credentials-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index a5459b533..5263d97f2 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -39,7 +39,7 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { if (splitPath.length >= 2) { serviceName = splitPath[1]; } - const hostname = splitHostPort(stream.getHost()).host; + const hostname = splitHostPort(stream.getHost())?.host ?? 'localhost'; /* Currently, call credentials are only allowed on HTTPS connections, so we * can assume that the scheme is "https" */ this.serviceUrl = `https://${hostname}/${serviceName}`; From ece7d0f56d91903fcf935cdc64eecb5ff5ce11df Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Jun 2020 13:36:20 -0700 Subject: [PATCH 1121/1899] grpc-js: Don't initiate a read after receiving a message --- packages/grpc-js/src/client.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 8ebb2537f..5f78ffe59 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -558,9 +558,7 @@ export class Client { }, // eslint-disable-next-line @typescript-eslint/no-explicit-any onReceiveMessage(message: any) { - if (stream.push(message)) { - call.startRead(); - } + stream.push(message); }, onReceiveStatus(status: StatusObject) { if (receivedStatus) { @@ -656,9 +654,7 @@ export class Client { stream.emit('metadata', metadata); }, onReceiveMessage(message: Buffer) { - if (stream.push(message)) { - call.startRead(); - } + stream.push(message) }, onReceiveStatus(status: StatusObject) { if (receivedStatus) { From b825055163aabe7658a5f4436f2cda369ce30c57 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Jun 2020 13:45:09 -0700 Subject: [PATCH 1122/1899] Add test for long stream --- test/api/interop_extra_test.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index b798f1a62..d97340bf7 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -144,6 +144,28 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done(); }); }); + it('should receive all messages in a long stream', function() { + var arg = { + response_type: 'COMPRESSABLE', + response_parameters: [ + ] + }; + for (let i = 0; i < 100_000; i++) { + arg.response_parameters.push({size: 0}); + } + var call = client.streamingOutputCall(arg); + let responseCount = 0; + call.on('data', (value) => { + responseCount++; + }); + call.on('end', () => { + assert.strictEqual(responseCount, arg.response_parameters.length); + done(); + }); + call.on('status', function(status) { + assert.strictEqual(status.code, grpc.status.OK); + }); + }); describe('max message size', function() { // A size that is larger than the default limit const largeMessageSize = 8 * 1024 * 1024; From 8a4a9b3235a0dcab241bf35bb53ef64820b89f60 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Jun 2020 14:05:58 -0700 Subject: [PATCH 1123/1899] Underscore in numbers is too new for some Node versions --- test/api/interop_extra_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index d97340bf7..1f31fb410 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -150,7 +150,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio response_parameters: [ ] }; - for (let i = 0; i < 100_000; i++) { + for (let i = 0; i < 100000; i++) { arg.response_parameters.push({size: 0}); } var call = client.streamingOutputCall(arg); From 68bc74d0bd11d90bde1a8fff72d411aed699bbad Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Jun 2020 15:02:08 -0700 Subject: [PATCH 1124/1899] Rearrange new test slightly --- test/api/interop_extra_test.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 1f31fb410..427c93f50 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -158,12 +158,13 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio call.on('data', (value) => { responseCount++; }); - call.on('end', () => { + call.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.OK); assert.strictEqual(responseCount, arg.response_parameters.length); done(); }); - call.on('status', function(status) { - assert.strictEqual(status.code, grpc.status.OK); + call.on('error', (error) => { + assert.ifError(error); }); }); describe('max message size', function() { From f50ed7c2236ccadc36ae699b1a00b99de0fe6d38 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Jun 2020 09:33:16 -0700 Subject: [PATCH 1125/1899] Make the new test actually pass --- test/api/interop_extra_test.js | 5 +++-- test/interop/async_delay_queue.js | 8 ++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 427c93f50..f94b07527 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -51,7 +51,7 @@ function echoMetadataGenerator(options, callback) { const credentials = grpc.credentials.createFromMetadataGenerator(echoMetadataGenerator); -describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { +describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { describe('Interop-adjacent tests', function() { let server; let client; @@ -144,7 +144,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done(); }); }); - it('should receive all messages in a long stream', function() { + it('should receive all messages in a long stream', function(done) { + this.timeout(20000); var arg = { response_type: 'COMPRESSABLE', response_parameters: [ diff --git a/test/interop/async_delay_queue.js b/test/interop/async_delay_queue.js index 43ac57387..f9a39b59a 100644 --- a/test/interop/async_delay_queue.js +++ b/test/interop/async_delay_queue.js @@ -39,9 +39,13 @@ AsyncDelayQueue.prototype.runNext = function() { var continueCallback = _.bind(this.runNext, this); if (next) { this.callback_pending = true; - setTimeout(function() { + if (next.delay === 0) { next.callback(continueCallback); - }, next.delay); + } else { + setTimeout(function() { + next.callback(continueCallback); + }, next.delay); + } } else { this.callback_pending = false; } From 25dfe88fb34222d9856c3f76ae6055560a873b95 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Jun 2020 11:25:26 -0700 Subject: [PATCH 1126/1899] grpc-js: bump to 1.1.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3d17f9a3d..1a2420121 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.0.5", + "version": "1.1.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From a34973b469f5a7ac6bd6e37a8fc12efe9d8c1faf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Jun 2020 11:32:48 -0700 Subject: [PATCH 1127/1899] Remove 'only' that was left over from test fixes --- test/api/interop_extra_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index f94b07527..67130e033 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -51,7 +51,7 @@ function echoMetadataGenerator(options, callback) { const credentials = grpc.credentials.createFromMetadataGenerator(echoMetadataGenerator); -describe.only(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { +describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { describe('Interop-adjacent tests', function() { let server; let client; From c6e17f2758e204b18e6c4650f86ee71d46eb1c1a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Jun 2020 10:14:55 -0700 Subject: [PATCH 1128/1899] Fix constructor argument declaration --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 0f3b82e87..6342d2bdc 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -426,7 +426,7 @@ function generateMasterFile(formatter: TextFormatter, root: Protobuf.Root, optio formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); formatter.writeLine('type SubtypeConstructor = {'); - formatter.writeLine(' new(args: ConstructorArguments): Subtype;'); + formatter.writeLine(' new(...args: ConstructorArguments): Subtype;'); formatter.writeLine('}'); formatter.writeLine(''); From c7bbf045b6774e3fdf70cb7aec49b01019b3644b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Jun 2020 15:52:37 -0700 Subject: [PATCH 1129/1899] Add json option and google.protobuf.Any wrapper type --- packages/proto-loader/README.md | 1 + .../bin/proto-loader-gen-types.ts | 46 +++++++++++++++++-- packages/proto-loader/package.json | 2 +- packages/proto-loader/src/index.ts | 35 ++++++++++++++ 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 481b86297..07f28907c 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -38,6 +38,7 @@ The options parameter is an object that can have the following optional properti | `arrays` | `true` or `false` | Set empty arrays for missing array values even if `defaults` is `false` Defaults to `false`. | `objects` | `true` or `false` | Set empty objects for missing object values even if `defaults` is `false` Defaults to `false`. | `oneofs` | `true` or `false` | Set virtual oneof properties to the present field's name. Defaults to `false`. +| `json` | `true` or `false` | Represent `Infinity` and `NaN` as strings in `float` fields, and automatically decode `google.protobuf.Any` values. Defaults to `false` | `includeDirs` | An array of strings | A list of search paths for imported `.proto` files. The following options object closely approximates the existing behavior of `grpc.load`: diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 6342d2bdc..7c70cd200 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -96,6 +96,15 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum, from?: Protobu } function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type) { + if (messageType.fullName === '.google.protobuf.Any') { + /* This describes the behavior of the Protobuf.js Any wrapper fromObject + * replacement function */ + formatter.writeLine('export type Any__Output = AnyExtension | {'); + formatter.writeLine(' type_url: string;'); + formatter.writeLine(' value: Buffer | Uint8Array | string;'); + formatter.writeLine('}'); + return; + } formatter.writeLine(`export interface ${messageType.name} {`); formatter.indent(); for (const field of messageType.fieldsArray) { @@ -104,6 +113,8 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp switch (field.type) { case 'double': case 'float': + type = 'number | string'; + break; case 'int32': case 'uint32': case 'sint32': @@ -149,6 +160,23 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp } function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions) { + if (messageType.fullName === '.google.protobuf.Any' && options.json) { + /* This describes the behavior of the Protobuf.js Any wrapper toObject + * replacement function */ + formatter.writeLine('export type Any__Output = AnyExtension | {'); + formatter.writeLine(' type_url: string;'); + let type: string; + if (options.bytes === Array) { + type = 'Uint8Array'; + } else if (options.bytes === String) { + type = 'string'; + } else { + type = 'Buffer'; + } + formatter.writeLine(` value: ${type};`); + formatter.writeLine('}'); + return; + } formatter.writeLine(`export interface ${messageType.name}__Output {`); formatter.indent(); for (const field of messageType.fieldsArray) { @@ -158,6 +186,12 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp switch (field.type) { case 'double': case 'float': + if (options.json) { + type = 'number | string'; + } else { + type = 'number'; + } + break; case 'int32': case 'uint32': case 'sint32': @@ -244,6 +278,9 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob if (usesLong) { formatter.writeLine("import { Long } from '@grpc/proto-loader';"); } + if (messageType.fullName === '.google.protobuf.Any') { + formatter.writeLine("import { AnyExtension } from '@grpc/proto-loader';") + } formatter.writeLine(''); generatePermissiveMessageInterface(formatter, messageType); @@ -524,7 +561,7 @@ function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json']) // .choices('longs', ['String', 'Number']) // .choices('enums', ['String']) // .choices('bytes', ['Array', 'String']) @@ -559,13 +596,14 @@ function runScript() { outDir: 'O' }).describe({ keepCase: 'Preserve the case of field names', - longs: 'The type that should be used to output 64 bit integer values', - enums: 'The type that should be used to output enum fields', - bytes: 'The type that should be used to output bytes fields', + longs: 'The type that should be used to output 64 bit integer values. Can be String, Number', + enums: 'The type that should be used to output enum fields. Can be String', + bytes: 'The type that should be used to output bytes fields. Can be String, Array', defaults: 'Output default values for omitted fields', arrays: 'Output default values for omitted repeated fields even if --defaults is not set', objects: 'Output default values for omitted message fields even if --defaults is not set', oneofs: 'Output virtual oneof fields set to the present field\'s name', + json: 'Represent Infinity and NaN as strings in float fields. Also decode google.protobuf.Any automatically', includeDirs: 'Directories to search for included files', outDir: 'Directory in which to output files', grpcLib: 'The gRPC implementation library that these types will be used with' diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 2bf93d42a..b84b79779 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre2", + "version": "0.6.0-pre3", "author": "Google Inc.", "contributors": [ { diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 45b6f150a..2e8507603 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -22,6 +22,39 @@ import * as descriptor from 'protobufjs/ext/descriptor'; export { Long } from 'long'; +/** + * This type exists for use with code generated by the proto-loader-gen-types + * tool. This type should be used with another interface, e.g. + * MessageType & AnyExtension for an object that is converted to or from a + * google.protobuf.Any message. + * For example, when processing an Any message: + * + * ```ts + * if (isAnyExtension(message)) { + * switch (message['@type']) { + * case TYPE1_URL: + * handleType1(message as AnyExtension & Type1); + * break; + * case TYPE2_URL: + * handleType2(message as AnyExtension & Type2); + * break; + * // ... + * } + * } + * ``` + */ +export interface AnyExtension { + /** + * The fully qualified name of the message type that this object represents, + * possibly including a URL prefix. + */ + '@type': string; +} + +export function isAnyExtension(obj: object): obj is AnyExtension { + return ('@type' in obj) && (typeof (obj as AnyExtension)['@type'] === 'string'); +} + import camelCase = require('lodash.camelcase'); declare module 'protobufjs' { @@ -331,6 +364,8 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { * `defaults` is `false`. Defaults to `false`. * @param options.oneofs Set virtual oneof properties to the present field's * name + * @param options.json Represent Infinity and NaN as strings in float fields, + * and automatically decode google.protobuf.Any values. * @param options.includeDirs Paths to search for imported `.proto` files. */ export function load( From cd8743e5699308973e7f8c41218e13772b1f14fb Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 19 Jun 2020 08:56:48 -0700 Subject: [PATCH 1130/1899] Omit port number from servername option --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 1a2420121..da8e28ae5 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.0", + "version": "1.1.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index bda63b6b3..bbaa1ce18 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,7 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; -import { GrpcUri, parseUri } from './uri-parser'; +import { GrpcUri, parseUri, splitHostPort } from './uri-parser'; import { ConnectionOptions } from 'tls'; import { FilterFactory, Filter } from './filter'; @@ -309,8 +309,9 @@ export class Subchannel { }; connectionOptions.servername = sslTargetNameOverride; } else { + const authorityHostname = splitHostPort(targetAuthority)?.host ?? 'localhost'; // We want to always set servername to support SNI - connectionOptions.servername = targetAuthority; + connectionOptions.servername = authorityHostname; } if (proxyConnectionResult.socket) { /* This is part of the workaround for From b1ca875836e1957f71419129230ec9f5df403084 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 22 Jun 2020 10:57:41 -0700 Subject: [PATCH 1131/1899] grpc-tools: Add compiler flag to fix error on Mac --- packages/grpc-tools/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index a0d3905ce..9d6690ba7 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -14,6 +14,7 @@ set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests") set(protobuf_WITH_ZLIB OFF CACHE BOOL "Build protobuf with zlib.") set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector") add_executable(grpc_node_plugin src/node_generator.cc From 3fa1c098c57bfbdc17d5428a83bf3c53482ee85b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Jun 2020 13:33:18 -0700 Subject: [PATCH 1132/1899] Start implementing XdsClient class --- .gitmodules | 6 ++ packages/grpc-js/deps/googleapis | 1 + packages/grpc-js/deps/protoc-gen-validate | 1 + packages/grpc-js/generateTypes.sh | 20 ++++ packages/grpc-js/package.json | 2 +- packages/grpc-js/src/xds-bootstrap.ts | 113 ++++++++++++++++++++++ packages/grpc-js/src/xds-client.ts | 49 ++++++++++ 7 files changed, 191 insertions(+), 1 deletion(-) create mode 160000 packages/grpc-js/deps/googleapis create mode 160000 packages/grpc-js/deps/protoc-gen-validate create mode 100644 packages/grpc-js/generateTypes.sh create mode 100644 packages/grpc-js/src/xds-bootstrap.ts create mode 100644 packages/grpc-js/src/xds-client.ts diff --git a/.gitmodules b/.gitmodules index 0d99efd55..7989090c6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,9 @@ [submodule "packages/grpc-js/deps/udpa"] path = packages/grpc-js/deps/udpa url = https://github.com/cncf/udpa.git +[submodule "packages/grpc-js/deps/googleapis"] + path = packages/grpc-js/deps/googleapis + url = https://github.com/googleapis/googleapis.git +[submodule "packages/grpc-js/deps/protoc-gen-validate"] + path = packages/grpc-js/deps/protoc-gen-validate + url = https://github.com/envoyproxy/protoc-gen-validate.git diff --git a/packages/grpc-js/deps/googleapis b/packages/grpc-js/deps/googleapis new file mode 160000 index 000000000..8c53b2cb7 --- /dev/null +++ b/packages/grpc-js/deps/googleapis @@ -0,0 +1 @@ +Subproject commit 8c53b2cb792234354c13336ac7daee61333deade diff --git a/packages/grpc-js/deps/protoc-gen-validate b/packages/grpc-js/deps/protoc-gen-validate new file mode 160000 index 000000000..0af61d9dc --- /dev/null +++ b/packages/grpc-js/deps/protoc-gen-validate @@ -0,0 +1 @@ +Subproject commit 0af61d9dc28712dc0e6f8e1a940855a2ee0cb9ed diff --git a/packages/grpc-js/generateTypes.sh b/packages/grpc-js/generateTypes.sh new file mode 100644 index 000000000..8eee726c0 --- /dev/null +++ b/packages/grpc-js/generateTypes.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +base=$(dirname $0) + +./node_modules/.bin/proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json\ + --includeDirs deps/envoy-api/ deps/udpa/ node_modules/protobufjs/ deps/googleapis/ deps/protoc-gen-validate/ \ + -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto \ No newline at end of file diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 86243b30c..2e5836f52 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.5.4", + "@grpc/proto-loader": "^0.6.0-pre3", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts new file mode 100644 index 000000000..95fd96e3a --- /dev/null +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -0,0 +1,113 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; +import * as adsTypes from './generated/ads'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export interface ChannelCredsConfig { + type: string; + config?: object; +} + +export interface XdsServerConfig { + serverUri: string; + channelCreds: ChannelCredsConfig[]; +} + +export interface BootstrapInfo { + xdsServers: XdsServerConfig[]; + node: adsTypes.messages.envoy.api.v2.core.Node; +} + +function validateChannelCredsConfig(obj: any): ChannelCredsConfig { + if (!('type' in obj)) { + throw new Error('type field missing in xds_servers.channel_creds element'); + } + if (typeof obj.type !== 'string') { + throw new Error(`xds_servers.channel_creds.type field: expected string, got ${typeof obj.type}`); + } + if ('config' in obj) { + if (typeof obj.config !== 'object' || obj.config === null) { + throw new Error('xds_servers.channel_creds config field must be an object if provided'); + } + } + return { + type: obj.type, + config: obj.config + } +} + +function validateXdsServerConfig(obj: any): XdsServerConfig { + if (!('server_uri' in obj)) { + throw new Error('server_uri field missing in xds_servers element'); + } + if (typeof obj.server_uri !== 'string') { + throw new Error(`xds_servers.server_uri field: expected string, got ${typeof obj.server_uri}`); + } + if (!('channel_creds' in obj)) { + throw new Error('channel_creds missing in xds_servers element'); + } + if (!Array.isArray(obj.channel_creds)) { + throw new Error(`xds_servers.channel_creds field: expected array, got ${typeof obj.channel_creds}`); + } + if (obj.channel_creds.length === 0) { + throw new Error('xds_servers.channel_creds field: at least one entry is required'); + } + return { + serverUri: obj.server_uri, + channelCreds: obj.channel_creds.map(validateChannelCredsConfig) + }; +} + +function validateNode(obj: any): adsTypes.messages.envoy.api.v2.core.Node { + throw new Error('Not implemented'); +} + +function validateBootstrapFile(obj: any): BootstrapInfo { + return { + xdsServers: obj.xds_servers.map(validateXdsServerConfig), + node: validateNode(obj.node) + } +} + +let loadedBootstrapInfo: Promise | null = null; + +export async function loadBootstrapInfo(): Promise { + if (loadedBootstrapInfo !== null) { + return loadedBootstrapInfo; + } + const bootstrapPath = process.env.GRPC_XDS_BOOTSTRAP; + if (bootstrapPath === undefined) { + return Promise.reject(new Error('GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS')); + } + loadedBootstrapInfo = new Promise((resolve, reject) => { + fs.readFile(bootstrapPath, { encoding: 'utf8'}, (err, data) => { + if (err) { + reject(new Error(`Failed to read xDS bootstrap file from path ${bootstrapPath} with error ${err.message}`)); + } + try { + const parsedFile = JSON.parse(data); + resolve(validateBootstrapFile(parsedFile)); + } catch (e) { + reject(new Error(`Failed to parse xDS bootstrap file at path ${bootstrapPath} with error ${e.message}`)); + } + }); + }); + return loadedBootstrapInfo; +} \ No newline at end of file diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts new file mode 100644 index 000000000..e8eea6f30 --- /dev/null +++ b/packages/grpc-js/src/xds-client.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; +import * as protoLoader from '@grpc/proto-loader'; +import { loadPackageDefinition } from './make-client'; +import * as adsTypes from './generated/ads'; +import { ChannelCredentials } from './channel-credentials'; + +const packageDefinition = protoLoader.loadSync([ + 'envoy/service/discovery/v2/ads.proto', + 'envoy/api/v2/listener.proto', + 'envoy/api/v2/route.proto', + 'envoy/api/v2/cluster.proto', + 'envoy/api/v2/endpoint.proto' + ], { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ] + }); + +const loadedDefinition = loadPackageDefinition(packageDefinition) as unknown as adsTypes.ProtoGrpcType; + +export class XdsClient { + +} \ No newline at end of file From f37e7d43bf9b8a98e4e7c0e93d97e4e0b90f437a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Jun 2020 16:36:26 -0700 Subject: [PATCH 1133/1899] A few more fixes to make the generated code compile --- .../bin/proto-loader-gen-types.ts | 80 ++++++++++++++----- packages/proto-loader/package.json | 4 +- 2 files changed, 64 insertions(+), 20 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 7c70cd200..9f9e0bd66 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -95,17 +95,30 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum, from?: Protobu return `import { ${importedTypes} } from '${filePath}';` } -function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type) { +function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf.Type | Protobuf.Enum)[] { + const messageList: (Protobuf.Type | Protobuf.Enum)[] = []; + for (const nested of namespace.nestedArray) { + if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { + messageList.push(nested); + } + if (isNamespaceBase(nested)) { + messageList.push(...getChildMessagesAndEnums(nested)); + } + } + return messageList; +} + +function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, nameOverride?: string) { if (messageType.fullName === '.google.protobuf.Any') { /* This describes the behavior of the Protobuf.js Any wrapper fromObject * replacement function */ - formatter.writeLine('export type Any__Output = AnyExtension | {'); + formatter.writeLine('export type Any = AnyExtension | {'); formatter.writeLine(' type_url: string;'); formatter.writeLine(' value: Buffer | Uint8Array | string;'); formatter.writeLine('}'); return; } - formatter.writeLine(`export interface ${messageType.name} {`); + formatter.writeLine(`export interface ${nameOverride ?? messageType.name} {`); formatter.indent(); for (const field of messageType.fieldsArray) { const repeatedString = field.repeated ? '[]' : ''; @@ -149,17 +162,17 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp type = `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; } } - formatter.writeLine(`${field.name}?: (${type})${repeatedString};`); + formatter.writeLine(`'${field.name}'?: (${type})${repeatedString};`); } for (const oneof of messageType.oneofsArray) { const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); - formatter.writeLine(`${oneof.name}?: ${typeString};`); + formatter.writeLine(`'${oneof.name}'?: ${typeString};`); } formatter.unindent(); formatter.writeLine('}'); } -function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions) { +function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions, nameOverride?: string) { if (messageType.fullName === '.google.protobuf.Any' && options.json) { /* This describes the behavior of the Protobuf.js Any wrapper toObject * replacement function */ @@ -177,7 +190,7 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp formatter.writeLine('}'); return; } - formatter.writeLine(`export interface ${messageType.name}__Output {`); + formatter.writeLine(`export interface ${nameOverride ?? messageType.name}__Output {`); formatter.indent(); for (const field of messageType.fieldsArray) { const repeatedString = field.repeated ? '[]' : ''; @@ -247,12 +260,12 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp fieldGuaranteed = false; } const optionalString = fieldGuaranteed ? '' : '?'; - formatter.writeLine(`${field.name}${optionalString}: (${type})${repeatedString};`); + formatter.writeLine(`'${field.name}'${optionalString}: (${type})${repeatedString};`); } if (options.oneofs) { for (const oneof of messageType.oneofsArray) { const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); - formatter.writeLine(`${oneof.name}: ${typeString};`); + formatter.writeLine(`'${oneof.name}': ${typeString};`); } } formatter.unindent(); @@ -262,8 +275,11 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp function generateMessageInterfaces(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions) { let usesLong: boolean = false; let seenDeps: Set = new Set(); + const childTypes = getChildMessagesAndEnums(messageType); + formatter.writeLine(`// Original file: ${messageType.filename}`); + formatter.writeLine(''); for (const field of messageType.fieldsArray) { - if (field.resolvedType) { + if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { const dependency = field.resolvedType; if (seenDeps.has(dependency.fullName)) { continue; @@ -275,6 +291,23 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob usesLong = true; } } + for (const childType of childTypes) { + if (childType instanceof Protobuf.Type) { + for (const field of childType.fieldsArray) { + if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { + const dependency = field.resolvedType; + if (seenDeps.has(dependency.fullName)) { + continue; + } + seenDeps.add(dependency.fullName); + formatter.writeLine(getImportLine(dependency, messageType)); + } + if (field.type.indexOf('64') >= 0) { + usesLong = true; + } + } + } + } if (usesLong) { formatter.writeLine("import { Long } from '@grpc/proto-loader';"); } @@ -282,14 +315,27 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob formatter.writeLine("import { AnyExtension } from '@grpc/proto-loader';") } formatter.writeLine(''); + for (const childType of childTypes) { + const nameOverride = getTypeInterfaceName(childType); + if (childType instanceof Protobuf.Type) { + generatePermissiveMessageInterface(formatter, childType, nameOverride); + formatter.writeLine(''); + generateRestrictedMessageInterface(formatter, childType, options, nameOverride); + } else { + generateEnumInterface(formatter, childType, nameOverride); + } + formatter.writeLine(''); + } generatePermissiveMessageInterface(formatter, messageType); formatter.writeLine(''); generateRestrictedMessageInterface(formatter, messageType, options); } -function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum) { - formatter.writeLine(`export enum ${enumType.name} {`); +function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, nameOverride?: string) { + formatter.writeLine(`// Original file: ${enumType.filename}`); + formatter.writeLine(''); + formatter.writeLine(`export enum ${nameOverride ?? enumType.name} {`); formatter.indent(); for (const key of Object.keys(enumType.values)) { formatter.writeLine(`${key} = ${enumType.values[key]},`); @@ -302,8 +348,7 @@ function generateMessageAndEnumImports(formatter: TextFormatter, namespace: Prot for (const nested of namespace.nestedArray) { if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { formatter.writeLine(getImportLine(nested)); - } - if (isNamespaceBase(nested)) { + } else if (isNamespaceBase(nested)) { generateMessageAndEnumImports(formatter, nested); } } @@ -491,14 +536,13 @@ function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: G const fileFormatter = new TextFormatter(); if (nested instanceof Protobuf.Type) { generateMessageInterfaces(fileFormatter, nested, options); - console.log(`Writing ${options.outDir}/${getPath(nested)}`); + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Enum) { generateEnumInterface(fileFormatter, nested); - console.log(`Writing ${options.outDir}/${getPath(nested)}`); + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); - } - if (isNamespaceBase(nested)) { + } else if (isNamespaceBase(nested)) { filePromises.push(...generateFilesForNamespace(nested, options)); } } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index b84b79779..ac2e84a6b 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre3", + "version": "0.6.0-pre4", "author": "Google Inc.", "contributors": [ { @@ -47,7 +47,7 @@ "lodash.camelcase": "^4.3.0", "long": "^4.0.0", "mkdirp": "^1.0.4", - "protobufjs": "^6.8.6", + "protobufjs": "^6.9.0", "yargs": "^15.3.1" }, "devDependencies": { From 110cb2f1b8950deec8032a69ad130f598ec1e606 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 25 Jun 2020 12:45:46 -0700 Subject: [PATCH 1134/1899] Export service client interfaces --- packages/proto-loader/bin/proto-loader-gen-types.ts | 12 ++++++++---- packages/proto-loader/package.json | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 9f9e0bd66..cfb5bd5b2 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -372,7 +372,7 @@ function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Prot } function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { - formatter.writeLine(`interface ${serviceType.name}Client extends grpc.Client {`); + formatter.writeLine(`export interface ${serviceType.name}Client extends grpc.Client {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods)) { const method = serviceType.methods[methodName]; @@ -416,7 +416,9 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P formatter.writeLine('}'); } -function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { +function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { + formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); + formatter.indent(); for (const nested of namespace.nestedArray) { if (nested instanceof Protobuf.Service) { generateServiceClientInterface(formatter, nested); @@ -424,11 +426,13 @@ function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: generateAllServiceClientInterfaces(formatter, nested); } } + formatter.unindent(); + formatter.writeLine('}'); } function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject) { if (nested instanceof Protobuf.Service) { - formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) + formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) } else if (nested instanceof Protobuf.Enum) { formatter.writeLine(`${nested.name}: EnumTypeDefinition`); } else if (nested instanceof Protobuf.Type) { @@ -503,7 +507,7 @@ function generateMasterFile(formatter: TextFormatter, root: Protobuf.Root, optio generateMessageAndEnumExports(formatter, root, 'messages'); formatter.writeLine(''); - generateAllServiceClientInterfaces(formatter, root); + generateAllServiceClientInterfaces(formatter, root, 'ClientInterfaces'); formatter.writeLine(''); formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index ac2e84a6b..688a41aaf 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre4", + "version": "0.6.0-pre5", "author": "Google Inc.", "contributors": [ { From c6d4ea5a0235592378918ad48a14c545c17ce62c Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Fri, 3 Jul 2020 09:22:02 +0100 Subject: [PATCH 1135/1899] Fix some type issues in the server interface --- packages/proto-loader/bin/proto-loader-gen-types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 9f9e0bd66..177ff4d97 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -461,15 +461,15 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: formatter.writeLine(`${methodName}(call: grpc.ServerDuplexStream<${requestType}, ${responseType}>): void;`); } else { // Client streaming - formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}>, callback: grpc.SendUnaryData<${responseType}>): void;`); + formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); } } else { if (method.responseStream) { // Server streaming - formatter.writeLine(`${methodName}(call: grpc.ServerWriteableStream<${requestType}, ${responseType}>): void;`); + formatter.writeLine(`${methodName}(call: grpc.ServerWritableStream<${requestType}, ${responseType}>): void;`); } else { // Unary - formatter.writeLine(`${methodName}(call: grpc.ServerUnaryCall<${requestType}>, callback: grpc.SendUnaryData<${responseType}>): void;`); + formatter.writeLine(`${methodName}(call: grpc.ServerUnaryCall<${requestType}, ${responseType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); } } formatter.writeLine(''); From f64599f7edcba42c531a2b8baacc199cc457e769 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Jul 2020 09:03:59 -0700 Subject: [PATCH 1136/1899] Bump to 0.6.0-pre6 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 688a41aaf..0d7512159 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre5", + "version": "0.6.0-pre6", "author": "Google Inc.", "contributors": [ { From 81fff185aeedd86e072476534063ca9773b35b23 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Jun 2020 16:43:48 -0700 Subject: [PATCH 1137/1899] Add generated code for Envoy APIs --- packages/grpc-js/src/generated/ads.d.ts | 983 +++++++++ packages/grpc-js/src/generated/cluster.d.ts | 1471 ++++++++++++++ packages/grpc-js/src/generated/endpoint.d.ts | 1140 +++++++++++ .../src/generated/envoy/api/v2/Cluster.d.ts | 339 ++++ .../envoy/api/v2/ClusterLoadAssignment.d.ts | 45 + .../envoy/api/v2/DeltaDiscoveryRequest.d.ts | 24 + .../envoy/api/v2/DeltaDiscoveryResponse.d.ts | 19 + .../envoy/api/v2/DiscoveryRequest.d.ts | 22 + .../envoy/api/v2/DiscoveryResponse.d.ts | 22 + .../src/generated/envoy/api/v2/Listener.d.ts | 93 + .../envoy/api/v2/LoadBalancingPolicy.d.ts | 24 + .../src/generated/envoy/api/v2/Resource.d.ts | 17 + .../envoy/api/v2/RouteConfiguration.d.ts | 32 + .../envoy/api/v2/UpstreamBindConfig.d.ts | 11 + .../api/v2/UpstreamConnectionOptions.d.ts | 11 + .../src/generated/envoy/api/v2/Vhds.d.ts | 11 + .../v2/auth/CertificateValidationContext.d.ts | 38 + .../envoy/api/v2/auth/CommonTlsContext.d.ts | 38 + .../api/v2/auth/DownstreamTlsContext.d.ts | 29 + .../envoy/api/v2/auth/GenericSecret.d.ts | 11 + .../envoy/api/v2/auth/PrivateKeyProvider.d.ts | 18 + .../envoy/api/v2/auth/SdsSecretConfig.d.ts | 13 + .../generated/envoy/api/v2/auth/Secret.d.ts | 24 + .../envoy/api/v2/auth/TlsCertificate.d.ts | 22 + .../envoy/api/v2/auth/TlsParameters.d.ts | 26 + .../api/v2/auth/TlsSessionTicketKeys.d.ts | 11 + .../envoy/api/v2/auth/UpstreamTlsContext.d.ts | 18 + .../envoy/api/v2/cluster/CircuitBreakers.d.ts | 45 + .../envoy/api/v2/cluster/Filter.d.ts | 13 + .../api/v2/cluster/OutlierDetection.d.ts | 50 + .../generated/envoy/api/v2/core/Address.d.ts | 16 + .../api/v2/core/AggregatedConfigSource.d.ts | 8 + .../envoy/api/v2/core/ApiConfigSource.d.ts | 37 + .../envoy/api/v2/core/ApiVersion.d.ts | 7 + .../envoy/api/v2/core/AsyncDataSource.d.ts | 16 + .../envoy/api/v2/core/BackoffStrategy.d.ts | 13 + .../envoy/api/v2/core/BindConfig.d.ts | 17 + .../envoy/api/v2/core/BuildVersion.d.ts | 14 + .../envoy/api/v2/core/CidrRange.d.ts | 13 + .../envoy/api/v2/core/ConfigSource.d.ts | 27 + .../envoy/api/v2/core/ControlPlane.d.ts | 10 + .../envoy/api/v2/core/DataSource.d.ts | 16 + .../envoy/api/v2/core/EventServiceConfig.d.ts | 13 + .../envoy/api/v2/core/Extension.d.ts | 19 + .../api/v2/core/GrpcProtocolOptions.d.ts | 11 + .../envoy/api/v2/core/GrpcService.d.ts | 163 ++ .../envoy/api/v2/core/HeaderMap.d.ts | 11 + .../envoy/api/v2/core/HeaderValue.d.ts | 12 + .../envoy/api/v2/core/HeaderValueOption.d.ts | 14 + .../envoy/api/v2/core/HealthCheck.d.ts | 153 ++ .../envoy/api/v2/core/HealthStatus.d.ts | 10 + .../api/v2/core/Http1ProtocolOptions.d.ts | 35 + .../api/v2/core/Http2ProtocolOptions.d.ts | 45 + .../api/v2/core/HttpProtocolOptions.d.ts | 28 + .../generated/envoy/api/v2/core/HttpUri.d.ts | 17 + .../generated/envoy/api/v2/core/Locality.d.ts | 14 + .../generated/envoy/api/v2/core/Metadata.d.ts | 11 + .../src/generated/envoy/api/v2/core/Node.d.ts | 37 + .../src/generated/envoy/api/v2/core/Pipe.d.ts | 12 + .../envoy/api/v2/core/RateLimitSettings.d.ts | 14 + .../envoy/api/v2/core/RemoteDataSource.d.ts | 16 + .../envoy/api/v2/core/RequestMethod.d.ts | 14 + .../envoy/api/v2/core/RetryPolicy.d.ts | 14 + .../envoy/api/v2/core/RoutingPriority.d.ts | 6 + .../envoy/api/v2/core/RuntimeDouble.d.ts | 12 + .../envoy/api/v2/core/RuntimeFeatureFlag.d.ts | 13 + .../api/v2/core/RuntimeFractionalPercent.d.ts | 13 + .../envoy/api/v2/core/RuntimeUInt32.d.ts | 12 + .../envoy/api/v2/core/SelfConfigSource.d.ts | 8 + .../envoy/api/v2/core/SocketAddress.d.ts | 29 + .../envoy/api/v2/core/SocketOption.d.ts | 31 + .../envoy/api/v2/core/TcpKeepalive.d.ts | 15 + .../envoy/api/v2/core/TcpProtocolOptions.d.ts | 8 + .../envoy/api/v2/core/TrafficDirection.d.ts | 7 + .../envoy/api/v2/core/TransportSocket.d.ts | 18 + .../v2/core/UpstreamHttpProtocolOptions.d.ts | 12 + .../envoy/api/v2/endpoint/Endpoint.d.ts | 25 + .../envoy/api/v2/endpoint/LbEndpoint.d.ts | 24 + .../api/v2/endpoint/LocalityLbEndpoints.d.ts | 21 + .../listener/ActiveRawUdpListenerConfig.d.ts | 8 + .../envoy/api/v2/listener/Filter.d.ts | 18 + .../envoy/api/v2/listener/FilterChain.d.ts | 28 + .../api/v2/listener/FilterChainMatch.d.ts | 38 + .../envoy/api/v2/listener/ListenerFilter.d.ts | 21 + .../ListenerFilterChainMatchPredicate.d.ts | 30 + .../api/v2/listener/UdpListenerConfig.d.ts | 18 + .../envoy/api/v2/route/CorsPolicy.d.ts | 35 + .../envoy/api/v2/route/Decorator.d.ts | 13 + .../api/v2/route/DirectResponseAction.d.ts | 13 + .../envoy/api/v2/route/FilterAction.d.ts | 11 + .../envoy/api/v2/route/HeaderMatcher.d.ts | 31 + .../envoy/api/v2/route/HedgePolicy.d.ts | 16 + .../api/v2/route/QueryParameterMatcher.d.ts | 22 + .../envoy/api/v2/route/RateLimit.d.ts | 85 + .../envoy/api/v2/route/RedirectAction.d.ts | 38 + .../envoy/api/v2/route/RetryPolicy.d.ts | 72 + .../generated/envoy/api/v2/route/Route.d.ts | 54 + .../envoy/api/v2/route/RouteAction.d.ts | 181 ++ .../envoy/api/v2/route/RouteMatch.d.ts | 51 + .../generated/envoy/api/v2/route/Tracing.d.ts | 18 + .../envoy/api/v2/route/VirtualCluster.d.ts | 18 + .../envoy/api/v2/route/VirtualHost.d.ts | 64 + .../envoy/api/v2/route/WeightedCluster.d.ts | 43 + .../config/filter/accesslog/v2/AccessLog.d.ts | 21 + .../filter/accesslog/v2/AccessLogFilter.d.ts | 43 + .../config/filter/accesslog/v2/AndFilter.d.ts | 11 + .../filter/accesslog/v2/ComparisonFilter.d.ts | 21 + .../filter/accesslog/v2/DurationFilter.d.ts | 11 + .../filter/accesslog/v2/ExtensionFilter.d.ts | 18 + .../filter/accesslog/v2/GrpcStatusFilter.d.ts | 34 + .../filter/accesslog/v2/HeaderFilter.d.ts | 11 + .../accesslog/v2/NotHealthCheckFilter.d.ts | 8 + .../config/filter/accesslog/v2/OrFilter.d.ts | 11 + .../accesslog/v2/ResponseFlagFilter.d.ts | 10 + .../filter/accesslog/v2/RuntimeFilter.d.ts | 15 + .../filter/accesslog/v2/StatusCodeFilter.d.ts | 11 + .../filter/accesslog/v2/TraceableFilter.d.ts | 8 + .../envoy/config/listener/v2/ApiListener.d.ts | 11 + .../envoy/service/discovery/v2/AdsDummy.d.ts | 8 + .../generated/envoy/type/CodecClientType.d.ts | 7 + .../src/generated/envoy/type/DoubleRange.d.ts | 12 + .../envoy/type/FractionalPercent.d.ts | 20 + .../src/generated/envoy/type/Int32Range.d.ts | 12 + .../src/generated/envoy/type/Int64Range.d.ts | 13 + .../src/generated/envoy/type/Percent.d.ts | 10 + .../generated/envoy/type/SemanticVersion.d.ts | 14 + .../envoy/type/matcher/ListStringMatcher.d.ts | 11 + .../type/matcher/RegexMatchAndSubstitute.d.ts | 13 + .../envoy/type/matcher/RegexMatcher.d.ts | 23 + .../envoy/type/matcher/StringMatcher.d.ts | 23 + .../envoy/type/metadata/v2/MetadataKey.d.ts | 22 + .../envoy/type/metadata/v2/MetadataKind.d.ts | 42 + .../envoy/type/tracing/v2/CustomTag.d.ts | 62 + .../google/api/CustomHttpPattern.d.ts | 12 + .../src/generated/google/api/Http.d.ts | 11 + .../src/generated/google/api/HttpRule.d.ts | 30 + .../src/generated/google/protobuf/Any.d.ts | 13 + .../generated/google/protobuf/BoolValue.d.ts | 10 + .../generated/google/protobuf/BytesValue.d.ts | 10 + .../google/protobuf/DescriptorProto.d.ts | 53 + .../google/protobuf/DoubleValue.d.ts | 10 + .../generated/google/protobuf/Duration.d.ts | 13 + .../src/generated/google/protobuf/Empty.d.ts | 8 + .../google/protobuf/EnumDescriptorProto.d.ts | 16 + .../google/protobuf/EnumOptions.d.ts | 18 + .../protobuf/EnumValueDescriptorProto.d.ts | 15 + .../google/protobuf/EnumValueOptions.d.ts | 18 + .../google/protobuf/FieldDescriptorProto.d.ts | 60 + .../google/protobuf/FieldOptions.d.ts | 49 + .../google/protobuf/FileDescriptorProto.d.ts | 38 + .../google/protobuf/FileDescriptorSet.d.ts | 11 + .../google/protobuf/FileOptions.d.ts | 53 + .../generated/google/protobuf/FloatValue.d.ts | 10 + .../google/protobuf/GeneratedCodeInfo.d.ts | 24 + .../generated/google/protobuf/Int32Value.d.ts | 10 + .../generated/google/protobuf/Int64Value.d.ts | 11 + .../generated/google/protobuf/ListValue.d.ts | 11 + .../google/protobuf/MessageOptions.d.ts | 24 + .../protobuf/MethodDescriptorProto.d.ts | 21 + .../google/protobuf/MethodOptions.d.ts | 16 + .../generated/google/protobuf/NullValue.d.ts | 5 + .../google/protobuf/OneofDescriptorProto.d.ts | 13 + .../google/protobuf/OneofOptions.d.ts | 13 + .../protobuf/ServiceDescriptorProto.d.ts | 16 + .../google/protobuf/ServiceOptions.d.ts | 13 + .../google/protobuf/SourceCodeInfo.d.ts | 26 + .../google/protobuf/StringValue.d.ts | 10 + .../src/generated/google/protobuf/Struct.d.ts | 11 + .../generated/google/protobuf/Timestamp.d.ts | 13 + .../google/protobuf/UInt32Value.d.ts | 10 + .../google/protobuf/UInt64Value.d.ts | 11 + .../google/protobuf/UninterpretedOption.d.ts | 33 + .../src/generated/google/protobuf/Value.d.ts | 25 + .../src/generated/google/rpc/Status.d.ts | 15 + packages/grpc-js/src/generated/listener.d.ts | 1757 +++++++++++++++++ packages/grpc-js/src/generated/route.d.ts | 1385 +++++++++++++ .../annotations/FieldMigrateAnnotation.d.ts | 12 + .../annotations/FileMigrateAnnotation.d.ts | 10 + .../udpa/annotations/MigrateAnnotation.d.ts | 10 + .../annotations/PackageVersionStatus.d.ts | 8 + .../udpa/annotations/StatusAnnotation.d.ts | 13 + .../src/generated/validate/AnyRules.d.ts | 14 + .../src/generated/validate/BoolRules.d.ts | 10 + .../src/generated/validate/BytesRules.d.ts | 37 + .../src/generated/validate/DoubleRules.d.ts | 22 + .../src/generated/validate/DurationRules.d.ts | 25 + .../src/generated/validate/EnumRules.d.ts | 16 + .../src/generated/validate/FieldRules.d.ts | 77 + .../src/generated/validate/Fixed32Rules.d.ts | 22 + .../src/generated/validate/Fixed64Rules.d.ts | 23 + .../src/generated/validate/FloatRules.d.ts | 22 + .../src/generated/validate/Int32Rules.d.ts | 22 + .../src/generated/validate/Int64Rules.d.ts | 23 + .../src/generated/validate/KnownRegex.d.ts | 7 + .../src/generated/validate/MapRules.d.ts | 20 + .../src/generated/validate/MessageRules.d.ts | 12 + .../src/generated/validate/RepeatedRules.d.ts | 18 + .../src/generated/validate/SFixed32Rules.d.ts | 22 + .../src/generated/validate/SFixed64Rules.d.ts | 23 + .../src/generated/validate/SInt32Rules.d.ts | 22 + .../src/generated/validate/SInt64Rules.d.ts | 23 + .../src/generated/validate/StringRules.d.ts | 62 + .../generated/validate/TimestampRules.d.ts | 28 + .../src/generated/validate/UInt32Rules.d.ts | 22 + .../src/generated/validate/UInt64Rules.d.ts | 23 + 205 files changed, 11772 insertions(+) create mode 100644 packages/grpc-js/src/generated/ads.d.ts create mode 100644 packages/grpc-js/src/generated/cluster.d.ts create mode 100644 packages/grpc-js/src/generated/endpoint.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/Cluster.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/Listener.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/Resource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/Vhds.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Address.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Extension.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Locality.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Node.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/Route.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/CodecClientType.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/DoubleRange.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/FractionalPercent.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/Int32Range.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/Int64Range.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/Percent.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/SemanticVersion.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.d.ts create mode 100644 packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.d.ts create mode 100644 packages/grpc-js/src/generated/google/api/CustomHttpPattern.d.ts create mode 100644 packages/grpc-js/src/generated/google/api/Http.d.ts create mode 100644 packages/grpc-js/src/generated/google/api/HttpRule.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Any.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/BoolValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/BytesValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/DescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/DoubleValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Duration.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Empty.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/EnumOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FieldOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FileOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FloatValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Int32Value.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Int64Value.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/ListValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/MessageOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/MethodOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/NullValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/OneofOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/ServiceOptions.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/StringValue.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Struct.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Timestamp.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/UInt32Value.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/UInt64Value.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.d.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Value.d.ts create mode 100644 packages/grpc-js/src/generated/google/rpc/Status.d.ts create mode 100644 packages/grpc-js/src/generated/listener.d.ts create mode 100644 packages/grpc-js/src/generated/route.d.ts create mode 100644 packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.d.ts create mode 100644 packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.d.ts create mode 100644 packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.d.ts create mode 100644 packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.d.ts create mode 100644 packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.d.ts create mode 100644 packages/grpc-js/src/generated/validate/AnyRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/BoolRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/BytesRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/DoubleRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/DurationRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/EnumRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/FieldRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/Fixed32Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/Fixed64Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/FloatRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/Int32Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/Int64Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/KnownRegex.d.ts create mode 100644 packages/grpc-js/src/generated/validate/MapRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/MessageRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/RepeatedRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/SFixed32Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/SFixed64Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/SInt32Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/SInt64Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/StringRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/TimestampRules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/UInt32Rules.d.ts create mode 100644 packages/grpc-js/src/generated/validate/UInt64Rules.d.ts diff --git a/packages/grpc-js/src/generated/ads.d.ts b/packages/grpc-js/src/generated/ads.d.ts new file mode 100644 index 000000000..fee58a0ed --- /dev/null +++ b/packages/grpc-js/src/generated/ads.d.ts @@ -0,0 +1,983 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { AdsDummy as _envoy_service_discovery_v2_AdsDummy, AdsDummy__Output as _envoy_service_discovery_v2_AdsDummy__Output } from './envoy/service/discovery/v2/AdsDummy'; +import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from './envoy/api/v2/DiscoveryRequest'; +import { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from './envoy/api/v2/DiscoveryResponse'; +import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from './envoy/api/v2/DeltaDiscoveryRequest'; +import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from './envoy/api/v2/DeltaDiscoveryResponse'; +import { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from './envoy/api/v2/Resource'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from './google/rpc/Status'; + +export namespace messages { + export namespace envoy { + export namespace service { + export namespace discovery { + export namespace v2 { + export namespace AggregatedDiscoveryService { + } + export type AdsDummy = _envoy_service_discovery_v2_AdsDummy; + export type AdsDummy__Output = _envoy_service_discovery_v2_AdsDummy__Output; + } + } + } + export namespace api { + export namespace v2 { + export type DiscoveryRequest = _envoy_api_v2_DiscoveryRequest; + export type DiscoveryRequest__Output = _envoy_api_v2_DiscoveryRequest__Output; + export type DiscoveryResponse = _envoy_api_v2_DiscoveryResponse; + export type DiscoveryResponse__Output = _envoy_api_v2_DiscoveryResponse__Output; + export type DeltaDiscoveryRequest = _envoy_api_v2_DeltaDiscoveryRequest; + export type DeltaDiscoveryRequest__Output = _envoy_api_v2_DeltaDiscoveryRequest__Output; + export type DeltaDiscoveryResponse = _envoy_api_v2_DeltaDiscoveryResponse; + export type DeltaDiscoveryResponse__Output = _envoy_api_v2_DeltaDiscoveryResponse__Output; + export type Resource = _envoy_api_v2_Resource; + export type Resource__Output = _envoy_api_v2_Resource__Output; + export namespace core { + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type BuildVersion = _envoy_api_v2_core_BuildVersion; + export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type Extension = _envoy_api_v2_core_Extension; + export type Extension__Output = _envoy_api_v2_core_Extension__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type HeaderValue = _envoy_api_v2_core_HeaderValue; + export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + } + } + } + export namespace type { + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; + export type FractionalPercent = _envoy_type_FractionalPercent; + export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; + } + } + export namespace udpa { + export namespace annotations { + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + } + } + export namespace validate { + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type KnownRegex = _validate_KnownRegex; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + } + export namespace google { + export namespace protobuf { + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; + export type NullValue = _google_protobuf_NullValue; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type BoolValue = _google_protobuf_BoolValue; + export type BoolValue__Output = _google_protobuf_BoolValue__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type BytesValue = _google_protobuf_BytesValue; + export type BytesValue__Output = _google_protobuf_BytesValue__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type DescriptorProto = _google_protobuf_DescriptorProto; + export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; + export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; + export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type FileOptions = _google_protobuf_FileOptions; + export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type MessageOptions = _google_protobuf_MessageOptions; + export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type OneofOptions = _google_protobuf_OneofOptions; + export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceOptions = _google_protobuf_ServiceOptions; + export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; + export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + } + export namespace rpc { + export type Status = _google_rpc_Status; + export type Status__Output = _google_rpc_Status__Output; + } + } +} + +export namespace ClientInterfaces { + export namespace envoy { + export namespace service { + export namespace discovery { + export namespace v2 { + export interface AggregatedDiscoveryServiceClient extends grpc.Client { + StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + + DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + + } + export namespace AdsDummy { + } + } + } + } + export namespace api { + export namespace v2 { + export namespace DiscoveryRequest { + } + export namespace DiscoveryResponse { + } + export namespace DeltaDiscoveryRequest { + } + export namespace DeltaDiscoveryResponse { + } + export namespace Resource { + } + export namespace core { + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace BackoffStrategy { + } + export namespace HttpUri { + } + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace SocketOption { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + } + } + export namespace udpa { + export namespace annotations { + export namespace StatusAnnotation { + } + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Any { + } + export namespace Duration { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Timestamp { + } + } + export namespace rpc { + export namespace Status { + } + } + } +} + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + service: { + discovery: { + v2: { + AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } + AdsDummy: MessageTypeDefinition + } + } + } + api: { + v2: { + DiscoveryRequest: MessageTypeDefinition + DiscoveryResponse: MessageTypeDefinition + DeltaDiscoveryRequest: MessageTypeDefinition + DeltaDiscoveryResponse: MessageTypeDefinition + Resource: MessageTypeDefinition + core: { + RoutingPriority: EnumTypeDefinition + RequestMethod: EnumTypeDefinition + TrafficDirection: EnumTypeDefinition + Locality: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + Extension: MessageTypeDefinition + Node: MessageTypeDefinition + Metadata: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + DataSource: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + TransportSocket: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition + SocketOption: MessageTypeDefinition + } + } + } + type: { + Percent: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } + } + udpa: { + annotations: { + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + } + } + validate: { + FieldRules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + StringRules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + BytesRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + MapRules: MessageTypeDefinition + AnyRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + } + google: { + protobuf: { + Any: MessageTypeDefinition + Duration: MessageTypeDefinition + Struct: MessageTypeDefinition + Value: MessageTypeDefinition + NullValue: EnumTypeDefinition + ListValue: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + FloatValue: MessageTypeDefinition + Int64Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + Int32Value: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + BoolValue: MessageTypeDefinition + StringValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + FileOptions: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Timestamp: MessageTypeDefinition + } + rpc: { + Status: MessageTypeDefinition + } + } +} + +export namespace ServiceHandlers { + export namespace envoy { + export namespace service { + export namespace discovery { + export namespace v2 { + export interface AggregatedDiscoveryService { + StreamAggregatedResources(call: grpc.ServerDuplexStream): void; + + DeltaAggregatedResources(call: grpc.ServerDuplexStream): void; + + } + export namespace AdsDummy { + } + } + } + } + export namespace api { + export namespace v2 { + export namespace DiscoveryRequest { + } + export namespace DiscoveryResponse { + } + export namespace DeltaDiscoveryRequest { + } + export namespace DeltaDiscoveryResponse { + } + export namespace Resource { + } + export namespace core { + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace BackoffStrategy { + } + export namespace HttpUri { + } + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace SocketOption { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + } + } + export namespace udpa { + export namespace annotations { + export namespace StatusAnnotation { + } + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Any { + } + export namespace Duration { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Timestamp { + } + } + export namespace rpc { + export namespace Status { + } + } + } +} diff --git a/packages/grpc-js/src/generated/cluster.d.ts b/packages/grpc-js/src/generated/cluster.d.ts new file mode 100644 index 000000000..bb137fbdd --- /dev/null +++ b/packages/grpc-js/src/generated/cluster.d.ts @@ -0,0 +1,1471 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { Cluster as _envoy_api_v2_Cluster, Cluster__Output as _envoy_api_v2_Cluster__Output } from './envoy/api/v2/Cluster'; +import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from './envoy/api/v2/LoadBalancingPolicy'; +import { UpstreamBindConfig as _envoy_api_v2_UpstreamBindConfig, UpstreamBindConfig__Output as _envoy_api_v2_UpstreamBindConfig__Output } from './envoy/api/v2/UpstreamBindConfig'; +import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from './envoy/api/v2/UpstreamConnectionOptions'; +import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; +import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; +import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; +import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; +import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; +import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; +import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; +import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; +import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; +import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; +import { TcpProtocolOptions as _envoy_api_v2_core_TcpProtocolOptions, TcpProtocolOptions__Output as _envoy_api_v2_core_TcpProtocolOptions__Output } from './envoy/api/v2/core/TcpProtocolOptions'; +import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from './envoy/api/v2/core/UpstreamHttpProtocolOptions'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from './envoy/api/v2/core/HttpProtocolOptions'; +import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from './envoy/api/v2/core/Http1ProtocolOptions'; +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from './envoy/api/v2/core/Http2ProtocolOptions'; +import { GrpcProtocolOptions as _envoy_api_v2_core_GrpcProtocolOptions, GrpcProtocolOptions__Output as _envoy_api_v2_core_GrpcProtocolOptions__Output } from './envoy/api/v2/core/GrpcProtocolOptions'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from './envoy/api/v2/cluster/CircuitBreakers'; +import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from './envoy/api/v2/cluster/Filter'; +import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from './envoy/api/v2/cluster/OutlierDetection'; +import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; +import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; +import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; +import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; +import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; + +export namespace messages { + export namespace envoy { + export namespace api { + export namespace v2 { + export type Cluster = _envoy_api_v2_Cluster; + export type Cluster__Output = _envoy_api_v2_Cluster__Output; + export type LoadBalancingPolicy = _envoy_api_v2_LoadBalancingPolicy; + export type LoadBalancingPolicy__Output = _envoy_api_v2_LoadBalancingPolicy__Output; + export type UpstreamBindConfig = _envoy_api_v2_UpstreamBindConfig; + export type UpstreamBindConfig__Output = _envoy_api_v2_UpstreamBindConfig__Output; + export type UpstreamConnectionOptions = _envoy_api_v2_UpstreamConnectionOptions; + export type UpstreamConnectionOptions__Output = _envoy_api_v2_UpstreamConnectionOptions__Output; + export namespace auth { + export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; + export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; + export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; + export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; + export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; + export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; + export type GenericSecret = _envoy_api_v2_auth_GenericSecret; + export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; + export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; + export type Secret = _envoy_api_v2_auth_Secret; + export type Secret__Output = _envoy_api_v2_auth_Secret__Output; + export type TlsParameters = _envoy_api_v2_auth_TlsParameters; + export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; + export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; + export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; + export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; + export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; + export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; + export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; + export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; + export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + } + export namespace core { + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type BuildVersion = _envoy_api_v2_core_BuildVersion; + export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type Extension = _envoy_api_v2_core_Extension; + export type Extension__Output = _envoy_api_v2_core_Extension__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type HeaderValue = _envoy_api_v2_core_HeaderValue; + export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type HealthStatus = _envoy_api_v2_core_HealthStatus; + export type HealthCheck = _envoy_api_v2_core_HealthCheck; + export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; + export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; + export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; + export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; + export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; + export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; + export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; + export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; + export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; + export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; + export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; + export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; + export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + } + export namespace cluster { + export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; + export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; + export type Filter = _envoy_api_v2_cluster_Filter; + export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; + export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; + export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; + } + export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; + export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; + export namespace endpoint { + export type Endpoint = _envoy_api_v2_endpoint_Endpoint; + export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; + export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; + export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; + export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; + export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; + } + } + } + export namespace type { + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; + export type FractionalPercent = _envoy_type_FractionalPercent; + export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + export namespace matcher { + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + } + export type CodecClientType = _envoy_type_CodecClientType; + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; + } + } + export namespace validate { + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type KnownRegex = _validate_KnownRegex; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + } + export namespace google { + export namespace protobuf { + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; + export type NullValue = _google_protobuf_NullValue; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type BoolValue = _google_protobuf_BoolValue; + export type BoolValue__Output = _google_protobuf_BoolValue__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type BytesValue = _google_protobuf_BytesValue; + export type BytesValue__Output = _google_protobuf_BytesValue__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type DescriptorProto = _google_protobuf_DescriptorProto; + export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; + export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; + export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type FileOptions = _google_protobuf_FileOptions; + export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type MessageOptions = _google_protobuf_MessageOptions; + export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type OneofOptions = _google_protobuf_OneofOptions; + export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceOptions = _google_protobuf_ServiceOptions; + export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; + export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; + } + export namespace api { + export type Http = _google_api_Http; + export type Http__Output = _google_api_Http__Output; + export type HttpRule = _google_api_HttpRule; + export type HttpRule__Output = _google_api_HttpRule__Output; + export type CustomHttpPattern = _google_api_CustomHttpPattern; + export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + } + } +} + +export namespace ClientInterfaces { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace Cluster { + export namespace TransportSocketMatch { + } + export namespace CustomClusterType { + } + export namespace EdsClusterConfig { + } + export namespace LbSubsetConfig { + export namespace LbSubsetSelector { + } + } + export namespace LeastRequestLbConfig { + } + export namespace RingHashLbConfig { + } + export namespace OriginalDstLbConfig { + } + export namespace CommonLbConfig { + export namespace ZoneAwareLbConfig { + } + export namespace LocalityWeightedLbConfig { + } + export namespace ConsistentHashingLbConfig { + } + } + export namespace RefreshRate { + } + } + export namespace LoadBalancingPolicy { + export namespace Policy { + } + } + export namespace UpstreamBindConfig { + } + export namespace UpstreamConnectionOptions { + } + export namespace auth { + export namespace UpstreamTlsContext { + } + export namespace DownstreamTlsContext { + } + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } + } + export namespace GenericSecret { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } + export namespace TlsParameters { + } + export namespace PrivateKeyProvider { + } + export namespace TlsCertificate { + } + export namespace TlsSessionTicketKeys { + } + export namespace CertificateValidationContext { + } + } + export namespace core { + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace HealthCheck { + export namespace Payload { + } + export namespace HttpHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace RedisHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace CustomHealthCheck { + } + export namespace TlsOptions { + } + } + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace ApiConfigSource { + } + export namespace AggregatedConfigSource { + } + export namespace SelfConfigSource { + } + export namespace RateLimitSettings { + } + export namespace ConfigSource { + } + export namespace TcpProtocolOptions { + } + export namespace UpstreamHttpProtocolOptions { + } + export namespace HttpProtocolOptions { + } + export namespace Http1ProtocolOptions { + export namespace HeaderKeyFormat { + export namespace ProperCaseWords { + } + } + } + export namespace Http2ProtocolOptions { + export namespace SettingsParameter { + } + } + export namespace GrpcProtocolOptions { + } + export namespace SocketOption { + } + export namespace HttpUri { + } + export namespace BackoffStrategy { + } + export namespace EventServiceConfig { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + export namespace cluster { + export namespace CircuitBreakers { + export namespace Thresholds { + export namespace RetryBudget { + } + } + } + export namespace Filter { + } + export namespace OutlierDetection { + } + } + export namespace ClusterLoadAssignment { + export namespace Policy { + export namespace DropOverload { + } + } + } + export namespace endpoint { + export namespace Endpoint { + export namespace HealthCheckConfig { + } + } + export namespace LbEndpoint { + } + export namespace LocalityLbEndpoints { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace matcher { + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Any { + } + export namespace Duration { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Timestamp { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Empty { + } + } + export namespace api { + export namespace Http { + } + export namespace HttpRule { + } + export namespace CustomHttpPattern { + } + } + } +} + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + api: { + v2: { + Cluster: MessageTypeDefinition + LoadBalancingPolicy: MessageTypeDefinition + UpstreamBindConfig: MessageTypeDefinition + UpstreamConnectionOptions: MessageTypeDefinition + auth: { + UpstreamTlsContext: MessageTypeDefinition + DownstreamTlsContext: MessageTypeDefinition + CommonTlsContext: MessageTypeDefinition + GenericSecret: MessageTypeDefinition + SdsSecretConfig: MessageTypeDefinition + Secret: MessageTypeDefinition + TlsParameters: MessageTypeDefinition + PrivateKeyProvider: MessageTypeDefinition + TlsCertificate: MessageTypeDefinition + TlsSessionTicketKeys: MessageTypeDefinition + CertificateValidationContext: MessageTypeDefinition + } + core: { + RoutingPriority: EnumTypeDefinition + RequestMethod: EnumTypeDefinition + TrafficDirection: EnumTypeDefinition + Locality: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + Extension: MessageTypeDefinition + Node: MessageTypeDefinition + Metadata: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + DataSource: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + TransportSocket: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + HealthCheck: MessageTypeDefinition + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + ApiConfigSource: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + TcpProtocolOptions: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition + SocketOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + EventServiceConfig: MessageTypeDefinition + GrpcService: MessageTypeDefinition + } + cluster: { + CircuitBreakers: MessageTypeDefinition + Filter: MessageTypeDefinition + OutlierDetection: MessageTypeDefinition + } + ClusterLoadAssignment: MessageTypeDefinition + endpoint: { + Endpoint: MessageTypeDefinition + LbEndpoint: MessageTypeDefinition + LocalityLbEndpoints: MessageTypeDefinition + } + } + } + type: { + Percent: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Int32Range: MessageTypeDefinition + DoubleRange: MessageTypeDefinition + matcher: { + StringMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + } + CodecClientType: EnumTypeDefinition + } + annotations: { + } + } + udpa: { + annotations: { + MigrateAnnotation: MessageTypeDefinition + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + FieldRules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + StringRules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + BytesRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + MapRules: MessageTypeDefinition + AnyRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + } + google: { + protobuf: { + Any: MessageTypeDefinition + Duration: MessageTypeDefinition + Struct: MessageTypeDefinition + Value: MessageTypeDefinition + NullValue: EnumTypeDefinition + ListValue: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + FloatValue: MessageTypeDefinition + Int64Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + Int32Value: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + BoolValue: MessageTypeDefinition + StringValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + Timestamp: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + FileOptions: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Empty: MessageTypeDefinition + } + api: { + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + CustomHttpPattern: MessageTypeDefinition + } + } +} + +export namespace ServiceHandlers { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace Cluster { + export namespace TransportSocketMatch { + } + export namespace CustomClusterType { + } + export namespace EdsClusterConfig { + } + export namespace LbSubsetConfig { + export namespace LbSubsetSelector { + } + } + export namespace LeastRequestLbConfig { + } + export namespace RingHashLbConfig { + } + export namespace OriginalDstLbConfig { + } + export namespace CommonLbConfig { + export namespace ZoneAwareLbConfig { + } + export namespace LocalityWeightedLbConfig { + } + export namespace ConsistentHashingLbConfig { + } + } + export namespace RefreshRate { + } + } + export namespace LoadBalancingPolicy { + export namespace Policy { + } + } + export namespace UpstreamBindConfig { + } + export namespace UpstreamConnectionOptions { + } + export namespace auth { + export namespace UpstreamTlsContext { + } + export namespace DownstreamTlsContext { + } + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } + } + export namespace GenericSecret { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } + export namespace TlsParameters { + } + export namespace PrivateKeyProvider { + } + export namespace TlsCertificate { + } + export namespace TlsSessionTicketKeys { + } + export namespace CertificateValidationContext { + } + } + export namespace core { + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace HealthCheck { + export namespace Payload { + } + export namespace HttpHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace RedisHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace CustomHealthCheck { + } + export namespace TlsOptions { + } + } + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace ApiConfigSource { + } + export namespace AggregatedConfigSource { + } + export namespace SelfConfigSource { + } + export namespace RateLimitSettings { + } + export namespace ConfigSource { + } + export namespace TcpProtocolOptions { + } + export namespace UpstreamHttpProtocolOptions { + } + export namespace HttpProtocolOptions { + } + export namespace Http1ProtocolOptions { + export namespace HeaderKeyFormat { + export namespace ProperCaseWords { + } + } + } + export namespace Http2ProtocolOptions { + export namespace SettingsParameter { + } + } + export namespace GrpcProtocolOptions { + } + export namespace SocketOption { + } + export namespace HttpUri { + } + export namespace BackoffStrategy { + } + export namespace EventServiceConfig { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + export namespace cluster { + export namespace CircuitBreakers { + export namespace Thresholds { + export namespace RetryBudget { + } + } + } + export namespace Filter { + } + export namespace OutlierDetection { + } + } + export namespace ClusterLoadAssignment { + export namespace Policy { + export namespace DropOverload { + } + } + } + export namespace endpoint { + export namespace Endpoint { + export namespace HealthCheckConfig { + } + } + export namespace LbEndpoint { + } + export namespace LocalityLbEndpoints { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace matcher { + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Any { + } + export namespace Duration { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Timestamp { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Empty { + } + } + export namespace api { + export namespace Http { + } + export namespace HttpRule { + } + export namespace CustomHttpPattern { + } + } + } +} diff --git a/packages/grpc-js/src/generated/endpoint.d.ts b/packages/grpc-js/src/generated/endpoint.d.ts new file mode 100644 index 000000000..e796f717f --- /dev/null +++ b/packages/grpc-js/src/generated/endpoint.d.ts @@ -0,0 +1,1140 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; +import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; +import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; +import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; +import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; +import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; + +export namespace messages { + export namespace envoy { + export namespace api { + export namespace v2 { + export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; + export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; + export namespace endpoint { + export type Endpoint = _envoy_api_v2_endpoint_Endpoint; + export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; + export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; + export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; + export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; + export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; + } + export namespace core { + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type BuildVersion = _envoy_api_v2_core_BuildVersion; + export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type Extension = _envoy_api_v2_core_Extension; + export type Extension__Output = _envoy_api_v2_core_Extension__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type HeaderValue = _envoy_api_v2_core_HeaderValue; + export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type HealthStatus = _envoy_api_v2_core_HealthStatus; + export type HealthCheck = _envoy_api_v2_core_HealthCheck; + export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; + export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + } + } + } + export namespace type { + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; + export type FractionalPercent = _envoy_type_FractionalPercent; + export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; + export type CodecClientType = _envoy_type_CodecClientType; + export namespace matcher { + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + } + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; + } + } + export namespace validate { + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type KnownRegex = _validate_KnownRegex; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + } + export namespace google { + export namespace protobuf { + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type BoolValue = _google_protobuf_BoolValue; + export type BoolValue__Output = _google_protobuf_BoolValue__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type BytesValue = _google_protobuf_BytesValue; + export type BytesValue__Output = _google_protobuf_BytesValue__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type DescriptorProto = _google_protobuf_DescriptorProto; + export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; + export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; + export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type FileOptions = _google_protobuf_FileOptions; + export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type MessageOptions = _google_protobuf_MessageOptions; + export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type OneofOptions = _google_protobuf_OneofOptions; + export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceOptions = _google_protobuf_ServiceOptions; + export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; + export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; + export type NullValue = _google_protobuf_NullValue; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; + } + export namespace api { + export type Http = _google_api_Http; + export type Http__Output = _google_api_Http__Output; + export type HttpRule = _google_api_HttpRule; + export type HttpRule__Output = _google_api_HttpRule__Output; + export type CustomHttpPattern = _google_api_CustomHttpPattern; + export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + } + } +} + +export namespace ClientInterfaces { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace ClusterLoadAssignment { + export namespace Policy { + export namespace DropOverload { + } + } + } + export namespace endpoint { + export namespace Endpoint { + export namespace HealthCheckConfig { + } + } + export namespace LbEndpoint { + } + export namespace LocalityLbEndpoints { + } + } + export namespace core { + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace HealthCheck { + export namespace Payload { + } + export namespace HttpHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace RedisHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace CustomHealthCheck { + } + export namespace TlsOptions { + } + } + export namespace SocketOption { + } + export namespace HttpUri { + } + export namespace EventServiceConfig { + } + export namespace BackoffStrategy { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + export namespace matcher { + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Duration { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Timestamp { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Any { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace Empty { + } + } + export namespace api { + export namespace Http { + } + export namespace HttpRule { + } + export namespace CustomHttpPattern { + } + } + } +} + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + api: { + v2: { + ClusterLoadAssignment: MessageTypeDefinition + endpoint: { + Endpoint: MessageTypeDefinition + LbEndpoint: MessageTypeDefinition + LocalityLbEndpoints: MessageTypeDefinition + } + core: { + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RequestMethod: EnumTypeDefinition + TrafficDirection: EnumTypeDefinition + Locality: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + Extension: MessageTypeDefinition + Node: MessageTypeDefinition + Metadata: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + DataSource: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + TransportSocket: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + HealthCheck: MessageTypeDefinition + SocketOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + EventServiceConfig: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + GrpcService: MessageTypeDefinition + } + } + } + type: { + Percent: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + CodecClientType: EnumTypeDefinition + matcher: { + StringMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + } + Int64Range: MessageTypeDefinition + Int32Range: MessageTypeDefinition + DoubleRange: MessageTypeDefinition + } + annotations: { + } + } + udpa: { + annotations: { + MigrateAnnotation: MessageTypeDefinition + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + FieldRules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + StringRules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + BytesRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + MapRules: MessageTypeDefinition + AnyRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + } + google: { + protobuf: { + Duration: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + FloatValue: MessageTypeDefinition + Int64Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + Int32Value: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + BoolValue: MessageTypeDefinition + StringValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + Timestamp: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + FileOptions: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Any: MessageTypeDefinition + Struct: MessageTypeDefinition + Value: MessageTypeDefinition + NullValue: EnumTypeDefinition + ListValue: MessageTypeDefinition + Empty: MessageTypeDefinition + } + api: { + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + CustomHttpPattern: MessageTypeDefinition + } + } +} + +export namespace ServiceHandlers { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace ClusterLoadAssignment { + export namespace Policy { + export namespace DropOverload { + } + } + } + export namespace endpoint { + export namespace Endpoint { + export namespace HealthCheckConfig { + } + } + export namespace LbEndpoint { + } + export namespace LocalityLbEndpoints { + } + } + export namespace core { + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace HealthCheck { + export namespace Payload { + } + export namespace HttpHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace RedisHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace CustomHealthCheck { + } + export namespace TlsOptions { + } + } + export namespace SocketOption { + } + export namespace HttpUri { + } + export namespace EventServiceConfig { + } + export namespace BackoffStrategy { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + export namespace matcher { + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Duration { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Timestamp { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Any { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace Empty { + } + } + export namespace api { + export namespace Http { + } + export namespace HttpRule { + } + export namespace CustomHttpPattern { + } + } + } +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.d.ts new file mode 100644 index 000000000..816031726 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.d.ts @@ -0,0 +1,339 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from '../../../envoy/api/v2/ClusterLoadAssignment'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from '../../../envoy/api/v2/core/HealthCheck'; +import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from '../../../envoy/api/v2/cluster/CircuitBreakers'; +import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from '../../../envoy/api/v2/auth/UpstreamTlsContext'; +import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../envoy/api/v2/core/HttpProtocolOptions'; +import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http1ProtocolOptions'; +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http2ProtocolOptions'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from '../../../envoy/api/v2/cluster/OutlierDetection'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from '../../../envoy/api/v2/core/BindConfig'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../envoy/api/v2/core/TransportSocket'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; +import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from '../../../envoy/api/v2/UpstreamConnectionOptions'; +import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from '../../../envoy/api/v2/cluster/Filter'; +import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from '../../../envoy/api/v2/LoadBalancingPolicy'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; +import { Long } from '@grpc/proto-loader'; + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_DiscoveryType { + STATIC = 0, + STRICT_DNS = 1, + LOGICAL_DNS = 2, + EDS = 3, + ORIGINAL_DST = 4, +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_LbPolicy { + ROUND_ROBIN = 0, + LEAST_REQUEST = 1, + RING_HASH = 2, + RANDOM = 3, + ORIGINAL_DST_LB = 4, + MAGLEV = 5, + CLUSTER_PROVIDED = 6, + LOAD_BALANCING_POLICY_CONFIG = 7, +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_DnsLookupFamily { + AUTO = 0, + V4_ONLY = 1, + V6_ONLY = 2, +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_ClusterProtocolSelection { + USE_CONFIGURED_PROTOCOL = 0, + USE_DOWNSTREAM_PROTOCOL = 1, +} + +export interface _envoy_api_v2_Cluster_TransportSocketMatch { + 'name'?: (string); + 'match'?: (_google_protobuf_Struct); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); +} + +export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { + 'name': (string); + 'match': (_google_protobuf_Struct__Output); + 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); +} + +export interface _envoy_api_v2_Cluster_CustomClusterType { + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any); +} + +export interface _envoy_api_v2_Cluster_CustomClusterType__Output { + 'name': (string); + 'typed_config': (_google_protobuf_Any__Output); +} + +export interface _envoy_api_v2_Cluster_EdsClusterConfig { + 'eds_config'?: (_envoy_api_v2_core_ConfigSource); + 'service_name'?: (string); +} + +export interface _envoy_api_v2_Cluster_EdsClusterConfig__Output { + 'eds_config': (_envoy_api_v2_core_ConfigSource__Output); + 'service_name': (string); +} + +export interface _envoy_api_v2_Cluster_LbSubsetConfig { + 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); + 'default_subset'?: (_google_protobuf_Struct); + 'subset_selectors'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector)[]; + 'locality_weight_aware'?: (boolean); + 'scale_locality_weight'?: (boolean); + 'panic_mode_any'?: (boolean); + 'list_as_any'?: (boolean); +} + +export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { + 'fallback_policy': (keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); + 'default_subset': (_google_protobuf_Struct__Output); + 'subset_selectors': (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector__Output)[]; + 'locality_weight_aware': (boolean); + 'scale_locality_weight': (boolean); + 'panic_mode_any': (boolean); + 'list_as_any': (boolean); +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy { + NO_FALLBACK = 0, + ANY_ENDPOINT = 1, + DEFAULT_SUBSET = 2, +} + +export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector { + 'keys'?: (string)[]; + 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); + 'fallback_keys_subset'?: (string)[]; +} + +export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector__Output { + 'keys': (string)[]; + 'fallback_policy': (keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); + 'fallback_keys_subset': (string)[]; +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy { + NOT_DEFINED = 0, + NO_FALLBACK = 1, + ANY_ENDPOINT = 2, + DEFAULT_SUBSET = 3, + KEYS_SUBSET = 4, +} + +export interface _envoy_api_v2_Cluster_LeastRequestLbConfig { + 'choice_count'?: (_google_protobuf_UInt32Value); +} + +export interface _envoy_api_v2_Cluster_LeastRequestLbConfig__Output { + 'choice_count': (_google_protobuf_UInt32Value__Output); +} + +export interface _envoy_api_v2_Cluster_RingHashLbConfig { + 'minimum_ring_size'?: (_google_protobuf_UInt64Value); + 'hash_function'?: (_envoy_api_v2_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + 'maximum_ring_size'?: (_google_protobuf_UInt64Value); +} + +export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { + 'minimum_ring_size': (_google_protobuf_UInt64Value__Output); + 'hash_function': (keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + 'maximum_ring_size': (_google_protobuf_UInt64Value__Output); +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { + XX_HASH = 0, + MURMUR_HASH_2 = 1, +} + +export interface _envoy_api_v2_Cluster_OriginalDstLbConfig { + 'use_http_header'?: (boolean); +} + +export interface _envoy_api_v2_Cluster_OriginalDstLbConfig__Output { + 'use_http_header': (boolean); +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig { + 'healthy_panic_threshold'?: (_envoy_type_Percent); + 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig); + 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig); + 'update_merge_window'?: (_google_protobuf_Duration); + 'ignore_new_hosts_until_first_hc'?: (boolean); + 'close_connections_on_host_set_change'?: (boolean); + 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig); + 'locality_config_specifier'?: "zone_aware_lb_config"|"locality_weighted_lb_config"; +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { + 'healthy_panic_threshold': (_envoy_type_Percent__Output); + 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); + 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); + 'update_merge_window': (_google_protobuf_Duration__Output); + 'ignore_new_hosts_until_first_hc': (boolean); + 'close_connections_on_host_set_change': (boolean); + 'consistent_hashing_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); + 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { + 'routing_enabled'?: (_envoy_type_Percent); + 'min_cluster_size'?: (_google_protobuf_UInt64Value); + 'fail_traffic_on_panic'?: (boolean); +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { + 'routing_enabled': (_envoy_type_Percent__Output); + 'min_cluster_size': (_google_protobuf_UInt64Value__Output); + 'fail_traffic_on_panic': (boolean); +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig { + 'use_hostname_for_hashing'?: (boolean); +} + +export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output { + 'use_hostname_for_hashing': (boolean); +} + +export interface _envoy_api_v2_Cluster_RefreshRate { + 'base_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration); +} + +export interface _envoy_api_v2_Cluster_RefreshRate__Output { + 'base_interval': (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output); +} + +export interface Cluster { + 'transport_socket_matches'?: (_envoy_api_v2_Cluster_TransportSocketMatch)[]; + 'name'?: (string); + 'alt_stat_name'?: (string); + 'type'?: (_envoy_api_v2_Cluster_DiscoveryType | keyof typeof _envoy_api_v2_Cluster_DiscoveryType); + 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType); + 'eds_cluster_config'?: (_envoy_api_v2_Cluster_EdsClusterConfig); + 'connect_timeout'?: (_google_protobuf_Duration); + 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'lb_policy'?: (_envoy_api_v2_Cluster_LbPolicy | keyof typeof _envoy_api_v2_Cluster_LbPolicy); + 'hosts'?: (_envoy_api_v2_core_Address)[]; + 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment); + 'health_checks'?: (_envoy_api_v2_core_HealthCheck)[]; + 'max_requests_per_connection'?: (_google_protobuf_UInt32Value); + 'circuit_breakers'?: (_envoy_api_v2_cluster_CircuitBreakers); + 'tls_context'?: (_envoy_api_v2_auth_UpstreamTlsContext); + 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions); + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); + 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); + 'extension_protocol_options'?: (_google_protobuf_Struct); + 'typed_extension_protocol_options'?: (_google_protobuf_Any); + 'dns_refresh_rate'?: (_google_protobuf_Duration); + 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate); + 'respect_dns_ttl'?: (boolean); + 'dns_lookup_family'?: (_envoy_api_v2_Cluster_DnsLookupFamily | keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); + 'dns_resolvers'?: (_envoy_api_v2_core_Address)[]; + 'use_tcp_for_dns_lookups'?: (boolean); + 'outlier_detection'?: (_envoy_api_v2_cluster_OutlierDetection); + 'cleanup_interval'?: (_google_protobuf_Duration); + 'upstream_bind_config'?: (_envoy_api_v2_core_BindConfig); + 'lb_subset_config'?: (_envoy_api_v2_Cluster_LbSubsetConfig); + 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig); + 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig); + 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig); + 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); + 'metadata'?: (_envoy_api_v2_core_Metadata); + 'protocol_selection'?: (_envoy_api_v2_Cluster_ClusterProtocolSelection | keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + 'upstream_connection_options'?: (_envoy_api_v2_UpstreamConnectionOptions); + 'close_connections_on_host_health_failure'?: (boolean); + 'drain_connections_on_host_removal'?: (boolean); + 'filters'?: (_envoy_api_v2_cluster_Filter)[]; + 'load_balancing_policy'?: (_envoy_api_v2_LoadBalancingPolicy); + 'lrs_server'?: (_envoy_api_v2_core_ConfigSource); + 'track_timeout_budgets'?: (boolean); + 'cluster_discovery_type'?: "type"|"cluster_type"; + 'lb_config'?: "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; +} + +export interface Cluster__Output { + 'transport_socket_matches': (_envoy_api_v2_Cluster_TransportSocketMatch__Output)[]; + 'name': (string); + 'alt_stat_name': (string); + 'type'?: (keyof typeof _envoy_api_v2_Cluster_DiscoveryType); + 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType__Output); + 'eds_cluster_config': (_envoy_api_v2_Cluster_EdsClusterConfig__Output); + 'connect_timeout': (_google_protobuf_Duration__Output); + 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'lb_policy': (keyof typeof _envoy_api_v2_Cluster_LbPolicy); + 'hosts': (_envoy_api_v2_core_Address__Output)[]; + 'load_assignment': (_envoy_api_v2_ClusterLoadAssignment__Output); + 'health_checks': (_envoy_api_v2_core_HealthCheck__Output)[]; + 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output); + 'circuit_breakers': (_envoy_api_v2_cluster_CircuitBreakers__Output); + 'tls_context': (_envoy_api_v2_auth_UpstreamTlsContext__Output); + 'upstream_http_protocol_options': (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); + 'common_http_protocol_options': (_envoy_api_v2_core_HttpProtocolOptions__Output); + 'http_protocol_options': (_envoy_api_v2_core_Http1ProtocolOptions__Output); + 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); + 'extension_protocol_options': (_google_protobuf_Struct__Output); + 'typed_extension_protocol_options': (_google_protobuf_Any__Output); + 'dns_refresh_rate': (_google_protobuf_Duration__Output); + 'dns_failure_refresh_rate': (_envoy_api_v2_Cluster_RefreshRate__Output); + 'respect_dns_ttl': (boolean); + 'dns_lookup_family': (keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); + 'dns_resolvers': (_envoy_api_v2_core_Address__Output)[]; + 'use_tcp_for_dns_lookups': (boolean); + 'outlier_detection': (_envoy_api_v2_cluster_OutlierDetection__Output); + 'cleanup_interval': (_google_protobuf_Duration__Output); + 'upstream_bind_config': (_envoy_api_v2_core_BindConfig__Output); + 'lb_subset_config': (_envoy_api_v2_Cluster_LbSubsetConfig__Output); + 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig__Output); + 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig__Output); + 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig__Output); + 'common_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig__Output); + 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'protocol_selection': (keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + 'upstream_connection_options': (_envoy_api_v2_UpstreamConnectionOptions__Output); + 'close_connections_on_host_health_failure': (boolean); + 'drain_connections_on_host_removal': (boolean); + 'filters': (_envoy_api_v2_cluster_Filter__Output)[]; + 'load_balancing_policy': (_envoy_api_v2_LoadBalancingPolicy__Output); + 'lrs_server': (_envoy_api_v2_core_ConfigSource__Output); + 'track_timeout_budgets': (boolean); + 'cluster_discovery_type': "type"|"cluster_type"; + 'lb_config': "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.d.ts new file mode 100644 index 000000000..19508d3c4 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.d.ts @@ -0,0 +1,45 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint.proto + +import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from '../../../envoy/api/v2/endpoint/LocalityLbEndpoints'; +import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../envoy/api/v2/endpoint/Endpoint'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../envoy/type/FractionalPercent'; + +export interface _envoy_api_v2_ClusterLoadAssignment_Policy { + 'drop_overloads'?: (_envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload)[]; + 'overprovisioning_factor'?: (_google_protobuf_UInt32Value); + 'endpoint_stale_after'?: (_google_protobuf_Duration); + 'disable_overprovisioning'?: (boolean); +} + +export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { + 'drop_overloads': (_envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output)[]; + 'overprovisioning_factor': (_google_protobuf_UInt32Value__Output); + 'endpoint_stale_after': (_google_protobuf_Duration__Output); + 'disable_overprovisioning': (boolean); +} + +export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload { + 'category'?: (string); + 'drop_percentage'?: (_envoy_type_FractionalPercent); +} + +export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output { + 'category': (string); + 'drop_percentage': (_envoy_type_FractionalPercent__Output); +} + +export interface ClusterLoadAssignment { + 'cluster_name'?: (string); + 'endpoints'?: (_envoy_api_v2_endpoint_LocalityLbEndpoints)[]; + 'named_endpoints'?: (_envoy_api_v2_endpoint_Endpoint); + 'policy'?: (_envoy_api_v2_ClusterLoadAssignment_Policy); +} + +export interface ClusterLoadAssignment__Output { + 'cluster_name': (string); + 'endpoints': (_envoy_api_v2_endpoint_LocalityLbEndpoints__Output)[]; + 'named_endpoints': (_envoy_api_v2_endpoint_Endpoint__Output); + 'policy': (_envoy_api_v2_ClusterLoadAssignment_Policy__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.d.ts new file mode 100644 index 000000000..bd09411a8 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.d.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/api/v2/discovery.proto + +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; + +export interface DeltaDiscoveryRequest { + 'node'?: (_envoy_api_v2_core_Node); + 'type_url'?: (string); + 'resource_names_subscribe'?: (string)[]; + 'resource_names_unsubscribe'?: (string)[]; + 'initial_resource_versions'?: (string); + 'response_nonce'?: (string); + 'error_detail'?: (_google_rpc_Status); +} + +export interface DeltaDiscoveryRequest__Output { + 'node': (_envoy_api_v2_core_Node__Output); + 'type_url': (string); + 'resource_names_subscribe': (string)[]; + 'resource_names_unsubscribe': (string)[]; + 'initial_resource_versions': (string); + 'response_nonce': (string); + 'error_detail': (_google_rpc_Status__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.d.ts new file mode 100644 index 000000000..5a6e8c643 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.d.ts @@ -0,0 +1,19 @@ +// Original file: deps/envoy-api/envoy/api/v2/discovery.proto + +import { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from '../../../envoy/api/v2/Resource'; + +export interface DeltaDiscoveryResponse { + 'system_version_info'?: (string); + 'resources'?: (_envoy_api_v2_Resource)[]; + 'type_url'?: (string); + 'removed_resources'?: (string)[]; + 'nonce'?: (string); +} + +export interface DeltaDiscoveryResponse__Output { + 'system_version_info': (string); + 'resources': (_envoy_api_v2_Resource__Output)[]; + 'type_url': (string); + 'removed_resources': (string)[]; + 'nonce': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.d.ts new file mode 100644 index 000000000..33b8fcf26 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/envoy-api/envoy/api/v2/discovery.proto + +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; + +export interface DiscoveryRequest { + 'version_info'?: (string); + 'node'?: (_envoy_api_v2_core_Node); + 'resource_names'?: (string)[]; + 'type_url'?: (string); + 'response_nonce'?: (string); + 'error_detail'?: (_google_rpc_Status); +} + +export interface DiscoveryRequest__Output { + 'version_info': (string); + 'node': (_envoy_api_v2_core_Node__Output); + 'resource_names': (string)[]; + 'type_url': (string); + 'response_nonce': (string); + 'error_detail': (_google_rpc_Status__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.d.ts new file mode 100644 index 000000000..5f209372e --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/envoy-api/envoy/api/v2/discovery.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from '../../../envoy/api/v2/core/ControlPlane'; + +export interface DiscoveryResponse { + 'version_info'?: (string); + 'resources'?: (_google_protobuf_Any)[]; + 'canary'?: (boolean); + 'type_url'?: (string); + 'nonce'?: (string); + 'control_plane'?: (_envoy_api_v2_core_ControlPlane); +} + +export interface DiscoveryResponse__Output { + 'version_info': (string); + 'resources': (_google_protobuf_Any__Output)[]; + 'canary': (boolean); + 'type_url': (string); + 'nonce': (string); + 'control_plane': (_envoy_api_v2_core_ControlPlane__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Listener.d.ts new file mode 100644 index 000000000..c14e3fdb8 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/Listener.d.ts @@ -0,0 +1,93 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener.proto + +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +import { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from '../../../envoy/api/v2/listener/FilterChain'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; +import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from '../../../envoy/api/v2/listener/ListenerFilter'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../envoy/api/v2/core/SocketOption'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from '../../../envoy/api/v2/core/TrafficDirection'; +import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from '../../../envoy/api/v2/listener/UdpListenerConfig'; +import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from '../../../envoy/config/listener/v2/ApiListener'; +import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../envoy/config/filter/accesslog/v2/AccessLog'; + +// Original file: deps/envoy-api/envoy/api/v2/listener.proto + +export enum _envoy_api_v2_Listener_DrainType { + DEFAULT = 0, + MODIFY_ONLY = 1, +} + +export interface _envoy_api_v2_Listener_DeprecatedV1 { + 'bind_to_port'?: (_google_protobuf_BoolValue); +} + +export interface _envoy_api_v2_Listener_DeprecatedV1__Output { + 'bind_to_port': (_google_protobuf_BoolValue__Output); +} + +export interface _envoy_api_v2_Listener_ConnectionBalanceConfig { + 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance); + 'balance_type'?: "exact_balance"; +} + +export interface _envoy_api_v2_Listener_ConnectionBalanceConfig__Output { + 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output); + 'balance_type': "exact_balance"; +} + +export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { +} + +export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output { +} + +export interface Listener { + 'name'?: (string); + 'address'?: (_envoy_api_v2_core_Address); + 'filter_chains'?: (_envoy_api_v2_listener_FilterChain)[]; + 'use_original_dst'?: (_google_protobuf_BoolValue); + 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'metadata'?: (_envoy_api_v2_core_Metadata); + 'deprecated_v1'?: (_envoy_api_v2_Listener_DeprecatedV1); + 'drain_type'?: (_envoy_api_v2_Listener_DrainType | keyof typeof _envoy_api_v2_Listener_DrainType); + 'listener_filters'?: (_envoy_api_v2_listener_ListenerFilter)[]; + 'listener_filters_timeout'?: (_google_protobuf_Duration); + 'continue_on_listener_filters_timeout'?: (boolean); + 'transparent'?: (_google_protobuf_BoolValue); + 'freebind'?: (_google_protobuf_BoolValue); + 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; + 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value); + 'traffic_direction'?: (_envoy_api_v2_core_TrafficDirection | keyof typeof _envoy_api_v2_core_TrafficDirection); + 'udp_listener_config'?: (_envoy_api_v2_listener_UdpListenerConfig); + 'api_listener'?: (_envoy_config_listener_v2_ApiListener); + 'connection_balance_config'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig); + 'reuse_port'?: (boolean); + 'access_log'?: (_envoy_config_filter_accesslog_v2_AccessLog)[]; +} + +export interface Listener__Output { + 'name': (string); + 'address': (_envoy_api_v2_core_Address__Output); + 'filter_chains': (_envoy_api_v2_listener_FilterChain__Output)[]; + 'use_original_dst': (_google_protobuf_BoolValue__Output); + 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'deprecated_v1': (_envoy_api_v2_Listener_DeprecatedV1__Output); + 'drain_type': (keyof typeof _envoy_api_v2_Listener_DrainType); + 'listener_filters': (_envoy_api_v2_listener_ListenerFilter__Output)[]; + 'listener_filters_timeout': (_google_protobuf_Duration__Output); + 'continue_on_listener_filters_timeout': (boolean); + 'transparent': (_google_protobuf_BoolValue__Output); + 'freebind': (_google_protobuf_BoolValue__Output); + 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; + 'tcp_fast_open_queue_length': (_google_protobuf_UInt32Value__Output); + 'traffic_direction': (keyof typeof _envoy_api_v2_core_TrafficDirection); + 'udp_listener_config': (_envoy_api_v2_listener_UdpListenerConfig__Output); + 'api_listener': (_envoy_config_listener_v2_ApiListener__Output); + 'connection_balance_config': (_envoy_api_v2_Listener_ConnectionBalanceConfig__Output); + 'reuse_port': (boolean); + 'access_log': (_envoy_config_filter_accesslog_v2_AccessLog__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.d.ts new file mode 100644 index 000000000..13af1f021 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.d.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +export interface _envoy_api_v2_LoadBalancingPolicy_Policy { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); +} + +export interface _envoy_api_v2_LoadBalancingPolicy_Policy__Output { + 'name': (string); + 'config': (_google_protobuf_Struct__Output); + 'typed_config': (_google_protobuf_Any__Output); +} + +export interface LoadBalancingPolicy { + 'policies'?: (_envoy_api_v2_LoadBalancingPolicy_Policy)[]; +} + +export interface LoadBalancingPolicy__Output { + 'policies': (_envoy_api_v2_LoadBalancingPolicy_Policy__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Resource.d.ts new file mode 100644 index 000000000..56dae2fc1 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/Resource.d.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/api/v2/discovery.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +export interface Resource { + 'name'?: (string); + 'aliases'?: (string)[]; + 'version'?: (string); + 'resource'?: (_google_protobuf_Any); +} + +export interface Resource__Output { + 'name': (string); + 'aliases': (string)[]; + 'version': (string); + 'resource': (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.d.ts new file mode 100644 index 000000000..5e8c67260 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.d.ts @@ -0,0 +1,32 @@ +// Original file: deps/envoy-api/envoy/api/v2/route.proto + +import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from '../../../envoy/api/v2/route/VirtualHost'; +import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../envoy/api/v2/core/HeaderValueOption'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; + +export interface RouteConfiguration { + 'name'?: (string); + 'virtual_hosts'?: (_envoy_api_v2_route_VirtualHost)[]; + 'vhds'?: (_envoy_api_v2_Vhds); + 'internal_only_headers'?: (string)[]; + 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_remove'?: (string)[]; + 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_remove'?: (string)[]; + 'most_specific_header_mutations_wins'?: (boolean); + 'validate_clusters'?: (_google_protobuf_BoolValue); +} + +export interface RouteConfiguration__Output { + 'name': (string); + 'virtual_hosts': (_envoy_api_v2_route_VirtualHost__Output)[]; + 'vhds': (_envoy_api_v2_Vhds__Output); + 'internal_only_headers': (string)[]; + 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_remove': (string)[]; + 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_remove': (string)[]; + 'most_specific_header_mutations_wins': (boolean); + 'validate_clusters': (_google_protobuf_BoolValue__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.d.ts new file mode 100644 index 000000000..9c6d979c8 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; + +export interface UpstreamBindConfig { + 'source_address'?: (_envoy_api_v2_core_Address); +} + +export interface UpstreamBindConfig__Output { + 'source_address': (_envoy_api_v2_core_Address__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.d.ts new file mode 100644 index 000000000..3dfda2164 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from '../../../envoy/api/v2/core/TcpKeepalive'; + +export interface UpstreamConnectionOptions { + 'tcp_keepalive'?: (_envoy_api_v2_core_TcpKeepalive); +} + +export interface UpstreamConnectionOptions__Output { + 'tcp_keepalive': (_envoy_api_v2_core_TcpKeepalive__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.d.ts new file mode 100644 index 000000000..62214f619 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/route.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; + +export interface Vhds { + 'config_source'?: (_envoy_api_v2_core_ConfigSource); +} + +export interface Vhds__Output { + 'config_source': (_envoy_api_v2_core_ConfigSource__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.d.ts new file mode 100644 index 000000000..b34aa4ba2 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.d.ts @@ -0,0 +1,38 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + +export enum _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification { + VERIFY_TRUST_CHAIN = 0, + ACCEPT_UNTRUSTED = 1, +} + +export interface CertificateValidationContext { + 'trusted_ca'?: (_envoy_api_v2_core_DataSource); + 'verify_certificate_spki'?: (string)[]; + 'verify_certificate_hash'?: (string)[]; + 'verify_subject_alt_name'?: (string)[]; + 'match_subject_alt_names'?: (_envoy_type_matcher_StringMatcher)[]; + 'require_ocsp_staple'?: (_google_protobuf_BoolValue); + 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue); + 'crl'?: (_envoy_api_v2_core_DataSource); + 'allow_expired_certificate'?: (boolean); + 'trust_chain_verification'?: (_envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification | keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); +} + +export interface CertificateValidationContext__Output { + 'trusted_ca': (_envoy_api_v2_core_DataSource__Output); + 'verify_certificate_spki': (string)[]; + 'verify_certificate_hash': (string)[]; + 'verify_subject_alt_name': (string)[]; + 'match_subject_alt_names': (_envoy_type_matcher_StringMatcher__Output)[]; + 'require_ocsp_staple': (_google_protobuf_BoolValue__Output); + 'require_signed_certificate_timestamp': (_google_protobuf_BoolValue__Output); + 'crl': (_envoy_api_v2_core_DataSource__Output); + 'allow_expired_certificate': (boolean); + 'trust_chain_verification': (keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.d.ts new file mode 100644 index 000000000..039ba89c1 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.d.ts @@ -0,0 +1,38 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto + +import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from '../../../../envoy/api/v2/auth/TlsParameters'; +import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; +import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; + +export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext { + 'default_validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); + 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); +} + +export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output { + 'default_validation_context': (_envoy_api_v2_auth_CertificateValidationContext__Output); + 'validation_context_sds_secret_config': (_envoy_api_v2_auth_SdsSecretConfig__Output); +} + +export interface CommonTlsContext { + 'tls_params'?: (_envoy_api_v2_auth_TlsParameters); + 'tls_certificates'?: (_envoy_api_v2_auth_TlsCertificate)[]; + 'tls_certificate_sds_secret_configs'?: (_envoy_api_v2_auth_SdsSecretConfig)[]; + 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); + 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); + 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext); + 'alpn_protocols'?: (string)[]; + 'validation_context_type'?: "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; +} + +export interface CommonTlsContext__Output { + 'tls_params': (_envoy_api_v2_auth_TlsParameters__Output); + 'tls_certificates': (_envoy_api_v2_auth_TlsCertificate__Output)[]; + 'tls_certificate_sds_secret_configs': (_envoy_api_v2_auth_SdsSecretConfig__Output)[]; + 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); + 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); + 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output); + 'alpn_protocols': (string)[]; + 'validation_context_type': "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.d.ts new file mode 100644 index 000000000..aaef34234 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.d.ts @@ -0,0 +1,29 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto + +import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +export interface DownstreamTlsContext { + 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext); + 'require_client_certificate'?: (_google_protobuf_BoolValue); + 'require_sni'?: (_google_protobuf_BoolValue); + 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); + 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); + 'disable_stateless_session_resumption'?: (boolean); + 'session_timeout'?: (_google_protobuf_Duration); + 'session_ticket_keys_type'?: "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; +} + +export interface DownstreamTlsContext__Output { + 'common_tls_context': (_envoy_api_v2_auth_CommonTlsContext__Output); + 'require_client_certificate': (_google_protobuf_BoolValue__Output); + 'require_sni': (_google_protobuf_BoolValue__Output); + 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); + 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); + 'disable_stateless_session_resumption'?: (boolean); + 'session_timeout': (_google_protobuf_Duration__Output); + 'session_ticket_keys_type': "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.d.ts new file mode 100644 index 000000000..5eeaffa2c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto + +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; + +export interface GenericSecret { + 'secret'?: (_envoy_api_v2_core_DataSource); +} + +export interface GenericSecret__Output { + 'secret': (_envoy_api_v2_core_DataSource__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.d.ts new file mode 100644 index 000000000..fe418a390 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface PrivateKeyProvider { + 'provider_name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface PrivateKeyProvider__Output { + 'provider_name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.d.ts new file mode 100644 index 000000000..acd9154cc --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../envoy/api/v2/core/ConfigSource'; + +export interface SdsSecretConfig { + 'name'?: (string); + 'sds_config'?: (_envoy_api_v2_core_ConfigSource); +} + +export interface SdsSecretConfig__Output { + 'name': (string); + 'sds_config': (_envoy_api_v2_core_ConfigSource__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.d.ts new file mode 100644 index 000000000..a25e6c7c1 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.d.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto + +import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; +import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; +import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; +import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from '../../../../envoy/api/v2/auth/GenericSecret'; + +export interface Secret { + 'name'?: (string); + 'tls_certificate'?: (_envoy_api_v2_auth_TlsCertificate); + 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); + 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); + 'generic_secret'?: (_envoy_api_v2_auth_GenericSecret); + 'type'?: "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; +} + +export interface Secret__Output { + 'name': (string); + 'tls_certificate'?: (_envoy_api_v2_auth_TlsCertificate__Output); + 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); + 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); + 'generic_secret'?: (_envoy_api_v2_auth_GenericSecret__Output); + 'type': "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.d.ts new file mode 100644 index 000000000..00d786e62 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from '../../../../envoy/api/v2/auth/PrivateKeyProvider'; + +export interface TlsCertificate { + 'certificate_chain'?: (_envoy_api_v2_core_DataSource); + 'private_key'?: (_envoy_api_v2_core_DataSource); + 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider); + 'password'?: (_envoy_api_v2_core_DataSource); + 'ocsp_staple'?: (_envoy_api_v2_core_DataSource); + 'signed_certificate_timestamp'?: (_envoy_api_v2_core_DataSource)[]; +} + +export interface TlsCertificate__Output { + 'certificate_chain': (_envoy_api_v2_core_DataSource__Output); + 'private_key': (_envoy_api_v2_core_DataSource__Output); + 'private_key_provider': (_envoy_api_v2_auth_PrivateKeyProvider__Output); + 'password': (_envoy_api_v2_core_DataSource__Output); + 'ocsp_staple': (_envoy_api_v2_core_DataSource__Output); + 'signed_certificate_timestamp': (_envoy_api_v2_core_DataSource__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.d.ts new file mode 100644 index 000000000..efa26951a --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.d.ts @@ -0,0 +1,26 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + + +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + +export enum _envoy_api_v2_auth_TlsParameters_TlsProtocol { + TLS_AUTO = 0, + TLSv1_0 = 1, + TLSv1_1 = 2, + TLSv1_2 = 3, + TLSv1_3 = 4, +} + +export interface TlsParameters { + 'tls_minimum_protocol_version'?: (_envoy_api_v2_auth_TlsParameters_TlsProtocol | keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + 'tls_maximum_protocol_version'?: (_envoy_api_v2_auth_TlsParameters_TlsProtocol | keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + 'cipher_suites'?: (string)[]; + 'ecdh_curves'?: (string)[]; +} + +export interface TlsParameters__Output { + 'tls_minimum_protocol_version': (keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + 'tls_maximum_protocol_version': (keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + 'cipher_suites': (string)[]; + 'ecdh_curves': (string)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.d.ts new file mode 100644 index 000000000..c9b27d26c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto + +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; + +export interface TlsSessionTicketKeys { + 'keys'?: (_envoy_api_v2_core_DataSource)[]; +} + +export interface TlsSessionTicketKeys__Output { + 'keys': (_envoy_api_v2_core_DataSource__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.d.ts new file mode 100644 index 000000000..e05f82569 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto + +import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface UpstreamTlsContext { + 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext); + 'sni'?: (string); + 'allow_renegotiation'?: (boolean); + 'max_session_keys'?: (_google_protobuf_UInt32Value); +} + +export interface UpstreamTlsContext__Output { + 'common_tls_context': (_envoy_api_v2_auth_CommonTlsContext__Output); + 'sni': (string); + 'allow_renegotiation': (boolean); + 'max_session_keys': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.d.ts new file mode 100644 index 000000000..d41112c85 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.d.ts @@ -0,0 +1,45 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto + +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../envoy/type/Percent'; + +export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds { + 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); + 'max_connections'?: (_google_protobuf_UInt32Value); + 'max_pending_requests'?: (_google_protobuf_UInt32Value); + 'max_requests'?: (_google_protobuf_UInt32Value); + 'max_retries'?: (_google_protobuf_UInt32Value); + 'retry_budget'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget); + 'track_remaining'?: (boolean); + 'max_connection_pools'?: (_google_protobuf_UInt32Value); +} + +export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { + 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); + 'max_connections': (_google_protobuf_UInt32Value__Output); + 'max_pending_requests': (_google_protobuf_UInt32Value__Output); + 'max_requests': (_google_protobuf_UInt32Value__Output); + 'max_retries': (_google_protobuf_UInt32Value__Output); + 'retry_budget': (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output); + 'track_remaining': (boolean); + 'max_connection_pools': (_google_protobuf_UInt32Value__Output); +} + +export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { + 'budget_percent'?: (_envoy_type_Percent); + 'min_retry_concurrency'?: (_google_protobuf_UInt32Value); +} + +export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output { + 'budget_percent': (_envoy_type_Percent__Output); + 'min_retry_concurrency': (_google_protobuf_UInt32Value__Output); +} + +export interface CircuitBreakers { + 'thresholds'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds)[]; +} + +export interface CircuitBreakers__Output { + 'thresholds': (_envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.d.ts new file mode 100644 index 000000000..e483c07d9 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster/filter.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface Filter { + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any); +} + +export interface Filter__Output { + 'name': (string); + 'typed_config': (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.d.ts new file mode 100644 index 000000000..278e22aea --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.d.ts @@ -0,0 +1,50 @@ +// Original file: deps/envoy-api/envoy/api/v2/cluster/outlier_detection.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +export interface OutlierDetection { + 'consecutive_5xx'?: (_google_protobuf_UInt32Value); + 'interval'?: (_google_protobuf_Duration); + 'base_ejection_time'?: (_google_protobuf_Duration); + 'max_ejection_percent'?: (_google_protobuf_UInt32Value); + 'enforcing_consecutive_5xx'?: (_google_protobuf_UInt32Value); + 'enforcing_success_rate'?: (_google_protobuf_UInt32Value); + 'success_rate_minimum_hosts'?: (_google_protobuf_UInt32Value); + 'success_rate_request_volume'?: (_google_protobuf_UInt32Value); + 'success_rate_stdev_factor'?: (_google_protobuf_UInt32Value); + 'consecutive_gateway_failure'?: (_google_protobuf_UInt32Value); + 'enforcing_consecutive_gateway_failure'?: (_google_protobuf_UInt32Value); + 'split_external_local_origin_errors'?: (boolean); + 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); + 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); + 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value); + 'failure_percentage_threshold'?: (_google_protobuf_UInt32Value); + 'enforcing_failure_percentage'?: (_google_protobuf_UInt32Value); + 'enforcing_failure_percentage_local_origin'?: (_google_protobuf_UInt32Value); + 'failure_percentage_minimum_hosts'?: (_google_protobuf_UInt32Value); + 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value); +} + +export interface OutlierDetection__Output { + 'consecutive_5xx': (_google_protobuf_UInt32Value__Output); + 'interval': (_google_protobuf_Duration__Output); + 'base_ejection_time': (_google_protobuf_Duration__Output); + 'max_ejection_percent': (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_5xx': (_google_protobuf_UInt32Value__Output); + 'enforcing_success_rate': (_google_protobuf_UInt32Value__Output); + 'success_rate_minimum_hosts': (_google_protobuf_UInt32Value__Output); + 'success_rate_request_volume': (_google_protobuf_UInt32Value__Output); + 'success_rate_stdev_factor': (_google_protobuf_UInt32Value__Output); + 'consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output); + 'split_external_local_origin_errors': (boolean); + 'consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output); + 'enforcing_local_origin_success_rate': (_google_protobuf_UInt32Value__Output); + 'failure_percentage_threshold': (_google_protobuf_UInt32Value__Output); + 'enforcing_failure_percentage': (_google_protobuf_UInt32Value__Output); + 'enforcing_failure_percentage_local_origin': (_google_protobuf_UInt32Value__Output); + 'failure_percentage_minimum_hosts': (_google_protobuf_UInt32Value__Output); + 'failure_percentage_request_volume': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Address.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Address.d.ts new file mode 100644 index 000000000..79b40931c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Address.d.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from '../../../../envoy/api/v2/core/Pipe'; + +export interface Address { + 'socket_address'?: (_envoy_api_v2_core_SocketAddress); + 'pipe'?: (_envoy_api_v2_core_Pipe); + 'address'?: "socket_address"|"pipe"; +} + +export interface Address__Output { + 'socket_address'?: (_envoy_api_v2_core_SocketAddress__Output); + 'pipe'?: (_envoy_api_v2_core_Pipe__Output); + 'address': "socket_address"|"pipe"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.d.ts new file mode 100644 index 000000000..dd0b6619b --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + + +export interface AggregatedConfigSource { +} + +export interface AggregatedConfigSource__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.d.ts new file mode 100644 index 000000000..93092c0fa --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.d.ts @@ -0,0 +1,37 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from '../../../../envoy/api/v2/core/RateLimitSettings'; + +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + +export enum _envoy_api_v2_core_ApiConfigSource_ApiType { + UNSUPPORTED_REST_LEGACY = 0, + REST = 1, + GRPC = 2, + DELTA_GRPC = 3, +} + +export interface ApiConfigSource { + 'api_type'?: (_envoy_api_v2_core_ApiConfigSource_ApiType | keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); + 'transport_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); + 'cluster_names'?: (string)[]; + 'grpc_services'?: (_envoy_api_v2_core_GrpcService)[]; + 'refresh_delay'?: (_google_protobuf_Duration); + 'request_timeout'?: (_google_protobuf_Duration); + 'rate_limit_settings'?: (_envoy_api_v2_core_RateLimitSettings); + 'set_node_on_first_message_only'?: (boolean); +} + +export interface ApiConfigSource__Output { + 'api_type': (keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); + 'transport_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); + 'cluster_names': (string)[]; + 'grpc_services': (_envoy_api_v2_core_GrpcService__Output)[]; + 'refresh_delay': (_google_protobuf_Duration__Output); + 'request_timeout': (_google_protobuf_Duration__Output); + 'rate_limit_settings': (_envoy_api_v2_core_RateLimitSettings__Output); + 'set_node_on_first_message_only': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.d.ts new file mode 100644 index 000000000..0a3952e61 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.d.ts @@ -0,0 +1,7 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + +export enum ApiVersion { + AUTO = 0, + V2 = 1, + V3 = 2, +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.d.ts new file mode 100644 index 000000000..1f8ea0b5f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.d.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from '../../../../envoy/api/v2/core/RemoteDataSource'; + +export interface AsyncDataSource { + 'local'?: (_envoy_api_v2_core_DataSource); + 'remote'?: (_envoy_api_v2_core_RemoteDataSource); + 'specifier'?: "local"|"remote"; +} + +export interface AsyncDataSource__Output { + 'local'?: (_envoy_api_v2_core_DataSource__Output); + 'remote'?: (_envoy_api_v2_core_RemoteDataSource__Output); + 'specifier': "local"|"remote"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.d.ts new file mode 100644 index 000000000..a95361e5a --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/backoff.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +export interface BackoffStrategy { + 'base_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration); +} + +export interface BackoffStrategy__Output { + 'base_interval': (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.d.ts new file mode 100644 index 000000000..05d32a072 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.d.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../../envoy/api/v2/core/SocketOption'; + +export interface BindConfig { + 'source_address'?: (_envoy_api_v2_core_SocketAddress); + 'freebind'?: (_google_protobuf_BoolValue); + 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; +} + +export interface BindConfig__Output { + 'source_address': (_envoy_api_v2_core_SocketAddress__Output); + 'freebind': (_google_protobuf_BoolValue__Output); + 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.d.ts new file mode 100644 index 000000000..1008082a2 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from '../../../../envoy/type/SemanticVersion'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; + +export interface BuildVersion { + 'version'?: (_envoy_type_SemanticVersion); + 'metadata'?: (_google_protobuf_Struct); +} + +export interface BuildVersion__Output { + 'version': (_envoy_type_SemanticVersion__Output); + 'metadata': (_google_protobuf_Struct__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.d.ts new file mode 100644 index 000000000..6c84de0c2 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface CidrRange { + 'address_prefix'?: (string); + 'prefix_len'?: (_google_protobuf_UInt32Value); +} + +export interface CidrRange__Output { + 'address_prefix': (string); + 'prefix_len': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.d.ts new file mode 100644 index 000000000..a9cd08e43 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.d.ts @@ -0,0 +1,27 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from '../../../../envoy/api/v2/core/ApiConfigSource'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from '../../../../envoy/api/v2/core/AggregatedConfigSource'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; + +export interface ConfigSource { + 'path'?: (string); + 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource); + 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource); + 'self'?: (_envoy_api_v2_core_SelfConfigSource); + 'initial_fetch_timeout'?: (_google_protobuf_Duration); + 'resource_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); + 'config_source_specifier'?: "path"|"api_config_source"|"ads"|"self"; +} + +export interface ConfigSource__Output { + 'path'?: (string); + 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource__Output); + 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource__Output); + 'self'?: (_envoy_api_v2_core_SelfConfigSource__Output); + 'initial_fetch_timeout': (_google_protobuf_Duration__Output); + 'resource_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); + 'config_source_specifier': "path"|"api_config_source"|"ads"|"self"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.d.ts new file mode 100644 index 000000000..0074cf060 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + + +export interface ControlPlane { + 'identifier'?: (string); +} + +export interface ControlPlane__Output { + 'identifier': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.d.ts new file mode 100644 index 000000000..ae5b5a302 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.d.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + + +export interface DataSource { + 'filename'?: (string); + 'inline_bytes'?: (Buffer | Uint8Array | string); + 'inline_string'?: (string); + 'specifier'?: "filename"|"inline_bytes"|"inline_string"; +} + +export interface DataSource__Output { + 'filename'?: (string); + 'inline_bytes'?: (Buffer); + 'inline_string'?: (string); + 'specifier': "filename"|"inline_bytes"|"inline_string"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.d.ts new file mode 100644 index 000000000..31601fa74 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/event_service_config.proto + +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; + +export interface EventServiceConfig { + 'grpc_service'?: (_envoy_api_v2_core_GrpcService); + 'config_source_specifier'?: "grpc_service"; +} + +export interface EventServiceConfig__Output { + 'grpc_service'?: (_envoy_api_v2_core_GrpcService__Output); + 'config_source_specifier': "grpc_service"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.d.ts new file mode 100644 index 000000000..285b68bea --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.d.ts @@ -0,0 +1,19 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; + +export interface Extension { + 'name'?: (string); + 'category'?: (string); + 'type_descriptor'?: (string); + 'version'?: (_envoy_api_v2_core_BuildVersion); + 'disabled'?: (boolean); +} + +export interface Extension__Output { + 'name': (string); + 'category': (string); + 'type_descriptor': (string); + 'version': (_envoy_api_v2_core_BuildVersion__Output); + 'disabled': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.d.ts new file mode 100644 index 000000000..fc1c3755f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../envoy/api/v2/core/Http2ProtocolOptions'; + +export interface GrpcProtocolOptions { + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); +} + +export interface GrpcProtocolOptions__Output { + 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.d.ts new file mode 100644 index 000000000..0e8021b19 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.d.ts @@ -0,0 +1,163 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/grpc_service.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { Long } from '@grpc/proto-loader'; + +export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc { + 'cluster_name'?: (string); +} + +export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc__Output { + 'cluster_name': (string); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc { + 'target_uri'?: (string); + 'channel_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials); + 'call_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials)[]; + 'stat_prefix'?: (string); + 'credentials_factory_name'?: (string); + 'config'?: (_google_protobuf_Struct); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { + 'target_uri': (string); + 'channel_credentials': (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output); + 'call_credentials': (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output)[]; + 'stat_prefix': (string); + 'credentials_factory_name': (string); + 'config': (_google_protobuf_Struct__Output); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { + 'root_certs'?: (_envoy_api_v2_core_DataSource); + 'private_key'?: (_envoy_api_v2_core_DataSource); + 'cert_chain'?: (_envoy_api_v2_core_DataSource); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { + 'root_certs': (_envoy_api_v2_core_DataSource__Output); + 'private_key': (_envoy_api_v2_core_DataSource__Output); + 'cert_chain': (_envoy_api_v2_core_DataSource__Output); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { + 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); + 'google_default'?: (_google_protobuf_Empty); + 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); + 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { + 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); + 'google_default'?: (_google_protobuf_Empty__Output); + 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); + 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { + 'access_token'?: (string); + 'google_compute_engine'?: (_google_protobuf_Empty); + 'google_refresh_token'?: (string); + 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); + 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); + 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); + 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService); + 'credential_specifier'?: "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output { + 'access_token'?: (string); + 'google_compute_engine'?: (_google_protobuf_Empty__Output); + 'google_refresh_token'?: (string); + 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); + 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); + 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); + 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); + 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials { + 'json_key'?: (string); + 'token_lifetime_seconds'?: (number | string | Long); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output { + 'json_key': (string); + 'token_lifetime_seconds': (string); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { + 'authorization_token'?: (string); + 'authority_selector'?: (string); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output { + 'authorization_token': (string); + 'authority_selector': (string); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService { + 'token_exchange_service_uri'?: (string); + 'resource'?: (string); + 'audience'?: (string); + 'scope'?: (string); + 'requested_token_type'?: (string); + 'subject_token_path'?: (string); + 'subject_token_type'?: (string); + 'actor_token_path'?: (string); + 'actor_token_type'?: (string); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output { + 'token_exchange_service_uri': (string); + 'resource': (string); + 'audience': (string); + 'scope': (string); + 'requested_token_type': (string); + 'subject_token_path': (string); + 'subject_token_type': (string); + 'actor_token_path': (string); + 'actor_token_type': (string); +} + +export interface GrpcService { + 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc); + 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc); + 'timeout'?: (_google_protobuf_Duration); + 'initial_metadata'?: (_envoy_api_v2_core_HeaderValue)[]; + 'target_specifier'?: "envoy_grpc"|"google_grpc"; +} + +export interface GrpcService__Output { + 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc__Output); + 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc__Output); + 'timeout': (_google_protobuf_Duration__Output); + 'initial_metadata': (_envoy_api_v2_core_HeaderValue__Output)[]; + 'target_specifier': "envoy_grpc"|"google_grpc"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.d.ts new file mode 100644 index 000000000..b3fafdc57 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; + +export interface HeaderMap { + 'headers'?: (_envoy_api_v2_core_HeaderValue)[]; +} + +export interface HeaderMap__Output { + 'headers': (_envoy_api_v2_core_HeaderValue__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.d.ts new file mode 100644 index 000000000..4b2e8ac92 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + + +export interface HeaderValue { + 'key'?: (string); + 'value'?: (string); +} + +export interface HeaderValue__Output { + 'key': (string); + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.d.ts new file mode 100644 index 000000000..ac8c4b971 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +export interface HeaderValueOption { + 'header'?: (_envoy_api_v2_core_HeaderValue); + 'append'?: (_google_protobuf_BoolValue); +} + +export interface HeaderValueOption__Output { + 'header': (_envoy_api_v2_core_HeaderValue__Output); + 'append': (_google_protobuf_BoolValue__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.d.ts new file mode 100644 index 000000000..934db81b2 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.d.ts @@ -0,0 +1,153 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/health_check.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from '../../../../envoy/api/v2/core/EventServiceConfig'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; +import { CodecClientType as _envoy_type_CodecClientType } from '../../../../envoy/type/CodecClientType'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { Long } from '@grpc/proto-loader'; + +export interface _envoy_api_v2_core_HealthCheck_Payload { + 'text'?: (string); + 'binary'?: (Buffer | Uint8Array | string); + 'payload'?: "text"|"binary"; +} + +export interface _envoy_api_v2_core_HealthCheck_Payload__Output { + 'text'?: (string); + 'binary'?: (Buffer); + 'payload': "text"|"binary"; +} + +export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck { + 'host'?: (string); + 'path'?: (string); + 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload); + 'service_name'?: (string); + 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_remove'?: (string)[]; + 'use_http2'?: (boolean); + 'expected_statuses'?: (_envoy_type_Int64Range)[]; + 'codec_client_type'?: (_envoy_type_CodecClientType | keyof typeof _envoy_type_CodecClientType); + 'service_name_matcher'?: (_envoy_type_matcher_StringMatcher); +} + +export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { + 'host': (string); + 'path': (string); + 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'service_name': (string); + 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_remove': (string)[]; + 'use_http2': (boolean); + 'expected_statuses': (_envoy_type_Int64Range__Output)[]; + 'codec_client_type': (keyof typeof _envoy_type_CodecClientType); + 'service_name_matcher': (_envoy_type_matcher_StringMatcher__Output); +} + +export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck { + 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload)[]; +} + +export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { + 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output)[]; +} + +export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck { + 'key'?: (string); +} + +export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck__Output { + 'key': (string); +} + +export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { + 'service_name'?: (string); + 'authority'?: (string); +} + +export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { + 'service_name': (string); + 'authority': (string); +} + +export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} + +export interface _envoy_api_v2_core_HealthCheck_TlsOptions { + 'alpn_protocols'?: (string)[]; +} + +export interface _envoy_api_v2_core_HealthCheck_TlsOptions__Output { + 'alpn_protocols': (string)[]; +} + +export interface HealthCheck { + 'timeout'?: (_google_protobuf_Duration); + 'interval'?: (_google_protobuf_Duration); + 'initial_jitter'?: (_google_protobuf_Duration); + 'interval_jitter'?: (_google_protobuf_Duration); + 'interval_jitter_percent'?: (number); + 'unhealthy_threshold'?: (_google_protobuf_UInt32Value); + 'healthy_threshold'?: (_google_protobuf_UInt32Value); + 'alt_port'?: (_google_protobuf_UInt32Value); + 'reuse_connection'?: (_google_protobuf_BoolValue); + 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck); + 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck); + 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck); + 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck); + 'no_traffic_interval'?: (_google_protobuf_Duration); + 'unhealthy_interval'?: (_google_protobuf_Duration); + 'unhealthy_edge_interval'?: (_google_protobuf_Duration); + 'healthy_edge_interval'?: (_google_protobuf_Duration); + 'event_log_path'?: (string); + 'event_service'?: (_envoy_api_v2_core_EventServiceConfig); + 'always_log_health_check_failures'?: (boolean); + 'tls_options'?: (_envoy_api_v2_core_HealthCheck_TlsOptions); + 'health_checker'?: "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; +} + +export interface HealthCheck__Output { + 'timeout': (_google_protobuf_Duration__Output); + 'interval': (_google_protobuf_Duration__Output); + 'initial_jitter': (_google_protobuf_Duration__Output); + 'interval_jitter': (_google_protobuf_Duration__Output); + 'interval_jitter_percent': (number); + 'unhealthy_threshold': (_google_protobuf_UInt32Value__Output); + 'healthy_threshold': (_google_protobuf_UInt32Value__Output); + 'alt_port': (_google_protobuf_UInt32Value__Output); + 'reuse_connection': (_google_protobuf_BoolValue__Output); + 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output); + 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output); + 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output); + 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output); + 'no_traffic_interval': (_google_protobuf_Duration__Output); + 'unhealthy_interval': (_google_protobuf_Duration__Output); + 'unhealthy_edge_interval': (_google_protobuf_Duration__Output); + 'healthy_edge_interval': (_google_protobuf_Duration__Output); + 'event_log_path': (string); + 'event_service': (_envoy_api_v2_core_EventServiceConfig__Output); + 'always_log_health_check_failures': (boolean); + 'tls_options': (_envoy_api_v2_core_HealthCheck_TlsOptions__Output); + 'health_checker': "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.d.ts new file mode 100644 index 000000000..a92dde214 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/health_check.proto + +export enum HealthStatus { + UNKNOWN = 0, + HEALTHY = 1, + UNHEALTHY = 2, + DRAINING = 3, + TIMEOUT = 4, + DEGRADED = 5, +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.d.ts new file mode 100644 index 000000000..566497ce3 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.d.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat { + 'proper_case_words'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords); + 'header_format'?: "proper_case_words"; +} + +export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output { + 'proper_case_words'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output); + 'header_format': "proper_case_words"; +} + +export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords { +} + +export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output { +} + +export interface Http1ProtocolOptions { + 'allow_absolute_url'?: (_google_protobuf_BoolValue); + 'accept_http_10'?: (boolean); + 'default_host_for_http_10'?: (string); + 'header_key_format'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat); + 'enable_trailers'?: (boolean); +} + +export interface Http1ProtocolOptions__Output { + 'allow_absolute_url': (_google_protobuf_BoolValue__Output); + 'accept_http_10': (boolean); + 'default_host_for_http_10': (string); + 'header_key_format': (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output); + 'enable_trailers': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.d.ts new file mode 100644 index 000000000..69d62ff81 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.d.ts @@ -0,0 +1,45 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter { + 'identifier'?: (_google_protobuf_UInt32Value); + 'value'?: (_google_protobuf_UInt32Value); +} + +export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Output { + 'identifier': (_google_protobuf_UInt32Value__Output); + 'value': (_google_protobuf_UInt32Value__Output); +} + +export interface Http2ProtocolOptions { + 'hpack_table_size'?: (_google_protobuf_UInt32Value); + 'max_concurrent_streams'?: (_google_protobuf_UInt32Value); + 'initial_stream_window_size'?: (_google_protobuf_UInt32Value); + 'initial_connection_window_size'?: (_google_protobuf_UInt32Value); + 'allow_connect'?: (boolean); + 'allow_metadata'?: (boolean); + 'max_outbound_frames'?: (_google_protobuf_UInt32Value); + 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value); + 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value); + 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value); + 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value); + 'stream_error_on_invalid_http_messaging'?: (boolean); + 'custom_settings_parameters'?: (_envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter)[]; +} + +export interface Http2ProtocolOptions__Output { + 'hpack_table_size': (_google_protobuf_UInt32Value__Output); + 'max_concurrent_streams': (_google_protobuf_UInt32Value__Output); + 'initial_stream_window_size': (_google_protobuf_UInt32Value__Output); + 'initial_connection_window_size': (_google_protobuf_UInt32Value__Output); + 'allow_connect': (boolean); + 'allow_metadata': (boolean); + 'max_outbound_frames': (_google_protobuf_UInt32Value__Output); + 'max_outbound_control_frames': (_google_protobuf_UInt32Value__Output); + 'max_consecutive_inbound_frames_with_empty_payload': (_google_protobuf_UInt32Value__Output); + 'max_inbound_priority_frames_per_stream': (_google_protobuf_UInt32Value__Output); + 'max_inbound_window_update_frames_per_data_frame_sent': (_google_protobuf_UInt32Value__Output); + 'stream_error_on_invalid_http_messaging': (boolean); + 'custom_settings_parameters': (_envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.d.ts new file mode 100644 index 000000000..f3594ce68 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.d.ts @@ -0,0 +1,28 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + +export enum _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction { + ALLOW = 0, + REJECT_REQUEST = 1, + DROP_HEADER = 2, +} + +export interface HttpProtocolOptions { + 'idle_timeout'?: (_google_protobuf_Duration); + 'max_connection_duration'?: (_google_protobuf_Duration); + 'max_headers_count'?: (_google_protobuf_UInt32Value); + 'max_stream_duration'?: (_google_protobuf_Duration); + 'headers_with_underscores_action'?: (_envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction | keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); +} + +export interface HttpProtocolOptions__Output { + 'idle_timeout': (_google_protobuf_Duration__Output); + 'max_connection_duration': (_google_protobuf_Duration__Output); + 'max_headers_count': (_google_protobuf_UInt32Value__Output); + 'max_stream_duration': (_google_protobuf_Duration__Output); + 'headers_with_underscores_action': (keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.d.ts new file mode 100644 index 000000000..4e0b1f86f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.d.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/http_uri.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +export interface HttpUri { + 'uri'?: (string); + 'cluster'?: (string); + 'timeout'?: (_google_protobuf_Duration); + 'http_upstream_type'?: "cluster"; +} + +export interface HttpUri__Output { + 'uri': (string); + 'cluster'?: (string); + 'timeout': (_google_protobuf_Duration__Output); + 'http_upstream_type': "cluster"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.d.ts new file mode 100644 index 000000000..c17f07413 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + + +export interface Locality { + 'region'?: (string); + 'zone'?: (string); + 'sub_zone'?: (string); +} + +export interface Locality__Output { + 'region': (string); + 'zone': (string); + 'sub_zone': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.d.ts new file mode 100644 index 000000000..dfc0406d9 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; + +export interface Metadata { + 'filter_metadata'?: (_google_protobuf_Struct); +} + +export interface Metadata__Output { + 'filter_metadata': (_google_protobuf_Struct__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.d.ts new file mode 100644 index 000000000..d20d3ec6f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.d.ts @@ -0,0 +1,37 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; +import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from '../../../../envoy/api/v2/core/Extension'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; + +export interface Node { + 'id'?: (string); + 'cluster'?: (string); + 'metadata'?: (_google_protobuf_Struct); + 'locality'?: (_envoy_api_v2_core_Locality); + 'build_version'?: (string); + 'user_agent_name'?: (string); + 'user_agent_version'?: (string); + 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion); + 'extensions'?: (_envoy_api_v2_core_Extension)[]; + 'client_features'?: (string)[]; + 'listening_addresses'?: (_envoy_api_v2_core_Address)[]; + 'user_agent_version_type'?: "user_agent_version"|"user_agent_build_version"; +} + +export interface Node__Output { + 'id': (string); + 'cluster': (string); + 'metadata': (_google_protobuf_Struct__Output); + 'locality': (_envoy_api_v2_core_Locality__Output); + 'build_version': (string); + 'user_agent_name': (string); + 'user_agent_version'?: (string); + 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion__Output); + 'extensions': (_envoy_api_v2_core_Extension__Output)[]; + 'client_features': (string)[]; + 'listening_addresses': (_envoy_api_v2_core_Address__Output)[]; + 'user_agent_version_type': "user_agent_version"|"user_agent_build_version"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.d.ts new file mode 100644 index 000000000..42ecc0aec --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + + +export interface Pipe { + 'path'?: (string); + 'mode'?: (number); +} + +export interface Pipe__Output { + 'path': (string); + 'mode': (number); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.d.ts new file mode 100644 index 000000000..e6b00f31c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from '../../../../google/protobuf/DoubleValue'; + +export interface RateLimitSettings { + 'max_tokens'?: (_google_protobuf_UInt32Value); + 'fill_rate'?: (_google_protobuf_DoubleValue); +} + +export interface RateLimitSettings__Output { + 'max_tokens': (_google_protobuf_UInt32Value__Output); + 'fill_rate': (_google_protobuf_DoubleValue__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.d.ts new file mode 100644 index 000000000..c372e2265 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.d.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from '../../../../envoy/api/v2/core/HttpUri'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from '../../../../envoy/api/v2/core/RetryPolicy'; + +export interface RemoteDataSource { + 'http_uri'?: (_envoy_api_v2_core_HttpUri); + 'sha256'?: (string); + 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy); +} + +export interface RemoteDataSource__Output { + 'http_uri': (_envoy_api_v2_core_HttpUri__Output); + 'sha256': (string); + 'retry_policy': (_envoy_api_v2_core_RetryPolicy__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.d.ts new file mode 100644 index 000000000..5532045c1 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +export enum RequestMethod { + METHOD_UNSPECIFIED = 0, + GET = 1, + HEAD = 2, + POST = 3, + PUT = 4, + DELETE = 5, + CONNECT = 6, + OPTIONS = 7, + TRACE = 8, + PATCH = 9, +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.d.ts new file mode 100644 index 000000000..a18f83648 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from '../../../../envoy/api/v2/core/BackoffStrategy'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface RetryPolicy { + 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy); + 'num_retries'?: (_google_protobuf_UInt32Value); +} + +export interface RetryPolicy__Output { + 'retry_back_off': (_envoy_api_v2_core_BackoffStrategy__Output); + 'num_retries': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.d.ts new file mode 100644 index 000000000..d386146e5 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.d.ts @@ -0,0 +1,6 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +export enum RoutingPriority { + DEFAULT = 0, + HIGH = 1, +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.d.ts new file mode 100644 index 000000000..177749784 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + + +export interface RuntimeDouble { + 'default_value'?: (number | string); + 'runtime_key'?: (string); +} + +export interface RuntimeDouble__Output { + 'default_value': (number | string); + 'runtime_key': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.d.ts new file mode 100644 index 000000000..897751270 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +export interface RuntimeFeatureFlag { + 'default_value'?: (_google_protobuf_BoolValue); + 'runtime_key'?: (string); +} + +export interface RuntimeFeatureFlag__Output { + 'default_value': (_google_protobuf_BoolValue__Output); + 'runtime_key': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.d.ts new file mode 100644 index 000000000..b6bb48d62 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; + +export interface RuntimeFractionalPercent { + 'default_value'?: (_envoy_type_FractionalPercent); + 'runtime_key'?: (string); +} + +export interface RuntimeFractionalPercent__Output { + 'default_value': (_envoy_type_FractionalPercent__Output); + 'runtime_key': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.d.ts new file mode 100644 index 000000000..bf6f7b903 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + + +export interface RuntimeUInt32 { + 'default_value'?: (number); + 'runtime_key'?: (string); +} + +export interface RuntimeUInt32__Output { + 'default_value': (number); + 'runtime_key': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.d.ts new file mode 100644 index 000000000..8551f7832 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto + + +export interface SelfConfigSource { +} + +export interface SelfConfigSource__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.d.ts new file mode 100644 index 000000000..415cf082c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.d.ts @@ -0,0 +1,29 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + + +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + +export enum _envoy_api_v2_core_SocketAddress_Protocol { + TCP = 0, + UDP = 1, +} + +export interface SocketAddress { + 'protocol'?: (_envoy_api_v2_core_SocketAddress_Protocol | keyof typeof _envoy_api_v2_core_SocketAddress_Protocol); + 'address'?: (string); + 'port_value'?: (number); + 'named_port'?: (string); + 'resolver_name'?: (string); + 'ipv4_compat'?: (boolean); + 'port_specifier'?: "port_value"|"named_port"; +} + +export interface SocketAddress__Output { + 'protocol': (keyof typeof _envoy_api_v2_core_SocketAddress_Protocol); + 'address': (string); + 'port_value'?: (number); + 'named_port'?: (string); + 'resolver_name': (string); + 'ipv4_compat': (boolean); + 'port_specifier': "port_value"|"named_port"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.d.ts new file mode 100644 index 000000000..0319328ff --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.d.ts @@ -0,0 +1,31 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto + +import { Long } from '@grpc/proto-loader'; + +// Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto + +export enum _envoy_api_v2_core_SocketOption_SocketState { + STATE_PREBIND = 0, + STATE_BOUND = 1, + STATE_LISTENING = 2, +} + +export interface SocketOption { + 'description'?: (string); + 'level'?: (number | string | Long); + 'name'?: (number | string | Long); + 'int_value'?: (number | string | Long); + 'buf_value'?: (Buffer | Uint8Array | string); + 'state'?: (_envoy_api_v2_core_SocketOption_SocketState | keyof typeof _envoy_api_v2_core_SocketOption_SocketState); + 'value'?: "int_value"|"buf_value"; +} + +export interface SocketOption__Output { + 'description': (string); + 'level': (string); + 'name': (string); + 'int_value'?: (string); + 'buf_value'?: (Buffer); + 'state': (keyof typeof _envoy_api_v2_core_SocketOption_SocketState); + 'value': "int_value"|"buf_value"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.d.ts new file mode 100644 index 000000000..dd77d08bd --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.d.ts @@ -0,0 +1,15 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/address.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface TcpKeepalive { + 'keepalive_probes'?: (_google_protobuf_UInt32Value); + 'keepalive_time'?: (_google_protobuf_UInt32Value); + 'keepalive_interval'?: (_google_protobuf_UInt32Value); +} + +export interface TcpKeepalive__Output { + 'keepalive_probes': (_google_protobuf_UInt32Value__Output); + 'keepalive_time': (_google_protobuf_UInt32Value__Output); + 'keepalive_interval': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.d.ts new file mode 100644 index 000000000..602fae7af --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + + +export interface TcpProtocolOptions { +} + +export interface TcpProtocolOptions__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.d.ts new file mode 100644 index 000000000..50f4bb28c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.d.ts @@ -0,0 +1,7 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +export enum TrafficDirection { + UNSPECIFIED = 0, + INBOUND = 1, + OUTBOUND = 2, +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.d.ts new file mode 100644 index 000000000..7062f81e2 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/base.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface TransportSocket { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface TransportSocket__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts new file mode 100644 index 000000000..d4e492413 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto + + +export interface UpstreamHttpProtocolOptions { + 'auto_sni'?: (boolean); + 'auto_san_validation'?: (boolean); +} + +export interface UpstreamHttpProtocolOptions__Output { + 'auto_sni': (boolean); + 'auto_san_validation': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.d.ts new file mode 100644 index 000000000..bdb23b50c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.d.ts @@ -0,0 +1,25 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto + +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; + +export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig { + 'port_value'?: (number); + 'hostname'?: (string); +} + +export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output { + 'port_value': (number); + 'hostname': (string); +} + +export interface Endpoint { + 'address'?: (_envoy_api_v2_core_Address); + 'health_check_config'?: (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig); + 'hostname'?: (string); +} + +export interface Endpoint__Output { + 'address': (_envoy_api_v2_core_Address__Output); + 'health_check_config': (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output); + 'hostname': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.d.ts new file mode 100644 index 000000000..cb40e7c95 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.d.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto + +import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../../envoy/api/v2/endpoint/Endpoint'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from '../../../../envoy/api/v2/core/HealthStatus'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface LbEndpoint { + 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint); + 'endpoint_name'?: (string); + 'health_status'?: (_envoy_api_v2_core_HealthStatus | keyof typeof _envoy_api_v2_core_HealthStatus); + 'metadata'?: (_envoy_api_v2_core_Metadata); + 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + 'host_identifier'?: "endpoint"|"endpoint_name"; +} + +export interface LbEndpoint__Output { + 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint__Output); + 'endpoint_name'?: (string); + 'health_status': (keyof typeof _envoy_api_v2_core_HealthStatus); + 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + 'host_identifier': "endpoint"|"endpoint_name"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts new file mode 100644 index 000000000..d42663b04 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts @@ -0,0 +1,21 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto + +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from '../../../../envoy/api/v2/endpoint/LbEndpoint'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface LocalityLbEndpoints { + 'locality'?: (_envoy_api_v2_core_Locality); + 'lb_endpoints'?: (_envoy_api_v2_endpoint_LbEndpoint)[]; + 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + 'priority'?: (number); + 'proximity'?: (_google_protobuf_UInt32Value); +} + +export interface LocalityLbEndpoints__Output { + 'locality': (_envoy_api_v2_core_Locality__Output); + 'lb_endpoints': (_envoy_api_v2_endpoint_LbEndpoint__Output)[]; + 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + 'priority': (number); + 'proximity': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts new file mode 100644 index 000000000..7bb47c26c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto + + +export interface ActiveRawUdpListenerConfig { +} + +export interface ActiveRawUdpListenerConfig__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.d.ts new file mode 100644 index 000000000..d9c2cc793 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface Filter { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface Filter__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.d.ts new file mode 100644 index 000000000..ca24c8429 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.d.ts @@ -0,0 +1,28 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto + +import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from '../../../../envoy/api/v2/listener/FilterChainMatch'; +import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from '../../../../envoy/api/v2/auth/DownstreamTlsContext'; +import { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from '../../../../envoy/api/v2/listener/Filter'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../../envoy/api/v2/core/TransportSocket'; + +export interface FilterChain { + 'filter_chain_match'?: (_envoy_api_v2_listener_FilterChainMatch); + 'tls_context'?: (_envoy_api_v2_auth_DownstreamTlsContext); + 'filters'?: (_envoy_api_v2_listener_Filter)[]; + 'use_proxy_proto'?: (_google_protobuf_BoolValue); + 'metadata'?: (_envoy_api_v2_core_Metadata); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); + 'name'?: (string); +} + +export interface FilterChain__Output { + 'filter_chain_match': (_envoy_api_v2_listener_FilterChainMatch__Output); + 'tls_context': (_envoy_api_v2_auth_DownstreamTlsContext__Output); + 'filters': (_envoy_api_v2_listener_Filter__Output)[]; + 'use_proxy_proto': (_google_protobuf_BoolValue__Output); + 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + 'name': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.d.ts new file mode 100644 index 000000000..4b74a5544 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.d.ts @@ -0,0 +1,38 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from '../../../../envoy/api/v2/core/CidrRange'; + +// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto + +export enum _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType { + ANY = 0, + LOCAL = 1, + EXTERNAL = 2, +} + +export interface FilterChainMatch { + 'destination_port'?: (_google_protobuf_UInt32Value); + 'prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; + 'address_suffix'?: (string); + 'suffix_len'?: (_google_protobuf_UInt32Value); + 'source_type'?: (_envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); + 'source_prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; + 'source_ports'?: (number)[]; + 'server_names'?: (string)[]; + 'transport_protocol'?: (string); + 'application_protocols'?: (string)[]; +} + +export interface FilterChainMatch__Output { + 'destination_port': (_google_protobuf_UInt32Value__Output); + 'prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; + 'address_suffix': (string); + 'suffix_len': (_google_protobuf_UInt32Value__Output); + 'source_type': (keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); + 'source_prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; + 'source_ports': (number)[]; + 'server_names': (string)[]; + 'transport_protocol': (string); + 'application_protocols': (string)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.d.ts new file mode 100644 index 000000000..bd143d311 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.d.ts @@ -0,0 +1,21 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; + +export interface ListenerFilter { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'filter_disabled'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate); + 'config_type'?: "config"|"typed_config"; +} + +export interface ListenerFilter__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'filter_disabled': (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts new file mode 100644 index 000000000..a795f0191 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts @@ -0,0 +1,30 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto + +import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from '../../../../envoy/type/Int32Range'; + +export interface _envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet { + 'rules'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate)[]; +} + +export interface _envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output { + 'rules': (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output)[]; +} + +export interface ListenerFilterChainMatchPredicate { + 'or_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet); + 'and_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet); + 'not_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate); + 'any_match'?: (boolean); + 'destination_port_range'?: (_envoy_type_Int32Range); + 'rule'?: "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; +} + +export interface ListenerFilterChainMatchPredicate__Output { + 'or_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output); + 'and_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output); + 'not_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + 'any_match'?: (boolean); + 'destination_port_range'?: (_envoy_type_Int32Range__Output); + 'rule': "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.d.ts new file mode 100644 index 000000000..775f4ae9f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface UdpListenerConfig { + 'udp_listener_name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface UdpListenerConfig__Output { + 'udp_listener_name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.d.ts new file mode 100644 index 000000000..d1f5b11d0 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.d.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; + +export interface CorsPolicy { + 'allow_origin'?: (string)[]; + 'allow_origin_regex'?: (string)[]; + 'allow_origin_string_match'?: (_envoy_type_matcher_StringMatcher)[]; + 'allow_methods'?: (string); + 'allow_headers'?: (string); + 'expose_headers'?: (string); + 'max_age'?: (string); + 'allow_credentials'?: (_google_protobuf_BoolValue); + 'enabled'?: (_google_protobuf_BoolValue); + 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'shadow_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'enabled_specifier'?: "enabled"|"filter_enabled"; +} + +export interface CorsPolicy__Output { + 'allow_origin': (string)[]; + 'allow_origin_regex': (string)[]; + 'allow_origin_string_match': (_envoy_type_matcher_StringMatcher__Output)[]; + 'allow_methods': (string); + 'allow_headers': (string); + 'expose_headers': (string); + 'max_age': (string); + 'allow_credentials': (_google_protobuf_BoolValue__Output); + 'enabled'?: (_google_protobuf_BoolValue__Output); + 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'shadow_enabled': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'enabled_specifier': "enabled"|"filter_enabled"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.d.ts new file mode 100644 index 000000000..84deb8b0c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +export interface Decorator { + 'operation'?: (string); + 'propagate'?: (_google_protobuf_BoolValue); +} + +export interface Decorator__Output { + 'operation': (string); + 'propagate': (_google_protobuf_BoolValue__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.d.ts new file mode 100644 index 000000000..83440efcf --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; + +export interface DirectResponseAction { + 'status'?: (number); + 'body'?: (_envoy_api_v2_core_DataSource); +} + +export interface DirectResponseAction__Output { + 'status': (number); + 'body': (_envoy_api_v2_core_DataSource__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.d.ts new file mode 100644 index 000000000..14455ae79 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface FilterAction { + 'action'?: (_google_protobuf_Any); +} + +export interface FilterAction__Output { + 'action': (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.d.ts new file mode 100644 index 000000000..97636e12b --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.d.ts @@ -0,0 +1,31 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; +import { Long } from '@grpc/proto-loader'; + +export interface HeaderMatcher { + 'name'?: (string); + 'exact_match'?: (string); + 'regex_match'?: (string); + 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher); + 'range_match'?: (_envoy_type_Int64Range); + 'present_match'?: (boolean); + 'prefix_match'?: (string); + 'suffix_match'?: (string); + 'invert_match'?: (boolean); + 'header_match_specifier'?: "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; +} + +export interface HeaderMatcher__Output { + 'name': (string); + 'exact_match'?: (string); + 'regex_match'?: (string); + 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher__Output); + 'range_match'?: (_envoy_type_Int64Range__Output); + 'present_match'?: (boolean); + 'prefix_match'?: (string); + 'suffix_match'?: (string); + 'invert_match': (boolean); + 'header_match_specifier': "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.d.ts new file mode 100644 index 000000000..5cab83560 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.d.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; + +export interface HedgePolicy { + 'initial_requests'?: (_google_protobuf_UInt32Value); + 'additional_request_chance'?: (_envoy_type_FractionalPercent); + 'hedge_on_per_try_timeout'?: (boolean); +} + +export interface HedgePolicy__Output { + 'initial_requests': (_google_protobuf_UInt32Value__Output); + 'additional_request_chance': (_envoy_type_FractionalPercent__Output); + 'hedge_on_per_try_timeout': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.d.ts new file mode 100644 index 000000000..48c6a51b0 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; + +export interface QueryParameterMatcher { + 'name'?: (string); + 'value'?: (string); + 'regex'?: (_google_protobuf_BoolValue); + 'string_match'?: (_envoy_type_matcher_StringMatcher); + 'present_match'?: (boolean); + 'query_parameter_match_specifier'?: "string_match"|"present_match"; +} + +export interface QueryParameterMatcher__Output { + 'name': (string); + 'value': (string); + 'regex': (_google_protobuf_BoolValue__Output); + 'string_match'?: (_envoy_type_matcher_StringMatcher__Output); + 'present_match'?: (boolean); + 'query_parameter_match_specifier': "string_match"|"present_match"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.d.ts new file mode 100644 index 000000000..86681d391 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.d.ts @@ -0,0 +1,85 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; + +export interface _envoy_api_v2_route_RateLimit_Action { + 'source_cluster'?: (_envoy_api_v2_route_RateLimit_Action_SourceCluster); + 'destination_cluster'?: (_envoy_api_v2_route_RateLimit_Action_DestinationCluster); + 'request_headers'?: (_envoy_api_v2_route_RateLimit_Action_RequestHeaders); + 'remote_address'?: (_envoy_api_v2_route_RateLimit_Action_RemoteAddress); + 'generic_key'?: (_envoy_api_v2_route_RateLimit_Action_GenericKey); + 'header_value_match'?: (_envoy_api_v2_route_RateLimit_Action_HeaderValueMatch); + 'action_specifier'?: "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; +} + +export interface _envoy_api_v2_route_RateLimit_Action__Output { + 'source_cluster'?: (_envoy_api_v2_route_RateLimit_Action_SourceCluster__Output); + 'destination_cluster'?: (_envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output); + 'request_headers'?: (_envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output); + 'remote_address'?: (_envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output); + 'generic_key'?: (_envoy_api_v2_route_RateLimit_Action_GenericKey__Output); + 'header_value_match'?: (_envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output); + 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; +} + +export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster { +} + +export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster__Output { +} + +export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster { +} + +export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output { +} + +export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders { + 'header_name'?: (string); + 'descriptor_key'?: (string); +} + +export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output { + 'header_name': (string); + 'descriptor_key': (string); +} + +export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress { +} + +export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output { +} + +export interface _envoy_api_v2_route_RateLimit_Action_GenericKey { + 'descriptor_value'?: (string); +} + +export interface _envoy_api_v2_route_RateLimit_Action_GenericKey__Output { + 'descriptor_value': (string); +} + +export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch { + 'descriptor_value'?: (string); + 'expect_match'?: (_google_protobuf_BoolValue); + 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; +} + +export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output { + 'descriptor_value': (string); + 'expect_match': (_google_protobuf_BoolValue__Output); + 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; +} + +export interface RateLimit { + 'stage'?: (_google_protobuf_UInt32Value); + 'disable_key'?: (string); + 'actions'?: (_envoy_api_v2_route_RateLimit_Action)[]; +} + +export interface RateLimit__Output { + 'stage': (_google_protobuf_UInt32Value__Output); + 'disable_key': (string); + 'actions': (_envoy_api_v2_route_RateLimit_Action__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.d.ts new file mode 100644 index 000000000..cdd33a9e6 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.d.ts @@ -0,0 +1,38 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + + +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +export enum _envoy_api_v2_route_RedirectAction_RedirectResponseCode { + MOVED_PERMANENTLY = 0, + FOUND = 1, + SEE_OTHER = 2, + TEMPORARY_REDIRECT = 3, + PERMANENT_REDIRECT = 4, +} + +export interface RedirectAction { + 'https_redirect'?: (boolean); + 'scheme_redirect'?: (string); + 'host_redirect'?: (string); + 'port_redirect'?: (number); + 'path_redirect'?: (string); + 'prefix_rewrite'?: (string); + 'response_code'?: (_envoy_api_v2_route_RedirectAction_RedirectResponseCode | keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); + 'strip_query'?: (boolean); + 'scheme_rewrite_specifier'?: "https_redirect"|"scheme_redirect"; + 'path_rewrite_specifier'?: "path_redirect"|"prefix_rewrite"; +} + +export interface RedirectAction__Output { + 'https_redirect'?: (boolean); + 'scheme_redirect'?: (string); + 'host_redirect': (string); + 'port_redirect': (number); + 'path_redirect'?: (string); + 'prefix_rewrite'?: (string); + 'response_code': (keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); + 'strip_query': (boolean); + 'scheme_rewrite_specifier': "https_redirect"|"scheme_redirect"; + 'path_rewrite_specifier': "path_redirect"|"prefix_rewrite"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.d.ts new file mode 100644 index 000000000..6a0be9e43 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.d.ts @@ -0,0 +1,72 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { Long } from '@grpc/proto-loader'; + +export interface _envoy_api_v2_route_RetryPolicy_RetryPriority { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryPriority__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff { + 'base_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration); +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff__Output { + 'base_interval': (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output); +} + +export interface RetryPolicy { + 'retry_on'?: (string); + 'num_retries'?: (_google_protobuf_UInt32Value); + 'per_try_timeout'?: (_google_protobuf_Duration); + 'retry_priority'?: (_envoy_api_v2_route_RetryPolicy_RetryPriority); + 'retry_host_predicate'?: (_envoy_api_v2_route_RetryPolicy_RetryHostPredicate)[]; + 'host_selection_retry_max_attempts'?: (number | string | Long); + 'retriable_status_codes'?: (number)[]; + 'retry_back_off'?: (_envoy_api_v2_route_RetryPolicy_RetryBackOff); + 'retriable_headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + 'retriable_request_headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; +} + +export interface RetryPolicy__Output { + 'retry_on': (string); + 'num_retries': (_google_protobuf_UInt32Value__Output); + 'per_try_timeout': (_google_protobuf_Duration__Output); + 'retry_priority': (_envoy_api_v2_route_RetryPolicy_RetryPriority__Output); + 'retry_host_predicate': (_envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output)[]; + 'host_selection_retry_max_attempts': (string); + 'retriable_status_codes': (number)[]; + 'retry_back_off': (_envoy_api_v2_route_RetryPolicy_RetryBackOff__Output); + 'retriable_headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + 'retriable_request_headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.d.ts new file mode 100644 index 000000000..700c3ac61 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.d.ts @@ -0,0 +1,54 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from '../../../../envoy/api/v2/route/RouteMatch'; +import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from '../../../../envoy/api/v2/route/RouteAction'; +import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from '../../../../envoy/api/v2/route/RedirectAction'; +import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from '../../../../envoy/api/v2/route/DirectResponseAction'; +import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from '../../../../envoy/api/v2/route/Decorator'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from '../../../../envoy/api/v2/route/Tracing'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface Route { + 'name'?: (string); + 'match'?: (_envoy_api_v2_route_RouteMatch); + 'route'?: (_envoy_api_v2_route_RouteAction); + 'redirect'?: (_envoy_api_v2_route_RedirectAction); + 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction); + 'filter_action'?: (_envoy_api_v2_route_FilterAction); + 'metadata'?: (_envoy_api_v2_core_Metadata); + 'decorator'?: (_envoy_api_v2_route_Decorator); + 'per_filter_config'?: (_google_protobuf_Struct); + 'typed_per_filter_config'?: (_google_protobuf_Any); + 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_remove'?: (string)[]; + 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_remove'?: (string)[]; + 'tracing'?: (_envoy_api_v2_route_Tracing); + 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'action'?: "route"|"redirect"|"direct_response"|"filter_action"; +} + +export interface Route__Output { + 'name': (string); + 'match': (_envoy_api_v2_route_RouteMatch__Output); + 'route'?: (_envoy_api_v2_route_RouteAction__Output); + 'redirect'?: (_envoy_api_v2_route_RedirectAction__Output); + 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction__Output); + 'filter_action'?: (_envoy_api_v2_route_FilterAction__Output); + 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'decorator': (_envoy_api_v2_route_Decorator__Output); + 'per_filter_config': (_google_protobuf_Struct__Output); + 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_remove': (string)[]; + 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_remove': (string)[]; + 'tracing': (_envoy_api_v2_route_Tracing__Output); + 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'action': "route"|"redirect"|"direct_response"|"filter_action"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.d.ts new file mode 100644 index 000000000..58f8f1acd --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.d.ts @@ -0,0 +1,181 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from '../../../../envoy/api/v2/route/WeightedCluster'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/RegexMatchAndSubstitute'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; +import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; +import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; + +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +export enum _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode { + SERVICE_UNAVAILABLE = 0, + NOT_FOUND = 1, +} + +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { + PASS_THROUGH_INTERNAL_REDIRECT = 0, + HANDLE_INTERNAL_REDIRECT = 1, +} + +export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { + 'cluster'?: (string); + 'runtime_key'?: (string); + 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'trace_sampled'?: (_google_protobuf_BoolValue); +} + +export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { + 'cluster': (string); + 'runtime_key': (string); + 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'trace_sampled': (_google_protobuf_BoolValue__Output); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy { + 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header); + 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie); + 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties); + 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter); + 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState); + 'terminal'?: (boolean); + 'policy_specifier'?: "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { + 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header__Output); + 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output); + 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output); + 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output); + 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output); + 'terminal': (boolean); + 'policy_specifier': "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header { + 'header_name'?: (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header__Output { + 'header_name': (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie { + 'name'?: (string); + 'ttl'?: (_google_protobuf_Duration); + 'path'?: (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output { + 'name': (string); + 'ttl': (_google_protobuf_Duration__Output); + 'path': (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties { + 'source_ip'?: (boolean); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output { + 'source_ip': (boolean); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter { + 'name'?: (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output { + 'name': (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState { + 'key'?: (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output { + 'key': (string); +} + +export interface _envoy_api_v2_route_RouteAction_UpgradeConfig { + 'upgrade_type'?: (string); + 'enabled'?: (_google_protobuf_BoolValue); +} + +export interface _envoy_api_v2_route_RouteAction_UpgradeConfig__Output { + 'upgrade_type': (string); + 'enabled': (_google_protobuf_BoolValue__Output); +} + +export interface RouteAction { + 'cluster'?: (string); + 'cluster_header'?: (string); + 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster); + 'cluster_not_found_response_code'?: (_envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); + 'metadata_match'?: (_envoy_api_v2_core_Metadata); + 'prefix_rewrite'?: (string); + 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute); + 'host_rewrite'?: (string); + 'auto_host_rewrite'?: (_google_protobuf_BoolValue); + 'auto_host_rewrite_header'?: (string); + 'timeout'?: (_google_protobuf_Duration); + 'idle_timeout'?: (_google_protobuf_Duration); + 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); + 'retry_policy_typed_config'?: (_google_protobuf_Any); + 'request_mirror_policy'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy); + 'request_mirror_policies'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy)[]; + 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); + 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; + 'include_vh_rate_limits'?: (_google_protobuf_BoolValue); + 'hash_policy'?: (_envoy_api_v2_route_RouteAction_HashPolicy)[]; + 'cors'?: (_envoy_api_v2_route_CorsPolicy); + 'max_grpc_timeout'?: (_google_protobuf_Duration); + 'grpc_timeout_offset'?: (_google_protobuf_Duration); + 'upgrade_configs'?: (_envoy_api_v2_route_RouteAction_UpgradeConfig)[]; + 'internal_redirect_action'?: (_envoy_api_v2_route_RouteAction_InternalRedirectAction | keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); + 'max_internal_redirects'?: (_google_protobuf_UInt32Value); + 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"; + 'host_rewrite_specifier'?: "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; +} + +export interface RouteAction__Output { + 'cluster'?: (string); + 'cluster_header'?: (string); + 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster__Output); + 'cluster_not_found_response_code': (keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); + 'metadata_match': (_envoy_api_v2_core_Metadata__Output); + 'prefix_rewrite': (string); + 'regex_rewrite': (_envoy_type_matcher_RegexMatchAndSubstitute__Output); + 'host_rewrite'?: (string); + 'auto_host_rewrite'?: (_google_protobuf_BoolValue__Output); + 'auto_host_rewrite_header'?: (string); + 'timeout': (_google_protobuf_Duration__Output); + 'idle_timeout': (_google_protobuf_Duration__Output); + 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); + 'retry_policy_typed_config': (_google_protobuf_Any__Output); + 'request_mirror_policy': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output); + 'request_mirror_policies': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output)[]; + 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); + 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; + 'include_vh_rate_limits': (_google_protobuf_BoolValue__Output); + 'hash_policy': (_envoy_api_v2_route_RouteAction_HashPolicy__Output)[]; + 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + 'max_grpc_timeout': (_google_protobuf_Duration__Output); + 'grpc_timeout_offset': (_google_protobuf_Duration__Output); + 'upgrade_configs': (_envoy_api_v2_route_RouteAction_UpgradeConfig__Output)[]; + 'internal_redirect_action': (keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); + 'max_internal_redirects': (_google_protobuf_UInt32Value__Output); + 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; + 'host_rewrite_specifier': "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.d.ts new file mode 100644 index 000000000..897583eaf --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.d.ts @@ -0,0 +1,51 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from '../../../../envoy/api/v2/route/QueryParameterMatcher'; + +export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions { +} + +export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output { +} + +export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions { + 'presented'?: (_google_protobuf_BoolValue); + 'validated'?: (_google_protobuf_BoolValue); +} + +export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output { + 'presented': (_google_protobuf_BoolValue__Output); + 'validated': (_google_protobuf_BoolValue__Output); +} + +export interface RouteMatch { + 'prefix'?: (string); + 'path'?: (string); + 'regex'?: (string); + 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); + 'case_sensitive'?: (_google_protobuf_BoolValue); + 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + 'query_parameters'?: (_envoy_api_v2_route_QueryParameterMatcher)[]; + 'grpc'?: (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions); + 'tls_context'?: (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions); + 'path_specifier'?: "prefix"|"path"|"regex"|"safe_regex"; +} + +export interface RouteMatch__Output { + 'prefix'?: (string); + 'path'?: (string); + 'regex'?: (string); + 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); + 'case_sensitive': (_google_protobuf_BoolValue__Output); + 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + 'query_parameters': (_envoy_api_v2_route_QueryParameterMatcher__Output)[]; + 'grpc': (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output); + 'tls_context': (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output); + 'path_specifier': "prefix"|"path"|"regex"|"safe_regex"; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.d.ts new file mode 100644 index 000000000..6709864e7 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../envoy/type/tracing/v2/CustomTag'; + +export interface Tracing { + 'client_sampling'?: (_envoy_type_FractionalPercent); + 'random_sampling'?: (_envoy_type_FractionalPercent); + 'overall_sampling'?: (_envoy_type_FractionalPercent); + 'custom_tags'?: (_envoy_type_tracing_v2_CustomTag)[]; +} + +export interface Tracing__Output { + 'client_sampling': (_envoy_type_FractionalPercent__Output); + 'random_sampling': (_envoy_type_FractionalPercent__Output); + 'overall_sampling': (_envoy_type_FractionalPercent__Output); + 'custom_tags': (_envoy_type_tracing_v2_CustomTag__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.d.ts new file mode 100644 index 000000000..e0c23d07a --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from '../../../../envoy/api/v2/core/RequestMethod'; + +export interface VirtualCluster { + 'pattern'?: (string); + 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + 'name'?: (string); + 'method'?: (_envoy_api_v2_core_RequestMethod | keyof typeof _envoy_api_v2_core_RequestMethod); +} + +export interface VirtualCluster__Output { + 'pattern': (string); + 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + 'name': (string); + 'method': (keyof typeof _envoy_api_v2_core_RequestMethod); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.d.ts new file mode 100644 index 000000000..4d046c805 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.d.ts @@ -0,0 +1,64 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from '../../../../envoy/api/v2/route/Route'; +import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from '../../../../envoy/api/v2/route/VirtualCluster'; +import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; +import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +export enum _envoy_api_v2_route_VirtualHost_TlsRequirementType { + NONE = 0, + EXTERNAL_ONLY = 1, + ALL = 2, +} + +export interface VirtualHost { + 'name'?: (string); + 'domains'?: (string)[]; + 'routes'?: (_envoy_api_v2_route_Route)[]; + 'require_tls'?: (_envoy_api_v2_route_VirtualHost_TlsRequirementType | keyof typeof _envoy_api_v2_route_VirtualHost_TlsRequirementType); + 'virtual_clusters'?: (_envoy_api_v2_route_VirtualCluster)[]; + 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; + 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_remove'?: (string)[]; + 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_remove'?: (string)[]; + 'cors'?: (_envoy_api_v2_route_CorsPolicy); + 'per_filter_config'?: (_google_protobuf_Struct); + 'typed_per_filter_config'?: (_google_protobuf_Any); + 'include_request_attempt_count'?: (boolean); + 'include_attempt_count_in_response'?: (boolean); + 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); + 'retry_policy_typed_config'?: (_google_protobuf_Any); + 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); +} + +export interface VirtualHost__Output { + 'name': (string); + 'domains': (string)[]; + 'routes': (_envoy_api_v2_route_Route__Output)[]; + 'require_tls': (keyof typeof _envoy_api_v2_route_VirtualHost_TlsRequirementType); + 'virtual_clusters': (_envoy_api_v2_route_VirtualCluster__Output)[]; + 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; + 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_remove': (string)[]; + 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_remove': (string)[]; + 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + 'per_filter_config': (_google_protobuf_Struct__Output); + 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'include_request_attempt_count': (boolean); + 'include_attempt_count_in_response': (boolean); + 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); + 'retry_policy_typed_config': (_google_protobuf_Any__Output); + 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.d.ts new file mode 100644 index 000000000..84ad2348b --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.d.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { + 'name'?: (string); + 'weight'?: (_google_protobuf_UInt32Value); + 'metadata_match'?: (_envoy_api_v2_core_Metadata); + 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_remove'?: (string)[]; + 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_remove'?: (string)[]; + 'per_filter_config'?: (_google_protobuf_Struct); + 'typed_per_filter_config'?: (_google_protobuf_Any); +} + +export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { + 'name': (string); + 'weight': (_google_protobuf_UInt32Value__Output); + 'metadata_match': (_envoy_api_v2_core_Metadata__Output); + 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_remove': (string)[]; + 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_remove': (string)[]; + 'per_filter_config': (_google_protobuf_Struct__Output); + 'typed_per_filter_config': (_google_protobuf_Any__Output); +} + +export interface WeightedCluster { + 'clusters'?: (_envoy_api_v2_route_WeightedCluster_ClusterWeight)[]; + 'total_weight'?: (_google_protobuf_UInt32Value); + 'runtime_key_prefix'?: (string); +} + +export interface WeightedCluster__Output { + 'clusters': (_envoy_api_v2_route_WeightedCluster_ClusterWeight__Output)[]; + 'total_weight': (_google_protobuf_UInt32Value__Output); + 'runtime_key_prefix': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.d.ts new file mode 100644 index 000000000..d89342b10 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.d.ts @@ -0,0 +1,21 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; + +export interface AccessLog { + 'name'?: (string); + 'filter'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface AccessLog__Output { + 'name': (string); + 'filter': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts new file mode 100644 index 000000000..ce399dc52 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/StatusCodeFilter'; +import { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/DurationFilter'; +import { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; +import { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/TraceableFilter'; +import { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/RuntimeFilter'; +import { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AndFilter'; +import { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/OrFilter'; +import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/HeaderFilter'; +import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ResponseFlagFilter'; +import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/GrpcStatusFilter'; +import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ExtensionFilter'; + +export interface AccessLogFilter { + 'status_code_filter'?: (_envoy_config_filter_accesslog_v2_StatusCodeFilter); + 'duration_filter'?: (_envoy_config_filter_accesslog_v2_DurationFilter); + 'not_health_check_filter'?: (_envoy_config_filter_accesslog_v2_NotHealthCheckFilter); + 'traceable_filter'?: (_envoy_config_filter_accesslog_v2_TraceableFilter); + 'runtime_filter'?: (_envoy_config_filter_accesslog_v2_RuntimeFilter); + 'and_filter'?: (_envoy_config_filter_accesslog_v2_AndFilter); + 'or_filter'?: (_envoy_config_filter_accesslog_v2_OrFilter); + 'header_filter'?: (_envoy_config_filter_accesslog_v2_HeaderFilter); + 'response_flag_filter'?: (_envoy_config_filter_accesslog_v2_ResponseFlagFilter); + 'grpc_status_filter'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter); + 'extension_filter'?: (_envoy_config_filter_accesslog_v2_ExtensionFilter); + 'filter_specifier'?: "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"; +} + +export interface AccessLogFilter__Output { + 'status_code_filter'?: (_envoy_config_filter_accesslog_v2_StatusCodeFilter__Output); + 'duration_filter'?: (_envoy_config_filter_accesslog_v2_DurationFilter__Output); + 'not_health_check_filter'?: (_envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output); + 'traceable_filter'?: (_envoy_config_filter_accesslog_v2_TraceableFilter__Output); + 'runtime_filter'?: (_envoy_config_filter_accesslog_v2_RuntimeFilter__Output); + 'and_filter'?: (_envoy_config_filter_accesslog_v2_AndFilter__Output); + 'or_filter'?: (_envoy_config_filter_accesslog_v2_OrFilter__Output); + 'header_filter'?: (_envoy_config_filter_accesslog_v2_HeaderFilter__Output); + 'response_flag_filter'?: (_envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output); + 'grpc_status_filter'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output); + 'extension_filter'?: (_envoy_config_filter_accesslog_v2_ExtensionFilter__Output); + 'filter_specifier': "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.d.ts new file mode 100644 index 000000000..490962c54 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; + +export interface AndFilter { + 'filters'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter)[]; +} + +export interface AndFilter__Output { + 'filters': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts new file mode 100644 index 000000000..518e5399c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts @@ -0,0 +1,21 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from '../../../../../envoy/api/v2/core/RuntimeUInt32'; + +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +export enum _envoy_config_filter_accesslog_v2_ComparisonFilter_Op { + EQ = 0, + GE = 1, + LE = 2, +} + +export interface ComparisonFilter { + 'op'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter_Op | keyof typeof _envoy_config_filter_accesslog_v2_ComparisonFilter_Op); + 'value'?: (_envoy_api_v2_core_RuntimeUInt32); +} + +export interface ComparisonFilter__Output { + 'op': (keyof typeof _envoy_config_filter_accesslog_v2_ComparisonFilter_Op); + 'value': (_envoy_api_v2_core_RuntimeUInt32__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.d.ts new file mode 100644 index 000000000..495154e27 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; + +export interface DurationFilter { + 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter); +} + +export interface DurationFilter__Output { + 'comparison': (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts new file mode 100644 index 000000000..047086c8b --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; + +export interface ExtensionFilter { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; +} + +export interface ExtensionFilter__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts new file mode 100644 index 000000000..086c08e3a --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + + +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +export enum _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status { + OK = 0, + CANCELED = 1, + UNKNOWN = 2, + INVALID_ARGUMENT = 3, + DEADLINE_EXCEEDED = 4, + NOT_FOUND = 5, + ALREADY_EXISTS = 6, + PERMISSION_DENIED = 7, + RESOURCE_EXHAUSTED = 8, + FAILED_PRECONDITION = 9, + ABORTED = 10, + OUT_OF_RANGE = 11, + UNIMPLEMENTED = 12, + INTERNAL = 13, + UNAVAILABLE = 14, + DATA_LOSS = 15, + UNAUTHENTICATED = 16, +} + +export interface GrpcStatusFilter { + 'statuses'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status | keyof typeof _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status)[]; + 'exclude'?: (boolean); +} + +export interface GrpcStatusFilter__Output { + 'statuses': (keyof typeof _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status)[]; + 'exclude': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.d.ts new file mode 100644 index 000000000..7fe39f9ee --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../../envoy/api/v2/route/HeaderMatcher'; + +export interface HeaderFilter { + 'header'?: (_envoy_api_v2_route_HeaderMatcher); +} + +export interface HeaderFilter__Output { + 'header': (_envoy_api_v2_route_HeaderMatcher__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts new file mode 100644 index 000000000..0895567da --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + + +export interface NotHealthCheckFilter { +} + +export interface NotHealthCheckFilter__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.d.ts new file mode 100644 index 000000000..f4b2a19d2 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; + +export interface OrFilter { + 'filters'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter)[]; +} + +export interface OrFilter__Output { + 'filters': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts new file mode 100644 index 000000000..bb744a0c6 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + + +export interface ResponseFlagFilter { + 'flags'?: (string)[]; +} + +export interface ResponseFlagFilter__Output { + 'flags': (string)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts new file mode 100644 index 000000000..83e98db33 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts @@ -0,0 +1,15 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../../envoy/type/FractionalPercent'; + +export interface RuntimeFilter { + 'runtime_key'?: (string); + 'percent_sampled'?: (_envoy_type_FractionalPercent); + 'use_independent_randomness'?: (boolean); +} + +export interface RuntimeFilter__Output { + 'runtime_key': (string); + 'percent_sampled': (_envoy_type_FractionalPercent__Output); + 'use_independent_randomness': (boolean); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts new file mode 100644 index 000000000..6f8c46d22 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + +import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; + +export interface StatusCodeFilter { + 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter); +} + +export interface StatusCodeFilter__Output { + 'comparison': (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.d.ts new file mode 100644 index 000000000..a428d1a8a --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto + + +export interface TraceableFilter { +} + +export interface TraceableFilter__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.d.ts b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.d.ts new file mode 100644 index 000000000..8d3b82f04 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/config/listener/v2/api_listener.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface ApiListener { + 'api_listener'?: (_google_protobuf_Any); +} + +export interface ApiListener__Output { + 'api_listener': (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.d.ts b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.d.ts new file mode 100644 index 000000000..985cd2200 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto + + +export interface AdsDummy { +} + +export interface AdsDummy__Output { +} diff --git a/packages/grpc-js/src/generated/envoy/type/CodecClientType.d.ts b/packages/grpc-js/src/generated/envoy/type/CodecClientType.d.ts new file mode 100644 index 000000000..b32b1b1a9 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/CodecClientType.d.ts @@ -0,0 +1,7 @@ +// Original file: deps/envoy-api/envoy/type/http.proto + +export enum CodecClientType { + HTTP1 = 0, + HTTP2 = 1, + HTTP3 = 2, +} diff --git a/packages/grpc-js/src/generated/envoy/type/DoubleRange.d.ts b/packages/grpc-js/src/generated/envoy/type/DoubleRange.d.ts new file mode 100644 index 000000000..9d9bb8958 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/DoubleRange.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/type/range.proto + + +export interface DoubleRange { + 'start'?: (number | string); + 'end'?: (number | string); +} + +export interface DoubleRange__Output { + 'start': (number | string); + 'end': (number | string); +} diff --git a/packages/grpc-js/src/generated/envoy/type/FractionalPercent.d.ts b/packages/grpc-js/src/generated/envoy/type/FractionalPercent.d.ts new file mode 100644 index 000000000..bc7d3d52c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/FractionalPercent.d.ts @@ -0,0 +1,20 @@ +// Original file: deps/envoy-api/envoy/type/percent.proto + + +// Original file: deps/envoy-api/envoy/type/percent.proto + +export enum _envoy_type_FractionalPercent_DenominatorType { + HUNDRED = 0, + TEN_THOUSAND = 1, + MILLION = 2, +} + +export interface FractionalPercent { + 'numerator'?: (number); + 'denominator'?: (_envoy_type_FractionalPercent_DenominatorType | keyof typeof _envoy_type_FractionalPercent_DenominatorType); +} + +export interface FractionalPercent__Output { + 'numerator': (number); + 'denominator': (keyof typeof _envoy_type_FractionalPercent_DenominatorType); +} diff --git a/packages/grpc-js/src/generated/envoy/type/Int32Range.d.ts b/packages/grpc-js/src/generated/envoy/type/Int32Range.d.ts new file mode 100644 index 000000000..3adec7571 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/Int32Range.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/envoy-api/envoy/type/range.proto + + +export interface Int32Range { + 'start'?: (number); + 'end'?: (number); +} + +export interface Int32Range__Output { + 'start': (number); + 'end': (number); +} diff --git a/packages/grpc-js/src/generated/envoy/type/Int64Range.d.ts b/packages/grpc-js/src/generated/envoy/type/Int64Range.d.ts new file mode 100644 index 000000000..adc30bbd1 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/Int64Range.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/type/range.proto + +import { Long } from '@grpc/proto-loader'; + +export interface Int64Range { + 'start'?: (number | string | Long); + 'end'?: (number | string | Long); +} + +export interface Int64Range__Output { + 'start': (string); + 'end': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/type/Percent.d.ts b/packages/grpc-js/src/generated/envoy/type/Percent.d.ts new file mode 100644 index 000000000..656408905 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/Percent.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/envoy-api/envoy/type/percent.proto + + +export interface Percent { + 'value'?: (number | string); +} + +export interface Percent__Output { + 'value': (number | string); +} diff --git a/packages/grpc-js/src/generated/envoy/type/SemanticVersion.d.ts b/packages/grpc-js/src/generated/envoy/type/SemanticVersion.d.ts new file mode 100644 index 000000000..aa1f7bc43 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/SemanticVersion.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/type/semantic_version.proto + + +export interface SemanticVersion { + 'major_number'?: (number); + 'minor_number'?: (number); + 'patch'?: (number); +} + +export interface SemanticVersion__Output { + 'major_number': (number); + 'minor_number': (number); + 'patch': (number); +} diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.d.ts new file mode 100644 index 000000000..aab545afe --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.d.ts @@ -0,0 +1,11 @@ +// Original file: deps/envoy-api/envoy/type/matcher/string.proto + +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../envoy/type/matcher/StringMatcher'; + +export interface ListStringMatcher { + 'patterns'?: (_envoy_type_matcher_StringMatcher)[]; +} + +export interface ListStringMatcher__Output { + 'patterns': (_envoy_type_matcher_StringMatcher__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.d.ts new file mode 100644 index 000000000..6b4fa903c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/envoy-api/envoy/type/matcher/regex.proto + +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; + +export interface RegexMatchAndSubstitute { + 'pattern'?: (_envoy_type_matcher_RegexMatcher); + 'substitution'?: (string); +} + +export interface RegexMatchAndSubstitute__Output { + 'pattern': (_envoy_type_matcher_RegexMatcher__Output); + 'substitution': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.d.ts new file mode 100644 index 000000000..d4904964f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/envoy-api/envoy/type/matcher/regex.proto + +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; + +export interface _envoy_type_matcher_RegexMatcher_GoogleRE2 { + 'max_program_size'?: (_google_protobuf_UInt32Value); +} + +export interface _envoy_type_matcher_RegexMatcher_GoogleRE2__Output { + 'max_program_size': (_google_protobuf_UInt32Value__Output); +} + +export interface RegexMatcher { + 'google_re2'?: (_envoy_type_matcher_RegexMatcher_GoogleRE2); + 'regex'?: (string); + 'engine_type'?: "google_re2"; +} + +export interface RegexMatcher__Output { + 'google_re2'?: (_envoy_type_matcher_RegexMatcher_GoogleRE2__Output); + 'regex': (string); + 'engine_type': "google_re2"; +} diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.d.ts new file mode 100644 index 000000000..6a63a54dc --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/envoy-api/envoy/type/matcher/string.proto + +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; + +export interface StringMatcher { + 'exact'?: (string); + 'prefix'?: (string); + 'suffix'?: (string); + 'regex'?: (string); + 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); + 'ignore_case'?: (boolean); + 'match_pattern'?: "exact"|"prefix"|"suffix"|"regex"|"safe_regex"; +} + +export interface StringMatcher__Output { + 'exact'?: (string); + 'prefix'?: (string); + 'suffix'?: (string); + 'regex'?: (string); + 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); + 'ignore_case': (boolean); + 'match_pattern': "exact"|"prefix"|"suffix"|"regex"|"safe_regex"; +} diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.d.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.d.ts new file mode 100644 index 000000000..cb35fcef9 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto + + +export interface _envoy_type_metadata_v2_MetadataKey_PathSegment { + 'key'?: (string); + 'segment'?: "key"; +} + +export interface _envoy_type_metadata_v2_MetadataKey_PathSegment__Output { + 'key'?: (string); + 'segment': "key"; +} + +export interface MetadataKey { + 'key'?: (string); + 'path'?: (_envoy_type_metadata_v2_MetadataKey_PathSegment)[]; +} + +export interface MetadataKey__Output { + 'key': (string); + 'path': (_envoy_type_metadata_v2_MetadataKey_PathSegment__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.d.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.d.ts new file mode 100644 index 000000000..75c47776b --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.d.ts @@ -0,0 +1,42 @@ +// Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto + + +export interface _envoy_type_metadata_v2_MetadataKind_Request { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Request__Output { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Route { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Route__Output { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Cluster { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Cluster__Output { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Host { +} + +export interface _envoy_type_metadata_v2_MetadataKind_Host__Output { +} + +export interface MetadataKind { + 'request'?: (_envoy_type_metadata_v2_MetadataKind_Request); + 'route'?: (_envoy_type_metadata_v2_MetadataKind_Route); + 'cluster'?: (_envoy_type_metadata_v2_MetadataKind_Cluster); + 'host'?: (_envoy_type_metadata_v2_MetadataKind_Host); + 'kind'?: "request"|"route"|"cluster"|"host"; +} + +export interface MetadataKind__Output { + 'request'?: (_envoy_type_metadata_v2_MetadataKind_Request__Output); + 'route'?: (_envoy_type_metadata_v2_MetadataKind_Route__Output); + 'cluster'?: (_envoy_type_metadata_v2_MetadataKind_Cluster__Output); + 'host'?: (_envoy_type_metadata_v2_MetadataKind_Host__Output); + 'kind': "request"|"route"|"cluster"|"host"; +} diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.d.ts b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.d.ts new file mode 100644 index 000000000..32baa84be --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.d.ts @@ -0,0 +1,62 @@ +// Original file: deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto + +import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from '../../../../envoy/type/metadata/v2/MetadataKind'; +import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from '../../../../envoy/type/metadata/v2/MetadataKey'; + +export interface _envoy_type_tracing_v2_CustomTag_Literal { + 'value'?: (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Literal__Output { + 'value': (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Environment { + 'name'?: (string); + 'default_value'?: (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Environment__Output { + 'name': (string); + 'default_value': (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Header { + 'name'?: (string); + 'default_value'?: (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Header__Output { + 'name': (string); + 'default_value': (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Metadata { + 'kind'?: (_envoy_type_metadata_v2_MetadataKind); + 'metadata_key'?: (_envoy_type_metadata_v2_MetadataKey); + 'default_value'?: (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Metadata__Output { + 'kind': (_envoy_type_metadata_v2_MetadataKind__Output); + 'metadata_key': (_envoy_type_metadata_v2_MetadataKey__Output); + 'default_value': (string); +} + +export interface CustomTag { + 'tag'?: (string); + 'literal'?: (_envoy_type_tracing_v2_CustomTag_Literal); + 'environment'?: (_envoy_type_tracing_v2_CustomTag_Environment); + 'request_header'?: (_envoy_type_tracing_v2_CustomTag_Header); + 'metadata'?: (_envoy_type_tracing_v2_CustomTag_Metadata); + 'type'?: "literal"|"environment"|"request_header"|"metadata"; +} + +export interface CustomTag__Output { + 'tag': (string); + 'literal'?: (_envoy_type_tracing_v2_CustomTag_Literal__Output); + 'environment'?: (_envoy_type_tracing_v2_CustomTag_Environment__Output); + 'request_header'?: (_envoy_type_tracing_v2_CustomTag_Header__Output); + 'metadata'?: (_envoy_type_tracing_v2_CustomTag_Metadata__Output); + 'type': "literal"|"environment"|"request_header"|"metadata"; +} diff --git a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.d.ts b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.d.ts new file mode 100644 index 000000000..01ce13ba8 --- /dev/null +++ b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.d.ts @@ -0,0 +1,12 @@ +// Original file: node_modules/protobufjs/google/api/http.proto + + +export interface CustomHttpPattern { + 'kind'?: (string); + 'path'?: (string); +} + +export interface CustomHttpPattern__Output { + 'kind': (string); + 'path': (string); +} diff --git a/packages/grpc-js/src/generated/google/api/Http.d.ts b/packages/grpc-js/src/generated/google/api/Http.d.ts new file mode 100644 index 000000000..6a04f7b8c --- /dev/null +++ b/packages/grpc-js/src/generated/google/api/Http.d.ts @@ -0,0 +1,11 @@ +// Original file: node_modules/protobufjs/google/api/http.proto + +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +export interface Http { + 'rules'?: (_google_api_HttpRule)[]; +} + +export interface Http__Output { + 'rules': (_google_api_HttpRule__Output)[]; +} diff --git a/packages/grpc-js/src/generated/google/api/HttpRule.d.ts b/packages/grpc-js/src/generated/google/api/HttpRule.d.ts new file mode 100644 index 000000000..3bd9acd2b --- /dev/null +++ b/packages/grpc-js/src/generated/google/api/HttpRule.d.ts @@ -0,0 +1,30 @@ +// Original file: node_modules/protobufjs/google/api/http.proto + +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +export interface HttpRule { + 'get'?: (string); + 'put'?: (string); + 'post'?: (string); + 'delete'?: (string); + 'patch'?: (string); + 'custom'?: (_google_api_CustomHttpPattern); + 'selector'?: (string); + 'body'?: (string); + 'additional_bindings'?: (_google_api_HttpRule)[]; + 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; +} + +export interface HttpRule__Output { + 'get'?: (string); + 'put'?: (string); + 'post'?: (string); + 'delete'?: (string); + 'patch'?: (string); + 'custom'?: (_google_api_CustomHttpPattern__Output); + 'selector': (string); + 'body': (string); + 'additional_bindings': (_google_api_HttpRule__Output)[]; + 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Any.d.ts b/packages/grpc-js/src/generated/google/protobuf/Any.d.ts new file mode 100644 index 000000000..b592af4ba --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Any.d.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { AnyExtension } from '@grpc/proto-loader'; + +export type Any = AnyExtension | { + type_url: string; + value: Buffer | Uint8Array | string; +} + +export type Any__Output = AnyExtension | { + type_url: string; + value: Buffer; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/BoolValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/BoolValue.d.ts new file mode 100644 index 000000000..86507eaf1 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/BoolValue.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface BoolValue { + 'value'?: (boolean); +} + +export interface BoolValue__Output { + 'value': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/BytesValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/BytesValue.d.ts new file mode 100644 index 000000000..9cec76f71 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/BytesValue.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface BytesValue { + 'value'?: (Buffer | Uint8Array | string); +} + +export interface BytesValue__Output { + 'value': (Buffer); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.d.ts new file mode 100644 index 000000000..97726c403 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.d.ts @@ -0,0 +1,53 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; + +export interface _google_protobuf_DescriptorProto_ExtensionRange { + 'start'?: (number); + 'end'?: (number); +} + +export interface _google_protobuf_DescriptorProto_ExtensionRange__Output { + 'start': (number); + 'end': (number); +} + +export interface _google_protobuf_DescriptorProto_ReservedRange { + 'start'?: (number); + 'end'?: (number); +} + +export interface _google_protobuf_DescriptorProto_ReservedRange__Output { + 'start': (number); + 'end': (number); +} + +export interface DescriptorProto { + 'name'?: (string); + 'field'?: (_google_protobuf_FieldDescriptorProto)[]; + 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; + 'nested_type'?: (_google_protobuf_DescriptorProto)[]; + 'enum_type'?: (_google_protobuf_EnumDescriptorProto)[]; + 'extension_range'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; + 'oneof_decl'?: (_google_protobuf_OneofDescriptorProto)[]; + 'options'?: (_google_protobuf_MessageOptions); + 'reserved_range'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; + 'reserved_name'?: (string)[]; +} + +export interface DescriptorProto__Output { + 'name': (string); + 'field': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'nested_type': (_google_protobuf_DescriptorProto__Output)[]; + 'enum_type': (_google_protobuf_EnumDescriptorProto__Output)[]; + 'extension_range': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; + 'oneof_decl': (_google_protobuf_OneofDescriptorProto__Output)[]; + 'options': (_google_protobuf_MessageOptions__Output); + 'reserved_range': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; + 'reserved_name': (string)[]; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/DoubleValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/DoubleValue.d.ts new file mode 100644 index 000000000..e4f2eb4b8 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/DoubleValue.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface DoubleValue { + 'value'?: (number | string); +} + +export interface DoubleValue__Output { + 'value': (number | string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Duration.d.ts b/packages/grpc-js/src/generated/google/protobuf/Duration.d.ts new file mode 100644 index 000000000..78610b80a --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Duration.d.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface Duration { + 'seconds'?: (number | string | Long); + 'nanos'?: (number); +} + +export interface Duration__Output { + 'seconds': (string); + 'nanos': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Empty.d.ts b/packages/grpc-js/src/generated/google/protobuf/Empty.d.ts new file mode 100644 index 000000000..f32c2a284 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Empty.d.ts @@ -0,0 +1,8 @@ +// Original file: null + + +export interface Empty { +} + +export interface Empty__Output { +} diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.d.ts new file mode 100644 index 000000000..55059ba9e --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.d.ts @@ -0,0 +1,16 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; + +export interface EnumDescriptorProto { + 'name'?: (string); + 'value'?: (_google_protobuf_EnumValueDescriptorProto)[]; + 'options'?: (_google_protobuf_EnumOptions); +} + +export interface EnumDescriptorProto__Output { + 'name': (string); + 'value': (_google_protobuf_EnumValueDescriptorProto__Output)[]; + 'options': (_google_protobuf_EnumOptions__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.d.ts new file mode 100644 index 000000000..1c096a306 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.d.ts @@ -0,0 +1,18 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; + +export interface EnumOptions { + 'allow_alias'?: (boolean); + 'deprecated'?: (boolean); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation); +} + +export interface EnumOptions__Output { + 'allow_alias': (boolean); + 'deprecated': (boolean); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.enum_migrate': (_udpa_annotations_MigrateAnnotation__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.d.ts new file mode 100644 index 000000000..a0b8308d8 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.d.ts @@ -0,0 +1,15 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; + +export interface EnumValueDescriptorProto { + 'name'?: (string); + 'number'?: (number); + 'options'?: (_google_protobuf_EnumValueOptions); +} + +export interface EnumValueDescriptorProto__Output { + 'name': (string); + 'number': (number); + 'options': (_google_protobuf_EnumValueOptions__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.d.ts new file mode 100644 index 000000000..29c560438 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.d.ts @@ -0,0 +1,18 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; + +export interface EnumValueOptions { + 'deprecated'?: (boolean); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation); + '.envoy.annotations.disallowed_by_default_enum'?: (boolean); +} + +export interface EnumValueOptions__Output { + 'deprecated': (boolean); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output); + '.envoy.annotations.disallowed_by_default_enum': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.d.ts new file mode 100644 index 000000000..b5c089c9c --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.d.ts @@ -0,0 +1,60 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; + +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +export enum _google_protobuf_FieldDescriptorProto_Type { + TYPE_DOUBLE = 1, + TYPE_FLOAT = 2, + TYPE_INT64 = 3, + TYPE_UINT64 = 4, + TYPE_INT32 = 5, + TYPE_FIXED64 = 6, + TYPE_FIXED32 = 7, + TYPE_BOOL = 8, + TYPE_STRING = 9, + TYPE_GROUP = 10, + TYPE_MESSAGE = 11, + TYPE_BYTES = 12, + TYPE_UINT32 = 13, + TYPE_ENUM = 14, + TYPE_SFIXED32 = 15, + TYPE_SFIXED64 = 16, + TYPE_SINT32 = 17, + TYPE_SINT64 = 18, +} + +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +export enum _google_protobuf_FieldDescriptorProto_Label { + LABEL_OPTIONAL = 1, + LABEL_REQUIRED = 2, + LABEL_REPEATED = 3, +} + +export interface FieldDescriptorProto { + 'name'?: (string); + 'number'?: (number); + 'label'?: (_google_protobuf_FieldDescriptorProto_Label | keyof typeof _google_protobuf_FieldDescriptorProto_Label); + 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); + 'type_name'?: (string); + 'extendee'?: (string); + 'default_value'?: (string); + 'oneof_index'?: (number); + 'json_name'?: (string); + 'options'?: (_google_protobuf_FieldOptions); +} + +export interface FieldDescriptorProto__Output { + 'name': (string); + 'number': (number); + 'label': (keyof typeof _google_protobuf_FieldDescriptorProto_Label); + 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); + 'type_name': (string); + 'extendee': (string); + 'default_value': (string); + 'oneof_index': (number); + 'json_name': (string); + 'options': (_google_protobuf_FieldOptions__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.d.ts new file mode 100644 index 000000000..d2bec450d --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.d.ts @@ -0,0 +1,49 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; + +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +export enum _google_protobuf_FieldOptions_CType { + STRING = 0, + CORD = 1, + STRING_PIECE = 2, +} + +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +export enum _google_protobuf_FieldOptions_JSType { + JS_NORMAL = 0, + JS_STRING = 1, + JS_NUMBER = 2, +} + +export interface FieldOptions { + 'ctype'?: (_google_protobuf_FieldOptions_CType | keyof typeof _google_protobuf_FieldOptions_CType); + 'packed'?: (boolean); + 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); + 'lazy'?: (boolean); + 'deprecated'?: (boolean); + 'weak'?: (boolean); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation); + '.validate.rules'?: (_validate_FieldRules); + '.envoy.annotations.disallowed_by_default'?: (boolean); + '.udpa.annotations.sensitive'?: (boolean); +} + +export interface FieldOptions__Output { + 'ctype': (keyof typeof _google_protobuf_FieldOptions_CType); + 'packed': (boolean); + 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); + 'lazy': (boolean); + 'deprecated': (boolean); + 'weak': (boolean); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output); + '.validate.rules': (_validate_FieldRules__Output); + '.envoy.annotations.disallowed_by_default': (boolean); + '.udpa.annotations.sensitive': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.d.ts new file mode 100644 index 000000000..aeebbf242 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.d.ts @@ -0,0 +1,38 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; + +export interface FileDescriptorProto { + 'name'?: (string); + 'package'?: (string); + 'dependency'?: (string)[]; + 'public_dependency'?: (number)[]; + 'weak_dependency'?: (number)[]; + 'message_type'?: (_google_protobuf_DescriptorProto)[]; + 'enum_type'?: (_google_protobuf_EnumDescriptorProto)[]; + 'service'?: (_google_protobuf_ServiceDescriptorProto)[]; + 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; + 'options'?: (_google_protobuf_FileOptions); + 'source_code_info'?: (_google_protobuf_SourceCodeInfo); + 'syntax'?: (string); +} + +export interface FileDescriptorProto__Output { + 'name': (string); + 'package': (string); + 'dependency': (string)[]; + 'public_dependency': (number)[]; + 'weak_dependency': (number)[]; + 'message_type': (_google_protobuf_DescriptorProto__Output)[]; + 'enum_type': (_google_protobuf_EnumDescriptorProto__Output)[]; + 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; + 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'options': (_google_protobuf_FileOptions__Output); + 'source_code_info': (_google_protobuf_SourceCodeInfo__Output); + 'syntax': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.d.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.d.ts new file mode 100644 index 000000000..b30f4679c --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.d.ts @@ -0,0 +1,11 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; + +export interface FileDescriptorSet { + 'file'?: (_google_protobuf_FileDescriptorProto)[]; +} + +export interface FileDescriptorSet__Output { + 'file': (_google_protobuf_FileDescriptorProto__Output)[]; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FileOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/FileOptions.d.ts new file mode 100644 index 000000000..337f38d82 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FileOptions.d.ts @@ -0,0 +1,53 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; + +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +export enum _google_protobuf_FileOptions_OptimizeMode { + SPEED = 1, + CODE_SIZE = 2, + LITE_RUNTIME = 3, +} + +export interface FileOptions { + 'java_package'?: (string); + 'java_outer_classname'?: (string); + 'java_multiple_files'?: (boolean); + 'java_generate_equals_and_hash'?: (boolean); + 'java_string_check_utf8'?: (boolean); + 'optimize_for'?: (_google_protobuf_FileOptions_OptimizeMode | keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'go_package'?: (string); + 'cc_generic_services'?: (boolean); + 'java_generic_services'?: (boolean); + 'py_generic_services'?: (boolean); + 'deprecated'?: (boolean); + 'cc_enable_arenas'?: (boolean); + 'objc_class_prefix'?: (string); + 'csharp_namespace'?: (string); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation); + '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation); +} + +export interface FileOptions__Output { + 'java_package': (string); + 'java_outer_classname': (string); + 'java_multiple_files': (boolean); + 'java_generate_equals_and_hash': (boolean); + 'java_string_check_utf8': (boolean); + 'optimize_for': (keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'go_package': (string); + 'cc_generic_services': (boolean); + 'java_generic_services': (boolean); + 'py_generic_services': (boolean); + 'deprecated': (boolean); + 'cc_enable_arenas': (boolean); + 'objc_class_prefix': (string); + 'csharp_namespace': (string); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.file_migrate': (_udpa_annotations_FileMigrateAnnotation__Output); + '.udpa.annotations.file_status': (_udpa_annotations_StatusAnnotation__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FloatValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/FloatValue.d.ts new file mode 100644 index 000000000..144a9a585 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FloatValue.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface FloatValue { + 'value'?: (number | string); +} + +export interface FloatValue__Output { + 'value': (number | string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.d.ts b/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.d.ts new file mode 100644 index 000000000..f925dbff1 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.d.ts @@ -0,0 +1,24 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + + +export interface _google_protobuf_GeneratedCodeInfo_Annotation { + 'path'?: (number)[]; + 'source_file'?: (string); + 'begin'?: (number); + 'end'?: (number); +} + +export interface _google_protobuf_GeneratedCodeInfo_Annotation__Output { + 'path': (number)[]; + 'source_file': (string); + 'begin': (number); + 'end': (number); +} + +export interface GeneratedCodeInfo { + 'annotation'?: (_google_protobuf_GeneratedCodeInfo_Annotation)[]; +} + +export interface GeneratedCodeInfo__Output { + 'annotation': (_google_protobuf_GeneratedCodeInfo_Annotation__Output)[]; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Int32Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/Int32Value.d.ts new file mode 100644 index 000000000..ec4eeb7ec --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Int32Value.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface Int32Value { + 'value'?: (number); +} + +export interface Int32Value__Output { + 'value': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Int64Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/Int64Value.d.ts new file mode 100644 index 000000000..38b0e28f3 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Int64Value.d.ts @@ -0,0 +1,11 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface Int64Value { + 'value'?: (number | string | Long); +} + +export interface Int64Value__Output { + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/ListValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/ListValue.d.ts new file mode 100644 index 000000000..4b3cf67d7 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/ListValue.d.ts @@ -0,0 +1,11 @@ +// Original file: null + +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; + +export interface ListValue { + 'values'?: (_google_protobuf_Value)[]; +} + +export interface ListValue__Output { + 'values': (_google_protobuf_Value__Output)[]; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.d.ts new file mode 100644 index 000000000..ec6508b0c --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.d.ts @@ -0,0 +1,24 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; + +export interface MessageOptions { + 'message_set_wire_format'?: (boolean); + 'no_standard_descriptor_accessor'?: (boolean); + 'deprecated'?: (boolean); + 'map_entry'?: (boolean); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation); + '.validate.disabled'?: (boolean); +} + +export interface MessageOptions__Output { + 'message_set_wire_format': (boolean); + 'no_standard_descriptor_accessor': (boolean); + 'deprecated': (boolean); + 'map_entry': (boolean); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output); + '.validate.disabled': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.d.ts new file mode 100644 index 000000000..a378ab637 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.d.ts @@ -0,0 +1,21 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; + +export interface MethodDescriptorProto { + 'name'?: (string); + 'input_type'?: (string); + 'output_type'?: (string); + 'options'?: (_google_protobuf_MethodOptions); + 'client_streaming'?: (boolean); + 'server_streaming'?: (boolean); +} + +export interface MethodDescriptorProto__Output { + 'name': (string); + 'input_type': (string); + 'output_type': (string); + 'options': (_google_protobuf_MethodOptions__Output); + 'client_streaming': (boolean); + 'server_streaming': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.d.ts new file mode 100644 index 000000000..582ba4bef --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.d.ts @@ -0,0 +1,16 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +export interface MethodOptions { + 'deprecated'?: (boolean); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.google.api.http'?: (_google_api_HttpRule); +} + +export interface MethodOptions__Output { + 'deprecated': (boolean); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.google.api.http': (_google_api_HttpRule__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/NullValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/NullValue.d.ts new file mode 100644 index 000000000..377aab885 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/NullValue.d.ts @@ -0,0 +1,5 @@ +// Original file: null + +export enum NullValue { + NULL_VALUE = 0, +} diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.d.ts new file mode 100644 index 000000000..084cabff5 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.d.ts @@ -0,0 +1,13 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; + +export interface OneofDescriptorProto { + 'name'?: (string); + 'options'?: (_google_protobuf_OneofOptions); +} + +export interface OneofDescriptorProto__Output { + 'name': (string); + 'options': (_google_protobuf_OneofOptions__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/OneofOptions.d.ts new file mode 100644 index 000000000..ea07ab22f --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/OneofOptions.d.ts @@ -0,0 +1,13 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface OneofOptions { + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + '.validate.required'?: (boolean); +} + +export interface OneofOptions__Output { + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + '.validate.required': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.d.ts new file mode 100644 index 000000000..aab7736ce --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.d.ts @@ -0,0 +1,16 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; + +export interface ServiceDescriptorProto { + 'name'?: (string); + 'method'?: (_google_protobuf_MethodDescriptorProto)[]; + 'options'?: (_google_protobuf_ServiceOptions); +} + +export interface ServiceDescriptorProto__Output { + 'name': (string); + 'method': (_google_protobuf_MethodDescriptorProto__Output)[]; + 'options': (_google_protobuf_ServiceOptions__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.d.ts new file mode 100644 index 000000000..602e670ad --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.d.ts @@ -0,0 +1,13 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface ServiceOptions { + 'deprecated'?: (boolean); + 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; +} + +export interface ServiceOptions__Output { + 'deprecated': (boolean); + 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.d.ts b/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.d.ts new file mode 100644 index 000000000..cf68f3ac1 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.d.ts @@ -0,0 +1,26 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + + +export interface _google_protobuf_SourceCodeInfo_Location { + 'path'?: (number)[]; + 'span'?: (number)[]; + 'leading_comments'?: (string); + 'trailing_comments'?: (string); + 'leading_detached_comments'?: (string)[]; +} + +export interface _google_protobuf_SourceCodeInfo_Location__Output { + 'path': (number)[]; + 'span': (number)[]; + 'leading_comments': (string); + 'trailing_comments': (string); + 'leading_detached_comments': (string)[]; +} + +export interface SourceCodeInfo { + 'location'?: (_google_protobuf_SourceCodeInfo_Location)[]; +} + +export interface SourceCodeInfo__Output { + 'location': (_google_protobuf_SourceCodeInfo_Location__Output)[]; +} diff --git a/packages/grpc-js/src/generated/google/protobuf/StringValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/StringValue.d.ts new file mode 100644 index 000000000..673090e3f --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/StringValue.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface StringValue { + 'value'?: (string); +} + +export interface StringValue__Output { + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Struct.d.ts b/packages/grpc-js/src/generated/google/protobuf/Struct.d.ts new file mode 100644 index 000000000..436a251a3 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Struct.d.ts @@ -0,0 +1,11 @@ +// Original file: null + +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; + +export interface Struct { + 'fields'?: (_google_protobuf_Value); +} + +export interface Struct__Output { + 'fields': (_google_protobuf_Value__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Timestamp.d.ts b/packages/grpc-js/src/generated/google/protobuf/Timestamp.d.ts new file mode 100644 index 000000000..f8747e93e --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Timestamp.d.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface Timestamp { + 'seconds'?: (number | string | Long); + 'nanos'?: (number); +} + +export interface Timestamp__Output { + 'seconds': (string); + 'nanos': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt32Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/UInt32Value.d.ts new file mode 100644 index 000000000..973ab34a5 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/UInt32Value.d.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface UInt32Value { + 'value'?: (number); +} + +export interface UInt32Value__Output { + 'value': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt64Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/UInt64Value.d.ts new file mode 100644 index 000000000..790901733 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/UInt64Value.d.ts @@ -0,0 +1,11 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface UInt64Value { + 'value'?: (number | string | Long); +} + +export interface UInt64Value__Output { + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.d.ts b/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.d.ts new file mode 100644 index 000000000..770394761 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.d.ts @@ -0,0 +1,33 @@ +// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto + +import { Long } from '@grpc/proto-loader'; + +export interface _google_protobuf_UninterpretedOption_NamePart { + 'name_part'?: (string); + 'is_extension'?: (boolean); +} + +export interface _google_protobuf_UninterpretedOption_NamePart__Output { + 'name_part': (string); + 'is_extension': (boolean); +} + +export interface UninterpretedOption { + 'name'?: (_google_protobuf_UninterpretedOption_NamePart)[]; + 'identifier_value'?: (string); + 'positive_int_value'?: (number | string | Long); + 'negative_int_value'?: (number | string | Long); + 'double_value'?: (number | string); + 'string_value'?: (Buffer | Uint8Array | string); + 'aggregate_value'?: (string); +} + +export interface UninterpretedOption__Output { + 'name': (_google_protobuf_UninterpretedOption_NamePart__Output)[]; + 'identifier_value': (string); + 'positive_int_value': (string); + 'negative_int_value': (string); + 'double_value': (number | string); + 'string_value': (Buffer); + 'aggregate_value': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/Value.d.ts new file mode 100644 index 000000000..0097135be --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Value.d.ts @@ -0,0 +1,25 @@ +// Original file: null + +import { NullValue as _google_protobuf_NullValue } from '../../google/protobuf/NullValue'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../google/protobuf/Struct'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from '../../google/protobuf/ListValue'; + +export interface Value { + 'nullValue'?: (_google_protobuf_NullValue | keyof typeof _google_protobuf_NullValue); + 'numberValue'?: (number | string); + 'stringValue'?: (string); + 'boolValue'?: (boolean); + 'structValue'?: (_google_protobuf_Struct); + 'listValue'?: (_google_protobuf_ListValue); + 'kind'?: "nullValue"|"numberValue"|"stringValue"|"boolValue"|"structValue"|"listValue"; +} + +export interface Value__Output { + 'nullValue'?: (keyof typeof _google_protobuf_NullValue); + 'numberValue'?: (number | string); + 'stringValue'?: (string); + 'boolValue'?: (boolean); + 'structValue'?: (_google_protobuf_Struct__Output); + 'listValue'?: (_google_protobuf_ListValue__Output); + 'kind': "nullValue"|"numberValue"|"stringValue"|"boolValue"|"structValue"|"listValue"; +} diff --git a/packages/grpc-js/src/generated/google/rpc/Status.d.ts b/packages/grpc-js/src/generated/google/rpc/Status.d.ts new file mode 100644 index 000000000..f1d6ecbcf --- /dev/null +++ b/packages/grpc-js/src/generated/google/rpc/Status.d.ts @@ -0,0 +1,15 @@ +// Original file: deps/googleapis/google/rpc/status.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; + +export interface Status { + 'code'?: (number); + 'message'?: (string); + 'details'?: (_google_protobuf_Any)[]; +} + +export interface Status__Output { + 'code': (number); + 'message': (string); + 'details': (_google_protobuf_Any__Output)[]; +} diff --git a/packages/grpc-js/src/generated/listener.d.ts b/packages/grpc-js/src/generated/listener.d.ts new file mode 100644 index 000000000..9d6d8cd6d --- /dev/null +++ b/packages/grpc-js/src/generated/listener.d.ts @@ -0,0 +1,1757 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { Listener as _envoy_api_v2_Listener, Listener__Output as _envoy_api_v2_Listener__Output } from './envoy/api/v2/Listener'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from './envoy/api/v2/listener/UdpListenerConfig'; +import { ActiveRawUdpListenerConfig as _envoy_api_v2_listener_ActiveRawUdpListenerConfig, ActiveRawUdpListenerConfig__Output as _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output } from './envoy/api/v2/listener/ActiveRawUdpListenerConfig'; +import { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from './envoy/api/v2/listener/Filter'; +import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from './envoy/api/v2/listener/FilterChainMatch'; +import { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from './envoy/api/v2/listener/FilterChain'; +import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from './envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; +import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from './envoy/api/v2/listener/ListenerFilter'; +import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; +import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; +import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; +import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; +import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; +import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; +import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; +import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; +import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; +import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; +import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; +import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; +import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; +import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; +import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; +import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from './envoy/api/v2/route/CorsPolicy'; +import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; +import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; +import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from './envoy/api/v2/route/HedgePolicy'; +import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from './envoy/api/v2/route/RedirectAction'; +import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; +import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; +import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from './envoy/api/v2/route/Tracing'; +import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from './envoy/api/v2/route/VirtualCluster'; +import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; +import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; +import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from './envoy/config/filter/accesslog/v2/AccessLog'; +import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from './envoy/config/filter/accesslog/v2/AccessLogFilter'; +import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from './envoy/config/filter/accesslog/v2/ComparisonFilter'; +import { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from './envoy/config/filter/accesslog/v2/StatusCodeFilter'; +import { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from './envoy/config/filter/accesslog/v2/DurationFilter'; +import { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from './envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; +import { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from './envoy/config/filter/accesslog/v2/TraceableFilter'; +import { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from './envoy/config/filter/accesslog/v2/RuntimeFilter'; +import { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from './envoy/config/filter/accesslog/v2/AndFilter'; +import { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from './envoy/config/filter/accesslog/v2/OrFilter'; +import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from './envoy/config/filter/accesslog/v2/HeaderFilter'; +import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from './envoy/config/filter/accesslog/v2/ResponseFlagFilter'; +import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from './envoy/config/filter/accesslog/v2/GrpcStatusFilter'; +import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from './envoy/config/filter/accesslog/v2/ExtensionFilter'; +import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from './envoy/config/listener/v2/ApiListener'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; +import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; +import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; +import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; + +export namespace messages { + export namespace envoy { + export namespace api { + export namespace v2 { + export type Listener = _envoy_api_v2_Listener; + export type Listener__Output = _envoy_api_v2_Listener__Output; + export namespace core { + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type BuildVersion = _envoy_api_v2_core_BuildVersion; + export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type Extension = _envoy_api_v2_core_Extension; + export type Extension__Output = _envoy_api_v2_core_Extension__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type HeaderValue = _envoy_api_v2_core_HeaderValue; + export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + } + export namespace listener { + export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; + export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; + export type ActiveRawUdpListenerConfig = _envoy_api_v2_listener_ActiveRawUdpListenerConfig; + export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; + export type Filter = _envoy_api_v2_listener_Filter; + export type Filter__Output = _envoy_api_v2_listener_Filter__Output; + export type FilterChainMatch = _envoy_api_v2_listener_FilterChainMatch; + export type FilterChainMatch__Output = _envoy_api_v2_listener_FilterChainMatch__Output; + export type FilterChain = _envoy_api_v2_listener_FilterChain; + export type FilterChain__Output = _envoy_api_v2_listener_FilterChain__Output; + export type ListenerFilterChainMatchPredicate = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate; + export type ListenerFilterChainMatchPredicate__Output = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output; + export type ListenerFilter = _envoy_api_v2_listener_ListenerFilter; + export type ListenerFilter__Output = _envoy_api_v2_listener_ListenerFilter__Output; + } + export namespace auth { + export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; + export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; + export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; + export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; + export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; + export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; + export type GenericSecret = _envoy_api_v2_auth_GenericSecret; + export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; + export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; + export type Secret = _envoy_api_v2_auth_Secret; + export type Secret__Output = _envoy_api_v2_auth_Secret__Output; + export type TlsParameters = _envoy_api_v2_auth_TlsParameters; + export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; + export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; + export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; + export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; + export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; + export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; + export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; + export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; + export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + } + export namespace route { + export type VirtualHost = _envoy_api_v2_route_VirtualHost; + export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; + export type FilterAction = _envoy_api_v2_route_FilterAction; + export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; + export type Route = _envoy_api_v2_route_Route; + export type Route__Output = _envoy_api_v2_route_Route__Output; + export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; + export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; + export type RouteMatch = _envoy_api_v2_route_RouteMatch; + export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; + export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; + export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; + export type RouteAction = _envoy_api_v2_route_RouteAction; + export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; + export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; + export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; + export type RedirectAction = _envoy_api_v2_route_RedirectAction; + export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; + export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; + export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; + export type Decorator = _envoy_api_v2_route_Decorator; + export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; + export type Tracing = _envoy_api_v2_route_Tracing; + export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; + export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; + export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; + export type RateLimit = _envoy_api_v2_route_RateLimit; + export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; + export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; + export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; + export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; + export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + } + } + } + export namespace config { + export namespace filter { + export namespace accesslog { + export namespace v2 { + export type AccessLog = _envoy_config_filter_accesslog_v2_AccessLog; + export type AccessLog__Output = _envoy_config_filter_accesslog_v2_AccessLog__Output; + export type AccessLogFilter = _envoy_config_filter_accesslog_v2_AccessLogFilter; + export type AccessLogFilter__Output = _envoy_config_filter_accesslog_v2_AccessLogFilter__Output; + export type ComparisonFilter = _envoy_config_filter_accesslog_v2_ComparisonFilter; + export type ComparisonFilter__Output = _envoy_config_filter_accesslog_v2_ComparisonFilter__Output; + export type StatusCodeFilter = _envoy_config_filter_accesslog_v2_StatusCodeFilter; + export type StatusCodeFilter__Output = _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output; + export type DurationFilter = _envoy_config_filter_accesslog_v2_DurationFilter; + export type DurationFilter__Output = _envoy_config_filter_accesslog_v2_DurationFilter__Output; + export type NotHealthCheckFilter = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter; + export type NotHealthCheckFilter__Output = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output; + export type TraceableFilter = _envoy_config_filter_accesslog_v2_TraceableFilter; + export type TraceableFilter__Output = _envoy_config_filter_accesslog_v2_TraceableFilter__Output; + export type RuntimeFilter = _envoy_config_filter_accesslog_v2_RuntimeFilter; + export type RuntimeFilter__Output = _envoy_config_filter_accesslog_v2_RuntimeFilter__Output; + export type AndFilter = _envoy_config_filter_accesslog_v2_AndFilter; + export type AndFilter__Output = _envoy_config_filter_accesslog_v2_AndFilter__Output; + export type OrFilter = _envoy_config_filter_accesslog_v2_OrFilter; + export type OrFilter__Output = _envoy_config_filter_accesslog_v2_OrFilter__Output; + export type HeaderFilter = _envoy_config_filter_accesslog_v2_HeaderFilter; + export type HeaderFilter__Output = _envoy_config_filter_accesslog_v2_HeaderFilter__Output; + export type ResponseFlagFilter = _envoy_config_filter_accesslog_v2_ResponseFlagFilter; + export type ResponseFlagFilter__Output = _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output; + export type GrpcStatusFilter = _envoy_config_filter_accesslog_v2_GrpcStatusFilter; + export type GrpcStatusFilter__Output = _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output; + export type ExtensionFilter = _envoy_config_filter_accesslog_v2_ExtensionFilter; + export type ExtensionFilter__Output = _envoy_config_filter_accesslog_v2_ExtensionFilter__Output; + } + } + } + export namespace listener { + export namespace v2 { + export type ApiListener = _envoy_config_listener_v2_ApiListener; + export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; + } + } + } + export namespace type { + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; + export type FractionalPercent = _envoy_type_FractionalPercent; + export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + export namespace matcher { + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + } + export namespace tracing { + export namespace v2 { + export type CustomTag = _envoy_type_tracing_v2_CustomTag; + export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; + } + } + export namespace metadata { + export namespace v2 { + export type MetadataKey = _envoy_type_metadata_v2_MetadataKey; + export type MetadataKey__Output = _envoy_type_metadata_v2_MetadataKey__Output; + export type MetadataKind = _envoy_type_metadata_v2_MetadataKind; + export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; + } + } + export namespace validate { + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type KnownRegex = _validate_KnownRegex; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + } + export namespace google { + export namespace protobuf { + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type BoolValue = _google_protobuf_BoolValue; + export type BoolValue__Output = _google_protobuf_BoolValue__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type BytesValue = _google_protobuf_BytesValue; + export type BytesValue__Output = _google_protobuf_BytesValue__Output; + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; + export type NullValue = _google_protobuf_NullValue; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type DescriptorProto = _google_protobuf_DescriptorProto; + export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; + export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; + export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type FileOptions = _google_protobuf_FileOptions; + export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type MessageOptions = _google_protobuf_MessageOptions; + export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type OneofOptions = _google_protobuf_OneofOptions; + export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceOptions = _google_protobuf_ServiceOptions; + export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; + export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; + } + export namespace api { + export type Http = _google_api_Http; + export type Http__Output = _google_api_Http__Output; + export type HttpRule = _google_api_HttpRule; + export type HttpRule__Output = _google_api_HttpRule__Output; + export type CustomHttpPattern = _google_api_CustomHttpPattern; + export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + } + } +} + +export namespace ClientInterfaces { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace Listener { + export namespace DeprecatedV1 { + } + export namespace ConnectionBalanceConfig { + export namespace ExactBalance { + } + } + } + export namespace core { + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace SocketOption { + } + export namespace BackoffStrategy { + } + export namespace HttpUri { + } + export namespace ApiConfigSource { + } + export namespace AggregatedConfigSource { + } + export namespace SelfConfigSource { + } + export namespace RateLimitSettings { + } + export namespace ConfigSource { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + export namespace listener { + export namespace UdpListenerConfig { + } + export namespace ActiveRawUdpListenerConfig { + } + export namespace Filter { + } + export namespace FilterChainMatch { + } + export namespace FilterChain { + } + export namespace ListenerFilterChainMatchPredicate { + export namespace MatchSet { + } + } + export namespace ListenerFilter { + } + } + export namespace auth { + export namespace UpstreamTlsContext { + } + export namespace DownstreamTlsContext { + } + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } + } + export namespace GenericSecret { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } + export namespace TlsParameters { + } + export namespace PrivateKeyProvider { + } + export namespace TlsCertificate { + } + export namespace TlsSessionTicketKeys { + } + export namespace CertificateValidationContext { + } + } + export namespace route { + export namespace VirtualHost { + } + export namespace FilterAction { + } + export namespace Route { + } + export namespace WeightedCluster { + export namespace ClusterWeight { + } + } + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { + } + export namespace TlsContextMatchOptions { + } + } + export namespace CorsPolicy { + } + export namespace RouteAction { + export namespace RequestMirrorPolicy { + } + export namespace HashPolicy { + export namespace Header { + } + export namespace Cookie { + } + export namespace ConnectionProperties { + } + export namespace QueryParameter { + } + export namespace FilterState { + } + } + export namespace UpgradeConfig { + } + } + export namespace RetryPolicy { + export namespace RetryPriority { + } + export namespace RetryHostPredicate { + } + export namespace RetryBackOff { + } + } + export namespace HedgePolicy { + } + export namespace RedirectAction { + } + export namespace DirectResponseAction { + } + export namespace Decorator { + } + export namespace Tracing { + } + export namespace VirtualCluster { + } + export namespace RateLimit { + export namespace Action { + export namespace SourceCluster { + } + export namespace DestinationCluster { + } + export namespace RequestHeaders { + } + export namespace RemoteAddress { + } + export namespace GenericKey { + } + export namespace HeaderValueMatch { + } + } + } + export namespace HeaderMatcher { + } + export namespace QueryParameterMatcher { + } + } + } + } + export namespace config { + export namespace filter { + export namespace accesslog { + export namespace v2 { + export namespace AccessLog { + } + export namespace AccessLogFilter { + } + export namespace ComparisonFilter { + } + export namespace StatusCodeFilter { + } + export namespace DurationFilter { + } + export namespace NotHealthCheckFilter { + } + export namespace TraceableFilter { + } + export namespace RuntimeFilter { + } + export namespace AndFilter { + } + export namespace OrFilter { + } + export namespace HeaderFilter { + } + export namespace ResponseFlagFilter { + } + export namespace GrpcStatusFilter { + } + export namespace ExtensionFilter { + } + } + } + } + export namespace listener { + export namespace v2 { + export namespace ApiListener { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace matcher { + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Literal { + } + export namespace Environment { + } + export namespace Header { + } + export namespace Metadata { + } + } + } + } + export namespace metadata { + export namespace v2 { + export namespace MetadataKey { + export namespace PathSegment { + } + } + export namespace MetadataKind { + export namespace Request { + } + export namespace Route { + } + export namespace Cluster { + } + export namespace Host { + } + } + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Duration { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Any { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Timestamp { + } + export namespace Empty { + } + } + export namespace api { + export namespace Http { + } + export namespace HttpRule { + } + export namespace CustomHttpPattern { + } + } + } +} + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + api: { + v2: { + Listener: MessageTypeDefinition + core: { + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RequestMethod: EnumTypeDefinition + TrafficDirection: EnumTypeDefinition + Locality: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + Extension: MessageTypeDefinition + Node: MessageTypeDefinition + Metadata: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + DataSource: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + TransportSocket: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + SocketOption: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + ApiConfigSource: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + GrpcService: MessageTypeDefinition + } + listener: { + UdpListenerConfig: MessageTypeDefinition + ActiveRawUdpListenerConfig: MessageTypeDefinition + Filter: MessageTypeDefinition + FilterChainMatch: MessageTypeDefinition + FilterChain: MessageTypeDefinition + ListenerFilterChainMatchPredicate: MessageTypeDefinition + ListenerFilter: MessageTypeDefinition + } + auth: { + UpstreamTlsContext: MessageTypeDefinition + DownstreamTlsContext: MessageTypeDefinition + CommonTlsContext: MessageTypeDefinition + GenericSecret: MessageTypeDefinition + SdsSecretConfig: MessageTypeDefinition + Secret: MessageTypeDefinition + TlsParameters: MessageTypeDefinition + PrivateKeyProvider: MessageTypeDefinition + TlsCertificate: MessageTypeDefinition + TlsSessionTicketKeys: MessageTypeDefinition + CertificateValidationContext: MessageTypeDefinition + } + route: { + VirtualHost: MessageTypeDefinition + FilterAction: MessageTypeDefinition + Route: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + CorsPolicy: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + Decorator: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + RateLimit: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + } + } + } + config: { + filter: { + accesslog: { + v2: { + AccessLog: MessageTypeDefinition + AccessLogFilter: MessageTypeDefinition + ComparisonFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + DurationFilter: MessageTypeDefinition + NotHealthCheckFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition + OrFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition + ResponseFlagFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + } + } + } + listener: { + v2: { + ApiListener: MessageTypeDefinition + } + } + } + type: { + Percent: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Int32Range: MessageTypeDefinition + DoubleRange: MessageTypeDefinition + matcher: { + StringMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + } + tracing: { + v2: { + CustomTag: MessageTypeDefinition + } + } + metadata: { + v2: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + } + annotations: { + } + } + udpa: { + annotations: { + MigrateAnnotation: MessageTypeDefinition + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + FieldRules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + StringRules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + BytesRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + MapRules: MessageTypeDefinition + AnyRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + } + google: { + protobuf: { + Duration: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + FloatValue: MessageTypeDefinition + Int64Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + Int32Value: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + BoolValue: MessageTypeDefinition + StringValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + Any: MessageTypeDefinition + Struct: MessageTypeDefinition + Value: MessageTypeDefinition + NullValue: EnumTypeDefinition + ListValue: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + FileOptions: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Timestamp: MessageTypeDefinition + Empty: MessageTypeDefinition + } + api: { + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + CustomHttpPattern: MessageTypeDefinition + } + } +} + +export namespace ServiceHandlers { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace Listener { + export namespace DeprecatedV1 { + } + export namespace ConnectionBalanceConfig { + export namespace ExactBalance { + } + } + } + export namespace core { + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace SocketOption { + } + export namespace BackoffStrategy { + } + export namespace HttpUri { + } + export namespace ApiConfigSource { + } + export namespace AggregatedConfigSource { + } + export namespace SelfConfigSource { + } + export namespace RateLimitSettings { + } + export namespace ConfigSource { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + export namespace listener { + export namespace UdpListenerConfig { + } + export namespace ActiveRawUdpListenerConfig { + } + export namespace Filter { + } + export namespace FilterChainMatch { + } + export namespace FilterChain { + } + export namespace ListenerFilterChainMatchPredicate { + export namespace MatchSet { + } + } + export namespace ListenerFilter { + } + } + export namespace auth { + export namespace UpstreamTlsContext { + } + export namespace DownstreamTlsContext { + } + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } + } + export namespace GenericSecret { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } + export namespace TlsParameters { + } + export namespace PrivateKeyProvider { + } + export namespace TlsCertificate { + } + export namespace TlsSessionTicketKeys { + } + export namespace CertificateValidationContext { + } + } + export namespace route { + export namespace VirtualHost { + } + export namespace FilterAction { + } + export namespace Route { + } + export namespace WeightedCluster { + export namespace ClusterWeight { + } + } + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { + } + export namespace TlsContextMatchOptions { + } + } + export namespace CorsPolicy { + } + export namespace RouteAction { + export namespace RequestMirrorPolicy { + } + export namespace HashPolicy { + export namespace Header { + } + export namespace Cookie { + } + export namespace ConnectionProperties { + } + export namespace QueryParameter { + } + export namespace FilterState { + } + } + export namespace UpgradeConfig { + } + } + export namespace RetryPolicy { + export namespace RetryPriority { + } + export namespace RetryHostPredicate { + } + export namespace RetryBackOff { + } + } + export namespace HedgePolicy { + } + export namespace RedirectAction { + } + export namespace DirectResponseAction { + } + export namespace Decorator { + } + export namespace Tracing { + } + export namespace VirtualCluster { + } + export namespace RateLimit { + export namespace Action { + export namespace SourceCluster { + } + export namespace DestinationCluster { + } + export namespace RequestHeaders { + } + export namespace RemoteAddress { + } + export namespace GenericKey { + } + export namespace HeaderValueMatch { + } + } + } + export namespace HeaderMatcher { + } + export namespace QueryParameterMatcher { + } + } + } + } + export namespace config { + export namespace filter { + export namespace accesslog { + export namespace v2 { + export namespace AccessLog { + } + export namespace AccessLogFilter { + } + export namespace ComparisonFilter { + } + export namespace StatusCodeFilter { + } + export namespace DurationFilter { + } + export namespace NotHealthCheckFilter { + } + export namespace TraceableFilter { + } + export namespace RuntimeFilter { + } + export namespace AndFilter { + } + export namespace OrFilter { + } + export namespace HeaderFilter { + } + export namespace ResponseFlagFilter { + } + export namespace GrpcStatusFilter { + } + export namespace ExtensionFilter { + } + } + } + } + export namespace listener { + export namespace v2 { + export namespace ApiListener { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace SemanticVersion { + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace matcher { + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Literal { + } + export namespace Environment { + } + export namespace Header { + } + export namespace Metadata { + } + } + } + } + export namespace metadata { + export namespace v2 { + export namespace MetadataKey { + export namespace PathSegment { + } + } + export namespace MetadataKind { + export namespace Request { + } + export namespace Route { + } + export namespace Cluster { + } + export namespace Host { + } + } + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace Duration { + } + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Any { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Timestamp { + } + export namespace Empty { + } + } + export namespace api { + export namespace Http { + } + export namespace HttpRule { + } + export namespace CustomHttpPattern { + } + } + } +} diff --git a/packages/grpc-js/src/generated/route.d.ts b/packages/grpc-js/src/generated/route.d.ts new file mode 100644 index 000000000..d1326917f --- /dev/null +++ b/packages/grpc-js/src/generated/route.d.ts @@ -0,0 +1,1385 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from './envoy/api/v2/RouteConfiguration'; +import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from './envoy/api/v2/Vhds'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; +import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; +import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; +import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; +import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; +import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; +import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from './envoy/api/v2/route/CorsPolicy'; +import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; +import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; +import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from './envoy/api/v2/route/HedgePolicy'; +import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from './envoy/api/v2/route/RedirectAction'; +import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; +import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; +import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from './envoy/api/v2/route/Tracing'; +import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from './envoy/api/v2/route/VirtualCluster'; +import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; +import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; +import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; +import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; + +export namespace messages { + export namespace envoy { + export namespace api { + export namespace v2 { + export type RouteConfiguration = _envoy_api_v2_RouteConfiguration; + export type RouteConfiguration__Output = _envoy_api_v2_RouteConfiguration__Output; + export type Vhds = _envoy_api_v2_Vhds; + export type Vhds__Output = _envoy_api_v2_Vhds__Output; + export namespace core { + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type BuildVersion = _envoy_api_v2_core_BuildVersion; + export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type Extension = _envoy_api_v2_core_Extension; + export type Extension__Output = _envoy_api_v2_core_Extension__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type HeaderValue = _envoy_api_v2_core_HeaderValue; + export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + } + export namespace route { + export type VirtualHost = _envoy_api_v2_route_VirtualHost; + export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; + export type FilterAction = _envoy_api_v2_route_FilterAction; + export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; + export type Route = _envoy_api_v2_route_Route; + export type Route__Output = _envoy_api_v2_route_Route__Output; + export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; + export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; + export type RouteMatch = _envoy_api_v2_route_RouteMatch; + export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; + export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; + export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; + export type RouteAction = _envoy_api_v2_route_RouteAction; + export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; + export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; + export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; + export type RedirectAction = _envoy_api_v2_route_RedirectAction; + export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; + export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; + export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; + export type Decorator = _envoy_api_v2_route_Decorator; + export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; + export type Tracing = _envoy_api_v2_route_Tracing; + export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; + export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; + export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; + export type RateLimit = _envoy_api_v2_route_RateLimit; + export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; + export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; + export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; + export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; + export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + } + } + } + export namespace type { + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; + export type FractionalPercent = _envoy_type_FractionalPercent; + export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + export namespace matcher { + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + } + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; + export namespace tracing { + export namespace v2 { + export type CustomTag = _envoy_type_tracing_v2_CustomTag; + export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; + } + } + export namespace metadata { + export namespace v2 { + export type MetadataKey = _envoy_type_metadata_v2_MetadataKey; + export type MetadataKey__Output = _envoy_type_metadata_v2_MetadataKey__Output; + export type MetadataKind = _envoy_type_metadata_v2_MetadataKind; + export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; + } + } + export namespace validate { + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type KnownRegex = _validate_KnownRegex; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + } + export namespace google { + export namespace protobuf { + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type BoolValue = _google_protobuf_BoolValue; + export type BoolValue__Output = _google_protobuf_BoolValue__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type BytesValue = _google_protobuf_BytesValue; + export type BytesValue__Output = _google_protobuf_BytesValue__Output; + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; + export type NullValue = _google_protobuf_NullValue; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type DescriptorProto = _google_protobuf_DescriptorProto; + export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; + export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; + export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type FileOptions = _google_protobuf_FileOptions; + export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type MessageOptions = _google_protobuf_MessageOptions; + export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type OneofOptions = _google_protobuf_OneofOptions; + export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceOptions = _google_protobuf_ServiceOptions; + export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; + export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; + } + } +} + +export namespace ClientInterfaces { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace RouteConfiguration { + } + export namespace Vhds { + } + export namespace core { + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace ApiConfigSource { + } + export namespace AggregatedConfigSource { + } + export namespace SelfConfigSource { + } + export namespace RateLimitSettings { + } + export namespace ConfigSource { + } + export namespace BackoffStrategy { + } + export namespace HttpUri { + } + export namespace SocketOption { + } + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + export namespace route { + export namespace VirtualHost { + } + export namespace FilterAction { + } + export namespace Route { + } + export namespace WeightedCluster { + export namespace ClusterWeight { + } + } + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { + } + export namespace TlsContextMatchOptions { + } + } + export namespace CorsPolicy { + } + export namespace RouteAction { + export namespace RequestMirrorPolicy { + } + export namespace HashPolicy { + export namespace Header { + } + export namespace Cookie { + } + export namespace ConnectionProperties { + } + export namespace QueryParameter { + } + export namespace FilterState { + } + } + export namespace UpgradeConfig { + } + } + export namespace RetryPolicy { + export namespace RetryPriority { + } + export namespace RetryHostPredicate { + } + export namespace RetryBackOff { + } + } + export namespace HedgePolicy { + } + export namespace RedirectAction { + } + export namespace DirectResponseAction { + } + export namespace Decorator { + } + export namespace Tracing { + } + export namespace VirtualCluster { + } + export namespace RateLimit { + export namespace Action { + export namespace SourceCluster { + } + export namespace DestinationCluster { + } + export namespace RequestHeaders { + } + export namespace RemoteAddress { + } + export namespace GenericKey { + } + export namespace HeaderValueMatch { + } + } + } + export namespace HeaderMatcher { + } + export namespace QueryParameterMatcher { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace matcher { + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + } + export namespace SemanticVersion { + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Literal { + } + export namespace Environment { + } + export namespace Header { + } + export namespace Metadata { + } + } + } + } + export namespace metadata { + export namespace v2 { + export namespace MetadataKey { + export namespace PathSegment { + } + } + export namespace MetadataKind { + export namespace Request { + } + export namespace Route { + } + export namespace Cluster { + } + export namespace Host { + } + } + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Any { + } + export namespace Duration { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Timestamp { + } + export namespace Empty { + } + } + } +} + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + api: { + v2: { + RouteConfiguration: MessageTypeDefinition + Vhds: MessageTypeDefinition + core: { + RoutingPriority: EnumTypeDefinition + RequestMethod: EnumTypeDefinition + TrafficDirection: EnumTypeDefinition + Locality: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + Extension: MessageTypeDefinition + Node: MessageTypeDefinition + Metadata: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + DataSource: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + TransportSocket: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + ApiConfigSource: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + SocketOption: MessageTypeDefinition + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition + GrpcService: MessageTypeDefinition + } + route: { + VirtualHost: MessageTypeDefinition + FilterAction: MessageTypeDefinition + Route: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + CorsPolicy: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + Decorator: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + RateLimit: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + } + } + } + type: { + Percent: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Int32Range: MessageTypeDefinition + DoubleRange: MessageTypeDefinition + matcher: { + RegexMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + } + SemanticVersion: MessageTypeDefinition + tracing: { + v2: { + CustomTag: MessageTypeDefinition + } + } + metadata: { + v2: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + } + annotations: { + } + } + udpa: { + annotations: { + MigrateAnnotation: MessageTypeDefinition + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + FieldRules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + StringRules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + BytesRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + MapRules: MessageTypeDefinition + AnyRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + } + google: { + protobuf: { + DoubleValue: MessageTypeDefinition + FloatValue: MessageTypeDefinition + Int64Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + Int32Value: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + BoolValue: MessageTypeDefinition + StringValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + Any: MessageTypeDefinition + Duration: MessageTypeDefinition + Struct: MessageTypeDefinition + Value: MessageTypeDefinition + NullValue: EnumTypeDefinition + ListValue: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + FileOptions: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Timestamp: MessageTypeDefinition + Empty: MessageTypeDefinition + } + } +} + +export namespace ServiceHandlers { + export namespace envoy { + export namespace api { + export namespace v2 { + export namespace RouteConfiguration { + } + export namespace Vhds { + } + export namespace core { + export namespace Locality { + } + export namespace BuildVersion { + } + export namespace Extension { + } + export namespace Node { + } + export namespace Metadata { + } + export namespace RuntimeUInt32 { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { + } + export namespace ApiConfigSource { + } + export namespace AggregatedConfigSource { + } + export namespace SelfConfigSource { + } + export namespace RateLimitSettings { + } + export namespace ConfigSource { + } + export namespace BackoffStrategy { + } + export namespace HttpUri { + } + export namespace SocketOption { + } + export namespace Pipe { + } + export namespace SocketAddress { + } + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace SslCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace ChannelCredentials { + } + export namespace CallCredentials { + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace StsService { + } + } + } + } + } + export namespace route { + export namespace VirtualHost { + } + export namespace FilterAction { + } + export namespace Route { + } + export namespace WeightedCluster { + export namespace ClusterWeight { + } + } + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { + } + export namespace TlsContextMatchOptions { + } + } + export namespace CorsPolicy { + } + export namespace RouteAction { + export namespace RequestMirrorPolicy { + } + export namespace HashPolicy { + export namespace Header { + } + export namespace Cookie { + } + export namespace ConnectionProperties { + } + export namespace QueryParameter { + } + export namespace FilterState { + } + } + export namespace UpgradeConfig { + } + } + export namespace RetryPolicy { + export namespace RetryPriority { + } + export namespace RetryHostPredicate { + } + export namespace RetryBackOff { + } + } + export namespace HedgePolicy { + } + export namespace RedirectAction { + } + export namespace DirectResponseAction { + } + export namespace Decorator { + } + export namespace Tracing { + } + export namespace VirtualCluster { + } + export namespace RateLimit { + export namespace Action { + export namespace SourceCluster { + } + export namespace DestinationCluster { + } + export namespace RequestHeaders { + } + export namespace RemoteAddress { + } + export namespace GenericKey { + } + export namespace HeaderValueMatch { + } + } + } + export namespace HeaderMatcher { + } + export namespace QueryParameterMatcher { + } + } + } + } + export namespace type { + export namespace Percent { + } + export namespace FractionalPercent { + } + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace matcher { + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace RegexMatchAndSubstitute { + } + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } + } + export namespace SemanticVersion { + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Literal { + } + export namespace Environment { + } + export namespace Header { + } + export namespace Metadata { + } + } + } + } + export namespace metadata { + export namespace v2 { + export namespace MetadataKey { + export namespace PathSegment { + } + } + export namespace MetadataKind { + export namespace Request { + } + export namespace Route { + } + export namespace Cluster { + } + export namespace Host { + } + } + } + } + } + export namespace annotations { + } + } + export namespace udpa { + export namespace annotations { + export namespace MigrateAnnotation { + } + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace FieldRules { + } + export namespace FloatRules { + } + export namespace DoubleRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace BoolRules { + } + export namespace StringRules { + } + export namespace BytesRules { + } + export namespace EnumRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace MapRules { + } + export namespace AnyRules { + } + export namespace DurationRules { + } + export namespace TimestampRules { + } + } + export namespace google { + export namespace protobuf { + export namespace DoubleValue { + } + export namespace FloatValue { + } + export namespace Int64Value { + } + export namespace UInt64Value { + } + export namespace Int32Value { + } + export namespace UInt32Value { + } + export namespace BoolValue { + } + export namespace StringValue { + } + export namespace BytesValue { + } + export namespace Any { + } + export namespace Duration { + } + export namespace Struct { + } + export namespace Value { + } + export namespace ListValue { + } + export namespace FileDescriptorSet { + } + export namespace FileDescriptorProto { + } + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } + } + export namespace FieldDescriptorProto { + } + export namespace OneofDescriptorProto { + } + export namespace EnumDescriptorProto { + } + export namespace EnumValueDescriptorProto { + } + export namespace ServiceDescriptorProto { + } + export namespace MethodDescriptorProto { + } + export namespace FileOptions { + } + export namespace MessageOptions { + } + export namespace FieldOptions { + } + export namespace OneofOptions { + } + export namespace EnumOptions { + } + export namespace EnumValueOptions { + } + export namespace ServiceOptions { + } + export namespace MethodOptions { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace GeneratedCodeInfo { + export namespace Annotation { + } + } + export namespace Timestamp { + } + export namespace Empty { + } + } + } +} diff --git a/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.d.ts new file mode 100644 index 000000000..375c1f5be --- /dev/null +++ b/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/udpa/udpa/annotations/migrate.proto + + +export interface FieldMigrateAnnotation { + 'rename'?: (string); + 'oneof_promotion'?: (string); +} + +export interface FieldMigrateAnnotation__Output { + 'rename': (string); + 'oneof_promotion': (string); +} diff --git a/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.d.ts new file mode 100644 index 000000000..a6f113694 --- /dev/null +++ b/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/udpa/udpa/annotations/migrate.proto + + +export interface FileMigrateAnnotation { + 'move_to_package'?: (string); +} + +export interface FileMigrateAnnotation__Output { + 'move_to_package': (string); +} diff --git a/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.d.ts new file mode 100644 index 000000000..57402231f --- /dev/null +++ b/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/udpa/udpa/annotations/migrate.proto + + +export interface MigrateAnnotation { + 'rename'?: (string); +} + +export interface MigrateAnnotation__Output { + 'rename': (string); +} diff --git a/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.d.ts b/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.d.ts new file mode 100644 index 000000000..9888e1d14 --- /dev/null +++ b/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.d.ts @@ -0,0 +1,8 @@ +// Original file: deps/udpa/udpa/annotations/status.proto + +export enum PackageVersionStatus { + UNKNOWN = 0, + FROZEN = 1, + ACTIVE = 2, + NEXT_MAJOR_VERSION_CANDIDATE = 3, +} diff --git a/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.d.ts new file mode 100644 index 000000000..3b4748c00 --- /dev/null +++ b/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.d.ts @@ -0,0 +1,13 @@ +// Original file: deps/udpa/udpa/annotations/status.proto + +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from '../../udpa/annotations/PackageVersionStatus'; + +export interface StatusAnnotation { + 'work_in_progress'?: (boolean); + 'package_version_status'?: (_udpa_annotations_PackageVersionStatus | keyof typeof _udpa_annotations_PackageVersionStatus); +} + +export interface StatusAnnotation__Output { + 'work_in_progress': (boolean); + 'package_version_status': (keyof typeof _udpa_annotations_PackageVersionStatus); +} diff --git a/packages/grpc-js/src/generated/validate/AnyRules.d.ts b/packages/grpc-js/src/generated/validate/AnyRules.d.ts new file mode 100644 index 000000000..c55a03f58 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/AnyRules.d.ts @@ -0,0 +1,14 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface AnyRules { + 'required'?: (boolean); + 'in'?: (string)[]; + 'not_in'?: (string)[]; +} + +export interface AnyRules__Output { + 'required': (boolean); + 'in': (string)[]; + 'not_in': (string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/BoolRules.d.ts b/packages/grpc-js/src/generated/validate/BoolRules.d.ts new file mode 100644 index 000000000..85db6c621 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/BoolRules.d.ts @@ -0,0 +1,10 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface BoolRules { + 'const'?: (boolean); +} + +export interface BoolRules__Output { + 'const': (boolean); +} diff --git a/packages/grpc-js/src/generated/validate/BytesRules.d.ts b/packages/grpc-js/src/generated/validate/BytesRules.d.ts new file mode 100644 index 000000000..7d356fef2 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/BytesRules.d.ts @@ -0,0 +1,37 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Long } from '@grpc/proto-loader'; + +export interface BytesRules { + 'const'?: (Buffer | Uint8Array | string); + 'len'?: (number | string | Long); + 'min_len'?: (number | string | Long); + 'max_len'?: (number | string | Long); + 'pattern'?: (string); + 'prefix'?: (Buffer | Uint8Array | string); + 'suffix'?: (Buffer | Uint8Array | string); + 'contains'?: (Buffer | Uint8Array | string); + 'in'?: (Buffer | Uint8Array | string)[]; + 'not_in'?: (Buffer | Uint8Array | string)[]; + 'ip'?: (boolean); + 'ipv4'?: (boolean); + 'ipv6'?: (boolean); + 'well_known'?: "ip"|"ipv4"|"ipv6"; +} + +export interface BytesRules__Output { + 'const': (Buffer); + 'len': (string); + 'min_len': (string); + 'max_len': (string); + 'pattern': (string); + 'prefix': (Buffer); + 'suffix': (Buffer); + 'contains': (Buffer); + 'in': (Buffer)[]; + 'not_in': (Buffer)[]; + 'ip'?: (boolean); + 'ipv4'?: (boolean); + 'ipv6'?: (boolean); + 'well_known': "ip"|"ipv4"|"ipv6"; +} diff --git a/packages/grpc-js/src/generated/validate/DoubleRules.d.ts b/packages/grpc-js/src/generated/validate/DoubleRules.d.ts new file mode 100644 index 000000000..476d0b9bc --- /dev/null +++ b/packages/grpc-js/src/generated/validate/DoubleRules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface DoubleRules { + 'const'?: (number | string); + 'lt'?: (number | string); + 'lte'?: (number | string); + 'gt'?: (number | string); + 'gte'?: (number | string); + 'in'?: (number | string)[]; + 'not_in'?: (number | string)[]; +} + +export interface DoubleRules__Output { + 'const': (number | string); + 'lt': (number | string); + 'lte': (number | string); + 'gt': (number | string); + 'gte': (number | string); + 'in': (number | string)[]; + 'not_in': (number | string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/DurationRules.d.ts b/packages/grpc-js/src/generated/validate/DurationRules.d.ts new file mode 100644 index 000000000..6bd07149d --- /dev/null +++ b/packages/grpc-js/src/generated/validate/DurationRules.d.ts @@ -0,0 +1,25 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; + +export interface DurationRules { + 'required'?: (boolean); + 'const'?: (_google_protobuf_Duration); + 'lt'?: (_google_protobuf_Duration); + 'lte'?: (_google_protobuf_Duration); + 'gt'?: (_google_protobuf_Duration); + 'gte'?: (_google_protobuf_Duration); + 'in'?: (_google_protobuf_Duration)[]; + 'not_in'?: (_google_protobuf_Duration)[]; +} + +export interface DurationRules__Output { + 'required': (boolean); + 'const': (_google_protobuf_Duration__Output); + 'lt': (_google_protobuf_Duration__Output); + 'lte': (_google_protobuf_Duration__Output); + 'gt': (_google_protobuf_Duration__Output); + 'gte': (_google_protobuf_Duration__Output); + 'in': (_google_protobuf_Duration__Output)[]; + 'not_in': (_google_protobuf_Duration__Output)[]; +} diff --git a/packages/grpc-js/src/generated/validate/EnumRules.d.ts b/packages/grpc-js/src/generated/validate/EnumRules.d.ts new file mode 100644 index 000000000..02ae6330e --- /dev/null +++ b/packages/grpc-js/src/generated/validate/EnumRules.d.ts @@ -0,0 +1,16 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface EnumRules { + 'const'?: (number); + 'defined_only'?: (boolean); + 'in'?: (number)[]; + 'not_in'?: (number)[]; +} + +export interface EnumRules__Output { + 'const': (number); + 'defined_only': (boolean); + 'in': (number)[]; + 'not_in': (number)[]; +} diff --git a/packages/grpc-js/src/generated/validate/FieldRules.d.ts b/packages/grpc-js/src/generated/validate/FieldRules.d.ts new file mode 100644 index 000000000..099391f44 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/FieldRules.d.ts @@ -0,0 +1,77 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from '../validate/MessageRules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from '../validate/FloatRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from '../validate/DoubleRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from '../validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from '../validate/Int64Rules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from '../validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from '../validate/UInt64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from '../validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from '../validate/SInt64Rules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from '../validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from '../validate/Fixed64Rules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from '../validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from '../validate/SFixed64Rules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from '../validate/BoolRules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from '../validate/StringRules'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from '../validate/BytesRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from '../validate/EnumRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from '../validate/RepeatedRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from '../validate/MapRules'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from '../validate/AnyRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from '../validate/DurationRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from '../validate/TimestampRules'; +import { Long } from '@grpc/proto-loader'; + +export interface FieldRules { + 'message'?: (_validate_MessageRules); + 'float'?: (_validate_FloatRules); + 'double'?: (_validate_DoubleRules); + 'int32'?: (_validate_Int32Rules); + 'int64'?: (_validate_Int64Rules); + 'uint32'?: (_validate_UInt32Rules); + 'uint64'?: (_validate_UInt64Rules); + 'sint32'?: (_validate_SInt32Rules); + 'sint64'?: (_validate_SInt64Rules); + 'fixed32'?: (_validate_Fixed32Rules); + 'fixed64'?: (_validate_Fixed64Rules); + 'sfixed32'?: (_validate_SFixed32Rules); + 'sfixed64'?: (_validate_SFixed64Rules); + 'bool'?: (_validate_BoolRules); + 'string'?: (_validate_StringRules); + 'bytes'?: (_validate_BytesRules); + 'enum'?: (_validate_EnumRules); + 'repeated'?: (_validate_RepeatedRules); + 'map'?: (_validate_MapRules); + 'any'?: (_validate_AnyRules); + 'duration'?: (_validate_DurationRules); + 'timestamp'?: (_validate_TimestampRules); + 'type'?: "float"|"double"|"int32"|"int64"|"uint32"|"uint64"|"sint32"|"sint64"|"fixed32"|"fixed64"|"sfixed32"|"sfixed64"|"bool"|"string"|"bytes"|"enum"|"repeated"|"map"|"any"|"duration"|"timestamp"; +} + +export interface FieldRules__Output { + 'message': (_validate_MessageRules__Output); + 'float'?: (_validate_FloatRules__Output); + 'double'?: (_validate_DoubleRules__Output); + 'int32'?: (_validate_Int32Rules__Output); + 'int64'?: (_validate_Int64Rules__Output); + 'uint32'?: (_validate_UInt32Rules__Output); + 'uint64'?: (_validate_UInt64Rules__Output); + 'sint32'?: (_validate_SInt32Rules__Output); + 'sint64'?: (_validate_SInt64Rules__Output); + 'fixed32'?: (_validate_Fixed32Rules__Output); + 'fixed64'?: (_validate_Fixed64Rules__Output); + 'sfixed32'?: (_validate_SFixed32Rules__Output); + 'sfixed64'?: (_validate_SFixed64Rules__Output); + 'bool'?: (_validate_BoolRules__Output); + 'string'?: (_validate_StringRules__Output); + 'bytes'?: (_validate_BytesRules__Output); + 'enum'?: (_validate_EnumRules__Output); + 'repeated'?: (_validate_RepeatedRules__Output); + 'map'?: (_validate_MapRules__Output); + 'any'?: (_validate_AnyRules__Output); + 'duration'?: (_validate_DurationRules__Output); + 'timestamp'?: (_validate_TimestampRules__Output); + 'type': "float"|"double"|"int32"|"int64"|"uint32"|"uint64"|"sint32"|"sint64"|"fixed32"|"fixed64"|"sfixed32"|"sfixed64"|"bool"|"string"|"bytes"|"enum"|"repeated"|"map"|"any"|"duration"|"timestamp"; +} diff --git a/packages/grpc-js/src/generated/validate/Fixed32Rules.d.ts b/packages/grpc-js/src/generated/validate/Fixed32Rules.d.ts new file mode 100644 index 000000000..27bbdad93 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/Fixed32Rules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface Fixed32Rules { + 'const'?: (number); + 'lt'?: (number); + 'lte'?: (number); + 'gt'?: (number); + 'gte'?: (number); + 'in'?: (number)[]; + 'not_in'?: (number)[]; +} + +export interface Fixed32Rules__Output { + 'const': (number); + 'lt': (number); + 'lte': (number); + 'gt': (number); + 'gte': (number); + 'in': (number)[]; + 'not_in': (number)[]; +} diff --git a/packages/grpc-js/src/generated/validate/Fixed64Rules.d.ts b/packages/grpc-js/src/generated/validate/Fixed64Rules.d.ts new file mode 100644 index 000000000..8a211bac0 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/Fixed64Rules.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Long } from '@grpc/proto-loader'; + +export interface Fixed64Rules { + 'const'?: (number | string | Long); + 'lt'?: (number | string | Long); + 'lte'?: (number | string | Long); + 'gt'?: (number | string | Long); + 'gte'?: (number | string | Long); + 'in'?: (number | string | Long)[]; + 'not_in'?: (number | string | Long)[]; +} + +export interface Fixed64Rules__Output { + 'const': (string); + 'lt': (string); + 'lte': (string); + 'gt': (string); + 'gte': (string); + 'in': (string)[]; + 'not_in': (string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/FloatRules.d.ts b/packages/grpc-js/src/generated/validate/FloatRules.d.ts new file mode 100644 index 000000000..6d29f67d8 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/FloatRules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface FloatRules { + 'const'?: (number | string); + 'lt'?: (number | string); + 'lte'?: (number | string); + 'gt'?: (number | string); + 'gte'?: (number | string); + 'in'?: (number | string)[]; + 'not_in'?: (number | string)[]; +} + +export interface FloatRules__Output { + 'const': (number | string); + 'lt': (number | string); + 'lte': (number | string); + 'gt': (number | string); + 'gte': (number | string); + 'in': (number | string)[]; + 'not_in': (number | string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/Int32Rules.d.ts b/packages/grpc-js/src/generated/validate/Int32Rules.d.ts new file mode 100644 index 000000000..03fb112c7 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/Int32Rules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface Int32Rules { + 'const'?: (number); + 'lt'?: (number); + 'lte'?: (number); + 'gt'?: (number); + 'gte'?: (number); + 'in'?: (number)[]; + 'not_in'?: (number)[]; +} + +export interface Int32Rules__Output { + 'const': (number); + 'lt': (number); + 'lte': (number); + 'gt': (number); + 'gte': (number); + 'in': (number)[]; + 'not_in': (number)[]; +} diff --git a/packages/grpc-js/src/generated/validate/Int64Rules.d.ts b/packages/grpc-js/src/generated/validate/Int64Rules.d.ts new file mode 100644 index 000000000..91551365a --- /dev/null +++ b/packages/grpc-js/src/generated/validate/Int64Rules.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Long } from '@grpc/proto-loader'; + +export interface Int64Rules { + 'const'?: (number | string | Long); + 'lt'?: (number | string | Long); + 'lte'?: (number | string | Long); + 'gt'?: (number | string | Long); + 'gte'?: (number | string | Long); + 'in'?: (number | string | Long)[]; + 'not_in'?: (number | string | Long)[]; +} + +export interface Int64Rules__Output { + 'const': (string); + 'lt': (string); + 'lte': (string); + 'gt': (string); + 'gte': (string); + 'in': (string)[]; + 'not_in': (string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/KnownRegex.d.ts b/packages/grpc-js/src/generated/validate/KnownRegex.d.ts new file mode 100644 index 000000000..68938449e --- /dev/null +++ b/packages/grpc-js/src/generated/validate/KnownRegex.d.ts @@ -0,0 +1,7 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +export enum KnownRegex { + UNKNOWN = 0, + HTTP_HEADER_NAME = 1, + HTTP_HEADER_VALUE = 2, +} diff --git a/packages/grpc-js/src/generated/validate/MapRules.d.ts b/packages/grpc-js/src/generated/validate/MapRules.d.ts new file mode 100644 index 000000000..159c9bc07 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/MapRules.d.ts @@ -0,0 +1,20 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; +import { Long } from '@grpc/proto-loader'; + +export interface MapRules { + 'min_pairs'?: (number | string | Long); + 'max_pairs'?: (number | string | Long); + 'no_sparse'?: (boolean); + 'keys'?: (_validate_FieldRules); + 'values'?: (_validate_FieldRules); +} + +export interface MapRules__Output { + 'min_pairs': (string); + 'max_pairs': (string); + 'no_sparse': (boolean); + 'keys': (_validate_FieldRules__Output); + 'values': (_validate_FieldRules__Output); +} diff --git a/packages/grpc-js/src/generated/validate/MessageRules.d.ts b/packages/grpc-js/src/generated/validate/MessageRules.d.ts new file mode 100644 index 000000000..9229b1940 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/MessageRules.d.ts @@ -0,0 +1,12 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface MessageRules { + 'skip'?: (boolean); + 'required'?: (boolean); +} + +export interface MessageRules__Output { + 'skip': (boolean); + 'required': (boolean); +} diff --git a/packages/grpc-js/src/generated/validate/RepeatedRules.d.ts b/packages/grpc-js/src/generated/validate/RepeatedRules.d.ts new file mode 100644 index 000000000..3b41cd1ee --- /dev/null +++ b/packages/grpc-js/src/generated/validate/RepeatedRules.d.ts @@ -0,0 +1,18 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; +import { Long } from '@grpc/proto-loader'; + +export interface RepeatedRules { + 'min_items'?: (number | string | Long); + 'max_items'?: (number | string | Long); + 'unique'?: (boolean); + 'items'?: (_validate_FieldRules); +} + +export interface RepeatedRules__Output { + 'min_items': (string); + 'max_items': (string); + 'unique': (boolean); + 'items': (_validate_FieldRules__Output); +} diff --git a/packages/grpc-js/src/generated/validate/SFixed32Rules.d.ts b/packages/grpc-js/src/generated/validate/SFixed32Rules.d.ts new file mode 100644 index 000000000..55f2e695a --- /dev/null +++ b/packages/grpc-js/src/generated/validate/SFixed32Rules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface SFixed32Rules { + 'const'?: (number); + 'lt'?: (number); + 'lte'?: (number); + 'gt'?: (number); + 'gte'?: (number); + 'in'?: (number)[]; + 'not_in'?: (number)[]; +} + +export interface SFixed32Rules__Output { + 'const': (number); + 'lt': (number); + 'lte': (number); + 'gt': (number); + 'gte': (number); + 'in': (number)[]; + 'not_in': (number)[]; +} diff --git a/packages/grpc-js/src/generated/validate/SFixed64Rules.d.ts b/packages/grpc-js/src/generated/validate/SFixed64Rules.d.ts new file mode 100644 index 000000000..262d98418 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/SFixed64Rules.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Long } from '@grpc/proto-loader'; + +export interface SFixed64Rules { + 'const'?: (number | string | Long); + 'lt'?: (number | string | Long); + 'lte'?: (number | string | Long); + 'gt'?: (number | string | Long); + 'gte'?: (number | string | Long); + 'in'?: (number | string | Long)[]; + 'not_in'?: (number | string | Long)[]; +} + +export interface SFixed64Rules__Output { + 'const': (string); + 'lt': (string); + 'lte': (string); + 'gt': (string); + 'gte': (string); + 'in': (string)[]; + 'not_in': (string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/SInt32Rules.d.ts b/packages/grpc-js/src/generated/validate/SInt32Rules.d.ts new file mode 100644 index 000000000..9acd90794 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/SInt32Rules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface SInt32Rules { + 'const'?: (number); + 'lt'?: (number); + 'lte'?: (number); + 'gt'?: (number); + 'gte'?: (number); + 'in'?: (number)[]; + 'not_in'?: (number)[]; +} + +export interface SInt32Rules__Output { + 'const': (number); + 'lt': (number); + 'lte': (number); + 'gt': (number); + 'gte': (number); + 'in': (number)[]; + 'not_in': (number)[]; +} diff --git a/packages/grpc-js/src/generated/validate/SInt64Rules.d.ts b/packages/grpc-js/src/generated/validate/SInt64Rules.d.ts new file mode 100644 index 000000000..c85200031 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/SInt64Rules.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Long } from '@grpc/proto-loader'; + +export interface SInt64Rules { + 'const'?: (number | string | Long); + 'lt'?: (number | string | Long); + 'lte'?: (number | string | Long); + 'gt'?: (number | string | Long); + 'gte'?: (number | string | Long); + 'in'?: (number | string | Long)[]; + 'not_in'?: (number | string | Long)[]; +} + +export interface SInt64Rules__Output { + 'const': (string); + 'lt': (string); + 'lte': (string); + 'gt': (string); + 'gte': (string); + 'in': (string)[]; + 'not_in': (string)[]; +} diff --git a/packages/grpc-js/src/generated/validate/StringRules.d.ts b/packages/grpc-js/src/generated/validate/StringRules.d.ts new file mode 100644 index 000000000..ed4339f90 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/StringRules.d.ts @@ -0,0 +1,62 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { KnownRegex as _validate_KnownRegex } from '../validate/KnownRegex'; +import { Long } from '@grpc/proto-loader'; + +export interface StringRules { + 'const'?: (string); + 'len'?: (number | string | Long); + 'min_len'?: (number | string | Long); + 'max_len'?: (number | string | Long); + 'len_bytes'?: (number | string | Long); + 'min_bytes'?: (number | string | Long); + 'max_bytes'?: (number | string | Long); + 'pattern'?: (string); + 'prefix'?: (string); + 'suffix'?: (string); + 'contains'?: (string); + 'not_contains'?: (string); + 'in'?: (string)[]; + 'not_in'?: (string)[]; + 'email'?: (boolean); + 'hostname'?: (boolean); + 'ip'?: (boolean); + 'ipv4'?: (boolean); + 'ipv6'?: (boolean); + 'uri'?: (boolean); + 'uri_ref'?: (boolean); + 'address'?: (boolean); + 'uuid'?: (boolean); + 'well_known_regex'?: (_validate_KnownRegex | keyof typeof _validate_KnownRegex); + 'strict'?: (boolean); + 'well_known'?: "email"|"hostname"|"ip"|"ipv4"|"ipv6"|"uri"|"uri_ref"|"address"|"uuid"|"well_known_regex"; +} + +export interface StringRules__Output { + 'const': (string); + 'len': (string); + 'min_len': (string); + 'max_len': (string); + 'len_bytes': (string); + 'min_bytes': (string); + 'max_bytes': (string); + 'pattern': (string); + 'prefix': (string); + 'suffix': (string); + 'contains': (string); + 'not_contains': (string); + 'in': (string)[]; + 'not_in': (string)[]; + 'email'?: (boolean); + 'hostname'?: (boolean); + 'ip'?: (boolean); + 'ipv4'?: (boolean); + 'ipv6'?: (boolean); + 'uri'?: (boolean); + 'uri_ref'?: (boolean); + 'address'?: (boolean); + 'uuid'?: (boolean); + 'well_known_regex'?: (keyof typeof _validate_KnownRegex); + 'strict': (boolean); + 'well_known': "email"|"hostname"|"ip"|"ipv4"|"ipv6"|"uri"|"uri_ref"|"address"|"uuid"|"well_known_regex"; +} diff --git a/packages/grpc-js/src/generated/validate/TimestampRules.d.ts b/packages/grpc-js/src/generated/validate/TimestampRules.d.ts new file mode 100644 index 000000000..63a6ba4f2 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/TimestampRules.d.ts @@ -0,0 +1,28 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../google/protobuf/Timestamp'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; + +export interface TimestampRules { + 'required'?: (boolean); + 'const'?: (_google_protobuf_Timestamp); + 'lt'?: (_google_protobuf_Timestamp); + 'lte'?: (_google_protobuf_Timestamp); + 'gt'?: (_google_protobuf_Timestamp); + 'gte'?: (_google_protobuf_Timestamp); + 'lt_now'?: (boolean); + 'gt_now'?: (boolean); + 'within'?: (_google_protobuf_Duration); +} + +export interface TimestampRules__Output { + 'required': (boolean); + 'const': (_google_protobuf_Timestamp__Output); + 'lt': (_google_protobuf_Timestamp__Output); + 'lte': (_google_protobuf_Timestamp__Output); + 'gt': (_google_protobuf_Timestamp__Output); + 'gte': (_google_protobuf_Timestamp__Output); + 'lt_now': (boolean); + 'gt_now': (boolean); + 'within': (_google_protobuf_Duration__Output); +} diff --git a/packages/grpc-js/src/generated/validate/UInt32Rules.d.ts b/packages/grpc-js/src/generated/validate/UInt32Rules.d.ts new file mode 100644 index 000000000..bc12fe5ce --- /dev/null +++ b/packages/grpc-js/src/generated/validate/UInt32Rules.d.ts @@ -0,0 +1,22 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + + +export interface UInt32Rules { + 'const'?: (number); + 'lt'?: (number); + 'lte'?: (number); + 'gt'?: (number); + 'gte'?: (number); + 'in'?: (number)[]; + 'not_in'?: (number)[]; +} + +export interface UInt32Rules__Output { + 'const': (number); + 'lt': (number); + 'lte': (number); + 'gt': (number); + 'gte': (number); + 'in': (number)[]; + 'not_in': (number)[]; +} diff --git a/packages/grpc-js/src/generated/validate/UInt64Rules.d.ts b/packages/grpc-js/src/generated/validate/UInt64Rules.d.ts new file mode 100644 index 000000000..3c8a81ce9 --- /dev/null +++ b/packages/grpc-js/src/generated/validate/UInt64Rules.d.ts @@ -0,0 +1,23 @@ +// Original file: deps/protoc-gen-validate/validate/validate.proto + +import { Long } from '@grpc/proto-loader'; + +export interface UInt64Rules { + 'const'?: (number | string | Long); + 'lt'?: (number | string | Long); + 'lte'?: (number | string | Long); + 'gt'?: (number | string | Long); + 'gte'?: (number | string | Long); + 'in'?: (number | string | Long)[]; + 'not_in'?: (number | string | Long)[]; +} + +export interface UInt64Rules__Output { + 'const': (string); + 'lt': (string); + 'lte': (string); + 'gt': (string); + 'gte': (string); + 'in': (string)[]; + 'not_in': (string)[]; +} From 5767f7d10773204cb705d8f8cd2d76813d3f53c9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Jul 2020 09:26:52 -0700 Subject: [PATCH 1138/1899] Complete most of the endpoint watcher implementation --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/xds-client.ts | 243 ++++++++++++++++++++++++++++- 2 files changed, 240 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 2e5836f52..280950245 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre3", + "@grpc/proto-loader": "^0.6.0-pre5", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index e8eea6f30..6d80f3b79 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -19,9 +19,26 @@ import * as fs from 'fs'; import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; -import { ChannelCredentials } from './channel-credentials'; +import * as edsTypes from './generated/endpoint'; +import { ChannelCredentials, createGoogleDefaultCredentials } from './channel-credentials'; +import { loadBootstrapInfo } from './xds-bootstrap'; +import { ClientDuplexStream, ServiceError } from './call'; +import { StatusObject } from './call-stream'; +import { isIPv4, isIPv6 } from 'net'; +import { Status } from './constants'; +import { Metadata } from './metadata'; -const packageDefinition = protoLoader.loadSync([ +const clientVersion = require('../../package.json').version; + +const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; + +let loadedProtos: Promise | null = null; + +function loadAdsProtos(): Promise { + if (loadedProtos !== null) { + return loadedProtos; + } + loadedProtos = protoLoader.load([ 'envoy/service/discovery/v2/ads.proto', 'envoy/api/v2/listener.proto', 'envoy/api/v2/route.proto', @@ -40,10 +57,228 @@ const packageDefinition = protoLoader.loadSync([ 'deps/googleapis/', 'deps/protoc-gen-validate/' ] - }); + }).then(packageDefinition => loadPackageDefinition(packageDefinition) as unknown as adsTypes.ProtoGrpcType); + return loadedProtos; +} -const loadedDefinition = loadPackageDefinition(packageDefinition) as unknown as adsTypes.ProtoGrpcType; +export interface Watcher { + onValidUpdate(update: UpdateType): void; + onTransientError(error: StatusObject): void; + onResourceDoesNotExist(): void; +} export class XdsClient { + private node: adsTypes.messages.envoy.api.v2.core.Node | null = null; + private client: adsTypes.ClientInterfaces.envoy.service.discovery.v2.AggregatedDiscoveryServiceClient | null = null; + private adsCall: ClientDuplexStream | null = null; + + private endpointWatchers: Map[]> = new Map[]>(); + private lastEdsVersionInfo: string = ''; + private lastEdsNonce: string = ''; + + constructor() { + Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then(([bootstrapInfo, protoDefinitions]) => { + this.node = { + ...bootstrapInfo.node, + build_version: `gRPC Node Pure JS ${clientVersion}`, + user_agent_name: 'gRPC Node Pure JS' + } + this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService(bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials()); + this.maybeStartAdsStream(); + }, (error) => { + // Bubble this error up to any listeners + for (const watcherList of this.endpointWatchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError({ + code: Status.INTERNAL, + details: `Failed to initialize xDS Client. ${error.message}`, + metadata: new Metadata() + }) + } + } + }); + } + + /** + * Start the ADS stream if the client exists and there is not already an + * existing stream. + */ + private maybeStartAdsStream() { + if (this.client === null) { + return; + } + if (this.adsCall !== null) { + return; + } + this.adsCall = this.client.StreamAggregatedResources(); + this.adsCall.on('data', (message: adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output) => { + switch (message.type_url) { + case EDS_TYPE_URL: + const edsResponses: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output[] = []; + for (const resource of message.resources) { + if (protoLoader.isAnyExtension(resource) && resource['@type'] === EDS_TYPE_URL) { + const resp = resource as protoLoader.AnyExtension & edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output; + if (!this.validateEdsResponse(resp)) { + this.nackEds('ClusterLoadAssignment validation failed'); + return; + } + edsResponses.push(resp); + } else { + this.nackEds(`Invalid resource type ${protoLoader.isAnyExtension(resource) ? resource['@type'] : resource.type_url}`); + return; + } + } + for (const message of edsResponses) { + this.handleEdsResponse(message); + } + this.lastEdsVersionInfo = message.version_info; + this.lastEdsNonce = message.nonce; + this.ackEds(); + break; + default: + this.nackUnknown(message.type_url, message.version_info, message.nonce); + } + }); + this.adsCall.on('error', (error: ServiceError) => { + this.adsCall = null; + this.reportStreamError(error); + this.maybeStartAdsStream(); + }); + const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); + if (endpointWatcherNames.length > 0) { + this.adsCall.write({ + node: this.node, + type_url: EDS_TYPE_URL, + resource_names: endpointWatcherNames + }); + } + } + + private nackUnknown(typeUrl: string, versionInfo: string, nonce: string) { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node, + type_url: typeUrl, + version_info: versionInfo, + response_nonce: nonce, + error_detail: { + message: `Unknown type_url ${typeUrl}` + } + }); + } + + /** + * Acknowledge an EDS update. This should be called after the local nonce and + * version info are updated so that it sends the post-update values. + */ + private ackEds() { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node, + type_url: EDS_TYPE_URL, + resource_names: Array.from(this.endpointWatchers.keys()), + response_nonce: this.lastEdsNonce, + version_info: this.lastEdsVersionInfo + }); + } + + /** + * Reject an EDS update. This should be called without updating the local + * nonce and version info. + */ + private nackEds(message: string) { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node, + type_url: EDS_TYPE_URL, + resource_names: Array.from(this.endpointWatchers.keys()), + response_nonce: this.lastEdsNonce, + version_info: this.lastEdsVersionInfo, + error_detail: { + message + } + }); + } + + private validateEdsResponse(message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output): boolean { + for (const endpoint of message.endpoints) { + for (const lb of endpoint.lb_endpoints) { + if (!lb.endpoint) { + return false; + } + if (!lb.endpoint.address) { + return false; + } + if (!lb.endpoint.address.socket_address) { + return false; + } + const socketAddress = lb.endpoint.address.socket_address; + if (socketAddress.port_specifier !== 'port_value') { + return false; + } + if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { + return false; + } + } + } + return true; + } + + private handleEdsResponse(message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output) { + const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + + private updateEdsNames() { + if (this.adsCall) { + this.adsCall.write({ + node: this.node, + type_url: EDS_TYPE_URL, + resource_names: Array.from(this.endpointWatchers.keys()), + response_nonce: this.lastEdsNonce, + version_info: this.lastEdsVersionInfo + }); + } + } + + private reportStreamError(status: StatusObject) { + for (const watcherList of this.endpointWatchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + // Also do the same for other types of watchers when those are implemented + } + + addEndpointWatcher(edsServiceName: string, watcher: Watcher) { + let watchersEntry = this.endpointWatchers.get(edsServiceName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.endpointWatchers.set(edsServiceName, watchersEntry); + } + watchersEntry.push(watcher); + if (addedServiceName) { + this.updateEdsNames(); + } + } + removeEndpointWatcher(edsServiceName: string, watcher: Watcher) { + const watchersEntry = this.endpointWatchers.get(edsServiceName); + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + } + } } \ No newline at end of file From 46c84bdb4ef87969e370ff9b39c542a78b58d746 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Jul 2020 10:51:42 -0700 Subject: [PATCH 1139/1899] grpc-js: Improve error handling in a few places --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 9 +++++++++ packages/grpc-js/src/subchannel.ts | 27 +++++++++++++++++++++++++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index da8e28ae5..27aa679c9 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.1", + "version": "1.1.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 041f9651c..825342a58 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -541,6 +541,15 @@ export class Http2CallStream implements Call { code = Status.PERMISSION_DENIED; details = 'Protocol not secure enough'; break; + case http2.constants.NGHTTP2_INTERNAL_ERROR: + code = Status.INTERNAL; + /* This error code was previously handled in the default case, and + * there are several instances of it online, so I wanted to + * preserve the original error message so that people find existing + * information in searches, but also include the more recognizable + * "Internal server error" message. */ + details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; + break; default: code = Status.INTERNAL; details = `Received RST_STREAM with code ${stream.rstCode}`; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index bbaa1ce18..be72680e2 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -309,7 +309,8 @@ export class Subchannel { }; connectionOptions.servername = sslTargetNameOverride; } else { - const authorityHostname = splitHostPort(targetAuthority)?.host ?? 'localhost'; + const authorityHostname = + splitHostPort(targetAuthority)?.host ?? 'localhost'; // We want to always set servername to support SNI connectionOptions.servername = authorityHostname; } @@ -413,6 +414,11 @@ export class Subchannel { KEEPALIVE_MAX_TIME_MS ); } + trace( + this.subchannelAddress + + ' connection closed by GOAWAY with code ' + + errorCode + ); this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], ConnectivityState.IDLE @@ -661,7 +667,24 @@ export class Subchannel { headers[HTTP2_HEADER_METHOD] = 'POST'; headers[HTTP2_HEADER_PATH] = callStream.getMethod(); headers[HTTP2_HEADER_TE] = 'trailers'; - const http2Stream = this.session!.request(headers); + let http2Stream: http2.ClientHttp2Stream; + /* In theory, if an error is thrown by session.request because session has + * become unusable (e.g. because it has received a goaway), this subchannel + * should soon see the corresponding close or goaway event anyway and leave + * READY. But we have seen reports that this does not happen + * (https://github.com/googleapis/nodejs-firestore/issues/1023#issuecomment-653204096) + * so for defense in depth, we just discard the session when we see an + * error here. + */ + try { + http2Stream = this.session!.request(headers); + } catch (e) { + this.transitionToState( + [ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE + ); + throw e; + } let headersString = ''; for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; From 8a2c5af8f70754b87f70eb5fcb07b44891a2a1f8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Jul 2020 14:48:54 -0700 Subject: [PATCH 1140/1899] Finish up bootstrap and EDS client code --- packages/grpc-js/src/xds-bootstrap.ts | 113 +++++++++++++++++++++++++- packages/grpc-js/src/xds-client.ts | 107 +++++++++++++++++------- 2 files changed, 190 insertions(+), 30 deletions(-) diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index 95fd96e3a..c8e88a01d 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -75,8 +75,117 @@ function validateXdsServerConfig(obj: any): XdsServerConfig { }; } +function validateValue(obj: any): adsTypes.messages.google.protobuf.Value { + if (Array.isArray(obj)) { + return { + kind: 'listValue', + listValue: { + values: obj.map(value => validateValue(value)) + } + } + } else { + switch (typeof obj) { + case 'boolean': + return { + kind: 'boolValue', + boolValue: obj + }; + case 'number': + return { + kind: 'numberValue', + numberValue: obj + }; + case 'string': + return { + kind: 'stringValue', + stringValue: obj + }; + case 'object': + if (obj === null) { + return { + kind: 'nullValue', + nullValue: 'NULL_VALUE' + }; + } else { + return { + kind: 'structValue', + structValue: getStructFromJson(obj) + }; + } + default: + throw new Error(`Could not handle struct value of type ${typeof obj}`); + } + } +} + +function getStructFromJson(obj: any): adsTypes.messages.google.protobuf.Struct { + if (typeof obj !== 'object' || obj === null) { + throw new Error('Invalid JSON object for Struct field'); + } + const result = Object.keys(obj).map(key => validateValue(key)); + if (result.length === 1) { + return { + fields: result[0] + } + } else { + return { + fields: { + kind: 'listValue', + listValue: { + values: result + } + } + } + }; +} + +/** + * Validate that the input obj is a valid Node proto message. Only checks the + * fields we expect to see: id, cluster, locality, and metadata. + * @param obj + */ function validateNode(obj: any): adsTypes.messages.envoy.api.v2.core.Node { - throw new Error('Not implemented'); + const result: adsTypes.messages.envoy.api.v2.core.Node = {}; + if (!('id' in obj)) { + throw new Error('id field missing in node element'); + } + if (typeof obj.id !== 'string') { + throw new Error(`node.id field: expected string, got ${typeof obj.id}`); + } + result.id = obj.id; + if (!('cluster' in obj)) { + throw new Error('cluster field missing in node element'); + } + if (typeof obj.cluster !== 'string') { + throw new Error(`node.cluster field: expected string, got ${typeof obj.cluster}`); + } + result.cluster = obj.cluster; + if (!('locality' in obj)) { + throw new Error('locality field missing in node element'); + } + result.locality = {}; + if ('region' in obj.locality) { + if (typeof obj.locality.region !== 'string') { + throw new Error(`node.locality.region field: expected string, got ${typeof obj.locality.region}`); + } + result.locality.region = obj.locality.region; + } + if ('zone' in obj.locality) { + if (typeof obj.locality.region !== 'string') { + throw new Error(`node.locality.zone field: expected string, got ${typeof obj.locality.zone}`); + } + result.locality.zone = obj.locality.zone; + } + if ('sub_zone' in obj.locality) { + if (typeof obj.locality.sub_zone !== 'string') { + throw new Error(`node.locality.sub_zone field: expected string, got ${typeof obj.locality.sub_zone}`); + } + result.locality.sub_zone = obj.locality.sub_zone; + } + if ('metadata' in obj) { + result.metadata = getStructFromJson(obj.metadata); + } + return result; } function validateBootstrapFile(obj: any): BootstrapInfo { @@ -94,7 +203,7 @@ export async function loadBootstrapInfo(): Promise { } const bootstrapPath = process.env.GRPC_XDS_BOOTSTRAP; if (bootstrapPath === undefined) { - return Promise.reject(new Error('GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS')); + return Promise.reject(new Error('The GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS')); } loadedBootstrapInfo = new Promise((resolve, reject) => { fs.readFile(bootstrapPath, { encoding: 'utf8'}, (err, data) => { diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 6d80f3b79..050762141 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -15,18 +15,26 @@ * */ -import * as fs from 'fs'; import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; import * as edsTypes from './generated/endpoint'; -import { ChannelCredentials, createGoogleDefaultCredentials } from './channel-credentials'; +import { createGoogleDefaultCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; import { ClientDuplexStream, ServiceError } from './call'; import { StatusObject } from './call-stream'; import { isIPv4, isIPv6 } from 'net'; -import { Status } from './constants'; +import { Status, LogVerbosity } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { ServiceConfig } from './service-config'; +import { ChannelOptions } from './channel-options'; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const clientVersion = require('../../package.json').version; @@ -72,36 +80,57 @@ export class XdsClient { private client: adsTypes.ClientInterfaces.envoy.service.discovery.v2.AggregatedDiscoveryServiceClient | null = null; private adsCall: ClientDuplexStream | null = null; + private hasShutdown: boolean = false; + private endpointWatchers: Map[]> = new Map[]>(); private lastEdsVersionInfo: string = ''; private lastEdsNonce: string = ''; - constructor() { + constructor(private targetName: string, private serviceConfigWatcher: Watcher, channelOptions: ChannelOptions) { + const channelArgs = {...channelOptions}; + const channelArgsToRemove = [ + /* The SSL target name override corresponds to the target, and this + * client has its own target */ + 'grpc.ssl_target_name_override', + /* The default authority also corresponds to the target */ + 'grpc.default_authority', + /* This client will have its own specific keepalive time setting */ + 'grpc.keepalive_time_ms', + /* The service config specifies the load balancing policy. This channel + * needs its own separate load balancing policy setting. In particular, + * recursively using an xDS load balancer for the xDS client would be + * bad */ + 'grpc.service_config' + ]; + for (const arg of channelArgsToRemove) { + delete channelArgs[arg]; + } + channelArgs['grpc.keepalive_time_ms'] = 5000; Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then(([bootstrapInfo, protoDefinitions]) => { + if (this.hasShutdown) { + return; + } this.node = { ...bootstrapInfo.node, build_version: `gRPC Node Pure JS ${clientVersion}`, user_agent_name: 'gRPC Node Pure JS' } - this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService(bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials()); + this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService(bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), channelArgs); this.maybeStartAdsStream(); }, (error) => { + trace('Failed to initialize xDS Client. ' + error.message); // Bubble this error up to any listeners - for (const watcherList of this.endpointWatchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError({ - code: Status.INTERNAL, - details: `Failed to initialize xDS Client. ${error.message}`, - metadata: new Metadata() - }) - } - } + this.reportStreamError({ + code: Status.INTERNAL, + details: `Failed to initialize xDS Client. ${error.message}`, + metadata: new Metadata() + }); }); } /** * Start the ADS stream if the client exists and there is not already an - * existing stream. + * existing stream, and there */ private maybeStartAdsStream() { if (this.client === null) { @@ -110,6 +139,9 @@ export class XdsClient { if (this.adsCall !== null) { return; } + if (this.hasShutdown) { + return; + } this.adsCall = this.client.StreamAggregatedResources(); this.adsCall.on('data', (message: adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output) => { switch (message.type_url) { @@ -140,14 +172,18 @@ export class XdsClient { } }); this.adsCall.on('error', (error: ServiceError) => { + trace('ADS stream ended. code=' + error.code + ' details= ' + error.details); this.adsCall = null; this.reportStreamError(error); + /* Connection backoff is handled by the client object, so we can + * immediately start a new request to indicate that it should try to + * reconnect */ this.maybeStartAdsStream(); }); const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); if (endpointWatcherNames.length > 0) { this.adsCall.write({ - node: this.node, + node: this.node!, type_url: EDS_TYPE_URL, resource_names: endpointWatcherNames }); @@ -159,7 +195,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node, + node: this.node!, type_url: typeUrl, version_info: versionInfo, response_nonce: nonce, @@ -178,7 +214,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node, + node: this.node!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -195,7 +231,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node, + node: this.node!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -206,19 +242,18 @@ export class XdsClient { }); } + /** + * Validate the ClusterLoadAssignment object by these rules: + * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto + * @param message + */ private validateEdsResponse(message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output): boolean { for (const endpoint of message.endpoints) { for (const lb of endpoint.lb_endpoints) { - if (!lb.endpoint) { - return false; - } - if (!lb.endpoint.address) { - return false; - } - if (!lb.endpoint.address.socket_address) { + const socketAddress = lb.endpoint?.address?.socket_address; + if (!socketAddress) { return false; } - const socketAddress = lb.endpoint.address.socket_address; if (socketAddress.port_specifier !== 'port_value') { return false; } @@ -240,7 +275,7 @@ export class XdsClient { private updateEdsNames() { if (this.adsCall) { this.adsCall.write({ - node: this.node, + node: this.node!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -259,6 +294,7 @@ export class XdsClient { } addEndpointWatcher(edsServiceName: string, watcher: Watcher) { + trace('Watcher added for endpoint ' + edsServiceName); let watchersEntry = this.endpointWatchers.get(edsServiceName); let addedServiceName = false; if (watchersEntry === undefined) { @@ -273,12 +309,27 @@ export class XdsClient { } removeEndpointWatcher(edsServiceName: string, watcher: Watcher) { + trace('Watcher removed for endpoint ' + edsServiceName); const watchersEntry = this.endpointWatchers.get(edsServiceName); + let removedServiceName = false; if (watchersEntry !== undefined) { const entryIndex = watchersEntry.indexOf(watcher); if (entryIndex >= 0) { watchersEntry.splice(entryIndex, 1); } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.endpointWatchers.delete(edsServiceName); + } + } + if (removedServiceName) { + this.updateEdsNames(); } } + + shutdown(): void { + this.adsCall?.cancel(); + this.client?.close(); + this.hasShutdown = true; + } } \ No newline at end of file From dbef8619484f87b6e6209126fdaab4abfda511f2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Jul 2020 14:49:28 -0700 Subject: [PATCH 1141/1899] Add files, dependencies, and generation script to package.json --- packages/grpc-js/generateTypes.sh | 20 -------------------- packages/grpc-js/package.json | 15 +++++++++++---- 2 files changed, 11 insertions(+), 24 deletions(-) delete mode 100644 packages/grpc-js/generateTypes.sh diff --git a/packages/grpc-js/generateTypes.sh b/packages/grpc-js/generateTypes.sh deleted file mode 100644 index 8eee726c0..000000000 --- a/packages/grpc-js/generateTypes.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -# Copyright 2020 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -base=$(dirname $0) - -./node_modules/.bin/proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json\ - --includeDirs deps/envoy-api/ deps/udpa/ node_modules/protobufjs/ deps/googleapis/ deps/protoc-gen-validate/ \ - -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto \ No newline at end of file diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 280950245..8a20a6842 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,6 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre5", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -48,6 +47,7 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeDirs deps/envoy-api/ deps/udpa/ node_modules/protobufjs/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", @@ -57,16 +57,23 @@ "posttest": "npm run check" }, "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre6", "semver": "^6.2.0" }, "peerDependencies": { "google-auth-library": "5.x || 6.x" }, "files": [ - "src/*.ts", + "src/**/*.ts", "build/src/*.{js,d.ts,js.map}", "LICENSE", - "deps/envoy-api/envoy/**/*.proto", - "deps/udpa/udpa/**/*.proto" + "deps/envoy-api/envoy/api/v2/**/*.proto", + "deps/envoy-api/envoy/config/**/*.proto", + "deps/envoy-api/envoy/service/**/*.proto", + "deps/envoy-api/envoy/type/**/*.proto", + "deps/udpa/udpa/**/*.proto", + "deps/googleapis/google/api/*.proto", + "deps/googleapis/google/rpc/*.proto", + "deps/protoc-gen-validate/validate/**/*.proto" ] } From 0c41a4e039a7e8300bf873dbd1477bec1e4bc905 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Jul 2020 15:13:02 -0700 Subject: [PATCH 1142/1899] Move the generated files to .ts instead of .d.ts --- .../src/generated/{ads.d.ts => ads.ts} | 32 +- .../generated/{cluster.d.ts => cluster.ts} | 508 +++++++++--------- .../generated/{endpoint.d.ts => endpoint.ts} | 196 +++---- .../envoy/api/v2/{Cluster.d.ts => Cluster.ts} | 0 ...signment.d.ts => ClusterLoadAssignment.ts} | 0 ...yRequest.d.ts => DeltaDiscoveryRequest.ts} | 0 ...esponse.d.ts => DeltaDiscoveryResponse.ts} | 0 ...coveryRequest.d.ts => DiscoveryRequest.ts} | 0 ...veryResponse.d.ts => DiscoveryResponse.ts} | 0 .../api/v2/{Listener.d.ts => Listener.ts} | 0 ...cingPolicy.d.ts => LoadBalancingPolicy.ts} | 0 .../api/v2/{Resource.d.ts => Resource.ts} | 0 ...nfiguration.d.ts => RouteConfiguration.ts} | 0 ...mBindConfig.d.ts => UpstreamBindConfig.ts} | 0 ...ions.d.ts => UpstreamConnectionOptions.ts} | 0 .../envoy/api/v2/{Vhds.d.ts => Vhds.ts} | 0 ...t.d.ts => CertificateValidationContext.ts} | 0 ...monTlsContext.d.ts => CommonTlsContext.ts} | 0 ...lsContext.d.ts => DownstreamTlsContext.ts} | 0 .../{GenericSecret.d.ts => GenericSecret.ts} | 0 ...KeyProvider.d.ts => PrivateKeyProvider.ts} | 0 ...dsSecretConfig.d.ts => SdsSecretConfig.ts} | 0 .../api/v2/auth/{Secret.d.ts => Secret.ts} | 0 ...{TlsCertificate.d.ts => TlsCertificate.ts} | 0 .../{TlsParameters.d.ts => TlsParameters.ts} | 0 ...icketKeys.d.ts => TlsSessionTicketKeys.ts} | 0 ...mTlsContext.d.ts => UpstreamTlsContext.ts} | 0 ...ircuitBreakers.d.ts => CircuitBreakers.ts} | 0 .../api/v2/cluster/{Filter.d.ts => Filter.ts} | 0 ...lierDetection.d.ts => OutlierDetection.ts} | 0 .../api/v2/core/{Address.d.ts => Address.ts} | 0 ...gSource.d.ts => AggregatedConfigSource.ts} | 0 ...piConfigSource.d.ts => ApiConfigSource.ts} | 0 .../core/{ApiVersion.d.ts => ApiVersion.ts} | 0 ...syncDataSource.d.ts => AsyncDataSource.ts} | 0 ...ackoffStrategy.d.ts => BackoffStrategy.ts} | 0 .../core/{BindConfig.d.ts => BindConfig.ts} | 0 .../{BuildVersion.d.ts => BuildVersion.ts} | 0 .../v2/core/{CidrRange.d.ts => CidrRange.ts} | 0 .../{ConfigSource.d.ts => ConfigSource.ts} | 0 .../{ControlPlane.d.ts => ControlPlane.ts} | 0 .../core/{DataSource.d.ts => DataSource.ts} | 0 ...rviceConfig.d.ts => EventServiceConfig.ts} | 0 .../v2/core/{Extension.d.ts => Extension.ts} | 0 ...colOptions.d.ts => GrpcProtocolOptions.ts} | 0 .../core/{GrpcService.d.ts => GrpcService.ts} | 0 .../v2/core/{HeaderMap.d.ts => HeaderMap.ts} | 0 .../core/{HeaderValue.d.ts => HeaderValue.ts} | 0 ...rValueOption.d.ts => HeaderValueOption.ts} | 0 .../core/{HealthCheck.d.ts => HealthCheck.ts} | 0 .../{HealthStatus.d.ts => HealthStatus.ts} | 0 ...olOptions.d.ts => Http1ProtocolOptions.ts} | 0 ...olOptions.d.ts => Http2ProtocolOptions.ts} | 0 ...colOptions.d.ts => HttpProtocolOptions.ts} | 0 .../api/v2/core/{HttpUri.d.ts => HttpUri.ts} | 0 .../v2/core/{Locality.d.ts => Locality.ts} | 0 .../v2/core/{Metadata.d.ts => Metadata.ts} | 0 .../envoy/api/v2/core/{Node.d.ts => Node.ts} | 0 .../envoy/api/v2/core/{Pipe.d.ts => Pipe.ts} | 0 ...imitSettings.d.ts => RateLimitSettings.ts} | 0 ...oteDataSource.d.ts => RemoteDataSource.ts} | 0 .../{RequestMethod.d.ts => RequestMethod.ts} | 0 .../core/{RetryPolicy.d.ts => RetryPolicy.ts} | 0 ...outingPriority.d.ts => RoutingPriority.ts} | 0 .../{RuntimeDouble.d.ts => RuntimeDouble.ts} | 0 ...FeatureFlag.d.ts => RuntimeFeatureFlag.ts} | 0 ...rcent.d.ts => RuntimeFractionalPercent.ts} | 0 .../{RuntimeUInt32.d.ts => RuntimeUInt32.ts} | 0 ...fConfigSource.d.ts => SelfConfigSource.ts} | 0 .../{SocketAddress.d.ts => SocketAddress.ts} | 0 .../{SocketOption.d.ts => SocketOption.ts} | 0 .../{TcpKeepalive.d.ts => TcpKeepalive.ts} | 0 ...ocolOptions.d.ts => TcpProtocolOptions.ts} | 0 ...fficDirection.d.ts => TrafficDirection.ts} | 0 ...ransportSocket.d.ts => TransportSocket.ts} | 0 ...ns.d.ts => UpstreamHttpProtocolOptions.ts} | 0 .../endpoint/{Endpoint.d.ts => Endpoint.ts} | 0 .../{LbEndpoint.d.ts => LbEndpoint.ts} | 0 ...bEndpoints.d.ts => LocalityLbEndpoints.ts} | 0 ...fig.d.ts => ActiveRawUdpListenerConfig.ts} | 0 .../v2/listener/{Filter.d.ts => Filter.ts} | 0 .../{FilterChain.d.ts => FilterChain.ts} | 0 ...terChainMatch.d.ts => FilterChainMatch.ts} | 0 ...{ListenerFilter.d.ts => ListenerFilter.ts} | 0 ...s => ListenerFilterChainMatchPredicate.ts} | 0 ...stenerConfig.d.ts => UdpListenerConfig.ts} | 0 .../route/{CorsPolicy.d.ts => CorsPolicy.ts} | 0 .../v2/route/{Decorator.d.ts => Decorator.ts} | 0 ...nseAction.d.ts => DirectResponseAction.ts} | 0 .../{FilterAction.d.ts => FilterAction.ts} | 0 .../{HeaderMatcher.d.ts => HeaderMatcher.ts} | 0 .../{HedgePolicy.d.ts => HedgePolicy.ts} | 0 ...rMatcher.d.ts => QueryParameterMatcher.ts} | 0 .../v2/route/{RateLimit.d.ts => RateLimit.ts} | 0 ...{RedirectAction.d.ts => RedirectAction.ts} | 0 .../{RetryPolicy.d.ts => RetryPolicy.ts} | 0 .../api/v2/route/{Route.d.ts => Route.ts} | 0 .../{RouteAction.d.ts => RouteAction.ts} | 0 .../route/{RouteMatch.d.ts => RouteMatch.ts} | 0 .../api/v2/route/{Tracing.d.ts => Tracing.ts} | 0 ...{VirtualCluster.d.ts => VirtualCluster.ts} | 0 .../{VirtualHost.d.ts => VirtualHost.ts} | 0 ...eightedCluster.d.ts => WeightedCluster.ts} | 0 .../v2/{AccessLog.d.ts => AccessLog.ts} | 0 ...ccessLogFilter.d.ts => AccessLogFilter.ts} | 0 .../v2/{AndFilter.d.ts => AndFilter.ts} | 0 ...parisonFilter.d.ts => ComparisonFilter.ts} | 0 ...{DurationFilter.d.ts => DurationFilter.ts} | 0 ...xtensionFilter.d.ts => ExtensionFilter.ts} | 0 ...cStatusFilter.d.ts => GrpcStatusFilter.ts} | 0 .../v2/{HeaderFilter.d.ts => HeaderFilter.ts} | 0 ...eckFilter.d.ts => NotHealthCheckFilter.ts} | 0 .../v2/{OrFilter.d.ts => OrFilter.ts} | 0 ...eFlagFilter.d.ts => ResponseFlagFilter.ts} | 0 .../{RuntimeFilter.d.ts => RuntimeFilter.ts} | 0 ...tusCodeFilter.d.ts => StatusCodeFilter.ts} | 0 ...raceableFilter.d.ts => TraceableFilter.ts} | 0 .../v2/{ApiListener.d.ts => ApiListener.ts} | 0 .../v2/{AdsDummy.d.ts => AdsDummy.ts} | 0 ...odecClientType.d.ts => CodecClientType.ts} | 0 .../type/{DoubleRange.d.ts => DoubleRange.ts} | 0 ...ionalPercent.d.ts => FractionalPercent.ts} | 0 .../type/{Int32Range.d.ts => Int32Range.ts} | 0 .../type/{Int64Range.d.ts => Int64Range.ts} | 0 .../envoy/type/{Percent.d.ts => Percent.ts} | 0 ...emanticVersion.d.ts => SemanticVersion.ts} | 0 ...tringMatcher.d.ts => ListStringMatcher.ts} | 0 ...titute.d.ts => RegexMatchAndSubstitute.ts} | 0 .../{RegexMatcher.d.ts => RegexMatcher.ts} | 0 .../{StringMatcher.d.ts => StringMatcher.ts} | 0 .../v2/{MetadataKey.d.ts => MetadataKey.ts} | 0 .../v2/{MetadataKind.d.ts => MetadataKind.ts} | 0 .../v2/{CustomTag.d.ts => CustomTag.ts} | 0 ...mHttpPattern.d.ts => CustomHttpPattern.ts} | 0 .../google/api/{Http.d.ts => Http.ts} | 0 .../google/api/{HttpRule.d.ts => HttpRule.ts} | 0 .../google/protobuf/{Any.d.ts => Any.ts} | 0 .../protobuf/{BoolValue.d.ts => BoolValue.ts} | 0 .../{BytesValue.d.ts => BytesValue.ts} | 0 ...escriptorProto.d.ts => DescriptorProto.ts} | 0 .../{DoubleValue.d.ts => DoubleValue.ts} | 0 .../protobuf/{Duration.d.ts => Duration.ts} | 0 .../google/protobuf/{Empty.d.ts => Empty.ts} | 0 ...iptorProto.d.ts => EnumDescriptorProto.ts} | 0 .../{EnumOptions.d.ts => EnumOptions.ts} | 0 ...Proto.d.ts => EnumValueDescriptorProto.ts} | 0 ...mValueOptions.d.ts => EnumValueOptions.ts} | 0 ...ptorProto.d.ts => FieldDescriptorProto.ts} | 0 .../{FieldOptions.d.ts => FieldOptions.ts} | 0 ...iptorProto.d.ts => FileDescriptorProto.ts} | 0 ...escriptorSet.d.ts => FileDescriptorSet.ts} | 0 .../{FileOptions.d.ts => FileOptions.ts} | 0 .../{FloatValue.d.ts => FloatValue.ts} | 0 ...atedCodeInfo.d.ts => GeneratedCodeInfo.ts} | 0 .../{Int32Value.d.ts => Int32Value.ts} | 0 .../{Int64Value.d.ts => Int64Value.ts} | 0 .../protobuf/{ListValue.d.ts => ListValue.ts} | 0 ...{MessageOptions.d.ts => MessageOptions.ts} | 0 ...torProto.d.ts => MethodDescriptorProto.ts} | 0 .../{MethodOptions.d.ts => MethodOptions.ts} | 0 .../protobuf/{NullValue.d.ts => NullValue.ts} | 0 ...ptorProto.d.ts => OneofDescriptorProto.ts} | 0 .../{OneofOptions.d.ts => OneofOptions.ts} | 0 ...orProto.d.ts => ServiceDescriptorProto.ts} | 0 ...{ServiceOptions.d.ts => ServiceOptions.ts} | 0 ...{SourceCodeInfo.d.ts => SourceCodeInfo.ts} | 0 .../{StringValue.d.ts => StringValue.ts} | 0 .../protobuf/{Struct.d.ts => Struct.ts} | 0 .../protobuf/{Timestamp.d.ts => Timestamp.ts} | 0 .../{UInt32Value.d.ts => UInt32Value.ts} | 0 .../{UInt64Value.d.ts => UInt64Value.ts} | 0 ...etedOption.d.ts => UninterpretedOption.ts} | 0 .../google/protobuf/{Value.d.ts => Value.ts} | 0 .../google/rpc/{Status.d.ts => Status.ts} | 0 .../generated/{listener.d.ts => listener.ts} | 208 +++---- .../src/generated/{route.d.ts => route.ts} | 126 ++--- ...otation.d.ts => FieldMigrateAnnotation.ts} | 0 ...notation.d.ts => FileMigrateAnnotation.ts} | 0 ...teAnnotation.d.ts => MigrateAnnotation.ts} | 0 ...ionStatus.d.ts => PackageVersionStatus.ts} | 0 ...tusAnnotation.d.ts => StatusAnnotation.ts} | 0 .../validate/{AnyRules.d.ts => AnyRules.ts} | 0 .../validate/{BoolRules.d.ts => BoolRules.ts} | 0 .../{BytesRules.d.ts => BytesRules.ts} | 0 .../{DoubleRules.d.ts => DoubleRules.ts} | 0 .../{DurationRules.d.ts => DurationRules.ts} | 0 .../validate/{EnumRules.d.ts => EnumRules.ts} | 0 .../{FieldRules.d.ts => FieldRules.ts} | 0 .../{Fixed32Rules.d.ts => Fixed32Rules.ts} | 0 .../{Fixed64Rules.d.ts => Fixed64Rules.ts} | 0 .../{FloatRules.d.ts => FloatRules.ts} | 0 .../{Int32Rules.d.ts => Int32Rules.ts} | 0 .../{Int64Rules.d.ts => Int64Rules.ts} | 0 .../{KnownRegex.d.ts => KnownRegex.ts} | 0 .../validate/{MapRules.d.ts => MapRules.ts} | 0 .../{MessageRules.d.ts => MessageRules.ts} | 0 .../{RepeatedRules.d.ts => RepeatedRules.ts} | 0 .../{SFixed32Rules.d.ts => SFixed32Rules.ts} | 0 .../{SFixed64Rules.d.ts => SFixed64Rules.ts} | 0 .../{SInt32Rules.d.ts => SInt32Rules.ts} | 0 .../{SInt64Rules.d.ts => SInt64Rules.ts} | 0 .../{StringRules.d.ts => StringRules.ts} | 0 ...{TimestampRules.d.ts => TimestampRules.ts} | 0 .../{UInt32Rules.d.ts => UInt32Rules.ts} | 0 .../{UInt64Rules.d.ts => UInt64Rules.ts} | 0 205 files changed, 535 insertions(+), 535 deletions(-) rename packages/grpc-js/src/generated/{ads.d.ts => ads.ts} (100%) rename packages/grpc-js/src/generated/{cluster.d.ts => cluster.ts} (100%) rename packages/grpc-js/src/generated/{endpoint.d.ts => endpoint.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{Cluster.d.ts => Cluster.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{ClusterLoadAssignment.d.ts => ClusterLoadAssignment.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{DeltaDiscoveryRequest.d.ts => DeltaDiscoveryRequest.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{DeltaDiscoveryResponse.d.ts => DeltaDiscoveryResponse.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{DiscoveryRequest.d.ts => DiscoveryRequest.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{DiscoveryResponse.d.ts => DiscoveryResponse.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{Listener.d.ts => Listener.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{LoadBalancingPolicy.d.ts => LoadBalancingPolicy.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{Resource.d.ts => Resource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{RouteConfiguration.d.ts => RouteConfiguration.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{UpstreamBindConfig.d.ts => UpstreamBindConfig.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{UpstreamConnectionOptions.d.ts => UpstreamConnectionOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/{Vhds.d.ts => Vhds.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{CertificateValidationContext.d.ts => CertificateValidationContext.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{CommonTlsContext.d.ts => CommonTlsContext.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{DownstreamTlsContext.d.ts => DownstreamTlsContext.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{GenericSecret.d.ts => GenericSecret.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{PrivateKeyProvider.d.ts => PrivateKeyProvider.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{SdsSecretConfig.d.ts => SdsSecretConfig.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{Secret.d.ts => Secret.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{TlsCertificate.d.ts => TlsCertificate.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{TlsParameters.d.ts => TlsParameters.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{TlsSessionTicketKeys.d.ts => TlsSessionTicketKeys.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/auth/{UpstreamTlsContext.d.ts => UpstreamTlsContext.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/cluster/{CircuitBreakers.d.ts => CircuitBreakers.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/cluster/{Filter.d.ts => Filter.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/cluster/{OutlierDetection.d.ts => OutlierDetection.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Address.d.ts => Address.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{AggregatedConfigSource.d.ts => AggregatedConfigSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{ApiConfigSource.d.ts => ApiConfigSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{ApiVersion.d.ts => ApiVersion.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{AsyncDataSource.d.ts => AsyncDataSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{BackoffStrategy.d.ts => BackoffStrategy.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{BindConfig.d.ts => BindConfig.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{BuildVersion.d.ts => BuildVersion.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{CidrRange.d.ts => CidrRange.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{ConfigSource.d.ts => ConfigSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{ControlPlane.d.ts => ControlPlane.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{DataSource.d.ts => DataSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{EventServiceConfig.d.ts => EventServiceConfig.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Extension.d.ts => Extension.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{GrpcProtocolOptions.d.ts => GrpcProtocolOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{GrpcService.d.ts => GrpcService.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HeaderMap.d.ts => HeaderMap.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HeaderValue.d.ts => HeaderValue.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HeaderValueOption.d.ts => HeaderValueOption.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HealthCheck.d.ts => HealthCheck.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HealthStatus.d.ts => HealthStatus.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Http1ProtocolOptions.d.ts => Http1ProtocolOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Http2ProtocolOptions.d.ts => Http2ProtocolOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HttpProtocolOptions.d.ts => HttpProtocolOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{HttpUri.d.ts => HttpUri.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Locality.d.ts => Locality.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Metadata.d.ts => Metadata.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Node.d.ts => Node.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{Pipe.d.ts => Pipe.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RateLimitSettings.d.ts => RateLimitSettings.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RemoteDataSource.d.ts => RemoteDataSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RequestMethod.d.ts => RequestMethod.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RetryPolicy.d.ts => RetryPolicy.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RoutingPriority.d.ts => RoutingPriority.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RuntimeDouble.d.ts => RuntimeDouble.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RuntimeFeatureFlag.d.ts => RuntimeFeatureFlag.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RuntimeFractionalPercent.d.ts => RuntimeFractionalPercent.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{RuntimeUInt32.d.ts => RuntimeUInt32.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{SelfConfigSource.d.ts => SelfConfigSource.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{SocketAddress.d.ts => SocketAddress.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{SocketOption.d.ts => SocketOption.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{TcpKeepalive.d.ts => TcpKeepalive.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{TcpProtocolOptions.d.ts => TcpProtocolOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{TrafficDirection.d.ts => TrafficDirection.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{TransportSocket.d.ts => TransportSocket.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/core/{UpstreamHttpProtocolOptions.d.ts => UpstreamHttpProtocolOptions.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/endpoint/{Endpoint.d.ts => Endpoint.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/endpoint/{LbEndpoint.d.ts => LbEndpoint.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/endpoint/{LocalityLbEndpoints.d.ts => LocalityLbEndpoints.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{ActiveRawUdpListenerConfig.d.ts => ActiveRawUdpListenerConfig.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{Filter.d.ts => Filter.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{FilterChain.d.ts => FilterChain.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{FilterChainMatch.d.ts => FilterChainMatch.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{ListenerFilter.d.ts => ListenerFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{ListenerFilterChainMatchPredicate.d.ts => ListenerFilterChainMatchPredicate.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/listener/{UdpListenerConfig.d.ts => UdpListenerConfig.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{CorsPolicy.d.ts => CorsPolicy.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{Decorator.d.ts => Decorator.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{DirectResponseAction.d.ts => DirectResponseAction.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{FilterAction.d.ts => FilterAction.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{HeaderMatcher.d.ts => HeaderMatcher.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{HedgePolicy.d.ts => HedgePolicy.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{QueryParameterMatcher.d.ts => QueryParameterMatcher.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{RateLimit.d.ts => RateLimit.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{RedirectAction.d.ts => RedirectAction.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{RetryPolicy.d.ts => RetryPolicy.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{Route.d.ts => Route.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{RouteAction.d.ts => RouteAction.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{RouteMatch.d.ts => RouteMatch.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{Tracing.d.ts => Tracing.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{VirtualCluster.d.ts => VirtualCluster.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{VirtualHost.d.ts => VirtualHost.ts} (100%) rename packages/grpc-js/src/generated/envoy/api/v2/route/{WeightedCluster.d.ts => WeightedCluster.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{AccessLog.d.ts => AccessLog.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{AccessLogFilter.d.ts => AccessLogFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{AndFilter.d.ts => AndFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{ComparisonFilter.d.ts => ComparisonFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{DurationFilter.d.ts => DurationFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{ExtensionFilter.d.ts => ExtensionFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{GrpcStatusFilter.d.ts => GrpcStatusFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{HeaderFilter.d.ts => HeaderFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{NotHealthCheckFilter.d.ts => NotHealthCheckFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{OrFilter.d.ts => OrFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{ResponseFlagFilter.d.ts => ResponseFlagFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{RuntimeFilter.d.ts => RuntimeFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{StatusCodeFilter.d.ts => StatusCodeFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/{TraceableFilter.d.ts => TraceableFilter.ts} (100%) rename packages/grpc-js/src/generated/envoy/config/listener/v2/{ApiListener.d.ts => ApiListener.ts} (100%) rename packages/grpc-js/src/generated/envoy/service/discovery/v2/{AdsDummy.d.ts => AdsDummy.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{CodecClientType.d.ts => CodecClientType.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{DoubleRange.d.ts => DoubleRange.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{FractionalPercent.d.ts => FractionalPercent.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{Int32Range.d.ts => Int32Range.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{Int64Range.d.ts => Int64Range.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{Percent.d.ts => Percent.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/{SemanticVersion.d.ts => SemanticVersion.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/matcher/{ListStringMatcher.d.ts => ListStringMatcher.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/matcher/{RegexMatchAndSubstitute.d.ts => RegexMatchAndSubstitute.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/matcher/{RegexMatcher.d.ts => RegexMatcher.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/matcher/{StringMatcher.d.ts => StringMatcher.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/metadata/v2/{MetadataKey.d.ts => MetadataKey.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/metadata/v2/{MetadataKind.d.ts => MetadataKind.ts} (100%) rename packages/grpc-js/src/generated/envoy/type/tracing/v2/{CustomTag.d.ts => CustomTag.ts} (100%) rename packages/grpc-js/src/generated/google/api/{CustomHttpPattern.d.ts => CustomHttpPattern.ts} (100%) rename packages/grpc-js/src/generated/google/api/{Http.d.ts => Http.ts} (100%) rename packages/grpc-js/src/generated/google/api/{HttpRule.d.ts => HttpRule.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Any.d.ts => Any.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{BoolValue.d.ts => BoolValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{BytesValue.d.ts => BytesValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{DescriptorProto.d.ts => DescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{DoubleValue.d.ts => DoubleValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Duration.d.ts => Duration.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Empty.d.ts => Empty.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{EnumDescriptorProto.d.ts => EnumDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{EnumOptions.d.ts => EnumOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{EnumValueDescriptorProto.d.ts => EnumValueDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{EnumValueOptions.d.ts => EnumValueOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{FieldDescriptorProto.d.ts => FieldDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{FieldOptions.d.ts => FieldOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{FileDescriptorProto.d.ts => FileDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{FileDescriptorSet.d.ts => FileDescriptorSet.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{FileOptions.d.ts => FileOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{FloatValue.d.ts => FloatValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{GeneratedCodeInfo.d.ts => GeneratedCodeInfo.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Int32Value.d.ts => Int32Value.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Int64Value.d.ts => Int64Value.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{ListValue.d.ts => ListValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{MessageOptions.d.ts => MessageOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{MethodDescriptorProto.d.ts => MethodDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{MethodOptions.d.ts => MethodOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{NullValue.d.ts => NullValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{OneofDescriptorProto.d.ts => OneofDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{OneofOptions.d.ts => OneofOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{ServiceDescriptorProto.d.ts => ServiceDescriptorProto.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{ServiceOptions.d.ts => ServiceOptions.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{SourceCodeInfo.d.ts => SourceCodeInfo.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{StringValue.d.ts => StringValue.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Struct.d.ts => Struct.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Timestamp.d.ts => Timestamp.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{UInt32Value.d.ts => UInt32Value.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{UInt64Value.d.ts => UInt64Value.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{UninterpretedOption.d.ts => UninterpretedOption.ts} (100%) rename packages/grpc-js/src/generated/google/protobuf/{Value.d.ts => Value.ts} (100%) rename packages/grpc-js/src/generated/google/rpc/{Status.d.ts => Status.ts} (100%) rename packages/grpc-js/src/generated/{listener.d.ts => listener.ts} (100%) rename packages/grpc-js/src/generated/{route.d.ts => route.ts} (100%) rename packages/grpc-js/src/generated/udpa/annotations/{FieldMigrateAnnotation.d.ts => FieldMigrateAnnotation.ts} (100%) rename packages/grpc-js/src/generated/udpa/annotations/{FileMigrateAnnotation.d.ts => FileMigrateAnnotation.ts} (100%) rename packages/grpc-js/src/generated/udpa/annotations/{MigrateAnnotation.d.ts => MigrateAnnotation.ts} (100%) rename packages/grpc-js/src/generated/udpa/annotations/{PackageVersionStatus.d.ts => PackageVersionStatus.ts} (100%) rename packages/grpc-js/src/generated/udpa/annotations/{StatusAnnotation.d.ts => StatusAnnotation.ts} (100%) rename packages/grpc-js/src/generated/validate/{AnyRules.d.ts => AnyRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{BoolRules.d.ts => BoolRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{BytesRules.d.ts => BytesRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{DoubleRules.d.ts => DoubleRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{DurationRules.d.ts => DurationRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{EnumRules.d.ts => EnumRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{FieldRules.d.ts => FieldRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{Fixed32Rules.d.ts => Fixed32Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{Fixed64Rules.d.ts => Fixed64Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{FloatRules.d.ts => FloatRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{Int32Rules.d.ts => Int32Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{Int64Rules.d.ts => Int64Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{KnownRegex.d.ts => KnownRegex.ts} (100%) rename packages/grpc-js/src/generated/validate/{MapRules.d.ts => MapRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{MessageRules.d.ts => MessageRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{RepeatedRules.d.ts => RepeatedRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{SFixed32Rules.d.ts => SFixed32Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{SFixed64Rules.d.ts => SFixed64Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{SInt32Rules.d.ts => SInt32Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{SInt64Rules.d.ts => SInt64Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{StringRules.d.ts => StringRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{TimestampRules.d.ts => TimestampRules.ts} (100%) rename packages/grpc-js/src/generated/validate/{UInt32Rules.d.ts => UInt32Rules.ts} (100%) rename packages/grpc-js/src/generated/validate/{UInt64Rules.d.ts => UInt64Rules.ts} (100%) diff --git a/packages/grpc-js/src/generated/ads.d.ts b/packages/grpc-js/src/generated/ads.ts similarity index 100% rename from packages/grpc-js/src/generated/ads.d.ts rename to packages/grpc-js/src/generated/ads.ts index fee58a0ed..fd9f8e2c4 100644 --- a/packages/grpc-js/src/generated/ads.d.ts +++ b/packages/grpc-js/src/generated/ads.ts @@ -28,8 +28,6 @@ import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource_ import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; @@ -37,6 +35,8 @@ import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _env import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; @@ -171,10 +171,6 @@ export namespace messages { export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; export type ControlPlane = _envoy_api_v2_core_ControlPlane; export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; export type SocketAddress = _envoy_api_v2_core_SocketAddress; @@ -189,6 +185,10 @@ export namespace messages { export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; export type SocketOption = _envoy_api_v2_core_SocketOption; export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; } } } @@ -415,10 +415,6 @@ export namespace ClientInterfaces { } export namespace ControlPlane { } - export namespace BackoffStrategy { - } - export namespace HttpUri { - } export namespace Pipe { } export namespace SocketAddress { @@ -433,6 +429,10 @@ export namespace ClientInterfaces { } export namespace SocketOption { } + export namespace HttpUri { + } + export namespace BackoffStrategy { + } } } } @@ -639,8 +639,6 @@ export interface ProtoGrpcType { TransportSocket: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition ControlPlane: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition - HttpUri: MessageTypeDefinition Pipe: MessageTypeDefinition SocketAddress: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition @@ -648,6 +646,8 @@ export interface ProtoGrpcType { Address: MessageTypeDefinition CidrRange: MessageTypeDefinition SocketOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition } } } @@ -802,10 +802,6 @@ export namespace ServiceHandlers { } export namespace ControlPlane { } - export namespace BackoffStrategy { - } - export namespace HttpUri { - } export namespace Pipe { } export namespace SocketAddress { @@ -820,6 +816,10 @@ export namespace ServiceHandlers { } export namespace SocketOption { } + export namespace HttpUri { + } + export namespace BackoffStrategy { + } } } } diff --git a/packages/grpc-js/src/generated/cluster.d.ts b/packages/grpc-js/src/generated/cluster.ts similarity index 100% rename from packages/grpc-js/src/generated/cluster.d.ts rename to packages/grpc-js/src/generated/cluster.ts index bb137fbdd..6c45ee4cd 100644 --- a/packages/grpc-js/src/generated/cluster.d.ts +++ b/packages/grpc-js/src/generated/cluster.ts @@ -5,6 +5,9 @@ import { Cluster as _envoy_api_v2_Cluster, Cluster__Output as _envoy_api_v2_Clus import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from './envoy/api/v2/LoadBalancingPolicy'; import { UpstreamBindConfig as _envoy_api_v2_UpstreamBindConfig, UpstreamBindConfig__Output as _envoy_api_v2_UpstreamBindConfig__Output } from './envoy/api/v2/UpstreamBindConfig'; import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from './envoy/api/v2/UpstreamConnectionOptions'; +import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from './envoy/api/v2/cluster/Filter'; +import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from './envoy/api/v2/cluster/CircuitBreakers'; +import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from './envoy/api/v2/cluster/OutlierDetection'; import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; @@ -16,6 +19,26 @@ import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKey import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; +import { TcpProtocolOptions as _envoy_api_v2_core_TcpProtocolOptions, TcpProtocolOptions__Output as _envoy_api_v2_core_TcpProtocolOptions__Output } from './envoy/api/v2/core/TcpProtocolOptions'; +import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from './envoy/api/v2/core/UpstreamHttpProtocolOptions'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from './envoy/api/v2/core/HttpProtocolOptions'; +import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from './envoy/api/v2/core/Http1ProtocolOptions'; +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from './envoy/api/v2/core/Http2ProtocolOptions'; +import { GrpcProtocolOptions as _envoy_api_v2_core_GrpcProtocolOptions, GrpcProtocolOptions__Output as _envoy_api_v2_core_GrpcProtocolOptions__Output } from './envoy/api/v2/core/GrpcProtocolOptions'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; @@ -37,49 +60,26 @@ import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource_ import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { TcpProtocolOptions as _envoy_api_v2_core_TcpProtocolOptions, TcpProtocolOptions__Output as _envoy_api_v2_core_TcpProtocolOptions__Output } from './envoy/api/v2/core/TcpProtocolOptions'; -import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from './envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from './envoy/api/v2/core/HttpProtocolOptions'; -import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from './envoy/api/v2/core/Http1ProtocolOptions'; -import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from './envoy/api/v2/core/Http2ProtocolOptions'; -import { GrpcProtocolOptions as _envoy_api_v2_core_GrpcProtocolOptions, GrpcProtocolOptions__Output as _envoy_api_v2_core_GrpcProtocolOptions__Output } from './envoy/api/v2/core/GrpcProtocolOptions'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from './envoy/api/v2/cluster/CircuitBreakers'; -import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from './envoy/api/v2/cluster/Filter'; -import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from './envoy/api/v2/cluster/OutlierDetection'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; @@ -162,6 +162,14 @@ export namespace messages { export type UpstreamBindConfig__Output = _envoy_api_v2_UpstreamBindConfig__Output; export type UpstreamConnectionOptions = _envoy_api_v2_UpstreamConnectionOptions; export type UpstreamConnectionOptions__Output = _envoy_api_v2_UpstreamConnectionOptions__Output; + export namespace cluster { + export type Filter = _envoy_api_v2_cluster_Filter; + export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; + export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; + export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; + export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; + export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; + } export namespace auth { export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; @@ -187,6 +195,44 @@ export namespace messages { export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; } export namespace core { + export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; + export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; + export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; + export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; + export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; + export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; + export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; + export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; + export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; + export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; + export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; + export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; + export type HealthStatus = _envoy_api_v2_core_HealthStatus; + export type HealthCheck = _envoy_api_v2_core_HealthCheck; + export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; export type RequestMethod = _envoy_api_v2_core_RequestMethod; export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; @@ -226,62 +272,16 @@ export namespace messages { export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; export type ControlPlane = _envoy_api_v2_core_ControlPlane; export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type HealthStatus = _envoy_api_v2_core_HealthStatus; - export type HealthCheck = _envoy_api_v2_core_HealthCheck; - export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - export type Address = _envoy_api_v2_core_Address; - export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; - export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; - export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; - export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; - export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; - export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; - export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; - export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; - export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; - export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; - export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; - export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; - export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; - export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; - export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; - export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; - export type SocketOption = _envoy_api_v2_core_SocketOption; - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; export type GrpcService = _envoy_api_v2_core_GrpcService; export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; - } - export namespace cluster { - export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; - export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; - export type Filter = _envoy_api_v2_cluster_Filter; - export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; - export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; - export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; } export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; @@ -295,19 +295,13 @@ export namespace messages { } } } + export namespace annotations { + } export namespace type { export type Percent = _envoy_type_Percent; export type Percent__Output = _envoy_type_Percent__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - export type SemanticVersion = _envoy_type_SemanticVersion; - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - export type Int64Range = _envoy_type_Int64Range; - export type Int64Range__Output = _envoy_type_Int64Range__Output; - export type Int32Range = _envoy_type_Int32Range; - export type Int32Range__Output = _envoy_type_Int32Range__Output; - export type DoubleRange = _envoy_type_DoubleRange; - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export namespace matcher { export type StringMatcher = _envoy_type_matcher_StringMatcher; export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; @@ -318,9 +312,15 @@ export namespace messages { export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; } + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export type CodecClientType = _envoy_type_CodecClientType; - } - export namespace annotations { + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; } } export namespace udpa { @@ -512,6 +512,18 @@ export namespace ClientInterfaces { } export namespace UpstreamConnectionOptions { } + export namespace cluster { + export namespace Filter { + } + export namespace CircuitBreakers { + export namespace Thresholds { + export namespace RetryBudget { + } + } + } + export namespace OutlierDetection { + } + } export namespace auth { export namespace UpstreamTlsContext { } @@ -539,41 +551,23 @@ export namespace ClientInterfaces { } } export namespace core { - export namespace Locality { - } - export namespace BuildVersion { - } - export namespace Extension { - } - export namespace Node { - } - export namespace Metadata { - } - export namespace RuntimeUInt32 { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HeaderMap { - } - export namespace DataSource { - } - export namespace RetryPolicy { + export namespace TcpProtocolOptions { } - export namespace RemoteDataSource { + export namespace UpstreamHttpProtocolOptions { } - export namespace AsyncDataSource { + export namespace HttpProtocolOptions { } - export namespace TransportSocket { + export namespace Http1ProtocolOptions { + export namespace HeaderKeyFormat { + export namespace ProperCaseWords { + } + } } - export namespace RuntimeFractionalPercent { + export namespace Http2ProtocolOptions { + export namespace SettingsParameter { + } } - export namespace ControlPlane { + export namespace GrpcProtocolOptions { } export namespace HealthCheck { export namespace Payload { @@ -613,29 +607,41 @@ export namespace ClientInterfaces { } export namespace ConfigSource { } - export namespace TcpProtocolOptions { + export namespace Locality { } - export namespace UpstreamHttpProtocolOptions { + export namespace BuildVersion { } - export namespace HttpProtocolOptions { + export namespace Extension { } - export namespace Http1ProtocolOptions { - export namespace HeaderKeyFormat { - export namespace ProperCaseWords { - } - } + export namespace Node { } - export namespace Http2ProtocolOptions { - export namespace SettingsParameter { - } + export namespace Metadata { } - export namespace GrpcProtocolOptions { + export namespace RuntimeUInt32 { } - export namespace SocketOption { + export namespace RuntimeDouble { } - export namespace HttpUri { + export namespace RuntimeFeatureFlag { } - export namespace BackoffStrategy { + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { } export namespace EventServiceConfig { } @@ -661,17 +667,11 @@ export namespace ClientInterfaces { } } } - } - export namespace cluster { - export namespace CircuitBreakers { - export namespace Thresholds { - export namespace RetryBudget { - } - } + export namespace HttpUri { } - export namespace Filter { + export namespace BackoffStrategy { } - export namespace OutlierDetection { + export namespace SocketOption { } } export namespace ClusterLoadAssignment { @@ -692,19 +692,13 @@ export namespace ClientInterfaces { } } } + export namespace annotations { + } export namespace type { export namespace Percent { } export namespace FractionalPercent { } - export namespace SemanticVersion { - } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } export namespace matcher { export namespace StringMatcher { } @@ -717,8 +711,14 @@ export namespace ClientInterfaces { export namespace RegexMatchAndSubstitute { } } - } - export namespace annotations { + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace SemanticVersion { + } } } export namespace udpa { @@ -890,6 +890,11 @@ export interface ProtoGrpcType { LoadBalancingPolicy: MessageTypeDefinition UpstreamBindConfig: MessageTypeDefinition UpstreamConnectionOptions: MessageTypeDefinition + cluster: { + Filter: MessageTypeDefinition + CircuitBreakers: MessageTypeDefinition + OutlierDetection: MessageTypeDefinition + } auth: { UpstreamTlsContext: MessageTypeDefinition DownstreamTlsContext: MessageTypeDefinition @@ -904,6 +909,26 @@ export interface ProtoGrpcType { CertificateValidationContext: MessageTypeDefinition } core: { + TcpProtocolOptions: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + HealthCheck: MessageTypeDefinition + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + ApiConfigSource: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + ConfigSource: MessageTypeDefinition RoutingPriority: EnumTypeDefinition RequestMethod: EnumTypeDefinition TrafficDirection: EnumTypeDefinition @@ -925,36 +950,11 @@ export interface ProtoGrpcType { TransportSocket: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition ControlPlane: MessageTypeDefinition - HealthStatus: EnumTypeDefinition - HealthCheck: MessageTypeDefinition - Pipe: MessageTypeDefinition - SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition - Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition - ApiVersion: EnumTypeDefinition - ApiConfigSource: MessageTypeDefinition - AggregatedConfigSource: MessageTypeDefinition - SelfConfigSource: MessageTypeDefinition - RateLimitSettings: MessageTypeDefinition - ConfigSource: MessageTypeDefinition - TcpProtocolOptions: MessageTypeDefinition - UpstreamHttpProtocolOptions: MessageTypeDefinition - HttpProtocolOptions: MessageTypeDefinition - Http1ProtocolOptions: MessageTypeDefinition - Http2ProtocolOptions: MessageTypeDefinition - GrpcProtocolOptions: MessageTypeDefinition - SocketOption: MessageTypeDefinition - HttpUri: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition EventServiceConfig: MessageTypeDefinition GrpcService: MessageTypeDefinition - } - cluster: { - CircuitBreakers: MessageTypeDefinition - Filter: MessageTypeDefinition - OutlierDetection: MessageTypeDefinition + HttpUri: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + SocketOption: MessageTypeDefinition } ClusterLoadAssignment: MessageTypeDefinition endpoint: { @@ -964,22 +964,22 @@ export interface ProtoGrpcType { } } } + annotations: { + } type: { Percent: MessageTypeDefinition FractionalPercent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Int32Range: MessageTypeDefinition - DoubleRange: MessageTypeDefinition matcher: { StringMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition RegexMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition } + Int64Range: MessageTypeDefinition + Int32Range: MessageTypeDefinition + DoubleRange: MessageTypeDefinition CodecClientType: EnumTypeDefinition - } - annotations: { + SemanticVersion: MessageTypeDefinition } } udpa: { @@ -1105,6 +1105,18 @@ export namespace ServiceHandlers { } export namespace UpstreamConnectionOptions { } + export namespace cluster { + export namespace Filter { + } + export namespace CircuitBreakers { + export namespace Thresholds { + export namespace RetryBudget { + } + } + } + export namespace OutlierDetection { + } + } export namespace auth { export namespace UpstreamTlsContext { } @@ -1132,41 +1144,23 @@ export namespace ServiceHandlers { } } export namespace core { - export namespace Locality { - } - export namespace BuildVersion { - } - export namespace Extension { - } - export namespace Node { - } - export namespace Metadata { - } - export namespace RuntimeUInt32 { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HeaderMap { - } - export namespace DataSource { - } - export namespace RetryPolicy { + export namespace TcpProtocolOptions { } - export namespace RemoteDataSource { + export namespace UpstreamHttpProtocolOptions { } - export namespace AsyncDataSource { + export namespace HttpProtocolOptions { } - export namespace TransportSocket { + export namespace Http1ProtocolOptions { + export namespace HeaderKeyFormat { + export namespace ProperCaseWords { + } + } } - export namespace RuntimeFractionalPercent { + export namespace Http2ProtocolOptions { + export namespace SettingsParameter { + } } - export namespace ControlPlane { + export namespace GrpcProtocolOptions { } export namespace HealthCheck { export namespace Payload { @@ -1206,29 +1200,41 @@ export namespace ServiceHandlers { } export namespace ConfigSource { } - export namespace TcpProtocolOptions { + export namespace Locality { } - export namespace UpstreamHttpProtocolOptions { + export namespace BuildVersion { } - export namespace HttpProtocolOptions { + export namespace Extension { } - export namespace Http1ProtocolOptions { - export namespace HeaderKeyFormat { - export namespace ProperCaseWords { - } - } + export namespace Node { } - export namespace Http2ProtocolOptions { - export namespace SettingsParameter { - } + export namespace Metadata { } - export namespace GrpcProtocolOptions { + export namespace RuntimeUInt32 { } - export namespace SocketOption { + export namespace RuntimeDouble { } - export namespace HttpUri { + export namespace RuntimeFeatureFlag { } - export namespace BackoffStrategy { + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HeaderMap { + } + export namespace DataSource { + } + export namespace RetryPolicy { + } + export namespace RemoteDataSource { + } + export namespace AsyncDataSource { + } + export namespace TransportSocket { + } + export namespace RuntimeFractionalPercent { + } + export namespace ControlPlane { } export namespace EventServiceConfig { } @@ -1254,17 +1260,11 @@ export namespace ServiceHandlers { } } } - } - export namespace cluster { - export namespace CircuitBreakers { - export namespace Thresholds { - export namespace RetryBudget { - } - } + export namespace HttpUri { } - export namespace Filter { + export namespace BackoffStrategy { } - export namespace OutlierDetection { + export namespace SocketOption { } } export namespace ClusterLoadAssignment { @@ -1285,19 +1285,13 @@ export namespace ServiceHandlers { } } } + export namespace annotations { + } export namespace type { export namespace Percent { } export namespace FractionalPercent { } - export namespace SemanticVersion { - } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } export namespace matcher { export namespace StringMatcher { } @@ -1310,8 +1304,14 @@ export namespace ServiceHandlers { export namespace RegexMatchAndSubstitute { } } - } - export namespace annotations { + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { + } + export namespace SemanticVersion { + } } } export namespace udpa { diff --git a/packages/grpc-js/src/generated/endpoint.d.ts b/packages/grpc-js/src/generated/endpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/endpoint.d.ts rename to packages/grpc-js/src/generated/endpoint.ts index e796f717f..b9d7dbeea 100644 --- a/packages/grpc-js/src/generated/endpoint.d.ts +++ b/packages/grpc-js/src/generated/endpoint.ts @@ -5,12 +5,8 @@ import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLo import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; @@ -32,17 +28,21 @@ import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource_ import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; @@ -135,18 +135,9 @@ export namespace messages { export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; } export namespace core { - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - export type Address = _envoy_api_v2_core_Address; - export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type HealthStatus = _envoy_api_v2_core_HealthStatus; + export type HealthCheck = _envoy_api_v2_core_HealthCheck; + export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; export type RequestMethod = _envoy_api_v2_core_RequestMethod; export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; @@ -186,17 +177,26 @@ export namespace messages { export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; export type ControlPlane = _envoy_api_v2_core_ControlPlane; export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type HealthStatus = _envoy_api_v2_core_HealthStatus; - export type HealthCheck = _envoy_api_v2_core_HealthCheck; - export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; - export type SocketOption = _envoy_api_v2_core_SocketOption; - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type GrpcService = _envoy_api_v2_core_GrpcService; export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; } @@ -207,9 +207,9 @@ export namespace messages { export type Percent__Output = _envoy_type_Percent__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type CodecClientType = _envoy_type_CodecClientType; export type SemanticVersion = _envoy_type_SemanticVersion; export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - export type CodecClientType = _envoy_type_CodecClientType; export namespace matcher { export type StringMatcher = _envoy_type_matcher_StringMatcher; export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; @@ -400,17 +400,21 @@ export namespace ClientInterfaces { } } export namespace core { - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { - } - export namespace BindConfig { - } - export namespace Address { - } - export namespace CidrRange { + export namespace HealthCheck { + export namespace Payload { + } + export namespace HttpHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace RedisHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace CustomHealthCheck { + } + export namespace TlsOptions { + } } export namespace Locality { } @@ -448,30 +452,26 @@ export namespace ClientInterfaces { } export namespace ControlPlane { } - export namespace HealthCheck { - export namespace Payload { - } - export namespace HttpHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace RedisHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace CustomHealthCheck { - } - export namespace TlsOptions { - } + export namespace Pipe { } - export namespace SocketOption { + export namespace SocketAddress { } - export namespace HttpUri { + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { } export namespace EventServiceConfig { } export namespace BackoffStrategy { } + export namespace HttpUri { + } + export namespace SocketOption { + } export namespace GrpcService { export namespace EnvoyGrpc { } @@ -698,12 +698,8 @@ export interface ProtoGrpcType { LocalityLbEndpoints: MessageTypeDefinition } core: { - Pipe: MessageTypeDefinition - SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition - Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + HealthCheck: MessageTypeDefinition RoutingPriority: EnumTypeDefinition RequestMethod: EnumTypeDefinition TrafficDirection: EnumTypeDefinition @@ -725,12 +721,16 @@ export interface ProtoGrpcType { TransportSocket: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition ControlPlane: MessageTypeDefinition - HealthStatus: EnumTypeDefinition - HealthCheck: MessageTypeDefinition - SocketOption: MessageTypeDefinition - HttpUri: MessageTypeDefinition + Pipe: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + BindConfig: MessageTypeDefinition + Address: MessageTypeDefinition + CidrRange: MessageTypeDefinition EventServiceConfig: MessageTypeDefinition BackoffStrategy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + SocketOption: MessageTypeDefinition GrpcService: MessageTypeDefinition } } @@ -738,8 +738,8 @@ export interface ProtoGrpcType { type: { Percent: MessageTypeDefinition FractionalPercent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition CodecClientType: EnumTypeDefinition + SemanticVersion: MessageTypeDefinition matcher: { StringMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition @@ -857,17 +857,21 @@ export namespace ServiceHandlers { } } export namespace core { - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { - } - export namespace BindConfig { - } - export namespace Address { - } - export namespace CidrRange { + export namespace HealthCheck { + export namespace Payload { + } + export namespace HttpHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace RedisHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace CustomHealthCheck { + } + export namespace TlsOptions { + } } export namespace Locality { } @@ -905,30 +909,26 @@ export namespace ServiceHandlers { } export namespace ControlPlane { } - export namespace HealthCheck { - export namespace Payload { - } - export namespace HttpHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace RedisHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace CustomHealthCheck { - } - export namespace TlsOptions { - } + export namespace Pipe { } - export namespace SocketOption { + export namespace SocketAddress { } - export namespace HttpUri { + export namespace TcpKeepalive { + } + export namespace BindConfig { + } + export namespace Address { + } + export namespace CidrRange { } export namespace EventServiceConfig { } export namespace BackoffStrategy { } + export namespace HttpUri { + } + export namespace SocketOption { + } export namespace GrpcService { export namespace EnvoyGrpc { } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Cluster.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Listener.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/Listener.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Resource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/Resource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Vhds.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Address.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Address.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Extension.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Locality.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Node.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Route.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.d.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.d.ts rename to packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.d.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.d.ts rename to packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.d.ts b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.d.ts rename to packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.d.ts b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.d.ts rename to packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts diff --git a/packages/grpc-js/src/generated/envoy/type/CodecClientType.d.ts b/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/CodecClientType.d.ts rename to packages/grpc-js/src/generated/envoy/type/CodecClientType.ts diff --git a/packages/grpc-js/src/generated/envoy/type/DoubleRange.d.ts b/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/DoubleRange.d.ts rename to packages/grpc-js/src/generated/envoy/type/DoubleRange.ts diff --git a/packages/grpc-js/src/generated/envoy/type/FractionalPercent.d.ts b/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/FractionalPercent.d.ts rename to packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Int32Range.d.ts b/packages/grpc-js/src/generated/envoy/type/Int32Range.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Int32Range.d.ts rename to packages/grpc-js/src/generated/envoy/type/Int32Range.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Int64Range.d.ts b/packages/grpc-js/src/generated/envoy/type/Int64Range.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Int64Range.d.ts rename to packages/grpc-js/src/generated/envoy/type/Int64Range.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Percent.d.ts b/packages/grpc-js/src/generated/envoy/type/Percent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Percent.d.ts rename to packages/grpc-js/src/generated/envoy/type/Percent.ts diff --git a/packages/grpc-js/src/generated/envoy/type/SemanticVersion.d.ts b/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/SemanticVersion.d.ts rename to packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.d.ts rename to packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.d.ts rename to packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.d.ts rename to packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.d.ts b/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.d.ts rename to packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.d.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.d.ts rename to packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.d.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.d.ts rename to packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.d.ts b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.d.ts rename to packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts diff --git a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.d.ts b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/CustomHttpPattern.d.ts rename to packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts diff --git a/packages/grpc-js/src/generated/google/api/Http.d.ts b/packages/grpc-js/src/generated/google/api/Http.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/Http.d.ts rename to packages/grpc-js/src/generated/google/api/Http.ts diff --git a/packages/grpc-js/src/generated/google/api/HttpRule.d.ts b/packages/grpc-js/src/generated/google/api/HttpRule.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/HttpRule.d.ts rename to packages/grpc-js/src/generated/google/api/HttpRule.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Any.d.ts b/packages/grpc-js/src/generated/google/protobuf/Any.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Any.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Any.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/BoolValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/BoolValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/BoolValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/BoolValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/BytesValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/BytesValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/BytesValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/BytesValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/DescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/DoubleValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/DoubleValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Duration.d.ts b/packages/grpc-js/src/generated/google/protobuf/Duration.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Duration.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Duration.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Empty.d.ts b/packages/grpc-js/src/generated/google/protobuf/Empty.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Empty.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Empty.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FieldOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.d.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.d.ts rename to packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/FileOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FloatValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/FloatValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FloatValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/FloatValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.d.ts b/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.d.ts rename to packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Int32Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/Int32Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Int32Value.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Int32Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Int64Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/Int64Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Int64Value.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Int64Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ListValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/ListValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ListValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/ListValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MessageOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MethodOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/NullValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/NullValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/NullValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/NullValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/OneofOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.d.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.d.ts rename to packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.d.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ServiceOptions.d.ts rename to packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.d.ts b/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.d.ts rename to packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/StringValue.d.ts b/packages/grpc-js/src/generated/google/protobuf/StringValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/StringValue.d.ts rename to packages/grpc-js/src/generated/google/protobuf/StringValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Struct.d.ts b/packages/grpc-js/src/generated/google/protobuf/Struct.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Struct.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Struct.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Timestamp.d.ts b/packages/grpc-js/src/generated/google/protobuf/Timestamp.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Timestamp.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Timestamp.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt32Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UInt32Value.d.ts rename to packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt64Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UInt64Value.d.ts rename to packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.d.ts b/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.d.ts rename to packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Value.d.ts b/packages/grpc-js/src/generated/google/protobuf/Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Value.d.ts rename to packages/grpc-js/src/generated/google/protobuf/Value.ts diff --git a/packages/grpc-js/src/generated/google/rpc/Status.d.ts b/packages/grpc-js/src/generated/google/rpc/Status.ts similarity index 100% rename from packages/grpc-js/src/generated/google/rpc/Status.d.ts rename to packages/grpc-js/src/generated/google/rpc/Status.ts diff --git a/packages/grpc-js/src/generated/listener.d.ts b/packages/grpc-js/src/generated/listener.ts similarity index 100% rename from packages/grpc-js/src/generated/listener.d.ts rename to packages/grpc-js/src/generated/listener.ts index 9d6d8cd6d..ef657d3a3 100644 --- a/packages/grpc-js/src/generated/listener.d.ts +++ b/packages/grpc-js/src/generated/listener.ts @@ -2,6 +2,7 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { Listener as _envoy_api_v2_Listener, Listener__Output as _envoy_api_v2_Listener__Output } from './envoy/api/v2/Listener'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; @@ -29,7 +30,6 @@ import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource_ import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; @@ -39,24 +39,24 @@ import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSour import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from './envoy/api/v2/listener/UdpListenerConfig'; -import { ActiveRawUdpListenerConfig as _envoy_api_v2_listener_ActiveRawUdpListenerConfig, ActiveRawUdpListenerConfig__Output as _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output } from './envoy/api/v2/listener/ActiveRawUdpListenerConfig'; import { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from './envoy/api/v2/listener/Filter'; import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from './envoy/api/v2/listener/FilterChainMatch'; import { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from './envoy/api/v2/listener/FilterChain'; import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from './envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from './envoy/api/v2/listener/ListenerFilter'; +import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from './envoy/api/v2/listener/UdpListenerConfig'; +import { ActiveRawUdpListenerConfig as _envoy_api_v2_listener_ActiveRawUdpListenerConfig, ActiveRawUdpListenerConfig__Output as _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output } from './envoy/api/v2/listener/ActiveRawUdpListenerConfig'; import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; -import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; -import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; +import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; +import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; @@ -74,6 +74,7 @@ import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__O import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; +import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from './envoy/config/listener/v2/ApiListener'; import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from './envoy/config/filter/accesslog/v2/AccessLog'; import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from './envoy/config/filter/accesslog/v2/AccessLogFilter'; import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from './envoy/config/filter/accesslog/v2/ComparisonFilter'; @@ -88,17 +89,16 @@ import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderF import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from './envoy/config/filter/accesslog/v2/ResponseFlagFilter'; import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from './envoy/config/filter/accesslog/v2/GrpcStatusFilter'; import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from './envoy/config/filter/accesslog/v2/ExtensionFilter'; -import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from './envoy/config/listener/v2/ApiListener'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; @@ -146,6 +146,7 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; @@ -166,7 +167,6 @@ import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; @@ -179,6 +179,8 @@ export namespace messages { export type Listener = _envoy_api_v2_Listener; export type Listener__Output = _envoy_api_v2_Listener__Output; export namespace core { + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; export type SocketAddress = _envoy_api_v2_core_SocketAddress; @@ -230,8 +232,6 @@ export namespace messages { export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; export type ControlPlane = _envoy_api_v2_core_ControlPlane; export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type SocketOption = _envoy_api_v2_core_SocketOption; - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type HttpUri = _envoy_api_v2_core_HttpUri; @@ -251,10 +251,6 @@ export namespace messages { export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; } export namespace listener { - export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; - export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; - export type ActiveRawUdpListenerConfig = _envoy_api_v2_listener_ActiveRawUdpListenerConfig; - export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; export type Filter = _envoy_api_v2_listener_Filter; export type Filter__Output = _envoy_api_v2_listener_Filter__Output; export type FilterChainMatch = _envoy_api_v2_listener_FilterChainMatch; @@ -265,6 +261,10 @@ export namespace messages { export type ListenerFilterChainMatchPredicate__Output = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output; export type ListenerFilter = _envoy_api_v2_listener_ListenerFilter; export type ListenerFilter__Output = _envoy_api_v2_listener_ListenerFilter__Output; + export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; + export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; + export type ActiveRawUdpListenerConfig = _envoy_api_v2_listener_ActiveRawUdpListenerConfig; + export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; } export namespace auth { export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; @@ -273,12 +273,6 @@ export namespace messages { export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; - export type GenericSecret = _envoy_api_v2_auth_GenericSecret; - export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; - export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; - export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; - export type Secret = _envoy_api_v2_auth_Secret; - export type Secret__Output = _envoy_api_v2_auth_Secret__Output; export type TlsParameters = _envoy_api_v2_auth_TlsParameters; export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; @@ -289,6 +283,12 @@ export namespace messages { export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + export type GenericSecret = _envoy_api_v2_auth_GenericSecret; + export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; + export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; + export type Secret = _envoy_api_v2_auth_Secret; + export type Secret__Output = _envoy_api_v2_auth_Secret__Output; } export namespace route { export type VirtualHost = _envoy_api_v2_route_VirtualHost; @@ -329,6 +329,12 @@ export namespace messages { } } export namespace config { + export namespace listener { + export namespace v2 { + export type ApiListener = _envoy_config_listener_v2_ApiListener; + export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; + } + } export namespace filter { export namespace accesslog { export namespace v2 { @@ -363,35 +369,29 @@ export namespace messages { } } } - export namespace listener { - export namespace v2 { - export type ApiListener = _envoy_config_listener_v2_ApiListener; - export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; - } - } } export namespace type { export type Percent = _envoy_type_Percent; export type Percent__Output = _envoy_type_Percent__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - export type SemanticVersion = _envoy_type_SemanticVersion; - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export type Int64Range = _envoy_type_Int64Range; export type Int64Range__Output = _envoy_type_Int64Range__Output; export type Int32Range = _envoy_type_Int32Range; export type Int32Range__Output = _envoy_type_Int32Range__Output; export type DoubleRange = _envoy_type_DoubleRange; export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { - export type StringMatcher = _envoy_type_matcher_StringMatcher; - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; export type RegexMatcher = _envoy_type_matcher_RegexMatcher; export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; } export namespace tracing { export namespace v2 { @@ -504,6 +504,8 @@ export namespace messages { export type NullValue = _google_protobuf_NullValue; export type ListValue = _google_protobuf_ListValue; export type ListValue__Output = _google_protobuf_ListValue__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; @@ -544,8 +546,6 @@ export namespace messages { export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; export type Empty = _google_protobuf_Empty; export type Empty__Output = _google_protobuf_Empty__Output; } @@ -573,6 +573,8 @@ export namespace ClientInterfaces { } } export namespace core { + export namespace SocketOption { + } export namespace Pipe { } export namespace SocketAddress { @@ -621,8 +623,6 @@ export namespace ClientInterfaces { } export namespace ControlPlane { } - export namespace SocketOption { - } export namespace BackoffStrategy { } export namespace HttpUri { @@ -661,10 +661,6 @@ export namespace ClientInterfaces { } } export namespace listener { - export namespace UdpListenerConfig { - } - export namespace ActiveRawUdpListenerConfig { - } export namespace Filter { } export namespace FilterChainMatch { @@ -677,6 +673,10 @@ export namespace ClientInterfaces { } export namespace ListenerFilter { } + export namespace UdpListenerConfig { + } + export namespace ActiveRawUdpListenerConfig { + } } export namespace auth { export namespace UpstreamTlsContext { @@ -687,12 +687,6 @@ export namespace ClientInterfaces { export namespace CombinedCertificateValidationContext { } } - export namespace GenericSecret { - } - export namespace SdsSecretConfig { - } - export namespace Secret { - } export namespace TlsParameters { } export namespace PrivateKeyProvider { @@ -703,6 +697,12 @@ export namespace ClientInterfaces { } export namespace CertificateValidationContext { } + export namespace GenericSecret { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } } export namespace route { export namespace VirtualHost { @@ -785,6 +785,12 @@ export namespace ClientInterfaces { } } export namespace config { + export namespace listener { + export namespace v2 { + export namespace ApiListener { + } + } + } export namespace filter { export namespace accesslog { export namespace v2 { @@ -819,37 +825,31 @@ export namespace ClientInterfaces { } } } - export namespace listener { - export namespace v2 { - export namespace ApiListener { - } - } - } } export namespace type { export namespace Percent { } export namespace FractionalPercent { } - export namespace SemanticVersion { - } export namespace Int64Range { } export namespace Int32Range { } export namespace DoubleRange { } + export namespace SemanticVersion { + } export namespace matcher { - export namespace StringMatcher { - } - export namespace ListStringMatcher { - } export namespace RegexMatcher { export namespace GoogleRE2 { } } export namespace RegexMatchAndSubstitute { } + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } } export namespace tracing { export namespace v2 { @@ -977,6 +977,8 @@ export namespace ClientInterfaces { } export namespace ListValue { } + export namespace Timestamp { + } export namespace FileDescriptorSet { } export namespace FileDescriptorProto { @@ -1027,8 +1029,6 @@ export namespace ClientInterfaces { export namespace Annotation { } } - export namespace Timestamp { - } export namespace Empty { } } @@ -1054,6 +1054,7 @@ export interface ProtoGrpcType { v2: { Listener: MessageTypeDefinition core: { + SocketOption: MessageTypeDefinition Pipe: MessageTypeDefinition SocketAddress: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition @@ -1081,7 +1082,6 @@ export interface ProtoGrpcType { TransportSocket: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition ControlPlane: MessageTypeDefinition - SocketOption: MessageTypeDefinition BackoffStrategy: MessageTypeDefinition HttpUri: MessageTypeDefinition ApiVersion: EnumTypeDefinition @@ -1093,26 +1093,26 @@ export interface ProtoGrpcType { GrpcService: MessageTypeDefinition } listener: { - UdpListenerConfig: MessageTypeDefinition - ActiveRawUdpListenerConfig: MessageTypeDefinition Filter: MessageTypeDefinition FilterChainMatch: MessageTypeDefinition FilterChain: MessageTypeDefinition ListenerFilterChainMatchPredicate: MessageTypeDefinition ListenerFilter: MessageTypeDefinition + UdpListenerConfig: MessageTypeDefinition + ActiveRawUdpListenerConfig: MessageTypeDefinition } auth: { UpstreamTlsContext: MessageTypeDefinition DownstreamTlsContext: MessageTypeDefinition CommonTlsContext: MessageTypeDefinition - GenericSecret: MessageTypeDefinition - SdsSecretConfig: MessageTypeDefinition - Secret: MessageTypeDefinition TlsParameters: MessageTypeDefinition PrivateKeyProvider: MessageTypeDefinition TlsCertificate: MessageTypeDefinition TlsSessionTicketKeys: MessageTypeDefinition CertificateValidationContext: MessageTypeDefinition + GenericSecret: MessageTypeDefinition + SdsSecretConfig: MessageTypeDefinition + Secret: MessageTypeDefinition } route: { VirtualHost: MessageTypeDefinition @@ -1136,6 +1136,11 @@ export interface ProtoGrpcType { } } config: { + listener: { + v2: { + ApiListener: MessageTypeDefinition + } + } filter: { accesslog: { v2: { @@ -1156,24 +1161,19 @@ export interface ProtoGrpcType { } } } - listener: { - v2: { - ApiListener: MessageTypeDefinition - } - } } type: { Percent: MessageTypeDefinition FractionalPercent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition Int64Range: MessageTypeDefinition Int32Range: MessageTypeDefinition DoubleRange: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition matcher: { - StringMatcher: MessageTypeDefinition - ListStringMatcher: MessageTypeDefinition RegexMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition } tracing: { v2: { @@ -1242,6 +1242,7 @@ export interface ProtoGrpcType { Value: MessageTypeDefinition NullValue: EnumTypeDefinition ListValue: MessageTypeDefinition + Timestamp: MessageTypeDefinition FileDescriptorSet: MessageTypeDefinition FileDescriptorProto: MessageTypeDefinition DescriptorProto: MessageTypeDefinition @@ -1262,7 +1263,6 @@ export interface ProtoGrpcType { UninterpretedOption: MessageTypeDefinition SourceCodeInfo: MessageTypeDefinition GeneratedCodeInfo: MessageTypeDefinition - Timestamp: MessageTypeDefinition Empty: MessageTypeDefinition } api: { @@ -1286,6 +1286,8 @@ export namespace ServiceHandlers { } } export namespace core { + export namespace SocketOption { + } export namespace Pipe { } export namespace SocketAddress { @@ -1334,8 +1336,6 @@ export namespace ServiceHandlers { } export namespace ControlPlane { } - export namespace SocketOption { - } export namespace BackoffStrategy { } export namespace HttpUri { @@ -1374,10 +1374,6 @@ export namespace ServiceHandlers { } } export namespace listener { - export namespace UdpListenerConfig { - } - export namespace ActiveRawUdpListenerConfig { - } export namespace Filter { } export namespace FilterChainMatch { @@ -1390,6 +1386,10 @@ export namespace ServiceHandlers { } export namespace ListenerFilter { } + export namespace UdpListenerConfig { + } + export namespace ActiveRawUdpListenerConfig { + } } export namespace auth { export namespace UpstreamTlsContext { @@ -1400,12 +1400,6 @@ export namespace ServiceHandlers { export namespace CombinedCertificateValidationContext { } } - export namespace GenericSecret { - } - export namespace SdsSecretConfig { - } - export namespace Secret { - } export namespace TlsParameters { } export namespace PrivateKeyProvider { @@ -1416,6 +1410,12 @@ export namespace ServiceHandlers { } export namespace CertificateValidationContext { } + export namespace GenericSecret { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } } export namespace route { export namespace VirtualHost { @@ -1498,6 +1498,12 @@ export namespace ServiceHandlers { } } export namespace config { + export namespace listener { + export namespace v2 { + export namespace ApiListener { + } + } + } export namespace filter { export namespace accesslog { export namespace v2 { @@ -1532,37 +1538,31 @@ export namespace ServiceHandlers { } } } - export namespace listener { - export namespace v2 { - export namespace ApiListener { - } - } - } } export namespace type { export namespace Percent { } export namespace FractionalPercent { } - export namespace SemanticVersion { - } export namespace Int64Range { } export namespace Int32Range { } export namespace DoubleRange { } + export namespace SemanticVersion { + } export namespace matcher { - export namespace StringMatcher { - } - export namespace ListStringMatcher { - } export namespace RegexMatcher { export namespace GoogleRE2 { } } export namespace RegexMatchAndSubstitute { } + export namespace StringMatcher { + } + export namespace ListStringMatcher { + } } export namespace tracing { export namespace v2 { @@ -1690,6 +1690,8 @@ export namespace ServiceHandlers { } export namespace ListValue { } + export namespace Timestamp { + } export namespace FileDescriptorSet { } export namespace FileDescriptorProto { @@ -1740,8 +1742,6 @@ export namespace ServiceHandlers { export namespace Annotation { } } - export namespace Timestamp { - } export namespace Empty { } } diff --git a/packages/grpc-js/src/generated/route.d.ts b/packages/grpc-js/src/generated/route.ts similarity index 100% rename from packages/grpc-js/src/generated/route.d.ts rename to packages/grpc-js/src/generated/route.ts index d1326917f..b7d34ee2e 100644 --- a/packages/grpc-js/src/generated/route.d.ts +++ b/packages/grpc-js/src/generated/route.ts @@ -31,15 +31,15 @@ import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSour import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; @@ -59,22 +59,22 @@ import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Outp import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; @@ -114,6 +114,7 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; @@ -134,7 +135,6 @@ import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; export namespace messages { @@ -198,10 +198,6 @@ export namespace messages { export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - export type SocketOption = _envoy_api_v2_core_SocketOption; - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; export type SocketAddress = _envoy_api_v2_core_SocketAddress; @@ -214,8 +210,12 @@ export namespace messages { export type Address__Output = _envoy_api_v2_core_Address__Output; export type CidrRange = _envoy_api_v2_core_CidrRange; export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; export type GrpcService = _envoy_api_v2_core_GrpcService; export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; } export namespace route { export type VirtualHost = _envoy_api_v2_route_VirtualHost; @@ -260,12 +260,8 @@ export namespace messages { export type Percent__Output = _envoy_type_Percent__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - export type Int64Range = _envoy_type_Int64Range; - export type Int64Range__Output = _envoy_type_Int64Range__Output; - export type Int32Range = _envoy_type_Int32Range; - export type Int32Range__Output = _envoy_type_Int32Range__Output; - export type DoubleRange = _envoy_type_DoubleRange; - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { export type RegexMatcher = _envoy_type_matcher_RegexMatcher; export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; @@ -276,8 +272,12 @@ export namespace messages { export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; } - export type SemanticVersion = _envoy_type_SemanticVersion; - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export namespace tracing { export namespace v2 { export type CustomTag = _envoy_type_tracing_v2_CustomTag; @@ -298,15 +298,15 @@ export namespace messages { } export namespace udpa { export namespace annotations { + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } } export namespace validate { @@ -389,6 +389,8 @@ export namespace messages { export type NullValue = _google_protobuf_NullValue; export type ListValue = _google_protobuf_ListValue; export type ListValue__Output = _google_protobuf_ListValue__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; @@ -429,8 +431,6 @@ export namespace messages { export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; export type Empty = _google_protobuf_Empty; export type Empty__Output = _google_protobuf_Empty__Output; } @@ -494,10 +494,6 @@ export namespace ClientInterfaces { } export namespace BackoffStrategy { } - export namespace HttpUri { - } - export namespace SocketOption { - } export namespace Pipe { } export namespace SocketAddress { @@ -510,6 +506,8 @@ export namespace ClientInterfaces { } export namespace CidrRange { } + export namespace HttpUri { + } export namespace GrpcService { export namespace EnvoyGrpc { } @@ -532,6 +530,8 @@ export namespace ClientInterfaces { } } } + export namespace SocketOption { + } } export namespace route { export namespace VirtualHost { @@ -618,11 +618,7 @@ export namespace ClientInterfaces { } export namespace FractionalPercent { } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { + export namespace SemanticVersion { } export namespace matcher { export namespace RegexMatcher { @@ -636,7 +632,11 @@ export namespace ClientInterfaces { export namespace ListStringMatcher { } } - export namespace SemanticVersion { + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { } export namespace tracing { export namespace v2 { @@ -676,14 +676,14 @@ export namespace ClientInterfaces { } export namespace udpa { export namespace annotations { + export namespace StatusAnnotation { + } export namespace MigrateAnnotation { } export namespace FieldMigrateAnnotation { } export namespace FileMigrateAnnotation { } - export namespace StatusAnnotation { - } } } export namespace validate { @@ -764,6 +764,8 @@ export namespace ClientInterfaces { } export namespace ListValue { } + export namespace Timestamp { + } export namespace FileDescriptorSet { } export namespace FileDescriptorProto { @@ -814,8 +816,6 @@ export namespace ClientInterfaces { export namespace Annotation { } } - export namespace Timestamp { - } export namespace Empty { } } @@ -862,15 +862,15 @@ export interface ProtoGrpcType { RateLimitSettings: MessageTypeDefinition ConfigSource: MessageTypeDefinition BackoffStrategy: MessageTypeDefinition - HttpUri: MessageTypeDefinition - SocketOption: MessageTypeDefinition Pipe: MessageTypeDefinition SocketAddress: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition BindConfig: MessageTypeDefinition Address: MessageTypeDefinition CidrRange: MessageTypeDefinition + HttpUri: MessageTypeDefinition GrpcService: MessageTypeDefinition + SocketOption: MessageTypeDefinition } route: { VirtualHost: MessageTypeDefinition @@ -896,16 +896,16 @@ export interface ProtoGrpcType { type: { Percent: MessageTypeDefinition FractionalPercent: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Int32Range: MessageTypeDefinition - DoubleRange: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition matcher: { RegexMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition StringMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition } - SemanticVersion: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Int32Range: MessageTypeDefinition + DoubleRange: MessageTypeDefinition tracing: { v2: { CustomTag: MessageTypeDefinition @@ -923,11 +923,11 @@ export interface ProtoGrpcType { } udpa: { annotations: { + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition MigrateAnnotation: MessageTypeDefinition FieldMigrateAnnotation: MessageTypeDefinition FileMigrateAnnotation: MessageTypeDefinition - PackageVersionStatus: EnumTypeDefinition - StatusAnnotation: MessageTypeDefinition } } validate: { @@ -973,6 +973,7 @@ export interface ProtoGrpcType { Value: MessageTypeDefinition NullValue: EnumTypeDefinition ListValue: MessageTypeDefinition + Timestamp: MessageTypeDefinition FileDescriptorSet: MessageTypeDefinition FileDescriptorProto: MessageTypeDefinition DescriptorProto: MessageTypeDefinition @@ -993,7 +994,6 @@ export interface ProtoGrpcType { UninterpretedOption: MessageTypeDefinition SourceCodeInfo: MessageTypeDefinition GeneratedCodeInfo: MessageTypeDefinition - Timestamp: MessageTypeDefinition Empty: MessageTypeDefinition } } @@ -1056,10 +1056,6 @@ export namespace ServiceHandlers { } export namespace BackoffStrategy { } - export namespace HttpUri { - } - export namespace SocketOption { - } export namespace Pipe { } export namespace SocketAddress { @@ -1072,6 +1068,8 @@ export namespace ServiceHandlers { } export namespace CidrRange { } + export namespace HttpUri { + } export namespace GrpcService { export namespace EnvoyGrpc { } @@ -1094,6 +1092,8 @@ export namespace ServiceHandlers { } } } + export namespace SocketOption { + } } export namespace route { export namespace VirtualHost { @@ -1180,11 +1180,7 @@ export namespace ServiceHandlers { } export namespace FractionalPercent { } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { + export namespace SemanticVersion { } export namespace matcher { export namespace RegexMatcher { @@ -1198,7 +1194,11 @@ export namespace ServiceHandlers { export namespace ListStringMatcher { } } - export namespace SemanticVersion { + export namespace Int64Range { + } + export namespace Int32Range { + } + export namespace DoubleRange { } export namespace tracing { export namespace v2 { @@ -1238,14 +1238,14 @@ export namespace ServiceHandlers { } export namespace udpa { export namespace annotations { + export namespace StatusAnnotation { + } export namespace MigrateAnnotation { } export namespace FieldMigrateAnnotation { } export namespace FileMigrateAnnotation { } - export namespace StatusAnnotation { - } } } export namespace validate { @@ -1326,6 +1326,8 @@ export namespace ServiceHandlers { } export namespace ListValue { } + export namespace Timestamp { + } export namespace FileDescriptorSet { } export namespace FileDescriptorProto { @@ -1376,8 +1378,6 @@ export namespace ServiceHandlers { export namespace Annotation { } } - export namespace Timestamp { - } export namespace Empty { } } diff --git a/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.d.ts rename to packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.d.ts rename to packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.d.ts rename to packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.d.ts b/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.d.ts rename to packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.d.ts b/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.d.ts rename to packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts diff --git a/packages/grpc-js/src/generated/validate/AnyRules.d.ts b/packages/grpc-js/src/generated/validate/AnyRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/AnyRules.d.ts rename to packages/grpc-js/src/generated/validate/AnyRules.ts diff --git a/packages/grpc-js/src/generated/validate/BoolRules.d.ts b/packages/grpc-js/src/generated/validate/BoolRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/BoolRules.d.ts rename to packages/grpc-js/src/generated/validate/BoolRules.ts diff --git a/packages/grpc-js/src/generated/validate/BytesRules.d.ts b/packages/grpc-js/src/generated/validate/BytesRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/BytesRules.d.ts rename to packages/grpc-js/src/generated/validate/BytesRules.ts diff --git a/packages/grpc-js/src/generated/validate/DoubleRules.d.ts b/packages/grpc-js/src/generated/validate/DoubleRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/DoubleRules.d.ts rename to packages/grpc-js/src/generated/validate/DoubleRules.ts diff --git a/packages/grpc-js/src/generated/validate/DurationRules.d.ts b/packages/grpc-js/src/generated/validate/DurationRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/DurationRules.d.ts rename to packages/grpc-js/src/generated/validate/DurationRules.ts diff --git a/packages/grpc-js/src/generated/validate/EnumRules.d.ts b/packages/grpc-js/src/generated/validate/EnumRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/EnumRules.d.ts rename to packages/grpc-js/src/generated/validate/EnumRules.ts diff --git a/packages/grpc-js/src/generated/validate/FieldRules.d.ts b/packages/grpc-js/src/generated/validate/FieldRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/FieldRules.d.ts rename to packages/grpc-js/src/generated/validate/FieldRules.ts diff --git a/packages/grpc-js/src/generated/validate/Fixed32Rules.d.ts b/packages/grpc-js/src/generated/validate/Fixed32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Fixed32Rules.d.ts rename to packages/grpc-js/src/generated/validate/Fixed32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/Fixed64Rules.d.ts b/packages/grpc-js/src/generated/validate/Fixed64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Fixed64Rules.d.ts rename to packages/grpc-js/src/generated/validate/Fixed64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/FloatRules.d.ts b/packages/grpc-js/src/generated/validate/FloatRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/FloatRules.d.ts rename to packages/grpc-js/src/generated/validate/FloatRules.ts diff --git a/packages/grpc-js/src/generated/validate/Int32Rules.d.ts b/packages/grpc-js/src/generated/validate/Int32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Int32Rules.d.ts rename to packages/grpc-js/src/generated/validate/Int32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/Int64Rules.d.ts b/packages/grpc-js/src/generated/validate/Int64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Int64Rules.d.ts rename to packages/grpc-js/src/generated/validate/Int64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/KnownRegex.d.ts b/packages/grpc-js/src/generated/validate/KnownRegex.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/KnownRegex.d.ts rename to packages/grpc-js/src/generated/validate/KnownRegex.ts diff --git a/packages/grpc-js/src/generated/validate/MapRules.d.ts b/packages/grpc-js/src/generated/validate/MapRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/MapRules.d.ts rename to packages/grpc-js/src/generated/validate/MapRules.ts diff --git a/packages/grpc-js/src/generated/validate/MessageRules.d.ts b/packages/grpc-js/src/generated/validate/MessageRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/MessageRules.d.ts rename to packages/grpc-js/src/generated/validate/MessageRules.ts diff --git a/packages/grpc-js/src/generated/validate/RepeatedRules.d.ts b/packages/grpc-js/src/generated/validate/RepeatedRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/RepeatedRules.d.ts rename to packages/grpc-js/src/generated/validate/RepeatedRules.ts diff --git a/packages/grpc-js/src/generated/validate/SFixed32Rules.d.ts b/packages/grpc-js/src/generated/validate/SFixed32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SFixed32Rules.d.ts rename to packages/grpc-js/src/generated/validate/SFixed32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SFixed64Rules.d.ts b/packages/grpc-js/src/generated/validate/SFixed64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SFixed64Rules.d.ts rename to packages/grpc-js/src/generated/validate/SFixed64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SInt32Rules.d.ts b/packages/grpc-js/src/generated/validate/SInt32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SInt32Rules.d.ts rename to packages/grpc-js/src/generated/validate/SInt32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SInt64Rules.d.ts b/packages/grpc-js/src/generated/validate/SInt64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SInt64Rules.d.ts rename to packages/grpc-js/src/generated/validate/SInt64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/StringRules.d.ts b/packages/grpc-js/src/generated/validate/StringRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/StringRules.d.ts rename to packages/grpc-js/src/generated/validate/StringRules.ts diff --git a/packages/grpc-js/src/generated/validate/TimestampRules.d.ts b/packages/grpc-js/src/generated/validate/TimestampRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/TimestampRules.d.ts rename to packages/grpc-js/src/generated/validate/TimestampRules.ts diff --git a/packages/grpc-js/src/generated/validate/UInt32Rules.d.ts b/packages/grpc-js/src/generated/validate/UInt32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/UInt32Rules.d.ts rename to packages/grpc-js/src/generated/validate/UInt32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/UInt64Rules.d.ts b/packages/grpc-js/src/generated/validate/UInt64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/UInt64Rules.d.ts rename to packages/grpc-js/src/generated/validate/UInt64Rules.ts From 7b1bd147a67ab76e11cebc6b0dfd74f253feec3b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Jul 2020 15:18:15 -0700 Subject: [PATCH 1143/1899] gts fix --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/xds-bootstrap.ts | 477 +++++++++-------- packages/grpc-js/src/xds-client.ts | 734 ++++++++++++++------------ 3 files changed, 655 insertions(+), 558 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8a20a6842..8831891de 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -52,7 +52,7 @@ "prepare": "npm run compile", "test": "gulp test", "check": "gts check src/**/*.ts", - "fix": "gts fix src/**/*.ts", + "fix": "gts fix src/*.ts", "pretest": "npm run compile", "posttest": "npm run check" }, diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index c8e88a01d..90cded00a 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -1,222 +1,255 @@ -/* - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import * as fs from 'fs'; -import * as adsTypes from './generated/ads'; - -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export interface ChannelCredsConfig { - type: string; - config?: object; -} - -export interface XdsServerConfig { - serverUri: string; - channelCreds: ChannelCredsConfig[]; -} - -export interface BootstrapInfo { - xdsServers: XdsServerConfig[]; - node: adsTypes.messages.envoy.api.v2.core.Node; -} - -function validateChannelCredsConfig(obj: any): ChannelCredsConfig { - if (!('type' in obj)) { - throw new Error('type field missing in xds_servers.channel_creds element'); - } - if (typeof obj.type !== 'string') { - throw new Error(`xds_servers.channel_creds.type field: expected string, got ${typeof obj.type}`); - } - if ('config' in obj) { - if (typeof obj.config !== 'object' || obj.config === null) { - throw new Error('xds_servers.channel_creds config field must be an object if provided'); - } - } - return { - type: obj.type, - config: obj.config - } -} - -function validateXdsServerConfig(obj: any): XdsServerConfig { - if (!('server_uri' in obj)) { - throw new Error('server_uri field missing in xds_servers element'); - } - if (typeof obj.server_uri !== 'string') { - throw new Error(`xds_servers.server_uri field: expected string, got ${typeof obj.server_uri}`); - } - if (!('channel_creds' in obj)) { - throw new Error('channel_creds missing in xds_servers element'); - } - if (!Array.isArray(obj.channel_creds)) { - throw new Error(`xds_servers.channel_creds field: expected array, got ${typeof obj.channel_creds}`); - } - if (obj.channel_creds.length === 0) { - throw new Error('xds_servers.channel_creds field: at least one entry is required'); - } - return { - serverUri: obj.server_uri, - channelCreds: obj.channel_creds.map(validateChannelCredsConfig) - }; -} - -function validateValue(obj: any): adsTypes.messages.google.protobuf.Value { - if (Array.isArray(obj)) { - return { - kind: 'listValue', - listValue: { - values: obj.map(value => validateValue(value)) - } - } - } else { - switch (typeof obj) { - case 'boolean': - return { - kind: 'boolValue', - boolValue: obj - }; - case 'number': - return { - kind: 'numberValue', - numberValue: obj - }; - case 'string': - return { - kind: 'stringValue', - stringValue: obj - }; - case 'object': - if (obj === null) { - return { - kind: 'nullValue', - nullValue: 'NULL_VALUE' - }; - } else { - return { - kind: 'structValue', - structValue: getStructFromJson(obj) - }; - } - default: - throw new Error(`Could not handle struct value of type ${typeof obj}`); - } - } -} - -function getStructFromJson(obj: any): adsTypes.messages.google.protobuf.Struct { - if (typeof obj !== 'object' || obj === null) { - throw new Error('Invalid JSON object for Struct field'); - } - const result = Object.keys(obj).map(key => validateValue(key)); - if (result.length === 1) { - return { - fields: result[0] - } - } else { - return { - fields: { - kind: 'listValue', - listValue: { - values: result - } - } - } - }; -} - -/** - * Validate that the input obj is a valid Node proto message. Only checks the - * fields we expect to see: id, cluster, locality, and metadata. - * @param obj - */ -function validateNode(obj: any): adsTypes.messages.envoy.api.v2.core.Node { - const result: adsTypes.messages.envoy.api.v2.core.Node = {}; - if (!('id' in obj)) { - throw new Error('id field missing in node element'); - } - if (typeof obj.id !== 'string') { - throw new Error(`node.id field: expected string, got ${typeof obj.id}`); - } - result.id = obj.id; - if (!('cluster' in obj)) { - throw new Error('cluster field missing in node element'); - } - if (typeof obj.cluster !== 'string') { - throw new Error(`node.cluster field: expected string, got ${typeof obj.cluster}`); - } - result.cluster = obj.cluster; - if (!('locality' in obj)) { - throw new Error('locality field missing in node element'); - } - result.locality = {}; - if ('region' in obj.locality) { - if (typeof obj.locality.region !== 'string') { - throw new Error(`node.locality.region field: expected string, got ${typeof obj.locality.region}`); - } - result.locality.region = obj.locality.region; - } - if ('zone' in obj.locality) { - if (typeof obj.locality.region !== 'string') { - throw new Error(`node.locality.zone field: expected string, got ${typeof obj.locality.zone}`); - } - result.locality.zone = obj.locality.zone; - } - if ('sub_zone' in obj.locality) { - if (typeof obj.locality.sub_zone !== 'string') { - throw new Error(`node.locality.sub_zone field: expected string, got ${typeof obj.locality.sub_zone}`); - } - result.locality.sub_zone = obj.locality.sub_zone; - } - if ('metadata' in obj) { - result.metadata = getStructFromJson(obj.metadata); - } - return result; -} - -function validateBootstrapFile(obj: any): BootstrapInfo { - return { - xdsServers: obj.xds_servers.map(validateXdsServerConfig), - node: validateNode(obj.node) - } -} - -let loadedBootstrapInfo: Promise | null = null; - -export async function loadBootstrapInfo(): Promise { - if (loadedBootstrapInfo !== null) { - return loadedBootstrapInfo; - } - const bootstrapPath = process.env.GRPC_XDS_BOOTSTRAP; - if (bootstrapPath === undefined) { - return Promise.reject(new Error('The GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS')); - } - loadedBootstrapInfo = new Promise((resolve, reject) => { - fs.readFile(bootstrapPath, { encoding: 'utf8'}, (err, data) => { - if (err) { - reject(new Error(`Failed to read xDS bootstrap file from path ${bootstrapPath} with error ${err.message}`)); - } - try { - const parsedFile = JSON.parse(data); - resolve(validateBootstrapFile(parsedFile)); - } catch (e) { - reject(new Error(`Failed to parse xDS bootstrap file at path ${bootstrapPath} with error ${e.message}`)); - } - }); - }); - return loadedBootstrapInfo; -} \ No newline at end of file +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; +import * as adsTypes from './generated/ads'; + +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export interface ChannelCredsConfig { + type: string; + config?: object; +} + +export interface XdsServerConfig { + serverUri: string; + channelCreds: ChannelCredsConfig[]; +} + +export interface BootstrapInfo { + xdsServers: XdsServerConfig[]; + node: adsTypes.messages.envoy.api.v2.core.Node; +} + +function validateChannelCredsConfig(obj: any): ChannelCredsConfig { + if (!('type' in obj)) { + throw new Error('type field missing in xds_servers.channel_creds element'); + } + if (typeof obj.type !== 'string') { + throw new Error( + `xds_servers.channel_creds.type field: expected string, got ${typeof obj.type}` + ); + } + if ('config' in obj) { + if (typeof obj.config !== 'object' || obj.config === null) { + throw new Error( + 'xds_servers.channel_creds config field must be an object if provided' + ); + } + } + return { + type: obj.type, + config: obj.config, + }; +} + +function validateXdsServerConfig(obj: any): XdsServerConfig { + if (!('server_uri' in obj)) { + throw new Error('server_uri field missing in xds_servers element'); + } + if (typeof obj.server_uri !== 'string') { + throw new Error( + `xds_servers.server_uri field: expected string, got ${typeof obj.server_uri}` + ); + } + if (!('channel_creds' in obj)) { + throw new Error('channel_creds missing in xds_servers element'); + } + if (!Array.isArray(obj.channel_creds)) { + throw new Error( + `xds_servers.channel_creds field: expected array, got ${typeof obj.channel_creds}` + ); + } + if (obj.channel_creds.length === 0) { + throw new Error( + 'xds_servers.channel_creds field: at least one entry is required' + ); + } + return { + serverUri: obj.server_uri, + channelCreds: obj.channel_creds.map(validateChannelCredsConfig), + }; +} + +function validateValue(obj: any): adsTypes.messages.google.protobuf.Value { + if (Array.isArray(obj)) { + return { + kind: 'listValue', + listValue: { + values: obj.map((value) => validateValue(value)), + }, + }; + } else { + switch (typeof obj) { + case 'boolean': + return { + kind: 'boolValue', + boolValue: obj, + }; + case 'number': + return { + kind: 'numberValue', + numberValue: obj, + }; + case 'string': + return { + kind: 'stringValue', + stringValue: obj, + }; + case 'object': + if (obj === null) { + return { + kind: 'nullValue', + nullValue: 'NULL_VALUE', + }; + } else { + return { + kind: 'structValue', + structValue: getStructFromJson(obj), + }; + } + default: + throw new Error(`Could not handle struct value of type ${typeof obj}`); + } + } +} + +function getStructFromJson(obj: any): adsTypes.messages.google.protobuf.Struct { + if (typeof obj !== 'object' || obj === null) { + throw new Error('Invalid JSON object for Struct field'); + } + const result = Object.keys(obj).map((key) => validateValue(key)); + if (result.length === 1) { + return { + fields: result[0], + }; + } else { + return { + fields: { + kind: 'listValue', + listValue: { + values: result, + }, + }, + }; + } +} + +/** + * Validate that the input obj is a valid Node proto message. Only checks the + * fields we expect to see: id, cluster, locality, and metadata. + * @param obj + */ +function validateNode(obj: any): adsTypes.messages.envoy.api.v2.core.Node { + const result: adsTypes.messages.envoy.api.v2.core.Node = {}; + if (!('id' in obj)) { + throw new Error('id field missing in node element'); + } + if (typeof obj.id !== 'string') { + throw new Error(`node.id field: expected string, got ${typeof obj.id}`); + } + result.id = obj.id; + if (!('cluster' in obj)) { + throw new Error('cluster field missing in node element'); + } + if (typeof obj.cluster !== 'string') { + throw new Error( + `node.cluster field: expected string, got ${typeof obj.cluster}` + ); + } + result.cluster = obj.cluster; + if (!('locality' in obj)) { + throw new Error('locality field missing in node element'); + } + result.locality = {}; + if ('region' in obj.locality) { + if (typeof obj.locality.region !== 'string') { + throw new Error( + `node.locality.region field: expected string, got ${typeof obj.locality + .region}` + ); + } + result.locality.region = obj.locality.region; + } + if ('zone' in obj.locality) { + if (typeof obj.locality.region !== 'string') { + throw new Error( + `node.locality.zone field: expected string, got ${typeof obj.locality + .zone}` + ); + } + result.locality.zone = obj.locality.zone; + } + if ('sub_zone' in obj.locality) { + if (typeof obj.locality.sub_zone !== 'string') { + throw new Error( + `node.locality.sub_zone field: expected string, got ${typeof obj + .locality.sub_zone}` + ); + } + result.locality.sub_zone = obj.locality.sub_zone; + } + if ('metadata' in obj) { + result.metadata = getStructFromJson(obj.metadata); + } + return result; +} + +function validateBootstrapFile(obj: any): BootstrapInfo { + return { + xdsServers: obj.xds_servers.map(validateXdsServerConfig), + node: validateNode(obj.node), + }; +} + +let loadedBootstrapInfo: Promise | null = null; + +export async function loadBootstrapInfo(): Promise { + if (loadedBootstrapInfo !== null) { + return loadedBootstrapInfo; + } + const bootstrapPath = process.env.GRPC_XDS_BOOTSTRAP; + if (bootstrapPath === undefined) { + return Promise.reject( + new Error( + 'The GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS' + ) + ); + } + loadedBootstrapInfo = new Promise((resolve, reject) => { + fs.readFile(bootstrapPath, { encoding: 'utf8' }, (err, data) => { + if (err) { + reject( + new Error( + `Failed to read xDS bootstrap file from path ${bootstrapPath} with error ${err.message}` + ) + ); + } + try { + const parsedFile = JSON.parse(data); + resolve(validateBootstrapFile(parsedFile)); + } catch (e) { + reject( + new Error( + `Failed to parse xDS bootstrap file at path ${bootstrapPath} with error ${e.message}` + ) + ); + } + }); + }); + return loadedBootstrapInfo; +} diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 050762141..732858a3a 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1,335 +1,399 @@ -/* - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import * as protoLoader from '@grpc/proto-loader'; -import { loadPackageDefinition } from './make-client'; -import * as adsTypes from './generated/ads'; -import * as edsTypes from './generated/endpoint'; -import { createGoogleDefaultCredentials } from './channel-credentials'; -import { loadBootstrapInfo } from './xds-bootstrap'; -import { ClientDuplexStream, ServiceError } from './call'; -import { StatusObject } from './call-stream'; -import { isIPv4, isIPv6 } from 'net'; -import { Status, LogVerbosity } from './constants'; -import { Metadata } from './metadata'; -import * as logging from './logging'; -import { ServiceConfig } from './service-config'; -import { ChannelOptions } from './channel-options'; - -const TRACER_NAME = 'xds_client'; - -function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); -} - -const clientVersion = require('../../package.json').version; - -const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; - -let loadedProtos: Promise | null = null; - -function loadAdsProtos(): Promise { - if (loadedProtos !== null) { - return loadedProtos; - } - loadedProtos = protoLoader.load([ - 'envoy/service/discovery/v2/ads.proto', - 'envoy/api/v2/listener.proto', - 'envoy/api/v2/route.proto', - 'envoy/api/v2/cluster.proto', - 'envoy/api/v2/endpoint.proto' - ], { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true, - includeDirs: [ - 'deps/envoy-api/', - 'deps/udpa/', - 'node_modules/protobufjs/', - 'deps/googleapis/', - 'deps/protoc-gen-validate/' - ] - }).then(packageDefinition => loadPackageDefinition(packageDefinition) as unknown as adsTypes.ProtoGrpcType); - return loadedProtos; -} - -export interface Watcher { - onValidUpdate(update: UpdateType): void; - onTransientError(error: StatusObject): void; - onResourceDoesNotExist(): void; -} - -export class XdsClient { - private node: adsTypes.messages.envoy.api.v2.core.Node | null = null; - private client: adsTypes.ClientInterfaces.envoy.service.discovery.v2.AggregatedDiscoveryServiceClient | null = null; - private adsCall: ClientDuplexStream | null = null; - - private hasShutdown: boolean = false; - - private endpointWatchers: Map[]> = new Map[]>(); - private lastEdsVersionInfo: string = ''; - private lastEdsNonce: string = ''; - - constructor(private targetName: string, private serviceConfigWatcher: Watcher, channelOptions: ChannelOptions) { - const channelArgs = {...channelOptions}; - const channelArgsToRemove = [ - /* The SSL target name override corresponds to the target, and this - * client has its own target */ - 'grpc.ssl_target_name_override', - /* The default authority also corresponds to the target */ - 'grpc.default_authority', - /* This client will have its own specific keepalive time setting */ - 'grpc.keepalive_time_ms', - /* The service config specifies the load balancing policy. This channel - * needs its own separate load balancing policy setting. In particular, - * recursively using an xDS load balancer for the xDS client would be - * bad */ - 'grpc.service_config' - ]; - for (const arg of channelArgsToRemove) { - delete channelArgs[arg]; - } - channelArgs['grpc.keepalive_time_ms'] = 5000; - Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then(([bootstrapInfo, protoDefinitions]) => { - if (this.hasShutdown) { - return; - } - this.node = { - ...bootstrapInfo.node, - build_version: `gRPC Node Pure JS ${clientVersion}`, - user_agent_name: 'gRPC Node Pure JS' - } - this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService(bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), channelArgs); - this.maybeStartAdsStream(); - }, (error) => { - trace('Failed to initialize xDS Client. ' + error.message); - // Bubble this error up to any listeners - this.reportStreamError({ - code: Status.INTERNAL, - details: `Failed to initialize xDS Client. ${error.message}`, - metadata: new Metadata() - }); - }); - } - - /** - * Start the ADS stream if the client exists and there is not already an - * existing stream, and there - */ - private maybeStartAdsStream() { - if (this.client === null) { - return; - } - if (this.adsCall !== null) { - return; - } - if (this.hasShutdown) { - return; - } - this.adsCall = this.client.StreamAggregatedResources(); - this.adsCall.on('data', (message: adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output) => { - switch (message.type_url) { - case EDS_TYPE_URL: - const edsResponses: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output[] = []; - for (const resource of message.resources) { - if (protoLoader.isAnyExtension(resource) && resource['@type'] === EDS_TYPE_URL) { - const resp = resource as protoLoader.AnyExtension & edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output; - if (!this.validateEdsResponse(resp)) { - this.nackEds('ClusterLoadAssignment validation failed'); - return; - } - edsResponses.push(resp); - } else { - this.nackEds(`Invalid resource type ${protoLoader.isAnyExtension(resource) ? resource['@type'] : resource.type_url}`); - return; - } - } - for (const message of edsResponses) { - this.handleEdsResponse(message); - } - this.lastEdsVersionInfo = message.version_info; - this.lastEdsNonce = message.nonce; - this.ackEds(); - break; - default: - this.nackUnknown(message.type_url, message.version_info, message.nonce); - } - }); - this.adsCall.on('error', (error: ServiceError) => { - trace('ADS stream ended. code=' + error.code + ' details= ' + error.details); - this.adsCall = null; - this.reportStreamError(error); - /* Connection backoff is handled by the client object, so we can - * immediately start a new request to indicate that it should try to - * reconnect */ - this.maybeStartAdsStream(); - }); - const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); - if (endpointWatcherNames.length > 0) { - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: endpointWatcherNames - }); - } - } - - private nackUnknown(typeUrl: string, versionInfo: string, nonce: string) { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: typeUrl, - version_info: versionInfo, - response_nonce: nonce, - error_detail: { - message: `Unknown type_url ${typeUrl}` - } - }); - } - - /** - * Acknowledge an EDS update. This should be called after the local nonce and - * version info are updated so that it sends the post-update values. - */ - private ackEds() { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo - }); - } - - /** - * Reject an EDS update. This should be called without updating the local - * nonce and version info. - */ - private nackEds(message: string) { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - error_detail: { - message - } - }); - } - - /** - * Validate the ClusterLoadAssignment object by these rules: - * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto - * @param message - */ - private validateEdsResponse(message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output): boolean { - for (const endpoint of message.endpoints) { - for (const lb of endpoint.lb_endpoints) { - const socketAddress = lb.endpoint?.address?.socket_address; - if (!socketAddress) { - return false; - } - if (socketAddress.port_specifier !== 'port_value') { - return false; - } - if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { - return false; - } - } - } - return true; - } - - private handleEdsResponse(message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output) { - const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); - } - } - - private updateEdsNames() { - if (this.adsCall) { - this.adsCall.write({ - node: this.node!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo - }); - } - } - - private reportStreamError(status: StatusObject) { - for (const watcherList of this.endpointWatchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - // Also do the same for other types of watchers when those are implemented - } - - addEndpointWatcher(edsServiceName: string, watcher: Watcher) { - trace('Watcher added for endpoint ' + edsServiceName); - let watchersEntry = this.endpointWatchers.get(edsServiceName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.endpointWatchers.set(edsServiceName, watchersEntry); - } - watchersEntry.push(watcher); - if (addedServiceName) { - this.updateEdsNames(); - } - } - - removeEndpointWatcher(edsServiceName: string, watcher: Watcher) { - trace('Watcher removed for endpoint ' + edsServiceName); - const watchersEntry = this.endpointWatchers.get(edsServiceName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.endpointWatchers.delete(edsServiceName); - } - } - if (removedServiceName) { - this.updateEdsNames(); - } - } - - shutdown(): void { - this.adsCall?.cancel(); - this.client?.close(); - this.hasShutdown = true; - } -} \ No newline at end of file +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as protoLoader from '@grpc/proto-loader'; +import { loadPackageDefinition } from './make-client'; +import * as adsTypes from './generated/ads'; +import * as edsTypes from './generated/endpoint'; +import { createGoogleDefaultCredentials } from './channel-credentials'; +import { loadBootstrapInfo } from './xds-bootstrap'; +import { ClientDuplexStream, ServiceError } from './call'; +import { StatusObject } from './call-stream'; +import { isIPv4, isIPv6 } from 'net'; +import { Status, LogVerbosity } from './constants'; +import { Metadata } from './metadata'; +import * as logging from './logging'; +import { ServiceConfig } from './service-config'; +import { ChannelOptions } from './channel-options'; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + +const clientVersion = require('../../package.json').version; + +const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; + +let loadedProtos: Promise | null = null; + +function loadAdsProtos(): Promise { + if (loadedProtos !== null) { + return loadedProtos; + } + loadedProtos = protoLoader + .load( + [ + 'envoy/service/discovery/v2/ads.proto', + 'envoy/api/v2/listener.proto', + 'envoy/api/v2/route.proto', + 'envoy/api/v2/cluster.proto', + 'envoy/api/v2/endpoint.proto', + ], + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/', + ], + } + ) + .then( + (packageDefinition) => + (loadPackageDefinition( + packageDefinition + ) as unknown) as adsTypes.ProtoGrpcType + ); + return loadedProtos; +} + +export interface Watcher { + onValidUpdate(update: UpdateType): void; + onTransientError(error: StatusObject): void; + onResourceDoesNotExist(): void; +} + +export class XdsClient { + private node: adsTypes.messages.envoy.api.v2.core.Node | null = null; + private client: adsTypes.ClientInterfaces.envoy.service.discovery.v2.AggregatedDiscoveryServiceClient | null = null; + private adsCall: ClientDuplexStream< + adsTypes.messages.envoy.api.v2.DiscoveryRequest, + adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output + > | null = null; + + private hasShutdown = false; + + private endpointWatchers: Map< + string, + Watcher[] + > = new Map< + string, + Watcher[] + >(); + private lastEdsVersionInfo = ''; + private lastEdsNonce = ''; + + constructor( + private targetName: string, + private serviceConfigWatcher: Watcher, + channelOptions: ChannelOptions + ) { + const channelArgs = { ...channelOptions }; + const channelArgsToRemove = [ + /* The SSL target name override corresponds to the target, and this + * client has its own target */ + 'grpc.ssl_target_name_override', + /* The default authority also corresponds to the target */ + 'grpc.default_authority', + /* This client will have its own specific keepalive time setting */ + 'grpc.keepalive_time_ms', + /* The service config specifies the load balancing policy. This channel + * needs its own separate load balancing policy setting. In particular, + * recursively using an xDS load balancer for the xDS client would be + * bad */ + 'grpc.service_config', + ]; + for (const arg of channelArgsToRemove) { + delete channelArgs[arg]; + } + channelArgs['grpc.keepalive_time_ms'] = 5000; + Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( + ([bootstrapInfo, protoDefinitions]) => { + if (this.hasShutdown) { + return; + } + this.node = { + ...bootstrapInfo.node, + build_version: `gRPC Node Pure JS ${clientVersion}`, + user_agent_name: 'gRPC Node Pure JS', + }; + this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( + bootstrapInfo.xdsServers[0].serverUri, + createGoogleDefaultCredentials(), + channelArgs + ); + this.maybeStartAdsStream(); + }, + (error) => { + trace('Failed to initialize xDS Client. ' + error.message); + // Bubble this error up to any listeners + this.reportStreamError({ + code: Status.INTERNAL, + details: `Failed to initialize xDS Client. ${error.message}`, + metadata: new Metadata(), + }); + } + ); + } + + /** + * Start the ADS stream if the client exists and there is not already an + * existing stream, and there + */ + private maybeStartAdsStream() { + if (this.client === null) { + return; + } + if (this.adsCall !== null) { + return; + } + if (this.hasShutdown) { + return; + } + this.adsCall = this.client.StreamAggregatedResources(); + this.adsCall.on( + 'data', + (message: adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output) => { + switch (message.type_url) { + case EDS_TYPE_URL: { + const edsResponses: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output[] = []; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === EDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & + edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output; + if (!this.validateEdsResponse(resp)) { + this.nackEds('ClusterLoadAssignment validation failed'); + return; + } + edsResponses.push(resp); + } else { + this.nackEds( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); + return; + } + } + for (const message of edsResponses) { + this.handleEdsResponse(message); + } + this.lastEdsVersionInfo = message.version_info; + this.lastEdsNonce = message.nonce; + this.ackEds(); + break; + } + default: + this.nackUnknown( + message.type_url, + message.version_info, + message.nonce + ); + } + } + ); + this.adsCall.on('error', (error: ServiceError) => { + trace( + 'ADS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.adsCall = null; + this.reportStreamError(error); + /* Connection backoff is handled by the client object, so we can + * immediately start a new request to indicate that it should try to + * reconnect */ + this.maybeStartAdsStream(); + }); + const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); + if (endpointWatcherNames.length > 0) { + this.adsCall.write({ + node: this.node!, + type_url: EDS_TYPE_URL, + resource_names: endpointWatcherNames, + }); + } + } + + private nackUnknown(typeUrl: string, versionInfo: string, nonce: string) { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node!, + type_url: typeUrl, + version_info: versionInfo, + response_nonce: nonce, + error_detail: { + message: `Unknown type_url ${typeUrl}`, + }, + }); + } + + /** + * Acknowledge an EDS update. This should be called after the local nonce and + * version info are updated so that it sends the post-update values. + */ + private ackEds() { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node!, + type_url: EDS_TYPE_URL, + resource_names: Array.from(this.endpointWatchers.keys()), + response_nonce: this.lastEdsNonce, + version_info: this.lastEdsVersionInfo, + }); + } + + /** + * Reject an EDS update. This should be called without updating the local + * nonce and version info. + */ + private nackEds(message: string) { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node!, + type_url: EDS_TYPE_URL, + resource_names: Array.from(this.endpointWatchers.keys()), + response_nonce: this.lastEdsNonce, + version_info: this.lastEdsVersionInfo, + error_detail: { + message, + }, + }); + } + + /** + * Validate the ClusterLoadAssignment object by these rules: + * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto + * @param message + */ + private validateEdsResponse( + message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + ): boolean { + for (const endpoint of message.endpoints) { + for (const lb of endpoint.lb_endpoints) { + const socketAddress = lb.endpoint?.address?.socket_address; + if (!socketAddress) { + return false; + } + if (socketAddress.port_specifier !== 'port_value') { + return false; + } + if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { + return false; + } + } + } + return true; + } + + private handleEdsResponse( + message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + ) { + const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + + private updateEdsNames() { + if (this.adsCall) { + this.adsCall.write({ + node: this.node!, + type_url: EDS_TYPE_URL, + resource_names: Array.from(this.endpointWatchers.keys()), + response_nonce: this.lastEdsNonce, + version_info: this.lastEdsVersionInfo, + }); + } + } + + private reportStreamError(status: StatusObject) { + for (const watcherList of this.endpointWatchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + // Also do the same for other types of watchers when those are implemented + } + + addEndpointWatcher( + edsServiceName: string, + watcher: Watcher< + edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + > + ) { + trace('Watcher added for endpoint ' + edsServiceName); + let watchersEntry = this.endpointWatchers.get(edsServiceName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.endpointWatchers.set(edsServiceName, watchersEntry); + } + watchersEntry.push(watcher); + if (addedServiceName) { + this.updateEdsNames(); + } + } + + removeEndpointWatcher( + edsServiceName: string, + watcher: Watcher< + edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + > + ) { + trace('Watcher removed for endpoint ' + edsServiceName); + const watchersEntry = this.endpointWatchers.get(edsServiceName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.endpointWatchers.delete(edsServiceName); + } + } + if (removedServiceName) { + this.updateEdsNames(); + } + } + + shutdown(): void { + this.adsCall?.cancel(); + this.client?.close(); + this.hasShutdown = true; + } +} From 7cf93591ca278b6cad78d9133fa650480c8ccd60 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Jul 2020 09:57:00 -0700 Subject: [PATCH 1144/1899] grpc-js: Remove peerDependency on google-auth-library --- packages/grpc-js/package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index da8e28ae5..8a60a6471 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -59,9 +59,6 @@ "dependencies": { "semver": "^6.2.0" }, - "peerDependencies": { - "google-auth-library": "5.x || 6.x" - }, "files": [ "src/*.ts", "build/src/*.{js,d.ts,js.map}", From 930d40916554dd01f6125eb6e759e3370dc981a2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 08:41:58 -0700 Subject: [PATCH 1145/1899] Fix include paths for loading protos --- packages/grpc-js/src/xds-client.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 732858a3a..80d19e0ea 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -62,11 +62,12 @@ function loadAdsProtos(): Promise { defaults: true, oneofs: true, includeDirs: [ - 'deps/envoy-api/', - 'deps/udpa/', - 'node_modules/protobufjs/', - 'deps/googleapis/', - 'deps/protoc-gen-validate/', + // Paths are relative to src/build + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/udpa/', + __dirname + '/../../node_modules/protobufjs/', + __dirname + '/../../deps/googleapis/', + __dirname + '/../../deps/protoc-gen-validate/', ], } ) From e03118d8cba177e476ef68393d6f648e93e48ec1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 08:46:03 -0700 Subject: [PATCH 1146/1899] Generate .ts files instead of .d.ts for better handling by tsc --- packages/proto-loader/bin/proto-loader-gen-types.ts | 4 ++-- packages/proto-loader/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index fd81e5db8..551281de0 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -72,7 +72,7 @@ function getImportPath(to: Protobuf.Type | Protobuf.Enum) { } function getPath(to: Protobuf.Type | Protobuf.Enum) { - return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.d.ts'; + return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.ts'; } function getRelativeImportPath(from: Protobuf.Type, to: Protobuf.Type | Protobuf.Enum) { @@ -600,7 +600,7 @@ async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { } const loadedRoot = await root.load(filename, options); root.resolveAll(); - writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.d.ts'), options); + writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.ts'), options); } } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 0d7512159..c7036bb2a 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre6", + "version": "0.6.0-pre7", "author": "Google Inc.", "contributors": [ { From cee9a455a6f2b4dfab02e55d86a3ec0dc595488a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 09:04:52 -0700 Subject: [PATCH 1147/1899] Load google/protobuf/* into common using require --- packages/proto-loader/package.json | 2 +- packages/proto-loader/src/index.ts | 44 +++++++++++-------- .../proto-loader/test_protos/well_known.proto | 4 ++ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 022eb41c3..cba96b43e 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.4", + "version": "0.5.5", "author": "Google Inc.", "contributors": [ { diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index b29e26f33..ffef89d30 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -369,23 +369,29 @@ export function loadSync( } // Load Google's well-known proto files that aren't exposed by Protobuf.js. -{ - // Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, - // and wrappers. compiler/plugin is excluded in Protobuf.js and here. - const wellKnownProtos = ['api', 'descriptor', 'source_context', 'type']; - const sourceDir = path.join( - path.dirname(require.resolve('protobufjs')), - 'google', - 'protobuf' - ); - - for (const proto of wellKnownProtos) { - const file = path.join(sourceDir, `${proto}.proto`); - const descriptor = Protobuf.loadSync(file).toJSON(); - Protobuf.common( - proto, - (descriptor.nested!.google as Protobuf.INamespace).nested! - ); - } -} +// Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, +// and wrappers. compiler/plugin is excluded in Protobuf.js and here. + +// Using constant strings for compatibility with tools like Webpack +const apiDescriptor = require('protobufjs/google/protobuf/api.json'); +const descriptorDescriptor = require('protobufjs/google/protobuf/descriptor.json'); +const sourceContextDescriptor = require('protobufjs/google/protobuf/source_context.json'); +const typeDescriptor = require('protobufjs/google/protobuf/type.json'); + +Protobuf.common( + 'api', + apiDescriptor.nested.google.nested.protobuf.nested +); +Protobuf.common( + 'descriptor', + descriptorDescriptor.nested.google.nested.protobuf.nested +); +Protobuf.common( + 'source_context', + sourceContextDescriptor.nested.google.nested.protobuf.nested +); +Protobuf.common( + 'type', + typeDescriptor.nested.google.nested.protobuf.nested +); diff --git a/packages/proto-loader/test_protos/well_known.proto b/packages/proto-loader/test_protos/well_known.proto index dd70402be..3ff2292fc 100644 --- a/packages/proto-loader/test_protos/well_known.proto +++ b/packages/proto-loader/test_protos/well_known.proto @@ -19,3 +19,7 @@ import "google/protobuf/descriptor.proto"; extend google.protobuf.FieldOptions { bool redact = 52000; } + +message DescriptorHolder { + google.protobuf.DescriptorProto descriptor = 1; +} From a068d589ae5445144f1b7cd1654baf24e058481b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 11:53:20 -0700 Subject: [PATCH 1148/1899] Don't explicitly include protobufjs when loading protos --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/xds-client.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8831891de..a795afc78 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -47,7 +47,7 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeDirs deps/envoy-api/ deps/udpa/ node_modules/protobufjs/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 80d19e0ea..9fb5279ed 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -65,7 +65,6 @@ function loadAdsProtos(): Promise { // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', __dirname + '/../../deps/udpa/', - __dirname + '/../../node_modules/protobufjs/', __dirname + '/../../deps/googleapis/', __dirname + '/../../deps/protoc-gen-validate/', ], From db75460000450bdbfd09651e5ae3193e33e2ed54 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 12:38:52 -0700 Subject: [PATCH 1149/1899] Regenerate type files --- packages/grpc-js/src/generated/ads.ts | 1276 +++++----- packages/grpc-js/src/generated/cluster.ts | 1846 +++++++------- packages/grpc-js/src/generated/endpoint.ts | 1550 ++++++------ .../src/generated/envoy/api/v2/Cluster.ts | 258 +- .../envoy/api/v2/ClusterLoadAssignment.ts | 4 +- .../envoy/api/v2/DeltaDiscoveryResponse.ts | 4 +- .../src/generated/envoy/api/v2/Listener.ts | 44 +- .../src/generated/envoy/api/v2/Resource.ts | 8 +- .../envoy/api/v2/RouteConfiguration.ts | 10 +- .../v2/auth/CertificateValidationContext.ts | 10 +- .../envoy/api/v2/auth/CommonTlsContext.ts | 10 +- .../envoy/api/v2/auth/DownstreamTlsContext.ts | 4 +- .../envoy/api/v2/auth/TlsCertificate.ts | 4 +- .../envoy/api/v2/core/ApiConfigSource.ts | 12 +- .../envoy/api/v2/core/ConfigSource.ts | 6 +- .../envoy/api/v2/core/GrpcService.ts | 86 +- .../envoy/api/v2/core/HealthCheck.ts | 88 +- .../envoy/api/v2/core/HttpProtocolOptions.ts | 4 +- .../envoy/api/v2/endpoint/LbEndpoint.ts | 4 +- .../envoy/api/v2/listener/FilterChainMatch.ts | 14 +- .../envoy/api/v2/route/CorsPolicy.ts | 10 +- .../envoy/api/v2/route/HeaderMatcher.ts | 10 +- .../generated/envoy/api/v2/route/RateLimit.ts | 44 +- .../envoy/api/v2/route/RedirectAction.ts | 16 +- .../envoy/api/v2/route/RetryPolicy.ts | 28 +- .../src/generated/envoy/api/v2/route/Route.ts | 26 +- .../envoy/api/v2/route/RouteAction.ts | 104 +- .../envoy/api/v2/route/RouteMatch.ts | 12 +- .../envoy/api/v2/route/VirtualCluster.ts | 6 +- .../envoy/api/v2/route/VirtualHost.ts | 20 +- .../envoy/api/v2/route/WeightedCluster.ts | 4 +- .../envoy/type/metadata/v2/MetadataKind.ts | 16 +- .../envoy/type/tracing/v2/CustomTag.ts | 16 +- .../generated/google/api/CustomHttpPattern.ts | 2 +- .../grpc-js/src/generated/google/api/Http.ts | 4 +- .../src/generated/google/api/HttpRule.ts | 12 +- .../google/protobuf/DescriptorProto.ts | 28 +- .../google/protobuf/EnumDescriptorProto.ts | 2 +- .../generated/google/protobuf/EnumOptions.ts | 10 +- .../protobuf/EnumValueDescriptorProto.ts | 2 +- .../google/protobuf/EnumValueOptions.ts | 10 +- .../google/protobuf/FieldDescriptorProto.ts | 40 +- .../generated/google/protobuf/FieldOptions.ts | 28 +- .../google/protobuf/FileDescriptorProto.ts | 22 +- .../google/protobuf/FileDescriptorSet.ts | 2 +- .../generated/google/protobuf/FileOptions.ts | 60 +- .../google/protobuf/GeneratedCodeInfo.ts | 6 +- .../google/protobuf/MessageOptions.ts | 22 +- .../google/protobuf/MethodDescriptorProto.ts | 18 +- .../google/protobuf/MethodOptions.ts | 6 +- .../google/protobuf/OneofDescriptorProto.ts | 2 +- .../generated/google/protobuf/OneofOptions.ts | 6 +- .../google/protobuf/ServiceDescriptorProto.ts | 2 +- .../google/protobuf/ServiceOptions.ts | 6 +- .../google/protobuf/SourceCodeInfo.ts | 14 +- .../google/protobuf/UninterpretedOption.ts | 34 +- packages/grpc-js/src/generated/listener.ts | 2214 ++++++++--------- packages/grpc-js/src/generated/route.ts | 1758 ++++++------- .../src/generated/validate/BytesRules.ts | 4 +- .../src/generated/validate/FieldRules.ts | 6 +- .../src/generated/validate/StringRules.ts | 12 +- 61 files changed, 4945 insertions(+), 4941 deletions(-) diff --git a/packages/grpc-js/src/generated/ads.ts b/packages/grpc-js/src/generated/ads.ts index fd9f8e2c4..4a5a4d121 100644 --- a/packages/grpc-js/src/generated/ads.ts +++ b/packages/grpc-js/src/generated/ads.ts @@ -1,596 +1,596 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { AdsDummy as _envoy_service_discovery_v2_AdsDummy, AdsDummy__Output as _envoy_service_discovery_v2_AdsDummy__Output } from './envoy/service/discovery/v2/AdsDummy'; -import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from './envoy/api/v2/DiscoveryRequest'; -import { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from './envoy/api/v2/DiscoveryResponse'; import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from './envoy/api/v2/DeltaDiscoveryRequest'; import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from './envoy/api/v2/DeltaDiscoveryResponse'; +import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from './envoy/api/v2/DiscoveryRequest'; +import { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from './envoy/api/v2/DiscoveryResponse'; import { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from './envoy/api/v2/Resource'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { AdsDummy as _envoy_service_discovery_v2_AdsDummy, AdsDummy__Output as _envoy_service_discovery_v2_AdsDummy__Output } from './envoy/service/discovery/v2/AdsDummy'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from './google/rpc/Status'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; export namespace messages { export namespace envoy { - export namespace service { - export namespace discovery { - export namespace v2 { - export namespace AggregatedDiscoveryService { - } - export type AdsDummy = _envoy_service_discovery_v2_AdsDummy; - export type AdsDummy__Output = _envoy_service_discovery_v2_AdsDummy__Output; - } - } - } export namespace api { export namespace v2 { - export type DiscoveryRequest = _envoy_api_v2_DiscoveryRequest; - export type DiscoveryRequest__Output = _envoy_api_v2_DiscoveryRequest__Output; - export type DiscoveryResponse = _envoy_api_v2_DiscoveryResponse; - export type DiscoveryResponse__Output = _envoy_api_v2_DiscoveryResponse__Output; export type DeltaDiscoveryRequest = _envoy_api_v2_DeltaDiscoveryRequest; export type DeltaDiscoveryRequest__Output = _envoy_api_v2_DeltaDiscoveryRequest__Output; export type DeltaDiscoveryResponse = _envoy_api_v2_DeltaDiscoveryResponse; export type DeltaDiscoveryResponse__Output = _envoy_api_v2_DeltaDiscoveryResponse__Output; + export type DiscoveryRequest = _envoy_api_v2_DiscoveryRequest; + export type DiscoveryRequest__Output = _envoy_api_v2_DiscoveryRequest__Output; + export type DiscoveryResponse = _envoy_api_v2_DiscoveryResponse; + export type DiscoveryResponse__Output = _envoy_api_v2_DiscoveryResponse__Output; export type Resource = _envoy_api_v2_Resource; export type Resource__Output = _envoy_api_v2_Resource__Output; export namespace core { - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - export type Locality = _envoy_api_v2_core_Locality; - export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; export type BuildVersion = _envoy_api_v2_core_BuildVersion; export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; export type Extension = _envoy_api_v2_core_Extension; export type Extension__Output = _envoy_api_v2_core_Extension__Output; - export type Node = _envoy_api_v2_core_Node; - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Metadata = _envoy_api_v2_core_Metadata; - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; export type HeaderValue = _envoy_api_v2_core_HeaderValue; export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - export type DataSource = _envoy_api_v2_core_DataSource; - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; export type SocketAddress = _envoy_api_v2_core_SocketAddress; export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - export type Address = _envoy_api_v2_core_Address; - export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; export type SocketOption = _envoy_api_v2_core_SocketOption; export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + } + } + } + export namespace service { + export namespace discovery { + export namespace v2 { + export type AdsDummy = _envoy_service_discovery_v2_AdsDummy; + export type AdsDummy__Output = _envoy_service_discovery_v2_AdsDummy__Output; + export namespace AggregatedDiscoveryService { + } } } } export namespace type { - export type Percent = _envoy_type_Percent; - export type Percent__Output = _envoy_type_Percent__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; export type SemanticVersion = _envoy_type_SemanticVersion; export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; } } - export namespace udpa { - export namespace annotations { - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - } - } - export namespace validate { - export type FieldRules = _validate_FieldRules; - export type FieldRules__Output = _validate_FieldRules__Output; - export type FloatRules = _validate_FloatRules; - export type FloatRules__Output = _validate_FloatRules__Output; - export type DoubleRules = _validate_DoubleRules; - export type DoubleRules__Output = _validate_DoubleRules__Output; - export type Int32Rules = _validate_Int32Rules; - export type Int32Rules__Output = _validate_Int32Rules__Output; - export type Int64Rules = _validate_Int64Rules; - export type Int64Rules__Output = _validate_Int64Rules__Output; - export type UInt32Rules = _validate_UInt32Rules; - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - export type UInt64Rules = _validate_UInt64Rules; - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - export type SInt32Rules = _validate_SInt32Rules; - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - export type SInt64Rules = _validate_SInt64Rules; - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - export type Fixed32Rules = _validate_Fixed32Rules; - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - export type Fixed64Rules = _validate_Fixed64Rules; - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - export type SFixed32Rules = _validate_SFixed32Rules; - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - export type SFixed64Rules = _validate_SFixed64Rules; - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - export type BoolRules = _validate_BoolRules; - export type BoolRules__Output = _validate_BoolRules__Output; - export type StringRules = _validate_StringRules; - export type StringRules__Output = _validate_StringRules__Output; - export type KnownRegex = _validate_KnownRegex; - export type BytesRules = _validate_BytesRules; - export type BytesRules__Output = _validate_BytesRules__Output; - export type EnumRules = _validate_EnumRules; - export type EnumRules__Output = _validate_EnumRules__Output; - export type MessageRules = _validate_MessageRules; - export type MessageRules__Output = _validate_MessageRules__Output; - export type RepeatedRules = _validate_RepeatedRules; - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - export type MapRules = _validate_MapRules; - export type MapRules__Output = _validate_MapRules__Output; - export type AnyRules = _validate_AnyRules; - export type AnyRules__Output = _validate_AnyRules__Output; - export type DurationRules = _validate_DurationRules; - export type DurationRules__Output = _validate_DurationRules__Output; - export type TimestampRules = _validate_TimestampRules; - export type TimestampRules__Output = _validate_TimestampRules__Output; - } export namespace google { export namespace protobuf { export type Any = _google_protobuf_Any; export type Any__Output = _google_protobuf_Any__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - export type NullValue = _google_protobuf_NullValue; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; export type BoolValue = _google_protobuf_BoolValue; export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; export type BytesValue = _google_protobuf_BytesValue; export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; export type DescriptorProto = _google_protobuf_DescriptorProto; export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; export type FileOptions = _google_protobuf_FileOptions; export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; export type MessageOptions = _google_protobuf_MessageOptions; export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type NullValue = _google_protobuf_NullValue; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; export type OneofOptions = _google_protobuf_OneofOptions; export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; export type ServiceOptions = _google_protobuf_ServiceOptions; export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; export type Timestamp = _google_protobuf_Timestamp; export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; } export namespace rpc { export type Status = _google_rpc_Status; export type Status__Output = _google_rpc_Status__Output; } } -} - -export namespace ClientInterfaces { - export namespace envoy { - export namespace service { - export namespace discovery { - export namespace v2 { - export interface AggregatedDiscoveryServiceClient extends grpc.Client { - StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - - DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - - } - export namespace AdsDummy { - } - } - } + export namespace udpa { + export namespace annotations { + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } + } + export namespace validate { + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type KnownRegex = _validate_KnownRegex; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + } +} + +export namespace ClientInterfaces { + export namespace envoy { export namespace api { export namespace v2 { - export namespace DiscoveryRequest { - } - export namespace DiscoveryResponse { - } export namespace DeltaDiscoveryRequest { } export namespace DeltaDiscoveryResponse { } + export namespace DiscoveryRequest { + } + export namespace DiscoveryResponse { + } export namespace Resource { } export namespace core { - export namespace Locality { + export namespace Address { } - export namespace BuildVersion { + export namespace AsyncDataSource { } - export namespace Extension { + export namespace BackoffStrategy { } - export namespace Node { + export namespace BindConfig { } - export namespace Metadata { + export namespace BuildVersion { } - export namespace RuntimeUInt32 { + export namespace CidrRange { } - export namespace RuntimeDouble { + export namespace ControlPlane { } - export namespace RuntimeFeatureFlag { + export namespace DataSource { + } + export namespace Extension { + } + export namespace HeaderMap { } export namespace HeaderValue { } export namespace HeaderValueOption { } - export namespace HeaderMap { + export namespace HttpUri { } - export namespace DataSource { + export namespace Locality { } - export namespace RetryPolicy { + export namespace Metadata { } - export namespace RemoteDataSource { + export namespace Node { } - export namespace AsyncDataSource { + export namespace Pipe { } - export namespace TransportSocket { + export namespace RemoteDataSource { } - export namespace RuntimeFractionalPercent { + export namespace RetryPolicy { } - export namespace ControlPlane { + export namespace RuntimeDouble { } - export namespace Pipe { + export namespace RuntimeFeatureFlag { } - export namespace SocketAddress { + export namespace RuntimeFractionalPercent { } - export namespace TcpKeepalive { + export namespace RuntimeUInt32 { } - export namespace BindConfig { + export namespace SocketAddress { } - export namespace Address { + export namespace SocketOption { } - export namespace CidrRange { + export namespace TcpKeepalive { } - export namespace SocketOption { + export namespace TransportSocket { } - export namespace HttpUri { + } + } + } + export namespace service { + export namespace discovery { + export namespace v2 { + export namespace AdsDummy { } - export namespace BackoffStrategy { + export interface AggregatedDiscoveryServiceClient extends grpc.Client { + DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + + StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + } } } } export namespace type { - export namespace Percent { - } export namespace FractionalPercent { } - export namespace SemanticVersion { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace StatusAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { + export namespace Percent { } - export namespace FileMigrateAnnotation { + export namespace SemanticVersion { } } } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } export namespace google { export namespace protobuf { export namespace Any { } - export namespace Duration { - } - export namespace Struct { + export namespace BoolValue { } - export namespace Value { + export namespace BytesValue { } - export namespace ListValue { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } export namespace DoubleValue { } - export namespace FloatValue { + export namespace Duration { } - export namespace Int64Value { + export namespace EnumDescriptorProto { } - export namespace UInt64Value { + export namespace EnumOptions { } - export namespace Int32Value { + export namespace EnumValueDescriptorProto { } - export namespace UInt32Value { + export namespace EnumValueOptions { } - export namespace BoolValue { + export namespace FieldDescriptorProto { } - export namespace StringValue { + export namespace FieldOptions { } - export namespace BytesValue { + export namespace FileDescriptorProto { } export namespace FileDescriptorSet { } - export namespace FileDescriptorProto { + export namespace FileOptions { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } + export namespace FloatValue { } - export namespace FieldDescriptorProto { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofDescriptorProto { + export namespace Int32Value { } - export namespace EnumDescriptorProto { + export namespace Int64Value { } - export namespace EnumValueDescriptorProto { + export namespace ListValue { } - export namespace ServiceDescriptorProto { + export namespace MessageOptions { } export namespace MethodDescriptorProto { } - export namespace FileOptions { - } - export namespace MessageOptions { + export namespace MethodOptions { } - export namespace FieldOptions { + export namespace OneofDescriptorProto { } export namespace OneofOptions { } - export namespace EnumOptions { - } - export namespace EnumValueOptions { + export namespace ServiceDescriptorProto { } export namespace ServiceOptions { } - export namespace MethodOptions { + export namespace SourceCodeInfo { + export namespace Location { + } + } + export namespace StringValue { + } + export namespace Struct { + } + export namespace Timestamp { + } + export namespace UInt32Value { + } + export namespace UInt64Value { } export namespace UninterpretedOption { export namespace NamePart { } } - export namespace SourceCodeInfo { - export namespace Location { - } + export namespace Value { } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } + } + export namespace rpc { + export namespace Status { } - export namespace Timestamp { + } + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { } + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { } - export namespace rpc { - export namespace Status { - } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { } } } @@ -602,382 +602,382 @@ type SubtypeConstructor = { export interface ProtoGrpcType { envoy: { - service: { - discovery: { - v2: { - AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } - AdsDummy: MessageTypeDefinition - } - } - } api: { v2: { - DiscoveryRequest: MessageTypeDefinition - DiscoveryResponse: MessageTypeDefinition DeltaDiscoveryRequest: MessageTypeDefinition DeltaDiscoveryResponse: MessageTypeDefinition + DiscoveryRequest: MessageTypeDefinition + DiscoveryResponse: MessageTypeDefinition Resource: MessageTypeDefinition core: { - RoutingPriority: EnumTypeDefinition - RequestMethod: EnumTypeDefinition - TrafficDirection: EnumTypeDefinition - Locality: MessageTypeDefinition + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition Extension: MessageTypeDefinition - Node: MessageTypeDefinition - Metadata: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition + HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition HeaderValueOption: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - DataSource: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - TransportSocket: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - Pipe: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition - Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition SocketOption: MessageTypeDefinition - HttpUri: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + } + } + } + service: { + discovery: { + v2: { + AdsDummy: MessageTypeDefinition + AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } } } } type: { - Percent: MessageTypeDefinition FractionalPercent: MessageTypeDefinition + Percent: MessageTypeDefinition SemanticVersion: MessageTypeDefinition } } - udpa: { - annotations: { - PackageVersionStatus: EnumTypeDefinition - StatusAnnotation: MessageTypeDefinition - MigrateAnnotation: MessageTypeDefinition - FieldMigrateAnnotation: MessageTypeDefinition - FileMigrateAnnotation: MessageTypeDefinition - } - } - validate: { - FieldRules: MessageTypeDefinition - FloatRules: MessageTypeDefinition - DoubleRules: MessageTypeDefinition - Int32Rules: MessageTypeDefinition - Int64Rules: MessageTypeDefinition - UInt32Rules: MessageTypeDefinition - UInt64Rules: MessageTypeDefinition - SInt32Rules: MessageTypeDefinition - SInt64Rules: MessageTypeDefinition - Fixed32Rules: MessageTypeDefinition - Fixed64Rules: MessageTypeDefinition - SFixed32Rules: MessageTypeDefinition - SFixed64Rules: MessageTypeDefinition - BoolRules: MessageTypeDefinition - StringRules: MessageTypeDefinition - KnownRegex: EnumTypeDefinition - BytesRules: MessageTypeDefinition - EnumRules: MessageTypeDefinition - MessageRules: MessageTypeDefinition - RepeatedRules: MessageTypeDefinition - MapRules: MessageTypeDefinition - AnyRules: MessageTypeDefinition - DurationRules: MessageTypeDefinition - TimestampRules: MessageTypeDefinition - } google: { protobuf: { Any: MessageTypeDefinition - Duration: MessageTypeDefinition - Struct: MessageTypeDefinition - Value: MessageTypeDefinition - NullValue: EnumTypeDefinition - ListValue: MessageTypeDefinition - DoubleValue: MessageTypeDefinition - FloatValue: MessageTypeDefinition - Int64Value: MessageTypeDefinition - UInt64Value: MessageTypeDefinition - Int32Value: MessageTypeDefinition - UInt32Value: MessageTypeDefinition BoolValue: MessageTypeDefinition - StringValue: MessageTypeDefinition BytesValue: MessageTypeDefinition - FileDescriptorSet: MessageTypeDefinition - FileDescriptorProto: MessageTypeDefinition DescriptorProto: MessageTypeDefinition - FieldDescriptorProto: MessageTypeDefinition - OneofDescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition EnumValueDescriptorProto: MessageTypeDefinition - ServiceDescriptorProto: MessageTypeDefinition - MethodDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition MessageOptions: MessageTypeDefinition - FieldOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition OneofOptions: MessageTypeDefinition - EnumOptions: MessageTypeDefinition - EnumValueOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition ServiceOptions: MessageTypeDefinition - MethodOptions: MessageTypeDefinition - UninterpretedOption: MessageTypeDefinition SourceCodeInfo: MessageTypeDefinition - GeneratedCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition } rpc: { Status: MessageTypeDefinition } } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } } export namespace ServiceHandlers { export namespace envoy { - export namespace service { - export namespace discovery { - export namespace v2 { - export interface AggregatedDiscoveryService { - StreamAggregatedResources(call: grpc.ServerDuplexStream): void; - - DeltaAggregatedResources(call: grpc.ServerDuplexStream): void; - - } - export namespace AdsDummy { - } - } - } - } export namespace api { export namespace v2 { - export namespace DiscoveryRequest { - } - export namespace DiscoveryResponse { - } export namespace DeltaDiscoveryRequest { } export namespace DeltaDiscoveryResponse { } + export namespace DiscoveryRequest { + } + export namespace DiscoveryResponse { + } export namespace Resource { } export namespace core { - export namespace Locality { + export namespace Address { } - export namespace BuildVersion { + export namespace AsyncDataSource { } - export namespace Extension { + export namespace BackoffStrategy { } - export namespace Node { + export namespace BindConfig { + } + export namespace BuildVersion { + } + export namespace CidrRange { } - export namespace Metadata { + export namespace ControlPlane { } - export namespace RuntimeUInt32 { + export namespace DataSource { } - export namespace RuntimeDouble { + export namespace Extension { } - export namespace RuntimeFeatureFlag { + export namespace HeaderMap { } export namespace HeaderValue { } export namespace HeaderValueOption { } - export namespace HeaderMap { + export namespace HttpUri { } - export namespace DataSource { + export namespace Locality { } - export namespace RetryPolicy { + export namespace Metadata { } - export namespace RemoteDataSource { + export namespace Node { } - export namespace AsyncDataSource { + export namespace Pipe { } - export namespace TransportSocket { + export namespace RemoteDataSource { } - export namespace RuntimeFractionalPercent { + export namespace RetryPolicy { } - export namespace ControlPlane { + export namespace RuntimeDouble { } - export namespace Pipe { + export namespace RuntimeFeatureFlag { } - export namespace SocketAddress { + export namespace RuntimeFractionalPercent { } - export namespace TcpKeepalive { + export namespace RuntimeUInt32 { } - export namespace BindConfig { + export namespace SocketAddress { } - export namespace Address { + export namespace SocketOption { } - export namespace CidrRange { + export namespace TcpKeepalive { } - export namespace SocketOption { + export namespace TransportSocket { } - export namespace HttpUri { + } + } + } + export namespace service { + export namespace discovery { + export namespace v2 { + export namespace AdsDummy { } - export namespace BackoffStrategy { + export interface AggregatedDiscoveryService { + DeltaAggregatedResources(call: grpc.ServerDuplexStream): void; + + StreamAggregatedResources(call: grpc.ServerDuplexStream): void; + } } } } export namespace type { - export namespace Percent { - } export namespace FractionalPercent { } - export namespace SemanticVersion { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace StatusAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { + export namespace Percent { } - export namespace FileMigrateAnnotation { + export namespace SemanticVersion { } } } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } export namespace google { export namespace protobuf { export namespace Any { } - export namespace Duration { - } - export namespace Struct { + export namespace BoolValue { } - export namespace Value { + export namespace BytesValue { } - export namespace ListValue { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } export namespace DoubleValue { } - export namespace FloatValue { + export namespace Duration { } - export namespace Int64Value { + export namespace EnumDescriptorProto { } - export namespace UInt64Value { + export namespace EnumOptions { } - export namespace Int32Value { + export namespace EnumValueDescriptorProto { } - export namespace UInt32Value { + export namespace EnumValueOptions { } - export namespace BoolValue { + export namespace FieldDescriptorProto { } - export namespace StringValue { + export namespace FieldOptions { } - export namespace BytesValue { + export namespace FileDescriptorProto { } export namespace FileDescriptorSet { } - export namespace FileDescriptorProto { + export namespace FileOptions { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } + export namespace FloatValue { } - export namespace FieldDescriptorProto { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofDescriptorProto { + export namespace Int32Value { } - export namespace EnumDescriptorProto { + export namespace Int64Value { } - export namespace EnumValueDescriptorProto { + export namespace ListValue { } - export namespace ServiceDescriptorProto { + export namespace MessageOptions { } export namespace MethodDescriptorProto { } - export namespace FileOptions { - } - export namespace MessageOptions { + export namespace MethodOptions { } - export namespace FieldOptions { + export namespace OneofDescriptorProto { } export namespace OneofOptions { } - export namespace EnumOptions { - } - export namespace EnumValueOptions { + export namespace ServiceDescriptorProto { } export namespace ServiceOptions { } - export namespace MethodOptions { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } + export namespace StringValue { + } + export namespace Struct { } export namespace Timestamp { } + export namespace UInt32Value { + } + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace Value { + } } export namespace rpc { export namespace Status { } } } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { + } + export namespace FileMigrateAnnotation { + } + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } diff --git a/packages/grpc-js/src/generated/cluster.ts b/packages/grpc-js/src/generated/cluster.ts index 6c45ee4cd..a99ff3277 100644 --- a/packages/grpc-js/src/generated/cluster.ts +++ b/packages/grpc-js/src/generated/cluster.ts @@ -2,289 +2,291 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { Cluster as _envoy_api_v2_Cluster, Cluster__Output as _envoy_api_v2_Cluster__Output } from './envoy/api/v2/Cluster'; +import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from './envoy/api/v2/LoadBalancingPolicy'; import { UpstreamBindConfig as _envoy_api_v2_UpstreamBindConfig, UpstreamBindConfig__Output as _envoy_api_v2_UpstreamBindConfig__Output } from './envoy/api/v2/UpstreamBindConfig'; import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from './envoy/api/v2/UpstreamConnectionOptions'; -import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from './envoy/api/v2/cluster/Filter'; -import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from './envoy/api/v2/cluster/CircuitBreakers'; -import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from './envoy/api/v2/cluster/OutlierDetection'; -import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; -import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; +import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; +import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; +import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; -import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; -import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; +import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; -import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; -import { TcpProtocolOptions as _envoy_api_v2_core_TcpProtocolOptions, TcpProtocolOptions__Output as _envoy_api_v2_core_TcpProtocolOptions__Output } from './envoy/api/v2/core/TcpProtocolOptions'; -import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from './envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from './envoy/api/v2/core/HttpProtocolOptions'; -import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from './envoy/api/v2/core/Http1ProtocolOptions'; -import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from './envoy/api/v2/core/Http2ProtocolOptions'; -import { GrpcProtocolOptions as _envoy_api_v2_core_GrpcProtocolOptions, GrpcProtocolOptions__Output as _envoy_api_v2_core_GrpcProtocolOptions__Output } from './envoy/api/v2/core/GrpcProtocolOptions'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; +import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from './envoy/api/v2/cluster/CircuitBreakers'; +import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from './envoy/api/v2/cluster/Filter'; +import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from './envoy/api/v2/cluster/OutlierDetection'; import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { GrpcProtocolOptions as _envoy_api_v2_core_GrpcProtocolOptions, GrpcProtocolOptions__Output as _envoy_api_v2_core_GrpcProtocolOptions__Output } from './envoy/api/v2/core/GrpcProtocolOptions'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; +import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from './envoy/api/v2/core/Http1ProtocolOptions'; +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from './envoy/api/v2/core/Http2ProtocolOptions'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from './envoy/api/v2/core/HttpProtocolOptions'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { TcpProtocolOptions as _envoy_api_v2_core_TcpProtocolOptions, TcpProtocolOptions__Output as _envoy_api_v2_core_TcpProtocolOptions__Output } from './envoy/api/v2/core/TcpProtocolOptions'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from './envoy/api/v2/core/UpstreamHttpProtocolOptions'; import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; +import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; export namespace messages { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export type Cluster = _envoy_api_v2_Cluster; export type Cluster__Output = _envoy_api_v2_Cluster__Output; + export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; + export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; export type LoadBalancingPolicy = _envoy_api_v2_LoadBalancingPolicy; export type LoadBalancingPolicy__Output = _envoy_api_v2_LoadBalancingPolicy__Output; export type UpstreamBindConfig = _envoy_api_v2_UpstreamBindConfig; export type UpstreamBindConfig__Output = _envoy_api_v2_UpstreamBindConfig__Output; export type UpstreamConnectionOptions = _envoy_api_v2_UpstreamConnectionOptions; export type UpstreamConnectionOptions__Output = _envoy_api_v2_UpstreamConnectionOptions__Output; - export namespace cluster { - export type Filter = _envoy_api_v2_cluster_Filter; - export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; - export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; - export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; - export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; - export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; - } export namespace auth { - export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; - export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; - export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; - export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; + export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; + export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; + export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; + export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; export type GenericSecret = _envoy_api_v2_auth_GenericSecret; export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; + export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; export type Secret = _envoy_api_v2_auth_Secret; export type Secret__Output = _envoy_api_v2_auth_Secret__Output; - export type TlsParameters = _envoy_api_v2_auth_TlsParameters; - export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; - export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; - export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; + export type TlsParameters = _envoy_api_v2_auth_TlsParameters; + export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; - export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; - export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; + export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; } - export namespace core { - export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; - export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; - export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; - export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; - export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; - export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; - export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; - export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; - export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; - export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; - export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; - export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; - export type HealthStatus = _envoy_api_v2_core_HealthStatus; - export type HealthCheck = _envoy_api_v2_core_HealthCheck; - export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + export namespace cluster { + export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; + export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; + export type Filter = _envoy_api_v2_cluster_Filter; + export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; + export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; + export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; + } + export namespace core { export type Address = _envoy_api_v2_core_Address; export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; - export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; - export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - export type Locality = _envoy_api_v2_core_Locality; - export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; export type BuildVersion = _envoy_api_v2_core_BuildVersion; export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; + export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; export type Extension = _envoy_api_v2_core_Extension; export type Extension__Output = _envoy_api_v2_core_Extension__Output; - export type Node = _envoy_api_v2_core_Node; - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Metadata = _envoy_api_v2_core_Metadata; - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; + export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; export type HeaderValue = _envoy_api_v2_core_HeaderValue; export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - export type DataSource = _envoy_api_v2_core_DataSource; - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type HealthCheck = _envoy_api_v2_core_HealthCheck; + export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + export type HealthStatus = _envoy_api_v2_core_HealthStatus; + export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; + export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; + export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; + export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; + export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; + export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; - export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; - export type GrpcService = _envoy_api_v2_core_GrpcService; - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; export type SocketOption = _envoy_api_v2_core_SocketOption; export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; + export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; + export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; } - export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; - export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; export namespace endpoint { export type Endpoint = _envoy_api_v2_endpoint_Endpoint; export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; @@ -295,189 +297,195 @@ export namespace messages { } } } - export namespace annotations { - } export namespace type { - export type Percent = _envoy_type_Percent; - export type Percent__Output = _envoy_type_Percent__Output; + export type CodecClientType = _envoy_type_CodecClientType; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; + export type SemanticVersion = _envoy_type_SemanticVersion; + export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { - export type StringMatcher = _envoy_type_matcher_StringMatcher; - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; } - export type Int64Range = _envoy_type_Int64Range; - export type Int64Range__Output = _envoy_type_Int64Range__Output; - export type Int32Range = _envoy_type_Int32Range; - export type Int32Range__Output = _envoy_type_Int32Range__Output; - export type DoubleRange = _envoy_type_DoubleRange; - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - export type CodecClientType = _envoy_type_CodecClientType; - export type SemanticVersion = _envoy_type_SemanticVersion; - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; } } - export namespace udpa { - export namespace annotations { - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - export type FieldRules = _validate_FieldRules; - export type FieldRules__Output = _validate_FieldRules__Output; - export type FloatRules = _validate_FloatRules; - export type FloatRules__Output = _validate_FloatRules__Output; - export type DoubleRules = _validate_DoubleRules; - export type DoubleRules__Output = _validate_DoubleRules__Output; - export type Int32Rules = _validate_Int32Rules; - export type Int32Rules__Output = _validate_Int32Rules__Output; - export type Int64Rules = _validate_Int64Rules; - export type Int64Rules__Output = _validate_Int64Rules__Output; - export type UInt32Rules = _validate_UInt32Rules; - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - export type UInt64Rules = _validate_UInt64Rules; - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - export type SInt32Rules = _validate_SInt32Rules; - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - export type SInt64Rules = _validate_SInt64Rules; - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - export type Fixed32Rules = _validate_Fixed32Rules; - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - export type Fixed64Rules = _validate_Fixed64Rules; - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - export type SFixed32Rules = _validate_SFixed32Rules; - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - export type SFixed64Rules = _validate_SFixed64Rules; - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - export type BoolRules = _validate_BoolRules; - export type BoolRules__Output = _validate_BoolRules__Output; - export type StringRules = _validate_StringRules; - export type StringRules__Output = _validate_StringRules__Output; - export type KnownRegex = _validate_KnownRegex; - export type BytesRules = _validate_BytesRules; - export type BytesRules__Output = _validate_BytesRules__Output; - export type EnumRules = _validate_EnumRules; - export type EnumRules__Output = _validate_EnumRules__Output; - export type MessageRules = _validate_MessageRules; - export type MessageRules__Output = _validate_MessageRules__Output; - export type RepeatedRules = _validate_RepeatedRules; - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - export type MapRules = _validate_MapRules; - export type MapRules__Output = _validate_MapRules__Output; - export type AnyRules = _validate_AnyRules; - export type AnyRules__Output = _validate_AnyRules__Output; - export type DurationRules = _validate_DurationRules; - export type DurationRules__Output = _validate_DurationRules__Output; - export type TimestampRules = _validate_TimestampRules; - export type TimestampRules__Output = _validate_TimestampRules__Output; - } export namespace google { + export namespace api { + export type CustomHttpPattern = _google_api_CustomHttpPattern; + export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + export type Http = _google_api_Http; + export type Http__Output = _google_api_Http__Output; + export type HttpRule = _google_api_HttpRule; + export type HttpRule__Output = _google_api_HttpRule__Output; + } export namespace protobuf { export type Any = _google_protobuf_Any; export type Any__Output = _google_protobuf_Any__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - export type NullValue = _google_protobuf_NullValue; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; export type BoolValue = _google_protobuf_BoolValue; export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; export type BytesValue = _google_protobuf_BytesValue; export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; export type DescriptorProto = _google_protobuf_DescriptorProto; export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; export type FileOptions = _google_protobuf_FileOptions; export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; export type MessageOptions = _google_protobuf_MessageOptions; export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type NullValue = _google_protobuf_NullValue; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; export type OneofOptions = _google_protobuf_OneofOptions; export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; export type ServiceOptions = _google_protobuf_ServiceOptions; export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; } - export namespace api { - export type Http = _google_api_Http; - export type Http__Output = _google_api_Http__Output; - export type HttpRule = _google_api_HttpRule; - export type HttpRule__Output = _google_api_HttpRule__Output; - export type CustomHttpPattern = _google_api_CustomHttpPattern; - export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + } + export namespace udpa { + export namespace annotations { + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } } + export namespace validate { + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type KnownRegex = _validate_KnownRegex; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + } } export namespace ClientInterfaces { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace Cluster { - export namespace TransportSocketMatch { + export namespace CommonLbConfig { + export namespace ConsistentHashingLbConfig { + } + export namespace LocalityWeightedLbConfig { + } + export namespace ZoneAwareLbConfig { + } } export namespace CustomClusterType { } @@ -489,20 +497,20 @@ export namespace ClientInterfaces { } export namespace LeastRequestLbConfig { } + export namespace OriginalDstLbConfig { + } + export namespace RefreshRate { + } export namespace RingHashLbConfig { } - export namespace OriginalDstLbConfig { + export namespace TransportSocketMatch { } - export namespace CommonLbConfig { - export namespace ZoneAwareLbConfig { - } - export namespace LocalityWeightedLbConfig { - } - export namespace ConsistentHashingLbConfig { + } + export namespace ClusterLoadAssignment { + export namespace Policy { + export namespace DropOverload { } } - export namespace RefreshRate { - } } export namespace LoadBalancingPolicy { export namespace Policy { @@ -512,172 +520,166 @@ export namespace ClientInterfaces { } export namespace UpstreamConnectionOptions { } - export namespace cluster { - export namespace Filter { + export namespace auth { + export namespace CertificateValidationContext { + } + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } + } + export namespace DownstreamTlsContext { + } + export namespace GenericSecret { + } + export namespace PrivateKeyProvider { + } + export namespace SdsSecretConfig { + } + export namespace Secret { + } + export namespace TlsCertificate { + } + export namespace TlsParameters { } + export namespace TlsSessionTicketKeys { + } + export namespace UpstreamTlsContext { + } + } + export namespace cluster { export namespace CircuitBreakers { export namespace Thresholds { export namespace RetryBudget { } } } + export namespace Filter { + } export namespace OutlierDetection { } } - export namespace auth { - export namespace UpstreamTlsContext { + export namespace core { + export namespace Address { } - export namespace DownstreamTlsContext { + export namespace AggregatedConfigSource { } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } + export namespace ApiConfigSource { } - export namespace GenericSecret { + export namespace AsyncDataSource { } - export namespace SdsSecretConfig { + export namespace BackoffStrategy { } - export namespace Secret { + export namespace BindConfig { } - export namespace TlsParameters { + export namespace BuildVersion { } - export namespace PrivateKeyProvider { + export namespace CidrRange { } - export namespace TlsCertificate { + export namespace ConfigSource { } - export namespace TlsSessionTicketKeys { + export namespace ControlPlane { } - export namespace CertificateValidationContext { + export namespace DataSource { } - } - export namespace core { - export namespace TcpProtocolOptions { + export namespace EventServiceConfig { } - export namespace UpstreamHttpProtocolOptions { + export namespace Extension { } - export namespace HttpProtocolOptions { + export namespace GrpcProtocolOptions { } - export namespace Http1ProtocolOptions { - export namespace HeaderKeyFormat { - export namespace ProperCaseWords { + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace CallCredentials { + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace StsService { + } + } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { } } } - export namespace Http2ProtocolOptions { - export namespace SettingsParameter { - } + export namespace HeaderMap { } - export namespace GrpcProtocolOptions { + export namespace HeaderValue { + } + export namespace HeaderValueOption { } export namespace HealthCheck { - export namespace Payload { + export namespace CustomHealthCheck { + } + export namespace GrpcHealthCheck { } export namespace HttpHealthCheck { } - export namespace TcpHealthCheck { + export namespace Payload { } export namespace RedisHealthCheck { } - export namespace GrpcHealthCheck { - } - export namespace CustomHealthCheck { + export namespace TcpHealthCheck { } export namespace TlsOptions { } } - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { - } - export namespace BindConfig { - } - export namespace Address { - } - export namespace CidrRange { - } - export namespace ApiConfigSource { - } - export namespace AggregatedConfigSource { + export namespace Http1ProtocolOptions { + export namespace HeaderKeyFormat { + export namespace ProperCaseWords { + } + } } - export namespace SelfConfigSource { + export namespace Http2ProtocolOptions { + export namespace SettingsParameter { + } } - export namespace RateLimitSettings { + export namespace HttpProtocolOptions { } - export namespace ConfigSource { + export namespace HttpUri { } export namespace Locality { } - export namespace BuildVersion { - } - export namespace Extension { - } - export namespace Node { - } export namespace Metadata { } - export namespace RuntimeUInt32 { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace HeaderValue { + export namespace Node { } - export namespace HeaderValueOption { + export namespace Pipe { } - export namespace HeaderMap { + export namespace RateLimitSettings { } - export namespace DataSource { + export namespace RemoteDataSource { } export namespace RetryPolicy { } - export namespace RemoteDataSource { - } - export namespace AsyncDataSource { + export namespace RuntimeDouble { } - export namespace TransportSocket { + export namespace RuntimeFeatureFlag { } export namespace RuntimeFractionalPercent { } - export namespace ControlPlane { + export namespace RuntimeUInt32 { } - export namespace EventServiceConfig { + export namespace SelfConfigSource { } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace SslCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace ChannelCredentials { - } - export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace StsService { - } - } - } + export namespace SocketAddress { } - export namespace HttpUri { + export namespace SocketOption { } - export namespace BackoffStrategy { + export namespace TcpKeepalive { } - export namespace SocketOption { + export namespace TcpProtocolOptions { } - } - export namespace ClusterLoadAssignment { - export namespace Policy { - export namespace DropOverload { - } + export namespace TransportSocket { + } + export namespace UpstreamHttpProtocolOptions { } } export namespace endpoint { @@ -692,189 +694,187 @@ export namespace ClientInterfaces { } } } - export namespace annotations { - } export namespace type { - export namespace Percent { + export namespace DoubleRange { } export namespace FractionalPercent { } + export namespace Int32Range { + } + export namespace Int64Range { + } + export namespace Percent { + } + export namespace SemanticVersion { + } export namespace matcher { - export namespace StringMatcher { - } export namespace ListStringMatcher { } + export namespace RegexMatchAndSubstitute { + } export namespace RegexMatcher { export namespace GoogleRE2 { } } - export namespace RegexMatchAndSubstitute { + export namespace StringMatcher { } } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - export namespace SemanticVersion { - } } } - export namespace udpa { - export namespace annotations { - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { + export namespace google { + export namespace api { + export namespace CustomHttpPattern { } - export namespace FileMigrateAnnotation { + export namespace Http { } - export namespace StatusAnnotation { + export namespace HttpRule { } } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } - export namespace google { export namespace protobuf { export namespace Any { } - export namespace Duration { - } - export namespace Struct { + export namespace BoolValue { } - export namespace Value { + export namespace BytesValue { } - export namespace ListValue { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } export namespace DoubleValue { } - export namespace FloatValue { + export namespace Duration { } - export namespace Int64Value { + export namespace Empty { } - export namespace UInt64Value { + export namespace EnumDescriptorProto { } - export namespace Int32Value { + export namespace EnumOptions { } - export namespace UInt32Value { + export namespace EnumValueDescriptorProto { } - export namespace BoolValue { + export namespace EnumValueOptions { } - export namespace StringValue { + export namespace FieldDescriptorProto { } - export namespace BytesValue { + export namespace FieldOptions { } - export namespace Timestamp { + export namespace FileDescriptorProto { } export namespace FileDescriptorSet { } - export namespace FileDescriptorProto { + export namespace FileOptions { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } + export namespace FloatValue { } - export namespace FieldDescriptorProto { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofDescriptorProto { + export namespace Int32Value { } - export namespace EnumDescriptorProto { + export namespace Int64Value { } - export namespace EnumValueDescriptorProto { + export namespace ListValue { } - export namespace ServiceDescriptorProto { + export namespace MessageOptions { } export namespace MethodDescriptorProto { } - export namespace FileOptions { - } - export namespace MessageOptions { + export namespace MethodOptions { } - export namespace FieldOptions { + export namespace OneofDescriptorProto { } export namespace OneofOptions { } - export namespace EnumOptions { - } - export namespace EnumValueOptions { + export namespace ServiceDescriptorProto { } export namespace ServiceOptions { } - export namespace MethodOptions { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { + export namespace StringValue { + } + export namespace Struct { + } + export namespace Timestamp { + } + export namespace UInt32Value { + } + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { } } - export namespace Empty { + export namespace Value { + } + } + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - } - export namespace api { - export namespace Http { + export namespace FileMigrateAnnotation { } - export namespace HttpRule { + export namespace MigrateAnnotation { } - export namespace CustomHttpPattern { + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; @@ -884,79 +884,81 @@ type SubtypeConstructor = { export interface ProtoGrpcType { envoy: { + annotations: { + } api: { v2: { Cluster: MessageTypeDefinition + ClusterLoadAssignment: MessageTypeDefinition LoadBalancingPolicy: MessageTypeDefinition UpstreamBindConfig: MessageTypeDefinition UpstreamConnectionOptions: MessageTypeDefinition - cluster: { - Filter: MessageTypeDefinition - CircuitBreakers: MessageTypeDefinition - OutlierDetection: MessageTypeDefinition - } auth: { - UpstreamTlsContext: MessageTypeDefinition - DownstreamTlsContext: MessageTypeDefinition + CertificateValidationContext: MessageTypeDefinition CommonTlsContext: MessageTypeDefinition + DownstreamTlsContext: MessageTypeDefinition GenericSecret: MessageTypeDefinition + PrivateKeyProvider: MessageTypeDefinition SdsSecretConfig: MessageTypeDefinition Secret: MessageTypeDefinition - TlsParameters: MessageTypeDefinition - PrivateKeyProvider: MessageTypeDefinition TlsCertificate: MessageTypeDefinition + TlsParameters: MessageTypeDefinition TlsSessionTicketKeys: MessageTypeDefinition - CertificateValidationContext: MessageTypeDefinition + UpstreamTlsContext: MessageTypeDefinition + } + cluster: { + CircuitBreakers: MessageTypeDefinition + Filter: MessageTypeDefinition + OutlierDetection: MessageTypeDefinition } core: { - TcpProtocolOptions: MessageTypeDefinition - UpstreamHttpProtocolOptions: MessageTypeDefinition - HttpProtocolOptions: MessageTypeDefinition - Http1ProtocolOptions: MessageTypeDefinition - Http2ProtocolOptions: MessageTypeDefinition - GrpcProtocolOptions: MessageTypeDefinition - HealthStatus: EnumTypeDefinition - HealthCheck: MessageTypeDefinition - Pipe: MessageTypeDefinition - SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition - ApiVersion: EnumTypeDefinition - ApiConfigSource: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition - SelfConfigSource: MessageTypeDefinition - RateLimitSettings: MessageTypeDefinition - ConfigSource: MessageTypeDefinition - RoutingPriority: EnumTypeDefinition - RequestMethod: EnumTypeDefinition - TrafficDirection: EnumTypeDefinition - Locality: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + EventServiceConfig: MessageTypeDefinition Extension: MessageTypeDefinition - Node: MessageTypeDefinition - Metadata: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition HeaderValueOption: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - DataSource: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + HealthCheck: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - TransportSocket: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - EventServiceConfig: MessageTypeDefinition - GrpcService: MessageTypeDefinition - HttpUri: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TcpProtocolOptions: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition } - ClusterLoadAssignment: MessageTypeDefinition endpoint: { Endpoint: MessageTypeDefinition LbEndpoint: MessageTypeDefinition @@ -964,113 +966,119 @@ export interface ProtoGrpcType { } } } - annotations: { - } type: { - Percent: MessageTypeDefinition + CodecClientType: EnumTypeDefinition + DoubleRange: MessageTypeDefinition FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition matcher: { - StringMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition } - Int64Range: MessageTypeDefinition - Int32Range: MessageTypeDefinition - DoubleRange: MessageTypeDefinition - CodecClientType: EnumTypeDefinition - SemanticVersion: MessageTypeDefinition - } - } - udpa: { - annotations: { - MigrateAnnotation: MessageTypeDefinition - FieldMigrateAnnotation: MessageTypeDefinition - FileMigrateAnnotation: MessageTypeDefinition - PackageVersionStatus: EnumTypeDefinition - StatusAnnotation: MessageTypeDefinition } } - validate: { - FieldRules: MessageTypeDefinition - FloatRules: MessageTypeDefinition - DoubleRules: MessageTypeDefinition - Int32Rules: MessageTypeDefinition - Int64Rules: MessageTypeDefinition - UInt32Rules: MessageTypeDefinition - UInt64Rules: MessageTypeDefinition - SInt32Rules: MessageTypeDefinition - SInt64Rules: MessageTypeDefinition - Fixed32Rules: MessageTypeDefinition - Fixed64Rules: MessageTypeDefinition - SFixed32Rules: MessageTypeDefinition - SFixed64Rules: MessageTypeDefinition - BoolRules: MessageTypeDefinition - StringRules: MessageTypeDefinition - KnownRegex: EnumTypeDefinition - BytesRules: MessageTypeDefinition - EnumRules: MessageTypeDefinition - MessageRules: MessageTypeDefinition - RepeatedRules: MessageTypeDefinition - MapRules: MessageTypeDefinition - AnyRules: MessageTypeDefinition - DurationRules: MessageTypeDefinition - TimestampRules: MessageTypeDefinition - } google: { + api: { + CustomHttpPattern: MessageTypeDefinition + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + } protobuf: { Any: MessageTypeDefinition - Duration: MessageTypeDefinition - Struct: MessageTypeDefinition - Value: MessageTypeDefinition - NullValue: EnumTypeDefinition - ListValue: MessageTypeDefinition - DoubleValue: MessageTypeDefinition - FloatValue: MessageTypeDefinition - Int64Value: MessageTypeDefinition - UInt64Value: MessageTypeDefinition - Int32Value: MessageTypeDefinition - UInt32Value: MessageTypeDefinition BoolValue: MessageTypeDefinition - StringValue: MessageTypeDefinition BytesValue: MessageTypeDefinition - Timestamp: MessageTypeDefinition - FileDescriptorSet: MessageTypeDefinition - FileDescriptorProto: MessageTypeDefinition DescriptorProto: MessageTypeDefinition - FieldDescriptorProto: MessageTypeDefinition - OneofDescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition EnumValueDescriptorProto: MessageTypeDefinition - ServiceDescriptorProto: MessageTypeDefinition - MethodDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition MessageOptions: MessageTypeDefinition - FieldOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition OneofOptions: MessageTypeDefinition - EnumOptions: MessageTypeDefinition - EnumValueOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition ServiceOptions: MessageTypeDefinition - MethodOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition UninterpretedOption: MessageTypeDefinition - SourceCodeInfo: MessageTypeDefinition - GeneratedCodeInfo: MessageTypeDefinition - Empty: MessageTypeDefinition + Value: MessageTypeDefinition } - api: { - Http: MessageTypeDefinition - HttpRule: MessageTypeDefinition - CustomHttpPattern: MessageTypeDefinition + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition } } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } } export namespace ServiceHandlers { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace Cluster { - export namespace TransportSocketMatch { + export namespace CommonLbConfig { + export namespace ConsistentHashingLbConfig { + } + export namespace LocalityWeightedLbConfig { + } + export namespace ZoneAwareLbConfig { + } } export namespace CustomClusterType { } @@ -1082,20 +1090,20 @@ export namespace ServiceHandlers { } export namespace LeastRequestLbConfig { } + export namespace OriginalDstLbConfig { + } + export namespace RefreshRate { + } export namespace RingHashLbConfig { } - export namespace OriginalDstLbConfig { + export namespace TransportSocketMatch { } - export namespace CommonLbConfig { - export namespace ZoneAwareLbConfig { - } - export namespace LocalityWeightedLbConfig { - } - export namespace ConsistentHashingLbConfig { + } + export namespace ClusterLoadAssignment { + export namespace Policy { + export namespace DropOverload { } } - export namespace RefreshRate { - } } export namespace LoadBalancingPolicy { export namespace Policy { @@ -1105,172 +1113,166 @@ export namespace ServiceHandlers { } export namespace UpstreamConnectionOptions { } - export namespace cluster { - export namespace Filter { - } - export namespace CircuitBreakers { - export namespace Thresholds { - export namespace RetryBudget { - } - } - } - export namespace OutlierDetection { - } - } export namespace auth { - export namespace UpstreamTlsContext { - } - export namespace DownstreamTlsContext { + export namespace CertificateValidationContext { } export namespace CommonTlsContext { export namespace CombinedCertificateValidationContext { } } + export namespace DownstreamTlsContext { + } export namespace GenericSecret { } + export namespace PrivateKeyProvider { + } export namespace SdsSecretConfig { } export namespace Secret { } - export namespace TlsParameters { - } - export namespace PrivateKeyProvider { - } export namespace TlsCertificate { } + export namespace TlsParameters { + } export namespace TlsSessionTicketKeys { } - export namespace CertificateValidationContext { + export namespace UpstreamTlsContext { } } - export namespace core { - export namespace TcpProtocolOptions { - } - export namespace UpstreamHttpProtocolOptions { - } - export namespace HttpProtocolOptions { - } - export namespace Http1ProtocolOptions { - export namespace HeaderKeyFormat { - export namespace ProperCaseWords { + export namespace cluster { + export namespace CircuitBreakers { + export namespace Thresholds { + export namespace RetryBudget { } } } - export namespace Http2ProtocolOptions { - export namespace SettingsParameter { - } - } - export namespace GrpcProtocolOptions { - } - export namespace HealthCheck { - export namespace Payload { - } - export namespace HttpHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace RedisHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace CustomHealthCheck { - } - export namespace TlsOptions { - } - } - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { + export namespace Filter { } - export namespace BindConfig { + export namespace OutlierDetection { } + } + export namespace core { export namespace Address { } - export namespace CidrRange { - } - export namespace ApiConfigSource { - } export namespace AggregatedConfigSource { } - export namespace SelfConfigSource { + export namespace ApiConfigSource { } - export namespace RateLimitSettings { + export namespace AsyncDataSource { } - export namespace ConfigSource { + export namespace BackoffStrategy { } - export namespace Locality { + export namespace BindConfig { } export namespace BuildVersion { } - export namespace Extension { - } - export namespace Node { - } - export namespace Metadata { - } - export namespace RuntimeUInt32 { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace HeaderValue { + export namespace CidrRange { } - export namespace HeaderValueOption { + export namespace ConfigSource { } - export namespace HeaderMap { + export namespace ControlPlane { } export namespace DataSource { } - export namespace RetryPolicy { - } - export namespace RemoteDataSource { - } - export namespace AsyncDataSource { - } - export namespace TransportSocket { - } - export namespace RuntimeFractionalPercent { + export namespace EventServiceConfig { } - export namespace ControlPlane { + export namespace Extension { } - export namespace EventServiceConfig { + export namespace GrpcProtocolOptions { } export namespace GrpcService { export namespace EnvoyGrpc { } export namespace GoogleGrpc { - export namespace SslCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace ChannelCredentials { - } export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } export namespace GoogleIAMCredentials { } export namespace MetadataCredentialsFromPlugin { } + export namespace ServiceAccountJWTAccessCredentials { + } export namespace StsService { } } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } + } + } + export namespace HeaderMap { + } + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HealthCheck { + export namespace CustomHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace HttpHealthCheck { + } + export namespace Payload { + } + export namespace RedisHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace TlsOptions { + } + } + export namespace Http1ProtocolOptions { + export namespace HeaderKeyFormat { + export namespace ProperCaseWords { + } + } + } + export namespace Http2ProtocolOptions { + export namespace SettingsParameter { } } - export namespace HttpUri { + export namespace HttpProtocolOptions { + } + export namespace HttpUri { + } + export namespace Locality { + } + export namespace Metadata { + } + export namespace Node { + } + export namespace Pipe { + } + export namespace RateLimitSettings { + } + export namespace RemoteDataSource { + } + export namespace RetryPolicy { } - export namespace BackoffStrategy { + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace RuntimeFractionalPercent { + } + export namespace RuntimeUInt32 { + } + export namespace SelfConfigSource { + } + export namespace SocketAddress { } export namespace SocketOption { } - } - export namespace ClusterLoadAssignment { - export namespace Policy { - export namespace DropOverload { - } + export namespace TcpKeepalive { + } + export namespace TcpProtocolOptions { + } + export namespace TransportSocket { + } + export namespace UpstreamHttpProtocolOptions { } } export namespace endpoint { @@ -1285,187 +1287,185 @@ export namespace ServiceHandlers { } } } - export namespace annotations { - } export namespace type { - export namespace Percent { + export namespace DoubleRange { } export namespace FractionalPercent { } + export namespace Int32Range { + } + export namespace Int64Range { + } + export namespace Percent { + } + export namespace SemanticVersion { + } export namespace matcher { - export namespace StringMatcher { - } export namespace ListStringMatcher { } + export namespace RegexMatchAndSubstitute { + } export namespace RegexMatcher { export namespace GoogleRE2 { } } - export namespace RegexMatchAndSubstitute { + export namespace StringMatcher { } } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - export namespace SemanticVersion { - } } } - export namespace udpa { - export namespace annotations { - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { + export namespace google { + export namespace api { + export namespace CustomHttpPattern { } - export namespace FileMigrateAnnotation { + export namespace Http { } - export namespace StatusAnnotation { + export namespace HttpRule { } } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } - export namespace google { export namespace protobuf { export namespace Any { } - export namespace Duration { - } - export namespace Struct { + export namespace BoolValue { } - export namespace Value { + export namespace BytesValue { } - export namespace ListValue { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } export namespace DoubleValue { } - export namespace FloatValue { + export namespace Duration { } - export namespace Int64Value { + export namespace Empty { } - export namespace UInt64Value { + export namespace EnumDescriptorProto { } - export namespace Int32Value { + export namespace EnumOptions { } - export namespace UInt32Value { + export namespace EnumValueDescriptorProto { } - export namespace BoolValue { + export namespace EnumValueOptions { } - export namespace StringValue { + export namespace FieldDescriptorProto { } - export namespace BytesValue { + export namespace FieldOptions { } - export namespace Timestamp { + export namespace FileDescriptorProto { } export namespace FileDescriptorSet { } - export namespace FileDescriptorProto { + export namespace FileOptions { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } + export namespace FloatValue { } - export namespace FieldDescriptorProto { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofDescriptorProto { + export namespace Int32Value { } - export namespace EnumDescriptorProto { + export namespace Int64Value { } - export namespace EnumValueDescriptorProto { + export namespace ListValue { } - export namespace ServiceDescriptorProto { + export namespace MessageOptions { } export namespace MethodDescriptorProto { } - export namespace FileOptions { - } - export namespace MessageOptions { + export namespace MethodOptions { } - export namespace FieldOptions { + export namespace OneofDescriptorProto { } export namespace OneofOptions { } - export namespace EnumOptions { - } - export namespace EnumValueOptions { + export namespace ServiceDescriptorProto { } export namespace ServiceOptions { } - export namespace MethodOptions { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { + export namespace StringValue { + } + export namespace Struct { + } + export namespace Timestamp { + } + export namespace UInt32Value { + } + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { } } - export namespace Empty { + export namespace Value { } } - export namespace api { - export namespace Http { + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace HttpRule { + export namespace FileMigrateAnnotation { } - export namespace CustomHttpPattern { + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } diff --git a/packages/grpc-js/src/generated/endpoint.ts b/packages/grpc-js/src/generated/endpoint.ts index b9d7dbeea..7bfbe093f 100644 --- a/packages/grpc-js/src/generated/endpoint.ts +++ b/packages/grpc-js/src/generated/endpoint.ts @@ -2,385 +2,387 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; -import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; -import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; -import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; +import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; +import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; +import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; +import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; +import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; export namespace messages { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; - export namespace endpoint { - export type Endpoint = _envoy_api_v2_endpoint_Endpoint; - export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; - export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; - export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; - export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; - export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; - } export namespace core { - export type HealthStatus = _envoy_api_v2_core_HealthStatus; - export type HealthCheck = _envoy_api_v2_core_HealthCheck; - export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - export type Locality = _envoy_api_v2_core_Locality; - export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; export type BuildVersion = _envoy_api_v2_core_BuildVersion; export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; + export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; export type Extension = _envoy_api_v2_core_Extension; export type Extension__Output = _envoy_api_v2_core_Extension__Output; - export type Node = _envoy_api_v2_core_Node; - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Metadata = _envoy_api_v2_core_Metadata; - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; export type HeaderValue = _envoy_api_v2_core_HeaderValue; export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - export type DataSource = _envoy_api_v2_core_DataSource; - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type HealthCheck = _envoy_api_v2_core_HealthCheck; + export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + export type HealthStatus = _envoy_api_v2_core_HealthStatus; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; export type SocketAddress = _envoy_api_v2_core_SocketAddress; export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - export type Address = _envoy_api_v2_core_Address; - export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; - export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; export type SocketOption = _envoy_api_v2_core_SocketOption; export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type GrpcService = _envoy_api_v2_core_GrpcService; - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + } + export namespace endpoint { + export type Endpoint = _envoy_api_v2_endpoint_Endpoint; + export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; + export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; + export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; + export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; + export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; } } } export namespace type { - export type Percent = _envoy_type_Percent; - export type Percent__Output = _envoy_type_Percent__Output; + export type CodecClientType = _envoy_type_CodecClientType; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - export type CodecClientType = _envoy_type_CodecClientType; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; export type SemanticVersion = _envoy_type_SemanticVersion; export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { - export type StringMatcher = _envoy_type_matcher_StringMatcher; - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type StringMatcher = _envoy_type_matcher_StringMatcher; + export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; } - export type Int64Range = _envoy_type_Int64Range; - export type Int64Range__Output = _envoy_type_Int64Range__Output; - export type Int32Range = _envoy_type_Int32Range; - export type Int32Range__Output = _envoy_type_Int32Range__Output; - export type DoubleRange = _envoy_type_DoubleRange; - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - } - export namespace annotations { - } - } - export namespace udpa { - export namespace annotations { - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } } - export namespace validate { - export type FieldRules = _validate_FieldRules; - export type FieldRules__Output = _validate_FieldRules__Output; - export type FloatRules = _validate_FloatRules; - export type FloatRules__Output = _validate_FloatRules__Output; - export type DoubleRules = _validate_DoubleRules; - export type DoubleRules__Output = _validate_DoubleRules__Output; - export type Int32Rules = _validate_Int32Rules; - export type Int32Rules__Output = _validate_Int32Rules__Output; - export type Int64Rules = _validate_Int64Rules; - export type Int64Rules__Output = _validate_Int64Rules__Output; - export type UInt32Rules = _validate_UInt32Rules; - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - export type UInt64Rules = _validate_UInt64Rules; - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - export type SInt32Rules = _validate_SInt32Rules; - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - export type SInt64Rules = _validate_SInt64Rules; - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - export type Fixed32Rules = _validate_Fixed32Rules; - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - export type Fixed64Rules = _validate_Fixed64Rules; - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - export type SFixed32Rules = _validate_SFixed32Rules; - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - export type SFixed64Rules = _validate_SFixed64Rules; - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - export type BoolRules = _validate_BoolRules; - export type BoolRules__Output = _validate_BoolRules__Output; - export type StringRules = _validate_StringRules; - export type StringRules__Output = _validate_StringRules__Output; - export type KnownRegex = _validate_KnownRegex; - export type BytesRules = _validate_BytesRules; - export type BytesRules__Output = _validate_BytesRules__Output; - export type EnumRules = _validate_EnumRules; - export type EnumRules__Output = _validate_EnumRules__Output; - export type MessageRules = _validate_MessageRules; - export type MessageRules__Output = _validate_MessageRules__Output; - export type RepeatedRules = _validate_RepeatedRules; - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - export type MapRules = _validate_MapRules; - export type MapRules__Output = _validate_MapRules__Output; - export type AnyRules = _validate_AnyRules; - export type AnyRules__Output = _validate_AnyRules__Output; - export type DurationRules = _validate_DurationRules; - export type DurationRules__Output = _validate_DurationRules__Output; - export type TimestampRules = _validate_TimestampRules; - export type TimestampRules__Output = _validate_TimestampRules__Output; - } export namespace google { + export namespace api { + export type CustomHttpPattern = _google_api_CustomHttpPattern; + export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + export type Http = _google_api_Http; + export type Http__Output = _google_api_Http__Output; + export type HttpRule = _google_api_HttpRule; + export type HttpRule__Output = _google_api_HttpRule__Output; + } export namespace protobuf { - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; export type BoolValue = _google_protobuf_BoolValue; export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; export type BytesValue = _google_protobuf_BytesValue; export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; export type DescriptorProto = _google_protobuf_DescriptorProto; export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; export type FileOptions = _google_protobuf_FileOptions; export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; export type MessageOptions = _google_protobuf_MessageOptions; export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type NullValue = _google_protobuf_NullValue; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; export type OneofOptions = _google_protobuf_OneofOptions; export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; export type ServiceOptions = _google_protobuf_ServiceOptions; export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; export type Struct = _google_protobuf_Struct; export type Struct__Output = _google_protobuf_Struct__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; export type Value = _google_protobuf_Value; export type Value__Output = _google_protobuf_Value__Output; - export type NullValue = _google_protobuf_NullValue; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; } - export namespace api { - export type Http = _google_api_Http; - export type Http__Output = _google_api_Http__Output; - export type HttpRule = _google_api_HttpRule; - export type HttpRule__Output = _google_api_HttpRule__Output; - export type CustomHttpPattern = _google_api_CustomHttpPattern; - export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + } + export namespace udpa { + export namespace annotations { + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } } + export namespace validate { + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type KnownRegex = _validate_KnownRegex; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + } } export namespace ClientInterfaces { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace ClusterLoadAssignment { @@ -389,230 +391,156 @@ export namespace ClientInterfaces { } } } - export namespace endpoint { - export namespace Endpoint { - export namespace HealthCheckConfig { - } - } - export namespace LbEndpoint { - } - export namespace LocalityLbEndpoints { - } - } export namespace core { - export namespace HealthCheck { - export namespace Payload { - } - export namespace HttpHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace RedisHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace CustomHealthCheck { - } - export namespace TlsOptions { - } - } - export namespace Locality { - } - export namespace BuildVersion { - } - export namespace Extension { - } - export namespace Node { - } - export namespace Metadata { - } - export namespace RuntimeUInt32 { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HeaderMap { - } - export namespace DataSource { - } - export namespace RetryPolicy { - } - export namespace RemoteDataSource { + export namespace Address { } export namespace AsyncDataSource { } - export namespace TransportSocket { - } - export namespace RuntimeFractionalPercent { - } - export namespace ControlPlane { - } - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { + export namespace BackoffStrategy { } export namespace BindConfig { } - export namespace Address { + export namespace BuildVersion { } export namespace CidrRange { } - export namespace EventServiceConfig { + export namespace ControlPlane { } - export namespace BackoffStrategy { + export namespace DataSource { } - export namespace HttpUri { + export namespace EventServiceConfig { } - export namespace SocketOption { + export namespace Extension { } export namespace GrpcService { export namespace EnvoyGrpc { } export namespace GoogleGrpc { - export namespace SslCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace ChannelCredentials { - } export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } export namespace GoogleIAMCredentials { } export namespace MetadataCredentialsFromPlugin { } + export namespace ServiceAccountJWTAccessCredentials { + } export namespace StsService { } } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } } } - } - } - } - export namespace type { - export namespace Percent { - } - export namespace FractionalPercent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace StringMatcher { - } - export namespace ListStringMatcher { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { + export namespace HeaderMap { } - } - export namespace RegexMatchAndSubstitute { - } - } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - } - export namespace annotations { - } - } - export namespace udpa { - export namespace annotations { - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { + export namespace HeaderValue { + } + export namespace HeaderValueOption { + } + export namespace HealthCheck { + export namespace CustomHealthCheck { + } + export namespace GrpcHealthCheck { + } + export namespace HttpHealthCheck { + } + export namespace Payload { + } + export namespace RedisHealthCheck { + } + export namespace TcpHealthCheck { + } + export namespace TlsOptions { + } + } + export namespace HttpUri { + } + export namespace Locality { + } + export namespace Metadata { + } + export namespace Node { + } + export namespace Pipe { + } + export namespace RemoteDataSource { + } + export namespace RetryPolicy { + } + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace RuntimeFractionalPercent { + } + export namespace RuntimeUInt32 { + } + export namespace SocketAddress { + } + export namespace SocketOption { + } + export namespace TcpKeepalive { + } + export namespace TransportSocket { + } + } + export namespace endpoint { + export namespace Endpoint { + export namespace HealthCheckConfig { + } + } + export namespace LbEndpoint { + } + export namespace LocalityLbEndpoints { + } + } + } } - } - export namespace google { - export namespace protobuf { - export namespace Duration { + export namespace type { + export namespace DoubleRange { } - export namespace DoubleValue { + export namespace FractionalPercent { } - export namespace FloatValue { + export namespace Int32Range { } - export namespace Int64Value { + export namespace Int64Range { } - export namespace UInt64Value { + export namespace Percent { } - export namespace Int32Value { + export namespace SemanticVersion { } - export namespace UInt32Value { + export namespace matcher { + export namespace ListStringMatcher { + } + export namespace RegexMatchAndSubstitute { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace StringMatcher { + } } - export namespace BoolValue { + } + } + export namespace google { + export namespace api { + export namespace CustomHttpPattern { } - export namespace StringValue { + export namespace Http { } - export namespace BytesValue { + export namespace HttpRule { } - export namespace Timestamp { + } + export namespace protobuf { + export namespace Any { } - export namespace FileDescriptorSet { + export namespace BoolValue { } - export namespace FileDescriptorProto { + export namespace BytesValue { } export namespace DescriptorProto { export namespace ExtensionRange { @@ -620,66 +548,138 @@ export namespace ClientInterfaces { export namespace ReservedRange { } } - export namespace FieldDescriptorProto { + export namespace DoubleValue { } - export namespace OneofDescriptorProto { + export namespace Duration { + } + export namespace Empty { } export namespace EnumDescriptorProto { } + export namespace EnumOptions { + } export namespace EnumValueDescriptorProto { } - export namespace ServiceDescriptorProto { + export namespace EnumValueOptions { } - export namespace MethodDescriptorProto { + export namespace FieldDescriptorProto { + } + export namespace FieldOptions { + } + export namespace FileDescriptorProto { + } + export namespace FileDescriptorSet { } export namespace FileOptions { } - export namespace MessageOptions { + export namespace FloatValue { } - export namespace FieldOptions { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofOptions { + export namespace Int32Value { } - export namespace EnumOptions { + export namespace Int64Value { } - export namespace EnumValueOptions { + export namespace ListValue { } - export namespace ServiceOptions { + export namespace MessageOptions { + } + export namespace MethodDescriptorProto { } export namespace MethodOptions { } - export namespace UninterpretedOption { - export namespace NamePart { - } + export namespace OneofDescriptorProto { + } + export namespace OneofOptions { + } + export namespace ServiceDescriptorProto { + } + export namespace ServiceOptions { } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Any { + export namespace StringValue { } export namespace Struct { } - export namespace Value { + export namespace Timestamp { } - export namespace ListValue { + export namespace UInt32Value { } - export namespace Empty { + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace Value { } } - export namespace api { - export namespace Http { + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace HttpRule { + export namespace FileMigrateAnnotation { } - export namespace CustomHttpPattern { + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; @@ -689,155 +689,157 @@ type SubtypeConstructor = { export interface ProtoGrpcType { envoy: { + annotations: { + } api: { v2: { ClusterLoadAssignment: MessageTypeDefinition - endpoint: { - Endpoint: MessageTypeDefinition - LbEndpoint: MessageTypeDefinition - LocalityLbEndpoints: MessageTypeDefinition - } core: { - HealthStatus: EnumTypeDefinition - HealthCheck: MessageTypeDefinition - RoutingPriority: EnumTypeDefinition - RequestMethod: EnumTypeDefinition - TrafficDirection: EnumTypeDefinition - Locality: MessageTypeDefinition + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + EventServiceConfig: MessageTypeDefinition Extension: MessageTypeDefinition - Node: MessageTypeDefinition - Metadata: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition HeaderValueOption: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - DataSource: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + HealthCheck: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - TransportSocket: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - Pipe: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition - Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition - EventServiceConfig: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition - HttpUri: MessageTypeDefinition SocketOption: MessageTypeDefinition - GrpcService: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + } + endpoint: { + Endpoint: MessageTypeDefinition + LbEndpoint: MessageTypeDefinition + LocalityLbEndpoints: MessageTypeDefinition } } } type: { - Percent: MessageTypeDefinition - FractionalPercent: MessageTypeDefinition CodecClientType: EnumTypeDefinition + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition SemanticVersion: MessageTypeDefinition matcher: { - StringMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition } - Int64Range: MessageTypeDefinition - Int32Range: MessageTypeDefinition - DoubleRange: MessageTypeDefinition } - annotations: { + } + google: { + api: { + CustomHttpPattern: MessageTypeDefinition + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + } + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition } } udpa: { annotations: { - MigrateAnnotation: MessageTypeDefinition FieldMigrateAnnotation: MessageTypeDefinition FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition } } validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition FloatRules: MessageTypeDefinition - DoubleRules: MessageTypeDefinition Int32Rules: MessageTypeDefinition Int64Rules: MessageTypeDefinition - UInt32Rules: MessageTypeDefinition - UInt64Rules: MessageTypeDefinition - SInt32Rules: MessageTypeDefinition - SInt64Rules: MessageTypeDefinition - Fixed32Rules: MessageTypeDefinition - Fixed64Rules: MessageTypeDefinition - SFixed32Rules: MessageTypeDefinition - SFixed64Rules: MessageTypeDefinition - BoolRules: MessageTypeDefinition - StringRules: MessageTypeDefinition KnownRegex: EnumTypeDefinition - BytesRules: MessageTypeDefinition - EnumRules: MessageTypeDefinition + MapRules: MessageTypeDefinition MessageRules: MessageTypeDefinition RepeatedRules: MessageTypeDefinition - MapRules: MessageTypeDefinition - AnyRules: MessageTypeDefinition - DurationRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition TimestampRules: MessageTypeDefinition - } - google: { - protobuf: { - Duration: MessageTypeDefinition - DoubleValue: MessageTypeDefinition - FloatValue: MessageTypeDefinition - Int64Value: MessageTypeDefinition - UInt64Value: MessageTypeDefinition - Int32Value: MessageTypeDefinition - UInt32Value: MessageTypeDefinition - BoolValue: MessageTypeDefinition - StringValue: MessageTypeDefinition - BytesValue: MessageTypeDefinition - Timestamp: MessageTypeDefinition - FileDescriptorSet: MessageTypeDefinition - FileDescriptorProto: MessageTypeDefinition - DescriptorProto: MessageTypeDefinition - FieldDescriptorProto: MessageTypeDefinition - OneofDescriptorProto: MessageTypeDefinition - EnumDescriptorProto: MessageTypeDefinition - EnumValueDescriptorProto: MessageTypeDefinition - ServiceDescriptorProto: MessageTypeDefinition - MethodDescriptorProto: MessageTypeDefinition - FileOptions: MessageTypeDefinition - MessageOptions: MessageTypeDefinition - FieldOptions: MessageTypeDefinition - OneofOptions: MessageTypeDefinition - EnumOptions: MessageTypeDefinition - EnumValueOptions: MessageTypeDefinition - ServiceOptions: MessageTypeDefinition - MethodOptions: MessageTypeDefinition - UninterpretedOption: MessageTypeDefinition - SourceCodeInfo: MessageTypeDefinition - GeneratedCodeInfo: MessageTypeDefinition - Any: MessageTypeDefinition - Struct: MessageTypeDefinition - Value: MessageTypeDefinition - NullValue: EnumTypeDefinition - ListValue: MessageTypeDefinition - Empty: MessageTypeDefinition - } - api: { - Http: MessageTypeDefinition - HttpRule: MessageTypeDefinition - CustomHttpPattern: MessageTypeDefinition - } + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition } } export namespace ServiceHandlers { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace ClusterLoadAssignment { @@ -846,295 +848,293 @@ export namespace ServiceHandlers { } } } - export namespace endpoint { - export namespace Endpoint { - export namespace HealthCheckConfig { + export namespace core { + export namespace Address { + } + export namespace AsyncDataSource { + } + export namespace BackoffStrategy { + } + export namespace BindConfig { + } + export namespace BuildVersion { + } + export namespace CidrRange { + } + export namespace ControlPlane { + } + export namespace DataSource { + } + export namespace EventServiceConfig { + } + export namespace Extension { + } + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace CallCredentials { + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace StsService { + } + } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } } } - export namespace LbEndpoint { + export namespace HeaderMap { } - export namespace LocalityLbEndpoints { + export namespace HeaderValue { + } + export namespace HeaderValueOption { } - } - export namespace core { export namespace HealthCheck { - export namespace Payload { + export namespace CustomHealthCheck { + } + export namespace GrpcHealthCheck { } export namespace HttpHealthCheck { } - export namespace TcpHealthCheck { + export namespace Payload { } export namespace RedisHealthCheck { } - export namespace GrpcHealthCheck { - } - export namespace CustomHealthCheck { + export namespace TcpHealthCheck { } export namespace TlsOptions { } } - export namespace Locality { - } - export namespace BuildVersion { - } - export namespace Extension { + export namespace HttpUri { } - export namespace Node { + export namespace Locality { } export namespace Metadata { } - export namespace RuntimeUInt32 { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { + export namespace Node { } - export namespace HeaderMap { + export namespace Pipe { } - export namespace DataSource { + export namespace RemoteDataSource { } export namespace RetryPolicy { } - export namespace RemoteDataSource { - } - export namespace AsyncDataSource { + export namespace RuntimeDouble { } - export namespace TransportSocket { + export namespace RuntimeFeatureFlag { } export namespace RuntimeFractionalPercent { } - export namespace ControlPlane { - } - export namespace Pipe { + export namespace RuntimeUInt32 { } export namespace SocketAddress { } - export namespace TcpKeepalive { - } - export namespace BindConfig { - } - export namespace Address { - } - export namespace CidrRange { - } - export namespace EventServiceConfig { - } - export namespace BackoffStrategy { + export namespace SocketOption { } - export namespace HttpUri { + export namespace TcpKeepalive { } - export namespace SocketOption { + export namespace TransportSocket { } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace SslCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace ChannelCredentials { - } - export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace StsService { - } - } + } + export namespace endpoint { + export namespace Endpoint { + export namespace HealthCheckConfig { } } + export namespace LbEndpoint { + } + export namespace LocalityLbEndpoints { + } } } } export namespace type { - export namespace Percent { + export namespace DoubleRange { } export namespace FractionalPercent { } + export namespace Int32Range { + } + export namespace Int64Range { + } + export namespace Percent { + } export namespace SemanticVersion { } export namespace matcher { - export namespace StringMatcher { - } export namespace ListStringMatcher { } + export namespace RegexMatchAndSubstitute { + } export namespace RegexMatcher { export namespace GoogleRE2 { } } - export namespace RegexMatchAndSubstitute { + export namespace StringMatcher { } } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - } - export namespace annotations { } } - export namespace udpa { - export namespace annotations { - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { + export namespace google { + export namespace api { + export namespace CustomHttpPattern { } - export namespace FileMigrateAnnotation { + export namespace Http { } - export namespace StatusAnnotation { + export namespace HttpRule { } } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } - export namespace google { export namespace protobuf { - export namespace Duration { - } - export namespace DoubleValue { - } - export namespace FloatValue { - } - export namespace Int64Value { - } - export namespace UInt64Value { - } - export namespace Int32Value { - } - export namespace UInt32Value { + export namespace Any { } export namespace BoolValue { } - export namespace StringValue { - } export namespace BytesValue { } - export namespace Timestamp { - } - export namespace FileDescriptorSet { - } - export namespace FileDescriptorProto { - } export namespace DescriptorProto { export namespace ExtensionRange { } export namespace ReservedRange { } } - export namespace FieldDescriptorProto { + export namespace DoubleValue { } - export namespace OneofDescriptorProto { + export namespace Duration { + } + export namespace Empty { } export namespace EnumDescriptorProto { } + export namespace EnumOptions { + } export namespace EnumValueDescriptorProto { } - export namespace ServiceDescriptorProto { + export namespace EnumValueOptions { } - export namespace MethodDescriptorProto { + export namespace FieldDescriptorProto { + } + export namespace FieldOptions { + } + export namespace FileDescriptorProto { + } + export namespace FileDescriptorSet { } export namespace FileOptions { } - export namespace MessageOptions { + export namespace FloatValue { } - export namespace FieldOptions { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofOptions { + export namespace Int32Value { } - export namespace EnumOptions { + export namespace Int64Value { } - export namespace EnumValueOptions { + export namespace ListValue { } - export namespace ServiceOptions { + export namespace MessageOptions { + } + export namespace MethodDescriptorProto { } export namespace MethodOptions { } - export namespace UninterpretedOption { - export namespace NamePart { - } + export namespace OneofDescriptorProto { + } + export namespace OneofOptions { + } + export namespace ServiceDescriptorProto { + } + export namespace ServiceOptions { } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Any { + export namespace StringValue { } export namespace Struct { } - export namespace Value { + export namespace Timestamp { } - export namespace ListValue { + export namespace UInt32Value { } - export namespace Empty { + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { + } + } + export namespace Value { } } - export namespace api { - export namespace Http { + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace HttpRule { + export namespace FileMigrateAnnotation { } - export namespace CustomHttpPattern { + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts index 816031726..e3d33e0ac 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts @@ -3,76 +3,81 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; -import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from '../../../envoy/api/v2/ClusterLoadAssignment'; import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from '../../../envoy/api/v2/core/HealthCheck'; import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from '../../../envoy/api/v2/cluster/CircuitBreakers'; import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from '../../../envoy/api/v2/auth/UpstreamTlsContext'; -import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../envoy/api/v2/core/HttpProtocolOptions'; import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http1ProtocolOptions'; import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http2ProtocolOptions'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from '../../../envoy/api/v2/cluster/OutlierDetection'; import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from '../../../envoy/api/v2/core/BindConfig'; import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../envoy/api/v2/core/TransportSocket'; import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../envoy/api/v2/core/HttpProtocolOptions'; import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from '../../../envoy/api/v2/UpstreamConnectionOptions'; +import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from '../../../envoy/api/v2/ClusterLoadAssignment'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from '../../../envoy/api/v2/cluster/Filter'; import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from '../../../envoy/api/v2/LoadBalancingPolicy'; import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; +import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; import { Long } from '@grpc/proto-loader'; // Original file: deps/envoy-api/envoy/api/v2/cluster.proto -export enum _envoy_api_v2_Cluster_DiscoveryType { - STATIC = 0, - STRICT_DNS = 1, - LOGICAL_DNS = 2, - EDS = 3, - ORIGINAL_DST = 4, +export enum _envoy_api_v2_Cluster_ClusterProtocolSelection { + USE_CONFIGURED_PROTOCOL = 0, + USE_DOWNSTREAM_PROTOCOL = 1, } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +export interface _envoy_api_v2_Cluster_CommonLbConfig { + 'healthy_panic_threshold'?: (_envoy_type_Percent); + 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig); + 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig); + 'update_merge_window'?: (_google_protobuf_Duration); + 'ignore_new_hosts_until_first_hc'?: (boolean); + 'close_connections_on_host_set_change'?: (boolean); + 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig); + 'locality_config_specifier'?: "zone_aware_lb_config"|"locality_weighted_lb_config"; +} -export enum _envoy_api_v2_Cluster_LbPolicy { - ROUND_ROBIN = 0, - LEAST_REQUEST = 1, - RING_HASH = 2, - RANDOM = 3, - ORIGINAL_DST_LB = 4, - MAGLEV = 5, - CLUSTER_PROVIDED = 6, - LOAD_BALANCING_POLICY_CONFIG = 7, +export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { + 'healthy_panic_threshold': (_envoy_type_Percent__Output); + 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); + 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); + 'update_merge_window': (_google_protobuf_Duration__Output); + 'ignore_new_hosts_until_first_hc': (boolean); + 'close_connections_on_host_set_change': (boolean); + 'consistent_hashing_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); + 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig { + 'use_hostname_for_hashing'?: (boolean); +} -export enum _envoy_api_v2_Cluster_DnsLookupFamily { - AUTO = 0, - V4_ONLY = 1, - V6_ONLY = 2, +export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output { + 'use_hostname_for_hashing': (boolean); } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { +} -export enum _envoy_api_v2_Cluster_ClusterProtocolSelection { - USE_CONFIGURED_PROTOCOL = 0, - USE_DOWNSTREAM_PROTOCOL = 1, +export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { } -export interface _envoy_api_v2_Cluster_TransportSocketMatch { - 'name'?: (string); - 'match'?: (_google_protobuf_Struct); - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); +export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { + 'routing_enabled'?: (_envoy_type_Percent); + 'min_cluster_size'?: (_google_protobuf_UInt64Value); + 'fail_traffic_on_panic'?: (boolean); } -export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { - 'name': (string); - 'match': (_google_protobuf_Struct__Output); - 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); +export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { + 'routing_enabled': (_envoy_type_Percent__Output); + 'min_cluster_size': (_google_protobuf_UInt64Value__Output); + 'fail_traffic_on_panic': (boolean); } export interface _envoy_api_v2_Cluster_CustomClusterType { @@ -85,6 +90,24 @@ export interface _envoy_api_v2_Cluster_CustomClusterType__Output { 'typed_config': (_google_protobuf_Any__Output); } +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_DiscoveryType { + STATIC = 0, + STRICT_DNS = 1, + LOGICAL_DNS = 2, + EDS = 3, + ORIGINAL_DST = 4, +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_DnsLookupFamily { + AUTO = 0, + V4_ONLY = 1, + V6_ONLY = 2, +} + export interface _envoy_api_v2_Cluster_EdsClusterConfig { 'eds_config'?: (_envoy_api_v2_core_ConfigSource); 'service_name'?: (string); @@ -95,6 +118,19 @@ export interface _envoy_api_v2_Cluster_EdsClusterConfig__Output { 'service_name': (string); } +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + +export enum _envoy_api_v2_Cluster_LbPolicy { + ROUND_ROBIN = 0, + LEAST_REQUEST = 1, + RING_HASH = 2, + RANDOM = 3, + ORIGINAL_DST_LB = 4, + MAGLEV = 5, + CLUSTER_PROVIDED = 6, + LOAD_BALANCING_POLICY_CONFIG = 7, +} + export interface _envoy_api_v2_Cluster_LbSubsetConfig { 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); 'default_subset'?: (_google_protobuf_Struct); @@ -153,25 +189,6 @@ export interface _envoy_api_v2_Cluster_LeastRequestLbConfig__Output { 'choice_count': (_google_protobuf_UInt32Value__Output); } -export interface _envoy_api_v2_Cluster_RingHashLbConfig { - 'minimum_ring_size'?: (_google_protobuf_UInt64Value); - 'hash_function'?: (_envoy_api_v2_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); - 'maximum_ring_size'?: (_google_protobuf_UInt64Value); -} - -export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { - 'minimum_ring_size': (_google_protobuf_UInt64Value__Output); - 'hash_function': (keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); - 'maximum_ring_size': (_google_protobuf_UInt64Value__Output); -} - -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto - -export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { - XX_HASH = 0, - MURMUR_HASH_2 = 1, -} - export interface _envoy_api_v2_Cluster_OriginalDstLbConfig { 'use_http_header'?: (boolean); } @@ -180,159 +197,142 @@ export interface _envoy_api_v2_Cluster_OriginalDstLbConfig__Output { 'use_http_header': (boolean); } -export interface _envoy_api_v2_Cluster_CommonLbConfig { - 'healthy_panic_threshold'?: (_envoy_type_Percent); - 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig); - 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig); - 'update_merge_window'?: (_google_protobuf_Duration); - 'ignore_new_hosts_until_first_hc'?: (boolean); - 'close_connections_on_host_set_change'?: (boolean); - 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig); - 'locality_config_specifier'?: "zone_aware_lb_config"|"locality_weighted_lb_config"; -} - -export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { - 'healthy_panic_threshold': (_envoy_type_Percent__Output); - 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); - 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); - 'update_merge_window': (_google_protobuf_Duration__Output); - 'ignore_new_hosts_until_first_hc': (boolean); - 'close_connections_on_host_set_change': (boolean); - 'consistent_hashing_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); - 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; -} - -export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { - 'routing_enabled'?: (_envoy_type_Percent); - 'min_cluster_size'?: (_google_protobuf_UInt64Value); - 'fail_traffic_on_panic'?: (boolean); +export interface _envoy_api_v2_Cluster_RefreshRate { + 'base_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration); } -export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { - 'routing_enabled': (_envoy_type_Percent__Output); - 'min_cluster_size': (_google_protobuf_UInt64Value__Output); - 'fail_traffic_on_panic': (boolean); +export interface _envoy_api_v2_Cluster_RefreshRate__Output { + 'base_interval': (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output); } -export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { +export interface _envoy_api_v2_Cluster_RingHashLbConfig { + 'minimum_ring_size'?: (_google_protobuf_UInt64Value); + 'hash_function'?: (_envoy_api_v2_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + 'maximum_ring_size'?: (_google_protobuf_UInt64Value); } -export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { +export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { + 'minimum_ring_size': (_google_protobuf_UInt64Value__Output); + 'hash_function': (keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + 'maximum_ring_size': (_google_protobuf_UInt64Value__Output); } -export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig { - 'use_hostname_for_hashing'?: (boolean); -} +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto -export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output { - 'use_hostname_for_hashing': (boolean); +export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { + XX_HASH = 0, + MURMUR_HASH_2 = 1, } -export interface _envoy_api_v2_Cluster_RefreshRate { - 'base_interval'?: (_google_protobuf_Duration); - 'max_interval'?: (_google_protobuf_Duration); +export interface _envoy_api_v2_Cluster_TransportSocketMatch { + 'name'?: (string); + 'match'?: (_google_protobuf_Struct); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); } -export interface _envoy_api_v2_Cluster_RefreshRate__Output { - 'base_interval': (_google_protobuf_Duration__Output); - 'max_interval': (_google_protobuf_Duration__Output); +export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { + 'name': (string); + 'match': (_google_protobuf_Struct__Output); + 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); } export interface Cluster { - 'transport_socket_matches'?: (_envoy_api_v2_Cluster_TransportSocketMatch)[]; 'name'?: (string); - 'alt_stat_name'?: (string); 'type'?: (_envoy_api_v2_Cluster_DiscoveryType | keyof typeof _envoy_api_v2_Cluster_DiscoveryType); - 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType); 'eds_cluster_config'?: (_envoy_api_v2_Cluster_EdsClusterConfig); 'connect_timeout'?: (_google_protobuf_Duration); 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); 'lb_policy'?: (_envoy_api_v2_Cluster_LbPolicy | keyof typeof _envoy_api_v2_Cluster_LbPolicy); 'hosts'?: (_envoy_api_v2_core_Address)[]; - 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment); 'health_checks'?: (_envoy_api_v2_core_HealthCheck)[]; 'max_requests_per_connection'?: (_google_protobuf_UInt32Value); 'circuit_breakers'?: (_envoy_api_v2_cluster_CircuitBreakers); 'tls_context'?: (_envoy_api_v2_auth_UpstreamTlsContext); - 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions); - 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); - 'extension_protocol_options'?: (_google_protobuf_Struct); - 'typed_extension_protocol_options'?: (_google_protobuf_Any); 'dns_refresh_rate'?: (_google_protobuf_Duration); - 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate); - 'respect_dns_ttl'?: (boolean); 'dns_lookup_family'?: (_envoy_api_v2_Cluster_DnsLookupFamily | keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); 'dns_resolvers'?: (_envoy_api_v2_core_Address)[]; - 'use_tcp_for_dns_lookups'?: (boolean); 'outlier_detection'?: (_envoy_api_v2_cluster_OutlierDetection); 'cleanup_interval'?: (_google_protobuf_Duration); 'upstream_bind_config'?: (_envoy_api_v2_core_BindConfig); 'lb_subset_config'?: (_envoy_api_v2_Cluster_LbSubsetConfig); 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig); - 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig); - 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig); - 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig); 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); 'metadata'?: (_envoy_api_v2_core_Metadata); 'protocol_selection'?: (_envoy_api_v2_Cluster_ClusterProtocolSelection | keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig); + 'alt_stat_name'?: (string); + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); 'upstream_connection_options'?: (_envoy_api_v2_UpstreamConnectionOptions); 'close_connections_on_host_health_failure'?: (boolean); 'drain_connections_on_host_removal'?: (boolean); + 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment); + 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig); + 'extension_protocol_options'?: (_google_protobuf_Struct); + 'typed_extension_protocol_options'?: (_google_protobuf_Any); + 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig); + 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType); + 'respect_dns_ttl'?: (boolean); 'filters'?: (_envoy_api_v2_cluster_Filter)[]; 'load_balancing_policy'?: (_envoy_api_v2_LoadBalancingPolicy); 'lrs_server'?: (_envoy_api_v2_core_ConfigSource); + 'transport_socket_matches'?: (_envoy_api_v2_Cluster_TransportSocketMatch)[]; + 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate); + 'use_tcp_for_dns_lookups'?: (boolean); + 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions); 'track_timeout_budgets'?: (boolean); 'cluster_discovery_type'?: "type"|"cluster_type"; 'lb_config'?: "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; } export interface Cluster__Output { - 'transport_socket_matches': (_envoy_api_v2_Cluster_TransportSocketMatch__Output)[]; 'name': (string); - 'alt_stat_name': (string); 'type'?: (keyof typeof _envoy_api_v2_Cluster_DiscoveryType); - 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType__Output); 'eds_cluster_config': (_envoy_api_v2_Cluster_EdsClusterConfig__Output); 'connect_timeout': (_google_protobuf_Duration__Output); 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); 'lb_policy': (keyof typeof _envoy_api_v2_Cluster_LbPolicy); 'hosts': (_envoy_api_v2_core_Address__Output)[]; - 'load_assignment': (_envoy_api_v2_ClusterLoadAssignment__Output); 'health_checks': (_envoy_api_v2_core_HealthCheck__Output)[]; 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output); 'circuit_breakers': (_envoy_api_v2_cluster_CircuitBreakers__Output); 'tls_context': (_envoy_api_v2_auth_UpstreamTlsContext__Output); - 'upstream_http_protocol_options': (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); - 'common_http_protocol_options': (_envoy_api_v2_core_HttpProtocolOptions__Output); 'http_protocol_options': (_envoy_api_v2_core_Http1ProtocolOptions__Output); 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); - 'extension_protocol_options': (_google_protobuf_Struct__Output); - 'typed_extension_protocol_options': (_google_protobuf_Any__Output); 'dns_refresh_rate': (_google_protobuf_Duration__Output); - 'dns_failure_refresh_rate': (_envoy_api_v2_Cluster_RefreshRate__Output); - 'respect_dns_ttl': (boolean); 'dns_lookup_family': (keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); 'dns_resolvers': (_envoy_api_v2_core_Address__Output)[]; - 'use_tcp_for_dns_lookups': (boolean); 'outlier_detection': (_envoy_api_v2_cluster_OutlierDetection__Output); 'cleanup_interval': (_google_protobuf_Duration__Output); 'upstream_bind_config': (_envoy_api_v2_core_BindConfig__Output); 'lb_subset_config': (_envoy_api_v2_Cluster_LbSubsetConfig__Output); 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig__Output); - 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig__Output); - 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig__Output); - 'common_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig__Output); 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); 'metadata': (_envoy_api_v2_core_Metadata__Output); 'protocol_selection': (keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + 'common_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig__Output); + 'alt_stat_name': (string); + 'common_http_protocol_options': (_envoy_api_v2_core_HttpProtocolOptions__Output); 'upstream_connection_options': (_envoy_api_v2_UpstreamConnectionOptions__Output); 'close_connections_on_host_health_failure': (boolean); 'drain_connections_on_host_removal': (boolean); + 'load_assignment': (_envoy_api_v2_ClusterLoadAssignment__Output); + 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig__Output); + 'extension_protocol_options': (_google_protobuf_Struct__Output); + 'typed_extension_protocol_options': (_google_protobuf_Any__Output); + 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig__Output); + 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType__Output); + 'respect_dns_ttl': (boolean); 'filters': (_envoy_api_v2_cluster_Filter__Output)[]; 'load_balancing_policy': (_envoy_api_v2_LoadBalancingPolicy__Output); 'lrs_server': (_envoy_api_v2_core_ConfigSource__Output); + 'transport_socket_matches': (_envoy_api_v2_Cluster_TransportSocketMatch__Output)[]; + 'dns_failure_refresh_rate': (_envoy_api_v2_Cluster_RefreshRate__Output); + 'use_tcp_for_dns_lookups': (boolean); + 'upstream_http_protocol_options': (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); 'track_timeout_budgets': (boolean); 'cluster_discovery_type': "type"|"cluster_type"; 'lb_config': "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts index 19508d3c4..4f9c08bb3 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts @@ -33,13 +33,13 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output export interface ClusterLoadAssignment { 'cluster_name'?: (string); 'endpoints'?: (_envoy_api_v2_endpoint_LocalityLbEndpoints)[]; - 'named_endpoints'?: (_envoy_api_v2_endpoint_Endpoint); 'policy'?: (_envoy_api_v2_ClusterLoadAssignment_Policy); + 'named_endpoints'?: (_envoy_api_v2_endpoint_Endpoint); } export interface ClusterLoadAssignment__Output { 'cluster_name': (string); 'endpoints': (_envoy_api_v2_endpoint_LocalityLbEndpoints__Output)[]; - 'named_endpoints': (_envoy_api_v2_endpoint_Endpoint__Output); 'policy': (_envoy_api_v2_ClusterLoadAssignment_Policy__Output); + 'named_endpoints': (_envoy_api_v2_endpoint_Endpoint__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts index 5a6e8c643..53be2989e 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts @@ -6,14 +6,14 @@ export interface DeltaDiscoveryResponse { 'system_version_info'?: (string); 'resources'?: (_envoy_api_v2_Resource)[]; 'type_url'?: (string); - 'removed_resources'?: (string)[]; 'nonce'?: (string); + 'removed_resources'?: (string)[]; } export interface DeltaDiscoveryResponse__Output { 'system_version_info': (string); 'resources': (_envoy_api_v2_Resource__Output)[]; 'type_url': (string); - 'removed_resources': (string)[]; 'nonce': (string); + 'removed_resources': (string)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts index c14e3fdb8..d5a152016 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts @@ -6,28 +6,13 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_p import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from '../../../envoy/api/v2/listener/ListenerFilter'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../envoy/api/v2/core/SocketOption'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from '../../../envoy/api/v2/core/TrafficDirection'; import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from '../../../envoy/api/v2/listener/UdpListenerConfig'; import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from '../../../envoy/config/listener/v2/ApiListener'; import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../envoy/config/filter/accesslog/v2/AccessLog'; -// Original file: deps/envoy-api/envoy/api/v2/listener.proto - -export enum _envoy_api_v2_Listener_DrainType { - DEFAULT = 0, - MODIFY_ONLY = 1, -} - -export interface _envoy_api_v2_Listener_DeprecatedV1 { - 'bind_to_port'?: (_google_protobuf_BoolValue); -} - -export interface _envoy_api_v2_Listener_DeprecatedV1__Output { - 'bind_to_port': (_google_protobuf_BoolValue__Output); -} - export interface _envoy_api_v2_Listener_ConnectionBalanceConfig { 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance); 'balance_type'?: "exact_balance"; @@ -44,6 +29,21 @@ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output { } +export interface _envoy_api_v2_Listener_DeprecatedV1 { + 'bind_to_port'?: (_google_protobuf_BoolValue); +} + +export interface _envoy_api_v2_Listener_DeprecatedV1__Output { + 'bind_to_port': (_google_protobuf_BoolValue__Output); +} + +// Original file: deps/envoy-api/envoy/api/v2/listener.proto + +export enum _envoy_api_v2_Listener_DrainType { + DEFAULT = 0, + MODIFY_ONLY = 1, +} + export interface Listener { 'name'?: (string); 'address'?: (_envoy_api_v2_core_Address); @@ -54,13 +54,13 @@ export interface Listener { 'deprecated_v1'?: (_envoy_api_v2_Listener_DeprecatedV1); 'drain_type'?: (_envoy_api_v2_Listener_DrainType | keyof typeof _envoy_api_v2_Listener_DrainType); 'listener_filters'?: (_envoy_api_v2_listener_ListenerFilter)[]; - 'listener_filters_timeout'?: (_google_protobuf_Duration); - 'continue_on_listener_filters_timeout'?: (boolean); 'transparent'?: (_google_protobuf_BoolValue); 'freebind'?: (_google_protobuf_BoolValue); - 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value); + 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; + 'listener_filters_timeout'?: (_google_protobuf_Duration); 'traffic_direction'?: (_envoy_api_v2_core_TrafficDirection | keyof typeof _envoy_api_v2_core_TrafficDirection); + 'continue_on_listener_filters_timeout'?: (boolean); 'udp_listener_config'?: (_envoy_api_v2_listener_UdpListenerConfig); 'api_listener'?: (_envoy_config_listener_v2_ApiListener); 'connection_balance_config'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig); @@ -78,13 +78,13 @@ export interface Listener__Output { 'deprecated_v1': (_envoy_api_v2_Listener_DeprecatedV1__Output); 'drain_type': (keyof typeof _envoy_api_v2_Listener_DrainType); 'listener_filters': (_envoy_api_v2_listener_ListenerFilter__Output)[]; - 'listener_filters_timeout': (_google_protobuf_Duration__Output); - 'continue_on_listener_filters_timeout': (boolean); 'transparent': (_google_protobuf_BoolValue__Output); 'freebind': (_google_protobuf_BoolValue__Output); - 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; 'tcp_fast_open_queue_length': (_google_protobuf_UInt32Value__Output); + 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; + 'listener_filters_timeout': (_google_protobuf_Duration__Output); 'traffic_direction': (keyof typeof _envoy_api_v2_core_TrafficDirection); + 'continue_on_listener_filters_timeout': (boolean); 'udp_listener_config': (_envoy_api_v2_listener_UdpListenerConfig__Output); 'api_listener': (_envoy_config_listener_v2_ApiListener__Output); 'connection_balance_config': (_envoy_api_v2_Listener_ConnectionBalanceConfig__Output); diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts index 56dae2fc1..965d007d0 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts @@ -3,15 +3,15 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; export interface Resource { - 'name'?: (string); - 'aliases'?: (string)[]; 'version'?: (string); 'resource'?: (_google_protobuf_Any); + 'name'?: (string); + 'aliases'?: (string)[]; } export interface Resource__Output { - 'name': (string); - 'aliases': (string)[]; 'version': (string); 'resource': (_google_protobuf_Any__Output); + 'name': (string); + 'aliases': (string)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts index 5e8c67260..2c25c8b6f 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts @@ -1,32 +1,32 @@ // Original file: deps/envoy-api/envoy/api/v2/route.proto import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from '../../../envoy/api/v2/route/VirtualHost'; -import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../envoy/api/v2/core/HeaderValueOption'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; +import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; export interface RouteConfiguration { 'name'?: (string); 'virtual_hosts'?: (_envoy_api_v2_route_VirtualHost)[]; - 'vhds'?: (_envoy_api_v2_Vhds); 'internal_only_headers'?: (string)[]; 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; 'response_headers_to_remove'?: (string)[]; 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'validate_clusters'?: (_google_protobuf_BoolValue); 'request_headers_to_remove'?: (string)[]; + 'vhds'?: (_envoy_api_v2_Vhds); 'most_specific_header_mutations_wins'?: (boolean); - 'validate_clusters'?: (_google_protobuf_BoolValue); } export interface RouteConfiguration__Output { 'name': (string); 'virtual_hosts': (_envoy_api_v2_route_VirtualHost__Output)[]; - 'vhds': (_envoy_api_v2_Vhds__Output); 'internal_only_headers': (string)[]; 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; 'response_headers_to_remove': (string)[]; 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'validate_clusters': (_google_protobuf_BoolValue__Output); 'request_headers_to_remove': (string)[]; + 'vhds': (_envoy_api_v2_Vhds__Output); 'most_specific_header_mutations_wins': (boolean); - 'validate_clusters': (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts index b34aa4ba2..9aaa2a455 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto @@ -13,26 +13,26 @@ export enum _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerificati export interface CertificateValidationContext { 'trusted_ca'?: (_envoy_api_v2_core_DataSource); - 'verify_certificate_spki'?: (string)[]; 'verify_certificate_hash'?: (string)[]; + 'verify_certificate_spki'?: (string)[]; 'verify_subject_alt_name'?: (string)[]; - 'match_subject_alt_names'?: (_envoy_type_matcher_StringMatcher)[]; 'require_ocsp_staple'?: (_google_protobuf_BoolValue); 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue); 'crl'?: (_envoy_api_v2_core_DataSource); 'allow_expired_certificate'?: (boolean); + 'match_subject_alt_names'?: (_envoy_type_matcher_StringMatcher)[]; 'trust_chain_verification'?: (_envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification | keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); } export interface CertificateValidationContext__Output { 'trusted_ca': (_envoy_api_v2_core_DataSource__Output); - 'verify_certificate_spki': (string)[]; 'verify_certificate_hash': (string)[]; + 'verify_certificate_spki': (string)[]; 'verify_subject_alt_name': (string)[]; - 'match_subject_alt_names': (_envoy_type_matcher_StringMatcher__Output)[]; 'require_ocsp_staple': (_google_protobuf_BoolValue__Output); 'require_signed_certificate_timestamp': (_google_protobuf_BoolValue__Output); 'crl': (_envoy_api_v2_core_DataSource__Output); 'allow_expired_certificate': (boolean); + 'match_subject_alt_names': (_envoy_type_matcher_StringMatcher__Output)[]; 'trust_chain_verification': (keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts index 039ba89c1..aa2db06f6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts @@ -2,8 +2,8 @@ import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from '../../../../envoy/api/v2/auth/TlsParameters'; import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext { 'default_validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); @@ -18,21 +18,21 @@ export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidati export interface CommonTlsContext { 'tls_params'?: (_envoy_api_v2_auth_TlsParameters); 'tls_certificates'?: (_envoy_api_v2_auth_TlsCertificate)[]; - 'tls_certificate_sds_secret_configs'?: (_envoy_api_v2_auth_SdsSecretConfig)[]; 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); + 'alpn_protocols'?: (string)[]; + 'tls_certificate_sds_secret_configs'?: (_envoy_api_v2_auth_SdsSecretConfig)[]; 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext); - 'alpn_protocols'?: (string)[]; 'validation_context_type'?: "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; } export interface CommonTlsContext__Output { 'tls_params': (_envoy_api_v2_auth_TlsParameters__Output); 'tls_certificates': (_envoy_api_v2_auth_TlsCertificate__Output)[]; - 'tls_certificate_sds_secret_configs': (_envoy_api_v2_auth_SdsSecretConfig__Output)[]; 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); + 'alpn_protocols': (string)[]; + 'tls_certificate_sds_secret_configs': (_envoy_api_v2_auth_SdsSecretConfig__Output)[]; 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output); - 'alpn_protocols': (string)[]; 'validation_context_type': "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts index aaef34234..fa731c9c2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts @@ -12,8 +12,8 @@ export interface DownstreamTlsContext { 'require_sni'?: (_google_protobuf_BoolValue); 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); - 'disable_stateless_session_resumption'?: (boolean); 'session_timeout'?: (_google_protobuf_Duration); + 'disable_stateless_session_resumption'?: (boolean); 'session_ticket_keys_type'?: "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; } @@ -23,7 +23,7 @@ export interface DownstreamTlsContext__Output { 'require_sni': (_google_protobuf_BoolValue__Output); 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); - 'disable_stateless_session_resumption'?: (boolean); 'session_timeout': (_google_protobuf_Duration__Output); + 'disable_stateless_session_resumption'?: (boolean); 'session_ticket_keys_type': "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts index 00d786e62..9346e94d6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts @@ -6,17 +6,17 @@ import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKey export interface TlsCertificate { 'certificate_chain'?: (_envoy_api_v2_core_DataSource); 'private_key'?: (_envoy_api_v2_core_DataSource); - 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider); 'password'?: (_envoy_api_v2_core_DataSource); 'ocsp_staple'?: (_envoy_api_v2_core_DataSource); 'signed_certificate_timestamp'?: (_envoy_api_v2_core_DataSource)[]; + 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider); } export interface TlsCertificate__Output { 'certificate_chain': (_envoy_api_v2_core_DataSource__Output); 'private_key': (_envoy_api_v2_core_DataSource__Output); - 'private_key_provider': (_envoy_api_v2_auth_PrivateKeyProvider__Output); 'password': (_envoy_api_v2_core_DataSource__Output); 'ocsp_staple': (_envoy_api_v2_core_DataSource__Output); 'signed_certificate_timestamp': (_envoy_api_v2_core_DataSource__Output)[]; + 'private_key_provider': (_envoy_api_v2_auth_PrivateKeyProvider__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts index 93092c0fa..0d951870e 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from '../../../../envoy/api/v2/core/RateLimitSettings'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto @@ -16,22 +16,22 @@ export enum _envoy_api_v2_core_ApiConfigSource_ApiType { export interface ApiConfigSource { 'api_type'?: (_envoy_api_v2_core_ApiConfigSource_ApiType | keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); - 'transport_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); 'cluster_names'?: (string)[]; - 'grpc_services'?: (_envoy_api_v2_core_GrpcService)[]; 'refresh_delay'?: (_google_protobuf_Duration); + 'grpc_services'?: (_envoy_api_v2_core_GrpcService)[]; 'request_timeout'?: (_google_protobuf_Duration); 'rate_limit_settings'?: (_envoy_api_v2_core_RateLimitSettings); 'set_node_on_first_message_only'?: (boolean); + 'transport_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); } export interface ApiConfigSource__Output { 'api_type': (keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); - 'transport_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); 'cluster_names': (string)[]; - 'grpc_services': (_envoy_api_v2_core_GrpcService__Output)[]; 'refresh_delay': (_google_protobuf_Duration__Output); + 'grpc_services': (_envoy_api_v2_core_GrpcService__Output)[]; 'request_timeout': (_google_protobuf_Duration__Output); 'rate_limit_settings': (_envoy_api_v2_core_RateLimitSettings__Output); 'set_node_on_first_message_only': (boolean); + 'transport_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts index a9cd08e43..9f6952a7f 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts @@ -2,16 +2,16 @@ import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from '../../../../envoy/api/v2/core/ApiConfigSource'; import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from '../../../../envoy/api/v2/core/AggregatedConfigSource'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; export interface ConfigSource { 'path'?: (string); 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource); 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource); - 'self'?: (_envoy_api_v2_core_SelfConfigSource); 'initial_fetch_timeout'?: (_google_protobuf_Duration); + 'self'?: (_envoy_api_v2_core_SelfConfigSource); 'resource_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); 'config_source_specifier'?: "path"|"api_config_source"|"ads"|"self"; } @@ -20,8 +20,8 @@ export interface ConfigSource__Output { 'path'?: (string); 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource__Output); 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource__Output); - 'self'?: (_envoy_api_v2_core_SelfConfigSource__Output); 'initial_fetch_timeout': (_google_protobuf_Duration__Output); + 'self'?: (_envoy_api_v2_core_SelfConfigSource__Output); 'resource_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); 'config_source_specifier': "path"|"api_config_source"|"ads"|"self"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts index 0e8021b19..10fabd16c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts @@ -3,9 +3,9 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; import { Long } from '@grpc/proto-loader'; export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc { @@ -34,38 +34,6 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { 'config': (_google_protobuf_Struct__Output); } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { - 'root_certs'?: (_envoy_api_v2_core_DataSource); - 'private_key'?: (_envoy_api_v2_core_DataSource); - 'cert_chain'?: (_envoy_api_v2_core_DataSource); -} - -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { - 'root_certs': (_envoy_api_v2_core_DataSource__Output); - 'private_key': (_envoy_api_v2_core_DataSource__Output); - 'cert_chain': (_envoy_api_v2_core_DataSource__Output); -} - -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { -} - -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { -} - -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { - 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); - 'google_default'?: (_google_protobuf_Empty); - 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); - 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; -} - -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { - 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); - 'google_default'?: (_google_protobuf_Empty__Output); - 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); - 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; -} - export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { 'access_token'?: (string); 'google_compute_engine'?: (_google_protobuf_Empty); @@ -88,16 +56,6 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Outp 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials { - 'json_key'?: (string); - 'token_lifetime_seconds'?: (number | string | Long); -} - -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output { - 'json_key': (string); - 'token_lifetime_seconds': (string); -} - export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { 'authorization_token'?: (string); 'authority_selector'?: (string); @@ -122,6 +80,16 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_Metad 'config_type': "config"|"typed_config"; } +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials { + 'json_key'?: (string); + 'token_lifetime_seconds'?: (number | string | Long); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output { + 'json_key': (string); + 'token_lifetime_seconds': (string); +} + export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService { 'token_exchange_service_uri'?: (string); 'resource'?: (string); @@ -146,6 +114,38 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsSe 'actor_token_type': (string); } +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { + 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); + 'google_default'?: (_google_protobuf_Empty); + 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); + 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { + 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); + 'google_default'?: (_google_protobuf_Empty__Output); + 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); + 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { + 'root_certs'?: (_envoy_api_v2_core_DataSource); + 'private_key'?: (_envoy_api_v2_core_DataSource); + 'cert_chain'?: (_envoy_api_v2_core_DataSource); +} + +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { + 'root_certs': (_envoy_api_v2_core_DataSource__Output); + 'private_key': (_envoy_api_v2_core_DataSource__Output); + 'cert_chain': (_envoy_api_v2_core_DataSource__Output); +} + export interface GrpcService { 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc); 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc); diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts index 934db81b2..e91ef5dbe 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts @@ -4,24 +4,36 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_prot import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from '../../../../envoy/api/v2/core/EventServiceConfig'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; import { CodecClientType as _envoy_type_CodecClientType } from '../../../../envoy/type/CodecClientType'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { Long } from '@grpc/proto-loader'; -export interface _envoy_api_v2_core_HealthCheck_Payload { - 'text'?: (string); - 'binary'?: (Buffer | Uint8Array | string); - 'payload'?: "text"|"binary"; +export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck { + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "config"|"typed_config"; } -export interface _envoy_api_v2_core_HealthCheck_Payload__Output { - 'text'?: (string); - 'binary'?: (Buffer); - 'payload': "text"|"binary"; +export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output { + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "config"|"typed_config"; +} + +export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { + 'service_name'?: (string); + 'authority'?: (string); +} + +export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { + 'service_name': (string); + 'authority': (string); } export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck { @@ -52,14 +64,16 @@ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { 'service_name_matcher': (_envoy_type_matcher_StringMatcher__Output); } -export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck { - 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); - 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload)[]; +export interface _envoy_api_v2_core_HealthCheck_Payload { + 'text'?: (string); + 'binary'?: (Buffer | Uint8Array | string); + 'payload'?: "text"|"binary"; } -export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { - 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); - 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output)[]; +export interface _envoy_api_v2_core_HealthCheck_Payload__Output { + 'text'?: (string); + 'binary'?: (Buffer); + 'payload': "text"|"binary"; } export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck { @@ -70,28 +84,14 @@ export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck__Output { 'key': (string); } -export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { - 'service_name'?: (string); - 'authority'?: (string); -} - -export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { - 'service_name': (string); - 'authority': (string); -} - -export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck { - 'name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); - 'config_type'?: "config"|"typed_config"; +export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck { + 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload)[]; } -export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output { - 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); - 'config_type': "config"|"typed_config"; +export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { + 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output)[]; } export interface _envoy_api_v2_core_HealthCheck_TlsOptions { @@ -105,9 +105,7 @@ export interface _envoy_api_v2_core_HealthCheck_TlsOptions__Output { export interface HealthCheck { 'timeout'?: (_google_protobuf_Duration); 'interval'?: (_google_protobuf_Duration); - 'initial_jitter'?: (_google_protobuf_Duration); 'interval_jitter'?: (_google_protobuf_Duration); - 'interval_jitter_percent'?: (number); 'unhealthy_threshold'?: (_google_protobuf_UInt32Value); 'healthy_threshold'?: (_google_protobuf_UInt32Value); 'alt_port'?: (_google_protobuf_UInt32Value); @@ -115,24 +113,24 @@ export interface HealthCheck { 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck); 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck); 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck); - 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck); 'no_traffic_interval'?: (_google_protobuf_Duration); + 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck); 'unhealthy_interval'?: (_google_protobuf_Duration); 'unhealthy_edge_interval'?: (_google_protobuf_Duration); 'healthy_edge_interval'?: (_google_protobuf_Duration); 'event_log_path'?: (string); - 'event_service'?: (_envoy_api_v2_core_EventServiceConfig); + 'interval_jitter_percent'?: (number); 'always_log_health_check_failures'?: (boolean); + 'initial_jitter'?: (_google_protobuf_Duration); 'tls_options'?: (_envoy_api_v2_core_HealthCheck_TlsOptions); + 'event_service'?: (_envoy_api_v2_core_EventServiceConfig); 'health_checker'?: "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } export interface HealthCheck__Output { 'timeout': (_google_protobuf_Duration__Output); 'interval': (_google_protobuf_Duration__Output); - 'initial_jitter': (_google_protobuf_Duration__Output); 'interval_jitter': (_google_protobuf_Duration__Output); - 'interval_jitter_percent': (number); 'unhealthy_threshold': (_google_protobuf_UInt32Value__Output); 'healthy_threshold': (_google_protobuf_UInt32Value__Output); 'alt_port': (_google_protobuf_UInt32Value__Output); @@ -140,14 +138,16 @@ export interface HealthCheck__Output { 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output); 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output); 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output); - 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output); 'no_traffic_interval': (_google_protobuf_Duration__Output); + 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output); 'unhealthy_interval': (_google_protobuf_Duration__Output); 'unhealthy_edge_interval': (_google_protobuf_Duration__Output); 'healthy_edge_interval': (_google_protobuf_Duration__Output); 'event_log_path': (string); - 'event_service': (_envoy_api_v2_core_EventServiceConfig__Output); + 'interval_jitter_percent': (number); 'always_log_health_check_failures': (boolean); + 'initial_jitter': (_google_protobuf_Duration__Output); 'tls_options': (_envoy_api_v2_core_HealthCheck_TlsOptions__Output); + 'event_service': (_envoy_api_v2_core_EventServiceConfig__Output); 'health_checker': "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts index f3594ce68..559140a1f 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts @@ -13,16 +13,16 @@ export enum _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction export interface HttpProtocolOptions { 'idle_timeout'?: (_google_protobuf_Duration); - 'max_connection_duration'?: (_google_protobuf_Duration); 'max_headers_count'?: (_google_protobuf_UInt32Value); + 'max_connection_duration'?: (_google_protobuf_Duration); 'max_stream_duration'?: (_google_protobuf_Duration); 'headers_with_underscores_action'?: (_envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction | keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); } export interface HttpProtocolOptions__Output { 'idle_timeout': (_google_protobuf_Duration__Output); - 'max_connection_duration': (_google_protobuf_Duration__Output); 'max_headers_count': (_google_protobuf_UInt32Value__Output); + 'max_connection_duration': (_google_protobuf_Duration__Output); 'max_stream_duration': (_google_protobuf_Duration__Output); 'headers_with_underscores_action': (keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts index cb40e7c95..50d5f46b2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts @@ -7,18 +7,18 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go export interface LbEndpoint { 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint); - 'endpoint_name'?: (string); 'health_status'?: (_envoy_api_v2_core_HealthStatus | keyof typeof _envoy_api_v2_core_HealthStatus); 'metadata'?: (_envoy_api_v2_core_Metadata); 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + 'endpoint_name'?: (string); 'host_identifier'?: "endpoint"|"endpoint_name"; } export interface LbEndpoint__Output { 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint__Output); - 'endpoint_name'?: (string); 'health_status': (keyof typeof _envoy_api_v2_core_HealthStatus); 'metadata': (_envoy_api_v2_core_Metadata__Output); 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + 'endpoint_name'?: (string); 'host_identifier': "endpoint"|"endpoint_name"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts index 4b74a5544..374621458 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from '../../../../envoy/api/v2/core/CidrRange'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto @@ -12,27 +12,27 @@ export enum _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType { } export interface FilterChainMatch { - 'destination_port'?: (_google_protobuf_UInt32Value); 'prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; 'address_suffix'?: (string); 'suffix_len'?: (_google_protobuf_UInt32Value); - 'source_type'?: (_envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); 'source_prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; 'source_ports'?: (number)[]; - 'server_names'?: (string)[]; + 'destination_port'?: (_google_protobuf_UInt32Value); 'transport_protocol'?: (string); 'application_protocols'?: (string)[]; + 'server_names'?: (string)[]; + 'source_type'?: (_envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); } export interface FilterChainMatch__Output { - 'destination_port': (_google_protobuf_UInt32Value__Output); 'prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; 'address_suffix': (string); 'suffix_len': (_google_protobuf_UInt32Value__Output); - 'source_type': (keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); 'source_prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; 'source_ports': (number)[]; - 'server_names': (string)[]; + 'destination_port': (_google_protobuf_UInt32Value__Output); 'transport_protocol': (string); 'application_protocols': (string)[]; + 'server_names': (string)[]; + 'source_type': (keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts index d1f5b11d0..fbb1524f4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts @@ -1,35 +1,35 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; export interface CorsPolicy { 'allow_origin'?: (string)[]; - 'allow_origin_regex'?: (string)[]; - 'allow_origin_string_match'?: (_envoy_type_matcher_StringMatcher)[]; 'allow_methods'?: (string); 'allow_headers'?: (string); 'expose_headers'?: (string); 'max_age'?: (string); 'allow_credentials'?: (_google_protobuf_BoolValue); 'enabled'?: (_google_protobuf_BoolValue); + 'allow_origin_regex'?: (string)[]; 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); 'shadow_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'allow_origin_string_match'?: (_envoy_type_matcher_StringMatcher)[]; 'enabled_specifier'?: "enabled"|"filter_enabled"; } export interface CorsPolicy__Output { 'allow_origin': (string)[]; - 'allow_origin_regex': (string)[]; - 'allow_origin_string_match': (_envoy_type_matcher_StringMatcher__Output)[]; 'allow_methods': (string); 'allow_headers': (string); 'expose_headers': (string); 'max_age': (string); 'allow_credentials': (_google_protobuf_BoolValue__Output); 'enabled'?: (_google_protobuf_BoolValue__Output); + 'allow_origin_regex': (string)[]; 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); 'shadow_enabled': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'allow_origin_string_match': (_envoy_type_matcher_StringMatcher__Output)[]; 'enabled_specifier': "enabled"|"filter_enabled"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts index 97636e12b..6a189d87f 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts @@ -1,19 +1,19 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; import { Long } from '@grpc/proto-loader'; export interface HeaderMatcher { 'name'?: (string); 'exact_match'?: (string); 'regex_match'?: (string); - 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher); 'range_match'?: (_envoy_type_Int64Range); 'present_match'?: (boolean); + 'invert_match'?: (boolean); 'prefix_match'?: (string); 'suffix_match'?: (string); - 'invert_match'?: (boolean); + 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher); 'header_match_specifier'?: "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; } @@ -21,11 +21,11 @@ export interface HeaderMatcher__Output { 'name': (string); 'exact_match'?: (string); 'regex_match'?: (string); - 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher__Output); 'range_match'?: (_envoy_type_Int64Range__Output); 'present_match'?: (boolean); + 'invert_match': (boolean); 'prefix_match'?: (string); 'suffix_match'?: (string); - 'invert_match': (boolean); + 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher__Output); 'header_match_specifier': "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts index 86681d391..b75b9b446 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts @@ -24,34 +24,12 @@ export interface _envoy_api_v2_route_RateLimit_Action__Output { 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; } -export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster { -} - -export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster__Output { -} - export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster { } export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output { } -export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders { - 'header_name'?: (string); - 'descriptor_key'?: (string); -} - -export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output { - 'header_name': (string); - 'descriptor_key': (string); -} - -export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress { -} - -export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output { -} - export interface _envoy_api_v2_route_RateLimit_Action_GenericKey { 'descriptor_value'?: (string); } @@ -72,6 +50,28 @@ export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output { 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; } +export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress { +} + +export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output { +} + +export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders { + 'header_name'?: (string); + 'descriptor_key'?: (string); +} + +export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output { + 'header_name': (string); + 'descriptor_key': (string); +} + +export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster { +} + +export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster__Output { +} + export interface RateLimit { 'stage'?: (_google_protobuf_UInt32Value); 'disable_key'?: (string); diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts index cdd33a9e6..06214c9db 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts @@ -12,27 +12,27 @@ export enum _envoy_api_v2_route_RedirectAction_RedirectResponseCode { } export interface RedirectAction { - 'https_redirect'?: (boolean); - 'scheme_redirect'?: (string); 'host_redirect'?: (string); - 'port_redirect'?: (number); 'path_redirect'?: (string); - 'prefix_rewrite'?: (string); 'response_code'?: (_envoy_api_v2_route_RedirectAction_RedirectResponseCode | keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); + 'https_redirect'?: (boolean); + 'prefix_rewrite'?: (string); 'strip_query'?: (boolean); + 'scheme_redirect'?: (string); + 'port_redirect'?: (number); 'scheme_rewrite_specifier'?: "https_redirect"|"scheme_redirect"; 'path_rewrite_specifier'?: "path_redirect"|"prefix_rewrite"; } export interface RedirectAction__Output { - 'https_redirect'?: (boolean); - 'scheme_redirect'?: (string); 'host_redirect': (string); - 'port_redirect': (number); 'path_redirect'?: (string); - 'prefix_rewrite'?: (string); 'response_code': (keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); + 'https_redirect'?: (boolean); + 'prefix_rewrite'?: (string); 'strip_query': (boolean); + 'scheme_redirect'?: (string); + 'port_redirect': (number); 'scheme_rewrite_specifier': "https_redirect"|"scheme_redirect"; 'path_rewrite_specifier': "path_redirect"|"prefix_rewrite"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts index 6a0be9e43..e43648001 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts @@ -7,44 +7,44 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { Long } from '@grpc/proto-loader'; -export interface _envoy_api_v2_route_RetryPolicy_RetryPriority { +export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff { + 'base_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration); +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff__Output { + 'base_interval': (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output); +} + +export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate { 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); 'config_type'?: "config"|"typed_config"; } -export interface _envoy_api_v2_route_RetryPolicy_RetryPriority__Output { +export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output { 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); 'config_type': "config"|"typed_config"; } -export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate { +export interface _envoy_api_v2_route_RetryPolicy_RetryPriority { 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); 'config_type'?: "config"|"typed_config"; } -export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output { +export interface _envoy_api_v2_route_RetryPolicy_RetryPriority__Output { 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); 'config_type': "config"|"typed_config"; } -export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff { - 'base_interval'?: (_google_protobuf_Duration); - 'max_interval'?: (_google_protobuf_Duration); -} - -export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff__Output { - 'base_interval': (_google_protobuf_Duration__Output); - 'max_interval': (_google_protobuf_Duration__Output); -} - export interface RetryPolicy { 'retry_on'?: (string); 'num_retries'?: (_google_protobuf_UInt32Value); diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts index 700c3ac61..42202684c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts @@ -3,52 +3,52 @@ import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from '../../../../envoy/api/v2/route/RouteMatch'; import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from '../../../../envoy/api/v2/route/RouteAction'; import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from '../../../../envoy/api/v2/route/RedirectAction'; -import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from '../../../../envoy/api/v2/route/DirectResponseAction'; -import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from '../../../../envoy/api/v2/route/Decorator'; +import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from '../../../../envoy/api/v2/route/DirectResponseAction'; import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from '../../../../envoy/api/v2/route/Tracing'; import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; export interface Route { - 'name'?: (string); 'match'?: (_envoy_api_v2_route_RouteMatch); 'route'?: (_envoy_api_v2_route_RouteAction); 'redirect'?: (_envoy_api_v2_route_RedirectAction); - 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction); - 'filter_action'?: (_envoy_api_v2_route_FilterAction); 'metadata'?: (_envoy_api_v2_core_Metadata); 'decorator'?: (_envoy_api_v2_route_Decorator); + 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction); 'per_filter_config'?: (_google_protobuf_Struct); - 'typed_per_filter_config'?: (_google_protobuf_Any); 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; - 'request_headers_to_remove'?: (string)[]; 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; 'response_headers_to_remove'?: (string)[]; + 'request_headers_to_remove'?: (string)[]; + 'typed_per_filter_config'?: (_google_protobuf_Any); + 'name'?: (string); 'tracing'?: (_envoy_api_v2_route_Tracing); 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'filter_action'?: (_envoy_api_v2_route_FilterAction); 'action'?: "route"|"redirect"|"direct_response"|"filter_action"; } export interface Route__Output { - 'name': (string); 'match': (_envoy_api_v2_route_RouteMatch__Output); 'route'?: (_envoy_api_v2_route_RouteAction__Output); 'redirect'?: (_envoy_api_v2_route_RedirectAction__Output); - 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction__Output); - 'filter_action'?: (_envoy_api_v2_route_FilterAction__Output); 'metadata': (_envoy_api_v2_core_Metadata__Output); 'decorator': (_envoy_api_v2_route_Decorator__Output); + 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction__Output); 'per_filter_config': (_google_protobuf_Struct__Output); - 'typed_per_filter_config': (_google_protobuf_Any__Output); 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; - 'request_headers_to_remove': (string)[]; 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; 'response_headers_to_remove': (string)[]; + 'request_headers_to_remove': (string)[]; + 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'name': (string); 'tracing': (_envoy_api_v2_route_Tracing__Output); 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'filter_action'?: (_envoy_api_v2_route_FilterAction__Output); 'action': "route"|"redirect"|"direct_response"|"filter_action"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts index 58f8f1acd..7b58e06ee 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts @@ -2,16 +2,16 @@ import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from '../../../../envoy/api/v2/route/WeightedCluster'; import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/RegexMatchAndSubstitute'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/RegexMatchAndSubstitute'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto @@ -21,27 +21,6 @@ export enum _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode { NOT_FOUND = 1, } -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { - PASS_THROUGH_INTERNAL_REDIRECT = 0, - HANDLE_INTERNAL_REDIRECT = 1, -} - -export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { - 'cluster'?: (string); - 'runtime_key'?: (string); - 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); - 'trace_sampled'?: (_google_protobuf_BoolValue); -} - -export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { - 'cluster': (string); - 'runtime_key': (string); - 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); - 'trace_sampled': (_google_protobuf_BoolValue__Output); -} - export interface _envoy_api_v2_route_RouteAction_HashPolicy { 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header); 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie); @@ -62,12 +41,12 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { 'policy_specifier': "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header { - 'header_name'?: (string); +export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties { + 'source_ip'?: (boolean); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header__Output { - 'header_name': (string); +export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output { + 'source_ip': (boolean); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie { @@ -82,12 +61,20 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output { 'path': (string); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties { - 'source_ip'?: (boolean); +export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState { + 'key'?: (string); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output { - 'source_ip': (boolean); +export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output { + 'key': (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header { + 'header_name'?: (string); +} + +export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header__Output { + 'header_name': (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter { @@ -98,12 +85,25 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Outp 'name': (string); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState { - 'key'?: (string); +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { + PASS_THROUGH_INTERNAL_REDIRECT = 0, + HANDLE_INTERNAL_REDIRECT = 1, } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output { - 'key': (string); +export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { + 'cluster'?: (string); + 'runtime_key'?: (string); + 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'trace_sampled'?: (_google_protobuf_BoolValue); +} + +export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { + 'cluster': (string); + 'runtime_key': (string); + 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'trace_sampled': (_google_protobuf_BoolValue__Output); } export interface _envoy_api_v2_route_RouteAction_UpgradeConfig { @@ -120,30 +120,30 @@ export interface RouteAction { 'cluster'?: (string); 'cluster_header'?: (string); 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster); - 'cluster_not_found_response_code'?: (_envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); 'metadata_match'?: (_envoy_api_v2_core_Metadata); 'prefix_rewrite'?: (string); - 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute); 'host_rewrite'?: (string); 'auto_host_rewrite'?: (_google_protobuf_BoolValue); - 'auto_host_rewrite_header'?: (string); 'timeout'?: (_google_protobuf_Duration); - 'idle_timeout'?: (_google_protobuf_Duration); 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); - 'retry_policy_typed_config'?: (_google_protobuf_Any); 'request_mirror_policy'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy); - 'request_mirror_policies'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy)[]; 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; 'include_vh_rate_limits'?: (_google_protobuf_BoolValue); 'hash_policy'?: (_envoy_api_v2_route_RouteAction_HashPolicy)[]; 'cors'?: (_envoy_api_v2_route_CorsPolicy); + 'cluster_not_found_response_code'?: (_envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); 'max_grpc_timeout'?: (_google_protobuf_Duration); - 'grpc_timeout_offset'?: (_google_protobuf_Duration); + 'idle_timeout'?: (_google_protobuf_Duration); 'upgrade_configs'?: (_envoy_api_v2_route_RouteAction_UpgradeConfig)[]; 'internal_redirect_action'?: (_envoy_api_v2_route_RouteAction_InternalRedirectAction | keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); - 'max_internal_redirects'?: (_google_protobuf_UInt32Value); 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + 'grpc_timeout_offset'?: (_google_protobuf_Duration); + 'auto_host_rewrite_header'?: (string); + 'request_mirror_policies'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy)[]; + 'max_internal_redirects'?: (_google_protobuf_UInt32Value); + 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute); + 'retry_policy_typed_config'?: (_google_protobuf_Any); 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier'?: "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; } @@ -152,30 +152,30 @@ export interface RouteAction__Output { 'cluster'?: (string); 'cluster_header'?: (string); 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster__Output); - 'cluster_not_found_response_code': (keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); 'metadata_match': (_envoy_api_v2_core_Metadata__Output); 'prefix_rewrite': (string); - 'regex_rewrite': (_envoy_type_matcher_RegexMatchAndSubstitute__Output); 'host_rewrite'?: (string); 'auto_host_rewrite'?: (_google_protobuf_BoolValue__Output); - 'auto_host_rewrite_header'?: (string); 'timeout': (_google_protobuf_Duration__Output); - 'idle_timeout': (_google_protobuf_Duration__Output); 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); - 'retry_policy_typed_config': (_google_protobuf_Any__Output); 'request_mirror_policy': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output); - 'request_mirror_policies': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output)[]; 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; 'include_vh_rate_limits': (_google_protobuf_BoolValue__Output); 'hash_policy': (_envoy_api_v2_route_RouteAction_HashPolicy__Output)[]; 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + 'cluster_not_found_response_code': (keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); 'max_grpc_timeout': (_google_protobuf_Duration__Output); - 'grpc_timeout_offset': (_google_protobuf_Duration__Output); + 'idle_timeout': (_google_protobuf_Duration__Output); 'upgrade_configs': (_envoy_api_v2_route_RouteAction_UpgradeConfig__Output)[]; 'internal_redirect_action': (keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); - 'max_internal_redirects': (_google_protobuf_UInt32Value__Output); 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + 'grpc_timeout_offset': (_google_protobuf_Duration__Output); + 'auto_host_rewrite_header'?: (string); + 'request_mirror_policies': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output)[]; + 'max_internal_redirects': (_google_protobuf_UInt32Value__Output); + 'regex_rewrite': (_envoy_type_matcher_RegexMatchAndSubstitute__Output); + 'retry_policy_typed_config': (_google_protobuf_Any__Output); 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier': "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts index 897583eaf..188335bbf 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from '../../../../envoy/api/v2/route/QueryParameterMatcher'; +import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions { } @@ -26,12 +26,12 @@ export interface RouteMatch { 'prefix'?: (string); 'path'?: (string); 'regex'?: (string); - 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); 'case_sensitive'?: (_google_protobuf_BoolValue); - 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; 'query_parameters'?: (_envoy_api_v2_route_QueryParameterMatcher)[]; 'grpc'?: (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions); + 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); 'tls_context'?: (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions); 'path_specifier'?: "prefix"|"path"|"regex"|"safe_regex"; } @@ -40,12 +40,12 @@ export interface RouteMatch__Output { 'prefix'?: (string); 'path'?: (string); 'regex'?: (string); - 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); 'case_sensitive': (_google_protobuf_BoolValue__Output); - 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; 'query_parameters': (_envoy_api_v2_route_QueryParameterMatcher__Output)[]; 'grpc': (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output); + 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); 'tls_context': (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output); 'path_specifier': "prefix"|"path"|"regex"|"safe_regex"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts index e0c23d07a..5596328e5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts @@ -1,18 +1,18 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; import { RequestMethod as _envoy_api_v2_core_RequestMethod } from '../../../../envoy/api/v2/core/RequestMethod'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; export interface VirtualCluster { 'pattern'?: (string); - 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; 'name'?: (string); 'method'?: (_envoy_api_v2_core_RequestMethod | keyof typeof _envoy_api_v2_core_RequestMethod); + 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; } export interface VirtualCluster__Output { 'pattern': (string); - 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; 'name': (string); 'method': (keyof typeof _envoy_api_v2_core_RequestMethod); + 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts index 4d046c805..5126a8e7c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts @@ -27,18 +27,18 @@ export interface VirtualHost { 'virtual_clusters'?: (_envoy_api_v2_route_VirtualCluster)[]; 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; - 'request_headers_to_remove'?: (string)[]; + 'cors'?: (_envoy_api_v2_route_CorsPolicy); 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; 'response_headers_to_remove'?: (string)[]; - 'cors'?: (_envoy_api_v2_route_CorsPolicy); 'per_filter_config'?: (_google_protobuf_Struct); - 'typed_per_filter_config'?: (_google_protobuf_Any); + 'request_headers_to_remove'?: (string)[]; 'include_request_attempt_count'?: (boolean); - 'include_attempt_count_in_response'?: (boolean); + 'typed_per_filter_config'?: (_google_protobuf_Any); 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); - 'retry_policy_typed_config'?: (_google_protobuf_Any); 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'include_attempt_count_in_response'?: (boolean); + 'retry_policy_typed_config'?: (_google_protobuf_Any); } export interface VirtualHost__Output { @@ -49,16 +49,16 @@ export interface VirtualHost__Output { 'virtual_clusters': (_envoy_api_v2_route_VirtualCluster__Output)[]; 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; - 'request_headers_to_remove': (string)[]; + 'cors': (_envoy_api_v2_route_CorsPolicy__Output); 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; 'response_headers_to_remove': (string)[]; - 'cors': (_envoy_api_v2_route_CorsPolicy__Output); 'per_filter_config': (_google_protobuf_Struct__Output); - 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'request_headers_to_remove': (string)[]; 'include_request_attempt_count': (boolean); - 'include_attempt_count_in_response': (boolean); + 'typed_per_filter_config': (_google_protobuf_Any__Output); 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); - 'retry_policy_typed_config': (_google_protobuf_Any__Output); 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'include_attempt_count_in_response': (boolean); + 'retry_policy_typed_config': (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts index 84ad2348b..234ec5da7 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts @@ -32,12 +32,12 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { export interface WeightedCluster { 'clusters'?: (_envoy_api_v2_route_WeightedCluster_ClusterWeight)[]; - 'total_weight'?: (_google_protobuf_UInt32Value); 'runtime_key_prefix'?: (string); + 'total_weight'?: (_google_protobuf_UInt32Value); } export interface WeightedCluster__Output { 'clusters': (_envoy_api_v2_route_WeightedCluster_ClusterWeight__Output)[]; - 'total_weight': (_google_protobuf_UInt32Value__Output); 'runtime_key_prefix': (string); + 'total_weight': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts index 75c47776b..0cf870bec 100644 --- a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts +++ b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts @@ -1,28 +1,28 @@ // Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto -export interface _envoy_type_metadata_v2_MetadataKind_Request { +export interface _envoy_type_metadata_v2_MetadataKind_Cluster { } -export interface _envoy_type_metadata_v2_MetadataKind_Request__Output { +export interface _envoy_type_metadata_v2_MetadataKind_Cluster__Output { } -export interface _envoy_type_metadata_v2_MetadataKind_Route { +export interface _envoy_type_metadata_v2_MetadataKind_Host { } -export interface _envoy_type_metadata_v2_MetadataKind_Route__Output { +export interface _envoy_type_metadata_v2_MetadataKind_Host__Output { } -export interface _envoy_type_metadata_v2_MetadataKind_Cluster { +export interface _envoy_type_metadata_v2_MetadataKind_Request { } -export interface _envoy_type_metadata_v2_MetadataKind_Cluster__Output { +export interface _envoy_type_metadata_v2_MetadataKind_Request__Output { } -export interface _envoy_type_metadata_v2_MetadataKind_Host { +export interface _envoy_type_metadata_v2_MetadataKind_Route { } -export interface _envoy_type_metadata_v2_MetadataKind_Host__Output { +export interface _envoy_type_metadata_v2_MetadataKind_Route__Output { } export interface MetadataKind { diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts index 32baa84be..fef01ffa0 100644 --- a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts +++ b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts @@ -3,14 +3,6 @@ import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from '../../../../envoy/type/metadata/v2/MetadataKind'; import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from '../../../../envoy/type/metadata/v2/MetadataKey'; -export interface _envoy_type_tracing_v2_CustomTag_Literal { - 'value'?: (string); -} - -export interface _envoy_type_tracing_v2_CustomTag_Literal__Output { - 'value': (string); -} - export interface _envoy_type_tracing_v2_CustomTag_Environment { 'name'?: (string); 'default_value'?: (string); @@ -31,6 +23,14 @@ export interface _envoy_type_tracing_v2_CustomTag_Header__Output { 'default_value': (string); } +export interface _envoy_type_tracing_v2_CustomTag_Literal { + 'value'?: (string); +} + +export interface _envoy_type_tracing_v2_CustomTag_Literal__Output { + 'value': (string); +} + export interface _envoy_type_tracing_v2_CustomTag_Metadata { 'kind'?: (_envoy_type_metadata_v2_MetadataKind); 'metadata_key'?: (_envoy_type_metadata_v2_MetadataKey); diff --git a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts index 01ce13ba8..ebdc3e39a 100644 --- a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts +++ b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/api/http.proto +// Original file: deps/googleapis/google/api/http.proto export interface CustomHttpPattern { diff --git a/packages/grpc-js/src/generated/google/api/Http.ts b/packages/grpc-js/src/generated/google/api/Http.ts index 6a04f7b8c..fc3839eb1 100644 --- a/packages/grpc-js/src/generated/google/api/Http.ts +++ b/packages/grpc-js/src/generated/google/api/Http.ts @@ -1,11 +1,13 @@ -// Original file: node_modules/protobufjs/google/api/http.proto +// Original file: deps/googleapis/google/api/http.proto import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface Http { 'rules'?: (_google_api_HttpRule)[]; + 'fully_decode_reserved_expansion'?: (boolean); } export interface Http__Output { 'rules': (_google_api_HttpRule__Output)[]; + 'fully_decode_reserved_expansion': (boolean); } diff --git a/packages/grpc-js/src/generated/google/api/HttpRule.ts b/packages/grpc-js/src/generated/google/api/HttpRule.ts index 3bd9acd2b..3b268a026 100644 --- a/packages/grpc-js/src/generated/google/api/HttpRule.ts +++ b/packages/grpc-js/src/generated/google/api/HttpRule.ts @@ -1,30 +1,32 @@ -// Original file: node_modules/protobufjs/google/api/http.proto +// Original file: deps/googleapis/google/api/http.proto import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface HttpRule { + 'selector'?: (string); 'get'?: (string); 'put'?: (string); 'post'?: (string); 'delete'?: (string); 'patch'?: (string); - 'custom'?: (_google_api_CustomHttpPattern); - 'selector'?: (string); 'body'?: (string); + 'custom'?: (_google_api_CustomHttpPattern); 'additional_bindings'?: (_google_api_HttpRule)[]; + 'response_body'?: (string); 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; } export interface HttpRule__Output { + 'selector': (string); 'get'?: (string); 'put'?: (string); 'post'?: (string); 'delete'?: (string); 'patch'?: (string); - 'custom'?: (_google_api_CustomHttpPattern__Output); - 'selector': (string); 'body': (string); + 'custom'?: (_google_api_CustomHttpPattern__Output); 'additional_bindings': (_google_api_HttpRule__Output)[]; + 'response_body': (string); 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; } diff --git a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts index 97726c403..423ec0f03 100644 --- a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts @@ -1,10 +1,10 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; export interface _google_protobuf_DescriptorProto_ExtensionRange { 'start'?: (number); @@ -29,25 +29,25 @@ export interface _google_protobuf_DescriptorProto_ReservedRange__Output { export interface DescriptorProto { 'name'?: (string); 'field'?: (_google_protobuf_FieldDescriptorProto)[]; + 'nestedType'?: (_google_protobuf_DescriptorProto)[]; + 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; + 'extensionRange'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'nested_type'?: (_google_protobuf_DescriptorProto)[]; - 'enum_type'?: (_google_protobuf_EnumDescriptorProto)[]; - 'extension_range'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; - 'oneof_decl'?: (_google_protobuf_OneofDescriptorProto)[]; 'options'?: (_google_protobuf_MessageOptions); - 'reserved_range'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; - 'reserved_name'?: (string)[]; + 'oneofDecl'?: (_google_protobuf_OneofDescriptorProto)[]; + 'reservedRange'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; + 'reservedName'?: (string)[]; } export interface DescriptorProto__Output { 'name': (string); 'field': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'nestedType': (_google_protobuf_DescriptorProto__Output)[]; + 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; + 'extensionRange': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'nested_type': (_google_protobuf_DescriptorProto__Output)[]; - 'enum_type': (_google_protobuf_EnumDescriptorProto__Output)[]; - 'extension_range': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; - 'oneof_decl': (_google_protobuf_OneofDescriptorProto__Output)[]; 'options': (_google_protobuf_MessageOptions__Output); - 'reserved_range': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; - 'reserved_name': (string)[]; + 'oneofDecl': (_google_protobuf_OneofDescriptorProto__Output)[]; + 'reservedRange': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; + 'reservedName': (string)[]; } diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts index 55059ba9e..5c5f2b7bb 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts index 1c096a306..9671ecc31 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts @@ -1,18 +1,18 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumOptions { - 'allow_alias'?: (boolean); + 'allowAlias'?: (boolean); 'deprecated'?: (boolean); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation); } export interface EnumOptions__Output { - 'allow_alias': (boolean); + 'allowAlias': (boolean); 'deprecated': (boolean); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.udpa.annotations.enum_migrate': (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts index a0b8308d8..042c82ff9 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts index 29c560438..2d4036158 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts @@ -1,18 +1,18 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumValueOptions { 'deprecated'?: (boolean); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.envoy.annotations.disallowed_by_default_enum'?: (boolean); + '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation); } export interface EnumValueOptions__Output { 'deprecated': (boolean); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.envoy.annotations.disallowed_by_default_enum': (boolean); + '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts index b5c089c9c..f9c52a7e1 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts @@ -1,8 +1,16 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null + +export enum _google_protobuf_FieldDescriptorProto_Label { + LABEL_OPTIONAL = 1, + LABEL_REQUIRED = 2, + LABEL_REPEATED = 3, +} + +// Original file: null export enum _google_protobuf_FieldDescriptorProto_Type { TYPE_DOUBLE = 1, @@ -25,36 +33,28 @@ export enum _google_protobuf_FieldDescriptorProto_Type { TYPE_SINT64 = 18, } -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto - -export enum _google_protobuf_FieldDescriptorProto_Label { - LABEL_OPTIONAL = 1, - LABEL_REQUIRED = 2, - LABEL_REPEATED = 3, -} - export interface FieldDescriptorProto { 'name'?: (string); + 'extendee'?: (string); 'number'?: (number); 'label'?: (_google_protobuf_FieldDescriptorProto_Label | keyof typeof _google_protobuf_FieldDescriptorProto_Label); 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); - 'type_name'?: (string); - 'extendee'?: (string); - 'default_value'?: (string); - 'oneof_index'?: (number); - 'json_name'?: (string); + 'typeName'?: (string); + 'defaultValue'?: (string); 'options'?: (_google_protobuf_FieldOptions); + 'oneofIndex'?: (number); + 'jsonName'?: (string); } export interface FieldDescriptorProto__Output { 'name': (string); + 'extendee': (string); 'number': (number); 'label': (keyof typeof _google_protobuf_FieldDescriptorProto_Label); 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); - 'type_name': (string); - 'extendee': (string); - 'default_value': (string); - 'oneof_index': (number); - 'json_name': (string); + 'typeName': (string); + 'defaultValue': (string); 'options': (_google_protobuf_FieldOptions__Output); + 'oneofIndex': (number); + 'jsonName': (string); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts index d2bec450d..dcba8be7c 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts @@ -1,10 +1,10 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null export enum _google_protobuf_FieldOptions_CType { STRING = 0, @@ -12,7 +12,7 @@ export enum _google_protobuf_FieldOptions_CType { STRING_PIECE = 2, } -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null export enum _google_protobuf_FieldOptions_JSType { JS_NORMAL = 0, @@ -23,27 +23,27 @@ export enum _google_protobuf_FieldOptions_JSType { export interface FieldOptions { 'ctype'?: (_google_protobuf_FieldOptions_CType | keyof typeof _google_protobuf_FieldOptions_CType); 'packed'?: (boolean); - 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); - 'lazy'?: (boolean); 'deprecated'?: (boolean); + 'lazy'?: (boolean); + 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); 'weak'?: (boolean); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.rules'?: (_validate_FieldRules); - '.envoy.annotations.disallowed_by_default'?: (boolean); '.udpa.annotations.sensitive'?: (boolean); + '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation); + '.envoy.annotations.disallowed_by_default'?: (boolean); } export interface FieldOptions__Output { 'ctype': (keyof typeof _google_protobuf_FieldOptions_CType); 'packed': (boolean); - 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); - 'lazy': (boolean); 'deprecated': (boolean); + 'lazy': (boolean); + 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); 'weak': (boolean); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.rules': (_validate_FieldRules__Output); - '.envoy.annotations.disallowed_by_default': (boolean); '.udpa.annotations.sensitive': (boolean); + '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output); + '.envoy.annotations.disallowed_by_default': (boolean); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts index aeebbf242..fd69f164e 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; @@ -11,14 +11,14 @@ export interface FileDescriptorProto { 'name'?: (string); 'package'?: (string); 'dependency'?: (string)[]; - 'public_dependency'?: (number)[]; - 'weak_dependency'?: (number)[]; - 'message_type'?: (_google_protobuf_DescriptorProto)[]; - 'enum_type'?: (_google_protobuf_EnumDescriptorProto)[]; + 'messageType'?: (_google_protobuf_DescriptorProto)[]; + 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; 'service'?: (_google_protobuf_ServiceDescriptorProto)[]; 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; 'options'?: (_google_protobuf_FileOptions); - 'source_code_info'?: (_google_protobuf_SourceCodeInfo); + 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo); + 'publicDependency'?: (number)[]; + 'weakDependency'?: (number)[]; 'syntax'?: (string); } @@ -26,13 +26,13 @@ export interface FileDescriptorProto__Output { 'name': (string); 'package': (string); 'dependency': (string)[]; - 'public_dependency': (number)[]; - 'weak_dependency': (number)[]; - 'message_type': (_google_protobuf_DescriptorProto__Output)[]; - 'enum_type': (_google_protobuf_EnumDescriptorProto__Output)[]; + 'messageType': (_google_protobuf_DescriptorProto__Output)[]; + 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; 'options': (_google_protobuf_FileOptions__Output); - 'source_code_info': (_google_protobuf_SourceCodeInfo__Output); + 'sourceCodeInfo': (_google_protobuf_SourceCodeInfo__Output); + 'publicDependency': (number)[]; + 'weakDependency': (number)[]; 'syntax': (string); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts index b30f4679c..f01cabc4c 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; diff --git a/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts index 337f38d82..ac556b3be 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts @@ -1,10 +1,10 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null export enum _google_protobuf_FileOptions_OptimizeMode { SPEED = 1, @@ -13,41 +13,41 @@ export enum _google_protobuf_FileOptions_OptimizeMode { } export interface FileOptions { - 'java_package'?: (string); - 'java_outer_classname'?: (string); - 'java_multiple_files'?: (boolean); - 'java_generate_equals_and_hash'?: (boolean); - 'java_string_check_utf8'?: (boolean); - 'optimize_for'?: (_google_protobuf_FileOptions_OptimizeMode | keyof typeof _google_protobuf_FileOptions_OptimizeMode); - 'go_package'?: (string); - 'cc_generic_services'?: (boolean); - 'java_generic_services'?: (boolean); - 'py_generic_services'?: (boolean); + 'javaPackage'?: (string); + 'javaOuterClassname'?: (string); + 'optimizeFor'?: (_google_protobuf_FileOptions_OptimizeMode | keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'javaMultipleFiles'?: (boolean); + 'goPackage'?: (string); + 'ccGenericServices'?: (boolean); + 'javaGenericServices'?: (boolean); + 'pyGenericServices'?: (boolean); + 'javaGenerateEqualsAndHash'?: (boolean); 'deprecated'?: (boolean); - 'cc_enable_arenas'?: (boolean); - 'objc_class_prefix'?: (string); - 'csharp_namespace'?: (string); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + 'javaStringCheckUtf8'?: (boolean); + 'ccEnableArenas'?: (boolean); + 'objcClassPrefix'?: (string); + 'csharpNamespace'?: (string); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation); '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation); } export interface FileOptions__Output { - 'java_package': (string); - 'java_outer_classname': (string); - 'java_multiple_files': (boolean); - 'java_generate_equals_and_hash': (boolean); - 'java_string_check_utf8': (boolean); - 'optimize_for': (keyof typeof _google_protobuf_FileOptions_OptimizeMode); - 'go_package': (string); - 'cc_generic_services': (boolean); - 'java_generic_services': (boolean); - 'py_generic_services': (boolean); + 'javaPackage': (string); + 'javaOuterClassname': (string); + 'optimizeFor': (keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'javaMultipleFiles': (boolean); + 'goPackage': (string); + 'ccGenericServices': (boolean); + 'javaGenericServices': (boolean); + 'pyGenericServices': (boolean); + 'javaGenerateEqualsAndHash': (boolean); 'deprecated': (boolean); - 'cc_enable_arenas': (boolean); - 'objc_class_prefix': (string); - 'csharp_namespace': (string); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + 'javaStringCheckUtf8': (boolean); + 'ccEnableArenas': (boolean); + 'objcClassPrefix': (string); + 'csharpNamespace': (string); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.udpa.annotations.file_migrate': (_udpa_annotations_FileMigrateAnnotation__Output); '.udpa.annotations.file_status': (_udpa_annotations_StatusAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts b/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts index f925dbff1..019fb0e15 100644 --- a/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts +++ b/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts @@ -1,16 +1,16 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null export interface _google_protobuf_GeneratedCodeInfo_Annotation { 'path'?: (number)[]; - 'source_file'?: (string); + 'sourceFile'?: (string); 'begin'?: (number); 'end'?: (number); } export interface _google_protobuf_GeneratedCodeInfo_Annotation__Output { 'path': (number)[]; - 'source_file': (string); + 'sourceFile': (string); 'begin': (number); 'end': (number); } diff --git a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts index ec6508b0c..4bdb411ec 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts @@ -1,24 +1,24 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface MessageOptions { - 'message_set_wire_format'?: (boolean); - 'no_standard_descriptor_accessor'?: (boolean); + 'messageSetWireFormat'?: (boolean); + 'noStandardDescriptorAccessor'?: (boolean); 'deprecated'?: (boolean); - 'map_entry'?: (boolean); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation); + 'mapEntry'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.disabled'?: (boolean); + '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation); } export interface MessageOptions__Output { - 'message_set_wire_format': (boolean); - 'no_standard_descriptor_accessor': (boolean); + 'messageSetWireFormat': (boolean); + 'noStandardDescriptorAccessor': (boolean); 'deprecated': (boolean); - 'map_entry': (boolean); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output); + 'mapEntry': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.disabled': (boolean); + '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts index a378ab637..2457567b0 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts @@ -1,21 +1,21 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; export interface MethodDescriptorProto { 'name'?: (string); - 'input_type'?: (string); - 'output_type'?: (string); + 'inputType'?: (string); + 'outputType'?: (string); 'options'?: (_google_protobuf_MethodOptions); - 'client_streaming'?: (boolean); - 'server_streaming'?: (boolean); + 'clientStreaming'?: (boolean); + 'serverStreaming'?: (boolean); } export interface MethodDescriptorProto__Output { 'name': (string); - 'input_type': (string); - 'output_type': (string); + 'inputType': (string); + 'outputType': (string); 'options': (_google_protobuf_MethodOptions__Output); - 'client_streaming': (boolean); - 'server_streaming': (boolean); + 'clientStreaming': (boolean); + 'serverStreaming': (boolean); } diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts index 582ba4bef..d2bbd8516 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts @@ -1,16 +1,16 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface MethodOptions { 'deprecated'?: (boolean); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.google.api.http'?: (_google_api_HttpRule); } export interface MethodOptions__Output { 'deprecated': (boolean); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.google.api.http': (_google_api_HttpRule__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts index 084cabff5..ab1f85e6e 100644 --- a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts b/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts index ea07ab22f..01fdc9d2b 100644 --- a/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts @@ -1,13 +1,13 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface OneofOptions { - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.required'?: (boolean); } export interface OneofOptions__Output { - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.required': (boolean); } diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts index aab7736ce..0e0bd5bab 100644 --- a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts @@ -1,4 +1,4 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts index 602e670ad..c1bd83603 100644 --- a/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts @@ -1,13 +1,13 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface ServiceOptions { 'deprecated'?: (boolean); - 'uninterpreted_option'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; } export interface ServiceOptions__Output { 'deprecated': (boolean); - 'uninterpreted_option': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; } diff --git a/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts b/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts index cf68f3ac1..d30e59b4f 100644 --- a/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts +++ b/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts @@ -1,20 +1,20 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null export interface _google_protobuf_SourceCodeInfo_Location { 'path'?: (number)[]; 'span'?: (number)[]; - 'leading_comments'?: (string); - 'trailing_comments'?: (string); - 'leading_detached_comments'?: (string)[]; + 'leadingComments'?: (string); + 'trailingComments'?: (string); + 'leadingDetachedComments'?: (string)[]; } export interface _google_protobuf_SourceCodeInfo_Location__Output { 'path': (number)[]; 'span': (number)[]; - 'leading_comments': (string); - 'trailing_comments': (string); - 'leading_detached_comments': (string)[]; + 'leadingComments': (string); + 'trailingComments': (string); + 'leadingDetachedComments': (string)[]; } export interface SourceCodeInfo { diff --git a/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts b/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts index 770394761..91e3b99bc 100644 --- a/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts +++ b/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts @@ -1,33 +1,33 @@ -// Original file: node_modules/protobufjs/google/protobuf/descriptor.proto +// Original file: null import { Long } from '@grpc/proto-loader'; export interface _google_protobuf_UninterpretedOption_NamePart { - 'name_part'?: (string); - 'is_extension'?: (boolean); + 'namePart'?: (string); + 'isExtension'?: (boolean); } export interface _google_protobuf_UninterpretedOption_NamePart__Output { - 'name_part': (string); - 'is_extension': (boolean); + 'namePart': (string); + 'isExtension': (boolean); } export interface UninterpretedOption { 'name'?: (_google_protobuf_UninterpretedOption_NamePart)[]; - 'identifier_value'?: (string); - 'positive_int_value'?: (number | string | Long); - 'negative_int_value'?: (number | string | Long); - 'double_value'?: (number | string); - 'string_value'?: (Buffer | Uint8Array | string); - 'aggregate_value'?: (string); + 'identifierValue'?: (string); + 'positiveIntValue'?: (number | string | Long); + 'negativeIntValue'?: (number | string | Long); + 'doubleValue'?: (number | string); + 'stringValue'?: (Buffer | Uint8Array | string); + 'aggregateValue'?: (string); } export interface UninterpretedOption__Output { 'name': (_google_protobuf_UninterpretedOption_NamePart__Output)[]; - 'identifier_value': (string); - 'positive_int_value': (string); - 'negative_int_value': (string); - 'double_value': (number | string); - 'string_value': (Buffer); - 'aggregate_value': (string); + 'identifierValue': (string); + 'positiveIntValue': (string); + 'negativeIntValue': (string); + 'doubleValue': (number | string); + 'stringValue': (Buffer); + 'aggregateValue': (string); } diff --git a/packages/grpc-js/src/generated/listener.ts b/packages/grpc-js/src/generated/listener.ts index ef657d3a3..65a514ab7 100644 --- a/packages/grpc-js/src/generated/listener.ts +++ b/packages/grpc-js/src/generated/listener.ts @@ -2,339 +2,335 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { Listener as _envoy_api_v2_Listener, Listener__Output as _envoy_api_v2_Listener__Output } from './envoy/api/v2/Listener'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; +import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; +import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; +import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; +import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; +import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; +import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; +import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; +import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; +import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; +import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; +import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; +import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { ActiveRawUdpListenerConfig as _envoy_api_v2_listener_ActiveRawUdpListenerConfig, ActiveRawUdpListenerConfig__Output as _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output } from './envoy/api/v2/listener/ActiveRawUdpListenerConfig'; import { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from './envoy/api/v2/listener/Filter'; -import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from './envoy/api/v2/listener/FilterChainMatch'; import { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from './envoy/api/v2/listener/FilterChain'; -import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from './envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; +import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from './envoy/api/v2/listener/FilterChainMatch'; import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from './envoy/api/v2/listener/ListenerFilter'; +import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from './envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from './envoy/api/v2/listener/UdpListenerConfig'; -import { ActiveRawUdpListenerConfig as _envoy_api_v2_listener_ActiveRawUdpListenerConfig, ActiveRawUdpListenerConfig__Output as _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output } from './envoy/api/v2/listener/ActiveRawUdpListenerConfig'; -import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; -import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; -import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; -import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; -import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; -import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; -import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; -import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; -import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; -import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; -import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; -import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; -import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; -import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; -import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from './envoy/api/v2/route/CorsPolicy'; -import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; -import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; +import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; +import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; +import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from './envoy/api/v2/route/HedgePolicy'; +import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; +import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from './envoy/api/v2/route/RedirectAction'; -import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; -import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; +import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; +import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; +import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; +import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from './envoy/api/v2/route/Tracing'; import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from './envoy/api/v2/route/VirtualCluster'; -import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; -import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; -import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from './envoy/config/listener/v2/ApiListener'; +import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; +import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from './envoy/config/filter/accesslog/v2/AccessLog'; import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from './envoy/config/filter/accesslog/v2/AccessLogFilter'; +import { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from './envoy/config/filter/accesslog/v2/AndFilter'; import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from './envoy/config/filter/accesslog/v2/ComparisonFilter'; -import { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from './envoy/config/filter/accesslog/v2/StatusCodeFilter'; import { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from './envoy/config/filter/accesslog/v2/DurationFilter'; +import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from './envoy/config/filter/accesslog/v2/ExtensionFilter'; +import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from './envoy/config/filter/accesslog/v2/GrpcStatusFilter'; +import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from './envoy/config/filter/accesslog/v2/HeaderFilter'; import { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from './envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; -import { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from './envoy/config/filter/accesslog/v2/TraceableFilter'; -import { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from './envoy/config/filter/accesslog/v2/RuntimeFilter'; -import { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from './envoy/config/filter/accesslog/v2/AndFilter'; import { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from './envoy/config/filter/accesslog/v2/OrFilter'; -import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from './envoy/config/filter/accesslog/v2/HeaderFilter'; import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from './envoy/config/filter/accesslog/v2/ResponseFlagFilter'; -import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from './envoy/config/filter/accesslog/v2/GrpcStatusFilter'; -import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from './envoy/config/filter/accesslog/v2/ExtensionFilter'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from './envoy/config/filter/accesslog/v2/RuntimeFilter'; +import { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from './envoy/config/filter/accesslog/v2/StatusCodeFilter'; +import { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from './envoy/config/filter/accesslog/v2/TraceableFilter'; +import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from './envoy/config/listener/v2/ApiListener'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; +import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; +import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; export namespace messages { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export type Listener = _envoy_api_v2_Listener; export type Listener__Output = _envoy_api_v2_Listener__Output; + export namespace auth { + export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; + export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; + export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; + export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; + export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; + export type GenericSecret = _envoy_api_v2_auth_GenericSecret; + export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; + export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; + export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; + export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; + export type Secret = _envoy_api_v2_auth_Secret; + export type Secret__Output = _envoy_api_v2_auth_Secret__Output; + export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; + export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; + export type TlsParameters = _envoy_api_v2_auth_TlsParameters; + export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; + export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; + export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; + export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; + export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; + } export namespace core { - export type SocketOption = _envoy_api_v2_core_SocketOption; - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; export type Address = _envoy_api_v2_core_Address; export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - export type Locality = _envoy_api_v2_core_Locality; - export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; export type BuildVersion = _envoy_api_v2_core_BuildVersion; export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; export type Extension = _envoy_api_v2_core_Extension; export type Extension__Output = _envoy_api_v2_core_Extension__Output; - export type Node = _envoy_api_v2_core_Node; - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Metadata = _envoy_api_v2_core_Metadata; - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; export type HeaderValue = _envoy_api_v2_core_HeaderValue; export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - export type DataSource = _envoy_api_v2_core_DataSource; - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; - export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; - export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - export type GrpcService = _envoy_api_v2_core_GrpcService; - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type SocketAddress = _envoy_api_v2_core_SocketAddress; + export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + export type SocketOption = _envoy_api_v2_core_SocketOption; + export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; } export namespace listener { + export type ActiveRawUdpListenerConfig = _envoy_api_v2_listener_ActiveRawUdpListenerConfig; + export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; export type Filter = _envoy_api_v2_listener_Filter; export type Filter__Output = _envoy_api_v2_listener_Filter__Output; - export type FilterChainMatch = _envoy_api_v2_listener_FilterChainMatch; - export type FilterChainMatch__Output = _envoy_api_v2_listener_FilterChainMatch__Output; export type FilterChain = _envoy_api_v2_listener_FilterChain; export type FilterChain__Output = _envoy_api_v2_listener_FilterChain__Output; - export type ListenerFilterChainMatchPredicate = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate; - export type ListenerFilterChainMatchPredicate__Output = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output; + export type FilterChainMatch = _envoy_api_v2_listener_FilterChainMatch; + export type FilterChainMatch__Output = _envoy_api_v2_listener_FilterChainMatch__Output; export type ListenerFilter = _envoy_api_v2_listener_ListenerFilter; export type ListenerFilter__Output = _envoy_api_v2_listener_ListenerFilter__Output; - export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; - export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; - export type ActiveRawUdpListenerConfig = _envoy_api_v2_listener_ActiveRawUdpListenerConfig; - export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; - } - export namespace auth { - export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; - export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; - export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; - export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; - export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; - export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; - export type TlsParameters = _envoy_api_v2_auth_TlsParameters; - export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; - export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; - export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; - export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; - export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; - export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; - export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; - export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; - export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; - export type GenericSecret = _envoy_api_v2_auth_GenericSecret; - export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; - export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; - export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; - export type Secret = _envoy_api_v2_auth_Secret; - export type Secret__Output = _envoy_api_v2_auth_Secret__Output; + export type ListenerFilterChainMatchPredicate = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate; + export type ListenerFilterChainMatchPredicate__Output = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output; + export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; + export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; } export namespace route { - export type VirtualHost = _envoy_api_v2_route_VirtualHost; - export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; - export type FilterAction = _envoy_api_v2_route_FilterAction; - export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; - export type Route = _envoy_api_v2_route_Route; - export type Route__Output = _envoy_api_v2_route_Route__Output; - export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; - export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; - export type RouteMatch = _envoy_api_v2_route_RouteMatch; - export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; - export type RouteAction = _envoy_api_v2_route_RouteAction; - export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; - export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + export type Decorator = _envoy_api_v2_route_Decorator; + export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; + export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; + export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; + export type FilterAction = _envoy_api_v2_route_FilterAction; + export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; + export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; + export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; + export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; + export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + export type RateLimit = _envoy_api_v2_route_RateLimit; + export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; export type RedirectAction = _envoy_api_v2_route_RedirectAction; export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; - export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; - export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; - export type Decorator = _envoy_api_v2_route_Decorator; - export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; + export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + export type Route = _envoy_api_v2_route_Route; + export type Route__Output = _envoy_api_v2_route_Route__Output; + export type RouteAction = _envoy_api_v2_route_RouteAction; + export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; + export type RouteMatch = _envoy_api_v2_route_RouteMatch; + export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; export type Tracing = _envoy_api_v2_route_Tracing; export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; - export type RateLimit = _envoy_api_v2_route_RateLimit; - export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; - export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; - export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; - export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; - export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + export type VirtualHost = _envoy_api_v2_route_VirtualHost; + export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; + export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; + export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; } } } export namespace config { - export namespace listener { - export namespace v2 { - export type ApiListener = _envoy_config_listener_v2_ApiListener; - export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; - } - } export namespace filter { export namespace accesslog { export namespace v2 { @@ -342,62 +338,62 @@ export namespace messages { export type AccessLog__Output = _envoy_config_filter_accesslog_v2_AccessLog__Output; export type AccessLogFilter = _envoy_config_filter_accesslog_v2_AccessLogFilter; export type AccessLogFilter__Output = _envoy_config_filter_accesslog_v2_AccessLogFilter__Output; + export type AndFilter = _envoy_config_filter_accesslog_v2_AndFilter; + export type AndFilter__Output = _envoy_config_filter_accesslog_v2_AndFilter__Output; export type ComparisonFilter = _envoy_config_filter_accesslog_v2_ComparisonFilter; export type ComparisonFilter__Output = _envoy_config_filter_accesslog_v2_ComparisonFilter__Output; - export type StatusCodeFilter = _envoy_config_filter_accesslog_v2_StatusCodeFilter; - export type StatusCodeFilter__Output = _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output; export type DurationFilter = _envoy_config_filter_accesslog_v2_DurationFilter; export type DurationFilter__Output = _envoy_config_filter_accesslog_v2_DurationFilter__Output; + export type ExtensionFilter = _envoy_config_filter_accesslog_v2_ExtensionFilter; + export type ExtensionFilter__Output = _envoy_config_filter_accesslog_v2_ExtensionFilter__Output; + export type GrpcStatusFilter = _envoy_config_filter_accesslog_v2_GrpcStatusFilter; + export type GrpcStatusFilter__Output = _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output; + export type HeaderFilter = _envoy_config_filter_accesslog_v2_HeaderFilter; + export type HeaderFilter__Output = _envoy_config_filter_accesslog_v2_HeaderFilter__Output; export type NotHealthCheckFilter = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter; export type NotHealthCheckFilter__Output = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output; - export type TraceableFilter = _envoy_config_filter_accesslog_v2_TraceableFilter; - export type TraceableFilter__Output = _envoy_config_filter_accesslog_v2_TraceableFilter__Output; - export type RuntimeFilter = _envoy_config_filter_accesslog_v2_RuntimeFilter; - export type RuntimeFilter__Output = _envoy_config_filter_accesslog_v2_RuntimeFilter__Output; - export type AndFilter = _envoy_config_filter_accesslog_v2_AndFilter; - export type AndFilter__Output = _envoy_config_filter_accesslog_v2_AndFilter__Output; export type OrFilter = _envoy_config_filter_accesslog_v2_OrFilter; export type OrFilter__Output = _envoy_config_filter_accesslog_v2_OrFilter__Output; - export type HeaderFilter = _envoy_config_filter_accesslog_v2_HeaderFilter; - export type HeaderFilter__Output = _envoy_config_filter_accesslog_v2_HeaderFilter__Output; export type ResponseFlagFilter = _envoy_config_filter_accesslog_v2_ResponseFlagFilter; export type ResponseFlagFilter__Output = _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output; - export type GrpcStatusFilter = _envoy_config_filter_accesslog_v2_GrpcStatusFilter; - export type GrpcStatusFilter__Output = _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output; - export type ExtensionFilter = _envoy_config_filter_accesslog_v2_ExtensionFilter; - export type ExtensionFilter__Output = _envoy_config_filter_accesslog_v2_ExtensionFilter__Output; + export type RuntimeFilter = _envoy_config_filter_accesslog_v2_RuntimeFilter; + export type RuntimeFilter__Output = _envoy_config_filter_accesslog_v2_RuntimeFilter__Output; + export type StatusCodeFilter = _envoy_config_filter_accesslog_v2_StatusCodeFilter; + export type StatusCodeFilter__Output = _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output; + export type TraceableFilter = _envoy_config_filter_accesslog_v2_TraceableFilter; + export type TraceableFilter__Output = _envoy_config_filter_accesslog_v2_TraceableFilter__Output; } } } + export namespace listener { + export namespace v2 { + export type ApiListener = _envoy_config_listener_v2_ApiListener; + export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; + } + } } export namespace type { - export type Percent = _envoy_type_Percent; - export type Percent__Output = _envoy_type_Percent__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - export type Int64Range = _envoy_type_Int64Range; - export type Int64Range__Output = _envoy_type_Int64Range__Output; export type Int32Range = _envoy_type_Int32Range; export type Int32Range__Output = _envoy_type_Int32Range__Output; - export type DoubleRange = _envoy_type_DoubleRange; - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; export type SemanticVersion = _envoy_type_SemanticVersion; export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; export type StringMatcher = _envoy_type_matcher_StringMatcher; export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - } - export namespace tracing { - export namespace v2 { - export type CustomTag = _envoy_type_tracing_v2_CustomTag; - export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; - } } export namespace metadata { export namespace v2 { @@ -407,390 +403,390 @@ export namespace messages { export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; } } + export namespace tracing { + export namespace v2 { + export type CustomTag = _envoy_type_tracing_v2_CustomTag; + export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; + } + } } - export namespace annotations { - } - } - export namespace udpa { - export namespace annotations { - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - export type FieldRules = _validate_FieldRules; - export type FieldRules__Output = _validate_FieldRules__Output; - export type FloatRules = _validate_FloatRules; - export type FloatRules__Output = _validate_FloatRules__Output; - export type DoubleRules = _validate_DoubleRules; - export type DoubleRules__Output = _validate_DoubleRules__Output; - export type Int32Rules = _validate_Int32Rules; - export type Int32Rules__Output = _validate_Int32Rules__Output; - export type Int64Rules = _validate_Int64Rules; - export type Int64Rules__Output = _validate_Int64Rules__Output; - export type UInt32Rules = _validate_UInt32Rules; - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - export type UInt64Rules = _validate_UInt64Rules; - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - export type SInt32Rules = _validate_SInt32Rules; - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - export type SInt64Rules = _validate_SInt64Rules; - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - export type Fixed32Rules = _validate_Fixed32Rules; - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - export type Fixed64Rules = _validate_Fixed64Rules; - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - export type SFixed32Rules = _validate_SFixed32Rules; - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - export type SFixed64Rules = _validate_SFixed64Rules; - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - export type BoolRules = _validate_BoolRules; - export type BoolRules__Output = _validate_BoolRules__Output; - export type StringRules = _validate_StringRules; - export type StringRules__Output = _validate_StringRules__Output; - export type KnownRegex = _validate_KnownRegex; - export type BytesRules = _validate_BytesRules; - export type BytesRules__Output = _validate_BytesRules__Output; - export type EnumRules = _validate_EnumRules; - export type EnumRules__Output = _validate_EnumRules__Output; - export type MessageRules = _validate_MessageRules; - export type MessageRules__Output = _validate_MessageRules__Output; - export type RepeatedRules = _validate_RepeatedRules; - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - export type MapRules = _validate_MapRules; - export type MapRules__Output = _validate_MapRules__Output; - export type AnyRules = _validate_AnyRules; - export type AnyRules__Output = _validate_AnyRules__Output; - export type DurationRules = _validate_DurationRules; - export type DurationRules__Output = _validate_DurationRules__Output; - export type TimestampRules = _validate_TimestampRules; - export type TimestampRules__Output = _validate_TimestampRules__Output; } export namespace google { + export namespace api { + export type CustomHttpPattern = _google_api_CustomHttpPattern; + export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + export type Http = _google_api_Http; + export type Http__Output = _google_api_Http__Output; + export type HttpRule = _google_api_HttpRule; + export type HttpRule__Output = _google_api_HttpRule__Output; + } export namespace protobuf { - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; export type BoolValue = _google_protobuf_BoolValue; export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; export type BytesValue = _google_protobuf_BytesValue; export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - export type NullValue = _google_protobuf_NullValue; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; export type DescriptorProto = _google_protobuf_DescriptorProto; export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; export type FileOptions = _google_protobuf_FileOptions; export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; export type MessageOptions = _google_protobuf_MessageOptions; export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type NullValue = _google_protobuf_NullValue; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; export type OneofOptions = _google_protobuf_OneofOptions; export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; export type ServiceOptions = _google_protobuf_ServiceOptions; export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; } - export namespace api { - export type Http = _google_api_Http; - export type Http__Output = _google_api_Http__Output; - export type HttpRule = _google_api_HttpRule; - export type HttpRule__Output = _google_api_HttpRule__Output; - export type CustomHttpPattern = _google_api_CustomHttpPattern; - export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + } + export namespace udpa { + export namespace annotations { + export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; + export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; + export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; + export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } } + export namespace validate { + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; + export type FieldRules = _validate_FieldRules; + export type FieldRules__Output = _validate_FieldRules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type FloatRules = _validate_FloatRules; + export type FloatRules__Output = _validate_FloatRules__Output; + export type Int32Rules = _validate_Int32Rules; + export type Int32Rules__Output = _validate_Int32Rules__Output; + export type Int64Rules = _validate_Int64Rules; + export type Int64Rules__Output = _validate_Int64Rules__Output; + export type KnownRegex = _validate_KnownRegex; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; + export type SFixed32Rules = _validate_SFixed32Rules; + export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + export type SFixed64Rules = _validate_SFixed64Rules; + export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; + export type StringRules = _validate_StringRules; + export type StringRules__Output = _validate_StringRules__Output; + export type TimestampRules = _validate_TimestampRules; + export type TimestampRules__Output = _validate_TimestampRules__Output; + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; + } } export namespace ClientInterfaces { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace Listener { - export namespace DeprecatedV1 { - } export namespace ConnectionBalanceConfig { export namespace ExactBalance { } } - } - export namespace core { - export namespace SocketOption { - } - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { - } - export namespace BindConfig { - } - export namespace Address { - } - export namespace CidrRange { + export namespace DeprecatedV1 { } - export namespace Locality { + } + export namespace auth { + export namespace CertificateValidationContext { } - export namespace BuildVersion { + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } } - export namespace Extension { + export namespace DownstreamTlsContext { } - export namespace Node { + export namespace GenericSecret { } - export namespace Metadata { + export namespace PrivateKeyProvider { } - export namespace RuntimeUInt32 { + export namespace SdsSecretConfig { } - export namespace RuntimeDouble { + export namespace Secret { } - export namespace RuntimeFeatureFlag { + export namespace TlsCertificate { } - export namespace HeaderValue { + export namespace TlsParameters { } - export namespace HeaderValueOption { + export namespace TlsSessionTicketKeys { } - export namespace HeaderMap { + export namespace UpstreamTlsContext { } - export namespace DataSource { + } + export namespace core { + export namespace Address { } - export namespace RetryPolicy { + export namespace AggregatedConfigSource { } - export namespace RemoteDataSource { + export namespace ApiConfigSource { } export namespace AsyncDataSource { } - export namespace TransportSocket { - } - export namespace RuntimeFractionalPercent { - } - export namespace ControlPlane { - } export namespace BackoffStrategy { } - export namespace HttpUri { + export namespace BindConfig { } - export namespace ApiConfigSource { + export namespace BuildVersion { } - export namespace AggregatedConfigSource { + export namespace CidrRange { } - export namespace SelfConfigSource { + export namespace ConfigSource { } - export namespace RateLimitSettings { + export namespace ControlPlane { } - export namespace ConfigSource { + export namespace DataSource { + } + export namespace Extension { } export namespace GrpcService { export namespace EnvoyGrpc { } export namespace GoogleGrpc { - export namespace SslCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace ChannelCredentials { - } export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } export namespace GoogleIAMCredentials { } export namespace MetadataCredentialsFromPlugin { } + export namespace ServiceAccountJWTAccessCredentials { + } export namespace StsService { } } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } } } - } - export namespace listener { - export namespace Filter { + export namespace HeaderMap { } - export namespace FilterChainMatch { + export namespace HeaderValue { } - export namespace FilterChain { + export namespace HeaderValueOption { } - export namespace ListenerFilterChainMatchPredicate { - export namespace MatchSet { - } + export namespace HttpUri { } - export namespace ListenerFilter { + export namespace Locality { } - export namespace UdpListenerConfig { + export namespace Metadata { } - export namespace ActiveRawUdpListenerConfig { + export namespace Node { } - } - export namespace auth { - export namespace UpstreamTlsContext { + export namespace Pipe { } - export namespace DownstreamTlsContext { + export namespace RateLimitSettings { } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } + export namespace RemoteDataSource { } - export namespace TlsParameters { + export namespace RetryPolicy { } - export namespace PrivateKeyProvider { + export namespace RuntimeDouble { + } + export namespace RuntimeFeatureFlag { + } + export namespace RuntimeFractionalPercent { + } + export namespace RuntimeUInt32 { + } + export namespace SelfConfigSource { + } + export namespace SocketAddress { + } + export namespace SocketOption { + } + export namespace TcpKeepalive { + } + export namespace TransportSocket { + } + } + export namespace listener { + export namespace ActiveRawUdpListenerConfig { } - export namespace TlsCertificate { + export namespace Filter { } - export namespace TlsSessionTicketKeys { + export namespace FilterChain { } - export namespace CertificateValidationContext { + export namespace FilterChainMatch { } - export namespace GenericSecret { + export namespace ListenerFilter { } - export namespace SdsSecretConfig { + export namespace ListenerFilterChainMatchPredicate { + export namespace MatchSet { + } } - export namespace Secret { + export namespace UdpListenerConfig { } } export namespace route { - export namespace VirtualHost { + export namespace CorsPolicy { + } + export namespace Decorator { + } + export namespace DirectResponseAction { } export namespace FilterAction { } - export namespace Route { + export namespace HeaderMatcher { } - export namespace WeightedCluster { - export namespace ClusterWeight { + export namespace HedgePolicy { + } + export namespace QueryParameterMatcher { + } + export namespace RateLimit { + export namespace Action { + export namespace DestinationCluster { + } + export namespace GenericKey { + } + export namespace HeaderValueMatch { + } + export namespace RemoteAddress { + } + export namespace RequestHeaders { + } + export namespace SourceCluster { + } } } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { + export namespace RedirectAction { + } + export namespace RetryPolicy { + export namespace RetryBackOff { } - export namespace TlsContextMatchOptions { + export namespace RetryHostPredicate { + } + export namespace RetryPriority { } } - export namespace CorsPolicy { + export namespace Route { } export namespace RouteAction { - export namespace RequestMirrorPolicy { - } export namespace HashPolicy { - export namespace Header { + export namespace ConnectionProperties { } export namespace Cookie { } - export namespace ConnectionProperties { + export namespace FilterState { } - export namespace QueryParameter { + export namespace Header { } - export namespace FilterState { + export namespace QueryParameter { } } + export namespace RequestMirrorPolicy { + } export namespace UpgradeConfig { } } - export namespace RetryPolicy { - export namespace RetryPriority { - } - export namespace RetryHostPredicate { + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { } - export namespace RetryBackOff { + export namespace TlsContextMatchOptions { } } - export namespace HedgePolicy { - } - export namespace RedirectAction { - } - export namespace DirectResponseAction { - } - export namespace Decorator { - } export namespace Tracing { } export namespace VirtualCluster { } - export namespace RateLimit { - export namespace Action { - export namespace SourceCluster { - } - export namespace DestinationCluster { - } - export namespace RequestHeaders { - } - export namespace RemoteAddress { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - } - } - export namespace HeaderMatcher { + export namespace VirtualHost { } - export namespace QueryParameterMatcher { + export namespace WeightedCluster { + export namespace ClusterWeight { + } } } } } export namespace config { - export namespace listener { - export namespace v2 { - export namespace ApiListener { - } - } - } export namespace filter { export namespace accesslog { export namespace v2 { @@ -798,190 +794,114 @@ export namespace ClientInterfaces { } export namespace AccessLogFilter { } - export namespace ComparisonFilter { + export namespace AndFilter { } - export namespace StatusCodeFilter { + export namespace ComparisonFilter { } export namespace DurationFilter { } - export namespace NotHealthCheckFilter { + export namespace ExtensionFilter { } - export namespace TraceableFilter { + export namespace GrpcStatusFilter { } - export namespace RuntimeFilter { + export namespace HeaderFilter { } - export namespace AndFilter { + export namespace NotHealthCheckFilter { } export namespace OrFilter { } - export namespace HeaderFilter { - } export namespace ResponseFlagFilter { } - export namespace GrpcStatusFilter { - } - export namespace ExtensionFilter { - } - } - } - } - } - export namespace type { - export namespace Percent { - } - export namespace FractionalPercent { - } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace RegexMatchAndSubstitute { - } - export namespace StringMatcher { - } - export namespace ListStringMatcher { - } - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Literal { - } - export namespace Environment { - } - export namespace Header { - } - export namespace Metadata { - } - } - } - } - export namespace metadata { - export namespace v2 { - export namespace MetadataKey { - export namespace PathSegment { - } - } - export namespace MetadataKind { - export namespace Request { - } - export namespace Route { + export namespace RuntimeFilter { } - export namespace Cluster { + export namespace StatusCodeFilter { } - export namespace Host { + export namespace TraceableFilter { } } } } - } - export namespace annotations { - } - } - export namespace udpa { - export namespace annotations { - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } - export namespace google { - export namespace protobuf { - export namespace Duration { - } - export namespace DoubleValue { + export namespace listener { + export namespace v2 { + export namespace ApiListener { + } + } } - export namespace FloatValue { + } + export namespace type { + export namespace DoubleRange { } - export namespace Int64Value { + export namespace FractionalPercent { } - export namespace UInt64Value { + export namespace Int32Range { } - export namespace Int32Value { + export namespace Int64Range { } - export namespace UInt32Value { + export namespace Percent { } - export namespace BoolValue { + export namespace SemanticVersion { } - export namespace StringValue { + export namespace matcher { + export namespace ListStringMatcher { + } + export namespace RegexMatchAndSubstitute { + } + export namespace RegexMatcher { + export namespace GoogleRE2 { + } + } + export namespace StringMatcher { + } } - export namespace BytesValue { + export namespace metadata { + export namespace v2 { + export namespace MetadataKey { + export namespace PathSegment { + } + } + export namespace MetadataKind { + export namespace Cluster { + } + export namespace Host { + } + export namespace Request { + } + export namespace Route { + } + } + } } - export namespace Any { + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Environment { + } + export namespace Header { + } + export namespace Literal { + } + export namespace Metadata { + } + } + } } - export namespace Struct { + } + } + export namespace google { + export namespace api { + export namespace CustomHttpPattern { } - export namespace Value { + export namespace Http { } - export namespace ListValue { + export namespace HttpRule { } - export namespace Timestamp { + } + export namespace protobuf { + export namespace Any { } - export namespace FileDescriptorSet { + export namespace BoolValue { } - export namespace FileDescriptorProto { + export namespace BytesValue { } export namespace DescriptorProto { export namespace ExtensionRange { @@ -989,58 +909,138 @@ export namespace ClientInterfaces { export namespace ReservedRange { } } - export namespace FieldDescriptorProto { + export namespace DoubleValue { } - export namespace OneofDescriptorProto { + export namespace Duration { + } + export namespace Empty { } export namespace EnumDescriptorProto { } + export namespace EnumOptions { + } export namespace EnumValueDescriptorProto { } - export namespace ServiceDescriptorProto { + export namespace EnumValueOptions { } - export namespace MethodDescriptorProto { + export namespace FieldDescriptorProto { + } + export namespace FieldOptions { + } + export namespace FileDescriptorProto { + } + export namespace FileDescriptorSet { } export namespace FileOptions { } - export namespace MessageOptions { + export namespace FloatValue { } - export namespace FieldOptions { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofOptions { + export namespace Int32Value { } - export namespace EnumOptions { + export namespace Int64Value { } - export namespace EnumValueOptions { + export namespace ListValue { } - export namespace ServiceOptions { + export namespace MessageOptions { + } + export namespace MethodDescriptorProto { } export namespace MethodOptions { } - export namespace UninterpretedOption { - export namespace NamePart { - } + export namespace OneofDescriptorProto { + } + export namespace OneofOptions { + } + export namespace ServiceDescriptorProto { + } + export namespace ServiceOptions { } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { + export namespace StringValue { + } + export namespace Struct { + } + export namespace Timestamp { + } + export namespace UInt32Value { + } + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { } } - export namespace Empty { + export namespace Value { } } - export namespace api { - export namespace Http { + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace HttpRule { + export namespace FileMigrateAnnotation { } - export namespace CustomHttpPattern { + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; @@ -1050,135 +1050,132 @@ type SubtypeConstructor = { export interface ProtoGrpcType { envoy: { + annotations: { + } api: { v2: { Listener: MessageTypeDefinition + auth: { + CertificateValidationContext: MessageTypeDefinition + CommonTlsContext: MessageTypeDefinition + DownstreamTlsContext: MessageTypeDefinition + GenericSecret: MessageTypeDefinition + PrivateKeyProvider: MessageTypeDefinition + SdsSecretConfig: MessageTypeDefinition + Secret: MessageTypeDefinition + TlsCertificate: MessageTypeDefinition + TlsParameters: MessageTypeDefinition + TlsSessionTicketKeys: MessageTypeDefinition + UpstreamTlsContext: MessageTypeDefinition + } core: { - SocketOption: MessageTypeDefinition - Pipe: MessageTypeDefinition - SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition - RoutingPriority: EnumTypeDefinition - RequestMethod: EnumTypeDefinition - TrafficDirection: EnumTypeDefinition - Locality: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition Extension: MessageTypeDefinition - Node: MessageTypeDefinition - Metadata: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition HeaderValueOption: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - DataSource: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - TransportSocket: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition - HttpUri: MessageTypeDefinition - ApiVersion: EnumTypeDefinition - ApiConfigSource: MessageTypeDefinition - AggregatedConfigSource: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition - RateLimitSettings: MessageTypeDefinition - ConfigSource: MessageTypeDefinition - GrpcService: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition } listener: { + ActiveRawUdpListenerConfig: MessageTypeDefinition Filter: MessageTypeDefinition - FilterChainMatch: MessageTypeDefinition FilterChain: MessageTypeDefinition - ListenerFilterChainMatchPredicate: MessageTypeDefinition + FilterChainMatch: MessageTypeDefinition ListenerFilter: MessageTypeDefinition + ListenerFilterChainMatchPredicate: MessageTypeDefinition UdpListenerConfig: MessageTypeDefinition - ActiveRawUdpListenerConfig: MessageTypeDefinition - } - auth: { - UpstreamTlsContext: MessageTypeDefinition - DownstreamTlsContext: MessageTypeDefinition - CommonTlsContext: MessageTypeDefinition - TlsParameters: MessageTypeDefinition - PrivateKeyProvider: MessageTypeDefinition - TlsCertificate: MessageTypeDefinition - TlsSessionTicketKeys: MessageTypeDefinition - CertificateValidationContext: MessageTypeDefinition - GenericSecret: MessageTypeDefinition - SdsSecretConfig: MessageTypeDefinition - Secret: MessageTypeDefinition } route: { - VirtualHost: MessageTypeDefinition - FilterAction: MessageTypeDefinition - Route: MessageTypeDefinition - WeightedCluster: MessageTypeDefinition - RouteMatch: MessageTypeDefinition CorsPolicy: MessageTypeDefinition - RouteAction: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition - DirectResponseAction: MessageTypeDefinition - Decorator: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteMatch: MessageTypeDefinition Tracing: MessageTypeDefinition VirtualCluster: MessageTypeDefinition - RateLimit: MessageTypeDefinition - HeaderMatcher: MessageTypeDefinition - QueryParameterMatcher: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition } } } config: { - listener: { - v2: { - ApiListener: MessageTypeDefinition - } - } filter: { accesslog: { v2: { AccessLog: MessageTypeDefinition AccessLogFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition ComparisonFilter: MessageTypeDefinition - StatusCodeFilter: MessageTypeDefinition DurationFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition NotHealthCheckFilter: MessageTypeDefinition - TraceableFilter: MessageTypeDefinition - RuntimeFilter: MessageTypeDefinition - AndFilter: MessageTypeDefinition OrFilter: MessageTypeDefinition - HeaderFilter: MessageTypeDefinition ResponseFlagFilter: MessageTypeDefinition - GrpcStatusFilter: MessageTypeDefinition - ExtensionFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition } } } + listener: { + v2: { + ApiListener: MessageTypeDefinition + } + } } type: { - Percent: MessageTypeDefinition + DoubleRange: MessageTypeDefinition FractionalPercent: MessageTypeDefinition - Int64Range: MessageTypeDefinition Int32Range: MessageTypeDefinition - DoubleRange: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition SemanticVersion: MessageTypeDefinition matcher: { - RegexMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition StringMatcher: MessageTypeDefinition - ListStringMatcher: MessageTypeDefinition - } - tracing: { - v2: { - CustomTag: MessageTypeDefinition - } } metadata: { v2: { @@ -1186,324 +1183,323 @@ export interface ProtoGrpcType { MetadataKind: MessageTypeDefinition } } + tracing: { + v2: { + CustomTag: MessageTypeDefinition + } + } } - annotations: { + } + google: { + api: { + CustomHttpPattern: MessageTypeDefinition + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + } + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition } } udpa: { annotations: { - MigrateAnnotation: MessageTypeDefinition FieldMigrateAnnotation: MessageTypeDefinition FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition } } validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition FloatRules: MessageTypeDefinition - DoubleRules: MessageTypeDefinition Int32Rules: MessageTypeDefinition Int64Rules: MessageTypeDefinition - UInt32Rules: MessageTypeDefinition - UInt64Rules: MessageTypeDefinition - SInt32Rules: MessageTypeDefinition - SInt64Rules: MessageTypeDefinition - Fixed32Rules: MessageTypeDefinition - Fixed64Rules: MessageTypeDefinition - SFixed32Rules: MessageTypeDefinition - SFixed64Rules: MessageTypeDefinition - BoolRules: MessageTypeDefinition - StringRules: MessageTypeDefinition KnownRegex: EnumTypeDefinition - BytesRules: MessageTypeDefinition - EnumRules: MessageTypeDefinition + MapRules: MessageTypeDefinition MessageRules: MessageTypeDefinition RepeatedRules: MessageTypeDefinition - MapRules: MessageTypeDefinition - AnyRules: MessageTypeDefinition - DurationRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition TimestampRules: MessageTypeDefinition - } - google: { - protobuf: { - Duration: MessageTypeDefinition - DoubleValue: MessageTypeDefinition - FloatValue: MessageTypeDefinition - Int64Value: MessageTypeDefinition - UInt64Value: MessageTypeDefinition - Int32Value: MessageTypeDefinition - UInt32Value: MessageTypeDefinition - BoolValue: MessageTypeDefinition - StringValue: MessageTypeDefinition - BytesValue: MessageTypeDefinition - Any: MessageTypeDefinition - Struct: MessageTypeDefinition - Value: MessageTypeDefinition - NullValue: EnumTypeDefinition - ListValue: MessageTypeDefinition - Timestamp: MessageTypeDefinition - FileDescriptorSet: MessageTypeDefinition - FileDescriptorProto: MessageTypeDefinition - DescriptorProto: MessageTypeDefinition - FieldDescriptorProto: MessageTypeDefinition - OneofDescriptorProto: MessageTypeDefinition - EnumDescriptorProto: MessageTypeDefinition - EnumValueDescriptorProto: MessageTypeDefinition - ServiceDescriptorProto: MessageTypeDefinition - MethodDescriptorProto: MessageTypeDefinition - FileOptions: MessageTypeDefinition - MessageOptions: MessageTypeDefinition - FieldOptions: MessageTypeDefinition - OneofOptions: MessageTypeDefinition - EnumOptions: MessageTypeDefinition - EnumValueOptions: MessageTypeDefinition - ServiceOptions: MessageTypeDefinition - MethodOptions: MessageTypeDefinition - UninterpretedOption: MessageTypeDefinition - SourceCodeInfo: MessageTypeDefinition - GeneratedCodeInfo: MessageTypeDefinition - Empty: MessageTypeDefinition - } - api: { - Http: MessageTypeDefinition - HttpRule: MessageTypeDefinition - CustomHttpPattern: MessageTypeDefinition - } + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition } } export namespace ServiceHandlers { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace Listener { - export namespace DeprecatedV1 { - } export namespace ConnectionBalanceConfig { export namespace ExactBalance { } } - } - export namespace core { - export namespace SocketOption { - } - export namespace Pipe { - } - export namespace SocketAddress { - } - export namespace TcpKeepalive { - } - export namespace BindConfig { - } - export namespace Address { - } - export namespace CidrRange { - } - export namespace Locality { - } - export namespace BuildVersion { - } - export namespace Extension { + export namespace DeprecatedV1 { } - export namespace Node { + } + export namespace auth { + export namespace CertificateValidationContext { } - export namespace Metadata { + export namespace CommonTlsContext { + export namespace CombinedCertificateValidationContext { + } } - export namespace RuntimeUInt32 { + export namespace DownstreamTlsContext { } - export namespace RuntimeDouble { + export namespace GenericSecret { } - export namespace RuntimeFeatureFlag { + export namespace PrivateKeyProvider { } - export namespace HeaderValue { + export namespace SdsSecretConfig { } - export namespace HeaderValueOption { + export namespace Secret { } - export namespace HeaderMap { + export namespace TlsCertificate { } - export namespace DataSource { + export namespace TlsParameters { } - export namespace RetryPolicy { + export namespace TlsSessionTicketKeys { } - export namespace RemoteDataSource { + export namespace UpstreamTlsContext { } - export namespace AsyncDataSource { + } + export namespace core { + export namespace Address { } - export namespace TransportSocket { + export namespace AggregatedConfigSource { } - export namespace RuntimeFractionalPercent { + export namespace ApiConfigSource { } - export namespace ControlPlane { + export namespace AsyncDataSource { } export namespace BackoffStrategy { } - export namespace HttpUri { + export namespace BindConfig { } - export namespace ApiConfigSource { + export namespace BuildVersion { } - export namespace AggregatedConfigSource { + export namespace CidrRange { } - export namespace SelfConfigSource { + export namespace ConfigSource { } - export namespace RateLimitSettings { + export namespace ControlPlane { } - export namespace ConfigSource { + export namespace DataSource { + } + export namespace Extension { } export namespace GrpcService { export namespace EnvoyGrpc { } export namespace GoogleGrpc { - export namespace SslCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace ChannelCredentials { - } export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } export namespace GoogleIAMCredentials { } export namespace MetadataCredentialsFromPlugin { } + export namespace ServiceAccountJWTAccessCredentials { + } export namespace StsService { } } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } } } - } - export namespace listener { - export namespace Filter { + export namespace HeaderMap { } - export namespace FilterChainMatch { + export namespace HeaderValue { } - export namespace FilterChain { + export namespace HeaderValueOption { } - export namespace ListenerFilterChainMatchPredicate { - export namespace MatchSet { - } + export namespace HttpUri { } - export namespace ListenerFilter { + export namespace Locality { } - export namespace UdpListenerConfig { + export namespace Metadata { } - export namespace ActiveRawUdpListenerConfig { + export namespace Node { } - } - export namespace auth { - export namespace UpstreamTlsContext { + export namespace Pipe { } - export namespace DownstreamTlsContext { + export namespace RateLimitSettings { } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } + export namespace RemoteDataSource { } - export namespace TlsParameters { + export namespace RetryPolicy { } - export namespace PrivateKeyProvider { + export namespace RuntimeDouble { } - export namespace TlsCertificate { + export namespace RuntimeFeatureFlag { } - export namespace TlsSessionTicketKeys { + export namespace RuntimeFractionalPercent { } - export namespace CertificateValidationContext { + export namespace RuntimeUInt32 { } - export namespace GenericSecret { + export namespace SelfConfigSource { } - export namespace SdsSecretConfig { + export namespace SocketAddress { } - export namespace Secret { + export namespace SocketOption { + } + export namespace TcpKeepalive { + } + export namespace TransportSocket { + } + } + export namespace listener { + export namespace ActiveRawUdpListenerConfig { + } + export namespace Filter { + } + export namespace FilterChain { + } + export namespace FilterChainMatch { + } + export namespace ListenerFilter { + } + export namespace ListenerFilterChainMatchPredicate { + export namespace MatchSet { + } + } + export namespace UdpListenerConfig { } } export namespace route { - export namespace VirtualHost { + export namespace CorsPolicy { + } + export namespace Decorator { + } + export namespace DirectResponseAction { } export namespace FilterAction { } - export namespace Route { + export namespace HeaderMatcher { } - export namespace WeightedCluster { - export namespace ClusterWeight { + export namespace HedgePolicy { + } + export namespace QueryParameterMatcher { + } + export namespace RateLimit { + export namespace Action { + export namespace DestinationCluster { + } + export namespace GenericKey { + } + export namespace HeaderValueMatch { + } + export namespace RemoteAddress { + } + export namespace RequestHeaders { + } + export namespace SourceCluster { + } } } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { + export namespace RedirectAction { + } + export namespace RetryPolicy { + export namespace RetryBackOff { } - export namespace TlsContextMatchOptions { + export namespace RetryHostPredicate { + } + export namespace RetryPriority { } } - export namespace CorsPolicy { + export namespace Route { } export namespace RouteAction { - export namespace RequestMirrorPolicy { - } export namespace HashPolicy { - export namespace Header { + export namespace ConnectionProperties { } export namespace Cookie { } - export namespace ConnectionProperties { + export namespace FilterState { } - export namespace QueryParameter { + export namespace Header { } - export namespace FilterState { + export namespace QueryParameter { } } + export namespace RequestMirrorPolicy { + } export namespace UpgradeConfig { } } - export namespace RetryPolicy { - export namespace RetryPriority { - } - export namespace RetryHostPredicate { + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { } - export namespace RetryBackOff { + export namespace TlsContextMatchOptions { } } - export namespace HedgePolicy { - } - export namespace RedirectAction { - } - export namespace DirectResponseAction { - } - export namespace Decorator { - } export namespace Tracing { } export namespace VirtualCluster { } - export namespace RateLimit { - export namespace Action { - export namespace SourceCluster { - } - export namespace DestinationCluster { - } - export namespace RequestHeaders { - } - export namespace RemoteAddress { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - } - } - export namespace HeaderMatcher { + export namespace VirtualHost { } - export namespace QueryParameterMatcher { + export namespace WeightedCluster { + export namespace ClusterWeight { + } } } } } export namespace config { - export namespace listener { - export namespace v2 { - export namespace ApiListener { - } - } - } export namespace filter { export namespace accesslog { export namespace v2 { @@ -1511,72 +1507,64 @@ export namespace ServiceHandlers { } export namespace AccessLogFilter { } - export namespace ComparisonFilter { + export namespace AndFilter { } - export namespace StatusCodeFilter { + export namespace ComparisonFilter { } export namespace DurationFilter { } - export namespace NotHealthCheckFilter { + export namespace ExtensionFilter { } - export namespace TraceableFilter { + export namespace GrpcStatusFilter { } - export namespace RuntimeFilter { + export namespace HeaderFilter { } - export namespace AndFilter { + export namespace NotHealthCheckFilter { } export namespace OrFilter { } - export namespace HeaderFilter { - } export namespace ResponseFlagFilter { } - export namespace GrpcStatusFilter { + export namespace RuntimeFilter { } - export namespace ExtensionFilter { + export namespace StatusCodeFilter { + } + export namespace TraceableFilter { } } } } + export namespace listener { + export namespace v2 { + export namespace ApiListener { + } + } + } } export namespace type { - export namespace Percent { + export namespace DoubleRange { } export namespace FractionalPercent { } - export namespace Int64Range { - } export namespace Int32Range { } - export namespace DoubleRange { + export namespace Int64Range { + } + export namespace Percent { } export namespace SemanticVersion { } export namespace matcher { + export namespace ListStringMatcher { + } + export namespace RegexMatchAndSubstitute { + } export namespace RegexMatcher { export namespace GoogleRE2 { } } - export namespace RegexMatchAndSubstitute { - } export namespace StringMatcher { } - export namespace ListStringMatcher { - } - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Literal { - } - export namespace Environment { - } - export namespace Header { - } - export namespace Metadata { - } - } - } } export namespace metadata { export namespace v2 { @@ -1585,173 +1573,185 @@ export namespace ServiceHandlers { } } export namespace MetadataKind { + export namespace Cluster { + } + export namespace Host { + } export namespace Request { } export namespace Route { } - export namespace Cluster { + } + } + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Environment { } - export namespace Host { + export namespace Header { + } + export namespace Literal { + } + export namespace Metadata { } } } } } - export namespace annotations { - } } - export namespace udpa { - export namespace annotations { - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { + export namespace google { + export namespace api { + export namespace CustomHttpPattern { } - export namespace FileMigrateAnnotation { + export namespace Http { } - export namespace StatusAnnotation { + export namespace HttpRule { } } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } - export namespace google { export namespace protobuf { - export namespace Duration { - } - export namespace DoubleValue { + export namespace Any { } - export namespace FloatValue { + export namespace BoolValue { } - export namespace Int64Value { + export namespace BytesValue { } - export namespace UInt64Value { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } - export namespace Int32Value { + export namespace DoubleValue { } - export namespace UInt32Value { + export namespace Duration { } - export namespace BoolValue { + export namespace Empty { } - export namespace StringValue { + export namespace EnumDescriptorProto { } - export namespace BytesValue { + export namespace EnumOptions { } - export namespace Any { + export namespace EnumValueDescriptorProto { } - export namespace Struct { + export namespace EnumValueOptions { } - export namespace Value { + export namespace FieldDescriptorProto { } - export namespace ListValue { + export namespace FieldOptions { } - export namespace Timestamp { + export namespace FileDescriptorProto { } export namespace FileDescriptorSet { } - export namespace FileDescriptorProto { + export namespace FileOptions { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } + export namespace FloatValue { } - export namespace FieldDescriptorProto { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace OneofDescriptorProto { + export namespace Int32Value { } - export namespace EnumDescriptorProto { + export namespace Int64Value { } - export namespace EnumValueDescriptorProto { + export namespace ListValue { } - export namespace ServiceDescriptorProto { + export namespace MessageOptions { } export namespace MethodDescriptorProto { } - export namespace FileOptions { - } - export namespace MessageOptions { + export namespace MethodOptions { } - export namespace FieldOptions { + export namespace OneofDescriptorProto { } export namespace OneofOptions { } - export namespace EnumOptions { - } - export namespace EnumValueOptions { + export namespace ServiceDescriptorProto { } export namespace ServiceOptions { } - export namespace MethodOptions { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } export namespace SourceCodeInfo { export namespace Location { } } - export namespace GeneratedCodeInfo { - export namespace Annotation { + export namespace StringValue { + } + export namespace Struct { + } + export namespace Timestamp { + } + export namespace UInt32Value { + } + export namespace UInt64Value { + } + export namespace UninterpretedOption { + export namespace NamePart { } } - export namespace Empty { + export namespace Value { } } - export namespace api { - export namespace Http { + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace HttpRule { + export namespace FileMigrateAnnotation { } - export namespace CustomHttpPattern { + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } diff --git a/packages/grpc-js/src/generated/route.ts b/packages/grpc-js/src/generated/route.ts index b7d34ee2e..b3de909f2 100644 --- a/packages/grpc-js/src/generated/route.ts +++ b/packages/grpc-js/src/generated/route.ts @@ -3,142 +3,144 @@ import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@g import { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from './envoy/api/v2/RouteConfiguration'; import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from './envoy/api/v2/Vhds'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; +import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; +import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; +import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; +import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; +import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; +import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; +import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; +import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; +import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; +import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; +import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; +import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; +import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; +import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; +import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; +import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; +import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; +import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; -import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; -import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; -import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; -import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; +import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; +import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; +import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from './envoy/api/v2/route/CorsPolicy'; -import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; -import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; +import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; +import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; +import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; +import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from './envoy/api/v2/route/HedgePolicy'; +import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; +import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from './envoy/api/v2/route/RedirectAction'; -import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; -import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; +import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; +import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; +import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; +import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from './envoy/api/v2/route/Tracing'; import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from './envoy/api/v2/route/VirtualCluster'; -import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; -import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; +import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; +import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; +import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; +import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; +import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; +import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; +import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; +import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; +import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; +import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; +import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; +import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; +import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; +import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; +import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; +import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; +import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; +import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; +import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; +import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; +import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; +import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; +import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; +import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; +import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; +import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; +import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; +import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; +import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; +import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; +import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; +import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; +import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; +import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; +import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; +import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; +import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; +import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; +import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; +import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; +import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; +import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; +import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; +import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; +import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; +import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; export namespace messages { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export type RouteConfiguration = _envoy_api_v2_RouteConfiguration; @@ -146,143 +148,137 @@ export namespace messages { export type Vhds = _envoy_api_v2_Vhds; export type Vhds__Output = _envoy_api_v2_Vhds__Output; export namespace core { - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - export type Locality = _envoy_api_v2_core_Locality; - export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Address = _envoy_api_v2_core_Address; + export type Address__Output = _envoy_api_v2_core_Address__Output; + export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + export type ApiVersion = _envoy_api_v2_core_ApiVersion; + export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; + export type BindConfig = _envoy_api_v2_core_BindConfig; + export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; export type BuildVersion = _envoy_api_v2_core_BuildVersion; export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + export type CidrRange = _envoy_api_v2_core_CidrRange; + export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + export type ConfigSource = _envoy_api_v2_core_ConfigSource; + export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + export type ControlPlane = _envoy_api_v2_core_ControlPlane; + export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + export type DataSource = _envoy_api_v2_core_DataSource; + export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; export type Extension = _envoy_api_v2_core_Extension; export type Extension__Output = _envoy_api_v2_core_Extension__Output; - export type Node = _envoy_api_v2_core_Node; - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Metadata = _envoy_api_v2_core_Metadata; - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + export type GrpcService = _envoy_api_v2_core_GrpcService; + export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + export type HeaderMap = _envoy_api_v2_core_HeaderMap; + export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; export type HeaderValue = _envoy_api_v2_core_HeaderValue; export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - export type DataSource = _envoy_api_v2_core_DataSource; - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type HttpUri = _envoy_api_v2_core_HttpUri; + export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + export type Locality = _envoy_api_v2_core_Locality; + export type Locality__Output = _envoy_api_v2_core_Locality__Output; + export type Metadata = _envoy_api_v2_core_Metadata; + export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + export type Node = _envoy_api_v2_core_Node; + export type Node__Output = _envoy_api_v2_core_Node__Output; + export type Pipe = _envoy_api_v2_core_Pipe; + export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; + export type RequestMethod = _envoy_api_v2_core_RequestMethod; + export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; - export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; - export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; export type SocketAddress = _envoy_api_v2_core_SocketAddress; export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - export type Address = _envoy_api_v2_core_Address; - export type Address__Output = _envoy_api_v2_core_Address__Output; - export type CidrRange = _envoy_api_v2_core_CidrRange; - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - export type HttpUri = _envoy_api_v2_core_HttpUri; - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - export type GrpcService = _envoy_api_v2_core_GrpcService; - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; export type SocketOption = _envoy_api_v2_core_SocketOption; export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; + export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; + export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + export type TransportSocket = _envoy_api_v2_core_TransportSocket; + export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; } export namespace route { - export type VirtualHost = _envoy_api_v2_route_VirtualHost; - export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; - export type FilterAction = _envoy_api_v2_route_FilterAction; - export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; - export type Route = _envoy_api_v2_route_Route; - export type Route__Output = _envoy_api_v2_route_Route__Output; - export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; - export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; - export type RouteMatch = _envoy_api_v2_route_RouteMatch; - export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; - export type RouteAction = _envoy_api_v2_route_RouteAction; - export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; - export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; - export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + export type Decorator = _envoy_api_v2_route_Decorator; + export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; + export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; + export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; + export type FilterAction = _envoy_api_v2_route_FilterAction; + export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; + export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; + export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; + export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; + export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + export type RateLimit = _envoy_api_v2_route_RateLimit; + export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; export type RedirectAction = _envoy_api_v2_route_RedirectAction; export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; - export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; - export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; - export type Decorator = _envoy_api_v2_route_Decorator; - export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; + export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; + export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + export type Route = _envoy_api_v2_route_Route; + export type Route__Output = _envoy_api_v2_route_Route__Output; + export type RouteAction = _envoy_api_v2_route_RouteAction; + export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; + export type RouteMatch = _envoy_api_v2_route_RouteMatch; + export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; export type Tracing = _envoy_api_v2_route_Tracing; export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; - export type RateLimit = _envoy_api_v2_route_RateLimit; - export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; - export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; - export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; - export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; - export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + export type VirtualHost = _envoy_api_v2_route_VirtualHost; + export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; + export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; + export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; } } } export namespace type { - export type Percent = _envoy_type_Percent; - export type Percent__Output = _envoy_type_Percent__Output; + export type DoubleRange = _envoy_type_DoubleRange; + export type DoubleRange__Output = _envoy_type_DoubleRange__Output; export type FractionalPercent = _envoy_type_FractionalPercent; export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + export type Int32Range = _envoy_type_Int32Range; + export type Int32Range__Output = _envoy_type_Int32Range__Output; + export type Int64Range = _envoy_type_Int64Range; + export type Int64Range__Output = _envoy_type_Int64Range__Output; + export type Percent = _envoy_type_Percent; + export type Percent__Output = _envoy_type_Percent__Output; export type SemanticVersion = _envoy_type_SemanticVersion; export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; export type StringMatcher = _envoy_type_matcher_StringMatcher; export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - } - export type Int64Range = _envoy_type_Int64Range; - export type Int64Range__Output = _envoy_type_Int64Range__Output; - export type Int32Range = _envoy_type_Int32Range; - export type Int32Range__Output = _envoy_type_Int32Range__Output; - export type DoubleRange = _envoy_type_DoubleRange; - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - export namespace tracing { - export namespace v2 { - export type CustomTag = _envoy_type_tracing_v2_CustomTag; - export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; - } } export namespace metadata { export namespace v2 { @@ -292,153 +288,159 @@ export namespace messages { export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; } } + export namespace tracing { + export namespace v2 { + export type CustomTag = _envoy_type_tracing_v2_CustomTag; + export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; + } + } } - export namespace annotations { + } + export namespace google { + export namespace protobuf { + export type Any = _google_protobuf_Any; + export type Any__Output = _google_protobuf_Any__Output; + export type BoolValue = _google_protobuf_BoolValue; + export type BoolValue__Output = _google_protobuf_BoolValue__Output; + export type BytesValue = _google_protobuf_BytesValue; + export type BytesValue__Output = _google_protobuf_BytesValue__Output; + export type DescriptorProto = _google_protobuf_DescriptorProto; + export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; + export type DoubleValue = _google_protobuf_DoubleValue; + export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; + export type Duration = _google_protobuf_Duration; + export type Duration__Output = _google_protobuf_Duration__Output; + export type Empty = _google_protobuf_Empty; + export type Empty__Output = _google_protobuf_Empty__Output; + export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; + export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; + export type EnumOptions = _google_protobuf_EnumOptions; + export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; + export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; + export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; + export type EnumValueOptions = _google_protobuf_EnumValueOptions; + export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; + export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; + export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; + export type FieldOptions = _google_protobuf_FieldOptions; + export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; + export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; + export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; + export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; + export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; + export type FileOptions = _google_protobuf_FileOptions; + export type FileOptions__Output = _google_protobuf_FileOptions__Output; + export type FloatValue = _google_protobuf_FloatValue; + export type FloatValue__Output = _google_protobuf_FloatValue__Output; + export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; + export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; + export type Int32Value = _google_protobuf_Int32Value; + export type Int32Value__Output = _google_protobuf_Int32Value__Output; + export type Int64Value = _google_protobuf_Int64Value; + export type Int64Value__Output = _google_protobuf_Int64Value__Output; + export type ListValue = _google_protobuf_ListValue; + export type ListValue__Output = _google_protobuf_ListValue__Output; + export type MessageOptions = _google_protobuf_MessageOptions; + export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; + export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; + export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; + export type MethodOptions = _google_protobuf_MethodOptions; + export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; + export type NullValue = _google_protobuf_NullValue; + export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; + export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; + export type OneofOptions = _google_protobuf_OneofOptions; + export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; + export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; + export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; + export type ServiceOptions = _google_protobuf_ServiceOptions; + export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; + export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; + export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; + export type StringValue = _google_protobuf_StringValue; + export type StringValue__Output = _google_protobuf_StringValue__Output; + export type Struct = _google_protobuf_Struct; + export type Struct__Output = _google_protobuf_Struct__Output; + export type Timestamp = _google_protobuf_Timestamp; + export type Timestamp__Output = _google_protobuf_Timestamp__Output; + export type UInt32Value = _google_protobuf_UInt32Value; + export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; + export type UInt64Value = _google_protobuf_UInt64Value; + export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; + export type UninterpretedOption = _google_protobuf_UninterpretedOption; + export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; + export type Value = _google_protobuf_Value; + export type Value__Output = _google_protobuf_Value__Output; } } export namespace udpa { export namespace annotations { - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; + export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; + export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; + export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; + export type StatusAnnotation = _udpa_annotations_StatusAnnotation; + export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; } } export namespace validate { + export type AnyRules = _validate_AnyRules; + export type AnyRules__Output = _validate_AnyRules__Output; + export type BoolRules = _validate_BoolRules; + export type BoolRules__Output = _validate_BoolRules__Output; + export type BytesRules = _validate_BytesRules; + export type BytesRules__Output = _validate_BytesRules__Output; + export type DoubleRules = _validate_DoubleRules; + export type DoubleRules__Output = _validate_DoubleRules__Output; + export type DurationRules = _validate_DurationRules; + export type DurationRules__Output = _validate_DurationRules__Output; + export type EnumRules = _validate_EnumRules; + export type EnumRules__Output = _validate_EnumRules__Output; export type FieldRules = _validate_FieldRules; export type FieldRules__Output = _validate_FieldRules__Output; + export type Fixed32Rules = _validate_Fixed32Rules; + export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + export type Fixed64Rules = _validate_Fixed64Rules; + export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; export type FloatRules = _validate_FloatRules; export type FloatRules__Output = _validate_FloatRules__Output; - export type DoubleRules = _validate_DoubleRules; - export type DoubleRules__Output = _validate_DoubleRules__Output; export type Int32Rules = _validate_Int32Rules; export type Int32Rules__Output = _validate_Int32Rules__Output; export type Int64Rules = _validate_Int64Rules; export type Int64Rules__Output = _validate_Int64Rules__Output; - export type UInt32Rules = _validate_UInt32Rules; - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - export type UInt64Rules = _validate_UInt64Rules; - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - export type SInt32Rules = _validate_SInt32Rules; - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - export type SInt64Rules = _validate_SInt64Rules; - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - export type Fixed32Rules = _validate_Fixed32Rules; - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - export type Fixed64Rules = _validate_Fixed64Rules; - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + export type KnownRegex = _validate_KnownRegex; + export type MapRules = _validate_MapRules; + export type MapRules__Output = _validate_MapRules__Output; + export type MessageRules = _validate_MessageRules; + export type MessageRules__Output = _validate_MessageRules__Output; + export type RepeatedRules = _validate_RepeatedRules; + export type RepeatedRules__Output = _validate_RepeatedRules__Output; export type SFixed32Rules = _validate_SFixed32Rules; export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; export type SFixed64Rules = _validate_SFixed64Rules; export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - export type BoolRules = _validate_BoolRules; - export type BoolRules__Output = _validate_BoolRules__Output; + export type SInt32Rules = _validate_SInt32Rules; + export type SInt32Rules__Output = _validate_SInt32Rules__Output; + export type SInt64Rules = _validate_SInt64Rules; + export type SInt64Rules__Output = _validate_SInt64Rules__Output; export type StringRules = _validate_StringRules; export type StringRules__Output = _validate_StringRules__Output; - export type KnownRegex = _validate_KnownRegex; - export type BytesRules = _validate_BytesRules; - export type BytesRules__Output = _validate_BytesRules__Output; - export type EnumRules = _validate_EnumRules; - export type EnumRules__Output = _validate_EnumRules__Output; - export type MessageRules = _validate_MessageRules; - export type MessageRules__Output = _validate_MessageRules__Output; - export type RepeatedRules = _validate_RepeatedRules; - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - export type MapRules = _validate_MapRules; - export type MapRules__Output = _validate_MapRules__Output; - export type AnyRules = _validate_AnyRules; - export type AnyRules__Output = _validate_AnyRules__Output; - export type DurationRules = _validate_DurationRules; - export type DurationRules__Output = _validate_DurationRules__Output; export type TimestampRules = _validate_TimestampRules; export type TimestampRules__Output = _validate_TimestampRules__Output; - } - export namespace google { - export namespace protobuf { - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; - export type BoolValue = _google_protobuf_BoolValue; - export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; - export type BytesValue = _google_protobuf_BytesValue; - export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - export type NullValue = _google_protobuf_NullValue; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; - export type DescriptorProto = _google_protobuf_DescriptorProto; - export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; - export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; - export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; - export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; - export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; - export type FileOptions = _google_protobuf_FileOptions; - export type FileOptions__Output = _google_protobuf_FileOptions__Output; - export type MessageOptions = _google_protobuf_MessageOptions; - export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; - export type OneofOptions = _google_protobuf_OneofOptions; - export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; - export type ServiceOptions = _google_protobuf_ServiceOptions; - export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; - export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; - export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; - } + export type UInt32Rules = _validate_UInt32Rules; + export type UInt32Rules__Output = _validate_UInt32Rules__Output; + export type UInt64Rules = _validate_UInt64Rules; + export type UInt64Rules__Output = _validate_UInt64Rules__Output; } } export namespace ClientInterfaces { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace RouteConfiguration { @@ -446,211 +448,197 @@ export namespace ClientInterfaces { export namespace Vhds { } export namespace core { - export namespace Locality { + export namespace Address { + } + export namespace AggregatedConfigSource { + } + export namespace ApiConfigSource { + } + export namespace AsyncDataSource { + } + export namespace BackoffStrategy { + } + export namespace BindConfig { } export namespace BuildVersion { } - export namespace Extension { + export namespace CidrRange { } - export namespace Node { + export namespace ConfigSource { } - export namespace Metadata { + export namespace ControlPlane { } - export namespace RuntimeUInt32 { + export namespace DataSource { } - export namespace RuntimeDouble { + export namespace Extension { } - export namespace RuntimeFeatureFlag { + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace CallCredentials { + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace StsService { + } + } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } + } + } + export namespace HeaderMap { } export namespace HeaderValue { } export namespace HeaderValueOption { } - export namespace HeaderMap { + export namespace HttpUri { } - export namespace DataSource { + export namespace Locality { } - export namespace RetryPolicy { + export namespace Metadata { } - export namespace RemoteDataSource { + export namespace Node { } - export namespace AsyncDataSource { + export namespace Pipe { } - export namespace TransportSocket { + export namespace RateLimitSettings { } - export namespace RuntimeFractionalPercent { + export namespace RemoteDataSource { } - export namespace ControlPlane { + export namespace RetryPolicy { } - export namespace ApiConfigSource { + export namespace RuntimeDouble { } - export namespace AggregatedConfigSource { + export namespace RuntimeFeatureFlag { + } + export namespace RuntimeFractionalPercent { + } + export namespace RuntimeUInt32 { } export namespace SelfConfigSource { } - export namespace RateLimitSettings { + export namespace SocketAddress { } - export namespace ConfigSource { + export namespace SocketOption { } - export namespace BackoffStrategy { + export namespace TcpKeepalive { } - export namespace Pipe { + export namespace TransportSocket { } - export namespace SocketAddress { + } + export namespace route { + export namespace CorsPolicy { } - export namespace TcpKeepalive { + export namespace Decorator { } - export namespace BindConfig { + export namespace DirectResponseAction { } - export namespace Address { + export namespace FilterAction { } - export namespace CidrRange { + export namespace HeaderMatcher { } - export namespace HttpUri { + export namespace HedgePolicy { } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace SslCredentials { + export namespace QueryParameterMatcher { + } + export namespace RateLimit { + export namespace Action { + export namespace DestinationCluster { } - export namespace GoogleLocalCredentials { + export namespace GenericKey { } - export namespace ChannelCredentials { + export namespace HeaderValueMatch { + } + export namespace RemoteAddress { + } + export namespace RequestHeaders { } - export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace StsService { - } + export namespace SourceCluster { } } } - export namespace SocketOption { - } - } - export namespace route { - export namespace VirtualHost { - } - export namespace FilterAction { - } - export namespace Route { + export namespace RedirectAction { } - export namespace WeightedCluster { - export namespace ClusterWeight { + export namespace RetryPolicy { + export namespace RetryBackOff { } - } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { + export namespace RetryHostPredicate { } - export namespace TlsContextMatchOptions { + export namespace RetryPriority { } } - export namespace CorsPolicy { + export namespace Route { } export namespace RouteAction { - export namespace RequestMirrorPolicy { - } export namespace HashPolicy { - export namespace Header { + export namespace ConnectionProperties { } export namespace Cookie { } - export namespace ConnectionProperties { + export namespace FilterState { } - export namespace QueryParameter { + export namespace Header { } - export namespace FilterState { + export namespace QueryParameter { } } + export namespace RequestMirrorPolicy { + } export namespace UpgradeConfig { } } - export namespace RetryPolicy { - export namespace RetryPriority { - } - export namespace RetryHostPredicate { + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { } - export namespace RetryBackOff { + export namespace TlsContextMatchOptions { } } - export namespace HedgePolicy { - } - export namespace RedirectAction { - } - export namespace DirectResponseAction { - } - export namespace Decorator { - } export namespace Tracing { } export namespace VirtualCluster { } - export namespace RateLimit { - export namespace Action { - export namespace SourceCluster { - } - export namespace DestinationCluster { - } - export namespace RequestHeaders { - } - export namespace RemoteAddress { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - } - } - export namespace HeaderMatcher { + export namespace VirtualHost { } - export namespace QueryParameterMatcher { + export namespace WeightedCluster { + export namespace ClusterWeight { + } } } } } export namespace type { - export namespace Percent { + export namespace DoubleRange { } export namespace FractionalPercent { } + export namespace Int32Range { + } + export namespace Int64Range { + } + export namespace Percent { + } export namespace SemanticVersion { } export namespace matcher { + export namespace ListStringMatcher { + } + export namespace RegexMatchAndSubstitute { + } export namespace RegexMatcher { export namespace GoogleRE2 { } } - export namespace RegexMatchAndSubstitute { - } export namespace StringMatcher { } - export namespace ListStringMatcher { - } - } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Literal { - } - export namespace Environment { - } - export namespace Header { - } - export namespace Metadata { - } - } - } } export namespace metadata { export namespace v2 { @@ -659,165 +647,177 @@ export namespace ClientInterfaces { } } export namespace MetadataKind { + export namespace Cluster { + } + export namespace Host { + } export namespace Request { } export namespace Route { } - export namespace Cluster { + } + } + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Environment { } - export namespace Host { + export namespace Header { + } + export namespace Literal { + } + export namespace Metadata { } } } } } - export namespace annotations { - } - } - export namespace udpa { - export namespace annotations { - export namespace StatusAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } } export namespace google { export namespace protobuf { - export namespace DoubleValue { - } - export namespace FloatValue { + export namespace Any { } - export namespace Int64Value { + export namespace BoolValue { } - export namespace UInt64Value { + export namespace BytesValue { } - export namespace Int32Value { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } - export namespace UInt32Value { + export namespace DoubleValue { } - export namespace BoolValue { + export namespace Duration { } - export namespace StringValue { + export namespace Empty { } - export namespace BytesValue { + export namespace EnumDescriptorProto { } - export namespace Any { + export namespace EnumOptions { } - export namespace Duration { + export namespace EnumValueDescriptorProto { } - export namespace Struct { + export namespace EnumValueOptions { } - export namespace Value { + export namespace FieldDescriptorProto { } - export namespace ListValue { + export namespace FieldOptions { } - export namespace Timestamp { + export namespace FileDescriptorProto { } export namespace FileDescriptorSet { } - export namespace FileDescriptorProto { + export namespace FileOptions { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { + export namespace FloatValue { + } + export namespace GeneratedCodeInfo { + export namespace Annotation { } } - export namespace FieldDescriptorProto { + export namespace Int32Value { } - export namespace OneofDescriptorProto { + export namespace Int64Value { } - export namespace EnumDescriptorProto { + export namespace ListValue { } - export namespace EnumValueDescriptorProto { + export namespace MessageOptions { } - export namespace ServiceDescriptorProto { + export namespace MethodDescriptorProto { + } + export namespace MethodOptions { + } + export namespace OneofDescriptorProto { } - export namespace MethodDescriptorProto { + export namespace OneofOptions { } - export namespace FileOptions { + export namespace ServiceDescriptorProto { } - export namespace MessageOptions { + export namespace ServiceOptions { } - export namespace FieldOptions { + export namespace SourceCodeInfo { + export namespace Location { + } } - export namespace OneofOptions { + export namespace StringValue { } - export namespace EnumOptions { + export namespace Struct { } - export namespace EnumValueOptions { + export namespace Timestamp { } - export namespace ServiceOptions { + export namespace UInt32Value { } - export namespace MethodOptions { + export namespace UInt64Value { } export namespace UninterpretedOption { export namespace NamePart { } } - export namespace SourceCodeInfo { - export namespace Location { - } + export namespace Value { } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } + } + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace Empty { + export namespace FileMigrateAnnotation { + } + export namespace MigrateAnnotation { } + export namespace StatusAnnotation { + } + } + } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { } } } @@ -829,87 +829,84 @@ type SubtypeConstructor = { export interface ProtoGrpcType { envoy: { + annotations: { + } api: { v2: { RouteConfiguration: MessageTypeDefinition Vhds: MessageTypeDefinition core: { - RoutingPriority: EnumTypeDefinition - RequestMethod: EnumTypeDefinition - TrafficDirection: EnumTypeDefinition - Locality: MessageTypeDefinition + Address: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition Extension: MessageTypeDefinition - Node: MessageTypeDefinition - Metadata: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition HeaderValueOption: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - DataSource: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - TransportSocket: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - ApiVersion: EnumTypeDefinition - ApiConfigSource: MessageTypeDefinition - AggregatedConfigSource: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition - RateLimitSettings: MessageTypeDefinition - ConfigSource: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition - Pipe: MessageTypeDefinition SocketAddress: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - BindConfig: MessageTypeDefinition - Address: MessageTypeDefinition - CidrRange: MessageTypeDefinition - HttpUri: MessageTypeDefinition - GrpcService: MessageTypeDefinition SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition } route: { - VirtualHost: MessageTypeDefinition - FilterAction: MessageTypeDefinition - Route: MessageTypeDefinition - WeightedCluster: MessageTypeDefinition - RouteMatch: MessageTypeDefinition CorsPolicy: MessageTypeDefinition - RouteAction: MessageTypeDefinition - RetryPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition - DirectResponseAction: MessageTypeDefinition - Decorator: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteMatch: MessageTypeDefinition Tracing: MessageTypeDefinition VirtualCluster: MessageTypeDefinition - RateLimit: MessageTypeDefinition - HeaderMatcher: MessageTypeDefinition - QueryParameterMatcher: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition } } } type: { - Percent: MessageTypeDefinition + DoubleRange: MessageTypeDefinition FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition SemanticVersion: MessageTypeDefinition matcher: { - RegexMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition StringMatcher: MessageTypeDefinition - ListStringMatcher: MessageTypeDefinition - } - Int64Range: MessageTypeDefinition - Int32Range: MessageTypeDefinition - DoubleRange: MessageTypeDefinition - tracing: { - v2: { - CustomTag: MessageTypeDefinition - } } metadata: { v2: { @@ -917,90 +914,95 @@ export interface ProtoGrpcType { MetadataKind: MessageTypeDefinition } } + tracing: { + v2: { + CustomTag: MessageTypeDefinition + } + } } - annotations: { - } - } - udpa: { - annotations: { - PackageVersionStatus: EnumTypeDefinition - StatusAnnotation: MessageTypeDefinition - MigrateAnnotation: MessageTypeDefinition - FieldMigrateAnnotation: MessageTypeDefinition - FileMigrateAnnotation: MessageTypeDefinition - } - } - validate: { - FieldRules: MessageTypeDefinition - FloatRules: MessageTypeDefinition - DoubleRules: MessageTypeDefinition - Int32Rules: MessageTypeDefinition - Int64Rules: MessageTypeDefinition - UInt32Rules: MessageTypeDefinition - UInt64Rules: MessageTypeDefinition - SInt32Rules: MessageTypeDefinition - SInt64Rules: MessageTypeDefinition - Fixed32Rules: MessageTypeDefinition - Fixed64Rules: MessageTypeDefinition - SFixed32Rules: MessageTypeDefinition - SFixed64Rules: MessageTypeDefinition - BoolRules: MessageTypeDefinition - StringRules: MessageTypeDefinition - KnownRegex: EnumTypeDefinition - BytesRules: MessageTypeDefinition - EnumRules: MessageTypeDefinition - MessageRules: MessageTypeDefinition - RepeatedRules: MessageTypeDefinition - MapRules: MessageTypeDefinition - AnyRules: MessageTypeDefinition - DurationRules: MessageTypeDefinition - TimestampRules: MessageTypeDefinition } google: { protobuf: { - DoubleValue: MessageTypeDefinition - FloatValue: MessageTypeDefinition - Int64Value: MessageTypeDefinition - UInt64Value: MessageTypeDefinition - Int32Value: MessageTypeDefinition - UInt32Value: MessageTypeDefinition + Any: MessageTypeDefinition BoolValue: MessageTypeDefinition - StringValue: MessageTypeDefinition BytesValue: MessageTypeDefinition - Any: MessageTypeDefinition - Duration: MessageTypeDefinition - Struct: MessageTypeDefinition - Value: MessageTypeDefinition - NullValue: EnumTypeDefinition - ListValue: MessageTypeDefinition - Timestamp: MessageTypeDefinition - FileDescriptorSet: MessageTypeDefinition - FileDescriptorProto: MessageTypeDefinition DescriptorProto: MessageTypeDefinition - FieldDescriptorProto: MessageTypeDefinition - OneofDescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition EnumValueDescriptorProto: MessageTypeDefinition - ServiceDescriptorProto: MessageTypeDefinition - MethodDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition MessageOptions: MessageTypeDefinition - FieldOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition OneofOptions: MessageTypeDefinition - EnumOptions: MessageTypeDefinition - EnumValueOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition ServiceOptions: MessageTypeDefinition - MethodOptions: MessageTypeDefinition - UninterpretedOption: MessageTypeDefinition SourceCodeInfo: MessageTypeDefinition - GeneratedCodeInfo: MessageTypeDefinition - Empty: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition } } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } } export namespace ServiceHandlers { export namespace envoy { + export namespace annotations { + } export namespace api { export namespace v2 { export namespace RouteConfiguration { @@ -1008,211 +1010,197 @@ export namespace ServiceHandlers { export namespace Vhds { } export namespace core { - export namespace Locality { + export namespace Address { + } + export namespace AggregatedConfigSource { + } + export namespace ApiConfigSource { + } + export namespace AsyncDataSource { + } + export namespace BackoffStrategy { + } + export namespace BindConfig { } export namespace BuildVersion { } - export namespace Extension { + export namespace CidrRange { } - export namespace Node { + export namespace ConfigSource { } - export namespace Metadata { + export namespace ControlPlane { } - export namespace RuntimeUInt32 { + export namespace DataSource { } - export namespace RuntimeDouble { + export namespace Extension { } - export namespace RuntimeFeatureFlag { + export namespace GrpcService { + export namespace EnvoyGrpc { + } + export namespace GoogleGrpc { + export namespace CallCredentials { + export namespace GoogleIAMCredentials { + } + export namespace MetadataCredentialsFromPlugin { + } + export namespace ServiceAccountJWTAccessCredentials { + } + export namespace StsService { + } + } + export namespace ChannelCredentials { + } + export namespace GoogleLocalCredentials { + } + export namespace SslCredentials { + } + } + } + export namespace HeaderMap { } export namespace HeaderValue { } export namespace HeaderValueOption { } - export namespace HeaderMap { + export namespace HttpUri { } - export namespace DataSource { + export namespace Locality { } - export namespace RetryPolicy { + export namespace Metadata { } - export namespace RemoteDataSource { + export namespace Node { } - export namespace AsyncDataSource { + export namespace Pipe { } - export namespace TransportSocket { + export namespace RateLimitSettings { } - export namespace RuntimeFractionalPercent { + export namespace RemoteDataSource { } - export namespace ControlPlane { + export namespace RetryPolicy { } - export namespace ApiConfigSource { + export namespace RuntimeDouble { } - export namespace AggregatedConfigSource { + export namespace RuntimeFeatureFlag { + } + export namespace RuntimeFractionalPercent { + } + export namespace RuntimeUInt32 { } export namespace SelfConfigSource { } - export namespace RateLimitSettings { + export namespace SocketAddress { } - export namespace ConfigSource { + export namespace SocketOption { } - export namespace BackoffStrategy { + export namespace TcpKeepalive { } - export namespace Pipe { + export namespace TransportSocket { } - export namespace SocketAddress { + } + export namespace route { + export namespace CorsPolicy { } - export namespace TcpKeepalive { + export namespace Decorator { } - export namespace BindConfig { + export namespace DirectResponseAction { } - export namespace Address { + export namespace FilterAction { } - export namespace CidrRange { + export namespace HeaderMatcher { } - export namespace HttpUri { + export namespace HedgePolicy { } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace SslCredentials { + export namespace QueryParameterMatcher { + } + export namespace RateLimit { + export namespace Action { + export namespace DestinationCluster { } - export namespace GoogleLocalCredentials { + export namespace GenericKey { } - export namespace ChannelCredentials { + export namespace HeaderValueMatch { } - export namespace CallCredentials { - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace StsService { - } + export namespace RemoteAddress { + } + export namespace RequestHeaders { + } + export namespace SourceCluster { } } } - export namespace SocketOption { - } - } - export namespace route { - export namespace VirtualHost { - } - export namespace FilterAction { - } - export namespace Route { + export namespace RedirectAction { } - export namespace WeightedCluster { - export namespace ClusterWeight { + export namespace RetryPolicy { + export namespace RetryBackOff { } - } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { + export namespace RetryHostPredicate { } - export namespace TlsContextMatchOptions { + export namespace RetryPriority { } } - export namespace CorsPolicy { + export namespace Route { } export namespace RouteAction { - export namespace RequestMirrorPolicy { - } export namespace HashPolicy { - export namespace Header { + export namespace ConnectionProperties { } export namespace Cookie { } - export namespace ConnectionProperties { + export namespace FilterState { } - export namespace QueryParameter { + export namespace Header { } - export namespace FilterState { + export namespace QueryParameter { } } + export namespace RequestMirrorPolicy { + } export namespace UpgradeConfig { } } - export namespace RetryPolicy { - export namespace RetryPriority { - } - export namespace RetryHostPredicate { + export namespace RouteMatch { + export namespace GrpcRouteMatchOptions { } - export namespace RetryBackOff { + export namespace TlsContextMatchOptions { } } - export namespace HedgePolicy { - } - export namespace RedirectAction { - } - export namespace DirectResponseAction { - } - export namespace Decorator { - } export namespace Tracing { } export namespace VirtualCluster { } - export namespace RateLimit { - export namespace Action { - export namespace SourceCluster { - } - export namespace DestinationCluster { - } - export namespace RequestHeaders { - } - export namespace RemoteAddress { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - } - } - export namespace HeaderMatcher { + export namespace VirtualHost { } - export namespace QueryParameterMatcher { + export namespace WeightedCluster { + export namespace ClusterWeight { + } } } } } export namespace type { - export namespace Percent { + export namespace DoubleRange { } export namespace FractionalPercent { } + export namespace Int32Range { + } + export namespace Int64Range { + } + export namespace Percent { + } export namespace SemanticVersion { } export namespace matcher { + export namespace ListStringMatcher { + } + export namespace RegexMatchAndSubstitute { + } export namespace RegexMatcher { export namespace GoogleRE2 { } } - export namespace RegexMatchAndSubstitute { - } export namespace StringMatcher { } - export namespace ListStringMatcher { - } - } - export namespace Int64Range { - } - export namespace Int32Range { - } - export namespace DoubleRange { - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Literal { - } - export namespace Environment { - } - export namespace Header { - } - export namespace Metadata { - } - } - } } export namespace metadata { export namespace v2 { @@ -1221,165 +1209,177 @@ export namespace ServiceHandlers { } } export namespace MetadataKind { + export namespace Cluster { + } + export namespace Host { + } export namespace Request { } export namespace Route { } - export namespace Cluster { + } + } + } + export namespace tracing { + export namespace v2 { + export namespace CustomTag { + export namespace Environment { } - export namespace Host { + export namespace Header { + } + export namespace Literal { + } + export namespace Metadata { } } } } } - export namespace annotations { - } } - export namespace udpa { - export namespace annotations { - export namespace StatusAnnotation { + export namespace google { + export namespace protobuf { + export namespace Any { } - export namespace MigrateAnnotation { + export namespace BoolValue { } - export namespace FieldMigrateAnnotation { + export namespace BytesValue { } - export namespace FileMigrateAnnotation { + export namespace DescriptorProto { + export namespace ExtensionRange { + } + export namespace ReservedRange { + } } - } - } - export namespace validate { - export namespace FieldRules { - } - export namespace FloatRules { - } - export namespace DoubleRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace BoolRules { - } - export namespace StringRules { - } - export namespace BytesRules { - } - export namespace EnumRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace MapRules { - } - export namespace AnyRules { - } - export namespace DurationRules { - } - export namespace TimestampRules { - } - } - export namespace google { - export namespace protobuf { export namespace DoubleValue { } - export namespace FloatValue { + export namespace Duration { } - export namespace Int64Value { + export namespace Empty { } - export namespace UInt64Value { + export namespace EnumDescriptorProto { } - export namespace Int32Value { + export namespace EnumOptions { } - export namespace UInt32Value { + export namespace EnumValueDescriptorProto { } - export namespace BoolValue { + export namespace EnumValueOptions { } - export namespace StringValue { + export namespace FieldDescriptorProto { } - export namespace BytesValue { + export namespace FieldOptions { } - export namespace Any { + export namespace FileDescriptorProto { } - export namespace Duration { + export namespace FileDescriptorSet { } - export namespace Struct { + export namespace FileOptions { } - export namespace Value { + export namespace FloatValue { } - export namespace ListValue { + export namespace GeneratedCodeInfo { + export namespace Annotation { + } } - export namespace Timestamp { + export namespace Int32Value { } - export namespace FileDescriptorSet { + export namespace Int64Value { } - export namespace FileDescriptorProto { + export namespace ListValue { } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } + export namespace MessageOptions { } - export namespace FieldDescriptorProto { + export namespace MethodDescriptorProto { } - export namespace OneofDescriptorProto { + export namespace MethodOptions { } - export namespace EnumDescriptorProto { + export namespace OneofDescriptorProto { } - export namespace EnumValueDescriptorProto { + export namespace OneofOptions { } export namespace ServiceDescriptorProto { } - export namespace MethodDescriptorProto { - } - export namespace FileOptions { - } - export namespace MessageOptions { + export namespace ServiceOptions { } - export namespace FieldOptions { + export namespace SourceCodeInfo { + export namespace Location { + } } - export namespace OneofOptions { + export namespace StringValue { } - export namespace EnumOptions { + export namespace Struct { } - export namespace EnumValueOptions { + export namespace Timestamp { } - export namespace ServiceOptions { + export namespace UInt32Value { } - export namespace MethodOptions { + export namespace UInt64Value { } export namespace UninterpretedOption { export namespace NamePart { } } - export namespace SourceCodeInfo { - export namespace Location { - } + export namespace Value { } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } + } + } + export namespace udpa { + export namespace annotations { + export namespace FieldMigrateAnnotation { } - export namespace Empty { + export namespace FileMigrateAnnotation { + } + export namespace MigrateAnnotation { + } + export namespace StatusAnnotation { } } } + export namespace validate { + export namespace AnyRules { + } + export namespace BoolRules { + } + export namespace BytesRules { + } + export namespace DoubleRules { + } + export namespace DurationRules { + } + export namespace EnumRules { + } + export namespace FieldRules { + } + export namespace Fixed32Rules { + } + export namespace Fixed64Rules { + } + export namespace FloatRules { + } + export namespace Int32Rules { + } + export namespace Int64Rules { + } + export namespace MapRules { + } + export namespace MessageRules { + } + export namespace RepeatedRules { + } + export namespace SFixed32Rules { + } + export namespace SFixed64Rules { + } + export namespace SInt32Rules { + } + export namespace SInt64Rules { + } + export namespace StringRules { + } + export namespace TimestampRules { + } + export namespace UInt32Rules { + } + export namespace UInt64Rules { + } + } } diff --git a/packages/grpc-js/src/generated/validate/BytesRules.ts b/packages/grpc-js/src/generated/validate/BytesRules.ts index 7d356fef2..a18bf6906 100644 --- a/packages/grpc-js/src/generated/validate/BytesRules.ts +++ b/packages/grpc-js/src/generated/validate/BytesRules.ts @@ -4,7 +4,6 @@ import { Long } from '@grpc/proto-loader'; export interface BytesRules { 'const'?: (Buffer | Uint8Array | string); - 'len'?: (number | string | Long); 'min_len'?: (number | string | Long); 'max_len'?: (number | string | Long); 'pattern'?: (string); @@ -16,12 +15,12 @@ export interface BytesRules { 'ip'?: (boolean); 'ipv4'?: (boolean); 'ipv6'?: (boolean); + 'len'?: (number | string | Long); 'well_known'?: "ip"|"ipv4"|"ipv6"; } export interface BytesRules__Output { 'const': (Buffer); - 'len': (string); 'min_len': (string); 'max_len': (string); 'pattern': (string); @@ -33,5 +32,6 @@ export interface BytesRules__Output { 'ip'?: (boolean); 'ipv4'?: (boolean); 'ipv6'?: (boolean); + 'len': (string); 'well_known': "ip"|"ipv4"|"ipv6"; } diff --git a/packages/grpc-js/src/generated/validate/FieldRules.ts b/packages/grpc-js/src/generated/validate/FieldRules.ts index 099391f44..5451902d7 100644 --- a/packages/grpc-js/src/generated/validate/FieldRules.ts +++ b/packages/grpc-js/src/generated/validate/FieldRules.ts @@ -1,6 +1,5 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from '../validate/MessageRules'; import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from '../validate/FloatRules'; import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from '../validate/DoubleRules'; import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from '../validate/Int32Rules'; @@ -17,6 +16,7 @@ import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRu import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from '../validate/StringRules'; import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from '../validate/BytesRules'; import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from '../validate/EnumRules'; +import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from '../validate/MessageRules'; import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from '../validate/RepeatedRules'; import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from '../validate/MapRules'; import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from '../validate/AnyRules'; @@ -25,7 +25,6 @@ import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _ import { Long } from '@grpc/proto-loader'; export interface FieldRules { - 'message'?: (_validate_MessageRules); 'float'?: (_validate_FloatRules); 'double'?: (_validate_DoubleRules); 'int32'?: (_validate_Int32Rules); @@ -42,6 +41,7 @@ export interface FieldRules { 'string'?: (_validate_StringRules); 'bytes'?: (_validate_BytesRules); 'enum'?: (_validate_EnumRules); + 'message'?: (_validate_MessageRules); 'repeated'?: (_validate_RepeatedRules); 'map'?: (_validate_MapRules); 'any'?: (_validate_AnyRules); @@ -51,7 +51,6 @@ export interface FieldRules { } export interface FieldRules__Output { - 'message': (_validate_MessageRules__Output); 'float'?: (_validate_FloatRules__Output); 'double'?: (_validate_DoubleRules__Output); 'int32'?: (_validate_Int32Rules__Output); @@ -68,6 +67,7 @@ export interface FieldRules__Output { 'string'?: (_validate_StringRules__Output); 'bytes'?: (_validate_BytesRules__Output); 'enum'?: (_validate_EnumRules__Output); + 'message': (_validate_MessageRules__Output); 'repeated'?: (_validate_RepeatedRules__Output); 'map'?: (_validate_MapRules__Output); 'any'?: (_validate_AnyRules__Output); diff --git a/packages/grpc-js/src/generated/validate/StringRules.ts b/packages/grpc-js/src/generated/validate/StringRules.ts index ed4339f90..810697f57 100644 --- a/packages/grpc-js/src/generated/validate/StringRules.ts +++ b/packages/grpc-js/src/generated/validate/StringRules.ts @@ -5,17 +5,14 @@ import { Long } from '@grpc/proto-loader'; export interface StringRules { 'const'?: (string); - 'len'?: (number | string | Long); 'min_len'?: (number | string | Long); 'max_len'?: (number | string | Long); - 'len_bytes'?: (number | string | Long); 'min_bytes'?: (number | string | Long); 'max_bytes'?: (number | string | Long); 'pattern'?: (string); 'prefix'?: (string); 'suffix'?: (string); 'contains'?: (string); - 'not_contains'?: (string); 'in'?: (string)[]; 'not_in'?: (string)[]; 'email'?: (boolean); @@ -25,8 +22,11 @@ export interface StringRules { 'ipv6'?: (boolean); 'uri'?: (boolean); 'uri_ref'?: (boolean); + 'len'?: (number | string | Long); + 'len_bytes'?: (number | string | Long); 'address'?: (boolean); 'uuid'?: (boolean); + 'not_contains'?: (string); 'well_known_regex'?: (_validate_KnownRegex | keyof typeof _validate_KnownRegex); 'strict'?: (boolean); 'well_known'?: "email"|"hostname"|"ip"|"ipv4"|"ipv6"|"uri"|"uri_ref"|"address"|"uuid"|"well_known_regex"; @@ -34,17 +34,14 @@ export interface StringRules { export interface StringRules__Output { 'const': (string); - 'len': (string); 'min_len': (string); 'max_len': (string); - 'len_bytes': (string); 'min_bytes': (string); 'max_bytes': (string); 'pattern': (string); 'prefix': (string); 'suffix': (string); 'contains': (string); - 'not_contains': (string); 'in': (string)[]; 'not_in': (string)[]; 'email'?: (boolean); @@ -54,8 +51,11 @@ export interface StringRules__Output { 'ipv6'?: (boolean); 'uri'?: (boolean); 'uri_ref'?: (boolean); + 'len': (string); + 'len_bytes': (string); 'address'?: (boolean); 'uuid'?: (boolean); + 'not_contains': (string); 'well_known_regex'?: (keyof typeof _validate_KnownRegex); 'strict': (boolean); 'well_known': "email"|"hostname"|"ip"|"ipv4"|"ipv6"|"uri"|"uri_ref"|"address"|"uuid"|"well_known_regex"; From e80d89479e931e2a92db6962028c356b02a51c18 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 12:48:53 -0700 Subject: [PATCH 1150/1899] Refactor shared code, remove mkdirp, sort some things for stable output, add verbose option --- .../bin/proto-loader-gen-types.ts | 99 +++++++-------- packages/proto-loader/package.json | 1 - packages/proto-loader/src/index.ts | 89 ++------------ packages/proto-loader/src/util.ts | 113 ++++++++++++++++++ 4 files changed, 169 insertions(+), 133 deletions(-) create mode 100644 packages/proto-loader/src/util.ts diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 551281de0..8b12a878a 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -20,16 +20,27 @@ import * as fs from 'fs'; import * as path from 'path'; -import * as mkdirp from 'mkdirp'; import * as Protobuf from 'protobufjs'; import * as yargs from 'yargs'; import camelCase = require('lodash.camelcase'); +import { loadProtosWithOptions, addCommonProtos } from '../src/util'; + +function compareName(x: {name: string}, y: {name: string}): number { + if (x.name < y.name) { + return -1; + } else if (x.name > y.name) { + return 1 + } else { + return 0; + } +} type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeDirs?: string[]; grpcLib: string; outDir: string; + verbose?: boolean; } class TextFormatter { @@ -278,6 +289,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob const childTypes = getChildMessagesAndEnums(messageType); formatter.writeLine(`// Original file: ${messageType.filename}`); formatter.writeLine(''); + messageType.fieldsArray.sort((fieldA, fieldB) => fieldA.id - fieldB.id); for (const field of messageType.fieldsArray) { if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { const dependency = field.resolvedType; @@ -345,7 +357,7 @@ function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum } function generateMessageAndEnumImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { - for (const nested of namespace.nestedArray) { + for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { formatter.writeLine(getImportLine(nested)); } else if (isNamespaceBase(nested)) { @@ -357,7 +369,7 @@ function generateMessageAndEnumImports(formatter: TextFormatter, namespace: Prot function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); formatter.indent(); - for (const nested of namespace.nestedArray) { + for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Enum || nested instanceof Protobuf.Type) { formatter.writeLine(`export type ${nested.name} = ${getTypeInterfaceName(nested)};`); if (nested instanceof Protobuf.Type) { @@ -374,7 +386,7 @@ function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Prot function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { formatter.writeLine(`export interface ${serviceType.name}Client extends grpc.Client {`); formatter.indent(); - for (const methodName of Object.keys(serviceType.methods)) { + for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; for (const name of [methodName, camelCase(methodName)]) { const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName); @@ -419,7 +431,7 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); formatter.indent(); - for (const nested of namespace.nestedArray) { + for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { generateServiceClientInterface(formatter, nested); } else if (isNamespaceBase(nested)) { @@ -445,7 +457,7 @@ function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Pr function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { formatter.writeLine(`${namespace.name}: {`); formatter.indent(); - for (const nested of namespace.nestedArray) { + for (const nested of namespace.nestedArray.sort(compareName)) { generateSingleLoadedDefinitionType(formatter, nested); } formatter.unindent(); @@ -455,7 +467,7 @@ function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Prot function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { formatter.writeLine(`export interface ${serviceType.name} {`); formatter.indent(); - for (const methodName of Object.keys(serviceType.methods)) { + for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName) + '__Output'; const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName); @@ -485,7 +497,7 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: function generateAllServiceHandlerInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); formatter.indent(); - for (const nested of namespace.nestedArray) { + for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { generateServiceHandlerInterface(formatter, nested); } else if (isNamespaceBase(nested)) { @@ -496,7 +508,7 @@ function generateAllServiceHandlerInterfaces(formatter: TextFormatter, namespace formatter.writeLine('}'); } -function generateMasterFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { +function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { formatter.writeLine(`import * as grpc from '${options.grpcLib}';`); formatter.writeLine("import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); formatter.writeLine(''); @@ -528,10 +540,9 @@ function generateMasterFile(formatter: TextFormatter, root: Protobuf.Root, optio generateAllServiceHandlerInterfaces(formatter, root, 'ServiceHandlers'); } -function writeFile(filename: string, contents: string): Promise { - return mkdirp(path.dirname(filename)).then( - () => fs.promises.writeFile(filename, contents) - ); +async function writeFile(filename: string, contents: string): Promise { + await fs.promises.mkdir(path.dirname(filename), {recursive: true}); + return fs.promises.writeFile(filename, contents); } function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: GeneratorOptions): Promise[] { @@ -540,11 +551,15 @@ function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: G const fileFormatter = new TextFormatter(); if (nested instanceof Protobuf.Type) { generateMessageInterfaces(fileFormatter, nested, options); - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + } filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Enum) { generateEnumInterface(fileFormatter, nested); - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + } filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); } else if (isNamespaceBase(nested)) { filePromises.push(...generateFilesForNamespace(nested, options)); @@ -557,8 +572,10 @@ function writeFilesForRoot(root: Protobuf.Root, masterFileName: string, options: const filePromises: Promise[] = []; const masterFileFormatter = new TextFormatter(); - generateMasterFile(masterFileFormatter, root, options); - console.log(`Writing ${options.outDir}/${masterFileName}`); + generateRootFile(masterFileFormatter, root, options); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${masterFileName}`); + } filePromises.push(writeFile(`${options.outDir}/${masterFileName}`, masterFileFormatter.getFullText())); filePromises.push(...generateFilesForNamespace(root, options)); @@ -566,40 +583,10 @@ function writeFilesForRoot(root: Protobuf.Root, masterFileName: string, options: return filePromises; } -function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { - const originalResolvePath = root.resolvePath; - root.resolvePath = (origin: string, target: string) => { - if (path.isAbsolute(target)) { - return target; - } - for (const directory of includePaths) { - const fullPath: string = path.join(directory, target); - try { - fs.accessSync(fullPath, fs.constants.R_OK); - return fullPath; - } catch (err) { - continue; - } - } - process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); - return originalResolvePath(origin, target); - }; -} - async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { - await mkdirp(options.outDir); + await fs.promises.mkdir(options.outDir, {recursive: true}); for (const filename of protoFiles) { - console.log(`Processing ${filename}`); - const root: Protobuf.Root = new Protobuf.Root(); - options = options || {}; - if (!!options.includeDirs) { - if (!Array.isArray(options.includeDirs)) { - throw new Error('The includeDirs option must be an array'); - } - addIncludePathResolver(root, options.includeDirs as string[]); - } - const loadedRoot = await root.load(filename, options); - root.resolveAll(); + const loadedRoot = await loadProtosWithOptions(filename, options); writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.ts'), options); } } @@ -609,7 +596,7 @@ function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose']) // .choices('longs', ['String', 'Number']) // .choices('enums', ['String']) // .choices('bytes', ['Array', 'String']) @@ -641,7 +628,8 @@ function runScript() { } }).alias({ includeDirs: 'I', - outDir: 'O' + outDir: 'O', + verbose: 'v' }).describe({ keepCase: 'Preserve the case of field names', longs: 'The type that should be used to output 64 bit integer values. Can be String, Number', @@ -660,9 +648,14 @@ function runScript() { .usage('$0 [options] filenames...') .epilogue('WARNING: This tool is in alpha. The CLI and generated code are subject to change') .argv; - console.log(argv); + if (argv.verbose) { + console.log('Parsed arguments:', argv); + } + addCommonProtos(); writeAllFiles(argv._, argv).then(() => { - console.log('Success'); + if (argv.verbose) { + console.log('Success'); + } }, (error) => { throw error; }) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index c7036bb2a..cba1fa556 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -46,7 +46,6 @@ "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^4.0.0", - "mkdirp": "^1.0.4", "protobufjs": "^6.9.0", "yargs": "^15.3.1" }, diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 03c9512aa..a830ac3eb 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -15,11 +15,13 @@ * limitations under the License. * */ -import * as fs from 'fs'; -import * as path from 'path'; + +import camelCase = require('lodash.camelcase'); import * as Protobuf from 'protobufjs'; import * as descriptor from 'protobufjs/ext/descriptor'; +import { loadProtosWithOptionsSync, loadProtosWithOptions, Options, addCommonProtos } from './util'; + export { Long } from 'long'; /** @@ -55,8 +57,6 @@ export function isAnyExtension(obj: object): obj is AnyExtension { return ('@type' in obj) && (typeof (obj as AnyExtension)['@type'] === 'string'); } -import camelCase = require('lodash.camelcase'); - declare module 'protobufjs' { interface Type { toDescriptor( @@ -128,10 +128,7 @@ export interface PackageDefinition { [index: string]: AnyDefinition; } -export type Options = Protobuf.IParseOptions & - Protobuf.IConversionOptions & { - includeDirs?: string[]; - }; +export { Options }; const descriptorOptions: Protobuf.IConversionOptions = { longs: String, @@ -322,26 +319,6 @@ function createPackageDefinition( return def; } -function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { - const originalResolvePath = root.resolvePath; - root.resolvePath = (origin: string, target: string) => { - if (path.isAbsolute(target)) { - return target; - } - for (const directory of includePaths) { - const fullPath: string = path.join(directory, target); - try { - fs.accessSync(fullPath, fs.constants.R_OK); - return fullPath; - } catch (err) { - continue; - } - } - process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); - return originalResolvePath(origin, target); - }; -} - /** * Load a .proto file with the specified options. * @param filename One or multiple file paths to load. Can be an absolute path @@ -372,19 +349,8 @@ export function load( filename: string | string[], options?: Options ): Promise { - const root: Protobuf.Root = new Protobuf.Root(); - options = options || {}; - if (!!options.includeDirs) { - if (!Array.isArray(options.includeDirs)) { - return Promise.reject( - new Error('The includeDirs option must be an array') - ); - } - addIncludePathResolver(root, options.includeDirs as string[]); - } - return root.load(filename, options).then(loadedRoot => { - loadedRoot.resolveAll(); - return createPackageDefinition(root, options!); + return loadProtosWithOptions(filename, options).then(loadedRoot => { + return createPackageDefinition(loadedRoot, options!); }); } @@ -392,43 +358,8 @@ export function loadSync( filename: string | string[], options?: Options ): PackageDefinition { - const root: Protobuf.Root = new Protobuf.Root(); - options = options || {}; - if (!!options.includeDirs) { - if (!Array.isArray(options.includeDirs)) { - throw new Error('The includeDirs option must be an array'); - } - addIncludePathResolver(root, options.includeDirs as string[]); - } - const loadedRoot = root.loadSync(filename, options); - loadedRoot.resolveAll(); - return createPackageDefinition(root, options!); + const loadedRoot = loadProtosWithOptionsSync(filename, options); + return createPackageDefinition(loadedRoot, options!); } -// Load Google's well-known proto files that aren't exposed by Protobuf.js. - -// Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, -// and wrappers. compiler/plugin is excluded in Protobuf.js and here. - -// Using constant strings for compatibility with tools like Webpack -const apiDescriptor = require('protobufjs/google/protobuf/api.json'); -const descriptorDescriptor = require('protobufjs/google/protobuf/descriptor.json'); -const sourceContextDescriptor = require('protobufjs/google/protobuf/source_context.json'); -const typeDescriptor = require('protobufjs/google/protobuf/type.json'); - -Protobuf.common( - 'api', - apiDescriptor.nested.google.nested.protobuf.nested -); -Protobuf.common( - 'descriptor', - descriptorDescriptor.nested.google.nested.protobuf.nested -); -Protobuf.common( - 'source_context', - sourceContextDescriptor.nested.google.nested.protobuf.nested -); -Protobuf.common( - 'type', - typeDescriptor.nested.google.nested.protobuf.nested -); +addCommonProtos(); diff --git a/packages/proto-loader/src/util.ts b/packages/proto-loader/src/util.ts new file mode 100644 index 000000000..a4a8502b6 --- /dev/null +++ b/packages/proto-loader/src/util.ts @@ -0,0 +1,113 @@ +/** + * @license + * Copyright 2018 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; +import * as path from 'path'; +import * as Protobuf from 'protobufjs'; + +function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { + const originalResolvePath = root.resolvePath; + root.resolvePath = (origin: string, target: string) => { + if (path.isAbsolute(target)) { + return target; + } + for (const directory of includePaths) { + const fullPath: string = path.join(directory, target); + try { + fs.accessSync(fullPath, fs.constants.R_OK); + return fullPath; + } catch (err) { + continue; + } + } + process.emitWarning(`${target} not found in any of the include paths ${includePaths}`); + return originalResolvePath(origin, target); + }; +} + +export type Options = Protobuf.IParseOptions & + Protobuf.IConversionOptions & { + includeDirs?: string[]; + }; + +export async function loadProtosWithOptions( + filename: string | string[], + options?: Options +): Promise { + const root: Protobuf.Root = new Protobuf.Root(); + options = options || {}; + if (!!options.includeDirs) { + if (!Array.isArray(options.includeDirs)) { + return Promise.reject( + new Error('The includeDirs option must be an array') + ); + } + addIncludePathResolver(root, options.includeDirs as string[]); + } + const loadedRoot = await root.load(filename, options); + loadedRoot.resolveAll(); + return loadedRoot; +} + +export function loadProtosWithOptionsSync( + filename: string | string[], + options?: Options +): Protobuf.Root { + const root: Protobuf.Root = new Protobuf.Root(); + options = options || {}; + if (!!options.includeDirs) { + if (!Array.isArray(options.includeDirs)) { + throw new Error('The includeDirs option must be an array'); + } + addIncludePathResolver(root, options.includeDirs as string[]); + } + const loadedRoot = root.loadSync(filename, options); + loadedRoot.resolveAll(); + return loadedRoot; +} + +/** + * Load Google's well-known proto files that aren't exposed by Protobuf.js. + */ +export function addCommonProtos(): void { + // Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, + // and wrappers. compiler/plugin is excluded in Protobuf.js and here. + + // Using constant strings for compatibility with tools like Webpack + const apiDescriptor = require('protobufjs/google/protobuf/api.json'); + const descriptorDescriptor = require('protobufjs/google/protobuf/descriptor.json'); + const sourceContextDescriptor = require('protobufjs/google/protobuf/source_context.json'); + const typeDescriptor = require('protobufjs/google/protobuf/type.json'); + + Protobuf.common( + 'api', + apiDescriptor.nested.google.nested.protobuf.nested + ); + Protobuf.common( + 'descriptor', + descriptorDescriptor.nested.google.nested.protobuf.nested + ); + Protobuf.common( + 'source_context', + sourceContextDescriptor.nested.google.nested.protobuf.nested + ); + Protobuf.common( + 'type', + typeDescriptor.nested.google.nested.protobuf.nested + ); +} \ No newline at end of file From e14667207e2b009b849f27876d029f02a8a4fd02 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 12:49:37 -0700 Subject: [PATCH 1151/1899] Bump prerelease version again --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index cba1fa556..eda794253 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre7", + "version": "0.6.0-pre8", "author": "Google Inc.", "contributors": [ { From 8e6dae7bb768b5d8125ab021c2a0112818bc00ee Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 14:14:24 -0700 Subject: [PATCH 1152/1899] Add option to generate comments --- .../bin/proto-loader-gen-types.ts | 137 +++++++++++++----- packages/proto-loader/package.json | 2 +- 2 files changed, 100 insertions(+), 39 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 8b12a878a..ea035d6cd 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -26,21 +26,12 @@ import * as yargs from 'yargs'; import camelCase = require('lodash.camelcase'); import { loadProtosWithOptions, addCommonProtos } from '../src/util'; -function compareName(x: {name: string}, y: {name: string}): number { - if (x.name < y.name) { - return -1; - } else if (x.name > y.name) { - return 1 - } else { - return 0; - } -} - type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeDirs?: string[]; grpcLib: string; outDir: string; verbose?: boolean; + includeComments?: boolean; } class TextFormatter { @@ -70,6 +61,18 @@ class TextFormatter { } } +// GENERATOR UTILITY FUNCTIONS + +function compareName(x: {name: string}, y: {name: string}): number { + if (x.name < y.name) { + return -1; + } else if (x.name > y.name) { + return 1 + } else { + return 0; + } +} + function isNamespaceBase(obj: Protobuf.ReflectionObject): obj is Protobuf.NamespaceBase { return Array.isArray((obj as Protobuf.NamespaceBase).nestedArray); } @@ -119,7 +122,23 @@ function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf. return messageList; } -function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, nameOverride?: string) { +function formatComment(formatter: TextFormatter, comment?: string | null) { + if (!comment) { + return; + } + formatter.writeLine('/**'); + for(const line of comment.split('\n')) { + formatter.writeLine(` * ${line.replace(/\*\//g, '* /')}`); + } + formatter.writeLine(' */'); +} + +// GENERATOR FUNCTIONS + +function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { + if (options.includeComments) { + formatComment(formatter, messageType.comment); + } if (messageType.fullName === '.google.protobuf.Any') { /* This describes the behavior of the Protobuf.js Any wrapper fromObject * replacement function */ @@ -173,17 +192,26 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp type = `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; } } + if (options.includeComments) { + formatComment(formatter, field.comment); + } formatter.writeLine(`'${field.name}'?: (${type})${repeatedString};`); } for (const oneof of messageType.oneofsArray) { const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); + if (options.includeComments) { + formatComment(formatter, oneof.comment); + } formatter.writeLine(`'${oneof.name}'?: ${typeString};`); } formatter.unindent(); formatter.writeLine('}'); } -function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions, nameOverride?: string) { +function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { + if (options.includeComments) { + formatComment(formatter, messageType.comment); + } if (messageType.fullName === '.google.protobuf.Any' && options.json) { /* This describes the behavior of the Protobuf.js Any wrapper toObject * replacement function */ @@ -271,11 +299,17 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp fieldGuaranteed = false; } const optionalString = fieldGuaranteed ? '' : '?'; + if (options.includeComments) { + formatComment(formatter, field.comment); + } formatter.writeLine(`'${field.name}'${optionalString}: (${type})${repeatedString};`); } if (options.oneofs) { for (const oneof of messageType.oneofsArray) { const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); + if (options.includeComments) { + formatComment(formatter, oneof.comment); + } formatter.writeLine(`'${oneof.name}': ${typeString};`); } } @@ -283,7 +317,7 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp formatter.writeLine('}'); } -function generateMessageInterfaces(formatter: TextFormatter, messageType: Protobuf.Type, options: Protobuf.IConversionOptions) { +function generateMessageInterfaces(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions) { let usesLong: boolean = false; let seenDeps: Set = new Set(); const childTypes = getChildMessagesAndEnums(messageType); @@ -330,26 +364,32 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob for (const childType of childTypes) { const nameOverride = getTypeInterfaceName(childType); if (childType instanceof Protobuf.Type) { - generatePermissiveMessageInterface(formatter, childType, nameOverride); + generatePermissiveMessageInterface(formatter, childType, options, nameOverride); formatter.writeLine(''); generateRestrictedMessageInterface(formatter, childType, options, nameOverride); } else { - generateEnumInterface(formatter, childType, nameOverride); + generateEnumInterface(formatter, childType, options, nameOverride); } formatter.writeLine(''); } - generatePermissiveMessageInterface(formatter, messageType); + generatePermissiveMessageInterface(formatter, messageType, options); formatter.writeLine(''); generateRestrictedMessageInterface(formatter, messageType, options); } -function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, nameOverride?: string) { +function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, options: GeneratorOptions, nameOverride?: string) { formatter.writeLine(`// Original file: ${enumType.filename}`); formatter.writeLine(''); + if (options.includeComments) { + formatComment(formatter, enumType.comment); + } formatter.writeLine(`export enum ${nameOverride ?? enumType.name} {`); formatter.indent(); for (const key of Object.keys(enumType.values)) { + if (options.includeComments) { + formatComment(formatter, enumType.comments[key]); + } formatter.writeLine(`${key} = ${enumType.values[key]},`); } formatter.unindent(); @@ -366,29 +406,41 @@ function generateMessageAndEnumImports(formatter: TextFormatter, namespace: Prot } } -function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { +function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions, nameOverride?: string) { formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); formatter.indent(); for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Enum || nested instanceof Protobuf.Type) { + if (options.includeComments) { + formatComment(formatter, nested.comment); + } formatter.writeLine(`export type ${nested.name} = ${getTypeInterfaceName(nested)};`); if (nested instanceof Protobuf.Type) { + if (options.includeComments) { + formatComment(formatter, nested.comment); + } formatter.writeLine(`export type ${nested.name}__Output = ${getTypeInterfaceName(nested)}__Output;`); } } else if (isNamespaceBase(nested)) { - generateMessageAndEnumExports(formatter, nested); + generateMessageAndEnumExports(formatter, nested, options); } } formatter.unindent(); formatter.writeLine('}'); } -function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { +function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + if (options.includeComments) { + formatComment(formatter, serviceType.comment); + } formatter.writeLine(`export interface ${serviceType.name}Client extends grpc.Client {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; for (const name of [methodName, camelCase(methodName)]) { + if (options.includeComments) { + formatComment(formatter, method.comment); + } const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName); const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName) + '__Output'; const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; @@ -428,47 +480,56 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P formatter.writeLine('}'); } -function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { +function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions, nameOverride?: string) { formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); formatter.indent(); for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { - generateServiceClientInterface(formatter, nested); + generateServiceClientInterface(formatter, nested, options); } else if (isNamespaceBase(nested)) { - generateAllServiceClientInterfaces(formatter, nested); + generateAllServiceClientInterfaces(formatter, nested, options); } } formatter.unindent(); formatter.writeLine('}'); } -function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject) { +function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject, options: GeneratorOptions) { if (nested instanceof Protobuf.Service) { + if (options.includeComments) { + formatComment(formatter, nested.comment); + } formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) } else if (nested instanceof Protobuf.Enum) { formatter.writeLine(`${nested.name}: EnumTypeDefinition`); } else if (nested instanceof Protobuf.Type) { formatter.writeLine(`${nested.name}: MessageTypeDefinition`); } else if (isNamespaceBase(nested)) { - generateLoadedDefinitionTypes(formatter, nested); + generateLoadedDefinitionTypes(formatter, nested, options); } } -function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { +function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { formatter.writeLine(`${namespace.name}: {`); formatter.indent(); for (const nested of namespace.nestedArray.sort(compareName)) { - generateSingleLoadedDefinitionType(formatter, nested); + generateSingleLoadedDefinitionType(formatter, nested, options); } formatter.unindent(); formatter.writeLine('}'); } -function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { +function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + if (options.includeComments) { + formatComment(formatter, serviceType.comment); + } formatter.writeLine(`export interface ${serviceType.name} {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; + if (options.includeComments) { + formatComment(formatter, method.comment); + } const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName) + '__Output'; const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName); if (method.requestStream) { @@ -494,14 +555,14 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: formatter.writeLine('}'); } -function generateAllServiceHandlerInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, nameOverride?: string) { +function generateAllServiceHandlerInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions, nameOverride?: string) { formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); formatter.indent(); for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { - generateServiceHandlerInterface(formatter, nested); + generateServiceHandlerInterface(formatter, nested, options); } else if (isNamespaceBase(nested)) { - generateAllServiceHandlerInterfaces(formatter, nested); + generateAllServiceHandlerInterfaces(formatter, nested, options); } } formatter.unindent(); @@ -516,10 +577,10 @@ function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options generateMessageAndEnumImports(formatter, root); formatter.writeLine(''); - generateMessageAndEnumExports(formatter, root, 'messages'); + generateMessageAndEnumExports(formatter, root, options, 'messages'); formatter.writeLine(''); - generateAllServiceClientInterfaces(formatter, root, 'ClientInterfaces'); + generateAllServiceClientInterfaces(formatter, root, options, 'ClientInterfaces'); formatter.writeLine(''); formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); @@ -531,13 +592,13 @@ function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options formatter.writeLine('export interface ProtoGrpcType {'); formatter.indent(); for (const nested of root.nestedArray) { - generateSingleLoadedDefinitionType(formatter, nested); + generateSingleLoadedDefinitionType(formatter, nested, options); } formatter.unindent(); formatter.writeLine('}'); formatter.writeLine(''); - generateAllServiceHandlerInterfaces(formatter, root, 'ServiceHandlers'); + generateAllServiceHandlerInterfaces(formatter, root, options, 'ServiceHandlers'); } async function writeFile(filename: string, contents: string): Promise { @@ -556,7 +617,7 @@ function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: G } filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); } else if (nested instanceof Protobuf.Enum) { - generateEnumInterface(fileFormatter, nested); + generateEnumInterface(fileFormatter, nested, options); if (options.verbose) { console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); } @@ -596,7 +657,7 @@ function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'generateComments']) // .choices('longs', ['String', 'Number']) // .choices('enums', ['String']) // .choices('bytes', ['Array', 'String']) @@ -652,7 +713,7 @@ function runScript() { console.log('Parsed arguments:', argv); } addCommonProtos(); - writeAllFiles(argv._, argv).then(() => { + writeAllFiles(argv._, {...argv, alternateCommentMode: true}).then(() => { if (argv.verbose) { console.log('Success'); } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index eda794253..3ebcd21b0 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre8", + "version": "0.6.0-pre9", "author": "Google Inc.", "contributors": [ { From bf471a96a6cc301b46380f16d8e97d661ed9634b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Jul 2020 14:24:54 -0700 Subject: [PATCH 1153/1899] Generate comments in generated code --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/generated/ads.ts | 579 ++++++ packages/grpc-js/src/generated/cluster.ts | 1325 +++++++++++++ packages/grpc-js/src/generated/endpoint.ts | 1117 +++++++++++ .../src/generated/envoy/api/v2/Cluster.ts | 1340 +++++++++++++ .../envoy/api/v2/ClusterLoadAssignment.ts | 190 ++ .../envoy/api/v2/DeltaDiscoveryRequest.ts | 178 ++ .../envoy/api/v2/DeltaDiscoveryResponse.ts | 44 + .../envoy/api/v2/DiscoveryRequest.ts | 88 + .../envoy/api/v2/DiscoveryResponse.ts | 86 + .../src/generated/envoy/api/v2/Listener.ts | 411 ++++ .../envoy/api/v2/LoadBalancingPolicy.ts | 66 + .../src/generated/envoy/api/v2/Resource.ts | 26 + .../envoy/api/v2/RouteConfiguration.ts | 154 ++ .../envoy/api/v2/UpstreamBindConfig.ts | 14 + .../envoy/api/v2/UpstreamConnectionOptions.ts | 6 + .../src/generated/envoy/api/v2/Vhds.ts | 6 + .../v2/auth/CertificateValidationContext.ts | 277 +++ .../envoy/api/v2/auth/CommonTlsContext.ts | 102 + .../envoy/api/v2/auth/DownstreamTlsContext.ts | 72 + .../envoy/api/v2/auth/GenericSecret.ts | 6 + .../envoy/api/v2/auth/PrivateKeyProvider.ts | 24 + .../envoy/api/v2/auth/SdsSecretConfig.ts | 10 + .../src/generated/envoy/api/v2/auth/Secret.ts | 12 + .../envoy/api/v2/auth/TlsCertificate.ts | 56 + .../envoy/api/v2/auth/TlsParameters.ts | 145 ++ .../envoy/api/v2/auth/TlsSessionTicketKeys.ts | 50 + .../envoy/api/v2/auth/UpstreamTlsContext.ts | 50 + .../envoy/api/v2/cluster/CircuitBreakers.ts | 150 ++ .../generated/envoy/api/v2/cluster/Filter.ts | 16 + .../envoy/api/v2/cluster/OutlierDetection.ts | 250 +++ .../generated/envoy/api/v2/core/Address.ts | 10 + .../api/v2/core/AggregatedConfigSource.ts | 10 + .../envoy/api/v2/core/ApiConfigSource.ts | 98 + .../generated/envoy/api/v2/core/ApiVersion.ts | 15 + .../envoy/api/v2/core/AsyncDataSource.ts | 18 + .../envoy/api/v2/core/BackoffStrategy.ts | 30 + .../generated/envoy/api/v2/core/BindConfig.ts | 32 + .../envoy/api/v2/core/BuildVersion.ts | 22 + .../generated/envoy/api/v2/core/CidrRange.ts | 20 + .../envoy/api/v2/core/ConfigSource.ts | 116 ++ .../envoy/api/v2/core/ControlPlane.ts | 16 + .../generated/envoy/api/v2/core/DataSource.ts | 24 + .../envoy/api/v2/core/EventServiceConfig.ts | 14 + .../generated/envoy/api/v2/core/Extension.ts | 56 + .../envoy/api/v2/core/GrpcProtocolOptions.ts | 6 + .../envoy/api/v2/core/GrpcService.ts | 318 ++++ .../generated/envoy/api/v2/core/HeaderMap.ts | 6 + .../envoy/api/v2/core/HeaderValue.ts | 26 + .../envoy/api/v2/core/HeaderValueOption.ts | 20 + .../envoy/api/v2/core/HealthCheck.ts | 454 +++++ .../envoy/api/v2/core/HealthStatus.ts | 26 + .../envoy/api/v2/core/Http1ProtocolOptions.ts | 84 + .../envoy/api/v2/core/Http2ProtocolOptions.ts | 280 +++ .../envoy/api/v2/core/HttpProtocolOptions.ts | 98 + .../generated/envoy/api/v2/core/HttpUri.ts | 62 + .../generated/envoy/api/v2/core/Locality.ts | 42 + .../generated/envoy/api/v2/core/Metadata.ts | 56 + .../src/generated/envoy/api/v2/core/Node.ts | 136 ++ .../src/generated/envoy/api/v2/core/Pipe.ts | 18 + .../envoy/api/v2/core/RateLimitSettings.ts | 22 + .../envoy/api/v2/core/RemoteDataSource.ts | 24 + .../envoy/api/v2/core/RequestMethod.ts | 3 + .../envoy/api/v2/core/RetryPolicy.ts | 24 + .../envoy/api/v2/core/RoutingPriority.ts | 9 + .../envoy/api/v2/core/RuntimeDouble.ts | 18 + .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 22 + .../api/v2/core/RuntimeFractionalPercent.ts | 36 + .../envoy/api/v2/core/RuntimeUInt32.ts | 18 + .../envoy/api/v2/core/SelfConfigSource.ts | 12 + .../envoy/api/v2/core/SocketAddress.ts | 68 + .../envoy/api/v2/core/SocketOption.ts | 59 + .../envoy/api/v2/core/TcpKeepalive.ts | 28 + .../envoy/api/v2/core/TcpProtocolOptions.ts | 6 + .../envoy/api/v2/core/TrafficDirection.ts | 12 + .../envoy/api/v2/core/TransportSocket.ts | 28 + .../v2/core/UpstreamHttpProtocolOptions.ts | 22 + .../envoy/api/v2/endpoint/Endpoint.ts | 94 + .../envoy/api/v2/endpoint/LbEndpoint.ts | 66 + .../api/v2/endpoint/LocalityLbEndpoints.ts | 90 + .../generated/envoy/api/v2/listener/Filter.ts | 16 + .../envoy/api/v2/listener/FilterChain.ts | 90 + .../envoy/api/v2/listener/FilterChainMatch.ts | 225 +++ .../envoy/api/v2/listener/ListenerFilter.ts | 26 + .../ListenerFilterChainMatchPredicate.ts | 106 ++ .../api/v2/listener/UdpListenerConfig.ts | 18 + .../envoy/api/v2/route/CorsPolicy.ts | 134 ++ .../generated/envoy/api/v2/route/Decorator.ts | 26 + .../api/v2/route/DirectResponseAction.ts | 26 + .../envoy/api/v2/route/FilterAction.ts | 6 + .../envoy/api/v2/route/HeaderMatcher.ts | 196 ++ .../envoy/api/v2/route/HedgePolicy.ts | 50 + .../api/v2/route/QueryParameterMatcher.ts | 64 + .../generated/envoy/api/v2/route/RateLimit.ts | 256 +++ .../envoy/api/v2/route/RedirectAction.ts | 101 + .../envoy/api/v2/route/RetryPolicy.ts | 146 ++ .../src/generated/envoy/api/v2/route/Route.ts | 174 ++ .../envoy/api/v2/route/RouteAction.ts | 823 ++++++++ .../envoy/api/v2/route/RouteMatch.ts | 196 ++ .../generated/envoy/api/v2/route/Tracing.ts | 66 + .../envoy/api/v2/route/VirtualCluster.ts | 102 + .../envoy/api/v2/route/VirtualHost.ts | 277 +++ .../envoy/api/v2/route/WeightedCluster.ts | 170 ++ .../config/filter/accesslog/v2/AccessLog.ts | 44 + .../filter/accesslog/v2/AccessLogFilter.ts | 72 + .../config/filter/accesslog/v2/AndFilter.ts | 10 + .../filter/accesslog/v2/ComparisonFilter.ts | 27 + .../filter/accesslog/v2/DurationFilter.ts | 12 + .../filter/accesslog/v2/ExtensionFilter.ts | 20 + .../filter/accesslog/v2/GrpcStatusFilter.ts | 22 + .../filter/accesslog/v2/HeaderFilter.ts | 14 + .../accesslog/v2/NotHealthCheckFilter.ts | 8 + .../config/filter/accesslog/v2/OrFilter.ts | 10 + .../filter/accesslog/v2/ResponseFlagFilter.ts | 20 + .../filter/accesslog/v2/RuntimeFilter.ts | 48 + .../filter/accesslog/v2/StatusCodeFilter.ts | 12 + .../filter/accesslog/v2/TraceableFilter.ts | 8 + .../envoy/config/listener/v2/ApiListener.ts | 28 + .../envoy/service/discovery/v2/AdsDummy.ts | 8 + .../generated/envoy/type/CodecClientType.ts | 5 + .../src/generated/envoy/type/DoubleRange.ts | 20 + .../generated/envoy/type/FractionalPercent.ts | 48 + .../src/generated/envoy/type/Int32Range.ts | 20 + .../src/generated/envoy/type/Int64Range.ts | 20 + .../src/generated/envoy/type/Percent.ts | 6 + .../generated/envoy/type/SemanticVersion.ts | 10 + .../envoy/type/matcher/ListStringMatcher.ts | 6 + .../type/matcher/RegexMatchAndSubstitute.ts | 52 + .../envoy/type/matcher/RegexMatcher.ts | 46 + .../envoy/type/matcher/StringMatcher.ts | 100 + .../envoy/type/metadata/v2/MetadataKey.ts | 86 + .../envoy/type/metadata/v2/MetadataKind.ts | 56 + .../envoy/type/tracing/v2/CustomTag.ts | 136 ++ .../generated/google/api/CustomHttpPattern.ts | 18 + .../grpc-js/src/generated/google/api/Http.ts | 36 + .../src/generated/google/api/HttpRule.ts | 648 +++++++ .../src/generated/google/rpc/Status.ts | 42 + packages/grpc-js/src/generated/listener.ts | 1656 +++++++++++++++++ packages/grpc-js/src/generated/route.ts | 822 ++++++++ .../annotations/FieldMigrateAnnotation.ts | 16 + .../udpa/annotations/FileMigrateAnnotation.ts | 8 + .../udpa/annotations/MigrateAnnotation.ts | 6 + .../udpa/annotations/PackageVersionStatus.ts | 13 + .../udpa/annotations/StatusAnnotation.ts | 12 + .../src/generated/validate/AnyRules.ts | 30 + .../src/generated/validate/BoolRules.ts | 12 + .../src/generated/validate/BytesRules.ts | 116 ++ .../src/generated/validate/DoubleRules.ts | 64 + .../src/generated/validate/DurationRules.ts | 68 + .../src/generated/validate/EnumRules.ts | 36 + .../src/generated/validate/FieldRules.ts | 26 + .../src/generated/validate/Fixed32Rules.ts | 64 + .../src/generated/validate/Fixed64Rules.ts | 64 + .../src/generated/validate/FloatRules.ts | 64 + .../src/generated/validate/Int32Rules.ts | 64 + .../src/generated/validate/Int64Rules.ts | 64 + .../src/generated/validate/KnownRegex.ts | 9 + .../src/generated/validate/MapRules.ts | 46 + .../src/generated/validate/MessageRules.ts | 22 + .../src/generated/validate/RepeatedRules.ts | 42 + .../src/generated/validate/SFixed32Rules.ts | 64 + .../src/generated/validate/SFixed64Rules.ts | 64 + .../src/generated/validate/SInt32Rules.ts | 64 + .../src/generated/validate/SInt64Rules.ts | 64 + .../src/generated/validate/StringRules.ts | 226 +++ .../src/generated/validate/TimestampRules.ts | 78 + .../src/generated/validate/UInt32Rules.ts | 64 + .../src/generated/validate/UInt64Rules.ts | 64 + 168 files changed, 18649 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a795afc78..e1b380ba1 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -47,7 +47,7 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --generateComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/generated/ads.ts b/packages/grpc-js/src/generated/ads.ts index 4a5a4d121..369b6b8c1 100644 --- a/packages/grpc-js/src/generated/ads.ts +++ b/packages/grpc-js/src/generated/ads.ts @@ -111,73 +111,410 @@ export namespace messages { export namespace envoy { export namespace api { export namespace v2 { + /** + * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC + * endpoint for Delta xDS. + * + * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full + * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a + * diff to the state of a xDS client. + * In Delta XDS there are per-resource versions, which allow tracking state at + * the resource granularity. + * An xDS Delta session is always in the context of a gRPC bidirectional + * stream. This allows the xDS server to keep track of the state of xDS clients + * connected to it. + * + * In Delta xDS the nonce field is required and used to pair + * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. + * Optionally, a response message level system_version_info is present for + * debugging purposes only. + * + * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest + * can be either or both of: [1] informing the server of what resources the + * client has gained/lost interest in (using resource_names_subscribe and + * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from + * the server (using response_nonce, with presence of error_detail making it a NACK). + * Additionally, the first message (for a given type_url) of a reconnected gRPC stream + * has a third role: informing the server of the resources (and their versions) + * that the client already possesses, using the initial_resource_versions field. + * + * As with state-of-the-world, when multiple resource types are multiplexed (ADS), + * all requests/acknowledgments/updates are logically walled off by type_url: + * a Cluster ACK exists in a completely separate world from a prior Route NACK. + * In particular, initial_resource_versions being sent at the "start" of every + * gRPC stream actually entails a message for each type_url, each with its own + * initial_resource_versions. + * [#next-free-field: 8] + */ export type DeltaDiscoveryRequest = _envoy_api_v2_DeltaDiscoveryRequest; + /** + * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC + * endpoint for Delta xDS. + * + * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full + * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a + * diff to the state of a xDS client. + * In Delta XDS there are per-resource versions, which allow tracking state at + * the resource granularity. + * An xDS Delta session is always in the context of a gRPC bidirectional + * stream. This allows the xDS server to keep track of the state of xDS clients + * connected to it. + * + * In Delta xDS the nonce field is required and used to pair + * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. + * Optionally, a response message level system_version_info is present for + * debugging purposes only. + * + * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest + * can be either or both of: [1] informing the server of what resources the + * client has gained/lost interest in (using resource_names_subscribe and + * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from + * the server (using response_nonce, with presence of error_detail making it a NACK). + * Additionally, the first message (for a given type_url) of a reconnected gRPC stream + * has a third role: informing the server of the resources (and their versions) + * that the client already possesses, using the initial_resource_versions field. + * + * As with state-of-the-world, when multiple resource types are multiplexed (ADS), + * all requests/acknowledgments/updates are logically walled off by type_url: + * a Cluster ACK exists in a completely separate world from a prior Route NACK. + * In particular, initial_resource_versions being sent at the "start" of every + * gRPC stream actually entails a message for each type_url, each with its own + * initial_resource_versions. + * [#next-free-field: 8] + */ export type DeltaDiscoveryRequest__Output = _envoy_api_v2_DeltaDiscoveryRequest__Output; + /** + * [#next-free-field: 7] + */ export type DeltaDiscoveryResponse = _envoy_api_v2_DeltaDiscoveryResponse; + /** + * [#next-free-field: 7] + */ export type DeltaDiscoveryResponse__Output = _envoy_api_v2_DeltaDiscoveryResponse__Output; + /** + * A DiscoveryRequest requests a set of versioned resources of the same type for + * a given Envoy node on some API. + * [#next-free-field: 7] + */ export type DiscoveryRequest = _envoy_api_v2_DiscoveryRequest; + /** + * A DiscoveryRequest requests a set of versioned resources of the same type for + * a given Envoy node on some API. + * [#next-free-field: 7] + */ export type DiscoveryRequest__Output = _envoy_api_v2_DiscoveryRequest__Output; + /** + * [#next-free-field: 7] + */ export type DiscoveryResponse = _envoy_api_v2_DiscoveryResponse; + /** + * [#next-free-field: 7] + */ export type DiscoveryResponse__Output = _envoy_api_v2_DiscoveryResponse__Output; export type Resource = _envoy_api_v2_Resource; export type Resource__Output = _envoy_api_v2_Resource__Output; export namespace core { + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address = _envoy_api_v2_core_Address; + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address__Output = _envoy_api_v2_core_Address__Output; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type BindConfig = _envoy_api_v2_core_BindConfig; export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion = _envoy_api_v2_core_BuildVersion; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange = _envoy_api_v2_core_CidrRange; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane = _envoy_api_v2_core_ControlPlane; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource = _envoy_api_v2_core_DataSource; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension = _envoy_api_v2_core_Extension; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension__Output = _envoy_api_v2_core_Extension__Output; + /** + * Wrapper for a set of headers. + */ export type HeaderMap = _envoy_api_v2_core_HeaderMap; + /** + * Wrapper for a set of headers. + */ export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + /** + * Header name/value pair. + */ export type HeaderValue = _envoy_api_v2_core_HeaderValue; + /** + * Header name/value pair. + */ export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + /** + * Envoy external URI descriptor + */ export type HttpUri = _envoy_api_v2_core_HttpUri; + /** + * Envoy external URI descriptor + */ export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality = _envoy_api_v2_core_Locality; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality__Output = _envoy_api_v2_core_Locality__Output; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata = _envoy_api_v2_core_Metadata; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node = _envoy_api_v2_core_Node; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node__Output = _envoy_api_v2_core_Node__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + /** + * HTTP request method. + */ export type RequestMethod = _envoy_api_v2_core_RequestMethod; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + /** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + /** + * [#next-free-field: 7] + */ export type SocketAddress = _envoy_api_v2_core_SocketAddress; + /** + * [#next-free-field: 7] + */ export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption = _envoy_api_v2_core_SocketOption; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + /** + * Identifies the direction of the traffic relative to the local Envoy. + */ export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket = _envoy_api_v2_core_TransportSocket; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; } } @@ -185,7 +522,15 @@ export namespace messages { export namespace service { export namespace discovery { export namespace v2 { + /** + * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing + * services: https://github.com/google/protobuf/issues/4221 + */ export type AdsDummy = _envoy_service_discovery_v2_AdsDummy; + /** + * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing + * services: https://github.com/google/protobuf/issues/4221 + */ export type AdsDummy__Output = _envoy_service_discovery_v2_AdsDummy__Output; export namespace AggregatedDiscoveryService { } @@ -193,11 +538,43 @@ export namespace messages { } } export namespace type { + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent = _envoy_type_FractionalPercent; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent = _envoy_type_Percent; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent__Output = _envoy_type_Percent__Output; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion = _envoy_type_SemanticVersion; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; } } @@ -276,7 +653,25 @@ export namespace messages { export type Value__Output = _google_protobuf_Value__Output; } export namespace rpc { + /** + * The `Status` type defines a logical error model that is suitable for + * different programming environments, including REST APIs and RPC APIs. It is + * used by [gRPC](https://github.com/grpc). Each `Status` message contains + * three pieces of data: error code, error message, and error details. + * + * You can find out more about this error model and how to work with it in the + * [API Design Guide](https://cloud.google.com/apis/design/errors). + */ export type Status = _google_rpc_Status; + /** + * The `Status` type defines a logical error model that is suitable for + * different programming environments, including REST APIs and RPC APIs. It is + * used by [gRPC](https://github.com/grpc). Each `Status` message contains + * three pieces of data: error code, error message, and error details. + * + * You can find out more about this error model and how to work with it in the + * [API Design Guide](https://cloud.google.com/apis/design/errors). + */ export type Status__Output = _google_rpc_Status__Output; } } @@ -294,52 +689,203 @@ export namespace messages { } } export namespace validate { + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules = _validate_AnyRules; + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules__Output = _validate_AnyRules__Output; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules = _validate_BoolRules; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules__Output = _validate_BoolRules__Output; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules = _validate_BytesRules; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules__Output = _validate_BytesRules__Output; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules = _validate_DoubleRules; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules__Output = _validate_DoubleRules__Output; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules = _validate_DurationRules; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules__Output = _validate_DurationRules__Output; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules = _validate_EnumRules; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules__Output = _validate_EnumRules__Output; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules = _validate_FieldRules; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules__Output = _validate_FieldRules__Output; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules = _validate_Fixed32Rules; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules = _validate_Fixed64Rules; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules = _validate_FloatRules; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules__Output = _validate_FloatRules__Output; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules = _validate_Int32Rules; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules__Output = _validate_Int32Rules__Output; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules = _validate_Int64Rules; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules__Output = _validate_Int64Rules__Output; + /** + * WellKnownRegex contain some well-known patterns. + */ export type KnownRegex = _validate_KnownRegex; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules = _validate_MapRules; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules__Output = _validate_MapRules__Output; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules = _validate_MessageRules; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules__Output = _validate_MessageRules__Output; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules = _validate_RepeatedRules; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules__Output = _validate_RepeatedRules__Output; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules = _validate_SFixed32Rules; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules = _validate_SFixed64Rules; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules = _validate_SInt32Rules; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules__Output = _validate_SInt32Rules__Output; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules = _validate_SInt64Rules; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules__Output = _validate_SInt64Rules__Output; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules = _validate_StringRules; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules__Output = _validate_StringRules__Output; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules = _validate_TimestampRules; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules__Output = _validate_TimestampRules__Output; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules = _validate_UInt32Rules; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules__Output = _validate_UInt32Rules__Output; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules = _validate_UInt64Rules; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules__Output = _validate_UInt64Rules__Output; } } @@ -421,14 +967,28 @@ export namespace ClientInterfaces { export namespace v2 { export namespace AdsDummy { } + /** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ export interface AggregatedDiscoveryServiceClient extends grpc.Client { DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + /** + * This is a gRPC-only API. + */ StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; + /** + * This is a gRPC-only API. + */ streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; @@ -647,6 +1207,14 @@ export interface ProtoGrpcType { discovery: { v2: { AdsDummy: MessageTypeDefinition + /** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } } } @@ -814,9 +1382,20 @@ export namespace ServiceHandlers { export namespace v2 { export namespace AdsDummy { } + /** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ export interface AggregatedDiscoveryService { DeltaAggregatedResources(call: grpc.ServerDuplexStream): void; + /** + * This is a gRPC-only API. + */ StreamAggregatedResources(call: grpc.ServerDuplexStream): void; } diff --git a/packages/grpc-js/src/generated/cluster.ts b/packages/grpc-js/src/generated/cluster.ts index a99ff3277..bf6f37bfc 100644 --- a/packages/grpc-js/src/generated/cluster.ts +++ b/packages/grpc-js/src/generated/cluster.ts @@ -156,32 +156,156 @@ export namespace messages { } export namespace api { export namespace v2 { + /** + * Configuration for a single upstream cluster. + * [#next-free-field: 48] + */ export type Cluster = _envoy_api_v2_Cluster; + /** + * Configuration for a single upstream cluster. + * [#next-free-field: 48] + */ export type Cluster__Output = _envoy_api_v2_Cluster__Output; + /** + * Each route from RDS will map to a single cluster or traffic split across + * clusters using weights expressed in the RDS WeightedCluster. + * + * With EDS, each cluster is treated independently from a LB perspective, with + * LB taking place between the Localities within a cluster and at a finer + * granularity between the hosts within a locality. The percentage of traffic + * for each endpoint is determined by both its load_balancing_weight, and the + * load_balancing_weight of its locality. First, a locality will be selected, + * then an endpoint within that locality will be chose based on its weight. + * [#next-free-field: 6] + */ export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; + /** + * Each route from RDS will map to a single cluster or traffic split across + * clusters using weights expressed in the RDS WeightedCluster. + * + * With EDS, each cluster is treated independently from a LB perspective, with + * LB taking place between the Localities within a cluster and at a finer + * granularity between the hosts within a locality. The percentage of traffic + * for each endpoint is determined by both its load_balancing_weight, and the + * load_balancing_weight of its locality. First, a locality will be selected, + * then an endpoint within that locality will be chose based on its weight. + * [#next-free-field: 6] + */ export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; + /** + * [#not-implemented-hide:] Extensible load balancing policy configuration. + * + * Every LB policy defined via this mechanism will be identified via a unique name using reverse + * DNS notation. If the policy needs configuration parameters, it must define a message for its + * own configuration, which will be stored in the config field. The name of the policy will tell + * clients which type of message they should expect to see in the config field. + * + * Note that there are cases where it is useful to be able to independently select LB policies + * for choosing a locality and for choosing an endpoint within that locality. For example, a + * given deployment may always use the same policy to choose the locality, but for choosing the + * endpoint within the locality, some clusters may use weighted-round-robin, while others may + * use some sort of session-based balancing. + * + * This can be accomplished via hierarchical LB policies, where the parent LB policy creates a + * child LB policy for each locality. For each request, the parent chooses the locality and then + * delegates to the child policy for that locality to choose the endpoint within the locality. + * + * To facilitate this, the config message for the top-level LB policy may include a field of + * type LoadBalancingPolicy that specifies the child policy. + */ export type LoadBalancingPolicy = _envoy_api_v2_LoadBalancingPolicy; + /** + * [#not-implemented-hide:] Extensible load balancing policy configuration. + * + * Every LB policy defined via this mechanism will be identified via a unique name using reverse + * DNS notation. If the policy needs configuration parameters, it must define a message for its + * own configuration, which will be stored in the config field. The name of the policy will tell + * clients which type of message they should expect to see in the config field. + * + * Note that there are cases where it is useful to be able to independently select LB policies + * for choosing a locality and for choosing an endpoint within that locality. For example, a + * given deployment may always use the same policy to choose the locality, but for choosing the + * endpoint within the locality, some clusters may use weighted-round-robin, while others may + * use some sort of session-based balancing. + * + * This can be accomplished via hierarchical LB policies, where the parent LB policy creates a + * child LB policy for each locality. For each request, the parent chooses the locality and then + * delegates to the child policy for that locality to choose the endpoint within the locality. + * + * To facilitate this, the config message for the top-level LB policy may include a field of + * type LoadBalancingPolicy that specifies the child policy. + */ export type LoadBalancingPolicy__Output = _envoy_api_v2_LoadBalancingPolicy__Output; + /** + * An extensible structure containing the address Envoy should bind to when + * establishing upstream connections. + */ export type UpstreamBindConfig = _envoy_api_v2_UpstreamBindConfig; + /** + * An extensible structure containing the address Envoy should bind to when + * establishing upstream connections. + */ export type UpstreamBindConfig__Output = _envoy_api_v2_UpstreamBindConfig__Output; export type UpstreamConnectionOptions = _envoy_api_v2_UpstreamConnectionOptions; export type UpstreamConnectionOptions__Output = _envoy_api_v2_UpstreamConnectionOptions__Output; export namespace auth { + /** + * [#next-free-field: 11] + */ export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; + /** + * [#next-free-field: 11] + */ export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + /** + * TLS context shared by both client and server TLS contexts. + * [#next-free-field: 9] + */ export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; + /** + * TLS context shared by both client and server TLS contexts. + * [#next-free-field: 9] + */ export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; + /** + * [#next-free-field: 8] + */ export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; + /** + * [#next-free-field: 8] + */ export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; export type GenericSecret = _envoy_api_v2_auth_GenericSecret; export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + /** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; + /** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; + /** + * [#next-free-field: 6] + */ export type Secret = _envoy_api_v2_auth_Secret; + /** + * [#next-free-field: 6] + */ export type Secret__Output = _envoy_api_v2_auth_Secret__Output; + /** + * [#next-free-field: 7] + */ export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; + /** + * [#next-free-field: 7] + */ export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; export type TlsParameters = _envoy_api_v2_auth_TlsParameters; export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; @@ -191,145 +315,1195 @@ export namespace messages { export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; } export namespace cluster { + /** + * :ref:`Circuit breaking` settings can be + * specified individually for each defined priority. + */ export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; + /** + * :ref:`Circuit breaking` settings can be + * specified individually for each defined priority. + */ export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; export type Filter = _envoy_api_v2_cluster_Filter; export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; + /** + * See the :ref:`architecture overview ` for + * more information on outlier detection. + * [#next-free-field: 21] + */ export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; + /** + * See the :ref:`architecture overview ` for + * more information on outlier detection. + * [#next-free-field: 21] + */ export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; } export namespace core { + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address = _envoy_api_v2_core_Address; + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address__Output = _envoy_api_v2_core_Address__Output; + /** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + /** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + /** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + /** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + /** + * xDS API version. This is used to describe both resource and transport + * protocol versions (in distinct configuration fields). + */ export type ApiVersion = _envoy_api_v2_core_ApiVersion; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type BindConfig = _envoy_api_v2_core_BindConfig; export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion = _envoy_api_v2_core_BuildVersion; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange = _envoy_api_v2_core_CidrRange; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + /** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export type ConfigSource = _envoy_api_v2_core_ConfigSource; + /** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane = _envoy_api_v2_core_ControlPlane; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource = _envoy_api_v2_core_DataSource; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + /** + * [#not-implemented-hide:] + * Configuration of the event reporting service endpoint. + */ export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; + /** + * [#not-implemented-hide:] + * Configuration of the event reporting service endpoint. + */ export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension = _envoy_api_v2_core_Extension; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension__Output = _envoy_api_v2_core_Extension__Output; + /** + * [#not-implemented-hide:] + */ export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; + /** + * [#not-implemented-hide:] + */ export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService = _envoy_api_v2_core_GrpcService; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + /** + * Wrapper for a set of headers. + */ export type HeaderMap = _envoy_api_v2_core_HeaderMap; + /** + * Wrapper for a set of headers. + */ export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + /** + * Header name/value pair. + */ export type HeaderValue = _envoy_api_v2_core_HeaderValue; + /** + * Header name/value pair. + */ export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + /** + * [#next-free-field: 23] + */ export type HealthCheck = _envoy_api_v2_core_HealthCheck; + /** + * [#next-free-field: 23] + */ export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + /** + * Endpoint health status. + */ export type HealthStatus = _envoy_api_v2_core_HealthStatus; + /** + * [#next-free-field: 6] + */ export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; + /** + * [#next-free-field: 6] + */ export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; + /** + * [#next-free-field: 14] + */ export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; + /** + * [#next-free-field: 14] + */ export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; + /** + * [#next-free-field: 6] + */ export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; + /** + * [#next-free-field: 6] + */ export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; + /** + * Envoy external URI descriptor + */ export type HttpUri = _envoy_api_v2_core_HttpUri; + /** + * Envoy external URI descriptor + */ export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality = _envoy_api_v2_core_Locality; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality__Output = _envoy_api_v2_core_Locality__Output; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata = _envoy_api_v2_core_Metadata; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node = _envoy_api_v2_core_Node; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node__Output = _envoy_api_v2_core_Node__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + /** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + /** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + /** + * HTTP request method. + */ export type RequestMethod = _envoy_api_v2_core_RequestMethod; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + /** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + /** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + /** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + /** + * [#next-free-field: 7] + */ export type SocketAddress = _envoy_api_v2_core_SocketAddress; + /** + * [#next-free-field: 7] + */ export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption = _envoy_api_v2_core_SocketOption; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + /** + * [#not-implemented-hide:] + */ export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; + /** + * [#not-implemented-hide:] + */ export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; + /** + * Identifies the direction of the traffic relative to the local Envoy. + */ export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket = _envoy_api_v2_core_TransportSocket; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; } export namespace endpoint { + /** + * Upstream host identifier. + */ export type Endpoint = _envoy_api_v2_endpoint_Endpoint; + /** + * Upstream host identifier. + */ export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; + /** + * An Endpoint that Envoy can route traffic to. + * [#next-free-field: 6] + */ export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; + /** + * An Endpoint that Envoy can route traffic to. + * [#next-free-field: 6] + */ export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; + /** + * A group of endpoints belonging to a Locality. + * One can have multiple LocalityLbEndpoints for a locality, but this is + * generally only done if the different groups need to have different load + * balancing weights or different priorities. + * [#next-free-field: 7] + */ export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; + /** + * A group of endpoints belonging to a Locality. + * One can have multiple LocalityLbEndpoints for a locality, but this is + * generally only done if the different groups need to have different load + * balancing weights or different priorities. + * [#next-free-field: 7] + */ export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; } } } export namespace type { export type CodecClientType = _envoy_type_CodecClientType; + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange = _envoy_type_DoubleRange; + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent = _envoy_type_FractionalPercent; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range = _envoy_type_Int32Range; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range__Output = _envoy_type_Int32Range__Output; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range = _envoy_type_Int64Range; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range__Output = _envoy_type_Int64Range__Output; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent = _envoy_type_Percent; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent__Output = _envoy_type_Percent__Output; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion = _envoy_type_SemanticVersion; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher = _envoy_type_matcher_StringMatcher; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; } } } export namespace google { export namespace api { + /** + * A custom pattern is used for defining custom HTTP verb. + */ export type CustomHttpPattern = _google_api_CustomHttpPattern; + /** + * A custom pattern is used for defining custom HTTP verb. + */ export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + /** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export type Http = _google_api_Http; + /** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export type Http__Output = _google_api_Http__Output; + /** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export type HttpRule = _google_api_HttpRule; + /** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export type HttpRule__Output = _google_api_HttpRule__Output; } export namespace protobuf { @@ -422,52 +1596,203 @@ export namespace messages { } } export namespace validate { + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules = _validate_AnyRules; + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules__Output = _validate_AnyRules__Output; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules = _validate_BoolRules; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules__Output = _validate_BoolRules__Output; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules = _validate_BytesRules; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules__Output = _validate_BytesRules__Output; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules = _validate_DoubleRules; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules__Output = _validate_DoubleRules__Output; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules = _validate_DurationRules; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules__Output = _validate_DurationRules__Output; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules = _validate_EnumRules; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules__Output = _validate_EnumRules__Output; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules = _validate_FieldRules; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules__Output = _validate_FieldRules__Output; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules = _validate_Fixed32Rules; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules = _validate_Fixed64Rules; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules = _validate_FloatRules; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules__Output = _validate_FloatRules__Output; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules = _validate_Int32Rules; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules__Output = _validate_Int32Rules__Output; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules = _validate_Int64Rules; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules__Output = _validate_Int64Rules__Output; + /** + * WellKnownRegex contain some well-known patterns. + */ export type KnownRegex = _validate_KnownRegex; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules = _validate_MapRules; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules__Output = _validate_MapRules__Output; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules = _validate_MessageRules; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules__Output = _validate_MessageRules__Output; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules = _validate_RepeatedRules; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules__Output = _validate_RepeatedRules__Output; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules = _validate_SFixed32Rules; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules = _validate_SFixed64Rules; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules = _validate_SInt32Rules; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules__Output = _validate_SInt32Rules__Output; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules = _validate_SInt64Rules; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules__Output = _validate_SInt64Rules__Output; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules = _validate_StringRules; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules__Output = _validate_StringRules__Output; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules = _validate_TimestampRules; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules__Output = _validate_TimestampRules__Output; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules = _validate_UInt32Rules; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules__Output = _validate_UInt32Rules__Output; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules = _validate_UInt64Rules; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules__Output = _validate_UInt64Rules__Output; } } diff --git a/packages/grpc-js/src/generated/endpoint.ts b/packages/grpc-js/src/generated/endpoint.ts index 7bfbe093f..bbd9ef7df 100644 --- a/packages/grpc-js/src/generated/endpoint.ts +++ b/packages/grpc-js/src/generated/endpoint.ts @@ -126,117 +126,1083 @@ export namespace messages { } export namespace api { export namespace v2 { + /** + * Each route from RDS will map to a single cluster or traffic split across + * clusters using weights expressed in the RDS WeightedCluster. + * + * With EDS, each cluster is treated independently from a LB perspective, with + * LB taking place between the Localities within a cluster and at a finer + * granularity between the hosts within a locality. The percentage of traffic + * for each endpoint is determined by both its load_balancing_weight, and the + * load_balancing_weight of its locality. First, a locality will be selected, + * then an endpoint within that locality will be chose based on its weight. + * [#next-free-field: 6] + */ export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; + /** + * Each route from RDS will map to a single cluster or traffic split across + * clusters using weights expressed in the RDS WeightedCluster. + * + * With EDS, each cluster is treated independently from a LB perspective, with + * LB taking place between the Localities within a cluster and at a finer + * granularity between the hosts within a locality. The percentage of traffic + * for each endpoint is determined by both its load_balancing_weight, and the + * load_balancing_weight of its locality. First, a locality will be selected, + * then an endpoint within that locality will be chose based on its weight. + * [#next-free-field: 6] + */ export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; export namespace core { + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address = _envoy_api_v2_core_Address; + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address__Output = _envoy_api_v2_core_Address__Output; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type BindConfig = _envoy_api_v2_core_BindConfig; export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion = _envoy_api_v2_core_BuildVersion; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange = _envoy_api_v2_core_CidrRange; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane = _envoy_api_v2_core_ControlPlane; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource = _envoy_api_v2_core_DataSource; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + /** + * [#not-implemented-hide:] + * Configuration of the event reporting service endpoint. + */ export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; + /** + * [#not-implemented-hide:] + * Configuration of the event reporting service endpoint. + */ export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension = _envoy_api_v2_core_Extension; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension__Output = _envoy_api_v2_core_Extension__Output; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService = _envoy_api_v2_core_GrpcService; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + /** + * Wrapper for a set of headers. + */ export type HeaderMap = _envoy_api_v2_core_HeaderMap; + /** + * Wrapper for a set of headers. + */ export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + /** + * Header name/value pair. + */ export type HeaderValue = _envoy_api_v2_core_HeaderValue; + /** + * Header name/value pair. + */ export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + /** + * [#next-free-field: 23] + */ export type HealthCheck = _envoy_api_v2_core_HealthCheck; + /** + * [#next-free-field: 23] + */ export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; + /** + * Endpoint health status. + */ export type HealthStatus = _envoy_api_v2_core_HealthStatus; + /** + * Envoy external URI descriptor + */ export type HttpUri = _envoy_api_v2_core_HttpUri; + /** + * Envoy external URI descriptor + */ export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality = _envoy_api_v2_core_Locality; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality__Output = _envoy_api_v2_core_Locality__Output; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata = _envoy_api_v2_core_Metadata; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node = _envoy_api_v2_core_Node; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node__Output = _envoy_api_v2_core_Node__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + /** + * HTTP request method. + */ export type RequestMethod = _envoy_api_v2_core_RequestMethod; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + /** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + /** + * [#next-free-field: 7] + */ export type SocketAddress = _envoy_api_v2_core_SocketAddress; + /** + * [#next-free-field: 7] + */ export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption = _envoy_api_v2_core_SocketOption; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + /** + * Identifies the direction of the traffic relative to the local Envoy. + */ export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket = _envoy_api_v2_core_TransportSocket; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; } export namespace endpoint { + /** + * Upstream host identifier. + */ export type Endpoint = _envoy_api_v2_endpoint_Endpoint; + /** + * Upstream host identifier. + */ export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; + /** + * An Endpoint that Envoy can route traffic to. + * [#next-free-field: 6] + */ export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; + /** + * An Endpoint that Envoy can route traffic to. + * [#next-free-field: 6] + */ export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; + /** + * A group of endpoints belonging to a Locality. + * One can have multiple LocalityLbEndpoints for a locality, but this is + * generally only done if the different groups need to have different load + * balancing weights or different priorities. + * [#next-free-field: 7] + */ export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; + /** + * A group of endpoints belonging to a Locality. + * One can have multiple LocalityLbEndpoints for a locality, but this is + * generally only done if the different groups need to have different load + * balancing weights or different priorities. + * [#next-free-field: 7] + */ export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; } } } export namespace type { export type CodecClientType = _envoy_type_CodecClientType; + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange = _envoy_type_DoubleRange; + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent = _envoy_type_FractionalPercent; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range = _envoy_type_Int32Range; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range__Output = _envoy_type_Int32Range__Output; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range = _envoy_type_Int64Range; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range__Output = _envoy_type_Int64Range__Output; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent = _envoy_type_Percent; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent__Output = _envoy_type_Percent__Output; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion = _envoy_type_SemanticVersion; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher = _envoy_type_matcher_StringMatcher; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; } } } export namespace google { export namespace api { + /** + * A custom pattern is used for defining custom HTTP verb. + */ export type CustomHttpPattern = _google_api_CustomHttpPattern; + /** + * A custom pattern is used for defining custom HTTP verb. + */ export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + /** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export type Http = _google_api_Http; + /** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export type Http__Output = _google_api_Http__Output; + /** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export type HttpRule = _google_api_HttpRule; + /** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export type HttpRule__Output = _google_api_HttpRule__Output; } export namespace protobuf { @@ -329,52 +1295,203 @@ export namespace messages { } } export namespace validate { + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules = _validate_AnyRules; + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules__Output = _validate_AnyRules__Output; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules = _validate_BoolRules; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules__Output = _validate_BoolRules__Output; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules = _validate_BytesRules; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules__Output = _validate_BytesRules__Output; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules = _validate_DoubleRules; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules__Output = _validate_DoubleRules__Output; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules = _validate_DurationRules; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules__Output = _validate_DurationRules__Output; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules = _validate_EnumRules; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules__Output = _validate_EnumRules__Output; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules = _validate_FieldRules; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules__Output = _validate_FieldRules__Output; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules = _validate_Fixed32Rules; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules = _validate_Fixed64Rules; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules = _validate_FloatRules; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules__Output = _validate_FloatRules__Output; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules = _validate_Int32Rules; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules__Output = _validate_Int32Rules__Output; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules = _validate_Int64Rules; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules__Output = _validate_Int64Rules__Output; + /** + * WellKnownRegex contain some well-known patterns. + */ export type KnownRegex = _validate_KnownRegex; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules = _validate_MapRules; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules__Output = _validate_MapRules__Output; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules = _validate_MessageRules; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules__Output = _validate_MessageRules__Output; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules = _validate_RepeatedRules; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules__Output = _validate_RepeatedRules__Output; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules = _validate_SFixed32Rules; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules = _validate_SFixed64Rules; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules = _validate_SInt32Rules; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules__Output = _validate_SInt32Rules__Output; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules = _validate_SInt64Rules; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules__Output = _validate_SInt64Rules__Output; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules = _validate_StringRules; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules__Output = _validate_StringRules__Output; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules = _validate_TimestampRules; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules__Output = _validate_TimestampRules__Output; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules = _validate_UInt32Rules; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules__Output = _validate_UInt32Rules__Output; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules = _validate_UInt64Rules; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules__Output = _validate_UInt64Rules__Output; } } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts index e3d33e0ac..9d7cad537 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts @@ -28,312 +28,1652 @@ import { Long } from '@grpc/proto-loader'; // Original file: deps/envoy-api/envoy/api/v2/cluster.proto export enum _envoy_api_v2_Cluster_ClusterProtocolSelection { + /** + * Cluster can only operate on one of the possible upstream protocols (HTTP1.1, HTTP2). + * If :ref:`http2_protocol_options ` are + * present, HTTP2 will be used, otherwise HTTP1.1 will be used. + */ USE_CONFIGURED_PROTOCOL = 0, + /** + * Use HTTP1.1 or HTTP2, depending on which one is used on the downstream connection. + */ USE_DOWNSTREAM_PROTOCOL = 1, } +/** + * Common configuration for all load balancer implementations. + * [#next-free-field: 8] + */ export interface _envoy_api_v2_Cluster_CommonLbConfig { + /** + * Configures the :ref:`healthy panic threshold `. + * If not specified, the default is 50%. + * To disable panic mode, set to 0%. + * + * .. note:: + * The specified percent will be truncated to the nearest 1%. + */ 'healthy_panic_threshold'?: (_envoy_type_Percent); 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig); 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig); + /** + * If set, all health check/weight/metadata updates that happen within this duration will be + * merged and delivered in one shot when the duration expires. The start of the duration is when + * the first update happens. This is useful for big clusters, with potentially noisy deploys + * that might trigger excessive CPU usage due to a constant stream of healthcheck state changes + * or metadata updates. The first set of updates to be seen apply immediately (e.g.: a new + * cluster). Please always keep in mind that the use of sandbox technologies may change this + * behavior. + * + * If this is not set, we default to a merge window of 1000ms. To disable it, set the merge + * window to 0. + * + * Note: merging does not apply to cluster membership changes (e.g.: adds/removes); this is + * because merging those updates isn't currently safe. See + * https://github.com/envoyproxy/envoy/pull/3941. + */ 'update_merge_window'?: (_google_protobuf_Duration); + /** + * If set to true, Envoy will not consider new hosts when computing load balancing weights until + * they have been health checked for the first time. This will have no effect unless + * active health checking is also configured. + * + * Ignoring a host means that for any load balancing calculations that adjust weights based + * on the ratio of eligible hosts and total hosts (priority spillover, locality weighting and + * panic mode) Envoy will exclude these hosts in the denominator. + * + * For example, with hosts in two priorities P0 and P1, where P0 looks like + * {healthy, unhealthy (new), unhealthy (new)} + * and where P1 looks like + * {healthy, healthy} + * all traffic will still hit P0, as 1 / (3 - 2) = 1. + * + * Enabling this will allow scaling up the number of hosts for a given cluster without entering + * panic mode or triggering priority spillover, assuming the hosts pass the first health check. + * + * If panic mode is triggered, new hosts are still eligible for traffic; they simply do not + * contribute to the calculation when deciding whether panic mode is enabled or not. + */ 'ignore_new_hosts_until_first_hc'?: (boolean); + /** + * If set to `true`, the cluster manager will drain all existing + * connections to upstream hosts whenever hosts are added or removed from the cluster. + */ 'close_connections_on_host_set_change'?: (boolean); + /** + * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) + */ 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig); 'locality_config_specifier'?: "zone_aware_lb_config"|"locality_weighted_lb_config"; } +/** + * Common configuration for all load balancer implementations. + * [#next-free-field: 8] + */ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { + /** + * Configures the :ref:`healthy panic threshold `. + * If not specified, the default is 50%. + * To disable panic mode, set to 0%. + * + * .. note:: + * The specified percent will be truncated to the nearest 1%. + */ 'healthy_panic_threshold': (_envoy_type_Percent__Output); 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); + /** + * If set, all health check/weight/metadata updates that happen within this duration will be + * merged and delivered in one shot when the duration expires. The start of the duration is when + * the first update happens. This is useful for big clusters, with potentially noisy deploys + * that might trigger excessive CPU usage due to a constant stream of healthcheck state changes + * or metadata updates. The first set of updates to be seen apply immediately (e.g.: a new + * cluster). Please always keep in mind that the use of sandbox technologies may change this + * behavior. + * + * If this is not set, we default to a merge window of 1000ms. To disable it, set the merge + * window to 0. + * + * Note: merging does not apply to cluster membership changes (e.g.: adds/removes); this is + * because merging those updates isn't currently safe. See + * https://github.com/envoyproxy/envoy/pull/3941. + */ 'update_merge_window': (_google_protobuf_Duration__Output); + /** + * If set to true, Envoy will not consider new hosts when computing load balancing weights until + * they have been health checked for the first time. This will have no effect unless + * active health checking is also configured. + * + * Ignoring a host means that for any load balancing calculations that adjust weights based + * on the ratio of eligible hosts and total hosts (priority spillover, locality weighting and + * panic mode) Envoy will exclude these hosts in the denominator. + * + * For example, with hosts in two priorities P0 and P1, where P0 looks like + * {healthy, unhealthy (new), unhealthy (new)} + * and where P1 looks like + * {healthy, healthy} + * all traffic will still hit P0, as 1 / (3 - 2) = 1. + * + * Enabling this will allow scaling up the number of hosts for a given cluster without entering + * panic mode or triggering priority spillover, assuming the hosts pass the first health check. + * + * If panic mode is triggered, new hosts are still eligible for traffic; they simply do not + * contribute to the calculation when deciding whether panic mode is enabled or not. + */ 'ignore_new_hosts_until_first_hc': (boolean); + /** + * If set to `true`, the cluster manager will drain all existing + * connections to upstream hosts whenever hosts are added or removed from the cluster. + */ 'close_connections_on_host_set_change': (boolean); + /** + * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) + */ 'consistent_hashing_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; } +/** + * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) + */ export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig { + /** + * If set to `true`, the cluster will use hostname instead of the resolved + * address as the key to consistently hash to an upstream host. Only valid for StrictDNS clusters with hostnames which resolve to a single IP address. + */ 'use_hostname_for_hashing'?: (boolean); } +/** + * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) + */ export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output { + /** + * If set to `true`, the cluster will use hostname instead of the resolved + * address as the key to consistently hash to an upstream host. Only valid for StrictDNS clusters with hostnames which resolve to a single IP address. + */ 'use_hostname_for_hashing': (boolean); } +/** + * Configuration for :ref:`locality weighted load balancing + * ` + */ export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { } +/** + * Configuration for :ref:`locality weighted load balancing + * ` + */ export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { } +/** + * Configuration for :ref:`zone aware routing + * `. + */ export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { + /** + * Configures percentage of requests that will be considered for zone aware routing + * if zone aware routing is configured. If not specified, the default is 100%. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ 'routing_enabled'?: (_envoy_type_Percent); + /** + * Configures minimum upstream cluster size required for zone aware routing + * If upstream cluster size is less than specified, zone aware routing is not performed + * even if zone aware routing is configured. If not specified, the default is 6. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ 'min_cluster_size'?: (_google_protobuf_UInt64Value); + /** + * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic + * mode`. Instead, the cluster will fail all + * requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a + * failing service. + */ 'fail_traffic_on_panic'?: (boolean); } +/** + * Configuration for :ref:`zone aware routing + * `. + */ export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { + /** + * Configures percentage of requests that will be considered for zone aware routing + * if zone aware routing is configured. If not specified, the default is 100%. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ 'routing_enabled': (_envoy_type_Percent__Output); + /** + * Configures minimum upstream cluster size required for zone aware routing + * If upstream cluster size is less than specified, zone aware routing is not performed + * even if zone aware routing is configured. If not specified, the default is 6. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ 'min_cluster_size': (_google_protobuf_UInt64Value__Output); + /** + * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic + * mode`. Instead, the cluster will fail all + * requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a + * failing service. + */ 'fail_traffic_on_panic': (boolean); } +/** + * Extended cluster type. + */ export interface _envoy_api_v2_Cluster_CustomClusterType { + /** + * The type of the cluster to instantiate. The name must match a supported cluster type. + */ 'name'?: (string); + /** + * Cluster specific configuration which depends on the cluster being instantiated. + * See the supported cluster for further documentation. + */ 'typed_config'?: (_google_protobuf_Any); } +/** + * Extended cluster type. + */ export interface _envoy_api_v2_Cluster_CustomClusterType__Output { + /** + * The type of the cluster to instantiate. The name must match a supported cluster type. + */ 'name': (string); + /** + * Cluster specific configuration which depends on the cluster being instantiated. + * See the supported cluster for further documentation. + */ 'typed_config': (_google_protobuf_Any__Output); } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * Refer to :ref:`service discovery type ` + * for an explanation on each type. + */ export enum _envoy_api_v2_Cluster_DiscoveryType { + /** + * Refer to the :ref:`static discovery type` + * for an explanation. + */ STATIC = 0, + /** + * Refer to the :ref:`strict DNS discovery + * type` + * for an explanation. + */ STRICT_DNS = 1, + /** + * Refer to the :ref:`logical DNS discovery + * type` + * for an explanation. + */ LOGICAL_DNS = 2, + /** + * Refer to the :ref:`service discovery type` + * for an explanation. + */ EDS = 3, + /** + * Refer to the :ref:`original destination discovery + * type` + * for an explanation. + */ ORIGINAL_DST = 4, } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * When V4_ONLY is selected, the DNS resolver will only perform a lookup for + * addresses in the IPv4 family. If V6_ONLY is selected, the DNS resolver will + * only perform a lookup for addresses in the IPv6 family. If AUTO is + * specified, the DNS resolver will first perform a lookup for addresses in + * the IPv6 family and fallback to a lookup for addresses in the IPv4 family. + * For cluster types other than + * :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS`, + * this setting is + * ignored. + */ export enum _envoy_api_v2_Cluster_DnsLookupFamily { AUTO = 0, V4_ONLY = 1, V6_ONLY = 2, } +/** + * Only valid when discovery type is EDS. + */ export interface _envoy_api_v2_Cluster_EdsClusterConfig { + /** + * Configuration for the source of EDS updates for this Cluster. + */ 'eds_config'?: (_envoy_api_v2_core_ConfigSource); + /** + * Optional alternative to cluster name to present to EDS. This does not + * have the same restrictions as cluster name, i.e. it may be arbitrary + * length. + */ 'service_name'?: (string); } +/** + * Only valid when discovery type is EDS. + */ export interface _envoy_api_v2_Cluster_EdsClusterConfig__Output { + /** + * Configuration for the source of EDS updates for this Cluster. + */ 'eds_config': (_envoy_api_v2_core_ConfigSource__Output); + /** + * Optional alternative to cluster name to present to EDS. This does not + * have the same restrictions as cluster name, i.e. it may be arbitrary + * length. + */ 'service_name': (string); } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * Refer to :ref:`load balancer type ` architecture + * overview section for information on each type. + */ export enum _envoy_api_v2_Cluster_LbPolicy { + /** + * Refer to the :ref:`round robin load balancing + * policy` + * for an explanation. + */ ROUND_ROBIN = 0, + /** + * Refer to the :ref:`least request load balancing + * policy` + * for an explanation. + */ LEAST_REQUEST = 1, + /** + * Refer to the :ref:`ring hash load balancing + * policy` + * for an explanation. + */ RING_HASH = 2, + /** + * Refer to the :ref:`random load balancing + * policy` + * for an explanation. + */ RANDOM = 3, + /** + * Refer to the :ref:`original destination load balancing + * policy` + * for an explanation. + * + * .. attention:: + * + * **This load balancing policy is deprecated**. Use CLUSTER_PROVIDED instead. + */ ORIGINAL_DST_LB = 4, + /** + * Refer to the :ref:`Maglev load balancing policy` + * for an explanation. + */ MAGLEV = 5, + /** + * This load balancer type must be specified if the configured cluster provides a cluster + * specific load balancer. Consult the configured cluster's documentation for whether to set + * this option or not. + */ CLUSTER_PROVIDED = 6, + /** + * [#not-implemented-hide:] Use the new :ref:`load_balancing_policy + * ` field to determine the LB policy. + * [#next-major-version: In the v3 API, we should consider deprecating the lb_policy field + * and instead using the new load_balancing_policy field as the one and only mechanism for + * configuring this.] + */ LOAD_BALANCING_POLICY_CONFIG = 7, } +/** + * Optionally divide the endpoints in this cluster into subsets defined by + * endpoint metadata and selected by route and weighted cluster metadata. + * [#next-free-field: 8] + */ export interface _envoy_api_v2_Cluster_LbSubsetConfig { + /** + * The behavior used when no endpoint subset matches the selected route's + * metadata. The value defaults to + * :ref:`NO_FALLBACK`. + */ 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); + /** + * Specifies the default subset of endpoints used during fallback if + * fallback_policy is + * :ref:`DEFAULT_SUBSET`. + * Each field in default_subset is + * compared to the matching LbEndpoint.Metadata under the *envoy.lb* + * namespace. It is valid for no hosts to match, in which case the behavior + * is the same as a fallback_policy of + * :ref:`NO_FALLBACK`. + */ 'default_subset'?: (_google_protobuf_Struct); + /** + * For each entry, LbEndpoint.Metadata's + * *envoy.lb* namespace is traversed and a subset is created for each unique + * combination of key and value. For example: + * + * .. code-block:: json + * + * { "subset_selectors": [ + * { "keys": [ "version" ] }, + * { "keys": [ "stage", "hardware_type" ] } + * ]} + * + * A subset is matched when the metadata from the selected route and + * weighted cluster contains the same keys and values as the subset's + * metadata. The same host may appear in multiple subsets. + */ 'subset_selectors'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector)[]; + /** + * If true, routing to subsets will take into account the localities and locality weights of the + * endpoints when making the routing decision. + * + * There are some potential pitfalls associated with enabling this feature, as the resulting + * traffic split after applying both a subset match and locality weights might be undesirable. + * + * Consider for example a situation in which you have 50/50 split across two localities X/Y + * which have 100 hosts each without subsetting. If the subset LB results in X having only 1 + * host selected but Y having 100, then a lot more load is being dumped on the single host in X + * than originally anticipated in the load balancing assignment delivered via EDS. + */ 'locality_weight_aware'?: (boolean); + /** + * When used with locality_weight_aware, scales the weight of each locality by the ratio + * of hosts in the subset vs hosts in the original subset. This aims to even out the load + * going to an individual locality if said locality is disproportionately affected by the + * subset predicate. + */ 'scale_locality_weight'?: (boolean); + /** + * If true, when a fallback policy is configured and its corresponding subset fails to find + * a host this will cause any host to be selected instead. + * + * This is useful when using the default subset as the fallback policy, given the default + * subset might become empty. With this option enabled, if that happens the LB will attempt + * to select a host from the entire cluster. + */ 'panic_mode_any'?: (boolean); + /** + * If true, metadata specified for a metadata key will be matched against the corresponding + * endpoint metadata if the endpoint metadata matches the value exactly OR it is a list value + * and any of the elements in the list matches the criteria. + */ 'list_as_any'?: (boolean); } +/** + * Optionally divide the endpoints in this cluster into subsets defined by + * endpoint metadata and selected by route and weighted cluster metadata. + * [#next-free-field: 8] + */ export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { + /** + * The behavior used when no endpoint subset matches the selected route's + * metadata. The value defaults to + * :ref:`NO_FALLBACK`. + */ 'fallback_policy': (keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); + /** + * Specifies the default subset of endpoints used during fallback if + * fallback_policy is + * :ref:`DEFAULT_SUBSET`. + * Each field in default_subset is + * compared to the matching LbEndpoint.Metadata under the *envoy.lb* + * namespace. It is valid for no hosts to match, in which case the behavior + * is the same as a fallback_policy of + * :ref:`NO_FALLBACK`. + */ 'default_subset': (_google_protobuf_Struct__Output); + /** + * For each entry, LbEndpoint.Metadata's + * *envoy.lb* namespace is traversed and a subset is created for each unique + * combination of key and value. For example: + * + * .. code-block:: json + * + * { "subset_selectors": [ + * { "keys": [ "version" ] }, + * { "keys": [ "stage", "hardware_type" ] } + * ]} + * + * A subset is matched when the metadata from the selected route and + * weighted cluster contains the same keys and values as the subset's + * metadata. The same host may appear in multiple subsets. + */ 'subset_selectors': (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector__Output)[]; + /** + * If true, routing to subsets will take into account the localities and locality weights of the + * endpoints when making the routing decision. + * + * There are some potential pitfalls associated with enabling this feature, as the resulting + * traffic split after applying both a subset match and locality weights might be undesirable. + * + * Consider for example a situation in which you have 50/50 split across two localities X/Y + * which have 100 hosts each without subsetting. If the subset LB results in X having only 1 + * host selected but Y having 100, then a lot more load is being dumped on the single host in X + * than originally anticipated in the load balancing assignment delivered via EDS. + */ 'locality_weight_aware': (boolean); + /** + * When used with locality_weight_aware, scales the weight of each locality by the ratio + * of hosts in the subset vs hosts in the original subset. This aims to even out the load + * going to an individual locality if said locality is disproportionately affected by the + * subset predicate. + */ 'scale_locality_weight': (boolean); + /** + * If true, when a fallback policy is configured and its corresponding subset fails to find + * a host this will cause any host to be selected instead. + * + * This is useful when using the default subset as the fallback policy, given the default + * subset might become empty. With this option enabled, if that happens the LB will attempt + * to select a host from the entire cluster. + */ 'panic_mode_any': (boolean); + /** + * If true, metadata specified for a metadata key will be matched against the corresponding + * endpoint metadata if the endpoint metadata matches the value exactly OR it is a list value + * and any of the elements in the list matches the criteria. + */ 'list_as_any': (boolean); } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * If NO_FALLBACK is selected, a result + * equivalent to no healthy hosts is reported. If ANY_ENDPOINT is selected, + * any cluster endpoint may be returned (subject to policy, health checks, + * etc). If DEFAULT_SUBSET is selected, load balancing is performed over the + * endpoints matching the values from the default_subset field. + */ export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy { NO_FALLBACK = 0, ANY_ENDPOINT = 1, DEFAULT_SUBSET = 2, } +/** + * Specifications for subsets. + */ export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector { + /** + * List of keys to match with the weighted cluster metadata. + */ 'keys'?: (string)[]; + /** + * The behavior used when no endpoint subset matches the selected route's + * metadata. + */ 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); + /** + * Subset of + * :ref:`keys` used by + * :ref:`KEYS_SUBSET` + * fallback policy. + * It has to be a non empty list if KEYS_SUBSET fallback policy is selected. + * For any other fallback policy the parameter is not used and should not be set. + * Only values also present in + * :ref:`keys` are allowed, but + * `fallback_keys_subset` cannot be equal to `keys`. + */ 'fallback_keys_subset'?: (string)[]; } +/** + * Specifications for subsets. + */ export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector__Output { + /** + * List of keys to match with the weighted cluster metadata. + */ 'keys': (string)[]; + /** + * The behavior used when no endpoint subset matches the selected route's + * metadata. + */ 'fallback_policy': (keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); + /** + * Subset of + * :ref:`keys` used by + * :ref:`KEYS_SUBSET` + * fallback policy. + * It has to be a non empty list if KEYS_SUBSET fallback policy is selected. + * For any other fallback policy the parameter is not used and should not be set. + * Only values also present in + * :ref:`keys` are allowed, but + * `fallback_keys_subset` cannot be equal to `keys`. + */ 'fallback_keys_subset': (string)[]; } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * Allows to override top level fallback policy per selector. + */ export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy { + /** + * If NOT_DEFINED top level config fallback policy is used instead. + */ NOT_DEFINED = 0, + /** + * If NO_FALLBACK is selected, a result equivalent to no healthy hosts is reported. + */ NO_FALLBACK = 1, + /** + * If ANY_ENDPOINT is selected, any cluster endpoint may be returned + * (subject to policy, health checks, etc). + */ ANY_ENDPOINT = 2, + /** + * If DEFAULT_SUBSET is selected, load balancing is performed over the + * endpoints matching the values from the default_subset field. + */ DEFAULT_SUBSET = 3, + /** + * If KEYS_SUBSET is selected, subset selector matching is performed again with metadata + * keys reduced to + * :ref:`fallback_keys_subset`. + * It allows for a fallback to a different, less specific selector if some of the keys of + * the selector are considered optional. + */ KEYS_SUBSET = 4, } +/** + * Specific configuration for the LeastRequest load balancing policy. + */ export interface _envoy_api_v2_Cluster_LeastRequestLbConfig { + /** + * The number of random healthy hosts from which the host with the fewest active requests will + * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. + */ 'choice_count'?: (_google_protobuf_UInt32Value); } +/** + * Specific configuration for the LeastRequest load balancing policy. + */ export interface _envoy_api_v2_Cluster_LeastRequestLbConfig__Output { + /** + * The number of random healthy hosts from which the host with the fewest active requests will + * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. + */ 'choice_count': (_google_protobuf_UInt32Value__Output); } +/** + * Specific configuration for the + * :ref:`Original Destination ` + * load balancing policy. + */ export interface _envoy_api_v2_Cluster_OriginalDstLbConfig { + /** + * When true, :ref:`x-envoy-original-dst-host + * ` can be used to override destination + * address. + * + * .. attention:: + * + * This header isn't sanitized by default, so enabling this feature allows HTTP clients to + * route traffic to arbitrary hosts and/or ports, which may have serious security + * consequences. + */ 'use_http_header'?: (boolean); } +/** + * Specific configuration for the + * :ref:`Original Destination ` + * load balancing policy. + */ export interface _envoy_api_v2_Cluster_OriginalDstLbConfig__Output { + /** + * When true, :ref:`x-envoy-original-dst-host + * ` can be used to override destination + * address. + * + * .. attention:: + * + * This header isn't sanitized by default, so enabling this feature allows HTTP clients to + * route traffic to arbitrary hosts and/or ports, which may have serious security + * consequences. + */ 'use_http_header': (boolean); } export interface _envoy_api_v2_Cluster_RefreshRate { + /** + * Specifies the base interval between refreshes. This parameter is required and must be greater + * than zero and less than + * :ref:`max_interval `. + */ 'base_interval'?: (_google_protobuf_Duration); + /** + * Specifies the maximum interval between refreshes. This parameter is optional, but must be + * greater than or equal to the + * :ref:`base_interval ` if set. The default + * is 10 times the :ref:`base_interval `. + */ 'max_interval'?: (_google_protobuf_Duration); } export interface _envoy_api_v2_Cluster_RefreshRate__Output { + /** + * Specifies the base interval between refreshes. This parameter is required and must be greater + * than zero and less than + * :ref:`max_interval `. + */ 'base_interval': (_google_protobuf_Duration__Output); + /** + * Specifies the maximum interval between refreshes. This parameter is optional, but must be + * greater than or equal to the + * :ref:`base_interval ` if set. The default + * is 10 times the :ref:`base_interval `. + */ 'max_interval': (_google_protobuf_Duration__Output); } +/** + * Specific configuration for the :ref:`RingHash` + * load balancing policy. + */ export interface _envoy_api_v2_Cluster_RingHashLbConfig { + /** + * Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each + * provided host) the better the request distribution will reflect the desired weights. Defaults + * to 1024 entries, and limited to 8M entries. See also + * :ref:`maximum_ring_size`. + */ 'minimum_ring_size'?: (_google_protobuf_UInt64Value); + /** + * The hash function used to hash hosts onto the ketama ring. The value defaults to + * :ref:`XX_HASH`. + */ 'hash_function'?: (_envoy_api_v2_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + /** + * Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered + * to further constrain resource use. See also + * :ref:`minimum_ring_size`. + */ 'maximum_ring_size'?: (_google_protobuf_UInt64Value); } +/** + * Specific configuration for the :ref:`RingHash` + * load balancing policy. + */ export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { + /** + * Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each + * provided host) the better the request distribution will reflect the desired weights. Defaults + * to 1024 entries, and limited to 8M entries. See also + * :ref:`maximum_ring_size`. + */ 'minimum_ring_size': (_google_protobuf_UInt64Value__Output); + /** + * The hash function used to hash hosts onto the ketama ring. The value defaults to + * :ref:`XX_HASH`. + */ 'hash_function': (keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + /** + * Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered + * to further constrain resource use. See also + * :ref:`minimum_ring_size`. + */ 'maximum_ring_size': (_google_protobuf_UInt64Value__Output); } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * The hash function used to hash hosts onto the ketama ring. + */ export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { + /** + * Use `xxHash `_, this is the default hash function. + */ XX_HASH = 0, + /** + * Use `MurmurHash2 `_, this is compatible with + * std:hash in GNU libstdc++ 3.4.20 or above. This is typically the case when compiled + * on Linux and not macOS. + */ MURMUR_HASH_2 = 1, } +/** + * TransportSocketMatch specifies what transport socket config will be used + * when the match conditions are satisfied. + */ export interface _envoy_api_v2_Cluster_TransportSocketMatch { + /** + * The name of the match, used in stats generation. + */ 'name'?: (string); + /** + * Optional endpoint metadata match criteria. + * The connection to the endpoint with metadata matching what is set in this field + * will use the transport socket configuration specified here. + * The endpoint's metadata entry in *envoy.transport_socket_match* is used to match + * against the values specified in this field. + */ 'match'?: (_google_protobuf_Struct); + /** + * The configuration of the transport socket. + */ 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); } +/** + * TransportSocketMatch specifies what transport socket config will be used + * when the match conditions are satisfied. + */ export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { + /** + * The name of the match, used in stats generation. + */ 'name': (string); + /** + * Optional endpoint metadata match criteria. + * The connection to the endpoint with metadata matching what is set in this field + * will use the transport socket configuration specified here. + * The endpoint's metadata entry in *envoy.transport_socket_match* is used to match + * against the values specified in this field. + */ 'match': (_google_protobuf_Struct__Output); + /** + * The configuration of the transport socket. + */ 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); } +/** + * Configuration for a single upstream cluster. + * [#next-free-field: 48] + */ export interface Cluster { + /** + * Supplies the name of the cluster which must be unique across all clusters. + * The cluster name is used when emitting + * :ref:`statistics ` if :ref:`alt_stat_name + * ` is not provided. + * Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. + */ 'name'?: (string); + /** + * The :ref:`service discovery type ` + * to use for resolving the cluster. + */ 'type'?: (_envoy_api_v2_Cluster_DiscoveryType | keyof typeof _envoy_api_v2_Cluster_DiscoveryType); + /** + * Configuration to use for EDS updates for the Cluster. + */ 'eds_cluster_config'?: (_envoy_api_v2_Cluster_EdsClusterConfig); + /** + * The timeout for new network connections to hosts in the cluster. + */ 'connect_timeout'?: (_google_protobuf_Duration); + /** + * Soft limit on size of the cluster’s connections read and write buffers. If + * unspecified, an implementation defined default is applied (1MiB). + */ 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + /** + * The :ref:`load balancer type ` to use + * when picking a host in the cluster. + */ 'lb_policy'?: (_envoy_api_v2_Cluster_LbPolicy | keyof typeof _envoy_api_v2_Cluster_LbPolicy); + /** + * If the service discovery type is + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS`, + * then hosts is required. + * + * .. attention:: + * + * **This field is deprecated**. Set the + * :ref:`load_assignment` field instead. + */ 'hosts'?: (_envoy_api_v2_core_Address)[]; + /** + * Optional :ref:`active health checking ` + * configuration for the cluster. If no + * configuration is specified no health checking will be done and all cluster + * members will be considered healthy at all times. + */ 'health_checks'?: (_envoy_api_v2_core_HealthCheck)[]; + /** + * Optional maximum requests for a single upstream connection. This parameter + * is respected by both the HTTP/1.1 and HTTP/2 connection pool + * implementations. If not specified, there is no limit. Setting this + * parameter to 1 will effectively disable keep alive. + */ 'max_requests_per_connection'?: (_google_protobuf_UInt32Value); + /** + * Optional :ref:`circuit breaking ` for the cluster. + */ 'circuit_breakers'?: (_envoy_api_v2_cluster_CircuitBreakers); + /** + * The TLS configuration for connections to the upstream cluster. + * + * .. attention:: + * + * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are + * set, `transport_socket` takes priority. + */ 'tls_context'?: (_envoy_api_v2_auth_UpstreamTlsContext); + /** + * Additional options when handling HTTP1 requests. + */ 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); + /** + * Even if default HTTP2 protocol options are desired, this field must be + * set so that Envoy will assume that the upstream supports HTTP/2 when + * making new HTTP connection pool connections. Currently, Envoy only + * supports prior knowledge for upstream connections. Even if TLS is used + * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 + * connections to happen over plain text. + */ 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); + /** + * If the DNS refresh rate is specified and the cluster type is either + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, + * this value is used as the cluster’s DNS refresh + * rate. The value configured must be at least 1ms. If this setting is not specified, the + * value defaults to 5000ms. For cluster types other than + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` + * this setting is ignored. + */ 'dns_refresh_rate'?: (_google_protobuf_Duration); + /** + * The DNS IP address resolution policy. If this setting is not specified, the + * value defaults to + * :ref:`AUTO`. + */ 'dns_lookup_family'?: (_envoy_api_v2_Cluster_DnsLookupFamily | keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); + /** + * If DNS resolvers are specified and the cluster type is either + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, + * this value is used to specify the cluster’s dns resolvers. + * If this setting is not specified, the value defaults to the default + * resolver, which uses /etc/resolv.conf for configuration. For cluster types + * other than + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` + * this setting is ignored. + */ 'dns_resolvers'?: (_envoy_api_v2_core_Address)[]; + /** + * If specified, outlier detection will be enabled for this upstream cluster. + * Each of the configuration values can be overridden via + * :ref:`runtime values `. + */ 'outlier_detection'?: (_envoy_api_v2_cluster_OutlierDetection); + /** + * The interval for removing stale hosts from a cluster type + * :ref:`ORIGINAL_DST`. + * Hosts are considered stale if they have not been used + * as upstream destinations during this interval. New hosts are added + * to original destination clusters on demand as new connections are + * redirected to Envoy, causing the number of hosts in the cluster to + * grow over time. Hosts that are not stale (they are actively used as + * destinations) are kept in the cluster, which allows connections to + * them remain open, saving the latency that would otherwise be spent + * on opening new connections. If this setting is not specified, the + * value defaults to 5000ms. For cluster types other than + * :ref:`ORIGINAL_DST` + * this setting is ignored. + */ 'cleanup_interval'?: (_google_protobuf_Duration); + /** + * Optional configuration used to bind newly established upstream connections. + * This overrides any bind_config specified in the bootstrap proto. + * If the address and port are empty, no bind will be performed. + */ 'upstream_bind_config'?: (_envoy_api_v2_core_BindConfig); + /** + * Configuration for load balancing subsetting. + */ 'lb_subset_config'?: (_envoy_api_v2_Cluster_LbSubsetConfig); + /** + * Optional configuration for the Ring Hash load balancing policy. + */ 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig); + /** + * Optional custom transport socket implementation to use for upstream connections. + * To setup TLS, set a transport socket with name `tls` and + * :ref:`UpstreamTlsContexts ` in the `typed_config`. + * If no transport socket configuration is specified, new connections + * will be set up with plaintext. + */ 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); + /** + * The Metadata field can be used to provide additional information about the + * cluster. It can be used for stats, logging, and varying filter behavior. + * Fields should use reverse DNS notation to denote which entity within Envoy + * will need the information. For instance, if the metadata is intended for + * the Router filter, the filter name should be specified as *envoy.filters.http.router*. + */ 'metadata'?: (_envoy_api_v2_core_Metadata); + /** + * Determines how Envoy selects the protocol used to speak to upstream hosts. + */ 'protocol_selection'?: (_envoy_api_v2_Cluster_ClusterProtocolSelection | keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + /** + * Common configuration for all load balancer implementations. + */ 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig); + /** + * An optional alternative to the cluster name to be used while emitting stats. + * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be + * confused with :ref:`Router Filter Header + * `. + */ 'alt_stat_name'?: (string); + /** + * Additional options when handling HTTP requests upstream. These options will be applicable to + * both HTTP1 and HTTP2 requests. + */ 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); + /** + * Optional options for upstream connections. + */ 'upstream_connection_options'?: (_envoy_api_v2_UpstreamConnectionOptions); + /** + * If an upstream host becomes unhealthy (as determined by the configured health checks + * or outlier detection), immediately close all connections to the failed host. + * + * .. note:: + * + * This is currently only supported for connections created by tcp_proxy. + * + * .. note:: + * + * The current implementation of this feature closes all connections immediately when + * the unhealthy status is detected. If there are a large number of connections open + * to an upstream host that becomes unhealthy, Envoy may spend a substantial amount of + * time exclusively closing these connections, and not processing any other traffic. + */ 'close_connections_on_host_health_failure'?: (boolean); + /** + * If set to true, Envoy will ignore the health value of a host when processing its removal + * from service discovery. This means that if active health checking is used, Envoy will *not* + * wait for the endpoint to go unhealthy before removing it. + */ 'drain_connections_on_host_removal'?: (boolean); + /** + * Setting this is required for specifying members of + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS` clusters. + * This field supersedes the *hosts* field in the v2 API. + * + * .. attention:: + * + * Setting this allows non-EDS cluster types to contain embedded EDS equivalent + * :ref:`endpoint assignments`. + */ 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment); + /** + * Optional configuration for the Original Destination load balancing policy. + */ 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig); + /** + * The extension_protocol_options field is used to provide extension-specific protocol options + * for upstream connections. The key should match the extension filter name, such as + * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on + * specific options. + */ 'extension_protocol_options'?: (_google_protobuf_Struct); + /** + * The extension_protocol_options field is used to provide extension-specific protocol options + * for upstream connections. The key should match the extension filter name, such as + * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on + * specific options. + */ 'typed_extension_protocol_options'?: (_google_protobuf_Any); + /** + * Optional configuration for the LeastRequest load balancing policy. + */ 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig); + /** + * The custom cluster type. + */ 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType); + /** + * Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, + * cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS + * resolution. + */ 'respect_dns_ttl'?: (boolean); + /** + * An (optional) network filter chain, listed in the order the filters should be applied. + * The chain will be applied to all outgoing connections that Envoy makes to the upstream + * servers of this cluster. + */ 'filters'?: (_envoy_api_v2_cluster_Filter)[]; + /** + * [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the + * :ref:`lb_policy` field has the value + * :ref:`LOAD_BALANCING_POLICY_CONFIG`. + */ 'load_balancing_policy'?: (_envoy_api_v2_LoadBalancingPolicy); + /** + * [#not-implemented-hide:] + * If present, tells the client where to send load reports via LRS. If not present, the + * client will fall back to a client-side default, which may be either (a) don't send any + * load reports or (b) send load reports for all clusters to a single default server + * (which may be configured in the bootstrap file). + * + * Note that if multiple clusters point to the same LRS server, the client may choose to + * create a separate stream for each cluster or it may choose to coalesce the data for + * multiple clusters onto a single stream. Either way, the client must make sure to send + * the data for any given cluster on no more than one stream. + * + * [#next-major-version: In the v3 API, we should consider restructuring this somehow, + * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation + * from the LRS stream here.] + */ 'lrs_server'?: (_envoy_api_v2_core_ConfigSource); + /** + * Configuration to use different transport sockets for different endpoints. + * The entry of *envoy.transport_socket_match* in the + * :ref:`LbEndpoint.Metadata ` + * is used to match against the transport sockets as they appear in the list. The first + * :ref:`match ` is used. + * For example, with the following match + * + * .. code-block:: yaml + * + * transport_socket_matches: + * - name: "enableMTLS" + * match: + * acceptMTLS: true + * transport_socket: + * name: envoy.transport_sockets.tls + * config: { ... } # tls socket configuration + * - name: "defaultToPlaintext" + * match: {} + * transport_socket: + * name: envoy.transport_sockets.raw_buffer + * + * Connections to the endpoints whose metadata value under *envoy.transport_socket_match* + * having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. + * + * If a :ref:`socket match ` with empty match + * criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" + * socket match in case above. + * + * If an endpoint metadata's value under *envoy.transport_socket_match* does not match any + * *TransportSocketMatch*, socket configuration fallbacks to use the *tls_context* or + * *transport_socket* specified in this cluster. + * + * This field allows gradual and flexible transport socket configuration changes. + * + * The metadata of endpoints in EDS can indicate transport socket capabilities. For example, + * an endpoint's metadata can have two key value pairs as "acceptMTLS": "true", + * "acceptPlaintext": "true". While some other endpoints, only accepting plaintext traffic + * has "acceptPlaintext": "true" metadata information. + * + * Then the xDS server can configure the CDS to a client, Envoy A, to send mutual TLS + * traffic for endpoints with "acceptMTLS": "true", by adding a corresponding + * *TransportSocketMatch* in this field. Other client Envoys receive CDS without + * *transport_socket_match* set, and still send plain text traffic to the same cluster. + * + * [#comment:TODO(incfly): add a detailed architecture doc on intended usage.] + */ 'transport_socket_matches'?: (_envoy_api_v2_Cluster_TransportSocketMatch)[]; + /** + * If the DNS failure refresh rate is specified and the cluster type is either + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, + * this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is + * not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types + * other than :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS` this setting is + * ignored. + */ 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate); + /** + * [#next-major-version: Reconcile DNS options in a single message.] + * Always use TCP queries instead of UDP queries for DNS lookups. + */ 'use_tcp_for_dns_lookups'?: (boolean); + /** + * HTTP protocol options that are applied only to upstream HTTP connections. + * These options apply to all HTTP versions. + */ 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions); + /** + * If track_timeout_budgets is true, the :ref:`timeout budget histograms + * ` will be published for each + * request. These show what percentage of a request's per try and global timeout was used. A value + * of 0 would indicate that none of the timeout was used or that the timeout was infinite. A value + * of 100 would indicate that the request took the entirety of the timeout given to it. + */ 'track_timeout_budgets'?: (boolean); 'cluster_discovery_type'?: "type"|"cluster_type"; + /** + * Optional configuration for the load balancing algorithm selected by + * LbPolicy. Currently only + * :ref:`RING_HASH` and + * :ref:`LEAST_REQUEST` + * has additional configuration options. + * Specifying ring_hash_lb_config or least_request_lb_config without setting the corresponding + * LbPolicy will generate an error at runtime. + */ 'lb_config'?: "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; } +/** + * Configuration for a single upstream cluster. + * [#next-free-field: 48] + */ export interface Cluster__Output { + /** + * Supplies the name of the cluster which must be unique across all clusters. + * The cluster name is used when emitting + * :ref:`statistics ` if :ref:`alt_stat_name + * ` is not provided. + * Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. + */ 'name': (string); + /** + * The :ref:`service discovery type ` + * to use for resolving the cluster. + */ 'type'?: (keyof typeof _envoy_api_v2_Cluster_DiscoveryType); + /** + * Configuration to use for EDS updates for the Cluster. + */ 'eds_cluster_config': (_envoy_api_v2_Cluster_EdsClusterConfig__Output); + /** + * The timeout for new network connections to hosts in the cluster. + */ 'connect_timeout': (_google_protobuf_Duration__Output); + /** + * Soft limit on size of the cluster’s connections read and write buffers. If + * unspecified, an implementation defined default is applied (1MiB). + */ 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + /** + * The :ref:`load balancer type ` to use + * when picking a host in the cluster. + */ 'lb_policy': (keyof typeof _envoy_api_v2_Cluster_LbPolicy); + /** + * If the service discovery type is + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS`, + * then hosts is required. + * + * .. attention:: + * + * **This field is deprecated**. Set the + * :ref:`load_assignment` field instead. + */ 'hosts': (_envoy_api_v2_core_Address__Output)[]; + /** + * Optional :ref:`active health checking ` + * configuration for the cluster. If no + * configuration is specified no health checking will be done and all cluster + * members will be considered healthy at all times. + */ 'health_checks': (_envoy_api_v2_core_HealthCheck__Output)[]; + /** + * Optional maximum requests for a single upstream connection. This parameter + * is respected by both the HTTP/1.1 and HTTP/2 connection pool + * implementations. If not specified, there is no limit. Setting this + * parameter to 1 will effectively disable keep alive. + */ 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output); + /** + * Optional :ref:`circuit breaking ` for the cluster. + */ 'circuit_breakers': (_envoy_api_v2_cluster_CircuitBreakers__Output); + /** + * The TLS configuration for connections to the upstream cluster. + * + * .. attention:: + * + * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are + * set, `transport_socket` takes priority. + */ 'tls_context': (_envoy_api_v2_auth_UpstreamTlsContext__Output); + /** + * Additional options when handling HTTP1 requests. + */ 'http_protocol_options': (_envoy_api_v2_core_Http1ProtocolOptions__Output); + /** + * Even if default HTTP2 protocol options are desired, this field must be + * set so that Envoy will assume that the upstream supports HTTP/2 when + * making new HTTP connection pool connections. Currently, Envoy only + * supports prior knowledge for upstream connections. Even if TLS is used + * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 + * connections to happen over plain text. + */ 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); + /** + * If the DNS refresh rate is specified and the cluster type is either + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, + * this value is used as the cluster’s DNS refresh + * rate. The value configured must be at least 1ms. If this setting is not specified, the + * value defaults to 5000ms. For cluster types other than + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` + * this setting is ignored. + */ 'dns_refresh_rate': (_google_protobuf_Duration__Output); + /** + * The DNS IP address resolution policy. If this setting is not specified, the + * value defaults to + * :ref:`AUTO`. + */ 'dns_lookup_family': (keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); + /** + * If DNS resolvers are specified and the cluster type is either + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, + * this value is used to specify the cluster’s dns resolvers. + * If this setting is not specified, the value defaults to the default + * resolver, which uses /etc/resolv.conf for configuration. For cluster types + * other than + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` + * this setting is ignored. + */ 'dns_resolvers': (_envoy_api_v2_core_Address__Output)[]; + /** + * If specified, outlier detection will be enabled for this upstream cluster. + * Each of the configuration values can be overridden via + * :ref:`runtime values `. + */ 'outlier_detection': (_envoy_api_v2_cluster_OutlierDetection__Output); + /** + * The interval for removing stale hosts from a cluster type + * :ref:`ORIGINAL_DST`. + * Hosts are considered stale if they have not been used + * as upstream destinations during this interval. New hosts are added + * to original destination clusters on demand as new connections are + * redirected to Envoy, causing the number of hosts in the cluster to + * grow over time. Hosts that are not stale (they are actively used as + * destinations) are kept in the cluster, which allows connections to + * them remain open, saving the latency that would otherwise be spent + * on opening new connections. If this setting is not specified, the + * value defaults to 5000ms. For cluster types other than + * :ref:`ORIGINAL_DST` + * this setting is ignored. + */ 'cleanup_interval': (_google_protobuf_Duration__Output); + /** + * Optional configuration used to bind newly established upstream connections. + * This overrides any bind_config specified in the bootstrap proto. + * If the address and port are empty, no bind will be performed. + */ 'upstream_bind_config': (_envoy_api_v2_core_BindConfig__Output); + /** + * Configuration for load balancing subsetting. + */ 'lb_subset_config': (_envoy_api_v2_Cluster_LbSubsetConfig__Output); + /** + * Optional configuration for the Ring Hash load balancing policy. + */ 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig__Output); + /** + * Optional custom transport socket implementation to use for upstream connections. + * To setup TLS, set a transport socket with name `tls` and + * :ref:`UpstreamTlsContexts ` in the `typed_config`. + * If no transport socket configuration is specified, new connections + * will be set up with plaintext. + */ 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + /** + * The Metadata field can be used to provide additional information about the + * cluster. It can be used for stats, logging, and varying filter behavior. + * Fields should use reverse DNS notation to denote which entity within Envoy + * will need the information. For instance, if the metadata is intended for + * the Router filter, the filter name should be specified as *envoy.filters.http.router*. + */ 'metadata': (_envoy_api_v2_core_Metadata__Output); + /** + * Determines how Envoy selects the protocol used to speak to upstream hosts. + */ 'protocol_selection': (keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + /** + * Common configuration for all load balancer implementations. + */ 'common_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig__Output); + /** + * An optional alternative to the cluster name to be used while emitting stats. + * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be + * confused with :ref:`Router Filter Header + * `. + */ 'alt_stat_name': (string); + /** + * Additional options when handling HTTP requests upstream. These options will be applicable to + * both HTTP1 and HTTP2 requests. + */ 'common_http_protocol_options': (_envoy_api_v2_core_HttpProtocolOptions__Output); + /** + * Optional options for upstream connections. + */ 'upstream_connection_options': (_envoy_api_v2_UpstreamConnectionOptions__Output); + /** + * If an upstream host becomes unhealthy (as determined by the configured health checks + * or outlier detection), immediately close all connections to the failed host. + * + * .. note:: + * + * This is currently only supported for connections created by tcp_proxy. + * + * .. note:: + * + * The current implementation of this feature closes all connections immediately when + * the unhealthy status is detected. If there are a large number of connections open + * to an upstream host that becomes unhealthy, Envoy may spend a substantial amount of + * time exclusively closing these connections, and not processing any other traffic. + */ 'close_connections_on_host_health_failure': (boolean); + /** + * If set to true, Envoy will ignore the health value of a host when processing its removal + * from service discovery. This means that if active health checking is used, Envoy will *not* + * wait for the endpoint to go unhealthy before removing it. + */ 'drain_connections_on_host_removal': (boolean); + /** + * Setting this is required for specifying members of + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS` clusters. + * This field supersedes the *hosts* field in the v2 API. + * + * .. attention:: + * + * Setting this allows non-EDS cluster types to contain embedded EDS equivalent + * :ref:`endpoint assignments`. + */ 'load_assignment': (_envoy_api_v2_ClusterLoadAssignment__Output); + /** + * Optional configuration for the Original Destination load balancing policy. + */ 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig__Output); + /** + * The extension_protocol_options field is used to provide extension-specific protocol options + * for upstream connections. The key should match the extension filter name, such as + * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on + * specific options. + */ 'extension_protocol_options': (_google_protobuf_Struct__Output); + /** + * The extension_protocol_options field is used to provide extension-specific protocol options + * for upstream connections. The key should match the extension filter name, such as + * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on + * specific options. + */ 'typed_extension_protocol_options': (_google_protobuf_Any__Output); + /** + * Optional configuration for the LeastRequest load balancing policy. + */ 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig__Output); + /** + * The custom cluster type. + */ 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType__Output); + /** + * Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, + * cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS + * resolution. + */ 'respect_dns_ttl': (boolean); + /** + * An (optional) network filter chain, listed in the order the filters should be applied. + * The chain will be applied to all outgoing connections that Envoy makes to the upstream + * servers of this cluster. + */ 'filters': (_envoy_api_v2_cluster_Filter__Output)[]; + /** + * [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the + * :ref:`lb_policy` field has the value + * :ref:`LOAD_BALANCING_POLICY_CONFIG`. + */ 'load_balancing_policy': (_envoy_api_v2_LoadBalancingPolicy__Output); + /** + * [#not-implemented-hide:] + * If present, tells the client where to send load reports via LRS. If not present, the + * client will fall back to a client-side default, which may be either (a) don't send any + * load reports or (b) send load reports for all clusters to a single default server + * (which may be configured in the bootstrap file). + * + * Note that if multiple clusters point to the same LRS server, the client may choose to + * create a separate stream for each cluster or it may choose to coalesce the data for + * multiple clusters onto a single stream. Either way, the client must make sure to send + * the data for any given cluster on no more than one stream. + * + * [#next-major-version: In the v3 API, we should consider restructuring this somehow, + * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation + * from the LRS stream here.] + */ 'lrs_server': (_envoy_api_v2_core_ConfigSource__Output); + /** + * Configuration to use different transport sockets for different endpoints. + * The entry of *envoy.transport_socket_match* in the + * :ref:`LbEndpoint.Metadata ` + * is used to match against the transport sockets as they appear in the list. The first + * :ref:`match ` is used. + * For example, with the following match + * + * .. code-block:: yaml + * + * transport_socket_matches: + * - name: "enableMTLS" + * match: + * acceptMTLS: true + * transport_socket: + * name: envoy.transport_sockets.tls + * config: { ... } # tls socket configuration + * - name: "defaultToPlaintext" + * match: {} + * transport_socket: + * name: envoy.transport_sockets.raw_buffer + * + * Connections to the endpoints whose metadata value under *envoy.transport_socket_match* + * having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. + * + * If a :ref:`socket match ` with empty match + * criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" + * socket match in case above. + * + * If an endpoint metadata's value under *envoy.transport_socket_match* does not match any + * *TransportSocketMatch*, socket configuration fallbacks to use the *tls_context* or + * *transport_socket* specified in this cluster. + * + * This field allows gradual and flexible transport socket configuration changes. + * + * The metadata of endpoints in EDS can indicate transport socket capabilities. For example, + * an endpoint's metadata can have two key value pairs as "acceptMTLS": "true", + * "acceptPlaintext": "true". While some other endpoints, only accepting plaintext traffic + * has "acceptPlaintext": "true" metadata information. + * + * Then the xDS server can configure the CDS to a client, Envoy A, to send mutual TLS + * traffic for endpoints with "acceptMTLS": "true", by adding a corresponding + * *TransportSocketMatch* in this field. Other client Envoys receive CDS without + * *transport_socket_match* set, and still send plain text traffic to the same cluster. + * + * [#comment:TODO(incfly): add a detailed architecture doc on intended usage.] + */ 'transport_socket_matches': (_envoy_api_v2_Cluster_TransportSocketMatch__Output)[]; + /** + * If the DNS failure refresh rate is specified and the cluster type is either + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, + * this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is + * not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types + * other than :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS` this setting is + * ignored. + */ 'dns_failure_refresh_rate': (_envoy_api_v2_Cluster_RefreshRate__Output); + /** + * [#next-major-version: Reconcile DNS options in a single message.] + * Always use TCP queries instead of UDP queries for DNS lookups. + */ 'use_tcp_for_dns_lookups': (boolean); + /** + * HTTP protocol options that are applied only to upstream HTTP connections. + * These options apply to all HTTP versions. + */ 'upstream_http_protocol_options': (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); + /** + * If track_timeout_budgets is true, the :ref:`timeout budget histograms + * ` will be published for each + * request. These show what percentage of a request's per try and global timeout was used. A value + * of 0 would indicate that none of the timeout was used or that the timeout was infinite. A value + * of 100 would indicate that the request took the entirety of the timeout given to it. + */ 'track_timeout_budgets': (boolean); 'cluster_discovery_type': "type"|"cluster_type"; + /** + * Optional configuration for the load balancing algorithm selected by + * LbPolicy. Currently only + * :ref:`RING_HASH` and + * :ref:`LEAST_REQUEST` + * has additional configuration options. + * Specifying ring_hash_lb_config or least_request_lb_config without setting the corresponding + * LbPolicy will generate an error at runtime. + */ 'lb_config': "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts index 4f9c08bb3..0f6baa546 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts @@ -6,40 +6,230 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../envoy/type/FractionalPercent'; +/** + * Load balancing policy settings. + * [#next-free-field: 6] + */ export interface _envoy_api_v2_ClusterLoadAssignment_Policy { + /** + * Action to trim the overall incoming traffic to protect the upstream + * hosts. This action allows protection in case the hosts are unable to + * recover from an outage, or unable to autoscale or unable to handle + * incoming traffic volume for any reason. + * + * At the client each category is applied one after the other to generate + * the 'actual' drop percentage on all outgoing traffic. For example: + * + * .. code-block:: json + * + * { "drop_overloads": [ + * { "category": "throttle", "drop_percentage": 60 } + * { "category": "lb", "drop_percentage": 50 } + * ]} + * + * The actual drop percentages applied to the traffic at the clients will be + * "throttle"_drop = 60% + * "lb"_drop = 20% // 50% of the remaining 'actual' load, which is 40%. + * actual_outgoing_load = 20% // remaining after applying all categories. + * [#not-implemented-hide:] + */ 'drop_overloads'?: (_envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload)[]; + /** + * Priority levels and localities are considered overprovisioned with this + * factor (in percentage). This means that we don't consider a priority + * level or locality unhealthy until the percentage of healthy hosts + * multiplied by the overprovisioning factor drops below 100. + * With the default value 140(1.4), Envoy doesn't consider a priority level + * or a locality unhealthy until their percentage of healthy hosts drops + * below 72%. For example: + * + * .. code-block:: json + * + * { "overprovisioning_factor": 100 } + * + * Read more at :ref:`priority levels ` and + * :ref:`localities `. + */ 'overprovisioning_factor'?: (_google_protobuf_UInt32Value); + /** + * The max time until which the endpoints from this assignment can be used. + * If no new assignments are received before this time expires the endpoints + * are considered stale and should be marked unhealthy. + * Defaults to 0 which means endpoints never go stale. + */ 'endpoint_stale_after'?: (_google_protobuf_Duration); + /** + * The flag to disable overprovisioning. If it is set to true, + * :ref:`overprovisioning factor + * ` will be ignored + * and Envoy will not perform graceful failover between priority levels or + * localities as endpoints become unhealthy. Otherwise Envoy will perform + * graceful failover as :ref:`overprovisioning factor + * ` suggests. + * [#not-implemented-hide:] + */ 'disable_overprovisioning'?: (boolean); } +/** + * Load balancing policy settings. + * [#next-free-field: 6] + */ export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { + /** + * Action to trim the overall incoming traffic to protect the upstream + * hosts. This action allows protection in case the hosts are unable to + * recover from an outage, or unable to autoscale or unable to handle + * incoming traffic volume for any reason. + * + * At the client each category is applied one after the other to generate + * the 'actual' drop percentage on all outgoing traffic. For example: + * + * .. code-block:: json + * + * { "drop_overloads": [ + * { "category": "throttle", "drop_percentage": 60 } + * { "category": "lb", "drop_percentage": 50 } + * ]} + * + * The actual drop percentages applied to the traffic at the clients will be + * "throttle"_drop = 60% + * "lb"_drop = 20% // 50% of the remaining 'actual' load, which is 40%. + * actual_outgoing_load = 20% // remaining after applying all categories. + * [#not-implemented-hide:] + */ 'drop_overloads': (_envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output)[]; + /** + * Priority levels and localities are considered overprovisioned with this + * factor (in percentage). This means that we don't consider a priority + * level or locality unhealthy until the percentage of healthy hosts + * multiplied by the overprovisioning factor drops below 100. + * With the default value 140(1.4), Envoy doesn't consider a priority level + * or a locality unhealthy until their percentage of healthy hosts drops + * below 72%. For example: + * + * .. code-block:: json + * + * { "overprovisioning_factor": 100 } + * + * Read more at :ref:`priority levels ` and + * :ref:`localities `. + */ 'overprovisioning_factor': (_google_protobuf_UInt32Value__Output); + /** + * The max time until which the endpoints from this assignment can be used. + * If no new assignments are received before this time expires the endpoints + * are considered stale and should be marked unhealthy. + * Defaults to 0 which means endpoints never go stale. + */ 'endpoint_stale_after': (_google_protobuf_Duration__Output); + /** + * The flag to disable overprovisioning. If it is set to true, + * :ref:`overprovisioning factor + * ` will be ignored + * and Envoy will not perform graceful failover between priority levels or + * localities as endpoints become unhealthy. Otherwise Envoy will perform + * graceful failover as :ref:`overprovisioning factor + * ` suggests. + * [#not-implemented-hide:] + */ 'disable_overprovisioning': (boolean); } +/** + * [#not-implemented-hide:] + */ export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload { + /** + * Identifier for the policy specifying the drop. + */ 'category'?: (string); + /** + * Percentage of traffic that should be dropped for the category. + */ 'drop_percentage'?: (_envoy_type_FractionalPercent); } +/** + * [#not-implemented-hide:] + */ export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output { + /** + * Identifier for the policy specifying the drop. + */ 'category': (string); + /** + * Percentage of traffic that should be dropped for the category. + */ 'drop_percentage': (_envoy_type_FractionalPercent__Output); } +/** + * Each route from RDS will map to a single cluster or traffic split across + * clusters using weights expressed in the RDS WeightedCluster. + * + * With EDS, each cluster is treated independently from a LB perspective, with + * LB taking place between the Localities within a cluster and at a finer + * granularity between the hosts within a locality. The percentage of traffic + * for each endpoint is determined by both its load_balancing_weight, and the + * load_balancing_weight of its locality. First, a locality will be selected, + * then an endpoint within that locality will be chose based on its weight. + * [#next-free-field: 6] + */ export interface ClusterLoadAssignment { + /** + * Name of the cluster. This will be the :ref:`service_name + * ` value if specified + * in the cluster :ref:`EdsClusterConfig + * `. + */ 'cluster_name'?: (string); + /** + * List of endpoints to load balance to. + */ 'endpoints'?: (_envoy_api_v2_endpoint_LocalityLbEndpoints)[]; + /** + * Load balancing policy settings. + */ 'policy'?: (_envoy_api_v2_ClusterLoadAssignment_Policy); + /** + * Map of named endpoints that can be referenced in LocalityLbEndpoints. + * [#not-implemented-hide:] + */ 'named_endpoints'?: (_envoy_api_v2_endpoint_Endpoint); } +/** + * Each route from RDS will map to a single cluster or traffic split across + * clusters using weights expressed in the RDS WeightedCluster. + * + * With EDS, each cluster is treated independently from a LB perspective, with + * LB taking place between the Localities within a cluster and at a finer + * granularity between the hosts within a locality. The percentage of traffic + * for each endpoint is determined by both its load_balancing_weight, and the + * load_balancing_weight of its locality. First, a locality will be selected, + * then an endpoint within that locality will be chose based on its weight. + * [#next-free-field: 6] + */ export interface ClusterLoadAssignment__Output { + /** + * Name of the cluster. This will be the :ref:`service_name + * ` value if specified + * in the cluster :ref:`EdsClusterConfig + * `. + */ 'cluster_name': (string); + /** + * List of endpoints to load balance to. + */ 'endpoints': (_envoy_api_v2_endpoint_LocalityLbEndpoints__Output)[]; + /** + * Load balancing policy settings. + */ 'policy': (_envoy_api_v2_ClusterLoadAssignment_Policy__Output); + /** + * Map of named endpoints that can be referenced in LocalityLbEndpoints. + * [#not-implemented-hide:] + */ 'named_endpoints': (_envoy_api_v2_endpoint_Endpoint__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts index bd09411a8..341c9b9a4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts @@ -3,22 +3,200 @@ import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +/** + * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC + * endpoint for Delta xDS. + * + * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full + * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a + * diff to the state of a xDS client. + * In Delta XDS there are per-resource versions, which allow tracking state at + * the resource granularity. + * An xDS Delta session is always in the context of a gRPC bidirectional + * stream. This allows the xDS server to keep track of the state of xDS clients + * connected to it. + * + * In Delta xDS the nonce field is required and used to pair + * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. + * Optionally, a response message level system_version_info is present for + * debugging purposes only. + * + * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest + * can be either or both of: [1] informing the server of what resources the + * client has gained/lost interest in (using resource_names_subscribe and + * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from + * the server (using response_nonce, with presence of error_detail making it a NACK). + * Additionally, the first message (for a given type_url) of a reconnected gRPC stream + * has a third role: informing the server of the resources (and their versions) + * that the client already possesses, using the initial_resource_versions field. + * + * As with state-of-the-world, when multiple resource types are multiplexed (ADS), + * all requests/acknowledgments/updates are logically walled off by type_url: + * a Cluster ACK exists in a completely separate world from a prior Route NACK. + * In particular, initial_resource_versions being sent at the "start" of every + * gRPC stream actually entails a message for each type_url, each with its own + * initial_resource_versions. + * [#next-free-field: 8] + */ export interface DeltaDiscoveryRequest { + /** + * The node making the request. + */ 'node'?: (_envoy_api_v2_core_Node); + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". + */ 'type_url'?: (string); + /** + * DeltaDiscoveryRequests allow the client to add or remove individual + * resources to the set of tracked resources in the context of a stream. + * All resource names in the resource_names_subscribe list are added to the + * set of tracked resources and all resource names in the resource_names_unsubscribe + * list are removed from the set of tracked resources. + * + * *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or + * resource_names_unsubscribe list simply means that no resources are to be + * added or removed to the resource list. + * *Like* state-of-the-world xDS, the server must send updates for all tracked + * resources, but can also send updates for resources the client has not subscribed to. + * + * NOTE: the server must respond with all resources listed in resource_names_subscribe, + * even if it believes the client has the most recent version of them. The reason: + * the client may have dropped them, but then regained interest before it had a chance + * to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. + * + * These two fields can be set in any DeltaDiscoveryRequest, including ACKs + * and initial_resource_versions. + * + * A list of Resource names to add to the list of tracked resources. + */ 'resource_names_subscribe'?: (string)[]; + /** + * A list of Resource names to remove from the list of tracked resources. + */ 'resource_names_unsubscribe'?: (string)[]; + /** + * Informs the server of the versions of the resources the xDS client knows of, to enable the + * client to continue the same logical xDS session even in the face of gRPC stream reconnection. + * It will not be populated: [1] in the very first stream of a session, since the client will + * not yet have any resources, [2] in any message after the first in a stream (for a given + * type_url), since the server will already be correctly tracking the client's state. + * (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) + * The map's keys are names of xDS resources known to the xDS client. + * The map's values are opaque resource versions. + */ 'initial_resource_versions'?: (string); + /** + * When the DeltaDiscoveryRequest is a ACK or NACK message in response + * to a previous DeltaDiscoveryResponse, the response_nonce must be the + * nonce in the DeltaDiscoveryResponse. + * Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. + */ 'response_nonce'?: (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* + * provides the Envoy internal exception related to the failure. + */ 'error_detail'?: (_google_rpc_Status); } +/** + * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC + * endpoint for Delta xDS. + * + * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full + * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a + * diff to the state of a xDS client. + * In Delta XDS there are per-resource versions, which allow tracking state at + * the resource granularity. + * An xDS Delta session is always in the context of a gRPC bidirectional + * stream. This allows the xDS server to keep track of the state of xDS clients + * connected to it. + * + * In Delta xDS the nonce field is required and used to pair + * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. + * Optionally, a response message level system_version_info is present for + * debugging purposes only. + * + * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest + * can be either or both of: [1] informing the server of what resources the + * client has gained/lost interest in (using resource_names_subscribe and + * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from + * the server (using response_nonce, with presence of error_detail making it a NACK). + * Additionally, the first message (for a given type_url) of a reconnected gRPC stream + * has a third role: informing the server of the resources (and their versions) + * that the client already possesses, using the initial_resource_versions field. + * + * As with state-of-the-world, when multiple resource types are multiplexed (ADS), + * all requests/acknowledgments/updates are logically walled off by type_url: + * a Cluster ACK exists in a completely separate world from a prior Route NACK. + * In particular, initial_resource_versions being sent at the "start" of every + * gRPC stream actually entails a message for each type_url, each with its own + * initial_resource_versions. + * [#next-free-field: 8] + */ export interface DeltaDiscoveryRequest__Output { + /** + * The node making the request. + */ 'node': (_envoy_api_v2_core_Node__Output); + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". + */ 'type_url': (string); + /** + * DeltaDiscoveryRequests allow the client to add or remove individual + * resources to the set of tracked resources in the context of a stream. + * All resource names in the resource_names_subscribe list are added to the + * set of tracked resources and all resource names in the resource_names_unsubscribe + * list are removed from the set of tracked resources. + * + * *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or + * resource_names_unsubscribe list simply means that no resources are to be + * added or removed to the resource list. + * *Like* state-of-the-world xDS, the server must send updates for all tracked + * resources, but can also send updates for resources the client has not subscribed to. + * + * NOTE: the server must respond with all resources listed in resource_names_subscribe, + * even if it believes the client has the most recent version of them. The reason: + * the client may have dropped them, but then regained interest before it had a chance + * to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. + * + * These two fields can be set in any DeltaDiscoveryRequest, including ACKs + * and initial_resource_versions. + * + * A list of Resource names to add to the list of tracked resources. + */ 'resource_names_subscribe': (string)[]; + /** + * A list of Resource names to remove from the list of tracked resources. + */ 'resource_names_unsubscribe': (string)[]; + /** + * Informs the server of the versions of the resources the xDS client knows of, to enable the + * client to continue the same logical xDS session even in the face of gRPC stream reconnection. + * It will not be populated: [1] in the very first stream of a session, since the client will + * not yet have any resources, [2] in any message after the first in a stream (for a given + * type_url), since the server will already be correctly tracking the client's state. + * (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) + * The map's keys are names of xDS resources known to the xDS client. + * The map's values are opaque resource versions. + */ 'initial_resource_versions': (string); + /** + * When the DeltaDiscoveryRequest is a ACK or NACK message in response + * to a previous DeltaDiscoveryResponse, the response_nonce must be the + * nonce in the DeltaDiscoveryResponse. + * Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. + */ 'response_nonce': (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* + * provides the Envoy internal exception related to the failure. + */ 'error_detail': (_google_rpc_Status__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts index 53be2989e..8af4b4eb5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts @@ -2,18 +2,62 @@ import { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from '../../../envoy/api/v2/Resource'; +/** + * [#next-free-field: 7] + */ export interface DeltaDiscoveryResponse { + /** + * The version of the response data (used for debugging). + */ 'system_version_info'?: (string); + /** + * The response resources. These are typed resources, whose types must match + * the type_url field. + */ 'resources'?: (_envoy_api_v2_Resource)[]; + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the Any within 'resources' if 'resources' is non-empty. + */ 'type_url'?: (string); + /** + * The nonce provides a way for DeltaDiscoveryRequests to uniquely + * reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. + */ 'nonce'?: (string); + /** + * Resources names of resources that have be deleted and to be removed from the xDS Client. + * Removed resources for missing resources can be ignored. + */ 'removed_resources'?: (string)[]; } +/** + * [#next-free-field: 7] + */ export interface DeltaDiscoveryResponse__Output { + /** + * The version of the response data (used for debugging). + */ 'system_version_info': (string); + /** + * The response resources. These are typed resources, whose types must match + * the type_url field. + */ 'resources': (_envoy_api_v2_Resource__Output)[]; + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the Any within 'resources' if 'resources' is non-empty. + */ 'type_url': (string); + /** + * The nonce provides a way for DeltaDiscoveryRequests to uniquely + * reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. + */ 'nonce': (string); + /** + * Resources names of resources that have be deleted and to be removed from the xDS Client. + * Removed resources for missing resources can be ignored. + */ 'removed_resources': (string)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts index 33b8fcf26..43c926b74 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts @@ -3,20 +3,108 @@ import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +/** + * A DiscoveryRequest requests a set of versioned resources of the same type for + * a given Envoy node on some API. + * [#next-free-field: 7] + */ export interface DiscoveryRequest { + /** + * The version_info provided in the request messages will be the version_info + * received with the most recent successfully processed response or empty on + * the first request. It is expected that no new request is sent after a + * response is received until the Envoy instance is ready to ACK/NACK the new + * configuration. ACK/NACK takes place by returning the new API config version + * as applied or the previous API config version respectively. Each type_url + * (see below) has an independent version associated with it. + */ 'version_info'?: (string); + /** + * The node making the request. + */ 'node'?: (_envoy_api_v2_core_Node); + /** + * List of resources to subscribe to, e.g. list of cluster names or a route + * configuration name. If this is empty, all resources for the API are + * returned. LDS/CDS may have empty resource_names, which will cause all + * resources for the Envoy instance to be returned. The LDS and CDS responses + * will then imply a number of resources that need to be fetched via EDS/RDS, + * which will be explicitly enumerated in resource_names. + */ 'resource_names'?: (string)[]; + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit + * in requests made via singleton xDS APIs such as CDS, LDS, etc. but is + * required for ADS. + */ 'type_url'?: (string); + /** + * nonce corresponding to DiscoveryResponse being ACK/NACKed. See above + * discussion on version_info and the DiscoveryResponse nonce comment. This + * may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, + * or 2) the client has not yet accepted an update in this xDS stream (unlike + * delta, where it is populated only for new explicit ACKs). + */ 'response_nonce'?: (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* provides the Envoy + * internal exception related to the failure. It is only intended for consumption during manual + * debugging, the string provided is not guaranteed to be stable across Envoy versions. + */ 'error_detail'?: (_google_rpc_Status); } +/** + * A DiscoveryRequest requests a set of versioned resources of the same type for + * a given Envoy node on some API. + * [#next-free-field: 7] + */ export interface DiscoveryRequest__Output { + /** + * The version_info provided in the request messages will be the version_info + * received with the most recent successfully processed response or empty on + * the first request. It is expected that no new request is sent after a + * response is received until the Envoy instance is ready to ACK/NACK the new + * configuration. ACK/NACK takes place by returning the new API config version + * as applied or the previous API config version respectively. Each type_url + * (see below) has an independent version associated with it. + */ 'version_info': (string); + /** + * The node making the request. + */ 'node': (_envoy_api_v2_core_Node__Output); + /** + * List of resources to subscribe to, e.g. list of cluster names or a route + * configuration name. If this is empty, all resources for the API are + * returned. LDS/CDS may have empty resource_names, which will cause all + * resources for the Envoy instance to be returned. The LDS and CDS responses + * will then imply a number of resources that need to be fetched via EDS/RDS, + * which will be explicitly enumerated in resource_names. + */ 'resource_names': (string)[]; + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit + * in requests made via singleton xDS APIs such as CDS, LDS, etc. but is + * required for ADS. + */ 'type_url': (string); + /** + * nonce corresponding to DiscoveryResponse being ACK/NACKed. See above + * discussion on version_info and the DiscoveryResponse nonce comment. This + * may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, + * or 2) the client has not yet accepted an update in this xDS stream (unlike + * delta, where it is populated only for new explicit ACKs). + */ 'response_nonce': (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* provides the Envoy + * internal exception related to the failure. It is only intended for consumption during manual + * debugging, the string provided is not guaranteed to be stable across Envoy versions. + */ 'error_detail': (_google_rpc_Status__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts index 5f209372e..db6033ffa 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts @@ -3,20 +3,106 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from '../../../envoy/api/v2/core/ControlPlane'; +/** + * [#next-free-field: 7] + */ export interface DiscoveryResponse { + /** + * The version of the response data. + */ 'version_info'?: (string); + /** + * The response resources. These resources are typed and depend on the API being called. + */ 'resources'?: (_google_protobuf_Any)[]; + /** + * [#not-implemented-hide:] + * Canary is used to support two Envoy command line flags: + * + * * --terminate-on-canary-transition-failure. When set, Envoy is able to + * terminate if it detects that configuration is stuck at canary. Consider + * this example sequence of updates: + * - Management server applies a canary config successfully. + * - Management server rolls back to a production config. + * - Envoy rejects the new production config. + * Since there is no sensible way to continue receiving configuration + * updates, Envoy will then terminate and apply production config from a + * clean slate. + * * --dry-run-canary. When set, a canary response will never be applied, only + * validated via a dry run. + */ 'canary'?: (boolean); + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the 'resources' repeated Any (if non-empty). + */ 'type_url'?: (string); + /** + * For gRPC based subscriptions, the nonce provides a way to explicitly ack a + * specific DiscoveryResponse in a following DiscoveryRequest. Additional + * messages may have been sent by Envoy to the management server for the + * previous version on the stream prior to this DiscoveryResponse, that were + * unprocessed at response send time. The nonce allows the management server + * to ignore any further DiscoveryRequests for the previous version until a + * DiscoveryRequest bearing the nonce. The nonce is optional and is not + * required for non-stream based xDS implementations. + */ 'nonce'?: (string); + /** + * [#not-implemented-hide:] + * The control plane instance that sent the response. + */ 'control_plane'?: (_envoy_api_v2_core_ControlPlane); } +/** + * [#next-free-field: 7] + */ export interface DiscoveryResponse__Output { + /** + * The version of the response data. + */ 'version_info': (string); + /** + * The response resources. These resources are typed and depend on the API being called. + */ 'resources': (_google_protobuf_Any__Output)[]; + /** + * [#not-implemented-hide:] + * Canary is used to support two Envoy command line flags: + * + * * --terminate-on-canary-transition-failure. When set, Envoy is able to + * terminate if it detects that configuration is stuck at canary. Consider + * this example sequence of updates: + * - Management server applies a canary config successfully. + * - Management server rolls back to a production config. + * - Envoy rejects the new production config. + * Since there is no sensible way to continue receiving configuration + * updates, Envoy will then terminate and apply production config from a + * clean slate. + * * --dry-run-canary. When set, a canary response will never be applied, only + * validated via a dry run. + */ 'canary': (boolean); + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the 'resources' repeated Any (if non-empty). + */ 'type_url': (string); + /** + * For gRPC based subscriptions, the nonce provides a way to explicitly ack a + * specific DiscoveryResponse in a following DiscoveryRequest. Additional + * messages may have been sent by Envoy to the management server for the + * previous version on the stream prior to this DiscoveryResponse, that were + * unprocessed at response send time. The nonce allows the management server + * to ignore any further DiscoveryRequests for the previous version until a + * DiscoveryRequest bearing the nonce. The nonce is optional and is not + * required for non-stream based xDS implementations. + */ 'nonce': (string); + /** + * [#not-implemented-hide:] + * The control plane instance that sent the response. + */ 'control_plane': (_envoy_api_v2_core_ControlPlane__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts index d5a152016..befc353b9 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts @@ -13,81 +13,492 @@ import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListe import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from '../../../envoy/config/listener/v2/ApiListener'; import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../envoy/config/filter/accesslog/v2/AccessLog'; +/** + * Configuration for listener connection balancing. + */ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig { + /** + * If specified, the listener will use the exact connection balancer. + */ 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance); 'balance_type'?: "exact_balance"; } +/** + * Configuration for listener connection balancing. + */ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig__Output { + /** + * If specified, the listener will use the exact connection balancer. + */ 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output); 'balance_type': "exact_balance"; } +/** + * A connection balancer implementation that does exact balancing. This means that a lock is + * held during balancing so that connection counts are nearly exactly balanced between worker + * threads. This is "nearly" exact in the sense that a connection might close in parallel thus + * making the counts incorrect, but this should be rectified on the next accept. This balancer + * sacrifices accept throughput for accuracy and should be used when there are a small number of + * connections that rarely cycle (e.g., service mesh gRPC egress). + */ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { } +/** + * A connection balancer implementation that does exact balancing. This means that a lock is + * held during balancing so that connection counts are nearly exactly balanced between worker + * threads. This is "nearly" exact in the sense that a connection might close in parallel thus + * making the counts incorrect, but this should be rectified on the next accept. This balancer + * sacrifices accept throughput for accuracy and should be used when there are a small number of + * connections that rarely cycle (e.g., service mesh gRPC egress). + */ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output { } +/** + * [#not-implemented-hide:] + */ export interface _envoy_api_v2_Listener_DeprecatedV1 { + /** + * Whether the listener should bind to the port. A listener that doesn't + * bind can only receive connections redirected from other listeners that + * set use_original_dst parameter to true. Default is true. + * + * This is deprecated in v2, all Listeners will bind to their port. An + * additional filter chain must be created for every original destination + * port this listener may redirect to in v2, with the original port + * specified in the FilterChainMatch destination_port field. + * + * [#comment:TODO(PiotrSikora): Remove this once verified that we no longer need it.] + */ 'bind_to_port'?: (_google_protobuf_BoolValue); } +/** + * [#not-implemented-hide:] + */ export interface _envoy_api_v2_Listener_DeprecatedV1__Output { + /** + * Whether the listener should bind to the port. A listener that doesn't + * bind can only receive connections redirected from other listeners that + * set use_original_dst parameter to true. Default is true. + * + * This is deprecated in v2, all Listeners will bind to their port. An + * additional filter chain must be created for every original destination + * port this listener may redirect to in v2, with the original port + * specified in the FilterChainMatch destination_port field. + * + * [#comment:TODO(PiotrSikora): Remove this once verified that we no longer need it.] + */ 'bind_to_port': (_google_protobuf_BoolValue__Output); } // Original file: deps/envoy-api/envoy/api/v2/listener.proto export enum _envoy_api_v2_Listener_DrainType { + /** + * Drain in response to calling /healthcheck/fail admin endpoint (along with the health check + * filter), listener removal/modification, and hot restart. + */ DEFAULT = 0, + /** + * Drain in response to listener removal/modification and hot restart. This setting does not + * include /healthcheck/fail. This setting may be desirable if Envoy is hosting both ingress + * and egress listeners. + */ MODIFY_ONLY = 1, } +/** + * [#next-free-field: 23] + */ export interface Listener { + /** + * The unique name by which this listener is known. If no name is provided, + * Envoy will allocate an internal UUID for the listener. If the listener is to be dynamically + * updated or removed via :ref:`LDS ` a unique name must be provided. + */ 'name'?: (string); + /** + * The address that the listener should listen on. In general, the address must be unique, though + * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on + * Linux as the actual port will be allocated by the OS. + */ 'address'?: (_envoy_api_v2_core_Address); + /** + * A list of filter chains to consider for this listener. The + * :ref:`FilterChain ` with the most specific + * :ref:`FilterChainMatch ` criteria is used on a + * connection. + * + * Example using SNI for filter chain selection can be found in the + * :ref:`FAQ entry `. + */ 'filter_chains'?: (_envoy_api_v2_listener_FilterChain)[]; + /** + * If a connection is redirected using *iptables*, the port on which the proxy + * receives it might be different from the original destination address. When this flag is set to + * true, the listener hands off redirected connections to the listener associated with the + * original destination address. If there is no listener associated with the original destination + * address, the connection is handled by the listener that receives it. Defaults to false. + * + * .. attention:: + * + * This field is deprecated. Use :ref:`an original_dst ` + * :ref:`listener filter ` instead. + * + * Note that hand off to another listener is *NOT* performed without this flag. Once + * :ref:`FilterChainMatch ` is implemented this flag + * will be removed, as filter chain matching can be used to select a filter chain based on the + * restored destination address. + */ 'use_original_dst'?: (_google_protobuf_BoolValue); + /** + * Soft limit on size of the listener’s new connection read and write buffers. + * If unspecified, an implementation defined default is applied (1MiB). + */ 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + /** + * Listener metadata. + */ 'metadata'?: (_envoy_api_v2_core_Metadata); + /** + * [#not-implemented-hide:] + */ 'deprecated_v1'?: (_envoy_api_v2_Listener_DeprecatedV1); + /** + * The type of draining to perform at a listener-wide level. + */ 'drain_type'?: (_envoy_api_v2_Listener_DrainType | keyof typeof _envoy_api_v2_Listener_DrainType); + /** + * Listener filters have the opportunity to manipulate and augment the connection metadata that + * is used in connection filter chain matching, for example. These filters are run before any in + * :ref:`filter_chains `. Order matters as the + * filters are processed sequentially right after a socket has been accepted by the listener, and + * before a connection is created. + * UDP Listener filters can be specified when the protocol in the listener socket address in + * :ref:`protocol ` is :ref:`UDP + * `. + * UDP listeners currently support a single filter. + */ 'listener_filters'?: (_envoy_api_v2_listener_ListenerFilter)[]; + /** + * Whether the listener should be set as a transparent socket. + * When this flag is set to true, connections can be redirected to the listener using an + * *iptables* *TPROXY* target, in which case the original source and destination addresses and + * ports are preserved on accepted connections. This flag should be used in combination with + * :ref:`an original_dst ` :ref:`listener filter + * ` to mark the connections' local addresses as + * "restored." This can be used to hand off each redirected connection to another listener + * associated with the connection's destination address. Direct connections to the socket without + * using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are + * therefore treated as if they were redirected. + * When this flag is set to false, the listener's socket is explicitly reset as non-transparent. + * Setting this flag requires Envoy to run with the *CAP_NET_ADMIN* capability. + * When this flag is not set (default), the socket is not modified, i.e. the transparent option + * is neither set nor reset. + */ 'transparent'?: (_google_protobuf_BoolValue); + /** + * Whether the listener should set the *IP_FREEBIND* socket option. When this + * flag is set to true, listeners can be bound to an IP address that is not + * configured on the system running Envoy. When this flag is set to false, the + * option *IP_FREEBIND* is disabled on the socket. When this flag is not set + * (default), the socket is not modified, i.e. the option is neither enabled + * nor disabled. + */ 'freebind'?: (_google_protobuf_BoolValue); + /** + * Whether the listener should accept TCP Fast Open (TFO) connections. + * When this flag is set to a value greater than 0, the option TCP_FASTOPEN is enabled on + * the socket, with a queue length of the specified size + * (see `details in RFC7413 `_). + * When this flag is set to 0, the option TCP_FASTOPEN is disabled on the socket. + * When this flag is not set (default), the socket is not modified, + * i.e. the option is neither enabled nor disabled. + * + * On Linux, the net.ipv4.tcp_fastopen kernel parameter must include flag 0x2 to enable + * TCP_FASTOPEN. + * See `ip-sysctl.txt `_. + * + * On macOS, only values of 0, 1, and unset are valid; other values may result in an error. + * To set the queue length on macOS, set the net.inet.tcp.fastopen_backlog kernel parameter. + */ 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; + /** + * The timeout to wait for all listener filters to complete operation. If the timeout is reached, + * the accepted socket is closed without a connection being created unless + * `continue_on_listener_filters_timeout` is set to true. Specify 0 to disable the + * timeout. If not specified, a default timeout of 15s is used. + */ 'listener_filters_timeout'?: (_google_protobuf_Duration); + /** + * Specifies the intended direction of the traffic relative to the local Envoy. + */ 'traffic_direction'?: (_envoy_api_v2_core_TrafficDirection | keyof typeof _envoy_api_v2_core_TrafficDirection); + /** + * Whether a connection should be created when listener filters timeout. Default is false. + * + * .. attention:: + * + * Some listener filters, such as :ref:`Proxy Protocol filter + * `, should not be used with this option. It will cause + * unexpected behavior when a connection is created. + */ 'continue_on_listener_filters_timeout'?: (boolean); + /** + * If the protocol in the listener socket address in :ref:`protocol + * ` is :ref:`UDP + * `, this field specifies the actual udp + * listener to create, i.e. :ref:`udp_listener_name + * ` = "raw_udp_listener" for + * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". + */ 'udp_listener_config'?: (_envoy_api_v2_listener_UdpListenerConfig); + /** + * Used to represent an API listener, which is used in non-proxy clients. The type of API + * exposed to the non-proxy application depends on the type of API listener. + * When this field is set, no other field except for :ref:`name` + * should be set. + * + * .. note:: + * + * Currently only one ApiListener can be installed; and it can only be done via bootstrap config, + * not LDS. + * + * [#next-major-version: In the v3 API, instead of this messy approach where the socket + * listener fields are directly in the top-level Listener message and the API listener types + * are in the ApiListener message, the socket listener messages should be in their own message, + * and the top-level Listener should essentially be a oneof that selects between the + * socket listener and the various types of API listener. That way, a given Listener message + * can structurally only contain the fields of the relevant type.] + */ 'api_listener'?: (_envoy_config_listener_v2_ApiListener); + /** + * The listener's connection balancer configuration, currently only applicable to TCP listeners. + * If no configuration is specified, Envoy will not attempt to balance active connections between + * worker threads. + */ 'connection_balance_config'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig); + /** + * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and + * create one socket for each worker thread. This makes inbound connections + * distribute among worker threads roughly evenly in cases where there are a high number + * of connections. When this flag is set to false, all worker threads share one socket. + * + * Before Linux v4.19-rc1, new TCP connections may be rejected during hot restart + * (see `3rd paragraph in 'soreuseport' commit message + * `_). + * This issue was fixed by `tcp: Avoid TCP syncookie rejected by SO_REUSEPORT socket + * `_. + */ 'reuse_port'?: (boolean); + /** + * Configuration for :ref:`access logs ` + * emitted by this listener. + */ 'access_log'?: (_envoy_config_filter_accesslog_v2_AccessLog)[]; } +/** + * [#next-free-field: 23] + */ export interface Listener__Output { + /** + * The unique name by which this listener is known. If no name is provided, + * Envoy will allocate an internal UUID for the listener. If the listener is to be dynamically + * updated or removed via :ref:`LDS ` a unique name must be provided. + */ 'name': (string); + /** + * The address that the listener should listen on. In general, the address must be unique, though + * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on + * Linux as the actual port will be allocated by the OS. + */ 'address': (_envoy_api_v2_core_Address__Output); + /** + * A list of filter chains to consider for this listener. The + * :ref:`FilterChain ` with the most specific + * :ref:`FilterChainMatch ` criteria is used on a + * connection. + * + * Example using SNI for filter chain selection can be found in the + * :ref:`FAQ entry `. + */ 'filter_chains': (_envoy_api_v2_listener_FilterChain__Output)[]; + /** + * If a connection is redirected using *iptables*, the port on which the proxy + * receives it might be different from the original destination address. When this flag is set to + * true, the listener hands off redirected connections to the listener associated with the + * original destination address. If there is no listener associated with the original destination + * address, the connection is handled by the listener that receives it. Defaults to false. + * + * .. attention:: + * + * This field is deprecated. Use :ref:`an original_dst ` + * :ref:`listener filter ` instead. + * + * Note that hand off to another listener is *NOT* performed without this flag. Once + * :ref:`FilterChainMatch ` is implemented this flag + * will be removed, as filter chain matching can be used to select a filter chain based on the + * restored destination address. + */ 'use_original_dst': (_google_protobuf_BoolValue__Output); + /** + * Soft limit on size of the listener’s new connection read and write buffers. + * If unspecified, an implementation defined default is applied (1MiB). + */ 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + /** + * Listener metadata. + */ 'metadata': (_envoy_api_v2_core_Metadata__Output); + /** + * [#not-implemented-hide:] + */ 'deprecated_v1': (_envoy_api_v2_Listener_DeprecatedV1__Output); + /** + * The type of draining to perform at a listener-wide level. + */ 'drain_type': (keyof typeof _envoy_api_v2_Listener_DrainType); + /** + * Listener filters have the opportunity to manipulate and augment the connection metadata that + * is used in connection filter chain matching, for example. These filters are run before any in + * :ref:`filter_chains `. Order matters as the + * filters are processed sequentially right after a socket has been accepted by the listener, and + * before a connection is created. + * UDP Listener filters can be specified when the protocol in the listener socket address in + * :ref:`protocol ` is :ref:`UDP + * `. + * UDP listeners currently support a single filter. + */ 'listener_filters': (_envoy_api_v2_listener_ListenerFilter__Output)[]; + /** + * Whether the listener should be set as a transparent socket. + * When this flag is set to true, connections can be redirected to the listener using an + * *iptables* *TPROXY* target, in which case the original source and destination addresses and + * ports are preserved on accepted connections. This flag should be used in combination with + * :ref:`an original_dst ` :ref:`listener filter + * ` to mark the connections' local addresses as + * "restored." This can be used to hand off each redirected connection to another listener + * associated with the connection's destination address. Direct connections to the socket without + * using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are + * therefore treated as if they were redirected. + * When this flag is set to false, the listener's socket is explicitly reset as non-transparent. + * Setting this flag requires Envoy to run with the *CAP_NET_ADMIN* capability. + * When this flag is not set (default), the socket is not modified, i.e. the transparent option + * is neither set nor reset. + */ 'transparent': (_google_protobuf_BoolValue__Output); + /** + * Whether the listener should set the *IP_FREEBIND* socket option. When this + * flag is set to true, listeners can be bound to an IP address that is not + * configured on the system running Envoy. When this flag is set to false, the + * option *IP_FREEBIND* is disabled on the socket. When this flag is not set + * (default), the socket is not modified, i.e. the option is neither enabled + * nor disabled. + */ 'freebind': (_google_protobuf_BoolValue__Output); + /** + * Whether the listener should accept TCP Fast Open (TFO) connections. + * When this flag is set to a value greater than 0, the option TCP_FASTOPEN is enabled on + * the socket, with a queue length of the specified size + * (see `details in RFC7413 `_). + * When this flag is set to 0, the option TCP_FASTOPEN is disabled on the socket. + * When this flag is not set (default), the socket is not modified, + * i.e. the option is neither enabled nor disabled. + * + * On Linux, the net.ipv4.tcp_fastopen kernel parameter must include flag 0x2 to enable + * TCP_FASTOPEN. + * See `ip-sysctl.txt `_. + * + * On macOS, only values of 0, 1, and unset are valid; other values may result in an error. + * To set the queue length on macOS, set the net.inet.tcp.fastopen_backlog kernel parameter. + */ 'tcp_fast_open_queue_length': (_google_protobuf_UInt32Value__Output); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; + /** + * The timeout to wait for all listener filters to complete operation. If the timeout is reached, + * the accepted socket is closed without a connection being created unless + * `continue_on_listener_filters_timeout` is set to true. Specify 0 to disable the + * timeout. If not specified, a default timeout of 15s is used. + */ 'listener_filters_timeout': (_google_protobuf_Duration__Output); + /** + * Specifies the intended direction of the traffic relative to the local Envoy. + */ 'traffic_direction': (keyof typeof _envoy_api_v2_core_TrafficDirection); + /** + * Whether a connection should be created when listener filters timeout. Default is false. + * + * .. attention:: + * + * Some listener filters, such as :ref:`Proxy Protocol filter + * `, should not be used with this option. It will cause + * unexpected behavior when a connection is created. + */ 'continue_on_listener_filters_timeout': (boolean); + /** + * If the protocol in the listener socket address in :ref:`protocol + * ` is :ref:`UDP + * `, this field specifies the actual udp + * listener to create, i.e. :ref:`udp_listener_name + * ` = "raw_udp_listener" for + * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". + */ 'udp_listener_config': (_envoy_api_v2_listener_UdpListenerConfig__Output); + /** + * Used to represent an API listener, which is used in non-proxy clients. The type of API + * exposed to the non-proxy application depends on the type of API listener. + * When this field is set, no other field except for :ref:`name` + * should be set. + * + * .. note:: + * + * Currently only one ApiListener can be installed; and it can only be done via bootstrap config, + * not LDS. + * + * [#next-major-version: In the v3 API, instead of this messy approach where the socket + * listener fields are directly in the top-level Listener message and the API listener types + * are in the ApiListener message, the socket listener messages should be in their own message, + * and the top-level Listener should essentially be a oneof that selects between the + * socket listener and the various types of API listener. That way, a given Listener message + * can structurally only contain the fields of the relevant type.] + */ 'api_listener': (_envoy_config_listener_v2_ApiListener__Output); + /** + * The listener's connection balancer configuration, currently only applicable to TCP listeners. + * If no configuration is specified, Envoy will not attempt to balance active connections between + * worker threads. + */ 'connection_balance_config': (_envoy_api_v2_Listener_ConnectionBalanceConfig__Output); + /** + * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and + * create one socket for each worker thread. This makes inbound connections + * distribute among worker threads roughly evenly in cases where there are a high number + * of connections. When this flag is set to false, all worker threads share one socket. + * + * Before Linux v4.19-rc1, new TCP connections may be rejected during hot restart + * (see `3rd paragraph in 'soreuseport' commit message + * `_). + * This issue was fixed by `tcp: Avoid TCP syncookie rejected by SO_REUSEPORT socket + * `_. + */ 'reuse_port': (boolean); + /** + * Configuration for :ref:`access logs ` + * emitted by this listener. + */ 'access_log': (_envoy_config_filter_accesslog_v2_AccessLog__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts index 13af1f021..b2653ca03 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts @@ -4,21 +4,87 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; export interface _envoy_api_v2_LoadBalancingPolicy_Policy { + /** + * Required. The name of the LB policy. + */ 'name'?: (string); + /** + * Optional config for the LB policy. + * No more than one of these two fields may be populated. + */ 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); } export interface _envoy_api_v2_LoadBalancingPolicy_Policy__Output { + /** + * Required. The name of the LB policy. + */ 'name': (string); + /** + * Optional config for the LB policy. + * No more than one of these two fields may be populated. + */ 'config': (_google_protobuf_Struct__Output); 'typed_config': (_google_protobuf_Any__Output); } +/** + * [#not-implemented-hide:] Extensible load balancing policy configuration. + * + * Every LB policy defined via this mechanism will be identified via a unique name using reverse + * DNS notation. If the policy needs configuration parameters, it must define a message for its + * own configuration, which will be stored in the config field. The name of the policy will tell + * clients which type of message they should expect to see in the config field. + * + * Note that there are cases where it is useful to be able to independently select LB policies + * for choosing a locality and for choosing an endpoint within that locality. For example, a + * given deployment may always use the same policy to choose the locality, but for choosing the + * endpoint within the locality, some clusters may use weighted-round-robin, while others may + * use some sort of session-based balancing. + * + * This can be accomplished via hierarchical LB policies, where the parent LB policy creates a + * child LB policy for each locality. For each request, the parent chooses the locality and then + * delegates to the child policy for that locality to choose the endpoint within the locality. + * + * To facilitate this, the config message for the top-level LB policy may include a field of + * type LoadBalancingPolicy that specifies the child policy. + */ export interface LoadBalancingPolicy { + /** + * Each client will iterate over the list in order and stop at the first policy that it + * supports. This provides a mechanism for starting to use new LB policies that are not yet + * supported by all clients. + */ 'policies'?: (_envoy_api_v2_LoadBalancingPolicy_Policy)[]; } +/** + * [#not-implemented-hide:] Extensible load balancing policy configuration. + * + * Every LB policy defined via this mechanism will be identified via a unique name using reverse + * DNS notation. If the policy needs configuration parameters, it must define a message for its + * own configuration, which will be stored in the config field. The name of the policy will tell + * clients which type of message they should expect to see in the config field. + * + * Note that there are cases where it is useful to be able to independently select LB policies + * for choosing a locality and for choosing an endpoint within that locality. For example, a + * given deployment may always use the same policy to choose the locality, but for choosing the + * endpoint within the locality, some clusters may use weighted-round-robin, while others may + * use some sort of session-based balancing. + * + * This can be accomplished via hierarchical LB policies, where the parent LB policy creates a + * child LB policy for each locality. For each request, the parent chooses the locality and then + * delegates to the child policy for that locality to choose the endpoint within the locality. + * + * To facilitate this, the config message for the top-level LB policy may include a field of + * type LoadBalancingPolicy that specifies the child policy. + */ export interface LoadBalancingPolicy__Output { + /** + * Each client will iterate over the list in order and stop at the first policy that it + * supports. This provides a mechanism for starting to use new LB policies that are not yet + * supported by all clients. + */ 'policies': (_envoy_api_v2_LoadBalancingPolicy_Policy__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts index 965d007d0..11fb70002 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts @@ -3,15 +3,41 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; export interface Resource { + /** + * The resource level version. It allows xDS to track the state of individual + * resources. + */ 'version'?: (string); + /** + * The resource being tracked. + */ 'resource'?: (_google_protobuf_Any); + /** + * The resource's name, to distinguish it from others of the same type of resource. + */ 'name'?: (string); + /** + * The aliases are a list of other names that this resource can go by. + */ 'aliases'?: (string)[]; } export interface Resource__Output { + /** + * The resource level version. It allows xDS to track the state of individual + * resources. + */ 'version': (string); + /** + * The resource being tracked. + */ 'resource': (_google_protobuf_Any__Output); + /** + * The resource's name, to distinguish it from others of the same type of resource. + */ 'name': (string); + /** + * The aliases are a list of other names that this resource can go by. + */ 'aliases': (string)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts index 2c25c8b6f..538c15b35 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts @@ -5,28 +5,182 @@ import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueO import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; +/** + * [#next-free-field: 11] + */ export interface RouteConfiguration { + /** + * The name of the route configuration. For example, it might match + * :ref:`route_config_name + * ` in + * :ref:`envoy_api_msg_config.filter.network.http_connection_manager.v2.Rds`. + */ 'name'?: (string); + /** + * An array of virtual hosts that make up the route table. + */ 'virtual_hosts'?: (_envoy_api_v2_route_VirtualHost)[]; + /** + * Optionally specifies a list of HTTP headers that the connection manager + * will consider to be internal only. If they are found on external requests they will be cleaned + * prior to filter invocation. See :ref:`config_http_conn_man_headers_x-envoy-internal` for more + * information. + */ 'internal_only_headers'?: (string)[]; + /** + * Specifies a list of HTTP headers that should be added to each response that + * the connection manager encodes. Headers specified at this level are applied + * after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or + * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a list of HTTP headers that should be removed from each response + * that the connection manager encodes. + */ 'response_headers_to_remove'?: (string)[]; + /** + * Specifies a list of HTTP headers that should be added to each request + * routed by the HTTP connection manager. Headers specified at this level are + * applied after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or + * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * An optional boolean that specifies whether the clusters that the route + * table refers to will be validated by the cluster manager. If set to true + * and a route refers to a non-existent cluster, the route table will not + * load. If set to false and a route refers to a non-existent cluster, the + * route table will load and the router filter will return a 404 if the route + * is selected at runtime. This setting defaults to true if the route table + * is statically defined via the :ref:`route_config + * ` + * option. This setting default to false if the route table is loaded dynamically via the + * :ref:`rds + * ` + * option. Users may wish to override the default behavior in certain cases (for example when + * using CDS with a static route table). + */ 'validate_clusters'?: (_google_protobuf_BoolValue); + /** + * Specifies a list of HTTP headers that should be removed from each request + * routed by the HTTP connection manager. + */ 'request_headers_to_remove'?: (string)[]; + /** + * An array of virtual hosts will be dynamically loaded via the VHDS API. + * Both *virtual_hosts* and *vhds* fields will be used when present. *virtual_hosts* can be used + * for a base routing table or for infrequently changing virtual hosts. *vhds* is used for + * on-demand discovery of virtual hosts. The contents of these two fields will be merged to + * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration + * taking precedence. + */ 'vhds'?: (_envoy_api_v2_Vhds); + /** + * By default, headers that should be added/removed are evaluated from most to least specific: + * + * * route level + * * virtual host level + * * connection manager level + * + * To allow setting overrides at the route or virtual host level, this order can be reversed + * by setting this option to true. Defaults to false. + * + * [#next-major-version: In the v3 API, this will default to true.] + */ 'most_specific_header_mutations_wins'?: (boolean); } +/** + * [#next-free-field: 11] + */ export interface RouteConfiguration__Output { + /** + * The name of the route configuration. For example, it might match + * :ref:`route_config_name + * ` in + * :ref:`envoy_api_msg_config.filter.network.http_connection_manager.v2.Rds`. + */ 'name': (string); + /** + * An array of virtual hosts that make up the route table. + */ 'virtual_hosts': (_envoy_api_v2_route_VirtualHost__Output)[]; + /** + * Optionally specifies a list of HTTP headers that the connection manager + * will consider to be internal only. If they are found on external requests they will be cleaned + * prior to filter invocation. See :ref:`config_http_conn_man_headers_x-envoy-internal` for more + * information. + */ 'internal_only_headers': (string)[]; + /** + * Specifies a list of HTTP headers that should be added to each response that + * the connection manager encodes. Headers specified at this level are applied + * after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or + * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a list of HTTP headers that should be removed from each response + * that the connection manager encodes. + */ 'response_headers_to_remove': (string)[]; + /** + * Specifies a list of HTTP headers that should be added to each request + * routed by the HTTP connection manager. Headers specified at this level are + * applied after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or + * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * An optional boolean that specifies whether the clusters that the route + * table refers to will be validated by the cluster manager. If set to true + * and a route refers to a non-existent cluster, the route table will not + * load. If set to false and a route refers to a non-existent cluster, the + * route table will load and the router filter will return a 404 if the route + * is selected at runtime. This setting defaults to true if the route table + * is statically defined via the :ref:`route_config + * ` + * option. This setting default to false if the route table is loaded dynamically via the + * :ref:`rds + * ` + * option. Users may wish to override the default behavior in certain cases (for example when + * using CDS with a static route table). + */ 'validate_clusters': (_google_protobuf_BoolValue__Output); + /** + * Specifies a list of HTTP headers that should be removed from each request + * routed by the HTTP connection manager. + */ 'request_headers_to_remove': (string)[]; + /** + * An array of virtual hosts will be dynamically loaded via the VHDS API. + * Both *virtual_hosts* and *vhds* fields will be used when present. *virtual_hosts* can be used + * for a base routing table or for infrequently changing virtual hosts. *vhds* is used for + * on-demand discovery of virtual hosts. The contents of these two fields will be merged to + * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration + * taking precedence. + */ 'vhds': (_envoy_api_v2_Vhds__Output); + /** + * By default, headers that should be added/removed are evaluated from most to least specific: + * + * * route level + * * virtual host level + * * connection manager level + * + * To allow setting overrides at the route or virtual host level, this order can be reversed + * by setting this option to true. Defaults to false. + * + * [#next-major-version: In the v3 API, this will default to true.] + */ 'most_specific_header_mutations_wins': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts index 9c6d979c8..2b26da489 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts @@ -2,10 +2,24 @@ import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +/** + * An extensible structure containing the address Envoy should bind to when + * establishing upstream connections. + */ export interface UpstreamBindConfig { + /** + * The address Envoy should bind to when establishing upstream connections. + */ 'source_address'?: (_envoy_api_v2_core_Address); } +/** + * An extensible structure containing the address Envoy should bind to when + * establishing upstream connections. + */ export interface UpstreamBindConfig__Output { + /** + * The address Envoy should bind to when establishing upstream connections. + */ 'source_address': (_envoy_api_v2_core_Address__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts index 3dfda2164..2fc601530 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts @@ -3,9 +3,15 @@ import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from '../../../envoy/api/v2/core/TcpKeepalive'; export interface UpstreamConnectionOptions { + /** + * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. + */ 'tcp_keepalive'?: (_envoy_api_v2_core_TcpKeepalive); } export interface UpstreamConnectionOptions__Output { + /** + * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. + */ 'tcp_keepalive': (_envoy_api_v2_core_TcpKeepalive__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts index 62214f619..f30d4a721 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts @@ -3,9 +3,15 @@ import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; export interface Vhds { + /** + * Configuration source specifier for VHDS. + */ 'config_source'?: (_envoy_api_v2_core_ConfigSource); } export interface Vhds__Output { + /** + * Configuration source specifier for VHDS. + */ 'config_source': (_envoy_api_v2_core_ConfigSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts index 9aaa2a455..e45e0a4a8 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts @@ -6,33 +6,310 @@ import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Outp // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto +/** + * Peer certificate verification mode. + */ export enum _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification { + /** + * Perform default certificate verification (e.g., against CA / verification lists) + */ VERIFY_TRUST_CHAIN = 0, + /** + * Connections where the certificate fails verification will be permitted. + * For HTTP connections, the result of certificate verification can be used in route matching. ( + * see :ref:`validated ` ). + */ ACCEPT_UNTRUSTED = 1, } +/** + * [#next-free-field: 11] + */ export interface CertificateValidationContext { + /** + * TLS certificate data containing certificate authority certificates to use in verifying + * a presented peer certificate (e.g. server certificate for clusters or client certificate + * for listeners). If not specified and a peer certificate is presented it will not be + * verified. By default, a client certificate is optional, unless one of the additional + * options (:ref:`require_client_certificate + * `, + * :ref:`verify_certificate_spki + * `, + * :ref:`verify_certificate_hash + * `, or + * :ref:`match_subject_alt_names + * `) is also + * specified. + * + * It can optionally contain certificate revocation lists, in which case Envoy will verify + * that the presented peer certificate has not been revoked by one of the included CRLs. + * + * See :ref:`the TLS overview ` for a list of common + * system CA locations. + */ 'trusted_ca'?: (_envoy_api_v2_core_DataSource); + /** + * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that + * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + * + * A hex-encoded SHA-256 of the certificate can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 + * df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a + * + * A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 + * DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A + * + * Both of those formats are acceptable. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + */ 'verify_certificate_hash'?: (string)[]; + /** + * An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the + * SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate + * matches one of the specified values. + * + * A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -pubkey + * | openssl pkey -pubin -outform DER + * | openssl dgst -sha256 -binary + * | openssl enc -base64 + * NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= + * + * This is the format used in HTTP Public Key Pinning. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + * + * .. attention:: + * + * This option is preferred over :ref:`verify_certificate_hash + * `, + * because SPKI is tied to a private key, so it doesn't change when the certificate + * is renewed using the same private key. + */ 'verify_certificate_spki'?: (string)[]; + /** + * An optional list of Subject Alternative Names. If specified, Envoy will verify that the + * Subject Alternative Name of the presented certificate matches one of the specified values. + * + * .. attention:: + * + * Subject Alternative Names are easily spoofable and verifying only them is insecure, + * therefore this option must be used together with :ref:`trusted_ca + * `. + */ 'verify_subject_alt_name'?: (string)[]; + /** + * [#not-implemented-hide:] Must present a signed time-stamped OCSP response. + */ 'require_ocsp_staple'?: (_google_protobuf_BoolValue); + /** + * [#not-implemented-hide:] Must present signed certificate time-stamp. + */ 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue); + /** + * An optional `certificate revocation list + * `_ + * (in PEM format). If specified, Envoy will verify that the presented peer + * certificate has not been revoked by this CRL. If this DataSource contains + * multiple CRLs, all of them will be used. + */ 'crl'?: (_envoy_api_v2_core_DataSource); + /** + * If specified, Envoy will not reject expired certificates. + */ 'allow_expired_certificate'?: (boolean); + /** + * An optional list of Subject Alternative name matchers. Envoy will verify that the + * Subject Alternative Name of the presented certificate matches one of the specified matches. + * + * When a certificate has wildcard DNS SAN entries, to match a specific client, it should be + * configured with exact match type in the :ref:`string matcher `. + * For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com", + * it should be configured as shown below. + * + * .. code-block:: yaml + * + * match_subject_alt_names: + * exact: "api.example.com" + * + * .. attention:: + * + * Subject Alternative Names are easily spoofable and verifying only them is insecure, + * therefore this option must be used together with :ref:`trusted_ca + * `. + */ 'match_subject_alt_names'?: (_envoy_type_matcher_StringMatcher)[]; + /** + * Certificate trust chain verification mode. + */ 'trust_chain_verification'?: (_envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification | keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); } +/** + * [#next-free-field: 11] + */ export interface CertificateValidationContext__Output { + /** + * TLS certificate data containing certificate authority certificates to use in verifying + * a presented peer certificate (e.g. server certificate for clusters or client certificate + * for listeners). If not specified and a peer certificate is presented it will not be + * verified. By default, a client certificate is optional, unless one of the additional + * options (:ref:`require_client_certificate + * `, + * :ref:`verify_certificate_spki + * `, + * :ref:`verify_certificate_hash + * `, or + * :ref:`match_subject_alt_names + * `) is also + * specified. + * + * It can optionally contain certificate revocation lists, in which case Envoy will verify + * that the presented peer certificate has not been revoked by one of the included CRLs. + * + * See :ref:`the TLS overview ` for a list of common + * system CA locations. + */ 'trusted_ca': (_envoy_api_v2_core_DataSource__Output); + /** + * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that + * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + * + * A hex-encoded SHA-256 of the certificate can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 + * df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a + * + * A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 + * DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A + * + * Both of those formats are acceptable. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + */ 'verify_certificate_hash': (string)[]; + /** + * An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the + * SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate + * matches one of the specified values. + * + * A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -pubkey + * | openssl pkey -pubin -outform DER + * | openssl dgst -sha256 -binary + * | openssl enc -base64 + * NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= + * + * This is the format used in HTTP Public Key Pinning. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + * + * .. attention:: + * + * This option is preferred over :ref:`verify_certificate_hash + * `, + * because SPKI is tied to a private key, so it doesn't change when the certificate + * is renewed using the same private key. + */ 'verify_certificate_spki': (string)[]; + /** + * An optional list of Subject Alternative Names. If specified, Envoy will verify that the + * Subject Alternative Name of the presented certificate matches one of the specified values. + * + * .. attention:: + * + * Subject Alternative Names are easily spoofable and verifying only them is insecure, + * therefore this option must be used together with :ref:`trusted_ca + * `. + */ 'verify_subject_alt_name': (string)[]; + /** + * [#not-implemented-hide:] Must present a signed time-stamped OCSP response. + */ 'require_ocsp_staple': (_google_protobuf_BoolValue__Output); + /** + * [#not-implemented-hide:] Must present signed certificate time-stamp. + */ 'require_signed_certificate_timestamp': (_google_protobuf_BoolValue__Output); + /** + * An optional `certificate revocation list + * `_ + * (in PEM format). If specified, Envoy will verify that the presented peer + * certificate has not been revoked by this CRL. If this DataSource contains + * multiple CRLs, all of them will be used. + */ 'crl': (_envoy_api_v2_core_DataSource__Output); + /** + * If specified, Envoy will not reject expired certificates. + */ 'allow_expired_certificate': (boolean); + /** + * An optional list of Subject Alternative name matchers. Envoy will verify that the + * Subject Alternative Name of the presented certificate matches one of the specified matches. + * + * When a certificate has wildcard DNS SAN entries, to match a specific client, it should be + * configured with exact match type in the :ref:`string matcher `. + * For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com", + * it should be configured as shown below. + * + * .. code-block:: yaml + * + * match_subject_alt_names: + * exact: "api.example.com" + * + * .. attention:: + * + * Subject Alternative Names are easily spoofable and verifying only them is insecure, + * therefore this option must be used together with :ref:`trusted_ca + * `. + */ 'match_subject_alt_names': (_envoy_type_matcher_StringMatcher__Output)[]; + /** + * Certificate trust chain verification mode. + */ 'trust_chain_verification': (keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts index aa2db06f6..b75f3f533 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts @@ -6,33 +6,135 @@ import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidatio import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext { + /** + * How to validate peer certificates. + */ 'default_validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); + /** + * Config for fetching validation context via SDS API. + */ 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); } export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output { + /** + * How to validate peer certificates. + */ 'default_validation_context': (_envoy_api_v2_auth_CertificateValidationContext__Output); + /** + * Config for fetching validation context via SDS API. + */ 'validation_context_sds_secret_config': (_envoy_api_v2_auth_SdsSecretConfig__Output); } +/** + * TLS context shared by both client and server TLS contexts. + * [#next-free-field: 9] + */ export interface CommonTlsContext { + /** + * TLS protocol versions, cipher suites etc. + */ 'tls_params'?: (_envoy_api_v2_auth_TlsParameters); + /** + * :ref:`Multiple TLS certificates ` can be associated with the + * same context to allow both RSA and ECDSA certificates. + * + * Only a single TLS certificate is supported in client contexts. In server contexts, the first + * RSA certificate is used for clients that only support RSA and the first ECDSA certificate is + * used for clients that support ECDSA. + */ 'tls_certificates'?: (_envoy_api_v2_auth_TlsCertificate)[]; + /** + * How to validate peer certificates. + */ 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); + /** + * Supplies the list of ALPN protocols that the listener should expose. In + * practice this is likely to be set to one of two values (see the + * :ref:`codec_type + * ` + * parameter in the HTTP connection manager for more information): + * + * * "h2,http/1.1" If the listener is going to support both HTTP/2 and HTTP/1.1. + * * "http/1.1" If the listener is only going to support HTTP/1.1. + * + * There is no default for this parameter. If empty, Envoy will not expose ALPN. + */ 'alpn_protocols'?: (string)[]; + /** + * Configs for fetching TLS certificates via SDS API. + */ 'tls_certificate_sds_secret_configs'?: (_envoy_api_v2_auth_SdsSecretConfig)[]; + /** + * Config for fetching validation context via SDS API. + */ 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); + /** + * Combined certificate validation context holds a default CertificateValidationContext + * and SDS config. When SDS server returns dynamic CertificateValidationContext, both dynamic + * and default CertificateValidationContext are merged into a new CertificateValidationContext + * for validation. This merge is done by Message::MergeFrom(), so dynamic + * CertificateValidationContext overwrites singular fields in default + * CertificateValidationContext, and concatenates repeated fields to default + * CertificateValidationContext, and logical OR is applied to boolean fields. + */ 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext); 'validation_context_type'?: "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; } +/** + * TLS context shared by both client and server TLS contexts. + * [#next-free-field: 9] + */ export interface CommonTlsContext__Output { + /** + * TLS protocol versions, cipher suites etc. + */ 'tls_params': (_envoy_api_v2_auth_TlsParameters__Output); + /** + * :ref:`Multiple TLS certificates ` can be associated with the + * same context to allow both RSA and ECDSA certificates. + * + * Only a single TLS certificate is supported in client contexts. In server contexts, the first + * RSA certificate is used for clients that only support RSA and the first ECDSA certificate is + * used for clients that support ECDSA. + */ 'tls_certificates': (_envoy_api_v2_auth_TlsCertificate__Output)[]; + /** + * How to validate peer certificates. + */ 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); + /** + * Supplies the list of ALPN protocols that the listener should expose. In + * practice this is likely to be set to one of two values (see the + * :ref:`codec_type + * ` + * parameter in the HTTP connection manager for more information): + * + * * "h2,http/1.1" If the listener is going to support both HTTP/2 and HTTP/1.1. + * * "http/1.1" If the listener is only going to support HTTP/1.1. + * + * There is no default for this parameter. If empty, Envoy will not expose ALPN. + */ 'alpn_protocols': (string)[]; + /** + * Configs for fetching TLS certificates via SDS API. + */ 'tls_certificate_sds_secret_configs': (_envoy_api_v2_auth_SdsSecretConfig__Output)[]; + /** + * Config for fetching validation context via SDS API. + */ 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); + /** + * Combined certificate validation context holds a default CertificateValidationContext + * and SDS config. When SDS server returns dynamic CertificateValidationContext, both dynamic + * and default CertificateValidationContext are merged into a new CertificateValidationContext + * for validation. This merge is done by Message::MergeFrom(), so dynamic + * CertificateValidationContext overwrites singular fields in default + * CertificateValidationContext, and concatenates repeated fields to default + * CertificateValidationContext, and logical OR is applied to boolean fields. + */ 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output); 'validation_context_type': "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts index fa731c9c2..faf26f180 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts @@ -6,24 +6,96 @@ import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSes import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +/** + * [#next-free-field: 8] + */ export interface DownstreamTlsContext { + /** + * Common TLS context settings. + */ 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext); + /** + * If specified, Envoy will reject connections without a valid client + * certificate. + */ 'require_client_certificate'?: (_google_protobuf_BoolValue); + /** + * If specified, Envoy will reject connections without a valid and matching SNI. + * [#not-implemented-hide:] + */ 'require_sni'?: (_google_protobuf_BoolValue); + /** + * TLS session ticket key settings. + */ 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); + /** + * Config for fetching TLS session ticket keys via SDS API. + */ 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); + /** + * If specified, session_timeout will change maximum lifetime (in seconds) of TLS session + * Currently this value is used as a hint to `TLS session ticket lifetime (for TLSv1.2) + * ` + * only seconds could be specified (fractional seconds are going to be ignored). + */ 'session_timeout'?: (_google_protobuf_Duration); + /** + * Config for controlling stateless TLS session resumption: setting this to true will cause the TLS + * server to not issue TLS session tickets for the purposes of stateless TLS session resumption. + * If set to false, the TLS server will issue TLS session tickets and encrypt/decrypt them using + * the keys specified through either :ref:`session_ticket_keys ` + * or :ref:`session_ticket_keys_sds_secret_config `. + * If this config is set to false and no keys are explicitly configured, the TLS server will issue + * TLS session tickets and encrypt/decrypt them using an internally-generated and managed key, with the + * implication that sessions cannot be resumed across hot restarts or on different hosts. + */ 'disable_stateless_session_resumption'?: (boolean); 'session_ticket_keys_type'?: "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; } +/** + * [#next-free-field: 8] + */ export interface DownstreamTlsContext__Output { + /** + * Common TLS context settings. + */ 'common_tls_context': (_envoy_api_v2_auth_CommonTlsContext__Output); + /** + * If specified, Envoy will reject connections without a valid client + * certificate. + */ 'require_client_certificate': (_google_protobuf_BoolValue__Output); + /** + * If specified, Envoy will reject connections without a valid and matching SNI. + * [#not-implemented-hide:] + */ 'require_sni': (_google_protobuf_BoolValue__Output); + /** + * TLS session ticket key settings. + */ 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); + /** + * Config for fetching TLS session ticket keys via SDS API. + */ 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); + /** + * If specified, session_timeout will change maximum lifetime (in seconds) of TLS session + * Currently this value is used as a hint to `TLS session ticket lifetime (for TLSv1.2) + * ` + * only seconds could be specified (fractional seconds are going to be ignored). + */ 'session_timeout': (_google_protobuf_Duration__Output); + /** + * Config for controlling stateless TLS session resumption: setting this to true will cause the TLS + * server to not issue TLS session tickets for the purposes of stateless TLS session resumption. + * If set to false, the TLS server will issue TLS session tickets and encrypt/decrypt them using + * the keys specified through either :ref:`session_ticket_keys ` + * or :ref:`session_ticket_keys_sds_secret_config `. + * If this config is set to false and no keys are explicitly configured, the TLS server will issue + * TLS session tickets and encrypt/decrypt them using an internally-generated and managed key, with the + * implication that sessions cannot be resumed across hot restarts or on different hosts. + */ 'disable_stateless_session_resumption'?: (boolean); 'session_ticket_keys_type': "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts index 5eeaffa2c..761009282 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts @@ -3,9 +3,15 @@ import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; export interface GenericSecret { + /** + * Secret of generic type and is available to filters. + */ 'secret'?: (_envoy_api_v2_core_DataSource); } export interface GenericSecret__Output { + /** + * Secret of generic type and is available to filters. + */ 'secret': (_envoy_api_v2_core_DataSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts index fe418a390..3726e5434 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts @@ -3,16 +3,40 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +/** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ export interface PrivateKeyProvider { + /** + * Private key method provider name. The name must match a + * supported private key method provider type. + */ 'provider_name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Private key method provider specific configuration. + */ 'config_type'?: "config"|"typed_config"; } +/** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ export interface PrivateKeyProvider__Output { + /** + * Private key method provider name. The name must match a + * supported private key method provider type. + */ 'provider_name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Private key method provider specific configuration. + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts index acd9154cc..bcddbaf09 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts @@ -3,11 +3,21 @@ import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../envoy/api/v2/core/ConfigSource'; export interface SdsSecretConfig { + /** + * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + * When both name and config are specified, then secret can be fetched and/or reloaded via + * SDS. When only name is specified, then secret will be loaded from static resources. + */ 'name'?: (string); 'sds_config'?: (_envoy_api_v2_core_ConfigSource); } export interface SdsSecretConfig__Output { + /** + * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + * When both name and config are specified, then secret can be fetched and/or reloaded via + * SDS. When only name is specified, then secret will be loaded from static resources. + */ 'name': (string); 'sds_config': (_envoy_api_v2_core_ConfigSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts index a25e6c7c1..086f7648e 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts @@ -5,7 +5,13 @@ import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSes import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from '../../../../envoy/api/v2/auth/GenericSecret'; +/** + * [#next-free-field: 6] + */ export interface Secret { + /** + * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + */ 'name'?: (string); 'tls_certificate'?: (_envoy_api_v2_auth_TlsCertificate); 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); @@ -14,7 +20,13 @@ export interface Secret { 'type'?: "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; } +/** + * [#next-free-field: 6] + */ export interface Secret__Output { + /** + * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + */ 'name': (string); 'tls_certificate'?: (_envoy_api_v2_auth_TlsCertificate__Output); 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts index 9346e94d6..243789b23 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts @@ -3,20 +3,76 @@ import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from '../../../../envoy/api/v2/auth/PrivateKeyProvider'; +/** + * [#next-free-field: 7] + */ export interface TlsCertificate { + /** + * The TLS certificate chain. + */ 'certificate_chain'?: (_envoy_api_v2_core_DataSource); + /** + * The TLS private key. + */ 'private_key'?: (_envoy_api_v2_core_DataSource); + /** + * The password to decrypt the TLS private key. If this field is not set, it is assumed that the + * TLS private key is not password encrypted. + */ 'password'?: (_envoy_api_v2_core_DataSource); + /** + * [#not-implemented-hide:] + */ 'ocsp_staple'?: (_envoy_api_v2_core_DataSource); + /** + * [#not-implemented-hide:] + */ 'signed_certificate_timestamp'?: (_envoy_api_v2_core_DataSource)[]; + /** + * BoringSSL private key method provider. This is an alternative to :ref:`private_key + * ` field. This can't be + * marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key + * ` and + * :ref:`private_key_provider + * ` fields will result in an + * error. + */ 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider); } +/** + * [#next-free-field: 7] + */ export interface TlsCertificate__Output { + /** + * The TLS certificate chain. + */ 'certificate_chain': (_envoy_api_v2_core_DataSource__Output); + /** + * The TLS private key. + */ 'private_key': (_envoy_api_v2_core_DataSource__Output); + /** + * The password to decrypt the TLS private key. If this field is not set, it is assumed that the + * TLS private key is not password encrypted. + */ 'password': (_envoy_api_v2_core_DataSource__Output); + /** + * [#not-implemented-hide:] + */ 'ocsp_staple': (_envoy_api_v2_core_DataSource__Output); + /** + * [#not-implemented-hide:] + */ 'signed_certificate_timestamp': (_envoy_api_v2_core_DataSource__Output)[]; + /** + * BoringSSL private key method provider. This is an alternative to :ref:`private_key + * ` field. This can't be + * marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key + * ` and + * :ref:`private_key_provider + * ` fields will result in an + * error. + */ 'private_key_provider': (_envoy_api_v2_auth_PrivateKeyProvider__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts index efa26951a..29fe8f4c8 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts @@ -4,23 +4,168 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto export enum _envoy_api_v2_auth_TlsParameters_TlsProtocol { + /** + * Envoy will choose the optimal TLS version. + */ TLS_AUTO = 0, + /** + * TLS 1.0 + */ TLSv1_0 = 1, + /** + * TLS 1.1 + */ TLSv1_1 = 2, + /** + * TLS 1.2 + */ TLSv1_2 = 3, + /** + * TLS 1.3 + */ TLSv1_3 = 4, } export interface TlsParameters { + /** + * Minimum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_0`` for + * servers. + */ 'tls_minimum_protocol_version'?: (_envoy_api_v2_auth_TlsParameters_TlsProtocol | keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + /** + * Maximum TLS protocol version. By default, it's ``TLSv1_3`` for servers in non-FIPS builds, and + * ``TLSv1_2`` for clients and for servers using :ref:`BoringSSL FIPS `. + */ 'tls_maximum_protocol_version'?: (_envoy_api_v2_auth_TlsParameters_TlsProtocol | keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + /** + * If specified, the TLS listener will only support the specified `cipher list + * `_ + * when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). If not + * specified, the default list will be used. + * + * In non-FIPS builds, the default cipher list is: + * + * .. code-block:: none + * + * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + * + * In builds using :ref:`BoringSSL FIPS `, the default cipher list is: + * + * .. code-block:: none + * + * ECDHE-ECDSA-AES128-GCM-SHA256 + * ECDHE-RSA-AES128-GCM-SHA256 + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + */ 'cipher_suites'?: (string)[]; + /** + * If specified, the TLS connection will only support the specified ECDH + * curves. If not specified, the default curves will be used. + * + * In non-FIPS builds, the default curves are: + * + * .. code-block:: none + * + * X25519 + * P-256 + * + * In builds using :ref:`BoringSSL FIPS `, the default curve is: + * + * .. code-block:: none + * + * P-256 + */ 'ecdh_curves'?: (string)[]; } export interface TlsParameters__Output { + /** + * Minimum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_0`` for + * servers. + */ 'tls_minimum_protocol_version': (keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + /** + * Maximum TLS protocol version. By default, it's ``TLSv1_3`` for servers in non-FIPS builds, and + * ``TLSv1_2`` for clients and for servers using :ref:`BoringSSL FIPS `. + */ 'tls_maximum_protocol_version': (keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); + /** + * If specified, the TLS listener will only support the specified `cipher list + * `_ + * when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). If not + * specified, the default list will be used. + * + * In non-FIPS builds, the default cipher list is: + * + * .. code-block:: none + * + * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + * + * In builds using :ref:`BoringSSL FIPS `, the default cipher list is: + * + * .. code-block:: none + * + * ECDHE-ECDSA-AES128-GCM-SHA256 + * ECDHE-RSA-AES128-GCM-SHA256 + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + */ 'cipher_suites': (string)[]; + /** + * If specified, the TLS connection will only support the specified ECDH + * curves. If not specified, the default curves will be used. + * + * In non-FIPS builds, the default curves are: + * + * .. code-block:: none + * + * X25519 + * P-256 + * + * In builds using :ref:`BoringSSL FIPS `, the default curve is: + * + * .. code-block:: none + * + * P-256 + */ 'ecdh_curves': (string)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts index c9b27d26c..80a79fa08 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts @@ -3,9 +3,59 @@ import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; export interface TlsSessionTicketKeys { + /** + * Keys for encrypting and decrypting TLS session tickets. The + * first key in the array contains the key to encrypt all new sessions created by this context. + * All keys are candidates for decrypting received tickets. This allows for easy rotation of keys + * by, for example, putting the new key first, and the previous key second. + * + * If :ref:`session_ticket_keys ` + * is not specified, the TLS library will still support resuming sessions via tickets, but it will + * use an internally-generated and managed key, so sessions cannot be resumed across hot restarts + * or on different hosts. + * + * Each key must contain exactly 80 bytes of cryptographically-secure random data. For + * example, the output of ``openssl rand 80``. + * + * .. attention:: + * + * Using this feature has serious security considerations and risks. Improper handling of keys + * may result in loss of secrecy in connections, even if ciphers supporting perfect forward + * secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some + * discussion. To minimize the risk, you must: + * + * * Keep the session ticket keys at least as secure as your TLS certificate private keys + * * Rotate session ticket keys at least daily, and preferably hourly + * * Always generate keys using a cryptographically-secure random data source + */ 'keys'?: (_envoy_api_v2_core_DataSource)[]; } export interface TlsSessionTicketKeys__Output { + /** + * Keys for encrypting and decrypting TLS session tickets. The + * first key in the array contains the key to encrypt all new sessions created by this context. + * All keys are candidates for decrypting received tickets. This allows for easy rotation of keys + * by, for example, putting the new key first, and the previous key second. + * + * If :ref:`session_ticket_keys ` + * is not specified, the TLS library will still support resuming sessions via tickets, but it will + * use an internally-generated and managed key, so sessions cannot be resumed across hot restarts + * or on different hosts. + * + * Each key must contain exactly 80 bytes of cryptographically-secure random data. For + * example, the output of ``openssl rand 80``. + * + * .. attention:: + * + * Using this feature has serious security considerations and risks. Improper handling of keys + * may result in loss of secrecy in connections, even if ciphers supporting perfect forward + * secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some + * discussion. To minimize the risk, you must: + * + * * Keep the session ticket keys at least as secure as your TLS certificate private keys + * * Rotate session ticket keys at least daily, and preferably hourly + * * Always generate keys using a cryptographically-secure random data source + */ 'keys': (_envoy_api_v2_core_DataSource__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts index e05f82569..78c7eaaa2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts @@ -4,15 +4,65 @@ import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsConte import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; export interface UpstreamTlsContext { + /** + * Common TLS context settings. + * + * .. attention:: + * + * Server certificate verification is not enabled by default. Configure + * :ref:`trusted_ca` to enable + * verification. + */ 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext); + /** + * SNI string to use when creating TLS backend connections. + */ 'sni'?: (string); + /** + * If true, server-initiated TLS renegotiation will be allowed. + * + * .. attention:: + * + * TLS renegotiation is considered insecure and shouldn't be used unless absolutely necessary. + */ 'allow_renegotiation'?: (boolean); + /** + * Maximum number of session keys (Pre-Shared Keys for TLSv1.3+, Session IDs and Session Tickets + * for TLSv1.2 and older) to store for the purpose of session resumption. + * + * Defaults to 1, setting this to 0 disables session resumption. + */ 'max_session_keys'?: (_google_protobuf_UInt32Value); } export interface UpstreamTlsContext__Output { + /** + * Common TLS context settings. + * + * .. attention:: + * + * Server certificate verification is not enabled by default. Configure + * :ref:`trusted_ca` to enable + * verification. + */ 'common_tls_context': (_envoy_api_v2_auth_CommonTlsContext__Output); + /** + * SNI string to use when creating TLS backend connections. + */ 'sni': (string); + /** + * If true, server-initiated TLS renegotiation will be allowed. + * + * .. attention:: + * + * TLS renegotiation is considered insecure and shouldn't be used unless absolutely necessary. + */ 'allow_renegotiation': (boolean); + /** + * Maximum number of session keys (Pre-Shared Keys for TLSv1.3+, Session IDs and Session Tickets + * for TLSv1.2 and older) to store for the purpose of session resumption. + * + * Defaults to 1, setting this to 0 disables session resumption. + */ 'max_session_keys': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts index d41112c85..f5addf5f2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts @@ -4,42 +4,192 @@ import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../envoy/type/Percent'; +/** + * A Thresholds defines CircuitBreaker settings for a + * :ref:`RoutingPriority`. + * [#next-free-field: 9] + */ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds { + /** + * The :ref:`RoutingPriority` + * the specified CircuitBreaker settings apply to. + */ 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); + /** + * The maximum number of connections that Envoy will make to the upstream + * cluster. If not specified, the default is 1024. + */ 'max_connections'?: (_google_protobuf_UInt32Value); + /** + * The maximum number of pending requests that Envoy will allow to the + * upstream cluster. If not specified, the default is 1024. + */ 'max_pending_requests'?: (_google_protobuf_UInt32Value); + /** + * The maximum number of parallel requests that Envoy will make to the + * upstream cluster. If not specified, the default is 1024. + */ 'max_requests'?: (_google_protobuf_UInt32Value); + /** + * The maximum number of parallel retries that Envoy will allow to the + * upstream cluster. If not specified, the default is 3. + */ 'max_retries'?: (_google_protobuf_UInt32Value); + /** + * Specifies a limit on concurrent retries in relation to the number of active requests. This + * parameter is optional. + * + * .. note:: + * + * If this field is set, the retry budget will override any configured retry circuit + * breaker. + */ 'retry_budget'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget); + /** + * If track_remaining is true, then stats will be published that expose + * the number of resources remaining until the circuit breakers open. If + * not specified, the default is false. + * + * .. note:: + * + * If a retry budget is used in lieu of the max_retries circuit breaker, + * the remaining retry resources remaining will not be tracked. + */ 'track_remaining'?: (boolean); + /** + * The maximum number of connection pools per cluster that Envoy will concurrently support at + * once. If not specified, the default is unlimited. Set this for clusters which create a + * large number of connection pools. See + * :ref:`Circuit Breaking ` for + * more details. + */ 'max_connection_pools'?: (_google_protobuf_UInt32Value); } +/** + * A Thresholds defines CircuitBreaker settings for a + * :ref:`RoutingPriority`. + * [#next-free-field: 9] + */ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { + /** + * The :ref:`RoutingPriority` + * the specified CircuitBreaker settings apply to. + */ 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); + /** + * The maximum number of connections that Envoy will make to the upstream + * cluster. If not specified, the default is 1024. + */ 'max_connections': (_google_protobuf_UInt32Value__Output); + /** + * The maximum number of pending requests that Envoy will allow to the + * upstream cluster. If not specified, the default is 1024. + */ 'max_pending_requests': (_google_protobuf_UInt32Value__Output); + /** + * The maximum number of parallel requests that Envoy will make to the + * upstream cluster. If not specified, the default is 1024. + */ 'max_requests': (_google_protobuf_UInt32Value__Output); + /** + * The maximum number of parallel retries that Envoy will allow to the + * upstream cluster. If not specified, the default is 3. + */ 'max_retries': (_google_protobuf_UInt32Value__Output); + /** + * Specifies a limit on concurrent retries in relation to the number of active requests. This + * parameter is optional. + * + * .. note:: + * + * If this field is set, the retry budget will override any configured retry circuit + * breaker. + */ 'retry_budget': (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output); + /** + * If track_remaining is true, then stats will be published that expose + * the number of resources remaining until the circuit breakers open. If + * not specified, the default is false. + * + * .. note:: + * + * If a retry budget is used in lieu of the max_retries circuit breaker, + * the remaining retry resources remaining will not be tracked. + */ 'track_remaining': (boolean); + /** + * The maximum number of connection pools per cluster that Envoy will concurrently support at + * once. If not specified, the default is unlimited. Set this for clusters which create a + * large number of connection pools. See + * :ref:`Circuit Breaking ` for + * more details. + */ 'max_connection_pools': (_google_protobuf_UInt32Value__Output); } export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { + /** + * Specifies the limit on concurrent retries as a percentage of the sum of active requests and + * active pending requests. For example, if there are 100 active requests and the + * budget_percent is set to 25, there may be 25 active retries. + * + * This parameter is optional. Defaults to 20%. + */ 'budget_percent'?: (_envoy_type_Percent); + /** + * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the + * number of active retries may never go below this number. + * + * This parameter is optional. Defaults to 3. + */ 'min_retry_concurrency'?: (_google_protobuf_UInt32Value); } export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output { + /** + * Specifies the limit on concurrent retries as a percentage of the sum of active requests and + * active pending requests. For example, if there are 100 active requests and the + * budget_percent is set to 25, there may be 25 active retries. + * + * This parameter is optional. Defaults to 20%. + */ 'budget_percent': (_envoy_type_Percent__Output); + /** + * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the + * number of active retries may never go below this number. + * + * This parameter is optional. Defaults to 3. + */ 'min_retry_concurrency': (_google_protobuf_UInt32Value__Output); } +/** + * :ref:`Circuit breaking` settings can be + * specified individually for each defined priority. + */ export interface CircuitBreakers { + /** + * If multiple :ref:`Thresholds` + * are defined with the same :ref:`RoutingPriority`, + * the first one in the list is used. If no Thresholds is defined for a given + * :ref:`RoutingPriority`, the default values + * are used. + */ 'thresholds'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds)[]; } +/** + * :ref:`Circuit breaking` settings can be + * specified individually for each defined priority. + */ export interface CircuitBreakers__Output { + /** + * If multiple :ref:`Thresholds` + * are defined with the same :ref:`RoutingPriority`, + * the first one in the list is used. If no Thresholds is defined for a given + * :ref:`RoutingPriority`, the default values + * are used. + */ 'thresholds': (_envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts index e483c07d9..9e54a595e 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts @@ -3,11 +3,27 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface Filter { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ 'name'?: (string); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + */ 'typed_config'?: (_google_protobuf_Any); } export interface Filter__Output { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ 'name': (string); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + */ 'typed_config': (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts index 278e22aea..6cd429c12 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts @@ -3,48 +3,298 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +/** + * See the :ref:`architecture overview ` for + * more information on outlier detection. + * [#next-free-field: 21] + */ export interface OutlierDetection { + /** + * The number of consecutive 5xx responses or local origin errors that are mapped + * to 5xx error codes before a consecutive 5xx ejection + * occurs. Defaults to 5. + */ 'consecutive_5xx'?: (_google_protobuf_UInt32Value); + /** + * The time interval between ejection analysis sweeps. This can result in + * both new ejections as well as hosts being returned to service. Defaults + * to 10000ms or 10s. + */ 'interval'?: (_google_protobuf_Duration); + /** + * The base time that a host is ejected for. The real time is equal to the + * base time multiplied by the number of times the host has been ejected. + * Defaults to 30000ms or 30s. + */ 'base_ejection_time'?: (_google_protobuf_Duration); + /** + * The maximum % of an upstream cluster that can be ejected due to outlier + * detection. Defaults to 10% but will eject at least one host regardless of the value. + */ 'max_ejection_percent'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through consecutive 5xx. This setting can be used to disable + * ejection or to ramp it up slowly. Defaults to 100. + */ 'enforcing_consecutive_5xx'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through success rate statistics. This setting can be used to + * disable ejection or to ramp it up slowly. Defaults to 100. + */ 'enforcing_success_rate'?: (_google_protobuf_UInt32Value); + /** + * The number of hosts in a cluster that must have enough request volume to + * detect success rate outliers. If the number of hosts is less than this + * setting, outlier detection via success rate statistics is not performed + * for any host in the cluster. Defaults to 5. + */ 'success_rate_minimum_hosts'?: (_google_protobuf_UInt32Value); + /** + * The minimum number of total requests that must be collected in one + * interval (as defined by the interval duration above) to include this host + * in success rate based outlier detection. If the volume is lower than this + * setting, outlier detection via success rate statistics is not performed + * for that host. Defaults to 100. + */ 'success_rate_request_volume'?: (_google_protobuf_UInt32Value); + /** + * This factor is used to determine the ejection threshold for success rate + * outlier ejection. The ejection threshold is the difference between the + * mean success rate, and the product of this factor and the standard + * deviation of the mean success rate: mean - (stdev * + * success_rate_stdev_factor). This factor is divided by a thousand to get a + * double. That is, if the desired factor is 1.9, the runtime value should + * be 1900. Defaults to 1900. + */ 'success_rate_stdev_factor'?: (_google_protobuf_UInt32Value); + /** + * The number of consecutive gateway failures (502, 503, 504 status codes) + * before a consecutive gateway failure ejection occurs. Defaults to 5. + */ 'consecutive_gateway_failure'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through consecutive gateway failures. This setting can be + * used to disable ejection or to ramp it up slowly. Defaults to 0. + */ 'enforcing_consecutive_gateway_failure'?: (_google_protobuf_UInt32Value); + /** + * Determines whether to distinguish local origin failures from external errors. If set to true + * the following configuration parameters are taken into account: + * :ref:`consecutive_local_origin_failure`, + * :ref:`enforcing_consecutive_local_origin_failure` + * and + * :ref:`enforcing_local_origin_success_rate`. + * Defaults to false. + */ 'split_external_local_origin_errors'?: (boolean); + /** + * The number of consecutive locally originated failures before ejection + * occurs. Defaults to 5. Parameter takes effect only when + * :ref:`split_external_local_origin_errors` + * is set to true. + */ 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through consecutive locally originated failures. This setting can be + * used to disable ejection or to ramp it up slowly. Defaults to 100. + * Parameter takes effect only when + * :ref:`split_external_local_origin_errors` + * is set to true. + */ 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through success rate statistics for locally originated errors. + * This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. + * Parameter takes effect only when + * :ref:`split_external_local_origin_errors` + * is set to true. + */ 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value); + /** + * The failure percentage to use when determining failure percentage-based outlier detection. If + * the failure percentage of a given host is greater than or equal to this value, it will be + * ejected. Defaults to 85. + */ 'failure_percentage_threshold'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status is detected through + * failure percentage statistics. This setting can be used to disable ejection or to ramp it up + * slowly. Defaults to 0. + * + * [#next-major-version: setting this without setting failure_percentage_threshold should be + * invalid in v4.] + */ 'enforcing_failure_percentage'?: (_google_protobuf_UInt32Value); + /** + * The % chance that a host will be actually ejected when an outlier status is detected through + * local-origin failure percentage statistics. This setting can be used to disable ejection or to + * ramp it up slowly. Defaults to 0. + */ 'enforcing_failure_percentage_local_origin'?: (_google_protobuf_UInt32Value); + /** + * The minimum number of hosts in a cluster in order to perform failure percentage-based ejection. + * If the total number of hosts in the cluster is less than this value, failure percentage-based + * ejection will not be performed. Defaults to 5. + */ 'failure_percentage_minimum_hosts'?: (_google_protobuf_UInt32Value); + /** + * The minimum number of total requests that must be collected in one interval (as defined by the + * interval duration above) to perform failure percentage-based ejection for this host. If the + * volume is lower than this setting, failure percentage-based ejection will not be performed for + * this host. Defaults to 50. + */ 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value); } +/** + * See the :ref:`architecture overview ` for + * more information on outlier detection. + * [#next-free-field: 21] + */ export interface OutlierDetection__Output { + /** + * The number of consecutive 5xx responses or local origin errors that are mapped + * to 5xx error codes before a consecutive 5xx ejection + * occurs. Defaults to 5. + */ 'consecutive_5xx': (_google_protobuf_UInt32Value__Output); + /** + * The time interval between ejection analysis sweeps. This can result in + * both new ejections as well as hosts being returned to service. Defaults + * to 10000ms or 10s. + */ 'interval': (_google_protobuf_Duration__Output); + /** + * The base time that a host is ejected for. The real time is equal to the + * base time multiplied by the number of times the host has been ejected. + * Defaults to 30000ms or 30s. + */ 'base_ejection_time': (_google_protobuf_Duration__Output); + /** + * The maximum % of an upstream cluster that can be ejected due to outlier + * detection. Defaults to 10% but will eject at least one host regardless of the value. + */ 'max_ejection_percent': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through consecutive 5xx. This setting can be used to disable + * ejection or to ramp it up slowly. Defaults to 100. + */ 'enforcing_consecutive_5xx': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through success rate statistics. This setting can be used to + * disable ejection or to ramp it up slowly. Defaults to 100. + */ 'enforcing_success_rate': (_google_protobuf_UInt32Value__Output); + /** + * The number of hosts in a cluster that must have enough request volume to + * detect success rate outliers. If the number of hosts is less than this + * setting, outlier detection via success rate statistics is not performed + * for any host in the cluster. Defaults to 5. + */ 'success_rate_minimum_hosts': (_google_protobuf_UInt32Value__Output); + /** + * The minimum number of total requests that must be collected in one + * interval (as defined by the interval duration above) to include this host + * in success rate based outlier detection. If the volume is lower than this + * setting, outlier detection via success rate statistics is not performed + * for that host. Defaults to 100. + */ 'success_rate_request_volume': (_google_protobuf_UInt32Value__Output); + /** + * This factor is used to determine the ejection threshold for success rate + * outlier ejection. The ejection threshold is the difference between the + * mean success rate, and the product of this factor and the standard + * deviation of the mean success rate: mean - (stdev * + * success_rate_stdev_factor). This factor is divided by a thousand to get a + * double. That is, if the desired factor is 1.9, the runtime value should + * be 1900. Defaults to 1900. + */ 'success_rate_stdev_factor': (_google_protobuf_UInt32Value__Output); + /** + * The number of consecutive gateway failures (502, 503, 504 status codes) + * before a consecutive gateway failure ejection occurs. Defaults to 5. + */ 'consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through consecutive gateway failures. This setting can be + * used to disable ejection or to ramp it up slowly. Defaults to 0. + */ 'enforcing_consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output); + /** + * Determines whether to distinguish local origin failures from external errors. If set to true + * the following configuration parameters are taken into account: + * :ref:`consecutive_local_origin_failure`, + * :ref:`enforcing_consecutive_local_origin_failure` + * and + * :ref:`enforcing_local_origin_success_rate`. + * Defaults to false. + */ 'split_external_local_origin_errors': (boolean); + /** + * The number of consecutive locally originated failures before ejection + * occurs. Defaults to 5. Parameter takes effect only when + * :ref:`split_external_local_origin_errors` + * is set to true. + */ 'consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through consecutive locally originated failures. This setting can be + * used to disable ejection or to ramp it up slowly. Defaults to 100. + * Parameter takes effect only when + * :ref:`split_external_local_origin_errors` + * is set to true. + */ 'enforcing_consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status + * is detected through success rate statistics for locally originated errors. + * This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. + * Parameter takes effect only when + * :ref:`split_external_local_origin_errors` + * is set to true. + */ 'enforcing_local_origin_success_rate': (_google_protobuf_UInt32Value__Output); + /** + * The failure percentage to use when determining failure percentage-based outlier detection. If + * the failure percentage of a given host is greater than or equal to this value, it will be + * ejected. Defaults to 85. + */ 'failure_percentage_threshold': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status is detected through + * failure percentage statistics. This setting can be used to disable ejection or to ramp it up + * slowly. Defaults to 0. + * + * [#next-major-version: setting this without setting failure_percentage_threshold should be + * invalid in v4.] + */ 'enforcing_failure_percentage': (_google_protobuf_UInt32Value__Output); + /** + * The % chance that a host will be actually ejected when an outlier status is detected through + * local-origin failure percentage statistics. This setting can be used to disable ejection or to + * ramp it up slowly. Defaults to 0. + */ 'enforcing_failure_percentage_local_origin': (_google_protobuf_UInt32Value__Output); + /** + * The minimum number of hosts in a cluster in order to perform failure percentage-based ejection. + * If the total number of hosts in the cluster is less than this value, failure percentage-based + * ejection will not be performed. Defaults to 5. + */ 'failure_percentage_minimum_hosts': (_google_protobuf_UInt32Value__Output); + /** + * The minimum number of total requests that must be collected in one interval (as defined by the + * interval duration above) to perform failure percentage-based ejection for this host. If the + * volume is lower than this setting, failure percentage-based ejection will not be performed for + * this host. Defaults to 50. + */ 'failure_percentage_request_volume': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts index 79b40931c..4ccd1e892 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts @@ -3,12 +3,22 @@ import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from '../../../../envoy/api/v2/core/Pipe'; +/** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export interface Address { 'socket_address'?: (_envoy_api_v2_core_SocketAddress); 'pipe'?: (_envoy_api_v2_core_Pipe); 'address'?: "socket_address"|"pipe"; } +/** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export interface Address__Output { 'socket_address'?: (_envoy_api_v2_core_SocketAddress__Output); 'pipe'?: (_envoy_api_v2_core_Pipe__Output); diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts index dd0b6619b..6837dd0db 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts @@ -1,8 +1,18 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +/** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export interface AggregatedConfigSource { } +/** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export interface AggregatedConfigSource__Output { } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts index 0d951870e..ecec8d5a5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts @@ -7,31 +7,129 @@ import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/a // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +/** + * APIs may be fetched via either REST or gRPC. + */ export enum _envoy_api_v2_core_ApiConfigSource_ApiType { + /** + * Ideally this would be 'reserved 0' but one can't reserve the default + * value. Instead we throw an exception if this is ever used. + */ UNSUPPORTED_REST_LEGACY = 0, + /** + * REST-JSON v2 API. The `canonical JSON encoding + * `_ for + * the v2 protos is used. + */ REST = 1, + /** + * gRPC v2 API. + */ GRPC = 2, + /** + * Using the delta xDS gRPC service, i.e. DeltaDiscovery{Request,Response} + * rather than Discovery{Request,Response}. Rather than sending Envoy the entire state + * with every update, the xDS server only sends what has changed since the last update. + */ DELTA_GRPC = 3, } +/** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export interface ApiConfigSource { + /** + * API type (gRPC, REST, delta gRPC) + */ 'api_type'?: (_envoy_api_v2_core_ApiConfigSource_ApiType | keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); + /** + * Cluster names should be used only with REST. If > 1 + * cluster is defined, clusters will be cycled through if any kind of failure + * occurs. + * + * .. note:: + * + * The cluster with name ``cluster_name`` must be statically defined and its + * type must not be ``EDS``. + */ 'cluster_names'?: (string)[]; + /** + * For REST APIs, the delay between successive polls. + */ 'refresh_delay'?: (_google_protobuf_Duration); + /** + * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, + * services will be cycled through if any kind of failure occurs. + */ 'grpc_services'?: (_envoy_api_v2_core_GrpcService)[]; + /** + * For REST APIs, the request timeout. If not set, a default value of 1s will be used. + */ 'request_timeout'?: (_google_protobuf_Duration); + /** + * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be + * rate limited. + */ 'rate_limit_settings'?: (_envoy_api_v2_core_RateLimitSettings); + /** + * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. + */ 'set_node_on_first_message_only'?: (boolean); + /** + * API version for xDS transport protocol. This describes the xDS gRPC/REST + * endpoint and version of [Delta]DiscoveryRequest/Response used on the wire. + */ 'transport_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); } +/** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export interface ApiConfigSource__Output { + /** + * API type (gRPC, REST, delta gRPC) + */ 'api_type': (keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); + /** + * Cluster names should be used only with REST. If > 1 + * cluster is defined, clusters will be cycled through if any kind of failure + * occurs. + * + * .. note:: + * + * The cluster with name ``cluster_name`` must be statically defined and its + * type must not be ``EDS``. + */ 'cluster_names': (string)[]; + /** + * For REST APIs, the delay between successive polls. + */ 'refresh_delay': (_google_protobuf_Duration__Output); + /** + * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, + * services will be cycled through if any kind of failure occurs. + */ 'grpc_services': (_envoy_api_v2_core_GrpcService__Output)[]; + /** + * For REST APIs, the request timeout. If not set, a default value of 1s will be used. + */ 'request_timeout': (_google_protobuf_Duration__Output); + /** + * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be + * rate limited. + */ 'rate_limit_settings': (_envoy_api_v2_core_RateLimitSettings__Output); + /** + * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. + */ 'set_node_on_first_message_only': (boolean); + /** + * API version for xDS transport protocol. This describes the xDS gRPC/REST + * endpoint and version of [Delta]DiscoveryRequest/Response used on the wire. + */ 'transport_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts index 0a3952e61..7f03a5995 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts @@ -1,7 +1,22 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +/** + * xDS API version. This is used to describe both resource and transport + * protocol versions (in distinct configuration fields). + */ export enum ApiVersion { + /** + * When not specified, we assume v2, to ease migration to Envoy's stable API + * versioning. If a client does not support v2 (e.g. due to deprecation), this + * is an invalid value. + */ AUTO = 0, + /** + * Use xDS v2 API. + */ V2 = 1, + /** + * Use xDS v3 API. + */ V3 = 2, } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts index 1f8ea0b5f..c4de49ee0 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts @@ -3,14 +3,32 @@ import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from '../../../../envoy/api/v2/core/RemoteDataSource'; +/** + * Async data source which support async data fetch. + */ export interface AsyncDataSource { + /** + * Local async data source. + */ 'local'?: (_envoy_api_v2_core_DataSource); + /** + * Remote async data source. + */ 'remote'?: (_envoy_api_v2_core_RemoteDataSource); 'specifier'?: "local"|"remote"; } +/** + * Async data source which support async data fetch. + */ export interface AsyncDataSource__Output { + /** + * Local async data source. + */ 'local'?: (_envoy_api_v2_core_DataSource__Output); + /** + * Remote async data source. + */ 'remote'?: (_envoy_api_v2_core_RemoteDataSource__Output); 'specifier': "local"|"remote"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts index a95361e5a..636b768fe 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts @@ -2,12 +2,42 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +/** + * Configuration defining a jittered exponential back off strategy. + */ export interface BackoffStrategy { + /** + * The base interval to be used for the next back off computation. It should + * be greater than zero and less than or equal to :ref:`max_interval + * `. + */ 'base_interval'?: (_google_protobuf_Duration); + /** + * Specifies the maximum interval between retries. This parameter is optional, + * but must be greater than or equal to the :ref:`base_interval + * ` if set. The default + * is 10 times the :ref:`base_interval + * `. + */ 'max_interval'?: (_google_protobuf_Duration); } +/** + * Configuration defining a jittered exponential back off strategy. + */ export interface BackoffStrategy__Output { + /** + * The base interval to be used for the next back off computation. It should + * be greater than zero and less than or equal to :ref:`max_interval + * `. + */ 'base_interval': (_google_protobuf_Duration__Output); + /** + * Specifies the maximum interval between retries. This parameter is optional, + * but must be greater than or equal to the :ref:`base_interval + * ` if set. The default + * is 10 times the :ref:`base_interval + * `. + */ 'max_interval': (_google_protobuf_Duration__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts index 05d32a072..af81592bf 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts @@ -5,13 +5,45 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_p import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../../envoy/api/v2/core/SocketOption'; export interface BindConfig { + /** + * The address to bind to when creating a socket. + */ 'source_address'?: (_envoy_api_v2_core_SocketAddress); + /** + * Whether to set the *IP_FREEBIND* option when creating the socket. When this + * flag is set to true, allows the :ref:`source_address + * ` to be an IP address + * that is not configured on the system running Envoy. When this flag is set + * to false, the option *IP_FREEBIND* is disabled on the socket. When this + * flag is not set (default), the socket is not modified, i.e. the option is + * neither enabled nor disabled. + */ 'freebind'?: (_google_protobuf_BoolValue); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; } export interface BindConfig__Output { + /** + * The address to bind to when creating a socket. + */ 'source_address': (_envoy_api_v2_core_SocketAddress__Output); + /** + * Whether to set the *IP_FREEBIND* option when creating the socket. When this + * flag is set to true, allows the :ref:`source_address + * ` to be an IP address + * that is not configured on the system running Envoy. When this flag is set + * to false, the option *IP_FREEBIND* is disabled on the socket. When this + * flag is not set (default), the socket is not modified, i.e. the option is + * neither enabled nor disabled. + */ 'freebind': (_google_protobuf_BoolValue__Output); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts index 1008082a2..305ad3c4d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts @@ -3,12 +3,34 @@ import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from '../../../../envoy/type/SemanticVersion'; import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +/** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export interface BuildVersion { + /** + * SemVer version of extension. + */ 'version'?: (_envoy_type_SemanticVersion); + /** + * Free-form build information. + * Envoy defines several well known keys in the source/common/common/version.h file + */ 'metadata'?: (_google_protobuf_Struct); } +/** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export interface BuildVersion__Output { + /** + * SemVer version of extension. + */ 'version': (_envoy_type_SemanticVersion__Output); + /** + * Free-form build information. + * Envoy defines several well known keys in the source/common/common/version.h file + */ 'metadata': (_google_protobuf_Struct__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts index 6c84de0c2..e0c19da92 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts @@ -2,12 +2,32 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +/** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export interface CidrRange { + /** + * IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. + */ 'address_prefix'?: (string); + /** + * Length of prefix, e.g. 0, 32. + */ 'prefix_len'?: (_google_protobuf_UInt32Value); } +/** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export interface CidrRange__Output { + /** + * IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. + */ 'address_prefix': (string); + /** + * Length of prefix, e.g. 0, 32. + */ 'prefix_len': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts index 9f6952a7f..3ce5cc5d8 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts @@ -6,22 +6,138 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_prot import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; +/** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export interface ConfigSource { + /** + * Path on the filesystem to source and watch for configuration updates. + * When sourcing configuration for :ref:`secret `, + * the certificate and key files are also watched for updates. + * + * .. note:: + * + * The path to the source must exist at config load time. + * + * .. note:: + * + * Envoy will only watch the file path for *moves.* This is because in general only moves + * are atomic. The same method of swapping files as is demonstrated in the + * :ref:`runtime documentation ` can be used here also. + */ 'path'?: (string); + /** + * API configuration source. + */ 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource); + /** + * When set, ADS will be used to fetch resources. The ADS API configuration + * source in the bootstrap configuration is used. + */ 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource); + /** + * When this timeout is specified, Envoy will wait no longer than the specified time for first + * config response on this xDS subscription during the :ref:`initialization process + * `. After reaching the timeout, Envoy will move to the next + * initialization phase, even if the first config is not delivered yet. The timer is activated + * when the xDS API subscription starts, and is disarmed on first config update or on error. 0 + * means no timeout - Envoy will wait indefinitely for the first xDS config (unless another + * timeout applies). The default is 15s. + */ 'initial_fetch_timeout'?: (_google_protobuf_Duration); + /** + * [#not-implemented-hide:] + * When set, the client will access the resources from the same server it got the + * ConfigSource from, although not necessarily from the same stream. This is similar to the + * :ref:`ads` field, except that the client may use a + * different stream to the same server. As a result, this field can be used for things + * like LRS that cannot be sent on an ADS stream. It can also be used to link from (e.g.) + * LDS to RDS on the same server without requiring the management server to know its name + * or required credentials. + * [#next-major-version: In xDS v3, consider replacing the ads field with this one, since + * this field can implicitly mean to use the same stream in the case where the ConfigSource + * is provided via ADS and the specified data can also be obtained via ADS.] + */ 'self'?: (_envoy_api_v2_core_SelfConfigSource); + /** + * API version for xDS resources. This implies the type URLs that the client + * will request for resources and the resource type that the client will in + * turn expect to be delivered. + */ 'resource_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); 'config_source_specifier'?: "path"|"api_config_source"|"ads"|"self"; } +/** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export interface ConfigSource__Output { + /** + * Path on the filesystem to source and watch for configuration updates. + * When sourcing configuration for :ref:`secret `, + * the certificate and key files are also watched for updates. + * + * .. note:: + * + * The path to the source must exist at config load time. + * + * .. note:: + * + * Envoy will only watch the file path for *moves.* This is because in general only moves + * are atomic. The same method of swapping files as is demonstrated in the + * :ref:`runtime documentation ` can be used here also. + */ 'path'?: (string); + /** + * API configuration source. + */ 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource__Output); + /** + * When set, ADS will be used to fetch resources. The ADS API configuration + * source in the bootstrap configuration is used. + */ 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource__Output); + /** + * When this timeout is specified, Envoy will wait no longer than the specified time for first + * config response on this xDS subscription during the :ref:`initialization process + * `. After reaching the timeout, Envoy will move to the next + * initialization phase, even if the first config is not delivered yet. The timer is activated + * when the xDS API subscription starts, and is disarmed on first config update or on error. 0 + * means no timeout - Envoy will wait indefinitely for the first xDS config (unless another + * timeout applies). The default is 15s. + */ 'initial_fetch_timeout': (_google_protobuf_Duration__Output); + /** + * [#not-implemented-hide:] + * When set, the client will access the resources from the same server it got the + * ConfigSource from, although not necessarily from the same stream. This is similar to the + * :ref:`ads` field, except that the client may use a + * different stream to the same server. As a result, this field can be used for things + * like LRS that cannot be sent on an ADS stream. It can also be used to link from (e.g.) + * LDS to RDS on the same server without requiring the management server to know its name + * or required credentials. + * [#next-major-version: In xDS v3, consider replacing the ads field with this one, since + * this field can implicitly mean to use the same stream in the case where the ConfigSource + * is provided via ADS and the specified data can also be obtained via ADS.] + */ 'self'?: (_envoy_api_v2_core_SelfConfigSource__Output); + /** + * API version for xDS resources. This implies the type URLs that the client + * will request for resources and the resource type that the client will in + * turn expect to be delivered. + */ 'resource_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); 'config_source_specifier': "path"|"api_config_source"|"ads"|"self"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts index 0074cf060..551f693a2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts @@ -1,10 +1,26 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export interface ControlPlane { + /** + * An opaque control plane identifier that uniquely identifies an instance + * of control plane. This can be used to identify which control plane instance, + * the Envoy is connected to. + */ 'identifier'?: (string); } +/** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export interface ControlPlane__Output { + /** + * An opaque control plane identifier that uniquely identifies an instance + * of control plane. This can be used to identify which control plane instance, + * the Envoy is connected to. + */ 'identifier': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts index ae5b5a302..a04100054 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts @@ -1,16 +1,40 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Data source consisting of either a file or an inline value. + */ export interface DataSource { + /** + * Local filesystem data source. + */ 'filename'?: (string); + /** + * Bytes inlined in the configuration. + */ 'inline_bytes'?: (Buffer | Uint8Array | string); + /** + * String inlined in the configuration. + */ 'inline_string'?: (string); 'specifier'?: "filename"|"inline_bytes"|"inline_string"; } +/** + * Data source consisting of either a file or an inline value. + */ export interface DataSource__Output { + /** + * Local filesystem data source. + */ 'filename'?: (string); + /** + * Bytes inlined in the configuration. + */ 'inline_bytes'?: (Buffer); + /** + * String inlined in the configuration. + */ 'inline_string'?: (string); 'specifier': "filename"|"inline_bytes"|"inline_string"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts index 31601fa74..3cba29184 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts @@ -2,12 +2,26 @@ import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; +/** + * [#not-implemented-hide:] + * Configuration of the event reporting service endpoint. + */ export interface EventServiceConfig { + /** + * Specifies the gRPC service that hosts the event reporting service. + */ 'grpc_service'?: (_envoy_api_v2_core_GrpcService); 'config_source_specifier'?: "grpc_service"; } +/** + * [#not-implemented-hide:] + * Configuration of the event reporting service endpoint. + */ export interface EventServiceConfig__Output { + /** + * Specifies the gRPC service that hosts the event reporting service. + */ 'grpc_service'?: (_envoy_api_v2_core_GrpcService__Output); 'config_source_specifier': "grpc_service"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts index 285b68bea..3d17d6225 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts @@ -2,18 +2,74 @@ import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; +/** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export interface Extension { + /** + * This is the name of the Envoy filter as specified in the Envoy + * configuration, e.g. envoy.filters.http.router, com.acme.widget. + */ 'name'?: (string); + /** + * Category of the extension. + * Extension category names use reverse DNS notation. For instance "envoy.filters.listener" + * for Envoy's built-in listener filters or "com.acme.filters.http" for HTTP filters from + * acme.com vendor. + * [#comment:TODO(yanavlasov): Link to the doc with existing envoy category names.] + */ 'category'?: (string); + /** + * [#not-implemented-hide:] Type descriptor of extension configuration proto. + * [#comment:TODO(yanavlasov): Link to the doc with existing configuration protos.] + * [#comment:TODO(yanavlasov): Add tests when PR #9391 lands.] + */ 'type_descriptor'?: (string); + /** + * The version is a property of the extension and maintained independently + * of other extensions and the Envoy API. + * This field is not set when extension did not provide version information. + */ 'version'?: (_envoy_api_v2_core_BuildVersion); + /** + * Indicates that the extension is present but was disabled via dynamic configuration. + */ 'disabled'?: (boolean); } +/** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export interface Extension__Output { + /** + * This is the name of the Envoy filter as specified in the Envoy + * configuration, e.g. envoy.filters.http.router, com.acme.widget. + */ 'name': (string); + /** + * Category of the extension. + * Extension category names use reverse DNS notation. For instance "envoy.filters.listener" + * for Envoy's built-in listener filters or "com.acme.filters.http" for HTTP filters from + * acme.com vendor. + * [#comment:TODO(yanavlasov): Link to the doc with existing envoy category names.] + */ 'category': (string); + /** + * [#not-implemented-hide:] Type descriptor of extension configuration proto. + * [#comment:TODO(yanavlasov): Link to the doc with existing configuration protos.] + * [#comment:TODO(yanavlasov): Add tests when PR #9391 lands.] + */ 'type_descriptor': (string); + /** + * The version is a property of the extension and maintained independently + * of other extensions and the Envoy API. + * This field is not set when extension did not provide version information. + */ 'version': (_envoy_api_v2_core_BuildVersion__Output); + /** + * Indicates that the extension is present but was disabled via dynamic configuration. + */ 'disabled': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts index fc1c3755f..65148f419 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts @@ -2,10 +2,16 @@ import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../envoy/api/v2/core/Http2ProtocolOptions'; +/** + * [#not-implemented-hide:] + */ export interface GrpcProtocolOptions { 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); } +/** + * [#not-implemented-hide:] + */ export interface GrpcProtocolOptions__Output { 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts index 10fabd16c..e536cb317 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts @@ -9,49 +9,189 @@ import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _env import { Long } from '@grpc/proto-loader'; export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc { + /** + * The name of the upstream gRPC cluster. SSL credentials will be supplied + * in the :ref:`Cluster ` :ref:`transport_socket + * `. + */ 'cluster_name'?: (string); } export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc__Output { + /** + * The name of the upstream gRPC cluster. SSL credentials will be supplied + * in the :ref:`Cluster ` :ref:`transport_socket + * `. + */ 'cluster_name': (string); } +/** + * [#next-free-field: 7] + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc { + /** + * The target URI when using the `Google C++ gRPC client + * `_. SSL credentials will be supplied in + * :ref:`channel_credentials `. + */ 'target_uri'?: (string); 'channel_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials); + /** + * A set of call credentials that can be composed with `channel credentials + * `_. + */ 'call_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials)[]; + /** + * The human readable prefix to use when emitting statistics for the gRPC + * service. + * + * .. csv-table:: + * :header: Name, Type, Description + * :widths: 1, 1, 2 + * + * streams_total, Counter, Total number of streams opened + * streams_closed_, Counter, Total streams closed with + */ 'stat_prefix'?: (string); + /** + * The name of the Google gRPC credentials factory to use. This must have been registered with + * Envoy. If this is empty, a default credentials factory will be used that sets up channel + * credentials based on other configuration parameters. + */ 'credentials_factory_name'?: (string); + /** + * Additional configuration for site-specific customizations of the Google + * gRPC library. + */ 'config'?: (_google_protobuf_Struct); } +/** + * [#next-free-field: 7] + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { + /** + * The target URI when using the `Google C++ gRPC client + * `_. SSL credentials will be supplied in + * :ref:`channel_credentials `. + */ 'target_uri': (string); 'channel_credentials': (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output); + /** + * A set of call credentials that can be composed with `channel credentials + * `_. + */ 'call_credentials': (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output)[]; + /** + * The human readable prefix to use when emitting statistics for the gRPC + * service. + * + * .. csv-table:: + * :header: Name, Type, Description + * :widths: 1, 1, 2 + * + * streams_total, Counter, Total number of streams opened + * streams_closed_, Counter, Total streams closed with + */ 'stat_prefix': (string); + /** + * The name of the Google gRPC credentials factory to use. This must have been registered with + * Envoy. If this is empty, a default credentials factory will be used that sets up channel + * credentials based on other configuration parameters. + */ 'credentials_factory_name': (string); + /** + * Additional configuration for site-specific customizations of the Google + * gRPC library. + */ 'config': (_google_protobuf_Struct__Output); } +/** + * [#next-free-field: 8] + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { + /** + * Access token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. + */ 'access_token'?: (string); + /** + * Google Compute Engine credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ 'google_compute_engine'?: (_google_protobuf_Empty); + /** + * Google refresh token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. + */ 'google_refresh_token'?: (string); + /** + * Service Account JWT Access credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. + */ 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); + /** + * Google IAM credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. + */ 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); + /** + * Custom authenticator credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. + * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. + */ 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); + /** + * Custom security token service which implements OAuth 2.0 token exchange. + * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 + * See https://github.com/grpc/grpc/pull/19587. + */ 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService); 'credential_specifier'?: "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } +/** + * [#next-free-field: 8] + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output { + /** + * Access token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. + */ 'access_token'?: (string); + /** + * Google Compute Engine credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ 'google_compute_engine'?: (_google_protobuf_Empty__Output); + /** + * Google refresh token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. + */ 'google_refresh_token'?: (string); + /** + * Service Account JWT Access credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. + */ 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); + /** + * Google IAM credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. + */ 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); + /** + * Custom authenticator credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. + * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. + */ 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); + /** + * Custom security token service which implements OAuth 2.0 token exchange. + * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 + * See https://github.com/grpc/grpc/pull/19587. + */ 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } @@ -90,74 +230,252 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_Servi 'token_lifetime_seconds': (string); } +/** + * Security token service configuration that allows Google gRPC to + * fetch security token from an OAuth 2.0 authorization server. + * See https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 and + * https://github.com/grpc/grpc/pull/19587. + * [#next-free-field: 10] + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService { + /** + * URI of the token exchange service that handles token exchange requests. + * [#comment:TODO(asraa): Add URI validation when implemented. Tracked by + * https://github.com/envoyproxy/protoc-gen-validate/issues/303] + */ 'token_exchange_service_uri'?: (string); + /** + * Location of the target service or resource where the client + * intends to use the requested security token. + */ 'resource'?: (string); + /** + * Logical name of the target service where the client intends to + * use the requested security token. + */ 'audience'?: (string); + /** + * The desired scope of the requested security token in the + * context of the service or resource where the token will be used. + */ 'scope'?: (string); + /** + * Type of the requested security token. + */ 'requested_token_type'?: (string); + /** + * The path of subject token, a security token that represents the + * identity of the party on behalf of whom the request is being made. + */ 'subject_token_path'?: (string); + /** + * Type of the subject token. + */ 'subject_token_type'?: (string); + /** + * The path of actor token, a security token that represents the identity + * of the acting party. The acting party is authorized to use the + * requested security token and act on behalf of the subject. + */ 'actor_token_path'?: (string); + /** + * Type of the actor token. + */ 'actor_token_type'?: (string); } +/** + * Security token service configuration that allows Google gRPC to + * fetch security token from an OAuth 2.0 authorization server. + * See https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 and + * https://github.com/grpc/grpc/pull/19587. + * [#next-free-field: 10] + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output { + /** + * URI of the token exchange service that handles token exchange requests. + * [#comment:TODO(asraa): Add URI validation when implemented. Tracked by + * https://github.com/envoyproxy/protoc-gen-validate/issues/303] + */ 'token_exchange_service_uri': (string); + /** + * Location of the target service or resource where the client + * intends to use the requested security token. + */ 'resource': (string); + /** + * Logical name of the target service where the client intends to + * use the requested security token. + */ 'audience': (string); + /** + * The desired scope of the requested security token in the + * context of the service or resource where the token will be used. + */ 'scope': (string); + /** + * Type of the requested security token. + */ 'requested_token_type': (string); + /** + * The path of subject token, a security token that represents the + * identity of the party on behalf of whom the request is being made. + */ 'subject_token_path': (string); + /** + * Type of the subject token. + */ 'subject_token_type': (string); + /** + * The path of actor token, a security token that represents the identity + * of the acting party. The acting party is authorized to use the + * requested security token and act on behalf of the subject. + */ 'actor_token_path': (string); + /** + * Type of the actor token. + */ 'actor_token_type': (string); } +/** + * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call + * credential types. + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); + /** + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ 'google_default'?: (_google_protobuf_Empty); 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; } +/** + * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call + * credential types. + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); + /** + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ 'google_default'?: (_google_protobuf_Empty__Output); 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; } +/** + * Local channel credentials. Only UDS is supported for now. + * See https://github.com/grpc/grpc/pull/15909. + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { } +/** + * Local channel credentials. Only UDS is supported for now. + * See https://github.com/grpc/grpc/pull/15909. + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { } +/** + * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { + /** + * PEM encoded server root certificates. + */ 'root_certs'?: (_envoy_api_v2_core_DataSource); + /** + * PEM encoded client private key. + */ 'private_key'?: (_envoy_api_v2_core_DataSource); + /** + * PEM encoded client certificate chain. + */ 'cert_chain'?: (_envoy_api_v2_core_DataSource); } +/** + * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. + */ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { + /** + * PEM encoded server root certificates. + */ 'root_certs': (_envoy_api_v2_core_DataSource__Output); + /** + * PEM encoded client private key. + */ 'private_key': (_envoy_api_v2_core_DataSource__Output); + /** + * PEM encoded client certificate chain. + */ 'cert_chain': (_envoy_api_v2_core_DataSource__Output); } +/** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export interface GrpcService { + /** + * Envoy's in-built gRPC client. + * See the :ref:`gRPC services overview ` + * documentation for discussion on gRPC client selection. + */ 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc); + /** + * `Google C++ gRPC client `_ + * See the :ref:`gRPC services overview ` + * documentation for discussion on gRPC client selection. + */ 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc); + /** + * The timeout for the gRPC request. This is the timeout for a specific + * request. + */ 'timeout'?: (_google_protobuf_Duration); + /** + * Additional metadata to include in streams initiated to the GrpcService. + * This can be used for scenarios in which additional ad hoc authorization + * headers (e.g. ``x-foo-bar: baz-key``) are to be injected. + */ 'initial_metadata'?: (_envoy_api_v2_core_HeaderValue)[]; 'target_specifier'?: "envoy_grpc"|"google_grpc"; } +/** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export interface GrpcService__Output { + /** + * Envoy's in-built gRPC client. + * See the :ref:`gRPC services overview ` + * documentation for discussion on gRPC client selection. + */ 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc__Output); + /** + * `Google C++ gRPC client `_ + * See the :ref:`gRPC services overview ` + * documentation for discussion on gRPC client selection. + */ 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc__Output); + /** + * The timeout for the gRPC request. This is the timeout for a specific + * request. + */ 'timeout': (_google_protobuf_Duration__Output); + /** + * Additional metadata to include in streams initiated to the GrpcService. + * This can be used for scenarios in which additional ad hoc authorization + * headers (e.g. ``x-foo-bar: baz-key``) are to be injected. + */ 'initial_metadata': (_envoy_api_v2_core_HeaderValue__Output)[]; 'target_specifier': "envoy_grpc"|"google_grpc"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts index b3fafdc57..3144e668c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts @@ -2,10 +2,16 @@ import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +/** + * Wrapper for a set of headers. + */ export interface HeaderMap { 'headers'?: (_envoy_api_v2_core_HeaderValue)[]; } +/** + * Wrapper for a set of headers. + */ export interface HeaderMap__Output { 'headers': (_envoy_api_v2_core_HeaderValue__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts index 4b2e8ac92..b36605324 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts @@ -1,12 +1,38 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Header name/value pair. + */ export interface HeaderValue { + /** + * Header name. + */ 'key'?: (string); + /** + * Header value. + * + * The same :ref:`format specifier ` as used for + * :ref:`HTTP access logging ` applies here, however + * unknown header values are replaced with the empty string instead of `-`. + */ 'value'?: (string); } +/** + * Header name/value pair. + */ export interface HeaderValue__Output { + /** + * Header name. + */ 'key': (string); + /** + * Header value. + * + * The same :ref:`format specifier ` as used for + * :ref:`HTTP access logging ` applies here, however + * unknown header values are replaced with the empty string instead of `-`. + */ 'value': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts index ac8c4b971..96350736b 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts @@ -3,12 +3,32 @@ import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +/** + * Header name/value pair plus option to control append behavior. + */ export interface HeaderValueOption { + /** + * Header name/value pair that this option applies to. + */ 'header'?: (_envoy_api_v2_core_HeaderValue); + /** + * Should the value be appended? If true (default), the value is appended to + * existing values. + */ 'append'?: (_google_protobuf_BoolValue); } +/** + * Header name/value pair plus option to control append behavior. + */ export interface HeaderValueOption__Output { + /** + * Header name/value pair that this option applies to. + */ 'header': (_envoy_api_v2_core_HeaderValue__Output); + /** + * Should the value be appended? If true (default), the value is appended to + * existing values. + */ 'append': (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts index e91ef5dbe..662e73752 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts @@ -12,142 +12,596 @@ import { CodecClientType as _envoy_type_CodecClientType } from '../../../../envo import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; import { Long } from '@grpc/proto-loader'; +/** + * Custom health check. + */ export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck { + /** + * The registered name of the custom health checker. + */ 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * A custom health checker specific configuration which depends on the custom health checker + * being instantiated. See :api:`envoy/config/health_checker` for reference. + */ 'config_type'?: "config"|"typed_config"; } +/** + * Custom health check. + */ export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output { + /** + * The registered name of the custom health checker. + */ 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * A custom health checker specific configuration which depends on the custom health checker + * being instantiated. See :api:`envoy/config/health_checker` for reference. + */ 'config_type': "config"|"typed_config"; } +/** + * `grpc.health.v1.Health + * `_-based + * healthcheck. See `gRPC doc `_ + * for details. + */ export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { + /** + * An optional service name parameter which will be sent to gRPC service in + * `grpc.health.v1.HealthCheckRequest + * `_. + * message. See `gRPC health-checking overview + * `_ for more information. + */ 'service_name'?: (string); + /** + * The value of the :authority header in the gRPC health check request. If + * left empty (default value), the name of the cluster this health check is associated + * with will be used. The authority header can be customized for a specific endpoint by setting + * the :ref:`hostname ` field. + */ 'authority'?: (string); } +/** + * `grpc.health.v1.Health + * `_-based + * healthcheck. See `gRPC doc `_ + * for details. + */ export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { + /** + * An optional service name parameter which will be sent to gRPC service in + * `grpc.health.v1.HealthCheckRequest + * `_. + * message. See `gRPC health-checking overview + * `_ for more information. + */ 'service_name': (string); + /** + * The value of the :authority header in the gRPC health check request. If + * left empty (default value), the name of the cluster this health check is associated + * with will be used. The authority header can be customized for a specific endpoint by setting + * the :ref:`hostname ` field. + */ 'authority': (string); } +/** + * [#next-free-field: 12] + */ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck { + /** + * The value of the host header in the HTTP health check request. If + * left empty (default value), the name of the cluster this health check is associated + * with will be used. The host header can be customized for a specific endpoint by setting the + * :ref:`hostname ` field. + */ 'host'?: (string); + /** + * Specifies the HTTP path that will be requested during health checking. For example + * * /healthcheck*. + */ 'path'?: (string); + /** + * [#not-implemented-hide:] HTTP specific payload. + */ 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + /** + * [#not-implemented-hide:] HTTP specific response. + */ 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload); + /** + * An optional service name parameter which is used to validate the identity of + * the health checked cluster. See the :ref:`architecture overview + * ` for more information. + * + * .. attention:: + * + * This field has been deprecated in favor of `service_name_matcher` for better flexibility + * over matching with service-cluster name. + */ 'service_name'?: (string); + /** + * Specifies a list of HTTP headers that should be added to each request that is sent to the + * health checked cluster. For more information, including details on header value syntax, see + * the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a list of HTTP headers that should be removed from each request that is sent to the + * health checked cluster. + */ 'request_headers_to_remove'?: (string)[]; + /** + * If set, health checks will be made using http/2. + * Deprecated, use :ref:`codec_client_type + * ` instead. + */ 'use_http2'?: (boolean); + /** + * Specifies a list of HTTP response statuses considered healthy. If provided, replaces default + * 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open + * semantics of :ref:`Int64Range `. The start and end of each + * range are required. Only statuses in the range [100, 600) are allowed. + */ 'expected_statuses'?: (_envoy_type_Int64Range)[]; + /** + * Use specified application protocol for health checks. + */ 'codec_client_type'?: (_envoy_type_CodecClientType | keyof typeof _envoy_type_CodecClientType); + /** + * An optional service name parameter which is used to validate the identity of + * the health checked cluster using a :ref:`StringMatcher + * `. See the :ref:`architecture overview + * ` for more information. + */ 'service_name_matcher'?: (_envoy_type_matcher_StringMatcher); } +/** + * [#next-free-field: 12] + */ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { + /** + * The value of the host header in the HTTP health check request. If + * left empty (default value), the name of the cluster this health check is associated + * with will be used. The host header can be customized for a specific endpoint by setting the + * :ref:`hostname ` field. + */ 'host': (string); + /** + * Specifies the HTTP path that will be requested during health checking. For example + * * /healthcheck*. + */ 'path': (string); + /** + * [#not-implemented-hide:] HTTP specific payload. + */ 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + /** + * [#not-implemented-hide:] HTTP specific response. + */ 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output); + /** + * An optional service name parameter which is used to validate the identity of + * the health checked cluster. See the :ref:`architecture overview + * ` for more information. + * + * .. attention:: + * + * This field has been deprecated in favor of `service_name_matcher` for better flexibility + * over matching with service-cluster name. + */ 'service_name': (string); + /** + * Specifies a list of HTTP headers that should be added to each request that is sent to the + * health checked cluster. For more information, including details on header value syntax, see + * the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a list of HTTP headers that should be removed from each request that is sent to the + * health checked cluster. + */ 'request_headers_to_remove': (string)[]; + /** + * If set, health checks will be made using http/2. + * Deprecated, use :ref:`codec_client_type + * ` instead. + */ 'use_http2': (boolean); + /** + * Specifies a list of HTTP response statuses considered healthy. If provided, replaces default + * 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open + * semantics of :ref:`Int64Range `. The start and end of each + * range are required. Only statuses in the range [100, 600) are allowed. + */ 'expected_statuses': (_envoy_type_Int64Range__Output)[]; + /** + * Use specified application protocol for health checks. + */ 'codec_client_type': (keyof typeof _envoy_type_CodecClientType); + /** + * An optional service name parameter which is used to validate the identity of + * the health checked cluster using a :ref:`StringMatcher + * `. See the :ref:`architecture overview + * ` for more information. + */ 'service_name_matcher': (_envoy_type_matcher_StringMatcher__Output); } +/** + * Describes the encoding of the payload bytes in the payload. + */ export interface _envoy_api_v2_core_HealthCheck_Payload { + /** + * Hex encoded payload. E.g., "000000FF". + */ 'text'?: (string); + /** + * [#not-implemented-hide:] Binary payload. + */ 'binary'?: (Buffer | Uint8Array | string); 'payload'?: "text"|"binary"; } +/** + * Describes the encoding of the payload bytes in the payload. + */ export interface _envoy_api_v2_core_HealthCheck_Payload__Output { + /** + * Hex encoded payload. E.g., "000000FF". + */ 'text'?: (string); + /** + * [#not-implemented-hide:] Binary payload. + */ 'binary'?: (Buffer); 'payload': "text"|"binary"; } export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck { + /** + * If set, optionally perform ``EXISTS `` instead of ``PING``. A return value + * from Redis of 0 (does not exist) is considered a passing healthcheck. A return value other + * than 0 is considered a failure. This allows the user to mark a Redis instance for maintenance + * by setting the specified key to any value and waiting for traffic to drain. + */ 'key'?: (string); } export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck__Output { + /** + * If set, optionally perform ``EXISTS `` instead of ``PING``. A return value + * from Redis of 0 (does not exist) is considered a passing healthcheck. A return value other + * than 0 is considered a failure. This allows the user to mark a Redis instance for maintenance + * by setting the specified key to any value and waiting for traffic to drain. + */ 'key': (string); } export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck { + /** + * Empty payloads imply a connect-only health check. + */ 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + /** + * When checking the response, “fuzzy†matching is performed such that each + * binary block must be found, and in the order specified, but not + * necessarily contiguous. + */ 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload)[]; } export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { + /** + * Empty payloads imply a connect-only health check. + */ 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + /** + * When checking the response, “fuzzy†matching is performed such that each + * binary block must be found, and in the order specified, but not + * necessarily contiguous. + */ 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output)[]; } +/** + * Health checks occur over the transport socket specified for the cluster. This implies that if a + * cluster is using a TLS-enabled transport socket, the health check will also occur over TLS. + * + * This allows overriding the cluster TLS settings, just for health check connections. + */ export interface _envoy_api_v2_core_HealthCheck_TlsOptions { + /** + * Specifies the ALPN protocols for health check connections. This is useful if the + * corresponding upstream is using ALPN-based :ref:`FilterChainMatch + * ` along with different protocols for health checks + * versus data connections. If empty, no ALPN protocols will be set on health check connections. + */ 'alpn_protocols'?: (string)[]; } +/** + * Health checks occur over the transport socket specified for the cluster. This implies that if a + * cluster is using a TLS-enabled transport socket, the health check will also occur over TLS. + * + * This allows overriding the cluster TLS settings, just for health check connections. + */ export interface _envoy_api_v2_core_HealthCheck_TlsOptions__Output { + /** + * Specifies the ALPN protocols for health check connections. This is useful if the + * corresponding upstream is using ALPN-based :ref:`FilterChainMatch + * ` along with different protocols for health checks + * versus data connections. If empty, no ALPN protocols will be set on health check connections. + */ 'alpn_protocols': (string)[]; } +/** + * [#next-free-field: 23] + */ export interface HealthCheck { + /** + * The time to wait for a health check response. If the timeout is reached the + * health check attempt will be considered a failure. + */ 'timeout'?: (_google_protobuf_Duration); + /** + * The interval between health checks. + */ 'interval'?: (_google_protobuf_Duration); + /** + * An optional jitter amount in milliseconds. If specified, during every + * interval Envoy will add interval_jitter to the wait time. + */ 'interval_jitter'?: (_google_protobuf_Duration); + /** + * The number of unhealthy health checks required before a host is marked + * unhealthy. Note that for *http* health checking if a host responds with 503 + * this threshold is ignored and the host is considered unhealthy immediately. + */ 'unhealthy_threshold'?: (_google_protobuf_UInt32Value); + /** + * The number of healthy health checks required before a host is marked + * healthy. Note that during startup, only a single successful health check is + * required to mark a host healthy. + */ 'healthy_threshold'?: (_google_protobuf_UInt32Value); + /** + * [#not-implemented-hide:] Non-serving port for health checking. + */ 'alt_port'?: (_google_protobuf_UInt32Value); + /** + * Reuse health check connection between health checks. Default is true. + */ 'reuse_connection'?: (_google_protobuf_BoolValue); + /** + * HTTP health check. + */ 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck); + /** + * TCP health check. + */ 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck); + /** + * gRPC health check. + */ 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck); + /** + * The "no traffic interval" is a special health check interval that is used when a cluster has + * never had traffic routed to it. This lower interval allows cluster information to be kept up to + * date, without sending a potentially large amount of active health checking traffic for no + * reason. Once a cluster has been used for traffic routing, Envoy will shift back to using the + * standard health check interval that is defined. Note that this interval takes precedence over + * any other. + * + * The default value for "no traffic interval" is 60 seconds. + */ 'no_traffic_interval'?: (_google_protobuf_Duration); + /** + * Custom health check. + */ 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck); + /** + * The "unhealthy interval" is a health check interval that is used for hosts that are marked as + * unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the + * standard health check interval that is defined. + * + * The default value for "unhealthy interval" is the same as "interval". + */ 'unhealthy_interval'?: (_google_protobuf_Duration); + /** + * The "unhealthy edge interval" is a special health check interval that is used for the first + * health check right after a host is marked as unhealthy. For subsequent health checks + * Envoy will shift back to using either "unhealthy interval" if present or the standard health + * check interval that is defined. + * + * The default value for "unhealthy edge interval" is the same as "unhealthy interval". + */ 'unhealthy_edge_interval'?: (_google_protobuf_Duration); + /** + * The "healthy edge interval" is a special health check interval that is used for the first + * health check right after a host is marked as healthy. For subsequent health checks + * Envoy will shift back to using the standard health check interval that is defined. + * + * The default value for "healthy edge interval" is the same as the default interval. + */ 'healthy_edge_interval'?: (_google_protobuf_Duration); + /** + * Specifies the path to the :ref:`health check event log `. + * If empty, no event log will be written. + */ 'event_log_path'?: (string); + /** + * An optional jitter amount as a percentage of interval_ms. If specified, + * during every interval Envoy will add interval_ms * + * interval_jitter_percent / 100 to the wait time. + * + * If interval_jitter_ms and interval_jitter_percent are both set, both of + * them will be used to increase the wait time. + */ 'interval_jitter_percent'?: (number); + /** + * If set to true, health check failure events will always be logged. If set to false, only the + * initial health check failure event will be logged. + * The default value is false. + */ 'always_log_health_check_failures'?: (boolean); + /** + * An optional jitter amount in milliseconds. If specified, Envoy will start health + * checking after for a random time in ms between 0 and initial_jitter. This only + * applies to the first health check. + */ 'initial_jitter'?: (_google_protobuf_Duration); + /** + * This allows overriding the cluster TLS settings, just for health check connections. + */ 'tls_options'?: (_envoy_api_v2_core_HealthCheck_TlsOptions); + /** + * [#not-implemented-hide:] + * The gRPC service for the health check event service. + * If empty, health check events won't be sent to a remote endpoint. + */ 'event_service'?: (_envoy_api_v2_core_EventServiceConfig); 'health_checker'?: "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } +/** + * [#next-free-field: 23] + */ export interface HealthCheck__Output { + /** + * The time to wait for a health check response. If the timeout is reached the + * health check attempt will be considered a failure. + */ 'timeout': (_google_protobuf_Duration__Output); + /** + * The interval between health checks. + */ 'interval': (_google_protobuf_Duration__Output); + /** + * An optional jitter amount in milliseconds. If specified, during every + * interval Envoy will add interval_jitter to the wait time. + */ 'interval_jitter': (_google_protobuf_Duration__Output); + /** + * The number of unhealthy health checks required before a host is marked + * unhealthy. Note that for *http* health checking if a host responds with 503 + * this threshold is ignored and the host is considered unhealthy immediately. + */ 'unhealthy_threshold': (_google_protobuf_UInt32Value__Output); + /** + * The number of healthy health checks required before a host is marked + * healthy. Note that during startup, only a single successful health check is + * required to mark a host healthy. + */ 'healthy_threshold': (_google_protobuf_UInt32Value__Output); + /** + * [#not-implemented-hide:] Non-serving port for health checking. + */ 'alt_port': (_google_protobuf_UInt32Value__Output); + /** + * Reuse health check connection between health checks. Default is true. + */ 'reuse_connection': (_google_protobuf_BoolValue__Output); + /** + * HTTP health check. + */ 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output); + /** + * TCP health check. + */ 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output); + /** + * gRPC health check. + */ 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output); + /** + * The "no traffic interval" is a special health check interval that is used when a cluster has + * never had traffic routed to it. This lower interval allows cluster information to be kept up to + * date, without sending a potentially large amount of active health checking traffic for no + * reason. Once a cluster has been used for traffic routing, Envoy will shift back to using the + * standard health check interval that is defined. Note that this interval takes precedence over + * any other. + * + * The default value for "no traffic interval" is 60 seconds. + */ 'no_traffic_interval': (_google_protobuf_Duration__Output); + /** + * Custom health check. + */ 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output); + /** + * The "unhealthy interval" is a health check interval that is used for hosts that are marked as + * unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the + * standard health check interval that is defined. + * + * The default value for "unhealthy interval" is the same as "interval". + */ 'unhealthy_interval': (_google_protobuf_Duration__Output); + /** + * The "unhealthy edge interval" is a special health check interval that is used for the first + * health check right after a host is marked as unhealthy. For subsequent health checks + * Envoy will shift back to using either "unhealthy interval" if present or the standard health + * check interval that is defined. + * + * The default value for "unhealthy edge interval" is the same as "unhealthy interval". + */ 'unhealthy_edge_interval': (_google_protobuf_Duration__Output); + /** + * The "healthy edge interval" is a special health check interval that is used for the first + * health check right after a host is marked as healthy. For subsequent health checks + * Envoy will shift back to using the standard health check interval that is defined. + * + * The default value for "healthy edge interval" is the same as the default interval. + */ 'healthy_edge_interval': (_google_protobuf_Duration__Output); + /** + * Specifies the path to the :ref:`health check event log `. + * If empty, no event log will be written. + */ 'event_log_path': (string); + /** + * An optional jitter amount as a percentage of interval_ms. If specified, + * during every interval Envoy will add interval_ms * + * interval_jitter_percent / 100 to the wait time. + * + * If interval_jitter_ms and interval_jitter_percent are both set, both of + * them will be used to increase the wait time. + */ 'interval_jitter_percent': (number); + /** + * If set to true, health check failure events will always be logged. If set to false, only the + * initial health check failure event will be logged. + * The default value is false. + */ 'always_log_health_check_failures': (boolean); + /** + * An optional jitter amount in milliseconds. If specified, Envoy will start health + * checking after for a random time in ms between 0 and initial_jitter. This only + * applies to the first health check. + */ 'initial_jitter': (_google_protobuf_Duration__Output); + /** + * This allows overriding the cluster TLS settings, just for health check connections. + */ 'tls_options': (_envoy_api_v2_core_HealthCheck_TlsOptions__Output); + /** + * [#not-implemented-hide:] + * The gRPC service for the health check event service. + * If empty, health check events won't be sent to a remote endpoint. + */ 'event_service': (_envoy_api_v2_core_EventServiceConfig__Output); 'health_checker': "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts index a92dde214..e1d572fa4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts @@ -1,10 +1,36 @@ // Original file: deps/envoy-api/envoy/api/v2/core/health_check.proto +/** + * Endpoint health status. + */ export enum HealthStatus { + /** + * The health status is not known. This is interpreted by Envoy as *HEALTHY*. + */ UNKNOWN = 0, + /** + * Healthy. + */ HEALTHY = 1, + /** + * Unhealthy. + */ UNHEALTHY = 2, + /** + * Connection draining in progress. E.g., + * ``_ + * or + * ``_. + * This is interpreted by Envoy as *UNHEALTHY*. + */ DRAINING = 3, + /** + * Health check timed out. This is part of HDS and is interpreted by Envoy as + * *UNHEALTHY*. + */ TIMEOUT = 4, + /** + * Degraded. + */ DEGRADED = 5, } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts index 566497ce3..13abc9ec4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts @@ -3,11 +3,25 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat { + /** + * Formats the header by proper casing words: the first character and any character following + * a special character will be capitalized if it's an alpha character. For example, + * "content-type" becomes "Content-Type", and "foo$b#$are" becomes "Foo$B#$Are". + * Note that while this results in most headers following conventional casing, certain headers + * are not covered. For example, the "TE" header will be formatted as "Te". + */ 'proper_case_words'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords); 'header_format'?: "proper_case_words"; } export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output { + /** + * Formats the header by proper casing words: the first character and any character following + * a special character will be capitalized if it's an alpha character. For example, + * "content-type" becomes "Content-Type", and "foo$b#$are" becomes "Foo$B#$Are". + * Note that while this results in most headers following conventional casing, certain headers + * are not covered. For example, the "TE" header will be formatted as "Te". + */ 'proper_case_words'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output); 'header_format': "proper_case_words"; } @@ -18,18 +32,88 @@ export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperC export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output { } +/** + * [#next-free-field: 6] + */ export interface Http1ProtocolOptions { + /** + * Handle HTTP requests with absolute URLs in the requests. These requests + * are generally sent by clients to forward/explicit proxies. This allows clients to configure + * envoy as their HTTP proxy. In Unix, for example, this is typically done by setting the + * *http_proxy* environment variable. + */ 'allow_absolute_url'?: (_google_protobuf_BoolValue); + /** + * Handle incoming HTTP/1.0 and HTTP 0.9 requests. + * This is off by default, and not fully standards compliant. There is support for pre-HTTP/1.1 + * style connect logic, dechunking, and handling lack of client host iff + * *default_host_for_http_10* is configured. + */ 'accept_http_10'?: (boolean); + /** + * A default host for HTTP/1.0 requests. This is highly suggested if *accept_http_10* is true as + * Envoy does not otherwise support HTTP/1.0 without a Host header. + * This is a no-op if *accept_http_10* is not true. + */ 'default_host_for_http_10'?: (string); + /** + * Describes how the keys for response headers should be formatted. By default, all header keys + * are lower cased. + */ 'header_key_format'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat); + /** + * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. + * + * .. attention:: + * + * Note that this only happens when Envoy is chunk encoding which occurs when: + * - The request is HTTP/1.1. + * - Is neither a HEAD only request nor a HTTP Upgrade. + * - Not a response to a HEAD request. + * - The content length header is not present. + */ 'enable_trailers'?: (boolean); } +/** + * [#next-free-field: 6] + */ export interface Http1ProtocolOptions__Output { + /** + * Handle HTTP requests with absolute URLs in the requests. These requests + * are generally sent by clients to forward/explicit proxies. This allows clients to configure + * envoy as their HTTP proxy. In Unix, for example, this is typically done by setting the + * *http_proxy* environment variable. + */ 'allow_absolute_url': (_google_protobuf_BoolValue__Output); + /** + * Handle incoming HTTP/1.0 and HTTP 0.9 requests. + * This is off by default, and not fully standards compliant. There is support for pre-HTTP/1.1 + * style connect logic, dechunking, and handling lack of client host iff + * *default_host_for_http_10* is configured. + */ 'accept_http_10': (boolean); + /** + * A default host for HTTP/1.0 requests. This is highly suggested if *accept_http_10* is true as + * Envoy does not otherwise support HTTP/1.0 without a Host header. + * This is a no-op if *accept_http_10* is not true. + */ 'default_host_for_http_10': (string); + /** + * Describes how the keys for response headers should be formatted. By default, all header keys + * are lower cased. + */ 'header_key_format': (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output); + /** + * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. + * + * .. attention:: + * + * Note that this only happens when Envoy is chunk encoding which occurs when: + * - The request is HTTP/1.1. + * - Is neither a HEAD only request nor a HTTP Upgrade. + * - Not a response to a HEAD request. + * - The content length header is not present. + */ 'enable_trailers': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts index 69d62ff81..97208657d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts @@ -2,44 +2,324 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +/** + * Defines a parameter to be sent in the SETTINGS frame. + * See `RFC7540, sec. 6.5.1 `_ for details. + */ export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter { + /** + * The 16 bit parameter identifier. + */ 'identifier'?: (_google_protobuf_UInt32Value); + /** + * The 32 bit parameter value. + */ 'value'?: (_google_protobuf_UInt32Value); } +/** + * Defines a parameter to be sent in the SETTINGS frame. + * See `RFC7540, sec. 6.5.1 `_ for details. + */ export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Output { + /** + * The 16 bit parameter identifier. + */ 'identifier': (_google_protobuf_UInt32Value__Output); + /** + * The 32 bit parameter value. + */ 'value': (_google_protobuf_UInt32Value__Output); } +/** + * [#next-free-field: 14] + */ export interface Http2ProtocolOptions { + /** + * `Maximum table size `_ + * (in octets) that the encoder is permitted to use for the dynamic HPACK table. Valid values + * range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header + * compression. + */ 'hpack_table_size'?: (_google_protobuf_UInt32Value); + /** + * `Maximum concurrent streams `_ + * allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) + * and defaults to 2147483647. + * + * For upstream connections, this also limits how many streams Envoy will initiate concurrently + * on a single connection. If the limit is reached, Envoy may queue requests or establish + * additional connections (as allowed per circuit breaker limits). + */ 'max_concurrent_streams'?: (_google_protobuf_UInt32Value); + /** + * `Initial stream-level flow-control window + * `_ size. Valid values range from 65535 + * (2^16 - 1, HTTP/2 default) to 2147483647 (2^31 - 1, HTTP/2 maximum) and defaults to 268435456 + * (256 * 1024 * 1024). + * + * NOTE: 65535 is the initial window size from HTTP/2 spec. We only support increasing the default + * window size now, so it's also the minimum. + * + * This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the + * HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to + * stop the flow of data to the codec buffers. + */ 'initial_stream_window_size'?: (_google_protobuf_UInt32Value); + /** + * Similar to *initial_stream_window_size*, but for connection-level flow-control + * window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. + */ 'initial_connection_window_size'?: (_google_protobuf_UInt32Value); + /** + * Allows proxying Websocket and other upgrades over H2 connect. + */ 'allow_connect'?: (boolean); + /** + * [#not-implemented-hide:] Hiding until envoy has full metadata support. + * Still under implementation. DO NOT USE. + * + * Allows metadata. See [metadata + * docs](https://github.com/envoyproxy/envoy/blob/master/source/docs/h2_metadata.md) for more + * information. + */ 'allow_metadata'?: (boolean); + /** + * Limit the number of pending outbound downstream frames of all types (frames that are waiting to + * be written into the socket). Exceeding this limit triggers flood mitigation and connection is + * terminated. The ``http2.outbound_flood`` stat tracks the number of terminated connections due + * to flood mitigation. The default limit is 10000. + * [#comment:TODO: implement same limits for upstream outbound frames as well.] + */ 'max_outbound_frames'?: (_google_protobuf_UInt32Value); + /** + * Limit the number of pending outbound downstream frames of types PING, SETTINGS and RST_STREAM, + * preventing high memory utilization when receiving continuous stream of these frames. Exceeding + * this limit triggers flood mitigation and connection is terminated. The + * ``http2.outbound_control_flood`` stat tracks the number of terminated connections due to flood + * mitigation. The default limit is 1000. + * [#comment:TODO: implement same limits for upstream outbound frames as well.] + */ 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value); + /** + * Limit the number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA with an + * empty payload and no end stream flag. Those frames have no legitimate use and are abusive, but + * might be a result of a broken HTTP/2 implementation. The `http2.inbound_empty_frames_flood`` + * stat tracks the number of connections terminated due to flood mitigation. + * Setting this to 0 will terminate connection upon receiving first frame with an empty payload + * and no end stream flag. The default limit is 1. + * [#comment:TODO: implement same limits for upstream inbound frames as well.] + */ 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value); + /** + * Limit the number of inbound PRIORITY frames allowed per each opened stream. If the number + * of PRIORITY frames received over the lifetime of connection exceeds the value calculated + * using this formula:: + * + * max_inbound_priority_frames_per_stream * (1 + inbound_streams) + * + * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + * the number of connections terminated due to flood mitigation. The default limit is 100. + * [#comment:TODO: implement same limits for upstream inbound frames as well.] + */ 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value); + /** + * Limit the number of inbound WINDOW_UPDATE frames allowed per DATA frame sent. If the number + * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated + * using this formula:: + * + * 1 + 2 * (inbound_streams + + * max_inbound_window_update_frames_per_data_frame_sent * outbound_data_frames) + * + * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + * the number of connections terminated due to flood mitigation. The default limit is 10. + * Setting this to 1 should be enough to support HTTP/2 implementations with basic flow control, + * but more complex implementations that try to estimate available bandwidth require at least 2. + * [#comment:TODO: implement same limits for upstream inbound frames as well.] + */ 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value); + /** + * Allows invalid HTTP messaging and headers. When this option is disabled (default), then + * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, + * when this option is enabled, only the offending stream is terminated. + * + * See `RFC7540, sec. 8.1 `_ for details. + */ 'stream_error_on_invalid_http_messaging'?: (boolean); + /** + * [#not-implemented-hide:] + * Specifies SETTINGS frame parameters to be sent to the peer, with two exceptions: + * + * 1. SETTINGS_ENABLE_PUSH (0x2) is not configurable as HTTP/2 server push is not supported by + * Envoy. + * + * 2. SETTINGS_ENABLE_CONNECT_PROTOCOL (0x8) is only configurable through the named field + * 'allow_connect'. + * + * Note that custom parameters specified through this field can not also be set in the + * corresponding named parameters: + * + * .. code-block:: text + * + * ID Field Name + * ---------------- + * 0x1 hpack_table_size + * 0x3 max_concurrent_streams + * 0x4 initial_stream_window_size + * + * Collisions will trigger config validation failure on load/update. Likewise, inconsistencies + * between custom parameters with the same identifier will trigger a failure. + * + * See `IANA HTTP/2 Settings + * `_ for + * standardized identifiers. + */ 'custom_settings_parameters'?: (_envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter)[]; } +/** + * [#next-free-field: 14] + */ export interface Http2ProtocolOptions__Output { + /** + * `Maximum table size `_ + * (in octets) that the encoder is permitted to use for the dynamic HPACK table. Valid values + * range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header + * compression. + */ 'hpack_table_size': (_google_protobuf_UInt32Value__Output); + /** + * `Maximum concurrent streams `_ + * allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) + * and defaults to 2147483647. + * + * For upstream connections, this also limits how many streams Envoy will initiate concurrently + * on a single connection. If the limit is reached, Envoy may queue requests or establish + * additional connections (as allowed per circuit breaker limits). + */ 'max_concurrent_streams': (_google_protobuf_UInt32Value__Output); + /** + * `Initial stream-level flow-control window + * `_ size. Valid values range from 65535 + * (2^16 - 1, HTTP/2 default) to 2147483647 (2^31 - 1, HTTP/2 maximum) and defaults to 268435456 + * (256 * 1024 * 1024). + * + * NOTE: 65535 is the initial window size from HTTP/2 spec. We only support increasing the default + * window size now, so it's also the minimum. + * + * This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the + * HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to + * stop the flow of data to the codec buffers. + */ 'initial_stream_window_size': (_google_protobuf_UInt32Value__Output); + /** + * Similar to *initial_stream_window_size*, but for connection-level flow-control + * window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. + */ 'initial_connection_window_size': (_google_protobuf_UInt32Value__Output); + /** + * Allows proxying Websocket and other upgrades over H2 connect. + */ 'allow_connect': (boolean); + /** + * [#not-implemented-hide:] Hiding until envoy has full metadata support. + * Still under implementation. DO NOT USE. + * + * Allows metadata. See [metadata + * docs](https://github.com/envoyproxy/envoy/blob/master/source/docs/h2_metadata.md) for more + * information. + */ 'allow_metadata': (boolean); + /** + * Limit the number of pending outbound downstream frames of all types (frames that are waiting to + * be written into the socket). Exceeding this limit triggers flood mitigation and connection is + * terminated. The ``http2.outbound_flood`` stat tracks the number of terminated connections due + * to flood mitigation. The default limit is 10000. + * [#comment:TODO: implement same limits for upstream outbound frames as well.] + */ 'max_outbound_frames': (_google_protobuf_UInt32Value__Output); + /** + * Limit the number of pending outbound downstream frames of types PING, SETTINGS and RST_STREAM, + * preventing high memory utilization when receiving continuous stream of these frames. Exceeding + * this limit triggers flood mitigation and connection is terminated. The + * ``http2.outbound_control_flood`` stat tracks the number of terminated connections due to flood + * mitigation. The default limit is 1000. + * [#comment:TODO: implement same limits for upstream outbound frames as well.] + */ 'max_outbound_control_frames': (_google_protobuf_UInt32Value__Output); + /** + * Limit the number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA with an + * empty payload and no end stream flag. Those frames have no legitimate use and are abusive, but + * might be a result of a broken HTTP/2 implementation. The `http2.inbound_empty_frames_flood`` + * stat tracks the number of connections terminated due to flood mitigation. + * Setting this to 0 will terminate connection upon receiving first frame with an empty payload + * and no end stream flag. The default limit is 1. + * [#comment:TODO: implement same limits for upstream inbound frames as well.] + */ 'max_consecutive_inbound_frames_with_empty_payload': (_google_protobuf_UInt32Value__Output); + /** + * Limit the number of inbound PRIORITY frames allowed per each opened stream. If the number + * of PRIORITY frames received over the lifetime of connection exceeds the value calculated + * using this formula:: + * + * max_inbound_priority_frames_per_stream * (1 + inbound_streams) + * + * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + * the number of connections terminated due to flood mitigation. The default limit is 100. + * [#comment:TODO: implement same limits for upstream inbound frames as well.] + */ 'max_inbound_priority_frames_per_stream': (_google_protobuf_UInt32Value__Output); + /** + * Limit the number of inbound WINDOW_UPDATE frames allowed per DATA frame sent. If the number + * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated + * using this formula:: + * + * 1 + 2 * (inbound_streams + + * max_inbound_window_update_frames_per_data_frame_sent * outbound_data_frames) + * + * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + * the number of connections terminated due to flood mitigation. The default limit is 10. + * Setting this to 1 should be enough to support HTTP/2 implementations with basic flow control, + * but more complex implementations that try to estimate available bandwidth require at least 2. + * [#comment:TODO: implement same limits for upstream inbound frames as well.] + */ 'max_inbound_window_update_frames_per_data_frame_sent': (_google_protobuf_UInt32Value__Output); + /** + * Allows invalid HTTP messaging and headers. When this option is disabled (default), then + * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, + * when this option is enabled, only the offending stream is terminated. + * + * See `RFC7540, sec. 8.1 `_ for details. + */ 'stream_error_on_invalid_http_messaging': (boolean); + /** + * [#not-implemented-hide:] + * Specifies SETTINGS frame parameters to be sent to the peer, with two exceptions: + * + * 1. SETTINGS_ENABLE_PUSH (0x2) is not configurable as HTTP/2 server push is not supported by + * Envoy. + * + * 2. SETTINGS_ENABLE_CONNECT_PROTOCOL (0x8) is only configurable through the named field + * 'allow_connect'. + * + * Note that custom parameters specified through this field can not also be set in the + * corresponding named parameters: + * + * .. code-block:: text + * + * ID Field Name + * ---------------- + * 0x1 hpack_table_size + * 0x3 max_concurrent_streams + * 0x4 initial_stream_window_size + * + * Collisions will trigger config validation failure on load/update. Likewise, inconsistencies + * between custom parameters with the same identifier will trigger a failure. + * + * See `IANA HTTP/2 Settings + * `_ for + * standardized identifiers. + */ 'custom_settings_parameters': (_envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts index 559140a1f..026e236e7 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts @@ -5,24 +5,122 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +/** + * Action to take when Envoy receives client request with header names containing underscore + * characters. + * Underscore character is allowed in header names by the RFC-7230 and this behavior is implemented + * as a security measure due to systems that treat '_' and '-' as interchangeable. Envoy by default allows client request headers with underscore + * characters. + */ export enum _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction { + /** + * Allow headers with underscores. This is the default behavior. + */ ALLOW = 0, + /** + * Reject client request. HTTP/1 requests are rejected with the 400 status. HTTP/2 requests + * end with the stream reset. The "httpN.requests_rejected_with_underscores_in_headers" counter + * is incremented for each rejected request. + */ REJECT_REQUEST = 1, + /** + * Drop the header with name containing underscores. The header is dropped before the filter chain is + * invoked and as such filters will not see dropped headers. The + * "httpN.dropped_headers_with_underscores" is incremented for each dropped header. + */ DROP_HEADER = 2, } +/** + * [#next-free-field: 6] + */ export interface HttpProtocolOptions { + /** + * The idle timeout for connections. The idle timeout is defined as the + * period in which there are no active requests. When the + * idle timeout is reached the connection will be closed. If the connection is an HTTP/2 + * downstream connection a drain sequence will occur prior to closing the connection, see + * :ref:`drain_timeout + * `. + * Note that request based timeouts mean that HTTP/2 PINGs will not keep the connection alive. + * If not specified, this defaults to 1 hour. To disable idle timeouts explicitly set this to 0. + * + * .. warning:: + * Disabling this timeout has a highly likelihood of yielding connection leaks due to lost TCP + * FIN packets, etc. + */ 'idle_timeout'?: (_google_protobuf_Duration); + /** + * The maximum number of headers. If unconfigured, the default + * maximum number of request headers allowed is 100. Requests that exceed this limit will receive + * a 431 response for HTTP/1.x and cause a stream reset for HTTP/2. + */ 'max_headers_count'?: (_google_protobuf_UInt32Value); + /** + * The maximum duration of a connection. The duration is defined as a period since a connection + * was established. If not set, there is no max duration. When max_connection_duration is reached + * the connection will be closed. Drain sequence will occur prior to closing the connection if + * if's applicable. See :ref:`drain_timeout + * `. + * Note: not implemented for upstream connections. + */ 'max_connection_duration'?: (_google_protobuf_Duration); + /** + * Total duration to keep alive an HTTP request/response stream. If the time limit is reached the stream will be + * reset independent of any other timeouts. If not specified, this value is not set. + */ 'max_stream_duration'?: (_google_protobuf_Duration); + /** + * Action to take when a client request with a header name containing underscore characters is received. + * If this setting is not specified, the value defaults to ALLOW. + * Note: upstream responses are not affected by this setting. + */ 'headers_with_underscores_action'?: (_envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction | keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); } +/** + * [#next-free-field: 6] + */ export interface HttpProtocolOptions__Output { + /** + * The idle timeout for connections. The idle timeout is defined as the + * period in which there are no active requests. When the + * idle timeout is reached the connection will be closed. If the connection is an HTTP/2 + * downstream connection a drain sequence will occur prior to closing the connection, see + * :ref:`drain_timeout + * `. + * Note that request based timeouts mean that HTTP/2 PINGs will not keep the connection alive. + * If not specified, this defaults to 1 hour. To disable idle timeouts explicitly set this to 0. + * + * .. warning:: + * Disabling this timeout has a highly likelihood of yielding connection leaks due to lost TCP + * FIN packets, etc. + */ 'idle_timeout': (_google_protobuf_Duration__Output); + /** + * The maximum number of headers. If unconfigured, the default + * maximum number of request headers allowed is 100. Requests that exceed this limit will receive + * a 431 response for HTTP/1.x and cause a stream reset for HTTP/2. + */ 'max_headers_count': (_google_protobuf_UInt32Value__Output); + /** + * The maximum duration of a connection. The duration is defined as a period since a connection + * was established. If not set, there is no max duration. When max_connection_duration is reached + * the connection will be closed. Drain sequence will occur prior to closing the connection if + * if's applicable. See :ref:`drain_timeout + * `. + * Note: not implemented for upstream connections. + */ 'max_connection_duration': (_google_protobuf_Duration__Output); + /** + * Total duration to keep alive an HTTP request/response stream. If the time limit is reached the stream will be + * reset independent of any other timeouts. If not specified, this value is not set. + */ 'max_stream_duration': (_google_protobuf_Duration__Output); + /** + * Action to take when a client request with a header name containing underscore characters is received. + * If this setting is not specified, the value defaults to ALLOW. + * Note: upstream responses are not affected by this setting. + */ 'headers_with_underscores_action': (keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts index 4e0b1f86f..998f8816c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts @@ -2,16 +2,78 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +/** + * Envoy external URI descriptor + */ export interface HttpUri { + /** + * The HTTP server URI. It should be a full FQDN with protocol, host and path. + * + * Example: + * + * .. code-block:: yaml + * + * uri: https://www.googleapis.com/oauth2/v1/certs + */ 'uri'?: (string); + /** + * A cluster is created in the Envoy "cluster_manager" config + * section. This field specifies the cluster name. + * + * Example: + * + * .. code-block:: yaml + * + * cluster: jwks_cluster + */ 'cluster'?: (string); + /** + * Sets the maximum duration in milliseconds that a response can take to arrive upon request. + */ 'timeout'?: (_google_protobuf_Duration); + /** + * Specify how `uri` is to be fetched. Today, this requires an explicit + * cluster, but in the future we may support dynamic cluster creation or + * inline DNS resolution. See `issue + * `_. + */ 'http_upstream_type'?: "cluster"; } +/** + * Envoy external URI descriptor + */ export interface HttpUri__Output { + /** + * The HTTP server URI. It should be a full FQDN with protocol, host and path. + * + * Example: + * + * .. code-block:: yaml + * + * uri: https://www.googleapis.com/oauth2/v1/certs + */ 'uri': (string); + /** + * A cluster is created in the Envoy "cluster_manager" config + * section. This field specifies the cluster name. + * + * Example: + * + * .. code-block:: yaml + * + * cluster: jwks_cluster + */ 'cluster'?: (string); + /** + * Sets the maximum duration in milliseconds that a response can take to arrive upon request. + */ 'timeout': (_google_protobuf_Duration__Output); + /** + * Specify how `uri` is to be fetched. Today, this requires an explicit + * cluster, but in the future we may support dynamic cluster creation or + * inline DNS resolution. See `issue + * `_. + */ 'http_upstream_type': "cluster"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts index c17f07413..49fb232a4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts @@ -1,14 +1,56 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export interface Locality { + /** + * Region this :ref:`zone ` belongs to. + */ 'region'?: (string); + /** + * Defines the local service zone where Envoy is running. Though optional, it + * should be set if discovery service routing is used and the discovery + * service exposes :ref:`zone data `, + * either in this message or via :option:`--service-zone`. The meaning of zone + * is context dependent, e.g. `Availability Zone (AZ) + * `_ + * on AWS, `Zone `_ on + * GCP, etc. + */ 'zone'?: (string); + /** + * When used for locality of upstream hosts, this field further splits zone + * into smaller chunks of sub-zones so they can be load balanced + * independently. + */ 'sub_zone'?: (string); } +/** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export interface Locality__Output { + /** + * Region this :ref:`zone ` belongs to. + */ 'region': (string); + /** + * Defines the local service zone where Envoy is running. Though optional, it + * should be set if discovery service routing is used and the discovery + * service exposes :ref:`zone data `, + * either in this message or via :option:`--service-zone`. The meaning of zone + * is context dependent, e.g. `Availability Zone (AZ) + * `_ + * on AWS, `Zone `_ on + * GCP, etc. + */ 'zone': (string); + /** + * When used for locality of upstream hosts, this field further splits zone + * into smaller chunks of sub-zones so they can be load balanced + * independently. + */ 'sub_zone': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts index dfc0406d9..1774252e5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts @@ -2,10 +2,66 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +/** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export interface Metadata { + /** + * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* + * namespace is reserved for Envoy's built-in filters. + */ 'filter_metadata'?: (_google_protobuf_Struct); } +/** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export interface Metadata__Output { + /** + * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* + * namespace is reserved for Envoy's built-in filters. + */ 'filter_metadata': (_google_protobuf_Struct__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts index d20d3ec6f..27a156c66 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts @@ -6,32 +6,168 @@ import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output a import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from '../../../../envoy/api/v2/core/Extension'; import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +/** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export interface Node { + /** + * An opaque node identifier for the Envoy node. This also provides the local + * service node name. It should be set if any of the following features are + * used: :ref:`statsd `, :ref:`CDS + * `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-node`. + */ 'id'?: (string); + /** + * Defines the local service cluster name where Envoy is running. Though + * optional, it should be set if any of the following features are used: + * :ref:`statsd `, :ref:`health check cluster + * verification + * `, + * :ref:`runtime override directory `, + * :ref:`user agent addition + * `, + * :ref:`HTTP global rate limiting `, + * :ref:`CDS `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-cluster`. + */ 'cluster'?: (string); + /** + * Opaque metadata extending the node identifier. Envoy will pass this + * directly to the management server. + */ 'metadata'?: (_google_protobuf_Struct); + /** + * Locality specifying where the Envoy instance is running. + */ 'locality'?: (_envoy_api_v2_core_Locality); + /** + * This is motivated by informing a management server during canary which + * version of Envoy is being tested in a heterogeneous fleet. This will be set + * by Envoy in management server RPCs. + * This field is deprecated in favor of the user_agent_name and user_agent_version values. + */ 'build_version'?: (string); + /** + * Free-form string that identifies the entity requesting config. + * E.g. "envoy" or "grpc" + */ 'user_agent_name'?: (string); + /** + * Free-form string that identifies the version of the entity requesting config. + * E.g. "1.12.2" or "abcd1234", or "SpecialEnvoyBuild" + */ 'user_agent_version'?: (string); + /** + * Structured version of the entity requesting config. + */ 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion); + /** + * List of extensions and their versions supported by the node. + */ 'extensions'?: (_envoy_api_v2_core_Extension)[]; + /** + * Client feature support list. These are well known features described + * in the Envoy API repository for a given major version of an API. Client features + * use reverse DNS naming scheme, for example `com.acme.feature`. + * See :ref:`the list of features ` that xDS client may + * support. + */ 'client_features'?: (string)[]; + /** + * Known listening ports on the node as a generic hint to the management server + * for filtering :ref:`listeners ` to be returned. For example, + * if there is a listener bound to port 80, the list can optionally contain the + * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. + */ 'listening_addresses'?: (_envoy_api_v2_core_Address)[]; 'user_agent_version_type'?: "user_agent_version"|"user_agent_build_version"; } +/** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export interface Node__Output { + /** + * An opaque node identifier for the Envoy node. This also provides the local + * service node name. It should be set if any of the following features are + * used: :ref:`statsd `, :ref:`CDS + * `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-node`. + */ 'id': (string); + /** + * Defines the local service cluster name where Envoy is running. Though + * optional, it should be set if any of the following features are used: + * :ref:`statsd `, :ref:`health check cluster + * verification + * `, + * :ref:`runtime override directory `, + * :ref:`user agent addition + * `, + * :ref:`HTTP global rate limiting `, + * :ref:`CDS `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-cluster`. + */ 'cluster': (string); + /** + * Opaque metadata extending the node identifier. Envoy will pass this + * directly to the management server. + */ 'metadata': (_google_protobuf_Struct__Output); + /** + * Locality specifying where the Envoy instance is running. + */ 'locality': (_envoy_api_v2_core_Locality__Output); + /** + * This is motivated by informing a management server during canary which + * version of Envoy is being tested in a heterogeneous fleet. This will be set + * by Envoy in management server RPCs. + * This field is deprecated in favor of the user_agent_name and user_agent_version values. + */ 'build_version': (string); + /** + * Free-form string that identifies the entity requesting config. + * E.g. "envoy" or "grpc" + */ 'user_agent_name': (string); + /** + * Free-form string that identifies the version of the entity requesting config. + * E.g. "1.12.2" or "abcd1234", or "SpecialEnvoyBuild" + */ 'user_agent_version'?: (string); + /** + * Structured version of the entity requesting config. + */ 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion__Output); + /** + * List of extensions and their versions supported by the node. + */ 'extensions': (_envoy_api_v2_core_Extension__Output)[]; + /** + * Client feature support list. These are well known features described + * in the Envoy API repository for a given major version of an API. Client features + * use reverse DNS naming scheme, for example `com.acme.feature`. + * See :ref:`the list of features ` that xDS client may + * support. + */ 'client_features': (string)[]; + /** + * Known listening ports on the node as a generic hint to the management server + * for filtering :ref:`listeners ` to be returned. For example, + * if there is a listener bound to port 80, the list can optionally contain the + * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. + */ 'listening_addresses': (_envoy_api_v2_core_Address__Output)[]; 'user_agent_version_type': "user_agent_version"|"user_agent_build_version"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts index 42ecc0aec..9e6cbb82d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts @@ -2,11 +2,29 @@ export interface Pipe { + /** + * Unix Domain Socket path. On Linux, paths starting with '@' will use the + * abstract namespace. The starting '@' is replaced by a null byte by Envoy. + * Paths starting with '@' will result in an error in environments other than + * Linux. + */ 'path'?: (string); + /** + * The mode for the Pipe. Not applicable for abstract sockets. + */ 'mode'?: (number); } export interface Pipe__Output { + /** + * Unix Domain Socket path. On Linux, paths starting with '@' will use the + * abstract namespace. The starting '@' is replaced by a null byte by Envoy. + * Paths starting with '@' will result in an error in environments other than + * Linux. + */ 'path': (string); + /** + * The mode for the Pipe. Not applicable for abstract sockets. + */ 'mode': (number); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts index e6b00f31c..bf52aaaf3 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts @@ -3,12 +3,34 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from '../../../../google/protobuf/DoubleValue'; +/** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export interface RateLimitSettings { + /** + * Maximum number of tokens to be used for rate limiting discovery request calls. If not set, a + * default value of 100 will be used. + */ 'max_tokens'?: (_google_protobuf_UInt32Value); + /** + * Rate at which tokens will be filled per second. If not set, a default fill rate of 10 tokens + * per second will be used. + */ 'fill_rate'?: (_google_protobuf_DoubleValue); } +/** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export interface RateLimitSettings__Output { + /** + * Maximum number of tokens to be used for rate limiting discovery request calls. If not set, a + * default value of 100 will be used. + */ 'max_tokens': (_google_protobuf_UInt32Value__Output); + /** + * Rate at which tokens will be filled per second. If not set, a default fill rate of 10 tokens + * per second will be used. + */ 'fill_rate': (_google_protobuf_DoubleValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts index c372e2265..c0ec51d75 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts @@ -3,14 +3,38 @@ import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from '../../../../envoy/api/v2/core/HttpUri'; import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from '../../../../envoy/api/v2/core/RetryPolicy'; +/** + * The message specifies how to fetch data from remote and how to verify it. + */ export interface RemoteDataSource { + /** + * The HTTP URI to fetch the remote data. + */ 'http_uri'?: (_envoy_api_v2_core_HttpUri); + /** + * SHA256 string for verifying data. + */ 'sha256'?: (string); + /** + * Retry policy for fetching remote data. + */ 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy); } +/** + * The message specifies how to fetch data from remote and how to verify it. + */ export interface RemoteDataSource__Output { + /** + * The HTTP URI to fetch the remote data. + */ 'http_uri': (_envoy_api_v2_core_HttpUri__Output); + /** + * SHA256 string for verifying data. + */ 'sha256': (string); + /** + * Retry policy for fetching remote data. + */ 'retry_policy': (_envoy_api_v2_core_RetryPolicy__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts index 5532045c1..029e9882d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts @@ -1,5 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * HTTP request method. + */ export enum RequestMethod { METHOD_UNSPECIFIED = 0, GET = 1, diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts index a18f83648..f3dc4bac1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts @@ -3,12 +3,36 @@ import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from '../../../../envoy/api/v2/core/BackoffStrategy'; import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +/** + * The message specifies the retry policy of remote data source when fetching fails. + */ export interface RetryPolicy { + /** + * Specifies parameters that control :ref:`retry backoff strategy `. + * This parameter is optional, in which case the default base interval is 1000 milliseconds. The + * default maximum interval is 10 times the base interval. + */ 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. + */ 'num_retries'?: (_google_protobuf_UInt32Value); } +/** + * The message specifies the retry policy of remote data source when fetching fails. + */ export interface RetryPolicy__Output { + /** + * Specifies parameters that control :ref:`retry backoff strategy `. + * This parameter is optional, in which case the default base interval is 1000 milliseconds. The + * default maximum interval is 10 times the base interval. + */ 'retry_back_off': (_envoy_api_v2_core_BackoffStrategy__Output); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. + */ 'num_retries': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts index d386146e5..5937fceb2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts @@ -1,5 +1,14 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ export enum RoutingPriority { DEFAULT = 0, HIGH = 1, diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts index 177749784..8d9aba3e0 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts @@ -1,12 +1,30 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Runtime derived double with a default when not specified. + */ export interface RuntimeDouble { + /** + * Default value if runtime value is not available. + */ 'default_value'?: (number | string); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ 'runtime_key'?: (string); } +/** + * Runtime derived double with a default when not specified. + */ export interface RuntimeDouble__Output { + /** + * Default value if runtime value is not available. + */ 'default_value': (number | string); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ 'runtime_key': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts index 897751270..fd88cf9df 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts @@ -2,12 +2,34 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +/** + * Runtime derived bool with a default when not specified. + */ export interface RuntimeFeatureFlag { + /** + * Default value if runtime value is not available. + */ 'default_value'?: (_google_protobuf_BoolValue); + /** + * Runtime key to get value for comparison. This value is used if defined. The boolean value must + * be represented via its + * `canonical JSON encoding `_. + */ 'runtime_key'?: (string); } +/** + * Runtime derived bool with a default when not specified. + */ export interface RuntimeFeatureFlag__Output { + /** + * Default value if runtime value is not available. + */ 'default_value': (_google_protobuf_BoolValue__Output); + /** + * Runtime key to get value for comparison. This value is used if defined. The boolean value must + * be represented via its + * `canonical JSON encoding `_. + */ 'runtime_key': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts index b6bb48d62..222c1b9d7 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts @@ -2,12 +2,48 @@ import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; +/** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export interface RuntimeFractionalPercent { + /** + * Default value if the runtime value's for the numerator/denominator keys are not available. + */ 'default_value'?: (_envoy_type_FractionalPercent); + /** + * Runtime key for a YAML representation of a FractionalPercent. + */ 'runtime_key'?: (string); } +/** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export interface RuntimeFractionalPercent__Output { + /** + * Default value if the runtime value's for the numerator/denominator keys are not available. + */ 'default_value': (_envoy_type_FractionalPercent__Output); + /** + * Runtime key for a YAML representation of a FractionalPercent. + */ 'runtime_key': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts index bf6f7b903..72e8972a4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts @@ -1,12 +1,30 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Runtime derived uint32 with a default when not specified. + */ export interface RuntimeUInt32 { + /** + * Default value if runtime value is not available. + */ 'default_value'?: (number); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ 'runtime_key'?: (string); } +/** + * Runtime derived uint32 with a default when not specified. + */ export interface RuntimeUInt32__Output { + /** + * Default value if runtime value is not available. + */ 'default_value': (number); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ 'runtime_key': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts index 8551f7832..144cfdf5a 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts @@ -1,8 +1,20 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +/** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export interface SelfConfigSource { } +/** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export interface SelfConfigSource__Output { } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts index 415cf082c..f81c981c1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts @@ -8,22 +8,90 @@ export enum _envoy_api_v2_core_SocketAddress_Protocol { UDP = 1, } +/** + * [#next-free-field: 7] + */ export interface SocketAddress { 'protocol'?: (_envoy_api_v2_core_SocketAddress_Protocol | keyof typeof _envoy_api_v2_core_SocketAddress_Protocol); + /** + * The address for this socket. :ref:`Listeners ` will bind + * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` + * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: + * It is possible to distinguish a Listener address via the prefix/suffix matching + * in :ref:`FilterChainMatch `.] When used + * within an upstream :ref:`BindConfig `, the address + * controls the source address of outbound connections. For :ref:`clusters + * `, the cluster type determines whether the + * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS + * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized + * via :ref:`resolver_name `. + */ 'address'?: (string); 'port_value'?: (number); + /** + * This is only valid if :ref:`resolver_name + * ` is specified below and the + * named resolver is capable of named port resolution. + */ 'named_port'?: (string); + /** + * The name of the custom resolver. This must have been registered with Envoy. If + * this is empty, a context dependent default applies. If the address is a concrete + * IP address, no resolution will occur. If address is a hostname this + * should be set for resolution other than DNS. Specifying a custom resolver with + * *STRICT_DNS* or *LOGICAL_DNS* will generate an error at runtime. + */ 'resolver_name'?: (string); + /** + * When binding to an IPv6 address above, this enables `IPv4 compatibility + * `_. Binding to ``::`` will + * allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into + * IPv6 space as ``::FFFF:``. + */ 'ipv4_compat'?: (boolean); 'port_specifier'?: "port_value"|"named_port"; } +/** + * [#next-free-field: 7] + */ export interface SocketAddress__Output { 'protocol': (keyof typeof _envoy_api_v2_core_SocketAddress_Protocol); + /** + * The address for this socket. :ref:`Listeners ` will bind + * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` + * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: + * It is possible to distinguish a Listener address via the prefix/suffix matching + * in :ref:`FilterChainMatch `.] When used + * within an upstream :ref:`BindConfig `, the address + * controls the source address of outbound connections. For :ref:`clusters + * `, the cluster type determines whether the + * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS + * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized + * via :ref:`resolver_name `. + */ 'address': (string); 'port_value'?: (number); + /** + * This is only valid if :ref:`resolver_name + * ` is specified below and the + * named resolver is capable of named port resolution. + */ 'named_port'?: (string); + /** + * The name of the custom resolver. This must have been registered with Envoy. If + * this is empty, a context dependent default applies. If the address is a concrete + * IP address, no resolution will occur. If address is a hostname this + * should be set for resolution other than DNS. Specifying a custom resolver with + * *STRICT_DNS* or *LOGICAL_DNS* will generate an error at runtime. + */ 'resolver_name': (string); + /** + * When binding to an IPv6 address above, this enables `IPv4 compatibility + * `_. Binding to ``::`` will + * allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into + * IPv6 space as ``::FFFF:``. + */ 'ipv4_compat': (boolean); 'port_specifier': "port_value"|"named_port"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts index 0319328ff..0c4a4e1ca 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts @@ -5,27 +5,86 @@ import { Long } from '@grpc/proto-loader'; // Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto export enum _envoy_api_v2_core_SocketOption_SocketState { + /** + * Socket options are applied after socket creation but before binding the socket to a port + */ STATE_PREBIND = 0, + /** + * Socket options are applied after binding the socket to a port but before calling listen() + */ STATE_BOUND = 1, + /** + * Socket options are applied after calling listen() + */ STATE_LISTENING = 2, } +/** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export interface SocketOption { + /** + * An optional name to give this socket option for debugging, etc. + * Uniqueness is not required and no special meaning is assumed. + */ 'description'?: (string); + /** + * Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP + */ 'level'?: (number | string | Long); + /** + * The numeric name as passed to setsockopt + */ 'name'?: (number | string | Long); + /** + * Because many sockopts take an int value. + */ 'int_value'?: (number | string | Long); + /** + * Otherwise it's a byte buffer. + */ 'buf_value'?: (Buffer | Uint8Array | string); + /** + * The state in which the option will be applied. When used in BindConfig + * STATE_PREBIND is currently the only valid value. + */ 'state'?: (_envoy_api_v2_core_SocketOption_SocketState | keyof typeof _envoy_api_v2_core_SocketOption_SocketState); 'value'?: "int_value"|"buf_value"; } +/** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export interface SocketOption__Output { + /** + * An optional name to give this socket option for debugging, etc. + * Uniqueness is not required and no special meaning is assumed. + */ 'description': (string); + /** + * Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP + */ 'level': (string); + /** + * The numeric name as passed to setsockopt + */ 'name': (string); + /** + * Because many sockopts take an int value. + */ 'int_value'?: (string); + /** + * Otherwise it's a byte buffer. + */ 'buf_value'?: (Buffer); + /** + * The state in which the option will be applied. When used in BindConfig + * STATE_PREBIND is currently the only valid value. + */ 'state': (keyof typeof _envoy_api_v2_core_SocketOption_SocketState); 'value': "int_value"|"buf_value"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts index dd77d08bd..9318af4e5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts @@ -3,13 +3,41 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; export interface TcpKeepalive { + /** + * Maximum number of keepalive probes to send without response before deciding + * the connection is dead. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 9.) + */ 'keepalive_probes'?: (_google_protobuf_UInt32Value); + /** + * The number of seconds a connection needs to be idle before keep-alive probes + * start being sent. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 7200s (i.e., 2 hours.) + */ 'keepalive_time'?: (_google_protobuf_UInt32Value); + /** + * The number of seconds between keep-alive probes. Default is to use the OS + * level configuration (unless overridden, Linux defaults to 75s.) + */ 'keepalive_interval'?: (_google_protobuf_UInt32Value); } export interface TcpKeepalive__Output { + /** + * Maximum number of keepalive probes to send without response before deciding + * the connection is dead. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 9.) + */ 'keepalive_probes': (_google_protobuf_UInt32Value__Output); + /** + * The number of seconds a connection needs to be idle before keep-alive probes + * start being sent. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 7200s (i.e., 2 hours.) + */ 'keepalive_time': (_google_protobuf_UInt32Value__Output); + /** + * The number of seconds between keep-alive probes. Default is to use the OS + * level configuration (unless overridden, Linux defaults to 75s.) + */ 'keepalive_interval': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts index 602fae7af..bb7afc1d1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts @@ -1,8 +1,14 @@ // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +/** + * [#not-implemented-hide:] + */ export interface TcpProtocolOptions { } +/** + * [#not-implemented-hide:] + */ export interface TcpProtocolOptions__Output { } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts index 50f4bb28c..41cf36523 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts @@ -1,7 +1,19 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto +/** + * Identifies the direction of the traffic relative to the local Envoy. + */ export enum TrafficDirection { + /** + * Default option is unspecified. + */ UNSPECIFIED = 0, + /** + * The transport is used for incoming traffic. + */ INBOUND = 1, + /** + * The transport is used for outgoing traffic. + */ OUTBOUND = 2, } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts index 7062f81e2..3034df987 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts @@ -3,16 +3,44 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +/** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export interface TransportSocket { + /** + * The name of the transport socket to instantiate. The name must match a supported transport + * socket implementation. + */ 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Implementation specific configuration which depends on the implementation being instantiated. + * See the supported transport socket implementations for further documentation. + */ 'config_type'?: "config"|"typed_config"; } +/** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export interface TransportSocket__Output { + /** + * The name of the transport socket to instantiate. The name must match a supported transport + * socket implementation. + */ 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Implementation specific configuration which depends on the implementation being instantiated. + * See the supported transport socket implementations for further documentation. + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts index d4e492413..9c55560e8 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts @@ -2,11 +2,33 @@ export interface UpstreamHttpProtocolOptions { + /** + * Set transport socket `SNI `_ for new + * upstream connections based on the downstream HTTP host/authority header, as seen by the + * :ref:`router filter `. + */ 'auto_sni'?: (boolean); + /** + * Automatic validate upstream presented certificate for new upstream connections based on the + * downstream HTTP host/authority header, as seen by the + * :ref:`router filter `. + * This field is intended to set with `auto_sni` field. + */ 'auto_san_validation'?: (boolean); } export interface UpstreamHttpProtocolOptions__Output { + /** + * Set transport socket `SNI `_ for new + * upstream connections based on the downstream HTTP host/authority header, as seen by the + * :ref:`router filter `. + */ 'auto_sni': (boolean); + /** + * Automatic validate upstream presented certificate for new upstream connections based on the + * downstream HTTP host/authority header, as seen by the + * :ref:`router filter `. + * This field is intended to set with `auto_sni` field. + */ 'auto_san_validation': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts index bdb23b50c..e66fb182b 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts @@ -2,24 +2,118 @@ import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +/** + * The optional health check configuration. + */ export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig { + /** + * Optional alternative health check port value. + * + * By default the health check address port of an upstream host is the same + * as the host's serving address port. This provides an alternative health + * check port. Setting this with a non-zero value allows an upstream host + * to have different health check address port. + */ 'port_value'?: (number); + /** + * By default, the host header for L7 health checks is controlled by cluster level configuration + * (see: :ref:`host ` and + * :ref:`authority `). Setting this + * to a non-empty value allows overriding the cluster level configuration for a specific + * endpoint. + */ 'hostname'?: (string); } +/** + * The optional health check configuration. + */ export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output { + /** + * Optional alternative health check port value. + * + * By default the health check address port of an upstream host is the same + * as the host's serving address port. This provides an alternative health + * check port. Setting this with a non-zero value allows an upstream host + * to have different health check address port. + */ 'port_value': (number); + /** + * By default, the host header for L7 health checks is controlled by cluster level configuration + * (see: :ref:`host ` and + * :ref:`authority `). Setting this + * to a non-empty value allows overriding the cluster level configuration for a specific + * endpoint. + */ 'hostname': (string); } +/** + * Upstream host identifier. + */ export interface Endpoint { + /** + * The upstream host address. + * + * .. attention:: + * + * The form of host address depends on the given cluster type. For STATIC or EDS, + * it is expected to be a direct IP address (or something resolvable by the + * specified :ref:`resolver ` + * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, + * and will be resolved via DNS. + */ 'address'?: (_envoy_api_v2_core_Address); + /** + * The optional health check configuration is used as configuration for the + * health checker to contact the health checked host. + * + * .. attention:: + * + * This takes into effect only for upstream clusters with + * :ref:`active health checking ` enabled. + */ 'health_check_config'?: (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig); + /** + * The hostname associated with this endpoint. This hostname is not used for routing or address + * resolution. If provided, it will be associated with the endpoint, and can be used for features + * that require a hostname, like + * :ref:`auto_host_rewrite `. + */ 'hostname'?: (string); } +/** + * Upstream host identifier. + */ export interface Endpoint__Output { + /** + * The upstream host address. + * + * .. attention:: + * + * The form of host address depends on the given cluster type. For STATIC or EDS, + * it is expected to be a direct IP address (or something resolvable by the + * specified :ref:`resolver ` + * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, + * and will be resolved via DNS. + */ 'address': (_envoy_api_v2_core_Address__Output); + /** + * The optional health check configuration is used as configuration for the + * health checker to contact the health checked host. + * + * .. attention:: + * + * This takes into effect only for upstream clusters with + * :ref:`active health checking ` enabled. + */ 'health_check_config': (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output); + /** + * The hostname associated with this endpoint. This hostname is not used for routing or address + * resolution. If provided, it will be associated with the endpoint, and can be used for features + * that require a hostname, like + * :ref:`auto_host_rewrite `. + */ 'hostname': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts index 50d5f46b2..84883c8a2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts @@ -5,20 +5,86 @@ import { HealthStatus as _envoy_api_v2_core_HealthStatus } from '../../../../env import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +/** + * An Endpoint that Envoy can route traffic to. + * [#next-free-field: 6] + */ export interface LbEndpoint { 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint); + /** + * Optional health status when known and supplied by EDS server. + */ 'health_status'?: (_envoy_api_v2_core_HealthStatus | keyof typeof _envoy_api_v2_core_HealthStatus); + /** + * The endpoint metadata specifies values that may be used by the load + * balancer to select endpoints in a cluster for a given request. The filter + * name should be specified as *envoy.lb*. An example boolean key-value pair + * is *canary*, providing the optional canary status of the upstream host. + * This may be matched against in a route's + * :ref:`RouteAction ` metadata_match field + * to subset the endpoints considered in cluster load balancing. + */ 'metadata'?: (_envoy_api_v2_core_Metadata); + /** + * The optional load balancing weight of the upstream host; at least 1. + * Envoy uses the load balancing weight in some of the built in load + * balancers. The load balancing weight for an endpoint is divided by the sum + * of the weights of all endpoints in the endpoint's locality to produce a + * percentage of traffic for the endpoint. This percentage is then further + * weighted by the endpoint's locality's load balancing weight from + * LocalityLbEndpoints. If unspecified, each host is presumed to have equal + * weight in a locality. The sum of the weights of all endpoints in the + * endpoint's locality must not exceed uint32_t maximal value (4294967295). + */ 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + /** + * [#not-implemented-hide:] + */ 'endpoint_name'?: (string); + /** + * Upstream host identifier or a named reference. + */ 'host_identifier'?: "endpoint"|"endpoint_name"; } +/** + * An Endpoint that Envoy can route traffic to. + * [#next-free-field: 6] + */ export interface LbEndpoint__Output { 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint__Output); + /** + * Optional health status when known and supplied by EDS server. + */ 'health_status': (keyof typeof _envoy_api_v2_core_HealthStatus); + /** + * The endpoint metadata specifies values that may be used by the load + * balancer to select endpoints in a cluster for a given request. The filter + * name should be specified as *envoy.lb*. An example boolean key-value pair + * is *canary*, providing the optional canary status of the upstream host. + * This may be matched against in a route's + * :ref:`RouteAction ` metadata_match field + * to subset the endpoints considered in cluster load balancing. + */ 'metadata': (_envoy_api_v2_core_Metadata__Output); + /** + * The optional load balancing weight of the upstream host; at least 1. + * Envoy uses the load balancing weight in some of the built in load + * balancers. The load balancing weight for an endpoint is divided by the sum + * of the weights of all endpoints in the endpoint's locality to produce a + * percentage of traffic for the endpoint. This percentage is then further + * weighted by the endpoint's locality's load balancing weight from + * LocalityLbEndpoints. If unspecified, each host is presumed to have equal + * weight in a locality. The sum of the weights of all endpoints in the + * endpoint's locality must not exceed uint32_t maximal value (4294967295). + */ 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + /** + * [#not-implemented-hide:] + */ 'endpoint_name'?: (string); + /** + * Upstream host identifier or a named reference. + */ 'host_identifier': "endpoint"|"endpoint_name"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts index d42663b04..6565a34f1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts @@ -4,18 +4,108 @@ import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from '../../../../envoy/api/v2/endpoint/LbEndpoint'; import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +/** + * A group of endpoints belonging to a Locality. + * One can have multiple LocalityLbEndpoints for a locality, but this is + * generally only done if the different groups need to have different load + * balancing weights or different priorities. + * [#next-free-field: 7] + */ export interface LocalityLbEndpoints { + /** + * Identifies location of where the upstream hosts run. + */ 'locality'?: (_envoy_api_v2_core_Locality); + /** + * The group of endpoints belonging to the locality specified. + */ 'lb_endpoints'?: (_envoy_api_v2_endpoint_LbEndpoint)[]; + /** + * Optional: Per priority/region/zone/sub_zone weight; at least 1. The load + * balancing weight for a locality is divided by the sum of the weights of all + * localities at the same priority level to produce the effective percentage + * of traffic for the locality. The sum of the weights of all localities at + * the same priority level must not exceed uint32_t maximal value (4294967295). + * + * Locality weights are only considered when :ref:`locality weighted load + * balancing ` is + * configured. These weights are ignored otherwise. If no weights are + * specified when locality weighted load balancing is enabled, the locality is + * assigned no load. + */ 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + /** + * Optional: the priority for this LocalityLbEndpoints. If unspecified this will + * default to the highest priority (0). + * + * Under usual circumstances, Envoy will only select endpoints for the highest + * priority (0). In the event all endpoints for a particular priority are + * unavailable/unhealthy, Envoy will fail over to selecting endpoints for the + * next highest priority group. + * + * Priorities should range from 0 (highest) to N (lowest) without skipping. + */ 'priority'?: (number); + /** + * Optional: Per locality proximity value which indicates how close this + * locality is from the source locality. This value only provides ordering + * information (lower the value, closer it is to the source locality). + * This will be consumed by load balancing schemes that need proximity order + * to determine where to route the requests. + * [#not-implemented-hide:] + */ 'proximity'?: (_google_protobuf_UInt32Value); } +/** + * A group of endpoints belonging to a Locality. + * One can have multiple LocalityLbEndpoints for a locality, but this is + * generally only done if the different groups need to have different load + * balancing weights or different priorities. + * [#next-free-field: 7] + */ export interface LocalityLbEndpoints__Output { + /** + * Identifies location of where the upstream hosts run. + */ 'locality': (_envoy_api_v2_core_Locality__Output); + /** + * The group of endpoints belonging to the locality specified. + */ 'lb_endpoints': (_envoy_api_v2_endpoint_LbEndpoint__Output)[]; + /** + * Optional: Per priority/region/zone/sub_zone weight; at least 1. The load + * balancing weight for a locality is divided by the sum of the weights of all + * localities at the same priority level to produce the effective percentage + * of traffic for the locality. The sum of the weights of all localities at + * the same priority level must not exceed uint32_t maximal value (4294967295). + * + * Locality weights are only considered when :ref:`locality weighted load + * balancing ` is + * configured. These weights are ignored otherwise. If no weights are + * specified when locality weighted load balancing is enabled, the locality is + * assigned no load. + */ 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + /** + * Optional: the priority for this LocalityLbEndpoints. If unspecified this will + * default to the highest priority (0). + * + * Under usual circumstances, Envoy will only select endpoints for the highest + * priority (0). In the event all endpoints for a particular priority are + * unavailable/unhealthy, Envoy will fail over to selecting endpoints for the + * next highest priority group. + * + * Priorities should range from 0 (highest) to N (lowest) without skipping. + */ 'priority': (number); + /** + * Optional: Per locality proximity value which indicates how close this + * locality is from the source locality. This value only provides ordering + * information (lower the value, closer it is to the source locality). + * This will be consumed by load balancing schemes that need proximity order + * to determine where to route the requests. + * [#not-implemented-hide:] + */ 'proximity': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts index d9c2cc793..017302934 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts @@ -4,15 +4,31 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface Filter { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + */ 'config_type'?: "config"|"typed_config"; } export interface Filter__Output { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts index ca24c8429..585836f15 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts @@ -7,22 +7,112 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_p import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../../envoy/api/v2/core/TransportSocket'; +/** + * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and + * various other parameters. + * [#next-free-field: 8] + */ export interface FilterChain { + /** + * The criteria to use when matching a connection to this filter chain. + */ 'filter_chain_match'?: (_envoy_api_v2_listener_FilterChainMatch); + /** + * The TLS context for this filter chain. + * + * .. attention:: + * + * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are + * set, `transport_socket` takes priority. + */ 'tls_context'?: (_envoy_api_v2_auth_DownstreamTlsContext); + /** + * A list of individual network filters that make up the filter chain for + * connections established with the listener. Order matters as the filters are + * processed sequentially as connection events happen. Note: If the filter + * list is empty, the connection will close by default. + */ 'filters'?: (_envoy_api_v2_listener_Filter)[]; + /** + * Whether the listener should expect a PROXY protocol V1 header on new + * connections. If this option is enabled, the listener will assume that that + * remote address of the connection is the one specified in the header. Some + * load balancers including the AWS ELB support this option. If the option is + * absent or set to false, Envoy will use the physical peer address of the + * connection as the remote address. + */ 'use_proxy_proto'?: (_google_protobuf_BoolValue); + /** + * [#not-implemented-hide:] filter chain metadata. + */ 'metadata'?: (_envoy_api_v2_core_Metadata); + /** + * Optional custom transport socket implementation to use for downstream connections. + * To setup TLS, set a transport socket with name `tls` and + * :ref:`DownstreamTlsContext ` in the `typed_config`. + * If no transport socket configuration is specified, new connections + * will be set up with plaintext. + */ 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); + /** + * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no + * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter + * chain is to be dynamically updated or removed via FCDS a unique name must be provided. + */ 'name'?: (string); } +/** + * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and + * various other parameters. + * [#next-free-field: 8] + */ export interface FilterChain__Output { + /** + * The criteria to use when matching a connection to this filter chain. + */ 'filter_chain_match': (_envoy_api_v2_listener_FilterChainMatch__Output); + /** + * The TLS context for this filter chain. + * + * .. attention:: + * + * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are + * set, `transport_socket` takes priority. + */ 'tls_context': (_envoy_api_v2_auth_DownstreamTlsContext__Output); + /** + * A list of individual network filters that make up the filter chain for + * connections established with the listener. Order matters as the filters are + * processed sequentially as connection events happen. Note: If the filter + * list is empty, the connection will close by default. + */ 'filters': (_envoy_api_v2_listener_Filter__Output)[]; + /** + * Whether the listener should expect a PROXY protocol V1 header on new + * connections. If this option is enabled, the listener will assume that that + * remote address of the connection is the one specified in the header. Some + * load balancers including the AWS ELB support this option. If the option is + * absent or set to false, Envoy will use the physical peer address of the + * connection as the remote address. + */ 'use_proxy_proto': (_google_protobuf_BoolValue__Output); + /** + * [#not-implemented-hide:] filter chain metadata. + */ 'metadata': (_envoy_api_v2_core_Metadata__Output); + /** + * Optional custom transport socket implementation to use for downstream connections. + * To setup TLS, set a transport socket with name `tls` and + * :ref:`DownstreamTlsContext ` in the `typed_config`. + * If no transport socket configuration is specified, new connections + * will be set up with plaintext. + */ 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + /** + * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no + * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter + * chain is to be dynamically updated or removed via FCDS a unique name must be provided. + */ 'name': (string); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts index 374621458..67f03a928 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts @@ -6,33 +6,258 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto export enum _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType { + /** + * Any connection source matches. + */ ANY = 0, + /** + * Match a connection originating from the same host. + */ LOCAL = 1, + /** + * Match a connection originating from a different host. + */ EXTERNAL = 2, } +/** + * Specifies the match criteria for selecting a specific filter chain for a + * listener. + * + * In order for a filter chain to be selected, *ALL* of its criteria must be + * fulfilled by the incoming connection, properties of which are set by the + * networking stack and/or listener filters. + * + * The following order applies: + * + * 1. Destination port. + * 2. Destination IP address. + * 3. Server name (e.g. SNI for TLS protocol), + * 4. Transport protocol. + * 5. Application protocols (e.g. ALPN for TLS protocol). + * 6. Source type (e.g. any, local or external network). + * 7. Source IP address. + * 8. Source port. + * + * For criteria that allow ranges or wildcards, the most specific value in any + * of the configured filter chains that matches the incoming connection is going + * to be used (e.g. for SNI ``www.example.com`` the most specific match would be + * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter + * chain without ``server_names`` requirements). + * + * [#comment: Implemented rules are kept in the preference order, with deprecated fields + * listed at the end, because that's how we want to list them in the docs. + * + * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] + * [#next-free-field: 13] + */ export interface FilterChainMatch { + /** + * If non-empty, an IP address and prefix length to match addresses when the + * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + */ 'prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; + /** + * If non-empty, an IP address and suffix length to match addresses when the + * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + * [#not-implemented-hide:] + */ 'address_suffix'?: (string); + /** + * [#not-implemented-hide:] + */ 'suffix_len'?: (_google_protobuf_UInt32Value); + /** + * The criteria is satisfied if the source IP address of the downstream + * connection is contained in at least one of the specified subnets. If the + * parameter is not specified or the list is empty, the source IP address is + * ignored. + */ 'source_prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; + /** + * The criteria is satisfied if the source port of the downstream connection + * is contained in at least one of the specified ports. If the parameter is + * not specified, the source port is ignored. + */ 'source_ports'?: (number)[]; + /** + * Optional destination port to consider when use_original_dst is set on the + * listener in determining a filter chain match. + */ 'destination_port'?: (_google_protobuf_UInt32Value); + /** + * If non-empty, a transport protocol to consider when determining a filter chain match. + * This value will be compared against the transport protocol of a new connection, when + * it's detected by one of the listener filters. + * + * Suggested values include: + * + * * ``raw_buffer`` - default, used when no transport protocol is detected, + * * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` + * when TLS protocol is detected. + */ 'transport_protocol'?: (string); + /** + * If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when + * determining a filter chain match. Those values will be compared against the application + * protocols of a new connection, when detected by one of the listener filters. + * + * Suggested values include: + * + * * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector + * `, + * * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` + * + * .. attention:: + * + * Currently, only :ref:`TLS Inspector ` provides + * application protocol detection based on the requested + * `ALPN `_ values. + * + * However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, + * and matching on values other than ``h2`` is going to lead to a lot of false negatives, + * unless all connecting clients are known to use ALPN. + */ 'application_protocols'?: (string)[]; + /** + * If non-empty, a list of server names (e.g. SNI for TLS protocol) to consider when determining + * a filter chain match. Those values will be compared against the server names of a new + * connection, when detected by one of the listener filters. + * + * The server name will be matched against all wildcard domains, i.e. ``www.example.com`` + * will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. + * + * Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. + * + * .. attention:: + * + * See the :ref:`FAQ entry ` on how to configure SNI for more + * information. + */ 'server_names'?: (string)[]; + /** + * Specifies the connection source IP match type. Can be any, local or external network. + */ 'source_type'?: (_envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); } +/** + * Specifies the match criteria for selecting a specific filter chain for a + * listener. + * + * In order for a filter chain to be selected, *ALL* of its criteria must be + * fulfilled by the incoming connection, properties of which are set by the + * networking stack and/or listener filters. + * + * The following order applies: + * + * 1. Destination port. + * 2. Destination IP address. + * 3. Server name (e.g. SNI for TLS protocol), + * 4. Transport protocol. + * 5. Application protocols (e.g. ALPN for TLS protocol). + * 6. Source type (e.g. any, local or external network). + * 7. Source IP address. + * 8. Source port. + * + * For criteria that allow ranges or wildcards, the most specific value in any + * of the configured filter chains that matches the incoming connection is going + * to be used (e.g. for SNI ``www.example.com`` the most specific match would be + * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter + * chain without ``server_names`` requirements). + * + * [#comment: Implemented rules are kept in the preference order, with deprecated fields + * listed at the end, because that's how we want to list them in the docs. + * + * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] + * [#next-free-field: 13] + */ export interface FilterChainMatch__Output { + /** + * If non-empty, an IP address and prefix length to match addresses when the + * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + */ 'prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; + /** + * If non-empty, an IP address and suffix length to match addresses when the + * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. + * [#not-implemented-hide:] + */ 'address_suffix': (string); + /** + * [#not-implemented-hide:] + */ 'suffix_len': (_google_protobuf_UInt32Value__Output); + /** + * The criteria is satisfied if the source IP address of the downstream + * connection is contained in at least one of the specified subnets. If the + * parameter is not specified or the list is empty, the source IP address is + * ignored. + */ 'source_prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; + /** + * The criteria is satisfied if the source port of the downstream connection + * is contained in at least one of the specified ports. If the parameter is + * not specified, the source port is ignored. + */ 'source_ports': (number)[]; + /** + * Optional destination port to consider when use_original_dst is set on the + * listener in determining a filter chain match. + */ 'destination_port': (_google_protobuf_UInt32Value__Output); + /** + * If non-empty, a transport protocol to consider when determining a filter chain match. + * This value will be compared against the transport protocol of a new connection, when + * it's detected by one of the listener filters. + * + * Suggested values include: + * + * * ``raw_buffer`` - default, used when no transport protocol is detected, + * * ``tls`` - set by :ref:`envoy.filters.listener.tls_inspector ` + * when TLS protocol is detected. + */ 'transport_protocol': (string); + /** + * If non-empty, a list of application protocols (e.g. ALPN for TLS protocol) to consider when + * determining a filter chain match. Those values will be compared against the application + * protocols of a new connection, when detected by one of the listener filters. + * + * Suggested values include: + * + * * ``http/1.1`` - set by :ref:`envoy.filters.listener.tls_inspector + * `, + * * ``h2`` - set by :ref:`envoy.filters.listener.tls_inspector ` + * + * .. attention:: + * + * Currently, only :ref:`TLS Inspector ` provides + * application protocol detection based on the requested + * `ALPN `_ values. + * + * However, the use of ALPN is pretty much limited to the HTTP/2 traffic on the Internet, + * and matching on values other than ``h2`` is going to lead to a lot of false negatives, + * unless all connecting clients are known to use ALPN. + */ 'application_protocols': (string)[]; + /** + * If non-empty, a list of server names (e.g. SNI for TLS protocol) to consider when determining + * a filter chain match. Those values will be compared against the server names of a new + * connection, when detected by one of the listener filters. + * + * The server name will be matched against all wildcard domains, i.e. ``www.example.com`` + * will be first matched against ``www.example.com``, then ``*.example.com``, then ``*.com``. + * + * Note that partial wildcards are not supported, and values like ``*w.example.com`` are invalid. + * + * .. attention:: + * + * See the :ref:`FAQ entry ` on how to configure SNI for more + * information. + */ 'server_names': (string)[]; + /** + * Specifies the connection source IP match type. Can be any, local or external network. + */ 'source_type': (keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts index bd143d311..5949135da 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts @@ -5,17 +5,43 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Outpu import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; export interface ListenerFilter { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. + * See :ref:`ListenerFilterChainMatchPredicate ` + * for further examples. + */ 'filter_disabled'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate); + /** + * Filter specific configuration which depends on the filter being instantiated. + * See the supported filters for further documentation. + */ 'config_type'?: "config"|"typed_config"; } export interface ListenerFilter__Output { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. + * See :ref:`ListenerFilterChainMatchPredicate ` + * for further examples. + */ 'filter_disabled': (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + /** + * Filter specific configuration which depends on the filter being instantiated. + * See the supported filters for further documentation. + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts index a795f0191..547e74d11 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts @@ -3,28 +3,134 @@ import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from '../../../../envoy/type/Int32Range'; +/** + * A set of match configurations used for logical operations. + */ export interface _envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet { + /** + * The list of rules that make up the set. + */ 'rules'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate)[]; } +/** + * A set of match configurations used for logical operations. + */ export interface _envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output { + /** + * The list of rules that make up the set. + */ 'rules': (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output)[]; } +/** + * Listener filter chain match configuration. This is a recursive structure which allows complex + * nested match configurations to be built using various logical operators. + * + * Examples: + * + * * Matches if the destination port is 3306. + * + * .. code-block:: yaml + * + * destination_port_range: + * start: 3306 + * end: 3307 + * + * * Matches if the destination port is 3306 or 15000. + * + * .. code-block:: yaml + * + * or_match: + * rules: + * - destination_port_range: + * start: 3306 + * end: 3306 + * - destination_port_range: + * start: 15000 + * end: 15001 + * + * [#next-free-field: 6] + */ export interface ListenerFilterChainMatchPredicate { + /** + * A set that describes a logical OR. If any member of the set matches, the match configuration + * matches. + */ 'or_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet); + /** + * A set that describes a logical AND. If all members of the set match, the match configuration + * matches. + */ 'and_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet); + /** + * A negation match. The match configuration will match if the negated match condition matches. + */ 'not_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate); + /** + * The match configuration will always match. + */ 'any_match'?: (boolean); + /** + * Match destination port. Particularly, the match evaluation must use the recovered local port if + * the owning listener filter is after :ref:`an original_dst listener filter `. + */ 'destination_port_range'?: (_envoy_type_Int32Range); 'rule'?: "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; } +/** + * Listener filter chain match configuration. This is a recursive structure which allows complex + * nested match configurations to be built using various logical operators. + * + * Examples: + * + * * Matches if the destination port is 3306. + * + * .. code-block:: yaml + * + * destination_port_range: + * start: 3306 + * end: 3307 + * + * * Matches if the destination port is 3306 or 15000. + * + * .. code-block:: yaml + * + * or_match: + * rules: + * - destination_port_range: + * start: 3306 + * end: 3306 + * - destination_port_range: + * start: 15000 + * end: 15001 + * + * [#next-free-field: 6] + */ export interface ListenerFilterChainMatchPredicate__Output { + /** + * A set that describes a logical OR. If any member of the set matches, the match configuration + * matches. + */ 'or_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output); + /** + * A set that describes a logical AND. If all members of the set match, the match configuration + * matches. + */ 'and_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output); + /** + * A negation match. The match configuration will match if the negated match condition matches. + */ 'not_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + /** + * The match configuration will always match. + */ 'any_match'?: (boolean); + /** + * Match destination port. Particularly, the match evaluation must use the recovered local port if + * the owning listener filter is after :ref:`an original_dst listener filter `. + */ 'destination_port_range'?: (_envoy_type_Int32Range__Output); 'rule': "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts index 775f4ae9f..34a710b14 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts @@ -4,15 +4,33 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface UdpListenerConfig { + /** + * Used to look up UDP listener factory, matches "raw_udp_listener" or + * "quic_listener" to create a specific udp listener. + * If not specified, treat as "raw_udp_listener". + */ 'udp_listener_name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Used to create a specific listener factory. To some factory, e.g. + * "raw_udp_listener", config is not needed. + */ 'config_type'?: "config"|"typed_config"; } export interface UdpListenerConfig__Output { + /** + * Used to look up UDP listener factory, matches "raw_udp_listener" or + * "quic_listener" to create a specific udp listener. + * If not specified, treat as "raw_udp_listener". + */ 'udp_listener_name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Used to create a specific listener factory. To some factory, e.g. + * "raw_udp_listener", config is not needed. + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts index fbb1524f4..cb48b5eec 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts @@ -4,32 +4,166 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_p import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +/** + * [#next-free-field: 12] + */ export interface CorsPolicy { + /** + * Specifies the origins that will be allowed to do CORS requests. + * + * An origin is allowed if either allow_origin or allow_origin_regex match. + * + * .. attention:: + * This field has been deprecated in favor of `allow_origin_string_match`. + */ 'allow_origin'?: (string)[]; + /** + * Specifies the content for the *access-control-allow-methods* header. + */ 'allow_methods'?: (string); + /** + * Specifies the content for the *access-control-allow-headers* header. + */ 'allow_headers'?: (string); + /** + * Specifies the content for the *access-control-expose-headers* header. + */ 'expose_headers'?: (string); + /** + * Specifies the content for the *access-control-max-age* header. + */ 'max_age'?: (string); + /** + * Specifies whether the resource allows credentials. + */ 'allow_credentials'?: (_google_protobuf_BoolValue); + /** + * Specifies if the CORS filter is enabled. Defaults to true. Only effective on route. + * + * .. attention:: + * + * **This field is deprecated**. Set the + * :ref:`filter_enabled` field instead. + */ 'enabled'?: (_google_protobuf_BoolValue); + /** + * Specifies regex patterns that match allowed origins. + * + * An origin is allowed if either allow_origin or allow_origin_regex match. + * + * .. attention:: + * This field has been deprecated in favor of `allow_origin_string_match` as it is not safe for + * use with untrusted input in all cases. + */ 'allow_origin_regex'?: (string)[]; + /** + * Specifies the % of requests for which the CORS filter is enabled. + * + * If neither ``enabled``, ``filter_enabled``, nor ``shadow_enabled`` are specified, the CORS + * filter will be enabled for 100% of the requests. + * + * If :ref:`runtime_key ` is + * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. + */ 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + /** + * Specifies the % of requests for which the CORS policies will be evaluated and tracked, but not + * enforced. + * + * This field is intended to be used when ``filter_enabled`` and ``enabled`` are off. One of those + * fields have to explicitly disable the filter in order for this setting to take effect. + * + * If :ref:`runtime_key ` is specified, + * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate + * and track the request's *Origin* to determine if it's valid but will not enforce any policies. + */ 'shadow_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + /** + * Specifies string patterns that match allowed origins. An origin is allowed if any of the + * string matchers match. + */ 'allow_origin_string_match'?: (_envoy_type_matcher_StringMatcher)[]; 'enabled_specifier'?: "enabled"|"filter_enabled"; } +/** + * [#next-free-field: 12] + */ export interface CorsPolicy__Output { + /** + * Specifies the origins that will be allowed to do CORS requests. + * + * An origin is allowed if either allow_origin or allow_origin_regex match. + * + * .. attention:: + * This field has been deprecated in favor of `allow_origin_string_match`. + */ 'allow_origin': (string)[]; + /** + * Specifies the content for the *access-control-allow-methods* header. + */ 'allow_methods': (string); + /** + * Specifies the content for the *access-control-allow-headers* header. + */ 'allow_headers': (string); + /** + * Specifies the content for the *access-control-expose-headers* header. + */ 'expose_headers': (string); + /** + * Specifies the content for the *access-control-max-age* header. + */ 'max_age': (string); + /** + * Specifies whether the resource allows credentials. + */ 'allow_credentials': (_google_protobuf_BoolValue__Output); + /** + * Specifies if the CORS filter is enabled. Defaults to true. Only effective on route. + * + * .. attention:: + * + * **This field is deprecated**. Set the + * :ref:`filter_enabled` field instead. + */ 'enabled'?: (_google_protobuf_BoolValue__Output); + /** + * Specifies regex patterns that match allowed origins. + * + * An origin is allowed if either allow_origin or allow_origin_regex match. + * + * .. attention:: + * This field has been deprecated in favor of `allow_origin_string_match` as it is not safe for + * use with untrusted input in all cases. + */ 'allow_origin_regex': (string)[]; + /** + * Specifies the % of requests for which the CORS filter is enabled. + * + * If neither ``enabled``, ``filter_enabled``, nor ``shadow_enabled`` are specified, the CORS + * filter will be enabled for 100% of the requests. + * + * If :ref:`runtime_key ` is + * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. + */ 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + /** + * Specifies the % of requests for which the CORS policies will be evaluated and tracked, but not + * enforced. + * + * This field is intended to be used when ``filter_enabled`` and ``enabled`` are off. One of those + * fields have to explicitly disable the filter in order for this setting to take effect. + * + * If :ref:`runtime_key ` is specified, + * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate + * and track the request's *Origin* to determine if it's valid but will not enforce any policies. + */ 'shadow_enabled': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + /** + * Specifies string patterns that match allowed origins. An origin is allowed if any of the + * string matchers match. + */ 'allow_origin_string_match': (_envoy_type_matcher_StringMatcher__Output)[]; 'enabled_specifier': "enabled"|"filter_enabled"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts index 84deb8b0c..43bc7408c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts @@ -3,11 +3,37 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; export interface Decorator { + /** + * The operation name associated with the request matched to this route. If tracing is + * enabled, this information will be used as the span name reported for this request. + * + * .. note:: + * + * For ingress (inbound) requests, or egress (outbound) responses, this value may be overridden + * by the :ref:`x-envoy-decorator-operation + * ` header. + */ 'operation'?: (string); + /** + * Whether the decorated details should be propagated to the other party. The default is true. + */ 'propagate'?: (_google_protobuf_BoolValue); } export interface Decorator__Output { + /** + * The operation name associated with the request matched to this route. If tracing is + * enabled, this information will be used as the span name reported for this request. + * + * .. note:: + * + * For ingress (inbound) requests, or egress (outbound) responses, this value may be overridden + * by the :ref:`x-envoy-decorator-operation + * ` header. + */ 'operation': (string); + /** + * Whether the decorated details should be propagated to the other party. The default is true. + */ 'propagate': (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts index 83440efcf..7585f376c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts @@ -3,11 +3,37 @@ import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; export interface DirectResponseAction { + /** + * Specifies the HTTP response status to be returned. + */ 'status'?: (number); + /** + * Specifies the content of the response body. If this setting is omitted, + * no body is included in the generated response. + * + * .. note:: + * + * Headers can be specified using *response_headers_to_add* in the enclosing + * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or + * :ref:`envoy_api_msg_route.VirtualHost`. + */ 'body'?: (_envoy_api_v2_core_DataSource); } export interface DirectResponseAction__Output { + /** + * Specifies the HTTP response status to be returned. + */ 'status': (number); + /** + * Specifies the content of the response body. If this setting is omitted, + * no body is included in the generated response. + * + * .. note:: + * + * Headers can be specified using *response_headers_to_add* in the enclosing + * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or + * :ref:`envoy_api_msg_route.VirtualHost`. + */ 'body': (_envoy_api_v2_core_DataSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts index 14455ae79..8e0985e12 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts @@ -2,10 +2,16 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +/** + * A filter-defined action type. + */ export interface FilterAction { 'action'?: (_google_protobuf_Any); } +/** + * A filter-defined action type. + */ export interface FilterAction__Output { 'action': (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts index 6a189d87f..3e9793649 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts @@ -4,28 +4,224 @@ import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; import { Long } from '@grpc/proto-loader'; +/** + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* + * header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. attention:: + * + * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both + * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., + * + * .. code-block:: json + * + * { + * "name": ":method", + * "exact_match": "POST" + * } + * + * .. attention:: + * In the absence of any header match specifier, match will default to :ref:`present_match + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's + * value. + * + * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] + * [#next-free-field: 12] + */ export interface HeaderMatcher { + /** + * Specifies the name of the header in the request. + */ 'name'?: (string); + /** + * If specified, header match will be performed based on the value of the header. + */ 'exact_match'?: (string); + /** + * If specified, this regex string is a regular expression rule which implies the entire request + * header value must match the regex. The rule will not match if only a subsequence of the + * request header value matches the regex. The regex grammar used in the value field is defined + * `here `_. + * + * Examples: + * + * * The regex ``\d{3}`` matches the value *123* + * * The regex ``\d{3}`` does not match the value *1234* + * * The regex ``\d{3}`` does not match the value *123.456* + * + * .. attention:: + * This field has been deprecated in favor of `safe_regex_match` as it is not safe for use + * with untrusted input in all cases. + */ 'regex_match'?: (string); + /** + * If specified, header match will be performed based on range. + * The rule will match if the request header value is within this range. + * The entire request header value must represent an integer in base 10 notation: consisting of + * an optional plus or minus sign followed by a sequence of digits. The rule will not match if + * the header value does not represent an integer. Match will fail for empty values, floating + * point numbers or if only a subsequence of the header value is an integer. + * + * Examples: + * + * * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, + * "-1somestring" + */ 'range_match'?: (_envoy_type_Int64Range); + /** + * If specified, header match will be performed based on whether the header is in the + * request. + */ 'present_match'?: (boolean); + /** + * If specified, the match result will be inverted before checking. Defaults to false. + * + * Examples: + * + * * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. + * * The range [-10,0) will match the value -1, so it will not match when inverted. + */ 'invert_match'?: (boolean); + /** + * If specified, header match will be performed based on the prefix of the header value. + * Note: empty prefix is not allowed, please use present_match instead. + * + * Examples: + * + * * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. + */ 'prefix_match'?: (string); + /** + * If specified, header match will be performed based on the suffix of the header value. + * Note: empty suffix is not allowed, please use present_match instead. + * + * Examples: + * + * * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. + */ 'suffix_match'?: (string); + /** + * If specified, this regex string is a regular expression rule which implies the entire request + * header value must match the regex. The rule will not match if only a subsequence of the + * request header value matches the regex. + */ 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher); + /** + * Specifies how the header match will be performed to route the request. + */ 'header_match_specifier'?: "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; } +/** + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* + * header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. attention:: + * + * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both + * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., + * + * .. code-block:: json + * + * { + * "name": ":method", + * "exact_match": "POST" + * } + * + * .. attention:: + * In the absence of any header match specifier, match will default to :ref:`present_match + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's + * value. + * + * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] + * [#next-free-field: 12] + */ export interface HeaderMatcher__Output { + /** + * Specifies the name of the header in the request. + */ 'name': (string); + /** + * If specified, header match will be performed based on the value of the header. + */ 'exact_match'?: (string); + /** + * If specified, this regex string is a regular expression rule which implies the entire request + * header value must match the regex. The rule will not match if only a subsequence of the + * request header value matches the regex. The regex grammar used in the value field is defined + * `here `_. + * + * Examples: + * + * * The regex ``\d{3}`` matches the value *123* + * * The regex ``\d{3}`` does not match the value *1234* + * * The regex ``\d{3}`` does not match the value *123.456* + * + * .. attention:: + * This field has been deprecated in favor of `safe_regex_match` as it is not safe for use + * with untrusted input in all cases. + */ 'regex_match'?: (string); + /** + * If specified, header match will be performed based on range. + * The rule will match if the request header value is within this range. + * The entire request header value must represent an integer in base 10 notation: consisting of + * an optional plus or minus sign followed by a sequence of digits. The rule will not match if + * the header value does not represent an integer. Match will fail for empty values, floating + * point numbers or if only a subsequence of the header value is an integer. + * + * Examples: + * + * * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, + * "-1somestring" + */ 'range_match'?: (_envoy_type_Int64Range__Output); + /** + * If specified, header match will be performed based on whether the header is in the + * request. + */ 'present_match'?: (boolean); + /** + * If specified, the match result will be inverted before checking. Defaults to false. + * + * Examples: + * + * * The regex ``\d{3}`` does not match the value *1234*, so it will match when inverted. + * * The range [-10,0) will match the value -1, so it will not match when inverted. + */ 'invert_match': (boolean); + /** + * If specified, header match will be performed based on the prefix of the header value. + * Note: empty prefix is not allowed, please use present_match instead. + * + * Examples: + * + * * The prefix *abcd* matches the value *abcdxyz*, but not for *abcxyz*. + */ 'prefix_match'?: (string); + /** + * If specified, header match will be performed based on the suffix of the header value. + * Note: empty suffix is not allowed, please use present_match instead. + * + * Examples: + * + * * The suffix *abcd* matches the value *xyzabcd*, but not for *xyzbcd*. + */ 'suffix_match'?: (string); + /** + * If specified, this regex string is a regular expression rule which implies the entire request + * header value must match the regex. The rule will not match if only a subsequence of the + * request header value matches the regex. + */ 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher__Output); + /** + * Specifies how the header match will be performed to route the request. + */ 'header_match_specifier': "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts index 5cab83560..a1c641711 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts @@ -3,14 +3,64 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; +/** + * HTTP request hedging :ref:`architecture overview `. + */ export interface HedgePolicy { + /** + * Specifies the number of initial requests that should be sent upstream. + * Must be at least 1. + * Defaults to 1. + * [#not-implemented-hide:] + */ 'initial_requests'?: (_google_protobuf_UInt32Value); + /** + * Specifies a probability that an additional upstream request should be sent + * on top of what is specified by initial_requests. + * Defaults to 0. + * [#not-implemented-hide:] + */ 'additional_request_chance'?: (_envoy_type_FractionalPercent); + /** + * Indicates that a hedged request should be sent when the per-try timeout + * is hit. This will only occur if the retry policy also indicates that a + * timed out request should be retried. + * Once a timed out request is retried due to per try timeout, the router + * filter will ensure that it is not retried again even if the returned + * response headers would otherwise be retried according the specified + * :ref:`RetryPolicy `. + * Defaults to false. + */ 'hedge_on_per_try_timeout'?: (boolean); } +/** + * HTTP request hedging :ref:`architecture overview `. + */ export interface HedgePolicy__Output { + /** + * Specifies the number of initial requests that should be sent upstream. + * Must be at least 1. + * Defaults to 1. + * [#not-implemented-hide:] + */ 'initial_requests': (_google_protobuf_UInt32Value__Output); + /** + * Specifies a probability that an additional upstream request should be sent + * on top of what is specified by initial_requests. + * Defaults to 0. + * [#not-implemented-hide:] + */ 'additional_request_chance': (_envoy_type_FractionalPercent__Output); + /** + * Indicates that a hedged request should be sent when the per-try timeout + * is hit. This will only occur if the retry policy also indicates that a + * timed out request should be retried. + * Once a timed out request is retried due to per try timeout, the router + * filter will ensure that it is not retried again even if the returned + * response headers would otherwise be retried according the specified + * :ref:`RetryPolicy `. + * Defaults to false. + */ 'hedge_on_per_try_timeout': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts index 48c6a51b0..8f0041ce6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts @@ -3,20 +3,84 @@ import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +/** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ export interface QueryParameterMatcher { + /** + * Specifies the name of a key that must be present in the requested + * *path*'s query string. + */ 'name'?: (string); + /** + * Specifies the value of the key. If the value is absent, a request + * that contains the key in its query string will match, whether the + * key appears with a value (e.g., "?debug=true") or not (e.g., "?debug") + * + * ..attention:: + * This field is deprecated. Use an `exact` match inside the `string_match` field. + */ 'value'?: (string); + /** + * Specifies whether the query parameter value is a regular expression. + * Defaults to false. The entire query parameter value (i.e., the part to + * the right of the equals sign in "key=value") must match the regex. + * E.g., the regex ``\d+$`` will match *123* but not *a123* or *123a*. + * + * ..attention:: + * This field is deprecated. Use a `safe_regex` match inside the `string_match` field. + */ 'regex'?: (_google_protobuf_BoolValue); + /** + * Specifies whether a query parameter value should match against a string. + */ 'string_match'?: (_envoy_type_matcher_StringMatcher); + /** + * Specifies whether a query parameter should be present. + */ 'present_match'?: (boolean); 'query_parameter_match_specifier'?: "string_match"|"present_match"; } +/** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ export interface QueryParameterMatcher__Output { + /** + * Specifies the name of a key that must be present in the requested + * *path*'s query string. + */ 'name': (string); + /** + * Specifies the value of the key. If the value is absent, a request + * that contains the key in its query string will match, whether the + * key appears with a value (e.g., "?debug=true") or not (e.g., "?debug") + * + * ..attention:: + * This field is deprecated. Use an `exact` match inside the `string_match` field. + */ 'value': (string); + /** + * Specifies whether the query parameter value is a regular expression. + * Defaults to false. The entire query parameter value (i.e., the part to + * the right of the equals sign in "key=value") must match the regex. + * E.g., the regex ``\d+$`` will match *123* but not *a123* or *123a*. + * + * ..attention:: + * This field is deprecated. Use a `safe_regex` match inside the `string_match` field. + */ 'regex': (_google_protobuf_BoolValue__Output); + /** + * Specifies whether a query parameter value should match against a string. + */ 'string_match'?: (_envoy_type_matcher_StringMatcher__Output); + /** + * Specifies whether a query parameter should be present. + */ 'present_match'?: (boolean); 'query_parameter_match_specifier': "string_match"|"present_match"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts index b75b9b446..6361f5032 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts @@ -4,82 +4,338 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +/** + * [#next-free-field: 7] + */ export interface _envoy_api_v2_route_RateLimit_Action { + /** + * Rate limit on source cluster. + */ 'source_cluster'?: (_envoy_api_v2_route_RateLimit_Action_SourceCluster); + /** + * Rate limit on destination cluster. + */ 'destination_cluster'?: (_envoy_api_v2_route_RateLimit_Action_DestinationCluster); + /** + * Rate limit on request headers. + */ 'request_headers'?: (_envoy_api_v2_route_RateLimit_Action_RequestHeaders); + /** + * Rate limit on remote address. + */ 'remote_address'?: (_envoy_api_v2_route_RateLimit_Action_RemoteAddress); + /** + * Rate limit on a generic key. + */ 'generic_key'?: (_envoy_api_v2_route_RateLimit_Action_GenericKey); + /** + * Rate limit on the existence of request headers. + */ 'header_value_match'?: (_envoy_api_v2_route_RateLimit_Action_HeaderValueMatch); 'action_specifier'?: "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; } +/** + * [#next-free-field: 7] + */ export interface _envoy_api_v2_route_RateLimit_Action__Output { + /** + * Rate limit on source cluster. + */ 'source_cluster'?: (_envoy_api_v2_route_RateLimit_Action_SourceCluster__Output); + /** + * Rate limit on destination cluster. + */ 'destination_cluster'?: (_envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output); + /** + * Rate limit on request headers. + */ 'request_headers'?: (_envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output); + /** + * Rate limit on remote address. + */ 'remote_address'?: (_envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output); + /** + * Rate limit on a generic key. + */ 'generic_key'?: (_envoy_api_v2_route_RateLimit_Action_GenericKey__Output); + /** + * Rate limit on the existence of request headers. + */ 'header_value_match'?: (_envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output); 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("destination_cluster", "") + * + * Once a request matches against a route table rule, a routed cluster is determined by one of + * the following :ref:`route table configuration ` + * settings: + * + * * :ref:`cluster ` indicates the upstream cluster + * to route to. + * * :ref:`weighted_clusters ` + * chooses a cluster randomly from a set of clusters with attributed weight. + * * :ref:`cluster_header ` indicates which + * header in the request contains the target cluster. + */ export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster { } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("destination_cluster", "") + * + * Once a request matches against a route table rule, a routed cluster is determined by one of + * the following :ref:`route table configuration ` + * settings: + * + * * :ref:`cluster ` indicates the upstream cluster + * to route to. + * * :ref:`weighted_clusters ` + * chooses a cluster randomly from a set of clusters with attributed weight. + * * :ref:`cluster_header ` indicates which + * header in the request contains the target cluster. + */ export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output { } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("generic_key", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_GenericKey { + /** + * The value to use in the descriptor entry. + */ 'descriptor_value'?: (string); } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("generic_key", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_GenericKey__Output { + /** + * The value to use in the descriptor entry. + */ 'descriptor_value': (string); } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("header_match", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch { + /** + * The value to use in the descriptor entry. + */ 'descriptor_value'?: (string); + /** + * If set to true, the action will append a descriptor entry when the + * request matches the headers. If set to false, the action will append a + * descriptor entry when the request does not match the headers. The + * default value is true. + */ 'expect_match'?: (_google_protobuf_BoolValue); + /** + * Specifies a set of headers that the rate limit action should match + * on. The action will check the request’s headers against all the + * specified headers in the config. A match will happen if all the + * headers in the config are present in the request with the same values + * (or based on presence if the value field is not in the config). + */ 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("header_match", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output { + /** + * The value to use in the descriptor entry. + */ 'descriptor_value': (string); + /** + * If set to true, the action will append a descriptor entry when the + * request matches the headers. If set to false, the action will append a + * descriptor entry when the request does not match the headers. The + * default value is true. + */ 'expect_match': (_google_protobuf_BoolValue__Output); + /** + * Specifies a set of headers that the rate limit action should match + * on. The action will check the request’s headers against all the + * specified headers in the config. A match will happen if all the + * headers in the config are present in the request with the same values + * (or based on presence if the value field is not in the config). + */ 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; } +/** + * The following descriptor entry is appended to the descriptor and is populated using the + * trusted address from :ref:`x-forwarded-for `: + * + * .. code-block:: cpp + * + * ("remote_address", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress { } +/** + * The following descriptor entry is appended to the descriptor and is populated using the + * trusted address from :ref:`x-forwarded-for `: + * + * .. code-block:: cpp + * + * ("remote_address", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output { } +/** + * The following descriptor entry is appended when a header contains a key that matches the + * *header_name*: + * + * .. code-block:: cpp + * + * ("", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders { + /** + * The header name to be queried from the request headers. The header’s + * value is used to populate the value of the descriptor entry for the + * descriptor_key. + */ 'header_name'?: (string); + /** + * The key to use in the descriptor entry. + */ 'descriptor_key'?: (string); } +/** + * The following descriptor entry is appended when a header contains a key that matches the + * *header_name*: + * + * .. code-block:: cpp + * + * ("", "") + */ export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output { + /** + * The header name to be queried from the request headers. The header’s + * value is used to populate the value of the descriptor entry for the + * descriptor_key. + */ 'header_name': (string); + /** + * The key to use in the descriptor entry. + */ 'descriptor_key': (string); } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("source_cluster", "") + * + * is derived from the :option:`--service-cluster` option. + */ export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster { } +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("source_cluster", "") + * + * is derived from the :option:`--service-cluster` option. + */ export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster__Output { } +/** + * Global rate limiting :ref:`architecture overview `. + */ export interface RateLimit { + /** + * Refers to the stage set in the filter. The rate limit configuration only + * applies to filters with the same stage number. The default stage number is + * 0. + * + * .. note:: + * + * The filter supports a range of 0 - 10 inclusively for stage numbers. + */ 'stage'?: (_google_protobuf_UInt32Value); + /** + * The key to be set in runtime to disable this rate limit configuration. + */ 'disable_key'?: (string); + /** + * A list of actions that are to be applied for this rate limit configuration. + * Order matters as the actions are processed sequentially and the descriptor + * is composed by appending descriptor entries in that sequence. If an action + * cannot append a descriptor entry, no descriptor is generated for the + * configuration. See :ref:`composing actions + * ` for additional documentation. + */ 'actions'?: (_envoy_api_v2_route_RateLimit_Action)[]; } +/** + * Global rate limiting :ref:`architecture overview `. + */ export interface RateLimit__Output { + /** + * Refers to the stage set in the filter. The rate limit configuration only + * applies to filters with the same stage number. The default stage number is + * 0. + * + * .. note:: + * + * The filter supports a range of 0 - 10 inclusively for stage numbers. + */ 'stage': (_google_protobuf_UInt32Value__Output); + /** + * The key to be set in runtime to disable this rate limit configuration. + */ 'disable_key': (string); + /** + * A list of actions that are to be applied for this rate limit configuration. + * Order matters as the actions are processed sequentially and the descriptor + * is composed by appending descriptor entries in that sequence. If an action + * cannot append a descriptor entry, no descriptor is generated for the + * configuration. See :ref:`composing actions + * ` for additional documentation. + */ 'actions': (_envoy_api_v2_route_RateLimit_Action__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts index 06214c9db..de7105a54 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts @@ -4,35 +4,136 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto export enum _envoy_api_v2_route_RedirectAction_RedirectResponseCode { + /** + * Moved Permanently HTTP Status Code - 301. + */ MOVED_PERMANENTLY = 0, + /** + * Found HTTP Status Code - 302. + */ FOUND = 1, + /** + * See Other HTTP Status Code - 303. + */ SEE_OTHER = 2, + /** + * Temporary Redirect HTTP Status Code - 307. + */ TEMPORARY_REDIRECT = 3, + /** + * Permanent Redirect HTTP Status Code - 308. + */ PERMANENT_REDIRECT = 4, } +/** + * [#next-free-field: 9] + */ export interface RedirectAction { + /** + * The host portion of the URL will be swapped with this value. + */ 'host_redirect'?: (string); + /** + * The path portion of the URL will be swapped with this value. + */ 'path_redirect'?: (string); + /** + * The HTTP status code to use in the redirect response. The default response + * code is MOVED_PERMANENTLY (301). + */ 'response_code'?: (_envoy_api_v2_route_RedirectAction_RedirectResponseCode | keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); + /** + * The scheme portion of the URL will be swapped with "https". + */ 'https_redirect'?: (boolean); + /** + * Indicates that during redirection, the matched prefix (or path) + * should be swapped with this value. This option allows redirect URLs be dynamically created + * based on the request. + * + * .. attention:: + * + * Pay attention to the use of trailing slashes as mentioned in + * :ref:`RouteAction's prefix_rewrite `. + */ 'prefix_rewrite'?: (string); + /** + * Indicates that during redirection, the query portion of the URL will + * be removed. Default value is false. + */ 'strip_query'?: (boolean); + /** + * The scheme portion of the URL will be swapped with this value. + */ 'scheme_redirect'?: (string); + /** + * The port value of the URL will be swapped with this value. + */ 'port_redirect'?: (number); + /** + * When the scheme redirection take place, the following rules apply: + * 1. If the source URI scheme is `http` and the port is explicitly + * set to `:80`, the port will be removed after the redirection + * 2. If the source URI scheme is `https` and the port is explicitly + * set to `:443`, the port will be removed after the redirection + */ 'scheme_rewrite_specifier'?: "https_redirect"|"scheme_redirect"; 'path_rewrite_specifier'?: "path_redirect"|"prefix_rewrite"; } +/** + * [#next-free-field: 9] + */ export interface RedirectAction__Output { + /** + * The host portion of the URL will be swapped with this value. + */ 'host_redirect': (string); + /** + * The path portion of the URL will be swapped with this value. + */ 'path_redirect'?: (string); + /** + * The HTTP status code to use in the redirect response. The default response + * code is MOVED_PERMANENTLY (301). + */ 'response_code': (keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); + /** + * The scheme portion of the URL will be swapped with "https". + */ 'https_redirect'?: (boolean); + /** + * Indicates that during redirection, the matched prefix (or path) + * should be swapped with this value. This option allows redirect URLs be dynamically created + * based on the request. + * + * .. attention:: + * + * Pay attention to the use of trailing slashes as mentioned in + * :ref:`RouteAction's prefix_rewrite `. + */ 'prefix_rewrite'?: (string); + /** + * Indicates that during redirection, the query portion of the URL will + * be removed. Default value is false. + */ 'strip_query': (boolean); + /** + * The scheme portion of the URL will be swapped with this value. + */ 'scheme_redirect'?: (string); + /** + * The port value of the URL will be swapped with this value. + */ 'port_redirect': (number); + /** + * When the scheme redirection take place, the following rules apply: + * 1. If the source URI scheme is `http` and the port is explicitly + * set to `:80`, the port will be removed after the redirection + * 2. If the source URI scheme is `https` and the port is explicitly + * set to `:443`, the port will be removed after the redirection + */ 'scheme_rewrite_specifier': "https_redirect"|"scheme_redirect"; 'path_rewrite_specifier': "path_redirect"|"prefix_rewrite"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts index e43648001..48df89fdb 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts @@ -8,12 +8,36 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Outpu import { Long } from '@grpc/proto-loader'; export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff { + /** + * Specifies the base interval between retries. This parameter is required and must be greater + * than zero. Values less than 1 ms are rounded up to 1 ms. + * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's + * back-off algorithm. + */ 'base_interval'?: (_google_protobuf_Duration); + /** + * Specifies the maximum interval between retries. This parameter is optional, but must be + * greater than or equal to the `base_interval` if set. The default is 10 times the + * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion + * of Envoy's back-off algorithm. + */ 'max_interval'?: (_google_protobuf_Duration); } export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff__Output { + /** + * Specifies the base interval between retries. This parameter is required and must be greater + * than zero. Values less than 1 ms are rounded up to 1 ms. + * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's + * back-off algorithm. + */ 'base_interval': (_google_protobuf_Duration__Output); + /** + * Specifies the maximum interval between retries. This parameter is optional, but must be + * greater than or equal to the `base_interval` if set. The default is 10 times the + * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion + * of Envoy's back-off algorithm. + */ 'max_interval': (_google_protobuf_Duration__Output); } @@ -45,28 +69,150 @@ export interface _envoy_api_v2_route_RetryPolicy_RetryPriority__Output { 'config_type': "config"|"typed_config"; } +/** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 11] + */ export interface RetryPolicy { + /** + * Specifies the conditions under which retry takes place. These are the same + * conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and + * :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. + */ 'retry_on'?: (string); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. These are the same conditions documented for + * :ref:`config_http_filters_router_x-envoy-max-retries`. + */ 'num_retries'?: (_google_protobuf_UInt32Value); + /** + * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The + * same conditions documented for + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. + * + * .. note:: + * + * If left unspecified, Envoy will use the global + * :ref:`route timeout ` for the request. + * Consequently, when using a :ref:`5xx ` based + * retry policy, a request that times out will not be retried as the total timeout budget + * would have been exhausted. + */ 'per_try_timeout'?: (_google_protobuf_Duration); + /** + * Specifies an implementation of a RetryPriority which is used to determine the + * distribution of load across priorities used for retries. Refer to + * :ref:`retry plugin configuration ` for more details. + */ 'retry_priority'?: (_envoy_api_v2_route_RetryPolicy_RetryPriority); + /** + * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host + * for retries. If any of the predicates reject the host, host selection will be reattempted. + * Refer to :ref:`retry plugin configuration ` for more + * details. + */ 'retry_host_predicate'?: (_envoy_api_v2_route_RetryPolicy_RetryHostPredicate)[]; + /** + * The maximum number of times host selection will be reattempted before giving up, at which + * point the host that was last selected will be routed to. If unspecified, this will default to + * retrying once. + */ 'host_selection_retry_max_attempts'?: (number | string | Long); + /** + * HTTP status codes that should trigger a retry in addition to those specified by retry_on. + */ 'retriable_status_codes'?: (number)[]; + /** + * Specifies parameters that control retry back off. This parameter is optional, in which case the + * default base interval is 25 milliseconds or, if set, the current value of the + * `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times + * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` + * describes Envoy's back-off algorithm. + */ 'retry_back_off'?: (_envoy_api_v2_route_RetryPolicy_RetryBackOff); + /** + * HTTP response headers that trigger a retry if present in the response. A retry will be + * triggered if any of the header matches match the upstream response headers. + * The field is only consulted if 'retriable-headers' retry policy is active. + */ 'retriable_headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + /** + * HTTP headers which must be present in the request for retries to be attempted. + */ 'retriable_request_headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; } +/** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 11] + */ export interface RetryPolicy__Output { + /** + * Specifies the conditions under which retry takes place. These are the same + * conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and + * :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. + */ 'retry_on': (string); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. These are the same conditions documented for + * :ref:`config_http_filters_router_x-envoy-max-retries`. + */ 'num_retries': (_google_protobuf_UInt32Value__Output); + /** + * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The + * same conditions documented for + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. + * + * .. note:: + * + * If left unspecified, Envoy will use the global + * :ref:`route timeout ` for the request. + * Consequently, when using a :ref:`5xx ` based + * retry policy, a request that times out will not be retried as the total timeout budget + * would have been exhausted. + */ 'per_try_timeout': (_google_protobuf_Duration__Output); + /** + * Specifies an implementation of a RetryPriority which is used to determine the + * distribution of load across priorities used for retries. Refer to + * :ref:`retry plugin configuration ` for more details. + */ 'retry_priority': (_envoy_api_v2_route_RetryPolicy_RetryPriority__Output); + /** + * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host + * for retries. If any of the predicates reject the host, host selection will be reattempted. + * Refer to :ref:`retry plugin configuration ` for more + * details. + */ 'retry_host_predicate': (_envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output)[]; + /** + * The maximum number of times host selection will be reattempted before giving up, at which + * point the host that was last selected will be routed to. If unspecified, this will default to + * retrying once. + */ 'host_selection_retry_max_attempts': (string); + /** + * HTTP status codes that should trigger a retry in addition to those specified by retry_on. + */ 'retriable_status_codes': (number)[]; + /** + * Specifies parameters that control retry back off. This parameter is optional, in which case the + * default base interval is 25 milliseconds or, if set, the current value of the + * `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times + * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` + * describes Envoy's back-off algorithm. + */ 'retry_back_off': (_envoy_api_v2_route_RetryPolicy_RetryBackOff__Output); + /** + * HTTP response headers that trigger a retry if present in the response. A retry will be + * triggered if any of the header matches match the upstream response headers. + * The field is only consulted if 'retriable-headers' retry policy is active. + */ 'retriable_headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + /** + * HTTP headers which must be present in the request for retries to be attempted. + */ 'retriable_request_headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts index 42202684c..32c4786e0 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts @@ -13,42 +13,216 @@ import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; +/** + * A route is both a specification of how to match a request as well as an indication of what to do + * next (e.g., redirect, forward, rewrite, etc.). + * + * .. attention:: + * + * Envoy supports routing on HTTP method via :ref:`header matching + * `. + * [#next-free-field: 18] + */ export interface Route { + /** + * Route matching parameters. + */ 'match'?: (_envoy_api_v2_route_RouteMatch); + /** + * Route request to some upstream cluster. + */ 'route'?: (_envoy_api_v2_route_RouteAction); + /** + * Return a redirect. + */ 'redirect'?: (_envoy_api_v2_route_RedirectAction); + /** + * The Metadata field can be used to provide additional information + * about the route. It can be used for configuration, stats, and logging. + * The metadata should go under the filter namespace that will need it. + * For instance, if the metadata is intended for the Router filter, + * the filter name should be specified as *envoy.filters.http.router*. + */ 'metadata'?: (_envoy_api_v2_core_Metadata); + /** + * Decorator for the matched route. + */ 'decorator'?: (_envoy_api_v2_route_Decorator); + /** + * Return an arbitrary HTTP response directly, without proxying. + */ 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction); + /** + * The per_filter_config field can be used to provide route-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` for + * if and how it is utilized. + */ 'per_filter_config'?: (_google_protobuf_Struct); + /** + * Specifies a set of headers that will be added to requests matching this + * route. Headers specified at this level are applied before headers from the + * enclosing :ref:`envoy_api_msg_route.VirtualHost` and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a set of headers that will be added to responses to requests + * matching this route. Headers specified at this level are applied before + * headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * details on header value syntax, see the documentation on + * :ref:`custom request headers `. + */ 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a list of HTTP headers that should be removed from each response + * to requests matching this route. + */ 'response_headers_to_remove'?: (string)[]; + /** + * Specifies a list of HTTP headers that should be removed from each request + * matching this route. + */ 'request_headers_to_remove'?: (string)[]; + /** + * The typed_per_filter_config field can be used to provide route-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` for + * if and how it is utilized. + */ 'typed_per_filter_config'?: (_google_protobuf_Any); + /** + * Name for the route. + */ 'name'?: (string); + /** + * Presence of the object defines whether the connection manager's tracing configuration + * is overridden by this route specific instance. + */ 'tracing'?: (_envoy_api_v2_route_Tracing); + /** + * The maximum bytes which will be buffered for retries and shadowing. + * If set, the bytes actually buffered will be the minimum value of this and the + * listener per_connection_buffer_limit_bytes. + */ 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + /** + * [#not-implemented-hide:] + * If true, a filter will define the action (e.g., it could dynamically generate the + * RouteAction). + */ 'filter_action'?: (_envoy_api_v2_route_FilterAction); 'action'?: "route"|"redirect"|"direct_response"|"filter_action"; } +/** + * A route is both a specification of how to match a request as well as an indication of what to do + * next (e.g., redirect, forward, rewrite, etc.). + * + * .. attention:: + * + * Envoy supports routing on HTTP method via :ref:`header matching + * `. + * [#next-free-field: 18] + */ export interface Route__Output { + /** + * Route matching parameters. + */ 'match': (_envoy_api_v2_route_RouteMatch__Output); + /** + * Route request to some upstream cluster. + */ 'route'?: (_envoy_api_v2_route_RouteAction__Output); + /** + * Return a redirect. + */ 'redirect'?: (_envoy_api_v2_route_RedirectAction__Output); + /** + * The Metadata field can be used to provide additional information + * about the route. It can be used for configuration, stats, and logging. + * The metadata should go under the filter namespace that will need it. + * For instance, if the metadata is intended for the Router filter, + * the filter name should be specified as *envoy.filters.http.router*. + */ 'metadata': (_envoy_api_v2_core_Metadata__Output); + /** + * Decorator for the matched route. + */ 'decorator': (_envoy_api_v2_route_Decorator__Output); + /** + * Return an arbitrary HTTP response directly, without proxying. + */ 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction__Output); + /** + * The per_filter_config field can be used to provide route-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` for + * if and how it is utilized. + */ 'per_filter_config': (_google_protobuf_Struct__Output); + /** + * Specifies a set of headers that will be added to requests matching this + * route. Headers specified at this level are applied before headers from the + * enclosing :ref:`envoy_api_msg_route.VirtualHost` and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a set of headers that will be added to responses to requests + * matching this route. Headers specified at this level are applied before + * headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * details on header value syntax, see the documentation on + * :ref:`custom request headers `. + */ 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a list of HTTP headers that should be removed from each response + * to requests matching this route. + */ 'response_headers_to_remove': (string)[]; + /** + * Specifies a list of HTTP headers that should be removed from each request + * matching this route. + */ 'request_headers_to_remove': (string)[]; + /** + * The typed_per_filter_config field can be used to provide route-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` for + * if and how it is utilized. + */ 'typed_per_filter_config': (_google_protobuf_Any__Output); + /** + * Name for the route. + */ 'name': (string); + /** + * Presence of the object defines whether the connection manager's tracing configuration + * is overridden by this route specific instance. + */ 'tracing': (_envoy_api_v2_route_Tracing__Output); + /** + * The maximum bytes which will be buffered for retries and shadowing. + * If set, the bytes actually buffered will be the minimum value of this and the + * listener per_connection_buffer_limit_bytes. + */ 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + /** + * [#not-implemented-hide:] + * If true, a filter will define the action (e.g., it could dynamically generate the + * RouteAction). + */ 'filter_action'?: (_envoy_api_v2_route_FilterAction__Output); 'action': "route"|"redirect"|"direct_response"|"filter_action"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts index 7b58e06ee..02a8665a4 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts @@ -17,164 +17,987 @@ import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto export enum _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode { + /** + * HTTP status code - 503 Service Unavailable. + */ SERVICE_UNAVAILABLE = 0, + /** + * HTTP status code - 404 Not Found. + */ NOT_FOUND = 1, } +/** + * Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer + * `. + * [#next-free-field: 7] + */ export interface _envoy_api_v2_route_RouteAction_HashPolicy { + /** + * Header hash policy. + */ 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header); + /** + * Cookie hash policy. + */ 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie); + /** + * Connection properties hash policy. + */ 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties); + /** + * Query parameter hash policy. + */ 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter); + /** + * Filter state hash policy. + */ 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState); + /** + * The flag that short-circuits the hash computing. This field provides a + * 'fallback' style of configuration: "if a terminal policy doesn't work, + * fallback to rest of the policy list", it saves time when the terminal + * policy works. + * + * If true, and there is already a hash computed, ignore rest of the + * list of hash polices. + * For example, if the following hash methods are configured: + * + * ========= ======== + * specifier terminal + * ========= ======== + * Header A true + * Header B false + * Header C false + * ========= ======== + * + * The generateHash process ends if policy "header A" generates a hash, as + * it's a terminal policy. + */ 'terminal'?: (boolean); 'policy_specifier'?: "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; } +/** + * Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer + * `. + * [#next-free-field: 7] + */ export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { + /** + * Header hash policy. + */ 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header__Output); + /** + * Cookie hash policy. + */ 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output); + /** + * Connection properties hash policy. + */ 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output); + /** + * Query parameter hash policy. + */ 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output); + /** + * Filter state hash policy. + */ 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output); + /** + * The flag that short-circuits the hash computing. This field provides a + * 'fallback' style of configuration: "if a terminal policy doesn't work, + * fallback to rest of the policy list", it saves time when the terminal + * policy works. + * + * If true, and there is already a hash computed, ignore rest of the + * list of hash polices. + * For example, if the following hash methods are configured: + * + * ========= ======== + * specifier terminal + * ========= ======== + * Header A true + * Header B false + * Header C false + * ========= ======== + * + * The generateHash process ends if policy "header A" generates a hash, as + * it's a terminal policy. + */ 'terminal': (boolean); 'policy_specifier': "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; } export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties { + /** + * Hash on source IP address. + */ 'source_ip'?: (boolean); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output { + /** + * Hash on source IP address. + */ 'source_ip': (boolean); } +/** + * Envoy supports two types of cookie affinity: + * + * 1. Passive. Envoy takes a cookie that's present in the cookies header and + * hashes on its value. + * + * 2. Generated. Envoy generates and sets a cookie with an expiration (TTL) + * on the first request from the client in its response to the client, + * based on the endpoint the request gets sent to. The client then + * presents this on the next and all subsequent requests. The hash of + * this is sufficient to ensure these requests get sent to the same + * endpoint. The cookie is generated by hashing the source and + * destination ports and addresses so that multiple independent HTTP2 + * streams on the same connection will independently receive the same + * cookie, even if they arrive at the Envoy simultaneously. + */ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie { + /** + * The name of the cookie that will be used to obtain the hash key. If the + * cookie is not present and ttl below is not set, no hash will be + * produced. + */ 'name'?: (string); + /** + * If specified, a cookie with the TTL will be generated if the cookie is + * not present. If the TTL is present and zero, the generated cookie will + * be a session cookie. + */ 'ttl'?: (_google_protobuf_Duration); + /** + * The name of the path for the cookie. If no path is specified here, no path + * will be set for the cookie. + */ 'path'?: (string); } +/** + * Envoy supports two types of cookie affinity: + * + * 1. Passive. Envoy takes a cookie that's present in the cookies header and + * hashes on its value. + * + * 2. Generated. Envoy generates and sets a cookie with an expiration (TTL) + * on the first request from the client in its response to the client, + * based on the endpoint the request gets sent to. The client then + * presents this on the next and all subsequent requests. The hash of + * this is sufficient to ensure these requests get sent to the same + * endpoint. The cookie is generated by hashing the source and + * destination ports and addresses so that multiple independent HTTP2 + * streams on the same connection will independently receive the same + * cookie, even if they arrive at the Envoy simultaneously. + */ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output { + /** + * The name of the cookie that will be used to obtain the hash key. If the + * cookie is not present and ttl below is not set, no hash will be + * produced. + */ 'name': (string); + /** + * If specified, a cookie with the TTL will be generated if the cookie is + * not present. If the TTL is present and zero, the generated cookie will + * be a session cookie. + */ 'ttl': (_google_protobuf_Duration__Output); + /** + * The name of the path for the cookie. If no path is specified here, no path + * will be set for the cookie. + */ 'path': (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState { + /** + * The name of the Object in the per-request filterState, which is an + * Envoy::Http::Hashable object. If there is no data associated with the key, + * or the stored object is not Envoy::Http::Hashable, no hash will be produced. + */ 'key'?: (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output { + /** + * The name of the Object in the per-request filterState, which is an + * Envoy::Http::Hashable object. If there is no data associated with the key, + * or the stored object is not Envoy::Http::Hashable, no hash will be produced. + */ 'key': (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header { + /** + * The name of the request header that will be used to obtain the hash + * key. If the request header is not present, no hash will be produced. + */ 'header_name'?: (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header__Output { + /** + * The name of the request header that will be used to obtain the hash + * key. If the request header is not present, no hash will be produced. + */ 'header_name': (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter { + /** + * The name of the URL query parameter that will be used to obtain the hash + * key. If the parameter is not present, no hash will be produced. Query + * parameter names are case-sensitive. + */ 'name'?: (string); } export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output { + /** + * The name of the URL query parameter that will be used to obtain the hash + * key. If the parameter is not present, no hash will be produced. Query + * parameter names are case-sensitive. + */ 'name': (string); } // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +/** + * Configures :ref:`internal redirect ` behavior. + */ export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { PASS_THROUGH_INTERNAL_REDIRECT = 0, HANDLE_INTERNAL_REDIRECT = 1, } +/** + * The router is capable of shadowing traffic from one cluster to another. The current + * implementation is "fire and forget," meaning Envoy will not wait for the shadow cluster to + * respond before returning the response from the primary cluster. All normal statistics are + * collected for the shadow cluster making this feature useful for testing. + * + * During shadowing, the host/authority header is altered such that *-shadow* is appended. This is + * useful for logging. For example, *cluster1* becomes *cluster1-shadow*. + * + * .. note:: + * + * Shadowing will not be triggered if the primary cluster does not exist. + */ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { + /** + * Specifies the cluster that requests will be mirrored to. The cluster must + * exist in the cluster manager configuration. + */ 'cluster'?: (string); + /** + * If not specified, all requests to the target cluster will be mirrored. If + * specified, Envoy will lookup the runtime key to get the % of requests to + * mirror. Valid values are from 0 to 10000, allowing for increments of + * 0.01% of requests to be mirrored. If the runtime key is specified in the + * configuration but not present in runtime, 0 is the default and thus 0% of + * requests will be mirrored. + * + * .. attention:: + * + * **This field is deprecated**. Set the + * :ref:`runtime_fraction + * ` + * field instead. Mirroring occurs if both this and + * ` + * are not set. + */ 'runtime_key'?: (string); + /** + * If not specified, all requests to the target cluster will be mirrored. + * + * If specified, this field takes precedence over the `runtime_key` field and requests must also + * fall under the percentage of matches indicated by this field. + * + * For some fraction N/D, a random number in the range [0,D) is selected. If the + * number is <= the value of the numerator N, or if the key is not present, the default + * value, the request will be mirrored. + */ 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + /** + * Determines if the trace span should be sampled. Defaults to true. + */ 'trace_sampled'?: (_google_protobuf_BoolValue); } +/** + * The router is capable of shadowing traffic from one cluster to another. The current + * implementation is "fire and forget," meaning Envoy will not wait for the shadow cluster to + * respond before returning the response from the primary cluster. All normal statistics are + * collected for the shadow cluster making this feature useful for testing. + * + * During shadowing, the host/authority header is altered such that *-shadow* is appended. This is + * useful for logging. For example, *cluster1* becomes *cluster1-shadow*. + * + * .. note:: + * + * Shadowing will not be triggered if the primary cluster does not exist. + */ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { + /** + * Specifies the cluster that requests will be mirrored to. The cluster must + * exist in the cluster manager configuration. + */ 'cluster': (string); + /** + * If not specified, all requests to the target cluster will be mirrored. If + * specified, Envoy will lookup the runtime key to get the % of requests to + * mirror. Valid values are from 0 to 10000, allowing for increments of + * 0.01% of requests to be mirrored. If the runtime key is specified in the + * configuration but not present in runtime, 0 is the default and thus 0% of + * requests will be mirrored. + * + * .. attention:: + * + * **This field is deprecated**. Set the + * :ref:`runtime_fraction + * ` + * field instead. Mirroring occurs if both this and + * ` + * are not set. + */ 'runtime_key': (string); + /** + * If not specified, all requests to the target cluster will be mirrored. + * + * If specified, this field takes precedence over the `runtime_key` field and requests must also + * fall under the percentage of matches indicated by this field. + * + * For some fraction N/D, a random number in the range [0,D) is selected. If the + * number is <= the value of the numerator N, or if the key is not present, the default + * value, the request will be mirrored. + */ 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + /** + * Determines if the trace span should be sampled. Defaults to true. + */ 'trace_sampled': (_google_protobuf_BoolValue__Output); } +/** + * Allows enabling and disabling upgrades on a per-route basis. + * This overrides any enabled/disabled upgrade filter chain specified in the + * HttpConnectionManager + * :ref:`upgrade_configs + * ` + * but does not affect any custom filter chain specified there. + */ export interface _envoy_api_v2_route_RouteAction_UpgradeConfig { + /** + * The case-insensitive name of this upgrade, e.g. "websocket". + * For each upgrade type present in upgrade_configs, requests with + * Upgrade: [upgrade_type] will be proxied upstream. + */ 'upgrade_type'?: (string); + /** + * Determines if upgrades are available on this route. Defaults to true. + */ 'enabled'?: (_google_protobuf_BoolValue); } +/** + * Allows enabling and disabling upgrades on a per-route basis. + * This overrides any enabled/disabled upgrade filter chain specified in the + * HttpConnectionManager + * :ref:`upgrade_configs + * ` + * but does not affect any custom filter chain specified there. + */ export interface _envoy_api_v2_route_RouteAction_UpgradeConfig__Output { + /** + * The case-insensitive name of this upgrade, e.g. "websocket". + * For each upgrade type present in upgrade_configs, requests with + * Upgrade: [upgrade_type] will be proxied upstream. + */ 'upgrade_type': (string); + /** + * Determines if upgrades are available on this route. Defaults to true. + */ 'enabled': (_google_protobuf_BoolValue__Output); } +/** + * [#next-free-field: 34] + */ export interface RouteAction { + /** + * Indicates the upstream cluster to which the request should be routed + * to. + */ 'cluster'?: (string); + /** + * Envoy will determine the cluster to route to by reading the value of the + * HTTP header named by cluster_header from the request headers. If the + * header is not found or the referenced cluster does not exist, Envoy will + * return a 404 response. + * + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 + * *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + */ 'cluster_header'?: (string); + /** + * Multiple upstream clusters can be specified for a given route. The + * request is routed to one of the upstream clusters based on weights + * assigned to each cluster. See + * :ref:`traffic splitting ` + * for additional documentation. + */ 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster); + /** + * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints + * in the upstream cluster with metadata matching what's set in this field will be considered + * for load balancing. If using :ref:`weighted_clusters + * `, metadata will be merged, with values + * provided there taking precedence. The filter name should be specified as *envoy.lb*. + */ 'metadata_match'?: (_envoy_api_v2_core_Metadata); + /** + * Indicates that during forwarding, the matched prefix (or path) should be + * swapped with this value. This option allows application URLs to be rooted + * at a different path from those exposed at the reverse proxy layer. The router filter will + * place the original path before rewrite into the :ref:`x-envoy-original-path + * ` header. + * + * Only one of *prefix_rewrite* or + * :ref:`regex_rewrite ` + * may be specified. + * + * .. attention:: + * + * Pay careful attention to the use of trailing slashes in the + * :ref:`route's match ` prefix value. + * Stripping a prefix from a path requires multiple Routes to handle all cases. For example, + * rewriting * /prefix* to * /* and * /prefix/etc* to * /etc* cannot be done in a single + * :ref:`Route `, as shown by the below config entries: + * + * .. code-block:: yaml + * + * - match: + * prefix: "/prefix/" + * route: + * prefix_rewrite: "/" + * - match: + * prefix: "/prefix" + * route: + * prefix_rewrite: "/" + * + * Having above entries in the config, requests to * /prefix* will be stripped to * /*, while + * requests to * /prefix/etc* will be stripped to * /etc*. + */ 'prefix_rewrite'?: (string); + /** + * Indicates that during forwarding, the host header will be swapped with + * this value. + */ 'host_rewrite'?: (string); + /** + * Indicates that during forwarding, the host header will be swapped with + * the hostname of the upstream host chosen by the cluster manager. This + * option is applicable only when the destination cluster for a route is of + * type *strict_dns* or *logical_dns*. Setting this to true with other cluster + * types has no effect. + */ 'auto_host_rewrite'?: (_google_protobuf_BoolValue); + /** + * Specifies the upstream timeout for the route. If not specified, the default is 15s. This + * spans between the point at which the entire downstream request (i.e. end-of-stream) has been + * processed and when the upstream response has been completely processed. A value of 0 will + * disable the route's timeout. + * + * .. note:: + * + * This timeout includes all retries. See also + * :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the + * :ref:`retry overview `. + */ 'timeout'?: (_google_protobuf_Duration); + /** + * Indicates that the route has a retry policy. Note that if this is set, + * it'll take precedence over the virtual host level retry policy entirely + * (e.g.: policies are not merged, most internal one becomes the enforced policy). + */ 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); + /** + * Indicates that the route has a request mirroring policy. + * + * .. attention:: + * This field has been deprecated in favor of `request_mirror_policies` which supports one or + * more mirroring policies. + */ 'request_mirror_policy'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy); + /** + * Optionally specifies the :ref:`routing priority `. + */ 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); + /** + * Specifies a set of rate limit configurations that could be applied to the + * route. + */ 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; + /** + * Specifies if the rate limit filter should include the virtual host rate + * limits. By default, if the route configured rate limits, the virtual host + * :ref:`rate_limits ` are not applied to the + * request. + */ 'include_vh_rate_limits'?: (_google_protobuf_BoolValue); + /** + * Specifies a list of hash policies to use for ring hash load balancing. Each + * hash policy is evaluated individually and the combined result is used to + * route the request. The method of combination is deterministic such that + * identical lists of hash policies will produce the same hash. Since a hash + * policy examines specific parts of a request, it can fail to produce a hash + * (i.e. if the hashed header is not present). If (and only if) all configured + * hash policies fail to generate a hash, no hash will be produced for + * the route. In this case, the behavior is the same as if no hash policies + * were specified (i.e. the ring hash load balancer will choose a random + * backend). If a hash policy has the "terminal" attribute set to true, and + * there is already a hash generated, the hash is returned immediately, + * ignoring the rest of the hash policy list. + */ 'hash_policy'?: (_envoy_api_v2_route_RouteAction_HashPolicy)[]; + /** + * Indicates that the route has a CORS policy. + */ 'cors'?: (_envoy_api_v2_route_CorsPolicy); + /** + * The HTTP status code to use when configured cluster is not found. + * The default response code is 503 Service Unavailable. + */ 'cluster_not_found_response_code'?: (_envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); + /** + * If present, and the request is a gRPC request, use the + * `grpc-timeout header `_, + * or its default value (infinity) instead of + * :ref:`timeout `, but limit the applied timeout + * to the maximum value specified here. If configured as 0, the maximum allowed timeout for + * gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used + * and gRPC requests time out like any other requests using + * :ref:`timeout ` or its default. + * This can be used to prevent unexpected upstream request timeouts due to potentially long + * time gaps between gRPC request and response in gRPC streaming mode. + * + * .. note:: + * + * If a timeout is specified using :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, it takes + * precedence over `grpc-timeout header `_, when + * both are present. See also + * :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the + * :ref:`retry overview `. + */ 'max_grpc_timeout'?: (_google_protobuf_Duration); + /** + * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, + * although the connection manager wide :ref:`stream_idle_timeout + * ` + * will still apply. A value of 0 will completely disable the route's idle timeout, even if a + * connection manager stream idle timeout is configured. + * + * The idle timeout is distinct to :ref:`timeout + * `, which provides an upper bound + * on the upstream response time; :ref:`idle_timeout + * ` instead bounds the amount + * of time the request's stream may be idle. + * + * After header decoding, the idle timeout will apply on downstream and + * upstream request events. Each time an encode/decode event for headers or + * data is processed for the stream, the timer will be reset. If the timeout + * fires, the stream is terminated with a 408 Request Timeout error code if no + * upstream response header has been received, otherwise a stream reset + * occurs. + */ 'idle_timeout'?: (_google_protobuf_Duration); 'upgrade_configs'?: (_envoy_api_v2_route_RouteAction_UpgradeConfig)[]; 'internal_redirect_action'?: (_envoy_api_v2_route_RouteAction_InternalRedirectAction | keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); + /** + * Indicates that the route has a hedge policy. Note that if this is set, + * it'll take precedence over the virtual host level hedge policy entirely + * (e.g.: policies are not merged, most internal one becomes the enforced policy). + */ 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + /** + * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting + * the provided duration from the header. This is useful in allowing Envoy to set its global + * timeout to be less than that of the deadline imposed by the calling client, which makes it more + * likely that Envoy will handle the timeout instead of having the call canceled by the client. + * The offset will only be applied if the provided grpc_timeout is greater than the offset. This + * ensures that the offset will only ever decrease the timeout and never set it to 0 (meaning + * infinity). + */ 'grpc_timeout_offset'?: (_google_protobuf_Duration); + /** + * Indicates that during forwarding, the host header will be swapped with the content of given + * downstream or :ref:`custom ` header. + * If header value is empty, host header is left intact. + * + * .. attention:: + * + * Pay attention to the potential security implications of using this option. Provided header + * must come from trusted source. + */ 'auto_host_rewrite_header'?: (string); + /** + * Indicates that the route has request mirroring policies. + */ 'request_mirror_policies'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy)[]; + /** + * An internal redirect is handled, iff the number of previous internal redirects that a + * downstream request has encountered is lower than this value, and + * :ref:`internal_redirect_action ` + * is set to :ref:`HANDLE_INTERNAL_REDIRECT + * ` + * In the case where a downstream request is bounced among multiple routes by internal redirect, + * the first route that hits this threshold, or has + * :ref:`internal_redirect_action ` + * set to + * :ref:`PASS_THROUGH_INTERNAL_REDIRECT + * ` + * will pass the redirect back to downstream. + * + * If not specified, at most one redirect will be followed. + */ 'max_internal_redirects'?: (_google_protobuf_UInt32Value); + /** + * Indicates that during forwarding, portions of the path that match the + * pattern should be rewritten, even allowing the substitution of capture + * groups from the pattern into the new path as specified by the rewrite + * substitution string. This is useful to allow application paths to be + * rewritten in a way that is aware of segments with variable content like + * identifiers. The router filter will place the original path as it was + * before the rewrite into the :ref:`x-envoy-original-path + * ` header. + * + * Only one of :ref:`prefix_rewrite ` + * or *regex_rewrite* may be specified. + * + * Examples using Google's `RE2 `_ engine: + * + * * The path pattern ``^/service/([^/]+)(/.*)$`` paired with a substitution + * string of ``\2/instance/\1`` would transform ``/service/foo/v1/api`` + * into ``/v1/api/instance/foo``. + * + * * The pattern ``one`` paired with a substitution string of ``two`` would + * transform ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/two/zzz``. + * + * * The pattern ``^(.*?)one(.*)$`` paired with a substitution string of + * ``\1two\2`` would replace only the first occurrence of ``one``, + * transforming path ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/one/zzz``. + * + * * The pattern ``(?i)/xxx/`` paired with a substitution string of ``/yyy/`` + * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to + * ``/aaa/yyy/bbb``. + */ 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute); + /** + * [#not-implemented-hide:] + * Specifies the configuration for retry policy extension. Note that if this is set, it'll take + * precedence over the virtual host level retry policy entirely (e.g.: policies are not merged, + * most internal one becomes the enforced policy). :ref:`Retry policy ` + * should not be set if this field is used. + */ 'retry_policy_typed_config'?: (_google_protobuf_Any); 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier'?: "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; } +/** + * [#next-free-field: 34] + */ export interface RouteAction__Output { + /** + * Indicates the upstream cluster to which the request should be routed + * to. + */ 'cluster'?: (string); + /** + * Envoy will determine the cluster to route to by reading the value of the + * HTTP header named by cluster_header from the request headers. If the + * header is not found or the referenced cluster does not exist, Envoy will + * return a 404 response. + * + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 + * *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + */ 'cluster_header'?: (string); + /** + * Multiple upstream clusters can be specified for a given route. The + * request is routed to one of the upstream clusters based on weights + * assigned to each cluster. See + * :ref:`traffic splitting ` + * for additional documentation. + */ 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster__Output); + /** + * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints + * in the upstream cluster with metadata matching what's set in this field will be considered + * for load balancing. If using :ref:`weighted_clusters + * `, metadata will be merged, with values + * provided there taking precedence. The filter name should be specified as *envoy.lb*. + */ 'metadata_match': (_envoy_api_v2_core_Metadata__Output); + /** + * Indicates that during forwarding, the matched prefix (or path) should be + * swapped with this value. This option allows application URLs to be rooted + * at a different path from those exposed at the reverse proxy layer. The router filter will + * place the original path before rewrite into the :ref:`x-envoy-original-path + * ` header. + * + * Only one of *prefix_rewrite* or + * :ref:`regex_rewrite ` + * may be specified. + * + * .. attention:: + * + * Pay careful attention to the use of trailing slashes in the + * :ref:`route's match ` prefix value. + * Stripping a prefix from a path requires multiple Routes to handle all cases. For example, + * rewriting * /prefix* to * /* and * /prefix/etc* to * /etc* cannot be done in a single + * :ref:`Route `, as shown by the below config entries: + * + * .. code-block:: yaml + * + * - match: + * prefix: "/prefix/" + * route: + * prefix_rewrite: "/" + * - match: + * prefix: "/prefix" + * route: + * prefix_rewrite: "/" + * + * Having above entries in the config, requests to * /prefix* will be stripped to * /*, while + * requests to * /prefix/etc* will be stripped to * /etc*. + */ 'prefix_rewrite': (string); + /** + * Indicates that during forwarding, the host header will be swapped with + * this value. + */ 'host_rewrite'?: (string); + /** + * Indicates that during forwarding, the host header will be swapped with + * the hostname of the upstream host chosen by the cluster manager. This + * option is applicable only when the destination cluster for a route is of + * type *strict_dns* or *logical_dns*. Setting this to true with other cluster + * types has no effect. + */ 'auto_host_rewrite'?: (_google_protobuf_BoolValue__Output); + /** + * Specifies the upstream timeout for the route. If not specified, the default is 15s. This + * spans between the point at which the entire downstream request (i.e. end-of-stream) has been + * processed and when the upstream response has been completely processed. A value of 0 will + * disable the route's timeout. + * + * .. note:: + * + * This timeout includes all retries. See also + * :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the + * :ref:`retry overview `. + */ 'timeout': (_google_protobuf_Duration__Output); + /** + * Indicates that the route has a retry policy. Note that if this is set, + * it'll take precedence over the virtual host level retry policy entirely + * (e.g.: policies are not merged, most internal one becomes the enforced policy). + */ 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); + /** + * Indicates that the route has a request mirroring policy. + * + * .. attention:: + * This field has been deprecated in favor of `request_mirror_policies` which supports one or + * more mirroring policies. + */ 'request_mirror_policy': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output); + /** + * Optionally specifies the :ref:`routing priority `. + */ 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); + /** + * Specifies a set of rate limit configurations that could be applied to the + * route. + */ 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; + /** + * Specifies if the rate limit filter should include the virtual host rate + * limits. By default, if the route configured rate limits, the virtual host + * :ref:`rate_limits ` are not applied to the + * request. + */ 'include_vh_rate_limits': (_google_protobuf_BoolValue__Output); + /** + * Specifies a list of hash policies to use for ring hash load balancing. Each + * hash policy is evaluated individually and the combined result is used to + * route the request. The method of combination is deterministic such that + * identical lists of hash policies will produce the same hash. Since a hash + * policy examines specific parts of a request, it can fail to produce a hash + * (i.e. if the hashed header is not present). If (and only if) all configured + * hash policies fail to generate a hash, no hash will be produced for + * the route. In this case, the behavior is the same as if no hash policies + * were specified (i.e. the ring hash load balancer will choose a random + * backend). If a hash policy has the "terminal" attribute set to true, and + * there is already a hash generated, the hash is returned immediately, + * ignoring the rest of the hash policy list. + */ 'hash_policy': (_envoy_api_v2_route_RouteAction_HashPolicy__Output)[]; + /** + * Indicates that the route has a CORS policy. + */ 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + /** + * The HTTP status code to use when configured cluster is not found. + * The default response code is 503 Service Unavailable. + */ 'cluster_not_found_response_code': (keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); + /** + * If present, and the request is a gRPC request, use the + * `grpc-timeout header `_, + * or its default value (infinity) instead of + * :ref:`timeout `, but limit the applied timeout + * to the maximum value specified here. If configured as 0, the maximum allowed timeout for + * gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used + * and gRPC requests time out like any other requests using + * :ref:`timeout ` or its default. + * This can be used to prevent unexpected upstream request timeouts due to potentially long + * time gaps between gRPC request and response in gRPC streaming mode. + * + * .. note:: + * + * If a timeout is specified using :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, it takes + * precedence over `grpc-timeout header `_, when + * both are present. See also + * :ref:`config_http_filters_router_x-envoy-upstream-rq-timeout-ms`, + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the + * :ref:`retry overview `. + */ 'max_grpc_timeout': (_google_protobuf_Duration__Output); + /** + * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, + * although the connection manager wide :ref:`stream_idle_timeout + * ` + * will still apply. A value of 0 will completely disable the route's idle timeout, even if a + * connection manager stream idle timeout is configured. + * + * The idle timeout is distinct to :ref:`timeout + * `, which provides an upper bound + * on the upstream response time; :ref:`idle_timeout + * ` instead bounds the amount + * of time the request's stream may be idle. + * + * After header decoding, the idle timeout will apply on downstream and + * upstream request events. Each time an encode/decode event for headers or + * data is processed for the stream, the timer will be reset. If the timeout + * fires, the stream is terminated with a 408 Request Timeout error code if no + * upstream response header has been received, otherwise a stream reset + * occurs. + */ 'idle_timeout': (_google_protobuf_Duration__Output); 'upgrade_configs': (_envoy_api_v2_route_RouteAction_UpgradeConfig__Output)[]; 'internal_redirect_action': (keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); + /** + * Indicates that the route has a hedge policy. Note that if this is set, + * it'll take precedence over the virtual host level hedge policy entirely + * (e.g.: policies are not merged, most internal one becomes the enforced policy). + */ 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + /** + * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting + * the provided duration from the header. This is useful in allowing Envoy to set its global + * timeout to be less than that of the deadline imposed by the calling client, which makes it more + * likely that Envoy will handle the timeout instead of having the call canceled by the client. + * The offset will only be applied if the provided grpc_timeout is greater than the offset. This + * ensures that the offset will only ever decrease the timeout and never set it to 0 (meaning + * infinity). + */ 'grpc_timeout_offset': (_google_protobuf_Duration__Output); + /** + * Indicates that during forwarding, the host header will be swapped with the content of given + * downstream or :ref:`custom ` header. + * If header value is empty, host header is left intact. + * + * .. attention:: + * + * Pay attention to the potential security implications of using this option. Provided header + * must come from trusted source. + */ 'auto_host_rewrite_header'?: (string); + /** + * Indicates that the route has request mirroring policies. + */ 'request_mirror_policies': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output)[]; + /** + * An internal redirect is handled, iff the number of previous internal redirects that a + * downstream request has encountered is lower than this value, and + * :ref:`internal_redirect_action ` + * is set to :ref:`HANDLE_INTERNAL_REDIRECT + * ` + * In the case where a downstream request is bounced among multiple routes by internal redirect, + * the first route that hits this threshold, or has + * :ref:`internal_redirect_action ` + * set to + * :ref:`PASS_THROUGH_INTERNAL_REDIRECT + * ` + * will pass the redirect back to downstream. + * + * If not specified, at most one redirect will be followed. + */ 'max_internal_redirects': (_google_protobuf_UInt32Value__Output); + /** + * Indicates that during forwarding, portions of the path that match the + * pattern should be rewritten, even allowing the substitution of capture + * groups from the pattern into the new path as specified by the rewrite + * substitution string. This is useful to allow application paths to be + * rewritten in a way that is aware of segments with variable content like + * identifiers. The router filter will place the original path as it was + * before the rewrite into the :ref:`x-envoy-original-path + * ` header. + * + * Only one of :ref:`prefix_rewrite ` + * or *regex_rewrite* may be specified. + * + * Examples using Google's `RE2 `_ engine: + * + * * The path pattern ``^/service/([^/]+)(/.*)$`` paired with a substitution + * string of ``\2/instance/\1`` would transform ``/service/foo/v1/api`` + * into ``/v1/api/instance/foo``. + * + * * The pattern ``one`` paired with a substitution string of ``two`` would + * transform ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/two/zzz``. + * + * * The pattern ``^(.*?)one(.*)$`` paired with a substitution string of + * ``\1two\2`` would replace only the first occurrence of ``one``, + * transforming path ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/one/zzz``. + * + * * The pattern ``(?i)/xxx/`` paired with a substitution string of ``/yyy/`` + * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to + * ``/aaa/yyy/bbb``. + */ 'regex_rewrite': (_envoy_type_matcher_RegexMatchAndSubstitute__Output); + /** + * [#not-implemented-hide:] + * Specifies the configuration for retry policy extension. Note that if this is set, it'll take + * precedence over the virtual host level retry policy entirely (e.g.: policies are not merged, + * most internal one becomes the enforced policy). :ref:`Retry policy ` + * should not be set if this field is used. + */ 'retry_policy_typed_config': (_google_protobuf_Any__Output); 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier': "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts index 188335bbf..c60c956fe 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts @@ -13,39 +13,235 @@ export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output { } export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions { + /** + * If specified, the route will match against whether or not a certificate is presented. + * If not specified, certificate presentation status (true or false) will not be considered when route matching. + */ 'presented'?: (_google_protobuf_BoolValue); + /** + * If specified, the route will match against whether or not a certificate is validated. + * If not specified, certificate validation status (true or false) will not be considered when route matching. + */ 'validated'?: (_google_protobuf_BoolValue); } export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output { + /** + * If specified, the route will match against whether or not a certificate is presented. + * If not specified, certificate presentation status (true or false) will not be considered when route matching. + */ 'presented': (_google_protobuf_BoolValue__Output); + /** + * If specified, the route will match against whether or not a certificate is validated. + * If not specified, certificate validation status (true or false) will not be considered when route matching. + */ 'validated': (_google_protobuf_BoolValue__Output); } +/** + * [#next-free-field: 12] + */ export interface RouteMatch { + /** + * If specified, the route is a prefix rule meaning that the prefix must + * match the beginning of the *:path* header. + */ 'prefix'?: (string); + /** + * If specified, the route is an exact path rule meaning that the path must + * exactly match the *:path* header once the query string is removed. + */ 'path'?: (string); + /** + * If specified, the route is a regular expression rule meaning that the + * regex must match the *:path* header once the query string is removed. The entire path + * (without the query string) must match the regex. The rule will not match if only a + * subsequence of the *:path* header matches the regex. The regex grammar is defined `here + * `_. + * + * Examples: + * + * * The regex ``/b[io]t`` matches the path * /bit* + * * The regex ``/b[io]t`` matches the path * /bot* + * * The regex ``/b[io]t`` does not match the path * /bite* + * * The regex ``/b[io]t`` does not match the path * /bit/bot* + * + * .. attention:: + * This field has been deprecated in favor of `safe_regex` as it is not safe for use with + * untrusted input in all cases. + */ 'regex'?: (string); + /** + * Indicates that prefix/path matching should be case insensitive. The default + * is true. + */ 'case_sensitive'?: (_google_protobuf_BoolValue); + /** + * Specifies a set of headers that the route should match on. The router will + * check the request’s headers against all the specified headers in the route + * config. A match will happen if all the headers in the route are present in + * the request with the same values (or based on presence if the value field + * is not in the config). + */ 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + /** + * Specifies a set of URL query parameters on which the route should + * match. The router will check the query string from the *path* header + * against all the specified query parameters. If the number of specified + * query parameters is nonzero, they all must match the *path* header's + * query string for a match to occur. + */ 'query_parameters'?: (_envoy_api_v2_route_QueryParameterMatcher)[]; + /** + * If specified, only gRPC requests will be matched. The router will check + * that the content-type header has a application/grpc or one of the various + * application/grpc+ values. + */ 'grpc'?: (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions); + /** + * Indicates that the route should additionally match on a runtime key. Every time the route + * is considered for a match, it must also fall under the percentage of matches indicated by + * this field. For some fraction N/D, a random number in the range [0,D) is selected. If the + * number is <= the value of the numerator N, or if the key is not present, the default + * value, the router continues to evaluate the remaining match criteria. A runtime_fraction + * route configuration can be used to roll out route changes in a gradual manner without full + * code/config deploys. Refer to the :ref:`traffic shifting + * ` docs for additional documentation. + * + * .. note:: + * + * Parsing this field is implemented such that the runtime key's data may be represented + * as a FractionalPercent proto represented as JSON/YAML and may also be represented as an + * integer with the assumption that the value is an integral percentage out of 100. For + * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent + * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. + */ 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + /** + * If specified, the route is a regular expression rule meaning that the + * regex must match the *:path* header once the query string is removed. The entire path + * (without the query string) must match the regex. The rule will not match if only a + * subsequence of the *:path* header matches the regex. + * + * [#next-major-version: In the v3 API we should redo how path specification works such + * that we utilize StringMatcher, and additionally have consistent options around whether we + * strip query strings, do a case sensitive match, etc. In the interim it will be too disruptive + * to deprecate the existing options. We should even consider whether we want to do away with + * path_specifier entirely and just rely on a set of header matchers which can already match + * on :path, etc. The issue with that is it is unclear how to generically deal with query string + * stripping. This needs more thought.] + */ 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); + /** + * If specified, the client tls context will be matched against the defined + * match options. + * + * [#next-major-version: unify with RBAC] + */ 'tls_context'?: (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions); 'path_specifier'?: "prefix"|"path"|"regex"|"safe_regex"; } +/** + * [#next-free-field: 12] + */ export interface RouteMatch__Output { + /** + * If specified, the route is a prefix rule meaning that the prefix must + * match the beginning of the *:path* header. + */ 'prefix'?: (string); + /** + * If specified, the route is an exact path rule meaning that the path must + * exactly match the *:path* header once the query string is removed. + */ 'path'?: (string); + /** + * If specified, the route is a regular expression rule meaning that the + * regex must match the *:path* header once the query string is removed. The entire path + * (without the query string) must match the regex. The rule will not match if only a + * subsequence of the *:path* header matches the regex. The regex grammar is defined `here + * `_. + * + * Examples: + * + * * The regex ``/b[io]t`` matches the path * /bit* + * * The regex ``/b[io]t`` matches the path * /bot* + * * The regex ``/b[io]t`` does not match the path * /bite* + * * The regex ``/b[io]t`` does not match the path * /bit/bot* + * + * .. attention:: + * This field has been deprecated in favor of `safe_regex` as it is not safe for use with + * untrusted input in all cases. + */ 'regex'?: (string); + /** + * Indicates that prefix/path matching should be case insensitive. The default + * is true. + */ 'case_sensitive': (_google_protobuf_BoolValue__Output); + /** + * Specifies a set of headers that the route should match on. The router will + * check the request’s headers against all the specified headers in the route + * config. A match will happen if all the headers in the route are present in + * the request with the same values (or based on presence if the value field + * is not in the config). + */ 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + /** + * Specifies a set of URL query parameters on which the route should + * match. The router will check the query string from the *path* header + * against all the specified query parameters. If the number of specified + * query parameters is nonzero, they all must match the *path* header's + * query string for a match to occur. + */ 'query_parameters': (_envoy_api_v2_route_QueryParameterMatcher__Output)[]; + /** + * If specified, only gRPC requests will be matched. The router will check + * that the content-type header has a application/grpc or one of the various + * application/grpc+ values. + */ 'grpc': (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output); + /** + * Indicates that the route should additionally match on a runtime key. Every time the route + * is considered for a match, it must also fall under the percentage of matches indicated by + * this field. For some fraction N/D, a random number in the range [0,D) is selected. If the + * number is <= the value of the numerator N, or if the key is not present, the default + * value, the router continues to evaluate the remaining match criteria. A runtime_fraction + * route configuration can be used to roll out route changes in a gradual manner without full + * code/config deploys. Refer to the :ref:`traffic shifting + * ` docs for additional documentation. + * + * .. note:: + * + * Parsing this field is implemented such that the runtime key's data may be represented + * as a FractionalPercent proto represented as JSON/YAML and may also be represented as an + * integer with the assumption that the value is an integral percentage out of 100. For + * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent + * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. + */ 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + /** + * If specified, the route is a regular expression rule meaning that the + * regex must match the *:path* header once the query string is removed. The entire path + * (without the query string) must match the regex. The rule will not match if only a + * subsequence of the *:path* header matches the regex. + * + * [#next-major-version: In the v3 API we should redo how path specification works such + * that we utilize StringMatcher, and additionally have consistent options around whether we + * strip query strings, do a case sensitive match, etc. In the interim it will be too disruptive + * to deprecate the existing options. We should even consider whether we want to do away with + * path_specifier entirely and just rely on a set of header matchers which can already match + * on :path, etc. The issue with that is it is unclear how to generically deal with query string + * stripping. This needs more thought.] + */ 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); + /** + * If specified, the client tls context will be matched against the defined + * match options. + * + * [#next-major-version: unify with RBAC] + */ 'tls_context': (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output); 'path_specifier': "prefix"|"path"|"regex"|"safe_regex"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts index 6709864e7..f69211c43 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts @@ -4,15 +4,81 @@ import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__ import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../envoy/type/tracing/v2/CustomTag'; export interface Tracing { + /** + * Target percentage of requests managed by this HTTP connection manager that will be force + * traced if the :ref:`x-client-trace-id ` + * header is set. This field is a direct analog for the runtime variable + * 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + * `. + * Default: 100% + */ 'client_sampling'?: (_envoy_type_FractionalPercent); + /** + * Target percentage of requests managed by this HTTP connection manager that will be randomly + * selected for trace generation, if not requested by the client or not forced. This field is + * a direct analog for the runtime variable 'tracing.random_sampling' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ 'random_sampling'?: (_envoy_type_FractionalPercent); + /** + * Target percentage of requests managed by this HTTP connection manager that will be traced + * after all other sampling checks have been applied (client-directed, force tracing, random + * sampling). This field functions as an upper limit on the total configured sampling rate. For + * instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + * of client requests with the appropriate headers to be force traced. This field is a direct + * analog for the runtime variable 'tracing.global_enabled' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ 'overall_sampling'?: (_envoy_type_FractionalPercent); + /** + * A list of custom tags with unique tag name to create tags for the active span. + * It will take effect after merging with the :ref:`corresponding configuration + * ` + * configured in the HTTP connection manager. If two tags with the same name are configured + * each in the HTTP connection manager and the route level, the one configured here takes + * priority. + */ 'custom_tags'?: (_envoy_type_tracing_v2_CustomTag)[]; } export interface Tracing__Output { + /** + * Target percentage of requests managed by this HTTP connection manager that will be force + * traced if the :ref:`x-client-trace-id ` + * header is set. This field is a direct analog for the runtime variable + * 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + * `. + * Default: 100% + */ 'client_sampling': (_envoy_type_FractionalPercent__Output); + /** + * Target percentage of requests managed by this HTTP connection manager that will be randomly + * selected for trace generation, if not requested by the client or not forced. This field is + * a direct analog for the runtime variable 'tracing.random_sampling' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ 'random_sampling': (_envoy_type_FractionalPercent__Output); + /** + * Target percentage of requests managed by this HTTP connection manager that will be traced + * after all other sampling checks have been applied (client-directed, force tracing, random + * sampling). This field functions as an upper limit on the total configured sampling rate. For + * instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + * of client requests with the appropriate headers to be force traced. This field is a direct + * analog for the runtime variable 'tracing.global_enabled' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ 'overall_sampling': (_envoy_type_FractionalPercent__Output); + /** + * A list of custom tags with unique tag name to create tags for the active span. + * It will take effect after merging with the :ref:`corresponding configuration + * ` + * configured in the HTTP connection manager. If two tags with the same name are configured + * each in the HTTP connection manager and the route level, the one configured here takes + * priority. + */ 'custom_tags': (_envoy_type_tracing_v2_CustomTag__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts index 5596328e5..fb62d9a51 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts @@ -3,16 +3,118 @@ import { RequestMethod as _envoy_api_v2_core_RequestMethod } from '../../../../envoy/api/v2/core/RequestMethod'; import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +/** + * A virtual cluster is a way of specifying a regex matching rule against + * certain important endpoints such that statistics are generated explicitly for + * the matched requests. The reason this is useful is that when doing + * prefix/path matching Envoy does not always know what the application + * considers to be an endpoint. Thus, it’s impossible for Envoy to generically + * emit per endpoint statistics. However, often systems have highly critical + * endpoints that they wish to get “perfect†statistics on. Virtual cluster + * statistics are perfect in the sense that they are emitted on the downstream + * side such that they include network level failures. + * + * Documentation for :ref:`virtual cluster statistics `. + * + * .. note:: + * + * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for + * every application endpoint. This is both not easily maintainable and as well the matching and + * statistics output are not free. + */ export interface VirtualCluster { + /** + * Specifies a regex pattern to use for matching requests. The entire path of the request + * must match the regex. The regex grammar used is defined `here + * `_. + * + * Examples: + * + * * The regex ``/rides/\d+`` matches the path * /rides/0* + * * The regex ``/rides/\d+`` matches the path * /rides/123* + * * The regex ``/rides/\d+`` does not match the path * /rides/123/456* + * + * .. attention:: + * This field has been deprecated in favor of `headers` as it is not safe for use with + * untrusted input in all cases. + */ 'pattern'?: (string); + /** + * Specifies the name of the virtual cluster. The virtual cluster name as well + * as the virtual host name are used when emitting statistics. The statistics are emitted by the + * router filter and are documented :ref:`here `. + */ 'name'?: (string); + /** + * Optionally specifies the HTTP method to match on. For example GET, PUT, + * etc. + * + * .. attention:: + * This field has been deprecated in favor of `headers`. + */ 'method'?: (_envoy_api_v2_core_RequestMethod | keyof typeof _envoy_api_v2_core_RequestMethod); + /** + * Specifies a list of header matchers to use for matching requests. Each specified header must + * match. The pseudo-headers `:path` and `:method` can be used to match the request path and + * method, respectively. + */ 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; } +/** + * A virtual cluster is a way of specifying a regex matching rule against + * certain important endpoints such that statistics are generated explicitly for + * the matched requests. The reason this is useful is that when doing + * prefix/path matching Envoy does not always know what the application + * considers to be an endpoint. Thus, it’s impossible for Envoy to generically + * emit per endpoint statistics. However, often systems have highly critical + * endpoints that they wish to get “perfect†statistics on. Virtual cluster + * statistics are perfect in the sense that they are emitted on the downstream + * side such that they include network level failures. + * + * Documentation for :ref:`virtual cluster statistics `. + * + * .. note:: + * + * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for + * every application endpoint. This is both not easily maintainable and as well the matching and + * statistics output are not free. + */ export interface VirtualCluster__Output { + /** + * Specifies a regex pattern to use for matching requests. The entire path of the request + * must match the regex. The regex grammar used is defined `here + * `_. + * + * Examples: + * + * * The regex ``/rides/\d+`` matches the path * /rides/0* + * * The regex ``/rides/\d+`` matches the path * /rides/123* + * * The regex ``/rides/\d+`` does not match the path * /rides/123/456* + * + * .. attention:: + * This field has been deprecated in favor of `headers` as it is not safe for use with + * untrusted input in all cases. + */ 'pattern': (string); + /** + * Specifies the name of the virtual cluster. The virtual cluster name as well + * as the virtual host name are used when emitting statistics. The statistics are emitted by the + * router filter and are documented :ref:`here `. + */ 'name': (string); + /** + * Optionally specifies the HTTP method to match on. For example GET, PUT, + * etc. + * + * .. attention:: + * This field has been deprecated in favor of `headers`. + */ 'method': (keyof typeof _envoy_api_v2_core_RequestMethod); + /** + * Specifies a list of header matchers to use for matching requests. Each specified header must + * match. The pseudo-headers `:path` and `:method` can be used to match the request path and + * method, respectively. + */ 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts index 5126a8e7c..ebb926f16 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts @@ -14,51 +14,328 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto export enum _envoy_api_v2_route_VirtualHost_TlsRequirementType { + /** + * No TLS requirement for the virtual host. + */ NONE = 0, + /** + * External requests must use TLS. If a request is external and it is not + * using TLS, a 301 redirect will be sent telling the client to use HTTPS. + */ EXTERNAL_ONLY = 1, + /** + * All requests must use TLS. If a request is not using TLS, a 301 redirect + * will be sent telling the client to use HTTPS. + */ ALL = 2, } +/** + * The top level element in the routing configuration is a virtual host. Each virtual host has + * a logical name as well as a set of domains that get routed to it based on the incoming request's + * host header. This allows a single listener to service multiple top level domain path trees. Once + * a virtual host is selected based on the domain, the routes are processed in order to see which + * upstream cluster to route to or whether to perform a redirect. + * [#next-free-field: 21] + */ export interface VirtualHost { + /** + * The logical name of the virtual host. This is used when emitting certain + * statistics but is not relevant for routing. + */ 'name'?: (string); + /** + * A list of domains (host/authority header) that will be matched to this + * virtual host. Wildcard hosts are supported in the suffix or prefix form. + * + * Domain search order: + * 1. Exact domain names: ``www.foo.com``. + * 2. Suffix domain wildcards: ``*.foo.com`` or ``*-bar.foo.com``. + * 3. Prefix domain wildcards: ``foo.*`` or ``foo-*``. + * 4. Special wildcard ``*`` matching any domain. + * + * .. note:: + * + * The wildcard will not match the empty string. + * e.g. ``*-bar.foo.com`` will match ``baz-bar.foo.com`` but not ``-bar.foo.com``. + * The longest wildcards match first. + * Only a single virtual host in the entire route configuration can match on ``*``. A domain + * must be unique across all virtual hosts or the config will fail to load. + * + * Domains cannot contain control characters. This is validated by the well_known_regex HTTP_HEADER_VALUE. + */ 'domains'?: (string)[]; + /** + * The list of routes that will be matched, in order, for incoming requests. + * The first route that matches will be used. + */ 'routes'?: (_envoy_api_v2_route_Route)[]; + /** + * Specifies the type of TLS enforcement the virtual host expects. If this option is not + * specified, there is no TLS requirement for the virtual host. + */ 'require_tls'?: (_envoy_api_v2_route_VirtualHost_TlsRequirementType | keyof typeof _envoy_api_v2_route_VirtualHost_TlsRequirementType); + /** + * A list of virtual clusters defined for this virtual host. Virtual clusters + * are used for additional statistics gathering. + */ 'virtual_clusters'?: (_envoy_api_v2_route_VirtualCluster)[]; + /** + * Specifies a set of rate limit configurations that will be applied to the + * virtual host. + */ 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; + /** + * Specifies a list of HTTP headers that should be added to each request + * handled by this virtual host. Headers specified at this level are applied + * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * details on header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Indicates that the virtual host has a CORS policy. + */ 'cors'?: (_envoy_api_v2_route_CorsPolicy); + /** + * Specifies a list of HTTP headers that should be added to each response + * handled by this virtual host. Headers specified at this level are applied + * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * details on header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a list of HTTP headers that should be removed from each response + * handled by this virtual host. + */ 'response_headers_to_remove'?: (string)[]; + /** + * The per_filter_config field can be used to provide virtual host-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'per_filter_config'?: (_google_protobuf_Struct); + /** + * Specifies a list of HTTP headers that should be removed from each request + * handled by this virtual host. + */ 'request_headers_to_remove'?: (string)[]; + /** + * Decides whether the :ref:`x-envoy-attempt-count + * ` header should be included + * in the upstream request. Setting this option will cause it to override any existing header + * value, so in the case of two Envoys on the request path with this option enabled, the upstream + * will see the attempt count as perceived by the second Envoy. Defaults to false. + * This header is unaffected by the + * :ref:`suppress_envoy_headers + * ` flag. + * + * [#next-major-version: rename to include_attempt_count_in_request.] + */ 'include_request_attempt_count'?: (boolean); + /** + * The per_filter_config field can be used to provide virtual host-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'typed_per_filter_config'?: (_google_protobuf_Any); + /** + * Indicates the retry policy for all routes in this virtual host. Note that setting a + * route level entry will take precedence over this config and it'll be treated + * independently (e.g.: values are not inherited). + */ 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); + /** + * Indicates the hedge policy for all routes in this virtual host. Note that setting a + * route level entry will take precedence over this config and it'll be treated + * independently (e.g.: values are not inherited). + */ 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + /** + * The maximum bytes which will be buffered for retries and shadowing. + * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum + * value of this and the listener per_connection_buffer_limit_bytes. + */ 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + /** + * Decides whether the :ref:`x-envoy-attempt-count + * ` header should be included + * in the downstream response. Setting this option will cause the router to override any existing header + * value, so in the case of two Envoys on the request path with this option enabled, the downstream + * will see the attempt count as perceived by the Envoy closest upstream from itself. Defaults to false. + * This header is unaffected by the + * :ref:`suppress_envoy_headers + * ` flag. + */ 'include_attempt_count_in_response'?: (boolean); + /** + * [#not-implemented-hide:] + * Specifies the configuration for retry policy extension. Note that setting a route level entry + * will take precedence over this config and it'll be treated independently (e.g.: values are not + * inherited). :ref:`Retry policy ` should not be + * set if this field is used. + */ 'retry_policy_typed_config'?: (_google_protobuf_Any); } +/** + * The top level element in the routing configuration is a virtual host. Each virtual host has + * a logical name as well as a set of domains that get routed to it based on the incoming request's + * host header. This allows a single listener to service multiple top level domain path trees. Once + * a virtual host is selected based on the domain, the routes are processed in order to see which + * upstream cluster to route to or whether to perform a redirect. + * [#next-free-field: 21] + */ export interface VirtualHost__Output { + /** + * The logical name of the virtual host. This is used when emitting certain + * statistics but is not relevant for routing. + */ 'name': (string); + /** + * A list of domains (host/authority header) that will be matched to this + * virtual host. Wildcard hosts are supported in the suffix or prefix form. + * + * Domain search order: + * 1. Exact domain names: ``www.foo.com``. + * 2. Suffix domain wildcards: ``*.foo.com`` or ``*-bar.foo.com``. + * 3. Prefix domain wildcards: ``foo.*`` or ``foo-*``. + * 4. Special wildcard ``*`` matching any domain. + * + * .. note:: + * + * The wildcard will not match the empty string. + * e.g. ``*-bar.foo.com`` will match ``baz-bar.foo.com`` but not ``-bar.foo.com``. + * The longest wildcards match first. + * Only a single virtual host in the entire route configuration can match on ``*``. A domain + * must be unique across all virtual hosts or the config will fail to load. + * + * Domains cannot contain control characters. This is validated by the well_known_regex HTTP_HEADER_VALUE. + */ 'domains': (string)[]; + /** + * The list of routes that will be matched, in order, for incoming requests. + * The first route that matches will be used. + */ 'routes': (_envoy_api_v2_route_Route__Output)[]; + /** + * Specifies the type of TLS enforcement the virtual host expects. If this option is not + * specified, there is no TLS requirement for the virtual host. + */ 'require_tls': (keyof typeof _envoy_api_v2_route_VirtualHost_TlsRequirementType); + /** + * A list of virtual clusters defined for this virtual host. Virtual clusters + * are used for additional statistics gathering. + */ 'virtual_clusters': (_envoy_api_v2_route_VirtualCluster__Output)[]; + /** + * Specifies a set of rate limit configurations that will be applied to the + * virtual host. + */ 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; + /** + * Specifies a list of HTTP headers that should be added to each request + * handled by this virtual host. Headers specified at this level are applied + * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * details on header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Indicates that the virtual host has a CORS policy. + */ 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + /** + * Specifies a list of HTTP headers that should be added to each response + * handled by this virtual host. Headers specified at this level are applied + * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * details on header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a list of HTTP headers that should be removed from each response + * handled by this virtual host. + */ 'response_headers_to_remove': (string)[]; + /** + * The per_filter_config field can be used to provide virtual host-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'per_filter_config': (_google_protobuf_Struct__Output); + /** + * Specifies a list of HTTP headers that should be removed from each request + * handled by this virtual host. + */ 'request_headers_to_remove': (string)[]; + /** + * Decides whether the :ref:`x-envoy-attempt-count + * ` header should be included + * in the upstream request. Setting this option will cause it to override any existing header + * value, so in the case of two Envoys on the request path with this option enabled, the upstream + * will see the attempt count as perceived by the second Envoy. Defaults to false. + * This header is unaffected by the + * :ref:`suppress_envoy_headers + * ` flag. + * + * [#next-major-version: rename to include_attempt_count_in_request.] + */ 'include_request_attempt_count': (boolean); + /** + * The per_filter_config field can be used to provide virtual host-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'typed_per_filter_config': (_google_protobuf_Any__Output); + /** + * Indicates the retry policy for all routes in this virtual host. Note that setting a + * route level entry will take precedence over this config and it'll be treated + * independently (e.g.: values are not inherited). + */ 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); + /** + * Indicates the hedge policy for all routes in this virtual host. Note that setting a + * route level entry will take precedence over this config and it'll be treated + * independently (e.g.: values are not inherited). + */ 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + /** + * The maximum bytes which will be buffered for retries and shadowing. + * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum + * value of this and the listener per_connection_buffer_limit_bytes. + */ 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + /** + * Decides whether the :ref:`x-envoy-attempt-count + * ` header should be included + * in the downstream response. Setting this option will cause the router to override any existing header + * value, so in the case of two Envoys on the request path with this option enabled, the downstream + * will see the attempt count as perceived by the Envoy closest upstream from itself. Defaults to false. + * This header is unaffected by the + * :ref:`suppress_envoy_headers + * ` flag. + */ 'include_attempt_count_in_response': (boolean); + /** + * [#not-implemented-hide:] + * Specifies the configuration for retry policy extension. Note that setting a route level entry + * will take precedence over this config and it'll be treated independently (e.g.: values are not + * inherited). :ref:`Retry policy ` should not be + * set if this field is used. + */ 'retry_policy_typed_config': (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts index 234ec5da7..fb0c260b3 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts @@ -6,38 +6,208 @@ import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueO import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +/** + * [#next-free-field: 11] + */ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { + /** + * Name of the upstream cluster. The cluster must exist in the + * :ref:`cluster manager configuration `. + */ 'name'?: (string); + /** + * An integer between 0 and :ref:`total_weight + * `. When a request matches the route, + * the choice of an upstream cluster is determined by its weight. The sum of weights across all + * entries in the clusters array must add up to the total_weight, which defaults to 100. + */ 'weight'?: (_google_protobuf_UInt32Value); + /** + * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in + * the upstream cluster with metadata matching what is set in this field will be considered for + * load balancing. Note that this will be merged with what's provided in + * :ref:`RouteAction.metadata_match `, with + * values here taking precedence. The filter name should be specified as *envoy.lb*. + */ 'metadata_match'?: (_envoy_api_v2_core_Metadata); + /** + * Specifies a list of headers to be added to requests when this cluster is selected + * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * Headers specified at this level are applied before headers from the enclosing + * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a list of HTTP headers that should be removed from each request when + * this cluster is selected through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + */ 'request_headers_to_remove'?: (string)[]; + /** + * Specifies a list of headers to be added to responses when this cluster is selected + * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * Headers specified at this level are applied before headers from the enclosing + * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + /** + * Specifies a list of headers to be removed from responses when this cluster is selected + * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + */ 'response_headers_to_remove'?: (string)[]; + /** + * The per_filter_config field can be used to provide weighted cluster-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'per_filter_config'?: (_google_protobuf_Struct); + /** + * The per_filter_config field can be used to provide weighted cluster-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'typed_per_filter_config'?: (_google_protobuf_Any); } +/** + * [#next-free-field: 11] + */ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { + /** + * Name of the upstream cluster. The cluster must exist in the + * :ref:`cluster manager configuration `. + */ 'name': (string); + /** + * An integer between 0 and :ref:`total_weight + * `. When a request matches the route, + * the choice of an upstream cluster is determined by its weight. The sum of weights across all + * entries in the clusters array must add up to the total_weight, which defaults to 100. + */ 'weight': (_google_protobuf_UInt32Value__Output); + /** + * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in + * the upstream cluster with metadata matching what is set in this field will be considered for + * load balancing. Note that this will be merged with what's provided in + * :ref:`RouteAction.metadata_match `, with + * values here taking precedence. The filter name should be specified as *envoy.lb*. + */ 'metadata_match': (_envoy_api_v2_core_Metadata__Output); + /** + * Specifies a list of headers to be added to requests when this cluster is selected + * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * Headers specified at this level are applied before headers from the enclosing + * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a list of HTTP headers that should be removed from each request when + * this cluster is selected through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + */ 'request_headers_to_remove': (string)[]; + /** + * Specifies a list of headers to be added to responses when this cluster is selected + * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * Headers specified at this level are applied before headers from the enclosing + * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and + * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * header value syntax, see the documentation on :ref:`custom request headers + * `. + */ 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + /** + * Specifies a list of headers to be removed from responses when this cluster is selected + * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + */ 'response_headers_to_remove': (string)[]; + /** + * The per_filter_config field can be used to provide weighted cluster-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'per_filter_config': (_google_protobuf_Struct__Output); + /** + * The per_filter_config field can be used to provide weighted cluster-specific + * configurations for filters. The key should match the filter name, such as + * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter + * specific; see the :ref:`HTTP filter documentation ` + * for if and how it is utilized. + */ 'typed_per_filter_config': (_google_protobuf_Any__Output); } +/** + * Compared to the :ref:`cluster ` field that specifies a + * single upstream cluster as the target of a request, the :ref:`weighted_clusters + * ` option allows for specification of + * multiple upstream clusters along with weights that indicate the percentage of + * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the + * weights. + */ export interface WeightedCluster { + /** + * Specifies one or more upstream clusters associated with the route. + */ 'clusters'?: (_envoy_api_v2_route_WeightedCluster_ClusterWeight)[]; + /** + * Specifies the runtime key prefix that should be used to construct the + * runtime keys associated with each cluster. When the *runtime_key_prefix* is + * specified, the router will look for weights associated with each upstream + * cluster under the key *runtime_key_prefix* + "." + *cluster[i].name* where + * *cluster[i]* denotes an entry in the clusters array field. If the runtime + * key for the cluster does not exist, the value specified in the + * configuration file will be used as the default weight. See the :ref:`runtime documentation + * ` for how key names map to the underlying implementation. + */ 'runtime_key_prefix'?: (string); + /** + * Specifies the total weight across all clusters. The sum of all cluster weights must equal this + * value, which must be greater than 0. Defaults to 100. + */ 'total_weight'?: (_google_protobuf_UInt32Value); } +/** + * Compared to the :ref:`cluster ` field that specifies a + * single upstream cluster as the target of a request, the :ref:`weighted_clusters + * ` option allows for specification of + * multiple upstream clusters along with weights that indicate the percentage of + * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the + * weights. + */ export interface WeightedCluster__Output { + /** + * Specifies one or more upstream clusters associated with the route. + */ 'clusters': (_envoy_api_v2_route_WeightedCluster_ClusterWeight__Output)[]; + /** + * Specifies the runtime key prefix that should be used to construct the + * runtime keys associated with each cluster. When the *runtime_key_prefix* is + * specified, the router will look for weights associated with each upstream + * cluster under the key *runtime_key_prefix* + "." + *cluster[i].name* where + * *cluster[i]* denotes an entry in the clusters array field. If the runtime + * key for the cluster does not exist, the value specified in the + * configuration file will be used as the default weight. See the :ref:`runtime documentation + * ` for how key names map to the underlying implementation. + */ 'runtime_key_prefix': (string); + /** + * Specifies the total weight across all clusters. The sum of all cluster weights must equal this + * value, which must be greater than 0. Defaults to 100. + */ 'total_weight': (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts index d89342b10..7a1b23f0d 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts @@ -5,17 +5,61 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_S import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; export interface AccessLog { + /** + * The name of the access log implementation to instantiate. The name must + * match a statically registered access log. Current built-in loggers include: + * + * #. "envoy.access_loggers.file" + * #. "envoy.access_loggers.http_grpc" + * #. "envoy.access_loggers.tcp_grpc" + */ 'name'?: (string); + /** + * Filter which is used to determine if the access log needs to be written. + */ 'filter'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Custom configuration that depends on the access log being instantiated. Built-in + * configurations include: + * + * #. "envoy.access_loggers.file": :ref:`FileAccessLog + * ` + * #. "envoy.access_loggers.http_grpc": :ref:`HttpGrpcAccessLogConfig + * ` + * #. "envoy.access_loggers.tcp_grpc": :ref:`TcpGrpcAccessLogConfig + * ` + */ 'config_type'?: "config"|"typed_config"; } export interface AccessLog__Output { + /** + * The name of the access log implementation to instantiate. The name must + * match a statically registered access log. Current built-in loggers include: + * + * #. "envoy.access_loggers.file" + * #. "envoy.access_loggers.http_grpc" + * #. "envoy.access_loggers.tcp_grpc" + */ 'name': (string); + /** + * Filter which is used to determine if the access log needs to be written. + */ 'filter': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Custom configuration that depends on the access log being instantiated. Built-in + * configurations include: + * + * #. "envoy.access_loggers.file": :ref:`FileAccessLog + * ` + * #. "envoy.access_loggers.http_grpc": :ref:`HttpGrpcAccessLogConfig + * ` + * #. "envoy.access_loggers.tcp_grpc": :ref:`TcpGrpcAccessLogConfig + * ` + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts index ce399dc52..19eb4ed28 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts @@ -12,32 +12,104 @@ import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFil import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/GrpcStatusFilter'; import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ExtensionFilter'; +/** + * [#next-free-field: 12] + */ export interface AccessLogFilter { + /** + * Status code filter. + */ 'status_code_filter'?: (_envoy_config_filter_accesslog_v2_StatusCodeFilter); + /** + * Duration filter. + */ 'duration_filter'?: (_envoy_config_filter_accesslog_v2_DurationFilter); + /** + * Not health check filter. + */ 'not_health_check_filter'?: (_envoy_config_filter_accesslog_v2_NotHealthCheckFilter); + /** + * Traceable filter. + */ 'traceable_filter'?: (_envoy_config_filter_accesslog_v2_TraceableFilter); + /** + * Runtime filter. + */ 'runtime_filter'?: (_envoy_config_filter_accesslog_v2_RuntimeFilter); + /** + * And filter. + */ 'and_filter'?: (_envoy_config_filter_accesslog_v2_AndFilter); + /** + * Or filter. + */ 'or_filter'?: (_envoy_config_filter_accesslog_v2_OrFilter); + /** + * Header filter. + */ 'header_filter'?: (_envoy_config_filter_accesslog_v2_HeaderFilter); + /** + * Response flag filter. + */ 'response_flag_filter'?: (_envoy_config_filter_accesslog_v2_ResponseFlagFilter); + /** + * gRPC status filter. + */ 'grpc_status_filter'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter); + /** + * Extension filter. + */ 'extension_filter'?: (_envoy_config_filter_accesslog_v2_ExtensionFilter); 'filter_specifier'?: "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"; } +/** + * [#next-free-field: 12] + */ export interface AccessLogFilter__Output { + /** + * Status code filter. + */ 'status_code_filter'?: (_envoy_config_filter_accesslog_v2_StatusCodeFilter__Output); + /** + * Duration filter. + */ 'duration_filter'?: (_envoy_config_filter_accesslog_v2_DurationFilter__Output); + /** + * Not health check filter. + */ 'not_health_check_filter'?: (_envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output); + /** + * Traceable filter. + */ 'traceable_filter'?: (_envoy_config_filter_accesslog_v2_TraceableFilter__Output); + /** + * Runtime filter. + */ 'runtime_filter'?: (_envoy_config_filter_accesslog_v2_RuntimeFilter__Output); + /** + * And filter. + */ 'and_filter'?: (_envoy_config_filter_accesslog_v2_AndFilter__Output); + /** + * Or filter. + */ 'or_filter'?: (_envoy_config_filter_accesslog_v2_OrFilter__Output); + /** + * Header filter. + */ 'header_filter'?: (_envoy_config_filter_accesslog_v2_HeaderFilter__Output); + /** + * Response flag filter. + */ 'response_flag_filter'?: (_envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output); + /** + * gRPC status filter. + */ 'grpc_status_filter'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output); + /** + * Extension filter. + */ 'extension_filter'?: (_envoy_config_filter_accesslog_v2_ExtensionFilter__Output); 'filter_specifier': "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"; } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts index 490962c54..a39ba8f21 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts @@ -2,10 +2,20 @@ import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +/** + * Performs a logical “and†operation on the result of each filter in filters. + * Filters are evaluated sequentially and if one of them returns false, the + * filter returns false immediately. + */ export interface AndFilter { 'filters'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter)[]; } +/** + * Performs a logical “and†operation on the result of each filter in filters. + * Filters are evaluated sequentially and if one of them returns false, the + * filter returns false immediately. + */ export interface AndFilter__Output { 'filters': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts index 518e5399c..dc4e88872 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts @@ -5,17 +5,44 @@ import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Outpu // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto export enum _envoy_config_filter_accesslog_v2_ComparisonFilter_Op { + /** + * = + */ EQ = 0, + /** + * >= + */ GE = 1, + /** + * <= + */ LE = 2, } +/** + * Filter on an integer comparison. + */ export interface ComparisonFilter { + /** + * Comparison operator. + */ 'op'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter_Op | keyof typeof _envoy_config_filter_accesslog_v2_ComparisonFilter_Op); + /** + * Value to compare against. + */ 'value'?: (_envoy_api_v2_core_RuntimeUInt32); } +/** + * Filter on an integer comparison. + */ export interface ComparisonFilter__Output { + /** + * Comparison operator. + */ 'op': (keyof typeof _envoy_config_filter_accesslog_v2_ComparisonFilter_Op); + /** + * Value to compare against. + */ 'value': (_envoy_api_v2_core_RuntimeUInt32__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts index 495154e27..9a2162efb 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts @@ -2,10 +2,22 @@ import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; +/** + * Filters on total request duration in milliseconds. + */ export interface DurationFilter { + /** + * Comparison. + */ 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter); } +/** + * Filters on total request duration in milliseconds. + */ export interface DurationFilter__Output { + /** + * Comparison. + */ 'comparison': (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts index 047086c8b..b0a061b82 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts @@ -3,16 +3,36 @@ import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; +/** + * Extension filter is statically registered at runtime. + */ export interface ExtensionFilter { + /** + * The name of the filter implementation to instantiate. The name must + * match a statically registered filter. + */ 'name'?: (string); 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); + /** + * Custom configuration that depends on the filter being instantiated. + */ 'config_type'?: "config"|"typed_config"; } +/** + * Extension filter is statically registered at runtime. + */ export interface ExtensionFilter__Output { + /** + * The name of the filter implementation to instantiate. The name must + * match a statically registered filter. + */ 'name': (string); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Custom configuration that depends on the filter being instantiated. + */ 'config_type': "config"|"typed_config"; } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts index 086c08e3a..8e8b0981e 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts @@ -23,12 +23,34 @@ export enum _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status { UNAUTHENTICATED = 16, } +/** + * Filters gRPC requests based on their response status. If a gRPC status is not provided, the + * filter will infer the status from the HTTP status code. + */ export interface GrpcStatusFilter { + /** + * Logs only responses that have any one of the gRPC statuses in this field. + */ 'statuses'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status | keyof typeof _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status)[]; + /** + * If included and set to true, the filter will instead block all responses with a gRPC status or + * inferred gRPC status enumerated in statuses, and allow all other responses. + */ 'exclude'?: (boolean); } +/** + * Filters gRPC requests based on their response status. If a gRPC status is not provided, the + * filter will infer the status from the HTTP status code. + */ export interface GrpcStatusFilter__Output { + /** + * Logs only responses that have any one of the gRPC statuses in this field. + */ 'statuses': (keyof typeof _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status)[]; + /** + * If included and set to true, the filter will instead block all responses with a gRPC status or + * inferred gRPC status enumerated in statuses, and allow all other responses. + */ 'exclude': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts index 7fe39f9ee..56c4df1ea 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts @@ -2,10 +2,24 @@ import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../../envoy/api/v2/route/HeaderMatcher'; +/** + * Filters requests based on the presence or value of a request header. + */ export interface HeaderFilter { + /** + * Only requests with a header which matches the specified HeaderMatcher will pass the filter + * check. + */ 'header'?: (_envoy_api_v2_route_HeaderMatcher); } +/** + * Filters requests based on the presence or value of a request header. + */ export interface HeaderFilter__Output { + /** + * Only requests with a header which matches the specified HeaderMatcher will pass the filter + * check. + */ 'header': (_envoy_api_v2_route_HeaderMatcher__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts index 0895567da..3de68f081 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts @@ -1,8 +1,16 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +/** + * Filters for requests that are not health check requests. A health check + * request is marked by the health check filter. + */ export interface NotHealthCheckFilter { } +/** + * Filters for requests that are not health check requests. A health check + * request is marked by the health check filter. + */ export interface NotHealthCheckFilter__Output { } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts index f4b2a19d2..def55d54a 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts @@ -2,10 +2,20 @@ import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +/** + * Performs a logical “or†operation on the result of each individual filter. + * Filters are evaluated sequentially and if one of them returns true, the + * filter returns true immediately. + */ export interface OrFilter { 'filters'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter)[]; } +/** + * Performs a logical “or†operation on the result of each individual filter. + * Filters are evaluated sequentially and if one of them returns true, the + * filter returns true immediately. + */ export interface OrFilter__Output { 'filters': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts index bb744a0c6..280fbb26a 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts @@ -1,10 +1,30 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +/** + * Filters requests that received responses with an Envoy response flag set. + * A list of the response flags can be found + * in the access log formatter :ref:`documentation`. + */ export interface ResponseFlagFilter { + /** + * Only responses with the any of the flags listed in this field will be logged. + * This field is optional. If it is not specified, then any response flag will pass + * the filter check. + */ 'flags'?: (string)[]; } +/** + * Filters requests that received responses with an Envoy response flag set. + * A list of the response flags can be found + * in the access log formatter :ref:`documentation`. + */ export interface ResponseFlagFilter__Output { + /** + * Only responses with the any of the flags listed in this field will be logged. + * This field is optional. If it is not specified, then any response flag will pass + * the filter check. + */ 'flags': (string)[]; } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts index 83e98db33..f11e4bc2b 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts @@ -2,14 +2,62 @@ import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../../envoy/type/FractionalPercent'; +/** + * Filters for random sampling of requests. + */ export interface RuntimeFilter { + /** + * Runtime key to get an optional overridden numerator for use in the *percent_sampled* field. + * If found in runtime, this value will replace the default numerator. + */ 'runtime_key'?: (string); + /** + * The default sampling percentage. If not specified, defaults to 0% with denominator of 100. + */ 'percent_sampled'?: (_envoy_type_FractionalPercent); + /** + * By default, sampling pivots on the header + * :ref:`x-request-id` being present. If + * :ref:`x-request-id` is present, the filter will + * consistently sample across multiple hosts based on the runtime key value and the value + * extracted from :ref:`x-request-id`. If it is + * missing, or *use_independent_randomness* is set to true, the filter will randomly sample based + * on the runtime key value alone. *use_independent_randomness* can be used for logging kill + * switches within complex nested :ref:`AndFilter + * ` and :ref:`OrFilter + * ` blocks that are easier to reason about + * from a probability perspective (i.e., setting to true will cause the filter to behave like + * an independent random variable when composed within logical operator filters). + */ 'use_independent_randomness'?: (boolean); } +/** + * Filters for random sampling of requests. + */ export interface RuntimeFilter__Output { + /** + * Runtime key to get an optional overridden numerator for use in the *percent_sampled* field. + * If found in runtime, this value will replace the default numerator. + */ 'runtime_key': (string); + /** + * The default sampling percentage. If not specified, defaults to 0% with denominator of 100. + */ 'percent_sampled': (_envoy_type_FractionalPercent__Output); + /** + * By default, sampling pivots on the header + * :ref:`x-request-id` being present. If + * :ref:`x-request-id` is present, the filter will + * consistently sample across multiple hosts based on the runtime key value and the value + * extracted from :ref:`x-request-id`. If it is + * missing, or *use_independent_randomness* is set to true, the filter will randomly sample based + * on the runtime key value alone. *use_independent_randomness* can be used for logging kill + * switches within complex nested :ref:`AndFilter + * ` and :ref:`OrFilter + * ` blocks that are easier to reason about + * from a probability perspective (i.e., setting to true will cause the filter to behave like + * an independent random variable when composed within logical operator filters). + */ 'use_independent_randomness': (boolean); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts index 6f8c46d22..950bd696a 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts @@ -2,10 +2,22 @@ import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; +/** + * Filters on HTTP response/status code. + */ export interface StatusCodeFilter { + /** + * Comparison. + */ 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter); } +/** + * Filters on HTTP response/status code. + */ export interface StatusCodeFilter__Output { + /** + * Comparison. + */ 'comparison': (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts index a428d1a8a..8de24656a 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts @@ -1,8 +1,16 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +/** + * Filters for requests that are traceable. See the tracing overview for more + * information on how a request becomes traceable. + */ export interface TraceableFilter { } +/** + * Filters for requests that are traceable. See the tracing overview for more + * information on how a request becomes traceable. + */ export interface TraceableFilter__Output { } diff --git a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts index 8d3b82f04..095bc2c53 100644 --- a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts +++ b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts @@ -2,10 +2,38 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +/** + * Describes a type of API listener, which is used in non-proxy clients. The type of API + * exposed to the non-proxy application depends on the type of API listener. + */ export interface ApiListener { + /** + * The type in this field determines the type of API listener. At present, the following + * types are supported: + * envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager (HTTP) + * [#next-major-version: In the v3 API, replace this Any field with a oneof containing the + * specific config message for each type of API listener. We could not do this in v2 because + * it would have caused circular dependencies for go protos: lds.proto depends on this file, + * and http_connection_manager.proto depends on rds.proto, which is in the same directory as + * lds.proto, so lds.proto cannot depend on this file.] + */ 'api_listener'?: (_google_protobuf_Any); } +/** + * Describes a type of API listener, which is used in non-proxy clients. The type of API + * exposed to the non-proxy application depends on the type of API listener. + */ export interface ApiListener__Output { + /** + * The type in this field determines the type of API listener. At present, the following + * types are supported: + * envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager (HTTP) + * [#next-major-version: In the v3 API, replace this Any field with a oneof containing the + * specific config message for each type of API listener. We could not do this in v2 because + * it would have caused circular dependencies for go protos: lds.proto depends on this file, + * and http_connection_manager.proto depends on rds.proto, which is in the same directory as + * lds.proto, so lds.proto cannot depend on this file.] + */ 'api_listener': (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts index 985cd2200..eeb6aa6af 100644 --- a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts +++ b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts @@ -1,8 +1,16 @@ // Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto +/** + * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing + * services: https://github.com/google/protobuf/issues/4221 + */ export interface AdsDummy { } +/** + * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing + * services: https://github.com/google/protobuf/issues/4221 + */ export interface AdsDummy__Output { } diff --git a/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts b/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts index b32b1b1a9..a0bf07351 100644 --- a/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts +++ b/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts @@ -3,5 +3,10 @@ export enum CodecClientType { HTTP1 = 0, HTTP2 = 1, + /** + * [#not-implemented-hide:] QUIC implementation is not production ready yet. Use this enum with + * caution to prevent accidental execution of QUIC code. I.e. `!= HTTP2` is no longer sufficient + * to distinguish HTTP1 and HTTP2 traffic. + */ HTTP3 = 2, } diff --git a/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts b/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts index 9d9bb8958..5ebc3a579 100644 --- a/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts +++ b/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts @@ -1,12 +1,32 @@ // Original file: deps/envoy-api/envoy/type/range.proto +/** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export interface DoubleRange { + /** + * start of the range (inclusive) + */ 'start'?: (number | string); + /** + * end of the range (exclusive) + */ 'end'?: (number | string); } +/** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export interface DoubleRange__Output { + /** + * start of the range (inclusive) + */ 'start': (number | string); + /** + * end of the range (exclusive) + */ 'end': (number | string); } diff --git a/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts b/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts index bc7d3d52c..e450f0bfa 100644 --- a/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts +++ b/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts @@ -3,18 +3,66 @@ // Original file: deps/envoy-api/envoy/type/percent.proto +/** + * Fraction percentages support several fixed denominator values. + */ export enum _envoy_type_FractionalPercent_DenominatorType { + /** + * 100. + * + * **Example**: 1/100 = 1%. + */ HUNDRED = 0, + /** + * 10,000. + * + * **Example**: 1/10000 = 0.01%. + */ TEN_THOUSAND = 1, + /** + * 1,000,000. + * + * **Example**: 1/1000000 = 0.0001%. + */ MILLION = 2, } +/** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export interface FractionalPercent { + /** + * Specifies the numerator. Defaults to 0. + */ 'numerator'?: (number); + /** + * Specifies the denominator. If the denominator specified is less than the numerator, the final + * fractional percentage is capped at 1 (100%). + */ 'denominator'?: (_envoy_type_FractionalPercent_DenominatorType | keyof typeof _envoy_type_FractionalPercent_DenominatorType); } +/** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export interface FractionalPercent__Output { + /** + * Specifies the numerator. Defaults to 0. + */ 'numerator': (number); + /** + * Specifies the denominator. If the denominator specified is less than the numerator, the final + * fractional percentage is capped at 1 (100%). + */ 'denominator': (keyof typeof _envoy_type_FractionalPercent_DenominatorType); } diff --git a/packages/grpc-js/src/generated/envoy/type/Int32Range.ts b/packages/grpc-js/src/generated/envoy/type/Int32Range.ts index 3adec7571..f5475c2db 100644 --- a/packages/grpc-js/src/generated/envoy/type/Int32Range.ts +++ b/packages/grpc-js/src/generated/envoy/type/Int32Range.ts @@ -1,12 +1,32 @@ // Original file: deps/envoy-api/envoy/type/range.proto +/** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export interface Int32Range { + /** + * start of the range (inclusive) + */ 'start'?: (number); + /** + * end of the range (exclusive) + */ 'end'?: (number); } +/** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export interface Int32Range__Output { + /** + * start of the range (inclusive) + */ 'start': (number); + /** + * end of the range (exclusive) + */ 'end': (number); } diff --git a/packages/grpc-js/src/generated/envoy/type/Int64Range.ts b/packages/grpc-js/src/generated/envoy/type/Int64Range.ts index adc30bbd1..16c8235ca 100644 --- a/packages/grpc-js/src/generated/envoy/type/Int64Range.ts +++ b/packages/grpc-js/src/generated/envoy/type/Int64Range.ts @@ -2,12 +2,32 @@ import { Long } from '@grpc/proto-loader'; +/** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export interface Int64Range { + /** + * start of the range (inclusive) + */ 'start'?: (number | string | Long); + /** + * end of the range (exclusive) + */ 'end'?: (number | string | Long); } +/** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export interface Int64Range__Output { + /** + * start of the range (inclusive) + */ 'start': (string); + /** + * end of the range (exclusive) + */ 'end': (string); } diff --git a/packages/grpc-js/src/generated/envoy/type/Percent.ts b/packages/grpc-js/src/generated/envoy/type/Percent.ts index 656408905..f63553acd 100644 --- a/packages/grpc-js/src/generated/envoy/type/Percent.ts +++ b/packages/grpc-js/src/generated/envoy/type/Percent.ts @@ -1,10 +1,16 @@ // Original file: deps/envoy-api/envoy/type/percent.proto +/** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export interface Percent { 'value'?: (number | string); } +/** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export interface Percent__Output { 'value': (number | string); } diff --git a/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts b/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts index aa1f7bc43..f99431703 100644 --- a/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts +++ b/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts @@ -1,12 +1,22 @@ // Original file: deps/envoy-api/envoy/type/semantic_version.proto +/** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export interface SemanticVersion { 'major_number'?: (number); 'minor_number'?: (number); 'patch'?: (number); } +/** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export interface SemanticVersion__Output { 'major_number': (number); 'minor_number': (number); diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts b/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts index aab545afe..e4ac83f0d 100644 --- a/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts @@ -2,10 +2,16 @@ import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../envoy/type/matcher/StringMatcher'; +/** + * Specifies a list of ways to match a string. + */ export interface ListStringMatcher { 'patterns'?: (_envoy_type_matcher_StringMatcher)[]; } +/** + * Specifies a list of ways to match a string. + */ export interface ListStringMatcher__Output { 'patterns': (_envoy_type_matcher_StringMatcher__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts index 6b4fa903c..55c8c8644 100644 --- a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts +++ b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts @@ -2,12 +2,64 @@ import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; +/** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export interface RegexMatchAndSubstitute { + /** + * The regular expression used to find portions of a string (hereafter called + * the "subject string") that should be replaced. When a new string is + * produced during the substitution operation, the new string is initially + * the same as the subject string, but then all matches in the subject string + * are replaced by the substitution string. If replacing all matches isn't + * desired, regular expression anchors can be used to ensure a single match, + * so as to replace just one occurrence of a pattern. Capture groups can be + * used in the pattern to extract portions of the subject string, and then + * referenced in the substitution string. + */ 'pattern'?: (_envoy_type_matcher_RegexMatcher); + /** + * The string that should be substituted into matching portions of the + * subject string during a substitution operation to produce a new string. + * Capture groups in the pattern can be referenced in the substitution + * string. Note, however, that the syntax for referring to capture groups is + * defined by the chosen regular expression engine. Google's `RE2 + * `_ regular expression engine uses a + * backslash followed by the capture group number to denote a numbered + * capture group. E.g., ``\1`` refers to capture group 1, and ``\2`` refers + * to capture group 2. + */ 'substitution'?: (string); } +/** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export interface RegexMatchAndSubstitute__Output { + /** + * The regular expression used to find portions of a string (hereafter called + * the "subject string") that should be replaced. When a new string is + * produced during the substitution operation, the new string is initially + * the same as the subject string, but then all matches in the subject string + * are replaced by the substitution string. If replacing all matches isn't + * desired, regular expression anchors can be used to ensure a single match, + * so as to replace just one occurrence of a pattern. Capture groups can be + * used in the pattern to extract portions of the subject string, and then + * referenced in the substitution string. + */ 'pattern': (_envoy_type_matcher_RegexMatcher__Output); + /** + * The string that should be substituted into matching portions of the + * subject string during a substitution operation to produce a new string. + * Capture groups in the pattern can be referenced in the substitution + * string. Note, however, that the syntax for referring to capture groups is + * defined by the chosen regular expression engine. Google's `RE2 + * `_ regular expression engine uses a + * backslash followed by the capture group number to denote a numbered + * capture group. E.g., ``\1`` refers to capture group 1, and ``\2`` refers + * to capture group 2. + */ 'substitution': (string); } diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts index d4904964f..674fef3f5 100644 --- a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts @@ -2,22 +2,68 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +/** + * Google's `RE2 `_ regex engine. The regex string must adhere to + * the documented `syntax `_. The engine is designed + * to complete execution in linear time as well as limit the amount of memory used. + */ export interface _envoy_type_matcher_RegexMatcher_GoogleRE2 { + /** + * This field controls the RE2 "program size" which is a rough estimate of how complex a + * compiled regex is to evaluate. A regex that has a program size greater than the configured + * value will fail to compile. In this case, the configured max program size can be increased + * or the regex can be simplified. If not specified, the default is 100. + * + * This field is deprecated; regexp validation should be performed on the management server + * instead of being done by each individual client. + */ 'max_program_size'?: (_google_protobuf_UInt32Value); } +/** + * Google's `RE2 `_ regex engine. The regex string must adhere to + * the documented `syntax `_. The engine is designed + * to complete execution in linear time as well as limit the amount of memory used. + */ export interface _envoy_type_matcher_RegexMatcher_GoogleRE2__Output { + /** + * This field controls the RE2 "program size" which is a rough estimate of how complex a + * compiled regex is to evaluate. A regex that has a program size greater than the configured + * value will fail to compile. In this case, the configured max program size can be increased + * or the regex can be simplified. If not specified, the default is 100. + * + * This field is deprecated; regexp validation should be performed on the management server + * instead of being done by each individual client. + */ 'max_program_size': (_google_protobuf_UInt32Value__Output); } +/** + * A regex matcher designed for safety when used with untrusted input. + */ export interface RegexMatcher { + /** + * Google's RE2 regex engine. + */ 'google_re2'?: (_envoy_type_matcher_RegexMatcher_GoogleRE2); + /** + * The regex match string. The string must be supported by the configured engine. + */ 'regex'?: (string); 'engine_type'?: "google_re2"; } +/** + * A regex matcher designed for safety when used with untrusted input. + */ export interface RegexMatcher__Output { + /** + * Google's RE2 regex engine. + */ 'google_re2'?: (_envoy_type_matcher_RegexMatcher_GoogleRE2__Output); + /** + * The regex match string. The string must be supported by the configured engine. + */ 'regex': (string); 'engine_type': "google_re2"; } diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts b/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts index 6a63a54dc..de8ce5dc2 100644 --- a/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts @@ -2,22 +2,122 @@ import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; +/** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export interface StringMatcher { + /** + * The input string must match exactly the string specified here. + * + * Examples: + * + * * *abc* only matches the value *abc*. + */ 'exact'?: (string); + /** + * The input string must have the prefix specified here. + * Note: empty prefix is not allowed, please use regex instead. + * + * Examples: + * + * * *abc* matches the value *abc.xyz* + */ 'prefix'?: (string); + /** + * The input string must have the suffix specified here. + * Note: empty prefix is not allowed, please use regex instead. + * + * Examples: + * + * * *abc* matches the value *xyz.abc* + */ 'suffix'?: (string); + /** + * The input string must match the regular expression specified here. + * The regex grammar is defined `here + * `_. + * + * Examples: + * + * * The regex ``\d{3}`` matches the value *123* + * * The regex ``\d{3}`` does not match the value *1234* + * * The regex ``\d{3}`` does not match the value *123.456* + * + * .. attention:: + * This field has been deprecated in favor of `safe_regex` as it is not safe for use with + * untrusted input in all cases. + */ 'regex'?: (string); + /** + * The input string must match the regular expression specified here. + */ 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); + /** + * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no + * effect for the safe_regex match. + * For example, the matcher *data* will match both input string *Data* and *data* if set to true. + */ 'ignore_case'?: (boolean); 'match_pattern'?: "exact"|"prefix"|"suffix"|"regex"|"safe_regex"; } +/** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export interface StringMatcher__Output { + /** + * The input string must match exactly the string specified here. + * + * Examples: + * + * * *abc* only matches the value *abc*. + */ 'exact'?: (string); + /** + * The input string must have the prefix specified here. + * Note: empty prefix is not allowed, please use regex instead. + * + * Examples: + * + * * *abc* matches the value *abc.xyz* + */ 'prefix'?: (string); + /** + * The input string must have the suffix specified here. + * Note: empty prefix is not allowed, please use regex instead. + * + * Examples: + * + * * *abc* matches the value *xyz.abc* + */ 'suffix'?: (string); + /** + * The input string must match the regular expression specified here. + * The regex grammar is defined `here + * `_. + * + * Examples: + * + * * The regex ``\d{3}`` matches the value *123* + * * The regex ``\d{3}`` does not match the value *1234* + * * The regex ``\d{3}`` does not match the value *123.456* + * + * .. attention:: + * This field has been deprecated in favor of `safe_regex` as it is not safe for use with + * untrusted input in all cases. + */ 'regex'?: (string); + /** + * The input string must match the regular expression specified here. + */ 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); + /** + * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no + * effect for the safe_regex match. + * For example, the matcher *data* will match both input string *Data* and *data* if set to true. + */ 'ignore_case': (boolean); 'match_pattern': "exact"|"prefix"|"suffix"|"regex"|"safe_regex"; } diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts index cb35fcef9..94d661879 100644 --- a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts +++ b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts @@ -1,22 +1,108 @@ // Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto +/** + * Specifies the segment in a path to retrieve value from Metadata. + * Currently it is only supported to specify the key, i.e. field name, as one segment of a path. + */ export interface _envoy_type_metadata_v2_MetadataKey_PathSegment { + /** + * If specified, use the key to retrieve the value in a Struct. + */ 'key'?: (string); 'segment'?: "key"; } +/** + * Specifies the segment in a path to retrieve value from Metadata. + * Currently it is only supported to specify the key, i.e. field name, as one segment of a path. + */ export interface _envoy_type_metadata_v2_MetadataKey_PathSegment__Output { + /** + * If specified, use the key to retrieve the value in a Struct. + */ 'key'?: (string); 'segment': "key"; } +/** + * MetadataKey provides a general interface using `key` and `path` to retrieve value from + * :ref:`Metadata `. + * + * For example, for the following Metadata: + * + * .. code-block:: yaml + * + * filter_metadata: + * envoy.xxx: + * prop: + * foo: bar + * xyz: + * hello: envoy + * + * The following MetadataKey will retrieve a string value "bar" from the Metadata. + * + * .. code-block:: yaml + * + * key: envoy.xxx + * path: + * - key: prop + * - key: foo + */ export interface MetadataKey { + /** + * The key name of Metadata to retrieve the Struct from the metadata. + * Typically, it represents a builtin subsystem or custom extension. + */ 'key'?: (string); + /** + * The path to retrieve the Value from the Struct. It can be a prefix or a full path, + * e.g. ``[prop, xyz]`` for a struct or ``[prop, foo]`` for a string in the example, + * which depends on the particular scenario. + * + * Note: Due to that only the key type segment is supported, the path can not specify a list + * unless the list is the last segment. + */ 'path'?: (_envoy_type_metadata_v2_MetadataKey_PathSegment)[]; } +/** + * MetadataKey provides a general interface using `key` and `path` to retrieve value from + * :ref:`Metadata `. + * + * For example, for the following Metadata: + * + * .. code-block:: yaml + * + * filter_metadata: + * envoy.xxx: + * prop: + * foo: bar + * xyz: + * hello: envoy + * + * The following MetadataKey will retrieve a string value "bar" from the Metadata. + * + * .. code-block:: yaml + * + * key: envoy.xxx + * path: + * - key: prop + * - key: foo + */ export interface MetadataKey__Output { + /** + * The key name of Metadata to retrieve the Struct from the metadata. + * Typically, it represents a builtin subsystem or custom extension. + */ 'key': (string); + /** + * The path to retrieve the Value from the Struct. It can be a prefix or a full path, + * e.g. ``[prop, xyz]`` for a struct or ``[prop, foo]`` for a string in the example, + * which depends on the particular scenario. + * + * Note: Due to that only the key type segment is supported, the path can not specify a list + * unless the list is the last segment. + */ 'path': (_envoy_type_metadata_v2_MetadataKey_PathSegment__Output)[]; } diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts index 0cf870bec..665b95f0d 100644 --- a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts +++ b/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts @@ -1,42 +1,98 @@ // Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto +/** + * Represents metadata from :ref:`the upstream cluster`. + */ export interface _envoy_type_metadata_v2_MetadataKind_Cluster { } +/** + * Represents metadata from :ref:`the upstream cluster`. + */ export interface _envoy_type_metadata_v2_MetadataKind_Cluster__Output { } +/** + * Represents metadata from :ref:`the upstream + * host`. + */ export interface _envoy_type_metadata_v2_MetadataKind_Host { } +/** + * Represents metadata from :ref:`the upstream + * host`. + */ export interface _envoy_type_metadata_v2_MetadataKind_Host__Output { } +/** + * Represents dynamic metadata associated with the request. + */ export interface _envoy_type_metadata_v2_MetadataKind_Request { } +/** + * Represents dynamic metadata associated with the request. + */ export interface _envoy_type_metadata_v2_MetadataKind_Request__Output { } +/** + * Represents metadata from :ref:`the route`. + */ export interface _envoy_type_metadata_v2_MetadataKind_Route { } +/** + * Represents metadata from :ref:`the route`. + */ export interface _envoy_type_metadata_v2_MetadataKind_Route__Output { } +/** + * Describes what kind of metadata. + */ export interface MetadataKind { + /** + * Request kind of metadata. + */ 'request'?: (_envoy_type_metadata_v2_MetadataKind_Request); + /** + * Route kind of metadata. + */ 'route'?: (_envoy_type_metadata_v2_MetadataKind_Route); + /** + * Cluster kind of metadata. + */ 'cluster'?: (_envoy_type_metadata_v2_MetadataKind_Cluster); + /** + * Host kind of metadata. + */ 'host'?: (_envoy_type_metadata_v2_MetadataKind_Host); 'kind'?: "request"|"route"|"cluster"|"host"; } +/** + * Describes what kind of metadata. + */ export interface MetadataKind__Output { + /** + * Request kind of metadata. + */ 'request'?: (_envoy_type_metadata_v2_MetadataKind_Request__Output); + /** + * Route kind of metadata. + */ 'route'?: (_envoy_type_metadata_v2_MetadataKind_Route__Output); + /** + * Cluster kind of metadata. + */ 'cluster'?: (_envoy_type_metadata_v2_MetadataKind_Cluster__Output); + /** + * Host kind of metadata. + */ 'host'?: (_envoy_type_metadata_v2_MetadataKind_Host__Output); 'kind': "request"|"route"|"cluster"|"host"; } diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts index fef01ffa0..0b5874d97 100644 --- a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts +++ b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts @@ -3,60 +3,196 @@ import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from '../../../../envoy/type/metadata/v2/MetadataKind'; import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from '../../../../envoy/type/metadata/v2/MetadataKey'; +/** + * Environment type custom tag with environment name and default value. + */ export interface _envoy_type_tracing_v2_CustomTag_Environment { + /** + * Environment variable name to obtain the value to populate the tag value. + */ 'name'?: (string); + /** + * When the environment variable is not found, + * the tag value will be populated with this default value if specified, + * otherwise no tag will be populated. + */ 'default_value'?: (string); } +/** + * Environment type custom tag with environment name and default value. + */ export interface _envoy_type_tracing_v2_CustomTag_Environment__Output { + /** + * Environment variable name to obtain the value to populate the tag value. + */ 'name': (string); + /** + * When the environment variable is not found, + * the tag value will be populated with this default value if specified, + * otherwise no tag will be populated. + */ 'default_value': (string); } +/** + * Header type custom tag with header name and default value. + */ export interface _envoy_type_tracing_v2_CustomTag_Header { + /** + * Header name to obtain the value to populate the tag value. + */ 'name'?: (string); + /** + * When the header does not exist, + * the tag value will be populated with this default value if specified, + * otherwise no tag will be populated. + */ 'default_value'?: (string); } +/** + * Header type custom tag with header name and default value. + */ export interface _envoy_type_tracing_v2_CustomTag_Header__Output { + /** + * Header name to obtain the value to populate the tag value. + */ 'name': (string); + /** + * When the header does not exist, + * the tag value will be populated with this default value if specified, + * otherwise no tag will be populated. + */ 'default_value': (string); } +/** + * Literal type custom tag with static value for the tag value. + */ export interface _envoy_type_tracing_v2_CustomTag_Literal { + /** + * Static literal value to populate the tag value. + */ 'value'?: (string); } +/** + * Literal type custom tag with static value for the tag value. + */ export interface _envoy_type_tracing_v2_CustomTag_Literal__Output { + /** + * Static literal value to populate the tag value. + */ 'value': (string); } +/** + * Metadata type custom tag using + * :ref:`MetadataKey ` to retrieve the protobuf value + * from :ref:`Metadata `, and populate the tag value with + * `the canonical JSON `_ + * representation of it. + */ export interface _envoy_type_tracing_v2_CustomTag_Metadata { + /** + * Specify what kind of metadata to obtain tag value from. + */ 'kind'?: (_envoy_type_metadata_v2_MetadataKind); + /** + * Metadata key to define the path to retrieve the tag value. + */ 'metadata_key'?: (_envoy_type_metadata_v2_MetadataKey); + /** + * When no valid metadata is found, + * the tag value would be populated with this default value if specified, + * otherwise no tag would be populated. + */ 'default_value'?: (string); } +/** + * Metadata type custom tag using + * :ref:`MetadataKey ` to retrieve the protobuf value + * from :ref:`Metadata `, and populate the tag value with + * `the canonical JSON `_ + * representation of it. + */ export interface _envoy_type_tracing_v2_CustomTag_Metadata__Output { + /** + * Specify what kind of metadata to obtain tag value from. + */ 'kind': (_envoy_type_metadata_v2_MetadataKind__Output); + /** + * Metadata key to define the path to retrieve the tag value. + */ 'metadata_key': (_envoy_type_metadata_v2_MetadataKey__Output); + /** + * When no valid metadata is found, + * the tag value would be populated with this default value if specified, + * otherwise no tag would be populated. + */ 'default_value': (string); } +/** + * Describes custom tags for the active span. + * [#next-free-field: 6] + */ export interface CustomTag { + /** + * Used to populate the tag name. + */ 'tag'?: (string); + /** + * A literal custom tag. + */ 'literal'?: (_envoy_type_tracing_v2_CustomTag_Literal); + /** + * An environment custom tag. + */ 'environment'?: (_envoy_type_tracing_v2_CustomTag_Environment); + /** + * A request header custom tag. + */ 'request_header'?: (_envoy_type_tracing_v2_CustomTag_Header); + /** + * A custom tag to obtain tag value from the metadata. + */ 'metadata'?: (_envoy_type_tracing_v2_CustomTag_Metadata); + /** + * Used to specify what kind of custom tag. + */ 'type'?: "literal"|"environment"|"request_header"|"metadata"; } +/** + * Describes custom tags for the active span. + * [#next-free-field: 6] + */ export interface CustomTag__Output { + /** + * Used to populate the tag name. + */ 'tag': (string); + /** + * A literal custom tag. + */ 'literal'?: (_envoy_type_tracing_v2_CustomTag_Literal__Output); + /** + * An environment custom tag. + */ 'environment'?: (_envoy_type_tracing_v2_CustomTag_Environment__Output); + /** + * A request header custom tag. + */ 'request_header'?: (_envoy_type_tracing_v2_CustomTag_Header__Output); + /** + * A custom tag to obtain tag value from the metadata. + */ 'metadata'?: (_envoy_type_tracing_v2_CustomTag_Metadata__Output); + /** + * Used to specify what kind of custom tag. + */ 'type': "literal"|"environment"|"request_header"|"metadata"; } diff --git a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts index ebdc3e39a..2b6490be6 100644 --- a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts +++ b/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts @@ -1,12 +1,30 @@ // Original file: deps/googleapis/google/api/http.proto +/** + * A custom pattern is used for defining custom HTTP verb. + */ export interface CustomHttpPattern { + /** + * The name of this custom HTTP verb. + */ 'kind'?: (string); + /** + * The path matched by this custom verb. + */ 'path'?: (string); } +/** + * A custom pattern is used for defining custom HTTP verb. + */ export interface CustomHttpPattern__Output { + /** + * The name of this custom HTTP verb. + */ 'kind': (string); + /** + * The path matched by this custom verb. + */ 'path': (string); } diff --git a/packages/grpc-js/src/generated/google/api/Http.ts b/packages/grpc-js/src/generated/google/api/Http.ts index fc3839eb1..038c57e5e 100644 --- a/packages/grpc-js/src/generated/google/api/Http.ts +++ b/packages/grpc-js/src/generated/google/api/Http.ts @@ -2,12 +2,48 @@ import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export interface Http { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + */ 'rules'?: (_google_api_HttpRule)[]; + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + */ 'fully_decode_reserved_expansion'?: (boolean); } +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export interface Http__Output { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + */ 'rules': (_google_api_HttpRule__Output)[]; + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + */ 'fully_decode_reserved_expansion': (boolean); } diff --git a/packages/grpc-js/src/generated/google/api/HttpRule.ts b/packages/grpc-js/src/generated/google/api/HttpRule.ts index 3b268a026..ed9921e5e 100644 --- a/packages/grpc-js/src/generated/google/api/HttpRule.ts +++ b/packages/grpc-js/src/generated/google/api/HttpRule.ts @@ -3,30 +3,678 @@ import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +/** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export interface HttpRule { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + */ 'selector'?: (string); + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + */ 'get'?: (string); + /** + * Maps to HTTP PUT. Used for replacing a resource. + */ 'put'?: (string); + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + */ 'post'?: (string); + /** + * Maps to HTTP DELETE. Used for deleting a resource. + */ 'delete'?: (string); + /** + * Maps to HTTP PATCH. Used for updating a resource. + */ 'patch'?: (string); + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + */ 'body'?: (string); + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + */ 'custom'?: (_google_api_CustomHttpPattern); + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + */ 'additional_bindings'?: (_google_api_HttpRule)[]; + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + */ 'response_body'?: (string); + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + */ 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; } +/** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export interface HttpRule__Output { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + */ 'selector': (string); + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + */ 'get'?: (string); + /** + * Maps to HTTP PUT. Used for replacing a resource. + */ 'put'?: (string); + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + */ 'post'?: (string); + /** + * Maps to HTTP DELETE. Used for deleting a resource. + */ 'delete'?: (string); + /** + * Maps to HTTP PATCH. Used for updating a resource. + */ 'patch'?: (string); + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + */ 'body': (string); + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + */ 'custom'?: (_google_api_CustomHttpPattern__Output); + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + */ 'additional_bindings': (_google_api_HttpRule__Output)[]; + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + */ 'response_body': (string); + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + */ 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; } diff --git a/packages/grpc-js/src/generated/google/rpc/Status.ts b/packages/grpc-js/src/generated/google/rpc/Status.ts index f1d6ecbcf..7da370379 100644 --- a/packages/grpc-js/src/generated/google/rpc/Status.ts +++ b/packages/grpc-js/src/generated/google/rpc/Status.ts @@ -2,14 +2,56 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +/** + * The `Status` type defines a logical error model that is suitable for + * different programming environments, including REST APIs and RPC APIs. It is + * used by [gRPC](https://github.com/grpc). Each `Status` message contains + * three pieces of data: error code, error message, and error details. + * + * You can find out more about this error model and how to work with it in the + * [API Design Guide](https://cloud.google.com/apis/design/errors). + */ export interface Status { + /** + * The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + */ 'code'?: (number); + /** + * A developer-facing error message, which should be in English. Any + * user-facing error message should be localized and sent in the + * [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + */ 'message'?: (string); + /** + * A list of messages that carry the error details. There is a common set of + * message types for APIs to use. + */ 'details'?: (_google_protobuf_Any)[]; } +/** + * The `Status` type defines a logical error model that is suitable for + * different programming environments, including REST APIs and RPC APIs. It is + * used by [gRPC](https://github.com/grpc). Each `Status` message contains + * three pieces of data: error code, error message, and error details. + * + * You can find out more about this error model and how to work with it in the + * [API Design Guide](https://cloud.google.com/apis/design/errors). + */ export interface Status__Output { + /** + * The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + */ 'code': (number); + /** + * A developer-facing error message, which should be in English. Any + * user-facing error message should be localized and sent in the + * [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + */ 'message': (string); + /** + * A list of messages that carry the error details. There is a common set of + * message types for APIs to use. + */ 'details': (_google_protobuf_Any__Output)[]; } diff --git a/packages/grpc-js/src/generated/listener.ts b/packages/grpc-js/src/generated/listener.ts index 65a514ab7..4bc0d85cf 100644 --- a/packages/grpc-js/src/generated/listener.ts +++ b/packages/grpc-js/src/generated/listener.ts @@ -178,24 +178,72 @@ export namespace messages { } export namespace api { export namespace v2 { + /** + * [#next-free-field: 23] + */ export type Listener = _envoy_api_v2_Listener; + /** + * [#next-free-field: 23] + */ export type Listener__Output = _envoy_api_v2_Listener__Output; export namespace auth { + /** + * [#next-free-field: 11] + */ export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; + /** + * [#next-free-field: 11] + */ export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; + /** + * TLS context shared by both client and server TLS contexts. + * [#next-free-field: 9] + */ export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; + /** + * TLS context shared by both client and server TLS contexts. + * [#next-free-field: 9] + */ export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; + /** + * [#next-free-field: 8] + */ export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; + /** + * [#next-free-field: 8] + */ export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; export type GenericSecret = _envoy_api_v2_auth_GenericSecret; export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; + /** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; + /** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; + /** + * [#next-free-field: 6] + */ export type Secret = _envoy_api_v2_auth_Secret; + /** + * [#next-free-field: 6] + */ export type Secret__Output = _envoy_api_v2_auth_Secret__Output; + /** + * [#next-free-field: 7] + */ export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; + /** + * [#next-free-field: 7] + */ export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; export type TlsParameters = _envoy_api_v2_auth_TlsParameters; export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; @@ -205,75 +253,390 @@ export namespace messages { export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; } export namespace core { + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address = _envoy_api_v2_core_Address; + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address__Output = _envoy_api_v2_core_Address__Output; + /** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + /** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + /** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + /** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + /** + * xDS API version. This is used to describe both resource and transport + * protocol versions (in distinct configuration fields). + */ export type ApiVersion = _envoy_api_v2_core_ApiVersion; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type BindConfig = _envoy_api_v2_core_BindConfig; export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion = _envoy_api_v2_core_BuildVersion; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange = _envoy_api_v2_core_CidrRange; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + /** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export type ConfigSource = _envoy_api_v2_core_ConfigSource; + /** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane = _envoy_api_v2_core_ControlPlane; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource = _envoy_api_v2_core_DataSource; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension = _envoy_api_v2_core_Extension; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension__Output = _envoy_api_v2_core_Extension__Output; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService = _envoy_api_v2_core_GrpcService; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + /** + * Wrapper for a set of headers. + */ export type HeaderMap = _envoy_api_v2_core_HeaderMap; + /** + * Wrapper for a set of headers. + */ export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + /** + * Header name/value pair. + */ export type HeaderValue = _envoy_api_v2_core_HeaderValue; + /** + * Header name/value pair. + */ export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + /** + * Envoy external URI descriptor + */ export type HttpUri = _envoy_api_v2_core_HttpUri; + /** + * Envoy external URI descriptor + */ export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality = _envoy_api_v2_core_Locality; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality__Output = _envoy_api_v2_core_Locality__Output; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata = _envoy_api_v2_core_Metadata; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node = _envoy_api_v2_core_Node; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node__Output = _envoy_api_v2_core_Node__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + /** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + /** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + /** + * HTTP request method. + */ export type RequestMethod = _envoy_api_v2_core_RequestMethod; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + /** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + /** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + /** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + /** + * [#next-free-field: 7] + */ export type SocketAddress = _envoy_api_v2_core_SocketAddress; + /** + * [#next-free-field: 7] + */ export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption = _envoy_api_v2_core_SocketOption; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + /** + * Identifies the direction of the traffic relative to the local Envoy. + */ export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket = _envoy_api_v2_core_TransportSocket; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; } export namespace listener { @@ -281,51 +644,385 @@ export namespace messages { export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; export type Filter = _envoy_api_v2_listener_Filter; export type Filter__Output = _envoy_api_v2_listener_Filter__Output; + /** + * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and + * various other parameters. + * [#next-free-field: 8] + */ export type FilterChain = _envoy_api_v2_listener_FilterChain; + /** + * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and + * various other parameters. + * [#next-free-field: 8] + */ export type FilterChain__Output = _envoy_api_v2_listener_FilterChain__Output; + /** + * Specifies the match criteria for selecting a specific filter chain for a + * listener. + * + * In order for a filter chain to be selected, *ALL* of its criteria must be + * fulfilled by the incoming connection, properties of which are set by the + * networking stack and/or listener filters. + * + * The following order applies: + * + * 1. Destination port. + * 2. Destination IP address. + * 3. Server name (e.g. SNI for TLS protocol), + * 4. Transport protocol. + * 5. Application protocols (e.g. ALPN for TLS protocol). + * 6. Source type (e.g. any, local or external network). + * 7. Source IP address. + * 8. Source port. + * + * For criteria that allow ranges or wildcards, the most specific value in any + * of the configured filter chains that matches the incoming connection is going + * to be used (e.g. for SNI ``www.example.com`` the most specific match would be + * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter + * chain without ``server_names`` requirements). + * + * [#comment: Implemented rules are kept in the preference order, with deprecated fields + * listed at the end, because that's how we want to list them in the docs. + * + * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] + * [#next-free-field: 13] + */ export type FilterChainMatch = _envoy_api_v2_listener_FilterChainMatch; + /** + * Specifies the match criteria for selecting a specific filter chain for a + * listener. + * + * In order for a filter chain to be selected, *ALL* of its criteria must be + * fulfilled by the incoming connection, properties of which are set by the + * networking stack and/or listener filters. + * + * The following order applies: + * + * 1. Destination port. + * 2. Destination IP address. + * 3. Server name (e.g. SNI for TLS protocol), + * 4. Transport protocol. + * 5. Application protocols (e.g. ALPN for TLS protocol). + * 6. Source type (e.g. any, local or external network). + * 7. Source IP address. + * 8. Source port. + * + * For criteria that allow ranges or wildcards, the most specific value in any + * of the configured filter chains that matches the incoming connection is going + * to be used (e.g. for SNI ``www.example.com`` the most specific match would be + * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter + * chain without ``server_names`` requirements). + * + * [#comment: Implemented rules are kept in the preference order, with deprecated fields + * listed at the end, because that's how we want to list them in the docs. + * + * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] + * [#next-free-field: 13] + */ export type FilterChainMatch__Output = _envoy_api_v2_listener_FilterChainMatch__Output; export type ListenerFilter = _envoy_api_v2_listener_ListenerFilter; export type ListenerFilter__Output = _envoy_api_v2_listener_ListenerFilter__Output; + /** + * Listener filter chain match configuration. This is a recursive structure which allows complex + * nested match configurations to be built using various logical operators. + * + * Examples: + * + * * Matches if the destination port is 3306. + * + * .. code-block:: yaml + * + * destination_port_range: + * start: 3306 + * end: 3307 + * + * * Matches if the destination port is 3306 or 15000. + * + * .. code-block:: yaml + * + * or_match: + * rules: + * - destination_port_range: + * start: 3306 + * end: 3306 + * - destination_port_range: + * start: 15000 + * end: 15001 + * + * [#next-free-field: 6] + */ export type ListenerFilterChainMatchPredicate = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate; + /** + * Listener filter chain match configuration. This is a recursive structure which allows complex + * nested match configurations to be built using various logical operators. + * + * Examples: + * + * * Matches if the destination port is 3306. + * + * .. code-block:: yaml + * + * destination_port_range: + * start: 3306 + * end: 3307 + * + * * Matches if the destination port is 3306 or 15000. + * + * .. code-block:: yaml + * + * or_match: + * rules: + * - destination_port_range: + * start: 3306 + * end: 3306 + * - destination_port_range: + * start: 15000 + * end: 15001 + * + * [#next-free-field: 6] + */ export type ListenerFilterChainMatchPredicate__Output = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output; export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; } export namespace route { + /** + * [#next-free-field: 12] + */ export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; + /** + * [#next-free-field: 12] + */ export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; export type Decorator = _envoy_api_v2_route_Decorator; export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; + /** + * A filter-defined action type. + */ export type FilterAction = _envoy_api_v2_route_FilterAction; + /** + * A filter-defined action type. + */ export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; + /** + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* + * header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. attention:: + * + * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both + * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., + * + * .. code-block:: json + * + * { + * "name": ":method", + * "exact_match": "POST" + * } + * + * .. attention:: + * In the absence of any header match specifier, match will default to :ref:`present_match + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's + * value. + * + * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] + * [#next-free-field: 12] + */ export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; + /** + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* + * header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. attention:: + * + * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both + * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., + * + * .. code-block:: json + * + * { + * "name": ":method", + * "exact_match": "POST" + * } + * + * .. attention:: + * In the absence of any header match specifier, match will default to :ref:`present_match + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's + * value. + * + * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] + * [#next-free-field: 12] + */ export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; + /** + * HTTP request hedging :ref:`architecture overview `. + */ export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; + /** + * HTTP request hedging :ref:`architecture overview `. + */ export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; + /** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; + /** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + /** + * Global rate limiting :ref:`architecture overview `. + */ export type RateLimit = _envoy_api_v2_route_RateLimit; + /** + * Global rate limiting :ref:`architecture overview `. + */ export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; + /** + * [#next-free-field: 9] + */ export type RedirectAction = _envoy_api_v2_route_RedirectAction; + /** + * [#next-free-field: 9] + */ export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; + /** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 11] + */ export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; + /** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 11] + */ export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + /** + * A route is both a specification of how to match a request as well as an indication of what to do + * next (e.g., redirect, forward, rewrite, etc.). + * + * .. attention:: + * + * Envoy supports routing on HTTP method via :ref:`header matching + * `. + * [#next-free-field: 18] + */ export type Route = _envoy_api_v2_route_Route; + /** + * A route is both a specification of how to match a request as well as an indication of what to do + * next (e.g., redirect, forward, rewrite, etc.). + * + * .. attention:: + * + * Envoy supports routing on HTTP method via :ref:`header matching + * `. + * [#next-free-field: 18] + */ export type Route__Output = _envoy_api_v2_route_Route__Output; + /** + * [#next-free-field: 34] + */ export type RouteAction = _envoy_api_v2_route_RouteAction; + /** + * [#next-free-field: 34] + */ export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; + /** + * [#next-free-field: 12] + */ export type RouteMatch = _envoy_api_v2_route_RouteMatch; + /** + * [#next-free-field: 12] + */ export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; export type Tracing = _envoy_api_v2_route_Tracing; export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; + /** + * A virtual cluster is a way of specifying a regex matching rule against + * certain important endpoints such that statistics are generated explicitly for + * the matched requests. The reason this is useful is that when doing + * prefix/path matching Envoy does not always know what the application + * considers to be an endpoint. Thus, it’s impossible for Envoy to generically + * emit per endpoint statistics. However, often systems have highly critical + * endpoints that they wish to get “perfect†statistics on. Virtual cluster + * statistics are perfect in the sense that they are emitted on the downstream + * side such that they include network level failures. + * + * Documentation for :ref:`virtual cluster statistics `. + * + * .. note:: + * + * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for + * every application endpoint. This is both not easily maintainable and as well the matching and + * statistics output are not free. + */ export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; + /** + * A virtual cluster is a way of specifying a regex matching rule against + * certain important endpoints such that statistics are generated explicitly for + * the matched requests. The reason this is useful is that when doing + * prefix/path matching Envoy does not always know what the application + * considers to be an endpoint. Thus, it’s impossible for Envoy to generically + * emit per endpoint statistics. However, often systems have highly critical + * endpoints that they wish to get “perfect†statistics on. Virtual cluster + * statistics are perfect in the sense that they are emitted on the downstream + * side such that they include network level failures. + * + * Documentation for :ref:`virtual cluster statistics `. + * + * .. note:: + * + * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for + * every application endpoint. This is both not easily maintainable and as well the matching and + * statistics output are not free. + */ export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; + /** + * The top level element in the routing configuration is a virtual host. Each virtual host has + * a logical name as well as a set of domains that get routed to it based on the incoming request's + * host header. This allows a single listener to service multiple top level domain path trees. Once + * a virtual host is selected based on the domain, the routes are processed in order to see which + * upstream cluster to route to or whether to perform a redirect. + * [#next-free-field: 21] + */ export type VirtualHost = _envoy_api_v2_route_VirtualHost; + /** + * The top level element in the routing configuration is a virtual host. Each virtual host has + * a logical name as well as a set of domains that get routed to it based on the incoming request's + * host header. This allows a single listener to service multiple top level domain path trees. Once + * a virtual host is selected based on the domain, the routes are processed in order to see which + * upstream cluster to route to or whether to perform a redirect. + * [#next-free-field: 21] + */ export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; + /** + * Compared to the :ref:`cluster ` field that specifies a + * single upstream cluster as the target of a request, the :ref:`weighted_clusters + * ` option allows for specification of + * multiple upstream clusters along with weights that indicate the percentage of + * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the + * weights. + */ export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; + /** + * Compared to the :ref:`cluster ` field that specifies a + * single upstream cluster as the target of a request, the :ref:`weighted_clusters + * ` option allows for specification of + * multiple upstream clusters along with weights that indicate the percentage of + * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the + * weights. + */ export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; } } @@ -336,76 +1033,326 @@ export namespace messages { export namespace v2 { export type AccessLog = _envoy_config_filter_accesslog_v2_AccessLog; export type AccessLog__Output = _envoy_config_filter_accesslog_v2_AccessLog__Output; + /** + * [#next-free-field: 12] + */ export type AccessLogFilter = _envoy_config_filter_accesslog_v2_AccessLogFilter; + /** + * [#next-free-field: 12] + */ export type AccessLogFilter__Output = _envoy_config_filter_accesslog_v2_AccessLogFilter__Output; + /** + * Performs a logical “and†operation on the result of each filter in filters. + * Filters are evaluated sequentially and if one of them returns false, the + * filter returns false immediately. + */ export type AndFilter = _envoy_config_filter_accesslog_v2_AndFilter; + /** + * Performs a logical “and†operation on the result of each filter in filters. + * Filters are evaluated sequentially and if one of them returns false, the + * filter returns false immediately. + */ export type AndFilter__Output = _envoy_config_filter_accesslog_v2_AndFilter__Output; + /** + * Filter on an integer comparison. + */ export type ComparisonFilter = _envoy_config_filter_accesslog_v2_ComparisonFilter; + /** + * Filter on an integer comparison. + */ export type ComparisonFilter__Output = _envoy_config_filter_accesslog_v2_ComparisonFilter__Output; + /** + * Filters on total request duration in milliseconds. + */ export type DurationFilter = _envoy_config_filter_accesslog_v2_DurationFilter; + /** + * Filters on total request duration in milliseconds. + */ export type DurationFilter__Output = _envoy_config_filter_accesslog_v2_DurationFilter__Output; + /** + * Extension filter is statically registered at runtime. + */ export type ExtensionFilter = _envoy_config_filter_accesslog_v2_ExtensionFilter; + /** + * Extension filter is statically registered at runtime. + */ export type ExtensionFilter__Output = _envoy_config_filter_accesslog_v2_ExtensionFilter__Output; + /** + * Filters gRPC requests based on their response status. If a gRPC status is not provided, the + * filter will infer the status from the HTTP status code. + */ export type GrpcStatusFilter = _envoy_config_filter_accesslog_v2_GrpcStatusFilter; + /** + * Filters gRPC requests based on their response status. If a gRPC status is not provided, the + * filter will infer the status from the HTTP status code. + */ export type GrpcStatusFilter__Output = _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output; + /** + * Filters requests based on the presence or value of a request header. + */ export type HeaderFilter = _envoy_config_filter_accesslog_v2_HeaderFilter; + /** + * Filters requests based on the presence or value of a request header. + */ export type HeaderFilter__Output = _envoy_config_filter_accesslog_v2_HeaderFilter__Output; + /** + * Filters for requests that are not health check requests. A health check + * request is marked by the health check filter. + */ export type NotHealthCheckFilter = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter; + /** + * Filters for requests that are not health check requests. A health check + * request is marked by the health check filter. + */ export type NotHealthCheckFilter__Output = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output; + /** + * Performs a logical “or†operation on the result of each individual filter. + * Filters are evaluated sequentially and if one of them returns true, the + * filter returns true immediately. + */ export type OrFilter = _envoy_config_filter_accesslog_v2_OrFilter; + /** + * Performs a logical “or†operation on the result of each individual filter. + * Filters are evaluated sequentially and if one of them returns true, the + * filter returns true immediately. + */ export type OrFilter__Output = _envoy_config_filter_accesslog_v2_OrFilter__Output; + /** + * Filters requests that received responses with an Envoy response flag set. + * A list of the response flags can be found + * in the access log formatter :ref:`documentation`. + */ export type ResponseFlagFilter = _envoy_config_filter_accesslog_v2_ResponseFlagFilter; + /** + * Filters requests that received responses with an Envoy response flag set. + * A list of the response flags can be found + * in the access log formatter :ref:`documentation`. + */ export type ResponseFlagFilter__Output = _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output; + /** + * Filters for random sampling of requests. + */ export type RuntimeFilter = _envoy_config_filter_accesslog_v2_RuntimeFilter; + /** + * Filters for random sampling of requests. + */ export type RuntimeFilter__Output = _envoy_config_filter_accesslog_v2_RuntimeFilter__Output; + /** + * Filters on HTTP response/status code. + */ export type StatusCodeFilter = _envoy_config_filter_accesslog_v2_StatusCodeFilter; + /** + * Filters on HTTP response/status code. + */ export type StatusCodeFilter__Output = _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output; + /** + * Filters for requests that are traceable. See the tracing overview for more + * information on how a request becomes traceable. + */ export type TraceableFilter = _envoy_config_filter_accesslog_v2_TraceableFilter; + /** + * Filters for requests that are traceable. See the tracing overview for more + * information on how a request becomes traceable. + */ export type TraceableFilter__Output = _envoy_config_filter_accesslog_v2_TraceableFilter__Output; } } } export namespace listener { export namespace v2 { + /** + * Describes a type of API listener, which is used in non-proxy clients. The type of API + * exposed to the non-proxy application depends on the type of API listener. + */ export type ApiListener = _envoy_config_listener_v2_ApiListener; + /** + * Describes a type of API listener, which is used in non-proxy clients. The type of API + * exposed to the non-proxy application depends on the type of API listener. + */ export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; } } } export namespace type { + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange = _envoy_type_DoubleRange; + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent = _envoy_type_FractionalPercent; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range = _envoy_type_Int32Range; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range__Output = _envoy_type_Int32Range__Output; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range = _envoy_type_Int64Range; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range__Output = _envoy_type_Int64Range__Output; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent = _envoy_type_Percent; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent__Output = _envoy_type_Percent__Output; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion = _envoy_type_SemanticVersion; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher = _envoy_type_matcher_StringMatcher; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; } export namespace metadata { export namespace v2 { + /** + * MetadataKey provides a general interface using `key` and `path` to retrieve value from + * :ref:`Metadata `. + * + * For example, for the following Metadata: + * + * .. code-block:: yaml + * + * filter_metadata: + * envoy.xxx: + * prop: + * foo: bar + * xyz: + * hello: envoy + * + * The following MetadataKey will retrieve a string value "bar" from the Metadata. + * + * .. code-block:: yaml + * + * key: envoy.xxx + * path: + * - key: prop + * - key: foo + */ export type MetadataKey = _envoy_type_metadata_v2_MetadataKey; + /** + * MetadataKey provides a general interface using `key` and `path` to retrieve value from + * :ref:`Metadata `. + * + * For example, for the following Metadata: + * + * .. code-block:: yaml + * + * filter_metadata: + * envoy.xxx: + * prop: + * foo: bar + * xyz: + * hello: envoy + * + * The following MetadataKey will retrieve a string value "bar" from the Metadata. + * + * .. code-block:: yaml + * + * key: envoy.xxx + * path: + * - key: prop + * - key: foo + */ export type MetadataKey__Output = _envoy_type_metadata_v2_MetadataKey__Output; + /** + * Describes what kind of metadata. + */ export type MetadataKind = _envoy_type_metadata_v2_MetadataKind; + /** + * Describes what kind of metadata. + */ export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; } } export namespace tracing { export namespace v2 { + /** + * Describes custom tags for the active span. + * [#next-free-field: 6] + */ export type CustomTag = _envoy_type_tracing_v2_CustomTag; + /** + * Describes custom tags for the active span. + * [#next-free-field: 6] + */ export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; } } @@ -413,11 +1360,569 @@ export namespace messages { } export namespace google { export namespace api { + /** + * A custom pattern is used for defining custom HTTP verb. + */ export type CustomHttpPattern = _google_api_CustomHttpPattern; + /** + * A custom pattern is used for defining custom HTTP verb. + */ export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; + /** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export type Http = _google_api_Http; + /** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export type Http__Output = _google_api_Http__Output; + /** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export type HttpRule = _google_api_HttpRule; + /** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export type HttpRule__Output = _google_api_HttpRule__Output; } export namespace protobuf { @@ -510,52 +2015,203 @@ export namespace messages { } } export namespace validate { + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules = _validate_AnyRules; + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules__Output = _validate_AnyRules__Output; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules = _validate_BoolRules; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules__Output = _validate_BoolRules__Output; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules = _validate_BytesRules; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules__Output = _validate_BytesRules__Output; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules = _validate_DoubleRules; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules__Output = _validate_DoubleRules__Output; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules = _validate_DurationRules; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules__Output = _validate_DurationRules__Output; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules = _validate_EnumRules; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules__Output = _validate_EnumRules__Output; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules = _validate_FieldRules; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules__Output = _validate_FieldRules__Output; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules = _validate_Fixed32Rules; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules = _validate_Fixed64Rules; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules = _validate_FloatRules; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules__Output = _validate_FloatRules__Output; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules = _validate_Int32Rules; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules__Output = _validate_Int32Rules__Output; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules = _validate_Int64Rules; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules__Output = _validate_Int64Rules__Output; + /** + * WellKnownRegex contain some well-known patterns. + */ export type KnownRegex = _validate_KnownRegex; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules = _validate_MapRules; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules__Output = _validate_MapRules__Output; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules = _validate_MessageRules; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules__Output = _validate_MessageRules__Output; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules = _validate_RepeatedRules; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules__Output = _validate_RepeatedRules__Output; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules = _validate_SFixed32Rules; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules = _validate_SFixed64Rules; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules = _validate_SInt32Rules; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules__Output = _validate_SInt32Rules__Output; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules = _validate_SInt64Rules; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules__Output = _validate_SInt64Rules__Output; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules = _validate_StringRules; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules__Output = _validate_StringRules__Output; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules = _validate_TimestampRules; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules__Output = _validate_TimestampRules__Output; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules = _validate_UInt32Rules; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules__Output = _validate_UInt32Rules__Output; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules = _validate_UInt64Rules; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules__Output = _validate_UInt64Rules__Output; } } diff --git a/packages/grpc-js/src/generated/route.ts b/packages/grpc-js/src/generated/route.ts index b3de909f2..2a676be88 100644 --- a/packages/grpc-js/src/generated/route.ts +++ b/packages/grpc-js/src/generated/route.ts @@ -143,154 +143,825 @@ export namespace messages { } export namespace api { export namespace v2 { + /** + * [#next-free-field: 11] + */ export type RouteConfiguration = _envoy_api_v2_RouteConfiguration; + /** + * [#next-free-field: 11] + */ export type RouteConfiguration__Output = _envoy_api_v2_RouteConfiguration__Output; export type Vhds = _envoy_api_v2_Vhds; export type Vhds__Output = _envoy_api_v2_Vhds__Output; export namespace core { + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address = _envoy_api_v2_core_Address; + /** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ export type Address__Output = _envoy_api_v2_core_Address__Output; + /** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; + /** + * Aggregated Discovery Service (ADS) options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that ADS is to be used. + */ export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; + /** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; + /** + * API configuration source. This identifies the API type and cluster that Envoy + * will use to fetch an xDS API. + * [#next-free-field: 9] + */ export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; + /** + * xDS API version. This is used to describe both resource and transport + * protocol versions (in distinct configuration fields). + */ export type ApiVersion = _envoy_api_v2_core_ApiVersion; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; + /** + * Async data source which support async data fetch. + */ export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; + /** + * Configuration defining a jittered exponential back off strategy. + */ export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; export type BindConfig = _envoy_api_v2_core_BindConfig; export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion = _envoy_api_v2_core_BuildVersion; + /** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange = _envoy_api_v2_core_CidrRange; + /** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; + /** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export type ConfigSource = _envoy_api_v2_core_ConfigSource; + /** + * Configuration for :ref:`listeners `, :ref:`clusters + * `, :ref:`routes + * `, :ref:`endpoints + * ` etc. may either be sourced from the + * filesystem or from an xDS API source. Filesystem configs are watched with + * inotify for updates. + * [#next-free-field: 7] + */ export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane = _envoy_api_v2_core_ControlPlane; + /** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource = _envoy_api_v2_core_DataSource; + /** + * Data source consisting of either a file or an inline value. + */ export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension = _envoy_api_v2_core_Extension; + /** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ export type Extension__Output = _envoy_api_v2_core_Extension__Output; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService = _envoy_api_v2_core_GrpcService; + /** + * gRPC service configuration. This is used by :ref:`ApiConfigSource + * ` and filter configurations. + * [#next-free-field: 6] + */ export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; + /** + * Wrapper for a set of headers. + */ export type HeaderMap = _envoy_api_v2_core_HeaderMap; + /** + * Wrapper for a set of headers. + */ export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; + /** + * Header name/value pair. + */ export type HeaderValue = _envoy_api_v2_core_HeaderValue; + /** + * Header name/value pair. + */ export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; + /** + * Header name/value pair plus option to control append behavior. + */ export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; + /** + * Envoy external URI descriptor + */ export type HttpUri = _envoy_api_v2_core_HttpUri; + /** + * Envoy external URI descriptor + */ export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality = _envoy_api_v2_core_Locality; + /** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ export type Locality__Output = _envoy_api_v2_core_Locality__Output; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata = _envoy_api_v2_core_Metadata; + /** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node = _envoy_api_v2_core_Node; + /** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ export type Node__Output = _envoy_api_v2_core_Node__Output; export type Pipe = _envoy_api_v2_core_Pipe; export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; + /** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; + /** + * Rate Limit settings to be applied for discovery requests made by Envoy. + */ export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; + /** + * The message specifies how to fetch data from remote and how to verify it. + */ export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; + /** + * HTTP request method. + */ export type RequestMethod = _envoy_api_v2_core_RequestMethod; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; + /** + * The message specifies the retry policy of remote data source when fetching fails. + */ export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; + /** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; + /** + * Runtime derived double with a default when not specified. + */ export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; + /** + * Runtime derived bool with a default when not specified. + */ export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; + /** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; + /** + * Runtime derived uint32 with a default when not specified. + */ export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; + /** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; + /** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; + /** + * [#next-free-field: 7] + */ export type SocketAddress = _envoy_api_v2_core_SocketAddress; + /** + * [#next-free-field: 7] + */ export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption = _envoy_api_v2_core_SocketOption; + /** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; + /** + * Identifies the direction of the traffic relative to the local Envoy. + */ export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket = _envoy_api_v2_core_TransportSocket; + /** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; } export namespace route { + /** + * [#next-free-field: 12] + */ export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; + /** + * [#next-free-field: 12] + */ export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; export type Decorator = _envoy_api_v2_route_Decorator; export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; + /** + * A filter-defined action type. + */ export type FilterAction = _envoy_api_v2_route_FilterAction; + /** + * A filter-defined action type. + */ export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; + /** + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* + * header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. attention:: + * + * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both + * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., + * + * .. code-block:: json + * + * { + * "name": ":method", + * "exact_match": "POST" + * } + * + * .. attention:: + * In the absence of any header match specifier, match will default to :ref:`present_match + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's + * value. + * + * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] + * [#next-free-field: 12] + */ export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; + /** + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* + * header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. attention:: + * + * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both + * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., + * + * .. code-block:: json + * + * { + * "name": ":method", + * "exact_match": "POST" + * } + * + * .. attention:: + * In the absence of any header match specifier, match will default to :ref:`present_match + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's + * value. + * + * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] + * [#next-free-field: 12] + */ export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; + /** + * HTTP request hedging :ref:`architecture overview `. + */ export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; + /** + * HTTP request hedging :ref:`architecture overview `. + */ export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; + /** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; + /** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; + /** + * Global rate limiting :ref:`architecture overview `. + */ export type RateLimit = _envoy_api_v2_route_RateLimit; + /** + * Global rate limiting :ref:`architecture overview `. + */ export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; + /** + * [#next-free-field: 9] + */ export type RedirectAction = _envoy_api_v2_route_RedirectAction; + /** + * [#next-free-field: 9] + */ export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; + /** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 11] + */ export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; + /** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 11] + */ export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; + /** + * A route is both a specification of how to match a request as well as an indication of what to do + * next (e.g., redirect, forward, rewrite, etc.). + * + * .. attention:: + * + * Envoy supports routing on HTTP method via :ref:`header matching + * `. + * [#next-free-field: 18] + */ export type Route = _envoy_api_v2_route_Route; + /** + * A route is both a specification of how to match a request as well as an indication of what to do + * next (e.g., redirect, forward, rewrite, etc.). + * + * .. attention:: + * + * Envoy supports routing on HTTP method via :ref:`header matching + * `. + * [#next-free-field: 18] + */ export type Route__Output = _envoy_api_v2_route_Route__Output; + /** + * [#next-free-field: 34] + */ export type RouteAction = _envoy_api_v2_route_RouteAction; + /** + * [#next-free-field: 34] + */ export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; + /** + * [#next-free-field: 12] + */ export type RouteMatch = _envoy_api_v2_route_RouteMatch; + /** + * [#next-free-field: 12] + */ export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; export type Tracing = _envoy_api_v2_route_Tracing; export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; + /** + * A virtual cluster is a way of specifying a regex matching rule against + * certain important endpoints such that statistics are generated explicitly for + * the matched requests. The reason this is useful is that when doing + * prefix/path matching Envoy does not always know what the application + * considers to be an endpoint. Thus, it’s impossible for Envoy to generically + * emit per endpoint statistics. However, often systems have highly critical + * endpoints that they wish to get “perfect†statistics on. Virtual cluster + * statistics are perfect in the sense that they are emitted on the downstream + * side such that they include network level failures. + * + * Documentation for :ref:`virtual cluster statistics `. + * + * .. note:: + * + * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for + * every application endpoint. This is both not easily maintainable and as well the matching and + * statistics output are not free. + */ export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; + /** + * A virtual cluster is a way of specifying a regex matching rule against + * certain important endpoints such that statistics are generated explicitly for + * the matched requests. The reason this is useful is that when doing + * prefix/path matching Envoy does not always know what the application + * considers to be an endpoint. Thus, it’s impossible for Envoy to generically + * emit per endpoint statistics. However, often systems have highly critical + * endpoints that they wish to get “perfect†statistics on. Virtual cluster + * statistics are perfect in the sense that they are emitted on the downstream + * side such that they include network level failures. + * + * Documentation for :ref:`virtual cluster statistics `. + * + * .. note:: + * + * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for + * every application endpoint. This is both not easily maintainable and as well the matching and + * statistics output are not free. + */ export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; + /** + * The top level element in the routing configuration is a virtual host. Each virtual host has + * a logical name as well as a set of domains that get routed to it based on the incoming request's + * host header. This allows a single listener to service multiple top level domain path trees. Once + * a virtual host is selected based on the domain, the routes are processed in order to see which + * upstream cluster to route to or whether to perform a redirect. + * [#next-free-field: 21] + */ export type VirtualHost = _envoy_api_v2_route_VirtualHost; + /** + * The top level element in the routing configuration is a virtual host. Each virtual host has + * a logical name as well as a set of domains that get routed to it based on the incoming request's + * host header. This allows a single listener to service multiple top level domain path trees. Once + * a virtual host is selected based on the domain, the routes are processed in order to see which + * upstream cluster to route to or whether to perform a redirect. + * [#next-free-field: 21] + */ export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; + /** + * Compared to the :ref:`cluster ` field that specifies a + * single upstream cluster as the target of a request, the :ref:`weighted_clusters + * ` option allows for specification of + * multiple upstream clusters along with weights that indicate the percentage of + * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the + * weights. + */ export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; + /** + * Compared to the :ref:`cluster ` field that specifies a + * single upstream cluster as the target of a request, the :ref:`weighted_clusters + * ` option allows for specification of + * multiple upstream clusters along with weights that indicate the percentage of + * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the + * weights. + */ export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; } } } export namespace type { + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange = _envoy_type_DoubleRange; + /** + * Specifies the double start and end of the range using half-open interval semantics [start, + * end). + */ export type DoubleRange__Output = _envoy_type_DoubleRange__Output; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent = _envoy_type_FractionalPercent; + /** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range = _envoy_type_Int32Range; + /** + * Specifies the int32 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int32Range__Output = _envoy_type_Int32Range__Output; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range = _envoy_type_Int64Range; + /** + * Specifies the int64 start and end of the range using half-open interval semantics [start, + * end). + */ export type Int64Range__Output = _envoy_type_Int64Range__Output; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent = _envoy_type_Percent; + /** + * Identifies a percentage, in the range [0.0, 100.0]. + */ export type Percent__Output = _envoy_type_Percent__Output; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion = _envoy_type_SemanticVersion; + /** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; export namespace matcher { + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; + /** + * Specifies a list of ways to match a string. + */ export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; + /** + * Describes how to match a string and then produce a new string using a regular + * expression and a substitution string. + */ export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher = _envoy_type_matcher_RegexMatcher; + /** + * A regex matcher designed for safety when used with untrusted input. + */ export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher = _envoy_type_matcher_StringMatcher; + /** + * Specifies the way to match a string. + * [#next-free-field: 7] + */ export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; } export namespace metadata { export namespace v2 { + /** + * MetadataKey provides a general interface using `key` and `path` to retrieve value from + * :ref:`Metadata `. + * + * For example, for the following Metadata: + * + * .. code-block:: yaml + * + * filter_metadata: + * envoy.xxx: + * prop: + * foo: bar + * xyz: + * hello: envoy + * + * The following MetadataKey will retrieve a string value "bar" from the Metadata. + * + * .. code-block:: yaml + * + * key: envoy.xxx + * path: + * - key: prop + * - key: foo + */ export type MetadataKey = _envoy_type_metadata_v2_MetadataKey; + /** + * MetadataKey provides a general interface using `key` and `path` to retrieve value from + * :ref:`Metadata `. + * + * For example, for the following Metadata: + * + * .. code-block:: yaml + * + * filter_metadata: + * envoy.xxx: + * prop: + * foo: bar + * xyz: + * hello: envoy + * + * The following MetadataKey will retrieve a string value "bar" from the Metadata. + * + * .. code-block:: yaml + * + * key: envoy.xxx + * path: + * - key: prop + * - key: foo + */ export type MetadataKey__Output = _envoy_type_metadata_v2_MetadataKey__Output; + /** + * Describes what kind of metadata. + */ export type MetadataKind = _envoy_type_metadata_v2_MetadataKind; + /** + * Describes what kind of metadata. + */ export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; } } export namespace tracing { export namespace v2 { + /** + * Describes custom tags for the active span. + * [#next-free-field: 6] + */ export type CustomTag = _envoy_type_tracing_v2_CustomTag; + /** + * Describes custom tags for the active span. + * [#next-free-field: 6] + */ export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; } } @@ -387,52 +1058,203 @@ export namespace messages { } } export namespace validate { + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules = _validate_AnyRules; + /** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export type AnyRules__Output = _validate_AnyRules__Output; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules = _validate_BoolRules; + /** + * BoolRules describes the constraints applied to `bool` values + */ export type BoolRules__Output = _validate_BoolRules__Output; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules = _validate_BytesRules; + /** + * BytesRules describe the constraints applied to `bytes` values + */ export type BytesRules__Output = _validate_BytesRules__Output; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules = _validate_DoubleRules; + /** + * DoubleRules describes the constraints applied to `double` values + */ export type DoubleRules__Output = _validate_DoubleRules__Output; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules = _validate_DurationRules; + /** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export type DurationRules__Output = _validate_DurationRules__Output; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules = _validate_EnumRules; + /** + * EnumRules describe the constraints applied to enum values + */ export type EnumRules__Output = _validate_EnumRules__Output; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules = _validate_FieldRules; + /** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export type FieldRules__Output = _validate_FieldRules__Output; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules = _validate_Fixed32Rules; + /** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules = _validate_Fixed64Rules; + /** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules = _validate_FloatRules; + /** + * FloatRules describes the constraints applied to `float` values + */ export type FloatRules__Output = _validate_FloatRules__Output; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules = _validate_Int32Rules; + /** + * Int32Rules describes the constraints applied to `int32` values + */ export type Int32Rules__Output = _validate_Int32Rules__Output; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules = _validate_Int64Rules; + /** + * Int64Rules describes the constraints applied to `int64` values + */ export type Int64Rules__Output = _validate_Int64Rules__Output; + /** + * WellKnownRegex contain some well-known patterns. + */ export type KnownRegex = _validate_KnownRegex; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules = _validate_MapRules; + /** + * MapRules describe the constraints applied to `map` values + */ export type MapRules__Output = _validate_MapRules__Output; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules = _validate_MessageRules; + /** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export type MessageRules__Output = _validate_MessageRules__Output; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules = _validate_RepeatedRules; + /** + * RepeatedRules describe the constraints applied to `repeated` values + */ export type RepeatedRules__Output = _validate_RepeatedRules__Output; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules = _validate_SFixed32Rules; + /** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules = _validate_SFixed64Rules; + /** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules = _validate_SInt32Rules; + /** + * SInt32Rules describes the constraints applied to `sint32` values + */ export type SInt32Rules__Output = _validate_SInt32Rules__Output; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules = _validate_SInt64Rules; + /** + * SInt64Rules describes the constraints applied to `sint64` values + */ export type SInt64Rules__Output = _validate_SInt64Rules__Output; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules = _validate_StringRules; + /** + * StringRules describe the constraints applied to `string` values + */ export type StringRules__Output = _validate_StringRules__Output; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules = _validate_TimestampRules; + /** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export type TimestampRules__Output = _validate_TimestampRules__Output; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules = _validate_UInt32Rules; + /** + * UInt32Rules describes the constraints applied to `uint32` values + */ export type UInt32Rules__Output = _validate_UInt32Rules__Output; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules = _validate_UInt64Rules; + /** + * UInt64Rules describes the constraints applied to `uint64` values + */ export type UInt64Rules__Output = _validate_UInt64Rules__Output; } } diff --git a/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts b/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts index 375c1f5be..1ad015b25 100644 --- a/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts +++ b/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts @@ -2,11 +2,27 @@ export interface FieldMigrateAnnotation { + /** + * Rename the field in next version. + */ 'rename'?: (string); + /** + * Add the field to a named oneof in next version. If this already exists, the + * field will join its siblings under the oneof, otherwise a new oneof will be + * created with the given name. + */ 'oneof_promotion'?: (string); } export interface FieldMigrateAnnotation__Output { + /** + * Rename the field in next version. + */ 'rename': (string); + /** + * Add the field to a named oneof in next version. If this already exists, the + * field will join its siblings under the oneof, otherwise a new oneof will be + * created with the given name. + */ 'oneof_promotion': (string); } diff --git a/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts b/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts index a6f113694..b7ef7c21d 100644 --- a/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts +++ b/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts @@ -2,9 +2,17 @@ export interface FileMigrateAnnotation { + /** + * Move all types in the file to another package, this implies changing proto + * file path. + */ 'move_to_package'?: (string); } export interface FileMigrateAnnotation__Output { + /** + * Move all types in the file to another package, this implies changing proto + * file path. + */ 'move_to_package': (string); } diff --git a/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts b/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts index 57402231f..e3fdcaa99 100644 --- a/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts +++ b/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts @@ -2,9 +2,15 @@ export interface MigrateAnnotation { + /** + * Rename the message/enum/enum value in next version. + */ 'rename'?: (string); } export interface MigrateAnnotation__Output { + /** + * Rename the message/enum/enum value in next version. + */ 'rename': (string); } diff --git a/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts b/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts index 9888e1d14..c60c3f984 100644 --- a/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts +++ b/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts @@ -1,8 +1,21 @@ // Original file: deps/udpa/udpa/annotations/status.proto export enum PackageVersionStatus { + /** + * Unknown package version status. + */ UNKNOWN = 0, + /** + * This version of the package is frozen. + */ FROZEN = 1, + /** + * This version of the package is the active development version. + */ ACTIVE = 2, + /** + * This version of the package is the candidate for the next major version. It + * is typically machine generated from the active development version. + */ NEXT_MAJOR_VERSION_CANDIDATE = 3, } diff --git a/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts b/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts index 3b4748c00..1b00aa9fc 100644 --- a/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts +++ b/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts @@ -3,11 +3,23 @@ import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from '../../udpa/annotations/PackageVersionStatus'; export interface StatusAnnotation { + /** + * The entity is work-in-progress and subject to breaking changes. + */ 'work_in_progress'?: (boolean); + /** + * The entity belongs to a package with the given version status. + */ 'package_version_status'?: (_udpa_annotations_PackageVersionStatus | keyof typeof _udpa_annotations_PackageVersionStatus); } export interface StatusAnnotation__Output { + /** + * The entity is work-in-progress and subject to breaking changes. + */ 'work_in_progress': (boolean); + /** + * The entity belongs to a package with the given version status. + */ 'package_version_status': (keyof typeof _udpa_annotations_PackageVersionStatus); } diff --git a/packages/grpc-js/src/generated/validate/AnyRules.ts b/packages/grpc-js/src/generated/validate/AnyRules.ts index c55a03f58..6b16d986c 100644 --- a/packages/grpc-js/src/generated/validate/AnyRules.ts +++ b/packages/grpc-js/src/generated/validate/AnyRules.ts @@ -1,14 +1,44 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export interface AnyRules { + /** + * Required specifies that this field must be set + */ 'required'?: (boolean); + /** + * In specifies that this field's `type_url` must be equal to one of the + * specified values. + */ 'in'?: (string)[]; + /** + * NotIn specifies that this field's `type_url` must not be equal to any of + * the specified values. + */ 'not_in'?: (string)[]; } +/** + * AnyRules describe constraints applied exclusively to the + * `google.protobuf.Any` well-known type + */ export interface AnyRules__Output { + /** + * Required specifies that this field must be set + */ 'required': (boolean); + /** + * In specifies that this field's `type_url` must be equal to one of the + * specified values. + */ 'in': (string)[]; + /** + * NotIn specifies that this field's `type_url` must not be equal to any of + * the specified values. + */ 'not_in': (string)[]; } diff --git a/packages/grpc-js/src/generated/validate/BoolRules.ts b/packages/grpc-js/src/generated/validate/BoolRules.ts index 85db6c621..3fd2a7a64 100644 --- a/packages/grpc-js/src/generated/validate/BoolRules.ts +++ b/packages/grpc-js/src/generated/validate/BoolRules.ts @@ -1,10 +1,22 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * BoolRules describes the constraints applied to `bool` values + */ export interface BoolRules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (boolean); } +/** + * BoolRules describes the constraints applied to `bool` values + */ export interface BoolRules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (boolean); } diff --git a/packages/grpc-js/src/generated/validate/BytesRules.ts b/packages/grpc-js/src/generated/validate/BytesRules.ts index a18bf6906..656d70194 100644 --- a/packages/grpc-js/src/generated/validate/BytesRules.ts +++ b/packages/grpc-js/src/generated/validate/BytesRules.ts @@ -2,36 +2,152 @@ import { Long } from '@grpc/proto-loader'; +/** + * BytesRules describe the constraints applied to `bytes` values + */ export interface BytesRules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (Buffer | Uint8Array | string); + /** + * MinLen specifies that this field must be the specified number of bytes + * at a minimum + */ 'min_len'?: (number | string | Long); + /** + * MaxLen specifies that this field must be the specified number of bytes + * at a maximum + */ 'max_len'?: (number | string | Long); + /** + * Pattern specifes that this field must match against the specified + * regular expression (RE2 syntax). The included expression should elide + * any delimiters. + */ 'pattern'?: (string); + /** + * Prefix specifies that this field must have the specified bytes at the + * beginning of the string. + */ 'prefix'?: (Buffer | Uint8Array | string); + /** + * Suffix specifies that this field must have the specified bytes at the + * end of the string. + */ 'suffix'?: (Buffer | Uint8Array | string); + /** + * Contains specifies that this field must have the specified bytes + * anywhere in the string. + */ 'contains'?: (Buffer | Uint8Array | string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (Buffer | Uint8Array | string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (Buffer | Uint8Array | string)[]; + /** + * Ip specifies that the field must be a valid IP (v4 or v6) address in + * byte format + */ 'ip'?: (boolean); + /** + * Ipv4 specifies that the field must be a valid IPv4 address in byte + * format + */ 'ipv4'?: (boolean); + /** + * Ipv6 specifies that the field must be a valid IPv6 address in byte + * format + */ 'ipv6'?: (boolean); + /** + * Len specifies that this field must be the specified number of bytes + */ 'len'?: (number | string | Long); + /** + * WellKnown rules provide advanced constraints against common byte + * patterns + */ 'well_known'?: "ip"|"ipv4"|"ipv6"; } +/** + * BytesRules describe the constraints applied to `bytes` values + */ export interface BytesRules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (Buffer); + /** + * MinLen specifies that this field must be the specified number of bytes + * at a minimum + */ 'min_len': (string); + /** + * MaxLen specifies that this field must be the specified number of bytes + * at a maximum + */ 'max_len': (string); + /** + * Pattern specifes that this field must match against the specified + * regular expression (RE2 syntax). The included expression should elide + * any delimiters. + */ 'pattern': (string); + /** + * Prefix specifies that this field must have the specified bytes at the + * beginning of the string. + */ 'prefix': (Buffer); + /** + * Suffix specifies that this field must have the specified bytes at the + * end of the string. + */ 'suffix': (Buffer); + /** + * Contains specifies that this field must have the specified bytes + * anywhere in the string. + */ 'contains': (Buffer); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (Buffer)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (Buffer)[]; + /** + * Ip specifies that the field must be a valid IP (v4 or v6) address in + * byte format + */ 'ip'?: (boolean); + /** + * Ipv4 specifies that the field must be a valid IPv4 address in byte + * format + */ 'ipv4'?: (boolean); + /** + * Ipv6 specifies that the field must be a valid IPv6 address in byte + * format + */ 'ipv6'?: (boolean); + /** + * Len specifies that this field must be the specified number of bytes + */ 'len': (string); + /** + * WellKnown rules provide advanced constraints against common byte + * patterns + */ 'well_known': "ip"|"ipv4"|"ipv6"; } diff --git a/packages/grpc-js/src/generated/validate/DoubleRules.ts b/packages/grpc-js/src/generated/validate/DoubleRules.ts index 476d0b9bc..fead5072a 100644 --- a/packages/grpc-js/src/generated/validate/DoubleRules.ts +++ b/packages/grpc-js/src/generated/validate/DoubleRules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * DoubleRules describes the constraints applied to `double` values + */ export interface DoubleRules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string)[]; } +/** + * DoubleRules describes the constraints applied to `double` values + */ export interface DoubleRules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number | string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number | string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number | string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number | string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number | string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number | string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number | string)[]; } diff --git a/packages/grpc-js/src/generated/validate/DurationRules.ts b/packages/grpc-js/src/generated/validate/DurationRules.ts index 6bd07149d..ed249bc8d 100644 --- a/packages/grpc-js/src/generated/validate/DurationRules.ts +++ b/packages/grpc-js/src/generated/validate/DurationRules.ts @@ -2,24 +2,92 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; +/** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export interface DurationRules { + /** + * Required specifies that this field must be set + */ 'required'?: (boolean); + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (_google_protobuf_Duration); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (_google_protobuf_Duration); + /** + * Lt specifies that this field must be less than the specified value, + * inclusive + */ 'lte'?: (_google_protobuf_Duration); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive + */ 'gt'?: (_google_protobuf_Duration); + /** + * Gte specifies that this field must be greater than the specified value, + * inclusive + */ 'gte'?: (_google_protobuf_Duration); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (_google_protobuf_Duration)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (_google_protobuf_Duration)[]; } +/** + * DurationRules describe the constraints applied exclusively to the + * `google.protobuf.Duration` well-known type + */ export interface DurationRules__Output { + /** + * Required specifies that this field must be set + */ 'required': (boolean); + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (_google_protobuf_Duration__Output); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (_google_protobuf_Duration__Output); + /** + * Lt specifies that this field must be less than the specified value, + * inclusive + */ 'lte': (_google_protobuf_Duration__Output); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive + */ 'gt': (_google_protobuf_Duration__Output); + /** + * Gte specifies that this field must be greater than the specified value, + * inclusive + */ 'gte': (_google_protobuf_Duration__Output); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (_google_protobuf_Duration__Output)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (_google_protobuf_Duration__Output)[]; } diff --git a/packages/grpc-js/src/generated/validate/EnumRules.ts b/packages/grpc-js/src/generated/validate/EnumRules.ts index 02ae6330e..c70eb0b19 100644 --- a/packages/grpc-js/src/generated/validate/EnumRules.ts +++ b/packages/grpc-js/src/generated/validate/EnumRules.ts @@ -1,16 +1,52 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * EnumRules describe the constraints applied to enum values + */ export interface EnumRules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number); + /** + * DefinedOnly specifies that this field must be only one of the defined + * values for this enum, failing on any undefined value. + */ 'defined_only'?: (boolean); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number)[]; } +/** + * EnumRules describe the constraints applied to enum values + */ export interface EnumRules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number); + /** + * DefinedOnly specifies that this field must be only one of the defined + * values for this enum, failing on any undefined value. + */ 'defined_only': (boolean); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number)[]; } diff --git a/packages/grpc-js/src/generated/validate/FieldRules.ts b/packages/grpc-js/src/generated/validate/FieldRules.ts index 5451902d7..3601f0dad 100644 --- a/packages/grpc-js/src/generated/validate/FieldRules.ts +++ b/packages/grpc-js/src/generated/validate/FieldRules.ts @@ -24,7 +24,14 @@ import { DurationRules as _validate_DurationRules, DurationRules__Output as _val import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from '../validate/TimestampRules'; import { Long } from '@grpc/proto-loader'; +/** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export interface FieldRules { + /** + * Scalar Field Types + */ 'float'?: (_validate_FloatRules); 'double'?: (_validate_DoubleRules); 'int32'?: (_validate_Int32Rules); @@ -40,17 +47,30 @@ export interface FieldRules { 'bool'?: (_validate_BoolRules); 'string'?: (_validate_StringRules); 'bytes'?: (_validate_BytesRules); + /** + * Complex Field Types + */ 'enum'?: (_validate_EnumRules); 'message'?: (_validate_MessageRules); 'repeated'?: (_validate_RepeatedRules); 'map'?: (_validate_MapRules); + /** + * Well-Known Field Types + */ 'any'?: (_validate_AnyRules); 'duration'?: (_validate_DurationRules); 'timestamp'?: (_validate_TimestampRules); 'type'?: "float"|"double"|"int32"|"int64"|"uint32"|"uint64"|"sint32"|"sint64"|"fixed32"|"fixed64"|"sfixed32"|"sfixed64"|"bool"|"string"|"bytes"|"enum"|"repeated"|"map"|"any"|"duration"|"timestamp"; } +/** + * FieldRules encapsulates the rules for each type of field. Depending on the + * field, the correct set should be used to ensure proper validations. + */ export interface FieldRules__Output { + /** + * Scalar Field Types + */ 'float'?: (_validate_FloatRules__Output); 'double'?: (_validate_DoubleRules__Output); 'int32'?: (_validate_Int32Rules__Output); @@ -66,10 +86,16 @@ export interface FieldRules__Output { 'bool'?: (_validate_BoolRules__Output); 'string'?: (_validate_StringRules__Output); 'bytes'?: (_validate_BytesRules__Output); + /** + * Complex Field Types + */ 'enum'?: (_validate_EnumRules__Output); 'message': (_validate_MessageRules__Output); 'repeated'?: (_validate_RepeatedRules__Output); 'map'?: (_validate_MapRules__Output); + /** + * Well-Known Field Types + */ 'any'?: (_validate_AnyRules__Output); 'duration'?: (_validate_DurationRules__Output); 'timestamp'?: (_validate_TimestampRules__Output); diff --git a/packages/grpc-js/src/generated/validate/Fixed32Rules.ts b/packages/grpc-js/src/generated/validate/Fixed32Rules.ts index 27bbdad93..e88953875 100644 --- a/packages/grpc-js/src/generated/validate/Fixed32Rules.ts +++ b/packages/grpc-js/src/generated/validate/Fixed32Rules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export interface Fixed32Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number)[]; } +/** + * Fixed32Rules describes the constraints applied to `fixed32` values + */ export interface Fixed32Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number)[]; } diff --git a/packages/grpc-js/src/generated/validate/Fixed64Rules.ts b/packages/grpc-js/src/generated/validate/Fixed64Rules.ts index 8a211bac0..0b750efc8 100644 --- a/packages/grpc-js/src/generated/validate/Fixed64Rules.ts +++ b/packages/grpc-js/src/generated/validate/Fixed64Rules.ts @@ -2,22 +2,86 @@ import { Long } from '@grpc/proto-loader'; +/** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export interface Fixed64Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string | Long); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string | Long); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string | Long); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string | Long); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string | Long); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string | Long)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string | Long)[]; } +/** + * Fixed64Rules describes the constraints applied to `fixed64` values + */ export interface Fixed64Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (string)[]; } diff --git a/packages/grpc-js/src/generated/validate/FloatRules.ts b/packages/grpc-js/src/generated/validate/FloatRules.ts index 6d29f67d8..35aafa809 100644 --- a/packages/grpc-js/src/generated/validate/FloatRules.ts +++ b/packages/grpc-js/src/generated/validate/FloatRules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * FloatRules describes the constraints applied to `float` values + */ export interface FloatRules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string)[]; } +/** + * FloatRules describes the constraints applied to `float` values + */ export interface FloatRules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number | string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number | string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number | string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number | string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number | string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number | string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number | string)[]; } diff --git a/packages/grpc-js/src/generated/validate/Int32Rules.ts b/packages/grpc-js/src/generated/validate/Int32Rules.ts index 03fb112c7..ea7ed42f3 100644 --- a/packages/grpc-js/src/generated/validate/Int32Rules.ts +++ b/packages/grpc-js/src/generated/validate/Int32Rules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * Int32Rules describes the constraints applied to `int32` values + */ export interface Int32Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number)[]; } +/** + * Int32Rules describes the constraints applied to `int32` values + */ export interface Int32Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number)[]; } diff --git a/packages/grpc-js/src/generated/validate/Int64Rules.ts b/packages/grpc-js/src/generated/validate/Int64Rules.ts index 91551365a..cb167c960 100644 --- a/packages/grpc-js/src/generated/validate/Int64Rules.ts +++ b/packages/grpc-js/src/generated/validate/Int64Rules.ts @@ -2,22 +2,86 @@ import { Long } from '@grpc/proto-loader'; +/** + * Int64Rules describes the constraints applied to `int64` values + */ export interface Int64Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string | Long); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string | Long); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string | Long); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string | Long); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string | Long); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string | Long)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string | Long)[]; } +/** + * Int64Rules describes the constraints applied to `int64` values + */ export interface Int64Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (string)[]; } diff --git a/packages/grpc-js/src/generated/validate/KnownRegex.ts b/packages/grpc-js/src/generated/validate/KnownRegex.ts index 68938449e..5880b5baf 100644 --- a/packages/grpc-js/src/generated/validate/KnownRegex.ts +++ b/packages/grpc-js/src/generated/validate/KnownRegex.ts @@ -1,7 +1,16 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * WellKnownRegex contain some well-known patterns. + */ export enum KnownRegex { UNKNOWN = 0, + /** + * HTTP header name as defined by RFC 7230. + */ HTTP_HEADER_NAME = 1, + /** + * HTTP header value as defined by RFC 7230. + */ HTTP_HEADER_VALUE = 2, } diff --git a/packages/grpc-js/src/generated/validate/MapRules.ts b/packages/grpc-js/src/generated/validate/MapRules.ts index 159c9bc07..5ebe1836d 100644 --- a/packages/grpc-js/src/generated/validate/MapRules.ts +++ b/packages/grpc-js/src/generated/validate/MapRules.ts @@ -3,18 +3,64 @@ import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; import { Long } from '@grpc/proto-loader'; +/** + * MapRules describe the constraints applied to `map` values + */ export interface MapRules { + /** + * MinPairs specifies that this field must have the specified number of + * KVs at a minimum + */ 'min_pairs'?: (number | string | Long); + /** + * MaxPairs specifies that this field must have the specified number of + * KVs at a maximum + */ 'max_pairs'?: (number | string | Long); + /** + * NoSparse specifies values in this field cannot be unset. This only + * applies to map's with message value types. + */ 'no_sparse'?: (boolean); + /** + * Keys specifies the constraints to be applied to each key in the field. + */ 'keys'?: (_validate_FieldRules); + /** + * Values specifies the constraints to be applied to the value of each key + * in the field. Message values will still have their validations evaluated + * unless skip is specified here. + */ 'values'?: (_validate_FieldRules); } +/** + * MapRules describe the constraints applied to `map` values + */ export interface MapRules__Output { + /** + * MinPairs specifies that this field must have the specified number of + * KVs at a minimum + */ 'min_pairs': (string); + /** + * MaxPairs specifies that this field must have the specified number of + * KVs at a maximum + */ 'max_pairs': (string); + /** + * NoSparse specifies values in this field cannot be unset. This only + * applies to map's with message value types. + */ 'no_sparse': (boolean); + /** + * Keys specifies the constraints to be applied to each key in the field. + */ 'keys': (_validate_FieldRules__Output); + /** + * Values specifies the constraints to be applied to the value of each key + * in the field. Message values will still have their validations evaluated + * unless skip is specified here. + */ 'values': (_validate_FieldRules__Output); } diff --git a/packages/grpc-js/src/generated/validate/MessageRules.ts b/packages/grpc-js/src/generated/validate/MessageRules.ts index 9229b1940..d22a85c63 100644 --- a/packages/grpc-js/src/generated/validate/MessageRules.ts +++ b/packages/grpc-js/src/generated/validate/MessageRules.ts @@ -1,12 +1,34 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export interface MessageRules { + /** + * Skip specifies that the validation rules of this field should not be + * evaluated + */ 'skip'?: (boolean); + /** + * Required specifies that this field must be set + */ 'required'?: (boolean); } +/** + * MessageRules describe the constraints applied to embedded message values. + * For message-type fields, validation is performed recursively. + */ export interface MessageRules__Output { + /** + * Skip specifies that the validation rules of this field should not be + * evaluated + */ 'skip': (boolean); + /** + * Required specifies that this field must be set + */ 'required': (boolean); } diff --git a/packages/grpc-js/src/generated/validate/RepeatedRules.ts b/packages/grpc-js/src/generated/validate/RepeatedRules.ts index 3b41cd1ee..921c80dba 100644 --- a/packages/grpc-js/src/generated/validate/RepeatedRules.ts +++ b/packages/grpc-js/src/generated/validate/RepeatedRules.ts @@ -3,16 +3,58 @@ import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; import { Long } from '@grpc/proto-loader'; +/** + * RepeatedRules describe the constraints applied to `repeated` values + */ export interface RepeatedRules { + /** + * MinItems specifies that this field must have the specified number of + * items at a minimum + */ 'min_items'?: (number | string | Long); + /** + * MaxItems specifies that this field must have the specified number of + * items at a maximum + */ 'max_items'?: (number | string | Long); + /** + * Unique specifies that all elements in this field must be unique. This + * contraint is only applicable to scalar and enum types (messages are not + * supported). + */ 'unique'?: (boolean); + /** + * Items specifies the contraints to be applied to each item in the field. + * Repeated message fields will still execute validation against each item + * unless skip is specified here. + */ 'items'?: (_validate_FieldRules); } +/** + * RepeatedRules describe the constraints applied to `repeated` values + */ export interface RepeatedRules__Output { + /** + * MinItems specifies that this field must have the specified number of + * items at a minimum + */ 'min_items': (string); + /** + * MaxItems specifies that this field must have the specified number of + * items at a maximum + */ 'max_items': (string); + /** + * Unique specifies that all elements in this field must be unique. This + * contraint is only applicable to scalar and enum types (messages are not + * supported). + */ 'unique': (boolean); + /** + * Items specifies the contraints to be applied to each item in the field. + * Repeated message fields will still execute validation against each item + * unless skip is specified here. + */ 'items': (_validate_FieldRules__Output); } diff --git a/packages/grpc-js/src/generated/validate/SFixed32Rules.ts b/packages/grpc-js/src/generated/validate/SFixed32Rules.ts index 55f2e695a..892e8f018 100644 --- a/packages/grpc-js/src/generated/validate/SFixed32Rules.ts +++ b/packages/grpc-js/src/generated/validate/SFixed32Rules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export interface SFixed32Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number)[]; } +/** + * SFixed32Rules describes the constraints applied to `sfixed32` values + */ export interface SFixed32Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number)[]; } diff --git a/packages/grpc-js/src/generated/validate/SFixed64Rules.ts b/packages/grpc-js/src/generated/validate/SFixed64Rules.ts index 262d98418..ccd5be954 100644 --- a/packages/grpc-js/src/generated/validate/SFixed64Rules.ts +++ b/packages/grpc-js/src/generated/validate/SFixed64Rules.ts @@ -2,22 +2,86 @@ import { Long } from '@grpc/proto-loader'; +/** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export interface SFixed64Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string | Long); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string | Long); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string | Long); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string | Long); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string | Long); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string | Long)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string | Long)[]; } +/** + * SFixed64Rules describes the constraints applied to `sfixed64` values + */ export interface SFixed64Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (string)[]; } diff --git a/packages/grpc-js/src/generated/validate/SInt32Rules.ts b/packages/grpc-js/src/generated/validate/SInt32Rules.ts index 9acd90794..744d067fc 100644 --- a/packages/grpc-js/src/generated/validate/SInt32Rules.ts +++ b/packages/grpc-js/src/generated/validate/SInt32Rules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * SInt32Rules describes the constraints applied to `sint32` values + */ export interface SInt32Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number)[]; } +/** + * SInt32Rules describes the constraints applied to `sint32` values + */ export interface SInt32Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number)[]; } diff --git a/packages/grpc-js/src/generated/validate/SInt64Rules.ts b/packages/grpc-js/src/generated/validate/SInt64Rules.ts index c85200031..61b3dd35f 100644 --- a/packages/grpc-js/src/generated/validate/SInt64Rules.ts +++ b/packages/grpc-js/src/generated/validate/SInt64Rules.ts @@ -2,22 +2,86 @@ import { Long } from '@grpc/proto-loader'; +/** + * SInt64Rules describes the constraints applied to `sint64` values + */ export interface SInt64Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string | Long); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string | Long); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string | Long); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string | Long); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string | Long); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string | Long)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string | Long)[]; } +/** + * SInt64Rules describes the constraints applied to `sint64` values + */ export interface SInt64Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (string)[]; } diff --git a/packages/grpc-js/src/generated/validate/StringRules.ts b/packages/grpc-js/src/generated/validate/StringRules.ts index 810697f57..83d0b8e48 100644 --- a/packages/grpc-js/src/generated/validate/StringRules.ts +++ b/packages/grpc-js/src/generated/validate/StringRules.ts @@ -3,60 +3,286 @@ import { KnownRegex as _validate_KnownRegex } from '../validate/KnownRegex'; import { Long } from '@grpc/proto-loader'; +/** + * StringRules describe the constraints applied to `string` values + */ export interface StringRules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (string); + /** + * MinLen specifies that this field must be the specified number of + * characters (Unicode code points) at a minimum. Note that the number of + * characters may differ from the number of bytes in the string. + */ 'min_len'?: (number | string | Long); + /** + * MaxLen specifies that this field must be the specified number of + * characters (Unicode code points) at a maximum. Note that the number of + * characters may differ from the number of bytes in the string. + */ 'max_len'?: (number | string | Long); + /** + * MinBytes specifies that this field must be the specified number of bytes + * at a minimum + */ 'min_bytes'?: (number | string | Long); + /** + * MaxBytes specifies that this field must be the specified number of bytes + * at a maximum + */ 'max_bytes'?: (number | string | Long); + /** + * Pattern specifes that this field must match against the specified + * regular expression (RE2 syntax). The included expression should elide + * any delimiters. + */ 'pattern'?: (string); + /** + * Prefix specifies that this field must have the specified substring at + * the beginning of the string. + */ 'prefix'?: (string); + /** + * Suffix specifies that this field must have the specified substring at + * the end of the string. + */ 'suffix'?: (string); + /** + * Contains specifies that this field must have the specified substring + * anywhere in the string. + */ 'contains'?: (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (string)[]; + /** + * Email specifies that the field must be a valid email address as + * defined by RFC 5322 + */ 'email'?: (boolean); + /** + * Hostname specifies that the field must be a valid hostname as + * defined by RFC 1034. This constraint does not support + * internationalized domain names (IDNs). + */ 'hostname'?: (boolean); + /** + * Ip specifies that the field must be a valid IP (v4 or v6) address. + * Valid IPv6 addresses should not include surrounding square brackets. + */ 'ip'?: (boolean); + /** + * Ipv4 specifies that the field must be a valid IPv4 address. + */ 'ipv4'?: (boolean); + /** + * Ipv6 specifies that the field must be a valid IPv6 address. Valid + * IPv6 addresses should not include surrounding square brackets. + */ 'ipv6'?: (boolean); + /** + * Uri specifies that the field must be a valid, absolute URI as defined + * by RFC 3986 + */ 'uri'?: (boolean); + /** + * UriRef specifies that the field must be a valid URI as defined by RFC + * 3986 and may be relative or absolute. + */ 'uri_ref'?: (boolean); + /** + * Len specifies that this field must be the specified number of + * characters (Unicode code points). Note that the number of + * characters may differ from the number of bytes in the string. + */ 'len'?: (number | string | Long); + /** + * LenBytes specifies that this field must be the specified number of bytes + * at a minimum + */ 'len_bytes'?: (number | string | Long); + /** + * Address specifies that the field must be either a valid hostname as + * defined by RFC 1034 (which does not support internationalized domain + * names or IDNs), or it can be a valid IP (v4 or v6). + */ 'address'?: (boolean); + /** + * Uuid specifies that the field must be a valid UUID as defined by + * RFC 4122 + */ 'uuid'?: (boolean); + /** + * NotContains specifies that this field cannot have the specified substring + * anywhere in the string. + */ 'not_contains'?: (string); + /** + * WellKnownRegex specifies a common well known pattern defined as a regex. + */ 'well_known_regex'?: (_validate_KnownRegex | keyof typeof _validate_KnownRegex); + /** + * This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable + * strict header validation. + * By default, this is true, and HTTP header validations are RFC-compliant. + * Setting to false will enable a looser validations that only disallows + * \r\n\0 characters, which can be used to bypass header matching rules. + */ 'strict'?: (boolean); + /** + * WellKnown rules provide advanced constraints against common string + * patterns + */ 'well_known'?: "email"|"hostname"|"ip"|"ipv4"|"ipv6"|"uri"|"uri_ref"|"address"|"uuid"|"well_known_regex"; } +/** + * StringRules describe the constraints applied to `string` values + */ export interface StringRules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (string); + /** + * MinLen specifies that this field must be the specified number of + * characters (Unicode code points) at a minimum. Note that the number of + * characters may differ from the number of bytes in the string. + */ 'min_len': (string); + /** + * MaxLen specifies that this field must be the specified number of + * characters (Unicode code points) at a maximum. Note that the number of + * characters may differ from the number of bytes in the string. + */ 'max_len': (string); + /** + * MinBytes specifies that this field must be the specified number of bytes + * at a minimum + */ 'min_bytes': (string); + /** + * MaxBytes specifies that this field must be the specified number of bytes + * at a maximum + */ 'max_bytes': (string); + /** + * Pattern specifes that this field must match against the specified + * regular expression (RE2 syntax). The included expression should elide + * any delimiters. + */ 'pattern': (string); + /** + * Prefix specifies that this field must have the specified substring at + * the beginning of the string. + */ 'prefix': (string); + /** + * Suffix specifies that this field must have the specified substring at + * the end of the string. + */ 'suffix': (string); + /** + * Contains specifies that this field must have the specified substring + * anywhere in the string. + */ 'contains': (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (string)[]; + /** + * Email specifies that the field must be a valid email address as + * defined by RFC 5322 + */ 'email'?: (boolean); + /** + * Hostname specifies that the field must be a valid hostname as + * defined by RFC 1034. This constraint does not support + * internationalized domain names (IDNs). + */ 'hostname'?: (boolean); + /** + * Ip specifies that the field must be a valid IP (v4 or v6) address. + * Valid IPv6 addresses should not include surrounding square brackets. + */ 'ip'?: (boolean); + /** + * Ipv4 specifies that the field must be a valid IPv4 address. + */ 'ipv4'?: (boolean); + /** + * Ipv6 specifies that the field must be a valid IPv6 address. Valid + * IPv6 addresses should not include surrounding square brackets. + */ 'ipv6'?: (boolean); + /** + * Uri specifies that the field must be a valid, absolute URI as defined + * by RFC 3986 + */ 'uri'?: (boolean); + /** + * UriRef specifies that the field must be a valid URI as defined by RFC + * 3986 and may be relative or absolute. + */ 'uri_ref'?: (boolean); + /** + * Len specifies that this field must be the specified number of + * characters (Unicode code points). Note that the number of + * characters may differ from the number of bytes in the string. + */ 'len': (string); + /** + * LenBytes specifies that this field must be the specified number of bytes + * at a minimum + */ 'len_bytes': (string); + /** + * Address specifies that the field must be either a valid hostname as + * defined by RFC 1034 (which does not support internationalized domain + * names or IDNs), or it can be a valid IP (v4 or v6). + */ 'address'?: (boolean); + /** + * Uuid specifies that the field must be a valid UUID as defined by + * RFC 4122 + */ 'uuid'?: (boolean); + /** + * NotContains specifies that this field cannot have the specified substring + * anywhere in the string. + */ 'not_contains': (string); + /** + * WellKnownRegex specifies a common well known pattern defined as a regex. + */ 'well_known_regex'?: (keyof typeof _validate_KnownRegex); + /** + * This applies to regexes HTTP_HEADER_NAME and HTTP_HEADER_VALUE to enable + * strict header validation. + * By default, this is true, and HTTP header validations are RFC-compliant. + * Setting to false will enable a looser validations that only disallows + * \r\n\0 characters, which can be used to bypass header matching rules. + */ 'strict': (boolean); + /** + * WellKnown rules provide advanced constraints against common string + * patterns + */ 'well_known': "email"|"hostname"|"ip"|"ipv4"|"ipv6"|"uri"|"uri_ref"|"address"|"uuid"|"well_known_regex"; } diff --git a/packages/grpc-js/src/generated/validate/TimestampRules.ts b/packages/grpc-js/src/generated/validate/TimestampRules.ts index 63a6ba4f2..598e05770 100644 --- a/packages/grpc-js/src/generated/validate/TimestampRules.ts +++ b/packages/grpc-js/src/generated/validate/TimestampRules.ts @@ -3,26 +3,104 @@ import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../google/protobuf/Timestamp'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; +/** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export interface TimestampRules { + /** + * Required specifies that this field must be set + */ 'required'?: (boolean); + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (_google_protobuf_Timestamp); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (_google_protobuf_Timestamp); + /** + * Lte specifies that this field must be less than the specified value, + * inclusive + */ 'lte'?: (_google_protobuf_Timestamp); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive + */ 'gt'?: (_google_protobuf_Timestamp); + /** + * Gte specifies that this field must be greater than the specified value, + * inclusive + */ 'gte'?: (_google_protobuf_Timestamp); + /** + * LtNow specifies that this must be less than the current time. LtNow + * can only be used with the Within rule. + */ 'lt_now'?: (boolean); + /** + * GtNow specifies that this must be greater than the current time. GtNow + * can only be used with the Within rule. + */ 'gt_now'?: (boolean); + /** + * Within specifies that this field must be within this duration of the + * current time. This constraint can be used alone or with the LtNow and + * GtNow rules. + */ 'within'?: (_google_protobuf_Duration); } +/** + * TimestampRules describe the constraints applied exclusively to the + * `google.protobuf.Timestamp` well-known type + */ export interface TimestampRules__Output { + /** + * Required specifies that this field must be set + */ 'required': (boolean); + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (_google_protobuf_Timestamp__Output); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (_google_protobuf_Timestamp__Output); + /** + * Lte specifies that this field must be less than the specified value, + * inclusive + */ 'lte': (_google_protobuf_Timestamp__Output); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive + */ 'gt': (_google_protobuf_Timestamp__Output); + /** + * Gte specifies that this field must be greater than the specified value, + * inclusive + */ 'gte': (_google_protobuf_Timestamp__Output); + /** + * LtNow specifies that this must be less than the current time. LtNow + * can only be used with the Within rule. + */ 'lt_now': (boolean); + /** + * GtNow specifies that this must be greater than the current time. GtNow + * can only be used with the Within rule. + */ 'gt_now': (boolean); + /** + * Within specifies that this field must be within this duration of the + * current time. This constraint can be used alone or with the LtNow and + * GtNow rules. + */ 'within': (_google_protobuf_Duration__Output); } diff --git a/packages/grpc-js/src/generated/validate/UInt32Rules.ts b/packages/grpc-js/src/generated/validate/UInt32Rules.ts index bc12fe5ce..61873da2f 100644 --- a/packages/grpc-js/src/generated/validate/UInt32Rules.ts +++ b/packages/grpc-js/src/generated/validate/UInt32Rules.ts @@ -1,22 +1,86 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto +/** + * UInt32Rules describes the constraints applied to `uint32` values + */ export interface UInt32Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number)[]; } +/** + * UInt32Rules describes the constraints applied to `uint32` values + */ export interface UInt32Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (number); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (number); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (number); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (number); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (number); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (number)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (number)[]; } diff --git a/packages/grpc-js/src/generated/validate/UInt64Rules.ts b/packages/grpc-js/src/generated/validate/UInt64Rules.ts index 3c8a81ce9..263431ad7 100644 --- a/packages/grpc-js/src/generated/validate/UInt64Rules.ts +++ b/packages/grpc-js/src/generated/validate/UInt64Rules.ts @@ -2,22 +2,86 @@ import { Long } from '@grpc/proto-loader'; +/** + * UInt64Rules describes the constraints applied to `uint64` values + */ export interface UInt64Rules { + /** + * Const specifies that this field must be exactly the specified value + */ 'const'?: (number | string | Long); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt'?: (number | string | Long); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte'?: (number | string | Long); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt'?: (number | string | Long); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte'?: (number | string | Long); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in'?: (number | string | Long)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in'?: (number | string | Long)[]; } +/** + * UInt64Rules describes the constraints applied to `uint64` values + */ export interface UInt64Rules__Output { + /** + * Const specifies that this field must be exactly the specified value + */ 'const': (string); + /** + * Lt specifies that this field must be less than the specified value, + * exclusive + */ 'lt': (string); + /** + * Lte specifies that this field must be less than or equal to the + * specified value, inclusive + */ 'lte': (string); + /** + * Gt specifies that this field must be greater than the specified value, + * exclusive. If the value of Gt is larger than a specified Lt or Lte, the + * range is reversed. + */ 'gt': (string); + /** + * Gte specifies that this field must be greater than or equal to the + * specified value, inclusive. If the value of Gte is larger than a + * specified Lt or Lte, the range is reversed. + */ 'gte': (string); + /** + * In specifies that this field must be equal to one of the specified + * values + */ 'in': (string)[]; + /** + * NotIn specifies that this field cannot be equal to one of the specified + * values + */ 'not_in': (string)[]; } From f91c837058af8cabba396cfd589ab53ded7743ce Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Jul 2020 13:02:47 -0700 Subject: [PATCH 1154/1899] Update generated code with separate service files --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/generated/ads.ts | 1411 +------- packages/grpc-js/src/generated/cluster.ts | 2604 -------------- packages/grpc-js/src/generated/endpoint.ts | 2099 ----------- .../src/generated/envoy/api/v2/Cluster.ts | 182 +- .../envoy/api/v2/ClusterLoadAssignment.ts | 56 +- .../src/generated/envoy/api/v2/Listener.ts | 44 +- .../envoy/api/v2/cluster/CircuitBreakers.ts | 72 +- .../envoy/api/v2/core/GrpcService.ts | 334 +- .../envoy/api/v2/core/HealthCheck.ts | 4 +- .../envoy/api/v2/route/RouteAction.ts | 224 +- .../v2/AggregatedDiscoveryService.ts | 52 + packages/grpc-js/src/generated/listener.ts | 3179 ----------------- packages/grpc-js/src/generated/route.ts | 2026 ----------- packages/grpc-js/src/xds-bootstrap.ts | 14 +- packages/grpc-js/src/xds-client.ts | 32 +- 16 files changed, 539 insertions(+), 11796 deletions(-) create mode 100644 packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e1b380ba1..7080270e2 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -47,7 +47,7 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --generateComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/generated/ads.ts b/packages/grpc-js/src/generated/ads.ts index 369b6b8c1..a33270cc6 100644 --- a/packages/grpc-js/src/generated/ads.ts +++ b/packages/grpc-js/src/generated/ads.ts @@ -1,1159 +1,7 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from './envoy/api/v2/DeltaDiscoveryRequest'; -import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from './envoy/api/v2/DeltaDiscoveryResponse'; -import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from './envoy/api/v2/DiscoveryRequest'; -import { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from './envoy/api/v2/DiscoveryResponse'; -import { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from './envoy/api/v2/Resource'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; -import { AdsDummy as _envoy_service_discovery_v2_AdsDummy, AdsDummy__Output as _envoy_service_discovery_v2_AdsDummy__Output } from './envoy/service/discovery/v2/AdsDummy'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from './google/rpc/Status'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; - -export namespace messages { - export namespace envoy { - export namespace api { - export namespace v2 { - /** - * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC - * endpoint for Delta xDS. - * - * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full - * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a - * diff to the state of a xDS client. - * In Delta XDS there are per-resource versions, which allow tracking state at - * the resource granularity. - * An xDS Delta session is always in the context of a gRPC bidirectional - * stream. This allows the xDS server to keep track of the state of xDS clients - * connected to it. - * - * In Delta xDS the nonce field is required and used to pair - * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. - * Optionally, a response message level system_version_info is present for - * debugging purposes only. - * - * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest - * can be either or both of: [1] informing the server of what resources the - * client has gained/lost interest in (using resource_names_subscribe and - * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from - * the server (using response_nonce, with presence of error_detail making it a NACK). - * Additionally, the first message (for a given type_url) of a reconnected gRPC stream - * has a third role: informing the server of the resources (and their versions) - * that the client already possesses, using the initial_resource_versions field. - * - * As with state-of-the-world, when multiple resource types are multiplexed (ADS), - * all requests/acknowledgments/updates are logically walled off by type_url: - * a Cluster ACK exists in a completely separate world from a prior Route NACK. - * In particular, initial_resource_versions being sent at the "start" of every - * gRPC stream actually entails a message for each type_url, each with its own - * initial_resource_versions. - * [#next-free-field: 8] - */ - export type DeltaDiscoveryRequest = _envoy_api_v2_DeltaDiscoveryRequest; - /** - * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC - * endpoint for Delta xDS. - * - * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full - * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a - * diff to the state of a xDS client. - * In Delta XDS there are per-resource versions, which allow tracking state at - * the resource granularity. - * An xDS Delta session is always in the context of a gRPC bidirectional - * stream. This allows the xDS server to keep track of the state of xDS clients - * connected to it. - * - * In Delta xDS the nonce field is required and used to pair - * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. - * Optionally, a response message level system_version_info is present for - * debugging purposes only. - * - * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest - * can be either or both of: [1] informing the server of what resources the - * client has gained/lost interest in (using resource_names_subscribe and - * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from - * the server (using response_nonce, with presence of error_detail making it a NACK). - * Additionally, the first message (for a given type_url) of a reconnected gRPC stream - * has a third role: informing the server of the resources (and their versions) - * that the client already possesses, using the initial_resource_versions field. - * - * As with state-of-the-world, when multiple resource types are multiplexed (ADS), - * all requests/acknowledgments/updates are logically walled off by type_url: - * a Cluster ACK exists in a completely separate world from a prior Route NACK. - * In particular, initial_resource_versions being sent at the "start" of every - * gRPC stream actually entails a message for each type_url, each with its own - * initial_resource_versions. - * [#next-free-field: 8] - */ - export type DeltaDiscoveryRequest__Output = _envoy_api_v2_DeltaDiscoveryRequest__Output; - /** - * [#next-free-field: 7] - */ - export type DeltaDiscoveryResponse = _envoy_api_v2_DeltaDiscoveryResponse; - /** - * [#next-free-field: 7] - */ - export type DeltaDiscoveryResponse__Output = _envoy_api_v2_DeltaDiscoveryResponse__Output; - /** - * A DiscoveryRequest requests a set of versioned resources of the same type for - * a given Envoy node on some API. - * [#next-free-field: 7] - */ - export type DiscoveryRequest = _envoy_api_v2_DiscoveryRequest; - /** - * A DiscoveryRequest requests a set of versioned resources of the same type for - * a given Envoy node on some API. - * [#next-free-field: 7] - */ - export type DiscoveryRequest__Output = _envoy_api_v2_DiscoveryRequest__Output; - /** - * [#next-free-field: 7] - */ - export type DiscoveryResponse = _envoy_api_v2_DiscoveryResponse; - /** - * [#next-free-field: 7] - */ - export type DiscoveryResponse__Output = _envoy_api_v2_DiscoveryResponse__Output; - export type Resource = _envoy_api_v2_Resource; - export type Resource__Output = _envoy_api_v2_Resource__Output; - export namespace core { - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address = _envoy_api_v2_core_Address; - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address__Output = _envoy_api_v2_core_Address__Output; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion = _envoy_api_v2_core_BuildVersion; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange = _envoy_api_v2_core_CidrRange; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource = _envoy_api_v2_core_DataSource; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension = _envoy_api_v2_core_Extension; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension__Output = _envoy_api_v2_core_Extension__Output; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - /** - * Header name/value pair. - */ - export type HeaderValue = _envoy_api_v2_core_HeaderValue; - /** - * Header name/value pair. - */ - export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - /** - * Envoy external URI descriptor - */ - export type HttpUri = _envoy_api_v2_core_HttpUri; - /** - * Envoy external URI descriptor - */ - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality = _envoy_api_v2_core_Locality; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality__Output = _envoy_api_v2_core_Locality__Output; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata = _envoy_api_v2_core_Metadata; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node = _envoy_api_v2_core_Node; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - /** - * HTTP request method. - */ - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; - /** - * Envoy supports :ref:`upstream priority routing - * ` both at the route and the virtual - * cluster level. The current priority implementation uses different connection - * pool and circuit breaking settings for each priority level. This means that - * even for HTTP/2 requests, two physical connections will be used to an - * upstream host. In the future Envoy will likely support true HTTP/2 priority - * over a single upstream connection. - */ - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - /** - * [#next-free-field: 7] - */ - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - /** - * [#next-free-field: 7] - */ - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption = _envoy_api_v2_core_SocketOption; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - /** - * Identifies the direction of the traffic relative to the local Envoy. - */ - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; - } - } - } - export namespace service { - export namespace discovery { - export namespace v2 { - /** - * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing - * services: https://github.com/google/protobuf/issues/4221 - */ - export type AdsDummy = _envoy_service_discovery_v2_AdsDummy; - /** - * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing - * services: https://github.com/google/protobuf/issues/4221 - */ - export type AdsDummy__Output = _envoy_service_discovery_v2_AdsDummy__Output; - export namespace AggregatedDiscoveryService { - } - } - } - } - export namespace type { - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent = _envoy_type_FractionalPercent; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent = _envoy_type_Percent; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent__Output = _envoy_type_Percent__Output; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion = _envoy_type_SemanticVersion; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - } - } - export namespace google { - export namespace protobuf { - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type BoolValue = _google_protobuf_BoolValue; - export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type BytesValue = _google_protobuf_BytesValue; - export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type DescriptorProto = _google_protobuf_DescriptorProto; - export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; - export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; - export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileOptions = _google_protobuf_FileOptions; - export type FileOptions__Output = _google_protobuf_FileOptions__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type MessageOptions = _google_protobuf_MessageOptions; - export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type NullValue = _google_protobuf_NullValue; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; - export type OneofOptions = _google_protobuf_OneofOptions; - export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type ServiceOptions = _google_protobuf_ServiceOptions; - export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; - export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - } - export namespace rpc { - /** - * The `Status` type defines a logical error model that is suitable for - * different programming environments, including REST APIs and RPC APIs. It is - * used by [gRPC](https://github.com/grpc). Each `Status` message contains - * three pieces of data: error code, error message, and error details. - * - * You can find out more about this error model and how to work with it in the - * [API Design Guide](https://cloud.google.com/apis/design/errors). - */ - export type Status = _google_rpc_Status; - /** - * The `Status` type defines a logical error model that is suitable for - * different programming environments, including REST APIs and RPC APIs. It is - * used by [gRPC](https://github.com/grpc). Each `Status` message contains - * three pieces of data: error code, error message, and error details. - * - * You can find out more about this error model and how to work with it in the - * [API Design Guide](https://cloud.google.com/apis/design/errors). - */ - export type Status__Output = _google_rpc_Status__Output; - } - } - export namespace udpa { - export namespace annotations { - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules = _validate_AnyRules; - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules__Output = _validate_AnyRules__Output; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules = _validate_BoolRules; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules__Output = _validate_BoolRules__Output; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules = _validate_BytesRules; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules__Output = _validate_BytesRules__Output; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules = _validate_DoubleRules; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules__Output = _validate_DoubleRules__Output; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules = _validate_DurationRules; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules__Output = _validate_DurationRules__Output; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules = _validate_EnumRules; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules__Output = _validate_EnumRules__Output; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules = _validate_FieldRules; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules__Output = _validate_FieldRules__Output; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules = _validate_Fixed32Rules; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules = _validate_Fixed64Rules; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules = _validate_FloatRules; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules__Output = _validate_FloatRules__Output; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules = _validate_Int32Rules; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules__Output = _validate_Int32Rules__Output; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules = _validate_Int64Rules; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules__Output = _validate_Int64Rules__Output; - /** - * WellKnownRegex contain some well-known patterns. - */ - export type KnownRegex = _validate_KnownRegex; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules = _validate_MapRules; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules__Output = _validate_MapRules__Output; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules = _validate_MessageRules; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules__Output = _validate_MessageRules__Output; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules = _validate_RepeatedRules; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules = _validate_SFixed32Rules; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules = _validate_SFixed64Rules; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules = _validate_SInt32Rules; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules = _validate_SInt64Rules; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules = _validate_StringRules; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules__Output = _validate_StringRules__Output; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules = _validate_TimestampRules; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules__Output = _validate_TimestampRules__Output; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules = _validate_UInt32Rules; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules = _validate_UInt64Rules; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - } -} - -export namespace ClientInterfaces { - export namespace envoy { - export namespace api { - export namespace v2 { - export namespace DeltaDiscoveryRequest { - } - export namespace DeltaDiscoveryResponse { - } - export namespace DiscoveryRequest { - } - export namespace DiscoveryResponse { - } - export namespace Resource { - } - export namespace core { - export namespace Address { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace Extension { - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - } - } - export namespace service { - export namespace discovery { - export namespace v2 { - export namespace AdsDummy { - } - /** - * See https://github.com/lyft/envoy-api#apis for a description of the role of - * ADS and how it is intended to be used by a management server. ADS requests - * have the same structure as their singleton xDS counterparts, but can - * multiplex many resource types on a single stream. The type_url in the - * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover - * the multiplexed singleton APIs at the Envoy instance and management server. - */ - export interface AggregatedDiscoveryServiceClient extends grpc.Client { - DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - - /** - * This is a gRPC-only API. - */ - StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - /** - * This is a gRPC-only API. - */ - streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; - streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream; - - } - } - } - } - export namespace type { - export namespace FractionalPercent { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - } - } - export namespace google { - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - export namespace rpc { - export namespace Status { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} +import { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { @@ -1215,7 +63,7 @@ export interface ProtoGrpcType { * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover * the multiplexed singleton APIs at the Envoy instance and management server. */ - AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } + AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } } } } @@ -1305,258 +153,3 @@ export interface ProtoGrpcType { } } -export namespace ServiceHandlers { - export namespace envoy { - export namespace api { - export namespace v2 { - export namespace DeltaDiscoveryRequest { - } - export namespace DeltaDiscoveryResponse { - } - export namespace DiscoveryRequest { - } - export namespace DiscoveryResponse { - } - export namespace Resource { - } - export namespace core { - export namespace Address { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace Extension { - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - } - } - export namespace service { - export namespace discovery { - export namespace v2 { - export namespace AdsDummy { - } - /** - * See https://github.com/lyft/envoy-api#apis for a description of the role of - * ADS and how it is intended to be used by a management server. ADS requests - * have the same structure as their singleton xDS counterparts, but can - * multiplex many resource types on a single stream. The type_url in the - * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover - * the multiplexed singleton APIs at the Envoy instance and management server. - */ - export interface AggregatedDiscoveryService { - DeltaAggregatedResources(call: grpc.ServerDuplexStream): void; - - /** - * This is a gRPC-only API. - */ - StreamAggregatedResources(call: grpc.ServerDuplexStream): void; - - } - } - } - } - export namespace type { - export namespace FractionalPercent { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - } - } - export namespace google { - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - export namespace rpc { - export namespace Status { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} diff --git a/packages/grpc-js/src/generated/cluster.ts b/packages/grpc-js/src/generated/cluster.ts index bf6f37bfc..7d2b34a43 100644 --- a/packages/grpc-js/src/generated/cluster.ts +++ b/packages/grpc-js/src/generated/cluster.ts @@ -1,2206 +1,6 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { Cluster as _envoy_api_v2_Cluster, Cluster__Output as _envoy_api_v2_Cluster__Output } from './envoy/api/v2/Cluster'; -import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; -import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from './envoy/api/v2/LoadBalancingPolicy'; -import { UpstreamBindConfig as _envoy_api_v2_UpstreamBindConfig, UpstreamBindConfig__Output as _envoy_api_v2_UpstreamBindConfig__Output } from './envoy/api/v2/UpstreamBindConfig'; -import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from './envoy/api/v2/UpstreamConnectionOptions'; -import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; -import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; -import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; -import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; -import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; -import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; -import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; -import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; -import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; -import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; -import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from './envoy/api/v2/cluster/CircuitBreakers'; -import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from './envoy/api/v2/cluster/Filter'; -import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from './envoy/api/v2/cluster/OutlierDetection'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; -import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { GrpcProtocolOptions as _envoy_api_v2_core_GrpcProtocolOptions, GrpcProtocolOptions__Output as _envoy_api_v2_core_GrpcProtocolOptions__Output } from './envoy/api/v2/core/GrpcProtocolOptions'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; -import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from './envoy/api/v2/core/Http1ProtocolOptions'; -import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from './envoy/api/v2/core/Http2ProtocolOptions'; -import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from './envoy/api/v2/core/HttpProtocolOptions'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { TcpProtocolOptions as _envoy_api_v2_core_TcpProtocolOptions, TcpProtocolOptions__Output as _envoy_api_v2_core_TcpProtocolOptions__Output } from './envoy/api/v2/core/TcpProtocolOptions'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; -import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from './envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; -import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; -import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; -import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; -import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; - -export namespace messages { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - /** - * Configuration for a single upstream cluster. - * [#next-free-field: 48] - */ - export type Cluster = _envoy_api_v2_Cluster; - /** - * Configuration for a single upstream cluster. - * [#next-free-field: 48] - */ - export type Cluster__Output = _envoy_api_v2_Cluster__Output; - /** - * Each route from RDS will map to a single cluster or traffic split across - * clusters using weights expressed in the RDS WeightedCluster. - * - * With EDS, each cluster is treated independently from a LB perspective, with - * LB taking place between the Localities within a cluster and at a finer - * granularity between the hosts within a locality. The percentage of traffic - * for each endpoint is determined by both its load_balancing_weight, and the - * load_balancing_weight of its locality. First, a locality will be selected, - * then an endpoint within that locality will be chose based on its weight. - * [#next-free-field: 6] - */ - export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; - /** - * Each route from RDS will map to a single cluster or traffic split across - * clusters using weights expressed in the RDS WeightedCluster. - * - * With EDS, each cluster is treated independently from a LB perspective, with - * LB taking place between the Localities within a cluster and at a finer - * granularity between the hosts within a locality. The percentage of traffic - * for each endpoint is determined by both its load_balancing_weight, and the - * load_balancing_weight of its locality. First, a locality will be selected, - * then an endpoint within that locality will be chose based on its weight. - * [#next-free-field: 6] - */ - export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; - /** - * [#not-implemented-hide:] Extensible load balancing policy configuration. - * - * Every LB policy defined via this mechanism will be identified via a unique name using reverse - * DNS notation. If the policy needs configuration parameters, it must define a message for its - * own configuration, which will be stored in the config field. The name of the policy will tell - * clients which type of message they should expect to see in the config field. - * - * Note that there are cases where it is useful to be able to independently select LB policies - * for choosing a locality and for choosing an endpoint within that locality. For example, a - * given deployment may always use the same policy to choose the locality, but for choosing the - * endpoint within the locality, some clusters may use weighted-round-robin, while others may - * use some sort of session-based balancing. - * - * This can be accomplished via hierarchical LB policies, where the parent LB policy creates a - * child LB policy for each locality. For each request, the parent chooses the locality and then - * delegates to the child policy for that locality to choose the endpoint within the locality. - * - * To facilitate this, the config message for the top-level LB policy may include a field of - * type LoadBalancingPolicy that specifies the child policy. - */ - export type LoadBalancingPolicy = _envoy_api_v2_LoadBalancingPolicy; - /** - * [#not-implemented-hide:] Extensible load balancing policy configuration. - * - * Every LB policy defined via this mechanism will be identified via a unique name using reverse - * DNS notation. If the policy needs configuration parameters, it must define a message for its - * own configuration, which will be stored in the config field. The name of the policy will tell - * clients which type of message they should expect to see in the config field. - * - * Note that there are cases where it is useful to be able to independently select LB policies - * for choosing a locality and for choosing an endpoint within that locality. For example, a - * given deployment may always use the same policy to choose the locality, but for choosing the - * endpoint within the locality, some clusters may use weighted-round-robin, while others may - * use some sort of session-based balancing. - * - * This can be accomplished via hierarchical LB policies, where the parent LB policy creates a - * child LB policy for each locality. For each request, the parent chooses the locality and then - * delegates to the child policy for that locality to choose the endpoint within the locality. - * - * To facilitate this, the config message for the top-level LB policy may include a field of - * type LoadBalancingPolicy that specifies the child policy. - */ - export type LoadBalancingPolicy__Output = _envoy_api_v2_LoadBalancingPolicy__Output; - /** - * An extensible structure containing the address Envoy should bind to when - * establishing upstream connections. - */ - export type UpstreamBindConfig = _envoy_api_v2_UpstreamBindConfig; - /** - * An extensible structure containing the address Envoy should bind to when - * establishing upstream connections. - */ - export type UpstreamBindConfig__Output = _envoy_api_v2_UpstreamBindConfig__Output; - export type UpstreamConnectionOptions = _envoy_api_v2_UpstreamConnectionOptions; - export type UpstreamConnectionOptions__Output = _envoy_api_v2_UpstreamConnectionOptions__Output; - export namespace auth { - /** - * [#next-free-field: 11] - */ - export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; - /** - * [#next-free-field: 11] - */ - export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; - /** - * TLS context shared by both client and server TLS contexts. - * [#next-free-field: 9] - */ - export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; - /** - * TLS context shared by both client and server TLS contexts. - * [#next-free-field: 9] - */ - export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; - /** - * [#next-free-field: 8] - */ - export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; - /** - * [#next-free-field: 8] - */ - export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; - export type GenericSecret = _envoy_api_v2_auth_GenericSecret; - export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; - /** - * BoringSSL private key method configuration. The private key methods are used for external - * (potentially asynchronous) signing and decryption operations. Some use cases for private key - * methods would be TPM support and TLS acceleration. - */ - export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; - /** - * BoringSSL private key method configuration. The private key methods are used for external - * (potentially asynchronous) signing and decryption operations. Some use cases for private key - * methods would be TPM support and TLS acceleration. - */ - export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; - export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; - export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; - /** - * [#next-free-field: 6] - */ - export type Secret = _envoy_api_v2_auth_Secret; - /** - * [#next-free-field: 6] - */ - export type Secret__Output = _envoy_api_v2_auth_Secret__Output; - /** - * [#next-free-field: 7] - */ - export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; - /** - * [#next-free-field: 7] - */ - export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; - export type TlsParameters = _envoy_api_v2_auth_TlsParameters; - export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; - export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; - export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; - export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; - export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; - } - export namespace cluster { - /** - * :ref:`Circuit breaking` settings can be - * specified individually for each defined priority. - */ - export type CircuitBreakers = _envoy_api_v2_cluster_CircuitBreakers; - /** - * :ref:`Circuit breaking` settings can be - * specified individually for each defined priority. - */ - export type CircuitBreakers__Output = _envoy_api_v2_cluster_CircuitBreakers__Output; - export type Filter = _envoy_api_v2_cluster_Filter; - export type Filter__Output = _envoy_api_v2_cluster_Filter__Output; - /** - * See the :ref:`architecture overview ` for - * more information on outlier detection. - * [#next-free-field: 21] - */ - export type OutlierDetection = _envoy_api_v2_cluster_OutlierDetection; - /** - * See the :ref:`architecture overview ` for - * more information on outlier detection. - * [#next-free-field: 21] - */ - export type OutlierDetection__Output = _envoy_api_v2_cluster_OutlierDetection__Output; - } - export namespace core { - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address = _envoy_api_v2_core_Address; - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address__Output = _envoy_api_v2_core_Address__Output; - /** - * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that ADS is to be used. - */ - export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; - /** - * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that ADS is to be used. - */ - export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; - /** - * API configuration source. This identifies the API type and cluster that Envoy - * will use to fetch an xDS API. - * [#next-free-field: 9] - */ - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - /** - * API configuration source. This identifies the API type and cluster that Envoy - * will use to fetch an xDS API. - * [#next-free-field: 9] - */ - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; - /** - * xDS API version. This is used to describe both resource and transport - * protocol versions (in distinct configuration fields). - */ - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion = _envoy_api_v2_core_BuildVersion; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange = _envoy_api_v2_core_CidrRange; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - /** - * Configuration for :ref:`listeners `, :ref:`clusters - * `, :ref:`routes - * `, :ref:`endpoints - * ` etc. may either be sourced from the - * filesystem or from an xDS API source. Filesystem configs are watched with - * inotify for updates. - * [#next-free-field: 7] - */ - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - /** - * Configuration for :ref:`listeners `, :ref:`clusters - * `, :ref:`routes - * `, :ref:`endpoints - * ` etc. may either be sourced from the - * filesystem or from an xDS API source. Filesystem configs are watched with - * inotify for updates. - * [#next-free-field: 7] - */ - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource = _envoy_api_v2_core_DataSource; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - /** - * [#not-implemented-hide:] - * Configuration of the event reporting service endpoint. - */ - export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; - /** - * [#not-implemented-hide:] - * Configuration of the event reporting service endpoint. - */ - export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension = _envoy_api_v2_core_Extension; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension__Output = _envoy_api_v2_core_Extension__Output; - /** - * [#not-implemented-hide:] - */ - export type GrpcProtocolOptions = _envoy_api_v2_core_GrpcProtocolOptions; - /** - * [#not-implemented-hide:] - */ - export type GrpcProtocolOptions__Output = _envoy_api_v2_core_GrpcProtocolOptions__Output; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService = _envoy_api_v2_core_GrpcService; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - /** - * Header name/value pair. - */ - export type HeaderValue = _envoy_api_v2_core_HeaderValue; - /** - * Header name/value pair. - */ - export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - /** - * [#next-free-field: 23] - */ - export type HealthCheck = _envoy_api_v2_core_HealthCheck; - /** - * [#next-free-field: 23] - */ - export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; - /** - * Endpoint health status. - */ - export type HealthStatus = _envoy_api_v2_core_HealthStatus; - /** - * [#next-free-field: 6] - */ - export type Http1ProtocolOptions = _envoy_api_v2_core_Http1ProtocolOptions; - /** - * [#next-free-field: 6] - */ - export type Http1ProtocolOptions__Output = _envoy_api_v2_core_Http1ProtocolOptions__Output; - /** - * [#next-free-field: 14] - */ - export type Http2ProtocolOptions = _envoy_api_v2_core_Http2ProtocolOptions; - /** - * [#next-free-field: 14] - */ - export type Http2ProtocolOptions__Output = _envoy_api_v2_core_Http2ProtocolOptions__Output; - /** - * [#next-free-field: 6] - */ - export type HttpProtocolOptions = _envoy_api_v2_core_HttpProtocolOptions; - /** - * [#next-free-field: 6] - */ - export type HttpProtocolOptions__Output = _envoy_api_v2_core_HttpProtocolOptions__Output; - /** - * Envoy external URI descriptor - */ - export type HttpUri = _envoy_api_v2_core_HttpUri; - /** - * Envoy external URI descriptor - */ - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality = _envoy_api_v2_core_Locality; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality__Output = _envoy_api_v2_core_Locality__Output; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata = _envoy_api_v2_core_Metadata; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node = _envoy_api_v2_core_Node; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - /** - * Rate Limit settings to be applied for discovery requests made by Envoy. - */ - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - /** - * Rate Limit settings to be applied for discovery requests made by Envoy. - */ - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - /** - * HTTP request method. - */ - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; - /** - * Envoy supports :ref:`upstream priority routing - * ` both at the route and the virtual - * cluster level. The current priority implementation uses different connection - * pool and circuit breaking settings for each priority level. This means that - * even for HTTP/2 requests, two physical connections will be used to an - * upstream host. In the future Envoy will likely support true HTTP/2 priority - * over a single upstream connection. - */ - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - /** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ - export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; - /** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ - export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - /** - * [#next-free-field: 7] - */ - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - /** - * [#next-free-field: 7] - */ - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption = _envoy_api_v2_core_SocketOption; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - /** - * [#not-implemented-hide:] - */ - export type TcpProtocolOptions = _envoy_api_v2_core_TcpProtocolOptions; - /** - * [#not-implemented-hide:] - */ - export type TcpProtocolOptions__Output = _envoy_api_v2_core_TcpProtocolOptions__Output; - /** - * Identifies the direction of the traffic relative to the local Envoy. - */ - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; - export type UpstreamHttpProtocolOptions = _envoy_api_v2_core_UpstreamHttpProtocolOptions; - export type UpstreamHttpProtocolOptions__Output = _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output; - } - export namespace endpoint { - /** - * Upstream host identifier. - */ - export type Endpoint = _envoy_api_v2_endpoint_Endpoint; - /** - * Upstream host identifier. - */ - export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; - /** - * An Endpoint that Envoy can route traffic to. - * [#next-free-field: 6] - */ - export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; - /** - * An Endpoint that Envoy can route traffic to. - * [#next-free-field: 6] - */ - export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; - /** - * A group of endpoints belonging to a Locality. - * One can have multiple LocalityLbEndpoints for a locality, but this is - * generally only done if the different groups need to have different load - * balancing weights or different priorities. - * [#next-free-field: 7] - */ - export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; - /** - * A group of endpoints belonging to a Locality. - * One can have multiple LocalityLbEndpoints for a locality, but this is - * generally only done if the different groups need to have different load - * balancing weights or different priorities. - * [#next-free-field: 7] - */ - export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; - } - } - } - export namespace type { - export type CodecClientType = _envoy_type_CodecClientType; - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange = _envoy_type_DoubleRange; - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent = _envoy_type_FractionalPercent; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range = _envoy_type_Int32Range; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range__Output = _envoy_type_Int32Range__Output; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range = _envoy_type_Int64Range; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range__Output = _envoy_type_Int64Range__Output; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent = _envoy_type_Percent; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent__Output = _envoy_type_Percent__Output; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion = _envoy_type_SemanticVersion; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - export namespace matcher { - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher = _envoy_type_matcher_StringMatcher; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - } - } - } - export namespace google { - export namespace api { - /** - * A custom pattern is used for defining custom HTTP verb. - */ - export type CustomHttpPattern = _google_api_CustomHttpPattern; - /** - * A custom pattern is used for defining custom HTTP verb. - */ - export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; - /** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ - export type Http = _google_api_Http; - /** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ - export type Http__Output = _google_api_Http__Output; - /** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ - export type HttpRule = _google_api_HttpRule; - /** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ - export type HttpRule__Output = _google_api_HttpRule__Output; - } - export namespace protobuf { - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type BoolValue = _google_protobuf_BoolValue; - export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type BytesValue = _google_protobuf_BytesValue; - export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type DescriptorProto = _google_protobuf_DescriptorProto; - export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; - export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; - export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; - export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileOptions = _google_protobuf_FileOptions; - export type FileOptions__Output = _google_protobuf_FileOptions__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type MessageOptions = _google_protobuf_MessageOptions; - export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type NullValue = _google_protobuf_NullValue; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; - export type OneofOptions = _google_protobuf_OneofOptions; - export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type ServiceOptions = _google_protobuf_ServiceOptions; - export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; - export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - } - } - export namespace udpa { - export namespace annotations { - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules = _validate_AnyRules; - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules__Output = _validate_AnyRules__Output; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules = _validate_BoolRules; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules__Output = _validate_BoolRules__Output; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules = _validate_BytesRules; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules__Output = _validate_BytesRules__Output; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules = _validate_DoubleRules; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules__Output = _validate_DoubleRules__Output; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules = _validate_DurationRules; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules__Output = _validate_DurationRules__Output; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules = _validate_EnumRules; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules__Output = _validate_EnumRules__Output; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules = _validate_FieldRules; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules__Output = _validate_FieldRules__Output; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules = _validate_Fixed32Rules; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules = _validate_Fixed64Rules; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules = _validate_FloatRules; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules__Output = _validate_FloatRules__Output; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules = _validate_Int32Rules; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules__Output = _validate_Int32Rules__Output; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules = _validate_Int64Rules; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules__Output = _validate_Int64Rules__Output; - /** - * WellKnownRegex contain some well-known patterns. - */ - export type KnownRegex = _validate_KnownRegex; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules = _validate_MapRules; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules__Output = _validate_MapRules__Output; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules = _validate_MessageRules; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules__Output = _validate_MessageRules__Output; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules = _validate_RepeatedRules; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules = _validate_SFixed32Rules; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules = _validate_SFixed64Rules; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules = _validate_SInt32Rules; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules = _validate_SInt64Rules; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules = _validate_StringRules; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules__Output = _validate_StringRules__Output; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules = _validate_TimestampRules; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules__Output = _validate_TimestampRules__Output; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules = _validate_UInt32Rules; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules = _validate_UInt64Rules; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - } -} - -export namespace ClientInterfaces { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace Cluster { - export namespace CommonLbConfig { - export namespace ConsistentHashingLbConfig { - } - export namespace LocalityWeightedLbConfig { - } - export namespace ZoneAwareLbConfig { - } - } - export namespace CustomClusterType { - } - export namespace EdsClusterConfig { - } - export namespace LbSubsetConfig { - export namespace LbSubsetSelector { - } - } - export namespace LeastRequestLbConfig { - } - export namespace OriginalDstLbConfig { - } - export namespace RefreshRate { - } - export namespace RingHashLbConfig { - } - export namespace TransportSocketMatch { - } - } - export namespace ClusterLoadAssignment { - export namespace Policy { - export namespace DropOverload { - } - } - } - export namespace LoadBalancingPolicy { - export namespace Policy { - } - } - export namespace UpstreamBindConfig { - } - export namespace UpstreamConnectionOptions { - } - export namespace auth { - export namespace CertificateValidationContext { - } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } - } - export namespace DownstreamTlsContext { - } - export namespace GenericSecret { - } - export namespace PrivateKeyProvider { - } - export namespace SdsSecretConfig { - } - export namespace Secret { - } - export namespace TlsCertificate { - } - export namespace TlsParameters { - } - export namespace TlsSessionTicketKeys { - } - export namespace UpstreamTlsContext { - } - } - export namespace cluster { - export namespace CircuitBreakers { - export namespace Thresholds { - export namespace RetryBudget { - } - } - } - export namespace Filter { - } - export namespace OutlierDetection { - } - } - export namespace core { - export namespace Address { - } - export namespace AggregatedConfigSource { - } - export namespace ApiConfigSource { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ConfigSource { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace EventServiceConfig { - } - export namespace Extension { - } - export namespace GrpcProtocolOptions { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HealthCheck { - export namespace CustomHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace HttpHealthCheck { - } - export namespace Payload { - } - export namespace RedisHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace TlsOptions { - } - } - export namespace Http1ProtocolOptions { - export namespace HeaderKeyFormat { - export namespace ProperCaseWords { - } - } - } - export namespace Http2ProtocolOptions { - export namespace SettingsParameter { - } - } - export namespace HttpProtocolOptions { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RateLimitSettings { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SelfConfigSource { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TcpProtocolOptions { - } - export namespace TransportSocket { - } - export namespace UpstreamHttpProtocolOptions { - } - } - export namespace endpoint { - export namespace Endpoint { - export namespace HealthCheckConfig { - } - } - export namespace LbEndpoint { - } - export namespace LocalityLbEndpoints { - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - } - } - export namespace google { - export namespace api { - export namespace CustomHttpPattern { - } - export namespace Http { - } - export namespace HttpRule { - } - } - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { @@ -2390,407 +190,3 @@ export interface ProtoGrpcType { } } -export namespace ServiceHandlers { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace Cluster { - export namespace CommonLbConfig { - export namespace ConsistentHashingLbConfig { - } - export namespace LocalityWeightedLbConfig { - } - export namespace ZoneAwareLbConfig { - } - } - export namespace CustomClusterType { - } - export namespace EdsClusterConfig { - } - export namespace LbSubsetConfig { - export namespace LbSubsetSelector { - } - } - export namespace LeastRequestLbConfig { - } - export namespace OriginalDstLbConfig { - } - export namespace RefreshRate { - } - export namespace RingHashLbConfig { - } - export namespace TransportSocketMatch { - } - } - export namespace ClusterLoadAssignment { - export namespace Policy { - export namespace DropOverload { - } - } - } - export namespace LoadBalancingPolicy { - export namespace Policy { - } - } - export namespace UpstreamBindConfig { - } - export namespace UpstreamConnectionOptions { - } - export namespace auth { - export namespace CertificateValidationContext { - } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } - } - export namespace DownstreamTlsContext { - } - export namespace GenericSecret { - } - export namespace PrivateKeyProvider { - } - export namespace SdsSecretConfig { - } - export namespace Secret { - } - export namespace TlsCertificate { - } - export namespace TlsParameters { - } - export namespace TlsSessionTicketKeys { - } - export namespace UpstreamTlsContext { - } - } - export namespace cluster { - export namespace CircuitBreakers { - export namespace Thresholds { - export namespace RetryBudget { - } - } - } - export namespace Filter { - } - export namespace OutlierDetection { - } - } - export namespace core { - export namespace Address { - } - export namespace AggregatedConfigSource { - } - export namespace ApiConfigSource { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ConfigSource { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace EventServiceConfig { - } - export namespace Extension { - } - export namespace GrpcProtocolOptions { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HealthCheck { - export namespace CustomHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace HttpHealthCheck { - } - export namespace Payload { - } - export namespace RedisHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace TlsOptions { - } - } - export namespace Http1ProtocolOptions { - export namespace HeaderKeyFormat { - export namespace ProperCaseWords { - } - } - } - export namespace Http2ProtocolOptions { - export namespace SettingsParameter { - } - } - export namespace HttpProtocolOptions { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RateLimitSettings { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SelfConfigSource { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TcpProtocolOptions { - } - export namespace TransportSocket { - } - export namespace UpstreamHttpProtocolOptions { - } - } - export namespace endpoint { - export namespace Endpoint { - export namespace HealthCheckConfig { - } - } - export namespace LbEndpoint { - } - export namespace LocalityLbEndpoints { - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - } - } - export namespace google { - export namespace api { - export namespace CustomHttpPattern { - } - export namespace Http { - } - export namespace HttpRule { - } - } - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} diff --git a/packages/grpc-js/src/generated/endpoint.ts b/packages/grpc-js/src/generated/endpoint.ts index bbd9ef7df..ade62c993 100644 --- a/packages/grpc-js/src/generated/endpoint.ts +++ b/packages/grpc-js/src/generated/endpoint.ts @@ -1,1803 +1,6 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from './envoy/api/v2/ClusterLoadAssignment'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from './envoy/api/v2/core/EventServiceConfig'; -import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from './envoy/api/v2/core/HealthCheck'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from './envoy/api/v2/core/HealthStatus'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; -import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from './envoy/api/v2/endpoint/Endpoint'; -import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from './envoy/api/v2/endpoint/LbEndpoint'; -import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from './envoy/api/v2/endpoint/LocalityLbEndpoints'; -import { CodecClientType as _envoy_type_CodecClientType } from './envoy/type/CodecClientType'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; -import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; - -export namespace messages { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - /** - * Each route from RDS will map to a single cluster or traffic split across - * clusters using weights expressed in the RDS WeightedCluster. - * - * With EDS, each cluster is treated independently from a LB perspective, with - * LB taking place between the Localities within a cluster and at a finer - * granularity between the hosts within a locality. The percentage of traffic - * for each endpoint is determined by both its load_balancing_weight, and the - * load_balancing_weight of its locality. First, a locality will be selected, - * then an endpoint within that locality will be chose based on its weight. - * [#next-free-field: 6] - */ - export type ClusterLoadAssignment = _envoy_api_v2_ClusterLoadAssignment; - /** - * Each route from RDS will map to a single cluster or traffic split across - * clusters using weights expressed in the RDS WeightedCluster. - * - * With EDS, each cluster is treated independently from a LB perspective, with - * LB taking place between the Localities within a cluster and at a finer - * granularity between the hosts within a locality. The percentage of traffic - * for each endpoint is determined by both its load_balancing_weight, and the - * load_balancing_weight of its locality. First, a locality will be selected, - * then an endpoint within that locality will be chose based on its weight. - * [#next-free-field: 6] - */ - export type ClusterLoadAssignment__Output = _envoy_api_v2_ClusterLoadAssignment__Output; - export namespace core { - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address = _envoy_api_v2_core_Address; - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address__Output = _envoy_api_v2_core_Address__Output; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion = _envoy_api_v2_core_BuildVersion; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange = _envoy_api_v2_core_CidrRange; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource = _envoy_api_v2_core_DataSource; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - /** - * [#not-implemented-hide:] - * Configuration of the event reporting service endpoint. - */ - export type EventServiceConfig = _envoy_api_v2_core_EventServiceConfig; - /** - * [#not-implemented-hide:] - * Configuration of the event reporting service endpoint. - */ - export type EventServiceConfig__Output = _envoy_api_v2_core_EventServiceConfig__Output; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension = _envoy_api_v2_core_Extension; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension__Output = _envoy_api_v2_core_Extension__Output; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService = _envoy_api_v2_core_GrpcService; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - /** - * Header name/value pair. - */ - export type HeaderValue = _envoy_api_v2_core_HeaderValue; - /** - * Header name/value pair. - */ - export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - /** - * [#next-free-field: 23] - */ - export type HealthCheck = _envoy_api_v2_core_HealthCheck; - /** - * [#next-free-field: 23] - */ - export type HealthCheck__Output = _envoy_api_v2_core_HealthCheck__Output; - /** - * Endpoint health status. - */ - export type HealthStatus = _envoy_api_v2_core_HealthStatus; - /** - * Envoy external URI descriptor - */ - export type HttpUri = _envoy_api_v2_core_HttpUri; - /** - * Envoy external URI descriptor - */ - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality = _envoy_api_v2_core_Locality; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality__Output = _envoy_api_v2_core_Locality__Output; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata = _envoy_api_v2_core_Metadata; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node = _envoy_api_v2_core_Node; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - /** - * HTTP request method. - */ - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; - /** - * Envoy supports :ref:`upstream priority routing - * ` both at the route and the virtual - * cluster level. The current priority implementation uses different connection - * pool and circuit breaking settings for each priority level. This means that - * even for HTTP/2 requests, two physical connections will be used to an - * upstream host. In the future Envoy will likely support true HTTP/2 priority - * over a single upstream connection. - */ - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - /** - * [#next-free-field: 7] - */ - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - /** - * [#next-free-field: 7] - */ - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption = _envoy_api_v2_core_SocketOption; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - /** - * Identifies the direction of the traffic relative to the local Envoy. - */ - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; - } - export namespace endpoint { - /** - * Upstream host identifier. - */ - export type Endpoint = _envoy_api_v2_endpoint_Endpoint; - /** - * Upstream host identifier. - */ - export type Endpoint__Output = _envoy_api_v2_endpoint_Endpoint__Output; - /** - * An Endpoint that Envoy can route traffic to. - * [#next-free-field: 6] - */ - export type LbEndpoint = _envoy_api_v2_endpoint_LbEndpoint; - /** - * An Endpoint that Envoy can route traffic to. - * [#next-free-field: 6] - */ - export type LbEndpoint__Output = _envoy_api_v2_endpoint_LbEndpoint__Output; - /** - * A group of endpoints belonging to a Locality. - * One can have multiple LocalityLbEndpoints for a locality, but this is - * generally only done if the different groups need to have different load - * balancing weights or different priorities. - * [#next-free-field: 7] - */ - export type LocalityLbEndpoints = _envoy_api_v2_endpoint_LocalityLbEndpoints; - /** - * A group of endpoints belonging to a Locality. - * One can have multiple LocalityLbEndpoints for a locality, but this is - * generally only done if the different groups need to have different load - * balancing weights or different priorities. - * [#next-free-field: 7] - */ - export type LocalityLbEndpoints__Output = _envoy_api_v2_endpoint_LocalityLbEndpoints__Output; - } - } - } - export namespace type { - export type CodecClientType = _envoy_type_CodecClientType; - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange = _envoy_type_DoubleRange; - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent = _envoy_type_FractionalPercent; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range = _envoy_type_Int32Range; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range__Output = _envoy_type_Int32Range__Output; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range = _envoy_type_Int64Range; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range__Output = _envoy_type_Int64Range__Output; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent = _envoy_type_Percent; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent__Output = _envoy_type_Percent__Output; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion = _envoy_type_SemanticVersion; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - export namespace matcher { - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher = _envoy_type_matcher_StringMatcher; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - } - } - } - export namespace google { - export namespace api { - /** - * A custom pattern is used for defining custom HTTP verb. - */ - export type CustomHttpPattern = _google_api_CustomHttpPattern; - /** - * A custom pattern is used for defining custom HTTP verb. - */ - export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; - /** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ - export type Http = _google_api_Http; - /** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ - export type Http__Output = _google_api_Http__Output; - /** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ - export type HttpRule = _google_api_HttpRule; - /** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ - export type HttpRule__Output = _google_api_HttpRule__Output; - } - export namespace protobuf { - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type BoolValue = _google_protobuf_BoolValue; - export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type BytesValue = _google_protobuf_BytesValue; - export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type DescriptorProto = _google_protobuf_DescriptorProto; - export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; - export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; - export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; - export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileOptions = _google_protobuf_FileOptions; - export type FileOptions__Output = _google_protobuf_FileOptions__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type MessageOptions = _google_protobuf_MessageOptions; - export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type NullValue = _google_protobuf_NullValue; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; - export type OneofOptions = _google_protobuf_OneofOptions; - export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type ServiceOptions = _google_protobuf_ServiceOptions; - export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; - export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - } - } - export namespace udpa { - export namespace annotations { - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules = _validate_AnyRules; - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules__Output = _validate_AnyRules__Output; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules = _validate_BoolRules; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules__Output = _validate_BoolRules__Output; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules = _validate_BytesRules; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules__Output = _validate_BytesRules__Output; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules = _validate_DoubleRules; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules__Output = _validate_DoubleRules__Output; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules = _validate_DurationRules; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules__Output = _validate_DurationRules__Output; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules = _validate_EnumRules; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules__Output = _validate_EnumRules__Output; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules = _validate_FieldRules; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules__Output = _validate_FieldRules__Output; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules = _validate_Fixed32Rules; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules = _validate_Fixed64Rules; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules = _validate_FloatRules; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules__Output = _validate_FloatRules__Output; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules = _validate_Int32Rules; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules__Output = _validate_Int32Rules__Output; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules = _validate_Int64Rules; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules__Output = _validate_Int64Rules__Output; - /** - * WellKnownRegex contain some well-known patterns. - */ - export type KnownRegex = _validate_KnownRegex; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules = _validate_MapRules; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules__Output = _validate_MapRules__Output; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules = _validate_MessageRules; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules__Output = _validate_MessageRules__Output; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules = _validate_RepeatedRules; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules = _validate_SFixed32Rules; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules = _validate_SFixed64Rules; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules = _validate_SInt32Rules; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules = _validate_SInt64Rules; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules = _validate_StringRules; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules__Output = _validate_StringRules__Output; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules = _validate_TimestampRules; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules__Output = _validate_TimestampRules__Output; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules = _validate_UInt32Rules; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules = _validate_UInt64Rules; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - } -} - -export namespace ClientInterfaces { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace ClusterLoadAssignment { - export namespace Policy { - export namespace DropOverload { - } - } - } - export namespace core { - export namespace Address { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace EventServiceConfig { - } - export namespace Extension { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HealthCheck { - export namespace CustomHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace HttpHealthCheck { - } - export namespace Payload { - } - export namespace RedisHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace TlsOptions { - } - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - export namespace endpoint { - export namespace Endpoint { - export namespace HealthCheckConfig { - } - } - export namespace LbEndpoint { - } - export namespace LocalityLbEndpoints { - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - } - } - export namespace google { - export namespace api { - export namespace CustomHttpPattern { - } - export namespace Http { - } - export namespace HttpRule { - } - } - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { @@ -1953,305 +156,3 @@ export interface ProtoGrpcType { } } -export namespace ServiceHandlers { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace ClusterLoadAssignment { - export namespace Policy { - export namespace DropOverload { - } - } - } - export namespace core { - export namespace Address { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace EventServiceConfig { - } - export namespace Extension { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HealthCheck { - export namespace CustomHealthCheck { - } - export namespace GrpcHealthCheck { - } - export namespace HttpHealthCheck { - } - export namespace Payload { - } - export namespace RedisHealthCheck { - } - export namespace TcpHealthCheck { - } - export namespace TlsOptions { - } - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - export namespace endpoint { - export namespace Endpoint { - export namespace HealthCheckConfig { - } - } - export namespace LbEndpoint { - } - export namespace LocalityLbEndpoints { - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - } - } - export namespace google { - export namespace api { - export namespace CustomHttpPattern { - } - export namespace Http { - } - export namespace HttpRule { - } - } - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts index 9d7cad537..4f6d10c60 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts @@ -21,8 +21,8 @@ import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2 import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from '../../../envoy/api/v2/LoadBalancingPolicy'; import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; import { Long } from '@grpc/proto-loader'; // Original file: deps/envoy-api/envoy/api/v2/cluster.proto @@ -196,78 +196,6 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig_ 'use_hostname_for_hashing': (boolean); } -/** - * Configuration for :ref:`locality weighted load balancing - * ` - */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { -} - -/** - * Configuration for :ref:`locality weighted load balancing - * ` - */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { -} - -/** - * Configuration for :ref:`zone aware routing - * `. - */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { - /** - * Configures percentage of requests that will be considered for zone aware routing - * if zone aware routing is configured. If not specified, the default is 100%. - * * :ref:`runtime values `. - * * :ref:`Zone aware routing support `. - */ - 'routing_enabled'?: (_envoy_type_Percent); - /** - * Configures minimum upstream cluster size required for zone aware routing - * If upstream cluster size is less than specified, zone aware routing is not performed - * even if zone aware routing is configured. If not specified, the default is 6. - * * :ref:`runtime values `. - * * :ref:`Zone aware routing support `. - */ - 'min_cluster_size'?: (_google_protobuf_UInt64Value); - /** - * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic - * mode`. Instead, the cluster will fail all - * requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a - * failing service. - */ - 'fail_traffic_on_panic'?: (boolean); -} - -/** - * Configuration for :ref:`zone aware routing - * `. - */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { - /** - * Configures percentage of requests that will be considered for zone aware routing - * if zone aware routing is configured. If not specified, the default is 100%. - * * :ref:`runtime values `. - * * :ref:`Zone aware routing support `. - */ - 'routing_enabled': (_envoy_type_Percent__Output); - /** - * Configures minimum upstream cluster size required for zone aware routing - * If upstream cluster size is less than specified, zone aware routing is not performed - * even if zone aware routing is configured. If not specified, the default is 6. - * * :ref:`runtime values `. - * * :ref:`Zone aware routing support `. - */ - 'min_cluster_size': (_google_protobuf_UInt64Value__Output); - /** - * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic - * mode`. Instead, the cluster will fail all - * requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a - * failing service. - */ - 'fail_traffic_on_panic': (boolean); -} - /** * Extended cluster type. */ @@ -389,6 +317,24 @@ export interface _envoy_api_v2_Cluster_EdsClusterConfig__Output { // Original file: deps/envoy-api/envoy/api/v2/cluster.proto +/** + * The hash function used to hash hosts onto the ketama ring. + */ +export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { + /** + * Use `xxHash `_, this is the default hash function. + */ + XX_HASH = 0, + /** + * Use `MurmurHash2 `_, this is compatible with + * std:hash in GNU libstdc++ 3.4.20 or above. This is typically the case when compiled + * on Linux and not macOS. + */ + MURMUR_HASH_2 = 1, +} + +// Original file: deps/envoy-api/envoy/api/v2/cluster.proto + /** * Refer to :ref:`load balancer type ` architecture * overview section for information on each type. @@ -728,6 +674,20 @@ export interface _envoy_api_v2_Cluster_LeastRequestLbConfig__Output { 'choice_count': (_google_protobuf_UInt32Value__Output); } +/** + * Configuration for :ref:`locality weighted load balancing + * ` + */ +export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { +} + +/** + * Configuration for :ref:`locality weighted load balancing + * ` + */ +export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { +} + /** * Specific configuration for the * :ref:`Original Destination ` @@ -850,24 +810,6 @@ export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { 'maximum_ring_size': (_google_protobuf_UInt64Value__Output); } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto - -/** - * The hash function used to hash hosts onto the ketama ring. - */ -export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { - /** - * Use `xxHash `_, this is the default hash function. - */ - XX_HASH = 0, - /** - * Use `MurmurHash2 `_, this is compatible with - * std:hash in GNU libstdc++ 3.4.20 or above. This is typically the case when compiled - * on Linux and not macOS. - */ - MURMUR_HASH_2 = 1, -} - /** * TransportSocketMatch specifies what transport socket config will be used * when the match conditions are satisfied. @@ -914,6 +856,64 @@ export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); } +/** + * Configuration for :ref:`zone aware routing + * `. + */ +export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { + /** + * Configures percentage of requests that will be considered for zone aware routing + * if zone aware routing is configured. If not specified, the default is 100%. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ + 'routing_enabled'?: (_envoy_type_Percent); + /** + * Configures minimum upstream cluster size required for zone aware routing + * If upstream cluster size is less than specified, zone aware routing is not performed + * even if zone aware routing is configured. If not specified, the default is 6. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ + 'min_cluster_size'?: (_google_protobuf_UInt64Value); + /** + * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic + * mode`. Instead, the cluster will fail all + * requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a + * failing service. + */ + 'fail_traffic_on_panic'?: (boolean); +} + +/** + * Configuration for :ref:`zone aware routing + * `. + */ +export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { + /** + * Configures percentage of requests that will be considered for zone aware routing + * if zone aware routing is configured. If not specified, the default is 100%. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ + 'routing_enabled': (_envoy_type_Percent__Output); + /** + * Configures minimum upstream cluster size required for zone aware routing + * If upstream cluster size is less than specified, zone aware routing is not performed + * even if zone aware routing is configured. If not specified, the default is 6. + * * :ref:`runtime values `. + * * :ref:`Zone aware routing support `. + */ + 'min_cluster_size': (_google_protobuf_UInt64Value__Output); + /** + * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic + * mode`. Instead, the cluster will fail all + * requests as if all hosts are unhealthy. This can help avoid potentially overwhelming a + * failing service. + */ + 'fail_traffic_on_panic': (boolean); +} + /** * Configuration for a single upstream cluster. * [#next-free-field: 48] diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts index 0f6baa546..ecb8034ed 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts @@ -6,6 +6,34 @@ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _go import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../envoy/type/FractionalPercent'; +/** + * [#not-implemented-hide:] + */ +export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload { + /** + * Identifier for the policy specifying the drop. + */ + 'category'?: (string); + /** + * Percentage of traffic that should be dropped for the category. + */ + 'drop_percentage'?: (_envoy_type_FractionalPercent); +} + +/** + * [#not-implemented-hide:] + */ +export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output { + /** + * Identifier for the policy specifying the drop. + */ + 'category': (string); + /** + * Percentage of traffic that should be dropped for the category. + */ + 'drop_percentage': (_envoy_type_FractionalPercent__Output); +} + /** * Load balancing policy settings. * [#next-free-field: 6] @@ -136,34 +164,6 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { 'disable_overprovisioning': (boolean); } -/** - * [#not-implemented-hide:] - */ -export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload { - /** - * Identifier for the policy specifying the drop. - */ - 'category'?: (string); - /** - * Percentage of traffic that should be dropped for the category. - */ - 'drop_percentage'?: (_envoy_type_FractionalPercent); -} - -/** - * [#not-implemented-hide:] - */ -export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output { - /** - * Identifier for the policy specifying the drop. - */ - 'category': (string); - /** - * Percentage of traffic that should be dropped for the category. - */ - 'drop_percentage': (_envoy_type_FractionalPercent__Output); -} - /** * Each route from RDS will map to a single cluster or traffic split across * clusters using weights expressed in the RDS WeightedCluster. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts index befc353b9..9c0368ce7 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts @@ -35,28 +35,6 @@ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig__Output { 'balance_type': "exact_balance"; } -/** - * A connection balancer implementation that does exact balancing. This means that a lock is - * held during balancing so that connection counts are nearly exactly balanced between worker - * threads. This is "nearly" exact in the sense that a connection might close in parallel thus - * making the counts incorrect, but this should be rectified on the next accept. This balancer - * sacrifices accept throughput for accuracy and should be used when there are a small number of - * connections that rarely cycle (e.g., service mesh gRPC egress). - */ -export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { -} - -/** - * A connection balancer implementation that does exact balancing. This means that a lock is - * held during balancing so that connection counts are nearly exactly balanced between worker - * threads. This is "nearly" exact in the sense that a connection might close in parallel thus - * making the counts incorrect, but this should be rectified on the next accept. This balancer - * sacrifices accept throughput for accuracy and should be used when there are a small number of - * connections that rarely cycle (e.g., service mesh gRPC egress). - */ -export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output { -} - /** * [#not-implemented-hide:] */ @@ -111,6 +89,28 @@ export enum _envoy_api_v2_Listener_DrainType { MODIFY_ONLY = 1, } +/** + * A connection balancer implementation that does exact balancing. This means that a lock is + * held during balancing so that connection counts are nearly exactly balanced between worker + * threads. This is "nearly" exact in the sense that a connection might close in parallel thus + * making the counts incorrect, but this should be rectified on the next accept. This balancer + * sacrifices accept throughput for accuracy and should be used when there are a small number of + * connections that rarely cycle (e.g., service mesh gRPC egress). + */ +export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { +} + +/** + * A connection balancer implementation that does exact balancing. This means that a lock is + * held during balancing so that connection counts are nearly exactly balanced between worker + * threads. This is "nearly" exact in the sense that a connection might close in parallel thus + * making the counts incorrect, but this should be rectified on the next accept. This balancer + * sacrifices accept throughput for accuracy and should be used when there are a small number of + * connections that rarely cycle (e.g., service mesh gRPC egress). + */ +export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output { +} + /** * [#next-free-field: 23] */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts index f5addf5f2..0b2f01db6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts @@ -4,6 +4,42 @@ import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../ import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../envoy/type/Percent'; +export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { + /** + * Specifies the limit on concurrent retries as a percentage of the sum of active requests and + * active pending requests. For example, if there are 100 active requests and the + * budget_percent is set to 25, there may be 25 active retries. + * + * This parameter is optional. Defaults to 20%. + */ + 'budget_percent'?: (_envoy_type_Percent); + /** + * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the + * number of active retries may never go below this number. + * + * This parameter is optional. Defaults to 3. + */ + 'min_retry_concurrency'?: (_google_protobuf_UInt32Value); +} + +export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output { + /** + * Specifies the limit on concurrent retries as a percentage of the sum of active requests and + * active pending requests. For example, if there are 100 active requests and the + * budget_percent is set to 25, there may be 25 active retries. + * + * This parameter is optional. Defaults to 20%. + */ + 'budget_percent': (_envoy_type_Percent__Output); + /** + * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the + * number of active retries may never go below this number. + * + * This parameter is optional. Defaults to 3. + */ + 'min_retry_concurrency': (_google_protobuf_UInt32Value__Output); +} + /** * A Thresholds defines CircuitBreaker settings for a * :ref:`RoutingPriority`. @@ -128,42 +164,6 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { 'max_connection_pools': (_google_protobuf_UInt32Value__Output); } -export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { - /** - * Specifies the limit on concurrent retries as a percentage of the sum of active requests and - * active pending requests. For example, if there are 100 active requests and the - * budget_percent is set to 25, there may be 25 active retries. - * - * This parameter is optional. Defaults to 20%. - */ - 'budget_percent'?: (_envoy_type_Percent); - /** - * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the - * number of active retries may never go below this number. - * - * This parameter is optional. Defaults to 3. - */ - 'min_retry_concurrency'?: (_google_protobuf_UInt32Value); -} - -export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output { - /** - * Specifies the limit on concurrent retries as a percentage of the sum of active requests and - * active pending requests. For example, if there are 100 active requests and the - * budget_percent is set to 25, there may be 25 active retries. - * - * This parameter is optional. Defaults to 20%. - */ - 'budget_percent': (_envoy_type_Percent__Output); - /** - * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the - * number of active retries may never go below this number. - * - * This parameter is optional. Defaults to 3. - */ - 'min_retry_concurrency': (_google_protobuf_UInt32Value__Output); -} - /** * :ref:`Circuit breaking` settings can be * specified individually for each defined priority. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts index e536cb317..b67f63e45 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts @@ -3,11 +3,127 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; import { Long } from '@grpc/proto-loader'; +/** + * [#next-free-field: 8] + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { + /** + * Access token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. + */ + 'access_token'?: (string); + /** + * Google Compute Engine credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ + 'google_compute_engine'?: (_google_protobuf_Empty); + /** + * Google refresh token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. + */ + 'google_refresh_token'?: (string); + /** + * Service Account JWT Access credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. + */ + 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); + /** + * Google IAM credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. + */ + 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); + /** + * Custom authenticator credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. + * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. + */ + 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); + /** + * Custom security token service which implements OAuth 2.0 token exchange. + * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 + * See https://github.com/grpc/grpc/pull/19587. + */ + 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService); + 'credential_specifier'?: "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; +} + +/** + * [#next-free-field: 8] + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output { + /** + * Access token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. + */ + 'access_token'?: (string); + /** + * Google Compute Engine credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ + 'google_compute_engine'?: (_google_protobuf_Empty__Output); + /** + * Google refresh token credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. + */ + 'google_refresh_token'?: (string); + /** + * Service Account JWT Access credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. + */ + 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); + /** + * Google IAM credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. + */ + 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); + /** + * Custom authenticator credentials. + * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. + * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. + */ + 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); + /** + * Custom security token service which implements OAuth 2.0 token exchange. + * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 + * See https://github.com/grpc/grpc/pull/19587. + */ + 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); + 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; +} + +/** + * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call + * credential types. + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { + 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); + /** + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ + 'google_default'?: (_google_protobuf_Empty); + 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); + 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; +} + +/** + * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call + * credential types. + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { + 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); + /** + * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 + */ + 'google_default'?: (_google_protobuf_Empty__Output); + 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); + 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; +} + export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc { /** * The name of the upstream gRPC cluster. SSL credentials will be supplied @@ -108,94 +224,6 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { 'config': (_google_protobuf_Struct__Output); } -/** - * [#next-free-field: 8] - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { - /** - * Access token credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. - */ - 'access_token'?: (string); - /** - * Google Compute Engine credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 - */ - 'google_compute_engine'?: (_google_protobuf_Empty); - /** - * Google refresh token credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. - */ - 'google_refresh_token'?: (string); - /** - * Service Account JWT Access credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. - */ - 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); - /** - * Google IAM credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. - */ - 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); - /** - * Custom authenticator credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. - * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. - */ - 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); - /** - * Custom security token service which implements OAuth 2.0 token exchange. - * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 - * See https://github.com/grpc/grpc/pull/19587. - */ - 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService); - 'credential_specifier'?: "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; -} - -/** - * [#next-free-field: 8] - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output { - /** - * Access token credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. - */ - 'access_token'?: (string); - /** - * Google Compute Engine credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 - */ - 'google_compute_engine'?: (_google_protobuf_Empty__Output); - /** - * Google refresh token credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. - */ - 'google_refresh_token'?: (string); - /** - * Service Account JWT Access credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. - */ - 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); - /** - * Google IAM credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. - */ - 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); - /** - * Custom authenticator credentials. - * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. - * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. - */ - 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); - /** - * Custom security token service which implements OAuth 2.0 token exchange. - * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 - * See https://github.com/grpc/grpc/pull/19587. - */ - 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); - 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; -} - export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { 'authorization_token'?: (string); 'authority_selector'?: (string); @@ -206,6 +234,20 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_Googl 'authority_selector': (string); } +/** + * Local channel credentials. Only UDS is supported for now. + * See https://github.com/grpc/grpc/pull/15909. + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { +} + +/** + * Local channel credentials. Only UDS is supported for now. + * See https://github.com/grpc/grpc/pull/15909. + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { +} + export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin { 'name'?: (string); 'config'?: (_google_protobuf_Struct); @@ -230,6 +272,42 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_Servi 'token_lifetime_seconds': (string); } +/** + * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { + /** + * PEM encoded server root certificates. + */ + 'root_certs'?: (_envoy_api_v2_core_DataSource); + /** + * PEM encoded client private key. + */ + 'private_key'?: (_envoy_api_v2_core_DataSource); + /** + * PEM encoded client certificate chain. + */ + 'cert_chain'?: (_envoy_api_v2_core_DataSource); +} + +/** + * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. + */ +export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { + /** + * PEM encoded server root certificates. + */ + 'root_certs': (_envoy_api_v2_core_DataSource__Output); + /** + * PEM encoded client private key. + */ + 'private_key': (_envoy_api_v2_core_DataSource__Output); + /** + * PEM encoded client certificate chain. + */ + 'cert_chain': (_envoy_api_v2_core_DataSource__Output); +} + /** * Security token service configuration that allows Google gRPC to * fetch security token from an OAuth 2.0 authorization server. @@ -338,84 +416,6 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsSe 'actor_token_type': (string); } -/** - * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call - * credential types. - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { - 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); - /** - * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 - */ - 'google_default'?: (_google_protobuf_Empty); - 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); - 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; -} - -/** - * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call - * credential types. - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { - 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); - /** - * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 - */ - 'google_default'?: (_google_protobuf_Empty__Output); - 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); - 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; -} - -/** - * Local channel credentials. Only UDS is supported for now. - * See https://github.com/grpc/grpc/pull/15909. - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { -} - -/** - * Local channel credentials. Only UDS is supported for now. - * See https://github.com/grpc/grpc/pull/15909. - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { -} - -/** - * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { - /** - * PEM encoded server root certificates. - */ - 'root_certs'?: (_envoy_api_v2_core_DataSource); - /** - * PEM encoded client private key. - */ - 'private_key'?: (_envoy_api_v2_core_DataSource); - /** - * PEM encoded client certificate chain. - */ - 'cert_chain'?: (_envoy_api_v2_core_DataSource); -} - -/** - * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. - */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { - /** - * PEM encoded server root certificates. - */ - 'root_certs': (_envoy_api_v2_core_DataSource__Output); - /** - * PEM encoded client private key. - */ - 'private_key': (_envoy_api_v2_core_DataSource__Output); - /** - * PEM encoded client certificate chain. - */ - 'cert_chain': (_envoy_api_v2_core_DataSource__Output); -} - /** * gRPC service configuration. This is used by :ref:`ApiConfigSource * ` and filter configurations. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts index 662e73752..972560cd5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts @@ -4,12 +4,12 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_prot import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from '../../../../envoy/api/v2/core/EventServiceConfig'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; import { CodecClientType as _envoy_type_CodecClientType } from '../../../../envoy/type/CodecClientType'; import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import { Long } from '@grpc/proto-loader'; /** diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts index 02a8665a4..490718e80 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts @@ -27,108 +27,6 @@ export enum _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode { NOT_FOUND = 1, } -/** - * Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer - * `. - * [#next-free-field: 7] - */ -export interface _envoy_api_v2_route_RouteAction_HashPolicy { - /** - * Header hash policy. - */ - 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header); - /** - * Cookie hash policy. - */ - 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie); - /** - * Connection properties hash policy. - */ - 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties); - /** - * Query parameter hash policy. - */ - 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter); - /** - * Filter state hash policy. - */ - 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState); - /** - * The flag that short-circuits the hash computing. This field provides a - * 'fallback' style of configuration: "if a terminal policy doesn't work, - * fallback to rest of the policy list", it saves time when the terminal - * policy works. - * - * If true, and there is already a hash computed, ignore rest of the - * list of hash polices. - * For example, if the following hash methods are configured: - * - * ========= ======== - * specifier terminal - * ========= ======== - * Header A true - * Header B false - * Header C false - * ========= ======== - * - * The generateHash process ends if policy "header A" generates a hash, as - * it's a terminal policy. - */ - 'terminal'?: (boolean); - 'policy_specifier'?: "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; -} - -/** - * Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer - * `. - * [#next-free-field: 7] - */ -export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { - /** - * Header hash policy. - */ - 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header__Output); - /** - * Cookie hash policy. - */ - 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output); - /** - * Connection properties hash policy. - */ - 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output); - /** - * Query parameter hash policy. - */ - 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output); - /** - * Filter state hash policy. - */ - 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output); - /** - * The flag that short-circuits the hash computing. This field provides a - * 'fallback' style of configuration: "if a terminal policy doesn't work, - * fallback to rest of the policy list", it saves time when the terminal - * policy works. - * - * If true, and there is already a hash computed, ignore rest of the - * list of hash polices. - * For example, if the following hash methods are configured: - * - * ========= ======== - * specifier terminal - * ========= ======== - * Header A true - * Header B false - * Header C false - * ========= ======== - * - * The generateHash process ends if policy "header A" generates a hash, as - * it's a terminal policy. - */ - 'terminal': (boolean); - 'policy_specifier': "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; -} - export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties { /** * Hash on source IP address. @@ -233,6 +131,108 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output 'key': (string); } +/** + * Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer + * `. + * [#next-free-field: 7] + */ +export interface _envoy_api_v2_route_RouteAction_HashPolicy { + /** + * Header hash policy. + */ + 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header); + /** + * Cookie hash policy. + */ + 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie); + /** + * Connection properties hash policy. + */ + 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties); + /** + * Query parameter hash policy. + */ + 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter); + /** + * Filter state hash policy. + */ + 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState); + /** + * The flag that short-circuits the hash computing. This field provides a + * 'fallback' style of configuration: "if a terminal policy doesn't work, + * fallback to rest of the policy list", it saves time when the terminal + * policy works. + * + * If true, and there is already a hash computed, ignore rest of the + * list of hash polices. + * For example, if the following hash methods are configured: + * + * ========= ======== + * specifier terminal + * ========= ======== + * Header A true + * Header B false + * Header C false + * ========= ======== + * + * The generateHash process ends if policy "header A" generates a hash, as + * it's a terminal policy. + */ + 'terminal'?: (boolean); + 'policy_specifier'?: "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; +} + +/** + * Specifies the route's hashing policy if the upstream cluster uses a hashing :ref:`load balancer + * `. + * [#next-free-field: 7] + */ +export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { + /** + * Header hash policy. + */ + 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header__Output); + /** + * Cookie hash policy. + */ + 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output); + /** + * Connection properties hash policy. + */ + 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output); + /** + * Query parameter hash policy. + */ + 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output); + /** + * Filter state hash policy. + */ + 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output); + /** + * The flag that short-circuits the hash computing. This field provides a + * 'fallback' style of configuration: "if a terminal policy doesn't work, + * fallback to rest of the policy list", it saves time when the terminal + * policy works. + * + * If true, and there is already a hash computed, ignore rest of the + * list of hash polices. + * For example, if the following hash methods are configured: + * + * ========= ======== + * specifier terminal + * ========= ======== + * Header A true + * Header B false + * Header C false + * ========= ======== + * + * The generateHash process ends if policy "header A" generates a hash, as + * it's a terminal policy. + */ + 'terminal': (boolean); + 'policy_specifier': "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; +} + export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header { /** * The name of the request header that will be used to obtain the hash @@ -249,6 +249,16 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header__Output { 'header_name': (string); } +// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto + +/** + * Configures :ref:`internal redirect ` behavior. + */ +export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { + PASS_THROUGH_INTERNAL_REDIRECT = 0, + HANDLE_INTERNAL_REDIRECT = 1, +} + export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter { /** * The name of the URL query parameter that will be used to obtain the hash @@ -267,16 +277,6 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Outp 'name': (string); } -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -/** - * Configures :ref:`internal redirect ` behavior. - */ -export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { - PASS_THROUGH_INTERNAL_REDIRECT = 0, - HANDLE_INTERNAL_REDIRECT = 1, -} - /** * The router is capable of shadowing traffic from one cluster to another. The current * implementation is "fire and forget," meaning Envoy will not wait for the shadow cluster to diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts new file mode 100644 index 000000000..32cc9ba51 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts @@ -0,0 +1,52 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto + +import * as grpc from '../../../../../index' +import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; +import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; +import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; +import { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from '../../../../envoy/api/v2/DiscoveryResponse'; + +/** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ +export interface AggregatedDiscoveryServiceClient extends grpc.Client { + DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; + DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; + deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; + deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; + + /** + * This is a gRPC-only API. + */ + StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; + StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; + /** + * This is a gRPC-only API. + */ + streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; + streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; + +} + +/** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ +export interface AggregatedDiscoveryServiceHandlers { + DeltaAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>): void; + + /** + * This is a gRPC-only API. + */ + StreamAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>): void; + +} diff --git a/packages/grpc-js/src/generated/listener.ts b/packages/grpc-js/src/generated/listener.ts index 4bc0d85cf..040c1d52a 100644 --- a/packages/grpc-js/src/generated/listener.ts +++ b/packages/grpc-js/src/generated/listener.ts @@ -1,2703 +1,6 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { Listener as _envoy_api_v2_Listener, Listener__Output as _envoy_api_v2_Listener__Output } from './envoy/api/v2/Listener'; -import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from './envoy/api/v2/auth/CertificateValidationContext'; -import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from './envoy/api/v2/auth/CommonTlsContext'; -import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from './envoy/api/v2/auth/DownstreamTlsContext'; -import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from './envoy/api/v2/auth/GenericSecret'; -import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from './envoy/api/v2/auth/PrivateKeyProvider'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from './envoy/api/v2/auth/SdsSecretConfig'; -import { Secret as _envoy_api_v2_auth_Secret, Secret__Output as _envoy_api_v2_auth_Secret__Output } from './envoy/api/v2/auth/Secret'; -import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from './envoy/api/v2/auth/TlsCertificate'; -import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from './envoy/api/v2/auth/TlsParameters'; -import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from './envoy/api/v2/auth/TlsSessionTicketKeys'; -import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from './envoy/api/v2/auth/UpstreamTlsContext'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; -import { ActiveRawUdpListenerConfig as _envoy_api_v2_listener_ActiveRawUdpListenerConfig, ActiveRawUdpListenerConfig__Output as _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output } from './envoy/api/v2/listener/ActiveRawUdpListenerConfig'; -import { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from './envoy/api/v2/listener/Filter'; -import { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from './envoy/api/v2/listener/FilterChain'; -import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from './envoy/api/v2/listener/FilterChainMatch'; -import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from './envoy/api/v2/listener/ListenerFilter'; -import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from './envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; -import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from './envoy/api/v2/listener/UdpListenerConfig'; -import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from './envoy/api/v2/route/CorsPolicy'; -import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; -import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; -import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; -import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from './envoy/api/v2/route/HedgePolicy'; -import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; -import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; -import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from './envoy/api/v2/route/RedirectAction'; -import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; -import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; -import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; -import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; -import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from './envoy/api/v2/route/Tracing'; -import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from './envoy/api/v2/route/VirtualCluster'; -import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; -import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; -import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from './envoy/config/filter/accesslog/v2/AccessLog'; -import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from './envoy/config/filter/accesslog/v2/AccessLogFilter'; -import { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from './envoy/config/filter/accesslog/v2/AndFilter'; -import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from './envoy/config/filter/accesslog/v2/ComparisonFilter'; -import { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from './envoy/config/filter/accesslog/v2/DurationFilter'; -import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from './envoy/config/filter/accesslog/v2/ExtensionFilter'; -import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from './envoy/config/filter/accesslog/v2/GrpcStatusFilter'; -import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from './envoy/config/filter/accesslog/v2/HeaderFilter'; -import { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from './envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; -import { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from './envoy/config/filter/accesslog/v2/OrFilter'; -import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from './envoy/config/filter/accesslog/v2/ResponseFlagFilter'; -import { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from './envoy/config/filter/accesslog/v2/RuntimeFilter'; -import { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from './envoy/config/filter/accesslog/v2/StatusCodeFilter'; -import { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from './envoy/config/filter/accesslog/v2/TraceableFilter'; -import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from './envoy/config/listener/v2/ApiListener'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; -import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; -import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from './google/api/CustomHttpPattern'; -import { Http as _google_api_Http, Http__Output as _google_api_Http__Output } from './google/api/Http'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from './google/api/HttpRule'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; - -export namespace messages { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - /** - * [#next-free-field: 23] - */ - export type Listener = _envoy_api_v2_Listener; - /** - * [#next-free-field: 23] - */ - export type Listener__Output = _envoy_api_v2_Listener__Output; - export namespace auth { - /** - * [#next-free-field: 11] - */ - export type CertificateValidationContext = _envoy_api_v2_auth_CertificateValidationContext; - /** - * [#next-free-field: 11] - */ - export type CertificateValidationContext__Output = _envoy_api_v2_auth_CertificateValidationContext__Output; - /** - * TLS context shared by both client and server TLS contexts. - * [#next-free-field: 9] - */ - export type CommonTlsContext = _envoy_api_v2_auth_CommonTlsContext; - /** - * TLS context shared by both client and server TLS contexts. - * [#next-free-field: 9] - */ - export type CommonTlsContext__Output = _envoy_api_v2_auth_CommonTlsContext__Output; - /** - * [#next-free-field: 8] - */ - export type DownstreamTlsContext = _envoy_api_v2_auth_DownstreamTlsContext; - /** - * [#next-free-field: 8] - */ - export type DownstreamTlsContext__Output = _envoy_api_v2_auth_DownstreamTlsContext__Output; - export type GenericSecret = _envoy_api_v2_auth_GenericSecret; - export type GenericSecret__Output = _envoy_api_v2_auth_GenericSecret__Output; - /** - * BoringSSL private key method configuration. The private key methods are used for external - * (potentially asynchronous) signing and decryption operations. Some use cases for private key - * methods would be TPM support and TLS acceleration. - */ - export type PrivateKeyProvider = _envoy_api_v2_auth_PrivateKeyProvider; - /** - * BoringSSL private key method configuration. The private key methods are used for external - * (potentially asynchronous) signing and decryption operations. Some use cases for private key - * methods would be TPM support and TLS acceleration. - */ - export type PrivateKeyProvider__Output = _envoy_api_v2_auth_PrivateKeyProvider__Output; - export type SdsSecretConfig = _envoy_api_v2_auth_SdsSecretConfig; - export type SdsSecretConfig__Output = _envoy_api_v2_auth_SdsSecretConfig__Output; - /** - * [#next-free-field: 6] - */ - export type Secret = _envoy_api_v2_auth_Secret; - /** - * [#next-free-field: 6] - */ - export type Secret__Output = _envoy_api_v2_auth_Secret__Output; - /** - * [#next-free-field: 7] - */ - export type TlsCertificate = _envoy_api_v2_auth_TlsCertificate; - /** - * [#next-free-field: 7] - */ - export type TlsCertificate__Output = _envoy_api_v2_auth_TlsCertificate__Output; - export type TlsParameters = _envoy_api_v2_auth_TlsParameters; - export type TlsParameters__Output = _envoy_api_v2_auth_TlsParameters__Output; - export type TlsSessionTicketKeys = _envoy_api_v2_auth_TlsSessionTicketKeys; - export type TlsSessionTicketKeys__Output = _envoy_api_v2_auth_TlsSessionTicketKeys__Output; - export type UpstreamTlsContext = _envoy_api_v2_auth_UpstreamTlsContext; - export type UpstreamTlsContext__Output = _envoy_api_v2_auth_UpstreamTlsContext__Output; - } - export namespace core { - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address = _envoy_api_v2_core_Address; - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address__Output = _envoy_api_v2_core_Address__Output; - /** - * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that ADS is to be used. - */ - export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; - /** - * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that ADS is to be used. - */ - export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; - /** - * API configuration source. This identifies the API type and cluster that Envoy - * will use to fetch an xDS API. - * [#next-free-field: 9] - */ - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - /** - * API configuration source. This identifies the API type and cluster that Envoy - * will use to fetch an xDS API. - * [#next-free-field: 9] - */ - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; - /** - * xDS API version. This is used to describe both resource and transport - * protocol versions (in distinct configuration fields). - */ - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion = _envoy_api_v2_core_BuildVersion; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange = _envoy_api_v2_core_CidrRange; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - /** - * Configuration for :ref:`listeners `, :ref:`clusters - * `, :ref:`routes - * `, :ref:`endpoints - * ` etc. may either be sourced from the - * filesystem or from an xDS API source. Filesystem configs are watched with - * inotify for updates. - * [#next-free-field: 7] - */ - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - /** - * Configuration for :ref:`listeners `, :ref:`clusters - * `, :ref:`routes - * `, :ref:`endpoints - * ` etc. may either be sourced from the - * filesystem or from an xDS API source. Filesystem configs are watched with - * inotify for updates. - * [#next-free-field: 7] - */ - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource = _envoy_api_v2_core_DataSource; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension = _envoy_api_v2_core_Extension; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension__Output = _envoy_api_v2_core_Extension__Output; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService = _envoy_api_v2_core_GrpcService; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - /** - * Header name/value pair. - */ - export type HeaderValue = _envoy_api_v2_core_HeaderValue; - /** - * Header name/value pair. - */ - export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - /** - * Envoy external URI descriptor - */ - export type HttpUri = _envoy_api_v2_core_HttpUri; - /** - * Envoy external URI descriptor - */ - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality = _envoy_api_v2_core_Locality; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality__Output = _envoy_api_v2_core_Locality__Output; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata = _envoy_api_v2_core_Metadata; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node = _envoy_api_v2_core_Node; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - /** - * Rate Limit settings to be applied for discovery requests made by Envoy. - */ - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - /** - * Rate Limit settings to be applied for discovery requests made by Envoy. - */ - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - /** - * HTTP request method. - */ - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; - /** - * Envoy supports :ref:`upstream priority routing - * ` both at the route and the virtual - * cluster level. The current priority implementation uses different connection - * pool and circuit breaking settings for each priority level. This means that - * even for HTTP/2 requests, two physical connections will be used to an - * upstream host. In the future Envoy will likely support true HTTP/2 priority - * over a single upstream connection. - */ - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - /** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ - export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; - /** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ - export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - /** - * [#next-free-field: 7] - */ - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - /** - * [#next-free-field: 7] - */ - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption = _envoy_api_v2_core_SocketOption; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - /** - * Identifies the direction of the traffic relative to the local Envoy. - */ - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; - } - export namespace listener { - export type ActiveRawUdpListenerConfig = _envoy_api_v2_listener_ActiveRawUdpListenerConfig; - export type ActiveRawUdpListenerConfig__Output = _envoy_api_v2_listener_ActiveRawUdpListenerConfig__Output; - export type Filter = _envoy_api_v2_listener_Filter; - export type Filter__Output = _envoy_api_v2_listener_Filter__Output; - /** - * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and - * various other parameters. - * [#next-free-field: 8] - */ - export type FilterChain = _envoy_api_v2_listener_FilterChain; - /** - * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and - * various other parameters. - * [#next-free-field: 8] - */ - export type FilterChain__Output = _envoy_api_v2_listener_FilterChain__Output; - /** - * Specifies the match criteria for selecting a specific filter chain for a - * listener. - * - * In order for a filter chain to be selected, *ALL* of its criteria must be - * fulfilled by the incoming connection, properties of which are set by the - * networking stack and/or listener filters. - * - * The following order applies: - * - * 1. Destination port. - * 2. Destination IP address. - * 3. Server name (e.g. SNI for TLS protocol), - * 4. Transport protocol. - * 5. Application protocols (e.g. ALPN for TLS protocol). - * 6. Source type (e.g. any, local or external network). - * 7. Source IP address. - * 8. Source port. - * - * For criteria that allow ranges or wildcards, the most specific value in any - * of the configured filter chains that matches the incoming connection is going - * to be used (e.g. for SNI ``www.example.com`` the most specific match would be - * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter - * chain without ``server_names`` requirements). - * - * [#comment: Implemented rules are kept in the preference order, with deprecated fields - * listed at the end, because that's how we want to list them in the docs. - * - * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] - * [#next-free-field: 13] - */ - export type FilterChainMatch = _envoy_api_v2_listener_FilterChainMatch; - /** - * Specifies the match criteria for selecting a specific filter chain for a - * listener. - * - * In order for a filter chain to be selected, *ALL* of its criteria must be - * fulfilled by the incoming connection, properties of which are set by the - * networking stack and/or listener filters. - * - * The following order applies: - * - * 1. Destination port. - * 2. Destination IP address. - * 3. Server name (e.g. SNI for TLS protocol), - * 4. Transport protocol. - * 5. Application protocols (e.g. ALPN for TLS protocol). - * 6. Source type (e.g. any, local or external network). - * 7. Source IP address. - * 8. Source port. - * - * For criteria that allow ranges or wildcards, the most specific value in any - * of the configured filter chains that matches the incoming connection is going - * to be used (e.g. for SNI ``www.example.com`` the most specific match would be - * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter - * chain without ``server_names`` requirements). - * - * [#comment: Implemented rules are kept in the preference order, with deprecated fields - * listed at the end, because that's how we want to list them in the docs. - * - * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] - * [#next-free-field: 13] - */ - export type FilterChainMatch__Output = _envoy_api_v2_listener_FilterChainMatch__Output; - export type ListenerFilter = _envoy_api_v2_listener_ListenerFilter; - export type ListenerFilter__Output = _envoy_api_v2_listener_ListenerFilter__Output; - /** - * Listener filter chain match configuration. This is a recursive structure which allows complex - * nested match configurations to be built using various logical operators. - * - * Examples: - * - * * Matches if the destination port is 3306. - * - * .. code-block:: yaml - * - * destination_port_range: - * start: 3306 - * end: 3307 - * - * * Matches if the destination port is 3306 or 15000. - * - * .. code-block:: yaml - * - * or_match: - * rules: - * - destination_port_range: - * start: 3306 - * end: 3306 - * - destination_port_range: - * start: 15000 - * end: 15001 - * - * [#next-free-field: 6] - */ - export type ListenerFilterChainMatchPredicate = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate; - /** - * Listener filter chain match configuration. This is a recursive structure which allows complex - * nested match configurations to be built using various logical operators. - * - * Examples: - * - * * Matches if the destination port is 3306. - * - * .. code-block:: yaml - * - * destination_port_range: - * start: 3306 - * end: 3307 - * - * * Matches if the destination port is 3306 or 15000. - * - * .. code-block:: yaml - * - * or_match: - * rules: - * - destination_port_range: - * start: 3306 - * end: 3306 - * - destination_port_range: - * start: 15000 - * end: 15001 - * - * [#next-free-field: 6] - */ - export type ListenerFilterChainMatchPredicate__Output = _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output; - export type UdpListenerConfig = _envoy_api_v2_listener_UdpListenerConfig; - export type UdpListenerConfig__Output = _envoy_api_v2_listener_UdpListenerConfig__Output; - } - export namespace route { - /** - * [#next-free-field: 12] - */ - export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; - /** - * [#next-free-field: 12] - */ - export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; - export type Decorator = _envoy_api_v2_route_Decorator; - export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; - export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; - export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; - /** - * A filter-defined action type. - */ - export type FilterAction = _envoy_api_v2_route_FilterAction; - /** - * A filter-defined action type. - */ - export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; - /** - * .. attention:: - * - * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* - * header. Thus, if attempting to match on *Host*, match on *:authority* instead. - * - * .. attention:: - * - * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both - * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., - * - * .. code-block:: json - * - * { - * "name": ":method", - * "exact_match": "POST" - * } - * - * .. attention:: - * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's - * value. - * - * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 12] - */ - export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; - /** - * .. attention:: - * - * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* - * header. Thus, if attempting to match on *Host*, match on *:authority* instead. - * - * .. attention:: - * - * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both - * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., - * - * .. code-block:: json - * - * { - * "name": ":method", - * "exact_match": "POST" - * } - * - * .. attention:: - * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's - * value. - * - * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 12] - */ - export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; - /** - * HTTP request hedging :ref:`architecture overview `. - */ - export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; - /** - * HTTP request hedging :ref:`architecture overview `. - */ - export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; - /** - * Query parameter matching treats the query string of a request's :path header - * as an ampersand-separated list of keys and/or key=value elements. - * [#next-free-field: 7] - */ - export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; - /** - * Query parameter matching treats the query string of a request's :path header - * as an ampersand-separated list of keys and/or key=value elements. - * [#next-free-field: 7] - */ - export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; - /** - * Global rate limiting :ref:`architecture overview `. - */ - export type RateLimit = _envoy_api_v2_route_RateLimit; - /** - * Global rate limiting :ref:`architecture overview `. - */ - export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; - /** - * [#next-free-field: 9] - */ - export type RedirectAction = _envoy_api_v2_route_RedirectAction; - /** - * [#next-free-field: 9] - */ - export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; - /** - * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 11] - */ - export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; - /** - * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 11] - */ - export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; - /** - * A route is both a specification of how to match a request as well as an indication of what to do - * next (e.g., redirect, forward, rewrite, etc.). - * - * .. attention:: - * - * Envoy supports routing on HTTP method via :ref:`header matching - * `. - * [#next-free-field: 18] - */ - export type Route = _envoy_api_v2_route_Route; - /** - * A route is both a specification of how to match a request as well as an indication of what to do - * next (e.g., redirect, forward, rewrite, etc.). - * - * .. attention:: - * - * Envoy supports routing on HTTP method via :ref:`header matching - * `. - * [#next-free-field: 18] - */ - export type Route__Output = _envoy_api_v2_route_Route__Output; - /** - * [#next-free-field: 34] - */ - export type RouteAction = _envoy_api_v2_route_RouteAction; - /** - * [#next-free-field: 34] - */ - export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; - /** - * [#next-free-field: 12] - */ - export type RouteMatch = _envoy_api_v2_route_RouteMatch; - /** - * [#next-free-field: 12] - */ - export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; - export type Tracing = _envoy_api_v2_route_Tracing; - export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; - /** - * A virtual cluster is a way of specifying a regex matching rule against - * certain important endpoints such that statistics are generated explicitly for - * the matched requests. The reason this is useful is that when doing - * prefix/path matching Envoy does not always know what the application - * considers to be an endpoint. Thus, it’s impossible for Envoy to generically - * emit per endpoint statistics. However, often systems have highly critical - * endpoints that they wish to get “perfect†statistics on. Virtual cluster - * statistics are perfect in the sense that they are emitted on the downstream - * side such that they include network level failures. - * - * Documentation for :ref:`virtual cluster statistics `. - * - * .. note:: - * - * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for - * every application endpoint. This is both not easily maintainable and as well the matching and - * statistics output are not free. - */ - export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; - /** - * A virtual cluster is a way of specifying a regex matching rule against - * certain important endpoints such that statistics are generated explicitly for - * the matched requests. The reason this is useful is that when doing - * prefix/path matching Envoy does not always know what the application - * considers to be an endpoint. Thus, it’s impossible for Envoy to generically - * emit per endpoint statistics. However, often systems have highly critical - * endpoints that they wish to get “perfect†statistics on. Virtual cluster - * statistics are perfect in the sense that they are emitted on the downstream - * side such that they include network level failures. - * - * Documentation for :ref:`virtual cluster statistics `. - * - * .. note:: - * - * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for - * every application endpoint. This is both not easily maintainable and as well the matching and - * statistics output are not free. - */ - export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; - /** - * The top level element in the routing configuration is a virtual host. Each virtual host has - * a logical name as well as a set of domains that get routed to it based on the incoming request's - * host header. This allows a single listener to service multiple top level domain path trees. Once - * a virtual host is selected based on the domain, the routes are processed in order to see which - * upstream cluster to route to or whether to perform a redirect. - * [#next-free-field: 21] - */ - export type VirtualHost = _envoy_api_v2_route_VirtualHost; - /** - * The top level element in the routing configuration is a virtual host. Each virtual host has - * a logical name as well as a set of domains that get routed to it based on the incoming request's - * host header. This allows a single listener to service multiple top level domain path trees. Once - * a virtual host is selected based on the domain, the routes are processed in order to see which - * upstream cluster to route to or whether to perform a redirect. - * [#next-free-field: 21] - */ - export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; - /** - * Compared to the :ref:`cluster ` field that specifies a - * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of - * multiple upstream clusters along with weights that indicate the percentage of - * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the - * weights. - */ - export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; - /** - * Compared to the :ref:`cluster ` field that specifies a - * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of - * multiple upstream clusters along with weights that indicate the percentage of - * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the - * weights. - */ - export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; - } - } - } - export namespace config { - export namespace filter { - export namespace accesslog { - export namespace v2 { - export type AccessLog = _envoy_config_filter_accesslog_v2_AccessLog; - export type AccessLog__Output = _envoy_config_filter_accesslog_v2_AccessLog__Output; - /** - * [#next-free-field: 12] - */ - export type AccessLogFilter = _envoy_config_filter_accesslog_v2_AccessLogFilter; - /** - * [#next-free-field: 12] - */ - export type AccessLogFilter__Output = _envoy_config_filter_accesslog_v2_AccessLogFilter__Output; - /** - * Performs a logical “and†operation on the result of each filter in filters. - * Filters are evaluated sequentially and if one of them returns false, the - * filter returns false immediately. - */ - export type AndFilter = _envoy_config_filter_accesslog_v2_AndFilter; - /** - * Performs a logical “and†operation on the result of each filter in filters. - * Filters are evaluated sequentially and if one of them returns false, the - * filter returns false immediately. - */ - export type AndFilter__Output = _envoy_config_filter_accesslog_v2_AndFilter__Output; - /** - * Filter on an integer comparison. - */ - export type ComparisonFilter = _envoy_config_filter_accesslog_v2_ComparisonFilter; - /** - * Filter on an integer comparison. - */ - export type ComparisonFilter__Output = _envoy_config_filter_accesslog_v2_ComparisonFilter__Output; - /** - * Filters on total request duration in milliseconds. - */ - export type DurationFilter = _envoy_config_filter_accesslog_v2_DurationFilter; - /** - * Filters on total request duration in milliseconds. - */ - export type DurationFilter__Output = _envoy_config_filter_accesslog_v2_DurationFilter__Output; - /** - * Extension filter is statically registered at runtime. - */ - export type ExtensionFilter = _envoy_config_filter_accesslog_v2_ExtensionFilter; - /** - * Extension filter is statically registered at runtime. - */ - export type ExtensionFilter__Output = _envoy_config_filter_accesslog_v2_ExtensionFilter__Output; - /** - * Filters gRPC requests based on their response status. If a gRPC status is not provided, the - * filter will infer the status from the HTTP status code. - */ - export type GrpcStatusFilter = _envoy_config_filter_accesslog_v2_GrpcStatusFilter; - /** - * Filters gRPC requests based on their response status. If a gRPC status is not provided, the - * filter will infer the status from the HTTP status code. - */ - export type GrpcStatusFilter__Output = _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output; - /** - * Filters requests based on the presence or value of a request header. - */ - export type HeaderFilter = _envoy_config_filter_accesslog_v2_HeaderFilter; - /** - * Filters requests based on the presence or value of a request header. - */ - export type HeaderFilter__Output = _envoy_config_filter_accesslog_v2_HeaderFilter__Output; - /** - * Filters for requests that are not health check requests. A health check - * request is marked by the health check filter. - */ - export type NotHealthCheckFilter = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter; - /** - * Filters for requests that are not health check requests. A health check - * request is marked by the health check filter. - */ - export type NotHealthCheckFilter__Output = _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output; - /** - * Performs a logical “or†operation on the result of each individual filter. - * Filters are evaluated sequentially and if one of them returns true, the - * filter returns true immediately. - */ - export type OrFilter = _envoy_config_filter_accesslog_v2_OrFilter; - /** - * Performs a logical “or†operation on the result of each individual filter. - * Filters are evaluated sequentially and if one of them returns true, the - * filter returns true immediately. - */ - export type OrFilter__Output = _envoy_config_filter_accesslog_v2_OrFilter__Output; - /** - * Filters requests that received responses with an Envoy response flag set. - * A list of the response flags can be found - * in the access log formatter :ref:`documentation`. - */ - export type ResponseFlagFilter = _envoy_config_filter_accesslog_v2_ResponseFlagFilter; - /** - * Filters requests that received responses with an Envoy response flag set. - * A list of the response flags can be found - * in the access log formatter :ref:`documentation`. - */ - export type ResponseFlagFilter__Output = _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output; - /** - * Filters for random sampling of requests. - */ - export type RuntimeFilter = _envoy_config_filter_accesslog_v2_RuntimeFilter; - /** - * Filters for random sampling of requests. - */ - export type RuntimeFilter__Output = _envoy_config_filter_accesslog_v2_RuntimeFilter__Output; - /** - * Filters on HTTP response/status code. - */ - export type StatusCodeFilter = _envoy_config_filter_accesslog_v2_StatusCodeFilter; - /** - * Filters on HTTP response/status code. - */ - export type StatusCodeFilter__Output = _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output; - /** - * Filters for requests that are traceable. See the tracing overview for more - * information on how a request becomes traceable. - */ - export type TraceableFilter = _envoy_config_filter_accesslog_v2_TraceableFilter; - /** - * Filters for requests that are traceable. See the tracing overview for more - * information on how a request becomes traceable. - */ - export type TraceableFilter__Output = _envoy_config_filter_accesslog_v2_TraceableFilter__Output; - } - } - } - export namespace listener { - export namespace v2 { - /** - * Describes a type of API listener, which is used in non-proxy clients. The type of API - * exposed to the non-proxy application depends on the type of API listener. - */ - export type ApiListener = _envoy_config_listener_v2_ApiListener; - /** - * Describes a type of API listener, which is used in non-proxy clients. The type of API - * exposed to the non-proxy application depends on the type of API listener. - */ - export type ApiListener__Output = _envoy_config_listener_v2_ApiListener__Output; - } - } - } - export namespace type { - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange = _envoy_type_DoubleRange; - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent = _envoy_type_FractionalPercent; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range = _envoy_type_Int32Range; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range__Output = _envoy_type_Int32Range__Output; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range = _envoy_type_Int64Range; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range__Output = _envoy_type_Int64Range__Output; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent = _envoy_type_Percent; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent__Output = _envoy_type_Percent__Output; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion = _envoy_type_SemanticVersion; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - export namespace matcher { - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher = _envoy_type_matcher_StringMatcher; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - } - export namespace metadata { - export namespace v2 { - /** - * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. - * - * For example, for the following Metadata: - * - * .. code-block:: yaml - * - * filter_metadata: - * envoy.xxx: - * prop: - * foo: bar - * xyz: - * hello: envoy - * - * The following MetadataKey will retrieve a string value "bar" from the Metadata. - * - * .. code-block:: yaml - * - * key: envoy.xxx - * path: - * - key: prop - * - key: foo - */ - export type MetadataKey = _envoy_type_metadata_v2_MetadataKey; - /** - * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. - * - * For example, for the following Metadata: - * - * .. code-block:: yaml - * - * filter_metadata: - * envoy.xxx: - * prop: - * foo: bar - * xyz: - * hello: envoy - * - * The following MetadataKey will retrieve a string value "bar" from the Metadata. - * - * .. code-block:: yaml - * - * key: envoy.xxx - * path: - * - key: prop - * - key: foo - */ - export type MetadataKey__Output = _envoy_type_metadata_v2_MetadataKey__Output; - /** - * Describes what kind of metadata. - */ - export type MetadataKind = _envoy_type_metadata_v2_MetadataKind; - /** - * Describes what kind of metadata. - */ - export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; - } - } - export namespace tracing { - export namespace v2 { - /** - * Describes custom tags for the active span. - * [#next-free-field: 6] - */ - export type CustomTag = _envoy_type_tracing_v2_CustomTag; - /** - * Describes custom tags for the active span. - * [#next-free-field: 6] - */ - export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; - } - } - } - } - export namespace google { - export namespace api { - /** - * A custom pattern is used for defining custom HTTP verb. - */ - export type CustomHttpPattern = _google_api_CustomHttpPattern; - /** - * A custom pattern is used for defining custom HTTP verb. - */ - export type CustomHttpPattern__Output = _google_api_CustomHttpPattern__Output; - /** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ - export type Http = _google_api_Http; - /** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ - export type Http__Output = _google_api_Http__Output; - /** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ - export type HttpRule = _google_api_HttpRule; - /** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ - export type HttpRule__Output = _google_api_HttpRule__Output; - } - export namespace protobuf { - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type BoolValue = _google_protobuf_BoolValue; - export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type BytesValue = _google_protobuf_BytesValue; - export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type DescriptorProto = _google_protobuf_DescriptorProto; - export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; - export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; - export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; - export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileOptions = _google_protobuf_FileOptions; - export type FileOptions__Output = _google_protobuf_FileOptions__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type MessageOptions = _google_protobuf_MessageOptions; - export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type NullValue = _google_protobuf_NullValue; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; - export type OneofOptions = _google_protobuf_OneofOptions; - export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type ServiceOptions = _google_protobuf_ServiceOptions; - export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; - export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - } - } - export namespace udpa { - export namespace annotations { - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules = _validate_AnyRules; - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules__Output = _validate_AnyRules__Output; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules = _validate_BoolRules; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules__Output = _validate_BoolRules__Output; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules = _validate_BytesRules; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules__Output = _validate_BytesRules__Output; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules = _validate_DoubleRules; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules__Output = _validate_DoubleRules__Output; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules = _validate_DurationRules; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules__Output = _validate_DurationRules__Output; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules = _validate_EnumRules; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules__Output = _validate_EnumRules__Output; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules = _validate_FieldRules; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules__Output = _validate_FieldRules__Output; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules = _validate_Fixed32Rules; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules = _validate_Fixed64Rules; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules = _validate_FloatRules; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules__Output = _validate_FloatRules__Output; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules = _validate_Int32Rules; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules__Output = _validate_Int32Rules__Output; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules = _validate_Int64Rules; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules__Output = _validate_Int64Rules__Output; - /** - * WellKnownRegex contain some well-known patterns. - */ - export type KnownRegex = _validate_KnownRegex; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules = _validate_MapRules; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules__Output = _validate_MapRules__Output; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules = _validate_MessageRules; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules__Output = _validate_MessageRules__Output; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules = _validate_RepeatedRules; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules = _validate_SFixed32Rules; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules = _validate_SFixed64Rules; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules = _validate_SInt32Rules; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules = _validate_SInt64Rules; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules = _validate_StringRules; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules__Output = _validate_StringRules__Output; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules = _validate_TimestampRules; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules__Output = _validate_TimestampRules__Output; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules = _validate_UInt32Rules; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules = _validate_UInt64Rules; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - } -} - -export namespace ClientInterfaces { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace Listener { - export namespace ConnectionBalanceConfig { - export namespace ExactBalance { - } - } - export namespace DeprecatedV1 { - } - } - export namespace auth { - export namespace CertificateValidationContext { - } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } - } - export namespace DownstreamTlsContext { - } - export namespace GenericSecret { - } - export namespace PrivateKeyProvider { - } - export namespace SdsSecretConfig { - } - export namespace Secret { - } - export namespace TlsCertificate { - } - export namespace TlsParameters { - } - export namespace TlsSessionTicketKeys { - } - export namespace UpstreamTlsContext { - } - } - export namespace core { - export namespace Address { - } - export namespace AggregatedConfigSource { - } - export namespace ApiConfigSource { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ConfigSource { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace Extension { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RateLimitSettings { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SelfConfigSource { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - export namespace listener { - export namespace ActiveRawUdpListenerConfig { - } - export namespace Filter { - } - export namespace FilterChain { - } - export namespace FilterChainMatch { - } - export namespace ListenerFilter { - } - export namespace ListenerFilterChainMatchPredicate { - export namespace MatchSet { - } - } - export namespace UdpListenerConfig { - } - } - export namespace route { - export namespace CorsPolicy { - } - export namespace Decorator { - } - export namespace DirectResponseAction { - } - export namespace FilterAction { - } - export namespace HeaderMatcher { - } - export namespace HedgePolicy { - } - export namespace QueryParameterMatcher { - } - export namespace RateLimit { - export namespace Action { - export namespace DestinationCluster { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - export namespace RemoteAddress { - } - export namespace RequestHeaders { - } - export namespace SourceCluster { - } - } - } - export namespace RedirectAction { - } - export namespace RetryPolicy { - export namespace RetryBackOff { - } - export namespace RetryHostPredicate { - } - export namespace RetryPriority { - } - } - export namespace Route { - } - export namespace RouteAction { - export namespace HashPolicy { - export namespace ConnectionProperties { - } - export namespace Cookie { - } - export namespace FilterState { - } - export namespace Header { - } - export namespace QueryParameter { - } - } - export namespace RequestMirrorPolicy { - } - export namespace UpgradeConfig { - } - } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { - } - export namespace TlsContextMatchOptions { - } - } - export namespace Tracing { - } - export namespace VirtualCluster { - } - export namespace VirtualHost { - } - export namespace WeightedCluster { - export namespace ClusterWeight { - } - } - } - } - } - export namespace config { - export namespace filter { - export namespace accesslog { - export namespace v2 { - export namespace AccessLog { - } - export namespace AccessLogFilter { - } - export namespace AndFilter { - } - export namespace ComparisonFilter { - } - export namespace DurationFilter { - } - export namespace ExtensionFilter { - } - export namespace GrpcStatusFilter { - } - export namespace HeaderFilter { - } - export namespace NotHealthCheckFilter { - } - export namespace OrFilter { - } - export namespace ResponseFlagFilter { - } - export namespace RuntimeFilter { - } - export namespace StatusCodeFilter { - } - export namespace TraceableFilter { - } - } - } - } - export namespace listener { - export namespace v2 { - export namespace ApiListener { - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - export namespace metadata { - export namespace v2 { - export namespace MetadataKey { - export namespace PathSegment { - } - } - export namespace MetadataKind { - export namespace Cluster { - } - export namespace Host { - } - export namespace Request { - } - export namespace Route { - } - } - } - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Environment { - } - export namespace Header { - } - export namespace Literal { - } - export namespace Metadata { - } - } - } - } - } - } - export namespace google { - export namespace api { - export namespace CustomHttpPattern { - } - export namespace Http { - } - export namespace HttpRule { - } - } - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { @@ -2929,485 +232,3 @@ export interface ProtoGrpcType { } } -export namespace ServiceHandlers { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace Listener { - export namespace ConnectionBalanceConfig { - export namespace ExactBalance { - } - } - export namespace DeprecatedV1 { - } - } - export namespace auth { - export namespace CertificateValidationContext { - } - export namespace CommonTlsContext { - export namespace CombinedCertificateValidationContext { - } - } - export namespace DownstreamTlsContext { - } - export namespace GenericSecret { - } - export namespace PrivateKeyProvider { - } - export namespace SdsSecretConfig { - } - export namespace Secret { - } - export namespace TlsCertificate { - } - export namespace TlsParameters { - } - export namespace TlsSessionTicketKeys { - } - export namespace UpstreamTlsContext { - } - } - export namespace core { - export namespace Address { - } - export namespace AggregatedConfigSource { - } - export namespace ApiConfigSource { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ConfigSource { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace Extension { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RateLimitSettings { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SelfConfigSource { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - export namespace listener { - export namespace ActiveRawUdpListenerConfig { - } - export namespace Filter { - } - export namespace FilterChain { - } - export namespace FilterChainMatch { - } - export namespace ListenerFilter { - } - export namespace ListenerFilterChainMatchPredicate { - export namespace MatchSet { - } - } - export namespace UdpListenerConfig { - } - } - export namespace route { - export namespace CorsPolicy { - } - export namespace Decorator { - } - export namespace DirectResponseAction { - } - export namespace FilterAction { - } - export namespace HeaderMatcher { - } - export namespace HedgePolicy { - } - export namespace QueryParameterMatcher { - } - export namespace RateLimit { - export namespace Action { - export namespace DestinationCluster { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - export namespace RemoteAddress { - } - export namespace RequestHeaders { - } - export namespace SourceCluster { - } - } - } - export namespace RedirectAction { - } - export namespace RetryPolicy { - export namespace RetryBackOff { - } - export namespace RetryHostPredicate { - } - export namespace RetryPriority { - } - } - export namespace Route { - } - export namespace RouteAction { - export namespace HashPolicy { - export namespace ConnectionProperties { - } - export namespace Cookie { - } - export namespace FilterState { - } - export namespace Header { - } - export namespace QueryParameter { - } - } - export namespace RequestMirrorPolicy { - } - export namespace UpgradeConfig { - } - } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { - } - export namespace TlsContextMatchOptions { - } - } - export namespace Tracing { - } - export namespace VirtualCluster { - } - export namespace VirtualHost { - } - export namespace WeightedCluster { - export namespace ClusterWeight { - } - } - } - } - } - export namespace config { - export namespace filter { - export namespace accesslog { - export namespace v2 { - export namespace AccessLog { - } - export namespace AccessLogFilter { - } - export namespace AndFilter { - } - export namespace ComparisonFilter { - } - export namespace DurationFilter { - } - export namespace ExtensionFilter { - } - export namespace GrpcStatusFilter { - } - export namespace HeaderFilter { - } - export namespace NotHealthCheckFilter { - } - export namespace OrFilter { - } - export namespace ResponseFlagFilter { - } - export namespace RuntimeFilter { - } - export namespace StatusCodeFilter { - } - export namespace TraceableFilter { - } - } - } - } - export namespace listener { - export namespace v2 { - export namespace ApiListener { - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - export namespace metadata { - export namespace v2 { - export namespace MetadataKey { - export namespace PathSegment { - } - } - export namespace MetadataKind { - export namespace Cluster { - } - export namespace Host { - } - export namespace Request { - } - export namespace Route { - } - } - } - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Environment { - } - export namespace Header { - } - export namespace Literal { - } - export namespace Metadata { - } - } - } - } - } - } - export namespace google { - export namespace api { - export namespace CustomHttpPattern { - } - export namespace Http { - } - export namespace HttpRule { - } - } - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} diff --git a/packages/grpc-js/src/generated/route.ts b/packages/grpc-js/src/generated/route.ts index 2a676be88..5b251477a 100644 --- a/packages/grpc-js/src/generated/route.ts +++ b/packages/grpc-js/src/generated/route.ts @@ -1,1648 +1,6 @@ import * as grpc from '../index'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from './envoy/api/v2/RouteConfiguration'; -import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from './envoy/api/v2/Vhds'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from './envoy/api/v2/core/Address'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from './envoy/api/v2/core/AggregatedConfigSource'; -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from './envoy/api/v2/core/ApiConfigSource'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from './envoy/api/v2/core/ApiVersion'; -import { AsyncDataSource as _envoy_api_v2_core_AsyncDataSource, AsyncDataSource__Output as _envoy_api_v2_core_AsyncDataSource__Output } from './envoy/api/v2/core/AsyncDataSource'; -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from './envoy/api/v2/core/BackoffStrategy'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from './envoy/api/v2/core/BindConfig'; -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from './envoy/api/v2/core/BuildVersion'; -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from './envoy/api/v2/core/CidrRange'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from './envoy/api/v2/core/ConfigSource'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from './envoy/api/v2/core/ControlPlane'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from './envoy/api/v2/core/DataSource'; -import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from './envoy/api/v2/core/Extension'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from './envoy/api/v2/core/GrpcService'; -import { HeaderMap as _envoy_api_v2_core_HeaderMap, HeaderMap__Output as _envoy_api_v2_core_HeaderMap__Output } from './envoy/api/v2/core/HeaderMap'; -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from './envoy/api/v2/core/HeaderValue'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from './envoy/api/v2/core/HeaderValueOption'; -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from './envoy/api/v2/core/HttpUri'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from './envoy/api/v2/core/Locality'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from './envoy/api/v2/core/Metadata'; -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from './envoy/api/v2/core/Node'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from './envoy/api/v2/core/Pipe'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from './envoy/api/v2/core/RateLimitSettings'; -import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from './envoy/api/v2/core/RemoteDataSource'; -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from './envoy/api/v2/core/RequestMethod'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from './envoy/api/v2/core/RetryPolicy'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from './envoy/api/v2/core/RoutingPriority'; -import { RuntimeDouble as _envoy_api_v2_core_RuntimeDouble, RuntimeDouble__Output as _envoy_api_v2_core_RuntimeDouble__Output } from './envoy/api/v2/core/RuntimeDouble'; -import { RuntimeFeatureFlag as _envoy_api_v2_core_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_api_v2_core_RuntimeFeatureFlag__Output } from './envoy/api/v2/core/RuntimeFeatureFlag'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from './envoy/api/v2/core/RuntimeFractionalPercent'; -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from './envoy/api/v2/core/RuntimeUInt32'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from './envoy/api/v2/core/SelfConfigSource'; -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from './envoy/api/v2/core/SocketAddress'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from './envoy/api/v2/core/SocketOption'; -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from './envoy/api/v2/core/TcpKeepalive'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from './envoy/api/v2/core/TrafficDirection'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from './envoy/api/v2/core/TransportSocket'; -import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from './envoy/api/v2/route/CorsPolicy'; -import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from './envoy/api/v2/route/Decorator'; -import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from './envoy/api/v2/route/DirectResponseAction'; -import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from './envoy/api/v2/route/FilterAction'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from './envoy/api/v2/route/HeaderMatcher'; -import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from './envoy/api/v2/route/HedgePolicy'; -import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from './envoy/api/v2/route/QueryParameterMatcher'; -import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from './envoy/api/v2/route/RateLimit'; -import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from './envoy/api/v2/route/RedirectAction'; -import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from './envoy/api/v2/route/RetryPolicy'; -import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from './envoy/api/v2/route/Route'; -import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from './envoy/api/v2/route/RouteAction'; -import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from './envoy/api/v2/route/RouteMatch'; -import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from './envoy/api/v2/route/Tracing'; -import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from './envoy/api/v2/route/VirtualCluster'; -import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from './envoy/api/v2/route/VirtualHost'; -import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from './envoy/api/v2/route/WeightedCluster'; -import { DoubleRange as _envoy_type_DoubleRange, DoubleRange__Output as _envoy_type_DoubleRange__Output } from './envoy/type/DoubleRange'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from './envoy/type/FractionalPercent'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from './envoy/type/Int32Range'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from './envoy/type/Int64Range'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from './envoy/type/Percent'; -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from './envoy/type/SemanticVersion'; -import { ListStringMatcher as _envoy_type_matcher_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_ListStringMatcher__Output } from './envoy/type/matcher/ListStringMatcher'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from './envoy/type/matcher/RegexMatchAndSubstitute'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from './envoy/type/matcher/RegexMatcher'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from './envoy/type/matcher/StringMatcher'; -import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from './envoy/type/metadata/v2/MetadataKey'; -import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from './envoy/type/metadata/v2/MetadataKind'; -import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from './envoy/type/tracing/v2/CustomTag'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from './google/protobuf/Any'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from './google/protobuf/BoolValue'; -import { BytesValue as _google_protobuf_BytesValue, BytesValue__Output as _google_protobuf_BytesValue__Output } from './google/protobuf/BytesValue'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from './google/protobuf/DescriptorProto'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from './google/protobuf/DoubleValue'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from './google/protobuf/Duration'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from './google/protobuf/Empty'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from './google/protobuf/EnumDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from './google/protobuf/EnumOptions'; -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from './google/protobuf/EnumValueDescriptorProto'; -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from './google/protobuf/EnumValueOptions'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from './google/protobuf/FieldDescriptorProto'; -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from './google/protobuf/FieldOptions'; -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from './google/protobuf/FileDescriptorProto'; -import { FileDescriptorSet as _google_protobuf_FileDescriptorSet, FileDescriptorSet__Output as _google_protobuf_FileDescriptorSet__Output } from './google/protobuf/FileDescriptorSet'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from './google/protobuf/FileOptions'; -import { FloatValue as _google_protobuf_FloatValue, FloatValue__Output as _google_protobuf_FloatValue__Output } from './google/protobuf/FloatValue'; -import { GeneratedCodeInfo as _google_protobuf_GeneratedCodeInfo, GeneratedCodeInfo__Output as _google_protobuf_GeneratedCodeInfo__Output } from './google/protobuf/GeneratedCodeInfo'; -import { Int32Value as _google_protobuf_Int32Value, Int32Value__Output as _google_protobuf_Int32Value__Output } from './google/protobuf/Int32Value'; -import { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from './google/protobuf/Int64Value'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from './google/protobuf/ListValue'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from './google/protobuf/MessageOptions'; -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from './google/protobuf/MethodDescriptorProto'; -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from './google/protobuf/MethodOptions'; -import { NullValue as _google_protobuf_NullValue } from './google/protobuf/NullValue'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from './google/protobuf/OneofDescriptorProto'; -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from './google/protobuf/OneofOptions'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from './google/protobuf/ServiceDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from './google/protobuf/ServiceOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from './google/protobuf/SourceCodeInfo'; -import { StringValue as _google_protobuf_StringValue, StringValue__Output as _google_protobuf_StringValue__Output } from './google/protobuf/StringValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from './google/protobuf/Struct'; -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from './google/protobuf/Timestamp'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from './google/protobuf/UInt32Value'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from './google/protobuf/UInt64Value'; -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from './google/protobuf/UninterpretedOption'; -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from './google/protobuf/Value'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from './udpa/annotations/FieldMigrateAnnotation'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from './udpa/annotations/FileMigrateAnnotation'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from './udpa/annotations/MigrateAnnotation'; -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from './udpa/annotations/PackageVersionStatus'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from './udpa/annotations/StatusAnnotation'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from './validate/AnyRules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from './validate/BoolRules'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from './validate/BytesRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from './validate/DoubleRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from './validate/DurationRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from './validate/EnumRules'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from './validate/FieldRules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from './validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from './validate/Fixed64Rules'; -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from './validate/FloatRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from './validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from './validate/Int64Rules'; -import { KnownRegex as _validate_KnownRegex } from './validate/KnownRegex'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from './validate/MapRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from './validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from './validate/RepeatedRules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from './validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from './validate/SFixed64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from './validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from './validate/SInt64Rules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from './validate/StringRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from './validate/TimestampRules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from './validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from './validate/UInt64Rules'; - -export namespace messages { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - /** - * [#next-free-field: 11] - */ - export type RouteConfiguration = _envoy_api_v2_RouteConfiguration; - /** - * [#next-free-field: 11] - */ - export type RouteConfiguration__Output = _envoy_api_v2_RouteConfiguration__Output; - export type Vhds = _envoy_api_v2_Vhds; - export type Vhds__Output = _envoy_api_v2_Vhds__Output; - export namespace core { - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address = _envoy_api_v2_core_Address; - /** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ - export type Address__Output = _envoy_api_v2_core_Address__Output; - /** - * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that ADS is to be used. - */ - export type AggregatedConfigSource = _envoy_api_v2_core_AggregatedConfigSource; - /** - * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that ADS is to be used. - */ - export type AggregatedConfigSource__Output = _envoy_api_v2_core_AggregatedConfigSource__Output; - /** - * API configuration source. This identifies the API type and cluster that Envoy - * will use to fetch an xDS API. - * [#next-free-field: 9] - */ - export type ApiConfigSource = _envoy_api_v2_core_ApiConfigSource; - /** - * API configuration source. This identifies the API type and cluster that Envoy - * will use to fetch an xDS API. - * [#next-free-field: 9] - */ - export type ApiConfigSource__Output = _envoy_api_v2_core_ApiConfigSource__Output; - /** - * xDS API version. This is used to describe both resource and transport - * protocol versions (in distinct configuration fields). - */ - export type ApiVersion = _envoy_api_v2_core_ApiVersion; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource = _envoy_api_v2_core_AsyncDataSource; - /** - * Async data source which support async data fetch. - */ - export type AsyncDataSource__Output = _envoy_api_v2_core_AsyncDataSource__Output; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy = _envoy_api_v2_core_BackoffStrategy; - /** - * Configuration defining a jittered exponential back off strategy. - */ - export type BackoffStrategy__Output = _envoy_api_v2_core_BackoffStrategy__Output; - export type BindConfig = _envoy_api_v2_core_BindConfig; - export type BindConfig__Output = _envoy_api_v2_core_BindConfig__Output; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion = _envoy_api_v2_core_BuildVersion; - /** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ - export type BuildVersion__Output = _envoy_api_v2_core_BuildVersion__Output; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange = _envoy_api_v2_core_CidrRange; - /** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ - export type CidrRange__Output = _envoy_api_v2_core_CidrRange__Output; - /** - * Configuration for :ref:`listeners `, :ref:`clusters - * `, :ref:`routes - * `, :ref:`endpoints - * ` etc. may either be sourced from the - * filesystem or from an xDS API source. Filesystem configs are watched with - * inotify for updates. - * [#next-free-field: 7] - */ - export type ConfigSource = _envoy_api_v2_core_ConfigSource; - /** - * Configuration for :ref:`listeners `, :ref:`clusters - * `, :ref:`routes - * `, :ref:`endpoints - * ` etc. may either be sourced from the - * filesystem or from an xDS API source. Filesystem configs are watched with - * inotify for updates. - * [#next-free-field: 7] - */ - export type ConfigSource__Output = _envoy_api_v2_core_ConfigSource__Output; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane = _envoy_api_v2_core_ControlPlane; - /** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ - export type ControlPlane__Output = _envoy_api_v2_core_ControlPlane__Output; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource = _envoy_api_v2_core_DataSource; - /** - * Data source consisting of either a file or an inline value. - */ - export type DataSource__Output = _envoy_api_v2_core_DataSource__Output; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension = _envoy_api_v2_core_Extension; - /** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ - export type Extension__Output = _envoy_api_v2_core_Extension__Output; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService = _envoy_api_v2_core_GrpcService; - /** - * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. - * [#next-free-field: 6] - */ - export type GrpcService__Output = _envoy_api_v2_core_GrpcService__Output; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap = _envoy_api_v2_core_HeaderMap; - /** - * Wrapper for a set of headers. - */ - export type HeaderMap__Output = _envoy_api_v2_core_HeaderMap__Output; - /** - * Header name/value pair. - */ - export type HeaderValue = _envoy_api_v2_core_HeaderValue; - /** - * Header name/value pair. - */ - export type HeaderValue__Output = _envoy_api_v2_core_HeaderValue__Output; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption = _envoy_api_v2_core_HeaderValueOption; - /** - * Header name/value pair plus option to control append behavior. - */ - export type HeaderValueOption__Output = _envoy_api_v2_core_HeaderValueOption__Output; - /** - * Envoy external URI descriptor - */ - export type HttpUri = _envoy_api_v2_core_HttpUri; - /** - * Envoy external URI descriptor - */ - export type HttpUri__Output = _envoy_api_v2_core_HttpUri__Output; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality = _envoy_api_v2_core_Locality; - /** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ - export type Locality__Output = _envoy_api_v2_core_Locality__Output; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata = _envoy_api_v2_core_Metadata; - /** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ - export type Metadata__Output = _envoy_api_v2_core_Metadata__Output; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node = _envoy_api_v2_core_Node; - /** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ - export type Node__Output = _envoy_api_v2_core_Node__Output; - export type Pipe = _envoy_api_v2_core_Pipe; - export type Pipe__Output = _envoy_api_v2_core_Pipe__Output; - /** - * Rate Limit settings to be applied for discovery requests made by Envoy. - */ - export type RateLimitSettings = _envoy_api_v2_core_RateLimitSettings; - /** - * Rate Limit settings to be applied for discovery requests made by Envoy. - */ - export type RateLimitSettings__Output = _envoy_api_v2_core_RateLimitSettings__Output; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource = _envoy_api_v2_core_RemoteDataSource; - /** - * The message specifies how to fetch data from remote and how to verify it. - */ - export type RemoteDataSource__Output = _envoy_api_v2_core_RemoteDataSource__Output; - /** - * HTTP request method. - */ - export type RequestMethod = _envoy_api_v2_core_RequestMethod; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy = _envoy_api_v2_core_RetryPolicy; - /** - * The message specifies the retry policy of remote data source when fetching fails. - */ - export type RetryPolicy__Output = _envoy_api_v2_core_RetryPolicy__Output; - /** - * Envoy supports :ref:`upstream priority routing - * ` both at the route and the virtual - * cluster level. The current priority implementation uses different connection - * pool and circuit breaking settings for each priority level. This means that - * even for HTTP/2 requests, two physical connections will be used to an - * upstream host. In the future Envoy will likely support true HTTP/2 priority - * over a single upstream connection. - */ - export type RoutingPriority = _envoy_api_v2_core_RoutingPriority; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble = _envoy_api_v2_core_RuntimeDouble; - /** - * Runtime derived double with a default when not specified. - */ - export type RuntimeDouble__Output = _envoy_api_v2_core_RuntimeDouble__Output; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag = _envoy_api_v2_core_RuntimeFeatureFlag; - /** - * Runtime derived bool with a default when not specified. - */ - export type RuntimeFeatureFlag__Output = _envoy_api_v2_core_RuntimeFeatureFlag__Output; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent = _envoy_api_v2_core_RuntimeFractionalPercent; - /** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ - export type RuntimeFractionalPercent__Output = _envoy_api_v2_core_RuntimeFractionalPercent__Output; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32 = _envoy_api_v2_core_RuntimeUInt32; - /** - * Runtime derived uint32 with a default when not specified. - */ - export type RuntimeUInt32__Output = _envoy_api_v2_core_RuntimeUInt32__Output; - /** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ - export type SelfConfigSource = _envoy_api_v2_core_SelfConfigSource; - /** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ - export type SelfConfigSource__Output = _envoy_api_v2_core_SelfConfigSource__Output; - /** - * [#next-free-field: 7] - */ - export type SocketAddress = _envoy_api_v2_core_SocketAddress; - /** - * [#next-free-field: 7] - */ - export type SocketAddress__Output = _envoy_api_v2_core_SocketAddress__Output; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption = _envoy_api_v2_core_SocketOption; - /** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ - export type SocketOption__Output = _envoy_api_v2_core_SocketOption__Output; - export type TcpKeepalive = _envoy_api_v2_core_TcpKeepalive; - export type TcpKeepalive__Output = _envoy_api_v2_core_TcpKeepalive__Output; - /** - * Identifies the direction of the traffic relative to the local Envoy. - */ - export type TrafficDirection = _envoy_api_v2_core_TrafficDirection; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket = _envoy_api_v2_core_TransportSocket; - /** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ - export type TransportSocket__Output = _envoy_api_v2_core_TransportSocket__Output; - } - export namespace route { - /** - * [#next-free-field: 12] - */ - export type CorsPolicy = _envoy_api_v2_route_CorsPolicy; - /** - * [#next-free-field: 12] - */ - export type CorsPolicy__Output = _envoy_api_v2_route_CorsPolicy__Output; - export type Decorator = _envoy_api_v2_route_Decorator; - export type Decorator__Output = _envoy_api_v2_route_Decorator__Output; - export type DirectResponseAction = _envoy_api_v2_route_DirectResponseAction; - export type DirectResponseAction__Output = _envoy_api_v2_route_DirectResponseAction__Output; - /** - * A filter-defined action type. - */ - export type FilterAction = _envoy_api_v2_route_FilterAction; - /** - * A filter-defined action type. - */ - export type FilterAction__Output = _envoy_api_v2_route_FilterAction__Output; - /** - * .. attention:: - * - * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* - * header. Thus, if attempting to match on *Host*, match on *:authority* instead. - * - * .. attention:: - * - * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both - * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., - * - * .. code-block:: json - * - * { - * "name": ":method", - * "exact_match": "POST" - * } - * - * .. attention:: - * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's - * value. - * - * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 12] - */ - export type HeaderMatcher = _envoy_api_v2_route_HeaderMatcher; - /** - * .. attention:: - * - * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 *Host* - * header. Thus, if attempting to match on *Host*, match on *:authority* instead. - * - * .. attention:: - * - * To route on HTTP method, use the special HTTP/2 *:method* header. This works for both - * HTTP/1 and HTTP/2 as Envoy normalizes headers. E.g., - * - * .. code-block:: json - * - * { - * "name": ":method", - * "exact_match": "POST" - * } - * - * .. attention:: - * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's - * value. - * - * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 12] - */ - export type HeaderMatcher__Output = _envoy_api_v2_route_HeaderMatcher__Output; - /** - * HTTP request hedging :ref:`architecture overview `. - */ - export type HedgePolicy = _envoy_api_v2_route_HedgePolicy; - /** - * HTTP request hedging :ref:`architecture overview `. - */ - export type HedgePolicy__Output = _envoy_api_v2_route_HedgePolicy__Output; - /** - * Query parameter matching treats the query string of a request's :path header - * as an ampersand-separated list of keys and/or key=value elements. - * [#next-free-field: 7] - */ - export type QueryParameterMatcher = _envoy_api_v2_route_QueryParameterMatcher; - /** - * Query parameter matching treats the query string of a request's :path header - * as an ampersand-separated list of keys and/or key=value elements. - * [#next-free-field: 7] - */ - export type QueryParameterMatcher__Output = _envoy_api_v2_route_QueryParameterMatcher__Output; - /** - * Global rate limiting :ref:`architecture overview `. - */ - export type RateLimit = _envoy_api_v2_route_RateLimit; - /** - * Global rate limiting :ref:`architecture overview `. - */ - export type RateLimit__Output = _envoy_api_v2_route_RateLimit__Output; - /** - * [#next-free-field: 9] - */ - export type RedirectAction = _envoy_api_v2_route_RedirectAction; - /** - * [#next-free-field: 9] - */ - export type RedirectAction__Output = _envoy_api_v2_route_RedirectAction__Output; - /** - * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 11] - */ - export type RetryPolicy = _envoy_api_v2_route_RetryPolicy; - /** - * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 11] - */ - export type RetryPolicy__Output = _envoy_api_v2_route_RetryPolicy__Output; - /** - * A route is both a specification of how to match a request as well as an indication of what to do - * next (e.g., redirect, forward, rewrite, etc.). - * - * .. attention:: - * - * Envoy supports routing on HTTP method via :ref:`header matching - * `. - * [#next-free-field: 18] - */ - export type Route = _envoy_api_v2_route_Route; - /** - * A route is both a specification of how to match a request as well as an indication of what to do - * next (e.g., redirect, forward, rewrite, etc.). - * - * .. attention:: - * - * Envoy supports routing on HTTP method via :ref:`header matching - * `. - * [#next-free-field: 18] - */ - export type Route__Output = _envoy_api_v2_route_Route__Output; - /** - * [#next-free-field: 34] - */ - export type RouteAction = _envoy_api_v2_route_RouteAction; - /** - * [#next-free-field: 34] - */ - export type RouteAction__Output = _envoy_api_v2_route_RouteAction__Output; - /** - * [#next-free-field: 12] - */ - export type RouteMatch = _envoy_api_v2_route_RouteMatch; - /** - * [#next-free-field: 12] - */ - export type RouteMatch__Output = _envoy_api_v2_route_RouteMatch__Output; - export type Tracing = _envoy_api_v2_route_Tracing; - export type Tracing__Output = _envoy_api_v2_route_Tracing__Output; - /** - * A virtual cluster is a way of specifying a regex matching rule against - * certain important endpoints such that statistics are generated explicitly for - * the matched requests. The reason this is useful is that when doing - * prefix/path matching Envoy does not always know what the application - * considers to be an endpoint. Thus, it’s impossible for Envoy to generically - * emit per endpoint statistics. However, often systems have highly critical - * endpoints that they wish to get “perfect†statistics on. Virtual cluster - * statistics are perfect in the sense that they are emitted on the downstream - * side such that they include network level failures. - * - * Documentation for :ref:`virtual cluster statistics `. - * - * .. note:: - * - * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for - * every application endpoint. This is both not easily maintainable and as well the matching and - * statistics output are not free. - */ - export type VirtualCluster = _envoy_api_v2_route_VirtualCluster; - /** - * A virtual cluster is a way of specifying a regex matching rule against - * certain important endpoints such that statistics are generated explicitly for - * the matched requests. The reason this is useful is that when doing - * prefix/path matching Envoy does not always know what the application - * considers to be an endpoint. Thus, it’s impossible for Envoy to generically - * emit per endpoint statistics. However, often systems have highly critical - * endpoints that they wish to get “perfect†statistics on. Virtual cluster - * statistics are perfect in the sense that they are emitted on the downstream - * side such that they include network level failures. - * - * Documentation for :ref:`virtual cluster statistics `. - * - * .. note:: - * - * Virtual clusters are a useful tool, but we do not recommend setting up a virtual cluster for - * every application endpoint. This is both not easily maintainable and as well the matching and - * statistics output are not free. - */ - export type VirtualCluster__Output = _envoy_api_v2_route_VirtualCluster__Output; - /** - * The top level element in the routing configuration is a virtual host. Each virtual host has - * a logical name as well as a set of domains that get routed to it based on the incoming request's - * host header. This allows a single listener to service multiple top level domain path trees. Once - * a virtual host is selected based on the domain, the routes are processed in order to see which - * upstream cluster to route to or whether to perform a redirect. - * [#next-free-field: 21] - */ - export type VirtualHost = _envoy_api_v2_route_VirtualHost; - /** - * The top level element in the routing configuration is a virtual host. Each virtual host has - * a logical name as well as a set of domains that get routed to it based on the incoming request's - * host header. This allows a single listener to service multiple top level domain path trees. Once - * a virtual host is selected based on the domain, the routes are processed in order to see which - * upstream cluster to route to or whether to perform a redirect. - * [#next-free-field: 21] - */ - export type VirtualHost__Output = _envoy_api_v2_route_VirtualHost__Output; - /** - * Compared to the :ref:`cluster ` field that specifies a - * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of - * multiple upstream clusters along with weights that indicate the percentage of - * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the - * weights. - */ - export type WeightedCluster = _envoy_api_v2_route_WeightedCluster; - /** - * Compared to the :ref:`cluster ` field that specifies a - * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of - * multiple upstream clusters along with weights that indicate the percentage of - * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the - * weights. - */ - export type WeightedCluster__Output = _envoy_api_v2_route_WeightedCluster__Output; - } - } - } - export namespace type { - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange = _envoy_type_DoubleRange; - /** - * Specifies the double start and end of the range using half-open interval semantics [start, - * end). - */ - export type DoubleRange__Output = _envoy_type_DoubleRange__Output; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent = _envoy_type_FractionalPercent; - /** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ - export type FractionalPercent__Output = _envoy_type_FractionalPercent__Output; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range = _envoy_type_Int32Range; - /** - * Specifies the int32 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int32Range__Output = _envoy_type_Int32Range__Output; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range = _envoy_type_Int64Range; - /** - * Specifies the int64 start and end of the range using half-open interval semantics [start, - * end). - */ - export type Int64Range__Output = _envoy_type_Int64Range__Output; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent = _envoy_type_Percent; - /** - * Identifies a percentage, in the range [0.0, 100.0]. - */ - export type Percent__Output = _envoy_type_Percent__Output; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion = _envoy_type_SemanticVersion; - /** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ - export type SemanticVersion__Output = _envoy_type_SemanticVersion__Output; - export namespace matcher { - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher = _envoy_type_matcher_ListStringMatcher; - /** - * Specifies a list of ways to match a string. - */ - export type ListStringMatcher__Output = _envoy_type_matcher_ListStringMatcher__Output; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute = _envoy_type_matcher_RegexMatchAndSubstitute; - /** - * Describes how to match a string and then produce a new string using a regular - * expression and a substitution string. - */ - export type RegexMatchAndSubstitute__Output = _envoy_type_matcher_RegexMatchAndSubstitute__Output; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher = _envoy_type_matcher_RegexMatcher; - /** - * A regex matcher designed for safety when used with untrusted input. - */ - export type RegexMatcher__Output = _envoy_type_matcher_RegexMatcher__Output; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher = _envoy_type_matcher_StringMatcher; - /** - * Specifies the way to match a string. - * [#next-free-field: 7] - */ - export type StringMatcher__Output = _envoy_type_matcher_StringMatcher__Output; - } - export namespace metadata { - export namespace v2 { - /** - * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. - * - * For example, for the following Metadata: - * - * .. code-block:: yaml - * - * filter_metadata: - * envoy.xxx: - * prop: - * foo: bar - * xyz: - * hello: envoy - * - * The following MetadataKey will retrieve a string value "bar" from the Metadata. - * - * .. code-block:: yaml - * - * key: envoy.xxx - * path: - * - key: prop - * - key: foo - */ - export type MetadataKey = _envoy_type_metadata_v2_MetadataKey; - /** - * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. - * - * For example, for the following Metadata: - * - * .. code-block:: yaml - * - * filter_metadata: - * envoy.xxx: - * prop: - * foo: bar - * xyz: - * hello: envoy - * - * The following MetadataKey will retrieve a string value "bar" from the Metadata. - * - * .. code-block:: yaml - * - * key: envoy.xxx - * path: - * - key: prop - * - key: foo - */ - export type MetadataKey__Output = _envoy_type_metadata_v2_MetadataKey__Output; - /** - * Describes what kind of metadata. - */ - export type MetadataKind = _envoy_type_metadata_v2_MetadataKind; - /** - * Describes what kind of metadata. - */ - export type MetadataKind__Output = _envoy_type_metadata_v2_MetadataKind__Output; - } - } - export namespace tracing { - export namespace v2 { - /** - * Describes custom tags for the active span. - * [#next-free-field: 6] - */ - export type CustomTag = _envoy_type_tracing_v2_CustomTag; - /** - * Describes custom tags for the active span. - * [#next-free-field: 6] - */ - export type CustomTag__Output = _envoy_type_tracing_v2_CustomTag__Output; - } - } - } - } - export namespace google { - export namespace protobuf { - export type Any = _google_protobuf_Any; - export type Any__Output = _google_protobuf_Any__Output; - export type BoolValue = _google_protobuf_BoolValue; - export type BoolValue__Output = _google_protobuf_BoolValue__Output; - export type BytesValue = _google_protobuf_BytesValue; - export type BytesValue__Output = _google_protobuf_BytesValue__Output; - export type DescriptorProto = _google_protobuf_DescriptorProto; - export type DescriptorProto__Output = _google_protobuf_DescriptorProto__Output; - export type DoubleValue = _google_protobuf_DoubleValue; - export type DoubleValue__Output = _google_protobuf_DoubleValue__Output; - export type Duration = _google_protobuf_Duration; - export type Duration__Output = _google_protobuf_Duration__Output; - export type Empty = _google_protobuf_Empty; - export type Empty__Output = _google_protobuf_Empty__Output; - export type EnumDescriptorProto = _google_protobuf_EnumDescriptorProto; - export type EnumDescriptorProto__Output = _google_protobuf_EnumDescriptorProto__Output; - export type EnumOptions = _google_protobuf_EnumOptions; - export type EnumOptions__Output = _google_protobuf_EnumOptions__Output; - export type EnumValueDescriptorProto = _google_protobuf_EnumValueDescriptorProto; - export type EnumValueDescriptorProto__Output = _google_protobuf_EnumValueDescriptorProto__Output; - export type EnumValueOptions = _google_protobuf_EnumValueOptions; - export type EnumValueOptions__Output = _google_protobuf_EnumValueOptions__Output; - export type FieldDescriptorProto = _google_protobuf_FieldDescriptorProto; - export type FieldDescriptorProto__Output = _google_protobuf_FieldDescriptorProto__Output; - export type FieldOptions = _google_protobuf_FieldOptions; - export type FieldOptions__Output = _google_protobuf_FieldOptions__Output; - export type FileDescriptorProto = _google_protobuf_FileDescriptorProto; - export type FileDescriptorProto__Output = _google_protobuf_FileDescriptorProto__Output; - export type FileDescriptorSet = _google_protobuf_FileDescriptorSet; - export type FileDescriptorSet__Output = _google_protobuf_FileDescriptorSet__Output; - export type FileOptions = _google_protobuf_FileOptions; - export type FileOptions__Output = _google_protobuf_FileOptions__Output; - export type FloatValue = _google_protobuf_FloatValue; - export type FloatValue__Output = _google_protobuf_FloatValue__Output; - export type GeneratedCodeInfo = _google_protobuf_GeneratedCodeInfo; - export type GeneratedCodeInfo__Output = _google_protobuf_GeneratedCodeInfo__Output; - export type Int32Value = _google_protobuf_Int32Value; - export type Int32Value__Output = _google_protobuf_Int32Value__Output; - export type Int64Value = _google_protobuf_Int64Value; - export type Int64Value__Output = _google_protobuf_Int64Value__Output; - export type ListValue = _google_protobuf_ListValue; - export type ListValue__Output = _google_protobuf_ListValue__Output; - export type MessageOptions = _google_protobuf_MessageOptions; - export type MessageOptions__Output = _google_protobuf_MessageOptions__Output; - export type MethodDescriptorProto = _google_protobuf_MethodDescriptorProto; - export type MethodDescriptorProto__Output = _google_protobuf_MethodDescriptorProto__Output; - export type MethodOptions = _google_protobuf_MethodOptions; - export type MethodOptions__Output = _google_protobuf_MethodOptions__Output; - export type NullValue = _google_protobuf_NullValue; - export type OneofDescriptorProto = _google_protobuf_OneofDescriptorProto; - export type OneofDescriptorProto__Output = _google_protobuf_OneofDescriptorProto__Output; - export type OneofOptions = _google_protobuf_OneofOptions; - export type OneofOptions__Output = _google_protobuf_OneofOptions__Output; - export type ServiceDescriptorProto = _google_protobuf_ServiceDescriptorProto; - export type ServiceDescriptorProto__Output = _google_protobuf_ServiceDescriptorProto__Output; - export type ServiceOptions = _google_protobuf_ServiceOptions; - export type ServiceOptions__Output = _google_protobuf_ServiceOptions__Output; - export type SourceCodeInfo = _google_protobuf_SourceCodeInfo; - export type SourceCodeInfo__Output = _google_protobuf_SourceCodeInfo__Output; - export type StringValue = _google_protobuf_StringValue; - export type StringValue__Output = _google_protobuf_StringValue__Output; - export type Struct = _google_protobuf_Struct; - export type Struct__Output = _google_protobuf_Struct__Output; - export type Timestamp = _google_protobuf_Timestamp; - export type Timestamp__Output = _google_protobuf_Timestamp__Output; - export type UInt32Value = _google_protobuf_UInt32Value; - export type UInt32Value__Output = _google_protobuf_UInt32Value__Output; - export type UInt64Value = _google_protobuf_UInt64Value; - export type UInt64Value__Output = _google_protobuf_UInt64Value__Output; - export type UninterpretedOption = _google_protobuf_UninterpretedOption; - export type UninterpretedOption__Output = _google_protobuf_UninterpretedOption__Output; - export type Value = _google_protobuf_Value; - export type Value__Output = _google_protobuf_Value__Output; - } - } - export namespace udpa { - export namespace annotations { - export type FieldMigrateAnnotation = _udpa_annotations_FieldMigrateAnnotation; - export type FieldMigrateAnnotation__Output = _udpa_annotations_FieldMigrateAnnotation__Output; - export type FileMigrateAnnotation = _udpa_annotations_FileMigrateAnnotation; - export type FileMigrateAnnotation__Output = _udpa_annotations_FileMigrateAnnotation__Output; - export type MigrateAnnotation = _udpa_annotations_MigrateAnnotation; - export type MigrateAnnotation__Output = _udpa_annotations_MigrateAnnotation__Output; - export type PackageVersionStatus = _udpa_annotations_PackageVersionStatus; - export type StatusAnnotation = _udpa_annotations_StatusAnnotation; - export type StatusAnnotation__Output = _udpa_annotations_StatusAnnotation__Output; - } - } - export namespace validate { - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules = _validate_AnyRules; - /** - * AnyRules describe constraints applied exclusively to the - * `google.protobuf.Any` well-known type - */ - export type AnyRules__Output = _validate_AnyRules__Output; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules = _validate_BoolRules; - /** - * BoolRules describes the constraints applied to `bool` values - */ - export type BoolRules__Output = _validate_BoolRules__Output; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules = _validate_BytesRules; - /** - * BytesRules describe the constraints applied to `bytes` values - */ - export type BytesRules__Output = _validate_BytesRules__Output; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules = _validate_DoubleRules; - /** - * DoubleRules describes the constraints applied to `double` values - */ - export type DoubleRules__Output = _validate_DoubleRules__Output; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules = _validate_DurationRules; - /** - * DurationRules describe the constraints applied exclusively to the - * `google.protobuf.Duration` well-known type - */ - export type DurationRules__Output = _validate_DurationRules__Output; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules = _validate_EnumRules; - /** - * EnumRules describe the constraints applied to enum values - */ - export type EnumRules__Output = _validate_EnumRules__Output; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules = _validate_FieldRules; - /** - * FieldRules encapsulates the rules for each type of field. Depending on the - * field, the correct set should be used to ensure proper validations. - */ - export type FieldRules__Output = _validate_FieldRules__Output; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules = _validate_Fixed32Rules; - /** - * Fixed32Rules describes the constraints applied to `fixed32` values - */ - export type Fixed32Rules__Output = _validate_Fixed32Rules__Output; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules = _validate_Fixed64Rules; - /** - * Fixed64Rules describes the constraints applied to `fixed64` values - */ - export type Fixed64Rules__Output = _validate_Fixed64Rules__Output; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules = _validate_FloatRules; - /** - * FloatRules describes the constraints applied to `float` values - */ - export type FloatRules__Output = _validate_FloatRules__Output; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules = _validate_Int32Rules; - /** - * Int32Rules describes the constraints applied to `int32` values - */ - export type Int32Rules__Output = _validate_Int32Rules__Output; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules = _validate_Int64Rules; - /** - * Int64Rules describes the constraints applied to `int64` values - */ - export type Int64Rules__Output = _validate_Int64Rules__Output; - /** - * WellKnownRegex contain some well-known patterns. - */ - export type KnownRegex = _validate_KnownRegex; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules = _validate_MapRules; - /** - * MapRules describe the constraints applied to `map` values - */ - export type MapRules__Output = _validate_MapRules__Output; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules = _validate_MessageRules; - /** - * MessageRules describe the constraints applied to embedded message values. - * For message-type fields, validation is performed recursively. - */ - export type MessageRules__Output = _validate_MessageRules__Output; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules = _validate_RepeatedRules; - /** - * RepeatedRules describe the constraints applied to `repeated` values - */ - export type RepeatedRules__Output = _validate_RepeatedRules__Output; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules = _validate_SFixed32Rules; - /** - * SFixed32Rules describes the constraints applied to `sfixed32` values - */ - export type SFixed32Rules__Output = _validate_SFixed32Rules__Output; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules = _validate_SFixed64Rules; - /** - * SFixed64Rules describes the constraints applied to `sfixed64` values - */ - export type SFixed64Rules__Output = _validate_SFixed64Rules__Output; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules = _validate_SInt32Rules; - /** - * SInt32Rules describes the constraints applied to `sint32` values - */ - export type SInt32Rules__Output = _validate_SInt32Rules__Output; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules = _validate_SInt64Rules; - /** - * SInt64Rules describes the constraints applied to `sint64` values - */ - export type SInt64Rules__Output = _validate_SInt64Rules__Output; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules = _validate_StringRules; - /** - * StringRules describe the constraints applied to `string` values - */ - export type StringRules__Output = _validate_StringRules__Output; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules = _validate_TimestampRules; - /** - * TimestampRules describe the constraints applied exclusively to the - * `google.protobuf.Timestamp` well-known type - */ - export type TimestampRules__Output = _validate_TimestampRules__Output; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules = _validate_UInt32Rules; - /** - * UInt32Rules describes the constraints applied to `uint32` values - */ - export type UInt32Rules__Output = _validate_UInt32Rules__Output; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules = _validate_UInt64Rules; - /** - * UInt64Rules describes the constraints applied to `uint64` values - */ - export type UInt64Rules__Output = _validate_UInt64Rules__Output; - } -} - -export namespace ClientInterfaces { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace RouteConfiguration { - } - export namespace Vhds { - } - export namespace core { - export namespace Address { - } - export namespace AggregatedConfigSource { - } - export namespace ApiConfigSource { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ConfigSource { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace Extension { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RateLimitSettings { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SelfConfigSource { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - export namespace route { - export namespace CorsPolicy { - } - export namespace Decorator { - } - export namespace DirectResponseAction { - } - export namespace FilterAction { - } - export namespace HeaderMatcher { - } - export namespace HedgePolicy { - } - export namespace QueryParameterMatcher { - } - export namespace RateLimit { - export namespace Action { - export namespace DestinationCluster { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - export namespace RemoteAddress { - } - export namespace RequestHeaders { - } - export namespace SourceCluster { - } - } - } - export namespace RedirectAction { - } - export namespace RetryPolicy { - export namespace RetryBackOff { - } - export namespace RetryHostPredicate { - } - export namespace RetryPriority { - } - } - export namespace Route { - } - export namespace RouteAction { - export namespace HashPolicy { - export namespace ConnectionProperties { - } - export namespace Cookie { - } - export namespace FilterState { - } - export namespace Header { - } - export namespace QueryParameter { - } - } - export namespace RequestMirrorPolicy { - } - export namespace UpgradeConfig { - } - } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { - } - export namespace TlsContextMatchOptions { - } - } - export namespace Tracing { - } - export namespace VirtualCluster { - } - export namespace VirtualHost { - } - export namespace WeightedCluster { - export namespace ClusterWeight { - } - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - export namespace metadata { - export namespace v2 { - export namespace MetadataKey { - export namespace PathSegment { - } - } - export namespace MetadataKind { - export namespace Cluster { - } - export namespace Host { - } - export namespace Request { - } - export namespace Route { - } - } - } - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Environment { - } - export namespace Header { - } - export namespace Literal { - } - export namespace Metadata { - } - } - } - } - } - } - export namespace google { - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { @@ -1821,387 +179,3 @@ export interface ProtoGrpcType { } } -export namespace ServiceHandlers { - export namespace envoy { - export namespace annotations { - } - export namespace api { - export namespace v2 { - export namespace RouteConfiguration { - } - export namespace Vhds { - } - export namespace core { - export namespace Address { - } - export namespace AggregatedConfigSource { - } - export namespace ApiConfigSource { - } - export namespace AsyncDataSource { - } - export namespace BackoffStrategy { - } - export namespace BindConfig { - } - export namespace BuildVersion { - } - export namespace CidrRange { - } - export namespace ConfigSource { - } - export namespace ControlPlane { - } - export namespace DataSource { - } - export namespace Extension { - } - export namespace GrpcService { - export namespace EnvoyGrpc { - } - export namespace GoogleGrpc { - export namespace CallCredentials { - export namespace GoogleIAMCredentials { - } - export namespace MetadataCredentialsFromPlugin { - } - export namespace ServiceAccountJWTAccessCredentials { - } - export namespace StsService { - } - } - export namespace ChannelCredentials { - } - export namespace GoogleLocalCredentials { - } - export namespace SslCredentials { - } - } - } - export namespace HeaderMap { - } - export namespace HeaderValue { - } - export namespace HeaderValueOption { - } - export namespace HttpUri { - } - export namespace Locality { - } - export namespace Metadata { - } - export namespace Node { - } - export namespace Pipe { - } - export namespace RateLimitSettings { - } - export namespace RemoteDataSource { - } - export namespace RetryPolicy { - } - export namespace RuntimeDouble { - } - export namespace RuntimeFeatureFlag { - } - export namespace RuntimeFractionalPercent { - } - export namespace RuntimeUInt32 { - } - export namespace SelfConfigSource { - } - export namespace SocketAddress { - } - export namespace SocketOption { - } - export namespace TcpKeepalive { - } - export namespace TransportSocket { - } - } - export namespace route { - export namespace CorsPolicy { - } - export namespace Decorator { - } - export namespace DirectResponseAction { - } - export namespace FilterAction { - } - export namespace HeaderMatcher { - } - export namespace HedgePolicy { - } - export namespace QueryParameterMatcher { - } - export namespace RateLimit { - export namespace Action { - export namespace DestinationCluster { - } - export namespace GenericKey { - } - export namespace HeaderValueMatch { - } - export namespace RemoteAddress { - } - export namespace RequestHeaders { - } - export namespace SourceCluster { - } - } - } - export namespace RedirectAction { - } - export namespace RetryPolicy { - export namespace RetryBackOff { - } - export namespace RetryHostPredicate { - } - export namespace RetryPriority { - } - } - export namespace Route { - } - export namespace RouteAction { - export namespace HashPolicy { - export namespace ConnectionProperties { - } - export namespace Cookie { - } - export namespace FilterState { - } - export namespace Header { - } - export namespace QueryParameter { - } - } - export namespace RequestMirrorPolicy { - } - export namespace UpgradeConfig { - } - } - export namespace RouteMatch { - export namespace GrpcRouteMatchOptions { - } - export namespace TlsContextMatchOptions { - } - } - export namespace Tracing { - } - export namespace VirtualCluster { - } - export namespace VirtualHost { - } - export namespace WeightedCluster { - export namespace ClusterWeight { - } - } - } - } - } - export namespace type { - export namespace DoubleRange { - } - export namespace FractionalPercent { - } - export namespace Int32Range { - } - export namespace Int64Range { - } - export namespace Percent { - } - export namespace SemanticVersion { - } - export namespace matcher { - export namespace ListStringMatcher { - } - export namespace RegexMatchAndSubstitute { - } - export namespace RegexMatcher { - export namespace GoogleRE2 { - } - } - export namespace StringMatcher { - } - } - export namespace metadata { - export namespace v2 { - export namespace MetadataKey { - export namespace PathSegment { - } - } - export namespace MetadataKind { - export namespace Cluster { - } - export namespace Host { - } - export namespace Request { - } - export namespace Route { - } - } - } - } - export namespace tracing { - export namespace v2 { - export namespace CustomTag { - export namespace Environment { - } - export namespace Header { - } - export namespace Literal { - } - export namespace Metadata { - } - } - } - } - } - } - export namespace google { - export namespace protobuf { - export namespace Any { - } - export namespace BoolValue { - } - export namespace BytesValue { - } - export namespace DescriptorProto { - export namespace ExtensionRange { - } - export namespace ReservedRange { - } - } - export namespace DoubleValue { - } - export namespace Duration { - } - export namespace Empty { - } - export namespace EnumDescriptorProto { - } - export namespace EnumOptions { - } - export namespace EnumValueDescriptorProto { - } - export namespace EnumValueOptions { - } - export namespace FieldDescriptorProto { - } - export namespace FieldOptions { - } - export namespace FileDescriptorProto { - } - export namespace FileDescriptorSet { - } - export namespace FileOptions { - } - export namespace FloatValue { - } - export namespace GeneratedCodeInfo { - export namespace Annotation { - } - } - export namespace Int32Value { - } - export namespace Int64Value { - } - export namespace ListValue { - } - export namespace MessageOptions { - } - export namespace MethodDescriptorProto { - } - export namespace MethodOptions { - } - export namespace OneofDescriptorProto { - } - export namespace OneofOptions { - } - export namespace ServiceDescriptorProto { - } - export namespace ServiceOptions { - } - export namespace SourceCodeInfo { - export namespace Location { - } - } - export namespace StringValue { - } - export namespace Struct { - } - export namespace Timestamp { - } - export namespace UInt32Value { - } - export namespace UInt64Value { - } - export namespace UninterpretedOption { - export namespace NamePart { - } - } - export namespace Value { - } - } - } - export namespace udpa { - export namespace annotations { - export namespace FieldMigrateAnnotation { - } - export namespace FileMigrateAnnotation { - } - export namespace MigrateAnnotation { - } - export namespace StatusAnnotation { - } - } - } - export namespace validate { - export namespace AnyRules { - } - export namespace BoolRules { - } - export namespace BytesRules { - } - export namespace DoubleRules { - } - export namespace DurationRules { - } - export namespace EnumRules { - } - export namespace FieldRules { - } - export namespace Fixed32Rules { - } - export namespace Fixed64Rules { - } - export namespace FloatRules { - } - export namespace Int32Rules { - } - export namespace Int64Rules { - } - export namespace MapRules { - } - export namespace MessageRules { - } - export namespace RepeatedRules { - } - export namespace SFixed32Rules { - } - export namespace SFixed64Rules { - } - export namespace SInt32Rules { - } - export namespace SInt64Rules { - } - export namespace StringRules { - } - export namespace TimestampRules { - } - export namespace UInt32Rules { - } - export namespace UInt64Rules { - } - } -} diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index 90cded00a..ca360f483 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -16,7 +16,9 @@ */ import * as fs from 'fs'; -import * as adsTypes from './generated/ads'; +import { Struct } from './generated/google/protobuf/Struct'; +import { Node } from './generated/envoy/api/v2/core/Node'; +import { Value } from './generated/google/protobuf/Value'; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -32,7 +34,7 @@ export interface XdsServerConfig { export interface BootstrapInfo { xdsServers: XdsServerConfig[]; - node: adsTypes.messages.envoy.api.v2.core.Node; + node: Node; } function validateChannelCredsConfig(obj: any): ChannelCredsConfig { @@ -85,7 +87,7 @@ function validateXdsServerConfig(obj: any): XdsServerConfig { }; } -function validateValue(obj: any): adsTypes.messages.google.protobuf.Value { +function validateValue(obj: any): Value { if (Array.isArray(obj)) { return { kind: 'listValue', @@ -128,7 +130,7 @@ function validateValue(obj: any): adsTypes.messages.google.protobuf.Value { } } -function getStructFromJson(obj: any): adsTypes.messages.google.protobuf.Struct { +function getStructFromJson(obj: any): Struct { if (typeof obj !== 'object' || obj === null) { throw new Error('Invalid JSON object for Struct field'); } @@ -154,8 +156,8 @@ function getStructFromJson(obj: any): adsTypes.messages.google.protobuf.Struct { * fields we expect to see: id, cluster, locality, and metadata. * @param obj */ -function validateNode(obj: any): adsTypes.messages.envoy.api.v2.core.Node { - const result: adsTypes.messages.envoy.api.v2.core.Node = {}; +function validateNode(obj: any): Node { + const result: Node = {}; if (!('id' in obj)) { throw new Error('id field missing in node element'); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 9fb5279ed..b9275963c 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -18,7 +18,6 @@ import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; -import * as edsTypes from './generated/endpoint'; import { createGoogleDefaultCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; import { ClientDuplexStream, ServiceError } from './call'; @@ -29,6 +28,11 @@ import { Metadata } from './metadata'; import * as logging from './logging'; import { ServiceConfig } from './service-config'; import { ChannelOptions } from './channel-options'; +import { Node } from './generated/envoy/api/v2/core/Node'; +import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; +import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; +import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; +import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; const TRACER_NAME = 'xds_client'; @@ -86,21 +90,21 @@ export interface Watcher { } export class XdsClient { - private node: adsTypes.messages.envoy.api.v2.core.Node | null = null; - private client: adsTypes.ClientInterfaces.envoy.service.discovery.v2.AggregatedDiscoveryServiceClient | null = null; + private node: Node | null = null; + private client: AggregatedDiscoveryServiceClient | null = null; private adsCall: ClientDuplexStream< - adsTypes.messages.envoy.api.v2.DiscoveryRequest, - adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output + DiscoveryRequest, + DiscoveryResponse__Output > | null = null; private hasShutdown = false; private endpointWatchers: Map< string, - Watcher[] + Watcher[] > = new Map< string, - Watcher[] + Watcher[] >(); private lastEdsVersionInfo = ''; private lastEdsNonce = ''; @@ -175,17 +179,17 @@ export class XdsClient { this.adsCall = this.client.StreamAggregatedResources(); this.adsCall.on( 'data', - (message: adsTypes.messages.envoy.api.v2.DiscoveryResponse__Output) => { + (message: DiscoveryResponse__Output) => { switch (message.type_url) { case EDS_TYPE_URL: { - const edsResponses: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output[] = []; + const edsResponses: ClusterLoadAssignment__Output[] = []; for (const resource of message.resources) { if ( protoLoader.isAnyExtension(resource) && resource['@type'] === EDS_TYPE_URL ) { const resp = resource as protoLoader.AnyExtension & - edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output; + ClusterLoadAssignment__Output; if (!this.validateEdsResponse(resp)) { this.nackEds('ClusterLoadAssignment validation failed'); return; @@ -298,7 +302,7 @@ export class XdsClient { * @param message */ private validateEdsResponse( - message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + message: ClusterLoadAssignment__Output ): boolean { for (const endpoint of message.endpoints) { for (const lb of endpoint.lb_endpoints) { @@ -318,7 +322,7 @@ export class XdsClient { } private handleEdsResponse( - message: edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + message: ClusterLoadAssignment__Output ) { const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { @@ -350,7 +354,7 @@ export class XdsClient { addEndpointWatcher( edsServiceName: string, watcher: Watcher< - edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + ClusterLoadAssignment__Output > ) { trace('Watcher added for endpoint ' + edsServiceName); @@ -370,7 +374,7 @@ export class XdsClient { removeEndpointWatcher( edsServiceName: string, watcher: Watcher< - edsTypes.messages.envoy.api.v2.ClusterLoadAssignment__Output + ClusterLoadAssignment__Output > ) { trace('Watcher removed for endpoint ' + edsServiceName); From a0b050aa0cba3edc370e49630f0472cce7be3d30 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Jul 2020 13:11:54 -0700 Subject: [PATCH 1155/1899] gts fix --- packages/grpc-js/src/xds-client.ts | 98 +++++++++++++----------------- 1 file changed, 42 insertions(+), 56 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index b9275963c..98454817f 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -102,10 +102,7 @@ export class XdsClient { private endpointWatchers: Map< string, Watcher[] - > = new Map< - string, - Watcher[] - >(); + > = new Map[]>(); private lastEdsVersionInfo = ''; private lastEdsNonce = ''; @@ -177,52 +174,49 @@ export class XdsClient { return; } this.adsCall = this.client.StreamAggregatedResources(); - this.adsCall.on( - 'data', - (message: DiscoveryResponse__Output) => { - switch (message.type_url) { - case EDS_TYPE_URL: { - const edsResponses: ClusterLoadAssignment__Output[] = []; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === EDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - ClusterLoadAssignment__Output; - if (!this.validateEdsResponse(resp)) { - this.nackEds('ClusterLoadAssignment validation failed'); - return; - } - edsResponses.push(resp); - } else { - this.nackEds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); + this.adsCall.on('data', (message: DiscoveryResponse__Output) => { + switch (message.type_url) { + case EDS_TYPE_URL: { + const edsResponses: ClusterLoadAssignment__Output[] = []; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === EDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & + ClusterLoadAssignment__Output; + if (!this.validateEdsResponse(resp)) { + this.nackEds('ClusterLoadAssignment validation failed'); return; } + edsResponses.push(resp); + } else { + this.nackEds( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); + return; } - for (const message of edsResponses) { - this.handleEdsResponse(message); - } - this.lastEdsVersionInfo = message.version_info; - this.lastEdsNonce = message.nonce; - this.ackEds(); - break; } - default: - this.nackUnknown( - message.type_url, - message.version_info, - message.nonce - ); + for (const message of edsResponses) { + this.handleEdsResponse(message); + } + this.lastEdsVersionInfo = message.version_info; + this.lastEdsNonce = message.nonce; + this.ackEds(); + break; } + default: + this.nackUnknown( + message.type_url, + message.version_info, + message.nonce + ); } - ); + }); this.adsCall.on('error', (error: ServiceError) => { trace( 'ADS stream ended. code=' + error.code + ' details= ' + error.details @@ -301,9 +295,7 @@ export class XdsClient { * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto * @param message */ - private validateEdsResponse( - message: ClusterLoadAssignment__Output - ): boolean { + private validateEdsResponse(message: ClusterLoadAssignment__Output): boolean { for (const endpoint of message.endpoints) { for (const lb of endpoint.lb_endpoints) { const socketAddress = lb.endpoint?.address?.socket_address; @@ -321,9 +313,7 @@ export class XdsClient { return true; } - private handleEdsResponse( - message: ClusterLoadAssignment__Output - ) { + private handleEdsResponse(message: ClusterLoadAssignment__Output) { const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { watcher.onValidUpdate(message); @@ -353,9 +343,7 @@ export class XdsClient { addEndpointWatcher( edsServiceName: string, - watcher: Watcher< - ClusterLoadAssignment__Output - > + watcher: Watcher ) { trace('Watcher added for endpoint ' + edsServiceName); let watchersEntry = this.endpointWatchers.get(edsServiceName); @@ -373,9 +361,7 @@ export class XdsClient { removeEndpointWatcher( edsServiceName: string, - watcher: Watcher< - ClusterLoadAssignment__Output - > + watcher: Watcher ) { trace('Watcher removed for endpoint ' + edsServiceName); const watchersEntry = this.endpointWatchers.get(edsServiceName); From cca10597d5707bee1cd4e4a81882e43a4c5ea224 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Jul 2020 13:13:39 -0700 Subject: [PATCH 1156/1899] Add files for service definitions, remove redundant exports from root files --- .../bin/proto-loader-gen-types.ts | 183 ++++++++---------- packages/proto-loader/package.json | 2 +- 2 files changed, 83 insertions(+), 102 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index ea035d6cd..2fb72436e 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -81,31 +81,44 @@ function stripLeadingPeriod(name: string) { return name.startsWith('.') ? name.substring(1) : name; } -function getImportPath(to: Protobuf.Type | Protobuf.Enum) { +function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); } -function getPath(to: Protobuf.Type | Protobuf.Enum) { +function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.ts'; } -function getRelativeImportPath(from: Protobuf.Type, to: Protobuf.Type | Protobuf.Enum) { +function getPathToRoot(from: Protobuf.NamespaceBase) { const depth = stripLeadingPeriod(from.fullName).split('.').length - 1; let path = ''; for (let i = 0; i < depth; i++) { path += '../'; } - return path + getImportPath(to); + return path; } -function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum) { +function getRelativeImportPath(from: Protobuf.Type | Protobuf.Service, to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { + return getPathToRoot(from) + getImportPath(to); +} + +function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { return type.fullName.replace(/\./g, '_'); } -function getImportLine(dependency: Protobuf.Type | Protobuf.Enum, from?: Protobuf.Type) { +function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Service, from?: Protobuf.Type | Protobuf.Service) { const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); const typeInterfaceName = getTypeInterfaceName(dependency); - const importedTypes = dependency instanceof Protobuf.Type ? `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output` : `${dependency.name} as ${typeInterfaceName}`; + let importedTypes: string; + if (dependency instanceof Protobuf.Type) { + importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; + } else if (dependency instanceof Protobuf.Enum) { + importedTypes = `${dependency.name} as ${typeInterfaceName}`; + } else if (dependency instanceof Protobuf.Service) { + importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; + } else { + throw new Error('Invalid object passed to getImportLine'); + } return `import { ${importedTypes} } from '${filePath}';` } @@ -361,7 +374,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob formatter.writeLine("import { AnyExtension } from '@grpc/proto-loader';") } formatter.writeLine(''); - for (const childType of childTypes) { + for (const childType of childTypes.sort(compareName)) { const nameOverride = getTypeInterfaceName(childType); if (childType instanceof Protobuf.Type) { generatePermissiveMessageInterface(formatter, childType, options, nameOverride); @@ -396,39 +409,6 @@ function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum formatter.writeLine('}'); } -function generateMessageAndEnumImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase) { - for (const nested of namespace.nestedArray.sort(compareName)) { - if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { - formatter.writeLine(getImportLine(nested)); - } else if (isNamespaceBase(nested)) { - generateMessageAndEnumImports(formatter, nested); - } - } -} - -function generateMessageAndEnumExports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions, nameOverride?: string) { - formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); - formatter.indent(); - for (const nested of namespace.nestedArray.sort(compareName)) { - if (nested instanceof Protobuf.Enum || nested instanceof Protobuf.Type) { - if (options.includeComments) { - formatComment(formatter, nested.comment); - } - formatter.writeLine(`export type ${nested.name} = ${getTypeInterfaceName(nested)};`); - if (nested instanceof Protobuf.Type) { - if (options.includeComments) { - formatComment(formatter, nested.comment); - } - formatter.writeLine(`export type ${nested.name}__Output = ${getTypeInterfaceName(nested)}__Output;`); - } - } else if (isNamespaceBase(nested)) { - generateMessageAndEnumExports(formatter, nested, options); - } - } - formatter.unindent(); - formatter.writeLine('}'); -} - function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { if (options.includeComments) { formatComment(formatter, serviceType.comment); @@ -441,8 +421,8 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P if (options.includeComments) { formatComment(formatter, method.comment); } - const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName); - const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName) + '__Output'; + const requestType = getTypeInterfaceName(method.resolvedRequestType!); + const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; if (method.requestStream) { if (method.responseStream) { @@ -480,58 +460,19 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P formatter.writeLine('}'); } -function generateAllServiceClientInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions, nameOverride?: string) { - formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); - formatter.indent(); - for (const nested of namespace.nestedArray.sort(compareName)) { - if (nested instanceof Protobuf.Service) { - generateServiceClientInterface(formatter, nested, options); - } else if (isNamespaceBase(nested)) { - generateAllServiceClientInterfaces(formatter, nested, options); - } - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject, options: GeneratorOptions) { - if (nested instanceof Protobuf.Service) { - if (options.includeComments) { - formatComment(formatter, nested.comment); - } - formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) - } else if (nested instanceof Protobuf.Enum) { - formatter.writeLine(`${nested.name}: EnumTypeDefinition`); - } else if (nested instanceof Protobuf.Type) { - formatter.writeLine(`${nested.name}: MessageTypeDefinition`); - } else if (isNamespaceBase(nested)) { - generateLoadedDefinitionTypes(formatter, nested, options); - } -} - -function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { - formatter.writeLine(`${namespace.name}: {`); - formatter.indent(); - for (const nested of namespace.nestedArray.sort(compareName)) { - generateSingleLoadedDefinitionType(formatter, nested, options); - } - formatter.unindent(); - formatter.writeLine('}'); -} - function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { if (options.includeComments) { formatComment(formatter, serviceType.comment); } - formatter.writeLine(`export interface ${serviceType.name} {`); + formatter.writeLine(`export interface ${serviceType.name}Handlers {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; if (options.includeComments) { formatComment(formatter, method.comment); } - const requestType = 'messages.' + stripLeadingPeriod(method.resolvedRequestType!.fullName) + '__Output'; - const responseType = 'messages.' + stripLeadingPeriod(method.resolvedResponseType!.fullName); + const requestType = getTypeInterfaceName(method.resolvedRequestType!); + const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; if (method.requestStream) { if (method.responseStream) { // Bidi streaming @@ -555,15 +496,57 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: formatter.writeLine('}'); } -function generateAllServiceHandlerInterfaces(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions, nameOverride?: string) { - formatter.writeLine(`export namespace ${nameOverride ?? namespace.name} {`); - formatter.indent(); +function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + formatter.writeLine(`// Original file: ${serviceType.filename}`); + formatter.writeLine(''); + const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; + formatter.writeLine(`import * as grpc from '${grpcImportPath}'`); + const dependencies: Set = new Set(); + for (const method of serviceType.methodsArray) { + dependencies.add(method.resolvedRequestType!); + dependencies.add(method.resolvedResponseType!); + } + for (const dep of Array.from(dependencies.values()).sort(compareName)) { + formatter.writeLine(getImportLine(dep, serviceType)); + } + formatter.writeLine(''); + + generateServiceClientInterface(formatter, serviceType, options); + formatter.writeLine(''); + + generateServiceHandlerInterface(formatter, serviceType, options); +} + +function generateServiceImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { - generateServiceHandlerInterface(formatter, nested, options); - } else if (isNamespaceBase(nested)) { - generateAllServiceHandlerInterfaces(formatter, nested, options); + formatter.writeLine(getImportLine(nested)); + } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { + generateServiceImports(formatter, nested, options); + } + } +} + +function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject, options: GeneratorOptions) { + if (nested instanceof Protobuf.Service) { + if (options.includeComments) { + formatComment(formatter, nested.comment); } + formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) + } else if (nested instanceof Protobuf.Enum) { + formatter.writeLine(`${nested.name}: EnumTypeDefinition`); + } else if (nested instanceof Protobuf.Type) { + formatter.writeLine(`${nested.name}: MessageTypeDefinition`); + } else if (isNamespaceBase(nested)) { + generateLoadedDefinitionTypes(formatter, nested, options); + } +} + +function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { + formatter.writeLine(`${namespace.name}: {`); + formatter.indent(); + for (const nested of namespace.nestedArray.sort(compareName)) { + generateSingleLoadedDefinitionType(formatter, nested, options); } formatter.unindent(); formatter.writeLine('}'); @@ -573,14 +556,8 @@ function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options formatter.writeLine(`import * as grpc from '${options.grpcLib}';`); formatter.writeLine("import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); formatter.writeLine(''); - - generateMessageAndEnumImports(formatter, root); - formatter.writeLine(''); - - generateMessageAndEnumExports(formatter, root, options, 'messages'); - formatter.writeLine(''); - - generateAllServiceClientInterfaces(formatter, root, options, 'ClientInterfaces'); + + generateServiceImports(formatter, root, options); formatter.writeLine(''); formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); @@ -597,8 +574,6 @@ function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options formatter.unindent(); formatter.writeLine('}'); formatter.writeLine(''); - - generateAllServiceHandlerInterfaces(formatter, root, options, 'ServiceHandlers'); } async function writeFile(filename: string, contents: string): Promise { @@ -622,6 +597,12 @@ function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: G console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); } filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + } else if (nested instanceof Protobuf.Service) { + generateServiceInterfaces(fileFormatter, nested, options); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + } + filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); } else if (isNamespaceBase(nested)) { filePromises.push(...generateFilesForNamespace(nested, options)); } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 3ebcd21b0..26b97d07e 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre9", + "version": "0.6.0-pre10", "author": "Google Inc.", "contributors": [ { From 25b2a279914fe823c40b35cd04946a26648e6a12 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Jul 2020 09:39:59 -0700 Subject: [PATCH 1157/1899] Move proto-loader to dev deps temporarily --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7080270e2..310845e76 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,6 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { + "@grpc/proto-loader": "^0.6.0-pre6", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -57,7 +58,6 @@ "posttest": "npm run check" }, "dependencies": { - "@grpc/proto-loader": "^0.6.0-pre6", "semver": "^6.2.0" }, "peerDependencies": { From 898ba43c54ae92b7e5209b1f61146fb189037c5a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Jul 2020 09:57:56 -0700 Subject: [PATCH 1158/1899] Update @types/gulp-mocha dependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 70a15fbbf..8849300c2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@types/execa": "^0.8.0", "@types/gulp": "^4.0.5", - "@types/gulp-mocha": "0.0.31", + "@types/gulp-mocha": "0.0.33", "@types/ncp": "^2.0.1", "@types/node": "^8.0.32", "@types/pify": "^3.0.0", From c0840f1269a60e62720e956ee54e550ee2a88f1b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Jul 2020 10:16:17 -0700 Subject: [PATCH 1159/1899] Update grpc-tools patch version --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 67f6af4d0..7dddbff0f 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.9.0", + "version": "1.9.1", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 842757c55f46ea7e426d0698b6d1010e0efb575b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 15 Jul 2020 10:36:52 -0700 Subject: [PATCH 1160/1899] Fix @types/mocha compatibility issue --- packages/proto-loader/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index cba96b43e..155a0abfa 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -44,6 +44,7 @@ }, "devDependencies": { "@types/lodash.camelcase": "^4.3.4", + "@types/mocha": "^5.2.7", "@types/node": "^10.12.5", "clang-format": "^1.2.2", "gts": "^1.1.0", From 8eaf7e87254e88feafd13025c27328157d825e3d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 15 Jul 2020 11:24:46 -0700 Subject: [PATCH 1161/1899] Revert "Update @types/gulp-mocha dependency" This reverts commit 898ba43c54ae92b7e5209b1f61146fb189037c5a. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8849300c2..70a15fbbf 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "devDependencies": { "@types/execa": "^0.8.0", "@types/gulp": "^4.0.5", - "@types/gulp-mocha": "0.0.33", + "@types/gulp-mocha": "0.0.31", "@types/ncp": "^2.0.1", "@types/node": "^8.0.32", "@types/pify": "^3.0.0", From 5e28fb3078ee9feeabdf061f83526d626ec772e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 17 Jul 2020 10:35:04 -0700 Subject: [PATCH 1162/1899] grpc-js: Implement EDS load balancer --- packages/grpc-js/src/load-balancer-eds.ts | 254 ++++++++++++++++++ packages/grpc-js/src/load-balancing-config.ts | 32 ++- 2 files changed, 285 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js/src/load-balancer-eds.ts diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts new file mode 100644 index 000000000..312d059c5 --- /dev/null +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -0,0 +1,254 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig } from "./load-balancer"; +import { SubchannelAddress } from "./subchannel"; +import { LoadBalancingConfig, isEdsLoadBalancingConfig, EdsLoadBalancingConfig, PriorityLbConfig, PriorityChild, WeightedTarget, PriorityLoadBalancingConfig } from "./load-balancing-config"; +import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; +import { XdsClient, Watcher } from "./xds-client"; +import { ClusterLoadAssignment__Output } from "./generated/envoy/api/v2/ClusterLoadAssignment"; +import { ConnectivityState } from "./channel"; +import { UnavailablePicker } from "./picker"; +import { Locality__Output } from "./generated/envoy/api/v2/core/Locality"; +import { LocalitySubchannelAddress } from "./load-balancer-priority"; +import { Status } from "./constants"; +import { Metadata } from "./metadata"; + +const TYPE_NAME = 'eds'; + +function localityToName(locality: Locality__Output) { + return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; +} + +/** + * This class load balances over a cluster by making an EDS request and then + * transforming the result into a configuration for another load balancing + * policy. + */ +export class EdsLoadBalancer implements LoadBalancer { + /** + * The child load balancer that will handle balancing the results of the EDS + * requests. + */ + private childBalancer: ChildLoadBalancerHandler; + private xdsClient: XdsClient | null = null; + private edsServiceName: string | null = null; + private watcher: Watcher; + /** + * Indicates whether the watcher has already been passed to this.xdsClient + * and is getting updates. + */ + private isWatcherActive = false; + + private lastestConfig: EdsLoadBalancingConfig | null = null; + private latestAttributes: {[key: string]: unknown} = {}; + private latestEdsUpdate: ClusterLoadAssignment__Output | null = null; + + /** + * The priority of each locality the last time we got an update. + */ + private localityPriorities: Map = new Map(); + /** + * The name we assigned to each priority number the last time we got an + * update. + */ + private priorityNames: string[] = []; + + private nextPriorityChildNumber = 0; + + constructor(private readonly channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.watcher = { + onValidUpdate: update => { + this.latestEdsUpdate = update; + this.updateChild(); + }, + onResourceDoesNotExist: () => { + /* TODO(murgatroid99): Figure out what needs to be done here after + * implementing CDS */ + }, + onTransientError: (status) => { + if (this.latestEdsUpdate === null) { + channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: `xDS request failed with error ${status.details}`, + metadata: new Metadata() + })); + } + } + } + } + + /** + * Should be called when this balancer gets a new config and when the + * XdsClient returns a new ClusterLoadAssignment. + */ + private updateChild() { + if (!(this.lastestConfig && this.latestEdsUpdate)) { + return; + } + /** + * Maps each priority number to the list of localities with that priority, + * and the list of addresses associated with each locality. + */ + const priorityList: {locality: Locality__Output, weight: number, addresses: SubchannelAddress[]}[][] = []; + const newLocalityPriorities: Map = new Map(); + /* We are given a list of localities, each of which has a priority. This + * loop consolidates localities into buckets by priority, while also + * simplifying the data structure to make the later steps simpler */ + for (const endpoint of this.latestEdsUpdate.endpoints) { + let localityArray = priorityList[endpoint.priority]; + if (localityArray === undefined) { + localityArray = []; + priorityList[endpoint.priority] = localityArray; + } + const addresses: SubchannelAddress[] = endpoint.lb_endpoints.map(lbEndpoint => { + /* The validator in the XdsClient class ensures that each endpoint has + * a socket_address with an IP address and a port_value. */ + const socketAddress = lbEndpoint.endpoint!.address.socket_address!; + return {host: socketAddress.address!, port: socketAddress.port_value!}; + }); + localityArray.push({ + locality: endpoint.locality, + addresses: addresses, + weight: endpoint.load_balancing_weight.value + }); + newLocalityPriorities.set(localityToName(endpoint.locality), endpoint.priority); + } + + const newPriorityNames: string[] = []; + const addressList: LocalitySubchannelAddress[] = []; + const priorityChildren: Map = new Map(); + /* The algorithm here is as follows: for each priority we are given, from + * high to low: + * - If the previous mapping had any of the same localities at the same or + * a lower priority, use the matching name from the highest such + * priority, unless the new mapping has already used that name. + * - Otherwise, construct a new name using this.nextPriorityChildNumber. + */ + for (const [priority, localityArray] of priorityList.entries()) { + if (localityArray === undefined) { + continue; + } + /** + * Highest (smallest number) priority value that any of the localities in + * this locality array had a in the previous mapping. + */ + let highestOldPriority = Infinity; + for (const localityObj of localityArray) { + const oldPriority = this.localityPriorities.get(localityToName(localityObj.locality)); + if (oldPriority !== undefined && oldPriority >= priority && oldPriority < highestOldPriority) { + highestOldPriority = oldPriority; + } + } + let newPriorityName: string; + if (highestOldPriority === Infinity) { + /* No existing priority at or below the same number as the priority we + * are looking at had any of the localities in this priority. So, we + * use a new name. */ + newPriorityName = `child${this.nextPriorityChildNumber++}`; + } else { + const newName = this.priorityNames[highestOldPriority]; + if (newPriorityNames.indexOf(newName) < 0) { + newPriorityName = newName; + } else { + newPriorityName = `child${this.nextPriorityChildNumber++}`; + } + } + newPriorityNames[priority] = newPriorityName; + + const childTargets: Map = new Map(); + for (const localityObj of localityArray) { + childTargets.set(localityToName(localityObj.locality), { + weight: localityObj.weight, + /* TODO(murgatroid99): Insert an lrs config around the round_robin + * config after implementing lrs */ + /* Use the endpoint picking policy from the config, default to + * round_robin. */ + child_policy: [...this.lastestConfig.eds.endpointPickingPolicy, {name: 'round_robin', round_robin: {}}] + }); + for (const address of localityObj.addresses) { + addressList.push({ + localityPath: [newPriorityName, localityToName(localityObj.locality)], + ...address + }); + } + } + + priorityChildren.set(newPriorityName, { + config: [{ + name: 'weighted_target', + weighted_target: { + targets: childTargets + } + }] + }); + } + const childConfig: PriorityLoadBalancingConfig = { + name: 'priority', + priority: { + children: priorityChildren, + /* Contract the priority names array if it is sparse. This config only + * cares about the order of priorities, not their specific numbers */ + priorities: newPriorityNames.filter(value => value !== undefined) + } + }; + this.childBalancer.updateAddressList(addressList, childConfig, this.latestAttributes); + + this.localityPriorities = newLocalityPriorities; + this.priorityNames = newPriorityNames; + } + + updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { + if (!isEdsLoadBalancingConfig(lbConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + this.lastestConfig = lbConfig; + this.latestAttributes = attributes; + this.xdsClient = attributes.xdsClient; + this.edsServiceName = lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + + if (!this.isWatcherActive) { + this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); + this.isWatcherActive = true; + } + + this.updateChild(); + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + if (this.edsServiceName) { + this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); + } + this.childBalancer.destroy(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer); +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 736e3d42d..164e1ab4d 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -57,6 +57,24 @@ export interface WeightedTargetLbConfig { targets: Map; } +export interface EdsLbConfig { + cluster: string; + edsServiceName?: string; + lrsLoadReportingServerName?: string; + /** + * This policy's config is expected to be in the format used by the + * weighted_target policy. Defaults to weighted_target if not specified. + * + * This is currently not used because there is currently no other config + * that has the same format as weighted_target. + */ + localityPickingPolicy: LoadBalancingConfig[]; + /** + * Defaults to round_robin if not specified. + */ + endpointPickingPolicy: LoadBalancingConfig[]; +} + export interface PickFirstLoadBalancingConfig { name: 'pick_first'; pick_first: PickFirstConfig; @@ -87,13 +105,19 @@ export interface WeightedTargetLoadBalancingConfig { weighted_target: WeightedTargetLbConfig; } +export interface EdsLoadBalancingConfig { + name: 'eds'; + eds: EdsLbConfig; +} + export type LoadBalancingConfig = | PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig | XdsLoadBalancingConfig | GrpcLbLoadBalancingConfig | PriorityLoadBalancingConfig - | WeightedTargetLoadBalancingConfig; + | WeightedTargetLoadBalancingConfig + | EdsLoadBalancingConfig; export function isRoundRobinLoadBalancingConfig( lbconfig: LoadBalancingConfig @@ -125,6 +149,12 @@ export function isWeightedTargetLoadBalancingConfig( return lbconfig.name === 'weighted_target'; } +export function isEdsLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is EdsLoadBalancingConfig { + return lbconfig.name === 'eds'; +} + /* In these functions we assume the input came from a JSON object. Therefore we * expect that the prototype is uninteresting and that `in` can be used * effectively */ From f061e4e762750edcf1ea5f3c9fc04b87c900b8f3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 17 Jul 2020 10:37:49 -0700 Subject: [PATCH 1163/1899] gts fix --- packages/grpc-js/src/load-balancer-eds.ts | 567 ++++++++++++---------- 1 file changed, 313 insertions(+), 254 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 312d059c5..57582849f 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -1,254 +1,313 @@ -/* - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig } from "./load-balancer"; -import { SubchannelAddress } from "./subchannel"; -import { LoadBalancingConfig, isEdsLoadBalancingConfig, EdsLoadBalancingConfig, PriorityLbConfig, PriorityChild, WeightedTarget, PriorityLoadBalancingConfig } from "./load-balancing-config"; -import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; -import { XdsClient, Watcher } from "./xds-client"; -import { ClusterLoadAssignment__Output } from "./generated/envoy/api/v2/ClusterLoadAssignment"; -import { ConnectivityState } from "./channel"; -import { UnavailablePicker } from "./picker"; -import { Locality__Output } from "./generated/envoy/api/v2/core/Locality"; -import { LocalitySubchannelAddress } from "./load-balancer-priority"; -import { Status } from "./constants"; -import { Metadata } from "./metadata"; - -const TYPE_NAME = 'eds'; - -function localityToName(locality: Locality__Output) { - return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; -} - -/** - * This class load balances over a cluster by making an EDS request and then - * transforming the result into a configuration for another load balancing - * policy. - */ -export class EdsLoadBalancer implements LoadBalancer { - /** - * The child load balancer that will handle balancing the results of the EDS - * requests. - */ - private childBalancer: ChildLoadBalancerHandler; - private xdsClient: XdsClient | null = null; - private edsServiceName: string | null = null; - private watcher: Watcher; - /** - * Indicates whether the watcher has already been passed to this.xdsClient - * and is getting updates. - */ - private isWatcherActive = false; - - private lastestConfig: EdsLoadBalancingConfig | null = null; - private latestAttributes: {[key: string]: unknown} = {}; - private latestEdsUpdate: ClusterLoadAssignment__Output | null = null; - - /** - * The priority of each locality the last time we got an update. - */ - private localityPriorities: Map = new Map(); - /** - * The name we assigned to each priority number the last time we got an - * update. - */ - private priorityNames: string[] = []; - - private nextPriorityChildNumber = 0; - - constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); - this.watcher = { - onValidUpdate: update => { - this.latestEdsUpdate = update; - this.updateChild(); - }, - onResourceDoesNotExist: () => { - /* TODO(murgatroid99): Figure out what needs to be done here after - * implementing CDS */ - }, - onTransientError: (status) => { - if (this.latestEdsUpdate === null) { - channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: `xDS request failed with error ${status.details}`, - metadata: new Metadata() - })); - } - } - } - } - - /** - * Should be called when this balancer gets a new config and when the - * XdsClient returns a new ClusterLoadAssignment. - */ - private updateChild() { - if (!(this.lastestConfig && this.latestEdsUpdate)) { - return; - } - /** - * Maps each priority number to the list of localities with that priority, - * and the list of addresses associated with each locality. - */ - const priorityList: {locality: Locality__Output, weight: number, addresses: SubchannelAddress[]}[][] = []; - const newLocalityPriorities: Map = new Map(); - /* We are given a list of localities, each of which has a priority. This - * loop consolidates localities into buckets by priority, while also - * simplifying the data structure to make the later steps simpler */ - for (const endpoint of this.latestEdsUpdate.endpoints) { - let localityArray = priorityList[endpoint.priority]; - if (localityArray === undefined) { - localityArray = []; - priorityList[endpoint.priority] = localityArray; - } - const addresses: SubchannelAddress[] = endpoint.lb_endpoints.map(lbEndpoint => { - /* The validator in the XdsClient class ensures that each endpoint has - * a socket_address with an IP address and a port_value. */ - const socketAddress = lbEndpoint.endpoint!.address.socket_address!; - return {host: socketAddress.address!, port: socketAddress.port_value!}; - }); - localityArray.push({ - locality: endpoint.locality, - addresses: addresses, - weight: endpoint.load_balancing_weight.value - }); - newLocalityPriorities.set(localityToName(endpoint.locality), endpoint.priority); - } - - const newPriorityNames: string[] = []; - const addressList: LocalitySubchannelAddress[] = []; - const priorityChildren: Map = new Map(); - /* The algorithm here is as follows: for each priority we are given, from - * high to low: - * - If the previous mapping had any of the same localities at the same or - * a lower priority, use the matching name from the highest such - * priority, unless the new mapping has already used that name. - * - Otherwise, construct a new name using this.nextPriorityChildNumber. - */ - for (const [priority, localityArray] of priorityList.entries()) { - if (localityArray === undefined) { - continue; - } - /** - * Highest (smallest number) priority value that any of the localities in - * this locality array had a in the previous mapping. - */ - let highestOldPriority = Infinity; - for (const localityObj of localityArray) { - const oldPriority = this.localityPriorities.get(localityToName(localityObj.locality)); - if (oldPriority !== undefined && oldPriority >= priority && oldPriority < highestOldPriority) { - highestOldPriority = oldPriority; - } - } - let newPriorityName: string; - if (highestOldPriority === Infinity) { - /* No existing priority at or below the same number as the priority we - * are looking at had any of the localities in this priority. So, we - * use a new name. */ - newPriorityName = `child${this.nextPriorityChildNumber++}`; - } else { - const newName = this.priorityNames[highestOldPriority]; - if (newPriorityNames.indexOf(newName) < 0) { - newPriorityName = newName; - } else { - newPriorityName = `child${this.nextPriorityChildNumber++}`; - } - } - newPriorityNames[priority] = newPriorityName; - - const childTargets: Map = new Map(); - for (const localityObj of localityArray) { - childTargets.set(localityToName(localityObj.locality), { - weight: localityObj.weight, - /* TODO(murgatroid99): Insert an lrs config around the round_robin - * config after implementing lrs */ - /* Use the endpoint picking policy from the config, default to - * round_robin. */ - child_policy: [...this.lastestConfig.eds.endpointPickingPolicy, {name: 'round_robin', round_robin: {}}] - }); - for (const address of localityObj.addresses) { - addressList.push({ - localityPath: [newPriorityName, localityToName(localityObj.locality)], - ...address - }); - } - } - - priorityChildren.set(newPriorityName, { - config: [{ - name: 'weighted_target', - weighted_target: { - targets: childTargets - } - }] - }); - } - const childConfig: PriorityLoadBalancingConfig = { - name: 'priority', - priority: { - children: priorityChildren, - /* Contract the priority names array if it is sparse. This config only - * cares about the order of priorities, not their specific numbers */ - priorities: newPriorityNames.filter(value => value !== undefined) - } - }; - this.childBalancer.updateAddressList(addressList, childConfig, this.latestAttributes); - - this.localityPriorities = newLocalityPriorities; - this.priorityNames = newPriorityNames; - } - - updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { - if (!isEdsLoadBalancingConfig(lbConfig)) { - return; - } - if (!(attributes.xdsClient instanceof XdsClient)) { - return; - } - this.lastestConfig = lbConfig; - this.latestAttributes = attributes; - this.xdsClient = attributes.xdsClient; - this.edsServiceName = lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; - - if (!this.isWatcherActive) { - this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); - this.isWatcherActive = true; - } - - this.updateChild(); - } - exitIdle(): void { - this.childBalancer.exitIdle(); - } - resetBackoff(): void { - this.childBalancer.resetBackoff(); - } - destroy(): void { - if (this.edsServiceName) { - this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); - } - this.childBalancer.destroy(); - } - getTypeName(): string { - return TYPE_NAME; - } -} - -export function setup() { - registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer); -} \ No newline at end of file +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + registerLoadBalancerType, + getFirstUsableConfig, +} from './load-balancer'; +import { SubchannelAddress } from './subchannel'; +import { + LoadBalancingConfig, + isEdsLoadBalancingConfig, + EdsLoadBalancingConfig, + PriorityLbConfig, + PriorityChild, + WeightedTarget, + PriorityLoadBalancingConfig, +} from './load-balancing-config'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { XdsClient, Watcher } from './xds-client'; +import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; +import { ConnectivityState } from './channel'; +import { UnavailablePicker } from './picker'; +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { LocalitySubchannelAddress } from './load-balancer-priority'; +import { Status } from './constants'; +import { Metadata } from './metadata'; + +const TYPE_NAME = 'eds'; + +function localityToName(locality: Locality__Output) { + return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; +} + +/** + * This class load balances over a cluster by making an EDS request and then + * transforming the result into a configuration for another load balancing + * policy. + */ +export class EdsLoadBalancer implements LoadBalancer { + /** + * The child load balancer that will handle balancing the results of the EDS + * requests. + */ + private childBalancer: ChildLoadBalancerHandler; + private xdsClient: XdsClient | null = null; + private edsServiceName: string | null = null; + private watcher: Watcher; + /** + * Indicates whether the watcher has already been passed to this.xdsClient + * and is getting updates. + */ + private isWatcherActive = false; + + private lastestConfig: EdsLoadBalancingConfig | null = null; + private latestAttributes: { [key: string]: unknown } = {}; + private latestEdsUpdate: ClusterLoadAssignment__Output | null = null; + + /** + * The priority of each locality the last time we got an update. + */ + private localityPriorities: Map = new Map(); + /** + * The name we assigned to each priority number the last time we got an + * update. + */ + private priorityNames: string[] = []; + + private nextPriorityChildNumber = 0; + + constructor(private readonly channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.watcher = { + onValidUpdate: (update) => { + this.latestEdsUpdate = update; + this.updateChild(); + }, + onResourceDoesNotExist: () => { + /* TODO(murgatroid99): Figure out what needs to be done here after + * implementing CDS */ + }, + onTransientError: (status) => { + if (this.latestEdsUpdate === null) { + channelControlHelper.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: `xDS request failed with error ${status.details}`, + metadata: new Metadata(), + }) + ); + } + }, + }; + } + + /** + * Should be called when this balancer gets a new config and when the + * XdsClient returns a new ClusterLoadAssignment. + */ + private updateChild() { + if (!(this.lastestConfig && this.latestEdsUpdate)) { + return; + } + /** + * Maps each priority number to the list of localities with that priority, + * and the list of addresses associated with each locality. + */ + const priorityList: { + locality: Locality__Output; + weight: number; + addresses: SubchannelAddress[]; + }[][] = []; + const newLocalityPriorities: Map = new Map< + string, + number + >(); + /* We are given a list of localities, each of which has a priority. This + * loop consolidates localities into buckets by priority, while also + * simplifying the data structure to make the later steps simpler */ + for (const endpoint of this.latestEdsUpdate.endpoints) { + let localityArray = priorityList[endpoint.priority]; + if (localityArray === undefined) { + localityArray = []; + priorityList[endpoint.priority] = localityArray; + } + const addresses: SubchannelAddress[] = endpoint.lb_endpoints.map( + (lbEndpoint) => { + /* The validator in the XdsClient class ensures that each endpoint has + * a socket_address with an IP address and a port_value. */ + const socketAddress = lbEndpoint.endpoint!.address.socket_address!; + return { + host: socketAddress.address!, + port: socketAddress.port_value!, + }; + } + ); + localityArray.push({ + locality: endpoint.locality, + addresses: addresses, + weight: endpoint.load_balancing_weight.value, + }); + newLocalityPriorities.set( + localityToName(endpoint.locality), + endpoint.priority + ); + } + + const newPriorityNames: string[] = []; + const addressList: LocalitySubchannelAddress[] = []; + const priorityChildren: Map = new Map< + string, + PriorityChild + >(); + /* The algorithm here is as follows: for each priority we are given, from + * high to low: + * - If the previous mapping had any of the same localities at the same or + * a lower priority, use the matching name from the highest such + * priority, unless the new mapping has already used that name. + * - Otherwise, construct a new name using this.nextPriorityChildNumber. + */ + for (const [priority, localityArray] of priorityList.entries()) { + if (localityArray === undefined) { + continue; + } + /** + * Highest (smallest number) priority value that any of the localities in + * this locality array had a in the previous mapping. + */ + let highestOldPriority = Infinity; + for (const localityObj of localityArray) { + const oldPriority = this.localityPriorities.get( + localityToName(localityObj.locality) + ); + if ( + oldPriority !== undefined && + oldPriority >= priority && + oldPriority < highestOldPriority + ) { + highestOldPriority = oldPriority; + } + } + let newPriorityName: string; + if (highestOldPriority === Infinity) { + /* No existing priority at or below the same number as the priority we + * are looking at had any of the localities in this priority. So, we + * use a new name. */ + newPriorityName = `child${this.nextPriorityChildNumber++}`; + } else { + const newName = this.priorityNames[highestOldPriority]; + if (newPriorityNames.indexOf(newName) < 0) { + newPriorityName = newName; + } else { + newPriorityName = `child${this.nextPriorityChildNumber++}`; + } + } + newPriorityNames[priority] = newPriorityName; + + const childTargets: Map = new Map< + string, + WeightedTarget + >(); + for (const localityObj of localityArray) { + childTargets.set(localityToName(localityObj.locality), { + weight: localityObj.weight, + /* TODO(murgatroid99): Insert an lrs config around the round_robin + * config after implementing lrs */ + /* Use the endpoint picking policy from the config, default to + * round_robin. */ + child_policy: [ + ...this.lastestConfig.eds.endpointPickingPolicy, + { name: 'round_robin', round_robin: {} }, + ], + }); + for (const address of localityObj.addresses) { + addressList.push({ + localityPath: [ + newPriorityName, + localityToName(localityObj.locality), + ], + ...address, + }); + } + } + + priorityChildren.set(newPriorityName, { + config: [ + { + name: 'weighted_target', + weighted_target: { + targets: childTargets, + }, + }, + ], + }); + } + const childConfig: PriorityLoadBalancingConfig = { + name: 'priority', + priority: { + children: priorityChildren, + /* Contract the priority names array if it is sparse. This config only + * cares about the order of priorities, not their specific numbers */ + priorities: newPriorityNames.filter((value) => value !== undefined), + }, + }; + this.childBalancer.updateAddressList( + addressList, + childConfig, + this.latestAttributes + ); + + this.localityPriorities = newLocalityPriorities; + this.priorityNames = newPriorityNames; + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!isEdsLoadBalancingConfig(lbConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + this.lastestConfig = lbConfig; + this.latestAttributes = attributes; + this.xdsClient = attributes.xdsClient; + this.edsServiceName = lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + + if (!this.isWatcherActive) { + this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); + this.isWatcherActive = true; + } + + this.updateChild(); + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + if (this.edsServiceName) { + this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); + } + this.childBalancer.destroy(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer); +} From 248479bc225ca32c2e15897b6c05f88394642f28 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Jul 2020 13:51:50 -0700 Subject: [PATCH 1164/1899] grpc-js: Implement CDS LB policy --- packages/grpc-js/src/load-balancer-cds.ts | 115 ++++++++++++++ packages/grpc-js/src/load-balancer-eds.ts | 4 +- packages/grpc-js/src/load-balancing-config.ts | 18 ++- packages/grpc-js/src/xds-client.ts | 144 +++++++++++++++++- 4 files changed, 277 insertions(+), 4 deletions(-) create mode 100644 packages/grpc-js/src/load-balancer-cds.ts diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts new file mode 100644 index 000000000..33fe42c73 --- /dev/null +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -0,0 +1,115 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + registerLoadBalancerType, +} from './load-balancer'; +import { SubchannelAddress } from './subchannel'; +import { LoadBalancingConfig, isCdsLoadBalancingConfig, EdsLbConfig, CdsLoadBalancingConfig } from './load-balancing-config'; +import { XdsClient, Watcher } from './xds-client'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; +import { ConnectivityState } from './channel'; +import { UnavailablePicker } from './picker'; +import { Status } from './constants'; +import { Metadata } from '.'; + +const TYPE_NAME = 'cds'; + +export class CdsLoadBalancer implements LoadBalancer { + private childBalancer: ChildLoadBalancerHandler; + private xdsClient: XdsClient | null = null; + private watcher: Watcher; + + private isWatcherActive = false; + + private latestCdsUpdate: Cluster__Output | null = null; + + private latestConfig: CdsLoadBalancingConfig | null = null; + private latestAttributes: { [key: string]: unknown } = {}; + + constructor(private readonly channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.watcher = { + onValidUpdate: update => { + this.latestCdsUpdate = update; + const edsConfig: EdsLbConfig = { + cluster: update.name, + edsServiceName: update.eds_cluster_config.service_name === '' ? undefined : update.eds_cluster_config.service_name, + localityPickingPolicy: [], + endpointPickingPolicy: [] + // TODO(murgatroid99): populate lrsLoadReportingServerName + } + this.childBalancer.updateAddressList([], {name: 'eds', eds: edsConfig}, this.latestAttributes); + }, + onResourceDoesNotExist: () => { + this.xdsClient?.removeClusterWatcher(this.latestConfig!.cds.cluster, this.watcher); + this.isWatcherActive = false; + }, + onTransientError: status => { + if (this.latestCdsUpdate === null) { + channelControlHelper.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: `xDS request failed with error ${status.details}`, + metadata: new Metadata(), + }) + ); + } + } + }; + } + + updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { + if (!isCdsLoadBalancingConfig(lbConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + this.xdsClient = attributes.xdsClient; + this.latestConfig = lbConfig; + this.latestAttributes = attributes; + + if (!this.isWatcherActive) { + this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); + this.isWatcherActive = true; + } + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + if (this.isWatcherActive) { + this.xdsClient?.removeClusterWatcher(this.latestConfig!.cds.cluster, this.watcher); + } + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer); +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 57582849f..d02754be5 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -91,8 +91,8 @@ export class EdsLoadBalancer implements LoadBalancer { this.updateChild(); }, onResourceDoesNotExist: () => { - /* TODO(murgatroid99): Figure out what needs to be done here after - * implementing CDS */ + this.xdsClient?.removeEndpointWatcher(this.edsServiceName!, this.watcher); + this.isWatcherActive = false; }, onTransientError: (status) => { if (this.latestEdsUpdate === null) { diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 164e1ab4d..92c4b2b9c 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -75,6 +75,10 @@ export interface EdsLbConfig { endpointPickingPolicy: LoadBalancingConfig[]; } +export interface CdsLbConfig { + cluster: string; +} + export interface PickFirstLoadBalancingConfig { name: 'pick_first'; pick_first: PickFirstConfig; @@ -110,6 +114,11 @@ export interface EdsLoadBalancingConfig { eds: EdsLbConfig; } +export interface CdsLoadBalancingConfig { + name: 'cds'; + cds: CdsLbConfig; +} + export type LoadBalancingConfig = | PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig @@ -117,7 +126,8 @@ export type LoadBalancingConfig = | GrpcLbLoadBalancingConfig | PriorityLoadBalancingConfig | WeightedTargetLoadBalancingConfig - | EdsLoadBalancingConfig; + | EdsLoadBalancingConfig + | CdsLoadBalancingConfig; export function isRoundRobinLoadBalancingConfig( lbconfig: LoadBalancingConfig @@ -155,6 +165,12 @@ export function isEdsLoadBalancingConfig( return lbconfig.name === 'eds'; } +export function isCdsLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is CdsLoadBalancingConfig { + return lbconfig.name === 'cds'; +} + /* In these functions we assume the input came from a JSON object. Therefore we * expect that the prototype is uninteresting and that `in` can be used * effectively */ diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 98454817f..c3e4e49fe 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -33,6 +33,7 @@ import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/disc import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; +import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; const TRACER_NAME = 'xds_client'; @@ -43,6 +44,7 @@ function trace(text: string): void { const clientVersion = require('../../package.json').version; const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; +const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster' let loadedProtos: Promise | null = null; @@ -105,6 +107,10 @@ export class XdsClient { > = new Map[]>(); private lastEdsVersionInfo = ''; private lastEdsNonce = ''; + + private clusterWatchers: Map[]> = new Map[]>(); + private lastCdsVersionInfo = ''; + private lastCdsNonce = ''; constructor( private targetName: string, @@ -209,6 +215,36 @@ export class XdsClient { this.ackEds(); break; } + case CDS_TYPE_URL: + const cdsResponses: Cluster__Output[] = []; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === CDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & Cluster__Output; + if (!this.validateCdsResponse(resp)) { + this.nackCds('Cluster validation failed'); + return; + } + } else { + this.nackEds( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); + return; + } + } + for (const message of cdsResponses) { + this.handleCdsResponse(message); + } + this.lastCdsVersionInfo = message.version_info; + this.lastCdsNonce = message.nonce; + this.ackCds(); + break; default: this.nackUnknown( message.type_url, @@ -270,6 +306,19 @@ export class XdsClient { }); } + private ackCds() { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node!, + type_url: CDS_TYPE_URL, + resource_names: Array.from(this.clusterWatchers.keys()), + response_nonce: this.lastCdsNonce, + version_info: this.lastCdsVersionInfo, + }); + } + /** * Reject an EDS update. This should be called without updating the local * nonce and version info. @@ -290,6 +339,22 @@ export class XdsClient { }); } + private nackCds(message: string) { + if (!this.adsCall) { + return; + } + this.adsCall.write({ + node: this.node!, + type_url: CDS_TYPE_URL, + resource_names: Array.from(this.clusterWatchers.keys()), + response_nonce: this.lastCdsNonce, + version_info: this.lastCdsVersionInfo, + error_detail: { + message, + }, + }); + } + /** * Validate the ClusterLoadAssignment object by these rules: * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto @@ -313,6 +378,24 @@ export class XdsClient { return true; } + private validateCdsResponse(message: Cluster__Output): boolean { + if (message.type !== 'EDS') { + return false; + } + if (!message.eds_cluster_config.eds_config.ads) { + return false; + } + if (message.lb_policy !== 'ROUND_ROBIN') { + return false; + } + if (message.lrs_server) { + if (!message.lrs_server.self) { + return false; + } + } + return true; + } + private handleEdsResponse(message: ClusterLoadAssignment__Output) { const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { @@ -320,6 +403,13 @@ export class XdsClient { } } + private handleCdsResponse(message: Cluster__Output) { + const watchers = this.clusterWatchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + private updateEdsNames() { if (this.adsCall) { this.adsCall.write({ @@ -332,8 +422,20 @@ export class XdsClient { } } + private updateCdsNames() { + if (this.adsCall) { + this.adsCall.write({ + node: this.node!, + type_url: CDS_TYPE_URL, + resource_names: Array.from(this.clusterWatchers.keys()), + response_nonce: this.lastCdsNonce, + version_info: this.lastCdsVersionInfo, + }); + } + } + private reportStreamError(status: StatusObject) { - for (const watcherList of this.endpointWatchers.values()) { + for (const watcherList of [...this.endpointWatchers.values(), ...this.clusterWatchers.values()]) { for (const watcher of watcherList) { watcher.onTransientError(status); } @@ -381,6 +483,46 @@ export class XdsClient { } } + addClusterWatcher( + clusterName: string, + watcher: Watcher + ) { + trace('Watcher added for cluster ' + clusterName); + let watchersEntry = this.clusterWatchers.get(clusterName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.clusterWatchers.set(clusterName, watchersEntry); + } + watchersEntry.push(watcher); + if (addedServiceName) { + this.updateCdsNames(); + } + } + + removeClusterWatcher( + clusterName: string, + watcher: Watcher + ) { + trace('Watcher removed for endpoint ' + clusterName); + const watchersEntry = this.clusterWatchers.get(clusterName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.endpointWatchers.delete(clusterName); + } + } + if (removedServiceName) { + this.updateCdsNames(); + } + } + shutdown(): void { this.adsCall?.cancel(); this.client?.close(); From 4963b0d9f8f0eda7025cf70ac0cc07bcb857bbb0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Jul 2020 14:06:42 -0700 Subject: [PATCH 1165/1899] Update protobufjs dependency to ^6.10.0 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 26b97d07e..22e28f73f 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -46,7 +46,7 @@ "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^4.0.0", - "protobufjs": "^6.9.0", + "protobufjs": "^6.10.0", "yargs": "^15.3.1" }, "devDependencies": { From b96cb3b8cc89d6494174a9f51dba280d778512f2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Jul 2020 14:26:38 -0700 Subject: [PATCH 1166/1899] Make messages always optional, fix map type generation --- .../bin/proto-loader-gen-types.ts | 255 +++++++++--------- packages/proto-loader/package.json | 2 +- 2 files changed, 136 insertions(+), 121 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 2fb72436e..23ac5f841 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -148,6 +148,52 @@ function formatComment(formatter: TextFormatter, comment?: string | null) { // GENERATOR FUNCTIONS +function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null): string { + switch (fieldType) { + case 'double': + case 'float': + return 'number | string'; + case 'int32': + case 'uint32': + case 'sint32': + case 'fixed32': + case 'sfixed32': + return 'number'; + case 'int64': + case 'uint64': + case 'sint64': + case 'fixed64': + case 'sfixed64': + return 'number | string | Long'; + case 'bool': + return 'boolean'; + case 'string': + return 'string'; + case 'bytes': + return 'Buffer | Uint8Array | string'; + default: + if (resolvedType === null) { + throw new Error('Found field with no usable type'); + } + const typeInterfaceName = getTypeInterfaceName(resolvedType); + if (resolvedType instanceof Protobuf.Type) { + return typeInterfaceName; + } else { + return `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; + } + } +} + +function getFieldTypePermissive(field: Protobuf.FieldBase): string { + const valueType = getTypeNamePermissive(field.type, field.resolvedType); + if (field instanceof Protobuf.MapField) { + const keyType = field.keyType === 'string' ? 'string' : 'number'; + return `{[key: ${keyType}]: ${valueType}}`; + } else { + return valueType; + } +} + function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { if (options.includeComments) { formatComment(formatter, messageType.comment); @@ -165,46 +211,7 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp formatter.indent(); for (const field of messageType.fieldsArray) { const repeatedString = field.repeated ? '[]' : ''; - let type: string; - switch (field.type) { - case 'double': - case 'float': - type = 'number | string'; - break; - case 'int32': - case 'uint32': - case 'sint32': - case 'fixed32': - case 'sfixed32': - type = 'number'; - break; - case 'int64': - case 'uint64': - case 'sint64': - case 'fixed64': - case 'sfixed64': - type = 'number | string | Long'; - break; - case 'bool': - type = 'boolean'; - break; - case 'string': - type = 'string'; - break; - case 'bytes': - type = 'Buffer | Uint8Array | string'; - break; - default: - if (field.resolvedType === null) { - throw new Error('Found field with no usable type'); - } - const typeInterfaceName = getTypeInterfaceName(field.resolvedType); - if (field.resolvedType instanceof Protobuf.Type) { - type = typeInterfaceName; - } else { - type = `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; - } - } + const type: string = getFieldTypePermissive(field); if (options.includeComments) { formatComment(formatter, field.comment); } @@ -221,6 +228,72 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp formatter.writeLine('}'); } +function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, options: GeneratorOptions): string { + switch (fieldType) { + case 'double': + case 'float': + if (options.json) { + return 'number | string'; + } else { + return 'number'; + } + case 'int32': + case 'uint32': + case 'sint32': + case 'fixed32': + case 'sfixed32': + return 'number'; + case 'int64': + case 'uint64': + case 'sint64': + case 'fixed64': + case 'sfixed64': + if (options.longs === Number) { + return 'number'; + } else if (options.longs === String) { + return 'string'; + } else { + return 'Long'; + } + case 'bool': + return 'boolean'; + case 'string': + return 'string'; + case 'bytes': + if (options.bytes === Array) { + return 'Uint8Array'; + } else if (options.bytes === String) { + return 'string'; + } else { + return 'Buffer'; + } + default: + if (resolvedType === null) { + throw new Error('Found field with no usable type'); + } + const typeInterfaceName = getTypeInterfaceName(resolvedType); + if (resolvedType instanceof Protobuf.Type) { + return typeInterfaceName + '__Output'; + } else { + if (options.enums == String) { + return `keyof typeof ${typeInterfaceName}`; + } else { + return typeInterfaceName; + } + } + } +} + +function getFieldTypeRestricted(field: Protobuf.FieldBase, options: GeneratorOptions): string { + const valueType = getTypeNameRestricted(field.type, field.resolvedType, options); + if (field instanceof Protobuf.MapField) { + const keyType = field.keyType === 'string' ? 'string' : 'number'; + return `{[key: ${keyType}]: ${valueType}}`; + } else { + return valueType; + } +} + function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { if (options.includeComments) { formatComment(formatter, messageType.comment); @@ -228,90 +301,39 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp if (messageType.fullName === '.google.protobuf.Any' && options.json) { /* This describes the behavior of the Protobuf.js Any wrapper toObject * replacement function */ + let optionalString = options.defaults ? '' : '?'; formatter.writeLine('export type Any__Output = AnyExtension | {'); - formatter.writeLine(' type_url: string;'); - let type: string; - if (options.bytes === Array) { - type = 'Uint8Array'; - } else if (options.bytes === String) { - type = 'string'; - } else { - type = 'Buffer'; - } - formatter.writeLine(` value: ${type};`); + formatter.writeLine(` type_url${optionalString}: string;`); + formatter.writeLine(` value${optionalString}: ${getTypeNameRestricted('bytes', null, options)};`); formatter.writeLine('}'); return; } formatter.writeLine(`export interface ${nameOverride ?? messageType.name}__Output {`); formatter.indent(); for (const field of messageType.fieldsArray) { - const repeatedString = field.repeated ? '[]' : ''; - let fieldGuaranteed = options.defaults || (field.repeated && options.arrays); - let type: string; - switch (field.type) { - case 'double': - case 'float': - if (options.json) { - type = 'number | string'; - } else { - type = 'number'; - } - break; - case 'int32': - case 'uint32': - case 'sint32': - case 'fixed32': - case 'sfixed32': - type = 'number'; - break; - case 'int64': - case 'uint64': - case 'sint64': - case 'fixed64': - case 'sfixed64': - if (options.longs === Number) { - type = 'number'; - } else if (options.longs === String) { - type = 'string'; - } else { - type = 'Long'; - } - break; - case 'bool': - type = 'boolean'; - break; - case 'string': - type = 'string'; - break; - case 'bytes': - if (options.bytes === Array) { - type = 'Uint8Array'; - } else if (options.bytes === String) { - type = 'string'; - } else { - type = 'Buffer'; - } - break; - default: - if (field.resolvedType === null) { - throw new Error('Found field with no usable type'); - } - const typeInterfaceName = getTypeInterfaceName(field.resolvedType); - if (field.resolvedType instanceof Protobuf.Type) { - fieldGuaranteed = fieldGuaranteed || options.objects; - type = typeInterfaceName + '__Output'; - } else { - if (options.enums == String) { - type = `keyof typeof ${typeInterfaceName}`; - } else { - type = typeInterfaceName; - } - } - } + let fieldGuaranteed: boolean; if (field.partOf) { + // The field is not guaranteed populated if it is part of a oneof fieldGuaranteed = false; + } else if (field.repeated) { + fieldGuaranteed = (options.defaults || options.arrays) ?? false; + } else if (field.resolvedType) { + if (field.resolvedType instanceof Protobuf.Enum) { + fieldGuaranteed = options.defaults ?? false; + } else { + // Message fields can always be omitted + fieldGuaranteed = false; + } + } else { + if (field.map) { + fieldGuaranteed = (options.defaults || options.objects) ?? false; + } else { + fieldGuaranteed = options.defaults ?? false; + } } const optionalString = fieldGuaranteed ? '' : '?'; + const repeatedString = field.repeated ? '[]' : ''; + const type = getFieldTypeRestricted(field, options); if (options.includeComments) { formatComment(formatter, field.comment); } @@ -643,13 +665,6 @@ function runScript() { // .choices('enums', ['String']) // .choices('bytes', ['Array', 'String']) .string(['longs', 'enums', 'bytes']) - .middleware(argv => { - if (argv.longs) { - switch (argv.longs) { - case 'String': argv.longsArg = String; - } - } - }) .coerce('longs', value => { switch (value) { case 'String': return String; diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 22e28f73f..b0897cf6b 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre10", + "version": "0.6.0-pre11", "author": "Google Inc.", "contributors": [ { From a3762259a1cfaee1d97978f9ad813a3cf8ae8583 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Jul 2020 14:32:19 -0700 Subject: [PATCH 1167/1899] Fix generated code errors --- .../src/generated/envoy/api/v2/Cluster.ts | 84 +++++++++---------- .../envoy/api/v2/ClusterLoadAssignment.ts | 12 +-- .../envoy/api/v2/DeltaDiscoveryRequest.ts | 8 +- .../envoy/api/v2/DiscoveryRequest.ts | 4 +- .../envoy/api/v2/DiscoveryResponse.ts | 2 +- .../src/generated/envoy/api/v2/Listener.ts | 26 +++--- .../envoy/api/v2/LoadBalancingPolicy.ts | 4 +- .../src/generated/envoy/api/v2/Resource.ts | 2 +- .../envoy/api/v2/RouteConfiguration.ts | 4 +- .../envoy/api/v2/UpstreamBindConfig.ts | 2 +- .../envoy/api/v2/UpstreamConnectionOptions.ts | 2 +- .../src/generated/envoy/api/v2/Vhds.ts | 2 +- .../v2/auth/CertificateValidationContext.ts | 8 +- .../envoy/api/v2/auth/CommonTlsContext.ts | 6 +- .../envoy/api/v2/auth/DownstreamTlsContext.ts | 8 +- .../envoy/api/v2/auth/GenericSecret.ts | 2 +- .../envoy/api/v2/auth/SdsSecretConfig.ts | 2 +- .../envoy/api/v2/auth/TlsCertificate.ts | 10 +-- .../envoy/api/v2/auth/UpstreamTlsContext.ts | 4 +- .../envoy/api/v2/cluster/CircuitBreakers.ts | 16 ++-- .../generated/envoy/api/v2/cluster/Filter.ts | 2 +- .../envoy/api/v2/cluster/OutlierDetection.ts | 38 ++++----- .../envoy/api/v2/core/ApiConfigSource.ts | 6 +- .../envoy/api/v2/core/BackoffStrategy.ts | 4 +- .../generated/envoy/api/v2/core/BindConfig.ts | 4 +- .../envoy/api/v2/core/BuildVersion.ts | 4 +- .../generated/envoy/api/v2/core/CidrRange.ts | 2 +- .../envoy/api/v2/core/ConfigSource.ts | 2 +- .../generated/envoy/api/v2/core/Extension.ts | 2 +- .../envoy/api/v2/core/GrpcProtocolOptions.ts | 2 +- .../envoy/api/v2/core/GrpcService.ts | 12 +-- .../envoy/api/v2/core/HeaderValueOption.ts | 4 +- .../envoy/api/v2/core/HealthCheck.ts | 36 ++++---- .../envoy/api/v2/core/Http1ProtocolOptions.ts | 4 +- .../envoy/api/v2/core/Http2ProtocolOptions.ts | 22 ++--- .../envoy/api/v2/core/HttpProtocolOptions.ts | 8 +- .../generated/envoy/api/v2/core/HttpUri.ts | 2 +- .../generated/envoy/api/v2/core/Metadata.ts | 4 +- .../src/generated/envoy/api/v2/core/Node.ts | 4 +- .../envoy/api/v2/core/RateLimitSettings.ts | 4 +- .../envoy/api/v2/core/RemoteDataSource.ts | 4 +- .../envoy/api/v2/core/RetryPolicy.ts | 4 +- .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 2 +- .../api/v2/core/RuntimeFractionalPercent.ts | 2 +- .../envoy/api/v2/core/TcpKeepalive.ts | 6 +- .../envoy/api/v2/endpoint/Endpoint.ts | 4 +- .../envoy/api/v2/endpoint/LbEndpoint.ts | 4 +- .../api/v2/endpoint/LocalityLbEndpoints.ts | 6 +- .../envoy/api/v2/listener/FilterChain.ts | 10 +-- .../envoy/api/v2/listener/FilterChainMatch.ts | 4 +- .../envoy/api/v2/listener/ListenerFilter.ts | 2 +- .../envoy/api/v2/route/CorsPolicy.ts | 4 +- .../generated/envoy/api/v2/route/Decorator.ts | 2 +- .../api/v2/route/DirectResponseAction.ts | 2 +- .../envoy/api/v2/route/FilterAction.ts | 2 +- .../envoy/api/v2/route/HedgePolicy.ts | 4 +- .../api/v2/route/QueryParameterMatcher.ts | 2 +- .../generated/envoy/api/v2/route/RateLimit.ts | 4 +- .../envoy/api/v2/route/RetryPolicy.ts | 12 +-- .../src/generated/envoy/api/v2/route/Route.ts | 18 ++-- .../envoy/api/v2/route/RouteAction.ts | 34 ++++---- .../envoy/api/v2/route/RouteMatch.ts | 12 +-- .../generated/envoy/api/v2/route/Tracing.ts | 6 +- .../envoy/api/v2/route/VirtualHost.ts | 18 ++-- .../envoy/api/v2/route/WeightedCluster.ts | 14 ++-- .../config/filter/accesslog/v2/AccessLog.ts | 2 +- .../filter/accesslog/v2/ComparisonFilter.ts | 2 +- .../filter/accesslog/v2/DurationFilter.ts | 2 +- .../filter/accesslog/v2/HeaderFilter.ts | 2 +- .../filter/accesslog/v2/RuntimeFilter.ts | 2 +- .../filter/accesslog/v2/StatusCodeFilter.ts | 2 +- .../envoy/config/listener/v2/ApiListener.ts | 2 +- .../type/matcher/RegexMatchAndSubstitute.ts | 2 +- .../envoy/type/matcher/RegexMatcher.ts | 2 +- .../envoy/type/tracing/v2/CustomTag.ts | 4 +- .../google/protobuf/DescriptorProto.ts | 2 +- .../google/protobuf/EnumDescriptorProto.ts | 2 +- .../generated/google/protobuf/EnumOptions.ts | 2 +- .../protobuf/EnumValueDescriptorProto.ts | 2 +- .../google/protobuf/EnumValueOptions.ts | 2 +- .../google/protobuf/FieldDescriptorProto.ts | 2 +- .../generated/google/protobuf/FieldOptions.ts | 4 +- .../google/protobuf/FileDescriptorProto.ts | 4 +- .../generated/google/protobuf/FileOptions.ts | 4 +- .../google/protobuf/MessageOptions.ts | 2 +- .../google/protobuf/MethodDescriptorProto.ts | 2 +- .../google/protobuf/MethodOptions.ts | 2 +- .../google/protobuf/OneofDescriptorProto.ts | 2 +- .../google/protobuf/ServiceDescriptorProto.ts | 2 +- .../src/generated/google/protobuf/Struct.ts | 4 +- .../src/generated/validate/DurationRules.ts | 10 +-- .../src/generated/validate/FieldRules.ts | 2 +- .../src/generated/validate/MapRules.ts | 4 +- .../src/generated/validate/RepeatedRules.ts | 2 +- .../src/generated/validate/TimestampRules.ts | 12 +-- packages/grpc-js/src/xds-bootstrap.ts | 20 ++--- 96 files changed, 329 insertions(+), 337 deletions(-) diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts index 4f6d10c60..4bda5ec6e 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts @@ -120,7 +120,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { * .. note:: * The specified percent will be truncated to the nearest 1%. */ - 'healthy_panic_threshold': (_envoy_type_Percent__Output); + 'healthy_panic_threshold'?: (_envoy_type_Percent__Output); 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); /** @@ -139,7 +139,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { * because merging those updates isn't currently safe. See * https://github.com/envoyproxy/envoy/pull/3941. */ - 'update_merge_window': (_google_protobuf_Duration__Output); + 'update_merge_window'?: (_google_protobuf_Duration__Output); /** * If set to true, Envoy will not consider new hosts when computing load balancing weights until * they have been health checked for the first time. This will have no effect unless @@ -170,7 +170,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ - 'consistent_hashing_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); + 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; } @@ -223,7 +223,7 @@ export interface _envoy_api_v2_Cluster_CustomClusterType__Output { * Cluster specific configuration which depends on the cluster being instantiated. * See the supported cluster for further documentation. */ - 'typed_config': (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output); } // Original file: deps/envoy-api/envoy/api/v2/cluster.proto @@ -306,7 +306,7 @@ export interface _envoy_api_v2_Cluster_EdsClusterConfig__Output { /** * Configuration for the source of EDS updates for this Cluster. */ - 'eds_config': (_envoy_api_v2_core_ConfigSource__Output); + 'eds_config'?: (_envoy_api_v2_core_ConfigSource__Output); /** * Optional alternative to cluster name to present to EDS. This does not * have the same restrictions as cluster name, i.e. it may be arbitrary @@ -494,7 +494,7 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { * is the same as a fallback_policy of * :ref:`NO_FALLBACK`. */ - 'default_subset': (_google_protobuf_Struct__Output); + 'default_subset'?: (_google_protobuf_Struct__Output); /** * For each entry, LbEndpoint.Metadata's * *envoy.lb* namespace is traversed and a subset is created for each unique @@ -671,7 +671,7 @@ export interface _envoy_api_v2_Cluster_LeastRequestLbConfig__Output { * The number of random healthy hosts from which the host with the fewest active requests will * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. */ - 'choice_count': (_google_protobuf_UInt32Value__Output); + 'choice_count'?: (_google_protobuf_UInt32Value__Output); } /** @@ -750,14 +750,14 @@ export interface _envoy_api_v2_Cluster_RefreshRate__Output { * than zero and less than * :ref:`max_interval `. */ - 'base_interval': (_google_protobuf_Duration__Output); + 'base_interval'?: (_google_protobuf_Duration__Output); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the * :ref:`base_interval ` if set. The default * is 10 times the :ref:`base_interval `. */ - 'max_interval': (_google_protobuf_Duration__Output); + 'max_interval'?: (_google_protobuf_Duration__Output); } /** @@ -796,7 +796,7 @@ export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { * to 1024 entries, and limited to 8M entries. See also * :ref:`maximum_ring_size`. */ - 'minimum_ring_size': (_google_protobuf_UInt64Value__Output); + 'minimum_ring_size'?: (_google_protobuf_UInt64Value__Output); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to * :ref:`XX_HASH`. @@ -807,7 +807,7 @@ export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { * to further constrain resource use. See also * :ref:`minimum_ring_size`. */ - 'maximum_ring_size': (_google_protobuf_UInt64Value__Output); + 'maximum_ring_size'?: (_google_protobuf_UInt64Value__Output); } /** @@ -849,11 +849,11 @@ export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { * The endpoint's metadata entry in *envoy.transport_socket_match* is used to match * against the values specified in this field. */ - 'match': (_google_protobuf_Struct__Output); + 'match'?: (_google_protobuf_Struct__Output); /** * The configuration of the transport socket. */ - 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket__Output); } /** @@ -896,7 +896,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'routing_enabled': (_envoy_type_Percent__Output); + 'routing_enabled'?: (_envoy_type_Percent__Output); /** * Configures minimum upstream cluster size required for zone aware routing * If upstream cluster size is less than specified, zone aware routing is not performed @@ -904,7 +904,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'min_cluster_size': (_google_protobuf_UInt64Value__Output); + 'min_cluster_size'?: (_google_protobuf_UInt64Value__Output); /** * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic * mode`. Instead, the cluster will fail all @@ -1155,14 +1155,14 @@ export interface Cluster { * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on * specific options. */ - 'extension_protocol_options'?: (_google_protobuf_Struct); + 'extension_protocol_options'?: ({[key: string]: _google_protobuf_Struct}); /** * The extension_protocol_options field is used to provide extension-specific protocol options * for upstream connections. The key should match the extension filter name, such as * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on * specific options. */ - 'typed_extension_protocol_options'?: (_google_protobuf_Any); + 'typed_extension_protocol_options'?: ({[key: string]: _google_protobuf_Any}); /** * Optional configuration for the LeastRequest load balancing policy. */ @@ -1317,16 +1317,16 @@ export interface Cluster__Output { /** * Configuration to use for EDS updates for the Cluster. */ - 'eds_cluster_config': (_envoy_api_v2_Cluster_EdsClusterConfig__Output); + 'eds_cluster_config'?: (_envoy_api_v2_Cluster_EdsClusterConfig__Output); /** * The timeout for new network connections to hosts in the cluster. */ - 'connect_timeout': (_google_protobuf_Duration__Output); + 'connect_timeout'?: (_google_protobuf_Duration__Output); /** * Soft limit on size of the cluster’s connections read and write buffers. If * unspecified, an implementation defined default is applied (1MiB). */ - 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. @@ -1358,11 +1358,11 @@ export interface Cluster__Output { * implementations. If not specified, there is no limit. Setting this * parameter to 1 will effectively disable keep alive. */ - 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output); + 'max_requests_per_connection'?: (_google_protobuf_UInt32Value__Output); /** * Optional :ref:`circuit breaking ` for the cluster. */ - 'circuit_breakers': (_envoy_api_v2_cluster_CircuitBreakers__Output); + 'circuit_breakers'?: (_envoy_api_v2_cluster_CircuitBreakers__Output); /** * The TLS configuration for connections to the upstream cluster. * @@ -1371,11 +1371,11 @@ export interface Cluster__Output { * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are * set, `transport_socket` takes priority. */ - 'tls_context': (_envoy_api_v2_auth_UpstreamTlsContext__Output); + 'tls_context'?: (_envoy_api_v2_auth_UpstreamTlsContext__Output); /** * Additional options when handling HTTP1 requests. */ - 'http_protocol_options': (_envoy_api_v2_core_Http1ProtocolOptions__Output); + 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions__Output); /** * Even if default HTTP2 protocol options are desired, this field must be * set so that Envoy will assume that the upstream supports HTTP/2 when @@ -1384,7 +1384,7 @@ export interface Cluster__Output { * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 * connections to happen over plain text. */ - 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); /** * If the DNS refresh rate is specified and the cluster type is either * :ref:`STRICT_DNS`, @@ -1396,7 +1396,7 @@ export interface Cluster__Output { * and :ref:`LOGICAL_DNS` * this setting is ignored. */ - 'dns_refresh_rate': (_google_protobuf_Duration__Output); + 'dns_refresh_rate'?: (_google_protobuf_Duration__Output); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to @@ -1421,7 +1421,7 @@ export interface Cluster__Output { * Each of the configuration values can be overridden via * :ref:`runtime values `. */ - 'outlier_detection': (_envoy_api_v2_cluster_OutlierDetection__Output); + 'outlier_detection'?: (_envoy_api_v2_cluster_OutlierDetection__Output); /** * The interval for removing stale hosts from a cluster type * :ref:`ORIGINAL_DST`. @@ -1437,17 +1437,17 @@ export interface Cluster__Output { * :ref:`ORIGINAL_DST` * this setting is ignored. */ - 'cleanup_interval': (_google_protobuf_Duration__Output); + 'cleanup_interval'?: (_google_protobuf_Duration__Output); /** * Optional configuration used to bind newly established upstream connections. * This overrides any bind_config specified in the bootstrap proto. * If the address and port are empty, no bind will be performed. */ - 'upstream_bind_config': (_envoy_api_v2_core_BindConfig__Output); + 'upstream_bind_config'?: (_envoy_api_v2_core_BindConfig__Output); /** * Configuration for load balancing subsetting. */ - 'lb_subset_config': (_envoy_api_v2_Cluster_LbSubsetConfig__Output); + 'lb_subset_config'?: (_envoy_api_v2_Cluster_LbSubsetConfig__Output); /** * Optional configuration for the Ring Hash load balancing policy. */ @@ -1459,7 +1459,7 @@ export interface Cluster__Output { * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket__Output); /** * The Metadata field can be used to provide additional information about the * cluster. It can be used for stats, logging, and varying filter behavior. @@ -1467,7 +1467,7 @@ export interface Cluster__Output { * will need the information. For instance, if the metadata is intended for * the Router filter, the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_api_v2_core_Metadata__Output); /** * Determines how Envoy selects the protocol used to speak to upstream hosts. */ @@ -1475,7 +1475,7 @@ export interface Cluster__Output { /** * Common configuration for all load balancer implementations. */ - 'common_lb_config': (_envoy_api_v2_Cluster_CommonLbConfig__Output); + 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig__Output); /** * An optional alternative to the cluster name to be used while emitting stats. * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be @@ -1487,11 +1487,11 @@ export interface Cluster__Output { * Additional options when handling HTTP requests upstream. These options will be applicable to * both HTTP1 and HTTP2 requests. */ - 'common_http_protocol_options': (_envoy_api_v2_core_HttpProtocolOptions__Output); + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions__Output); /** * Optional options for upstream connections. */ - 'upstream_connection_options': (_envoy_api_v2_UpstreamConnectionOptions__Output); + 'upstream_connection_options'?: (_envoy_api_v2_UpstreamConnectionOptions__Output); /** * If an upstream host becomes unhealthy (as determined by the configured health checks * or outlier detection), immediately close all connections to the failed host. @@ -1526,7 +1526,7 @@ export interface Cluster__Output { * Setting this allows non-EDS cluster types to contain embedded EDS equivalent * :ref:`endpoint assignments`. */ - 'load_assignment': (_envoy_api_v2_ClusterLoadAssignment__Output); + 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment__Output); /** * Optional configuration for the Original Destination load balancing policy. */ @@ -1537,14 +1537,14 @@ export interface Cluster__Output { * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on * specific options. */ - 'extension_protocol_options': (_google_protobuf_Struct__Output); + 'extension_protocol_options'?: ({[key: string]: _google_protobuf_Struct__Output}); /** * The extension_protocol_options field is used to provide extension-specific protocol options * for upstream connections. The key should match the extension filter name, such as * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on * specific options. */ - 'typed_extension_protocol_options': (_google_protobuf_Any__Output); + 'typed_extension_protocol_options'?: ({[key: string]: _google_protobuf_Any__Output}); /** * Optional configuration for the LeastRequest load balancing policy. */ @@ -1570,7 +1570,7 @@ export interface Cluster__Output { * :ref:`lb_policy` field has the value * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ - 'load_balancing_policy': (_envoy_api_v2_LoadBalancingPolicy__Output); + 'load_balancing_policy'?: (_envoy_api_v2_LoadBalancingPolicy__Output); /** * [#not-implemented-hide:] * If present, tells the client where to send load reports via LRS. If not present, the @@ -1587,7 +1587,7 @@ export interface Cluster__Output { * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation * from the LRS stream here.] */ - 'lrs_server': (_envoy_api_v2_core_ConfigSource__Output); + 'lrs_server'?: (_envoy_api_v2_core_ConfigSource__Output); /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the @@ -1646,7 +1646,7 @@ export interface Cluster__Output { * :ref:`LOGICAL_DNS` this setting is * ignored. */ - 'dns_failure_refresh_rate': (_envoy_api_v2_Cluster_RefreshRate__Output); + 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate__Output); /** * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. @@ -1656,7 +1656,7 @@ export interface Cluster__Output { * HTTP protocol options that are applied only to upstream HTTP connections. * These options apply to all HTTP versions. */ - 'upstream_http_protocol_options': (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); + 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); /** * If track_timeout_budgets is true, the :ref:`timeout budget histograms * ` will be published for each diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts index ecb8034ed..bb5ac327d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts @@ -31,7 +31,7 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output /** * Percentage of traffic that should be dropped for the category. */ - 'drop_percentage': (_envoy_type_FractionalPercent__Output); + 'drop_percentage'?: (_envoy_type_FractionalPercent__Output); } /** @@ -143,14 +143,14 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { * Read more at :ref:`priority levels ` and * :ref:`localities `. */ - 'overprovisioning_factor': (_google_protobuf_UInt32Value__Output); + 'overprovisioning_factor'?: (_google_protobuf_UInt32Value__Output); /** * The max time until which the endpoints from this assignment can be used. * If no new assignments are received before this time expires the endpoints * are considered stale and should be marked unhealthy. * Defaults to 0 which means endpoints never go stale. */ - 'endpoint_stale_after': (_google_protobuf_Duration__Output); + 'endpoint_stale_after'?: (_google_protobuf_Duration__Output); /** * The flag to disable overprovisioning. If it is set to true, * :ref:`overprovisioning factor @@ -196,7 +196,7 @@ export interface ClusterLoadAssignment { * Map of named endpoints that can be referenced in LocalityLbEndpoints. * [#not-implemented-hide:] */ - 'named_endpoints'?: (_envoy_api_v2_endpoint_Endpoint); + 'named_endpoints'?: ({[key: string]: _envoy_api_v2_endpoint_Endpoint}); } /** @@ -226,10 +226,10 @@ export interface ClusterLoadAssignment__Output { /** * Load balancing policy settings. */ - 'policy': (_envoy_api_v2_ClusterLoadAssignment_Policy__Output); + 'policy'?: (_envoy_api_v2_ClusterLoadAssignment_Policy__Output); /** * Map of named endpoints that can be referenced in LocalityLbEndpoints. * [#not-implemented-hide:] */ - 'named_endpoints': (_envoy_api_v2_endpoint_Endpoint__Output); + 'named_endpoints'?: ({[key: string]: _envoy_api_v2_endpoint_Endpoint__Output}); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts index 341c9b9a4..4791e30b3 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts @@ -86,7 +86,7 @@ export interface DeltaDiscoveryRequest { * The map's keys are names of xDS resources known to the xDS client. * The map's values are opaque resource versions. */ - 'initial_resource_versions'?: (string); + 'initial_resource_versions'?: ({[key: string]: string}); /** * When the DeltaDiscoveryRequest is a ACK or NACK message in response * to a previous DeltaDiscoveryResponse, the response_nonce must be the @@ -141,7 +141,7 @@ export interface DeltaDiscoveryRequest__Output { /** * The node making the request. */ - 'node': (_envoy_api_v2_core_Node__Output); + 'node'?: (_envoy_api_v2_core_Node__Output); /** * Type of the resource that is being requested, e.g. * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". @@ -185,7 +185,7 @@ export interface DeltaDiscoveryRequest__Output { * The map's keys are names of xDS resources known to the xDS client. * The map's values are opaque resource versions. */ - 'initial_resource_versions': (string); + 'initial_resource_versions': ({[key: string]: string}); /** * When the DeltaDiscoveryRequest is a ACK or NACK message in response * to a previous DeltaDiscoveryResponse, the response_nonce must be the @@ -198,5 +198,5 @@ export interface DeltaDiscoveryRequest__Output { * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ - 'error_detail': (_google_rpc_Status__Output); + 'error_detail'?: (_google_rpc_Status__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts index 43c926b74..ee24e74fa 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts @@ -75,7 +75,7 @@ export interface DiscoveryRequest__Output { /** * The node making the request. */ - 'node': (_envoy_api_v2_core_Node__Output); + 'node'?: (_envoy_api_v2_core_Node__Output); /** * List of resources to subscribe to, e.g. list of cluster names or a route * configuration name. If this is empty, all resources for the API are @@ -106,5 +106,5 @@ export interface DiscoveryRequest__Output { * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. */ - 'error_detail': (_google_rpc_Status__Output); + 'error_detail'?: (_google_rpc_Status__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts index db6033ffa..8eb7d42c0 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts @@ -104,5 +104,5 @@ export interface DiscoveryResponse__Output { * [#not-implemented-hide:] * The control plane instance that sent the response. */ - 'control_plane': (_envoy_api_v2_core_ControlPlane__Output); + 'control_plane'?: (_envoy_api_v2_core_ControlPlane__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts index 9c0368ce7..73bfb6ec6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts @@ -70,7 +70,7 @@ export interface _envoy_api_v2_Listener_DeprecatedV1__Output { * * [#comment:TODO(PiotrSikora): Remove this once verified that we no longer need it.] */ - 'bind_to_port': (_google_protobuf_BoolValue__Output); + 'bind_to_port'?: (_google_protobuf_BoolValue__Output); } // Original file: deps/envoy-api/envoy/api/v2/listener.proto @@ -322,7 +322,7 @@ export interface Listener__Output { * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on * Linux as the actual port will be allocated by the OS. */ - 'address': (_envoy_api_v2_core_Address__Output); + 'address'?: (_envoy_api_v2_core_Address__Output); /** * A list of filter chains to consider for this listener. The * :ref:`FilterChain ` with the most specific @@ -350,20 +350,20 @@ export interface Listener__Output { * will be removed, as filter chain matching can be used to select a filter chain based on the * restored destination address. */ - 'use_original_dst': (_google_protobuf_BoolValue__Output); + 'use_original_dst'?: (_google_protobuf_BoolValue__Output); /** * Soft limit on size of the listener’s new connection read and write buffers. * If unspecified, an implementation defined default is applied (1MiB). */ - 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); /** * Listener metadata. */ - 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_api_v2_core_Metadata__Output); /** * [#not-implemented-hide:] */ - 'deprecated_v1': (_envoy_api_v2_Listener_DeprecatedV1__Output); + 'deprecated_v1'?: (_envoy_api_v2_Listener_DeprecatedV1__Output); /** * The type of draining to perform at a listener-wide level. */ @@ -396,7 +396,7 @@ export interface Listener__Output { * When this flag is not set (default), the socket is not modified, i.e. the transparent option * is neither set nor reset. */ - 'transparent': (_google_protobuf_BoolValue__Output); + 'transparent'?: (_google_protobuf_BoolValue__Output); /** * Whether the listener should set the *IP_FREEBIND* socket option. When this * flag is set to true, listeners can be bound to an IP address that is not @@ -405,7 +405,7 @@ export interface Listener__Output { * (default), the socket is not modified, i.e. the option is neither enabled * nor disabled. */ - 'freebind': (_google_protobuf_BoolValue__Output); + 'freebind'?: (_google_protobuf_BoolValue__Output); /** * Whether the listener should accept TCP Fast Open (TFO) connections. * When this flag is set to a value greater than 0, the option TCP_FASTOPEN is enabled on @@ -422,7 +422,7 @@ export interface Listener__Output { * On macOS, only values of 0, 1, and unset are valid; other values may result in an error. * To set the queue length on macOS, set the net.inet.tcp.fastopen_backlog kernel parameter. */ - 'tcp_fast_open_queue_length': (_google_protobuf_UInt32Value__Output); + 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value__Output); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. @@ -434,7 +434,7 @@ export interface Listener__Output { * `continue_on_listener_filters_timeout` is set to true. Specify 0 to disable the * timeout. If not specified, a default timeout of 15s is used. */ - 'listener_filters_timeout': (_google_protobuf_Duration__Output); + 'listener_filters_timeout'?: (_google_protobuf_Duration__Output); /** * Specifies the intended direction of the traffic relative to the local Envoy. */ @@ -457,7 +457,7 @@ export interface Listener__Output { * ` = "raw_udp_listener" for * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". */ - 'udp_listener_config': (_envoy_api_v2_listener_UdpListenerConfig__Output); + 'udp_listener_config'?: (_envoy_api_v2_listener_UdpListenerConfig__Output); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. @@ -476,13 +476,13 @@ export interface Listener__Output { * socket listener and the various types of API listener. That way, a given Listener message * can structurally only contain the fields of the relevant type.] */ - 'api_listener': (_envoy_config_listener_v2_ApiListener__Output); + 'api_listener'?: (_envoy_config_listener_v2_ApiListener__Output); /** * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. */ - 'connection_balance_config': (_envoy_api_v2_Listener_ConnectionBalanceConfig__Output); + 'connection_balance_config'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig__Output); /** * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and * create one socket for each worker thread. This makes inbound connections diff --git a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts index b2653ca03..03c33c853 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts @@ -25,8 +25,8 @@ export interface _envoy_api_v2_LoadBalancingPolicy_Policy__Output { * Optional config for the LB policy. * No more than one of these two fields may be populated. */ - 'config': (_google_protobuf_Struct__Output); - 'typed_config': (_google_protobuf_Any__Output); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); } /** diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts index 11fb70002..88c511cb1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts @@ -31,7 +31,7 @@ export interface Resource__Output { /** * The resource being tracked. */ - 'resource': (_google_protobuf_Any__Output); + 'resource'?: (_google_protobuf_Any__Output); /** * The resource's name, to distinguish it from others of the same type of resource. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts index 538c15b35..495950ff6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts @@ -155,7 +155,7 @@ export interface RouteConfiguration__Output { * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ - 'validate_clusters': (_google_protobuf_BoolValue__Output); + 'validate_clusters'?: (_google_protobuf_BoolValue__Output); /** * Specifies a list of HTTP headers that should be removed from each request * routed by the HTTP connection manager. @@ -169,7 +169,7 @@ export interface RouteConfiguration__Output { * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration * taking precedence. */ - 'vhds': (_envoy_api_v2_Vhds__Output); + 'vhds'?: (_envoy_api_v2_Vhds__Output); /** * By default, headers that should be added/removed are evaluated from most to least specific: * diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts index 2b26da489..d90e9ad91 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts @@ -21,5 +21,5 @@ export interface UpstreamBindConfig__Output { /** * The address Envoy should bind to when establishing upstream connections. */ - 'source_address': (_envoy_api_v2_core_Address__Output); + 'source_address'?: (_envoy_api_v2_core_Address__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts index 2fc601530..6a4244741 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts @@ -13,5 +13,5 @@ export interface UpstreamConnectionOptions__Output { /** * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. */ - 'tcp_keepalive': (_envoy_api_v2_core_TcpKeepalive__Output); + 'tcp_keepalive'?: (_envoy_api_v2_core_TcpKeepalive__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts index f30d4a721..a89f2276b 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts @@ -13,5 +13,5 @@ export interface Vhds__Output { /** * Configuration source specifier for VHDS. */ - 'config_source': (_envoy_api_v2_core_ConfigSource__Output); + 'config_source'?: (_envoy_api_v2_core_ConfigSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts index e45e0a4a8..fe8637fd3 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts @@ -193,7 +193,7 @@ export interface CertificateValidationContext__Output { * See :ref:`the TLS overview ` for a list of common * system CA locations. */ - 'trusted_ca': (_envoy_api_v2_core_DataSource__Output); + 'trusted_ca'?: (_envoy_api_v2_core_DataSource__Output); /** * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. @@ -270,11 +270,11 @@ export interface CertificateValidationContext__Output { /** * [#not-implemented-hide:] Must present a signed time-stamped OCSP response. */ - 'require_ocsp_staple': (_google_protobuf_BoolValue__Output); + 'require_ocsp_staple'?: (_google_protobuf_BoolValue__Output); /** * [#not-implemented-hide:] Must present signed certificate time-stamp. */ - 'require_signed_certificate_timestamp': (_google_protobuf_BoolValue__Output); + 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue__Output); /** * An optional `certificate revocation list * `_ @@ -282,7 +282,7 @@ export interface CertificateValidationContext__Output { * certificate has not been revoked by this CRL. If this DataSource contains * multiple CRLs, all of them will be used. */ - 'crl': (_envoy_api_v2_core_DataSource__Output); + 'crl'?: (_envoy_api_v2_core_DataSource__Output); /** * If specified, Envoy will not reject expired certificates. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts index b75f3f533..a57288fa5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts @@ -20,11 +20,11 @@ export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidati /** * How to validate peer certificates. */ - 'default_validation_context': (_envoy_api_v2_auth_CertificateValidationContext__Output); + 'default_validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); /** * Config for fetching validation context via SDS API. */ - 'validation_context_sds_secret_config': (_envoy_api_v2_auth_SdsSecretConfig__Output); + 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); } /** @@ -91,7 +91,7 @@ export interface CommonTlsContext__Output { /** * TLS protocol versions, cipher suites etc. */ - 'tls_params': (_envoy_api_v2_auth_TlsParameters__Output); + 'tls_params'?: (_envoy_api_v2_auth_TlsParameters__Output); /** * :ref:`Multiple TLS certificates ` can be associated with the * same context to allow both RSA and ECDSA certificates. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts index faf26f180..c63b2a719 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts @@ -60,17 +60,17 @@ export interface DownstreamTlsContext__Output { /** * Common TLS context settings. */ - 'common_tls_context': (_envoy_api_v2_auth_CommonTlsContext__Output); + 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext__Output); /** * If specified, Envoy will reject connections without a valid client * certificate. */ - 'require_client_certificate': (_google_protobuf_BoolValue__Output); + 'require_client_certificate'?: (_google_protobuf_BoolValue__Output); /** * If specified, Envoy will reject connections without a valid and matching SNI. * [#not-implemented-hide:] */ - 'require_sni': (_google_protobuf_BoolValue__Output); + 'require_sni'?: (_google_protobuf_BoolValue__Output); /** * TLS session ticket key settings. */ @@ -85,7 +85,7 @@ export interface DownstreamTlsContext__Output { * ` * only seconds could be specified (fractional seconds are going to be ignored). */ - 'session_timeout': (_google_protobuf_Duration__Output); + 'session_timeout'?: (_google_protobuf_Duration__Output); /** * Config for controlling stateless TLS session resumption: setting this to true will cause the TLS * server to not issue TLS session tickets for the purposes of stateless TLS session resumption. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts index 761009282..fc57bebb1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts @@ -13,5 +13,5 @@ export interface GenericSecret__Output { /** * Secret of generic type and is available to filters. */ - 'secret': (_envoy_api_v2_core_DataSource__Output); + 'secret'?: (_envoy_api_v2_core_DataSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts index bcddbaf09..5a4292951 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts @@ -19,5 +19,5 @@ export interface SdsSecretConfig__Output { * SDS. When only name is specified, then secret will be loaded from static resources. */ 'name': (string); - 'sds_config': (_envoy_api_v2_core_ConfigSource__Output); + 'sds_config'?: (_envoy_api_v2_core_ConfigSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts index 243789b23..cdefe7040 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts @@ -47,20 +47,20 @@ export interface TlsCertificate__Output { /** * The TLS certificate chain. */ - 'certificate_chain': (_envoy_api_v2_core_DataSource__Output); + 'certificate_chain'?: (_envoy_api_v2_core_DataSource__Output); /** * The TLS private key. */ - 'private_key': (_envoy_api_v2_core_DataSource__Output); + 'private_key'?: (_envoy_api_v2_core_DataSource__Output); /** * The password to decrypt the TLS private key. If this field is not set, it is assumed that the * TLS private key is not password encrypted. */ - 'password': (_envoy_api_v2_core_DataSource__Output); + 'password'?: (_envoy_api_v2_core_DataSource__Output); /** * [#not-implemented-hide:] */ - 'ocsp_staple': (_envoy_api_v2_core_DataSource__Output); + 'ocsp_staple'?: (_envoy_api_v2_core_DataSource__Output); /** * [#not-implemented-hide:] */ @@ -74,5 +74,5 @@ export interface TlsCertificate__Output { * ` fields will result in an * error. */ - 'private_key_provider': (_envoy_api_v2_auth_PrivateKeyProvider__Output); + 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts index 78c7eaaa2..7a56be3c0 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts @@ -45,7 +45,7 @@ export interface UpstreamTlsContext__Output { * :ref:`trusted_ca` to enable * verification. */ - 'common_tls_context': (_envoy_api_v2_auth_CommonTlsContext__Output); + 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext__Output); /** * SNI string to use when creating TLS backend connections. */ @@ -64,5 +64,5 @@ export interface UpstreamTlsContext__Output { * * Defaults to 1, setting this to 0 disables session resumption. */ - 'max_session_keys': (_google_protobuf_UInt32Value__Output); + 'max_session_keys'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts index 0b2f01db6..f9380aec1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts @@ -30,14 +30,14 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__O * * This parameter is optional. Defaults to 20%. */ - 'budget_percent': (_envoy_type_Percent__Output); + 'budget_percent'?: (_envoy_type_Percent__Output); /** * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the * number of active retries may never go below this number. * * This parameter is optional. Defaults to 3. */ - 'min_retry_concurrency': (_google_protobuf_UInt32Value__Output); + 'min_retry_concurrency'?: (_google_protobuf_UInt32Value__Output); } /** @@ -117,22 +117,22 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { * The maximum number of connections that Envoy will make to the upstream * cluster. If not specified, the default is 1024. */ - 'max_connections': (_google_protobuf_UInt32Value__Output); + 'max_connections'?: (_google_protobuf_UInt32Value__Output); /** * The maximum number of pending requests that Envoy will allow to the * upstream cluster. If not specified, the default is 1024. */ - 'max_pending_requests': (_google_protobuf_UInt32Value__Output); + 'max_pending_requests'?: (_google_protobuf_UInt32Value__Output); /** * The maximum number of parallel requests that Envoy will make to the * upstream cluster. If not specified, the default is 1024. */ - 'max_requests': (_google_protobuf_UInt32Value__Output); + 'max_requests'?: (_google_protobuf_UInt32Value__Output); /** * The maximum number of parallel retries that Envoy will allow to the * upstream cluster. If not specified, the default is 3. */ - 'max_retries': (_google_protobuf_UInt32Value__Output); + 'max_retries'?: (_google_protobuf_UInt32Value__Output); /** * Specifies a limit on concurrent retries in relation to the number of active requests. This * parameter is optional. @@ -142,7 +142,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { * If this field is set, the retry budget will override any configured retry circuit * breaker. */ - 'retry_budget': (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output); + 'retry_budget'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output); /** * If track_remaining is true, then stats will be published that expose * the number of resources remaining until the circuit breakers open. If @@ -161,7 +161,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { * :ref:`Circuit Breaking ` for * more details. */ - 'max_connection_pools': (_google_protobuf_UInt32Value__Output); + 'max_connection_pools'?: (_google_protobuf_UInt32Value__Output); } /** diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts index 9e54a595e..225928629 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts @@ -25,5 +25,5 @@ export interface Filter__Output { * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. */ - 'typed_config': (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts index 6cd429c12..995b01180 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts @@ -162,43 +162,43 @@ export interface OutlierDetection__Output { * to 5xx error codes before a consecutive 5xx ejection * occurs. Defaults to 5. */ - 'consecutive_5xx': (_google_protobuf_UInt32Value__Output); + 'consecutive_5xx'?: (_google_protobuf_UInt32Value__Output); /** * The time interval between ejection analysis sweeps. This can result in * both new ejections as well as hosts being returned to service. Defaults * to 10000ms or 10s. */ - 'interval': (_google_protobuf_Duration__Output); + 'interval'?: (_google_protobuf_Duration__Output); /** * The base time that a host is ejected for. The real time is equal to the * base time multiplied by the number of times the host has been ejected. * Defaults to 30000ms or 30s. */ - 'base_ejection_time': (_google_protobuf_Duration__Output); + 'base_ejection_time'?: (_google_protobuf_Duration__Output); /** * The maximum % of an upstream cluster that can be ejected due to outlier * detection. Defaults to 10% but will eject at least one host regardless of the value. */ - 'max_ejection_percent': (_google_protobuf_UInt32Value__Output); + 'max_ejection_percent'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive 5xx. This setting can be used to disable * ejection or to ramp it up slowly. Defaults to 100. */ - 'enforcing_consecutive_5xx': (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_5xx'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status * is detected through success rate statistics. This setting can be used to * disable ejection or to ramp it up slowly. Defaults to 100. */ - 'enforcing_success_rate': (_google_protobuf_UInt32Value__Output); + 'enforcing_success_rate'?: (_google_protobuf_UInt32Value__Output); /** * The number of hosts in a cluster that must have enough request volume to * detect success rate outliers. If the number of hosts is less than this * setting, outlier detection via success rate statistics is not performed * for any host in the cluster. Defaults to 5. */ - 'success_rate_minimum_hosts': (_google_protobuf_UInt32Value__Output); + 'success_rate_minimum_hosts'?: (_google_protobuf_UInt32Value__Output); /** * The minimum number of total requests that must be collected in one * interval (as defined by the interval duration above) to include this host @@ -206,7 +206,7 @@ export interface OutlierDetection__Output { * setting, outlier detection via success rate statistics is not performed * for that host. Defaults to 100. */ - 'success_rate_request_volume': (_google_protobuf_UInt32Value__Output); + 'success_rate_request_volume'?: (_google_protobuf_UInt32Value__Output); /** * This factor is used to determine the ejection threshold for success rate * outlier ejection. The ejection threshold is the difference between the @@ -216,18 +216,18 @@ export interface OutlierDetection__Output { * double. That is, if the desired factor is 1.9, the runtime value should * be 1900. Defaults to 1900. */ - 'success_rate_stdev_factor': (_google_protobuf_UInt32Value__Output); + 'success_rate_stdev_factor'?: (_google_protobuf_UInt32Value__Output); /** * The number of consecutive gateway failures (502, 503, 504 status codes) * before a consecutive gateway failure ejection occurs. Defaults to 5. */ - 'consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output); + 'consecutive_gateway_failure'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive gateway failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 0. */ - 'enforcing_consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_gateway_failure'?: (_google_protobuf_UInt32Value__Output); /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: @@ -244,7 +244,7 @@ export interface OutlierDetection__Output { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output); + 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive locally originated failures. This setting can be @@ -253,7 +253,7 @@ export interface OutlierDetection__Output { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'enforcing_consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status * is detected through success rate statistics for locally originated errors. @@ -262,13 +262,13 @@ export interface OutlierDetection__Output { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'enforcing_local_origin_success_rate': (_google_protobuf_UInt32Value__Output); + 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value__Output); /** * The failure percentage to use when determining failure percentage-based outlier detection. If * the failure percentage of a given host is greater than or equal to this value, it will be * ejected. Defaults to 85. */ - 'failure_percentage_threshold': (_google_protobuf_UInt32Value__Output); + 'failure_percentage_threshold'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status is detected through * failure percentage statistics. This setting can be used to disable ejection or to ramp it up @@ -277,24 +277,24 @@ export interface OutlierDetection__Output { * [#next-major-version: setting this without setting failure_percentage_threshold should be * invalid in v4.] */ - 'enforcing_failure_percentage': (_google_protobuf_UInt32Value__Output); + 'enforcing_failure_percentage'?: (_google_protobuf_UInt32Value__Output); /** * The % chance that a host will be actually ejected when an outlier status is detected through * local-origin failure percentage statistics. This setting can be used to disable ejection or to * ramp it up slowly. Defaults to 0. */ - 'enforcing_failure_percentage_local_origin': (_google_protobuf_UInt32Value__Output); + 'enforcing_failure_percentage_local_origin'?: (_google_protobuf_UInt32Value__Output); /** * The minimum number of hosts in a cluster in order to perform failure percentage-based ejection. * If the total number of hosts in the cluster is less than this value, failure percentage-based * ejection will not be performed. Defaults to 5. */ - 'failure_percentage_minimum_hosts': (_google_protobuf_UInt32Value__Output); + 'failure_percentage_minimum_hosts'?: (_google_protobuf_UInt32Value__Output); /** * The minimum number of total requests that must be collected in one interval (as defined by the * interval duration above) to perform failure percentage-based ejection for this host. If the * volume is lower than this setting, failure percentage-based ejection will not be performed for * this host. Defaults to 50. */ - 'failure_percentage_request_volume': (_google_protobuf_UInt32Value__Output); + 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts index ecec8d5a5..b6906acd5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts @@ -108,7 +108,7 @@ export interface ApiConfigSource__Output { /** * For REST APIs, the delay between successive polls. */ - 'refresh_delay': (_google_protobuf_Duration__Output); + 'refresh_delay'?: (_google_protobuf_Duration__Output); /** * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, * services will be cycled through if any kind of failure occurs. @@ -117,12 +117,12 @@ export interface ApiConfigSource__Output { /** * For REST APIs, the request timeout. If not set, a default value of 1s will be used. */ - 'request_timeout': (_google_protobuf_Duration__Output); + 'request_timeout'?: (_google_protobuf_Duration__Output); /** * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be * rate limited. */ - 'rate_limit_settings': (_envoy_api_v2_core_RateLimitSettings__Output); + 'rate_limit_settings'?: (_envoy_api_v2_core_RateLimitSettings__Output); /** * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts index 636b768fe..3e8c6dd49 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts @@ -31,7 +31,7 @@ export interface BackoffStrategy__Output { * be greater than zero and less than or equal to :ref:`max_interval * `. */ - 'base_interval': (_google_protobuf_Duration__Output); + 'base_interval'?: (_google_protobuf_Duration__Output); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval @@ -39,5 +39,5 @@ export interface BackoffStrategy__Output { * is 10 times the :ref:`base_interval * `. */ - 'max_interval': (_google_protobuf_Duration__Output); + 'max_interval'?: (_google_protobuf_Duration__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts index af81592bf..8b8451080 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts @@ -30,7 +30,7 @@ export interface BindConfig__Output { /** * The address to bind to when creating a socket. */ - 'source_address': (_envoy_api_v2_core_SocketAddress__Output); + 'source_address'?: (_envoy_api_v2_core_SocketAddress__Output); /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address @@ -40,7 +40,7 @@ export interface BindConfig__Output { * flag is not set (default), the socket is not modified, i.e. the option is * neither enabled nor disabled. */ - 'freebind': (_google_protobuf_BoolValue__Output); + 'freebind'?: (_google_protobuf_BoolValue__Output); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts index 305ad3c4d..b3b9a808d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts @@ -27,10 +27,10 @@ export interface BuildVersion__Output { /** * SemVer version of extension. */ - 'version': (_envoy_type_SemanticVersion__Output); + 'version'?: (_envoy_type_SemanticVersion__Output); /** * Free-form build information. * Envoy defines several well known keys in the source/common/common/version.h file */ - 'metadata': (_google_protobuf_Struct__Output); + 'metadata'?: (_google_protobuf_Struct__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts index e0c19da92..18b693fcf 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts @@ -29,5 +29,5 @@ export interface CidrRange__Output { /** * Length of prefix, e.g. 0, 32. */ - 'prefix_len': (_google_protobuf_UInt32Value__Output); + 'prefix_len'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts index 3ce5cc5d8..1e4bfa4cd 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts @@ -118,7 +118,7 @@ export interface ConfigSource__Output { * means no timeout - Envoy will wait indefinitely for the first xDS config (unless another * timeout applies). The default is 15s. */ - 'initial_fetch_timeout': (_google_protobuf_Duration__Output); + 'initial_fetch_timeout'?: (_google_protobuf_Duration__Output); /** * [#not-implemented-hide:] * When set, the client will access the resources from the same server it got the diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts index 3d17d6225..3656f1f9a 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts @@ -67,7 +67,7 @@ export interface Extension__Output { * of other extensions and the Envoy API. * This field is not set when extension did not provide version information. */ - 'version': (_envoy_api_v2_core_BuildVersion__Output); + 'version'?: (_envoy_api_v2_core_BuildVersion__Output); /** * Indicates that the extension is present but was disabled via dynamic configuration. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts index 65148f419..038245239 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts @@ -13,5 +13,5 @@ export interface GrpcProtocolOptions { * [#not-implemented-hide:] */ export interface GrpcProtocolOptions__Output { - 'http2_protocol_options': (_envoy_api_v2_core_Http2ProtocolOptions__Output); + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts index b67f63e45..567da12bc 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts @@ -193,7 +193,7 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { * :ref:`channel_credentials `. */ 'target_uri': (string); - 'channel_credentials': (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output); + 'channel_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output); /** * A set of call credentials that can be composed with `channel credentials * `_. @@ -221,7 +221,7 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { * Additional configuration for site-specific customizations of the Google * gRPC library. */ - 'config': (_google_protobuf_Struct__Output); + 'config'?: (_google_protobuf_Struct__Output); } export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { @@ -297,15 +297,15 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Outpu /** * PEM encoded server root certificates. */ - 'root_certs': (_envoy_api_v2_core_DataSource__Output); + 'root_certs'?: (_envoy_api_v2_core_DataSource__Output); /** * PEM encoded client private key. */ - 'private_key': (_envoy_api_v2_core_DataSource__Output); + 'private_key'?: (_envoy_api_v2_core_DataSource__Output); /** * PEM encoded client certificate chain. */ - 'cert_chain': (_envoy_api_v2_core_DataSource__Output); + 'cert_chain'?: (_envoy_api_v2_core_DataSource__Output); } /** @@ -470,7 +470,7 @@ export interface GrpcService__Output { * The timeout for the gRPC request. This is the timeout for a specific * request. */ - 'timeout': (_google_protobuf_Duration__Output); + 'timeout'?: (_google_protobuf_Duration__Output); /** * Additional metadata to include in streams initiated to the GrpcService. * This can be used for scenarios in which additional ad hoc authorization diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts index 96350736b..c66ce9aad 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts @@ -25,10 +25,10 @@ export interface HeaderValueOption__Output { /** * Header name/value pair that this option applies to. */ - 'header': (_envoy_api_v2_core_HeaderValue__Output); + 'header'?: (_envoy_api_v2_core_HeaderValue__Output); /** * Should the value be appended? If true (default), the value is appended to * existing values. */ - 'append': (_google_protobuf_BoolValue__Output); + 'append'?: (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts index 972560cd5..a9a3e3310 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts @@ -186,11 +186,11 @@ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { /** * [#not-implemented-hide:] HTTP specific payload. */ - 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'send'?: (_envoy_api_v2_core_HealthCheck_Payload__Output); /** * [#not-implemented-hide:] HTTP specific response. */ - 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload__Output); /** * An optional service name parameter which is used to validate the identity of * the health checked cluster. See the :ref:`architecture overview @@ -237,7 +237,7 @@ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { * `. See the :ref:`architecture overview * ` for more information. */ - 'service_name_matcher': (_envoy_type_matcher_StringMatcher__Output); + 'service_name_matcher'?: (_envoy_type_matcher_StringMatcher__Output); } /** @@ -307,7 +307,7 @@ export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { /** * Empty payloads imply a connect-only health check. */ - 'send': (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'send'?: (_envoy_api_v2_core_HealthCheck_Payload__Output); /** * When checking the response, “fuzzy†matching is performed such that each * binary block must be found, and in the order specified, but not @@ -485,36 +485,36 @@ export interface HealthCheck__Output { * The time to wait for a health check response. If the timeout is reached the * health check attempt will be considered a failure. */ - 'timeout': (_google_protobuf_Duration__Output); + 'timeout'?: (_google_protobuf_Duration__Output); /** * The interval between health checks. */ - 'interval': (_google_protobuf_Duration__Output); + 'interval'?: (_google_protobuf_Duration__Output); /** * An optional jitter amount in milliseconds. If specified, during every * interval Envoy will add interval_jitter to the wait time. */ - 'interval_jitter': (_google_protobuf_Duration__Output); + 'interval_jitter'?: (_google_protobuf_Duration__Output); /** * The number of unhealthy health checks required before a host is marked * unhealthy. Note that for *http* health checking if a host responds with 503 * this threshold is ignored and the host is considered unhealthy immediately. */ - 'unhealthy_threshold': (_google_protobuf_UInt32Value__Output); + 'unhealthy_threshold'?: (_google_protobuf_UInt32Value__Output); /** * The number of healthy health checks required before a host is marked * healthy. Note that during startup, only a single successful health check is * required to mark a host healthy. */ - 'healthy_threshold': (_google_protobuf_UInt32Value__Output); + 'healthy_threshold'?: (_google_protobuf_UInt32Value__Output); /** * [#not-implemented-hide:] Non-serving port for health checking. */ - 'alt_port': (_google_protobuf_UInt32Value__Output); + 'alt_port'?: (_google_protobuf_UInt32Value__Output); /** * Reuse health check connection between health checks. Default is true. */ - 'reuse_connection': (_google_protobuf_BoolValue__Output); + 'reuse_connection'?: (_google_protobuf_BoolValue__Output); /** * HTTP health check. */ @@ -537,7 +537,7 @@ export interface HealthCheck__Output { * * The default value for "no traffic interval" is 60 seconds. */ - 'no_traffic_interval': (_google_protobuf_Duration__Output); + 'no_traffic_interval'?: (_google_protobuf_Duration__Output); /** * Custom health check. */ @@ -549,7 +549,7 @@ export interface HealthCheck__Output { * * The default value for "unhealthy interval" is the same as "interval". */ - 'unhealthy_interval': (_google_protobuf_Duration__Output); + 'unhealthy_interval'?: (_google_protobuf_Duration__Output); /** * The "unhealthy edge interval" is a special health check interval that is used for the first * health check right after a host is marked as unhealthy. For subsequent health checks @@ -558,7 +558,7 @@ export interface HealthCheck__Output { * * The default value for "unhealthy edge interval" is the same as "unhealthy interval". */ - 'unhealthy_edge_interval': (_google_protobuf_Duration__Output); + 'unhealthy_edge_interval'?: (_google_protobuf_Duration__Output); /** * The "healthy edge interval" is a special health check interval that is used for the first * health check right after a host is marked as healthy. For subsequent health checks @@ -566,7 +566,7 @@ export interface HealthCheck__Output { * * The default value for "healthy edge interval" is the same as the default interval. */ - 'healthy_edge_interval': (_google_protobuf_Duration__Output); + 'healthy_edge_interval'?: (_google_protobuf_Duration__Output); /** * Specifies the path to the :ref:`health check event log `. * If empty, no event log will be written. @@ -592,16 +592,16 @@ export interface HealthCheck__Output { * checking after for a random time in ms between 0 and initial_jitter. This only * applies to the first health check. */ - 'initial_jitter': (_google_protobuf_Duration__Output); + 'initial_jitter'?: (_google_protobuf_Duration__Output); /** * This allows overriding the cluster TLS settings, just for health check connections. */ - 'tls_options': (_envoy_api_v2_core_HealthCheck_TlsOptions__Output); + 'tls_options'?: (_envoy_api_v2_core_HealthCheck_TlsOptions__Output); /** * [#not-implemented-hide:] * The gRPC service for the health check event service. * If empty, health check events won't be sent to a remote endpoint. */ - 'event_service': (_envoy_api_v2_core_EventServiceConfig__Output); + 'event_service'?: (_envoy_api_v2_core_EventServiceConfig__Output); 'health_checker': "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts index 13abc9ec4..7feca246a 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts @@ -85,7 +85,7 @@ export interface Http1ProtocolOptions__Output { * envoy as their HTTP proxy. In Unix, for example, this is typically done by setting the * *http_proxy* environment variable. */ - 'allow_absolute_url': (_google_protobuf_BoolValue__Output); + 'allow_absolute_url'?: (_google_protobuf_BoolValue__Output); /** * Handle incoming HTTP/1.0 and HTTP 0.9 requests. * This is off by default, and not fully standards compliant. There is support for pre-HTTP/1.1 @@ -103,7 +103,7 @@ export interface Http1ProtocolOptions__Output { * Describes how the keys for response headers should be formatted. By default, all header keys * are lower cased. */ - 'header_key_format': (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output); + 'header_key_format'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output); /** * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. * diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts index 97208657d..d24c38a55 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts @@ -25,11 +25,11 @@ export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Outp /** * The 16 bit parameter identifier. */ - 'identifier': (_google_protobuf_UInt32Value__Output); + 'identifier'?: (_google_protobuf_UInt32Value__Output); /** * The 32 bit parameter value. */ - 'value': (_google_protobuf_UInt32Value__Output); + 'value'?: (_google_protobuf_UInt32Value__Output); } /** @@ -188,7 +188,7 @@ export interface Http2ProtocolOptions__Output { * range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header * compression. */ - 'hpack_table_size': (_google_protobuf_UInt32Value__Output); + 'hpack_table_size'?: (_google_protobuf_UInt32Value__Output); /** * `Maximum concurrent streams `_ * allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) @@ -198,7 +198,7 @@ export interface Http2ProtocolOptions__Output { * on a single connection. If the limit is reached, Envoy may queue requests or establish * additional connections (as allowed per circuit breaker limits). */ - 'max_concurrent_streams': (_google_protobuf_UInt32Value__Output); + 'max_concurrent_streams'?: (_google_protobuf_UInt32Value__Output); /** * `Initial stream-level flow-control window * `_ size. Valid values range from 65535 @@ -212,12 +212,12 @@ export interface Http2ProtocolOptions__Output { * HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to * stop the flow of data to the codec buffers. */ - 'initial_stream_window_size': (_google_protobuf_UInt32Value__Output); + 'initial_stream_window_size'?: (_google_protobuf_UInt32Value__Output); /** * Similar to *initial_stream_window_size*, but for connection-level flow-control * window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. */ - 'initial_connection_window_size': (_google_protobuf_UInt32Value__Output); + 'initial_connection_window_size'?: (_google_protobuf_UInt32Value__Output); /** * Allows proxying Websocket and other upgrades over H2 connect. */ @@ -238,7 +238,7 @@ export interface Http2ProtocolOptions__Output { * to flood mitigation. The default limit is 10000. * [#comment:TODO: implement same limits for upstream outbound frames as well.] */ - 'max_outbound_frames': (_google_protobuf_UInt32Value__Output); + 'max_outbound_frames'?: (_google_protobuf_UInt32Value__Output); /** * Limit the number of pending outbound downstream frames of types PING, SETTINGS and RST_STREAM, * preventing high memory utilization when receiving continuous stream of these frames. Exceeding @@ -247,7 +247,7 @@ export interface Http2ProtocolOptions__Output { * mitigation. The default limit is 1000. * [#comment:TODO: implement same limits for upstream outbound frames as well.] */ - 'max_outbound_control_frames': (_google_protobuf_UInt32Value__Output); + 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value__Output); /** * Limit the number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA with an * empty payload and no end stream flag. Those frames have no legitimate use and are abusive, but @@ -257,7 +257,7 @@ export interface Http2ProtocolOptions__Output { * and no end stream flag. The default limit is 1. * [#comment:TODO: implement same limits for upstream inbound frames as well.] */ - 'max_consecutive_inbound_frames_with_empty_payload': (_google_protobuf_UInt32Value__Output); + 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value__Output); /** * Limit the number of inbound PRIORITY frames allowed per each opened stream. If the number * of PRIORITY frames received over the lifetime of connection exceeds the value calculated @@ -269,7 +269,7 @@ export interface Http2ProtocolOptions__Output { * the number of connections terminated due to flood mitigation. The default limit is 100. * [#comment:TODO: implement same limits for upstream inbound frames as well.] */ - 'max_inbound_priority_frames_per_stream': (_google_protobuf_UInt32Value__Output); + 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value__Output); /** * Limit the number of inbound WINDOW_UPDATE frames allowed per DATA frame sent. If the number * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated @@ -284,7 +284,7 @@ export interface Http2ProtocolOptions__Output { * but more complex implementations that try to estimate available bandwidth require at least 2. * [#comment:TODO: implement same limits for upstream inbound frames as well.] */ - 'max_inbound_window_update_frames_per_data_frame_sent': (_google_protobuf_UInt32Value__Output); + 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value__Output); /** * Allows invalid HTTP messaging and headers. When this option is disabled (default), then * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts index 026e236e7..964645696 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts @@ -96,13 +96,13 @@ export interface HttpProtocolOptions__Output { * Disabling this timeout has a highly likelihood of yielding connection leaks due to lost TCP * FIN packets, etc. */ - 'idle_timeout': (_google_protobuf_Duration__Output); + 'idle_timeout'?: (_google_protobuf_Duration__Output); /** * The maximum number of headers. If unconfigured, the default * maximum number of request headers allowed is 100. Requests that exceed this limit will receive * a 431 response for HTTP/1.x and cause a stream reset for HTTP/2. */ - 'max_headers_count': (_google_protobuf_UInt32Value__Output); + 'max_headers_count'?: (_google_protobuf_UInt32Value__Output); /** * The maximum duration of a connection. The duration is defined as a period since a connection * was established. If not set, there is no max duration. When max_connection_duration is reached @@ -111,12 +111,12 @@ export interface HttpProtocolOptions__Output { * `. * Note: not implemented for upstream connections. */ - 'max_connection_duration': (_google_protobuf_Duration__Output); + 'max_connection_duration'?: (_google_protobuf_Duration__Output); /** * Total duration to keep alive an HTTP request/response stream. If the time limit is reached the stream will be * reset independent of any other timeouts. If not specified, this value is not set. */ - 'max_stream_duration': (_google_protobuf_Duration__Output); + 'max_stream_duration'?: (_google_protobuf_Duration__Output); /** * Action to take when a client request with a header name containing underscore characters is received. * If this setting is not specified, the value defaults to ALLOW. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts index 998f8816c..b01489a64 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts @@ -68,7 +68,7 @@ export interface HttpUri__Output { /** * Sets the maximum duration in milliseconds that a response can take to arrive upon request. */ - 'timeout': (_google_protobuf_Duration__Output); + 'timeout'?: (_google_protobuf_Duration__Output); /** * Specify how `uri` is to be fetched. Today, this requires an explicit * cluster, but in the future we may support dynamic cluster creation or diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts index 1774252e5..2a3c8f996 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts @@ -31,7 +31,7 @@ export interface Metadata { * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* * namespace is reserved for Envoy's built-in filters. */ - 'filter_metadata'?: (_google_protobuf_Struct); + 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct}); } /** @@ -63,5 +63,5 @@ export interface Metadata__Output { * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* * namespace is reserved for Envoy's built-in filters. */ - 'filter_metadata': (_google_protobuf_Struct__Output); + 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct__Output}); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts index 27a156c66..5a8842482 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts @@ -124,11 +124,11 @@ export interface Node__Output { * Opaque metadata extending the node identifier. Envoy will pass this * directly to the management server. */ - 'metadata': (_google_protobuf_Struct__Output); + 'metadata'?: (_google_protobuf_Struct__Output); /** * Locality specifying where the Envoy instance is running. */ - 'locality': (_envoy_api_v2_core_Locality__Output); + 'locality'?: (_envoy_api_v2_core_Locality__Output); /** * This is motivated by informing a management server during canary which * version of Envoy is being tested in a heterogeneous fleet. This will be set diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts index bf52aaaf3..05cb819c9 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts @@ -27,10 +27,10 @@ export interface RateLimitSettings__Output { * Maximum number of tokens to be used for rate limiting discovery request calls. If not set, a * default value of 100 will be used. */ - 'max_tokens': (_google_protobuf_UInt32Value__Output); + 'max_tokens'?: (_google_protobuf_UInt32Value__Output); /** * Rate at which tokens will be filled per second. If not set, a default fill rate of 10 tokens * per second will be used. */ - 'fill_rate': (_google_protobuf_DoubleValue__Output); + 'fill_rate'?: (_google_protobuf_DoubleValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts index c0ec51d75..603cc258c 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts @@ -28,7 +28,7 @@ export interface RemoteDataSource__Output { /** * The HTTP URI to fetch the remote data. */ - 'http_uri': (_envoy_api_v2_core_HttpUri__Output); + 'http_uri'?: (_envoy_api_v2_core_HttpUri__Output); /** * SHA256 string for verifying data. */ @@ -36,5 +36,5 @@ export interface RemoteDataSource__Output { /** * Retry policy for fetching remote data. */ - 'retry_policy': (_envoy_api_v2_core_RetryPolicy__Output); + 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts index f3dc4bac1..4df63c53e 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts @@ -29,10 +29,10 @@ export interface RetryPolicy__Output { * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ - 'retry_back_off': (_envoy_api_v2_core_BackoffStrategy__Output); + 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy__Output); /** * Specifies the allowed number of retries. This parameter is optional and * defaults to 1. */ - 'num_retries': (_google_protobuf_UInt32Value__Output); + 'num_retries'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts index fd88cf9df..6994218d1 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts @@ -25,7 +25,7 @@ export interface RuntimeFeatureFlag__Output { /** * Default value if runtime value is not available. */ - 'default_value': (_google_protobuf_BoolValue__Output); + 'default_value'?: (_google_protobuf_BoolValue__Output); /** * Runtime key to get value for comparison. This value is used if defined. The boolean value must * be represented via its diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts index 222c1b9d7..78eeb3257 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts @@ -41,7 +41,7 @@ export interface RuntimeFractionalPercent__Output { /** * Default value if the runtime value's for the numerator/denominator keys are not available. */ - 'default_value': (_envoy_type_FractionalPercent__Output); + 'default_value'?: (_envoy_type_FractionalPercent__Output); /** * Runtime key for a YAML representation of a FractionalPercent. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts index 9318af4e5..e6c85ba44 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts @@ -28,16 +28,16 @@ export interface TcpKeepalive__Output { * the connection is dead. Default is to use the OS level configuration (unless * overridden, Linux defaults to 9.) */ - 'keepalive_probes': (_google_protobuf_UInt32Value__Output); + 'keepalive_probes'?: (_google_protobuf_UInt32Value__Output); /** * The number of seconds a connection needs to be idle before keep-alive probes * start being sent. Default is to use the OS level configuration (unless * overridden, Linux defaults to 7200s (i.e., 2 hours.) */ - 'keepalive_time': (_google_protobuf_UInt32Value__Output); + 'keepalive_time'?: (_google_protobuf_UInt32Value__Output); /** * The number of seconds between keep-alive probes. Default is to use the OS * level configuration (unless overridden, Linux defaults to 75s.) */ - 'keepalive_interval': (_google_protobuf_UInt32Value__Output); + 'keepalive_interval'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts index e66fb182b..f9a69142a 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts @@ -98,7 +98,7 @@ export interface Endpoint__Output { * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ - 'address': (_envoy_api_v2_core_Address__Output); + 'address'?: (_envoy_api_v2_core_Address__Output); /** * The optional health check configuration is used as configuration for the * health checker to contact the health checked host. @@ -108,7 +108,7 @@ export interface Endpoint__Output { * This takes into effect only for upstream clusters with * :ref:`active health checking ` enabled. */ - 'health_check_config': (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output); + 'health_check_config'?: (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output); /** * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts index 84883c8a2..fa8e64999 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts @@ -66,7 +66,7 @@ export interface LbEndpoint__Output { * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ - 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_api_v2_core_Metadata__Output); /** * The optional load balancing weight of the upstream host; at least 1. * Envoy uses the load balancing weight in some of the built in load @@ -78,7 +78,7 @@ export interface LbEndpoint__Output { * weight in a locality. The sum of the weights of all endpoints in the * endpoint's locality must not exceed uint32_t maximal value (4294967295). */ - 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + 'load_balancing_weight'?: (_google_protobuf_UInt32Value__Output); /** * [#not-implemented-hide:] */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts index 6565a34f1..401ea7313 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts @@ -68,7 +68,7 @@ export interface LocalityLbEndpoints__Output { /** * Identifies location of where the upstream hosts run. */ - 'locality': (_envoy_api_v2_core_Locality__Output); + 'locality'?: (_envoy_api_v2_core_Locality__Output); /** * The group of endpoints belonging to the locality specified. */ @@ -86,7 +86,7 @@ export interface LocalityLbEndpoints__Output { * specified when locality weighted load balancing is enabled, the locality is * assigned no load. */ - 'load_balancing_weight': (_google_protobuf_UInt32Value__Output); + 'load_balancing_weight'?: (_google_protobuf_UInt32Value__Output); /** * Optional: the priority for this LocalityLbEndpoints. If unspecified this will * default to the highest priority (0). @@ -107,5 +107,5 @@ export interface LocalityLbEndpoints__Output { * to determine where to route the requests. * [#not-implemented-hide:] */ - 'proximity': (_google_protobuf_UInt32Value__Output); + 'proximity'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts index 585836f15..fa2c8ddbe 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts @@ -71,7 +71,7 @@ export interface FilterChain__Output { /** * The criteria to use when matching a connection to this filter chain. */ - 'filter_chain_match': (_envoy_api_v2_listener_FilterChainMatch__Output); + 'filter_chain_match'?: (_envoy_api_v2_listener_FilterChainMatch__Output); /** * The TLS context for this filter chain. * @@ -80,7 +80,7 @@ export interface FilterChain__Output { * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are * set, `transport_socket` takes priority. */ - 'tls_context': (_envoy_api_v2_auth_DownstreamTlsContext__Output); + 'tls_context'?: (_envoy_api_v2_auth_DownstreamTlsContext__Output); /** * A list of individual network filters that make up the filter chain for * connections established with the listener. Order matters as the filters are @@ -96,11 +96,11 @@ export interface FilterChain__Output { * absent or set to false, Envoy will use the physical peer address of the * connection as the remote address. */ - 'use_proxy_proto': (_google_protobuf_BoolValue__Output); + 'use_proxy_proto'?: (_google_protobuf_BoolValue__Output); /** * [#not-implemented-hide:] filter chain metadata. */ - 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_api_v2_core_Metadata__Output); /** * Optional custom transport socket implementation to use for downstream connections. * To setup TLS, set a transport socket with name `tls` and @@ -108,7 +108,7 @@ export interface FilterChain__Output { * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket': (_envoy_api_v2_core_TransportSocket__Output); + 'transport_socket'?: (_envoy_api_v2_core_TransportSocket__Output); /** * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts index 67f03a928..cdf49bf0a 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts @@ -187,7 +187,7 @@ export interface FilterChainMatch__Output { /** * [#not-implemented-hide:] */ - 'suffix_len': (_google_protobuf_UInt32Value__Output); + 'suffix_len'?: (_google_protobuf_UInt32Value__Output); /** * The criteria is satisfied if the source IP address of the downstream * connection is contained in at least one of the specified subnets. If the @@ -205,7 +205,7 @@ export interface FilterChainMatch__Output { * Optional destination port to consider when use_original_dst is set on the * listener in determining a filter chain match. */ - 'destination_port': (_google_protobuf_UInt32Value__Output); + 'destination_port'?: (_google_protobuf_UInt32Value__Output); /** * If non-empty, a transport protocol to consider when determining a filter chain match. * This value will be compared against the transport protocol of a new connection, when diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts index 5949135da..75fc917e5 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts @@ -38,7 +38,7 @@ export interface ListenerFilter__Output { * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ - 'filter_disabled': (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + 'filter_disabled'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); /** * Filter specific configuration which depends on the filter being instantiated. * See the supported filters for further documentation. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts index cb48b5eec..b2429e5e2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts @@ -118,7 +118,7 @@ export interface CorsPolicy__Output { /** * Specifies whether the resource allows credentials. */ - 'allow_credentials': (_google_protobuf_BoolValue__Output); + 'allow_credentials'?: (_google_protobuf_BoolValue__Output); /** * Specifies if the CORS filter is enabled. Defaults to true. Only effective on route. * @@ -159,7 +159,7 @@ export interface CorsPolicy__Output { * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ - 'shadow_enabled': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'shadow_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); /** * Specifies string patterns that match allowed origins. An origin is allowed if any of the * string matchers match. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts index 43bc7408c..d1a2fa25f 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts @@ -35,5 +35,5 @@ export interface Decorator__Output { /** * Whether the decorated details should be propagated to the other party. The default is true. */ - 'propagate': (_google_protobuf_BoolValue__Output); + 'propagate'?: (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts index 7585f376c..6e9ed7cae 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts @@ -35,5 +35,5 @@ export interface DirectResponseAction__Output { * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or * :ref:`envoy_api_msg_route.VirtualHost`. */ - 'body': (_envoy_api_v2_core_DataSource__Output); + 'body'?: (_envoy_api_v2_core_DataSource__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts index 8e0985e12..ca626cfaf 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts @@ -13,5 +13,5 @@ export interface FilterAction { * A filter-defined action type. */ export interface FilterAction__Output { - 'action': (_google_protobuf_Any__Output); + 'action'?: (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts index a1c641711..c362bdc52 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts @@ -44,14 +44,14 @@ export interface HedgePolicy__Output { * Defaults to 1. * [#not-implemented-hide:] */ - 'initial_requests': (_google_protobuf_UInt32Value__Output); + 'initial_requests'?: (_google_protobuf_UInt32Value__Output); /** * Specifies a probability that an additional upstream request should be sent * on top of what is specified by initial_requests. * Defaults to 0. * [#not-implemented-hide:] */ - 'additional_request_chance': (_envoy_type_FractionalPercent__Output); + 'additional_request_chance'?: (_envoy_type_FractionalPercent__Output); /** * Indicates that a hedged request should be sent when the per-try timeout * is hit. This will only occur if the retry policy also indicates that a diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts index 8f0041ce6..eeed23abe 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts @@ -73,7 +73,7 @@ export interface QueryParameterMatcher__Output { * ..attention:: * This field is deprecated. Use a `safe_regex` match inside the `string_match` field. */ - 'regex': (_google_protobuf_BoolValue__Output); + 'regex'?: (_google_protobuf_BoolValue__Output); /** * Specifies whether a query parameter value should match against a string. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts index 6361f5032..385dad6f6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts @@ -183,7 +183,7 @@ export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output { * descriptor entry when the request does not match the headers. The * default value is true. */ - 'expect_match': (_google_protobuf_BoolValue__Output); + 'expect_match'?: (_google_protobuf_BoolValue__Output); /** * Specifies a set of headers that the rate limit action should match * on. The action will check the request’s headers against all the @@ -324,7 +324,7 @@ export interface RateLimit__Output { * * The filter supports a range of 0 - 10 inclusively for stage numbers. */ - 'stage': (_google_protobuf_UInt32Value__Output); + 'stage'?: (_google_protobuf_UInt32Value__Output); /** * The key to be set in runtime to disable this rate limit configuration. */ diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts index 48df89fdb..24bdd2814 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts @@ -31,14 +31,14 @@ export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff__Output { * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's * back-off algorithm. */ - 'base_interval': (_google_protobuf_Duration__Output); + 'base_interval'?: (_google_protobuf_Duration__Output); /** * Specifies the maximum interval between retries. This parameter is optional, but must be * greater than or equal to the `base_interval` if set. The default is 10 times the * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion * of Envoy's back-off algorithm. */ - 'max_interval': (_google_protobuf_Duration__Output); + 'max_interval'?: (_google_protobuf_Duration__Output); } export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate { @@ -159,7 +159,7 @@ export interface RetryPolicy__Output { * defaults to 1. These are the same conditions documented for * :ref:`config_http_filters_router_x-envoy-max-retries`. */ - 'num_retries': (_google_protobuf_UInt32Value__Output); + 'num_retries'?: (_google_protobuf_UInt32Value__Output); /** * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The * same conditions documented for @@ -173,13 +173,13 @@ export interface RetryPolicy__Output { * retry policy, a request that times out will not be retried as the total timeout budget * would have been exhausted. */ - 'per_try_timeout': (_google_protobuf_Duration__Output); + 'per_try_timeout'?: (_google_protobuf_Duration__Output); /** * Specifies an implementation of a RetryPriority which is used to determine the * distribution of load across priorities used for retries. Refer to * :ref:`retry plugin configuration ` for more details. */ - 'retry_priority': (_envoy_api_v2_route_RetryPolicy_RetryPriority__Output); + 'retry_priority'?: (_envoy_api_v2_route_RetryPolicy_RetryPriority__Output); /** * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host * for retries. If any of the predicates reject the host, host selection will be reattempted. @@ -204,7 +204,7 @@ export interface RetryPolicy__Output { * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` * describes Envoy's back-off algorithm. */ - 'retry_back_off': (_envoy_api_v2_route_RetryPolicy_RetryBackOff__Output); + 'retry_back_off'?: (_envoy_api_v2_route_RetryPolicy_RetryBackOff__Output); /** * HTTP response headers that trigger a retry if present in the response. A retry will be * triggered if any of the header matches match the upstream response headers. diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts index 32c4786e0..7d0ff8bd8 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts @@ -59,7 +59,7 @@ export interface Route { * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. */ - 'per_filter_config'?: (_google_protobuf_Struct); + 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct}); /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the @@ -95,7 +95,7 @@ export interface Route { * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. */ - 'typed_per_filter_config'?: (_google_protobuf_Any); + 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); /** * Name for the route. */ @@ -134,7 +134,7 @@ export interface Route__Output { /** * Route matching parameters. */ - 'match': (_envoy_api_v2_route_RouteMatch__Output); + 'match'?: (_envoy_api_v2_route_RouteMatch__Output); /** * Route request to some upstream cluster. */ @@ -150,11 +150,11 @@ export interface Route__Output { * For instance, if the metadata is intended for the Router filter, * the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata': (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_api_v2_core_Metadata__Output); /** * Decorator for the matched route. */ - 'decorator': (_envoy_api_v2_route_Decorator__Output); + 'decorator'?: (_envoy_api_v2_route_Decorator__Output); /** * Return an arbitrary HTTP response directly, without proxying. */ @@ -166,7 +166,7 @@ export interface Route__Output { * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. */ - 'per_filter_config': (_google_protobuf_Struct__Output); + 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct__Output}); /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the @@ -202,7 +202,7 @@ export interface Route__Output { * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. */ - 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); /** * Name for the route. */ @@ -211,13 +211,13 @@ export interface Route__Output { * Presence of the object defines whether the connection manager's tracing configuration * is overridden by this route specific instance. */ - 'tracing': (_envoy_api_v2_route_Tracing__Output); + 'tracing'?: (_envoy_api_v2_route_Tracing__Output); /** * The maximum bytes which will be buffered for retries and shadowing. * If set, the bytes actually buffered will be the minimum value of this and the * listener per_connection_buffer_limit_bytes. */ - 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); /** * [#not-implemented-hide:] * If true, a filter will define the action (e.g., it could dynamically generate the diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts index 490718e80..94e769deb 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts @@ -105,7 +105,7 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output { * not present. If the TTL is present and zero, the generated cookie will * be a session cookie. */ - 'ttl': (_google_protobuf_Duration__Output); + 'ttl'?: (_google_protobuf_Duration__Output); /** * The name of the path for the cookie. If no path is specified here, no path * will be set for the cookie. @@ -378,11 +378,11 @@ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { * number is <= the value of the numerator N, or if the key is not present, the default * value, the request will be mirrored. */ - 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); /** * Determines if the trace span should be sampled. Defaults to true. */ - 'trace_sampled': (_google_protobuf_BoolValue__Output); + 'trace_sampled'?: (_google_protobuf_BoolValue__Output); } /** @@ -424,7 +424,7 @@ export interface _envoy_api_v2_route_RouteAction_UpgradeConfig__Output { /** * Determines if upgrades are available on this route. Defaults to true. */ - 'enabled': (_google_protobuf_BoolValue__Output); + 'enabled'?: (_google_protobuf_BoolValue__Output); } /** @@ -751,7 +751,7 @@ export interface RouteAction__Output { * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match': (_envoy_api_v2_core_Metadata__Output); + 'metadata_match'?: (_envoy_api_v2_core_Metadata__Output); /** * Indicates that during forwarding, the matched prefix (or path) should be * swapped with this value. This option allows application URLs to be rooted @@ -812,13 +812,13 @@ export interface RouteAction__Output { * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the * :ref:`retry overview `. */ - 'timeout': (_google_protobuf_Duration__Output); + 'timeout'?: (_google_protobuf_Duration__Output); /** * Indicates that the route has a retry policy. Note that if this is set, * it'll take precedence over the virtual host level retry policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); + 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy__Output); /** * Indicates that the route has a request mirroring policy. * @@ -826,7 +826,7 @@ export interface RouteAction__Output { * This field has been deprecated in favor of `request_mirror_policies` which supports one or * more mirroring policies. */ - 'request_mirror_policy': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output); + 'request_mirror_policy'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output); /** * Optionally specifies the :ref:`routing priority `. */ @@ -842,7 +842,7 @@ export interface RouteAction__Output { * :ref:`rate_limits ` are not applied to the * request. */ - 'include_vh_rate_limits': (_google_protobuf_BoolValue__Output); + 'include_vh_rate_limits'?: (_google_protobuf_BoolValue__Output); /** * Specifies a list of hash policies to use for ring hash load balancing. Each * hash policy is evaluated individually and the combined result is used to @@ -861,7 +861,7 @@ export interface RouteAction__Output { /** * Indicates that the route has a CORS policy. */ - 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + 'cors'?: (_envoy_api_v2_route_CorsPolicy__Output); /** * The HTTP status code to use when configured cluster is not found. * The default response code is 503 Service Unavailable. @@ -888,7 +888,7 @@ export interface RouteAction__Output { * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the * :ref:`retry overview `. */ - 'max_grpc_timeout': (_google_protobuf_Duration__Output); + 'max_grpc_timeout'?: (_google_protobuf_Duration__Output); /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout @@ -909,7 +909,7 @@ export interface RouteAction__Output { * upstream response header has been received, otherwise a stream reset * occurs. */ - 'idle_timeout': (_google_protobuf_Duration__Output); + 'idle_timeout'?: (_google_protobuf_Duration__Output); 'upgrade_configs': (_envoy_api_v2_route_RouteAction_UpgradeConfig__Output)[]; 'internal_redirect_action': (keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); /** @@ -917,7 +917,7 @@ export interface RouteAction__Output { * it'll take precedence over the virtual host level hedge policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy__Output); /** * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting * the provided duration from the header. This is useful in allowing Envoy to set its global @@ -927,7 +927,7 @@ export interface RouteAction__Output { * ensures that the offset will only ever decrease the timeout and never set it to 0 (meaning * infinity). */ - 'grpc_timeout_offset': (_google_protobuf_Duration__Output); + 'grpc_timeout_offset'?: (_google_protobuf_Duration__Output); /** * Indicates that during forwarding, the host header will be swapped with the content of given * downstream or :ref:`custom ` header. @@ -959,7 +959,7 @@ export interface RouteAction__Output { * * If not specified, at most one redirect will be followed. */ - 'max_internal_redirects': (_google_protobuf_UInt32Value__Output); + 'max_internal_redirects'?: (_google_protobuf_UInt32Value__Output); /** * Indicates that during forwarding, portions of the path that match the * pattern should be rewritten, even allowing the substitution of capture @@ -990,7 +990,7 @@ export interface RouteAction__Output { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite': (_envoy_type_matcher_RegexMatchAndSubstitute__Output); + 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute__Output); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take @@ -998,7 +998,7 @@ export interface RouteAction__Output { * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ - 'retry_policy_typed_config': (_google_protobuf_Any__Output); + 'retry_policy_typed_config'?: (_google_protobuf_Any__Output); 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier': "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts index c60c956fe..b4af4adf2 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts @@ -30,12 +30,12 @@ export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output { * If specified, the route will match against whether or not a certificate is presented. * If not specified, certificate presentation status (true or false) will not be considered when route matching. */ - 'presented': (_google_protobuf_BoolValue__Output); + 'presented'?: (_google_protobuf_BoolValue__Output); /** * If specified, the route will match against whether or not a certificate is validated. * If not specified, certificate validation status (true or false) will not be considered when route matching. */ - 'validated': (_google_protobuf_BoolValue__Output); + 'validated'?: (_google_protobuf_BoolValue__Output); } /** @@ -179,7 +179,7 @@ export interface RouteMatch__Output { * Indicates that prefix/path matching should be case insensitive. The default * is true. */ - 'case_sensitive': (_google_protobuf_BoolValue__Output); + 'case_sensitive'?: (_google_protobuf_BoolValue__Output); /** * Specifies a set of headers that the route should match on. The router will * check the request’s headers against all the specified headers in the route @@ -201,7 +201,7 @@ export interface RouteMatch__Output { * that the content-type header has a application/grpc or one of the various * application/grpc+ values. */ - 'grpc': (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output); + 'grpc'?: (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output); /** * Indicates that the route should additionally match on a runtime key. Every time the route * is considered for a match, it must also fall under the percentage of matches indicated by @@ -220,7 +220,7 @@ export interface RouteMatch__Output { * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. */ - 'runtime_fraction': (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); /** * If specified, the route is a regular expression rule meaning that the * regex must match the *:path* header once the query string is removed. The entire path @@ -242,6 +242,6 @@ export interface RouteMatch__Output { * * [#next-major-version: unify with RBAC] */ - 'tls_context': (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output); + 'tls_context'?: (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output); 'path_specifier': "prefix"|"path"|"regex"|"safe_regex"; } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts index f69211c43..d60486314 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts @@ -52,7 +52,7 @@ export interface Tracing__Output { * `. * Default: 100% */ - 'client_sampling': (_envoy_type_FractionalPercent__Output); + 'client_sampling'?: (_envoy_type_FractionalPercent__Output); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -60,7 +60,7 @@ export interface Tracing__Output { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling': (_envoy_type_FractionalPercent__Output); + 'random_sampling'?: (_envoy_type_FractionalPercent__Output); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -71,7 +71,7 @@ export interface Tracing__Output { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling': (_envoy_type_FractionalPercent__Output); + 'overall_sampling'?: (_envoy_type_FractionalPercent__Output); /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts index ebb926f16..5c8c6cfa6 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts @@ -119,7 +119,7 @@ export interface VirtualHost { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'per_filter_config'?: (_google_protobuf_Struct); + 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct}); /** * Specifies a list of HTTP headers that should be removed from each request * handled by this virtual host. @@ -145,7 +145,7 @@ export interface VirtualHost { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'typed_per_filter_config'?: (_google_protobuf_Any); + 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); /** * Indicates the retry policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated @@ -252,7 +252,7 @@ export interface VirtualHost__Output { /** * Indicates that the virtual host has a CORS policy. */ - 'cors': (_envoy_api_v2_route_CorsPolicy__Output); + 'cors'?: (_envoy_api_v2_route_CorsPolicy__Output); /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied @@ -274,7 +274,7 @@ export interface VirtualHost__Output { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'per_filter_config': (_google_protobuf_Struct__Output); + 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct__Output}); /** * Specifies a list of HTTP headers that should be removed from each request * handled by this virtual host. @@ -300,25 +300,25 @@ export interface VirtualHost__Output { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); /** * Indicates the retry policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'retry_policy': (_envoy_api_v2_route_RetryPolicy__Output); + 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy__Output); /** * Indicates the hedge policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'hedge_policy': (_envoy_api_v2_route_HedgePolicy__Output); + 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy__Output); /** * The maximum bytes which will be buffered for retries and shadowing. * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum * value of this and the listener per_connection_buffer_limit_bytes. */ - 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output); + 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); /** * Decides whether the :ref:`x-envoy-attempt-count * ` header should be included @@ -337,5 +337,5 @@ export interface VirtualHost__Output { * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ - 'retry_policy_typed_config': (_google_protobuf_Any__Output); + 'retry_policy_typed_config'?: (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts index fb0c260b3..512c06b4d 100644 --- a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts +++ b/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts @@ -67,7 +67,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'per_filter_config'?: (_google_protobuf_Struct); + 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct}); /** * The per_filter_config field can be used to provide weighted cluster-specific * configurations for filters. The key should match the filter name, such as @@ -75,7 +75,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'typed_per_filter_config'?: (_google_protobuf_Any); + 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); } /** @@ -93,7 +93,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ - 'weight': (_google_protobuf_UInt32Value__Output); + 'weight'?: (_google_protobuf_UInt32Value__Output); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for @@ -101,7 +101,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match': (_envoy_api_v2_core_Metadata__Output); + 'metadata_match'?: (_envoy_api_v2_core_Metadata__Output); /** * Specifies a list of headers to be added to requests when this cluster is selected * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. @@ -139,7 +139,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'per_filter_config': (_google_protobuf_Struct__Output); + 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct__Output}); /** * The per_filter_config field can be used to provide weighted cluster-specific * configurations for filters. The key should match the filter name, such as @@ -147,7 +147,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. */ - 'typed_per_filter_config': (_google_protobuf_Any__Output); + 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); } /** @@ -209,5 +209,5 @@ export interface WeightedCluster__Output { * Specifies the total weight across all clusters. The sum of all cluster weights must equal this * value, which must be greater than 0. Defaults to 100. */ - 'total_weight': (_google_protobuf_UInt32Value__Output); + 'total_weight'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts index 7a1b23f0d..7ff4a751c 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts @@ -47,7 +47,7 @@ export interface AccessLog__Output { /** * Filter which is used to determine if the access log needs to be written. */ - 'filter': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output); + 'filter'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output); 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts index dc4e88872..9e264d7a4 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts @@ -44,5 +44,5 @@ export interface ComparisonFilter__Output { /** * Value to compare against. */ - 'value': (_envoy_api_v2_core_RuntimeUInt32__Output); + 'value'?: (_envoy_api_v2_core_RuntimeUInt32__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts index 9a2162efb..e8756385a 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts @@ -19,5 +19,5 @@ export interface DurationFilter__Output { /** * Comparison. */ - 'comparison': (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); + 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts index 56c4df1ea..2b4e6275d 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts @@ -21,5 +21,5 @@ export interface HeaderFilter__Output { * Only requests with a header which matches the specified HeaderMatcher will pass the filter * check. */ - 'header': (_envoy_api_v2_route_HeaderMatcher__Output); + 'header'?: (_envoy_api_v2_route_HeaderMatcher__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts index f11e4bc2b..9548b5a16 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts @@ -44,7 +44,7 @@ export interface RuntimeFilter__Output { /** * The default sampling percentage. If not specified, defaults to 0% with denominator of 100. */ - 'percent_sampled': (_envoy_type_FractionalPercent__Output); + 'percent_sampled'?: (_envoy_type_FractionalPercent__Output); /** * By default, sampling pivots on the header * :ref:`x-request-id` being present. If diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts index 950bd696a..d51d42b49 100644 --- a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts +++ b/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts @@ -19,5 +19,5 @@ export interface StatusCodeFilter__Output { /** * Comparison. */ - 'comparison': (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); + 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); } diff --git a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts index 095bc2c53..be4d2415e 100644 --- a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts +++ b/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts @@ -35,5 +35,5 @@ export interface ApiListener__Output { * and http_connection_manager.proto depends on rds.proto, which is in the same directory as * lds.proto, so lds.proto cannot depend on this file.] */ - 'api_listener': (_google_protobuf_Any__Output); + 'api_listener'?: (_google_protobuf_Any__Output); } diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts index 55c8c8644..390bae053 100644 --- a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts +++ b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts @@ -49,7 +49,7 @@ export interface RegexMatchAndSubstitute__Output { * used in the pattern to extract portions of the subject string, and then * referenced in the substitution string. */ - 'pattern': (_envoy_type_matcher_RegexMatcher__Output); + 'pattern'?: (_envoy_type_matcher_RegexMatcher__Output); /** * The string that should be substituted into matching portions of the * subject string during a substitution operation to produce a new string. diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts index 674fef3f5..697b9d6a9 100644 --- a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts +++ b/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts @@ -35,7 +35,7 @@ export interface _envoy_type_matcher_RegexMatcher_GoogleRE2__Output { * This field is deprecated; regexp validation should be performed on the management server * instead of being done by each individual client. */ - 'max_program_size': (_google_protobuf_UInt32Value__Output); + 'max_program_size'?: (_google_protobuf_UInt32Value__Output); } /** diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts index 0b5874d97..75d33cf4a 100644 --- a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts +++ b/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts @@ -122,11 +122,11 @@ export interface _envoy_type_tracing_v2_CustomTag_Metadata__Output { /** * Specify what kind of metadata to obtain tag value from. */ - 'kind': (_envoy_type_metadata_v2_MetadataKind__Output); + 'kind'?: (_envoy_type_metadata_v2_MetadataKind__Output); /** * Metadata key to define the path to retrieve the tag value. */ - 'metadata_key': (_envoy_type_metadata_v2_MetadataKey__Output); + 'metadata_key'?: (_envoy_type_metadata_v2_MetadataKey__Output); /** * When no valid metadata is found, * the tag value would be populated with this default value if specified, diff --git a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts index 423ec0f03..8ab286897 100644 --- a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts @@ -46,7 +46,7 @@ export interface DescriptorProto__Output { 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'extensionRange': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options': (_google_protobuf_MessageOptions__Output); + 'options'?: (_google_protobuf_MessageOptions__Output); 'oneofDecl': (_google_protobuf_OneofDescriptorProto__Output)[]; 'reservedRange': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; 'reservedName': (string)[]; diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts index 5c5f2b7bb..1971fccb0 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts @@ -12,5 +12,5 @@ export interface EnumDescriptorProto { export interface EnumDescriptorProto__Output { 'name': (string); 'value': (_google_protobuf_EnumValueDescriptorProto__Output)[]; - 'options': (_google_protobuf_EnumOptions__Output); + 'options'?: (_google_protobuf_EnumOptions__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts index 9671ecc31..a4f3b7a45 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts @@ -14,5 +14,5 @@ export interface EnumOptions__Output { 'allowAlias': (boolean); 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.enum_migrate': (_udpa_annotations_MigrateAnnotation__Output); + '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts index 042c82ff9..919b7aa38 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts @@ -11,5 +11,5 @@ export interface EnumValueDescriptorProto { export interface EnumValueDescriptorProto__Output { 'name': (string); 'number': (number); - 'options': (_google_protobuf_EnumValueOptions__Output); + 'options'?: (_google_protobuf_EnumValueOptions__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts index 2d4036158..0fac2df8f 100644 --- a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts @@ -14,5 +14,5 @@ export interface EnumValueOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.envoy.annotations.disallowed_by_default_enum': (boolean); - '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output); + '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts index f9c52a7e1..e0a1f4580 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts @@ -54,7 +54,7 @@ export interface FieldDescriptorProto__Output { 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName': (string); 'defaultValue': (string); - 'options': (_google_protobuf_FieldOptions__Output); + 'options'?: (_google_protobuf_FieldOptions__Output); 'oneofIndex': (number); 'jsonName': (string); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts index dcba8be7c..12a2661a3 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts @@ -42,8 +42,8 @@ export interface FieldOptions__Output { 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); 'weak': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.validate.rules': (_validate_FieldRules__Output); + '.validate.rules'?: (_validate_FieldRules__Output); '.udpa.annotations.sensitive': (boolean); - '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output); + '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation__Output); '.envoy.annotations.disallowed_by_default': (boolean); } diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts index fd69f164e..65315a644 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts @@ -30,8 +30,8 @@ export interface FileDescriptorProto__Output { 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options': (_google_protobuf_FileOptions__Output); - 'sourceCodeInfo': (_google_protobuf_SourceCodeInfo__Output); + 'options'?: (_google_protobuf_FileOptions__Output); + 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo__Output); 'publicDependency': (number)[]; 'weakDependency': (number)[]; 'syntax': (string); diff --git a/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts index ac556b3be..b11540d27 100644 --- a/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts @@ -48,6 +48,6 @@ export interface FileOptions__Output { 'objcClassPrefix': (string); 'csharpNamespace': (string); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.file_migrate': (_udpa_annotations_FileMigrateAnnotation__Output); - '.udpa.annotations.file_status': (_udpa_annotations_StatusAnnotation__Output); + '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation__Output); + '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts index 4bdb411ec..88f654828 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts @@ -20,5 +20,5 @@ export interface MessageOptions__Output { 'mapEntry': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.disabled': (boolean); - '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output); + '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts index 2457567b0..b62d45731 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts @@ -15,7 +15,7 @@ export interface MethodDescriptorProto__Output { 'name': (string); 'inputType': (string); 'outputType': (string); - 'options': (_google_protobuf_MethodOptions__Output); + 'options'?: (_google_protobuf_MethodOptions__Output); 'clientStreaming': (boolean); 'serverStreaming': (boolean); } diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts index d2bbd8516..a5edbd8bb 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts @@ -12,5 +12,5 @@ export interface MethodOptions { export interface MethodOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.google.api.http': (_google_api_HttpRule__Output); + '.google.api.http'?: (_google_api_HttpRule__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts index ab1f85e6e..5d1512003 100644 --- a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts @@ -9,5 +9,5 @@ export interface OneofDescriptorProto { export interface OneofDescriptorProto__Output { 'name': (string); - 'options': (_google_protobuf_OneofOptions__Output); + 'options'?: (_google_protobuf_OneofOptions__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts index 0e0bd5bab..fe5cab5b4 100644 --- a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts @@ -12,5 +12,5 @@ export interface ServiceDescriptorProto { export interface ServiceDescriptorProto__Output { 'name': (string); 'method': (_google_protobuf_MethodDescriptorProto__Output)[]; - 'options': (_google_protobuf_ServiceOptions__Output); + 'options'?: (_google_protobuf_ServiceOptions__Output); } diff --git a/packages/grpc-js/src/generated/google/protobuf/Struct.ts b/packages/grpc-js/src/generated/google/protobuf/Struct.ts index 436a251a3..4b4c3be78 100644 --- a/packages/grpc-js/src/generated/google/protobuf/Struct.ts +++ b/packages/grpc-js/src/generated/google/protobuf/Struct.ts @@ -3,9 +3,9 @@ import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; export interface Struct { - 'fields'?: (_google_protobuf_Value); + 'fields'?: ({[key: string]: _google_protobuf_Value}); } export interface Struct__Output { - 'fields': (_google_protobuf_Value__Output); + 'fields'?: ({[key: string]: _google_protobuf_Value__Output}); } diff --git a/packages/grpc-js/src/generated/validate/DurationRules.ts b/packages/grpc-js/src/generated/validate/DurationRules.ts index ed249bc8d..8a74651c8 100644 --- a/packages/grpc-js/src/generated/validate/DurationRules.ts +++ b/packages/grpc-js/src/generated/validate/DurationRules.ts @@ -59,27 +59,27 @@ export interface DurationRules__Output { /** * Const specifies that this field must be exactly the specified value */ - 'const': (_google_protobuf_Duration__Output); + 'const'?: (_google_protobuf_Duration__Output); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt': (_google_protobuf_Duration__Output); + 'lt'?: (_google_protobuf_Duration__Output); /** * Lt specifies that this field must be less than the specified value, * inclusive */ - 'lte': (_google_protobuf_Duration__Output); + 'lte'?: (_google_protobuf_Duration__Output); /** * Gt specifies that this field must be greater than the specified value, * exclusive */ - 'gt': (_google_protobuf_Duration__Output); + 'gt'?: (_google_protobuf_Duration__Output); /** * Gte specifies that this field must be greater than the specified value, * inclusive */ - 'gte': (_google_protobuf_Duration__Output); + 'gte'?: (_google_protobuf_Duration__Output); /** * In specifies that this field must be equal to one of the specified * values diff --git a/packages/grpc-js/src/generated/validate/FieldRules.ts b/packages/grpc-js/src/generated/validate/FieldRules.ts index 3601f0dad..09cd9d9ee 100644 --- a/packages/grpc-js/src/generated/validate/FieldRules.ts +++ b/packages/grpc-js/src/generated/validate/FieldRules.ts @@ -90,7 +90,7 @@ export interface FieldRules__Output { * Complex Field Types */ 'enum'?: (_validate_EnumRules__Output); - 'message': (_validate_MessageRules__Output); + 'message'?: (_validate_MessageRules__Output); 'repeated'?: (_validate_RepeatedRules__Output); 'map'?: (_validate_MapRules__Output); /** diff --git a/packages/grpc-js/src/generated/validate/MapRules.ts b/packages/grpc-js/src/generated/validate/MapRules.ts index 5ebe1836d..1be003f65 100644 --- a/packages/grpc-js/src/generated/validate/MapRules.ts +++ b/packages/grpc-js/src/generated/validate/MapRules.ts @@ -56,11 +56,11 @@ export interface MapRules__Output { /** * Keys specifies the constraints to be applied to each key in the field. */ - 'keys': (_validate_FieldRules__Output); + 'keys'?: (_validate_FieldRules__Output); /** * Values specifies the constraints to be applied to the value of each key * in the field. Message values will still have their validations evaluated * unless skip is specified here. */ - 'values': (_validate_FieldRules__Output); + 'values'?: (_validate_FieldRules__Output); } diff --git a/packages/grpc-js/src/generated/validate/RepeatedRules.ts b/packages/grpc-js/src/generated/validate/RepeatedRules.ts index 921c80dba..b3b690684 100644 --- a/packages/grpc-js/src/generated/validate/RepeatedRules.ts +++ b/packages/grpc-js/src/generated/validate/RepeatedRules.ts @@ -56,5 +56,5 @@ export interface RepeatedRules__Output { * Repeated message fields will still execute validation against each item * unless skip is specified here. */ - 'items': (_validate_FieldRules__Output); + 'items'?: (_validate_FieldRules__Output); } diff --git a/packages/grpc-js/src/generated/validate/TimestampRules.ts b/packages/grpc-js/src/generated/validate/TimestampRules.ts index 598e05770..7fd9b0ce4 100644 --- a/packages/grpc-js/src/generated/validate/TimestampRules.ts +++ b/packages/grpc-js/src/generated/validate/TimestampRules.ts @@ -66,27 +66,27 @@ export interface TimestampRules__Output { /** * Const specifies that this field must be exactly the specified value */ - 'const': (_google_protobuf_Timestamp__Output); + 'const'?: (_google_protobuf_Timestamp__Output); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt': (_google_protobuf_Timestamp__Output); + 'lt'?: (_google_protobuf_Timestamp__Output); /** * Lte specifies that this field must be less than the specified value, * inclusive */ - 'lte': (_google_protobuf_Timestamp__Output); + 'lte'?: (_google_protobuf_Timestamp__Output); /** * Gt specifies that this field must be greater than the specified value, * exclusive */ - 'gt': (_google_protobuf_Timestamp__Output); + 'gt'?: (_google_protobuf_Timestamp__Output); /** * Gte specifies that this field must be greater than the specified value, * inclusive */ - 'gte': (_google_protobuf_Timestamp__Output); + 'gte'?: (_google_protobuf_Timestamp__Output); /** * LtNow specifies that this must be less than the current time. LtNow * can only be used with the Within rule. @@ -102,5 +102,5 @@ export interface TimestampRules__Output { * current time. This constraint can be used alone or with the LtNow and * GtNow rules. */ - 'within': (_google_protobuf_Duration__Output); + 'within'?: (_google_protobuf_Duration__Output); } diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index ca360f483..4bf6245d3 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -134,21 +134,13 @@ function getStructFromJson(obj: any): Struct { if (typeof obj !== 'object' || obj === null) { throw new Error('Invalid JSON object for Struct field'); } - const result = Object.keys(obj).map((key) => validateValue(key)); - if (result.length === 1) { - return { - fields: result[0], - }; - } else { - return { - fields: { - kind: 'listValue', - listValue: { - values: result, - }, - }, - }; + const fields: {[key: string]: Value} = {}; + for (const [fieldName, value] of Object.entries(obj)) { + fields[fieldName] = validateValue(value); } + return { + fields + }; } /** From 6b03311475488cf0a642a4f42e75019c893485b1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jul 2020 10:10:51 -0700 Subject: [PATCH 1168/1899] gts fix --- packages/grpc-js/src/xds-bootstrap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index 4bf6245d3..b8e446b25 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -134,12 +134,12 @@ function getStructFromJson(obj: any): Struct { if (typeof obj !== 'object' || obj === null) { throw new Error('Invalid JSON object for Struct field'); } - const fields: {[key: string]: Value} = {}; + const fields: { [key: string]: Value } = {}; for (const [fieldName, value] of Object.entries(obj)) { fields[fieldName] = validateValue(value); } return { - fields + fields, }; } From 59471863bfd72a06f54f5db4c70684e10aac6d53 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jul 2020 10:31:19 -0700 Subject: [PATCH 1169/1899] Add 'golden' generator output from a file in gapic-showcase --- .gitmodules | 6 ++ packages/proto-loader/deps/gapic-showcase | 1 + packages/proto-loader/deps/googleapis | 1 + .../proto-loader/golden-generated/echo.ts | 78 +++++++++++++++++ .../google/api/CustomHttpPattern.ts | 12 +++ .../google/api/FieldBehavior.ts | 10 +++ .../golden-generated/google/api/Http.ts | 13 +++ .../golden-generated/google/api/HttpRule.ts | 32 +++++++ .../longrunning/CancelOperationRequest.ts | 10 +++ .../longrunning/DeleteOperationRequest.ts | 10 +++ .../google/longrunning/GetOperationRequest.ts | 10 +++ .../longrunning/ListOperationsRequest.ts | 16 ++++ .../longrunning/ListOperationsResponse.ts | 13 +++ .../google/longrunning/Operation.ts | 22 +++++ .../google/longrunning/OperationInfo.ts | 12 +++ .../google/longrunning/Operations.ts | 72 +++++++++++++++ .../longrunning/WaitOperationRequest.ts | 13 +++ .../golden-generated/google/protobuf/Any.ts | 13 +++ .../google/protobuf/DescriptorProto.ts | 53 +++++++++++ .../google/protobuf/Duration.ts | 13 +++ .../golden-generated/google/protobuf/Empty.ts | 8 ++ .../google/protobuf/EnumDescriptorProto.ts | 16 ++++ .../google/protobuf/EnumOptions.ts | 15 ++++ .../protobuf/EnumValueDescriptorProto.ts | 15 ++++ .../google/protobuf/EnumValueOptions.ts | 13 +++ .../google/protobuf/FieldDescriptorProto.ts | 60 +++++++++++++ .../google/protobuf/FieldOptions.ts | 42 +++++++++ .../google/protobuf/FileDescriptorProto.ts | 38 ++++++++ .../google/protobuf/FileDescriptorSet.ts | 11 +++ .../google/protobuf/FileOptions.ts | 47 ++++++++++ .../google/protobuf/GeneratedCodeInfo.ts | 24 +++++ .../google/protobuf/MessageOptions.ts | 19 ++++ .../google/protobuf/MethodDescriptorProto.ts | 21 +++++ .../google/protobuf/MethodOptions.ts | 21 +++++ .../google/protobuf/OneofDescriptorProto.ts | 13 +++ .../google/protobuf/OneofOptions.ts | 11 +++ .../google/protobuf/ServiceDescriptorProto.ts | 16 ++++ .../google/protobuf/ServiceOptions.ts | 17 ++++ .../google/protobuf/SourceCodeInfo.ts | 26 ++++++ .../google/protobuf/Timestamp.ts | 13 +++ .../google/protobuf/UninterpretedOption.ts | 33 +++++++ .../golden-generated/google/rpc/Status.ts | 15 ++++ .../google/showcase/v1beta1/BlockRequest.ts | 19 ++++ .../google/showcase/v1beta1/BlockResponse.ts | 10 +++ .../google/showcase/v1beta1/Echo.ts | 87 +++++++++++++++++++ .../google/showcase/v1beta1/EchoRequest.ts | 18 ++++ .../google/showcase/v1beta1/EchoResponse.ts | 13 +++ .../google/showcase/v1beta1/ExpandRequest.ts | 13 +++ .../showcase/v1beta1/PagedExpandRequest.ts | 14 +++ .../showcase/v1beta1/PagedExpandResponse.ts | 13 +++ .../google/showcase/v1beta1/Severity.ts | 8 ++ .../google/showcase/v1beta1/WaitMetadata.ts | 11 +++ .../google/showcase/v1beta1/WaitRequest.ts | 24 +++++ .../google/showcase/v1beta1/WaitResponse.ts | 10 +++ packages/proto-loader/gulpfile.ts | 4 +- packages/proto-loader/package.json | 4 +- 56 files changed, 1150 insertions(+), 2 deletions(-) create mode 160000 packages/proto-loader/deps/gapic-showcase create mode 160000 packages/proto-loader/deps/googleapis create mode 100644 packages/proto-loader/golden-generated/echo.ts create mode 100644 packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts create mode 100644 packages/proto-loader/golden-generated/google/api/FieldBehavior.ts create mode 100644 packages/proto-loader/golden-generated/google/api/Http.ts create mode 100644 packages/proto-loader/golden-generated/google/api/HttpRule.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/Operation.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/Operations.ts create mode 100644 packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/Any.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/Duration.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/Empty.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts create mode 100644 packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts create mode 100644 packages/proto-loader/golden-generated/google/rpc/Status.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts create mode 100644 packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts diff --git a/.gitmodules b/.gitmodules index c17c34644..28faf1a38 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,9 @@ [submodule "packages/grpc-tools/deps/protobuf"] path = packages/grpc-tools/deps/protobuf url = https://github.com/protocolbuffers/protobuf +[submodule "packages/proto-loader/deps/gapic-showcase"] + path = packages/proto-loader/deps/gapic-showcase + url = https://github.com/googleapis/gapic-showcase.git +[submodule "packages/proto-loader/deps/googleapis"] + path = packages/proto-loader/deps/googleapis + url = https://github.com/googleapis/googleapis.git diff --git a/packages/proto-loader/deps/gapic-showcase b/packages/proto-loader/deps/gapic-showcase new file mode 160000 index 000000000..b09b3ba9a --- /dev/null +++ b/packages/proto-loader/deps/gapic-showcase @@ -0,0 +1 @@ +Subproject commit b09b3ba9a8db8aae7d5d7c3939853681cc97c293 diff --git a/packages/proto-loader/deps/googleapis b/packages/proto-loader/deps/googleapis new file mode 160000 index 000000000..8f2eda119 --- /dev/null +++ b/packages/proto-loader/deps/googleapis @@ -0,0 +1 @@ +Subproject commit 8f2eda119e11c8bd0c189b545da18bba9019c83e diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts new file mode 100644 index 000000000..c5e2bd540 --- /dev/null +++ b/packages/proto-loader/golden-generated/echo.ts @@ -0,0 +1,78 @@ +import * as grpc from '@grpc/grpc-js'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { OperationsClient as _google_longrunning_OperationsClient } from './google/longrunning/Operations'; +import { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/showcase/v1beta1/Echo'; + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + google: { + api: { + CustomHttpPattern: MessageTypeDefinition + FieldBehavior: EnumTypeDefinition + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + } + longrunning: { + CancelOperationRequest: MessageTypeDefinition + DeleteOperationRequest: MessageTypeDefinition + GetOperationRequest: MessageTypeDefinition + ListOperationsRequest: MessageTypeDefinition + ListOperationsResponse: MessageTypeDefinition + Operation: MessageTypeDefinition + OperationInfo: MessageTypeDefinition + Operations: SubtypeConstructor & { service: ServiceDefinition } + WaitOperationRequest: MessageTypeDefinition + } + protobuf: { + Any: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + } + rpc: { + Status: MessageTypeDefinition + } + showcase: { + v1beta1: { + BlockRequest: MessageTypeDefinition + BlockResponse: MessageTypeDefinition + Echo: SubtypeConstructor & { service: ServiceDefinition } + EchoRequest: MessageTypeDefinition + EchoResponse: MessageTypeDefinition + ExpandRequest: MessageTypeDefinition + PagedExpandRequest: MessageTypeDefinition + PagedExpandResponse: MessageTypeDefinition + Severity: EnumTypeDefinition + WaitMetadata: MessageTypeDefinition + WaitRequest: MessageTypeDefinition + WaitResponse: MessageTypeDefinition + } + } + } +} + diff --git a/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts b/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts new file mode 100644 index 000000000..ebdc3e39a --- /dev/null +++ b/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts @@ -0,0 +1,12 @@ +// Original file: deps/googleapis/google/api/http.proto + + +export interface CustomHttpPattern { + 'kind'?: (string); + 'path'?: (string); +} + +export interface CustomHttpPattern__Output { + 'kind': (string); + 'path': (string); +} diff --git a/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts b/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts new file mode 100644 index 000000000..5d6ae4cbf --- /dev/null +++ b/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts @@ -0,0 +1,10 @@ +// Original file: deps/googleapis/google/api/field_behavior.proto + +export enum FieldBehavior { + FIELD_BEHAVIOR_UNSPECIFIED = 0, + OPTIONAL = 1, + REQUIRED = 2, + OUTPUT_ONLY = 3, + INPUT_ONLY = 4, + IMMUTABLE = 5, +} diff --git a/packages/proto-loader/golden-generated/google/api/Http.ts b/packages/proto-loader/golden-generated/google/api/Http.ts new file mode 100644 index 000000000..fc3839eb1 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/api/Http.ts @@ -0,0 +1,13 @@ +// Original file: deps/googleapis/google/api/http.proto + +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +export interface Http { + 'rules'?: (_google_api_HttpRule)[]; + 'fully_decode_reserved_expansion'?: (boolean); +} + +export interface Http__Output { + 'rules': (_google_api_HttpRule__Output)[]; + 'fully_decode_reserved_expansion': (boolean); +} diff --git a/packages/proto-loader/golden-generated/google/api/HttpRule.ts b/packages/proto-loader/golden-generated/google/api/HttpRule.ts new file mode 100644 index 000000000..3b268a026 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/api/HttpRule.ts @@ -0,0 +1,32 @@ +// Original file: deps/googleapis/google/api/http.proto + +import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +export interface HttpRule { + 'selector'?: (string); + 'get'?: (string); + 'put'?: (string); + 'post'?: (string); + 'delete'?: (string); + 'patch'?: (string); + 'body'?: (string); + 'custom'?: (_google_api_CustomHttpPattern); + 'additional_bindings'?: (_google_api_HttpRule)[]; + 'response_body'?: (string); + 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; +} + +export interface HttpRule__Output { + 'selector': (string); + 'get'?: (string); + 'put'?: (string); + 'post'?: (string); + 'delete'?: (string); + 'patch'?: (string); + 'body': (string); + 'custom'?: (_google_api_CustomHttpPattern__Output); + 'additional_bindings': (_google_api_HttpRule__Output)[]; + 'response_body': (string); + 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts new file mode 100644 index 000000000..274c762b5 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts @@ -0,0 +1,10 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + + +export interface CancelOperationRequest { + 'name'?: (string); +} + +export interface CancelOperationRequest__Output { + 'name': (string); +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts new file mode 100644 index 000000000..43fbebf8d --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts @@ -0,0 +1,10 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + + +export interface DeleteOperationRequest { + 'name'?: (string); +} + +export interface DeleteOperationRequest__Output { + 'name': (string); +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts new file mode 100644 index 000000000..995426cb0 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts @@ -0,0 +1,10 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + + +export interface GetOperationRequest { + 'name'?: (string); +} + +export interface GetOperationRequest__Output { + 'name': (string); +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts new file mode 100644 index 000000000..2e8dfcf0e --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts @@ -0,0 +1,16 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + + +export interface ListOperationsRequest { + 'filter'?: (string); + 'page_size'?: (number); + 'page_token'?: (string); + 'name'?: (string); +} + +export interface ListOperationsRequest__Output { + 'filter': (string); + 'page_size': (number); + 'page_token': (string); + 'name': (string); +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts new file mode 100644 index 000000000..a94557fe9 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts @@ -0,0 +1,13 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + +import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; + +export interface ListOperationsResponse { + 'operations'?: (_google_longrunning_Operation)[]; + 'next_page_token'?: (string); +} + +export interface ListOperationsResponse__Output { + 'operations': (_google_longrunning_Operation__Output)[]; + 'next_page_token': (string); +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts new file mode 100644 index 000000000..3c1c8c88d --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts @@ -0,0 +1,22 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../google/rpc/Status'; + +export interface Operation { + 'name'?: (string); + 'metadata'?: (_google_protobuf_Any); + 'done'?: (boolean); + 'error'?: (_google_rpc_Status); + 'response'?: (_google_protobuf_Any); + 'result'?: "error"|"response"; +} + +export interface Operation__Output { + 'name': (string); + 'metadata'?: (_google_protobuf_Any__Output); + 'done': (boolean); + 'error'?: (_google_rpc_Status__Output); + 'response'?: (_google_protobuf_Any__Output); + 'result': "error"|"response"; +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts b/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts new file mode 100644 index 000000000..a185e3d6e --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts @@ -0,0 +1,12 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + + +export interface OperationInfo { + 'response_type'?: (string); + 'metadata_type'?: (string); +} + +export interface OperationInfo__Output { + 'response_type': (string); + 'metadata_type': (string); +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts new file mode 100644 index 000000000..3991739b0 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -0,0 +1,72 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + +import * as grpc from '@grpc/grpc-js' +import { CancelOperationRequest as _google_longrunning_CancelOperationRequest, CancelOperationRequest__Output as _google_longrunning_CancelOperationRequest__Output } from '../../google/longrunning/CancelOperationRequest'; +import { DeleteOperationRequest as _google_longrunning_DeleteOperationRequest, DeleteOperationRequest__Output as _google_longrunning_DeleteOperationRequest__Output } from '../../google/longrunning/DeleteOperationRequest'; +import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../google/protobuf/Empty'; +import { GetOperationRequest as _google_longrunning_GetOperationRequest, GetOperationRequest__Output as _google_longrunning_GetOperationRequest__Output } from '../../google/longrunning/GetOperationRequest'; +import { ListOperationsRequest as _google_longrunning_ListOperationsRequest, ListOperationsRequest__Output as _google_longrunning_ListOperationsRequest__Output } from '../../google/longrunning/ListOperationsRequest'; +import { ListOperationsResponse as _google_longrunning_ListOperationsResponse, ListOperationsResponse__Output as _google_longrunning_ListOperationsResponse__Output } from '../../google/longrunning/ListOperationsResponse'; +import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; +import { WaitOperationRequest as _google_longrunning_WaitOperationRequest, WaitOperationRequest__Output as _google_longrunning_WaitOperationRequest__Output } from '../../google/longrunning/WaitOperationRequest'; + +export interface OperationsClient extends grpc.Client { + CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + + GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + + ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + + WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + +} + +export interface OperationsHandlers { + CancelOperation(call: grpc.ServerUnaryCall<_google_longrunning_CancelOperationRequest, _google_protobuf_Empty__Output>, callback: grpc.sendUnaryData<_google_protobuf_Empty__Output>): void; + + DeleteOperation(call: grpc.ServerUnaryCall<_google_longrunning_DeleteOperationRequest, _google_protobuf_Empty__Output>, callback: grpc.sendUnaryData<_google_protobuf_Empty__Output>): void; + + GetOperation(call: grpc.ServerUnaryCall<_google_longrunning_GetOperationRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + + ListOperations(call: grpc.ServerUnaryCall<_google_longrunning_ListOperationsRequest, _google_longrunning_ListOperationsResponse__Output>, callback: grpc.sendUnaryData<_google_longrunning_ListOperationsResponse__Output>): void; + + WaitOperation(call: grpc.ServerUnaryCall<_google_longrunning_WaitOperationRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + +} diff --git a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts new file mode 100644 index 000000000..ae8364169 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts @@ -0,0 +1,13 @@ +// Original file: deps/googleapis/google/longrunning/operations.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../google/protobuf/Duration'; + +export interface WaitOperationRequest { + 'name'?: (string); + 'timeout'?: (_google_protobuf_Duration); +} + +export interface WaitOperationRequest__Output { + 'name': (string); + 'timeout'?: (_google_protobuf_Duration__Output); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/Any.ts b/packages/proto-loader/golden-generated/google/protobuf/Any.ts new file mode 100644 index 000000000..b592af4ba --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/Any.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { AnyExtension } from '@grpc/proto-loader'; + +export type Any = AnyExtension | { + type_url: string; + value: Buffer | Uint8Array | string; +} + +export type Any__Output = AnyExtension | { + type_url: string; + value: Buffer; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts new file mode 100644 index 000000000..8ab286897 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts @@ -0,0 +1,53 @@ +// Original file: null + +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; +import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; + +export interface _google_protobuf_DescriptorProto_ExtensionRange { + 'start'?: (number); + 'end'?: (number); +} + +export interface _google_protobuf_DescriptorProto_ExtensionRange__Output { + 'start': (number); + 'end': (number); +} + +export interface _google_protobuf_DescriptorProto_ReservedRange { + 'start'?: (number); + 'end'?: (number); +} + +export interface _google_protobuf_DescriptorProto_ReservedRange__Output { + 'start': (number); + 'end': (number); +} + +export interface DescriptorProto { + 'name'?: (string); + 'field'?: (_google_protobuf_FieldDescriptorProto)[]; + 'nestedType'?: (_google_protobuf_DescriptorProto)[]; + 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; + 'extensionRange'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; + 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; + 'options'?: (_google_protobuf_MessageOptions); + 'oneofDecl'?: (_google_protobuf_OneofDescriptorProto)[]; + 'reservedRange'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; + 'reservedName'?: (string)[]; +} + +export interface DescriptorProto__Output { + 'name': (string); + 'field': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'nestedType': (_google_protobuf_DescriptorProto__Output)[]; + 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; + 'extensionRange': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; + 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'options'?: (_google_protobuf_MessageOptions__Output); + 'oneofDecl': (_google_protobuf_OneofDescriptorProto__Output)[]; + 'reservedRange': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; + 'reservedName': (string)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts new file mode 100644 index 000000000..78610b80a --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface Duration { + 'seconds'?: (number | string | Long); + 'nanos'?: (number); +} + +export interface Duration__Output { + 'seconds': (string); + 'nanos': (number); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/Empty.ts b/packages/proto-loader/golden-generated/google/protobuf/Empty.ts new file mode 100644 index 000000000..f32c2a284 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/Empty.ts @@ -0,0 +1,8 @@ +// Original file: null + + +export interface Empty { +} + +export interface Empty__Output { +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts new file mode 100644 index 000000000..1971fccb0 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts @@ -0,0 +1,16 @@ +// Original file: null + +import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; +import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; + +export interface EnumDescriptorProto { + 'name'?: (string); + 'value'?: (_google_protobuf_EnumValueDescriptorProto)[]; + 'options'?: (_google_protobuf_EnumOptions); +} + +export interface EnumDescriptorProto__Output { + 'name': (string); + 'value': (_google_protobuf_EnumValueDescriptorProto__Output)[]; + 'options'?: (_google_protobuf_EnumOptions__Output); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts new file mode 100644 index 000000000..56c8db7df --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts @@ -0,0 +1,15 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface EnumOptions { + 'allowAlias'?: (boolean); + 'deprecated'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; +} + +export interface EnumOptions__Output { + 'allowAlias': (boolean); + 'deprecated': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts new file mode 100644 index 000000000..919b7aa38 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts @@ -0,0 +1,15 @@ +// Original file: null + +import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; + +export interface EnumValueDescriptorProto { + 'name'?: (string); + 'number'?: (number); + 'options'?: (_google_protobuf_EnumValueOptions); +} + +export interface EnumValueDescriptorProto__Output { + 'name': (string); + 'number': (number); + 'options'?: (_google_protobuf_EnumValueOptions__Output); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts new file mode 100644 index 000000000..6bbd4951f --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface EnumValueOptions { + 'deprecated'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; +} + +export interface EnumValueOptions__Output { + 'deprecated': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts new file mode 100644 index 000000000..e0a1f4580 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts @@ -0,0 +1,60 @@ +// Original file: null + +import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; + +// Original file: null + +export enum _google_protobuf_FieldDescriptorProto_Label { + LABEL_OPTIONAL = 1, + LABEL_REQUIRED = 2, + LABEL_REPEATED = 3, +} + +// Original file: null + +export enum _google_protobuf_FieldDescriptorProto_Type { + TYPE_DOUBLE = 1, + TYPE_FLOAT = 2, + TYPE_INT64 = 3, + TYPE_UINT64 = 4, + TYPE_INT32 = 5, + TYPE_FIXED64 = 6, + TYPE_FIXED32 = 7, + TYPE_BOOL = 8, + TYPE_STRING = 9, + TYPE_GROUP = 10, + TYPE_MESSAGE = 11, + TYPE_BYTES = 12, + TYPE_UINT32 = 13, + TYPE_ENUM = 14, + TYPE_SFIXED32 = 15, + TYPE_SFIXED64 = 16, + TYPE_SINT32 = 17, + TYPE_SINT64 = 18, +} + +export interface FieldDescriptorProto { + 'name'?: (string); + 'extendee'?: (string); + 'number'?: (number); + 'label'?: (_google_protobuf_FieldDescriptorProto_Label | keyof typeof _google_protobuf_FieldDescriptorProto_Label); + 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); + 'typeName'?: (string); + 'defaultValue'?: (string); + 'options'?: (_google_protobuf_FieldOptions); + 'oneofIndex'?: (number); + 'jsonName'?: (string); +} + +export interface FieldDescriptorProto__Output { + 'name': (string); + 'extendee': (string); + 'number': (number); + 'label': (keyof typeof _google_protobuf_FieldDescriptorProto_Label); + 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); + 'typeName': (string); + 'defaultValue': (string); + 'options'?: (_google_protobuf_FieldOptions__Output); + 'oneofIndex': (number); + 'jsonName': (string); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts new file mode 100644 index 000000000..ebed365b7 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts @@ -0,0 +1,42 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { FieldBehavior as _google_api_FieldBehavior } from '../../google/api/FieldBehavior'; + +// Original file: null + +export enum _google_protobuf_FieldOptions_CType { + STRING = 0, + CORD = 1, + STRING_PIECE = 2, +} + +// Original file: null + +export enum _google_protobuf_FieldOptions_JSType { + JS_NORMAL = 0, + JS_STRING = 1, + JS_NUMBER = 2, +} + +export interface FieldOptions { + 'ctype'?: (_google_protobuf_FieldOptions_CType | keyof typeof _google_protobuf_FieldOptions_CType); + 'packed'?: (boolean); + 'deprecated'?: (boolean); + 'lazy'?: (boolean); + 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); + 'weak'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.google.api.field_behavior'?: (_google_api_FieldBehavior | keyof typeof _google_api_FieldBehavior)[]; +} + +export interface FieldOptions__Output { + 'ctype': (keyof typeof _google_protobuf_FieldOptions_CType); + 'packed': (boolean); + 'deprecated': (boolean); + 'lazy': (boolean); + 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); + 'weak': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.google.api.field_behavior': (keyof typeof _google_api_FieldBehavior)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts new file mode 100644 index 000000000..65315a644 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts @@ -0,0 +1,38 @@ +// Original file: null + +import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; +import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; +import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; + +export interface FileDescriptorProto { + 'name'?: (string); + 'package'?: (string); + 'dependency'?: (string)[]; + 'messageType'?: (_google_protobuf_DescriptorProto)[]; + 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; + 'service'?: (_google_protobuf_ServiceDescriptorProto)[]; + 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; + 'options'?: (_google_protobuf_FileOptions); + 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo); + 'publicDependency'?: (number)[]; + 'weakDependency'?: (number)[]; + 'syntax'?: (string); +} + +export interface FileDescriptorProto__Output { + 'name': (string); + 'package': (string); + 'dependency': (string)[]; + 'messageType': (_google_protobuf_DescriptorProto__Output)[]; + 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; + 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; + 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; + 'options'?: (_google_protobuf_FileOptions__Output); + 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo__Output); + 'publicDependency': (number)[]; + 'weakDependency': (number)[]; + 'syntax': (string); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts new file mode 100644 index 000000000..f01cabc4c --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts @@ -0,0 +1,11 @@ +// Original file: null + +import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; + +export interface FileDescriptorSet { + 'file'?: (_google_protobuf_FileDescriptorProto)[]; +} + +export interface FileDescriptorSet__Output { + 'file': (_google_protobuf_FileDescriptorProto__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts new file mode 100644 index 000000000..5a1d270c5 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts @@ -0,0 +1,47 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +// Original file: null + +export enum _google_protobuf_FileOptions_OptimizeMode { + SPEED = 1, + CODE_SIZE = 2, + LITE_RUNTIME = 3, +} + +export interface FileOptions { + 'javaPackage'?: (string); + 'javaOuterClassname'?: (string); + 'optimizeFor'?: (_google_protobuf_FileOptions_OptimizeMode | keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'javaMultipleFiles'?: (boolean); + 'goPackage'?: (string); + 'ccGenericServices'?: (boolean); + 'javaGenericServices'?: (boolean); + 'pyGenericServices'?: (boolean); + 'javaGenerateEqualsAndHash'?: (boolean); + 'deprecated'?: (boolean); + 'javaStringCheckUtf8'?: (boolean); + 'ccEnableArenas'?: (boolean); + 'objcClassPrefix'?: (string); + 'csharpNamespace'?: (string); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; +} + +export interface FileOptions__Output { + 'javaPackage': (string); + 'javaOuterClassname': (string); + 'optimizeFor': (keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'javaMultipleFiles': (boolean); + 'goPackage': (string); + 'ccGenericServices': (boolean); + 'javaGenericServices': (boolean); + 'pyGenericServices': (boolean); + 'javaGenerateEqualsAndHash': (boolean); + 'deprecated': (boolean); + 'javaStringCheckUtf8': (boolean); + 'ccEnableArenas': (boolean); + 'objcClassPrefix': (string); + 'csharpNamespace': (string); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts b/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts new file mode 100644 index 000000000..019fb0e15 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts @@ -0,0 +1,24 @@ +// Original file: null + + +export interface _google_protobuf_GeneratedCodeInfo_Annotation { + 'path'?: (number)[]; + 'sourceFile'?: (string); + 'begin'?: (number); + 'end'?: (number); +} + +export interface _google_protobuf_GeneratedCodeInfo_Annotation__Output { + 'path': (number)[]; + 'sourceFile': (string); + 'begin': (number); + 'end': (number); +} + +export interface GeneratedCodeInfo { + 'annotation'?: (_google_protobuf_GeneratedCodeInfo_Annotation)[]; +} + +export interface GeneratedCodeInfo__Output { + 'annotation': (_google_protobuf_GeneratedCodeInfo_Annotation__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts new file mode 100644 index 000000000..40bf29272 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts @@ -0,0 +1,19 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface MessageOptions { + 'messageSetWireFormat'?: (boolean); + 'noStandardDescriptorAccessor'?: (boolean); + 'deprecated'?: (boolean); + 'mapEntry'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; +} + +export interface MessageOptions__Output { + 'messageSetWireFormat': (boolean); + 'noStandardDescriptorAccessor': (boolean); + 'deprecated': (boolean); + 'mapEntry': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts new file mode 100644 index 000000000..b62d45731 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts @@ -0,0 +1,21 @@ +// Original file: null + +import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; + +export interface MethodDescriptorProto { + 'name'?: (string); + 'inputType'?: (string); + 'outputType'?: (string); + 'options'?: (_google_protobuf_MethodOptions); + 'clientStreaming'?: (boolean); + 'serverStreaming'?: (boolean); +} + +export interface MethodDescriptorProto__Output { + 'name': (string); + 'inputType': (string); + 'outputType': (string); + 'options'?: (_google_protobuf_MethodOptions__Output); + 'clientStreaming': (boolean); + 'serverStreaming': (boolean); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts new file mode 100644 index 000000000..7a4943367 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts @@ -0,0 +1,21 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import { OperationInfo as _google_longrunning_OperationInfo, OperationInfo__Output as _google_longrunning_OperationInfo__Output } from '../../google/longrunning/OperationInfo'; +import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +export interface MethodOptions { + 'deprecated'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.google.longrunning.operation_info'?: (_google_longrunning_OperationInfo); + '.google.api.method_signature'?: (string)[]; + '.google.api.http'?: (_google_api_HttpRule); +} + +export interface MethodOptions__Output { + 'deprecated': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.google.longrunning.operation_info'?: (_google_longrunning_OperationInfo__Output); + '.google.api.method_signature': (string)[]; + '.google.api.http'?: (_google_api_HttpRule__Output); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts new file mode 100644 index 000000000..5d1512003 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; + +export interface OneofDescriptorProto { + 'name'?: (string); + 'options'?: (_google_protobuf_OneofOptions); +} + +export interface OneofDescriptorProto__Output { + 'name': (string); + 'options'?: (_google_protobuf_OneofOptions__Output); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts new file mode 100644 index 000000000..02353a0a4 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts @@ -0,0 +1,11 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface OneofOptions { + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; +} + +export interface OneofOptions__Output { + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts new file mode 100644 index 000000000..fe5cab5b4 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts @@ -0,0 +1,16 @@ +// Original file: null + +import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; +import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; + +export interface ServiceDescriptorProto { + 'name'?: (string); + 'method'?: (_google_protobuf_MethodDescriptorProto)[]; + 'options'?: (_google_protobuf_ServiceOptions); +} + +export interface ServiceDescriptorProto__Output { + 'name': (string); + 'method': (_google_protobuf_MethodDescriptorProto__Output)[]; + 'options'?: (_google_protobuf_ServiceOptions__Output); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts new file mode 100644 index 000000000..7754279c5 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts @@ -0,0 +1,17 @@ +// Original file: null + +import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; + +export interface ServiceOptions { + 'deprecated'?: (boolean); + 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.google.api.default_host'?: (string); + '.google.api.oauth_scopes'?: (string); +} + +export interface ServiceOptions__Output { + 'deprecated': (boolean); + 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.google.api.default_host': (string); + '.google.api.oauth_scopes': (string); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts b/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts new file mode 100644 index 000000000..d30e59b4f --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts @@ -0,0 +1,26 @@ +// Original file: null + + +export interface _google_protobuf_SourceCodeInfo_Location { + 'path'?: (number)[]; + 'span'?: (number)[]; + 'leadingComments'?: (string); + 'trailingComments'?: (string); + 'leadingDetachedComments'?: (string)[]; +} + +export interface _google_protobuf_SourceCodeInfo_Location__Output { + 'path': (number)[]; + 'span': (number)[]; + 'leadingComments': (string); + 'trailingComments': (string); + 'leadingDetachedComments': (string)[]; +} + +export interface SourceCodeInfo { + 'location'?: (_google_protobuf_SourceCodeInfo_Location)[]; +} + +export interface SourceCodeInfo__Output { + 'location': (_google_protobuf_SourceCodeInfo_Location__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts new file mode 100644 index 000000000..f8747e93e --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts @@ -0,0 +1,13 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface Timestamp { + 'seconds'?: (number | string | Long); + 'nanos'?: (number); +} + +export interface Timestamp__Output { + 'seconds': (string); + 'nanos': (number); +} diff --git a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts new file mode 100644 index 000000000..91e3b99bc --- /dev/null +++ b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts @@ -0,0 +1,33 @@ +// Original file: null + +import { Long } from '@grpc/proto-loader'; + +export interface _google_protobuf_UninterpretedOption_NamePart { + 'namePart'?: (string); + 'isExtension'?: (boolean); +} + +export interface _google_protobuf_UninterpretedOption_NamePart__Output { + 'namePart': (string); + 'isExtension': (boolean); +} + +export interface UninterpretedOption { + 'name'?: (_google_protobuf_UninterpretedOption_NamePart)[]; + 'identifierValue'?: (string); + 'positiveIntValue'?: (number | string | Long); + 'negativeIntValue'?: (number | string | Long); + 'doubleValue'?: (number | string); + 'stringValue'?: (Buffer | Uint8Array | string); + 'aggregateValue'?: (string); +} + +export interface UninterpretedOption__Output { + 'name': (_google_protobuf_UninterpretedOption_NamePart__Output)[]; + 'identifierValue': (string); + 'positiveIntValue': (string); + 'negativeIntValue': (string); + 'doubleValue': (number | string); + 'stringValue': (Buffer); + 'aggregateValue': (string); +} diff --git a/packages/proto-loader/golden-generated/google/rpc/Status.ts b/packages/proto-loader/golden-generated/google/rpc/Status.ts new file mode 100644 index 000000000..f1d6ecbcf --- /dev/null +++ b/packages/proto-loader/golden-generated/google/rpc/Status.ts @@ -0,0 +1,15 @@ +// Original file: deps/googleapis/google/rpc/status.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; + +export interface Status { + 'code'?: (number); + 'message'?: (string); + 'details'?: (_google_protobuf_Any)[]; +} + +export interface Status__Output { + 'code': (number); + 'message': (string); + 'details': (_google_protobuf_Any__Output)[]; +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts new file mode 100644 index 000000000..8c3bf3e7e --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts @@ -0,0 +1,19 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; + +export interface BlockRequest { + 'response_delay'?: (_google_protobuf_Duration); + 'error'?: (_google_rpc_Status); + 'success'?: (_google_showcase_v1beta1_BlockResponse); + 'response'?: "error"|"success"; +} + +export interface BlockRequest__Output { + 'response_delay'?: (_google_protobuf_Duration__Output); + 'error'?: (_google_rpc_Status__Output); + 'success'?: (_google_showcase_v1beta1_BlockResponse__Output); + 'response': "error"|"success"; +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts new file mode 100644 index 000000000..b328154fc --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts @@ -0,0 +1,10 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + + +export interface BlockResponse { + 'content'?: (string); +} + +export interface BlockResponse__Output { + 'content': (string); +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts new file mode 100644 index 000000000..d9d7eaf79 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -0,0 +1,87 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import * as grpc from '@grpc/grpc-js' +import { BlockRequest as _google_showcase_v1beta1_BlockRequest, BlockRequest__Output as _google_showcase_v1beta1_BlockRequest__Output } from '../../../google/showcase/v1beta1/BlockRequest'; +import { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; +import { EchoRequest as _google_showcase_v1beta1_EchoRequest, EchoRequest__Output as _google_showcase_v1beta1_EchoRequest__Output } from '../../../google/showcase/v1beta1/EchoRequest'; +import { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; +import { ExpandRequest as _google_showcase_v1beta1_ExpandRequest, ExpandRequest__Output as _google_showcase_v1beta1_ExpandRequest__Output } from '../../../google/showcase/v1beta1/ExpandRequest'; +import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../../google/longrunning/Operation'; +import { PagedExpandRequest as _google_showcase_v1beta1_PagedExpandRequest, PagedExpandRequest__Output as _google_showcase_v1beta1_PagedExpandRequest__Output } from '../../../google/showcase/v1beta1/PagedExpandRequest'; +import { PagedExpandResponse as _google_showcase_v1beta1_PagedExpandResponse, PagedExpandResponse__Output as _google_showcase_v1beta1_PagedExpandResponse__Output } from '../../../google/showcase/v1beta1/PagedExpandResponse'; +import { WaitRequest as _google_showcase_v1beta1_WaitRequest, WaitRequest__Output as _google_showcase_v1beta1_WaitRequest__Output } from '../../../google/showcase/v1beta1/WaitRequest'; + +export interface EchoClient extends grpc.Client { + Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + + Chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + Chat(options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + chat(options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + + Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + + Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + + Expand(argument: _google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Expand(argument: _google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + expand(argument: _google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + expand(argument: _google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + + Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + +} + +export interface EchoHandlers { + Block(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_BlockRequest, _google_showcase_v1beta1_BlockResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_BlockResponse__Output>): void; + + Chat(call: grpc.ServerDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>): void; + + Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse__Output>): void; + + Echo(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse__Output>): void; + + Expand(call: grpc.ServerWritableStream<_google_showcase_v1beta1_ExpandRequest, _google_showcase_v1beta1_EchoResponse__Output>): void; + + PagedExpand(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_PagedExpandRequest, _google_showcase_v1beta1_PagedExpandResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_PagedExpandResponse__Output>): void; + + Wait(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_WaitRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts new file mode 100644 index 000000000..242c4c487 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -0,0 +1,18 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; + +export interface EchoRequest { + 'content'?: (string); + 'error'?: (_google_rpc_Status); + 'severity'?: (_google_showcase_v1beta1_Severity | keyof typeof _google_showcase_v1beta1_Severity); + 'response'?: "content"|"error"; +} + +export interface EchoRequest__Output { + 'content'?: (string); + 'error'?: (_google_rpc_Status__Output); + 'severity': (keyof typeof _google_showcase_v1beta1_Severity); + 'response': "content"|"error"; +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts new file mode 100644 index 000000000..2297bad57 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts @@ -0,0 +1,13 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; + +export interface EchoResponse { + 'content'?: (string); + 'severity'?: (_google_showcase_v1beta1_Severity | keyof typeof _google_showcase_v1beta1_Severity); +} + +export interface EchoResponse__Output { + 'content': (string); + 'severity': (keyof typeof _google_showcase_v1beta1_Severity); +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts new file mode 100644 index 000000000..29acdeb34 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts @@ -0,0 +1,13 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; + +export interface ExpandRequest { + 'content'?: (string); + 'error'?: (_google_rpc_Status); +} + +export interface ExpandRequest__Output { + 'content': (string); + 'error'?: (_google_rpc_Status__Output); +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts new file mode 100644 index 000000000..9a6dca3ae --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts @@ -0,0 +1,14 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + + +export interface PagedExpandRequest { + 'content'?: (string); + 'page_size'?: (number); + 'page_token'?: (string); +} + +export interface PagedExpandRequest__Output { + 'content': (string); + 'page_size': (number); + 'page_token': (string); +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts new file mode 100644 index 000000000..e784165a6 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts @@ -0,0 +1,13 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; + +export interface PagedExpandResponse { + 'responses'?: (_google_showcase_v1beta1_EchoResponse)[]; + 'next_page_token'?: (string); +} + +export interface PagedExpandResponse__Output { + 'responses': (_google_showcase_v1beta1_EchoResponse__Output)[]; + 'next_page_token': (string); +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts new file mode 100644 index 000000000..2cd0ea19f --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts @@ -0,0 +1,8 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +export enum Severity { + UNNECESSARY = 0, + NECESSARY = 1, + URGENT = 2, + CRITICAL = 3, +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts new file mode 100644 index 000000000..848f38d8e --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts @@ -0,0 +1,11 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; + +export interface WaitMetadata { + 'end_time'?: (_google_protobuf_Timestamp); +} + +export interface WaitMetadata__Output { + 'end_time'?: (_google_protobuf_Timestamp__Output); +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts new file mode 100644 index 000000000..e44c77b8b --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts @@ -0,0 +1,24 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + +import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import { WaitResponse as _google_showcase_v1beta1_WaitResponse, WaitResponse__Output as _google_showcase_v1beta1_WaitResponse__Output } from '../../../google/showcase/v1beta1/WaitResponse'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; + +export interface WaitRequest { + 'end_time'?: (_google_protobuf_Timestamp); + 'error'?: (_google_rpc_Status); + 'success'?: (_google_showcase_v1beta1_WaitResponse); + 'ttl'?: (_google_protobuf_Duration); + 'end'?: "end_time"|"ttl"; + 'response'?: "error"|"success"; +} + +export interface WaitRequest__Output { + 'end_time'?: (_google_protobuf_Timestamp__Output); + 'error'?: (_google_rpc_Status__Output); + 'success'?: (_google_showcase_v1beta1_WaitResponse__Output); + 'ttl'?: (_google_protobuf_Duration__Output); + 'end': "end_time"|"ttl"; + 'response': "error"|"success"; +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts new file mode 100644 index 000000000..a08d8b299 --- /dev/null +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts @@ -0,0 +1,10 @@ +// Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto + + +export interface WaitResponse { + 'content'?: (string); +} + +export interface WaitResponse__Output { + 'content': (string); +} diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index ff8f08552..1b27eaa84 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -69,7 +69,9 @@ const runTests = () => { } } -const test = gulp.series(install, runTests); +const testGeneratorGolden = () => execNpmCommand('validate-golden'); + +const test = gulp.series(install, runTests, testGeneratorGolden); export { install, diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index b0897cf6b..25a0dd1cf 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -23,7 +23,9 @@ "check": "gts check", "fix": "gts fix", "pretest": "npm run compile", - "posttest": "npm run check" + "posttest": "npm run check", + "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", + "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -r ./golden-generated ./golden-generated-old" }, "repository": { "type": "git", From 8438fc7a12d4f2d936dc6634931dd1f2dd14d2e4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jul 2020 13:25:43 -0700 Subject: [PATCH 1170/1899] Fix golden file test --- packages/proto-loader/gulpfile.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index 1b27eaa84..60a843416 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -69,7 +69,11 @@ const runTests = () => { } } -const testGeneratorGolden = () => execNpmCommand('validate-golden'); +const testGeneratorGolden = () => { + if (semver.satisfies(process.version, ">=10")) { + return execNpmCommand('validate-golden'); + } +} const test = gulp.series(install, runTests, testGeneratorGolden); From 437f5349309925b76aaab7563fdc36c53941ed7e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jul 2020 13:43:30 -0700 Subject: [PATCH 1171/1899] Generate comments in golden files --- .../bin/proto-loader-gen-types.ts | 3 +- .../proto-loader/golden-generated/echo.ts | 18 + .../google/api/CustomHttpPattern.ts | 18 + .../google/api/FieldBehavior.ts | 37 + .../golden-generated/google/api/Http.ts | 36 + .../golden-generated/google/api/HttpRule.ts | 648 ++++++++++++++++++ .../longrunning/CancelOperationRequest.ts | 12 + .../longrunning/DeleteOperationRequest.ts | 12 + .../google/longrunning/GetOperationRequest.ts | 12 + .../longrunning/ListOperationsRequest.ts | 30 + .../longrunning/ListOperationsResponse.ts | 18 + .../google/longrunning/Operation.ts | 76 ++ .../google/longrunning/OperationInfo.ts | 64 ++ .../google/longrunning/Operations.ts | 160 +++++ .../longrunning/WaitOperationRequest.ts | 22 + .../golden-generated/google/rpc/Status.ts | 42 ++ .../google/showcase/v1beta1/BlockRequest.ts | 26 + .../google/showcase/v1beta1/BlockResponse.ts | 14 + .../google/showcase/v1beta1/Echo.ts | 104 +++ .../google/showcase/v1beta1/EchoRequest.ts | 30 + .../google/showcase/v1beta1/EchoResponse.ts | 18 + .../google/showcase/v1beta1/ExpandRequest.ts | 18 + .../showcase/v1beta1/PagedExpandRequest.ts | 24 + .../showcase/v1beta1/PagedExpandResponse.ts | 18 + .../google/showcase/v1beta1/Severity.ts | 3 + .../google/showcase/v1beta1/WaitMetadata.ts | 12 + .../google/showcase/v1beta1/WaitRequest.ts | 32 + .../google/showcase/v1beta1/WaitResponse.ts | 12 + packages/proto-loader/package.json | 2 +- 29 files changed, 1519 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 23ac5f841..74e95ac52 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -660,7 +660,7 @@ function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'generateComments']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) // .choices('longs', ['String', 'Number']) // .choices('enums', ['String']) // .choices('bytes', ['Array', 'String']) @@ -697,6 +697,7 @@ function runScript() { objects: 'Output default values for omitted message fields even if --defaults is not set', oneofs: 'Output virtual oneof fields set to the present field\'s name', json: 'Represent Infinity and NaN as strings in float fields. Also decode google.protobuf.Any automatically', + includeComments: 'Generate doc comments from comments in the original files', includeDirs: 'Directories to search for included files', outDir: 'Directory in which to output files', grpcLib: 'The gRPC implementation library that these types will be used with' diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index c5e2bd540..f4b07e5a2 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -25,6 +25,17 @@ export interface ProtoGrpcType { ListOperationsResponse: MessageTypeDefinition Operation: MessageTypeDefinition OperationInfo: MessageTypeDefinition + /** + * Manages long-running operations with an API service. + * + * When an API method normally takes long time to complete, it can be designed + * to return [Operation][google.longrunning.Operation] to the client, and the client can use this + * interface to receive the real response asynchronously by polling the + * operation resource, or pass the operation resource to another API (such as + * Google Cloud Pub/Sub API) to receive the response. Any API service that + * returns long-running operations should implement the `Operations` interface + * so developers can have a consistent client experience. + */ Operations: SubtypeConstructor & { service: ServiceDefinition } WaitOperationRequest: MessageTypeDefinition } @@ -61,6 +72,13 @@ export interface ProtoGrpcType { v1beta1: { BlockRequest: MessageTypeDefinition BlockResponse: MessageTypeDefinition + /** + * This service is used showcase the four main types of rpcs - unary, server + * side streaming, client side streaming, and bidirectional streaming. This + * service also exposes methods that explicitly implement server delay, and + * paginated calls. Set the 'showcase-trailer' metadata key on any method + * to have the values echoed in the response trailers. + */ Echo: SubtypeConstructor & { service: ServiceDefinition } EchoRequest: MessageTypeDefinition EchoResponse: MessageTypeDefinition diff --git a/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts b/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts index ebdc3e39a..2b6490be6 100644 --- a/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts +++ b/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts @@ -1,12 +1,30 @@ // Original file: deps/googleapis/google/api/http.proto +/** + * A custom pattern is used for defining custom HTTP verb. + */ export interface CustomHttpPattern { + /** + * The name of this custom HTTP verb. + */ 'kind'?: (string); + /** + * The path matched by this custom verb. + */ 'path'?: (string); } +/** + * A custom pattern is used for defining custom HTTP verb. + */ export interface CustomHttpPattern__Output { + /** + * The name of this custom HTTP verb. + */ 'kind': (string); + /** + * The path matched by this custom verb. + */ 'path': (string); } diff --git a/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts b/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts index 5d6ae4cbf..8ab676709 100644 --- a/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts +++ b/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts @@ -1,10 +1,47 @@ // Original file: deps/googleapis/google/api/field_behavior.proto +/** + * An indicator of the behavior of a given field (for example, that a field + * is required in requests, or given as output but ignored as input). + * This **does not** change the behavior in protocol buffers itself; it only + * denotes the behavior and may affect how API tooling handles the field. + * + * Note: This enum **may** receive new values in the future. + */ export enum FieldBehavior { + /** + * Conventional default for enums. Do not use this. + */ FIELD_BEHAVIOR_UNSPECIFIED = 0, + /** + * Specifically denotes a field as optional. + * While all fields in protocol buffers are optional, this may be specified + * for emphasis if appropriate. + */ OPTIONAL = 1, + /** + * Denotes a field as required. + * This indicates that the field **must** be provided as part of the request, + * and failure to do so will cause an error (usually `INVALID_ARGUMENT`). + */ REQUIRED = 2, + /** + * Denotes a field as output only. + * This indicates that the field is provided in responses, but including the + * field in a request does nothing (the server *must* ignore it and + * *must not* throw an error as a result of the field's presence). + */ OUTPUT_ONLY = 3, + /** + * Denotes a field as input only. + * This indicates that the field is provided in requests, and the + * corresponding field is not included in output. + */ INPUT_ONLY = 4, + /** + * Denotes a field as immutable. + * This indicates that the field may be set once in a request to create a + * resource, but may not be changed thereafter. + */ IMMUTABLE = 5, } diff --git a/packages/proto-loader/golden-generated/google/api/Http.ts b/packages/proto-loader/golden-generated/google/api/Http.ts index fc3839eb1..038c57e5e 100644 --- a/packages/proto-loader/golden-generated/google/api/Http.ts +++ b/packages/proto-loader/golden-generated/google/api/Http.ts @@ -2,12 +2,48 @@ import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export interface Http { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + */ 'rules'?: (_google_api_HttpRule)[]; + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + */ 'fully_decode_reserved_expansion'?: (boolean); } +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ export interface Http__Output { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + */ 'rules': (_google_api_HttpRule__Output)[]; + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + */ 'fully_decode_reserved_expansion': (boolean); } diff --git a/packages/proto-loader/golden-generated/google/api/HttpRule.ts b/packages/proto-loader/golden-generated/google/api/HttpRule.ts index 3b268a026..ed9921e5e 100644 --- a/packages/proto-loader/golden-generated/google/api/HttpRule.ts +++ b/packages/proto-loader/golden-generated/google/api/HttpRule.ts @@ -3,30 +3,678 @@ import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +/** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export interface HttpRule { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + */ 'selector'?: (string); + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + */ 'get'?: (string); + /** + * Maps to HTTP PUT. Used for replacing a resource. + */ 'put'?: (string); + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + */ 'post'?: (string); + /** + * Maps to HTTP DELETE. Used for deleting a resource. + */ 'delete'?: (string); + /** + * Maps to HTTP PATCH. Used for updating a resource. + */ 'patch'?: (string); + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + */ 'body'?: (string); + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + */ 'custom'?: (_google_api_CustomHttpPattern); + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + */ 'additional_bindings'?: (_google_api_HttpRule)[]; + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + */ 'response_body'?: (string); + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + */ 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; } +/** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ export interface HttpRule__Output { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + */ 'selector': (string); + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + */ 'get'?: (string); + /** + * Maps to HTTP PUT. Used for replacing a resource. + */ 'put'?: (string); + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + */ 'post'?: (string); + /** + * Maps to HTTP DELETE. Used for deleting a resource. + */ 'delete'?: (string); + /** + * Maps to HTTP PATCH. Used for updating a resource. + */ 'patch'?: (string); + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + */ 'body': (string); + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + */ 'custom'?: (_google_api_CustomHttpPattern__Output); + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + */ 'additional_bindings': (_google_api_HttpRule__Output)[]; + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + */ 'response_body': (string); + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + */ 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; } diff --git a/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts index 274c762b5..05fbc842e 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts @@ -1,10 +1,22 @@ // Original file: deps/googleapis/google/longrunning/operations.proto +/** + * The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. + */ export interface CancelOperationRequest { + /** + * The name of the operation resource to be cancelled. + */ 'name'?: (string); } +/** + * The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. + */ export interface CancelOperationRequest__Output { + /** + * The name of the operation resource to be cancelled. + */ 'name': (string); } diff --git a/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts index 43fbebf8d..0ad87cde9 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts @@ -1,10 +1,22 @@ // Original file: deps/googleapis/google/longrunning/operations.proto +/** + * The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. + */ export interface DeleteOperationRequest { + /** + * The name of the operation resource to be deleted. + */ 'name'?: (string); } +/** + * The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. + */ export interface DeleteOperationRequest__Output { + /** + * The name of the operation resource to be deleted. + */ 'name': (string); } diff --git a/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts index 995426cb0..039f01674 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts @@ -1,10 +1,22 @@ // Original file: deps/googleapis/google/longrunning/operations.proto +/** + * The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. + */ export interface GetOperationRequest { + /** + * The name of the operation resource. + */ 'name'?: (string); } +/** + * The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. + */ export interface GetOperationRequest__Output { + /** + * The name of the operation resource. + */ 'name': (string); } diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts index 2e8dfcf0e..294ec6773 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts @@ -1,16 +1,46 @@ // Original file: deps/googleapis/google/longrunning/operations.proto +/** + * The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. + */ export interface ListOperationsRequest { + /** + * The standard list filter. + */ 'filter'?: (string); + /** + * The standard list page size. + */ 'page_size'?: (number); + /** + * The standard list page token. + */ 'page_token'?: (string); + /** + * The name of the operation's parent resource. + */ 'name'?: (string); } +/** + * The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. + */ export interface ListOperationsRequest__Output { + /** + * The standard list filter. + */ 'filter': (string); + /** + * The standard list page size. + */ 'page_size': (number); + /** + * The standard list page token. + */ 'page_token': (string); + /** + * The name of the operation's parent resource. + */ 'name': (string); } diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts index a94557fe9..4d893c45f 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts @@ -2,12 +2,30 @@ import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; +/** + * The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. + */ export interface ListOperationsResponse { + /** + * A list of operations that matches the specified filter in the request. + */ 'operations'?: (_google_longrunning_Operation)[]; + /** + * The standard List next-page token. + */ 'next_page_token'?: (string); } +/** + * The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. + */ export interface ListOperationsResponse__Output { + /** + * A list of operations that matches the specified filter in the request. + */ 'operations': (_google_longrunning_Operation__Output)[]; + /** + * The standard List next-page token. + */ 'next_page_token': (string); } diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts index 3c1c8c88d..095b77799 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts @@ -3,20 +3,96 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../google/rpc/Status'; +/** + * This resource represents a long-running operation that is the result of a + * network API call. + */ export interface Operation { + /** + * The server-assigned name, which is only unique within the same service that + * originally returns it. If you use the default HTTP mapping, the + * `name` should be a resource name ending with `operations/{unique_id}`. + */ 'name'?: (string); + /** + * Service-specific metadata associated with the operation. It typically + * contains progress information and common metadata such as create time. + * Some services might not provide such metadata. Any method that returns a + * long-running operation should document the metadata type, if any. + */ 'metadata'?: (_google_protobuf_Any); + /** + * If the value is `false`, it means the operation is still in progress. + * If `true`, the operation is completed, and either `error` or `response` is + * available. + */ 'done'?: (boolean); + /** + * The error result of the operation in case of failure or cancellation. + */ 'error'?: (_google_rpc_Status); + /** + * The normal response of the operation in case of success. If the original + * method returns no data on success, such as `Delete`, the response is + * `google.protobuf.Empty`. If the original method is standard + * `Get`/`Create`/`Update`, the response should be the resource. For other + * methods, the response should have the type `XxxResponse`, where `Xxx` + * is the original method name. For example, if the original method name + * is `TakeSnapshot()`, the inferred response type is + * `TakeSnapshotResponse`. + */ 'response'?: (_google_protobuf_Any); + /** + * The operation result, which can be either an `error` or a valid `response`. + * If `done` == `false`, neither `error` nor `response` is set. + * If `done` == `true`, exactly one of `error` or `response` is set. + */ 'result'?: "error"|"response"; } +/** + * This resource represents a long-running operation that is the result of a + * network API call. + */ export interface Operation__Output { + /** + * The server-assigned name, which is only unique within the same service that + * originally returns it. If you use the default HTTP mapping, the + * `name` should be a resource name ending with `operations/{unique_id}`. + */ 'name': (string); + /** + * Service-specific metadata associated with the operation. It typically + * contains progress information and common metadata such as create time. + * Some services might not provide such metadata. Any method that returns a + * long-running operation should document the metadata type, if any. + */ 'metadata'?: (_google_protobuf_Any__Output); + /** + * If the value is `false`, it means the operation is still in progress. + * If `true`, the operation is completed, and either `error` or `response` is + * available. + */ 'done': (boolean); + /** + * The error result of the operation in case of failure or cancellation. + */ 'error'?: (_google_rpc_Status__Output); + /** + * The normal response of the operation in case of success. If the original + * method returns no data on success, such as `Delete`, the response is + * `google.protobuf.Empty`. If the original method is standard + * `Get`/`Create`/`Update`, the response should be the resource. For other + * methods, the response should have the type `XxxResponse`, where `Xxx` + * is the original method name. For example, if the original method name + * is `TakeSnapshot()`, the inferred response type is + * `TakeSnapshotResponse`. + */ 'response'?: (_google_protobuf_Any__Output); + /** + * The operation result, which can be either an `error` or a valid `response`. + * If `done` == `false`, neither `error` nor `response` is set. + * If `done` == `true`, exactly one of `error` or `response` is set. + */ 'result': "error"|"response"; } diff --git a/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts b/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts index a185e3d6e..343e2f8c9 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts @@ -1,12 +1,76 @@ // Original file: deps/googleapis/google/longrunning/operations.proto +/** + * A message representing the message types used by a long-running operation. + * + * Example: + * + * rpc LongRunningRecognize(LongRunningRecognizeRequest) + * returns (google.longrunning.Operation) { + * option (google.longrunning.operation_info) = { + * response_type: "LongRunningRecognizeResponse" + * metadata_type: "LongRunningRecognizeMetadata" + * }; + * } + */ export interface OperationInfo { + /** + * Required. The message name of the primary return type for this + * long-running operation. + * This type will be used to deserialize the LRO's response. + * + * If the response is in a different package from the rpc, a fully-qualified + * message name must be used (e.g. `google.protobuf.Struct`). + * + * Note: Altering this value constitutes a breaking change. + */ 'response_type'?: (string); + /** + * Required. The message name of the metadata type for this long-running + * operation. + * + * If the response is in a different package from the rpc, a fully-qualified + * message name must be used (e.g. `google.protobuf.Struct`). + * + * Note: Altering this value constitutes a breaking change. + */ 'metadata_type'?: (string); } +/** + * A message representing the message types used by a long-running operation. + * + * Example: + * + * rpc LongRunningRecognize(LongRunningRecognizeRequest) + * returns (google.longrunning.Operation) { + * option (google.longrunning.operation_info) = { + * response_type: "LongRunningRecognizeResponse" + * metadata_type: "LongRunningRecognizeMetadata" + * }; + * } + */ export interface OperationInfo__Output { + /** + * Required. The message name of the primary return type for this + * long-running operation. + * This type will be used to deserialize the LRO's response. + * + * If the response is in a different package from the rpc, a fully-qualified + * message name must be used (e.g. `google.protobuf.Struct`). + * + * Note: Altering this value constitutes a breaking change. + */ 'response_type': (string); + /** + * Required. The message name of the metadata type for this long-running + * operation. + * + * If the response is in a different package from the rpc, a fully-qualified + * message name must be used (e.g. `google.protobuf.Struct`). + * + * Note: Altering this value constitutes a breaking change. + */ 'metadata_type': (string); } diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 3991739b0..64cc32ba9 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -10,47 +10,150 @@ import { ListOperationsResponse as _google_longrunning_ListOperationsResponse, L import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; import { WaitOperationRequest as _google_longrunning_WaitOperationRequest, WaitOperationRequest__Output as _google_longrunning_WaitOperationRequest__Output } from '../../google/longrunning/WaitOperationRequest'; +/** + * Manages long-running operations with an API service. + * + * When an API method normally takes long time to complete, it can be designed + * to return [Operation][google.longrunning.Operation] to the client, and the client can use this + * interface to receive the real response asynchronously by polling the + * operation resource, or pass the operation resource to another API (such as + * Google Cloud Pub/Sub API) to receive the response. Any API service that + * returns long-running operations should implement the `Operations` interface + * so developers can have a consistent client experience. + */ export interface OperationsClient extends grpc.Client { + /** + * Starts asynchronous cancellation on a long-running operation. The server + * makes a best effort to cancel the operation, but success is not + * guaranteed. If the server doesn't support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. Clients can use + * [Operations.GetOperation][google.longrunning.Operations.GetOperation] or + * other methods to check whether the cancellation succeeded or whether the + * operation completed despite cancellation. On successful cancellation, + * the operation is not deleted; instead, it becomes an operation with + * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, + * corresponding to `Code.CANCELLED`. + */ CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * Starts asynchronous cancellation on a long-running operation. The server + * makes a best effort to cancel the operation, but success is not + * guaranteed. If the server doesn't support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. Clients can use + * [Operations.GetOperation][google.longrunning.Operations.GetOperation] or + * other methods to check whether the cancellation succeeded or whether the + * operation completed despite cancellation. On successful cancellation, + * the operation is not deleted; instead, it becomes an operation with + * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, + * corresponding to `Code.CANCELLED`. + */ cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * Deletes a long-running operation. This method indicates that the client is + * no longer interested in the operation result. It does not cancel the + * operation. If the server doesn't support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. + */ DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * Deletes a long-running operation. This method indicates that the client is + * no longer interested in the operation result. It does not cancel the + * operation. If the server doesn't support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. + */ deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * Gets the latest state of a long-running operation. Clients can use this + * method to poll the operation result at intervals as recommended by the API + * service. + */ GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + /** + * Gets the latest state of a long-running operation. Clients can use this + * method to poll the operation result at intervals as recommended by the API + * service. + */ getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + /** + * Lists operations that match the specified filter in the request. If the + * server doesn't support this method, it returns `UNIMPLEMENTED`. + * + * NOTE: the `name` binding allows API services to override the binding + * to use different resource name schemes, such as `users/* /operations`. To + * override the binding, API services can add a binding such as + * `"/v1/{name=users/*}/operations"` to their service configuration. + * For backwards compatibility, the default name includes the operations + * collection id, however overriding users must ensure the name binding + * is the parent resource, without the operations collection id. + */ ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Lists operations that match the specified filter in the request. If the + * server doesn't support this method, it returns `UNIMPLEMENTED`. + * + * NOTE: the `name` binding allows API services to override the binding + * to use different resource name schemes, such as `users/* /operations`. To + * override the binding, API services can add a binding such as + * `"/v1/{name=users/*}/operations"` to their service configuration. + * For backwards compatibility, the default name includes the operations + * collection id, however overriding users must ensure the name binding + * is the parent resource, without the operations collection id. + */ listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Waits for the specified long-running operation until it is done or reaches + * at most a specified timeout, returning the latest state. If the operation + * is already done, the latest state is immediately returned. If the timeout + * specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + * timeout is used. If the server does not support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. + * Note that this method is on a best-effort basis. It may return the latest + * state before the specified timeout (including immediately), meaning even an + * immediate response is no guarantee that the operation is done. + */ WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + /** + * Waits for the specified long-running operation until it is done or reaches + * at most a specified timeout, returning the latest state. If the operation + * is already done, the latest state is immediately returned. If the timeout + * specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + * timeout is used. If the server does not support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. + * Note that this method is on a best-effort basis. It may return the latest + * state before the specified timeout (including immediately), meaning even an + * immediate response is no guarantee that the operation is done. + */ waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; @@ -58,15 +161,72 @@ export interface OperationsClient extends grpc.Client { } +/** + * Manages long-running operations with an API service. + * + * When an API method normally takes long time to complete, it can be designed + * to return [Operation][google.longrunning.Operation] to the client, and the client can use this + * interface to receive the real response asynchronously by polling the + * operation resource, or pass the operation resource to another API (such as + * Google Cloud Pub/Sub API) to receive the response. Any API service that + * returns long-running operations should implement the `Operations` interface + * so developers can have a consistent client experience. + */ export interface OperationsHandlers { + /** + * Starts asynchronous cancellation on a long-running operation. The server + * makes a best effort to cancel the operation, but success is not + * guaranteed. If the server doesn't support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. Clients can use + * [Operations.GetOperation][google.longrunning.Operations.GetOperation] or + * other methods to check whether the cancellation succeeded or whether the + * operation completed despite cancellation. On successful cancellation, + * the operation is not deleted; instead, it becomes an operation with + * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, + * corresponding to `Code.CANCELLED`. + */ CancelOperation(call: grpc.ServerUnaryCall<_google_longrunning_CancelOperationRequest, _google_protobuf_Empty__Output>, callback: grpc.sendUnaryData<_google_protobuf_Empty__Output>): void; + /** + * Deletes a long-running operation. This method indicates that the client is + * no longer interested in the operation result. It does not cancel the + * operation. If the server doesn't support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. + */ DeleteOperation(call: grpc.ServerUnaryCall<_google_longrunning_DeleteOperationRequest, _google_protobuf_Empty__Output>, callback: grpc.sendUnaryData<_google_protobuf_Empty__Output>): void; + /** + * Gets the latest state of a long-running operation. Clients can use this + * method to poll the operation result at intervals as recommended by the API + * service. + */ GetOperation(call: grpc.ServerUnaryCall<_google_longrunning_GetOperationRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + /** + * Lists operations that match the specified filter in the request. If the + * server doesn't support this method, it returns `UNIMPLEMENTED`. + * + * NOTE: the `name` binding allows API services to override the binding + * to use different resource name schemes, such as `users/* /operations`. To + * override the binding, API services can add a binding such as + * `"/v1/{name=users/*}/operations"` to their service configuration. + * For backwards compatibility, the default name includes the operations + * collection id, however overriding users must ensure the name binding + * is the parent resource, without the operations collection id. + */ ListOperations(call: grpc.ServerUnaryCall<_google_longrunning_ListOperationsRequest, _google_longrunning_ListOperationsResponse__Output>, callback: grpc.sendUnaryData<_google_longrunning_ListOperationsResponse__Output>): void; + /** + * Waits for the specified long-running operation until it is done or reaches + * at most a specified timeout, returning the latest state. If the operation + * is already done, the latest state is immediately returned. If the timeout + * specified is greater than the default HTTP/RPC timeout, the HTTP/RPC + * timeout is used. If the server does not support this method, it returns + * `google.rpc.Code.UNIMPLEMENTED`. + * Note that this method is on a best-effort basis. It may return the latest + * state before the specified timeout (including immediately), meaning even an + * immediate response is no guarantee that the operation is done. + */ WaitOperation(call: grpc.ServerUnaryCall<_google_longrunning_WaitOperationRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; } diff --git a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts index ae8364169..865e180cf 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts @@ -2,12 +2,34 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../google/protobuf/Duration'; +/** + * The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. + */ export interface WaitOperationRequest { + /** + * The name of the operation resource to wait on. + */ 'name'?: (string); + /** + * The maximum duration to wait before timing out. If left blank, the wait + * will be at most the time permitted by the underlying HTTP/RPC protocol. + * If RPC context deadline is also specified, the shorter one will be used. + */ 'timeout'?: (_google_protobuf_Duration); } +/** + * The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. + */ export interface WaitOperationRequest__Output { + /** + * The name of the operation resource to wait on. + */ 'name': (string); + /** + * The maximum duration to wait before timing out. If left blank, the wait + * will be at most the time permitted by the underlying HTTP/RPC protocol. + * If RPC context deadline is also specified, the shorter one will be used. + */ 'timeout'?: (_google_protobuf_Duration__Output); } diff --git a/packages/proto-loader/golden-generated/google/rpc/Status.ts b/packages/proto-loader/golden-generated/google/rpc/Status.ts index f1d6ecbcf..7da370379 100644 --- a/packages/proto-loader/golden-generated/google/rpc/Status.ts +++ b/packages/proto-loader/golden-generated/google/rpc/Status.ts @@ -2,14 +2,56 @@ import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +/** + * The `Status` type defines a logical error model that is suitable for + * different programming environments, including REST APIs and RPC APIs. It is + * used by [gRPC](https://github.com/grpc). Each `Status` message contains + * three pieces of data: error code, error message, and error details. + * + * You can find out more about this error model and how to work with it in the + * [API Design Guide](https://cloud.google.com/apis/design/errors). + */ export interface Status { + /** + * The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + */ 'code'?: (number); + /** + * A developer-facing error message, which should be in English. Any + * user-facing error message should be localized and sent in the + * [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + */ 'message'?: (string); + /** + * A list of messages that carry the error details. There is a common set of + * message types for APIs to use. + */ 'details'?: (_google_protobuf_Any)[]; } +/** + * The `Status` type defines a logical error model that is suitable for + * different programming environments, including REST APIs and RPC APIs. It is + * used by [gRPC](https://github.com/grpc). Each `Status` message contains + * three pieces of data: error code, error message, and error details. + * + * You can find out more about this error model and how to work with it in the + * [API Design Guide](https://cloud.google.com/apis/design/errors). + */ export interface Status__Output { + /** + * The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + */ 'code': (number); + /** + * A developer-facing error message, which should be in English. Any + * user-facing error message should be localized and sent in the + * [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + */ 'message': (string); + /** + * A list of messages that carry the error details. There is a common set of + * message types for APIs to use. + */ 'details': (_google_protobuf_Any__Output)[]; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts index 8c3bf3e7e..39cde368c 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts @@ -4,16 +4,42 @@ import { Duration as _google_protobuf_Duration, Duration__Output as _google_prot import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; import { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; +/** + * The request for Block method. + */ export interface BlockRequest { + /** + * The amount of time to block before returning a response. + */ 'response_delay'?: (_google_protobuf_Duration); + /** + * The error that will be returned by the server. If this code is specified + * to be the OK rpc code, an empty response will be returned. + */ 'error'?: (_google_rpc_Status); + /** + * The response to be returned that will signify successful method call. + */ 'success'?: (_google_showcase_v1beta1_BlockResponse); 'response'?: "error"|"success"; } +/** + * The request for Block method. + */ export interface BlockRequest__Output { + /** + * The amount of time to block before returning a response. + */ 'response_delay'?: (_google_protobuf_Duration__Output); + /** + * The error that will be returned by the server. If this code is specified + * to be the OK rpc code, an empty response will be returned. + */ 'error'?: (_google_rpc_Status__Output); + /** + * The response to be returned that will signify successful method call. + */ 'success'?: (_google_showcase_v1beta1_BlockResponse__Output); 'response': "error"|"success"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts index b328154fc..5634b19d4 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts @@ -1,10 +1,24 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto +/** + * The response for Block method. + */ export interface BlockResponse { + /** + * This content can contain anything, the server will not depend on a value + * here. + */ 'content'?: (string); } +/** + * The response for Block method. + */ export interface BlockResponse__Output { + /** + * This content can contain anything, the server will not depend on a value + * here. + */ 'content': (string); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index d9d7eaf79..e518665d5 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -11,57 +11,124 @@ import { PagedExpandRequest as _google_showcase_v1beta1_PagedExpandRequest, Page import { PagedExpandResponse as _google_showcase_v1beta1_PagedExpandResponse, PagedExpandResponse__Output as _google_showcase_v1beta1_PagedExpandResponse__Output } from '../../../google/showcase/v1beta1/PagedExpandResponse'; import { WaitRequest as _google_showcase_v1beta1_WaitRequest, WaitRequest__Output as _google_showcase_v1beta1_WaitRequest__Output } from '../../../google/showcase/v1beta1/WaitRequest'; +/** + * This service is used showcase the four main types of rpcs - unary, server + * side streaming, client side streaming, and bidirectional streaming. This + * service also exposes methods that explicitly implement server delay, and + * paginated calls. Set the 'showcase-trailer' metadata key on any method + * to have the values echoed in the response trailers. + */ export interface EchoClient extends grpc.Client { + /** + * This method will block (wait) for the requested amount of time + * and then return the response or error. + * This method showcases how a client handles delays or retries. + */ Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + /** + * This method will block (wait) for the requested amount of time + * and then return the response or error. + * This method showcases how a client handles delays or retries. + */ block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + /** + * This method, upon receiving a request on the stream, the same content will + * be passed back on the stream. This method showcases bidirectional + * streaming rpcs. + */ Chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; Chat(options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + /** + * This method, upon receiving a request on the stream, the same content will + * be passed back on the stream. This method showcases bidirectional + * streaming rpcs. + */ chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; chat(options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + /** + * This method will collect the words given to it. When the stream is closed + * by the client, this method will return the a concatenation of the strings + * passed to it. This method showcases client-side streaming rpcs. + */ Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + /** + * This method will collect the words given to it. When the stream is closed + * by the client, this method will return the a concatenation of the strings + * passed to it. This method showcases client-side streaming rpcs. + */ collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + /** + * This method simply echos the request. This method is showcases unary rpcs. + */ Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + /** + * This method simply echos the request. This method is showcases unary rpcs. + */ echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + /** + * This method split the given content into words and will pass each word back + * through the stream. This method showcases server-side streaming rpcs. + */ Expand(argument: _google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; Expand(argument: _google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + /** + * This method split the given content into words and will pass each word back + * through the stream. This method showcases server-side streaming rpcs. + */ expand(argument: _google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; expand(argument: _google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + /** + * This is similar to the Expand method but instead of returning a stream of + * expanded words, this method returns a paged list of expanded words. + */ PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + /** + * This is similar to the Expand method but instead of returning a stream of + * expanded words, this method returns a paged list of expanded words. + */ pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + /** + * This method will wait the requested amount of and then return. + * This method showcases how a client handles a request timing out. + */ Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + /** + * This method will wait the requested amount of and then return. + * This method showcases how a client handles a request timing out. + */ wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; @@ -69,19 +136,56 @@ export interface EchoClient extends grpc.Client { } +/** + * This service is used showcase the four main types of rpcs - unary, server + * side streaming, client side streaming, and bidirectional streaming. This + * service also exposes methods that explicitly implement server delay, and + * paginated calls. Set the 'showcase-trailer' metadata key on any method + * to have the values echoed in the response trailers. + */ export interface EchoHandlers { + /** + * This method will block (wait) for the requested amount of time + * and then return the response or error. + * This method showcases how a client handles delays or retries. + */ Block(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_BlockRequest, _google_showcase_v1beta1_BlockResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_BlockResponse__Output>): void; + /** + * This method, upon receiving a request on the stream, the same content will + * be passed back on the stream. This method showcases bidirectional + * streaming rpcs. + */ Chat(call: grpc.ServerDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>): void; + /** + * This method will collect the words given to it. When the stream is closed + * by the client, this method will return the a concatenation of the strings + * passed to it. This method showcases client-side streaming rpcs. + */ Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse__Output>): void; + /** + * This method simply echos the request. This method is showcases unary rpcs. + */ Echo(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse__Output>): void; + /** + * This method split the given content into words and will pass each word back + * through the stream. This method showcases server-side streaming rpcs. + */ Expand(call: grpc.ServerWritableStream<_google_showcase_v1beta1_ExpandRequest, _google_showcase_v1beta1_EchoResponse__Output>): void; + /** + * This is similar to the Expand method but instead of returning a stream of + * expanded words, this method returns a paged list of expanded words. + */ PagedExpand(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_PagedExpandRequest, _google_showcase_v1beta1_PagedExpandResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_PagedExpandResponse__Output>): void; + /** + * This method will wait the requested amount of and then return. + * This method showcases how a client handles a request timing out. + */ Wait(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_WaitRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts index 242c4c487..c5060cdfd 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -3,16 +3,46 @@ import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; import { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; +/** + * The request message used for the Echo, Collect and Chat methods. + * If content or opt are set in this message then the request will succeed. + * If status is set in this message + * then the status will be returned as an error. + */ export interface EchoRequest { + /** + * The content to be echoed by the server. + */ 'content'?: (string); + /** + * The error to be thrown by the server. + */ 'error'?: (_google_rpc_Status); + /** + * The severity to be echoed by the server. + */ 'severity'?: (_google_showcase_v1beta1_Severity | keyof typeof _google_showcase_v1beta1_Severity); 'response'?: "content"|"error"; } +/** + * The request message used for the Echo, Collect and Chat methods. + * If content or opt are set in this message then the request will succeed. + * If status is set in this message + * then the status will be returned as an error. + */ export interface EchoRequest__Output { + /** + * The content to be echoed by the server. + */ 'content'?: (string); + /** + * The error to be thrown by the server. + */ 'error'?: (_google_rpc_Status__Output); + /** + * The severity to be echoed by the server. + */ 'severity': (keyof typeof _google_showcase_v1beta1_Severity); 'response': "content"|"error"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts index 2297bad57..97028b22a 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts @@ -2,12 +2,30 @@ import { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; +/** + * The response message for the Echo methods. + */ export interface EchoResponse { + /** + * The content specified in the request. + */ 'content'?: (string); + /** + * The severity specified in the request. + */ 'severity'?: (_google_showcase_v1beta1_Severity | keyof typeof _google_showcase_v1beta1_Severity); } +/** + * The response message for the Echo methods. + */ export interface EchoResponse__Output { + /** + * The content specified in the request. + */ 'content': (string); + /** + * The severity specified in the request. + */ 'severity': (keyof typeof _google_showcase_v1beta1_Severity); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts index 29acdeb34..8db54519d 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts @@ -2,12 +2,30 @@ import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +/** + * The request message for the Expand method. + */ export interface ExpandRequest { + /** + * The content that will be split into words and returned on the stream. + */ 'content'?: (string); + /** + * The error that is thrown after all words are sent on the stream. + */ 'error'?: (_google_rpc_Status); } +/** + * The request message for the Expand method. + */ export interface ExpandRequest__Output { + /** + * The content that will be split into words and returned on the stream. + */ 'content': (string); + /** + * The error that is thrown after all words are sent on the stream. + */ 'error'?: (_google_rpc_Status__Output); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts index 9a6dca3ae..13c945134 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts @@ -1,14 +1,38 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto +/** + * The request for the PagedExpand method. + */ export interface PagedExpandRequest { + /** + * The string to expand. + */ 'content'?: (string); + /** + * The amount of words to returned in each page. + */ 'page_size'?: (number); + /** + * The position of the page to be returned. + */ 'page_token'?: (string); } +/** + * The request for the PagedExpand method. + */ export interface PagedExpandRequest__Output { + /** + * The string to expand. + */ 'content': (string); + /** + * The amount of words to returned in each page. + */ 'page_size': (number); + /** + * The position of the page to be returned. + */ 'page_token': (string); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts index e784165a6..4c37e4401 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts @@ -2,12 +2,30 @@ import { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; +/** + * The response for the PagedExpand method. + */ export interface PagedExpandResponse { + /** + * The words that were expanded. + */ 'responses'?: (_google_showcase_v1beta1_EchoResponse)[]; + /** + * The next page token. + */ 'next_page_token'?: (string); } +/** + * The response for the PagedExpand method. + */ export interface PagedExpandResponse__Output { + /** + * The words that were expanded. + */ 'responses': (_google_showcase_v1beta1_EchoResponse__Output)[]; + /** + * The next page token. + */ 'next_page_token': (string); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts index 2cd0ea19f..fc3fe6415 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts @@ -1,5 +1,8 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto +/** + * A severity enum used to test enum capabilities in GAPIC surfaces + */ export enum Severity { UNNECESSARY = 0, NECESSARY = 1, diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts index 848f38d8e..481d38412 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts @@ -2,10 +2,22 @@ import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +/** + * The metadata for Wait operation. + */ export interface WaitMetadata { + /** + * The time that this operation will complete. + */ 'end_time'?: (_google_protobuf_Timestamp); } +/** + * The metadata for Wait operation. + */ export interface WaitMetadata__Output { + /** + * The time that this operation will complete. + */ 'end_time'?: (_google_protobuf_Timestamp__Output); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts index e44c77b8b..fe6081203 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts @@ -5,19 +5,51 @@ import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Out import { WaitResponse as _google_showcase_v1beta1_WaitResponse, WaitResponse__Output as _google_showcase_v1beta1_WaitResponse__Output } from '../../../google/showcase/v1beta1/WaitResponse'; import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +/** + * The request for Wait method. + */ export interface WaitRequest { + /** + * The time that this operation will complete. + */ 'end_time'?: (_google_protobuf_Timestamp); + /** + * The error that will be returned by the server. If this code is specified + * to be the OK rpc code, an empty response will be returned. + */ 'error'?: (_google_rpc_Status); + /** + * The response to be returned on operation completion. + */ 'success'?: (_google_showcase_v1beta1_WaitResponse); + /** + * The duration of this operation. + */ 'ttl'?: (_google_protobuf_Duration); 'end'?: "end_time"|"ttl"; 'response'?: "error"|"success"; } +/** + * The request for Wait method. + */ export interface WaitRequest__Output { + /** + * The time that this operation will complete. + */ 'end_time'?: (_google_protobuf_Timestamp__Output); + /** + * The error that will be returned by the server. If this code is specified + * to be the OK rpc code, an empty response will be returned. + */ 'error'?: (_google_rpc_Status__Output); + /** + * The response to be returned on operation completion. + */ 'success'?: (_google_showcase_v1beta1_WaitResponse__Output); + /** + * The duration of this operation. + */ 'ttl'?: (_google_protobuf_Duration__Output); 'end': "end_time"|"ttl"; 'response': "error"|"success"; diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts index a08d8b299..84b804f6b 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts @@ -1,10 +1,22 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto +/** + * The result of the Wait operation. + */ export interface WaitResponse { + /** + * This content of the result. + */ 'content'?: (string); } +/** + * The result of the Wait operation. + */ export interface WaitResponse__Output { + /** + * This content of the result. + */ 'content': (string); } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 852b4a315..7dbb89d0d 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -24,7 +24,7 @@ "fix": "gts fix", "pretest": "npm run compile", "posttest": "npm run check", - "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", + "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json --includeComments -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -r ./golden-generated ./golden-generated-old" }, "repository": { From 71e5cb9c4f84388d245c4f3f66e02af012878afc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jul 2020 13:58:16 -0700 Subject: [PATCH 1172/1899] Update submodules in test script --- run-tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-tests.sh b/run-tests.sh index f23475b90..c4bffacda 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -25,6 +25,8 @@ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.4/install.sh | b set -ex cd $ROOT +git submodule update --init --recursive + if [ ! -n "$node_versions" ] ; then node_versions="8 10 12" fi From d329387c8f285361be6fad034fa527d03df9d230 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jul 2020 15:07:39 -0700 Subject: [PATCH 1173/1899] Skip test properly on older versions --- packages/proto-loader/gulpfile.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/proto-loader/gulpfile.ts b/packages/proto-loader/gulpfile.ts index 60a843416..f8d47c800 100644 --- a/packages/proto-loader/gulpfile.ts +++ b/packages/proto-loader/gulpfile.ts @@ -72,6 +72,9 @@ const runTests = () => { const testGeneratorGolden = () => { if (semver.satisfies(process.version, ">=10")) { return execNpmCommand('validate-golden'); + } else { + console.log(`Skipping generator test for Node ${process.version}`); + return Promise.resolve(null); } } From 044da58c76b94a392cff2d2c8cba3d960a41ff71 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 22 Jul 2020 16:38:00 -0700 Subject: [PATCH 1174/1899] Update with changes from xDS Client PR --- packages/grpc-js/src/load-balancer-eds.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 57582849f..73a27bc4d 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -143,7 +143,7 @@ export class EdsLoadBalancer implements LoadBalancer { (lbEndpoint) => { /* The validator in the XdsClient class ensures that each endpoint has * a socket_address with an IP address and a port_value. */ - const socketAddress = lbEndpoint.endpoint!.address.socket_address!; + const socketAddress = lbEndpoint.endpoint!.address!.socket_address!; return { host: socketAddress.address!, port: socketAddress.port_value!, @@ -151,12 +151,12 @@ export class EdsLoadBalancer implements LoadBalancer { } ); localityArray.push({ - locality: endpoint.locality, + locality: endpoint.locality!, addresses: addresses, - weight: endpoint.load_balancing_weight.value, + weight: endpoint.load_balancing_weight?.value ?? 0, }); newLocalityPriorities.set( - localityToName(endpoint.locality), + localityToName(endpoint.locality!), endpoint.priority ); } From ef225cba30efd54027b527ecd6627d0b065d45d8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jul 2020 10:08:50 -0700 Subject: [PATCH 1175/1899] Handle changing EDS service name, add comments --- packages/grpc-js/src/load-balancer-eds.ts | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 73a27bc4d..1bbce0a2c 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -282,13 +282,30 @@ export class EdsLoadBalancer implements LoadBalancer { this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; - this.edsServiceName = lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + const newEdsServiceName = lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + + /* If the name is changing, disable the old watcher before adding the new + * one */ + if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { + this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); + /* Setting isWatcherActive to false here lets us have one code path for + * calling addEndpointWatcher */ + this.isWatcherActive = false; + /* If we have a new name, the latestEdsUpdate does not correspond to + * the new config, so it is no longer valid */ + this.latestEdsUpdate = null; + } + + this.edsServiceName = newEdsServiceName; if (!this.isWatcherActive) { this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); this.isWatcherActive = true; } + /* If updateAddressList is called after receiving an update and the update + * is still valid, we want to update the child config with the information + * in the new EdsLoadBalancingConfig. */ this.updateChild(); } exitIdle(): void { From fc2fd00da7d9ea9efafb65a2dfe24225aceccd35 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jul 2020 10:27:01 -0700 Subject: [PATCH 1176/1899] grpc-js: xDS Client: cache updates to pass them to new watchers --- packages/grpc-js/src/xds-client.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 98454817f..ff4d36b8d 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -105,6 +105,7 @@ export class XdsClient { > = new Map[]>(); private lastEdsVersionInfo = ''; private lastEdsNonce = ''; + private latestEdsResponses: ClusterLoadAssignment__Output[] = []; constructor( private targetName: string, @@ -206,6 +207,7 @@ export class XdsClient { } this.lastEdsVersionInfo = message.version_info; this.lastEdsNonce = message.nonce; + this.latestEdsResponses = edsResponses; this.ackEds(); break; } @@ -357,6 +359,18 @@ export class XdsClient { if (addedServiceName) { this.updateEdsNames(); } + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestEdsResponses) { + if (message.cluster_name === edsServiceName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + watcher.onValidUpdate(message); + }); + } + } } removeEndpointWatcher( From 1fc0895d173ef7aefb66b8342fb3a2aa56b127c6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jul 2020 11:21:09 -0700 Subject: [PATCH 1177/1899] grpc-js: Fix handling of unsuccessful TXT record lookups --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/resolver-dns.ts | 20 +++++++------------ .../grpc-js/src/resolving-load-balancer.ts | 18 ++++++----------- 3 files changed, 14 insertions(+), 26 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 1f28e3240..6473bb32e 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.2", + "version": "1.1.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 8a7f4f229..74e43ca0f 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -237,19 +237,13 @@ class DnsResolver implements Resolver { } }, (err) => { - this.latestServiceConfigError = { - code: Status.UNAVAILABLE, - details: 'TXT query failed', - metadata: new Metadata(), - }; - if (this.latestLookupResult !== null) { - this.listener.onSuccessfulResolution( - this.latestLookupResult, - this.latestServiceConfig, - this.latestServiceConfigError, - {} - ); - } + /* If TXT lookup fails we should do nothing, which means that we + * continue to use the result of the most recent successful lookup, + * or the default null config object if there has never been a + * successful lookup. We do not set the latestServiceConfigError + * here because that is specifically used for response validation + * errors. We still need to handle this error so that it does not + * bubble up as an unhandled promise rejection. */ } ); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index fe75944de..43a074806 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -60,10 +60,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { /** * The service config object from the last successful resolution, if * available. A value of undefined indicates that there has not yet - * been a successful resolution. A value of null indicates that the last - * successful resolution explicitly provided a null service config. + * been a successful resolution, or that the last succesful resolution + * explicitly provided a null service config. */ - private previousServiceConfig: ServiceConfig | null | undefined = undefined; + private previousServiceConfig: ServiceConfig | null = null; /** * The backoff timer for handling name resolution failures. @@ -131,19 +131,13 @@ export class ResolvingLoadBalancer implements LoadBalancer { // Step 4 and 5 if (serviceConfigError === null) { // Step 5 - this.previousServiceConfig = serviceConfig; + this.previousServiceConfig = this.defaultServiceConfig; workingServiceConfig = this.defaultServiceConfig; } else { // Step 4 - if (this.previousServiceConfig === undefined) { + if (this.previousServiceConfig === null) { // Step 4.ii - if (this.defaultServiceConfig === null) { - // Step 4.ii.b - this.handleResolutionFailure(serviceConfigError); - } else { - // Step 4.ii.a - workingServiceConfig = this.defaultServiceConfig; - } + this.handleResolutionFailure(serviceConfigError); } else { // Step 4.i workingServiceConfig = this.previousServiceConfig; From f05e9fb3f458a6195be1217275d757130d13857a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jul 2020 12:57:13 -0700 Subject: [PATCH 1178/1899] Refine service config error handling --- packages/grpc-js/src/resolving-load-balancer.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 43a074806..b467a767c 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -59,9 +59,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { private currentState: ConnectivityState = ConnectivityState.IDLE; /** * The service config object from the last successful resolution, if - * available. A value of undefined indicates that there has not yet - * been a successful resolution, or that the last succesful resolution - * explicitly provided a null service config. + * available. A value of null indicates that we have not yet received a valid + * service config from the resolver. */ private previousServiceConfig: ServiceConfig | null = null; @@ -131,7 +130,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { // Step 4 and 5 if (serviceConfigError === null) { // Step 5 - this.previousServiceConfig = this.defaultServiceConfig; + this.previousServiceConfig = null; workingServiceConfig = this.defaultServiceConfig; } else { // Step 4 From c9074b634cea34fe69225afc74124c8c02d89acd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jul 2020 14:21:53 -0700 Subject: [PATCH 1179/1899] Finish implementing the CDS load balancer --- packages/grpc-js/src/load-balancer-cds.ts | 277 +++++++++++++--------- packages/grpc-js/src/load-balancer-eds.ts | 12 +- packages/grpc-js/src/load-balancer.ts | 4 + packages/grpc-js/src/xds-client.ts | 46 ++-- 4 files changed, 205 insertions(+), 134 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 33fe42c73..7e7bfe177 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -1,115 +1,162 @@ -/* - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { LoadBalancingConfig, isCdsLoadBalancingConfig, EdsLbConfig, CdsLoadBalancingConfig } from './load-balancing-config'; -import { XdsClient, Watcher } from './xds-client'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; -import { ConnectivityState } from './channel'; -import { UnavailablePicker } from './picker'; -import { Status } from './constants'; -import { Metadata } from '.'; - -const TYPE_NAME = 'cds'; - -export class CdsLoadBalancer implements LoadBalancer { - private childBalancer: ChildLoadBalancerHandler; - private xdsClient: XdsClient | null = null; - private watcher: Watcher; - - private isWatcherActive = false; - - private latestCdsUpdate: Cluster__Output | null = null; - - private latestConfig: CdsLoadBalancingConfig | null = null; - private latestAttributes: { [key: string]: unknown } = {}; - - constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); - this.watcher = { - onValidUpdate: update => { - this.latestCdsUpdate = update; - const edsConfig: EdsLbConfig = { - cluster: update.name, - edsServiceName: update.eds_cluster_config.service_name === '' ? undefined : update.eds_cluster_config.service_name, - localityPickingPolicy: [], - endpointPickingPolicy: [] - // TODO(murgatroid99): populate lrsLoadReportingServerName - } - this.childBalancer.updateAddressList([], {name: 'eds', eds: edsConfig}, this.latestAttributes); - }, - onResourceDoesNotExist: () => { - this.xdsClient?.removeClusterWatcher(this.latestConfig!.cds.cluster, this.watcher); - this.isWatcherActive = false; - }, - onTransientError: status => { - if (this.latestCdsUpdate === null) { - channelControlHelper.updateState( - ConnectivityState.TRANSIENT_FAILURE, - new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: `xDS request failed with error ${status.details}`, - metadata: new Metadata(), - }) - ); - } - } - }; - } - - updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { - if (!isCdsLoadBalancingConfig(lbConfig)) { - return; - } - if (!(attributes.xdsClient instanceof XdsClient)) { - return; - } - this.xdsClient = attributes.xdsClient; - this.latestConfig = lbConfig; - this.latestAttributes = attributes; - - if (!this.isWatcherActive) { - this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); - this.isWatcherActive = true; - } - } - exitIdle(): void { - this.childBalancer.exitIdle(); - } - resetBackoff(): void { - this.childBalancer.resetBackoff(); - } - destroy(): void { - this.childBalancer.destroy(); - if (this.isWatcherActive) { - this.xdsClient?.removeClusterWatcher(this.latestConfig!.cds.cluster, this.watcher); - } - } - getTypeName(): string { - return TYPE_NAME; - } -} - -export function setup() { - registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer); -} \ No newline at end of file +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + registerLoadBalancerType, +} from './load-balancer'; +import { SubchannelAddress } from './subchannel'; +import { + LoadBalancingConfig, + isCdsLoadBalancingConfig, + EdsLbConfig, + CdsLoadBalancingConfig, +} from './load-balancing-config'; +import { XdsClient, Watcher } from './xds-client'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; +import { ConnectivityState } from './channel'; +import { UnavailablePicker } from './picker'; +import { Status } from './constants'; +import { Metadata } from '.'; + +const TYPE_NAME = 'cds'; + +export class CdsLoadBalancer implements LoadBalancer { + private childBalancer: ChildLoadBalancerHandler; + private xdsClient: XdsClient | null = null; + private watcher: Watcher; + + private isWatcherActive = false; + + private latestCdsUpdate: Cluster__Output | null = null; + + private latestConfig: CdsLoadBalancingConfig | null = null; + private latestAttributes: { [key: string]: unknown } = {}; + + constructor(private readonly channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.watcher = { + onValidUpdate: (update) => { + this.latestCdsUpdate = update; + const edsConfig: EdsLbConfig = { + cluster: update.name, + edsServiceName: + update.eds_cluster_config!.service_name === '' + ? undefined + : update.eds_cluster_config!.service_name, + localityPickingPolicy: [], + endpointPickingPolicy: [], + }; + if (update.lrs_server?.self) { + /* the lrs_server.self field indicates that the same server should be + * used for load reporting as for other xDS operations. Setting + * lrsLoadReportingServerName to the empty string sets that behavior. + * Otherwise, if the field is omitted, load reporting is disabled. */ + edsConfig.lrsLoadReportingServerName = ''; + } + this.childBalancer.updateAddressList( + [], + { name: 'eds', eds: edsConfig }, + this.latestAttributes + ); + }, + onResourceDoesNotExist: () => { + this.xdsClient?.removeClusterWatcher( + this.latestConfig!.cds.cluster, + this.watcher + ); + this.isWatcherActive = false; + }, + onTransientError: (status) => { + if (this.latestCdsUpdate === null) { + channelControlHelper.updateState( + ConnectivityState.TRANSIENT_FAILURE, + new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: `xDS request failed with error ${status.details}`, + metadata: new Metadata(), + }) + ); + } + }, + }; + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!isCdsLoadBalancingConfig(lbConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + this.xdsClient = attributes.xdsClient; + this.latestAttributes = attributes; + + /* If the cluster is changing, disable the old watcher before adding the new + * one */ + if ( + this.isWatcherActive && + this.latestConfig?.cds.cluster !== lbConfig.cds.cluster + ) { + this.xdsClient.removeClusterWatcher( + this.latestConfig!.cds.cluster, + this.watcher + ); + /* Setting isWatcherActive to false here lets us have one code path for + * calling addClusterWatcher */ + this.isWatcherActive = false; + /* If we have a new name, the latestCdsUpdate does not correspond to + * the new config, so it is no longer valid */ + this.latestCdsUpdate = null; + } + + this.latestConfig = lbConfig; + + if (!this.isWatcherActive) { + this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); + this.isWatcherActive = true; + } + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + if (this.isWatcherActive) { + this.xdsClient?.removeClusterWatcher( + this.latestConfig!.cds.cluster, + this.watcher + ); + } + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer); +} diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 5dbbfd702..24b464af6 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -91,7 +91,10 @@ export class EdsLoadBalancer implements LoadBalancer { this.updateChild(); }, onResourceDoesNotExist: () => { - this.xdsClient?.removeEndpointWatcher(this.edsServiceName!, this.watcher); + this.xdsClient?.removeEndpointWatcher( + this.edsServiceName!, + this.watcher + ); this.isWatcherActive = false; }, onTransientError: (status) => { @@ -282,17 +285,18 @@ export class EdsLoadBalancer implements LoadBalancer { this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; - const newEdsServiceName = lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + const newEdsServiceName = + lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; /* If the name is changing, disable the old watcher before adding the new * one */ if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); /* Setting isWatcherActive to false here lets us have one code path for - * calling addEndpointWatcher */ + * calling addEndpointWatcher */ this.isWatcherActive = false; /* If we have a new name, the latestEdsUpdate does not correspond to - * the new config, so it is no longer valid */ + * the new config, so it is no longer valid */ this.latestEdsUpdate = null; } diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 9a1c1fcdc..227bbe9cf 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -24,6 +24,8 @@ import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; import * as load_balancer_priority from './load-balancer-priority'; import * as load_balancer_weighted_target from './load-balancer-weighted-target'; +import * as load_balancer_eds from './load-balancer-eds'; +import * as load_balancer_cds from './load-balancer-cds'; /** * A collection of functions associated with a channel that a load balancer @@ -141,4 +143,6 @@ export function registerAll() { load_balancer_round_robin.setup(); load_balancer_priority.setup(); load_balancer_weighted_target.setup(); + load_balancer_eds.setup(); + load_balancer_cds.setup(); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 54d059e29..98bafda37 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -44,7 +44,7 @@ function trace(text: string): void { const clientVersion = require('../../package.json').version; const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; -const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster' +const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; let loadedProtos: Promise | null = null; @@ -108,10 +108,14 @@ export class XdsClient { private lastEdsVersionInfo = ''; private lastEdsNonce = ''; private latestEdsResponses: ClusterLoadAssignment__Output[] = []; - - private clusterWatchers: Map[]> = new Map[]>(); + + private clusterWatchers: Map[]> = new Map< + string, + Watcher[] + >(); private lastCdsVersionInfo = ''; private lastCdsNonce = ''; + private latestCdsResponses: Cluster__Output[] = []; constructor( private targetName: string, @@ -217,14 +221,15 @@ export class XdsClient { this.ackEds(); break; } - case CDS_TYPE_URL: + case CDS_TYPE_URL: { const cdsResponses: Cluster__Output[] = []; for (const resource of message.resources) { if ( protoLoader.isAnyExtension(resource) && resource['@type'] === CDS_TYPE_URL ) { - const resp = resource as protoLoader.AnyExtension & Cluster__Output; + const resp = resource as protoLoader.AnyExtension & + Cluster__Output; if (!this.validateCdsResponse(resp)) { this.nackCds('Cluster validation failed'); return; @@ -245,8 +250,10 @@ export class XdsClient { } this.lastCdsVersionInfo = message.version_info; this.lastCdsNonce = message.nonce; + this.latestCdsResponses = cdsResponses; this.ackCds(); break; + } default: this.nackUnknown( message.type_url, @@ -384,7 +391,7 @@ export class XdsClient { if (message.type !== 'EDS') { return false; } - if (!message.eds_cluster_config.eds_config.ads) { + if (!message.eds_cluster_config?.eds_config?.ads) { return false; } if (message.lb_policy !== 'ROUND_ROBIN') { @@ -437,7 +444,10 @@ export class XdsClient { } private reportStreamError(status: StatusObject) { - for (const watcherList of [...this.endpointWatchers.values(), ...this.clusterWatchers.values()]) { + for (const watcherList of [ + ...this.endpointWatchers.values(), + ...this.clusterWatchers.values(), + ]) { for (const watcher of watcherList) { watcher.onTransientError(status); } @@ -497,10 +507,7 @@ export class XdsClient { } } - addClusterWatcher( - clusterName: string, - watcher: Watcher - ) { + addClusterWatcher(clusterName: string, watcher: Watcher) { trace('Watcher added for cluster ' + clusterName); let watchersEntry = this.clusterWatchers.get(clusterName); let addedServiceName = false; @@ -513,12 +520,21 @@ export class XdsClient { if (addedServiceName) { this.updateCdsNames(); } + + /* If we have already received an update for the requested clusterName, + * immediately pass that update along to the watcher */ + for (const message of this.latestCdsResponses) { + if (message.name === clusterName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + watcher.onValidUpdate(message); + }); + } + } } - removeClusterWatcher( - clusterName: string, - watcher: Watcher - ) { + removeClusterWatcher(clusterName: string, watcher: Watcher) { trace('Watcher removed for endpoint ' + clusterName); const watchersEntry = this.clusterWatchers.get(clusterName); let removedServiceName = false; From fbf2a487f16024965cc67ccd34f234aad8fee662 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Jul 2020 09:56:33 -0700 Subject: [PATCH 1180/1899] Fix Metadata import path --- packages/grpc-js/src/load-balancer-cds.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 7e7bfe177..823469787 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -33,7 +33,7 @@ import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; import { ConnectivityState } from './channel'; import { UnavailablePicker } from './picker'; import { Status } from './constants'; -import { Metadata } from '.'; +import { Metadata } from './metadata'; const TYPE_NAME = 'cds'; From 9fb6f48bd6900fe345483451e8c9f98856fd2399 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Jul 2020 16:06:37 -0700 Subject: [PATCH 1181/1899] grpc-js: xDS: add support for dropping calls and reporting drops --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 6 + .../envoy/api/v2/endpoint/ClusterStats.ts | 117 +++++++ .../v2/endpoint/EndpointLoadMetricStats.ts | 41 +++ .../api/v2/endpoint/UpstreamEndpointStats.ts | 106 +++++++ .../api/v2/endpoint/UpstreamLocalityStats.ts | 108 +++++++ .../load_stats/v2/LoadReportingService.ts | 108 +++++++ .../service/load_stats/v2/LoadStatsRequest.ts | 34 ++ .../load_stats/v2/LoadStatsResponse.ts | 71 +++++ packages/grpc-js/src/generated/lrs.ts | 146 +++++++++ packages/grpc-js/src/load-balancer-eds.ts | 89 +++++- packages/grpc-js/src/picker.ts | 9 + packages/grpc-js/src/xds-client.ts | 290 ++++++++++++++++-- 13 files changed, 1105 insertions(+), 22 deletions(-) create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts create mode 100644 packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts create mode 100644 packages/grpc-js/src/generated/lrs.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6473bb32e..4c4e59f06 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -48,7 +48,7 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index fe85dec04..f2ad181ab 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -390,6 +390,12 @@ export class ChannelImplementation implements Channel { ); } break; + case PickResultType.DROP: + callStream.cancelWithStatus( + pickResult.status!.code, + pickResult.status!.details + ); + break; default: throw new Error( `Invalid state: unknown pickResultType ${pickResult.pickResultType}` diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts new file mode 100644 index 000000000..8b2492899 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts @@ -0,0 +1,117 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { UpstreamLocalityStats as _envoy_api_v2_endpoint_UpstreamLocalityStats, UpstreamLocalityStats__Output as _envoy_api_v2_endpoint_UpstreamLocalityStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamLocalityStats'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import { Long } from '@grpc/proto-loader'; + +export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests { + /** + * Identifier for the policy specifying the drop. + */ + 'category'?: (string); + /** + * Total number of deliberately dropped requests for the category. + */ + 'dropped_count'?: (number | string | Long); +} + +export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests__Output { + /** + * Identifier for the policy specifying the drop. + */ + 'category': (string); + /** + * Total number of deliberately dropped requests for the category. + */ + 'dropped_count': (string); +} + +/** + * Per cluster load stats. Envoy reports these stats a management server in a + * :ref:`LoadStatsRequest` + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * Next ID: 7 + * [#next-free-field: 7] + */ +export interface ClusterStats { + /** + * The name of the cluster. + */ + 'cluster_name'?: (string); + /** + * Need at least one. + */ + 'upstream_locality_stats'?: (_envoy_api_v2_endpoint_UpstreamLocalityStats)[]; + /** + * Cluster-level stats such as total_successful_requests may be computed by + * summing upstream_locality_stats. In addition, below there are additional + * cluster-wide stats. + * + * The total number of dropped requests. This covers requests + * deliberately dropped by the drop_overload policy and circuit breaking. + */ + 'total_dropped_requests'?: (number | string | Long); + /** + * Period over which the actual load report occurred. This will be guaranteed to include every + * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy + * and the *LoadStatsResponse* message sent from the management server, this may be longer than + * the requested load reporting interval in the *LoadStatsResponse*. + */ + 'load_report_interval'?: (_google_protobuf_Duration); + /** + * Information about deliberately dropped requests for each category specified + * in the DropOverload policy. + */ + 'dropped_requests'?: (_envoy_api_v2_endpoint_ClusterStats_DroppedRequests)[]; + /** + * The eds_cluster_config service_name of the cluster. + * It's possible that two clusters send the same service_name to EDS, + * in that case, the management server is supposed to do aggregation on the load reports. + */ + 'cluster_service_name'?: (string); +} + +/** + * Per cluster load stats. Envoy reports these stats a management server in a + * :ref:`LoadStatsRequest` + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * Next ID: 7 + * [#next-free-field: 7] + */ +export interface ClusterStats__Output { + /** + * The name of the cluster. + */ + 'cluster_name': (string); + /** + * Need at least one. + */ + 'upstream_locality_stats': (_envoy_api_v2_endpoint_UpstreamLocalityStats__Output)[]; + /** + * Cluster-level stats such as total_successful_requests may be computed by + * summing upstream_locality_stats. In addition, below there are additional + * cluster-wide stats. + * + * The total number of dropped requests. This covers requests + * deliberately dropped by the drop_overload policy and circuit breaking. + */ + 'total_dropped_requests': (string); + /** + * Period over which the actual load report occurred. This will be guaranteed to include every + * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy + * and the *LoadStatsResponse* message sent from the management server, this may be longer than + * the requested load reporting interval in the *LoadStatsResponse*. + */ + 'load_report_interval'?: (_google_protobuf_Duration__Output); + /** + * Information about deliberately dropped requests for each category specified + * in the DropOverload policy. + */ + 'dropped_requests': (_envoy_api_v2_endpoint_ClusterStats_DroppedRequests__Output)[]; + /** + * The eds_cluster_config service_name of the cluster. + * It's possible that two clusters send the same service_name to EDS, + * in that case, the management server is supposed to do aggregation on the load reports. + */ + 'cluster_service_name': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts new file mode 100644 index 000000000..a42087c9c --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts @@ -0,0 +1,41 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { Long } from '@grpc/proto-loader'; + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface EndpointLoadMetricStats { + /** + * Name of the metric; may be empty. + */ + 'metric_name'?: (string); + /** + * Number of calls that finished and included this metric. + */ + 'num_requests_finished_with_metric'?: (number | string | Long); + /** + * Sum of metric values across all calls that finished with this metric for + * load_reporting_interval. + */ + 'total_metric_value'?: (number | string); +} + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface EndpointLoadMetricStats__Output { + /** + * Name of the metric; may be empty. + */ + 'metric_name': (string); + /** + * Number of calls that finished and included this metric. + */ + 'num_requests_finished_with_metric': (string); + /** + * Sum of metric values across all calls that finished with this metric for + * load_reporting_interval. + */ + 'total_metric_value': (number | string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts new file mode 100644 index 000000000..4d2df5d2f --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts @@ -0,0 +1,106 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +import { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Long } from '@grpc/proto-loader'; + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 8] + */ +export interface UpstreamEndpointStats { + /** + * Upstream host address. + */ + 'address'?: (_envoy_api_v2_core_Address); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. These include non-5xx responses for HTTP, where errors + * originate at the client and the endpoint responded successfully. For gRPC, + * the grpc-status values are those not covered by total_error_requests below. + */ + 'total_successful_requests'?: (number | string | Long); + /** + * The total number of unfinished requests for this endpoint. + */ + 'total_requests_in_progress'?: (number | string | Long); + /** + * The total number of requests that failed due to errors at the endpoint. + * For HTTP these are responses with 5xx status codes and for gRPC the + * grpc-status values: + * + * - DeadlineExceeded + * - Unimplemented + * - Internal + * - Unavailable + * - Unknown + * - DataLoss + */ + 'total_error_requests'?: (number | string | Long); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats'?: (_envoy_api_v2_endpoint_EndpointLoadMetricStats)[]; + /** + * Opaque and implementation dependent metadata of the + * endpoint. Envoy will pass this directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct); + /** + * The total number of requests that were issued to this endpoint + * since the last report. A single TCP connection, HTTP or gRPC + * request or stream is counted as one request. + */ + 'total_issued_requests'?: (number | string | Long); +} + +/** + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 8] + */ +export interface UpstreamEndpointStats__Output { + /** + * Upstream host address. + */ + 'address'?: (_envoy_api_v2_core_Address__Output); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. These include non-5xx responses for HTTP, where errors + * originate at the client and the endpoint responded successfully. For gRPC, + * the grpc-status values are those not covered by total_error_requests below. + */ + 'total_successful_requests': (string); + /** + * The total number of unfinished requests for this endpoint. + */ + 'total_requests_in_progress': (string); + /** + * The total number of requests that failed due to errors at the endpoint. + * For HTTP these are responses with 5xx status codes and for gRPC the + * grpc-status values: + * + * - DeadlineExceeded + * - Unimplemented + * - Internal + * - Unavailable + * - Unknown + * - DataLoss + */ + 'total_error_requests': (string); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats': (_envoy_api_v2_endpoint_EndpointLoadMetricStats__Output)[]; + /** + * Opaque and implementation dependent metadata of the + * endpoint. Envoy will pass this directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct__Output); + /** + * The total number of requests that were issued to this endpoint + * since the last report. A single TCP connection, HTTP or gRPC + * request or stream is counted as one request. + */ + 'total_issued_requests': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts new file mode 100644 index 000000000..946ca76bc --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts @@ -0,0 +1,108 @@ +// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto + +import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; +import { UpstreamEndpointStats as _envoy_api_v2_endpoint_UpstreamEndpointStats, UpstreamEndpointStats__Output as _envoy_api_v2_endpoint_UpstreamEndpointStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamEndpointStats'; +import { Long } from '@grpc/proto-loader'; + +/** + * These are stats Envoy reports to GLB every so often. Report frequency is + * defined by + * :ref:`LoadStatsResponse.load_reporting_interval`. + * Stats per upstream region/zone and optionally per subzone. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 9] + */ +export interface UpstreamLocalityStats { + /** + * Name of zone, region and optionally endpoint group these metrics were + * collected from. Zone and region names could be empty if unknown. + */ + 'locality'?: (_envoy_api_v2_core_Locality); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. + */ + 'total_successful_requests'?: (number | string | Long); + /** + * The total number of unfinished requests + */ + 'total_requests_in_progress'?: (number | string | Long); + /** + * The total number of requests that failed due to errors at the endpoint, + * aggregated over all endpoints in the locality. + */ + 'total_error_requests'?: (number | string | Long); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats'?: (_envoy_api_v2_endpoint_EndpointLoadMetricStats)[]; + /** + * [#not-implemented-hide:] The priority of the endpoint group these metrics + * were collected from. + */ + 'priority'?: (number); + /** + * Endpoint granularity stats information for this locality. This information + * is populated if the Server requests it by setting + * :ref:`LoadStatsResponse.report_endpoint_granularity`. + */ + 'upstream_endpoint_stats'?: (_envoy_api_v2_endpoint_UpstreamEndpointStats)[]; + /** + * The total number of requests that were issued by this Envoy since + * the last report. This information is aggregated over all the + * upstream endpoints in the locality. + */ + 'total_issued_requests'?: (number | string | Long); +} + +/** + * These are stats Envoy reports to GLB every so often. Report frequency is + * defined by + * :ref:`LoadStatsResponse.load_reporting_interval`. + * Stats per upstream region/zone and optionally per subzone. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + * [#next-free-field: 9] + */ +export interface UpstreamLocalityStats__Output { + /** + * Name of zone, region and optionally endpoint group these metrics were + * collected from. Zone and region names could be empty if unknown. + */ + 'locality'?: (_envoy_api_v2_core_Locality__Output); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. + */ + 'total_successful_requests': (string); + /** + * The total number of unfinished requests + */ + 'total_requests_in_progress': (string); + /** + * The total number of requests that failed due to errors at the endpoint, + * aggregated over all endpoints in the locality. + */ + 'total_error_requests': (string); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats': (_envoy_api_v2_endpoint_EndpointLoadMetricStats__Output)[]; + /** + * [#not-implemented-hide:] The priority of the endpoint group these metrics + * were collected from. + */ + 'priority': (number); + /** + * Endpoint granularity stats information for this locality. This information + * is populated if the Server requests it by setting + * :ref:`LoadStatsResponse.report_endpoint_granularity`. + */ + 'upstream_endpoint_stats': (_envoy_api_v2_endpoint_UpstreamEndpointStats__Output)[]; + /** + * The total number of requests that were issued by this Envoy since + * the last report. This information is aggregated over all the + * upstream endpoints in the locality. + */ + 'total_issued_requests': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts new file mode 100644 index 000000000..13d006947 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts @@ -0,0 +1,108 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto + +import * as grpc from '../../../../../index' +import { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; +import { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; + +export interface LoadReportingServiceClient extends grpc.Client { + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + StreamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + StreamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + streamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + streamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; + +} + +export interface LoadReportingServiceHandlers { + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + StreamLoadStats(call: grpc.ServerDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>): void; + +} diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts new file mode 100644 index 000000000..f2c2393cb --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto + +import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../../envoy/api/v2/core/Node'; +import { ClusterStats as _envoy_api_v2_endpoint_ClusterStats, ClusterStats__Output as _envoy_api_v2_endpoint_ClusterStats__Output } from '../../../../envoy/api/v2/endpoint/ClusterStats'; + +/** + * A load report Envoy sends to the management server. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsRequest { + /** + * Node identifier for Envoy instance. + */ + 'node'?: (_envoy_api_v2_core_Node); + /** + * A list of load stats to report. + */ + 'cluster_stats'?: (_envoy_api_v2_endpoint_ClusterStats)[]; +} + +/** + * A load report Envoy sends to the management server. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsRequest__Output { + /** + * Node identifier for Envoy instance. + */ + 'node'?: (_envoy_api_v2_core_Node__Output); + /** + * A list of load stats to report. + */ + 'cluster_stats': (_envoy_api_v2_endpoint_ClusterStats__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts new file mode 100644 index 000000000..9326d869b --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts @@ -0,0 +1,71 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto + +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * The management server sends envoy a LoadStatsResponse with all clusters it + * is interested in learning load stats about. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsResponse { + /** + * Clusters to report stats for. + * Not populated if *send_all_clusters* is true. + */ + 'clusters'?: (string)[]; + /** + * The minimum interval of time to collect stats over. This is only a minimum for two reasons: + * 1. There may be some delay from when the timer fires until stats sampling occurs. + * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic + * that is observed in between the corresponding previous *LoadStatsRequest* and this + * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period + * of inobservability that might otherwise exists between the messages. New clusters are not + * subject to this consideration. + */ + 'load_reporting_interval'?: (_google_protobuf_Duration); + /** + * Set to *true* if the management server supports endpoint granularity + * report. + */ + 'report_endpoint_granularity'?: (boolean); + /** + * If true, the client should send all clusters it knows about. + * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their + * :ref:`client_features` field will honor this field. + */ + 'send_all_clusters'?: (boolean); +} + +/** + * The management server sends envoy a LoadStatsResponse with all clusters it + * is interested in learning load stats about. + * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. + */ +export interface LoadStatsResponse__Output { + /** + * Clusters to report stats for. + * Not populated if *send_all_clusters* is true. + */ + 'clusters': (string)[]; + /** + * The minimum interval of time to collect stats over. This is only a minimum for two reasons: + * 1. There may be some delay from when the timer fires until stats sampling occurs. + * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic + * that is observed in between the corresponding previous *LoadStatsRequest* and this + * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period + * of inobservability that might otherwise exists between the messages. New clusters are not + * subject to this consideration. + */ + 'load_reporting_interval'?: (_google_protobuf_Duration__Output); + /** + * Set to *true* if the management server supports endpoint granularity + * report. + */ + 'report_endpoint_granularity': (boolean); + /** + * If true, the client should send all clusters it knows about. + * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their + * :ref:`client_features` field will honor this field. + */ + 'send_all_clusters': (boolean); +} diff --git a/packages/grpc-js/src/generated/lrs.ts b/packages/grpc-js/src/generated/lrs.ts new file mode 100644 index 000000000..47c5de6df --- /dev/null +++ b/packages/grpc-js/src/generated/lrs.ts @@ -0,0 +1,146 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + api: { + v2: { + core: { + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + Extension: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + } + endpoint: { + ClusterStats: MessageTypeDefinition + EndpointLoadMetricStats: MessageTypeDefinition + UpstreamEndpointStats: MessageTypeDefinition + UpstreamLocalityStats: MessageTypeDefinition + } + } + } + service: { + load_stats: { + v2: { + LoadReportingService: SubtypeConstructor & { service: ServiceDefinition } + LoadStatsRequest: MessageTypeDefinition + LoadStatsResponse: MessageTypeDefinition + } + } + } + type: { + FractionalPercent: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } + } + google: { + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } +} + diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 24b464af6..15fd72876 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -32,10 +32,10 @@ import { PriorityLoadBalancingConfig, } from './load-balancing-config'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { XdsClient, Watcher } from './xds-client'; +import { XdsClient, Watcher, XdsClusterDropStats } from './xds-client'; import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; import { ConnectivityState } from './channel'; -import { UnavailablePicker } from './picker'; +import { UnavailablePicker, Picker, PickResultType } from './picker'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { LocalitySubchannelAddress } from './load-balancer-priority'; import { Status } from './constants'; @@ -83,8 +83,48 @@ export class EdsLoadBalancer implements LoadBalancer { private nextPriorityChildNumber = 0; + private clusterDropStats: XdsClusterDropStats | null = null; + constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddres, subchannelArgs) => + this.channelControlHelper.createSubchannel( + subchannelAddres, + subchannelArgs + ), + requestReresolution: () => + this.channelControlHelper.requestReresolution(), + updateState: (connectivityState, originalPicker) => { + if (this.latestEdsUpdate === null) { + return; + } + const edsPicker: Picker = { + pick: (pickArgs) => { + const dropCategory = this.checkForDrop(); + /* If we drop the call, it ends with an UNAVAILABLE status. + * Otherwise, delegate picking the subchannel to the child + * balancer. */ + if (dropCategory === null) { + return originalPicker.pick(pickArgs); + } else { + this.clusterDropStats?.addCallDropped(dropCategory); + return { + pickResultType: PickResultType.DROP, + status: { + code: Status.UNAVAILABLE, + details: `Call dropped by load balancing policy. Category: ${dropCategory}`, + metadata: new Metadata(), + }, + subchannel: null, + extraFilterFactory: null, + onCallStarted: null, + }; + } + }, + }; + this.channelControlHelper.updateState(connectivityState, edsPicker); + }, + }); this.watcher = { onValidUpdate: (update) => { this.latestEdsUpdate = update; @@ -112,6 +152,44 @@ export class EdsLoadBalancer implements LoadBalancer { }; } + /** + * Check whether a single call should be dropped according to the current + * policy, based on randomly chosen numbers. Returns the drop category if + * the call should be dropped, and null otherwise. + */ + private checkForDrop(): string | null { + if (!this.latestEdsUpdate?.policy) { + return null; + } + /* The drop_overloads policy is a list of pairs of category names and + * probabilities. For each one, if the random number is within that + * probability range, we drop the call citing that category. Otherwise, the + * call proceeds as usual. */ + for (const dropOverload of this.latestEdsUpdate.policy.drop_overloads) { + if (!dropOverload.drop_percentage) { + continue; + } + let randNum: number; + switch (dropOverload.drop_percentage.denominator) { + case 'HUNDRED': + randNum = Math.random() * 100; + break; + case 'TEN_THOUSAND': + randNum = Math.random() * 10_000; + break; + case 'MILLION': + randNum = Math.random() * 1_000_000; + break; + default: + continue; + } + if (randNum < dropOverload.drop_percentage.numerator) { + return dropOverload.category; + } + } + return null; + } + /** * Should be called when this balancer gets a new config and when the * XdsClient returns a new ClusterLoadAssignment. @@ -307,6 +385,11 @@ export class EdsLoadBalancer implements LoadBalancer { this.isWatcherActive = true; } + this.clusterDropStats = this.xdsClient.addClusterDropStats( + lbConfig.eds.cluster, + lbConfig.eds.edsServiceName ?? '' + ); + /* If updateAddressList is called after receiving an update and the update * is still valid, we want to update the child config with the information * in the new EdsLoadBalancingConfig. */ diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 42eeda821..184047b23 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -26,6 +26,7 @@ export enum PickResultType { COMPLETE, QUEUE, TRANSIENT_FAILURE, + DROP, } export interface PickResult { @@ -74,6 +75,14 @@ export interface TransientFailurePickResult extends PickResult { onCallStarted: null; } +export interface DropCallPickResult extends PickResult { + pickResultType: PickResultType.DROP; + subchannel: null; + status: StatusObject; + extraFilterFactory: null; + onCallStarted: null; +} + export interface PickArgs { metadata: Metadata; } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 98bafda37..25bc748b9 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -18,6 +18,7 @@ import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; +import * as lrsTypes from './generated/lrs'; import { createGoogleDefaultCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; import { ClientDuplexStream, ServiceError } from './call'; @@ -34,6 +35,15 @@ import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; +import { LoadReportingServiceClient } from './generated/envoy/service/load_stats/v2/LoadReportingService'; +import { LoadStatsRequest } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; +import { LoadStatsResponse__Output } from './generated/envoy/service/load_stats/v2/LoadStatsResponse'; +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { + ClusterStats, + _envoy_api_v2_endpoint_ClusterStats_DroppedRequests, +} from './generated/envoy/api/v2/endpoint/ClusterStats'; +import { UpstreamLocalityStats } from './generated/envoy/api/v2/endpoint/UpstreamLocalityStats'; const TRACER_NAME = 'xds_client'; @@ -46,9 +56,13 @@ const clientVersion = require('../../package.json').version; const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; -let loadedProtos: Promise | null = null; +let loadedProtos: Promise< + adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType +> | null = null; -function loadAdsProtos(): Promise { +function loadAdsProtos(): Promise< + adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType +> { if (loadedProtos !== null) { return loadedProtos; } @@ -80,7 +94,7 @@ function loadAdsProtos(): Promise { (packageDefinition) => (loadPackageDefinition( packageDefinition - ) as unknown) as adsTypes.ProtoGrpcType + ) as unknown) as adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType ); return loadedProtos; } @@ -91,14 +105,102 @@ export interface Watcher { onResourceDoesNotExist(): void; } +export interface XdsClusterDropStats { + addCallDropped(category: string): void; +} + +interface ClusterLocalityStats { + locality: Locality__Output; + callsStarted: number; + callsSucceeded: number; + callsFailed: number; + callsInProgress: number; +} + +interface ClusterLoadReport { + callsDropped: Map; + localityStats: ClusterLocalityStats[]; + intervalStart: [number, number]; +} + +class ClusterLoadReportMap { + private statsMap: { + clusterName: string; + edsServiceName: string; + stats: ClusterLoadReport; + }[] = []; + + get( + clusterName: string, + edsServiceName: string + ): ClusterLoadReport | undefined { + for (const statsObj of this.statsMap) { + if ( + statsObj.clusterName === clusterName && + statsObj.edsServiceName === edsServiceName + ) { + return statsObj.stats; + } + } + return undefined; + } + + getOrCreate(clusterName: string, edsServiceName: string): ClusterLoadReport { + for (const statsObj of this.statsMap) { + if ( + statsObj.clusterName === clusterName && + statsObj.edsServiceName === edsServiceName + ) { + return statsObj.stats; + } + } + const newStats: ClusterLoadReport = { + callsDropped: new Map(), + localityStats: [], + intervalStart: process.hrtime(), + }; + this.statsMap.push({ + clusterName, + edsServiceName, + stats: newStats, + }); + return newStats; + } + + *entries(): IterableIterator< + [{ clusterName: string; edsServiceName: string }, ClusterLoadReport] + > { + for (const statsEntry of this.statsMap) { + yield [ + { + clusterName: statsEntry.clusterName, + edsServiceName: statsEntry.edsServiceName, + }, + statsEntry.stats, + ]; + } + } +} + export class XdsClient { - private node: Node | null = null; - private client: AggregatedDiscoveryServiceClient | null = null; + private adsNode: Node | null = null; + private adsClient: AggregatedDiscoveryServiceClient | null = null; private adsCall: ClientDuplexStream< DiscoveryRequest, DiscoveryResponse__Output > | null = null; + private lrsNode: Node | null = null; + private lrsClient: LoadReportingServiceClient | null = null; + private lrsCall: ClientDuplexStream< + LoadStatsRequest, + LoadStatsResponse__Output + > | null = null; + private latestLrsSettings: LoadStatsResponse__Output | null = null; + + private clusterStatsMap: ClusterLoadReportMap = new ClusterLoadReportMap(); + private statsTimer: NodeJS.Timer; + private hasShutdown = false; private endpointWatchers: Map< @@ -146,17 +248,32 @@ export class XdsClient { if (this.hasShutdown) { return; } - this.node = { + const node: Node = { ...bootstrapInfo.node, build_version: `gRPC Node Pure JS ${clientVersion}`, user_agent_name: 'gRPC Node Pure JS', }; - this.client = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( + this.adsNode = { + ...node, + client_features: ['envoy.lb.does_not_support_overprovisioning'], + }; + this.lrsNode = { + ...node, + client_features: ['envoy.lrs.supports_send_all_clusters'], + }; + this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), channelArgs ); this.maybeStartAdsStream(); + + this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( + bootstrapInfo.xdsServers[0].serverUri, + createGoogleDefaultCredentials(), + channelArgs + ); + this.maybeStartLrsStream(); }, (error) => { trace('Failed to initialize xDS Client. ' + error.message); @@ -168,6 +285,8 @@ export class XdsClient { }); } ); + this.statsTimer = setInterval(() => {}, 0); + clearInterval(this.statsTimer); } /** @@ -175,7 +294,7 @@ export class XdsClient { * existing stream, and there */ private maybeStartAdsStream() { - if (this.client === null) { + if (this.adsClient === null) { return; } if (this.adsCall !== null) { @@ -184,7 +303,7 @@ export class XdsClient { if (this.hasShutdown) { return; } - this.adsCall = this.client.StreamAggregatedResources(); + this.adsCall = this.adsClient.StreamAggregatedResources(); this.adsCall.on('data', (message: DiscoveryResponse__Output) => { switch (message.type_url) { case EDS_TYPE_URL: { @@ -276,7 +395,7 @@ export class XdsClient { const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); if (endpointWatcherNames.length > 0) { this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: endpointWatcherNames, }); @@ -288,7 +407,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: typeUrl, version_info: versionInfo, response_nonce: nonce, @@ -307,7 +426,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -320,7 +439,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: CDS_TYPE_URL, resource_names: Array.from(this.clusterWatchers.keys()), response_nonce: this.lastCdsNonce, @@ -337,7 +456,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -353,7 +472,7 @@ export class XdsClient { return; } this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: CDS_TYPE_URL, resource_names: Array.from(this.clusterWatchers.keys()), response_nonce: this.lastCdsNonce, @@ -422,7 +541,7 @@ export class XdsClient { private updateEdsNames() { if (this.adsCall) { this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: EDS_TYPE_URL, resource_names: Array.from(this.endpointWatchers.keys()), response_nonce: this.lastEdsNonce, @@ -434,7 +553,7 @@ export class XdsClient { private updateCdsNames() { if (this.adsCall) { this.adsCall.write({ - node: this.node!, + node: this.adsNode!, type_url: CDS_TYPE_URL, resource_names: Array.from(this.clusterWatchers.keys()), response_nonce: this.lastCdsNonce, @@ -455,6 +574,125 @@ export class XdsClient { // Also do the same for other types of watchers when those are implemented } + private maybeStartLrsStream() { + if (!this.lrsClient) { + return; + } + if (this.lrsCall) { + return; + } + if (this.hasShutdown) { + return; + } + + this.lrsCall = this.lrsClient.streamLoadStats(); + this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { + if ( + message.load_reporting_interval?.seconds !== + this.latestLrsSettings?.load_reporting_interval?.seconds || + message.load_reporting_interval?.nanos !== + this.latestLrsSettings?.load_reporting_interval?.nanos + ) { + /* Only reset the timer if the interval has changed or was not set + * before. */ + clearInterval(this.statsTimer); + /* Convert a google.protobuf.Duration to a number of milliseconds for + * use with setInterval. */ + const loadReportingIntervalMs = + Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + + message.load_reporting_interval!.nanos / 1_000_000; + setInterval(() => { + this.sendStats(); + }, loadReportingIntervalMs); + } + this.latestLrsSettings = message; + }); + this.lrsCall.on('error', (error: ServiceError) => { + trace( + 'LRS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.lrsCall = null; + clearInterval(this.statsTimer); + /* Connection backoff is handled by the client object, so we can + * immediately start a new request to indicate that it should try to + * reconnect */ + this.maybeStartAdsStream(); + }); + this.lrsCall.write({ + node: this.lrsNode!, + }); + } + + private sendStats() { + if (!this.lrsCall) { + return; + } + const clusterStats: ClusterStats[] = []; + for (const [ + { clusterName, edsServiceName }, + stats, + ] of this.clusterStatsMap.entries()) { + if ( + this.latestLrsSettings!.send_all_clusters || + this.latestLrsSettings!.clusters.indexOf(clusterName) > 0 + ) { + const upstreamLocalityStats: UpstreamLocalityStats[] = []; + for (const localityStats of stats.localityStats) { + // Skip localities with 0 requests + if ( + localityStats.callsStarted > 0 || + localityStats.callsSucceeded > 0 || + localityStats.callsFailed > 0 + ) { + upstreamLocalityStats.push({ + locality: localityStats.locality, + total_issued_requests: localityStats.callsStarted, + total_successful_requests: localityStats.callsSucceeded, + total_error_requests: localityStats.callsFailed, + total_requests_in_progress: localityStats.callsInProgress, + }); + localityStats.callsStarted = 0; + localityStats.callsSucceeded = 0; + localityStats.callsFailed = 0; + } + } + const droppedRequests: _envoy_api_v2_endpoint_ClusterStats_DroppedRequests[] = []; + let totalDroppedRequests = 0; + for (const [category, count] of stats.callsDropped.entries()) { + if (count > 0) { + droppedRequests.push({ + category, + dropped_count: count, + }); + totalDroppedRequests += count; + } + } + // Clear out dropped call stats after sending them + stats.callsDropped.clear(); + const interval = process.hrtime(stats.intervalStart); + stats.intervalStart = process.hrtime(); + // Skip clusters with 0 requests + if (upstreamLocalityStats.length > 0 || totalDroppedRequests > 0) { + clusterStats.push({ + cluster_name: clusterName, + cluster_service_name: edsServiceName, + dropped_requests: droppedRequests, + total_dropped_requests: totalDroppedRequests, + upstream_locality_stats: upstreamLocalityStats, + load_report_interval: { + seconds: interval[0], + nanos: interval[1], + }, + }); + } + } + } + this.lrsCall.write({ + node: this.lrsNode!, + cluster_stats: clusterStats, + }); + } + addEndpointWatcher( edsServiceName: string, watcher: Watcher @@ -553,9 +791,25 @@ export class XdsClient { } } + addClusterDropStats( + clusterName: string, + edsServiceName: string + ): XdsClusterDropStats { + const clusterStats = this.clusterStatsMap.getOrCreate( + clusterName, + edsServiceName + ); + return { + addCallDropped: (category) => { + const prevCount = clusterStats.callsDropped.get(category) ?? 0; + clusterStats.callsDropped.set(category, prevCount + 1); + }, + }; + } + shutdown(): void { this.adsCall?.cancel(); - this.client?.close(); + this.adsClient?.close(); this.hasShutdown = true; } } From 3c948f5d66abe0a1be00351fdcb922a71e8f9a05 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Jul 2020 09:17:06 -0700 Subject: [PATCH 1182/1899] Fixes from PR comments --- packages/grpc-js/src/load-balancer-eds.ts | 15 +++++++++------ packages/grpc-js/src/xds-client.ts | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 15fd72876..bc8124925 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -87,9 +87,9 @@ export class EdsLoadBalancer implements LoadBalancer { constructor(private readonly channelControlHelper: ChannelControlHelper) { this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddres, subchannelArgs) => + createSubchannel: (subchannelAddress, subchannelArgs) => this.channelControlHelper.createSubchannel( - subchannelAddres, + subchannelAddress, subchannelArgs ), requestReresolution: () => @@ -385,10 +385,13 @@ export class EdsLoadBalancer implements LoadBalancer { this.isWatcherActive = true; } - this.clusterDropStats = this.xdsClient.addClusterDropStats( - lbConfig.eds.cluster, - lbConfig.eds.edsServiceName ?? '' - ); + if (lbConfig.eds.lrsLoadReportingServerName) { + this.clusterDropStats = this.xdsClient.addClusterDropStats( + lbConfig.eds.lrsLoadReportingServerName, + lbConfig.eds.cluster, + lbConfig.eds.edsServiceName ?? '' + ); + } /* If updateAddressList is called after receiving an update and the update * is still valid, we want to update the child config with the information diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 25bc748b9..165e545be 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -791,10 +791,24 @@ export class XdsClient { } } + /** + * + * @param lrsServer The target name of the server to send stats to. An empty + * string indicates that the default LRS client should be used. Currently + * only the empty string is supported here. + * @param clusterName + * @param edsServiceName + */ addClusterDropStats( + lrsServer: string, clusterName: string, edsServiceName: string ): XdsClusterDropStats { + if (lrsServer !== '') { + return { + addCallDropped: category => {} + }; + } const clusterStats = this.clusterStatsMap.getOrCreate( clusterName, edsServiceName @@ -810,6 +824,8 @@ export class XdsClient { shutdown(): void { this.adsCall?.cancel(); this.adsClient?.close(); + this.lrsCall?.cancel(); + this.lrsClient?.close(); this.hasShutdown = true; } } From 669d25404587806c20483efaa46aa787d495876f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Jul 2020 11:40:42 -0700 Subject: [PATCH 1183/1899] grpc-js: Add LrsLoadBalancer class --- packages/grpc-js/src/load-balancer-eds.ts | 33 +++- packages/grpc-js/src/load-balancer-lrs.ts | 169 ++++++++++++++++++ packages/grpc-js/src/load-balancer.ts | 2 + packages/grpc-js/src/load-balancing-config.ts | 24 ++- packages/grpc-js/src/xds-client.ts | 81 ++++++++- 5 files changed, 295 insertions(+), 14 deletions(-) create mode 100644 packages/grpc-js/src/load-balancer-lrs.ts diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index bc8124925..57aac25b3 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -297,16 +297,33 @@ export class EdsLoadBalancer implements LoadBalancer { WeightedTarget >(); for (const localityObj of localityArray) { + /* Use the endpoint picking policy from the config, default to + * round_robin. */ + const endpointPickingPolicy: LoadBalancingConfig[] = [ + ...this.lastestConfig.eds.endpointPickingPolicy, + { name: 'round_robin', round_robin: {} }, + ]; + let childPolicy: LoadBalancingConfig[]; + if (this.lastestConfig.eds.lrsLoadReportingServerName) { + childPolicy = [ + { + name: 'lrs', + lrs: { + cluster_name: this.lastestConfig.eds.cluster, + eds_service_name: this.lastestConfig.eds.edsServiceName ?? '', + lrs_load_reporting_server_name: this.lastestConfig.eds + .lrsLoadReportingServerName, + locality: localityObj.locality, + child_policy: endpointPickingPolicy, + }, + }, + ]; + } else { + childPolicy = endpointPickingPolicy; + } childTargets.set(localityToName(localityObj.locality), { weight: localityObj.weight, - /* TODO(murgatroid99): Insert an lrs config around the round_robin - * config after implementing lrs */ - /* Use the endpoint picking policy from the config, default to - * round_robin. */ - child_policy: [ - ...this.lastestConfig.eds.endpointPickingPolicy, - { name: 'round_robin', round_robin: {} }, - ], + child_policy: childPolicy, }); for (const address of localityObj.addresses) { addressList.push({ diff --git a/packages/grpc-js/src/load-balancer-lrs.ts b/packages/grpc-js/src/load-balancer-lrs.ts new file mode 100644 index 000000000..da09593b0 --- /dev/null +++ b/packages/grpc-js/src/load-balancer-lrs.ts @@ -0,0 +1,169 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { + LoadBalancer, + ChannelControlHelper, + registerLoadBalancerType, + getFirstUsableConfig, +} from './load-balancer'; +import { SubchannelAddress } from './subchannel'; +import { + LoadBalancingConfig, + isLrsLoadBalancingConfig, +} from './load-balancing-config'; +import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { ConnectivityState } from './channel'; +import { Picker, PickArgs, PickResultType, PickResult } from './picker'; +import { XdsClusterLocalityStats, XdsClient } from './xds-client'; +import { Filter, BaseFilter, FilterFactory } from './filter'; +import { StatusObject, Call } from './call-stream'; +import { Status } from './constants'; +import { FilterStackFactory } from './filter-stack'; + +const TYPE_NAME = 'lrs'; + +/** + * Filter class that reports when the call ends. + */ +class CallEndTrackingFilter extends BaseFilter implements Filter { + constructor(private localityStatsReporter: XdsClusterLocalityStats) { + super(); + } + + receiveTrailers(status: StatusObject) { + this.localityStatsReporter.addCallFinished(status.code !== Status.OK); + return status; + } +} + +class CallEndTrackingFilterFactory + implements FilterFactory { + constructor(private localityStatsReporter: XdsClusterLocalityStats) {} + + createFilter(callStream: Call): CallEndTrackingFilter { + return new CallEndTrackingFilter(this.localityStatsReporter); + } +} + +/** + * Picker that delegates picking to another picker, and reports when calls + * created using those picks start and end. + */ +class LoadReportingPicker implements Picker { + constructor( + private wrappedPicker: Picker, + private localityStatsReporter: XdsClusterLocalityStats + ) {} + + pick(pickArgs: PickArgs): PickResult { + const wrappedPick = this.wrappedPicker.pick(pickArgs); + if (wrappedPick.pickResultType === PickResultType.COMPLETE) { + const trackingFilterFactory = new CallEndTrackingFilterFactory( + this.localityStatsReporter + ); + /* In the unlikely event that the wrappedPick already has an + * extraFilterFactory, preserve it in a FilterStackFactory. */ + const extraFilterFactory = wrappedPick.extraFilterFactory + ? new FilterStackFactory([ + wrappedPick.extraFilterFactory, + trackingFilterFactory, + ]) + : trackingFilterFactory; + return { + pickResultType: PickResultType.COMPLETE, + subchannel: wrappedPick.subchannel, + status: null, + onCallStarted: () => { + wrappedPick.onCallStarted?.(); + this.localityStatsReporter.addCallStarted(); + }, + extraFilterFactory: extraFilterFactory, + }; + } else { + return wrappedPick; + } + } +} + +/** + * "Load balancer" that delegates the actual load balancing logic to another + * LoadBalancer class and adds hooks to track when calls started using that + * LoadBalancer start and end, and uses the XdsClient to report that + * information back to the xDS server. + */ +export class LrsLoadBalancer implements LoadBalancer { + private childBalancer: ChildLoadBalancerHandler; + private localityStatsReporter: XdsClusterLocalityStats | null = null; + + constructor(private channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddress, subchannelArgs) => + channelControlHelper.createSubchannel( + subchannelAddress, + subchannelArgs + ), + requestReresolution: () => channelControlHelper.requestReresolution(), + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + if (this.localityStatsReporter !== null) { + picker = new LoadReportingPicker(picker, this.localityStatsReporter); + } + channelControlHelper.updateState(connectivityState, picker); + }, + }); + } + + updateAddressList( + addressList: SubchannelAddress[], + lbConfig: LoadBalancingConfig, + attributes: { [key: string]: unknown } + ): void { + if (!isLrsLoadBalancingConfig(lbConfig)) { + return; + } + if (!(attributes.xdsClient instanceof XdsClient)) { + return; + } + const lrsConfig = lbConfig.lrs; + this.localityStatsReporter = attributes.xdsClient.addClusterLocalityStats( + lrsConfig.lrs_load_reporting_server_name, + lrsConfig.cluster_name, + lrsConfig.eds_service_name, + lrsConfig.locality + ); + const childPolicy: LoadBalancingConfig = getFirstUsableConfig( + lrsConfig.child_policy + ) ?? { name: 'pick_first', pick_first: {} }; + this.childBalancer.updateAddressList(addressList, childPolicy, attributes); + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, LrsLoadBalancer); +} diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 227bbe9cf..56dd06f3b 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -26,6 +26,7 @@ import * as load_balancer_priority from './load-balancer-priority'; import * as load_balancer_weighted_target from './load-balancer-weighted-target'; import * as load_balancer_eds from './load-balancer-eds'; import * as load_balancer_cds from './load-balancer-cds'; +import * as load_balancer_lrs from './load-balancer-lrs'; /** * A collection of functions associated with a channel that a load balancer @@ -145,4 +146,5 @@ export function registerAll() { load_balancer_weighted_target.setup(); load_balancer_eds.setup(); load_balancer_cds.setup(); + load_balancer_lrs.setup(); } diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts index 92c4b2b9c..d4d7792e9 100644 --- a/packages/grpc-js/src/load-balancing-config.ts +++ b/packages/grpc-js/src/load-balancing-config.ts @@ -15,6 +15,8 @@ * */ +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; + /* This file is an implementation of gRFC A24: * https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md. Each * function here takes an object with unknown structure and returns its @@ -79,6 +81,14 @@ export interface CdsLbConfig { cluster: string; } +export interface LrsLbConfig { + cluster_name: string; + eds_service_name: string; + lrs_load_reporting_server_name: string; + locality: Locality__Output; + child_policy: LoadBalancingConfig[]; +} + export interface PickFirstLoadBalancingConfig { name: 'pick_first'; pick_first: PickFirstConfig; @@ -119,6 +129,11 @@ export interface CdsLoadBalancingConfig { cds: CdsLbConfig; } +export interface LrsLoadBalancingConfig { + name: 'lrs'; + lrs: LrsLbConfig; +} + export type LoadBalancingConfig = | PickFirstLoadBalancingConfig | RoundRobinLoadBalancingConfig @@ -127,7 +142,8 @@ export type LoadBalancingConfig = | PriorityLoadBalancingConfig | WeightedTargetLoadBalancingConfig | EdsLoadBalancingConfig - | CdsLoadBalancingConfig; + | CdsLoadBalancingConfig + | LrsLoadBalancingConfig; export function isRoundRobinLoadBalancingConfig( lbconfig: LoadBalancingConfig @@ -171,6 +187,12 @@ export function isCdsLoadBalancingConfig( return lbconfig.name === 'cds'; } +export function isLrsLoadBalancingConfig( + lbconfig: LoadBalancingConfig +): lbconfig is LrsLoadBalancingConfig { + return lbconfig.name === 'lrs'; +} + /* In these functions we assume the input came from a JSON object. Therefore we * expect that the prototype is uninteresting and that `in` can be used * effectively */ diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 165e545be..5460c52b4 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -38,7 +38,10 @@ import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; import { LoadReportingServiceClient } from './generated/envoy/service/load_stats/v2/LoadReportingService'; import { LoadStatsRequest } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; import { LoadStatsResponse__Output } from './generated/envoy/service/load_stats/v2/LoadStatsResponse'; -import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { + Locality__Output, + Locality, +} from './generated/envoy/api/v2/core/Locality'; import { ClusterStats, _envoy_api_v2_endpoint_ClusterStats_DroppedRequests, @@ -99,6 +102,17 @@ function loadAdsProtos(): Promise< return loadedProtos; } +function localityEqual( + loc1: Locality__Output, + loc2: Locality__Output +): boolean { + return ( + loc1.region === loc2.region && + loc1.zone === loc2.zone && + loc1.sub_zone === loc2.sub_zone + ); +} + export interface Watcher { onValidUpdate(update: UpdateType): void; onTransientError(error: StatusObject): void; @@ -109,6 +123,11 @@ export interface XdsClusterDropStats { addCallDropped(category: string): void; } +export interface XdsClusterLocalityStats { + addCallStarted(): void; + addCallFinished(fail: boolean): void; +} + interface ClusterLocalityStats { locality: Locality__Output; callsStarted: number; @@ -792,12 +811,12 @@ export class XdsClient { } /** - * + * * @param lrsServer The target name of the server to send stats to. An empty * string indicates that the default LRS client should be used. Currently * only the empty string is supported here. - * @param clusterName - * @param edsServiceName + * @param clusterName + * @param edsServiceName */ addClusterDropStats( lrsServer: string, @@ -806,7 +825,7 @@ export class XdsClient { ): XdsClusterDropStats { if (lrsServer !== '') { return { - addCallDropped: category => {} + addCallDropped: (category) => {}, }; } const clusterStats = this.clusterStatsMap.getOrCreate( @@ -821,6 +840,58 @@ export class XdsClient { }; } + addClusterLocalityStats( + lrsServer: string, + clusterName: string, + edsServiceName: string, + locality: Locality__Output + ): XdsClusterLocalityStats { + if (lrsServer !== '') { + return { + addCallStarted: () => {}, + addCallFinished: (fail) => {}, + }; + } + const clusterStats = this.clusterStatsMap.getOrCreate( + clusterName, + edsServiceName + ); + let localityStats: ClusterLocalityStats | null = null; + for (const statsObj of clusterStats.localityStats) { + if (localityEqual(locality, statsObj.locality)) { + localityStats = statsObj; + break; + } + } + if (localityStats === null) { + localityStats = { + locality, + callsInProgress: 0, + callsStarted: 0, + callsSucceeded: 0, + callsFailed: 0, + }; + clusterStats.localityStats.push(localityStats); + } + /* Help the compiler understand that this object is always non-null in the + * closure */ + const finalLocalityStats: ClusterLocalityStats = localityStats; + return { + addCallStarted: () => { + finalLocalityStats.callsSucceeded += 1; + finalLocalityStats.callsInProgress += 1; + }, + addCallFinished: (fail) => { + if (fail) { + finalLocalityStats.callsFailed += 1; + } else { + finalLocalityStats.callsSucceeded += 1; + } + finalLocalityStats.callsInProgress -= 1; + }, + }; + } + shutdown(): void { this.adsCall?.cancel(); this.adsClient?.close(); From a3b27be21158daff53dc2a3802969cbf12022903 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Jul 2020 15:43:39 -0700 Subject: [PATCH 1184/1899] Address a couple of comments --- packages/grpc-js/src/xds-client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 5460c52b4..fc2aa17f2 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -865,7 +865,7 @@ export class XdsClient { } if (localityStats === null) { localityStats = { - locality, + locality: locality, callsInProgress: 0, callsStarted: 0, callsSucceeded: 0, @@ -878,7 +878,7 @@ export class XdsClient { const finalLocalityStats: ClusterLocalityStats = localityStats; return { addCallStarted: () => { - finalLocalityStats.callsSucceeded += 1; + finalLocalityStats.callsStarted += 1; finalLocalityStats.callsInProgress += 1; }, addCallFinished: (fail) => { From 9cdd7fc5fc3589a7882b45c38f1eb2abe14dd776 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 Jul 2020 22:59:13 +0000 Subject: [PATCH 1185/1899] build(deps): bump dot-prop in /test/client-libraries-integration Bumps [dot-prop](https://github.com/sindresorhus/dot-prop) from 4.2.0 to 5.2.0. - [Release notes](https://github.com/sindresorhus/dot-prop/releases) - [Commits](https://github.com/sindresorhus/dot-prop/compare/v4.2.0...v5.2.0) Signed-off-by: dependabot[bot] --- test/client-libraries-integration/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/client-libraries-integration/package.json b/test/client-libraries-integration/package.json index 69e024757..784714eeb 100644 --- a/test/client-libraries-integration/package.json +++ b/test/client-libraries-integration/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "", "dependencies": { - "dot-prop": "^4.2.0", + "dot-prop": "^5.2.0", "google-proto-files": "^0.15.1", "mocha": "^5.0.4", "shimmer": "^1.2.0" From 52eb0df1f8bb7e19d534267893dcb218d0acee38 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 31 Jul 2020 12:00:14 -0700 Subject: [PATCH 1186/1899] grpc-js: Add XdsResolver and corresponding XdsClient behavior --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel.ts | 12 +- .../envoy/api/v2/ScopedRouteConfiguration.ts | 204 ++++ .../v2/HttpConnectionManager.ts | 1039 +++++++++++++++++ .../http_connection_manager/v2/HttpFilter.ts | 34 + .../network/http_connection_manager/v2/Rds.ts | 31 + .../v2/RequestIDExtension.ts | 17 + .../http_connection_manager/v2/ScopedRds.ts | 17 + .../v2/ScopedRouteConfigurationsList.ts | 17 + .../v2/ScopedRoutes.ts | 265 +++++ .../envoy/config/trace/v2/Tracing.ts | 114 ++ .../google/protobuf/MethodOptions.ts | 3 - .../src/generated/http_connection_manager.ts | 228 ++++ packages/grpc-js/src/resolver-dns.ts | 7 +- packages/grpc-js/src/resolver-uds.ts | 7 +- packages/grpc-js/src/resolver-xds.ts | 82 ++ packages/grpc-js/src/resolver.ts | 12 +- .../grpc-js/src/resolving-load-balancer.ts | 136 ++- packages/grpc-js/src/server.ts | 2 +- packages/grpc-js/src/xds-client.ts | 401 +++++-- packages/grpc-js/test/test-resolver.ts | 28 +- 21 files changed, 2487 insertions(+), 171 deletions(-) create mode 100644 packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts create mode 100644 packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts create mode 100644 packages/grpc-js/src/generated/http_connection_manager.ts create mode 100644 packages/grpc-js/src/resolver-xds.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4c4e59f06..ee910cfb6 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -48,7 +48,7 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f2ad181ab..49535c19d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -220,20 +220,10 @@ export class ChannelImplementation implements Channel { ); }, }; - // TODO(murgatroid99): check channel arg for default service config - let defaultServiceConfig: ServiceConfig = { - loadBalancingConfig: [], - methodConfig: [], - }; - if (options['grpc.service_config']) { - defaultServiceConfig = validateServiceConfig( - JSON.parse(options['grpc.service_config']!) - ); - } this.resolvingLoadBalancer = new ResolvingLoadBalancer( this.target, channelControlHelper, - defaultServiceConfig + options ); this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts b/packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts new file mode 100644 index 000000000..02810bf02 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts @@ -0,0 +1,204 @@ +// Original file: deps/envoy-api/envoy/api/v2/scoped_route.proto + + +export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment { + /** + * A string to match against. + */ + 'string_key'?: (string); + 'type'?: "string_key"; +} + +export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output { + /** + * A string to match against. + */ + 'string_key'?: (string); + 'type': "string_key"; +} + +/** + * Specifies a key which is matched against the output of the + * :ref:`scope_key_builder` + * specified in the HttpConnectionManager. The matching is done per HTTP + * request and is dependent on the order of the fragments contained in the + * Key. + */ +export interface _envoy_api_v2_ScopedRouteConfiguration_Key { + /** + * The ordered set of fragments to match against. The order must match the + * fragments in the corresponding + * :ref:`scope_key_builder`. + */ + 'fragments'?: (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment)[]; +} + +/** + * Specifies a key which is matched against the output of the + * :ref:`scope_key_builder` + * specified in the HttpConnectionManager. The matching is done per HTTP + * request and is dependent on the order of the fragments contained in the + * Key. + */ +export interface _envoy_api_v2_ScopedRouteConfiguration_Key__Output { + /** + * The ordered set of fragments to match against. The order must match the + * fragments in the corresponding + * :ref:`scope_key_builder`. + */ + 'fragments': (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output)[]; +} + +/** + * Specifies a routing scope, which associates a + * :ref:`Key` to a + * :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). + * + * The HTTP connection manager builds up a table consisting of these Key to + * RouteConfiguration mappings, and looks up the RouteConfiguration to use per + * request according to the algorithm specified in the + * :ref:`scope_key_builder` + * assigned to the HttpConnectionManager. + * + * For example, with the following configurations (in YAML): + * + * HttpConnectionManager config: + * + * .. code:: + * + * ... + * scoped_routes: + * name: foo-scoped-routes + * scope_key_builder: + * fragments: + * - header_value_extractor: + * name: X-Route-Selector + * element_separator: , + * element: + * separator: = + * key: vip + * + * ScopedRouteConfiguration resources (specified statically via + * :ref:`scoped_route_configurations_list` + * or obtained dynamically via SRDS): + * + * .. code:: + * + * (1) + * name: route-scope1 + * route_configuration_name: route-config1 + * key: + * fragments: + * - string_key: 172.10.10.20 + * + * (2) + * name: route-scope2 + * route_configuration_name: route-config2 + * key: + * fragments: + * - string_key: 172.20.20.30 + * + * A request from a client such as: + * + * .. code:: + * + * GET / HTTP/1.1 + * Host: foo.com + * X-Route-Selector: vip=172.10.10.20 + * + * would result in the routing table defined by the `route-config1` + * RouteConfiguration being assigned to the HTTP request/stream. + */ +export interface ScopedRouteConfiguration { + /** + * The name assigned to the routing scope. + */ + 'name'?: (string); + /** + * The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + * with this scope. + */ + 'route_configuration_name'?: (string); + /** + * The key to match against. + */ + 'key'?: (_envoy_api_v2_ScopedRouteConfiguration_Key); +} + +/** + * Specifies a routing scope, which associates a + * :ref:`Key` to a + * :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). + * + * The HTTP connection manager builds up a table consisting of these Key to + * RouteConfiguration mappings, and looks up the RouteConfiguration to use per + * request according to the algorithm specified in the + * :ref:`scope_key_builder` + * assigned to the HttpConnectionManager. + * + * For example, with the following configurations (in YAML): + * + * HttpConnectionManager config: + * + * .. code:: + * + * ... + * scoped_routes: + * name: foo-scoped-routes + * scope_key_builder: + * fragments: + * - header_value_extractor: + * name: X-Route-Selector + * element_separator: , + * element: + * separator: = + * key: vip + * + * ScopedRouteConfiguration resources (specified statically via + * :ref:`scoped_route_configurations_list` + * or obtained dynamically via SRDS): + * + * .. code:: + * + * (1) + * name: route-scope1 + * route_configuration_name: route-config1 + * key: + * fragments: + * - string_key: 172.10.10.20 + * + * (2) + * name: route-scope2 + * route_configuration_name: route-config2 + * key: + * fragments: + * - string_key: 172.20.20.30 + * + * A request from a client such as: + * + * .. code:: + * + * GET / HTTP/1.1 + * Host: foo.com + * X-Route-Selector: vip=172.10.10.20 + * + * would result in the routing table defined by the `route-config1` + * RouteConfiguration being assigned to the HTTP request/stream. + */ +export interface ScopedRouteConfiguration__Output { + /** + * The name assigned to the routing scope. + */ + 'name': (string); + /** + * The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + * with this scope. + */ + 'route_configuration_name': (string); + /** + * The key to match against. + */ + 'key'?: (_envoy_api_v2_ScopedRouteConfiguration_Key__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts new file mode 100644 index 000000000..9aa2b2d25 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts @@ -0,0 +1,1039 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { Rds as _envoy_config_filter_network_http_connection_manager_v2_Rds, Rds__Output as _envoy_config_filter_network_http_connection_manager_v2_Rds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/Rds'; +import { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from '../../../../../../envoy/api/v2/RouteConfiguration'; +import { HttpFilter as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter, HttpFilter__Output as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/HttpFilter'; +import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../../google/protobuf/BoolValue'; +import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http1ProtocolOptions'; +import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http2ProtocolOptions'; +import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../../google/protobuf/Duration'; +import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../../../../envoy/config/filter/accesslog/v2/AccessLog'; +import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; +import { ScopedRoutes as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes, ScopedRoutes__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes'; +import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/HttpProtocolOptions'; +import { RequestIDExtension as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension, RequestIDExtension__Output as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension'; +import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../../../envoy/type/Percent'; +import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../../../envoy/type/tracing/v2/CustomTag'; +import { _envoy_config_trace_v2_Tracing_Http, _envoy_config_trace_v2_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v2/Tracing'; + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType { + /** + * For every new connection, the connection manager will determine which + * codec to use. This mode supports both ALPN for TLS listeners as well as + * protocol inference for plaintext listeners. If ALPN data is available, it + * is preferred, otherwise protocol inference is used. In almost all cases, + * this is the right option to choose for this setting. + */ + AUTO = 0, + /** + * The connection manager will assume that the client is speaking HTTP/1.1. + */ + HTTP1 = 1, + /** + * The connection manager will assume that the client is speaking HTTP/2 + * (Envoy does not require HTTP/2 to take place over TLS or to use ALPN. + * Prior knowledge is allowed). + */ + HTTP2 = 2, + /** + * [#not-implemented-hide:] QUIC implementation is not production ready yet. Use this enum with + * caution to prevent accidental execution of QUIC code. I.e. `!= HTTP2` is no longer sufficient + * to distinguish HTTP1 and HTTP2 traffic. + */ + HTTP3 = 3, +} + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +/** + * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + * header. + */ +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails { + /** + * Do not send the XFCC header to the next hop. This is the default value. + */ + SANITIZE = 0, + /** + * When the client connection is mTLS (Mutual TLS), forward the XFCC header + * in the request. + */ + FORWARD_ONLY = 1, + /** + * When the client connection is mTLS, append the client certificate + * information to the request’s XFCC header and forward it. + */ + APPEND_FORWARD = 2, + /** + * When the client connection is mTLS, reset the XFCC header with the client + * certificate information and send it to the next hop. + */ + SANITIZE_SET = 3, + /** + * Always forward the XFCC header in the request, regardless of whether the + * client connection is mTLS. + */ + ALWAYS_FORWARD_ONLY = 4, +} + +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig { + /** + * Whether unix socket addresses should be considered internal. + */ + 'unix_sockets'?: (boolean); +} + +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig__Output { + /** + * Whether unix socket addresses should be considered internal. + */ + 'unix_sockets': (boolean); +} + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName { + /** + * The HTTP listener is used for ingress/incoming requests. + */ + INGRESS = 0, + /** + * The HTTP listener is used for egress/outgoing requests. + */ + EGRESS = 1, +} + +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation { + /** + * Overwrite any Server header with the contents of server_name. + */ + OVERWRITE = 0, + /** + * If no Server header is present, append Server server_name + * If a Server header is present, pass it through. + */ + APPEND_IF_ABSENT = 1, + /** + * Pass through the value of the server header, and do not append a header + * if none is present. + */ + PASS_THROUGH = 2, +} + +/** + * [#next-free-field: 7] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails { + /** + * Whether to forward the subject of the client cert. Defaults to false. + */ + 'subject'?: (_google_protobuf_BoolValue); + /** + * Whether to forward the entire client cert in URL encoded PEM format. This will appear in the + * XFCC header comma separated from other values with the value Cert="PEM". + * Defaults to false. + */ + 'cert'?: (boolean); + /** + * Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM + * format. This will appear in the XFCC header comma separated from other values with the value + * Chain="PEM". + * Defaults to false. + */ + 'chain'?: (boolean); + /** + * Whether to forward the DNS type Subject Alternative Names of the client cert. + * Defaults to false. + */ + 'dns'?: (boolean); + /** + * Whether to forward the URI type Subject Alternative Name of the client cert. Defaults to + * false. + */ + 'uri'?: (boolean); +} + +/** + * [#next-free-field: 7] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails__Output { + /** + * Whether to forward the subject of the client cert. Defaults to false. + */ + 'subject'?: (_google_protobuf_BoolValue__Output); + /** + * Whether to forward the entire client cert in URL encoded PEM format. This will appear in the + * XFCC header comma separated from other values with the value Cert="PEM". + * Defaults to false. + */ + 'cert': (boolean); + /** + * Whether to forward the entire client cert chain (including the leaf cert) in URL encoded PEM + * format. This will appear in the XFCC header comma separated from other values with the value + * Chain="PEM". + * Defaults to false. + */ + 'chain': (boolean); + /** + * Whether to forward the DNS type Subject Alternative Names of the client cert. + * Defaults to false. + */ + 'dns': (boolean); + /** + * Whether to forward the URI type Subject Alternative Name of the client cert. Defaults to + * false. + */ + 'uri': (boolean); +} + +/** + * [#next-free-field: 10] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing { + /** + * The span name will be derived from this field. If + * :ref:`traffic_direction ` is + * specified on the parent listener, then it is used instead of this field. + * + * .. attention:: + * This field has been deprecated in favor of `traffic_direction`. + */ + 'operation_name'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName); + /** + * A list of header names used to create tags for the active span. The header name is used to + * populate the tag name, and the header value is used to populate the tag value. The tag is + * created if the specified header name is present in the request's headers. + * + * .. attention:: + * This field has been deprecated in favor of :ref:`custom_tags + * `. + */ + 'request_headers_for_tags'?: (string)[]; + /** + * Target percentage of requests managed by this HTTP connection manager that will be force + * traced if the :ref:`x-client-trace-id ` + * header is set. This field is a direct analog for the runtime variable + * 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + * `. + * Default: 100% + */ + 'client_sampling'?: (_envoy_type_Percent); + /** + * Target percentage of requests managed by this HTTP connection manager that will be randomly + * selected for trace generation, if not requested by the client or not forced. This field is + * a direct analog for the runtime variable 'tracing.random_sampling' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'random_sampling'?: (_envoy_type_Percent); + /** + * Target percentage of requests managed by this HTTP connection manager that will be traced + * after all other sampling checks have been applied (client-directed, force tracing, random + * sampling). This field functions as an upper limit on the total configured sampling rate. For + * instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + * of client requests with the appropriate headers to be force traced. This field is a direct + * analog for the runtime variable 'tracing.global_enabled' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'overall_sampling'?: (_envoy_type_Percent); + /** + * Whether to annotate spans with additional data. If true, spans will include logs for stream + * events. + */ + 'verbose'?: (boolean); + /** + * Maximum length of the request path to extract and include in the HttpUrl tag. Used to + * truncate lengthy request paths to meet the needs of a tracing backend. + * Default: 256 + */ + 'max_path_tag_length'?: (_google_protobuf_UInt32Value); + /** + * A list of custom tags with unique tag name to create tags for the active span. + */ + 'custom_tags'?: (_envoy_type_tracing_v2_CustomTag)[]; + /** + * Configuration for an external tracing provider. + * If not specified, no tracing will be performed. + * + * .. attention:: + * Please be aware that *envoy.tracers.opencensus* provider can only be configured once + * in Envoy lifetime. + * Any attempts to reconfigure it or to use different configurations for different HCM filters + * will be rejected. + * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes + * on OpenCensus side. + */ + 'provider'?: (_envoy_config_trace_v2_Tracing_Http); +} + +/** + * [#next-free-field: 10] + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing__Output { + /** + * The span name will be derived from this field. If + * :ref:`traffic_direction ` is + * specified on the parent listener, then it is used instead of this field. + * + * .. attention:: + * This field has been deprecated in favor of `traffic_direction`. + */ + 'operation_name': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName); + /** + * A list of header names used to create tags for the active span. The header name is used to + * populate the tag name, and the header value is used to populate the tag value. The tag is + * created if the specified header name is present in the request's headers. + * + * .. attention:: + * This field has been deprecated in favor of :ref:`custom_tags + * `. + */ + 'request_headers_for_tags': (string)[]; + /** + * Target percentage of requests managed by this HTTP connection manager that will be force + * traced if the :ref:`x-client-trace-id ` + * header is set. This field is a direct analog for the runtime variable + * 'tracing.client_sampling' in the :ref:`HTTP Connection Manager + * `. + * Default: 100% + */ + 'client_sampling'?: (_envoy_type_Percent__Output); + /** + * Target percentage of requests managed by this HTTP connection manager that will be randomly + * selected for trace generation, if not requested by the client or not forced. This field is + * a direct analog for the runtime variable 'tracing.random_sampling' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'random_sampling'?: (_envoy_type_Percent__Output); + /** + * Target percentage of requests managed by this HTTP connection manager that will be traced + * after all other sampling checks have been applied (client-directed, force tracing, random + * sampling). This field functions as an upper limit on the total configured sampling rate. For + * instance, setting client_sampling to 100% but overall_sampling to 1% will result in only 1% + * of client requests with the appropriate headers to be force traced. This field is a direct + * analog for the runtime variable 'tracing.global_enabled' in the + * :ref:`HTTP Connection Manager `. + * Default: 100% + */ + 'overall_sampling'?: (_envoy_type_Percent__Output); + /** + * Whether to annotate spans with additional data. If true, spans will include logs for stream + * events. + */ + 'verbose': (boolean); + /** + * Maximum length of the request path to extract and include in the HttpUrl tag. Used to + * truncate lengthy request paths to meet the needs of a tracing backend. + * Default: 256 + */ + 'max_path_tag_length'?: (_google_protobuf_UInt32Value__Output); + /** + * A list of custom tags with unique tag name to create tags for the active span. + */ + 'custom_tags': (_envoy_type_tracing_v2_CustomTag__Output)[]; + /** + * Configuration for an external tracing provider. + * If not specified, no tracing will be performed. + * + * .. attention:: + * Please be aware that *envoy.tracers.opencensus* provider can only be configured once + * in Envoy lifetime. + * Any attempts to reconfigure it or to use different configurations for different HCM filters + * will be rejected. + * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes + * on OpenCensus side. + */ + 'provider'?: (_envoy_config_trace_v2_Tracing_Http__Output); +} + +/** + * The configuration for HTTP upgrades. + * For each upgrade type desired, an UpgradeConfig must be added. + * + * .. warning:: + * + * The current implementation of upgrade headers does not handle + * multi-valued upgrade headers. Support for multi-valued headers may be + * added in the future if needed. + * + * .. warning:: + * The current implementation of upgrade headers does not work with HTTP/2 + * upstreams. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig { + /** + * The case-insensitive name of this upgrade, e.g. "websocket". + * For each upgrade type present in upgrade_configs, requests with + * Upgrade: [upgrade_type] + * will be proxied upstream. + */ + 'upgrade_type'?: (string); + /** + * If present, this represents the filter chain which will be created for + * this type of upgrade. If no filters are present, the filter chain for + * HTTP connections will be used for this upgrade type. + */ + 'filters'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter)[]; + /** + * Determines if upgrades are enabled or disabled by default. Defaults to true. + * This can be overridden on a per-route basis with :ref:`cluster + * ` as documented in the + * :ref:`upgrade documentation `. + */ + 'enabled'?: (_google_protobuf_BoolValue); +} + +/** + * The configuration for HTTP upgrades. + * For each upgrade type desired, an UpgradeConfig must be added. + * + * .. warning:: + * + * The current implementation of upgrade headers does not handle + * multi-valued upgrade headers. Support for multi-valued headers may be + * added in the future if needed. + * + * .. warning:: + * The current implementation of upgrade headers does not work with HTTP/2 + * upstreams. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig__Output { + /** + * The case-insensitive name of this upgrade, e.g. "websocket". + * For each upgrade type present in upgrade_configs, requests with + * Upgrade: [upgrade_type] + * will be proxied upstream. + */ + 'upgrade_type': (string); + /** + * If present, this represents the filter chain which will be created for + * this type of upgrade. If no filters are present, the filter chain for + * HTTP connections will be used for this upgrade type. + */ + 'filters': (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output)[]; + /** + * Determines if upgrades are enabled or disabled by default. Defaults to true. + * This can be overridden on a per-route basis with :ref:`cluster + * ` as documented in the + * :ref:`upgrade documentation `. + */ + 'enabled'?: (_google_protobuf_BoolValue__Output); +} + +/** + * [#next-free-field: 37] + */ +export interface HttpConnectionManager { + /** + * Supplies the type of codec that the connection manager should use. + */ + 'codec_type'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType); + /** + * The human readable prefix to use when emitting statistics for the + * connection manager. See the :ref:`statistics documentation ` for + * more information. + */ + 'stat_prefix'?: (string); + /** + * The connection manager’s route table will be dynamically loaded via the RDS API. + */ + 'rds'?: (_envoy_config_filter_network_http_connection_manager_v2_Rds); + /** + * The route table for the connection manager is static and is specified in this property. + */ + 'route_config'?: (_envoy_api_v2_RouteConfiguration); + /** + * A list of individual HTTP filters that make up the filter chain for + * requests made to the connection manager. :ref:`Order matters ` + * as the filters are processed sequentially as request events happen. + */ + 'http_filters'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter)[]; + /** + * Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` + * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked + * documentation for more information. Defaults to false. + */ + 'add_user_agent'?: (_google_protobuf_BoolValue); + /** + * Presence of the object defines whether the connection manager + * emits :ref:`tracing ` data to the :ref:`configured tracing provider + * `. + */ + 'tracing'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing); + /** + * Additional HTTP/1 settings that are passed to the HTTP/1 codec. + */ + 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); + /** + * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. + */ + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); + /** + * An optional override that the connection manager will write to the server + * header in responses. If not set, the default is *envoy*. + */ + 'server_name'?: (string); + /** + * The idle timeout for connections managed by the connection manager. The + * idle timeout is defined as the period in which there are no active + * requests. If not set, there is no idle timeout. When the idle timeout is + * reached the connection will be closed. If the connection is an HTTP/2 + * connection a drain sequence will occur prior to closing the connection. + * This field is deprecated. Use :ref:`idle_timeout + * ` + * instead. + */ + 'idle_timeout'?: (_google_protobuf_Duration); + /** + * The time that Envoy will wait between sending an HTTP/2 “shutdown + * notification†(GOAWAY frame with max stream ID) and a final GOAWAY frame. + * This is used so that Envoy provides a grace period for new streams that + * race with the final GOAWAY frame. During this grace period, Envoy will + * continue to accept new streams. After the grace period, a final GOAWAY + * frame is sent and Envoy will start refusing new streams. Draining occurs + * both when a connection hits the idle timeout or during general server + * draining. The default grace period is 5000 milliseconds (5 seconds) if this + * option is not specified. + */ + 'drain_timeout'?: (_google_protobuf_Duration); + /** + * Configuration for :ref:`HTTP access logs ` + * emitted by the connection manager. + */ + 'access_log'?: (_envoy_config_filter_accesslog_v2_AccessLog)[]; + /** + * If set to true, the connection manager will use the real remote address + * of the client connection when determining internal versus external origin and manipulating + * various headers. If set to false or absent, the connection manager will use the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for`, + * :ref:`config_http_conn_man_headers_x-envoy-internal`, and + * :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. + */ + 'use_remote_address'?: (_google_protobuf_BoolValue); + /** + * Whether the connection manager will generate the :ref:`x-request-id + * ` header if it does not exist. This defaults to + * true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature + * is not desired it can be disabled. + */ + 'generate_request_id'?: (_google_protobuf_BoolValue); + /** + * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + * header. + */ + 'forward_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails); + /** + * This field is valid only when :ref:`forward_client_cert_details + * ` + * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in + * the client certificate to be forwarded. Note that in the + * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and + * *By* is always set when the client certificate presents the URI type Subject Alternative Name + * value. + */ + 'set_current_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails); + /** + * If proxy_100_continue is true, Envoy will proxy incoming "Expect: + * 100-continue" headers upstream, and forward "100 Continue" responses + * downstream. If this is false or not set, Envoy will instead strip the + * "Expect: 100-continue" header, and send a "100 Continue" response itself. + */ + 'proxy_100_continue'?: (boolean); + /** + * The number of additional ingress proxy hops from the right side of the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header to trust when + * determining the origin client's IP address. The default is zero if this option + * is not specified. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for` for more information. + */ + 'xff_num_trusted_hops'?: (number); + /** + * If + * :ref:`use_remote_address + * ` + * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is + * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. + * This is useful for testing compatibility of upstream services that parse the header value. For + * example, 50.0.0.1 is represented as ::FFFF:50.0.0.1. See `IPv4-Mapped IPv6 Addresses + * `_ for details. This will also affect the + * :ref:`config_http_conn_man_headers_x-envoy-external-address` header. See + * :ref:`http_connection_manager.represent_ipv4_remote_address_as_ipv4_mapped_ipv6 + * ` for runtime + * control. + * [#not-implemented-hide:] + */ + 'represent_ipv4_remote_address_as_ipv4_mapped_ipv6'?: (boolean); + /** + * If set, Envoy will not append the remote address to the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in + * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager + * has mutated the request headers. While :ref:`use_remote_address + * ` + * will also suppress XFF addition, it has consequences for logging and other + * Envoy uses of the remote address, so *skip_xff_append* should be used + * when only an elision of XFF addition is intended. + */ + 'skip_xff_append'?: (boolean); + /** + * Via header value to append to request and response headers. If this is + * empty, no via header will be appended. + */ + 'via'?: (string); + 'upgrade_configs'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig)[]; + /** + * The stream idle timeout for connections managed by the connection manager. + * If not specified, this defaults to 5 minutes. The default value was selected + * so as not to interfere with any smaller configured timeouts that may have + * existed in configurations prior to the introduction of this feature, while + * introducing robustness to TCP connections that terminate without a FIN. + * + * This idle timeout applies to new streams and is overridable by the + * :ref:`route-level idle_timeout + * `. Even on a stream in + * which the override applies, prior to receipt of the initial request + * headers, the :ref:`stream_idle_timeout + * ` + * applies. Each time an encode/decode event for headers or data is processed + * for the stream, the timer will be reset. If the timeout fires, the stream + * is terminated with a 408 Request Timeout error code if no upstream response + * header has been received, otherwise a stream reset occurs. + * + * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due + * to the granularity of events presented to the connection manager. For example, while receiving + * very large request headers, it may be the case that there is traffic regularly arriving on the + * wire while the connection manage is only able to observe the end-of-headers event, hence the + * stream may still idle timeout. + * + * A value of 0 will completely disable the connection manager stream idle + * timeout, although per-route idle timeout overrides will continue to apply. + */ + 'stream_idle_timeout'?: (_google_protobuf_Duration); + /** + * Configures what network addresses are considered internal for stats and header sanitation + * purposes. If unspecified, only RFC1918 IP addresses will be considered internal. + * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more + * information about internal/external addresses. + */ + 'internal_address_config'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig); + /** + * The delayed close timeout is for downstream connections managed by the HTTP connection manager. + * It is defined as a grace period after connection close processing has been locally initiated + * during which Envoy will wait for the peer to close (i.e., a TCP FIN/RST is received by Envoy + * from the downstream connection) prior to Envoy closing the socket associated with that + * connection. + * NOTE: This timeout is enforced even when the socket associated with the downstream connection + * is pending a flush of the write buffer. However, any progress made writing data to the socket + * will restart the timer associated with this timeout. This means that the total grace period for + * a socket in this state will be + * +. + * + * Delaying Envoy's connection close and giving the peer the opportunity to initiate the close + * sequence mitigates a race condition that exists when downstream clients do not drain/process + * data in a connection's receive buffer after a remote close has been detected via a socket + * write(). This race leads to such clients failing to process the response code sent by Envoy, + * which could result in erroneous downstream processing. + * + * If the timeout triggers, Envoy will close the connection's socket. + * + * The default timeout is 1000 ms if this option is not specified. + * + * .. NOTE:: + * To be useful in avoiding the race condition described above, this timeout must be set + * to *at least* +<100ms to account for + * a reasonable "worst" case processing time for a full iteration of Envoy's event loop>. + * + * .. WARNING:: + * A value of 0 will completely disable delayed close processing. When disabled, the downstream + * connection's socket will be closed immediately after the write flush is completed or will + * never close if the write flush does not complete. + */ + 'delayed_close_timeout'?: (_google_protobuf_Duration); + /** + * The amount of time that Envoy will wait for the entire request to be received. + * The timer is activated when the request is initiated, and is disarmed when the last byte of the + * request is sent upstream (i.e. all decoding filters have processed the request), OR when the + * response is initiated. If not specified or set to 0, this timeout is disabled. + */ + 'request_timeout'?: (_google_protobuf_Duration); + /** + * The maximum request headers size for incoming connections. + * If unconfigured, the default max request headers allowed is 60 KiB. + * Requests that exceed this limit will receive a 431 response. + * The max configurable limit is 96 KiB, based on current implementation + * constraints. + */ + 'max_request_headers_kb'?: (_google_protobuf_UInt32Value); + /** + * Should paths be normalized according to RFC 3986 before any processing of + * requests by HTTP filters or routing? This affects the upstream *:path* header + * as well. For paths that fail this check, Envoy will respond with 400 to + * paths that are malformed. This defaults to false currently but will default + * true in the future. When not specified, this value may be overridden by the + * runtime variable + * :ref:`http_connection_manager.normalize_path`. + * See `Normalization and Comparison ` + * for details of normalization. + * Note that Envoy does not perform + * `case normalization ` + */ + 'normalize_path'?: (_google_protobuf_BoolValue); + /** + * A route table will be dynamically assigned to each request based on request attributes + * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are + * specified in this message. + */ + 'scoped_routes'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes); + /** + * Whether the connection manager will keep the :ref:`x-request-id + * ` header if passed for a request that is edge + * (Edge request is the request from external clients to front Envoy) and not reset it, which + * is the current Envoy behaviour. This defaults to false. + */ + 'preserve_external_request_id'?: (boolean); + /** + * Determines if adjacent slashes in the path are merged into one before any processing of + * requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without + * setting this option, incoming requests with path `//dir///file` will not match against route + * with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of + * `HTTP spec ` and is provided for convenience. + */ + 'merge_slashes'?: (boolean); + /** + * Defines the action to be applied to the Server header on the response path. + * By default, Envoy will overwrite the header with the value specified in + * server_name. + */ + 'server_header_transformation'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation); + /** + * Additional settings for HTTP requests handled by the connection manager. These will be + * applicable to both HTTP1 and HTTP2 requests. + */ + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); + /** + * The configuration of the request ID extension. This includes operations such as + * generation, validation, and associated tracing operations. + * + * If not set, Envoy uses the default UUID-based behavior: + * + * 1. Request ID is propagated using *x-request-id* header. + * + * 2. Request ID is a universally unique identifier (UUID). + * + * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. + */ + 'request_id_extension'?: (_envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension); + 'route_specifier'?: "rds"|"route_config"|"scoped_routes"; +} + +/** + * [#next-free-field: 37] + */ +export interface HttpConnectionManager__Output { + /** + * Supplies the type of codec that the connection manager should use. + */ + 'codec_type': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType); + /** + * The human readable prefix to use when emitting statistics for the + * connection manager. See the :ref:`statistics documentation ` for + * more information. + */ + 'stat_prefix': (string); + /** + * The connection manager’s route table will be dynamically loaded via the RDS API. + */ + 'rds'?: (_envoy_config_filter_network_http_connection_manager_v2_Rds__Output); + /** + * The route table for the connection manager is static and is specified in this property. + */ + 'route_config'?: (_envoy_api_v2_RouteConfiguration__Output); + /** + * A list of individual HTTP filters that make up the filter chain for + * requests made to the connection manager. :ref:`Order matters ` + * as the filters are processed sequentially as request events happen. + */ + 'http_filters': (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output)[]; + /** + * Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` + * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked + * documentation for more information. Defaults to false. + */ + 'add_user_agent'?: (_google_protobuf_BoolValue__Output); + /** + * Presence of the object defines whether the connection manager + * emits :ref:`tracing ` data to the :ref:`configured tracing provider + * `. + */ + 'tracing'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing__Output); + /** + * Additional HTTP/1 settings that are passed to the HTTP/1 codec. + */ + 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions__Output); + /** + * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. + */ + 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); + /** + * An optional override that the connection manager will write to the server + * header in responses. If not set, the default is *envoy*. + */ + 'server_name': (string); + /** + * The idle timeout for connections managed by the connection manager. The + * idle timeout is defined as the period in which there are no active + * requests. If not set, there is no idle timeout. When the idle timeout is + * reached the connection will be closed. If the connection is an HTTP/2 + * connection a drain sequence will occur prior to closing the connection. + * This field is deprecated. Use :ref:`idle_timeout + * ` + * instead. + */ + 'idle_timeout'?: (_google_protobuf_Duration__Output); + /** + * The time that Envoy will wait between sending an HTTP/2 “shutdown + * notification†(GOAWAY frame with max stream ID) and a final GOAWAY frame. + * This is used so that Envoy provides a grace period for new streams that + * race with the final GOAWAY frame. During this grace period, Envoy will + * continue to accept new streams. After the grace period, a final GOAWAY + * frame is sent and Envoy will start refusing new streams. Draining occurs + * both when a connection hits the idle timeout or during general server + * draining. The default grace period is 5000 milliseconds (5 seconds) if this + * option is not specified. + */ + 'drain_timeout'?: (_google_protobuf_Duration__Output); + /** + * Configuration for :ref:`HTTP access logs ` + * emitted by the connection manager. + */ + 'access_log': (_envoy_config_filter_accesslog_v2_AccessLog__Output)[]; + /** + * If set to true, the connection manager will use the real remote address + * of the client connection when determining internal versus external origin and manipulating + * various headers. If set to false or absent, the connection manager will use the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for`, + * :ref:`config_http_conn_man_headers_x-envoy-internal`, and + * :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. + */ + 'use_remote_address'?: (_google_protobuf_BoolValue__Output); + /** + * Whether the connection manager will generate the :ref:`x-request-id + * ` header if it does not exist. This defaults to + * true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature + * is not desired it can be disabled. + */ + 'generate_request_id'?: (_google_protobuf_BoolValue__Output); + /** + * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP + * header. + */ + 'forward_client_cert_details': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails); + /** + * This field is valid only when :ref:`forward_client_cert_details + * ` + * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in + * the client certificate to be forwarded. Note that in the + * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and + * *By* is always set when the client certificate presents the URI type Subject Alternative Name + * value. + */ + 'set_current_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails__Output); + /** + * If proxy_100_continue is true, Envoy will proxy incoming "Expect: + * 100-continue" headers upstream, and forward "100 Continue" responses + * downstream. If this is false or not set, Envoy will instead strip the + * "Expect: 100-continue" header, and send a "100 Continue" response itself. + */ + 'proxy_100_continue': (boolean); + /** + * The number of additional ingress proxy hops from the right side of the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header to trust when + * determining the origin client's IP address. The default is zero if this option + * is not specified. See the documentation for + * :ref:`config_http_conn_man_headers_x-forwarded-for` for more information. + */ + 'xff_num_trusted_hops': (number); + /** + * If + * :ref:`use_remote_address + * ` + * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is + * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. + * This is useful for testing compatibility of upstream services that parse the header value. For + * example, 50.0.0.1 is represented as ::FFFF:50.0.0.1. See `IPv4-Mapped IPv6 Addresses + * `_ for details. This will also affect the + * :ref:`config_http_conn_man_headers_x-envoy-external-address` header. See + * :ref:`http_connection_manager.represent_ipv4_remote_address_as_ipv4_mapped_ipv6 + * ` for runtime + * control. + * [#not-implemented-hide:] + */ + 'represent_ipv4_remote_address_as_ipv4_mapped_ipv6': (boolean); + /** + * If set, Envoy will not append the remote address to the + * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in + * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager + * has mutated the request headers. While :ref:`use_remote_address + * ` + * will also suppress XFF addition, it has consequences for logging and other + * Envoy uses of the remote address, so *skip_xff_append* should be used + * when only an elision of XFF addition is intended. + */ + 'skip_xff_append': (boolean); + /** + * Via header value to append to request and response headers. If this is + * empty, no via header will be appended. + */ + 'via': (string); + 'upgrade_configs': (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig__Output)[]; + /** + * The stream idle timeout for connections managed by the connection manager. + * If not specified, this defaults to 5 minutes. The default value was selected + * so as not to interfere with any smaller configured timeouts that may have + * existed in configurations prior to the introduction of this feature, while + * introducing robustness to TCP connections that terminate without a FIN. + * + * This idle timeout applies to new streams and is overridable by the + * :ref:`route-level idle_timeout + * `. Even on a stream in + * which the override applies, prior to receipt of the initial request + * headers, the :ref:`stream_idle_timeout + * ` + * applies. Each time an encode/decode event for headers or data is processed + * for the stream, the timer will be reset. If the timeout fires, the stream + * is terminated with a 408 Request Timeout error code if no upstream response + * header has been received, otherwise a stream reset occurs. + * + * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due + * to the granularity of events presented to the connection manager. For example, while receiving + * very large request headers, it may be the case that there is traffic regularly arriving on the + * wire while the connection manage is only able to observe the end-of-headers event, hence the + * stream may still idle timeout. + * + * A value of 0 will completely disable the connection manager stream idle + * timeout, although per-route idle timeout overrides will continue to apply. + */ + 'stream_idle_timeout'?: (_google_protobuf_Duration__Output); + /** + * Configures what network addresses are considered internal for stats and header sanitation + * purposes. If unspecified, only RFC1918 IP addresses will be considered internal. + * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more + * information about internal/external addresses. + */ + 'internal_address_config'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig__Output); + /** + * The delayed close timeout is for downstream connections managed by the HTTP connection manager. + * It is defined as a grace period after connection close processing has been locally initiated + * during which Envoy will wait for the peer to close (i.e., a TCP FIN/RST is received by Envoy + * from the downstream connection) prior to Envoy closing the socket associated with that + * connection. + * NOTE: This timeout is enforced even when the socket associated with the downstream connection + * is pending a flush of the write buffer. However, any progress made writing data to the socket + * will restart the timer associated with this timeout. This means that the total grace period for + * a socket in this state will be + * +. + * + * Delaying Envoy's connection close and giving the peer the opportunity to initiate the close + * sequence mitigates a race condition that exists when downstream clients do not drain/process + * data in a connection's receive buffer after a remote close has been detected via a socket + * write(). This race leads to such clients failing to process the response code sent by Envoy, + * which could result in erroneous downstream processing. + * + * If the timeout triggers, Envoy will close the connection's socket. + * + * The default timeout is 1000 ms if this option is not specified. + * + * .. NOTE:: + * To be useful in avoiding the race condition described above, this timeout must be set + * to *at least* +<100ms to account for + * a reasonable "worst" case processing time for a full iteration of Envoy's event loop>. + * + * .. WARNING:: + * A value of 0 will completely disable delayed close processing. When disabled, the downstream + * connection's socket will be closed immediately after the write flush is completed or will + * never close if the write flush does not complete. + */ + 'delayed_close_timeout'?: (_google_protobuf_Duration__Output); + /** + * The amount of time that Envoy will wait for the entire request to be received. + * The timer is activated when the request is initiated, and is disarmed when the last byte of the + * request is sent upstream (i.e. all decoding filters have processed the request), OR when the + * response is initiated. If not specified or set to 0, this timeout is disabled. + */ + 'request_timeout'?: (_google_protobuf_Duration__Output); + /** + * The maximum request headers size for incoming connections. + * If unconfigured, the default max request headers allowed is 60 KiB. + * Requests that exceed this limit will receive a 431 response. + * The max configurable limit is 96 KiB, based on current implementation + * constraints. + */ + 'max_request_headers_kb'?: (_google_protobuf_UInt32Value__Output); + /** + * Should paths be normalized according to RFC 3986 before any processing of + * requests by HTTP filters or routing? This affects the upstream *:path* header + * as well. For paths that fail this check, Envoy will respond with 400 to + * paths that are malformed. This defaults to false currently but will default + * true in the future. When not specified, this value may be overridden by the + * runtime variable + * :ref:`http_connection_manager.normalize_path`. + * See `Normalization and Comparison ` + * for details of normalization. + * Note that Envoy does not perform + * `case normalization ` + */ + 'normalize_path'?: (_google_protobuf_BoolValue__Output); + /** + * A route table will be dynamically assigned to each request based on request attributes + * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are + * specified in this message. + */ + 'scoped_routes'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output); + /** + * Whether the connection manager will keep the :ref:`x-request-id + * ` header if passed for a request that is edge + * (Edge request is the request from external clients to front Envoy) and not reset it, which + * is the current Envoy behaviour. This defaults to false. + */ + 'preserve_external_request_id': (boolean); + /** + * Determines if adjacent slashes in the path are merged into one before any processing of + * requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without + * setting this option, incoming requests with path `//dir///file` will not match against route + * with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of + * `HTTP spec ` and is provided for convenience. + */ + 'merge_slashes': (boolean); + /** + * Defines the action to be applied to the Server header on the response path. + * By default, Envoy will overwrite the header with the value specified in + * server_name. + */ + 'server_header_transformation': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation); + /** + * Additional settings for HTTP requests handled by the connection manager. These will be + * applicable to both HTTP1 and HTTP2 requests. + */ + 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions__Output); + /** + * The configuration of the request ID extension. This includes operations such as + * generation, validation, and associated tracing operations. + * + * If not set, Envoy uses the default UUID-based behavior: + * + * 1. Request ID is propagated using *x-request-id* header. + * + * 2. Request ID is a universally unique identifier (UUID). + * + * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. + */ + 'request_id_extension'?: (_envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output); + 'route_specifier': "rds"|"route_config"|"scoped_routes"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts new file mode 100644 index 000000000..cf68dd989 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; + +export interface HttpFilter { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + /** + * Filter specific configuration which depends on the filter being instantiated. See the supported + * filters for further documentation. + */ + 'config_type'?: "config"|"typed_config"; +} + +export interface HttpFilter__Output { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Filter specific configuration which depends on the filter being instantiated. See the supported + * filters for further documentation. + */ + 'config_type': "config"|"typed_config"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts new file mode 100644 index 000000000..306cc0ddb --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts @@ -0,0 +1,31 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; + +export interface Rds { + /** + * Configuration source specifier for RDS. + */ + 'config_source'?: (_envoy_api_v2_core_ConfigSource); + /** + * The name of the route configuration. This name will be passed to the RDS + * API. This allows an Envoy configuration with multiple HTTP listeners (and + * associated HTTP connection manager filters) to use different route + * configurations. + */ + 'route_config_name'?: (string); +} + +export interface Rds__Output { + /** + * Configuration source specifier for RDS. + */ + 'config_source'?: (_envoy_api_v2_core_ConfigSource__Output); + /** + * The name of the route configuration. This name will be passed to the RDS + * API. This allows an Envoy configuration with multiple HTTP listeners (and + * associated HTTP connection manager filters) to use different route + * configurations. + */ + 'route_config_name': (string); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts new file mode 100644 index 000000000..4688b09cd --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; + +export interface RequestIDExtension { + /** + * Request ID extension specific configuration. + */ + 'typed_config'?: (_google_protobuf_Any); +} + +export interface RequestIDExtension__Output { + /** + * Request ID extension specific configuration. + */ + 'typed_config'?: (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts new file mode 100644 index 000000000..989aee155 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; + +export interface ScopedRds { + /** + * Configuration source specifier for scoped RDS. + */ + 'scoped_rds_config_source'?: (_envoy_api_v2_core_ConfigSource); +} + +export interface ScopedRds__Output { + /** + * Configuration source specifier for scoped RDS. + */ + 'scoped_rds_config_source'?: (_envoy_api_v2_core_ConfigSource__Output); +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts new file mode 100644 index 000000000..81de7333e --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ScopedRouteConfiguration as _envoy_api_v2_ScopedRouteConfiguration, ScopedRouteConfiguration__Output as _envoy_api_v2_ScopedRouteConfiguration__Output } from '../../../../../../envoy/api/v2/ScopedRouteConfiguration'; + +/** + * This message is used to work around the limitations with 'oneof' and repeated fields. + */ +export interface ScopedRouteConfigurationsList { + 'scoped_route_configurations'?: (_envoy_api_v2_ScopedRouteConfiguration)[]; +} + +/** + * This message is used to work around the limitations with 'oneof' and repeated fields. + */ +export interface ScopedRouteConfigurationsList__Output { + 'scoped_route_configurations': (_envoy_api_v2_ScopedRouteConfiguration__Output)[]; +} diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts new file mode 100644 index 000000000..1409cb899 --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts @@ -0,0 +1,265 @@ +// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto + +import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; +import { ScopedRouteConfigurationsList as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList, ScopedRouteConfigurationsList__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList'; +import { ScopedRds as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds, ScopedRds__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRds'; + +/** + * Specifies the mechanism for constructing key fragments which are composed into scope keys. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder { + /** + * Specifies how a header field's value should be extracted. + */ + 'header_value_extractor'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor); + 'type'?: "header_value_extractor"; +} + +/** + * Specifies the mechanism for constructing key fragments which are composed into scope keys. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output { + /** + * Specifies how a header field's value should be extracted. + */ + 'header_value_extractor'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output); + 'type': "header_value_extractor"; +} + +/** + * Specifies how the value of a header should be extracted. + * The following example maps the structure of a header to the fields in this message. + * + * .. code:: + * + * <0> <1> <-- index + * X-Header: a=b;c=d + * | || | + * | || \----> + * | || + * | |\----> + * | | + * | \----> + * | + * \----> + * + * Each 'a=b' key-value pair constitutes an 'element' of the header field. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor { + /** + * The name of the header field to extract the value from. + */ + 'name'?: (string); + /** + * The element separator (e.g., ';' separates 'a;b;c;d'). + * Default: empty string. This causes the entirety of the header field to be extracted. + * If this field is set to an empty string and 'index' is used in the oneof below, 'index' + * must be set to 0. + */ + 'element_separator'?: (string); + /** + * Specifies the zero based index of the element to extract. + * Note Envoy concatenates multiple values of the same header key into a comma separated + * string, the splitting always happens after the concatenation. + */ + 'index'?: (number); + /** + * Specifies the key value pair to extract the value from. + */ + 'element'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement); + 'extract_type'?: "index"|"element"; +} + +/** + * Specifies how the value of a header should be extracted. + * The following example maps the structure of a header to the fields in this message. + * + * .. code:: + * + * <0> <1> <-- index + * X-Header: a=b;c=d + * | || | + * | || \----> + * | || + * | |\----> + * | | + * | \----> + * | + * \----> + * + * Each 'a=b' key-value pair constitutes an 'element' of the header field. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output { + /** + * The name of the header field to extract the value from. + */ + 'name': (string); + /** + * The element separator (e.g., ';' separates 'a;b;c;d'). + * Default: empty string. This causes the entirety of the header field to be extracted. + * If this field is set to an empty string and 'index' is used in the oneof below, 'index' + * must be set to 0. + */ + 'element_separator': (string); + /** + * Specifies the zero based index of the element to extract. + * Note Envoy concatenates multiple values of the same header key into a comma separated + * string, the splitting always happens after the concatenation. + */ + 'index'?: (number); + /** + * Specifies the key value pair to extract the value from. + */ + 'element'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output); + 'extract_type': "index"|"element"; +} + +/** + * Specifies a header field's key value pair to match on. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement { + /** + * The separator between key and value (e.g., '=' separates 'k=v;...'). + * If an element is an empty string, the element is ignored. + * If an element contains no separator, the whole element is parsed as key and the + * fragment value is an empty string. + * If there are multiple values for a matched key, the first value is returned. + */ + 'separator'?: (string); + /** + * The key to match on. + */ + 'key'?: (string); +} + +/** + * Specifies a header field's key value pair to match on. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output { + /** + * The separator between key and value (e.g., '=' separates 'k=v;...'). + * If an element is an empty string, the element is ignored. + * If an element contains no separator, the whole element is parsed as key and the + * fragment value is an empty string. + * If there are multiple values for a matched key, the first value is returned. + */ + 'separator': (string); + /** + * The key to match on. + */ + 'key': (string); +} + +/** + * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` + * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via + * :ref:`scoped_route_configurations_list`. + * + * Upon receiving a request's headers, the Router will build a key using the algorithm specified + * by this message. This key will be used to look up the routing table (i.e., the + * :ref:`RouteConfiguration`) to use for the request. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder { + /** + * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the + * fragments of a :ref:`ScopedRouteConfiguration`. + * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. + */ + 'fragments'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder)[]; +} + +/** + * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` + * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via + * :ref:`scoped_route_configurations_list`. + * + * Upon receiving a request's headers, the Router will build a key using the algorithm specified + * by this message. This key will be used to look up the routing table (i.e., the + * :ref:`RouteConfiguration`) to use for the request. + */ +export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder__Output { + /** + * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the + * fragments of a :ref:`ScopedRouteConfiguration`. + * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. + */ + 'fragments': (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output)[]; +} + +/** + * [#next-free-field: 6] + */ +export interface ScopedRoutes { + /** + * The name assigned to the scoped routing configuration. + */ + 'name'?: (string); + /** + * The algorithm to use for constructing a scope key for each request. + */ + 'scope_key_builder'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder); + /** + * Configuration source specifier for RDS. + * This config source is used to subscribe to RouteConfiguration resources specified in + * ScopedRouteConfiguration messages. + */ + 'rds_config_source'?: (_envoy_api_v2_core_ConfigSource); + /** + * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by + * matching a key constructed from the request's attributes according to the algorithm specified + * by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_route_configurations_list'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList); + /** + * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS + * API. A scope is assigned to a request by matching a key constructed from the request's + * attributes according to the algorithm specified by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds); + 'config_specifier'?: "scoped_route_configurations_list"|"scoped_rds"; +} + +/** + * [#next-free-field: 6] + */ +export interface ScopedRoutes__Output { + /** + * The name assigned to the scoped routing configuration. + */ + 'name': (string); + /** + * The algorithm to use for constructing a scope key for each request. + */ + 'scope_key_builder'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder__Output); + /** + * Configuration source specifier for RDS. + * This config source is used to subscribe to RouteConfiguration resources specified in + * ScopedRouteConfiguration messages. + */ + 'rds_config_source'?: (_envoy_api_v2_core_ConfigSource__Output); + /** + * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by + * matching a key constructed from the request's attributes according to the algorithm specified + * by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_route_configurations_list'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output); + /** + * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS + * API. A scope is assigned to a request by matching a key constructed from the request's + * attributes according to the algorithm specified by the + * :ref:`ScopeKeyBuilder` + * in this message. + */ + 'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output); + 'config_specifier': "scoped_route_configurations_list"|"scoped_rds"; +} diff --git a/packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts b/packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts new file mode 100644 index 000000000..b7ee1c3ad --- /dev/null +++ b/packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts @@ -0,0 +1,114 @@ +// Original file: deps/envoy-api/envoy/config/trace/v2/http_tracer.proto + +import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * Configuration for an HTTP tracer provider used by Envoy. + * + * The configuration is defined by the + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` + * field. + */ +export interface _envoy_config_trace_v2_Tracing_Http { + /** + * The name of the HTTP trace driver to instantiate. The name must match a + * supported HTTP trace driver. Built-in trace drivers: + * + * - *envoy.tracers.lightstep* + * - *envoy.tracers.zipkin* + * - *envoy.tracers.dynamic_ot* + * - *envoy.tracers.datadog* + * - *envoy.tracers.opencensus* + * - *envoy.tracers.xray* + */ + 'name'?: (string); + 'config'?: (_google_protobuf_Struct); + 'typed_config'?: (_google_protobuf_Any); + /** + * Trace driver specific configuration which depends on the driver being instantiated. + * See the trace drivers for examples: + * + * - :ref:`LightstepConfig ` + * - :ref:`ZipkinConfig ` + * - :ref:`DynamicOtConfig ` + * - :ref:`DatadogConfig ` + * - :ref:`OpenCensusConfig ` + * - :ref:`AWS X-Ray ` + */ + 'config_type'?: "config"|"typed_config"; +} + +/** + * Configuration for an HTTP tracer provider used by Envoy. + * + * The configuration is defined by the + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` + * field. + */ +export interface _envoy_config_trace_v2_Tracing_Http__Output { + /** + * The name of the HTTP trace driver to instantiate. The name must match a + * supported HTTP trace driver. Built-in trace drivers: + * + * - *envoy.tracers.lightstep* + * - *envoy.tracers.zipkin* + * - *envoy.tracers.dynamic_ot* + * - *envoy.tracers.datadog* + * - *envoy.tracers.opencensus* + * - *envoy.tracers.xray* + */ + 'name': (string); + 'config'?: (_google_protobuf_Struct__Output); + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Trace driver specific configuration which depends on the driver being instantiated. + * See the trace drivers for examples: + * + * - :ref:`LightstepConfig ` + * - :ref:`ZipkinConfig ` + * - :ref:`DynamicOtConfig ` + * - :ref:`DatadogConfig ` + * - :ref:`OpenCensusConfig ` + * - :ref:`AWS X-Ray ` + */ + 'config_type': "config"|"typed_config"; +} + +/** + * The tracing configuration specifies settings for an HTTP tracer provider used by Envoy. + * + * Envoy may support other tracers in the future, but right now the HTTP tracer is the only one + * supported. + * + * .. attention:: + * + * Use of this message type has been deprecated in favor of direct use of + * :ref:`Tracing.Http `. + */ +export interface Tracing { + /** + * Provides configuration for the HTTP tracer. + */ + 'http'?: (_envoy_config_trace_v2_Tracing_Http); +} + +/** + * The tracing configuration specifies settings for an HTTP tracer provider used by Envoy. + * + * Envoy may support other tracers in the future, but right now the HTTP tracer is the only one + * supported. + * + * .. attention:: + * + * Use of this message type has been deprecated in favor of direct use of + * :ref:`Tracing.Http `. + */ +export interface Tracing__Output { + /** + * Provides configuration for the HTTP tracer. + */ + 'http'?: (_envoy_config_trace_v2_Tracing_Http__Output); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts index a5edbd8bb..982c7d5dc 100644 --- a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts @@ -1,16 +1,13 @@ // Original file: null import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface MethodOptions { 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.google.api.http'?: (_google_api_HttpRule); } export interface MethodOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.google.api.http'?: (_google_api_HttpRule__Output); } diff --git a/packages/grpc-js/src/generated/http_connection_manager.ts b/packages/grpc-js/src/generated/http_connection_manager.ts new file mode 100644 index 000000000..37fe303bb --- /dev/null +++ b/packages/grpc-js/src/generated/http_connection_manager.ts @@ -0,0 +1,228 @@ +import * as grpc from '../index'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +} + +export interface ProtoGrpcType { + envoy: { + annotations: { + } + api: { + v2: { + RouteConfiguration: MessageTypeDefinition + ScopedRouteConfiguration: MessageTypeDefinition + Vhds: MessageTypeDefinition + core: { + Address: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + Extension: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TcpProtocolOptions: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition + } + route: { + CorsPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + } + } + } + config: { + filter: { + accesslog: { + v2: { + AccessLog: MessageTypeDefinition + AccessLogFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition + ComparisonFilter: MessageTypeDefinition + DurationFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition + NotHealthCheckFilter: MessageTypeDefinition + OrFilter: MessageTypeDefinition + ResponseFlagFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition + } + } + network: { + http_connection_manager: { + v2: { + HttpConnectionManager: MessageTypeDefinition + HttpFilter: MessageTypeDefinition + Rds: MessageTypeDefinition + RequestIDExtension: MessageTypeDefinition + ScopedRds: MessageTypeDefinition + ScopedRouteConfigurationsList: MessageTypeDefinition + ScopedRoutes: MessageTypeDefinition + } + } + } + } + trace: { + v2: { + Tracing: MessageTypeDefinition + } + } + } + type: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + matcher: { + ListStringMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } + metadata: { + v2: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + tracing: { + v2: { + CustomTag: MessageTypeDefinition + } + } + } + } + google: { + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } +} + diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 74e43ca0f..2db8a5e41 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -31,6 +31,7 @@ import { LogVerbosity } from './constants'; import { SubchannelAddress, TcpSubchannelAddress } from './subchannel'; import { GrpcUri, uriToString, splitHostPort } from './uri-parser'; import { isIPv6, isIPv4 } from 'net'; +import { ChannelOptions } from './channel-options'; const TRACER_NAME = 'dns_resolver'; @@ -84,7 +85,11 @@ class DnsResolver implements Resolver { private latestServiceConfigError: StatusObject | null = null; private percentage: number; private defaultResolutionError: StatusObject; - constructor(private target: GrpcUri, private listener: ResolverListener) { + constructor( + private target: GrpcUri, + private listener: ResolverListener, + channelOptions: ChannelOptions + ) { trace('Resolver constructed for target ' + uriToString(target)); const hostPort = splitHostPort(target.path); if (hostPort === null) { diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 258569138..14bc0176a 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -17,10 +17,15 @@ import { Resolver, ResolverListener, registerResolver } from './resolver'; import { SubchannelAddress } from './subchannel'; import { GrpcUri } from './uri-parser'; +import { ChannelOptions } from './channel-options'; class UdsResolver implements Resolver { private addresses: SubchannelAddress[] = []; - constructor(target: GrpcUri, private listener: ResolverListener) { + constructor( + target: GrpcUri, + private listener: ResolverListener, + channelOptions: ChannelOptions + ) { let path: string; if (target.authority === '') { path = '/' + target.path; diff --git a/packages/grpc-js/src/resolver-xds.ts b/packages/grpc-js/src/resolver-xds.ts new file mode 100644 index 000000000..e92fddffd --- /dev/null +++ b/packages/grpc-js/src/resolver-xds.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Resolver, ResolverListener, registerResolver } from './resolver'; +import { GrpcUri, uriToString } from './uri-parser'; +import { XdsClient } from './xds-client'; +import { ServiceConfig } from './service-config'; +import { StatusObject } from './call-stream'; +import { Status } from './constants'; +import { Metadata } from './metadata'; +import { ChannelOptions } from './channel-options'; + +class XdsResolver implements Resolver { + private resolutionStarted = false; + private hasReportedSuccess = false; + + constructor( + private target: GrpcUri, + private listener: ResolverListener, + private channelOptions: ChannelOptions + ) {} + + private reportResolutionError() { + this.listener.onError({ + code: Status.UNAVAILABLE, + details: `xDS name resolution failed for target ${uriToString( + this.target + )}`, + metadata: new Metadata(), + }); + } + + updateResolution(): void { + // Wait until updateResolution is called once to start the xDS requests + if (!this.resolutionStarted) { + this.resolutionStarted = true; + const xdsClient = new XdsClient( + this.target.path, + { + onValidUpdate: (update: ServiceConfig) => { + this.hasReportedSuccess = true; + this.listener.onSuccessfulResolution([], update, null, { + xdsClient: xdsClient, + }); + }, + onTransientError: (error: StatusObject) => { + /* A transient error only needs to bubble up as a failure if we have + * not already provided a ServiceConfig for the upper layer to use */ + if (!this.hasReportedSuccess) { + this.reportResolutionError(); + } + }, + onResourceDoesNotExist: () => { + this.reportResolutionError(); + }, + }, + this.channelOptions + ); + } + } + + static getDefaultAuthority(target: GrpcUri) { + return target.path; + } +} + +export function setup() { + registerResolver('xds', XdsResolver); +} diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 16c843517..57c750aea 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -21,6 +21,7 @@ import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; +import { ChannelOptions } from './channel-options'; /** * A listener object passed to the resolver's constructor that provides name @@ -64,7 +65,11 @@ export interface Resolver { } export interface ResolverConstructor { - new (target: GrpcUri, listener: ResolverListener): Resolver; + new ( + target: GrpcUri, + listener: ResolverListener, + channelOptions: ChannelOptions + ): Resolver; /** * Get the default authority for a target. This loosely corresponds to that * target's hostname. Throws an error if this resolver class cannot parse the @@ -108,10 +113,11 @@ export function registerDefaultScheme(scheme: string) { */ export function createResolver( target: GrpcUri, - listener: ResolverListener + listener: ResolverListener, + options: ChannelOptions ): Resolver { if (target.scheme !== undefined && target.scheme in registeredResolvers) { - return new registeredResolvers[target.scheme](target, listener); + return new registeredResolvers[target.scheme](target, listener, options); } else { throw new Error( `No resolver could be created for target ${uriToString(target)}` diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index b467a767c..452d3c28d 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -20,7 +20,7 @@ import { LoadBalancer, getFirstUsableConfig, } from './load-balancer'; -import { ServiceConfig } from './service-config'; +import { ServiceConfig, validateServiceConfig } from './service-config'; import { ConnectivityState } from './channel'; import { createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; @@ -35,6 +35,7 @@ import { LogVerbosity } from './constants'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { ChannelOptions } from './channel-options'; const TRACER_NAME = 'resolving_load_balancer'; @@ -57,6 +58,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { * This resolving load balancer's current connectivity state. */ private currentState: ConnectivityState = ConnectivityState.IDLE; + private readonly defaultServiceConfig: ServiceConfig; /** * The service config object from the last successful resolution, if * available. A value of null indicates that we have not yet received a valid @@ -90,8 +92,18 @@ export class ResolvingLoadBalancer implements LoadBalancer { constructor( private readonly target: GrpcUri, private readonly channelControlHelper: ChannelControlHelper, - private readonly defaultServiceConfig: ServiceConfig | null + private readonly channelOptions: ChannelOptions ) { + if (channelOptions['grpc.service_config']) { + this.defaultServiceConfig = validateServiceConfig( + JSON.parse(channelOptions['grpc.service_config']!) + ); + } else { + this.defaultServiceConfig = { + loadBalancingConfig: [], + methodConfig: [], + }; + } this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); this.childLoadBalancer = new ChildLoadBalancerHandler({ createSubchannel: channelControlHelper.createSubchannel.bind( @@ -114,68 +126,72 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.updateState(newState, picker); }, }); - this.innerResolver = createResolver(target, { - onSuccessfulResolution: ( - addressList: SubchannelAddress[], - serviceConfig: ServiceConfig | null, - serviceConfigError: ServiceError | null, - attributes: { [key: string]: unknown } - ) => { - let workingServiceConfig: ServiceConfig | null = null; - /* This first group of conditionals implements the algorithm described - * in https://github.com/grpc/proposal/blob/master/A21-service-config-error-handling.md - * in the section called "Behavior on receiving a new gRPC Config". - */ - if (serviceConfig === null) { - // Step 4 and 5 - if (serviceConfigError === null) { - // Step 5 - this.previousServiceConfig = null; - workingServiceConfig = this.defaultServiceConfig; - } else { - // Step 4 - if (this.previousServiceConfig === null) { - // Step 4.ii - this.handleResolutionFailure(serviceConfigError); + this.innerResolver = createResolver( + target, + { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: ServiceError | null, + attributes: { [key: string]: unknown } + ) => { + let workingServiceConfig: ServiceConfig | null = null; + /* This first group of conditionals implements the algorithm described + * in https://github.com/grpc/proposal/blob/master/A21-service-config-error-handling.md + * in the section called "Behavior on receiving a new gRPC Config". + */ + if (serviceConfig === null) { + // Step 4 and 5 + if (serviceConfigError === null) { + // Step 5 + this.previousServiceConfig = null; + workingServiceConfig = this.defaultServiceConfig; } else { - // Step 4.i - workingServiceConfig = this.previousServiceConfig; + // Step 4 + if (this.previousServiceConfig === null) { + // Step 4.ii + this.handleResolutionFailure(serviceConfigError); + } else { + // Step 4.i + workingServiceConfig = this.previousServiceConfig; + } } + } else { + // Step 3 + workingServiceConfig = serviceConfig; + this.previousServiceConfig = serviceConfig; } - } else { - // Step 3 - workingServiceConfig = serviceConfig; - this.previousServiceConfig = serviceConfig; - } - const workingConfigList = - workingServiceConfig?.loadBalancingConfig ?? []; - if (workingConfigList.length === 0) { - workingConfigList.push({ - name: 'pick_first', - pick_first: {}, - }); - } - const loadBalancingConfig = getFirstUsableConfig(workingConfigList); - if (loadBalancingConfig === null) { - // There were load balancing configs but none are supported. This counts as a resolution failure - this.handleResolutionFailure({ - code: Status.UNAVAILABLE, - details: - 'All load balancer options in service config are not compatible', - metadata: new Metadata(), - }); - return; - } - this.childLoadBalancer.updateAddressList( - addressList, - loadBalancingConfig, - attributes - ); - }, - onError: (error: StatusObject) => { - this.handleResolutionFailure(error); + const workingConfigList = + workingServiceConfig?.loadBalancingConfig ?? []; + if (workingConfigList.length === 0) { + workingConfigList.push({ + name: 'pick_first', + pick_first: {}, + }); + } + const loadBalancingConfig = getFirstUsableConfig(workingConfigList); + if (loadBalancingConfig === null) { + // There were load balancing configs but none are supported. This counts as a resolution failure + this.handleResolutionFailure({ + code: Status.UNAVAILABLE, + details: + 'All load balancer options in service config are not compatible', + metadata: new Metadata(), + }); + return; + } + this.childLoadBalancer.updateAddressList( + addressList, + loadBalancingConfig, + attributes + ); + }, + onError: (error: StatusObject) => { + this.handleResolutionFailure(error); + }, }, - }); + channelOptions + ); this.backoffTimeout = new BackoffTimeout(() => { if (this.continueResolving) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ebd4504d7..683198c59 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -415,7 +415,7 @@ export class Server { }, }; - const resolver = createResolver(portUri, resolverListener); + const resolver = createResolver(portUri, resolverListener, this.options); resolver.updateResolution(); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index fc2aa17f2..cce798246 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -47,6 +47,9 @@ import { _envoy_api_v2_endpoint_ClusterStats_DroppedRequests, } from './generated/envoy/api/v2/endpoint/ClusterStats'; import { UpstreamLocalityStats } from './generated/envoy/api/v2/endpoint/UpstreamLocalityStats'; +import { Listener__Output } from './generated/envoy/api/v2/Listener'; +import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; +import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; const TRACER_NAME = 'xds_client'; @@ -58,6 +61,11 @@ const clientVersion = require('../../package.json').version; const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; +const LDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Listener'; +const RDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; + +const HTTP_CONNECTION_MANGER_TYPE_URL = + 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; let loadedProtos: Promise< adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType @@ -73,10 +81,12 @@ function loadAdsProtos(): Promise< .load( [ 'envoy/service/discovery/v2/ads.proto', + 'envoy/service/load_stats/v2/lrs.proto', 'envoy/api/v2/listener.proto', 'envoy/api/v2/route.proto', 'envoy/api/v2/cluster.proto', 'envoy/api/v2/endpoint.proto', + 'envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto', ], { keepCase: true, @@ -238,6 +248,15 @@ export class XdsClient { private lastCdsNonce = ''; private latestCdsResponses: Cluster__Output[] = []; + private lastLdsVersionInfo = ''; + private lastLdsNonce = ''; + private latestLdsResponse: Listener__Output | null = null; + + private routeConfigName: string | null = null; + private lastRdsVersionInfo = ''; + private lastRdsNonce = ''; + private latestRdsResponse: RouteConfiguration__Output | null = null; + constructor( private targetName: string, private serviceConfigWatcher: Watcher, @@ -308,97 +327,171 @@ export class XdsClient { clearInterval(this.statsTimer); } - /** - * Start the ADS stream if the client exists and there is not already an - * existing stream, and there - */ - private maybeStartAdsStream() { - if (this.adsClient === null) { - return; - } - if (this.adsCall !== null) { - return; - } - if (this.hasShutdown) { - return; - } - this.adsCall = this.adsClient.StreamAggregatedResources(); - this.adsCall.on('data', (message: DiscoveryResponse__Output) => { - switch (message.type_url) { - case EDS_TYPE_URL: { - const edsResponses: ClusterLoadAssignment__Output[] = []; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === EDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - ClusterLoadAssignment__Output; - if (!this.validateEdsResponse(resp)) { - this.nackEds('ClusterLoadAssignment validation failed'); - return; - } - edsResponses.push(resp); - } else { - this.nackEds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); + private handleAdsResponse(message: DiscoveryResponse__Output) { + switch (message.type_url) { + case EDS_TYPE_URL: { + const edsResponses: ClusterLoadAssignment__Output[] = []; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === EDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & + ClusterLoadAssignment__Output; + if (!this.validateEdsResponse(resp)) { + this.nackEds('ClusterLoadAssignment validation failed'); + return; + } + edsResponses.push(resp); + } else { + this.nackEds( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); + return; + } + } + for (const message of edsResponses) { + this.handleEdsResponse(message); + } + this.lastEdsVersionInfo = message.version_info; + this.lastEdsNonce = message.nonce; + this.latestEdsResponses = edsResponses; + this.ackEds(); + break; + } + case CDS_TYPE_URL: { + const cdsResponses: Cluster__Output[] = []; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === CDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & Cluster__Output; + if (!this.validateCdsResponse(resp)) { + this.nackCds('Cluster validation failed'); return; } + } else { + this.nackCds( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); + return; } - for (const message of edsResponses) { - this.handleEdsResponse(message); + } + for (const message of cdsResponses) { + this.handleCdsResponse(message); + } + this.lastCdsVersionInfo = message.version_info; + this.lastCdsNonce = message.nonce; + this.latestCdsResponses = cdsResponses; + this.ackCds(); + break; + } + case LDS_TYPE_URL: { + let nackError: string | null = null; + for (const resource of message.resources) { + if ( + protoLoader.isAnyExtension(resource) && + resource['@type'] === LDS_TYPE_URL + ) { + const resp = resource as protoLoader.AnyExtension & + Listener__Output; + if (resp.name === this.targetName) { + if (this.validateLdsResponse(resp)) { + this.handleLdsResponse(resp); + this.lastLdsVersionInfo = message.version_info; + this.lastLdsNonce = message.nonce; + this.latestLdsResponse = resp; + } else { + nackError = 'Listener validation failed'; + } + break; + } + } else { + nackError = `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }`; + break; } - this.lastEdsVersionInfo = message.version_info; - this.lastEdsNonce = message.nonce; - this.latestEdsResponses = edsResponses; - this.ackEds(); - break; } - case CDS_TYPE_URL: { - const cdsResponses: Cluster__Output[] = []; + if (nackError) { + this.nackLds(nackError); + } else { + this.ackLds(); + } + break; + } + case RDS_TYPE_URL: { + let nackError: string | null = null; + if (this.routeConfigName === null) { + nackError = 'Unexpected RouteConfiguration response'; + } else { for (const resource of message.resources) { if ( protoLoader.isAnyExtension(resource) && - resource['@type'] === CDS_TYPE_URL + resource['@type'] === LDS_TYPE_URL ) { const resp = resource as protoLoader.AnyExtension & - Cluster__Output; - if (!this.validateCdsResponse(resp)) { - this.nackCds('Cluster validation failed'); - return; + RouteConfiguration__Output; + if (resp.name === this.routeConfigName) { + if (this.validateRdsResponse(resp)) { + this.handleRdsResponse(resp); + this.lastRdsVersionInfo = message.version_info; + this.lastRdsNonce = message.nonce; + this.latestRdsResponse = resp; + } else { + nackError = 'RouteConfiguration validation failed'; + } } } else { - this.nackEds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); - return; + nackError = `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }`; + break; } } - for (const message of cdsResponses) { - this.handleCdsResponse(message); - } - this.lastCdsVersionInfo = message.version_info; - this.lastCdsNonce = message.nonce; - this.latestCdsResponses = cdsResponses; - this.ackCds(); - break; } - default: - this.nackUnknown( - message.type_url, - message.version_info, - message.nonce - ); + if (nackError) { + this.nackRds(nackError); + } else { + this.ackRds(); + } + break; } + default: + this.nackUnknown(message.type_url, message.version_info, message.nonce); + } + } + + /** + * Start the ADS stream if the client exists and there is not already an + * existing stream, and there + */ + private maybeStartAdsStream() { + if (this.adsClient === null) { + return; + } + if (this.adsCall !== null) { + return; + } + if (this.hasShutdown) { + return; + } + this.adsCall = this.adsClient.StreamAggregatedResources(); + this.adsCall.on('data', (message: DiscoveryResponse__Output) => { + this.handleAdsResponse(message); }); this.adsCall.on('error', (error: ServiceError) => { trace( @@ -411,6 +504,30 @@ export class XdsClient { * reconnect */ this.maybeStartAdsStream(); }); + + this.adsCall.write({ + node: this.adsNode!, + type_url: LDS_TYPE_URL, + resource_names: [this.targetName], + }); + + if (this.routeConfigName) { + this.adsCall.write({ + node: this.adsNode!, + type_url: RDS_TYPE_URL, + resource_names: [this.routeConfigName], + }); + } + + const clusterNames = Array.from(this.clusterWatchers.keys()); + if (clusterNames.length > 0) { + this.adsCall.write({ + node: this.adsNode!, + type_url: CDS_TYPE_URL, + resource_names: clusterNames, + }); + } + const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); if (endpointWatcherNames.length > 0) { this.adsCall.write({ @@ -466,6 +583,26 @@ export class XdsClient { }); } + private ackLds() { + this.adsCall?.write({ + node: this.adsNode!, + type_url: LDS_TYPE_URL, + resource_names: [this.targetName], + response_nonce: this.lastLdsNonce, + version_info: this.lastLdsVersionInfo, + }); + } + + private ackRds() { + this.adsCall?.write({ + node: this.adsNode!, + type_url: RDS_TYPE_URL, + resource_names: [this.routeConfigName!], + response_nonce: this.lastRdsNonce, + version_info: this.lastRdsVersionInfo, + }); + } + /** * Reject an EDS update. This should be called without updating the local * nonce and version info. @@ -502,6 +639,32 @@ export class XdsClient { }); } + private nackLds(message: string) { + this.adsCall?.write({ + node: this.adsNode!, + type_url: LDS_TYPE_URL, + resource_names: [this.targetName], + response_nonce: this.lastLdsNonce, + version_info: this.lastLdsVersionInfo, + error_detail: { + message, + }, + }); + } + + private nackRds(message: string) { + this.adsCall?.write({ + node: this.adsNode!, + type_url: RDS_TYPE_URL, + resource_names: this.routeConfigName ? [this.routeConfigName] : [], + response_nonce: this.lastRdsNonce, + version_info: this.lastRdsVersionInfo, + error_detail: { + message, + }, + }); + } + /** * Validate the ClusterLoadAssignment object by these rules: * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto @@ -543,6 +706,36 @@ export class XdsClient { return true; } + private validateLdsResponse(message: Listener__Output): boolean { + if ( + !( + message.api_listener?.api_listener && + protoLoader.isAnyExtension(message.api_listener.api_listener) && + message.api_listener?.api_listener['@type'] === + HTTP_CONNECTION_MANGER_TYPE_URL + ) + ) { + return false; + } + const httpConnectionManager = message.api_listener + ?.api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + if (!httpConnectionManager.rds?.config_source?.ads) { + return false; + } + break; + case 'route_config': + return this.validateRdsResponse(httpConnectionManager.route_config!); + } + return false; + } + + private validateRdsResponse(message: RouteConfiguration__Output): boolean { + return true; + } + private handleEdsResponse(message: ClusterLoadAssignment__Output) { const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { @@ -557,6 +750,52 @@ export class XdsClient { } } + private handleLdsResponse(message: Listener__Output) { + // The validation step ensures that this is correct + const httpConnectionManager = message.api_listener! + .api_listener as protoLoader.AnyExtension & HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + this.routeConfigName = httpConnectionManager.rds!.route_config_name; + this.updateRdsNames(); + break; + case 'route_config': + this.handleRdsResponse(httpConnectionManager.route_config!); + if (this.routeConfigName) { + this.routeConfigName = null; + this.updateRdsNames(); + } + break; + default: + // The validation rules should prevent this + } + } + + private handleRdsResponse(message: RouteConfiguration__Output) { + for (const virtualHost of message.virtual_hosts) { + if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + this.serviceConfigWatcher.onValidUpdate({ + methodConfig: [], + loadBalancingConfig: [ + { + name: 'cds', + cds: { + cluster: route.route.cluster, + }, + }, + ], + }); + break; + } + } + } + /* If none of the routes match the one we are looking for, bubble up an + * error. */ + this.serviceConfigWatcher.onResourceDoesNotExist(); + } + private updateEdsNames() { if (this.adsCall) { this.adsCall.write({ @@ -581,16 +820,26 @@ export class XdsClient { } } + private updateRdsNames() { + this.adsCall?.write({ + node: this.adsNode!, + type_url: CDS_TYPE_URL, + resource_names: this.routeConfigName ? [this.routeConfigName] : [], + response_nonce: this.lastRdsNonce, + version_info: this.lastRdsVersionInfo, + }); + } + private reportStreamError(status: StatusObject) { for (const watcherList of [ ...this.endpointWatchers.values(), ...this.clusterWatchers.values(), + [this.serviceConfigWatcher], ]) { for (const watcher of watcherList) { watcher.onTransientError(status); } } - // Also do the same for other types of watchers when those are implemented } private maybeStartLrsStream() { diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index d2a85fc47..42ca64d4d 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -63,7 +63,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should default to port 443', done => { @@ -98,7 +98,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should correctly represent an ipv4 address', done => { @@ -125,7 +125,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should correctly represent an ipv6 address', done => { @@ -152,7 +152,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should correctly represent a bracketed ipv6 address', done => { @@ -179,7 +179,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a public address', done => { @@ -199,7 +199,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a name with multiple dots', done => { @@ -226,7 +226,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); /* TODO(murgatroid99): re-enable this test, once we can get the IPv6 result @@ -255,7 +255,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { @@ -284,7 +284,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve a name with a hyphen', done => { @@ -306,7 +306,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should resolve gRPC interop servers', done => { @@ -331,9 +331,9 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver1 = resolverManager.createResolver(target1, listener); + const resolver1 = resolverManager.createResolver(target1, listener, {}); resolver1.updateResolution(); - const resolver2 = resolverManager.createResolver(target2, listener); + const resolver2 = resolverManager.createResolver(target2, listener, {}); resolver2.updateResolution(); }); }); @@ -359,7 +359,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); it('Should handle an absolute Unix Domain Socket name', done => { @@ -384,7 +384,7 @@ describe('Name Resolver', () => { done(new Error(`Failed with status ${error.details}`)); }, }; - const resolver = resolverManager.createResolver(target, listener); + const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); }); From d8e035445cab44e73e6753f3a9a07330f9d2e112 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 3 Aug 2020 10:59:10 -0700 Subject: [PATCH 1187/1899] Fix imports of messages defined in other messages, add missing comma --- .../bin/proto-loader-gen-types.ts | 37 ++++++++++++++----- .../proto-loader/golden-generated/echo.ts | 2 +- packages/proto-loader/package.json | 2 +- 3 files changed, 30 insertions(+), 11 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 74e95ac52..a01004ef8 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -81,7 +81,12 @@ function stripLeadingPeriod(name: string) { return name.startsWith('.') ? name.substring(1) : name; } -function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { +function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service): string { + /* If the thing we are importing is defined in a message, it is generated in + * the same file as that message. */ + if (to.parent instanceof Protobuf.Type) { + return getImportPath(to.parent); + } return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); } @@ -110,14 +115,28 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); const typeInterfaceName = getTypeInterfaceName(dependency); let importedTypes: string; - if (dependency instanceof Protobuf.Type) { - importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; - } else if (dependency instanceof Protobuf.Enum) { - importedTypes = `${dependency.name} as ${typeInterfaceName}`; - } else if (dependency instanceof Protobuf.Service) { - importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; + /* If the dependenc is defined within a message, it will be generated in that + * message's file and exported using its typeInterfaceName. */ + if (dependency.parent instanceof Protobuf.Type) { + if (dependency instanceof Protobuf.Type) { + importedTypes = `${typeInterfaceName}, ${typeInterfaceName}__Output`; + } else if (dependency instanceof Protobuf.Enum) { + importedTypes = `${typeInterfaceName}`; + } else if (dependency instanceof Protobuf.Service) { + importedTypes = `${typeInterfaceName}Client`; + } else { + throw new Error('Invalid object passed to getImportLine'); + } } else { - throw new Error('Invalid object passed to getImportLine'); + if (dependency instanceof Protobuf.Type) { + importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; + } else if (dependency instanceof Protobuf.Enum) { + importedTypes = `${dependency.name} as ${typeInterfaceName}`; + } else if (dependency instanceof Protobuf.Service) { + importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; + } else { + throw new Error('Invalid object passed to getImportLine'); + } } return `import { ${importedTypes} } from '${filePath}';` } @@ -585,7 +604,7 @@ function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); formatter.writeLine('type SubtypeConstructor = {'); formatter.writeLine(' new(...args: ConstructorArguments): Subtype;'); - formatter.writeLine('}'); + formatter.writeLine('};'); formatter.writeLine(''); formatter.writeLine('export interface ProtoGrpcType {'); diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index f4b07e5a2..e875e5076 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -7,7 +7,7 @@ import { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/show type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { google: { diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 7dbb89d0d..a5fda1101 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre11", + "version": "0.6.0-pre12", "author": "Google Inc.", "contributors": [ { From ddec63af2055038ebbe235e73b2371cdd2cfaac0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 11:22:18 -0700 Subject: [PATCH 1188/1899] grpc-js: Clean up call even if status throws an error --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 11 ++++++++++- packages/grpc-js/src/server-call.ts | 6 ++++++ packages/grpc-js/src/server.ts | 12 +++++++++++- packages/grpc-js/src/subchannel.ts | 2 +- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4c4e59f06..70ebe0576 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.3", + "version": "1.1.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 825342a58..45bc665fc 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -227,7 +227,15 @@ export class Http2CallStream implements Call { const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! ); - this.listener?.onReceiveStatus(filteredStatus); + /* We delay the actual action of bubbling up the status to insulate the + * cleanup code in this class from any errors that may be thrown in the + * upper layers as a result of bubbling up the status. In particular, + * if the status is not OK, the "error" event may be emitted + * synchronously at the top level, which will result in a thrown error if + * the user does not handle that event. */ + process.nextTick(() => { + this.listener?.onReceiveStatus(filteredStatus); + }); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -602,6 +610,7 @@ export class Http2CallStream implements Call { } else { code = http2.constants.NGHTTP2_CANCEL; } + this.trace('close http2 stream with code ' + code); this.http2Stream.close(code); } } diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d885173..fb76ca030 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -373,6 +373,12 @@ export class Http2ServerCallStream< }); this.stream.once('close', () => { + trace( + 'Request to method ' + + this.handler?.path + + ' stream closed with rstCode ' + + this.stream.rstCode + ); this.cancelled = true; this.emit('cancelled', 'cancelled'); }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ebd4504d7..3580d89a4 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -543,11 +543,21 @@ export class Server { try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; + const serverAddress = http2Server.address(); + let serverAddressString = 'null'; + if (serverAddress) { + if (typeof serverAddress === 'string') { + serverAddressString = serverAddress; + } else { + serverAddressString = + serverAddress.address + ':' + serverAddress.port; + } + } trace( 'Received call to method ' + path + ' at address ' + - http2Server.address()?.toString() + serverAddressString ); const handler = this.handlers.get(path); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index be72680e2..736562a66 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -415,7 +415,7 @@ export class Subchannel { ); } trace( - this.subchannelAddress + + this.subchannelAddressString + ' connection closed by GOAWAY with code ' + errorCode ); From d9b3f9f3645c57b2168f92af1994e37f5973d1e5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 11:37:08 -0700 Subject: [PATCH 1189/1899] grpc-js: Add end(md?: Metadata) method to streaming server calls --- packages/grpc-js/src/server-call.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d885173..1e935995c 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -91,10 +91,13 @@ export type ServerWritableStream< RequestType, ResponseType > = ServerSurfaceCall & - ObjectWritable & { request: RequestType | null }; + ObjectWritable & { + request: RequestType | null; + end: (metadata?: Metadata) => void; + }; export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & - ObjectWritable; + ObjectWritable & { end: (metadata?: Metadata) => void }; export class ServerUnaryCallImpl extends EventEmitter implements ServerUnaryCall { @@ -255,6 +258,15 @@ export class ServerDuplexStreamImpl extends Duplex sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + end(metadata?: any) { + if (metadata) { + this.trailingMetadata = metadata; + } + + super.end(); + } } ServerDuplexStreamImpl.prototype._read = From 33a4c85f89591c36cb7001d604ce1f62b65e2db6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 13:03:08 -0700 Subject: [PATCH 1190/1899] grpc-js: Implement getPeer on the client and server --- packages/grpc-js/src/call-stream.ts | 2 +- packages/grpc-js/src/call.ts | 8 ++++---- packages/grpc-js/src/server-call.ts | 21 +++++++++++++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 825342a58..2c9f01cba 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -630,7 +630,7 @@ export class Http2CallStream implements Call { } getPeer(): string { - throw new Error('Not yet implemented'); + return this.subchannel?.getAddress() ?? this.channel.getTarget(); } getMethod(): string { diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index 0d88ef151..cfe37ecfb 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -93,7 +93,7 @@ export class ClientUnaryCallImpl extends EventEmitter } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } } @@ -109,7 +109,7 @@ export class ClientReadableStreamImpl extends Readable } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } _read(_size: number): void { @@ -129,7 +129,7 @@ export class ClientWritableStreamImpl extends Writable } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } _write(chunk: RequestType, encoding: string, cb: WriteCallback) { @@ -164,7 +164,7 @@ export class ClientDuplexStreamImpl extends Duplex } getPeer(): string { - return this.call?.getPeer() ?? ''; + return this.call?.getPeer() ?? 'unknown'; } _read(_size: number): void { diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d885173..bd9927735 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -112,7 +112,7 @@ export class ServerUnaryCallImpl extends EventEmitter } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -145,7 +145,7 @@ export class ServerReadableStreamImpl } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -178,7 +178,7 @@ export class ServerWritableStreamImpl } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -249,7 +249,7 @@ export class ServerDuplexStreamImpl extends Duplex } getPeer(): string { - throw new Error('not implemented yet'); + return this.call.getPeer(); } sendMetadata(responseMetadata: Metadata): void { @@ -738,6 +738,19 @@ export class Http2ServerCallStream< ); } } + + getPeer(): string { + const socket = this.stream.session.socket; + if (socket.remoteAddress) { + if (socket.remotePort) { + return `${socket.remoteAddress}:${socket.remotePort}`; + } else { + return socket.remoteAddress; + } + } else { + return 'unknown'; + } + } } /* eslint-disable @typescript-eslint/no-explicit-any */ From 128d4e90831fe7592386fab3d7e617b8f06d4b73 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Aug 2020 13:23:02 -0700 Subject: [PATCH 1191/1899] Add TS generator information to README --- packages/proto-loader/README.md | 34 +++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 07f28907c..7a97a3b1b 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -52,3 +52,37 @@ const options = { oneofs: true } ``` + +## Generating TypeScript types + +The `proto-loader-gen-types` script distributed with this package can be used to generate TypeScript type information for the objects loaded at runtime. More information about how to use it can be found in [the *@grpc/proto-loader TypeScript Type Generator CLI Tool* proposal document](https://github.com/grpc/proposal/blob/master/L70-node-proto-loader-type-generator.md). The arguments mostly match the `load` function's options; the full usage information is as follows: + +``` +proto-loader-gen-types.js [options] filenames... + +Options: + --help Show help [boolean] + --version Show version number [boolean] + --keepCase Preserve the case of field names [boolean] + --longs The type that should be used to output 64 bit integer + values. Can be String, Number [string] + --enums The type that should be used to output enum fields. Can be + String [string] + --bytes The type that should be used to output bytes fields. Can be + String, Array [string] + --defaults Output default values for omitted fields [boolean] + --arrays Output default values for omitted repeated fields even if + --defaults is not set [boolean] + --objects Output default values for omitted message fields even if + --defaults is not set [boolean] + --oneofs Output virtual oneof fields set to the present field's name + [boolean] + --json Represent Infinity and NaN as strings in float fields. Also + decode google.protobuf.Any automatically [boolean] + --includeComments Generate doc comments from comments in the original files + [boolean] + --includeDirs, -I Directories to search for included files [array] + --outDir, -O Directory in which to output files [string] [required] + --grpcLib The gRPC implementation library that these types will be + used with [string] [required] +``` \ No newline at end of file From 0b146c8b076c6b5ca883e536128d00d9b29d0c28 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Aug 2020 12:38:43 -0700 Subject: [PATCH 1192/1899] Address PR comments --- packages/grpc-js/src/channel.ts | 1 - packages/grpc-js/src/xds-client.ts | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 49535c19d..8c3691928 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -34,7 +34,6 @@ import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; import { getDefaultAuthority, mapUriDefaultScheme } from './resolver'; -import { ServiceConfig, validateServiceConfig } from './service-config'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index cce798246..f867ed7cf 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -439,7 +439,7 @@ export class XdsClient { for (const resource of message.resources) { if ( protoLoader.isAnyExtension(resource) && - resource['@type'] === LDS_TYPE_URL + resource['@type'] === RDS_TYPE_URL ) { const resp = resource as protoLoader.AnyExtension & RouteConfiguration__Output; @@ -823,7 +823,7 @@ export class XdsClient { private updateRdsNames() { this.adsCall?.write({ node: this.adsNode!, - type_url: CDS_TYPE_URL, + type_url: RDS_TYPE_URL, resource_names: this.routeConfigName ? [this.routeConfigName] : [], response_nonce: this.lastRdsNonce, version_info: this.lastRdsVersionInfo, From 76bb17091bbcd4afe70a240d51aa506b3543f56b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Aug 2020 12:57:54 -0700 Subject: [PATCH 1193/1899] Stop processing RDS requests after finding the matching one --- packages/grpc-js/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index f867ed7cf..f5725d789 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -452,6 +452,7 @@ export class XdsClient { } else { nackError = 'RouteConfiguration validation failed'; } + break; } } else { nackError = `Invalid resource type ${ From 5dcce9ebf17181a32afa6fe994174ca9343b9a6e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 Aug 2020 13:08:59 -0700 Subject: [PATCH 1194/1899] grpc-js: XdsClient: separate ADS stream handling by message type --- packages/grpc-js/src/xds-client.ts | 1174 ++++++++++++++-------------- 1 file changed, 578 insertions(+), 596 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index f5725d789..4375c77a7 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -33,7 +33,10 @@ import { Node } from './generated/envoy/api/v2/core/Node'; import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; -import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; +import { + ClusterLoadAssignment__Output, + ClusterLoadAssignment, +} from './generated/envoy/api/v2/ClusterLoadAssignment'; import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; import { LoadReportingServiceClient } from './generated/envoy/service/load_stats/v2/LoadReportingService'; import { LoadStatsRequest } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; @@ -50,6 +53,7 @@ import { UpstreamLocalityStats } from './generated/envoy/api/v2/endpoint/Upstrea import { Listener__Output } from './generated/envoy/api/v2/Listener'; import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; +import { Any__Output } from './generated/google/protobuf/Any'; const TRACER_NAME = 'xds_client'; @@ -64,6 +68,13 @@ const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; const LDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Listener'; const RDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; +type EdsTypeUrl = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; +type CdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Cluster'; +type LdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Listener'; +type RdsTypeUrl = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; + +type AdsTypeUrl = EdsTypeUrl | CdsTypeUrl | RdsTypeUrl | LdsTypeUrl; + const HTTP_CONNECTION_MANGER_TYPE_URL = 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; @@ -211,485 +222,209 @@ class ClusterLoadReportMap { } } -export class XdsClient { - private adsNode: Node | null = null; - private adsClient: AggregatedDiscoveryServiceClient | null = null; - private adsCall: ClientDuplexStream< - DiscoveryRequest, - DiscoveryResponse__Output - > | null = null; - - private lrsNode: Node | null = null; - private lrsClient: LoadReportingServiceClient | null = null; - private lrsCall: ClientDuplexStream< - LoadStatsRequest, - LoadStatsResponse__Output - > | null = null; - private latestLrsSettings: LoadStatsResponse__Output | null = null; +interface XdsStreamState { + versionInfo: string; + nonce: string; + getResourceNames(): string[]; + /** + * Returns a string containing the error details if the message should be nacked, + * or null if it should be acked. + * @param responses + */ + handleResponses(responses: ResponseType[]): string | null; - private clusterStatsMap: ClusterLoadReportMap = new ClusterLoadReportMap(); - private statsTimer: NodeJS.Timer; + reportStreamError(status: StatusObject): void; +} - private hasShutdown = false; +class EdsState implements XdsStreamState { + public versionInfo = ''; + public nonce = ''; - private endpointWatchers: Map< + private watchers: Map< string, Watcher[] > = new Map[]>(); - private lastEdsVersionInfo = ''; - private lastEdsNonce = ''; - private latestEdsResponses: ClusterLoadAssignment__Output[] = []; - private clusterWatchers: Map[]> = new Map< - string, - Watcher[] - >(); - private lastCdsVersionInfo = ''; - private lastCdsNonce = ''; - private latestCdsResponses: Cluster__Output[] = []; - - private lastLdsVersionInfo = ''; - private lastLdsNonce = ''; - private latestLdsResponse: Listener__Output | null = null; + private latestResponses: ClusterLoadAssignment__Output[] = []; - private routeConfigName: string | null = null; - private lastRdsVersionInfo = ''; - private lastRdsNonce = ''; - private latestRdsResponse: RouteConfiguration__Output | null = null; + constructor(private updateResourceNames: () => void) {} - constructor( - private targetName: string, - private serviceConfigWatcher: Watcher, - channelOptions: ChannelOptions - ) { - const channelArgs = { ...channelOptions }; - const channelArgsToRemove = [ - /* The SSL target name override corresponds to the target, and this - * client has its own target */ - 'grpc.ssl_target_name_override', - /* The default authority also corresponds to the target */ - 'grpc.default_authority', - /* This client will have its own specific keepalive time setting */ - 'grpc.keepalive_time_ms', - /* The service config specifies the load balancing policy. This channel - * needs its own separate load balancing policy setting. In particular, - * recursively using an xDS load balancer for the xDS client would be - * bad */ - 'grpc.service_config', - ]; - for (const arg of channelArgsToRemove) { - delete channelArgs[arg]; + /** + * Add the watcher to the watcher list. Returns true if the list of resource + * names has changed, and false otherwise. + * @param edsServiceName + * @param watcher + */ + addWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + let watchersEntry = this.watchers.get(edsServiceName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(edsServiceName, watchersEntry); } - channelArgs['grpc.keepalive_time_ms'] = 5000; - Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( - ([bootstrapInfo, protoDefinitions]) => { - if (this.hasShutdown) { - return; - } - const node: Node = { - ...bootstrapInfo.node, - build_version: `gRPC Node Pure JS ${clientVersion}`, - user_agent_name: 'gRPC Node Pure JS', - }; - this.adsNode = { - ...node, - client_features: ['envoy.lb.does_not_support_overprovisioning'], - }; - this.lrsNode = { - ...node, - client_features: ['envoy.lrs.supports_send_all_clusters'], - }; - this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( - bootstrapInfo.xdsServers[0].serverUri, - createGoogleDefaultCredentials(), - channelArgs - ); - this.maybeStartAdsStream(); + watchersEntry.push(watcher); - this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( - bootstrapInfo.xdsServers[0].serverUri, - createGoogleDefaultCredentials(), - channelArgs - ); - this.maybeStartLrsStream(); - }, - (error) => { - trace('Failed to initialize xDS Client. ' + error.message); - // Bubble this error up to any listeners - this.reportStreamError({ - code: Status.INTERNAL, - details: `Failed to initialize xDS Client. ${error.message}`, - metadata: new Metadata(), + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.cluster_name === edsServiceName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + watcher.onValidUpdate(message); }); } - ); - this.statsTimer = setInterval(() => {}, 0); - clearInterval(this.statsTimer); + } + if (addedServiceName) { + this.updateResourceNames(); + } } - private handleAdsResponse(message: DiscoveryResponse__Output) { - switch (message.type_url) { - case EDS_TYPE_URL: { - const edsResponses: ClusterLoadAssignment__Output[] = []; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === EDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - ClusterLoadAssignment__Output; - if (!this.validateEdsResponse(resp)) { - this.nackEds('ClusterLoadAssignment validation failed'); - return; - } - edsResponses.push(resp); - } else { - this.nackEds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); - return; - } - } - for (const message of edsResponses) { - this.handleEdsResponse(message); - } - this.lastEdsVersionInfo = message.version_info; - this.lastEdsNonce = message.nonce; - this.latestEdsResponses = edsResponses; - this.ackEds(); - break; + removeWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + const watchersEntry = this.watchers.get(edsServiceName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); } - case CDS_TYPE_URL: { - const cdsResponses: Cluster__Output[] = []; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === CDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & Cluster__Output; - if (!this.validateCdsResponse(resp)) { - this.nackCds('Cluster validation failed'); - return; - } - } else { - this.nackCds( - `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }` - ); - return; - } - } - for (const message of cdsResponses) { - this.handleCdsResponse(message); - } - this.lastCdsVersionInfo = message.version_info; - this.lastCdsNonce = message.nonce; - this.latestCdsResponses = cdsResponses; - this.ackCds(); - break; + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(edsServiceName); } - case LDS_TYPE_URL: { - let nackError: string | null = null; - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === LDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - Listener__Output; - if (resp.name === this.targetName) { - if (this.validateLdsResponse(resp)) { - this.handleLdsResponse(resp); - this.lastLdsVersionInfo = message.version_info; - this.lastLdsNonce = message.nonce; - this.latestLdsResponse = resp; - } else { - nackError = 'Listener validation failed'; - } - break; - } - } else { - nackError = `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }`; - break; - } - } - if (nackError) { - this.nackLds(nackError); - } else { - this.ackLds(); + } + if (removedServiceName) { + this.updateResourceNames(); + } + } + + getResourceNames(): string[] { + return Array.from(this.watchers.keys()); + } + + /** + * Validate the ClusterLoadAssignment object by these rules: + * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto + * @param message + */ + private validateResponse(message: ClusterLoadAssignment__Output) { + for (const endpoint of message.endpoints) { + for (const lb of endpoint.lb_endpoints) { + const socketAddress = lb.endpoint?.address?.socket_address; + if (!socketAddress) { + return false; } - break; - } - case RDS_TYPE_URL: { - let nackError: string | null = null; - if (this.routeConfigName === null) { - nackError = 'Unexpected RouteConfiguration response'; - } else { - for (const resource of message.resources) { - if ( - protoLoader.isAnyExtension(resource) && - resource['@type'] === RDS_TYPE_URL - ) { - const resp = resource as protoLoader.AnyExtension & - RouteConfiguration__Output; - if (resp.name === this.routeConfigName) { - if (this.validateRdsResponse(resp)) { - this.handleRdsResponse(resp); - this.lastRdsVersionInfo = message.version_info; - this.lastRdsNonce = message.nonce; - this.latestRdsResponse = resp; - } else { - nackError = 'RouteConfiguration validation failed'; - } - break; - } - } else { - nackError = `Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }`; - break; - } - } + if (socketAddress.port_specifier !== 'port_value') { + return false; } - if (nackError) { - this.nackRds(nackError); - } else { - this.ackRds(); + if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { + return false; } - break; } - default: - this.nackUnknown(message.type_url, message.version_info, message.nonce); } + return true; } - /** - * Start the ADS stream if the client exists and there is not already an - * existing stream, and there - */ - private maybeStartAdsStream() { - if (this.adsClient === null) { - return; - } - if (this.adsCall !== null) { - return; + handleResponses(responses: ClusterLoadAssignment__Output[]) { + for (const message of responses) { + if (!this.validateResponse(message)) { + return 'ClusterLoadAssignment validation failed'; + } } - if (this.hasShutdown) { - return; + this.latestResponses = responses; + for (const message of responses) { + const watchers = this.watchers.get(message.cluster_name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } } - this.adsCall = this.adsClient.StreamAggregatedResources(); - this.adsCall.on('data', (message: DiscoveryResponse__Output) => { - this.handleAdsResponse(message); - }); - this.adsCall.on('error', (error: ServiceError) => { - trace( - 'ADS stream ended. code=' + error.code + ' details= ' + error.details - ); - this.adsCall = null; - this.reportStreamError(error); - /* Connection backoff is handled by the client object, so we can - * immediately start a new request to indicate that it should try to - * reconnect */ - this.maybeStartAdsStream(); - }); - - this.adsCall.write({ - node: this.adsNode!, - type_url: LDS_TYPE_URL, - resource_names: [this.targetName], - }); + return null; + } - if (this.routeConfigName) { - this.adsCall.write({ - node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: [this.routeConfigName], - }); + reportStreamError(status: StatusObject): void { + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } } + } +} - const clusterNames = Array.from(this.clusterWatchers.keys()); - if (clusterNames.length > 0) { - this.adsCall.write({ - node: this.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: clusterNames, - }); - } +class CdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; - const endpointWatcherNames = Array.from(this.endpointWatchers.keys()); - if (endpointWatcherNames.length > 0) { - this.adsCall.write({ - node: this.adsNode!, - type_url: EDS_TYPE_URL, - resource_names: endpointWatcherNames, - }); - } - } + private watchers: Map[]> = new Map< + string, + Watcher[] + >(); - private nackUnknown(typeUrl: string, versionInfo: string, nonce: string) { - if (!this.adsCall) { - return; - } - this.adsCall.write({ - node: this.adsNode!, - type_url: typeUrl, - version_info: versionInfo, - response_nonce: nonce, - error_detail: { - message: `Unknown type_url ${typeUrl}`, - }, - }); - } + private latestResponses: Cluster__Output[] = []; + + constructor(private updateResourceNames: () => void) {} /** - * Acknowledge an EDS update. This should be called after the local nonce and - * version info are updated so that it sends the post-update values. + * Add the watcher to the watcher list. Returns true if the list of resource + * names has changed, and false otherwise. + * @param clusterName + * @param watcher */ - private ackEds() { - if (!this.adsCall) { - return; + addWatcher(clusterName: string, watcher: Watcher): void { + let watchersEntry = this.watchers.get(clusterName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(clusterName, watchersEntry); } - this.adsCall.write({ - node: this.adsNode!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - }); - } + watchersEntry.push(watcher); - private ackCds() { - if (!this.adsCall) { - return; + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.name === clusterName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); } - this.adsCall.write({ - node: this.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - }); - } - - private ackLds() { - this.adsCall?.write({ - node: this.adsNode!, - type_url: LDS_TYPE_URL, - resource_names: [this.targetName], - response_nonce: this.lastLdsNonce, - version_info: this.lastLdsVersionInfo, - }); } - private ackRds() { - this.adsCall?.write({ - node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: [this.routeConfigName!], - response_nonce: this.lastRdsNonce, - version_info: this.lastRdsVersionInfo, - }); - } - - /** - * Reject an EDS update. This should be called without updating the local - * nonce and version info. - */ - private nackEds(message: string) { - if (!this.adsCall) { - return; + removeWatcher(clusterName: string, watcher: Watcher): void { + const watchersEntry = this.watchers.get(clusterName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(clusterName); + } } - this.adsCall.write({ - node: this.adsNode!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - error_detail: { - message, - }, - }); - } - - private nackCds(message: string) { - if (!this.adsCall) { - return; + if (removedServiceName) { + this.updateResourceNames(); } - this.adsCall.write({ - node: this.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - error_detail: { - message, - }, - }); - } - - private nackLds(message: string) { - this.adsCall?.write({ - node: this.adsNode!, - type_url: LDS_TYPE_URL, - resource_names: [this.targetName], - response_nonce: this.lastLdsNonce, - version_info: this.lastLdsVersionInfo, - error_detail: { - message, - }, - }); } - private nackRds(message: string) { - this.adsCall?.write({ - node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: this.routeConfigName ? [this.routeConfigName] : [], - response_nonce: this.lastRdsNonce, - version_info: this.lastRdsVersionInfo, - error_detail: { - message, - }, - }); - } - - /** - * Validate the ClusterLoadAssignment object by these rules: - * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto - * @param message - */ - private validateEdsResponse(message: ClusterLoadAssignment__Output): boolean { - for (const endpoint of message.endpoints) { - for (const lb of endpoint.lb_endpoints) { - const socketAddress = lb.endpoint?.address?.socket_address; - if (!socketAddress) { - return false; - } - if (socketAddress.port_specifier !== 'port_value') { - return false; - } - if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { - return false; - } - } - } - return true; + getResourceNames(): string[] { + return Array.from(this.watchers.keys()); } - private validateCdsResponse(message: Cluster__Output): boolean { + private validateResponse(message: Cluster__Output): boolean { if (message.type !== 'EDS') { return false; } @@ -707,7 +442,107 @@ export class XdsClient { return true; } - private validateLdsResponse(message: Listener__Output): boolean { + handleResponses(responses: Cluster__Output[]): string | null { + for (const message of responses) { + if (!this.validateResponse(message)) { + return 'Cluster validation failed'; + } + } + this.latestResponses = responses; + for (const message of responses) { + const watchers = this.watchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + return null; + } + + reportStreamError(status: StatusObject): void { + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + } +} + +class RdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + private routeConfigName: string | null = null; + + constructor( + private watcher: Watcher, + private updateResouceNames: () => void + ) {} + + getResourceNames(): string[] { + return this.routeConfigName ? [this.routeConfigName] : []; + } + + handleSingleMessage(message: RouteConfiguration__Output) { + for (const virtualHost of message.virtual_hosts) { + if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + this.watcher.onValidUpdate({ + methodConfig: [], + loadBalancingConfig: [ + { + name: 'cds', + cds: { + cluster: route.route.cluster, + }, + }, + ], + }); + break; + } + } + } + /* If none of the routes match the one we are looking for, bubble up an + * error. */ + this.watcher.onResourceDoesNotExist(); + } + + handleResponses(responses: RouteConfiguration__Output[]): string | null { + if (this.routeConfigName !== null) { + for (const message of responses) { + if (message.name === this.routeConfigName) { + this.handleSingleMessage(message); + return null; + } + } + } + return null; + } + + setRouteConfigName(name: string | null) { + const oldName = this.routeConfigName; + this.routeConfigName = name; + if (name !== oldName) { + this.updateResouceNames(); + } + } + + reportStreamError(status: StatusObject): void { + this.watcher.onTransientError(status); + } +} + +class LdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + constructor(private targetName: string, private rdsState: RdsState) {} + + getResourceNames(): string[] { + return [this.targetName]; + } + + private validateResponse(message: Listener__Output): boolean { if ( !( message.api_listener?.api_listener && @@ -723,124 +558,343 @@ export class XdsClient { HttpConnectionManager__Output; switch (httpConnectionManager.route_specifier) { case 'rds': - if (!httpConnectionManager.rds?.config_source?.ads) { - return false; - } - break; + return !!httpConnectionManager.rds?.config_source?.ads; case 'route_config': - return this.validateRdsResponse(httpConnectionManager.route_config!); + return true; } return false; } - private validateRdsResponse(message: RouteConfiguration__Output): boolean { - return true; + handleResponses(responses: Listener__Output[]): string | null { + for (const message of responses) { + if (message.name === this.targetName) { + if (this.validateResponse(message)) { + // The validation step ensures that this is correct + const httpConnectionManager = message.api_listener! + .api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + this.rdsState.setRouteConfigName( + httpConnectionManager.rds!.route_config_name + ); + break; + case 'route_config': + this.rdsState.setRouteConfigName(null); + this.rdsState.handleSingleMessage( + httpConnectionManager.route_config! + ); + break; + default: + // The validation rules should prevent this + } + } else { + return 'Listener validation failed'; + } + } + } + throw new Error('Method not implemented.'); + } + + reportStreamError(status: StatusObject): void { + // Nothing to do here } +} + +interface AdsState { + [EDS_TYPE_URL]: EdsState; + [CDS_TYPE_URL]: CdsState; + [RDS_TYPE_URL]: RdsState; + [LDS_TYPE_URL]: LdsState; +} - private handleEdsResponse(message: ClusterLoadAssignment__Output) { - const watchers = this.endpointWatchers.get(message.cluster_name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); +/** + * Map type URLs to their corresponding message types + */ +type OutputType = T extends EdsTypeUrl + ? ClusterLoadAssignment__Output + : T extends CdsTypeUrl + ? Cluster__Output + : T extends RdsTypeUrl + ? RouteConfiguration__Output + : Listener__Output; + +function getResponseMessages( + typeUrl: T, + resources: Any__Output[] +): OutputType[] { + const result: OutputType[] = []; + for (const resource of resources) { + if (protoLoader.isAnyExtension(resource) && resource['@type'] === typeUrl) { + result.push(resource as protoLoader.AnyExtension & OutputType); + } else { + throw new Error( + `Invalid resource type ${ + protoLoader.isAnyExtension(resource) + ? resource['@type'] + : resource.type_url + }` + ); } } + return result; +} + +export class XdsClient { + private adsNode: Node | null = null; + private adsClient: AggregatedDiscoveryServiceClient | null = null; + private adsCall: ClientDuplexStream< + DiscoveryRequest, + DiscoveryResponse__Output + > | null = null; + + private lrsNode: Node | null = null; + private lrsClient: LoadReportingServiceClient | null = null; + private lrsCall: ClientDuplexStream< + LoadStatsRequest, + LoadStatsResponse__Output + > | null = null; + private latestLrsSettings: LoadStatsResponse__Output | null = null; + + private clusterStatsMap: ClusterLoadReportMap = new ClusterLoadReportMap(); + private statsTimer: NodeJS.Timer; + + private hasShutdown = false; + + private adsState: AdsState; - private handleCdsResponse(message: Cluster__Output) { - const watchers = this.clusterWatchers.get(message.name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); + constructor( + targetName: string, + serviceConfigWatcher: Watcher, + channelOptions: ChannelOptions + ) { + const edsState = new EdsState(() => { + this.updateNames(EDS_TYPE_URL); + }); + const cdsState = new CdsState(() => { + this.updateNames(CDS_TYPE_URL); + }); + const rdsState = new RdsState(serviceConfigWatcher, () => { + this.updateNames(RDS_TYPE_URL); + }); + const ldsState = new LdsState(targetName, rdsState); + this.adsState = { + [EDS_TYPE_URL]: edsState, + [CDS_TYPE_URL]: cdsState, + [RDS_TYPE_URL]: rdsState, + [LDS_TYPE_URL]: ldsState, + }; + + const channelArgs = { ...channelOptions }; + const channelArgsToRemove = [ + /* The SSL target name override corresponds to the target, and this + * client has its own target */ + 'grpc.ssl_target_name_override', + /* The default authority also corresponds to the target */ + 'grpc.default_authority', + /* This client will have its own specific keepalive time setting */ + 'grpc.keepalive_time_ms', + /* The service config specifies the load balancing policy. This channel + * needs its own separate load balancing policy setting. In particular, + * recursively using an xDS load balancer for the xDS client would be + * bad */ + 'grpc.service_config', + ]; + for (const arg of channelArgsToRemove) { + delete channelArgs[arg]; } + channelArgs['grpc.keepalive_time_ms'] = 5000; + Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( + ([bootstrapInfo, protoDefinitions]) => { + if (this.hasShutdown) { + return; + } + const node: Node = { + ...bootstrapInfo.node, + build_version: `gRPC Node Pure JS ${clientVersion}`, + user_agent_name: 'gRPC Node Pure JS', + }; + this.adsNode = { + ...node, + client_features: ['envoy.lb.does_not_support_overprovisioning'], + }; + this.lrsNode = { + ...node, + client_features: ['envoy.lrs.supports_send_all_clusters'], + }; + this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( + bootstrapInfo.xdsServers[0].serverUri, + createGoogleDefaultCredentials(), + channelArgs + ); + this.maybeStartAdsStream(); + + this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( + bootstrapInfo.xdsServers[0].serverUri, + createGoogleDefaultCredentials(), + channelArgs + ); + this.maybeStartLrsStream(); + }, + (error) => { + trace('Failed to initialize xDS Client. ' + error.message); + // Bubble this error up to any listeners + this.reportStreamError({ + code: Status.INTERNAL, + details: `Failed to initialize xDS Client. ${error.message}`, + metadata: new Metadata(), + }); + } + ); + this.statsTimer = setInterval(() => {}, 0); + clearInterval(this.statsTimer); } - private handleLdsResponse(message: Listener__Output) { - // The validation step ensures that this is correct - const httpConnectionManager = message.api_listener! - .api_listener as protoLoader.AnyExtension & HttpConnectionManager__Output; - switch (httpConnectionManager.route_specifier) { - case 'rds': - this.routeConfigName = httpConnectionManager.rds!.route_config_name; - this.updateRdsNames(); + private handleAdsResponse(message: DiscoveryResponse__Output) { + let errorString: string | null; + /* The cases in this switch statement look redundant but separating them + * out like this is necessary for the typechecker to validate the types + * as narrowly as we need it to. */ + switch (message.type_url) { + case EDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); break; - case 'route_config': - this.handleRdsResponse(httpConnectionManager.route_config!); - if (this.routeConfigName) { - this.routeConfigName = null; - this.updateRdsNames(); - } + case CDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); + break; + case RDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); + break; + case LDS_TYPE_URL: + errorString = this.adsState[message.type_url].handleResponses( + getResponseMessages(message.type_url, message.resources) + ); break; default: - // The validation rules should prevent this + errorString = `Unknown type_url ${message.type_url}`; + } + if (errorString === null) { + /* errorString can only be null in one of the first 4 cases, which + * implies that message.type_url is one of the 4 known type URLs, which + * means that this type assertion is valid. */ + const typeUrl = message.type_url as AdsTypeUrl; + this.adsState[typeUrl].nonce = message.nonce; + this.adsState[typeUrl].versionInfo = message.version_info; + this.ack(typeUrl); + } else { + this.nack(message.type_url, errorString); } } - private handleRdsResponse(message: RouteConfiguration__Output) { - for (const virtualHost of message.virtual_hosts) { - if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { - const route = virtualHost.routes[virtualHost.routes.length - 1]; - if (route.match?.prefix === '' && route.route?.cluster) { - this.serviceConfigWatcher.onValidUpdate({ - methodConfig: [], - loadBalancingConfig: [ - { - name: 'cds', - cds: { - cluster: route.route.cluster, - }, - }, - ], - }); - break; - } + /** + * Start the ADS stream if the client exists and there is not already an + * existing stream, and there + */ + private maybeStartAdsStream() { + if (this.adsClient === null) { + return; + } + if (this.adsCall !== null) { + return; + } + if (this.hasShutdown) { + return; + } + this.adsCall = this.adsClient.StreamAggregatedResources(); + this.adsCall.on('data', (message: DiscoveryResponse__Output) => { + this.handleAdsResponse(message); + }); + this.adsCall.on('error', (error: ServiceError) => { + trace( + 'ADS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.adsCall = null; + this.reportStreamError(error); + /* Connection backoff is handled by the client object, so we can + * immediately start a new request to indicate that it should try to + * reconnect */ + this.maybeStartAdsStream(); + }); + + const allTypeUrls: AdsTypeUrl[] = [ + EDS_TYPE_URL, + CDS_TYPE_URL, + RDS_TYPE_URL, + LDS_TYPE_URL, + ]; + for (const typeUrl of allTypeUrls) { + const state = this.adsState[typeUrl]; + state.nonce = ''; + state.versionInfo = ''; + if (state.getResourceNames().length > 0) { + this.updateNames(typeUrl); } } - /* If none of the routes match the one we are looking for, bubble up an - * error. */ - this.serviceConfigWatcher.onResourceDoesNotExist(); } - private updateEdsNames() { - if (this.adsCall) { - this.adsCall.write({ - node: this.adsNode!, - type_url: EDS_TYPE_URL, - resource_names: Array.from(this.endpointWatchers.keys()), - response_nonce: this.lastEdsNonce, - version_info: this.lastEdsVersionInfo, - }); - } + /** + * Acknowledge an update. This should be called after the local nonce and + * version info are updated so that it sends the post-update values. + */ + ack(typeUrl: AdsTypeUrl) { + this.updateNames(typeUrl); } - private updateCdsNames() { - if (this.adsCall) { - this.adsCall.write({ - node: this.adsNode!, - type_url: CDS_TYPE_URL, - resource_names: Array.from(this.clusterWatchers.keys()), - response_nonce: this.lastCdsNonce, - version_info: this.lastCdsVersionInfo, - }); + /** + * Reject an update. This should be called without updating the local + * nonce and version info. + */ + private nack(typeUrl: string, message: string) { + let resourceNames: string[]; + let nonce: string; + let versionInfo: string; + switch (typeUrl) { + case EDS_TYPE_URL: + case CDS_TYPE_URL: + case RDS_TYPE_URL: + case LDS_TYPE_URL: + resourceNames = this.adsState[typeUrl].getResourceNames(); + nonce = this.adsState[typeUrl].nonce; + versionInfo = this.adsState[typeUrl].versionInfo; + break; + default: + resourceNames = []; + nonce = ''; + versionInfo = ''; } + this.adsCall?.write({ + node: this.adsNode!, + type_url: typeUrl, + resource_names: resourceNames, + response_nonce: nonce, + version_info: versionInfo, + error_detail: { + message: message, + }, + }); } - private updateRdsNames() { + private updateNames(typeUrl: AdsTypeUrl) { this.adsCall?.write({ node: this.adsNode!, - type_url: RDS_TYPE_URL, - resource_names: this.routeConfigName ? [this.routeConfigName] : [], - response_nonce: this.lastRdsNonce, - version_info: this.lastRdsVersionInfo, + type_url: typeUrl, + resource_names: this.adsState[typeUrl].getResourceNames(), + response_nonce: this.adsState[typeUrl].nonce, + version_info: this.adsState[typeUrl].versionInfo, }); } private reportStreamError(status: StatusObject) { - for (const watcherList of [ - ...this.endpointWatchers.values(), - ...this.clusterWatchers.values(), - [this.serviceConfigWatcher], - ]) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } + this.adsState[EDS_TYPE_URL].reportStreamError(status); + this.adsState[CDS_TYPE_URL].reportStreamError(status); + this.adsState[RDS_TYPE_URL].reportStreamError(status); + this.adsState[LDS_TYPE_URL].reportStreamError(status); } private maybeStartLrsStream() { @@ -967,29 +1021,7 @@ export class XdsClient { watcher: Watcher ) { trace('Watcher added for endpoint ' + edsServiceName); - let watchersEntry = this.endpointWatchers.get(edsServiceName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.endpointWatchers.set(edsServiceName, watchersEntry); - } - watchersEntry.push(watcher); - if (addedServiceName) { - this.updateEdsNames(); - } - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - for (const message of this.latestEdsResponses) { - if (message.cluster_name === edsServiceName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - watcher.onValidUpdate(message); - }); - } - } + this.adsState[EDS_TYPE_URL].addWatcher(edsServiceName, watcher); } removeEndpointWatcher( @@ -997,67 +1029,17 @@ export class XdsClient { watcher: Watcher ) { trace('Watcher removed for endpoint ' + edsServiceName); - const watchersEntry = this.endpointWatchers.get(edsServiceName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.endpointWatchers.delete(edsServiceName); - } - } - if (removedServiceName) { - this.updateEdsNames(); - } + this.adsState[EDS_TYPE_URL].removeWatcher(edsServiceName, watcher); } addClusterWatcher(clusterName: string, watcher: Watcher) { trace('Watcher added for cluster ' + clusterName); - let watchersEntry = this.clusterWatchers.get(clusterName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.clusterWatchers.set(clusterName, watchersEntry); - } - watchersEntry.push(watcher); - if (addedServiceName) { - this.updateCdsNames(); - } - - /* If we have already received an update for the requested clusterName, - * immediately pass that update along to the watcher */ - for (const message of this.latestCdsResponses) { - if (message.name === clusterName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - watcher.onValidUpdate(message); - }); - } - } + this.adsState[CDS_TYPE_URL].addWatcher(clusterName, watcher); } removeClusterWatcher(clusterName: string, watcher: Watcher) { trace('Watcher removed for endpoint ' + clusterName); - const watchersEntry = this.clusterWatchers.get(clusterName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.endpointWatchers.delete(clusterName); - } - } - if (removedServiceName) { - this.updateCdsNames(); - } + this.adsState[CDS_TYPE_URL].removeWatcher(clusterName, watcher); } /** From 6c0012499ab7b6b252fdb2e46728c29cac923f0e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 Aug 2020 13:30:24 -0700 Subject: [PATCH 1195/1899] Implement onResourceDoesNotExist notifications --- packages/grpc-js/src/xds-client.ts | 51 ++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 4375c77a7..d29d29b8f 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -332,6 +332,22 @@ class EdsState implements XdsStreamState { return true; } + /** + * Given a list of edsServiceNames (which may actually be the cluster name), + * for each watcher watching a name not on the list, call that watcher's + * onResourceDoesNotExist method. + * @param allClusterNames + */ + handleMissingNames(allEdsServiceNames: Set) { + for (const [edsServiceName, watcherList] of this.watchers.entries()) { + if (!allEdsServiceNames.has(edsServiceName)) { + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + handleResponses(responses: ClusterLoadAssignment__Output[]) { for (const message of responses) { if (!this.validateResponse(message)) { @@ -339,12 +355,15 @@ class EdsState implements XdsStreamState { } } this.latestResponses = responses; + const allClusterNames: Set = new Set(); for (const message of responses) { + allClusterNames.add(message.cluster_name); const watchers = this.watchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { watcher.onValidUpdate(message); } } + this.handleMissingNames(allClusterNames); return null; } @@ -368,7 +387,10 @@ class CdsState implements XdsStreamState { private latestResponses: Cluster__Output[] = []; - constructor(private updateResourceNames: () => void) {} + constructor( + private edsState: EdsState, + private updateResourceNames: () => void + ) {} /** * Add the watcher to the watcher list. Returns true if the list of resource @@ -442,6 +464,22 @@ class CdsState implements XdsStreamState { return true; } + /** + * Given a list of edsServiceNames (which may actually be the cluster name), + * for each watcher watching a name not on the list, call that watcher's + * onResourceDoesNotExist method. + * @param allClusterNames + */ + private handleMissingNames(allClusterNames: Set) { + for (const [edsServiceName, watcherList] of this.watchers.entries()) { + if (!allClusterNames.has(edsServiceName)) { + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + handleResponses(responses: Cluster__Output[]): string | null { for (const message of responses) { if (!this.validateResponse(message)) { @@ -449,12 +487,21 @@ class CdsState implements XdsStreamState { } } this.latestResponses = responses; + const allEdsServiceNames: Set = new Set(); + const allClusterNames: Set = new Set(); for (const message of responses) { + allClusterNames.add(message.name); + const edsServiceName = message.eds_cluster_config?.service_name ?? ''; + allEdsServiceNames.add( + edsServiceName === '' ? message.name : edsServiceName + ); const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { watcher.onValidUpdate(message); } } + this.handleMissingNames(allClusterNames); + this.edsState.handleMissingNames(allEdsServiceNames); return null; } @@ -671,7 +718,7 @@ export class XdsClient { const edsState = new EdsState(() => { this.updateNames(EDS_TYPE_URL); }); - const cdsState = new CdsState(() => { + const cdsState = new CdsState(edsState, () => { this.updateNames(CDS_TYPE_URL); }); const rdsState = new RdsState(serviceConfigWatcher, () => { From bbff8cb449c6994f6b010b423b502ebc1edb64cc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 11:35:26 -0700 Subject: [PATCH 1196/1899] A few more service type fixes --- .../bin/proto-loader-gen-types.ts | 14 ++--- .../google/longrunning/Operations.ts | 50 ++++++++--------- .../google/showcase/v1beta1/Echo.ts | 54 +++++++++---------- packages/proto-loader/package.json | 2 +- 4 files changed, 60 insertions(+), 60 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index a01004ef8..83a91c8ee 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -476,8 +476,8 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P const callType = `grpc.ClientWritableStream<${responseType}>`; formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(callback: ${callbackType}): ${callType};`); } } else { if (method.responseStream) { @@ -490,8 +490,8 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P const callType = 'grpc.ClientUnaryCall'; formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, callback: ${callbackType}): ${callType};`); } } } @@ -505,15 +505,15 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: if (options.includeComments) { formatComment(formatter, serviceType.comment); } - formatter.writeLine(`export interface ${serviceType.name}Handlers {`); + formatter.writeLine(`export interface ${serviceType.name}Handlers extends grpc.UntypedServiceImplementation {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; if (options.includeComments) { formatComment(formatter, method.comment); } - const requestType = getTypeInterfaceName(method.resolvedRequestType!); - const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; + const requestType = getTypeInterfaceName(method.resolvedRequestType!) + '__Output'; + const responseType = getTypeInterfaceName(method.resolvedResponseType!); if (method.requestStream) { if (method.responseStream) { // Bidi streaming diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 64cc32ba9..d9db95847 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -36,8 +36,8 @@ export interface OperationsClient extends grpc.Client { */ CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; /** * Starts asynchronous cancellation on a long-running operation. The server * makes a best effort to cancel the operation, but success is not @@ -52,8 +52,8 @@ export interface OperationsClient extends grpc.Client { */ cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is @@ -63,8 +63,8 @@ export interface OperationsClient extends grpc.Client { */ DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is * no longer interested in the operation result. It does not cancel the @@ -73,8 +73,8 @@ export interface OperationsClient extends grpc.Client { */ deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this @@ -83,8 +83,8 @@ export interface OperationsClient extends grpc.Client { */ GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API @@ -92,8 +92,8 @@ export interface OperationsClient extends grpc.Client { */ getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; /** * Lists operations that match the specified filter in the request. If the @@ -109,8 +109,8 @@ export interface OperationsClient extends grpc.Client { */ ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; /** * Lists operations that match the specified filter in the request. If the * server doesn't support this method, it returns `UNIMPLEMENTED`. @@ -125,8 +125,8 @@ export interface OperationsClient extends grpc.Client { */ listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches @@ -141,8 +141,8 @@ export interface OperationsClient extends grpc.Client { */ WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches * at most a specified timeout, returning the latest state. If the operation @@ -156,8 +156,8 @@ export interface OperationsClient extends grpc.Client { */ waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; } @@ -185,7 +185,7 @@ export interface OperationsHandlers { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - CancelOperation(call: grpc.ServerUnaryCall<_google_longrunning_CancelOperationRequest, _google_protobuf_Empty__Output>, callback: grpc.sendUnaryData<_google_protobuf_Empty__Output>): void; + CancelOperation(call: grpc.ServerUnaryCall<_google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty>, callback: grpc.sendUnaryData<_google_protobuf_Empty>): void; /** * Deletes a long-running operation. This method indicates that the client is @@ -193,14 +193,14 @@ export interface OperationsHandlers { * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - DeleteOperation(call: grpc.ServerUnaryCall<_google_longrunning_DeleteOperationRequest, _google_protobuf_Empty__Output>, callback: grpc.sendUnaryData<_google_protobuf_Empty__Output>): void; + DeleteOperation(call: grpc.ServerUnaryCall<_google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty>, callback: grpc.sendUnaryData<_google_protobuf_Empty>): void; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - GetOperation(call: grpc.ServerUnaryCall<_google_longrunning_GetOperationRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + GetOperation(call: grpc.ServerUnaryCall<_google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation>, callback: grpc.sendUnaryData<_google_longrunning_Operation>): void; /** * Lists operations that match the specified filter in the request. If the @@ -214,7 +214,7 @@ export interface OperationsHandlers { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - ListOperations(call: grpc.ServerUnaryCall<_google_longrunning_ListOperationsRequest, _google_longrunning_ListOperationsResponse__Output>, callback: grpc.sendUnaryData<_google_longrunning_ListOperationsResponse__Output>): void; + ListOperations(call: grpc.ServerUnaryCall<_google_longrunning_ListOperationsRequest__Output, _google_longrunning_ListOperationsResponse>, callback: grpc.sendUnaryData<_google_longrunning_ListOperationsResponse>): void; /** * Waits for the specified long-running operation until it is done or reaches @@ -227,6 +227,6 @@ export interface OperationsHandlers { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - WaitOperation(call: grpc.ServerUnaryCall<_google_longrunning_WaitOperationRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + WaitOperation(call: grpc.ServerUnaryCall<_google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation>, callback: grpc.sendUnaryData<_google_longrunning_Operation>): void; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index e518665d5..d33ff1893 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -26,8 +26,8 @@ export interface EchoClient extends grpc.Client { */ Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; /** * This method will block (wait) for the requested amount of time * and then return the response or error. @@ -35,8 +35,8 @@ export interface EchoClient extends grpc.Client { */ block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; /** * This method, upon receiving a request on the stream, the same content will @@ -60,8 +60,8 @@ export interface EchoClient extends grpc.Client { */ Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings @@ -69,23 +69,23 @@ export interface EchoClient extends grpc.Client { */ collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; /** * This method simply echos the request. This method is showcases unary rpcs. */ Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; /** * This method simply echos the request. This method is showcases unary rpcs. */ echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; /** * This method split the given content into words and will pass each word back @@ -106,16 +106,16 @@ export interface EchoClient extends grpc.Client { */ PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; /** * This method will wait the requested amount of and then return. @@ -123,16 +123,16 @@ export interface EchoClient extends grpc.Client { */ Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; } @@ -149,43 +149,43 @@ export interface EchoHandlers { * and then return the response or error. * This method showcases how a client handles delays or retries. */ - Block(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_BlockRequest, _google_showcase_v1beta1_BlockResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_BlockResponse__Output>): void; + Block(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_BlockResponse>): void; /** * This method, upon receiving a request on the stream, the same content will * be passed back on the stream. This method showcases bidirectional * streaming rpcs. */ - Chat(call: grpc.ServerDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>): void; + Chat(call: grpc.ServerDuplexStream<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>): void; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse__Output>): void; + Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse>): void; /** * This method simply echos the request. This method is showcases unary rpcs. */ - Echo(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse__Output>): void; + Echo(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse>): void; /** * This method split the given content into words and will pass each word back * through the stream. This method showcases server-side streaming rpcs. */ - Expand(call: grpc.ServerWritableStream<_google_showcase_v1beta1_ExpandRequest, _google_showcase_v1beta1_EchoResponse__Output>): void; + Expand(call: grpc.ServerWritableStream<_google_showcase_v1beta1_ExpandRequest__Output, _google_showcase_v1beta1_EchoResponse>): void; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - PagedExpand(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_PagedExpandRequest, _google_showcase_v1beta1_PagedExpandResponse__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_PagedExpandResponse__Output>): void; + PagedExpand(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_PagedExpandRequest__Output, _google_showcase_v1beta1_PagedExpandResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_PagedExpandResponse>): void; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - Wait(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_WaitRequest, _google_longrunning_Operation__Output>, callback: grpc.sendUnaryData<_google_longrunning_Operation__Output>): void; + Wait(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation>, callback: grpc.sendUnaryData<_google_longrunning_Operation>): void; } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index a5fda1101..99443d715 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre12", + "version": "0.6.0-pre13", "author": "Google Inc.", "contributors": [ { From 471c59fa276013bcdb5d40343430b46fc0b5b23a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:18:58 -0700 Subject: [PATCH 1197/1899] Fix missing type argument in client streaming server handler --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- packages/proto-loader/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 83a91c8ee..0d71e5495 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -520,7 +520,7 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: formatter.writeLine(`${methodName}(call: grpc.ServerDuplexStream<${requestType}, ${responseType}>): void;`); } else { // Client streaming - formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); + formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}, ${responseType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); } } else { if (method.responseStream) { diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 99443d715..5751b4bae 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre13", + "version": "0.6.0-pre14", "author": "Google Inc.", "contributors": [ { From 7550c00a24e80b2dac56e15655842a6fe023c0e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:20:13 -0700 Subject: [PATCH 1198/1899] Regenerate golden files --- .../golden-generated/google/longrunning/Operations.ts | 2 +- .../golden-generated/google/showcase/v1beta1/Echo.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index d9db95847..1d1d2b070 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -172,7 +172,7 @@ export interface OperationsClient extends grpc.Client { * returns long-running operations should implement the `Operations` interface * so developers can have a consistent client experience. */ -export interface OperationsHandlers { +export interface OperationsHandlers extends grpc.UntypedServiceImplementation { /** * Starts asynchronous cancellation on a long-running operation. The server * makes a best effort to cancel the operation, but success is not diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index d33ff1893..eb4772a1d 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -143,7 +143,7 @@ export interface EchoClient extends grpc.Client { * paginated calls. Set the 'showcase-trailer' metadata key on any method * to have the values echoed in the response trailers. */ -export interface EchoHandlers { +export interface EchoHandlers extends grpc.UntypedServiceImplementation { /** * This method will block (wait) for the requested amount of time * and then return the response or error. @@ -163,7 +163,7 @@ export interface EchoHandlers { * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest__Output>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse>): void; + Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse>): void; /** * This method simply echos the request. This method is showcases unary rpcs. From cb63d6afcd1f5b88d565018cdbcfeff9a672f49f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:27:26 -0700 Subject: [PATCH 1199/1899] grpc-js: Add xDS interop client and associated generated code --- .../generated/grpc/testing/BoolValue.ts | 26 +++ .../generated/grpc/testing/EchoStatus.ts | 20 ++ .../interop/generated/grpc/testing/Empty.ts | 26 +++ .../generated/grpc/testing/GrpclbRouteType.ts | 24 ++ .../grpc/testing/LoadBalancerStatsRequest.ts | 24 ++ .../grpc/testing/LoadBalancerStatsResponse.ts | 40 ++++ .../grpc/testing/LoadBalancerStatsService.ts | 37 +++ .../interop/generated/grpc/testing/Payload.ts | 31 +++ .../generated/grpc/testing/PayloadType.ts | 11 + .../generated/grpc/testing/ReconnectInfo.ts | 22 ++ .../generated/grpc/testing/ReconnectParams.ts | 18 ++ .../grpc/testing/ReconnectService.ts | 40 ++++ .../grpc/testing/ResponseParameters.ts | 47 ++++ .../generated/grpc/testing/SimpleRequest.ts | 106 +++++++++ .../generated/grpc/testing/SimpleResponse.ts | 68 ++++++ .../grpc/testing/StreamingInputCallRequest.ts | 38 +++ .../testing/StreamingInputCallResponse.ts | 22 ++ .../testing/StreamingOutputCallRequest.ts | 56 +++++ .../testing/StreamingOutputCallResponse.ts | 23 ++ .../generated/grpc/testing/TestService.ts | 202 ++++++++++++++++ .../grpc/testing/UnimplementedService.ts | 38 +++ .../grpc/testing/XdsUpdateHealthService.ts | 38 +++ packages/grpc-js/interop/generated/test.ts | 60 +++++ .../grpc-js/interop/xds-interop-client.ts | 220 ++++++++++++++++++ 24 files changed, 1237 insertions(+) create mode 100644 packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/Empty.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/Payload.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/TestService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts create mode 100644 packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts create mode 100644 packages/grpc-js/interop/generated/test.ts create mode 100644 packages/grpc-js/interop/xds-interop-client.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts b/packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts new file mode 100644 index 000000000..a1e31ab33 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts @@ -0,0 +1,26 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * TODO(dgq): Go back to using well-known types once + * https://github.com/grpc/grpc/issues/6980 has been fixed. + * import "google/protobuf/wrappers.proto"; + */ +export interface BoolValue { + /** + * The bool value. + */ + 'value'?: (boolean); +} + +/** + * TODO(dgq): Go back to using well-known types once + * https://github.com/grpc/grpc/issues/6980 has been fixed. + * import "google/protobuf/wrappers.proto"; + */ +export interface BoolValue__Output { + /** + * The bool value. + */ + 'value': (boolean); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts b/packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts new file mode 100644 index 000000000..d5da75017 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts @@ -0,0 +1,20 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * A protobuf representation for grpc status. This is used by test + * clients to specify a status that the server should attempt to return. + */ +export interface EchoStatus { + 'code'?: (number); + 'message'?: (string); +} + +/** + * A protobuf representation for grpc status. This is used by test + * clients to specify a status that the server should attempt to return. + */ +export interface EchoStatus__Output { + 'code': (number); + 'message': (string); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/Empty.ts b/packages/grpc-js/interop/generated/grpc/testing/Empty.ts new file mode 100644 index 000000000..d79db52be --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/Empty.ts @@ -0,0 +1,26 @@ +// Original file: proto/grpc/testing/empty.proto + + +/** + * An empty message that you can re-use to avoid defining duplicated empty + * messages in your project. A typical example is to use it as argument or the + * return value of a service API. For instance: + * + * service Foo { + * rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; + * }; + */ +export interface Empty { +} + +/** + * An empty message that you can re-use to avoid defining duplicated empty + * messages in your project. A typical example is to use it as argument or the + * return value of a service API. For instance: + * + * service Foo { + * rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; + * }; + */ +export interface Empty__Output { +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts b/packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts new file mode 100644 index 000000000..8ab0146b7 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts @@ -0,0 +1,24 @@ +// Original file: proto/grpc/testing/messages.proto + +/** + * The type of route that a client took to reach a server w.r.t. gRPCLB. + * The server must fill in "fallback" if it detects that the RPC reached + * the server via the "gRPCLB fallback" path, and "backend" if it detects + * that the RPC reached the server via "gRPCLB backend" path (i.e. if it got + * the address of this server from the gRPCLB server BalanceLoad RPC). Exactly + * how this detection is done is context and server dependent. + */ +export enum GrpclbRouteType { + /** + * Server didn't detect the route that a client took to reach it. + */ + GRPCLB_ROUTE_TYPE_UNKNOWN = 0, + /** + * Indicates that a client reached a server via gRPCLB fallback. + */ + GRPCLB_ROUTE_TYPE_FALLBACK = 1, + /** + * Indicates that a client reached a server as a gRPCLB-given backend. + */ + GRPCLB_ROUTE_TYPE_BACKEND = 2, +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts new file mode 100644 index 000000000..189d871b0 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts @@ -0,0 +1,24 @@ +// Original file: proto/grpc/testing/messages.proto + + +export interface LoadBalancerStatsRequest { + /** + * Request stats for the next num_rpcs sent by client. + */ + 'num_rpcs'?: (number); + /** + * If num_rpcs have not completed within timeout_sec, return partial results. + */ + 'timeout_sec'?: (number); +} + +export interface LoadBalancerStatsRequest__Output { + /** + * Request stats for the next num_rpcs sent by client. + */ + 'num_rpcs': (number); + /** + * If num_rpcs have not completed within timeout_sec, return partial results. + */ + 'timeout_sec': (number); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts new file mode 100644 index 000000000..184a6e258 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts @@ -0,0 +1,40 @@ +// Original file: proto/grpc/testing/messages.proto + + +export interface _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer'?: ({[key: string]: number}); +} + +export interface _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer__Output { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer': ({[key: string]: number}); +} + +export interface LoadBalancerStatsResponse { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer'?: ({[key: string]: number}); + /** + * The number of RPCs that failed to record a remote peer. + */ + 'num_failures'?: (number); + 'rpcs_by_method'?: ({[key: string]: _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer}); +} + +export interface LoadBalancerStatsResponse__Output { + /** + * The number of completed RPCs for each peer. + */ + 'rpcs_by_peer': ({[key: string]: number}); + /** + * The number of RPCs that failed to record a remote peer. + */ + 'num_failures': (number); + 'rpcs_by_method'?: ({[key: string]: _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer__Output}); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts new file mode 100644 index 000000000..eece848b1 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -0,0 +1,37 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +import { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; +import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; + +/** + * A service used to obtain stats for verifying LB behavior. + */ +export interface LoadBalancerStatsServiceClient extends grpc.Client { + /** + * Gets the backend distribution for RPCs sent by a test client. + */ + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets the backend distribution for RPCs sent by a test client. + */ + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientStats(argument: _grpc_testing_LoadBalancerStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerStatsResponse__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service used to obtain stats for verifying LB behavior. + */ +export interface LoadBalancerStatsServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Gets the backend distribution for RPCs sent by a test client. + */ + GetClientStats(call: grpc.ServerUnaryCall<_grpc_testing_LoadBalancerStatsRequest__Output, _grpc_testing_LoadBalancerStatsResponse>, callback: grpc.sendUnaryData<_grpc_testing_LoadBalancerStatsResponse>): void; + +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/Payload.ts b/packages/grpc-js/interop/generated/grpc/testing/Payload.ts new file mode 100644 index 000000000..87fc0cf3d --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/Payload.ts @@ -0,0 +1,31 @@ +// Original file: proto/grpc/testing/messages.proto + +import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; + +/** + * A block of data, to simply increase gRPC message size. + */ +export interface Payload { + /** + * The type of data in body. + */ + 'type'?: (_grpc_testing_PayloadType | keyof typeof _grpc_testing_PayloadType); + /** + * Primary contents of payload. + */ + 'body'?: (Buffer | Uint8Array | string); +} + +/** + * A block of data, to simply increase gRPC message size. + */ +export interface Payload__Output { + /** + * The type of data in body. + */ + 'type': (keyof typeof _grpc_testing_PayloadType); + /** + * Primary contents of payload. + */ + 'body': (Buffer); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts b/packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts new file mode 100644 index 000000000..3cf9d375a --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts @@ -0,0 +1,11 @@ +// Original file: proto/grpc/testing/messages.proto + +/** + * The type of payload that should be returned. + */ +export enum PayloadType { + /** + * Compressable text format. + */ + COMPRESSABLE = 0, +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts b/packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts new file mode 100644 index 000000000..616de9ebf --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts @@ -0,0 +1,22 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * For reconnect interop test only. + * Server tells client whether its reconnects are following the spec and the + * reconnect backoffs it saw. + */ +export interface ReconnectInfo { + 'passed'?: (boolean); + 'backoff_ms'?: (number)[]; +} + +/** + * For reconnect interop test only. + * Server tells client whether its reconnects are following the spec and the + * reconnect backoffs it saw. + */ +export interface ReconnectInfo__Output { + 'passed': (boolean); + 'backoff_ms': (number)[]; +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts b/packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts new file mode 100644 index 000000000..1337b5688 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts @@ -0,0 +1,18 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * For reconnect interop test only. + * Client tells server what reconnection parameters it used. + */ +export interface ReconnectParams { + 'max_reconnect_backoff_ms'?: (number); +} + +/** + * For reconnect interop test only. + * Client tells server what reconnection parameters it used. + */ +export interface ReconnectParams__Output { + 'max_reconnect_backoff_ms': (number); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts b/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts new file mode 100644 index 000000000..3829506b9 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts @@ -0,0 +1,40 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import { ReconnectInfo as _grpc_testing_ReconnectInfo, ReconnectInfo__Output as _grpc_testing_ReconnectInfo__Output } from '../../grpc/testing/ReconnectInfo'; +import { ReconnectParams as _grpc_testing_ReconnectParams, ReconnectParams__Output as _grpc_testing_ReconnectParams__Output } from '../../grpc/testing/ReconnectParams'; + +/** + * A service used to control reconnect server. + */ +export interface ReconnectServiceClient extends grpc.Client { + Start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + Start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + Start(argument: _grpc_testing_ReconnectParams, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + Start(argument: _grpc_testing_ReconnectParams, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + start(argument: _grpc_testing_ReconnectParams, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + + Stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + Stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + Stop(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + Stop(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + stop(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ReconnectInfo__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service used to control reconnect server. + */ +export interface ReconnectServiceHandlers extends grpc.UntypedServiceImplementation { + Start(call: grpc.ServerUnaryCall<_grpc_testing_ReconnectParams__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + + Stop(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_ReconnectInfo>, callback: grpc.sendUnaryData<_grpc_testing_ReconnectInfo>): void; + +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts b/packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts new file mode 100644 index 000000000..9bd24ee3b --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts @@ -0,0 +1,47 @@ +// Original file: proto/grpc/testing/messages.proto + +import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; + +/** + * Configuration for a particular response. + */ +export interface ResponseParameters { + /** + * Desired payload sizes in responses from the server. + */ + 'size'?: (number); + /** + * Desired interval between consecutive responses in the response stream in + * microseconds. + */ + 'interval_us'?: (number); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'compressed'?: (_grpc_testing_BoolValue); +} + +/** + * Configuration for a particular response. + */ +export interface ResponseParameters__Output { + /** + * Desired payload sizes in responses from the server. + */ + 'size': (number); + /** + * Desired interval between consecutive responses in the response stream in + * microseconds. + */ + 'interval_us': (number); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'compressed'?: (_grpc_testing_BoolValue__Output); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts new file mode 100644 index 000000000..b03f6f6dc --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts @@ -0,0 +1,106 @@ +// Original file: proto/grpc/testing/messages.proto + +import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; +import { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; + +/** + * Unary request. + */ +export interface SimpleRequest { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, server randomly chooses one from other formats. + */ + 'response_type'?: (_grpc_testing_PayloadType | keyof typeof _grpc_testing_PayloadType); + /** + * Desired payload size in the response from the server. + */ + 'response_size'?: (number); + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * Whether SimpleResponse should include username. + */ + 'fill_username'?: (boolean); + /** + * Whether SimpleResponse should include OAuth scope. + */ + 'fill_oauth_scope'?: (boolean); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'response_compressed'?: (_grpc_testing_BoolValue); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus); + /** + * Whether the server should expect this request to be compressed. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue); + /** + * Whether SimpleResponse should include server_id. + */ + 'fill_server_id'?: (boolean); + /** + * Whether SimpleResponse should include grpclb_route_type. + */ + 'fill_grpclb_route_type'?: (boolean); +} + +/** + * Unary request. + */ +export interface SimpleRequest__Output { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, server randomly chooses one from other formats. + */ + 'response_type': (keyof typeof _grpc_testing_PayloadType); + /** + * Desired payload size in the response from the server. + */ + 'response_size': (number); + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * Whether SimpleResponse should include username. + */ + 'fill_username': (boolean); + /** + * Whether SimpleResponse should include OAuth scope. + */ + 'fill_oauth_scope': (boolean); + /** + * Whether to request the server to compress the response. This field is + * "nullable" in order to interoperate seamlessly with clients not able to + * implement the full compression tests by introspecting the call to verify + * the response's compression status. + */ + 'response_compressed'?: (_grpc_testing_BoolValue__Output); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus__Output); + /** + * Whether the server should expect this request to be compressed. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue__Output); + /** + * Whether SimpleResponse should include server_id. + */ + 'fill_server_id': (boolean); + /** + * Whether SimpleResponse should include grpclb_route_type. + */ + 'fill_grpclb_route_type': (boolean); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts new file mode 100644 index 000000000..7a96e7dfc --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts @@ -0,0 +1,68 @@ +// Original file: proto/grpc/testing/messages.proto + +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { GrpclbRouteType as _grpc_testing_GrpclbRouteType } from '../../grpc/testing/GrpclbRouteType'; + +/** + * Unary response, as configured by the request. + */ +export interface SimpleResponse { + /** + * Payload to increase message size. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * The user the request came from, for verifying authentication was + * successful when the client expected it. + */ + 'username'?: (string); + /** + * OAuth scope. + */ + 'oauth_scope'?: (string); + /** + * Server ID. This must be unique among different server instances, + * but the same across all RPC's made to a particular server instance. + */ + 'server_id'?: (string); + /** + * gRPCLB Path. + */ + 'grpclb_route_type'?: (_grpc_testing_GrpclbRouteType | keyof typeof _grpc_testing_GrpclbRouteType); + /** + * Server hostname. + */ + 'hostname'?: (string); +} + +/** + * Unary response, as configured by the request. + */ +export interface SimpleResponse__Output { + /** + * Payload to increase message size. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * The user the request came from, for verifying authentication was + * successful when the client expected it. + */ + 'username': (string); + /** + * OAuth scope. + */ + 'oauth_scope': (string); + /** + * Server ID. This must be unique among different server instances, + * but the same across all RPC's made to a particular server instance. + */ + 'server_id': (string); + /** + * gRPCLB Path. + */ + 'grpclb_route_type': (keyof typeof _grpc_testing_GrpclbRouteType); + /** + * Server hostname. + */ + 'hostname': (string); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts new file mode 100644 index 000000000..db9d8d40c --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/messages.proto + +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; + +/** + * Client-streaming request. + */ +export interface StreamingInputCallRequest { + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * Whether the server should expect this request to be compressed. This field + * is "nullable" in order to interoperate seamlessly with servers not able to + * implement the full compression tests by introspecting the call to verify + * the request's compression status. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue); +} + +/** + * Client-streaming request. + */ +export interface StreamingInputCallRequest__Output { + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * Whether the server should expect this request to be compressed. This field + * is "nullable" in order to interoperate seamlessly with servers not able to + * implement the full compression tests by introspecting the call to verify + * the request's compression status. + */ + 'expect_compressed'?: (_grpc_testing_BoolValue__Output); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts new file mode 100644 index 000000000..1703e755e --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts @@ -0,0 +1,22 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Client-streaming response. + */ +export interface StreamingInputCallResponse { + /** + * Aggregated size of payloads received from the client. + */ + 'aggregated_payload_size'?: (number); +} + +/** + * Client-streaming response. + */ +export interface StreamingInputCallResponse__Output { + /** + * Aggregated size of payloads received from the client. + */ + 'aggregated_payload_size': (number); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts new file mode 100644 index 000000000..0d7bff2f1 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts @@ -0,0 +1,56 @@ +// Original file: proto/grpc/testing/messages.proto + +import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import { ResponseParameters as _grpc_testing_ResponseParameters, ResponseParameters__Output as _grpc_testing_ResponseParameters__Output } from '../../grpc/testing/ResponseParameters'; +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; + +/** + * Server-streaming request. + */ +export interface StreamingOutputCallRequest { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, the payload from each response in the stream + * might be of different types. This is to simulate a mixed type of payload + * stream. + */ + 'response_type'?: (_grpc_testing_PayloadType | keyof typeof _grpc_testing_PayloadType); + /** + * Configuration for each expected response message. + */ + 'response_parameters'?: (_grpc_testing_ResponseParameters)[]; + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus); +} + +/** + * Server-streaming request. + */ +export interface StreamingOutputCallRequest__Output { + /** + * Desired payload type in the response from the server. + * If response_type is RANDOM, the payload from each response in the stream + * might be of different types. This is to simulate a mixed type of payload + * stream. + */ + 'response_type': (keyof typeof _grpc_testing_PayloadType); + /** + * Configuration for each expected response message. + */ + 'response_parameters': (_grpc_testing_ResponseParameters__Output)[]; + /** + * Optional input payload sent along with the request. + */ + 'payload'?: (_grpc_testing_Payload__Output); + /** + * Whether server should return a given status + */ + 'response_status'?: (_grpc_testing_EchoStatus__Output); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts b/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts new file mode 100644 index 000000000..9b8f49e38 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts @@ -0,0 +1,23 @@ +// Original file: proto/grpc/testing/messages.proto + +import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; + +/** + * Server-streaming response, as configured by the request and parameters. + */ +export interface StreamingOutputCallResponse { + /** + * Payload to increase response size. + */ + 'payload'?: (_grpc_testing_Payload); +} + +/** + * Server-streaming response, as configured by the request and parameters. + */ +export interface StreamingOutputCallResponse__Output { + /** + * Payload to increase response size. + */ + 'payload'?: (_grpc_testing_Payload__Output); +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/TestService.ts b/packages/grpc-js/interop/generated/grpc/testing/TestService.ts new file mode 100644 index 000000000..b95b7a979 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/TestService.ts @@ -0,0 +1,202 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; +import { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; +import { StreamingInputCallRequest as _grpc_testing_StreamingInputCallRequest, StreamingInputCallRequest__Output as _grpc_testing_StreamingInputCallRequest__Output } from '../../grpc/testing/StreamingInputCallRequest'; +import { StreamingInputCallResponse as _grpc_testing_StreamingInputCallResponse, StreamingInputCallResponse__Output as _grpc_testing_StreamingInputCallResponse__Output } from '../../grpc/testing/StreamingInputCallResponse'; +import { StreamingOutputCallRequest as _grpc_testing_StreamingOutputCallRequest, StreamingOutputCallRequest__Output as _grpc_testing_StreamingOutputCallRequest__Output } from '../../grpc/testing/StreamingOutputCallRequest'; +import { StreamingOutputCallResponse as _grpc_testing_StreamingOutputCallResponse, StreamingOutputCallResponse__Output as _grpc_testing_StreamingOutputCallResponse__Output } from '../../grpc/testing/StreamingOutputCallResponse'; + +/** + * A simple service to test the various types of RPCs and experiment with + * performance with various types of payload. + */ +export interface TestServiceClient extends grpc.Client { + /** + * One request followed by one response. Response has cache control + * headers set such that a caching HTTP proxy (such as GFE) can + * satisfy subsequent requests. + */ + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + CacheableUnaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + /** + * One request followed by one response. Response has cache control + * headers set such that a caching HTTP proxy (such as GFE) can + * satisfy subsequent requests. + */ + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + cacheableUnaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * One empty request followed by one empty response. + */ + EmptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + EmptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + EmptyCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + EmptyCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * One empty request followed by one empty response. + */ + emptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + emptyCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + emptyCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + emptyCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + + /** + * A sequence of requests with each request served by the server immediately. + * As one request could lead to multiple responses, this interface + * demonstrates the idea of full duplexing. + */ + FullDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + FullDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + /** + * A sequence of requests with each request served by the server immediately. + * As one request could lead to multiple responses, this interface + * demonstrates the idea of full duplexing. + */ + fullDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + fullDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + + /** + * A sequence of requests followed by a sequence of responses. + * The server buffers all the client requests and then serves them in order. A + * stream of responses are returned to the client when the server starts with + * first request. + */ + HalfDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + HalfDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + /** + * A sequence of requests followed by a sequence of responses. + * The server buffers all the client requests and then serves them in order. A + * stream of responses are returned to the client when the server starts with + * first request. + */ + halfDuplexCall(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + halfDuplexCall(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_StreamingOutputCallRequest, _grpc_testing_StreamingOutputCallResponse__Output>; + + /** + * A sequence of requests followed by one response (streamed upload). + * The server returns the aggregated size of client payload as the result. + */ + StreamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + /** + * A sequence of requests followed by one response (streamed upload). + * The server returns the aggregated size of client payload as the result. + */ + streamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + + /** + * One request followed by a sequence of responses (streamed download). + * The server returns the payload with client desired type and sizes. + */ + StreamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + StreamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + /** + * One request followed by a sequence of responses (streamed download). + * The server returns the payload with client desired type and sizes. + */ + streamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + streamingOutputCall(argument: _grpc_testing_StreamingOutputCallRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_StreamingOutputCallResponse__Output>; + + /** + * One request followed by one response. + */ + UnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + UnaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + UnaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + UnaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + /** + * One request followed by one response. + */ + unaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + unaryCall(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + unaryCall(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + unaryCall(argument: _grpc_testing_SimpleRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_SimpleResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * The test server will not implement this method. It will be used + * to test the behavior when clients call unimplemented methods. + */ + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * The test server will not implement this method. It will be used + * to test the behavior when clients call unimplemented methods. + */ + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A simple service to test the various types of RPCs and experiment with + * performance with various types of payload. + */ +export interface TestServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * One request followed by one response. Response has cache control + * headers set such that a caching HTTP proxy (such as GFE) can + * satisfy subsequent requests. + */ + CacheableUnaryCall(call: grpc.ServerUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>, callback: grpc.sendUnaryData<_grpc_testing_SimpleResponse>): void; + + /** + * One empty request followed by one empty response. + */ + EmptyCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + + /** + * A sequence of requests with each request served by the server immediately. + * As one request could lead to multiple responses, this interface + * demonstrates the idea of full duplexing. + */ + FullDuplexCall(call: grpc.ServerDuplexStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + + /** + * A sequence of requests followed by a sequence of responses. + * The server buffers all the client requests and then serves them in order. A + * stream of responses are returned to the client when the server starts with + * first request. + */ + HalfDuplexCall(call: grpc.ServerDuplexStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + + /** + * A sequence of requests followed by one response (streamed upload). + * The server returns the aggregated size of client payload as the result. + */ + StreamingInputCall(call: grpc.ServerReadableStream<_grpc_testing_StreamingInputCallRequest__Output, _grpc_testing_StreamingInputCallResponse>, callback: grpc.sendUnaryData<_grpc_testing_StreamingInputCallResponse>): void; + + /** + * One request followed by a sequence of responses (streamed download). + * The server returns the payload with client desired type and sizes. + */ + StreamingOutputCall(call: grpc.ServerWritableStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + + /** + * One request followed by one response. + */ + UnaryCall(call: grpc.ServerUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>, callback: grpc.sendUnaryData<_grpc_testing_SimpleResponse>): void; + + /** + * The test server will not implement this method. It will be used + * to test the behavior when clients call unimplemented methods. + */ + UnimplementedCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts b/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts new file mode 100644 index 000000000..afbf91173 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; + +/** + * A simple service NOT implemented at servers so clients can test for + * that case. + */ +export interface UnimplementedServiceClient extends grpc.Client { + /** + * A call that no server should implement + */ + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + UnimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + /** + * A call that no server should implement + */ + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + unimplementedCall(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A simple service NOT implemented at servers so clients can test for + * that case. + */ +export interface UnimplementedServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * A call that no server should implement + */ + UnimplementedCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + +} diff --git a/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts b/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts new file mode 100644 index 000000000..f27a461e3 --- /dev/null +++ b/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts @@ -0,0 +1,38 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '../../../../src' +import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; + +/** + * A service to remotely control health status of an xDS test server. + */ +export interface XdsUpdateHealthServiceClient extends grpc.Client { + SetNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetNotServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetNotServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setNotServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + + SetServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + SetServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + setServing(argument: _grpc_testing_Empty, callback: (error?: grpc.ServiceError, result?: _grpc_testing_Empty__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service to remotely control health status of an xDS test server. + */ +export interface XdsUpdateHealthServiceHandlers extends grpc.UntypedServiceImplementation { + SetNotServing(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + + SetServing(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + +} diff --git a/packages/grpc-js/interop/generated/test.ts b/packages/grpc-js/interop/generated/test.ts new file mode 100644 index 000000000..a5c95d951 --- /dev/null +++ b/packages/grpc-js/interop/generated/test.ts @@ -0,0 +1,60 @@ +import * as grpc from '../../src'; +import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServiceClient } from './grpc/testing/LoadBalancerStatsService'; +import { ReconnectServiceClient as _grpc_testing_ReconnectServiceClient } from './grpc/testing/ReconnectService'; +import { TestServiceClient as _grpc_testing_TestServiceClient } from './grpc/testing/TestService'; +import { UnimplementedServiceClient as _grpc_testing_UnimplementedServiceClient } from './grpc/testing/UnimplementedService'; +import { XdsUpdateHealthServiceClient as _grpc_testing_XdsUpdateHealthServiceClient } from './grpc/testing/XdsUpdateHealthService'; + +type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; +type SubtypeConstructor = { + new(...args: ConstructorArguments): Subtype; +}; + +export interface ProtoGrpcType { + grpc: { + testing: { + BoolValue: MessageTypeDefinition + EchoStatus: MessageTypeDefinition + Empty: MessageTypeDefinition + GrpclbRouteType: EnumTypeDefinition + LoadBalancerStatsRequest: MessageTypeDefinition + LoadBalancerStatsResponse: MessageTypeDefinition + /** + * A service used to obtain stats for verifying LB behavior. + */ + LoadBalancerStatsService: SubtypeConstructor & { service: ServiceDefinition } + Payload: MessageTypeDefinition + PayloadType: EnumTypeDefinition + ReconnectInfo: MessageTypeDefinition + ReconnectParams: MessageTypeDefinition + /** + * A service used to control reconnect server. + */ + ReconnectService: SubtypeConstructor & { service: ServiceDefinition } + ResponseParameters: MessageTypeDefinition + SimpleRequest: MessageTypeDefinition + SimpleResponse: MessageTypeDefinition + StreamingInputCallRequest: MessageTypeDefinition + StreamingInputCallResponse: MessageTypeDefinition + StreamingOutputCallRequest: MessageTypeDefinition + StreamingOutputCallResponse: MessageTypeDefinition + /** + * A simple service to test the various types of RPCs and experiment with + * performance with various types of payload. + */ + TestService: SubtypeConstructor & { service: ServiceDefinition } + /** + * A simple service NOT implemented at servers so clients can test for + * that case. + */ + UnimplementedService: SubtypeConstructor & { service: ServiceDefinition } + /** + * A service to remotely control health status of an xDS test server. + */ + XdsUpdateHealthService: SubtypeConstructor & { service: ServiceDefinition } + } + } +} + diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts new file mode 100644 index 000000000..e056fb08f --- /dev/null +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -0,0 +1,220 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as grpc from '../src'; + +import { ProtoGrpcType } from './generated/test'; + +import * as protoLoader from '@grpc/proto-loader'; +import { TestServiceClient } from './generated/grpc/testing/TestService'; +import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancerStatsResponse'; +import * as yargs from 'yargs'; +import { LoadBalancerStatsServiceHandlers } from './generated/grpc/testing/LoadBalancerStatsService'; + +const packageDefinition = protoLoader.loadSync('grpc/testing/test.proto', { + keepCase: true, + defaults: true, + oneofs: true, + json: true, + longs: String, + enums: String, + includeDirs: [__dirname + '/../../proto'] +}); + +const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as ProtoGrpcType; + +interface CallEndNotifier { + onCallSucceeded(peerName: string): void; + onCallFailed(): void; +} + +class CallSubscriber { + private callsStarted = 0; + private callsSucceededByPeer: {[key: string]: number} = {}; + private callsSucceeded = 0; + private callsFinished = 0; + + constructor(private callGoal: number, private onFinished: () => void) {} + + addCallStarted(): void { + this.callsStarted += 1; + } + + private maybeOnFinished() { + if (this.callsFinished == this.callGoal) { + this.onFinished(); + } + } + + addCallSucceeded(peerName: string): void { + if (peerName in this.callsSucceededByPeer) { + this.callsSucceededByPeer[peerName] += 1; + } else { + this.callsSucceededByPeer[peerName] = 1; + } + this.callsSucceeded += 1; + this.callsFinished += 1; + this.maybeOnFinished(); + } + addCallFailed(): void { + this.callsFinished += 1; + this.maybeOnFinished(); + } + + needsMoreCalls(): boolean { + return this.callsStarted < this.callGoal; + } + + getFinalStats(): LoadBalancerStatsResponse { + return { + rpcs_by_peer: this.callsSucceededByPeer, + num_failures: this.callsStarted - this.callsSucceeded + }; + } +} + +class CallStatsTracker { + + private subscribers: CallSubscriber[] = []; + + getCallStats(callCount: number, timeoutSec: number): Promise { + return new Promise((resolve, reject) => { + let finished = false; + const subscriber = new CallSubscriber(callCount, () => { + if (!finished) { + finished = true; + resolve(subscriber.getFinalStats()); + } + }); + setTimeout(() => { + if (!finished) { + finished = true; + this.subscribers.splice(this.subscribers.indexOf(subscriber), 1); + resolve(subscriber.getFinalStats()); + } + }, timeoutSec * 1000) + this.subscribers.push(subscriber); + }) + } + + startCall(): CallEndNotifier { + const callSubscribers = this.subscribers.slice(); + for (const subscriber of callSubscribers) { + subscriber.addCallStarted(); + if (!subscriber.needsMoreCalls()) { + this.subscribers.splice(this.subscribers.indexOf(subscriber), 1); + } + } + return { + onCallSucceeded: (peerName: string) => { + for (const subscriber of callSubscribers) { + subscriber.addCallSucceeded(peerName); + } + }, + onCallFailed: () => { + for (const subscriber of callSubscribers) { + subscriber.addCallFailed(); + } + } + } + } +} + +function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + let anyCallSucceeded: boolean = false; + setInterval(() => { + const notifier = callStatsTracker.startCall(); + let gotMetadata: boolean = false; + let hostname: string | null = null; + let completed: boolean = false; + let completedWithError: boolean = false; + const call = client.emptyCall({}, (error, value) => { + if (error) { + if (failOnFailedRpcs && anyCallSucceeded) { + console.error('A call failed after a call succeeded'); + process.exit(1); + } + completed = true; + completedWithError = true; + notifier.onCallFailed(); + } else { + anyCallSucceeded = true; + if (gotMetadata) { + if (hostname === null) { + notifier.onCallFailed() + } else { + notifier.onCallSucceeded(hostname); + } + } + } + }); + call.on('metadata', (metadata) => { + hostname = (metadata.get('hostname') as string[])[0] ?? null; + gotMetadata = true; + if (completed && !completedWithError) { + if (hostname === null) { + notifier.onCallFailed(); + } else { + notifier.onCallSucceeded(hostname); + } + } + }) + }, 1000/qps); +} + + + +function main() { + const argv = yargs + .string(['fail_on_failed_rpcs', 'server', 'stats_port']) + .number(['num_channels', 'qps']) + .require(['fail_on_failed_rpcs', 'num_channels', 'qps', 'server', 'stats_port']) + .argv; + const callStatsTracker = new CallStatsTracker(); + for (let i = 0; i < argv.num_channels; i++) { + /* The 'unique' channel argument is there solely to ensure that the + * channels do not share any subchannels. It does not have any + * inherent function. */ + sendConstantQps(new loadedProto.grpc.testing.TestService(argv.server, grpc.credentials.createInsecure(), {'unique': i}), + argv.qps, + argv.fail_on_failed_rpcs === 'true', + callStatsTracker); + } + + const loadBalancerStatsServiceImpl: LoadBalancerStatsServiceHandlers = { + GetClientStats: (call, callback) => { + callStatsTracker.getCallStats(call.request.num_rpcs, call.request.timeout_sec).then((value) => { + callback(null, value); + }, (error) => { + callback({code: grpc.status.ABORTED, details: 'Call stats collection failed'}); + }); + } + } + + const server = new grpc.Server(); + server.addService(loadedProto.grpc.testing.LoadBalancerStatsService.service, loadBalancerStatsServiceImpl); + server.bindAsync(`0.0.0.0:${argv.stats_port}`, grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + throw error; + } + server.start(); + }); +} + +if (require.main === module) { + main(); +} \ No newline at end of file From 409ad9502024519788ca1a32085cac64d6c1b536 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:48:42 -0700 Subject: [PATCH 1200/1899] Add dependencies for xDS, plus some fixes --- packages/grpc-js/package.json | 9 ++++++--- .../src/load-balancer-weighted-target.ts | 2 +- packages/grpc-js/src/server-call.ts | 18 ++++++++---------- packages/grpc-js/src/server.ts | 19 ++++++++++--------- packages/grpc-js/tsconfig.json | 3 ++- 5 files changed, 27 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ee910cfb6..b4c2d2856 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,6 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre6", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -24,9 +23,9 @@ "@types/node": "^12.7.5", "@types/pify": "^3.0.2", "@types/semver": "^6.0.1", + "@types/yargs": "^15.0.5", "clang-format": "^1.0.55", "execa": "^2.0.3", - "google-auth-library": "^6.0.0", "gts": "^2.0.0", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", @@ -36,7 +35,8 @@ "pify": "^4.0.1", "rimraf": "^3.0.2", "ts-node": "^8.3.0", - "typescript": "^3.7.2" + "typescript": "^3.7.2", + "yargs": "^15.4.1" }, "contributors": [ { @@ -49,6 +49,7 @@ "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto", + "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib ../../src grpc/testing/test.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", @@ -58,6 +59,8 @@ "posttest": "npm run check" }, "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14", + "google-auth-library": "^5.10.1", "semver": "^6.2.0" }, "files": [ diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts index 041459140..e8a5fe65a 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -229,7 +229,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { picker = new WeightedTargetPicker(pickerList); break; case ConnectivityState.CONNECTING: - case ConnectivityState.READY: + case ConnectivityState.IDLE: picker = new QueuePicker(this); break; default: diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d885173..2a75f01e3 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -81,7 +81,7 @@ export type ServerSurfaceCall = { } & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { - request: RequestType | null; + request: RequestType; }; export type ServerReadableStream< RequestType, @@ -91,7 +91,7 @@ export type ServerWritableStream< RequestType, ResponseType > = ServerSurfaceCall & - ObjectWritable & { request: RequestType | null }; + ObjectWritable & { request: RequestType }; export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & ObjectWritable; @@ -99,15 +99,14 @@ export type ServerDuplexStream = ServerSurfaceCall & export class ServerUnaryCallImpl extends EventEmitter implements ServerUnaryCall { cancelled: boolean; - request: RequestType | null; constructor( private call: Http2ServerCallStream, - public metadata: Metadata + public metadata: Metadata, + public request: RequestType ) { super(); this.cancelled = false; - this.request = null; this.call.setupSurfaceCall(this); } @@ -157,17 +156,16 @@ export class ServerWritableStreamImpl extends Writable implements ServerWritableStream { cancelled: boolean; - request: RequestType | null; private trailingMetadata: Metadata; constructor( private call: Http2ServerCallStream, public metadata: Metadata, - public serialize: Serialize + public serialize: Serialize, + public request: RequestType ) { super({ objectMode: true }); this.cancelled = false; - this.request = null; this.trailingMetadata = new Metadata(); this.call.setupSurfaceCall(this); @@ -268,7 +266,7 @@ ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; // Unary response callback signature. export type sendUnaryData = ( error: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) => void; @@ -506,7 +504,7 @@ export class Http2ServerCallStream< async sendUnaryMessage( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, metadata?: Metadata, flags?: number ) { diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 683198c59..8fdacd4db 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -622,22 +622,23 @@ async function handleUnary( handler: UnaryHandler, metadata: Metadata ): Promise { - const emitter = new ServerUnaryCallImpl( - call, - metadata - ); const request = await call.receiveUnaryMessage(); if (request === undefined || call.cancelled) { return; } + + const emitter = new ServerUnaryCallImpl( + call, + metadata, + request + ); - emitter.request = request; handler.func( emitter, ( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) => { @@ -659,7 +660,7 @@ function handleClientStreaming( function respond( err: ServerErrorResponse | ServerStatusResponse | null, - value: ResponseType | null, + value?: ResponseType | null, trailer?: Metadata, flags?: number ) { @@ -689,10 +690,10 @@ async function handleServerStreaming( const stream = new ServerWritableStreamImpl( call, metadata, - handler.serialize + handler.serialize, + request ); - stream.request = request; handler.func(stream); } diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index ba675db78..65ebf089e 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -10,6 +10,7 @@ }, "include": [ "src/**/*.ts", - "test/**/*.ts" + "test/**/*.ts", + "interop/**/*.ts" ] } From 94a4779bb68462c0175e02939ebb3513c8ba3d65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:49:24 -0700 Subject: [PATCH 1201/1899] Add xDS interop proto files --- .../grpc-js/proto/grpc/testing/empty.proto | 28 +++ .../grpc-js/proto/grpc/testing/messages.proto | 214 ++++++++++++++++++ .../grpc-js/proto/grpc/testing/test.proto | 92 ++++++++ 3 files changed, 334 insertions(+) create mode 100644 packages/grpc-js/proto/grpc/testing/empty.proto create mode 100644 packages/grpc-js/proto/grpc/testing/messages.proto create mode 100644 packages/grpc-js/proto/grpc/testing/test.proto diff --git a/packages/grpc-js/proto/grpc/testing/empty.proto b/packages/grpc-js/proto/grpc/testing/empty.proto new file mode 100644 index 000000000..6a0aa88df --- /dev/null +++ b/packages/grpc-js/proto/grpc/testing/empty.proto @@ -0,0 +1,28 @@ + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +// An empty message that you can re-use to avoid defining duplicated empty +// messages in your project. A typical example is to use it as argument or the +// return value of a service API. For instance: +// +// service Foo { +// rpc Bar (grpc.testing.Empty) returns (grpc.testing.Empty) { }; +// }; +// +message Empty {} diff --git a/packages/grpc-js/proto/grpc/testing/messages.proto b/packages/grpc-js/proto/grpc/testing/messages.proto new file mode 100644 index 000000000..70e342776 --- /dev/null +++ b/packages/grpc-js/proto/grpc/testing/messages.proto @@ -0,0 +1,214 @@ + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Message definitions to be used by integration test service definitions. + +syntax = "proto3"; + +package grpc.testing; + +// TODO(dgq): Go back to using well-known types once +// https://github.com/grpc/grpc/issues/6980 has been fixed. +// import "google/protobuf/wrappers.proto"; +message BoolValue { + // The bool value. + bool value = 1; +} + +// The type of payload that should be returned. +enum PayloadType { + // Compressable text format. + COMPRESSABLE = 0; +} + +// A block of data, to simply increase gRPC message size. +message Payload { + // The type of data in body. + PayloadType type = 1; + // Primary contents of payload. + bytes body = 2; +} + +// A protobuf representation for grpc status. This is used by test +// clients to specify a status that the server should attempt to return. +message EchoStatus { + int32 code = 1; + string message = 2; +} + +// The type of route that a client took to reach a server w.r.t. gRPCLB. +// The server must fill in "fallback" if it detects that the RPC reached +// the server via the "gRPCLB fallback" path, and "backend" if it detects +// that the RPC reached the server via "gRPCLB backend" path (i.e. if it got +// the address of this server from the gRPCLB server BalanceLoad RPC). Exactly +// how this detection is done is context and server dependent. +enum GrpclbRouteType { + // Server didn't detect the route that a client took to reach it. + GRPCLB_ROUTE_TYPE_UNKNOWN = 0; + // Indicates that a client reached a server via gRPCLB fallback. + GRPCLB_ROUTE_TYPE_FALLBACK = 1; + // Indicates that a client reached a server as a gRPCLB-given backend. + GRPCLB_ROUTE_TYPE_BACKEND = 2; +} + +// Unary request. +message SimpleRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, server randomly chooses one from other formats. + PayloadType response_type = 1; + + // Desired payload size in the response from the server. + int32 response_size = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether SimpleResponse should include username. + bool fill_username = 4; + + // Whether SimpleResponse should include OAuth scope. + bool fill_oauth_scope = 5; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue response_compressed = 6; + + // Whether server should return a given status + EchoStatus response_status = 7; + + // Whether the server should expect this request to be compressed. + BoolValue expect_compressed = 8; + + // Whether SimpleResponse should include server_id. + bool fill_server_id = 9; + + // Whether SimpleResponse should include grpclb_route_type. + bool fill_grpclb_route_type = 10; +} + +// Unary response, as configured by the request. +message SimpleResponse { + // Payload to increase message size. + Payload payload = 1; + // The user the request came from, for verifying authentication was + // successful when the client expected it. + string username = 2; + // OAuth scope. + string oauth_scope = 3; + + // Server ID. This must be unique among different server instances, + // but the same across all RPC's made to a particular server instance. + string server_id = 4; + // gRPCLB Path. + GrpclbRouteType grpclb_route_type = 5; + + // Server hostname. + string hostname = 6; +} + +// Client-streaming request. +message StreamingInputCallRequest { + // Optional input payload sent along with the request. + Payload payload = 1; + + // Whether the server should expect this request to be compressed. This field + // is "nullable" in order to interoperate seamlessly with servers not able to + // implement the full compression tests by introspecting the call to verify + // the request's compression status. + BoolValue expect_compressed = 2; + + // Not expecting any payload from the response. +} + +// Client-streaming response. +message StreamingInputCallResponse { + // Aggregated size of payloads received from the client. + int32 aggregated_payload_size = 1; +} + +// Configuration for a particular response. +message ResponseParameters { + // Desired payload sizes in responses from the server. + int32 size = 1; + + // Desired interval between consecutive responses in the response stream in + // microseconds. + int32 interval_us = 2; + + // Whether to request the server to compress the response. This field is + // "nullable" in order to interoperate seamlessly with clients not able to + // implement the full compression tests by introspecting the call to verify + // the response's compression status. + BoolValue compressed = 3; +} + +// Server-streaming request. +message StreamingOutputCallRequest { + // Desired payload type in the response from the server. + // If response_type is RANDOM, the payload from each response in the stream + // might be of different types. This is to simulate a mixed type of payload + // stream. + PayloadType response_type = 1; + + // Configuration for each expected response message. + repeated ResponseParameters response_parameters = 2; + + // Optional input payload sent along with the request. + Payload payload = 3; + + // Whether server should return a given status + EchoStatus response_status = 7; +} + +// Server-streaming response, as configured by the request and parameters. +message StreamingOutputCallResponse { + // Payload to increase response size. + Payload payload = 1; +} + +// For reconnect interop test only. +// Client tells server what reconnection parameters it used. +message ReconnectParams { + int32 max_reconnect_backoff_ms = 1; +} + +// For reconnect interop test only. +// Server tells client whether its reconnects are following the spec and the +// reconnect backoffs it saw. +message ReconnectInfo { + bool passed = 1; + repeated int32 backoff_ms = 2; +} + +message LoadBalancerStatsRequest { + // Request stats for the next num_rpcs sent by client. + int32 num_rpcs = 1; + // If num_rpcs have not completed within timeout_sec, return partial results. + int32 timeout_sec = 2; +} + +message LoadBalancerStatsResponse { + message RpcsByPeer { + // The number of completed RPCs for each peer. + map rpcs_by_peer = 1; + } + // The number of completed RPCs for each peer. + map rpcs_by_peer = 1; + // The number of RPCs that failed to record a remote peer. + int32 num_failures = 2; + map rpcs_by_method = 3; +} diff --git a/packages/grpc-js/proto/grpc/testing/test.proto b/packages/grpc-js/proto/grpc/testing/test.proto new file mode 100644 index 000000000..9d0fadd9a --- /dev/null +++ b/packages/grpc-js/proto/grpc/testing/test.proto @@ -0,0 +1,92 @@ + +// Copyright 2015-2016 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An integration test service that covers all the method signature permutations +// of unary/streaming requests/responses. + +syntax = "proto3"; + +import "grpc/testing/empty.proto"; +import "grpc/testing/messages.proto"; + +package grpc.testing; + +// A simple service to test the various types of RPCs and experiment with +// performance with various types of payload. +service TestService { + // One empty request followed by one empty response. + rpc EmptyCall(grpc.testing.Empty) returns (grpc.testing.Empty); + + // One request followed by one response. + rpc UnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by one response. Response has cache control + // headers set such that a caching HTTP proxy (such as GFE) can + // satisfy subsequent requests. + rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse); + + // One request followed by a sequence of responses (streamed download). + // The server returns the payload with client desired type and sizes. + rpc StreamingOutputCall(StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by one response (streamed upload). + // The server returns the aggregated size of client payload as the result. + rpc StreamingInputCall(stream StreamingInputCallRequest) + returns (StreamingInputCallResponse); + + // A sequence of requests with each request served by the server immediately. + // As one request could lead to multiple responses, this interface + // demonstrates the idea of full duplexing. + rpc FullDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // A sequence of requests followed by a sequence of responses. + // The server buffers all the client requests and then serves them in order. A + // stream of responses are returned to the client when the server starts with + // first request. + rpc HalfDuplexCall(stream StreamingOutputCallRequest) + returns (stream StreamingOutputCallResponse); + + // The test server will not implement this method. It will be used + // to test the behavior when clients call unimplemented methods. + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A simple service NOT implemented at servers so clients can test for +// that case. +service UnimplementedService { + // A call that no server should implement + rpc UnimplementedCall(grpc.testing.Empty) returns (grpc.testing.Empty); +} + +// A service used to control reconnect server. +service ReconnectService { + rpc Start(grpc.testing.ReconnectParams) returns (grpc.testing.Empty); + rpc Stop(grpc.testing.Empty) returns (grpc.testing.ReconnectInfo); +} + +// A service used to obtain stats for verifying LB behavior. +service LoadBalancerStatsService { + // Gets the backend distribution for RPCs sent by a test client. + rpc GetClientStats(LoadBalancerStatsRequest) + returns (LoadBalancerStatsResponse) {} +} + +// A service to remotely control health status of an xDS test server. +service XdsUpdateHealthService { + rpc SetServing(grpc.testing.Empty) returns (grpc.testing.Empty); + rpc SetNotServing(grpc.testing.Empty) returns (grpc.testing.Empty); +} From ba7a035770e5ca9865390ef1ae220142b9019ecd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Aug 2020 15:50:46 -0700 Subject: [PATCH 1202/1899] Enable 'xds' target scheme --- packages/grpc-js/src/resolver.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 57c750aea..0c4c0d6b9 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,6 +18,7 @@ import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; +import * as resolver_xds from './resolver-xds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; @@ -156,4 +157,5 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); + resolver_xds.setup(); } From f0ed1aba14ff53e356343178d5634af5e624a3f6 Mon Sep 17 00:00:00 2001 From: Martin <1224973+mavaa@users.noreply.github.com> Date: Wed, 12 Aug 2020 16:51:42 +0200 Subject: [PATCH 1203/1899] Fix incorrectly named grpc-tools flag Was "--generate_package_definitions" (with an s) but should be "generate_package_definition" as in the documentation here: https://github.com/grpc/grpc-node/tree/master/packages/grpc-tools --- packages/grpc-js/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 4d0cb5482..dadcd188b 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -28,7 +28,7 @@ This library does not directly handle `.proto` files. To use `.proto` files with `@grpc/grpc-js` is almost a drop-in replacement for `grpc`, but you may need to make a few code changes to use it: - If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. -- If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `--generate_package_definitions` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. +- If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `generate_package_definition` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. - If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead. ## Some Notes on API Guarantees From 1583786478042de1dd61300e810bc87d442d6c88 Mon Sep 17 00:00:00 2001 From: Thomas Hunter II Date: Sun, 16 Aug 2020 13:50:23 -0700 Subject: [PATCH 1204/1899] Add link to grpc docs in @grpc/grpc-js README - Adds a link to `grpc` documentation - Addresses some of the concerns in #1540 --- packages/grpc-js/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index dadcd188b..e34cee9c4 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -8,6 +8,10 @@ Node 12 is recommended. The exact set of compatible Node versions can be found i npm install @grpc/grpc-js ``` +## Documentation + +Documentation specifically for the `@grpc/grpc-js` package is currently not available. However, [documentation is available for the `grpc` package](https://grpc.github.io/grpc/node/grpc.html), and the two packages contain mostly the same interface. There are a few notable differences, however, and these differences are noted in the "Migrating from grpc" section below. + ## Features - Clients From 74930526724826892bb7696412bd6e7c2c2b4ced Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 18 Aug 2020 15:13:12 -0700 Subject: [PATCH 1205/1899] grpc-js: Move @types/node to a production dependency --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ee910cfb6..839c67f3a 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -21,7 +21,6 @@ "@types/lodash": "^4.14.108", "@types/mocha": "^5.2.6", "@types/ncp": "^2.0.1", - "@types/node": "^12.7.5", "@types/pify": "^3.0.2", "@types/semver": "^6.0.1", "clang-format": "^1.0.55", @@ -58,6 +57,7 @@ "posttest": "npm run check" }, "dependencies": { + "@types/node": "^12.12.47", "semver": "^6.2.0" }, "files": [ From 917b4fca77fc9ee81c8dc71d38043f54c4d98562 Mon Sep 17 00:00:00 2001 From: Richard Pringle Date: Wed, 19 Aug 2020 10:24:20 -0400 Subject: [PATCH 1206/1899] Prevent mutation of default headers --- packages/grpc-js/src/server-call.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 82d885173..bdefa68a6 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -413,7 +413,7 @@ export class Http2ServerCallStream< this.metadataSent = true; const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. - const headers = Object.assign(defaultResponseHeaders, custom); + const headers = Object.assign({}, defaultResponseHeaders, custom); this.stream.respond(headers, defaultResponseOptions); } From 5abb47390fa34078f5afd21da23bf488d79c0840 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 09:24:57 -0700 Subject: [PATCH 1207/1899] grpc-js: Move a couple of dev dependencies to prod --- packages/grpc-js/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f207c7536..7deb248e2 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.4", + "version": "1.1.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", @@ -15,7 +15,6 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.6.0-pre6", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -25,7 +24,6 @@ "@types/semver": "^6.0.1", "clang-format": "^1.0.55", "execa": "^2.0.3", - "google-auth-library": "^6.0.0", "gts": "^2.0.0", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", @@ -57,7 +55,9 @@ "posttest": "npm run check" }, "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14", "@types/node": "^12.12.47", + "google-auth-library": "^6.0.0", "semver": "^6.2.0" }, "files": [ From 6389e92c8b5aad7604707244099795a256a091fa Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 09:54:10 -0700 Subject: [PATCH 1208/1899] Bump version to 0.6.0 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 5751b4bae..ac76bd54d 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre14", + "version": "0.6.0", "author": "Google Inc.", "contributors": [ { From 305e192700546f355b32263c74a9ee8c4601b1d2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 13:31:23 -0700 Subject: [PATCH 1209/1899] Add xds interop test script to Linux tests --- packages/grpc-js/src/xds-client.ts | 2 -- run-tests.sh | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index d29d29b8f..64f6a5817 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -877,8 +877,6 @@ export class XdsClient { ]; for (const typeUrl of allTypeUrls) { const state = this.adsState[typeUrl]; - state.nonce = ''; - state.versionInfo = ''; if (state.getResourceNames().length > 0) { this.updateNames(typeUrl); } diff --git a/run-tests.sh b/run-tests.sh index f23475b90..ca4501d03 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -75,6 +75,12 @@ do npm test || FAILED="true" done +if [ "$OS" = "Linux" ] +then + # Run the xds interop tests only on Linux + ./packages/grpc-js/scripts/xds.sh +fi + set +ex nvm use 8 set -ex From 9a73734650f854037050c379579dfea5f6bf2a1d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 13:36:16 -0700 Subject: [PATCH 1210/1899] Actually add the xds interop script --- packages/grpc-js/scripts/xds.sh | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 packages/grpc-js/scripts/xds.sh diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh new file mode 100644 index 000000000..1b6fde5df --- /dev/null +++ b/packages/grpc-js/scripts/xds.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +nvm use 12 + +set -exu -o pipefail +[[ -f /VERSION ]] && cat /VERSION + +cd $(dirname $0) +cd .. +base=$(pwd) +npm run compile + +cd ../../.. +branch=$(git branch --all --no-color --contains "${KOKORO_GITHUB_COMMIT}" \ + | grep -v HEAD | head -1) +shopt -s extglob +branch="${branch//[[:space:]]}" +branch="${branch##remotes/origin/}" +shopt -u extglob + +git clone -b "${branch}" --single-branch --depth=1 https://github.com/grpc/grpc.git + +grpc/tools/run_tests/helper_scripts/prep_xds.sh + +# Test cases "path_matching" and "header_matching" are not included in "all", +# because not all interop clients in all languages support these new tests. +# +# TODO: remove "path_matching" and "header_matching" from --test_case after +# they are added into "all". +GRPC_TRACE=xds_client,round_robin,resolving_load_balancer GRPC_VERBOSITY=DEBUG \ + python3 grpc/tools/run_tests/run_xds_tests.py \ + --test_case="all" \ + --project_id=grpc-testing \ + --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ + --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ + --gcp_suffix=$(date '+%s') \ + --verbose \ + --client_cmd="node grpc-node/packages/grpc-js/build/interop/xds-interop-client \ + --server=xds:///{server_uri} \ + --stats_port={stats_port} \ + --qps={qps} \ + {fail_on_failed_rpc} \ + {rpcs_to_send} \ + {metadata_to_send}" \ No newline at end of file From 46c065a75bd1bf4f153edd7e938674cd46f4551a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 13:37:17 -0700 Subject: [PATCH 1211/1899] chmod a+x xds.sh --- packages/grpc-js/scripts/xds.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 packages/grpc-js/scripts/xds.sh diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh old mode 100644 new mode 100755 From f246833876c83f0cec62f76b58d39e832e4e4a36 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 14:00:46 -0700 Subject: [PATCH 1212/1899] Some test script fixes --- packages/grpc-js/scripts/xds.sh | 10 +--------- run-tests.sh | 3 +++ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 1b6fde5df..a4c44fae8 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -1,7 +1,5 @@ #!/bin/bash -nvm use 12 - set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION @@ -11,14 +9,8 @@ base=$(pwd) npm run compile cd ../../.. -branch=$(git branch --all --no-color --contains "${KOKORO_GITHUB_COMMIT}" \ - | grep -v HEAD | head -1) -shopt -s extglob -branch="${branch//[[:space:]]}" -branch="${branch##remotes/origin/}" -shopt -u extglob -git clone -b "${branch}" --single-branch --depth=1 https://github.com/grpc/grpc.git +git clone -b remotes/origin/ --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh diff --git a/run-tests.sh b/run-tests.sh index ca4501d03..55a08e49a 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -77,6 +77,9 @@ done if [ "$OS" = "Linux" ] then + set +ex + nvm use 12 + set -ex # Run the xds interop tests only on Linux ./packages/grpc-js/scripts/xds.sh fi From bc5c29604b2b4dcfbf226b08f592292729d25d9b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Aug 2020 14:20:47 -0700 Subject: [PATCH 1213/1899] More test script fixes --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index a4c44fae8..d39da5f69 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -10,7 +10,7 @@ npm run compile cd ../../.. -git clone -b remotes/origin/ --single-branch --depth=1 https://github.com/grpc/grpc.git +git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh From f4e9b63ddf99dac3615fa43394911ed2539bafd1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 00:10:35 -0700 Subject: [PATCH 1214/1899] Trace all --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index d39da5f69..64b9fafa2 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -19,7 +19,7 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh # # TODO: remove "path_matching" and "header_matching" from --test_case after # they are added into "all". -GRPC_TRACE=xds_client,round_robin,resolving_load_balancer GRPC_VERBOSITY=DEBUG \ +GRPC_TRACE=all GRPC_VERBOSITY=DEBUG \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all" \ --project_id=grpc-testing \ From 14eea7d6d27a9e5f445288c4c29aae68cf692920 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 09:46:45 -0700 Subject: [PATCH 1215/1899] Add separate trace and verbosity env variables for this library --- packages/grpc-js/scripts/xds.sh | 2 +- packages/grpc-js/src/logging.ts | 33 ++++++++++++++++----------------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 64b9fafa2..e1c59e8ee 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -19,7 +19,7 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh # # TODO: remove "path_matching" and "header_matching" from --test_case after # they are added into "all". -GRPC_TRACE=all GRPC_VERBOSITY=DEBUG \ +GRPC_NODE_TRACE=all GRPC_NODE_VERBOSITY=DEBUG \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all" \ --project_id=grpc-testing \ diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 91b4e8f04..1140e8d8a 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -20,20 +20,20 @@ import { LogVerbosity } from './constants'; let _logger: Partial = console; let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; -if (process.env.GRPC_VERBOSITY) { - switch (process.env.GRPC_VERBOSITY) { - case 'DEBUG': - _logVerbosity = LogVerbosity.DEBUG; - break; - case 'INFO': - _logVerbosity = LogVerbosity.INFO; - break; - case 'ERROR': - _logVerbosity = LogVerbosity.ERROR; - break; - default: - // Ignore any other values - } +const verbosityString = process.env.GRPC_NODE_VERBOSITY ?? process.env.GRPC_VERBOSITY ?? ''; + +switch (verbosityString) { + case 'DEBUG': + _logVerbosity = LogVerbosity.DEBUG; + break; + case 'INFO': + _logVerbosity = LogVerbosity.INFO; + break; + case 'ERROR': + _logVerbosity = LogVerbosity.ERROR; + break; + default: + // Ignore any other values } export const getLogger = (): Partial => { @@ -55,9 +55,8 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { } }; -const enabledTracers = process.env.GRPC_TRACE - ? process.env.GRPC_TRACE.split(',') - : []; +const tracersString = process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; +const enabledTracers = tracersString.split(','); const allEnabled = enabledTracers.includes('all'); export function trace( From 141dfeb790968359a060b4e812f35ae078c32b96 Mon Sep 17 00:00:00 2001 From: Simon Woolf Date: Fri, 21 Aug 2020 18:10:58 +0100 Subject: [PATCH 1216/1899] Channel#watchConnectivityState: handle infinite deadlines correctly Per https://grpc.github.io/grpc/node/grpc.html#~Deadline: "If it is a finite number, it is treated as a number of milliseconds since the Unix Epoch. If it is Infinity, the deadline will never be reached. If it is -Infinity, the deadline has already passed." --- packages/grpc-js/src/channel.ts | 40 +++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8c3691928..3195ebc2f 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -120,7 +120,7 @@ export interface Channel { interface ConnectivityStateWatcher { currentState: ConnectivityState; - timer: NodeJS.Timeout; + timer: NodeJS.Timeout | null; callback: (error?: Error) => void; } @@ -417,7 +417,9 @@ export class ChannelImplementation implements Channel { const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { if (newState !== watcherObject.currentState) { - clearTimeout(watcherObject.timer); + if(watcherObject.timer) { + clearTimeout(watcherObject.timer); + } this.removeConnectivityStateWatcher(watcherObject); watcherObject.callback(); } @@ -452,25 +454,29 @@ export class ChannelImplementation implements Channel { deadline: Date | number, callback: (error?: Error) => void ): void { - const deadlineDate: Date = - deadline instanceof Date ? deadline : new Date(deadline); - const now = new Date(); - if (deadlineDate <= now) { - process.nextTick( - callback, - new Error('Deadline passed without connectivity state change') - ); - return; - } - const watcherObject = { - currentState, - callback, - timer: setTimeout(() => { + let timer = null; + if(deadline !== Infinity) { + const deadlineDate: Date = + deadline instanceof Date ? deadline : new Date(deadline); + const now = new Date(); + if (deadline === -Infinity || deadlineDate <= now) { + process.nextTick( + callback, + new Error('Deadline passed without connectivity state change') + ); + return; + } + timer = setTimeout(() => { this.removeConnectivityStateWatcher(watcherObject); callback( new Error('Deadline passed without connectivity state change') ); - }, deadlineDate.getTime() - now.getTime()), + }, deadlineDate.getTime() - now.getTime()) + } + const watcherObject = { + currentState, + callback, + timer }; this.connectivityStateWatchers.push(watcherObject); } From 362b77259f4b3cd1e1f075e7470ef6cb212132ff Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 11:02:33 -0700 Subject: [PATCH 1217/1899] Add more logging to the xDS interop client --- packages/grpc-js/interop/xds-interop-client.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index e056fb08f..fc45b6151 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -184,11 +184,13 @@ function main() { .number(['num_channels', 'qps']) .require(['fail_on_failed_rpcs', 'num_channels', 'qps', 'server', 'stats_port']) .argv; + console.log('Starting xDS interop client. Args: ', argv); const callStatsTracker = new CallStatsTracker(); for (let i = 0; i < argv.num_channels; i++) { /* The 'unique' channel argument is there solely to ensure that the * channels do not share any subchannels. It does not have any * inherent function. */ + console.log(`Interop client channel ${i} starting sending ${argv.qps} QPS to ${argv.server}`); sendConstantQps(new loadedProto.grpc.testing.TestService(argv.server, grpc.credentials.createInsecure(), {'unique': i}), argv.qps, argv.fail_on_failed_rpcs === 'true', @@ -211,6 +213,7 @@ function main() { if (error) { throw error; } + console.log(`Starting stats service server bound to port ${port}`); server.start(); }); } From eb849db1aaa10859fabf27661a236b665a9ef991 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 12:47:17 -0700 Subject: [PATCH 1218/1899] Add a log line to the top level of xds-interop-client --- packages/grpc-js/interop/xds-interop-client.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index fc45b6151..37cb0623f 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -220,4 +220,6 @@ function main() { if (require.main === module) { main(); -} \ No newline at end of file +} + +console.log('Bottom of xds-interop-client'); \ No newline at end of file From 1e223048b807b6ae1bd448c0fe3625cd7dd2e880 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Aug 2020 12:58:05 -0700 Subject: [PATCH 1219/1899] Grab xds client logs in kokoro config --- packages/grpc-js/interop/xds-interop-client.ts | 4 +--- test/kokoro/linux.cfg | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 37cb0623f..fc45b6151 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -220,6 +220,4 @@ function main() { if (require.main === module) { main(); -} - -console.log('Bottom of xds-interop-client'); \ No newline at end of file +} \ No newline at end of file diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..24ed01aba 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -20,5 +20,6 @@ timeout_mins: 60 action { define_artifacts { regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From 0e8e1adfc456a36282fa3767d525f82422b22962 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 24 Aug 2020 15:53:07 -0700 Subject: [PATCH 1220/1899] More test script fixes, don't run xDS tests in PR tests --- packages/grpc-js/interop/xds-interop-client.ts | 3 ++- packages/grpc-js/scripts/xds.sh | 2 +- run-tests.sh | 9 --------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index fc45b6151..f2c4cb0a6 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -182,7 +182,8 @@ function main() { const argv = yargs .string(['fail_on_failed_rpcs', 'server', 'stats_port']) .number(['num_channels', 'qps']) - .require(['fail_on_failed_rpcs', 'num_channels', 'qps', 'server', 'stats_port']) + .require(['qps', 'server', 'stats_port']) + .default('num_channels', 1) .argv; console.log('Starting xDS interop client. Args: ', argv); const callStatsTracker = new CallStatsTracker(); diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index e1c59e8ee..ae169eebb 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -33,4 +33,4 @@ GRPC_NODE_TRACE=all GRPC_NODE_VERBOSITY=DEBUG \ --qps={qps} \ {fail_on_failed_rpc} \ {rpcs_to_send} \ - {metadata_to_send}" \ No newline at end of file + {metadata_to_send}" diff --git a/run-tests.sh b/run-tests.sh index 55a08e49a..f23475b90 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -75,15 +75,6 @@ do npm test || FAILED="true" done -if [ "$OS" = "Linux" ] -then - set +ex - nvm use 12 - set -ex - # Run the xds interop tests only on Linux - ./packages/grpc-js/scripts/xds.sh -fi - set +ex nvm use 8 set -ex From 7e35657cf1e1d0bcd408a133cd953c468a7e7ff0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 09:45:47 -0700 Subject: [PATCH 1221/1899] node.cluster is optional in the bootstrap file --- packages/grpc-js/src/xds-bootstrap.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index b8e446b25..47e7679e1 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -157,15 +157,6 @@ function validateNode(obj: any): Node { throw new Error(`node.id field: expected string, got ${typeof obj.id}`); } result.id = obj.id; - if (!('cluster' in obj)) { - throw new Error('cluster field missing in node element'); - } - if (typeof obj.cluster !== 'string') { - throw new Error( - `node.cluster field: expected string, got ${typeof obj.cluster}` - ); - } - result.cluster = obj.cluster; if (!('locality' in obj)) { throw new Error('locality field missing in node element'); } @@ -197,6 +188,14 @@ function validateNode(obj: any): Node { } result.locality.sub_zone = obj.locality.sub_zone; } + if ('cluster' in obj) { + if (typeof obj.cluster !== 'string') { + throw new Error( + `node.cluster field: expected string, got ${typeof obj.cluster}` + ); + } + result.cluster = obj.cluster; + } if ('metadata' in obj) { result.metadata = getStructFromJson(obj.metadata); } From 302b87183e3cc3316e2669d47495d02892140d84 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 10:05:44 -0700 Subject: [PATCH 1222/1899] Fix bug in bootstrap file validation --- packages/grpc-js/src/xds-bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js/src/xds-bootstrap.ts index 47e7679e1..00e13d09f 100644 --- a/packages/grpc-js/src/xds-bootstrap.ts +++ b/packages/grpc-js/src/xds-bootstrap.ts @@ -171,7 +171,7 @@ function validateNode(obj: any): Node { result.locality.region = obj.locality.region; } if ('zone' in obj.locality) { - if (typeof obj.locality.region !== 'string') { + if (typeof obj.locality.zone !== 'string') { throw new Error( `node.locality.zone field: expected string, got ${typeof obj.locality .zone}` From ee52de4f989c9d017165eb32641868dbcfc9dd05 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 10:54:56 -0700 Subject: [PATCH 1223/1899] Load proto files with json option to handle Any properly --- packages/grpc-js/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 64f6a5817..7580c2f4b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -105,6 +105,7 @@ function loadAdsProtos(): Promise< enums: String, defaults: true, oneofs: true, + json: true, includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', From 8580204a73b7c1af46e070e3585e8cd41fb9b8d1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 11:05:22 -0700 Subject: [PATCH 1224/1899] Fix incorrect 'Method not implemented' error --- packages/grpc-js/src/xds-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 7580c2f4b..bd2235ab1 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -641,7 +641,7 @@ class LdsState implements XdsStreamState { } } } - throw new Error('Method not implemented.'); + return null; } reportStreamError(status: StatusObject): void { From af949674da15eb3a99e82dc4cbf45e7f731f9a3a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 13:22:30 -0700 Subject: [PATCH 1225/1899] Add XdsClient tracers, and stream start backoff, and fix some bugs --- packages/grpc-js/src/xds-client.ts | 84 +++++++++++++++++++++++------- 1 file changed, 66 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index bd2235ab1..5b5ed5500 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -54,6 +54,7 @@ import { Listener__Output } from './generated/envoy/api/v2/Listener'; import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; import { Any__Output } from './generated/google/protobuf/Any'; +import { BackoffTimeout } from './backoff-timeout'; const TRACER_NAME = 'xds_client'; @@ -260,6 +261,7 @@ class EdsState implements XdsStreamState { edsServiceName: string, watcher: Watcher ): void { + trace('Adding EDS watcher for edsServiceName ' + edsServiceName); let watchersEntry = this.watchers.get(edsServiceName); let addedServiceName = false; if (watchersEntry === undefined) { @@ -276,6 +278,7 @@ class EdsState implements XdsStreamState { /* These updates normally occur asynchronously, so we ensure that * the same happens here */ process.nextTick(() => { + trace('Reporting existing EDS update for new watcher for edsServiceName ' + edsServiceName); watcher.onValidUpdate(message); }); } @@ -289,6 +292,7 @@ class EdsState implements XdsStreamState { edsServiceName: string, watcher: Watcher ): void { + trace('Removing EDS watcher for edsServiceName ' + edsServiceName); const watchersEntry = this.watchers.get(edsServiceName); let removedServiceName = false; if (watchersEntry !== undefined) { @@ -342,6 +346,7 @@ class EdsState implements XdsStreamState { handleMissingNames(allEdsServiceNames: Set) { for (const [edsServiceName, watcherList] of this.watchers.entries()) { if (!allEdsServiceNames.has(edsServiceName)) { + trace('Reporting EDS resource does not exist for edsServiceName ' + edsServiceName); for (const watcher of watcherList) { watcher.onResourceDoesNotExist(); } @@ -352,7 +357,7 @@ class EdsState implements XdsStreamState { handleResponses(responses: ClusterLoadAssignment__Output[]) { for (const message of responses) { if (!this.validateResponse(message)) { - return 'ClusterLoadAssignment validation failed'; + return 'EDS Error: ClusterLoadAssignment validation failed'; } } this.latestResponses = responses; @@ -364,6 +369,7 @@ class EdsState implements XdsStreamState { watcher.onValidUpdate(message); } } + trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); this.handleMissingNames(allClusterNames); return null; } @@ -400,6 +406,7 @@ class CdsState implements XdsStreamState { * @param watcher */ addWatcher(clusterName: string, watcher: Watcher): void { + trace('Adding CDS watcher for clusterName ' + clusterName); let watchersEntry = this.watchers.get(clusterName); let addedServiceName = false; if (watchersEntry === undefined) { @@ -416,6 +423,7 @@ class CdsState implements XdsStreamState { /* These updates normally occur asynchronously, so we ensure that * the same happens here */ process.nextTick(() => { + trace('Reporting existing CDS update for new watcher for clusterName ' + clusterName); watcher.onValidUpdate(message); }); } @@ -426,6 +434,7 @@ class CdsState implements XdsStreamState { } removeWatcher(clusterName: string, watcher: Watcher): void { + trace('Removing CDS watcher for clusterName ' + clusterName); const watchersEntry = this.watchers.get(clusterName); let removedServiceName = false; if (watchersEntry !== undefined) { @@ -466,14 +475,15 @@ class CdsState implements XdsStreamState { } /** - * Given a list of edsServiceNames (which may actually be the cluster name), + * Given a list of clusterNames (which may actually be the cluster name), * for each watcher watching a name not on the list, call that watcher's * onResourceDoesNotExist method. * @param allClusterNames */ private handleMissingNames(allClusterNames: Set) { - for (const [edsServiceName, watcherList] of this.watchers.entries()) { - if (!allClusterNames.has(edsServiceName)) { + for (const [clusterName, watcherList] of this.watchers.entries()) { + if (!allClusterNames.has(clusterName)) { + trace('Reporting CDS resource does not exist for clusterName ' + clusterName); for (const watcher of watcherList) { watcher.onResourceDoesNotExist(); } @@ -484,7 +494,7 @@ class CdsState implements XdsStreamState { handleResponses(responses: Cluster__Output[]): string | null { for (const message of responses) { if (!this.validateResponse(message)) { - return 'Cluster validation failed'; + return 'CDS Error: Cluster validation failed'; } } this.latestResponses = responses; @@ -501,6 +511,7 @@ class CdsState implements XdsStreamState { watcher.onValidUpdate(message); } } + trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); this.handleMissingNames(allClusterNames); this.edsState.handleMissingNames(allEdsServiceNames); return null; @@ -535,6 +546,7 @@ class RdsState implements XdsStreamState { if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { const route = virtualHost.routes[virtualHost.routes.length - 1]; if (route.match?.prefix === '' && route.route?.cluster) { + trace('Reporting RDS update for host ' + this.routeConfigName + ' with cluster ' + route.route.cluster); this.watcher.onValidUpdate({ methodConfig: [], loadBalancingConfig: [ @@ -546,10 +558,11 @@ class RdsState implements XdsStreamState { }, ], }); - break; + return; } } } + trace('Reporting RDS resource does not exist'); /* If none of the routes match the one we are looking for, bubble up an * error. */ this.watcher.onResourceDoesNotExist(); @@ -623,11 +636,13 @@ class LdsState implements XdsStreamState { HttpConnectionManager__Output; switch (httpConnectionManager.route_specifier) { case 'rds': + trace('Received LDS update with RDS route config name ' + httpConnectionManager.rds!.route_config_name); this.rdsState.setRouteConfigName( httpConnectionManager.rds!.route_config_name ); break; case 'route_config': + trace('Received LDS update with route configuration'); this.rdsState.setRouteConfigName(null); this.rdsState.handleSingleMessage( httpConnectionManager.route_config! @@ -637,7 +652,7 @@ class LdsState implements XdsStreamState { // The validation rules should prevent this } } else { - return 'Listener validation failed'; + return 'LRS Error: Listener validation failed'; } } } @@ -677,11 +692,11 @@ function getResponseMessages( result.push(resource as protoLoader.AnyExtension & OutputType); } else { throw new Error( - `Invalid resource type ${ + `ADS Error: Invalid resource type ${ protoLoader.isAnyExtension(resource) ? resource['@type'] : resource.type_url - }` + }, expected ${typeUrl}` ); } } @@ -711,6 +726,9 @@ export class XdsClient { private adsState: AdsState; + private adsBackoff: BackoffTimeout; + private lrsBackoff: BackoffTimeout; + constructor( targetName: string, serviceConfigWatcher: Watcher, @@ -752,6 +770,14 @@ export class XdsClient { delete channelArgs[arg]; } channelArgs['grpc.keepalive_time_ms'] = 5000; + + this.adsBackoff = new BackoffTimeout(() => { + this.maybeStartAdsStream(); + }); + this.lrsBackoff = new BackoffTimeout(() => { + this.maybeStartLrsStream(); + }) + Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( ([bootstrapInfo, protoDefinitions]) => { if (this.hasShutdown) { @@ -770,6 +796,7 @@ export class XdsClient { ...node, client_features: ['envoy.lrs.supports_send_all_clusters'], }; + trace('Starting xDS client connected to server URI ' + bootstrapInfo.xdsServers[0].serverUri); this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), @@ -828,6 +855,7 @@ export class XdsClient { errorString = `Unknown type_url ${message.type_url}`; } if (errorString === null) { + trace('Acking message with type URL ' + message.type_url); /* errorString can only be null in one of the first 4 cases, which * implies that message.type_url is one of the 4 known type URLs, which * means that this type assertion is valid. */ @@ -836,6 +864,7 @@ export class XdsClient { this.adsState[typeUrl].versionInfo = message.version_info; this.ack(typeUrl); } else { + trace('Nacking message with type URL ' + message.type_url + ': "' + errorString + '"'); this.nack(message.type_url, errorString); } } @@ -854,6 +883,9 @@ export class XdsClient { if (this.hasShutdown) { return; } + trace('Starting ADS stream'); + // Backoff relative to when we start the request + this.adsBackoff.runOnce(); this.adsCall = this.adsClient.StreamAggregatedResources(); this.adsCall.on('data', (message: DiscoveryResponse__Output) => { this.handleAdsResponse(message); @@ -864,10 +896,11 @@ export class XdsClient { ); this.adsCall = null; this.reportStreamError(error); - /* Connection backoff is handled by the client object, so we can - * immediately start a new request to indicate that it should try to - * reconnect */ - this.maybeStartAdsStream(); + /* If the backoff timer is no longer running, we do not need to wait any + * more to start the new call. */ + if (!this.adsBackoff.isRunning()) { + this.maybeStartAdsStream(); + } }); const allTypeUrls: AdsTypeUrl[] = [ @@ -889,6 +922,11 @@ export class XdsClient { * version info are updated so that it sends the post-update values. */ ack(typeUrl: AdsTypeUrl) { + /* An ack is the best indication of a successful interaction between the + * client and the server, so we can reset the backoff timer here. */ + this.adsBackoff.stop(); + this.adsBackoff.reset(); + this.updateNames(typeUrl); } @@ -953,8 +991,17 @@ export class XdsClient { if (this.hasShutdown) { return; } + + trace('Starting LRS stream'); + this.lrsBackoff.runOnce(); this.lrsCall = this.lrsClient.streamLoadStats(); + this.lrsCall.on('metadata', () => { + /* Once we get any response from the server, we assume that the stream is + * in a good state, so we can reset the backoff timer. */ + this.lrsBackoff.stop(); + this.lrsBackoff.reset(); + }); this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { if ( message.load_reporting_interval?.seconds !== @@ -970,7 +1017,7 @@ export class XdsClient { const loadReportingIntervalMs = Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + message.load_reporting_interval!.nanos / 1_000_000; - setInterval(() => { + this.statsTimer = setInterval(() => { this.sendStats(); }, loadReportingIntervalMs); } @@ -982,10 +1029,11 @@ export class XdsClient { ); this.lrsCall = null; clearInterval(this.statsTimer); - /* Connection backoff is handled by the client object, so we can - * immediately start a new request to indicate that it should try to - * reconnect */ - this.maybeStartAdsStream(); + /* If the backoff timer is no longer running, we do not need to wait any + * more to start the new call. */ + if (!this.lrsBackoff.isRunning()) { + this.maybeStartLrsStream(); + } }); this.lrsCall.write({ node: this.lrsNode!, From 36a6580921ff5f2db0ded02a1d49578450ef8592 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 13:49:28 -0700 Subject: [PATCH 1226/1899] Add more XdsClient tracing --- packages/grpc-js/src/xds-client.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 5b5ed5500..1af5d010c 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -357,6 +357,7 @@ class EdsState implements XdsStreamState { handleResponses(responses: ClusterLoadAssignment__Output[]) { for (const message of responses) { if (!this.validateResponse(message)) { + trace('EDS validation failed for message ' + JSON.stringify(message)); return 'EDS Error: ClusterLoadAssignment validation failed'; } } @@ -494,6 +495,7 @@ class CdsState implements XdsStreamState { handleResponses(responses: Cluster__Output[]): string | null { for (const message of responses) { if (!this.validateResponse(message)) { + trace('CDS validation failed for message ' + JSON.stringify(message)); return 'CDS Error: Cluster validation failed'; } } @@ -559,16 +561,19 @@ class RdsState implements XdsStreamState { ], }); return; + } else { + trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); } } } - trace('Reporting RDS resource does not exist'); + trace('Reporting RDS resource does not exist from domain lists ' + message.virtual_hosts.map(virtualHost => virtualHost.domains)); /* If none of the routes match the one we are looking for, bubble up an * error. */ this.watcher.onResourceDoesNotExist(); } handleResponses(responses: RouteConfiguration__Output[]): string | null { + trace('Received RDS response with route config names ' + responses.map(message => message.name)); if (this.routeConfigName !== null) { for (const message of responses) { if (message.name === this.routeConfigName) { @@ -627,6 +632,7 @@ class LdsState implements XdsStreamState { } handleResponses(responses: Listener__Output[]): string | null { + trace('Received LDS update with names ' + responses.map(message => message.name)); for (const message of responses) { if (message.name === this.targetName) { if (this.validateResponse(message)) { @@ -652,6 +658,7 @@ class LdsState implements XdsStreamState { // The validation rules should prevent this } } else { + trace('LRS validation error for message ' + JSON.stringify(message)); return 'LRS Error: Listener validation failed'; } } @@ -965,6 +972,7 @@ export class XdsClient { } private updateNames(typeUrl: AdsTypeUrl) { + trace('Sending update for type URL ' + typeUrl + ' with names ' + this.adsState[typeUrl].getResourceNames()); this.adsCall?.write({ node: this.adsNode!, type_url: typeUrl, From 240444623468754e08fa8dbc3914b174568716de Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Aug 2020 14:10:54 -0700 Subject: [PATCH 1227/1899] Fix RDS domain search --- packages/grpc-js/src/xds-client.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 1af5d010c..bfeb4ed53 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -535,6 +535,7 @@ class RdsState implements XdsStreamState { private routeConfigName: string | null = null; constructor( + private targetName: string, private watcher: Watcher, private updateResouceNames: () => void ) {} @@ -545,10 +546,10 @@ class RdsState implements XdsStreamState { handleSingleMessage(message: RouteConfiguration__Output) { for (const virtualHost of message.virtual_hosts) { - if (virtualHost.domains.indexOf(this.routeConfigName!) >= 0) { + if (virtualHost.domains.indexOf(this.targetName) >= 0) { const route = virtualHost.routes[virtualHost.routes.length - 1]; if (route.match?.prefix === '' && route.route?.cluster) { - trace('Reporting RDS update for host ' + this.routeConfigName + ' with cluster ' + route.route.cluster); + trace('Reporting RDS update for host ' + this.targetName + ' with cluster ' + route.route.cluster); this.watcher.onValidUpdate({ methodConfig: [], loadBalancingConfig: [ @@ -747,7 +748,7 @@ export class XdsClient { const cdsState = new CdsState(edsState, () => { this.updateNames(CDS_TYPE_URL); }); - const rdsState = new RdsState(serviceConfigWatcher, () => { + const rdsState = new RdsState(targetName, serviceConfigWatcher, () => { this.updateNames(RDS_TYPE_URL); }); const ldsState = new LdsState(targetName, rdsState); From 197cc84e7ac150bfe605e7cbf4a7bbc5dc724f64 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 11:05:54 -0700 Subject: [PATCH 1228/1899] Add more tracers, fix onResourceDoesNotExist handling --- .../grpc-js/interop/xds-interop-client.ts | 2 ++ packages/grpc-js/src/load-balancer-cds.ts | 14 +++++++++++ .../src/load-balancer-child-handler.ts | 2 ++ packages/grpc-js/src/load-balancer-eds.ts | 17 +++++++++++++- .../grpc-js/src/load-balancer-priority.ts | 18 ++++++++++++++- .../src/load-balancer-weighted-target.ts | 23 ++++++++++++++++--- packages/grpc-js/src/resolver-xds.ts | 13 ++++++++++- 7 files changed, 83 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index f2c4cb0a6..c33c5b380 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -200,7 +200,9 @@ function main() { const loadBalancerStatsServiceImpl: LoadBalancerStatsServiceHandlers = { GetClientStats: (call, callback) => { + console.log(`Received stats request with num_rpcs=${call.request.num_rpcs} and timeout_sec=${call.request.num_rpcs}`); callStatsTracker.getCallStats(call.request.num_rpcs, call.request.timeout_sec).then((value) => { + console.log(`Sending stats response: ${JSON.stringify(value)}`); callback(null, value); }, (error) => { callback({code: grpc.status.ABORTED, details: 'Call stats collection failed'}); diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 823469787..01cc4c62f 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -34,6 +34,14 @@ import { ConnectivityState } from './channel'; import { UnavailablePicker } from './picker'; import { Status } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'cds_balancer'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'cds'; @@ -70,6 +78,7 @@ export class CdsLoadBalancer implements LoadBalancer { * Otherwise, if the field is omitted, load reporting is disabled. */ edsConfig.lrsLoadReportingServerName = ''; } + trace('Child update EDS config: ' + JSON.stringify(edsConfig)); this.childBalancer.updateAddressList( [], { name: 'eds', eds: edsConfig }, @@ -82,6 +91,8 @@ export class CdsLoadBalancer implements LoadBalancer { this.watcher ); this.isWatcherActive = false; + this.channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'CDS resource does not exist', metadata: new Metadata()})); + this.childBalancer.destroy(); }, onTransientError: (status) => { if (this.latestCdsUpdate === null) { @@ -104,11 +115,14 @@ export class CdsLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { if (!isCdsLoadBalancingConfig(lbConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { + trace('Discarding address list update missing xdsClient attribute'); return; } + trace('Received update with config ' + JSON.stringify(lbConfig)); this.xdsClient = attributes.xdsClient; this.latestAttributes = attributes; diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 158108f0a..b0044d126 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -133,9 +133,11 @@ export class ChildLoadBalancerHandler implements LoadBalancer { destroy(): void { if (this.currentChild) { this.currentChild.destroy(); + this.currentChild = null; } if (this.pendingChild) { this.pendingChild.destroy(); + this.pendingChild = null; } } getTypeName(): string { diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 57aac25b3..c0d90e8ee 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -21,7 +21,7 @@ import { registerLoadBalancerType, getFirstUsableConfig, } from './load-balancer'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress, subchannelAddressToString } from './subchannel'; import { LoadBalancingConfig, isEdsLoadBalancingConfig, @@ -40,6 +40,14 @@ import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { LocalitySubchannelAddress } from './load-balancer-priority'; import { Status } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'eds_balancer'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'eds'; @@ -136,6 +144,8 @@ export class EdsLoadBalancer implements LoadBalancer { this.watcher ); this.isWatcherActive = false; + this.channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'EDS resource does not exist', metadata: new Metadata()})); + this.childBalancer.destroy(); }, onTransientError: (status) => { if (this.latestEdsUpdate === null) { @@ -356,6 +366,8 @@ export class EdsLoadBalancer implements LoadBalancer { priorities: newPriorityNames.filter((value) => value !== undefined), }, }; + trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); + trace('Child update service config: ' + JSON.stringify(childConfig)); this.childBalancer.updateAddressList( addressList, childConfig, @@ -372,11 +384,14 @@ export class EdsLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { if (!isEdsLoadBalancingConfig(lbConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { + trace('Discarding address list update missing xdsClient attribute'); return; } + trace('Received update with config: ' + JSON.stringify(lbConfig)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts index d30707156..6539e4b4e 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -21,7 +21,7 @@ import { getFirstUsableConfig, registerLoadBalancerType, } from './load-balancer'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress, subchannelAddressToString } from './subchannel'; import { LoadBalancingConfig, isPriorityLoadBalancingConfig, @@ -32,6 +32,14 @@ import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; import { Metadata } from './metadata'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'priority'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'priority'; @@ -222,6 +230,10 @@ export class PriorityLoadBalancer implements LoadBalancer { constructor(private channelControlHelper: ChannelControlHelper) {} private updateState(state: ConnectivityState, picker: Picker) { + trace( + 'Transitioning to ' + + ConnectivityState[state] + ); /* If switching to IDLE, use a QueuePicker attached to this load balancer * so that when the picker calls exitIdle, that in turn calls exitIdle on * the PriorityChildImpl, which will start the failover timer. */ @@ -233,6 +245,7 @@ export class PriorityLoadBalancer implements LoadBalancer { private onChildStateChange(child: PriorityChildBalancer) { const childState = child.getConnectivityState(); + trace('Child ' + child.getName() + ' transitioning to ' + ConnectivityState[childState]); if (child === this.currentChildFromBeforeUpdate) { if ( childState === ConnectivityState.READY || @@ -369,6 +382,7 @@ export class PriorityLoadBalancer implements LoadBalancer { ): void { if (!isPriorityLoadBalancingConfig(lbConfig)) { // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } const priorityConfig = lbConfig.priority; @@ -416,6 +430,7 @@ export class PriorityLoadBalancer implements LoadBalancer { const chosenChildConfig = getFirstUsableConfig(childConfig.config); if (chosenChildConfig !== null) { const childAddresses = childAddressMap.get(childName) ?? []; + trace('Assigning child ' + childName + ' address list ' + childAddresses.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')) this.latestUpdates.set(childName, { subchannelAddress: childAddresses, lbConfig: chosenChildConfig, @@ -433,6 +448,7 @@ export class PriorityLoadBalancer implements LoadBalancer { // Deactivate all children that are no longer in the priority list for (const [childName, child] of this.children) { if (this.priorities.indexOf(childName) < 0) { + trace('Deactivating child ' + childName); child.deactivate(); } } diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js/src/load-balancer-weighted-target.ts index e8a5fe65a..2da67e7f7 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js/src/load-balancer-weighted-target.ts @@ -16,7 +16,7 @@ */ import { LoadBalancer, ChannelControlHelper, getFirstUsableConfig, registerLoadBalancerType } from "./load-balancer"; -import { SubchannelAddress } from "./subchannel"; +import { SubchannelAddress, subchannelAddressToString } from "./subchannel"; import { LoadBalancingConfig, WeightedTarget, isWeightedTargetLoadBalancingConfig } from "./load-balancing-config"; import { Picker, PickResult, PickArgs, QueuePicker, UnavailablePicker } from "./picker"; import { ConnectivityState } from "./channel"; @@ -24,6 +24,14 @@ import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; import { Status } from "./constants"; import { Metadata } from "./metadata"; import { isLocalitySubchannelAddress, LocalitySubchannelAddress } from "./load-balancer-priority"; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; + +const TRACER_NAME = 'weighted_target'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'weighted_target'; @@ -116,6 +124,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } private updateState(connectivityState: ConnectivityState, picker: Picker) { + trace('Target ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; this.parent.updateState(); @@ -239,12 +248,17 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { metadata: new Metadata() }); } + trace( + 'Transitioning to ' + + ConnectivityState[connectivityState] + ); this.channelControlHelper.updateState(connectivityState, picker); } updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { if (!isWeightedTargetLoadBalancingConfig(lbConfig)) { // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); return; } @@ -252,7 +266,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { * which child it belongs to. So we bucket those addresses by that first * element, and pass along the rest of the localityPath for that child * to use. */ - const childAddressMap = new Map(); + const childAddressMap = new Map(); for (const address of addressList) { if (!isLocalitySubchannelAddress(address)) { // Reject address that cannot be associated with targets @@ -284,12 +298,15 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } else { target.maybeReactivate(); } - target.updateAddressList(childAddressMap.get(targetName) ?? [], targetConfig, attributes); + const targetAddresses = childAddressMap.get(targetName) ?? []; + trace('Assigning target ' + targetName + ' address list ' + targetAddresses.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); + target.updateAddressList(targetAddresses, targetConfig, attributes); } // Deactivate targets that are not in the new config for (const [targetName, target] of this.targets) { if (this.targetList.indexOf(targetName) < 0) { + trace('Deactivating target ' + targetName); target.deactivate(); } } diff --git a/packages/grpc-js/src/resolver-xds.ts b/packages/grpc-js/src/resolver-xds.ts index e92fddffd..38cc37a6b 100644 --- a/packages/grpc-js/src/resolver-xds.ts +++ b/packages/grpc-js/src/resolver-xds.ts @@ -19,9 +19,16 @@ import { GrpcUri, uriToString } from './uri-parser'; import { XdsClient } from './xds-client'; import { ServiceConfig } from './service-config'; import { StatusObject } from './call-stream'; -import { Status } from './constants'; +import { Status, LogVerbosity } from './constants'; import { Metadata } from './metadata'; import { ChannelOptions } from './channel-options'; +import * as logging from './logging'; + +const TRACER_NAME = 'xds_resolver'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} class XdsResolver implements Resolver { private resolutionStarted = false; @@ -47,10 +54,12 @@ class XdsResolver implements Resolver { // Wait until updateResolution is called once to start the xDS requests if (!this.resolutionStarted) { this.resolutionStarted = true; + trace('Starting resolution for target ' + this.target); const xdsClient = new XdsClient( this.target.path, { onValidUpdate: (update: ServiceConfig) => { + trace('Resolved service config for target ' + this.target + ': ' + JSON.stringify(update)); this.hasReportedSuccess = true; this.listener.onSuccessfulResolution([], update, null, { xdsClient: xdsClient, @@ -60,10 +69,12 @@ class XdsResolver implements Resolver { /* A transient error only needs to bubble up as a failure if we have * not already provided a ServiceConfig for the upper layer to use */ if (!this.hasReportedSuccess) { + trace('Resolution error for target ' + this.target + ' due to xDS client transient error ' + error.details); this.reportResolutionError(); } }, onResourceDoesNotExist: () => { + trace('Resolution error for target ' + this.target + ': resource does not exist'); this.reportResolutionError(); }, }, From 665632f48034f383b09704d82ec593624f4c0c20 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 12:47:53 -0700 Subject: [PATCH 1229/1899] Add more keepalive logging --- packages/grpc-js/src/subchannel.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 736562a66..c90df85ea 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -28,7 +28,7 @@ import * as logging from './logging'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; -import { GrpcUri, parseUri, splitHostPort } from './uri-parser'; +import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { ConnectionOptions } from 'tls'; import { FilterFactory, Filter } from './filter'; @@ -263,6 +263,7 @@ export class Subchannel { } private sendPing() { + logging.trace(LogVerbosity.DEBUG, 'keepalive', 'Sending ping to ' + this.subchannelAddressString); this.keepaliveTimeoutId = setTimeout(() => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); @@ -405,14 +406,14 @@ export class Subchannel { errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && opaqueData.equals(tooManyPingsData) ) { - logging.log( - LogVerbosity.ERROR, - `Connection to ${this.channelTarget} rejected by server because of excess pings` - ); this.keepaliveTimeMs = Math.min( 2 * this.keepaliveTimeMs, KEEPALIVE_MAX_TIME_MS ); + logging.log( + LogVerbosity.ERROR, + `Connection to ${uriToString(this.channelTarget)} at ${this.subchannelAddressString} rejected by server because of excess pings. Increasing ping interval to ${this.keepaliveTimeMs}` + ); } trace( this.subchannelAddressString + @@ -689,7 +690,7 @@ export class Subchannel { for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } - trace('Starting stream with headers\n' + headersString); + logging.trace(LogVerbosity.DEBUG, 'call_stream', 'Starting stream on subchannel ' + this.subchannelAddressString + ' with headers\n' + headersString); callStream.attachHttp2Stream(http2Stream, this, extraFilterFactory); } From c83d5a7c4deb5ffa7cfbeab3876f934c32bbe2c3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 13:23:07 -0700 Subject: [PATCH 1230/1899] Fix keepalive ping timing, change some trace logs --- packages/grpc-js/src/subchannel.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c90df85ea..394124f73 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -40,6 +40,10 @@ function trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } +function refTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'subchannel_refcount', text); +} + const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; const BACKOFF_MULTIPLIER = 1.6; @@ -278,7 +282,8 @@ export class Subchannel { this.keepaliveIntervalId = setInterval(() => { this.sendPing(); }, this.keepaliveTimeMs); - this.sendPing(); + /* Don't send a ping immediately because whatever caused us to start + * sending pings should also involve some network activity. */ } private stopKeepalivePings() { @@ -584,7 +589,7 @@ export class Subchannel { } callRef() { - trace( + refTrace( this.subchannelAddressString + ' callRefcount ' + this.callRefcount + @@ -601,7 +606,7 @@ export class Subchannel { } callUnref() { - trace( + refTrace( this.subchannelAddressString + ' callRefcount ' + this.callRefcount + @@ -619,7 +624,7 @@ export class Subchannel { } ref() { - trace( + refTrace( this.subchannelAddressString + ' refcount ' + this.refcount + @@ -630,7 +635,7 @@ export class Subchannel { } unref() { - trace( + refTrace( this.subchannelAddressString + ' refcount ' + this.refcount + From 1a47f78f4f5abcf78e29b535fdab4c9238cb6f7a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 14:17:29 -0700 Subject: [PATCH 1231/1899] Fix some trace logs, increase XdsClient keepalive interval --- packages/grpc-js/src/resolver-xds.ts | 8 ++++---- packages/grpc-js/src/subchannel.ts | 2 +- packages/grpc-js/src/xds-client.ts | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/resolver-xds.ts b/packages/grpc-js/src/resolver-xds.ts index 38cc37a6b..297c6c3fb 100644 --- a/packages/grpc-js/src/resolver-xds.ts +++ b/packages/grpc-js/src/resolver-xds.ts @@ -54,12 +54,12 @@ class XdsResolver implements Resolver { // Wait until updateResolution is called once to start the xDS requests if (!this.resolutionStarted) { this.resolutionStarted = true; - trace('Starting resolution for target ' + this.target); + trace('Starting resolution for target ' + uriToString(this.target)); const xdsClient = new XdsClient( this.target.path, { onValidUpdate: (update: ServiceConfig) => { - trace('Resolved service config for target ' + this.target + ': ' + JSON.stringify(update)); + trace('Resolved service config for target ' + uriToString(this.target) + ': ' + JSON.stringify(update)); this.hasReportedSuccess = true; this.listener.onSuccessfulResolution([], update, null, { xdsClient: xdsClient, @@ -69,12 +69,12 @@ class XdsResolver implements Resolver { /* A transient error only needs to bubble up as a failure if we have * not already provided a ServiceConfig for the upper layer to use */ if (!this.hasReportedSuccess) { - trace('Resolution error for target ' + this.target + ' due to xDS client transient error ' + error.details); + trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); this.reportResolutionError(); } }, onResourceDoesNotExist: () => { - trace('Resolution error for target ' + this.target + ': resource does not exist'); + trace('Resolution error for target ' + uriToString(this.target) + ': resource does not exist'); this.reportResolutionError(); }, }, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 394124f73..b7f2a118f 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -417,7 +417,7 @@ export class Subchannel { ); logging.log( LogVerbosity.ERROR, - `Connection to ${uriToString(this.channelTarget)} at ${this.subchannelAddressString} rejected by server because of excess pings. Increasing ping interval to ${this.keepaliveTimeMs}` + `Connection to ${uriToString(this.channelTarget)} at ${this.subchannelAddressString} rejected by server because of excess pings. Increasing ping interval to ${this.keepaliveTimeMs} ms` ); } trace( diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index bfeb4ed53..327f21561 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -777,7 +777,8 @@ export class XdsClient { for (const arg of channelArgsToRemove) { delete channelArgs[arg]; } - channelArgs['grpc.keepalive_time_ms'] = 5000; + // 5 minutes + channelArgs['grpc.keepalive_time_ms'] = 5 * 60 * 1000; this.adsBackoff = new BackoffTimeout(() => { this.maybeStartAdsStream(); From 82037fcdaffe478f1f1cfdbb3caeae9a456b9370 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 15:54:05 -0700 Subject: [PATCH 1232/1899] Add error logging to xDS interop client --- .../grpc-js/interop/xds-interop-client.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index c33c5b380..3a7418487 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -39,7 +39,7 @@ const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as interface CallEndNotifier { onCallSucceeded(peerName: string): void; - onCallFailed(): void; + onCallFailed(message: string): void; } class CallSubscriber { @@ -47,6 +47,7 @@ class CallSubscriber { private callsSucceededByPeer: {[key: string]: number} = {}; private callsSucceeded = 0; private callsFinished = 0; + private failureMessageCount: Map = new Map(); constructor(private callGoal: number, private onFinished: () => void) {} @@ -56,6 +57,10 @@ class CallSubscriber { private maybeOnFinished() { if (this.callsFinished == this.callGoal) { + console.log(`Out of a total of ${this.callsFinished} calls, ${this.callsSucceeded} succeeded`); + for (const [message, count] of this.failureMessageCount) { + console.log(`${count} failed with the message ${message}`); + } this.onFinished(); } } @@ -70,8 +75,9 @@ class CallSubscriber { this.callsFinished += 1; this.maybeOnFinished(); } - addCallFailed(): void { + addCallFailed(message: string): void { this.callsFinished += 1; + this.failureMessageCount.set(message, (this.failureMessageCount.get(message) ?? 0) + 1); this.maybeOnFinished(); } @@ -125,9 +131,9 @@ class CallStatsTracker { subscriber.addCallSucceeded(peerName); } }, - onCallFailed: () => { + onCallFailed: (message: string) => { for (const subscriber of callSubscribers) { - subscriber.addCallFailed(); + subscriber.addCallFailed(message); } } } @@ -150,12 +156,12 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc } completed = true; completedWithError = true; - notifier.onCallFailed(); + notifier.onCallFailed(error.message); } else { anyCallSucceeded = true; if (gotMetadata) { if (hostname === null) { - notifier.onCallFailed() + notifier.onCallFailed('Hostname omitted from call metadata'); } else { notifier.onCallSucceeded(hostname); } @@ -167,7 +173,7 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc gotMetadata = true; if (completed && !completedWithError) { if (hostname === null) { - notifier.onCallFailed(); + notifier.onCallFailed('Hostname omitted from call metadata'); } else { notifier.onCallSucceeded(hostname); } From 597fc1c57bac0c83e2864940007643a644fa7990 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 27 Aug 2020 18:14:03 -0700 Subject: [PATCH 1233/1899] Use the same channel for ADS and LRS clients --- packages/grpc-js/src/channel-options.ts | 2 +- packages/grpc-js/src/xds-client.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 8c4756ec7..ee4833b4b 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -33,7 +33,7 @@ export interface ChannelOptions { 'grpc.max_send_message_length'?: number; 'grpc.max_receive_message_length'?: number; 'grpc.enable_http_proxy'?: number; - [key: string]: string | number | undefined; + [key: string]: any; } /** diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 327f21561..1c4f149bf 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -816,7 +816,7 @@ export class XdsClient { this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( bootstrapInfo.xdsServers[0].serverUri, createGoogleDefaultCredentials(), - channelArgs + {channelOverride: this.adsClient.getChannel()} ); this.maybeStartLrsStream(); }, From 8269fd4bca21b428bc50c8d0b373aa235ead2719 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 09:50:33 -0700 Subject: [PATCH 1234/1899] priority: improve tracing, cancel failover timer when selecting child --- packages/grpc-js/src/load-balancer-priority.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js/src/load-balancer-priority.ts index 6539e4b4e..74f2e9781 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js/src/load-balancer-priority.ts @@ -111,6 +111,7 @@ export class PriorityLoadBalancer implements LoadBalancer { } private updateState(connectivityState: ConnectivityState, picker: Picker) { + trace('Child ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; this.parent.onChildStateChange(this); @@ -118,7 +119,9 @@ export class PriorityLoadBalancer implements LoadBalancer { private startFailoverTimer() { if (this.failoverTimer === null) { + trace('Starting failover timer for child ' + this.name); this.failoverTimer = setTimeout(() => { + trace('Failover timer triggered for child ' + this.name); this.failoverTimer = null; this.updateState( ConnectivityState.TRANSIENT_FAILURE, @@ -308,6 +311,7 @@ export class PriorityLoadBalancer implements LoadBalancer { private selectPriority(priority: number) { this.currentPriority = priority; const chosenChild = this.children.get(this.priorities[priority])!; + chosenChild.cancelFailoverTimer(); this.updateState( chosenChild.getConnectivityState(), chosenChild.getPicker() From 338941d6642228381b17d76d6ba15f761d79d207 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 10:06:57 -0700 Subject: [PATCH 1235/1899] Add more LRS tracing --- packages/grpc-js/src/xds-client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 1c4f149bf..62f14f61b 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1027,7 +1027,9 @@ export class XdsClient { const loadReportingIntervalMs = Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + message.load_reporting_interval!.nanos / 1_000_000; + trace('Received LRS request with load reporting interval ' + loadReportingIntervalMs + ' ms'); this.statsTimer = setInterval(() => { + trace('Sending LRS stats'); this.sendStats(); }, loadReportingIntervalMs); } From 60bc11285b5da059e641eb9e5b957b9be305014e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 10:43:16 -0700 Subject: [PATCH 1236/1899] Send buffered stats when starting LRS stream --- packages/grpc-js/src/xds-client.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 62f14f61b..39c01646a 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1029,7 +1029,6 @@ export class XdsClient { message.load_reporting_interval!.nanos / 1_000_000; trace('Received LRS request with load reporting interval ' + loadReportingIntervalMs + ' ms'); this.statsTimer = setInterval(() => { - trace('Sending LRS stats'); this.sendStats(); }, loadReportingIntervalMs); } @@ -1047,15 +1046,16 @@ export class XdsClient { this.maybeStartLrsStream(); } }); - this.lrsCall.write({ - node: this.lrsNode!, - }); + /* Send buffered stats information when starting LRS stream. If there is no + * buffered stats information, it will still send the node field. */ + this.sendStats(); } private sendStats() { if (!this.lrsCall) { return; } + trace('Sending LRS stats'); const clusterStats: ClusterStats[] = []; for (const [ { clusterName, edsServiceName }, From b9962feff080c2ef2aa91e14bdb4044a77666853 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 11:17:52 -0700 Subject: [PATCH 1237/1899] Add more interop client logging --- packages/grpc-js/interop/xds-interop-client.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 3a7418487..d9d7c4416 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -52,20 +52,18 @@ class CallSubscriber { constructor(private callGoal: number, private onFinished: () => void) {} addCallStarted(): void { + console.log('Call started'); this.callsStarted += 1; } private maybeOnFinished() { if (this.callsFinished == this.callGoal) { - console.log(`Out of a total of ${this.callsFinished} calls, ${this.callsSucceeded} succeeded`); - for (const [message, count] of this.failureMessageCount) { - console.log(`${count} failed with the message ${message}`); - } this.onFinished(); } } addCallSucceeded(peerName: string): void { + console.log(`Call to ${peerName} succeeded`); if (peerName in this.callsSucceededByPeer) { this.callsSucceededByPeer[peerName] += 1; } else { @@ -76,6 +74,7 @@ class CallSubscriber { this.maybeOnFinished(); } addCallFailed(message: string): void { + console.log(`Call failed with message ${message}`); this.callsFinished += 1; this.failureMessageCount.set(message, (this.failureMessageCount.get(message) ?? 0) + 1); this.maybeOnFinished(); @@ -86,6 +85,10 @@ class CallSubscriber { } getFinalStats(): LoadBalancerStatsResponse { + console.log(`Out of a total of ${this.callGoal} calls requested, ${this.callsFinished} finished. ${this.callsSucceeded} succeeded`); + for (const [message, count] of this.failureMessageCount) { + console.log(`${count} failed with the message ${message}`); + } return { rpcs_by_peer: this.callsSucceededByPeer, num_failures: this.callsStarted - this.callsSucceeded From 5827b3e01d2c95746bcc699ab3ce5f844e1100a4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 11:49:03 -0700 Subject: [PATCH 1238/1899] Reset saved LRS settings when the LRS stream ends --- packages/grpc-js/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 39c01646a..0b1fa7b9c 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -1039,6 +1039,7 @@ export class XdsClient { 'LRS stream ended. code=' + error.code + ' details= ' + error.details ); this.lrsCall = null; + this.latestLrsSettings = null; clearInterval(this.statsTimer); /* If the backoff timer is no longer running, we do not need to wait any * more to start the new call. */ From 36db24e39f0931a5c16a2c9add6350df45b84a29 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Aug 2020 12:50:53 -0700 Subject: [PATCH 1239/1899] Set a deadline on outgoing requests in the xds interop client --- packages/grpc-js/interop/xds-interop-client.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index d9d7c4416..949da238e 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -37,6 +37,8 @@ const packageDefinition = protoLoader.loadSync('grpc/testing/test.proto', { const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as ProtoGrpcType; +const REQUEST_TIMEOUT_SEC = 20; + interface CallEndNotifier { onCallSucceeded(peerName: string): void; onCallFailed(message: string): void; @@ -151,7 +153,9 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc let hostname: string | null = null; let completed: boolean = false; let completedWithError: boolean = false; - const call = client.emptyCall({}, (error, value) => { + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + REQUEST_TIMEOUT_SEC); + const call = client.emptyCall({}, {deadline}, (error, value) => { if (error) { if (failOnFailedRpcs && anyCallSucceeded) { console.error('A call failed after a call succeeded'); From c536178c675aa3527aa8cd366a274009ed7a050c Mon Sep 17 00:00:00 2001 From: WK Date: Sat, 29 Aug 2020 19:05:42 +0800 Subject: [PATCH 1240/1899] Fixed connectivity to Google PubSub over proxy Latest version has caused @google-cloud/pubsub fail to connect over a proxy connection. Snapshot of error: 2020-08-29T10:52:45.340Z | proxy | Successfully connected to pubsub.googleapis.c om:443 through proxy 172.16.52.252:443 2020-08-29T10:52:45.370Z | subchannel | 172.16.52.252:443 CONNECTING -> TRANSIEN T_FAILURE 2020-08-29T10:52:45.372Z | pick_first | CONNECTING -> TRANSIENT_FAILURE 2020-08-29T10:52:45.373Z | resolving_load_balancer | dns:172.16.52.252:443 CONNE CTING -> TRANSIENT_FAILURE 2020-08-29T10:52:45.375Z | channel | Pick result: TRANSIENT_FAILURE subchannel: undefined status: 14 No connection established 2020-08-29T10:52:45.377Z | call_stream | [11] cancelWithStatus code: 14 details: "No connection established" 2020-08-29T10:52:45.379Z | call_stream | [11] ended with status: code=14 details ="No connection established" 2020-08-29T10:52:45.381Z | connectivity_state | dns:172.16.52.252:443 CONNECTING -> TRANSIENT_FAILURE Before proposed fix: static getDefaultAuthority(target) { return target.path; // this returns "pubsub.googleapis.com:443" } After proposed fix: static getDefaultAuthority(target) { const hostPort = uri_parser_1.splitHostPort(target.path); // target.path is "pubsub.googleapis.com:443" if (hostPort !== null) { return hostPort.host; // this returns "pubsub.googleapis.com" } else { throw new Error(`Failed to parse target ${uri_parser_1.uriToString(target)}`); } } --- packages/grpc-js/src/resolver-dns.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 2db8a5e41..3f28254bd 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -268,7 +268,13 @@ class DnsResolver implements Resolver { * @param target */ static getDefaultAuthority(target: GrpcUri): string { - return target.path; + const hostPort = uri_parser_1.splitHostPort(target.path); + if (hostPort !== null) { + return hostPort.host; + } + else { + throw new Error(`Failed to parse target ${uri_parser_1.uriToString(target)}`); + } } } From 6f3db6f4d89c8fcd308e700374c69aadf864b19f Mon Sep 17 00:00:00 2001 From: WK Date: Sun, 30 Aug 2020 14:49:54 +0800 Subject: [PATCH 1241/1899] Update http_proxy.ts --- packages/grpc-js/src/http_proxy.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 8411e117d..e3fdee050 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -215,8 +215,10 @@ export function getProxiedConnection( * connection to a TLS connection. * This is a workaround for https://github.com/nodejs/node/issues/32922 * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ - const remoteHost = getDefaultAuthority(parsedTarget); - + const targetPath = getDefaultAuthority(parsedTarget); + const hostPort = splitHostPort(targetPath); + const remoteHost = (hostPort !== null) ? hostPort.host : targetPath; + const cts = tls.connect( { host: remoteHost, From 08350ec0efe84eabbb3e950fcdce6d470fe6c555 Mon Sep 17 00:00:00 2001 From: WK Date: Sun, 30 Aug 2020 14:52:20 +0800 Subject: [PATCH 1242/1899] Update subchannel.ts --- packages/grpc-js/src/subchannel.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 736562a66..878052466 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -467,11 +467,13 @@ export class Subchannel { * if a connection is successfully established through the proxy. * If the proxy is not used, these connectionOptions are discarded * anyway */ - connectionOptions.servername = getDefaultAuthority( + const targetPath = getDefaultAuthority( parseUri(this.options['grpc.http_connect_target'] as string) ?? { path: 'localhost', } ); + const hostPort = splitHostPort(targetPath); + connectionOptions.servername = (hostPort !== null) ? hostPort.host : targetPath; } } } From 6a99983ed110433cedd432c8f020b123aaaf4fd7 Mon Sep 17 00:00:00 2001 From: WK Date: Sun, 30 Aug 2020 14:56:23 +0800 Subject: [PATCH 1243/1899] Undo changes. --- packages/grpc-js/src/resolver-dns.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 3f28254bd..2db8a5e41 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -268,13 +268,7 @@ class DnsResolver implements Resolver { * @param target */ static getDefaultAuthority(target: GrpcUri): string { - const hostPort = uri_parser_1.splitHostPort(target.path); - if (hostPort !== null) { - return hostPort.host; - } - else { - throw new Error(`Failed to parse target ${uri_parser_1.uriToString(target)}`); - } + return target.path; } } From 2d1cb15dec0549cf069863e1e14df7dd72305be1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 09:40:17 -0700 Subject: [PATCH 1244/1899] Fix imports for messages without packages --- packages/proto-loader/bin/proto-loader-gen-types.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 0d71e5495..2e001e8c7 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -96,6 +96,9 @@ function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { function getPathToRoot(from: Protobuf.NamespaceBase) { const depth = stripLeadingPeriod(from.fullName).split('.').length - 1; + if (depth === 0) { + return './'; + } let path = ''; for (let i = 0; i < depth; i++) { path += '../'; From 62bd1cab6875d1127268db46d75092ffdbc59090 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 09:55:29 -0700 Subject: [PATCH 1245/1899] Add granular verbosity option to xDS interop client --- .../grpc-js/interop/xds-interop-client.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 949da238e..3009541c4 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -39,6 +39,8 @@ const loadedProto = grpc.loadPackageDefinition(packageDefinition) as unknown as const REQUEST_TIMEOUT_SEC = 20; +const VERBOSITY = Number.parseInt(process.env.NODE_XDS_INTEROP_VERBOSITY ?? '0'); + interface CallEndNotifier { onCallSucceeded(peerName: string): void; onCallFailed(message: string): void; @@ -54,7 +56,9 @@ class CallSubscriber { constructor(private callGoal: number, private onFinished: () => void) {} addCallStarted(): void { - console.log('Call started'); + if (VERBOSITY >= 2) { + console.log('Call started'); + } this.callsStarted += 1; } @@ -65,7 +69,9 @@ class CallSubscriber { } addCallSucceeded(peerName: string): void { - console.log(`Call to ${peerName} succeeded`); + if (VERBOSITY >= 2) { + console.log(`Call to ${peerName} succeeded`); + } if (peerName in this.callsSucceededByPeer) { this.callsSucceededByPeer[peerName] += 1; } else { @@ -76,7 +82,9 @@ class CallSubscriber { this.maybeOnFinished(); } addCallFailed(message: string): void { - console.log(`Call failed with message ${message}`); + if (VERBOSITY >= 2) { + console.log(`Call failed with message ${message}`); + } this.callsFinished += 1; this.failureMessageCount.set(message, (this.failureMessageCount.get(message) ?? 0) + 1); this.maybeOnFinished(); @@ -87,9 +95,11 @@ class CallSubscriber { } getFinalStats(): LoadBalancerStatsResponse { - console.log(`Out of a total of ${this.callGoal} calls requested, ${this.callsFinished} finished. ${this.callsSucceeded} succeeded`); - for (const [message, count] of this.failureMessageCount) { - console.log(`${count} failed with the message ${message}`); + if (VERBOSITY >= 1) { + console.log(`Out of a total of ${this.callGoal} calls requested, ${this.callsFinished} finished. ${this.callsSucceeded} succeeded`); + for (const [message, count] of this.failureMessageCount) { + console.log(`${count} failed with the message ${message}`); + } } return { rpcs_by_peer: this.callsSucceededByPeer, From 148b273f196ee5bdfc4a6459d07a5d6440edc0c9 Mon Sep 17 00:00:00 2001 From: WK Date: Tue, 1 Sep 2020 01:28:53 +0800 Subject: [PATCH 1246/1899] Update http_proxy.ts --- packages/grpc-js/src/http_proxy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index e3fdee050..84e29a50f 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -217,7 +217,7 @@ export function getProxiedConnection( * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ const targetPath = getDefaultAuthority(parsedTarget); const hostPort = splitHostPort(targetPath); - const remoteHost = (hostPort !== null) ? hostPort.host : targetPath; + const remoteHost = hostPort?.host ?? targetPath; const cts = tls.connect( { From 7fc0035f7f84646269fd391f9cb80ab404f5319a Mon Sep 17 00:00:00 2001 From: WK Date: Tue, 1 Sep 2020 01:30:35 +0800 Subject: [PATCH 1247/1899] Update subchannel.ts --- packages/grpc-js/src/subchannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 878052466..a8c81df80 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -473,7 +473,7 @@ export class Subchannel { } ); const hostPort = splitHostPort(targetPath); - connectionOptions.servername = (hostPort !== null) ? hostPort.host : targetPath; + connectionOptions.servername = hostPort?.host ?? : targetPath; } } } From 158d0dd99f9997e2ad34cec2fc756ae21bddc5f9 Mon Sep 17 00:00:00 2001 From: WK Date: Tue, 1 Sep 2020 01:40:14 +0800 Subject: [PATCH 1248/1899] Update subchannel.ts --- packages/grpc-js/src/subchannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index a8c81df80..3be6dd0a6 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -473,7 +473,7 @@ export class Subchannel { } ); const hostPort = splitHostPort(targetPath); - connectionOptions.servername = hostPort?.host ?? : targetPath; + connectionOptions.servername = hostPort?.host ?? targetPath; } } } From 38e988ea03bd76ab4002e69903d43d3fe1b31fd9 Mon Sep 17 00:00:00 2001 From: Slavo Vojacek Date: Mon, 31 Aug 2020 20:34:14 +0100 Subject: [PATCH 1249/1899] fix(grpc-js): Add support for impl type to server.addService --- packages/grpc-js/src/server.ts | 11 ++++++++--- packages/grpc-js/test/test-server.ts | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8d8952e8f..673e913d4 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -144,9 +144,14 @@ export class Server { throw new Error('Not implemented. Use addService() instead'); } - addService( - service: ServiceDefinition, - implementation: UntypedServiceImplementation + addService< + ImplementationType extends Record< + string, + UntypedHandleCall + > = UntypedServiceImplementation + >( + service: ServiceDefinition, + implementation: ImplementationType ): void { if (this.started === true) { throw new Error("Can't add a service to a started server."); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 434efbbc4..f8b13b309 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -181,7 +181,7 @@ describe('Server', () => { const server = new Server(); assert.throws(() => { - server.addService({}, dummyImpls); + server.addService({} as any, dummyImpls); }, /Cannot add an empty service to a server/); }); From 286c81a9240f30adb4c4b58252fdcaaba8c1f915 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 14:04:53 -0700 Subject: [PATCH 1250/1899] Handle endpoint health_status, improve some logging --- packages/grpc-js/src/load-balancer-eds.ts | 41 ++++++++++++++--------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index c0d90e8ee..2e606fcff 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -217,6 +217,10 @@ export class EdsLoadBalancer implements LoadBalancer { weight: number; addresses: SubchannelAddress[]; }[][] = []; + /** + * New replacement for this.localityPriorities, mapping locality names to + * priority values. The replacement occurrs at the end of this method. + */ const newLocalityPriorities: Map = new Map< string, number @@ -225,12 +229,7 @@ export class EdsLoadBalancer implements LoadBalancer { * loop consolidates localities into buckets by priority, while also * simplifying the data structure to make the later steps simpler */ for (const endpoint of this.latestEdsUpdate.endpoints) { - let localityArray = priorityList[endpoint.priority]; - if (localityArray === undefined) { - localityArray = []; - priorityList[endpoint.priority] = localityArray; - } - const addresses: SubchannelAddress[] = endpoint.lb_endpoints.map( + const addresses: SubchannelAddress[] = endpoint.lb_endpoints.filter(lbEndpoint => lbEndpoint.health_status === 'UNKNOWN' || lbEndpoint.health_status === 'HEALTHY').map( (lbEndpoint) => { /* The validator in the XdsClient class ensures that each endpoint has * a socket_address with an IP address and a port_value. */ @@ -241,15 +240,22 @@ export class EdsLoadBalancer implements LoadBalancer { }; } ); - localityArray.push({ - locality: endpoint.locality!, - addresses: addresses, - weight: endpoint.load_balancing_weight?.value ?? 0, - }); - newLocalityPriorities.set( - localityToName(endpoint.locality!), - endpoint.priority - ); + if (addresses.length > 0) { + let localityArray = priorityList[endpoint.priority]; + if (localityArray === undefined) { + localityArray = []; + priorityList[endpoint.priority] = localityArray; + } + localityArray.push({ + locality: endpoint.locality!, + addresses: addresses, + weight: endpoint.load_balancing_weight?.value ?? 0, + }); + newLocalityPriorities.set( + localityToName(endpoint.locality!), + endpoint.priority + ); + } } const newPriorityNames: string[] = []; @@ -266,6 +272,7 @@ export class EdsLoadBalancer implements LoadBalancer { * - Otherwise, construct a new name using this.nextPriorityChildNumber. */ for (const [priority, localityArray] of priorityList.entries()) { + // Skip priorities that have no localities with healthy endpoints if (localityArray === undefined) { continue; } @@ -367,7 +374,9 @@ export class EdsLoadBalancer implements LoadBalancer { }, }; trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); - trace('Child update service config: ' + JSON.stringify(childConfig)); + for (const [childName, child] of childConfig.priority.priorities.entries()) { + trace('Child update priority config: ' + childName + ' -> ' + JSON.stringify(child)); + } this.childBalancer.updateAddressList( addressList, childConfig, From 2c98a3d3f9728104498566a2f25bdf857fae99df Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Aug 2020 15:18:00 -0700 Subject: [PATCH 1251/1899] More EDS logging, and improved weight handling --- packages/grpc-js/src/load-balancer-eds.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 2e606fcff..ccc56e9f8 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -135,6 +135,7 @@ export class EdsLoadBalancer implements LoadBalancer { }); this.watcher = { onValidUpdate: (update) => { + trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update)); this.latestEdsUpdate = update; this.updateChild(); }, @@ -229,6 +230,9 @@ export class EdsLoadBalancer implements LoadBalancer { * loop consolidates localities into buckets by priority, while also * simplifying the data structure to make the later steps simpler */ for (const endpoint of this.latestEdsUpdate.endpoints) { + if (!endpoint.load_balancing_weight) { + continue; + } const addresses: SubchannelAddress[] = endpoint.lb_endpoints.filter(lbEndpoint => lbEndpoint.health_status === 'UNKNOWN' || lbEndpoint.health_status === 'HEALTHY').map( (lbEndpoint) => { /* The validator in the XdsClient class ensures that each endpoint has @@ -249,7 +253,7 @@ export class EdsLoadBalancer implements LoadBalancer { localityArray.push({ locality: endpoint.locality!, addresses: addresses, - weight: endpoint.load_balancing_weight?.value ?? 0, + weight: endpoint.load_balancing_weight.value, }); newLocalityPriorities.set( localityToName(endpoint.locality!), @@ -374,7 +378,8 @@ export class EdsLoadBalancer implements LoadBalancer { }, }; trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); - for (const [childName, child] of childConfig.priority.priorities.entries()) { + trace('Child update priority list: ' + childConfig.priority.priorities); + for (const [childName, child] of childConfig.priority.children) { trace('Child update priority config: ' + childName + ' -> ' + JSON.stringify(child)); } this.childBalancer.updateAddressList( From 5e42be1b3485949ccecd6b9068d603b298177e17 Mon Sep 17 00:00:00 2001 From: Algin Maduro Date: Tue, 1 Sep 2020 12:59:07 +0200 Subject: [PATCH 1252/1899] fix: preserve original error code if present --- packages/grpc-js/src/server-call.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 3ff4c55e5..7c7400133 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -743,7 +743,10 @@ export class Http2ServerCallStream< // Ignore any remaining messages when errors occur. this.bufferedMessages.length = 0; - err.code = Status.INTERNAL; + if(!err.code){ + err.code = Status.INTERNAL; + } + readable.emit('error', err); } From aaee068a6972d9ff18db8fc19c460b02b1a0b5ff Mon Sep 17 00:00:00 2001 From: Algin Maduro Date: Tue, 1 Sep 2020 13:28:23 +0200 Subject: [PATCH 1253/1899] fix: add addition check if the provided code is valid gRPC code --- packages/grpc-js/src/server-call.ts | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 7c7400133..fad0eddb0 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -739,15 +739,24 @@ export class Http2ServerCallStream< } else { this.messagesToPush.push(deserialized); } - } catch (err) { + } catch (error) { // Ignore any remaining messages when errors occur. this.bufferedMessages.length = 0; - if(!err.code){ - err.code = Status.INTERNAL; + if ( + !( + 'code' in error && + typeof error.code === 'number' && + Number.isInteger(error.code) && + error.code >= Status.OK && + error.code <= Status.UNAUTHENTICATED + ) + ) { + // The error code is not a valid gRPC code so its being overwritten. + error.code = Status.INTERNAL; } - - readable.emit('error', err); + + readable.emit('error', error); } this.isPushPending = false; From b2d89820a3ba920fc5a4ea35dad63a857b546346 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaroslav=20=C5=A0mol=C3=ADk?= Date: Tue, 1 Sep 2020 14:24:25 +0200 Subject: [PATCH 1254/1899] Fix ClientOptions types Remove index signature from ChannelOptions to fix intersection error described in #1558 which causes issues on using ClientOptions direct fields with TypeScript. Removing of index signature required few minor changes: - adding few constant types that were used throughout the app - using `as const` assertion in xds-client - using not-so-great type cast in channelOptionsEqual Alternative solution would be removing the index signature from ChannelOptions explicitly in ClientOptions definition, which is not trivial and probably calls for a generic type helper. See: https://github.com/grpc/grpc-node/issues/1558 Fixes: #1558 --- packages/grpc-js/src/channel-options.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 8c4756ec7..f316a58a0 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -33,7 +33,9 @@ export interface ChannelOptions { 'grpc.max_send_message_length'?: number; 'grpc.max_receive_message_length'?: number; 'grpc.enable_http_proxy'?: number; - [key: string]: string | number | undefined; + 'grpc.http_connect_target'?: string; + 'grpc.http_connect_creds'?: string; + [key: string]: any; } /** From 0d1d5a12fa1e3ee444db6929e9f7707b6bde5bc1 Mon Sep 17 00:00:00 2001 From: Slavo Vojacek Date: Wed, 2 Sep 2020 16:05:10 +0100 Subject: [PATCH 1255/1899] chore(Typings): Update types --- packages/grpc-js/src/server.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 673e913d4..9b5f3af8b 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -145,10 +145,9 @@ export class Server { } addService< - ImplementationType extends Record< - string, - UntypedHandleCall - > = UntypedServiceImplementation + ImplementationType extends { + readonly [index in keyof ImplementationType]: UntypedHandleCall; + } >( service: ServiceDefinition, implementation: ImplementationType @@ -166,7 +165,7 @@ export class Server { throw new Error('addService() requires two objects as arguments'); } - const serviceKeys = Object.keys(service); + const serviceKeys = Object.keys(service) as Array; if (serviceKeys.length === 0) { throw new Error('Cannot add an empty service to a server'); @@ -194,13 +193,13 @@ export class Server { let impl; if (implFn === undefined && typeof attrs.originalName === 'string') { - implFn = implementation[attrs.originalName]; + implFn = implementation[attrs.originalName as keyof ImplementationType]; } if (implFn !== undefined) { - impl = implFn.bind(implementation); + impl = implFn.bind(implementation as any); } else { - impl = getDefaultHandler(methodType, name); + impl = getDefaultHandler(methodType, name as string); } const success = this.register( From fba1ee0cc398c63d0a3e960e8418eb8dd3dbe30c Mon Sep 17 00:00:00 2001 From: Slavo Vojacek Date: Wed, 2 Sep 2020 20:32:31 +0100 Subject: [PATCH 1256/1899] fix(grpc): Fix typings --- packages/grpc-js/src/server.ts | 10 +++++----- packages/grpc-js/test/test-server.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 9b5f3af8b..64c17a023 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -146,7 +146,7 @@ export class Server { addService< ImplementationType extends { - readonly [index in keyof ImplementationType]: UntypedHandleCall; + [key: string]: any } >( service: ServiceDefinition, @@ -165,7 +165,7 @@ export class Server { throw new Error('addService() requires two objects as arguments'); } - const serviceKeys = Object.keys(service) as Array; + const serviceKeys = Object.keys(service); if (serviceKeys.length === 0) { throw new Error('Cannot add an empty service to a server'); @@ -193,13 +193,13 @@ export class Server { let impl; if (implFn === undefined && typeof attrs.originalName === 'string') { - implFn = implementation[attrs.originalName as keyof ImplementationType]; + implFn = implementation[attrs.originalName]; } if (implFn !== undefined) { - impl = implFn.bind(implementation as any); + impl = implFn.bind(implementation); } else { - impl = getDefaultHandler(methodType, name as string); + impl = getDefaultHandler(methodType, name); } const success = this.register( diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index f8b13b309..b30963fb0 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -181,7 +181,7 @@ describe('Server', () => { const server = new Server(); assert.throws(() => { - server.addService({} as any, dummyImpls); + server.addService(({} as any), dummyImpls); }, /Cannot add an empty service to a server/); }); From 677741d442c45193028ccd7ebfafdef5e5e4670f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Sep 2020 13:35:43 -0700 Subject: [PATCH 1257/1899] ConstructorParameters is already a TypeScript builtin --- packages/proto-loader/bin/proto-loader-gen-types.ts | 3 +-- packages/proto-loader/golden-generated/echo.ts | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 2e001e8c7..1238e0402 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -604,9 +604,8 @@ function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options generateServiceImports(formatter, root, options); formatter.writeLine(''); - formatter.writeLine('type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never;'); formatter.writeLine('type SubtypeConstructor = {'); - formatter.writeLine(' new(...args: ConstructorArguments): Subtype;'); + formatter.writeLine(' new(...args: ConstructorParameters): Subtype;'); formatter.writeLine('};'); formatter.writeLine(''); diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index e875e5076..f24c35ec5 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -4,9 +4,8 @@ import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@g import { OperationsClient as _google_longrunning_OperationsClient } from './google/longrunning/Operations'; import { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/showcase/v1beta1/Echo'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { From 2d4ab786da02a5d8de689c96f33cfecad34ccef6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Sep 2020 15:00:46 -0700 Subject: [PATCH 1258/1899] Add xds kokoro config and update the test script --- packages/grpc-js/scripts/xds.sh | 22 +++++++++++++--------- test/kokoro/linux.cfg | 1 - test/kokoro/xds-interop.cfg | 24 ++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 test/kokoro/xds-interop.cfg diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ae169eebb..76f6b214d 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -1,10 +1,19 @@ #!/bin/bash +# Install NVM +cd ~ +export NVM_DIR=`pwd`/.nvm +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.4/install.sh | bash + +# Load NVM +. $NVM_DIR/nvm.sh + +nvm install 12 + set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION -cd $(dirname $0) -cd .. +cd $(dirname $0)/.. base=$(pwd) npm run compile @@ -14,14 +23,9 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -# Test cases "path_matching" and "header_matching" are not included in "all", -# because not all interop clients in all languages support these new tests. -# -# TODO: remove "path_matching" and "header_matching" from --test_case after -# they are added into "all". -GRPC_NODE_TRACE=all GRPC_NODE_VERBOSITY=DEBUG \ +GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver GRPC_NODE_VERBOSITY=DEBUG \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all" \ + --test_case="backends_restart,change_backend_service,gentle_failover,ping_pong,remove_instance_group,round_robin,secondary_locality_gets_no_requests_on_partial_primary_failure,secondary_locality_gets_requests_on_primary_failure" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 24ed01aba..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -20,6 +20,5 @@ timeout_mins: 60 action { define_artifacts { regex: "github/grpc-node/reports/**/sponge_log.xml" - regex: "github/grpc/reports/**" } } diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg new file mode 100644 index 000000000..81a038736 --- /dev/null +++ b/test/kokoro/xds-interop.cfg @@ -0,0 +1,24 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc/reports/**" + } +} From 1fc284f59d67b4120dec5f8fc6372f5aa5741eca Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Sep 2020 15:17:57 -0700 Subject: [PATCH 1259/1899] Revert "fix(grpc-js): Add support for impl type to server.addService" --- packages/grpc-js/src/server.ts | 10 +++------- packages/grpc-js/test/test-server.ts | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 64c17a023..8d8952e8f 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -144,13 +144,9 @@ export class Server { throw new Error('Not implemented. Use addService() instead'); } - addService< - ImplementationType extends { - [key: string]: any - } - >( - service: ServiceDefinition, - implementation: ImplementationType + addService( + service: ServiceDefinition, + implementation: UntypedServiceImplementation ): void { if (this.started === true) { throw new Error("Can't add a service to a started server."); diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index b30963fb0..434efbbc4 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -181,7 +181,7 @@ describe('Server', () => { const server = new Server(); assert.throws(() => { - server.addService(({} as any), dummyImpls); + server.addService({}, dummyImpls); }, /Cannot add an empty service to a server/); }); From d8e00689d05cc0b5e5e46f60628edb30d9279c4b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 3 Sep 2020 14:32:30 -0700 Subject: [PATCH 1260/1899] Bump grpc-js to 1.1.6 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7deb248e2..a8428b249 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.5", + "version": "1.1.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 46ac39b1e2c3314cb73e216b30ff02c21c0f0ff2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Sep 2020 09:56:45 -0700 Subject: [PATCH 1261/1899] Add copyright notice to the new script --- packages/grpc-js/scripts/xds.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 76f6b214d..bd30702c7 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -1,4 +1,17 @@ #!/bin/bash +# Copyright 2020 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. # Install NVM cd ~ From b99872eee7e2a39f8345f01431376f0813885783 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Sep 2020 14:50:18 -0700 Subject: [PATCH 1262/1899] grpc-js: xDS: handle insecure and google_default bootstrap creds --- packages/grpc-js/src/xds-client.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 0b1fa7b9c..8ca4cfa27 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -19,7 +19,7 @@ import * as protoLoader from '@grpc/proto-loader'; import { loadPackageDefinition } from './make-client'; import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; -import { createGoogleDefaultCredentials } from './channel-credentials'; +import { createGoogleDefaultCredentials, ChannelCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; import { ClientDuplexStream, ServiceError } from './call'; import { StatusObject } from './call-stream'; @@ -805,17 +805,38 @@ export class XdsClient { ...node, client_features: ['envoy.lrs.supports_send_all_clusters'], }; + const credentialsConfigs = bootstrapInfo.xdsServers[0].channelCreds; + let channelCreds: ChannelCredentials | null = null; + for (const config of credentialsConfigs) { + if (config.type === 'google_default') { + channelCreds = createGoogleDefaultCredentials(); + break; + } else if (config.type === 'insecure') { + channelCreds = ChannelCredentials.createInsecure(); + break; + } + } + if (channelCreds === null) { + trace('Failed to initialize xDS Client. No valid credentials types found.'); + // Bubble this error up to any listeners + this.reportStreamError({ + code: Status.INTERNAL, + details: 'Failed to initialize xDS Client. No valid credentials types found.', + metadata: new Metadata(), + }); + return; + } trace('Starting xDS client connected to server URI ' + bootstrapInfo.xdsServers[0].serverUri); this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( bootstrapInfo.xdsServers[0].serverUri, - createGoogleDefaultCredentials(), + channelCreds, channelArgs ); this.maybeStartAdsStream(); this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( bootstrapInfo.xdsServers[0].serverUri, - createGoogleDefaultCredentials(), + channelCreds, {channelOverride: this.adsClient.getChannel()} ); this.maybeStartLrsStream(); From 58801acf1ef14c40c325d6b00b6730d4ca7cfc3e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Sep 2020 10:47:09 -0700 Subject: [PATCH 1263/1899] grpc-js: Fix path handling in xds interop script --- packages/grpc-js/scripts/xds.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index bd30702c7..126660695 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -13,6 +13,9 @@ # See the License for the specific language governing permissions and # limitations under the License. +cd $(dirname $0)/.. +base=$(pwd) + # Install NVM cd ~ export NVM_DIR=`pwd`/.nvm @@ -26,8 +29,7 @@ nvm install 12 set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION -cd $(dirname $0)/.. -base=$(pwd) +cd $base npm run compile cd ../../.. From d32734f49153141b20a1e0e10a3fb3d25a5dcde2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Sep 2020 13:03:31 -0700 Subject: [PATCH 1264/1899] grpc-js: Allow clients and servers to send metadata of unlimited size --- packages/grpc-js/src/server.ts | 4 +++- packages/grpc-js/src/subchannel.ts | 1 + test/api/interop_extra_test.js | 23 +++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 8d8952e8f..d54d61f4d 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -246,7 +246,9 @@ export class Server { throw new Error(`Could not get a default scheme for port "${port}"`); } - const serverOptions: http2.ServerOptions = {}; + const serverOptions: http2.ServerOptions = { + maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER + }; if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { maxConcurrentStreams: this.options['grpc.max_concurrent_streams'], diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 3be6dd0a6..7586d50e5 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -291,6 +291,7 @@ export class Subchannel { ); let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; + connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { addressScheme = 'https://'; diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 67130e033..ddd72298c 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -168,6 +168,29 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert.ifError(error); }); }); + it('should be able to send very large headers and trailers', function(done) { + done = multiDone(done, 3); + const header = 'X'.repeat(64 * 1024); + const trailer = Buffer.from('Y'.repeat(64 * 1024)); + const metadata = new Metadata(); + metadata.set('x-grpc-test-echo-initial', header); + metadata.set('x-grpc-test-echo-trailing-bin', trailer); + const call = client.unaryCall({}, metadata, (error, result) => { + assert.ifError(error); + done(); + }); + call.on('metadata', (metadata) => { + assert.deepStrictEqual(metadata.get('x-grpc-test-echo-initial'), + [header]); + done(); + }); + call.on('status', (status) => { + var echo_trailer = status.metadata.get('x-grpc-test-echo-trailing-bin'); + assert(echo_trailer.length === 1); + assert.strictEqual(echo_trailer[0].toString('ascii'), 'Y'.repeat(64 * 1024)); + done(); + }); + }); describe('max message size', function() { // A size that is larger than the default limit const largeMessageSize = 8 * 1024 * 1024; From f6e3ca38114fb4a1987ed4b540925b24164670c0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Sep 2020 13:42:49 -0700 Subject: [PATCH 1265/1899] Fix an error in the new test --- test/api/interop_extra_test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index ddd72298c..996fadfd4 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -172,7 +172,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio done = multiDone(done, 3); const header = 'X'.repeat(64 * 1024); const trailer = Buffer.from('Y'.repeat(64 * 1024)); - const metadata = new Metadata(); + const metadata = new grpc.Metadata(); metadata.set('x-grpc-test-echo-initial', header); metadata.set('x-grpc-test-echo-trailing-bin', trailer); const call = client.unaryCall({}, metadata, (error, result) => { From 876b58ed0c053d7eb11da5bf7d2f855b07a14d65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Sep 2020 10:30:26 -0700 Subject: [PATCH 1266/1899] Increase received metadata size limits in the test --- test/api/interop_extra_test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 996fadfd4..c7411c178 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -76,13 +76,15 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio const options = { 'grpc.ssl_target_name_override': 'foo.test.google.fr', 'grpc.default_authority': 'foo.test.google.fr', - 'grpc.max_send_message_length': 4*1024*1024 + 'grpc.max_send_message_length': 4*1024*1024, + 'grpc.max_metadata_size': 4*1024*1024 }; client = new testProto.TestService(`localhost:${port}`, creds, options); done(); } }, { - 'grpc.max_receive_message_length': -1 + 'grpc.max_receive_message_length': -1, + 'grpc.max_metadata_size': 4*1024*1024 }); }); after(function() { From 8162efdf54929b427439f41b7da923643b77982e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Sep 2020 15:48:03 -0700 Subject: [PATCH 1267/1899] grpc-js: Install dependencies in xds script --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 126660695..a3f10da3a 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -30,7 +30,7 @@ set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION cd $base -npm run compile +npm install cd ../../.. From 4d44dc11e2a9f5a2cd2dbd7eee9767e50cdd2aec Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 15 Sep 2020 10:41:52 -0700 Subject: [PATCH 1268/1899] grpc-js: Double the xds test job timeout --- test/kokoro/xds-interop.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 81a038736..7aae7d96c 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" -timeout_mins: 60 +timeout_mins: 120 action { define_artifacts { regex: "github/grpc/reports/**" From c0f31a8a028009a62089b86728f775ea9fdcf890 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 15 Sep 2020 14:52:00 -0700 Subject: [PATCH 1269/1899] grpc-js: Source nvm.sh in profile files in xds script to get nvm in subprocesses --- packages/grpc-js/scripts/xds.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index a3f10da3a..1c815fda7 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -29,6 +29,11 @@ nvm install 12 set -exu -o pipefail [[ -f /VERSION ]] && cat /VERSION +# Make nvm available to the subprocess that the python script spawns +echo "source $NVM_DIR/nvm.sh" > ~/.profile +echo "source $NVM_DIR/nvm.sh" > ~/.shrc +export ENV=~/.shrc + cd $base npm install From 2791dbbb2399af32080f942b38411c182473ab2b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Sep 2020 11:25:56 -0700 Subject: [PATCH 1270/1899] grpc-js: Add a timer that holds the event loop open while there are pending calls --- packages/grpc-js/src/channel.ts | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 3195ebc2f..5edaf370d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -137,6 +137,14 @@ export class ChannelImplementation implements Channel { private defaultAuthority: string; private filterStackFactory: FilterStackFactory; private target: GrpcUri; + /** + * This timer does not do anything on its own. Its purpose is to hold the + * event loop open while there are any pending calls for the channel that + * have not yet been assigned to specific subchannels. In other words, + * the invariant is that callRefTimer is reffed if and only if pickQueue + * is non-empty. + */ + private callRefTimer: NodeJS.Timer; constructor( target: string, private readonly credentials: ChannelCredentials, @@ -206,6 +214,7 @@ export class ChannelImplementation implements Channel { updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.currentPicker = picker; const queueCopy = this.pickQueue.slice(); + this.callRefTimer.unref?.(); this.pickQueue = []; for (const { callStream, callMetadata } of queueCopy) { this.tryPick(callStream, callMetadata); @@ -230,6 +239,14 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); + + this.callRefTimer = setInterval(() => {}, 1 << 31 - 1); + this.callRefTimer.unref?.(); + } + + private pushPick(callStream: Http2CallStream, callMetadata: Metadata) { + this.callRefTimer.ref?.(); + this.pickQueue.push({ callStream, callMetadata }); } /** @@ -276,7 +293,7 @@ export class ChannelImplementation implements Channel { ' has state ' + ConnectivityState[pickResult.subchannel!.getConnectivityState()] ); - this.pickQueue.push({ callStream, callMetadata }); + this.pushPick(callStream, callMetadata); break; } /* We need to clone the callMetadata here because the transparent @@ -367,11 +384,11 @@ export class ChannelImplementation implements Channel { } break; case PickResultType.QUEUE: - this.pickQueue.push({ callStream, callMetadata }); + this.pushPick(callStream, callMetadata); break; case PickResultType.TRANSIENT_FAILURE: if (callMetadata.getOptions().waitForReady) { - this.pickQueue.push({ callStream, callMetadata }); + this.pushPick(callStream, callMetadata); } else { callStream.cancelWithStatus( pickResult.status!.code, @@ -433,6 +450,7 @@ export class ChannelImplementation implements Channel { close() { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); + clearInterval(this.callRefTimer); this.subchannelPool.unrefUnusedSubchannels(); } From 6a32c00ed2cce4179bef5a6df100b879e1f82cca Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Sep 2020 12:15:47 -0700 Subject: [PATCH 1271/1899] Bump grpc-js to 1.1.7 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a8428b249..ec3f4a972 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.6", + "version": "1.1.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From a1600812d19cf96e501356cf6e97bd237577a204 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Sep 2020 13:18:11 -0700 Subject: [PATCH 1272/1899] Move timer initialization to the beginning of channel construction --- packages/grpc-js/src/channel.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 5edaf370d..dcfae483d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -48,6 +48,11 @@ export enum ConnectivityState { SHUTDOWN, } +/** + * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args + */ +const MAX_TIMEOUT_TIME = 2147483647; + let nextCallNumber = 0; function getNewCallNumber(): number { @@ -185,6 +190,10 @@ export class ChannelImplementation implements Channel { `Could not find a default scheme for target name "${target}"` ); } + + this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME); + this.callRefTimer.unref?.(); + if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { @@ -239,9 +248,6 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); - - this.callRefTimer = setInterval(() => {}, 1 << 31 - 1); - this.callRefTimer.unref?.(); } private pushPick(callStream: Http2CallStream, callMetadata: Metadata) { From a45d8da2046f686e2a4b8d7aedd3df2525d3495a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 11:12:38 -0700 Subject: [PATCH 1273/1899] Add debugging output to xds scripts --- packages/grpc-js/interop/xds-interop-client.ts | 3 +++ packages/grpc-js/scripts/xds.sh | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index 3009541c4..daaf47613 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -15,6 +15,9 @@ * */ +console.log(`Running xDS interop client on node ${process.version} from ${process.argv[0]}`); +console.log(`PATH: ${process.env.PATH}`); + import * as grpc from '../src'; import { ProtoGrpcType } from './generated/test'; diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index 1c815fda7..f6c187709 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -34,6 +34,10 @@ echo "source $NVM_DIR/nvm.sh" > ~/.profile echo "source $NVM_DIR/nvm.sh" > ~/.shrc export ENV=~/.shrc +echo $PATH +which node +node -v + cd $base npm install @@ -43,7 +47,9 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver GRPC_NODE_VERBOSITY=DEBUG \ +GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver + GRPC_NODE_VERBOSITY=DEBUG \ + NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="backends_restart,change_backend_service,gentle_failover,ping_pong,remove_instance_group,round_robin,secondary_locality_gets_no_requests_on_partial_primary_failure,secondary_locality_gets_requests_on_primary_failure" \ --project_id=grpc-testing \ From 6e0f6e2f8a41ab30c78822d389634d3cac20369d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 11:13:19 -0700 Subject: [PATCH 1274/1899] Borrow linux kokoro job for xds tests (revert before merging) --- test/kokoro/linux.cfg | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..04fa73334 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,11 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } + From c259edd7f89a2c01b6e09c6dd6d3e3b9fb375346 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 13:33:37 -0700 Subject: [PATCH 1275/1899] Patch xds python script with debug logging --- 0001-Add-PATH-logging.patch | 32 ++++++++++++++++++++++++++++++++ packages/grpc-js/scripts/xds.sh | 4 ++++ 2 files changed, 36 insertions(+) create mode 100644 0001-Add-PATH-logging.patch diff --git a/0001-Add-PATH-logging.patch b/0001-Add-PATH-logging.patch new file mode 100644 index 000000000..29c410a26 --- /dev/null +++ b/0001-Add-PATH-logging.patch @@ -0,0 +1,32 @@ +From 0761cc8780a5f94c10f187dbcd8d8e70c7b52577 Mon Sep 17 00:00:00 2001 +From: Michael Lumish +Date: Mon, 21 Sep 2020 13:28:08 -0700 +Subject: [PATCH] Add PATH logging + +--- + tools/run_tests/run_xds_tests.py | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tools/run_tests/run_xds_tests.py b/tools/run_tests/run_xds_tests.py +index 0cfa59e..df5a3f9 100755 +--- a/tools/run_tests/run_xds_tests.py ++++ b/tools/run_tests/run_xds_tests.py +@@ -1730,6 +1730,7 @@ try: + wait_for_healthy_backends(gcp, backend_service, instance_group) + + if args.test_case: ++ logger.debug('PATH: %s', os.environ['PATH']) + client_env = dict(os.environ) + bootstrap_server_features = [] + if gcp.service_port == _DEFAULT_SERVICE_PORT: +@@ -1800,6 +1801,7 @@ try: + rpcs_to_send=rpcs_to_send, + metadata_to_send=metadata_to_send) + logger.debug('running client: %s', client_cmd_formatted) ++ logger.debug('Using PATH: %s', client_env['PATH']) + client_cmd = shlex.split(client_cmd_formatted) + try: + client_process = subprocess.Popen(client_cmd, +-- +2.7.4 + diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index f6c187709..ad4744ec7 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -45,6 +45,10 @@ cd ../../.. git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git +cd grpc +git apply ../grpc-node/0001-Add-PATH-logging.patch +cd .. + grpc/tools/run_tests/helper_scripts/prep_xds.sh GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver From 2574952e06cc57fa033eefe1be1e868861e309b2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 14:15:21 -0700 Subject: [PATCH 1276/1899] Use full node path in client_cmd --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ad4744ec7..ae2362d67 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -61,7 +61,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ - --client_cmd="node grpc-node/packages/grpc-js/build/interop/xds-interop-client \ + --client_cmd="$(which node) grpc-node/packages/grpc-js/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ From ab5878e737f85d852aece8b92200e99929a43b8c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Sep 2020 16:32:46 -0700 Subject: [PATCH 1277/1899] Increase timeout for borrowed test --- test/kokoro/linux.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 04fa73334..e23febc67 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" -timeout_mins: 120 +timeout_mins: 360 action { define_artifacts { regex: "github/grpc/reports/**" From 474a496a7a9695f3ad8fd4a9cc6e106bcb2e7be9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 00:47:55 -0700 Subject: [PATCH 1278/1899] Update submodules in xds test script --- packages/grpc-js/scripts/xds.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ae2362d67..c15db9fca 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -39,6 +39,7 @@ which node node -v cd $base +git submodule update --init --recursive npm install cd ../../.. From fbdfcd4ee963ec3cb5a5aeea835c36278f119622 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 10:56:11 -0700 Subject: [PATCH 1279/1899] Fix tracer setting lines in xds script --- packages/grpc-js/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index c15db9fca..ea472bc1b 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -52,7 +52,7 @@ cd .. grpc/tools/run_tests/helper_scripts/prep_xds.sh -GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver +GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ From 0713b28da51de27311fbd204afff0c02d50d9b16 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 12:09:13 -0700 Subject: [PATCH 1280/1899] Revert testing changes --- 0001-Add-PATH-logging.patch | 32 ------------------- .../grpc-js/interop/xds-interop-client.ts | 3 -- packages/grpc-js/scripts/xds.sh | 8 ----- test/kokoro/linux.cfg | 7 ++-- 4 files changed, 3 insertions(+), 47 deletions(-) delete mode 100644 0001-Add-PATH-logging.patch diff --git a/0001-Add-PATH-logging.patch b/0001-Add-PATH-logging.patch deleted file mode 100644 index 29c410a26..000000000 --- a/0001-Add-PATH-logging.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 0761cc8780a5f94c10f187dbcd8d8e70c7b52577 Mon Sep 17 00:00:00 2001 -From: Michael Lumish -Date: Mon, 21 Sep 2020 13:28:08 -0700 -Subject: [PATCH] Add PATH logging - ---- - tools/run_tests/run_xds_tests.py | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/tools/run_tests/run_xds_tests.py b/tools/run_tests/run_xds_tests.py -index 0cfa59e..df5a3f9 100755 ---- a/tools/run_tests/run_xds_tests.py -+++ b/tools/run_tests/run_xds_tests.py -@@ -1730,6 +1730,7 @@ try: - wait_for_healthy_backends(gcp, backend_service, instance_group) - - if args.test_case: -+ logger.debug('PATH: %s', os.environ['PATH']) - client_env = dict(os.environ) - bootstrap_server_features = [] - if gcp.service_port == _DEFAULT_SERVICE_PORT: -@@ -1800,6 +1801,7 @@ try: - rpcs_to_send=rpcs_to_send, - metadata_to_send=metadata_to_send) - logger.debug('running client: %s', client_cmd_formatted) -+ logger.debug('Using PATH: %s', client_env['PATH']) - client_cmd = shlex.split(client_cmd_formatted) - try: - client_process = subprocess.Popen(client_cmd, --- -2.7.4 - diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js/interop/xds-interop-client.ts index daaf47613..3009541c4 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js/interop/xds-interop-client.ts @@ -15,9 +15,6 @@ * */ -console.log(`Running xDS interop client on node ${process.version} from ${process.argv[0]}`); -console.log(`PATH: ${process.env.PATH}`); - import * as grpc from '../src'; import { ProtoGrpcType } from './generated/test'; diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js/scripts/xds.sh index ea472bc1b..ce2b64179 100755 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js/scripts/xds.sh @@ -34,10 +34,6 @@ echo "source $NVM_DIR/nvm.sh" > ~/.profile echo "source $NVM_DIR/nvm.sh" > ~/.shrc export ENV=~/.shrc -echo $PATH -which node -node -v - cd $base git submodule update --init --recursive npm install @@ -46,10 +42,6 @@ cd ../../.. git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git -cd grpc -git apply ../grpc-node/0001-Add-PATH-logging.patch -cd .. - grpc/tools/run_tests/helper_scripts/prep_xds.sh GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index e23febc67..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,11 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" -timeout_mins: 360 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } - From 980e30c671144181ecf948e80641d043763d9c60 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 22 Sep 2020 16:05:43 -0700 Subject: [PATCH 1281/1899] Fix the max message size tests by making the requests with different clients --- test/api/interop_extra_test.js | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 67130e033..934f3514c 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -257,6 +257,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio describe('with a server with message size limits and a client without limits', function() { let restrictedServer; let restrictedServerClient; + let restrictedServerClient2; before(function(done) { interopServer.getServer(0, true, (err, serverObj) => { if (err) { @@ -273,6 +274,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio 'grpc.max_receive_message_length': -1 }; restrictedServerClient = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); + restrictedServerClient2 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 1}); done(); } }, {'grpc.max_send_message_length': 4 * 1024 * 1024}); @@ -284,7 +286,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio restrictedServerClient.unaryCall({payload: {body: largeMessage}}, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - const stream = restrictedServerClient.fullDuplexCall(); + const stream = restrictedServerClient2.fullDuplexCall(); stream.write({payload: {body: largeMessage}}); stream.end(); stream.on('data', () => {}); @@ -297,21 +299,19 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); it('should get an error when requesting a large message', function(done) { - done = multiDone(done, 2); restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - done(); - }); - const stream = restrictedServerClient.fullDuplexCall(); - stream.write({response_parameters: [{size: largeMessageSize}]}); - stream.end(); - stream.on('data', () => {}); - stream.on('status', (status) => { - assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); - done(); - }); - stream.on('error', (error) => { + const stream = restrictedServerClient2.fullDuplexCall(); + stream.write({response_parameters: [{size: largeMessageSize}]}); + stream.end(); + stream.on('data', () => {}); + stream.on('status', (status) => { + assert.strictEqual(status.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + stream.on('error', (error) => { + }); }); }); }); From 1a5f25de619d444e1963d938133ca8a5d613c654 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 23 Sep 2020 11:56:41 -0700 Subject: [PATCH 1282/1899] Use 4 clients for 4 requests, to avoid weird core client behavior --- test/api/interop_extra_test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 934f3514c..99f91e21a 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -258,6 +258,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio let restrictedServer; let restrictedServerClient; let restrictedServerClient2; + let restrictedServerClient3; + let restrictedServerClient4; before(function(done) { interopServer.getServer(0, true, (err, serverObj) => { if (err) { @@ -275,6 +277,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }; restrictedServerClient = new testProto.TestService(`localhost:${serverObj.port}`, creds, options); restrictedServerClient2 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 1}); + restrictedServerClient3 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 2}); + restrictedServerClient4 = new testProto.TestService(`localhost:${serverObj.port}`, creds, {...options, unique: 3}); done(); } }, {'grpc.max_send_message_length': 4 * 1024 * 1024}); @@ -299,10 +303,10 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); it('should get an error when requesting a large message', function(done) { - restrictedServerClient.unaryCall({response_size: largeMessageSize}, (error, result) => { + restrictedServerClient3.unaryCall({response_size: largeMessageSize}, (error, result) => { assert(error); assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); - const stream = restrictedServerClient2.fullDuplexCall(); + const stream = restrictedServerClient4.fullDuplexCall(); stream.write({response_parameters: [{size: largeMessageSize}]}); stream.end(); stream.on('data', () => {}); From f3d14bd2b39bd50c88cc3f123ed6fec8edeb8d46 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Thu, 24 Sep 2020 08:19:33 +0100 Subject: [PATCH 1283/1899] grpc-js: export handleClientStreamingCall type --- packages/grpc-js/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index f79a369bd..89e604e37 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -57,6 +57,7 @@ import { StatusBuilder } from './status-builder'; import { handleBidiStreamingCall, handleServerStreamingCall, + handleClientStreamingCall, handleUnaryCall, sendUnaryData, ServerUnaryCall, @@ -186,7 +187,7 @@ export { /**** Server ****/ -export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall }; +export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall, handleClientStreamingCall }; /* eslint-disable @typescript-eslint/no-explicit-any */ export type Call = From acf403b7042b6c9a0097b2a065cfd681f0b90cac Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Thu, 24 Sep 2020 09:40:48 +0100 Subject: [PATCH 1284/1899] proto-loader: use method descriptor types to define server handlers --- packages/proto-loader/bin/proto-loader-gen-types.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 1238e0402..3c972fbcf 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -520,18 +520,18 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: if (method.requestStream) { if (method.responseStream) { // Bidi streaming - formatter.writeLine(`${methodName}(call: grpc.ServerDuplexStream<${requestType}, ${responseType}>): void;`); + formatter.writeLine(`${methodName}: grpc.handleBidiStreamingCall<${requestType}, ${responseType}>;`); } else { // Client streaming - formatter.writeLine(`${methodName}(call: grpc.ServerReadableStream<${requestType}, ${responseType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); + formatter.writeLine(`${methodName}: grpc.handleClientStreamingCall<${requestType}, ${responseType}>;`); } } else { if (method.responseStream) { // Server streaming - formatter.writeLine(`${methodName}(call: grpc.ServerWritableStream<${requestType}, ${responseType}>): void;`); + formatter.writeLine(`${methodName}: grpc.handleServerStreamingCall<${requestType}, ${responseType}>;`); } else { // Unary - formatter.writeLine(`${methodName}(call: grpc.ServerUnaryCall<${requestType}, ${responseType}>, callback: grpc.sendUnaryData<${responseType}>): void;`); + formatter.writeLine(`${methodName}: grpc.handleUnaryCall<${requestType}, ${responseType}>;`); } } formatter.writeLine(''); From 829333c4598c0d9d9583be60cae89fbae1bfe2ed Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Thu, 24 Sep 2020 18:22:52 +0100 Subject: [PATCH 1285/1899] Regenerate golden types --- .../google/longrunning/Operations.ts | 10 +++++----- .../google/showcase/v1beta1/Echo.ts | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 1d1d2b070..57ff8722c 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -185,7 +185,7 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - CancelOperation(call: grpc.ServerUnaryCall<_google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty>, callback: grpc.sendUnaryData<_google_protobuf_Empty>): void; + CancelOperation: grpc.handleUnaryCall<_google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty>; /** * Deletes a long-running operation. This method indicates that the client is @@ -193,14 +193,14 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - DeleteOperation(call: grpc.ServerUnaryCall<_google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty>, callback: grpc.sendUnaryData<_google_protobuf_Empty>): void; + DeleteOperation: grpc.handleUnaryCall<_google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty>; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - GetOperation(call: grpc.ServerUnaryCall<_google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation>, callback: grpc.sendUnaryData<_google_longrunning_Operation>): void; + GetOperation: grpc.handleUnaryCall<_google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation>; /** * Lists operations that match the specified filter in the request. If the @@ -214,7 +214,7 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - ListOperations(call: grpc.ServerUnaryCall<_google_longrunning_ListOperationsRequest__Output, _google_longrunning_ListOperationsResponse>, callback: grpc.sendUnaryData<_google_longrunning_ListOperationsResponse>): void; + ListOperations: grpc.handleUnaryCall<_google_longrunning_ListOperationsRequest__Output, _google_longrunning_ListOperationsResponse>; /** * Waits for the specified long-running operation until it is done or reaches @@ -227,6 +227,6 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - WaitOperation(call: grpc.ServerUnaryCall<_google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation>, callback: grpc.sendUnaryData<_google_longrunning_Operation>): void; + WaitOperation: grpc.handleUnaryCall<_google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation>; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index eb4772a1d..124ee86e5 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -149,43 +149,43 @@ export interface EchoHandlers extends grpc.UntypedServiceImplementation { * and then return the response or error. * This method showcases how a client handles delays or retries. */ - Block(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_BlockResponse>): void; + Block: grpc.handleUnaryCall<_google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse>; /** * This method, upon receiving a request on the stream, the same content will * be passed back on the stream. This method showcases bidirectional * streaming rpcs. */ - Chat(call: grpc.ServerDuplexStream<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>): void; + Chat: grpc.handleBidiStreamingCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect(call: grpc.ServerReadableStream<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse>): void; + Collect: grpc.handleClientStreamingCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>; /** * This method simply echos the request. This method is showcases unary rpcs. */ - Echo(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_EchoResponse>): void; + Echo: grpc.handleUnaryCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>; /** * This method split the given content into words and will pass each word back * through the stream. This method showcases server-side streaming rpcs. */ - Expand(call: grpc.ServerWritableStream<_google_showcase_v1beta1_ExpandRequest__Output, _google_showcase_v1beta1_EchoResponse>): void; + Expand: grpc.handleServerStreamingCall<_google_showcase_v1beta1_ExpandRequest__Output, _google_showcase_v1beta1_EchoResponse>; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - PagedExpand(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_PagedExpandRequest__Output, _google_showcase_v1beta1_PagedExpandResponse>, callback: grpc.sendUnaryData<_google_showcase_v1beta1_PagedExpandResponse>): void; + PagedExpand: grpc.handleUnaryCall<_google_showcase_v1beta1_PagedExpandRequest__Output, _google_showcase_v1beta1_PagedExpandResponse>; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - Wait(call: grpc.ServerUnaryCall<_google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation>, callback: grpc.sendUnaryData<_google_longrunning_Operation>): void; + Wait: grpc.handleUnaryCall<_google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation>; } From dcf47460da01f50a752facbf092949f2031bd3f6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 24 Sep 2020 14:01:15 -0700 Subject: [PATCH 1286/1899] grpc-js: xDS: Do not remove watchers in onResourceDoesNotExist --- packages/grpc-js/src/load-balancer-cds.ts | 4 ---- packages/grpc-js/src/load-balancer-eds.ts | 4 ---- 2 files changed, 8 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 01cc4c62f..71a72c897 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -86,10 +86,6 @@ export class CdsLoadBalancer implements LoadBalancer { ); }, onResourceDoesNotExist: () => { - this.xdsClient?.removeClusterWatcher( - this.latestConfig!.cds.cluster, - this.watcher - ); this.isWatcherActive = false; this.channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'CDS resource does not exist', metadata: new Metadata()})); this.childBalancer.destroy(); diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index ccc56e9f8..902b28b50 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -140,10 +140,6 @@ export class EdsLoadBalancer implements LoadBalancer { this.updateChild(); }, onResourceDoesNotExist: () => { - this.xdsClient?.removeEndpointWatcher( - this.edsServiceName!, - this.watcher - ); this.isWatcherActive = false; this.channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'EDS resource does not exist', metadata: new Metadata()})); this.childBalancer.destroy(); From 73d3c307c934b743f44fbd43d32737733f7db8b1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Oct 2020 11:27:18 -0700 Subject: [PATCH 1287/1899] grpc-js: xds: Add more logging around adding and removing eds and cds watchers --- packages/grpc-js/src/load-balancer-cds.ts | 7 +++++-- packages/grpc-js/src/load-balancer-eds.ts | 5 ++++- packages/grpc-js/src/xds-client.ts | 3 ++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js/src/load-balancer-cds.ts index 71a72c897..15c55ed84 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js/src/load-balancer-cds.ts @@ -111,14 +111,14 @@ export class CdsLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { if (!isCdsLoadBalancingConfig(lbConfig)) { - trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig, undefined, 2)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { trace('Discarding address list update missing xdsClient attribute'); return; } - trace('Received update with config ' + JSON.stringify(lbConfig)); + trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2)); this.xdsClient = attributes.xdsClient; this.latestAttributes = attributes; @@ -128,6 +128,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.isWatcherActive && this.latestConfig?.cds.cluster !== lbConfig.cds.cluster ) { + trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.cds.cluster); this.xdsClient.removeClusterWatcher( this.latestConfig!.cds.cluster, this.watcher @@ -143,6 +144,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.latestConfig = lbConfig; if (!this.isWatcherActive) { + trace('Adding new cluster watcher for cluster name ' + lbConfig.cds.cluster); this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); this.isWatcherActive = true; } @@ -154,6 +156,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { + trace('Destroying load balancer with cluster name ' + this.latestConfig?.cds.cluster); this.childBalancer.destroy(); if (this.isWatcherActive) { this.xdsClient?.removeClusterWatcher( diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js/src/load-balancer-eds.ts index 902b28b50..9080a2f43 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js/src/load-balancer-eds.ts @@ -401,7 +401,7 @@ export class EdsLoadBalancer implements LoadBalancer { trace('Discarding address list update missing xdsClient attribute'); return; } - trace('Received update with config: ' + JSON.stringify(lbConfig)); + trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; @@ -411,6 +411,7 @@ export class EdsLoadBalancer implements LoadBalancer { /* If the name is changing, disable the old watcher before adding the new * one */ if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { + trace('Removing old endpoint watcher for edsServiceName ' + this.edsServiceName) this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); /* Setting isWatcherActive to false here lets us have one code path for * calling addEndpointWatcher */ @@ -423,6 +424,7 @@ export class EdsLoadBalancer implements LoadBalancer { this.edsServiceName = newEdsServiceName; if (!this.isWatcherActive) { + trace('Adding new endpoint watcher for edsServiceName ' + this.edsServiceName); this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); this.isWatcherActive = true; } @@ -447,6 +449,7 @@ export class EdsLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { + trace('Destroying load balancer with edsServiceName ' + this.edsServiceName); if (this.edsServiceName) { this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); } diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js/src/xds-client.ts index 8ca4cfa27..8b4d5d3ba 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js/src/xds-client.ts @@ -261,7 +261,6 @@ class EdsState implements XdsStreamState { edsServiceName: string, watcher: Watcher ): void { - trace('Adding EDS watcher for edsServiceName ' + edsServiceName); let watchersEntry = this.watchers.get(edsServiceName); let addedServiceName = false; if (watchersEntry === undefined) { @@ -269,6 +268,7 @@ class EdsState implements XdsStreamState { watchersEntry = []; this.watchers.set(edsServiceName, watchersEntry); } + trace('Adding EDS watcher (' + watchersEntry.length + ' ->' + (watchersEntry.length + 1) + ') for edsServiceName ' + edsServiceName); watchersEntry.push(watcher); /* If we have already received an update for the requested edsServiceName, @@ -298,6 +298,7 @@ class EdsState implements XdsStreamState { if (watchersEntry !== undefined) { const entryIndex = watchersEntry.indexOf(watcher); if (entryIndex >= 0) { + trace('Removed EDS watcher (' + watchersEntry.length + ' -> ' + (watchersEntry.length - 1) + ') for edsServiceName ' + edsServiceName); watchersEntry.splice(entryIndex, 1); } if (watchersEntry.length === 0) { From 89a030c00a3d4f26ebafe9db4ceff1a064f64cd0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Oct 2020 14:58:55 -0700 Subject: [PATCH 1288/1899] tests: Update google-auth-library dependency from 0.9 to 6.1 --- test/interop/interop_client.js | 64 ++++++++++------------------------ test/package.json | 2 +- 2 files changed, 19 insertions(+), 47 deletions(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 1c2ec8f3e..0b177e539 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -22,7 +22,8 @@ var fs = require('fs'); var path = require('path'); var grpc = require('../any_grpc').client; var protoLoader = require('../../packages/proto-loader'); -var GoogleAuth = require('google-auth-library'); + +const { GoogleAuth } = require('google-auth-library'); var protoPackage = protoLoader.loadSync( 'src/proto/grpc/testing/test.proto', @@ -463,60 +464,31 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { + const creds = grpc.credentials.createFromGoogleCredential(new GoogleAuth({scopes: extra.oauth_scope})); + client.unaryCall(arg, {credentials: creds}, function(err, resp) { assert.ifError(err); - var arg = { - fill_username: true, - fill_oauth_scope: true - }; - var scope = extra.oauth_scope; - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); + assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); + assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); + if (done) { + done(); } - var creds = grpc.credentials.createFromGoogleCredential(credential); - client.unaryCall(arg, {credentials: creds}, function(err, resp) { - assert.ifError(err); - assert.strictEqual(resp.username, SERVICE_ACCOUNT_EMAIL); - assert(extra.oauth_scope.indexOf(resp.oauth_scope) > -1); - if (done) { - done(); - } - }); }); } function getApplicationCreds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - if (credential.createScopedRequired() && scope) { - credential = credential.createScoped(scope); - } - callback(null, grpc.credentials.createFromGoogleCredential(credential)); - }); + callback(null, grpc.credentials.createFromGoogleCredential(new GoogleAuth({scopes: scope}))); } function getOauth2Creds(scope, callback) { - (new GoogleAuth()).getApplicationDefault(function(err, credential) { - if (err) { - callback(err); - return; - } - credential = credential.createScoped(scope); - credential.getAccessToken(function(err, token) { - if (err) { - callback(err); - return; - } - var updateMd = function(service_url, callback) { - var metadata = new grpc.Metadata(); - metadata.add('authorization', 'Bearer ' + token); - callback(null, metadata); - }; - callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); - }); + (new GoogleAuth()).getAccessToken().then((token) => { + var updateMd = function(service_url, callback) { + var metadata = new grpc.Metadata(); + metadata.add('authorization', 'Bearer ' + token); + callback(null, metadata); + }; + callback(null, grpc.credentials.createFromMetadataGenerator(updateMd)); + }, (error) => { + callback(error); }); } diff --git a/test/package.json b/test/package.json index 2867bc77e..4f42f7bf7 100644 --- a/test/package.json +++ b/test/package.json @@ -15,7 +15,7 @@ ], "dependencies": { "express": "^4.16.3", - "google-auth-library": "^0.9.2", + "google-auth-library": "^6.1.0", "grpc": "^1.24.2", "lodash": "^4.17.4", "poisson-process": "^1.0.0" From 330d1835fee7718434c42a528cbf4572693bf828 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Sun, 11 Oct 2020 12:01:32 +0100 Subject: [PATCH 1289/1899] proto-loader: fix typescript generation callType for client streaming --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 3c972fbcf..4c97a8d01 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -476,7 +476,7 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P formatter.writeLine(`${name}(options?: grpc.CallOptions): ${callType};`); } else { // Client streaming - const callType = `grpc.ClientWritableStream<${responseType}>`; + const callType = `grpc.ClientWritableStream<${requestType}>`; formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); formatter.writeLine(`${name}(options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); From e85b72bbc45c5f0d4e8087fa9d2b7c397b3913ae Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Sun, 11 Oct 2020 12:10:52 +0100 Subject: [PATCH 1290/1899] Regenerate golden types --- .../google/showcase/v1beta1/Echo.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index 124ee86e5..17df522c8 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -58,19 +58,19 @@ export interface EchoClient extends grpc.Client { * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - Collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - Collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; - collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoResponse__Output>; + collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; /** * This method simply echos the request. This method is showcases unary rpcs. From bbd7617ba746579a98792df5951b4a8237a62b8d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Oct 2020 10:23:03 -0700 Subject: [PATCH 1291/1899] Move grpc-js xDS features into a separate package --- packages/grpc-js-xds/.eslintrc.json | 3 +++ packages/grpc-js-xds/.prettierrc.js | 3 +++ packages/grpc-js-xds/package.json | 41 +++++++++++++++++++++++++++++ packages/grpc-js-xds/src/index.ts | 24 +++++++++++++++++ packages/grpc-js-xds/tsconfig.json | 11 ++++++++ packages/grpc-js/package.json | 2 -- 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 packages/grpc-js-xds/.eslintrc.json create mode 100644 packages/grpc-js-xds/.prettierrc.js create mode 100644 packages/grpc-js-xds/package.json create mode 100644 packages/grpc-js-xds/src/index.ts create mode 100644 packages/grpc-js-xds/tsconfig.json diff --git a/packages/grpc-js-xds/.eslintrc.json b/packages/grpc-js-xds/.eslintrc.json new file mode 100644 index 000000000..f95bb333f --- /dev/null +++ b/packages/grpc-js-xds/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "./node_modules/gts/" +} diff --git a/packages/grpc-js-xds/.prettierrc.js b/packages/grpc-js-xds/.prettierrc.js new file mode 100644 index 000000000..c634ea729 --- /dev/null +++ b/packages/grpc-js-xds/.prettierrc.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('gts/.prettierrc.json') +} \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json new file mode 100644 index 000000000..f8d44cb09 --- /dev/null +++ b/packages/grpc-js-xds/package.json @@ -0,0 +1,41 @@ +{ + "name": "@grpc/grpc-js-xds", + "version": "1.0.0", + "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", + "main": "build/src/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "check": "gts check", + "clean": "gts clean", + "compile": "tsc", + "fix": "gts fix", + "prepare": "npm run compile", + "pretest": "npm run compile", + "posttest": "npm run check" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/grpc/grpc-node.git" + }, + "keywords": [ + "grpc" + ], + "author": { + "name": "Google Inc." + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/grpc/grpc-node/issues" + }, + "homepage": "https://github.com/grpc/grpc-node#readme", + "devDependencies": { + "gts": "^2.0.2", + "typescript": "^3.8.3", + "@types/node": "^13.11.1", + "yargs": "^15.4.1" + }, + "dependencies": { + "@grpc/proto-loader": "^0.6.0-pre14", + "google-auth-library": "^6.1.1" + } +} diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts new file mode 100644 index 000000000..2c1da1263 --- /dev/null +++ b/packages/grpc-js-xds/src/index.ts @@ -0,0 +1,24 @@ +console.log('Try npm run check/fix!'); + +const longString = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.'; + +const trailing = 'Semicolon'; + +const why = 'am I tabbed?'; + +export function doSomeStuff( + withThis: string, + andThat: string, + andThose: string[] +) { + //function on one line + if (!andThose.length) { + return false; + } + console.log(withThis); + console.log(andThat); + console.dir(andThose); + return; +} +// TODO: more examples diff --git a/packages/grpc-js-xds/tsconfig.json b/packages/grpc-js-xds/tsconfig.json new file mode 100644 index 000000000..d1646f011 --- /dev/null +++ b/packages/grpc-js-xds/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "./node_modules/gts/tsconfig-google.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "build" + }, + "include": [ + "src/**/*.ts", + "test/**/*.ts" + ] +} diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index b28043814..45c4cad4b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -58,9 +58,7 @@ "posttest": "npm run check" }, "dependencies": { - "@grpc/proto-loader": "^0.6.0-pre14", "@types/node": "^12.12.47", - "google-auth-library": "^5.10.1", "semver": "^6.2.0" }, "files": [ From 4368ed37b8ae4e1ac1226439b1ca32453f430eec Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Oct 2020 10:40:32 -0700 Subject: [PATCH 1292/1899] Fix missing arg variable in perRpcCreds interop test --- test/interop/interop_client.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index 0b177e539..d7df128da 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -464,6 +464,10 @@ function oauth2Test(client, done, extra) { } function perRpcAuthTest(client, done, extra) { + var arg = { + fill_username: true, + fill_oauth_scope: true + }; const creds = grpc.credentials.createFromGoogleCredential(new GoogleAuth({scopes: extra.oauth_scope})); client.unaryCall(arg, {credentials: creds}, function(err, resp) { assert.ifError(err); From 967eeb5443891fba1230438d85d649bc9219b66e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Oct 2020 11:04:11 -0700 Subject: [PATCH 1293/1899] grpc-js: Prevent prototype pollution in loadPackageDefinition --- packages/grpc-js/src/make-client.ts | 8 +++++- .../grpc-js/test/test-prototype-pollution.ts | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js/test/test-prototype-pollution.ts diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 02ef91af2..05f06b89f 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -122,6 +122,9 @@ export function makeClientConstructor( } Object.keys(methods).forEach((name) => { + if (name === '__proto__') { + return; + } const attrs = methods[name]; let methodType: keyof typeof requesterFuncs; // TODO(murgatroid99): Verify that we don't need this anymore @@ -152,7 +155,7 @@ export function makeClientConstructor( ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method Object.assign(ServiceClientImpl.prototype[name], attrs); - if (attrs.originalName) { + if (attrs.originalName && attrs.originalName !== '__proto__') { ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; } @@ -201,6 +204,9 @@ export function loadPackageDefinition( if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) { const service = packageDef[serviceFqn]; const nameComponents = serviceFqn.split('.'); + if (nameComponents.some(comp => comp === '__proto__')) { + continue; + } const serviceName = nameComponents[nameComponents.length - 1]; let current = result; for (const packageName of nameComponents.slice(0, -1)) { diff --git a/packages/grpc-js/test/test-prototype-pollution.ts b/packages/grpc-js/test/test-prototype-pollution.ts new file mode 100644 index 000000000..12092608c --- /dev/null +++ b/packages/grpc-js/test/test-prototype-pollution.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; + +import { loadPackageDefinition } from '../src'; + +describe('loadPackageDefinition', () => { + it('Should not allow prototype pollution', () => { + loadPackageDefinition({'__proto__.polluted': true} as any); + assert.notStrictEqual(({} as any).polluted, true); + }); +}); From a6a8639343ad79c6548cae0cc331834d7c4f44a5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Oct 2020 10:38:00 -0700 Subject: [PATCH 1294/1899] grpc-js: Separate xds code into a separate plugin package --- .gitmodules | 16 +- .../{grpc-js => grpc-js-xds}/deps/envoy-api | 0 .../{grpc-js => grpc-js-xds}/deps/googleapis | 0 .../deps/protoc-gen-validate | 0 packages/{grpc-js => grpc-js-xds}/deps/udpa | 0 .../generated/grpc/testing/BoolValue.ts | 0 .../generated/grpc/testing/EchoStatus.ts | 0 .../interop/generated/grpc/testing/Empty.ts | 0 .../generated/grpc/testing/GrpclbRouteType.ts | 0 .../grpc/testing/LoadBalancerStatsRequest.ts | 0 .../grpc/testing/LoadBalancerStatsResponse.ts | 0 .../grpc/testing/LoadBalancerStatsService.ts | 2 +- .../interop/generated/grpc/testing/Payload.ts | 0 .../generated/grpc/testing/PayloadType.ts | 0 .../generated/grpc/testing/ReconnectInfo.ts | 0 .../generated/grpc/testing/ReconnectParams.ts | 0 .../grpc/testing/ReconnectService.ts | 2 +- .../grpc/testing/ResponseParameters.ts | 0 .../generated/grpc/testing/SimpleRequest.ts | 0 .../generated/grpc/testing/SimpleResponse.ts | 0 .../grpc/testing/StreamingInputCallRequest.ts | 0 .../testing/StreamingInputCallResponse.ts | 0 .../testing/StreamingOutputCallRequest.ts | 0 .../testing/StreamingOutputCallResponse.ts | 0 .../generated/grpc/testing/TestService.ts | 2 +- .../grpc/testing/UnimplementedService.ts | 2 +- .../grpc/testing/XdsUpdateHealthService.ts | 2 +- .../interop/generated/test.ts | 2 +- .../interop/xds-interop-client.ts | 6 +- packages/grpc-js-xds/package.json | 9 +- .../proto/grpc/testing/empty.proto | 0 .../proto/grpc/testing/messages.proto | 0 .../proto/grpc/testing/test.proto | 0 .../{grpc-js => grpc-js-xds}/scripts/xds.sh | 4 + .../src/generated/ads.ts | 4 +- .../src/generated/cluster.ts | 4 +- .../src/generated/endpoint.ts | 4 +- .../src/generated/envoy/api/v2/Cluster.ts | 0 .../envoy/api/v2/ClusterLoadAssignment.ts | 0 .../envoy/api/v2/DeltaDiscoveryRequest.ts | 0 .../envoy/api/v2/DeltaDiscoveryResponse.ts | 0 .../envoy/api/v2/DiscoveryRequest.ts | 0 .../envoy/api/v2/DiscoveryResponse.ts | 0 .../src/generated/envoy/api/v2/Listener.ts | 0 .../envoy/api/v2/LoadBalancingPolicy.ts | 0 .../src/generated/envoy/api/v2/Resource.ts | 0 .../envoy/api/v2/RouteConfiguration.ts | 0 .../envoy/api/v2/ScopedRouteConfiguration.ts | 0 .../envoy/api/v2/UpstreamBindConfig.ts | 0 .../envoy/api/v2/UpstreamConnectionOptions.ts | 0 .../src/generated/envoy/api/v2/Vhds.ts | 0 .../v2/auth/CertificateValidationContext.ts | 0 .../envoy/api/v2/auth/CommonTlsContext.ts | 0 .../envoy/api/v2/auth/DownstreamTlsContext.ts | 0 .../envoy/api/v2/auth/GenericSecret.ts | 0 .../envoy/api/v2/auth/PrivateKeyProvider.ts | 0 .../envoy/api/v2/auth/SdsSecretConfig.ts | 0 .../src/generated/envoy/api/v2/auth/Secret.ts | 0 .../envoy/api/v2/auth/TlsCertificate.ts | 0 .../envoy/api/v2/auth/TlsParameters.ts | 0 .../envoy/api/v2/auth/TlsSessionTicketKeys.ts | 0 .../envoy/api/v2/auth/UpstreamTlsContext.ts | 0 .../envoy/api/v2/cluster/CircuitBreakers.ts | 0 .../generated/envoy/api/v2/cluster/Filter.ts | 0 .../envoy/api/v2/cluster/OutlierDetection.ts | 0 .../generated/envoy/api/v2/core/Address.ts | 0 .../api/v2/core/AggregatedConfigSource.ts | 0 .../envoy/api/v2/core/ApiConfigSource.ts | 0 .../generated/envoy/api/v2/core/ApiVersion.ts | 0 .../envoy/api/v2/core/AsyncDataSource.ts | 0 .../envoy/api/v2/core/BackoffStrategy.ts | 0 .../generated/envoy/api/v2/core/BindConfig.ts | 0 .../envoy/api/v2/core/BuildVersion.ts | 0 .../generated/envoy/api/v2/core/CidrRange.ts | 0 .../envoy/api/v2/core/ConfigSource.ts | 0 .../envoy/api/v2/core/ControlPlane.ts | 0 .../generated/envoy/api/v2/core/DataSource.ts | 0 .../envoy/api/v2/core/EventServiceConfig.ts | 0 .../generated/envoy/api/v2/core/Extension.ts | 0 .../envoy/api/v2/core/GrpcProtocolOptions.ts | 0 .../envoy/api/v2/core/GrpcService.ts | 0 .../generated/envoy/api/v2/core/HeaderMap.ts | 0 .../envoy/api/v2/core/HeaderValue.ts | 0 .../envoy/api/v2/core/HeaderValueOption.ts | 0 .../envoy/api/v2/core/HealthCheck.ts | 0 .../envoy/api/v2/core/HealthStatus.ts | 0 .../envoy/api/v2/core/Http1ProtocolOptions.ts | 0 .../envoy/api/v2/core/Http2ProtocolOptions.ts | 0 .../envoy/api/v2/core/HttpProtocolOptions.ts | 0 .../generated/envoy/api/v2/core/HttpUri.ts | 0 .../generated/envoy/api/v2/core/Locality.ts | 0 .../generated/envoy/api/v2/core/Metadata.ts | 0 .../src/generated/envoy/api/v2/core/Node.ts | 0 .../src/generated/envoy/api/v2/core/Pipe.ts | 0 .../envoy/api/v2/core/RateLimitSettings.ts | 0 .../envoy/api/v2/core/RemoteDataSource.ts | 0 .../envoy/api/v2/core/RequestMethod.ts | 0 .../envoy/api/v2/core/RetryPolicy.ts | 0 .../envoy/api/v2/core/RoutingPriority.ts | 0 .../envoy/api/v2/core/RuntimeDouble.ts | 0 .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 0 .../api/v2/core/RuntimeFractionalPercent.ts | 0 .../envoy/api/v2/core/RuntimeUInt32.ts | 0 .../envoy/api/v2/core/SelfConfigSource.ts | 0 .../envoy/api/v2/core/SocketAddress.ts | 0 .../envoy/api/v2/core/SocketOption.ts | 0 .../envoy/api/v2/core/TcpKeepalive.ts | 0 .../envoy/api/v2/core/TcpProtocolOptions.ts | 0 .../envoy/api/v2/core/TrafficDirection.ts | 0 .../envoy/api/v2/core/TransportSocket.ts | 0 .../v2/core/UpstreamHttpProtocolOptions.ts | 0 .../envoy/api/v2/endpoint/ClusterStats.ts | 0 .../envoy/api/v2/endpoint/Endpoint.ts | 0 .../v2/endpoint/EndpointLoadMetricStats.ts | 0 .../envoy/api/v2/endpoint/LbEndpoint.ts | 0 .../api/v2/endpoint/LocalityLbEndpoints.ts | 0 .../api/v2/endpoint/UpstreamEndpointStats.ts | 0 .../api/v2/endpoint/UpstreamLocalityStats.ts | 0 .../v2/listener/ActiveRawUdpListenerConfig.ts | 0 .../generated/envoy/api/v2/listener/Filter.ts | 0 .../envoy/api/v2/listener/FilterChain.ts | 0 .../envoy/api/v2/listener/FilterChainMatch.ts | 0 .../envoy/api/v2/listener/ListenerFilter.ts | 0 .../ListenerFilterChainMatchPredicate.ts | 0 .../api/v2/listener/UdpListenerConfig.ts | 0 .../envoy/api/v2/route/CorsPolicy.ts | 0 .../generated/envoy/api/v2/route/Decorator.ts | 0 .../api/v2/route/DirectResponseAction.ts | 0 .../envoy/api/v2/route/FilterAction.ts | 0 .../envoy/api/v2/route/HeaderMatcher.ts | 0 .../envoy/api/v2/route/HedgePolicy.ts | 0 .../api/v2/route/QueryParameterMatcher.ts | 0 .../generated/envoy/api/v2/route/RateLimit.ts | 0 .../envoy/api/v2/route/RedirectAction.ts | 0 .../envoy/api/v2/route/RetryPolicy.ts | 0 .../src/generated/envoy/api/v2/route/Route.ts | 0 .../envoy/api/v2/route/RouteAction.ts | 0 .../envoy/api/v2/route/RouteMatch.ts | 0 .../generated/envoy/api/v2/route/Tracing.ts | 0 .../envoy/api/v2/route/VirtualCluster.ts | 0 .../envoy/api/v2/route/VirtualHost.ts | 0 .../envoy/api/v2/route/WeightedCluster.ts | 0 .../config/filter/accesslog/v2/AccessLog.ts | 0 .../filter/accesslog/v2/AccessLogFilter.ts | 0 .../config/filter/accesslog/v2/AndFilter.ts | 0 .../filter/accesslog/v2/ComparisonFilter.ts | 0 .../filter/accesslog/v2/DurationFilter.ts | 0 .../filter/accesslog/v2/ExtensionFilter.ts | 0 .../filter/accesslog/v2/GrpcStatusFilter.ts | 0 .../filter/accesslog/v2/HeaderFilter.ts | 0 .../accesslog/v2/NotHealthCheckFilter.ts | 0 .../config/filter/accesslog/v2/OrFilter.ts | 0 .../filter/accesslog/v2/ResponseFlagFilter.ts | 0 .../filter/accesslog/v2/RuntimeFilter.ts | 0 .../filter/accesslog/v2/StatusCodeFilter.ts | 0 .../filter/accesslog/v2/TraceableFilter.ts | 0 .../v2/HttpConnectionManager.ts | 0 .../http_connection_manager/v2/HttpFilter.ts | 0 .../network/http_connection_manager/v2/Rds.ts | 0 .../v2/RequestIDExtension.ts | 0 .../http_connection_manager/v2/ScopedRds.ts | 0 .../v2/ScopedRouteConfigurationsList.ts | 0 .../v2/ScopedRoutes.ts | 0 .../envoy/config/listener/v2/ApiListener.ts | 0 .../envoy/config/trace/v2/Tracing.ts | 0 .../envoy/service/discovery/v2/AdsDummy.ts | 0 .../v2/AggregatedDiscoveryService.ts | 8 +- .../load_stats/v2/LoadReportingService.ts | 6 +- .../service/load_stats/v2/LoadStatsRequest.ts | 0 .../load_stats/v2/LoadStatsResponse.ts | 0 .../generated/envoy/type/CodecClientType.ts | 0 .../src/generated/envoy/type/DoubleRange.ts | 0 .../generated/envoy/type/FractionalPercent.ts | 0 .../src/generated/envoy/type/Int32Range.ts | 0 .../src/generated/envoy/type/Int64Range.ts | 0 .../src/generated/envoy/type/Percent.ts | 0 .../generated/envoy/type/SemanticVersion.ts | 0 .../envoy/type/matcher/ListStringMatcher.ts | 0 .../type/matcher/RegexMatchAndSubstitute.ts | 0 .../envoy/type/matcher/RegexMatcher.ts | 0 .../envoy/type/matcher/StringMatcher.ts | 0 .../envoy/type/metadata/v2/MetadataKey.ts | 0 .../envoy/type/metadata/v2/MetadataKind.ts | 0 .../envoy/type/tracing/v2/CustomTag.ts | 0 .../generated/google/api/CustomHttpPattern.ts | 0 .../src/generated/google/api/Http.ts | 0 .../src/generated/google/api/HttpRule.ts | 0 .../src/generated/google/protobuf/Any.ts | 0 .../generated/google/protobuf/BoolValue.ts | 0 .../generated/google/protobuf/BytesValue.ts | 0 .../google/protobuf/DescriptorProto.ts | 0 .../generated/google/protobuf/DoubleValue.ts | 0 .../src/generated/google/protobuf/Duration.ts | 0 .../src/generated/google/protobuf/Empty.ts | 0 .../google/protobuf/EnumDescriptorProto.ts | 0 .../generated/google/protobuf/EnumOptions.ts | 0 .../protobuf/EnumValueDescriptorProto.ts | 0 .../google/protobuf/EnumValueOptions.ts | 0 .../google/protobuf/FieldDescriptorProto.ts | 0 .../generated/google/protobuf/FieldOptions.ts | 0 .../google/protobuf/FileDescriptorProto.ts | 0 .../google/protobuf/FileDescriptorSet.ts | 0 .../generated/google/protobuf/FileOptions.ts | 0 .../generated/google/protobuf/FloatValue.ts | 0 .../google/protobuf/GeneratedCodeInfo.ts | 0 .../generated/google/protobuf/Int32Value.ts | 0 .../generated/google/protobuf/Int64Value.ts | 0 .../generated/google/protobuf/ListValue.ts | 0 .../google/protobuf/MessageOptions.ts | 0 .../google/protobuf/MethodDescriptorProto.ts | 0 .../google/protobuf/MethodOptions.ts | 0 .../generated/google/protobuf/NullValue.ts | 0 .../google/protobuf/OneofDescriptorProto.ts | 0 .../generated/google/protobuf/OneofOptions.ts | 0 .../google/protobuf/ServiceDescriptorProto.ts | 0 .../google/protobuf/ServiceOptions.ts | 0 .../google/protobuf/SourceCodeInfo.ts | 0 .../generated/google/protobuf/StringValue.ts | 0 .../src/generated/google/protobuf/Struct.ts | 0 .../generated/google/protobuf/Timestamp.ts | 0 .../generated/google/protobuf/UInt32Value.ts | 0 .../generated/google/protobuf/UInt64Value.ts | 0 .../google/protobuf/UninterpretedOption.ts | 0 .../src/generated/google/protobuf/Value.ts | 0 .../src/generated/google/rpc/Status.ts | 0 .../src/generated/http_connection_manager.ts | 4 +- .../src/generated/listener.ts | 4 +- .../src/generated/lrs.ts | 4 +- .../src/generated/route.ts | 4 +- .../annotations/FieldMigrateAnnotation.ts | 0 .../udpa/annotations/FileMigrateAnnotation.ts | 0 .../udpa/annotations/MigrateAnnotation.ts | 0 .../udpa/annotations/PackageVersionStatus.ts | 0 .../udpa/annotations/StatusAnnotation.ts | 0 .../src/generated/validate/AnyRules.ts | 0 .../src/generated/validate/BoolRules.ts | 0 .../src/generated/validate/BytesRules.ts | 0 .../src/generated/validate/DoubleRules.ts | 0 .../src/generated/validate/DurationRules.ts | 0 .../src/generated/validate/EnumRules.ts | 0 .../src/generated/validate/FieldRules.ts | 0 .../src/generated/validate/Fixed32Rules.ts | 0 .../src/generated/validate/Fixed64Rules.ts | 0 .../src/generated/validate/FloatRules.ts | 0 .../src/generated/validate/Int32Rules.ts | 0 .../src/generated/validate/Int64Rules.ts | 0 .../src/generated/validate/KnownRegex.ts | 0 .../src/generated/validate/MapRules.ts | 0 .../src/generated/validate/MessageRules.ts | 0 .../src/generated/validate/RepeatedRules.ts | 0 .../src/generated/validate/SFixed32Rules.ts | 0 .../src/generated/validate/SFixed64Rules.ts | 0 .../src/generated/validate/SInt32Rules.ts | 0 .../src/generated/validate/SInt64Rules.ts | 0 .../src/generated/validate/StringRules.ts | 0 .../src/generated/validate/TimestampRules.ts | 0 .../src/generated/validate/UInt32Rules.ts | 0 .../src/generated/validate/UInt64Rules.ts | 0 packages/grpc-js-xds/src/index.ts | 52 +- .../src/load-balancer-cds.ts | 109 +- .../src/load-balancer-eds.ts | 167 +-- .../src/load-balancer-lrs.ts | 127 ++- .../src/load-balancer-priority.ts | 100 +- .../src/load-balancer-weighted-target.ts | 92 +- .../src/resolver-xds.ts | 19 +- .../src/xds-bootstrap.ts | 0 .../src/xds-client.ts | 28 +- packages/grpc-js-xds/tsconfig.json | 8 +- packages/grpc-js/log.txt | 971 ++++++++++++++++++ packages/grpc-js/package.json | 2 - packages/grpc-js/src/experimental.ts | 13 + packages/grpc-js/src/index.ts | 5 + .../src/load-balancer-child-handler.ts | 6 +- .../grpc-js/src/load-balancer-pick-first.ts | 22 +- .../grpc-js/src/load-balancer-round-robin.ts | 22 +- packages/grpc-js/src/load-balancer.ts | 67 +- packages/grpc-js/src/load-balancing-config.ts | 271 ----- packages/grpc-js/src/resolver.ts | 2 - .../grpc-js/src/resolving-load-balancer.ts | 11 +- packages/grpc-js/src/service-config.ts | 6 +- packages/grpc-js/tsconfig.json | 3 +- test/kokoro/xds-interop.cfg | 2 +- 282 files changed, 1600 insertions(+), 594 deletions(-) rename packages/{grpc-js => grpc-js-xds}/deps/envoy-api (100%) rename packages/{grpc-js => grpc-js-xds}/deps/googleapis (100%) rename packages/{grpc-js => grpc-js-xds}/deps/protoc-gen-validate (100%) rename packages/{grpc-js => grpc-js-xds}/deps/udpa (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/BoolValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/EchoStatus.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/Empty.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/GrpclbRouteType.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/LoadBalancerStatsService.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/Payload.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/PayloadType.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ReconnectInfo.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ReconnectParams.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ReconnectService.ts (99%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/ResponseParameters.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/SimpleRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/SimpleResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingInputCallRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingInputCallResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingOutputCallRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/StreamingOutputCallResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/TestService.ts (99%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/UnimplementedService.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/grpc/testing/XdsUpdateHealthService.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/generated/test.ts (98%) rename packages/{grpc-js => grpc-js-xds}/interop/xds-interop-client.ts (95%) rename packages/{grpc-js => grpc-js-xds}/proto/grpc/testing/empty.proto (100%) rename packages/{grpc-js => grpc-js-xds}/proto/grpc/testing/messages.proto (100%) rename packages/{grpc-js => grpc-js-xds}/proto/grpc/testing/test.proto (100%) rename packages/{grpc-js => grpc-js-xds}/scripts/xds.sh (94%) mode change 100755 => 100644 rename packages/{grpc-js => grpc-js-xds}/src/generated/ads.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/cluster.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/endpoint.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Cluster.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/ClusterLoadAssignment.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DiscoveryRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/DiscoveryResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Listener.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/LoadBalancingPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Resource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/RouteConfiguration.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/UpstreamBindConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/Vhds.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/CommonTlsContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/GenericSecret.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/Secret.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/TlsCertificate.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/TlsParameters.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/cluster/Filter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/cluster/OutlierDetection.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Address.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ApiConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ApiVersion.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/AsyncDataSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/BackoffStrategy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/BindConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/BuildVersion.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/CidrRange.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/ControlPlane.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/DataSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/EventServiceConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Extension.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/GrpcService.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HeaderMap.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HeaderValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HeaderValueOption.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HealthCheck.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HealthStatus.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/HttpUri.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Locality.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Metadata.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Node.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/Pipe.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RateLimitSettings.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RemoteDataSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RequestMethod.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RetryPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RoutingPriority.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeDouble.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/RuntimeUInt32.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/SelfConfigSource.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/SocketAddress.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/SocketOption.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TcpKeepalive.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TrafficDirection.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/TransportSocket.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/ClusterStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/Endpoint.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/Filter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/FilterChain.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/FilterChainMatch.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/ListenerFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/CorsPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/Decorator.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/DirectResponseAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/FilterAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/HeaderMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/HedgePolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RateLimit.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RedirectAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RetryPolicy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/Route.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RouteAction.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/RouteMatch.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/Tracing.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/VirtualCluster.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/VirtualHost.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/api/v2/route/WeightedCluster.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/listener/v2/ApiListener.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/config/trace/v2/Tracing.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/discovery/v2/AdsDummy.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts (92%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts (96%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/CodecClientType.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/DoubleRange.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/FractionalPercent.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/Int32Range.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/Int64Range.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/Percent.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/SemanticVersion.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/ListStringMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/RegexMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/matcher/StringMatcher.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/metadata/v2/MetadataKey.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/metadata/v2/MetadataKind.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/envoy/type/tracing/v2/CustomTag.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/api/CustomHttpPattern.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/api/Http.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/api/HttpRule.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Any.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/BoolValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/BytesValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/DescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/DoubleValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Duration.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Empty.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumValueDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/EnumValueOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FieldDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FieldOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FileDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FileDescriptorSet.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FileOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/FloatValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/GeneratedCodeInfo.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Int32Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Int64Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/ListValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/MessageOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/MethodDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/MethodOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/NullValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/OneofDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/OneofOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/ServiceDescriptorProto.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/ServiceOptions.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/SourceCodeInfo.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/StringValue.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Struct.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Timestamp.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/UInt32Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/UInt64Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/UninterpretedOption.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/protobuf/Value.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/google/rpc/Status.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/http_connection_manager.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/listener.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/lrs.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/route.ts (99%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/FieldMigrateAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/FileMigrateAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/MigrateAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/PackageVersionStatus.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/udpa/annotations/StatusAnnotation.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/AnyRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/BoolRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/BytesRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/DoubleRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/DurationRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/EnumRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/FieldRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Fixed32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Fixed64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/FloatRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Int32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/Int64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/KnownRegex.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/MapRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/MessageRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/RepeatedRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SFixed32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SFixed64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SInt32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/SInt64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/StringRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/TimestampRules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/UInt32Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/generated/validate/UInt64Rules.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-cds.ts (60%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-eds.ts (73%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-lrs.ts (51%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-priority.ts (83%) rename packages/{grpc-js => grpc-js-xds}/src/load-balancer-weighted-target.ts (75%) rename packages/{grpc-js => grpc-js-xds}/src/resolver-xds.ts (84%) rename packages/{grpc-js => grpc-js-xds}/src/xds-bootstrap.ts (100%) rename packages/{grpc-js => grpc-js-xds}/src/xds-client.ts (98%) create mode 100644 packages/grpc-js/log.txt create mode 100644 packages/grpc-js/src/experimental.ts delete mode 100644 packages/grpc-js/src/load-balancing-config.ts diff --git a/.gitmodules b/.gitmodules index 7989090c6..4a5a1e320 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,15 +1,15 @@ [submodule "packages/grpc-tools/deps/protobuf"] path = packages/grpc-tools/deps/protobuf url = https://github.com/protocolbuffers/protobuf -[submodule "packages/grpc-js/deps/envoy-api"] - path = packages/grpc-js/deps/envoy-api +[submodule "packages/grpc-js-xds/deps/envoy-api"] + path = packages/grpc-js-xds/deps/envoy-api url = https://github.com/envoyproxy/data-plane-api.git -[submodule "packages/grpc-js/deps/udpa"] - path = packages/grpc-js/deps/udpa +[submodule "packages/grpc-js-xds/deps/udpa"] + path = packages/grpc-js-xds/deps/udpa url = https://github.com/cncf/udpa.git -[submodule "packages/grpc-js/deps/googleapis"] - path = packages/grpc-js/deps/googleapis +[submodule "packages/grpc-js-xds/deps/googleapis"] + path = packages/grpc-js-xds/deps/googleapis url = https://github.com/googleapis/googleapis.git -[submodule "packages/grpc-js/deps/protoc-gen-validate"] - path = packages/grpc-js/deps/protoc-gen-validate +[submodule "packages/grpc-js-xds/deps/protoc-gen-validate"] + path = packages/grpc-js-xds/deps/protoc-gen-validate url = https://github.com/envoyproxy/protoc-gen-validate.git diff --git a/packages/grpc-js/deps/envoy-api b/packages/grpc-js-xds/deps/envoy-api similarity index 100% rename from packages/grpc-js/deps/envoy-api rename to packages/grpc-js-xds/deps/envoy-api diff --git a/packages/grpc-js/deps/googleapis b/packages/grpc-js-xds/deps/googleapis similarity index 100% rename from packages/grpc-js/deps/googleapis rename to packages/grpc-js-xds/deps/googleapis diff --git a/packages/grpc-js/deps/protoc-gen-validate b/packages/grpc-js-xds/deps/protoc-gen-validate similarity index 100% rename from packages/grpc-js/deps/protoc-gen-validate rename to packages/grpc-js-xds/deps/protoc-gen-validate diff --git a/packages/grpc-js/deps/udpa b/packages/grpc-js-xds/deps/udpa similarity index 100% rename from packages/grpc-js/deps/udpa rename to packages/grpc-js-xds/deps/udpa diff --git a/packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/BoolValue.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/BoolValue.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/EchoStatus.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/EchoStatus.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/Empty.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/Empty.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/Empty.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/GrpclbRouteType.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/GrpclbRouteType.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts similarity index 98% rename from packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts index eece848b1..aa4f409fd 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/LoadBalancerStatsService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; diff --git a/packages/grpc-js/interop/generated/grpc/testing/Payload.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/Payload.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/PayloadType.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/PayloadType.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/ReconnectInfo.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectInfo.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/ReconnectParams.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectParams.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts similarity index 99% rename from packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts index 3829506b9..211147653 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/ReconnectService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; import { ReconnectInfo as _grpc_testing_ReconnectInfo, ReconnectInfo__Output as _grpc_testing_ReconnectInfo__Output } from '../../grpc/testing/ReconnectInfo'; import { ReconnectParams as _grpc_testing_ReconnectParams, ReconnectParams__Output as _grpc_testing_ReconnectParams__Output } from '../../grpc/testing/ReconnectParams'; diff --git a/packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/ResponseParameters.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/SimpleRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/SimpleResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingInputCallResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallRequest.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts similarity index 100% rename from packages/grpc-js/interop/generated/grpc/testing/StreamingOutputCallResponse.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts diff --git a/packages/grpc-js/interop/generated/grpc/testing/TestService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts similarity index 99% rename from packages/grpc-js/interop/generated/grpc/testing/TestService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts index b95b7a979..2ccf45fdc 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/TestService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; import { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; import { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; diff --git a/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts similarity index 98% rename from packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts index afbf91173..121dfa919 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/UnimplementedService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; /** diff --git a/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts similarity index 98% rename from packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts rename to packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts index f27a461e3..f898a16dc 100644 --- a/packages/grpc-js/interop/generated/grpc/testing/XdsUpdateHealthService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '../../../../src' +import * as grpc from '@grpc/grpc-js' import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; /** diff --git a/packages/grpc-js/interop/generated/test.ts b/packages/grpc-js-xds/interop/generated/test.ts similarity index 98% rename from packages/grpc-js/interop/generated/test.ts rename to packages/grpc-js-xds/interop/generated/test.ts index a5c95d951..330dbc9fd 100644 --- a/packages/grpc-js/interop/generated/test.ts +++ b/packages/grpc-js-xds/interop/generated/test.ts @@ -1,4 +1,4 @@ -import * as grpc from '../../src'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServiceClient } from './grpc/testing/LoadBalancerStatsService'; diff --git a/packages/grpc-js/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts similarity index 95% rename from packages/grpc-js/interop/xds-interop-client.ts rename to packages/grpc-js-xds/interop/xds-interop-client.ts index 3009541c4..526c5194f 100644 --- a/packages/grpc-js/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -15,7 +15,9 @@ * */ -import * as grpc from '../src'; +import * as grpc from '@grpc/grpc-js'; + +import * as grpc_xds from '../src'; import { ProtoGrpcType } from './generated/test'; @@ -25,6 +27,8 @@ import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancer import * as yargs from 'yargs'; import { LoadBalancerStatsServiceHandlers } from './generated/grpc/testing/LoadBalancerStatsService'; +grpc_xds.register(); + const packageDefinition = protoLoader.loadSync('grpc/testing/test.proto', { keepCase: true, defaults: true, diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f8d44cb09..af6182c5d 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -11,7 +11,9 @@ "fix": "gts fix", "prepare": "npm run compile", "pretest": "npm run compile", - "posttest": "npm run check" + "posttest": "npm run check", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto", + "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { "type": "git", @@ -31,10 +33,15 @@ "devDependencies": { "gts": "^2.0.2", "typescript": "^3.8.3", + "@types/gulp": "^4.0.6", + "@types/gulp-mocha": "0.0.32", + "@types/mocha": "^5.2.6", "@types/node": "^13.11.1", + "@types/yargs": "^15.0.5", "yargs": "^15.4.1" }, "dependencies": { + "@grpc/grpc-js": "file:../grpc-js", "@grpc/proto-loader": "^0.6.0-pre14", "google-auth-library": "^6.1.1" } diff --git a/packages/grpc-js/proto/grpc/testing/empty.proto b/packages/grpc-js-xds/proto/grpc/testing/empty.proto similarity index 100% rename from packages/grpc-js/proto/grpc/testing/empty.proto rename to packages/grpc-js-xds/proto/grpc/testing/empty.proto diff --git a/packages/grpc-js/proto/grpc/testing/messages.proto b/packages/grpc-js-xds/proto/grpc/testing/messages.proto similarity index 100% rename from packages/grpc-js/proto/grpc/testing/messages.proto rename to packages/grpc-js-xds/proto/grpc/testing/messages.proto diff --git a/packages/grpc-js/proto/grpc/testing/test.proto b/packages/grpc-js-xds/proto/grpc/testing/test.proto similarity index 100% rename from packages/grpc-js/proto/grpc/testing/test.proto rename to packages/grpc-js-xds/proto/grpc/testing/test.proto diff --git a/packages/grpc-js/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh old mode 100755 new mode 100644 similarity index 94% rename from packages/grpc-js/scripts/xds.sh rename to packages/grpc-js-xds/scripts/xds.sh index ce2b64179..79c3a17a9 --- a/packages/grpc-js/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -34,6 +34,10 @@ echo "source $NVM_DIR/nvm.sh" > ~/.profile echo "source $NVM_DIR/nvm.sh" > ~/.shrc export ENV=~/.shrc +cd $base/../grpc-js +npm install + +# grpc-js-xds has a dev dependency on "../grpc-js", so it should pull that in automatically cd $base git submodule update --init --recursive npm install diff --git a/packages/grpc-js/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts similarity index 99% rename from packages/grpc-js/src/generated/ads.ts rename to packages/grpc-js-xds/src/generated/ads.ts index a33270cc6..10c420a1d 100644 --- a/packages/grpc-js/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -1,4 +1,4 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; @@ -6,7 +6,7 @@ import { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_Aggrega type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts similarity index 99% rename from packages/grpc-js/src/generated/cluster.ts rename to packages/grpc-js-xds/src/generated/cluster.ts index 7d2b34a43..b165ae6b4 100644 --- a/packages/grpc-js/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/endpoint.ts b/packages/grpc-js-xds/src/generated/endpoint.ts similarity index 99% rename from packages/grpc-js/src/generated/endpoint.ts rename to packages/grpc-js-xds/src/generated/endpoint.ts index ade62c993..18c439848 100644 --- a/packages/grpc-js/src/generated/endpoint.ts +++ b/packages/grpc-js-xds/src/generated/endpoint.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Cluster.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/ClusterLoadAssignment.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DiscoveryRequest.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/DiscoveryResponse.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Listener.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/LoadBalancingPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Resource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/RouteConfiguration.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/UpstreamBindConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/Vhds.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/CommonTlsContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/GenericSecret.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/Secret.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsCertificate.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsParameters.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/Filter.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/cluster/OutlierDetection.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Address.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ApiConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ApiVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/AsyncDataSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BackoffStrategy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BindConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/BuildVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/CidrRange.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/ControlPlane.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/DataSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/EventServiceConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Extension.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/GrpcService.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderMap.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValue.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HeaderValueOption.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HealthCheck.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HealthStatus.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/HttpUri.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Locality.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Metadata.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Node.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/Pipe.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RateLimitSettings.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RemoteDataSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RequestMethod.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RetryPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RoutingPriority.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeDouble.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/RuntimeUInt32.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SelfConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SocketAddress.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/SocketOption.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TcpKeepalive.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TrafficDirection.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/TransportSocket.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/ClusterStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/Endpoint.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/Filter.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChain.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/FilterChainMatch.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/CorsPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Decorator.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/DirectResponseAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/FilterAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/HeaderMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/HedgePolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RateLimit.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RedirectAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RetryPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Route.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RouteAction.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/RouteMatch.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/Tracing.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/VirtualCluster.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/VirtualHost.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts diff --git a/packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/api/v2/route/WeightedCluster.ts rename to packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts diff --git a/packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts rename to packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts diff --git a/packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/listener/v2/ApiListener.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts diff --git a/packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/config/trace/v2/Tracing.ts rename to packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/discovery/v2/AdsDummy.ts rename to packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts diff --git a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts similarity index 92% rename from packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts rename to packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts index 32cc9ba51..02c0da34e 100644 --- a/packages/grpc-js/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto -import * as grpc from '../../../../../index' +import * as grpc from '@grpc/grpc-js' import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; @@ -41,12 +41,12 @@ export interface AggregatedDiscoveryServiceClient extends grpc.Client { * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover * the multiplexed singleton APIs at the Envoy instance and management server. */ -export interface AggregatedDiscoveryServiceHandlers { - DeltaAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>): void; +export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceImplementation { + DeltaAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse>): void; /** * This is a gRPC-only API. */ - StreamAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>): void; + StreamAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse>): void; } diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts similarity index 96% rename from packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts rename to packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts index 13d006947..7db2bad1c 100644 --- a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto -import * as grpc from '../../../../../index' +import * as grpc from '@grpc/grpc-js' import { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; import { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; @@ -72,7 +72,7 @@ export interface LoadReportingServiceClient extends grpc.Client { } -export interface LoadReportingServiceHandlers { +export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImplementation { /** * Advanced API to allow for multi-dimensional load balancing by remote * server. For receiving LB assignments, the steps are: @@ -103,6 +103,6 @@ export interface LoadReportingServiceHandlers { * from around the world, computes global assignment and prepares traffic * assignment destined for each zone Envoys are located in. Goto 2. */ - StreamLoadStats(call: grpc.ServerDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>): void; + StreamLoadStats(call: grpc.ServerDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>): void; } diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts rename to packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts diff --git a/packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts rename to packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts diff --git a/packages/grpc-js/src/generated/envoy/type/CodecClientType.ts b/packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/CodecClientType.ts rename to packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts diff --git a/packages/grpc-js/src/generated/envoy/type/DoubleRange.ts b/packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/DoubleRange.ts rename to packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts diff --git a/packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/FractionalPercent.ts rename to packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Int32Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Int32Range.ts rename to packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Int64Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Int64Range.ts rename to packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts diff --git a/packages/grpc-js/src/generated/envoy/type/Percent.ts b/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/Percent.ts rename to packages/grpc-js-xds/src/generated/envoy/type/Percent.ts diff --git a/packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts b/packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/SemanticVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/ListStringMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/RegexMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/matcher/StringMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKey.ts rename to packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts diff --git a/packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/metadata/v2/MetadataKind.ts rename to packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts diff --git a/packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts similarity index 100% rename from packages/grpc-js/src/generated/envoy/type/tracing/v2/CustomTag.ts rename to packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts diff --git a/packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts b/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/CustomHttpPattern.ts rename to packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts diff --git a/packages/grpc-js/src/generated/google/api/Http.ts b/packages/grpc-js-xds/src/generated/google/api/Http.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/Http.ts rename to packages/grpc-js-xds/src/generated/google/api/Http.ts diff --git a/packages/grpc-js/src/generated/google/api/HttpRule.ts b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts similarity index 100% rename from packages/grpc-js/src/generated/google/api/HttpRule.ts rename to packages/grpc-js-xds/src/generated/google/api/HttpRule.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Any.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Any.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Any.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/BoolValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/BoolValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/BoolValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/BoolValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/BytesValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/BytesValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/BytesValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/BytesValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/DescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Duration.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Duration.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Empty.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Empty.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Empty.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Empty.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumValueDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/EnumValueOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FieldDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FieldOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileDescriptorSet.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FileOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/FloatValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/FloatValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts b/packages/grpc-js-xds/src/generated/google/protobuf/GeneratedCodeInfo.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/GeneratedCodeInfo.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/GeneratedCodeInfo.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Int32Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Int32Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Int32Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Int32Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Int64Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Int64Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ListValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ListValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MessageOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MethodDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/MethodOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/NullValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/NullValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/NullValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/NullValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/OneofDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/OneofOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ServiceDescriptorProto.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/ServiceOptions.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts b/packages/grpc-js-xds/src/generated/google/protobuf/SourceCodeInfo.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/SourceCodeInfo.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/SourceCodeInfo.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/StringValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/StringValue.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/StringValue.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/StringValue.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Struct.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Struct.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Timestamp.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Timestamp.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UInt32Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/UInt32Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/UninterpretedOption.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts diff --git a/packages/grpc-js/src/generated/google/protobuf/Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts similarity index 100% rename from packages/grpc-js/src/generated/google/protobuf/Value.ts rename to packages/grpc-js-xds/src/generated/google/protobuf/Value.ts diff --git a/packages/grpc-js/src/generated/google/rpc/Status.ts b/packages/grpc-js-xds/src/generated/google/rpc/Status.ts similarity index 100% rename from packages/grpc-js/src/generated/google/rpc/Status.ts rename to packages/grpc-js-xds/src/generated/google/rpc/Status.ts diff --git a/packages/grpc-js/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts similarity index 99% rename from packages/grpc-js/src/generated/http_connection_manager.ts rename to packages/grpc-js-xds/src/generated/http_connection_manager.ts index 37fe303bb..5a90451af 100644 --- a/packages/grpc-js/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts similarity index 99% rename from packages/grpc-js/src/generated/listener.ts rename to packages/grpc-js-xds/src/generated/listener.ts index 040c1d52a..57daeffd0 100644 --- a/packages/grpc-js/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts similarity index 99% rename from packages/grpc-js/src/generated/lrs.ts rename to packages/grpc-js-xds/src/generated/lrs.ts index 47c5de6df..56ada2f3d 100644 --- a/packages/grpc-js/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -1,4 +1,4 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; @@ -6,7 +6,7 @@ import { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportin type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts similarity index 99% rename from packages/grpc-js/src/generated/route.ts rename to packages/grpc-js-xds/src/generated/route.ts index 5b251477a..40bcdd55d 100644 --- a/packages/grpc-js/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -1,11 +1,11 @@ -import * as grpc from '../index'; +import * as grpc from '@grpc/grpc-js'; import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; type SubtypeConstructor = { new(...args: ConstructorArguments): Subtype; -} +}; export interface ProtoGrpcType { envoy: { diff --git a/packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/FieldMigrateAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/FileMigrateAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/MigrateAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/PackageVersionStatus.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts diff --git a/packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts similarity index 100% rename from packages/grpc-js/src/generated/udpa/annotations/StatusAnnotation.ts rename to packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts diff --git a/packages/grpc-js/src/generated/validate/AnyRules.ts b/packages/grpc-js-xds/src/generated/validate/AnyRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/AnyRules.ts rename to packages/grpc-js-xds/src/generated/validate/AnyRules.ts diff --git a/packages/grpc-js/src/generated/validate/BoolRules.ts b/packages/grpc-js-xds/src/generated/validate/BoolRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/BoolRules.ts rename to packages/grpc-js-xds/src/generated/validate/BoolRules.ts diff --git a/packages/grpc-js/src/generated/validate/BytesRules.ts b/packages/grpc-js-xds/src/generated/validate/BytesRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/BytesRules.ts rename to packages/grpc-js-xds/src/generated/validate/BytesRules.ts diff --git a/packages/grpc-js/src/generated/validate/DoubleRules.ts b/packages/grpc-js-xds/src/generated/validate/DoubleRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/DoubleRules.ts rename to packages/grpc-js-xds/src/generated/validate/DoubleRules.ts diff --git a/packages/grpc-js/src/generated/validate/DurationRules.ts b/packages/grpc-js-xds/src/generated/validate/DurationRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/DurationRules.ts rename to packages/grpc-js-xds/src/generated/validate/DurationRules.ts diff --git a/packages/grpc-js/src/generated/validate/EnumRules.ts b/packages/grpc-js-xds/src/generated/validate/EnumRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/EnumRules.ts rename to packages/grpc-js-xds/src/generated/validate/EnumRules.ts diff --git a/packages/grpc-js/src/generated/validate/FieldRules.ts b/packages/grpc-js-xds/src/generated/validate/FieldRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/FieldRules.ts rename to packages/grpc-js-xds/src/generated/validate/FieldRules.ts diff --git a/packages/grpc-js/src/generated/validate/Fixed32Rules.ts b/packages/grpc-js-xds/src/generated/validate/Fixed32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Fixed32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Fixed32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/Fixed64Rules.ts b/packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Fixed64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/FloatRules.ts b/packages/grpc-js-xds/src/generated/validate/FloatRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/FloatRules.ts rename to packages/grpc-js-xds/src/generated/validate/FloatRules.ts diff --git a/packages/grpc-js/src/generated/validate/Int32Rules.ts b/packages/grpc-js-xds/src/generated/validate/Int32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Int32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Int32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/Int64Rules.ts b/packages/grpc-js-xds/src/generated/validate/Int64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/Int64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/Int64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/KnownRegex.ts b/packages/grpc-js-xds/src/generated/validate/KnownRegex.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/KnownRegex.ts rename to packages/grpc-js-xds/src/generated/validate/KnownRegex.ts diff --git a/packages/grpc-js/src/generated/validate/MapRules.ts b/packages/grpc-js-xds/src/generated/validate/MapRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/MapRules.ts rename to packages/grpc-js-xds/src/generated/validate/MapRules.ts diff --git a/packages/grpc-js/src/generated/validate/MessageRules.ts b/packages/grpc-js-xds/src/generated/validate/MessageRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/MessageRules.ts rename to packages/grpc-js-xds/src/generated/validate/MessageRules.ts diff --git a/packages/grpc-js/src/generated/validate/RepeatedRules.ts b/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/RepeatedRules.ts rename to packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts diff --git a/packages/grpc-js/src/generated/validate/SFixed32Rules.ts b/packages/grpc-js-xds/src/generated/validate/SFixed32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SFixed32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SFixed32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SFixed64Rules.ts b/packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SFixed64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SInt32Rules.ts b/packages/grpc-js-xds/src/generated/validate/SInt32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SInt32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SInt32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/SInt64Rules.ts b/packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/SInt64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts diff --git a/packages/grpc-js/src/generated/validate/StringRules.ts b/packages/grpc-js-xds/src/generated/validate/StringRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/StringRules.ts rename to packages/grpc-js-xds/src/generated/validate/StringRules.ts diff --git a/packages/grpc-js/src/generated/validate/TimestampRules.ts b/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/TimestampRules.ts rename to packages/grpc-js-xds/src/generated/validate/TimestampRules.ts diff --git a/packages/grpc-js/src/generated/validate/UInt32Rules.ts b/packages/grpc-js-xds/src/generated/validate/UInt32Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/UInt32Rules.ts rename to packages/grpc-js-xds/src/generated/validate/UInt32Rules.ts diff --git a/packages/grpc-js/src/generated/validate/UInt64Rules.ts b/packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts similarity index 100% rename from packages/grpc-js/src/generated/validate/UInt64Rules.ts rename to packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 2c1da1263..5aea005d6 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -1,24 +1,32 @@ -console.log('Try npm run check/fix!'); +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ -const longString = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer ut aliquet diam.'; +import * as resolver_xds from './resolver-xds'; +import * as load_balancer_cds from './load-balancer-cds'; +import * as load_balancer_eds from './load-balancer-eds'; +import * as load_balancer_lrs from './load-balancer-lrs'; +import * as load_balancer_priority from './load-balancer-priority'; +import * as load_balancer_weighted_target from './load-balancer-weighted-target'; -const trailing = 'Semicolon'; - -const why = 'am I tabbed?'; - -export function doSomeStuff( - withThis: string, - andThat: string, - andThose: string[] -) { - //function on one line - if (!andThose.length) { - return false; - } - console.log(withThis); - console.log(andThat); - console.dir(andThose); - return; -} -// TODO: more examples +export function register() { + resolver_xds.setup(); + load_balancer_cds.setup(); + load_balancer_eds.setup(); + load_balancer_lrs.setup(); + load_balancer_priority.setup(); + load_balancer_weighted_target.setup(); +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts similarity index 60% rename from packages/grpc-js/src/load-balancer-cds.ts rename to packages/grpc-js-xds/src/load-balancer-cds.ts index 15c55ed84..a2961927c 100644 --- a/packages/grpc-js/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -15,36 +15,54 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isCdsLoadBalancingConfig, - EdsLbConfig, - CdsLoadBalancingConfig, -} from './load-balancing-config'; +import { connectivityState, status, Metadata, logVerbosity, experimental } from '@grpc/grpc-js'; import { XdsClient, Watcher } from './xds-client'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; -import { ConnectivityState } from './channel'; -import { UnavailablePicker } from './picker'; -import { Status } from './constants'; -import { Metadata } from './metadata'; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; +import SubchannelAddress = experimental.SubchannelAddress; +import UnavailablePicker = experimental.UnavailablePicker; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import { EdsLoadBalancingConfig } from './load-balancer-eds'; const TRACER_NAME = 'cds_balancer'; function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } const TYPE_NAME = 'cds'; +export class CdsLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + toJsonObject(): object { + return { + [TYPE_NAME]: { + cluster: this.cluster + } + } + } + + constructor(private cluster: string) {} + + getCluster() { + return this.cluster; + } + + static createFromJson(obj: any): CdsLoadBalancingConfig { + if ('cluster' in obj) { + return new CdsLoadBalancingConfig(obj.cluster); + } else { + throw new Error('Missing "cluster" in cds load balancing config'); + } + } +} + export class CdsLoadBalancer implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; private xdsClient: XdsClient | null = null; @@ -62,41 +80,30 @@ export class CdsLoadBalancer implements LoadBalancer { this.watcher = { onValidUpdate: (update) => { this.latestCdsUpdate = update; - const edsConfig: EdsLbConfig = { - cluster: update.name, - edsServiceName: - update.eds_cluster_config!.service_name === '' - ? undefined - : update.eds_cluster_config!.service_name, - localityPickingPolicy: [], - endpointPickingPolicy: [], - }; - if (update.lrs_server?.self) { - /* the lrs_server.self field indicates that the same server should be - * used for load reporting as for other xDS operations. Setting - * lrsLoadReportingServerName to the empty string sets that behavior. - * Otherwise, if the field is omitted, load reporting is disabled. */ - edsConfig.lrsLoadReportingServerName = ''; - } + /* the lrs_server.self field indicates that the same server should be + * used for load reporting as for other xDS operations. Setting + * lrsLoadReportingServerName to the empty string sets that behavior. + * Otherwise, if the field is omitted, load reporting is disabled. */ + const edsConfig: EdsLoadBalancingConfig = new EdsLoadBalancingConfig(update.name, [], [], update.eds_cluster_config!.service_name === '' ? undefined : update.eds_cluster_config!.service_name, update.lrs_server?.self ? '' : undefined); trace('Child update EDS config: ' + JSON.stringify(edsConfig)); this.childBalancer.updateAddressList( [], - { name: 'eds', eds: edsConfig }, + edsConfig, this.latestAttributes ); }, onResourceDoesNotExist: () => { this.isWatcherActive = false; - this.channelControlHelper.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'CDS resource does not exist', metadata: new Metadata()})); + this.channelControlHelper.updateState(connectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: status.UNAVAILABLE, details: 'CDS resource does not exist', metadata: new Metadata()})); this.childBalancer.destroy(); }, - onTransientError: (status) => { + onTransientError: (statusObj) => { if (this.latestCdsUpdate === null) { channelControlHelper.updateState( - ConnectivityState.TRANSIENT_FAILURE, + connectivityState.TRANSIENT_FAILURE, new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: `xDS request failed with error ${status.details}`, + code: status.UNAVAILABLE, + details: `xDS request failed with error ${statusObj.details}`, metadata: new Metadata(), }) ); @@ -110,7 +117,7 @@ export class CdsLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isCdsLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof CdsLoadBalancingConfig)) { trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig, undefined, 2)); return; } @@ -126,11 +133,11 @@ export class CdsLoadBalancer implements LoadBalancer { * one */ if ( this.isWatcherActive && - this.latestConfig?.cds.cluster !== lbConfig.cds.cluster + this.latestConfig?.getCluster() !== lbConfig.getCluster() ) { - trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.cds.cluster); + trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.getCluster()); this.xdsClient.removeClusterWatcher( - this.latestConfig!.cds.cluster, + this.latestConfig!.getCluster(), this.watcher ); /* Setting isWatcherActive to false here lets us have one code path for @@ -144,8 +151,8 @@ export class CdsLoadBalancer implements LoadBalancer { this.latestConfig = lbConfig; if (!this.isWatcherActive) { - trace('Adding new cluster watcher for cluster name ' + lbConfig.cds.cluster); - this.xdsClient.addClusterWatcher(lbConfig.cds.cluster, this.watcher); + trace('Adding new cluster watcher for cluster name ' + lbConfig.getCluster()); + this.xdsClient.addClusterWatcher(lbConfig.getCluster(), this.watcher); this.isWatcherActive = true; } } @@ -156,11 +163,11 @@ export class CdsLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { - trace('Destroying load balancer with cluster name ' + this.latestConfig?.cds.cluster); + trace('Destroying load balancer with cluster name ' + this.latestConfig?.getCluster()); this.childBalancer.destroy(); if (this.isWatcherActive) { this.xdsClient?.removeClusterWatcher( - this.latestConfig!.cds.cluster, + this.latestConfig!.getCluster(), this.watcher ); } @@ -171,5 +178,5 @@ export class CdsLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer); + registerLoadBalancerType(TYPE_NAME, CdsLoadBalancer, CdsLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts similarity index 73% rename from packages/grpc-js/src/load-balancer-eds.ts rename to packages/grpc-js-xds/src/load-balancer-eds.ts index 9080a2f43..8919f3174 100644 --- a/packages/grpc-js/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -15,38 +15,29 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, - getFirstUsableConfig, -} from './load-balancer'; -import { SubchannelAddress, subchannelAddressToString } from './subchannel'; -import { - LoadBalancingConfig, - isEdsLoadBalancingConfig, - EdsLoadBalancingConfig, - PriorityLbConfig, - PriorityChild, - WeightedTarget, - PriorityLoadBalancingConfig, -} from './load-balancing-config'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental } from '@grpc/grpc-js'; import { XdsClient, Watcher, XdsClusterDropStats } from './xds-client'; import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; -import { ConnectivityState } from './channel'; -import { UnavailablePicker, Picker, PickResultType } from './picker'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; -import { LocalitySubchannelAddress } from './load-balancer-priority'; -import { Status } from './constants'; -import { Metadata } from './metadata'; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; +import { LocalitySubchannelAddress, PriorityChild, PriorityLoadBalancingConfig } from './load-balancer-priority'; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import SubchannelAddress = experimental.SubchannelAddress; +import subchannelAddressToString = experimental.subchannelAddressToString; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import UnavailablePicker = experimental.UnavailablePicker; +import Picker = experimental.Picker; +import PickResultType = experimental.PickResultType; +import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; +import { WeightedTarget, WeightedTargetLoadBalancingConfig } from './load-balancer-weighted-target'; +import { LrsLoadBalancingConfig } from './load-balancer-lrs'; const TRACER_NAME = 'eds_balancer'; function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } const TYPE_NAME = 'eds'; @@ -55,6 +46,71 @@ function localityToName(locality: Locality__Output) { return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; } +export class EdsLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + const jsonObj: {[key: string]: any} = { + cluster: this.cluster, + locality_picking_policy: this.localityPickingPolicy.map(policy => policy.toJsonObject()), + endpoint_picking_policy: this.endpointPickingPolicy.map(policy => policy.toJsonObject()) + }; + if (this.edsServiceName !== undefined) { + jsonObj.eds_service_name = this.edsServiceName; + } + if (this.lrsLoadReportingServerName !== undefined) { + jsonObj.lrs_load_reporting_server_name = this.lrsLoadReportingServerName; + } + return { + [TYPE_NAME]: jsonObj + }; + } + + constructor(private cluster: string, private localityPickingPolicy: LoadBalancingConfig[], private endpointPickingPolicy: LoadBalancingConfig[], private edsServiceName?: string, private lrsLoadReportingServerName?: string) { + + } + + getCluster() { + return this.cluster; + } + + getLocalityPickingPolicy() { + return this.localityPickingPolicy; + } + + getEndpointPickingPolicy() { + return this.endpointPickingPolicy; + } + + getEdsServiceName() { + return this.edsServiceName; + } + + getLrsLoadReportingServerName() { + return this.lrsLoadReportingServerName; + } + + static createFromJson(obj: any): EdsLoadBalancingConfig { + if (!('cluster' in obj && typeof obj.cluster === 'string')) { + throw new Error('eds config must have a string field cluster'); + } + if (!('locality_picking_policy' in obj && Array.isArray(obj.locality_picking_policy))) { + throw new Error('eds config must have a locality_picking_policy array'); + } + if (!('endpoint_picking_policy' in obj && Array.isArray(obj.endpoint_picking_policy))) { + throw new Error('eds config must have an endpoint_picking_policy array'); + } + if ('eds_service_name' in obj && !(obj.eds_service_name === undefined || typeof obj.eds_service_name === 'string')) { + throw new Error('eds config eds_service_name field must be a string if provided'); + } + if ('lrs_load_reporting_server_name' in obj && (!obj.lrs_load_reporting_server_name === undefined || typeof obj.lrs_load_reporting_server_name === 'string')) { + throw new Error('eds config lrs_load_reporting_server_name must be a string if provided'); + } + return new EdsLoadBalancingConfig(obj.cluster, obj.locality_picking_policy.map(validateLoadBalancingConfig), obj.endpoint_picking_policy.map(validateLoadBalancingConfig), obj.eds_service_name, obj.lrs_load_reporting_server_name); + } +} + /** * This class load balances over a cluster by making an EDS request and then * transforming the result into a configuration for another load balancing @@ -317,24 +373,12 @@ export class EdsLoadBalancer implements LoadBalancer { /* Use the endpoint picking policy from the config, default to * round_robin. */ const endpointPickingPolicy: LoadBalancingConfig[] = [ - ...this.lastestConfig.eds.endpointPickingPolicy, - { name: 'round_robin', round_robin: {} }, + ...this.lastestConfig.getEndpointPickingPolicy(), + validateLoadBalancingConfig({ round_robin: {} }), ]; let childPolicy: LoadBalancingConfig[]; - if (this.lastestConfig.eds.lrsLoadReportingServerName) { - childPolicy = [ - { - name: 'lrs', - lrs: { - cluster_name: this.lastestConfig.eds.cluster, - eds_service_name: this.lastestConfig.eds.edsServiceName ?? '', - lrs_load_reporting_server_name: this.lastestConfig.eds - .lrsLoadReportingServerName, - locality: localityObj.locality, - child_policy: endpointPickingPolicy, - }, - }, - ]; + if (this.lastestConfig.getLrsLoadReportingServerName()) { + childPolicy = [new LrsLoadBalancingConfig(this.lastestConfig.getCluster(), this.lastestConfig.getEdsServiceName() ?? '', this.lastestConfig.getLrsLoadReportingServerName()!, localityObj.locality, endpointPickingPolicy)]; } else { childPolicy = endpointPickingPolicy; } @@ -355,29 +399,15 @@ export class EdsLoadBalancer implements LoadBalancer { priorityChildren.set(newPriorityName, { config: [ - { - name: 'weighted_target', - weighted_target: { - targets: childTargets, - }, - }, + new WeightedTargetLoadBalancingConfig(childTargets), ], }); } - const childConfig: PriorityLoadBalancingConfig = { - name: 'priority', - priority: { - children: priorityChildren, - /* Contract the priority names array if it is sparse. This config only - * cares about the order of priorities, not their specific numbers */ - priorities: newPriorityNames.filter((value) => value !== undefined), - }, - }; + /* Contract the priority names array if it is sparse. This config only + * cares about the order of priorities, not their specific numbers */ + const childConfig: PriorityLoadBalancingConfig = new PriorityLoadBalancingConfig(priorityChildren, newPriorityNames.filter((value) => value !== undefined)); trace('Child update addresses: ' + addressList.map(address => '(' + subchannelAddressToString(address) + ' path=' + address.localityPath + ')')); - trace('Child update priority list: ' + childConfig.priority.priorities); - for (const [childName, child] of childConfig.priority.children) { - trace('Child update priority config: ' + childName + ' -> ' + JSON.stringify(child)); - } + trace('Child update priority config: ' + JSON.stringify(childConfig.toJsonObject(), undefined, 2)); this.childBalancer.updateAddressList( addressList, childConfig, @@ -393,8 +423,8 @@ export class EdsLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isEdsLoadBalancingConfig(lbConfig)) { - trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); + if (!(lbConfig instanceof EdsLoadBalancingConfig)) { + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } if (!(attributes.xdsClient instanceof XdsClient)) { @@ -405,8 +435,7 @@ export class EdsLoadBalancer implements LoadBalancer { this.lastestConfig = lbConfig; this.latestAttributes = attributes; this.xdsClient = attributes.xdsClient; - const newEdsServiceName = - lbConfig.eds.edsServiceName ?? lbConfig.eds.cluster; + const newEdsServiceName = lbConfig.getEdsServiceName() ?? lbConfig.getCluster(); /* If the name is changing, disable the old watcher before adding the new * one */ @@ -429,11 +458,11 @@ export class EdsLoadBalancer implements LoadBalancer { this.isWatcherActive = true; } - if (lbConfig.eds.lrsLoadReportingServerName) { + if (lbConfig.getLrsLoadReportingServerName()) { this.clusterDropStats = this.xdsClient.addClusterDropStats( - lbConfig.eds.lrsLoadReportingServerName, - lbConfig.eds.cluster, - lbConfig.eds.edsServiceName ?? '' + lbConfig.getLrsLoadReportingServerName()!, + lbConfig.getCluster(), + lbConfig.getEdsServiceName() ?? '' ); } @@ -461,5 +490,5 @@ export class EdsLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer); + registerLoadBalancerType(TYPE_NAME, EdsLoadBalancer, EdsLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts similarity index 51% rename from packages/grpc-js/src/load-balancer-lrs.ts rename to packages/grpc-js-xds/src/load-balancer-lrs.ts index da09593b0..b6fa68091 100644 --- a/packages/grpc-js/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -15,28 +15,101 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - registerLoadBalancerType, - getFirstUsableConfig, -} from './load-balancer'; -import { SubchannelAddress } from './subchannel'; -import { - LoadBalancingConfig, - isLrsLoadBalancingConfig, -} from './load-balancing-config'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { ConnectivityState } from './channel'; -import { Picker, PickArgs, PickResultType, PickResult } from './picker'; +import { connectivityState as ConnectivityState, StatusObject, status as Status, experimental } from '@grpc/grpc-js'; +import { type } from 'os'; +import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { XdsClusterLocalityStats, XdsClient } from './xds-client'; -import { Filter, BaseFilter, FilterFactory } from './filter'; -import { StatusObject, Call } from './call-stream'; -import { Status } from './constants'; -import { FilterStackFactory } from './filter-stack'; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import SubchannelAddress = experimental.SubchannelAddress; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import Picker = experimental.Picker; +import PickArgs = experimental.PickArgs; +import PickResultType = experimental.PickResultType; +import PickResult = experimental.PickResult; +import Filter = experimental.Filter; +import BaseFilter = experimental.BaseFilter; +import FilterFactory = experimental.FilterFactory; +import FilterStackFactory = experimental.FilterStackFactory; +import Call = experimental.CallStream; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig const TYPE_NAME = 'lrs'; +export class LrsLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + return { + [TYPE_NAME]: { + cluster_name: this.clusterName, + eds_service_name: this.edsServiceName, + lrs_load_reporting_server_name: this.lrsLoadReportingServerName, + locality: this.locality, + child_policy: this.childPolicy.map(policy => policy.toJsonObject()) + } + } + } + + constructor(private clusterName: string, private edsServiceName: string, private lrsLoadReportingServerName: string, private locality: Locality__Output, private childPolicy: LoadBalancingConfig[]) {} + + getClusterName() { + return this.clusterName; + } + + getEdsServiceName() { + return this.edsServiceName; + } + + getLrsLoadReportingServerName() { + return this.lrsLoadReportingServerName; + } + + getLocality() { + return this.locality; + } + + getChildPolicy() { + return this.childPolicy; + } + + static createFromJson(obj: any): LrsLoadBalancingConfig { + if (!('cluster_name' in obj && typeof obj.cluster_name === 'string')) { + throw new Error('lrs config must have a string field cluster_name'); + } + if (!('eds_service_name' in obj && typeof obj.eds_service_name === 'string')) { + throw new Error('lrs config must have a string field eds_service_name'); + } + if (!('lrs_load_reporting_server_name' in obj && typeof obj.lrs_load_reporting_server_name === 'string')) { + throw new Error('lrs config must have a string field lrs_load_reporting_server_name'); + } + if (!('locality' in obj && obj.locality !== null && typeof obj.locality === 'object')) { + throw new Error('lrs config must have an object field locality'); + } + if ('region' in obj.locality && typeof obj.locality.region !== 'string') { + throw new Error('lrs config locality.region field must be a string if provided'); + } + if ('zone' in obj.locality && typeof obj.locality.zone !== 'string') { + throw new Error('lrs config locality.zone field must be a string if provided'); + } + if ('sub_zone' in obj.locality && typeof obj.locality.sub_zone !== 'string') { + throw new Error('lrs config locality.sub_zone field must be a string if provided'); + } + if (!('child_policy' in obj && Array.isArray(obj.child_policy))) { + throw new Error('lrs config must have a child_policy array'); + } + return new LrsLoadBalancingConfig(obj.cluster_name, obj.eds_service_name, obj.lrs_load_reporting_server_name, { + region: obj.locality.region ?? '', + zone: obj.locality.zone ?? '', + sub_zone: obj.locality.sub_zone ?? '' + }, obj.child_policy.map(validateLoadBalancingConfig)); + } +} + /** * Filter class that reports when the call ends. */ @@ -132,22 +205,22 @@ export class LrsLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isLrsLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof LrsLoadBalancingConfig)) { return; } if (!(attributes.xdsClient instanceof XdsClient)) { return; } - const lrsConfig = lbConfig.lrs; this.localityStatsReporter = attributes.xdsClient.addClusterLocalityStats( - lrsConfig.lrs_load_reporting_server_name, - lrsConfig.cluster_name, - lrsConfig.eds_service_name, - lrsConfig.locality + lbConfig.getLrsLoadReportingServerName(), + lbConfig.getClusterName(), + lbConfig.getEdsServiceName(), + lbConfig.getLocality() ); const childPolicy: LoadBalancingConfig = getFirstUsableConfig( - lrsConfig.child_policy - ) ?? { name: 'pick_first', pick_first: {} }; + lbConfig.getChildPolicy(), + true + ); this.childBalancer.updateAddressList(addressList, childPolicy, attributes); } exitIdle(): void { @@ -165,5 +238,5 @@ export class LrsLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, LrsLoadBalancer); + registerLoadBalancerType(TYPE_NAME, LrsLoadBalancer, LrsLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts similarity index 83% rename from packages/grpc-js/src/load-balancer-priority.ts rename to packages/grpc-js-xds/src/load-balancer-priority.ts index 74f2e9781..17c048123 100644 --- a/packages/grpc-js/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -15,30 +15,24 @@ * */ -import { - LoadBalancer, - ChannelControlHelper, - getFirstUsableConfig, - registerLoadBalancerType, -} from './load-balancer'; -import { SubchannelAddress, subchannelAddressToString } from './subchannel'; -import { - LoadBalancingConfig, - isPriorityLoadBalancingConfig, -} from './load-balancing-config'; -import { ConnectivityState } from './channel'; -import { Picker, QueuePicker, UnavailablePicker } from './picker'; -import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -import { ChannelOptions } from './channel-options'; -import { Status } from './constants'; -import { Metadata } from './metadata'; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, ChannelOptions } from '@grpc/grpc-js'; +import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import SubchannelAddress = experimental.SubchannelAddress; +import subchannelAddressToString = experimental.subchannelAddressToString; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import Picker = experimental.Picker; +import QueuePicker = experimental.QueuePicker; +import UnavailablePicker = experimental.UnavailablePicker; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; const TRACER_NAME = 'priority'; function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } const TYPE_NAME = 'priority'; @@ -56,6 +50,61 @@ export function isLocalitySubchannelAddress( return Array.isArray((address as LocalitySubchannelAddress).localityPath); } +export interface PriorityChild { + config: LoadBalancingConfig[]; +} + +export class PriorityLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + const childrenField: {[key: string]: object} = {} + for (const [childName, childValue] of this.children.entries()) { + childrenField[childName] = { + config: childValue.config.map(value => value.toJsonObject()) + }; + } + return { + [TYPE_NAME]: { + children: childrenField, + priorities: this.priorities + } + } + } + + constructor(private children: Map, private priorities: string[]) { + } + + getChildren() { + return this.children; + } + + getPriorities() { + return this.priorities; + } + + static createFromJson(obj: any): PriorityLoadBalancingConfig { + if (!('children' in obj && obj.children !== null && typeof obj.children === 'object')) { + throw new Error('Priority config must have a children map'); + } + if (!('priorities' in obj && Array.isArray(obj.priorities) && (obj.priorities as any[]).every(value => typeof value === 'string'))) { + throw new Error('Priority config must have a priorities list'); + } + const childrenMap: Map = new Map(); + for (const childName of obj.children) { + const childObj = obj.children[childName] + if (!('config' in childObj && Array.isArray(childObj.config))) { + throw new Error(`Priority child ${childName} must have a config list`); + } + childrenMap.set(childName, { + config: childObj.config.map(validateLoadBalancingConfig) + }); + } + return new PriorityLoadBalancingConfig(childrenMap, obj.priorities); + } +} + interface PriorityChildBalancer { updateAddressList( addressList: SubchannelAddress[], @@ -384,12 +433,11 @@ export class PriorityLoadBalancer implements LoadBalancer { lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown } ): void { - if (!isPriorityLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof PriorityLoadBalancingConfig)) { // Reject a config of the wrong type - trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } - const priorityConfig = lbConfig.priority; /* For each address, the first element of its localityPath array determines * which child it belongs to. So we bucket those addresses by that first * element, and pass along the rest of the localityPath for that child @@ -427,10 +475,10 @@ export class PriorityLoadBalancer implements LoadBalancer { } this.latestAttributes = attributes; this.latestUpdates.clear(); - this.priorities = priorityConfig.priorities; + this.priorities = lbConfig.getPriorities(); /* Pair up the new child configs with the corresponding address lists, and * update all existing children with their new configs */ - for (const [childName, childConfig] of priorityConfig.children) { + for (const [childName, childConfig] of lbConfig.getChildren()) { const chosenChildConfig = getFirstUsableConfig(childConfig.config); if (chosenChildConfig !== null) { const childAddresses = childAddressMap.get(childName) ?? []; @@ -483,5 +531,5 @@ export class PriorityLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, PriorityLoadBalancer); + registerLoadBalancerType(TYPE_NAME, PriorityLoadBalancer, PriorityLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-weighted-target.ts b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts similarity index 75% rename from packages/grpc-js/src/load-balancer-weighted-target.ts rename to packages/grpc-js-xds/src/load-balancer-weighted-target.ts index 2da67e7f7..44a6acf11 100644 --- a/packages/grpc-js/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -15,28 +15,88 @@ * */ -import { LoadBalancer, ChannelControlHelper, getFirstUsableConfig, registerLoadBalancerType } from "./load-balancer"; -import { SubchannelAddress, subchannelAddressToString } from "./subchannel"; -import { LoadBalancingConfig, WeightedTarget, isWeightedTargetLoadBalancingConfig } from "./load-balancing-config"; -import { Picker, PickResult, PickArgs, QueuePicker, UnavailablePicker } from "./picker"; -import { ConnectivityState } from "./channel"; -import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; -import { Status } from "./constants"; -import { Metadata } from "./metadata"; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity, experimental } from "@grpc/grpc-js"; import { isLocalitySubchannelAddress, LocalitySubchannelAddress } from "./load-balancer-priority"; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import LoadBalancer = experimental.LoadBalancer; +import ChannelControlHelper = experimental.ChannelControlHelper; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import registerLoadBalancerType = experimental.registerLoadBalancerType; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import Picker = experimental.Picker; +import PickResult = experimental.PickResult; +import PickArgs = experimental.PickArgs; +import QueuePicker = experimental.QueuePicker; +import UnavailablePicker = experimental.UnavailablePicker; +import SubchannelAddress = experimental.SubchannelAddress; +import subchannelAddressToString = experimental.subchannelAddressToString; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig; const TRACER_NAME = 'weighted_target'; function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } const TYPE_NAME = 'weighted_target'; const DEFAULT_RETENTION_INTERVAL_MS = 15 * 60 * 1000; + export interface WeightedTarget { + weight: number; + child_policy: LoadBalancingConfig[]; +} + +export class WeightedTargetLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor(private targets: Map) { + } + + getTargets() { + return this.targets; + } + + toJsonObject(): object { + const targetsField: {[key: string]: object} = {}; + for (const [targetName, targetValue] of this.targets.entries()) { + targetsField[targetName] = { + weight: targetValue.weight, + child_policy: targetValue.child_policy.map(policy => policy.toJsonObject()) + }; + } + return { + [TYPE_NAME]: { + targets: targetsField + } + } + } + + static createFromJson(obj: any): WeightedTargetLoadBalancingConfig { + const targetsMap: Map = new Map(); + if (!('targets' in obj && obj.targets !== null && typeof obj.targets === 'object')) { + throw new Error('Weighted target config must have a targets map'); + } + for (const key of obj.targets) { + const targetObj = obj.targets[key]; + if (!('weight' in targetObj && typeof targetObj.weight === 'number')) { + throw new Error(`Weighted target ${key} must have a numeric weight`); + } + if (!('child_policy' in targetObj && Array.isArray(targetObj.child_policy))) { + throw new Error(`Weighted target ${key} must have a child_policy array`); + } + const validatedTarget: WeightedTarget = { + weight: targetObj.weight, + child_policy: targetObj.child_policy.map(validateLoadBalancingConfig) + } + targetsMap.set(key, validatedTarget); + } + return new WeightedTargetLoadBalancingConfig(targetsMap); + } +} + /** * Represents a picker and a subinterval of a larger interval used for randomly * selecting an element of a list of these objects. @@ -256,9 +316,9 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { - if (!isWeightedTargetLoadBalancingConfig(lbConfig)) { + if (!(lbConfig instanceof WeightedTargetLoadBalancingConfig)) { // Reject a config of the wrong type - trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig)); + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } @@ -289,8 +349,8 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { childAddressList.push(childAddress); } - this.targetList = Array.from(lbConfig.weighted_target.targets.keys()); - for (const [targetName, targetConfig] of lbConfig.weighted_target.targets) { + this.targetList = Array.from(lbConfig.getTargets().keys()); + for (const [targetName, targetConfig] of lbConfig.getTargets()) { let target = this.targets.get(targetName); if (target === undefined) { target = new this.WeightedChildImpl(this, targetName); @@ -335,5 +395,5 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, WeightedTargetLoadBalancer); + registerLoadBalancerType(TYPE_NAME, WeightedTargetLoadBalancer, WeightedTargetLoadBalancingConfig); } \ No newline at end of file diff --git a/packages/grpc-js/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts similarity index 84% rename from packages/grpc-js/src/resolver-xds.ts rename to packages/grpc-js-xds/src/resolver-xds.ts index 297c6c3fb..814294c81 100644 --- a/packages/grpc-js/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -14,20 +14,19 @@ * limitations under the License. */ -import { Resolver, ResolverListener, registerResolver } from './resolver'; -import { GrpcUri, uriToString } from './uri-parser'; import { XdsClient } from './xds-client'; -import { ServiceConfig } from './service-config'; -import { StatusObject } from './call-stream'; -import { Status, LogVerbosity } from './constants'; -import { Metadata } from './metadata'; -import { ChannelOptions } from './channel-options'; -import * as logging from './logging'; +import { StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions } from '@grpc/grpc-js'; +import Resolver = experimental.Resolver; +import GrpcUri = experimental.GrpcUri; +import ResolverListener = experimental.ResolverListener; +import uriToString = experimental.uriToString; +import ServiceConfig = experimental.ServiceConfig; +import registerResolver = experimental.registerResolver; const TRACER_NAME = 'xds_resolver'; function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } class XdsResolver implements Resolver { @@ -42,7 +41,7 @@ class XdsResolver implements Resolver { private reportResolutionError() { this.listener.onError({ - code: Status.UNAVAILABLE, + code: status.UNAVAILABLE, details: `xDS name resolution failed for target ${uriToString( this.target )}`, diff --git a/packages/grpc-js/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts similarity index 100% rename from packages/grpc-js/src/xds-bootstrap.ts rename to packages/grpc-js-xds/src/xds-bootstrap.ts diff --git a/packages/grpc-js/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts similarity index 98% rename from packages/grpc-js/src/xds-client.ts rename to packages/grpc-js-xds/src/xds-client.ts index 8b4d5d3ba..525db7691 100644 --- a/packages/grpc-js/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -16,19 +16,11 @@ */ import * as protoLoader from '@grpc/proto-loader'; -import { loadPackageDefinition } from './make-client'; +import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials } from '@grpc/grpc-js'; import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; -import { createGoogleDefaultCredentials, ChannelCredentials } from './channel-credentials'; import { loadBootstrapInfo } from './xds-bootstrap'; -import { ClientDuplexStream, ServiceError } from './call'; -import { StatusObject } from './call-stream'; import { isIPv4, isIPv6 } from 'net'; -import { Status, LogVerbosity } from './constants'; -import { Metadata } from './metadata'; -import * as logging from './logging'; -import { ServiceConfig } from './service-config'; -import { ChannelOptions } from './channel-options'; import { Node } from './generated/envoy/api/v2/core/Node'; import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; @@ -54,12 +46,15 @@ import { Listener__Output } from './generated/envoy/api/v2/Listener'; import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; import { Any__Output } from './generated/google/protobuf/Any'; -import { BackoffTimeout } from './backoff-timeout'; +import BackoffTimeout = experimental.BackoffTimeout; +import ServiceConfig = experimental.ServiceConfig; +import createGoogleDefaultCredentials = experimental.createGoogleDefaultCredentials; +import { CdsLoadBalancingConfig } from './load-balancer-cds'; const TRACER_NAME = 'xds_client'; function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } const clientVersion = require('../../package.json').version; @@ -554,12 +549,7 @@ class RdsState implements XdsStreamState { this.watcher.onValidUpdate({ methodConfig: [], loadBalancingConfig: [ - { - name: 'cds', - cds: { - cluster: route.route.cluster, - }, - }, + new CdsLoadBalancingConfig(route.route.cluster) ], }); return; @@ -821,7 +811,7 @@ export class XdsClient { trace('Failed to initialize xDS Client. No valid credentials types found.'); // Bubble this error up to any listeners this.reportStreamError({ - code: Status.INTERNAL, + code: status.INTERNAL, details: 'Failed to initialize xDS Client. No valid credentials types found.', metadata: new Metadata(), }); @@ -846,7 +836,7 @@ export class XdsClient { trace('Failed to initialize xDS Client. ' + error.message); // Bubble this error up to any listeners this.reportStreamError({ - code: Status.INTERNAL, + code: status.INTERNAL, details: `Failed to initialize xDS Client. ${error.message}`, metadata: new Metadata(), }); diff --git a/packages/grpc-js-xds/tsconfig.json b/packages/grpc-js-xds/tsconfig.json index d1646f011..3148d112e 100644 --- a/packages/grpc-js-xds/tsconfig.json +++ b/packages/grpc-js-xds/tsconfig.json @@ -2,10 +2,14 @@ "extends": "./node_modules/gts/tsconfig-google.json", "compilerOptions": { "rootDir": ".", - "outDir": "build" + "outDir": "build", + "target": "es2017", + "lib": ["es2017"], + "module": "commonjs", + "incremental": true }, "include": [ "src/**/*.ts", - "test/**/*.ts" + "interop/**/*.ts" ] } diff --git a/packages/grpc-js/log.txt b/packages/grpc-js/log.txt new file mode 100644 index 000000000..7a6bbc2c8 --- /dev/null +++ b/packages/grpc-js/log.txt @@ -0,0 +1,971 @@ +{ + O: [Getter/Setter], + outDir: [Getter/Setter], + 'out-dir': [Getter/Setter], + _: [ + 'envoy/service/discovery/v2/ads.proto', + 'envoy/api/v2/listener.proto', + 'envoy/api/v2/route.proto', + 'envoy/api/v2/cluster.proto', + 'envoy/api/v2/endpoint.proto' + ], + keepCase: true, + 'keep-case': true, + longs: [Function: String], + enums: [Function: String], + defaults: true, + oneofs: true, + json: true, + includeDirs: [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ], + I: [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ], + 'include-dirs': [ + 'deps/envoy-api/', + 'deps/udpa/', + 'node_modules/protobufjs/', + 'deps/googleapis/', + 'deps/protoc-gen-validate/' + ], + grpcLib: '../index', + 'grpc-lib': '../index', + '$0': 'node_modules/.bin/proto-loader-gen-types' +} +Processing envoy/service/discovery/v2/ads.proto +Writing src/generated//ads.d.ts +Writing src/generated//envoy/service/discovery/v2/AdsDummy.d.ts from file deps/envoy-api/envoy/service/discovery/v2/ads.proto +Writing src/generated//envoy/api/v2/DiscoveryRequest.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/DiscoveryResponse.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/DeltaDiscoveryRequest.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/DeltaDiscoveryResponse.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/Resource.d.ts from file deps/envoy-api/envoy/api/v2/discovery.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/rpc/Status.d.ts from file deps/googleapis/google/rpc/status.proto +Processing envoy/api/v2/listener.proto +Writing src/generated//listener.d.ts +Writing src/generated//envoy/api/v2/Listener.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/DrainType.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/DeprecatedV1.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/ConnectionBalanceConfig.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/Listener/ConnectionBalanceConfig/ExactBalance.d.ts from file deps/envoy-api/envoy/api/v2/listener.proto +Writing src/generated//envoy/api/v2/listener/Filter.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/FilterChainMatch.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/FilterChainMatch/ConnectionSourceType.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/FilterChain.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/ListenerFilterChainMatchPredicate.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/ListenerFilterChainMatchPredicate/MatchSet.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/ListenerFilter.d.ts from file deps/envoy-api/envoy/api/v2/listener/listener_components.proto +Writing src/generated//envoy/api/v2/listener/UdpListenerConfig.d.ts from file deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto +Writing src/generated//envoy/api/v2/listener/ActiveRawUdpListenerConfig.d.ts from file deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/ApiVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource/ApiType.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/AggregatedConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/SelfConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RateLimitSettings.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/auth/UpstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/DownstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext/CombinedCertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/GenericSecret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/SdsSecretConfig.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/Secret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters/TlsProtocol.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/PrivateKeyProvider.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsCertificate.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsSessionTicketKeys.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext/TrustChainVerification.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/route/VirtualHost.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualHost/TlsRequirementType.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/FilterAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Route.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster/ClusterWeight.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/GrpcRouteMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/TlsContextMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/CorsPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/ClusterNotFoundResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/InternalRedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/RequestMirrorPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Header.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Cookie.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/ConnectionProperties.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/QueryParameter.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/FilterState.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/UpgradeConfig.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryPriority.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryHostPredicate.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryBackOff.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HedgePolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction/RedirectResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/DirectResponseAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Decorator.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Tracing.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/SourceCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/DestinationCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RequestHeaders.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RemoteAddress.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/GenericKey.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/HeaderValueMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HeaderMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/QueryParameterMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/config/listener/v2/ApiListener.d.ts from file deps/envoy-api/envoy/config/listener/v2/api_listener.proto +Writing src/generated//envoy/config/filter/accesslog/v2/AccessLog.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/AccessLogFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ComparisonFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ComparisonFilter/Op.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/StatusCodeFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/DurationFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/NotHealthCheckFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/TraceableFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/RuntimeFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/AndFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/OrFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/HeaderFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ResponseFlagFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/GrpcStatusFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/GrpcStatusFilter/Status.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/config/filter/accesslog/v2/ExtensionFilter.d.ts from file deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Literal.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Environment.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Header.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Metadata.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey/PathSegment.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Request.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Route.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Cluster.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Host.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Empty.d.ts from file null +Writing src/generated//google/api/Http.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/HttpRule.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/CustomHttpPattern.d.ts from file node_modules/protobufjs/google/api/http.proto +Processing envoy/api/v2/route.proto +Writing src/generated//route.d.ts +Writing src/generated//envoy/api/v2/RouteConfiguration.d.ts from file deps/envoy-api/envoy/api/v2/route.proto +Writing src/generated//envoy/api/v2/Vhds.d.ts from file deps/envoy-api/envoy/api/v2/route.proto +Writing src/generated//envoy/api/v2/core/ApiVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource/ApiType.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/AggregatedConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/SelfConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RateLimitSettings.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/route/VirtualHost.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualHost/TlsRequirementType.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/FilterAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Route.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/WeightedCluster/ClusterWeight.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/GrpcRouteMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteMatch/TlsContextMatchOptions.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/CorsPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/ClusterNotFoundResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/InternalRedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/RequestMirrorPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Header.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/Cookie.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/ConnectionProperties.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/QueryParameter.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/HashPolicy/FilterState.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RouteAction/UpgradeConfig.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryPriority.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryHostPredicate.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RetryPolicy/RetryBackOff.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HedgePolicy.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RedirectAction/RedirectResponseCode.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/DirectResponseAction.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Decorator.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/Tracing.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/VirtualCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/SourceCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/DestinationCluster.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RequestHeaders.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/RemoteAddress.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/GenericKey.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/RateLimit/Action/HeaderValueMatch.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/HeaderMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/api/v2/route/QueryParameterMatcher.d.ts from file deps/envoy-api/envoy/api/v2/route/route_components.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Literal.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Environment.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Header.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/tracing/v2/CustomTag/Metadata.d.ts from file deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKey/PathSegment.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Request.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Route.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Cluster.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//envoy/type/metadata/v2/MetadataKind/Host.d.ts from file deps/envoy-api/envoy/type/metadata/v2/metadata.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Empty.d.ts from file null +Processing envoy/api/v2/cluster.proto +Writing src/generated//cluster.d.ts +Writing src/generated//envoy/api/v2/Cluster.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/DiscoveryType.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/DnsLookupFamily.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/ClusterProtocolSelection.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/TransportSocketMatch.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CustomClusterType.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/EdsClusterConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig/LbSubsetFallbackPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig/LbSubsetSelector.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LbSubsetConfig/LbSubsetSelector/LbSubsetSelectorFallbackPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/LeastRequestLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/RingHashLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/RingHashLbConfig/HashFunction.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/OriginalDstLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig/ZoneAwareLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig/LocalityWeightedLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/CommonLbConfig/ConsistentHashingLbConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/Cluster/RefreshRate.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/LoadBalancingPolicy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/LoadBalancingPolicy/Policy.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/UpstreamBindConfig.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/UpstreamConnectionOptions.d.ts from file deps/envoy-api/envoy/api/v2/cluster.proto +Writing src/generated//envoy/api/v2/auth/UpstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/DownstreamTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/CommonTlsContext/CombinedCertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/tls.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsParameters/TlsProtocol.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/PrivateKeyProvider.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsCertificate.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/TlsSessionTicketKeys.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/CertificateValidationContext/TrustChainVerification.d.ts from file deps/envoy-api/envoy/api/v2/auth/common.proto +Writing src/generated//envoy/api/v2/auth/GenericSecret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/SdsSecretConfig.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/auth/Secret.d.ts from file deps/envoy-api/envoy/api/v2/auth/secret.proto +Writing src/generated//envoy/api/v2/core/ApiVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ApiConfigSource/ApiType.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/AggregatedConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/SelfConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/RateLimitSettings.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/ConfigSource.d.ts from file deps/envoy-api/envoy/api/v2/core/config_source.proto +Writing src/generated//envoy/api/v2/core/HealthStatus.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/Payload.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/HttpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TcpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/RedisHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/GrpcHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/CustomHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TlsOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/TcpProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/UpstreamHttpProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/HttpProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/HttpProtocolOptions/HeadersWithUnderscoresAction.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http1ProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http1ProtocolOptions/HeaderKeyFormat.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http1ProtocolOptions/HeaderKeyFormat/ProperCaseWords.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http2ProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Http2ProtocolOptions/SettingsParameter.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/GrpcProtocolOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/protocol.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/EventServiceConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/event_service_config.proto +Writing src/generated//envoy/api/v2/cluster/CircuitBreakers.d.ts from file deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +Writing src/generated//envoy/api/v2/cluster/CircuitBreakers/Thresholds.d.ts from file deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +Writing src/generated//envoy/api/v2/cluster/CircuitBreakers/Thresholds/RetryBudget.d.ts from file deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +Writing src/generated//envoy/api/v2/cluster/Filter.d.ts from file deps/envoy-api/envoy/api/v2/cluster/filter.proto +Writing src/generated//envoy/api/v2/cluster/OutlierDetection.d.ts from file deps/envoy-api/envoy/api/v2/cluster/outlier_detection.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy/DropOverload.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint/HealthCheckConfig.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LbEndpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/CodecClientType.d.ts from file deps/envoy-api/envoy/type/http.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/Empty.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/api/Http.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/HttpRule.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/CustomHttpPattern.d.ts from file node_modules/protobufjs/google/api/http.proto +Processing envoy/api/v2/endpoint.proto +Writing src/generated//endpoint.d.ts +Writing src/generated//envoy/api/v2/ClusterLoadAssignment.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/ClusterLoadAssignment/Policy/DropOverload.d.ts from file deps/envoy-api/envoy/api/v2/endpoint.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/Endpoint/HealthCheckConfig.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LbEndpoint.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/endpoint/LocalityLbEndpoints.d.ts from file deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +Writing src/generated//envoy/api/v2/core/RoutingPriority.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RequestMethod.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TrafficDirection.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Locality.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/BuildVersion.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Extension.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Node.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Metadata.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeUInt32.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeDouble.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFeatureFlag.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValue.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderValueOption.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/HeaderMap.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/DataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RetryPolicy.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RemoteDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/AsyncDataSource.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/TransportSocket.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/RuntimeFractionalPercent.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/ControlPlane.d.ts from file deps/envoy-api/envoy/api/v2/core/base.proto +Writing src/generated//envoy/api/v2/core/Pipe.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/SocketAddress/Protocol.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/TcpKeepalive.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/BindConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/Address.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/CidrRange.d.ts from file deps/envoy-api/envoy/api/v2/core/address.proto +Writing src/generated//envoy/api/v2/core/HealthStatus.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/Payload.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/HttpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TcpHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/RedisHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/GrpcHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/CustomHealthCheck.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/HealthCheck/TlsOptions.d.ts from file deps/envoy-api/envoy/api/v2/core/health_check.proto +Writing src/generated//envoy/api/v2/core/BackoffStrategy.d.ts from file deps/envoy-api/envoy/api/v2/core/backoff.proto +Writing src/generated//envoy/api/v2/core/HttpUri.d.ts from file deps/envoy-api/envoy/api/v2/core/http_uri.proto +Writing src/generated//envoy/api/v2/core/SocketOption.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/SocketOption/SocketState.d.ts from file deps/envoy-api/envoy/api/v2/core/socket_option.proto +Writing src/generated//envoy/api/v2/core/EventServiceConfig.d.ts from file deps/envoy-api/envoy/api/v2/core/event_service_config.proto +Writing src/generated//envoy/api/v2/core/GrpcService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/EnvoyGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/SslCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/GoogleLocalCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/ChannelCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/ServiceAccountJWTAccessCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/GoogleIAMCredentials.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/MetadataCredentialsFromPlugin.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/api/v2/core/GrpcService/GoogleGrpc/CallCredentials/StsService.d.ts from file deps/envoy-api/envoy/api/v2/core/grpc_service.proto +Writing src/generated//envoy/type/Percent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/FractionalPercent/DenominatorType.d.ts from file deps/envoy-api/envoy/type/percent.proto +Writing src/generated//envoy/type/matcher/StringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/ListStringMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/string.proto +Writing src/generated//envoy/type/matcher/RegexMatcher.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatcher/GoogleRE2.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/matcher/RegexMatchAndSubstitute.d.ts from file deps/envoy-api/envoy/type/matcher/regex.proto +Writing src/generated//envoy/type/SemanticVersion.d.ts from file deps/envoy-api/envoy/type/semantic_version.proto +Writing src/generated//envoy/type/CodecClientType.d.ts from file deps/envoy-api/envoy/type/http.proto +Writing src/generated//envoy/type/Int64Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/Int32Range.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//envoy/type/DoubleRange.d.ts from file deps/envoy-api/envoy/type/range.proto +Writing src/generated//udpa/annotations/MigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FieldMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/FileMigrateAnnotation.d.ts from file deps/udpa/udpa/annotations/migrate.proto +Writing src/generated//udpa/annotations/PackageVersionStatus.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//udpa/annotations/StatusAnnotation.d.ts from file deps/udpa/udpa/annotations/status.proto +Writing src/generated//validate/FieldRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/FloatRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DoubleRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Int64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/UInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SInt64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/Fixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed32Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/SFixed64Rules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BoolRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/StringRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/KnownRegex.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/BytesRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/EnumRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MessageRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/RepeatedRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/MapRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/AnyRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/DurationRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//validate/TimestampRules.d.ts from file deps/protoc-gen-validate/validate/validate.proto +Writing src/generated//google/protobuf/Duration.d.ts from file null +Writing src/generated//google/protobuf/DoubleValue.d.ts from file null +Writing src/generated//google/protobuf/FloatValue.d.ts from file null +Writing src/generated//google/protobuf/Int64Value.d.ts from file null +Writing src/generated//google/protobuf/UInt64Value.d.ts from file null +Writing src/generated//google/protobuf/Int32Value.d.ts from file null +Writing src/generated//google/protobuf/UInt32Value.d.ts from file null +Writing src/generated//google/protobuf/BoolValue.d.ts from file null +Writing src/generated//google/protobuf/StringValue.d.ts from file null +Writing src/generated//google/protobuf/BytesValue.d.ts from file null +Writing src/generated//google/protobuf/Timestamp.d.ts from file null +Writing src/generated//google/protobuf/FileDescriptorSet.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ExtensionRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/DescriptorProto/ReservedRange.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Type.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldDescriptorProto/Label.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodDescriptorProto.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FileOptions/OptimizeMode.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MessageOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/CType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/FieldOptions/JSType.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/OneofOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/EnumValueOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/ServiceOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/MethodOptions.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/UninterpretedOption/NamePart.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/SourceCodeInfo/Location.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/GeneratedCodeInfo/Annotation.d.ts from file node_modules/protobufjs/google/protobuf/descriptor.proto +Writing src/generated//google/protobuf/Any.d.ts from file null +Writing src/generated//google/protobuf/Struct.d.ts from file null +Writing src/generated//google/protobuf/Value.d.ts from file null +Writing src/generated//google/protobuf/NullValue.d.ts from file null +Writing src/generated//google/protobuf/ListValue.d.ts from file null +Writing src/generated//google/protobuf/Empty.d.ts from file null +Writing src/generated//google/api/Http.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/HttpRule.d.ts from file node_modules/protobufjs/google/api/http.proto +Writing src/generated//google/api/CustomHttpPattern.d.ts from file node_modules/protobufjs/google/api/http.proto +Success diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 45c4cad4b..b31448c3d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -47,8 +47,6 @@ "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib ../index envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto", - "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib ../../src grpc/testing/test.proto", "lint": "npm run check", "prepare": "npm run compile", "test": "gulp test", diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts new file mode 100644 index 000000000..b88f124ae --- /dev/null +++ b/packages/grpc-js/src/experimental.ts @@ -0,0 +1,13 @@ +export { trace } from './logging'; +export { Resolver, ResolverListener, registerResolver } from './resolver'; +export { GrpcUri, uriToString } from './uri-parser'; +export { ServiceConfig } from './service-config'; +export { createGoogleDefaultCredentials } from './channel-credentials'; +export { BackoffTimeout } from './backoff-timeout'; +export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig } from './load-balancer'; +export { SubchannelAddress, subchannelAddressToString } from './subchannel'; +export { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +export { Picker, UnavailablePicker, QueuePicker, PickResult, PickArgs, PickResultType } from './picker'; +export { Call as CallStream } from './call-stream'; +export { Filter, BaseFilter, FilterFactory } from './filter'; +export { FilterStackFactory } from './filter-stack'; \ No newline at end of file diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 89e604e37..e90ac4be8 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -246,6 +246,11 @@ export { export { GrpcObject } from './make-client'; +export { ChannelOptions } from './channel-options'; + +import * as experimental from './experimental'; +export { experimental }; + import * as resolver from './resolver'; import * as load_balancer from './load-balancer'; diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index b0044d126..337174c0d 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -19,9 +19,9 @@ import { LoadBalancer, ChannelControlHelper, createLoadBalancer, + LoadBalancingConfig } from './load-balancer'; import { SubchannelAddress, Subchannel } from './subchannel'; -import { LoadBalancingConfig } from './load-balancing-config'; import { ChannelOptions } from './channel-options'; import { ConnectivityState } from './channel'; import { Picker } from './picker'; @@ -90,10 +90,10 @@ export class ChildLoadBalancerHandler implements LoadBalancer { let childToUpdate: LoadBalancer; if ( this.currentChild === null || - this.currentChild.getTypeName() !== lbConfig.name + this.currentChild.getTypeName() !== lbConfig.getLoadBalancerName() ) { const newHelper = new this.ChildPolicyHelper(this); - const newChild = createLoadBalancer(lbConfig.name, newHelper)!; + const newChild = createLoadBalancer(lbConfig, newHelper)!; newHelper.setChild(newChild); if (this.currentChild === null) { this.currentChild = newChild; diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index b5cea06ce..31dc17847 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -19,6 +19,7 @@ import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType, + LoadBalancingConfig } from './load-balancer'; import { ConnectivityState } from './channel'; import { @@ -29,7 +30,6 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import { Subchannel, ConnectivityStateListener, @@ -53,6 +53,24 @@ const TYPE_NAME = 'pick_first'; */ const CONNECTION_DELAY_INTERVAL_MS = 250; +export class PickFirstLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor() {} + + toJsonObject(): object { + return { + [TYPE_NAME]: {} + }; + } + + static createFromJson(obj: any) { + return new PickFirstLoadBalancingConfig(); + } +} + /** * Picker for a `PickFirstLoadBalancer` in the READY state. Always returns the * picked subchannel. @@ -439,5 +457,5 @@ export class PickFirstLoadBalancer implements LoadBalancer { } export function setup(): void { - registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer); + registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer, PickFirstLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 8ee2201a5..fc9bef0c7 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -19,6 +19,7 @@ import { LoadBalancer, ChannelControlHelper, registerLoadBalancerType, + LoadBalancingConfig } from './load-balancer'; import { ConnectivityState } from './channel'; import { @@ -29,7 +30,6 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import { Subchannel, ConnectivityStateListener, @@ -47,6 +47,24 @@ function trace(text: string): void { const TYPE_NAME = 'round_robin'; +class RoundRobinLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor() {} + + toJsonObject(): object { + return { + [TYPE_NAME]: {} + }; + } + + static createFromJson(obj: any) { + return new RoundRobinLoadBalancingConfig(); + } +} + class RoundRobinPicker implements Picker { constructor( private readonly subchannelList: Subchannel[], @@ -231,5 +249,5 @@ export class RoundRobinLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer); + registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer, RoundRobinLoadBalancingConfig); } diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 56dd06f3b..8d5c7c837 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -19,14 +19,8 @@ import { ChannelOptions } from './channel-options'; import { Subchannel, SubchannelAddress } from './subchannel'; import { ConnectivityState } from './channel'; import { Picker } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; -import * as load_balancer_priority from './load-balancer-priority'; -import * as load_balancer_weighted_target from './load-balancer-weighted-target'; -import * as load_balancer_eds from './load-balancer-eds'; -import * as load_balancer_cds from './load-balancer-cds'; -import * as load_balancer_lrs from './load-balancer-lrs'; /** * A collection of functions associated with a channel that a load balancer @@ -102,23 +96,41 @@ export interface LoadBalancerConstructor { new (channelControlHelper: ChannelControlHelper): LoadBalancer; } +export interface LoadBalancingConfig { + getLoadBalancerName(): string; + toJsonObject(): object; +} + +export interface LoadBalancingConfigConstructor { + new(...args: any): LoadBalancingConfig; + createFromJson(obj: any): LoadBalancingConfig; +} + const registeredLoadBalancerTypes: { - [name: string]: LoadBalancerConstructor; + [name: string]: { + LoadBalancer: LoadBalancerConstructor, + LoadBalancingConfig: LoadBalancingConfigConstructor + }; } = {}; export function registerLoadBalancerType( typeName: string, - loadBalancerType: LoadBalancerConstructor + loadBalancerType: LoadBalancerConstructor, + loadBalancingConfigType: LoadBalancingConfigConstructor ) { - registeredLoadBalancerTypes[typeName] = loadBalancerType; + registeredLoadBalancerTypes[typeName] = { + LoadBalancer: loadBalancerType, + LoadBalancingConfig: loadBalancingConfigType + }; } export function createLoadBalancer( - typeName: string, + config: LoadBalancingConfig, channelControlHelper: ChannelControlHelper ): LoadBalancer | null { + const typeName = config.getLoadBalancerName(); if (typeName in registeredLoadBalancerTypes) { - return new registeredLoadBalancerTypes[typeName](channelControlHelper); + return new registeredLoadBalancerTypes[typeName].LoadBalancer(channelControlHelper); } else { return null; } @@ -128,23 +140,40 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; } +export function getFirstUsableConfig(configs: LoadBalancingConfig[], defaultPickFirst?: true): LoadBalancingConfig; export function getFirstUsableConfig( - configs: LoadBalancingConfig[] + configs: LoadBalancingConfig[], + defaultPickFirst: boolean = false ): LoadBalancingConfig | null { for (const config of configs) { - if (config.name in registeredLoadBalancerTypes) { + if (config.getLoadBalancerName() in registeredLoadBalancerTypes) { return config; } } - return null; + if (defaultPickFirst) { + return new load_balancer_pick_first.PickFirstLoadBalancingConfig() + } else { + return null; + } +} + +export function validateLoadBalancingConfig(obj: any): LoadBalancingConfig { + if (!(obj !== null && (typeof obj === 'object'))) { + throw new Error('Load balancing config must be an object'); + } + const keys = Object.keys(obj); + if (keys.length !== 1) { + throw new Error('Provided load balancing config has multiple conflicting entries'); + } + const typeName = keys[0]; + if (typeName in registeredLoadBalancerTypes) { + return registeredLoadBalancerTypes[typeName].LoadBalancingConfig.createFromJson(obj[typeName]); + } else { + throw new Error(`Unrecognized load balancing config name ${typeName}`); + } } export function registerAll() { load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); - load_balancer_priority.setup(); - load_balancer_weighted_target.setup(); - load_balancer_eds.setup(); - load_balancer_cds.setup(); - load_balancer_lrs.setup(); } diff --git a/packages/grpc-js/src/load-balancing-config.ts b/packages/grpc-js/src/load-balancing-config.ts deleted file mode 100644 index d4d7792e9..000000000 --- a/packages/grpc-js/src/load-balancing-config.ts +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; - -/* This file is an implementation of gRFC A24: - * https://github.com/grpc/proposal/blob/master/A24-lb-policy-config.md. Each - * function here takes an object with unknown structure and returns its - * specific object type if the input has the right structure, and throws an - * error otherwise. */ - -/* The any type is purposely used here. All functions validate their input at - * runtime */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export type PickFirstConfig = {}; - -export type RoundRobinConfig = {}; - -export interface XdsConfig { - balancerName: string; - childPolicy: LoadBalancingConfig[]; - fallbackPolicy: LoadBalancingConfig[]; -} - -export interface GrpcLbConfig { - childPolicy: LoadBalancingConfig[]; -} - -export interface PriorityChild { - config: LoadBalancingConfig[]; -} - -export interface PriorityLbConfig { - children: Map; - priorities: string[]; -} - -export interface WeightedTarget { - weight: number; - child_policy: LoadBalancingConfig[]; -} - -export interface WeightedTargetLbConfig { - targets: Map; -} - -export interface EdsLbConfig { - cluster: string; - edsServiceName?: string; - lrsLoadReportingServerName?: string; - /** - * This policy's config is expected to be in the format used by the - * weighted_target policy. Defaults to weighted_target if not specified. - * - * This is currently not used because there is currently no other config - * that has the same format as weighted_target. - */ - localityPickingPolicy: LoadBalancingConfig[]; - /** - * Defaults to round_robin if not specified. - */ - endpointPickingPolicy: LoadBalancingConfig[]; -} - -export interface CdsLbConfig { - cluster: string; -} - -export interface LrsLbConfig { - cluster_name: string; - eds_service_name: string; - lrs_load_reporting_server_name: string; - locality: Locality__Output; - child_policy: LoadBalancingConfig[]; -} - -export interface PickFirstLoadBalancingConfig { - name: 'pick_first'; - pick_first: PickFirstConfig; -} - -export interface RoundRobinLoadBalancingConfig { - name: 'round_robin'; - round_robin: RoundRobinConfig; -} - -export interface XdsLoadBalancingConfig { - name: 'xds'; - xds: XdsConfig; -} - -export interface GrpcLbLoadBalancingConfig { - name: 'grpclb'; - grpclb: GrpcLbConfig; -} - -export interface PriorityLoadBalancingConfig { - name: 'priority'; - priority: PriorityLbConfig; -} - -export interface WeightedTargetLoadBalancingConfig { - name: 'weighted_target'; - weighted_target: WeightedTargetLbConfig; -} - -export interface EdsLoadBalancingConfig { - name: 'eds'; - eds: EdsLbConfig; -} - -export interface CdsLoadBalancingConfig { - name: 'cds'; - cds: CdsLbConfig; -} - -export interface LrsLoadBalancingConfig { - name: 'lrs'; - lrs: LrsLbConfig; -} - -export type LoadBalancingConfig = - | PickFirstLoadBalancingConfig - | RoundRobinLoadBalancingConfig - | XdsLoadBalancingConfig - | GrpcLbLoadBalancingConfig - | PriorityLoadBalancingConfig - | WeightedTargetLoadBalancingConfig - | EdsLoadBalancingConfig - | CdsLoadBalancingConfig - | LrsLoadBalancingConfig; - -export function isRoundRobinLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is RoundRobinLoadBalancingConfig { - return lbconfig.name === 'round_robin'; -} - -export function isXdsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is XdsLoadBalancingConfig { - return lbconfig.name === 'xds'; -} - -export function isGrpcLbLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is GrpcLbLoadBalancingConfig { - return lbconfig.name === 'grpclb'; -} - -export function isPriorityLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is PriorityLoadBalancingConfig { - return lbconfig.name === 'priority'; -} - -export function isWeightedTargetLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is WeightedTargetLoadBalancingConfig { - return lbconfig.name === 'weighted_target'; -} - -export function isEdsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is EdsLoadBalancingConfig { - return lbconfig.name === 'eds'; -} - -export function isCdsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is CdsLoadBalancingConfig { - return lbconfig.name === 'cds'; -} - -export function isLrsLoadBalancingConfig( - lbconfig: LoadBalancingConfig -): lbconfig is LrsLoadBalancingConfig { - return lbconfig.name === 'lrs'; -} - -/* In these functions we assume the input came from a JSON object. Therefore we - * expect that the prototype is uninteresting and that `in` can be used - * effectively */ - -function validateXdsConfig(xds: any): XdsConfig { - if (!('balancerName' in xds) || typeof xds.balancerName !== 'string') { - throw new Error('Invalid xds config: invalid balancerName'); - } - const xdsConfig: XdsConfig = { - balancerName: xds.balancerName, - childPolicy: [], - fallbackPolicy: [], - }; - if ('childPolicy' in xds) { - if (!Array.isArray(xds.childPolicy)) { - throw new Error('Invalid xds config: invalid childPolicy'); - } - for (const policy of xds.childPolicy) { - xdsConfig.childPolicy.push(validateConfig(policy)); - } - } - if ('fallbackPolicy' in xds) { - if (!Array.isArray(xds.fallbackPolicy)) { - throw new Error('Invalid xds config: invalid fallbackPolicy'); - } - for (const policy of xds.fallbackPolicy) { - xdsConfig.fallbackPolicy.push(validateConfig(policy)); - } - } - return xdsConfig; -} - -function validateGrpcLbConfig(grpclb: any): GrpcLbConfig { - const grpcLbConfig: GrpcLbConfig = { - childPolicy: [], - }; - if ('childPolicy' in grpclb) { - if (!Array.isArray(grpclb.childPolicy)) { - throw new Error('Invalid xds config: invalid childPolicy'); - } - for (const policy of grpclb.childPolicy) { - grpcLbConfig.childPolicy.push(validateConfig(policy)); - } - } - return grpcLbConfig; -} - -export function validateConfig(obj: any): LoadBalancingConfig { - if ('round_robin' in obj) { - if ('xds' in obj || 'grpclb' in obj) { - throw new Error('Multiple load balancing policies configured'); - } - if (obj['round_robin'] instanceof Object) { - return { - name: 'round_robin', - round_robin: {}, - }; - } - } - if ('xds' in obj) { - if ('grpclb' in obj) { - throw new Error('Multiple load balancing policies configured'); - } - return { - name: 'xds', - xds: validateXdsConfig(obj.xds), - }; - } - if ('grpclb' in obj) { - return { - name: 'grpclb', - grpclb: validateGrpcLbConfig(obj.grpclb), - }; - } - throw new Error('No recognized load balancing policy configured'); -} diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 0c4c0d6b9..57c750aea 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,7 +18,6 @@ import { ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; -import * as resolver_xds from './resolver-xds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; @@ -157,5 +156,4 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); - resolver_xds.setup(); } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 452d3c28d..2ce59d0c2 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -19,13 +19,13 @@ import { ChannelControlHelper, LoadBalancer, getFirstUsableConfig, + LoadBalancingConfig } from './load-balancer'; import { ServiceConfig, validateServiceConfig } from './service-config'; import { ConnectivityState } from './channel'; import { createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; -import { LoadBalancingConfig } from './load-balancing-config'; import { BackoffTimeout } from './backoff-timeout'; import { Status } from './constants'; import { StatusObject } from './call-stream'; @@ -36,6 +36,7 @@ import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { ChannelOptions } from './channel-options'; +import { PickFirstLoadBalancingConfig } from './load-balancer-pick-first'; const TRACER_NAME = 'resolving_load_balancer'; @@ -163,13 +164,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } const workingConfigList = workingServiceConfig?.loadBalancingConfig ?? []; - if (workingConfigList.length === 0) { - workingConfigList.push({ - name: 'pick_first', - pick_first: {}, - }); - } - const loadBalancingConfig = getFirstUsableConfig(workingConfigList); + const loadBalancingConfig = getFirstUsableConfig(workingConfigList, true); if (loadBalancingConfig === null) { // There were load balancing configs but none are supported. This counts as a resolution failure this.handleResolutionFailure({ diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index ea5c449a7..ed225e087 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -26,8 +26,8 @@ * runtime */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import * as lbconfig from './load-balancing-config'; import * as os from 'os'; +import { LoadBalancingConfig, validateLoadBalancingConfig } from './load-balancer'; export interface MethodConfigName { service: string; @@ -44,7 +44,7 @@ export interface MethodConfig { export interface ServiceConfig { loadBalancingPolicy?: string; - loadBalancingConfig: lbconfig.LoadBalancingConfig[]; + loadBalancingConfig: LoadBalancingConfig[]; methodConfig: MethodConfig[]; } @@ -139,7 +139,7 @@ export function validateServiceConfig(obj: any): ServiceConfig { if ('loadBalancingConfig' in obj) { if (Array.isArray(obj.loadBalancingConfig)) { for (const config of obj.loadBalancingConfig) { - result.loadBalancingConfig.push(lbconfig.validateConfig(config)); + result.loadBalancingConfig.push(validateLoadBalancingConfig(config)); } } else { throw new Error('Invalid service config: invalid loadBalancingConfig'); diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index 65ebf089e..ba675db78 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -10,7 +10,6 @@ }, "include": [ "src/**/*.ts", - "test/**/*.ts", - "interop/**/*.ts" + "test/**/*.ts" ] } diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 7aae7d96c..16a7dc7dc 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js/scripts/xds.sh" +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" timeout_mins: 120 action { define_artifacts { From c86f08c770655994375e2b89801db088b3e9291c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 13:56:18 -0700 Subject: [PATCH 1295/1899] Document experimental namespace instability --- packages/grpc-js/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index e34cee9c4..4bb4da024 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -42,3 +42,4 @@ The public API of this library follows semantic versioning, with some caveats: - Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API. - The class `Call` is only exposed due to limitations of TypeScript. It should not be considered part of the public API. - In general, any API that is exposed by this library but is not exposed by the `grpc` library is likely an error and should not be considered part of the public API. +- The `grpc.experimental` namespace contains APIs that have not stabilized. Any API in that namespace may break in any minor version update. From e05b74b631aa2b45ede14fd987c1058d54607bcc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 14:06:14 -0700 Subject: [PATCH 1296/1899] Add grpc-js-xds README --- packages/grpc-js-xds/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/grpc-js-xds/README.md diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md new file mode 100644 index 000000000..2ada0bade --- /dev/null +++ b/packages/grpc-js-xds/README.md @@ -0,0 +1,24 @@ +# @grpc/grpc-js xDS plugin + +This package provides support for the `xds://` URL scheme to the `@grpc/grpc-js` library. The latest version of this package is compatible with `@grpc/grpc-js` version 1.2.x. + +## Installation + +``` +npm install @grpc/grpc-js-xds +``` + +## Usage + +```ts +import * as grpcJsXds from '@grpc/grpc-js-xds'; +grpcJsXds.register(); + +// ...get a @grpc/grpc-js Client class as usual + +const client = new MyServiceClient('xds:///example.com:123'); +``` + +## Supported Features + + - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) \ No newline at end of file From e71caded1b81f70b9ed6f6bae6765b052e62f7c3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 14:10:37 -0700 Subject: [PATCH 1297/1899] Put the google-auth-library dependency back in grpc-js --- packages/grpc-js-xds/package.json | 3 +-- packages/grpc-js/package.json | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index af6182c5d..5962d42a0 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -42,7 +42,6 @@ }, "dependencies": { "@grpc/grpc-js": "file:../grpc-js", - "@grpc/proto-loader": "^0.6.0-pre14", - "google-auth-library": "^6.1.1" + "@grpc/proto-loader": "^0.6.0-pre14" } } diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index b31448c3d..87e10abfb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -57,6 +57,7 @@ }, "dependencies": { "@types/node": "^12.12.47", + "google-auth-library": "^6.1.1", "semver": "^6.2.0" }, "files": [ From 96cba74b9b07461c63692c73c63a6e3c5af3531b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 14:33:21 -0700 Subject: [PATCH 1298/1899] Use 'import type' where possible --- .../proto-loader/bin/proto-loader-gen-types.ts | 8 ++++---- packages/proto-loader/golden-generated/echo.ts | 6 +++--- .../golden-generated/google/api/Http.ts | 2 +- .../golden-generated/google/api/HttpRule.ts | 4 ++-- .../longrunning/ListOperationsResponse.ts | 2 +- .../google/longrunning/Operation.ts | 4 ++-- .../google/longrunning/Operations.ts | 16 ++++++++-------- .../google/longrunning/WaitOperationRequest.ts | 2 +- .../golden-generated/google/protobuf/Any.ts | 2 +- .../google/protobuf/DescriptorProto.ts | 10 +++++----- .../google/protobuf/Duration.ts | 2 +- .../google/protobuf/EnumDescriptorProto.ts | 4 ++-- .../google/protobuf/EnumOptions.ts | 2 +- .../protobuf/EnumValueDescriptorProto.ts | 2 +- .../google/protobuf/EnumValueOptions.ts | 2 +- .../google/protobuf/FieldDescriptorProto.ts | 2 +- .../google/protobuf/FieldOptions.ts | 4 ++-- .../google/protobuf/FileDescriptorProto.ts | 12 ++++++------ .../google/protobuf/FileDescriptorSet.ts | 2 +- .../google/protobuf/FileOptions.ts | 2 +- .../google/protobuf/MessageOptions.ts | 2 +- .../google/protobuf/MethodDescriptorProto.ts | 2 +- .../google/protobuf/MethodOptions.ts | 6 +++--- .../google/protobuf/OneofDescriptorProto.ts | 2 +- .../google/protobuf/OneofOptions.ts | 2 +- .../google/protobuf/ServiceDescriptorProto.ts | 4 ++-- .../google/protobuf/ServiceOptions.ts | 2 +- .../google/protobuf/Timestamp.ts | 2 +- .../google/protobuf/UninterpretedOption.ts | 2 +- .../golden-generated/google/rpc/Status.ts | 2 +- .../google/showcase/v1beta1/BlockRequest.ts | 6 +++--- .../google/showcase/v1beta1/Echo.ts | 18 +++++++++--------- .../google/showcase/v1beta1/EchoRequest.ts | 4 ++-- .../google/showcase/v1beta1/EchoResponse.ts | 2 +- .../google/showcase/v1beta1/ExpandRequest.ts | 2 +- .../showcase/v1beta1/PagedExpandResponse.ts | 2 +- .../google/showcase/v1beta1/WaitMetadata.ts | 2 +- .../google/showcase/v1beta1/WaitRequest.ts | 8 ++++---- packages/proto-loader/package.json | 2 +- 39 files changed, 81 insertions(+), 81 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 1238e0402..3b34f52bb 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -141,7 +141,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv throw new Error('Invalid object passed to getImportLine'); } } - return `import { ${importedTypes} } from '${filePath}';` + return `import type { ${importedTypes} } from '${filePath}';` } function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf.Type | Protobuf.Enum)[] { @@ -412,10 +412,10 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob } } if (usesLong) { - formatter.writeLine("import { Long } from '@grpc/proto-loader';"); + formatter.writeLine("import type { Long } from '@grpc/proto-loader';"); } if (messageType.fullName === '.google.protobuf.Any') { - formatter.writeLine("import { AnyExtension } from '@grpc/proto-loader';") + formatter.writeLine("import type { AnyExtension } from '@grpc/proto-loader';") } formatter.writeLine(''); for (const childType of childTypes.sort(compareName)) { @@ -598,7 +598,7 @@ function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Prot function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { formatter.writeLine(`import * as grpc from '${options.grpcLib}';`); - formatter.writeLine("import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); + formatter.writeLine("import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); formatter.writeLine(''); generateServiceImports(formatter, root, options); diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index f24c35ec5..70cb030de 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -1,8 +1,8 @@ import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { OperationsClient as _google_longrunning_OperationsClient } from './google/longrunning/Operations'; -import { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/showcase/v1beta1/Echo'; +import type { OperationsClient as _google_longrunning_OperationsClient } from './google/longrunning/Operations'; +import type { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/showcase/v1beta1/Echo'; type SubtypeConstructor = { new(...args: ConstructorParameters): Subtype; diff --git a/packages/proto-loader/golden-generated/google/api/Http.ts b/packages/proto-loader/golden-generated/google/api/Http.ts index 038c57e5e..e9b3cb309 100644 --- a/packages/proto-loader/golden-generated/google/api/Http.ts +++ b/packages/proto-loader/golden-generated/google/api/Http.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/api/http.proto -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; /** * Defines the HTTP configuration for an API service. It contains a list of diff --git a/packages/proto-loader/golden-generated/google/api/HttpRule.ts b/packages/proto-loader/golden-generated/google/api/HttpRule.ts index ed9921e5e..21ad897ee 100644 --- a/packages/proto-loader/golden-generated/google/api/HttpRule.ts +++ b/packages/proto-loader/golden-generated/google/api/HttpRule.ts @@ -1,7 +1,7 @@ // Original file: deps/googleapis/google/api/http.proto -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; /** * # gRPC Transcoding diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts index 4d893c45f..c295aa801 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; +import type { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; /** * The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts index 095b77799..2aa9b8c71 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts @@ -1,7 +1,7 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../google/rpc/Status'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../google/rpc/Status'; /** * This resource represents a long-running operation that is the result of a diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 1d1d2b070..81a470320 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -1,14 +1,14 @@ // Original file: deps/googleapis/google/longrunning/operations.proto import * as grpc from '@grpc/grpc-js' -import { CancelOperationRequest as _google_longrunning_CancelOperationRequest, CancelOperationRequest__Output as _google_longrunning_CancelOperationRequest__Output } from '../../google/longrunning/CancelOperationRequest'; -import { DeleteOperationRequest as _google_longrunning_DeleteOperationRequest, DeleteOperationRequest__Output as _google_longrunning_DeleteOperationRequest__Output } from '../../google/longrunning/DeleteOperationRequest'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../google/protobuf/Empty'; -import { GetOperationRequest as _google_longrunning_GetOperationRequest, GetOperationRequest__Output as _google_longrunning_GetOperationRequest__Output } from '../../google/longrunning/GetOperationRequest'; -import { ListOperationsRequest as _google_longrunning_ListOperationsRequest, ListOperationsRequest__Output as _google_longrunning_ListOperationsRequest__Output } from '../../google/longrunning/ListOperationsRequest'; -import { ListOperationsResponse as _google_longrunning_ListOperationsResponse, ListOperationsResponse__Output as _google_longrunning_ListOperationsResponse__Output } from '../../google/longrunning/ListOperationsResponse'; -import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; -import { WaitOperationRequest as _google_longrunning_WaitOperationRequest, WaitOperationRequest__Output as _google_longrunning_WaitOperationRequest__Output } from '../../google/longrunning/WaitOperationRequest'; +import type { CancelOperationRequest as _google_longrunning_CancelOperationRequest, CancelOperationRequest__Output as _google_longrunning_CancelOperationRequest__Output } from '../../google/longrunning/CancelOperationRequest'; +import type { DeleteOperationRequest as _google_longrunning_DeleteOperationRequest, DeleteOperationRequest__Output as _google_longrunning_DeleteOperationRequest__Output } from '../../google/longrunning/DeleteOperationRequest'; +import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../google/protobuf/Empty'; +import type { GetOperationRequest as _google_longrunning_GetOperationRequest, GetOperationRequest__Output as _google_longrunning_GetOperationRequest__Output } from '../../google/longrunning/GetOperationRequest'; +import type { ListOperationsRequest as _google_longrunning_ListOperationsRequest, ListOperationsRequest__Output as _google_longrunning_ListOperationsRequest__Output } from '../../google/longrunning/ListOperationsRequest'; +import type { ListOperationsResponse as _google_longrunning_ListOperationsResponse, ListOperationsResponse__Output as _google_longrunning_ListOperationsResponse__Output } from '../../google/longrunning/ListOperationsResponse'; +import type { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; +import type { WaitOperationRequest as _google_longrunning_WaitOperationRequest, WaitOperationRequest__Output as _google_longrunning_WaitOperationRequest__Output } from '../../google/longrunning/WaitOperationRequest'; /** * Manages long-running operations with an API service. diff --git a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts index 865e180cf..2789ba33e 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../google/protobuf/Duration'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../google/protobuf/Duration'; /** * The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. diff --git a/packages/proto-loader/golden-generated/google/protobuf/Any.ts b/packages/proto-loader/golden-generated/google/protobuf/Any.ts index b592af4ba..fe0d05f12 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Any.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Any.ts @@ -1,6 +1,6 @@ // Original file: null -import { AnyExtension } from '@grpc/proto-loader'; +import type { AnyExtension } from '@grpc/proto-loader'; export type Any = AnyExtension | { type_url: string; diff --git a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts index 8ab286897..2f6f9f0cc 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts @@ -1,10 +1,10 @@ // Original file: null -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; +import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import type { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; +import type { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; export interface _google_protobuf_DescriptorProto_ExtensionRange { 'start'?: (number); diff --git a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts index 78610b80a..8595377a0 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface Duration { 'seconds'?: (number | string | Long); diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts index 1971fccb0..7aa40ce4d 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts @@ -1,7 +1,7 @@ // Original file: null -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; +import type { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; +import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; export interface EnumDescriptorProto { 'name'?: (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts index 56c8db7df..b92ade4f9 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface EnumOptions { 'allowAlias'?: (boolean); diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts index 919b7aa38..238e7fd01 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; +import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; export interface EnumValueDescriptorProto { 'name'?: (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts index 6bbd4951f..e60ee6f4c 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface EnumValueOptions { 'deprecated'?: (boolean); diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts index e0a1f4580..b59518c4b 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; +import type { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; // Original file: null diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts index ebed365b7..8304053f1 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts @@ -1,7 +1,7 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { FieldBehavior as _google_api_FieldBehavior } from '../../google/api/FieldBehavior'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { FieldBehavior as _google_api_FieldBehavior } from '../../google/api/FieldBehavior'; // Original file: null diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts index 65315a644..2954e4208 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts @@ -1,11 +1,11 @@ // Original file: null -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; +import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import type { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; +import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import type { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; +import type { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; export interface FileDescriptorProto { 'name'?: (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts index f01cabc4c..74ded2471 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts @@ -1,6 +1,6 @@ // Original file: null -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; +import type { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; export interface FileDescriptorSet { 'file'?: (_google_protobuf_FileDescriptorProto)[]; diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts index 5a1d270c5..573e847c0 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; // Original file: null diff --git a/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts index 40bf29272..31f669eb0 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface MessageOptions { 'messageSetWireFormat'?: (boolean); diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts index b62d45731..bc2f0afb5 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; +import type { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; export interface MethodDescriptorProto { 'name'?: (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts index 7a4943367..495e22514 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts @@ -1,8 +1,8 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { OperationInfo as _google_longrunning_OperationInfo, OperationInfo__Output as _google_longrunning_OperationInfo__Output } from '../../google/longrunning/OperationInfo'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { OperationInfo as _google_longrunning_OperationInfo, OperationInfo__Output as _google_longrunning_OperationInfo__Output } from '../../google/longrunning/OperationInfo'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface MethodOptions { 'deprecated'?: (boolean); diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts index 5d1512003..c10ccecd3 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; +import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; export interface OneofDescriptorProto { 'name'?: (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts index 02353a0a4..d81d34797 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface OneofOptions { 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts index fe5cab5b4..695a8775c 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts @@ -1,7 +1,7 @@ // Original file: null -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; +import type { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; +import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; export interface ServiceDescriptorProto { 'name'?: (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts index 7754279c5..c0522eca3 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface ServiceOptions { 'deprecated'?: (boolean); diff --git a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts index f8747e93e..ceaa32b5f 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface Timestamp { 'seconds'?: (number | string | Long); diff --git a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts index 91e3b99bc..433820f55 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface _google_protobuf_UninterpretedOption_NamePart { 'namePart'?: (string); diff --git a/packages/proto-loader/golden-generated/google/rpc/Status.ts b/packages/proto-loader/golden-generated/google/rpc/Status.ts index 7da370379..4ce45b6a9 100644 --- a/packages/proto-loader/golden-generated/google/rpc/Status.ts +++ b/packages/proto-loader/golden-generated/google/rpc/Status.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/rpc/status.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; /** * The `Status` type defines a logical error model that is suitable for diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts index 39cde368c..88c8010cd 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts @@ -1,8 +1,8 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; -import { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; /** * The request for Block method. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index eb4772a1d..230af7011 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -1,15 +1,15 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto import * as grpc from '@grpc/grpc-js' -import { BlockRequest as _google_showcase_v1beta1_BlockRequest, BlockRequest__Output as _google_showcase_v1beta1_BlockRequest__Output } from '../../../google/showcase/v1beta1/BlockRequest'; -import { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; -import { EchoRequest as _google_showcase_v1beta1_EchoRequest, EchoRequest__Output as _google_showcase_v1beta1_EchoRequest__Output } from '../../../google/showcase/v1beta1/EchoRequest'; -import { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; -import { ExpandRequest as _google_showcase_v1beta1_ExpandRequest, ExpandRequest__Output as _google_showcase_v1beta1_ExpandRequest__Output } from '../../../google/showcase/v1beta1/ExpandRequest'; -import { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../../google/longrunning/Operation'; -import { PagedExpandRequest as _google_showcase_v1beta1_PagedExpandRequest, PagedExpandRequest__Output as _google_showcase_v1beta1_PagedExpandRequest__Output } from '../../../google/showcase/v1beta1/PagedExpandRequest'; -import { PagedExpandResponse as _google_showcase_v1beta1_PagedExpandResponse, PagedExpandResponse__Output as _google_showcase_v1beta1_PagedExpandResponse__Output } from '../../../google/showcase/v1beta1/PagedExpandResponse'; -import { WaitRequest as _google_showcase_v1beta1_WaitRequest, WaitRequest__Output as _google_showcase_v1beta1_WaitRequest__Output } from '../../../google/showcase/v1beta1/WaitRequest'; +import type { BlockRequest as _google_showcase_v1beta1_BlockRequest, BlockRequest__Output as _google_showcase_v1beta1_BlockRequest__Output } from '../../../google/showcase/v1beta1/BlockRequest'; +import type { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; +import type { EchoRequest as _google_showcase_v1beta1_EchoRequest, EchoRequest__Output as _google_showcase_v1beta1_EchoRequest__Output } from '../../../google/showcase/v1beta1/EchoRequest'; +import type { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; +import type { ExpandRequest as _google_showcase_v1beta1_ExpandRequest, ExpandRequest__Output as _google_showcase_v1beta1_ExpandRequest__Output } from '../../../google/showcase/v1beta1/ExpandRequest'; +import type { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../../google/longrunning/Operation'; +import type { PagedExpandRequest as _google_showcase_v1beta1_PagedExpandRequest, PagedExpandRequest__Output as _google_showcase_v1beta1_PagedExpandRequest__Output } from '../../../google/showcase/v1beta1/PagedExpandRequest'; +import type { PagedExpandResponse as _google_showcase_v1beta1_PagedExpandResponse, PagedExpandResponse__Output as _google_showcase_v1beta1_PagedExpandResponse__Output } from '../../../google/showcase/v1beta1/PagedExpandResponse'; +import type { WaitRequest as _google_showcase_v1beta1_WaitRequest, WaitRequest__Output as _google_showcase_v1beta1_WaitRequest__Output } from '../../../google/showcase/v1beta1/WaitRequest'; /** * This service is used showcase the four main types of rpcs - unary, server diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts index c5060cdfd..0cf79d84f 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -1,7 +1,7 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; -import { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; /** * The request message used for the Echo, Collect and Chat methods. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts index 97028b22a..3fda238a1 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; +import type { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; /** * The response message for the Echo methods. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts index 8db54519d..00e7d05d2 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; /** * The request message for the Expand method. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts index 4c37e4401..823de43ed 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; +import type { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; /** * The response for the PagedExpand method. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts index 481d38412..38b0a083f 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; /** * The metadata for Wait operation. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts index fe6081203..eb2d2bc19 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts @@ -1,9 +1,9 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; -import { WaitResponse as _google_showcase_v1beta1_WaitResponse, WaitResponse__Output as _google_showcase_v1beta1_WaitResponse__Output } from '../../../google/showcase/v1beta1/WaitResponse'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { WaitResponse as _google_showcase_v1beta1_WaitResponse, WaitResponse__Output as _google_showcase_v1beta1_WaitResponse__Output } from '../../../google/showcase/v1beta1/WaitResponse'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; /** * The request for Wait method. diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index ac76bd54d..2b164f03a 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0", + "version": "0.6.0-pre15", "author": "Google Inc.", "contributors": [ { From f2c82cc8e50837198b74b27b2c589e6a6c69db76 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Oct 2020 14:36:50 -0700 Subject: [PATCH 1299/1899] Bump the version again to capture a merge --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 2b164f03a..02a1661ae 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre15", + "version": "0.6.0-pre16", "author": "Google Inc.", "contributors": [ { From 9699de5ec6e95e0ede257c3ad961a87963137543 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 09:59:23 -0700 Subject: [PATCH 1300/1899] Re-add grpc-js proto-loader dev dependency --- packages/grpc-js/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 87e10abfb..2f37f7fb9 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,6 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { + "@grpc/proto-loader": "../proto-loader", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", From fd406fbef120862a945dc6719a0fb89b61756140 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 10:27:03 -0700 Subject: [PATCH 1301/1899] Use a regular dependency for proto-loader --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 2f37f7fb9..e90193972 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,7 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "../proto-loader", + "@grpc/proto-loader": "^0.5.5", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", From 94391ca64df61b7ce06534d919673718b5754688 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 11:09:23 -0700 Subject: [PATCH 1302/1899] import type * as grpc, fix ConstructorParameters usage --- packages/proto-loader/bin/proto-loader-gen-types.ts | 6 +++--- packages/proto-loader/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 07b287fc1..54b1475c3 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -544,7 +544,7 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob formatter.writeLine(`// Original file: ${serviceType.filename}`); formatter.writeLine(''); const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; - formatter.writeLine(`import * as grpc from '${grpcImportPath}'`); + formatter.writeLine(`import type * as grpc from '${grpcImportPath}'`); const dependencies: Set = new Set(); for (const method of serviceType.methodsArray) { dependencies.add(method.resolvedRequestType!); @@ -597,14 +597,14 @@ function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Prot } function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { - formatter.writeLine(`import * as grpc from '${options.grpcLib}';`); + formatter.writeLine(`import type * as grpc from '${options.grpcLib}';`); formatter.writeLine("import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); formatter.writeLine(''); generateServiceImports(formatter, root, options); formatter.writeLine(''); - formatter.writeLine('type SubtypeConstructor = {'); + formatter.writeLine('type SubtypeConstructor any, Subtype> = {'); formatter.writeLine(' new(...args: ConstructorParameters): Subtype;'); formatter.writeLine('};'); formatter.writeLine(''); diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 02a1661ae..7947dcf0f 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre16", + "version": "0.6.0-pre17", "author": "Google Inc.", "contributors": [ { From 8c112adba0038ecc12837ecaa06fb330b3231bf3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 11:21:31 -0700 Subject: [PATCH 1303/1899] Borrow linux job for xds tests (DO NOT MERGE) --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..16a7dc7dc 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From 0a4219e0b853f689e06f8fc1c0aac076e4620a6a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 13:14:13 -0700 Subject: [PATCH 1304/1899] Fix a directory error in the xds script --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 79c3a17a9..bbfc30562 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -58,7 +58,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ - --client_cmd="$(which node) grpc-node/packages/grpc-js/build/interop/xds-interop-client \ + --client_cmd="$(which node) grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ From fba3a795c2b3af0e8a8eaed5f6cb4cd01a337732 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 14:22:51 -0700 Subject: [PATCH 1305/1899] Fix up grpc-js dependency --- packages/grpc-js-xds/package.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 5962d42a0..e22b40f5b 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -31,6 +31,7 @@ }, "homepage": "https://github.com/grpc/grpc-node#readme", "devDependencies": { + "@grpc/grpc-js": "file:../grpc-js", "gts": "^2.0.2", "typescript": "^3.8.3", "@types/gulp": "^4.0.6", @@ -41,7 +42,9 @@ "yargs": "^15.4.1" }, "dependencies": { - "@grpc/grpc-js": "file:../grpc-js", "@grpc/proto-loader": "^0.6.0-pre14" + }, + "peerDependencies": { + "@grpc/grpc-js": "~1.2.0" } } From 261c40e51b3ab7834930f138d25a1c8e2364370b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Oct 2020 14:22:59 -0700 Subject: [PATCH 1306/1899] Revert "Borrow linux job for xds tests (DO NOT MERGE)" This reverts commit 8c112adba0038ecc12837ecaa06fb330b3231bf3. --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 16a7dc7dc..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } From f312326e9cd71f5bca2f19136b31af9177f1fa9f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 23 Oct 2020 10:15:56 -0700 Subject: [PATCH 1307/1899] Set the default port of 80 explicitly in http_proxy --- packages/grpc-js/src/http_proxy.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 84e29a50f..f6921378b 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -84,8 +84,16 @@ function getProxyInfo(): ProxyInfo { userCred = proxyUrl.username; } } + const hostname = proxyUrl.hostname; + let port = proxyUrl.port; + /* The proxy URL uses the scheme "http:", which has a default port number of + * 80. We need to set that explicitly here if it is omitted because otherwise + * it will use gRPC's default port 443. */ + if (port === '') { + port = '80'; + } const result: ProxyInfo = { - address: proxyUrl.host, + address: `${hostname}:${port}` }; if (userCred) { result.creds = userCred; From dc80dc1f17a885e9449f2d968d4f44a013ee84fc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 23 Oct 2020 14:57:18 -0700 Subject: [PATCH 1308/1899] Add a simple test for the xds package to the test job --- gulpfile.ts | 11 +-- packages/grpc-js-xds/gulpfile.ts | 78 ++++++++++++++++++++++ packages/grpc-js-xds/package.json | 3 + packages/grpc-js-xds/src/index.ts | 3 + packages/grpc-js-xds/test/test-register.ts | 27 ++++++++ packages/grpc-js-xds/tsconfig.json | 1 + 6 files changed, 118 insertions(+), 5 deletions(-) create mode 100644 packages/grpc-js-xds/gulpfile.ts create mode 100644 packages/grpc-js-xds/test/test-register.ts diff --git a/gulpfile.ts b/gulpfile.ts index 367b4d1ba..a09931a18 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -18,28 +18,29 @@ import * as gulp from 'gulp'; import * as healthCheck from './packages/grpc-health-check/gulpfile'; import * as jsCore from './packages/grpc-js/gulpfile'; +import * as jsXds from './packages/grpc-js-xds/gulpfile'; import * as protobuf from './packages/proto-loader/gulpfile'; import * as internalTest from './test/gulpfile'; -const installAll = gulp.series(jsCore.install, healthCheck.install, protobuf.install, internalTest.install); +const installAll = gulp.series(jsCore.install, healthCheck.install, protobuf.install, internalTest.install, jsXds.install); const lint = gulp.parallel(jsCore.lint); -const build = gulp.series(jsCore.compile, protobuf.compile); +const build = gulp.series(jsCore.compile, protobuf.compile, jsXds.compile); const setup = gulp.series(installAll); const setupPureJSInterop = gulp.series(jsCore.install, protobuf.install, internalTest.install); -const clean = gulp.series(jsCore.clean, protobuf.clean); +const clean = gulp.series(jsCore.clean, protobuf.clean, jsXds.clean); -const cleanAll = gulp.series(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll); +const cleanAll = gulp.series(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll, jsXds.cleanAll); const nativeTestOnly = gulp.parallel(healthCheck.test); const nativeTest = gulp.series(build, nativeTestOnly); -const testOnly = gulp.parallel(jsCore.test, nativeTestOnly, protobuf.test); +const testOnly = gulp.parallel(jsCore.test, nativeTestOnly, protobuf.test, jsXds.test); const test = gulp.series(build, testOnly, internalTest.test); diff --git a/packages/grpc-js-xds/gulpfile.ts b/packages/grpc-js-xds/gulpfile.ts new file mode 100644 index 000000000..4ee6ac2c5 --- /dev/null +++ b/packages/grpc-js-xds/gulpfile.ts @@ -0,0 +1,78 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as gulp from 'gulp'; + +import * as mocha from 'gulp-mocha'; +import * as path from 'path'; +import * as execa from 'execa'; +import * as semver from 'semver'; + +Error.stackTraceLimit = Infinity; + +const jsCoreDir = __dirname; +const outDir = path.resolve(jsCoreDir, 'build'); + +const pkgPath = path.resolve(jsCoreDir, 'package.json'); +const supportedVersionRange = require(pkgPath).engines.node; +const versionNotSupported = () => { + console.log(`Skipping grpc-js-xds task for Node ${process.version}`); + return () => { return Promise.resolve(); }; +}; +const identity = (value: any): any => value; +const checkTask = semver.satisfies(process.version, supportedVersionRange) ? + identity : versionNotSupported; + +const execNpmVerb = (verb: string, ...args: string[]) => + execa('npm', [verb, ...args], {cwd: jsCoreDir, stdio: 'inherit'}); +const execNpmCommand = execNpmVerb.bind(null, 'run'); + +const install = checkTask(() => execNpmVerb('install', '--unsafe-perm')); + +/** + * Runs tslint on files in src/, with linting rules defined in tslint.json. + */ +const lint = checkTask(() => execNpmCommand('check')); + +const cleanFiles = checkTask(() => execNpmCommand('clean')); + +const clean = gulp.series(install, cleanFiles); + +const cleanAll = gulp.parallel(clean); + +/** + * Transpiles TypeScript files in src/ to JavaScript according to the settings + * found in tsconfig.json. + */ +const compile = checkTask(() => execNpmCommand('compile')); + +const runTests = checkTask(() => { + return gulp.src(`${outDir}/test/**/*.js`) + .pipe(mocha({reporter: 'mocha-jenkins-reporter', + require: ['ts-node/register']})); +}); + +const test = gulp.series(install, runTests); + +export { + install, + lint, + clean, + cleanAll, + compile, + test +} diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index e22b40f5b..78d90c1d0 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -46,5 +46,8 @@ }, "peerDependencies": { "@grpc/grpc-js": "~1.2.0" + }, + "engines": { + "node": ">=10.10.0" } } diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 5aea005d6..06bea9904 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -22,6 +22,9 @@ import * as load_balancer_lrs from './load-balancer-lrs'; import * as load_balancer_priority from './load-balancer-priority'; import * as load_balancer_weighted_target from './load-balancer-weighted-target'; +/** + * Register the "xds:" name scheme with the @grpc/grpc-js library. + */ export function register() { resolver_xds.setup(); load_balancer_cds.setup(); diff --git a/packages/grpc-js-xds/test/test-register.ts b/packages/grpc-js-xds/test/test-register.ts new file mode 100644 index 000000000..e7a07927a --- /dev/null +++ b/packages/grpc-js-xds/test/test-register.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import { register } from '../src'; + +/* This is just a basic test to confirm that the package builds and the setup + * code runs. */ +describe('register function', () => { + it('Should succeed without errors', () => { + assert.doesNotThrow(register); + }); +}); \ No newline at end of file diff --git a/packages/grpc-js-xds/tsconfig.json b/packages/grpc-js-xds/tsconfig.json index 3148d112e..c121a5f6d 100644 --- a/packages/grpc-js-xds/tsconfig.json +++ b/packages/grpc-js-xds/tsconfig.json @@ -10,6 +10,7 @@ }, "include": [ "src/**/*.ts", + "test/**/*.ts", "interop/**/*.ts" ] } From e4b69a8ee1307be15492401f6a567bb24a07368a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 28 Oct 2020 13:27:44 -0700 Subject: [PATCH 1309/1899] grpc-js: Add support for grpc.max_reconnect_backoff_ms channel arg --- PACKAGE-COMPARISON.md | 1 + packages/grpc-js/src/channel-options.ts | 2 ++ packages/grpc-js/src/subchannel.ts | 20 ++++++++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index 8bea1fd08..fa0ea319e 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -36,6 +36,7 @@ In addition, all channel arguments defined in [this header file](https://github. - `grpc.default_authority` - `grpc.keepalive_time_ms` - `grpc.keepalive_timeout_ms` + - `grpc.keepalive_permit_without_calls` - `grpc.service_config` - `grpc.max_concurrent_streams` - `grpc.initial_reconnect_backoff_ms` diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index f316a58a0..df6cbb2b1 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -25,6 +25,7 @@ export interface ChannelOptions { 'grpc.default_authority'?: string; 'grpc.keepalive_time_ms'?: number; 'grpc.keepalive_timeout_ms'?: number; + 'grpc.keepalive_permit_without_calls'?: number; 'grpc.service_config'?: string; 'grpc.max_concurrent_streams'?: number; 'grpc.initial_reconnect_backoff_ms'?: number; @@ -49,6 +50,7 @@ export const recognizedOptions = { 'grpc.default_authority': true, 'grpc.keepalive_time_ms': true, 'grpc.keepalive_timeout_ms': true, + 'grpc.keepalive_permit_without_calls': true, 'grpc.service_config': true, 'grpc.max_concurrent_streams': true, 'grpc.initial_reconnect_backoff_ms': true, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index b9535769e..3c6071446 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -180,6 +180,10 @@ export class Subchannel { * Timer reference tracking when the most recent ping will be considered lost */ private keepaliveTimeoutId: NodeJS.Timer; + /** + * Indicates whether keepalive pings should be sent without any active calls + */ + private keepaliveWithoutCalls: boolean = false; /** * Tracks calls with references to this subchannel @@ -226,6 +230,11 @@ export class Subchannel { if ('grpc.keepalive_timeout_ms' in options) { this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; } + if ('grpc.keepalive_permit_without_calls' in options) { + this.keepaliveWithoutCalls = options['grpc.keepalive_permit_without_calls'] === 1; + } else { + this.keepaliveWithoutCalls = false; + } this.keepaliveIntervalId = setTimeout(() => {}, 0); clearTimeout(this.keepaliveIntervalId); this.keepaliveTimeoutId = setTimeout(() => {}, 0); @@ -532,6 +541,9 @@ export class Subchannel { listener(); } }); + if (this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } break; case ConnectivityState.CONNECTING: this.startBackoff(); @@ -602,7 +614,9 @@ export class Subchannel { if (this.session) { this.session.ref(); } - this.startKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } } this.callRefcount += 1; } @@ -620,7 +634,9 @@ export class Subchannel { if (this.session) { this.session.unref(); } - this.stopKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.stopKeepalivePings(); + } this.checkBothRefcounts(); } } From e49524a2ba1c37b72635eeff08fcfd6be47cf518 Mon Sep 17 00:00:00 2001 From: Daniel Shmuglin Date: Thu, 29 Oct 2020 10:24:31 +0200 Subject: [PATCH 1310/1899] Server#addService - lift the limitation of adding a new service to started server --- packages/grpc-js/src/server.ts | 6 +----- packages/grpc-js/test/test-server.ts | 6 +++--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 5ac25c7ce..c0ced6f7a 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -148,10 +148,6 @@ export class Server { service: ServiceDefinition, implementation: UntypedServiceImplementation ): void { - if (this.started === true) { - throw new Error("Can't add a service to a started server."); - } - if ( service === null || typeof service !== 'object' || @@ -637,7 +633,7 @@ async function handleUnary( if (request === undefined || call.cancelled) { return; } - + const emitter = new ServerUnaryCallImpl( call, metadata, diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 434efbbc4..eb531c964 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -202,7 +202,7 @@ describe('Server', () => { }); }); - it('fails if the server has been started', done => { + it('succeeds after server has been started', done => { const server = new Server(); server.bindAsync( @@ -211,9 +211,9 @@ describe('Server', () => { (err, port) => { assert.ifError(err); server.start(); - assert.throws(() => { + assert.doesNotThrow(() => { server.addService(mathServiceAttrs, dummyImpls); - }, /Can't add a service to a started server\./); + }); server.tryShutdown(done); } ); From 7c3ccda8fff80fe2677ca27ebf4ed7499bd58731 Mon Sep 17 00:00:00 2001 From: Daniel Shmuglin Date: Thu, 29 Oct 2020 10:54:33 +0200 Subject: [PATCH 1311/1899] implement Server#unregister(handlerName) --- packages/grpc-js/src/server.ts | 4 ++ packages/grpc-js/test/test-server.ts | 55 ++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index c0ced6f7a..341b28bd8 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -458,6 +458,10 @@ export class Server { return true; } + unregister(name: string): boolean { + return this.handlers.delete(name); + } + start(): void { if ( this.http2ServerList.length === 0 || diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index eb531c964..6a95b5cf4 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -220,6 +220,61 @@ describe('Server', () => { }); }); + describe('unregister', () => { + + let server: Server; + let client: ServiceClient; + + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + const mathServiceAttrs = mathClient.service; + + beforeEach(done => { + server = new Server(); + server.addService(mathServiceAttrs, { + div(call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, {quotient: '42'}); + }, + }); + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); + }); + + afterEach(done => { + client.close(); + server.tryShutdown(done); + }); + + it('removes handler by name and returns true', done => { + const name = mathServiceAttrs['Div'].path; + assert.strictEqual(server.unregister(name), true, 'Server#unregister should return true on success'); + + client.div( + { divisor: 4, dividend: 3 }, + (error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + done(); + } + ); + }); + + it('returns false for unknown handler', () => { + assert.strictEqual(server.unregister('noOneHere'), false, 'Server#unregister should return false on failure'); + }); + }); + it('throws when unimplemented methods are called', () => { const server = new Server(); From 51ca00298e95f67727c9e10549e0500629f17987 Mon Sep 17 00:00:00 2001 From: Daniel Shmuglin Date: Thu, 29 Oct 2020 11:33:29 +0200 Subject: [PATCH 1312/1899] implement Server#unregisterService(serviceDefinition) --- packages/grpc-js/src/server.ts | 15 +++++++ packages/grpc-js/test/test-server.ts | 61 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 341b28bd8..28599160c 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -208,6 +208,21 @@ export class Server { }); } + removeService(service: ServiceDefinition): void { + if ( + service === null || + typeof service !== 'object' + ) { + throw new Error('removeService() requires object as argument'); + } + + const serviceKeys = Object.keys(service); + serviceKeys.forEach((name) => { + const attrs = service[name]; + this.unregister(attrs.path); + }); + } + bind(port: string, creds: ServerCredentials): void { throw new Error('Not implemented. Use bindAsync() instead'); } diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 6a95b5cf4..58b102883 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -220,6 +220,67 @@ describe('Server', () => { }); }); + describe('removeService', () => { + let server: Server; + let client: ServiceClient; + + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + const mathServiceAttrs = mathClient.service; + const dummyImpls = { div() {}, divMany() {}, fib() {}, sum() {} }; + + beforeEach(done => { + server = new Server(); + server.addService(mathServiceAttrs, dummyImpls); + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); + }); + + afterEach(done => { + client.close(); + server.tryShutdown(done); + }); + + it('succeeds with a single service by removing all method handlers', done => { + server.removeService(mathServiceAttrs); + + let methodsVerifiedCount = 0; + const methodsToVerify = Object.keys(mathServiceAttrs); + + const assertFailsWithUnimplementedError = (error: ServiceError) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + methodsVerifiedCount++; + if (methodsVerifiedCount === methodsToVerify.length) { + done(); + } + }; + + methodsToVerify.forEach((method) => { + const call = client[method]({}, assertFailsWithUnimplementedError); // for unary + call.on('error', assertFailsWithUnimplementedError); // for streamed + }); + }); + + it('fails for non-object service definition argument', () => { + assert.throws(() => { + server.removeService('upsie' as any) + }, /removeService.*requires object as argument/ + ); + }); + }); + describe('unregister', () => { let server: Server; From ae2b64bd659a74adcca0c48d1cefc6aa252795cf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 30 Oct 2020 11:38:30 -0700 Subject: [PATCH 1313/1899] grpc-js: Implement deadline and cancellation propagation --- packages/grpc-js/src/call-stream.ts | 16 +- packages/grpc-js/src/channel.ts | 14 +- packages/grpc-js/src/client-interceptors.ts | 20 +- packages/grpc-js/src/constants.ts | 3 +- packages/grpc-js/src/server-call.ts | 34 ++- .../grpc-js/test/test-call-propagation.ts | 253 ++++++++++++++++++ 6 files changed, 310 insertions(+), 30 deletions(-) create mode 100644 packages/grpc-js/test/test-call-propagation.ts diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index fd50a8076..32b851654 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -18,7 +18,7 @@ import * as http2 from 'http2'; import { CallCredentials } from './call-credentials'; -import { Status } from './constants'; +import { Propagate, Status } from './constants'; import { Filter, FilterFactory } from './filter'; import { FilterStackFactory, FilterStack } from './filter-stack'; import { Metadata } from './metadata'; @@ -27,6 +27,7 @@ import { ChannelImplementation } from './channel'; import { Subchannel } from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { ServerSurfaceCall } from './server-call'; const TRACER_NAME = 'call_stream'; @@ -42,7 +43,7 @@ export interface CallStreamOptions { deadline: Deadline; flags: number; host: string; - parentCall: Call | null; + parentCall: ServerSurfaceCall | null; } export type PartialCallStreamOptions = Partial; @@ -218,6 +219,11 @@ export class Http2CallStream implements Call { metadata: new Metadata(), }); }; + if (this.options.parentCall && this.options.flags & Propagate.CANCELLATION) { + this.options.parentCall.on('cancelled', () => { + this.cancelWithStatus(Status.CANCELLED, 'Cancelled by parent call'); + }); + } } private outputStatus() { @@ -623,7 +629,11 @@ export class Http2CallStream implements Call { } getDeadline(): Deadline { - return this.options.deadline; + if (this.options.parentCall && this.options.flags & Propagate.DEADLINE) { + return this.options.parentCall.getDeadline(); + } else { + return this.options.deadline; + } } getCredentials(): CallCredentials { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index dcfae483d..05588c497 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -28,7 +28,7 @@ import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; import { ChannelControlHelper } from './load-balancer'; import { UnavailablePicker, Picker, PickResultType } from './picker'; import { Metadata } from './metadata'; -import { Status, LogVerbosity } from './constants'; +import { Status, LogVerbosity, Propagate } from './constants'; import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; @@ -39,6 +39,8 @@ import { SubchannelAddress } from './subchannel'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; +import { ServerSurfaceCall } from './server-call'; +import { SurfaceCall } from './call'; export enum ConnectivityState { CONNECTING, @@ -118,7 +120,7 @@ export interface Channel { method: string, deadline: Deadline, host: string | null | undefined, - parentCall: any, // eslint-disable-line @typescript-eslint/no-explicit-any + parentCall: ServerSurfaceCall | null, propagateFlags: number | null | undefined ): Call; } @@ -509,7 +511,7 @@ export class ChannelImplementation implements Channel { method: string, deadline: Deadline, host: string | null | undefined, - parentCall: any, // eslint-disable-line @typescript-eslint/no-explicit-any + parentCall: ServerSurfaceCall | null, propagateFlags: number | null | undefined ): Call { if (typeof method !== 'string') { @@ -537,9 +539,9 @@ export class ChannelImplementation implements Channel { ); const finalOptions: CallStreamOptions = { deadline: deadline, - flags: propagateFlags || 0, - host: host || this.defaultAuthority, - parentCall: parentCall || null, + flags: propagateFlags ?? Propagate.DEFAULTS, + host: host ?? this.defaultAuthority, + parentCall: parentCall, }; const stream: Http2CallStream = new Http2CallStream( method, diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index fe36ea36d..09e7f5aa5 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -311,21 +311,11 @@ export class InterceptingCall implements InterceptingCallInterface { } function getCall(channel: Channel, path: string, options: CallOptions): Call { - let deadline; - let host; - const parent = null; - let propagateFlags; - let credentials; - if (options) { - deadline = options.deadline; - host = options.host; - - propagateFlags = options.propagate_flags; - credentials = options.credentials; - } - if (deadline === undefined) { - deadline = Infinity; - } + const deadline = options.deadline ?? Infinity; + const host = options.host; + const parent = options.parent ?? null; + const propagateFlags = options.propagate_flags; + const credentials = options.credentials; const call = channel.createCall(path, deadline, host, parent, propagateFlags); if (credentials) { call.setCredentials(credentials); diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index e760658d0..d30b78f08 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -50,7 +50,8 @@ export enum Propagate { CENSUS_STATS_CONTEXT = 2, CENSUS_TRACING_CONTEXT = 4, CANCELLATION = 8, - DEFAULTS = 65536, + // https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/propagation_bits.h#L43 + DEFAULTS = 0xffff | Propagate.DEADLINE | Propagate.CENSUS_STATS_CONTEXT | Propagate.CENSUS_TRACING_CONTEXT | Propagate.CANCELLATION, } // -1 means unlimited diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 2c62b206d..aa8bd647e 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -19,7 +19,7 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; -import { StatusObject } from './call-stream'; +import { Deadline, StatusObject } from './call-stream'; import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, @@ -78,6 +78,7 @@ export type ServerSurfaceCall = { readonly metadata: Metadata; getPeer(): string; sendMetadata(responseMetadata: Metadata): void; + getDeadline(): Deadline; } & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { @@ -120,6 +121,10 @@ export class ServerUnaryCallImpl extends EventEmitter sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } } export class ServerReadableStreamImpl @@ -153,6 +158,10 @@ export class ServerReadableStreamImpl sendMetadata(responseMetadata: Metadata): void { this.call.sendMetadata(responseMetadata); } + + getDeadline(): Deadline { + return this.call.getDeadline(); + } } export class ServerWritableStreamImpl @@ -186,6 +195,10 @@ export class ServerWritableStreamImpl this.call.sendMetadata(responseMetadata); } + getDeadline(): Deadline { + return this.call.getDeadline(); + } + _write( chunk: ResponseType, encoding: string, @@ -257,6 +270,10 @@ export class ServerDuplexStreamImpl extends Duplex this.call.sendMetadata(responseMetadata); } + getDeadline(): Deadline { + return this.call.getDeadline(); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any end(metadata?: any) { if (metadata) { @@ -357,7 +374,8 @@ export class Http2ServerCallStream< ResponseType > extends EventEmitter { cancelled = false; - deadline: NodeJS.Timer = setTimeout(() => {}, 0); + deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + private deadline: Deadline = Infinity; private wantTrailers = false; private metadataSent = false; private canPush = false; @@ -405,7 +423,7 @@ export class Http2ServerCallStream< } // Clear noop timer - clearTimeout(this.deadline); + clearTimeout(this.deadlineTimer); } private checkCancelled(): boolean { @@ -452,7 +470,9 @@ export class Http2ServerCallStream< const timeout = (+match[1] * deadlineUnitsToMs[match[2]]) | 0; - this.deadline = setTimeout(handleExpiredDeadline, timeout, this); + const now = new Date(); + this.deadline = now.setMilliseconds(now.getMilliseconds() + timeout); + this.deadlineTimer = setTimeout(handleExpiredDeadline, timeout, this); metadata.remove(GRPC_TIMEOUT_HEADER); } @@ -566,7 +586,7 @@ export class Http2ServerCallStream< statusObj.details ); - clearTimeout(this.deadline); + clearTimeout(this.deadlineTimer); if (!this.wantTrailers) { this.wantTrailers = true; @@ -779,6 +799,10 @@ export class Http2ServerCallStream< return 'unknown'; } } + + getDeadline(): Deadline { + return this.deadline; + } } /* eslint-disable @typescript-eslint/no-explicit-any */ diff --git a/packages/grpc-js/test/test-call-propagation.ts b/packages/grpc-js/test/test-call-propagation.ts new file mode 100644 index 000000000..3ce57be17 --- /dev/null +++ b/packages/grpc-js/test/test-call-propagation.ts @@ -0,0 +1,253 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; + +import * as grpc from '../src'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; + +import { loadProtoFile } from './common'; + +function multiDone(done: () => void, target: number) { + let count = 0; + return () => { + count++; + if (count >= target) { + done(); + } + } +} + +describe('Call propagation', () => { + let server: grpc.Server; + let Client: ServiceClientConstructor; + let client: ServiceClient; + let proxyServer: grpc.Server; + let proxyClient: ServiceClient; + + before((done) => { + Client = loadProtoFile(__dirname + '/fixtures/test_service.proto').TestService as ServiceClientConstructor; + server = new grpc.Server(); + server.addService(Client.service, { + unary: () => {}, + clientStream: () => {}, + serverStream: () => {}, + bidiStream: () => {} + }); + proxyServer = new grpc.Server(); + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + done(error); + return; + } + server.start(); + client = new Client(`localhost:${port}`, grpc.credentials.createInsecure()); + proxyServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, proxyPort) => { + if (error) { + done(error); + return; + } + proxyServer.start(); + proxyClient = new Client(`localhost:${proxyPort}`, grpc.credentials.createInsecure()); + done(); + }); + }); + }); + afterEach(() => { + proxyServer.removeService(Client.service); + }); + after(() => { + server.forceShutdown(); + proxyServer.forceShutdown(); + }); + describe('Cancellation', () => { + it('should work with unary requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientUnaryCall; + proxyServer.addService(Client.service, { + unary: (parent: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + client.unary(parent.request, {parent: parent}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + /* Cancel the original call after the server starts processing it to + * ensure that it does reach the server. */ + call.cancel(); + } + }); + call = proxyClient.unary({}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + }); + it('Should work with client streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientWritableStream; + proxyServer.addService(Client.service, { + clientStream: (parent: grpc.ServerReadableStream, callback: grpc.sendUnaryData) => { + client.clientStream({parent: parent}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + /* Cancel the original call after the server starts processing it to + * ensure that it does reach the server. */ + call.cancel(); + } + }); + call = proxyClient.clientStream((error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.CANCELLED); + done(); + }); + }); + it('Should work with server streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientReadableStream; + proxyServer.addService(Client.service, { + serverStream: (parent: grpc.ServerWritableStream) => { + const child = client.serverStream(parent.request, {parent: parent}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + } + }); + call = proxyClient.serverStream({}); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + }); + it('Should work with bidi streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientDuplexStream; + proxyServer.addService(Client.service, { + bidiStream: (parent: grpc.ServerDuplexStream) => { + const child = client.bidiStream({parent: parent}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + call.cancel(); + } + }); + call = proxyClient.bidiStream(); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.CANCELLED); + done(); + }); + }); + }); + describe('Deadlines', () => { + it('should work with unary requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientUnaryCall; + proxyServer.addService(Client.service, { + unary: (parent: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + client.unary(parent.request, {parent: parent, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.unary({}, {deadline}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + it('Should work with client streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientWritableStream; + proxyServer.addService(Client.service, { + clientStream: (parent: grpc.ServerReadableStream, callback: grpc.sendUnaryData) => { + client.clientStream({parent: parent, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + callback(error, value); + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.clientStream({deadline, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + it('Should work with server streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientReadableStream; + proxyServer.addService(Client.service, { + serverStream: (parent: grpc.ServerWritableStream) => { + const child = client.serverStream(parent.request, {parent: parent, propagate_flags: grpc.propagate.DEADLINE}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.serverStream({}, {deadline}); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + it('Should work with bidi streaming requests', (done) => { + done = multiDone(done, 2); + let call: grpc.ClientDuplexStream; + proxyServer.addService(Client.service, { + bidiStream: (parent: grpc.ServerDuplexStream) => { + const child = client.bidiStream({parent: parent, propagate_flags: grpc.propagate.DEADLINE}); + child.on('error', () => {}); + child.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + } + }); + const deadline = new Date(); + deadline.setMilliseconds(deadline.getMilliseconds() + 100); + call = proxyClient.bidiStream({deadline}); + call.on('error', () => {}); + call.on('status', (status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + }); +}); \ No newline at end of file From 62e5038fcccd1c2749ab29e82b33a9093750f967 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Nov 2020 10:10:07 -0800 Subject: [PATCH 1314/1899] Reorder gulp cleanup step to avoid breakages --- gulpfile.ts | 2 +- packages/grpc-js-xds/src/load-balancer-priority.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gulpfile.ts b/gulpfile.ts index a09931a18..7ac4e9a0b 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -34,7 +34,7 @@ const setupPureJSInterop = gulp.series(jsCore.install, protobuf.install, interna const clean = gulp.series(jsCore.clean, protobuf.clean, jsXds.clean); -const cleanAll = gulp.series(jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll, jsXds.cleanAll); +const cleanAll = gulp.series(jsXds.cleanAll, jsCore.cleanAll, internalTest.cleanAll, protobuf.cleanAll); const nativeTestOnly = gulp.parallel(healthCheck.test); diff --git a/packages/grpc-js-xds/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts index 17c048123..872ed7d1b 100644 --- a/packages/grpc-js-xds/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -16,7 +16,7 @@ */ import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, ChannelOptions } from '@grpc/grpc-js'; -import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig; import LoadBalancer = experimental.LoadBalancer; import ChannelControlHelper = experimental.ChannelControlHelper; import getFirstUsableConfig = experimental.getFirstUsableConfig; From b31fc293da4bd04e21622acfbdd962a4d4ab67f8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 5 Nov 2020 13:08:50 -0800 Subject: [PATCH 1315/1899] Skip non-working test, test JS-JS interop first --- test/api/interop_extra_test.js | 5 ++++- test/gulpfile.ts | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index c7411c178..ab686e14f 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -170,7 +170,10 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio assert.ifError(error); }); }); - it('should be able to send very large headers and trailers', function(done) { + /* The test against the JS server does not work because of + * https://github.com/nodejs/node/issues/35218. The test against the native + * server fails because of an unidentified timeout issue. */ + it.skip('should be able to send very large headers and trailers', function(done) { done = multiDone(done, 3); const header = 'X'.repeat(64 * 1024); const trailer = Buffer.from('Y'.repeat(64 * 1024)); diff --git a/test/gulpfile.ts b/test/gulpfile.ts index 05976c173..2024f02cb 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -52,9 +52,9 @@ const testNativeClientJsServer = runTestsWithFixture('js', 'native'); const testJsClientJsServer = runTestsWithFixture('js', 'js'); const test = gulp.series( + testJsClientJsServer, testJsClientNativeServer, - testNativeClientJsServer, - testJsClientJsServer + testNativeClientJsServer ); export { From cd2713f42a743cc3c48ffa9519b8c53a90671dea Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 9 Nov 2020 10:45:57 -0800 Subject: [PATCH 1316/1899] grpc-js: Rearrange connectivity state enum to match the native library --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index dcfae483d..5f49c7647 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -41,10 +41,10 @@ import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; export enum ConnectivityState { + IDLE, CONNECTING, READY, TRANSIENT_FAILURE, - IDLE, SHUTDOWN, } From adfd4db9eaf4fc498067054179ba9fddf167a5e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 9 Nov 2020 10:53:44 -0800 Subject: [PATCH 1317/1899] grpc-js: Update to 1.2.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e90193972..0e445377c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.1.7", + "version": "1.2.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 8bacb12d23506837e75ce21793cc667f286fe4f8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 13 Nov 2020 14:54:38 -0800 Subject: [PATCH 1318/1899] grpc-js-xds: Reset LRS backoff on data, not metadata --- packages/grpc-js-xds/src/xds-client.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 525db7691..da75dc7c7 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -1018,13 +1018,11 @@ export class XdsClient { this.lrsBackoff.runOnce(); this.lrsCall = this.lrsClient.streamLoadStats(); - this.lrsCall.on('metadata', () => { + this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { /* Once we get any response from the server, we assume that the stream is * in a good state, so we can reset the backoff timer. */ this.lrsBackoff.stop(); this.lrsBackoff.reset(); - }); - this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { if ( message.load_reporting_interval?.seconds !== this.latestLrsSettings?.load_reporting_interval?.seconds || From ccb85ba470e9b244d23a36fc5d5e447e467e4d3e Mon Sep 17 00:00:00 2001 From: Masaki Hara Date: Wed, 18 Nov 2020 16:01:08 +0900 Subject: [PATCH 1319/1899] Bump protobuf dep to v3.14.0 --- packages/grpc-tools/deps/protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index d0bfd5221..2514f0bd7 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit d0bfd5221182da1a7cc280f3337b5e41a89539cf +Subproject commit 2514f0bd7da7e2af1bed4c5d1b84f031c4d12c10 From c981d2cec351f043497a6ee3358897172f0b2360 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 18 Nov 2020 11:25:02 -0800 Subject: [PATCH 1320/1899] grpc-tools: Bump version to 1.10.0 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 7dddbff0f..86f45dc31 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.9.1", + "version": "1.10.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From c050f97534b3332fc0a4818e20415cdffaaaf60e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 18 Nov 2020 13:08:06 -0800 Subject: [PATCH 1321/1899] grpc-js: Make calls use the min of parent and own deadline when both are provided --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0e445377c..22142dcdd 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.0", + "version": "1.2.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 32b851654..91e24ea55 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -630,7 +630,11 @@ export class Http2CallStream implements Call { getDeadline(): Deadline { if (this.options.parentCall && this.options.flags & Propagate.DEADLINE) { - return this.options.parentCall.getDeadline(); + const parentDeadline = this.options.parentCall.getDeadline(); + const selfDeadline = this.options.deadline; + const parentDeadlineMsecs = parentDeadline instanceof Date ? parentDeadline.getTime() : parentDeadline; + const selfDeadlineMsecs = selfDeadline instanceof Date ? selfDeadline.getTime() : selfDeadline; + return Math.min(parentDeadlineMsecs, selfDeadlineMsecs); } else { return this.options.deadline; } From 08254e4d2e552abff4893098466ae2cf2ab919ed Mon Sep 17 00:00:00 2001 From: "A. Tate Barber" Date: Sun, 22 Nov 2020 17:29:14 -0600 Subject: [PATCH 1322/1899] Add functions for loading and parsing binary-encoded file decriptor sets Fixes #1627 --- packages/proto-loader/src/index.ts | 43 +++++++++++++++++++ .../proto-loader/test/descriptor_type_test.ts | 5 +++ packages/proto-loader/test_protos/rpc.desc | 11 +++++ packages/proto-loader/test_protos/rpc.proto | 13 ++++++ 4 files changed, 72 insertions(+) create mode 100644 packages/proto-loader/test_protos/rpc.desc create mode 100644 packages/proto-loader/test_protos/rpc.proto diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index ffef89d30..c2f203c4d 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -30,6 +30,17 @@ declare module 'protobufjs' { descriptor.IDescriptorProto; } + interface RootConstructor { + new (options?: Options): Root; + fromDescriptor( + descriptorSet: + | descriptor.IFileDescriptorSet + | Protobuf.Reader + | Uint8Array + ): Root; + fromJSON(json: Protobuf.INamespace, root?: Root): Root; + } + interface Root { toDescriptor( protoVersion: string @@ -368,6 +379,38 @@ export function loadSync( return createPackageDefinition(root, options!); } +export async function loadFileDescriptorSet( + descriptorSet: Protobuf.Message & + descriptor.IFileDescriptorSet, + options?: Options +): Promise { + options = options || {}; + const root = (Protobuf.Root as Protobuf.RootConstructor).fromDescriptor( + descriptorSet + ); + root.resolveAll(); + return createPackageDefinition(root, options); +} + +export function loadFileDescriptorSetFile( + filename: string, + options?: Options +): Promise { + return new Promise((resolve, reject) => { + fs.readFile(filename, (err, data) => { + if (err) { + return reject(err); + } + + const descriptorSet = descriptor.FileDescriptorSet.decode( + data + ) as Protobuf.Message & + descriptor.IFileDescriptorSet; + return resolve(loadFileDescriptorSet(descriptorSet, options)); + }); + }); +} + // Load Google's well-known proto files that aren't exposed by Protobuf.js. // Protobuf.js exposes: any, duration, empty, field_mask, struct, timestamp, diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 348c5c8e8..57eb9ab0f 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -99,4 +99,9 @@ describe('Descriptor types', () => { // This will throw if the well known protos are not available. proto_loader.loadSync(`${TEST_PROTO_DIR}/well_known.proto`); }); + + it('Can load binary-encoded proto file descriptor sets', () => { + // This will throw if the well known protos are not available. + proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc`); + }); }); diff --git a/packages/proto-loader/test_protos/rpc.desc b/packages/proto-loader/test_protos/rpc.desc new file mode 100644 index 000000000..9c6f12611 --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.desc @@ -0,0 +1,11 @@ + +˜ +test_protos/rpc.proto" + MyRequest +path ( Rpath"$ + +MyResponse +status (Rstatus20 + MyService# +MyMethod +.MyRequest .MyResponsebproto3 \ No newline at end of file diff --git a/packages/proto-loader/test_protos/rpc.proto b/packages/proto-loader/test_protos/rpc.proto new file mode 100644 index 000000000..a9841c06b --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.proto @@ -0,0 +1,13 @@ +syntax = "proto3"; + +service MyService { + rpc MyMethod (MyRequest) returns (MyResponse); +} + +message MyRequest { + string path = 1; +} + +message MyResponse { + int32 status = 2; +} From bf98c167cda9404f2fd24901598df0217f4f0f65 Mon Sep 17 00:00:00 2001 From: "A. Tate Barber" Date: Mon, 23 Nov 2020 21:24:39 -0600 Subject: [PATCH 1323/1899] Refactor loadFileDescriptorSet This change refactors the loadFileDescriptorSetFile function to take a plain Buffer or Javascript object as input. --- packages/proto-loader/src/index.ts | 32 +++++++++---- .../proto-loader/test/descriptor_type_test.ts | 8 +++- packages/proto-loader/test_protos/rpc.desc.ts | 46 +++++++++++++++++++ 3 files changed, 75 insertions(+), 11 deletions(-) create mode 100644 packages/proto-loader/test_protos/rpc.desc.ts diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index c2f203c4d..9d1901b1c 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -379,14 +379,30 @@ export function loadSync( return createPackageDefinition(root, options!); } -export async function loadFileDescriptorSet( - descriptorSet: Protobuf.Message & - descriptor.IFileDescriptorSet, +export function loadFileDescriptorSet( + descriptorSet: + | Buffer + | ReturnType, options?: Options -): Promise { +): PackageDefinition { + type DecodedDescriptorSet = Protobuf.Message & + descriptor.IFileDescriptorSet; + options = options || {}; + + let decodedDescriptorSet: DecodedDescriptorSet; + if (typeof descriptorSet === 'object') { + decodedDescriptorSet = descriptor.FileDescriptorSet.fromObject( + descriptorSet + ) as DecodedDescriptorSet; + } else { + decodedDescriptorSet = descriptor.FileDescriptorSet.decode( + descriptorSet + ) as DecodedDescriptorSet; + } + const root = (Protobuf.Root as Protobuf.RootConstructor).fromDescriptor( - descriptorSet + decodedDescriptorSet ); root.resolveAll(); return createPackageDefinition(root, options); @@ -402,11 +418,7 @@ export function loadFileDescriptorSetFile( return reject(err); } - const descriptorSet = descriptor.FileDescriptorSet.decode( - data - ) as Protobuf.Message & - descriptor.IFileDescriptorSet; - return resolve(loadFileDescriptorSet(descriptorSet, options)); + return resolve(loadFileDescriptorSet(data, options)); }); }); } diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 57eb9ab0f..227b75658 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -16,6 +16,7 @@ */ import * as assert from 'assert'; +import { rpcFileDescriptorSet } from '../test_protos/rpc.desc'; import * as proto_loader from '../src/index'; @@ -101,7 +102,12 @@ describe('Descriptor types', () => { }); it('Can load binary-encoded proto file descriptor sets', () => { - // This will throw if the well known protos are not available. + // This will throw if the rpc descriptor cannot be decoded proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc`); }); + + it('Can parse plain file descriptor set objects', () => { + // This will throw if the file descriptor object cannot be parsed + proto_loader.loadFileDescriptorSet(rpcFileDescriptorSet); + }); }); diff --git a/packages/proto-loader/test_protos/rpc.desc.ts b/packages/proto-loader/test_protos/rpc.desc.ts new file mode 100644 index 000000000..7e52ea0db --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.desc.ts @@ -0,0 +1,46 @@ +export const rpcFileDescriptorSet = { + "file": [ + { + "name": "test_protos/rpc.proto", + "messageType": [ + { + "name": "MyRequest", + "field": [ + { + "name": "path", + "number": 1, + "label": "LABEL_OPTIONAL", + "type": "TYPE_STRING", + "jsonName": "path" + } + ] + }, + { + "name": "MyResponse", + "field": [ + { + "name": "status", + "number": 2, + "label": "LABEL_OPTIONAL", + "type": "TYPE_INT32", + "jsonName": "status" + } + ] + } + ], + "service": [ + { + "name": "MyService", + "method": [ + { + "name": "MyMethod", + "inputType": ".MyRequest", + "outputType": ".MyResponse" + } + ] + } + ], + "syntax": "proto3" + } + ] +} From 63af3bcd6ae6b39ba20a6162d54da5808fa7eb1f Mon Sep 17 00:00:00 2001 From: "A. Tate Barber" Date: Mon, 23 Nov 2020 21:46:04 -0600 Subject: [PATCH 1324/1899] Enable loadFileDescriptorSetFile to parse JSON files --- packages/proto-loader/src/index.ts | 13 ++++-- .../proto-loader/test/descriptor_type_test.ts | 7 ++- .../test_protos/{rpc.desc => rpc.desc.bin} | 0 .../proto-loader/test_protos/rpc.desc.json | 46 +++++++++++++++++++ 4 files changed, 61 insertions(+), 5 deletions(-) rename packages/proto-loader/test_protos/{rpc.desc => rpc.desc.bin} (100%) create mode 100644 packages/proto-loader/test_protos/rpc.desc.json diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 9d1901b1c..eab449636 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -391,12 +391,12 @@ export function loadFileDescriptorSet( options = options || {}; let decodedDescriptorSet: DecodedDescriptorSet; - if (typeof descriptorSet === 'object') { - decodedDescriptorSet = descriptor.FileDescriptorSet.fromObject( + if (Buffer.isBuffer(descriptorSet)) { + decodedDescriptorSet = descriptor.FileDescriptorSet.decode( descriptorSet ) as DecodedDescriptorSet; } else { - decodedDescriptorSet = descriptor.FileDescriptorSet.decode( + decodedDescriptorSet = descriptor.FileDescriptorSet.fromObject( descriptorSet ) as DecodedDescriptorSet; } @@ -418,7 +418,12 @@ export function loadFileDescriptorSetFile( return reject(err); } - return resolve(loadFileDescriptorSet(data, options)); + try { + const jsonData = JSON.parse(data.toString()); + return resolve(loadFileDescriptorSet(jsonData, options)); + } catch (e) { + return resolve(loadFileDescriptorSet(data, options)); + } }); }); } diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 227b75658..7571da0ac 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -103,7 +103,12 @@ describe('Descriptor types', () => { it('Can load binary-encoded proto file descriptor sets', () => { // This will throw if the rpc descriptor cannot be decoded - proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc`); + proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc.bin`); + }); + + it('Can load json file descriptor sets', () => { + // This will throw if the rpc descriptor JSON cannot be decoded + proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc.json`); }); it('Can parse plain file descriptor set objects', () => { diff --git a/packages/proto-loader/test_protos/rpc.desc b/packages/proto-loader/test_protos/rpc.desc.bin similarity index 100% rename from packages/proto-loader/test_protos/rpc.desc rename to packages/proto-loader/test_protos/rpc.desc.bin diff --git a/packages/proto-loader/test_protos/rpc.desc.json b/packages/proto-loader/test_protos/rpc.desc.json new file mode 100644 index 000000000..3d608e0b4 --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.desc.json @@ -0,0 +1,46 @@ +{ + "file": [ + { + "name": "test_protos/rpc.proto", + "messageType": [ + { + "name": "MyRequest", + "field": [ + { + "name": "path", + "number": 1, + "label": "LABEL_OPTIONAL", + "type": "TYPE_STRING", + "jsonName": "path" + } + ] + }, + { + "name": "MyResponse", + "field": [ + { + "name": "status", + "number": 2, + "label": "LABEL_OPTIONAL", + "type": "TYPE_INT32", + "jsonName": "status" + } + ] + } + ], + "service": [ + { + "name": "MyService", + "method": [ + { + "name": "MyMethod", + "inputType": ".MyRequest", + "outputType": ".MyResponse" + } + ] + } + ], + "syntax": "proto3" + } + ] +} From 8c50e2d40fe91a38c968be6a12864db7ed84ffdf Mon Sep 17 00:00:00 2001 From: "A. Tate Barber" Date: Mon, 23 Nov 2020 21:54:34 -0600 Subject: [PATCH 1325/1899] Refactor loadFileDescriptorSetFile to not catch JSON decoding errors This change ensures that errors are not hidden when loadFileDescriptorSet fails to decode JSON. Instead, only JSON parsing errors are hidden. --- packages/proto-loader/src/index.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index eab449636..6b30e36e9 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -419,11 +419,10 @@ export function loadFileDescriptorSetFile( } try { - const jsonData = JSON.parse(data.toString()); - return resolve(loadFileDescriptorSet(jsonData, options)); - } catch (e) { - return resolve(loadFileDescriptorSet(data, options)); - } + data = JSON.parse(data.toString()); + } catch (e) {} + + return resolve(loadFileDescriptorSet(data, options)); }); }); } From 4b3e0b6a8a0ceb3554ad9a31afb7a7c163c838c7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 Nov 2020 16:18:47 -0800 Subject: [PATCH 1326/1899] Update version and dependencies for final release --- packages/proto-loader/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 7947dcf0f..cfc767a9b 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0-pre17", + "version": "0.6.0", "author": "Google Inc.", "contributors": [ { @@ -49,7 +49,7 @@ "lodash.camelcase": "^4.3.0", "long": "^4.0.0", "protobufjs": "^6.10.0", - "yargs": "^15.3.1" + "yargs": "^16.1.1" }, "devDependencies": { "@types/lodash.camelcase": "^4.3.4", From d3a1ba6cbf6ddf3c179b44ed98ed8c1d09067fd2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Nov 2020 10:04:05 -0800 Subject: [PATCH 1327/1899] Make grpc-js and grpc-js-xds versions match --- packages/grpc-js-xds/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 78d90c1d0..3008d3ec2 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.0.0", + "version": "1.2.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -32,13 +32,13 @@ "homepage": "https://github.com/grpc/grpc-node#readme", "devDependencies": { "@grpc/grpc-js": "file:../grpc-js", - "gts": "^2.0.2", - "typescript": "^3.8.3", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/mocha": "^5.2.6", "@types/node": "^13.11.1", "@types/yargs": "^15.0.5", + "gts": "^2.0.2", + "typescript": "^3.8.3", "yargs": "^15.4.1" }, "dependencies": { From a006be07f452da7e69fb3c5779e61c6092f150b8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Nov 2020 12:33:36 -0800 Subject: [PATCH 1328/1899] grpc-js-xds: Shutdown the xDS client used by the resolver when the channel shuts down --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/resolver-xds.ts | 13 ++++++++----- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/resolver-dns.ts | 6 ++++++ packages/grpc-js/src/resolver-uds.ts | 4 ++++ packages/grpc-js/src/resolver.ts | 5 +++++ packages/grpc-js/src/resolving-load-balancer.ts | 1 + packages/grpc-js/test/test-resolver.ts | 3 +++ 8 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 3008d3ec2..6c7349275 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -45,7 +45,7 @@ "@grpc/proto-loader": "^0.6.0-pre14" }, "peerDependencies": { - "@grpc/grpc-js": "~1.2.0" + "@grpc/grpc-js": "~1.2.2" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 814294c81..24d25b974 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -30,8 +30,8 @@ function trace(text: string): void { } class XdsResolver implements Resolver { - private resolutionStarted = false; private hasReportedSuccess = false; + private xdsClient: XdsClient | null = null; constructor( private target: GrpcUri, @@ -51,17 +51,16 @@ class XdsResolver implements Resolver { updateResolution(): void { // Wait until updateResolution is called once to start the xDS requests - if (!this.resolutionStarted) { - this.resolutionStarted = true; + if (this.xdsClient === null) { trace('Starting resolution for target ' + uriToString(this.target)); - const xdsClient = new XdsClient( + this.xdsClient = new XdsClient( this.target.path, { onValidUpdate: (update: ServiceConfig) => { trace('Resolved service config for target ' + uriToString(this.target) + ': ' + JSON.stringify(update)); this.hasReportedSuccess = true; this.listener.onSuccessfulResolution([], update, null, { - xdsClient: xdsClient, + xdsClient: this.xdsClient, }); }, onTransientError: (error: StatusObject) => { @@ -82,6 +81,10 @@ class XdsResolver implements Resolver { } } + destroy() { + this.xdsClient?.shutdown(); + } + static getDefaultAuthority(target: GrpcUri) { return target.path; } diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 22142dcdd..8519f5dfd 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.1", + "version": "1.2.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 2db8a5e41..f19318d33 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -262,6 +262,12 @@ class DnsResolver implements Resolver { } } + destroy() { + /* Do nothing. There is not a practical way to cancel in-flight DNS + * requests, and after this function is called we can expect that + * updateResolution will not be called again. */ + } + /** * Get the default authority for the given target. For IP targets, that is * the IP address. For DNS targets, it is the hostname. diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 14bc0176a..ed25177cc 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -44,6 +44,10 @@ class UdsResolver implements Resolver { ); } + destroy() { + // This resolver owns no resources, so we do nothing here. + } + static getDefaultAuthority(target: GrpcUri): string { return 'localhost'; } diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 57c750aea..74f3e5143 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -62,6 +62,11 @@ export interface Resolver { * called synchronously with the constructor or updateResolution. */ updateResolution(): void; + + /** + * Destroy the resolver. Should be called when the owning channel shuts down. + */ + destroy(): void; } export interface ResolverConstructor { diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 2ce59d0c2..5a4c62f57 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -257,6 +257,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { destroy() { this.childLoadBalancer.destroy(); + this.innerResolver.destroy(); this.updateState(ConnectivityState.SHUTDOWN, new UnavailablePicker()); } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 42ca64d4d..c4f42f6eb 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -394,6 +394,9 @@ describe('Name Resolver', () => { return []; } + destroy() { + } + static getDefaultAuthority(target: GrpcUri): string { return 'other'; } From d86994dc6ab3c581d9c5baff42936f0bed9df09a Mon Sep 17 00:00:00 2001 From: "A. Tate Barber" Date: Mon, 30 Nov 2020 20:45:18 -0600 Subject: [PATCH 1329/1899] Split file descriptor set logic into two utility functions This change exposes loadFileDescriptorSetFromBuffer and loadFileDescriptorSetFromObject functions. --- packages/proto-loader/src/index.ts | 72 +++++++++---------- .../proto-loader/test/descriptor_type_test.ts | 10 ++- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 6b30e36e9..c51bc0110 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -109,6 +109,9 @@ export type Options = Protobuf.IParseOptions & includeDirs?: string[]; }; +type DecodedDescriptorSet = Protobuf.Message & + descriptor.IFileDescriptorSet; + const descriptorOptions: Protobuf.IConversionOptions = { longs: String, enums: String, @@ -318,6 +321,19 @@ function addIncludePathResolver(root: Protobuf.Root, includePaths: string[]) { }; } +function createPackageDefinitionFromDescriptorSet( + decodedDescriptorSet: DecodedDescriptorSet, + options?: Options +) { + options = options || {}; + + const root = (Protobuf.Root as Protobuf.RootConstructor).fromDescriptor( + decodedDescriptorSet + ); + root.resolveAll(); + return createPackageDefinition(root, options); +} + /** * Load a .proto file with the specified options. * @param filename One or multiple file paths to load. Can be an absolute path @@ -379,52 +395,32 @@ export function loadSync( return createPackageDefinition(root, options!); } -export function loadFileDescriptorSet( - descriptorSet: - | Buffer - | ReturnType, +export function loadFileDescriptorSetFromBuffer( + descriptorSet: Buffer, options?: Options ): PackageDefinition { - type DecodedDescriptorSet = Protobuf.Message & - descriptor.IFileDescriptorSet; + const decodedDescriptorSet = descriptor.FileDescriptorSet.decode( + descriptorSet + ) as DecodedDescriptorSet; - options = options || {}; - - let decodedDescriptorSet: DecodedDescriptorSet; - if (Buffer.isBuffer(descriptorSet)) { - decodedDescriptorSet = descriptor.FileDescriptorSet.decode( - descriptorSet - ) as DecodedDescriptorSet; - } else { - decodedDescriptorSet = descriptor.FileDescriptorSet.fromObject( - descriptorSet - ) as DecodedDescriptorSet; - } - - const root = (Protobuf.Root as Protobuf.RootConstructor).fromDescriptor( - decodedDescriptorSet + return createPackageDefinitionFromDescriptorSet( + decodedDescriptorSet, + options ); - root.resolveAll(); - return createPackageDefinition(root, options); } -export function loadFileDescriptorSetFile( - filename: string, +export function loadFileDescriptorSetFromObject( + descriptorSet: Parameters[0], options?: Options -): Promise { - return new Promise((resolve, reject) => { - fs.readFile(filename, (err, data) => { - if (err) { - return reject(err); - } - - try { - data = JSON.parse(data.toString()); - } catch (e) {} +): PackageDefinition { + const decodedDescriptorSet = descriptor.FileDescriptorSet.fromObject( + descriptorSet + ) as DecodedDescriptorSet; - return resolve(loadFileDescriptorSet(data, options)); - }); - }); + return createPackageDefinitionFromDescriptorSet( + decodedDescriptorSet, + options + ); } // Load Google's well-known proto files that aren't exposed by Protobuf.js. diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 7571da0ac..32aca9fc6 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -17,6 +17,7 @@ import * as assert from 'assert'; import { rpcFileDescriptorSet } from '../test_protos/rpc.desc'; +import { readFileSync } from 'fs'; import * as proto_loader from '../src/index'; @@ -102,17 +103,20 @@ describe('Descriptor types', () => { }); it('Can load binary-encoded proto file descriptor sets', () => { + const buffer = readFileSync(`${TEST_PROTO_DIR}/rpc.desc.bin`); // This will throw if the rpc descriptor cannot be decoded - proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc.bin`); + proto_loader.loadFileDescriptorSetFromBuffer(buffer); }); it('Can load json file descriptor sets', () => { + const buffer = readFileSync(`${TEST_PROTO_DIR}/rpc.desc.json`); + const json = JSON.parse(buffer.toString()); // This will throw if the rpc descriptor JSON cannot be decoded - proto_loader.loadFileDescriptorSetFile(`${TEST_PROTO_DIR}/rpc.desc.json`); + proto_loader.loadFileDescriptorSetFromObject(json); }); it('Can parse plain file descriptor set objects', () => { // This will throw if the file descriptor object cannot be parsed - proto_loader.loadFileDescriptorSet(rpcFileDescriptorSet); + proto_loader.loadFileDescriptorSetFromObject(rpcFileDescriptorSet); }); }); From 21da990cb0fdb8130413ea27699f06b321daba87 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Dec 2020 12:00:19 -0800 Subject: [PATCH 1330/1899] grpc-js: End calls faster if the deadline has already passed --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/deadline-filter.ts | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8519f5dfd..17fb1a2e5 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.2", + "version": "1.2.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 2306bb8f5..99bfa2bec 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -56,10 +56,14 @@ export class DeadlineFilter extends BaseFilter implements Filter { } const now: number = new Date().getTime(); let timeout = this.deadline - now; - if (timeout < 0) { - timeout = 0; - } - if (this.deadline !== Infinity) { + if (timeout <= 0) { + process.nextTick(() => { + callStream.cancelWithStatus( + Status.DEADLINE_EXCEEDED, + 'Deadline exceeded' + ); + }); + } else if (this.deadline !== Infinity) { this.timer = setTimeout(() => { callStream.cancelWithStatus( Status.DEADLINE_EXCEEDED, From b2530119b90a10dcb15790022477221f47a8f9bc Mon Sep 17 00:00:00 2001 From: d3v53c Date: Mon, 7 Dec 2020 22:29:18 -0800 Subject: [PATCH 1331/1899] prototype pollution fix --- packages/grpc-js/src/make-client.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index 05f06b89f..a6cb91007 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -93,6 +93,15 @@ export interface ServiceClientConstructor { service: ServiceDefinition; } +/** + * Returns true, if given key is included in the blacklisted + * keys. + * @param key key for check, string. + */ +function isPrototypePolluted(key: string): Boolean { + return ['__proto__', 'prototype', 'constructor'].includes(key); +} + /** * Creates a constructor for a client with the given methods, as specified in * the methods argument. The resulting class will have an instance method for @@ -122,7 +131,7 @@ export function makeClientConstructor( } Object.keys(methods).forEach((name) => { - if (name === '__proto__') { + if (isPrototypePolluted(name)) { return; } const attrs = methods[name]; @@ -155,7 +164,7 @@ export function makeClientConstructor( ServiceClientImpl.prototype[name] = methodFunc; // Associate all provided attributes with the method Object.assign(ServiceClientImpl.prototype[name], attrs); - if (attrs.originalName && attrs.originalName !== '__proto__') { + if (attrs.originalName && !isPrototypePolluted(attrs.originalName)) { ServiceClientImpl.prototype[attrs.originalName] = ServiceClientImpl.prototype[name]; } @@ -204,7 +213,7 @@ export function loadPackageDefinition( if (Object.prototype.hasOwnProperty.call(packageDef, serviceFqn)) { const service = packageDef[serviceFqn]; const nameComponents = serviceFqn.split('.'); - if (nameComponents.some(comp => comp === '__proto__')) { + if (nameComponents.some((comp: string) => isPrototypePolluted(comp))) { continue; } const serviceName = nameComponents[nameComponents.length - 1]; From 61016943973875191ef746b06b9806042d31b96e Mon Sep 17 00:00:00 2001 From: d3v53c Date: Mon, 7 Dec 2020 22:40:14 -0800 Subject: [PATCH 1332/1899] added test case --- packages/grpc-js/test/test-prototype-pollution.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/test/test-prototype-pollution.ts b/packages/grpc-js/test/test-prototype-pollution.ts index 12092608c..6dc4b293c 100644 --- a/packages/grpc-js/test/test-prototype-pollution.ts +++ b/packages/grpc-js/test/test-prototype-pollution.ts @@ -24,4 +24,8 @@ describe('loadPackageDefinition', () => { loadPackageDefinition({'__proto__.polluted': true} as any); assert.notStrictEqual(({} as any).polluted, true); }); + it('Should not allow prototype pollution #2', () => { + loadPackageDefinition({'constructor.prototype.polluted': true} as any); + assert.notStrictEqual(({} as any).polluted, true); + }); }); From d3ef8f3233738a75cb48368d9c85c8ce2b85f4fe Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Sun, 20 Dec 2020 08:01:13 +0000 Subject: [PATCH 1333/1899] proto-loader: Replace Windows CRLF pair with Unix LF --- .../bin/proto-loader-gen-types.ts | 1490 ++++++++--------- 1 file changed, 745 insertions(+), 745 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 54b1475c3..bd294aa66 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -1,745 +1,745 @@ -#!/usr/bin/env node -/** - * @license - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import * as fs from 'fs'; -import * as path from 'path'; - -import * as Protobuf from 'protobufjs'; -import * as yargs from 'yargs'; - -import camelCase = require('lodash.camelcase'); -import { loadProtosWithOptions, addCommonProtos } from '../src/util'; - -type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { - includeDirs?: string[]; - grpcLib: string; - outDir: string; - verbose?: boolean; - includeComments?: boolean; -} - -class TextFormatter { - private readonly indentText = ' '; - private indentValue = 0; - private textParts: string[] = []; - constructor() {} - - indent() { - this.indentValue += 1; - } - - unindent() { - this.indentValue -= 1; - } - - writeLine(line: string) { - for (let i = 0; i < this.indentValue; i+=1) { - this.textParts.push(this.indentText); - } - this.textParts.push(line); - this.textParts.push('\n'); - } - - getFullText() { - return this.textParts.join(''); - } -} - -// GENERATOR UTILITY FUNCTIONS - -function compareName(x: {name: string}, y: {name: string}): number { - if (x.name < y.name) { - return -1; - } else if (x.name > y.name) { - return 1 - } else { - return 0; - } -} - -function isNamespaceBase(obj: Protobuf.ReflectionObject): obj is Protobuf.NamespaceBase { - return Array.isArray((obj as Protobuf.NamespaceBase).nestedArray); -} - -function stripLeadingPeriod(name: string) { - return name.startsWith('.') ? name.substring(1) : name; -} - -function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service): string { - /* If the thing we are importing is defined in a message, it is generated in - * the same file as that message. */ - if (to.parent instanceof Protobuf.Type) { - return getImportPath(to.parent); - } - return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); -} - -function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { - return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.ts'; -} - -function getPathToRoot(from: Protobuf.NamespaceBase) { - const depth = stripLeadingPeriod(from.fullName).split('.').length - 1; - if (depth === 0) { - return './'; - } - let path = ''; - for (let i = 0; i < depth; i++) { - path += '../'; - } - return path; -} - -function getRelativeImportPath(from: Protobuf.Type | Protobuf.Service, to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { - return getPathToRoot(from) + getImportPath(to); -} - -function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { - return type.fullName.replace(/\./g, '_'); -} - -function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Service, from?: Protobuf.Type | Protobuf.Service) { - const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); - const typeInterfaceName = getTypeInterfaceName(dependency); - let importedTypes: string; - /* If the dependenc is defined within a message, it will be generated in that - * message's file and exported using its typeInterfaceName. */ - if (dependency.parent instanceof Protobuf.Type) { - if (dependency instanceof Protobuf.Type) { - importedTypes = `${typeInterfaceName}, ${typeInterfaceName}__Output`; - } else if (dependency instanceof Protobuf.Enum) { - importedTypes = `${typeInterfaceName}`; - } else if (dependency instanceof Protobuf.Service) { - importedTypes = `${typeInterfaceName}Client`; - } else { - throw new Error('Invalid object passed to getImportLine'); - } - } else { - if (dependency instanceof Protobuf.Type) { - importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; - } else if (dependency instanceof Protobuf.Enum) { - importedTypes = `${dependency.name} as ${typeInterfaceName}`; - } else if (dependency instanceof Protobuf.Service) { - importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; - } else { - throw new Error('Invalid object passed to getImportLine'); - } - } - return `import type { ${importedTypes} } from '${filePath}';` -} - -function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf.Type | Protobuf.Enum)[] { - const messageList: (Protobuf.Type | Protobuf.Enum)[] = []; - for (const nested of namespace.nestedArray) { - if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { - messageList.push(nested); - } - if (isNamespaceBase(nested)) { - messageList.push(...getChildMessagesAndEnums(nested)); - } - } - return messageList; -} - -function formatComment(formatter: TextFormatter, comment?: string | null) { - if (!comment) { - return; - } - formatter.writeLine('/**'); - for(const line of comment.split('\n')) { - formatter.writeLine(` * ${line.replace(/\*\//g, '* /')}`); - } - formatter.writeLine(' */'); -} - -// GENERATOR FUNCTIONS - -function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null): string { - switch (fieldType) { - case 'double': - case 'float': - return 'number | string'; - case 'int32': - case 'uint32': - case 'sint32': - case 'fixed32': - case 'sfixed32': - return 'number'; - case 'int64': - case 'uint64': - case 'sint64': - case 'fixed64': - case 'sfixed64': - return 'number | string | Long'; - case 'bool': - return 'boolean'; - case 'string': - return 'string'; - case 'bytes': - return 'Buffer | Uint8Array | string'; - default: - if (resolvedType === null) { - throw new Error('Found field with no usable type'); - } - const typeInterfaceName = getTypeInterfaceName(resolvedType); - if (resolvedType instanceof Protobuf.Type) { - return typeInterfaceName; - } else { - return `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; - } - } -} - -function getFieldTypePermissive(field: Protobuf.FieldBase): string { - const valueType = getTypeNamePermissive(field.type, field.resolvedType); - if (field instanceof Protobuf.MapField) { - const keyType = field.keyType === 'string' ? 'string' : 'number'; - return `{[key: ${keyType}]: ${valueType}}`; - } else { - return valueType; - } -} - -function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { - if (options.includeComments) { - formatComment(formatter, messageType.comment); - } - if (messageType.fullName === '.google.protobuf.Any') { - /* This describes the behavior of the Protobuf.js Any wrapper fromObject - * replacement function */ - formatter.writeLine('export type Any = AnyExtension | {'); - formatter.writeLine(' type_url: string;'); - formatter.writeLine(' value: Buffer | Uint8Array | string;'); - formatter.writeLine('}'); - return; - } - formatter.writeLine(`export interface ${nameOverride ?? messageType.name} {`); - formatter.indent(); - for (const field of messageType.fieldsArray) { - const repeatedString = field.repeated ? '[]' : ''; - const type: string = getFieldTypePermissive(field); - if (options.includeComments) { - formatComment(formatter, field.comment); - } - formatter.writeLine(`'${field.name}'?: (${type})${repeatedString};`); - } - for (const oneof of messageType.oneofsArray) { - const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); - if (options.includeComments) { - formatComment(formatter, oneof.comment); - } - formatter.writeLine(`'${oneof.name}'?: ${typeString};`); - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, options: GeneratorOptions): string { - switch (fieldType) { - case 'double': - case 'float': - if (options.json) { - return 'number | string'; - } else { - return 'number'; - } - case 'int32': - case 'uint32': - case 'sint32': - case 'fixed32': - case 'sfixed32': - return 'number'; - case 'int64': - case 'uint64': - case 'sint64': - case 'fixed64': - case 'sfixed64': - if (options.longs === Number) { - return 'number'; - } else if (options.longs === String) { - return 'string'; - } else { - return 'Long'; - } - case 'bool': - return 'boolean'; - case 'string': - return 'string'; - case 'bytes': - if (options.bytes === Array) { - return 'Uint8Array'; - } else if (options.bytes === String) { - return 'string'; - } else { - return 'Buffer'; - } - default: - if (resolvedType === null) { - throw new Error('Found field with no usable type'); - } - const typeInterfaceName = getTypeInterfaceName(resolvedType); - if (resolvedType instanceof Protobuf.Type) { - return typeInterfaceName + '__Output'; - } else { - if (options.enums == String) { - return `keyof typeof ${typeInterfaceName}`; - } else { - return typeInterfaceName; - } - } - } -} - -function getFieldTypeRestricted(field: Protobuf.FieldBase, options: GeneratorOptions): string { - const valueType = getTypeNameRestricted(field.type, field.resolvedType, options); - if (field instanceof Protobuf.MapField) { - const keyType = field.keyType === 'string' ? 'string' : 'number'; - return `{[key: ${keyType}]: ${valueType}}`; - } else { - return valueType; - } -} - -function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { - if (options.includeComments) { - formatComment(formatter, messageType.comment); - } - if (messageType.fullName === '.google.protobuf.Any' && options.json) { - /* This describes the behavior of the Protobuf.js Any wrapper toObject - * replacement function */ - let optionalString = options.defaults ? '' : '?'; - formatter.writeLine('export type Any__Output = AnyExtension | {'); - formatter.writeLine(` type_url${optionalString}: string;`); - formatter.writeLine(` value${optionalString}: ${getTypeNameRestricted('bytes', null, options)};`); - formatter.writeLine('}'); - return; - } - formatter.writeLine(`export interface ${nameOverride ?? messageType.name}__Output {`); - formatter.indent(); - for (const field of messageType.fieldsArray) { - let fieldGuaranteed: boolean; - if (field.partOf) { - // The field is not guaranteed populated if it is part of a oneof - fieldGuaranteed = false; - } else if (field.repeated) { - fieldGuaranteed = (options.defaults || options.arrays) ?? false; - } else if (field.resolvedType) { - if (field.resolvedType instanceof Protobuf.Enum) { - fieldGuaranteed = options.defaults ?? false; - } else { - // Message fields can always be omitted - fieldGuaranteed = false; - } - } else { - if (field.map) { - fieldGuaranteed = (options.defaults || options.objects) ?? false; - } else { - fieldGuaranteed = options.defaults ?? false; - } - } - const optionalString = fieldGuaranteed ? '' : '?'; - const repeatedString = field.repeated ? '[]' : ''; - const type = getFieldTypeRestricted(field, options); - if (options.includeComments) { - formatComment(formatter, field.comment); - } - formatter.writeLine(`'${field.name}'${optionalString}: (${type})${repeatedString};`); - } - if (options.oneofs) { - for (const oneof of messageType.oneofsArray) { - const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); - if (options.includeComments) { - formatComment(formatter, oneof.comment); - } - formatter.writeLine(`'${oneof.name}': ${typeString};`); - } - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function generateMessageInterfaces(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions) { - let usesLong: boolean = false; - let seenDeps: Set = new Set(); - const childTypes = getChildMessagesAndEnums(messageType); - formatter.writeLine(`// Original file: ${messageType.filename}`); - formatter.writeLine(''); - messageType.fieldsArray.sort((fieldA, fieldB) => fieldA.id - fieldB.id); - for (const field of messageType.fieldsArray) { - if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { - const dependency = field.resolvedType; - if (seenDeps.has(dependency.fullName)) { - continue; - } - seenDeps.add(dependency.fullName); - formatter.writeLine(getImportLine(dependency, messageType)); - } - if (field.type.indexOf('64') >= 0) { - usesLong = true; - } - } - for (const childType of childTypes) { - if (childType instanceof Protobuf.Type) { - for (const field of childType.fieldsArray) { - if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { - const dependency = field.resolvedType; - if (seenDeps.has(dependency.fullName)) { - continue; - } - seenDeps.add(dependency.fullName); - formatter.writeLine(getImportLine(dependency, messageType)); - } - if (field.type.indexOf('64') >= 0) { - usesLong = true; - } - } - } - } - if (usesLong) { - formatter.writeLine("import type { Long } from '@grpc/proto-loader';"); - } - if (messageType.fullName === '.google.protobuf.Any') { - formatter.writeLine("import type { AnyExtension } from '@grpc/proto-loader';") - } - formatter.writeLine(''); - for (const childType of childTypes.sort(compareName)) { - const nameOverride = getTypeInterfaceName(childType); - if (childType instanceof Protobuf.Type) { - generatePermissiveMessageInterface(formatter, childType, options, nameOverride); - formatter.writeLine(''); - generateRestrictedMessageInterface(formatter, childType, options, nameOverride); - } else { - generateEnumInterface(formatter, childType, options, nameOverride); - } - formatter.writeLine(''); - } - - generatePermissiveMessageInterface(formatter, messageType, options); - formatter.writeLine(''); - generateRestrictedMessageInterface(formatter, messageType, options); -} - -function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, options: GeneratorOptions, nameOverride?: string) { - formatter.writeLine(`// Original file: ${enumType.filename}`); - formatter.writeLine(''); - if (options.includeComments) { - formatComment(formatter, enumType.comment); - } - formatter.writeLine(`export enum ${nameOverride ?? enumType.name} {`); - formatter.indent(); - for (const key of Object.keys(enumType.values)) { - if (options.includeComments) { - formatComment(formatter, enumType.comments[key]); - } - formatter.writeLine(`${key} = ${enumType.values[key]},`); - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { - if (options.includeComments) { - formatComment(formatter, serviceType.comment); - } - formatter.writeLine(`export interface ${serviceType.name}Client extends grpc.Client {`); - formatter.indent(); - for (const methodName of Object.keys(serviceType.methods).sort()) { - const method = serviceType.methods[methodName]; - for (const name of [methodName, camelCase(methodName)]) { - if (options.includeComments) { - formatComment(formatter, method.comment); - } - const requestType = getTypeInterfaceName(method.resolvedRequestType!); - const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; - const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; - if (method.requestStream) { - if (method.responseStream) { - // Bidi streaming - const callType = `grpc.ClientDuplexStream<${requestType}, ${responseType}>`; - formatter.writeLine(`${name}(metadata: grpc.Metadata, options?: grpc.CallOptions): ${callType};`); - formatter.writeLine(`${name}(options?: grpc.CallOptions): ${callType};`); - } else { - // Client streaming - const callType = `grpc.ClientWritableStream<${requestType}>`; - formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(callback: ${callbackType}): ${callType};`); - } - } else { - if (method.responseStream) { - // Server streaming - const callType = `grpc.ClientReadableStream<${responseType}>`; - formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options?: grpc.CallOptions): ${callType};`); - formatter.writeLine(`${name}(argument: ${requestType}, options?: grpc.CallOptions): ${callType};`); - } else { - // Unary - const callType = 'grpc.ClientUnaryCall'; - formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(argument: ${requestType}, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); - formatter.writeLine(`${name}(argument: ${requestType}, callback: ${callbackType}): ${callType};`); - } - } - } - formatter.writeLine(''); - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { - if (options.includeComments) { - formatComment(formatter, serviceType.comment); - } - formatter.writeLine(`export interface ${serviceType.name}Handlers extends grpc.UntypedServiceImplementation {`); - formatter.indent(); - for (const methodName of Object.keys(serviceType.methods).sort()) { - const method = serviceType.methods[methodName]; - if (options.includeComments) { - formatComment(formatter, method.comment); - } - const requestType = getTypeInterfaceName(method.resolvedRequestType!) + '__Output'; - const responseType = getTypeInterfaceName(method.resolvedResponseType!); - if (method.requestStream) { - if (method.responseStream) { - // Bidi streaming - formatter.writeLine(`${methodName}: grpc.handleBidiStreamingCall<${requestType}, ${responseType}>;`); - } else { - // Client streaming - formatter.writeLine(`${methodName}: grpc.handleClientStreamingCall<${requestType}, ${responseType}>;`); - } - } else { - if (method.responseStream) { - // Server streaming - formatter.writeLine(`${methodName}: grpc.handleServerStreamingCall<${requestType}, ${responseType}>;`); - } else { - // Unary - formatter.writeLine(`${methodName}: grpc.handleUnaryCall<${requestType}, ${responseType}>;`); - } - } - formatter.writeLine(''); - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { - formatter.writeLine(`// Original file: ${serviceType.filename}`); - formatter.writeLine(''); - const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; - formatter.writeLine(`import type * as grpc from '${grpcImportPath}'`); - const dependencies: Set = new Set(); - for (const method of serviceType.methodsArray) { - dependencies.add(method.resolvedRequestType!); - dependencies.add(method.resolvedResponseType!); - } - for (const dep of Array.from(dependencies.values()).sort(compareName)) { - formatter.writeLine(getImportLine(dep, serviceType)); - } - formatter.writeLine(''); - - generateServiceClientInterface(formatter, serviceType, options); - formatter.writeLine(''); - - generateServiceHandlerInterface(formatter, serviceType, options); -} - -function generateServiceImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { - for (const nested of namespace.nestedArray.sort(compareName)) { - if (nested instanceof Protobuf.Service) { - formatter.writeLine(getImportLine(nested)); - } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { - generateServiceImports(formatter, nested, options); - } - } -} - -function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject, options: GeneratorOptions) { - if (nested instanceof Protobuf.Service) { - if (options.includeComments) { - formatComment(formatter, nested.comment); - } - formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) - } else if (nested instanceof Protobuf.Enum) { - formatter.writeLine(`${nested.name}: EnumTypeDefinition`); - } else if (nested instanceof Protobuf.Type) { - formatter.writeLine(`${nested.name}: MessageTypeDefinition`); - } else if (isNamespaceBase(nested)) { - generateLoadedDefinitionTypes(formatter, nested, options); - } -} - -function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { - formatter.writeLine(`${namespace.name}: {`); - formatter.indent(); - for (const nested of namespace.nestedArray.sort(compareName)) { - generateSingleLoadedDefinitionType(formatter, nested, options); - } - formatter.unindent(); - formatter.writeLine('}'); -} - -function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { - formatter.writeLine(`import type * as grpc from '${options.grpcLib}';`); - formatter.writeLine("import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); - formatter.writeLine(''); - - generateServiceImports(formatter, root, options); - formatter.writeLine(''); - - formatter.writeLine('type SubtypeConstructor any, Subtype> = {'); - formatter.writeLine(' new(...args: ConstructorParameters): Subtype;'); - formatter.writeLine('};'); - formatter.writeLine(''); - - formatter.writeLine('export interface ProtoGrpcType {'); - formatter.indent(); - for (const nested of root.nestedArray) { - generateSingleLoadedDefinitionType(formatter, nested, options); - } - formatter.unindent(); - formatter.writeLine('}'); - formatter.writeLine(''); -} - -async function writeFile(filename: string, contents: string): Promise { - await fs.promises.mkdir(path.dirname(filename), {recursive: true}); - return fs.promises.writeFile(filename, contents); -} - -function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: GeneratorOptions): Promise[] { - const filePromises : Promise[] = []; - for (const nested of namespace.nestedArray) { - const fileFormatter = new TextFormatter(); - if (nested instanceof Protobuf.Type) { - generateMessageInterfaces(fileFormatter, nested, options); - if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); - } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); - } else if (nested instanceof Protobuf.Enum) { - generateEnumInterface(fileFormatter, nested, options); - if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); - } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); - } else if (nested instanceof Protobuf.Service) { - generateServiceInterfaces(fileFormatter, nested, options); - if (options.verbose) { - console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); - } - filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); - } else if (isNamespaceBase(nested)) { - filePromises.push(...generateFilesForNamespace(nested, options)); - } - } - return filePromises; -} - -function writeFilesForRoot(root: Protobuf.Root, masterFileName: string, options: GeneratorOptions): Promise[] { - const filePromises: Promise[] = []; - - const masterFileFormatter = new TextFormatter(); - generateRootFile(masterFileFormatter, root, options); - if (options.verbose) { - console.log(`Writing ${options.outDir}/${masterFileName}`); - } - filePromises.push(writeFile(`${options.outDir}/${masterFileName}`, masterFileFormatter.getFullText())); - - filePromises.push(...generateFilesForNamespace(root, options)); - - return filePromises; -} - -async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { - await fs.promises.mkdir(options.outDir, {recursive: true}); - for (const filename of protoFiles) { - const loadedRoot = await loadProtosWithOptions(filename, options); - writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.ts'), options); - } -} - -function runScript() { - const argv = yargs - .string(['includeDirs', 'grpcLib']) - .normalize(['includeDirs', 'outDir']) - .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) -// .choices('longs', ['String', 'Number']) -// .choices('enums', ['String']) -// .choices('bytes', ['Array', 'String']) - .string(['longs', 'enums', 'bytes']) - .coerce('longs', value => { - switch (value) { - case 'String': return String; - case 'Number': return Number; - default: return undefined; - } - }).coerce('enums', value => { - if (value === 'String') { - return String; - } else { - return undefined; - } - }).coerce('bytes', value => { - switch (value) { - case 'Array': return Array; - case 'String': return String; - default: return undefined; - } - }).alias({ - includeDirs: 'I', - outDir: 'O', - verbose: 'v' - }).describe({ - keepCase: 'Preserve the case of field names', - longs: 'The type that should be used to output 64 bit integer values. Can be String, Number', - enums: 'The type that should be used to output enum fields. Can be String', - bytes: 'The type that should be used to output bytes fields. Can be String, Array', - defaults: 'Output default values for omitted fields', - arrays: 'Output default values for omitted repeated fields even if --defaults is not set', - objects: 'Output default values for omitted message fields even if --defaults is not set', - oneofs: 'Output virtual oneof fields set to the present field\'s name', - json: 'Represent Infinity and NaN as strings in float fields. Also decode google.protobuf.Any automatically', - includeComments: 'Generate doc comments from comments in the original files', - includeDirs: 'Directories to search for included files', - outDir: 'Directory in which to output files', - grpcLib: 'The gRPC implementation library that these types will be used with' - }).demandOption(['outDir', 'grpcLib']) - .demand(1) - .usage('$0 [options] filenames...') - .epilogue('WARNING: This tool is in alpha. The CLI and generated code are subject to change') - .argv; - if (argv.verbose) { - console.log('Parsed arguments:', argv); - } - addCommonProtos(); - writeAllFiles(argv._, {...argv, alternateCommentMode: true}).then(() => { - if (argv.verbose) { - console.log('Success'); - } - }, (error) => { - throw error; - }) -} - -if (require.main === module) { - runScript(); -} \ No newline at end of file +#!/usr/bin/env node +/** + * @license + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as fs from 'fs'; +import * as path from 'path'; + +import * as Protobuf from 'protobufjs'; +import * as yargs from 'yargs'; + +import camelCase = require('lodash.camelcase'); +import { loadProtosWithOptions, addCommonProtos } from '../src/util'; + +type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { + includeDirs?: string[]; + grpcLib: string; + outDir: string; + verbose?: boolean; + includeComments?: boolean; +} + +class TextFormatter { + private readonly indentText = ' '; + private indentValue = 0; + private textParts: string[] = []; + constructor() {} + + indent() { + this.indentValue += 1; + } + + unindent() { + this.indentValue -= 1; + } + + writeLine(line: string) { + for (let i = 0; i < this.indentValue; i+=1) { + this.textParts.push(this.indentText); + } + this.textParts.push(line); + this.textParts.push('\n'); + } + + getFullText() { + return this.textParts.join(''); + } +} + +// GENERATOR UTILITY FUNCTIONS + +function compareName(x: {name: string}, y: {name: string}): number { + if (x.name < y.name) { + return -1; + } else if (x.name > y.name) { + return 1 + } else { + return 0; + } +} + +function isNamespaceBase(obj: Protobuf.ReflectionObject): obj is Protobuf.NamespaceBase { + return Array.isArray((obj as Protobuf.NamespaceBase).nestedArray); +} + +function stripLeadingPeriod(name: string) { + return name.startsWith('.') ? name.substring(1) : name; +} + +function getImportPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service): string { + /* If the thing we are importing is defined in a message, it is generated in + * the same file as that message. */ + if (to.parent instanceof Protobuf.Type) { + return getImportPath(to.parent); + } + return stripLeadingPeriod(to.fullName).replace(/\./g, '/'); +} + +function getPath(to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { + return stripLeadingPeriod(to.fullName).replace(/\./g, '/') + '.ts'; +} + +function getPathToRoot(from: Protobuf.NamespaceBase) { + const depth = stripLeadingPeriod(from.fullName).split('.').length - 1; + if (depth === 0) { + return './'; + } + let path = ''; + for (let i = 0; i < depth; i++) { + path += '../'; + } + return path; +} + +function getRelativeImportPath(from: Protobuf.Type | Protobuf.Service, to: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { + return getPathToRoot(from) + getImportPath(to); +} + +function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum | Protobuf.Service) { + return type.fullName.replace(/\./g, '_'); +} + +function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Service, from?: Protobuf.Type | Protobuf.Service) { + const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); + const typeInterfaceName = getTypeInterfaceName(dependency); + let importedTypes: string; + /* If the dependenc is defined within a message, it will be generated in that + * message's file and exported using its typeInterfaceName. */ + if (dependency.parent instanceof Protobuf.Type) { + if (dependency instanceof Protobuf.Type) { + importedTypes = `${typeInterfaceName}, ${typeInterfaceName}__Output`; + } else if (dependency instanceof Protobuf.Enum) { + importedTypes = `${typeInterfaceName}`; + } else if (dependency instanceof Protobuf.Service) { + importedTypes = `${typeInterfaceName}Client`; + } else { + throw new Error('Invalid object passed to getImportLine'); + } + } else { + if (dependency instanceof Protobuf.Type) { + importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; + } else if (dependency instanceof Protobuf.Enum) { + importedTypes = `${dependency.name} as ${typeInterfaceName}`; + } else if (dependency instanceof Protobuf.Service) { + importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; + } else { + throw new Error('Invalid object passed to getImportLine'); + } + } + return `import type { ${importedTypes} } from '${filePath}';` +} + +function getChildMessagesAndEnums(namespace: Protobuf.NamespaceBase): (Protobuf.Type | Protobuf.Enum)[] { + const messageList: (Protobuf.Type | Protobuf.Enum)[] = []; + for (const nested of namespace.nestedArray) { + if (nested instanceof Protobuf.Type || nested instanceof Protobuf.Enum) { + messageList.push(nested); + } + if (isNamespaceBase(nested)) { + messageList.push(...getChildMessagesAndEnums(nested)); + } + } + return messageList; +} + +function formatComment(formatter: TextFormatter, comment?: string | null) { + if (!comment) { + return; + } + formatter.writeLine('/**'); + for(const line of comment.split('\n')) { + formatter.writeLine(` * ${line.replace(/\*\//g, '* /')}`); + } + formatter.writeLine(' */'); +} + +// GENERATOR FUNCTIONS + +function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null): string { + switch (fieldType) { + case 'double': + case 'float': + return 'number | string'; + case 'int32': + case 'uint32': + case 'sint32': + case 'fixed32': + case 'sfixed32': + return 'number'; + case 'int64': + case 'uint64': + case 'sint64': + case 'fixed64': + case 'sfixed64': + return 'number | string | Long'; + case 'bool': + return 'boolean'; + case 'string': + return 'string'; + case 'bytes': + return 'Buffer | Uint8Array | string'; + default: + if (resolvedType === null) { + throw new Error('Found field with no usable type'); + } + const typeInterfaceName = getTypeInterfaceName(resolvedType); + if (resolvedType instanceof Protobuf.Type) { + return typeInterfaceName; + } else { + return `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; + } + } +} + +function getFieldTypePermissive(field: Protobuf.FieldBase): string { + const valueType = getTypeNamePermissive(field.type, field.resolvedType); + if (field instanceof Protobuf.MapField) { + const keyType = field.keyType === 'string' ? 'string' : 'number'; + return `{[key: ${keyType}]: ${valueType}}`; + } else { + return valueType; + } +} + +function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { + if (options.includeComments) { + formatComment(formatter, messageType.comment); + } + if (messageType.fullName === '.google.protobuf.Any') { + /* This describes the behavior of the Protobuf.js Any wrapper fromObject + * replacement function */ + formatter.writeLine('export type Any = AnyExtension | {'); + formatter.writeLine(' type_url: string;'); + formatter.writeLine(' value: Buffer | Uint8Array | string;'); + formatter.writeLine('}'); + return; + } + formatter.writeLine(`export interface ${nameOverride ?? messageType.name} {`); + formatter.indent(); + for (const field of messageType.fieldsArray) { + const repeatedString = field.repeated ? '[]' : ''; + const type: string = getFieldTypePermissive(field); + if (options.includeComments) { + formatComment(formatter, field.comment); + } + formatter.writeLine(`'${field.name}'?: (${type})${repeatedString};`); + } + for (const oneof of messageType.oneofsArray) { + const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); + if (options.includeComments) { + formatComment(formatter, oneof.comment); + } + formatter.writeLine(`'${oneof.name}'?: ${typeString};`); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, options: GeneratorOptions): string { + switch (fieldType) { + case 'double': + case 'float': + if (options.json) { + return 'number | string'; + } else { + return 'number'; + } + case 'int32': + case 'uint32': + case 'sint32': + case 'fixed32': + case 'sfixed32': + return 'number'; + case 'int64': + case 'uint64': + case 'sint64': + case 'fixed64': + case 'sfixed64': + if (options.longs === Number) { + return 'number'; + } else if (options.longs === String) { + return 'string'; + } else { + return 'Long'; + } + case 'bool': + return 'boolean'; + case 'string': + return 'string'; + case 'bytes': + if (options.bytes === Array) { + return 'Uint8Array'; + } else if (options.bytes === String) { + return 'string'; + } else { + return 'Buffer'; + } + default: + if (resolvedType === null) { + throw new Error('Found field with no usable type'); + } + const typeInterfaceName = getTypeInterfaceName(resolvedType); + if (resolvedType instanceof Protobuf.Type) { + return typeInterfaceName + '__Output'; + } else { + if (options.enums == String) { + return `keyof typeof ${typeInterfaceName}`; + } else { + return typeInterfaceName; + } + } + } +} + +function getFieldTypeRestricted(field: Protobuf.FieldBase, options: GeneratorOptions): string { + const valueType = getTypeNameRestricted(field.type, field.resolvedType, options); + if (field instanceof Protobuf.MapField) { + const keyType = field.keyType === 'string' ? 'string' : 'number'; + return `{[key: ${keyType}]: ${valueType}}`; + } else { + return valueType; + } +} + +function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { + if (options.includeComments) { + formatComment(formatter, messageType.comment); + } + if (messageType.fullName === '.google.protobuf.Any' && options.json) { + /* This describes the behavior of the Protobuf.js Any wrapper toObject + * replacement function */ + let optionalString = options.defaults ? '' : '?'; + formatter.writeLine('export type Any__Output = AnyExtension | {'); + formatter.writeLine(` type_url${optionalString}: string;`); + formatter.writeLine(` value${optionalString}: ${getTypeNameRestricted('bytes', null, options)};`); + formatter.writeLine('}'); + return; + } + formatter.writeLine(`export interface ${nameOverride ?? messageType.name}__Output {`); + formatter.indent(); + for (const field of messageType.fieldsArray) { + let fieldGuaranteed: boolean; + if (field.partOf) { + // The field is not guaranteed populated if it is part of a oneof + fieldGuaranteed = false; + } else if (field.repeated) { + fieldGuaranteed = (options.defaults || options.arrays) ?? false; + } else if (field.resolvedType) { + if (field.resolvedType instanceof Protobuf.Enum) { + fieldGuaranteed = options.defaults ?? false; + } else { + // Message fields can always be omitted + fieldGuaranteed = false; + } + } else { + if (field.map) { + fieldGuaranteed = (options.defaults || options.objects) ?? false; + } else { + fieldGuaranteed = options.defaults ?? false; + } + } + const optionalString = fieldGuaranteed ? '' : '?'; + const repeatedString = field.repeated ? '[]' : ''; + const type = getFieldTypeRestricted(field, options); + if (options.includeComments) { + formatComment(formatter, field.comment); + } + formatter.writeLine(`'${field.name}'${optionalString}: (${type})${repeatedString};`); + } + if (options.oneofs) { + for (const oneof of messageType.oneofsArray) { + const typeString = oneof.fieldsArray.map(field => `"${field.name}"`).join('|'); + if (options.includeComments) { + formatComment(formatter, oneof.comment); + } + formatter.writeLine(`'${oneof.name}': ${typeString};`); + } + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateMessageInterfaces(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions) { + let usesLong: boolean = false; + let seenDeps: Set = new Set(); + const childTypes = getChildMessagesAndEnums(messageType); + formatter.writeLine(`// Original file: ${messageType.filename}`); + formatter.writeLine(''); + messageType.fieldsArray.sort((fieldA, fieldB) => fieldA.id - fieldB.id); + for (const field of messageType.fieldsArray) { + if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { + const dependency = field.resolvedType; + if (seenDeps.has(dependency.fullName)) { + continue; + } + seenDeps.add(dependency.fullName); + formatter.writeLine(getImportLine(dependency, messageType)); + } + if (field.type.indexOf('64') >= 0) { + usesLong = true; + } + } + for (const childType of childTypes) { + if (childType instanceof Protobuf.Type) { + for (const field of childType.fieldsArray) { + if (field.resolvedType && childTypes.indexOf(field.resolvedType) < 0) { + const dependency = field.resolvedType; + if (seenDeps.has(dependency.fullName)) { + continue; + } + seenDeps.add(dependency.fullName); + formatter.writeLine(getImportLine(dependency, messageType)); + } + if (field.type.indexOf('64') >= 0) { + usesLong = true; + } + } + } + } + if (usesLong) { + formatter.writeLine("import type { Long } from '@grpc/proto-loader';"); + } + if (messageType.fullName === '.google.protobuf.Any') { + formatter.writeLine("import type { AnyExtension } from '@grpc/proto-loader';") + } + formatter.writeLine(''); + for (const childType of childTypes.sort(compareName)) { + const nameOverride = getTypeInterfaceName(childType); + if (childType instanceof Protobuf.Type) { + generatePermissiveMessageInterface(formatter, childType, options, nameOverride); + formatter.writeLine(''); + generateRestrictedMessageInterface(formatter, childType, options, nameOverride); + } else { + generateEnumInterface(formatter, childType, options, nameOverride); + } + formatter.writeLine(''); + } + + generatePermissiveMessageInterface(formatter, messageType, options); + formatter.writeLine(''); + generateRestrictedMessageInterface(formatter, messageType, options); +} + +function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, options: GeneratorOptions, nameOverride?: string) { + formatter.writeLine(`// Original file: ${enumType.filename}`); + formatter.writeLine(''); + if (options.includeComments) { + formatComment(formatter, enumType.comment); + } + formatter.writeLine(`export enum ${nameOverride ?? enumType.name} {`); + formatter.indent(); + for (const key of Object.keys(enumType.values)) { + if (options.includeComments) { + formatComment(formatter, enumType.comments[key]); + } + formatter.writeLine(`${key} = ${enumType.values[key]},`); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + if (options.includeComments) { + formatComment(formatter, serviceType.comment); + } + formatter.writeLine(`export interface ${serviceType.name}Client extends grpc.Client {`); + formatter.indent(); + for (const methodName of Object.keys(serviceType.methods).sort()) { + const method = serviceType.methods[methodName]; + for (const name of [methodName, camelCase(methodName)]) { + if (options.includeComments) { + formatComment(formatter, method.comment); + } + const requestType = getTypeInterfaceName(method.resolvedRequestType!); + const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; + const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; + if (method.requestStream) { + if (method.responseStream) { + // Bidi streaming + const callType = `grpc.ClientDuplexStream<${requestType}, ${responseType}>`; + formatter.writeLine(`${name}(metadata: grpc.Metadata, options?: grpc.CallOptions): ${callType};`); + formatter.writeLine(`${name}(options?: grpc.CallOptions): ${callType};`); + } else { + // Client streaming + const callType = `grpc.ClientWritableStream<${requestType}>`; + formatter.writeLine(`${name}(metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(callback: ${callbackType}): ${callType};`); + } + } else { + if (method.responseStream) { + // Server streaming + const callType = `grpc.ClientReadableStream<${responseType}>`; + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options?: grpc.CallOptions): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, options?: grpc.CallOptions): ${callType};`); + } else { + // Unary + const callType = 'grpc.ClientUnaryCall'; + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, metadata: grpc.Metadata, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, options: grpc.CallOptions, callback: ${callbackType}): ${callType};`); + formatter.writeLine(`${name}(argument: ${requestType}, callback: ${callbackType}): ${callType};`); + } + } + } + formatter.writeLine(''); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + if (options.includeComments) { + formatComment(formatter, serviceType.comment); + } + formatter.writeLine(`export interface ${serviceType.name}Handlers extends grpc.UntypedServiceImplementation {`); + formatter.indent(); + for (const methodName of Object.keys(serviceType.methods).sort()) { + const method = serviceType.methods[methodName]; + if (options.includeComments) { + formatComment(formatter, method.comment); + } + const requestType = getTypeInterfaceName(method.resolvedRequestType!) + '__Output'; + const responseType = getTypeInterfaceName(method.resolvedResponseType!); + if (method.requestStream) { + if (method.responseStream) { + // Bidi streaming + formatter.writeLine(`${methodName}: grpc.handleBidiStreamingCall<${requestType}, ${responseType}>;`); + } else { + // Client streaming + formatter.writeLine(`${methodName}: grpc.handleClientStreamingCall<${requestType}, ${responseType}>;`); + } + } else { + if (method.responseStream) { + // Server streaming + formatter.writeLine(`${methodName}: grpc.handleServerStreamingCall<${requestType}, ${responseType}>;`); + } else { + // Unary + formatter.writeLine(`${methodName}: grpc.handleUnaryCall<${requestType}, ${responseType}>;`); + } + } + formatter.writeLine(''); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + formatter.writeLine(`// Original file: ${serviceType.filename}`); + formatter.writeLine(''); + const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; + formatter.writeLine(`import type * as grpc from '${grpcImportPath}'`); + const dependencies: Set = new Set(); + for (const method of serviceType.methodsArray) { + dependencies.add(method.resolvedRequestType!); + dependencies.add(method.resolvedResponseType!); + } + for (const dep of Array.from(dependencies.values()).sort(compareName)) { + formatter.writeLine(getImportLine(dep, serviceType)); + } + formatter.writeLine(''); + + generateServiceClientInterface(formatter, serviceType, options); + formatter.writeLine(''); + + generateServiceHandlerInterface(formatter, serviceType, options); +} + +function generateServiceImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { + for (const nested of namespace.nestedArray.sort(compareName)) { + if (nested instanceof Protobuf.Service) { + formatter.writeLine(getImportLine(nested)); + } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { + generateServiceImports(formatter, nested, options); + } + } +} + +function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Protobuf.ReflectionObject, options: GeneratorOptions) { + if (nested instanceof Protobuf.Service) { + if (options.includeComments) { + formatComment(formatter, nested.comment); + } + formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) + } else if (nested instanceof Protobuf.Enum) { + formatter.writeLine(`${nested.name}: EnumTypeDefinition`); + } else if (nested instanceof Protobuf.Type) { + formatter.writeLine(`${nested.name}: MessageTypeDefinition`); + } else if (isNamespaceBase(nested)) { + generateLoadedDefinitionTypes(formatter, nested, options); + } +} + +function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { + formatter.writeLine(`${namespace.name}: {`); + formatter.indent(); + for (const nested of namespace.nestedArray.sort(compareName)) { + generateSingleLoadedDefinitionType(formatter, nested, options); + } + formatter.unindent(); + formatter.writeLine('}'); +} + +function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { + formatter.writeLine(`import type * as grpc from '${options.grpcLib}';`); + formatter.writeLine("import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); + formatter.writeLine(''); + + generateServiceImports(formatter, root, options); + formatter.writeLine(''); + + formatter.writeLine('type SubtypeConstructor any, Subtype> = {'); + formatter.writeLine(' new(...args: ConstructorParameters): Subtype;'); + formatter.writeLine('};'); + formatter.writeLine(''); + + formatter.writeLine('export interface ProtoGrpcType {'); + formatter.indent(); + for (const nested of root.nestedArray) { + generateSingleLoadedDefinitionType(formatter, nested, options); + } + formatter.unindent(); + formatter.writeLine('}'); + formatter.writeLine(''); +} + +async function writeFile(filename: string, contents: string): Promise { + await fs.promises.mkdir(path.dirname(filename), {recursive: true}); + return fs.promises.writeFile(filename, contents); +} + +function generateFilesForNamespace(namespace: Protobuf.NamespaceBase, options: GeneratorOptions): Promise[] { + const filePromises : Promise[] = []; + for (const nested of namespace.nestedArray) { + const fileFormatter = new TextFormatter(); + if (nested instanceof Protobuf.Type) { + generateMessageInterfaces(fileFormatter, nested, options); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + } + filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + } else if (nested instanceof Protobuf.Enum) { + generateEnumInterface(fileFormatter, nested, options); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + } + filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + } else if (nested instanceof Protobuf.Service) { + generateServiceInterfaces(fileFormatter, nested, options); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${getPath(nested)} from file ${nested.filename}`); + } + filePromises.push(writeFile(`${options.outDir}/${getPath(nested)}`, fileFormatter.getFullText())); + } else if (isNamespaceBase(nested)) { + filePromises.push(...generateFilesForNamespace(nested, options)); + } + } + return filePromises; +} + +function writeFilesForRoot(root: Protobuf.Root, masterFileName: string, options: GeneratorOptions): Promise[] { + const filePromises: Promise[] = []; + + const masterFileFormatter = new TextFormatter(); + generateRootFile(masterFileFormatter, root, options); + if (options.verbose) { + console.log(`Writing ${options.outDir}/${masterFileName}`); + } + filePromises.push(writeFile(`${options.outDir}/${masterFileName}`, masterFileFormatter.getFullText())); + + filePromises.push(...generateFilesForNamespace(root, options)); + + return filePromises; +} + +async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { + await fs.promises.mkdir(options.outDir, {recursive: true}); + for (const filename of protoFiles) { + const loadedRoot = await loadProtosWithOptions(filename, options); + writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.ts'), options); + } +} + +function runScript() { + const argv = yargs + .string(['includeDirs', 'grpcLib']) + .normalize(['includeDirs', 'outDir']) + .array('includeDirs') + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) +// .choices('longs', ['String', 'Number']) +// .choices('enums', ['String']) +// .choices('bytes', ['Array', 'String']) + .string(['longs', 'enums', 'bytes']) + .coerce('longs', value => { + switch (value) { + case 'String': return String; + case 'Number': return Number; + default: return undefined; + } + }).coerce('enums', value => { + if (value === 'String') { + return String; + } else { + return undefined; + } + }).coerce('bytes', value => { + switch (value) { + case 'Array': return Array; + case 'String': return String; + default: return undefined; + } + }).alias({ + includeDirs: 'I', + outDir: 'O', + verbose: 'v' + }).describe({ + keepCase: 'Preserve the case of field names', + longs: 'The type that should be used to output 64 bit integer values. Can be String, Number', + enums: 'The type that should be used to output enum fields. Can be String', + bytes: 'The type that should be used to output bytes fields. Can be String, Array', + defaults: 'Output default values for omitted fields', + arrays: 'Output default values for omitted repeated fields even if --defaults is not set', + objects: 'Output default values for omitted message fields even if --defaults is not set', + oneofs: 'Output virtual oneof fields set to the present field\'s name', + json: 'Represent Infinity and NaN as strings in float fields. Also decode google.protobuf.Any automatically', + includeComments: 'Generate doc comments from comments in the original files', + includeDirs: 'Directories to search for included files', + outDir: 'Directory in which to output files', + grpcLib: 'The gRPC implementation library that these types will be used with' + }).demandOption(['outDir', 'grpcLib']) + .demand(1) + .usage('$0 [options] filenames...') + .epilogue('WARNING: This tool is in alpha. The CLI and generated code are subject to change') + .argv; + if (argv.verbose) { + console.log('Parsed arguments:', argv); + } + addCommonProtos(); + writeAllFiles(argv._, {...argv, alternateCommentMode: true}).then(() => { + if (argv.verbose) { + console.log('Success'); + } + }, (error) => { + throw error; + }) +} + +if (require.main === module) { + runScript(); +} From 374309be66b908a58de667587d6eaa87cef3de93 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 5 Jan 2021 09:15:17 -0800 Subject: [PATCH 1334/1899] grpc-js: Propagate internal stream errors from the http2 module --- packages/grpc-js/src/call-stream.ts | 138 +++++++++++++++++----------- 1 file changed, 82 insertions(+), 56 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 91e24ea55..9c27aeb1f 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -37,6 +37,10 @@ const { NGHTTP2_CANCEL, } = http2.constants; +interface NodeError extends Error { + code: string; +} + export type Deadline = Date | number; export interface CallStreamOptions { @@ -202,6 +206,8 @@ export class Http2CallStream implements Call { private listener: InterceptingListener | null = null; + private internalErrorMessage: string | null = null; + constructor( private readonly methodName: string, private readonly channel: ChannelImplementation, @@ -518,66 +524,86 @@ export class Http2CallStream implements Call { this.maybeOutputStatus(); }); stream.on('close', () => { - this.trace('HTTP/2 stream closed with code ' + stream.rstCode); - /* If we have a final status with an OK status code, that means that - * we have received all of the messages and we have processed the - * trailers and the call completed successfully, so it doesn't matter - * how the stream ends after that */ - if (this.finalStatus?.code === Status.OK) { - return; - } - let code: Status; - let details = ''; - switch (stream.rstCode) { - case http2.constants.NGHTTP2_NO_ERROR: - /* If we get a NO_ERROR code and we already have a status, the - * stream completed properly and we just haven't fully processed - * it yet */ - if (this.finalStatus !== null) { - return; - } - code = Status.INTERNAL; - details = `Received RST_STREAM with code ${stream.rstCode}`; - break; - case http2.constants.NGHTTP2_REFUSED_STREAM: - code = Status.UNAVAILABLE; - details = 'Stream refused by server'; - break; - case http2.constants.NGHTTP2_CANCEL: - code = Status.CANCELLED; - details = 'Call cancelled'; - break; - case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: - code = Status.RESOURCE_EXHAUSTED; - details = 'Bandwidth exhausted'; - break; - case http2.constants.NGHTTP2_INADEQUATE_SECURITY: - code = Status.PERMISSION_DENIED; - details = 'Protocol not secure enough'; - break; - case http2.constants.NGHTTP2_INTERNAL_ERROR: - code = Status.INTERNAL; - /* This error code was previously handled in the default case, and - * there are several instances of it online, so I wanted to - * preserve the original error message so that people find existing - * information in searches, but also include the more recognizable - * "Internal server error" message. */ - details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; - break; - default: - code = Status.INTERNAL; - details = `Received RST_STREAM with code ${stream.rstCode}`; - } - // This is a no-op if trailers were received at all. - // This is OK, because status codes emitted here correspond to more - // catastrophic issues that prevent us from receiving trailers in the - // first place. - this.endCall({ code, details, metadata: new Metadata() }); + /* Use process.next tick to ensure that this code happens after any + * "error" event that may be emitted at about the same time, so that + * we can bubble up the error message from that event. */ + process.nextTick(() => { + this.trace('HTTP/2 stream closed with code ' + stream.rstCode); + /* If we have a final status with an OK status code, that means that + * we have received all of the messages and we have processed the + * trailers and the call completed successfully, so it doesn't matter + * how the stream ends after that */ + if (this.finalStatus?.code === Status.OK) { + return; + } + let code: Status; + let details = ''; + switch (stream.rstCode) { + case http2.constants.NGHTTP2_NO_ERROR: + /* If we get a NO_ERROR code and we already have a status, the + * stream completed properly and we just haven't fully processed + * it yet */ + if (this.finalStatus !== null) { + return; + } + code = Status.INTERNAL; + details = `Received RST_STREAM with code ${stream.rstCode}`; + break; + case http2.constants.NGHTTP2_REFUSED_STREAM: + code = Status.UNAVAILABLE; + details = 'Stream refused by server'; + break; + case http2.constants.NGHTTP2_CANCEL: + code = Status.CANCELLED; + details = 'Call cancelled'; + break; + case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: + code = Status.RESOURCE_EXHAUSTED; + details = 'Bandwidth exhausted'; + break; + case http2.constants.NGHTTP2_INADEQUATE_SECURITY: + code = Status.PERMISSION_DENIED; + details = 'Protocol not secure enough'; + break; + case http2.constants.NGHTTP2_INTERNAL_ERROR: + code = Status.INTERNAL; + if (this.internalErrorMessage === null) { + /* This error code was previously handled in the default case, and + * there are several instances of it online, so I wanted to + * preserve the original error message so that people find existing + * information in searches, but also include the more recognizable + * "Internal server error" message. */ + details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; + } else { + /* The "Received RST_STREAM with code ..." error is preserved + * here for continuity with errors reported online, but the + * error message at the end will probably be more relevant in + * most cases. */ + details = `Received RST_STREAM with code ${stream.rstCode} triggered by internal client error: ${this.internalErrorMessage}`; + } + break; + default: + code = Status.INTERNAL; + details = `Received RST_STREAM with code ${stream.rstCode}`; + } + // This is a no-op if trailers were received at all. + // This is OK, because status codes emitted here correspond to more + // catastrophic issues that prevent us from receiving trailers in the + // first place. + this.endCall({ code, details, metadata: new Metadata() }); + }); }); - stream.on('error', (err: Error) => { + stream.on('error', (err: NodeError) => { /* We need an error handler here to stop "Uncaught Error" exceptions * from bubbling up. However, errors here should all correspond to * "close" events, where we will handle the error more granularly */ + /* Specifically looking for stream errors that were *not* constructed + * from a RST_STREAM response here: + * https://github.com/nodejs/node/blob/8b8620d580314050175983402dfddf2674e8e22a/lib/internal/http2/core.js#L2267 + */ + if (err.code !== 'ERR_HTTP2_STREAM_ERROR') { + this.internalErrorMessage = err.message; + } }); if (!this.pendingRead) { stream.pause(); From ac86173a2036ab502edc9e9b94d568d0d5fc0742 Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Fri, 8 Jan 2021 08:11:24 +0000 Subject: [PATCH 1335/1899] proto-loader: Add example usage to README --- packages/proto-loader/README.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 7a97a3b1b..198f9d2bf 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -57,7 +57,7 @@ const options = { The `proto-loader-gen-types` script distributed with this package can be used to generate TypeScript type information for the objects loaded at runtime. More information about how to use it can be found in [the *@grpc/proto-loader TypeScript Type Generator CLI Tool* proposal document](https://github.com/grpc/proposal/blob/master/L70-node-proto-loader-type-generator.md). The arguments mostly match the `load` function's options; the full usage information is as follows: -``` +```console proto-loader-gen-types.js [options] filenames... Options: @@ -85,4 +85,33 @@ Options: --outDir, -O Directory in which to output files [string] [required] --grpcLib The gRPC implementation library that these types will be used with [string] [required] -``` \ No newline at end of file +``` + +### Example Usage + +Generate the types: + +```sh +$(npm bin)/proto-loader-gen-types --longs=String --enums=String --defaults --oneofs --grpcLib=@grpc/grpc-js --outDir=proto/ proto/*.proto +``` + +Consume the types: + +```ts +import * as grpc from '@grpc/grpc-js'; +import * as protoLoader from '@grpc/proto-loader'; +import { ProtoGrpcType } from './proto/example'; +import { ExampleHandlers } from './proto/example_package/Example'; + +const exampleServer: ExampleHandlers = { + // server handlers implementation... +}; + +const packageDefinition = protoLoader.loadSync('./proto/example.proto'); +const proto = (grpc.loadPackageDefinition( + packageDefinition +) as unknown) as ProtoGrpcType; + +const server = new grpc.Server(); +server.addService(proto.example_package.Example.service, exampleServer); +``` From cf9d0fd4cc16ab7547e6915bcc0f3a2941418abc Mon Sep 17 00:00:00 2001 From: Richard Willis Date: Fri, 8 Jan 2021 08:11:35 +0000 Subject: [PATCH 1336/1899] proto-loader: Fix yargs types --- packages/proto-loader/bin/proto-loader-gen-types.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index bd294aa66..8a8a082d9 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -678,6 +678,9 @@ async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { function runScript() { const argv = yargs + .parserConfiguration({ + 'parse-positional-numbers': false + }) .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') @@ -731,7 +734,7 @@ function runScript() { console.log('Parsed arguments:', argv); } addCommonProtos(); - writeAllFiles(argv._, {...argv, alternateCommentMode: true}).then(() => { + writeAllFiles(argv._ as string[], {...argv, alternateCommentMode: true}).then(() => { if (argv.verbose) { console.log('Success'); } From 36986f618a8455ade8ddeeafe5292bbba7104e79 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Jan 2021 13:43:56 -0800 Subject: [PATCH 1337/1899] grpc-js: round robin: re-resolve when subchannels go idle --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/load-balancer-round-robin.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 17fb1a2e5..60d3c908f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.3", + "version": "1.2.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index fc9bef0c7..daba45941 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -128,14 +128,12 @@ export class RoundRobinLoadBalancer implements LoadBalancer { this.subchannelStateCounts[previousState] -= 1; this.subchannelStateCounts[newState] += 1; this.calculateAndUpdateState(); - - if (newState === ConnectivityState.TRANSIENT_FAILURE) { - this.channelControlHelper.requestReresolution(); - } + if ( newState === ConnectivityState.TRANSIENT_FAILURE || newState === ConnectivityState.IDLE ) { + this.channelControlHelper.requestReresolution(); subchannel.startConnecting(); } }; From 7837e8e845226e2153fc103afadd23329b03d958 Mon Sep 17 00:00:00 2001 From: Andrey Melnik Date: Wed, 20 Jan 2021 01:00:57 +0300 Subject: [PATCH 1338/1899] feature(grpc-js): Add possibility to provide maxSessionMemory http2 option through ChannelOptions --- packages/grpc-js/src/channel-options.ts | 2 ++ packages/grpc-js/src/server.ts | 5 ++++- packages/grpc-js/src/subchannel.ts | 3 +++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index df6cbb2b1..e1ad94dce 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -28,6 +28,7 @@ export interface ChannelOptions { 'grpc.keepalive_permit_without_calls'?: number; 'grpc.service_config'?: string; 'grpc.max_concurrent_streams'?: number; + 'grpc.max_session_memory'?: number; 'grpc.initial_reconnect_backoff_ms'?: number; 'grpc.max_reconnect_backoff_ms'?: number; 'grpc.use_local_subchannel_pool'?: number; @@ -53,6 +54,7 @@ export const recognizedOptions = { 'grpc.keepalive_permit_without_calls': true, 'grpc.service_config': true, 'grpc.max_concurrent_streams': true, + 'grpc.max_session_memory': true, 'grpc.initial_reconnect_backoff_ms': true, 'grpc.max_reconnect_backoff_ms': true, 'grpc.use_local_subchannel_pool': true, diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 335a11fce..fe906af20 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -258,8 +258,11 @@ export class Server { } const serverOptions: http2.ServerOptions = { - maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER + maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER, }; + if ('grpc.max_session_memory' in this.options) { + serverOptions.maxSessionMemory = this.options['grpc.max_session_memory']; + } if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { maxConcurrentStreams: this.options['grpc.max_concurrent_streams'], diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c32ee43ea..bcbd8877e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -307,6 +307,9 @@ export class Subchannel { let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; + if ('grpc.max_session_memory' in this.options) { + connectionOptions.maxSessionMemory = this.options['grpc.max_session_memory']; + } let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { addressScheme = 'https://'; From b2776b52b4835bafdd0af141b97bfe5cc14b94b9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Jan 2021 14:36:41 -0800 Subject: [PATCH 1339/1899] proto-loader: bump to 0.5.6 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 155a0abfa..f0611b2b5 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.5.5", + "version": "0.5.6", "author": "Google Inc.", "contributors": [ { From 85111c2b0bb1e9652ca0a66db23e9a8fc3a6ce70 Mon Sep 17 00:00:00 2001 From: Srini Polavarapu Date: Fri, 22 Jan 2021 10:57:55 -0800 Subject: [PATCH 1340/1899] Add security policy doc --- SECURITY.md | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..be6e10870 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# Security Policy + +For information on gRPC Security Policy and reporting potentional security issues, please see [gRPC CVE Process](https://github.com/grpc/proposal/blob/master/P4-grpc-cve-process.md). From 5ac9a1c2b617e4ea0dab56a73c60564e9fc5b1bb Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 25 Jan 2021 13:24:39 -0800 Subject: [PATCH 1341/1899] grpc-js: Move call to user code out of try block --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/client-interceptors.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 60d3c908f..01a9d418f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.4", + "version": "1.2.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 09e7f5aa5..a7cc2f878 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -347,10 +347,11 @@ class BaseInterceptingCall implements InterceptingCallInterface { let serialized: Buffer; try { serialized = this.methodDefinition.requestSerialize(message); - this.call.sendMessageWithContext(context, serialized); } catch (e) { this.call.cancelWithStatus(Status.INTERNAL, `Request message serialization failure: ${e.message}`); + return; } + this.call.sendMessageWithContext(context, serialized); } // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessage(message: any) { @@ -370,7 +371,6 @@ class BaseInterceptingCall implements InterceptingCallInterface { let deserialized: any; try { deserialized = this.methodDefinition.responseDeserialize(message); - interceptingListener?.onReceiveMessage?.(deserialized); } catch (e) { readError = { code: Status.INTERNAL, @@ -378,7 +378,9 @@ class BaseInterceptingCall implements InterceptingCallInterface { metadata: new Metadata(), }; this.call.cancelWithStatus(readError.code, readError.details); + return; } + interceptingListener?.onReceiveMessage?.(deserialized); }, onReceiveStatus: (status) => { if (readError) { From b011bd069dc75699f0f4e9b6d668278e840331f8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 27 Jan 2021 11:15:04 -0800 Subject: [PATCH 1342/1899] grpc-js-xds: List the files to publish in package.json --- packages/grpc-js-xds/package.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 6c7349275..d8c2d48c2 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -49,5 +49,19 @@ }, "engines": { "node": ">=10.10.0" - } + }, + "files": [ + "src/**/*.ts", + "build/src/**/*.{js,d.ts,js.map}", + "deps/envoy-api/envoy/api/v2/**/*.proto", + "deps/envoy-api/envoy/config/**/*.proto", + "deps/envoy-api/envoy/service/**/*.proto", + "deps/envoy-api/envoy/type/**/*.proto", + "deps/envoy-api/envoy/annotations/**/*.proto", + "deps/googleapis/google/api/**/*.proto", + "deps/googleapis/google/protobuf/**/*.proto", + "deps/googleapis/google/rpc/**/*.proto", + "deps/udpa/udpa/annotations/**/*.proto", + "deps/protoc-gen-validate/validate/**/*.proto" + ] } From 0a98f6295dc1e4fb64f3d1d0f3e005da947ea627 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 27 Jan 2021 12:16:06 -0800 Subject: [PATCH 1343/1899] grpc-js-xds: Bubble up xds client initialization errors --- packages/grpc-js-xds/src/resolver-xds.ts | 8 ++++---- packages/grpc-js-xds/src/xds-client.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 24d25b974..f9e5264a4 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -39,12 +39,12 @@ class XdsResolver implements Resolver { private channelOptions: ChannelOptions ) {} - private reportResolutionError() { + private reportResolutionError(reason: string) { this.listener.onError({ code: status.UNAVAILABLE, details: `xDS name resolution failed for target ${uriToString( this.target - )}`, + )}: ${reason}`, metadata: new Metadata(), }); } @@ -68,12 +68,12 @@ class XdsResolver implements Resolver { * not already provided a ServiceConfig for the upper layer to use */ if (!this.hasReportedSuccess) { trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); - this.reportResolutionError(); + this.reportResolutionError(error.details); } }, onResourceDoesNotExist: () => { trace('Resolution error for target ' + uriToString(this.target) + ': resource does not exist'); - this.reportResolutionError(); + this.reportResolutionError("Resource does not exist"); }, }, this.channelOptions diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index da75dc7c7..ae67960d7 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -1155,7 +1155,7 @@ export class XdsClient { } removeClusterWatcher(clusterName: string, watcher: Watcher) { - trace('Watcher removed for endpoint ' + clusterName); + trace('Watcher removed for cluster ' + clusterName); this.adsState[CDS_TYPE_URL].removeWatcher(clusterName, watcher); } From e27e4e02ae97f24e473508867a64cac83a2e2393 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 27 Jan 2021 14:02:41 -0800 Subject: [PATCH 1344/1899] Bump grpc-js-xds to 1.2.1 --- packages/grpc-js-xds/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index d8c2d48c2..f2b32a773 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.2.0", + "version": "1.2.1", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { From 8e5f5bc18a0f7d8fac4b85e33ddd49c0f5efa3ff Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Feb 2021 14:18:24 -0800 Subject: [PATCH 1345/1899] grpc-js: Add ConfigSelector to Resolver API and plumb it through the channel --- packages/grpc-js-xds/src/resolver-xds.ts | 2 +- packages/grpc-js/src/channel.ts | 66 +++++++++++++++---- packages/grpc-js/src/picker.ts | 1 + packages/grpc-js/src/resolver-dns.ts | 4 +- packages/grpc-js/src/resolver-uds.ts | 1 + packages/grpc-js/src/resolver.ts | 20 +++++- .../grpc-js/src/resolving-load-balancer.ts | 38 ++++++++++- 7 files changed, 113 insertions(+), 19 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 814294c81..e1a0af11a 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -60,7 +60,7 @@ class XdsResolver implements Resolver { onValidUpdate: (update: ServiceConfig) => { trace('Resolved service config for target ' + uriToString(this.target) + ': ' + JSON.stringify(update)); this.hasReportedSuccess = true; - this.listener.onSuccessfulResolution([], update, null, { + this.listener.onSuccessfulResolution([], update, null, null, { xdsClient: xdsClient, }); }, diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index e1a76c092..7c61aa1f9 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -33,7 +33,7 @@ import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; -import { getDefaultAuthority, mapUriDefaultScheme } from './resolver'; +import { CallConfig, ConfigSelector, getDefaultAuthority, mapUriDefaultScheme } from './resolver'; import { trace, log } from './logging'; import { SubchannelAddress } from './subchannel'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; @@ -136,9 +136,18 @@ export class ChannelImplementation implements Channel { private subchannelPool: SubchannelPool; private connectivityState: ConnectivityState = ConnectivityState.IDLE; private currentPicker: Picker = new UnavailablePicker(); + /** + * Calls queued up to get a call config. Should only be populated before the + * first time the resolver returns a result, which includes the ConfigSelector. + */ + private configSelectionQueue: Array<{ + callStream: Http2CallStream; + callMetadata: Metadata; + }> = []; private pickQueue: Array<{ callStream: Http2CallStream; callMetadata: Metadata; + callConfig: CallConfig; }> = []; private connectivityStateWatchers: ConnectivityStateWatcher[] = []; private defaultAuthority: string; @@ -152,6 +161,7 @@ export class ChannelImplementation implements Channel { * is non-empty. */ private callRefTimer: NodeJS.Timer; + private configSelector: ConfigSelector | null = null; constructor( target: string, private readonly credentials: ChannelCredentials, @@ -227,8 +237,8 @@ export class ChannelImplementation implements Channel { const queueCopy = this.pickQueue.slice(); this.callRefTimer.unref?.(); this.pickQueue = []; - for (const { callStream, callMetadata } of queueCopy) { - this.tryPick(callStream, callMetadata); + for (const { callStream, callMetadata, callConfig } of queueCopy) { + this.tryPick(callStream, callMetadata, callConfig); } this.updateState(connectivityState); }, @@ -242,7 +252,17 @@ export class ChannelImplementation implements Channel { this.resolvingLoadBalancer = new ResolvingLoadBalancer( this.target, channelControlHelper, - options + options, + (configSelector) => { + this.configSelector = configSelector; + /* We process the queue asynchronously to ensure that the corresponding + * load balancer update has completed. */ + process.nextTick(() => { + for (const {callStream, callMetadata} of this.configSelectionQueue) { + this.tryGetConfig(callStream, callMetadata); + } + }); + } ); this.filterStackFactory = new FilterStackFactory([ new CallCredentialsFilterFactory(this), @@ -252,9 +272,9 @@ export class ChannelImplementation implements Channel { ]); } - private pushPick(callStream: Http2CallStream, callMetadata: Metadata) { + private pushPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { this.callRefTimer.ref?.(); - this.pickQueue.push({ callStream, callMetadata }); + this.pickQueue.push({ callStream, callMetadata, callConfig }); } /** @@ -264,8 +284,8 @@ export class ChannelImplementation implements Channel { * @param callStream * @param callMetadata */ - private tryPick(callStream: Http2CallStream, callMetadata: Metadata) { - const pickResult = this.currentPicker.pick({ metadata: callMetadata }); + private tryPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { + const pickResult = this.currentPicker.pick({ metadata: callMetadata, extraPickInfo: callConfig.pickInformation }); trace( LogVerbosity.DEBUG, 'channel', @@ -301,7 +321,7 @@ export class ChannelImplementation implements Channel { ' has state ' + ConnectivityState[pickResult.subchannel!.getConnectivityState()] ); - this.pushPick(callStream, callMetadata); + this.pushPick(callStream, callMetadata, callConfig); break; } /* We need to clone the callMetadata here because the transparent @@ -321,6 +341,7 @@ export class ChannelImplementation implements Channel { ); /* If we reach this point, the call stream has started * successfully */ + callConfig.onCommitted?.(); pickResult.onCallStarted?.(); } catch (error) { if ( @@ -349,7 +370,7 @@ export class ChannelImplementation implements Channel { (error as Error).message + '. Retrying pick' ); - this.tryPick(callStream, callMetadata); + this.tryPick(callStream, callMetadata, callConfig); } else { trace( LogVerbosity.INFO, @@ -378,7 +399,7 @@ export class ChannelImplementation implements Channel { ConnectivityState[subchannelState] + ' after metadata filters. Retrying pick' ); - this.tryPick(callStream, callMetadata); + this.tryPick(callStream, callMetadata, callConfig); } }, (error: Error & { code: number }) => { @@ -392,11 +413,11 @@ export class ChannelImplementation implements Channel { } break; case PickResultType.QUEUE: - this.pushPick(callStream, callMetadata); + this.pushPick(callStream, callMetadata, callConfig); break; case PickResultType.TRANSIENT_FAILURE: if (callMetadata.getOptions().waitForReady) { - this.pushPick(callStream, callMetadata); + this.pushPick(callStream, callMetadata, callConfig); } else { callStream.cancelWithStatus( pickResult.status!.code, @@ -451,8 +472,25 @@ export class ChannelImplementation implements Channel { } } + private tryGetConfig(stream: Http2CallStream, metadata: Metadata) { + if (this.configSelector === null) { + this.callRefTimer.ref?.(); + this.configSelectionQueue.push({ + callStream: stream, + callMetadata: metadata + }); + } else { + const callConfig = this.configSelector(stream.getMethod(), metadata); + if (callConfig.status === Status.OK) { + this.tryPick(stream, metadata, callConfig); + } else { + stream.cancelWithStatus(callConfig.status, "Failed to route call to method " + stream.getMethod()); + } + } + } + _startCallStream(stream: Http2CallStream, metadata: Metadata) { - this.tryPick(stream, metadata.clone()); + this.tryGetConfig(stream, metadata.clone()); } close() { diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 184047b23..6df61b59a 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -85,6 +85,7 @@ export interface DropCallPickResult extends PickResult { export interface PickArgs { metadata: Metadata; + extraPickInfo: {[key: string]: string}; } /** diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 2db8a5e41..96d78f8a3 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -129,7 +129,7 @@ class DnsResolver implements Resolver { if (this.ipResult !== null) { trace('Returning IP address for target ' + uriToString(this.target)); setImmediate(() => { - this.listener.onSuccessfulResolution(this.ipResult!, null, null, {}); + this.listener.onSuccessfulResolution(this.ipResult!, null, null, null, {}); }); return; } @@ -192,6 +192,7 @@ class DnsResolver implements Resolver { this.latestLookupResult, this.latestServiceConfig, this.latestServiceConfigError, + null, {} ); }, @@ -237,6 +238,7 @@ class DnsResolver implements Resolver { this.latestLookupResult, this.latestServiceConfig, this.latestServiceConfigError, + null, {} ); } diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 14bc0176a..e7667c78a 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -40,6 +40,7 @@ class UdsResolver implements Resolver { this.addresses, null, null, + null, {} ); } diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 57c750aea..e91762341 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -15,13 +15,30 @@ * */ -import { ServiceConfig } from './service-config'; +import { MethodConfig, ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; import { ChannelOptions } from './channel-options'; +import { Metadata } from './metadata'; +import { Status } from './constants'; + +export interface CallConfig { + methodConfig: MethodConfig; + onCommitted?: () => void; + pickInformation: {[key: string]: string}; + status: Status; +} + +/** + * Selects a configuration for a method given the name and metadata. Defined in + * https://github.com/grpc/proposal/blob/master/A31-xds-timeout-support-and-config-selector.md#new-functionality-in-grpc + */ +export interface ConfigSelector { + (methodName: string, metadata: Metadata): CallConfig; +} /** * A listener object passed to the resolver's constructor that provides name @@ -41,6 +58,7 @@ export interface ResolverListener { addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: StatusObject | null, + configSelector: ConfigSelector | null, attributes: { [key: string]: unknown } ): void; /** diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 2ce59d0c2..039a17b0d 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -23,7 +23,7 @@ import { } from './load-balancer'; import { ServiceConfig, validateServiceConfig } from './service-config'; import { ConnectivityState } from './channel'; -import { createResolver, Resolver } from './resolver'; +import { ConfigSelector, createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; import { BackoffTimeout } from './backoff-timeout'; @@ -46,6 +46,36 @@ function trace(text: string): void { const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; +function getDefaultConfigSelector(serviceConfig: ServiceConfig | null): ConfigSelector { + return function defaultConfigSelector(methodName: string, metadata: Metadata) { + const splitName = methodName.split('/').filter(x => x.length > 0); + const service = splitName[0] ?? ''; + const method = splitName[1] ?? ''; + if (serviceConfig && serviceConfig.methodConfig) { + for (const methodConfig of serviceConfig.methodConfig) { + for (const name of methodConfig.name) { + if (name.service === service && (name.method === undefined || name.method === method)) { + return { + methodConfig: methodConfig, + pickInformation: {}, + status: Status.OK + }; + } + } + } + } + return { + methodConfig: {name: []}, + pickInformation: {}, + status: Status.OK + }; + } +} + +export interface ResolutionCallback { + (configSelector: ConfigSelector): void; +} + export class ResolvingLoadBalancer implements LoadBalancer { /** * The resolver class constructed for the target address. @@ -93,7 +123,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { constructor( private readonly target: GrpcUri, private readonly channelControlHelper: ChannelControlHelper, - private readonly channelOptions: ChannelOptions + private readonly channelOptions: ChannelOptions, + private readonly onSuccessfulResolution: ResolutionCallback ) { if (channelOptions['grpc.service_config']) { this.defaultServiceConfig = validateServiceConfig( @@ -134,6 +165,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { addressList: SubchannelAddress[], serviceConfig: ServiceConfig | null, serviceConfigError: ServiceError | null, + configSelector: ConfigSelector | null, attributes: { [key: string]: unknown } ) => { let workingServiceConfig: ServiceConfig | null = null; @@ -180,6 +212,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { loadBalancingConfig, attributes ); + const finalServiceConfig = workingServiceConfig ?? this.defaultServiceConfig; + this.onSuccessfulResolution(configSelector ?? getDefaultConfigSelector(finalServiceConfig)); }, onError: (error: StatusObject) => { this.handleResolutionFailure(error); From 887d2ef677e66a0a1a6e6cca1faa6467ad252e96 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Feb 2021 14:16:10 -0800 Subject: [PATCH 1346/1899] Kick the ResolvingLoadBalancer out of IDLE when the first call is started. --- packages/grpc-js/src/channel.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 7c61aa1f9..fd015aff2 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -261,6 +261,7 @@ export class ChannelImplementation implements Channel { for (const {callStream, callMetadata} of this.configSelectionQueue) { this.tryGetConfig(callStream, callMetadata); } + this.configSelectionQueue = []; }); } ); @@ -474,6 +475,11 @@ export class ChannelImplementation implements Channel { private tryGetConfig(stream: Http2CallStream, metadata: Metadata) { if (this.configSelector === null) { + /* This branch will only be taken at the beginning of the channel's life, + * before the resolver ever returns a result. So, the + * ResolvingLoadBalancer may be idle and if so it needs to be kicked + * because it now has a pending request. */ + this.resolvingLoadBalancer.exitIdle(); this.callRefTimer.ref?.(); this.configSelectionQueue.push({ callStream: stream, From 259e00b86623bc8a30fda6cf4cee86a293135935 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 3 Feb 2021 11:54:13 -0800 Subject: [PATCH 1347/1899] grpc-js: Loosen dependency on @types/node --- packages/grpc-js/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 01a9d418f..7e7f45877 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.5", + "version": "1.2.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", @@ -57,7 +57,7 @@ "posttest": "npm run check" }, "dependencies": { - "@types/node": "^12.12.47", + "@types/node": ">=12.12.47", "google-auth-library": "^6.1.1", "semver": "^6.2.0" }, From 3806a99760c901f6a0cb40a1f3b899434555a45d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Feb 2021 09:08:41 -0800 Subject: [PATCH 1348/1899] Add handling for early name resolution failures --- packages/grpc-js/src/channel.ts | 41 +++++++++++++++++-- .../grpc-js/src/resolving-load-balancer.ts | 8 +++- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index fd015aff2..6f6142339 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -235,8 +235,8 @@ export class ChannelImplementation implements Channel { updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.currentPicker = picker; const queueCopy = this.pickQueue.slice(); - this.callRefTimer.unref?.(); this.pickQueue = []; + this.callRefTimerUnref(); for (const { callStream, callMetadata, callConfig } of queueCopy) { this.tryPick(callStream, callMetadata, callConfig); } @@ -258,11 +258,30 @@ export class ChannelImplementation implements Channel { /* We process the queue asynchronously to ensure that the corresponding * load balancer update has completed. */ process.nextTick(() => { - for (const {callStream, callMetadata} of this.configSelectionQueue) { + const localQueue = this.configSelectionQueue; + this.configSelectionQueue = []; + this.callRefTimerUnref() + for (const {callStream, callMetadata} of localQueue) { this.tryGetConfig(callStream, callMetadata); } this.configSelectionQueue = []; }); + }, + (status) => { + if (this.configSelectionQueue.length > 0) { + trace(LogVerbosity.DEBUG, 'channel', 'Name resolution failed for target ' + uriToString(this.target) + ' with calls queued for config selection'); + } + const localQueue = this.configSelectionQueue; + this.configSelectionQueue = []; + this.callRefTimerUnref(); + for (const {callStream, callMetadata} of localQueue) { + if (callMetadata.getOptions().waitForReady) { + this.callRefTimerRef(); + this.configSelectionQueue.push({callStream, callMetadata}); + } else { + callStream.cancelWithStatus(status.code, status.details); + } + } } ); this.filterStackFactory = new FilterStackFactory([ @@ -273,9 +292,23 @@ export class ChannelImplementation implements Channel { ]); } + private callRefTimerRef() { + if (!this.callRefTimer.hasRef()) { + trace(LogVerbosity.DEBUG, 'channel', 'callRefTimer.ref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + this.pickQueue.length); + this.callRefTimer.ref?.(); + } + } + + private callRefTimerUnref() { + if (this.callRefTimer.hasRef()) { + trace(LogVerbosity.DEBUG, 'channel', 'callRefTimer.unref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + this.pickQueue.length); + this.callRefTimer.unref?.(); + } + } + private pushPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { - this.callRefTimer.ref?.(); this.pickQueue.push({ callStream, callMetadata, callConfig }); + this.callRefTimerRef(); } /** @@ -480,11 +513,11 @@ export class ChannelImplementation implements Channel { * ResolvingLoadBalancer may be idle and if so it needs to be kicked * because it now has a pending request. */ this.resolvingLoadBalancer.exitIdle(); - this.callRefTimer.ref?.(); this.configSelectionQueue.push({ callStream: stream, callMetadata: metadata }); + this.callRefTimerRef(); } else { const callConfig = this.configSelector(stream.getMethod(), metadata); if (callConfig.status === Status.OK) { diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 7cf7e36d9..84fe4ae1d 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -76,6 +76,10 @@ export interface ResolutionCallback { (configSelector: ConfigSelector): void; } +export interface ResolutionFailureCallback { + (status: StatusObject): void; +} + export class ResolvingLoadBalancer implements LoadBalancer { /** * The resolver class constructed for the target address. @@ -124,7 +128,8 @@ export class ResolvingLoadBalancer implements LoadBalancer { private readonly target: GrpcUri, private readonly channelControlHelper: ChannelControlHelper, private readonly channelOptions: ChannelOptions, - private readonly onSuccessfulResolution: ResolutionCallback + private readonly onSuccessfulResolution: ResolutionCallback, + private readonly onFailedResolution: ResolutionFailureCallback ) { if (channelOptions['grpc.service_config']) { this.defaultServiceConfig = validateServiceConfig( @@ -261,6 +266,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker(error) ); + this.onFailedResolution(error); } this.backoffTimeout.runOnce(); } From 9e084bce1965d5dfa0a14564a0cf66d05c005724 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Feb 2021 11:39:15 -0800 Subject: [PATCH 1349/1899] Handle absence of Timer#hasRef on older Node versions --- packages/grpc-js/src/channel.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6f6142339..dad8a5324 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -293,14 +293,16 @@ export class ChannelImplementation implements Channel { } private callRefTimerRef() { - if (!this.callRefTimer.hasRef()) { + // If the hasRef function does not exist, always run the code + if (!this.callRefTimer.hasRef?.()) { trace(LogVerbosity.DEBUG, 'channel', 'callRefTimer.ref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + this.pickQueue.length); this.callRefTimer.ref?.(); } } private callRefTimerUnref() { - if (this.callRefTimer.hasRef()) { + // If the hasRef function does not exist, always run the code + if ((!this.callRefTimer.hasRef) || (this.callRefTimer.hasRef())) { trace(LogVerbosity.DEBUG, 'channel', 'callRefTimer.unref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + this.pickQueue.length); this.callRefTimer.unref?.(); } From c3c39af8ac324c73fd46b44596b1fc3e41199141 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Feb 2021 12:10:04 -0800 Subject: [PATCH 1350/1899] grpc-js-xds: Add XdsClusterManager LB policy --- packages/grpc-js-xds/src/index.ts | 2 + .../src/load-balancer-xds-cluster-manager.ts | 286 ++++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 06bea9904..1b24d25e6 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -21,6 +21,7 @@ import * as load_balancer_eds from './load-balancer-eds'; import * as load_balancer_lrs from './load-balancer-lrs'; import * as load_balancer_priority from './load-balancer-priority'; import * as load_balancer_weighted_target from './load-balancer-weighted-target'; +import * as load_balancer_xds_cluster_manager from './load-balancer-xds-cluster-manager'; /** * Register the "xds:" name scheme with the @grpc/grpc-js library. @@ -32,4 +33,5 @@ export function register() { load_balancer_lrs.setup(); load_balancer_priority.setup(); load_balancer_weighted_target.setup(); + load_balancer_xds_cluster_manager.setup(); } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts new file mode 100644 index 000000000..c4f53759a --- /dev/null +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -0,0 +1,286 @@ +/* + * Copyright 2020 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { connectivityState as ConnectivityState, status as Status, experimental, logVerbosity, Metadata, status } from "@grpc/grpc-js/"; + +import LoadBalancingConfig = experimental.LoadBalancingConfig; +import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig; +import LoadBalancer = experimental.LoadBalancer; +import Picker = experimental.Picker; +import PickResult = experimental.PickResult; +import PickArgs = experimental.PickArgs; +import PickResultType = experimental.PickResultType; +import UnavailablePicker = experimental.UnavailablePicker; +import QueuePicker = experimental.QueuePicker; +import SubchannelAddress = experimental.SubchannelAddress; +import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; +import getFirstUsableConfig = experimental.getFirstUsableConfig; +import ChannelControlHelper = experimental.ChannelControlHelper; +import registerLoadBalancerType = experimental.registerLoadBalancerType; + +const TRACER_NAME = 'weighted_target'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +const TYPE_NAME = 'xds_cluster_manager'; + +interface ClusterManagerChild { + child_policy: LoadBalancingConfig[]; +} + +class XdsClusterManagerLoadBalancingConfig implements LoadBalancingConfig { + getLoadBalancerName(): string { + return TYPE_NAME; + } + + constructor(private children: Map) {} + + getChildren() { + return this.children; + } + + toJsonObject(): object { + const childrenField: {[key: string]: object} = {}; + for (const [childName, childValue] of this.children.entries()) { + childrenField[childName] = { + child_policy: childValue.child_policy.map(policy => policy.toJsonObject()) + }; + } + return { + [TYPE_NAME]: { + children: childrenField + } + } + } + + static createFromJson(obj: any): XdsClusterManagerLoadBalancingConfig { + const childrenMap: Map = new Map(); + if (!('children' in obj && obj.children !== null && typeof obj.children === 'object')) { + throw new Error('xds_cluster_manager config must have a children map'); + } + for (const key of obj.children) { + const childObj = obj.children[key]; + if (!('child_policy' in childObj && Array.isArray(childObj.child_policy))) { + throw new Error(`xds_cluster_manager child ${key} must have a child_policy array`); + } + const validatedChild = { + child_policy: childObj.child_policy.map(validateLoadBalancingConfig) + }; + childrenMap.set(key, validatedChild); + } + return new XdsClusterManagerLoadBalancingConfig(childrenMap); + } +} + +class XdsClusterManagerPicker implements Picker { + constructor(private childPickers: Map) {} + + pick(pickArgs: PickArgs): PickResult { + /* extraPickInfo.cluster should be set for all calls by the config selector + * corresponding to the service config that specified the use of this LB + * policy. */ + const cluster = pickArgs.extraPickInfo.cluster ?? ''; + if (this.childPickers.has(cluster)) { + return this.childPickers.get(cluster)!.pick(pickArgs); + } else { + return { + pickResultType: PickResultType.TRANSIENT_FAILURE, + status: { + code: status.INTERNAL, + details: `Requested cluster ${cluster} not found`, + metadata: new Metadata(), + }, + subchannel: null, + extraFilterFactory: null, + onCallStarted: null + }; + } + } +} + +interface XdsClusterManagerChild { + updateAddressList(addressList: SubchannelAddress[], lbConfig: ClusterManagerChild, attributes: { [key: string]: unknown; }): void; + exitIdle(): void; + resetBackoff(): void; + destroy(): void; + getConnectivityState(): ConnectivityState; + getPicker(): Picker; + +} + +class XdsClusterManager implements LoadBalancer { + private XdsClusterManagerChildImpl = class implements XdsClusterManagerChild { + private connectivityState: ConnectivityState = ConnectivityState.IDLE; + private picker: Picker; + private childBalancer: ChildLoadBalancerHandler; + + constructor(private parent: XdsClusterManager, private name: string) { + this.childBalancer = new ChildLoadBalancerHandler({ + createSubchannel: (subchannelAddress, subchannelOptions) => { + return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelOptions); + }, + updateState: (connectivityState, picker) => { + this.updateState(connectivityState, picker); + }, + requestReresolution: () => { + this.parent.channelControlHelper.requestReresolution(); + } + }); + + this.picker = new QueuePicker(this.childBalancer); + } + + private updateState(connectivityState: ConnectivityState, picker: Picker) { + trace('Child ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); + this.connectivityState = connectivityState; + this.picker = picker; + this.parent.updateState(); + } + updateAddressList(addressList: SubchannelAddress[], lbConfig: ClusterManagerChild, attributes: { [key: string]: unknown; }): void { + const childConfig = getFirstUsableConfig(lbConfig.child_policy); + if (childConfig !== null) { + this.childBalancer.updateAddressList(addressList, childConfig, attributes); + } + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + } + getConnectivityState(): ConnectivityState { + return this.connectivityState; + } + getPicker(): Picker { + return this.picker; + } + } + // End of XdsClusterManagerChildImpl + + private children: Map = new Map(); + constructor(private channelControlHelper: ChannelControlHelper) {} + + private updateState() { + const pickerMap: Map = new Map(); + let anyReady = false; + let anyConnecting = false; + let anyIdle = false; + for (const [name, child] of this.children.entries()) { + pickerMap.set(name, child.getPicker()); + switch (child.getConnectivityState()) { + case ConnectivityState.READY: + anyReady = true; + break; + case ConnectivityState.CONNECTING: + anyConnecting = true; + break; + case ConnectivityState.IDLE: + anyIdle = true; + break; + } + } + let connectivityState: ConnectivityState; + if (anyReady) { + connectivityState = ConnectivityState.READY; + } else if (anyConnecting) { + connectivityState = ConnectivityState.CONNECTING; + } else if (anyIdle) { + connectivityState = ConnectivityState.IDLE; + } else { + connectivityState = ConnectivityState.TRANSIENT_FAILURE; + } + let picker: Picker; + + switch (connectivityState) { + case ConnectivityState.READY: + picker = new XdsClusterManagerPicker(pickerMap); + break; + case ConnectivityState.CONNECTING: + case ConnectivityState.IDLE: + picker = new QueuePicker(this); + break; + default: + picker = new UnavailablePicker({ + code: Status.UNAVAILABLE, + details: 'xds_cluster_manager: all children report state TRANSIENT_FAILURE', + metadata: new Metadata() + }); + } + trace( + 'Transitioning to ' + + ConnectivityState[connectivityState] + ); + this.channelControlHelper.updateState(connectivityState, picker); + } + + updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { + if (!(lbConfig instanceof XdsClusterManagerLoadBalancingConfig)) { + // Reject a config of the wrong type + trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); + return; + } + const configChildren = lbConfig.getChildren(); + // Delete children that are not in the new config + const namesToRemove: string[] = []; + for (const name of this.children.keys()) { + if (!configChildren.has(name)) { + namesToRemove.push(name); + } + } + for (const name of namesToRemove) { + this.children.get(name)!.destroy(); + this.children.delete(name); + } + // Add new children that were not in the previous config + for (const [name, childConfig] of configChildren.entries()) { + if (!this.children.has(name)) { + const newChild = new this.XdsClusterManagerChildImpl(this, name); + newChild.updateAddressList(addressList, childConfig, attributes); + this.children.set(name, newChild); + } + } + this.updateState(); + } + exitIdle(): void { + for (const child of this.children.values()) { + child.exitIdle(); + } + } + resetBackoff(): void { + for (const child of this.children.values()) { + child.resetBackoff(); + } + } + destroy(): void { + for (const child of this.children.values()) { + child.destroy(); + } + this.children.clear(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + registerLoadBalancerType(TYPE_NAME, XdsClusterManager, XdsClusterManagerLoadBalancingConfig); +} \ No newline at end of file From d1aa9aa6fc02ad7152a7495f43d3769b0a18dfc7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Feb 2021 12:20:01 -0800 Subject: [PATCH 1351/1899] Don't update identical states with identical pickers --- .../grpc-js-xds/src/load-balancer-xds-cluster-manager.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index c4f53759a..f8d2de258 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -177,6 +177,8 @@ class XdsClusterManager implements LoadBalancer { // End of XdsClusterManagerChildImpl private children: Map = new Map(); + // Shutdown is a placeholder value that will never appear in normal operation. + private currentState: ConnectivityState = ConnectivityState.SHUTDOWN; constructor(private channelControlHelper: ChannelControlHelper) {} private updateState() { @@ -208,6 +210,13 @@ class XdsClusterManager implements LoadBalancer { } else { connectivityState = ConnectivityState.TRANSIENT_FAILURE; } + /* For each of the states CONNECTING, IDLE, and TRANSIENT_FAILURE, there is + * exactly one corresponding picker, so if the state is one of those and + * that does not change, no new information is provided by passing the + * new state upward. */ + if (connectivityState === this.currentState && connectivityState !== ConnectivityState.READY) { + return; + } let picker: Picker; switch (connectivityState) { From cd14345cb429432e341a068c8bc3f940ccc6672c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 11 Feb 2021 09:55:24 -0800 Subject: [PATCH 1352/1899] grpc-js: Ref and unref backoff timer --- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js-xds/src/xds-client.ts | 4 +++- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/backoff-timeout.ts | 14 ++++++++++++++ packages/grpc-js/src/resolving-load-balancer.ts | 1 + packages/grpc-js/src/subchannel.ts | 2 ++ 6 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f2b32a773..5ff82e49d 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.2.1", + "version": "1.2.2", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -45,7 +45,7 @@ "@grpc/proto-loader": "^0.6.0-pre14" }, "peerDependencies": { - "@grpc/grpc-js": "~1.2.2" + "@grpc/grpc-js": "~1.2.7" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index ae67960d7..7f6586573 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -774,9 +774,11 @@ export class XdsClient { this.adsBackoff = new BackoffTimeout(() => { this.maybeStartAdsStream(); }); + this.adsBackoff.unref(); this.lrsBackoff = new BackoffTimeout(() => { this.maybeStartLrsStream(); - }) + }); + this.lrsBackoff.unref(); Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( ([bootstrapInfo, protoDefinitions]) => { diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7e7f45877..6b84fd9e2 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.6", + "version": "1.2.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts index 8cad14f74..49a5b1e29 100644 --- a/packages/grpc-js/src/backoff-timeout.ts +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -44,6 +44,7 @@ export class BackoffTimeout { private nextDelay: number; private timerId: NodeJS.Timer; private running = false; + private hasRef = true; constructor(private callback: () => void, options?: BackoffOptions) { if (options) { @@ -74,6 +75,9 @@ export class BackoffTimeout { this.callback(); this.running = false; }, this.nextDelay); + if (!this.hasRef) { + this.timerId.unref(); + } const nextBackoff = Math.min( this.nextDelay * this.multiplier, this.maxDelay @@ -102,4 +106,14 @@ export class BackoffTimeout { isRunning() { return this.running; } + + ref() { + this.hasRef = true; + this.timerId.ref(); + } + + unref() { + this.hasRef = false; + this.timerId.unref(); + } } diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 5a4c62f57..ca6d07213 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -196,6 +196,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.updateState(this.latestChildState, this.latestChildPicker); } }); + this.backoffTimeout.unref(); } private updateResolution() { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c32ee43ea..30959122d 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -615,6 +615,7 @@ export class Subchannel { if (this.session) { this.session.ref(); } + this.backoffTimeout.ref(); if (!this.keepaliveWithoutCalls) { this.startKeepalivePings(); } @@ -635,6 +636,7 @@ export class Subchannel { if (this.session) { this.session.unref(); } + this.backoffTimeout.unref(); if (!this.keepaliveWithoutCalls) { this.stopKeepalivePings(); } From 097d63b14b9621ddd8ccfb180c4eaefe144a8851 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Feb 2021 11:03:00 -0800 Subject: [PATCH 1353/1899] grpc-js: Add more details to 'Failed to start HTTP/2 stream' error --- packages/grpc-js/src/channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index e1a76c092..ad24876e8 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -362,7 +362,7 @@ export class ChannelImplementation implements Channel { ); callStream.cancelWithStatus( Status.INTERNAL, - 'Failed to start HTTP/2 stream' + `Failed to start HTTP/2 stream with error: ${(error as Error).message}` ); } } From c953a0e212b16e3d269ce3a661799caaf274039e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Feb 2021 13:37:52 -0800 Subject: [PATCH 1354/1899] refactor part of xds-client into seprate files --- packages/grpc-js-xds/src/load-balancer-cds.ts | 3 +- .../src/xds-stream-state/cds-state.ts | 171 +++++++++++++++++ .../src/xds-stream-state/eds-state.ts | 174 ++++++++++++++++++ .../src/xds-stream-state/lds-state.ts | 105 +++++++++++ .../src/xds-stream-state/rds-state.ts | 94 ++++++++++ .../src/xds-stream-state/xds-stream-state.ts | 38 ++++ 6 files changed, 584 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js-xds/src/xds-stream-state/cds-state.ts create mode 100644 packages/grpc-js-xds/src/xds-stream-state/eds-state.ts create mode 100644 packages/grpc-js-xds/src/xds-stream-state/lds-state.ts create mode 100644 packages/grpc-js-xds/src/xds-stream-state/rds-state.ts create mode 100644 packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index a2961927c..452b1304b 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -16,7 +16,7 @@ */ import { connectivityState, status, Metadata, logVerbosity, experimental } from '@grpc/grpc-js'; -import { XdsClient, Watcher } from './xds-client'; +import { XdsClient } from './xds-client'; import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; import SubchannelAddress = experimental.SubchannelAddress; import UnavailablePicker = experimental.UnavailablePicker; @@ -26,6 +26,7 @@ import ChannelControlHelper = experimental.ChannelControlHelper; import registerLoadBalancerType = experimental.registerLoadBalancerType; import LoadBalancingConfig = experimental.LoadBalancingConfig; import { EdsLoadBalancingConfig } from './load-balancer-eds'; +import { Watcher } from './xds-stream-state/xds-stream-state'; const TRACER_NAME = 'cds_balancer'; diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts new file mode 100644 index 000000000..343089958 --- /dev/null +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -0,0 +1,171 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { Cluster__Output } from "../generated/envoy/api/v2/Cluster"; +import { EdsState } from "./eds-state"; +import { Watcher, XdsStreamState } from "./xds-stream-state"; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +export class CdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + private watchers: Map[]> = new Map< + string, + Watcher[] + >(); + + private latestResponses: Cluster__Output[] = []; + + constructor( + private edsState: EdsState, + private updateResourceNames: () => void + ) {} + + /** + * Add the watcher to the watcher list. Returns true if the list of resource + * names has changed, and false otherwise. + * @param clusterName + * @param watcher + */ + addWatcher(clusterName: string, watcher: Watcher): void { + trace('Adding CDS watcher for clusterName ' + clusterName); + let watchersEntry = this.watchers.get(clusterName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(clusterName, watchersEntry); + } + watchersEntry.push(watcher); + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.name === clusterName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + trace('Reporting existing CDS update for new watcher for clusterName ' + clusterName); + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher(clusterName: string, watcher: Watcher): void { + trace('Removing CDS watcher for clusterName ' + clusterName); + const watchersEntry = this.watchers.get(clusterName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(clusterName); + } + } + if (removedServiceName) { + this.updateResourceNames(); + } + } + + getResourceNames(): string[] { + return Array.from(this.watchers.keys()); + } + + private validateResponse(message: Cluster__Output): boolean { + if (message.type !== 'EDS') { + return false; + } + if (!message.eds_cluster_config?.eds_config?.ads) { + return false; + } + if (message.lb_policy !== 'ROUND_ROBIN') { + return false; + } + if (message.lrs_server) { + if (!message.lrs_server.self) { + return false; + } + } + return true; + } + + /** + * Given a list of clusterNames (which may actually be the cluster name), + * for each watcher watching a name not on the list, call that watcher's + * onResourceDoesNotExist method. + * @param allClusterNames + */ + private handleMissingNames(allClusterNames: Set) { + for (const [clusterName, watcherList] of this.watchers.entries()) { + if (!allClusterNames.has(clusterName)) { + trace('Reporting CDS resource does not exist for clusterName ' + clusterName); + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + + handleResponses(responses: Cluster__Output[]): string | null { + for (const message of responses) { + if (!this.validateResponse(message)) { + trace('CDS validation failed for message ' + JSON.stringify(message)); + return 'CDS Error: Cluster validation failed'; + } + } + this.latestResponses = responses; + const allEdsServiceNames: Set = new Set(); + const allClusterNames: Set = new Set(); + for (const message of responses) { + allClusterNames.add(message.name); + const edsServiceName = message.eds_cluster_config?.service_name ?? ''; + allEdsServiceNames.add( + edsServiceName === '' ? message.name : edsServiceName + ); + const watchers = this.watchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); + this.handleMissingNames(allClusterNames); + this.edsState.handleMissingNames(allEdsServiceNames); + return null; + } + + reportStreamError(status: StatusObject): void { + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts new file mode 100644 index 000000000..c9beef292 --- /dev/null +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -0,0 +1,174 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { isIPv4, isIPv6 } from "net"; +import { ClusterLoadAssignment__Output } from "../generated/envoy/api/v2/ClusterLoadAssignment"; +import { Watcher, XdsStreamState } from "./xds-stream-state"; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +export class EdsState implements XdsStreamState { + public versionInfo = ''; + public nonce = ''; + + private watchers: Map< + string, + Watcher[] + > = new Map[]>(); + + private latestResponses: ClusterLoadAssignment__Output[] = []; + + constructor(private updateResourceNames: () => void) {} + + /** + * Add the watcher to the watcher list. Returns true if the list of resource + * names has changed, and false otherwise. + * @param edsServiceName + * @param watcher + */ + addWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + let watchersEntry = this.watchers.get(edsServiceName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(edsServiceName, watchersEntry); + } + trace('Adding EDS watcher (' + watchersEntry.length + ' ->' + (watchersEntry.length + 1) + ') for edsServiceName ' + edsServiceName); + watchersEntry.push(watcher); + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.cluster_name === edsServiceName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + trace('Reporting existing EDS update for new watcher for edsServiceName ' + edsServiceName); + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher( + edsServiceName: string, + watcher: Watcher + ): void { + trace('Removing EDS watcher for edsServiceName ' + edsServiceName); + const watchersEntry = this.watchers.get(edsServiceName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + trace('Removed EDS watcher (' + watchersEntry.length + ' -> ' + (watchersEntry.length - 1) + ') for edsServiceName ' + edsServiceName); + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(edsServiceName); + } + } + if (removedServiceName) { + this.updateResourceNames(); + } + } + + getResourceNames(): string[] { + return Array.from(this.watchers.keys()); + } + + /** + * Validate the ClusterLoadAssignment object by these rules: + * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto + * @param message + */ + private validateResponse(message: ClusterLoadAssignment__Output) { + for (const endpoint of message.endpoints) { + for (const lb of endpoint.lb_endpoints) { + const socketAddress = lb.endpoint?.address?.socket_address; + if (!socketAddress) { + return false; + } + if (socketAddress.port_specifier !== 'port_value') { + return false; + } + if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { + return false; + } + } + } + return true; + } + + /** + * Given a list of edsServiceNames (which may actually be the cluster name), + * for each watcher watching a name not on the list, call that watcher's + * onResourceDoesNotExist method. + * @param allClusterNames + */ + handleMissingNames(allEdsServiceNames: Set) { + for (const [edsServiceName, watcherList] of this.watchers.entries()) { + if (!allEdsServiceNames.has(edsServiceName)) { + trace('Reporting EDS resource does not exist for edsServiceName ' + edsServiceName); + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + + handleResponses(responses: ClusterLoadAssignment__Output[]) { + for (const message of responses) { + if (!this.validateResponse(message)) { + trace('EDS validation failed for message ' + JSON.stringify(message)); + return 'EDS Error: ClusterLoadAssignment validation failed'; + } + } + this.latestResponses = responses; + const allClusterNames: Set = new Set(); + for (const message of responses) { + allClusterNames.add(message.cluster_name); + const watchers = this.watchers.get(message.cluster_name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } + } + trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); + this.handleMissingNames(allClusterNames); + return null; + } + + reportStreamError(status: StatusObject): void { + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts new file mode 100644 index 000000000..c5db3bfad --- /dev/null +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -0,0 +1,105 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as protoLoader from '@grpc/proto-loader'; +import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { Listener__Output } from "../generated/envoy/api/v2/Listener"; +import { RdsState } from "./rds-state"; +import { XdsStreamState } from "./xds-stream-state"; +import { HttpConnectionManager__Output } from '../generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +const HTTP_CONNECTION_MANGER_TYPE_URL = + 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; + +export class LdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + constructor(private targetName: string, private rdsState: RdsState) {} + + getResourceNames(): string[] { + return [this.targetName]; + } + + private validateResponse(message: Listener__Output): boolean { + if ( + !( + message.api_listener?.api_listener && + protoLoader.isAnyExtension(message.api_listener.api_listener) && + message.api_listener?.api_listener['@type'] === + HTTP_CONNECTION_MANGER_TYPE_URL + ) + ) { + return false; + } + const httpConnectionManager = message.api_listener + ?.api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + return !!httpConnectionManager.rds?.config_source?.ads; + case 'route_config': + return true; + } + return false; + } + + handleResponses(responses: Listener__Output[]): string | null { + trace('Received LDS update with names ' + responses.map(message => message.name)); + for (const message of responses) { + if (message.name === this.targetName) { + if (this.validateResponse(message)) { + // The validation step ensures that this is correct + const httpConnectionManager = message.api_listener! + .api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': + trace('Received LDS update with RDS route config name ' + httpConnectionManager.rds!.route_config_name); + this.rdsState.setRouteConfigName( + httpConnectionManager.rds!.route_config_name + ); + break; + case 'route_config': + trace('Received LDS update with route configuration'); + this.rdsState.setRouteConfigName(null); + this.rdsState.handleSingleMessage( + httpConnectionManager.route_config! + ); + break; + default: + // The validation rules should prevent this + } + } else { + trace('LRS validation error for message ' + JSON.stringify(message)); + return 'LRS Error: Listener validation failed'; + } + } + } + return null; + } + + reportStreamError(status: StatusObject): void { + // Nothing to do here + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts new file mode 100644 index 000000000..182685875 --- /dev/null +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -0,0 +1,94 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { RouteConfiguration__Output } from "../generated/envoy/api/v2/RouteConfiguration"; +import { CdsLoadBalancingConfig } from "../load-balancer-cds"; +import { Watcher, XdsStreamState } from "./xds-stream-state"; +import ServiceConfig = experimental.ServiceConfig; + +const TRACER_NAME = 'xds_client'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + +export class RdsState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + private routeConfigName: string | null = null; + + constructor( + private targetName: string, + private watcher: Watcher, + private updateResouceNames: () => void + ) {} + + getResourceNames(): string[] { + return this.routeConfigName ? [this.routeConfigName] : []; + } + + handleSingleMessage(message: RouteConfiguration__Output) { + for (const virtualHost of message.virtual_hosts) { + if (virtualHost.domains.indexOf(this.targetName) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + trace('Reporting RDS update for host ' + this.targetName + ' with cluster ' + route.route.cluster); + this.watcher.onValidUpdate({ + methodConfig: [], + loadBalancingConfig: [ + new CdsLoadBalancingConfig(route.route.cluster) + ], + }); + return; + } else { + trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); + } + } + } + trace('Reporting RDS resource does not exist from domain lists ' + message.virtual_hosts.map(virtualHost => virtualHost.domains)); + /* If none of the routes match the one we are looking for, bubble up an + * error. */ + this.watcher.onResourceDoesNotExist(); + } + + handleResponses(responses: RouteConfiguration__Output[]): string | null { + trace('Received RDS response with route config names ' + responses.map(message => message.name)); + if (this.routeConfigName !== null) { + for (const message of responses) { + if (message.name === this.routeConfigName) { + this.handleSingleMessage(message); + return null; + } + } + } + return null; + } + + setRouteConfigName(name: string | null) { + const oldName = this.routeConfigName; + this.routeConfigName = name; + if (name !== oldName) { + this.updateResouceNames(); + } + } + + reportStreamError(status: StatusObject): void { + this.watcher.onTransientError(status); + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts new file mode 100644 index 000000000..83db1781e --- /dev/null +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -0,0 +1,38 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { StatusObject } from "@grpc/grpc-js"; + +export interface Watcher { + onValidUpdate(update: UpdateType): void; + onTransientError(error: StatusObject): void; + onResourceDoesNotExist(): void; +} + +export interface XdsStreamState { + versionInfo: string; + nonce: string; + getResourceNames(): string[]; + /** + * Returns a string containing the error details if the message should be nacked, + * or null if it should be acked. + * @param responses + */ + handleResponses(responses: ResponseType[]): string | null; + + reportStreamError(status: StatusObject): void; +} \ No newline at end of file From 40c19ea28be67d05f11a431a4279505dfedba265 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Feb 2021 12:42:10 -0800 Subject: [PATCH 1355/1899] grpc-js: Don't propagate non-numeric errors from auth plugins --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-credentials-filter.ts | 12 +++++++++++- packages/grpc-js/src/channel.ts | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6b84fd9e2..638c19200 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.7", + "version": "1.2.8", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index 5263d97f2..53bdba2f1 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -21,6 +21,7 @@ import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; import { Status } from './constants'; import { splitHostPort } from './uri-parser'; +import { ServiceError } from './call'; export class CallCredentialsFilter extends BaseFilter implements Filter { private serviceUrl: string; @@ -51,12 +52,21 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { service_url: this.serviceUrl, }); const resultMetadata = await metadata; - resultMetadata.merge(await credsMetadata); + try { + resultMetadata.merge(await credsMetadata); + } catch (error) { + this.stream.cancelWithStatus( + Status.UNAUTHENTICATED, + `Failed to retrieve auth metadata with error: ${error.message}` + ); + return Promise.reject('Failed to retrieve auth metadata'); + } if (resultMetadata.get('authorization').length > 1) { this.stream.cancelWithStatus( Status.INTERNAL, '"authorization" metadata cannot have multiple values' ); + return Promise.reject('"authorization" metadata cannot have multiple values'); } return resultMetadata; } diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index ad24876e8..0f055d1e9 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -384,7 +384,7 @@ export class ChannelImplementation implements Channel { (error: Error & { code: number }) => { // We assume the error code isn't 0 (Status.OK) callStream.cancelWithStatus( - error.code || Status.UNKNOWN, + (typeof error.code === 'number') ? error.code : Status.UNKNOWN, `Getting metadata from plugin failed with error: ${error.message}` ); } From 60eb600410fd58a8087e870c3dec988e1cccc46e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 25 Feb 2021 10:02:44 -0800 Subject: [PATCH 1356/1899] move createGoogleDefaultCredentials from grpc-js to grpc-js-xds --- packages/grpc-js-xds/package.json | 3 ++- .../src/google-default-credentials.ts | 27 +++++++++++++++++++ packages/grpc-js-xds/src/xds-client.ts | 2 +- packages/grpc-js/package.json | 1 - packages/grpc-js/src/channel-credentials.ts | 11 -------- packages/grpc-js/src/experimental.ts | 1 - 6 files changed, 30 insertions(+), 15 deletions(-) create mode 100644 packages/grpc-js-xds/src/google-default-credentials.ts diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f2b32a773..a26e03ea3 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -42,7 +42,8 @@ "yargs": "^15.4.1" }, "dependencies": { - "@grpc/proto-loader": "^0.6.0-pre14" + "@grpc/proto-loader": "^0.6.0-pre14", + "google-auth-library": "^7.0.2" }, "peerDependencies": { "@grpc/grpc-js": "~1.2.2" diff --git a/packages/grpc-js-xds/src/google-default-credentials.ts b/packages/grpc-js-xds/src/google-default-credentials.ts new file mode 100644 index 000000000..ec765ee49 --- /dev/null +++ b/packages/grpc-js-xds/src/google-default-credentials.ts @@ -0,0 +1,27 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +import { GoogleAuth } from 'google-auth-library'; +import { ChannelCredentials, CallCredentials } from '@grpc/grpc-js'; + +export function createGoogleDefaultCredentials(): ChannelCredentials { + const sslCreds = ChannelCredentials.createSsl(); + const googleAuthCreds = CallCredentials.createFromGoogleCredential( + new GoogleAuth() + ); + return sslCreds.compose(googleAuthCreds); +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index ae67960d7..bedafda9a 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -48,7 +48,7 @@ import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfig import { Any__Output } from './generated/google/protobuf/Any'; import BackoffTimeout = experimental.BackoffTimeout; import ServiceConfig = experimental.ServiceConfig; -import createGoogleDefaultCredentials = experimental.createGoogleDefaultCredentials; +import { createGoogleDefaultCredentials } from './google-default-credentials'; import { CdsLoadBalancingConfig } from './load-balancer-cds'; const TRACER_NAME = 'xds_client'; diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 01a9d418f..5d8360e6c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -58,7 +58,6 @@ }, "dependencies": { "@types/node": "^12.12.47", - "google-auth-library": "^6.1.1", "semver": "^6.2.0" }, "files": [ diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index aadf638b3..675e91628 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -19,7 +19,6 @@ import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; -import { GoogleAuth as GoogleAuthType } from 'google-auth-library'; // eslint-disable-next-line @typescript-eslint/no-explicit-any function verifyIsBufferOrNull(obj: any, friendlyName: string): void { @@ -279,13 +278,3 @@ class ComposedChannelCredentialsImpl extends ChannelCredentials { } } } - -export function createGoogleDefaultCredentials(): ChannelCredentials { - const GoogleAuth = require('google-auth-library') - .GoogleAuth as typeof GoogleAuthType; - const sslCreds = ChannelCredentials.createSsl(); - const googleAuthCreds = CallCredentials.createFromGoogleCredential( - new GoogleAuth() - ); - return sslCreds.compose(googleAuthCreds); -} diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index b88f124ae..c27f9810a 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -2,7 +2,6 @@ export { trace } from './logging'; export { Resolver, ResolverListener, registerResolver } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; export { ServiceConfig } from './service-config'; -export { createGoogleDefaultCredentials } from './channel-credentials'; export { BackoffTimeout } from './backoff-timeout'; export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig } from './load-balancer'; export { SubchannelAddress, subchannelAddressToString } from './subchannel'; From 131b604f2c01dffa80e34ae92df4174a8724311f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Feb 2021 14:25:41 -0800 Subject: [PATCH 1357/1899] Add routing and traffic splitting functionality --- packages/grpc-js-xds/package.json | 3 +- packages/grpc-js-xds/src/environment.ts | 18 + packages/grpc-js-xds/src/load-balancer-cds.ts | 10 +- packages/grpc-js-xds/src/load-balancer-eds.ts | 15 +- packages/grpc-js-xds/src/resolver-xds.ts | 444 ++++++++++++++- packages/grpc-js-xds/src/xds-client.ts | 532 ++---------------- .../src/xds-stream-state/lds-state.ts | 116 ++-- .../src/xds-stream-state/rds-state.ts | 177 ++++-- packages/grpc-js/src/experimental.ts | 2 +- 9 files changed, 719 insertions(+), 598 deletions(-) create mode 100644 packages/grpc-js-xds/src/environment.ts diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f2b32a773..eff02b685 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -42,7 +42,8 @@ "yargs": "^15.4.1" }, "dependencies": { - "@grpc/proto-loader": "^0.6.0-pre14" + "@grpc/proto-loader": "^0.6.0-pre14", + "re2-wasm": "^1.0.1" }, "peerDependencies": { "@grpc/grpc-js": "~1.2.2" diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts new file mode 100644 index 000000000..67fc531e4 --- /dev/null +++ b/packages/grpc-js-xds/src/environment.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export const GRPC_XDS_EXPERIMENTAL_ROUTING = (process.env.GRPC_XDS_EXPERIMENTAL_ROUTING === 'true'); \ No newline at end of file diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index 452b1304b..9a372588b 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -16,7 +16,7 @@ */ import { connectivityState, status, Metadata, logVerbosity, experimental } from '@grpc/grpc-js'; -import { XdsClient } from './xds-client'; +import { getSingletonXdsClient, XdsClient } from './xds-client'; import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; import SubchannelAddress = experimental.SubchannelAddress; import UnavailablePicker = experimental.UnavailablePicker; @@ -66,7 +66,6 @@ export class CdsLoadBalancingConfig implements LoadBalancingConfig { export class CdsLoadBalancer implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; - private xdsClient: XdsClient | null = null; private watcher: Watcher; private isWatcherActive = false; @@ -127,7 +126,6 @@ export class CdsLoadBalancer implements LoadBalancer { return; } trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2)); - this.xdsClient = attributes.xdsClient; this.latestAttributes = attributes; /* If the cluster is changing, disable the old watcher before adding the new @@ -137,7 +135,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.latestConfig?.getCluster() !== lbConfig.getCluster() ) { trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.getCluster()); - this.xdsClient.removeClusterWatcher( + getSingletonXdsClient().removeClusterWatcher( this.latestConfig!.getCluster(), this.watcher ); @@ -153,7 +151,7 @@ export class CdsLoadBalancer implements LoadBalancer { if (!this.isWatcherActive) { trace('Adding new cluster watcher for cluster name ' + lbConfig.getCluster()); - this.xdsClient.addClusterWatcher(lbConfig.getCluster(), this.watcher); + getSingletonXdsClient().addClusterWatcher(lbConfig.getCluster(), this.watcher); this.isWatcherActive = true; } } @@ -167,7 +165,7 @@ export class CdsLoadBalancer implements LoadBalancer { trace('Destroying load balancer with cluster name ' + this.latestConfig?.getCluster()); this.childBalancer.destroy(); if (this.isWatcherActive) { - this.xdsClient?.removeClusterWatcher( + getSingletonXdsClient().removeClusterWatcher( this.latestConfig!.getCluster(), this.watcher ); diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 8919f3174..35da2a46a 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -16,7 +16,7 @@ */ import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental } from '@grpc/grpc-js'; -import { XdsClient, Watcher, XdsClusterDropStats } from './xds-client'; +import { getSingletonXdsClient, XdsClient, XdsClusterDropStats } from './xds-client'; import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { LocalitySubchannelAddress, PriorityChild, PriorityLoadBalancingConfig } from './load-balancer-priority'; @@ -33,6 +33,7 @@ import PickResultType = experimental.PickResultType; import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimental'; import { WeightedTarget, WeightedTargetLoadBalancingConfig } from './load-balancer-weighted-target'; import { LrsLoadBalancingConfig } from './load-balancer-lrs'; +import { Watcher } from './xds-stream-state/xds-stream-state'; const TRACER_NAME = 'eds_balancer'; @@ -122,11 +123,10 @@ export class EdsLoadBalancer implements LoadBalancer { * requests. */ private childBalancer: ChildLoadBalancerHandler; - private xdsClient: XdsClient | null = null; private edsServiceName: string | null = null; private watcher: Watcher; /** - * Indicates whether the watcher has already been passed to this.xdsClient + * Indicates whether the watcher has already been passed to the xdsClient * and is getting updates. */ private isWatcherActive = false; @@ -434,14 +434,13 @@ export class EdsLoadBalancer implements LoadBalancer { trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; - this.xdsClient = attributes.xdsClient; const newEdsServiceName = lbConfig.getEdsServiceName() ?? lbConfig.getCluster(); /* If the name is changing, disable the old watcher before adding the new * one */ if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { trace('Removing old endpoint watcher for edsServiceName ' + this.edsServiceName) - this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); + getSingletonXdsClient().removeEndpointWatcher(this.edsServiceName!, this.watcher); /* Setting isWatcherActive to false here lets us have one code path for * calling addEndpointWatcher */ this.isWatcherActive = false; @@ -454,12 +453,12 @@ export class EdsLoadBalancer implements LoadBalancer { if (!this.isWatcherActive) { trace('Adding new endpoint watcher for edsServiceName ' + this.edsServiceName); - this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); + getSingletonXdsClient().addEndpointWatcher(this.edsServiceName, this.watcher); this.isWatcherActive = true; } if (lbConfig.getLrsLoadReportingServerName()) { - this.clusterDropStats = this.xdsClient.addClusterDropStats( + this.clusterDropStats = getSingletonXdsClient().addClusterDropStats( lbConfig.getLrsLoadReportingServerName()!, lbConfig.getCluster(), lbConfig.getEdsServiceName() ?? '' @@ -480,7 +479,7 @@ export class EdsLoadBalancer implements LoadBalancer { destroy(): void { trace('Destroying load balancer with edsServiceName ' + this.edsServiceName); if (this.edsServiceName) { - this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); + getSingletonXdsClient().removeEndpointWatcher(this.edsServiceName, this.watcher); } this.childBalancer.destroy(); } diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 1588f3b11..b3c78adaf 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -14,7 +14,11 @@ * limitations under the License. */ -import { XdsClient } from './xds-client'; +import * as protoLoader from '@grpc/proto-loader'; + +import { RE2 } from 're2-wasm'; + +import { getSingletonXdsClient, XdsClient } from './xds-client'; import { StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions } from '@grpc/grpc-js'; import Resolver = experimental.Resolver; import GrpcUri = experimental.GrpcUri; @@ -22,6 +26,17 @@ import ResolverListener = experimental.ResolverListener; import uriToString = experimental.uriToString; import ServiceConfig = experimental.ServiceConfig; import registerResolver = experimental.registerResolver; +import { Listener__Output } from './generated/envoy/api/v2/Listener'; +import { Watcher } from './xds-stream-state/xds-stream-state'; +import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; +import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; +import { GRPC_XDS_EXPERIMENTAL_ROUTING } from './environment'; +import { CdsLoadBalancingConfig } from './load-balancer-cds'; +import { VirtualHost__Output } from './generated/envoy/api/v2/route/VirtualHost'; +import { RouteMatch__Output } from './generated/envoy/api/v2/route/RouteMatch'; +import { HeaderMatcher__Output } from './generated/envoy/api/v2/route/HeaderMatcher'; +import ConfigSelector = experimental.ConfigSelector; +import LoadBalancingConfig = experimental.LoadBalancingConfig; const TRACER_NAME = 'xds_resolver'; @@ -29,15 +44,404 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } +// Better match type has smaller value. +enum MatchType { + EXACT_MATCH, + SUFFIX_MATCH, + PREFIX_MATCH, + UNIVERSE_MATCH, + INVALID_MATCH, +}; + +function domainPatternMatchType(domainPattern: string): MatchType { + if (domainPattern.length === 0) { + return MatchType.INVALID_MATCH; + } + if (domainPattern.indexOf('*') < 0) { + return MatchType.EXACT_MATCH; + } + if (domainPattern === '*') { + return MatchType.UNIVERSE_MATCH; + } + if (domainPattern.startsWith('*')) { + return MatchType.SUFFIX_MATCH; + } + if (domainPattern.endsWith('*')) { + return MatchType.PREFIX_MATCH; + } + return MatchType.INVALID_MATCH; +} + +function domainMatch(matchType: MatchType, domainPattern: string, expectedHostName: string) { + switch (matchType) { + case MatchType.EXACT_MATCH: + return expectedHostName === domainPattern; + case MatchType.SUFFIX_MATCH: + return expectedHostName.endsWith(domainPattern.substring(1)); + case MatchType.PREFIX_MATCH: + return expectedHostName.startsWith(domainPattern.substring(0, domainPattern.length - 1)); + case MatchType.UNIVERSE_MATCH: + return true; + case MatchType.INVALID_MATCH: + return false; + } +} + +function findVirtualHostForDomain(virutalHostList: VirtualHost__Output[], domain: string): VirtualHost__Output | null { + let targetVhost: VirtualHost__Output | null = null; + let bestMatchType: MatchType = MatchType.INVALID_MATCH; + let longestMatch = 0; + for (const virtualHost of virutalHostList) { + for (const domainPattern of virtualHost.domains) { + const matchType = domainPatternMatchType(domainPattern); + // If we already have a match of a better type, skip this one + if (matchType > bestMatchType) { + continue; + } + // If we already have a longer match of the same type, skip this one + if (matchType === bestMatchType && domainPattern.length <= longestMatch) { + continue; + } + if (domainMatch(matchType, domainPattern, domain)) { + targetVhost = virtualHost; + bestMatchType = matchType; + longestMatch = domainPattern.length; + } + if (bestMatchType === MatchType.EXACT_MATCH) { + break; + } + } + if (bestMatchType === MatchType.EXACT_MATCH) { + break; + } + } + return targetVhost; +} + +interface Matcher { + (methodName: string, metadata: Metadata): boolean; +} + +const numberRegex = new RE2(/^-?\d+$/u); + +function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Matcher { + let valueChecker: (value: string) => boolean; + switch (headerMatch.header_match_specifier) { + case 'exact_match': + valueChecker = value => value === headerMatch.exact_match; + break; + case 'safe_regex_match': + const regex = new RE2(`^${headerMatch.safe_regex_match}$`, 'u'); + valueChecker = value => regex.test(value); + break; + case 'range_match': + const start = BigInt(headerMatch.range_match!.start); + const end = BigInt(headerMatch.range_match!.end); + valueChecker = value => { + if (!numberRegex.test(value)) { + return false; + } + const numberValue = BigInt(value); + return start <= numberValue && numberValue < end; + } + break; + case 'present_match': + valueChecker = value => true; + break; + case 'prefix_match': + valueChecker = value => value.startsWith(headerMatch.prefix_match!); + break; + case 'suffix_match': + valueChecker = value => value.endsWith(headerMatch.suffix_match!); + break; + default: + // Should be prevented by validation rules + return (methodName, metadata) => false; + } + const headerMatcher: Matcher = (methodName, metadata) => { + if (headerMatch.name.endsWith('-bin')) { + return false; + } + let value: string; + if (headerMatch.name === 'content-type') { + value = 'application/grpc'; + } else { + const valueArray = metadata.get(headerMatch.name); + if (valueArray.length === 0) { + return false; + } else { + value = valueArray.join(','); + } + } + return valueChecker(value); + } + if (headerMatch.invert_match) { + return (methodName, metadata) => !headerMatcher(methodName, metadata); + } else { + return headerMatcher; + } +} + +const RUNTIME_FRACTION_DENOMINATOR_VALUES = { + HUNDRED: 100, + TEN_THOUSAND: 10_000, + MILLION: 1_000_000 +} + +function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { + let pathMatcher: Matcher; + switch (routeMatch.path_specifier) { + case 'prefix': + if (routeMatch.case_sensitive?.value === false) { + const prefix = routeMatch.prefix!.toLowerCase(); + pathMatcher = (methodName, metadata) => (methodName.toLowerCase().startsWith(prefix)); + } else { + const prefix = routeMatch.prefix!; + pathMatcher = (methodName, metadata) => (methodName.startsWith(prefix)); + } + break; + case 'path': + if (routeMatch.case_sensitive?.value === false) { + const path = routeMatch.path!.toLowerCase(); + pathMatcher = (methodName, metadata) => (methodName.toLowerCase() === path); + } else { + const path = routeMatch.path!; + pathMatcher = (methodName, metadata) => (methodName === path); + } + break; + case 'safe_regex': + const flags = routeMatch.case_sensitive?.value === false ? 'ui' : 'u'; + const regex = new RE2(`^${routeMatch.safe_regex!.regex!}$`, flags); + pathMatcher = (methodName, metadata) => (regex.test(methodName)); + break; + default: + // Should be prevented by validation rules + return (methodName, metadata) => false; + } + const headerMatchers: Matcher[] = routeMatch.headers.map(getPredicateForHeaderMatcher); + let runtimeFractionHandler: () => boolean; + if (!routeMatch.runtime_fraction?.default_value) { + runtimeFractionHandler = () => true; + } else { + const numerator = routeMatch.runtime_fraction.default_value.numerator; + const denominator = RUNTIME_FRACTION_DENOMINATOR_VALUES[routeMatch.runtime_fraction.default_value.denominator]; + runtimeFractionHandler = () => { + const randomNumber = Math.random() * denominator; + return randomNumber < numerator; + } + } + return (methodName, metadata) => pathMatcher(methodName, metadata) && headerMatchers.every(matcher => matcher(methodName, metadata)) && runtimeFractionHandler(); +} + class XdsResolver implements Resolver { private hasReportedSuccess = false; - private xdsClient: XdsClient | null = null; + + private ldsWatcher: Watcher; + private rdsWatcher: Watcher + private isLdsWatcherActive = false; + /** + * The latest route config name from an LDS response. The RDS watcher is + * actively watching that name if and only if this is not null. + */ + private latestRouteConfigName: string | null = null; + + private latestRouteConfig: RouteConfiguration__Output | null = null; + + private clusterRefcounts = new Map(); constructor( private target: GrpcUri, private listener: ResolverListener, private channelOptions: ChannelOptions - ) {} + ) { + this.ldsWatcher = { + onValidUpdate: (update: Listener__Output) => { + const httpConnectionManager = update.api_listener! + .api_listener as protoLoader.AnyExtension & + HttpConnectionManager__Output; + switch (httpConnectionManager.route_specifier) { + case 'rds': { + const routeConfigName = httpConnectionManager.rds!.route_config_name; + if (this.latestRouteConfigName !== routeConfigName) { + if (this.latestRouteConfigName !== null) { + getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); + } + getSingletonXdsClient().addRouteWatcher(httpConnectionManager.rds!.route_config_name, this.rdsWatcher); + this.latestRouteConfigName = routeConfigName; + } + break; + } + case 'route_config': + if (this.latestRouteConfigName) { + getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); + } + this.handleRouteConfig(httpConnectionManager.route_config!); + break; + default: + // This is prevented by the validation rules + } + }, + onTransientError: (error: StatusObject) => { + /* A transient error only needs to bubble up as a failure if we have + * not already provided a ServiceConfig for the upper layer to use */ + if (!this.hasReportedSuccess) { + trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); + this.reportResolutionError(error.details); + } + }, + onResourceDoesNotExist: () => { + trace('Resolution error for target ' + uriToString(this.target) + ': LDS resource does not exist'); + this.reportResolutionError(`Listener ${this.target} does not exist`); + } + }; + this.rdsWatcher = { + onValidUpdate: (update: RouteConfiguration__Output) => { + this.handleRouteConfig(update); + }, + onTransientError: (error: StatusObject) => { + /* A transient error only needs to bubble up as a failure if we have + * not already provided a ServiceConfig for the upper layer to use */ + if (!this.hasReportedSuccess) { + trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); + this.reportResolutionError(error.details); + } + }, + onResourceDoesNotExist: () => { + trace('Resolution error for target ' + uriToString(this.target) + ' and route config ' + this.latestRouteConfigName + ': RDS resource does not exist'); + this.reportResolutionError(`Route config ${this.latestRouteConfigName} does not exist`); + } + } + } + + private refCluster(clusterName: string) { + const refCount = this.clusterRefcounts.get(clusterName); + if (refCount) { + refCount.refCount += 1; + } + } + + private unrefCluster(clusterName: string) { + const refCount = this.clusterRefcounts.get(clusterName); + if (refCount) { + refCount.refCount -= 1; + if (!refCount.inLastConfig && refCount.refCount === 0) { + this.clusterRefcounts.delete(clusterName); + this.handleRouteConfig(this.latestRouteConfig!); + } + } + } + + private handleRouteConfig(routeConfig: RouteConfiguration__Output) { + this.latestRouteConfig = routeConfig; + if (GRPC_XDS_EXPERIMENTAL_ROUTING) { + const virtualHost = findVirtualHostForDomain(routeConfig.virtual_hosts, this.target.path); + if (virtualHost === null) { + this.reportResolutionError('No matching route found'); + return; + } + const allConfigClusters = new Set(); + const matchList: {matcher: Matcher, action: () => string}[] = []; + for (const route of virtualHost.routes) { + let routeAction: () => string; + switch (route.route!.cluster_specifier) { + case 'cluster_header': + continue; + case 'cluster':{ + const cluster = route.route!.cluster!; + allConfigClusters.add(cluster); + routeAction = () => cluster; + break; + } + case 'weighted_clusters': { + let lastNumerator = 0; + // clusterChoices is essentially the weighted choices represented as a CDF + const clusterChoices: {cluster: string, numerator: number}[] = []; + for (const clusterWeight of route.route!.weighted_clusters!.clusters) { + allConfigClusters.add(clusterWeight.name); + lastNumerator = lastNumerator + (clusterWeight.weight?.value ?? 0); + clusterChoices.push({cluster: clusterWeight.name, numerator: lastNumerator}); + } + routeAction = () => { + const randomNumber = Math.random() * (route.route!.weighted_clusters!.total_weight?.value ?? 100); + for (const choice of clusterChoices) { + if (randomNumber < choice.numerator) { + return choice.cluster; + } + } + // This should be prevented by the validation rules + return ''; + } + } + } + const routeMatcher = getPredicateForMatcher(route.match!); + matchList.push({matcher: routeMatcher, action: routeAction}); + } + // Mark clusters that are not in this config, and remove ones with no references + for (const [name, refCount] of Array.from(this.clusterRefcounts.entries())) { + if (!allConfigClusters.has(name)) { + refCount.inLastConfig = false; + if (refCount.refCount === 0) { + this.clusterRefcounts.delete(name); + } + } + } + for (const name of allConfigClusters) { + if (this.clusterRefcounts.has(name)) { + this.clusterRefcounts.get(name)!.inLastConfig = true; + } else { + this.clusterRefcounts.set(name, {inLastConfig: true, refCount: 0}); + } + } + const configSelector: ConfigSelector = (methodName, metadata) => { + for (const {matcher, action} of matchList) { + if (matcher(methodName, metadata)) { + const clusterName = action(); + this.refCluster(clusterName); + const onCommitted = () => { + this.unrefCluster(clusterName); + } + return { + methodConfig: {name: []}, + onCommitted: onCommitted, + pickInformation: {cluster: clusterName}, + status: status.OK + }; + } + } + return { + methodConfig: {name: []}, + // pickInformation won't be used here, but it's set because of some TypeScript weirdness + pickInformation: {cluster: ''}, + status: status.UNAVAILABLE + }; + }; + const clusterConfigMap = new Map(); + for (const clusterName of this.clusterRefcounts.keys()) { + clusterConfigMap.set(clusterName, {child_policy: [new CdsLoadBalancingConfig(clusterName)]}); + } + // TODO: Create xdsClusterManagerLoadBalancingConfig and report successful resolution + } else { + for (const virtualHost of routeConfig.virtual_hosts) { + if (virtualHost.domains.indexOf(this.target.path) >= 0) { + const route = virtualHost.routes[virtualHost.routes.length - 1]; + if (route.match?.prefix === '' && route.route?.cluster) { + trace('Reporting RDS update for host ' + uriToString(this.target) + ' with cluster ' + route.route.cluster); + this.listener.onSuccessfulResolution([], { + methodConfig: [], + loadBalancingConfig: [ + new CdsLoadBalancingConfig(route.route.cluster) + ], + }, null, null, {}); + this.hasReportedSuccess = true; + return; + } else { + trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); + } + } + } + this.reportResolutionError('No matching route found'); + } + } private reportResolutionError(reason: string) { this.listener.onError({ @@ -51,38 +455,18 @@ class XdsResolver implements Resolver { updateResolution(): void { // Wait until updateResolution is called once to start the xDS requests - if (this.xdsClient === null) { + if (!this.isLdsWatcherActive) { trace('Starting resolution for target ' + uriToString(this.target)); - this.xdsClient = new XdsClient( - this.target.path, - { - onValidUpdate: (update: ServiceConfig) => { - trace('Resolved service config for target ' + uriToString(this.target) + ': ' + JSON.stringify(update)); - this.hasReportedSuccess = true; - this.listener.onSuccessfulResolution([], update, null, null, { - xdsClient: this.xdsClient, - }); - }, - onTransientError: (error: StatusObject) => { - /* A transient error only needs to bubble up as a failure if we have - * not already provided a ServiceConfig for the upper layer to use */ - if (!this.hasReportedSuccess) { - trace('Resolution error for target ' + uriToString(this.target) + ' due to xDS client transient error ' + error.details); - this.reportResolutionError(error.details); - } - }, - onResourceDoesNotExist: () => { - trace('Resolution error for target ' + uriToString(this.target) + ': resource does not exist'); - this.reportResolutionError("Resource does not exist"); - }, - }, - this.channelOptions - ); + getSingletonXdsClient().addListenerWatcher(this.target.path, this.ldsWatcher); + this.isLdsWatcherActive = true; } } destroy() { - this.xdsClient?.shutdown(); + getSingletonXdsClient().removeListenerWatcher(this.target.path, this.ldsWatcher); + if (this.latestRouteConfigName) { + getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); + } } static getDefaultAuthority(target: GrpcUri) { diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index ae67960d7..28994943e 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -50,6 +50,11 @@ import BackoffTimeout = experimental.BackoffTimeout; import ServiceConfig = experimental.ServiceConfig; import createGoogleDefaultCredentials = experimental.createGoogleDefaultCredentials; import { CdsLoadBalancingConfig } from './load-balancer-cds'; +import { EdsState } from './xds-stream-state/eds-state'; +import { CdsState } from './xds-stream-state/cds-state'; +import { RdsState } from './xds-stream-state/rds-state'; +import { LdsState } from './xds-stream-state/lds-state'; +import { Watcher } from './xds-stream-state/xds-stream-state'; const TRACER_NAME = 'xds_client'; @@ -131,12 +136,6 @@ function localityEqual( ); } -export interface Watcher { - onValidUpdate(update: UpdateType): void; - onTransientError(error: StatusObject): void; - onResourceDoesNotExist(): void; -} - export interface XdsClusterDropStats { addCallDropped(category: string): void; } @@ -219,450 +218,6 @@ class ClusterLoadReportMap { } } -interface XdsStreamState { - versionInfo: string; - nonce: string; - getResourceNames(): string[]; - /** - * Returns a string containing the error details if the message should be nacked, - * or null if it should be acked. - * @param responses - */ - handleResponses(responses: ResponseType[]): string | null; - - reportStreamError(status: StatusObject): void; -} - -class EdsState implements XdsStreamState { - public versionInfo = ''; - public nonce = ''; - - private watchers: Map< - string, - Watcher[] - > = new Map[]>(); - - private latestResponses: ClusterLoadAssignment__Output[] = []; - - constructor(private updateResourceNames: () => void) {} - - /** - * Add the watcher to the watcher list. Returns true if the list of resource - * names has changed, and false otherwise. - * @param edsServiceName - * @param watcher - */ - addWatcher( - edsServiceName: string, - watcher: Watcher - ): void { - let watchersEntry = this.watchers.get(edsServiceName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.watchers.set(edsServiceName, watchersEntry); - } - trace('Adding EDS watcher (' + watchersEntry.length + ' ->' + (watchersEntry.length + 1) + ') for edsServiceName ' + edsServiceName); - watchersEntry.push(watcher); - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - for (const message of this.latestResponses) { - if (message.cluster_name === edsServiceName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - trace('Reporting existing EDS update for new watcher for edsServiceName ' + edsServiceName); - watcher.onValidUpdate(message); - }); - } - } - if (addedServiceName) { - this.updateResourceNames(); - } - } - - removeWatcher( - edsServiceName: string, - watcher: Watcher - ): void { - trace('Removing EDS watcher for edsServiceName ' + edsServiceName); - const watchersEntry = this.watchers.get(edsServiceName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - trace('Removed EDS watcher (' + watchersEntry.length + ' -> ' + (watchersEntry.length - 1) + ') for edsServiceName ' + edsServiceName); - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.watchers.delete(edsServiceName); - } - } - if (removedServiceName) { - this.updateResourceNames(); - } - } - - getResourceNames(): string[] { - return Array.from(this.watchers.keys()); - } - - /** - * Validate the ClusterLoadAssignment object by these rules: - * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto - * @param message - */ - private validateResponse(message: ClusterLoadAssignment__Output) { - for (const endpoint of message.endpoints) { - for (const lb of endpoint.lb_endpoints) { - const socketAddress = lb.endpoint?.address?.socket_address; - if (!socketAddress) { - return false; - } - if (socketAddress.port_specifier !== 'port_value') { - return false; - } - if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { - return false; - } - } - } - return true; - } - - /** - * Given a list of edsServiceNames (which may actually be the cluster name), - * for each watcher watching a name not on the list, call that watcher's - * onResourceDoesNotExist method. - * @param allClusterNames - */ - handleMissingNames(allEdsServiceNames: Set) { - for (const [edsServiceName, watcherList] of this.watchers.entries()) { - if (!allEdsServiceNames.has(edsServiceName)) { - trace('Reporting EDS resource does not exist for edsServiceName ' + edsServiceName); - for (const watcher of watcherList) { - watcher.onResourceDoesNotExist(); - } - } - } - } - - handleResponses(responses: ClusterLoadAssignment__Output[]) { - for (const message of responses) { - if (!this.validateResponse(message)) { - trace('EDS validation failed for message ' + JSON.stringify(message)); - return 'EDS Error: ClusterLoadAssignment validation failed'; - } - } - this.latestResponses = responses; - const allClusterNames: Set = new Set(); - for (const message of responses) { - allClusterNames.add(message.cluster_name); - const watchers = this.watchers.get(message.cluster_name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); - } - } - trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); - this.handleMissingNames(allClusterNames); - return null; - } - - reportStreamError(status: StatusObject): void { - for (const watcherList of this.watchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - } -} - -class CdsState implements XdsStreamState { - versionInfo = ''; - nonce = ''; - - private watchers: Map[]> = new Map< - string, - Watcher[] - >(); - - private latestResponses: Cluster__Output[] = []; - - constructor( - private edsState: EdsState, - private updateResourceNames: () => void - ) {} - - /** - * Add the watcher to the watcher list. Returns true if the list of resource - * names has changed, and false otherwise. - * @param clusterName - * @param watcher - */ - addWatcher(clusterName: string, watcher: Watcher): void { - trace('Adding CDS watcher for clusterName ' + clusterName); - let watchersEntry = this.watchers.get(clusterName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.watchers.set(clusterName, watchersEntry); - } - watchersEntry.push(watcher); - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - for (const message of this.latestResponses) { - if (message.name === clusterName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - trace('Reporting existing CDS update for new watcher for clusterName ' + clusterName); - watcher.onValidUpdate(message); - }); - } - } - if (addedServiceName) { - this.updateResourceNames(); - } - } - - removeWatcher(clusterName: string, watcher: Watcher): void { - trace('Removing CDS watcher for clusterName ' + clusterName); - const watchersEntry = this.watchers.get(clusterName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.watchers.delete(clusterName); - } - } - if (removedServiceName) { - this.updateResourceNames(); - } - } - - getResourceNames(): string[] { - return Array.from(this.watchers.keys()); - } - - private validateResponse(message: Cluster__Output): boolean { - if (message.type !== 'EDS') { - return false; - } - if (!message.eds_cluster_config?.eds_config?.ads) { - return false; - } - if (message.lb_policy !== 'ROUND_ROBIN') { - return false; - } - if (message.lrs_server) { - if (!message.lrs_server.self) { - return false; - } - } - return true; - } - - /** - * Given a list of clusterNames (which may actually be the cluster name), - * for each watcher watching a name not on the list, call that watcher's - * onResourceDoesNotExist method. - * @param allClusterNames - */ - private handleMissingNames(allClusterNames: Set) { - for (const [clusterName, watcherList] of this.watchers.entries()) { - if (!allClusterNames.has(clusterName)) { - trace('Reporting CDS resource does not exist for clusterName ' + clusterName); - for (const watcher of watcherList) { - watcher.onResourceDoesNotExist(); - } - } - } - } - - handleResponses(responses: Cluster__Output[]): string | null { - for (const message of responses) { - if (!this.validateResponse(message)) { - trace('CDS validation failed for message ' + JSON.stringify(message)); - return 'CDS Error: Cluster validation failed'; - } - } - this.latestResponses = responses; - const allEdsServiceNames: Set = new Set(); - const allClusterNames: Set = new Set(); - for (const message of responses) { - allClusterNames.add(message.name); - const edsServiceName = message.eds_cluster_config?.service_name ?? ''; - allEdsServiceNames.add( - edsServiceName === '' ? message.name : edsServiceName - ); - const watchers = this.watchers.get(message.name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message); - } - } - trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); - this.handleMissingNames(allClusterNames); - this.edsState.handleMissingNames(allEdsServiceNames); - return null; - } - - reportStreamError(status: StatusObject): void { - for (const watcherList of this.watchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - } -} - -class RdsState implements XdsStreamState { - versionInfo = ''; - nonce = ''; - - private routeConfigName: string | null = null; - - constructor( - private targetName: string, - private watcher: Watcher, - private updateResouceNames: () => void - ) {} - - getResourceNames(): string[] { - return this.routeConfigName ? [this.routeConfigName] : []; - } - - handleSingleMessage(message: RouteConfiguration__Output) { - for (const virtualHost of message.virtual_hosts) { - if (virtualHost.domains.indexOf(this.targetName) >= 0) { - const route = virtualHost.routes[virtualHost.routes.length - 1]; - if (route.match?.prefix === '' && route.route?.cluster) { - trace('Reporting RDS update for host ' + this.targetName + ' with cluster ' + route.route.cluster); - this.watcher.onValidUpdate({ - methodConfig: [], - loadBalancingConfig: [ - new CdsLoadBalancingConfig(route.route.cluster) - ], - }); - return; - } else { - trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); - } - } - } - trace('Reporting RDS resource does not exist from domain lists ' + message.virtual_hosts.map(virtualHost => virtualHost.domains)); - /* If none of the routes match the one we are looking for, bubble up an - * error. */ - this.watcher.onResourceDoesNotExist(); - } - - handleResponses(responses: RouteConfiguration__Output[]): string | null { - trace('Received RDS response with route config names ' + responses.map(message => message.name)); - if (this.routeConfigName !== null) { - for (const message of responses) { - if (message.name === this.routeConfigName) { - this.handleSingleMessage(message); - return null; - } - } - } - return null; - } - - setRouteConfigName(name: string | null) { - const oldName = this.routeConfigName; - this.routeConfigName = name; - if (name !== oldName) { - this.updateResouceNames(); - } - } - - reportStreamError(status: StatusObject): void { - this.watcher.onTransientError(status); - } -} - -class LdsState implements XdsStreamState { - versionInfo = ''; - nonce = ''; - - constructor(private targetName: string, private rdsState: RdsState) {} - - getResourceNames(): string[] { - return [this.targetName]; - } - - private validateResponse(message: Listener__Output): boolean { - if ( - !( - message.api_listener?.api_listener && - protoLoader.isAnyExtension(message.api_listener.api_listener) && - message.api_listener?.api_listener['@type'] === - HTTP_CONNECTION_MANGER_TYPE_URL - ) - ) { - return false; - } - const httpConnectionManager = message.api_listener - ?.api_listener as protoLoader.AnyExtension & - HttpConnectionManager__Output; - switch (httpConnectionManager.route_specifier) { - case 'rds': - return !!httpConnectionManager.rds?.config_source?.ads; - case 'route_config': - return true; - } - return false; - } - - handleResponses(responses: Listener__Output[]): string | null { - trace('Received LDS update with names ' + responses.map(message => message.name)); - for (const message of responses) { - if (message.name === this.targetName) { - if (this.validateResponse(message)) { - // The validation step ensures that this is correct - const httpConnectionManager = message.api_listener! - .api_listener as protoLoader.AnyExtension & - HttpConnectionManager__Output; - switch (httpConnectionManager.route_specifier) { - case 'rds': - trace('Received LDS update with RDS route config name ' + httpConnectionManager.rds!.route_config_name); - this.rdsState.setRouteConfigName( - httpConnectionManager.rds!.route_config_name - ); - break; - case 'route_config': - trace('Received LDS update with route configuration'); - this.rdsState.setRouteConfigName(null); - this.rdsState.handleSingleMessage( - httpConnectionManager.route_config! - ); - break; - default: - // The validation rules should prevent this - } - } else { - trace('LRS validation error for message ' + JSON.stringify(message)); - return 'LRS Error: Listener validation failed'; - } - } - } - return null; - } - - reportStreamError(status: StatusObject): void { - // Nothing to do here - } -} - interface AdsState { [EDS_TYPE_URL]: EdsState; [CDS_TYPE_URL]: CdsState; @@ -728,21 +283,19 @@ export class XdsClient { private adsBackoff: BackoffTimeout; private lrsBackoff: BackoffTimeout; - constructor( - targetName: string, - serviceConfigWatcher: Watcher, - channelOptions: ChannelOptions - ) { + constructor() { const edsState = new EdsState(() => { this.updateNames(EDS_TYPE_URL); }); const cdsState = new CdsState(edsState, () => { this.updateNames(CDS_TYPE_URL); }); - const rdsState = new RdsState(targetName, serviceConfigWatcher, () => { + const rdsState = new RdsState(() => { this.updateNames(RDS_TYPE_URL); }); - const ldsState = new LdsState(targetName, rdsState); + const ldsState = new LdsState(rdsState, () => { + this.updateNames(LDS_TYPE_URL); + }); this.adsState = { [EDS_TYPE_URL]: edsState, [CDS_TYPE_URL]: cdsState, @@ -750,26 +303,10 @@ export class XdsClient { [LDS_TYPE_URL]: ldsState, }; - const channelArgs = { ...channelOptions }; - const channelArgsToRemove = [ - /* The SSL target name override corresponds to the target, and this - * client has its own target */ - 'grpc.ssl_target_name_override', - /* The default authority also corresponds to the target */ - 'grpc.default_authority', - /* This client will have its own specific keepalive time setting */ - 'grpc.keepalive_time_ms', - /* The service config specifies the load balancing policy. This channel - * needs its own separate load balancing policy setting. In particular, - * recursively using an xDS load balancer for the xDS client would be - * bad */ - 'grpc.service_config', - ]; - for (const arg of channelArgsToRemove) { - delete channelArgs[arg]; + const channelArgs = { + // 5 minutes + 'grpc.keepalive_time_ms': 5 * 60 * 1000 } - // 5 minutes - channelArgs['grpc.keepalive_time_ms'] = 5 * 60 * 1000; this.adsBackoff = new BackoffTimeout(() => { this.maybeStartAdsStream(); @@ -823,14 +360,12 @@ export class XdsClient { channelCreds, channelArgs ); - this.maybeStartAdsStream(); this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( bootstrapInfo.xdsServers[0].serverUri, channelCreds, {channelOverride: this.adsClient.getChannel()} ); - this.maybeStartLrsStream(); }, (error) => { trace('Failed to initialize xDS Client. ' + error.message); @@ -986,6 +521,16 @@ export class XdsClient { } private updateNames(typeUrl: AdsTypeUrl) { + if (this.adsState[EDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[CDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[RDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[LDS_TYPE_URL].getResourceNames().length === 0) { + this.adsCall?.end(); + this.lrsCall?.end(); + return; + } + this.maybeStartAdsStream(); + this.maybeStartLrsStream(); trace('Sending update for type URL ' + typeUrl + ' with names ' + this.adsState[typeUrl].getResourceNames()); this.adsCall?.write({ node: this.adsNode!, @@ -1159,6 +704,26 @@ export class XdsClient { this.adsState[CDS_TYPE_URL].removeWatcher(clusterName, watcher); } + addRouteWatcher(routeConfigName: string, watcher: Watcher) { + trace('Watcher added for route ' + routeConfigName); + this.adsState[RDS_TYPE_URL].addWatcher(routeConfigName, watcher); + } + + removeRouteWatcher(routeConfigName: string, watcher: Watcher) { + trace('Watcher removed for route ' + routeConfigName); + this.adsState[RDS_TYPE_URL].removeWatcher(routeConfigName, watcher); + } + + addListenerWatcher(targetName: string, watcher: Watcher) { + trace('Watcher added for listener ' + targetName); + this.adsState[LDS_TYPE_URL].addWatcher(targetName, watcher); + } + + removeListenerWatcher(targetName: string, watcher: Watcher) { + trace('Watcher removed for listener ' + targetName); + this.adsState[LDS_TYPE_URL].removeWatcher(targetName, watcher); + } + /** * * @param lrsServer The target name of the server to send stats to. An empty @@ -1241,7 +806,7 @@ export class XdsClient { }; } - shutdown(): void { + private shutdown(): void { this.adsCall?.cancel(); this.adsClient?.close(); this.lrsCall?.cancel(); @@ -1249,3 +814,12 @@ export class XdsClient { this.hasShutdown = true; } } + +let singletonXdsClient: XdsClient | null = null; + +export function getSingletonXdsClient(): XdsClient { + if (singletonXdsClient === null) { + singletonXdsClient = new XdsClient(); + } + return singletonXdsClient; +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index c5db3bfad..554712727 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -19,7 +19,7 @@ import * as protoLoader from '@grpc/proto-loader'; import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { Listener__Output } from "../generated/envoy/api/v2/Listener"; import { RdsState } from "./rds-state"; -import { XdsStreamState } from "./xds-stream-state"; +import { Watcher, XdsStreamState } from "./xds-stream-state"; import { HttpConnectionManager__Output } from '../generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; const TRACER_NAME = 'xds_client'; @@ -35,10 +35,60 @@ export class LdsState implements XdsStreamState { versionInfo = ''; nonce = ''; - constructor(private targetName: string, private rdsState: RdsState) {} + private watchers: Map[]> = new Map[]>(); + private latestResponses: Listener__Output[] = []; + + constructor(private rdsState: RdsState, private updateResourceNames: () => void) {} + + addWatcher(targetName: string, watcher: Watcher) { + trace('Adding RDS watcher for targetName ' + targetName); + let watchersEntry = this.watchers.get(targetName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(targetName, watchersEntry); + } + watchersEntry.push(watcher); + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.name === targetName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + trace('Reporting existing RDS update for new watcher for targetName ' + targetName); + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } + + removeWatcher(targetName: string, watcher: Watcher): void { + trace('Removing RDS watcher for targetName ' + targetName); + const watchersEntry = this.watchers.get(targetName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(targetName); + } + } + if (removedServiceName) { + this.updateResourceNames(); + } + } getResourceNames(): string[] { - return [this.targetName]; + return Array.from(this.watchers.keys()); } private validateResponse(message: Listener__Output): boolean { @@ -59,47 +109,47 @@ export class LdsState implements XdsStreamState { case 'rds': return !!httpConnectionManager.rds?.config_source?.ads; case 'route_config': - return true; + return this.rdsState.validateResponse(httpConnectionManager.route_config!); } return false; } + private handleMissingNames(allTargetNames: Set) { + for (const [targetName, watcherList] of this.watchers.entries()) { + if (!allTargetNames.has(targetName)) { + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); + } + } + } + } + handleResponses(responses: Listener__Output[]): string | null { - trace('Received LDS update with names ' + responses.map(message => message.name)); for (const message of responses) { - if (message.name === this.targetName) { - if (this.validateResponse(message)) { - // The validation step ensures that this is correct - const httpConnectionManager = message.api_listener! - .api_listener as protoLoader.AnyExtension & - HttpConnectionManager__Output; - switch (httpConnectionManager.route_specifier) { - case 'rds': - trace('Received LDS update with RDS route config name ' + httpConnectionManager.rds!.route_config_name); - this.rdsState.setRouteConfigName( - httpConnectionManager.rds!.route_config_name - ); - break; - case 'route_config': - trace('Received LDS update with route configuration'); - this.rdsState.setRouteConfigName(null); - this.rdsState.handleSingleMessage( - httpConnectionManager.route_config! - ); - break; - default: - // The validation rules should prevent this - } - } else { - trace('LRS validation error for message ' + JSON.stringify(message)); - return 'LRS Error: Listener validation failed'; - } + if (!this.validateResponse(message)) { + trace('LDS validation failed for message ' + JSON.stringify(message)); + return 'LDS Error: Route validation failed'; + } + } + this.latestResponses = responses; + const allTargetNames = new Set(); + for (const message of responses) { + allTargetNames.add(message.name); + const watchers = this.watchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); } } + trace('Received RDS response with route config names ' + Array.from(allTargetNames)); + this.handleMissingNames(allTargetNames); return null; } reportStreamError(status: StatusObject): void { - // Nothing to do here + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } } } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 182685875..2ac924d98 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -16,6 +16,7 @@ */ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { GRPC_XDS_EXPERIMENTAL_ROUTING } from "../environment"; import { RouteConfiguration__Output } from "../generated/envoy/api/v2/RouteConfiguration"; import { CdsLoadBalancingConfig } from "../load-balancer-cds"; import { Watcher, XdsStreamState } from "./xds-stream-state"; @@ -27,68 +28,164 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } +const SUPPORTED_PATH_SPECIFIERS = ['prefix', 'path', 'safe_regex']; +const SUPPPORTED_HEADER_MATCH_SPECIFIERS = [ + 'exact_match', + 'safe_regex_match', + 'range_match', + 'present_match', + 'prefix_match', + 'suffix_match']; +const SUPPORTED_CLUSTER_SPECIFIERS = ['cluster', 'weighted_clusters', 'cluster_header']; + export class RdsState implements XdsStreamState { versionInfo = ''; nonce = ''; - private routeConfigName: string | null = null; + private watchers: Map[]> = new Map[]>(); + private latestResponses: RouteConfiguration__Output[] = []; + + constructor(private updateResourceNames: () => void) {} + + addWatcher(routeConfigName: string, watcher: Watcher) { + trace('Adding RDS watcher for routeConfigName ' + routeConfigName); + let watchersEntry = this.watchers.get(routeConfigName); + let addedServiceName = false; + if (watchersEntry === undefined) { + addedServiceName = true; + watchersEntry = []; + this.watchers.set(routeConfigName, watchersEntry); + } + watchersEntry.push(watcher); + + /* If we have already received an update for the requested edsServiceName, + * immediately pass that update along to the watcher */ + for (const message of this.latestResponses) { + if (message.name === routeConfigName) { + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + trace('Reporting existing RDS update for new watcher for routeConfigName ' + routeConfigName); + watcher.onValidUpdate(message); + }); + } + } + if (addedServiceName) { + this.updateResourceNames(); + } + } - constructor( - private targetName: string, - private watcher: Watcher, - private updateResouceNames: () => void - ) {} + removeWatcher(routeConfigName: string, watcher: Watcher): void { + trace('Removing RDS watcher for routeConfigName ' + routeConfigName); + const watchersEntry = this.watchers.get(routeConfigName); + let removedServiceName = false; + if (watchersEntry !== undefined) { + const entryIndex = watchersEntry.indexOf(watcher); + if (entryIndex >= 0) { + watchersEntry.splice(entryIndex, 1); + } + if (watchersEntry.length === 0) { + removedServiceName = true; + this.watchers.delete(routeConfigName); + } + } + if (removedServiceName) { + this.updateResourceNames(); + } + } getResourceNames(): string[] { - return this.routeConfigName ? [this.routeConfigName] : []; + return Array.from(this.watchers.keys()); } - handleSingleMessage(message: RouteConfiguration__Output) { - for (const virtualHost of message.virtual_hosts) { - if (virtualHost.domains.indexOf(this.targetName) >= 0) { - const route = virtualHost.routes[virtualHost.routes.length - 1]; - if (route.match?.prefix === '' && route.route?.cluster) { - trace('Reporting RDS update for host ' + this.targetName + ' with cluster ' + route.route.cluster); - this.watcher.onValidUpdate({ - methodConfig: [], - loadBalancingConfig: [ - new CdsLoadBalancingConfig(route.route.cluster) - ], - }); - return; - } else { - trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); + validateResponse(message: RouteConfiguration__Output): boolean { + if (GRPC_XDS_EXPERIMENTAL_ROUTING) { + // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation + for (const virtualHost of message.virtual_hosts) { + for (const domainPattern of virtualHost.domains) { + const starIndex = domainPattern.indexOf('*'); + const lastStarIndex = domainPattern.lastIndexOf('*'); + // A domain pattern can have at most one wildcard * + if (starIndex !== lastStarIndex) { + return false; + } + // A wildcard * can either be absent or at the beginning or end of the pattern + if (!(starIndex === -1 || starIndex === 0 || starIndex === domainPattern.length - 1)) { + return false; + } + } + for (const route of virtualHost.routes) { + const match = route.match; + if (!match) { + return false; + } + if (SUPPORTED_PATH_SPECIFIERS.indexOf(match.path_specifier) < 0) { + return false; + } + for (const headers of match.headers) { + if (SUPPPORTED_HEADER_MATCH_SPECIFIERS.indexOf(headers.header_match_specifier) < 0) { + return false; + } + } + if (route.action !== 'route') { + return false; + } + if ((route.route === undefined) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { + return false; + } + if (route.route!.cluster_specifier === 'weighted_clusters') { + let weightSum = 0; + for (const clusterWeight of route.route.weighted_clusters!.clusters) { + weightSum += clusterWeight.weight?.value ?? 0; + } + if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { + return false; + } + } } } + return true; + } else { + return true; } - trace('Reporting RDS resource does not exist from domain lists ' + message.virtual_hosts.map(virtualHost => virtualHost.domains)); - /* If none of the routes match the one we are looking for, bubble up an - * error. */ - this.watcher.onResourceDoesNotExist(); } - handleResponses(responses: RouteConfiguration__Output[]): string | null { - trace('Received RDS response with route config names ' + responses.map(message => message.name)); - if (this.routeConfigName !== null) { - for (const message of responses) { - if (message.name === this.routeConfigName) { - this.handleSingleMessage(message); - return null; + private handleMissingNames(allRouteConfigNames: Set) { + for (const [routeConfigName, watcherList] of this.watchers.entries()) { + if (!allRouteConfigNames.has(routeConfigName)) { + for (const watcher of watcherList) { + watcher.onResourceDoesNotExist(); } } } - return null; } - setRouteConfigName(name: string | null) { - const oldName = this.routeConfigName; - this.routeConfigName = name; - if (name !== oldName) { - this.updateResouceNames(); + handleResponses(responses: RouteConfiguration__Output[]): string | null { + for (const message of responses) { + if (!this.validateResponse(message)) { + trace('RDS validation failed for message ' + JSON.stringify(message)); + return 'RDS Error: Route validation failed'; + } + } + this.latestResponses = responses; + const allRouteConfigNames = new Set(); + for (const message of responses) { + allRouteConfigNames.add(message.name); + const watchers = this.watchers.get(message.name) ?? []; + for (const watcher of watchers) { + watcher.onValidUpdate(message); + } } + trace('Received RDS response with route config names ' + Array.from(allRouteConfigNames)); + this.handleMissingNames(allRouteConfigNames); + return null; } reportStreamError(status: StatusObject): void { - this.watcher.onTransientError(status); + for (const watcherList of this.watchers.values()) { + for (const watcher of watcherList) { + watcher.onTransientError(status); + } + } } } \ No newline at end of file diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index b88f124ae..a0119ccb8 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -1,5 +1,5 @@ export { trace } from './logging'; -export { Resolver, ResolverListener, registerResolver } from './resolver'; +export { Resolver, ResolverListener, registerResolver, ConfigSelector } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; export { ServiceConfig } from './service-config'; export { createGoogleDefaultCredentials } from './channel-credentials'; From 40242a4132ffd4297f24977cee5328b4dba49e35 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Mar 2021 11:42:20 -0800 Subject: [PATCH 1358/1899] Use the new LB policy in the resolver --- packages/grpc-js-xds/src/environment.ts | 4 ++++ .../src/load-balancer-xds-cluster-manager.ts | 2 +- packages/grpc-js-xds/src/resolver-xds.ts | 15 ++++++++++++--- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index 67fc531e4..56d233ddf 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -15,4 +15,8 @@ * */ +/** + * Environment variable protection for traffic splitting and routing + * https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#xds-resolver-and-xds-client + */ export const GRPC_XDS_EXPERIMENTAL_ROUTING = (process.env.GRPC_XDS_EXPERIMENTAL_ROUTING === 'true'); \ No newline at end of file diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index f8d2de258..6faa0505b 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -44,7 +44,7 @@ interface ClusterManagerChild { child_policy: LoadBalancingConfig[]; } -class XdsClusterManagerLoadBalancingConfig implements LoadBalancingConfig { +export class XdsClusterManagerLoadBalancingConfig implements LoadBalancingConfig { getLoadBalancerName(): string { return TYPE_NAME; } diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index b3c78adaf..99bbd58ce 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -37,6 +37,7 @@ import { RouteMatch__Output } from './generated/envoy/api/v2/route/RouteMatch'; import { HeaderMatcher__Output } from './generated/envoy/api/v2/route/HeaderMatcher'; import ConfigSelector = experimental.ConfigSelector; import LoadBalancingConfig = experimental.LoadBalancingConfig; +import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluster-manager'; const TRACER_NAME = 'xds_resolver'; @@ -376,7 +377,8 @@ class XdsResolver implements Resolver { const routeMatcher = getPredicateForMatcher(route.match!); matchList.push({matcher: routeMatcher, action: routeAction}); } - // Mark clusters that are not in this config, and remove ones with no references + /* Mark clusters that are not in this route config, and remove ones with + * no references */ for (const [name, refCount] of Array.from(this.clusterRefcounts.entries())) { if (!allConfigClusters.has(name)) { refCount.inLastConfig = false; @@ -385,6 +387,7 @@ class XdsResolver implements Resolver { } } } + // Add any new clusters from this route config for (const name of allConfigClusters) { if (this.clusterRefcounts.has(name)) { this.clusterRefcounts.get(name)!.inLastConfig = true; @@ -410,7 +413,7 @@ class XdsResolver implements Resolver { } return { methodConfig: {name: []}, - // pickInformation won't be used here, but it's set because of some TypeScript weirdness + // cluster won't be used here, but it's set because of some TypeScript weirdness pickInformation: {cluster: ''}, status: status.UNAVAILABLE }; @@ -419,8 +422,14 @@ class XdsResolver implements Resolver { for (const clusterName of this.clusterRefcounts.keys()) { clusterConfigMap.set(clusterName, {child_policy: [new CdsLoadBalancingConfig(clusterName)]}); } - // TODO: Create xdsClusterManagerLoadBalancingConfig and report successful resolution + const lbPolicyConfig = new XdsClusterManagerLoadBalancingConfig(clusterConfigMap); + const serviceConfig: ServiceConfig = { + methodConfig: [], + loadBalancingConfig: [lbPolicyConfig] + } + this.listener.onSuccessfulResolution([], serviceConfig, null, configSelector, {}); } else { + // !GRPC_XDS_EXPERIMENTAL_ROUTING for (const virtualHost of routeConfig.virtual_hosts) { if (virtualHost.domains.indexOf(this.target.path) >= 0) { const route = virtualHost.routes[virtualHost.routes.length - 1]; From 66d3f352639e0eb6d3f28866295ce2c5eeda3fc2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Mar 2021 11:54:20 -0800 Subject: [PATCH 1359/1899] Enable traffic splitting xds interop test --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index bbfc30562..a1bd7d406 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -52,7 +52,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="backends_restart,change_backend_service,gentle_failover,ping_pong,remove_instance_group,round_robin,secondary_locality_gets_no_requests_on_partial_primary_failure,secondary_locality_gets_requests_on_primary_failure" \ + --test_case="all" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From 2b451fdfba1e53ae6d0c682e5bda06a8c2453d64 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Mar 2021 11:55:15 -0800 Subject: [PATCH 1360/1899] Temporarily borrow linux test job for xds tests --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..16a7dc7dc 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From f6505b50db78c29aa4854e6b5d454bda26c63c0c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Mar 2021 13:03:13 -0800 Subject: [PATCH 1361/1899] Enable routing feature in xDS tests --- packages/grpc-js-xds/scripts/xds.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index a1bd7d406..d76eaf4f3 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -51,6 +51,7 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ + GRPC_XDS_EXPERIMENTAL_ROUTING=true \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all" \ --project_id=grpc-testing \ From c5cc8b2652b4ec8ccde978f1ef4b954a80e92df0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Mar 2021 11:55:42 -0800 Subject: [PATCH 1362/1899] grpc-js: Speculative fix for ECONNRESET errors --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 53 +++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 638c19200..8fffe4beb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.8", + "version": "1.2.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 9c27aeb1f..a51c1da28 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -16,6 +16,7 @@ */ import * as http2 from 'http2'; +import * as os from 'os'; import { CallCredentials } from './call-credentials'; import { Propagate, Status } from './constants'; @@ -37,8 +38,34 @@ const { NGHTTP2_CANCEL, } = http2.constants; -interface NodeError extends Error { +/** + * https://nodejs.org/api/errors.html#errors_class_systemerror + */ +interface SystemError extends Error { + address?: string; code: string; + dest?: string; + errno: number; + info?: object; + message: string; + path?: string; + port?: number; + syscall: string; +} + +/** + * Should do approximately the same thing as util.getSystemErrorName but the + * TypeScript types don't have that function for some reason so I just made my + * own. + * @param errno + */ +function getSystemErrorName(errno: number): string { + for (const [name, num] of Object.entries(os.constants.errno)) { + if (num === errno) { + return name; + } + } + return 'Unknown system error ' + errno; } export type Deadline = Date | number; @@ -206,7 +233,7 @@ export class Http2CallStream implements Call { private listener: InterceptingListener | null = null; - private internalErrorMessage: string | null = null; + private internalError: SystemError | null = null; constructor( private readonly methodName: string, @@ -567,7 +594,7 @@ export class Http2CallStream implements Call { break; case http2.constants.NGHTTP2_INTERNAL_ERROR: code = Status.INTERNAL; - if (this.internalErrorMessage === null) { + if (this.internalError === null) { /* This error code was previously handled in the default case, and * there are several instances of it online, so I wanted to * preserve the original error message so that people find existing @@ -575,11 +602,16 @@ export class Http2CallStream implements Call { * "Internal server error" message. */ details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; } else { - /* The "Received RST_STREAM with code ..." error is preserved - * here for continuity with errors reported online, but the - * error message at the end will probably be more relevant in - * most cases. */ - details = `Received RST_STREAM with code ${stream.rstCode} triggered by internal client error: ${this.internalErrorMessage}`; + if (this.internalError.errno === os.constants.errno.ECONNRESET) { + code = Status.UNAVAILABLE; + details = this.internalError.message; + } else { + /* The "Received RST_STREAM with code ..." error is preserved + * here for continuity with errors reported online, but the + * error message at the end will probably be more relevant in + * most cases. */ + details = `Received RST_STREAM with code ${stream.rstCode} triggered by internal client error: ${this.internalError.message}`; + } } break; default: @@ -593,7 +625,7 @@ export class Http2CallStream implements Call { this.endCall({ code, details, metadata: new Metadata() }); }); }); - stream.on('error', (err: NodeError) => { + stream.on('error', (err: SystemError) => { /* We need an error handler here to stop "Uncaught Error" exceptions * from bubbling up. However, errors here should all correspond to * "close" events, where we will handle the error more granularly */ @@ -602,7 +634,8 @@ export class Http2CallStream implements Call { * https://github.com/nodejs/node/blob/8b8620d580314050175983402dfddf2674e8e22a/lib/internal/http2/core.js#L2267 */ if (err.code !== 'ERR_HTTP2_STREAM_ERROR') { - this.internalErrorMessage = err.message; + this.trace('Node error event: message=' + err.message + ' code=' + err.code + ' errno=' + getSystemErrorName(err.errno) + ' syscall=' + err.syscall); + this.internalError = err; } }); if (!this.pendingRead) { From ca4b8f40c9c5562c83607b3ba0a184b26c1535a6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Mar 2021 12:51:23 -0800 Subject: [PATCH 1363/1899] Start ADS and LRS streams at client startup if watchers have been added --- packages/grpc-js-xds/src/xds-client.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 83cd86cc0..c928d5c08 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -360,12 +360,14 @@ export class XdsClient { channelCreds, channelArgs ); + this.maybeStartAdsStream(); this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( bootstrapInfo.xdsServers[0].serverUri, channelCreds, {channelOverride: this.adsClient.getChannel()} ); + this.maybeStartLrsStream(); }, (error) => { trace('Failed to initialize xDS Client. ' + error.message); @@ -439,6 +441,12 @@ export class XdsClient { if (this.hasShutdown) { return; } + if (this.adsState[EDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[CDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[RDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[LDS_TYPE_URL].getResourceNames().length === 0) { + return; + } trace('Starting ADS stream'); // Backoff relative to when we start the request this.adsBackoff.runOnce(); @@ -558,6 +566,12 @@ export class XdsClient { if (this.hasShutdown) { return; } + if (this.adsState[EDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[CDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[RDS_TYPE_URL].getResourceNames().length === 0 && + this.adsState[LDS_TYPE_URL].getResourceNames().length === 0) { + return; + } trace('Starting LRS stream'); From a72626558049eacd72d95f8139dabeb47edf494c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 3 Mar 2021 13:15:57 -0800 Subject: [PATCH 1364/1899] Remove checks for now-unused xdsClient attribute --- packages/grpc-js-xds/src/load-balancer-cds.ts | 4 ---- packages/grpc-js-xds/src/load-balancer-eds.ts | 4 ---- packages/grpc-js-xds/src/load-balancer-lrs.ts | 7 ++----- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index 9a372588b..d0fe2338a 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -121,10 +121,6 @@ export class CdsLoadBalancer implements LoadBalancer { trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig, undefined, 2)); return; } - if (!(attributes.xdsClient instanceof XdsClient)) { - trace('Discarding address list update missing xdsClient attribute'); - return; - } trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2)); this.latestAttributes = attributes; diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 35da2a46a..efc67ffea 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -427,10 +427,6 @@ export class EdsLoadBalancer implements LoadBalancer { trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } - if (!(attributes.xdsClient instanceof XdsClient)) { - trace('Discarding address list update missing xdsClient attribute'); - return; - } trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index b6fa68091..a6bbcb875 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -18,7 +18,7 @@ import { connectivityState as ConnectivityState, StatusObject, status as Status, experimental } from '@grpc/grpc-js'; import { type } from 'os'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; -import { XdsClusterLocalityStats, XdsClient } from './xds-client'; +import { XdsClusterLocalityStats, XdsClient, getSingletonXdsClient } from './xds-client'; import LoadBalancer = experimental.LoadBalancer; import ChannelControlHelper = experimental.ChannelControlHelper; import registerLoadBalancerType = experimental.registerLoadBalancerType; @@ -208,10 +208,7 @@ export class LrsLoadBalancer implements LoadBalancer { if (!(lbConfig instanceof LrsLoadBalancingConfig)) { return; } - if (!(attributes.xdsClient instanceof XdsClient)) { - return; - } - this.localityStatsReporter = attributes.xdsClient.addClusterLocalityStats( + this.localityStatsReporter = getSingletonXdsClient().addClusterLocalityStats( lbConfig.getLrsLoadReportingServerName(), lbConfig.getClusterName(), lbConfig.getEdsServiceName(), From fb8916cc6d202ebd39f78e85423d32a22e47e38e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 10:16:17 -0800 Subject: [PATCH 1365/1899] Enable path_matching and header_matching tests --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index d76eaf4f3..308017976 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -53,7 +53,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh NODE_XDS_INTEROP_VERBOSITY=1 \ GRPC_XDS_EXPERIMENTAL_ROUTING=true \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all" \ + --test_case="all,path_matching,header_matching" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From 08a359744d94319e492c900f80be063ec60b019c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 11:50:30 -0800 Subject: [PATCH 1366/1899] Add more detailed LRS tracing --- packages/grpc-js-xds/src/xds-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index c928d5c08..c42ce663c 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -625,7 +625,6 @@ export class XdsClient { if (!this.lrsCall) { return; } - trace('Sending LRS stats'); const clusterStats: ClusterStats[] = []; for (const [ { clusterName, edsServiceName }, @@ -686,6 +685,7 @@ export class XdsClient { } } } + trace('Sending LRS stats ' + JSON.stringify(clusterStats, undefined, 2)); this.lrsCall.write({ node: this.lrsNode!, cluster_stats: clusterStats, From 76f4e3fef445eed2a100d68c1ebc73bd287dc627 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 13:43:17 -0800 Subject: [PATCH 1367/1899] Disable path_matching and header_matching tests for now --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 308017976..d76eaf4f3 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -53,7 +53,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh NODE_XDS_INTEROP_VERBOSITY=1 \ GRPC_XDS_EXPERIMENTAL_ROUTING=true \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all,path_matching,header_matching" \ + --test_case="all" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From 5ef5246375b2d45a495c6c3f4c5c03fbc0a02144 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 13:53:02 -0800 Subject: [PATCH 1368/1899] Fix handling of LRS server name in EDS child config generation Also add more LRS logging --- packages/grpc-js-xds/src/load-balancer-eds.ts | 2 +- packages/grpc-js-xds/src/load-balancer-lrs.ts | 1 - packages/grpc-js-xds/src/xds-client.ts | 2 ++ 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index efc67ffea..01e40f5ac 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -377,7 +377,7 @@ export class EdsLoadBalancer implements LoadBalancer { validateLoadBalancingConfig({ round_robin: {} }), ]; let childPolicy: LoadBalancingConfig[]; - if (this.lastestConfig.getLrsLoadReportingServerName()) { + if (this.lastestConfig.getLrsLoadReportingServerName() !== undefined) { childPolicy = [new LrsLoadBalancingConfig(this.lastestConfig.getCluster(), this.lastestConfig.getEdsServiceName() ?? '', this.lastestConfig.getLrsLoadReportingServerName()!, localityObj.locality, endpointPickingPolicy)]; } else { childPolicy = endpointPickingPolicy; diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index a6bbcb875..0792b11c2 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -16,7 +16,6 @@ */ import { connectivityState as ConnectivityState, StatusObject, status as Status, experimental } from '@grpc/grpc-js'; -import { type } from 'os'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { XdsClusterLocalityStats, XdsClient, getSingletonXdsClient } from './xds-client'; import LoadBalancer = experimental.LoadBalancer; diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index c42ce663c..8ecd5bb75 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -751,6 +751,7 @@ export class XdsClient { clusterName: string, edsServiceName: string ): XdsClusterDropStats { + trace('addClusterDropStats(lrsServer=' + lrsServer + ', clusterName=' + clusterName + ', edsServiceName=' + edsServiceName + ')'); if (lrsServer !== '') { return { addCallDropped: (category) => {}, @@ -774,6 +775,7 @@ export class XdsClient { edsServiceName: string, locality: Locality__Output ): XdsClusterLocalityStats { + trace('addClusterLocalityStats(lrsServer=' + lrsServer + ', clusterName=' + clusterName + ', edsServiceName=' + edsServiceName + ', locality=' + JSON.stringify(locality) + ')'); if (lrsServer !== '') { return { addCallStarted: () => {}, From 356518a212355f90dd1248a2f6c7565771078ecc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 13:56:57 -0800 Subject: [PATCH 1369/1899] grpc-js-xds: Fix handling of empty LRS server names --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/scripts/xds.sh | 2 +- packages/grpc-js-xds/src/load-balancer-eds.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 5ff82e49d..b5c9d3f15 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.2.2", + "version": "1.2.3", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index bbfc30562..4629f42a7 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -52,7 +52,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="backends_restart,change_backend_service,gentle_failover,ping_pong,remove_instance_group,round_robin,secondary_locality_gets_no_requests_on_partial_primary_failure,secondary_locality_gets_requests_on_primary_failure" \ + --test_case="backends_restart,change_backend_service,gentle_failover,ping_pong,remove_instance_group,round_robin,secondary_locality_gets_no_requests_on_partial_primary_failure,secondary_locality_gets_requests_on_primary_failure,load_report_based_failover" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 8919f3174..93cc64218 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -377,7 +377,7 @@ export class EdsLoadBalancer implements LoadBalancer { validateLoadBalancingConfig({ round_robin: {} }), ]; let childPolicy: LoadBalancingConfig[]; - if (this.lastestConfig.getLrsLoadReportingServerName()) { + if (this.lastestConfig.getLrsLoadReportingServerName() !== undefined) { childPolicy = [new LrsLoadBalancingConfig(this.lastestConfig.getCluster(), this.lastestConfig.getEdsServiceName() ?? '', this.lastestConfig.getLrsLoadReportingServerName()!, localityObj.locality, endpointPickingPolicy)]; } else { childPolicy = endpointPickingPolicy; From 1702014385d00ec1c58fd6f91d35184414a6064d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 14:01:59 -0800 Subject: [PATCH 1370/1899] Borrow Linux Kokoro job for xDS testing --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..16a7dc7dc 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From b85c70839f4494371d586d463cd2f877c448d0d9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 11:50:30 -0800 Subject: [PATCH 1371/1899] Add more detailed LRS tracing --- packages/grpc-js-xds/src/xds-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 7f6586573..f147da0eb 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -1068,7 +1068,6 @@ export class XdsClient { if (!this.lrsCall) { return; } - trace('Sending LRS stats'); const clusterStats: ClusterStats[] = []; for (const [ { clusterName, edsServiceName }, @@ -1129,6 +1128,7 @@ export class XdsClient { } } } + trace('Sending LRS stats ' + JSON.stringify(clusterStats, undefined, 2)); this.lrsCall.write({ node: this.lrsNode!, cluster_stats: clusterStats, From e3b35505a0aff40b8a1adabafb5a5443bf7ce7d9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 13:53:02 -0800 Subject: [PATCH 1372/1899] Fix handling of LRS server name in EDS child config generation Also add more LRS logging --- packages/grpc-js-xds/src/load-balancer-lrs.ts | 1 - packages/grpc-js-xds/src/xds-client.ts | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index b6fa68091..5f860b170 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -16,7 +16,6 @@ */ import { connectivityState as ConnectivityState, StatusObject, status as Status, experimental } from '@grpc/grpc-js'; -import { type } from 'os'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { XdsClusterLocalityStats, XdsClient } from './xds-client'; import LoadBalancer = experimental.LoadBalancer; diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index f147da0eb..56ddddf93 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -1174,6 +1174,7 @@ export class XdsClient { clusterName: string, edsServiceName: string ): XdsClusterDropStats { + trace('addClusterDropStats(lrsServer=' + lrsServer + ', clusterName=' + clusterName + ', edsServiceName=' + edsServiceName + ')'); if (lrsServer !== '') { return { addCallDropped: (category) => {}, @@ -1197,6 +1198,7 @@ export class XdsClient { edsServiceName: string, locality: Locality__Output ): XdsClusterLocalityStats { + trace('addClusterLocalityStats(lrsServer=' + lrsServer + ', clusterName=' + clusterName + ', edsServiceName=' + edsServiceName + ', locality=' + JSON.stringify(locality) + ')'); if (lrsServer !== '') { return { addCallStarted: () => {}, From efc9a0f05c9e2dbbfe2758e6df8cb5527903cc9f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 16:34:53 -0800 Subject: [PATCH 1373/1899] Don't send status through the filter stack twice when receiving trailers --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 15 +-------------- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index b5c9d3f15..6ff858160 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -45,7 +45,7 @@ "@grpc/proto-loader": "^0.6.0-pre14" }, "peerDependencies": { - "@grpc/grpc-js": "~1.2.7" + "@grpc/grpc-js": "~1.2.10" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8fffe4beb..939827b28 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.9", + "version": "1.2.10", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index a51c1da28..8fcc7065e 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -442,21 +442,8 @@ export class Http2CallStream implements Call { ); } const status: StatusObject = { code, details, metadata }; - let finalStatus; - try { - // Attempt to assign final status. - finalStatus = this.filterStack.receiveTrailers(status); - } catch (error) { - // This is a no-op if the call was already ended when handling headers. - this.endCall({ - code: Status.INTERNAL, - details: 'Failed to process received status', - metadata: new Metadata(), - }); - return; - } // This is a no-op if the call was already ended when handling headers. - this.endCall(finalStatus); + this.endCall(status); } attachHttp2Stream( From 31074190ff01cc9c05ff103a702f9f550ee70ce5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 18:31:18 -0800 Subject: [PATCH 1374/1899] Revert "Borrow Linux Kokoro job for xDS testing" This reverts commit 1702014385d00ec1c58fd6f91d35184414a6064d. --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 16a7dc7dc..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } From dd22f8f499fc3831ca0bfd31e6b9aef4a00501fd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Mar 2021 18:35:12 -0800 Subject: [PATCH 1375/1899] Don't send status through the filter stack twice when receiving trailers --- packages/grpc-js/src/call-stream.ts | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 9c27aeb1f..7d0abb943 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -415,21 +415,8 @@ export class Http2CallStream implements Call { ); } const status: StatusObject = { code, details, metadata }; - let finalStatus; - try { - // Attempt to assign final status. - finalStatus = this.filterStack.receiveTrailers(status); - } catch (error) { - // This is a no-op if the call was already ended when handling headers. - this.endCall({ - code: Status.INTERNAL, - details: 'Failed to process received status', - metadata: new Metadata(), - }); - return; - } // This is a no-op if the call was already ended when handling headers. - this.endCall(finalStatus); + this.endCall(status); } attachHttp2Stream( From e7eaeeb090f0c4c503ef7005e7014059880bdefa Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 5 Mar 2021 11:09:21 -0800 Subject: [PATCH 1376/1899] Revert "Temporarily borrow linux test job for xds tests" This reverts commit 2b451fdfba1e53ae6d0c682e5bda06a8c2453d64. --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 16a7dc7dc..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } From 231619fcaa7ddd46b23df25c699c271cb92bc67e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 5 Mar 2021 14:18:50 -0800 Subject: [PATCH 1377/1899] grpc-js: Timer ref and unref might not exist --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/backoff-timeout.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 939827b28..4413d4d25 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.10", + "version": "1.2.11", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts index 49a5b1e29..7f2ab5ebf 100644 --- a/packages/grpc-js/src/backoff-timeout.ts +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -76,7 +76,7 @@ export class BackoffTimeout { this.running = false; }, this.nextDelay); if (!this.hasRef) { - this.timerId.unref(); + this.timerId.unref?.(); } const nextBackoff = Math.min( this.nextDelay * this.multiplier, @@ -109,11 +109,11 @@ export class BackoffTimeout { ref() { this.hasRef = true; - this.timerId.ref(); + this.timerId.ref?.(); } unref() { this.hasRef = false; - this.timerId.unref(); + this.timerId.unref?.(); } } From 2aec366508e8bb434efd081bea2256b1aeb3dc84 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Mar 2021 10:39:42 -0800 Subject: [PATCH 1378/1899] grpc-js-xds: Fix sending stats when reestablishing LRS stream --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/xds-client.ts | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 6ff858160..875c8645c 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.2.3", + "version": "1.2.4", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 56ddddf93..09420ba99 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -1020,12 +1020,14 @@ export class XdsClient { this.lrsBackoff.runOnce(); this.lrsCall = this.lrsClient.streamLoadStats(); + let receivedSettingsForThisStream = false; this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { /* Once we get any response from the server, we assume that the stream is * in a good state, so we can reset the backoff timer. */ this.lrsBackoff.stop(); this.lrsBackoff.reset(); if ( + !receivedSettingsForThisStream || message.load_reporting_interval?.seconds !== this.latestLrsSettings?.load_reporting_interval?.seconds || message.load_reporting_interval?.nanos !== @@ -1045,13 +1047,13 @@ export class XdsClient { }, loadReportingIntervalMs); } this.latestLrsSettings = message; + receivedSettingsForThisStream = true; }); this.lrsCall.on('error', (error: ServiceError) => { trace( 'LRS stream ended. code=' + error.code + ' details= ' + error.details ); this.lrsCall = null; - this.latestLrsSettings = null; clearInterval(this.statsTimer); /* If the backoff timer is no longer running, we do not need to wait any * more to start the new call. */ @@ -1068,14 +1070,20 @@ export class XdsClient { if (!this.lrsCall) { return; } + if (!this.latestLrsSettings) { + this.lrsCall.write({ + node: this.lrsNode!, + }); + return; + } const clusterStats: ClusterStats[] = []; for (const [ { clusterName, edsServiceName }, stats, ] of this.clusterStatsMap.entries()) { if ( - this.latestLrsSettings!.send_all_clusters || - this.latestLrsSettings!.clusters.indexOf(clusterName) > 0 + this.latestLrsSettings.send_all_clusters || + this.latestLrsSettings.clusters.indexOf(clusterName) > 0 ) { const upstreamLocalityStats: UpstreamLocalityStats[] = []; for (const localityStats of stats.localityStats) { From c2d7e4addaffc8b171341a62bc7e0bbcbc0b2c18 Mon Sep 17 00:00:00 2001 From: sovlookup Date: Fri, 12 Mar 2021 19:39:06 +0800 Subject: [PATCH 1379/1899] load protobuf.js JSON descriptor --- packages/proto-loader/src/index.ts | 17 +++++++++++++++++ .../proto-loader/test/descriptor_type_test.ts | 9 +++++++++ .../proto-loader/test_protos/rpc.proto.json | 16 ++++++++++++++++ 3 files changed, 42 insertions(+) create mode 100644 packages/proto-loader/test_protos/rpc.proto.json diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index c51bc0110..237fd8405 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -395,6 +395,23 @@ export function loadSync( return createPackageDefinition(root, options!); } +export function fromJSON( + json: Protobuf.INamespace, + root?: Protobuf.Root +): PackageDefinition { + const options: Options = json.options || {}; + const newRoot: Protobuf.Root = root || new Protobuf.Root(); + if (!!options.includeDirs) { + if (!Array.isArray(options.includeDirs)) { + throw new Error('The includeDirs option must be an array'); + } + addIncludePathResolver(newRoot, options.includeDirs as string[]); + } + const loadedRoot = Protobuf.Root.fromJSON(json, newRoot); + loadedRoot.resolveAll(); + return createPackageDefinition(newRoot, options!); +} + export function loadFileDescriptorSetFromBuffer( descriptorSet: Buffer, options?: Options diff --git a/packages/proto-loader/test/descriptor_type_test.ts b/packages/proto-loader/test/descriptor_type_test.ts index 32aca9fc6..180681c12 100644 --- a/packages/proto-loader/test/descriptor_type_test.ts +++ b/packages/proto-loader/test/descriptor_type_test.ts @@ -102,6 +102,15 @@ describe('Descriptor types', () => { proto_loader.loadSync(`${TEST_PROTO_DIR}/well_known.proto`); }); + it('Can load JSON descriptors', () => { + // This is protobuf.js JSON descriptor + // https://github.com/protobufjs/protobuf.js#using-json-descriptors + const buffer = readFileSync(`${TEST_PROTO_DIR}/rpc.proto.json`); + const json = JSON.parse(buffer.toString()); + // This will throw if the rpc descriptor JSON cannot be decoded + proto_loader.fromJSON(json); + }); + it('Can load binary-encoded proto file descriptor sets', () => { const buffer = readFileSync(`${TEST_PROTO_DIR}/rpc.desc.bin`); // This will throw if the rpc descriptor cannot be decoded diff --git a/packages/proto-loader/test_protos/rpc.proto.json b/packages/proto-loader/test_protos/rpc.proto.json new file mode 100644 index 000000000..e49dec1dd --- /dev/null +++ b/packages/proto-loader/test_protos/rpc.proto.json @@ -0,0 +1,16 @@ +{ + "nested": { + "awesomepackage": { + "nested": { + "AwesomeMessage": { + "fields": { + "awesomeField": { + "type": "string", + "id": 1 + } + } + } + } + } + } +} \ No newline at end of file From 602fcd23b4b39b3dba0d75af5ecb688a46b8c7a5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Mar 2021 09:39:50 -0800 Subject: [PATCH 1380/1899] grpc-js: Throw in watchConnectivityState if channel is closed --- packages/grpc-js/src/channel.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 0f055d1e9..416aaa081 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -480,6 +480,9 @@ export class ChannelImplementation implements Channel { deadline: Date | number, callback: (error?: Error) => void ): void { + if (this.connectivityState === ConnectivityState.SHUTDOWN) { + throw new Error('Channel has been shut down'); + } let timer = null; if(deadline !== Infinity) { const deadlineDate: Date = From 2b0ebcfc6a136e761061cfe357960104888f2402 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 12 Mar 2021 14:59:01 -0800 Subject: [PATCH 1381/1899] grpc-js-xds: Add functionality to the xDS interop client --- .../grpc/testing/ClientConfigureRequest.ts | 68 +++++++++ .../grpc/testing/ClientConfigureResponse.ts | 14 ++ .../LoadBalancerAccumulatedStatsRequest.ts | 14 ++ .../LoadBalancerAccumulatedStatsResponse.ts | 78 ++++++++++ .../grpc/testing/LoadBalancerStatsService.ts | 22 +++ .../XdsUpdateClientConfigureService.ts | 37 +++++ .../grpc-js-xds/interop/generated/test.ts | 9 ++ .../grpc-js-xds/interop/xds-interop-client.ts | 138 +++++++++++++----- .../proto/grpc/testing/messages.proto | 56 +++++++ .../grpc-js-xds/proto/grpc/testing/test.proto | 10 ++ 10 files changed, 412 insertions(+), 34 deletions(-) create mode 100644 packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts create mode 100644 packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts create mode 100644 packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts create mode 100644 packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts create mode 100644 packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts new file mode 100644 index 000000000..7f07e8966 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureRequest.ts @@ -0,0 +1,68 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Metadata to be attached for the given type of RPCs. + */ +export interface _grpc_testing_ClientConfigureRequest_Metadata { + 'type'?: (_grpc_testing_ClientConfigureRequest_RpcType | keyof typeof _grpc_testing_ClientConfigureRequest_RpcType); + 'key'?: (string); + 'value'?: (string); +} + +/** + * Metadata to be attached for the given type of RPCs. + */ +export interface _grpc_testing_ClientConfigureRequest_Metadata__Output { + 'type': (keyof typeof _grpc_testing_ClientConfigureRequest_RpcType); + 'key': (string); + 'value': (string); +} + +// Original file: proto/grpc/testing/messages.proto + +/** + * Type of RPCs to send. + */ +export enum _grpc_testing_ClientConfigureRequest_RpcType { + EMPTY_CALL = 0, + UNARY_CALL = 1, +} + +/** + * Configurations for a test client. + */ +export interface ClientConfigureRequest { + /** + * The types of RPCs the client sends. + */ + 'types'?: (_grpc_testing_ClientConfigureRequest_RpcType | keyof typeof _grpc_testing_ClientConfigureRequest_RpcType)[]; + /** + * The collection of custom metadata to be attached to RPCs sent by the client. + */ + 'metadata'?: (_grpc_testing_ClientConfigureRequest_Metadata)[]; + /** + * The deadline to use, in seconds, for all RPCs. If unset or zero, the + * client will use the default from the command-line. + */ + 'timeout_sec'?: (number); +} + +/** + * Configurations for a test client. + */ +export interface ClientConfigureRequest__Output { + /** + * The types of RPCs the client sends. + */ + 'types': (keyof typeof _grpc_testing_ClientConfigureRequest_RpcType)[]; + /** + * The collection of custom metadata to be attached to RPCs sent by the client. + */ + 'metadata': (_grpc_testing_ClientConfigureRequest_Metadata__Output)[]; + /** + * The deadline to use, in seconds, for all RPCs. If unset or zero, the + * client will use the default from the command-line. + */ + 'timeout_sec': (number); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts new file mode 100644 index 000000000..df663240a --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ClientConfigureResponse.ts @@ -0,0 +1,14 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Response for updating a test client's configuration. + */ +export interface ClientConfigureResponse { +} + +/** + * Response for updating a test client's configuration. + */ +export interface ClientConfigureResponse__Output { +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts new file mode 100644 index 000000000..1aa9773c5 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsRequest.ts @@ -0,0 +1,14 @@ +// Original file: proto/grpc/testing/messages.proto + + +/** + * Request for retrieving a test client's accumulated stats. + */ +export interface LoadBalancerAccumulatedStatsRequest { +} + +/** + * Request for retrieving a test client's accumulated stats. + */ +export interface LoadBalancerAccumulatedStatsRequest__Output { +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts new file mode 100644 index 000000000..91157ac4e --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerAccumulatedStatsResponse.ts @@ -0,0 +1,78 @@ +// Original file: proto/grpc/testing/messages.proto + + +export interface _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats { + /** + * The number of RPCs that were started for this method. + */ + 'rpcs_started'?: (number); + /** + * The number of RPCs that completed with each status for this method. The + * key is the integral value of a google.rpc.Code; the value is the count. + */ + 'result'?: ({[key: number]: number}); +} + +export interface _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats__Output { + /** + * The number of RPCs that were started for this method. + */ + 'rpcs_started': (number); + /** + * The number of RPCs that completed with each status for this method. The + * key is the integral value of a google.rpc.Code; the value is the count. + */ + 'result': ({[key: number]: number}); +} + +/** + * Accumulated stats for RPCs sent by a test client. + */ +export interface LoadBalancerAccumulatedStatsResponse { + /** + * The total number of RPCs have ever issued for each type. + * Deprecated: use stats_per_method.rpcs_started instead. + */ + 'num_rpcs_started_by_method'?: ({[key: string]: number}); + /** + * The total number of RPCs have ever completed successfully for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_succeeded_by_method'?: ({[key: string]: number}); + /** + * The total number of RPCs have ever failed for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_failed_by_method'?: ({[key: string]: number}); + /** + * Per-method RPC statistics. The key is the RpcType in string form; e.g. + * 'EMPTY_CALL' or 'UNARY_CALL' + */ + 'stats_per_method'?: ({[key: string]: _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats}); +} + +/** + * Accumulated stats for RPCs sent by a test client. + */ +export interface LoadBalancerAccumulatedStatsResponse__Output { + /** + * The total number of RPCs have ever issued for each type. + * Deprecated: use stats_per_method.rpcs_started instead. + */ + 'num_rpcs_started_by_method': ({[key: string]: number}); + /** + * The total number of RPCs have ever completed successfully for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_succeeded_by_method': ({[key: string]: number}); + /** + * The total number of RPCs have ever failed for each type. + * Deprecated: use stats_per_method.result instead. + */ + 'num_rpcs_failed_by_method': ({[key: string]: number}); + /** + * Per-method RPC statistics. The key is the RpcType in string form; e.g. + * 'EMPTY_CALL' or 'UNARY_CALL' + */ + 'stats_per_method'?: ({[key: string]: _grpc_testing_LoadBalancerAccumulatedStatsResponse_MethodStats__Output}); +} diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts index aa4f409fd..2c972726d 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -1,6 +1,8 @@ // Original file: proto/grpc/testing/test.proto import * as grpc from '@grpc/grpc-js' +import { LoadBalancerAccumulatedStatsRequest as _grpc_testing_LoadBalancerAccumulatedStatsRequest, LoadBalancerAccumulatedStatsRequest__Output as _grpc_testing_LoadBalancerAccumulatedStatsRequest__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsRequest'; +import { LoadBalancerAccumulatedStatsResponse as _grpc_testing_LoadBalancerAccumulatedStatsResponse, LoadBalancerAccumulatedStatsResponse__Output as _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsResponse'; import { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; @@ -8,6 +10,21 @@ import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, L * A service used to obtain stats for verifying LB behavior. */ export interface LoadBalancerStatsServiceClient extends grpc.Client { + /** + * Gets the accumulated stats for RPCs sent by a test client. + */ + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + GetClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets the accumulated stats for RPCs sent by a test client. + */ + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + getClientAccumulatedStats(argument: _grpc_testing_LoadBalancerAccumulatedStatsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output) => void): grpc.ClientUnaryCall; + /** * Gets the backend distribution for RPCs sent by a test client. */ @@ -29,6 +46,11 @@ export interface LoadBalancerStatsServiceClient extends grpc.Client { * A service used to obtain stats for verifying LB behavior. */ export interface LoadBalancerStatsServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Gets the accumulated stats for RPCs sent by a test client. + */ + GetClientAccumulatedStats(call: grpc.ServerUnaryCall<_grpc_testing_LoadBalancerAccumulatedStatsRequest__Output, _grpc_testing_LoadBalancerAccumulatedStatsResponse>, callback: grpc.sendUnaryData<_grpc_testing_LoadBalancerAccumulatedStatsResponse>): void; + /** * Gets the backend distribution for RPCs sent by a test client. */ diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts new file mode 100644 index 000000000..693c37ec6 --- /dev/null +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts @@ -0,0 +1,37 @@ +// Original file: proto/grpc/testing/test.proto + +import * as grpc from '@grpc/grpc-js' +import { ClientConfigureRequest as _grpc_testing_ClientConfigureRequest, ClientConfigureRequest__Output as _grpc_testing_ClientConfigureRequest__Output } from '../../grpc/testing/ClientConfigureRequest'; +import { ClientConfigureResponse as _grpc_testing_ClientConfigureResponse, ClientConfigureResponse__Output as _grpc_testing_ClientConfigureResponse__Output } from '../../grpc/testing/ClientConfigureResponse'; + +/** + * A service to dynamically update the configuration of an xDS test client. + */ +export interface XdsUpdateClientConfigureServiceClient extends grpc.Client { + /** + * Update the tes client's configuration. + */ + Configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + Configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + Configure(argument: _grpc_testing_ClientConfigureRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + Configure(argument: _grpc_testing_ClientConfigureRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Update the tes client's configuration. + */ + configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + configure(argument: _grpc_testing_ClientConfigureRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + configure(argument: _grpc_testing_ClientConfigureRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + configure(argument: _grpc_testing_ClientConfigureRequest, callback: (error?: grpc.ServiceError, result?: _grpc_testing_ClientConfigureResponse__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * A service to dynamically update the configuration of an xDS test client. + */ +export interface XdsUpdateClientConfigureServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Update the tes client's configuration. + */ + Configure(call: grpc.ServerUnaryCall<_grpc_testing_ClientConfigureRequest__Output, _grpc_testing_ClientConfigureResponse>, callback: grpc.sendUnaryData<_grpc_testing_ClientConfigureResponse>): void; + +} diff --git a/packages/grpc-js-xds/interop/generated/test.ts b/packages/grpc-js-xds/interop/generated/test.ts index 330dbc9fd..aedfa2455 100644 --- a/packages/grpc-js-xds/interop/generated/test.ts +++ b/packages/grpc-js-xds/interop/generated/test.ts @@ -5,6 +5,7 @@ import { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServic import { ReconnectServiceClient as _grpc_testing_ReconnectServiceClient } from './grpc/testing/ReconnectService'; import { TestServiceClient as _grpc_testing_TestServiceClient } from './grpc/testing/TestService'; import { UnimplementedServiceClient as _grpc_testing_UnimplementedServiceClient } from './grpc/testing/UnimplementedService'; +import { XdsUpdateClientConfigureServiceClient as _grpc_testing_XdsUpdateClientConfigureServiceClient } from './grpc/testing/XdsUpdateClientConfigureService'; import { XdsUpdateHealthServiceClient as _grpc_testing_XdsUpdateHealthServiceClient } from './grpc/testing/XdsUpdateHealthService'; type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; @@ -16,9 +17,13 @@ export interface ProtoGrpcType { grpc: { testing: { BoolValue: MessageTypeDefinition + ClientConfigureRequest: MessageTypeDefinition + ClientConfigureResponse: MessageTypeDefinition EchoStatus: MessageTypeDefinition Empty: MessageTypeDefinition GrpclbRouteType: EnumTypeDefinition + LoadBalancerAccumulatedStatsRequest: MessageTypeDefinition + LoadBalancerAccumulatedStatsResponse: MessageTypeDefinition LoadBalancerStatsRequest: MessageTypeDefinition LoadBalancerStatsResponse: MessageTypeDefinition /** @@ -50,6 +55,10 @@ export interface ProtoGrpcType { * that case. */ UnimplementedService: SubtypeConstructor & { service: ServiceDefinition } + /** + * A service to dynamically update the configuration of an xDS test client. + */ + XdsUpdateClientConfigureService: SubtypeConstructor & { service: ServiceDefinition } /** * A service to remotely control health status of an xDS test server. */ diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 526c5194f..c3cb55d5d 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -26,6 +26,9 @@ import { TestServiceClient } from './generated/grpc/testing/TestService'; import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancerStatsResponse'; import * as yargs from 'yargs'; import { LoadBalancerStatsServiceHandlers } from './generated/grpc/testing/LoadBalancerStatsService'; +import { XdsUpdateClientConfigureServiceHandlers } from './generated/grpc/testing/XdsUpdateClientConfigureService'; +import { Empty__Output } from './generated/grpc/testing/Empty'; +import { LoadBalancerAccumulatedStatsResponse } from './generated/grpc/testing/LoadBalancerAccumulatedStatsResponse'; grpc_xds.register(); @@ -159,47 +162,95 @@ class CallStatsTracker { } } -function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { - let anyCallSucceeded: boolean = false; - setInterval(() => { - const notifier = callStatsTracker.startCall(); - let gotMetadata: boolean = false; - let hostname: string | null = null; - let completed: boolean = false; - let completedWithError: boolean = false; - const deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + REQUEST_TIMEOUT_SEC); - const call = client.emptyCall({}, {deadline}, (error, value) => { - if (error) { - if (failOnFailedRpcs && anyCallSucceeded) { - console.error('A call failed after a call succeeded'); - process.exit(1); - } - completed = true; - completedWithError = true; - notifier.onCallFailed(error.message); - } else { - anyCallSucceeded = true; - if (gotMetadata) { - if (hostname === null) { - notifier.onCallFailed('Hostname omitted from call metadata'); - } else { - notifier.onCallSucceeded(hostname); - } - } +type CallType = 'EMPTY_CALL' | 'UNARY_CALL'; + +interface ClientConfiguration { + callTypes: (CallType)[]; + metadata: { + EMPTY_CALL: grpc.Metadata, + UNARY_CALL: grpc.Metadata + }, + timeoutSec: number +} + +const currentConfig: ClientConfiguration = { + callTypes: ['EMPTY_CALL'], + metadata: { + EMPTY_CALL: new grpc.Metadata(), + UNARY_CALL: new grpc.Metadata() + }, + timeoutSec: REQUEST_TIMEOUT_SEC +}; + +let anyCallSucceeded = false; + +const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { + stats_per_method: { + 'EMPTY_CALL': { + rpcs_started: 0, + result: {} + }, + 'UNARY_CALL': { + rpcs_started: 0, + result: {} + } + } +}; + +function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + const callTypeStats = accumulatedStats.stats_per_method![type]; + callTypeStats.rpcs_started! += 1; + + const notifier = callStatsTracker.startCall(); + let gotMetadata: boolean = false; + let hostname: string | null = null; + let completed: boolean = false; + let completedWithError: boolean = false; + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + currentConfig.timeoutSec); + const callback = (error: grpc.ServiceError | undefined, value: Empty__Output | undefined) => { + const statusCode = error?.code ?? grpc.status.OK; + callTypeStats.result![statusCode] = (callTypeStats.result![statusCode] ?? 0) + 1; + if (error) { + if (failOnFailedRpcs && anyCallSucceeded) { + console.error('A call failed after a call succeeded'); + process.exit(1); } - }); - call.on('metadata', (metadata) => { - hostname = (metadata.get('hostname') as string[])[0] ?? null; - gotMetadata = true; - if (completed && !completedWithError) { + completed = true; + completedWithError = true; + notifier.onCallFailed(error.message); + } else { + anyCallSucceeded = true; + if (gotMetadata) { if (hostname === null) { notifier.onCallFailed('Hostname omitted from call metadata'); } else { notifier.onCallSucceeded(hostname); } } - }) + } + }; + const method = (type === 'EMPTY_CALL' ? client.emptyCall : client.unaryCall).bind(client); + const call = method({}, currentConfig.metadata[type], {deadline}, callback); + call.on('metadata', (metadata) => { + hostname = (metadata.get('hostname') as string[])[0] ?? null; + gotMetadata = true; + if (completed && !completedWithError) { + if (hostname === null) { + notifier.onCallFailed('Hostname omitted from call metadata'); + } else { + notifier.onCallSucceeded(hostname); + } + } + }); + +} + +function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + setInterval(() => { + for (const callType of currentConfig.callTypes) { + makeSingleRequest(client, callType, failOnFailedRpcs, callStatsTracker); + } }, 1000/qps); } @@ -234,11 +285,30 @@ function main() { }, (error) => { callback({code: grpc.status.ABORTED, details: 'Call stats collection failed'}); }); + }, + GetClientAccumulatedStats: (call, callback) => { + callback(null, accumulatedStats); + } + } + + const xdsUpdateClientConfigureServiceImpl: XdsUpdateClientConfigureServiceHandlers = { + Configure: (call, callback) => { + const callMetadata = { + EMPTY_CALL: new grpc.Metadata(), + UNARY_CALL: new grpc.Metadata() + } + for (const metadataItem of call.request.metadata) { + callMetadata[metadataItem.type].add(metadataItem.key, metadataItem.value); + } + currentConfig.callTypes = call.request.types; + currentConfig.metadata = callMetadata; + currentConfig.timeoutSec = call.request.timeout_sec } } const server = new grpc.Server(); server.addService(loadedProto.grpc.testing.LoadBalancerStatsService.service, loadBalancerStatsServiceImpl); + server.addService(loadedProto.grpc.testing.XdsUpdateClientConfigureService.service, xdsUpdateClientConfigureServiceImpl); server.bindAsync(`0.0.0.0:${argv.stats_port}`, grpc.ServerCredentials.createInsecure(), (error, port) => { if (error) { throw error; diff --git a/packages/grpc-js-xds/proto/grpc/testing/messages.proto b/packages/grpc-js-xds/proto/grpc/testing/messages.proto index 70e342776..559876ed7 100644 --- a/packages/grpc-js-xds/proto/grpc/testing/messages.proto +++ b/packages/grpc-js-xds/proto/grpc/testing/messages.proto @@ -212,3 +212,59 @@ message LoadBalancerStatsResponse { int32 num_failures = 2; map rpcs_by_method = 3; } + +// Request for retrieving a test client's accumulated stats. +message LoadBalancerAccumulatedStatsRequest {} + +// Accumulated stats for RPCs sent by a test client. +message LoadBalancerAccumulatedStatsResponse { + // The total number of RPCs have ever issued for each type. + // Deprecated: use stats_per_method.rpcs_started instead. + map num_rpcs_started_by_method = 1 [deprecated = true]; + // The total number of RPCs have ever completed successfully for each type. + // Deprecated: use stats_per_method.result instead. + map num_rpcs_succeeded_by_method = 2 [deprecated = true]; + // The total number of RPCs have ever failed for each type. + // Deprecated: use stats_per_method.result instead. + map num_rpcs_failed_by_method = 3 [deprecated = true]; + + message MethodStats { + // The number of RPCs that were started for this method. + int32 rpcs_started = 1; + + // The number of RPCs that completed with each status for this method. The + // key is the integral value of a google.rpc.Code; the value is the count. + map result = 2; + } + + // Per-method RPC statistics. The key is the RpcType in string form; e.g. + // 'EMPTY_CALL' or 'UNARY_CALL' + map stats_per_method = 4; +} + +// Configurations for a test client. +message ClientConfigureRequest { + // Type of RPCs to send. + enum RpcType { + EMPTY_CALL = 0; + UNARY_CALL = 1; + } + + // Metadata to be attached for the given type of RPCs. + message Metadata { + RpcType type = 1; + string key = 2; + string value = 3; + } + + // The types of RPCs the client sends. + repeated RpcType types = 1; + // The collection of custom metadata to be attached to RPCs sent by the client. + repeated Metadata metadata = 2; + // The deadline to use, in seconds, for all RPCs. If unset or zero, the + // client will use the default from the command-line. + int32 timeout_sec = 3; +} + +// Response for updating a test client's configuration. +message ClientConfigureResponse {} diff --git a/packages/grpc-js-xds/proto/grpc/testing/test.proto b/packages/grpc-js-xds/proto/grpc/testing/test.proto index 9d0fadd9a..b2606a009 100644 --- a/packages/grpc-js-xds/proto/grpc/testing/test.proto +++ b/packages/grpc-js-xds/proto/grpc/testing/test.proto @@ -83,6 +83,10 @@ service LoadBalancerStatsService { // Gets the backend distribution for RPCs sent by a test client. rpc GetClientStats(LoadBalancerStatsRequest) returns (LoadBalancerStatsResponse) {} + + // Gets the accumulated stats for RPCs sent by a test client. + rpc GetClientAccumulatedStats(LoadBalancerAccumulatedStatsRequest) + returns (LoadBalancerAccumulatedStatsResponse) {} } // A service to remotely control health status of an xDS test server. @@ -90,3 +94,9 @@ service XdsUpdateHealthService { rpc SetServing(grpc.testing.Empty) returns (grpc.testing.Empty); rpc SetNotServing(grpc.testing.Empty) returns (grpc.testing.Empty); } + +// A service to dynamically update the configuration of an xDS test client. +service XdsUpdateClientConfigureService { + // Update the tes client's configuration. + rpc Configure(ClientConfigureRequest) returns (ClientConfigureResponse); +} From 65a16397981655293c9593df5c26d99c65d24db2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 16 Mar 2021 13:43:53 -0700 Subject: [PATCH 1382/1899] grpc-tools: Bump protobuf dependency to 3.15.6 --- packages/grpc-tools/deps/protobuf | 2 +- packages/grpc-tools/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index 2514f0bd7..6aa539bf0 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit 2514f0bd7da7e2af1bed4c5d1b84f031c4d12c10 +Subproject commit 6aa539bf0195f188ff86efe6fb8bfa2b676cdd46 diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 86f45dc31..5c7337f67 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.10.0", + "version": "1.11.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 550a4e93f52f3fc028a50d55110048cf4195f833 Mon Sep 17 00:00:00 2001 From: sovlookup Date: Wed, 17 Mar 2021 09:32:02 +0800 Subject: [PATCH 1383/1899] proto-loader: update fromJSON --- packages/proto-loader/src/index.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 237fd8405..883f7d600 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -399,17 +399,10 @@ export function fromJSON( json: Protobuf.INamespace, root?: Protobuf.Root ): PackageDefinition { - const options: Options = json.options || {}; const newRoot: Protobuf.Root = root || new Protobuf.Root(); - if (!!options.includeDirs) { - if (!Array.isArray(options.includeDirs)) { - throw new Error('The includeDirs option must be an array'); - } - addIncludePathResolver(newRoot, options.includeDirs as string[]); - } const loadedRoot = Protobuf.Root.fromJSON(json, newRoot); loadedRoot.resolveAll(); - return createPackageDefinition(newRoot, options!); + return createPackageDefinition(newRoot, {}); } export function loadFileDescriptorSetFromBuffer( From b7bf2bf6cd26551d99ee7d7982031b1503d2dd6b Mon Sep 17 00:00:00 2001 From: sovlookup Date: Wed, 17 Mar 2021 09:41:22 +0800 Subject: [PATCH 1384/1899] proto-loader: update fromJSON remove Protobuf.Root 'json' param --- packages/proto-loader/src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 883f7d600..69c21ecdf 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -396,10 +396,9 @@ export function loadSync( } export function fromJSON( - json: Protobuf.INamespace, - root?: Protobuf.Root + json: Protobuf.INamespace ): PackageDefinition { - const newRoot: Protobuf.Root = root || new Protobuf.Root(); + const newRoot: Protobuf.Root = new Protobuf.Root(); const loadedRoot = Protobuf.Root.fromJSON(json, newRoot); loadedRoot.resolveAll(); return createPackageDefinition(newRoot, {}); From fe2e93d30a3775b686be8de917f7a51b8da52e44 Mon Sep 17 00:00:00 2001 From: sovlookup Date: Wed, 17 Mar 2021 09:48:09 +0800 Subject: [PATCH 1385/1899] proto-loader: update fromJSON test --- .../proto-loader/test_protos/rpc.proto.json | 1515 ++++++++++++++++- 1 file changed, 1508 insertions(+), 7 deletions(-) diff --git a/packages/proto-loader/test_protos/rpc.proto.json b/packages/proto-loader/test_protos/rpc.proto.json index e49dec1dd..5f96dba93 100644 --- a/packages/proto-loader/test_protos/rpc.proto.json +++ b/packages/proto-loader/test_protos/rpc.proto.json @@ -1,16 +1,1517 @@ { + "options": { + "java_package": "com.google.apps.jspb.proto", + "java_multiple_files": true + }, "nested": { - "awesomepackage": { + "jspb": { "nested": { - "AwesomeMessage": { - "fields": { - "awesomeField": { - "type": "string", - "id": 1 + "test": { + "nested": { + "Empty": { + "fields": {} + }, + "OuterEnum": { + "values": { + "FOO": 1, + "BAR": 2 + } + }, + "EnumContainer": { + "fields": { + "outerEnum": { + "type": "OuterEnum", + "id": 1 + } + } + }, + "Simple1": { + "fields": { + "aString": { + "rule": "required", + "type": "string", + "id": 1 + }, + "aRepeatedString": { + "rule": "repeated", + "type": "string", + "id": 2 + }, + "aBoolean": { + "type": "bool", + "id": 3 + } + } + }, + "Simple2": { + "fields": { + "aString": { + "rule": "required", + "type": "string", + "id": 1 + }, + "aRepeatedString": { + "rule": "repeated", + "type": "string", + "id": 2 + } + } + }, + "SpecialCases": { + "fields": { + "normal": { + "rule": "required", + "type": "string", + "id": 1 + }, + "default": { + "rule": "required", + "type": "string", + "id": 2 + }, + "function": { + "rule": "required", + "type": "string", + "id": 3 + }, + "var": { + "rule": "required", + "type": "string", + "id": 4 + } + } + }, + "OptionalFields": { + "fields": { + "aString": { + "type": "string", + "id": 1 + }, + "aBool": { + "rule": "required", + "type": "bool", + "id": 2 + }, + "aNestedMessage": { + "type": "Nested", + "id": 3 + }, + "aRepeatedMessage": { + "rule": "repeated", + "type": "Nested", + "id": 4 + }, + "aRepeatedString": { + "rule": "repeated", + "type": "string", + "id": 5 + } + }, + "nested": { + "Nested": { + "fields": { + "anInt": { + "type": "int32", + "id": 1 + } + } + } + } + }, + "HasExtensions": { + "fields": { + "str1": { + "type": "string", + "id": 1 + }, + "str2": { + "type": "string", + "id": 2 + }, + "str3": { + "type": "string", + "id": 3 + } + }, + "extensions": [ + [ + 10, + 536870911 + ] + ] + }, + "Complex": { + "fields": { + "aString": { + "rule": "required", + "type": "string", + "id": 1 + }, + "anOutOfOrderBool": { + "rule": "required", + "type": "bool", + "id": 9 + }, + "aNestedMessage": { + "type": "Nested", + "id": 4 + }, + "aRepeatedMessage": { + "rule": "repeated", + "type": "Nested", + "id": 5 + }, + "aRepeatedString": { + "rule": "repeated", + "type": "string", + "id": 7 + } + }, + "nested": { + "Nested": { + "fields": { + "anInt": { + "rule": "required", + "type": "int32", + "id": 2 + } + } + } + } + }, + "OuterMessage": { + "fields": {}, + "nested": { + "Complex": { + "fields": { + "innerComplexField": { + "type": "int32", + "id": 1 + } + } + } + } + }, + "IsExtension": { + "fields": { + "ext1": { + "type": "string", + "id": 1 + } + }, + "nested": { + "extField": { + "type": "IsExtension", + "id": 100, + "extend": "HasExtensions" + }, + "simpleOption": { + "type": "string", + "id": 42113038, + "extend": "google.protobuf.EnumOptions" + } + } + }, + "IndirectExtension": { + "fields": {}, + "nested": { + "simple": { + "type": "Simple1", + "id": 101, + "extend": "HasExtensions" + }, + "str": { + "type": "string", + "id": 102, + "extend": "HasExtensions" + }, + "repeatedStr": { + "rule": "repeated", + "type": "string", + "id": 103, + "extend": "HasExtensions" + }, + "repeatedSimple": { + "rule": "repeated", + "type": "Simple1", + "id": 104, + "extend": "HasExtensions" + } + } + }, + "simple1": { + "type": "Simple1", + "id": 105, + "extend": "HasExtensions" + }, + "DefaultValues": { + "fields": { + "stringField": { + "type": "string", + "id": 1, + "options": { + "default": "default<>abc" + } + }, + "boolField": { + "type": "bool", + "id": 2, + "options": { + "default": true + } + }, + "intField": { + "type": "int64", + "id": 3, + "options": { + "default": 11 + } + }, + "enumField": { + "type": "Enum", + "id": 4, + "options": { + "default": "E1" + } + }, + "emptyField": { + "type": "string", + "id": 6, + "options": { + "default": "" + } + }, + "bytesField": { + "type": "bytes", + "id": 8, + "options": { + "default": "moo" + } + } + }, + "nested": { + "Enum": { + "values": { + "E1": 13, + "E2": 77 + } + } + } + }, + "FloatingPointFields": { + "fields": { + "optionalFloatField": { + "type": "float", + "id": 1 + }, + "requiredFloatField": { + "rule": "required", + "type": "float", + "id": 2 + }, + "repeatedFloatField": { + "rule": "repeated", + "type": "float", + "id": 3, + "options": { + "packed": false + } + }, + "defaultFloatField": { + "type": "float", + "id": 4, + "options": { + "default": 2 + } + }, + "optionalDoubleField": { + "type": "double", + "id": 5 + }, + "requiredDoubleField": { + "rule": "required", + "type": "double", + "id": 6 + }, + "repeatedDoubleField": { + "rule": "repeated", + "type": "double", + "id": 7, + "options": { + "packed": false + } + }, + "defaultDoubleField": { + "type": "double", + "id": 8, + "options": { + "default": 2 + } + } + } + }, + "TestClone": { + "fields": { + "str": { + "type": "string", + "id": 1 + }, + "simple1": { + "type": "Simple1", + "id": 3 + }, + "simple2": { + "rule": "repeated", + "type": "Simple1", + "id": 5 + }, + "bytesField": { + "type": "bytes", + "id": 6 + }, + "unused": { + "type": "string", + "id": 7 + } + }, + "extensions": [ + [ + 10, + 536870911 + ] + ] + }, + "CloneExtension": { + "fields": { + "ext": { + "type": "string", + "id": 2 + } + }, + "nested": { + "extField": { + "type": "CloneExtension", + "id": 100, + "extend": "TestClone" + } + } + }, + "TestGroup": { + "fields": { + "repeatedGroup": { + "rule": "repeated", + "type": "RepeatedGroup", + "id": 1 + }, + "requiredGroup": { + "rule": "required", + "type": "RequiredGroup", + "id": 2 + }, + "optionalGroup": { + "type": "OptionalGroup", + "id": 3 + }, + "id": { + "type": "string", + "id": 4 + }, + "requiredSimple": { + "rule": "required", + "type": "Simple2", + "id": 5 + }, + "optionalSimple": { + "type": "Simple2", + "id": 6 + } + }, + "nested": { + "RepeatedGroup": { + "fields": { + "id": { + "rule": "required", + "type": "string", + "id": 1 + }, + "someBool": { + "rule": "repeated", + "type": "bool", + "id": 2, + "options": { + "packed": false + } + } + }, + "group": true + }, + "RequiredGroup": { + "fields": { + "id": { + "rule": "required", + "type": "string", + "id": 1 + } + }, + "group": true + }, + "OptionalGroup": { + "fields": { + "id": { + "rule": "required", + "type": "string", + "id": 1 + } + }, + "group": true + } + } + }, + "TestGroup1": { + "fields": { + "group": { + "type": "TestGroup.RepeatedGroup", + "id": 1 + } + } + }, + "TestReservedNames": { + "fields": { + "extension": { + "type": "int32", + "id": 1 + } + }, + "extensions": [ + [ + 10, + 536870911 + ] + ] + }, + "TestReservedNamesExtension": { + "fields": {}, + "nested": { + "foo": { + "type": "int32", + "id": 10, + "extend": "TestReservedNames" + } + } + }, + "TestMessageWithOneof": { + "oneofs": { + "partialOneof": { + "oneof": [ + "pone", + "pthree" + ] + }, + "recursiveOneof": { + "oneof": [ + "rone", + "rtwo" + ] + }, + "defaultOneofA": { + "oneof": [ + "aone", + "atwo" + ] + }, + "defaultOneofB": { + "oneof": [ + "bone", + "btwo" + ] + } + }, + "fields": { + "pone": { + "type": "string", + "id": 3 + }, + "pthree": { + "type": "string", + "id": 5 + }, + "rone": { + "type": "TestMessageWithOneof", + "id": 6 + }, + "rtwo": { + "type": "string", + "id": 7 + }, + "normalField": { + "type": "bool", + "id": 8 + }, + "repeatedField": { + "rule": "repeated", + "type": "string", + "id": 9 + }, + "aone": { + "type": "int32", + "id": 10, + "options": { + "default": 1234 + } + }, + "atwo": { + "type": "int32", + "id": 11 + }, + "bone": { + "type": "int32", + "id": 12 + }, + "btwo": { + "type": "int32", + "id": 13, + "options": { + "default": 1234 + } + } + } + }, + "TestEndsWithBytes": { + "fields": { + "value": { + "type": "int32", + "id": 1 + }, + "data": { + "type": "bytes", + "id": 2 + } + } + }, + "TestMapFieldsNoBinary": { + "fields": { + "mapStringString": { + "keyType": "string", + "type": "string", + "id": 1 + }, + "mapStringInt32": { + "keyType": "string", + "type": "int32", + "id": 2 + }, + "mapStringInt64": { + "keyType": "string", + "type": "int64", + "id": 3 + }, + "mapStringBool": { + "keyType": "string", + "type": "bool", + "id": 4 + }, + "mapStringDouble": { + "keyType": "string", + "type": "double", + "id": 5 + }, + "mapStringEnum": { + "keyType": "string", + "type": "MapValueEnumNoBinary", + "id": 6 + }, + "mapStringMsg": { + "keyType": "string", + "type": "MapValueMessageNoBinary", + "id": 7 + }, + "mapInt32String": { + "keyType": "int32", + "type": "string", + "id": 8 + }, + "mapInt64String": { + "keyType": "int64", + "type": "string", + "id": 9 + }, + "mapBoolString": { + "keyType": "bool", + "type": "string", + "id": 10 + }, + "testMapFields": { + "type": "TestMapFieldsNoBinary", + "id": 11 + }, + "mapStringTestmapfields": { + "keyType": "string", + "type": "TestMapFieldsNoBinary", + "id": 12 + } + } + }, + "MapValueEnumNoBinary": { + "values": { + "MAP_VALUE_FOO_NOBINARY": 0, + "MAP_VALUE_BAR_NOBINARY": 1, + "MAP_VALUE_BAZ_NOBINARY": 2 + } + }, + "MapValueMessageNoBinary": { + "fields": { + "foo": { + "type": "int32", + "id": 1 + } + } + }, + "Deeply": { + "fields": {}, + "nested": { + "Nested": { + "fields": {}, + "nested": { + "Message": { + "fields": { + "count": { + "type": "int32", + "id": 1 + } + } + } + } + } + } + } + } + } + } + }, + "google": { + "nested": { + "protobuf": { + "options": { + "go_package": "descriptor", + "java_package": "com.google.protobuf", + "java_outer_classname": "DescriptorProtos", + "csharp_namespace": "Google.Protobuf.Reflection", + "objc_class_prefix": "GPB", + "optimize_for": "SPEED" + }, + "nested": { + "FileDescriptorSet": { + "fields": { + "file": { + "rule": "repeated", + "type": "FileDescriptorProto", + "id": 1 + } + } + }, + "FileDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "package": { + "type": "string", + "id": 2 + }, + "dependency": { + "rule": "repeated", + "type": "string", + "id": 3 + }, + "publicDependency": { + "rule": "repeated", + "type": "int32", + "id": 10, + "options": { + "packed": false + } + }, + "weakDependency": { + "rule": "repeated", + "type": "int32", + "id": 11, + "options": { + "packed": false + } + }, + "messageType": { + "rule": "repeated", + "type": "DescriptorProto", + "id": 4 + }, + "enumType": { + "rule": "repeated", + "type": "EnumDescriptorProto", + "id": 5 + }, + "service": { + "rule": "repeated", + "type": "ServiceDescriptorProto", + "id": 6 + }, + "extension": { + "rule": "repeated", + "type": "FieldDescriptorProto", + "id": 7 + }, + "options": { + "type": "FileOptions", + "id": 8 + }, + "sourceCodeInfo": { + "type": "SourceCodeInfo", + "id": 9 + }, + "syntax": { + "type": "string", + "id": 12 + } + } + }, + "DescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "field": { + "rule": "repeated", + "type": "FieldDescriptorProto", + "id": 2 + }, + "extension": { + "rule": "repeated", + "type": "FieldDescriptorProto", + "id": 6 + }, + "nestedType": { + "rule": "repeated", + "type": "DescriptorProto", + "id": 3 + }, + "enumType": { + "rule": "repeated", + "type": "EnumDescriptorProto", + "id": 4 + }, + "extensionRange": { + "rule": "repeated", + "type": "ExtensionRange", + "id": 5 + }, + "oneofDecl": { + "rule": "repeated", + "type": "OneofDescriptorProto", + "id": 8 + }, + "options": { + "type": "MessageOptions", + "id": 7 + }, + "reservedRange": { + "rule": "repeated", + "type": "ReservedRange", + "id": 9 + }, + "reservedName": { + "rule": "repeated", + "type": "string", + "id": 10 + } + }, + "nested": { + "ExtensionRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + } + } + }, + "ReservedRange": { + "fields": { + "start": { + "type": "int32", + "id": 1 + }, + "end": { + "type": "int32", + "id": 2 + } + } + } + } + }, + "FieldDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "number": { + "type": "int32", + "id": 3 + }, + "label": { + "type": "Label", + "id": 4 + }, + "type": { + "type": "Type", + "id": 5 + }, + "typeName": { + "type": "string", + "id": 6 + }, + "extendee": { + "type": "string", + "id": 2 + }, + "defaultValue": { + "type": "string", + "id": 7 + }, + "oneofIndex": { + "type": "int32", + "id": 9 + }, + "jsonName": { + "type": "string", + "id": 10 + }, + "options": { + "type": "FieldOptions", + "id": 8 + } + }, + "nested": { + "Type": { + "values": { + "TYPE_DOUBLE": 1, + "TYPE_FLOAT": 2, + "TYPE_INT64": 3, + "TYPE_UINT64": 4, + "TYPE_INT32": 5, + "TYPE_FIXED64": 6, + "TYPE_FIXED32": 7, + "TYPE_BOOL": 8, + "TYPE_STRING": 9, + "TYPE_GROUP": 10, + "TYPE_MESSAGE": 11, + "TYPE_BYTES": 12, + "TYPE_UINT32": 13, + "TYPE_ENUM": 14, + "TYPE_SFIXED32": 15, + "TYPE_SFIXED64": 16, + "TYPE_SINT32": 17, + "TYPE_SINT64": 18 + } + }, + "Label": { + "values": { + "LABEL_OPTIONAL": 1, + "LABEL_REQUIRED": 2, + "LABEL_REPEATED": 3 + } + } + } + }, + "OneofDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "options": { + "type": "OneofOptions", + "id": 2 + } + } + }, + "EnumDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "value": { + "rule": "repeated", + "type": "EnumValueDescriptorProto", + "id": 2 + }, + "options": { + "type": "EnumOptions", + "id": 3 + } + } + }, + "EnumValueDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "number": { + "type": "int32", + "id": 2 + }, + "options": { + "type": "EnumValueOptions", + "id": 3 + } + } + }, + "ServiceDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "method": { + "rule": "repeated", + "type": "MethodDescriptorProto", + "id": 2 + }, + "options": { + "type": "ServiceOptions", + "id": 3 + } + } + }, + "MethodDescriptorProto": { + "fields": { + "name": { + "type": "string", + "id": 1 + }, + "inputType": { + "type": "string", + "id": 2 + }, + "outputType": { + "type": "string", + "id": 3 + }, + "options": { + "type": "MethodOptions", + "id": 4 + }, + "clientStreaming": { + "type": "bool", + "id": 5, + "options": { + "default": false + } + }, + "serverStreaming": { + "type": "bool", + "id": 6, + "options": { + "default": false + } + } + } + }, + "FileOptions": { + "fields": { + "javaPackage": { + "type": "string", + "id": 1 + }, + "javaOuterClassname": { + "type": "string", + "id": 8 + }, + "javaMultipleFiles": { + "type": "bool", + "id": 10, + "options": { + "default": false + } + }, + "javaGenerateEqualsAndHash": { + "type": "bool", + "id": 20, + "options": { + "deprecated": true + } + }, + "javaStringCheckUtf8": { + "type": "bool", + "id": 27, + "options": { + "default": false + } + }, + "optimizeFor": { + "type": "OptimizeMode", + "id": 9, + "options": { + "default": "SPEED" + } + }, + "goPackage": { + "type": "string", + "id": 11 + }, + "ccGenericServices": { + "type": "bool", + "id": 16, + "options": { + "default": false + } + }, + "javaGenericServices": { + "type": "bool", + "id": 17, + "options": { + "default": false + } + }, + "pyGenericServices": { + "type": "bool", + "id": 18, + "options": { + "default": false + } + }, + "deprecated": { + "type": "bool", + "id": 23, + "options": { + "default": false + } + }, + "ccEnableArenas": { + "type": "bool", + "id": 31, + "options": { + "default": false + } + }, + "objcClassPrefix": { + "type": "string", + "id": 36 + }, + "csharpNamespace": { + "type": "string", + "id": 37 + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 38, + 38 + ] + ], + "nested": { + "OptimizeMode": { + "values": { + "SPEED": 1, + "CODE_SIZE": 2, + "LITE_RUNTIME": 3 + } + } + } + }, + "MessageOptions": { + "fields": { + "messageSetWireFormat": { + "type": "bool", + "id": 1, + "options": { + "default": false + } + }, + "noStandardDescriptorAccessor": { + "type": "bool", + "id": 2, + "options": { + "default": false + } + }, + "deprecated": { + "type": "bool", + "id": 3, + "options": { + "default": false + } + }, + "mapEntry": { + "type": "bool", + "id": 7 + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 8, + 8 + ] + ] + }, + "FieldOptions": { + "fields": { + "ctype": { + "type": "CType", + "id": 1, + "options": { + "default": "STRING" + } + }, + "packed": { + "type": "bool", + "id": 2 + }, + "jstype": { + "type": "JSType", + "id": 6, + "options": { + "default": "JS_NORMAL" + } + }, + "lazy": { + "type": "bool", + "id": 5, + "options": { + "default": false + } + }, + "deprecated": { + "type": "bool", + "id": 3, + "options": { + "default": false + } + }, + "weak": { + "type": "bool", + "id": 10, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "reserved": [ + [ + 4, + 4 + ] + ], + "nested": { + "CType": { + "values": { + "STRING": 0, + "CORD": 1, + "STRING_PIECE": 2 + } + }, + "JSType": { + "values": { + "JS_NORMAL": 0, + "JS_STRING": 1, + "JS_NUMBER": 2 + } + } + } + }, + "OneofOptions": { + "fields": { + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "EnumOptions": { + "fields": { + "allowAlias": { + "type": "bool", + "id": 2 + }, + "deprecated": { + "type": "bool", + "id": 3, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "EnumValueOptions": { + "fields": { + "deprecated": { + "type": "bool", + "id": 1, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "ServiceOptions": { + "fields": { + "deprecated": { + "type": "bool", + "id": 33, + "options": { + "default": false + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ] + }, + "MethodOptions": { + "fields": { + "deprecated": { + "type": "bool", + "id": 33, + "options": { + "default": false + } + }, + "idempotencyLevel": { + "type": "IdempotencyLevel", + "id": 34, + "options": { + "default": "IDEMPOTENCY_UNKNOWN" + } + }, + "uninterpretedOption": { + "rule": "repeated", + "type": "UninterpretedOption", + "id": 999 + } + }, + "extensions": [ + [ + 1000, + 536870911 + ] + ], + "nested": { + "IdempotencyLevel": { + "values": { + "IDEMPOTENCY_UNKNOWN": 0, + "NO_SIDE_EFFECTS": 1, + "IDEMPOTENT": 2 + } + } + } + }, + "UninterpretedOption": { + "fields": { + "name": { + "rule": "repeated", + "type": "NamePart", + "id": 2 + }, + "identifierValue": { + "type": "string", + "id": 3 + }, + "positiveIntValue": { + "type": "uint64", + "id": 4 + }, + "negativeIntValue": { + "type": "int64", + "id": 5 + }, + "doubleValue": { + "type": "double", + "id": 6 + }, + "stringValue": { + "type": "bytes", + "id": 7 + }, + "aggregateValue": { + "type": "string", + "id": 8 + } + }, + "nested": { + "NamePart": { + "fields": { + "namePart": { + "rule": "required", + "type": "string", + "id": 1 + }, + "isExtension": { + "rule": "required", + "type": "bool", + "id": 2 + } + } + } + } + }, + "SourceCodeInfo": { + "fields": { + "location": { + "rule": "repeated", + "type": "Location", + "id": 1 + } + }, + "nested": { + "Location": { + "fields": { + "path": { + "rule": "repeated", + "type": "int32", + "id": 1, + "options": { + "packed": true + } + }, + "span": { + "rule": "repeated", + "type": "int32", + "id": 2, + "options": { + "packed": true + } + }, + "leadingComments": { + "type": "string", + "id": 3 + }, + "trailingComments": { + "type": "string", + "id": 4 + }, + "leadingDetachedComments": { + "rule": "repeated", + "type": "string", + "id": 6 + } + } + } + } + }, + "GeneratedCodeInfo": { + "fields": { + "annotation": { + "rule": "repeated", + "type": "Annotation", + "id": 1 + } + }, + "nested": { + "Annotation": { + "fields": { + "path": { + "rule": "repeated", + "type": "int32", + "id": 1, + "options": { + "packed": true + } + }, + "sourceFile": { + "type": "string", + "id": 2 + }, + "begin": { + "type": "int32", + "id": 3 + }, + "end": { + "type": "int32", + "id": 4 + } + } + } + } } } } } } } -} \ No newline at end of file +} From bdd8e1a110a5ac6b1e381395367e2a6d1394e18c Mon Sep 17 00:00:00 2001 From: sovlookup Date: Thu, 18 Mar 2021 15:39:24 +0800 Subject: [PATCH 1386/1899] proto-loader: fromJSON rm newRoot --- packages/proto-loader/src/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 69c21ecdf..2e827a80f 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -398,10 +398,9 @@ export function loadSync( export function fromJSON( json: Protobuf.INamespace ): PackageDefinition { - const newRoot: Protobuf.Root = new Protobuf.Root(); - const loadedRoot = Protobuf.Root.fromJSON(json, newRoot); + const loadedRoot = Protobuf.Root.fromJSON(json); loadedRoot.resolveAll(); - return createPackageDefinition(newRoot, {}); + return createPackageDefinition(loadedRoot, {}); } export function loadFileDescriptorSetFromBuffer( From 114386768213345a5d1731e00aed09172464a90e Mon Sep 17 00:00:00 2001 From: sovlookup Date: Thu, 18 Mar 2021 16:21:55 +0800 Subject: [PATCH 1387/1899] proto-loader: fromJSON add options --- packages/proto-loader/src/index.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 2e827a80f..4cbcff8bd 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -396,11 +396,16 @@ export function loadSync( } export function fromJSON( - json: Protobuf.INamespace + json: Protobuf.INamespace, + options?: Options ): PackageDefinition { + options = options || {}; + if (!!options.includeDirs) { + throw new Error('The fromJSON does not need to load any files, checkout your options'); + } const loadedRoot = Protobuf.Root.fromJSON(json); loadedRoot.resolveAll(); - return createPackageDefinition(loadedRoot, {}); + return createPackageDefinition(loadedRoot, options!); } export function loadFileDescriptorSetFromBuffer( From 995540ceec4177ffb87f8464281052b2a7ab72e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Mar 2021 13:22:03 -0700 Subject: [PATCH 1388/1899] Update golden generated files to match recent changes --- packages/proto-loader/golden-generated/echo.ts | 4 ++-- .../golden-generated/google/longrunning/Operations.ts | 2 +- .../golden-generated/google/showcase/v1beta1/Echo.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index 70cb030de..02514f053 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -1,10 +1,10 @@ -import * as grpc from '@grpc/grpc-js'; +import type * as grpc from '@grpc/grpc-js'; import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import type { OperationsClient as _google_longrunning_OperationsClient } from './google/longrunning/Operations'; import type { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/showcase/v1beta1/Echo'; -type SubtypeConstructor = { +type SubtypeConstructor any, Subtype> = { new(...args: ConstructorParameters): Subtype; }; diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index eafd538e5..6aa477ada 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import * as grpc from '@grpc/grpc-js' +import type * as grpc from '@grpc/grpc-js' import type { CancelOperationRequest as _google_longrunning_CancelOperationRequest, CancelOperationRequest__Output as _google_longrunning_CancelOperationRequest__Output } from '../../google/longrunning/CancelOperationRequest'; import type { DeleteOperationRequest as _google_longrunning_DeleteOperationRequest, DeleteOperationRequest__Output as _google_longrunning_DeleteOperationRequest__Output } from '../../google/longrunning/DeleteOperationRequest'; import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../google/protobuf/Empty'; diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index ed3678400..33fe373a8 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import * as grpc from '@grpc/grpc-js' +import type * as grpc from '@grpc/grpc-js' import type { BlockRequest as _google_showcase_v1beta1_BlockRequest, BlockRequest__Output as _google_showcase_v1beta1_BlockRequest__Output } from '../../../google/showcase/v1beta1/BlockRequest'; import type { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; import type { EchoRequest as _google_showcase_v1beta1_EchoRequest, EchoRequest__Output as _google_showcase_v1beta1_EchoRequest__Output } from '../../../google/showcase/v1beta1/EchoRequest'; From 2ce608e1f42a46f37e234343084ac7e563a77265 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8E=E5=8C=97?= <805408477@qq.com> Date: Fri, 19 Mar 2021 08:33:23 +0800 Subject: [PATCH 1389/1899] Porto-loader fromJSON rm if optiondir --- packages/proto-loader/src/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 4cbcff8bd..d60d2bd0c 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -400,9 +400,6 @@ export function fromJSON( options?: Options ): PackageDefinition { options = options || {}; - if (!!options.includeDirs) { - throw new Error('The fromJSON does not need to load any files, checkout your options'); - } const loadedRoot = Protobuf.Root.fromJSON(json); loadedRoot.resolveAll(); return createPackageDefinition(loadedRoot, options!); From 4623ecca4295dd240d4cd90cb1049a946a9601a1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 22 Mar 2021 10:47:36 -0700 Subject: [PATCH 1390/1899] grpc-js: don't send accept-encoding: gzip --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/compression-filter.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4413d4d25..b87f95f0d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.11", + "version": "1.2.12", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 6f40ee4b8..330eb675a 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -170,7 +170,7 @@ export class CompressionFilter extends BaseFilter implements Filter { async sendMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; headers.set('grpc-accept-encoding', 'identity,deflate,gzip'); - headers.set('accept-encoding', 'identity,gzip'); + headers.set('accept-encoding', 'identity'); return headers; } From 40e623c7a59df7dc3ac28589f0a83a80160ffbb5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Mar 2021 10:58:25 -0700 Subject: [PATCH 1391/1899] Enable path_matching and header_matching xDS interop tests --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index d76eaf4f3..308017976 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -53,7 +53,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh NODE_XDS_INTEROP_VERBOSITY=1 \ GRPC_XDS_EXPERIMENTAL_ROUTING=true \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all" \ + --test_case="all,path_matching,header_matching" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From d160a2f248191bbcf3f2fcece6f4780524f7e569 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Mar 2021 10:59:17 -0700 Subject: [PATCH 1392/1899] Temporarily borrow Linux test job for xDS tests --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..16a7dc7dc 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 120 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } } From 661fae88c62c46dc35c0333667675ae872a22ba7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 22 Mar 2021 11:40:23 -0700 Subject: [PATCH 1393/1899] grpc-tools: make the plugin compatible with proto3 optional fields --- packages/grpc-tools/package.json | 2 +- packages/grpc-tools/src/node_plugin.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 5c7337f67..b1f83ce45 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.11.0", + "version": "1.11.1", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", diff --git a/packages/grpc-tools/src/node_plugin.cc b/packages/grpc-tools/src/node_plugin.cc index 9f83578b2..b847bcaba 100644 --- a/packages/grpc-tools/src/node_plugin.cc +++ b/packages/grpc-tools/src/node_plugin.cc @@ -65,6 +65,10 @@ class NodeGrpcGenerator : public grpc::protobuf::compiler::CodeGenerator { coded_out.WriteRaw(code.data(), code.size()); return true; } + + uint64_t GetSupportedFeatures() const override { + return FEATURE_PROTO3_OPTIONAL; + } }; int main(int argc, char* argv[]) { From 5cf93cf5fdff0075bb2ec1ceff2f14008d2873e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Mar 2021 09:35:27 -0700 Subject: [PATCH 1394/1899] Fix a typo in a comment Co-authored-by: Ian Edington --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 8a8a082d9..c4c7c516b 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -118,7 +118,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); const typeInterfaceName = getTypeInterfaceName(dependency); let importedTypes: string; - /* If the dependenc is defined within a message, it will be generated in that + /* If the dependency is defined within a message, it will be generated in that * message's file and exported using its typeInterfaceName. */ if (dependency.parent instanceof Protobuf.Type) { if (dependency instanceof Protobuf.Type) { From b995fa62cf292fcf999c5d24a094703f5ccd6d2e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Mar 2021 14:08:21 -0700 Subject: [PATCH 1395/1899] grpc-js-xds: Refactor matcher and routeAction for logging, add more interop client logging --- .../grpc-js-xds/interop/xds-interop-client.ts | 2 + packages/grpc-js-xds/src/matcher.ts | 245 ++++++++++++++++++ packages/grpc-js-xds/src/resolver-xds.ts | 129 +++------ packages/grpc-js-xds/src/route-action.ts | 72 +++++ 4 files changed, 357 insertions(+), 91 deletions(-) create mode 100644 packages/grpc-js-xds/src/matcher.ts create mode 100644 packages/grpc-js-xds/src/route-action.ts diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index c3cb55d5d..f70ed4ff7 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -303,6 +303,8 @@ function main() { currentConfig.callTypes = call.request.types; currentConfig.metadata = callMetadata; currentConfig.timeoutSec = call.request.timeout_sec + console.log('Received new client configuration: ' + JSON.stringify(currentConfig, undefined, 2)); + callback(null, {}); } } diff --git a/packages/grpc-js-xds/src/matcher.ts b/packages/grpc-js-xds/src/matcher.ts new file mode 100644 index 000000000..a70cf5d67 --- /dev/null +++ b/packages/grpc-js-xds/src/matcher.ts @@ -0,0 +1,245 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Metadata } from "@grpc/grpc-js"; +import { RE2 } from "re2-wasm"; + +/** + * An object representing a predicate that determines whether a given + * combination of a methodName and metadata matches some internal conditions. + */ +export interface Matcher { + toString(): string; + apply(methodName: string, metadata: Metadata): boolean; +} + +/** + * An object representing a predicate that determines whether a given string + * value matches some internal conditions. + */ +export interface ValueMatcher { + toString(): string; + apply(value: string): boolean; +} + +export class ExactValueMatcher implements ValueMatcher { + constructor(private targetValue: string) {} + + apply(value: string) { + return value === this.targetValue; + } + + toString() { + return 'Exact(' + this.targetValue + ')'; + } +} + +export class SafeRegexValueMatcher implements ValueMatcher { + private targetRegexImpl: RE2; + constructor(targetRegex: string) { + this.targetRegexImpl = new RE2(`^${targetRegex}$`, 'u'); + } + + apply(value: string) { + return this.targetRegexImpl.test(value); + } + + toString() { + return 'SafeRegex(' + this.targetRegexImpl.toString() + ')'; + } +} + +const numberRegex = new RE2(/^-?\d+$/u); + +export class RangeValueMatcher implements ValueMatcher { + constructor(private start: BigInt, private end: BigInt) {} + + apply(value: string) { + if (!numberRegex.test(value)) { + return false; + } + const numberValue = BigInt(value); + return this.start <= numberValue && numberValue < this.end; + } + + toString() { + return 'Range(' + this.start + ', ' + this.end + ')'; + } +} + +export class PresentValueMatcher implements ValueMatcher { + constructor() {} + + apply(value: string) { + return true; + } + + toString() { + return 'Present()'; + } +} + +export class PrefixValueMatcher implements ValueMatcher { + constructor(private prefix: string) {} + + apply(value: string) { + return value.startsWith(this.prefix); + } + + toString() { + return 'Prefix(' + this.prefix + ')'; + } +} + +export class SuffixValueMatcher implements ValueMatcher { + constructor(private suffix: string) {} + + apply(value: string) { + return value.endsWith(this.suffix); + } + + toString() { + return 'Suffix(' + this.suffix + ')'; + } +} + +export class RejectValueMatcher implements ValueMatcher { + constructor() {} + + apply(value: string) { + return false; + } + + toString() { + return 'Reject()'; + } +} + +export class HeaderMatcher implements Matcher { + constructor(private headerName: string, private valueMatcher: ValueMatcher, private invertMatch: boolean) {} + + private applyHelper(methodName: string, metadata: Metadata) { + if (this.headerName.endsWith('-bin')) { + return false; + } + let value: string; + if (this.headerName === 'content-type') { + value = 'application/grpc'; + } else { + const valueArray = metadata.get(this.headerName); + if (valueArray.length === 0) { + return false; + } else { + value = valueArray.join(','); + } + } + return this.valueMatcher.apply(value); + } + + apply(methodName: string, metadata: Metadata) { + const result = this.applyHelper(methodName, metadata); + if (this.invertMatch) { + return !result; + } else { + return result; + } + } + + toString() { + return 'HeaderMatch(' + this.headerName + ', ' + this.valueMatcher.toString() + ')'; + } +} + +export class PathPrefixValueMatcher { + constructor(private prefix: string, private caseInsensitive: boolean) {} + + apply(value: string) { + if (this.caseInsensitive) { + return value.toLowerCase().startsWith(this.prefix.toLowerCase()); + } else { + return value.startsWith(this.prefix); + } + } + + toString() { + return 'Prefix(' + this.prefix + ', ' + this.caseInsensitive + ')'; + } +} + +export class PathExactValueMatcher { + constructor(private targetValue: string, private caseInsensitive: boolean) {} + + apply(value: string) { + if (this.caseInsensitive) { + return value.toLowerCase().startsWith(this.targetValue.toLowerCase()); + } else { + return value === this.targetValue; + } + } + + toString() { + return 'Exact(' + this.targetValue + ', ' + this.caseInsensitive + ')'; + } +} + +export class PathSafeRegexValueMatcher { + private targetRegexImpl: RE2; + constructor(targetRegex: string, caseInsensitive: boolean) { + this.targetRegexImpl = new RE2(`^${targetRegex}$`, caseInsensitive ? 'iu' : 'u'); + } + + apply(value: string) { + return this.targetRegexImpl.test(value); + } + + toString() { + return 'SafeRegex(' + this.targetRegexImpl.toString() + ')'; + } +} + +export interface Fraction { + numerator: number; + denominator: number; +} + +function fractionToString(fraction: Fraction): string { + return `${fraction.numerator}/${fraction.denominator}`; +} + +export class FullMatcher implements Matcher { + constructor(private pathMatcher: ValueMatcher, private headerMatchers: Matcher[], private fraction: Fraction | null) {} + + apply(methodName: string, metadata: Metadata) { + if (!this.pathMatcher.apply(methodName)) { + return false; + } + if (!this.headerMatchers.every(matcher => matcher.apply(methodName, metadata))) { + return false; + } + if (this.fraction === null) { + return true; + } else { + const randomNumber = Math.random() * this.fraction.denominator; + return randomNumber < this.fraction.numerator; + } + } + + toString() { + return `path: ${this.pathMatcher} + headers: ${this.headerMatchers.map(matcher => matcher.toString()).join('\n\t')} + fraction: ${this.fraction ? fractionToString(this.fraction): 'none'}`; + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 99bbd58ce..0fbb30307 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -38,6 +38,8 @@ import { HeaderMatcher__Output } from './generated/envoy/api/v2/route/HeaderMatc import ConfigSelector = experimental.ConfigSelector; import LoadBalancingConfig = experimental.LoadBalancingConfig; import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluster-manager'; +import { ExactValueMatcher, Fraction, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; +import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action'; const TRACER_NAME = 'xds_resolver'; @@ -119,68 +121,35 @@ function findVirtualHostForDomain(virutalHostList: VirtualHost__Output[], domain return targetVhost; } -interface Matcher { - (methodName: string, metadata: Metadata): boolean; -} - const numberRegex = new RE2(/^-?\d+$/u); function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Matcher { - let valueChecker: (value: string) => boolean; + let valueChecker: ValueMatcher; switch (headerMatch.header_match_specifier) { case 'exact_match': - valueChecker = value => value === headerMatch.exact_match; + valueChecker = new ExactValueMatcher(headerMatch.exact_match!); break; case 'safe_regex_match': - const regex = new RE2(`^${headerMatch.safe_regex_match}$`, 'u'); - valueChecker = value => regex.test(value); + valueChecker = new SafeRegexValueMatcher(headerMatch.safe_regex_match!.regex); break; case 'range_match': const start = BigInt(headerMatch.range_match!.start); const end = BigInt(headerMatch.range_match!.end); - valueChecker = value => { - if (!numberRegex.test(value)) { - return false; - } - const numberValue = BigInt(value); - return start <= numberValue && numberValue < end; - } + valueChecker = new RangeValueMatcher(start, end); break; case 'present_match': - valueChecker = value => true; + valueChecker = new PresentValueMatcher(); break; case 'prefix_match': - valueChecker = value => value.startsWith(headerMatch.prefix_match!); + valueChecker = new PrefixValueMatcher(headerMatch.prefix_match!); break; case 'suffix_match': - valueChecker = value => value.endsWith(headerMatch.suffix_match!); + valueChecker = new SuffixValueMatcher(headerMatch.suffix_match!); break; default: - // Should be prevented by validation rules - return (methodName, metadata) => false; - } - const headerMatcher: Matcher = (methodName, metadata) => { - if (headerMatch.name.endsWith('-bin')) { - return false; - } - let value: string; - if (headerMatch.name === 'content-type') { - value = 'application/grpc'; - } else { - const valueArray = metadata.get(headerMatch.name); - if (valueArray.length === 0) { - return false; - } else { - value = valueArray.join(','); - } - } - return valueChecker(value); - } - if (headerMatch.invert_match) { - return (methodName, metadata) => !headerMatcher(methodName, metadata); - } else { - return headerMatcher; + valueChecker = new RejectValueMatcher(); } + return new HeaderMatcher(headerMatch.name, valueChecker, headerMatch.invert_match); } const RUNTIME_FRACTION_DENOMINATOR_VALUES = { @@ -190,48 +159,32 @@ const RUNTIME_FRACTION_DENOMINATOR_VALUES = { } function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { - let pathMatcher: Matcher; + let pathMatcher: ValueMatcher; + const caseInsensitive = routeMatch.case_sensitive?.value === false; switch (routeMatch.path_specifier) { case 'prefix': - if (routeMatch.case_sensitive?.value === false) { - const prefix = routeMatch.prefix!.toLowerCase(); - pathMatcher = (methodName, metadata) => (methodName.toLowerCase().startsWith(prefix)); - } else { - const prefix = routeMatch.prefix!; - pathMatcher = (methodName, metadata) => (methodName.startsWith(prefix)); - } + pathMatcher = new PathPrefixValueMatcher(routeMatch.prefix!, caseInsensitive); break; case 'path': - if (routeMatch.case_sensitive?.value === false) { - const path = routeMatch.path!.toLowerCase(); - pathMatcher = (methodName, metadata) => (methodName.toLowerCase() === path); - } else { - const path = routeMatch.path!; - pathMatcher = (methodName, metadata) => (methodName === path); - } + pathMatcher = new PathExactValueMatcher(routeMatch.path!, caseInsensitive); break; case 'safe_regex': - const flags = routeMatch.case_sensitive?.value === false ? 'ui' : 'u'; - const regex = new RE2(`^${routeMatch.safe_regex!.regex!}$`, flags); - pathMatcher = (methodName, metadata) => (regex.test(methodName)); + pathMatcher = new PathSafeRegexValueMatcher(routeMatch.safe_regex!.regex, caseInsensitive); break; default: - // Should be prevented by validation rules - return (methodName, metadata) => false; + pathMatcher = new RejectValueMatcher(); } const headerMatchers: Matcher[] = routeMatch.headers.map(getPredicateForHeaderMatcher); - let runtimeFractionHandler: () => boolean; + let runtimeFraction: Fraction | null; if (!routeMatch.runtime_fraction?.default_value) { - runtimeFractionHandler = () => true; + runtimeFraction = null; } else { - const numerator = routeMatch.runtime_fraction.default_value.numerator; - const denominator = RUNTIME_FRACTION_DENOMINATOR_VALUES[routeMatch.runtime_fraction.default_value.denominator]; - runtimeFractionHandler = () => { - const randomNumber = Math.random() * denominator; - return randomNumber < numerator; - } + runtimeFraction = { + numerator: routeMatch.runtime_fraction.default_value.numerator, + denominator: RUNTIME_FRACTION_DENOMINATOR_VALUES[routeMatch.runtime_fraction.default_value.denominator] + }; } - return (methodName, metadata) => pathMatcher(methodName, metadata) && headerMatchers.every(matcher => matcher(methodName, metadata)) && runtimeFractionHandler(); + return new FullMatcher(pathMatcher, headerMatchers, runtimeFraction); } class XdsResolver implements Resolver { @@ -340,38 +293,27 @@ class XdsResolver implements Resolver { this.reportResolutionError('No matching route found'); return; } + trace('Received virtual host config ' + JSON.stringify(virtualHost, undefined, 2)); const allConfigClusters = new Set(); - const matchList: {matcher: Matcher, action: () => string}[] = []; + const matchList: {matcher: Matcher, action: RouteAction}[] = []; for (const route of virtualHost.routes) { - let routeAction: () => string; + let routeAction: RouteAction; switch (route.route!.cluster_specifier) { case 'cluster_header': continue; case 'cluster':{ const cluster = route.route!.cluster!; allConfigClusters.add(cluster); - routeAction = () => cluster; + routeAction = new SingleClusterRouteAction(cluster); break; } case 'weighted_clusters': { - let lastNumerator = 0; - // clusterChoices is essentially the weighted choices represented as a CDF - const clusterChoices: {cluster: string, numerator: number}[] = []; + const weightedClusters: WeightedCluster[] = []; for (const clusterWeight of route.route!.weighted_clusters!.clusters) { allConfigClusters.add(clusterWeight.name); - lastNumerator = lastNumerator + (clusterWeight.weight?.value ?? 0); - clusterChoices.push({cluster: clusterWeight.name, numerator: lastNumerator}); - } - routeAction = () => { - const randomNumber = Math.random() * (route.route!.weighted_clusters!.total_weight?.value ?? 100); - for (const choice of clusterChoices) { - if (randomNumber < choice.numerator) { - return choice.cluster; - } - } - // This should be prevented by the validation rules - return ''; + weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0}); } + routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100); } } const routeMatcher = getPredicateForMatcher(route.match!); @@ -397,8 +339,8 @@ class XdsResolver implements Resolver { } const configSelector: ConfigSelector = (methodName, metadata) => { for (const {matcher, action} of matchList) { - if (matcher(methodName, metadata)) { - const clusterName = action(); + if (matcher.apply(methodName, metadata)) { + const clusterName = action.getCluster(); this.refCluster(clusterName); const onCommitted = () => { this.unrefCluster(clusterName); @@ -418,6 +360,11 @@ class XdsResolver implements Resolver { status: status.UNAVAILABLE }; }; + trace('Created ConfigSelector with configuration:'); + for (const {matcher, action} of matchList) { + trace(matcher.toString()); + trace('=> ' + action.toString()); + } const clusterConfigMap = new Map(); for (const clusterName of this.clusterRefcounts.keys()) { clusterConfigMap.set(clusterName, {child_policy: [new CdsLoadBalancingConfig(clusterName)]}); diff --git a/packages/grpc-js-xds/src/route-action.ts b/packages/grpc-js-xds/src/route-action.ts new file mode 100644 index 000000000..4ba2b5908 --- /dev/null +++ b/packages/grpc-js-xds/src/route-action.ts @@ -0,0 +1,72 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export interface RouteAction { + toString(): string; + getCluster(): string; +} + +export class SingleClusterRouteAction implements RouteAction { + constructor(private cluster: string) {} + + getCluster() { + return this.cluster; + } + + toString() { + return 'SingleCluster(' + this.cluster + ')'; + } +} + +export interface WeightedCluster { + name: string; + weight: number; +} + +interface ClusterChoice { + name: string; + numerator: number; +} + +export class WeightedClusterRouteAction implements RouteAction { + /** + * The weighted cluster choices represented as a CDF + */ + private clusterChoices: ClusterChoice[]; + constructor(private clusters: WeightedCluster[], private totalWeight: number) { + this.clusterChoices = []; + let lastNumerator = 0; + for (const clusterWeight of clusters) { + lastNumerator += clusterWeight.weight; + this.clusterChoices.push({name: clusterWeight.name, numerator: lastNumerator}); + } + } + + getCluster() { + const randomNumber = Math.random() * this.totalWeight; + for (const choice of this.clusterChoices) { + if (randomNumber < choice.numerator) { + return choice.name; + } + } + // This should be prevented by the validation rules + return ''; + } + + toString() { + return 'WeightedCluster(' + this.clusters.map(({name, weight}) => '(' + name + ':' + weight + ')').join(', ') + ')'; + } +} \ No newline at end of file From 3ddb8c0cf26760f9dceaddb48e85ef58f02d7c04 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 25 Mar 2021 10:44:45 -0700 Subject: [PATCH 1396/1899] xDS interop client: add support for rpcs_by_method stats response --- .../grpc-js-xds/interop/xds-interop-client.ts | 36 +++++++++++++------ 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index f70ed4ff7..26f2de77d 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -23,7 +23,7 @@ import { ProtoGrpcType } from './generated/test'; import * as protoLoader from '@grpc/proto-loader'; import { TestServiceClient } from './generated/grpc/testing/TestService'; -import { LoadBalancerStatsResponse } from './generated/grpc/testing/LoadBalancerStatsResponse'; +import { LoadBalancerStatsResponse, _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer__Output } from './generated/grpc/testing/LoadBalancerStatsResponse'; import * as yargs from 'yargs'; import { LoadBalancerStatsServiceHandlers } from './generated/grpc/testing/LoadBalancerStatsService'; import { XdsUpdateClientConfigureServiceHandlers } from './generated/grpc/testing/XdsUpdateClientConfigureService'; @@ -49,13 +49,14 @@ const REQUEST_TIMEOUT_SEC = 20; const VERBOSITY = Number.parseInt(process.env.NODE_XDS_INTEROP_VERBOSITY ?? '0'); interface CallEndNotifier { - onCallSucceeded(peerName: string): void; + onCallSucceeded(methodName: string, peerName: string): void; onCallFailed(message: string): void; } class CallSubscriber { private callsStarted = 0; - private callsSucceededByPeer: {[key: string]: number} = {}; + private callsSucceededByPeer: {[peer: string]: number} = {}; + private callsSucceededByMethod: {[method: string]: _grpc_testing_LoadBalancerStatsResponse_RpcsByPeer__Output} = {} private callsSucceeded = 0; private callsFinished = 0; private failureMessageCount: Map = new Map(); @@ -75,9 +76,18 @@ class CallSubscriber { } } - addCallSucceeded(peerName: string): void { + addCallSucceeded(methodName: string, peerName: string): void { if (VERBOSITY >= 2) { - console.log(`Call to ${peerName} succeeded`); + console.log(`Call ${methodName} to ${peerName} succeeded`); + } + if (methodName in this.callsSucceededByMethod) { + if (peerName in this.callsSucceededByMethod[methodName]) { + this.callsSucceededByMethod[methodName].rpcs_by_peer[peerName] += 1; + } else { + this.callsSucceededByMethod[methodName].rpcs_by_peer[peerName] = 1; + } + } else { + this.callsSucceededByMethod[methodName] = {rpcs_by_peer: {[peerName]: 1}}; } if (peerName in this.callsSucceededByPeer) { this.callsSucceededByPeer[peerName] += 1; @@ -110,7 +120,8 @@ class CallSubscriber { } return { rpcs_by_peer: this.callsSucceededByPeer, - num_failures: this.callsStarted - this.callsSucceeded + num_failures: this.callsStarted - this.callsSucceeded, + rpcs_by_method: this.callsSucceededByMethod }; } } @@ -148,9 +159,9 @@ class CallStatsTracker { } } return { - onCallSucceeded: (peerName: string) => { + onCallSucceeded: (methodName: string, peerName: string) => { for (const subscriber of callSubscribers) { - subscriber.addCallSucceeded(peerName); + subscriber.addCallSucceeded(methodName, peerName); } }, onCallFailed: (message: string) => { @@ -200,7 +211,10 @@ const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { const callTypeStats = accumulatedStats.stats_per_method![type]; callTypeStats.rpcs_started! += 1; - + const methodName = { + 'EMPTY_CALL': 'EmptyCall', + 'UNARY_CALL': 'UnaryCall' + }[type]; const notifier = callStatsTracker.startCall(); let gotMetadata: boolean = false; let hostname: string | null = null; @@ -225,7 +239,7 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail if (hostname === null) { notifier.onCallFailed('Hostname omitted from call metadata'); } else { - notifier.onCallSucceeded(hostname); + notifier.onCallSucceeded(methodName, hostname); } } } @@ -239,7 +253,7 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail if (hostname === null) { notifier.onCallFailed('Hostname omitted from call metadata'); } else { - notifier.onCallSucceeded(hostname); + notifier.onCallSucceeded(methodName, hostname); } } }); From 6661ff3fbfdda5b7c675af5360cad75527eee406 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 25 Mar 2021 13:19:54 -0700 Subject: [PATCH 1397/1899] xDS interop client: add support for rpc and metadata command line args --- .../grpc-js-xds/interop/xds-interop-client.ts | 59 +++++++++++-------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 26f2de77d..95d5362a2 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -81,7 +81,7 @@ class CallSubscriber { console.log(`Call ${methodName} to ${peerName} succeeded`); } if (methodName in this.callsSucceededByMethod) { - if (peerName in this.callsSucceededByMethod[methodName]) { + if (peerName in this.callsSucceededByMethod[methodName].rpcs_by_peer) { this.callsSucceededByMethod[methodName].rpcs_by_peer[peerName] += 1; } else { this.callsSucceededByMethod[methodName].rpcs_by_peer[peerName] = 1; @@ -173,22 +173,22 @@ class CallStatsTracker { } } -type CallType = 'EMPTY_CALL' | 'UNARY_CALL'; +type CallType = 'EmptyCall' | 'UnaryCall'; interface ClientConfiguration { callTypes: (CallType)[]; metadata: { - EMPTY_CALL: grpc.Metadata, - UNARY_CALL: grpc.Metadata + EmptyCall: grpc.Metadata, + UnaryCall: grpc.Metadata }, timeoutSec: number } const currentConfig: ClientConfiguration = { - callTypes: ['EMPTY_CALL'], + callTypes: ['UnaryCall'], metadata: { - EMPTY_CALL: new grpc.Metadata(), - UNARY_CALL: new grpc.Metadata() + EmptyCall: new grpc.Metadata(), + UnaryCall: new grpc.Metadata() }, timeoutSec: REQUEST_TIMEOUT_SEC }; @@ -197,11 +197,11 @@ let anyCallSucceeded = false; const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { stats_per_method: { - 'EMPTY_CALL': { + EmptyCall: { rpcs_started: 0, result: {} }, - 'UNARY_CALL': { + UnaryCall: { rpcs_started: 0, result: {} } @@ -211,10 +211,6 @@ const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { const callTypeStats = accumulatedStats.stats_per_method![type]; callTypeStats.rpcs_started! += 1; - const methodName = { - 'EMPTY_CALL': 'EmptyCall', - 'UNARY_CALL': 'UnaryCall' - }[type]; const notifier = callStatsTracker.startCall(); let gotMetadata: boolean = false; let hostname: string | null = null; @@ -239,12 +235,12 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail if (hostname === null) { notifier.onCallFailed('Hostname omitted from call metadata'); } else { - notifier.onCallSucceeded(methodName, hostname); + notifier.onCallSucceeded(type, hostname); } } } }; - const method = (type === 'EMPTY_CALL' ? client.emptyCall : client.unaryCall).bind(client); + const method = (type === 'EmptyCall' ? client.emptyCall : client.unaryCall).bind(client); const call = method({}, currentConfig.metadata[type], {deadline}, callback); call.on('metadata', (metadata) => { hostname = (metadata.get('hostname') as string[])[0] ?? null; @@ -253,7 +249,7 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail if (hostname === null) { notifier.onCallFailed('Hostname omitted from call metadata'); } else { - notifier.onCallSucceeded(methodName, hostname); + notifier.onCallSucceeded(type, hostname); } } }); @@ -268,16 +264,33 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc }, 1000/qps); } - +const callTypeEnumMap = { + 'EMPTY_CALL': 'EmptyCall' as CallType, + 'UNARY_CALL': 'UnaryCall' as CallType +}; function main() { const argv = yargs - .string(['fail_on_failed_rpcs', 'server', 'stats_port']) + .string(['fail_on_failed_rpcs', 'server', 'stats_port', 'rpc', 'metadata']) .number(['num_channels', 'qps']) - .require(['qps', 'server', 'stats_port']) + .demandOption(['server', 'stats_port']) .default('num_channels', 1) + .default('qps', 1) + .default('rpc', 'UnaryCall') + .default('metadata', '') .argv; console.log('Starting xDS interop client. Args: ', argv); + currentConfig.callTypes = argv.rpc.split(',').filter(value => value === 'EmptyCall' || value === 'UnaryCall') as CallType[]; + for (const item in argv.metadata.split(',')) { + const [method, key, value] = item.split(':'); + if (value === undefined) { + continue; + } + if (method !== 'EmptyCall' && method !== 'UnaryCall') { + continue; + } + currentConfig.metadata[method].add(key, value); + } const callStatsTracker = new CallStatsTracker(); for (let i = 0; i < argv.num_channels; i++) { /* The 'unique' channel argument is there solely to ensure that the @@ -308,13 +321,13 @@ function main() { const xdsUpdateClientConfigureServiceImpl: XdsUpdateClientConfigureServiceHandlers = { Configure: (call, callback) => { const callMetadata = { - EMPTY_CALL: new grpc.Metadata(), - UNARY_CALL: new grpc.Metadata() + EmptyCall: new grpc.Metadata(), + UnaryCall: new grpc.Metadata() } for (const metadataItem of call.request.metadata) { - callMetadata[metadataItem.type].add(metadataItem.key, metadataItem.value); + callMetadata[callTypeEnumMap[metadataItem.type]].add(metadataItem.key, metadataItem.value); } - currentConfig.callTypes = call.request.types; + currentConfig.callTypes = call.request.types.map(value => callTypeEnumMap[value]); currentConfig.metadata = callMetadata; currentConfig.timeoutSec = call.request.timeout_sec console.log('Received new client configuration: ' + JSON.stringify(currentConfig, undefined, 2)); From 8c7145ba5fa449928f8fd546da4b2e7bbb368244 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 25 Mar 2021 15:56:33 -0700 Subject: [PATCH 1398/1899] xDS interop client: add more debug logging --- packages/grpc-js-xds/interop/xds-interop-client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 95d5362a2..a397f4457 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -291,6 +291,8 @@ function main() { } currentConfig.metadata[method].add(key, value); } + console.log('EmptyCall metadata: ' + currentConfig.metadata.EmptyCall.getMap()); + console.log('UnaryCall metadata: ' + currentConfig.metadata.UnaryCall.getMap()); const callStatsTracker = new CallStatsTracker(); for (let i = 0; i < argv.num_channels; i++) { /* The 'unique' channel argument is there solely to ensure that the From 6be480c58fc6069d62ff0c80c47ddda97d091fee Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 29 Mar 2021 12:49:20 -0700 Subject: [PATCH 1399/1899] Add more trace logging --- packages/grpc-js-xds/src/load-balancer-eds.ts | 2 +- .../grpc-js-xds/src/load-balancer-xds-cluster-manager.ts | 3 ++- packages/grpc-js-xds/src/resolver-xds.ts | 6 ++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 01e40f5ac..657dc3a82 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -191,7 +191,7 @@ export class EdsLoadBalancer implements LoadBalancer { }); this.watcher = { onValidUpdate: (update) => { - trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update)); + trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update, undefined, 2)); this.latestEdsUpdate = update; this.updateChild(); }, diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index 6faa0505b..920a43db9 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -32,7 +32,7 @@ import getFirstUsableConfig = experimental.getFirstUsableConfig; import ChannelControlHelper = experimental.ChannelControlHelper; import registerLoadBalancerType = experimental.registerLoadBalancerType; -const TRACER_NAME = 'weighted_target'; +const TRACER_NAME = 'xds_cluster_manager'; function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); @@ -247,6 +247,7 @@ class XdsClusterManager implements LoadBalancer { trace('Discarding address list update with unrecognized config ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); return; } + trace('Received update with config: ' + JSON.stringify(lbConfig.toJsonObject(), undefined, 2)); const configChildren = lbConfig.getChildren(); // Delete children that are not in the new config const namesToRemove: string[] = []; diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 0fbb30307..f9cb3d1d8 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -40,6 +40,7 @@ import LoadBalancingConfig = experimental.LoadBalancingConfig; import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluster-manager'; import { ExactValueMatcher, Fraction, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action'; +import { LogVerbosity } from '@grpc/grpc-js/build/src/constants'; const TRACER_NAME = 'xds_resolver'; @@ -337,9 +338,14 @@ class XdsResolver implements Resolver { this.clusterRefcounts.set(name, {inLastConfig: true, refCount: 0}); } } + let configSelectorLogCounter = 0; const configSelector: ConfigSelector = (methodName, metadata) => { for (const {matcher, action} of matchList) { if (matcher.apply(methodName, metadata)) { + // 37 is coprime with most relevant numbers + if (configSelectorLogCounter % 37 === 0) { + trace('Call with method ' + methodName + ' and metadata ' + JSON.stringify(metadata.getMap(), undefined, 2) + ' matched ' + matcher.toString()); + } const clusterName = action.getCluster(); this.refCluster(clusterName); const onCommitted = () => { From 506982107f9b37d43259e153b1d56725b5049896 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 29 Mar 2021 14:28:22 -0700 Subject: [PATCH 1400/1899] Fix xDS interop client metadata logging --- packages/grpc-js-xds/interop/xds-interop-client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index a397f4457..a7aa7470f 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -291,8 +291,8 @@ function main() { } currentConfig.metadata[method].add(key, value); } - console.log('EmptyCall metadata: ' + currentConfig.metadata.EmptyCall.getMap()); - console.log('UnaryCall metadata: ' + currentConfig.metadata.UnaryCall.getMap()); + console.log('EmptyCall metadata: ' + JSON.stringify(currentConfig.metadata.EmptyCall.getMap())); + console.log('UnaryCall metadata: ' + JSON.stringify(currentConfig.metadata.UnaryCall.getMap())); const callStatsTracker = new CallStatsTracker(); for (let i = 0; i < argv.num_channels; i++) { /* The 'unique' channel argument is there solely to ensure that the From 30a90d8aaaec486bfb22863f77687c0ab9e1454b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 30 Mar 2021 00:10:13 -0700 Subject: [PATCH 1401/1899] xDS interop client: fix handling of metadata argument --- packages/grpc-js-xds/interop/xds-interop-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index a7aa7470f..5f32831c1 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -281,7 +281,7 @@ function main() { .argv; console.log('Starting xDS interop client. Args: ', argv); currentConfig.callTypes = argv.rpc.split(',').filter(value => value === 'EmptyCall' || value === 'UnaryCall') as CallType[]; - for (const item in argv.metadata.split(',')) { + for (const item of argv.metadata.split(',')) { const [method, key, value] = item.split(':'); if (value === undefined) { continue; From 49cd040154a0326b0cd9e46373053d232332b97d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 9 Mar 2021 10:39:42 -0800 Subject: [PATCH 1402/1899] grpc-js-xds: Fix sending stats when reestablishing LRS stream --- packages/grpc-js-xds/src/xds-client.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 8ecd5bb75..f3ea9c033 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -577,12 +577,14 @@ export class XdsClient { this.lrsBackoff.runOnce(); this.lrsCall = this.lrsClient.streamLoadStats(); + let receivedSettingsForThisStream = false; this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { /* Once we get any response from the server, we assume that the stream is * in a good state, so we can reset the backoff timer. */ this.lrsBackoff.stop(); this.lrsBackoff.reset(); if ( + !receivedSettingsForThisStream || message.load_reporting_interval?.seconds !== this.latestLrsSettings?.load_reporting_interval?.seconds || message.load_reporting_interval?.nanos !== @@ -602,13 +604,13 @@ export class XdsClient { }, loadReportingIntervalMs); } this.latestLrsSettings = message; + receivedSettingsForThisStream = true; }); this.lrsCall.on('error', (error: ServiceError) => { trace( 'LRS stream ended. code=' + error.code + ' details= ' + error.details ); this.lrsCall = null; - this.latestLrsSettings = null; clearInterval(this.statsTimer); /* If the backoff timer is no longer running, we do not need to wait any * more to start the new call. */ @@ -625,14 +627,20 @@ export class XdsClient { if (!this.lrsCall) { return; } + if (!this.latestLrsSettings) { + this.lrsCall.write({ + node: this.lrsNode!, + }); + return; + } const clusterStats: ClusterStats[] = []; for (const [ { clusterName, edsServiceName }, stats, ] of this.clusterStatsMap.entries()) { if ( - this.latestLrsSettings!.send_all_clusters || - this.latestLrsSettings!.clusters.indexOf(clusterName) > 0 + this.latestLrsSettings.send_all_clusters || + this.latestLrsSettings.clusters.indexOf(clusterName) > 0 ) { const upstreamLocalityStats: UpstreamLocalityStats[] = []; for (const localityStats of stats.localityStats) { From 17f72d34b954b9c57e61551a1dc1f1439850557a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 30 Mar 2021 13:26:02 -0700 Subject: [PATCH 1403/1899] Revert "Temporarily borrow Linux test job for xDS tests" This reverts commit d160a2f248191bbcf3f2fcece6f4780524f7e569. --- test/kokoro/linux.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 16a7dc7dc..f40e6db43 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -15,10 +15,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } } From a907086be472d0e4479dcaa249d002dfd4cb9a04 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 30 Mar 2021 13:26:42 -0700 Subject: [PATCH 1404/1899] Remove temporary debug log line --- packages/grpc-js-xds/src/resolver-xds.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index f9cb3d1d8..c07370b74 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -338,14 +338,9 @@ class XdsResolver implements Resolver { this.clusterRefcounts.set(name, {inLastConfig: true, refCount: 0}); } } - let configSelectorLogCounter = 0; const configSelector: ConfigSelector = (methodName, metadata) => { for (const {matcher, action} of matchList) { if (matcher.apply(methodName, metadata)) { - // 37 is coprime with most relevant numbers - if (configSelectorLogCounter % 37 === 0) { - trace('Call with method ' + methodName + ' and metadata ' + JSON.stringify(metadata.getMap(), undefined, 2) + ' matched ' + matcher.toString()); - } const clusterName = action.getCluster(); this.refCluster(clusterName); const onCommitted = () => { From 4742f9d57ee6602c81dae9439dd529dcb9701256 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 31 Mar 2021 13:04:05 -0700 Subject: [PATCH 1405/1899] Combine output for input files with the same basename --- packages/proto-loader/bin/proto-loader-gen-types.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 8a8a082d9..90a83bb98 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -670,9 +670,18 @@ function writeFilesForRoot(root: Protobuf.Root, masterFileName: string, options: async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { await fs.promises.mkdir(options.outDir, {recursive: true}); + const basenameMap = new Map(); for (const filename of protoFiles) { - const loadedRoot = await loadProtosWithOptions(filename, options); - writeFilesForRoot(loadedRoot, path.basename(filename).replace('.proto', '.ts'), options); + const basename = path.basename(filename).replace(/\.proto$/, '.ts'); + if (basenameMap.has(basename)) { + basenameMap.get(basename)!.push(filename); + } else { + basenameMap.set(basename, [filename]); + } + } + for (const [basename, filenames] of basenameMap.entries()) { + const loadedRoot = await loadProtosWithOptions(filenames, options); + writeFilesForRoot(loadedRoot, basename, options); } } From 3ac1e6ddb8787ad17b53f5c821d438eea44941fc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 31 Mar 2021 13:22:08 -0700 Subject: [PATCH 1406/1899] Address review comments --- .../bin/proto-loader-gen-types.ts | 22 +++++++++---------- packages/proto-loader/src/index.ts | 4 ++-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 90a83bb98..d410088b8 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -694,9 +694,6 @@ function runScript() { .normalize(['includeDirs', 'outDir']) .array('includeDirs') .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) -// .choices('longs', ['String', 'Number']) -// .choices('enums', ['String']) -// .choices('bytes', ['Array', 'String']) .string(['longs', 'enums', 'bytes']) .coerce('longs', value => { switch (value) { @@ -739,17 +736,18 @@ function runScript() { .usage('$0 [options] filenames...') .epilogue('WARNING: This tool is in alpha. The CLI and generated code are subject to change') .argv; + if (argv.verbose) { + console.log('Parsed arguments:', argv); + } + addCommonProtos(); + writeAllFiles(argv._ as string[], {...argv, alternateCommentMode: true}).then(() => { if (argv.verbose) { - console.log('Parsed arguments:', argv); + console.log('Success'); } - addCommonProtos(); - writeAllFiles(argv._ as string[], {...argv, alternateCommentMode: true}).then(() => { - if (argv.verbose) { - console.log('Success'); - } - }, (error) => { - throw error; - }) + }, (error) => { + console.error(error) + process.exit(1); + }); } if (require.main === module) { diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 4e15174cc..e31a1938a 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -24,6 +24,8 @@ import { loadProtosWithOptionsSync, loadProtosWithOptions, Options, addCommonPro export { Long } from 'long'; +export { Options }; + /** * This type exists for use with code generated by the proto-loader-gen-types * tool. This type should be used with another interface, e.g. @@ -139,8 +141,6 @@ export interface PackageDefinition { [index: string]: AnyDefinition; } -export { Options }; - type DecodedDescriptorSet = Protobuf.Message & descriptor.IFileDescriptorSet; From 21176c23ab7b2f96e85b5d07d330003661a5f016 Mon Sep 17 00:00:00 2001 From: Andrey Melnik Date: Wed, 20 Jan 2021 01:00:57 +0300 Subject: [PATCH 1407/1899] feature(grpc-js): Add possibility to provide maxSessionMemory http2 option through ChannelOptions --- packages/grpc-js/src/channel-options.ts | 4 ++-- packages/grpc-js/src/server.ts | 6 +++--- packages/grpc-js/src/subchannel.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index e1ad94dce..ebb724b0e 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -28,7 +28,6 @@ export interface ChannelOptions { 'grpc.keepalive_permit_without_calls'?: number; 'grpc.service_config'?: string; 'grpc.max_concurrent_streams'?: number; - 'grpc.max_session_memory'?: number; 'grpc.initial_reconnect_backoff_ms'?: number; 'grpc.max_reconnect_backoff_ms'?: number; 'grpc.use_local_subchannel_pool'?: number; @@ -37,6 +36,7 @@ export interface ChannelOptions { 'grpc.enable_http_proxy'?: number; 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; + 'grpc-node.max_session_memory'?: number; [key: string]: any; } @@ -54,13 +54,13 @@ export const recognizedOptions = { 'grpc.keepalive_permit_without_calls': true, 'grpc.service_config': true, 'grpc.max_concurrent_streams': true, - 'grpc.max_session_memory': true, 'grpc.initial_reconnect_backoff_ms': true, 'grpc.max_reconnect_backoff_ms': true, 'grpc.use_local_subchannel_pool': true, 'grpc.max_send_message_length': true, 'grpc.max_receive_message_length': true, 'grpc.enable_http_proxy': true, + 'grpc-node.max_session_memory': true, }; export function channelOptionsEqual( diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index fe906af20..255e210b6 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -258,10 +258,10 @@ export class Server { } const serverOptions: http2.ServerOptions = { - maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER, + maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER }; - if ('grpc.max_session_memory' in this.options) { - serverOptions.maxSessionMemory = this.options['grpc.max_session_memory']; + if ('grpc-node.max_session_memory' in this.options) { + serverOptions.maxSessionMemory = this.options['grpc-node.max_session_memory']; } if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index bcbd8877e..a435e452f 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -307,8 +307,8 @@ export class Subchannel { let connectionOptions: http2.SecureClientSessionOptions = this.credentials._getConnectionOptions() || {}; connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; - if ('grpc.max_session_memory' in this.options) { - connectionOptions.maxSessionMemory = this.options['grpc.max_session_memory']; + if ('grpc-node.max_session_memory' in this.options) { + connectionOptions.maxSessionMemory = this.options['grpc-node.max_session_memory']; } let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { From 65f1eb4a2983e2c38d89787be5280bc4a2a6d181 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 1 Apr 2021 11:53:30 -0700 Subject: [PATCH 1408/1899] Add default values to generator usage info --- packages/proto-loader/README.md | 51 ++++++++++--------- .../bin/proto-loader-gen-types.ts | 10 ++++ 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 198f9d2bf..123fad111 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -61,30 +61,33 @@ The `proto-loader-gen-types` script distributed with this package can be used to proto-loader-gen-types.js [options] filenames... Options: - --help Show help [boolean] - --version Show version number [boolean] - --keepCase Preserve the case of field names [boolean] - --longs The type that should be used to output 64 bit integer - values. Can be String, Number [string] - --enums The type that should be used to output enum fields. Can be - String [string] - --bytes The type that should be used to output bytes fields. Can be - String, Array [string] - --defaults Output default values for omitted fields [boolean] - --arrays Output default values for omitted repeated fields even if - --defaults is not set [boolean] - --objects Output default values for omitted message fields even if - --defaults is not set [boolean] - --oneofs Output virtual oneof fields set to the present field's name - [boolean] - --json Represent Infinity and NaN as strings in float fields. Also - decode google.protobuf.Any automatically [boolean] - --includeComments Generate doc comments from comments in the original files - [boolean] - --includeDirs, -I Directories to search for included files [array] - --outDir, -O Directory in which to output files [string] [required] - --grpcLib The gRPC implementation library that these types will be - used with [string] [required] + --help Show help [boolean] + --version Show version number [boolean] + --keepCase Preserve the case of field names + [boolean] [default: false] + --longs The type that should be used to output 64 bit integer + values. Can be String, Number[string] [default: "Long"] + --enums The type that should be used to output enum fields. Can + be String [string] [default: "number"] + --bytes The type that should be used to output bytes fields. + Can be String, Array [string] [default: "Buffer"] + --defaults Output default values for omitted fields + [boolean] [default: false] + --arrays Output default values for omitted repeated fields even + if --defaults is not set [boolean] [default: false] + --objects Output default values for omitted message fields even + if --defaults is not set [boolean] [default: false] + --oneofs Output virtual oneof fields set to the present field's + name [boolean] [default: false] + --json Represent Infinity and NaN as strings in float fields. + Also decode google.protobuf.Any automatically + [boolean] [default: false] + --includeComments Generate doc comments from comments in the original + files [boolean] [default: false] + -I, --includeDirs Directories to search for included files [array] + -O, --outDir Directory in which to output files [string] [required] + --grpcLib The gRPC implementation library that these types will + be used with [string] [required] ``` ### Example Usage diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 441f26fd9..c11befee0 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -695,6 +695,16 @@ function runScript() { .array('includeDirs') .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) .string(['longs', 'enums', 'bytes']) + .default('keepCase', false) + .default('defaults', false) + .default('arrays', false) + .default('objects', false) + .default('oneofs', false) + .default('json', false) + .default('includeComments', false) + .default('longs', 'Long') + .default('enums', 'number') + .default('bytes', 'Buffer') .coerce('longs', value => { switch (value) { case 'String': return String; From abfe46b99dd9b541734ec3be154d290c749fa15f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 2 Apr 2021 11:12:41 -0700 Subject: [PATCH 1409/1899] grpc-js-xds: Remove env var protection for routing feature --- packages/grpc-js-xds/src/environment.ts | 8 +- packages/grpc-js-xds/src/resolver-xds.ts | 176 ++++++++---------- .../src/xds-stream-state/rds-state.ts | 77 ++++---- 3 files changed, 113 insertions(+), 148 deletions(-) diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index 56d233ddf..c2c7f2e05 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -13,10 +13,4 @@ * See the License for the specific language governing permissions and * limitations under the License. * - */ - -/** - * Environment variable protection for traffic splitting and routing - * https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#xds-resolver-and-xds-client - */ -export const GRPC_XDS_EXPERIMENTAL_ROUTING = (process.env.GRPC_XDS_EXPERIMENTAL_ROUTING === 'true'); \ No newline at end of file + */ \ No newline at end of file diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index c07370b74..102a52349 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -30,7 +30,6 @@ import { Listener__Output } from './generated/envoy/api/v2/Listener'; import { Watcher } from './xds-stream-state/xds-stream-state'; import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; -import { GRPC_XDS_EXPERIMENTAL_ROUTING } from './environment'; import { CdsLoadBalancingConfig } from './load-balancer-cds'; import { VirtualHost__Output } from './generated/envoy/api/v2/route/VirtualHost'; import { RouteMatch__Output } from './generated/envoy/api/v2/route/RouteMatch'; @@ -288,116 +287,93 @@ class XdsResolver implements Resolver { private handleRouteConfig(routeConfig: RouteConfiguration__Output) { this.latestRouteConfig = routeConfig; - if (GRPC_XDS_EXPERIMENTAL_ROUTING) { - const virtualHost = findVirtualHostForDomain(routeConfig.virtual_hosts, this.target.path); - if (virtualHost === null) { - this.reportResolutionError('No matching route found'); - return; - } - trace('Received virtual host config ' + JSON.stringify(virtualHost, undefined, 2)); - const allConfigClusters = new Set(); - const matchList: {matcher: Matcher, action: RouteAction}[] = []; - for (const route of virtualHost.routes) { - let routeAction: RouteAction; - switch (route.route!.cluster_specifier) { - case 'cluster_header': - continue; - case 'cluster':{ - const cluster = route.route!.cluster!; - allConfigClusters.add(cluster); - routeAction = new SingleClusterRouteAction(cluster); - break; - } - case 'weighted_clusters': { - const weightedClusters: WeightedCluster[] = []; - for (const clusterWeight of route.route!.weighted_clusters!.clusters) { - allConfigClusters.add(clusterWeight.name); - weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0}); - } - routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100); - } + const virtualHost = findVirtualHostForDomain(routeConfig.virtual_hosts, this.target.path); + if (virtualHost === null) { + this.reportResolutionError('No matching route found'); + return; + } + trace('Received virtual host config ' + JSON.stringify(virtualHost, undefined, 2)); + const allConfigClusters = new Set(); + const matchList: {matcher: Matcher, action: RouteAction}[] = []; + for (const route of virtualHost.routes) { + let routeAction: RouteAction; + switch (route.route!.cluster_specifier) { + case 'cluster_header': + continue; + case 'cluster':{ + const cluster = route.route!.cluster!; + allConfigClusters.add(cluster); + routeAction = new SingleClusterRouteAction(cluster); + break; } - const routeMatcher = getPredicateForMatcher(route.match!); - matchList.push({matcher: routeMatcher, action: routeAction}); - } - /* Mark clusters that are not in this route config, and remove ones with - * no references */ - for (const [name, refCount] of Array.from(this.clusterRefcounts.entries())) { - if (!allConfigClusters.has(name)) { - refCount.inLastConfig = false; - if (refCount.refCount === 0) { - this.clusterRefcounts.delete(name); + case 'weighted_clusters': { + const weightedClusters: WeightedCluster[] = []; + for (const clusterWeight of route.route!.weighted_clusters!.clusters) { + allConfigClusters.add(clusterWeight.name); + weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0}); } + routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100); } } - // Add any new clusters from this route config - for (const name of allConfigClusters) { - if (this.clusterRefcounts.has(name)) { - this.clusterRefcounts.get(name)!.inLastConfig = true; - } else { - this.clusterRefcounts.set(name, {inLastConfig: true, refCount: 0}); - } - } - const configSelector: ConfigSelector = (methodName, metadata) => { - for (const {matcher, action} of matchList) { - if (matcher.apply(methodName, metadata)) { - const clusterName = action.getCluster(); - this.refCluster(clusterName); - const onCommitted = () => { - this.unrefCluster(clusterName); - } - return { - methodConfig: {name: []}, - onCommitted: onCommitted, - pickInformation: {cluster: clusterName}, - status: status.OK - }; - } + const routeMatcher = getPredicateForMatcher(route.match!); + matchList.push({matcher: routeMatcher, action: routeAction}); + } + /* Mark clusters that are not in this route config, and remove ones with + * no references */ + for (const [name, refCount] of Array.from(this.clusterRefcounts.entries())) { + if (!allConfigClusters.has(name)) { + refCount.inLastConfig = false; + if (refCount.refCount === 0) { + this.clusterRefcounts.delete(name); } - return { - methodConfig: {name: []}, - // cluster won't be used here, but it's set because of some TypeScript weirdness - pickInformation: {cluster: ''}, - status: status.UNAVAILABLE - }; - }; - trace('Created ConfigSelector with configuration:'); - for (const {matcher, action} of matchList) { - trace(matcher.toString()); - trace('=> ' + action.toString()); } - const clusterConfigMap = new Map(); - for (const clusterName of this.clusterRefcounts.keys()) { - clusterConfigMap.set(clusterName, {child_policy: [new CdsLoadBalancingConfig(clusterName)]}); - } - const lbPolicyConfig = new XdsClusterManagerLoadBalancingConfig(clusterConfigMap); - const serviceConfig: ServiceConfig = { - methodConfig: [], - loadBalancingConfig: [lbPolicyConfig] + } + // Add any new clusters from this route config + for (const name of allConfigClusters) { + if (this.clusterRefcounts.has(name)) { + this.clusterRefcounts.get(name)!.inLastConfig = true; + } else { + this.clusterRefcounts.set(name, {inLastConfig: true, refCount: 0}); } - this.listener.onSuccessfulResolution([], serviceConfig, null, configSelector, {}); - } else { - // !GRPC_XDS_EXPERIMENTAL_ROUTING - for (const virtualHost of routeConfig.virtual_hosts) { - if (virtualHost.domains.indexOf(this.target.path) >= 0) { - const route = virtualHost.routes[virtualHost.routes.length - 1]; - if (route.match?.prefix === '' && route.route?.cluster) { - trace('Reporting RDS update for host ' + uriToString(this.target) + ' with cluster ' + route.route.cluster); - this.listener.onSuccessfulResolution([], { - methodConfig: [], - loadBalancingConfig: [ - new CdsLoadBalancingConfig(route.route.cluster) - ], - }, null, null, {}); - this.hasReportedSuccess = true; - return; - } else { - trace('Discarded matching route with prefix ' + route.match?.prefix + ' and cluster ' + route.route?.cluster); + } + const configSelector: ConfigSelector = (methodName, metadata) => { + for (const {matcher, action} of matchList) { + if (matcher.apply(methodName, metadata)) { + const clusterName = action.getCluster(); + this.refCluster(clusterName); + const onCommitted = () => { + this.unrefCluster(clusterName); } + return { + methodConfig: {name: []}, + onCommitted: onCommitted, + pickInformation: {cluster: clusterName}, + status: status.OK + }; } } - this.reportResolutionError('No matching route found'); + return { + methodConfig: {name: []}, + // cluster won't be used here, but it's set because of some TypeScript weirdness + pickInformation: {cluster: ''}, + status: status.UNAVAILABLE + }; + }; + trace('Created ConfigSelector with configuration:'); + for (const {matcher, action} of matchList) { + trace(matcher.toString()); + trace('=> ' + action.toString()); + } + const clusterConfigMap = new Map(); + for (const clusterName of this.clusterRefcounts.keys()) { + clusterConfigMap.set(clusterName, {child_policy: [new CdsLoadBalancingConfig(clusterName)]}); + } + const lbPolicyConfig = new XdsClusterManagerLoadBalancingConfig(clusterConfigMap); + const serviceConfig: ServiceConfig = { + methodConfig: [], + loadBalancingConfig: [lbPolicyConfig] } + this.listener.onSuccessfulResolution([], serviceConfig, null, configSelector, {}); } private reportResolutionError(reason: string) { diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 2ac924d98..8f795e0f5 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -16,7 +16,6 @@ */ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; -import { GRPC_XDS_EXPERIMENTAL_ROUTING } from "../environment"; import { RouteConfiguration__Output } from "../generated/envoy/api/v2/RouteConfiguration"; import { CdsLoadBalancingConfig } from "../load-balancer-cds"; import { Watcher, XdsStreamState } from "./xds-stream-state"; @@ -99,55 +98,51 @@ export class RdsState implements XdsStreamState { } validateResponse(message: RouteConfiguration__Output): boolean { - if (GRPC_XDS_EXPERIMENTAL_ROUTING) { - // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation - for (const virtualHost of message.virtual_hosts) { - for (const domainPattern of virtualHost.domains) { - const starIndex = domainPattern.indexOf('*'); - const lastStarIndex = domainPattern.lastIndexOf('*'); - // A domain pattern can have at most one wildcard * - if (starIndex !== lastStarIndex) { - return false; - } - // A wildcard * can either be absent or at the beginning or end of the pattern - if (!(starIndex === -1 || starIndex === 0 || starIndex === domainPattern.length - 1)) { - return false; - } + // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation + for (const virtualHost of message.virtual_hosts) { + for (const domainPattern of virtualHost.domains) { + const starIndex = domainPattern.indexOf('*'); + const lastStarIndex = domainPattern.lastIndexOf('*'); + // A domain pattern can have at most one wildcard * + if (starIndex !== lastStarIndex) { + return false; } - for (const route of virtualHost.routes) { - const match = route.match; - if (!match) { - return false; - } - if (SUPPORTED_PATH_SPECIFIERS.indexOf(match.path_specifier) < 0) { + // A wildcard * can either be absent or at the beginning or end of the pattern + if (!(starIndex === -1 || starIndex === 0 || starIndex === domainPattern.length - 1)) { + return false; + } + } + for (const route of virtualHost.routes) { + const match = route.match; + if (!match) { + return false; + } + if (SUPPORTED_PATH_SPECIFIERS.indexOf(match.path_specifier) < 0) { + return false; + } + for (const headers of match.headers) { + if (SUPPPORTED_HEADER_MATCH_SPECIFIERS.indexOf(headers.header_match_specifier) < 0) { return false; } - for (const headers of match.headers) { - if (SUPPPORTED_HEADER_MATCH_SPECIFIERS.indexOf(headers.header_match_specifier) < 0) { - return false; - } - } - if (route.action !== 'route') { - return false; + } + if (route.action !== 'route') { + return false; + } + if ((route.route === undefined) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { + return false; + } + if (route.route!.cluster_specifier === 'weighted_clusters') { + let weightSum = 0; + for (const clusterWeight of route.route.weighted_clusters!.clusters) { + weightSum += clusterWeight.weight?.value ?? 0; } - if ((route.route === undefined) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { + if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { return false; } - if (route.route!.cluster_specifier === 'weighted_clusters') { - let weightSum = 0; - for (const clusterWeight of route.route.weighted_clusters!.clusters) { - weightSum += clusterWeight.weight?.value ?? 0; - } - if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { - return false; - } - } } } - return true; - } else { - return true; } + return true; } private handleMissingNames(allRouteConfigNames: Set) { From 87614c385f2b43dedeeee7acef91d0b26a6a1e89 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 2 Apr 2021 11:21:11 -0700 Subject: [PATCH 1410/1899] Don't use the removed env var in the script --- packages/grpc-js-xds/scripts/xds.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 308017976..714b6fff8 100644 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -51,7 +51,6 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ - GRPC_XDS_EXPERIMENTAL_ROUTING=true \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all,path_matching,header_matching" \ --project_id=grpc-testing \ From 746381a01204a7d5128c075de0e00a12b63d698d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 6 Apr 2021 10:49:43 -0700 Subject: [PATCH 1411/1899] grpc-js-xds: Update proto-loader dependency and regenerate generated files --- .../grpc/testing/LoadBalancerStatsService.ts | 14 +++--- .../interop/generated/grpc/testing/Payload.ts | 2 +- .../grpc/testing/ReconnectService.ts | 12 ++--- .../grpc/testing/ResponseParameters.ts | 2 +- .../generated/grpc/testing/SimpleRequest.ts | 8 ++-- .../generated/grpc/testing/SimpleResponse.ts | 4 +- .../grpc/testing/StreamingInputCallRequest.ts | 4 +- .../testing/StreamingOutputCallRequest.ts | 8 ++-- .../testing/StreamingOutputCallResponse.ts | 2 +- .../generated/grpc/testing/TestService.ts | 48 +++++++++---------- .../grpc/testing/UnimplementedService.ts | 6 +-- .../XdsUpdateClientConfigureService.ts | 8 ++-- .../grpc/testing/XdsUpdateHealthService.ts | 8 ++-- .../grpc-js-xds/interop/generated/test.ts | 21 ++++---- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/generated/ads.ts | 11 ++--- packages/grpc-js-xds/src/generated/cluster.ts | 9 ++-- .../grpc-js-xds/src/generated/endpoint.ts | 9 ++-- .../src/generated/envoy/api/v2/Cluster.ts | 48 +++++++++---------- .../envoy/api/v2/ClusterLoadAssignment.ts | 10 ++-- .../envoy/api/v2/DeltaDiscoveryRequest.ts | 4 +- .../envoy/api/v2/DeltaDiscoveryResponse.ts | 2 +- .../envoy/api/v2/DiscoveryRequest.ts | 4 +- .../envoy/api/v2/DiscoveryResponse.ts | 4 +- .../src/generated/envoy/api/v2/Listener.ts | 24 +++++----- .../envoy/api/v2/LoadBalancingPolicy.ts | 4 +- .../src/generated/envoy/api/v2/Resource.ts | 2 +- .../envoy/api/v2/RouteConfiguration.ts | 8 ++-- .../envoy/api/v2/UpstreamBindConfig.ts | 2 +- .../envoy/api/v2/UpstreamConnectionOptions.ts | 2 +- .../src/generated/envoy/api/v2/Vhds.ts | 2 +- .../v2/auth/CertificateValidationContext.ts | 6 +-- .../envoy/api/v2/auth/CommonTlsContext.ts | 8 ++-- .../envoy/api/v2/auth/DownstreamTlsContext.ts | 10 ++-- .../envoy/api/v2/auth/GenericSecret.ts | 2 +- .../envoy/api/v2/auth/PrivateKeyProvider.ts | 4 +- .../envoy/api/v2/auth/SdsSecretConfig.ts | 2 +- .../src/generated/envoy/api/v2/auth/Secret.ts | 8 ++-- .../envoy/api/v2/auth/TlsCertificate.ts | 4 +- .../envoy/api/v2/auth/TlsSessionTicketKeys.ts | 2 +- .../envoy/api/v2/auth/UpstreamTlsContext.ts | 4 +- .../envoy/api/v2/cluster/CircuitBreakers.ts | 6 +-- .../generated/envoy/api/v2/cluster/Filter.ts | 2 +- .../envoy/api/v2/cluster/OutlierDetection.ts | 4 +- .../generated/envoy/api/v2/core/Address.ts | 4 +- .../envoy/api/v2/core/ApiConfigSource.ts | 8 ++-- .../envoy/api/v2/core/AsyncDataSource.ts | 4 +- .../envoy/api/v2/core/BackoffStrategy.ts | 2 +- .../generated/envoy/api/v2/core/BindConfig.ts | 6 +-- .../envoy/api/v2/core/BuildVersion.ts | 4 +- .../generated/envoy/api/v2/core/CidrRange.ts | 2 +- .../envoy/api/v2/core/ConfigSource.ts | 10 ++-- .../envoy/api/v2/core/EventServiceConfig.ts | 2 +- .../generated/envoy/api/v2/core/Extension.ts | 2 +- .../envoy/api/v2/core/GrpcProtocolOptions.ts | 2 +- .../envoy/api/v2/core/GrpcService.ts | 14 +++--- .../generated/envoy/api/v2/core/HeaderMap.ts | 2 +- .../envoy/api/v2/core/HeaderValueOption.ts | 4 +- .../envoy/api/v2/core/HealthCheck.ts | 22 ++++----- .../envoy/api/v2/core/Http1ProtocolOptions.ts | 2 +- .../envoy/api/v2/core/Http2ProtocolOptions.ts | 2 +- .../envoy/api/v2/core/HttpProtocolOptions.ts | 4 +- .../generated/envoy/api/v2/core/HttpUri.ts | 2 +- .../generated/envoy/api/v2/core/Metadata.ts | 2 +- .../src/generated/envoy/api/v2/core/Node.ts | 10 ++-- .../envoy/api/v2/core/RateLimitSettings.ts | 4 +- .../envoy/api/v2/core/RemoteDataSource.ts | 4 +- .../envoy/api/v2/core/RetryPolicy.ts | 4 +- .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 2 +- .../api/v2/core/RuntimeFractionalPercent.ts | 2 +- .../envoy/api/v2/core/SocketOption.ts | 2 +- .../envoy/api/v2/core/TcpKeepalive.ts | 2 +- .../envoy/api/v2/core/TransportSocket.ts | 4 +- .../envoy/api/v2/endpoint/ClusterStats.ts | 6 +-- .../envoy/api/v2/endpoint/Endpoint.ts | 2 +- .../v2/endpoint/EndpointLoadMetricStats.ts | 2 +- .../envoy/api/v2/endpoint/LbEndpoint.ts | 8 ++-- .../api/v2/endpoint/LocalityLbEndpoints.ts | 6 +-- .../api/v2/endpoint/UpstreamEndpointStats.ts | 8 ++-- .../api/v2/endpoint/UpstreamLocalityStats.ts | 8 ++-- .../generated/envoy/api/v2/listener/Filter.ts | 4 +- .../envoy/api/v2/listener/FilterChain.ts | 12 ++--- .../envoy/api/v2/listener/FilterChainMatch.ts | 4 +- .../envoy/api/v2/listener/ListenerFilter.ts | 6 +-- .../ListenerFilterChainMatchPredicate.ts | 4 +- .../api/v2/listener/UdpListenerConfig.ts | 4 +- .../envoy/api/v2/route/CorsPolicy.ts | 6 +-- .../generated/envoy/api/v2/route/Decorator.ts | 2 +- .../api/v2/route/DirectResponseAction.ts | 2 +- .../envoy/api/v2/route/FilterAction.ts | 2 +- .../envoy/api/v2/route/HeaderMatcher.ts | 6 +-- .../envoy/api/v2/route/HedgePolicy.ts | 4 +- .../api/v2/route/QueryParameterMatcher.ts | 4 +- .../generated/envoy/api/v2/route/RateLimit.ts | 6 +-- .../envoy/api/v2/route/RetryPolicy.ts | 12 ++--- .../src/generated/envoy/api/v2/route/Route.ts | 24 +++++----- .../envoy/api/v2/route/RouteAction.ts | 26 +++++----- .../envoy/api/v2/route/RouteMatch.ts | 10 ++-- .../generated/envoy/api/v2/route/Tracing.ts | 4 +- .../envoy/api/v2/route/VirtualCluster.ts | 4 +- .../envoy/api/v2/route/VirtualHost.ts | 20 ++++---- .../envoy/api/v2/route/WeightedCluster.ts | 10 ++-- .../config/filter/accesslog/v2/AccessLog.ts | 6 +-- .../filter/accesslog/v2/AccessLogFilter.ts | 22 ++++----- .../config/filter/accesslog/v2/AndFilter.ts | 2 +- .../filter/accesslog/v2/ComparisonFilter.ts | 2 +- .../filter/accesslog/v2/DurationFilter.ts | 2 +- .../filter/accesslog/v2/ExtensionFilter.ts | 4 +- .../filter/accesslog/v2/HeaderFilter.ts | 2 +- .../config/filter/accesslog/v2/OrFilter.ts | 2 +- .../filter/accesslog/v2/RuntimeFilter.ts | 2 +- .../filter/accesslog/v2/StatusCodeFilter.ts | 2 +- .../v2/HttpConnectionManager.ts | 30 ++++++------ .../http_connection_manager/v2/HttpFilter.ts | 4 +- .../network/http_connection_manager/v2/Rds.ts | 2 +- .../v2/RequestIDExtension.ts | 2 +- .../http_connection_manager/v2/ScopedRds.ts | 2 +- .../v2/ScopedRouteConfigurationsList.ts | 2 +- .../v2/ScopedRoutes.ts | 6 +-- .../envoy/config/listener/v2/ApiListener.ts | 2 +- .../envoy/config/trace/v2/Tracing.ts | 4 +- .../v2/AggregatedDiscoveryService.ts | 14 +++--- .../load_stats/v2/LoadReportingService.ts | 8 ++-- .../service/load_stats/v2/LoadStatsRequest.ts | 4 +- .../load_stats/v2/LoadStatsResponse.ts | 2 +- .../src/generated/envoy/type/Int64Range.ts | 2 +- .../envoy/type/matcher/ListStringMatcher.ts | 2 +- .../type/matcher/RegexMatchAndSubstitute.ts | 2 +- .../envoy/type/matcher/RegexMatcher.ts | 2 +- .../envoy/type/matcher/StringMatcher.ts | 2 +- .../envoy/type/tracing/v2/CustomTag.ts | 4 +- .../src/generated/google/api/Http.ts | 2 +- .../src/generated/google/api/HttpRule.ts | 4 +- .../src/generated/google/protobuf/Any.ts | 2 +- .../google/protobuf/DescriptorProto.ts | 10 ++-- .../src/generated/google/protobuf/Duration.ts | 2 +- .../google/protobuf/EnumDescriptorProto.ts | 4 +- .../generated/google/protobuf/EnumOptions.ts | 4 +- .../protobuf/EnumValueDescriptorProto.ts | 2 +- .../google/protobuf/EnumValueOptions.ts | 4 +- .../google/protobuf/FieldDescriptorProto.ts | 2 +- .../generated/google/protobuf/FieldOptions.ts | 6 +-- .../google/protobuf/FileDescriptorProto.ts | 12 ++--- .../google/protobuf/FileDescriptorSet.ts | 2 +- .../generated/google/protobuf/FileOptions.ts | 6 +-- .../generated/google/protobuf/Int64Value.ts | 2 +- .../generated/google/protobuf/ListValue.ts | 2 +- .../google/protobuf/MessageOptions.ts | 4 +- .../google/protobuf/MethodDescriptorProto.ts | 2 +- .../google/protobuf/MethodOptions.ts | 2 +- .../google/protobuf/OneofDescriptorProto.ts | 2 +- .../generated/google/protobuf/OneofOptions.ts | 2 +- .../google/protobuf/ServiceDescriptorProto.ts | 4 +- .../google/protobuf/ServiceOptions.ts | 2 +- .../src/generated/google/protobuf/Struct.ts | 2 +- .../generated/google/protobuf/Timestamp.ts | 2 +- .../generated/google/protobuf/UInt64Value.ts | 2 +- .../google/protobuf/UninterpretedOption.ts | 2 +- .../src/generated/google/protobuf/Value.ts | 6 +-- .../src/generated/google/rpc/Status.ts | 2 +- .../src/generated/http_connection_manager.ts | 9 ++-- .../grpc-js-xds/src/generated/listener.ts | 9 ++-- packages/grpc-js-xds/src/generated/lrs.ts | 11 ++--- packages/grpc-js-xds/src/generated/route.ts | 9 ++-- .../udpa/annotations/StatusAnnotation.ts | 2 +- .../src/generated/validate/BytesRules.ts | 2 +- .../src/generated/validate/DurationRules.ts | 2 +- .../src/generated/validate/FieldRules.ts | 46 +++++++++--------- .../src/generated/validate/Fixed64Rules.ts | 2 +- .../src/generated/validate/Int64Rules.ts | 2 +- .../src/generated/validate/MapRules.ts | 4 +- .../src/generated/validate/RepeatedRules.ts | 4 +- .../src/generated/validate/SFixed64Rules.ts | 2 +- .../src/generated/validate/SInt64Rules.ts | 2 +- .../src/generated/validate/StringRules.ts | 4 +- .../src/generated/validate/TimestampRules.ts | 4 +- .../src/generated/validate/UInt64Rules.ts | 2 +- 177 files changed, 528 insertions(+), 536 deletions(-) diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts index 2c972726d..26cfee9d7 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/LoadBalancerStatsService.ts @@ -1,10 +1,10 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '@grpc/grpc-js' -import { LoadBalancerAccumulatedStatsRequest as _grpc_testing_LoadBalancerAccumulatedStatsRequest, LoadBalancerAccumulatedStatsRequest__Output as _grpc_testing_LoadBalancerAccumulatedStatsRequest__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsRequest'; -import { LoadBalancerAccumulatedStatsResponse as _grpc_testing_LoadBalancerAccumulatedStatsResponse, LoadBalancerAccumulatedStatsResponse__Output as _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsResponse'; -import { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; -import { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; +import type * as grpc from '@grpc/grpc-js' +import type { LoadBalancerAccumulatedStatsRequest as _grpc_testing_LoadBalancerAccumulatedStatsRequest, LoadBalancerAccumulatedStatsRequest__Output as _grpc_testing_LoadBalancerAccumulatedStatsRequest__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsRequest'; +import type { LoadBalancerAccumulatedStatsResponse as _grpc_testing_LoadBalancerAccumulatedStatsResponse, LoadBalancerAccumulatedStatsResponse__Output as _grpc_testing_LoadBalancerAccumulatedStatsResponse__Output } from '../../grpc/testing/LoadBalancerAccumulatedStatsResponse'; +import type { LoadBalancerStatsRequest as _grpc_testing_LoadBalancerStatsRequest, LoadBalancerStatsRequest__Output as _grpc_testing_LoadBalancerStatsRequest__Output } from '../../grpc/testing/LoadBalancerStatsRequest'; +import type { LoadBalancerStatsResponse as _grpc_testing_LoadBalancerStatsResponse, LoadBalancerStatsResponse__Output as _grpc_testing_LoadBalancerStatsResponse__Output } from '../../grpc/testing/LoadBalancerStatsResponse'; /** * A service used to obtain stats for verifying LB behavior. @@ -49,11 +49,11 @@ export interface LoadBalancerStatsServiceHandlers extends grpc.UntypedServiceImp /** * Gets the accumulated stats for RPCs sent by a test client. */ - GetClientAccumulatedStats(call: grpc.ServerUnaryCall<_grpc_testing_LoadBalancerAccumulatedStatsRequest__Output, _grpc_testing_LoadBalancerAccumulatedStatsResponse>, callback: grpc.sendUnaryData<_grpc_testing_LoadBalancerAccumulatedStatsResponse>): void; + GetClientAccumulatedStats: grpc.handleUnaryCall<_grpc_testing_LoadBalancerAccumulatedStatsRequest__Output, _grpc_testing_LoadBalancerAccumulatedStatsResponse>; /** * Gets the backend distribution for RPCs sent by a test client. */ - GetClientStats(call: grpc.ServerUnaryCall<_grpc_testing_LoadBalancerStatsRequest__Output, _grpc_testing_LoadBalancerStatsResponse>, callback: grpc.sendUnaryData<_grpc_testing_LoadBalancerStatsResponse>): void; + GetClientStats: grpc.handleUnaryCall<_grpc_testing_LoadBalancerStatsRequest__Output, _grpc_testing_LoadBalancerStatsResponse>; } diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts index 87fc0cf3d..79102d2bf 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/Payload.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/messages.proto -import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import type { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; /** * A block of data, to simply increase gRPC message size. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts index 211147653..e489e2849 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ReconnectService.ts @@ -1,9 +1,9 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '@grpc/grpc-js' -import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; -import { ReconnectInfo as _grpc_testing_ReconnectInfo, ReconnectInfo__Output as _grpc_testing_ReconnectInfo__Output } from '../../grpc/testing/ReconnectInfo'; -import { ReconnectParams as _grpc_testing_ReconnectParams, ReconnectParams__Output as _grpc_testing_ReconnectParams__Output } from '../../grpc/testing/ReconnectParams'; +import type * as grpc from '@grpc/grpc-js' +import type { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import type { ReconnectInfo as _grpc_testing_ReconnectInfo, ReconnectInfo__Output as _grpc_testing_ReconnectInfo__Output } from '../../grpc/testing/ReconnectInfo'; +import type { ReconnectParams as _grpc_testing_ReconnectParams, ReconnectParams__Output as _grpc_testing_ReconnectParams__Output } from '../../grpc/testing/ReconnectParams'; /** * A service used to control reconnect server. @@ -33,8 +33,8 @@ export interface ReconnectServiceClient extends grpc.Client { * A service used to control reconnect server. */ export interface ReconnectServiceHandlers extends grpc.UntypedServiceImplementation { - Start(call: grpc.ServerUnaryCall<_grpc_testing_ReconnectParams__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + Start: grpc.handleUnaryCall<_grpc_testing_ReconnectParams__Output, _grpc_testing_Empty>; - Stop(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_ReconnectInfo>, callback: grpc.sendUnaryData<_grpc_testing_ReconnectInfo>): void; + Stop: grpc.handleUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_ReconnectInfo>; } diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts index 9bd24ee3b..04ca94ced 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/ResponseParameters.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/messages.proto -import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; +import type { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; /** * Configuration for a particular response. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts index b03f6f6dc..056eb10b2 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleRequest.ts @@ -1,9 +1,9 @@ // Original file: proto/grpc/testing/messages.proto -import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; -import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; -import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; -import { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; +import type { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import type { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import type { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; +import type { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; /** * Unary request. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts index 7a96e7dfc..661f336ce 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/SimpleResponse.ts @@ -1,7 +1,7 @@ // Original file: proto/grpc/testing/messages.proto -import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; -import { GrpclbRouteType as _grpc_testing_GrpclbRouteType } from '../../grpc/testing/GrpclbRouteType'; +import type { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import type { GrpclbRouteType as _grpc_testing_GrpclbRouteType } from '../../grpc/testing/GrpclbRouteType'; /** * Unary response, as configured by the request. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts index db9d8d40c..56ad2b217 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingInputCallRequest.ts @@ -1,7 +1,7 @@ // Original file: proto/grpc/testing/messages.proto -import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; -import { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; +import type { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import type { BoolValue as _grpc_testing_BoolValue, BoolValue__Output as _grpc_testing_BoolValue__Output } from '../../grpc/testing/BoolValue'; /** * Client-streaming request. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts index 0d7bff2f1..52922062d 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallRequest.ts @@ -1,9 +1,9 @@ // Original file: proto/grpc/testing/messages.proto -import { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; -import { ResponseParameters as _grpc_testing_ResponseParameters, ResponseParameters__Output as _grpc_testing_ResponseParameters__Output } from '../../grpc/testing/ResponseParameters'; -import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; -import { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; +import type { PayloadType as _grpc_testing_PayloadType } from '../../grpc/testing/PayloadType'; +import type { ResponseParameters as _grpc_testing_ResponseParameters, ResponseParameters__Output as _grpc_testing_ResponseParameters__Output } from '../../grpc/testing/ResponseParameters'; +import type { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import type { EchoStatus as _grpc_testing_EchoStatus, EchoStatus__Output as _grpc_testing_EchoStatus__Output } from '../../grpc/testing/EchoStatus'; /** * Server-streaming request. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts index 9b8f49e38..19ab306dd 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/StreamingOutputCallResponse.ts @@ -1,6 +1,6 @@ // Original file: proto/grpc/testing/messages.proto -import { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; +import type { Payload as _grpc_testing_Payload, Payload__Output as _grpc_testing_Payload__Output } from '../../grpc/testing/Payload'; /** * Server-streaming response, as configured by the request and parameters. diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts index 2ccf45fdc..dbb606c83 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/TestService.ts @@ -1,13 +1,13 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '@grpc/grpc-js' -import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; -import { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; -import { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; -import { StreamingInputCallRequest as _grpc_testing_StreamingInputCallRequest, StreamingInputCallRequest__Output as _grpc_testing_StreamingInputCallRequest__Output } from '../../grpc/testing/StreamingInputCallRequest'; -import { StreamingInputCallResponse as _grpc_testing_StreamingInputCallResponse, StreamingInputCallResponse__Output as _grpc_testing_StreamingInputCallResponse__Output } from '../../grpc/testing/StreamingInputCallResponse'; -import { StreamingOutputCallRequest as _grpc_testing_StreamingOutputCallRequest, StreamingOutputCallRequest__Output as _grpc_testing_StreamingOutputCallRequest__Output } from '../../grpc/testing/StreamingOutputCallRequest'; -import { StreamingOutputCallResponse as _grpc_testing_StreamingOutputCallResponse, StreamingOutputCallResponse__Output as _grpc_testing_StreamingOutputCallResponse__Output } from '../../grpc/testing/StreamingOutputCallResponse'; +import type * as grpc from '@grpc/grpc-js' +import type { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import type { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; +import type { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; +import type { StreamingInputCallRequest as _grpc_testing_StreamingInputCallRequest, StreamingInputCallRequest__Output as _grpc_testing_StreamingInputCallRequest__Output } from '../../grpc/testing/StreamingInputCallRequest'; +import type { StreamingInputCallResponse as _grpc_testing_StreamingInputCallResponse, StreamingInputCallResponse__Output as _grpc_testing_StreamingInputCallResponse__Output } from '../../grpc/testing/StreamingInputCallResponse'; +import type { StreamingOutputCallRequest as _grpc_testing_StreamingOutputCallRequest, StreamingOutputCallRequest__Output as _grpc_testing_StreamingOutputCallRequest__Output } from '../../grpc/testing/StreamingOutputCallRequest'; +import type { StreamingOutputCallResponse as _grpc_testing_StreamingOutputCallResponse, StreamingOutputCallResponse__Output as _grpc_testing_StreamingOutputCallResponse__Output } from '../../grpc/testing/StreamingOutputCallResponse'; /** * A simple service to test the various types of RPCs and experiment with @@ -84,18 +84,18 @@ export interface TestServiceClient extends grpc.Client { * A sequence of requests followed by one response (streamed upload). * The server returns the aggregated size of client payload as the result. */ - StreamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; - StreamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; - StreamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; - StreamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + StreamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; + StreamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; + StreamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; + StreamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; /** * A sequence of requests followed by one response (streamed upload). * The server returns the aggregated size of client payload as the result. */ - streamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; - streamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; - streamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; - streamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallResponse__Output>; + streamingInputCall(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; + streamingInputCall(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; + streamingInputCall(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; + streamingInputCall(callback: (error?: grpc.ServiceError, result?: _grpc_testing_StreamingInputCallResponse__Output) => void): grpc.ClientWritableStream<_grpc_testing_StreamingInputCallRequest>; /** * One request followed by a sequence of responses (streamed download). @@ -154,19 +154,19 @@ export interface TestServiceHandlers extends grpc.UntypedServiceImplementation { * headers set such that a caching HTTP proxy (such as GFE) can * satisfy subsequent requests. */ - CacheableUnaryCall(call: grpc.ServerUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>, callback: grpc.sendUnaryData<_grpc_testing_SimpleResponse>): void; + CacheableUnaryCall: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>; /** * One empty request followed by one empty response. */ - EmptyCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + EmptyCall: grpc.handleUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>; /** * A sequence of requests with each request served by the server immediately. * As one request could lead to multiple responses, this interface * demonstrates the idea of full duplexing. */ - FullDuplexCall(call: grpc.ServerDuplexStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + FullDuplexCall: grpc.handleBidiStreamingCall<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>; /** * A sequence of requests followed by a sequence of responses. @@ -174,29 +174,29 @@ export interface TestServiceHandlers extends grpc.UntypedServiceImplementation { * stream of responses are returned to the client when the server starts with * first request. */ - HalfDuplexCall(call: grpc.ServerDuplexStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + HalfDuplexCall: grpc.handleBidiStreamingCall<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>; /** * A sequence of requests followed by one response (streamed upload). * The server returns the aggregated size of client payload as the result. */ - StreamingInputCall(call: grpc.ServerReadableStream<_grpc_testing_StreamingInputCallRequest__Output, _grpc_testing_StreamingInputCallResponse>, callback: grpc.sendUnaryData<_grpc_testing_StreamingInputCallResponse>): void; + StreamingInputCall: grpc.handleClientStreamingCall<_grpc_testing_StreamingInputCallRequest__Output, _grpc_testing_StreamingInputCallResponse>; /** * One request followed by a sequence of responses (streamed download). * The server returns the payload with client desired type and sizes. */ - StreamingOutputCall(call: grpc.ServerWritableStream<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>): void; + StreamingOutputCall: grpc.handleServerStreamingCall<_grpc_testing_StreamingOutputCallRequest__Output, _grpc_testing_StreamingOutputCallResponse>; /** * One request followed by one response. */ - UnaryCall(call: grpc.ServerUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>, callback: grpc.sendUnaryData<_grpc_testing_SimpleResponse>): void; + UnaryCall: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>; /** * The test server will not implement this method. It will be used * to test the behavior when clients call unimplemented methods. */ - UnimplementedCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + UnimplementedCall: grpc.handleUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>; } diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts index 121dfa919..d21dfcd0f 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/UnimplementedService.ts @@ -1,7 +1,7 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '@grpc/grpc-js' -import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import type * as grpc from '@grpc/grpc-js' +import type { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; /** * A simple service NOT implemented at servers so clients can test for @@ -33,6 +33,6 @@ export interface UnimplementedServiceHandlers extends grpc.UntypedServiceImpleme /** * A call that no server should implement */ - UnimplementedCall(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + UnimplementedCall: grpc.handleUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>; } diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts index 693c37ec6..22947619c 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateClientConfigureService.ts @@ -1,8 +1,8 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '@grpc/grpc-js' -import { ClientConfigureRequest as _grpc_testing_ClientConfigureRequest, ClientConfigureRequest__Output as _grpc_testing_ClientConfigureRequest__Output } from '../../grpc/testing/ClientConfigureRequest'; -import { ClientConfigureResponse as _grpc_testing_ClientConfigureResponse, ClientConfigureResponse__Output as _grpc_testing_ClientConfigureResponse__Output } from '../../grpc/testing/ClientConfigureResponse'; +import type * as grpc from '@grpc/grpc-js' +import type { ClientConfigureRequest as _grpc_testing_ClientConfigureRequest, ClientConfigureRequest__Output as _grpc_testing_ClientConfigureRequest__Output } from '../../grpc/testing/ClientConfigureRequest'; +import type { ClientConfigureResponse as _grpc_testing_ClientConfigureResponse, ClientConfigureResponse__Output as _grpc_testing_ClientConfigureResponse__Output } from '../../grpc/testing/ClientConfigureResponse'; /** * A service to dynamically update the configuration of an xDS test client. @@ -32,6 +32,6 @@ export interface XdsUpdateClientConfigureServiceHandlers extends grpc.UntypedSer /** * Update the tes client's configuration. */ - Configure(call: grpc.ServerUnaryCall<_grpc_testing_ClientConfigureRequest__Output, _grpc_testing_ClientConfigureResponse>, callback: grpc.sendUnaryData<_grpc_testing_ClientConfigureResponse>): void; + Configure: grpc.handleUnaryCall<_grpc_testing_ClientConfigureRequest__Output, _grpc_testing_ClientConfigureResponse>; } diff --git a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts index f898a16dc..aa1e35dca 100644 --- a/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts +++ b/packages/grpc-js-xds/interop/generated/grpc/testing/XdsUpdateHealthService.ts @@ -1,7 +1,7 @@ // Original file: proto/grpc/testing/test.proto -import * as grpc from '@grpc/grpc-js' -import { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; +import type * as grpc from '@grpc/grpc-js' +import type { Empty as _grpc_testing_Empty, Empty__Output as _grpc_testing_Empty__Output } from '../../grpc/testing/Empty'; /** * A service to remotely control health status of an xDS test server. @@ -31,8 +31,8 @@ export interface XdsUpdateHealthServiceClient extends grpc.Client { * A service to remotely control health status of an xDS test server. */ export interface XdsUpdateHealthServiceHandlers extends grpc.UntypedServiceImplementation { - SetNotServing(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + SetNotServing: grpc.handleUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>; - SetServing(call: grpc.ServerUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>, callback: grpc.sendUnaryData<_grpc_testing_Empty>): void; + SetServing: grpc.handleUnaryCall<_grpc_testing_Empty__Output, _grpc_testing_Empty>; } diff --git a/packages/grpc-js-xds/interop/generated/test.ts b/packages/grpc-js-xds/interop/generated/test.ts index aedfa2455..f91f0c970 100644 --- a/packages/grpc-js-xds/interop/generated/test.ts +++ b/packages/grpc-js-xds/interop/generated/test.ts @@ -1,16 +1,15 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServiceClient } from './grpc/testing/LoadBalancerStatsService'; -import { ReconnectServiceClient as _grpc_testing_ReconnectServiceClient } from './grpc/testing/ReconnectService'; -import { TestServiceClient as _grpc_testing_TestServiceClient } from './grpc/testing/TestService'; -import { UnimplementedServiceClient as _grpc_testing_UnimplementedServiceClient } from './grpc/testing/UnimplementedService'; -import { XdsUpdateClientConfigureServiceClient as _grpc_testing_XdsUpdateClientConfigureServiceClient } from './grpc/testing/XdsUpdateClientConfigureService'; -import { XdsUpdateHealthServiceClient as _grpc_testing_XdsUpdateHealthServiceClient } from './grpc/testing/XdsUpdateHealthService'; +import type { LoadBalancerStatsServiceClient as _grpc_testing_LoadBalancerStatsServiceClient } from './grpc/testing/LoadBalancerStatsService'; +import type { ReconnectServiceClient as _grpc_testing_ReconnectServiceClient } from './grpc/testing/ReconnectService'; +import type { TestServiceClient as _grpc_testing_TestServiceClient } from './grpc/testing/TestService'; +import type { UnimplementedServiceClient as _grpc_testing_UnimplementedServiceClient } from './grpc/testing/UnimplementedService'; +import type { XdsUpdateClientConfigureServiceClient as _grpc_testing_XdsUpdateClientConfigureServiceClient } from './grpc/testing/XdsUpdateClientConfigureService'; +import type { XdsUpdateHealthServiceClient as _grpc_testing_XdsUpdateHealthServiceClient } from './grpc/testing/XdsUpdateHealthService'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 9f8abb10a..3f90c7e97 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -42,7 +42,7 @@ "yargs": "^15.4.1" }, "dependencies": { - "@grpc/proto-loader": "^0.6.0-pre14", + "@grpc/proto-loader": "^0.6.0", "google-auth-library": "^7.0.2", "re2-wasm": "^1.0.1" }, diff --git a/packages/grpc-js-xds/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts index 10c420a1d..0eacd1e34 100644 --- a/packages/grpc-js-xds/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -1,11 +1,10 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; +import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts index b165ae6b4..b7005a3f0 100644 --- a/packages/grpc-js-xds/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -1,10 +1,9 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/endpoint.ts b/packages/grpc-js-xds/src/generated/endpoint.ts index 18c439848..33d5872ef 100644 --- a/packages/grpc-js-xds/src/generated/endpoint.ts +++ b/packages/grpc-js-xds/src/generated/endpoint.ts @@ -1,10 +1,9 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts index 4bda5ec6e..f077d2edc 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts @@ -1,29 +1,29 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; -import { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from '../../../envoy/api/v2/core/HealthCheck'; -import { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from '../../../envoy/api/v2/cluster/CircuitBreakers'; -import { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from '../../../envoy/api/v2/auth/UpstreamTlsContext'; -import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http1ProtocolOptions'; -import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http2ProtocolOptions'; -import { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from '../../../envoy/api/v2/cluster/OutlierDetection'; -import { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from '../../../envoy/api/v2/core/BindConfig'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../envoy/api/v2/core/TransportSocket'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; -import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../envoy/api/v2/core/HttpProtocolOptions'; -import { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from '../../../envoy/api/v2/UpstreamConnectionOptions'; -import { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from '../../../envoy/api/v2/ClusterLoadAssignment'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; -import { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from '../../../envoy/api/v2/cluster/Filter'; -import { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from '../../../envoy/api/v2/LoadBalancingPolicy'; -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; -import { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; -import { Long } from '@grpc/proto-loader'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +import type { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from '../../../envoy/api/v2/core/HealthCheck'; +import type { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from '../../../envoy/api/v2/cluster/CircuitBreakers'; +import type { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from '../../../envoy/api/v2/auth/UpstreamTlsContext'; +import type { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http1ProtocolOptions'; +import type { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http2ProtocolOptions'; +import type { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from '../../../envoy/api/v2/cluster/OutlierDetection'; +import type { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from '../../../envoy/api/v2/core/BindConfig'; +import type { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../envoy/api/v2/core/TransportSocket'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; +import type { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../envoy/api/v2/core/HttpProtocolOptions'; +import type { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from '../../../envoy/api/v2/UpstreamConnectionOptions'; +import type { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from '../../../envoy/api/v2/ClusterLoadAssignment'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from '../../../envoy/api/v2/cluster/Filter'; +import type { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from '../../../envoy/api/v2/LoadBalancingPolicy'; +import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; +import type { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; +import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; +import type { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; +import type { Long } from '@grpc/proto-loader'; // Original file: deps/envoy-api/envoy/api/v2/cluster.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts index bb5ac327d..14598bec1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint.proto -import { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from '../../../envoy/api/v2/endpoint/LocalityLbEndpoints'; -import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../envoy/api/v2/endpoint/Endpoint'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../envoy/type/FractionalPercent'; +import type { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from '../../../envoy/api/v2/endpoint/LocalityLbEndpoints'; +import type { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../envoy/api/v2/endpoint/Endpoint'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../envoy/type/FractionalPercent'; /** * [#not-implemented-hide:] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts index 4791e30b3..11cbe8c2c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/discovery.proto -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; /** * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts index 8af4b4eb5..1a2584b95 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/discovery.proto -import { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from '../../../envoy/api/v2/Resource'; +import type { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from '../../../envoy/api/v2/Resource'; /** * [#next-free-field: 7] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts index ee24e74fa..2150c41bc 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/discovery.proto -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; -import { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; /** * A DiscoveryRequest requests a set of versioned resources of the same type for diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts index 8eb7d42c0..dd7e70d4d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/discovery.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; -import { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from '../../../envoy/api/v2/core/ControlPlane'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from '../../../envoy/api/v2/core/ControlPlane'; /** * [#next-free-field: 7] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts index 73bfb6ec6..8aed6564d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts @@ -1,17 +1,17 @@ // Original file: deps/envoy-api/envoy/api/v2/listener.proto -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; -import { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from '../../../envoy/api/v2/listener/FilterChain'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; -import { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from '../../../envoy/api/v2/listener/ListenerFilter'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../envoy/api/v2/core/SocketOption'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from '../../../envoy/api/v2/core/TrafficDirection'; -import { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from '../../../envoy/api/v2/listener/UdpListenerConfig'; -import { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from '../../../envoy/config/listener/v2/ApiListener'; -import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../envoy/config/filter/accesslog/v2/AccessLog'; +import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +import type { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from '../../../envoy/api/v2/listener/FilterChain'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; +import type { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from '../../../envoy/api/v2/listener/ListenerFilter'; +import type { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../envoy/api/v2/core/SocketOption'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import type { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from '../../../envoy/api/v2/core/TrafficDirection'; +import type { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from '../../../envoy/api/v2/listener/UdpListenerConfig'; +import type { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from '../../../envoy/config/listener/v2/ApiListener'; +import type { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../envoy/config/filter/accesslog/v2/AccessLog'; /** * Configuration for listener connection balancing. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts index 03c33c853..f79112a1c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; export interface _envoy_api_v2_LoadBalancingPolicy_Policy { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts index 88c511cb1..4804201bd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/discovery.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; export interface Resource { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts index 495950ff6..de0634c24 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/route.proto -import { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from '../../../envoy/api/v2/route/VirtualHost'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../envoy/api/v2/core/HeaderValueOption'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; -import { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; +import type { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from '../../../envoy/api/v2/route/VirtualHost'; +import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../envoy/api/v2/core/HeaderValueOption'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; +import type { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; /** * [#next-free-field: 11] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts index d90e9ad91..966ccca85 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster.proto -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; /** * An extensible structure containing the address Envoy should bind to when diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts index 6a4244741..e46a2cd06 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster.proto -import { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from '../../../envoy/api/v2/core/TcpKeepalive'; +import type { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from '../../../envoy/api/v2/core/TcpKeepalive'; export interface UpstreamConnectionOptions { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts index a89f2276b..f2ec45d2d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/route.proto -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; +import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; export interface Vhds { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts index fe8637fd3..0272f3b5c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts index a57288fa5..784e3d2ce 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto -import { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from '../../../../envoy/api/v2/auth/TlsParameters'; -import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; -import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; +import type { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from '../../../../envoy/api/v2/auth/TlsParameters'; +import type { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; +import type { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; +import type { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts index c63b2a719..ef9a6f9a4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto -import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; -import { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; +import type { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; /** * [#next-free-field: 8] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts index fc57bebb1..d7b712525 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; export interface GenericSecret { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts index 3726e5434..415448053 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * BoringSSL private key method configuration. The private key methods are used for external diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts index 5a4292951..888059332 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../envoy/api/v2/core/ConfigSource'; +import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../envoy/api/v2/core/ConfigSource'; export interface SdsSecretConfig { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts index 086f7648e..0768daed8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto -import { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; -import { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; -import { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; -import { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from '../../../../envoy/api/v2/auth/GenericSecret'; +import type { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; +import type { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; +import type { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; +import type { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from '../../../../envoy/api/v2/auth/GenericSecret'; /** * [#next-free-field: 6] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts index cdefe7040..dd7efcf21 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from '../../../../envoy/api/v2/auth/PrivateKeyProvider'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from '../../../../envoy/api/v2/auth/PrivateKeyProvider'; /** * [#next-free-field: 7] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts index 80a79fa08..d4bedd682 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/common.proto -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; export interface TlsSessionTicketKeys { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts index 7a56be3c0..b9dc4414f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto -import { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; export interface UpstreamTlsContext { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts index f9380aec1..edf946590 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../envoy/type/Percent'; +import type { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../envoy/type/Percent'; export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts index 225928629..5608fadf2 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster/filter.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface Filter { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts index 995b01180..53c1b4609 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/cluster/outlier_detection.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; /** * See the :ref:`architecture overview ` for diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts index 4ccd1e892..b12c8d9b0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/address.proto -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; -import { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from '../../../../envoy/api/v2/core/Pipe'; +import type { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; +import type { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from '../../../../envoy/api/v2/core/Pipe'; /** * Addresses specify either a logical or physical address and port, which are diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts index b6906acd5..a99924d9b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; -import { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from '../../../../envoy/api/v2/core/RateLimitSettings'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; +import type { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from '../../../../envoy/api/v2/core/RateLimitSettings'; +import type { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts index c4de49ee0..fb312bb40 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from '../../../../envoy/api/v2/core/RemoteDataSource'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from '../../../../envoy/api/v2/core/RemoteDataSource'; /** * Async data source which support async data fetch. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts index 3e8c6dd49..48f9d904d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/backoff.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; /** * Configuration defining a jittered exponential back off strategy. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts index 8b8451080..f989494ea 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/core/address.proto -import { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../../envoy/api/v2/core/SocketOption'; +import type { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../../envoy/api/v2/core/SocketOption'; export interface BindConfig { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts index b3b9a808d..009506fa2 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from '../../../../envoy/type/SemanticVersion'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from '../../../../envoy/type/SemanticVersion'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; /** * BuildVersion combines SemVer version of extension with free-form build information diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts index 18b693fcf..00c67734f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/address.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** * CidrRange specifies an IP Address and a prefix length to construct diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts index 1e4bfa4cd..766af6148 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto -import { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from '../../../../envoy/api/v2/core/ApiConfigSource'; -import { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from '../../../../envoy/api/v2/core/AggregatedConfigSource'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; -import { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; +import type { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from '../../../../envoy/api/v2/core/ApiConfigSource'; +import type { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from '../../../../envoy/api/v2/core/AggregatedConfigSource'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; +import type { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; /** * Configuration for :ref:`listeners `, :ref:`clusters diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts index 3cba29184..d0637578c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/event_service_config.proto -import { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; +import type { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; /** * [#not-implemented-hide:] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts index 3656f1f9a..418c7a360 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; +import type { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; /** * Version and identification for an Envoy extension. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts index 038245239..66723801e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto -import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../envoy/api/v2/core/Http2ProtocolOptions'; +import type { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../envoy/api/v2/core/Http2ProtocolOptions'; /** * [#not-implemented-hide:] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts index 567da12bc..3bc894b57 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts @@ -1,12 +1,12 @@ // Original file: deps/envoy-api/envoy/api/v2/core/grpc_service.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { Long } from '@grpc/proto-loader'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Long } from '@grpc/proto-loader'; /** * [#next-free-field: 8] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts index 3144e668c..e093d4761 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +import type { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; /** * Wrapper for a set of headers. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts index c66ce9aad..b90bd85e1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; /** * Header name/value pair plus option to control append behavior. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts index a9a3e3310..0b45042f3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts @@ -1,16 +1,16 @@ // Original file: deps/envoy-api/envoy/api/v2/core/health_check.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from '../../../../envoy/api/v2/core/EventServiceConfig'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; -import { CodecClientType as _envoy_type_CodecClientType } from '../../../../envoy/type/CodecClientType'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { Long } from '@grpc/proto-loader'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from '../../../../envoy/api/v2/core/EventServiceConfig'; +import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import type { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; +import type { CodecClientType as _envoy_type_CodecClientType } from '../../../../envoy/type/CodecClientType'; +import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Long } from '@grpc/proto-loader'; /** * Custom health check. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts index 7feca246a..b9bb0ce54 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts index d24c38a55..893f61a15 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** * Defines a parameter to be sent in the SETTINGS frame. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts index 964645696..219fdb0c7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; // Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts index b01489a64..19711dde7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/http_uri.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; /** * Envoy external URI descriptor diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts index 2a3c8f996..ca823a27c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; /** * Metadata provides additional inputs to filters based on matched listeners, diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts index 5a8842482..c6ddea9d4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; -import { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; -import { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from '../../../../envoy/api/v2/core/Extension'; -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import type { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; +import type { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from '../../../../envoy/api/v2/core/Extension'; +import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; /** * Identifies a specific Envoy instance. The node identifier is presented to the diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts index 05cb819c9..222c86eb4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from '../../../../google/protobuf/DoubleValue'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from '../../../../google/protobuf/DoubleValue'; /** * Rate Limit settings to be applied for discovery requests made by Envoy. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts index 603cc258c..93e722eef 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from '../../../../envoy/api/v2/core/HttpUri'; -import { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from '../../../../envoy/api/v2/core/RetryPolicy'; +import type { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from '../../../../envoy/api/v2/core/HttpUri'; +import type { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from '../../../../envoy/api/v2/core/RetryPolicy'; /** * The message specifies how to fetch data from remote and how to verify it. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts index 4df63c53e..27c1096b7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from '../../../../envoy/api/v2/core/BackoffStrategy'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from '../../../../envoy/api/v2/core/BackoffStrategy'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** * The message specifies the retry policy of remote data source when fetching fails. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts index 6994218d1..47cf24097 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; /** * Runtime derived bool with a default when not specified. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts index 78eeb3257..08e29de1f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; +import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; /** * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts index 0c4a4e1ca..4a32e46b4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; // Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts index e6c85ba44..394a54feb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/core/address.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; export interface TcpKeepalive { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts index 3034df987..b45767eb2 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/core/base.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * Configuration for transport socket in :ref:`listeners ` and diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts index 8b2492899..4b5c30f4c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto -import { UpstreamLocalityStats as _envoy_api_v2_endpoint_UpstreamLocalityStats, UpstreamLocalityStats__Output as _envoy_api_v2_endpoint_UpstreamLocalityStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamLocalityStats'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { Long } from '@grpc/proto-loader'; +import type { UpstreamLocalityStats as _envoy_api_v2_endpoint_UpstreamLocalityStats, UpstreamLocalityStats__Output as _envoy_api_v2_endpoint_UpstreamLocalityStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamLocalityStats'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Long } from '@grpc/proto-loader'; export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts index f9a69142a..68bef75e1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; /** * The optional health check configuration. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts index a42087c9c..9ed8016b7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts index fa8e64999..1f8be9305 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto -import { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../../envoy/api/v2/endpoint/Endpoint'; -import { HealthStatus as _envoy_api_v2_core_HealthStatus } from '../../../../envoy/api/v2/core/HealthStatus'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../../envoy/api/v2/endpoint/Endpoint'; +import type { HealthStatus as _envoy_api_v2_core_HealthStatus } from '../../../../envoy/api/v2/core/HealthStatus'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** * An Endpoint that Envoy can route traffic to. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts index 401ea7313..557d97072 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; -import { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from '../../../../envoy/api/v2/endpoint/LbEndpoint'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import type { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from '../../../../envoy/api/v2/endpoint/LbEndpoint'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** * A group of endpoints belonging to a Locality. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts index 4d2df5d2f..5b5c62b32 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto -import { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; -import { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Long } from '@grpc/proto-loader'; +import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +import type { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Long } from '@grpc/proto-loader'; /** * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts index 946ca76bc..a1b20897e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts @@ -1,9 +1,9 @@ // Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto -import { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; -import { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; -import { UpstreamEndpointStats as _envoy_api_v2_endpoint_UpstreamEndpointStats, UpstreamEndpointStats__Output as _envoy_api_v2_endpoint_UpstreamEndpointStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamEndpointStats'; -import { Long } from '@grpc/proto-loader'; +import type { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; +import type { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; +import type { UpstreamEndpointStats as _envoy_api_v2_endpoint_UpstreamEndpointStats, UpstreamEndpointStats__Output as _envoy_api_v2_endpoint_UpstreamEndpointStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamEndpointStats'; +import type { Long } from '@grpc/proto-loader'; /** * These are stats Envoy reports to GLB every so often. Report frequency is diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts index 017302934..2c6e0d087 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface Filter { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts index fa2c8ddbe..1e98abe50 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts @@ -1,11 +1,11 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto -import { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from '../../../../envoy/api/v2/listener/FilterChainMatch'; -import { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from '../../../../envoy/api/v2/auth/DownstreamTlsContext'; -import { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from '../../../../envoy/api/v2/listener/Filter'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../../envoy/api/v2/core/TransportSocket'; +import type { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from '../../../../envoy/api/v2/listener/FilterChainMatch'; +import type { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from '../../../../envoy/api/v2/auth/DownstreamTlsContext'; +import type { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from '../../../../envoy/api/v2/listener/Filter'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../../envoy/api/v2/core/TransportSocket'; /** * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts index cdf49bf0a..881a5a961 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto -import { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from '../../../../envoy/api/v2/core/CidrRange'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from '../../../../envoy/api/v2/core/CidrRange'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts index 75fc917e5..080d922b1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; export interface ListenerFilter { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts index 547e74d11..ac3ddfd2a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto -import { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; -import { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from '../../../../envoy/type/Int32Range'; +import type { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; +import type { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from '../../../../envoy/type/Int32Range'; /** * A set of match configurations used for logical operations. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts index 34a710b14..2299c5719 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface UdpListenerConfig { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts index b2429e5e2..7b76b9d85 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; /** * [#next-free-field: 12] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts index d1a2fa25f..68c91327d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; export interface Decorator { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts index 6e9ed7cae..83777f9e3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; export interface DirectResponseAction { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts index ca626cfaf..a41f3f417 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * A filter-defined action type. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts index 3e9793649..347849901 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; -import { Long } from '@grpc/proto-loader'; +import type { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; +import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; +import type { Long } from '@grpc/proto-loader'; /** * .. attention:: diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts index c362bdc52..8134fc359 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; /** * HTTP request hedging :ref:`architecture overview `. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts index eeed23abe..68f4fbcaa 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; /** * Query parameter matching treats the query string of a request's :path header diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts index 385dad6f6..998d94e53 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; /** * [#next-free-field: 7] diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts index 24bdd2814..63b7deb5a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts @@ -1,11 +1,11 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { Long } from '@grpc/proto-loader'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Long } from '@grpc/proto-loader'; export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts index 7d0ff8bd8..86cb4ac3d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts @@ -1,17 +1,17 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from '../../../../envoy/api/v2/route/RouteMatch'; -import { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from '../../../../envoy/api/v2/route/RouteAction'; -import { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from '../../../../envoy/api/v2/route/RedirectAction'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from '../../../../envoy/api/v2/route/Decorator'; -import { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from '../../../../envoy/api/v2/route/DirectResponseAction'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from '../../../../envoy/api/v2/route/Tracing'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; +import type { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from '../../../../envoy/api/v2/route/RouteMatch'; +import type { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from '../../../../envoy/api/v2/route/RouteAction'; +import type { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from '../../../../envoy/api/v2/route/RedirectAction'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from '../../../../envoy/api/v2/route/Decorator'; +import type { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from '../../../../envoy/api/v2/route/DirectResponseAction'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from '../../../../envoy/api/v2/route/Tracing'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; /** * A route is both a specification of how to match a request as well as an indication of what to do diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts index 94e769deb..5f07bae9b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts @@ -1,18 +1,18 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from '../../../../envoy/api/v2/route/WeightedCluster'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; -import { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; -import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; -import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; -import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/RegexMatchAndSubstitute'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import type { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from '../../../../envoy/api/v2/route/WeightedCluster'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; +import type { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; +import type { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; +import type { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; +import type { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/RegexMatchAndSubstitute'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts index b4af4adf2..b055c0506 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; -import { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from '../../../../envoy/api/v2/route/QueryParameterMatcher'; -import { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import type { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from '../../../../envoy/api/v2/route/QueryParameterMatcher'; +import type { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions { } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts index d60486314..18b063339 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; -import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../envoy/type/tracing/v2/CustomTag'; +import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; +import type { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../envoy/type/tracing/v2/CustomTag'; export interface Tracing { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts index fb62d9a51..f072710ce 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { RequestMethod as _envoy_api_v2_core_RequestMethod } from '../../../../envoy/api/v2/core/RequestMethod'; -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import type { RequestMethod as _envoy_api_v2_core_RequestMethod } from '../../../../envoy/api/v2/core/RequestMethod'; +import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; /** * A virtual cluster is a way of specifying a regex matching rule against diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts index 5c8c6cfa6..ad806e949 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts @@ -1,15 +1,15 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from '../../../../envoy/api/v2/route/Route'; -import { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from '../../../../envoy/api/v2/route/VirtualCluster'; -import { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; -import { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from '../../../../envoy/api/v2/route/Route'; +import type { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from '../../../../envoy/api/v2/route/VirtualCluster'; +import type { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; +import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import type { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; +import type { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts index 512c06b4d..5b283404b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * [#next-free-field: 11] diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts index 7ff4a751c..82e056a4b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; +import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; export interface AccessLog { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts index 19eb4ed28..d75c9676c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts @@ -1,16 +1,16 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/StatusCodeFilter'; -import { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/DurationFilter'; -import { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; -import { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/TraceableFilter'; -import { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/RuntimeFilter'; -import { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AndFilter'; -import { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/OrFilter'; -import { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/HeaderFilter'; -import { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ResponseFlagFilter'; -import { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/GrpcStatusFilter'; -import { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ExtensionFilter'; +import type { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/StatusCodeFilter'; +import type { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/DurationFilter'; +import type { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; +import type { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/TraceableFilter'; +import type { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/RuntimeFilter'; +import type { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AndFilter'; +import type { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/OrFilter'; +import type { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/HeaderFilter'; +import type { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ResponseFlagFilter'; +import type { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/GrpcStatusFilter'; +import type { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ExtensionFilter'; /** * [#next-free-field: 12] diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts index a39ba8f21..7cf1cb98c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; /** * Performs a logical “and†operation on the result of each filter in filters. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts index 9e264d7a4..8989ba603 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from '../../../../../envoy/api/v2/core/RuntimeUInt32'; +import type { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from '../../../../../envoy/api/v2/core/RuntimeUInt32'; // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts index e8756385a..52a37cd95 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; +import type { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; /** * Filters on total request duration in milliseconds. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts index b0a061b82..184c76eb6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; /** * Extension filter is statically registered at runtime. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts index 2b4e6275d..d40610617 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../../envoy/api/v2/route/HeaderMatcher'; +import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../../envoy/api/v2/route/HeaderMatcher'; /** * Filters requests based on the presence or value of a request header. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts index def55d54a..859c1218c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; /** * Performs a logical “or†operation on the result of each individual filter. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts index 9548b5a16..100ce050b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../../envoy/type/FractionalPercent'; +import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../../envoy/type/FractionalPercent'; /** * Filters for random sampling of requests. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts index d51d42b49..d60a80a14 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto -import { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; +import type { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; /** * Filters on HTTP response/status code. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts index 9aa2b2d25..1838f89a7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts @@ -1,20 +1,20 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { Rds as _envoy_config_filter_network_http_connection_manager_v2_Rds, Rds__Output as _envoy_config_filter_network_http_connection_manager_v2_Rds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/Rds'; -import { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from '../../../../../../envoy/api/v2/RouteConfiguration'; -import { HttpFilter as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter, HttpFilter__Output as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/HttpFilter'; -import { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../../google/protobuf/BoolValue'; -import { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http1ProtocolOptions'; -import { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http2ProtocolOptions'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../../google/protobuf/Duration'; -import { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../../../../envoy/config/filter/accesslog/v2/AccessLog'; -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; -import { ScopedRoutes as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes, ScopedRoutes__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes'; -import { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/HttpProtocolOptions'; -import { RequestIDExtension as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension, RequestIDExtension__Output as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension'; -import { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../../../envoy/type/Percent'; -import { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../../../envoy/type/tracing/v2/CustomTag'; -import { _envoy_config_trace_v2_Tracing_Http, _envoy_config_trace_v2_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v2/Tracing'; +import type { Rds as _envoy_config_filter_network_http_connection_manager_v2_Rds, Rds__Output as _envoy_config_filter_network_http_connection_manager_v2_Rds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/Rds'; +import type { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from '../../../../../../envoy/api/v2/RouteConfiguration'; +import type { HttpFilter as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter, HttpFilter__Output as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/HttpFilter'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../../google/protobuf/BoolValue'; +import type { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http1ProtocolOptions'; +import type { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http2ProtocolOptions'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../../google/protobuf/Duration'; +import type { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../../../../envoy/config/filter/accesslog/v2/AccessLog'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; +import type { ScopedRoutes as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes, ScopedRoutes__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes'; +import type { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/HttpProtocolOptions'; +import type { RequestIDExtension as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension, RequestIDExtension__Output as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension'; +import type { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../../../envoy/type/Percent'; +import type { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../../../envoy/type/tracing/v2/CustomTag'; +import type { _envoy_config_trace_v2_Tracing_Http, _envoy_config_trace_v2_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v2/Tracing'; // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts index cf68dd989..84e4292fc 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; export interface HttpFilter { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts index 306cc0ddb..be9c038a6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; +import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; export interface Rds { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts index 4688b09cd..2f043d4a8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; export interface RequestIDExtension { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts index 989aee155..b3d89dffb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; +import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; export interface ScopedRds { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts index 81de7333e..a57f1725e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { ScopedRouteConfiguration as _envoy_api_v2_ScopedRouteConfiguration, ScopedRouteConfiguration__Output as _envoy_api_v2_ScopedRouteConfiguration__Output } from '../../../../../../envoy/api/v2/ScopedRouteConfiguration'; +import type { ScopedRouteConfiguration as _envoy_api_v2_ScopedRouteConfiguration, ScopedRouteConfiguration__Output as _envoy_api_v2_ScopedRouteConfiguration__Output } from '../../../../../../envoy/api/v2/ScopedRouteConfiguration'; /** * This message is used to work around the limitations with 'oneof' and repeated fields. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts index 1409cb899..b9b20d2bf 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto -import { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; -import { ScopedRouteConfigurationsList as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList, ScopedRouteConfigurationsList__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList'; -import { ScopedRds as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds, ScopedRds__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRds'; +import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; +import type { ScopedRouteConfigurationsList as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList, ScopedRouteConfigurationsList__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList'; +import type { ScopedRds as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds, ScopedRds__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRds'; /** * Specifies the mechanism for constructing key fragments which are composed into scope keys. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts index be4d2415e..f683d3e82 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/config/listener/v2/api_listener.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * Describes a type of API listener, which is used in non-proxy clients. The type of API diff --git a/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts index b7ee1c3ad..629e3f1cc 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/config/trace/v2/http_tracer.proto -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * Configuration for an HTTP tracer provider used by Envoy. diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts index 02c0da34e..ec7641dca 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts @@ -1,10 +1,10 @@ // Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto -import * as grpc from '@grpc/grpc-js' -import { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; -import { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; -import { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; -import { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from '../../../../envoy/api/v2/DiscoveryResponse'; +import type * as grpc from '@grpc/grpc-js' +import type { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; +import type { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; +import type { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; +import type { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from '../../../../envoy/api/v2/DiscoveryResponse'; /** * See https://github.com/lyft/envoy-api#apis for a description of the role of @@ -42,11 +42,11 @@ export interface AggregatedDiscoveryServiceClient extends grpc.Client { * the multiplexed singleton APIs at the Envoy instance and management server. */ export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceImplementation { - DeltaAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse>): void; + DeltaAggregatedResources: grpc.handleBidiStreamingCall<_envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse>; /** * This is a gRPC-only API. */ - StreamAggregatedResources(call: grpc.ServerDuplexStream<_envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse>): void; + StreamAggregatedResources: grpc.handleBidiStreamingCall<_envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse>; } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts index 7db2bad1c..41e73f0e9 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts @@ -1,8 +1,8 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto -import * as grpc from '@grpc/grpc-js' -import { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; -import { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; +import type * as grpc from '@grpc/grpc-js' +import type { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; +import type { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; export interface LoadReportingServiceClient extends grpc.Client { /** @@ -103,6 +103,6 @@ export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImpleme * from around the world, computes global assignment and prepares traffic * assignment destined for each zone Envoys are located in. Goto 2. */ - StreamLoadStats(call: grpc.ServerDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>): void; + StreamLoadStats: grpc.handleBidiStreamingCall<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>; } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts index f2c2393cb..a7ac6b8e1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto -import { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../../envoy/api/v2/core/Node'; -import { ClusterStats as _envoy_api_v2_endpoint_ClusterStats, ClusterStats__Output as _envoy_api_v2_endpoint_ClusterStats__Output } from '../../../../envoy/api/v2/endpoint/ClusterStats'; +import type { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../../envoy/api/v2/core/Node'; +import type { ClusterStats as _envoy_api_v2_endpoint_ClusterStats, ClusterStats__Output as _envoy_api_v2_endpoint_ClusterStats__Output } from '../../../../envoy/api/v2/endpoint/ClusterStats'; /** * A load report Envoy sends to the management server. diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts index 9326d869b..afec8f180 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; /** * The management server sends envoy a LoadStatsResponse with all clusters it diff --git a/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts index 16c8235ca..f9664cba4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/type/range.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * Specifies the int64 start and end of the range using half-open interval semantics [start, diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts index e4ac83f0d..42bde031b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/type/matcher/string.proto -import { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../envoy/type/matcher/StringMatcher'; +import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../envoy/type/matcher/StringMatcher'; /** * Specifies a list of ways to match a string. diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts index 390bae053..17c38c7c0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/type/matcher/regex.proto -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; +import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; /** * Describes how to match a string and then produce a new string using a regular diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts index 697b9d6a9..8a18816b0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/type/matcher/regex.proto -import { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; /** * Google's `RE2 `_ regex engine. The regex string must adhere to diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts index de8ce5dc2..e434b1e1b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts @@ -1,6 +1,6 @@ // Original file: deps/envoy-api/envoy/type/matcher/string.proto -import { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; +import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; /** * Specifies the way to match a string. diff --git a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts index 75d33cf4a..3eed4cf44 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts @@ -1,7 +1,7 @@ // Original file: deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto -import { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from '../../../../envoy/type/metadata/v2/MetadataKind'; -import { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from '../../../../envoy/type/metadata/v2/MetadataKey'; +import type { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from '../../../../envoy/type/metadata/v2/MetadataKind'; +import type { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from '../../../../envoy/type/metadata/v2/MetadataKey'; /** * Environment type custom tag with environment name and default value. diff --git a/packages/grpc-js-xds/src/generated/google/api/Http.ts b/packages/grpc-js-xds/src/generated/google/api/Http.ts index 038c57e5e..e9b3cb309 100644 --- a/packages/grpc-js-xds/src/generated/google/api/Http.ts +++ b/packages/grpc-js-xds/src/generated/google/api/Http.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/api/http.proto -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; /** * Defines the HTTP configuration for an API service. It contains a list of diff --git a/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts index ed9921e5e..21ad897ee 100644 --- a/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts +++ b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts @@ -1,7 +1,7 @@ // Original file: deps/googleapis/google/api/http.proto -import { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; -import { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; /** * # gRPC Transcoding diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts index b592af4ba..fe0d05f12 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts @@ -1,6 +1,6 @@ // Original file: null -import { AnyExtension } from '@grpc/proto-loader'; +import type { AnyExtension } from '@grpc/proto-loader'; export type Any = AnyExtension | { type_url: string; diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts index 8ab286897..2f6f9f0cc 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts @@ -1,10 +1,10 @@ // Original file: null -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; -import { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; +import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import type { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; +import type { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; export interface _google_protobuf_DescriptorProto_ExtensionRange { 'start'?: (number); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts index 78610b80a..8595377a0 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Duration.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface Duration { 'seconds'?: (number | string | Long); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts index 1971fccb0..7aa40ce4d 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts @@ -1,7 +1,7 @@ // Original file: null -import { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; -import { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; +import type { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; +import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; export interface EnumDescriptorProto { 'name'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts index a4f3b7a45..b92f699a0 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts @@ -1,7 +1,7 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumOptions { 'allowAlias'?: (boolean); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts index 919b7aa38..238e7fd01 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; +import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; export interface EnumValueDescriptorProto { 'name'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts index 0fac2df8f..db2770534 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts @@ -1,7 +1,7 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumValueOptions { 'deprecated'?: (boolean); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts index e0a1f4580..b59518c4b 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; +import type { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; // Original file: null diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index 12a2661a3..b76a60815 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -1,8 +1,8 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; -import { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; +import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; // Original file: null diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts index 65315a644..2954e4208 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts @@ -1,11 +1,11 @@ // Original file: null -import { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; -import { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; -import { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; -import { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; -import { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; +import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; +import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; +import type { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; +import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; +import type { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; +import type { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; export interface FileDescriptorProto { 'name'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts index f01cabc4c..74ded2471 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorSet.ts @@ -1,6 +1,6 @@ // Original file: null -import { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; +import type { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; export interface FileDescriptorSet { 'file'?: (_google_protobuf_FileDescriptorProto)[]; diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts index b11540d27..b2ddbb374 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts @@ -1,8 +1,8 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; -import { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; +import type { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; // Original file: null diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts index 38b0e28f3..f7375196d 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Int64Value.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface Int64Value { 'value'?: (number | string | Long); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts index 4b3cf67d7..fa762b9ba 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/ListValue.ts @@ -1,6 +1,6 @@ // Original file: null -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; +import type { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; export interface ListValue { 'values'?: (_google_protobuf_Value)[]; diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts index 88f654828..7560daa28 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts @@ -1,7 +1,7 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface MessageOptions { 'messageSetWireFormat'?: (boolean); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts index b62d45731..bc2f0afb5 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; +import type { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; export interface MethodDescriptorProto { 'name'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts index 982c7d5dc..e47fd756c 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface MethodOptions { 'deprecated'?: (boolean); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts index 5d1512003..c10ccecd3 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; +import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; export interface OneofDescriptorProto { 'name'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts index 01fdc9d2b..b54ecb0b1 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/OneofOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface OneofOptions { 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts index fe5cab5b4..695a8775c 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts @@ -1,7 +1,7 @@ // Original file: null -import { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; -import { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; +import type { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; +import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; export interface ServiceDescriptorProto { 'name'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts index c1bd83603..4899506a4 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; export interface ServiceOptions { 'deprecated'?: (boolean); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts index 4b4c3be78..9919350e4 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts @@ -1,6 +1,6 @@ // Original file: null -import { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; +import type { Value as _google_protobuf_Value, Value__Output as _google_protobuf_Value__Output } from '../../google/protobuf/Value'; export interface Struct { 'fields'?: ({[key: string]: _google_protobuf_Value}); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts index f8747e93e..ceaa32b5f 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Timestamp.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface Timestamp { 'seconds'?: (number | string | Long); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts index 790901733..7a85c39ce 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/UInt64Value.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface UInt64Value { 'value'?: (number | string | Long); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts index 91e3b99bc..433820f55 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts @@ -1,6 +1,6 @@ // Original file: null -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; export interface _google_protobuf_UninterpretedOption_NamePart { 'namePart'?: (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts index 0097135be..68b665dcb 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts @@ -1,8 +1,8 @@ // Original file: null -import { NullValue as _google_protobuf_NullValue } from '../../google/protobuf/NullValue'; -import { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../google/protobuf/Struct'; -import { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from '../../google/protobuf/ListValue'; +import type { NullValue as _google_protobuf_NullValue } from '../../google/protobuf/NullValue'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../google/protobuf/Struct'; +import type { ListValue as _google_protobuf_ListValue, ListValue__Output as _google_protobuf_ListValue__Output } from '../../google/protobuf/ListValue'; export interface Value { 'nullValue'?: (_google_protobuf_NullValue | keyof typeof _google_protobuf_NullValue); diff --git a/packages/grpc-js-xds/src/generated/google/rpc/Status.ts b/packages/grpc-js-xds/src/generated/google/rpc/Status.ts index 7da370379..4ce45b6a9 100644 --- a/packages/grpc-js-xds/src/generated/google/rpc/Status.ts +++ b/packages/grpc-js-xds/src/generated/google/rpc/Status.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/rpc/status.proto -import { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; /** * The `Status` type defines a logical error model that is suitable for diff --git a/packages/grpc-js-xds/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts index 5a90451af..7e822564d 100644 --- a/packages/grpc-js-xds/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -1,10 +1,9 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts index 57daeffd0..ab67cd096 100644 --- a/packages/grpc-js-xds/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -1,10 +1,9 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts index 56ada2f3d..f3f180807 100644 --- a/packages/grpc-js-xds/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -1,11 +1,10 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; +import type { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts index 40bcdd55d..05332fe37 100644 --- a/packages/grpc-js-xds/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -1,10 +1,9 @@ -import * as grpc from '@grpc/grpc-js'; -import { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -type ConstructorArguments = Constructor extends new (...args: infer Args) => any ? Args: never; -type SubtypeConstructor = { - new(...args: ConstructorArguments): Subtype; +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; }; export interface ProtoGrpcType { diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts index 1b00aa9fc..7b33ce9c8 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts @@ -1,6 +1,6 @@ // Original file: deps/udpa/udpa/annotations/status.proto -import { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from '../../udpa/annotations/PackageVersionStatus'; +import type { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from '../../udpa/annotations/PackageVersionStatus'; export interface StatusAnnotation { /** diff --git a/packages/grpc-js-xds/src/generated/validate/BytesRules.ts b/packages/grpc-js-xds/src/generated/validate/BytesRules.ts index 656d70194..cba6ca1ba 100644 --- a/packages/grpc-js-xds/src/generated/validate/BytesRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/BytesRules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * BytesRules describe the constraints applied to `bytes` values diff --git a/packages/grpc-js-xds/src/generated/validate/DurationRules.ts b/packages/grpc-js-xds/src/generated/validate/DurationRules.ts index 8a74651c8..86b80a34d 100644 --- a/packages/grpc-js-xds/src/generated/validate/DurationRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/DurationRules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; /** * DurationRules describe the constraints applied exclusively to the diff --git a/packages/grpc-js-xds/src/generated/validate/FieldRules.ts b/packages/grpc-js-xds/src/generated/validate/FieldRules.ts index 09cd9d9ee..dae124bc1 100644 --- a/packages/grpc-js-xds/src/generated/validate/FieldRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/FieldRules.ts @@ -1,28 +1,28 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from '../validate/FloatRules'; -import { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from '../validate/DoubleRules'; -import { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from '../validate/Int32Rules'; -import { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from '../validate/Int64Rules'; -import { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from '../validate/UInt32Rules'; -import { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from '../validate/UInt64Rules'; -import { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from '../validate/SInt32Rules'; -import { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from '../validate/SInt64Rules'; -import { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from '../validate/Fixed32Rules'; -import { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from '../validate/Fixed64Rules'; -import { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from '../validate/SFixed32Rules'; -import { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from '../validate/SFixed64Rules'; -import { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from '../validate/BoolRules'; -import { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from '../validate/StringRules'; -import { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from '../validate/BytesRules'; -import { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from '../validate/EnumRules'; -import { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from '../validate/MessageRules'; -import { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from '../validate/RepeatedRules'; -import { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from '../validate/MapRules'; -import { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from '../validate/AnyRules'; -import { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from '../validate/DurationRules'; -import { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from '../validate/TimestampRules'; -import { Long } from '@grpc/proto-loader'; +import type { FloatRules as _validate_FloatRules, FloatRules__Output as _validate_FloatRules__Output } from '../validate/FloatRules'; +import type { DoubleRules as _validate_DoubleRules, DoubleRules__Output as _validate_DoubleRules__Output } from '../validate/DoubleRules'; +import type { Int32Rules as _validate_Int32Rules, Int32Rules__Output as _validate_Int32Rules__Output } from '../validate/Int32Rules'; +import type { Int64Rules as _validate_Int64Rules, Int64Rules__Output as _validate_Int64Rules__Output } from '../validate/Int64Rules'; +import type { UInt32Rules as _validate_UInt32Rules, UInt32Rules__Output as _validate_UInt32Rules__Output } from '../validate/UInt32Rules'; +import type { UInt64Rules as _validate_UInt64Rules, UInt64Rules__Output as _validate_UInt64Rules__Output } from '../validate/UInt64Rules'; +import type { SInt32Rules as _validate_SInt32Rules, SInt32Rules__Output as _validate_SInt32Rules__Output } from '../validate/SInt32Rules'; +import type { SInt64Rules as _validate_SInt64Rules, SInt64Rules__Output as _validate_SInt64Rules__Output } from '../validate/SInt64Rules'; +import type { Fixed32Rules as _validate_Fixed32Rules, Fixed32Rules__Output as _validate_Fixed32Rules__Output } from '../validate/Fixed32Rules'; +import type { Fixed64Rules as _validate_Fixed64Rules, Fixed64Rules__Output as _validate_Fixed64Rules__Output } from '../validate/Fixed64Rules'; +import type { SFixed32Rules as _validate_SFixed32Rules, SFixed32Rules__Output as _validate_SFixed32Rules__Output } from '../validate/SFixed32Rules'; +import type { SFixed64Rules as _validate_SFixed64Rules, SFixed64Rules__Output as _validate_SFixed64Rules__Output } from '../validate/SFixed64Rules'; +import type { BoolRules as _validate_BoolRules, BoolRules__Output as _validate_BoolRules__Output } from '../validate/BoolRules'; +import type { StringRules as _validate_StringRules, StringRules__Output as _validate_StringRules__Output } from '../validate/StringRules'; +import type { BytesRules as _validate_BytesRules, BytesRules__Output as _validate_BytesRules__Output } from '../validate/BytesRules'; +import type { EnumRules as _validate_EnumRules, EnumRules__Output as _validate_EnumRules__Output } from '../validate/EnumRules'; +import type { MessageRules as _validate_MessageRules, MessageRules__Output as _validate_MessageRules__Output } from '../validate/MessageRules'; +import type { RepeatedRules as _validate_RepeatedRules, RepeatedRules__Output as _validate_RepeatedRules__Output } from '../validate/RepeatedRules'; +import type { MapRules as _validate_MapRules, MapRules__Output as _validate_MapRules__Output } from '../validate/MapRules'; +import type { AnyRules as _validate_AnyRules, AnyRules__Output as _validate_AnyRules__Output } from '../validate/AnyRules'; +import type { DurationRules as _validate_DurationRules, DurationRules__Output as _validate_DurationRules__Output } from '../validate/DurationRules'; +import type { TimestampRules as _validate_TimestampRules, TimestampRules__Output as _validate_TimestampRules__Output } from '../validate/TimestampRules'; +import type { Long } from '@grpc/proto-loader'; /** * FieldRules encapsulates the rules for each type of field. Depending on the diff --git a/packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts b/packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts index 0b750efc8..98fd1889e 100644 --- a/packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts +++ b/packages/grpc-js-xds/src/generated/validate/Fixed64Rules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * Fixed64Rules describes the constraints applied to `fixed64` values diff --git a/packages/grpc-js-xds/src/generated/validate/Int64Rules.ts b/packages/grpc-js-xds/src/generated/validate/Int64Rules.ts index cb167c960..3b91b3e09 100644 --- a/packages/grpc-js-xds/src/generated/validate/Int64Rules.ts +++ b/packages/grpc-js-xds/src/generated/validate/Int64Rules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * Int64Rules describes the constraints applied to `int64` values diff --git a/packages/grpc-js-xds/src/generated/validate/MapRules.ts b/packages/grpc-js-xds/src/generated/validate/MapRules.ts index 1be003f65..0c89bf2b3 100644 --- a/packages/grpc-js-xds/src/generated/validate/MapRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/MapRules.ts @@ -1,7 +1,7 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; -import { Long } from '@grpc/proto-loader'; +import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; +import type { Long } from '@grpc/proto-loader'; /** * MapRules describe the constraints applied to `map` values diff --git a/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts b/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts index b3b690684..1f6d4f0ff 100644 --- a/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts @@ -1,7 +1,7 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; -import { Long } from '@grpc/proto-loader'; +import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../validate/FieldRules'; +import type { Long } from '@grpc/proto-loader'; /** * RepeatedRules describe the constraints applied to `repeated` values diff --git a/packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts b/packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts index ccd5be954..2619e9475 100644 --- a/packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts +++ b/packages/grpc-js-xds/src/generated/validate/SFixed64Rules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * SFixed64Rules describes the constraints applied to `sfixed64` values diff --git a/packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts b/packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts index 61b3dd35f..db02f30c0 100644 --- a/packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts +++ b/packages/grpc-js-xds/src/generated/validate/SInt64Rules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * SInt64Rules describes the constraints applied to `sint64` values diff --git a/packages/grpc-js-xds/src/generated/validate/StringRules.ts b/packages/grpc-js-xds/src/generated/validate/StringRules.ts index 83d0b8e48..b6bb1e460 100644 --- a/packages/grpc-js-xds/src/generated/validate/StringRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/StringRules.ts @@ -1,7 +1,7 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { KnownRegex as _validate_KnownRegex } from '../validate/KnownRegex'; -import { Long } from '@grpc/proto-loader'; +import type { KnownRegex as _validate_KnownRegex } from '../validate/KnownRegex'; +import type { Long } from '@grpc/proto-loader'; /** * StringRules describe the constraints applied to `string` values diff --git a/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts b/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts index 7fd9b0ce4..9436cc8ee 100644 --- a/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts @@ -1,7 +1,7 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../google/protobuf/Timestamp'; -import { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../google/protobuf/Timestamp'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../google/protobuf/Duration'; /** * TimestampRules describe the constraints applied exclusively to the diff --git a/packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts b/packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts index 263431ad7..2878dfc8d 100644 --- a/packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts +++ b/packages/grpc-js-xds/src/generated/validate/UInt64Rules.ts @@ -1,6 +1,6 @@ // Original file: deps/protoc-gen-validate/validate/validate.proto -import { Long } from '@grpc/proto-loader'; +import type { Long } from '@grpc/proto-loader'; /** * UInt64Rules describes the constraints applied to `uint64` values From 72136bcf0bafdbc5148864803e1e139d05080f54 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 6 Apr 2021 10:57:11 -0700 Subject: [PATCH 1412/1899] grpc-js: Remove explicit version compatibility check --- packages/grpc-js/package.json | 4 +--- packages/grpc-js/src/index.ts | 7 ------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4c8cd9f94..6a027d391 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -22,7 +22,6 @@ "@types/mocha": "^5.2.6", "@types/ncp": "^2.0.1", "@types/pify": "^3.0.2", - "@types/semver": "^6.0.1", "@types/yargs": "^15.0.5", "clang-format": "^1.0.55", "execa": "^2.0.3", @@ -57,8 +56,7 @@ "posttest": "npm run check" }, "dependencies": { - "@types/node": ">=12.12.47", - "semver": "^6.2.0" + "@types/node": ">=12.12.47" }, "files": [ "src/**/*.ts", diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index e90ac4be8..308074640 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -15,8 +15,6 @@ * */ -import * as semver from 'semver'; - import { ClientDuplexStream, ClientReadableStream, @@ -66,11 +64,6 @@ import { ServerDuplexStream, } from './server-call'; -const supportedNodeVersions = require('../../package.json').engines.node; -if (!semver.satisfies(process.version, supportedNodeVersions)) { - throw new Error(`@grpc/grpc-js only works on Node ${supportedNodeVersions}`); -} - export { OAuth2Client }; /**** Client Credentials ****/ From 799bd16fe60aa137112b31c4e56998750db03170 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Apr 2021 11:22:04 -0700 Subject: [PATCH 1413/1899] proto-loader: generator: allow for null message values --- .../bin/proto-loader-gen-types.ts | 39 ++++++++++--------- .../golden-generated/google/api/HttpRule.ts | 4 +- .../google/longrunning/Operation.ts | 12 +++--- .../longrunning/WaitOperationRequest.ts | 4 +- .../google/protobuf/DescriptorProto.ts | 4 +- .../google/protobuf/EnumDescriptorProto.ts | 4 +- .../protobuf/EnumValueDescriptorProto.ts | 4 +- .../google/protobuf/FieldDescriptorProto.ts | 4 +- .../google/protobuf/FileDescriptorProto.ts | 8 ++-- .../google/protobuf/MethodDescriptorProto.ts | 4 +- .../google/protobuf/MethodOptions.ts | 8 ++-- .../google/protobuf/OneofDescriptorProto.ts | 4 +- .../google/protobuf/ServiceDescriptorProto.ts | 4 +- .../google/showcase/v1beta1/BlockRequest.ts | 12 +++--- .../google/showcase/v1beta1/EchoRequest.ts | 4 +- .../google/showcase/v1beta1/ExpandRequest.ts | 4 +- .../google/showcase/v1beta1/WaitMetadata.ts | 4 +- .../google/showcase/v1beta1/WaitRequest.ts | 16 ++++---- 18 files changed, 72 insertions(+), 71 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index c11befee0..66a6fec7a 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -170,7 +170,7 @@ function formatComment(formatter: TextFormatter, comment?: string | null) { // GENERATOR FUNCTIONS -function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null): string { +function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean): string { switch (fieldType) { case 'double': case 'float': @@ -199,7 +199,11 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | } const typeInterfaceName = getTypeInterfaceName(resolvedType); if (resolvedType instanceof Protobuf.Type) { - return typeInterfaceName; + if (repeated || map) { + return typeInterfaceName; + } else { + return `${typeInterfaceName} | null`; + } } else { return `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; } @@ -207,7 +211,7 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | } function getFieldTypePermissive(field: Protobuf.FieldBase): string { - const valueType = getTypeNamePermissive(field.type, field.resolvedType); + const valueType = getTypeNamePermissive(field.type, field.resolvedType, field.repeated, field.map); if (field instanceof Protobuf.MapField) { const keyType = field.keyType === 'string' ? 'string' : 'number'; return `{[key: ${keyType}]: ${valueType}}`; @@ -250,7 +254,7 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp formatter.writeLine('}'); } -function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, options: GeneratorOptions): string { +function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean, options: GeneratorOptions): string { switch (fieldType) { case 'double': case 'float': @@ -295,7 +299,13 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | } const typeInterfaceName = getTypeInterfaceName(resolvedType); if (resolvedType instanceof Protobuf.Type) { - return typeInterfaceName + '__Output'; + /* null is only used to represent absent message values if the defaults + * option is set, and only for non-repeated, non-map fields. */ + if (options.defaults && !repeated && !map) { + return `${typeInterfaceName}__Output | null`; + } else { + return `${typeInterfaceName}__Output`; + } } else { if (options.enums == String) { return `keyof typeof ${typeInterfaceName}`; @@ -307,7 +317,7 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | } function getFieldTypeRestricted(field: Protobuf.FieldBase, options: GeneratorOptions): string { - const valueType = getTypeNameRestricted(field.type, field.resolvedType, options); + const valueType = getTypeNameRestricted(field.type, field.resolvedType, field.repeated, field.map, options); if (field instanceof Protobuf.MapField) { const keyType = field.keyType === 'string' ? 'string' : 'number'; return `{[key: ${keyType}]: ${valueType}}`; @@ -326,7 +336,7 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp let optionalString = options.defaults ? '' : '?'; formatter.writeLine('export type Any__Output = AnyExtension | {'); formatter.writeLine(` type_url${optionalString}: string;`); - formatter.writeLine(` value${optionalString}: ${getTypeNameRestricted('bytes', null, options)};`); + formatter.writeLine(` value${optionalString}: ${getTypeNameRestricted('bytes', null, false, false, options)};`); formatter.writeLine('}'); return; } @@ -339,19 +349,10 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp fieldGuaranteed = false; } else if (field.repeated) { fieldGuaranteed = (options.defaults || options.arrays) ?? false; - } else if (field.resolvedType) { - if (field.resolvedType instanceof Protobuf.Enum) { - fieldGuaranteed = options.defaults ?? false; - } else { - // Message fields can always be omitted - fieldGuaranteed = false; - } + } else if (field.map) { + fieldGuaranteed = (options.defaults || options.objects) ?? false; } else { - if (field.map) { - fieldGuaranteed = (options.defaults || options.objects) ?? false; - } else { - fieldGuaranteed = options.defaults ?? false; - } + fieldGuaranteed = options.defaults ?? false; } const optionalString = fieldGuaranteed ? '' : '?'; const repeatedString = field.repeated ? '[]' : ''; diff --git a/packages/proto-loader/golden-generated/google/api/HttpRule.ts b/packages/proto-loader/golden-generated/google/api/HttpRule.ts index 21ad897ee..243a99f80 100644 --- a/packages/proto-loader/golden-generated/google/api/HttpRule.ts +++ b/packages/proto-loader/golden-generated/google/api/HttpRule.ts @@ -317,7 +317,7 @@ export interface HttpRule { * HTTP method unspecified for this rule. The wild-card rule is useful * for services that provide content to Web (HTML) clients. */ - 'custom'?: (_google_api_CustomHttpPattern); + 'custom'?: (_google_api_CustomHttpPattern | null); /** * Additional HTTP bindings for the selector. Nested bindings must * not contain an `additional_bindings` field themselves (that is, @@ -655,7 +655,7 @@ export interface HttpRule__Output { * HTTP method unspecified for this rule. The wild-card rule is useful * for services that provide content to Web (HTML) clients. */ - 'custom'?: (_google_api_CustomHttpPattern__Output); + 'custom'?: (_google_api_CustomHttpPattern__Output | null); /** * Additional HTTP bindings for the selector. Nested bindings must * not contain an `additional_bindings` field themselves (that is, diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts index 2aa9b8c71..2a4bbe1ee 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts @@ -20,7 +20,7 @@ export interface Operation { * Some services might not provide such metadata. Any method that returns a * long-running operation should document the metadata type, if any. */ - 'metadata'?: (_google_protobuf_Any); + 'metadata'?: (_google_protobuf_Any | null); /** * If the value is `false`, it means the operation is still in progress. * If `true`, the operation is completed, and either `error` or `response` is @@ -30,7 +30,7 @@ export interface Operation { /** * The error result of the operation in case of failure or cancellation. */ - 'error'?: (_google_rpc_Status); + 'error'?: (_google_rpc_Status | null); /** * The normal response of the operation in case of success. If the original * method returns no data on success, such as `Delete`, the response is @@ -41,7 +41,7 @@ export interface Operation { * is `TakeSnapshot()`, the inferred response type is * `TakeSnapshotResponse`. */ - 'response'?: (_google_protobuf_Any); + 'response'?: (_google_protobuf_Any | null); /** * The operation result, which can be either an `error` or a valid `response`. * If `done` == `false`, neither `error` nor `response` is set. @@ -67,7 +67,7 @@ export interface Operation__Output { * Some services might not provide such metadata. Any method that returns a * long-running operation should document the metadata type, if any. */ - 'metadata'?: (_google_protobuf_Any__Output); + 'metadata': (_google_protobuf_Any__Output | null); /** * If the value is `false`, it means the operation is still in progress. * If `true`, the operation is completed, and either `error` or `response` is @@ -77,7 +77,7 @@ export interface Operation__Output { /** * The error result of the operation in case of failure or cancellation. */ - 'error'?: (_google_rpc_Status__Output); + 'error'?: (_google_rpc_Status__Output | null); /** * The normal response of the operation in case of success. If the original * method returns no data on success, such as `Delete`, the response is @@ -88,7 +88,7 @@ export interface Operation__Output { * is `TakeSnapshot()`, the inferred response type is * `TakeSnapshotResponse`. */ - 'response'?: (_google_protobuf_Any__Output); + 'response'?: (_google_protobuf_Any__Output | null); /** * The operation result, which can be either an `error` or a valid `response`. * If `done` == `false`, neither `error` nor `response` is set. diff --git a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts index 2789ba33e..f97e39dc4 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts @@ -15,7 +15,7 @@ export interface WaitOperationRequest { * will be at most the time permitted by the underlying HTTP/RPC protocol. * If RPC context deadline is also specified, the shorter one will be used. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); } /** @@ -31,5 +31,5 @@ export interface WaitOperationRequest__Output { * will be at most the time permitted by the underlying HTTP/RPC protocol. * If RPC context deadline is also specified, the shorter one will be used. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts index 2f6f9f0cc..f729437f4 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts @@ -33,7 +33,7 @@ export interface DescriptorProto { 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; 'extensionRange'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'options'?: (_google_protobuf_MessageOptions); + 'options'?: (_google_protobuf_MessageOptions | null); 'oneofDecl'?: (_google_protobuf_OneofDescriptorProto)[]; 'reservedRange'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; 'reservedName'?: (string)[]; @@ -46,7 +46,7 @@ export interface DescriptorProto__Output { 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'extensionRange': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_MessageOptions__Output); + 'options': (_google_protobuf_MessageOptions__Output | null); 'oneofDecl': (_google_protobuf_OneofDescriptorProto__Output)[]; 'reservedRange': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; 'reservedName': (string)[]; diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts index 7aa40ce4d..dc4c9673e 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts @@ -6,11 +6,11 @@ import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output a export interface EnumDescriptorProto { 'name'?: (string); 'value'?: (_google_protobuf_EnumValueDescriptorProto)[]; - 'options'?: (_google_protobuf_EnumOptions); + 'options'?: (_google_protobuf_EnumOptions | null); } export interface EnumDescriptorProto__Output { 'name': (string); 'value': (_google_protobuf_EnumValueDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_EnumOptions__Output); + 'options': (_google_protobuf_EnumOptions__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts index 238e7fd01..7f8e57ea5 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts @@ -5,11 +5,11 @@ import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOp export interface EnumValueDescriptorProto { 'name'?: (string); 'number'?: (number); - 'options'?: (_google_protobuf_EnumValueOptions); + 'options'?: (_google_protobuf_EnumValueOptions | null); } export interface EnumValueDescriptorProto__Output { 'name': (string); 'number': (number); - 'options'?: (_google_protobuf_EnumValueOptions__Output); + 'options': (_google_protobuf_EnumValueOptions__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts index b59518c4b..c511e2eff 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts @@ -41,7 +41,7 @@ export interface FieldDescriptorProto { 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName'?: (string); 'defaultValue'?: (string); - 'options'?: (_google_protobuf_FieldOptions); + 'options'?: (_google_protobuf_FieldOptions | null); 'oneofIndex'?: (number); 'jsonName'?: (string); } @@ -54,7 +54,7 @@ export interface FieldDescriptorProto__Output { 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName': (string); 'defaultValue': (string); - 'options'?: (_google_protobuf_FieldOptions__Output); + 'options': (_google_protobuf_FieldOptions__Output | null); 'oneofIndex': (number); 'jsonName': (string); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts index 2954e4208..b723da7c0 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts @@ -15,8 +15,8 @@ export interface FileDescriptorProto { 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; 'service'?: (_google_protobuf_ServiceDescriptorProto)[]; 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'options'?: (_google_protobuf_FileOptions); - 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo); + 'options'?: (_google_protobuf_FileOptions | null); + 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo | null); 'publicDependency'?: (number)[]; 'weakDependency'?: (number)[]; 'syntax'?: (string); @@ -30,8 +30,8 @@ export interface FileDescriptorProto__Output { 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_FileOptions__Output); - 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo__Output); + 'options': (_google_protobuf_FileOptions__Output | null); + 'sourceCodeInfo': (_google_protobuf_SourceCodeInfo__Output | null); 'publicDependency': (number)[]; 'weakDependency': (number)[]; 'syntax': (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts index bc2f0afb5..c76c0ea23 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts @@ -6,7 +6,7 @@ export interface MethodDescriptorProto { 'name'?: (string); 'inputType'?: (string); 'outputType'?: (string); - 'options'?: (_google_protobuf_MethodOptions); + 'options'?: (_google_protobuf_MethodOptions | null); 'clientStreaming'?: (boolean); 'serverStreaming'?: (boolean); } @@ -15,7 +15,7 @@ export interface MethodDescriptorProto__Output { 'name': (string); 'inputType': (string); 'outputType': (string); - 'options'?: (_google_protobuf_MethodOptions__Output); + 'options': (_google_protobuf_MethodOptions__Output | null); 'clientStreaming': (boolean); 'serverStreaming': (boolean); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts index 495e22514..7581b9643 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts @@ -7,15 +7,15 @@ import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_ export interface MethodOptions { 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.google.longrunning.operation_info'?: (_google_longrunning_OperationInfo); + '.google.longrunning.operation_info'?: (_google_longrunning_OperationInfo | null); '.google.api.method_signature'?: (string)[]; - '.google.api.http'?: (_google_api_HttpRule); + '.google.api.http'?: (_google_api_HttpRule | null); } export interface MethodOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.google.longrunning.operation_info'?: (_google_longrunning_OperationInfo__Output); + '.google.longrunning.operation_info': (_google_longrunning_OperationInfo__Output | null); '.google.api.method_signature': (string)[]; - '.google.api.http'?: (_google_api_HttpRule__Output); + '.google.api.http': (_google_api_HttpRule__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts index c10ccecd3..636f13ed4 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts @@ -4,10 +4,10 @@ import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Outpu export interface OneofDescriptorProto { 'name'?: (string); - 'options'?: (_google_protobuf_OneofOptions); + 'options'?: (_google_protobuf_OneofOptions | null); } export interface OneofDescriptorProto__Output { 'name': (string); - 'options'?: (_google_protobuf_OneofOptions__Output); + 'options': (_google_protobuf_OneofOptions__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts index 695a8775c..40c9263ea 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts @@ -6,11 +6,11 @@ import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions_ export interface ServiceDescriptorProto { 'name'?: (string); 'method'?: (_google_protobuf_MethodDescriptorProto)[]; - 'options'?: (_google_protobuf_ServiceOptions); + 'options'?: (_google_protobuf_ServiceOptions | null); } export interface ServiceDescriptorProto__Output { 'name': (string); 'method': (_google_protobuf_MethodDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_ServiceOptions__Output); + 'options': (_google_protobuf_ServiceOptions__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts index 88c8010cd..383c409c5 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts @@ -11,16 +11,16 @@ export interface BlockRequest { /** * The amount of time to block before returning a response. */ - 'response_delay'?: (_google_protobuf_Duration); + 'response_delay'?: (_google_protobuf_Duration | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status); + 'error'?: (_google_rpc_Status | null); /** * The response to be returned that will signify successful method call. */ - 'success'?: (_google_showcase_v1beta1_BlockResponse); + 'success'?: (_google_showcase_v1beta1_BlockResponse | null); 'response'?: "error"|"success"; } @@ -31,15 +31,15 @@ export interface BlockRequest__Output { /** * The amount of time to block before returning a response. */ - 'response_delay'?: (_google_protobuf_Duration__Output); + 'response_delay': (_google_protobuf_Duration__Output | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status__Output); + 'error'?: (_google_rpc_Status__Output | null); /** * The response to be returned that will signify successful method call. */ - 'success'?: (_google_showcase_v1beta1_BlockResponse__Output); + 'success'?: (_google_showcase_v1beta1_BlockResponse__Output | null); 'response': "error"|"success"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts index 0cf79d84f..fb2bb67d3 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -17,7 +17,7 @@ export interface EchoRequest { /** * The error to be thrown by the server. */ - 'error'?: (_google_rpc_Status); + 'error'?: (_google_rpc_Status | null); /** * The severity to be echoed by the server. */ @@ -39,7 +39,7 @@ export interface EchoRequest__Output { /** * The error to be thrown by the server. */ - 'error'?: (_google_rpc_Status__Output); + 'error'?: (_google_rpc_Status__Output | null); /** * The severity to be echoed by the server. */ diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts index 00e7d05d2..33ce73c1f 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts @@ -13,7 +13,7 @@ export interface ExpandRequest { /** * The error that is thrown after all words are sent on the stream. */ - 'error'?: (_google_rpc_Status); + 'error'?: (_google_rpc_Status | null); } /** @@ -27,5 +27,5 @@ export interface ExpandRequest__Output { /** * The error that is thrown after all words are sent on the stream. */ - 'error'?: (_google_rpc_Status__Output); + 'error': (_google_rpc_Status__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts index 38b0a083f..5f17b4457 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts @@ -9,7 +9,7 @@ export interface WaitMetadata { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp); + 'end_time'?: (_google_protobuf_Timestamp | null); } /** @@ -19,5 +19,5 @@ export interface WaitMetadata__Output { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp__Output); + 'end_time': (_google_protobuf_Timestamp__Output | null); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts index eb2d2bc19..46c095b65 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts @@ -12,20 +12,20 @@ export interface WaitRequest { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp); + 'end_time'?: (_google_protobuf_Timestamp | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status); + 'error'?: (_google_rpc_Status | null); /** * The response to be returned on operation completion. */ - 'success'?: (_google_showcase_v1beta1_WaitResponse); + 'success'?: (_google_showcase_v1beta1_WaitResponse | null); /** * The duration of this operation. */ - 'ttl'?: (_google_protobuf_Duration); + 'ttl'?: (_google_protobuf_Duration | null); 'end'?: "end_time"|"ttl"; 'response'?: "error"|"success"; } @@ -37,20 +37,20 @@ export interface WaitRequest__Output { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp__Output); + 'end_time'?: (_google_protobuf_Timestamp__Output | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status__Output); + 'error'?: (_google_rpc_Status__Output | null); /** * The response to be returned on operation completion. */ - 'success'?: (_google_showcase_v1beta1_WaitResponse__Output); + 'success'?: (_google_showcase_v1beta1_WaitResponse__Output | null); /** * The duration of this operation. */ - 'ttl'?: (_google_protobuf_Duration__Output); + 'ttl'?: (_google_protobuf_Duration__Output | null); 'end': "end_time"|"ttl"; 'response': "error"|"success"; } From c3a49262cc3e6a3cf0144eb184dc154ebceaa752 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Apr 2021 12:56:50 -0700 Subject: [PATCH 1414/1899] proto-loader: generator: add specific service definition interfaces --- .../bin/proto-loader-gen-types.ts | 24 ++++++++++++++++--- .../proto-loader/golden-generated/echo.ts | 8 +++---- .../google/longrunning/Operations.ts | 9 +++++++ .../google/showcase/v1beta1/Echo.ts | 11 +++++++++ packages/proto-loader/src/index.ts | 6 ++--- 5 files changed, 48 insertions(+), 10 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index c11befee0..3e3a70503 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -126,7 +126,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv } else if (dependency instanceof Protobuf.Enum) { importedTypes = `${typeInterfaceName}`; } else if (dependency instanceof Protobuf.Service) { - importedTypes = `${typeInterfaceName}Client`; + importedTypes = `${typeInterfaceName}Client, ${typeInterfaceName}Definition`; } else { throw new Error('Invalid object passed to getImportLine'); } @@ -136,7 +136,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv } else if (dependency instanceof Protobuf.Enum) { importedTypes = `${dependency.name} as ${typeInterfaceName}`; } else if (dependency instanceof Protobuf.Service) { - importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client`; + importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client, ${dependency.name}Definition as ${typeInterfaceName}Definition`; } else { throw new Error('Invalid object passed to getImportLine'); } @@ -540,11 +540,25 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: formatter.writeLine('}'); } +function generateServiceDefinitionInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { + formatter.writeLine(`export interface ${serviceType.name}Definition {`); + formatter.indent(); + for (const methodName of Object.keys(serviceType.methods).sort()) { + const method = serviceType.methods[methodName]; + const requestType = getTypeInterfaceName(method.resolvedRequestType!); + const responseType = getTypeInterfaceName(method.resolvedResponseType!); + formatter.writeLine(`${methodName}: MethodDefinition<${requestType}, ${responseType}, ${requestType}__Output, ${responseType}__Output>`); + } + formatter.unindent(); + formatter.writeLine('}') +} + function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { formatter.writeLine(`// Original file: ${serviceType.filename}`); formatter.writeLine(''); const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; formatter.writeLine(`import type * as grpc from '${grpcImportPath}'`); + formatter.writeLine(`import type { MethodDefinition } from '@grpc/proto-loader'`) const dependencies: Set = new Set(); for (const method of serviceType.methodsArray) { dependencies.add(method.resolvedRequestType!); @@ -559,6 +573,9 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob formatter.writeLine(''); generateServiceHandlerInterface(formatter, serviceType, options); + formatter.writeLine(''); + + generateServiceDefinitionInterface(formatter, serviceType); } function generateServiceImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { @@ -576,7 +593,8 @@ function generateSingleLoadedDefinitionType(formatter: TextFormatter, nested: Pr if (options.includeComments) { formatComment(formatter, nested.comment); } - formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ServiceDefinition }`) + const typeInterfaceName = getTypeInterfaceName(nested); + formatter.writeLine(`${nested.name}: SubtypeConstructor & { service: ${typeInterfaceName}Definition }`); } else if (nested instanceof Protobuf.Enum) { formatter.writeLine(`${nested.name}: EnumTypeDefinition`); } else if (nested instanceof Protobuf.Type) { diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index 02514f053..f257a40e4 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import type { OperationsClient as _google_longrunning_OperationsClient } from './google/longrunning/Operations'; -import type { EchoClient as _google_showcase_v1beta1_EchoClient } from './google/showcase/v1beta1/Echo'; +import type { OperationsClient as _google_longrunning_OperationsClient, OperationsDefinition as _google_longrunning_OperationsDefinition } from './google/longrunning/Operations'; +import type { EchoClient as _google_showcase_v1beta1_EchoClient, EchoDefinition as _google_showcase_v1beta1_EchoDefinition } from './google/showcase/v1beta1/Echo'; type SubtypeConstructor any, Subtype> = { new(...args: ConstructorParameters): Subtype; @@ -35,7 +35,7 @@ export interface ProtoGrpcType { * returns long-running operations should implement the `Operations` interface * so developers can have a consistent client experience. */ - Operations: SubtypeConstructor & { service: ServiceDefinition } + Operations: SubtypeConstructor & { service: _google_longrunning_OperationsDefinition } WaitOperationRequest: MessageTypeDefinition } protobuf: { @@ -78,7 +78,7 @@ export interface ProtoGrpcType { * paginated calls. Set the 'showcase-trailer' metadata key on any method * to have the values echoed in the response trailers. */ - Echo: SubtypeConstructor & { service: ServiceDefinition } + Echo: SubtypeConstructor & { service: _google_showcase_v1beta1_EchoDefinition } EchoRequest: MessageTypeDefinition EchoResponse: MessageTypeDefinition ExpandRequest: MessageTypeDefinition diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 6aa477ada..8e5684ada 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -1,6 +1,7 @@ // Original file: deps/googleapis/google/longrunning/operations.proto import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' import type { CancelOperationRequest as _google_longrunning_CancelOperationRequest, CancelOperationRequest__Output as _google_longrunning_CancelOperationRequest__Output } from '../../google/longrunning/CancelOperationRequest'; import type { DeleteOperationRequest as _google_longrunning_DeleteOperationRequest, DeleteOperationRequest__Output as _google_longrunning_DeleteOperationRequest__Output } from '../../google/longrunning/DeleteOperationRequest'; import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../google/protobuf/Empty'; @@ -230,3 +231,11 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { WaitOperation: grpc.handleUnaryCall<_google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation>; } + +export interface OperationsDefinition { + CancelOperation: MethodDefinition<_google_longrunning_CancelOperationRequest, _google_protobuf_Empty, _google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty__Output> + DeleteOperation: MethodDefinition<_google_longrunning_DeleteOperationRequest, _google_protobuf_Empty, _google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty__Output> + GetOperation: MethodDefinition<_google_longrunning_GetOperationRequest, _google_longrunning_Operation, _google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation__Output> + ListOperations: MethodDefinition<_google_longrunning_ListOperationsRequest, _google_longrunning_ListOperationsResponse, _google_longrunning_ListOperationsRequest__Output, _google_longrunning_ListOperationsResponse__Output> + WaitOperation: MethodDefinition<_google_longrunning_WaitOperationRequest, _google_longrunning_Operation, _google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation__Output> +} diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index 33fe373a8..acb911270 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -1,6 +1,7 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' import type { BlockRequest as _google_showcase_v1beta1_BlockRequest, BlockRequest__Output as _google_showcase_v1beta1_BlockRequest__Output } from '../../../google/showcase/v1beta1/BlockRequest'; import type { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; import type { EchoRequest as _google_showcase_v1beta1_EchoRequest, EchoRequest__Output as _google_showcase_v1beta1_EchoRequest__Output } from '../../../google/showcase/v1beta1/EchoRequest'; @@ -189,3 +190,13 @@ export interface EchoHandlers extends grpc.UntypedServiceImplementation { Wait: grpc.handleUnaryCall<_google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation>; } + +export interface EchoDefinition { + Block: MethodDefinition<_google_showcase_v1beta1_BlockRequest, _google_showcase_v1beta1_BlockResponse, _google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse__Output> + Chat: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> + Collect: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> + Echo: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> + Expand: MethodDefinition<_google_showcase_v1beta1_ExpandRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_ExpandRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> + PagedExpand: MethodDefinition<_google_showcase_v1beta1_PagedExpandRequest, _google_showcase_v1beta1_PagedExpandResponse, _google_showcase_v1beta1_PagedExpandRequest__Output, _google_showcase_v1beta1_PagedExpandResponse__Output> + Wait: MethodDefinition<_google_showcase_v1beta1_WaitRequest, _google_longrunning_Operation, _google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation__Output> +} diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 6f76956a9..98ca97b51 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -115,14 +115,14 @@ export interface EnumTypeDefinition extends ProtobufTypeDefinition { format: 'Protocol Buffer 3 EnumDescriptorProto'; } -export interface MethodDefinition { +export interface MethodDefinition { path: string; requestStream: boolean; responseStream: boolean; requestSerialize: Serialize; responseSerialize: Serialize; - requestDeserialize: Deserialize; - responseDeserialize: Deserialize; + requestDeserialize: Deserialize; + responseDeserialize: Deserialize; originalName?: string; requestType: MessageTypeDefinition; responseType: MessageTypeDefinition; From e7dccd6656c7d9096f49b85f62187f6305fd3416 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Apr 2021 13:00:04 -0700 Subject: [PATCH 1415/1899] proto-loader: Bump version to 0.6.1 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index cfc767a9b..ee49abc40 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.0", + "version": "0.6.1", "author": "Google Inc.", "contributors": [ { From f3b6eb1c85b59022a3760f57a376ffd97c06edce Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 14 Apr 2021 14:00:16 -0700 Subject: [PATCH 1416/1899] grpc-js-xds: Update deps and generated code for xDS v3 --- packages/grpc-js-xds/deps/envoy-api | 2 +- packages/grpc-js-xds/deps/udpa | 2 +- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/generated/ads.ts | 63 + packages/grpc-js-xds/src/generated/cluster.ts | 89 +- .../grpc-js-xds/src/generated/endpoint.ts | 49 +- .../envoy/api/v2/UpstreamConnectionOptions.ts | 17 - .../src/generated/envoy/api/v2/Vhds.ts | 17 - .../v2/auth/CertificateValidationContext.ts | 315 ----- .../envoy/api/v2/auth/CommonTlsContext.ts | 140 --- .../envoy/api/v2/auth/DownstreamTlsContext.ts | 101 -- .../envoy/api/v2/auth/GenericSecret.ts | 17 - .../envoy/api/v2/auth/PrivateKeyProvider.ts | 42 - .../envoy/api/v2/auth/SdsSecretConfig.ts | 23 - .../src/generated/envoy/api/v2/auth/Secret.ts | 36 - .../envoy/api/v2/auth/TlsCertificate.ts | 78 -- .../envoy/api/v2/auth/TlsParameters.ts | 171 --- .../envoy/api/v2/auth/TlsSessionTicketKeys.ts | 61 - .../envoy/api/v2/auth/UpstreamTlsContext.ts | 68 -- .../envoy/api/v2/core/BuildVersion.ts | 4 +- .../envoy/api/v2/core/GrpcProtocolOptions.ts | 17 - .../envoy/api/v2/core/RuntimeDouble.ts | 2 +- .../envoy/api/v2/core/SelfConfigSource.ts | 20 - .../v2/endpoint/EndpointLoadMetricStats.ts | 2 +- .../generated/envoy/api/v2/listener/Filter.ts | 34 - .../envoy/api/v2/listener/FilterChain.ts | 118 -- .../envoy/api/v2/route/HedgePolicy.ts | 66 -- .../api/v2/route/QueryParameterMatcher.ts | 86 -- .../generated/envoy/api/v2/route/RateLimit.ts | 341 ------ .../envoy/api/v2/route/RedirectAction.ts | 139 --- .../envoy/api/v2/route/RetryPolicy.ts | 218 ---- .../v2 => accesslog/v3}/AccessLog.ts | 37 +- .../config/accesslog/v3/AccessLogFilter.ts | 124 ++ .../v2 => accesslog/v3}/AndFilter.ts | 8 +- .../config/accesslog/v3/ComparisonFilter.ts | 48 + .../config/accesslog/v3/DurationFilter.ts | 23 + .../v2 => accesslog/v3}/ExtensionFilter.ts | 11 +- .../v2 => accesslog/v3}/GrpcStatusFilter.ts | 28 +- .../envoy/config/accesslog/v3/HeaderFilter.ts | 25 + .../config/accesslog/v3/MetadataFilter.ts | 48 + .../v3}/NotHealthCheckFilter.ts | 2 +- .../accesslog/v2 => accesslog/v3}/OrFilter.ts | 8 +- .../v2 => accesslog/v3}/ResponseFlagFilter.ts | 20 +- .../config/accesslog/v3/RuntimeFilter.ts | 73 ++ .../config/accesslog/v3/StatusCodeFilter.ts | 23 + .../v2 => accesslog/v3}/TraceableFilter.ts | 2 +- .../cluster/v3}/CircuitBreakers.ts | 50 +- .../{api/v2 => config/cluster/v3}/Cluster.ts | 1043 +++++++++++------ .../config/cluster/v3/ClusterCollection.ts | 19 + .../cluster => config/cluster/v3}/Filter.ts | 2 +- .../cluster/v3}/LoadBalancingPolicy.ts | 23 +- .../cluster/v3}/OutlierDetection.ts | 48 +- .../config/cluster/v3/TrackClusterStats.ts | 36 + .../cluster/v3}/UpstreamBindConfig.ts | 8 +- .../cluster/v3/UpstreamConnectionOptions.ts | 17 + .../generated/envoy/config/core/v3/Address.ts | 35 + .../core/v3}/AggregatedConfigSource.ts | 6 +- .../core/v3}/ApiConfigSource.ts | 44 +- .../v2/core => config/core/v3}/ApiVersion.ts | 4 +- .../envoy/config/core/v3/AsyncDataSource.ts | 34 + .../envoy/config/core/v3/BackoffStrategy.ts | 43 + .../envoy/config/core/v3/BindConfig.ts | 49 + .../envoy/config/core/v3/BuildVersion.ts | 36 + .../envoy/config/core/v3/CidrRange.ts | 33 + .../core => config/core/v3}/ConfigSource.ts | 53 +- .../envoy/config/core/v3/ControlPlane.ts | 26 + .../envoy/config/core/v3/DataSource.ts | 40 + .../config/core/v3/EnvoyInternalAddress.ts | 28 + .../core/v3}/EventServiceConfig.ts | 8 +- .../envoy/config/core/v3/Extension.ts | 75 ++ .../config/core/v3/ExtensionConfigSource.ts | 72 ++ .../config/core/v3/GrpcProtocolOptions.ts | 17 + .../v2/core => config/core/v3}/GrpcService.ts | 213 ++-- .../envoy/config/core/v3/HeaderMap.ts | 17 + .../envoy/config/core/v3/HeaderValue.ts | 38 + .../envoy/config/core/v3/HeaderValueOption.ts | 34 + .../v2/core => config/core/v3}/HealthCheck.ts | 258 ++-- .../core => config/core/v3}/HealthStatus.ts | 2 +- .../core/v3}/Http1ProtocolOptions.ts | 62 +- .../core/v3}/Http2ProtocolOptions.ts | 128 +- .../config/core/v3/Http3ProtocolOptions.ts | 22 + .../core/v3}/HttpProtocolOptions.ts | 26 +- .../generated/envoy/config/core/v3/HttpUri.ts | 79 ++ .../envoy/config/core/v3/KeepaliveSettings.ts | 40 + .../envoy/config/core/v3/Locality.ts | 56 + .../envoy/config/core/v3/Metadata.ts | 67 ++ .../generated/envoy/config/core/v3/Node.ts | 159 +++ .../generated/envoy/config/core/v3/Pipe.ts | 30 + .../config/core/v3/ProxyProtocolConfig.ts | 29 + .../core/v3}/RateLimitSettings.ts | 2 +- .../envoy/config/core/v3/RemoteDataSource.ts | 40 + .../envoy/config/core/v3/RequestMethod.ts | 17 + .../envoy/config/core/v3/RetryPolicy.ts | 38 + .../envoy/config/core/v3/RoutingPriority.ts | 15 + .../envoy/config/core/v3/RuntimeDouble.ts | 30 + .../config/core/v3/RuntimeFeatureFlag.ts | 35 + .../core/v3/RuntimeFractionalPercent.ts | 49 + .../envoy/config/core/v3/RuntimePercent.ts | 31 + .../envoy/config/core/v3/RuntimeUInt32.ts | 30 + .../envoy/config/core/v3/SelfConfigSource.ts | 31 + .../envoy/config/core/v3/SocketAddress.ts | 97 ++ .../envoy/config/core/v3/SocketOption.ts | 90 ++ .../core/v3/SubstitutionFormatString.ts | 197 ++++ .../envoy/config/core/v3/TcpKeepalive.ts | 43 + .../core/v3}/TcpProtocolOptions.ts | 2 +- .../envoy/config/core/v3/TrafficDirection.ts | 19 + .../envoy/config/core/v3/TransportSocket.ts | 43 + .../config/core/v3/TypedExtensionConfig.ts | 43 + .../core/v3}/UpstreamHttpProtocolOptions.ts | 2 +- .../envoy/config/core/v3/WatchedDirectory.ts | 24 + .../endpoint/v3}/ClusterLoadAssignment.ts | 74 +- .../envoy/config/endpoint/v3/ClusterStats.ts | 115 ++ .../endpoint/v3}/Endpoint.ts | 32 +- .../endpoint/v3/EndpointLoadMetricStats.ts | 35 + .../endpoint/v3}/LbEndpoint.ts | 24 +- .../endpoint/v3}/LocalityLbEndpoints.ts | 14 +- .../endpoint/v3/UpstreamEndpointStats.ts | 104 ++ .../endpoint/v3/UpstreamLocalityStats.ts | 104 ++ .../filter/accesslog/v2/AccessLogFilter.ts | 115 -- .../filter/accesslog/v2/ComparisonFilter.ts | 48 - .../filter/accesslog/v2/DurationFilter.ts | 23 - .../filter/accesslog/v2/HeaderFilter.ts | 25 - .../filter/accesslog/v2/RuntimeFilter.ts | 63 - .../filter/accesslog/v2/StatusCodeFilter.ts | 23 - .../http_connection_manager/v2/HttpFilter.ts | 34 - .../http_connection_manager/v2/ScopedRds.ts | 17 - .../v2/ScopedRouteConfigurationsList.ts | 17 - .../v3}/ActiveRawUdpListenerConfig.ts | 2 +- .../config/listener/{v2 => v3}/ApiListener.ts | 2 +- .../envoy/config/listener/v3/Filter.ts | 52 + .../envoy/config/listener/v3/FilterChain.ts | 170 +++ .../listener/v3}/FilterChainMatch.ts | 46 +- .../v2 => config/listener/v3}/Listener.ts | 231 ++-- .../config/listener/v3/ListenerCollection.ts | 19 + .../listener/v3}/ListenerFilter.ts | 19 +- .../v3}/ListenerFilterChainMatchPredicate.ts | 30 +- .../listener/v3}/UdpListenerConfig.ts | 9 +- .../route => config/route/v3}/CorsPolicy.ts | 86 +- .../v2/route => config/route/v3}/Decorator.ts | 2 +- .../route/v3}/DirectResponseAction.ts | 16 +- .../route => config/route/v3}/FilterAction.ts | 2 +- .../envoy/config/route/v3/FilterConfig.ts | 47 + .../route/v3}/HeaderMatcher.ts | 84 +- .../envoy/config/route/v3/HedgePolicy.ts | 76 ++ .../config/route/v3/InternalRedirectPolicy.ts | 72 ++ .../config/route/v3/QueryParameterMatcher.ts | 47 + .../envoy/config/route/v3/RateLimit.ts | 578 +++++++++ .../envoy/config/route/v3/RedirectAction.ts | 222 ++++ .../envoy/config/route/v3/RetryPolicy.ts | 392 +++++++ .../v2/route => config/route/v3}/Route.ts | 107 +- .../route => config/route/v3}/RouteAction.ts | 479 +++++--- .../route/v3}/RouteConfiguration.ts | 89 +- .../route => config/route/v3}/RouteMatch.ts | 128 +- .../route/v3}/ScopedRouteConfiguration.ts | 58 +- .../v2/route => config/route/v3}/Tracing.ts | 26 +- .../generated/envoy/config/route/v3/Vhds.ts | 17 + .../route/v3}/VirtualCluster.ts | 57 +- .../route => config/route/v3}/VirtualHost.ts | 107 +- .../route/v3}/WeightedCluster.ts | 97 +- .../envoy/config/trace/{v2 => v3}/Tracing.ts | 53 +- .../v3}/HttpConnectionManager.ts | 395 ++++--- .../http_connection_manager/v3/HttpFilter.ts | 66 ++ .../v3/LocalReplyConfig.ts | 106 ++ .../http_connection_manager/v3}/Rds.ts | 8 +- .../v3}/RequestIDExtension.ts | 2 +- .../v3/ResponseMapper.ts | 67 ++ .../http_connection_manager/v3/ScopedRds.ts | 17 + .../v3/ScopedRouteConfigurationsList.ts | 17 + .../v3}/ScopedRoutes.ts | 88 +- .../envoy/service/discovery/v3/AdsDummy.ts | 16 + .../v3/AggregatedDiscoveryService.ts | 52 + .../discovery/v3/DeltaDiscoveryRequest.ts | 206 ++++ .../discovery/v3/DeltaDiscoveryResponse.ts | 74 ++ .../service/discovery/v3/DiscoveryRequest.ts | 110 ++ .../service/discovery/v3/DiscoveryResponse.ts | 106 ++ .../envoy/service/discovery/v3/Resource.ts | 118 ++ .../load_stats/v3/LoadReportingService.ts | 108 ++ .../service/load_stats/v3/LoadStatsRequest.ts | 32 + .../load_stats/v3/LoadStatsResponse.ts | 71 ++ .../src/generated/envoy/type/Percent.ts | 2 +- .../envoy/type/matcher/ListStringMatcher.ts | 17 - .../envoy/type/matcher/v3/DoubleMatcher.ts | 35 + .../envoy/type/matcher/v3/ListMatcher.ts | 25 + .../type/matcher/v3/ListStringMatcher.ts | 17 + .../envoy/type/matcher/v3/MetadataMatcher.ts | 65 + .../{ => v3}/RegexMatchAndSubstitute.ts | 8 +- .../type/matcher/{ => v3}/RegexMatcher.ts | 32 +- .../type/matcher/{ => v3}/StringMatcher.ts | 66 +- .../envoy/type/matcher/v3/ValueMatcher.ts | 101 ++ .../envoy/type/metadata/v2/MetadataKind.ts | 98 -- .../type/metadata/{v2 => v3}/MetadataKey.ts | 14 +- .../envoy/type/metadata/v3/MetadataKind.ts | 98 ++ .../type/tracing/{v2 => v3}/CustomTag.ts | 54 +- .../envoy/type/{ => v3}/CodecClientType.ts | 2 +- .../envoy/type/{ => v3}/DoubleRange.ts | 6 +- .../envoy/type/v3/FractionalPercent.ts | 68 ++ .../envoy/type/{ => v3}/Int32Range.ts | 2 +- .../envoy/type/{ => v3}/Int64Range.ts | 2 +- .../src/generated/envoy/type/v3/Percent.ts | 16 + .../envoy/type/v3/SemanticVersion.ts | 24 + .../generated/google/api/CustomHttpPattern.ts | 30 - .../src/generated/google/api/Http.ts | 49 - .../src/generated/google/api/HttpRule.ts | 680 ----------- .../src/generated/google/protobuf/Any.ts | 6 +- .../generated/google/protobuf/DoubleValue.ts | 2 +- .../generated/google/protobuf/FieldOptions.ts | 3 + .../generated/google/protobuf/FloatValue.ts | 2 +- .../google/protobuf/MessageOptions.ts | 3 + .../google/protobuf/UninterpretedOption.ts | 2 +- .../src/generated/google/protobuf/Value.ts | 2 +- .../src/generated/http_connection_manager.ts | 123 +- .../grpc-js-xds/src/generated/listener.ts | 132 ++- packages/grpc-js-xds/src/generated/lrs.ts | 59 + packages/grpc-js-xds/src/generated/route.ts | 58 +- .../annotations/FieldSecurityAnnotation.ts | 32 + .../udpa/annotations/VersioningAnnotation.ts | 20 + .../src/generated/validate/DoubleRules.ts | 14 +- .../src/generated/validate/FloatRules.ts | 14 +- .../src/generated/xds/core/v3/Authority.ts | 16 + .../generated/xds/core/v3/CollectionEntry.ts | 90 ++ .../generated/xds/core/v3/ContextParams.ts | 26 + .../generated/xds/core/v3/ResourceLocator.ts | 220 ++++ 222 files changed, 9580 insertions(+), 5510 deletions(-) delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/AccessLog.ts (54%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/AndFilter.ts (51%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/ExtensionFilter.ts (64%) rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/GrpcStatusFilter.ts (51%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/NotHealthCheckFilter.ts (81%) rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/OrFilter.ts (50%) rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/ResponseFlagFilter.ts (51%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts rename packages/grpc-js-xds/src/generated/envoy/config/{filter/accesslog/v2 => accesslog/v3}/TraceableFilter.ts (81%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/cluster => config/cluster/v3}/CircuitBreakers.ts (75%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/cluster/v3}/Cluster.ts (50%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/cluster => config/cluster/v3}/Filter.ts (92%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/cluster/v3}/LoadBalancingPolicy.ts (80%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/cluster => config/cluster/v3}/OutlierDetection.ts (85%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/TrackClusterStats.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/cluster/v3}/UpstreamBindConfig.ts (59%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/AggregatedConfigSource.ts (57%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/ApiConfigSource.ts (66%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/ApiVersion.ts (69%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/ConfigSource.ts (70%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/ControlPlane.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/DataSource.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/EventServiceConfig.ts (58%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/GrpcService.ts (59%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderMap.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValue.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/HealthCheck.ts (67%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/HealthStatus.ts (91%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/Http1ProtocolOptions.ts (57%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/Http2ProtocolOptions.ts (65%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/HttpProtocolOptions.ts (75%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/Pipe.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/ProxyProtocolConfig.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/RateLimitSettings.ts (94%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RequestMethod.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RoutingPriority.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeDouble.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeUInt32.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketOption.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/TcpProtocolOptions.ts (70%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/TrafficDirection.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/core => config/core/v3}/UpstreamHttpProtocolOptions.ts (95%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/WatchedDirectory.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/endpoint/v3}/ClusterLoadAssignment.ts (67%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/endpoint => config/endpoint/v3}/Endpoint.ts (69%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/EndpointLoadMetricStats.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/endpoint => config/endpoint/v3}/LbEndpoint.ts (74%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/endpoint => config/endpoint/v3}/LocalityLbEndpoints.ts (87%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/listener => config/listener/v3}/ActiveRawUdpListenerConfig.ts (56%) rename packages/grpc-js-xds/src/generated/envoy/config/listener/{v2 => v3}/ApiListener.ts (96%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/listener => config/listener/v3}/FilterChainMatch.ts (81%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/listener/v3}/Listener.ts (66%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerCollection.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/listener => config/listener/v3}/ListenerFilter.ts (58%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/listener => config/listener/v3}/ListenerFilterChainMatchPredicate.ts (66%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/listener => config/listener/v3}/UdpListenerConfig.ts (72%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/CorsPolicy.ts (50%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/Decorator.ts (94%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/DirectResponseAction.ts (52%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/FilterAction.ts (82%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/HeaderMatcher.ts (69%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/Route.ts (58%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/RouteAction.ts (62%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/route/v3}/RouteConfiguration.ts (63%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/RouteMatch.ts (67%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2 => config/route/v3}/ScopedRouteConfiguration.ts (59%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/Tracing.ts (75%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/VirtualCluster.ts (58%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/VirtualHost.ts (71%) rename packages/grpc-js-xds/src/generated/envoy/{api/v2/route => config/route/v3}/WeightedCluster.ts (64%) rename packages/grpc-js-xds/src/generated/envoy/config/trace/{v2 => v3}/Tracing.ts (54%) rename packages/grpc-js-xds/src/generated/envoy/{config/filter/network/http_connection_manager/v2 => extensions/filters/network/http_connection_manager/v3}/HttpConnectionManager.ts (64%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts rename packages/grpc-js-xds/src/generated/envoy/{config/filter/network/http_connection_manager/v2 => extensions/filters/network/http_connection_manager/v3}/Rds.ts (63%) rename packages/grpc-js-xds/src/generated/envoy/{config/filter/network/http_connection_manager/v2 => extensions/filters/network/http_connection_manager/v3}/RequestIDExtension.ts (78%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRouteConfigurationsList.ts rename packages/grpc-js-xds/src/generated/envoy/{config/filter/network/http_connection_manager/v2 => extensions/filters/network/http_connection_manager/v3}/ScopedRoutes.ts (57%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AdsDummy.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListStringMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts rename packages/grpc-js-xds/src/generated/envoy/type/matcher/{ => v3}/RegexMatchAndSubstitute.ts (89%) rename packages/grpc-js-xds/src/generated/envoy/type/matcher/{ => v3}/RegexMatcher.ts (57%) rename packages/grpc-js-xds/src/generated/envoy/type/matcher/{ => v3}/StringMatcher.ts (58%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts rename packages/grpc-js-xds/src/generated/envoy/type/metadata/{v2 => v3}/MetadataKey.ts (85%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts rename packages/grpc-js-xds/src/generated/envoy/type/tracing/{v2 => v3}/CustomTag.ts (66%) rename packages/grpc-js-xds/src/generated/envoy/type/{ => v3}/CodecClientType.ts (84%) rename packages/grpc-js-xds/src/generated/envoy/type/{ => v3}/DoubleRange.ts (82%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/v3/FractionalPercent.ts rename packages/grpc-js-xds/src/generated/envoy/type/{ => v3}/Int32Range.ts (90%) rename packages/grpc-js-xds/src/generated/envoy/type/{ => v3}/Int64Range.ts (91%) create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/v3/Percent.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/v3/SemanticVersion.ts delete mode 100644 packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts delete mode 100644 packages/grpc-js-xds/src/generated/google/api/Http.ts delete mode 100644 packages/grpc-js-xds/src/generated/google/api/HttpRule.ts create mode 100644 packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts create mode 100644 packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts diff --git a/packages/grpc-js-xds/deps/envoy-api b/packages/grpc-js-xds/deps/envoy-api index 50cef8fca..18b54850c 160000 --- a/packages/grpc-js-xds/deps/envoy-api +++ b/packages/grpc-js-xds/deps/envoy-api @@ -1 +1 @@ -Subproject commit 50cef8fcab37ba59a61068934d08a3f4c28a681f +Subproject commit 18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2 diff --git a/packages/grpc-js-xds/deps/udpa b/packages/grpc-js-xds/deps/udpa index 3b31d022a..cc1b757b3 160000 --- a/packages/grpc-js-xds/deps/udpa +++ b/packages/grpc-js-xds/deps/udpa @@ -1 +1 @@ -Subproject commit 3b31d022a144b334eb2224838e4d6952ab5253aa +Subproject commit cc1b757b3eddccaaaf0743cbb107742bb7e3ee4f diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 3f90c7e97..f69c8bf49 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/api/v2/listener.proto envoy/api/v2/route.proto envoy/api/v2/cluster.proto envoy/api/v2/endpoint.proto envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { diff --git a/packages/grpc-js-xds/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts index 0eacd1e34..665374958 100644 --- a/packages/grpc-js-xds/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -2,6 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; +import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v3_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v3/AggregatedDiscoveryService'; type SubtypeConstructor any, Subtype> = { new(...args: ConstructorParameters): Subtype; @@ -50,6 +51,45 @@ export interface ProtoGrpcType { } } } + config: { + core: { + v3: { + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition + Extension: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition + } + } + } service: { discovery: { v2: { @@ -64,12 +104,34 @@ export interface ProtoGrpcType { */ AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } } + v3: { + AdsDummy: MessageTypeDefinition + /** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ + AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } + DeltaDiscoveryRequest: MessageTypeDefinition + DeltaDiscoveryResponse: MessageTypeDefinition + DiscoveryRequest: MessageTypeDefinition + DiscoveryResponse: MessageTypeDefinition + Resource: MessageTypeDefinition + } } } type: { FractionalPercent: MessageTypeDefinition Percent: MessageTypeDefinition SemanticVersion: MessageTypeDefinition + v3: { + FractionalPercent: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } } } google: { @@ -122,6 +184,7 @@ export interface ProtoGrpcType { MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { diff --git a/packages/grpc-js-xds/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts index b7005a3f0..5e4683580 100644 --- a/packages/grpc-js-xds/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -10,32 +10,22 @@ export interface ProtoGrpcType { envoy: { annotations: { } - api: { - v2: { - Cluster: MessageTypeDefinition - ClusterLoadAssignment: MessageTypeDefinition - LoadBalancingPolicy: MessageTypeDefinition - UpstreamBindConfig: MessageTypeDefinition - UpstreamConnectionOptions: MessageTypeDefinition - auth: { - CertificateValidationContext: MessageTypeDefinition - CommonTlsContext: MessageTypeDefinition - DownstreamTlsContext: MessageTypeDefinition - GenericSecret: MessageTypeDefinition - PrivateKeyProvider: MessageTypeDefinition - SdsSecretConfig: MessageTypeDefinition - Secret: MessageTypeDefinition - TlsCertificate: MessageTypeDefinition - TlsParameters: MessageTypeDefinition - TlsSessionTicketKeys: MessageTypeDefinition - UpstreamTlsContext: MessageTypeDefinition - } - cluster: { + config: { + cluster: { + v3: { CircuitBreakers: MessageTypeDefinition + Cluster: MessageTypeDefinition + ClusterCollection: MessageTypeDefinition Filter: MessageTypeDefinition + LoadBalancingPolicy: MessageTypeDefinition OutlierDetection: MessageTypeDefinition + TrackClusterStats: MessageTypeDefinition + UpstreamBindConfig: MessageTypeDefinition + UpstreamConnectionOptions: MessageTypeDefinition } - core: { + } + core: { + v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition @@ -48,8 +38,10 @@ export interface ProtoGrpcType { ConfigSource: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition EventServiceConfig: MessageTypeDefinition Extension: MessageTypeDefinition + ExtensionConfigSource: MessageTypeDefinition GrpcProtocolOptions: MessageTypeDefinition GrpcService: MessageTypeDefinition HeaderMap: MessageTypeDefinition @@ -59,8 +51,10 @@ export interface ProtoGrpcType { HealthStatus: EnumTypeDefinition Http1ProtocolOptions: MessageTypeDefinition Http2ProtocolOptions: MessageTypeDefinition + Http3ProtocolOptions: MessageTypeDefinition HttpProtocolOptions: MessageTypeDefinition HttpUri: MessageTypeDefinition + KeepaliveSettings: MessageTypeDefinition Locality: MessageTypeDefinition Metadata: MessageTypeDefinition Node: MessageTypeDefinition @@ -73,6 +67,7 @@ export interface ProtoGrpcType { RuntimeDouble: MessageTypeDefinition RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition @@ -81,9 +76,14 @@ export interface ProtoGrpcType { TcpProtocolOptions: MessageTypeDefinition TrafficDirection: EnumTypeDefinition TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition UpstreamHttpProtocolOptions: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition } - endpoint: { + } + endpoint: { + v3: { + ClusterLoadAssignment: MessageTypeDefinition Endpoint: MessageTypeDefinition LbEndpoint: MessageTypeDefinition LocalityLbEndpoints: MessageTypeDefinition @@ -91,27 +91,26 @@ export interface ProtoGrpcType { } } type: { - CodecClientType: EnumTypeDefinition - DoubleRange: MessageTypeDefinition - FractionalPercent: MessageTypeDefinition - Int32Range: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition matcher: { - ListStringMatcher: MessageTypeDefinition - RegexMatchAndSubstitute: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition - StringMatcher: MessageTypeDefinition + v3: { + ListStringMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } + } + v3: { + CodecClientType: EnumTypeDefinition + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition } } } google: { - api: { - CustomHttpPattern: MessageTypeDefinition - Http: MessageTypeDefinition - HttpRule: MessageTypeDefinition - } protobuf: { Any: MessageTypeDefinition BoolValue: MessageTypeDefinition @@ -155,10 +154,12 @@ export interface ProtoGrpcType { udpa: { annotations: { FieldMigrateAnnotation: MessageTypeDefinition + FieldSecurityAnnotation: MessageTypeDefinition FileMigrateAnnotation: MessageTypeDefinition MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { @@ -187,5 +188,15 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + core: { + v3: { + Authority: MessageTypeDefinition + CollectionEntry: MessageTypeDefinition + ContextParams: MessageTypeDefinition + ResourceLocator: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/endpoint.ts b/packages/grpc-js-xds/src/generated/endpoint.ts index 33d5872ef..dda6a78da 100644 --- a/packages/grpc-js-xds/src/generated/endpoint.ts +++ b/packages/grpc-js-xds/src/generated/endpoint.ts @@ -8,12 +8,9 @@ type SubtypeConstructor any, Subtype> export interface ProtoGrpcType { envoy: { - annotations: { - } - api: { - v2: { - ClusterLoadAssignment: MessageTypeDefinition - core: { + config: { + core: { + v3: { Address: MessageTypeDefinition AsyncDataSource: MessageTypeDefinition BackoffStrategy: MessageTypeDefinition @@ -22,6 +19,7 @@ export interface ProtoGrpcType { CidrRange: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition EventServiceConfig: MessageTypeDefinition Extension: MessageTypeDefinition GrpcService: MessageTypeDefinition @@ -42,14 +40,19 @@ export interface ProtoGrpcType { RuntimeDouble: MessageTypeDefinition RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition TrafficDirection: EnumTypeDefinition TransportSocket: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition } - endpoint: { + } + endpoint: { + v3: { + ClusterLoadAssignment: MessageTypeDefinition Endpoint: MessageTypeDefinition LbEndpoint: MessageTypeDefinition LocalityLbEndpoints: MessageTypeDefinition @@ -57,27 +60,26 @@ export interface ProtoGrpcType { } } type: { - CodecClientType: EnumTypeDefinition - DoubleRange: MessageTypeDefinition - FractionalPercent: MessageTypeDefinition - Int32Range: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition matcher: { - ListStringMatcher: MessageTypeDefinition - RegexMatchAndSubstitute: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition - StringMatcher: MessageTypeDefinition + v3: { + ListStringMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } + } + v3: { + CodecClientType: EnumTypeDefinition + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition } } } google: { - api: { - CustomHttpPattern: MessageTypeDefinition - Http: MessageTypeDefinition - HttpRule: MessageTypeDefinition - } protobuf: { Any: MessageTypeDefinition BoolValue: MessageTypeDefinition @@ -125,6 +127,7 @@ export interface ProtoGrpcType { MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts deleted file mode 100644 index e46a2cd06..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamConnectionOptions.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto - -import type { TcpKeepalive as _envoy_api_v2_core_TcpKeepalive, TcpKeepalive__Output as _envoy_api_v2_core_TcpKeepalive__Output } from '../../../envoy/api/v2/core/TcpKeepalive'; - -export interface UpstreamConnectionOptions { - /** - * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. - */ - 'tcp_keepalive'?: (_envoy_api_v2_core_TcpKeepalive); -} - -export interface UpstreamConnectionOptions__Output { - /** - * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. - */ - 'tcp_keepalive'?: (_envoy_api_v2_core_TcpKeepalive__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts deleted file mode 100644 index f2ec45d2d..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Vhds.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/route.proto - -import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; - -export interface Vhds { - /** - * Configuration source specifier for VHDS. - */ - 'config_source'?: (_envoy_api_v2_core_ConfigSource); -} - -export interface Vhds__Output { - /** - * Configuration source specifier for VHDS. - */ - 'config_source'?: (_envoy_api_v2_core_ConfigSource__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts deleted file mode 100644 index 0272f3b5c..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CertificateValidationContext.ts +++ /dev/null @@ -1,315 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; - -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - -/** - * Peer certificate verification mode. - */ -export enum _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification { - /** - * Perform default certificate verification (e.g., against CA / verification lists) - */ - VERIFY_TRUST_CHAIN = 0, - /** - * Connections where the certificate fails verification will be permitted. - * For HTTP connections, the result of certificate verification can be used in route matching. ( - * see :ref:`validated ` ). - */ - ACCEPT_UNTRUSTED = 1, -} - -/** - * [#next-free-field: 11] - */ -export interface CertificateValidationContext { - /** - * TLS certificate data containing certificate authority certificates to use in verifying - * a presented peer certificate (e.g. server certificate for clusters or client certificate - * for listeners). If not specified and a peer certificate is presented it will not be - * verified. By default, a client certificate is optional, unless one of the additional - * options (:ref:`require_client_certificate - * `, - * :ref:`verify_certificate_spki - * `, - * :ref:`verify_certificate_hash - * `, or - * :ref:`match_subject_alt_names - * `) is also - * specified. - * - * It can optionally contain certificate revocation lists, in which case Envoy will verify - * that the presented peer certificate has not been revoked by one of the included CRLs. - * - * See :ref:`the TLS overview ` for a list of common - * system CA locations. - */ - 'trusted_ca'?: (_envoy_api_v2_core_DataSource); - /** - * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that - * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. - * - * A hex-encoded SHA-256 of the certificate can be generated with the following command: - * - * .. code-block:: bash - * - * $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 - * df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a - * - * A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate - * can be generated with the following command: - * - * .. code-block:: bash - * - * $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 - * DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A - * - * Both of those formats are acceptable. - * - * When both: - * :ref:`verify_certificate_hash - * ` and - * :ref:`verify_certificate_spki - * ` are specified, - * a hash matching value from either of the lists will result in the certificate being accepted. - */ - 'verify_certificate_hash'?: (string)[]; - /** - * An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the - * SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate - * matches one of the specified values. - * - * A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate - * can be generated with the following command: - * - * .. code-block:: bash - * - * $ openssl x509 -in path/to/client.crt -noout -pubkey - * | openssl pkey -pubin -outform DER - * | openssl dgst -sha256 -binary - * | openssl enc -base64 - * NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= - * - * This is the format used in HTTP Public Key Pinning. - * - * When both: - * :ref:`verify_certificate_hash - * ` and - * :ref:`verify_certificate_spki - * ` are specified, - * a hash matching value from either of the lists will result in the certificate being accepted. - * - * .. attention:: - * - * This option is preferred over :ref:`verify_certificate_hash - * `, - * because SPKI is tied to a private key, so it doesn't change when the certificate - * is renewed using the same private key. - */ - 'verify_certificate_spki'?: (string)[]; - /** - * An optional list of Subject Alternative Names. If specified, Envoy will verify that the - * Subject Alternative Name of the presented certificate matches one of the specified values. - * - * .. attention:: - * - * Subject Alternative Names are easily spoofable and verifying only them is insecure, - * therefore this option must be used together with :ref:`trusted_ca - * `. - */ - 'verify_subject_alt_name'?: (string)[]; - /** - * [#not-implemented-hide:] Must present a signed time-stamped OCSP response. - */ - 'require_ocsp_staple'?: (_google_protobuf_BoolValue); - /** - * [#not-implemented-hide:] Must present signed certificate time-stamp. - */ - 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue); - /** - * An optional `certificate revocation list - * `_ - * (in PEM format). If specified, Envoy will verify that the presented peer - * certificate has not been revoked by this CRL. If this DataSource contains - * multiple CRLs, all of them will be used. - */ - 'crl'?: (_envoy_api_v2_core_DataSource); - /** - * If specified, Envoy will not reject expired certificates. - */ - 'allow_expired_certificate'?: (boolean); - /** - * An optional list of Subject Alternative name matchers. Envoy will verify that the - * Subject Alternative Name of the presented certificate matches one of the specified matches. - * - * When a certificate has wildcard DNS SAN entries, to match a specific client, it should be - * configured with exact match type in the :ref:`string matcher `. - * For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com", - * it should be configured as shown below. - * - * .. code-block:: yaml - * - * match_subject_alt_names: - * exact: "api.example.com" - * - * .. attention:: - * - * Subject Alternative Names are easily spoofable and verifying only them is insecure, - * therefore this option must be used together with :ref:`trusted_ca - * `. - */ - 'match_subject_alt_names'?: (_envoy_type_matcher_StringMatcher)[]; - /** - * Certificate trust chain verification mode. - */ - 'trust_chain_verification'?: (_envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification | keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); -} - -/** - * [#next-free-field: 11] - */ -export interface CertificateValidationContext__Output { - /** - * TLS certificate data containing certificate authority certificates to use in verifying - * a presented peer certificate (e.g. server certificate for clusters or client certificate - * for listeners). If not specified and a peer certificate is presented it will not be - * verified. By default, a client certificate is optional, unless one of the additional - * options (:ref:`require_client_certificate - * `, - * :ref:`verify_certificate_spki - * `, - * :ref:`verify_certificate_hash - * `, or - * :ref:`match_subject_alt_names - * `) is also - * specified. - * - * It can optionally contain certificate revocation lists, in which case Envoy will verify - * that the presented peer certificate has not been revoked by one of the included CRLs. - * - * See :ref:`the TLS overview ` for a list of common - * system CA locations. - */ - 'trusted_ca'?: (_envoy_api_v2_core_DataSource__Output); - /** - * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that - * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. - * - * A hex-encoded SHA-256 of the certificate can be generated with the following command: - * - * .. code-block:: bash - * - * $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 - * df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a - * - * A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate - * can be generated with the following command: - * - * .. code-block:: bash - * - * $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 - * DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A - * - * Both of those formats are acceptable. - * - * When both: - * :ref:`verify_certificate_hash - * ` and - * :ref:`verify_certificate_spki - * ` are specified, - * a hash matching value from either of the lists will result in the certificate being accepted. - */ - 'verify_certificate_hash': (string)[]; - /** - * An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the - * SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate - * matches one of the specified values. - * - * A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate - * can be generated with the following command: - * - * .. code-block:: bash - * - * $ openssl x509 -in path/to/client.crt -noout -pubkey - * | openssl pkey -pubin -outform DER - * | openssl dgst -sha256 -binary - * | openssl enc -base64 - * NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= - * - * This is the format used in HTTP Public Key Pinning. - * - * When both: - * :ref:`verify_certificate_hash - * ` and - * :ref:`verify_certificate_spki - * ` are specified, - * a hash matching value from either of the lists will result in the certificate being accepted. - * - * .. attention:: - * - * This option is preferred over :ref:`verify_certificate_hash - * `, - * because SPKI is tied to a private key, so it doesn't change when the certificate - * is renewed using the same private key. - */ - 'verify_certificate_spki': (string)[]; - /** - * An optional list of Subject Alternative Names. If specified, Envoy will verify that the - * Subject Alternative Name of the presented certificate matches one of the specified values. - * - * .. attention:: - * - * Subject Alternative Names are easily spoofable and verifying only them is insecure, - * therefore this option must be used together with :ref:`trusted_ca - * `. - */ - 'verify_subject_alt_name': (string)[]; - /** - * [#not-implemented-hide:] Must present a signed time-stamped OCSP response. - */ - 'require_ocsp_staple'?: (_google_protobuf_BoolValue__Output); - /** - * [#not-implemented-hide:] Must present signed certificate time-stamp. - */ - 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue__Output); - /** - * An optional `certificate revocation list - * `_ - * (in PEM format). If specified, Envoy will verify that the presented peer - * certificate has not been revoked by this CRL. If this DataSource contains - * multiple CRLs, all of them will be used. - */ - 'crl'?: (_envoy_api_v2_core_DataSource__Output); - /** - * If specified, Envoy will not reject expired certificates. - */ - 'allow_expired_certificate': (boolean); - /** - * An optional list of Subject Alternative name matchers. Envoy will verify that the - * Subject Alternative Name of the presented certificate matches one of the specified matches. - * - * When a certificate has wildcard DNS SAN entries, to match a specific client, it should be - * configured with exact match type in the :ref:`string matcher `. - * For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com", - * it should be configured as shown below. - * - * .. code-block:: yaml - * - * match_subject_alt_names: - * exact: "api.example.com" - * - * .. attention:: - * - * Subject Alternative Names are easily spoofable and verifying only them is insecure, - * therefore this option must be used together with :ref:`trusted_ca - * `. - */ - 'match_subject_alt_names': (_envoy_type_matcher_StringMatcher__Output)[]; - /** - * Certificate trust chain verification mode. - */ - 'trust_chain_verification': (keyof typeof _envoy_api_v2_auth_CertificateValidationContext_TrustChainVerification); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts deleted file mode 100644 index 784e3d2ce..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/CommonTlsContext.ts +++ /dev/null @@ -1,140 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto - -import type { TlsParameters as _envoy_api_v2_auth_TlsParameters, TlsParameters__Output as _envoy_api_v2_auth_TlsParameters__Output } from '../../../../envoy/api/v2/auth/TlsParameters'; -import type { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; -import type { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; -import type { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; - -export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext { - /** - * How to validate peer certificates. - */ - 'default_validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); - /** - * Config for fetching validation context via SDS API. - */ - 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); -} - -export interface _envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output { - /** - * How to validate peer certificates. - */ - 'default_validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); - /** - * Config for fetching validation context via SDS API. - */ - 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); -} - -/** - * TLS context shared by both client and server TLS contexts. - * [#next-free-field: 9] - */ -export interface CommonTlsContext { - /** - * TLS protocol versions, cipher suites etc. - */ - 'tls_params'?: (_envoy_api_v2_auth_TlsParameters); - /** - * :ref:`Multiple TLS certificates ` can be associated with the - * same context to allow both RSA and ECDSA certificates. - * - * Only a single TLS certificate is supported in client contexts. In server contexts, the first - * RSA certificate is used for clients that only support RSA and the first ECDSA certificate is - * used for clients that support ECDSA. - */ - 'tls_certificates'?: (_envoy_api_v2_auth_TlsCertificate)[]; - /** - * How to validate peer certificates. - */ - 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); - /** - * Supplies the list of ALPN protocols that the listener should expose. In - * practice this is likely to be set to one of two values (see the - * :ref:`codec_type - * ` - * parameter in the HTTP connection manager for more information): - * - * * "h2,http/1.1" If the listener is going to support both HTTP/2 and HTTP/1.1. - * * "http/1.1" If the listener is only going to support HTTP/1.1. - * - * There is no default for this parameter. If empty, Envoy will not expose ALPN. - */ - 'alpn_protocols'?: (string)[]; - /** - * Configs for fetching TLS certificates via SDS API. - */ - 'tls_certificate_sds_secret_configs'?: (_envoy_api_v2_auth_SdsSecretConfig)[]; - /** - * Config for fetching validation context via SDS API. - */ - 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); - /** - * Combined certificate validation context holds a default CertificateValidationContext - * and SDS config. When SDS server returns dynamic CertificateValidationContext, both dynamic - * and default CertificateValidationContext are merged into a new CertificateValidationContext - * for validation. This merge is done by Message::MergeFrom(), so dynamic - * CertificateValidationContext overwrites singular fields in default - * CertificateValidationContext, and concatenates repeated fields to default - * CertificateValidationContext, and logical OR is applied to boolean fields. - */ - 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext); - 'validation_context_type'?: "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; -} - -/** - * TLS context shared by both client and server TLS contexts. - * [#next-free-field: 9] - */ -export interface CommonTlsContext__Output { - /** - * TLS protocol versions, cipher suites etc. - */ - 'tls_params'?: (_envoy_api_v2_auth_TlsParameters__Output); - /** - * :ref:`Multiple TLS certificates ` can be associated with the - * same context to allow both RSA and ECDSA certificates. - * - * Only a single TLS certificate is supported in client contexts. In server contexts, the first - * RSA certificate is used for clients that only support RSA and the first ECDSA certificate is - * used for clients that support ECDSA. - */ - 'tls_certificates': (_envoy_api_v2_auth_TlsCertificate__Output)[]; - /** - * How to validate peer certificates. - */ - 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); - /** - * Supplies the list of ALPN protocols that the listener should expose. In - * practice this is likely to be set to one of two values (see the - * :ref:`codec_type - * ` - * parameter in the HTTP connection manager for more information): - * - * * "h2,http/1.1" If the listener is going to support both HTTP/2 and HTTP/1.1. - * * "http/1.1" If the listener is only going to support HTTP/1.1. - * - * There is no default for this parameter. If empty, Envoy will not expose ALPN. - */ - 'alpn_protocols': (string)[]; - /** - * Configs for fetching TLS certificates via SDS API. - */ - 'tls_certificate_sds_secret_configs': (_envoy_api_v2_auth_SdsSecretConfig__Output)[]; - /** - * Config for fetching validation context via SDS API. - */ - 'validation_context_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); - /** - * Combined certificate validation context holds a default CertificateValidationContext - * and SDS config. When SDS server returns dynamic CertificateValidationContext, both dynamic - * and default CertificateValidationContext are merged into a new CertificateValidationContext - * for validation. This merge is done by Message::MergeFrom(), so dynamic - * CertificateValidationContext overwrites singular fields in default - * CertificateValidationContext, and concatenates repeated fields to default - * CertificateValidationContext, and logical OR is applied to boolean fields. - */ - 'combined_validation_context'?: (_envoy_api_v2_auth_CommonTlsContext_CombinedCertificateValidationContext__Output); - 'validation_context_type': "validation_context"|"validation_context_sds_secret_config"|"combined_validation_context"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts deleted file mode 100644 index ef9a6f9a4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/DownstreamTlsContext.ts +++ /dev/null @@ -1,101 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto - -import type { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; -import type { SdsSecretConfig as _envoy_api_v2_auth_SdsSecretConfig, SdsSecretConfig__Output as _envoy_api_v2_auth_SdsSecretConfig__Output } from '../../../../envoy/api/v2/auth/SdsSecretConfig'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; - -/** - * [#next-free-field: 8] - */ -export interface DownstreamTlsContext { - /** - * Common TLS context settings. - */ - 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext); - /** - * If specified, Envoy will reject connections without a valid client - * certificate. - */ - 'require_client_certificate'?: (_google_protobuf_BoolValue); - /** - * If specified, Envoy will reject connections without a valid and matching SNI. - * [#not-implemented-hide:] - */ - 'require_sni'?: (_google_protobuf_BoolValue); - /** - * TLS session ticket key settings. - */ - 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); - /** - * Config for fetching TLS session ticket keys via SDS API. - */ - 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig); - /** - * If specified, session_timeout will change maximum lifetime (in seconds) of TLS session - * Currently this value is used as a hint to `TLS session ticket lifetime (for TLSv1.2) - * ` - * only seconds could be specified (fractional seconds are going to be ignored). - */ - 'session_timeout'?: (_google_protobuf_Duration); - /** - * Config for controlling stateless TLS session resumption: setting this to true will cause the TLS - * server to not issue TLS session tickets for the purposes of stateless TLS session resumption. - * If set to false, the TLS server will issue TLS session tickets and encrypt/decrypt them using - * the keys specified through either :ref:`session_ticket_keys ` - * or :ref:`session_ticket_keys_sds_secret_config `. - * If this config is set to false and no keys are explicitly configured, the TLS server will issue - * TLS session tickets and encrypt/decrypt them using an internally-generated and managed key, with the - * implication that sessions cannot be resumed across hot restarts or on different hosts. - */ - 'disable_stateless_session_resumption'?: (boolean); - 'session_ticket_keys_type'?: "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; -} - -/** - * [#next-free-field: 8] - */ -export interface DownstreamTlsContext__Output { - /** - * Common TLS context settings. - */ - 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext__Output); - /** - * If specified, Envoy will reject connections without a valid client - * certificate. - */ - 'require_client_certificate'?: (_google_protobuf_BoolValue__Output); - /** - * If specified, Envoy will reject connections without a valid and matching SNI. - * [#not-implemented-hide:] - */ - 'require_sni'?: (_google_protobuf_BoolValue__Output); - /** - * TLS session ticket key settings. - */ - 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); - /** - * Config for fetching TLS session ticket keys via SDS API. - */ - 'session_ticket_keys_sds_secret_config'?: (_envoy_api_v2_auth_SdsSecretConfig__Output); - /** - * If specified, session_timeout will change maximum lifetime (in seconds) of TLS session - * Currently this value is used as a hint to `TLS session ticket lifetime (for TLSv1.2) - * ` - * only seconds could be specified (fractional seconds are going to be ignored). - */ - 'session_timeout'?: (_google_protobuf_Duration__Output); - /** - * Config for controlling stateless TLS session resumption: setting this to true will cause the TLS - * server to not issue TLS session tickets for the purposes of stateless TLS session resumption. - * If set to false, the TLS server will issue TLS session tickets and encrypt/decrypt them using - * the keys specified through either :ref:`session_ticket_keys ` - * or :ref:`session_ticket_keys_sds_secret_config `. - * If this config is set to false and no keys are explicitly configured, the TLS server will issue - * TLS session tickets and encrypt/decrypt them using an internally-generated and managed key, with the - * implication that sessions cannot be resumed across hot restarts or on different hosts. - */ - 'disable_stateless_session_resumption'?: (boolean); - 'session_ticket_keys_type': "session_ticket_keys"|"session_ticket_keys_sds_secret_config"|"disable_stateless_session_resumption"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts deleted file mode 100644 index d7b712525..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/GenericSecret.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto - -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; - -export interface GenericSecret { - /** - * Secret of generic type and is available to filters. - */ - 'secret'?: (_envoy_api_v2_core_DataSource); -} - -export interface GenericSecret__Output { - /** - * Secret of generic type and is available to filters. - */ - 'secret'?: (_envoy_api_v2_core_DataSource__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts deleted file mode 100644 index 415448053..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/PrivateKeyProvider.ts +++ /dev/null @@ -1,42 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; - -/** - * BoringSSL private key method configuration. The private key methods are used for external - * (potentially asynchronous) signing and decryption operations. Some use cases for private key - * methods would be TPM support and TLS acceleration. - */ -export interface PrivateKeyProvider { - /** - * Private key method provider name. The name must match a - * supported private key method provider type. - */ - 'provider_name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); - /** - * Private key method provider specific configuration. - */ - 'config_type'?: "config"|"typed_config"; -} - -/** - * BoringSSL private key method configuration. The private key methods are used for external - * (potentially asynchronous) signing and decryption operations. Some use cases for private key - * methods would be TPM support and TLS acceleration. - */ -export interface PrivateKeyProvider__Output { - /** - * Private key method provider name. The name must match a - * supported private key method provider type. - */ - 'provider_name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); - /** - * Private key method provider specific configuration. - */ - 'config_type': "config"|"typed_config"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts deleted file mode 100644 index 888059332..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/SdsSecretConfig.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto - -import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../envoy/api/v2/core/ConfigSource'; - -export interface SdsSecretConfig { - /** - * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. - * When both name and config are specified, then secret can be fetched and/or reloaded via - * SDS. When only name is specified, then secret will be loaded from static resources. - */ - 'name'?: (string); - 'sds_config'?: (_envoy_api_v2_core_ConfigSource); -} - -export interface SdsSecretConfig__Output { - /** - * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. - * When both name and config are specified, then secret can be fetched and/or reloaded via - * SDS. When only name is specified, then secret will be loaded from static resources. - */ - 'name': (string); - 'sds_config'?: (_envoy_api_v2_core_ConfigSource__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts deleted file mode 100644 index 0768daed8..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/Secret.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/secret.proto - -import type { TlsCertificate as _envoy_api_v2_auth_TlsCertificate, TlsCertificate__Output as _envoy_api_v2_auth_TlsCertificate__Output } from '../../../../envoy/api/v2/auth/TlsCertificate'; -import type { TlsSessionTicketKeys as _envoy_api_v2_auth_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_api_v2_auth_TlsSessionTicketKeys__Output } from '../../../../envoy/api/v2/auth/TlsSessionTicketKeys'; -import type { CertificateValidationContext as _envoy_api_v2_auth_CertificateValidationContext, CertificateValidationContext__Output as _envoy_api_v2_auth_CertificateValidationContext__Output } from '../../../../envoy/api/v2/auth/CertificateValidationContext'; -import type { GenericSecret as _envoy_api_v2_auth_GenericSecret, GenericSecret__Output as _envoy_api_v2_auth_GenericSecret__Output } from '../../../../envoy/api/v2/auth/GenericSecret'; - -/** - * [#next-free-field: 6] - */ -export interface Secret { - /** - * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. - */ - 'name'?: (string); - 'tls_certificate'?: (_envoy_api_v2_auth_TlsCertificate); - 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys); - 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext); - 'generic_secret'?: (_envoy_api_v2_auth_GenericSecret); - 'type'?: "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; -} - -/** - * [#next-free-field: 6] - */ -export interface Secret__Output { - /** - * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. - */ - 'name': (string); - 'tls_certificate'?: (_envoy_api_v2_auth_TlsCertificate__Output); - 'session_ticket_keys'?: (_envoy_api_v2_auth_TlsSessionTicketKeys__Output); - 'validation_context'?: (_envoy_api_v2_auth_CertificateValidationContext__Output); - 'generic_secret'?: (_envoy_api_v2_auth_GenericSecret__Output); - 'type': "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts deleted file mode 100644 index dd7efcf21..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsCertificate.ts +++ /dev/null @@ -1,78 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import type { PrivateKeyProvider as _envoy_api_v2_auth_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_api_v2_auth_PrivateKeyProvider__Output } from '../../../../envoy/api/v2/auth/PrivateKeyProvider'; - -/** - * [#next-free-field: 7] - */ -export interface TlsCertificate { - /** - * The TLS certificate chain. - */ - 'certificate_chain'?: (_envoy_api_v2_core_DataSource); - /** - * The TLS private key. - */ - 'private_key'?: (_envoy_api_v2_core_DataSource); - /** - * The password to decrypt the TLS private key. If this field is not set, it is assumed that the - * TLS private key is not password encrypted. - */ - 'password'?: (_envoy_api_v2_core_DataSource); - /** - * [#not-implemented-hide:] - */ - 'ocsp_staple'?: (_envoy_api_v2_core_DataSource); - /** - * [#not-implemented-hide:] - */ - 'signed_certificate_timestamp'?: (_envoy_api_v2_core_DataSource)[]; - /** - * BoringSSL private key method provider. This is an alternative to :ref:`private_key - * ` field. This can't be - * marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key - * ` and - * :ref:`private_key_provider - * ` fields will result in an - * error. - */ - 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider); -} - -/** - * [#next-free-field: 7] - */ -export interface TlsCertificate__Output { - /** - * The TLS certificate chain. - */ - 'certificate_chain'?: (_envoy_api_v2_core_DataSource__Output); - /** - * The TLS private key. - */ - 'private_key'?: (_envoy_api_v2_core_DataSource__Output); - /** - * The password to decrypt the TLS private key. If this field is not set, it is assumed that the - * TLS private key is not password encrypted. - */ - 'password'?: (_envoy_api_v2_core_DataSource__Output); - /** - * [#not-implemented-hide:] - */ - 'ocsp_staple'?: (_envoy_api_v2_core_DataSource__Output); - /** - * [#not-implemented-hide:] - */ - 'signed_certificate_timestamp': (_envoy_api_v2_core_DataSource__Output)[]; - /** - * BoringSSL private key method provider. This is an alternative to :ref:`private_key - * ` field. This can't be - * marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key - * ` and - * :ref:`private_key_provider - * ` fields will result in an - * error. - */ - 'private_key_provider'?: (_envoy_api_v2_auth_PrivateKeyProvider__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts deleted file mode 100644 index 29fe8f4c8..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsParameters.ts +++ /dev/null @@ -1,171 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - - -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - -export enum _envoy_api_v2_auth_TlsParameters_TlsProtocol { - /** - * Envoy will choose the optimal TLS version. - */ - TLS_AUTO = 0, - /** - * TLS 1.0 - */ - TLSv1_0 = 1, - /** - * TLS 1.1 - */ - TLSv1_1 = 2, - /** - * TLS 1.2 - */ - TLSv1_2 = 3, - /** - * TLS 1.3 - */ - TLSv1_3 = 4, -} - -export interface TlsParameters { - /** - * Minimum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_0`` for - * servers. - */ - 'tls_minimum_protocol_version'?: (_envoy_api_v2_auth_TlsParameters_TlsProtocol | keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); - /** - * Maximum TLS protocol version. By default, it's ``TLSv1_3`` for servers in non-FIPS builds, and - * ``TLSv1_2`` for clients and for servers using :ref:`BoringSSL FIPS `. - */ - 'tls_maximum_protocol_version'?: (_envoy_api_v2_auth_TlsParameters_TlsProtocol | keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); - /** - * If specified, the TLS listener will only support the specified `cipher list - * `_ - * when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). If not - * specified, the default list will be used. - * - * In non-FIPS builds, the default cipher list is: - * - * .. code-block:: none - * - * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] - * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] - * ECDHE-ECDSA-AES128-SHA - * ECDHE-RSA-AES128-SHA - * AES128-GCM-SHA256 - * AES128-SHA - * ECDHE-ECDSA-AES256-GCM-SHA384 - * ECDHE-RSA-AES256-GCM-SHA384 - * ECDHE-ECDSA-AES256-SHA - * ECDHE-RSA-AES256-SHA - * AES256-GCM-SHA384 - * AES256-SHA - * - * In builds using :ref:`BoringSSL FIPS `, the default cipher list is: - * - * .. code-block:: none - * - * ECDHE-ECDSA-AES128-GCM-SHA256 - * ECDHE-RSA-AES128-GCM-SHA256 - * ECDHE-ECDSA-AES128-SHA - * ECDHE-RSA-AES128-SHA - * AES128-GCM-SHA256 - * AES128-SHA - * ECDHE-ECDSA-AES256-GCM-SHA384 - * ECDHE-RSA-AES256-GCM-SHA384 - * ECDHE-ECDSA-AES256-SHA - * ECDHE-RSA-AES256-SHA - * AES256-GCM-SHA384 - * AES256-SHA - */ - 'cipher_suites'?: (string)[]; - /** - * If specified, the TLS connection will only support the specified ECDH - * curves. If not specified, the default curves will be used. - * - * In non-FIPS builds, the default curves are: - * - * .. code-block:: none - * - * X25519 - * P-256 - * - * In builds using :ref:`BoringSSL FIPS `, the default curve is: - * - * .. code-block:: none - * - * P-256 - */ - 'ecdh_curves'?: (string)[]; -} - -export interface TlsParameters__Output { - /** - * Minimum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_0`` for - * servers. - */ - 'tls_minimum_protocol_version': (keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); - /** - * Maximum TLS protocol version. By default, it's ``TLSv1_3`` for servers in non-FIPS builds, and - * ``TLSv1_2`` for clients and for servers using :ref:`BoringSSL FIPS `. - */ - 'tls_maximum_protocol_version': (keyof typeof _envoy_api_v2_auth_TlsParameters_TlsProtocol); - /** - * If specified, the TLS listener will only support the specified `cipher list - * `_ - * when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). If not - * specified, the default list will be used. - * - * In non-FIPS builds, the default cipher list is: - * - * .. code-block:: none - * - * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] - * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] - * ECDHE-ECDSA-AES128-SHA - * ECDHE-RSA-AES128-SHA - * AES128-GCM-SHA256 - * AES128-SHA - * ECDHE-ECDSA-AES256-GCM-SHA384 - * ECDHE-RSA-AES256-GCM-SHA384 - * ECDHE-ECDSA-AES256-SHA - * ECDHE-RSA-AES256-SHA - * AES256-GCM-SHA384 - * AES256-SHA - * - * In builds using :ref:`BoringSSL FIPS `, the default cipher list is: - * - * .. code-block:: none - * - * ECDHE-ECDSA-AES128-GCM-SHA256 - * ECDHE-RSA-AES128-GCM-SHA256 - * ECDHE-ECDSA-AES128-SHA - * ECDHE-RSA-AES128-SHA - * AES128-GCM-SHA256 - * AES128-SHA - * ECDHE-ECDSA-AES256-GCM-SHA384 - * ECDHE-RSA-AES256-GCM-SHA384 - * ECDHE-ECDSA-AES256-SHA - * ECDHE-RSA-AES256-SHA - * AES256-GCM-SHA384 - * AES256-SHA - */ - 'cipher_suites': (string)[]; - /** - * If specified, the TLS connection will only support the specified ECDH - * curves. If not specified, the default curves will be used. - * - * In non-FIPS builds, the default curves are: - * - * .. code-block:: none - * - * X25519 - * P-256 - * - * In builds using :ref:`BoringSSL FIPS `, the default curve is: - * - * .. code-block:: none - * - * P-256 - */ - 'ecdh_curves': (string)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts deleted file mode 100644 index d4bedd682..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/TlsSessionTicketKeys.ts +++ /dev/null @@ -1,61 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/common.proto - -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; - -export interface TlsSessionTicketKeys { - /** - * Keys for encrypting and decrypting TLS session tickets. The - * first key in the array contains the key to encrypt all new sessions created by this context. - * All keys are candidates for decrypting received tickets. This allows for easy rotation of keys - * by, for example, putting the new key first, and the previous key second. - * - * If :ref:`session_ticket_keys ` - * is not specified, the TLS library will still support resuming sessions via tickets, but it will - * use an internally-generated and managed key, so sessions cannot be resumed across hot restarts - * or on different hosts. - * - * Each key must contain exactly 80 bytes of cryptographically-secure random data. For - * example, the output of ``openssl rand 80``. - * - * .. attention:: - * - * Using this feature has serious security considerations and risks. Improper handling of keys - * may result in loss of secrecy in connections, even if ciphers supporting perfect forward - * secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some - * discussion. To minimize the risk, you must: - * - * * Keep the session ticket keys at least as secure as your TLS certificate private keys - * * Rotate session ticket keys at least daily, and preferably hourly - * * Always generate keys using a cryptographically-secure random data source - */ - 'keys'?: (_envoy_api_v2_core_DataSource)[]; -} - -export interface TlsSessionTicketKeys__Output { - /** - * Keys for encrypting and decrypting TLS session tickets. The - * first key in the array contains the key to encrypt all new sessions created by this context. - * All keys are candidates for decrypting received tickets. This allows for easy rotation of keys - * by, for example, putting the new key first, and the previous key second. - * - * If :ref:`session_ticket_keys ` - * is not specified, the TLS library will still support resuming sessions via tickets, but it will - * use an internally-generated and managed key, so sessions cannot be resumed across hot restarts - * or on different hosts. - * - * Each key must contain exactly 80 bytes of cryptographically-secure random data. For - * example, the output of ``openssl rand 80``. - * - * .. attention:: - * - * Using this feature has serious security considerations and risks. Improper handling of keys - * may result in loss of secrecy in connections, even if ciphers supporting perfect forward - * secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some - * discussion. To minimize the risk, you must: - * - * * Keep the session ticket keys at least as secure as your TLS certificate private keys - * * Rotate session ticket keys at least daily, and preferably hourly - * * Always generate keys using a cryptographically-secure random data source - */ - 'keys': (_envoy_api_v2_core_DataSource__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts deleted file mode 100644 index b9dc4414f..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/auth/UpstreamTlsContext.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/auth/tls.proto - -import type { CommonTlsContext as _envoy_api_v2_auth_CommonTlsContext, CommonTlsContext__Output as _envoy_api_v2_auth_CommonTlsContext__Output } from '../../../../envoy/api/v2/auth/CommonTlsContext'; -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; - -export interface UpstreamTlsContext { - /** - * Common TLS context settings. - * - * .. attention:: - * - * Server certificate verification is not enabled by default. Configure - * :ref:`trusted_ca` to enable - * verification. - */ - 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext); - /** - * SNI string to use when creating TLS backend connections. - */ - 'sni'?: (string); - /** - * If true, server-initiated TLS renegotiation will be allowed. - * - * .. attention:: - * - * TLS renegotiation is considered insecure and shouldn't be used unless absolutely necessary. - */ - 'allow_renegotiation'?: (boolean); - /** - * Maximum number of session keys (Pre-Shared Keys for TLSv1.3+, Session IDs and Session Tickets - * for TLSv1.2 and older) to store for the purpose of session resumption. - * - * Defaults to 1, setting this to 0 disables session resumption. - */ - 'max_session_keys'?: (_google_protobuf_UInt32Value); -} - -export interface UpstreamTlsContext__Output { - /** - * Common TLS context settings. - * - * .. attention:: - * - * Server certificate verification is not enabled by default. Configure - * :ref:`trusted_ca` to enable - * verification. - */ - 'common_tls_context'?: (_envoy_api_v2_auth_CommonTlsContext__Output); - /** - * SNI string to use when creating TLS backend connections. - */ - 'sni': (string); - /** - * If true, server-initiated TLS renegotiation will be allowed. - * - * .. attention:: - * - * TLS renegotiation is considered insecure and shouldn't be used unless absolutely necessary. - */ - 'allow_renegotiation': (boolean); - /** - * Maximum number of session keys (Pre-Shared Keys for TLSv1.3+, Session IDs and Session Tickets - * for TLSv1.2 and older) to store for the purpose of session resumption. - * - * Defaults to 1, setting this to 0 disables session resumption. - */ - 'max_session_keys'?: (_google_protobuf_UInt32Value__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts index 009506fa2..50a44a3b2 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts @@ -14,7 +14,7 @@ export interface BuildVersion { 'version'?: (_envoy_type_SemanticVersion); /** * Free-form build information. - * Envoy defines several well known keys in the source/common/common/version.h file + * Envoy defines several well known keys in the source/common/version/version.h file */ 'metadata'?: (_google_protobuf_Struct); } @@ -30,7 +30,7 @@ export interface BuildVersion__Output { 'version'?: (_envoy_type_SemanticVersion__Output); /** * Free-form build information. - * Envoy defines several well known keys in the source/common/common/version.h file + * Envoy defines several well known keys in the source/common/version/version.h file */ 'metadata'?: (_google_protobuf_Struct__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts deleted file mode 100644 index 66723801e..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcProtocolOptions.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto - -import type { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../envoy/api/v2/core/Http2ProtocolOptions'; - -/** - * [#not-implemented-hide:] - */ -export interface GrpcProtocolOptions { - 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); -} - -/** - * [#not-implemented-hide:] - */ -export interface GrpcProtocolOptions__Output { - 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts index 8d9aba3e0..1ea2b8146 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts @@ -22,7 +22,7 @@ export interface RuntimeDouble__Output { /** * Default value if runtime value is not available. */ - 'default_value': (number | string); + 'default_value': (number); /** * Runtime key to get value for comparison. This value is used if defined. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts deleted file mode 100644 index 144cfdf5a..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SelfConfigSource.ts +++ /dev/null @@ -1,20 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto - - -/** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ -export interface SelfConfigSource { -} - -/** - * [#not-implemented-hide:] - * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to - * specify that other data can be obtained from the same server. - */ -export interface SelfConfigSource__Output { -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts index 9ed8016b7..335b759b6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts @@ -37,5 +37,5 @@ export interface EndpointLoadMetricStats__Output { * Sum of metric values across all calls that finished with this metric for * load_reporting_interval. */ - 'total_metric_value': (number | string); + 'total_metric_value': (number); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts deleted file mode 100644 index 2c6e0d087..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/Filter.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto - -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; - -export interface Filter { - /** - * The name of the filter to instantiate. The name must match a - * :ref:`supported filter `. - */ - 'name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); - /** - * Filter specific configuration which depends on the filter being - * instantiated. See the supported filters for further documentation. - */ - 'config_type'?: "config"|"typed_config"; -} - -export interface Filter__Output { - /** - * The name of the filter to instantiate. The name must match a - * :ref:`supported filter `. - */ - 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); - /** - * Filter specific configuration which depends on the filter being - * instantiated. See the supported filters for further documentation. - */ - 'config_type': "config"|"typed_config"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts deleted file mode 100644 index 1e98abe50..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChain.ts +++ /dev/null @@ -1,118 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto - -import type { FilterChainMatch as _envoy_api_v2_listener_FilterChainMatch, FilterChainMatch__Output as _envoy_api_v2_listener_FilterChainMatch__Output } from '../../../../envoy/api/v2/listener/FilterChainMatch'; -import type { DownstreamTlsContext as _envoy_api_v2_auth_DownstreamTlsContext, DownstreamTlsContext__Output as _envoy_api_v2_auth_DownstreamTlsContext__Output } from '../../../../envoy/api/v2/auth/DownstreamTlsContext'; -import type { Filter as _envoy_api_v2_listener_Filter, Filter__Output as _envoy_api_v2_listener_Filter__Output } from '../../../../envoy/api/v2/listener/Filter'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import type { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../../envoy/api/v2/core/TransportSocket'; - -/** - * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and - * various other parameters. - * [#next-free-field: 8] - */ -export interface FilterChain { - /** - * The criteria to use when matching a connection to this filter chain. - */ - 'filter_chain_match'?: (_envoy_api_v2_listener_FilterChainMatch); - /** - * The TLS context for this filter chain. - * - * .. attention:: - * - * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are - * set, `transport_socket` takes priority. - */ - 'tls_context'?: (_envoy_api_v2_auth_DownstreamTlsContext); - /** - * A list of individual network filters that make up the filter chain for - * connections established with the listener. Order matters as the filters are - * processed sequentially as connection events happen. Note: If the filter - * list is empty, the connection will close by default. - */ - 'filters'?: (_envoy_api_v2_listener_Filter)[]; - /** - * Whether the listener should expect a PROXY protocol V1 header on new - * connections. If this option is enabled, the listener will assume that that - * remote address of the connection is the one specified in the header. Some - * load balancers including the AWS ELB support this option. If the option is - * absent or set to false, Envoy will use the physical peer address of the - * connection as the remote address. - */ - 'use_proxy_proto'?: (_google_protobuf_BoolValue); - /** - * [#not-implemented-hide:] filter chain metadata. - */ - 'metadata'?: (_envoy_api_v2_core_Metadata); - /** - * Optional custom transport socket implementation to use for downstream connections. - * To setup TLS, set a transport socket with name `tls` and - * :ref:`DownstreamTlsContext ` in the `typed_config`. - * If no transport socket configuration is specified, new connections - * will be set up with plaintext. - */ - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); - /** - * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no - * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter - * chain is to be dynamically updated or removed via FCDS a unique name must be provided. - */ - 'name'?: (string); -} - -/** - * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and - * various other parameters. - * [#next-free-field: 8] - */ -export interface FilterChain__Output { - /** - * The criteria to use when matching a connection to this filter chain. - */ - 'filter_chain_match'?: (_envoy_api_v2_listener_FilterChainMatch__Output); - /** - * The TLS context for this filter chain. - * - * .. attention:: - * - * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are - * set, `transport_socket` takes priority. - */ - 'tls_context'?: (_envoy_api_v2_auth_DownstreamTlsContext__Output); - /** - * A list of individual network filters that make up the filter chain for - * connections established with the listener. Order matters as the filters are - * processed sequentially as connection events happen. Note: If the filter - * list is empty, the connection will close by default. - */ - 'filters': (_envoy_api_v2_listener_Filter__Output)[]; - /** - * Whether the listener should expect a PROXY protocol V1 header on new - * connections. If this option is enabled, the listener will assume that that - * remote address of the connection is the one specified in the header. Some - * load balancers including the AWS ELB support this option. If the option is - * absent or set to false, Envoy will use the physical peer address of the - * connection as the remote address. - */ - 'use_proxy_proto'?: (_google_protobuf_BoolValue__Output); - /** - * [#not-implemented-hide:] filter chain metadata. - */ - 'metadata'?: (_envoy_api_v2_core_Metadata__Output); - /** - * Optional custom transport socket implementation to use for downstream connections. - * To setup TLS, set a transport socket with name `tls` and - * :ref:`DownstreamTlsContext ` in the `typed_config`. - * If no transport socket configuration is specified, new connections - * will be set up with plaintext. - */ - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket__Output); - /** - * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no - * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter - * chain is to be dynamically updated or removed via FCDS a unique name must be provided. - */ - 'name': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts deleted file mode 100644 index 8134fc359..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HedgePolicy.ts +++ /dev/null @@ -1,66 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; - -/** - * HTTP request hedging :ref:`architecture overview `. - */ -export interface HedgePolicy { - /** - * Specifies the number of initial requests that should be sent upstream. - * Must be at least 1. - * Defaults to 1. - * [#not-implemented-hide:] - */ - 'initial_requests'?: (_google_protobuf_UInt32Value); - /** - * Specifies a probability that an additional upstream request should be sent - * on top of what is specified by initial_requests. - * Defaults to 0. - * [#not-implemented-hide:] - */ - 'additional_request_chance'?: (_envoy_type_FractionalPercent); - /** - * Indicates that a hedged request should be sent when the per-try timeout - * is hit. This will only occur if the retry policy also indicates that a - * timed out request should be retried. - * Once a timed out request is retried due to per try timeout, the router - * filter will ensure that it is not retried again even if the returned - * response headers would otherwise be retried according the specified - * :ref:`RetryPolicy `. - * Defaults to false. - */ - 'hedge_on_per_try_timeout'?: (boolean); -} - -/** - * HTTP request hedging :ref:`architecture overview `. - */ -export interface HedgePolicy__Output { - /** - * Specifies the number of initial requests that should be sent upstream. - * Must be at least 1. - * Defaults to 1. - * [#not-implemented-hide:] - */ - 'initial_requests'?: (_google_protobuf_UInt32Value__Output); - /** - * Specifies a probability that an additional upstream request should be sent - * on top of what is specified by initial_requests. - * Defaults to 0. - * [#not-implemented-hide:] - */ - 'additional_request_chance'?: (_envoy_type_FractionalPercent__Output); - /** - * Indicates that a hedged request should be sent when the per-try timeout - * is hit. This will only occur if the retry policy also indicates that a - * timed out request should be retried. - * Once a timed out request is retried due to per try timeout, the router - * filter will ensure that it is not retried again even if the returned - * response headers would otherwise be retried according the specified - * :ref:`RetryPolicy `. - * Defaults to false. - */ - 'hedge_on_per_try_timeout': (boolean); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts deleted file mode 100644 index 68f4fbcaa..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/QueryParameterMatcher.ts +++ /dev/null @@ -1,86 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; - -/** - * Query parameter matching treats the query string of a request's :path header - * as an ampersand-separated list of keys and/or key=value elements. - * [#next-free-field: 7] - */ -export interface QueryParameterMatcher { - /** - * Specifies the name of a key that must be present in the requested - * *path*'s query string. - */ - 'name'?: (string); - /** - * Specifies the value of the key. If the value is absent, a request - * that contains the key in its query string will match, whether the - * key appears with a value (e.g., "?debug=true") or not (e.g., "?debug") - * - * ..attention:: - * This field is deprecated. Use an `exact` match inside the `string_match` field. - */ - 'value'?: (string); - /** - * Specifies whether the query parameter value is a regular expression. - * Defaults to false. The entire query parameter value (i.e., the part to - * the right of the equals sign in "key=value") must match the regex. - * E.g., the regex ``\d+$`` will match *123* but not *a123* or *123a*. - * - * ..attention:: - * This field is deprecated. Use a `safe_regex` match inside the `string_match` field. - */ - 'regex'?: (_google_protobuf_BoolValue); - /** - * Specifies whether a query parameter value should match against a string. - */ - 'string_match'?: (_envoy_type_matcher_StringMatcher); - /** - * Specifies whether a query parameter should be present. - */ - 'present_match'?: (boolean); - 'query_parameter_match_specifier'?: "string_match"|"present_match"; -} - -/** - * Query parameter matching treats the query string of a request's :path header - * as an ampersand-separated list of keys and/or key=value elements. - * [#next-free-field: 7] - */ -export interface QueryParameterMatcher__Output { - /** - * Specifies the name of a key that must be present in the requested - * *path*'s query string. - */ - 'name': (string); - /** - * Specifies the value of the key. If the value is absent, a request - * that contains the key in its query string will match, whether the - * key appears with a value (e.g., "?debug=true") or not (e.g., "?debug") - * - * ..attention:: - * This field is deprecated. Use an `exact` match inside the `string_match` field. - */ - 'value': (string); - /** - * Specifies whether the query parameter value is a regular expression. - * Defaults to false. The entire query parameter value (i.e., the part to - * the right of the equals sign in "key=value") must match the regex. - * E.g., the regex ``\d+$`` will match *123* but not *a123* or *123a*. - * - * ..attention:: - * This field is deprecated. Use a `safe_regex` match inside the `string_match` field. - */ - 'regex'?: (_google_protobuf_BoolValue__Output); - /** - * Specifies whether a query parameter value should match against a string. - */ - 'string_match'?: (_envoy_type_matcher_StringMatcher__Output); - /** - * Specifies whether a query parameter should be present. - */ - 'present_match'?: (boolean); - 'query_parameter_match_specifier': "string_match"|"present_match"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts deleted file mode 100644 index 998d94e53..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RateLimit.ts +++ /dev/null @@ -1,341 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; - -/** - * [#next-free-field: 7] - */ -export interface _envoy_api_v2_route_RateLimit_Action { - /** - * Rate limit on source cluster. - */ - 'source_cluster'?: (_envoy_api_v2_route_RateLimit_Action_SourceCluster); - /** - * Rate limit on destination cluster. - */ - 'destination_cluster'?: (_envoy_api_v2_route_RateLimit_Action_DestinationCluster); - /** - * Rate limit on request headers. - */ - 'request_headers'?: (_envoy_api_v2_route_RateLimit_Action_RequestHeaders); - /** - * Rate limit on remote address. - */ - 'remote_address'?: (_envoy_api_v2_route_RateLimit_Action_RemoteAddress); - /** - * Rate limit on a generic key. - */ - 'generic_key'?: (_envoy_api_v2_route_RateLimit_Action_GenericKey); - /** - * Rate limit on the existence of request headers. - */ - 'header_value_match'?: (_envoy_api_v2_route_RateLimit_Action_HeaderValueMatch); - 'action_specifier'?: "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; -} - -/** - * [#next-free-field: 7] - */ -export interface _envoy_api_v2_route_RateLimit_Action__Output { - /** - * Rate limit on source cluster. - */ - 'source_cluster'?: (_envoy_api_v2_route_RateLimit_Action_SourceCluster__Output); - /** - * Rate limit on destination cluster. - */ - 'destination_cluster'?: (_envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output); - /** - * Rate limit on request headers. - */ - 'request_headers'?: (_envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output); - /** - * Rate limit on remote address. - */ - 'remote_address'?: (_envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output); - /** - * Rate limit on a generic key. - */ - 'generic_key'?: (_envoy_api_v2_route_RateLimit_Action_GenericKey__Output); - /** - * Rate limit on the existence of request headers. - */ - 'header_value_match'?: (_envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output); - 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"; -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("destination_cluster", "") - * - * Once a request matches against a route table rule, a routed cluster is determined by one of - * the following :ref:`route table configuration ` - * settings: - * - * * :ref:`cluster ` indicates the upstream cluster - * to route to. - * * :ref:`weighted_clusters ` - * chooses a cluster randomly from a set of clusters with attributed weight. - * * :ref:`cluster_header ` indicates which - * header in the request contains the target cluster. - */ -export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster { -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("destination_cluster", "") - * - * Once a request matches against a route table rule, a routed cluster is determined by one of - * the following :ref:`route table configuration ` - * settings: - * - * * :ref:`cluster ` indicates the upstream cluster - * to route to. - * * :ref:`weighted_clusters ` - * chooses a cluster randomly from a set of clusters with attributed weight. - * * :ref:`cluster_header ` indicates which - * header in the request contains the target cluster. - */ -export interface _envoy_api_v2_route_RateLimit_Action_DestinationCluster__Output { -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("generic_key", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_GenericKey { - /** - * The value to use in the descriptor entry. - */ - 'descriptor_value'?: (string); -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("generic_key", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_GenericKey__Output { - /** - * The value to use in the descriptor entry. - */ - 'descriptor_value': (string); -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("header_match", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch { - /** - * The value to use in the descriptor entry. - */ - 'descriptor_value'?: (string); - /** - * If set to true, the action will append a descriptor entry when the - * request matches the headers. If set to false, the action will append a - * descriptor entry when the request does not match the headers. The - * default value is true. - */ - 'expect_match'?: (_google_protobuf_BoolValue); - /** - * Specifies a set of headers that the rate limit action should match - * on. The action will check the request’s headers against all the - * specified headers in the config. A match will happen if all the - * headers in the config are present in the request with the same values - * (or based on presence if the value field is not in the config). - */ - 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("header_match", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_HeaderValueMatch__Output { - /** - * The value to use in the descriptor entry. - */ - 'descriptor_value': (string); - /** - * If set to true, the action will append a descriptor entry when the - * request matches the headers. If set to false, the action will append a - * descriptor entry when the request does not match the headers. The - * default value is true. - */ - 'expect_match'?: (_google_protobuf_BoolValue__Output); - /** - * Specifies a set of headers that the rate limit action should match - * on. The action will check the request’s headers against all the - * specified headers in the config. A match will happen if all the - * headers in the config are present in the request with the same values - * (or based on presence if the value field is not in the config). - */ - 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; -} - -/** - * The following descriptor entry is appended to the descriptor and is populated using the - * trusted address from :ref:`x-forwarded-for `: - * - * .. code-block:: cpp - * - * ("remote_address", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress { -} - -/** - * The following descriptor entry is appended to the descriptor and is populated using the - * trusted address from :ref:`x-forwarded-for `: - * - * .. code-block:: cpp - * - * ("remote_address", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_RemoteAddress__Output { -} - -/** - * The following descriptor entry is appended when a header contains a key that matches the - * *header_name*: - * - * .. code-block:: cpp - * - * ("", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders { - /** - * The header name to be queried from the request headers. The header’s - * value is used to populate the value of the descriptor entry for the - * descriptor_key. - */ - 'header_name'?: (string); - /** - * The key to use in the descriptor entry. - */ - 'descriptor_key'?: (string); -} - -/** - * The following descriptor entry is appended when a header contains a key that matches the - * *header_name*: - * - * .. code-block:: cpp - * - * ("", "") - */ -export interface _envoy_api_v2_route_RateLimit_Action_RequestHeaders__Output { - /** - * The header name to be queried from the request headers. The header’s - * value is used to populate the value of the descriptor entry for the - * descriptor_key. - */ - 'header_name': (string); - /** - * The key to use in the descriptor entry. - */ - 'descriptor_key': (string); -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("source_cluster", "") - * - * is derived from the :option:`--service-cluster` option. - */ -export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster { -} - -/** - * The following descriptor entry is appended to the descriptor: - * - * .. code-block:: cpp - * - * ("source_cluster", "") - * - * is derived from the :option:`--service-cluster` option. - */ -export interface _envoy_api_v2_route_RateLimit_Action_SourceCluster__Output { -} - -/** - * Global rate limiting :ref:`architecture overview `. - */ -export interface RateLimit { - /** - * Refers to the stage set in the filter. The rate limit configuration only - * applies to filters with the same stage number. The default stage number is - * 0. - * - * .. note:: - * - * The filter supports a range of 0 - 10 inclusively for stage numbers. - */ - 'stage'?: (_google_protobuf_UInt32Value); - /** - * The key to be set in runtime to disable this rate limit configuration. - */ - 'disable_key'?: (string); - /** - * A list of actions that are to be applied for this rate limit configuration. - * Order matters as the actions are processed sequentially and the descriptor - * is composed by appending descriptor entries in that sequence. If an action - * cannot append a descriptor entry, no descriptor is generated for the - * configuration. See :ref:`composing actions - * ` for additional documentation. - */ - 'actions'?: (_envoy_api_v2_route_RateLimit_Action)[]; -} - -/** - * Global rate limiting :ref:`architecture overview `. - */ -export interface RateLimit__Output { - /** - * Refers to the stage set in the filter. The rate limit configuration only - * applies to filters with the same stage number. The default stage number is - * 0. - * - * .. note:: - * - * The filter supports a range of 0 - 10 inclusively for stage numbers. - */ - 'stage'?: (_google_protobuf_UInt32Value__Output); - /** - * The key to be set in runtime to disable this rate limit configuration. - */ - 'disable_key': (string); - /** - * A list of actions that are to be applied for this rate limit configuration. - * Order matters as the actions are processed sequentially and the descriptor - * is composed by appending descriptor entries in that sequence. If an action - * cannot append a descriptor entry, no descriptor is generated for the - * configuration. See :ref:`composing actions - * ` for additional documentation. - */ - 'actions': (_envoy_api_v2_route_RateLimit_Action__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts deleted file mode 100644 index de7105a54..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RedirectAction.ts +++ /dev/null @@ -1,139 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - - -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -export enum _envoy_api_v2_route_RedirectAction_RedirectResponseCode { - /** - * Moved Permanently HTTP Status Code - 301. - */ - MOVED_PERMANENTLY = 0, - /** - * Found HTTP Status Code - 302. - */ - FOUND = 1, - /** - * See Other HTTP Status Code - 303. - */ - SEE_OTHER = 2, - /** - * Temporary Redirect HTTP Status Code - 307. - */ - TEMPORARY_REDIRECT = 3, - /** - * Permanent Redirect HTTP Status Code - 308. - */ - PERMANENT_REDIRECT = 4, -} - -/** - * [#next-free-field: 9] - */ -export interface RedirectAction { - /** - * The host portion of the URL will be swapped with this value. - */ - 'host_redirect'?: (string); - /** - * The path portion of the URL will be swapped with this value. - */ - 'path_redirect'?: (string); - /** - * The HTTP status code to use in the redirect response. The default response - * code is MOVED_PERMANENTLY (301). - */ - 'response_code'?: (_envoy_api_v2_route_RedirectAction_RedirectResponseCode | keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); - /** - * The scheme portion of the URL will be swapped with "https". - */ - 'https_redirect'?: (boolean); - /** - * Indicates that during redirection, the matched prefix (or path) - * should be swapped with this value. This option allows redirect URLs be dynamically created - * based on the request. - * - * .. attention:: - * - * Pay attention to the use of trailing slashes as mentioned in - * :ref:`RouteAction's prefix_rewrite `. - */ - 'prefix_rewrite'?: (string); - /** - * Indicates that during redirection, the query portion of the URL will - * be removed. Default value is false. - */ - 'strip_query'?: (boolean); - /** - * The scheme portion of the URL will be swapped with this value. - */ - 'scheme_redirect'?: (string); - /** - * The port value of the URL will be swapped with this value. - */ - 'port_redirect'?: (number); - /** - * When the scheme redirection take place, the following rules apply: - * 1. If the source URI scheme is `http` and the port is explicitly - * set to `:80`, the port will be removed after the redirection - * 2. If the source URI scheme is `https` and the port is explicitly - * set to `:443`, the port will be removed after the redirection - */ - 'scheme_rewrite_specifier'?: "https_redirect"|"scheme_redirect"; - 'path_rewrite_specifier'?: "path_redirect"|"prefix_rewrite"; -} - -/** - * [#next-free-field: 9] - */ -export interface RedirectAction__Output { - /** - * The host portion of the URL will be swapped with this value. - */ - 'host_redirect': (string); - /** - * The path portion of the URL will be swapped with this value. - */ - 'path_redirect'?: (string); - /** - * The HTTP status code to use in the redirect response. The default response - * code is MOVED_PERMANENTLY (301). - */ - 'response_code': (keyof typeof _envoy_api_v2_route_RedirectAction_RedirectResponseCode); - /** - * The scheme portion of the URL will be swapped with "https". - */ - 'https_redirect'?: (boolean); - /** - * Indicates that during redirection, the matched prefix (or path) - * should be swapped with this value. This option allows redirect URLs be dynamically created - * based on the request. - * - * .. attention:: - * - * Pay attention to the use of trailing slashes as mentioned in - * :ref:`RouteAction's prefix_rewrite `. - */ - 'prefix_rewrite'?: (string); - /** - * Indicates that during redirection, the query portion of the URL will - * be removed. Default value is false. - */ - 'strip_query': (boolean); - /** - * The scheme portion of the URL will be swapped with this value. - */ - 'scheme_redirect'?: (string); - /** - * The port value of the URL will be swapped with this value. - */ - 'port_redirect': (number); - /** - * When the scheme redirection take place, the following rules apply: - * 1. If the source URI scheme is `http` and the port is explicitly - * set to `:80`, the port will be removed after the redirection - * 2. If the source URI scheme is `https` and the port is explicitly - * set to `:443`, the port will be removed after the redirection - */ - 'scheme_rewrite_specifier': "https_redirect"|"scheme_redirect"; - 'path_rewrite_specifier': "path_redirect"|"prefix_rewrite"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts deleted file mode 100644 index 63b7deb5a..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RetryPolicy.ts +++ /dev/null @@ -1,218 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto - -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import type { Long } from '@grpc/proto-loader'; - -export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff { - /** - * Specifies the base interval between retries. This parameter is required and must be greater - * than zero. Values less than 1 ms are rounded up to 1 ms. - * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's - * back-off algorithm. - */ - 'base_interval'?: (_google_protobuf_Duration); - /** - * Specifies the maximum interval between retries. This parameter is optional, but must be - * greater than or equal to the `base_interval` if set. The default is 10 times the - * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion - * of Envoy's back-off algorithm. - */ - 'max_interval'?: (_google_protobuf_Duration); -} - -export interface _envoy_api_v2_route_RetryPolicy_RetryBackOff__Output { - /** - * Specifies the base interval between retries. This parameter is required and must be greater - * than zero. Values less than 1 ms are rounded up to 1 ms. - * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's - * back-off algorithm. - */ - 'base_interval'?: (_google_protobuf_Duration__Output); - /** - * Specifies the maximum interval between retries. This parameter is optional, but must be - * greater than or equal to the `base_interval` if set. The default is 10 times the - * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion - * of Envoy's back-off algorithm. - */ - 'max_interval'?: (_google_protobuf_Duration__Output); -} - -export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate { - 'name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); - 'config_type'?: "config"|"typed_config"; -} - -export interface _envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output { - 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); - 'config_type': "config"|"typed_config"; -} - -export interface _envoy_api_v2_route_RetryPolicy_RetryPriority { - 'name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); - 'config_type'?: "config"|"typed_config"; -} - -export interface _envoy_api_v2_route_RetryPolicy_RetryPriority__Output { - 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); - 'config_type': "config"|"typed_config"; -} - -/** - * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 11] - */ -export interface RetryPolicy { - /** - * Specifies the conditions under which retry takes place. These are the same - * conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and - * :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. - */ - 'retry_on'?: (string); - /** - * Specifies the allowed number of retries. This parameter is optional and - * defaults to 1. These are the same conditions documented for - * :ref:`config_http_filters_router_x-envoy-max-retries`. - */ - 'num_retries'?: (_google_protobuf_UInt32Value); - /** - * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The - * same conditions documented for - * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. - * - * .. note:: - * - * If left unspecified, Envoy will use the global - * :ref:`route timeout ` for the request. - * Consequently, when using a :ref:`5xx ` based - * retry policy, a request that times out will not be retried as the total timeout budget - * would have been exhausted. - */ - 'per_try_timeout'?: (_google_protobuf_Duration); - /** - * Specifies an implementation of a RetryPriority which is used to determine the - * distribution of load across priorities used for retries. Refer to - * :ref:`retry plugin configuration ` for more details. - */ - 'retry_priority'?: (_envoy_api_v2_route_RetryPolicy_RetryPriority); - /** - * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host - * for retries. If any of the predicates reject the host, host selection will be reattempted. - * Refer to :ref:`retry plugin configuration ` for more - * details. - */ - 'retry_host_predicate'?: (_envoy_api_v2_route_RetryPolicy_RetryHostPredicate)[]; - /** - * The maximum number of times host selection will be reattempted before giving up, at which - * point the host that was last selected will be routed to. If unspecified, this will default to - * retrying once. - */ - 'host_selection_retry_max_attempts'?: (number | string | Long); - /** - * HTTP status codes that should trigger a retry in addition to those specified by retry_on. - */ - 'retriable_status_codes'?: (number)[]; - /** - * Specifies parameters that control retry back off. This parameter is optional, in which case the - * default base interval is 25 milliseconds or, if set, the current value of the - * `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times - * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` - * describes Envoy's back-off algorithm. - */ - 'retry_back_off'?: (_envoy_api_v2_route_RetryPolicy_RetryBackOff); - /** - * HTTP response headers that trigger a retry if present in the response. A retry will be - * triggered if any of the header matches match the upstream response headers. - * The field is only consulted if 'retriable-headers' retry policy is active. - */ - 'retriable_headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; - /** - * HTTP headers which must be present in the request for retries to be attempted. - */ - 'retriable_request_headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; -} - -/** - * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 11] - */ -export interface RetryPolicy__Output { - /** - * Specifies the conditions under which retry takes place. These are the same - * conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and - * :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. - */ - 'retry_on': (string); - /** - * Specifies the allowed number of retries. This parameter is optional and - * defaults to 1. These are the same conditions documented for - * :ref:`config_http_filters_router_x-envoy-max-retries`. - */ - 'num_retries'?: (_google_protobuf_UInt32Value__Output); - /** - * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The - * same conditions documented for - * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. - * - * .. note:: - * - * If left unspecified, Envoy will use the global - * :ref:`route timeout ` for the request. - * Consequently, when using a :ref:`5xx ` based - * retry policy, a request that times out will not be retried as the total timeout budget - * would have been exhausted. - */ - 'per_try_timeout'?: (_google_protobuf_Duration__Output); - /** - * Specifies an implementation of a RetryPriority which is used to determine the - * distribution of load across priorities used for retries. Refer to - * :ref:`retry plugin configuration ` for more details. - */ - 'retry_priority'?: (_envoy_api_v2_route_RetryPolicy_RetryPriority__Output); - /** - * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host - * for retries. If any of the predicates reject the host, host selection will be reattempted. - * Refer to :ref:`retry plugin configuration ` for more - * details. - */ - 'retry_host_predicate': (_envoy_api_v2_route_RetryPolicy_RetryHostPredicate__Output)[]; - /** - * The maximum number of times host selection will be reattempted before giving up, at which - * point the host that was last selected will be routed to. If unspecified, this will default to - * retrying once. - */ - 'host_selection_retry_max_attempts': (string); - /** - * HTTP status codes that should trigger a retry in addition to those specified by retry_on. - */ - 'retriable_status_codes': (number)[]; - /** - * Specifies parameters that control retry back off. This parameter is optional, in which case the - * default base interval is 25 milliseconds or, if set, the current value of the - * `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times - * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` - * describes Envoy's back-off algorithm. - */ - 'retry_back_off'?: (_envoy_api_v2_route_RetryPolicy_RetryBackOff__Output); - /** - * HTTP response headers that trigger a retry if present in the response. A retry will be - * triggered if any of the header matches match the upstream response headers. - * The field is only consulted if 'retriable-headers' retry policy is active. - */ - 'retriable_headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; - /** - * HTTP headers which must be present in the request for retries to be attempted. - */ - 'retriable_request_headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts similarity index 54% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts index 82e056a4b..413f569ce 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLog.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts @@ -1,8 +1,7 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto -import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; +import type { AccessLogFilter as _envoy_config_accesslog_v3_AccessLogFilter, AccessLogFilter__Output as _envoy_config_accesslog_v3_AccessLogFilter__Output } from '../../../../envoy/config/accesslog/v3/AccessLogFilter'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface AccessLog { /** @@ -17,21 +16,20 @@ export interface AccessLog { /** * Filter which is used to determine if the access log needs to be written. */ - 'filter'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter); - 'config'?: (_google_protobuf_Struct); + 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter); 'typed_config'?: (_google_protobuf_Any); /** - * Custom configuration that depends on the access log being instantiated. Built-in - * configurations include: + * Custom configuration that depends on the access log being instantiated. + * Built-in configurations include: * * #. "envoy.access_loggers.file": :ref:`FileAccessLog - * ` + * ` * #. "envoy.access_loggers.http_grpc": :ref:`HttpGrpcAccessLogConfig - * ` + * ` * #. "envoy.access_loggers.tcp_grpc": :ref:`TcpGrpcAccessLogConfig - * ` + * ` */ - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } export interface AccessLog__Output { @@ -47,19 +45,18 @@ export interface AccessLog__Output { /** * Filter which is used to determine if the access log needs to be written. */ - 'filter'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output); - 'config'?: (_google_protobuf_Struct__Output); + 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** - * Custom configuration that depends on the access log being instantiated. Built-in - * configurations include: + * Custom configuration that depends on the access log being instantiated. + * Built-in configurations include: * * #. "envoy.access_loggers.file": :ref:`FileAccessLog - * ` + * ` * #. "envoy.access_loggers.http_grpc": :ref:`HttpGrpcAccessLogConfig - * ` + * ` * #. "envoy.access_loggers.tcp_grpc": :ref:`TcpGrpcAccessLogConfig - * ` + * ` */ - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts new file mode 100644 index 000000000..9470b6eaa --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts @@ -0,0 +1,124 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { StatusCodeFilter as _envoy_config_accesslog_v3_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_accesslog_v3_StatusCodeFilter__Output } from '../../../../envoy/config/accesslog/v3/StatusCodeFilter'; +import type { DurationFilter as _envoy_config_accesslog_v3_DurationFilter, DurationFilter__Output as _envoy_config_accesslog_v3_DurationFilter__Output } from '../../../../envoy/config/accesslog/v3/DurationFilter'; +import type { NotHealthCheckFilter as _envoy_config_accesslog_v3_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_accesslog_v3_NotHealthCheckFilter__Output } from '../../../../envoy/config/accesslog/v3/NotHealthCheckFilter'; +import type { TraceableFilter as _envoy_config_accesslog_v3_TraceableFilter, TraceableFilter__Output as _envoy_config_accesslog_v3_TraceableFilter__Output } from '../../../../envoy/config/accesslog/v3/TraceableFilter'; +import type { RuntimeFilter as _envoy_config_accesslog_v3_RuntimeFilter, RuntimeFilter__Output as _envoy_config_accesslog_v3_RuntimeFilter__Output } from '../../../../envoy/config/accesslog/v3/RuntimeFilter'; +import type { AndFilter as _envoy_config_accesslog_v3_AndFilter, AndFilter__Output as _envoy_config_accesslog_v3_AndFilter__Output } from '../../../../envoy/config/accesslog/v3/AndFilter'; +import type { OrFilter as _envoy_config_accesslog_v3_OrFilter, OrFilter__Output as _envoy_config_accesslog_v3_OrFilter__Output } from '../../../../envoy/config/accesslog/v3/OrFilter'; +import type { HeaderFilter as _envoy_config_accesslog_v3_HeaderFilter, HeaderFilter__Output as _envoy_config_accesslog_v3_HeaderFilter__Output } from '../../../../envoy/config/accesslog/v3/HeaderFilter'; +import type { ResponseFlagFilter as _envoy_config_accesslog_v3_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_accesslog_v3_ResponseFlagFilter__Output } from '../../../../envoy/config/accesslog/v3/ResponseFlagFilter'; +import type { GrpcStatusFilter as _envoy_config_accesslog_v3_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_accesslog_v3_GrpcStatusFilter__Output } from '../../../../envoy/config/accesslog/v3/GrpcStatusFilter'; +import type { ExtensionFilter as _envoy_config_accesslog_v3_ExtensionFilter, ExtensionFilter__Output as _envoy_config_accesslog_v3_ExtensionFilter__Output } from '../../../../envoy/config/accesslog/v3/ExtensionFilter'; +import type { MetadataFilter as _envoy_config_accesslog_v3_MetadataFilter, MetadataFilter__Output as _envoy_config_accesslog_v3_MetadataFilter__Output } from '../../../../envoy/config/accesslog/v3/MetadataFilter'; + +/** + * [#next-free-field: 13] + */ +export interface AccessLogFilter { + /** + * Status code filter. + */ + 'status_code_filter'?: (_envoy_config_accesslog_v3_StatusCodeFilter); + /** + * Duration filter. + */ + 'duration_filter'?: (_envoy_config_accesslog_v3_DurationFilter); + /** + * Not health check filter. + */ + 'not_health_check_filter'?: (_envoy_config_accesslog_v3_NotHealthCheckFilter); + /** + * Traceable filter. + */ + 'traceable_filter'?: (_envoy_config_accesslog_v3_TraceableFilter); + /** + * Runtime filter. + */ + 'runtime_filter'?: (_envoy_config_accesslog_v3_RuntimeFilter); + /** + * And filter. + */ + 'and_filter'?: (_envoy_config_accesslog_v3_AndFilter); + /** + * Or filter. + */ + 'or_filter'?: (_envoy_config_accesslog_v3_OrFilter); + /** + * Header filter. + */ + 'header_filter'?: (_envoy_config_accesslog_v3_HeaderFilter); + /** + * Response flag filter. + */ + 'response_flag_filter'?: (_envoy_config_accesslog_v3_ResponseFlagFilter); + /** + * gRPC status filter. + */ + 'grpc_status_filter'?: (_envoy_config_accesslog_v3_GrpcStatusFilter); + /** + * Extension filter. + */ + 'extension_filter'?: (_envoy_config_accesslog_v3_ExtensionFilter); + /** + * Metadata Filter + */ + 'metadata_filter'?: (_envoy_config_accesslog_v3_MetadataFilter); + 'filter_specifier'?: "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"|"metadata_filter"; +} + +/** + * [#next-free-field: 13] + */ +export interface AccessLogFilter__Output { + /** + * Status code filter. + */ + 'status_code_filter'?: (_envoy_config_accesslog_v3_StatusCodeFilter__Output); + /** + * Duration filter. + */ + 'duration_filter'?: (_envoy_config_accesslog_v3_DurationFilter__Output); + /** + * Not health check filter. + */ + 'not_health_check_filter'?: (_envoy_config_accesslog_v3_NotHealthCheckFilter__Output); + /** + * Traceable filter. + */ + 'traceable_filter'?: (_envoy_config_accesslog_v3_TraceableFilter__Output); + /** + * Runtime filter. + */ + 'runtime_filter'?: (_envoy_config_accesslog_v3_RuntimeFilter__Output); + /** + * And filter. + */ + 'and_filter'?: (_envoy_config_accesslog_v3_AndFilter__Output); + /** + * Or filter. + */ + 'or_filter'?: (_envoy_config_accesslog_v3_OrFilter__Output); + /** + * Header filter. + */ + 'header_filter'?: (_envoy_config_accesslog_v3_HeaderFilter__Output); + /** + * Response flag filter. + */ + 'response_flag_filter'?: (_envoy_config_accesslog_v3_ResponseFlagFilter__Output); + /** + * gRPC status filter. + */ + 'grpc_status_filter'?: (_envoy_config_accesslog_v3_GrpcStatusFilter__Output); + /** + * Extension filter. + */ + 'extension_filter'?: (_envoy_config_accesslog_v3_ExtensionFilter__Output); + /** + * Metadata Filter + */ + 'metadata_filter'?: (_envoy_config_accesslog_v3_MetadataFilter__Output); + 'filter_specifier': "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"|"metadata_filter"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AndFilter.ts similarity index 51% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AndFilter.ts index 7cf1cb98c..c3c2ac8b4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AndFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AndFilter.ts @@ -1,6 +1,6 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto -import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +import type { AccessLogFilter as _envoy_config_accesslog_v3_AccessLogFilter, AccessLogFilter__Output as _envoy_config_accesslog_v3_AccessLogFilter__Output } from '../../../../envoy/config/accesslog/v3/AccessLogFilter'; /** * Performs a logical “and†operation on the result of each filter in filters. @@ -8,7 +8,7 @@ import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilt * filter returns false immediately. */ export interface AndFilter { - 'filters'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter)[]; + 'filters'?: (_envoy_config_accesslog_v3_AccessLogFilter)[]; } /** @@ -17,5 +17,5 @@ export interface AndFilter { * filter returns false immediately. */ export interface AndFilter__Output { - 'filters': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output)[]; + 'filters': (_envoy_config_accesslog_v3_AccessLogFilter__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts new file mode 100644 index 000000000..118a47a75 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts @@ -0,0 +1,48 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { RuntimeUInt32 as _envoy_config_core_v3_RuntimeUInt32, RuntimeUInt32__Output as _envoy_config_core_v3_RuntimeUInt32__Output } from '../../../../envoy/config/core/v3/RuntimeUInt32'; + +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +export enum _envoy_config_accesslog_v3_ComparisonFilter_Op { + /** + * = + */ + EQ = 0, + /** + * >= + */ + GE = 1, + /** + * <= + */ + LE = 2, +} + +/** + * Filter on an integer comparison. + */ +export interface ComparisonFilter { + /** + * Comparison operator. + */ + 'op'?: (_envoy_config_accesslog_v3_ComparisonFilter_Op | keyof typeof _envoy_config_accesslog_v3_ComparisonFilter_Op); + /** + * Value to compare against. + */ + 'value'?: (_envoy_config_core_v3_RuntimeUInt32); +} + +/** + * Filter on an integer comparison. + */ +export interface ComparisonFilter__Output { + /** + * Comparison operator. + */ + 'op': (keyof typeof _envoy_config_accesslog_v3_ComparisonFilter_Op); + /** + * Value to compare against. + */ + 'value'?: (_envoy_config_core_v3_RuntimeUInt32__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts new file mode 100644 index 000000000..03b0500e8 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts @@ -0,0 +1,23 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { ComparisonFilter as _envoy_config_accesslog_v3_ComparisonFilter, ComparisonFilter__Output as _envoy_config_accesslog_v3_ComparisonFilter__Output } from '../../../../envoy/config/accesslog/v3/ComparisonFilter'; + +/** + * Filters on total request duration in milliseconds. + */ +export interface DurationFilter { + /** + * Comparison. + */ + 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter); +} + +/** + * Filters on total request duration in milliseconds. + */ +export interface DurationFilter__Output { + /** + * Comparison. + */ + 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts similarity index 64% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts index 184c76eb6..127618eef 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ExtensionFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts @@ -1,7 +1,6 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * Extension filter is statically registered at runtime. @@ -12,12 +11,11 @@ export interface ExtensionFilter { * match a statically registered filter. */ 'name'?: (string); - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); /** * Custom configuration that depends on the filter being instantiated. */ - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } /** @@ -29,10 +27,9 @@ export interface ExtensionFilter__Output { * match a statically registered filter. */ 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** * Custom configuration that depends on the filter being instantiated. */ - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/GrpcStatusFilter.ts similarity index 51% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/GrpcStatusFilter.ts index 8e8b0981e..f7ccc8052 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/GrpcStatusFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/GrpcStatusFilter.ts @@ -1,9 +1,9 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto -export enum _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status { +export enum _envoy_config_accesslog_v3_GrpcStatusFilter_Status { OK = 0, CANCELED = 1, UNKNOWN = 2, @@ -24,33 +24,35 @@ export enum _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status { } /** - * Filters gRPC requests based on their response status. If a gRPC status is not provided, the - * filter will infer the status from the HTTP status code. + * Filters gRPC requests based on their response status. If a gRPC status is not + * provided, the filter will infer the status from the HTTP status code. */ export interface GrpcStatusFilter { /** * Logs only responses that have any one of the gRPC statuses in this field. */ - 'statuses'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status | keyof typeof _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status)[]; + 'statuses'?: (_envoy_config_accesslog_v3_GrpcStatusFilter_Status | keyof typeof _envoy_config_accesslog_v3_GrpcStatusFilter_Status)[]; /** - * If included and set to true, the filter will instead block all responses with a gRPC status or - * inferred gRPC status enumerated in statuses, and allow all other responses. + * If included and set to true, the filter will instead block all responses + * with a gRPC status or inferred gRPC status enumerated in statuses, and + * allow all other responses. */ 'exclude'?: (boolean); } /** - * Filters gRPC requests based on their response status. If a gRPC status is not provided, the - * filter will infer the status from the HTTP status code. + * Filters gRPC requests based on their response status. If a gRPC status is not + * provided, the filter will infer the status from the HTTP status code. */ export interface GrpcStatusFilter__Output { /** * Logs only responses that have any one of the gRPC statuses in this field. */ - 'statuses': (keyof typeof _envoy_config_filter_accesslog_v2_GrpcStatusFilter_Status)[]; + 'statuses': (keyof typeof _envoy_config_accesslog_v3_GrpcStatusFilter_Status)[]; /** - * If included and set to true, the filter will instead block all responses with a gRPC status or - * inferred gRPC status enumerated in statuses, and allow all other responses. + * If included and set to true, the filter will instead block all responses + * with a gRPC status or inferred gRPC status enumerated in statuses, and + * allow all other responses. */ 'exclude': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts new file mode 100644 index 000000000..9cda884b3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts @@ -0,0 +1,25 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; + +/** + * Filters requests based on the presence or value of a request header. + */ +export interface HeaderFilter { + /** + * Only requests with a header which matches the specified HeaderMatcher will + * pass the filter check. + */ + 'header'?: (_envoy_config_route_v3_HeaderMatcher); +} + +/** + * Filters requests based on the presence or value of a request header. + */ +export interface HeaderFilter__Output { + /** + * Only requests with a header which matches the specified HeaderMatcher will + * pass the filter check. + */ + 'header'?: (_envoy_config_route_v3_HeaderMatcher__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts new file mode 100644 index 000000000..7fdd1d447 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts @@ -0,0 +1,48 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { MetadataMatcher as _envoy_type_matcher_v3_MetadataMatcher, MetadataMatcher__Output as _envoy_type_matcher_v3_MetadataMatcher__Output } from '../../../../envoy/type/matcher/v3/MetadataMatcher'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +/** + * Filters based on matching dynamic metadata. + * If the matcher path and key correspond to an existing key in dynamic + * metadata, the request is logged only if the matcher value is equal to the + * metadata value. If the matcher path and key *do not* correspond to an + * existing key in dynamic metadata, the request is logged only if + * match_if_key_not_found is "true" or unset. + */ +export interface MetadataFilter { + /** + * Matcher to check metadata for specified value. For example, to match on the + * access_log_hint metadata, set the filter to "envoy.common" and the path to + * "access_log_hint", and the value to "true". + */ + 'matcher'?: (_envoy_type_matcher_v3_MetadataMatcher); + /** + * Default result if the key does not exist in dynamic metadata: if unset or + * true, then log; if false, then don't log. + */ + 'match_if_key_not_found'?: (_google_protobuf_BoolValue); +} + +/** + * Filters based on matching dynamic metadata. + * If the matcher path and key correspond to an existing key in dynamic + * metadata, the request is logged only if the matcher value is equal to the + * metadata value. If the matcher path and key *do not* correspond to an + * existing key in dynamic metadata, the request is logged only if + * match_if_key_not_found is "true" or unset. + */ +export interface MetadataFilter__Output { + /** + * Matcher to check metadata for specified value. For example, to match on the + * access_log_hint metadata, set the filter to "envoy.common" and the path to + * "access_log_hint", and the value to "true". + */ + 'matcher'?: (_envoy_type_matcher_v3_MetadataMatcher__Output); + /** + * Default result if the key does not exist in dynamic metadata: if unset or + * true, then log; if false, then don't log. + */ + 'match_if_key_not_found'?: (_google_protobuf_BoolValue__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/NotHealthCheckFilter.ts similarity index 81% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/NotHealthCheckFilter.ts index 3de68f081..40728fc34 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/NotHealthCheckFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/NotHealthCheckFilter.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/OrFilter.ts similarity index 50% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/OrFilter.ts index 859c1218c..1756d3ad5 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/OrFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/OrFilter.ts @@ -1,6 +1,6 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto -import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilter, AccessLogFilter__Output as _envoy_config_filter_accesslog_v2_AccessLogFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AccessLogFilter'; +import type { AccessLogFilter as _envoy_config_accesslog_v3_AccessLogFilter, AccessLogFilter__Output as _envoy_config_accesslog_v3_AccessLogFilter__Output } from '../../../../envoy/config/accesslog/v3/AccessLogFilter'; /** * Performs a logical “or†operation on the result of each individual filter. @@ -8,7 +8,7 @@ import type { AccessLogFilter as _envoy_config_filter_accesslog_v2_AccessLogFilt * filter returns true immediately. */ export interface OrFilter { - 'filters'?: (_envoy_config_filter_accesslog_v2_AccessLogFilter)[]; + 'filters'?: (_envoy_config_accesslog_v3_AccessLogFilter)[]; } /** @@ -17,5 +17,5 @@ export interface OrFilter { * filter returns true immediately. */ export interface OrFilter__Output { - 'filters': (_envoy_config_filter_accesslog_v2_AccessLogFilter__Output)[]; + 'filters': (_envoy_config_accesslog_v3_AccessLogFilter__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ResponseFlagFilter.ts similarity index 51% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ResponseFlagFilter.ts index 280fbb26a..c45a63054 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ResponseFlagFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ResponseFlagFilter.ts @@ -1,16 +1,17 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto /** * Filters requests that received responses with an Envoy response flag set. * A list of the response flags can be found - * in the access log formatter :ref:`documentation`. + * in the access log formatter + * :ref:`documentation`. */ export interface ResponseFlagFilter { /** - * Only responses with the any of the flags listed in this field will be logged. - * This field is optional. If it is not specified, then any response flag will pass - * the filter check. + * Only responses with the any of the flags listed in this field will be + * logged. This field is optional. If it is not specified, then any response + * flag will pass the filter check. */ 'flags'?: (string)[]; } @@ -18,13 +19,14 @@ export interface ResponseFlagFilter { /** * Filters requests that received responses with an Envoy response flag set. * A list of the response flags can be found - * in the access log formatter :ref:`documentation`. + * in the access log formatter + * :ref:`documentation`. */ export interface ResponseFlagFilter__Output { /** - * Only responses with the any of the flags listed in this field will be logged. - * This field is optional. If it is not specified, then any response flag will pass - * the filter check. + * Only responses with the any of the flags listed in this field will be + * logged. This field is optional. If it is not specified, then any response + * flag will pass the filter check. */ 'flags': (string)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts new file mode 100644 index 000000000..9388f49ec --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts @@ -0,0 +1,73 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../envoy/type/v3/FractionalPercent'; + +/** + * Filters for random sampling of requests. + */ +export interface RuntimeFilter { + /** + * Runtime key to get an optional overridden numerator for use in the + * *percent_sampled* field. If found in runtime, this value will replace the + * default numerator. + */ + 'runtime_key'?: (string); + /** + * The default sampling percentage. If not specified, defaults to 0% with + * denominator of 100. + */ + 'percent_sampled'?: (_envoy_type_v3_FractionalPercent); + /** + * By default, sampling pivots on the header + * :ref:`x-request-id` being + * present. If :ref:`x-request-id` + * is present, the filter will consistently sample across multiple hosts based + * on the runtime key value and the value extracted from + * :ref:`x-request-id`. If it is + * missing, or *use_independent_randomness* is set to true, the filter will + * randomly sample based on the runtime key value alone. + * *use_independent_randomness* can be used for logging kill switches within + * complex nested :ref:`AndFilter + * ` and :ref:`OrFilter + * ` blocks that are easier to + * reason about from a probability perspective (i.e., setting to true will + * cause the filter to behave like an independent random variable when + * composed within logical operator filters). + */ + 'use_independent_randomness'?: (boolean); +} + +/** + * Filters for random sampling of requests. + */ +export interface RuntimeFilter__Output { + /** + * Runtime key to get an optional overridden numerator for use in the + * *percent_sampled* field. If found in runtime, this value will replace the + * default numerator. + */ + 'runtime_key': (string); + /** + * The default sampling percentage. If not specified, defaults to 0% with + * denominator of 100. + */ + 'percent_sampled'?: (_envoy_type_v3_FractionalPercent__Output); + /** + * By default, sampling pivots on the header + * :ref:`x-request-id` being + * present. If :ref:`x-request-id` + * is present, the filter will consistently sample across multiple hosts based + * on the runtime key value and the value extracted from + * :ref:`x-request-id`. If it is + * missing, or *use_independent_randomness* is set to true, the filter will + * randomly sample based on the runtime key value alone. + * *use_independent_randomness* can be used for logging kill switches within + * complex nested :ref:`AndFilter + * ` and :ref:`OrFilter + * ` blocks that are easier to + * reason about from a probability perspective (i.e., setting to true will + * cause the filter to behave like an independent random variable when + * composed within logical operator filters). + */ + 'use_independent_randomness': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts new file mode 100644 index 000000000..313ed86ca --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts @@ -0,0 +1,23 @@ +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto + +import type { ComparisonFilter as _envoy_config_accesslog_v3_ComparisonFilter, ComparisonFilter__Output as _envoy_config_accesslog_v3_ComparisonFilter__Output } from '../../../../envoy/config/accesslog/v3/ComparisonFilter'; + +/** + * Filters on HTTP response/status code. + */ +export interface StatusCodeFilter { + /** + * Comparison. + */ + 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter); +} + +/** + * Filters on HTTP response/status code. + */ +export interface StatusCodeFilter__Output { + /** + * Comparison. + */ + 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/TraceableFilter.ts similarity index 81% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/TraceableFilter.ts index 8de24656a..c2b3a646b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/TraceableFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/TraceableFilter.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto +// Original file: deps/envoy-api/envoy/config/accesslog/v3/accesslog.proto /** diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts similarity index 75% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts rename to packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts index edf946590..c4f4add69 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/CircuitBreakers.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts @@ -1,10 +1,10 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster/circuit_breaker.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/circuit_breaker.proto -import type { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; +import type { RoutingPriority as _envoy_config_core_v3_RoutingPriority } from '../../../../envoy/config/core/v3/RoutingPriority'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../envoy/type/Percent'; +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../envoy/type/v3/Percent'; -export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { +export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget { /** * Specifies the limit on concurrent retries as a percentage of the sum of active requests and * active pending requests. For example, if there are 100 active requests and the @@ -12,7 +12,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { * * This parameter is optional. Defaults to 20%. */ - 'budget_percent'?: (_envoy_type_Percent); + 'budget_percent'?: (_envoy_type_v3_Percent); /** * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the * number of active retries may never go below this number. @@ -22,7 +22,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget { 'min_retry_concurrency'?: (_google_protobuf_UInt32Value); } -export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output { +export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget__Output { /** * Specifies the limit on concurrent retries as a percentage of the sum of active requests and * active pending requests. For example, if there are 100 active requests and the @@ -30,7 +30,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__O * * This parameter is optional. Defaults to 20%. */ - 'budget_percent'?: (_envoy_type_Percent__Output); + 'budget_percent'?: (_envoy_type_v3_Percent__Output); /** * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the * number of active retries may never go below this number. @@ -42,15 +42,15 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__O /** * A Thresholds defines CircuitBreaker settings for a - * :ref:`RoutingPriority`. + * :ref:`RoutingPriority`. * [#next-free-field: 9] */ -export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds { +export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds { /** - * The :ref:`RoutingPriority` + * The :ref:`RoutingPriority` * the specified CircuitBreaker settings apply to. */ - 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); + 'priority'?: (_envoy_config_core_v3_RoutingPriority | keyof typeof _envoy_config_core_v3_RoutingPriority); /** * The maximum number of connections that Envoy will make to the upstream * cluster. If not specified, the default is 1024. @@ -80,7 +80,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds { * If this field is set, the retry budget will override any configured retry circuit * breaker. */ - 'retry_budget'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget); + 'retry_budget'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget); /** * If track_remaining is true, then stats will be published that expose * the number of resources remaining until the circuit breakers open. If @@ -104,15 +104,15 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds { /** * A Thresholds defines CircuitBreaker settings for a - * :ref:`RoutingPriority`. + * :ref:`RoutingPriority`. * [#next-free-field: 9] */ -export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { +export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output { /** - * The :ref:`RoutingPriority` + * The :ref:`RoutingPriority` * the specified CircuitBreaker settings apply to. */ - 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); + 'priority': (keyof typeof _envoy_config_core_v3_RoutingPriority); /** * The maximum number of connections that Envoy will make to the upstream * cluster. If not specified, the default is 1024. @@ -142,7 +142,7 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { * If this field is set, the retry budget will override any configured retry circuit * breaker. */ - 'retry_budget'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds_RetryBudget__Output); + 'retry_budget'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget__Output); /** * If track_remaining is true, then stats will be published that expose * the number of resources remaining until the circuit breakers open. If @@ -170,13 +170,13 @@ export interface _envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output { */ export interface CircuitBreakers { /** - * If multiple :ref:`Thresholds` - * are defined with the same :ref:`RoutingPriority`, + * If multiple :ref:`Thresholds` + * are defined with the same :ref:`RoutingPriority`, * the first one in the list is used. If no Thresholds is defined for a given - * :ref:`RoutingPriority`, the default values + * :ref:`RoutingPriority`, the default values * are used. */ - 'thresholds'?: (_envoy_api_v2_cluster_CircuitBreakers_Thresholds)[]; + 'thresholds'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds)[]; } /** @@ -185,11 +185,11 @@ export interface CircuitBreakers { */ export interface CircuitBreakers__Output { /** - * If multiple :ref:`Thresholds` - * are defined with the same :ref:`RoutingPriority`, + * If multiple :ref:`Thresholds` + * are defined with the same :ref:`RoutingPriority`, * the first one in the list is used. If no Thresholds is defined for a given - * :ref:`RoutingPriority`, the default values + * :ref:`RoutingPriority`, the default values * are used. */ - 'thresholds': (_envoy_api_v2_cluster_CircuitBreakers_Thresholds__Output)[]; + 'thresholds': (_envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts similarity index 50% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts rename to packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts index f077d2edc..fa76fba89 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Cluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts @@ -1,36 +1,39 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; -import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; -import type { HealthCheck as _envoy_api_v2_core_HealthCheck, HealthCheck__Output as _envoy_api_v2_core_HealthCheck__Output } from '../../../envoy/api/v2/core/HealthCheck'; -import type { CircuitBreakers as _envoy_api_v2_cluster_CircuitBreakers, CircuitBreakers__Output as _envoy_api_v2_cluster_CircuitBreakers__Output } from '../../../envoy/api/v2/cluster/CircuitBreakers'; -import type { UpstreamTlsContext as _envoy_api_v2_auth_UpstreamTlsContext, UpstreamTlsContext__Output as _envoy_api_v2_auth_UpstreamTlsContext__Output } from '../../../envoy/api/v2/auth/UpstreamTlsContext'; -import type { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http1ProtocolOptions'; -import type { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../envoy/api/v2/core/Http2ProtocolOptions'; -import type { OutlierDetection as _envoy_api_v2_cluster_OutlierDetection, OutlierDetection__Output as _envoy_api_v2_cluster_OutlierDetection__Output } from '../../../envoy/api/v2/cluster/OutlierDetection'; -import type { BindConfig as _envoy_api_v2_core_BindConfig, BindConfig__Output as _envoy_api_v2_core_BindConfig__Output } from '../../../envoy/api/v2/core/BindConfig'; -import type { TransportSocket as _envoy_api_v2_core_TransportSocket, TransportSocket__Output as _envoy_api_v2_core_TransportSocket__Output } from '../../../envoy/api/v2/core/TransportSocket'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; -import type { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../envoy/api/v2/core/HttpProtocolOptions'; -import type { UpstreamConnectionOptions as _envoy_api_v2_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_api_v2_UpstreamConnectionOptions__Output } from '../../../envoy/api/v2/UpstreamConnectionOptions'; -import type { ClusterLoadAssignment as _envoy_api_v2_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_api_v2_ClusterLoadAssignment__Output } from '../../../envoy/api/v2/ClusterLoadAssignment'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; -import type { Filter as _envoy_api_v2_cluster_Filter, Filter__Output as _envoy_api_v2_cluster_Filter__Output } from '../../../envoy/api/v2/cluster/Filter'; -import type { LoadBalancingPolicy as _envoy_api_v2_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_api_v2_LoadBalancingPolicy__Output } from '../../../envoy/api/v2/LoadBalancingPolicy'; -import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../envoy/api/v2/core/ConfigSource'; -import type { UpstreamHttpProtocolOptions as _envoy_api_v2_core_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_api_v2_core_UpstreamHttpProtocolOptions__Output } from '../../../envoy/api/v2/core/UpstreamHttpProtocolOptions'; -import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../google/protobuf/UInt64Value'; -import type { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../envoy/type/Percent'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { HealthCheck as _envoy_config_core_v3_HealthCheck, HealthCheck__Output as _envoy_config_core_v3_HealthCheck__Output } from '../../../../envoy/config/core/v3/HealthCheck'; +import type { CircuitBreakers as _envoy_config_cluster_v3_CircuitBreakers, CircuitBreakers__Output as _envoy_config_cluster_v3_CircuitBreakers__Output } from '../../../../envoy/config/cluster/v3/CircuitBreakers'; +import type { Http1ProtocolOptions as _envoy_config_core_v3_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_config_core_v3_Http1ProtocolOptions__Output } from '../../../../envoy/config/core/v3/Http1ProtocolOptions'; +import type { Http2ProtocolOptions as _envoy_config_core_v3_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_config_core_v3_Http2ProtocolOptions__Output } from '../../../../envoy/config/core/v3/Http2ProtocolOptions'; +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { OutlierDetection as _envoy_config_cluster_v3_OutlierDetection, OutlierDetection__Output as _envoy_config_cluster_v3_OutlierDetection__Output } from '../../../../envoy/config/cluster/v3/OutlierDetection'; +import type { BindConfig as _envoy_config_core_v3_BindConfig, BindConfig__Output as _envoy_config_core_v3_BindConfig__Output } from '../../../../envoy/config/core/v3/BindConfig'; +import type { TransportSocket as _envoy_config_core_v3_TransportSocket, TransportSocket__Output as _envoy_config_core_v3_TransportSocket__Output } from '../../../../envoy/config/core/v3/TransportSocket'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; +import type { HttpProtocolOptions as _envoy_config_core_v3_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_config_core_v3_HttpProtocolOptions__Output } from '../../../../envoy/config/core/v3/HttpProtocolOptions'; +import type { UpstreamConnectionOptions as _envoy_config_cluster_v3_UpstreamConnectionOptions, UpstreamConnectionOptions__Output as _envoy_config_cluster_v3_UpstreamConnectionOptions__Output } from '../../../../envoy/config/cluster/v3/UpstreamConnectionOptions'; +import type { ClusterLoadAssignment as _envoy_config_endpoint_v3_ClusterLoadAssignment, ClusterLoadAssignment__Output as _envoy_config_endpoint_v3_ClusterLoadAssignment__Output } from '../../../../envoy/config/endpoint/v3/ClusterLoadAssignment'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Filter as _envoy_config_cluster_v3_Filter, Filter__Output as _envoy_config_cluster_v3_Filter__Output } from '../../../../envoy/config/cluster/v3/Filter'; +import type { LoadBalancingPolicy as _envoy_config_cluster_v3_LoadBalancingPolicy, LoadBalancingPolicy__Output as _envoy_config_cluster_v3_LoadBalancingPolicy__Output } from '../../../../envoy/config/cluster/v3/LoadBalancingPolicy'; +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../envoy/config/core/v3/ConfigSource'; +import type { UpstreamHttpProtocolOptions as _envoy_config_core_v3_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_config_core_v3_UpstreamHttpProtocolOptions__Output } from '../../../../envoy/config/core/v3/UpstreamHttpProtocolOptions'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; +import type { TrackClusterStats as _envoy_config_cluster_v3_TrackClusterStats, TrackClusterStats__Output as _envoy_config_cluster_v3_TrackClusterStats__Output } from '../../../../envoy/config/cluster/v3/TrackClusterStats'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { RuntimeDouble as _envoy_config_core_v3_RuntimeDouble, RuntimeDouble__Output as _envoy_config_core_v3_RuntimeDouble__Output } from '../../../../envoy/config/core/v3/RuntimeDouble'; +import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../../google/protobuf/UInt64Value'; +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../envoy/type/v3/Percent'; +import type { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from '../../../../google/protobuf/DoubleValue'; import type { Long } from '@grpc/proto-loader'; -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto -export enum _envoy_api_v2_Cluster_ClusterProtocolSelection { +export enum _envoy_config_cluster_v3_Cluster_ClusterProtocolSelection { /** * Cluster can only operate on one of the possible upstream protocols (HTTP1.1, HTTP2). - * If :ref:`http2_protocol_options ` are + * If :ref:`http2_protocol_options ` are * present, HTTP2 will be used, otherwise HTTP1.1 will be used. */ USE_CONFIGURED_PROTOCOL = 0, @@ -44,7 +47,7 @@ export enum _envoy_api_v2_Cluster_ClusterProtocolSelection { * Common configuration for all load balancer implementations. * [#next-free-field: 8] */ -export interface _envoy_api_v2_Cluster_CommonLbConfig { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig { /** * Configures the :ref:`healthy panic threshold `. * If not specified, the default is 50%. @@ -53,9 +56,9 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig { * .. note:: * The specified percent will be truncated to the nearest 1%. */ - 'healthy_panic_threshold'?: (_envoy_type_Percent); - 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig); - 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig); + 'healthy_panic_threshold'?: (_envoy_type_v3_Percent); + 'zone_aware_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig); + 'locality_weighted_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig); /** * If set, all health check/weight/metadata updates that happen within this duration will be * merged and delivered in one shot when the duration expires. The start of the duration is when @@ -74,25 +77,9 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig { */ 'update_merge_window'?: (_google_protobuf_Duration); /** - * If set to true, Envoy will not consider new hosts when computing load balancing weights until - * they have been health checked for the first time. This will have no effect unless - * active health checking is also configured. - * - * Ignoring a host means that for any load balancing calculations that adjust weights based - * on the ratio of eligible hosts and total hosts (priority spillover, locality weighting and - * panic mode) Envoy will exclude these hosts in the denominator. - * - * For example, with hosts in two priorities P0 and P1, where P0 looks like - * {healthy, unhealthy (new), unhealthy (new)} - * and where P1 looks like - * {healthy, healthy} - * all traffic will still hit P0, as 1 / (3 - 2) = 1. - * - * Enabling this will allow scaling up the number of hosts for a given cluster without entering - * panic mode or triggering priority spillover, assuming the hosts pass the first health check. - * - * If panic mode is triggered, new hosts are still eligible for traffic; they simply do not - * contribute to the calculation when deciding whether panic mode is enabled or not. + * If set to true, Envoy will :ref:`exclude ` new hosts + * when computing load balancing weights until they have been health checked for the first time. + * This will have no effect unless active health checking is also configured. */ 'ignore_new_hosts_until_first_hc'?: (boolean); /** @@ -103,7 +90,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig { /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ - 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig); + 'consistent_hashing_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig); 'locality_config_specifier'?: "zone_aware_lb_config"|"locality_weighted_lb_config"; } @@ -111,7 +98,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig { * Common configuration for all load balancer implementations. * [#next-free-field: 8] */ -export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig__Output { /** * Configures the :ref:`healthy panic threshold `. * If not specified, the default is 50%. @@ -120,9 +107,9 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { * .. note:: * The specified percent will be truncated to the nearest 1%. */ - 'healthy_panic_threshold'?: (_envoy_type_Percent__Output); - 'zone_aware_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); - 'locality_weighted_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); + 'healthy_panic_threshold'?: (_envoy_type_v3_Percent__Output); + 'zone_aware_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); + 'locality_weighted_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); /** * If set, all health check/weight/metadata updates that happen within this duration will be * merged and delivered in one shot when the duration expires. The start of the duration is when @@ -141,25 +128,9 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { */ 'update_merge_window'?: (_google_protobuf_Duration__Output); /** - * If set to true, Envoy will not consider new hosts when computing load balancing weights until - * they have been health checked for the first time. This will have no effect unless - * active health checking is also configured. - * - * Ignoring a host means that for any load balancing calculations that adjust weights based - * on the ratio of eligible hosts and total hosts (priority spillover, locality weighting and - * panic mode) Envoy will exclude these hosts in the denominator. - * - * For example, with hosts in two priorities P0 and P1, where P0 looks like - * {healthy, unhealthy (new), unhealthy (new)} - * and where P1 looks like - * {healthy, healthy} - * all traffic will still hit P0, as 1 / (3 - 2) = 1. - * - * Enabling this will allow scaling up the number of hosts for a given cluster without entering - * panic mode or triggering priority spillover, assuming the hosts pass the first health check. - * - * If panic mode is triggered, new hosts are still eligible for traffic; they simply do not - * contribute to the calculation when deciding whether panic mode is enabled or not. + * If set to true, Envoy will :ref:`exclude ` new hosts + * when computing load balancing weights until they have been health checked for the first time. + * This will have no effect unless active health checking is also configured. */ 'ignore_new_hosts_until_first_hc': (boolean); /** @@ -170,36 +141,78 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig__Output { /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ - 'consistent_hashing_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); + 'consistent_hashing_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; } /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig { /** * If set to `true`, the cluster will use hostname instead of the resolved * address as the key to consistently hash to an upstream host. Only valid for StrictDNS clusters with hostnames which resolve to a single IP address. */ 'use_hostname_for_hashing'?: (boolean); + /** + * Configures percentage of average cluster load to bound per upstream host. For example, with a value of 150 + * no upstream host will get a load more than 1.5 times the average load of all the hosts in the cluster. + * If not specified, the load is not bounded for any upstream host. Typical value for this parameter is between 120 and 200. + * Minimum is 100. + * + * Applies to both Ring Hash and Maglev load balancers. + * + * This is implemented based on the method described in the paper https://arxiv.org/abs/1608.01350. For the specified + * `hash_balance_factor`, requests to any upstream host are capped at `hash_balance_factor/100` times the average number of requests + * across the cluster. When a request arrives for an upstream host that is currently serving at its max capacity, linear probing + * is used to identify an eligible host. Further, the linear probe is implemented using a random jump in hosts ring/table to identify + * the eligible host (this technique is as described in the paper https://arxiv.org/abs/1908.08762 - the random jump avoids the + * cascading overflow effect when choosing the next host in the ring/table). + * + * If weights are specified on the hosts, they are respected. + * + * This is an O(N) algorithm, unlike other load balancers. Using a lower `hash_balance_factor` results in more hosts + * being probed, so use a higher value if you require better performance. + */ + 'hash_balance_factor'?: (_google_protobuf_UInt32Value); } /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output { /** * If set to `true`, the cluster will use hostname instead of the resolved * address as the key to consistently hash to an upstream host. Only valid for StrictDNS clusters with hostnames which resolve to a single IP address. */ 'use_hostname_for_hashing': (boolean); + /** + * Configures percentage of average cluster load to bound per upstream host. For example, with a value of 150 + * no upstream host will get a load more than 1.5 times the average load of all the hosts in the cluster. + * If not specified, the load is not bounded for any upstream host. Typical value for this parameter is between 120 and 200. + * Minimum is 100. + * + * Applies to both Ring Hash and Maglev load balancers. + * + * This is implemented based on the method described in the paper https://arxiv.org/abs/1608.01350. For the specified + * `hash_balance_factor`, requests to any upstream host are capped at `hash_balance_factor/100` times the average number of requests + * across the cluster. When a request arrives for an upstream host that is currently serving at its max capacity, linear probing + * is used to identify an eligible host. Further, the linear probe is implemented using a random jump in hosts ring/table to identify + * the eligible host (this technique is as described in the paper https://arxiv.org/abs/1908.08762 - the random jump avoids the + * cascading overflow effect when choosing the next host in the ring/table). + * + * If weights are specified on the hosts, they are respected. + * + * This is an O(N) algorithm, unlike other load balancers. Using a lower `hash_balance_factor` results in more hosts + * being probed, so use a higher value if you require better performance. + */ + 'hash_balance_factor'?: (_google_protobuf_UInt32Value__Output); } /** * Extended cluster type. */ -export interface _envoy_api_v2_Cluster_CustomClusterType { +export interface _envoy_config_cluster_v3_Cluster_CustomClusterType { /** * The type of the cluster to instantiate. The name must match a supported cluster type. */ @@ -214,7 +227,7 @@ export interface _envoy_api_v2_Cluster_CustomClusterType { /** * Extended cluster type. */ -export interface _envoy_api_v2_Cluster_CustomClusterType__Output { +export interface _envoy_config_cluster_v3_Cluster_CustomClusterType__Output { /** * The type of the cluster to instantiate. The name must match a supported cluster type. */ @@ -226,13 +239,13 @@ export interface _envoy_api_v2_Cluster_CustomClusterType__Output { 'typed_config'?: (_google_protobuf_Any__Output); } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto /** * Refer to :ref:`service discovery type ` * for an explanation on each type. */ -export enum _envoy_api_v2_Cluster_DiscoveryType { +export enum _envoy_config_cluster_v3_Cluster_DiscoveryType { /** * Refer to the :ref:`static discovery type` * for an explanation. @@ -263,7 +276,7 @@ export enum _envoy_api_v2_Cluster_DiscoveryType { ORIGINAL_DST = 4, } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto /** * When V4_ONLY is selected, the DNS resolver will only perform a lookup for @@ -272,12 +285,12 @@ export enum _envoy_api_v2_Cluster_DiscoveryType { * specified, the DNS resolver will first perform a lookup for addresses in * the IPv6 family and fallback to a lookup for addresses in the IPv4 family. * For cluster types other than - * :ref:`STRICT_DNS` and - * :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS`, * this setting is * ignored. */ -export enum _envoy_api_v2_Cluster_DnsLookupFamily { +export enum _envoy_config_cluster_v3_Cluster_DnsLookupFamily { AUTO = 0, V4_ONLY = 1, V6_ONLY = 2, @@ -286,15 +299,15 @@ export enum _envoy_api_v2_Cluster_DnsLookupFamily { /** * Only valid when discovery type is EDS. */ -export interface _envoy_api_v2_Cluster_EdsClusterConfig { +export interface _envoy_config_cluster_v3_Cluster_EdsClusterConfig { /** * Configuration for the source of EDS updates for this Cluster. */ - 'eds_config'?: (_envoy_api_v2_core_ConfigSource); + 'eds_config'?: (_envoy_config_core_v3_ConfigSource); /** * Optional alternative to cluster name to present to EDS. This does not * have the same restrictions as cluster name, i.e. it may be arbitrary - * length. + * length. This may be a xdstp:// URL. */ 'service_name'?: (string); } @@ -302,25 +315,25 @@ export interface _envoy_api_v2_Cluster_EdsClusterConfig { /** * Only valid when discovery type is EDS. */ -export interface _envoy_api_v2_Cluster_EdsClusterConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_EdsClusterConfig__Output { /** * Configuration for the source of EDS updates for this Cluster. */ - 'eds_config'?: (_envoy_api_v2_core_ConfigSource__Output); + 'eds_config'?: (_envoy_config_core_v3_ConfigSource__Output); /** * Optional alternative to cluster name to present to EDS. This does not * have the same restrictions as cluster name, i.e. it may be arbitrary - * length. + * length. This may be a xdstp:// URL. */ 'service_name': (string); } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto /** * The hash function used to hash hosts onto the ketama ring. */ -export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { +export enum _envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction { /** * Use `xxHash `_, this is the default hash function. */ @@ -333,13 +346,13 @@ export enum _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction { MURMUR_HASH_2 = 1, } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto /** * Refer to :ref:`load balancer type ` architecture * overview section for information on each type. */ -export enum _envoy_api_v2_Cluster_LbPolicy { +export enum _envoy_config_cluster_v3_Cluster_LbPolicy { /** * Refer to the :ref:`round robin load balancing * policy` @@ -364,16 +377,6 @@ export enum _envoy_api_v2_Cluster_LbPolicy { * for an explanation. */ RANDOM = 3, - /** - * Refer to the :ref:`original destination load balancing - * policy` - * for an explanation. - * - * .. attention:: - * - * **This load balancing policy is deprecated**. Use CLUSTER_PROVIDED instead. - */ - ORIGINAL_DST_LB = 4, /** * Refer to the :ref:`Maglev load balancing policy` * for an explanation. @@ -387,7 +390,7 @@ export enum _envoy_api_v2_Cluster_LbPolicy { CLUSTER_PROVIDED = 6, /** * [#not-implemented-hide:] Use the new :ref:`load_balancing_policy - * ` field to determine the LB policy. + * ` field to determine the LB policy. * [#next-major-version: In the v3 API, we should consider deprecating the lb_policy field * and instead using the new load_balancing_policy field as the one and only mechanism for * configuring this.] @@ -400,22 +403,22 @@ export enum _envoy_api_v2_Cluster_LbPolicy { * endpoint metadata and selected by route and weighted cluster metadata. * [#next-free-field: 8] */ -export interface _envoy_api_v2_Cluster_LbSubsetConfig { +export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig { /** * The behavior used when no endpoint subset matches the selected route's * metadata. The value defaults to - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ - 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); + 'fallback_policy'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy | keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); /** * Specifies the default subset of endpoints used during fallback if * fallback_policy is - * :ref:`DEFAULT_SUBSET`. + * :ref:`DEFAULT_SUBSET`. * Each field in default_subset is * compared to the matching LbEndpoint.Metadata under the *envoy.lb* * namespace. It is valid for no hosts to match, in which case the behavior * is the same as a fallback_policy of - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ 'default_subset'?: (_google_protobuf_Struct); /** @@ -434,7 +437,7 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig { * weighted cluster contains the same keys and values as the subset's * metadata. The same host may appear in multiple subsets. */ - 'subset_selectors'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector)[]; + 'subset_selectors'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector)[]; /** * If true, routing to subsets will take into account the localities and locality weights of the * endpoints when making the routing decision. @@ -477,22 +480,22 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig { * endpoint metadata and selected by route and weighted cluster metadata. * [#next-free-field: 8] */ -export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig__Output { /** * The behavior used when no endpoint subset matches the selected route's * metadata. The value defaults to - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ - 'fallback_policy': (keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); + 'fallback_policy': (keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); /** * Specifies the default subset of endpoints used during fallback if * fallback_policy is - * :ref:`DEFAULT_SUBSET`. + * :ref:`DEFAULT_SUBSET`. * Each field in default_subset is * compared to the matching LbEndpoint.Metadata under the *envoy.lb* * namespace. It is valid for no hosts to match, in which case the behavior * is the same as a fallback_policy of - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ 'default_subset'?: (_google_protobuf_Struct__Output); /** @@ -511,7 +514,7 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { * weighted cluster contains the same keys and values as the subset's * metadata. The same host may appear in multiple subsets. */ - 'subset_selectors': (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector__Output)[]; + 'subset_selectors': (_envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector__Output)[]; /** * If true, routing to subsets will take into account the localities and locality weights of the * endpoints when making the routing decision. @@ -549,7 +552,7 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { 'list_as_any': (boolean); } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto /** * If NO_FALLBACK is selected, a result @@ -558,7 +561,7 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig__Output { * etc). If DEFAULT_SUBSET is selected, load balancing is performed over the * endpoints matching the values from the default_subset field. */ -export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy { +export enum _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy { NO_FALLBACK = 0, ANY_ENDPOINT = 1, DEFAULT_SUBSET = 2, @@ -567,25 +570,40 @@ export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy { /** * Specifications for subsets. */ -export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector { +export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector { /** * List of keys to match with the weighted cluster metadata. */ 'keys'?: (string)[]; + /** + * Selects a mode of operation in which each subset has only one host. This mode uses the same rules for + * choosing a host, but updating hosts is faster, especially for large numbers of hosts. + * + * If a match is found to a host, that host will be used regardless of priority levels, unless the host is unhealthy. + * + * Currently, this mode is only supported if `subset_selectors` has only one entry, and `keys` contains + * only one entry. + * + * When this mode is enabled, configurations that contain more than one host with the same metadata value for the single key in `keys` + * will use only one of the hosts with the given key; no requests will be routed to the others. The cluster gauge + * :ref:`lb_subsets_single_host_per_subset_duplicate` indicates how many duplicates are + * present in the current configuration. + */ + 'single_host_per_subset'?: (boolean); /** * The behavior used when no endpoint subset matches the selected route's * metadata. */ - 'fallback_policy'?: (_envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy | keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); + 'fallback_policy'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy | keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); /** * Subset of - * :ref:`keys` used by - * :ref:`KEYS_SUBSET` + * :ref:`keys` used by + * :ref:`KEYS_SUBSET` * fallback policy. * It has to be a non empty list if KEYS_SUBSET fallback policy is selected. * For any other fallback policy the parameter is not used and should not be set. * Only values also present in - * :ref:`keys` are allowed, but + * :ref:`keys` are allowed, but * `fallback_keys_subset` cannot be equal to `keys`. */ 'fallback_keys_subset'?: (string)[]; @@ -594,36 +612,51 @@ export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector { /** * Specifications for subsets. */ -export interface _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector__Output { +export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector__Output { /** * List of keys to match with the weighted cluster metadata. */ 'keys': (string)[]; + /** + * Selects a mode of operation in which each subset has only one host. This mode uses the same rules for + * choosing a host, but updating hosts is faster, especially for large numbers of hosts. + * + * If a match is found to a host, that host will be used regardless of priority levels, unless the host is unhealthy. + * + * Currently, this mode is only supported if `subset_selectors` has only one entry, and `keys` contains + * only one entry. + * + * When this mode is enabled, configurations that contain more than one host with the same metadata value for the single key in `keys` + * will use only one of the hosts with the given key; no requests will be routed to the others. The cluster gauge + * :ref:`lb_subsets_single_host_per_subset_duplicate` indicates how many duplicates are + * present in the current configuration. + */ + 'single_host_per_subset': (boolean); /** * The behavior used when no endpoint subset matches the selected route's * metadata. */ - 'fallback_policy': (keyof typeof _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); + 'fallback_policy': (keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); /** * Subset of - * :ref:`keys` used by - * :ref:`KEYS_SUBSET` + * :ref:`keys` used by + * :ref:`KEYS_SUBSET` * fallback policy. * It has to be a non empty list if KEYS_SUBSET fallback policy is selected. * For any other fallback policy the parameter is not used and should not be set. * Only values also present in - * :ref:`keys` are allowed, but + * :ref:`keys` are allowed, but * `fallback_keys_subset` cannot be equal to `keys`. */ 'fallback_keys_subset': (string)[]; } -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto /** * Allows to override top level fallback policy per selector. */ -export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy { +export enum _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy { /** * If NOT_DEFINED top level config fallback policy is used instead. */ @@ -645,7 +678,7 @@ export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelect /** * If KEYS_SUBSET is selected, subset selector matching is performed again with metadata * keys reduced to - * :ref:`fallback_keys_subset`. + * :ref:`fallback_keys_subset`. * It allows for a fallback to a different, less specific selector if some of the keys of * the selector are considered optional. */ @@ -655,37 +688,117 @@ export enum _envoy_api_v2_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelect /** * Specific configuration for the LeastRequest load balancing policy. */ -export interface _envoy_api_v2_Cluster_LeastRequestLbConfig { +export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig { /** * The number of random healthy hosts from which the host with the fewest active requests will * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. */ 'choice_count'?: (_google_protobuf_UInt32Value); + /** + * The following formula is used to calculate the dynamic weights when hosts have different load + * balancing weights: + * + * `weight = load_balancing_weight / (active_requests + 1)^active_request_bias` + * + * The larger the active request bias is, the more aggressively active requests will lower the + * effective weight when all host weights are not equal. + * + * `active_request_bias` must be greater than or equal to 0.0. + * + * When `active_request_bias == 0.0` the Least Request Load Balancer doesn't consider the number + * of active requests at the time it picks a host and behaves like the Round Robin Load + * Balancer. + * + * When `active_request_bias > 0.0` the Least Request Load Balancer scales the load balancing + * weight by the number of active requests at the time it does a pick. + * + * The value is cached for performance reasons and refreshed whenever one of the Load Balancer's + * host sets changes, e.g., whenever there is a host membership update or a host load balancing + * weight change. + * + * .. note:: + * This setting only takes effect if all host weights are not equal. + */ + 'active_request_bias'?: (_envoy_config_core_v3_RuntimeDouble); } /** * Specific configuration for the LeastRequest load balancing policy. */ -export interface _envoy_api_v2_Cluster_LeastRequestLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output { /** * The number of random healthy hosts from which the host with the fewest active requests will * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. */ 'choice_count'?: (_google_protobuf_UInt32Value__Output); + /** + * The following formula is used to calculate the dynamic weights when hosts have different load + * balancing weights: + * + * `weight = load_balancing_weight / (active_requests + 1)^active_request_bias` + * + * The larger the active request bias is, the more aggressively active requests will lower the + * effective weight when all host weights are not equal. + * + * `active_request_bias` must be greater than or equal to 0.0. + * + * When `active_request_bias == 0.0` the Least Request Load Balancer doesn't consider the number + * of active requests at the time it picks a host and behaves like the Round Robin Load + * Balancer. + * + * When `active_request_bias > 0.0` the Least Request Load Balancer scales the load balancing + * weight by the number of active requests at the time it does a pick. + * + * The value is cached for performance reasons and refreshed whenever one of the Load Balancer's + * host sets changes, e.g., whenever there is a host membership update or a host load balancing + * weight change. + * + * .. note:: + * This setting only takes effect if all host weights are not equal. + */ + 'active_request_bias'?: (_envoy_config_core_v3_RuntimeDouble__Output); } /** * Configuration for :ref:`locality weighted load balancing * ` */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig { } /** * Configuration for :ref:`locality weighted load balancing * ` */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output { +} + +/** + * Specific configuration for the :ref:`Maglev` + * load balancing policy. + */ +export interface _envoy_config_cluster_v3_Cluster_MaglevLbConfig { + /** + * The table size for Maglev hashing. The Maglev aims for ‘minimal disruption’ rather than an absolute guarantee. + * Minimal disruption means that when the set of upstreams changes, a connection will likely be sent to the same + * upstream as it was before. Increasing the table size reduces the amount of disruption. + * The table size must be prime number. If it is not specified, the default is 65537. + */ + 'table_size'?: (_google_protobuf_UInt64Value); +} + +/** + * Specific configuration for the :ref:`Maglev` + * load balancing policy. + */ +export interface _envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output { + /** + * The table size for Maglev hashing. The Maglev aims for ‘minimal disruption’ rather than an absolute guarantee. + * Minimal disruption means that when the set of upstreams changes, a connection will likely be sent to the same + * upstream as it was before. Increasing the table size reduces the amount of disruption. + * The table size must be prime number. If it is not specified, the default is 65537. + */ + 'table_size'?: (_google_protobuf_UInt64Value__Output); } /** @@ -693,7 +806,7 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig_LocalityWeightedLbConfig__ * :ref:`Original Destination ` * load balancing policy. */ -export interface _envoy_api_v2_Cluster_OriginalDstLbConfig { +export interface _envoy_config_cluster_v3_Cluster_OriginalDstLbConfig { /** * When true, :ref:`x-envoy-original-dst-host * ` can be used to override destination @@ -704,6 +817,10 @@ export interface _envoy_api_v2_Cluster_OriginalDstLbConfig { * This header isn't sanitized by default, so enabling this feature allows HTTP clients to * route traffic to arbitrary hosts and/or ports, which may have serious security * consequences. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ 'use_http_header'?: (boolean); } @@ -713,7 +830,7 @@ export interface _envoy_api_v2_Cluster_OriginalDstLbConfig { * :ref:`Original Destination ` * load balancing policy. */ -export interface _envoy_api_v2_Cluster_OriginalDstLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_OriginalDstLbConfig__Output { /** * When true, :ref:`x-envoy-original-dst-host * ` can be used to override destination @@ -724,38 +841,152 @@ export interface _envoy_api_v2_Cluster_OriginalDstLbConfig__Output { * This header isn't sanitized by default, so enabling this feature allows HTTP clients to * route traffic to arbitrary hosts and/or ports, which may have serious security * consequences. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ 'use_http_header': (boolean); } -export interface _envoy_api_v2_Cluster_RefreshRate { +export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy { + /** + * Indicates how many streams (rounded up) can be anticipated per-upstream for each + * incoming stream. This is useful for high-QPS or latency-sensitive services. Preconnecting + * will only be done if the upstream is healthy and the cluster has traffic. + * + * For example if this is 2, for an incoming HTTP/1.1 stream, 2 connections will be + * established, one for the new incoming stream, and one for a presumed follow-up stream. For + * HTTP/2, only one connection would be established by default as one connection can + * serve both the original and presumed follow-up stream. + * + * In steady state for non-multiplexed connections a value of 1.5 would mean if there were 100 + * active streams, there would be 100 connections in use, and 50 connections preconnected. + * This might be a useful value for something like short lived single-use connections, + * for example proxying HTTP/1.1 if keep-alive were false and each stream resulted in connection + * termination. It would likely be overkill for long lived connections, such as TCP proxying SMTP + * or regular HTTP/1.1 with keep-alive. For long lived traffic, a value of 1.05 would be more + * reasonable, where for every 100 connections, 5 preconnected connections would be in the queue + * in case of unexpected disconnects where the connection could not be reused. + * + * If this value is not set, or set explicitly to one, Envoy will fetch as many connections + * as needed to serve streams in flight. This means in steady state if a connection is torn down, + * a subsequent streams will pay an upstream-rtt latency penalty waiting for a new connection. + * + * This is limited somewhat arbitrarily to 3 because preconnecting too aggressively can + * harm latency more than the preconnecting helps. + */ + 'per_upstream_preconnect_ratio'?: (_google_protobuf_DoubleValue); + /** + * Indicates how many many streams (rounded up) can be anticipated across a cluster for each + * stream, useful for low QPS services. This is currently supported for a subset of + * deterministic non-hash-based load-balancing algorithms (weighted round robin, random). + * Unlike *per_upstream_preconnect_ratio* this preconnects across the upstream instances in a + * cluster, doing best effort predictions of what upstream would be picked next and + * pre-establishing a connection. + * + * Preconnecting will be limited to one preconnect per configured upstream in the cluster and will + * only be done if there are healthy upstreams and the cluster has traffic. + * + * For example if preconnecting is set to 2 for a round robin HTTP/2 cluster, on the first + * incoming stream, 2 connections will be preconnected - one to the first upstream for this + * cluster, one to the second on the assumption there will be a follow-up stream. + * + * If this value is not set, or set explicitly to one, Envoy will fetch as many connections + * as needed to serve streams in flight, so during warm up and in steady state if a connection + * is closed (and per_upstream_preconnect_ratio is not set), there will be a latency hit for + * connection establishment. + * + * If both this and preconnect_ratio are set, Envoy will make sure both predicted needs are met, + * basically preconnecting max(predictive-preconnect, per-upstream-preconnect), for each + * upstream. + */ + 'predictive_preconnect_ratio'?: (_google_protobuf_DoubleValue); +} + +export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output { + /** + * Indicates how many streams (rounded up) can be anticipated per-upstream for each + * incoming stream. This is useful for high-QPS or latency-sensitive services. Preconnecting + * will only be done if the upstream is healthy and the cluster has traffic. + * + * For example if this is 2, for an incoming HTTP/1.1 stream, 2 connections will be + * established, one for the new incoming stream, and one for a presumed follow-up stream. For + * HTTP/2, only one connection would be established by default as one connection can + * serve both the original and presumed follow-up stream. + * + * In steady state for non-multiplexed connections a value of 1.5 would mean if there were 100 + * active streams, there would be 100 connections in use, and 50 connections preconnected. + * This might be a useful value for something like short lived single-use connections, + * for example proxying HTTP/1.1 if keep-alive were false and each stream resulted in connection + * termination. It would likely be overkill for long lived connections, such as TCP proxying SMTP + * or regular HTTP/1.1 with keep-alive. For long lived traffic, a value of 1.05 would be more + * reasonable, where for every 100 connections, 5 preconnected connections would be in the queue + * in case of unexpected disconnects where the connection could not be reused. + * + * If this value is not set, or set explicitly to one, Envoy will fetch as many connections + * as needed to serve streams in flight. This means in steady state if a connection is torn down, + * a subsequent streams will pay an upstream-rtt latency penalty waiting for a new connection. + * + * This is limited somewhat arbitrarily to 3 because preconnecting too aggressively can + * harm latency more than the preconnecting helps. + */ + 'per_upstream_preconnect_ratio'?: (_google_protobuf_DoubleValue__Output); + /** + * Indicates how many many streams (rounded up) can be anticipated across a cluster for each + * stream, useful for low QPS services. This is currently supported for a subset of + * deterministic non-hash-based load-balancing algorithms (weighted round robin, random). + * Unlike *per_upstream_preconnect_ratio* this preconnects across the upstream instances in a + * cluster, doing best effort predictions of what upstream would be picked next and + * pre-establishing a connection. + * + * Preconnecting will be limited to one preconnect per configured upstream in the cluster and will + * only be done if there are healthy upstreams and the cluster has traffic. + * + * For example if preconnecting is set to 2 for a round robin HTTP/2 cluster, on the first + * incoming stream, 2 connections will be preconnected - one to the first upstream for this + * cluster, one to the second on the assumption there will be a follow-up stream. + * + * If this value is not set, or set explicitly to one, Envoy will fetch as many connections + * as needed to serve streams in flight, so during warm up and in steady state if a connection + * is closed (and per_upstream_preconnect_ratio is not set), there will be a latency hit for + * connection establishment. + * + * If both this and preconnect_ratio are set, Envoy will make sure both predicted needs are met, + * basically preconnecting max(predictive-preconnect, per-upstream-preconnect), for each + * upstream. + */ + 'predictive_preconnect_ratio'?: (_google_protobuf_DoubleValue__Output); +} + +export interface _envoy_config_cluster_v3_Cluster_RefreshRate { /** * Specifies the base interval between refreshes. This parameter is required and must be greater * than zero and less than - * :ref:`max_interval `. + * :ref:`max_interval `. */ 'base_interval'?: (_google_protobuf_Duration); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the - * :ref:`base_interval ` if set. The default - * is 10 times the :ref:`base_interval `. + * :ref:`base_interval ` if set. The default + * is 10 times the :ref:`base_interval `. */ 'max_interval'?: (_google_protobuf_Duration); } -export interface _envoy_api_v2_Cluster_RefreshRate__Output { +export interface _envoy_config_cluster_v3_Cluster_RefreshRate__Output { /** * Specifies the base interval between refreshes. This parameter is required and must be greater * than zero and less than - * :ref:`max_interval `. + * :ref:`max_interval `. */ 'base_interval'?: (_google_protobuf_Duration__Output); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the - * :ref:`base_interval ` if set. The default - * is 10 times the :ref:`base_interval `. + * :ref:`base_interval ` if set. The default + * is 10 times the :ref:`base_interval `. */ 'max_interval'?: (_google_protobuf_Duration__Output); } @@ -764,23 +995,23 @@ export interface _envoy_api_v2_Cluster_RefreshRate__Output { * Specific configuration for the :ref:`RingHash` * load balancing policy. */ -export interface _envoy_api_v2_Cluster_RingHashLbConfig { +export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig { /** * Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each * provided host) the better the request distribution will reflect the desired weights. Defaults * to 1024 entries, and limited to 8M entries. See also - * :ref:`maximum_ring_size`. + * :ref:`maximum_ring_size`. */ 'minimum_ring_size'?: (_google_protobuf_UInt64Value); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to - * :ref:`XX_HASH`. + * :ref:`XX_HASH`. */ - 'hash_function'?: (_envoy_api_v2_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + 'hash_function'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction); /** * Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered * to further constrain resource use. See also - * :ref:`minimum_ring_size`. + * :ref:`minimum_ring_size`. */ 'maximum_ring_size'?: (_google_protobuf_UInt64Value); } @@ -789,23 +1020,23 @@ export interface _envoy_api_v2_Cluster_RingHashLbConfig { * Specific configuration for the :ref:`RingHash` * load balancing policy. */ -export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output { /** * Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each * provided host) the better the request distribution will reflect the desired weights. Defaults * to 1024 entries, and limited to 8M entries. See also - * :ref:`maximum_ring_size`. + * :ref:`maximum_ring_size`. */ 'minimum_ring_size'?: (_google_protobuf_UInt64Value__Output); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to - * :ref:`XX_HASH`. + * :ref:`XX_HASH`. */ - 'hash_function': (keyof typeof _envoy_api_v2_Cluster_RingHashLbConfig_HashFunction); + 'hash_function': (keyof typeof _envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction); /** * Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered * to further constrain resource use. See also - * :ref:`minimum_ring_size`. + * :ref:`minimum_ring_size`. */ 'maximum_ring_size'?: (_google_protobuf_UInt64Value__Output); } @@ -814,7 +1045,7 @@ export interface _envoy_api_v2_Cluster_RingHashLbConfig__Output { * TransportSocketMatch specifies what transport socket config will be used * when the match conditions are satisfied. */ -export interface _envoy_api_v2_Cluster_TransportSocketMatch { +export interface _envoy_config_cluster_v3_Cluster_TransportSocketMatch { /** * The name of the match, used in stats generation. */ @@ -830,14 +1061,14 @@ export interface _envoy_api_v2_Cluster_TransportSocketMatch { /** * The configuration of the transport socket. */ - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket); } /** * TransportSocketMatch specifies what transport socket config will be used * when the match conditions are satisfied. */ -export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { +export interface _envoy_config_cluster_v3_Cluster_TransportSocketMatch__Output { /** * The name of the match, used in stats generation. */ @@ -853,21 +1084,21 @@ export interface _envoy_api_v2_Cluster_TransportSocketMatch__Output { /** * The configuration of the transport socket. */ - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket__Output); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket__Output); } /** * Configuration for :ref:`zone aware routing * `. */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig { /** * Configures percentage of requests that will be considered for zone aware routing * if zone aware routing is configured. If not specified, the default is 100%. * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'routing_enabled'?: (_envoy_type_Percent); + 'routing_enabled'?: (_envoy_type_v3_Percent); /** * Configures minimum upstream cluster size required for zone aware routing * If upstream cluster size is less than specified, zone aware routing is not performed @@ -889,14 +1120,14 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig { * Configuration for :ref:`zone aware routing * `. */ -export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { +export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output { /** * Configures percentage of requests that will be considered for zone aware routing * if zone aware routing is configured. If not specified, the default is 100%. * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'routing_enabled'?: (_envoy_type_Percent__Output); + 'routing_enabled'?: (_envoy_type_v3_Percent__Output); /** * Configures minimum upstream cluster size required for zone aware routing * If upstream cluster size is less than specified, zone aware routing is not performed @@ -916,14 +1147,14 @@ export interface _envoy_api_v2_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output /** * Configuration for a single upstream cluster. - * [#next-free-field: 48] + * [#next-free-field: 53] */ export interface Cluster { /** * Supplies the name of the cluster which must be unique across all clusters. * The cluster name is used when emitting * :ref:`statistics ` if :ref:`alt_stat_name - * ` is not provided. + * ` is not provided. * Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. */ 'name'?: (string); @@ -931,11 +1162,11 @@ export interface Cluster { * The :ref:`service discovery type ` * to use for resolving the cluster. */ - 'type'?: (_envoy_api_v2_Cluster_DiscoveryType | keyof typeof _envoy_api_v2_Cluster_DiscoveryType); + 'type'?: (_envoy_config_cluster_v3_Cluster_DiscoveryType | keyof typeof _envoy_config_cluster_v3_Cluster_DiscoveryType); /** * Configuration to use for EDS updates for the Cluster. */ - 'eds_cluster_config'?: (_envoy_api_v2_Cluster_EdsClusterConfig); + 'eds_cluster_config'?: (_envoy_config_cluster_v3_Cluster_EdsClusterConfig); /** * The timeout for new network connections to hosts in the cluster. */ @@ -948,28 +1179,16 @@ export interface Cluster { /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. + * [#comment:TODO: Remove enum constraint :ref:`LOAD_BALANCING_POLICY_CONFIG` when implemented.] */ - 'lb_policy'?: (_envoy_api_v2_Cluster_LbPolicy | keyof typeof _envoy_api_v2_Cluster_LbPolicy); - /** - * If the service discovery type is - * :ref:`STATIC`, - * :ref:`STRICT_DNS` - * or :ref:`LOGICAL_DNS`, - * then hosts is required. - * - * .. attention:: - * - * **This field is deprecated**. Set the - * :ref:`load_assignment` field instead. - */ - 'hosts'?: (_envoy_api_v2_core_Address)[]; + 'lb_policy'?: (_envoy_config_cluster_v3_Cluster_LbPolicy | keyof typeof _envoy_config_cluster_v3_Cluster_LbPolicy); /** * Optional :ref:`active health checking ` * configuration for the cluster. If no * configuration is specified no health checking will be done and all cluster * members will be considered healthy at all times. */ - 'health_checks'?: (_envoy_api_v2_core_HealthCheck)[]; + 'health_checks'?: (_envoy_config_core_v3_HealthCheck)[]; /** * Optional maximum requests for a single upstream connection. This parameter * is respected by both the HTTP/1.1 and HTTP/2 connection pool @@ -980,20 +1199,18 @@ export interface Cluster { /** * Optional :ref:`circuit breaking ` for the cluster. */ - 'circuit_breakers'?: (_envoy_api_v2_cluster_CircuitBreakers); - /** - * The TLS configuration for connections to the upstream cluster. - * - * .. attention:: - * - * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are - * set, `transport_socket` takes priority. - */ - 'tls_context'?: (_envoy_api_v2_auth_UpstreamTlsContext); + 'circuit_breakers'?: (_envoy_config_cluster_v3_CircuitBreakers); /** * Additional options when handling HTTP1 requests. + * This has been deprecated in favor of http_protocol_options fields in the in the + * :ref:`http_protocol_options ` message. + * http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); + 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions); /** * Even if default HTTP2 protocol options are desired, this field must be * set so that Envoy will assume that the upstream supports HTTP/2 when @@ -1001,48 +1218,58 @@ export interface Cluster { * supports prior knowledge for upstream connections. Even if TLS is used * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 * connections to happen over plain text. + * This has been deprecated in favor of http2_protocol_options fields in the in the + * :ref:`http_protocol_options ` + * message. http2_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions); /** * If the DNS refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used as the cluster’s DNS refresh * rate. The value configured must be at least 1ms. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. */ 'dns_refresh_rate'?: (_google_protobuf_Duration); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to - * :ref:`AUTO`. + * :ref:`AUTO`. */ - 'dns_lookup_family'?: (_envoy_api_v2_Cluster_DnsLookupFamily | keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); + 'dns_lookup_family'?: (_envoy_config_cluster_v3_Cluster_DnsLookupFamily | keyof typeof _envoy_config_cluster_v3_Cluster_DnsLookupFamily); /** * If DNS resolvers are specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used to specify the cluster’s dns resolvers. * If this setting is not specified, the value defaults to the default * resolver, which uses /etc/resolv.conf for configuration. For cluster types * other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple's API only allows overriding DNS resolvers via system settings. */ - 'dns_resolvers'?: (_envoy_api_v2_core_Address)[]; + 'dns_resolvers'?: (_envoy_config_core_v3_Address)[]; /** * If specified, outlier detection will be enabled for this upstream cluster. * Each of the configuration values can be overridden via * :ref:`runtime values `. */ - 'outlier_detection'?: (_envoy_api_v2_cluster_OutlierDetection); + 'outlier_detection'?: (_envoy_config_cluster_v3_OutlierDetection); /** * The interval for removing stale hosts from a cluster type - * :ref:`ORIGINAL_DST`. + * :ref:`ORIGINAL_DST`. * Hosts are considered stale if they have not been used * as upstream destinations during this interval. New hosts are added * to original destination clusters on demand as new connections are @@ -1052,7 +1279,7 @@ export interface Cluster { * them remain open, saving the latency that would otherwise be spent * on opening new connections. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`ORIGINAL_DST` + * :ref:`ORIGINAL_DST` * this setting is ignored. */ 'cleanup_interval'?: (_google_protobuf_Duration); @@ -1061,23 +1288,23 @@ export interface Cluster { * This overrides any bind_config specified in the bootstrap proto. * If the address and port are empty, no bind will be performed. */ - 'upstream_bind_config'?: (_envoy_api_v2_core_BindConfig); + 'upstream_bind_config'?: (_envoy_config_core_v3_BindConfig); /** * Configuration for load balancing subsetting. */ - 'lb_subset_config'?: (_envoy_api_v2_Cluster_LbSubsetConfig); + 'lb_subset_config'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig); /** * Optional configuration for the Ring Hash load balancing policy. */ - 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig); + 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig); /** * Optional custom transport socket implementation to use for upstream connections. * To setup TLS, set a transport socket with name `tls` and - * :ref:`UpstreamTlsContexts ` in the `typed_config`. + * :ref:`UpstreamTlsContexts ` in the `typed_config`. * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket); /** * The Metadata field can be used to provide additional information about the * cluster. It can be used for stats, logging, and varying filter behavior. @@ -1085,15 +1312,20 @@ export interface Cluster { * will need the information. For instance, if the metadata is intended for * the Router filter, the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_api_v2_core_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata); /** * Determines how Envoy selects the protocol used to speak to upstream hosts. + * This has been deprecated in favor of setting explicit protocol selection + * in the :ref:`http_protocol_options + * ` message. + * http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. */ - 'protocol_selection'?: (_envoy_api_v2_Cluster_ClusterProtocolSelection | keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + 'protocol_selection'?: (_envoy_config_cluster_v3_Cluster_ClusterProtocolSelection | keyof typeof _envoy_config_cluster_v3_Cluster_ClusterProtocolSelection); /** * Common configuration for all load balancer implementations. */ - 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig); + 'common_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig); /** * An optional alternative to the cluster name to be used while emitting stats. * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be @@ -1104,12 +1336,20 @@ export interface Cluster { /** * Additional options when handling HTTP requests upstream. These options will be applicable to * both HTTP1 and HTTP2 requests. + * This has been deprecated in favor of + * :ref:`common_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. + * common_http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); + 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions); /** * Optional options for upstream connections. */ - 'upstream_connection_options'?: (_envoy_api_v2_UpstreamConnectionOptions); + 'upstream_connection_options'?: (_envoy_config_cluster_v3_UpstreamConnectionOptions); /** * If an upstream host becomes unhealthy (as determined by the configured health checks * or outlier detection), immediately close all connections to the failed host. @@ -1131,46 +1371,40 @@ export interface Cluster { * from service discovery. This means that if active health checking is used, Envoy will *not* * wait for the endpoint to go unhealthy before removing it. */ - 'drain_connections_on_host_removal'?: (boolean); + 'ignore_health_on_host_removal'?: (boolean); /** * Setting this is required for specifying members of - * :ref:`STATIC`, - * :ref:`STRICT_DNS` - * or :ref:`LOGICAL_DNS` clusters. + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS` clusters. * This field supersedes the *hosts* field in the v2 API. * * .. attention:: * * Setting this allows non-EDS cluster types to contain embedded EDS equivalent - * :ref:`endpoint assignments`. + * :ref:`endpoint assignments`. */ - 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment); + 'load_assignment'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment); /** * Optional configuration for the Original Destination load balancing policy. */ - 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig); - /** - * The extension_protocol_options field is used to provide extension-specific protocol options - * for upstream connections. The key should match the extension filter name, such as - * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on - * specific options. - */ - 'extension_protocol_options'?: ({[key: string]: _google_protobuf_Struct}); + 'original_dst_lb_config'?: (_envoy_config_cluster_v3_Cluster_OriginalDstLbConfig); /** * The extension_protocol_options field is used to provide extension-specific protocol options * for upstream connections. The key should match the extension filter name, such as * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on * specific options. + * [#next-major-version: make this a list of typed extensions.] */ 'typed_extension_protocol_options'?: ({[key: string]: _google_protobuf_Any}); /** * Optional configuration for the LeastRequest load balancing policy. */ - 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig); + 'least_request_lb_config'?: (_envoy_config_cluster_v3_Cluster_LeastRequestLbConfig); /** * The custom cluster type. */ - 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType); + 'cluster_type'?: (_envoy_config_cluster_v3_Cluster_CustomClusterType); /** * Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, * cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS @@ -1182,13 +1416,13 @@ export interface Cluster { * The chain will be applied to all outgoing connections that Envoy makes to the upstream * servers of this cluster. */ - 'filters'?: (_envoy_api_v2_cluster_Filter)[]; + 'filters'?: (_envoy_config_cluster_v3_Filter)[]; /** * [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the - * :ref:`lb_policy` field has the value - * :ref:`LOAD_BALANCING_POLICY_CONFIG`. + * :ref:`lb_policy` field has the value + * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ - 'load_balancing_policy'?: (_envoy_api_v2_LoadBalancingPolicy); + 'load_balancing_policy'?: (_envoy_config_cluster_v3_LoadBalancingPolicy); /** * [#not-implemented-hide:] * If present, tells the client where to send load reports via LRS. If not present, the @@ -1205,13 +1439,13 @@ export interface Cluster { * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation * from the LRS stream here.] */ - 'lrs_server'?: (_envoy_api_v2_core_ConfigSource); + 'lrs_server'?: (_envoy_config_core_v3_ConfigSource); /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the - * :ref:`LbEndpoint.Metadata ` + * :ref:`LbEndpoint.Metadata ` * is used to match against the transport sockets as they appear in the list. The first - * :ref:`match ` is used. + * :ref:`match ` is used. * For example, with the following match * * .. code-block:: yaml @@ -1231,7 +1465,7 @@ export interface Cluster { * Connections to the endpoints whose metadata value under *envoy.transport_socket_match* * having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. * - * If a :ref:`socket match ` with empty match + * If a :ref:`socket match ` with empty match * criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" * socket match in case above. * @@ -1251,61 +1485,119 @@ export interface Cluster { * *TransportSocketMatch* in this field. Other client Envoys receive CDS without * *transport_socket_match* set, and still send plain text traffic to the same cluster. * + * This field can be used to specify custom transport socket configurations for health + * checks by adding matching key/value pairs in a health check's + * :ref:`transport socket match criteria ` field. + * * [#comment:TODO(incfly): add a detailed architecture doc on intended usage.] */ - 'transport_socket_matches'?: (_envoy_api_v2_Cluster_TransportSocketMatch)[]; + 'transport_socket_matches'?: (_envoy_config_cluster_v3_Cluster_TransportSocketMatch)[]; /** * If the DNS failure refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is * not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types - * other than :ref:`STRICT_DNS` and - * :ref:`LOGICAL_DNS` this setting is + * other than :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS` this setting is * ignored. */ - 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate); + 'dns_failure_refresh_rate'?: (_envoy_config_cluster_v3_Cluster_RefreshRate); /** * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple' API only uses UDP for DNS resolution. */ 'use_tcp_for_dns_lookups'?: (boolean); /** * HTTP protocol options that are applied only to upstream HTTP connections. * These options apply to all HTTP versions. + * This has been deprecated in favor of + * :ref:`upstream_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. + * upstream_http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions); + 'upstream_http_protocol_options'?: (_envoy_config_core_v3_UpstreamHttpProtocolOptions); /** * If track_timeout_budgets is true, the :ref:`timeout budget histograms * ` will be published for each * request. These show what percentage of a request's per try and global timeout was used. A value * of 0 would indicate that none of the timeout was used or that the timeout was infinite. A value * of 100 would indicate that the request took the entirety of the timeout given to it. + * + * .. attention:: + * + * This field has been deprecated in favor of `timeout_budgets`, part of + * :ref:`track_cluster_stats `. */ 'track_timeout_budgets'?: (boolean); + /** + * Optional customization and configuration of upstream connection pool, and upstream type. + * + * Currently this field only applies for HTTP traffic but is designed for eventual use for custom + * TCP upstreams. + * + * For HTTP traffic, Envoy will generally take downstream HTTP and send it upstream as upstream + * HTTP, using the http connection pool and the codec from `http2_protocol_options` + * + * For routes where CONNECT termination is configured, Envoy will take downstream CONNECT + * requests and forward the CONNECT payload upstream over raw TCP using the tcp connection pool. + * + * The default pool used is the generic connection pool which creates the HTTP upstream for most + * HTTP requests, and the TCP upstream if CONNECT termination is configured. + * + * If users desire custom connection pool or upstream behavior, for example terminating + * CONNECT only if a custom filter indicates it is appropriate, the custom factories + * can be registered and configured here. + */ + 'upstream_config'?: (_envoy_config_core_v3_TypedExtensionConfig); + /** + * Configuration to track optional cluster stats. + */ + 'track_cluster_stats'?: (_envoy_config_cluster_v3_TrackClusterStats); + /** + * Preconnect configuration for this cluster. + */ + 'preconnect_policy'?: (_envoy_config_cluster_v3_Cluster_PreconnectPolicy); + /** + * If `connection_pool_per_downstream_connection` is true, the cluster will use a separate + * connection pool for every downstream connection + */ + 'connection_pool_per_downstream_connection'?: (boolean); + /** + * Optional configuration for the Maglev load balancing policy. + */ + 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig); 'cluster_discovery_type'?: "type"|"cluster_type"; /** * Optional configuration for the load balancing algorithm selected by * LbPolicy. Currently only - * :ref:`RING_HASH` and - * :ref:`LEAST_REQUEST` + * :ref:`RING_HASH`, + * :ref:`MAGLEV` and + * :ref:`LEAST_REQUEST` * has additional configuration options. - * Specifying ring_hash_lb_config or least_request_lb_config without setting the corresponding + * Specifying ring_hash_lb_config or maglev_lb_config or least_request_lb_config without setting the corresponding * LbPolicy will generate an error at runtime. */ - 'lb_config'?: "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; + 'lb_config'?: "ring_hash_lb_config"|"maglev_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; } /** * Configuration for a single upstream cluster. - * [#next-free-field: 48] + * [#next-free-field: 53] */ export interface Cluster__Output { /** * Supplies the name of the cluster which must be unique across all clusters. * The cluster name is used when emitting * :ref:`statistics ` if :ref:`alt_stat_name - * ` is not provided. + * ` is not provided. * Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. */ 'name': (string); @@ -1313,11 +1605,11 @@ export interface Cluster__Output { * The :ref:`service discovery type ` * to use for resolving the cluster. */ - 'type'?: (keyof typeof _envoy_api_v2_Cluster_DiscoveryType); + 'type'?: (keyof typeof _envoy_config_cluster_v3_Cluster_DiscoveryType); /** * Configuration to use for EDS updates for the Cluster. */ - 'eds_cluster_config'?: (_envoy_api_v2_Cluster_EdsClusterConfig__Output); + 'eds_cluster_config'?: (_envoy_config_cluster_v3_Cluster_EdsClusterConfig__Output); /** * The timeout for new network connections to hosts in the cluster. */ @@ -1330,28 +1622,16 @@ export interface Cluster__Output { /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. + * [#comment:TODO: Remove enum constraint :ref:`LOAD_BALANCING_POLICY_CONFIG` when implemented.] */ - 'lb_policy': (keyof typeof _envoy_api_v2_Cluster_LbPolicy); - /** - * If the service discovery type is - * :ref:`STATIC`, - * :ref:`STRICT_DNS` - * or :ref:`LOGICAL_DNS`, - * then hosts is required. - * - * .. attention:: - * - * **This field is deprecated**. Set the - * :ref:`load_assignment` field instead. - */ - 'hosts': (_envoy_api_v2_core_Address__Output)[]; + 'lb_policy': (keyof typeof _envoy_config_cluster_v3_Cluster_LbPolicy); /** * Optional :ref:`active health checking ` * configuration for the cluster. If no * configuration is specified no health checking will be done and all cluster * members will be considered healthy at all times. */ - 'health_checks': (_envoy_api_v2_core_HealthCheck__Output)[]; + 'health_checks': (_envoy_config_core_v3_HealthCheck__Output)[]; /** * Optional maximum requests for a single upstream connection. This parameter * is respected by both the HTTP/1.1 and HTTP/2 connection pool @@ -1362,20 +1642,18 @@ export interface Cluster__Output { /** * Optional :ref:`circuit breaking ` for the cluster. */ - 'circuit_breakers'?: (_envoy_api_v2_cluster_CircuitBreakers__Output); - /** - * The TLS configuration for connections to the upstream cluster. - * - * .. attention:: - * - * **This field is deprecated**. Use `transport_socket` with name `tls` instead. If both are - * set, `transport_socket` takes priority. - */ - 'tls_context'?: (_envoy_api_v2_auth_UpstreamTlsContext__Output); + 'circuit_breakers'?: (_envoy_config_cluster_v3_CircuitBreakers__Output); /** * Additional options when handling HTTP1 requests. + * This has been deprecated in favor of http_protocol_options fields in the in the + * :ref:`http_protocol_options ` message. + * http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions__Output); + 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions__Output); /** * Even if default HTTP2 protocol options are desired, this field must be * set so that Envoy will assume that the upstream supports HTTP/2 when @@ -1383,48 +1661,58 @@ export interface Cluster__Output { * supports prior knowledge for upstream connections. Even if TLS is used * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 * connections to happen over plain text. + * This has been deprecated in favor of http2_protocol_options fields in the in the + * :ref:`http_protocol_options ` + * message. http2_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions__Output); /** * If the DNS refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used as the cluster’s DNS refresh * rate. The value configured must be at least 1ms. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. */ 'dns_refresh_rate'?: (_google_protobuf_Duration__Output); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to - * :ref:`AUTO`. + * :ref:`AUTO`. */ - 'dns_lookup_family': (keyof typeof _envoy_api_v2_Cluster_DnsLookupFamily); + 'dns_lookup_family': (keyof typeof _envoy_config_cluster_v3_Cluster_DnsLookupFamily); /** * If DNS resolvers are specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used to specify the cluster’s dns resolvers. * If this setting is not specified, the value defaults to the default * resolver, which uses /etc/resolv.conf for configuration. For cluster types * other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple's API only allows overriding DNS resolvers via system settings. */ - 'dns_resolvers': (_envoy_api_v2_core_Address__Output)[]; + 'dns_resolvers': (_envoy_config_core_v3_Address__Output)[]; /** * If specified, outlier detection will be enabled for this upstream cluster. * Each of the configuration values can be overridden via * :ref:`runtime values `. */ - 'outlier_detection'?: (_envoy_api_v2_cluster_OutlierDetection__Output); + 'outlier_detection'?: (_envoy_config_cluster_v3_OutlierDetection__Output); /** * The interval for removing stale hosts from a cluster type - * :ref:`ORIGINAL_DST`. + * :ref:`ORIGINAL_DST`. * Hosts are considered stale if they have not been used * as upstream destinations during this interval. New hosts are added * to original destination clusters on demand as new connections are @@ -1434,7 +1722,7 @@ export interface Cluster__Output { * them remain open, saving the latency that would otherwise be spent * on opening new connections. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`ORIGINAL_DST` + * :ref:`ORIGINAL_DST` * this setting is ignored. */ 'cleanup_interval'?: (_google_protobuf_Duration__Output); @@ -1443,23 +1731,23 @@ export interface Cluster__Output { * This overrides any bind_config specified in the bootstrap proto. * If the address and port are empty, no bind will be performed. */ - 'upstream_bind_config'?: (_envoy_api_v2_core_BindConfig__Output); + 'upstream_bind_config'?: (_envoy_config_core_v3_BindConfig__Output); /** * Configuration for load balancing subsetting. */ - 'lb_subset_config'?: (_envoy_api_v2_Cluster_LbSubsetConfig__Output); + 'lb_subset_config'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig__Output); /** * Optional configuration for the Ring Hash load balancing policy. */ - 'ring_hash_lb_config'?: (_envoy_api_v2_Cluster_RingHashLbConfig__Output); + 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output); /** * Optional custom transport socket implementation to use for upstream connections. * To setup TLS, set a transport socket with name `tls` and - * :ref:`UpstreamTlsContexts ` in the `typed_config`. + * :ref:`UpstreamTlsContexts ` in the `typed_config`. * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket'?: (_envoy_api_v2_core_TransportSocket__Output); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket__Output); /** * The Metadata field can be used to provide additional information about the * cluster. It can be used for stats, logging, and varying filter behavior. @@ -1467,15 +1755,20 @@ export interface Cluster__Output { * will need the information. For instance, if the metadata is intended for * the Router filter, the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_config_core_v3_Metadata__Output); /** * Determines how Envoy selects the protocol used to speak to upstream hosts. + * This has been deprecated in favor of setting explicit protocol selection + * in the :ref:`http_protocol_options + * ` message. + * http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. */ - 'protocol_selection': (keyof typeof _envoy_api_v2_Cluster_ClusterProtocolSelection); + 'protocol_selection': (keyof typeof _envoy_config_cluster_v3_Cluster_ClusterProtocolSelection); /** * Common configuration for all load balancer implementations. */ - 'common_lb_config'?: (_envoy_api_v2_Cluster_CommonLbConfig__Output); + 'common_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig__Output); /** * An optional alternative to the cluster name to be used while emitting stats. * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be @@ -1486,12 +1779,20 @@ export interface Cluster__Output { /** * Additional options when handling HTTP requests upstream. These options will be applicable to * both HTTP1 and HTTP2 requests. + * This has been deprecated in favor of + * :ref:`common_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. + * common_http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions__Output); + 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions__Output); /** * Optional options for upstream connections. */ - 'upstream_connection_options'?: (_envoy_api_v2_UpstreamConnectionOptions__Output); + 'upstream_connection_options'?: (_envoy_config_cluster_v3_UpstreamConnectionOptions__Output); /** * If an upstream host becomes unhealthy (as determined by the configured health checks * or outlier detection), immediately close all connections to the failed host. @@ -1513,46 +1814,40 @@ export interface Cluster__Output { * from service discovery. This means that if active health checking is used, Envoy will *not* * wait for the endpoint to go unhealthy before removing it. */ - 'drain_connections_on_host_removal': (boolean); + 'ignore_health_on_host_removal': (boolean); /** * Setting this is required for specifying members of - * :ref:`STATIC`, - * :ref:`STRICT_DNS` - * or :ref:`LOGICAL_DNS` clusters. + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS` clusters. * This field supersedes the *hosts* field in the v2 API. * * .. attention:: * * Setting this allows non-EDS cluster types to contain embedded EDS equivalent - * :ref:`endpoint assignments`. + * :ref:`endpoint assignments`. */ - 'load_assignment'?: (_envoy_api_v2_ClusterLoadAssignment__Output); + 'load_assignment'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment__Output); /** * Optional configuration for the Original Destination load balancing policy. */ - 'original_dst_lb_config'?: (_envoy_api_v2_Cluster_OriginalDstLbConfig__Output); - /** - * The extension_protocol_options field is used to provide extension-specific protocol options - * for upstream connections. The key should match the extension filter name, such as - * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on - * specific options. - */ - 'extension_protocol_options'?: ({[key: string]: _google_protobuf_Struct__Output}); + 'original_dst_lb_config'?: (_envoy_config_cluster_v3_Cluster_OriginalDstLbConfig__Output); /** * The extension_protocol_options field is used to provide extension-specific protocol options * for upstream connections. The key should match the extension filter name, such as * "envoy.filters.network.thrift_proxy". See the extension's documentation for details on * specific options. + * [#next-major-version: make this a list of typed extensions.] */ 'typed_extension_protocol_options'?: ({[key: string]: _google_protobuf_Any__Output}); /** * Optional configuration for the LeastRequest load balancing policy. */ - 'least_request_lb_config'?: (_envoy_api_v2_Cluster_LeastRequestLbConfig__Output); + 'least_request_lb_config'?: (_envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output); /** * The custom cluster type. */ - 'cluster_type'?: (_envoy_api_v2_Cluster_CustomClusterType__Output); + 'cluster_type'?: (_envoy_config_cluster_v3_Cluster_CustomClusterType__Output); /** * Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, * cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS @@ -1564,13 +1859,13 @@ export interface Cluster__Output { * The chain will be applied to all outgoing connections that Envoy makes to the upstream * servers of this cluster. */ - 'filters': (_envoy_api_v2_cluster_Filter__Output)[]; + 'filters': (_envoy_config_cluster_v3_Filter__Output)[]; /** * [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the - * :ref:`lb_policy` field has the value - * :ref:`LOAD_BALANCING_POLICY_CONFIG`. + * :ref:`lb_policy` field has the value + * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ - 'load_balancing_policy'?: (_envoy_api_v2_LoadBalancingPolicy__Output); + 'load_balancing_policy'?: (_envoy_config_cluster_v3_LoadBalancingPolicy__Output); /** * [#not-implemented-hide:] * If present, tells the client where to send load reports via LRS. If not present, the @@ -1587,13 +1882,13 @@ export interface Cluster__Output { * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation * from the LRS stream here.] */ - 'lrs_server'?: (_envoy_api_v2_core_ConfigSource__Output); + 'lrs_server'?: (_envoy_config_core_v3_ConfigSource__Output); /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the - * :ref:`LbEndpoint.Metadata ` + * :ref:`LbEndpoint.Metadata ` * is used to match against the transport sockets as they appear in the list. The first - * :ref:`match ` is used. + * :ref:`match ` is used. * For example, with the following match * * .. code-block:: yaml @@ -1613,7 +1908,7 @@ export interface Cluster__Output { * Connections to the endpoints whose metadata value under *envoy.transport_socket_match* * having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. * - * If a :ref:`socket match ` with empty match + * If a :ref:`socket match ` with empty match * criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" * socket match in case above. * @@ -1633,47 +1928,105 @@ export interface Cluster__Output { * *TransportSocketMatch* in this field. Other client Envoys receive CDS without * *transport_socket_match* set, and still send plain text traffic to the same cluster. * + * This field can be used to specify custom transport socket configurations for health + * checks by adding matching key/value pairs in a health check's + * :ref:`transport socket match criteria ` field. + * * [#comment:TODO(incfly): add a detailed architecture doc on intended usage.] */ - 'transport_socket_matches': (_envoy_api_v2_Cluster_TransportSocketMatch__Output)[]; + 'transport_socket_matches': (_envoy_config_cluster_v3_Cluster_TransportSocketMatch__Output)[]; /** * If the DNS failure refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is * not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types - * other than :ref:`STRICT_DNS` and - * :ref:`LOGICAL_DNS` this setting is + * other than :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS` this setting is * ignored. */ - 'dns_failure_refresh_rate'?: (_envoy_api_v2_Cluster_RefreshRate__Output); + 'dns_failure_refresh_rate'?: (_envoy_config_cluster_v3_Cluster_RefreshRate__Output); /** * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple' API only uses UDP for DNS resolution. */ 'use_tcp_for_dns_lookups': (boolean); /** * HTTP protocol options that are applied only to upstream HTTP connections. * These options apply to all HTTP versions. + * This has been deprecated in favor of + * :ref:`upstream_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. + * upstream_http_protocol_options can be set via the cluster's + * :ref:`extension_protocol_options`. + * See ref:`upstream_http_protocol_options + * ` + * for example usage. */ - 'upstream_http_protocol_options'?: (_envoy_api_v2_core_UpstreamHttpProtocolOptions__Output); + 'upstream_http_protocol_options'?: (_envoy_config_core_v3_UpstreamHttpProtocolOptions__Output); /** * If track_timeout_budgets is true, the :ref:`timeout budget histograms * ` will be published for each * request. These show what percentage of a request's per try and global timeout was used. A value * of 0 would indicate that none of the timeout was used or that the timeout was infinite. A value * of 100 would indicate that the request took the entirety of the timeout given to it. + * + * .. attention:: + * + * This field has been deprecated in favor of `timeout_budgets`, part of + * :ref:`track_cluster_stats `. */ 'track_timeout_budgets': (boolean); + /** + * Optional customization and configuration of upstream connection pool, and upstream type. + * + * Currently this field only applies for HTTP traffic but is designed for eventual use for custom + * TCP upstreams. + * + * For HTTP traffic, Envoy will generally take downstream HTTP and send it upstream as upstream + * HTTP, using the http connection pool and the codec from `http2_protocol_options` + * + * For routes where CONNECT termination is configured, Envoy will take downstream CONNECT + * requests and forward the CONNECT payload upstream over raw TCP using the tcp connection pool. + * + * The default pool used is the generic connection pool which creates the HTTP upstream for most + * HTTP requests, and the TCP upstream if CONNECT termination is configured. + * + * If users desire custom connection pool or upstream behavior, for example terminating + * CONNECT only if a custom filter indicates it is appropriate, the custom factories + * can be registered and configured here. + */ + 'upstream_config'?: (_envoy_config_core_v3_TypedExtensionConfig__Output); + /** + * Configuration to track optional cluster stats. + */ + 'track_cluster_stats'?: (_envoy_config_cluster_v3_TrackClusterStats__Output); + /** + * Preconnect configuration for this cluster. + */ + 'preconnect_policy'?: (_envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output); + /** + * If `connection_pool_per_downstream_connection` is true, the cluster will use a separate + * connection pool for every downstream connection + */ + 'connection_pool_per_downstream_connection': (boolean); + /** + * Optional configuration for the Maglev load balancing policy. + */ + 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output); 'cluster_discovery_type': "type"|"cluster_type"; /** * Optional configuration for the load balancing algorithm selected by * LbPolicy. Currently only - * :ref:`RING_HASH` and - * :ref:`LEAST_REQUEST` + * :ref:`RING_HASH`, + * :ref:`MAGLEV` and + * :ref:`LEAST_REQUEST` * has additional configuration options. - * Specifying ring_hash_lb_config or least_request_lb_config without setting the corresponding + * Specifying ring_hash_lb_config or maglev_lb_config or least_request_lb_config without setting the corresponding * LbPolicy will generate an error at runtime. */ - 'lb_config': "ring_hash_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; + 'lb_config': "ring_hash_lb_config"|"maglev_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts new file mode 100644 index 000000000..aab9c6281 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts @@ -0,0 +1,19 @@ +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto + +import type { CollectionEntry as _xds_core_v3_CollectionEntry, CollectionEntry__Output as _xds_core_v3_CollectionEntry__Output } from '../../../../xds/core/v3/CollectionEntry'; + +/** + * Cluster list collections. Entries are *Cluster* resources or references. + * [#not-implemented-hide:] + */ +export interface ClusterCollection { + 'entries'?: (_xds_core_v3_CollectionEntry); +} + +/** + * Cluster list collections. Entries are *Cluster* resources or references. + * [#not-implemented-hide:] + */ +export interface ClusterCollection__Output { + 'entries'?: (_xds_core_v3_CollectionEntry__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts similarity index 92% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts index 5608fadf2..53feedb98 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster/filter.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/filter.proto import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts similarity index 80% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts index f79112a1c..29e343218 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/LoadBalancingPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts @@ -1,31 +1,20 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -export interface _envoy_api_v2_LoadBalancingPolicy_Policy { +export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy { /** * Required. The name of the LB policy. */ 'name'?: (string); - /** - * Optional config for the LB policy. - * No more than one of these two fields may be populated. - */ - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); } -export interface _envoy_api_v2_LoadBalancingPolicy_Policy__Output { +export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy__Output { /** * Required. The name of the LB policy. */ 'name': (string); - /** - * Optional config for the LB policy. - * No more than one of these two fields may be populated. - */ - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); } @@ -56,7 +45,7 @@ export interface LoadBalancingPolicy { * supports. This provides a mechanism for starting to use new LB policies that are not yet * supported by all clients. */ - 'policies'?: (_envoy_api_v2_LoadBalancingPolicy_Policy)[]; + 'policies'?: (_envoy_config_cluster_v3_LoadBalancingPolicy_Policy)[]; } /** @@ -86,5 +75,5 @@ export interface LoadBalancingPolicy__Output { * supports. This provides a mechanism for starting to use new LB policies that are not yet * supported by all clients. */ - 'policies': (_envoy_api_v2_LoadBalancingPolicy_Policy__Output)[]; + 'policies': (_envoy_config_cluster_v3_LoadBalancingPolicy_Policy__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts similarity index 85% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts rename to packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts index 53c1b4609..f37001691 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/cluster/OutlierDetection.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster/outlier_detection.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/outlier_detection.proto import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; @@ -6,7 +6,7 @@ import type { Duration as _google_protobuf_Duration, Duration__Output as _google /** * See the :ref:`architecture overview ` for * more information on outlier detection. - * [#next-free-field: 21] + * [#next-free-field: 22] */ export interface OutlierDetection { /** @@ -23,7 +23,8 @@ export interface OutlierDetection { 'interval'?: (_google_protobuf_Duration); /** * The base time that a host is ejected for. The real time is equal to the - * base time multiplied by the number of times the host has been ejected. + * base time multiplied by the number of times the host has been ejected and is + * capped by :ref:`max_ejection_time`. * Defaults to 30000ms or 30s. */ 'base_ejection_time'?: (_google_protobuf_Duration); @@ -83,17 +84,17 @@ export interface OutlierDetection { /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: - * :ref:`consecutive_local_origin_failure`, - * :ref:`enforcing_consecutive_local_origin_failure` + * :ref:`consecutive_local_origin_failure`, + * :ref:`enforcing_consecutive_local_origin_failure` * and - * :ref:`enforcing_local_origin_success_rate`. + * :ref:`enforcing_local_origin_success_rate`. * Defaults to false. */ 'split_external_local_origin_errors'?: (boolean); /** * The number of consecutive locally originated failures before ejection * occurs. Defaults to 5. Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); @@ -102,7 +103,7 @@ export interface OutlierDetection { * is detected through consecutive locally originated failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); @@ -111,7 +112,7 @@ export interface OutlierDetection { * is detected through success rate statistics for locally originated errors. * This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value); @@ -149,12 +150,18 @@ export interface OutlierDetection { * this host. Defaults to 50. */ 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value); + /** + * The maximum time that a host is ejected for. See :ref:`base_ejection_time` + * for more information. + * Defaults to 300000ms or 300s. + */ + 'max_ejection_time'?: (_google_protobuf_Duration); } /** * See the :ref:`architecture overview ` for * more information on outlier detection. - * [#next-free-field: 21] + * [#next-free-field: 22] */ export interface OutlierDetection__Output { /** @@ -171,7 +178,8 @@ export interface OutlierDetection__Output { 'interval'?: (_google_protobuf_Duration__Output); /** * The base time that a host is ejected for. The real time is equal to the - * base time multiplied by the number of times the host has been ejected. + * base time multiplied by the number of times the host has been ejected and is + * capped by :ref:`max_ejection_time`. * Defaults to 30000ms or 30s. */ 'base_ejection_time'?: (_google_protobuf_Duration__Output); @@ -231,17 +239,17 @@ export interface OutlierDetection__Output { /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: - * :ref:`consecutive_local_origin_failure`, - * :ref:`enforcing_consecutive_local_origin_failure` + * :ref:`consecutive_local_origin_failure`, + * :ref:`enforcing_consecutive_local_origin_failure` * and - * :ref:`enforcing_local_origin_success_rate`. + * :ref:`enforcing_local_origin_success_rate`. * Defaults to false. */ 'split_external_local_origin_errors': (boolean); /** * The number of consecutive locally originated failures before ejection * occurs. Defaults to 5. Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value__Output); @@ -250,7 +258,7 @@ export interface OutlierDetection__Output { * is detected through consecutive locally originated failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value__Output); @@ -259,7 +267,7 @@ export interface OutlierDetection__Output { * is detected through success rate statistics for locally originated errors. * This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value__Output); @@ -297,4 +305,10 @@ export interface OutlierDetection__Output { * this host. Defaults to 50. */ 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value__Output); + /** + * The maximum time that a host is ejected for. See :ref:`base_ejection_time` + * for more information. + * Defaults to 300000ms or 300s. + */ + 'max_ejection_time'?: (_google_protobuf_Duration__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/TrackClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/TrackClusterStats.ts new file mode 100644 index 000000000..a65d1fd8d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/TrackClusterStats.ts @@ -0,0 +1,36 @@ +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto + + +export interface TrackClusterStats { + /** + * If timeout_budgets is true, the :ref:`timeout budget histograms + * ` will be published for each + * request. These show what percentage of a request's per try and global timeout was used. A value + * of 0 would indicate that none of the timeout was used or that the timeout was infinite. A value + * of 100 would indicate that the request took the entirety of the timeout given to it. + */ + 'timeout_budgets'?: (boolean); + /** + * If request_response_sizes is true, then the :ref:`histograms + * ` tracking header and body sizes + * of requests and responses will be published. + */ + 'request_response_sizes'?: (boolean); +} + +export interface TrackClusterStats__Output { + /** + * If timeout_budgets is true, the :ref:`timeout budget histograms + * ` will be published for each + * request. These show what percentage of a request's per try and global timeout was used. A value + * of 0 would indicate that none of the timeout was used or that the timeout was infinite. A value + * of 100 would indicate that the request took the entirety of the timeout given to it. + */ + 'timeout_budgets': (boolean); + /** + * If request_response_sizes is true, then the :ref:`histograms + * ` tracking header and body sizes + * of requests and responses will be published. + */ + 'request_response_sizes': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts similarity index 59% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts index 966ccca85..0f95c0816 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/UpstreamBindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts @@ -1,6 +1,6 @@ -// Original file: deps/envoy-api/envoy/api/v2/cluster.proto +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto -import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; /** * An extensible structure containing the address Envoy should bind to when @@ -10,7 +10,7 @@ export interface UpstreamBindConfig { /** * The address Envoy should bind to when establishing upstream connections. */ - 'source_address'?: (_envoy_api_v2_core_Address); + 'source_address'?: (_envoy_config_core_v3_Address); } /** @@ -21,5 +21,5 @@ export interface UpstreamBindConfig__Output { /** * The address Envoy should bind to when establishing upstream connections. */ - 'source_address'?: (_envoy_api_v2_core_Address__Output); + 'source_address'?: (_envoy_config_core_v3_Address__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts new file mode 100644 index 000000000..2e7f23894 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto + +import type { TcpKeepalive as _envoy_config_core_v3_TcpKeepalive, TcpKeepalive__Output as _envoy_config_core_v3_TcpKeepalive__Output } from '../../../../envoy/config/core/v3/TcpKeepalive'; + +export interface UpstreamConnectionOptions { + /** + * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. + */ + 'tcp_keepalive'?: (_envoy_config_core_v3_TcpKeepalive); +} + +export interface UpstreamConnectionOptions__Output { + /** + * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. + */ + 'tcp_keepalive'?: (_envoy_config_core_v3_TcpKeepalive__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts new file mode 100644 index 000000000..4d5881baf --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + +import type { SocketAddress as _envoy_config_core_v3_SocketAddress, SocketAddress__Output as _envoy_config_core_v3_SocketAddress__Output } from '../../../../envoy/config/core/v3/SocketAddress'; +import type { Pipe as _envoy_config_core_v3_Pipe, Pipe__Output as _envoy_config_core_v3_Pipe__Output } from '../../../../envoy/config/core/v3/Pipe'; +import type { EnvoyInternalAddress as _envoy_config_core_v3_EnvoyInternalAddress, EnvoyInternalAddress__Output as _envoy_config_core_v3_EnvoyInternalAddress__Output } from '../../../../envoy/config/core/v3/EnvoyInternalAddress'; + +/** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ +export interface Address { + 'socket_address'?: (_envoy_config_core_v3_SocketAddress); + 'pipe'?: (_envoy_config_core_v3_Pipe); + /** + * [#not-implemented-hide:] + */ + 'envoy_internal_address'?: (_envoy_config_core_v3_EnvoyInternalAddress); + 'address'?: "socket_address"|"pipe"|"envoy_internal_address"; +} + +/** + * Addresses specify either a logical or physical address and port, which are + * used to tell Envoy where to bind/listen, connect to upstream and find + * management servers. + */ +export interface Address__Output { + 'socket_address'?: (_envoy_config_core_v3_SocketAddress__Output); + 'pipe'?: (_envoy_config_core_v3_Pipe__Output); + /** + * [#not-implemented-hide:] + */ + 'envoy_internal_address'?: (_envoy_config_core_v3_EnvoyInternalAddress__Output); + 'address': "socket_address"|"pipe"|"envoy_internal_address"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts similarity index 57% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts index 6837dd0db..824ef93c8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AggregatedConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts @@ -1,9 +1,9 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto /** * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to + * set in :ref:`ConfigSource ` can be used to * specify that ADS is to be used. */ export interface AggregatedConfigSource { @@ -11,7 +11,7 @@ export interface AggregatedConfigSource { /** * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to + * set in :ref:`ConfigSource ` can be used to * specify that ADS is to be used. */ export interface AggregatedConfigSource__Output { diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts similarity index 66% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts index a99924d9b..99afe9a26 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts @@ -1,21 +1,21 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import type { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; -import type { RateLimitSettings as _envoy_api_v2_core_RateLimitSettings, RateLimitSettings__Output as _envoy_api_v2_core_RateLimitSettings__Output } from '../../../../envoy/api/v2/core/RateLimitSettings'; -import type { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; +import type { GrpcService as _envoy_config_core_v3_GrpcService, GrpcService__Output as _envoy_config_core_v3_GrpcService__Output } from '../../../../envoy/config/core/v3/GrpcService'; +import type { RateLimitSettings as _envoy_config_core_v3_RateLimitSettings, RateLimitSettings__Output as _envoy_config_core_v3_RateLimitSettings__Output } from '../../../../envoy/config/core/v3/RateLimitSettings'; +import type { ApiVersion as _envoy_config_core_v3_ApiVersion } from '../../../../envoy/config/core/v3/ApiVersion'; -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto /** * APIs may be fetched via either REST or gRPC. */ -export enum _envoy_api_v2_core_ApiConfigSource_ApiType { +export enum _envoy_config_core_v3_ApiConfigSource_ApiType { /** * Ideally this would be 'reserved 0' but one can't reserve the default * value. Instead we throw an exception if this is ever used. */ - UNSUPPORTED_REST_LEGACY = 0, + DEPRECATED_AND_UNAVAILABLE_DO_NOT_USE = 0, /** * REST-JSON v2 API. The `canonical JSON encoding * `_ for @@ -23,7 +23,7 @@ export enum _envoy_api_v2_core_ApiConfigSource_ApiType { */ REST = 1, /** - * gRPC v2 API. + * SotW gRPC service. */ GRPC = 2, /** @@ -32,6 +32,18 @@ export enum _envoy_api_v2_core_ApiConfigSource_ApiType { * with every update, the xDS server only sends what has changed since the last update. */ DELTA_GRPC = 3, + /** + * SotW xDS gRPC with ADS. All resources which resolve to this configuration source will be + * multiplexed on a single connection to an ADS endpoint. + * [#not-implemented-hide:] + */ + AGGREGATED_GRPC = 5, + /** + * Delta xDS gRPC with ADS. All resources which resolve to this configuration source will be + * multiplexed on a single connection to an ADS endpoint. + * [#not-implemented-hide:] + */ + AGGREGATED_DELTA_GRPC = 6, } /** @@ -43,7 +55,7 @@ export interface ApiConfigSource { /** * API type (gRPC, REST, delta gRPC) */ - 'api_type'?: (_envoy_api_v2_core_ApiConfigSource_ApiType | keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); + 'api_type'?: (_envoy_config_core_v3_ApiConfigSource_ApiType | keyof typeof _envoy_config_core_v3_ApiConfigSource_ApiType); /** * Cluster names should be used only with REST. If > 1 * cluster is defined, clusters will be cycled through if any kind of failure @@ -63,7 +75,7 @@ export interface ApiConfigSource { * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, * services will be cycled through if any kind of failure occurs. */ - 'grpc_services'?: (_envoy_api_v2_core_GrpcService)[]; + 'grpc_services'?: (_envoy_config_core_v3_GrpcService)[]; /** * For REST APIs, the request timeout. If not set, a default value of 1s will be used. */ @@ -72,7 +84,7 @@ export interface ApiConfigSource { * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be * rate limited. */ - 'rate_limit_settings'?: (_envoy_api_v2_core_RateLimitSettings); + 'rate_limit_settings'?: (_envoy_config_core_v3_RateLimitSettings); /** * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. */ @@ -81,7 +93,7 @@ export interface ApiConfigSource { * API version for xDS transport protocol. This describes the xDS gRPC/REST * endpoint and version of [Delta]DiscoveryRequest/Response used on the wire. */ - 'transport_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); + 'transport_api_version'?: (_envoy_config_core_v3_ApiVersion | keyof typeof _envoy_config_core_v3_ApiVersion); } /** @@ -93,7 +105,7 @@ export interface ApiConfigSource__Output { /** * API type (gRPC, REST, delta gRPC) */ - 'api_type': (keyof typeof _envoy_api_v2_core_ApiConfigSource_ApiType); + 'api_type': (keyof typeof _envoy_config_core_v3_ApiConfigSource_ApiType); /** * Cluster names should be used only with REST. If > 1 * cluster is defined, clusters will be cycled through if any kind of failure @@ -113,7 +125,7 @@ export interface ApiConfigSource__Output { * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, * services will be cycled through if any kind of failure occurs. */ - 'grpc_services': (_envoy_api_v2_core_GrpcService__Output)[]; + 'grpc_services': (_envoy_config_core_v3_GrpcService__Output)[]; /** * For REST APIs, the request timeout. If not set, a default value of 1s will be used. */ @@ -122,7 +134,7 @@ export interface ApiConfigSource__Output { * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be * rate limited. */ - 'rate_limit_settings'?: (_envoy_api_v2_core_RateLimitSettings__Output); + 'rate_limit_settings'?: (_envoy_config_core_v3_RateLimitSettings__Output); /** * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. */ @@ -131,5 +143,5 @@ export interface ApiConfigSource__Output { * API version for xDS transport protocol. This describes the xDS gRPC/REST * endpoint and version of [Delta]DiscoveryRequest/Response used on the wire. */ - 'transport_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); + 'transport_api_version': (keyof typeof _envoy_config_core_v3_ApiVersion); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiVersion.ts similarity index 69% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiVersion.ts index 7f03a5995..b46f6ec43 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ApiVersion.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiVersion.ts @@ -1,7 +1,7 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto /** - * xDS API version. This is used to describe both resource and transport + * xDS API and non-xDS services version. This is used to describe both resource and transport * protocol versions (in distinct configuration fields). */ export enum ApiVersion { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts new file mode 100644 index 000000000..476ea851f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../envoy/config/core/v3/DataSource'; +import type { RemoteDataSource as _envoy_config_core_v3_RemoteDataSource, RemoteDataSource__Output as _envoy_config_core_v3_RemoteDataSource__Output } from '../../../../envoy/config/core/v3/RemoteDataSource'; + +/** + * Async data source which support async data fetch. + */ +export interface AsyncDataSource { + /** + * Local async data source. + */ + 'local'?: (_envoy_config_core_v3_DataSource); + /** + * Remote async data source. + */ + 'remote'?: (_envoy_config_core_v3_RemoteDataSource); + 'specifier'?: "local"|"remote"; +} + +/** + * Async data source which support async data fetch. + */ +export interface AsyncDataSource__Output { + /** + * Local async data source. + */ + 'local'?: (_envoy_config_core_v3_DataSource__Output); + /** + * Remote async data source. + */ + 'remote'?: (_envoy_config_core_v3_RemoteDataSource__Output); + 'specifier': "local"|"remote"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts new file mode 100644 index 000000000..9878375d6 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/backoff.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * Configuration defining a jittered exponential back off strategy. + */ +export interface BackoffStrategy { + /** + * The base interval to be used for the next back off computation. It should + * be greater than zero and less than or equal to :ref:`max_interval + * `. + */ + 'base_interval'?: (_google_protobuf_Duration); + /** + * Specifies the maximum interval between retries. This parameter is optional, + * but must be greater than or equal to the :ref:`base_interval + * ` if set. The default + * is 10 times the :ref:`base_interval + * `. + */ + 'max_interval'?: (_google_protobuf_Duration); +} + +/** + * Configuration defining a jittered exponential back off strategy. + */ +export interface BackoffStrategy__Output { + /** + * The base interval to be used for the next back off computation. It should + * be greater than zero and less than or equal to :ref:`max_interval + * `. + */ + 'base_interval'?: (_google_protobuf_Duration__Output); + /** + * Specifies the maximum interval between retries. This parameter is optional, + * but must be greater than or equal to the :ref:`base_interval + * ` if set. The default + * is 10 times the :ref:`base_interval + * `. + */ + 'max_interval'?: (_google_protobuf_Duration__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts new file mode 100644 index 000000000..eb2bc7626 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts @@ -0,0 +1,49 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + +import type { SocketAddress as _envoy_config_core_v3_SocketAddress, SocketAddress__Output as _envoy_config_core_v3_SocketAddress__Output } from '../../../../envoy/config/core/v3/SocketAddress'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { SocketOption as _envoy_config_core_v3_SocketOption, SocketOption__Output as _envoy_config_core_v3_SocketOption__Output } from '../../../../envoy/config/core/v3/SocketOption'; + +export interface BindConfig { + /** + * The address to bind to when creating a socket. + */ + 'source_address'?: (_envoy_config_core_v3_SocketAddress); + /** + * Whether to set the *IP_FREEBIND* option when creating the socket. When this + * flag is set to true, allows the :ref:`source_address + * ` to be an IP address + * that is not configured on the system running Envoy. When this flag is set + * to false, the option *IP_FREEBIND* is disabled on the socket. When this + * flag is not set (default), the socket is not modified, i.e. the option is + * neither enabled nor disabled. + */ + 'freebind'?: (_google_protobuf_BoolValue); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ + 'socket_options'?: (_envoy_config_core_v3_SocketOption)[]; +} + +export interface BindConfig__Output { + /** + * The address to bind to when creating a socket. + */ + 'source_address'?: (_envoy_config_core_v3_SocketAddress__Output); + /** + * Whether to set the *IP_FREEBIND* option when creating the socket. When this + * flag is set to true, allows the :ref:`source_address + * ` to be an IP address + * that is not configured on the system running Envoy. When this flag is set + * to false, the option *IP_FREEBIND* is disabled on the socket. When this + * flag is not set (default), the socket is not modified, i.e. the option is + * neither enabled nor disabled. + */ + 'freebind'?: (_google_protobuf_BoolValue__Output); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ + 'socket_options': (_envoy_config_core_v3_SocketOption__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts new file mode 100644 index 000000000..a3a33e4a3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts @@ -0,0 +1,36 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { SemanticVersion as _envoy_type_v3_SemanticVersion, SemanticVersion__Output as _envoy_type_v3_SemanticVersion__Output } from '../../../../envoy/type/v3/SemanticVersion'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; + +/** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ +export interface BuildVersion { + /** + * SemVer version of extension. + */ + 'version'?: (_envoy_type_v3_SemanticVersion); + /** + * Free-form build information. + * Envoy defines several well known keys in the source/common/version/version.h file + */ + 'metadata'?: (_google_protobuf_Struct); +} + +/** + * BuildVersion combines SemVer version of extension with free-form build information + * (i.e. 'alpha', 'private-build') as a set of strings. + */ +export interface BuildVersion__Output { + /** + * SemVer version of extension. + */ + 'version'?: (_envoy_type_v3_SemanticVersion__Output); + /** + * Free-form build information. + * Envoy defines several well known keys in the source/common/version/version.h file + */ + 'metadata'?: (_google_protobuf_Struct__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts new file mode 100644 index 000000000..c4a01b0da --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts @@ -0,0 +1,33 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +/** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ +export interface CidrRange { + /** + * IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. + */ + 'address_prefix'?: (string); + /** + * Length of prefix, e.g. 0, 32. + */ + 'prefix_len'?: (_google_protobuf_UInt32Value); +} + +/** + * CidrRange specifies an IP Address and a prefix length to construct + * the subnet mask for a `CIDR `_ range. + */ +export interface CidrRange__Output { + /** + * IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. + */ + 'address_prefix': (string); + /** + * Length of prefix, e.g. 0, 32. + */ + 'prefix_len'?: (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts similarity index 70% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts index 766af6148..9462f4844 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts @@ -1,24 +1,25 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto -import type { ApiConfigSource as _envoy_api_v2_core_ApiConfigSource, ApiConfigSource__Output as _envoy_api_v2_core_ApiConfigSource__Output } from '../../../../envoy/api/v2/core/ApiConfigSource'; -import type { AggregatedConfigSource as _envoy_api_v2_core_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_api_v2_core_AggregatedConfigSource__Output } from '../../../../envoy/api/v2/core/AggregatedConfigSource'; +import type { ApiConfigSource as _envoy_config_core_v3_ApiConfigSource, ApiConfigSource__Output as _envoy_config_core_v3_ApiConfigSource__Output } from '../../../../envoy/config/core/v3/ApiConfigSource'; +import type { AggregatedConfigSource as _envoy_config_core_v3_AggregatedConfigSource, AggregatedConfigSource__Output as _envoy_config_core_v3_AggregatedConfigSource__Output } from '../../../../envoy/config/core/v3/AggregatedConfigSource'; import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import type { SelfConfigSource as _envoy_api_v2_core_SelfConfigSource, SelfConfigSource__Output as _envoy_api_v2_core_SelfConfigSource__Output } from '../../../../envoy/api/v2/core/SelfConfigSource'; -import type { ApiVersion as _envoy_api_v2_core_ApiVersion } from '../../../../envoy/api/v2/core/ApiVersion'; +import type { SelfConfigSource as _envoy_config_core_v3_SelfConfigSource, SelfConfigSource__Output as _envoy_config_core_v3_SelfConfigSource__Output } from '../../../../envoy/config/core/v3/SelfConfigSource'; +import type { ApiVersion as _envoy_config_core_v3_ApiVersion } from '../../../../envoy/config/core/v3/ApiVersion'; +import type { Authority as _xds_core_v3_Authority, Authority__Output as _xds_core_v3_Authority__Output } from '../../../../xds/core/v3/Authority'; /** * Configuration for :ref:`listeners `, :ref:`clusters * `, :ref:`routes - * `, :ref:`endpoints + * `, :ref:`endpoints * ` etc. may either be sourced from the * filesystem or from an xDS API source. Filesystem configs are watched with * inotify for updates. - * [#next-free-field: 7] + * [#next-free-field: 8] */ export interface ConfigSource { /** * Path on the filesystem to source and watch for configuration updates. - * When sourcing configuration for :ref:`secret `, + * When sourcing configuration for :ref:`secret `, * the certificate and key files are also watched for updates. * * .. note:: @@ -35,12 +36,12 @@ export interface ConfigSource { /** * API configuration source. */ - 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource); + 'api_config_source'?: (_envoy_config_core_v3_ApiConfigSource); /** * When set, ADS will be used to fetch resources. The ADS API configuration * source in the bootstrap configuration is used. */ - 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource); + 'ads'?: (_envoy_config_core_v3_AggregatedConfigSource); /** * When this timeout is specified, Envoy will wait no longer than the specified time for first * config response on this xDS subscription during the :ref:`initialization process @@ -64,29 +65,36 @@ export interface ConfigSource { * this field can implicitly mean to use the same stream in the case where the ConfigSource * is provided via ADS and the specified data can also be obtained via ADS.] */ - 'self'?: (_envoy_api_v2_core_SelfConfigSource); + 'self'?: (_envoy_config_core_v3_SelfConfigSource); /** * API version for xDS resources. This implies the type URLs that the client * will request for resources and the resource type that the client will in * turn expect to be delivered. */ - 'resource_api_version'?: (_envoy_api_v2_core_ApiVersion | keyof typeof _envoy_api_v2_core_ApiVersion); + 'resource_api_version'?: (_envoy_config_core_v3_ApiVersion | keyof typeof _envoy_config_core_v3_ApiVersion); + /** + * Authorities that this config source may be used for. An authority specified in a xdstp:// URL + * is resolved to a *ConfigSource* prior to configuration fetch. This field provides the + * association between authority name and configuration source. + * [#not-implemented-hide:] + */ + 'authorities'?: (_xds_core_v3_Authority)[]; 'config_source_specifier'?: "path"|"api_config_source"|"ads"|"self"; } /** * Configuration for :ref:`listeners `, :ref:`clusters * `, :ref:`routes - * `, :ref:`endpoints + * `, :ref:`endpoints * ` etc. may either be sourced from the * filesystem or from an xDS API source. Filesystem configs are watched with * inotify for updates. - * [#next-free-field: 7] + * [#next-free-field: 8] */ export interface ConfigSource__Output { /** * Path on the filesystem to source and watch for configuration updates. - * When sourcing configuration for :ref:`secret `, + * When sourcing configuration for :ref:`secret `, * the certificate and key files are also watched for updates. * * .. note:: @@ -103,12 +111,12 @@ export interface ConfigSource__Output { /** * API configuration source. */ - 'api_config_source'?: (_envoy_api_v2_core_ApiConfigSource__Output); + 'api_config_source'?: (_envoy_config_core_v3_ApiConfigSource__Output); /** * When set, ADS will be used to fetch resources. The ADS API configuration * source in the bootstrap configuration is used. */ - 'ads'?: (_envoy_api_v2_core_AggregatedConfigSource__Output); + 'ads'?: (_envoy_config_core_v3_AggregatedConfigSource__Output); /** * When this timeout is specified, Envoy will wait no longer than the specified time for first * config response on this xDS subscription during the :ref:`initialization process @@ -132,12 +140,19 @@ export interface ConfigSource__Output { * this field can implicitly mean to use the same stream in the case where the ConfigSource * is provided via ADS and the specified data can also be obtained via ADS.] */ - 'self'?: (_envoy_api_v2_core_SelfConfigSource__Output); + 'self'?: (_envoy_config_core_v3_SelfConfigSource__Output); /** * API version for xDS resources. This implies the type URLs that the client * will request for resources and the resource type that the client will in * turn expect to be delivered. */ - 'resource_api_version': (keyof typeof _envoy_api_v2_core_ApiVersion); + 'resource_api_version': (keyof typeof _envoy_config_core_v3_ApiVersion); + /** + * Authorities that this config source may be used for. An authority specified in a xdstp:// URL + * is resolved to a *ConfigSource* prior to configuration fetch. This field provides the + * association between authority name and configuration source. + * [#not-implemented-hide:] + */ + 'authorities': (_xds_core_v3_Authority__Output)[]; 'config_source_specifier': "path"|"api_config_source"|"ads"|"self"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ControlPlane.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ControlPlane.ts new file mode 100644 index 000000000..dc55f8042 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ControlPlane.ts @@ -0,0 +1,26 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ +export interface ControlPlane { + /** + * An opaque control plane identifier that uniquely identifies an instance + * of control plane. This can be used to identify which control plane instance, + * the Envoy is connected to. + */ + 'identifier'?: (string); +} + +/** + * Identifies a specific ControlPlane instance that Envoy is connected to. + */ +export interface ControlPlane__Output { + /** + * An opaque control plane identifier that uniquely identifies an instance + * of control plane. This can be used to identify which control plane instance, + * the Envoy is connected to. + */ + 'identifier': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DataSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DataSource.ts new file mode 100644 index 000000000..cc29e084f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DataSource.ts @@ -0,0 +1,40 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Data source consisting of either a file or an inline value. + */ +export interface DataSource { + /** + * Local filesystem data source. + */ + 'filename'?: (string); + /** + * Bytes inlined in the configuration. + */ + 'inline_bytes'?: (Buffer | Uint8Array | string); + /** + * String inlined in the configuration. + */ + 'inline_string'?: (string); + 'specifier'?: "filename"|"inline_bytes"|"inline_string"; +} + +/** + * Data source consisting of either a file or an inline value. + */ +export interface DataSource__Output { + /** + * Local filesystem data source. + */ + 'filename'?: (string); + /** + * Bytes inlined in the configuration. + */ + 'inline_bytes'?: (Buffer); + /** + * String inlined in the configuration. + */ + 'inline_string'?: (string); + 'specifier': "filename"|"inline_bytes"|"inline_string"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts new file mode 100644 index 000000000..dfe6a52b4 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts @@ -0,0 +1,28 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + + +/** + * [#not-implemented-hide:] The address represents an envoy internal listener. + * TODO(lambdai): Make this address available for listener and endpoint. + * TODO(asraa): When address available, remove workaround from test/server/server_fuzz_test.cc:30. + */ +export interface EnvoyInternalAddress { + /** + * [#not-implemented-hide:] The :ref:`listener name ` of the destination internal listener. + */ + 'server_listener_name'?: (string); + 'address_name_specifier'?: "server_listener_name"; +} + +/** + * [#not-implemented-hide:] The address represents an envoy internal listener. + * TODO(lambdai): Make this address available for listener and endpoint. + * TODO(asraa): When address available, remove workaround from test/server/server_fuzz_test.cc:30. + */ +export interface EnvoyInternalAddress__Output { + /** + * [#not-implemented-hide:] The :ref:`listener name ` of the destination internal listener. + */ + 'server_listener_name'?: (string); + 'address_name_specifier': "server_listener_name"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts similarity index 58% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts index d0637578c..72aedc6ab 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/EventServiceConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts @@ -1,6 +1,6 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/event_service_config.proto +// Original file: deps/envoy-api/envoy/config/core/v3/event_service_config.proto -import type { GrpcService as _envoy_api_v2_core_GrpcService, GrpcService__Output as _envoy_api_v2_core_GrpcService__Output } from '../../../../envoy/api/v2/core/GrpcService'; +import type { GrpcService as _envoy_config_core_v3_GrpcService, GrpcService__Output as _envoy_config_core_v3_GrpcService__Output } from '../../../../envoy/config/core/v3/GrpcService'; /** * [#not-implemented-hide:] @@ -10,7 +10,7 @@ export interface EventServiceConfig { /** * Specifies the gRPC service that hosts the event reporting service. */ - 'grpc_service'?: (_envoy_api_v2_core_GrpcService); + 'grpc_service'?: (_envoy_config_core_v3_GrpcService); 'config_source_specifier'?: "grpc_service"; } @@ -22,6 +22,6 @@ export interface EventServiceConfig__Output { /** * Specifies the gRPC service that hosts the event reporting service. */ - 'grpc_service'?: (_envoy_api_v2_core_GrpcService__Output); + 'grpc_service'?: (_envoy_config_core_v3_GrpcService__Output); 'config_source_specifier': "grpc_service"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts new file mode 100644 index 000000000..0c7e0abd3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts @@ -0,0 +1,75 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { BuildVersion as _envoy_config_core_v3_BuildVersion, BuildVersion__Output as _envoy_config_core_v3_BuildVersion__Output } from '../../../../envoy/config/core/v3/BuildVersion'; + +/** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ +export interface Extension { + /** + * This is the name of the Envoy filter as specified in the Envoy + * configuration, e.g. envoy.filters.http.router, com.acme.widget. + */ + 'name'?: (string); + /** + * Category of the extension. + * Extension category names use reverse DNS notation. For instance "envoy.filters.listener" + * for Envoy's built-in listener filters or "com.acme.filters.http" for HTTP filters from + * acme.com vendor. + * [#comment:TODO(yanavlasov): Link to the doc with existing envoy category names.] + */ + 'category'?: (string); + /** + * [#not-implemented-hide:] Type descriptor of extension configuration proto. + * [#comment:TODO(yanavlasov): Link to the doc with existing configuration protos.] + * [#comment:TODO(yanavlasov): Add tests when PR #9391 lands.] + */ + 'type_descriptor'?: (string); + /** + * The version is a property of the extension and maintained independently + * of other extensions and the Envoy API. + * This field is not set when extension did not provide version information. + */ + 'version'?: (_envoy_config_core_v3_BuildVersion); + /** + * Indicates that the extension is present but was disabled via dynamic configuration. + */ + 'disabled'?: (boolean); +} + +/** + * Version and identification for an Envoy extension. + * [#next-free-field: 6] + */ +export interface Extension__Output { + /** + * This is the name of the Envoy filter as specified in the Envoy + * configuration, e.g. envoy.filters.http.router, com.acme.widget. + */ + 'name': (string); + /** + * Category of the extension. + * Extension category names use reverse DNS notation. For instance "envoy.filters.listener" + * for Envoy's built-in listener filters or "com.acme.filters.http" for HTTP filters from + * acme.com vendor. + * [#comment:TODO(yanavlasov): Link to the doc with existing envoy category names.] + */ + 'category': (string); + /** + * [#not-implemented-hide:] Type descriptor of extension configuration proto. + * [#comment:TODO(yanavlasov): Link to the doc with existing configuration protos.] + * [#comment:TODO(yanavlasov): Add tests when PR #9391 lands.] + */ + 'type_descriptor': (string); + /** + * The version is a property of the extension and maintained independently + * of other extensions and the Envoy API. + * This field is not set when extension did not provide version information. + */ + 'version'?: (_envoy_config_core_v3_BuildVersion__Output); + /** + * Indicates that the extension is present but was disabled via dynamic configuration. + */ + 'disabled': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts new file mode 100644 index 000000000..085324b6d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts @@ -0,0 +1,72 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/extension.proto + +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../envoy/config/core/v3/ConfigSource'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * Configuration source specifier for a late-bound extension configuration. The + * parent resource is warmed until all the initial extension configurations are + * received, unless the flag to apply the default configuration is set. + * Subsequent extension updates are atomic on a per-worker basis. Once an + * extension configuration is applied to a request or a connection, it remains + * constant for the duration of processing. If the initial delivery of the + * extension configuration fails, due to a timeout for example, the optional + * default configuration is applied. Without a default configuration, the + * extension is disabled, until an extension configuration is received. The + * behavior of a disabled extension depends on the context. For example, a + * filter chain with a disabled extension filter rejects all incoming streams. + */ +export interface ExtensionConfigSource { + 'config_source'?: (_envoy_config_core_v3_ConfigSource); + /** + * Optional default configuration to use as the initial configuration if + * there is a failure to receive the initial extension configuration or if + * `apply_default_config_without_warming` flag is set. + */ + 'default_config'?: (_google_protobuf_Any); + /** + * Use the default config as the initial configuration without warming and + * waiting for the first discovery response. Requires the default configuration + * to be supplied. + */ + 'apply_default_config_without_warming'?: (boolean); + /** + * A set of permitted extension type URLs. Extension configuration updates are rejected + * if they do not match any type URL in the set. + */ + 'type_urls'?: (string)[]; +} + +/** + * Configuration source specifier for a late-bound extension configuration. The + * parent resource is warmed until all the initial extension configurations are + * received, unless the flag to apply the default configuration is set. + * Subsequent extension updates are atomic on a per-worker basis. Once an + * extension configuration is applied to a request or a connection, it remains + * constant for the duration of processing. If the initial delivery of the + * extension configuration fails, due to a timeout for example, the optional + * default configuration is applied. Without a default configuration, the + * extension is disabled, until an extension configuration is received. The + * behavior of a disabled extension depends on the context. For example, a + * filter chain with a disabled extension filter rejects all incoming streams. + */ +export interface ExtensionConfigSource__Output { + 'config_source'?: (_envoy_config_core_v3_ConfigSource__Output); + /** + * Optional default configuration to use as the initial configuration if + * there is a failure to receive the initial extension configuration or if + * `apply_default_config_without_warming` flag is set. + */ + 'default_config'?: (_google_protobuf_Any__Output); + /** + * Use the default config as the initial configuration without warming and + * waiting for the first discovery response. Requires the default configuration + * to be supplied. + */ + 'apply_default_config_without_warming': (boolean); + /** + * A set of permitted extension type URLs. Extension configuration updates are rejected + * if they do not match any type URL in the set. + */ + 'type_urls': (string)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts new file mode 100644 index 000000000..b0486cc37 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto + +import type { Http2ProtocolOptions as _envoy_config_core_v3_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_config_core_v3_Http2ProtocolOptions__Output } from '../../../../envoy/config/core/v3/Http2ProtocolOptions'; + +/** + * [#not-implemented-hide:] + */ +export interface GrpcProtocolOptions { + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions); +} + +/** + * [#not-implemented-hide:] + */ +export interface GrpcProtocolOptions__Output { + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts similarity index 59% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts index 3bc894b57..24249309b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/GrpcService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts @@ -1,9 +1,10 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/grpc_service.proto +// Original file: deps/envoy-api/envoy/config/core/v3/grpc_service.proto import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import type { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; +import type { HeaderValue as _envoy_config_core_v3_HeaderValue, HeaderValue__Output as _envoy_config_core_v3_HeaderValue__Output } from '../../../../envoy/config/core/v3/HeaderValue'; import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../envoy/config/core/v3/DataSource'; import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../../../google/protobuf/Empty'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import type { Long } from '@grpc/proto-loader'; @@ -11,7 +12,7 @@ import type { Long } from '@grpc/proto-loader'; /** * [#next-free-field: 8] */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials { /** * Access token credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. @@ -31,31 +32,31 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials { * Service Account JWT Access credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. */ - 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); + 'service_account_jwt_access'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); /** * Google IAM credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. */ - 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); + 'google_iam'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); /** * Custom authenticator credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. */ - 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); + 'from_plugin'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); /** * Custom security token service which implements OAuth 2.0 token exchange. * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 * See https://github.com/grpc/grpc/pull/19587. */ - 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService); + 'sts_service'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService); 'credential_specifier'?: "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } /** * [#next-free-field: 8] */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials__Output { /** * Access token credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#ad3a80da696ffdaea943f0f858d7a360d. @@ -75,38 +76,58 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Outp * Service Account JWT Access credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. */ - 'service_account_jwt_access'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); + 'service_account_jwt_access'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); /** * Google IAM credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. */ - 'google_iam'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); + 'google_iam'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); /** * Custom authenticator credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. */ - 'from_plugin'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); + 'from_plugin'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); /** * Custom security token service which implements OAuth 2.0 token exchange. * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 * See https://github.com/grpc/grpc/pull/19587. */ - 'sts_service'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); + 'sts_service'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } +/** + * Channel arguments. + */ +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs { + /** + * See grpc_types.h GRPC_ARG #defines for keys that work here. + */ + 'args'?: ({[key: string]: _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value}); +} + +/** + * Channel arguments. + */ +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs__Output { + /** + * See grpc_types.h GRPC_ARG #defines for keys that work here. + */ + 'args'?: ({[key: string]: _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value__Output}); +} + /** * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call * credential types. */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { - 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials); +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials { + 'ssl_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials); /** * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 */ 'google_default'?: (_google_protobuf_Empty); - 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials); + 'local_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials); 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; } @@ -114,50 +135,60 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials { * See https://grpc.io/docs/guides/auth.html#credential-types to understand Channel and Call * credential types. */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output { - 'ssl_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output); +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials__Output { + 'ssl_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials__Output); /** * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 */ 'google_default'?: (_google_protobuf_Empty__Output); - 'local_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); + 'local_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; } -export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc { +export interface _envoy_config_core_v3_GrpcService_EnvoyGrpc { /** * The name of the upstream gRPC cluster. SSL credentials will be supplied - * in the :ref:`Cluster ` :ref:`transport_socket - * `. + * in the :ref:`Cluster ` :ref:`transport_socket + * `. */ 'cluster_name'?: (string); + /** + * The `:authority` header in the grpc request. If this field is not set, the authority header value will be `cluster_name`. + * Note that this authority does not override the SNI. The SNI is provided by the transport socket of the cluster. + */ + 'authority'?: (string); } -export interface _envoy_api_v2_core_GrpcService_EnvoyGrpc__Output { +export interface _envoy_config_core_v3_GrpcService_EnvoyGrpc__Output { /** * The name of the upstream gRPC cluster. SSL credentials will be supplied - * in the :ref:`Cluster ` :ref:`transport_socket - * `. + * in the :ref:`Cluster ` :ref:`transport_socket + * `. */ 'cluster_name': (string); + /** + * The `:authority` header in the grpc request. If this field is not set, the authority header value will be `cluster_name`. + * Note that this authority does not override the SNI. The SNI is provided by the transport socket of the cluster. + */ + 'authority': (string); } /** - * [#next-free-field: 7] + * [#next-free-field: 9] */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc { /** * The target URI when using the `Google C++ gRPC client * `_. SSL credentials will be supplied in - * :ref:`channel_credentials `. + * :ref:`channel_credentials `. */ 'target_uri'?: (string); - 'channel_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials); + 'channel_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials); /** * A set of call credentials that can be composed with `channel credentials * `_. */ - 'call_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials)[]; + 'call_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials)[]; /** * The human readable prefix to use when emitting statistics for the gRPC * service. @@ -181,24 +212,33 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc { * gRPC library. */ 'config'?: (_google_protobuf_Struct); + /** + * How many bytes each stream can buffer internally. + * If not set an implementation defined default is applied (1MiB). + */ + 'per_stream_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + /** + * Custom channels args. + */ + 'channel_args'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs); } /** - * [#next-free-field: 7] + * [#next-free-field: 9] */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc__Output { /** * The target URI when using the `Google C++ gRPC client * `_. SSL credentials will be supplied in - * :ref:`channel_credentials `. + * :ref:`channel_credentials `. */ 'target_uri': (string); - 'channel_credentials'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc_ChannelCredentials__Output); + 'channel_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials__Output); /** * A set of call credentials that can be composed with `channel credentials * `_. */ - 'call_credentials': (_envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials__Output)[]; + 'call_credentials': (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials__Output)[]; /** * The human readable prefix to use when emitting statistics for the gRPC * service. @@ -222,14 +262,23 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc__Output { * gRPC library. */ 'config'?: (_google_protobuf_Struct__Output); + /** + * How many bytes each stream can buffer internally. + * If not set an implementation defined default is applied (1MiB). + */ + 'per_stream_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); + /** + * Custom channels args. + */ + 'channel_args'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs__Output); } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { 'authorization_token'?: (string); 'authority_selector'?: (string); } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output { 'authorization_token': (string); 'authority_selector': (string); } @@ -238,36 +287,34 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_Googl * Local channel credentials. Only UDS is supported for now. * See https://github.com/grpc/grpc/pull/15909. */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials { } /** * Local channel credentials. Only UDS is supported for now. * See https://github.com/grpc/grpc/pull/15909. */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output { } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin { 'name'?: (string); - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output { 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials { 'json_key'?: (string); 'token_lifetime_seconds'?: (number | string | Long); } -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output { 'json_key': (string); 'token_lifetime_seconds': (string); } @@ -275,37 +322,37 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_Servi /** * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials { /** * PEM encoded server root certificates. */ - 'root_certs'?: (_envoy_api_v2_core_DataSource); + 'root_certs'?: (_envoy_config_core_v3_DataSource); /** * PEM encoded client private key. */ - 'private_key'?: (_envoy_api_v2_core_DataSource); + 'private_key'?: (_envoy_config_core_v3_DataSource); /** * PEM encoded client certificate chain. */ - 'cert_chain'?: (_envoy_api_v2_core_DataSource); + 'cert_chain'?: (_envoy_config_core_v3_DataSource); } /** * See https://grpc.io/grpc/cpp/structgrpc_1_1_ssl_credentials_options.html. */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials__Output { /** * PEM encoded server root certificates. */ - 'root_certs'?: (_envoy_api_v2_core_DataSource__Output); + 'root_certs'?: (_envoy_config_core_v3_DataSource__Output); /** * PEM encoded client private key. */ - 'private_key'?: (_envoy_api_v2_core_DataSource__Output); + 'private_key'?: (_envoy_config_core_v3_DataSource__Output); /** * PEM encoded client certificate chain. */ - 'cert_chain'?: (_envoy_api_v2_core_DataSource__Output); + 'cert_chain'?: (_envoy_config_core_v3_DataSource__Output); } /** @@ -315,7 +362,7 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_SslCredentials__Outpu * https://github.com/grpc/grpc/pull/19587. * [#next-free-field: 10] */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService { /** * URI of the token exchange service that handles token exchange requests. * [#comment:TODO(asraa): Add URI validation when implemented. Tracked by @@ -369,7 +416,7 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsSe * https://github.com/grpc/grpc/pull/19587. * [#next-free-field: 10] */ -export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsService__Output { +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService__Output { /** * URI of the token exchange service that handles token exchange requests. * [#comment:TODO(asraa): Add URI validation when implemented. Tracked by @@ -416,9 +463,29 @@ export interface _envoy_api_v2_core_GrpcService_GoogleGrpc_CallCredentials_StsSe 'actor_token_type': (string); } +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value { + 'string_value'?: (string); + 'int_value'?: (number | string | Long); + /** + * Pointer values are not supported, since they don't make any sense when + * delivered via the API. + */ + 'value_specifier'?: "string_value"|"int_value"; +} + +export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value__Output { + 'string_value'?: (string); + 'int_value'?: (string); + /** + * Pointer values are not supported, since they don't make any sense when + * delivered via the API. + */ + 'value_specifier': "string_value"|"int_value"; +} + /** * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. + * ` and filter configurations. * [#next-free-field: 6] */ export interface GrpcService { @@ -427,30 +494,32 @@ export interface GrpcService { * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc); + 'envoy_grpc'?: (_envoy_config_core_v3_GrpcService_EnvoyGrpc); /** * `Google C++ gRPC client `_ * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc); + 'google_grpc'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc); /** * The timeout for the gRPC request. This is the timeout for a specific * request. */ 'timeout'?: (_google_protobuf_Duration); /** - * Additional metadata to include in streams initiated to the GrpcService. - * This can be used for scenarios in which additional ad hoc authorization - * headers (e.g. ``x-foo-bar: baz-key``) are to be injected. + * Additional metadata to include in streams initiated to the GrpcService. This can be used for + * scenarios in which additional ad hoc authorization headers (e.g. ``x-foo-bar: baz-key``) are to + * be injected. For more information, including details on header value syntax, see the + * documentation on :ref:`custom request headers + * `. */ - 'initial_metadata'?: (_envoy_api_v2_core_HeaderValue)[]; + 'initial_metadata'?: (_envoy_config_core_v3_HeaderValue)[]; 'target_specifier'?: "envoy_grpc"|"google_grpc"; } /** * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. + * ` and filter configurations. * [#next-free-field: 6] */ export interface GrpcService__Output { @@ -459,23 +528,25 @@ export interface GrpcService__Output { * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'envoy_grpc'?: (_envoy_api_v2_core_GrpcService_EnvoyGrpc__Output); + 'envoy_grpc'?: (_envoy_config_core_v3_GrpcService_EnvoyGrpc__Output); /** * `Google C++ gRPC client `_ * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'google_grpc'?: (_envoy_api_v2_core_GrpcService_GoogleGrpc__Output); + 'google_grpc'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc__Output); /** * The timeout for the gRPC request. This is the timeout for a specific * request. */ 'timeout'?: (_google_protobuf_Duration__Output); /** - * Additional metadata to include in streams initiated to the GrpcService. - * This can be used for scenarios in which additional ad hoc authorization - * headers (e.g. ``x-foo-bar: baz-key``) are to be injected. + * Additional metadata to include in streams initiated to the GrpcService. This can be used for + * scenarios in which additional ad hoc authorization headers (e.g. ``x-foo-bar: baz-key``) are to + * be injected. For more information, including details on header value syntax, see the + * documentation on :ref:`custom request headers + * `. */ - 'initial_metadata': (_envoy_api_v2_core_HeaderValue__Output)[]; + 'initial_metadata': (_envoy_config_core_v3_HeaderValue__Output)[]; 'target_specifier': "envoy_grpc"|"google_grpc"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderMap.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderMap.ts new file mode 100644 index 000000000..3ee496152 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderMap.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { HeaderValue as _envoy_config_core_v3_HeaderValue, HeaderValue__Output as _envoy_config_core_v3_HeaderValue__Output } from '../../../../envoy/config/core/v3/HeaderValue'; + +/** + * Wrapper for a set of headers. + */ +export interface HeaderMap { + 'headers'?: (_envoy_config_core_v3_HeaderValue)[]; +} + +/** + * Wrapper for a set of headers. + */ +export interface HeaderMap__Output { + 'headers': (_envoy_config_core_v3_HeaderValue__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValue.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValue.ts new file mode 100644 index 000000000..a9fb6c07a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValue.ts @@ -0,0 +1,38 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Header name/value pair. + */ +export interface HeaderValue { + /** + * Header name. + */ + 'key'?: (string); + /** + * Header value. + * + * The same :ref:`format specifier ` as used for + * :ref:`HTTP access logging ` applies here, however + * unknown header values are replaced with the empty string instead of `-`. + */ + 'value'?: (string); +} + +/** + * Header name/value pair. + */ +export interface HeaderValue__Output { + /** + * Header name. + */ + 'key': (string); + /** + * Header value. + * + * The same :ref:`format specifier ` as used for + * :ref:`HTTP access logging ` applies here, however + * unknown header values are replaced with the empty string instead of `-`. + */ + 'value': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts new file mode 100644 index 000000000..4a0fe7120 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { HeaderValue as _envoy_config_core_v3_HeaderValue, HeaderValue__Output as _envoy_config_core_v3_HeaderValue__Output } from '../../../../envoy/config/core/v3/HeaderValue'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +/** + * Header name/value pair plus option to control append behavior. + */ +export interface HeaderValueOption { + /** + * Header name/value pair that this option applies to. + */ + 'header'?: (_envoy_config_core_v3_HeaderValue); + /** + * Should the value be appended? If true (default), the value is appended to + * existing values. Otherwise it replaces any existing values. + */ + 'append'?: (_google_protobuf_BoolValue); +} + +/** + * Header name/value pair plus option to control append behavior. + */ +export interface HeaderValueOption__Output { + /** + * Header name/value pair that this option applies to. + */ + 'header'?: (_envoy_config_core_v3_HeaderValue__Output); + /** + * Should the value be appended? If true (default), the value is appended to + * existing values. Otherwise it replaces any existing values. + */ + 'append'?: (_google_protobuf_BoolValue__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts similarity index 67% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts index 0b45042f3..3a7320a08 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthCheck.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts @@ -1,49 +1,47 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/health_check.proto +// Original file: deps/envoy-api/envoy/config/core/v3/health_check.proto import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { EventServiceConfig as _envoy_api_v2_core_EventServiceConfig, EventServiceConfig__Output as _envoy_api_v2_core_EventServiceConfig__Output } from '../../../../envoy/api/v2/core/EventServiceConfig'; -import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import type { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; -import type { CodecClientType as _envoy_type_CodecClientType } from '../../../../envoy/type/CodecClientType'; -import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import type { EventServiceConfig as _envoy_config_core_v3_EventServiceConfig, EventServiceConfig__Output as _envoy_config_core_v3_EventServiceConfig__Output } from '../../../../envoy/config/core/v3/EventServiceConfig'; import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, HeaderValueOption__Output as _envoy_config_core_v3_HeaderValueOption__Output } from '../../../../envoy/config/core/v3/HeaderValueOption'; +import type { Int64Range as _envoy_type_v3_Int64Range, Int64Range__Output as _envoy_type_v3_Int64Range__Output } from '../../../../envoy/type/v3/Int64Range'; +import type { CodecClientType as _envoy_type_v3_CodecClientType } from '../../../../envoy/type/v3/CodecClientType'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import type { Long } from '@grpc/proto-loader'; /** * Custom health check. */ -export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck { +export interface _envoy_config_core_v3_HealthCheck_CustomHealthCheck { /** * The registered name of the custom health checker. */ 'name'?: (string); - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); /** * A custom health checker specific configuration which depends on the custom health checker * being instantiated. See :api:`envoy/config/health_checker` for reference. */ - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } /** * Custom health check. */ -export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output { +export interface _envoy_config_core_v3_HealthCheck_CustomHealthCheck__Output { /** * The registered name of the custom health checker. */ 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** * A custom health checker specific configuration which depends on the custom health checker * being instantiated. See :api:`envoy/config/health_checker` for reference. */ - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } /** @@ -52,7 +50,7 @@ export interface _envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output { * healthcheck. See `gRPC doc `_ * for details. */ -export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { +export interface _envoy_config_core_v3_HealthCheck_GrpcHealthCheck { /** * An optional service name parameter which will be sent to gRPC service in * `grpc.health.v1.HealthCheckRequest @@ -65,7 +63,7 @@ export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { * The value of the :authority header in the gRPC health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The authority header can be customized for a specific endpoint by setting - * the :ref:`hostname ` field. + * the :ref:`hostname ` field. */ 'authority'?: (string); } @@ -76,7 +74,7 @@ export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck { * healthcheck. See `gRPC doc `_ * for details. */ -export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { +export interface _envoy_config_core_v3_HealthCheck_GrpcHealthCheck__Output { /** * An optional service name parameter which will be sent to gRPC service in * `grpc.health.v1.HealthCheckRequest @@ -89,7 +87,7 @@ export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { * The value of the :authority header in the gRPC health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The authority header can be customized for a specific endpoint by setting - * the :ref:`hostname ` field. + * the :ref:`hostname ` field. */ 'authority': (string); } @@ -97,12 +95,12 @@ export interface _envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output { /** * [#next-free-field: 12] */ -export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck { +export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck { /** * The value of the host header in the HTTP health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The host header can be customized for a specific endpoint by setting the - * :ref:`hostname ` field. + * :ref:`hostname ` field. */ 'host'?: (string); /** @@ -113,69 +111,52 @@ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck { /** * [#not-implemented-hide:] HTTP specific payload. */ - 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + 'send'?: (_envoy_config_core_v3_HealthCheck_Payload); /** * [#not-implemented-hide:] HTTP specific response. */ - 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload); - /** - * An optional service name parameter which is used to validate the identity of - * the health checked cluster. See the :ref:`architecture overview - * ` for more information. - * - * .. attention:: - * - * This field has been deprecated in favor of `service_name_matcher` for better flexibility - * over matching with service-cluster name. - */ - 'service_name'?: (string); + 'receive'?: (_envoy_config_core_v3_HealthCheck_Payload); /** * Specifies a list of HTTP headers that should be added to each request that is sent to the * health checked cluster. For more information, including details on header value syntax, see * the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of HTTP headers that should be removed from each request that is sent to the * health checked cluster. */ 'request_headers_to_remove'?: (string)[]; - /** - * If set, health checks will be made using http/2. - * Deprecated, use :ref:`codec_client_type - * ` instead. - */ - 'use_http2'?: (boolean); /** * Specifies a list of HTTP response statuses considered healthy. If provided, replaces default * 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open - * semantics of :ref:`Int64Range `. The start and end of each + * semantics of :ref:`Int64Range `. The start and end of each * range are required. Only statuses in the range [100, 600) are allowed. */ - 'expected_statuses'?: (_envoy_type_Int64Range)[]; + 'expected_statuses'?: (_envoy_type_v3_Int64Range)[]; /** * Use specified application protocol for health checks. */ - 'codec_client_type'?: (_envoy_type_CodecClientType | keyof typeof _envoy_type_CodecClientType); + 'codec_client_type'?: (_envoy_type_v3_CodecClientType | keyof typeof _envoy_type_v3_CodecClientType); /** * An optional service name parameter which is used to validate the identity of * the health checked cluster using a :ref:`StringMatcher - * `. See the :ref:`architecture overview + * `. See the :ref:`architecture overview * ` for more information. */ - 'service_name_matcher'?: (_envoy_type_matcher_StringMatcher); + 'service_name_matcher'?: (_envoy_type_matcher_v3_StringMatcher); } /** * [#next-free-field: 12] */ -export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { +export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output { /** * The value of the host header in the HTTP health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The host header can be customized for a specific endpoint by setting the - * :ref:`hostname ` field. + * :ref:`hostname ` field. */ 'host': (string); /** @@ -186,64 +167,47 @@ export interface _envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output { /** * [#not-implemented-hide:] HTTP specific payload. */ - 'send'?: (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'send'?: (_envoy_config_core_v3_HealthCheck_Payload__Output); /** * [#not-implemented-hide:] HTTP specific response. */ - 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload__Output); - /** - * An optional service name parameter which is used to validate the identity of - * the health checked cluster. See the :ref:`architecture overview - * ` for more information. - * - * .. attention:: - * - * This field has been deprecated in favor of `service_name_matcher` for better flexibility - * over matching with service-cluster name. - */ - 'service_name': (string); + 'receive'?: (_envoy_config_core_v3_HealthCheck_Payload__Output); /** * Specifies a list of HTTP headers that should be added to each request that is sent to the * health checked cluster. For more information, including details on header value syntax, see * the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of HTTP headers that should be removed from each request that is sent to the * health checked cluster. */ 'request_headers_to_remove': (string)[]; - /** - * If set, health checks will be made using http/2. - * Deprecated, use :ref:`codec_client_type - * ` instead. - */ - 'use_http2': (boolean); /** * Specifies a list of HTTP response statuses considered healthy. If provided, replaces default * 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open - * semantics of :ref:`Int64Range `. The start and end of each + * semantics of :ref:`Int64Range `. The start and end of each * range are required. Only statuses in the range [100, 600) are allowed. */ - 'expected_statuses': (_envoy_type_Int64Range__Output)[]; + 'expected_statuses': (_envoy_type_v3_Int64Range__Output)[]; /** * Use specified application protocol for health checks. */ - 'codec_client_type': (keyof typeof _envoy_type_CodecClientType); + 'codec_client_type': (keyof typeof _envoy_type_v3_CodecClientType); /** * An optional service name parameter which is used to validate the identity of * the health checked cluster using a :ref:`StringMatcher - * `. See the :ref:`architecture overview + * `. See the :ref:`architecture overview * ` for more information. */ - 'service_name_matcher'?: (_envoy_type_matcher_StringMatcher__Output); + 'service_name_matcher'?: (_envoy_type_matcher_v3_StringMatcher__Output); } /** * Describes the encoding of the payload bytes in the payload. */ -export interface _envoy_api_v2_core_HealthCheck_Payload { +export interface _envoy_config_core_v3_HealthCheck_Payload { /** * Hex encoded payload. E.g., "000000FF". */ @@ -258,7 +222,7 @@ export interface _envoy_api_v2_core_HealthCheck_Payload { /** * Describes the encoding of the payload bytes in the payload. */ -export interface _envoy_api_v2_core_HealthCheck_Payload__Output { +export interface _envoy_config_core_v3_HealthCheck_Payload__Output { /** * Hex encoded payload. E.g., "000000FF". */ @@ -270,7 +234,7 @@ export interface _envoy_api_v2_core_HealthCheck_Payload__Output { 'payload': "text"|"binary"; } -export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck { +export interface _envoy_config_core_v3_HealthCheck_RedisHealthCheck { /** * If set, optionally perform ``EXISTS `` instead of ``PING``. A return value * from Redis of 0 (does not exist) is considered a passing healthcheck. A return value other @@ -280,7 +244,7 @@ export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck { 'key'?: (string); } -export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck__Output { +export interface _envoy_config_core_v3_HealthCheck_RedisHealthCheck__Output { /** * If set, optionally perform ``EXISTS `` instead of ``PING``. A return value * from Redis of 0 (does not exist) is considered a passing healthcheck. A return value other @@ -290,30 +254,30 @@ export interface _envoy_api_v2_core_HealthCheck_RedisHealthCheck__Output { 'key': (string); } -export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck { +export interface _envoy_config_core_v3_HealthCheck_TcpHealthCheck { /** * Empty payloads imply a connect-only health check. */ - 'send'?: (_envoy_api_v2_core_HealthCheck_Payload); + 'send'?: (_envoy_config_core_v3_HealthCheck_Payload); /** * When checking the response, “fuzzy†matching is performed such that each * binary block must be found, and in the order specified, but not * necessarily contiguous. */ - 'receive'?: (_envoy_api_v2_core_HealthCheck_Payload)[]; + 'receive'?: (_envoy_config_core_v3_HealthCheck_Payload)[]; } -export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { +export interface _envoy_config_core_v3_HealthCheck_TcpHealthCheck__Output { /** * Empty payloads imply a connect-only health check. */ - 'send'?: (_envoy_api_v2_core_HealthCheck_Payload__Output); + 'send'?: (_envoy_config_core_v3_HealthCheck_Payload__Output); /** * When checking the response, “fuzzy†matching is performed such that each * binary block must be found, and in the order specified, but not * necessarily contiguous. */ - 'receive': (_envoy_api_v2_core_HealthCheck_Payload__Output)[]; + 'receive': (_envoy_config_core_v3_HealthCheck_Payload__Output)[]; } /** @@ -322,11 +286,11 @@ export interface _envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output { * * This allows overriding the cluster TLS settings, just for health check connections. */ -export interface _envoy_api_v2_core_HealthCheck_TlsOptions { +export interface _envoy_config_core_v3_HealthCheck_TlsOptions { /** * Specifies the ALPN protocols for health check connections. This is useful if the * corresponding upstream is using ALPN-based :ref:`FilterChainMatch - * ` along with different protocols for health checks + * ` along with different protocols for health checks * versus data connections. If empty, no ALPN protocols will be set on health check connections. */ 'alpn_protocols'?: (string)[]; @@ -338,18 +302,18 @@ export interface _envoy_api_v2_core_HealthCheck_TlsOptions { * * This allows overriding the cluster TLS settings, just for health check connections. */ -export interface _envoy_api_v2_core_HealthCheck_TlsOptions__Output { +export interface _envoy_config_core_v3_HealthCheck_TlsOptions__Output { /** * Specifies the ALPN protocols for health check connections. This is useful if the * corresponding upstream is using ALPN-based :ref:`FilterChainMatch - * ` along with different protocols for health checks + * ` along with different protocols for health checks * versus data connections. If empty, no ALPN protocols will be set on health check connections. */ 'alpn_protocols': (string)[]; } /** - * [#next-free-field: 23] + * [#next-free-field: 25] */ export interface HealthCheck { /** @@ -389,15 +353,15 @@ export interface HealthCheck { /** * HTTP health check. */ - 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck); + 'http_health_check'?: (_envoy_config_core_v3_HealthCheck_HttpHealthCheck); /** * TCP health check. */ - 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck); + 'tcp_health_check'?: (_envoy_config_core_v3_HealthCheck_TcpHealthCheck); /** * gRPC health check. */ - 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck); + 'grpc_health_check'?: (_envoy_config_core_v3_HealthCheck_GrpcHealthCheck); /** * The "no traffic interval" is a special health check interval that is used when a cluster has * never had traffic routed to it. This lower interval allows cluster information to be kept up to @@ -412,7 +376,7 @@ export interface HealthCheck { /** * Custom health check. */ - 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck); + 'custom_health_check'?: (_envoy_config_core_v3_HealthCheck_CustomHealthCheck); /** * The "unhealthy interval" is a health check interval that is used for hosts that are marked as * unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the @@ -467,18 +431,67 @@ export interface HealthCheck { /** * This allows overriding the cluster TLS settings, just for health check connections. */ - 'tls_options'?: (_envoy_api_v2_core_HealthCheck_TlsOptions); + 'tls_options'?: (_envoy_config_core_v3_HealthCheck_TlsOptions); /** * [#not-implemented-hide:] * The gRPC service for the health check event service. * If empty, health check events won't be sent to a remote endpoint. */ - 'event_service'?: (_envoy_api_v2_core_EventServiceConfig); + 'event_service'?: (_envoy_config_core_v3_EventServiceConfig); + /** + * Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's + * :ref:`tranport socket matches `. + * For example, the following match criteria + * + * .. code-block:: yaml + * + * transport_socket_match_criteria: + * useMTLS: true + * + * Will match the following :ref:`cluster socket match ` + * + * .. code-block:: yaml + * + * transport_socket_matches: + * - name: "useMTLS" + * match: + * useMTLS: true + * transport_socket: + * name: envoy.transport_sockets.tls + * config: { ... } # tls socket configuration + * + * If this field is set, then for health checks it will supersede an entry of *envoy.transport_socket* in the + * :ref:`LbEndpoint.Metadata `. + * This allows using different transport socket capabilities for health checking versus proxying to the + * endpoint. + * + * If the key/values pairs specified do not match any + * :ref:`transport socket matches `, + * the cluster's :ref:`transport socket ` + * will be used for health check socket configuration. + */ + 'transport_socket_match_criteria'?: (_google_protobuf_Struct); + /** + * The "no traffic healthy interval" is a special health check interval that + * is used for hosts that are currently passing active health checking + * (including new hosts) when the cluster has received no traffic. + * + * This is useful for when we want to send frequent health checks with + * `no_traffic_interval` but then revert to lower frequency `no_traffic_healthy_interval` once + * a host in the cluster is marked as healthy. + * + * Once a cluster has been used for traffic routing, Envoy will shift back to using the + * standard health check interval that is defined. + * + * If no_traffic_healthy_interval is not set, it will default to the + * no traffic interval and send that interval regardless of health state. + */ + 'no_traffic_healthy_interval'?: (_google_protobuf_Duration); 'health_checker'?: "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } /** - * [#next-free-field: 23] + * [#next-free-field: 25] */ export interface HealthCheck__Output { /** @@ -518,15 +531,15 @@ export interface HealthCheck__Output { /** * HTTP health check. */ - 'http_health_check'?: (_envoy_api_v2_core_HealthCheck_HttpHealthCheck__Output); + 'http_health_check'?: (_envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output); /** * TCP health check. */ - 'tcp_health_check'?: (_envoy_api_v2_core_HealthCheck_TcpHealthCheck__Output); + 'tcp_health_check'?: (_envoy_config_core_v3_HealthCheck_TcpHealthCheck__Output); /** * gRPC health check. */ - 'grpc_health_check'?: (_envoy_api_v2_core_HealthCheck_GrpcHealthCheck__Output); + 'grpc_health_check'?: (_envoy_config_core_v3_HealthCheck_GrpcHealthCheck__Output); /** * The "no traffic interval" is a special health check interval that is used when a cluster has * never had traffic routed to it. This lower interval allows cluster information to be kept up to @@ -541,7 +554,7 @@ export interface HealthCheck__Output { /** * Custom health check. */ - 'custom_health_check'?: (_envoy_api_v2_core_HealthCheck_CustomHealthCheck__Output); + 'custom_health_check'?: (_envoy_config_core_v3_HealthCheck_CustomHealthCheck__Output); /** * The "unhealthy interval" is a health check interval that is used for hosts that are marked as * unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the @@ -596,12 +609,61 @@ export interface HealthCheck__Output { /** * This allows overriding the cluster TLS settings, just for health check connections. */ - 'tls_options'?: (_envoy_api_v2_core_HealthCheck_TlsOptions__Output); + 'tls_options'?: (_envoy_config_core_v3_HealthCheck_TlsOptions__Output); /** * [#not-implemented-hide:] * The gRPC service for the health check event service. * If empty, health check events won't be sent to a remote endpoint. */ - 'event_service'?: (_envoy_api_v2_core_EventServiceConfig__Output); + 'event_service'?: (_envoy_config_core_v3_EventServiceConfig__Output); + /** + * Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's + * :ref:`tranport socket matches `. + * For example, the following match criteria + * + * .. code-block:: yaml + * + * transport_socket_match_criteria: + * useMTLS: true + * + * Will match the following :ref:`cluster socket match ` + * + * .. code-block:: yaml + * + * transport_socket_matches: + * - name: "useMTLS" + * match: + * useMTLS: true + * transport_socket: + * name: envoy.transport_sockets.tls + * config: { ... } # tls socket configuration + * + * If this field is set, then for health checks it will supersede an entry of *envoy.transport_socket* in the + * :ref:`LbEndpoint.Metadata `. + * This allows using different transport socket capabilities for health checking versus proxying to the + * endpoint. + * + * If the key/values pairs specified do not match any + * :ref:`transport socket matches `, + * the cluster's :ref:`transport socket ` + * will be used for health check socket configuration. + */ + 'transport_socket_match_criteria'?: (_google_protobuf_Struct__Output); + /** + * The "no traffic healthy interval" is a special health check interval that + * is used for hosts that are currently passing active health checking + * (including new hosts) when the cluster has received no traffic. + * + * This is useful for when we want to send frequent health checks with + * `no_traffic_interval` but then revert to lower frequency `no_traffic_healthy_interval` once + * a host in the cluster is marked as healthy. + * + * Once a cluster has been used for traffic routing, Envoy will shift back to using the + * standard health check interval that is defined. + * + * If no_traffic_healthy_interval is not set, it will default to the + * no traffic interval and send that interval regardless of health state. + */ + 'no_traffic_healthy_interval'?: (_google_protobuf_Duration__Output); 'health_checker': "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthStatus.ts similarity index 91% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthStatus.ts index e1d572fa4..6ecbca272 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HealthStatus.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthStatus.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/health_check.proto +// Original file: deps/envoy-api/envoy/config/core/v3/health_check.proto /** * Endpoint health status. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts similarity index 57% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts index b9bb0ce54..982f58b0e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http1ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts @@ -1,8 +1,8 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat { +export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat { /** * Formats the header by proper casing words: the first character and any character following * a special character will be capitalized if it's an alpha character. For example, @@ -10,11 +10,11 @@ export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat { * Note that while this results in most headers following conventional casing, certain headers * are not covered. For example, the "TE" header will be formatted as "Te". */ - 'proper_case_words'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords); + 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords); 'header_format'?: "proper_case_words"; } -export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output { +export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Output { /** * Formats the header by proper casing words: the first character and any character following * a special character will be capitalized if it's an alpha character. For example, @@ -22,18 +22,18 @@ export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output * Note that while this results in most headers following conventional casing, certain headers * are not covered. For example, the "TE" header will be formatted as "Te". */ - 'proper_case_words'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output); + 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output); 'header_format': "proper_case_words"; } -export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords { +export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords { } -export interface _envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output { +export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output { } /** - * [#next-free-field: 6] + * [#next-free-field: 8] */ export interface Http1ProtocolOptions { /** @@ -60,7 +60,7 @@ export interface Http1ProtocolOptions { * Describes how the keys for response headers should be formatted. By default, all header keys * are lower cased. */ - 'header_key_format'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat); + 'header_key_format'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat); /** * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. * @@ -73,10 +73,30 @@ export interface Http1ProtocolOptions { * - The content length header is not present. */ 'enable_trailers'?: (boolean); + /** + * Allows Envoy to process requests/responses with both `Content-Length` and `Transfer-Encoding` + * headers set. By default such messages are rejected, but if option is enabled - Envoy will + * remove Content-Length header and process message. + * See `RFC7230, sec. 3.3.3 ` for details. + * + * .. attention:: + * Enabling this option might lead to request smuggling vulnerability, especially if traffic + * is proxied via multiple layers of proxies. + */ + 'allow_chunked_length'?: (boolean); + /** + * Allows invalid HTTP messaging. When this option is false, then Envoy will terminate + * HTTP/1.1 connections upon receiving an invalid HTTP message. However, + * when this option is true, then Envoy will leave the HTTP/1.1 connection + * open where possible. + * If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging + * `. + */ + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue); } /** - * [#next-free-field: 6] + * [#next-free-field: 8] */ export interface Http1ProtocolOptions__Output { /** @@ -103,7 +123,7 @@ export interface Http1ProtocolOptions__Output { * Describes how the keys for response headers should be formatted. By default, all header keys * are lower cased. */ - 'header_key_format'?: (_envoy_api_v2_core_Http1ProtocolOptions_HeaderKeyFormat__Output); + 'header_key_format'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Output); /** * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. * @@ -116,4 +136,24 @@ export interface Http1ProtocolOptions__Output { * - The content length header is not present. */ 'enable_trailers': (boolean); + /** + * Allows Envoy to process requests/responses with both `Content-Length` and `Transfer-Encoding` + * headers set. By default such messages are rejected, but if option is enabled - Envoy will + * remove Content-Length header and process message. + * See `RFC7230, sec. 3.3.3 ` for details. + * + * .. attention:: + * Enabling this option might lead to request smuggling vulnerability, especially if traffic + * is proxied via multiple layers of proxies. + */ + 'allow_chunked_length': (boolean); + /** + * Allows invalid HTTP messaging. When this option is false, then Envoy will terminate + * HTTP/1.1 connections upon receiving an invalid HTTP message. However, + * when this option is true, then Envoy will leave the HTTP/1.1 connection + * open where possible. + * If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging + * `. + */ + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts similarity index 65% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts index 893f61a15..e379d44be 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Http2ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts @@ -1,12 +1,14 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { KeepaliveSettings as _envoy_config_core_v3_KeepaliveSettings, KeepaliveSettings__Output as _envoy_config_core_v3_KeepaliveSettings__Output } from '../../../../envoy/config/core/v3/KeepaliveSettings'; /** * Defines a parameter to be sent in the SETTINGS frame. * See `RFC7540, sec. 6.5.1 `_ for details. */ -export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter { +export interface _envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter { /** * The 16 bit parameter identifier. */ @@ -21,7 +23,7 @@ export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter { * Defines a parameter to be sent in the SETTINGS frame. * See `RFC7540, sec. 6.5.1 `_ for details. */ -export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Output { +export interface _envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter__Output { /** * The 16 bit parameter identifier. */ @@ -33,7 +35,7 @@ export interface _envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Outp } /** - * [#next-free-field: 14] + * [#next-free-field: 16] */ export interface Http2ProtocolOptions { /** @@ -81,7 +83,7 @@ export interface Http2ProtocolOptions { * Still under implementation. DO NOT USE. * * Allows metadata. See [metadata - * docs](https://github.com/envoyproxy/envoy/blob/master/source/docs/h2_metadata.md) for more + * docs](https://github.com/envoyproxy/envoy/blob/main/source/docs/h2_metadata.md) for more * information. */ 'allow_metadata'?: (boolean); @@ -90,7 +92,8 @@ export interface Http2ProtocolOptions { * be written into the socket). Exceeding this limit triggers flood mitigation and connection is * terminated. The ``http2.outbound_flood`` stat tracks the number of terminated connections due * to flood mitigation. The default limit is 10000. - * [#comment:TODO: implement same limits for upstream outbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_outbound_frames'?: (_google_protobuf_UInt32Value); /** @@ -99,7 +102,8 @@ export interface Http2ProtocolOptions { * this limit triggers flood mitigation and connection is terminated. The * ``http2.outbound_control_flood`` stat tracks the number of terminated connections due to flood * mitigation. The default limit is 1000. - * [#comment:TODO: implement same limits for upstream outbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value); /** @@ -109,7 +113,8 @@ export interface Http2ProtocolOptions { * stat tracks the number of connections terminated due to flood mitigation. * Setting this to 0 will terminate connection upon receiving first frame with an empty payload * and no end stream flag. The default limit is 1. - * [#comment:TODO: implement same limits for upstream inbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value); /** @@ -117,11 +122,15 @@ export interface Http2ProtocolOptions { * of PRIORITY frames received over the lifetime of connection exceeds the value calculated * using this formula:: * - * max_inbound_priority_frames_per_stream * (1 + inbound_streams) + * max_inbound_priority_frames_per_stream * (1 + opened_streams) * - * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + * the connection is terminated. For downstream connections the `opened_streams` is incremented when + * Envoy receives complete response headers from the upstream server. For upstream connection the + * `opened_streams` is incremented when Envoy send the HEADERS frame for a new stream. The + * ``http2.inbound_priority_frames_flood`` stat tracks * the number of connections terminated due to flood mitigation. The default limit is 100. - * [#comment:TODO: implement same limits for upstream inbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value); /** @@ -129,14 +138,18 @@ export interface Http2ProtocolOptions { * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated * using this formula:: * - * 1 + 2 * (inbound_streams + + * 5 + 2 * (opened_streams + * max_inbound_window_update_frames_per_data_frame_sent * outbound_data_frames) * - * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks - * the number of connections terminated due to flood mitigation. The default limit is 10. + * the connection is terminated. For downstream connections the `opened_streams` is incremented when + * Envoy receives complete response headers from the upstream server. For upstream connections the + * `opened_streams` is incremented when Envoy sends the HEADERS frame for a new stream. The + * ``http2.inbound_priority_frames_flood`` stat tracks the number of connections terminated due to + * flood mitigation. The default max_inbound_window_update_frames_per_data_frame_sent value is 10. * Setting this to 1 should be enough to support HTTP/2 implementations with basic flow control, * but more complex implementations that try to estimate available bandwidth require at least 2. - * [#comment:TODO: implement same limits for upstream inbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value); /** @@ -144,6 +157,13 @@ export interface Http2ProtocolOptions { * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, * when this option is enabled, only the offending stream is terminated. * + * This is overridden by HCM :ref:`stream_error_on_invalid_http_messaging + * ` + * iff present. + * + * This is deprecated in favor of :ref:`override_stream_error_on_invalid_http_message + * ` + * * See `RFC7540, sec. 8.1 `_ for details. */ 'stream_error_on_invalid_http_messaging'?: (boolean); @@ -175,11 +195,27 @@ export interface Http2ProtocolOptions { * `_ for * standardized identifiers. */ - 'custom_settings_parameters'?: (_envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter)[]; + 'custom_settings_parameters'?: (_envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter)[]; + /** + * Allows invalid HTTP messaging and headers. When this option is disabled (default), then + * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, + * when this option is enabled, only the offending stream is terminated. + * + * This overrides any HCM :ref:`stream_error_on_invalid_http_messaging + * ` + * + * See `RFC7540, sec. 8.1 `_ for details. + */ + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue); + /** + * Send HTTP/2 PING frames to verify that the connection is still healthy. If the remote peer + * does not respond within the configured timeout, the connection will be aborted. + */ + 'connection_keepalive'?: (_envoy_config_core_v3_KeepaliveSettings); } /** - * [#next-free-field: 14] + * [#next-free-field: 16] */ export interface Http2ProtocolOptions__Output { /** @@ -227,7 +263,7 @@ export interface Http2ProtocolOptions__Output { * Still under implementation. DO NOT USE. * * Allows metadata. See [metadata - * docs](https://github.com/envoyproxy/envoy/blob/master/source/docs/h2_metadata.md) for more + * docs](https://github.com/envoyproxy/envoy/blob/main/source/docs/h2_metadata.md) for more * information. */ 'allow_metadata': (boolean); @@ -236,7 +272,8 @@ export interface Http2ProtocolOptions__Output { * be written into the socket). Exceeding this limit triggers flood mitigation and connection is * terminated. The ``http2.outbound_flood`` stat tracks the number of terminated connections due * to flood mitigation. The default limit is 10000. - * [#comment:TODO: implement same limits for upstream outbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_outbound_frames'?: (_google_protobuf_UInt32Value__Output); /** @@ -245,7 +282,8 @@ export interface Http2ProtocolOptions__Output { * this limit triggers flood mitigation and connection is terminated. The * ``http2.outbound_control_flood`` stat tracks the number of terminated connections due to flood * mitigation. The default limit is 1000. - * [#comment:TODO: implement same limits for upstream outbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value__Output); /** @@ -255,7 +293,8 @@ export interface Http2ProtocolOptions__Output { * stat tracks the number of connections terminated due to flood mitigation. * Setting this to 0 will terminate connection upon receiving first frame with an empty payload * and no end stream flag. The default limit is 1. - * [#comment:TODO: implement same limits for upstream inbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value__Output); /** @@ -263,11 +302,15 @@ export interface Http2ProtocolOptions__Output { * of PRIORITY frames received over the lifetime of connection exceeds the value calculated * using this formula:: * - * max_inbound_priority_frames_per_stream * (1 + inbound_streams) + * max_inbound_priority_frames_per_stream * (1 + opened_streams) * - * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks + * the connection is terminated. For downstream connections the `opened_streams` is incremented when + * Envoy receives complete response headers from the upstream server. For upstream connection the + * `opened_streams` is incremented when Envoy send the HEADERS frame for a new stream. The + * ``http2.inbound_priority_frames_flood`` stat tracks * the number of connections terminated due to flood mitigation. The default limit is 100. - * [#comment:TODO: implement same limits for upstream inbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value__Output); /** @@ -275,14 +318,18 @@ export interface Http2ProtocolOptions__Output { * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated * using this formula:: * - * 1 + 2 * (inbound_streams + + * 5 + 2 * (opened_streams + * max_inbound_window_update_frames_per_data_frame_sent * outbound_data_frames) * - * the connection is terminated. The ``http2.inbound_priority_frames_flood`` stat tracks - * the number of connections terminated due to flood mitigation. The default limit is 10. + * the connection is terminated. For downstream connections the `opened_streams` is incremented when + * Envoy receives complete response headers from the upstream server. For upstream connections the + * `opened_streams` is incremented when Envoy sends the HEADERS frame for a new stream. The + * ``http2.inbound_priority_frames_flood`` stat tracks the number of connections terminated due to + * flood mitigation. The default max_inbound_window_update_frames_per_data_frame_sent value is 10. * Setting this to 1 should be enough to support HTTP/2 implementations with basic flow control, * but more complex implementations that try to estimate available bandwidth require at least 2. - * [#comment:TODO: implement same limits for upstream inbound frames as well.] + * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the + * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value__Output); /** @@ -290,6 +337,13 @@ export interface Http2ProtocolOptions__Output { * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, * when this option is enabled, only the offending stream is terminated. * + * This is overridden by HCM :ref:`stream_error_on_invalid_http_messaging + * ` + * iff present. + * + * This is deprecated in favor of :ref:`override_stream_error_on_invalid_http_message + * ` + * * See `RFC7540, sec. 8.1 `_ for details. */ 'stream_error_on_invalid_http_messaging': (boolean); @@ -321,5 +375,21 @@ export interface Http2ProtocolOptions__Output { * `_ for * standardized identifiers. */ - 'custom_settings_parameters': (_envoy_api_v2_core_Http2ProtocolOptions_SettingsParameter__Output)[]; + 'custom_settings_parameters': (_envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter__Output)[]; + /** + * Allows invalid HTTP messaging and headers. When this option is disabled (default), then + * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, + * when this option is enabled, only the offending stream is terminated. + * + * This overrides any HCM :ref:`stream_error_on_invalid_http_messaging + * ` + * + * See `RFC7540, sec. 8.1 `_ for details. + */ + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue__Output); + /** + * Send HTTP/2 PING frames to verify that the connection is still healthy. If the remote peer + * does not respond within the configured timeout, the connection will be aborted. + */ + 'connection_keepalive'?: (_envoy_config_core_v3_KeepaliveSettings__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts new file mode 100644 index 000000000..320285d87 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts @@ -0,0 +1,22 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto + + +/** + * [#not-implemented-hide:] + * + * A message which allows using HTTP/3 as an upstream protocol. + * + * Eventually this will include configuration for tuning HTTP/3. + */ +export interface Http3ProtocolOptions { +} + +/** + * [#not-implemented-hide:] + * + * A message which allows using HTTP/3 as an upstream protocol. + * + * Eventually this will include configuration for tuning HTTP/3. + */ +export interface Http3ProtocolOptions__Output { +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts similarity index 75% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts index 219fdb0c7..4a5efeebd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts @@ -1,9 +1,9 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto /** * Action to take when Envoy receives client request with header names containing underscore @@ -12,7 +12,7 @@ import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output a * as a security measure due to systems that treat '_' and '-' as interchangeable. Envoy by default allows client request headers with underscore * characters. */ -export enum _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction { +export enum _envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction { /** * Allow headers with underscores. This is the default behavior. */ @@ -41,13 +41,17 @@ export interface HttpProtocolOptions { * idle timeout is reached the connection will be closed. If the connection is an HTTP/2 * downstream connection a drain sequence will occur prior to closing the connection, see * :ref:`drain_timeout - * `. + * `. * Note that request based timeouts mean that HTTP/2 PINGs will not keep the connection alive. * If not specified, this defaults to 1 hour. To disable idle timeouts explicitly set this to 0. * * .. warning:: * Disabling this timeout has a highly likelihood of yielding connection leaks due to lost TCP * FIN packets, etc. + * + * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" + * is configured, this timeout is scaled for downstream connections according to the value for + * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. */ 'idle_timeout'?: (_google_protobuf_Duration); /** @@ -61,7 +65,7 @@ export interface HttpProtocolOptions { * was established. If not set, there is no max duration. When max_connection_duration is reached * the connection will be closed. Drain sequence will occur prior to closing the connection if * if's applicable. See :ref:`drain_timeout - * `. + * `. * Note: not implemented for upstream connections. */ 'max_connection_duration'?: (_google_protobuf_Duration); @@ -75,7 +79,7 @@ export interface HttpProtocolOptions { * If this setting is not specified, the value defaults to ALLOW. * Note: upstream responses are not affected by this setting. */ - 'headers_with_underscores_action'?: (_envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction | keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); + 'headers_with_underscores_action'?: (_envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction | keyof typeof _envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction); } /** @@ -88,13 +92,17 @@ export interface HttpProtocolOptions__Output { * idle timeout is reached the connection will be closed. If the connection is an HTTP/2 * downstream connection a drain sequence will occur prior to closing the connection, see * :ref:`drain_timeout - * `. + * `. * Note that request based timeouts mean that HTTP/2 PINGs will not keep the connection alive. * If not specified, this defaults to 1 hour. To disable idle timeouts explicitly set this to 0. * * .. warning:: * Disabling this timeout has a highly likelihood of yielding connection leaks due to lost TCP * FIN packets, etc. + * + * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" + * is configured, this timeout is scaled for downstream connections according to the value for + * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. */ 'idle_timeout'?: (_google_protobuf_Duration__Output); /** @@ -108,7 +116,7 @@ export interface HttpProtocolOptions__Output { * was established. If not set, there is no max duration. When max_connection_duration is reached * the connection will be closed. Drain sequence will occur prior to closing the connection if * if's applicable. See :ref:`drain_timeout - * `. + * `. * Note: not implemented for upstream connections. */ 'max_connection_duration'?: (_google_protobuf_Duration__Output); @@ -122,5 +130,5 @@ export interface HttpProtocolOptions__Output { * If this setting is not specified, the value defaults to ALLOW. * Note: upstream responses are not affected by this setting. */ - 'headers_with_underscores_action': (keyof typeof _envoy_api_v2_core_HttpProtocolOptions_HeadersWithUnderscoresAction); + 'headers_with_underscores_action': (keyof typeof _envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts new file mode 100644 index 000000000..5da6ed4c0 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts @@ -0,0 +1,79 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/http_uri.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * Envoy external URI descriptor + */ +export interface HttpUri { + /** + * The HTTP server URI. It should be a full FQDN with protocol, host and path. + * + * Example: + * + * .. code-block:: yaml + * + * uri: https://www.googleapis.com/oauth2/v1/certs + */ + 'uri'?: (string); + /** + * A cluster is created in the Envoy "cluster_manager" config + * section. This field specifies the cluster name. + * + * Example: + * + * .. code-block:: yaml + * + * cluster: jwks_cluster + */ + 'cluster'?: (string); + /** + * Sets the maximum duration in milliseconds that a response can take to arrive upon request. + */ + 'timeout'?: (_google_protobuf_Duration); + /** + * Specify how `uri` is to be fetched. Today, this requires an explicit + * cluster, but in the future we may support dynamic cluster creation or + * inline DNS resolution. See `issue + * `_. + */ + 'http_upstream_type'?: "cluster"; +} + +/** + * Envoy external URI descriptor + */ +export interface HttpUri__Output { + /** + * The HTTP server URI. It should be a full FQDN with protocol, host and path. + * + * Example: + * + * .. code-block:: yaml + * + * uri: https://www.googleapis.com/oauth2/v1/certs + */ + 'uri': (string); + /** + * A cluster is created in the Envoy "cluster_manager" config + * section. This field specifies the cluster name. + * + * Example: + * + * .. code-block:: yaml + * + * cluster: jwks_cluster + */ + 'cluster'?: (string); + /** + * Sets the maximum duration in milliseconds that a response can take to arrive upon request. + */ + 'timeout'?: (_google_protobuf_Duration__Output); + /** + * Specify how `uri` is to be fetched. Today, this requires an explicit + * cluster, but in the future we may support dynamic cluster creation or + * inline DNS resolution. See `issue + * `_. + */ + 'http_upstream_type': "cluster"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts new file mode 100644 index 000000000..cb2e14c58 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts @@ -0,0 +1,40 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../envoy/type/v3/Percent'; + +export interface KeepaliveSettings { + /** + * Send HTTP/2 PING frames at this period, in order to test that the connection is still alive. + */ + 'interval'?: (_google_protobuf_Duration); + /** + * How long to wait for a response to a keepalive PING. If a response is not received within this + * time period, the connection will be aborted. + */ + 'timeout'?: (_google_protobuf_Duration); + /** + * A random jitter amount as a percentage of interval that will be added to each interval. + * A value of zero means there will be no jitter. + * The default value is 15%. + */ + 'interval_jitter'?: (_envoy_type_v3_Percent); +} + +export interface KeepaliveSettings__Output { + /** + * Send HTTP/2 PING frames at this period, in order to test that the connection is still alive. + */ + 'interval'?: (_google_protobuf_Duration__Output); + /** + * How long to wait for a response to a keepalive PING. If a response is not received within this + * time period, the connection will be aborted. + */ + 'timeout'?: (_google_protobuf_Duration__Output); + /** + * A random jitter amount as a percentage of interval that will be added to each interval. + * A value of zero means there will be no jitter. + * The default value is 15%. + */ + 'interval_jitter'?: (_envoy_type_v3_Percent__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts new file mode 100644 index 000000000..2b4b42a75 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts @@ -0,0 +1,56 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ +export interface Locality { + /** + * Region this :ref:`zone ` belongs to. + */ + 'region'?: (string); + /** + * Defines the local service zone where Envoy is running. Though optional, it + * should be set if discovery service routing is used and the discovery + * service exposes :ref:`zone data `, + * either in this message or via :option:`--service-zone`. The meaning of zone + * is context dependent, e.g. `Availability Zone (AZ) + * `_ + * on AWS, `Zone `_ on + * GCP, etc. + */ + 'zone'?: (string); + /** + * When used for locality of upstream hosts, this field further splits zone + * into smaller chunks of sub-zones so they can be load balanced + * independently. + */ + 'sub_zone'?: (string); +} + +/** + * Identifies location of where either Envoy runs or where upstream hosts run. + */ +export interface Locality__Output { + /** + * Region this :ref:`zone ` belongs to. + */ + 'region': (string); + /** + * Defines the local service zone where Envoy is running. Though optional, it + * should be set if discovery service routing is used and the discovery + * service exposes :ref:`zone data `, + * either in this message or via :option:`--service-zone`. The meaning of zone + * is context dependent, e.g. `Availability Zone (AZ) + * `_ + * on AWS, `Zone `_ on + * GCP, etc. + */ + 'zone': (string); + /** + * When used for locality of upstream hosts, this field further splits zone + * into smaller chunks of sub-zones so they can be load balanced + * independently. + */ + 'sub_zone': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts new file mode 100644 index 000000000..6d7181f18 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts @@ -0,0 +1,67 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; + +/** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ +export interface Metadata { + /** + * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* + * namespace is reserved for Envoy's built-in filters. + */ + 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct}); +} + +/** + * Metadata provides additional inputs to filters based on matched listeners, + * filter chains, routes and endpoints. It is structured as a map, usually from + * filter name (in reverse DNS format) to metadata specific to the filter. Metadata + * key-values for a filter are merged as connection and request handling occurs, + * with later values for the same key overriding earlier values. + * + * An example use of metadata is providing additional values to + * http_connection_manager in the envoy.http_connection_manager.access_log + * namespace. + * + * Another example use of metadata is to per service config info in cluster metadata, which may get + * consumed by multiple filters. + * + * For load balancing, Metadata provides a means to subset cluster endpoints. + * Endpoints have a Metadata object associated and routes contain a Metadata + * object to match against. There are some well defined metadata used today for + * this purpose: + * + * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an + * endpoint and is also used during header processing + * (x-envoy-upstream-canary) and for stats purposes. + * [#next-major-version: move to type/metadata/v2] + */ +export interface Metadata__Output { + /** + * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* + * namespace is reserved for Envoy's built-in filters. + */ + 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct__Output}); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts new file mode 100644 index 000000000..717263976 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts @@ -0,0 +1,159 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Locality as _envoy_config_core_v3_Locality, Locality__Output as _envoy_config_core_v3_Locality__Output } from '../../../../envoy/config/core/v3/Locality'; +import type { BuildVersion as _envoy_config_core_v3_BuildVersion, BuildVersion__Output as _envoy_config_core_v3_BuildVersion__Output } from '../../../../envoy/config/core/v3/BuildVersion'; +import type { Extension as _envoy_config_core_v3_Extension, Extension__Output as _envoy_config_core_v3_Extension__Output } from '../../../../envoy/config/core/v3/Extension'; +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; + +/** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ +export interface Node { + /** + * An opaque node identifier for the Envoy node. This also provides the local + * service node name. It should be set if any of the following features are + * used: :ref:`statsd `, :ref:`CDS + * `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-node`. + */ + 'id'?: (string); + /** + * Defines the local service cluster name where Envoy is running. Though + * optional, it should be set if any of the following features are used: + * :ref:`statsd `, :ref:`health check cluster + * verification + * `, + * :ref:`runtime override directory `, + * :ref:`user agent addition + * `, + * :ref:`HTTP global rate limiting `, + * :ref:`CDS `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-cluster`. + */ + 'cluster'?: (string); + /** + * Opaque metadata extending the node identifier. Envoy will pass this + * directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct); + /** + * Locality specifying where the Envoy instance is running. + */ + 'locality'?: (_envoy_config_core_v3_Locality); + /** + * Free-form string that identifies the entity requesting config. + * E.g. "envoy" or "grpc" + */ + 'user_agent_name'?: (string); + /** + * Free-form string that identifies the version of the entity requesting config. + * E.g. "1.12.2" or "abcd1234", or "SpecialEnvoyBuild" + */ + 'user_agent_version'?: (string); + /** + * Structured version of the entity requesting config. + */ + 'user_agent_build_version'?: (_envoy_config_core_v3_BuildVersion); + /** + * List of extensions and their versions supported by the node. + */ + 'extensions'?: (_envoy_config_core_v3_Extension)[]; + /** + * Client feature support list. These are well known features described + * in the Envoy API repository for a given major version of an API. Client features + * use reverse DNS naming scheme, for example `com.acme.feature`. + * See :ref:`the list of features ` that xDS client may + * support. + */ + 'client_features'?: (string)[]; + /** + * Known listening ports on the node as a generic hint to the management server + * for filtering :ref:`listeners ` to be returned. For example, + * if there is a listener bound to port 80, the list can optionally contain the + * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. + */ + 'listening_addresses'?: (_envoy_config_core_v3_Address)[]; + 'user_agent_version_type'?: "user_agent_version"|"user_agent_build_version"; +} + +/** + * Identifies a specific Envoy instance. The node identifier is presented to the + * management server, which may use this identifier to distinguish per Envoy + * configuration for serving. + * [#next-free-field: 12] + */ +export interface Node__Output { + /** + * An opaque node identifier for the Envoy node. This also provides the local + * service node name. It should be set if any of the following features are + * used: :ref:`statsd `, :ref:`CDS + * `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-node`. + */ + 'id': (string); + /** + * Defines the local service cluster name where Envoy is running. Though + * optional, it should be set if any of the following features are used: + * :ref:`statsd `, :ref:`health check cluster + * verification + * `, + * :ref:`runtime override directory `, + * :ref:`user agent addition + * `, + * :ref:`HTTP global rate limiting `, + * :ref:`CDS `, and :ref:`HTTP tracing + * `, either in this message or via + * :option:`--service-cluster`. + */ + 'cluster': (string); + /** + * Opaque metadata extending the node identifier. Envoy will pass this + * directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct__Output); + /** + * Locality specifying where the Envoy instance is running. + */ + 'locality'?: (_envoy_config_core_v3_Locality__Output); + /** + * Free-form string that identifies the entity requesting config. + * E.g. "envoy" or "grpc" + */ + 'user_agent_name': (string); + /** + * Free-form string that identifies the version of the entity requesting config. + * E.g. "1.12.2" or "abcd1234", or "SpecialEnvoyBuild" + */ + 'user_agent_version'?: (string); + /** + * Structured version of the entity requesting config. + */ + 'user_agent_build_version'?: (_envoy_config_core_v3_BuildVersion__Output); + /** + * List of extensions and their versions supported by the node. + */ + 'extensions': (_envoy_config_core_v3_Extension__Output)[]; + /** + * Client feature support list. These are well known features described + * in the Envoy API repository for a given major version of an API. Client features + * use reverse DNS naming scheme, for example `com.acme.feature`. + * See :ref:`the list of features ` that xDS client may + * support. + */ + 'client_features': (string)[]; + /** + * Known listening ports on the node as a generic hint to the management server + * for filtering :ref:`listeners ` to be returned. For example, + * if there is a listener bound to port 80, the list can optionally contain the + * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. + */ + 'listening_addresses': (_envoy_config_core_v3_Address__Output)[]; + 'user_agent_version_type': "user_agent_version"|"user_agent_build_version"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Pipe.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Pipe.ts new file mode 100644 index 000000000..3d8fdb1c8 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Pipe.ts @@ -0,0 +1,30 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + + +export interface Pipe { + /** + * Unix Domain Socket path. On Linux, paths starting with '@' will use the + * abstract namespace. The starting '@' is replaced by a null byte by Envoy. + * Paths starting with '@' will result in an error in environments other than + * Linux. + */ + 'path'?: (string); + /** + * The mode for the Pipe. Not applicable for abstract sockets. + */ + 'mode'?: (number); +} + +export interface Pipe__Output { + /** + * Unix Domain Socket path. On Linux, paths starting with '@' will use the + * abstract namespace. The starting '@' is replaced by a null byte by Envoy. + * Paths starting with '@' will result in an error in environments other than + * Linux. + */ + 'path': (string); + /** + * The mode for the Pipe. Not applicable for abstract sockets. + */ + 'mode': (number); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ProxyProtocolConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ProxyProtocolConfig.ts new file mode 100644 index 000000000..a28de2dbe --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ProxyProtocolConfig.ts @@ -0,0 +1,29 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/proxy_protocol.proto + + +// Original file: deps/envoy-api/envoy/config/core/v3/proxy_protocol.proto + +export enum _envoy_config_core_v3_ProxyProtocolConfig_Version { + /** + * PROXY protocol version 1. Human readable format. + */ + V1 = 0, + /** + * PROXY protocol version 2. Binary format. + */ + V2 = 1, +} + +export interface ProxyProtocolConfig { + /** + * The PROXY protocol version to use. See https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt for details + */ + 'version'?: (_envoy_config_core_v3_ProxyProtocolConfig_Version | keyof typeof _envoy_config_core_v3_ProxyProtocolConfig_Version); +} + +export interface ProxyProtocolConfig__Output { + /** + * The PROXY protocol version to use. See https://www.haproxy.org/download/2.1/doc/proxy-protocol.txt for details + */ + 'version': (keyof typeof _envoy_config_core_v3_ProxyProtocolConfig_Version); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts similarity index 94% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts index 222c86eb4..8f4093fd4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RateLimitSettings.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/config_source.proto +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import type { DoubleValue as _google_protobuf_DoubleValue, DoubleValue__Output as _google_protobuf_DoubleValue__Output } from '../../../../google/protobuf/DoubleValue'; diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts new file mode 100644 index 000000000..99634015f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts @@ -0,0 +1,40 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { HttpUri as _envoy_config_core_v3_HttpUri, HttpUri__Output as _envoy_config_core_v3_HttpUri__Output } from '../../../../envoy/config/core/v3/HttpUri'; +import type { RetryPolicy as _envoy_config_core_v3_RetryPolicy, RetryPolicy__Output as _envoy_config_core_v3_RetryPolicy__Output } from '../../../../envoy/config/core/v3/RetryPolicy'; + +/** + * The message specifies how to fetch data from remote and how to verify it. + */ +export interface RemoteDataSource { + /** + * The HTTP URI to fetch the remote data. + */ + 'http_uri'?: (_envoy_config_core_v3_HttpUri); + /** + * SHA256 string for verifying data. + */ + 'sha256'?: (string); + /** + * Retry policy for fetching remote data. + */ + 'retry_policy'?: (_envoy_config_core_v3_RetryPolicy); +} + +/** + * The message specifies how to fetch data from remote and how to verify it. + */ +export interface RemoteDataSource__Output { + /** + * The HTTP URI to fetch the remote data. + */ + 'http_uri'?: (_envoy_config_core_v3_HttpUri__Output); + /** + * SHA256 string for verifying data. + */ + 'sha256': (string); + /** + * Retry policy for fetching remote data. + */ + 'retry_policy'?: (_envoy_config_core_v3_RetryPolicy__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RequestMethod.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RequestMethod.ts new file mode 100644 index 000000000..9be1aa6d1 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RequestMethod.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +/** + * HTTP request method. + */ +export enum RequestMethod { + METHOD_UNSPECIFIED = 0, + GET = 1, + HEAD = 2, + POST = 3, + PUT = 4, + DELETE = 5, + CONNECT = 6, + OPTIONS = 7, + TRACE = 8, + PATCH = 9, +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts new file mode 100644 index 000000000..6d0d9927b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts @@ -0,0 +1,38 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { BackoffStrategy as _envoy_config_core_v3_BackoffStrategy, BackoffStrategy__Output as _envoy_config_core_v3_BackoffStrategy__Output } from '../../../../envoy/config/core/v3/BackoffStrategy'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +/** + * The message specifies the retry policy of remote data source when fetching fails. + */ +export interface RetryPolicy { + /** + * Specifies parameters that control :ref:`retry backoff strategy `. + * This parameter is optional, in which case the default base interval is 1000 milliseconds. The + * default maximum interval is 10 times the base interval. + */ + 'retry_back_off'?: (_envoy_config_core_v3_BackoffStrategy); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. + */ + 'num_retries'?: (_google_protobuf_UInt32Value); +} + +/** + * The message specifies the retry policy of remote data source when fetching fails. + */ +export interface RetryPolicy__Output { + /** + * Specifies parameters that control :ref:`retry backoff strategy `. + * This parameter is optional, in which case the default base interval is 1000 milliseconds. The + * default maximum interval is 10 times the base interval. + */ + 'retry_back_off'?: (_envoy_config_core_v3_BackoffStrategy__Output); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. + */ + 'num_retries'?: (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RoutingPriority.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RoutingPriority.ts new file mode 100644 index 000000000..917d8a3df --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RoutingPriority.ts @@ -0,0 +1,15 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +/** + * Envoy supports :ref:`upstream priority routing + * ` both at the route and the virtual + * cluster level. The current priority implementation uses different connection + * pool and circuit breaking settings for each priority level. This means that + * even for HTTP/2 requests, two physical connections will be used to an + * upstream host. In the future Envoy will likely support true HTTP/2 priority + * over a single upstream connection. + */ +export enum RoutingPriority { + DEFAULT = 0, + HIGH = 1, +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeDouble.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeDouble.ts new file mode 100644 index 000000000..a0f849ab5 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeDouble.ts @@ -0,0 +1,30 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Runtime derived double with a default when not specified. + */ +export interface RuntimeDouble { + /** + * Default value if runtime value is not available. + */ + 'default_value'?: (number | string); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ + 'runtime_key'?: (string); +} + +/** + * Runtime derived double with a default when not specified. + */ +export interface RuntimeDouble__Output { + /** + * Default value if runtime value is not available. + */ + 'default_value': (number); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ + 'runtime_key': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts new file mode 100644 index 000000000..413a4f931 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; + +/** + * Runtime derived bool with a default when not specified. + */ +export interface RuntimeFeatureFlag { + /** + * Default value if runtime value is not available. + */ + 'default_value'?: (_google_protobuf_BoolValue); + /** + * Runtime key to get value for comparison. This value is used if defined. The boolean value must + * be represented via its + * `canonical JSON encoding `_. + */ + 'runtime_key'?: (string); +} + +/** + * Runtime derived bool with a default when not specified. + */ +export interface RuntimeFeatureFlag__Output { + /** + * Default value if runtime value is not available. + */ + 'default_value'?: (_google_protobuf_BoolValue__Output); + /** + * Runtime key to get value for comparison. This value is used if defined. The boolean value must + * be represented via its + * `canonical JSON encoding `_. + */ + 'runtime_key': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts new file mode 100644 index 000000000..5610f7bdd --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts @@ -0,0 +1,49 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../envoy/type/v3/FractionalPercent'; + +/** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ +export interface RuntimeFractionalPercent { + /** + * Default value if the runtime value's for the numerator/denominator keys are not available. + */ + 'default_value'?: (_envoy_type_v3_FractionalPercent); + /** + * Runtime key for a YAML representation of a FractionalPercent. + */ + 'runtime_key'?: (string); +} + +/** + * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not + * specified via a runtime key. + * + * .. note:: + * + * Parsing of the runtime key's data is implemented such that it may be represented as a + * :ref:`FractionalPercent ` proto represented as JSON/YAML + * and may also be represented as an integer with the assumption that the value is an integral + * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse + * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. + */ +export interface RuntimeFractionalPercent__Output { + /** + * Default value if the runtime value's for the numerator/denominator keys are not available. + */ + 'default_value'?: (_envoy_type_v3_FractionalPercent__Output); + /** + * Runtime key for a YAML representation of a FractionalPercent. + */ + 'runtime_key': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts new file mode 100644 index 000000000..b317b5aa2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts @@ -0,0 +1,31 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../envoy/type/v3/Percent'; + +/** + * Runtime derived percentage with a default when not specified. + */ +export interface RuntimePercent { + /** + * Default value if runtime value is not available. + */ + 'default_value'?: (_envoy_type_v3_Percent); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ + 'runtime_key'?: (string); +} + +/** + * Runtime derived percentage with a default when not specified. + */ +export interface RuntimePercent__Output { + /** + * Default value if runtime value is not available. + */ + 'default_value'?: (_envoy_type_v3_Percent__Output); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ + 'runtime_key': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeUInt32.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeUInt32.ts new file mode 100644 index 000000000..6cc9eead6 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeUInt32.ts @@ -0,0 +1,30 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Runtime derived uint32 with a default when not specified. + */ +export interface RuntimeUInt32 { + /** + * Default value if runtime value is not available. + */ + 'default_value'?: (number); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ + 'runtime_key'?: (string); +} + +/** + * Runtime derived uint32 with a default when not specified. + */ +export interface RuntimeUInt32__Output { + /** + * Default value if runtime value is not available. + */ + 'default_value': (number); + /** + * Runtime key to get value for comparison. This value is used if defined. + */ + 'runtime_key': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts new file mode 100644 index 000000000..e387adca2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts @@ -0,0 +1,31 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/config_source.proto + +import type { ApiVersion as _envoy_config_core_v3_ApiVersion } from '../../../../envoy/config/core/v3/ApiVersion'; + +/** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ +export interface SelfConfigSource { + /** + * API version for xDS transport protocol. This describes the xDS gRPC/REST + * endpoint and version of [Delta]DiscoveryRequest/Response used on the wire. + */ + 'transport_api_version'?: (_envoy_config_core_v3_ApiVersion | keyof typeof _envoy_config_core_v3_ApiVersion); +} + +/** + * [#not-implemented-hide:] + * Self-referencing config source options. This is currently empty, but when + * set in :ref:`ConfigSource ` can be used to + * specify that other data can be obtained from the same server. + */ +export interface SelfConfigSource__Output { + /** + * API version for xDS transport protocol. This describes the xDS gRPC/REST + * endpoint and version of [Delta]DiscoveryRequest/Response used on the wire. + */ + 'transport_api_version': (keyof typeof _envoy_config_core_v3_ApiVersion); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts new file mode 100644 index 000000000..e3f342d16 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts @@ -0,0 +1,97 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + + +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + +export enum _envoy_config_core_v3_SocketAddress_Protocol { + TCP = 0, + UDP = 1, +} + +/** + * [#next-free-field: 7] + */ +export interface SocketAddress { + 'protocol'?: (_envoy_config_core_v3_SocketAddress_Protocol | keyof typeof _envoy_config_core_v3_SocketAddress_Protocol); + /** + * The address for this socket. :ref:`Listeners ` will bind + * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` + * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: + * It is possible to distinguish a Listener address via the prefix/suffix matching + * in :ref:`FilterChainMatch `.] When used + * within an upstream :ref:`BindConfig `, the address + * controls the source address of outbound connections. For :ref:`clusters + * `, the cluster type determines whether the + * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS + * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized + * via :ref:`resolver_name `. + */ + 'address'?: (string); + 'port_value'?: (number); + /** + * This is only valid if :ref:`resolver_name + * ` is specified below and the + * named resolver is capable of named port resolution. + */ + 'named_port'?: (string); + /** + * The name of the custom resolver. This must have been registered with Envoy. If + * this is empty, a context dependent default applies. If the address is a concrete + * IP address, no resolution will occur. If address is a hostname this + * should be set for resolution other than DNS. Specifying a custom resolver with + * *STRICT_DNS* or *LOGICAL_DNS* will generate an error at runtime. + */ + 'resolver_name'?: (string); + /** + * When binding to an IPv6 address above, this enables `IPv4 compatibility + * `_. Binding to ``::`` will + * allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into + * IPv6 space as ``::FFFF:``. + */ + 'ipv4_compat'?: (boolean); + 'port_specifier'?: "port_value"|"named_port"; +} + +/** + * [#next-free-field: 7] + */ +export interface SocketAddress__Output { + 'protocol': (keyof typeof _envoy_config_core_v3_SocketAddress_Protocol); + /** + * The address for this socket. :ref:`Listeners ` will bind + * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` + * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: + * It is possible to distinguish a Listener address via the prefix/suffix matching + * in :ref:`FilterChainMatch `.] When used + * within an upstream :ref:`BindConfig `, the address + * controls the source address of outbound connections. For :ref:`clusters + * `, the cluster type determines whether the + * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS + * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized + * via :ref:`resolver_name `. + */ + 'address': (string); + 'port_value'?: (number); + /** + * This is only valid if :ref:`resolver_name + * ` is specified below and the + * named resolver is capable of named port resolution. + */ + 'named_port'?: (string); + /** + * The name of the custom resolver. This must have been registered with Envoy. If + * this is empty, a context dependent default applies. If the address is a concrete + * IP address, no resolution will occur. If address is a hostname this + * should be set for resolution other than DNS. Specifying a custom resolver with + * *STRICT_DNS* or *LOGICAL_DNS* will generate an error at runtime. + */ + 'resolver_name': (string); + /** + * When binding to an IPv6 address above, this enables `IPv4 compatibility + * `_. Binding to ``::`` will + * allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into + * IPv6 space as ``::FFFF:``. + */ + 'ipv4_compat': (boolean); + 'port_specifier': "port_value"|"named_port"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketOption.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketOption.ts new file mode 100644 index 000000000..56f13c339 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketOption.ts @@ -0,0 +1,90 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/socket_option.proto + +import type { Long } from '@grpc/proto-loader'; + +// Original file: deps/envoy-api/envoy/config/core/v3/socket_option.proto + +export enum _envoy_config_core_v3_SocketOption_SocketState { + /** + * Socket options are applied after socket creation but before binding the socket to a port + */ + STATE_PREBIND = 0, + /** + * Socket options are applied after binding the socket to a port but before calling listen() + */ + STATE_BOUND = 1, + /** + * Socket options are applied after calling listen() + */ + STATE_LISTENING = 2, +} + +/** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ +export interface SocketOption { + /** + * An optional name to give this socket option for debugging, etc. + * Uniqueness is not required and no special meaning is assumed. + */ + 'description'?: (string); + /** + * Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP + */ + 'level'?: (number | string | Long); + /** + * The numeric name as passed to setsockopt + */ + 'name'?: (number | string | Long); + /** + * Because many sockopts take an int value. + */ + 'int_value'?: (number | string | Long); + /** + * Otherwise it's a byte buffer. + */ + 'buf_value'?: (Buffer | Uint8Array | string); + /** + * The state in which the option will be applied. When used in BindConfig + * STATE_PREBIND is currently the only valid value. + */ + 'state'?: (_envoy_config_core_v3_SocketOption_SocketState | keyof typeof _envoy_config_core_v3_SocketOption_SocketState); + 'value'?: "int_value"|"buf_value"; +} + +/** + * Generic socket option message. This would be used to set socket options that + * might not exist in upstream kernels or precompiled Envoy binaries. + * [#next-free-field: 7] + */ +export interface SocketOption__Output { + /** + * An optional name to give this socket option for debugging, etc. + * Uniqueness is not required and no special meaning is assumed. + */ + 'description': (string); + /** + * Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP + */ + 'level': (string); + /** + * The numeric name as passed to setsockopt + */ + 'name': (string); + /** + * Because many sockopts take an int value. + */ + 'int_value'?: (string); + /** + * Otherwise it's a byte buffer. + */ + 'buf_value'?: (Buffer); + /** + * The state in which the option will be applied. When used in BindConfig + * STATE_PREBIND is currently the only valid value. + */ + 'state': (keyof typeof _envoy_config_core_v3_SocketOption_SocketState); + 'value': "int_value"|"buf_value"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts new file mode 100644 index 000000000..41bd5e539 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts @@ -0,0 +1,197 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/substitution_format_string.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../envoy/config/core/v3/DataSource'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * Configuration to use multiple :ref:`command operators ` + * to generate a new string in either plain text or JSON format. + * [#next-free-field: 7] + */ +export interface SubstitutionFormatString { + /** + * Specify a format with command operators to form a text string. + * Its details is described in :ref:`format string`. + * + * For example, setting ``text_format`` like below, + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * text_format: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n" + * + * generates plain text similar to: + * + * .. code-block:: text + * + * upstream connect error:503:path=/foo + * + * Deprecated in favor of :ref:`text_format_source `. To migrate text format strings, use the :ref:`inline_string ` field. + */ + 'text_format'?: (string); + /** + * Specify a format with command operators to form a JSON string. + * Its details is described in :ref:`format dictionary`. + * Values are rendered as strings, numbers, or boolean values as appropriate. + * Nested JSON objects may be produced by some command operators (e.g. FILTER_STATE or DYNAMIC_METADATA). + * See the documentation for a specific command operator for details. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * json_format: + * status: "%RESPONSE_CODE%" + * message: "%LOCAL_REPLY_BODY%" + * + * The following JSON object would be created: + * + * .. code-block:: json + * + * { + * "status": 500, + * "message": "My error message" + * } + */ + 'json_format'?: (_google_protobuf_Struct); + /** + * If set to true, when command operators are evaluated to null, + * + * * for ``text_format``, the output of the empty operator is changed from ``-`` to an + * empty string, so that empty values are omitted entirely. + * * for ``json_format`` the keys with null values are omitted in the output structure. + */ + 'omit_empty_values'?: (boolean); + /** + * Specify a *content_type* field. + * If this field is not set then ``text/plain`` is used for *text_format* and + * ``application/json`` is used for *json_format*. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * content_type: "text/html; charset=UTF-8" + */ + 'content_type'?: (string); + /** + * Specify a format with command operators to form a text string. + * Its details is described in :ref:`format string`. + * + * For example, setting ``text_format`` like below, + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * text_format_source: + * inline_string: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n" + * + * generates plain text similar to: + * + * .. code-block:: text + * + * upstream connect error:503:path=/foo + */ + 'text_format_source'?: (_envoy_config_core_v3_DataSource); + /** + * Specifies a collection of Formatter plugins that can be called from the access log configuration. + * See the formatters extensions documentation for details. + */ + 'formatters'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; + 'format'?: "text_format"|"json_format"|"text_format_source"; +} + +/** + * Configuration to use multiple :ref:`command operators ` + * to generate a new string in either plain text or JSON format. + * [#next-free-field: 7] + */ +export interface SubstitutionFormatString__Output { + /** + * Specify a format with command operators to form a text string. + * Its details is described in :ref:`format string`. + * + * For example, setting ``text_format`` like below, + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * text_format: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n" + * + * generates plain text similar to: + * + * .. code-block:: text + * + * upstream connect error:503:path=/foo + * + * Deprecated in favor of :ref:`text_format_source `. To migrate text format strings, use the :ref:`inline_string ` field. + */ + 'text_format'?: (string); + /** + * Specify a format with command operators to form a JSON string. + * Its details is described in :ref:`format dictionary`. + * Values are rendered as strings, numbers, or boolean values as appropriate. + * Nested JSON objects may be produced by some command operators (e.g. FILTER_STATE or DYNAMIC_METADATA). + * See the documentation for a specific command operator for details. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * json_format: + * status: "%RESPONSE_CODE%" + * message: "%LOCAL_REPLY_BODY%" + * + * The following JSON object would be created: + * + * .. code-block:: json + * + * { + * "status": 500, + * "message": "My error message" + * } + */ + 'json_format'?: (_google_protobuf_Struct__Output); + /** + * If set to true, when command operators are evaluated to null, + * + * * for ``text_format``, the output of the empty operator is changed from ``-`` to an + * empty string, so that empty values are omitted entirely. + * * for ``json_format`` the keys with null values are omitted in the output structure. + */ + 'omit_empty_values': (boolean); + /** + * Specify a *content_type* field. + * If this field is not set then ``text/plain`` is used for *text_format* and + * ``application/json`` is used for *json_format*. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * content_type: "text/html; charset=UTF-8" + */ + 'content_type': (string); + /** + * Specify a format with command operators to form a text string. + * Its details is described in :ref:`format string`. + * + * For example, setting ``text_format`` like below, + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * text_format_source: + * inline_string: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n" + * + * generates plain text similar to: + * + * .. code-block:: text + * + * upstream connect error:503:path=/foo + */ + 'text_format_source'?: (_envoy_config_core_v3_DataSource__Output); + /** + * Specifies a collection of Formatter plugins that can be called from the access log configuration. + * See the formatters extensions documentation for details. + */ + 'formatters': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; + 'format': "text_format"|"json_format"|"text_format_source"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts new file mode 100644 index 000000000..a1bac359e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/address.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +export interface TcpKeepalive { + /** + * Maximum number of keepalive probes to send without response before deciding + * the connection is dead. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 9.) + */ + 'keepalive_probes'?: (_google_protobuf_UInt32Value); + /** + * The number of seconds a connection needs to be idle before keep-alive probes + * start being sent. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 7200s (i.e., 2 hours.) + */ + 'keepalive_time'?: (_google_protobuf_UInt32Value); + /** + * The number of seconds between keep-alive probes. Default is to use the OS + * level configuration (unless overridden, Linux defaults to 75s.) + */ + 'keepalive_interval'?: (_google_protobuf_UInt32Value); +} + +export interface TcpKeepalive__Output { + /** + * Maximum number of keepalive probes to send without response before deciding + * the connection is dead. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 9.) + */ + 'keepalive_probes'?: (_google_protobuf_UInt32Value__Output); + /** + * The number of seconds a connection needs to be idle before keep-alive probes + * start being sent. Default is to use the OS level configuration (unless + * overridden, Linux defaults to 7200s (i.e., 2 hours.) + */ + 'keepalive_time'?: (_google_protobuf_UInt32Value__Output); + /** + * The number of seconds between keep-alive probes. Default is to use the OS + * level configuration (unless overridden, Linux defaults to 75s.) + */ + 'keepalive_interval'?: (_google_protobuf_UInt32Value__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpProtocolOptions.ts similarity index 70% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpProtocolOptions.ts index bb7afc1d1..28239f63e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpProtocolOptions.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TrafficDirection.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TrafficDirection.ts new file mode 100644 index 000000000..b68323b09 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TrafficDirection.ts @@ -0,0 +1,19 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +/** + * Identifies the direction of the traffic relative to the local Envoy. + */ +export enum TrafficDirection { + /** + * Default option is unspecified. + */ + UNSPECIFIED = 0, + /** + * The transport is used for incoming traffic. + */ + INBOUND = 1, + /** + * The transport is used for outgoing traffic. + */ + OUTBOUND = 2, +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts new file mode 100644 index 000000000..b14402783 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ +export interface TransportSocket { + /** + * The name of the transport socket to instantiate. The name must match a supported transport + * socket implementation. + */ + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any); + /** + * Implementation specific configuration which depends on the implementation being instantiated. + * See the supported transport socket implementations for further documentation. + */ + 'config_type'?: "typed_config"; +} + +/** + * Configuration for transport socket in :ref:`listeners ` and + * :ref:`clusters `. If the configuration is + * empty, a default transport socket implementation and configuration will be + * chosen based on the platform and existence of tls_context. + */ +export interface TransportSocket__Output { + /** + * The name of the transport socket to instantiate. The name must match a supported transport + * socket implementation. + */ + 'name': (string); + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Implementation specific configuration which depends on the implementation being instantiated. + * See the supported transport socket implementations for further documentation. + */ + 'config_type': "typed_config"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts new file mode 100644 index 000000000..788826a1b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/extension.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * Message type for extension configuration. + * [#next-major-version: revisit all existing typed_config that doesn't use this wrapper.]. + */ +export interface TypedExtensionConfig { + /** + * The name of an extension. This is not used to select the extension, instead + * it serves the role of an opaque identifier. + */ + 'name'?: (string); + /** + * The typed config for the extension. The type URL will be used to identify + * the extension. In the case that the type URL is *udpa.type.v1.TypedStruct*, + * the inner type URL of *TypedStruct* will be utilized. See the + * :ref:`extension configuration overview + * ` for further details. + */ + 'typed_config'?: (_google_protobuf_Any); +} + +/** + * Message type for extension configuration. + * [#next-major-version: revisit all existing typed_config that doesn't use this wrapper.]. + */ +export interface TypedExtensionConfig__Output { + /** + * The name of an extension. This is not used to select the extension, instead + * it serves the role of an opaque identifier. + */ + 'name': (string); + /** + * The typed config for the extension. The type URL will be used to identify + * the extension. In the case that the type URL is *udpa.type.v1.TypedStruct*, + * the inner type URL of *TypedStruct* will be utilized. See the + * :ref:`extension configuration overview + * ` for further details. + */ + 'typed_config'?: (_google_protobuf_Any__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts similarity index 95% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts rename to packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts index 9c55560e8..b765ec5a7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/UpstreamHttpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/protocol.proto +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto export interface UpstreamHttpProtocolOptions { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/WatchedDirectory.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/WatchedDirectory.ts new file mode 100644 index 000000000..d6f0d124b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/WatchedDirectory.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * A directory that is watched for changes, e.g. by inotify on Linux. Move/rename + * events inside this directory trigger the watch. + */ +export interface WatchedDirectory { + /** + * Directory path to watch. + */ + 'path'?: (string); +} + +/** + * A directory that is watched for changes, e.g. by inotify on Linux. Move/rename + * events inside this directory trigger the watch. + */ +export interface WatchedDirectory__Output { + /** + * Directory path to watch. + */ + 'path': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts similarity index 67% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts rename to packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts index 14598bec1..a092f0dde 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/ClusterLoadAssignment.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts @@ -1,15 +1,15 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint.proto +// Original file: deps/envoy-api/envoy/config/endpoint/v3/endpoint.proto -import type { LocalityLbEndpoints as _envoy_api_v2_endpoint_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_api_v2_endpoint_LocalityLbEndpoints__Output } from '../../../envoy/api/v2/endpoint/LocalityLbEndpoints'; -import type { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../envoy/api/v2/endpoint/Endpoint'; -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../envoy/type/FractionalPercent'; +import type { LocalityLbEndpoints as _envoy_config_endpoint_v3_LocalityLbEndpoints, LocalityLbEndpoints__Output as _envoy_config_endpoint_v3_LocalityLbEndpoints__Output } from '../../../../envoy/config/endpoint/v3/LocalityLbEndpoints'; +import type { Endpoint as _envoy_config_endpoint_v3_Endpoint, Endpoint__Output as _envoy_config_endpoint_v3_Endpoint__Output } from '../../../../envoy/config/endpoint/v3/Endpoint'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../envoy/type/v3/FractionalPercent'; /** * [#not-implemented-hide:] */ -export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload { +export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload { /** * Identifier for the policy specifying the drop. */ @@ -17,13 +17,13 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload { /** * Percentage of traffic that should be dropped for the category. */ - 'drop_percentage'?: (_envoy_type_FractionalPercent); + 'drop_percentage'?: (_envoy_type_v3_FractionalPercent); } /** * [#not-implemented-hide:] */ -export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output { +export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload__Output { /** * Identifier for the policy specifying the drop. */ @@ -31,14 +31,14 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output /** * Percentage of traffic that should be dropped for the category. */ - 'drop_percentage'?: (_envoy_type_FractionalPercent__Output); + 'drop_percentage'?: (_envoy_type_v3_FractionalPercent__Output); } /** * Load balancing policy settings. * [#next-free-field: 6] */ -export interface _envoy_api_v2_ClusterLoadAssignment_Policy { +export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy { /** * Action to trim the overall incoming traffic to protect the upstream * hosts. This action allows protection in case the hosts are unable to @@ -61,11 +61,11 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy { * actual_outgoing_load = 20% // remaining after applying all categories. * [#not-implemented-hide:] */ - 'drop_overloads'?: (_envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload)[]; + 'drop_overloads'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload)[]; /** * Priority levels and localities are considered overprovisioned with this * factor (in percentage). This means that we don't consider a priority - * level or locality unhealthy until the percentage of healthy hosts + * level or locality unhealthy until the fraction of healthy hosts * multiplied by the overprovisioning factor drops below 100. * With the default value 140(1.4), Envoy doesn't consider a priority level * or a locality unhealthy until their percentage of healthy hosts drops @@ -86,24 +86,13 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy { * Defaults to 0 which means endpoints never go stale. */ 'endpoint_stale_after'?: (_google_protobuf_Duration); - /** - * The flag to disable overprovisioning. If it is set to true, - * :ref:`overprovisioning factor - * ` will be ignored - * and Envoy will not perform graceful failover between priority levels or - * localities as endpoints become unhealthy. Otherwise Envoy will perform - * graceful failover as :ref:`overprovisioning factor - * ` suggests. - * [#not-implemented-hide:] - */ - 'disable_overprovisioning'?: (boolean); } /** * Load balancing policy settings. * [#next-free-field: 6] */ -export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { +export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy__Output { /** * Action to trim the overall incoming traffic to protect the upstream * hosts. This action allows protection in case the hosts are unable to @@ -126,11 +115,11 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { * actual_outgoing_load = 20% // remaining after applying all categories. * [#not-implemented-hide:] */ - 'drop_overloads': (_envoy_api_v2_ClusterLoadAssignment_Policy_DropOverload__Output)[]; + 'drop_overloads': (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOverload__Output)[]; /** * Priority levels and localities are considered overprovisioned with this * factor (in percentage). This means that we don't consider a priority - * level or locality unhealthy until the percentage of healthy hosts + * level or locality unhealthy until the fraction of healthy hosts * multiplied by the overprovisioning factor drops below 100. * With the default value 140(1.4), Envoy doesn't consider a priority level * or a locality unhealthy until their percentage of healthy hosts drops @@ -151,17 +140,6 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { * Defaults to 0 which means endpoints never go stale. */ 'endpoint_stale_after'?: (_google_protobuf_Duration__Output); - /** - * The flag to disable overprovisioning. If it is set to true, - * :ref:`overprovisioning factor - * ` will be ignored - * and Envoy will not perform graceful failover between priority levels or - * localities as endpoints become unhealthy. Otherwise Envoy will perform - * graceful failover as :ref:`overprovisioning factor - * ` suggests. - * [#not-implemented-hide:] - */ - 'disable_overprovisioning': (boolean); } /** @@ -179,24 +157,24 @@ export interface _envoy_api_v2_ClusterLoadAssignment_Policy__Output { export interface ClusterLoadAssignment { /** * Name of the cluster. This will be the :ref:`service_name - * ` value if specified + * ` value if specified * in the cluster :ref:`EdsClusterConfig - * `. + * `. */ 'cluster_name'?: (string); /** * List of endpoints to load balance to. */ - 'endpoints'?: (_envoy_api_v2_endpoint_LocalityLbEndpoints)[]; + 'endpoints'?: (_envoy_config_endpoint_v3_LocalityLbEndpoints)[]; /** * Load balancing policy settings. */ - 'policy'?: (_envoy_api_v2_ClusterLoadAssignment_Policy); + 'policy'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy); /** * Map of named endpoints that can be referenced in LocalityLbEndpoints. * [#not-implemented-hide:] */ - 'named_endpoints'?: ({[key: string]: _envoy_api_v2_endpoint_Endpoint}); + 'named_endpoints'?: ({[key: string]: _envoy_config_endpoint_v3_Endpoint}); } /** @@ -214,22 +192,22 @@ export interface ClusterLoadAssignment { export interface ClusterLoadAssignment__Output { /** * Name of the cluster. This will be the :ref:`service_name - * ` value if specified + * ` value if specified * in the cluster :ref:`EdsClusterConfig - * `. + * `. */ 'cluster_name': (string); /** * List of endpoints to load balance to. */ - 'endpoints': (_envoy_api_v2_endpoint_LocalityLbEndpoints__Output)[]; + 'endpoints': (_envoy_config_endpoint_v3_LocalityLbEndpoints__Output)[]; /** * Load balancing policy settings. */ - 'policy'?: (_envoy_api_v2_ClusterLoadAssignment_Policy__Output); + 'policy'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy__Output); /** * Map of named endpoints that can be referenced in LocalityLbEndpoints. * [#not-implemented-hide:] */ - 'named_endpoints'?: ({[key: string]: _envoy_api_v2_endpoint_Endpoint__Output}); + 'named_endpoints'?: ({[key: string]: _envoy_config_endpoint_v3_Endpoint__Output}); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts new file mode 100644 index 000000000..4d15bee14 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts @@ -0,0 +1,115 @@ +// Original file: deps/envoy-api/envoy/config/endpoint/v3/load_report.proto + +import type { UpstreamLocalityStats as _envoy_config_endpoint_v3_UpstreamLocalityStats, UpstreamLocalityStats__Output as _envoy_config_endpoint_v3_UpstreamLocalityStats__Output } from '../../../../envoy/config/endpoint/v3/UpstreamLocalityStats'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Long } from '@grpc/proto-loader'; + +export interface _envoy_config_endpoint_v3_ClusterStats_DroppedRequests { + /** + * Identifier for the policy specifying the drop. + */ + 'category'?: (string); + /** + * Total number of deliberately dropped requests for the category. + */ + 'dropped_count'?: (number | string | Long); +} + +export interface _envoy_config_endpoint_v3_ClusterStats_DroppedRequests__Output { + /** + * Identifier for the policy specifying the drop. + */ + 'category': (string); + /** + * Total number of deliberately dropped requests for the category. + */ + 'dropped_count': (string); +} + +/** + * Per cluster load stats. Envoy reports these stats a management server in a + * :ref:`LoadStatsRequest` + * Next ID: 7 + * [#next-free-field: 7] + */ +export interface ClusterStats { + /** + * The name of the cluster. + */ + 'cluster_name'?: (string); + /** + * Need at least one. + */ + 'upstream_locality_stats'?: (_envoy_config_endpoint_v3_UpstreamLocalityStats)[]; + /** + * Cluster-level stats such as total_successful_requests may be computed by + * summing upstream_locality_stats. In addition, below there are additional + * cluster-wide stats. + * + * The total number of dropped requests. This covers requests + * deliberately dropped by the drop_overload policy and circuit breaking. + */ + 'total_dropped_requests'?: (number | string | Long); + /** + * Period over which the actual load report occurred. This will be guaranteed to include every + * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy + * and the *LoadStatsResponse* message sent from the management server, this may be longer than + * the requested load reporting interval in the *LoadStatsResponse*. + */ + 'load_report_interval'?: (_google_protobuf_Duration); + /** + * Information about deliberately dropped requests for each category specified + * in the DropOverload policy. + */ + 'dropped_requests'?: (_envoy_config_endpoint_v3_ClusterStats_DroppedRequests)[]; + /** + * The eds_cluster_config service_name of the cluster. + * It's possible that two clusters send the same service_name to EDS, + * in that case, the management server is supposed to do aggregation on the load reports. + */ + 'cluster_service_name'?: (string); +} + +/** + * Per cluster load stats. Envoy reports these stats a management server in a + * :ref:`LoadStatsRequest` + * Next ID: 7 + * [#next-free-field: 7] + */ +export interface ClusterStats__Output { + /** + * The name of the cluster. + */ + 'cluster_name': (string); + /** + * Need at least one. + */ + 'upstream_locality_stats': (_envoy_config_endpoint_v3_UpstreamLocalityStats__Output)[]; + /** + * Cluster-level stats such as total_successful_requests may be computed by + * summing upstream_locality_stats. In addition, below there are additional + * cluster-wide stats. + * + * The total number of dropped requests. This covers requests + * deliberately dropped by the drop_overload policy and circuit breaking. + */ + 'total_dropped_requests': (string); + /** + * Period over which the actual load report occurred. This will be guaranteed to include every + * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy + * and the *LoadStatsResponse* message sent from the management server, this may be longer than + * the requested load reporting interval in the *LoadStatsResponse*. + */ + 'load_report_interval'?: (_google_protobuf_Duration__Output); + /** + * Information about deliberately dropped requests for each category specified + * in the DropOverload policy. + */ + 'dropped_requests': (_envoy_config_endpoint_v3_ClusterStats_DroppedRequests__Output)[]; + /** + * The eds_cluster_config service_name of the cluster. + * It's possible that two clusters send the same service_name to EDS, + * in that case, the management server is supposed to do aggregation on the load reports. + */ + 'cluster_service_name': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts similarity index 69% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts rename to packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts index 68bef75e1..7e1a7b346 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/Endpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts @@ -1,11 +1,11 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +// Original file: deps/envoy-api/envoy/config/endpoint/v3/endpoint_components.proto -import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; /** * The optional health check configuration. */ -export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig { +export interface _envoy_config_endpoint_v3_Endpoint_HealthCheckConfig { /** * Optional alternative health check port value. * @@ -17,8 +17,8 @@ export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig { 'port_value'?: (number); /** * By default, the host header for L7 health checks is controlled by cluster level configuration - * (see: :ref:`host ` and - * :ref:`authority `). Setting this + * (see: :ref:`host ` and + * :ref:`authority `). Setting this * to a non-empty value allows overriding the cluster level configuration for a specific * endpoint. */ @@ -28,7 +28,7 @@ export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig { /** * The optional health check configuration. */ -export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output { +export interface _envoy_config_endpoint_v3_Endpoint_HealthCheckConfig__Output { /** * Optional alternative health check port value. * @@ -40,8 +40,8 @@ export interface _envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output { 'port_value': (number); /** * By default, the host header for L7 health checks is controlled by cluster level configuration - * (see: :ref:`host ` and - * :ref:`authority `). Setting this + * (see: :ref:`host ` and + * :ref:`authority `). Setting this * to a non-empty value allows overriding the cluster level configuration for a specific * endpoint. */ @@ -59,11 +59,11 @@ export interface Endpoint { * * The form of host address depends on the given cluster type. For STATIC or EDS, * it is expected to be a direct IP address (or something resolvable by the - * specified :ref:`resolver ` + * specified :ref:`resolver ` * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ - 'address'?: (_envoy_api_v2_core_Address); + 'address'?: (_envoy_config_core_v3_Address); /** * The optional health check configuration is used as configuration for the * health checker to contact the health checked host. @@ -73,12 +73,12 @@ export interface Endpoint { * This takes into effect only for upstream clusters with * :ref:`active health checking ` enabled. */ - 'health_check_config'?: (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig); + 'health_check_config'?: (_envoy_config_endpoint_v3_Endpoint_HealthCheckConfig); /** * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features * that require a hostname, like - * :ref:`auto_host_rewrite `. + * :ref:`auto_host_rewrite `. */ 'hostname'?: (string); } @@ -94,11 +94,11 @@ export interface Endpoint__Output { * * The form of host address depends on the given cluster type. For STATIC or EDS, * it is expected to be a direct IP address (or something resolvable by the - * specified :ref:`resolver ` + * specified :ref:`resolver ` * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ - 'address'?: (_envoy_api_v2_core_Address__Output); + 'address'?: (_envoy_config_core_v3_Address__Output); /** * The optional health check configuration is used as configuration for the * health checker to contact the health checked host. @@ -108,12 +108,12 @@ export interface Endpoint__Output { * This takes into effect only for upstream clusters with * :ref:`active health checking ` enabled. */ - 'health_check_config'?: (_envoy_api_v2_endpoint_Endpoint_HealthCheckConfig__Output); + 'health_check_config'?: (_envoy_config_endpoint_v3_Endpoint_HealthCheckConfig__Output); /** * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features * that require a hostname, like - * :ref:`auto_host_rewrite `. + * :ref:`auto_host_rewrite `. */ 'hostname': (string); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/EndpointLoadMetricStats.ts new file mode 100644 index 000000000..50f63f4ca --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/EndpointLoadMetricStats.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/config/endpoint/v3/load_report.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface EndpointLoadMetricStats { + /** + * Name of the metric; may be empty. + */ + 'metric_name'?: (string); + /** + * Number of calls that finished and included this metric. + */ + 'num_requests_finished_with_metric'?: (number | string | Long); + /** + * Sum of metric values across all calls that finished with this metric for + * load_reporting_interval. + */ + 'total_metric_value'?: (number | string); +} + +export interface EndpointLoadMetricStats__Output { + /** + * Name of the metric; may be empty. + */ + 'metric_name': (string); + /** + * Number of calls that finished and included this metric. + */ + 'num_requests_finished_with_metric': (string); + /** + * Sum of metric values across all calls that finished with this metric for + * load_reporting_interval. + */ + 'total_metric_value': (number); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts similarity index 74% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts rename to packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts index 1f8be9305..449dd8aa3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LbEndpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts @@ -1,8 +1,8 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +// Original file: deps/envoy-api/envoy/config/endpoint/v3/endpoint_components.proto -import type { Endpoint as _envoy_api_v2_endpoint_Endpoint, Endpoint__Output as _envoy_api_v2_endpoint_Endpoint__Output } from '../../../../envoy/api/v2/endpoint/Endpoint'; -import type { HealthStatus as _envoy_api_v2_core_HealthStatus } from '../../../../envoy/api/v2/core/HealthStatus'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { Endpoint as _envoy_config_endpoint_v3_Endpoint, Endpoint__Output as _envoy_config_endpoint_v3_Endpoint__Output } from '../../../../envoy/config/endpoint/v3/Endpoint'; +import type { HealthStatus as _envoy_config_core_v3_HealthStatus } from '../../../../envoy/config/core/v3/HealthStatus'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** @@ -10,21 +10,21 @@ import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output a * [#next-free-field: 6] */ export interface LbEndpoint { - 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint); + 'endpoint'?: (_envoy_config_endpoint_v3_Endpoint); /** * Optional health status when known and supplied by EDS server. */ - 'health_status'?: (_envoy_api_v2_core_HealthStatus | keyof typeof _envoy_api_v2_core_HealthStatus); + 'health_status'?: (_envoy_config_core_v3_HealthStatus | keyof typeof _envoy_config_core_v3_HealthStatus); /** * The endpoint metadata specifies values that may be used by the load * balancer to select endpoints in a cluster for a given request. The filter * name should be specified as *envoy.lb*. An example boolean key-value pair * is *canary*, providing the optional canary status of the upstream host. * This may be matched against in a route's - * :ref:`RouteAction ` metadata_match field + * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ - 'metadata'?: (_envoy_api_v2_core_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata); /** * The optional load balancing weight of the upstream host; at least 1. * Envoy uses the load balancing weight in some of the built in load @@ -52,21 +52,21 @@ export interface LbEndpoint { * [#next-free-field: 6] */ export interface LbEndpoint__Output { - 'endpoint'?: (_envoy_api_v2_endpoint_Endpoint__Output); + 'endpoint'?: (_envoy_config_endpoint_v3_Endpoint__Output); /** * Optional health status when known and supplied by EDS server. */ - 'health_status': (keyof typeof _envoy_api_v2_core_HealthStatus); + 'health_status': (keyof typeof _envoy_config_core_v3_HealthStatus); /** * The endpoint metadata specifies values that may be used by the load * balancer to select endpoints in a cluster for a given request. The filter * name should be specified as *envoy.lb*. An example boolean key-value pair * is *canary*, providing the optional canary status of the upstream host. * This may be matched against in a route's - * :ref:`RouteAction ` metadata_match field + * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ - 'metadata'?: (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_config_core_v3_Metadata__Output); /** * The optional load balancing weight of the upstream host; at least 1. * Envoy uses the load balancing weight in some of the built in load diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts similarity index 87% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts rename to packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts index 557d97072..9924d2466 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/LocalityLbEndpoints.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts @@ -1,7 +1,7 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/endpoint_components.proto +// Original file: deps/envoy-api/envoy/config/endpoint/v3/endpoint_components.proto -import type { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; -import type { LbEndpoint as _envoy_api_v2_endpoint_LbEndpoint, LbEndpoint__Output as _envoy_api_v2_endpoint_LbEndpoint__Output } from '../../../../envoy/api/v2/endpoint/LbEndpoint'; +import type { Locality as _envoy_config_core_v3_Locality, Locality__Output as _envoy_config_core_v3_Locality__Output } from '../../../../envoy/config/core/v3/Locality'; +import type { LbEndpoint as _envoy_config_endpoint_v3_LbEndpoint, LbEndpoint__Output as _envoy_config_endpoint_v3_LbEndpoint__Output } from '../../../../envoy/config/endpoint/v3/LbEndpoint'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** @@ -15,11 +15,11 @@ export interface LocalityLbEndpoints { /** * Identifies location of where the upstream hosts run. */ - 'locality'?: (_envoy_api_v2_core_Locality); + 'locality'?: (_envoy_config_core_v3_Locality); /** * The group of endpoints belonging to the locality specified. */ - 'lb_endpoints'?: (_envoy_api_v2_endpoint_LbEndpoint)[]; + 'lb_endpoints'?: (_envoy_config_endpoint_v3_LbEndpoint)[]; /** * Optional: Per priority/region/zone/sub_zone weight; at least 1. The load * balancing weight for a locality is divided by the sum of the weights of all @@ -68,11 +68,11 @@ export interface LocalityLbEndpoints__Output { /** * Identifies location of where the upstream hosts run. */ - 'locality'?: (_envoy_api_v2_core_Locality__Output); + 'locality'?: (_envoy_config_core_v3_Locality__Output); /** * The group of endpoints belonging to the locality specified. */ - 'lb_endpoints': (_envoy_api_v2_endpoint_LbEndpoint__Output)[]; + 'lb_endpoints': (_envoy_config_endpoint_v3_LbEndpoint__Output)[]; /** * Optional: Per priority/region/zone/sub_zone weight; at least 1. The load * balancing weight for a locality is divided by the sum of the weights of all diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts new file mode 100644 index 000000000..8fe66d6c4 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts @@ -0,0 +1,104 @@ +// Original file: deps/envoy-api/envoy/config/endpoint/v3/load_report.proto + +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { EndpointLoadMetricStats as _envoy_config_endpoint_v3_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_config_endpoint_v3_EndpointLoadMetricStats__Output } from '../../../../envoy/config/endpoint/v3/EndpointLoadMetricStats'; +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Long } from '@grpc/proto-loader'; + +/** + * [#next-free-field: 8] + */ +export interface UpstreamEndpointStats { + /** + * Upstream host address. + */ + 'address'?: (_envoy_config_core_v3_Address); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. These include non-5xx responses for HTTP, where errors + * originate at the client and the endpoint responded successfully. For gRPC, + * the grpc-status values are those not covered by total_error_requests below. + */ + 'total_successful_requests'?: (number | string | Long); + /** + * The total number of unfinished requests for this endpoint. + */ + 'total_requests_in_progress'?: (number | string | Long); + /** + * The total number of requests that failed due to errors at the endpoint. + * For HTTP these are responses with 5xx status codes and for gRPC the + * grpc-status values: + * + * - DeadlineExceeded + * - Unimplemented + * - Internal + * - Unavailable + * - Unknown + * - DataLoss + */ + 'total_error_requests'?: (number | string | Long); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats'?: (_envoy_config_endpoint_v3_EndpointLoadMetricStats)[]; + /** + * Opaque and implementation dependent metadata of the + * endpoint. Envoy will pass this directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct); + /** + * The total number of requests that were issued to this endpoint + * since the last report. A single TCP connection, HTTP or gRPC + * request or stream is counted as one request. + */ + 'total_issued_requests'?: (number | string | Long); +} + +/** + * [#next-free-field: 8] + */ +export interface UpstreamEndpointStats__Output { + /** + * Upstream host address. + */ + 'address'?: (_envoy_config_core_v3_Address__Output); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. These include non-5xx responses for HTTP, where errors + * originate at the client and the endpoint responded successfully. For gRPC, + * the grpc-status values are those not covered by total_error_requests below. + */ + 'total_successful_requests': (string); + /** + * The total number of unfinished requests for this endpoint. + */ + 'total_requests_in_progress': (string); + /** + * The total number of requests that failed due to errors at the endpoint. + * For HTTP these are responses with 5xx status codes and for gRPC the + * grpc-status values: + * + * - DeadlineExceeded + * - Unimplemented + * - Internal + * - Unavailable + * - Unknown + * - DataLoss + */ + 'total_error_requests': (string); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats': (_envoy_config_endpoint_v3_EndpointLoadMetricStats__Output)[]; + /** + * Opaque and implementation dependent metadata of the + * endpoint. Envoy will pass this directly to the management server. + */ + 'metadata'?: (_google_protobuf_Struct__Output); + /** + * The total number of requests that were issued to this endpoint + * since the last report. A single TCP connection, HTTP or gRPC + * request or stream is counted as one request. + */ + 'total_issued_requests': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts new file mode 100644 index 000000000..3eb8cc4eb --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts @@ -0,0 +1,104 @@ +// Original file: deps/envoy-api/envoy/config/endpoint/v3/load_report.proto + +import type { Locality as _envoy_config_core_v3_Locality, Locality__Output as _envoy_config_core_v3_Locality__Output } from '../../../../envoy/config/core/v3/Locality'; +import type { EndpointLoadMetricStats as _envoy_config_endpoint_v3_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_config_endpoint_v3_EndpointLoadMetricStats__Output } from '../../../../envoy/config/endpoint/v3/EndpointLoadMetricStats'; +import type { UpstreamEndpointStats as _envoy_config_endpoint_v3_UpstreamEndpointStats, UpstreamEndpointStats__Output as _envoy_config_endpoint_v3_UpstreamEndpointStats__Output } from '../../../../envoy/config/endpoint/v3/UpstreamEndpointStats'; +import type { Long } from '@grpc/proto-loader'; + +/** + * These are stats Envoy reports to the management server at a frequency defined by + * :ref:`LoadStatsResponse.load_reporting_interval`. + * Stats per upstream region/zone and optionally per subzone. + * [#next-free-field: 9] + */ +export interface UpstreamLocalityStats { + /** + * Name of zone, region and optionally endpoint group these metrics were + * collected from. Zone and region names could be empty if unknown. + */ + 'locality'?: (_envoy_config_core_v3_Locality); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. + */ + 'total_successful_requests'?: (number | string | Long); + /** + * The total number of unfinished requests + */ + 'total_requests_in_progress'?: (number | string | Long); + /** + * The total number of requests that failed due to errors at the endpoint, + * aggregated over all endpoints in the locality. + */ + 'total_error_requests'?: (number | string | Long); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats'?: (_envoy_config_endpoint_v3_EndpointLoadMetricStats)[]; + /** + * [#not-implemented-hide:] The priority of the endpoint group these metrics + * were collected from. + */ + 'priority'?: (number); + /** + * Endpoint granularity stats information for this locality. This information + * is populated if the Server requests it by setting + * :ref:`LoadStatsResponse.report_endpoint_granularity`. + */ + 'upstream_endpoint_stats'?: (_envoy_config_endpoint_v3_UpstreamEndpointStats)[]; + /** + * The total number of requests that were issued by this Envoy since + * the last report. This information is aggregated over all the + * upstream endpoints in the locality. + */ + 'total_issued_requests'?: (number | string | Long); +} + +/** + * These are stats Envoy reports to the management server at a frequency defined by + * :ref:`LoadStatsResponse.load_reporting_interval`. + * Stats per upstream region/zone and optionally per subzone. + * [#next-free-field: 9] + */ +export interface UpstreamLocalityStats__Output { + /** + * Name of zone, region and optionally endpoint group these metrics were + * collected from. Zone and region names could be empty if unknown. + */ + 'locality'?: (_envoy_config_core_v3_Locality__Output); + /** + * The total number of requests successfully completed by the endpoints in the + * locality. + */ + 'total_successful_requests': (string); + /** + * The total number of unfinished requests + */ + 'total_requests_in_progress': (string); + /** + * The total number of requests that failed due to errors at the endpoint, + * aggregated over all endpoints in the locality. + */ + 'total_error_requests': (string); + /** + * Stats for multi-dimensional load balancing. + */ + 'load_metric_stats': (_envoy_config_endpoint_v3_EndpointLoadMetricStats__Output)[]; + /** + * [#not-implemented-hide:] The priority of the endpoint group these metrics + * were collected from. + */ + 'priority': (number); + /** + * Endpoint granularity stats information for this locality. This information + * is populated if the Server requests it by setting + * :ref:`LoadStatsResponse.report_endpoint_granularity`. + */ + 'upstream_endpoint_stats': (_envoy_config_endpoint_v3_UpstreamEndpointStats__Output)[]; + /** + * The total number of requests that were issued by this Envoy since + * the last report. This information is aggregated over all the + * upstream endpoints in the locality. + */ + 'total_issued_requests': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts deleted file mode 100644 index d75c9676c..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/AccessLogFilter.ts +++ /dev/null @@ -1,115 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -import type { StatusCodeFilter as _envoy_config_filter_accesslog_v2_StatusCodeFilter, StatusCodeFilter__Output as _envoy_config_filter_accesslog_v2_StatusCodeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/StatusCodeFilter'; -import type { DurationFilter as _envoy_config_filter_accesslog_v2_DurationFilter, DurationFilter__Output as _envoy_config_filter_accesslog_v2_DurationFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/DurationFilter'; -import type { NotHealthCheckFilter as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter, NotHealthCheckFilter__Output as _envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/NotHealthCheckFilter'; -import type { TraceableFilter as _envoy_config_filter_accesslog_v2_TraceableFilter, TraceableFilter__Output as _envoy_config_filter_accesslog_v2_TraceableFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/TraceableFilter'; -import type { RuntimeFilter as _envoy_config_filter_accesslog_v2_RuntimeFilter, RuntimeFilter__Output as _envoy_config_filter_accesslog_v2_RuntimeFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/RuntimeFilter'; -import type { AndFilter as _envoy_config_filter_accesslog_v2_AndFilter, AndFilter__Output as _envoy_config_filter_accesslog_v2_AndFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/AndFilter'; -import type { OrFilter as _envoy_config_filter_accesslog_v2_OrFilter, OrFilter__Output as _envoy_config_filter_accesslog_v2_OrFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/OrFilter'; -import type { HeaderFilter as _envoy_config_filter_accesslog_v2_HeaderFilter, HeaderFilter__Output as _envoy_config_filter_accesslog_v2_HeaderFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/HeaderFilter'; -import type { ResponseFlagFilter as _envoy_config_filter_accesslog_v2_ResponseFlagFilter, ResponseFlagFilter__Output as _envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ResponseFlagFilter'; -import type { GrpcStatusFilter as _envoy_config_filter_accesslog_v2_GrpcStatusFilter, GrpcStatusFilter__Output as _envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/GrpcStatusFilter'; -import type { ExtensionFilter as _envoy_config_filter_accesslog_v2_ExtensionFilter, ExtensionFilter__Output as _envoy_config_filter_accesslog_v2_ExtensionFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ExtensionFilter'; - -/** - * [#next-free-field: 12] - */ -export interface AccessLogFilter { - /** - * Status code filter. - */ - 'status_code_filter'?: (_envoy_config_filter_accesslog_v2_StatusCodeFilter); - /** - * Duration filter. - */ - 'duration_filter'?: (_envoy_config_filter_accesslog_v2_DurationFilter); - /** - * Not health check filter. - */ - 'not_health_check_filter'?: (_envoy_config_filter_accesslog_v2_NotHealthCheckFilter); - /** - * Traceable filter. - */ - 'traceable_filter'?: (_envoy_config_filter_accesslog_v2_TraceableFilter); - /** - * Runtime filter. - */ - 'runtime_filter'?: (_envoy_config_filter_accesslog_v2_RuntimeFilter); - /** - * And filter. - */ - 'and_filter'?: (_envoy_config_filter_accesslog_v2_AndFilter); - /** - * Or filter. - */ - 'or_filter'?: (_envoy_config_filter_accesslog_v2_OrFilter); - /** - * Header filter. - */ - 'header_filter'?: (_envoy_config_filter_accesslog_v2_HeaderFilter); - /** - * Response flag filter. - */ - 'response_flag_filter'?: (_envoy_config_filter_accesslog_v2_ResponseFlagFilter); - /** - * gRPC status filter. - */ - 'grpc_status_filter'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter); - /** - * Extension filter. - */ - 'extension_filter'?: (_envoy_config_filter_accesslog_v2_ExtensionFilter); - 'filter_specifier'?: "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"; -} - -/** - * [#next-free-field: 12] - */ -export interface AccessLogFilter__Output { - /** - * Status code filter. - */ - 'status_code_filter'?: (_envoy_config_filter_accesslog_v2_StatusCodeFilter__Output); - /** - * Duration filter. - */ - 'duration_filter'?: (_envoy_config_filter_accesslog_v2_DurationFilter__Output); - /** - * Not health check filter. - */ - 'not_health_check_filter'?: (_envoy_config_filter_accesslog_v2_NotHealthCheckFilter__Output); - /** - * Traceable filter. - */ - 'traceable_filter'?: (_envoy_config_filter_accesslog_v2_TraceableFilter__Output); - /** - * Runtime filter. - */ - 'runtime_filter'?: (_envoy_config_filter_accesslog_v2_RuntimeFilter__Output); - /** - * And filter. - */ - 'and_filter'?: (_envoy_config_filter_accesslog_v2_AndFilter__Output); - /** - * Or filter. - */ - 'or_filter'?: (_envoy_config_filter_accesslog_v2_OrFilter__Output); - /** - * Header filter. - */ - 'header_filter'?: (_envoy_config_filter_accesslog_v2_HeaderFilter__Output); - /** - * Response flag filter. - */ - 'response_flag_filter'?: (_envoy_config_filter_accesslog_v2_ResponseFlagFilter__Output); - /** - * gRPC status filter. - */ - 'grpc_status_filter'?: (_envoy_config_filter_accesslog_v2_GrpcStatusFilter__Output); - /** - * Extension filter. - */ - 'extension_filter'?: (_envoy_config_filter_accesslog_v2_ExtensionFilter__Output); - 'filter_specifier': "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts deleted file mode 100644 index 8989ba603..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/ComparisonFilter.ts +++ /dev/null @@ -1,48 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -import type { RuntimeUInt32 as _envoy_api_v2_core_RuntimeUInt32, RuntimeUInt32__Output as _envoy_api_v2_core_RuntimeUInt32__Output } from '../../../../../envoy/api/v2/core/RuntimeUInt32'; - -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -export enum _envoy_config_filter_accesslog_v2_ComparisonFilter_Op { - /** - * = - */ - EQ = 0, - /** - * >= - */ - GE = 1, - /** - * <= - */ - LE = 2, -} - -/** - * Filter on an integer comparison. - */ -export interface ComparisonFilter { - /** - * Comparison operator. - */ - 'op'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter_Op | keyof typeof _envoy_config_filter_accesslog_v2_ComparisonFilter_Op); - /** - * Value to compare against. - */ - 'value'?: (_envoy_api_v2_core_RuntimeUInt32); -} - -/** - * Filter on an integer comparison. - */ -export interface ComparisonFilter__Output { - /** - * Comparison operator. - */ - 'op': (keyof typeof _envoy_config_filter_accesslog_v2_ComparisonFilter_Op); - /** - * Value to compare against. - */ - 'value'?: (_envoy_api_v2_core_RuntimeUInt32__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts deleted file mode 100644 index 52a37cd95..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/DurationFilter.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -import type { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; - -/** - * Filters on total request duration in milliseconds. - */ -export interface DurationFilter { - /** - * Comparison. - */ - 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter); -} - -/** - * Filters on total request duration in milliseconds. - */ -export interface DurationFilter__Output { - /** - * Comparison. - */ - 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts deleted file mode 100644 index d40610617..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/HeaderFilter.ts +++ /dev/null @@ -1,25 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../../envoy/api/v2/route/HeaderMatcher'; - -/** - * Filters requests based on the presence or value of a request header. - */ -export interface HeaderFilter { - /** - * Only requests with a header which matches the specified HeaderMatcher will pass the filter - * check. - */ - 'header'?: (_envoy_api_v2_route_HeaderMatcher); -} - -/** - * Filters requests based on the presence or value of a request header. - */ -export interface HeaderFilter__Output { - /** - * Only requests with a header which matches the specified HeaderMatcher will pass the filter - * check. - */ - 'header'?: (_envoy_api_v2_route_HeaderMatcher__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts deleted file mode 100644 index 100ce050b..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/RuntimeFilter.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../../envoy/type/FractionalPercent'; - -/** - * Filters for random sampling of requests. - */ -export interface RuntimeFilter { - /** - * Runtime key to get an optional overridden numerator for use in the *percent_sampled* field. - * If found in runtime, this value will replace the default numerator. - */ - 'runtime_key'?: (string); - /** - * The default sampling percentage. If not specified, defaults to 0% with denominator of 100. - */ - 'percent_sampled'?: (_envoy_type_FractionalPercent); - /** - * By default, sampling pivots on the header - * :ref:`x-request-id` being present. If - * :ref:`x-request-id` is present, the filter will - * consistently sample across multiple hosts based on the runtime key value and the value - * extracted from :ref:`x-request-id`. If it is - * missing, or *use_independent_randomness* is set to true, the filter will randomly sample based - * on the runtime key value alone. *use_independent_randomness* can be used for logging kill - * switches within complex nested :ref:`AndFilter - * ` and :ref:`OrFilter - * ` blocks that are easier to reason about - * from a probability perspective (i.e., setting to true will cause the filter to behave like - * an independent random variable when composed within logical operator filters). - */ - 'use_independent_randomness'?: (boolean); -} - -/** - * Filters for random sampling of requests. - */ -export interface RuntimeFilter__Output { - /** - * Runtime key to get an optional overridden numerator for use in the *percent_sampled* field. - * If found in runtime, this value will replace the default numerator. - */ - 'runtime_key': (string); - /** - * The default sampling percentage. If not specified, defaults to 0% with denominator of 100. - */ - 'percent_sampled'?: (_envoy_type_FractionalPercent__Output); - /** - * By default, sampling pivots on the header - * :ref:`x-request-id` being present. If - * :ref:`x-request-id` is present, the filter will - * consistently sample across multiple hosts based on the runtime key value and the value - * extracted from :ref:`x-request-id`. If it is - * missing, or *use_independent_randomness* is set to true, the filter will randomly sample based - * on the runtime key value alone. *use_independent_randomness* can be used for logging kill - * switches within complex nested :ref:`AndFilter - * ` and :ref:`OrFilter - * ` blocks that are easier to reason about - * from a probability perspective (i.e., setting to true will cause the filter to behave like - * an independent random variable when composed within logical operator filters). - */ - 'use_independent_randomness': (boolean); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts deleted file mode 100644 index d60a80a14..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/accesslog/v2/StatusCodeFilter.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/accesslog/v2/accesslog.proto - -import type { ComparisonFilter as _envoy_config_filter_accesslog_v2_ComparisonFilter, ComparisonFilter__Output as _envoy_config_filter_accesslog_v2_ComparisonFilter__Output } from '../../../../../envoy/config/filter/accesslog/v2/ComparisonFilter'; - -/** - * Filters on HTTP response/status code. - */ -export interface StatusCodeFilter { - /** - * Comparison. - */ - 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter); -} - -/** - * Filters on HTTP response/status code. - */ -export interface StatusCodeFilter__Output { - /** - * Comparison. - */ - 'comparison'?: (_envoy_config_filter_accesslog_v2_ComparisonFilter__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts deleted file mode 100644 index 84e4292fc..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpFilter.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto - -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; - -export interface HttpFilter { - /** - * The name of the filter to instantiate. The name must match a - * :ref:`supported filter `. - */ - 'name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); - /** - * Filter specific configuration which depends on the filter being instantiated. See the supported - * filters for further documentation. - */ - 'config_type'?: "config"|"typed_config"; -} - -export interface HttpFilter__Output { - /** - * The name of the filter to instantiate. The name must match a - * :ref:`supported filter `. - */ - 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); - /** - * Filter specific configuration which depends on the filter being instantiated. See the supported - * filters for further documentation. - */ - 'config_type': "config"|"typed_config"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts deleted file mode 100644 index b3d89dffb..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRds.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto - -import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; - -export interface ScopedRds { - /** - * Configuration source specifier for scoped RDS. - */ - 'scoped_rds_config_source'?: (_envoy_api_v2_core_ConfigSource); -} - -export interface ScopedRds__Output { - /** - * Configuration source specifier for scoped RDS. - */ - 'scoped_rds_config_source'?: (_envoy_api_v2_core_ConfigSource__Output); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts b/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts deleted file mode 100644 index a57f1725e..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto - -import type { ScopedRouteConfiguration as _envoy_api_v2_ScopedRouteConfiguration, ScopedRouteConfiguration__Output as _envoy_api_v2_ScopedRouteConfiguration__Output } from '../../../../../../envoy/api/v2/ScopedRouteConfiguration'; - -/** - * This message is used to work around the limitations with 'oneof' and repeated fields. - */ -export interface ScopedRouteConfigurationsList { - 'scoped_route_configurations'?: (_envoy_api_v2_ScopedRouteConfiguration)[]; -} - -/** - * This message is used to work around the limitations with 'oneof' and repeated fields. - */ -export interface ScopedRouteConfigurationsList__Output { - 'scoped_route_configurations': (_envoy_api_v2_ScopedRouteConfiguration__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ActiveRawUdpListenerConfig.ts similarity index 56% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ActiveRawUdpListenerConfig.ts index 7bb47c26c..3cc895aa9 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ActiveRawUdpListenerConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ActiveRawUdpListenerConfig.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/udp_listener_config.proto export interface ActiveRawUdpListenerConfig { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts similarity index 96% rename from packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts index f683d3e82..508236641 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v2/ApiListener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/config/listener/v2/api_listener.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/api_listener.proto import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts new file mode 100644 index 000000000..a3d26c904 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts @@ -0,0 +1,52 @@ +// Original file: deps/envoy-api/envoy/config/listener/v3/listener_components.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { ExtensionConfigSource as _envoy_config_core_v3_ExtensionConfigSource, ExtensionConfigSource__Output as _envoy_config_core_v3_ExtensionConfigSource__Output } from '../../../../envoy/config/core/v3/ExtensionConfigSource'; + +/** + * [#next-free-field: 6] + */ +export interface Filter { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ + 'name'?: (string); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + */ + 'typed_config'?: (_google_protobuf_Any); + /** + * Configuration source specifier for an extension configuration discovery + * service. In case of a failure and without the default configuration, the + * listener closes the connections. + * [#not-implemented-hide:] + */ + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource); + 'config_type'?: "typed_config"|"config_discovery"; +} + +/** + * [#next-free-field: 6] + */ +export interface Filter__Output { + /** + * The name of the filter to instantiate. The name must match a + * :ref:`supported filter `. + */ + 'name': (string); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + */ + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Configuration source specifier for an extension configuration discovery + * service. In case of a failure and without the default configuration, the + * listener closes the connections. + * [#not-implemented-hide:] + */ + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output); + 'config_type': "typed_config"|"config_discovery"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts new file mode 100644 index 000000000..e7f0adb7c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts @@ -0,0 +1,170 @@ +// Original file: deps/envoy-api/envoy/config/listener/v3/listener_components.proto + +import type { FilterChainMatch as _envoy_config_listener_v3_FilterChainMatch, FilterChainMatch__Output as _envoy_config_listener_v3_FilterChainMatch__Output } from '../../../../envoy/config/listener/v3/FilterChainMatch'; +import type { Filter as _envoy_config_listener_v3_Filter, Filter__Output as _envoy_config_listener_v3_Filter__Output } from '../../../../envoy/config/listener/v3/Filter'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; +import type { TransportSocket as _envoy_config_core_v3_TransportSocket, TransportSocket__Output as _envoy_config_core_v3_TransportSocket__Output } from '../../../../envoy/config/core/v3/TransportSocket'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * The configuration for on-demand filter chain. If this field is not empty in FilterChain message, + * a filter chain will be built on-demand. + * On-demand filter chains help speedup the warming up of listeners since the building and initialization of + * an on-demand filter chain will be postponed to the arrival of new connection requests that require this filter chain. + * Filter chains that are not often used can be set as on-demand. + */ +export interface _envoy_config_listener_v3_FilterChain_OnDemandConfiguration { + /** + * The timeout to wait for filter chain placeholders to complete rebuilding. + * 1. If this field is set to 0, timeout is disabled. + * 2. If not specified, a default timeout of 15s is used. + * Rebuilding will wait until dependencies are ready, have failed, or this timeout is reached. + * Upon failure or timeout, all connections related to this filter chain will be closed. + * Rebuilding will start again on the next new connection. + */ + 'rebuild_timeout'?: (_google_protobuf_Duration); +} + +/** + * The configuration for on-demand filter chain. If this field is not empty in FilterChain message, + * a filter chain will be built on-demand. + * On-demand filter chains help speedup the warming up of listeners since the building and initialization of + * an on-demand filter chain will be postponed to the arrival of new connection requests that require this filter chain. + * Filter chains that are not often used can be set as on-demand. + */ +export interface _envoy_config_listener_v3_FilterChain_OnDemandConfiguration__Output { + /** + * The timeout to wait for filter chain placeholders to complete rebuilding. + * 1. If this field is set to 0, timeout is disabled. + * 2. If not specified, a default timeout of 15s is used. + * Rebuilding will wait until dependencies are ready, have failed, or this timeout is reached. + * Upon failure or timeout, all connections related to this filter chain will be closed. + * Rebuilding will start again on the next new connection. + */ + 'rebuild_timeout'?: (_google_protobuf_Duration__Output); +} + +/** + * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and + * various other parameters. + * [#next-free-field: 10] + */ +export interface FilterChain { + /** + * The criteria to use when matching a connection to this filter chain. + */ + 'filter_chain_match'?: (_envoy_config_listener_v3_FilterChainMatch); + /** + * A list of individual network filters that make up the filter chain for + * connections established with the listener. Order matters as the filters are + * processed sequentially as connection events happen. Note: If the filter + * list is empty, the connection will close by default. + */ + 'filters'?: (_envoy_config_listener_v3_Filter)[]; + /** + * Whether the listener should expect a PROXY protocol V1 header on new + * connections. If this option is enabled, the listener will assume that that + * remote address of the connection is the one specified in the header. Some + * load balancers including the AWS ELB support this option. If the option is + * absent or set to false, Envoy will use the physical peer address of the + * connection as the remote address. + * + * This field is deprecated. Add a + * :ref:`PROXY protocol listener filter ` + * explicitly instead. + */ + 'use_proxy_proto'?: (_google_protobuf_BoolValue); + /** + * [#not-implemented-hide:] filter chain metadata. + */ + 'metadata'?: (_envoy_config_core_v3_Metadata); + /** + * Optional custom transport socket implementation to use for downstream connections. + * To setup TLS, set a transport socket with name `tls` and + * :ref:`DownstreamTlsContext ` in the `typed_config`. + * If no transport socket configuration is specified, new connections + * will be set up with plaintext. + */ + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket); + /** + * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no + * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter + * chain is to be dynamically updated or removed via FCDS a unique name must be provided. + */ + 'name'?: (string); + /** + * [#not-implemented-hide:] The configuration to specify whether the filter chain will be built on-demand. + * If this field is not empty, the filter chain will be built on-demand. + * Otherwise, the filter chain will be built normally and block listener warming. + */ + 'on_demand_configuration'?: (_envoy_config_listener_v3_FilterChain_OnDemandConfiguration); + /** + * If present and nonzero, the amount of time to allow incoming connections to complete any + * transport socket negotiations. If this expires before the transport reports connection + * establishment, the connection is summarily closed. + */ + 'transport_socket_connect_timeout'?: (_google_protobuf_Duration); +} + +/** + * A filter chain wraps a set of match criteria, an option TLS context, a set of filters, and + * various other parameters. + * [#next-free-field: 10] + */ +export interface FilterChain__Output { + /** + * The criteria to use when matching a connection to this filter chain. + */ + 'filter_chain_match'?: (_envoy_config_listener_v3_FilterChainMatch__Output); + /** + * A list of individual network filters that make up the filter chain for + * connections established with the listener. Order matters as the filters are + * processed sequentially as connection events happen. Note: If the filter + * list is empty, the connection will close by default. + */ + 'filters': (_envoy_config_listener_v3_Filter__Output)[]; + /** + * Whether the listener should expect a PROXY protocol V1 header on new + * connections. If this option is enabled, the listener will assume that that + * remote address of the connection is the one specified in the header. Some + * load balancers including the AWS ELB support this option. If the option is + * absent or set to false, Envoy will use the physical peer address of the + * connection as the remote address. + * + * This field is deprecated. Add a + * :ref:`PROXY protocol listener filter ` + * explicitly instead. + */ + 'use_proxy_proto'?: (_google_protobuf_BoolValue__Output); + /** + * [#not-implemented-hide:] filter chain metadata. + */ + 'metadata'?: (_envoy_config_core_v3_Metadata__Output); + /** + * Optional custom transport socket implementation to use for downstream connections. + * To setup TLS, set a transport socket with name `tls` and + * :ref:`DownstreamTlsContext ` in the `typed_config`. + * If no transport socket configuration is specified, new connections + * will be set up with plaintext. + */ + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket__Output); + /** + * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no + * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter + * chain is to be dynamically updated or removed via FCDS a unique name must be provided. + */ + 'name': (string); + /** + * [#not-implemented-hide:] The configuration to specify whether the filter chain will be built on-demand. + * If this field is not empty, the filter chain will be built on-demand. + * Otherwise, the filter chain will be built normally and block listener warming. + */ + 'on_demand_configuration'?: (_envoy_config_listener_v3_FilterChain_OnDemandConfiguration__Output); + /** + * If present and nonzero, the amount of time to allow incoming connections to complete any + * transport socket negotiations. If this expires before the transport reports connection + * establishment, the connection is summarily closed. + */ + 'transport_socket_connect_timeout'?: (_google_protobuf_Duration__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts similarity index 81% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts index 881a5a961..1170232ae 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/FilterChainMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts @@ -1,11 +1,11 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/listener_components.proto -import type { CidrRange as _envoy_api_v2_core_CidrRange, CidrRange__Output as _envoy_api_v2_core_CidrRange__Output } from '../../../../envoy/api/v2/core/CidrRange'; +import type { CidrRange as _envoy_config_core_v3_CidrRange, CidrRange__Output as _envoy_config_core_v3_CidrRange__Output } from '../../../../envoy/config/core/v3/CidrRange'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/listener_components.proto -export enum _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType { +export enum _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType { /** * Any connection source matches. */ @@ -13,7 +13,7 @@ export enum _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType { /** * Match a connection originating from the same host. */ - LOCAL = 1, + SAME_IP_OR_LOOPBACK = 1, /** * Match a connection originating from a different host. */ @@ -45,6 +45,18 @@ export enum _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType { * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter * chain without ``server_names`` requirements). * + * A different way to reason about the filter chain matches: + * Suppose there exists N filter chains. Prune the filter chain set using the above 8 steps. + * In each step, filter chains which most specifically matches the attributes continue to the next step. + * The listener guarantees at most 1 filter chain is left after all of the steps. + * + * Example: + * + * For destination port, filter chains specifying the destination port of incoming traffic are the + * most specific match. If none of the filter chains specifies the exact destination port, the filter + * chains which do not specify ports are the most specific match. Filter chains specifying the + * wrong port can never be the most specific match. + * * [#comment: Implemented rules are kept in the preference order, with deprecated fields * listed at the end, because that's how we want to list them in the docs. * @@ -56,7 +68,7 @@ export interface FilterChainMatch { * If non-empty, an IP address and prefix length to match addresses when the * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. */ - 'prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; + 'prefix_ranges'?: (_envoy_config_core_v3_CidrRange)[]; /** * If non-empty, an IP address and suffix length to match addresses when the * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. @@ -73,7 +85,7 @@ export interface FilterChainMatch { * parameter is not specified or the list is empty, the source IP address is * ignored. */ - 'source_prefix_ranges'?: (_envoy_api_v2_core_CidrRange)[]; + 'source_prefix_ranges'?: (_envoy_config_core_v3_CidrRange)[]; /** * The criteria is satisfied if the source port of the downstream connection * is contained in at least one of the specified ports. If the parameter is @@ -138,7 +150,7 @@ export interface FilterChainMatch { /** * Specifies the connection source IP match type. Can be any, local or external network. */ - 'source_type'?: (_envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); + 'source_type'?: (_envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType); } /** @@ -166,6 +178,18 @@ export interface FilterChainMatch { * ``www.example.com``, then ``*.example.com``, then ``*.com``, then any filter * chain without ``server_names`` requirements). * + * A different way to reason about the filter chain matches: + * Suppose there exists N filter chains. Prune the filter chain set using the above 8 steps. + * In each step, filter chains which most specifically matches the attributes continue to the next step. + * The listener guarantees at most 1 filter chain is left after all of the steps. + * + * Example: + * + * For destination port, filter chains specifying the destination port of incoming traffic are the + * most specific match. If none of the filter chains specifies the exact destination port, the filter + * chains which do not specify ports are the most specific match. Filter chains specifying the + * wrong port can never be the most specific match. + * * [#comment: Implemented rules are kept in the preference order, with deprecated fields * listed at the end, because that's how we want to list them in the docs. * @@ -177,7 +201,7 @@ export interface FilterChainMatch__Output { * If non-empty, an IP address and prefix length to match addresses when the * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. */ - 'prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; + 'prefix_ranges': (_envoy_config_core_v3_CidrRange__Output)[]; /** * If non-empty, an IP address and suffix length to match addresses when the * listener is bound to 0.0.0.0/:: or when use_original_dst is specified. @@ -194,7 +218,7 @@ export interface FilterChainMatch__Output { * parameter is not specified or the list is empty, the source IP address is * ignored. */ - 'source_prefix_ranges': (_envoy_api_v2_core_CidrRange__Output)[]; + 'source_prefix_ranges': (_envoy_config_core_v3_CidrRange__Output)[]; /** * The criteria is satisfied if the source port of the downstream connection * is contained in at least one of the specified ports. If the parameter is @@ -259,5 +283,5 @@ export interface FilterChainMatch__Output { /** * Specifies the connection source IP match type. Can be any, local or external network. */ - 'source_type': (keyof typeof _envoy_api_v2_listener_FilterChainMatch_ConnectionSourceType); + 'source_type': (keyof typeof _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts similarity index 66% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts index 8aed6564d..ebcac4381 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Listener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts @@ -1,55 +1,52 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/listener.proto -import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../envoy/api/v2/core/Address'; -import type { FilterChain as _envoy_api_v2_listener_FilterChain, FilterChain__Output as _envoy_api_v2_listener_FilterChain__Output } from '../../../envoy/api/v2/listener/FilterChain'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../envoy/api/v2/core/Metadata'; -import type { ListenerFilter as _envoy_api_v2_listener_ListenerFilter, ListenerFilter__Output as _envoy_api_v2_listener_ListenerFilter__Output } from '../../../envoy/api/v2/listener/ListenerFilter'; -import type { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../envoy/api/v2/core/SocketOption'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import type { TrafficDirection as _envoy_api_v2_core_TrafficDirection } from '../../../envoy/api/v2/core/TrafficDirection'; -import type { UdpListenerConfig as _envoy_api_v2_listener_UdpListenerConfig, UdpListenerConfig__Output as _envoy_api_v2_listener_UdpListenerConfig__Output } from '../../../envoy/api/v2/listener/UdpListenerConfig'; -import type { ApiListener as _envoy_config_listener_v2_ApiListener, ApiListener__Output as _envoy_config_listener_v2_ApiListener__Output } from '../../../envoy/config/listener/v2/ApiListener'; -import type { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../envoy/config/filter/accesslog/v2/AccessLog'; +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { FilterChain as _envoy_config_listener_v3_FilterChain, FilterChain__Output as _envoy_config_listener_v3_FilterChain__Output } from '../../../../envoy/config/listener/v3/FilterChain'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; +import type { ListenerFilter as _envoy_config_listener_v3_ListenerFilter, ListenerFilter__Output as _envoy_config_listener_v3_ListenerFilter__Output } from '../../../../envoy/config/listener/v3/ListenerFilter'; +import type { SocketOption as _envoy_config_core_v3_SocketOption, SocketOption__Output as _envoy_config_core_v3_SocketOption__Output } from '../../../../envoy/config/core/v3/SocketOption'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { TrafficDirection as _envoy_config_core_v3_TrafficDirection } from '../../../../envoy/config/core/v3/TrafficDirection'; +import type { UdpListenerConfig as _envoy_config_listener_v3_UdpListenerConfig, UdpListenerConfig__Output as _envoy_config_listener_v3_UdpListenerConfig__Output } from '../../../../envoy/config/listener/v3/UdpListenerConfig'; +import type { ApiListener as _envoy_config_listener_v3_ApiListener, ApiListener__Output as _envoy_config_listener_v3_ApiListener__Output } from '../../../../envoy/config/listener/v3/ApiListener'; +import type { AccessLog as _envoy_config_accesslog_v3_AccessLog, AccessLog__Output as _envoy_config_accesslog_v3_AccessLog__Output } from '../../../../envoy/config/accesslog/v3/AccessLog'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; /** * Configuration for listener connection balancing. */ -export interface _envoy_api_v2_Listener_ConnectionBalanceConfig { +export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig { /** * If specified, the listener will use the exact connection balancer. */ - 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance); + 'exact_balance'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance); 'balance_type'?: "exact_balance"; } /** * Configuration for listener connection balancing. */ -export interface _envoy_api_v2_Listener_ConnectionBalanceConfig__Output { +export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig__Output { /** * If specified, the listener will use the exact connection balancer. */ - 'exact_balance'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output); + 'exact_balance'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance__Output); 'balance_type': "exact_balance"; } /** * [#not-implemented-hide:] */ -export interface _envoy_api_v2_Listener_DeprecatedV1 { +export interface _envoy_config_listener_v3_Listener_DeprecatedV1 { /** * Whether the listener should bind to the port. A listener that doesn't * bind can only receive connections redirected from other listeners that * set use_original_dst parameter to true. Default is true. * - * This is deprecated in v2, all Listeners will bind to their port. An - * additional filter chain must be created for every original destination - * port this listener may redirect to in v2, with the original port - * specified in the FilterChainMatch destination_port field. - * - * [#comment:TODO(PiotrSikora): Remove this once verified that we no longer need it.] + * This is deprecated. Use :ref:`Listener.bind_to_port + * ` */ 'bind_to_port'?: (_google_protobuf_BoolValue); } @@ -57,25 +54,21 @@ export interface _envoy_api_v2_Listener_DeprecatedV1 { /** * [#not-implemented-hide:] */ -export interface _envoy_api_v2_Listener_DeprecatedV1__Output { +export interface _envoy_config_listener_v3_Listener_DeprecatedV1__Output { /** * Whether the listener should bind to the port. A listener that doesn't * bind can only receive connections redirected from other listeners that * set use_original_dst parameter to true. Default is true. * - * This is deprecated in v2, all Listeners will bind to their port. An - * additional filter chain must be created for every original destination - * port this listener may redirect to in v2, with the original port - * specified in the FilterChainMatch destination_port field. - * - * [#comment:TODO(PiotrSikora): Remove this once verified that we no longer need it.] + * This is deprecated. Use :ref:`Listener.bind_to_port + * ` */ 'bind_to_port'?: (_google_protobuf_BoolValue__Output); } -// Original file: deps/envoy-api/envoy/api/v2/listener.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/listener.proto -export enum _envoy_api_v2_Listener_DrainType { +export enum _envoy_config_listener_v3_Listener_DrainType { /** * Drain in response to calling /healthcheck/fail admin endpoint (along with the health check * filter), listener removal/modification, and hot restart. @@ -97,7 +90,7 @@ export enum _envoy_api_v2_Listener_DrainType { * sacrifices accept throughput for accuracy and should be used when there are a small number of * connections that rarely cycle (e.g., service mesh gRPC egress). */ -export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { +export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance { } /** @@ -108,11 +101,11 @@ export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance { * sacrifices accept throughput for accuracy and should be used when there are a small number of * connections that rarely cycle (e.g., service mesh gRPC egress). */ -export interface _envoy_api_v2_Listener_ConnectionBalanceConfig_ExactBalance__Output { +export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance__Output { } /** - * [#next-free-field: 23] + * [#next-free-field: 27] */ export interface Listener { /** @@ -126,33 +119,23 @@ export interface Listener { * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on * Linux as the actual port will be allocated by the OS. */ - 'address'?: (_envoy_api_v2_core_Address); + 'address'?: (_envoy_config_core_v3_Address); /** * A list of filter chains to consider for this listener. The - * :ref:`FilterChain ` with the most specific - * :ref:`FilterChainMatch ` criteria is used on a + * :ref:`FilterChain ` with the most specific + * :ref:`FilterChainMatch ` criteria is used on a * connection. * * Example using SNI for filter chain selection can be found in the * :ref:`FAQ entry `. */ - 'filter_chains'?: (_envoy_api_v2_listener_FilterChain)[]; + 'filter_chains'?: (_envoy_config_listener_v3_FilterChain)[]; /** * If a connection is redirected using *iptables*, the port on which the proxy * receives it might be different from the original destination address. When this flag is set to * true, the listener hands off redirected connections to the listener associated with the * original destination address. If there is no listener associated with the original destination * address, the connection is handled by the listener that receives it. Defaults to false. - * - * .. attention:: - * - * This field is deprecated. Use :ref:`an original_dst ` - * :ref:`listener filter ` instead. - * - * Note that hand off to another listener is *NOT* performed without this flag. Once - * :ref:`FilterChainMatch ` is implemented this flag - * will be removed, as filter chain matching can be used to select a filter chain based on the - * restored destination address. */ 'use_original_dst'?: (_google_protobuf_BoolValue); /** @@ -163,34 +146,34 @@ export interface Listener { /** * Listener metadata. */ - 'metadata'?: (_envoy_api_v2_core_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata); /** * [#not-implemented-hide:] */ - 'deprecated_v1'?: (_envoy_api_v2_Listener_DeprecatedV1); + 'deprecated_v1'?: (_envoy_config_listener_v3_Listener_DeprecatedV1); /** * The type of draining to perform at a listener-wide level. */ - 'drain_type'?: (_envoy_api_v2_Listener_DrainType | keyof typeof _envoy_api_v2_Listener_DrainType); + 'drain_type'?: (_envoy_config_listener_v3_Listener_DrainType | keyof typeof _envoy_config_listener_v3_Listener_DrainType); /** * Listener filters have the opportunity to manipulate and augment the connection metadata that * is used in connection filter chain matching, for example. These filters are run before any in - * :ref:`filter_chains `. Order matters as the + * :ref:`filter_chains `. Order matters as the * filters are processed sequentially right after a socket has been accepted by the listener, and * before a connection is created. * UDP Listener filters can be specified when the protocol in the listener socket address in - * :ref:`protocol ` is :ref:`UDP - * `. + * :ref:`protocol ` is :ref:`UDP + * `. * UDP listeners currently support a single filter. */ - 'listener_filters'?: (_envoy_api_v2_listener_ListenerFilter)[]; + 'listener_filters'?: (_envoy_config_listener_v3_ListenerFilter)[]; /** * Whether the listener should be set as a transparent socket. * When this flag is set to true, connections can be redirected to the listener using an * *iptables* *TPROXY* target, in which case the original source and destination addresses and * ports are preserved on accepted connections. This flag should be used in combination with * :ref:`an original_dst ` :ref:`listener filter - * ` to mark the connections' local addresses as + * ` to mark the connections' local addresses as * "restored." This can be used to hand off each redirected connection to another listener * associated with the connection's destination address. Direct connections to the socket without * using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are @@ -231,7 +214,7 @@ export interface Listener { * Additional socket options that may not be present in Envoy source code or * precompiled binaries. */ - 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; + 'socket_options'?: (_envoy_config_core_v3_SocketOption)[]; /** * The timeout to wait for all listener filters to complete operation. If the timeout is reached, * the accepted socket is closed without a connection being created unless @@ -242,7 +225,7 @@ export interface Listener { /** * Specifies the intended direction of the traffic relative to the local Envoy. */ - 'traffic_direction'?: (_envoy_api_v2_core_TrafficDirection | keyof typeof _envoy_api_v2_core_TrafficDirection); + 'traffic_direction'?: (_envoy_config_core_v3_TrafficDirection | keyof typeof _envoy_config_core_v3_TrafficDirection); /** * Whether a connection should be created when listener filters timeout. Default is false. * @@ -255,17 +238,17 @@ export interface Listener { 'continue_on_listener_filters_timeout'?: (boolean); /** * If the protocol in the listener socket address in :ref:`protocol - * ` is :ref:`UDP - * `, this field specifies the actual udp + * ` is :ref:`UDP + * `, this field specifies the actual udp * listener to create, i.e. :ref:`udp_listener_name - * ` = "raw_udp_listener" for + * ` = "raw_udp_listener" for * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". */ - 'udp_listener_config'?: (_envoy_api_v2_listener_UdpListenerConfig); + 'udp_listener_config'?: (_envoy_config_listener_v3_UdpListenerConfig); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. - * When this field is set, no other field except for :ref:`name` + * When this field is set, no other field except for :ref:`name` * should be set. * * .. note:: @@ -280,13 +263,13 @@ export interface Listener { * socket listener and the various types of API listener. That way, a given Listener message * can structurally only contain the fields of the relevant type.] */ - 'api_listener'?: (_envoy_config_listener_v2_ApiListener); + 'api_listener'?: (_envoy_config_listener_v3_ApiListener); /** * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. */ - 'connection_balance_config'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig); + 'connection_balance_config'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig); /** * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and * create one socket for each worker thread. This makes inbound connections @@ -304,11 +287,39 @@ export interface Listener { * Configuration for :ref:`access logs ` * emitted by this listener. */ - 'access_log'?: (_envoy_config_filter_accesslog_v2_AccessLog)[]; + 'access_log'?: (_envoy_config_accesslog_v3_AccessLog)[]; + /** + * If the protocol in the listener socket address in :ref:`protocol + * ` is :ref:`UDP + * `, this field specifies the actual udp + * writer to create, i.e. :ref:`name ` + * = "udp_default_writer" for creating a udp writer with writing in passthrough mode, + * = "udp_gso_batch_writer" for creating a udp writer with writing in batch mode. + * If not present, treat it as "udp_default_writer". + * [#not-implemented-hide:] + */ + 'udp_writer_config'?: (_envoy_config_core_v3_TypedExtensionConfig); + /** + * The maximum length a tcp listener's pending connections queue can grow to. If no value is + * provided net.core.somaxconn will be used on Linux and 128 otherwise. + */ + 'tcp_backlog_size'?: (_google_protobuf_UInt32Value); + /** + * The default filter chain if none of the filter chain matches. If no default filter chain is supplied, + * the connection will be closed. The filter chain match is ignored in this field. + */ + 'default_filter_chain'?: (_envoy_config_listener_v3_FilterChain); + /** + * Whether the listener should bind to the port. A listener that doesn't + * bind can only receive connections redirected from other listeners that set + * :ref:`use_original_dst ` + * to true. Default is true. + */ + 'bind_to_port'?: (_google_protobuf_BoolValue); } /** - * [#next-free-field: 23] + * [#next-free-field: 27] */ export interface Listener__Output { /** @@ -322,33 +333,23 @@ export interface Listener__Output { * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on * Linux as the actual port will be allocated by the OS. */ - 'address'?: (_envoy_api_v2_core_Address__Output); + 'address'?: (_envoy_config_core_v3_Address__Output); /** * A list of filter chains to consider for this listener. The - * :ref:`FilterChain ` with the most specific - * :ref:`FilterChainMatch ` criteria is used on a + * :ref:`FilterChain ` with the most specific + * :ref:`FilterChainMatch ` criteria is used on a * connection. * * Example using SNI for filter chain selection can be found in the * :ref:`FAQ entry `. */ - 'filter_chains': (_envoy_api_v2_listener_FilterChain__Output)[]; + 'filter_chains': (_envoy_config_listener_v3_FilterChain__Output)[]; /** * If a connection is redirected using *iptables*, the port on which the proxy * receives it might be different from the original destination address. When this flag is set to * true, the listener hands off redirected connections to the listener associated with the * original destination address. If there is no listener associated with the original destination * address, the connection is handled by the listener that receives it. Defaults to false. - * - * .. attention:: - * - * This field is deprecated. Use :ref:`an original_dst ` - * :ref:`listener filter ` instead. - * - * Note that hand off to another listener is *NOT* performed without this flag. Once - * :ref:`FilterChainMatch ` is implemented this flag - * will be removed, as filter chain matching can be used to select a filter chain based on the - * restored destination address. */ 'use_original_dst'?: (_google_protobuf_BoolValue__Output); /** @@ -359,34 +360,34 @@ export interface Listener__Output { /** * Listener metadata. */ - 'metadata'?: (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_config_core_v3_Metadata__Output); /** * [#not-implemented-hide:] */ - 'deprecated_v1'?: (_envoy_api_v2_Listener_DeprecatedV1__Output); + 'deprecated_v1'?: (_envoy_config_listener_v3_Listener_DeprecatedV1__Output); /** * The type of draining to perform at a listener-wide level. */ - 'drain_type': (keyof typeof _envoy_api_v2_Listener_DrainType); + 'drain_type': (keyof typeof _envoy_config_listener_v3_Listener_DrainType); /** * Listener filters have the opportunity to manipulate and augment the connection metadata that * is used in connection filter chain matching, for example. These filters are run before any in - * :ref:`filter_chains `. Order matters as the + * :ref:`filter_chains `. Order matters as the * filters are processed sequentially right after a socket has been accepted by the listener, and * before a connection is created. * UDP Listener filters can be specified when the protocol in the listener socket address in - * :ref:`protocol ` is :ref:`UDP - * `. + * :ref:`protocol ` is :ref:`UDP + * `. * UDP listeners currently support a single filter. */ - 'listener_filters': (_envoy_api_v2_listener_ListenerFilter__Output)[]; + 'listener_filters': (_envoy_config_listener_v3_ListenerFilter__Output)[]; /** * Whether the listener should be set as a transparent socket. * When this flag is set to true, connections can be redirected to the listener using an * *iptables* *TPROXY* target, in which case the original source and destination addresses and * ports are preserved on accepted connections. This flag should be used in combination with * :ref:`an original_dst ` :ref:`listener filter - * ` to mark the connections' local addresses as + * ` to mark the connections' local addresses as * "restored." This can be used to hand off each redirected connection to another listener * associated with the connection's destination address. Direct connections to the socket without * using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are @@ -427,7 +428,7 @@ export interface Listener__Output { * Additional socket options that may not be present in Envoy source code or * precompiled binaries. */ - 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; + 'socket_options': (_envoy_config_core_v3_SocketOption__Output)[]; /** * The timeout to wait for all listener filters to complete operation. If the timeout is reached, * the accepted socket is closed without a connection being created unless @@ -438,7 +439,7 @@ export interface Listener__Output { /** * Specifies the intended direction of the traffic relative to the local Envoy. */ - 'traffic_direction': (keyof typeof _envoy_api_v2_core_TrafficDirection); + 'traffic_direction': (keyof typeof _envoy_config_core_v3_TrafficDirection); /** * Whether a connection should be created when listener filters timeout. Default is false. * @@ -451,17 +452,17 @@ export interface Listener__Output { 'continue_on_listener_filters_timeout': (boolean); /** * If the protocol in the listener socket address in :ref:`protocol - * ` is :ref:`UDP - * `, this field specifies the actual udp + * ` is :ref:`UDP + * `, this field specifies the actual udp * listener to create, i.e. :ref:`udp_listener_name - * ` = "raw_udp_listener" for + * ` = "raw_udp_listener" for * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". */ - 'udp_listener_config'?: (_envoy_api_v2_listener_UdpListenerConfig__Output); + 'udp_listener_config'?: (_envoy_config_listener_v3_UdpListenerConfig__Output); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. - * When this field is set, no other field except for :ref:`name` + * When this field is set, no other field except for :ref:`name` * should be set. * * .. note:: @@ -476,13 +477,13 @@ export interface Listener__Output { * socket listener and the various types of API listener. That way, a given Listener message * can structurally only contain the fields of the relevant type.] */ - 'api_listener'?: (_envoy_config_listener_v2_ApiListener__Output); + 'api_listener'?: (_envoy_config_listener_v3_ApiListener__Output); /** * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. */ - 'connection_balance_config'?: (_envoy_api_v2_Listener_ConnectionBalanceConfig__Output); + 'connection_balance_config'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig__Output); /** * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and * create one socket for each worker thread. This makes inbound connections @@ -500,5 +501,33 @@ export interface Listener__Output { * Configuration for :ref:`access logs ` * emitted by this listener. */ - 'access_log': (_envoy_config_filter_accesslog_v2_AccessLog__Output)[]; + 'access_log': (_envoy_config_accesslog_v3_AccessLog__Output)[]; + /** + * If the protocol in the listener socket address in :ref:`protocol + * ` is :ref:`UDP + * `, this field specifies the actual udp + * writer to create, i.e. :ref:`name ` + * = "udp_default_writer" for creating a udp writer with writing in passthrough mode, + * = "udp_gso_batch_writer" for creating a udp writer with writing in batch mode. + * If not present, treat it as "udp_default_writer". + * [#not-implemented-hide:] + */ + 'udp_writer_config'?: (_envoy_config_core_v3_TypedExtensionConfig__Output); + /** + * The maximum length a tcp listener's pending connections queue can grow to. If no value is + * provided net.core.somaxconn will be used on Linux and 128 otherwise. + */ + 'tcp_backlog_size'?: (_google_protobuf_UInt32Value__Output); + /** + * The default filter chain if none of the filter chain matches. If no default filter chain is supplied, + * the connection will be closed. The filter chain match is ignored in this field. + */ + 'default_filter_chain'?: (_envoy_config_listener_v3_FilterChain__Output); + /** + * Whether the listener should bind to the port. A listener that doesn't + * bind can only receive connections redirected from other listeners that set + * :ref:`use_original_dst ` + * to true. Default is true. + */ + 'bind_to_port'?: (_google_protobuf_BoolValue__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerCollection.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerCollection.ts new file mode 100644 index 000000000..590ca8ed3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerCollection.ts @@ -0,0 +1,19 @@ +// Original file: deps/envoy-api/envoy/config/listener/v3/listener.proto + +import type { CollectionEntry as _xds_core_v3_CollectionEntry, CollectionEntry__Output as _xds_core_v3_CollectionEntry__Output } from '../../../../xds/core/v3/CollectionEntry'; + +/** + * Listener list collections. Entries are *Listener* resources or references. + * [#not-implemented-hide:] + */ +export interface ListenerCollection { + 'entries'?: (_xds_core_v3_CollectionEntry)[]; +} + +/** + * Listener list collections. Entries are *Listener* resources or references. + * [#not-implemented-hide:] + */ +export interface ListenerCollection__Output { + 'entries': (_xds_core_v3_CollectionEntry__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts similarity index 58% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts index 080d922b1..e8a827618 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts @@ -1,8 +1,7 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/listener_components.proto -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import type { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; +import type { ListenerFilterChainMatchPredicate as _envoy_config_listener_v3_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/config/listener/v3/ListenerFilterChainMatchPredicate'; export interface ListenerFilter { /** @@ -10,19 +9,18 @@ export interface ListenerFilter { * :ref:`supported filter `. */ 'name'?: (string); - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); /** * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. - * See :ref:`ListenerFilterChainMatchPredicate ` + * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ - 'filter_disabled'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate); + 'filter_disabled'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate); /** * Filter specific configuration which depends on the filter being instantiated. * See the supported filters for further documentation. */ - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } export interface ListenerFilter__Output { @@ -31,17 +29,16 @@ export interface ListenerFilter__Output { * :ref:`supported filter `. */ 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. - * See :ref:`ListenerFilterChainMatchPredicate ` + * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ - 'filter_disabled'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + 'filter_disabled'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output); /** * Filter specific configuration which depends on the filter being instantiated. * See the supported filters for further documentation. */ - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts similarity index 66% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts index ac3ddfd2a..e0d9ccc3e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/ListenerFilterChainMatchPredicate.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts @@ -1,26 +1,26 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/listener_components.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/listener_components.proto -import type { ListenerFilterChainMatchPredicate as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/api/v2/listener/ListenerFilterChainMatchPredicate'; -import type { Int32Range as _envoy_type_Int32Range, Int32Range__Output as _envoy_type_Int32Range__Output } from '../../../../envoy/type/Int32Range'; +import type { ListenerFilterChainMatchPredicate as _envoy_config_listener_v3_ListenerFilterChainMatchPredicate, ListenerFilterChainMatchPredicate__Output as _envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output } from '../../../../envoy/config/listener/v3/ListenerFilterChainMatchPredicate'; +import type { Int32Range as _envoy_type_v3_Int32Range, Int32Range__Output as _envoy_type_v3_Int32Range__Output } from '../../../../envoy/type/v3/Int32Range'; /** * A set of match configurations used for logical operations. */ -export interface _envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet { +export interface _envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet { /** * The list of rules that make up the set. */ - 'rules'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate)[]; + 'rules'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate)[]; } /** * A set of match configurations used for logical operations. */ -export interface _envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output { +export interface _envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output { /** * The list of rules that make up the set. */ - 'rules': (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output)[]; + 'rules': (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output)[]; } /** @@ -57,16 +57,16 @@ export interface ListenerFilterChainMatchPredicate { * A set that describes a logical OR. If any member of the set matches, the match configuration * matches. */ - 'or_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet); + 'or_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet); /** * A set that describes a logical AND. If all members of the set match, the match configuration * matches. */ - 'and_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet); + 'and_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet); /** * A negation match. The match configuration will match if the negated match condition matches. */ - 'not_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate); + 'not_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate); /** * The match configuration will always match. */ @@ -75,7 +75,7 @@ export interface ListenerFilterChainMatchPredicate { * Match destination port. Particularly, the match evaluation must use the recovered local port if * the owning listener filter is after :ref:`an original_dst listener filter `. */ - 'destination_port_range'?: (_envoy_type_Int32Range); + 'destination_port_range'?: (_envoy_type_v3_Int32Range); 'rule'?: "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; } @@ -113,16 +113,16 @@ export interface ListenerFilterChainMatchPredicate__Output { * A set that describes a logical OR. If any member of the set matches, the match configuration * matches. */ - 'or_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output); + 'or_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output); /** * A set that describes a logical AND. If all members of the set match, the match configuration * matches. */ - 'and_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate_MatchSet__Output); + 'and_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output); /** * A negation match. The match configuration will match if the negated match condition matches. */ - 'not_match'?: (_envoy_api_v2_listener_ListenerFilterChainMatchPredicate__Output); + 'not_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output); /** * The match configuration will always match. */ @@ -131,6 +131,6 @@ export interface ListenerFilterChainMatchPredicate__Output { * Match destination port. Particularly, the match evaluation must use the recovered local port if * the owning listener filter is after :ref:`an original_dst listener filter `. */ - 'destination_port_range'?: (_envoy_type_Int32Range__Output); + 'destination_port_range'?: (_envoy_type_v3_Int32Range__Output); 'rule': "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts similarity index 72% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts rename to packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts index 2299c5719..c7475c42b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/listener/UdpListenerConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts @@ -1,6 +1,5 @@ -// Original file: deps/envoy-api/envoy/api/v2/listener/udp_listener_config.proto +// Original file: deps/envoy-api/envoy/config/listener/v3/udp_listener_config.proto -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; export interface UdpListenerConfig { @@ -10,13 +9,12 @@ export interface UdpListenerConfig { * If not specified, treat as "raw_udp_listener". */ 'udp_listener_name'?: (string); - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); /** * Used to create a specific listener factory. To some factory, e.g. * "raw_udp_listener", config is not needed. */ - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } export interface UdpListenerConfig__Output { @@ -26,11 +24,10 @@ export interface UdpListenerConfig__Output { * If not specified, treat as "raw_udp_listener". */ 'udp_listener_name': (string); - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** * Used to create a specific listener factory. To some factory, e.g. * "raw_udp_listener", config is not needed. */ - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts similarity index 50% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts index 7b76b9d85..c292a199a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/CorsPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts @@ -1,22 +1,13 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; -import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../../envoy/type/matcher/StringMatcher'; +import type { RuntimeFractionalPercent as _envoy_config_core_v3_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_config_core_v3_RuntimeFractionalPercent__Output } from '../../../../envoy/config/core/v3/RuntimeFractionalPercent'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; /** * [#next-free-field: 12] */ export interface CorsPolicy { - /** - * Specifies the origins that will be allowed to do CORS requests. - * - * An origin is allowed if either allow_origin or allow_origin_regex match. - * - * .. attention:: - * This field has been deprecated in favor of `allow_origin_string_match`. - */ - 'allow_origin'?: (string)[]; /** * Specifies the content for the *access-control-allow-methods* header. */ @@ -37,35 +28,16 @@ export interface CorsPolicy { * Specifies whether the resource allows credentials. */ 'allow_credentials'?: (_google_protobuf_BoolValue); - /** - * Specifies if the CORS filter is enabled. Defaults to true. Only effective on route. - * - * .. attention:: - * - * **This field is deprecated**. Set the - * :ref:`filter_enabled` field instead. - */ - 'enabled'?: (_google_protobuf_BoolValue); - /** - * Specifies regex patterns that match allowed origins. - * - * An origin is allowed if either allow_origin or allow_origin_regex match. - * - * .. attention:: - * This field has been deprecated in favor of `allow_origin_string_match` as it is not safe for - * use with untrusted input in all cases. - */ - 'allow_origin_regex'?: (string)[]; /** * Specifies the % of requests for which the CORS filter is enabled. * * If neither ``enabled``, ``filter_enabled``, nor ``shadow_enabled`` are specified, the CORS * filter will be enabled for 100% of the requests. * - * If :ref:`runtime_key ` is + * If :ref:`runtime_key ` is * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. */ - 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent); /** * Specifies the % of requests for which the CORS policies will be evaluated and tracked, but not * enforced. @@ -73,32 +45,23 @@ export interface CorsPolicy { * This field is intended to be used when ``filter_enabled`` and ``enabled`` are off. One of those * fields have to explicitly disable the filter in order for this setting to take effect. * - * If :ref:`runtime_key ` is specified, + * If :ref:`runtime_key ` is specified, * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ - 'shadow_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'shadow_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent); /** * Specifies string patterns that match allowed origins. An origin is allowed if any of the * string matchers match. */ - 'allow_origin_string_match'?: (_envoy_type_matcher_StringMatcher)[]; - 'enabled_specifier'?: "enabled"|"filter_enabled"; + 'allow_origin_string_match'?: (_envoy_type_matcher_v3_StringMatcher)[]; + 'enabled_specifier'?: "filter_enabled"; } /** * [#next-free-field: 12] */ export interface CorsPolicy__Output { - /** - * Specifies the origins that will be allowed to do CORS requests. - * - * An origin is allowed if either allow_origin or allow_origin_regex match. - * - * .. attention:: - * This field has been deprecated in favor of `allow_origin_string_match`. - */ - 'allow_origin': (string)[]; /** * Specifies the content for the *access-control-allow-methods* header. */ @@ -119,35 +82,16 @@ export interface CorsPolicy__Output { * Specifies whether the resource allows credentials. */ 'allow_credentials'?: (_google_protobuf_BoolValue__Output); - /** - * Specifies if the CORS filter is enabled. Defaults to true. Only effective on route. - * - * .. attention:: - * - * **This field is deprecated**. Set the - * :ref:`filter_enabled` field instead. - */ - 'enabled'?: (_google_protobuf_BoolValue__Output); - /** - * Specifies regex patterns that match allowed origins. - * - * An origin is allowed if either allow_origin or allow_origin_regex match. - * - * .. attention:: - * This field has been deprecated in favor of `allow_origin_string_match` as it is not safe for - * use with untrusted input in all cases. - */ - 'allow_origin_regex': (string)[]; /** * Specifies the % of requests for which the CORS filter is enabled. * * If neither ``enabled``, ``filter_enabled``, nor ``shadow_enabled`` are specified, the CORS * filter will be enabled for 100% of the requests. * - * If :ref:`runtime_key ` is + * If :ref:`runtime_key ` is * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. */ - 'filter_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); /** * Specifies the % of requests for which the CORS policies will be evaluated and tracked, but not * enforced. @@ -155,15 +99,15 @@ export interface CorsPolicy__Output { * This field is intended to be used when ``filter_enabled`` and ``enabled`` are off. One of those * fields have to explicitly disable the filter in order for this setting to take effect. * - * If :ref:`runtime_key ` is specified, + * If :ref:`runtime_key ` is specified, * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ - 'shadow_enabled'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'shadow_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); /** * Specifies string patterns that match allowed origins. An origin is allowed if any of the * string matchers match. */ - 'allow_origin_string_match': (_envoy_type_matcher_StringMatcher__Output)[]; - 'enabled_specifier': "enabled"|"filter_enabled"; + 'allow_origin_string_match': (_envoy_type_matcher_v3_StringMatcher__Output)[]; + 'enabled_specifier': "filter_enabled"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts similarity index 94% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts index 68c91327d..00e37d98f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Decorator.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts similarity index 52% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts index 83777f9e3..9088fe712 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/DirectResponseAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts @@ -1,6 +1,6 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../envoy/config/core/v3/DataSource'; export interface DirectResponseAction { /** @@ -14,10 +14,10 @@ export interface DirectResponseAction { * .. note:: * * Headers can be specified using *response_headers_to_add* in the enclosing - * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or - * :ref:`envoy_api_msg_route.VirtualHost`. + * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` or + * :ref:`envoy_api_msg_config.route.v3.VirtualHost`. */ - 'body'?: (_envoy_api_v2_core_DataSource); + 'body'?: (_envoy_config_core_v3_DataSource); } export interface DirectResponseAction__Output { @@ -32,8 +32,8 @@ export interface DirectResponseAction__Output { * .. note:: * * Headers can be specified using *response_headers_to_add* in the enclosing - * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_RouteConfiguration` or - * :ref:`envoy_api_msg_route.VirtualHost`. + * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` or + * :ref:`envoy_api_msg_config.route.v3.VirtualHost`. */ - 'body'?: (_envoy_api_v2_core_DataSource__Output); + 'body'?: (_envoy_config_core_v3_DataSource__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts similarity index 82% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts index a41f3f417..78221b2c7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/FilterAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts new file mode 100644 index 000000000..ff5976e0b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts @@ -0,0 +1,47 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * A simple wrapper for an HTTP filter config. This is intended to be used as a wrapper for the + * map value in + * :ref:`VirtualHost.typed_per_filter_config`, + * :ref:`Route.typed_per_filter_config`, + * or :ref:`WeightedCluster.ClusterWeight.typed_per_filter_config` + * to add additional flags to the filter. + * [#not-implemented-hide:] + */ +export interface FilterConfig { + /** + * The filter config. + */ + 'config'?: (_google_protobuf_Any); + /** + * If true, the filter is optional, meaning that if the client does + * not support the specified filter, it may ignore the map entry rather + * than rejecting the config. + */ + 'is_optional'?: (boolean); +} + +/** + * A simple wrapper for an HTTP filter config. This is intended to be used as a wrapper for the + * map value in + * :ref:`VirtualHost.typed_per_filter_config`, + * :ref:`Route.typed_per_filter_config`, + * or :ref:`WeightedCluster.ClusterWeight.typed_per_filter_config` + * to add additional flags to the filter. + * [#not-implemented-hide:] + */ +export interface FilterConfig__Output { + /** + * The filter config. + */ + 'config'?: (_google_protobuf_Any__Output); + /** + * If true, the filter is optional, meaning that if the client does + * not support the specified filter, it may ignore the map entry rather + * than rejecting the config. + */ + 'is_optional': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts similarity index 69% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts index 347849901..8d20c5c63 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/HeaderMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts @@ -1,7 +1,7 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { Int64Range as _envoy_type_Int64Range, Int64Range__Output as _envoy_type_Int64Range__Output } from '../../../../envoy/type/Int64Range'; -import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; +import type { Int64Range as _envoy_type_v3_Int64Range, Int64Range__Output as _envoy_type_v3_Int64Range__Output } from '../../../../envoy/type/v3/Int64Range'; +import type { RegexMatcher as _envoy_type_matcher_v3_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_v3_RegexMatcher__Output } from '../../../../envoy/type/matcher/v3/RegexMatcher'; import type { Long } from '@grpc/proto-loader'; /** @@ -24,12 +24,12 @@ import type { Long } from '@grpc/proto-loader'; * * .. attention:: * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's * value. * * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface HeaderMatcher { /** @@ -40,23 +40,6 @@ export interface HeaderMatcher { * If specified, header match will be performed based on the value of the header. */ 'exact_match'?: (string); - /** - * If specified, this regex string is a regular expression rule which implies the entire request - * header value must match the regex. The rule will not match if only a subsequence of the - * request header value matches the regex. The regex grammar used in the value field is defined - * `here `_. - * - * Examples: - * - * * The regex ``\d{3}`` matches the value *123* - * * The regex ``\d{3}`` does not match the value *1234* - * * The regex ``\d{3}`` does not match the value *123.456* - * - * .. attention:: - * This field has been deprecated in favor of `safe_regex_match` as it is not safe for use - * with untrusted input in all cases. - */ - 'regex_match'?: (string); /** * If specified, header match will be performed based on range. * The rule will match if the request header value is within this range. @@ -70,7 +53,7 @@ export interface HeaderMatcher { * * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, * "-1somestring" */ - 'range_match'?: (_envoy_type_Int64Range); + 'range_match'?: (_envoy_type_v3_Int64Range); /** * If specified, header match will be performed based on whether the header is in the * request. @@ -108,11 +91,21 @@ export interface HeaderMatcher { * header value must match the regex. The rule will not match if only a subsequence of the * request header value matches the regex. */ - 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher); + 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher); + /** + * If specified, header match will be performed based on whether the header value contains + * the given value or not. + * Note: empty contains match is not allowed, please use present_match instead. + * + * Examples: + * + * * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. + */ + 'contains_match'?: (string); /** * Specifies how the header match will be performed to route the request. */ - 'header_match_specifier'?: "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; + 'header_match_specifier'?: "exact_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"|"contains_match"; } /** @@ -135,12 +128,12 @@ export interface HeaderMatcher { * * .. attention:: * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's * value. * * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface HeaderMatcher__Output { /** @@ -151,23 +144,6 @@ export interface HeaderMatcher__Output { * If specified, header match will be performed based on the value of the header. */ 'exact_match'?: (string); - /** - * If specified, this regex string is a regular expression rule which implies the entire request - * header value must match the regex. The rule will not match if only a subsequence of the - * request header value matches the regex. The regex grammar used in the value field is defined - * `here `_. - * - * Examples: - * - * * The regex ``\d{3}`` matches the value *123* - * * The regex ``\d{3}`` does not match the value *1234* - * * The regex ``\d{3}`` does not match the value *123.456* - * - * .. attention:: - * This field has been deprecated in favor of `safe_regex_match` as it is not safe for use - * with untrusted input in all cases. - */ - 'regex_match'?: (string); /** * If specified, header match will be performed based on range. * The rule will match if the request header value is within this range. @@ -181,7 +157,7 @@ export interface HeaderMatcher__Output { * * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, * "-1somestring" */ - 'range_match'?: (_envoy_type_Int64Range__Output); + 'range_match'?: (_envoy_type_v3_Int64Range__Output); /** * If specified, header match will be performed based on whether the header is in the * request. @@ -219,9 +195,19 @@ export interface HeaderMatcher__Output { * header value must match the regex. The rule will not match if only a subsequence of the * request header value matches the regex. */ - 'safe_regex_match'?: (_envoy_type_matcher_RegexMatcher__Output); + 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher__Output); + /** + * If specified, header match will be performed based on whether the header value contains + * the given value or not. + * Note: empty contains match is not allowed, please use present_match instead. + * + * Examples: + * + * * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. + */ + 'contains_match'?: (string); /** * Specifies how the header match will be performed to route the request. */ - 'header_match_specifier': "exact_match"|"regex_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"; + 'header_match_specifier': "exact_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"|"contains_match"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts new file mode 100644 index 000000000..344d825e7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts @@ -0,0 +1,76 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../envoy/type/v3/FractionalPercent'; + +/** + * HTTP request hedging :ref:`architecture overview `. + */ +export interface HedgePolicy { + /** + * Specifies the number of initial requests that should be sent upstream. + * Must be at least 1. + * Defaults to 1. + * [#not-implemented-hide:] + */ + 'initial_requests'?: (_google_protobuf_UInt32Value); + /** + * Specifies a probability that an additional upstream request should be sent + * on top of what is specified by initial_requests. + * Defaults to 0. + * [#not-implemented-hide:] + */ + 'additional_request_chance'?: (_envoy_type_v3_FractionalPercent); + /** + * Indicates that a hedged request should be sent when the per-try timeout is hit. + * This means that a retry will be issued without resetting the original request, leaving multiple upstream requests in flight. + * The first request to complete successfully will be the one returned to the caller. + * + * * At any time, a successful response (i.e. not triggering any of the retry-on conditions) would be returned to the client. + * * Before per-try timeout, an error response (per retry-on conditions) would be retried immediately or returned ot the client + * if there are no more retries left. + * * After per-try timeout, an error response would be discarded, as a retry in the form of a hedged request is already in progress. + * + * Note: For this to have effect, you must have a :ref:`RetryPolicy ` that retries at least + * one error code and specifies a maximum number of retries. + * + * Defaults to false. + */ + 'hedge_on_per_try_timeout'?: (boolean); +} + +/** + * HTTP request hedging :ref:`architecture overview `. + */ +export interface HedgePolicy__Output { + /** + * Specifies the number of initial requests that should be sent upstream. + * Must be at least 1. + * Defaults to 1. + * [#not-implemented-hide:] + */ + 'initial_requests'?: (_google_protobuf_UInt32Value__Output); + /** + * Specifies a probability that an additional upstream request should be sent + * on top of what is specified by initial_requests. + * Defaults to 0. + * [#not-implemented-hide:] + */ + 'additional_request_chance'?: (_envoy_type_v3_FractionalPercent__Output); + /** + * Indicates that a hedged request should be sent when the per-try timeout is hit. + * This means that a retry will be issued without resetting the original request, leaving multiple upstream requests in flight. + * The first request to complete successfully will be the one returned to the caller. + * + * * At any time, a successful response (i.e. not triggering any of the retry-on conditions) would be returned to the client. + * * Before per-try timeout, an error response (per retry-on conditions) would be retried immediately or returned ot the client + * if there are no more retries left. + * * After per-try timeout, an error response would be discarded, as a retry in the form of a hedged request is already in progress. + * + * Note: For this to have effect, you must have a :ref:`RetryPolicy ` that retries at least + * one error code and specifies a maximum number of retries. + * + * Defaults to false. + */ + 'hedge_on_per_try_timeout': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts new file mode 100644 index 000000000..73a2bb32e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts @@ -0,0 +1,72 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * HTTP Internal Redirect :ref:`architecture overview `. + */ +export interface InternalRedirectPolicy { + /** + * An internal redirect is not handled, unless the number of previous internal redirects that a + * downstream request has encountered is lower than this value. + * In the case where a downstream request is bounced among multiple routes by internal redirect, + * the first route that hits this threshold, or does not set :ref:`internal_redirect_policy + * ` + * will pass the redirect back to downstream. + * + * If not specified, at most one redirect will be followed. + */ + 'max_internal_redirects'?: (_google_protobuf_UInt32Value); + /** + * Defines what upstream response codes are allowed to trigger internal redirect. If unspecified, + * only 302 will be treated as internal redirect. + * Only 301, 302, 303, 307 and 308 are valid values. Any other codes will be ignored. + */ + 'redirect_response_codes'?: (number)[]; + /** + * Specifies a list of predicates that are queried when an upstream response is deemed + * to trigger an internal redirect by all other criteria. Any predicate in the list can reject + * the redirect, causing the response to be proxied to downstream. + */ + 'predicates'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; + /** + * Allow internal redirect to follow a target URI with a different scheme than the value of + * x-forwarded-proto. The default is false. + */ + 'allow_cross_scheme_redirect'?: (boolean); +} + +/** + * HTTP Internal Redirect :ref:`architecture overview `. + */ +export interface InternalRedirectPolicy__Output { + /** + * An internal redirect is not handled, unless the number of previous internal redirects that a + * downstream request has encountered is lower than this value. + * In the case where a downstream request is bounced among multiple routes by internal redirect, + * the first route that hits this threshold, or does not set :ref:`internal_redirect_policy + * ` + * will pass the redirect back to downstream. + * + * If not specified, at most one redirect will be followed. + */ + 'max_internal_redirects'?: (_google_protobuf_UInt32Value__Output); + /** + * Defines what upstream response codes are allowed to trigger internal redirect. If unspecified, + * only 302 will be treated as internal redirect. + * Only 301, 302, 303, 307 and 308 are valid values. Any other codes will be ignored. + */ + 'redirect_response_codes': (number)[]; + /** + * Specifies a list of predicates that are queried when an upstream response is deemed + * to trigger an internal redirect by all other criteria. Any predicate in the list can reject + * the redirect, causing the response to be proxied to downstream. + */ + 'predicates': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; + /** + * Allow internal redirect to follow a target URI with a different scheme than the value of + * x-forwarded-proto. The default is false. + */ + 'allow_cross_scheme_redirect': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts new file mode 100644 index 000000000..c88fa8ff7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts @@ -0,0 +1,47 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; + +/** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ +export interface QueryParameterMatcher { + /** + * Specifies the name of a key that must be present in the requested + * *path*'s query string. + */ + 'name'?: (string); + /** + * Specifies whether a query parameter value should match against a string. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher); + /** + * Specifies whether a query parameter should be present. + */ + 'present_match'?: (boolean); + 'query_parameter_match_specifier'?: "string_match"|"present_match"; +} + +/** + * Query parameter matching treats the query string of a request's :path header + * as an ampersand-separated list of keys and/or key=value elements. + * [#next-free-field: 7] + */ +export interface QueryParameterMatcher__Output { + /** + * Specifies the name of a key that must be present in the requested + * *path*'s query string. + */ + 'name': (string); + /** + * Specifies whether a query parameter value should match against a string. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output); + /** + * Specifies whether a query parameter should be present. + */ + 'present_match'?: (boolean); + 'query_parameter_match_specifier': "string_match"|"present_match"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts new file mode 100644 index 000000000..33d93af7d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts @@ -0,0 +1,578 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; +import type { MetadataKey as _envoy_type_metadata_v3_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v3_MetadataKey__Output } from '../../../../envoy/type/metadata/v3/MetadataKey'; + +/** + * [#next-free-field: 10] + */ +export interface _envoy_config_route_v3_RateLimit_Action { + /** + * Rate limit on source cluster. + */ + 'source_cluster'?: (_envoy_config_route_v3_RateLimit_Action_SourceCluster); + /** + * Rate limit on destination cluster. + */ + 'destination_cluster'?: (_envoy_config_route_v3_RateLimit_Action_DestinationCluster); + /** + * Rate limit on request headers. + */ + 'request_headers'?: (_envoy_config_route_v3_RateLimit_Action_RequestHeaders); + /** + * Rate limit on remote address. + */ + 'remote_address'?: (_envoy_config_route_v3_RateLimit_Action_RemoteAddress); + /** + * Rate limit on a generic key. + */ + 'generic_key'?: (_envoy_config_route_v3_RateLimit_Action_GenericKey); + /** + * Rate limit on the existence of request headers. + */ + 'header_value_match'?: (_envoy_config_route_v3_RateLimit_Action_HeaderValueMatch); + /** + * Rate limit on dynamic metadata. + * + * .. attention:: + * This field has been deprecated in favor of the :ref:`metadata ` field + */ + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData); + /** + * Rate limit on metadata. + */ + 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData); + /** + * Rate limit descriptor extension. See the rate limit descriptor extensions documentation. + */ + 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig); + 'action_specifier'?: "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"|"dynamic_metadata"|"metadata"|"extension"; +} + +/** + * [#next-free-field: 10] + */ +export interface _envoy_config_route_v3_RateLimit_Action__Output { + /** + * Rate limit on source cluster. + */ + 'source_cluster'?: (_envoy_config_route_v3_RateLimit_Action_SourceCluster__Output); + /** + * Rate limit on destination cluster. + */ + 'destination_cluster'?: (_envoy_config_route_v3_RateLimit_Action_DestinationCluster__Output); + /** + * Rate limit on request headers. + */ + 'request_headers'?: (_envoy_config_route_v3_RateLimit_Action_RequestHeaders__Output); + /** + * Rate limit on remote address. + */ + 'remote_address'?: (_envoy_config_route_v3_RateLimit_Action_RemoteAddress__Output); + /** + * Rate limit on a generic key. + */ + 'generic_key'?: (_envoy_config_route_v3_RateLimit_Action_GenericKey__Output); + /** + * Rate limit on the existence of request headers. + */ + 'header_value_match'?: (_envoy_config_route_v3_RateLimit_Action_HeaderValueMatch__Output); + /** + * Rate limit on dynamic metadata. + * + * .. attention:: + * This field has been deprecated in favor of the :ref:`metadata ` field + */ + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output); + /** + * Rate limit on metadata. + */ + 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData__Output); + /** + * Rate limit descriptor extension. See the rate limit descriptor extensions documentation. + */ + 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig__Output); + 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"|"dynamic_metadata"|"metadata"|"extension"; +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("destination_cluster", "") + * + * Once a request matches against a route table rule, a routed cluster is determined by one of + * the following :ref:`route table configuration ` + * settings: + * + * * :ref:`cluster ` indicates the upstream cluster + * to route to. + * * :ref:`weighted_clusters ` + * chooses a cluster randomly from a set of clusters with attributed weight. + * * :ref:`cluster_header ` indicates which + * header in the request contains the target cluster. + */ +export interface _envoy_config_route_v3_RateLimit_Action_DestinationCluster { +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("destination_cluster", "") + * + * Once a request matches against a route table rule, a routed cluster is determined by one of + * the following :ref:`route table configuration ` + * settings: + * + * * :ref:`cluster ` indicates the upstream cluster + * to route to. + * * :ref:`weighted_clusters ` + * chooses a cluster randomly from a set of clusters with attributed weight. + * * :ref:`cluster_header ` indicates which + * header in the request contains the target cluster. + */ +export interface _envoy_config_route_v3_RateLimit_Action_DestinationCluster__Output { +} + +/** + * The following descriptor entry is appended when the + * :ref:`dynamic metadata ` contains a key value: + * + * .. code-block:: cpp + * + * ("", "") + * + * .. attention:: + * This action has been deprecated in favor of the :ref:`metadata ` action + */ +export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData { + /** + * The key to use in the descriptor entry. + */ + 'descriptor_key'?: (string); + /** + * Metadata struct that defines the key and path to retrieve the string value. A match will + * only happen if the value in the dynamic metadata is of type string. + */ + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); + /** + * An optional value to use if *metadata_key* is empty. If not set and + * no value is present under the metadata_key then no descriptor is generated. + */ + 'default_value'?: (string); +} + +/** + * The following descriptor entry is appended when the + * :ref:`dynamic metadata ` contains a key value: + * + * .. code-block:: cpp + * + * ("", "") + * + * .. attention:: + * This action has been deprecated in favor of the :ref:`metadata ` action + */ +export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output { + /** + * The key to use in the descriptor entry. + */ + 'descriptor_key': (string); + /** + * Metadata struct that defines the key and path to retrieve the string value. A match will + * only happen if the value in the dynamic metadata is of type string. + */ + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); + /** + * An optional value to use if *metadata_key* is empty. If not set and + * no value is present under the metadata_key then no descriptor is generated. + */ + 'default_value': (string); +} + +/** + * Fetches the override from the dynamic metadata. + */ +export interface _envoy_config_route_v3_RateLimit_Override_DynamicMetadata { + /** + * Metadata struct that defines the key and path to retrieve the struct value. + * The value must be a struct containing an integer "requests_per_unit" property + * and a "unit" property with a value parseable to :ref:`RateLimitUnit + * enum ` + */ + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); +} + +/** + * Fetches the override from the dynamic metadata. + */ +export interface _envoy_config_route_v3_RateLimit_Override_DynamicMetadata__Output { + /** + * Metadata struct that defines the key and path to retrieve the struct value. + * The value must be a struct containing an integer "requests_per_unit" property + * and a "unit" property with a value parseable to :ref:`RateLimitUnit + * enum ` + */ + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("generic_key", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_GenericKey { + /** + * The value to use in the descriptor entry. + */ + 'descriptor_value'?: (string); + /** + * An optional key to use in the descriptor entry. If not set it defaults + * to 'generic_key' as the descriptor key. + */ + 'descriptor_key'?: (string); +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("generic_key", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_GenericKey__Output { + /** + * The value to use in the descriptor entry. + */ + 'descriptor_value': (string); + /** + * An optional key to use in the descriptor entry. If not set it defaults + * to 'generic_key' as the descriptor key. + */ + 'descriptor_key': (string); +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("header_match", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_HeaderValueMatch { + /** + * The value to use in the descriptor entry. + */ + 'descriptor_value'?: (string); + /** + * If set to true, the action will append a descriptor entry when the + * request matches the headers. If set to false, the action will append a + * descriptor entry when the request does not match the headers. The + * default value is true. + */ + 'expect_match'?: (_google_protobuf_BoolValue); + /** + * Specifies a set of headers that the rate limit action should match + * on. The action will check the request’s headers against all the + * specified headers in the config. A match will happen if all the + * headers in the config are present in the request with the same values + * (or based on presence if the value field is not in the config). + */ + 'headers'?: (_envoy_config_route_v3_HeaderMatcher)[]; +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("header_match", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_HeaderValueMatch__Output { + /** + * The value to use in the descriptor entry. + */ + 'descriptor_value': (string); + /** + * If set to true, the action will append a descriptor entry when the + * request matches the headers. If set to false, the action will append a + * descriptor entry when the request does not match the headers. The + * default value is true. + */ + 'expect_match'?: (_google_protobuf_BoolValue__Output); + /** + * Specifies a set of headers that the rate limit action should match + * on. The action will check the request’s headers against all the + * specified headers in the config. A match will happen if all the + * headers in the config are present in the request with the same values + * (or based on presence if the value field is not in the config). + */ + 'headers': (_envoy_config_route_v3_HeaderMatcher__Output)[]; +} + +/** + * The following descriptor entry is appended when the metadata contains a key value: + * + * .. code-block:: cpp + * + * ("", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_MetaData { + /** + * The key to use in the descriptor entry. + */ + 'descriptor_key'?: (string); + /** + * Metadata struct that defines the key and path to retrieve the string value. A match will + * only happen if the value in the metadata is of type string. + */ + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); + /** + * An optional value to use if *metadata_key* is empty. If not set and + * no value is present under the metadata_key then no descriptor is generated. + */ + 'default_value'?: (string); + /** + * Source of metadata + */ + 'source'?: (_envoy_config_route_v3_RateLimit_Action_MetaData_Source | keyof typeof _envoy_config_route_v3_RateLimit_Action_MetaData_Source); +} + +/** + * The following descriptor entry is appended when the metadata contains a key value: + * + * .. code-block:: cpp + * + * ("", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_MetaData__Output { + /** + * The key to use in the descriptor entry. + */ + 'descriptor_key': (string); + /** + * Metadata struct that defines the key and path to retrieve the string value. A match will + * only happen if the value in the metadata is of type string. + */ + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); + /** + * An optional value to use if *metadata_key* is empty. If not set and + * no value is present under the metadata_key then no descriptor is generated. + */ + 'default_value': (string); + /** + * Source of metadata + */ + 'source': (keyof typeof _envoy_config_route_v3_RateLimit_Action_MetaData_Source); +} + +export interface _envoy_config_route_v3_RateLimit_Override { + /** + * Limit override from dynamic metadata. + */ + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Override_DynamicMetadata); + 'override_specifier'?: "dynamic_metadata"; +} + +export interface _envoy_config_route_v3_RateLimit_Override__Output { + /** + * Limit override from dynamic metadata. + */ + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Override_DynamicMetadata__Output); + 'override_specifier': "dynamic_metadata"; +} + +/** + * The following descriptor entry is appended to the descriptor and is populated using the + * trusted address from :ref:`x-forwarded-for `: + * + * .. code-block:: cpp + * + * ("remote_address", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_RemoteAddress { +} + +/** + * The following descriptor entry is appended to the descriptor and is populated using the + * trusted address from :ref:`x-forwarded-for `: + * + * .. code-block:: cpp + * + * ("remote_address", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_RemoteAddress__Output { +} + +/** + * The following descriptor entry is appended when a header contains a key that matches the + * *header_name*: + * + * .. code-block:: cpp + * + * ("", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_RequestHeaders { + /** + * The header name to be queried from the request headers. The header’s + * value is used to populate the value of the descriptor entry for the + * descriptor_key. + */ + 'header_name'?: (string); + /** + * The key to use in the descriptor entry. + */ + 'descriptor_key'?: (string); + /** + * If set to true, Envoy skips the descriptor while calling rate limiting service + * when header is not present in the request. By default it skips calling the + * rate limiting service if this header is not present in the request. + */ + 'skip_if_absent'?: (boolean); +} + +/** + * The following descriptor entry is appended when a header contains a key that matches the + * *header_name*: + * + * .. code-block:: cpp + * + * ("", "") + */ +export interface _envoy_config_route_v3_RateLimit_Action_RequestHeaders__Output { + /** + * The header name to be queried from the request headers. The header’s + * value is used to populate the value of the descriptor entry for the + * descriptor_key. + */ + 'header_name': (string); + /** + * The key to use in the descriptor entry. + */ + 'descriptor_key': (string); + /** + * If set to true, Envoy skips the descriptor while calling rate limiting service + * when header is not present in the request. By default it skips calling the + * rate limiting service if this header is not present in the request. + */ + 'skip_if_absent': (boolean); +} + +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +export enum _envoy_config_route_v3_RateLimit_Action_MetaData_Source { + /** + * Query :ref:`dynamic metadata ` + */ + DYNAMIC = 0, + /** + * Query :ref:`route entry metadata ` + */ + ROUTE_ENTRY = 1, +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("source_cluster", "") + * + * is derived from the :option:`--service-cluster` option. + */ +export interface _envoy_config_route_v3_RateLimit_Action_SourceCluster { +} + +/** + * The following descriptor entry is appended to the descriptor: + * + * .. code-block:: cpp + * + * ("source_cluster", "") + * + * is derived from the :option:`--service-cluster` option. + */ +export interface _envoy_config_route_v3_RateLimit_Action_SourceCluster__Output { +} + +/** + * Global rate limiting :ref:`architecture overview `. + * Also applies to Local rate limiting :ref:`using descriptors `. + */ +export interface RateLimit { + /** + * Refers to the stage set in the filter. The rate limit configuration only + * applies to filters with the same stage number. The default stage number is + * 0. + * + * .. note:: + * + * The filter supports a range of 0 - 10 inclusively for stage numbers. + */ + 'stage'?: (_google_protobuf_UInt32Value); + /** + * The key to be set in runtime to disable this rate limit configuration. + */ + 'disable_key'?: (string); + /** + * A list of actions that are to be applied for this rate limit configuration. + * Order matters as the actions are processed sequentially and the descriptor + * is composed by appending descriptor entries in that sequence. If an action + * cannot append a descriptor entry, no descriptor is generated for the + * configuration. See :ref:`composing actions + * ` for additional documentation. + */ + 'actions'?: (_envoy_config_route_v3_RateLimit_Action)[]; + /** + * An optional limit override to be appended to the descriptor produced by this + * rate limit configuration. If the override value is invalid or cannot be resolved + * from metadata, no override is provided. See :ref:`rate limit override + * ` for more information. + */ + 'limit'?: (_envoy_config_route_v3_RateLimit_Override); +} + +/** + * Global rate limiting :ref:`architecture overview `. + * Also applies to Local rate limiting :ref:`using descriptors `. + */ +export interface RateLimit__Output { + /** + * Refers to the stage set in the filter. The rate limit configuration only + * applies to filters with the same stage number. The default stage number is + * 0. + * + * .. note:: + * + * The filter supports a range of 0 - 10 inclusively for stage numbers. + */ + 'stage'?: (_google_protobuf_UInt32Value__Output); + /** + * The key to be set in runtime to disable this rate limit configuration. + */ + 'disable_key': (string); + /** + * A list of actions that are to be applied for this rate limit configuration. + * Order matters as the actions are processed sequentially and the descriptor + * is composed by appending descriptor entries in that sequence. If an action + * cannot append a descriptor entry, no descriptor is generated for the + * configuration. See :ref:`composing actions + * ` for additional documentation. + */ + 'actions': (_envoy_config_route_v3_RateLimit_Action__Output)[]; + /** + * An optional limit override to be appended to the descriptor produced by this + * rate limit configuration. If the override value is invalid or cannot be resolved + * from metadata, no override is provided. See :ref:`rate limit override + * ` for more information. + */ + 'limit'?: (_envoy_config_route_v3_RateLimit_Override__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts new file mode 100644 index 000000000..baea6bc4e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts @@ -0,0 +1,222 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { RegexMatchAndSubstitute as _envoy_type_matcher_v3_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_v3_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/v3/RegexMatchAndSubstitute'; + +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +export enum _envoy_config_route_v3_RedirectAction_RedirectResponseCode { + /** + * Moved Permanently HTTP Status Code - 301. + */ + MOVED_PERMANENTLY = 0, + /** + * Found HTTP Status Code - 302. + */ + FOUND = 1, + /** + * See Other HTTP Status Code - 303. + */ + SEE_OTHER = 2, + /** + * Temporary Redirect HTTP Status Code - 307. + */ + TEMPORARY_REDIRECT = 3, + /** + * Permanent Redirect HTTP Status Code - 308. + */ + PERMANENT_REDIRECT = 4, +} + +/** + * [#next-free-field: 10] + */ +export interface RedirectAction { + /** + * The host portion of the URL will be swapped with this value. + */ + 'host_redirect'?: (string); + /** + * The path portion of the URL will be swapped with this value. + * Please note that query string in path_redirect will override the + * request's query string and will not be stripped. + * + * For example, let's say we have the following routes: + * + * - match: { path: "/old-path-1" } + * redirect: { path_redirect: "/new-path-1" } + * - match: { path: "/old-path-2" } + * redirect: { path_redirect: "/new-path-2", strip-query: "true" } + * - match: { path: "/old-path-3" } + * redirect: { path_redirect: "/new-path-3?foo=1", strip_query: "true" } + * + * 1. if request uri is "/old-path-1?bar=1", users will be redirected to "/new-path-1?bar=1" + * 2. if request uri is "/old-path-2?bar=1", users will be redirected to "/new-path-2" + * 3. if request uri is "/old-path-3?bar=1", users will be redirected to "/new-path-3?foo=1" + */ + 'path_redirect'?: (string); + /** + * The HTTP status code to use in the redirect response. The default response + * code is MOVED_PERMANENTLY (301). + */ + 'response_code'?: (_envoy_config_route_v3_RedirectAction_RedirectResponseCode | keyof typeof _envoy_config_route_v3_RedirectAction_RedirectResponseCode); + /** + * The scheme portion of the URL will be swapped with "https". + */ + 'https_redirect'?: (boolean); + /** + * Indicates that during redirection, the matched prefix (or path) + * should be swapped with this value. This option allows redirect URLs be dynamically created + * based on the request. + * + * .. attention:: + * + * Pay attention to the use of trailing slashes as mentioned in + * :ref:`RouteAction's prefix_rewrite `. + */ + 'prefix_rewrite'?: (string); + /** + * Indicates that during redirection, the query portion of the URL will + * be removed. Default value is false. + */ + 'strip_query'?: (boolean); + /** + * The scheme portion of the URL will be swapped with this value. + */ + 'scheme_redirect'?: (string); + /** + * The port value of the URL will be swapped with this value. + */ + 'port_redirect'?: (number); + /** + * Indicates that during redirect, portions of the path that match the + * pattern should be rewritten, even allowing the substitution of capture + * groups from the pattern into the new path as specified by the rewrite + * substitution string. This is useful to allow application paths to be + * rewritten in a way that is aware of segments with variable content like + * identifiers. + * + * Examples using Google's `RE2 `_ engine: + * + * * The path pattern ``^/service/([^/]+)(/.*)$`` paired with a substitution + * string of ``\2/instance/\1`` would transform ``/service/foo/v1/api`` + * into ``/v1/api/instance/foo``. + * + * * The pattern ``one`` paired with a substitution string of ``two`` would + * transform ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/two/zzz``. + * + * * The pattern ``^(.*?)one(.*)$`` paired with a substitution string of + * ``\1two\2`` would replace only the first occurrence of ``one``, + * transforming path ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/one/zzz``. + * + * * The pattern ``(?i)/xxx/`` paired with a substitution string of ``/yyy/`` + * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to + * ``/aaa/yyy/bbb``. + */ + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); + /** + * When the scheme redirection take place, the following rules apply: + * 1. If the source URI scheme is `http` and the port is explicitly + * set to `:80`, the port will be removed after the redirection + * 2. If the source URI scheme is `https` and the port is explicitly + * set to `:443`, the port will be removed after the redirection + */ + 'scheme_rewrite_specifier'?: "https_redirect"|"scheme_redirect"; + 'path_rewrite_specifier'?: "path_redirect"|"prefix_rewrite"|"regex_rewrite"; +} + +/** + * [#next-free-field: 10] + */ +export interface RedirectAction__Output { + /** + * The host portion of the URL will be swapped with this value. + */ + 'host_redirect': (string); + /** + * The path portion of the URL will be swapped with this value. + * Please note that query string in path_redirect will override the + * request's query string and will not be stripped. + * + * For example, let's say we have the following routes: + * + * - match: { path: "/old-path-1" } + * redirect: { path_redirect: "/new-path-1" } + * - match: { path: "/old-path-2" } + * redirect: { path_redirect: "/new-path-2", strip-query: "true" } + * - match: { path: "/old-path-3" } + * redirect: { path_redirect: "/new-path-3?foo=1", strip_query: "true" } + * + * 1. if request uri is "/old-path-1?bar=1", users will be redirected to "/new-path-1?bar=1" + * 2. if request uri is "/old-path-2?bar=1", users will be redirected to "/new-path-2" + * 3. if request uri is "/old-path-3?bar=1", users will be redirected to "/new-path-3?foo=1" + */ + 'path_redirect'?: (string); + /** + * The HTTP status code to use in the redirect response. The default response + * code is MOVED_PERMANENTLY (301). + */ + 'response_code': (keyof typeof _envoy_config_route_v3_RedirectAction_RedirectResponseCode); + /** + * The scheme portion of the URL will be swapped with "https". + */ + 'https_redirect'?: (boolean); + /** + * Indicates that during redirection, the matched prefix (or path) + * should be swapped with this value. This option allows redirect URLs be dynamically created + * based on the request. + * + * .. attention:: + * + * Pay attention to the use of trailing slashes as mentioned in + * :ref:`RouteAction's prefix_rewrite `. + */ + 'prefix_rewrite'?: (string); + /** + * Indicates that during redirection, the query portion of the URL will + * be removed. Default value is false. + */ + 'strip_query': (boolean); + /** + * The scheme portion of the URL will be swapped with this value. + */ + 'scheme_redirect'?: (string); + /** + * The port value of the URL will be swapped with this value. + */ + 'port_redirect': (number); + /** + * Indicates that during redirect, portions of the path that match the + * pattern should be rewritten, even allowing the substitution of capture + * groups from the pattern into the new path as specified by the rewrite + * substitution string. This is useful to allow application paths to be + * rewritten in a way that is aware of segments with variable content like + * identifiers. + * + * Examples using Google's `RE2 `_ engine: + * + * * The path pattern ``^/service/([^/]+)(/.*)$`` paired with a substitution + * string of ``\2/instance/\1`` would transform ``/service/foo/v1/api`` + * into ``/v1/api/instance/foo``. + * + * * The pattern ``one`` paired with a substitution string of ``two`` would + * transform ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/two/zzz``. + * + * * The pattern ``^(.*?)one(.*)$`` paired with a substitution string of + * ``\1two\2`` would replace only the first occurrence of ``one``, + * transforming path ``/xxx/one/yyy/one/zzz`` into ``/xxx/two/yyy/one/zzz``. + * + * * The pattern ``(?i)/xxx/`` paired with a substitution string of ``/yyy/`` + * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to + * ``/aaa/yyy/bbb``. + */ + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); + /** + * When the scheme redirection take place, the following rules apply: + * 1. If the source URI scheme is `http` and the port is explicitly + * set to `:80`, the port will be removed after the redirection + * 2. If the source URI scheme is `https` and the port is explicitly + * set to `:443`, the port will be removed after the redirection + */ + 'scheme_rewrite_specifier': "https_redirect"|"scheme_redirect"; + 'path_rewrite_specifier': "path_redirect"|"prefix_rewrite"|"regex_rewrite"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts new file mode 100644 index 000000000..52f391dd9 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts @@ -0,0 +1,392 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Long } from '@grpc/proto-loader'; + +/** + * A retry back-off strategy that applies when the upstream server rate limits + * the request. + * + * Given this configuration: + * + * .. code-block:: yaml + * + * rate_limited_retry_back_off: + * reset_headers: + * - name: Retry-After + * format: SECONDS + * - name: X-RateLimit-Reset + * format: UNIX_TIMESTAMP + * max_interval: "300s" + * + * The following algorithm will apply: + * + * 1. If the response contains the header ``Retry-After`` its value must be on + * the form ``120`` (an integer that represents the number of seconds to + * wait before retrying). If so, this value is used as the back-off interval. + * 2. Otherwise, if the response contains the header ``X-RateLimit-Reset`` its + * value must be on the form ``1595320702`` (an integer that represents the + * point in time at which to retry, as a Unix timestamp in seconds). If so, + * the current time is subtracted from this value and the result is used as + * the back-off interval. + * 3. Otherwise, Envoy will use the default + * :ref:`exponential back-off ` + * strategy. + * + * No matter which format is used, if the resulting back-off interval exceeds + * ``max_interval`` it is discarded and the next header in ``reset_headers`` + * is tried. If a request timeout is configured for the route it will further + * limit how long the request will be allowed to run. + * + * To prevent many clients retrying at the same point in time jitter is added + * to the back-off interval, so the resulting interval is decided by taking: + * ``random(interval, interval * 1.5)``. + * + * .. attention:: + * + * Configuring ``rate_limited_retry_back_off`` will not by itself cause a request + * to be retried. You will still need to configure the right retry policy to match + * the responses from the upstream server. + */ +export interface _envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff { + /** + * Specifies the reset headers (like ``Retry-After`` or ``X-RateLimit-Reset``) + * to match against the response. Headers are tried in order, and matched case + * insensitive. The first header to be parsed successfully is used. If no headers + * match the default exponential back-off is used instead. + */ + 'reset_headers'?: (_envoy_config_route_v3_RetryPolicy_ResetHeader)[]; + /** + * Specifies the maximum back off interval that Envoy will allow. If a reset + * header contains an interval longer than this then it will be discarded and + * the next header will be tried. Defaults to 300 seconds. + */ + 'max_interval'?: (_google_protobuf_Duration); +} + +/** + * A retry back-off strategy that applies when the upstream server rate limits + * the request. + * + * Given this configuration: + * + * .. code-block:: yaml + * + * rate_limited_retry_back_off: + * reset_headers: + * - name: Retry-After + * format: SECONDS + * - name: X-RateLimit-Reset + * format: UNIX_TIMESTAMP + * max_interval: "300s" + * + * The following algorithm will apply: + * + * 1. If the response contains the header ``Retry-After`` its value must be on + * the form ``120`` (an integer that represents the number of seconds to + * wait before retrying). If so, this value is used as the back-off interval. + * 2. Otherwise, if the response contains the header ``X-RateLimit-Reset`` its + * value must be on the form ``1595320702`` (an integer that represents the + * point in time at which to retry, as a Unix timestamp in seconds). If so, + * the current time is subtracted from this value and the result is used as + * the back-off interval. + * 3. Otherwise, Envoy will use the default + * :ref:`exponential back-off ` + * strategy. + * + * No matter which format is used, if the resulting back-off interval exceeds + * ``max_interval`` it is discarded and the next header in ``reset_headers`` + * is tried. If a request timeout is configured for the route it will further + * limit how long the request will be allowed to run. + * + * To prevent many clients retrying at the same point in time jitter is added + * to the back-off interval, so the resulting interval is decided by taking: + * ``random(interval, interval * 1.5)``. + * + * .. attention:: + * + * Configuring ``rate_limited_retry_back_off`` will not by itself cause a request + * to be retried. You will still need to configure the right retry policy to match + * the responses from the upstream server. + */ +export interface _envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff__Output { + /** + * Specifies the reset headers (like ``Retry-After`` or ``X-RateLimit-Reset``) + * to match against the response. Headers are tried in order, and matched case + * insensitive. The first header to be parsed successfully is used. If no headers + * match the default exponential back-off is used instead. + */ + 'reset_headers': (_envoy_config_route_v3_RetryPolicy_ResetHeader__Output)[]; + /** + * Specifies the maximum back off interval that Envoy will allow. If a reset + * header contains an interval longer than this then it will be discarded and + * the next header will be tried. Defaults to 300 seconds. + */ + 'max_interval'?: (_google_protobuf_Duration__Output); +} + +export interface _envoy_config_route_v3_RetryPolicy_ResetHeader { + /** + * The name of the reset header. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. + */ + 'name'?: (string); + /** + * The format of the reset header. + */ + 'format'?: (_envoy_config_route_v3_RetryPolicy_ResetHeaderFormat | keyof typeof _envoy_config_route_v3_RetryPolicy_ResetHeaderFormat); +} + +export interface _envoy_config_route_v3_RetryPolicy_ResetHeader__Output { + /** + * The name of the reset header. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. + */ + 'name': (string); + /** + * The format of the reset header. + */ + 'format': (keyof typeof _envoy_config_route_v3_RetryPolicy_ResetHeaderFormat); +} + +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + +export enum _envoy_config_route_v3_RetryPolicy_ResetHeaderFormat { + SECONDS = 0, + UNIX_TIMESTAMP = 1, +} + +export interface _envoy_config_route_v3_RetryPolicy_RetryBackOff { + /** + * Specifies the base interval between retries. This parameter is required and must be greater + * than zero. Values less than 1 ms are rounded up to 1 ms. + * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's + * back-off algorithm. + */ + 'base_interval'?: (_google_protobuf_Duration); + /** + * Specifies the maximum interval between retries. This parameter is optional, but must be + * greater than or equal to the `base_interval` if set. The default is 10 times the + * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion + * of Envoy's back-off algorithm. + */ + 'max_interval'?: (_google_protobuf_Duration); +} + +export interface _envoy_config_route_v3_RetryPolicy_RetryBackOff__Output { + /** + * Specifies the base interval between retries. This parameter is required and must be greater + * than zero. Values less than 1 ms are rounded up to 1 ms. + * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's + * back-off algorithm. + */ + 'base_interval'?: (_google_protobuf_Duration__Output); + /** + * Specifies the maximum interval between retries. This parameter is optional, but must be + * greater than or equal to the `base_interval` if set. The default is 10 times the + * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion + * of Envoy's back-off algorithm. + */ + 'max_interval'?: (_google_protobuf_Duration__Output); +} + +export interface _envoy_config_route_v3_RetryPolicy_RetryHostPredicate { + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "typed_config"; +} + +export interface _envoy_config_route_v3_RetryPolicy_RetryHostPredicate__Output { + 'name': (string); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "typed_config"; +} + +export interface _envoy_config_route_v3_RetryPolicy_RetryPriority { + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any); + 'config_type'?: "typed_config"; +} + +export interface _envoy_config_route_v3_RetryPolicy_RetryPriority__Output { + 'name': (string); + 'typed_config'?: (_google_protobuf_Any__Output); + 'config_type': "typed_config"; +} + +/** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 12] + */ +export interface RetryPolicy { + /** + * Specifies the conditions under which retry takes place. These are the same + * conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and + * :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. + */ + 'retry_on'?: (string); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. These are the same conditions documented for + * :ref:`config_http_filters_router_x-envoy-max-retries`. + */ + 'num_retries'?: (_google_protobuf_UInt32Value); + /** + * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The + * same conditions documented for + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. + * + * .. note:: + * + * If left unspecified, Envoy will use the global + * :ref:`route timeout ` for the request. + * Consequently, when using a :ref:`5xx ` based + * retry policy, a request that times out will not be retried as the total timeout budget + * would have been exhausted. + */ + 'per_try_timeout'?: (_google_protobuf_Duration); + /** + * Specifies an implementation of a RetryPriority which is used to determine the + * distribution of load across priorities used for retries. Refer to + * :ref:`retry plugin configuration ` for more details. + */ + 'retry_priority'?: (_envoy_config_route_v3_RetryPolicy_RetryPriority); + /** + * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host + * for retries. If any of the predicates reject the host, host selection will be reattempted. + * Refer to :ref:`retry plugin configuration ` for more + * details. + */ + 'retry_host_predicate'?: (_envoy_config_route_v3_RetryPolicy_RetryHostPredicate)[]; + /** + * The maximum number of times host selection will be reattempted before giving up, at which + * point the host that was last selected will be routed to. If unspecified, this will default to + * retrying once. + */ + 'host_selection_retry_max_attempts'?: (number | string | Long); + /** + * HTTP status codes that should trigger a retry in addition to those specified by retry_on. + */ + 'retriable_status_codes'?: (number)[]; + /** + * Specifies parameters that control exponential retry back off. This parameter is optional, in which case the + * default base interval is 25 milliseconds or, if set, the current value of the + * `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times + * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` + * describes Envoy's back-off algorithm. + */ + 'retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RetryBackOff); + /** + * HTTP response headers that trigger a retry if present in the response. A retry will be + * triggered if any of the header matches match the upstream response headers. + * The field is only consulted if 'retriable-headers' retry policy is active. + */ + 'retriable_headers'?: (_envoy_config_route_v3_HeaderMatcher)[]; + /** + * HTTP headers which must be present in the request for retries to be attempted. + */ + 'retriable_request_headers'?: (_envoy_config_route_v3_HeaderMatcher)[]; + /** + * Specifies parameters that control a retry back-off strategy that is used + * when the request is rate limited by the upstream server. The server may + * return a response header like ``Retry-After`` or ``X-RateLimit-Reset`` to + * provide feedback to the client on how long to wait before retrying. If + * configured, this back-off strategy will be used instead of the + * default exponential back off strategy (configured using `retry_back_off`) + * whenever a response includes the matching headers. + */ + 'rate_limited_retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff); +} + +/** + * HTTP retry :ref:`architecture overview `. + * [#next-free-field: 12] + */ +export interface RetryPolicy__Output { + /** + * Specifies the conditions under which retry takes place. These are the same + * conditions documented for :ref:`config_http_filters_router_x-envoy-retry-on` and + * :ref:`config_http_filters_router_x-envoy-retry-grpc-on`. + */ + 'retry_on': (string); + /** + * Specifies the allowed number of retries. This parameter is optional and + * defaults to 1. These are the same conditions documented for + * :ref:`config_http_filters_router_x-envoy-max-retries`. + */ + 'num_retries'?: (_google_protobuf_UInt32Value__Output); + /** + * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The + * same conditions documented for + * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. + * + * .. note:: + * + * If left unspecified, Envoy will use the global + * :ref:`route timeout ` for the request. + * Consequently, when using a :ref:`5xx ` based + * retry policy, a request that times out will not be retried as the total timeout budget + * would have been exhausted. + */ + 'per_try_timeout'?: (_google_protobuf_Duration__Output); + /** + * Specifies an implementation of a RetryPriority which is used to determine the + * distribution of load across priorities used for retries. Refer to + * :ref:`retry plugin configuration ` for more details. + */ + 'retry_priority'?: (_envoy_config_route_v3_RetryPolicy_RetryPriority__Output); + /** + * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host + * for retries. If any of the predicates reject the host, host selection will be reattempted. + * Refer to :ref:`retry plugin configuration ` for more + * details. + */ + 'retry_host_predicate': (_envoy_config_route_v3_RetryPolicy_RetryHostPredicate__Output)[]; + /** + * The maximum number of times host selection will be reattempted before giving up, at which + * point the host that was last selected will be routed to. If unspecified, this will default to + * retrying once. + */ + 'host_selection_retry_max_attempts': (string); + /** + * HTTP status codes that should trigger a retry in addition to those specified by retry_on. + */ + 'retriable_status_codes': (number)[]; + /** + * Specifies parameters that control exponential retry back off. This parameter is optional, in which case the + * default base interval is 25 milliseconds or, if set, the current value of the + * `upstream.base_retry_backoff_ms` runtime parameter. The default maximum interval is 10 times + * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` + * describes Envoy's back-off algorithm. + */ + 'retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RetryBackOff__Output); + /** + * HTTP response headers that trigger a retry if present in the response. A retry will be + * triggered if any of the header matches match the upstream response headers. + * The field is only consulted if 'retriable-headers' retry policy is active. + */ + 'retriable_headers': (_envoy_config_route_v3_HeaderMatcher__Output)[]; + /** + * HTTP headers which must be present in the request for retries to be attempted. + */ + 'retriable_request_headers': (_envoy_config_route_v3_HeaderMatcher__Output)[]; + /** + * Specifies parameters that control a retry back-off strategy that is used + * when the request is rate limited by the upstream server. The server may + * return a response header like ``Retry-After`` or ``X-RateLimit-Reset`` to + * provide feedback to the client on how long to wait before retrying. If + * configured, this back-off strategy will be used instead of the + * default exponential back off strategy (configured using `retry_back_off`) + * whenever a response includes the matching headers. + */ + 'rate_limited_retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts similarity index 58% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts index 86cb4ac3d..ea00564f8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Route.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts @@ -1,17 +1,16 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { RouteMatch as _envoy_api_v2_route_RouteMatch, RouteMatch__Output as _envoy_api_v2_route_RouteMatch__Output } from '../../../../envoy/api/v2/route/RouteMatch'; -import type { RouteAction as _envoy_api_v2_route_RouteAction, RouteAction__Output as _envoy_api_v2_route_RouteAction__Output } from '../../../../envoy/api/v2/route/RouteAction'; -import type { RedirectAction as _envoy_api_v2_route_RedirectAction, RedirectAction__Output as _envoy_api_v2_route_RedirectAction__Output } from '../../../../envoy/api/v2/route/RedirectAction'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import type { Decorator as _envoy_api_v2_route_Decorator, Decorator__Output as _envoy_api_v2_route_Decorator__Output } from '../../../../envoy/api/v2/route/Decorator'; -import type { DirectResponseAction as _envoy_api_v2_route_DirectResponseAction, DirectResponseAction__Output as _envoy_api_v2_route_DirectResponseAction__Output } from '../../../../envoy/api/v2/route/DirectResponseAction'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; +import type { RouteMatch as _envoy_config_route_v3_RouteMatch, RouteMatch__Output as _envoy_config_route_v3_RouteMatch__Output } from '../../../../envoy/config/route/v3/RouteMatch'; +import type { RouteAction as _envoy_config_route_v3_RouteAction, RouteAction__Output as _envoy_config_route_v3_RouteAction__Output } from '../../../../envoy/config/route/v3/RouteAction'; +import type { RedirectAction as _envoy_config_route_v3_RedirectAction, RedirectAction__Output as _envoy_config_route_v3_RedirectAction__Output } from '../../../../envoy/config/route/v3/RedirectAction'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; +import type { Decorator as _envoy_config_route_v3_Decorator, Decorator__Output as _envoy_config_route_v3_Decorator__Output } from '../../../../envoy/config/route/v3/Decorator'; +import type { DirectResponseAction as _envoy_config_route_v3_DirectResponseAction, DirectResponseAction__Output as _envoy_config_route_v3_DirectResponseAction__Output } from '../../../../envoy/config/route/v3/DirectResponseAction'; +import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, HeaderValueOption__Output as _envoy_config_core_v3_HeaderValueOption__Output } from '../../../../envoy/config/core/v3/HeaderValueOption'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import type { Tracing as _envoy_api_v2_route_Tracing, Tracing__Output as _envoy_api_v2_route_Tracing__Output } from '../../../../envoy/api/v2/route/Tracing'; +import type { Tracing as _envoy_config_route_v3_Tracing, Tracing__Output as _envoy_config_route_v3_Tracing__Output } from '../../../../envoy/config/route/v3/Tracing'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Output as _envoy_api_v2_route_FilterAction__Output } from '../../../../envoy/api/v2/route/FilterAction'; +import type { FilterAction as _envoy_config_route_v3_FilterAction, FilterAction__Output as _envoy_config_route_v3_FilterAction__Output } from '../../../../envoy/config/route/v3/FilterAction'; /** * A route is both a specification of how to match a request as well as an indication of what to do @@ -20,22 +19,22 @@ import type { FilterAction as _envoy_api_v2_route_FilterAction, FilterAction__Ou * .. attention:: * * Envoy supports routing on HTTP method via :ref:`header matching - * `. + * `. * [#next-free-field: 18] */ export interface Route { /** * Route matching parameters. */ - 'match'?: (_envoy_api_v2_route_RouteMatch); + 'match'?: (_envoy_config_route_v3_RouteMatch); /** * Route request to some upstream cluster. */ - 'route'?: (_envoy_api_v2_route_RouteAction); + 'route'?: (_envoy_config_route_v3_RouteAction); /** * Return a redirect. */ - 'redirect'?: (_envoy_api_v2_route_RedirectAction); + 'redirect'?: (_envoy_config_route_v3_RedirectAction); /** * The Metadata field can be used to provide additional information * about the route. It can be used for configuration, stats, and logging. @@ -43,41 +42,33 @@ export interface Route { * For instance, if the metadata is intended for the Router filter, * the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_api_v2_core_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata); /** * Decorator for the matched route. */ - 'decorator'?: (_envoy_api_v2_route_Decorator); + 'decorator'?: (_envoy_config_route_v3_Decorator); /** * Return an arbitrary HTTP response directly, without proxying. */ - 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction); - /** - * The per_filter_config field can be used to provide route-specific - * configurations for filters. The key should match the filter name, such as - * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter - * specific; see the :ref:`HTTP filter documentation ` for - * if and how it is utilized. - */ - 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct}); + 'direct_response'?: (_envoy_config_route_v3_DirectResponseAction); /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the - * enclosing :ref:`envoy_api_msg_route.VirtualHost` and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a set of headers that will be added to responses to requests * matching this route. Headers specified at this level are applied before - * headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * headers from the enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on * :ref:`custom request headers `. */ - 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of HTTP headers that should be removed from each response * to requests matching this route. @@ -94,6 +85,9 @@ export interface Route { * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. + * [#comment: An entry's value may be wrapped in a + * :ref:`FilterConfig` + * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); /** @@ -104,7 +98,7 @@ export interface Route { * Presence of the object defines whether the connection manager's tracing configuration * is overridden by this route specific instance. */ - 'tracing'?: (_envoy_api_v2_route_Tracing); + 'tracing'?: (_envoy_config_route_v3_Tracing); /** * The maximum bytes which will be buffered for retries and shadowing. * If set, the bytes actually buffered will be the minimum value of this and the @@ -115,8 +109,10 @@ export interface Route { * [#not-implemented-hide:] * If true, a filter will define the action (e.g., it could dynamically generate the * RouteAction). + * [#comment: TODO(samflattery): Remove cleanup in route_fuzz_test.cc when + * implemented] */ - 'filter_action'?: (_envoy_api_v2_route_FilterAction); + 'filter_action'?: (_envoy_config_route_v3_FilterAction); 'action'?: "route"|"redirect"|"direct_response"|"filter_action"; } @@ -127,22 +123,22 @@ export interface Route { * .. attention:: * * Envoy supports routing on HTTP method via :ref:`header matching - * `. + * `. * [#next-free-field: 18] */ export interface Route__Output { /** * Route matching parameters. */ - 'match'?: (_envoy_api_v2_route_RouteMatch__Output); + 'match'?: (_envoy_config_route_v3_RouteMatch__Output); /** * Route request to some upstream cluster. */ - 'route'?: (_envoy_api_v2_route_RouteAction__Output); + 'route'?: (_envoy_config_route_v3_RouteAction__Output); /** * Return a redirect. */ - 'redirect'?: (_envoy_api_v2_route_RedirectAction__Output); + 'redirect'?: (_envoy_config_route_v3_RedirectAction__Output); /** * The Metadata field can be used to provide additional information * about the route. It can be used for configuration, stats, and logging. @@ -150,41 +146,33 @@ export interface Route__Output { * For instance, if the metadata is intended for the Router filter, * the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_api_v2_core_Metadata__Output); + 'metadata'?: (_envoy_config_core_v3_Metadata__Output); /** * Decorator for the matched route. */ - 'decorator'?: (_envoy_api_v2_route_Decorator__Output); + 'decorator'?: (_envoy_config_route_v3_Decorator__Output); /** * Return an arbitrary HTTP response directly, without proxying. */ - 'direct_response'?: (_envoy_api_v2_route_DirectResponseAction__Output); - /** - * The per_filter_config field can be used to provide route-specific - * configurations for filters. The key should match the filter name, such as - * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter - * specific; see the :ref:`HTTP filter documentation ` for - * if and how it is utilized. - */ - 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct__Output}); + 'direct_response'?: (_envoy_config_route_v3_DirectResponseAction__Output); /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the - * enclosing :ref:`envoy_api_msg_route.VirtualHost` and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a set of headers that will be added to responses to requests * matching this route. Headers specified at this level are applied before - * headers from the enclosing :ref:`envoy_api_msg_route.VirtualHost` and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * headers from the enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on * :ref:`custom request headers `. */ - 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of HTTP headers that should be removed from each response * to requests matching this route. @@ -201,6 +189,9 @@ export interface Route__Output { * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. + * [#comment: An entry's value may be wrapped in a + * :ref:`FilterConfig` + * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); /** @@ -211,7 +202,7 @@ export interface Route__Output { * Presence of the object defines whether the connection manager's tracing configuration * is overridden by this route specific instance. */ - 'tracing'?: (_envoy_api_v2_route_Tracing__Output); + 'tracing'?: (_envoy_config_route_v3_Tracing__Output); /** * The maximum bytes which will be buffered for retries and shadowing. * If set, the bytes actually buffered will be the minimum value of this and the @@ -222,7 +213,9 @@ export interface Route__Output { * [#not-implemented-hide:] * If true, a filter will define the action (e.g., it could dynamically generate the * RouteAction). + * [#comment: TODO(samflattery): Remove cleanup in route_fuzz_test.cc when + * implemented] */ - 'filter_action'?: (_envoy_api_v2_route_FilterAction__Output); + 'filter_action'?: (_envoy_config_route_v3_FilterAction__Output); 'action': "route"|"redirect"|"direct_response"|"filter_action"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts similarity index 62% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts index 5f07bae9b..797d6eda6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts @@ -1,22 +1,24 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { WeightedCluster as _envoy_api_v2_route_WeightedCluster, WeightedCluster__Output as _envoy_api_v2_route_WeightedCluster__Output } from '../../../../envoy/api/v2/route/WeightedCluster'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; +import type { WeightedCluster as _envoy_config_route_v3_WeightedCluster, WeightedCluster__Output as _envoy_config_route_v3_WeightedCluster__Output } from '../../../../envoy/config/route/v3/WeightedCluster'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import type { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; -import type { RoutingPriority as _envoy_api_v2_core_RoutingPriority } from '../../../../envoy/api/v2/core/RoutingPriority'; -import type { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; -import type { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; -import type { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import type { RetryPolicy as _envoy_config_route_v3_RetryPolicy, RetryPolicy__Output as _envoy_config_route_v3_RetryPolicy__Output } from '../../../../envoy/config/route/v3/RetryPolicy'; +import type { RoutingPriority as _envoy_config_core_v3_RoutingPriority } from '../../../../envoy/config/core/v3/RoutingPriority'; +import type { RateLimit as _envoy_config_route_v3_RateLimit, RateLimit__Output as _envoy_config_route_v3_RateLimit__Output } from '../../../../envoy/config/route/v3/RateLimit'; +import type { CorsPolicy as _envoy_config_route_v3_CorsPolicy, CorsPolicy__Output as _envoy_config_route_v3_CorsPolicy__Output } from '../../../../envoy/config/route/v3/CorsPolicy'; +import type { HedgePolicy as _envoy_config_route_v3_HedgePolicy, HedgePolicy__Output as _envoy_config_route_v3_HedgePolicy__Output } from '../../../../envoy/config/route/v3/HedgePolicy'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { RegexMatchAndSubstitute as _envoy_type_matcher_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/RegexMatchAndSubstitute'; +import type { RegexMatchAndSubstitute as _envoy_type_matcher_v3_RegexMatchAndSubstitute, RegexMatchAndSubstitute__Output as _envoy_type_matcher_v3_RegexMatchAndSubstitute__Output } from '../../../../envoy/type/matcher/v3/RegexMatchAndSubstitute'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import type { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; +import type { InternalRedirectPolicy as _envoy_config_route_v3_InternalRedirectPolicy, InternalRedirectPolicy__Output as _envoy_config_route_v3_InternalRedirectPolicy__Output } from '../../../../envoy/config/route/v3/InternalRedirectPolicy'; +import type { RuntimeFractionalPercent as _envoy_config_core_v3_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_config_core_v3_RuntimeFractionalPercent__Output } from '../../../../envoy/config/core/v3/RuntimeFractionalPercent'; +import type { ProxyProtocolConfig as _envoy_config_core_v3_ProxyProtocolConfig, ProxyProtocolConfig__Output as _envoy_config_core_v3_ProxyProtocolConfig__Output } from '../../../../envoy/config/core/v3/ProxyProtocolConfig'; -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -export enum _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode { +export enum _envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode { /** * HTTP status code - 503 Service Unavailable. */ @@ -27,14 +29,44 @@ export enum _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode { NOT_FOUND = 1, } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties { +/** + * Configuration for sending data upstream as a raw data payload. This is used for + * CONNECT or POST requests, when forwarding request payload as raw TCP. + */ +export interface _envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig { + /** + * If present, the proxy protocol header will be prepended to the CONNECT payload sent upstream. + */ + 'proxy_protocol_config'?: (_envoy_config_core_v3_ProxyProtocolConfig); + /** + * If set, the route will also allow forwarding POST payload as raw TCP. + */ + 'allow_post'?: (boolean); +} + +/** + * Configuration for sending data upstream as a raw data payload. This is used for + * CONNECT or POST requests, when forwarding request payload as raw TCP. + */ +export interface _envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__Output { + /** + * If present, the proxy protocol header will be prepended to the CONNECT payload sent upstream. + */ + 'proxy_protocol_config'?: (_envoy_config_core_v3_ProxyProtocolConfig__Output); + /** + * If set, the route will also allow forwarding POST payload as raw TCP. + */ + 'allow_post': (boolean); +} + +export interface _envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties { /** * Hash on source IP address. */ 'source_ip'?: (boolean); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties__Output { /** * Hash on source IP address. */ @@ -57,7 +89,7 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties * streams on the same connection will independently receive the same * cookie, even if they arrive at the Envoy simultaneously. */ -export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_Cookie { /** * The name of the cookie that will be used to obtain the hash key. If the * cookie is not present and ttl below is not set, no hash will be @@ -93,7 +125,7 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie { * streams on the same connection will independently receive the same * cookie, even if they arrive at the Envoy simultaneously. */ -export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_Cookie__Output { /** * The name of the cookie that will be used to obtain the hash key. If the * cookie is not present and ttl below is not set, no hash will be @@ -113,7 +145,7 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output { 'path': (string); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_FilterState { /** * The name of the Object in the per-request filterState, which is an * Envoy::Http::Hashable object. If there is no data associated with the key, @@ -122,7 +154,7 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState { 'key'?: (string); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_FilterState__Output { /** * The name of the Object in the per-request filterState, which is an * Envoy::Http::Hashable object. If there is no data associated with the key, @@ -136,27 +168,27 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output * `. * [#next-free-field: 7] */ -export interface _envoy_api_v2_route_RouteAction_HashPolicy { +export interface _envoy_config_route_v3_RouteAction_HashPolicy { /** * Header hash policy. */ - 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header); + 'header'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Header); /** * Cookie hash policy. */ - 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie); + 'cookie'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Cookie); /** * Connection properties hash policy. */ - 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties); + 'connection_properties'?: (_envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties); /** * Query parameter hash policy. */ - 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter); + 'query_parameter'?: (_envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter); /** * Filter state hash policy. */ - 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState); + 'filter_state'?: (_envoy_config_route_v3_RouteAction_HashPolicy_FilterState); /** * The flag that short-circuits the hash computing. This field provides a * 'fallback' style of configuration: "if a terminal policy doesn't work, @@ -187,27 +219,27 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy { * `. * [#next-free-field: 7] */ -export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { +export interface _envoy_config_route_v3_RouteAction_HashPolicy__Output { /** * Header hash policy. */ - 'header'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Header__Output); + 'header'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Header__Output); /** * Cookie hash policy. */ - 'cookie'?: (_envoy_api_v2_route_RouteAction_HashPolicy_Cookie__Output); + 'cookie'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Cookie__Output); /** * Connection properties hash policy. */ - 'connection_properties'?: (_envoy_api_v2_route_RouteAction_HashPolicy_ConnectionProperties__Output); + 'connection_properties'?: (_envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties__Output); /** * Query parameter hash policy. */ - 'query_parameter'?: (_envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output); + 'query_parameter'?: (_envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter__Output); /** * Filter state hash policy. */ - 'filter_state'?: (_envoy_api_v2_route_RouteAction_HashPolicy_FilterState__Output); + 'filter_state'?: (_envoy_config_route_v3_RouteAction_HashPolicy_FilterState__Output); /** * The flag that short-circuits the hash computing. This field provides a * 'fallback' style of configuration: "if a terminal policy doesn't work, @@ -233,33 +265,104 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy__Output { 'policy_specifier': "header"|"cookie"|"connection_properties"|"query_parameter"|"filter_state"; } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_Header { /** * The name of the request header that will be used to obtain the hash * key. If the request header is not present, no hash will be produced. */ 'header_name'?: (string); + /** + * If specified, the request header value will be rewritten and used + * to produce the hash key. + */ + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_Header__Output { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_Header__Output { /** * The name of the request header that will be used to obtain the hash * key. If the request header is not present, no hash will be produced. */ 'header_name': (string); + /** + * If specified, the request header value will be rewritten and used + * to produce the hash key. + */ + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); } -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto /** * Configures :ref:`internal redirect ` behavior. + * [#next-major-version: remove this definition - it's defined in the InternalRedirectPolicy message.] */ -export enum _envoy_api_v2_route_RouteAction_InternalRedirectAction { +export enum _envoy_config_route_v3_RouteAction_InternalRedirectAction { PASS_THROUGH_INTERNAL_REDIRECT = 0, HANDLE_INTERNAL_REDIRECT = 1, } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter { +export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration { + /** + * Specifies the maximum duration allowed for streams on the route. If not specified, the value + * from the :ref:`max_stream_duration + * ` field in + * :ref:`HttpConnectionManager.common_http_protocol_options + * ` + * is used. If this field is set explicitly to zero, any + * HttpConnectionManager max_stream_duration timeout will be disabled for + * this route. + */ + 'max_stream_duration'?: (_google_protobuf_Duration); + /** + * If present, and the request contains a `grpc-timeout header + * `_, use that value as the + * *max_stream_duration*, but limit the applied timeout to the maximum value specified here. + * If set to 0, the `grpc-timeout` header is used without modification. + */ + 'grpc_timeout_header_max'?: (_google_protobuf_Duration); + /** + * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by + * subtracting the provided duration from the header. This is useful for allowing Envoy to set + * its global timeout to be less than that of the deadline imposed by the calling client, which + * makes it more likely that Envoy will handle the timeout instead of having the call canceled + * by the client. If, after applying the offset, the resulting timeout is zero or negative, + * the stream will timeout immediately. + */ + 'grpc_timeout_header_offset'?: (_google_protobuf_Duration); +} + +export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration__Output { + /** + * Specifies the maximum duration allowed for streams on the route. If not specified, the value + * from the :ref:`max_stream_duration + * ` field in + * :ref:`HttpConnectionManager.common_http_protocol_options + * ` + * is used. If this field is set explicitly to zero, any + * HttpConnectionManager max_stream_duration timeout will be disabled for + * this route. + */ + 'max_stream_duration'?: (_google_protobuf_Duration__Output); + /** + * If present, and the request contains a `grpc-timeout header + * `_, use that value as the + * *max_stream_duration*, but limit the applied timeout to the maximum value specified here. + * If set to 0, the `grpc-timeout` header is used without modification. + */ + 'grpc_timeout_header_max'?: (_google_protobuf_Duration__Output); + /** + * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by + * subtracting the provided duration from the header. This is useful for allowing Envoy to set + * its global timeout to be less than that of the deadline imposed by the calling client, which + * makes it more likely that Envoy will handle the timeout instead of having the call canceled + * by the client. If, after applying the offset, the resulting timeout is zero or negative, + * the stream will timeout immediately. + */ + 'grpc_timeout_header_offset'?: (_google_protobuf_Duration__Output); +} + +export interface _envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter { /** * The name of the URL query parameter that will be used to obtain the hash * key. If the parameter is not present, no hash will be produced. Query @@ -268,7 +371,7 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter { 'name'?: (string); } -export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Output { +export interface _envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter__Output { /** * The name of the URL query parameter that will be used to obtain the hash * key. If the parameter is not present, no hash will be produced. Query @@ -290,30 +393,12 @@ export interface _envoy_api_v2_route_RouteAction_HashPolicy_QueryParameter__Outp * * Shadowing will not be triggered if the primary cluster does not exist. */ -export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { +export interface _envoy_config_route_v3_RouteAction_RequestMirrorPolicy { /** * Specifies the cluster that requests will be mirrored to. The cluster must * exist in the cluster manager configuration. */ 'cluster'?: (string); - /** - * If not specified, all requests to the target cluster will be mirrored. If - * specified, Envoy will lookup the runtime key to get the % of requests to - * mirror. Valid values are from 0 to 10000, allowing for increments of - * 0.01% of requests to be mirrored. If the runtime key is specified in the - * configuration but not present in runtime, 0 is the default and thus 0% of - * requests will be mirrored. - * - * .. attention:: - * - * **This field is deprecated**. Set the - * :ref:`runtime_fraction - * ` - * field instead. Mirroring occurs if both this and - * ` - * are not set. - */ - 'runtime_key'?: (string); /** * If not specified, all requests to the target cluster will be mirrored. * @@ -324,7 +409,7 @@ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { * number is <= the value of the numerator N, or if the key is not present, the default * value, the request will be mirrored. */ - 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent); /** * Determines if the trace span should be sampled. Defaults to true. */ @@ -344,30 +429,12 @@ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy { * * Shadowing will not be triggered if the primary cluster does not exist. */ -export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { +export interface _envoy_config_route_v3_RouteAction_RequestMirrorPolicy__Output { /** * Specifies the cluster that requests will be mirrored to. The cluster must * exist in the cluster manager configuration. */ 'cluster': (string); - /** - * If not specified, all requests to the target cluster will be mirrored. If - * specified, Envoy will lookup the runtime key to get the % of requests to - * mirror. Valid values are from 0 to 10000, allowing for increments of - * 0.01% of requests to be mirrored. If the runtime key is specified in the - * configuration but not present in runtime, 0 is the default and thus 0% of - * requests will be mirrored. - * - * .. attention:: - * - * **This field is deprecated**. Set the - * :ref:`runtime_fraction - * ` - * field instead. Mirroring occurs if both this and - * ` - * are not set. - */ - 'runtime_key': (string); /** * If not specified, all requests to the target cluster will be mirrored. * @@ -378,7 +445,7 @@ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { * number is <= the value of the numerator N, or if the key is not present, the default * value, the request will be mirrored. */ - 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); /** * Determines if the trace span should be sampled. Defaults to true. */ @@ -390,10 +457,10 @@ export interface _envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output { * This overrides any enabled/disabled upgrade filter chain specified in the * HttpConnectionManager * :ref:`upgrade_configs - * ` + * ` * but does not affect any custom filter chain specified there. */ -export interface _envoy_api_v2_route_RouteAction_UpgradeConfig { +export interface _envoy_config_route_v3_RouteAction_UpgradeConfig { /** * The case-insensitive name of this upgrade, e.g. "websocket". * For each upgrade type present in upgrade_configs, requests with @@ -404,6 +471,13 @@ export interface _envoy_api_v2_route_RouteAction_UpgradeConfig { * Determines if upgrades are available on this route. Defaults to true. */ 'enabled'?: (_google_protobuf_BoolValue); + /** + * Configuration for sending data upstream as a raw data payload. This is used for + * CONNECT requests, when forwarding CONNECT payload as raw TCP. + * Note that CONNECT support is currently considered alpha in Envoy. + * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + */ + 'connect_config'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig); } /** @@ -411,10 +485,10 @@ export interface _envoy_api_v2_route_RouteAction_UpgradeConfig { * This overrides any enabled/disabled upgrade filter chain specified in the * HttpConnectionManager * :ref:`upgrade_configs - * ` + * ` * but does not affect any custom filter chain specified there. */ -export interface _envoy_api_v2_route_RouteAction_UpgradeConfig__Output { +export interface _envoy_config_route_v3_RouteAction_UpgradeConfig__Output { /** * The case-insensitive name of this upgrade, e.g. "websocket". * For each upgrade type present in upgrade_configs, requests with @@ -425,10 +499,17 @@ export interface _envoy_api_v2_route_RouteAction_UpgradeConfig__Output { * Determines if upgrades are available on this route. Defaults to true. */ 'enabled'?: (_google_protobuf_BoolValue__Output); + /** + * Configuration for sending data upstream as a raw data payload. This is used for + * CONNECT requests, when forwarding CONNECT payload as raw TCP. + * Note that CONNECT support is currently considered alpha in Envoy. + * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + */ + 'connect_config'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__Output); } /** - * [#next-free-field: 34] + * [#next-free-field: 37] */ export interface RouteAction { /** @@ -446,6 +527,10 @@ export interface RouteAction { * * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 * *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ 'cluster_header'?: (string); /** @@ -455,15 +540,15 @@ export interface RouteAction { * :ref:`traffic splitting ` * for additional documentation. */ - 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster); + 'weighted_clusters'?: (_envoy_config_route_v3_WeightedCluster); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints * in the upstream cluster with metadata matching what's set in this field will be considered * for load balancing. If using :ref:`weighted_clusters - * `, metadata will be merged, with values + * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_api_v2_core_Metadata); + 'metadata_match'?: (_envoy_config_core_v3_Metadata); /** * Indicates that during forwarding, the matched prefix (or path) should be * swapped with this value. This option allows application URLs to be rooted @@ -472,16 +557,16 @@ export interface RouteAction { * ` header. * * Only one of *prefix_rewrite* or - * :ref:`regex_rewrite ` + * :ref:`regex_rewrite ` * may be specified. * * .. attention:: * * Pay careful attention to the use of trailing slashes in the - * :ref:`route's match ` prefix value. + * :ref:`route's match ` prefix value. * Stripping a prefix from a path requires multiple Routes to handle all cases. For example, * rewriting * /prefix* to * /* and * /prefix/etc* to * /etc* cannot be done in a single - * :ref:`Route `, as shown by the below config entries: + * :ref:`Route `, as shown by the below config entries: * * .. code-block:: yaml * @@ -502,7 +587,7 @@ export interface RouteAction { * Indicates that during forwarding, the host header will be swapped with * this value. */ - 'host_rewrite'?: (string); + 'host_rewrite_literal'?: (string); /** * Indicates that during forwarding, the host header will be swapped with * the hostname of the upstream host chosen by the cluster manager. This @@ -530,29 +615,23 @@ export interface RouteAction { * it'll take precedence over the virtual host level retry policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); - /** - * Indicates that the route has a request mirroring policy. - * - * .. attention:: - * This field has been deprecated in favor of `request_mirror_policies` which supports one or - * more mirroring policies. - */ - 'request_mirror_policy'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy); + 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy); /** * Optionally specifies the :ref:`routing priority `. */ - 'priority'?: (_envoy_api_v2_core_RoutingPriority | keyof typeof _envoy_api_v2_core_RoutingPriority); + 'priority'?: (_envoy_config_core_v3_RoutingPriority | keyof typeof _envoy_config_core_v3_RoutingPriority); /** * Specifies a set of rate limit configurations that could be applied to the * route. */ - 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; + 'rate_limits'?: (_envoy_config_route_v3_RateLimit)[]; /** * Specifies if the rate limit filter should include the virtual host rate * limits. By default, if the route configured rate limits, the virtual host - * :ref:`rate_limits ` are not applied to the + * :ref:`rate_limits ` are not applied to the * request. + * + * This field is deprecated. Please use :ref:`vh_rate_limits ` */ 'include_vh_rate_limits'?: (_google_protobuf_BoolValue); /** @@ -569,25 +648,26 @@ export interface RouteAction { * there is already a hash generated, the hash is returned immediately, * ignoring the rest of the hash policy list. */ - 'hash_policy'?: (_envoy_api_v2_route_RouteAction_HashPolicy)[]; + 'hash_policy'?: (_envoy_config_route_v3_RouteAction_HashPolicy)[]; /** * Indicates that the route has a CORS policy. */ - 'cors'?: (_envoy_api_v2_route_CorsPolicy); + 'cors'?: (_envoy_config_route_v3_CorsPolicy); /** * The HTTP status code to use when configured cluster is not found. * The default response code is 503 Service Unavailable. */ - 'cluster_not_found_response_code'?: (_envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); + 'cluster_not_found_response_code'?: (_envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode); /** + * Deprecated by :ref:`grpc_timeout_header_max ` * If present, and the request is a gRPC request, use the * `grpc-timeout header `_, * or its default value (infinity) instead of - * :ref:`timeout `, but limit the applied timeout + * :ref:`timeout `, but limit the applied timeout * to the maximum value specified here. If configured as 0, the maximum allowed timeout for * gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used * and gRPC requests time out like any other requests using - * :ref:`timeout ` or its default. + * :ref:`timeout ` or its default. * This can be used to prevent unexpected upstream request timeouts due to potentially long * time gaps between gRPC request and response in gRPC streaming mode. * @@ -604,14 +684,14 @@ export interface RouteAction { /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout - * ` + * ` * will still apply. A value of 0 will completely disable the route's idle timeout, even if a * connection manager stream idle timeout is configured. * * The idle timeout is distinct to :ref:`timeout - * `, which provides an upper bound + * `, which provides an upper bound * on the upstream response time; :ref:`idle_timeout - * ` instead bounds the amount + * ` instead bounds the amount * of time the request's stream may be idle. * * After header decoding, the idle timeout will apply on downstream and @@ -620,17 +700,22 @@ export interface RouteAction { * fires, the stream is terminated with a 408 Request Timeout error code if no * upstream response header has been received, otherwise a stream reset * occurs. + * + * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" + * is configured, this timeout is scaled according to the value for + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. */ 'idle_timeout'?: (_google_protobuf_Duration); - 'upgrade_configs'?: (_envoy_api_v2_route_RouteAction_UpgradeConfig)[]; - 'internal_redirect_action'?: (_envoy_api_v2_route_RouteAction_InternalRedirectAction | keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); + 'upgrade_configs'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig)[]; + 'internal_redirect_action'?: (_envoy_config_route_v3_RouteAction_InternalRedirectAction | keyof typeof _envoy_config_route_v3_RouteAction_InternalRedirectAction); /** * Indicates that the route has a hedge policy. Note that if this is set, * it'll take precedence over the virtual host level hedge policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy); /** + * Deprecated by :ref:`grpc_timeout_header_offset `. * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting * the provided duration from the header. This is useful in allowing Envoy to set its global * timeout to be less than that of the deadline imposed by the calling client, which makes it more @@ -649,24 +734,28 @@ export interface RouteAction { * * Pay attention to the potential security implications of using this option. Provided header * must come from trusted source. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ - 'auto_host_rewrite_header'?: (string); + 'host_rewrite_header'?: (string); /** * Indicates that the route has request mirroring policies. */ - 'request_mirror_policies'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy)[]; + 'request_mirror_policies'?: (_envoy_config_route_v3_RouteAction_RequestMirrorPolicy)[]; /** * An internal redirect is handled, iff the number of previous internal redirects that a * downstream request has encountered is lower than this value, and - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * is set to :ref:`HANDLE_INTERNAL_REDIRECT - * ` + * ` * In the case where a downstream request is bounced among multiple routes by internal redirect, * the first route that hits this threshold, or has - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * set to * :ref:`PASS_THROUGH_INTERNAL_REDIRECT - * ` + * ` * will pass the redirect back to downstream. * * If not specified, at most one redirect will be followed. @@ -682,7 +771,7 @@ export interface RouteAction { * before the rewrite into the :ref:`x-envoy-original-path * ` header. * - * Only one of :ref:`prefix_rewrite ` + * Only one of :ref:`prefix_rewrite ` * or *regex_rewrite* may be specified. * * Examples using Google's `RE2 `_ engine: @@ -702,21 +791,50 @@ export interface RouteAction { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute); + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take * precedence over the virtual host level retry policy entirely (e.g.: policies are not merged, - * most internal one becomes the enforced policy). :ref:`Retry policy ` + * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ 'retry_policy_typed_config'?: (_google_protobuf_Any); + /** + * If present, Envoy will try to follow an upstream redirect response instead of proxying the + * response back to the downstream. An upstream redirect response is defined + * by :ref:`redirect_response_codes + * `. + */ + 'internal_redirect_policy'?: (_envoy_config_route_v3_InternalRedirectPolicy); + /** + * Indicates that during forwarding, the host header will be swapped with + * the result of the regex substitution executed on path value with query and fragment removed. + * This is useful for transitioning variable content between path segment and subdomain. + * + * For example with the following config: + * + * .. code-block:: yaml + * + * host_rewrite_path_regex: + * pattern: + * google_re2: {} + * regex: "^/(.+)/.+$" + * substitution: \1 + * + * Would rewrite the host header to `envoyproxy.io` given the path `/envoyproxy.io/some/path`. + */ + 'host_rewrite_path_regex'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); + /** + * Specifies the maximum stream duration for this route. + */ + 'max_stream_duration'?: (_envoy_config_route_v3_RouteAction_MaxStreamDuration); 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"; - 'host_rewrite_specifier'?: "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; + 'host_rewrite_specifier'?: "host_rewrite_literal"|"auto_host_rewrite"|"host_rewrite_header"|"host_rewrite_path_regex"; } /** - * [#next-free-field: 34] + * [#next-free-field: 37] */ export interface RouteAction__Output { /** @@ -734,6 +852,10 @@ export interface RouteAction__Output { * * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 * *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ 'cluster_header'?: (string); /** @@ -743,15 +865,15 @@ export interface RouteAction__Output { * :ref:`traffic splitting ` * for additional documentation. */ - 'weighted_clusters'?: (_envoy_api_v2_route_WeightedCluster__Output); + 'weighted_clusters'?: (_envoy_config_route_v3_WeightedCluster__Output); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints * in the upstream cluster with metadata matching what's set in this field will be considered * for load balancing. If using :ref:`weighted_clusters - * `, metadata will be merged, with values + * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_api_v2_core_Metadata__Output); + 'metadata_match'?: (_envoy_config_core_v3_Metadata__Output); /** * Indicates that during forwarding, the matched prefix (or path) should be * swapped with this value. This option allows application URLs to be rooted @@ -760,16 +882,16 @@ export interface RouteAction__Output { * ` header. * * Only one of *prefix_rewrite* or - * :ref:`regex_rewrite ` + * :ref:`regex_rewrite ` * may be specified. * * .. attention:: * * Pay careful attention to the use of trailing slashes in the - * :ref:`route's match ` prefix value. + * :ref:`route's match ` prefix value. * Stripping a prefix from a path requires multiple Routes to handle all cases. For example, * rewriting * /prefix* to * /* and * /prefix/etc* to * /etc* cannot be done in a single - * :ref:`Route `, as shown by the below config entries: + * :ref:`Route `, as shown by the below config entries: * * .. code-block:: yaml * @@ -790,7 +912,7 @@ export interface RouteAction__Output { * Indicates that during forwarding, the host header will be swapped with * this value. */ - 'host_rewrite'?: (string); + 'host_rewrite_literal'?: (string); /** * Indicates that during forwarding, the host header will be swapped with * the hostname of the upstream host chosen by the cluster manager. This @@ -818,29 +940,23 @@ export interface RouteAction__Output { * it'll take precedence over the virtual host level retry policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy__Output); - /** - * Indicates that the route has a request mirroring policy. - * - * .. attention:: - * This field has been deprecated in favor of `request_mirror_policies` which supports one or - * more mirroring policies. - */ - 'request_mirror_policy'?: (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output); + 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy__Output); /** * Optionally specifies the :ref:`routing priority `. */ - 'priority': (keyof typeof _envoy_api_v2_core_RoutingPriority); + 'priority': (keyof typeof _envoy_config_core_v3_RoutingPriority); /** * Specifies a set of rate limit configurations that could be applied to the * route. */ - 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; + 'rate_limits': (_envoy_config_route_v3_RateLimit__Output)[]; /** * Specifies if the rate limit filter should include the virtual host rate * limits. By default, if the route configured rate limits, the virtual host - * :ref:`rate_limits ` are not applied to the + * :ref:`rate_limits ` are not applied to the * request. + * + * This field is deprecated. Please use :ref:`vh_rate_limits ` */ 'include_vh_rate_limits'?: (_google_protobuf_BoolValue__Output); /** @@ -857,25 +973,26 @@ export interface RouteAction__Output { * there is already a hash generated, the hash is returned immediately, * ignoring the rest of the hash policy list. */ - 'hash_policy': (_envoy_api_v2_route_RouteAction_HashPolicy__Output)[]; + 'hash_policy': (_envoy_config_route_v3_RouteAction_HashPolicy__Output)[]; /** * Indicates that the route has a CORS policy. */ - 'cors'?: (_envoy_api_v2_route_CorsPolicy__Output); + 'cors'?: (_envoy_config_route_v3_CorsPolicy__Output); /** * The HTTP status code to use when configured cluster is not found. * The default response code is 503 Service Unavailable. */ - 'cluster_not_found_response_code': (keyof typeof _envoy_api_v2_route_RouteAction_ClusterNotFoundResponseCode); + 'cluster_not_found_response_code': (keyof typeof _envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode); /** + * Deprecated by :ref:`grpc_timeout_header_max ` * If present, and the request is a gRPC request, use the * `grpc-timeout header `_, * or its default value (infinity) instead of - * :ref:`timeout `, but limit the applied timeout + * :ref:`timeout `, but limit the applied timeout * to the maximum value specified here. If configured as 0, the maximum allowed timeout for * gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used * and gRPC requests time out like any other requests using - * :ref:`timeout ` or its default. + * :ref:`timeout ` or its default. * This can be used to prevent unexpected upstream request timeouts due to potentially long * time gaps between gRPC request and response in gRPC streaming mode. * @@ -892,14 +1009,14 @@ export interface RouteAction__Output { /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout - * ` + * ` * will still apply. A value of 0 will completely disable the route's idle timeout, even if a * connection manager stream idle timeout is configured. * * The idle timeout is distinct to :ref:`timeout - * `, which provides an upper bound + * `, which provides an upper bound * on the upstream response time; :ref:`idle_timeout - * ` instead bounds the amount + * ` instead bounds the amount * of time the request's stream may be idle. * * After header decoding, the idle timeout will apply on downstream and @@ -908,17 +1025,22 @@ export interface RouteAction__Output { * fires, the stream is terminated with a 408 Request Timeout error code if no * upstream response header has been received, otherwise a stream reset * occurs. + * + * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" + * is configured, this timeout is scaled according to the value for + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. */ 'idle_timeout'?: (_google_protobuf_Duration__Output); - 'upgrade_configs': (_envoy_api_v2_route_RouteAction_UpgradeConfig__Output)[]; - 'internal_redirect_action': (keyof typeof _envoy_api_v2_route_RouteAction_InternalRedirectAction); + 'upgrade_configs': (_envoy_config_route_v3_RouteAction_UpgradeConfig__Output)[]; + 'internal_redirect_action': (keyof typeof _envoy_config_route_v3_RouteAction_InternalRedirectAction); /** * Indicates that the route has a hedge policy. Note that if this is set, * it'll take precedence over the virtual host level hedge policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy__Output); + 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy__Output); /** + * Deprecated by :ref:`grpc_timeout_header_offset `. * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting * the provided duration from the header. This is useful in allowing Envoy to set its global * timeout to be less than that of the deadline imposed by the calling client, which makes it more @@ -937,24 +1059,28 @@ export interface RouteAction__Output { * * Pay attention to the potential security implications of using this option. Provided header * must come from trusted source. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ - 'auto_host_rewrite_header'?: (string); + 'host_rewrite_header'?: (string); /** * Indicates that the route has request mirroring policies. */ - 'request_mirror_policies': (_envoy_api_v2_route_RouteAction_RequestMirrorPolicy__Output)[]; + 'request_mirror_policies': (_envoy_config_route_v3_RouteAction_RequestMirrorPolicy__Output)[]; /** * An internal redirect is handled, iff the number of previous internal redirects that a * downstream request has encountered is lower than this value, and - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * is set to :ref:`HANDLE_INTERNAL_REDIRECT - * ` + * ` * In the case where a downstream request is bounced among multiple routes by internal redirect, * the first route that hits this threshold, or has - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * set to * :ref:`PASS_THROUGH_INTERNAL_REDIRECT - * ` + * ` * will pass the redirect back to downstream. * * If not specified, at most one redirect will be followed. @@ -970,7 +1096,7 @@ export interface RouteAction__Output { * before the rewrite into the :ref:`x-envoy-original-path * ` header. * - * Only one of :ref:`prefix_rewrite ` + * Only one of :ref:`prefix_rewrite ` * or *regex_rewrite* may be specified. * * Examples using Google's `RE2 `_ engine: @@ -990,15 +1116,44 @@ export interface RouteAction__Output { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite'?: (_envoy_type_matcher_RegexMatchAndSubstitute__Output); + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take * precedence over the virtual host level retry policy entirely (e.g.: policies are not merged, - * most internal one becomes the enforced policy). :ref:`Retry policy ` + * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ 'retry_policy_typed_config'?: (_google_protobuf_Any__Output); + /** + * If present, Envoy will try to follow an upstream redirect response instead of proxying the + * response back to the downstream. An upstream redirect response is defined + * by :ref:`redirect_response_codes + * `. + */ + 'internal_redirect_policy'?: (_envoy_config_route_v3_InternalRedirectPolicy__Output); + /** + * Indicates that during forwarding, the host header will be swapped with + * the result of the regex substitution executed on path value with query and fragment removed. + * This is useful for transitioning variable content between path segment and subdomain. + * + * For example with the following config: + * + * .. code-block:: yaml + * + * host_rewrite_path_regex: + * pattern: + * google_re2: {} + * regex: "^/(.+)/.+$" + * substitution: \1 + * + * Would rewrite the host header to `envoyproxy.io` given the path `/envoyproxy.io/some/path`. + */ + 'host_rewrite_path_regex'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); + /** + * Specifies the maximum stream duration for this route. + */ + 'max_stream_duration'?: (_envoy_config_route_v3_RouteAction_MaxStreamDuration__Output); 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; - 'host_rewrite_specifier': "host_rewrite"|"auto_host_rewrite"|"auto_host_rewrite_header"; + 'host_rewrite_specifier': "host_rewrite_literal"|"auto_host_rewrite"|"host_rewrite_header"|"host_rewrite_path_regex"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts similarity index 63% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts index de0634c24..e9ad30257 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/RouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts @@ -1,25 +1,26 @@ -// Original file: deps/envoy-api/envoy/api/v2/route.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route.proto -import type { VirtualHost as _envoy_api_v2_route_VirtualHost, VirtualHost__Output as _envoy_api_v2_route_VirtualHost__Output } from '../../../envoy/api/v2/route/VirtualHost'; -import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../envoy/api/v2/core/HeaderValueOption'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../google/protobuf/BoolValue'; -import type { Vhds as _envoy_api_v2_Vhds, Vhds__Output as _envoy_api_v2_Vhds__Output } from '../../../envoy/api/v2/Vhds'; +import type { VirtualHost as _envoy_config_route_v3_VirtualHost, VirtualHost__Output as _envoy_config_route_v3_VirtualHost__Output } from '../../../../envoy/config/route/v3/VirtualHost'; +import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, HeaderValueOption__Output as _envoy_config_core_v3_HeaderValueOption__Output } from '../../../../envoy/config/core/v3/HeaderValueOption'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { Vhds as _envoy_config_route_v3_Vhds, Vhds__Output as _envoy_config_route_v3_Vhds__Output } from '../../../../envoy/config/route/v3/Vhds'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** - * [#next-free-field: 11] + * [#next-free-field: 12] */ export interface RouteConfiguration { /** * The name of the route configuration. For example, it might match * :ref:`route_config_name - * ` in - * :ref:`envoy_api_msg_config.filter.network.http_connection_manager.v2.Rds`. + * ` in + * :ref:`envoy_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. */ 'name'?: (string); /** * An array of virtual hosts that make up the route table. */ - 'virtual_hosts'?: (_envoy_api_v2_route_VirtualHost)[]; + 'virtual_hosts'?: (_envoy_config_route_v3_VirtualHost)[]; /** * Optionally specifies a list of HTTP headers that the connection manager * will consider to be internal only. If they are found on external requests they will be cleaned @@ -30,12 +31,12 @@ export interface RouteConfiguration { /** * Specifies a list of HTTP headers that should be added to each response that * the connection manager encodes. Headers specified at this level are applied - * after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or - * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of HTTP headers that should be removed from each response * that the connection manager encodes. @@ -44,12 +45,12 @@ export interface RouteConfiguration { /** * Specifies a list of HTTP headers that should be added to each request * routed by the HTTP connection manager. Headers specified at this level are - * applied after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or - * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * applied after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * An optional boolean that specifies whether the clusters that the route * table refers to will be validated by the cluster manager. If set to true @@ -58,10 +59,10 @@ export interface RouteConfiguration { * route table will load and the router filter will return a 404 if the route * is selected at runtime. This setting defaults to true if the route table * is statically defined via the :ref:`route_config - * ` + * ` * option. This setting default to false if the route table is loaded dynamically via the * :ref:`rds - * ` + * ` * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ @@ -79,7 +80,7 @@ export interface RouteConfiguration { * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration * taking precedence. */ - 'vhds'?: (_envoy_api_v2_Vhds); + 'vhds'?: (_envoy_config_route_v3_Vhds); /** * By default, headers that should be added/removed are evaluated from most to least specific: * @@ -93,23 +94,36 @@ export interface RouteConfiguration { * [#next-major-version: In the v3 API, this will default to true.] */ 'most_specific_header_mutations_wins'?: (boolean); + /** + * The maximum bytes of the response :ref:`direct response body + * ` size. If not specified the default + * is 4096. + * + * .. warning:: + * + * Envoy currently holds the content of :ref:`direct response body + * ` in memory. Be careful setting + * this to be larger than the default 4KB, since the allocated memory for direct response body + * is not subject to data plane buffering controls. + */ + 'max_direct_response_body_size_bytes'?: (_google_protobuf_UInt32Value); } /** - * [#next-free-field: 11] + * [#next-free-field: 12] */ export interface RouteConfiguration__Output { /** * The name of the route configuration. For example, it might match * :ref:`route_config_name - * ` in - * :ref:`envoy_api_msg_config.filter.network.http_connection_manager.v2.Rds`. + * ` in + * :ref:`envoy_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. */ 'name': (string); /** * An array of virtual hosts that make up the route table. */ - 'virtual_hosts': (_envoy_api_v2_route_VirtualHost__Output)[]; + 'virtual_hosts': (_envoy_config_route_v3_VirtualHost__Output)[]; /** * Optionally specifies a list of HTTP headers that the connection manager * will consider to be internal only. If they are found on external requests they will be cleaned @@ -120,12 +134,12 @@ export interface RouteConfiguration__Output { /** * Specifies a list of HTTP headers that should be added to each response that * the connection manager encodes. Headers specified at this level are applied - * after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or - * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of HTTP headers that should be removed from each response * that the connection manager encodes. @@ -134,12 +148,12 @@ export interface RouteConfiguration__Output { /** * Specifies a list of HTTP headers that should be added to each request * routed by the HTTP connection manager. Headers specified at this level are - * applied after headers from any enclosed :ref:`envoy_api_msg_route.VirtualHost` or - * :ref:`envoy_api_msg_route.RouteAction`. For more information, including details on + * applied after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * An optional boolean that specifies whether the clusters that the route * table refers to will be validated by the cluster manager. If set to true @@ -148,10 +162,10 @@ export interface RouteConfiguration__Output { * route table will load and the router filter will return a 404 if the route * is selected at runtime. This setting defaults to true if the route table * is statically defined via the :ref:`route_config - * ` + * ` * option. This setting default to false if the route table is loaded dynamically via the * :ref:`rds - * ` + * ` * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ @@ -169,7 +183,7 @@ export interface RouteConfiguration__Output { * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration * taking precedence. */ - 'vhds'?: (_envoy_api_v2_Vhds__Output); + 'vhds'?: (_envoy_config_route_v3_Vhds__Output); /** * By default, headers that should be added/removed are evaluated from most to least specific: * @@ -183,4 +197,17 @@ export interface RouteConfiguration__Output { * [#next-major-version: In the v3 API, this will default to true.] */ 'most_specific_header_mutations_wins': (boolean); + /** + * The maximum bytes of the response :ref:`direct response body + * ` size. If not specified the default + * is 4096. + * + * .. warning:: + * + * Envoy currently holds the content of :ref:`direct response body + * ` in memory. Be careful setting + * this to be larger than the default 4KB, since the allocated memory for direct response body + * is not subject to data plane buffering controls. + */ + 'max_direct_response_body_size_bytes'?: (_google_protobuf_UInt32Value__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts similarity index 67% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts index b055c0506..d941bcfd1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/RouteMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts @@ -1,18 +1,30 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; -import type { QueryParameterMatcher as _envoy_api_v2_route_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_api_v2_route_QueryParameterMatcher__Output } from '../../../../envoy/api/v2/route/QueryParameterMatcher'; -import type { RuntimeFractionalPercent as _envoy_api_v2_core_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_api_v2_core_RuntimeFractionalPercent__Output } from '../../../../envoy/api/v2/core/RuntimeFractionalPercent'; -import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../../envoy/type/matcher/RegexMatcher'; +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; +import type { QueryParameterMatcher as _envoy_config_route_v3_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_config_route_v3_QueryParameterMatcher__Output } from '../../../../envoy/config/route/v3/QueryParameterMatcher'; +import type { RuntimeFractionalPercent as _envoy_config_core_v3_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_config_core_v3_RuntimeFractionalPercent__Output } from '../../../../envoy/config/core/v3/RuntimeFractionalPercent'; +import type { RegexMatcher as _envoy_type_matcher_v3_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_v3_RegexMatcher__Output } from '../../../../envoy/type/matcher/v3/RegexMatcher'; -export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions { +/** + * An extensible message for matching CONNECT requests. + */ +export interface _envoy_config_route_v3_RouteMatch_ConnectMatcher { +} + +/** + * An extensible message for matching CONNECT requests. + */ +export interface _envoy_config_route_v3_RouteMatch_ConnectMatcher__Output { +} + +export interface _envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions { } -export interface _envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output { +export interface _envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions__Output { } -export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions { +export interface _envoy_config_route_v3_RouteMatch_TlsContextMatchOptions { /** * If specified, the route will match against whether or not a certificate is presented. * If not specified, certificate presentation status (true or false) will not be considered when route matching. @@ -25,7 +37,7 @@ export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions { 'validated'?: (_google_protobuf_BoolValue); } -export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output { +export interface _envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Output { /** * If specified, the route will match against whether or not a certificate is presented. * If not specified, certificate presentation status (true or false) will not be considered when route matching. @@ -39,7 +51,7 @@ export interface _envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output { } /** - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface RouteMatch { /** @@ -53,26 +65,7 @@ export interface RouteMatch { */ 'path'?: (string); /** - * If specified, the route is a regular expression rule meaning that the - * regex must match the *:path* header once the query string is removed. The entire path - * (without the query string) must match the regex. The rule will not match if only a - * subsequence of the *:path* header matches the regex. The regex grammar is defined `here - * `_. - * - * Examples: - * - * * The regex ``/b[io]t`` matches the path * /bit* - * * The regex ``/b[io]t`` matches the path * /bot* - * * The regex ``/b[io]t`` does not match the path * /bite* - * * The regex ``/b[io]t`` does not match the path * /bit/bot* - * - * .. attention:: - * This field has been deprecated in favor of `safe_regex` as it is not safe for use with - * untrusted input in all cases. - */ - 'regex'?: (string); - /** - * Indicates that prefix/path matching should be case insensitive. The default + * Indicates that prefix/path matching should be case sensitive. The default * is true. */ 'case_sensitive'?: (_google_protobuf_BoolValue); @@ -83,7 +76,7 @@ export interface RouteMatch { * the request with the same values (or based on presence if the value field * is not in the config). */ - 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + 'headers'?: (_envoy_config_route_v3_HeaderMatcher)[]; /** * Specifies a set of URL query parameters on which the route should * match. The router will check the query string from the *path* header @@ -91,13 +84,13 @@ export interface RouteMatch { * query parameters is nonzero, they all must match the *path* header's * query string for a match to occur. */ - 'query_parameters'?: (_envoy_api_v2_route_QueryParameterMatcher)[]; + 'query_parameters'?: (_envoy_config_route_v3_QueryParameterMatcher)[]; /** * If specified, only gRPC requests will be matched. The router will check * that the content-type header has a application/grpc or one of the various * application/grpc+ values. */ - 'grpc'?: (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions); + 'grpc'?: (_envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions); /** * Indicates that the route should additionally match on a runtime key. Every time the route * is considered for a match, it must also fall under the percentage of matches indicated by @@ -116,7 +109,7 @@ export interface RouteMatch { * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. */ - 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent); + 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent); /** * If specified, the route is a regular expression rule meaning that the * regex must match the *:path* header once the query string is removed. The entire path @@ -131,19 +124,31 @@ export interface RouteMatch { * on :path, etc. The issue with that is it is unclear how to generically deal with query string * stripping. This needs more thought.] */ - 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher); /** * If specified, the client tls context will be matched against the defined * match options. * * [#next-major-version: unify with RBAC] */ - 'tls_context'?: (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions); - 'path_specifier'?: "prefix"|"path"|"regex"|"safe_regex"; + 'tls_context'?: (_envoy_config_route_v3_RouteMatch_TlsContextMatchOptions); + /** + * If this is used as the matcher, the matcher will only match CONNECT requests. + * Note that this will not match HTTP/2 upgrade-style CONNECT requests + * (WebSocket and the like) as they are normalized in Envoy as HTTP/1.1 style + * upgrades. + * This is the only way to match CONNECT requests for HTTP/1.1. For HTTP/2, + * where Extended CONNECT requests may have a path, the path matchers will work if + * there is a path present. + * Note that CONNECT support is currently considered alpha in Envoy. + * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + */ + 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher); + 'path_specifier'?: "prefix"|"path"|"safe_regex"|"connect_matcher"; } /** - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface RouteMatch__Output { /** @@ -157,26 +162,7 @@ export interface RouteMatch__Output { */ 'path'?: (string); /** - * If specified, the route is a regular expression rule meaning that the - * regex must match the *:path* header once the query string is removed. The entire path - * (without the query string) must match the regex. The rule will not match if only a - * subsequence of the *:path* header matches the regex. The regex grammar is defined `here - * `_. - * - * Examples: - * - * * The regex ``/b[io]t`` matches the path * /bit* - * * The regex ``/b[io]t`` matches the path * /bot* - * * The regex ``/b[io]t`` does not match the path * /bite* - * * The regex ``/b[io]t`` does not match the path * /bit/bot* - * - * .. attention:: - * This field has been deprecated in favor of `safe_regex` as it is not safe for use with - * untrusted input in all cases. - */ - 'regex'?: (string); - /** - * Indicates that prefix/path matching should be case insensitive. The default + * Indicates that prefix/path matching should be case sensitive. The default * is true. */ 'case_sensitive'?: (_google_protobuf_BoolValue__Output); @@ -187,7 +173,7 @@ export interface RouteMatch__Output { * the request with the same values (or based on presence if the value field * is not in the config). */ - 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + 'headers': (_envoy_config_route_v3_HeaderMatcher__Output)[]; /** * Specifies a set of URL query parameters on which the route should * match. The router will check the query string from the *path* header @@ -195,13 +181,13 @@ export interface RouteMatch__Output { * query parameters is nonzero, they all must match the *path* header's * query string for a match to occur. */ - 'query_parameters': (_envoy_api_v2_route_QueryParameterMatcher__Output)[]; + 'query_parameters': (_envoy_config_route_v3_QueryParameterMatcher__Output)[]; /** * If specified, only gRPC requests will be matched. The router will check * that the content-type header has a application/grpc or one of the various * application/grpc+ values. */ - 'grpc'?: (_envoy_api_v2_route_RouteMatch_GrpcRouteMatchOptions__Output); + 'grpc'?: (_envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions__Output); /** * Indicates that the route should additionally match on a runtime key. Every time the route * is considered for a match, it must also fall under the percentage of matches indicated by @@ -220,7 +206,7 @@ export interface RouteMatch__Output { * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. */ - 'runtime_fraction'?: (_envoy_api_v2_core_RuntimeFractionalPercent__Output); + 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); /** * If specified, the route is a regular expression rule meaning that the * regex must match the *:path* header once the query string is removed. The entire path @@ -235,13 +221,25 @@ export interface RouteMatch__Output { * on :path, etc. The issue with that is it is unclear how to generically deal with query string * stripping. This needs more thought.] */ - 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output); /** * If specified, the client tls context will be matched against the defined * match options. * * [#next-major-version: unify with RBAC] */ - 'tls_context'?: (_envoy_api_v2_route_RouteMatch_TlsContextMatchOptions__Output); - 'path_specifier': "prefix"|"path"|"regex"|"safe_regex"; + 'tls_context'?: (_envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Output); + /** + * If this is used as the matcher, the matcher will only match CONNECT requests. + * Note that this will not match HTTP/2 upgrade-style CONNECT requests + * (WebSocket and the like) as they are normalized in Envoy as HTTP/1.1 style + * upgrades. + * This is the only way to match CONNECT requests for HTTP/1.1. For HTTP/2, + * where Extended CONNECT requests may have a path, the path matchers will work if + * there is a path present. + * Note that CONNECT support is currently considered alpha in Envoy. + * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + */ + 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher__Output); + 'path_specifier': "prefix"|"path"|"safe_regex"|"connect_matcher"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts similarity index 59% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts index 02810bf02..afbb9886b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/ScopedRouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts @@ -1,7 +1,7 @@ -// Original file: deps/envoy-api/envoy/api/v2/scoped_route.proto +// Original file: deps/envoy-api/envoy/config/route/v3/scoped_route.proto -export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment { +export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment { /** * A string to match against. */ @@ -9,7 +9,7 @@ export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment { 'type'?: "string_key"; } -export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output { +export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment__Output { /** * A string to match against. */ @@ -19,45 +19,45 @@ export interface _envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output { /** * Specifies a key which is matched against the output of the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * specified in the HttpConnectionManager. The matching is done per HTTP * request and is dependent on the order of the fragments contained in the * Key. */ -export interface _envoy_api_v2_ScopedRouteConfiguration_Key { +export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key { /** * The ordered set of fragments to match against. The order must match the * fragments in the corresponding - * :ref:`scope_key_builder`. + * :ref:`scope_key_builder`. */ - 'fragments'?: (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment)[]; + 'fragments'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment)[]; } /** * Specifies a key which is matched against the output of the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * specified in the HttpConnectionManager. The matching is done per HTTP * request and is dependent on the order of the fragments contained in the * Key. */ -export interface _envoy_api_v2_ScopedRouteConfiguration_Key__Output { +export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key__Output { /** * The ordered set of fragments to match against. The order must match the * fragments in the corresponding - * :ref:`scope_key_builder`. + * :ref:`scope_key_builder`. */ - 'fragments': (_envoy_api_v2_ScopedRouteConfiguration_Key_Fragment__Output)[]; + 'fragments': (_envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment__Output)[]; } /** * Specifies a routing scope, which associates a - * :ref:`Key` to a - * :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). + * :ref:`Key` to a + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` (identified by its resource name). * * The HTTP connection manager builds up a table consisting of these Key to * RouteConfiguration mappings, and looks up the RouteConfiguration to use per * request according to the algorithm specified in the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * assigned to the HttpConnectionManager. * * For example, with the following configurations (in YAML): @@ -79,7 +79,7 @@ export interface _envoy_api_v2_ScopedRouteConfiguration_Key__Output { * key: vip * * ScopedRouteConfiguration resources (specified statically via - * :ref:`scoped_route_configurations_list` + * :ref:`scoped_route_configurations_list` * or obtained dynamically via SRDS): * * .. code:: @@ -115,26 +115,30 @@ export interface ScopedRouteConfiguration { */ 'name'?: (string); /** - * The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an - * RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + * The resource name to use for a :ref:`envoy_api_msg_service.discovery.v3.DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` associated * with this scope. */ 'route_configuration_name'?: (string); /** * The key to match against. */ - 'key'?: (_envoy_api_v2_ScopedRouteConfiguration_Key); + 'key'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key); + /** + * Whether the RouteConfiguration should be loaded on demand. + */ + 'on_demand'?: (boolean); } /** * Specifies a routing scope, which associates a - * :ref:`Key` to a - * :ref:`envoy_api_msg_RouteConfiguration` (identified by its resource name). + * :ref:`Key` to a + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` (identified by its resource name). * * The HTTP connection manager builds up a table consisting of these Key to * RouteConfiguration mappings, and looks up the RouteConfiguration to use per * request according to the algorithm specified in the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * assigned to the HttpConnectionManager. * * For example, with the following configurations (in YAML): @@ -156,7 +160,7 @@ export interface ScopedRouteConfiguration { * key: vip * * ScopedRouteConfiguration resources (specified statically via - * :ref:`scoped_route_configurations_list` + * :ref:`scoped_route_configurations_list` * or obtained dynamically via SRDS): * * .. code:: @@ -192,13 +196,17 @@ export interface ScopedRouteConfiguration__Output { */ 'name': (string); /** - * The resource name to use for a :ref:`envoy_api_msg_DiscoveryRequest` to an - * RDS server to fetch the :ref:`envoy_api_msg_RouteConfiguration` associated + * The resource name to use for a :ref:`envoy_api_msg_service.discovery.v3.DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` associated * with this scope. */ 'route_configuration_name': (string); /** * The key to match against. */ - 'key'?: (_envoy_api_v2_ScopedRouteConfiguration_Key__Output); + 'key'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key__Output); + /** + * Whether the RouteConfiguration should be loaded on demand. + */ + 'on_demand': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts similarity index 75% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts index 18b063339..5be619a5f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts @@ -1,7 +1,7 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; -import type { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../envoy/type/tracing/v2/CustomTag'; +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../envoy/type/v3/FractionalPercent'; +import type { CustomTag as _envoy_type_tracing_v3_CustomTag, CustomTag__Output as _envoy_type_tracing_v3_CustomTag__Output } from '../../../../envoy/type/tracing/v3/CustomTag'; export interface Tracing { /** @@ -12,7 +12,7 @@ export interface Tracing { * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_FractionalPercent); + 'client_sampling'?: (_envoy_type_v3_FractionalPercent); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -20,7 +20,7 @@ export interface Tracing { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_FractionalPercent); + 'random_sampling'?: (_envoy_type_v3_FractionalPercent); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -31,16 +31,16 @@ export interface Tracing { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_FractionalPercent); + 'overall_sampling'?: (_envoy_type_v3_FractionalPercent); /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration - * ` + * ` * configured in the HTTP connection manager. If two tags with the same name are configured * each in the HTTP connection manager and the route level, the one configured here takes * priority. */ - 'custom_tags'?: (_envoy_type_tracing_v2_CustomTag)[]; + 'custom_tags'?: (_envoy_type_tracing_v3_CustomTag)[]; } export interface Tracing__Output { @@ -52,7 +52,7 @@ export interface Tracing__Output { * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_FractionalPercent__Output); + 'client_sampling'?: (_envoy_type_v3_FractionalPercent__Output); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -60,7 +60,7 @@ export interface Tracing__Output { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_FractionalPercent__Output); + 'random_sampling'?: (_envoy_type_v3_FractionalPercent__Output); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -71,14 +71,14 @@ export interface Tracing__Output { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_FractionalPercent__Output); + 'overall_sampling'?: (_envoy_type_v3_FractionalPercent__Output); /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration - * ` + * ` * configured in the HTTP connection manager. If two tags with the same name are configured * each in the HTTP connection manager and the route level, the one configured here takes * priority. */ - 'custom_tags': (_envoy_type_tracing_v2_CustomTag__Output)[]; + 'custom_tags': (_envoy_type_tracing_v3_CustomTag__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts new file mode 100644 index 000000000..2868685b2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route.proto + +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../envoy/config/core/v3/ConfigSource'; + +export interface Vhds { + /** + * Configuration source specifier for VHDS. + */ + 'config_source'?: (_envoy_config_core_v3_ConfigSource); +} + +export interface Vhds__Output { + /** + * Configuration source specifier for VHDS. + */ + 'config_source'?: (_envoy_config_core_v3_ConfigSource__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualCluster.ts similarity index 58% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualCluster.ts index f072710ce..7674da733 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualCluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualCluster.ts @@ -1,7 +1,6 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { RequestMethod as _envoy_api_v2_core_RequestMethod } from '../../../../envoy/api/v2/core/RequestMethod'; -import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher__Output as _envoy_api_v2_route_HeaderMatcher__Output } from '../../../../envoy/api/v2/route/HeaderMatcher'; +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; /** * A virtual cluster is a way of specifying a regex matching rule against @@ -23,42 +22,18 @@ import type { HeaderMatcher as _envoy_api_v2_route_HeaderMatcher, HeaderMatcher_ * statistics output are not free. */ export interface VirtualCluster { - /** - * Specifies a regex pattern to use for matching requests. The entire path of the request - * must match the regex. The regex grammar used is defined `here - * `_. - * - * Examples: - * - * * The regex ``/rides/\d+`` matches the path * /rides/0* - * * The regex ``/rides/\d+`` matches the path * /rides/123* - * * The regex ``/rides/\d+`` does not match the path * /rides/123/456* - * - * .. attention:: - * This field has been deprecated in favor of `headers` as it is not safe for use with - * untrusted input in all cases. - */ - 'pattern'?: (string); /** * Specifies the name of the virtual cluster. The virtual cluster name as well * as the virtual host name are used when emitting statistics. The statistics are emitted by the * router filter and are documented :ref:`here `. */ 'name'?: (string); - /** - * Optionally specifies the HTTP method to match on. For example GET, PUT, - * etc. - * - * .. attention:: - * This field has been deprecated in favor of `headers`. - */ - 'method'?: (_envoy_api_v2_core_RequestMethod | keyof typeof _envoy_api_v2_core_RequestMethod); /** * Specifies a list of header matchers to use for matching requests. Each specified header must * match. The pseudo-headers `:path` and `:method` can be used to match the request path and * method, respectively. */ - 'headers'?: (_envoy_api_v2_route_HeaderMatcher)[]; + 'headers'?: (_envoy_config_route_v3_HeaderMatcher)[]; } /** @@ -81,40 +56,16 @@ export interface VirtualCluster { * statistics output are not free. */ export interface VirtualCluster__Output { - /** - * Specifies a regex pattern to use for matching requests. The entire path of the request - * must match the regex. The regex grammar used is defined `here - * `_. - * - * Examples: - * - * * The regex ``/rides/\d+`` matches the path * /rides/0* - * * The regex ``/rides/\d+`` matches the path * /rides/123* - * * The regex ``/rides/\d+`` does not match the path * /rides/123/456* - * - * .. attention:: - * This field has been deprecated in favor of `headers` as it is not safe for use with - * untrusted input in all cases. - */ - 'pattern': (string); /** * Specifies the name of the virtual cluster. The virtual cluster name as well * as the virtual host name are used when emitting statistics. The statistics are emitted by the * router filter and are documented :ref:`here `. */ 'name': (string); - /** - * Optionally specifies the HTTP method to match on. For example GET, PUT, - * etc. - * - * .. attention:: - * This field has been deprecated in favor of `headers`. - */ - 'method': (keyof typeof _envoy_api_v2_core_RequestMethod); /** * Specifies a list of header matchers to use for matching requests. Each specified header must * match. The pseudo-headers `:path` and `:method` can be used to match the request path and * method, respectively. */ - 'headers': (_envoy_api_v2_route_HeaderMatcher__Output)[]; + 'headers': (_envoy_config_route_v3_HeaderMatcher__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts similarity index 71% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts index ad806e949..86088ded6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/VirtualHost.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts @@ -1,19 +1,18 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -import type { Route as _envoy_api_v2_route_Route, Route__Output as _envoy_api_v2_route_Route__Output } from '../../../../envoy/api/v2/route/Route'; -import type { VirtualCluster as _envoy_api_v2_route_VirtualCluster, VirtualCluster__Output as _envoy_api_v2_route_VirtualCluster__Output } from '../../../../envoy/api/v2/route/VirtualCluster'; -import type { RateLimit as _envoy_api_v2_route_RateLimit, RateLimit__Output as _envoy_api_v2_route_RateLimit__Output } from '../../../../envoy/api/v2/route/RateLimit'; -import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import type { CorsPolicy as _envoy_api_v2_route_CorsPolicy, CorsPolicy__Output as _envoy_api_v2_route_CorsPolicy__Output } from '../../../../envoy/api/v2/route/CorsPolicy'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Route as _envoy_config_route_v3_Route, Route__Output as _envoy_config_route_v3_Route__Output } from '../../../../envoy/config/route/v3/Route'; +import type { VirtualCluster as _envoy_config_route_v3_VirtualCluster, VirtualCluster__Output as _envoy_config_route_v3_VirtualCluster__Output } from '../../../../envoy/config/route/v3/VirtualCluster'; +import type { RateLimit as _envoy_config_route_v3_RateLimit, RateLimit__Output as _envoy_config_route_v3_RateLimit__Output } from '../../../../envoy/config/route/v3/RateLimit'; +import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, HeaderValueOption__Output as _envoy_config_core_v3_HeaderValueOption__Output } from '../../../../envoy/config/core/v3/HeaderValueOption'; +import type { CorsPolicy as _envoy_config_route_v3_CorsPolicy, CorsPolicy__Output as _envoy_config_route_v3_CorsPolicy__Output } from '../../../../envoy/config/route/v3/CorsPolicy'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; -import type { RetryPolicy as _envoy_api_v2_route_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_route_RetryPolicy__Output } from '../../../../envoy/api/v2/route/RetryPolicy'; -import type { HedgePolicy as _envoy_api_v2_route_HedgePolicy, HedgePolicy__Output as _envoy_api_v2_route_HedgePolicy__Output } from '../../../../envoy/api/v2/route/HedgePolicy'; +import type { RetryPolicy as _envoy_config_route_v3_RetryPolicy, RetryPolicy__Output as _envoy_config_route_v3_RetryPolicy__Output } from '../../../../envoy/config/route/v3/RetryPolicy'; +import type { HedgePolicy as _envoy_config_route_v3_HedgePolicy, HedgePolicy__Output as _envoy_config_route_v3_HedgePolicy__Output } from '../../../../envoy/config/route/v3/HedgePolicy'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto -export enum _envoy_api_v2_route_VirtualHost_TlsRequirementType { +export enum _envoy_config_route_v3_VirtualHost_TlsRequirementType { /** * No TLS requirement for the virtual host. */ @@ -69,57 +68,49 @@ export interface VirtualHost { * The list of routes that will be matched, in order, for incoming requests. * The first route that matches will be used. */ - 'routes'?: (_envoy_api_v2_route_Route)[]; + 'routes'?: (_envoy_config_route_v3_Route)[]; /** * Specifies the type of TLS enforcement the virtual host expects. If this option is not * specified, there is no TLS requirement for the virtual host. */ - 'require_tls'?: (_envoy_api_v2_route_VirtualHost_TlsRequirementType | keyof typeof _envoy_api_v2_route_VirtualHost_TlsRequirementType); + 'require_tls'?: (_envoy_config_route_v3_VirtualHost_TlsRequirementType | keyof typeof _envoy_config_route_v3_VirtualHost_TlsRequirementType); /** * A list of virtual clusters defined for this virtual host. Virtual clusters * are used for additional statistics gathering. */ - 'virtual_clusters'?: (_envoy_api_v2_route_VirtualCluster)[]; + 'virtual_clusters'?: (_envoy_config_route_v3_VirtualCluster)[]; /** * Specifies a set of rate limit configurations that will be applied to the * virtual host. */ - 'rate_limits'?: (_envoy_api_v2_route_RateLimit)[]; + 'rate_limits'?: (_envoy_config_route_v3_RateLimit)[]; /** * Specifies a list of HTTP headers that should be added to each request * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Indicates that the virtual host has a CORS policy. */ - 'cors'?: (_envoy_api_v2_route_CorsPolicy); + 'cors'?: (_envoy_config_route_v3_CorsPolicy); /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of HTTP headers that should be removed from each response * handled by this virtual host. */ 'response_headers_to_remove'?: (string)[]; - /** - * The per_filter_config field can be used to provide virtual host-specific - * configurations for filters. The key should match the filter name, such as - * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter - * specific; see the :ref:`HTTP filter documentation ` - * for if and how it is utilized. - */ - 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct}); /** * Specifies a list of HTTP headers that should be removed from each request * handled by this virtual host. @@ -133,7 +124,7 @@ export interface VirtualHost { * will see the attempt count as perceived by the second Envoy. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. * * [#next-major-version: rename to include_attempt_count_in_request.] */ @@ -144,6 +135,9 @@ export interface VirtualHost { * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. + * [#comment: An entry's value may be wrapped in a + * :ref:`FilterConfig` + * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); /** @@ -151,13 +145,13 @@ export interface VirtualHost { * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy); + 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy); /** * Indicates the hedge policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy); + 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy); /** * The maximum bytes which will be buffered for retries and shadowing. * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum @@ -172,14 +166,14 @@ export interface VirtualHost { * will see the attempt count as perceived by the Envoy closest upstream from itself. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. */ 'include_attempt_count_in_response'?: (boolean); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that setting a route level entry * will take precedence over this config and it'll be treated independently (e.g.: values are not - * inherited). :ref:`Retry policy ` should not be + * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ 'retry_policy_typed_config'?: (_google_protobuf_Any); @@ -224,57 +218,49 @@ export interface VirtualHost__Output { * The list of routes that will be matched, in order, for incoming requests. * The first route that matches will be used. */ - 'routes': (_envoy_api_v2_route_Route__Output)[]; + 'routes': (_envoy_config_route_v3_Route__Output)[]; /** * Specifies the type of TLS enforcement the virtual host expects. If this option is not * specified, there is no TLS requirement for the virtual host. */ - 'require_tls': (keyof typeof _envoy_api_v2_route_VirtualHost_TlsRequirementType); + 'require_tls': (keyof typeof _envoy_config_route_v3_VirtualHost_TlsRequirementType); /** * A list of virtual clusters defined for this virtual host. Virtual clusters * are used for additional statistics gathering. */ - 'virtual_clusters': (_envoy_api_v2_route_VirtualCluster__Output)[]; + 'virtual_clusters': (_envoy_config_route_v3_VirtualCluster__Output)[]; /** * Specifies a set of rate limit configurations that will be applied to the * virtual host. */ - 'rate_limits': (_envoy_api_v2_route_RateLimit__Output)[]; + 'rate_limits': (_envoy_config_route_v3_RateLimit__Output)[]; /** * Specifies a list of HTTP headers that should be added to each request * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Indicates that the virtual host has a CORS policy. */ - 'cors'?: (_envoy_api_v2_route_CorsPolicy__Output); + 'cors'?: (_envoy_config_route_v3_CorsPolicy__Output); /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_route.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of HTTP headers that should be removed from each response * handled by this virtual host. */ 'response_headers_to_remove': (string)[]; - /** - * The per_filter_config field can be used to provide virtual host-specific - * configurations for filters. The key should match the filter name, such as - * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter - * specific; see the :ref:`HTTP filter documentation ` - * for if and how it is utilized. - */ - 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct__Output}); /** * Specifies a list of HTTP headers that should be removed from each request * handled by this virtual host. @@ -288,7 +274,7 @@ export interface VirtualHost__Output { * will see the attempt count as perceived by the second Envoy. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. * * [#next-major-version: rename to include_attempt_count_in_request.] */ @@ -299,6 +285,9 @@ export interface VirtualHost__Output { * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. + * [#comment: An entry's value may be wrapped in a + * :ref:`FilterConfig` + * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); /** @@ -306,13 +295,13 @@ export interface VirtualHost__Output { * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'retry_policy'?: (_envoy_api_v2_route_RetryPolicy__Output); + 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy__Output); /** * Indicates the hedge policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'hedge_policy'?: (_envoy_api_v2_route_HedgePolicy__Output); + 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy__Output); /** * The maximum bytes which will be buffered for retries and shadowing. * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum @@ -327,14 +316,14 @@ export interface VirtualHost__Output { * will see the attempt count as perceived by the Envoy closest upstream from itself. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. */ 'include_attempt_count_in_response': (boolean); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that setting a route level entry * will take precedence over this config and it'll be treated independently (e.g.: values are not - * inherited). :ref:`Retry policy ` should not be + * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ 'retry_policy_typed_config'?: (_google_protobuf_Any__Output); diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts similarity index 64% rename from packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts rename to packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts index 5b283404b..7974508ea 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/route/WeightedCluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts @@ -1,15 +1,14 @@ -// Original file: deps/envoy-api/envoy/api/v2/route/route_components.proto +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; -import type { Metadata as _envoy_api_v2_core_Metadata, Metadata__Output as _envoy_api_v2_core_Metadata__Output } from '../../../../envoy/api/v2/core/Metadata'; -import type { HeaderValueOption as _envoy_api_v2_core_HeaderValueOption, HeaderValueOption__Output as _envoy_api_v2_core_HeaderValueOption__Output } from '../../../../envoy/api/v2/core/HeaderValueOption'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Metadata as _envoy_config_core_v3_Metadata, Metadata__Output as _envoy_config_core_v3_Metadata__Output } from '../../../../envoy/config/core/v3/Metadata'; +import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, HeaderValueOption__Output as _envoy_config_core_v3_HeaderValueOption__Output } from '../../../../envoy/config/core/v3/HeaderValueOption'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * [#next-free-field: 11] */ -export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { +export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight { /** * Name of the upstream cluster. The cluster must exist in the * :ref:`cluster manager configuration `. @@ -17,7 +16,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { 'name'?: (string); /** * An integer between 0 and :ref:`total_weight - * `. When a request matches the route, + * `. When a request matches the route, * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ @@ -26,38 +25,38 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for * load balancing. Note that this will be merged with what's provided in - * :ref:`RouteAction.metadata_match `, with + * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_api_v2_core_Metadata); + 'metadata_match'?: (_envoy_config_core_v3_Metadata); /** * Specifies a list of headers to be added to requests when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'request_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of HTTP headers that should be removed from each request when - * this cluster is selected through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * this cluster is selected through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. */ 'request_headers_to_remove'?: (string)[]; /** * Specifies a list of headers to be added to responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'response_headers_to_add'?: (_envoy_api_v2_core_HeaderValueOption)[]; + 'response_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of headers to be removed from responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. */ 'response_headers_to_remove'?: (string)[]; /** @@ -66,14 +65,9 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. - */ - 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct}); - /** - * The per_filter_config field can be used to provide weighted cluster-specific - * configurations for filters. The key should match the filter name, such as - * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter - * specific; see the :ref:`HTTP filter documentation ` - * for if and how it is utilized. + * [#comment: An entry's value may be wrapped in a + * :ref:`FilterConfig` + * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); } @@ -81,7 +75,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight { /** * [#next-free-field: 11] */ -export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { +export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { /** * Name of the upstream cluster. The cluster must exist in the * :ref:`cluster manager configuration `. @@ -89,7 +83,7 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { 'name': (string); /** * An integer between 0 and :ref:`total_weight - * `. When a request matches the route, + * `. When a request matches the route, * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ @@ -98,38 +92,38 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for * load balancing. Note that this will be merged with what's provided in - * :ref:`RouteAction.metadata_match `, with + * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_api_v2_core_Metadata__Output); + 'metadata_match'?: (_envoy_config_core_v3_Metadata__Output); /** * Specifies a list of headers to be added to requests when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'request_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'request_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of HTTP headers that should be removed from each request when - * this cluster is selected through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * this cluster is selected through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. */ 'request_headers_to_remove': (string)[]; /** * Specifies a list of headers to be added to responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_route.Route`, :ref:`envoy_api_msg_route.VirtualHost`, and - * :ref:`envoy_api_msg_RouteConfiguration`. For more information, including details on + * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ - 'response_headers_to_add': (_envoy_api_v2_core_HeaderValueOption__Output)[]; + 'response_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of headers to be removed from responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_route.RouteAction`. + * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. */ 'response_headers_to_remove': (string)[]; /** @@ -138,22 +132,17 @@ export interface _envoy_api_v2_route_WeightedCluster_ClusterWeight__Output { * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. - */ - 'per_filter_config'?: ({[key: string]: _google_protobuf_Struct__Output}); - /** - * The per_filter_config field can be used to provide weighted cluster-specific - * configurations for filters. The key should match the filter name, such as - * *envoy.filters.http.buffer* for the HTTP buffer filter. Use of this field is filter - * specific; see the :ref:`HTTP filter documentation ` - * for if and how it is utilized. + * [#comment: An entry's value may be wrapped in a + * :ref:`FilterConfig` + * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); } /** - * Compared to the :ref:`cluster ` field that specifies a + * Compared to the :ref:`cluster ` field that specifies a * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of + * ` option allows for specification of * multiple upstream clusters along with weights that indicate the percentage of * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the * weights. @@ -162,7 +151,7 @@ export interface WeightedCluster { /** * Specifies one or more upstream clusters associated with the route. */ - 'clusters'?: (_envoy_api_v2_route_WeightedCluster_ClusterWeight)[]; + 'clusters'?: (_envoy_config_route_v3_WeightedCluster_ClusterWeight)[]; /** * Specifies the runtime key prefix that should be used to construct the * runtime keys associated with each cluster. When the *runtime_key_prefix* is @@ -182,9 +171,9 @@ export interface WeightedCluster { } /** - * Compared to the :ref:`cluster ` field that specifies a + * Compared to the :ref:`cluster ` field that specifies a * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of + * ` option allows for specification of * multiple upstream clusters along with weights that indicate the percentage of * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the * weights. @@ -193,7 +182,7 @@ export interface WeightedCluster__Output { /** * Specifies one or more upstream clusters associated with the route. */ - 'clusters': (_envoy_api_v2_route_WeightedCluster_ClusterWeight__Output)[]; + 'clusters': (_envoy_config_route_v3_WeightedCluster_ClusterWeight__Output)[]; /** * Specifies the runtime key prefix that should be used to construct the * runtime keys associated with each cluster. When the *runtime_key_prefix* is diff --git a/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts similarity index 54% rename from packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts rename to packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts index 629e3f1cc..36dfade51 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/trace/v2/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts @@ -1,17 +1,16 @@ -// Original file: deps/envoy-api/envoy/config/trace/v2/http_tracer.proto +// Original file: deps/envoy-api/envoy/config/trace/v3/http_tracer.proto -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * Configuration for an HTTP tracer provider used by Envoy. * * The configuration is defined by the - * :ref:`HttpConnectionManager.Tracing ` - * :ref:`provider ` + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` * field. */ -export interface _envoy_config_trace_v2_Tracing_Http { +export interface _envoy_config_trace_v3_Tracing_Http { /** * The name of the HTTP trace driver to instantiate. The name must match a * supported HTTP trace driver. Built-in trace drivers: @@ -24,31 +23,30 @@ export interface _envoy_config_trace_v2_Tracing_Http { * - *envoy.tracers.xray* */ 'name'?: (string); - 'config'?: (_google_protobuf_Struct); 'typed_config'?: (_google_protobuf_Any); /** * Trace driver specific configuration which depends on the driver being instantiated. * See the trace drivers for examples: * - * - :ref:`LightstepConfig ` - * - :ref:`ZipkinConfig ` - * - :ref:`DynamicOtConfig ` - * - :ref:`DatadogConfig ` - * - :ref:`OpenCensusConfig ` - * - :ref:`AWS X-Ray ` + * - :ref:`LightstepConfig ` + * - :ref:`ZipkinConfig ` + * - :ref:`DynamicOtConfig ` + * - :ref:`DatadogConfig ` + * - :ref:`OpenCensusConfig ` + * - :ref:`AWS X-Ray ` */ - 'config_type'?: "config"|"typed_config"; + 'config_type'?: "typed_config"; } /** * Configuration for an HTTP tracer provider used by Envoy. * * The configuration is defined by the - * :ref:`HttpConnectionManager.Tracing ` - * :ref:`provider ` + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` * field. */ -export interface _envoy_config_trace_v2_Tracing_Http__Output { +export interface _envoy_config_trace_v3_Tracing_Http__Output { /** * The name of the HTTP trace driver to instantiate. The name must match a * supported HTTP trace driver. Built-in trace drivers: @@ -61,20 +59,19 @@ export interface _envoy_config_trace_v2_Tracing_Http__Output { * - *envoy.tracers.xray* */ 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); 'typed_config'?: (_google_protobuf_Any__Output); /** * Trace driver specific configuration which depends on the driver being instantiated. * See the trace drivers for examples: * - * - :ref:`LightstepConfig ` - * - :ref:`ZipkinConfig ` - * - :ref:`DynamicOtConfig ` - * - :ref:`DatadogConfig ` - * - :ref:`OpenCensusConfig ` - * - :ref:`AWS X-Ray ` + * - :ref:`LightstepConfig ` + * - :ref:`ZipkinConfig ` + * - :ref:`DynamicOtConfig ` + * - :ref:`DatadogConfig ` + * - :ref:`OpenCensusConfig ` + * - :ref:`AWS X-Ray ` */ - 'config_type': "config"|"typed_config"; + 'config_type': "typed_config"; } /** @@ -86,13 +83,13 @@ export interface _envoy_config_trace_v2_Tracing_Http__Output { * .. attention:: * * Use of this message type has been deprecated in favor of direct use of - * :ref:`Tracing.Http `. + * :ref:`Tracing.Http `. */ export interface Tracing { /** * Provides configuration for the HTTP tracer. */ - 'http'?: (_envoy_config_trace_v2_Tracing_Http); + 'http'?: (_envoy_config_trace_v3_Tracing_Http); } /** @@ -104,11 +101,11 @@ export interface Tracing { * .. attention:: * * Use of this message type has been deprecated in favor of direct use of - * :ref:`Tracing.Http `. + * :ref:`Tracing.Http `. */ export interface Tracing__Output { /** * Provides configuration for the HTTP tracer. */ - 'http'?: (_envoy_config_trace_v2_Tracing_Http__Output); + 'http'?: (_envoy_config_trace_v3_Tracing_Http__Output); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts similarity index 64% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts rename to packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts index 1838f89a7..b68e812ef 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts @@ -1,24 +1,25 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto -import type { Rds as _envoy_config_filter_network_http_connection_manager_v2_Rds, Rds__Output as _envoy_config_filter_network_http_connection_manager_v2_Rds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/Rds'; -import type { RouteConfiguration as _envoy_api_v2_RouteConfiguration, RouteConfiguration__Output as _envoy_api_v2_RouteConfiguration__Output } from '../../../../../../envoy/api/v2/RouteConfiguration'; -import type { HttpFilter as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter, HttpFilter__Output as _envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/HttpFilter'; +import type { Rds as _envoy_extensions_filters_network_http_connection_manager_v3_Rds, Rds__Output as _envoy_extensions_filters_network_http_connection_manager_v3_Rds__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/Rds'; +import type { RouteConfiguration as _envoy_config_route_v3_RouteConfiguration, RouteConfiguration__Output as _envoy_config_route_v3_RouteConfiguration__Output } from '../../../../../../envoy/config/route/v3/RouteConfiguration'; +import type { HttpFilter as _envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter, HttpFilter__Output as _envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter'; import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../../google/protobuf/BoolValue'; -import type { Http1ProtocolOptions as _envoy_api_v2_core_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_api_v2_core_Http1ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http1ProtocolOptions'; -import type { Http2ProtocolOptions as _envoy_api_v2_core_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_api_v2_core_Http2ProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/Http2ProtocolOptions'; +import type { Http1ProtocolOptions as _envoy_config_core_v3_Http1ProtocolOptions, Http1ProtocolOptions__Output as _envoy_config_core_v3_Http1ProtocolOptions__Output } from '../../../../../../envoy/config/core/v3/Http1ProtocolOptions'; +import type { Http2ProtocolOptions as _envoy_config_core_v3_Http2ProtocolOptions, Http2ProtocolOptions__Output as _envoy_config_core_v3_Http2ProtocolOptions__Output } from '../../../../../../envoy/config/core/v3/Http2ProtocolOptions'; import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../../google/protobuf/Duration'; -import type { AccessLog as _envoy_config_filter_accesslog_v2_AccessLog, AccessLog__Output as _envoy_config_filter_accesslog_v2_AccessLog__Output } from '../../../../../../envoy/config/filter/accesslog/v2/AccessLog'; +import type { AccessLog as _envoy_config_accesslog_v3_AccessLog, AccessLog__Output as _envoy_config_accesslog_v3_AccessLog__Output } from '../../../../../../envoy/config/accesslog/v3/AccessLog'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; -import type { ScopedRoutes as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes, ScopedRoutes__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes'; -import type { HttpProtocolOptions as _envoy_api_v2_core_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_api_v2_core_HttpProtocolOptions__Output } from '../../../../../../envoy/api/v2/core/HttpProtocolOptions'; -import type { RequestIDExtension as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension, RequestIDExtension__Output as _envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension'; -import type { Percent as _envoy_type_Percent, Percent__Output as _envoy_type_Percent__Output } from '../../../../../../envoy/type/Percent'; -import type { CustomTag as _envoy_type_tracing_v2_CustomTag, CustomTag__Output as _envoy_type_tracing_v2_CustomTag__Output } from '../../../../../../envoy/type/tracing/v2/CustomTag'; -import type { _envoy_config_trace_v2_Tracing_Http, _envoy_config_trace_v2_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v2/Tracing'; +import type { ScopedRoutes as _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes, ScopedRoutes__Output as _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes'; +import type { HttpProtocolOptions as _envoy_config_core_v3_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_config_core_v3_HttpProtocolOptions__Output } from '../../../../../../envoy/config/core/v3/HttpProtocolOptions'; +import type { RequestIDExtension as _envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension, RequestIDExtension__Output as _envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension'; +import type { LocalReplyConfig as _envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig, LocalReplyConfig__Output as _envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig'; +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../../../envoy/type/v3/Percent'; +import type { CustomTag as _envoy_type_tracing_v3_CustomTag, CustomTag__Output as _envoy_type_tracing_v3_CustomTag__Output } from '../../../../../../envoy/type/tracing/v3/CustomTag'; +import type { _envoy_config_trace_v3_Tracing_Http, _envoy_config_trace_v3_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v3/Tracing'; -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto -export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType { +export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_CodecType { /** * For every new connection, the connection manager will determine which * codec to use. This mode supports both ALPN for TLS listeners as well as @@ -45,13 +46,13 @@ export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnecti HTTP3 = 3, } -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto /** * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP * header. */ -export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails { +export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails { /** * Do not send the XFCC header to the next hop. This is the default value. */ @@ -78,23 +79,23 @@ export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnecti ALWAYS_FORWARD_ONLY = 4, } -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig { /** * Whether unix socket addresses should be considered internal. */ 'unix_sockets'?: (boolean); } -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig__Output { /** * Whether unix socket addresses should be considered internal. */ 'unix_sockets': (boolean); } -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto -export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName { +export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing_OperationName { /** * The HTTP listener is used for ingress/incoming requests. */ @@ -105,9 +106,9 @@ export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnecti EGRESS = 1, } -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto -export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation { +export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ServerHeaderTransformation { /** * Overwrite any Server header with the contents of server_name. */ @@ -127,7 +128,7 @@ export enum _envoy_config_filter_network_http_connection_manager_v2_HttpConnecti /** * [#next-free-field: 7] */ -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails { /** * Whether to forward the subject of the client cert. Defaults to false. */ @@ -160,7 +161,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon /** * [#next-free-field: 7] */ -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails__Output { /** * Whether to forward the subject of the client cert. Defaults to false. */ @@ -193,26 +194,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon /** * [#next-free-field: 10] */ -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing { - /** - * The span name will be derived from this field. If - * :ref:`traffic_direction ` is - * specified on the parent listener, then it is used instead of this field. - * - * .. attention:: - * This field has been deprecated in favor of `traffic_direction`. - */ - 'operation_name'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName); - /** - * A list of header names used to create tags for the active span. The header name is used to - * populate the tag name, and the header value is used to populate the tag value. The tag is - * created if the specified header name is present in the request's headers. - * - * .. attention:: - * This field has been deprecated in favor of :ref:`custom_tags - * `. - */ - 'request_headers_for_tags'?: (string)[]; +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing { /** * Target percentage of requests managed by this HTTP connection manager that will be force * traced if the :ref:`x-client-trace-id ` @@ -221,7 +203,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_Percent); + 'client_sampling'?: (_envoy_type_v3_Percent); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -229,7 +211,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_Percent); + 'random_sampling'?: (_envoy_type_v3_Percent); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -240,7 +222,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_Percent); + 'overall_sampling'?: (_envoy_type_v3_Percent); /** * Whether to annotate spans with additional data. If true, spans will include logs for stream * events. @@ -255,7 +237,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon /** * A list of custom tags with unique tag name to create tags for the active span. */ - 'custom_tags'?: (_envoy_type_tracing_v2_CustomTag)[]; + 'custom_tags'?: (_envoy_type_tracing_v3_CustomTag)[]; /** * Configuration for an external tracing provider. * If not specified, no tracing will be performed. @@ -268,32 +250,13 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes * on OpenCensus side. */ - 'provider'?: (_envoy_config_trace_v2_Tracing_Http); + 'provider'?: (_envoy_config_trace_v3_Tracing_Http); } /** * [#next-free-field: 10] */ -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing__Output { - /** - * The span name will be derived from this field. If - * :ref:`traffic_direction ` is - * specified on the parent listener, then it is used instead of this field. - * - * .. attention:: - * This field has been deprecated in favor of `traffic_direction`. - */ - 'operation_name': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing_OperationName); - /** - * A list of header names used to create tags for the active span. The header name is used to - * populate the tag name, and the header value is used to populate the tag value. The tag is - * created if the specified header name is present in the request's headers. - * - * .. attention:: - * This field has been deprecated in favor of :ref:`custom_tags - * `. - */ - 'request_headers_for_tags': (string)[]; +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing__Output { /** * Target percentage of requests managed by this HTTP connection manager that will be force * traced if the :ref:`x-client-trace-id ` @@ -302,7 +265,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_Percent__Output); + 'client_sampling'?: (_envoy_type_v3_Percent__Output); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -310,7 +273,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_Percent__Output); + 'random_sampling'?: (_envoy_type_v3_Percent__Output); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -321,7 +284,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_Percent__Output); + 'overall_sampling'?: (_envoy_type_v3_Percent__Output); /** * Whether to annotate spans with additional data. If true, spans will include logs for stream * events. @@ -336,7 +299,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon /** * A list of custom tags with unique tag name to create tags for the active span. */ - 'custom_tags': (_envoy_type_tracing_v2_CustomTag__Output)[]; + 'custom_tags': (_envoy_type_tracing_v3_CustomTag__Output)[]; /** * Configuration for an external tracing provider. * If not specified, no tracing will be performed. @@ -349,7 +312,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes * on OpenCensus side. */ - 'provider'?: (_envoy_config_trace_v2_Tracing_Http__Output); + 'provider'?: (_envoy_config_trace_v3_Tracing_Http__Output); } /** @@ -366,7 +329,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * The current implementation of upgrade headers does not work with HTTP/2 * upstreams. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig { /** * The case-insensitive name of this upgrade, e.g. "websocket". * For each upgrade type present in upgrade_configs, requests with @@ -379,11 +342,11 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * this type of upgrade. If no filters are present, the filter chain for * HTTP connections will be used for this upgrade type. */ - 'filters'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter)[]; + 'filters'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter)[]; /** * Determines if upgrades are enabled or disabled by default. Defaults to true. * This can be overridden on a per-route basis with :ref:`cluster - * ` as documented in the + * ` as documented in the * :ref:`upgrade documentation `. */ 'enabled'?: (_google_protobuf_BoolValue); @@ -403,7 +366,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * The current implementation of upgrade headers does not work with HTTP/2 * upstreams. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig__Output { /** * The case-insensitive name of this upgrade, e.g. "websocket". * For each upgrade type present in upgrade_configs, requests with @@ -416,24 +379,24 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_HttpCon * this type of upgrade. If no filters are present, the filter chain for * HTTP connections will be used for this upgrade type. */ - 'filters': (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output)[]; + 'filters': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter__Output)[]; /** * Determines if upgrades are enabled or disabled by default. Defaults to true. * This can be overridden on a per-route basis with :ref:`cluster - * ` as documented in the + * ` as documented in the * :ref:`upgrade documentation `. */ 'enabled'?: (_google_protobuf_BoolValue__Output); } /** - * [#next-free-field: 37] + * [#next-free-field: 43] */ export interface HttpConnectionManager { /** * Supplies the type of codec that the connection manager should use. */ - 'codec_type'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType); + 'codec_type'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_CodecType | keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_CodecType); /** * The human readable prefix to use when emitting statistics for the * connection manager. See the :ref:`statistics documentation ` for @@ -443,17 +406,17 @@ export interface HttpConnectionManager { /** * The connection manager’s route table will be dynamically loaded via the RDS API. */ - 'rds'?: (_envoy_config_filter_network_http_connection_manager_v2_Rds); + 'rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_Rds); /** * The route table for the connection manager is static and is specified in this property. */ - 'route_config'?: (_envoy_api_v2_RouteConfiguration); + 'route_config'?: (_envoy_config_route_v3_RouteConfiguration); /** * A list of individual HTTP filters that make up the filter chain for * requests made to the connection manager. :ref:`Order matters ` * as the filters are processed sequentially as request events happen. */ - 'http_filters'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter)[]; + 'http_filters'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter)[]; /** * Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked @@ -463,33 +426,22 @@ export interface HttpConnectionManager { /** * Presence of the object defines whether the connection manager * emits :ref:`tracing ` data to the :ref:`configured tracing provider - * `. + * `. */ - 'tracing'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing); + 'tracing'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing); /** * Additional HTTP/1 settings that are passed to the HTTP/1 codec. */ - 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions); + 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions); /** * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. */ - 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions); /** * An optional override that the connection manager will write to the server * header in responses. If not set, the default is *envoy*. */ 'server_name'?: (string); - /** - * The idle timeout for connections managed by the connection manager. The - * idle timeout is defined as the period in which there are no active - * requests. If not set, there is no idle timeout. When the idle timeout is - * reached the connection will be closed. If the connection is an HTTP/2 - * connection a drain sequence will occur prior to closing the connection. - * This field is deprecated. Use :ref:`idle_timeout - * ` - * instead. - */ - 'idle_timeout'?: (_google_protobuf_Duration); /** * The time that Envoy will wait between sending an HTTP/2 “shutdown * notification†(GOAWAY frame with max stream ID) and a final GOAWAY frame. @@ -506,7 +458,7 @@ export interface HttpConnectionManager { * Configuration for :ref:`HTTP access logs ` * emitted by the connection manager. */ - 'access_log'?: (_envoy_config_filter_accesslog_v2_AccessLog)[]; + 'access_log'?: (_envoy_config_accesslog_v3_AccessLog)[]; /** * If set to true, the connection manager will use the real remote address * of the client connection when determining internal versus external origin and manipulating @@ -528,17 +480,17 @@ export interface HttpConnectionManager { * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP * header. */ - 'forward_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails); + 'forward_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails | keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails); /** * This field is valid only when :ref:`forward_client_cert_details - * ` + * ` * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in * the client certificate to be forwarded. Note that in the * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and * *By* is always set when the client certificate presents the URI type Subject Alternative Name * value. */ - 'set_current_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails); + 'set_current_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails); /** * If proxy_100_continue is true, Envoy will proxy incoming "Expect: * 100-continue" headers upstream, and forward "100 Continue" responses @@ -557,7 +509,7 @@ export interface HttpConnectionManager { /** * If * :ref:`use_remote_address - * ` + * ` * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. * This is useful for testing compatibility of upstream services that parse the header value. For @@ -575,7 +527,7 @@ export interface HttpConnectionManager { * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager * has mutated the request headers. While :ref:`use_remote_address - * ` + * ` * will also suppress XFF addition, it has consequences for logging and other * Envoy uses of the remote address, so *skip_xff_append* should be used * when only an elision of XFF addition is intended. @@ -586,7 +538,7 @@ export interface HttpConnectionManager { * empty, no via header will be appended. */ 'via'?: (string); - 'upgrade_configs'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig)[]; + 'upgrade_configs'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig)[]; /** * The stream idle timeout for connections managed by the connection manager. * If not specified, this defaults to 5 minutes. The default value was selected @@ -596,15 +548,29 @@ export interface HttpConnectionManager { * * This idle timeout applies to new streams and is overridable by the * :ref:`route-level idle_timeout - * `. Even on a stream in + * `. Even on a stream in * which the override applies, prior to receipt of the initial request * headers, the :ref:`stream_idle_timeout - * ` + * ` * applies. Each time an encode/decode event for headers or data is processed * for the stream, the timer will be reset. If the timeout fires, the stream * is terminated with a 408 Request Timeout error code if no upstream response * header has been received, otherwise a stream reset occurs. * + * This timeout also specifies the amount of time that Envoy will wait for the peer to open enough + * window to write any remaining stream data once the entirety of stream data (local end stream is + * true) has been buffered pending available window. In other words, this timeout defends against + * a peer that does not release enough window to completely write the stream, even though all + * data has been proxied within available flow control windows. If the timeout is hit in this + * case, the :ref:`tx_flush_timeout ` counter will be + * incremented. Note that :ref:`max_stream_duration + * ` does not apply to + * this corner case. + * + * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" + * is configured, this timeout is scaled according to the value for + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. + * * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due * to the granularity of events presented to the connection manager. For example, while receiving * very large request headers, it may be the case that there is traffic regularly arriving on the @@ -621,7 +587,7 @@ export interface HttpConnectionManager { * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more * information about internal/external addresses. */ - 'internal_address_config'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig); + 'internal_address_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig); /** * The delayed close timeout is for downstream connections managed by the HTTP connection manager. * It is defined as a grace period after connection close processing has been locally initiated @@ -678,10 +644,10 @@ export interface HttpConnectionManager { * true in the future. When not specified, this value may be overridden by the * runtime variable * :ref:`http_connection_manager.normalize_path`. - * See `Normalization and Comparison ` + * See `Normalization and Comparison `_ * for details of normalization. * Note that Envoy does not perform - * `case normalization ` + * `case normalization `_ */ 'normalize_path'?: (_google_protobuf_BoolValue); /** @@ -689,7 +655,7 @@ export interface HttpConnectionManager { * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are * specified in this message. */ - 'scoped_routes'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes); + 'scoped_routes'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes); /** * Whether the connection manager will keep the :ref:`x-request-id * ` header if passed for a request that is edge @@ -702,7 +668,7 @@ export interface HttpConnectionManager { * requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without * setting this option, incoming requests with path `//dir///file` will not match against route * with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of - * `HTTP spec ` and is provided for convenience. + * `HTTP spec `_ and is provided for convenience. */ 'merge_slashes'?: (boolean); /** @@ -710,12 +676,12 @@ export interface HttpConnectionManager { * By default, Envoy will overwrite the header with the value specified in * server_name. */ - 'server_header_transformation'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation | keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation); + 'server_header_transformation'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ServerHeaderTransformation | keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ServerHeaderTransformation); /** * Additional settings for HTTP requests handled by the connection manager. These will be * applicable to both HTTP1 and HTTP2 requests. */ - 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions); + 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions); /** * The configuration of the request ID extension. This includes operations such as * generation, validation, and associated tracing operations. @@ -728,18 +694,76 @@ export interface HttpConnectionManager { * * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. */ - 'request_id_extension'?: (_envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension); + 'request_id_extension'?: (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension); + /** + * If set, Envoy will always set :ref:`x-request-id ` header in response. + * If this is false or not set, the request ID is returned in responses only if tracing is forced using + * :ref:`x-envoy-force-trace ` header. + */ + 'always_set_request_id_in_response'?: (boolean); + /** + * The configuration to customize local reply returned by Envoy. It can customize status code, + * body text and response content type. If not specified, status code and text body are hard + * coded in Envoy, the response content type is plain text. + */ + 'local_reply_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig); + /** + * Determines if the port part should be removed from host/authority header before any processing + * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` + * local port and request method is not CONNECT. This affects the upstream host header as well. + * Without setting this option, incoming requests with host `example:443` will not match against + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * of `HTTP spec `_ and is provided for convenience. + * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. + */ + 'strip_matching_host_port'?: (boolean); + /** + * Governs Envoy's behavior when receiving invalid HTTP from downstream. + * If this option is false (default), Envoy will err on the conservative side handling HTTP + * errors, terminating both HTTP/1.1 and HTTP/2 connections when receiving an invalid request. + * If this option is set to true, Envoy will be more permissive, only resetting the invalid + * stream in the case of HTTP/2 and leaving the connection open where possible (if the entire + * request is read for HTTP/1.1) + * In general this should be true for deployments receiving trusted traffic (L2 Envoys, + * company-internal mesh) and false when receiving untrusted traffic (edge deployments). + * + * If different behaviors for invalid_http_message for HTTP/1 and HTTP/2 are + * desired, one should use the new HTTP/1 option :ref:`override_stream_error_on_invalid_http_message + * ` or the new HTTP/2 option + * :ref:`override_stream_error_on_invalid_http_message + * ` + * *not* the deprecated but similarly named :ref:`stream_error_on_invalid_http_messaging + * ` + */ + 'stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue); + /** + * The amount of time that Envoy will wait for the request headers to be received. The timer is + * activated when the first byte of the headers is received, and is disarmed when the last byte of + * the headers has been received. If not specified or set to 0, this timeout is disabled. + */ + 'request_headers_timeout'?: (_google_protobuf_Duration); + /** + * Determines if the port part should be removed from host/authority header before any processing + * of request by HTTP filters or routing. The port would be removed only if request method is not CONNECT. + * This affects the upstream host header as well. + * Without setting this option, incoming requests with host `example:443` will not match against + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * of `HTTP spec `_ and is provided for convenience. + * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. + */ + 'strip_any_host_port'?: (boolean); 'route_specifier'?: "rds"|"route_config"|"scoped_routes"; + 'strip_port_mode'?: "strip_any_host_port"; } /** - * [#next-free-field: 37] + * [#next-free-field: 43] */ export interface HttpConnectionManager__Output { /** * Supplies the type of codec that the connection manager should use. */ - 'codec_type': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_CodecType); + 'codec_type': (keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_CodecType); /** * The human readable prefix to use when emitting statistics for the * connection manager. See the :ref:`statistics documentation ` for @@ -749,17 +773,17 @@ export interface HttpConnectionManager__Output { /** * The connection manager’s route table will be dynamically loaded via the RDS API. */ - 'rds'?: (_envoy_config_filter_network_http_connection_manager_v2_Rds__Output); + 'rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_Rds__Output); /** * The route table for the connection manager is static and is specified in this property. */ - 'route_config'?: (_envoy_api_v2_RouteConfiguration__Output); + 'route_config'?: (_envoy_config_route_v3_RouteConfiguration__Output); /** * A list of individual HTTP filters that make up the filter chain for * requests made to the connection manager. :ref:`Order matters ` * as the filters are processed sequentially as request events happen. */ - 'http_filters': (_envoy_config_filter_network_http_connection_manager_v2_HttpFilter__Output)[]; + 'http_filters': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpFilter__Output)[]; /** * Whether the connection manager manipulates the :ref:`config_http_conn_man_headers_user-agent` * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked @@ -769,33 +793,22 @@ export interface HttpConnectionManager__Output { /** * Presence of the object defines whether the connection manager * emits :ref:`tracing ` data to the :ref:`configured tracing provider - * `. + * `. */ - 'tracing'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_Tracing__Output); + 'tracing'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing__Output); /** * Additional HTTP/1 settings that are passed to the HTTP/1 codec. */ - 'http_protocol_options'?: (_envoy_api_v2_core_Http1ProtocolOptions__Output); + 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions__Output); /** * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. */ - 'http2_protocol_options'?: (_envoy_api_v2_core_Http2ProtocolOptions__Output); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions__Output); /** * An optional override that the connection manager will write to the server * header in responses. If not set, the default is *envoy*. */ 'server_name': (string); - /** - * The idle timeout for connections managed by the connection manager. The - * idle timeout is defined as the period in which there are no active - * requests. If not set, there is no idle timeout. When the idle timeout is - * reached the connection will be closed. If the connection is an HTTP/2 - * connection a drain sequence will occur prior to closing the connection. - * This field is deprecated. Use :ref:`idle_timeout - * ` - * instead. - */ - 'idle_timeout'?: (_google_protobuf_Duration__Output); /** * The time that Envoy will wait between sending an HTTP/2 “shutdown * notification†(GOAWAY frame with max stream ID) and a final GOAWAY frame. @@ -812,7 +825,7 @@ export interface HttpConnectionManager__Output { * Configuration for :ref:`HTTP access logs ` * emitted by the connection manager. */ - 'access_log': (_envoy_config_filter_accesslog_v2_AccessLog__Output)[]; + 'access_log': (_envoy_config_accesslog_v3_AccessLog__Output)[]; /** * If set to true, the connection manager will use the real remote address * of the client connection when determining internal versus external origin and manipulating @@ -834,17 +847,17 @@ export interface HttpConnectionManager__Output { * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP * header. */ - 'forward_client_cert_details': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ForwardClientCertDetails); + 'forward_client_cert_details': (keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails); /** * This field is valid only when :ref:`forward_client_cert_details - * ` + * ` * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in * the client certificate to be forwarded. Note that in the * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and * *By* is always set when the client certificate presents the URI type Subject Alternative Name * value. */ - 'set_current_client_cert_details'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_SetCurrentClientCertDetails__Output); + 'set_current_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails__Output); /** * If proxy_100_continue is true, Envoy will proxy incoming "Expect: * 100-continue" headers upstream, and forward "100 Continue" responses @@ -863,7 +876,7 @@ export interface HttpConnectionManager__Output { /** * If * :ref:`use_remote_address - * ` + * ` * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. * This is useful for testing compatibility of upstream services that parse the header value. For @@ -881,7 +894,7 @@ export interface HttpConnectionManager__Output { * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager * has mutated the request headers. While :ref:`use_remote_address - * ` + * ` * will also suppress XFF addition, it has consequences for logging and other * Envoy uses of the remote address, so *skip_xff_append* should be used * when only an elision of XFF addition is intended. @@ -892,7 +905,7 @@ export interface HttpConnectionManager__Output { * empty, no via header will be appended. */ 'via': (string); - 'upgrade_configs': (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_UpgradeConfig__Output)[]; + 'upgrade_configs': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_UpgradeConfig__Output)[]; /** * The stream idle timeout for connections managed by the connection manager. * If not specified, this defaults to 5 minutes. The default value was selected @@ -902,15 +915,29 @@ export interface HttpConnectionManager__Output { * * This idle timeout applies to new streams and is overridable by the * :ref:`route-level idle_timeout - * `. Even on a stream in + * `. Even on a stream in * which the override applies, prior to receipt of the initial request * headers, the :ref:`stream_idle_timeout - * ` + * ` * applies. Each time an encode/decode event for headers or data is processed * for the stream, the timer will be reset. If the timeout fires, the stream * is terminated with a 408 Request Timeout error code if no upstream response * header has been received, otherwise a stream reset occurs. * + * This timeout also specifies the amount of time that Envoy will wait for the peer to open enough + * window to write any remaining stream data once the entirety of stream data (local end stream is + * true) has been buffered pending available window. In other words, this timeout defends against + * a peer that does not release enough window to completely write the stream, even though all + * data has been proxied within available flow control windows. If the timeout is hit in this + * case, the :ref:`tx_flush_timeout ` counter will be + * incremented. Note that :ref:`max_stream_duration + * ` does not apply to + * this corner case. + * + * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" + * is configured, this timeout is scaled according to the value for + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. + * * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due * to the granularity of events presented to the connection manager. For example, while receiving * very large request headers, it may be the case that there is traffic regularly arriving on the @@ -927,7 +954,7 @@ export interface HttpConnectionManager__Output { * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more * information about internal/external addresses. */ - 'internal_address_config'?: (_envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_InternalAddressConfig__Output); + 'internal_address_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig__Output); /** * The delayed close timeout is for downstream connections managed by the HTTP connection manager. * It is defined as a grace period after connection close processing has been locally initiated @@ -984,10 +1011,10 @@ export interface HttpConnectionManager__Output { * true in the future. When not specified, this value may be overridden by the * runtime variable * :ref:`http_connection_manager.normalize_path`. - * See `Normalization and Comparison ` + * See `Normalization and Comparison `_ * for details of normalization. * Note that Envoy does not perform - * `case normalization ` + * `case normalization `_ */ 'normalize_path'?: (_google_protobuf_BoolValue__Output); /** @@ -995,7 +1022,7 @@ export interface HttpConnectionManager__Output { * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are * specified in this message. */ - 'scoped_routes'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes__Output); + 'scoped_routes'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes__Output); /** * Whether the connection manager will keep the :ref:`x-request-id * ` header if passed for a request that is edge @@ -1008,7 +1035,7 @@ export interface HttpConnectionManager__Output { * requests by HTTP filters or routing. This affects the upstream *:path* header as well. Without * setting this option, incoming requests with path `//dir///file` will not match against route * with `prefix` match set to `/dir`. Defaults to `false`. Note that slash merging is not part of - * `HTTP spec ` and is provided for convenience. + * `HTTP spec `_ and is provided for convenience. */ 'merge_slashes': (boolean); /** @@ -1016,12 +1043,12 @@ export interface HttpConnectionManager__Output { * By default, Envoy will overwrite the header with the value specified in * server_name. */ - 'server_header_transformation': (keyof typeof _envoy_config_filter_network_http_connection_manager_v2_HttpConnectionManager_ServerHeaderTransformation); + 'server_header_transformation': (keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ServerHeaderTransformation); /** * Additional settings for HTTP requests handled by the connection manager. These will be * applicable to both HTTP1 and HTTP2 requests. */ - 'common_http_protocol_options'?: (_envoy_api_v2_core_HttpProtocolOptions__Output); + 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions__Output); /** * The configuration of the request ID extension. This includes operations such as * generation, validation, and associated tracing operations. @@ -1034,6 +1061,64 @@ export interface HttpConnectionManager__Output { * * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. */ - 'request_id_extension'?: (_envoy_config_filter_network_http_connection_manager_v2_RequestIDExtension__Output); + 'request_id_extension'?: (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension__Output); + /** + * If set, Envoy will always set :ref:`x-request-id ` header in response. + * If this is false or not set, the request ID is returned in responses only if tracing is forced using + * :ref:`x-envoy-force-trace ` header. + */ + 'always_set_request_id_in_response': (boolean); + /** + * The configuration to customize local reply returned by Envoy. It can customize status code, + * body text and response content type. If not specified, status code and text body are hard + * coded in Envoy, the response content type is plain text. + */ + 'local_reply_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig__Output); + /** + * Determines if the port part should be removed from host/authority header before any processing + * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` + * local port and request method is not CONNECT. This affects the upstream host header as well. + * Without setting this option, incoming requests with host `example:443` will not match against + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * of `HTTP spec `_ and is provided for convenience. + * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. + */ + 'strip_matching_host_port': (boolean); + /** + * Governs Envoy's behavior when receiving invalid HTTP from downstream. + * If this option is false (default), Envoy will err on the conservative side handling HTTP + * errors, terminating both HTTP/1.1 and HTTP/2 connections when receiving an invalid request. + * If this option is set to true, Envoy will be more permissive, only resetting the invalid + * stream in the case of HTTP/2 and leaving the connection open where possible (if the entire + * request is read for HTTP/1.1) + * In general this should be true for deployments receiving trusted traffic (L2 Envoys, + * company-internal mesh) and false when receiving untrusted traffic (edge deployments). + * + * If different behaviors for invalid_http_message for HTTP/1 and HTTP/2 are + * desired, one should use the new HTTP/1 option :ref:`override_stream_error_on_invalid_http_message + * ` or the new HTTP/2 option + * :ref:`override_stream_error_on_invalid_http_message + * ` + * *not* the deprecated but similarly named :ref:`stream_error_on_invalid_http_messaging + * ` + */ + 'stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue__Output); + /** + * The amount of time that Envoy will wait for the request headers to be received. The timer is + * activated when the first byte of the headers is received, and is disarmed when the last byte of + * the headers has been received. If not specified or set to 0, this timeout is disabled. + */ + 'request_headers_timeout'?: (_google_protobuf_Duration__Output); + /** + * Determines if the port part should be removed from host/authority header before any processing + * of request by HTTP filters or routing. The port would be removed only if request method is not CONNECT. + * This affects the upstream host header as well. + * Without setting this option, incoming requests with host `example:443` will not match against + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * of `HTTP spec `_ and is provided for convenience. + * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. + */ + 'strip_any_host_port'?: (boolean); 'route_specifier': "rds"|"route_config"|"scoped_routes"; + 'strip_port_mode': "strip_any_host_port"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts new file mode 100644 index 000000000..881e2c714 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts @@ -0,0 +1,66 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; +import type { ExtensionConfigSource as _envoy_config_core_v3_ExtensionConfigSource, ExtensionConfigSource__Output as _envoy_config_core_v3_ExtensionConfigSource__Output } from '../../../../../../envoy/config/core/v3/ExtensionConfigSource'; + +/** + * [#next-free-field: 7] + */ +export interface HttpFilter { + /** + * The name of the filter configuration. The name is used as a fallback to + * select an extension if the type of the configuration proto is not + * sufficient. It also serves as a resource name in ExtensionConfigDS. + */ + 'name'?: (string); + /** + * Filter specific configuration which depends on the filter being instantiated. See the supported + * filters for further documentation. + */ + 'typed_config'?: (_google_protobuf_Any); + /** + * Configuration source specifier for an extension configuration discovery service. + * In case of a failure and without the default configuration, the HTTP listener responds with code 500. + * Extension configs delivered through this mechanism are not expected to require warming (see https://github.com/envoyproxy/envoy/issues/12061). + */ + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource); + /** + * If true, clients that do not support this filter may ignore the + * filter but otherwise accept the config. + * Otherwise, clients that do not support this filter must reject the config. + * [#not-implemented-hide:] + */ + 'is_optional'?: (boolean); + 'config_type'?: "typed_config"|"config_discovery"; +} + +/** + * [#next-free-field: 7] + */ +export interface HttpFilter__Output { + /** + * The name of the filter configuration. The name is used as a fallback to + * select an extension if the type of the configuration proto is not + * sufficient. It also serves as a resource name in ExtensionConfigDS. + */ + 'name': (string); + /** + * Filter specific configuration which depends on the filter being instantiated. See the supported + * filters for further documentation. + */ + 'typed_config'?: (_google_protobuf_Any__Output); + /** + * Configuration source specifier for an extension configuration discovery service. + * In case of a failure and without the default configuration, the HTTP listener responds with code 500. + * Extension configs delivered through this mechanism are not expected to require warming (see https://github.com/envoyproxy/envoy/issues/12061). + */ + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output); + /** + * If true, clients that do not support this filter may ignore the + * filter but otherwise accept the config. + * Otherwise, clients that do not support this filter must reject the config. + * [#not-implemented-hide:] + */ + 'is_optional': (boolean); + 'config_type': "typed_config"|"config_discovery"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts new file mode 100644 index 000000000..10bb6e700 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts @@ -0,0 +1,106 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +import type { ResponseMapper as _envoy_extensions_filters_network_http_connection_manager_v3_ResponseMapper, ResponseMapper__Output as _envoy_extensions_filters_network_http_connection_manager_v3_ResponseMapper__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper'; +import type { SubstitutionFormatString as _envoy_config_core_v3_SubstitutionFormatString, SubstitutionFormatString__Output as _envoy_config_core_v3_SubstitutionFormatString__Output } from '../../../../../../envoy/config/core/v3/SubstitutionFormatString'; + +/** + * The configuration to customize local reply returned by Envoy. + */ +export interface LocalReplyConfig { + /** + * Configuration of list of mappers which allows to filter and change local response. + * The mappers will be checked by the specified order until one is matched. + */ + 'mappers'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ResponseMapper)[]; + /** + * The configuration to form response body from the :ref:`command operators ` + * and to specify response content type as one of: plain/text or application/json. + * + * Example one: "plain/text" ``body_format``. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * text_format: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n" + * + * The following response body in "plain/text" format will be generated for a request with + * local reply body of "upstream connection error", response_code=503 and path=/foo. + * + * .. code-block:: text + * + * upstream connect error:503:path=/foo + * + * Example two: "application/json" ``body_format``. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * json_format: + * status: "%RESPONSE_CODE%" + * message: "%LOCAL_REPLY_BODY%" + * path: "%REQ(:path)%" + * + * The following response body in "application/json" format would be generated for a request with + * local reply body of "upstream connection error", response_code=503 and path=/foo. + * + * .. code-block:: json + * + * { + * "status": 503, + * "message": "upstream connection error", + * "path": "/foo" + * } + */ + 'body_format'?: (_envoy_config_core_v3_SubstitutionFormatString); +} + +/** + * The configuration to customize local reply returned by Envoy. + */ +export interface LocalReplyConfig__Output { + /** + * Configuration of list of mappers which allows to filter and change local response. + * The mappers will be checked by the specified order until one is matched. + */ + 'mappers': (_envoy_extensions_filters_network_http_connection_manager_v3_ResponseMapper__Output)[]; + /** + * The configuration to form response body from the :ref:`command operators ` + * and to specify response content type as one of: plain/text or application/json. + * + * Example one: "plain/text" ``body_format``. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * text_format: "%LOCAL_REPLY_BODY%:%RESPONSE_CODE%:path=%REQ(:path)%\n" + * + * The following response body in "plain/text" format will be generated for a request with + * local reply body of "upstream connection error", response_code=503 and path=/foo. + * + * .. code-block:: text + * + * upstream connect error:503:path=/foo + * + * Example two: "application/json" ``body_format``. + * + * .. validated-code-block:: yaml + * :type-name: envoy.config.core.v3.SubstitutionFormatString + * + * json_format: + * status: "%RESPONSE_CODE%" + * message: "%LOCAL_REPLY_BODY%" + * path: "%REQ(:path)%" + * + * The following response body in "application/json" format would be generated for a request with + * local reply body of "upstream connection error", response_code=503 and path=/foo. + * + * .. code-block:: json + * + * { + * "status": 503, + * "message": "upstream connection error", + * "path": "/foo" + * } + */ + 'body_format'?: (_envoy_config_core_v3_SubstitutionFormatString__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts similarity index 63% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts rename to packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts index be9c038a6..8e06a6d67 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/Rds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts @@ -1,12 +1,12 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto -import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../../../envoy/config/core/v3/ConfigSource'; export interface Rds { /** * Configuration source specifier for RDS. */ - 'config_source'?: (_envoy_api_v2_core_ConfigSource); + 'config_source'?: (_envoy_config_core_v3_ConfigSource); /** * The name of the route configuration. This name will be passed to the RDS * API. This allows an Envoy configuration with multiple HTTP listeners (and @@ -20,7 +20,7 @@ export interface Rds__Output { /** * Configuration source specifier for RDS. */ - 'config_source'?: (_envoy_api_v2_core_ConfigSource__Output); + 'config_source'?: (_envoy_config_core_v3_ConfigSource__Output); /** * The name of the route configuration. This name will be passed to the RDS * API. This allows an Envoy configuration with multiple HTTP listeners (and diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts similarity index 78% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts rename to packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts index 2f043d4a8..24e05ccc3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/RequestIDExtension.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../../google/protobuf/Any'; diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts new file mode 100644 index 000000000..67af3aec4 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts @@ -0,0 +1,67 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +import type { AccessLogFilter as _envoy_config_accesslog_v3_AccessLogFilter, AccessLogFilter__Output as _envoy_config_accesslog_v3_AccessLogFilter__Output } from '../../../../../../envoy/config/accesslog/v3/AccessLogFilter'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../../../envoy/config/core/v3/DataSource'; +import type { SubstitutionFormatString as _envoy_config_core_v3_SubstitutionFormatString, SubstitutionFormatString__Output as _envoy_config_core_v3_SubstitutionFormatString__Output } from '../../../../../../envoy/config/core/v3/SubstitutionFormatString'; +import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, HeaderValueOption__Output as _envoy_config_core_v3_HeaderValueOption__Output } from '../../../../../../envoy/config/core/v3/HeaderValueOption'; + +/** + * The configuration to filter and change local response. + * [#next-free-field: 6] + */ +export interface ResponseMapper { + /** + * Filter to determine if this mapper should apply. + */ + 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter); + /** + * The new response status code if specified. + */ + 'status_code'?: (_google_protobuf_UInt32Value); + /** + * The new local reply body text if specified. It will be used in the `%LOCAL_REPLY_BODY%` + * command operator in the `body_format`. + */ + 'body'?: (_envoy_config_core_v3_DataSource); + /** + * A per mapper `body_format` to override the :ref:`body_format `. + * It will be used when this mapper is matched. + */ + 'body_format_override'?: (_envoy_config_core_v3_SubstitutionFormatString); + /** + * HTTP headers to add to a local reply. This allows the response mapper to append, to add + * or to override headers of any local reply before it is sent to a downstream client. + */ + 'headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; +} + +/** + * The configuration to filter and change local response. + * [#next-free-field: 6] + */ +export interface ResponseMapper__Output { + /** + * Filter to determine if this mapper should apply. + */ + 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter__Output); + /** + * The new response status code if specified. + */ + 'status_code'?: (_google_protobuf_UInt32Value__Output); + /** + * The new local reply body text if specified. It will be used in the `%LOCAL_REPLY_BODY%` + * command operator in the `body_format`. + */ + 'body'?: (_envoy_config_core_v3_DataSource__Output); + /** + * A per mapper `body_format` to override the :ref:`body_format `. + * It will be used when this mapper is matched. + */ + 'body_format_override'?: (_envoy_config_core_v3_SubstitutionFormatString__Output); + /** + * HTTP headers to add to a local reply. This allows the response mapper to append, to add + * or to override headers of any local reply before it is sent to a downstream client. + */ + 'headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts new file mode 100644 index 000000000..a9995b455 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../../../envoy/config/core/v3/ConfigSource'; + +export interface ScopedRds { + /** + * Configuration source specifier for scoped RDS. + */ + 'scoped_rds_config_source'?: (_envoy_config_core_v3_ConfigSource); +} + +export interface ScopedRds__Output { + /** + * Configuration source specifier for scoped RDS. + */ + 'scoped_rds_config_source'?: (_envoy_config_core_v3_ConfigSource__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRouteConfigurationsList.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRouteConfigurationsList.ts new file mode 100644 index 000000000..e7f05e340 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRouteConfigurationsList.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +import type { ScopedRouteConfiguration as _envoy_config_route_v3_ScopedRouteConfiguration, ScopedRouteConfiguration__Output as _envoy_config_route_v3_ScopedRouteConfiguration__Output } from '../../../../../../envoy/config/route/v3/ScopedRouteConfiguration'; + +/** + * This message is used to work around the limitations with 'oneof' and repeated fields. + */ +export interface ScopedRouteConfigurationsList { + 'scoped_route_configurations'?: (_envoy_config_route_v3_ScopedRouteConfiguration)[]; +} + +/** + * This message is used to work around the limitations with 'oneof' and repeated fields. + */ +export interface ScopedRouteConfigurationsList__Output { + 'scoped_route_configurations': (_envoy_config_route_v3_ScopedRouteConfiguration__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts similarity index 57% rename from packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts rename to packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts index b9b20d2bf..a19e59b2a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/filter/network/http_connection_manager/v2/ScopedRoutes.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts @@ -1,28 +1,28 @@ -// Original file: deps/envoy-api/envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto -import type { ConfigSource as _envoy_api_v2_core_ConfigSource, ConfigSource__Output as _envoy_api_v2_core_ConfigSource__Output } from '../../../../../../envoy/api/v2/core/ConfigSource'; -import type { ScopedRouteConfigurationsList as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList, ScopedRouteConfigurationsList__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRouteConfigurationsList'; -import type { ScopedRds as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds, ScopedRds__Output as _envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output } from '../../../../../../envoy/config/filter/network/http_connection_manager/v2/ScopedRds'; +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../../../envoy/config/core/v3/ConfigSource'; +import type { ScopedRouteConfigurationsList as _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList, ScopedRouteConfigurationsList__Output as _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/ScopedRouteConfigurationsList'; +import type { ScopedRds as _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds, ScopedRds__Output as _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds'; /** * Specifies the mechanism for constructing key fragments which are composed into scope keys. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder { /** * Specifies how a header field's value should be extracted. */ - 'header_value_extractor'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor); + 'header_value_extractor'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor); 'type'?: "header_value_extractor"; } /** * Specifies the mechanism for constructing key fragments which are composed into scope keys. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output { /** * Specifies how a header field's value should be extracted. */ - 'header_value_extractor'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output); + 'header_value_extractor'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output); 'type': "header_value_extractor"; } @@ -45,9 +45,13 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedR * * Each 'a=b' key-value pair constitutes an 'element' of the header field. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor { /** * The name of the header field to extract the value from. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ 'name'?: (string); /** @@ -66,7 +70,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedR /** * Specifies the key value pair to extract the value from. */ - 'element'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement); + 'element'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement); 'extract_type'?: "index"|"element"; } @@ -89,9 +93,13 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedR * * Each 'a=b' key-value pair constitutes an 'element' of the header field. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output { /** * The name of the header field to extract the value from. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. */ 'name': (string); /** @@ -110,14 +118,14 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedR /** * Specifies the key value pair to extract the value from. */ - 'element'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output); + 'element'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output); 'extract_type': "index"|"element"; } /** * Specifies a header field's key value pair to match on. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement { /** * The separator between key and value (e.g., '=' separates 'k=v;...'). * If an element is an empty string, the element is ignored. @@ -135,7 +143,7 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedR /** * Specifies a header field's key value pair to match on. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output { /** * The separator between key and value (e.g., '=' separates 'k=v;...'). * If an element is an empty string, the element is ignored. @@ -152,42 +160,42 @@ export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedR /** * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These - * keys are matched against a set of :ref:`Key` - * objects assembled from :ref:`ScopedRouteConfiguration` + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via - * :ref:`scoped_route_configurations_list`. + * :ref:`scoped_route_configurations_list`. * * Upon receiving a request's headers, the Router will build a key using the algorithm specified * by this message. This key will be used to look up the routing table (i.e., the - * :ref:`RouteConfiguration`) to use for the request. + * :ref:`RouteConfiguration`) to use for the request. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder { /** * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the - * fragments of a :ref:`ScopedRouteConfiguration`. + * fragments of a :ref:`ScopedRouteConfiguration`. * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. */ - 'fragments'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder)[]; + 'fragments'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder)[]; } /** * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These - * keys are matched against a set of :ref:`Key` - * objects assembled from :ref:`ScopedRouteConfiguration` + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via - * :ref:`scoped_route_configurations_list`. + * :ref:`scoped_route_configurations_list`. * * Upon receiving a request's headers, the Router will build a key using the algorithm specified * by this message. This key will be used to look up the routing table (i.e., the - * :ref:`RouteConfiguration`) to use for the request. + * :ref:`RouteConfiguration`) to use for the request. */ -export interface _envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder__Output { +export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder__Output { /** * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the - * fragments of a :ref:`ScopedRouteConfiguration`. + * fragments of a :ref:`ScopedRouteConfiguration`. * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. */ - 'fragments': (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output)[]; + 'fragments': (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output)[]; } /** @@ -201,29 +209,29 @@ export interface ScopedRoutes { /** * The algorithm to use for constructing a scope key for each request. */ - 'scope_key_builder'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder); + 'scope_key_builder'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder); /** * Configuration source specifier for RDS. * This config source is used to subscribe to RouteConfiguration resources specified in * ScopedRouteConfiguration messages. */ - 'rds_config_source'?: (_envoy_api_v2_core_ConfigSource); + 'rds_config_source'?: (_envoy_config_core_v3_ConfigSource); /** * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by * matching a key constructed from the request's attributes according to the algorithm specified * by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_route_configurations_list'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList); + 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList); /** * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS * API. A scope is assigned to a request by matching a key constructed from the request's * attributes according to the algorithm specified by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds); + 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds); 'config_specifier'?: "scoped_route_configurations_list"|"scoped_rds"; } @@ -238,28 +246,28 @@ export interface ScopedRoutes__Output { /** * The algorithm to use for constructing a scope key for each request. */ - 'scope_key_builder'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRoutes_ScopeKeyBuilder__Output); + 'scope_key_builder'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder__Output); /** * Configuration source specifier for RDS. * This config source is used to subscribe to RouteConfiguration resources specified in * ScopedRouteConfiguration messages. */ - 'rds_config_source'?: (_envoy_api_v2_core_ConfigSource__Output); + 'rds_config_source'?: (_envoy_config_core_v3_ConfigSource__Output); /** * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by * matching a key constructed from the request's attributes according to the algorithm specified * by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_route_configurations_list'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRouteConfigurationsList__Output); + 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList__Output); /** * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS * API. A scope is assigned to a request by matching a key constructed from the request's * attributes according to the algorithm specified by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_rds'?: (_envoy_config_filter_network_http_connection_manager_v2_ScopedRds__Output); + 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds__Output); 'config_specifier': "scoped_route_configurations_list"|"scoped_rds"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AdsDummy.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AdsDummy.ts new file mode 100644 index 000000000..c15510877 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AdsDummy.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/ads.proto + + +/** + * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing + * services: https://github.com/google/protobuf/issues/4221 + */ +export interface AdsDummy { +} + +/** + * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing + * services: https://github.com/google/protobuf/issues/4221 + */ +export interface AdsDummy__Output { +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts new file mode 100644 index 000000000..445057d44 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts @@ -0,0 +1,52 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/ads.proto + +import type * as grpc from '@grpc/grpc-js' +import type { DeltaDiscoveryRequest as _envoy_service_discovery_v3_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_service_discovery_v3_DeltaDiscoveryRequest__Output } from '../../../../envoy/service/discovery/v3/DeltaDiscoveryRequest'; +import type { DeltaDiscoveryResponse as _envoy_service_discovery_v3_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output } from '../../../../envoy/service/discovery/v3/DeltaDiscoveryResponse'; +import type { DiscoveryRequest as _envoy_service_discovery_v3_DiscoveryRequest, DiscoveryRequest__Output as _envoy_service_discovery_v3_DiscoveryRequest__Output } from '../../../../envoy/service/discovery/v3/DiscoveryRequest'; +import type { DiscoveryResponse as _envoy_service_discovery_v3_DiscoveryResponse, DiscoveryResponse__Output as _envoy_service_discovery_v3_DiscoveryResponse__Output } from '../../../../envoy/service/discovery/v3/DiscoveryResponse'; + +/** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ +export interface AggregatedDiscoveryServiceClient extends grpc.Client { + DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DeltaDiscoveryRequest, _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output>; + DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DeltaDiscoveryRequest, _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output>; + deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DeltaDiscoveryRequest, _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output>; + deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DeltaDiscoveryRequest, _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output>; + + /** + * This is a gRPC-only API. + */ + StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DiscoveryRequest, _envoy_service_discovery_v3_DiscoveryResponse__Output>; + StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DiscoveryRequest, _envoy_service_discovery_v3_DiscoveryResponse__Output>; + /** + * This is a gRPC-only API. + */ + streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DiscoveryRequest, _envoy_service_discovery_v3_DiscoveryResponse__Output>; + streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_discovery_v3_DiscoveryRequest, _envoy_service_discovery_v3_DiscoveryResponse__Output>; + +} + +/** + * See https://github.com/lyft/envoy-api#apis for a description of the role of + * ADS and how it is intended to be used by a management server. ADS requests + * have the same structure as their singleton xDS counterparts, but can + * multiplex many resource types on a single stream. The type_url in the + * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover + * the multiplexed singleton APIs at the Envoy instance and management server. + */ +export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceImplementation { + DeltaAggregatedResources: grpc.handleBidiStreamingCall<_envoy_service_discovery_v3_DeltaDiscoveryRequest__Output, _envoy_service_discovery_v3_DeltaDiscoveryResponse>; + + /** + * This is a gRPC-only API. + */ + StreamAggregatedResources: grpc.handleBidiStreamingCall<_envoy_service_discovery_v3_DiscoveryRequest__Output, _envoy_service_discovery_v3_DiscoveryResponse>; + +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts new file mode 100644 index 000000000..bcf2de4e2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts @@ -0,0 +1,206 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/discovery.proto + +import type { Node as _envoy_config_core_v3_Node, Node__Output as _envoy_config_core_v3_Node__Output } from '../../../../envoy/config/core/v3/Node'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../../google/rpc/Status'; + +/** + * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC + * endpoint for Delta xDS. + * + * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full + * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a + * diff to the state of a xDS client. + * In Delta XDS there are per-resource versions, which allow tracking state at + * the resource granularity. + * An xDS Delta session is always in the context of a gRPC bidirectional + * stream. This allows the xDS server to keep track of the state of xDS clients + * connected to it. + * + * In Delta xDS the nonce field is required and used to pair + * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. + * Optionally, a response message level system_version_info is present for + * debugging purposes only. + * + * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest + * can be either or both of: [1] informing the server of what resources the + * client has gained/lost interest in (using resource_names_subscribe and + * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from + * the server (using response_nonce, with presence of error_detail making it a NACK). + * Additionally, the first message (for a given type_url) of a reconnected gRPC stream + * has a third role: informing the server of the resources (and their versions) + * that the client already possesses, using the initial_resource_versions field. + * + * As with state-of-the-world, when multiple resource types are multiplexed (ADS), + * all requests/acknowledgments/updates are logically walled off by type_url: + * a Cluster ACK exists in a completely separate world from a prior Route NACK. + * In particular, initial_resource_versions being sent at the "start" of every + * gRPC stream actually entails a message for each type_url, each with its own + * initial_resource_versions. + * [#next-free-field: 8] + */ +export interface DeltaDiscoveryRequest { + /** + * The node making the request. + */ + 'node'?: (_envoy_config_core_v3_Node); + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This does not need to be set if + * resources are only referenced via *xds_resource_subscribe* and + * *xds_resources_unsubscribe*. + */ + 'type_url'?: (string); + /** + * DeltaDiscoveryRequests allow the client to add or remove individual + * resources to the set of tracked resources in the context of a stream. + * All resource names in the resource_names_subscribe list are added to the + * set of tracked resources and all resource names in the resource_names_unsubscribe + * list are removed from the set of tracked resources. + * + * *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or + * resource_names_unsubscribe list simply means that no resources are to be + * added or removed to the resource list. + * *Like* state-of-the-world xDS, the server must send updates for all tracked + * resources, but can also send updates for resources the client has not subscribed to. + * + * NOTE: the server must respond with all resources listed in resource_names_subscribe, + * even if it believes the client has the most recent version of them. The reason: + * the client may have dropped them, but then regained interest before it had a chance + * to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. + * + * These two fields can be set in any DeltaDiscoveryRequest, including ACKs + * and initial_resource_versions. + * + * A list of Resource names to add to the list of tracked resources. + */ + 'resource_names_subscribe'?: (string)[]; + /** + * A list of Resource names to remove from the list of tracked resources. + */ + 'resource_names_unsubscribe'?: (string)[]; + /** + * Informs the server of the versions of the resources the xDS client knows of, to enable the + * client to continue the same logical xDS session even in the face of gRPC stream reconnection. + * It will not be populated: [1] in the very first stream of a session, since the client will + * not yet have any resources, [2] in any message after the first in a stream (for a given + * type_url), since the server will already be correctly tracking the client's state. + * (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) + * The map's keys are names of xDS resources known to the xDS client. + * The map's values are opaque resource versions. + */ + 'initial_resource_versions'?: ({[key: string]: string}); + /** + * When the DeltaDiscoveryRequest is a ACK or NACK message in response + * to a previous DeltaDiscoveryResponse, the response_nonce must be the + * nonce in the DeltaDiscoveryResponse. + * Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. + */ + 'response_nonce'?: (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* + * provides the Envoy internal exception related to the failure. + */ + 'error_detail'?: (_google_rpc_Status); +} + +/** + * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC + * endpoint for Delta xDS. + * + * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full + * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a + * diff to the state of a xDS client. + * In Delta XDS there are per-resource versions, which allow tracking state at + * the resource granularity. + * An xDS Delta session is always in the context of a gRPC bidirectional + * stream. This allows the xDS server to keep track of the state of xDS clients + * connected to it. + * + * In Delta xDS the nonce field is required and used to pair + * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. + * Optionally, a response message level system_version_info is present for + * debugging purposes only. + * + * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest + * can be either or both of: [1] informing the server of what resources the + * client has gained/lost interest in (using resource_names_subscribe and + * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from + * the server (using response_nonce, with presence of error_detail making it a NACK). + * Additionally, the first message (for a given type_url) of a reconnected gRPC stream + * has a third role: informing the server of the resources (and their versions) + * that the client already possesses, using the initial_resource_versions field. + * + * As with state-of-the-world, when multiple resource types are multiplexed (ADS), + * all requests/acknowledgments/updates are logically walled off by type_url: + * a Cluster ACK exists in a completely separate world from a prior Route NACK. + * In particular, initial_resource_versions being sent at the "start" of every + * gRPC stream actually entails a message for each type_url, each with its own + * initial_resource_versions. + * [#next-free-field: 8] + */ +export interface DeltaDiscoveryRequest__Output { + /** + * The node making the request. + */ + 'node'?: (_envoy_config_core_v3_Node__Output); + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This does not need to be set if + * resources are only referenced via *xds_resource_subscribe* and + * *xds_resources_unsubscribe*. + */ + 'type_url': (string); + /** + * DeltaDiscoveryRequests allow the client to add or remove individual + * resources to the set of tracked resources in the context of a stream. + * All resource names in the resource_names_subscribe list are added to the + * set of tracked resources and all resource names in the resource_names_unsubscribe + * list are removed from the set of tracked resources. + * + * *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or + * resource_names_unsubscribe list simply means that no resources are to be + * added or removed to the resource list. + * *Like* state-of-the-world xDS, the server must send updates for all tracked + * resources, but can also send updates for resources the client has not subscribed to. + * + * NOTE: the server must respond with all resources listed in resource_names_subscribe, + * even if it believes the client has the most recent version of them. The reason: + * the client may have dropped them, but then regained interest before it had a chance + * to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. + * + * These two fields can be set in any DeltaDiscoveryRequest, including ACKs + * and initial_resource_versions. + * + * A list of Resource names to add to the list of tracked resources. + */ + 'resource_names_subscribe': (string)[]; + /** + * A list of Resource names to remove from the list of tracked resources. + */ + 'resource_names_unsubscribe': (string)[]; + /** + * Informs the server of the versions of the resources the xDS client knows of, to enable the + * client to continue the same logical xDS session even in the face of gRPC stream reconnection. + * It will not be populated: [1] in the very first stream of a session, since the client will + * not yet have any resources, [2] in any message after the first in a stream (for a given + * type_url), since the server will already be correctly tracking the client's state. + * (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) + * The map's keys are names of xDS resources known to the xDS client. + * The map's values are opaque resource versions. + */ + 'initial_resource_versions': ({[key: string]: string}); + /** + * When the DeltaDiscoveryRequest is a ACK or NACK message in response + * to a previous DeltaDiscoveryResponse, the response_nonce must be the + * nonce in the DeltaDiscoveryResponse. + * Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. + */ + 'response_nonce': (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* + * provides the Envoy internal exception related to the failure. + */ + 'error_detail'?: (_google_rpc_Status__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts new file mode 100644 index 000000000..c22690cd9 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts @@ -0,0 +1,74 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/discovery.proto + +import type { Resource as _envoy_service_discovery_v3_Resource, Resource__Output as _envoy_service_discovery_v3_Resource__Output } from '../../../../envoy/service/discovery/v3/Resource'; +import type { ControlPlane as _envoy_config_core_v3_ControlPlane, ControlPlane__Output as _envoy_config_core_v3_ControlPlane__Output } from '../../../../envoy/config/core/v3/ControlPlane'; + +/** + * [#next-free-field: 8] + */ +export interface DeltaDiscoveryResponse { + /** + * The version of the response data (used for debugging). + */ + 'system_version_info'?: (string); + /** + * The response resources. These are typed resources, whose types must match + * the type_url field. + */ + 'resources'?: (_envoy_service_discovery_v3_Resource)[]; + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the Any within 'resources' if 'resources' is non-empty. + */ + 'type_url'?: (string); + /** + * The nonce provides a way for DeltaDiscoveryRequests to uniquely + * reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. + */ + 'nonce'?: (string); + /** + * Resources names of resources that have be deleted and to be removed from the xDS Client. + * Removed resources for missing resources can be ignored. + */ + 'removed_resources'?: (string)[]; + /** + * [#not-implemented-hide:] + * The control plane instance that sent the response. + */ + 'control_plane'?: (_envoy_config_core_v3_ControlPlane); +} + +/** + * [#next-free-field: 8] + */ +export interface DeltaDiscoveryResponse__Output { + /** + * The version of the response data (used for debugging). + */ + 'system_version_info': (string); + /** + * The response resources. These are typed resources, whose types must match + * the type_url field. + */ + 'resources': (_envoy_service_discovery_v3_Resource__Output)[]; + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the Any within 'resources' if 'resources' is non-empty. + */ + 'type_url': (string); + /** + * The nonce provides a way for DeltaDiscoveryRequests to uniquely + * reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. + */ + 'nonce': (string); + /** + * Resources names of resources that have be deleted and to be removed from the xDS Client. + * Removed resources for missing resources can be ignored. + */ + 'removed_resources': (string)[]; + /** + * [#not-implemented-hide:] + * The control plane instance that sent the response. + */ + 'control_plane'?: (_envoy_config_core_v3_ControlPlane__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts new file mode 100644 index 000000000..2b23ee869 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts @@ -0,0 +1,110 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/discovery.proto + +import type { Node as _envoy_config_core_v3_Node, Node__Output as _envoy_config_core_v3_Node__Output } from '../../../../envoy/config/core/v3/Node'; +import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../../google/rpc/Status'; + +/** + * A DiscoveryRequest requests a set of versioned resources of the same type for + * a given Envoy node on some API. + * [#next-free-field: 7] + */ +export interface DiscoveryRequest { + /** + * The version_info provided in the request messages will be the version_info + * received with the most recent successfully processed response or empty on + * the first request. It is expected that no new request is sent after a + * response is received until the Envoy instance is ready to ACK/NACK the new + * configuration. ACK/NACK takes place by returning the new API config version + * as applied or the previous API config version respectively. Each type_url + * (see below) has an independent version associated with it. + */ + 'version_info'?: (string); + /** + * The node making the request. + */ + 'node'?: (_envoy_config_core_v3_Node); + /** + * List of resources to subscribe to, e.g. list of cluster names or a route + * configuration name. If this is empty, all resources for the API are + * returned. LDS/CDS may have empty resource_names, which will cause all + * resources for the Envoy instance to be returned. The LDS and CDS responses + * will then imply a number of resources that need to be fetched via EDS/RDS, + * which will be explicitly enumerated in resource_names. + */ + 'resource_names'?: (string)[]; + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit + * in requests made via singleton xDS APIs such as CDS, LDS, etc. but is + * required for ADS. + */ + 'type_url'?: (string); + /** + * nonce corresponding to DiscoveryResponse being ACK/NACKed. See above + * discussion on version_info and the DiscoveryResponse nonce comment. This + * may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, + * or 2) the client has not yet accepted an update in this xDS stream (unlike + * delta, where it is populated only for new explicit ACKs). + */ + 'response_nonce'?: (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* provides the Envoy + * internal exception related to the failure. It is only intended for consumption during manual + * debugging, the string provided is not guaranteed to be stable across Envoy versions. + */ + 'error_detail'?: (_google_rpc_Status); +} + +/** + * A DiscoveryRequest requests a set of versioned resources of the same type for + * a given Envoy node on some API. + * [#next-free-field: 7] + */ +export interface DiscoveryRequest__Output { + /** + * The version_info provided in the request messages will be the version_info + * received with the most recent successfully processed response or empty on + * the first request. It is expected that no new request is sent after a + * response is received until the Envoy instance is ready to ACK/NACK the new + * configuration. ACK/NACK takes place by returning the new API config version + * as applied or the previous API config version respectively. Each type_url + * (see below) has an independent version associated with it. + */ + 'version_info': (string); + /** + * The node making the request. + */ + 'node'?: (_envoy_config_core_v3_Node__Output); + /** + * List of resources to subscribe to, e.g. list of cluster names or a route + * configuration name. If this is empty, all resources for the API are + * returned. LDS/CDS may have empty resource_names, which will cause all + * resources for the Envoy instance to be returned. The LDS and CDS responses + * will then imply a number of resources that need to be fetched via EDS/RDS, + * which will be explicitly enumerated in resource_names. + */ + 'resource_names': (string)[]; + /** + * Type of the resource that is being requested, e.g. + * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit + * in requests made via singleton xDS APIs such as CDS, LDS, etc. but is + * required for ADS. + */ + 'type_url': (string); + /** + * nonce corresponding to DiscoveryResponse being ACK/NACKed. See above + * discussion on version_info and the DiscoveryResponse nonce comment. This + * may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, + * or 2) the client has not yet accepted an update in this xDS stream (unlike + * delta, where it is populated only for new explicit ACKs). + */ + 'response_nonce': (string); + /** + * This is populated when the previous :ref:`DiscoveryResponse ` + * failed to update configuration. The *message* field in *error_details* provides the Envoy + * internal exception related to the failure. It is only intended for consumption during manual + * debugging, the string provided is not guaranteed to be stable across Envoy versions. + */ + 'error_detail'?: (_google_rpc_Status__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts new file mode 100644 index 000000000..f69944b80 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts @@ -0,0 +1,106 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/discovery.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { ControlPlane as _envoy_config_core_v3_ControlPlane, ControlPlane__Output as _envoy_config_core_v3_ControlPlane__Output } from '../../../../envoy/config/core/v3/ControlPlane'; + +/** + * [#next-free-field: 7] + */ +export interface DiscoveryResponse { + /** + * The version of the response data. + */ + 'version_info'?: (string); + /** + * The response resources. These resources are typed and depend on the API being called. + */ + 'resources'?: (_google_protobuf_Any)[]; + /** + * [#not-implemented-hide:] + * Canary is used to support two Envoy command line flags: + * + * * --terminate-on-canary-transition-failure. When set, Envoy is able to + * terminate if it detects that configuration is stuck at canary. Consider + * this example sequence of updates: + * - Management server applies a canary config successfully. + * - Management server rolls back to a production config. + * - Envoy rejects the new production config. + * Since there is no sensible way to continue receiving configuration + * updates, Envoy will then terminate and apply production config from a + * clean slate. + * * --dry-run-canary. When set, a canary response will never be applied, only + * validated via a dry run. + */ + 'canary'?: (boolean); + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the 'resources' repeated Any (if non-empty). + */ + 'type_url'?: (string); + /** + * For gRPC based subscriptions, the nonce provides a way to explicitly ack a + * specific DiscoveryResponse in a following DiscoveryRequest. Additional + * messages may have been sent by Envoy to the management server for the + * previous version on the stream prior to this DiscoveryResponse, that were + * unprocessed at response send time. The nonce allows the management server + * to ignore any further DiscoveryRequests for the previous version until a + * DiscoveryRequest bearing the nonce. The nonce is optional and is not + * required for non-stream based xDS implementations. + */ + 'nonce'?: (string); + /** + * The control plane instance that sent the response. + */ + 'control_plane'?: (_envoy_config_core_v3_ControlPlane); +} + +/** + * [#next-free-field: 7] + */ +export interface DiscoveryResponse__Output { + /** + * The version of the response data. + */ + 'version_info': (string); + /** + * The response resources. These resources are typed and depend on the API being called. + */ + 'resources': (_google_protobuf_Any__Output)[]; + /** + * [#not-implemented-hide:] + * Canary is used to support two Envoy command line flags: + * + * * --terminate-on-canary-transition-failure. When set, Envoy is able to + * terminate if it detects that configuration is stuck at canary. Consider + * this example sequence of updates: + * - Management server applies a canary config successfully. + * - Management server rolls back to a production config. + * - Envoy rejects the new production config. + * Since there is no sensible way to continue receiving configuration + * updates, Envoy will then terminate and apply production config from a + * clean slate. + * * --dry-run-canary. When set, a canary response will never be applied, only + * validated via a dry run. + */ + 'canary': (boolean); + /** + * Type URL for resources. Identifies the xDS API when muxing over ADS. + * Must be consistent with the type_url in the 'resources' repeated Any (if non-empty). + */ + 'type_url': (string); + /** + * For gRPC based subscriptions, the nonce provides a way to explicitly ack a + * specific DiscoveryResponse in a following DiscoveryRequest. Additional + * messages may have been sent by Envoy to the management server for the + * previous version on the stream prior to this DiscoveryResponse, that were + * unprocessed at response send time. The nonce allows the management server + * to ignore any further DiscoveryRequests for the previous version until a + * DiscoveryRequest bearing the nonce. The nonce is optional and is not + * required for non-stream based xDS implementations. + */ + 'nonce': (string); + /** + * The control plane instance that sent the response. + */ + 'control_plane'?: (_envoy_config_core_v3_ControlPlane__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts new file mode 100644 index 000000000..27a70c97c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts @@ -0,0 +1,118 @@ +// Original file: deps/envoy-api/envoy/service/discovery/v3/discovery.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * Cache control properties for the resource. + * [#not-implemented-hide:] + */ +export interface _envoy_service_discovery_v3_Resource_CacheControl { + /** + * If true, xDS proxies may not cache this resource. + * Note that this does not apply to clients other than xDS proxies, which must cache resources + * for their own use, regardless of the value of this field. + */ + 'do_not_cache'?: (boolean); +} + +/** + * Cache control properties for the resource. + * [#not-implemented-hide:] + */ +export interface _envoy_service_discovery_v3_Resource_CacheControl__Output { + /** + * If true, xDS proxies may not cache this resource. + * Note that this does not apply to clients other than xDS proxies, which must cache resources + * for their own use, regardless of the value of this field. + */ + 'do_not_cache': (boolean); +} + +/** + * [#next-free-field: 8] + */ +export interface Resource { + /** + * The resource level version. It allows xDS to track the state of individual + * resources. + */ + 'version'?: (string); + /** + * The resource being tracked. + */ + 'resource'?: (_google_protobuf_Any); + /** + * The resource's name, to distinguish it from others of the same type of resource. + */ + 'name'?: (string); + /** + * The aliases are a list of other names that this resource can go by. + */ + 'aliases'?: (string)[]; + /** + * Time-to-live value for the resource. For each resource, a timer is started. The timer is + * reset each time the resource is received with a new TTL. If the resource is received with + * no TTL set, the timer is removed for the resource. Upon expiration of the timer, the + * configuration for the resource will be removed. + * + * The TTL can be refreshed or changed by sending a response that doesn't change the resource + * version. In this case the resource field does not need to be populated, which allows for + * light-weight "heartbeat" updates to keep a resource with a TTL alive. + * + * The TTL feature is meant to support configurations that should be removed in the event of + * a management server failure. For example, the feature may be used for fault injection + * testing where the fault injection should be terminated in the event that Envoy loses contact + * with the management server. + */ + 'ttl'?: (_google_protobuf_Duration); + /** + * Cache control properties for the resource. + * [#not-implemented-hide:] + */ + 'cache_control'?: (_envoy_service_discovery_v3_Resource_CacheControl); +} + +/** + * [#next-free-field: 8] + */ +export interface Resource__Output { + /** + * The resource level version. It allows xDS to track the state of individual + * resources. + */ + 'version': (string); + /** + * The resource being tracked. + */ + 'resource'?: (_google_protobuf_Any__Output); + /** + * The resource's name, to distinguish it from others of the same type of resource. + */ + 'name': (string); + /** + * The aliases are a list of other names that this resource can go by. + */ + 'aliases': (string)[]; + /** + * Time-to-live value for the resource. For each resource, a timer is started. The timer is + * reset each time the resource is received with a new TTL. If the resource is received with + * no TTL set, the timer is removed for the resource. Upon expiration of the timer, the + * configuration for the resource will be removed. + * + * The TTL can be refreshed or changed by sending a response that doesn't change the resource + * version. In this case the resource field does not need to be populated, which allows for + * light-weight "heartbeat" updates to keep a resource with a TTL alive. + * + * The TTL feature is meant to support configurations that should be removed in the event of + * a management server failure. For example, the feature may be used for fault injection + * testing where the fault injection should be terminated in the event that Envoy loses contact + * with the management server. + */ + 'ttl'?: (_google_protobuf_Duration__Output); + /** + * Cache control properties for the resource. + * [#not-implemented-hide:] + */ + 'cache_control'?: (_envoy_service_discovery_v3_Resource_CacheControl__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts new file mode 100644 index 000000000..24a9de55e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts @@ -0,0 +1,108 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v3/lrs.proto + +import type * as grpc from '@grpc/grpc-js' +import type { LoadStatsRequest as _envoy_service_load_stats_v3_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v3_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v3/LoadStatsRequest'; +import type { LoadStatsResponse as _envoy_service_load_stats_v3_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v3_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v3/LoadStatsResponse'; + +export interface LoadReportingServiceClient extends grpc.Client { + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + StreamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v3_LoadStatsRequest, _envoy_service_load_stats_v3_LoadStatsResponse__Output>; + StreamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v3_LoadStatsRequest, _envoy_service_load_stats_v3_LoadStatsResponse__Output>; + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + streamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v3_LoadStatsRequest, _envoy_service_load_stats_v3_LoadStatsResponse__Output>; + streamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v3_LoadStatsRequest, _envoy_service_load_stats_v3_LoadStatsResponse__Output>; + +} + +export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImplementation { + /** + * Advanced API to allow for multi-dimensional load balancing by remote + * server. For receiving LB assignments, the steps are: + * 1, The management server is configured with per cluster/zone/load metric + * capacity configuration. The capacity configuration definition is + * outside of the scope of this document. + * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters + * to balance. + * + * Independently, Envoy will initiate a StreamLoadStats bidi stream with a + * management server: + * 1. Once a connection establishes, the management server publishes a + * LoadStatsResponse for all clusters it is interested in learning load + * stats about. + * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts + * based on per-zone weights and/or per-instance weights (if specified) + * based on intra-zone LbPolicy. This information comes from the above + * {Stream,Fetch}Endpoints. + * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. + * 4. Envoy aggregates load reports over the period of time given to it in + * LoadStatsResponse.load_reporting_interval. This includes aggregation + * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as + * well as load metrics from upstream hosts. + * 5. When the timer of load_reporting_interval expires, Envoy sends new + * LoadStatsRequest filled with load reports for each cluster. + * 6. The management server uses the load reports from all reported Envoys + * from around the world, computes global assignment and prepares traffic + * assignment destined for each zone Envoys are located in. Goto 2. + */ + StreamLoadStats: grpc.handleBidiStreamingCall<_envoy_service_load_stats_v3_LoadStatsRequest__Output, _envoy_service_load_stats_v3_LoadStatsResponse>; + +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts new file mode 100644 index 000000000..6f0e19525 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts @@ -0,0 +1,32 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v3/lrs.proto + +import type { Node as _envoy_config_core_v3_Node, Node__Output as _envoy_config_core_v3_Node__Output } from '../../../../envoy/config/core/v3/Node'; +import type { ClusterStats as _envoy_config_endpoint_v3_ClusterStats, ClusterStats__Output as _envoy_config_endpoint_v3_ClusterStats__Output } from '../../../../envoy/config/endpoint/v3/ClusterStats'; + +/** + * A load report Envoy sends to the management server. + */ +export interface LoadStatsRequest { + /** + * Node identifier for Envoy instance. + */ + 'node'?: (_envoy_config_core_v3_Node); + /** + * A list of load stats to report. + */ + 'cluster_stats'?: (_envoy_config_endpoint_v3_ClusterStats)[]; +} + +/** + * A load report Envoy sends to the management server. + */ +export interface LoadStatsRequest__Output { + /** + * Node identifier for Envoy instance. + */ + 'node'?: (_envoy_config_core_v3_Node__Output); + /** + * A list of load stats to report. + */ + 'cluster_stats': (_envoy_config_endpoint_v3_ClusterStats__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts new file mode 100644 index 000000000..51f017474 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts @@ -0,0 +1,71 @@ +// Original file: deps/envoy-api/envoy/service/load_stats/v3/lrs.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; + +/** + * The management server sends envoy a LoadStatsResponse with all clusters it + * is interested in learning load stats about. + */ +export interface LoadStatsResponse { + /** + * Clusters to report stats for. + * Not populated if *send_all_clusters* is true. + */ + 'clusters'?: (string)[]; + /** + * The minimum interval of time to collect stats over. This is only a minimum for two reasons: + * + * 1. There may be some delay from when the timer fires until stats sampling occurs. + * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic + * that is observed in between the corresponding previous *LoadStatsRequest* and this + * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period + * of inobservability that might otherwise exists between the messages. New clusters are not + * subject to this consideration. + */ + 'load_reporting_interval'?: (_google_protobuf_Duration); + /** + * Set to *true* if the management server supports endpoint granularity + * report. + */ + 'report_endpoint_granularity'?: (boolean); + /** + * If true, the client should send all clusters it knows about. + * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their + * :ref:`client_features` field will honor this field. + */ + 'send_all_clusters'?: (boolean); +} + +/** + * The management server sends envoy a LoadStatsResponse with all clusters it + * is interested in learning load stats about. + */ +export interface LoadStatsResponse__Output { + /** + * Clusters to report stats for. + * Not populated if *send_all_clusters* is true. + */ + 'clusters': (string)[]; + /** + * The minimum interval of time to collect stats over. This is only a minimum for two reasons: + * + * 1. There may be some delay from when the timer fires until stats sampling occurs. + * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic + * that is observed in between the corresponding previous *LoadStatsRequest* and this + * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period + * of inobservability that might otherwise exists between the messages. New clusters are not + * subject to this consideration. + */ + 'load_reporting_interval'?: (_google_protobuf_Duration__Output); + /** + * Set to *true* if the management server supports endpoint granularity + * report. + */ + 'report_endpoint_granularity': (boolean); + /** + * If true, the client should send all clusters it knows about. + * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their + * :ref:`client_features` field will honor this field. + */ + 'send_all_clusters': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts b/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts index f63553acd..364419994 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts @@ -12,5 +12,5 @@ export interface Percent { * Identifies a percentage, in the range [0.0, 100.0]. */ export interface Percent__Output { - 'value': (number | string); + 'value': (number); } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts deleted file mode 100644 index 42bde031b..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/ListStringMatcher.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/type/matcher/string.proto - -import type { StringMatcher as _envoy_type_matcher_StringMatcher, StringMatcher__Output as _envoy_type_matcher_StringMatcher__Output } from '../../../envoy/type/matcher/StringMatcher'; - -/** - * Specifies a list of ways to match a string. - */ -export interface ListStringMatcher { - 'patterns'?: (_envoy_type_matcher_StringMatcher)[]; -} - -/** - * Specifies a list of ways to match a string. - */ -export interface ListStringMatcher__Output { - 'patterns': (_envoy_type_matcher_StringMatcher__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts new file mode 100644 index 000000000..e91a4898e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/number.proto + +import type { DoubleRange as _envoy_type_v3_DoubleRange, DoubleRange__Output as _envoy_type_v3_DoubleRange__Output } from '../../../../envoy/type/v3/DoubleRange'; + +/** + * Specifies the way to match a double value. + */ +export interface DoubleMatcher { + /** + * If specified, the input double value must be in the range specified here. + * Note: The range is using half-open interval semantics [start, end). + */ + 'range'?: (_envoy_type_v3_DoubleRange); + /** + * If specified, the input double value must be equal to the value specified here. + */ + 'exact'?: (number | string); + 'match_pattern'?: "range"|"exact"; +} + +/** + * Specifies the way to match a double value. + */ +export interface DoubleMatcher__Output { + /** + * If specified, the input double value must be in the range specified here. + * Note: The range is using half-open interval semantics [start, end). + */ + 'range'?: (_envoy_type_v3_DoubleRange__Output); + /** + * If specified, the input double value must be equal to the value specified here. + */ + 'exact'?: (number); + 'match_pattern': "range"|"exact"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts new file mode 100644 index 000000000..c32b72a39 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts @@ -0,0 +1,25 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/value.proto + +import type { ValueMatcher as _envoy_type_matcher_v3_ValueMatcher, ValueMatcher__Output as _envoy_type_matcher_v3_ValueMatcher__Output } from '../../../../envoy/type/matcher/v3/ValueMatcher'; + +/** + * Specifies the way to match a list value. + */ +export interface ListMatcher { + /** + * If specified, at least one of the values in the list must match the value specified. + */ + 'one_of'?: (_envoy_type_matcher_v3_ValueMatcher); + 'match_pattern'?: "one_of"; +} + +/** + * Specifies the way to match a list value. + */ +export interface ListMatcher__Output { + /** + * If specified, at least one of the values in the list must match the value specified. + */ + 'one_of'?: (_envoy_type_matcher_v3_ValueMatcher__Output); + 'match_pattern': "one_of"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListStringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListStringMatcher.ts new file mode 100644 index 000000000..4d5062382 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListStringMatcher.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/string.proto + +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; + +/** + * Specifies a list of ways to match a string. + */ +export interface ListStringMatcher { + 'patterns'?: (_envoy_type_matcher_v3_StringMatcher)[]; +} + +/** + * Specifies a list of ways to match a string. + */ +export interface ListStringMatcher__Output { + 'patterns': (_envoy_type_matcher_v3_StringMatcher__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts new file mode 100644 index 000000000..8d80408a3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts @@ -0,0 +1,65 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/metadata.proto + +import type { ValueMatcher as _envoy_type_matcher_v3_ValueMatcher, ValueMatcher__Output as _envoy_type_matcher_v3_ValueMatcher__Output } from '../../../../envoy/type/matcher/v3/ValueMatcher'; + +/** + * Specifies the segment in a path to retrieve value from Metadata. + * Note: Currently it's not supported to retrieve a value from a list in Metadata. This means that + * if the segment key refers to a list, it has to be the last segment in a path. + */ +export interface _envoy_type_matcher_v3_MetadataMatcher_PathSegment { + /** + * If specified, use the key to retrieve the value in a Struct. + */ + 'key'?: (string); + 'segment'?: "key"; +} + +/** + * Specifies the segment in a path to retrieve value from Metadata. + * Note: Currently it's not supported to retrieve a value from a list in Metadata. This means that + * if the segment key refers to a list, it has to be the last segment in a path. + */ +export interface _envoy_type_matcher_v3_MetadataMatcher_PathSegment__Output { + /** + * If specified, use the key to retrieve the value in a Struct. + */ + 'key'?: (string); + 'segment': "key"; +} + +/** + * [#next-major-version: MetadataMatcher should use StructMatcher] + */ +export interface MetadataMatcher { + /** + * The filter name to retrieve the Struct from the Metadata. + */ + 'filter'?: (string); + /** + * The path to retrieve the Value from the Struct. + */ + 'path'?: (_envoy_type_matcher_v3_MetadataMatcher_PathSegment)[]; + /** + * The MetadataMatcher is matched if the value retrieved by path is matched to this value. + */ + 'value'?: (_envoy_type_matcher_v3_ValueMatcher); +} + +/** + * [#next-major-version: MetadataMatcher should use StructMatcher] + */ +export interface MetadataMatcher__Output { + /** + * The filter name to retrieve the Struct from the Metadata. + */ + 'filter': (string); + /** + * The path to retrieve the Value from the Struct. + */ + 'path': (_envoy_type_matcher_v3_MetadataMatcher_PathSegment__Output)[]; + /** + * The MetadataMatcher is matched if the value retrieved by path is matched to this value. + */ + 'value'?: (_envoy_type_matcher_v3_ValueMatcher__Output); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts similarity index 89% rename from packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts index 17c38c7c0..4abddc655 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatchAndSubstitute.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts @@ -1,6 +1,6 @@ -// Original file: deps/envoy-api/envoy/type/matcher/regex.proto +// Original file: deps/envoy-api/envoy/type/matcher/v3/regex.proto -import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; +import type { RegexMatcher as _envoy_type_matcher_v3_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_v3_RegexMatcher__Output } from '../../../../envoy/type/matcher/v3/RegexMatcher'; /** * Describes how to match a string and then produce a new string using a regular @@ -18,7 +18,7 @@ export interface RegexMatchAndSubstitute { * used in the pattern to extract portions of the subject string, and then * referenced in the substitution string. */ - 'pattern'?: (_envoy_type_matcher_RegexMatcher); + 'pattern'?: (_envoy_type_matcher_v3_RegexMatcher); /** * The string that should be substituted into matching portions of the * subject string during a substitution operation to produce a new string. @@ -49,7 +49,7 @@ export interface RegexMatchAndSubstitute__Output { * used in the pattern to extract portions of the subject string, and then * referenced in the substitution string. */ - 'pattern'?: (_envoy_type_matcher_RegexMatcher__Output); + 'pattern'?: (_envoy_type_matcher_v3_RegexMatcher__Output); /** * The string that should be substituted into matching portions of the * subject string during a substitution operation to produce a new string. diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts similarity index 57% rename from packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts index 8a18816b0..0e8b37f08 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/RegexMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts @@ -1,13 +1,23 @@ -// Original file: deps/envoy-api/envoy/type/matcher/regex.proto +// Original file: deps/envoy-api/envoy/type/matcher/v3/regex.proto -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../google/protobuf/UInt32Value'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; /** * Google's `RE2 `_ regex engine. The regex string must adhere to * the documented `syntax `_. The engine is designed * to complete execution in linear time as well as limit the amount of memory used. + * + * Envoy supports program size checking via runtime. The runtime keys `re2.max_program_size.error_level` + * and `re2.max_program_size.warn_level` can be set to integers as the maximum program size or + * complexity that a compiled regex can have before an exception is thrown or a warning is + * logged, respectively. `re2.max_program_size.error_level` defaults to 100, and + * `re2.max_program_size.warn_level` has no default if unset (will not check/log a warning). + * + * Envoy emits two stats for tracking the program size of regexes: the histogram `re2.program_size`, + * which records the program size, and the counter `re2.exceeded_warn_level`, which is incremented + * each time the program size exceeds the warn level threshold. */ -export interface _envoy_type_matcher_RegexMatcher_GoogleRE2 { +export interface _envoy_type_matcher_v3_RegexMatcher_GoogleRE2 { /** * This field controls the RE2 "program size" which is a rough estimate of how complex a * compiled regex is to evaluate. A regex that has a program size greater than the configured @@ -24,8 +34,18 @@ export interface _envoy_type_matcher_RegexMatcher_GoogleRE2 { * Google's `RE2 `_ regex engine. The regex string must adhere to * the documented `syntax `_. The engine is designed * to complete execution in linear time as well as limit the amount of memory used. + * + * Envoy supports program size checking via runtime. The runtime keys `re2.max_program_size.error_level` + * and `re2.max_program_size.warn_level` can be set to integers as the maximum program size or + * complexity that a compiled regex can have before an exception is thrown or a warning is + * logged, respectively. `re2.max_program_size.error_level` defaults to 100, and + * `re2.max_program_size.warn_level` has no default if unset (will not check/log a warning). + * + * Envoy emits two stats for tracking the program size of regexes: the histogram `re2.program_size`, + * which records the program size, and the counter `re2.exceeded_warn_level`, which is incremented + * each time the program size exceeds the warn level threshold. */ -export interface _envoy_type_matcher_RegexMatcher_GoogleRE2__Output { +export interface _envoy_type_matcher_v3_RegexMatcher_GoogleRE2__Output { /** * This field controls the RE2 "program size" which is a rough estimate of how complex a * compiled regex is to evaluate. A regex that has a program size greater than the configured @@ -45,7 +65,7 @@ export interface RegexMatcher { /** * Google's RE2 regex engine. */ - 'google_re2'?: (_envoy_type_matcher_RegexMatcher_GoogleRE2); + 'google_re2'?: (_envoy_type_matcher_v3_RegexMatcher_GoogleRE2); /** * The regex match string. The string must be supported by the configured engine. */ @@ -60,7 +80,7 @@ export interface RegexMatcher__Output { /** * Google's RE2 regex engine. */ - 'google_re2'?: (_envoy_type_matcher_RegexMatcher_GoogleRE2__Output); + 'google_re2'?: (_envoy_type_matcher_v3_RegexMatcher_GoogleRE2__Output); /** * The regex match string. The string must be supported by the configured engine. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts similarity index 58% rename from packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts rename to packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts index e434b1e1b..58616dde8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/StringMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts @@ -1,10 +1,10 @@ -// Original file: deps/envoy-api/envoy/type/matcher/string.proto +// Original file: deps/envoy-api/envoy/type/matcher/v3/string.proto -import type { RegexMatcher as _envoy_type_matcher_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_RegexMatcher__Output } from '../../../envoy/type/matcher/RegexMatcher'; +import type { RegexMatcher as _envoy_type_matcher_v3_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_v3_RegexMatcher__Output } from '../../../../envoy/type/matcher/v3/RegexMatcher'; /** * Specifies the way to match a string. - * [#next-free-field: 7] + * [#next-free-field: 8] */ export interface StringMatcher { /** @@ -33,38 +33,31 @@ export interface StringMatcher { * * *abc* matches the value *xyz.abc* */ 'suffix'?: (string); - /** - * The input string must match the regular expression specified here. - * The regex grammar is defined `here - * `_. - * - * Examples: - * - * * The regex ``\d{3}`` matches the value *123* - * * The regex ``\d{3}`` does not match the value *1234* - * * The regex ``\d{3}`` does not match the value *123.456* - * - * .. attention:: - * This field has been deprecated in favor of `safe_regex` as it is not safe for use with - * untrusted input in all cases. - */ - 'regex'?: (string); /** * The input string must match the regular expression specified here. */ - 'safe_regex'?: (_envoy_type_matcher_RegexMatcher); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher); /** * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no * effect for the safe_regex match. * For example, the matcher *data* will match both input string *Data* and *data* if set to true. */ 'ignore_case'?: (boolean); - 'match_pattern'?: "exact"|"prefix"|"suffix"|"regex"|"safe_regex"; + /** + * The input string must have the substring specified here. + * Note: empty contains match is not allowed, please use regex instead. + * + * Examples: + * + * * *abc* matches the value *xyz.abc.def* + */ + 'contains'?: (string); + 'match_pattern'?: "exact"|"prefix"|"suffix"|"safe_regex"|"contains"; } /** * Specifies the way to match a string. - * [#next-free-field: 7] + * [#next-free-field: 8] */ export interface StringMatcher__Output { /** @@ -93,31 +86,24 @@ export interface StringMatcher__Output { * * *abc* matches the value *xyz.abc* */ 'suffix'?: (string); - /** - * The input string must match the regular expression specified here. - * The regex grammar is defined `here - * `_. - * - * Examples: - * - * * The regex ``\d{3}`` matches the value *123* - * * The regex ``\d{3}`` does not match the value *1234* - * * The regex ``\d{3}`` does not match the value *123.456* - * - * .. attention:: - * This field has been deprecated in favor of `safe_regex` as it is not safe for use with - * untrusted input in all cases. - */ - 'regex'?: (string); /** * The input string must match the regular expression specified here. */ - 'safe_regex'?: (_envoy_type_matcher_RegexMatcher__Output); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output); /** * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no * effect for the safe_regex match. * For example, the matcher *data* will match both input string *Data* and *data* if set to true. */ 'ignore_case': (boolean); - 'match_pattern': "exact"|"prefix"|"suffix"|"regex"|"safe_regex"; + /** + * The input string must have the substring specified here. + * Note: empty contains match is not allowed, please use regex instead. + * + * Examples: + * + * * *abc* matches the value *xyz.abc.def* + */ + 'contains'?: (string); + 'match_pattern': "exact"|"prefix"|"suffix"|"safe_regex"|"contains"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts new file mode 100644 index 000000000..6c271162a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts @@ -0,0 +1,101 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/value.proto + +import type { DoubleMatcher as _envoy_type_matcher_v3_DoubleMatcher, DoubleMatcher__Output as _envoy_type_matcher_v3_DoubleMatcher__Output } from '../../../../envoy/type/matcher/v3/DoubleMatcher'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; +import type { ListMatcher as _envoy_type_matcher_v3_ListMatcher, ListMatcher__Output as _envoy_type_matcher_v3_ListMatcher__Output } from '../../../../envoy/type/matcher/v3/ListMatcher'; + +/** + * NullMatch is an empty message to specify a null value. + */ +export interface _envoy_type_matcher_v3_ValueMatcher_NullMatch { +} + +/** + * NullMatch is an empty message to specify a null value. + */ +export interface _envoy_type_matcher_v3_ValueMatcher_NullMatch__Output { +} + +/** + * Specifies the way to match a ProtobufWkt::Value. Primitive values and ListValue are supported. + * StructValue is not supported and is always not matched. + * [#next-free-field: 7] + */ +export interface ValueMatcher { + /** + * If specified, a match occurs if and only if the target value is a NullValue. + */ + 'null_match'?: (_envoy_type_matcher_v3_ValueMatcher_NullMatch); + /** + * If specified, a match occurs if and only if the target value is a double value and is + * matched to this field. + */ + 'double_match'?: (_envoy_type_matcher_v3_DoubleMatcher); + /** + * If specified, a match occurs if and only if the target value is a string value and is + * matched to this field. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher); + /** + * If specified, a match occurs if and only if the target value is a bool value and is equal + * to this field. + */ + 'bool_match'?: (boolean); + /** + * If specified, value match will be performed based on whether the path is referring to a + * valid primitive value in the metadata. If the path is referring to a non-primitive value, + * the result is always not matched. + */ + 'present_match'?: (boolean); + /** + * If specified, a match occurs if and only if the target value is a list value and + * is matched to this field. + */ + 'list_match'?: (_envoy_type_matcher_v3_ListMatcher); + /** + * Specifies how to match a value. + */ + 'match_pattern'?: "null_match"|"double_match"|"string_match"|"bool_match"|"present_match"|"list_match"; +} + +/** + * Specifies the way to match a ProtobufWkt::Value. Primitive values and ListValue are supported. + * StructValue is not supported and is always not matched. + * [#next-free-field: 7] + */ +export interface ValueMatcher__Output { + /** + * If specified, a match occurs if and only if the target value is a NullValue. + */ + 'null_match'?: (_envoy_type_matcher_v3_ValueMatcher_NullMatch__Output); + /** + * If specified, a match occurs if and only if the target value is a double value and is + * matched to this field. + */ + 'double_match'?: (_envoy_type_matcher_v3_DoubleMatcher__Output); + /** + * If specified, a match occurs if and only if the target value is a string value and is + * matched to this field. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output); + /** + * If specified, a match occurs if and only if the target value is a bool value and is equal + * to this field. + */ + 'bool_match'?: (boolean); + /** + * If specified, value match will be performed based on whether the path is referring to a + * valid primitive value in the metadata. If the path is referring to a non-primitive value, + * the result is always not matched. + */ + 'present_match'?: (boolean); + /** + * If specified, a match occurs if and only if the target value is a list value and + * is matched to this field. + */ + 'list_match'?: (_envoy_type_matcher_v3_ListMatcher__Output); + /** + * Specifies how to match a value. + */ + 'match_pattern': "null_match"|"double_match"|"string_match"|"bool_match"|"present_match"|"list_match"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts deleted file mode 100644 index 665b95f0d..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKind.ts +++ /dev/null @@ -1,98 +0,0 @@ -// Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto - - -/** - * Represents metadata from :ref:`the upstream cluster`. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Cluster { -} - -/** - * Represents metadata from :ref:`the upstream cluster`. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Cluster__Output { -} - -/** - * Represents metadata from :ref:`the upstream - * host`. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Host { -} - -/** - * Represents metadata from :ref:`the upstream - * host`. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Host__Output { -} - -/** - * Represents dynamic metadata associated with the request. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Request { -} - -/** - * Represents dynamic metadata associated with the request. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Request__Output { -} - -/** - * Represents metadata from :ref:`the route`. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Route { -} - -/** - * Represents metadata from :ref:`the route`. - */ -export interface _envoy_type_metadata_v2_MetadataKind_Route__Output { -} - -/** - * Describes what kind of metadata. - */ -export interface MetadataKind { - /** - * Request kind of metadata. - */ - 'request'?: (_envoy_type_metadata_v2_MetadataKind_Request); - /** - * Route kind of metadata. - */ - 'route'?: (_envoy_type_metadata_v2_MetadataKind_Route); - /** - * Cluster kind of metadata. - */ - 'cluster'?: (_envoy_type_metadata_v2_MetadataKind_Cluster); - /** - * Host kind of metadata. - */ - 'host'?: (_envoy_type_metadata_v2_MetadataKind_Host); - 'kind'?: "request"|"route"|"cluster"|"host"; -} - -/** - * Describes what kind of metadata. - */ -export interface MetadataKind__Output { - /** - * Request kind of metadata. - */ - 'request'?: (_envoy_type_metadata_v2_MetadataKind_Request__Output); - /** - * Route kind of metadata. - */ - 'route'?: (_envoy_type_metadata_v2_MetadataKind_Route__Output); - /** - * Cluster kind of metadata. - */ - 'cluster'?: (_envoy_type_metadata_v2_MetadataKind_Cluster__Output); - /** - * Host kind of metadata. - */ - 'host'?: (_envoy_type_metadata_v2_MetadataKind_Host__Output); - 'kind': "request"|"route"|"cluster"|"host"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts similarity index 85% rename from packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts rename to packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts index 94d661879..fcc43b07b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v2/MetadataKey.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts @@ -1,11 +1,11 @@ -// Original file: deps/envoy-api/envoy/type/metadata/v2/metadata.proto +// Original file: deps/envoy-api/envoy/type/metadata/v3/metadata.proto /** * Specifies the segment in a path to retrieve value from Metadata. * Currently it is only supported to specify the key, i.e. field name, as one segment of a path. */ -export interface _envoy_type_metadata_v2_MetadataKey_PathSegment { +export interface _envoy_type_metadata_v3_MetadataKey_PathSegment { /** * If specified, use the key to retrieve the value in a Struct. */ @@ -17,7 +17,7 @@ export interface _envoy_type_metadata_v2_MetadataKey_PathSegment { * Specifies the segment in a path to retrieve value from Metadata. * Currently it is only supported to specify the key, i.e. field name, as one segment of a path. */ -export interface _envoy_type_metadata_v2_MetadataKey_PathSegment__Output { +export interface _envoy_type_metadata_v3_MetadataKey_PathSegment__Output { /** * If specified, use the key to retrieve the value in a Struct. */ @@ -27,7 +27,7 @@ export interface _envoy_type_metadata_v2_MetadataKey_PathSegment__Output { /** * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. + * :ref:`Metadata `. * * For example, for the following Metadata: * @@ -63,12 +63,12 @@ export interface MetadataKey { * Note: Due to that only the key type segment is supported, the path can not specify a list * unless the list is the last segment. */ - 'path'?: (_envoy_type_metadata_v2_MetadataKey_PathSegment)[]; + 'path'?: (_envoy_type_metadata_v3_MetadataKey_PathSegment)[]; } /** * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. + * :ref:`Metadata `. * * For example, for the following Metadata: * @@ -104,5 +104,5 @@ export interface MetadataKey__Output { * Note: Due to that only the key type segment is supported, the path can not specify a list * unless the list is the last segment. */ - 'path': (_envoy_type_metadata_v2_MetadataKey_PathSegment__Output)[]; + 'path': (_envoy_type_metadata_v3_MetadataKey_PathSegment__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts new file mode 100644 index 000000000..c231ecf98 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts @@ -0,0 +1,98 @@ +// Original file: deps/envoy-api/envoy/type/metadata/v3/metadata.proto + + +/** + * Represents metadata from :ref:`the upstream cluster`. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Cluster { +} + +/** + * Represents metadata from :ref:`the upstream cluster`. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Cluster__Output { +} + +/** + * Represents metadata from :ref:`the upstream + * host`. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Host { +} + +/** + * Represents metadata from :ref:`the upstream + * host`. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Host__Output { +} + +/** + * Represents dynamic metadata associated with the request. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Request { +} + +/** + * Represents dynamic metadata associated with the request. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Request__Output { +} + +/** + * Represents metadata from :ref:`the route`. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Route { +} + +/** + * Represents metadata from :ref:`the route`. + */ +export interface _envoy_type_metadata_v3_MetadataKind_Route__Output { +} + +/** + * Describes what kind of metadata. + */ +export interface MetadataKind { + /** + * Request kind of metadata. + */ + 'request'?: (_envoy_type_metadata_v3_MetadataKind_Request); + /** + * Route kind of metadata. + */ + 'route'?: (_envoy_type_metadata_v3_MetadataKind_Route); + /** + * Cluster kind of metadata. + */ + 'cluster'?: (_envoy_type_metadata_v3_MetadataKind_Cluster); + /** + * Host kind of metadata. + */ + 'host'?: (_envoy_type_metadata_v3_MetadataKind_Host); + 'kind'?: "request"|"route"|"cluster"|"host"; +} + +/** + * Describes what kind of metadata. + */ +export interface MetadataKind__Output { + /** + * Request kind of metadata. + */ + 'request'?: (_envoy_type_metadata_v3_MetadataKind_Request__Output); + /** + * Route kind of metadata. + */ + 'route'?: (_envoy_type_metadata_v3_MetadataKind_Route__Output); + /** + * Cluster kind of metadata. + */ + 'cluster'?: (_envoy_type_metadata_v3_MetadataKind_Cluster__Output); + /** + * Host kind of metadata. + */ + 'host'?: (_envoy_type_metadata_v3_MetadataKind_Host__Output); + 'kind': "request"|"route"|"cluster"|"host"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts similarity index 66% rename from packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts rename to packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts index 3eed4cf44..ef29c3420 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v2/CustomTag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts @@ -1,12 +1,12 @@ -// Original file: deps/envoy-api/envoy/type/tracing/v2/custom_tag.proto +// Original file: deps/envoy-api/envoy/type/tracing/v3/custom_tag.proto -import type { MetadataKind as _envoy_type_metadata_v2_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v2_MetadataKind__Output } from '../../../../envoy/type/metadata/v2/MetadataKind'; -import type { MetadataKey as _envoy_type_metadata_v2_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v2_MetadataKey__Output } from '../../../../envoy/type/metadata/v2/MetadataKey'; +import type { MetadataKind as _envoy_type_metadata_v3_MetadataKind, MetadataKind__Output as _envoy_type_metadata_v3_MetadataKind__Output } from '../../../../envoy/type/metadata/v3/MetadataKind'; +import type { MetadataKey as _envoy_type_metadata_v3_MetadataKey, MetadataKey__Output as _envoy_type_metadata_v3_MetadataKey__Output } from '../../../../envoy/type/metadata/v3/MetadataKey'; /** * Environment type custom tag with environment name and default value. */ -export interface _envoy_type_tracing_v2_CustomTag_Environment { +export interface _envoy_type_tracing_v3_CustomTag_Environment { /** * Environment variable name to obtain the value to populate the tag value. */ @@ -22,7 +22,7 @@ export interface _envoy_type_tracing_v2_CustomTag_Environment { /** * Environment type custom tag with environment name and default value. */ -export interface _envoy_type_tracing_v2_CustomTag_Environment__Output { +export interface _envoy_type_tracing_v3_CustomTag_Environment__Output { /** * Environment variable name to obtain the value to populate the tag value. */ @@ -38,7 +38,7 @@ export interface _envoy_type_tracing_v2_CustomTag_Environment__Output { /** * Header type custom tag with header name and default value. */ -export interface _envoy_type_tracing_v2_CustomTag_Header { +export interface _envoy_type_tracing_v3_CustomTag_Header { /** * Header name to obtain the value to populate the tag value. */ @@ -54,7 +54,7 @@ export interface _envoy_type_tracing_v2_CustomTag_Header { /** * Header type custom tag with header name and default value. */ -export interface _envoy_type_tracing_v2_CustomTag_Header__Output { +export interface _envoy_type_tracing_v3_CustomTag_Header__Output { /** * Header name to obtain the value to populate the tag value. */ @@ -70,7 +70,7 @@ export interface _envoy_type_tracing_v2_CustomTag_Header__Output { /** * Literal type custom tag with static value for the tag value. */ -export interface _envoy_type_tracing_v2_CustomTag_Literal { +export interface _envoy_type_tracing_v3_CustomTag_Literal { /** * Static literal value to populate the tag value. */ @@ -80,7 +80,7 @@ export interface _envoy_type_tracing_v2_CustomTag_Literal { /** * Literal type custom tag with static value for the tag value. */ -export interface _envoy_type_tracing_v2_CustomTag_Literal__Output { +export interface _envoy_type_tracing_v3_CustomTag_Literal__Output { /** * Static literal value to populate the tag value. */ @@ -89,20 +89,20 @@ export interface _envoy_type_tracing_v2_CustomTag_Literal__Output { /** * Metadata type custom tag using - * :ref:`MetadataKey ` to retrieve the protobuf value - * from :ref:`Metadata `, and populate the tag value with + * :ref:`MetadataKey ` to retrieve the protobuf value + * from :ref:`Metadata `, and populate the tag value with * `the canonical JSON `_ * representation of it. */ -export interface _envoy_type_tracing_v2_CustomTag_Metadata { +export interface _envoy_type_tracing_v3_CustomTag_Metadata { /** * Specify what kind of metadata to obtain tag value from. */ - 'kind'?: (_envoy_type_metadata_v2_MetadataKind); + 'kind'?: (_envoy_type_metadata_v3_MetadataKind); /** * Metadata key to define the path to retrieve the tag value. */ - 'metadata_key'?: (_envoy_type_metadata_v2_MetadataKey); + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); /** * When no valid metadata is found, * the tag value would be populated with this default value if specified, @@ -113,20 +113,20 @@ export interface _envoy_type_tracing_v2_CustomTag_Metadata { /** * Metadata type custom tag using - * :ref:`MetadataKey ` to retrieve the protobuf value - * from :ref:`Metadata `, and populate the tag value with + * :ref:`MetadataKey ` to retrieve the protobuf value + * from :ref:`Metadata `, and populate the tag value with * `the canonical JSON `_ * representation of it. */ -export interface _envoy_type_tracing_v2_CustomTag_Metadata__Output { +export interface _envoy_type_tracing_v3_CustomTag_Metadata__Output { /** * Specify what kind of metadata to obtain tag value from. */ - 'kind'?: (_envoy_type_metadata_v2_MetadataKind__Output); + 'kind'?: (_envoy_type_metadata_v3_MetadataKind__Output); /** * Metadata key to define the path to retrieve the tag value. */ - 'metadata_key'?: (_envoy_type_metadata_v2_MetadataKey__Output); + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); /** * When no valid metadata is found, * the tag value would be populated with this default value if specified, @@ -147,19 +147,19 @@ export interface CustomTag { /** * A literal custom tag. */ - 'literal'?: (_envoy_type_tracing_v2_CustomTag_Literal); + 'literal'?: (_envoy_type_tracing_v3_CustomTag_Literal); /** * An environment custom tag. */ - 'environment'?: (_envoy_type_tracing_v2_CustomTag_Environment); + 'environment'?: (_envoy_type_tracing_v3_CustomTag_Environment); /** * A request header custom tag. */ - 'request_header'?: (_envoy_type_tracing_v2_CustomTag_Header); + 'request_header'?: (_envoy_type_tracing_v3_CustomTag_Header); /** * A custom tag to obtain tag value from the metadata. */ - 'metadata'?: (_envoy_type_tracing_v2_CustomTag_Metadata); + 'metadata'?: (_envoy_type_tracing_v3_CustomTag_Metadata); /** * Used to specify what kind of custom tag. */ @@ -178,19 +178,19 @@ export interface CustomTag__Output { /** * A literal custom tag. */ - 'literal'?: (_envoy_type_tracing_v2_CustomTag_Literal__Output); + 'literal'?: (_envoy_type_tracing_v3_CustomTag_Literal__Output); /** * An environment custom tag. */ - 'environment'?: (_envoy_type_tracing_v2_CustomTag_Environment__Output); + 'environment'?: (_envoy_type_tracing_v3_CustomTag_Environment__Output); /** * A request header custom tag. */ - 'request_header'?: (_envoy_type_tracing_v2_CustomTag_Header__Output); + 'request_header'?: (_envoy_type_tracing_v3_CustomTag_Header__Output); /** * A custom tag to obtain tag value from the metadata. */ - 'metadata'?: (_envoy_type_tracing_v2_CustomTag_Metadata__Output); + 'metadata'?: (_envoy_type_tracing_v3_CustomTag_Metadata__Output); /** * Used to specify what kind of custom tag. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/CodecClientType.ts similarity index 84% rename from packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts rename to packages/grpc-js-xds/src/generated/envoy/type/v3/CodecClientType.ts index a0bf07351..308f14446 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/CodecClientType.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/CodecClientType.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/type/http.proto +// Original file: deps/envoy-api/envoy/type/v3/http.proto export enum CodecClientType { HTTP1 = 0, diff --git a/packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/DoubleRange.ts similarity index 82% rename from packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts rename to packages/grpc-js-xds/src/generated/envoy/type/v3/DoubleRange.ts index 5ebc3a579..5d13bebdb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/DoubleRange.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/DoubleRange.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/type/range.proto +// Original file: deps/envoy-api/envoy/type/v3/range.proto /** @@ -24,9 +24,9 @@ export interface DoubleRange__Output { /** * start of the range (inclusive) */ - 'start': (number | string); + 'start': (number); /** * end of the range (exclusive) */ - 'end': (number | string); + 'end': (number); } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/v3/FractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/FractionalPercent.ts new file mode 100644 index 000000000..564af9a0f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/FractionalPercent.ts @@ -0,0 +1,68 @@ +// Original file: deps/envoy-api/envoy/type/v3/percent.proto + + +// Original file: deps/envoy-api/envoy/type/v3/percent.proto + +/** + * Fraction percentages support several fixed denominator values. + */ +export enum _envoy_type_v3_FractionalPercent_DenominatorType { + /** + * 100. + * + * **Example**: 1/100 = 1%. + */ + HUNDRED = 0, + /** + * 10,000. + * + * **Example**: 1/10000 = 0.01%. + */ + TEN_THOUSAND = 1, + /** + * 1,000,000. + * + * **Example**: 1/1000000 = 0.0001%. + */ + MILLION = 2, +} + +/** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ +export interface FractionalPercent { + /** + * Specifies the numerator. Defaults to 0. + */ + 'numerator'?: (number); + /** + * Specifies the denominator. If the denominator specified is less than the numerator, the final + * fractional percentage is capped at 1 (100%). + */ + 'denominator'?: (_envoy_type_v3_FractionalPercent_DenominatorType | keyof typeof _envoy_type_v3_FractionalPercent_DenominatorType); +} + +/** + * A fractional percentage is used in cases in which for performance reasons performing floating + * point to integer conversions during randomness calculations is undesirable. The message includes + * both a numerator and denominator that together determine the final fractional value. + * + * * **Example**: 1/100 = 1%. + * * **Example**: 3/10000 = 0.03%. + */ +export interface FractionalPercent__Output { + /** + * Specifies the numerator. Defaults to 0. + */ + 'numerator': (number); + /** + * Specifies the denominator. If the denominator specified is less than the numerator, the final + * fractional percentage is capped at 1 (100%). + */ + 'denominator': (keyof typeof _envoy_type_v3_FractionalPercent_DenominatorType); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/Int32Range.ts similarity index 90% rename from packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts rename to packages/grpc-js-xds/src/generated/envoy/type/v3/Int32Range.ts index f5475c2db..826af6c38 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/Int32Range.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/Int32Range.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/type/range.proto +// Original file: deps/envoy-api/envoy/type/v3/range.proto /** diff --git a/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/Int64Range.ts similarity index 91% rename from packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts rename to packages/grpc-js-xds/src/generated/envoy/type/v3/Int64Range.ts index f9664cba4..89ce7fb8d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/Int64Range.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/Int64Range.ts @@ -1,4 +1,4 @@ -// Original file: deps/envoy-api/envoy/type/range.proto +// Original file: deps/envoy-api/envoy/type/v3/range.proto import type { Long } from '@grpc/proto-loader'; diff --git a/packages/grpc-js-xds/src/generated/envoy/type/v3/Percent.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/Percent.ts new file mode 100644 index 000000000..01d236c4e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/Percent.ts @@ -0,0 +1,16 @@ +// Original file: deps/envoy-api/envoy/type/v3/percent.proto + + +/** + * Identifies a percentage, in the range [0.0, 100.0]. + */ +export interface Percent { + 'value'?: (number | string); +} + +/** + * Identifies a percentage, in the range [0.0, 100.0]. + */ +export interface Percent__Output { + 'value': (number); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/v3/SemanticVersion.ts b/packages/grpc-js-xds/src/generated/envoy/type/v3/SemanticVersion.ts new file mode 100644 index 000000000..3f714a766 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/v3/SemanticVersion.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/type/v3/semantic_version.proto + + +/** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ +export interface SemanticVersion { + 'major_number'?: (number); + 'minor_number'?: (number); + 'patch'?: (number); +} + +/** + * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate + * expected behaviors and APIs, the patch version field is used only + * for security fixes and can be generally ignored. + */ +export interface SemanticVersion__Output { + 'major_number': (number); + 'minor_number': (number); + 'patch': (number); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts b/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts deleted file mode 100644 index 2b6490be6..000000000 --- a/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Original file: deps/googleapis/google/api/http.proto - - -/** - * A custom pattern is used for defining custom HTTP verb. - */ -export interface CustomHttpPattern { - /** - * The name of this custom HTTP verb. - */ - 'kind'?: (string); - /** - * The path matched by this custom verb. - */ - 'path'?: (string); -} - -/** - * A custom pattern is used for defining custom HTTP verb. - */ -export interface CustomHttpPattern__Output { - /** - * The name of this custom HTTP verb. - */ - 'kind': (string); - /** - * The path matched by this custom verb. - */ - 'path': (string); -} diff --git a/packages/grpc-js-xds/src/generated/google/api/Http.ts b/packages/grpc-js-xds/src/generated/google/api/Http.ts deleted file mode 100644 index e9b3cb309..000000000 --- a/packages/grpc-js-xds/src/generated/google/api/Http.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Original file: deps/googleapis/google/api/http.proto - -import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; - -/** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ -export interface Http { - /** - * A list of HTTP configuration rules that apply to individual API methods. - * - * **NOTE:** All service configuration rules follow "last one wins" order. - */ - 'rules'?: (_google_api_HttpRule)[]; - /** - * When set to true, URL path parameters will be fully URI-decoded except in - * cases of single segment matches in reserved expansion, where "%2F" will be - * left encoded. - * - * The default behavior is to not decode RFC 6570 reserved characters in multi - * segment matches. - */ - 'fully_decode_reserved_expansion'?: (boolean); -} - -/** - * Defines the HTTP configuration for an API service. It contains a list of - * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method - * to one or more HTTP REST API methods. - */ -export interface Http__Output { - /** - * A list of HTTP configuration rules that apply to individual API methods. - * - * **NOTE:** All service configuration rules follow "last one wins" order. - */ - 'rules': (_google_api_HttpRule__Output)[]; - /** - * When set to true, URL path parameters will be fully URI-decoded except in - * cases of single segment matches in reserved expansion, where "%2F" will be - * left encoded. - * - * The default behavior is to not decode RFC 6570 reserved characters in multi - * segment matches. - */ - 'fully_decode_reserved_expansion': (boolean); -} diff --git a/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts deleted file mode 100644 index 21ad897ee..000000000 --- a/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts +++ /dev/null @@ -1,680 +0,0 @@ -// Original file: deps/googleapis/google/api/http.proto - -import type { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; -import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; - -/** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ -export interface HttpRule { - /** - * Selects a method to which this rule applies. - * - * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. - */ - 'selector'?: (string); - /** - * Maps to HTTP GET. Used for listing and getting information about - * resources. - */ - 'get'?: (string); - /** - * Maps to HTTP PUT. Used for replacing a resource. - */ - 'put'?: (string); - /** - * Maps to HTTP POST. Used for creating a resource or performing an action. - */ - 'post'?: (string); - /** - * Maps to HTTP DELETE. Used for deleting a resource. - */ - 'delete'?: (string); - /** - * Maps to HTTP PATCH. Used for updating a resource. - */ - 'patch'?: (string); - /** - * The name of the request field whose value is mapped to the HTTP request - * body, or `*` for mapping all request fields not captured by the path - * pattern to the HTTP body, or omitted for not having any HTTP request body. - * - * NOTE: the referred field must be present at the top-level of the request - * message type. - */ - 'body'?: (string); - /** - * The custom pattern is used for specifying an HTTP method that is not - * included in the `pattern` field, such as HEAD, or "*" to leave the - * HTTP method unspecified for this rule. The wild-card rule is useful - * for services that provide content to Web (HTML) clients. - */ - 'custom'?: (_google_api_CustomHttpPattern); - /** - * Additional HTTP bindings for the selector. Nested bindings must - * not contain an `additional_bindings` field themselves (that is, - * the nesting may only be one level deep). - */ - 'additional_bindings'?: (_google_api_HttpRule)[]; - /** - * Optional. The name of the response field whose value is mapped to the HTTP - * response body. When omitted, the entire response message will be used - * as the HTTP response body. - * - * NOTE: The referred field must be present at the top-level of the response - * message type. - */ - 'response_body'?: (string); - /** - * Determines the URL pattern is matched by this rules. This pattern can be - * used with any of the {get|put|post|delete|patch} methods. A custom method - * can be defined using the 'custom' field. - */ - 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; -} - -/** - * # gRPC Transcoding - * - * gRPC Transcoding is a feature for mapping between a gRPC method and one or - * more HTTP REST endpoints. It allows developers to build a single API service - * that supports both gRPC APIs and REST APIs. Many systems, including [Google - * APIs](https://github.com/googleapis/googleapis), - * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC - * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), - * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature - * and use it for large scale production services. - * - * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies - * how different portions of the gRPC request message are mapped to the URL - * path, URL query parameters, and HTTP request body. It also controls how the - * gRPC response message is mapped to the HTTP response body. `HttpRule` is - * typically specified as an `google.api.http` annotation on the gRPC method. - * - * Each mapping specifies a URL path template and an HTTP method. The path - * template may refer to one or more fields in the gRPC request message, as long - * as each field is a non-repeated field with a primitive (non-message) type. - * The path template controls how fields of the request message are mapped to - * the URL path. - * - * Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/{name=messages/*}" - * }; - * } - * } - * message GetMessageRequest { - * string name = 1; // Mapped to URL path. - * } - * message Message { - * string text = 1; // The resource content. - * } - * - * This enables an HTTP REST to gRPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` - * - * Any fields in the request message which are not bound by the path template - * automatically become HTTP query parameters if there is no HTTP request body. - * For example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get:"/v1/messages/{message_id}" - * }; - * } - * } - * message GetMessageRequest { - * message SubMessage { - * string subfield = 1; - * } - * string message_id = 1; // Mapped to URL path. - * int64 revision = 2; // Mapped to URL query parameter `revision`. - * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. - * } - * - * This enables a HTTP JSON to RPC mapping as below: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | - * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: - * "foo"))` - * - * Note that fields which are mapped to URL query parameters must have a - * primitive type or a repeated primitive type or a non-repeated message type. - * In the case of a repeated type, the parameter can be repeated in the URL - * as `...?param=A¶m=B`. In the case of a message type, each field of the - * message is mapped to a separate parameter, such as - * `...?foo.a=A&foo.b=B&foo.c=C`. - * - * For HTTP methods that allow a request body, the `body` field - * specifies the mapping. Consider a REST update method on the - * message resource collection: - * - * service Messaging { - * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "message" - * }; - * } - * } - * message UpdateMessageRequest { - * string message_id = 1; // mapped to the URL - * Message message = 2; // mapped to the body - * } - * - * The following HTTP JSON to RPC mapping is enabled, where the - * representation of the JSON in the request body is determined by - * protos JSON encoding: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" message { text: "Hi!" })` - * - * The special name `*` can be used in the body mapping to define that - * every field not bound by the path template should be mapped to the - * request body. This enables the following alternative definition of - * the update method: - * - * service Messaging { - * rpc UpdateMessage(Message) returns (Message) { - * option (google.api.http) = { - * patch: "/v1/messages/{message_id}" - * body: "*" - * }; - * } - * } - * message Message { - * string message_id = 1; - * string text = 2; - * } - * - * - * The following HTTP JSON to RPC mapping is enabled: - * - * HTTP | gRPC - * -----|----- - * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: - * "123456" text: "Hi!")` - * - * Note that when using `*` in the body mapping, it is not possible to - * have HTTP parameters, as all fields not bound by the path end in - * the body. This makes this option more rarely used in practice when - * defining REST APIs. The common usage of `*` is in custom methods - * which don't use the URL at all for transferring data. - * - * It is possible to define multiple HTTP methods for one RPC by using - * the `additional_bindings` option. Example: - * - * service Messaging { - * rpc GetMessage(GetMessageRequest) returns (Message) { - * option (google.api.http) = { - * get: "/v1/messages/{message_id}" - * additional_bindings { - * get: "/v1/users/{user_id}/messages/{message_id}" - * } - * }; - * } - * } - * message GetMessageRequest { - * string message_id = 1; - * string user_id = 2; - * } - * - * This enables the following two alternative HTTP JSON to RPC mappings: - * - * HTTP | gRPC - * -----|----- - * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` - * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: - * "123456")` - * - * ## Rules for HTTP mapping - * - * 1. Leaf request fields (recursive expansion nested messages in the request - * message) are classified into three categories: - * - Fields referred by the path template. They are passed via the URL path. - * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP - * request body. - * - All other fields are passed via the URL query parameters, and the - * parameter name is the field path in the request message. A repeated - * field can be represented as multiple query parameters under the same - * name. - * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields - * are passed via URL path and HTTP request body. - * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all - * fields are passed via URL path and URL query parameters. - * - * ### Path template syntax - * - * Template = "/" Segments [ Verb ] ; - * Segments = Segment { "/" Segment } ; - * Segment = "*" | "**" | LITERAL | Variable ; - * Variable = "{" FieldPath [ "=" Segments ] "}" ; - * FieldPath = IDENT { "." IDENT } ; - * Verb = ":" LITERAL ; - * - * The syntax `*` matches a single URL path segment. The syntax `**` matches - * zero or more URL path segments, which must be the last part of the URL path - * except the `Verb`. - * - * The syntax `Variable` matches part of the URL path as specified by its - * template. A variable template must not contain other variables. If a variable - * matches a single path segment, its template may be omitted, e.g. `{var}` - * is equivalent to `{var=*}`. - * - * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` - * contains any reserved character, such characters should be percent-encoded - * before the matching. - * - * If a variable contains exactly one path segment, such as `"{var}"` or - * `"{var=*}"`, when such a variable is expanded into a URL path on the client - * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The - * server side does the reverse decoding. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{var}`. - * - * If a variable contains multiple path segments, such as `"{var=foo/*}"` - * or `"{var=**}"`, when such a variable is expanded into a URL path on the - * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. - * The server side does the reverse decoding, except "%2F" and "%2f" are left - * unchanged. Such variables show up in the - * [Discovery - * Document](https://developers.google.com/discovery/v1/reference/apis) as - * `{+var}`. - * - * ## Using gRPC API Service Configuration - * - * gRPC API Service Configuration (service config) is a configuration language - * for configuring a gRPC service to become a user-facing product. The - * service config is simply the YAML representation of the `google.api.Service` - * proto message. - * - * As an alternative to annotating your proto file, you can configure gRPC - * transcoding in your service config YAML files. You do this by specifying a - * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same - * effect as the proto annotation. This can be particularly useful if you - * have a proto that is reused in multiple services. Note that any transcoding - * specified in the service config will override any matching transcoding - * configuration in the proto. - * - * Example: - * - * http: - * rules: - * # Selects a gRPC method and applies HttpRule to it. - * - selector: example.v1.Messaging.GetMessage - * get: /v1/messages/{message_id}/{sub.subfield} - * - * ## Special notes - * - * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the - * proto to JSON conversion must follow the [proto3 - * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). - * - * While the single segment variable follows the semantics of - * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String - * Expansion, the multi segment variable **does not** follow RFC 6570 Section - * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion - * does not expand special characters like `?` and `#`, which would lead - * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding - * for multi segment variables. - * - * The path variables **must not** refer to any repeated or mapped field, - * because client libraries are not capable of handling such variable expansion. - * - * The path variables **must not** capture the leading "/" character. The reason - * is that the most common use case "{var}" does not capture the leading "/" - * character. For consistency, all path variables must share the same behavior. - * - * Repeated message fields must not be mapped to URL query parameters, because - * no client library can support such complicated mapping. - * - * If an API needs to use a JSON array for request or response body, it can map - * the request or response body to a repeated field. However, some gRPC - * Transcoding implementations may not support this feature. - */ -export interface HttpRule__Output { - /** - * Selects a method to which this rule applies. - * - * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. - */ - 'selector': (string); - /** - * Maps to HTTP GET. Used for listing and getting information about - * resources. - */ - 'get'?: (string); - /** - * Maps to HTTP PUT. Used for replacing a resource. - */ - 'put'?: (string); - /** - * Maps to HTTP POST. Used for creating a resource or performing an action. - */ - 'post'?: (string); - /** - * Maps to HTTP DELETE. Used for deleting a resource. - */ - 'delete'?: (string); - /** - * Maps to HTTP PATCH. Used for updating a resource. - */ - 'patch'?: (string); - /** - * The name of the request field whose value is mapped to the HTTP request - * body, or `*` for mapping all request fields not captured by the path - * pattern to the HTTP body, or omitted for not having any HTTP request body. - * - * NOTE: the referred field must be present at the top-level of the request - * message type. - */ - 'body': (string); - /** - * The custom pattern is used for specifying an HTTP method that is not - * included in the `pattern` field, such as HEAD, or "*" to leave the - * HTTP method unspecified for this rule. The wild-card rule is useful - * for services that provide content to Web (HTML) clients. - */ - 'custom'?: (_google_api_CustomHttpPattern__Output); - /** - * Additional HTTP bindings for the selector. Nested bindings must - * not contain an `additional_bindings` field themselves (that is, - * the nesting may only be one level deep). - */ - 'additional_bindings': (_google_api_HttpRule__Output)[]; - /** - * Optional. The name of the response field whose value is mapped to the HTTP - * response body. When omitted, the entire response message will be used - * as the HTTP response body. - * - * NOTE: The referred field must be present at the top-level of the response - * message type. - */ - 'response_body': (string); - /** - * Determines the URL pattern is matched by this rules. This pattern can be - * used with any of the {get|put|post|delete|patch} methods. A custom method - * can be defined using the 'custom' field. - */ - 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; -} diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts index fe0d05f12..fcaa6724e 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Any.ts @@ -7,7 +7,7 @@ export type Any = AnyExtension | { value: Buffer | Uint8Array | string; } -export type Any__Output = AnyExtension | { - type_url: string; - value: Buffer; +export interface Any__Output { + 'type_url': (string); + 'value': (Buffer); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts index e4f2eb4b8..d70b303c2 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/DoubleValue.ts @@ -6,5 +6,5 @@ export interface DoubleValue { } export interface DoubleValue__Output { - 'value': (number | string); + 'value': (number); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index b76a60815..63f8a015f 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -2,6 +2,7 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; +import type { FieldSecurityAnnotation as _udpa_annotations_FieldSecurityAnnotation, FieldSecurityAnnotation__Output as _udpa_annotations_FieldSecurityAnnotation__Output } from '../../udpa/annotations/FieldSecurityAnnotation'; import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; // Original file: null @@ -29,6 +30,7 @@ export interface FieldOptions { 'weak'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.rules'?: (_validate_FieldRules); + '.udpa.annotations.security'?: (_udpa_annotations_FieldSecurityAnnotation); '.udpa.annotations.sensitive'?: (boolean); '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation); '.envoy.annotations.disallowed_by_default'?: (boolean); @@ -43,6 +45,7 @@ export interface FieldOptions__Output { 'weak': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.rules'?: (_validate_FieldRules__Output); + '.udpa.annotations.security'?: (_udpa_annotations_FieldSecurityAnnotation__Output); '.udpa.annotations.sensitive': (boolean); '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation__Output); '.envoy.annotations.disallowed_by_default': (boolean); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts index 144a9a585..54a655fbb 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FloatValue.ts @@ -6,5 +6,5 @@ export interface FloatValue { } export interface FloatValue__Output { - 'value': (number | string); + 'value': (number); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts index 7560daa28..219e4bfd2 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts @@ -1,6 +1,7 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { VersioningAnnotation as _udpa_annotations_VersioningAnnotation, VersioningAnnotation__Output as _udpa_annotations_VersioningAnnotation__Output } from '../../udpa/annotations/VersioningAnnotation'; import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface MessageOptions { @@ -10,6 +11,7 @@ export interface MessageOptions { 'mapEntry'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.disabled'?: (boolean); + '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation); '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation); } @@ -20,5 +22,6 @@ export interface MessageOptions__Output { 'mapEntry': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.disabled': (boolean); + '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation__Output); '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts b/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts index 433820f55..6e9fc275b 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/UninterpretedOption.ts @@ -27,7 +27,7 @@ export interface UninterpretedOption__Output { 'identifierValue': (string); 'positiveIntValue': (string); 'negativeIntValue': (string); - 'doubleValue': (number | string); + 'doubleValue': (number); 'stringValue': (Buffer); 'aggregateValue': (string); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts index 68b665dcb..0860535dc 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts @@ -16,7 +16,7 @@ export interface Value { export interface Value__Output { 'nullValue'?: (keyof typeof _google_protobuf_NullValue); - 'numberValue'?: (number | string); + 'numberValue'?: (number); 'stringValue'?: (string); 'boolValue'?: (boolean); 'structValue'?: (_google_protobuf_Struct__Output); diff --git a/packages/grpc-js-xds/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts index 7e822564d..9cb81bb0e 100644 --- a/packages/grpc-js-xds/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -10,12 +10,28 @@ export interface ProtoGrpcType { envoy: { annotations: { } - api: { - v2: { - RouteConfiguration: MessageTypeDefinition - ScopedRouteConfiguration: MessageTypeDefinition - Vhds: MessageTypeDefinition - core: { + config: { + accesslog: { + v3: { + AccessLog: MessageTypeDefinition + AccessLogFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition + ComparisonFilter: MessageTypeDefinition + DurationFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition + MetadataFilter: MessageTypeDefinition + NotHealthCheckFilter: MessageTypeDefinition + OrFilter: MessageTypeDefinition + ResponseFlagFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition + } + } + core: { + v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition @@ -28,7 +44,9 @@ export interface ProtoGrpcType { ConfigSource: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition Extension: MessageTypeDefinition + ExtensionConfigSource: MessageTypeDefinition GrpcProtocolOptions: MessageTypeDefinition GrpcService: MessageTypeDefinition HeaderMap: MessageTypeDefinition @@ -36,12 +54,15 @@ export interface ProtoGrpcType { HeaderValueOption: MessageTypeDefinition Http1ProtocolOptions: MessageTypeDefinition Http2ProtocolOptions: MessageTypeDefinition + Http3ProtocolOptions: MessageTypeDefinition HttpProtocolOptions: MessageTypeDefinition HttpUri: MessageTypeDefinition + KeepaliveSettings: MessageTypeDefinition Locality: MessageTypeDefinition Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + ProxyProtocolConfig: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -50,64 +71,64 @@ export interface ProtoGrpcType { RuntimeDouble: MessageTypeDefinition RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition + SubstitutionFormatString: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition TcpProtocolOptions: MessageTypeDefinition TrafficDirection: EnumTypeDefinition TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition UpstreamHttpProtocolOptions: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition } - route: { + } + route: { + v3: { CorsPolicy: MessageTypeDefinition Decorator: MessageTypeDefinition DirectResponseAction: MessageTypeDefinition FilterAction: MessageTypeDefinition + FilterConfig: MessageTypeDefinition HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition + InternalRedirectPolicy: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition RetryPolicy: MessageTypeDefinition Route: MessageTypeDefinition RouteAction: MessageTypeDefinition + RouteConfiguration: MessageTypeDefinition RouteMatch: MessageTypeDefinition + ScopedRouteConfiguration: MessageTypeDefinition Tracing: MessageTypeDefinition + Vhds: MessageTypeDefinition VirtualCluster: MessageTypeDefinition VirtualHost: MessageTypeDefinition WeightedCluster: MessageTypeDefinition } } - } - config: { - filter: { - accesslog: { - v2: { - AccessLog: MessageTypeDefinition - AccessLogFilter: MessageTypeDefinition - AndFilter: MessageTypeDefinition - ComparisonFilter: MessageTypeDefinition - DurationFilter: MessageTypeDefinition - ExtensionFilter: MessageTypeDefinition - GrpcStatusFilter: MessageTypeDefinition - HeaderFilter: MessageTypeDefinition - NotHealthCheckFilter: MessageTypeDefinition - OrFilter: MessageTypeDefinition - ResponseFlagFilter: MessageTypeDefinition - RuntimeFilter: MessageTypeDefinition - StatusCodeFilter: MessageTypeDefinition - TraceableFilter: MessageTypeDefinition - } + trace: { + v3: { + Tracing: MessageTypeDefinition } + } + } + extensions: { + filters: { network: { http_connection_manager: { - v2: { + v3: { HttpConnectionManager: MessageTypeDefinition HttpFilter: MessageTypeDefinition + LocalReplyConfig: MessageTypeDefinition Rds: MessageTypeDefinition RequestIDExtension: MessageTypeDefinition + ResponseMapper: MessageTypeDefinition ScopedRds: MessageTypeDefinition ScopedRouteConfigurationsList: MessageTypeDefinition ScopedRoutes: MessageTypeDefinition @@ -115,36 +136,39 @@ export interface ProtoGrpcType { } } } - trace: { - v2: { - Tracing: MessageTypeDefinition - } - } } type: { - DoubleRange: MessageTypeDefinition - FractionalPercent: MessageTypeDefinition - Int32Range: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition matcher: { - ListStringMatcher: MessageTypeDefinition - RegexMatchAndSubstitute: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition - StringMatcher: MessageTypeDefinition + v3: { + DoubleMatcher: MessageTypeDefinition + ListMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + MetadataMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + ValueMatcher: MessageTypeDefinition + } } metadata: { - v2: { + v3: { MetadataKey: MessageTypeDefinition MetadataKind: MessageTypeDefinition } } tracing: { - v2: { + v3: { CustomTag: MessageTypeDefinition } } + v3: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } } } google: { @@ -191,10 +215,12 @@ export interface ProtoGrpcType { udpa: { annotations: { FieldMigrateAnnotation: MessageTypeDefinition + FieldSecurityAnnotation: MessageTypeDefinition FileMigrateAnnotation: MessageTypeDefinition MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { @@ -223,5 +249,12 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + core: { + v3: { + Authority: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts index ab67cd096..69454efdc 100644 --- a/packages/grpc-js-xds/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -10,23 +10,28 @@ export interface ProtoGrpcType { envoy: { annotations: { } - api: { - v2: { - Listener: MessageTypeDefinition - auth: { - CertificateValidationContext: MessageTypeDefinition - CommonTlsContext: MessageTypeDefinition - DownstreamTlsContext: MessageTypeDefinition - GenericSecret: MessageTypeDefinition - PrivateKeyProvider: MessageTypeDefinition - SdsSecretConfig: MessageTypeDefinition - Secret: MessageTypeDefinition - TlsCertificate: MessageTypeDefinition - TlsParameters: MessageTypeDefinition - TlsSessionTicketKeys: MessageTypeDefinition - UpstreamTlsContext: MessageTypeDefinition + config: { + accesslog: { + v3: { + AccessLog: MessageTypeDefinition + AccessLogFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition + ComparisonFilter: MessageTypeDefinition + DurationFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition + MetadataFilter: MessageTypeDefinition + NotHealthCheckFilter: MessageTypeDefinition + OrFilter: MessageTypeDefinition + ResponseFlagFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition } - core: { + } + core: { + v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition @@ -39,7 +44,9 @@ export interface ProtoGrpcType { ConfigSource: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition Extension: MessageTypeDefinition + ExtensionConfigSource: MessageTypeDefinition GrpcService: MessageTypeDefinition HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition @@ -49,6 +56,7 @@ export interface ProtoGrpcType { Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + ProxyProtocolConfig: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -57,6 +65,7 @@ export interface ProtoGrpcType { RuntimeDouble: MessageTypeDefinition RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition @@ -64,23 +73,34 @@ export interface ProtoGrpcType { TcpKeepalive: MessageTypeDefinition TrafficDirection: EnumTypeDefinition TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition } - listener: { + } + listener: { + v3: { ActiveRawUdpListenerConfig: MessageTypeDefinition + ApiListener: MessageTypeDefinition Filter: MessageTypeDefinition FilterChain: MessageTypeDefinition FilterChainMatch: MessageTypeDefinition + Listener: MessageTypeDefinition + ListenerCollection: MessageTypeDefinition ListenerFilter: MessageTypeDefinition ListenerFilterChainMatchPredicate: MessageTypeDefinition UdpListenerConfig: MessageTypeDefinition } - route: { + } + route: { + v3: { CorsPolicy: MessageTypeDefinition Decorator: MessageTypeDefinition DirectResponseAction: MessageTypeDefinition FilterAction: MessageTypeDefinition + FilterConfig: MessageTypeDefinition HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition + InternalRedirectPolicy: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition @@ -95,65 +115,41 @@ export interface ProtoGrpcType { } } } - config: { - filter: { - accesslog: { - v2: { - AccessLog: MessageTypeDefinition - AccessLogFilter: MessageTypeDefinition - AndFilter: MessageTypeDefinition - ComparisonFilter: MessageTypeDefinition - DurationFilter: MessageTypeDefinition - ExtensionFilter: MessageTypeDefinition - GrpcStatusFilter: MessageTypeDefinition - HeaderFilter: MessageTypeDefinition - NotHealthCheckFilter: MessageTypeDefinition - OrFilter: MessageTypeDefinition - ResponseFlagFilter: MessageTypeDefinition - RuntimeFilter: MessageTypeDefinition - StatusCodeFilter: MessageTypeDefinition - TraceableFilter: MessageTypeDefinition - } - } - } - listener: { - v2: { - ApiListener: MessageTypeDefinition - } - } - } type: { - DoubleRange: MessageTypeDefinition - FractionalPercent: MessageTypeDefinition - Int32Range: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition matcher: { - ListStringMatcher: MessageTypeDefinition - RegexMatchAndSubstitute: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition - StringMatcher: MessageTypeDefinition + v3: { + DoubleMatcher: MessageTypeDefinition + ListMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + MetadataMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + ValueMatcher: MessageTypeDefinition + } } metadata: { - v2: { + v3: { MetadataKey: MessageTypeDefinition MetadataKind: MessageTypeDefinition } } tracing: { - v2: { + v3: { CustomTag: MessageTypeDefinition } } + v3: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } } } google: { - api: { - CustomHttpPattern: MessageTypeDefinition - Http: MessageTypeDefinition - HttpRule: MessageTypeDefinition - } protobuf: { Any: MessageTypeDefinition BoolValue: MessageTypeDefinition @@ -197,10 +193,12 @@ export interface ProtoGrpcType { udpa: { annotations: { FieldMigrateAnnotation: MessageTypeDefinition + FieldSecurityAnnotation: MessageTypeDefinition FileMigrateAnnotation: MessageTypeDefinition MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { @@ -229,5 +227,15 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + core: { + v3: { + Authority: MessageTypeDefinition + CollectionEntry: MessageTypeDefinition + ContextParams: MessageTypeDefinition + ResourceLocator: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts index f3f180807..9a2864fcf 100644 --- a/packages/grpc-js-xds/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -2,6 +2,7 @@ import type * as grpc from '@grpc/grpc-js'; import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import type { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; +import type { LoadReportingServiceClient as _envoy_service_load_stats_v3_LoadReportingServiceClient } from './envoy/service/load_stats/v3/LoadReportingService'; type SubtypeConstructor any, Subtype> = { new(...args: ConstructorParameters): Subtype; @@ -51,6 +52,53 @@ export interface ProtoGrpcType { } } } + config: { + core: { + v3: { + Address: MessageTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition + Extension: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition + } + } + endpoint: { + v3: { + ClusterStats: MessageTypeDefinition + EndpointLoadMetricStats: MessageTypeDefinition + UpstreamEndpointStats: MessageTypeDefinition + UpstreamLocalityStats: MessageTypeDefinition + } + } + } service: { load_stats: { v2: { @@ -58,12 +106,22 @@ export interface ProtoGrpcType { LoadStatsRequest: MessageTypeDefinition LoadStatsResponse: MessageTypeDefinition } + v3: { + LoadReportingService: SubtypeConstructor & { service: ServiceDefinition } + LoadStatsRequest: MessageTypeDefinition + LoadStatsResponse: MessageTypeDefinition + } } } type: { FractionalPercent: MessageTypeDefinition Percent: MessageTypeDefinition SemanticVersion: MessageTypeDefinition + v3: { + FractionalPercent: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } } } google: { @@ -113,6 +171,7 @@ export interface ProtoGrpcType { MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { diff --git a/packages/grpc-js-xds/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts index 05332fe37..a51060779 100644 --- a/packages/grpc-js-xds/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -10,11 +10,9 @@ export interface ProtoGrpcType { envoy: { annotations: { } - api: { - v2: { - RouteConfiguration: MessageTypeDefinition - Vhds: MessageTypeDefinition - core: { + config: { + core: { + v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition @@ -27,7 +25,9 @@ export interface ProtoGrpcType { ConfigSource: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition Extension: MessageTypeDefinition + ExtensionConfigSource: MessageTypeDefinition GrpcService: MessageTypeDefinition HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition @@ -37,6 +37,7 @@ export interface ProtoGrpcType { Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + ProxyProtocolConfig: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -45,6 +46,7 @@ export interface ProtoGrpcType { RuntimeDouble: MessageTypeDefinition RuntimeFeatureFlag: MessageTypeDefinition RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition @@ -52,22 +54,30 @@ export interface ProtoGrpcType { TcpKeepalive: MessageTypeDefinition TrafficDirection: EnumTypeDefinition TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition } - route: { + } + route: { + v3: { CorsPolicy: MessageTypeDefinition Decorator: MessageTypeDefinition DirectResponseAction: MessageTypeDefinition FilterAction: MessageTypeDefinition + FilterConfig: MessageTypeDefinition HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition + InternalRedirectPolicy: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition RetryPolicy: MessageTypeDefinition Route: MessageTypeDefinition RouteAction: MessageTypeDefinition + RouteConfiguration: MessageTypeDefinition RouteMatch: MessageTypeDefinition Tracing: MessageTypeDefinition + Vhds: MessageTypeDefinition VirtualCluster: MessageTypeDefinition VirtualHost: MessageTypeDefinition WeightedCluster: MessageTypeDefinition @@ -75,29 +85,33 @@ export interface ProtoGrpcType { } } type: { - DoubleRange: MessageTypeDefinition - FractionalPercent: MessageTypeDefinition - Int32Range: MessageTypeDefinition - Int64Range: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition matcher: { - ListStringMatcher: MessageTypeDefinition - RegexMatchAndSubstitute: MessageTypeDefinition - RegexMatcher: MessageTypeDefinition - StringMatcher: MessageTypeDefinition + v3: { + ListStringMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } } metadata: { - v2: { + v3: { MetadataKey: MessageTypeDefinition MetadataKind: MessageTypeDefinition } } tracing: { - v2: { + v3: { CustomTag: MessageTypeDefinition } } + v3: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } } } google: { @@ -148,6 +162,7 @@ export interface ProtoGrpcType { MigrateAnnotation: MessageTypeDefinition PackageVersionStatus: EnumTypeDefinition StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition } } validate: { @@ -176,5 +191,12 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + core: { + v3: { + Authority: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts new file mode 100644 index 000000000..13d48b5ce --- /dev/null +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts @@ -0,0 +1,32 @@ +// Original file: deps/udpa/udpa/annotations/security.proto + + +/** + * These annotations indicate metadata for the purpose of understanding the + * security significance of fields. + */ +export interface FieldSecurityAnnotation { + /** + * Field should be set in the presence of untrusted downstreams. + */ + 'configure_for_untrusted_downstream'?: (boolean); + /** + * Field should be set in the presence of untrusted upstreams. + */ + 'configure_for_untrusted_upstream'?: (boolean); +} + +/** + * These annotations indicate metadata for the purpose of understanding the + * security significance of fields. + */ +export interface FieldSecurityAnnotation__Output { + /** + * Field should be set in the presence of untrusted downstreams. + */ + 'configure_for_untrusted_downstream': (boolean); + /** + * Field should be set in the presence of untrusted upstreams. + */ + 'configure_for_untrusted_upstream': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts new file mode 100644 index 000000000..1a3d09dc8 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts @@ -0,0 +1,20 @@ +// Original file: deps/udpa/udpa/annotations/versioning.proto + + +export interface VersioningAnnotation { + /** + * Track the previous message type. E.g. this message might be + * udpa.foo.v3alpha.Foo and it was previously udpa.bar.v2.Bar. This + * information is consumed by UDPA via proto descriptors. + */ + 'previous_message_type'?: (string); +} + +export interface VersioningAnnotation__Output { + /** + * Track the previous message type. E.g. this message might be + * udpa.foo.v3alpha.Foo and it was previously udpa.bar.v2.Bar. This + * information is consumed by UDPA via proto descriptors. + */ + 'previous_message_type': (string); +} diff --git a/packages/grpc-js-xds/src/generated/validate/DoubleRules.ts b/packages/grpc-js-xds/src/generated/validate/DoubleRules.ts index fead5072a..e756c86b9 100644 --- a/packages/grpc-js-xds/src/generated/validate/DoubleRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/DoubleRules.ts @@ -50,37 +50,37 @@ export interface DoubleRules__Output { /** * Const specifies that this field must be exactly the specified value */ - 'const': (number | string); + 'const': (number); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt': (number | string); + 'lt': (number); /** * Lte specifies that this field must be less than or equal to the * specified value, inclusive */ - 'lte': (number | string); + 'lte': (number); /** * Gt specifies that this field must be greater than the specified value, * exclusive. If the value of Gt is larger than a specified Lt or Lte, the * range is reversed. */ - 'gt': (number | string); + 'gt': (number); /** * Gte specifies that this field must be greater than or equal to the * specified value, inclusive. If the value of Gte is larger than a * specified Lt or Lte, the range is reversed. */ - 'gte': (number | string); + 'gte': (number); /** * In specifies that this field must be equal to one of the specified * values */ - 'in': (number | string)[]; + 'in': (number)[]; /** * NotIn specifies that this field cannot be equal to one of the specified * values */ - 'not_in': (number | string)[]; + 'not_in': (number)[]; } diff --git a/packages/grpc-js-xds/src/generated/validate/FloatRules.ts b/packages/grpc-js-xds/src/generated/validate/FloatRules.ts index 35aafa809..8d5244c2b 100644 --- a/packages/grpc-js-xds/src/generated/validate/FloatRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/FloatRules.ts @@ -50,37 +50,37 @@ export interface FloatRules__Output { /** * Const specifies that this field must be exactly the specified value */ - 'const': (number | string); + 'const': (number); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt': (number | string); + 'lt': (number); /** * Lte specifies that this field must be less than or equal to the * specified value, inclusive */ - 'lte': (number | string); + 'lte': (number); /** * Gt specifies that this field must be greater than the specified value, * exclusive. If the value of Gt is larger than a specified Lt or Lte, the * range is reversed. */ - 'gt': (number | string); + 'gt': (number); /** * Gte specifies that this field must be greater than or equal to the * specified value, inclusive. If the value of Gte is larger than a * specified Lt or Lte, the range is reversed. */ - 'gte': (number | string); + 'gte': (number); /** * In specifies that this field must be equal to one of the specified * values */ - 'in': (number | string)[]; + 'in': (number)[]; /** * NotIn specifies that this field cannot be equal to one of the specified * values */ - 'not_in': (number | string)[]; + 'not_in': (number)[]; } diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts new file mode 100644 index 000000000..8e9211838 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts @@ -0,0 +1,16 @@ +// Original file: deps/udpa/xds/core/v3/authority.proto + + +/** + * xDS authority information. + */ +export interface Authority { + 'name'?: (string); +} + +/** + * xDS authority information. + */ +export interface Authority__Output { + 'name': (string); +} diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts new file mode 100644 index 000000000..4a9a45527 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts @@ -0,0 +1,90 @@ +// Original file: deps/udpa/xds/core/v3/collection_entry.proto + +import type { ResourceLocator as _xds_core_v3_ResourceLocator, ResourceLocator__Output as _xds_core_v3_ResourceLocator__Output } from '../../../xds/core/v3/ResourceLocator'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +/** + * Inlined resource entry. + */ +export interface _xds_core_v3_CollectionEntry_InlineEntry { + /** + * Optional name to describe the inlined resource. Resource names must + * [a-zA-Z0-9_-\./]+ (TODO(htuch): turn this into a PGV constraint once + * finalized, probably should be a RFC3986 pchar). This name allows + * reference via the #entry directive in ResourceLocator. + */ + 'name'?: (string); + /** + * The resource's logical version. It is illegal to have the same named xDS + * resource name at a given version with different resource payloads. + */ + 'version'?: (string); + /** + * The resource payload, including type URL. + */ + 'resource'?: (_google_protobuf_Any); +} + +/** + * Inlined resource entry. + */ +export interface _xds_core_v3_CollectionEntry_InlineEntry__Output { + /** + * Optional name to describe the inlined resource. Resource names must + * [a-zA-Z0-9_-\./]+ (TODO(htuch): turn this into a PGV constraint once + * finalized, probably should be a RFC3986 pchar). This name allows + * reference via the #entry directive in ResourceLocator. + */ + 'name': (string); + /** + * The resource's logical version. It is illegal to have the same named xDS + * resource name at a given version with different resource payloads. + */ + 'version': (string); + /** + * The resource payload, including type URL. + */ + 'resource'?: (_google_protobuf_Any__Output); +} + +/** + * xDS collection resource wrapper. This encapsulates a xDS resource when + * appearing inside a list collection resource. List collection resources are + * regular Resource messages of type: + * + * message Collection { + * repeated CollectionEntry resources = 1; + * } + */ +export interface CollectionEntry { + /** + * A resource locator describing how the member resource is to be located. + */ + 'locator'?: (_xds_core_v3_ResourceLocator); + /** + * The resource is inlined in the list collection. + */ + 'inline_entry'?: (_xds_core_v3_CollectionEntry_InlineEntry); + 'resource_specifier'?: "locator"|"inline_entry"; +} + +/** + * xDS collection resource wrapper. This encapsulates a xDS resource when + * appearing inside a list collection resource. List collection resources are + * regular Resource messages of type: + * + * message Collection { + * repeated CollectionEntry resources = 1; + * } + */ +export interface CollectionEntry__Output { + /** + * A resource locator describing how the member resource is to be located. + */ + 'locator'?: (_xds_core_v3_ResourceLocator__Output); + /** + * The resource is inlined in the list collection. + */ + 'inline_entry'?: (_xds_core_v3_CollectionEntry_InlineEntry__Output); + 'resource_specifier': "locator"|"inline_entry"; +} diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts new file mode 100644 index 000000000..f9c57249c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts @@ -0,0 +1,26 @@ +// Original file: deps/udpa/xds/core/v3/context_params.proto + + +/** + * Additional parameters that can be used to select resource variants. These include any + * global context parameters, per-resource type client feature capabilities and per-resource + * type functional attributes. All per-resource type attributes will be `xds.resource.` + * prefixed and some of these are documented below: + * `xds.resource.listening_address`: The value is "IP:port" (e.g. "10.1.1.3:8080") which is + * the listening address of a Listener. Used in a Listener resource query. + */ +export interface ContextParams { + 'params'?: ({[key: string]: string}); +} + +/** + * Additional parameters that can be used to select resource variants. These include any + * global context parameters, per-resource type client feature capabilities and per-resource + * type functional attributes. All per-resource type attributes will be `xds.resource.` + * prefixed and some of these are documented below: + * `xds.resource.listening_address`: The value is "IP:port" (e.g. "10.1.1.3:8080") which is + * the listening address of a Listener. Used in a Listener resource query. + */ +export interface ContextParams__Output { + 'params': ({[key: string]: string}); +} diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts new file mode 100644 index 000000000..f28a31d20 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts @@ -0,0 +1,220 @@ +// Original file: deps/udpa/xds/core/v3/resource_locator.proto + +import type { ContextParams as _xds_core_v3_ContextParams, ContextParams__Output as _xds_core_v3_ContextParams__Output } from '../../../xds/core/v3/ContextParams'; +import type { ResourceLocator as _xds_core_v3_ResourceLocator, ResourceLocator__Output as _xds_core_v3_ResourceLocator__Output } from '../../../xds/core/v3/ResourceLocator'; + +/** + * Directives provide information to data-plane load balancers on how xDS + * resource names are to be interpreted and potentially further resolved. For + * example, they may provide alternative resource locators for when primary + * resolution fails. Directives are not part of resource names and do not + * appear in a xDS transport discovery request. + * + * When encoding to URIs, directives take the form: + * + * = + * + * For example, we can have alt=xdstp://foo/bar or entry=some%20thing. Each + * directive value type may have its own string encoding, in the case of + * ResourceLocator there is a recursive URI encoding. + * + * Percent encoding applies to the URI encoding of the directive value. + * Multiple directives are comma-separated, so the reserved characters that + * require percent encoding in a directive value are [',', '#', '[', ']', + * '%']. These are the RFC3986 fragment reserved characters with the addition + * of the xDS scheme specific ','. See + * https://tools.ietf.org/html/rfc3986#page-49 for further details on URI ABNF + * and reserved characters. + */ +export interface _xds_core_v3_ResourceLocator_Directive { + /** + * An alternative resource locator for fallback if the resource is + * unavailable. For example, take the resource locator: + * + * xdstp://foo/some-type/some-route-table#alt=xdstp://bar/some-type/another-route-table + * + * If the data-plane load balancer is unable to reach `foo` to fetch the + * resource, it will fallback to `bar`. Alternative resources do not need + * to have equivalent content, but they should be functional substitutes. + */ + 'alt'?: (_xds_core_v3_ResourceLocator); + /** + * List collections support inlining of resources via the entry field in + * Resource. These inlined Resource objects may have an optional name + * field specified. When specified, the entry directive allows + * ResourceLocator to directly reference these inlined resources, e.g. + * xdstp://.../foo#entry=bar. + */ + 'entry'?: (string); + 'directive'?: "alt"|"entry"; +} + +/** + * Directives provide information to data-plane load balancers on how xDS + * resource names are to be interpreted and potentially further resolved. For + * example, they may provide alternative resource locators for when primary + * resolution fails. Directives are not part of resource names and do not + * appear in a xDS transport discovery request. + * + * When encoding to URIs, directives take the form: + * + * = + * + * For example, we can have alt=xdstp://foo/bar or entry=some%20thing. Each + * directive value type may have its own string encoding, in the case of + * ResourceLocator there is a recursive URI encoding. + * + * Percent encoding applies to the URI encoding of the directive value. + * Multiple directives are comma-separated, so the reserved characters that + * require percent encoding in a directive value are [',', '#', '[', ']', + * '%']. These are the RFC3986 fragment reserved characters with the addition + * of the xDS scheme specific ','. See + * https://tools.ietf.org/html/rfc3986#page-49 for further details on URI ABNF + * and reserved characters. + */ +export interface _xds_core_v3_ResourceLocator_Directive__Output { + /** + * An alternative resource locator for fallback if the resource is + * unavailable. For example, take the resource locator: + * + * xdstp://foo/some-type/some-route-table#alt=xdstp://bar/some-type/another-route-table + * + * If the data-plane load balancer is unable to reach `foo` to fetch the + * resource, it will fallback to `bar`. Alternative resources do not need + * to have equivalent content, but they should be functional substitutes. + */ + 'alt'?: (_xds_core_v3_ResourceLocator__Output); + /** + * List collections support inlining of resources via the entry field in + * Resource. These inlined Resource objects may have an optional name + * field specified. When specified, the entry directive allows + * ResourceLocator to directly reference these inlined resources, e.g. + * xdstp://.../foo#entry=bar. + */ + 'entry'?: (string); + 'directive': "alt"|"entry"; +} + +// Original file: deps/udpa/xds/core/v3/resource_locator.proto + +export enum _xds_core_v3_ResourceLocator_Scheme { + XDSTP = 0, + HTTP = 1, + FILE = 2, +} + +/** + * xDS resource locators identify a xDS resource name and instruct the + * data-plane load balancer on how the resource may be located. + * + * Resource locators have a canonical xdstp:// URI representation: + * + * xdstp://{authority}/{type_url}/{id}?{context_params}{#directive,*} + * + * where context_params take the form of URI query parameters. + * + * Resource locators have a similar canonical http:// URI representation: + * + * http://{authority}/{type_url}/{id}?{context_params}{#directive,*} + * + * Resource locators also have a simplified file:// URI representation: + * + * file:///{id}{#directive,*} + */ +export interface ResourceLocator { + /** + * URI scheme. + */ + 'scheme'?: (_xds_core_v3_ResourceLocator_Scheme | keyof typeof _xds_core_v3_ResourceLocator_Scheme); + /** + * Opaque identifier for the resource. Any '/' will not be escaped during URI + * encoding and will form part of the URI path. This may end + * with ‘*’ for glob collection references. + */ + 'id'?: (string); + /** + * Logical authority for resource (not necessarily transport network address). + * Authorities are opaque in the xDS API, data-plane load balancers will map + * them to concrete network transports such as an xDS management server, e.g. + * via envoy.config.core.v3.ConfigSource. + */ + 'authority'?: (string); + /** + * Fully qualified resource type (as in type URL without types.googleapis.com/ + * prefix). + */ + 'resource_type'?: (string); + /** + * Additional parameters that can be used to select resource variants. + * Matches must be exact, i.e. all context parameters must match exactly and + * there must be no additional context parameters set on the matched + * resource. + */ + 'exact_context'?: (_xds_core_v3_ContextParams); + /** + * A list of directives that appear in the xDS resource locator #fragment. + * + * When encoding to URI form, directives are percent encoded with comma + * separation. + */ + 'directives'?: (_xds_core_v3_ResourceLocator_Directive)[]; + 'context_param_specifier'?: "exact_context"; +} + +/** + * xDS resource locators identify a xDS resource name and instruct the + * data-plane load balancer on how the resource may be located. + * + * Resource locators have a canonical xdstp:// URI representation: + * + * xdstp://{authority}/{type_url}/{id}?{context_params}{#directive,*} + * + * where context_params take the form of URI query parameters. + * + * Resource locators have a similar canonical http:// URI representation: + * + * http://{authority}/{type_url}/{id}?{context_params}{#directive,*} + * + * Resource locators also have a simplified file:// URI representation: + * + * file:///{id}{#directive,*} + */ +export interface ResourceLocator__Output { + /** + * URI scheme. + */ + 'scheme': (keyof typeof _xds_core_v3_ResourceLocator_Scheme); + /** + * Opaque identifier for the resource. Any '/' will not be escaped during URI + * encoding and will form part of the URI path. This may end + * with ‘*’ for glob collection references. + */ + 'id': (string); + /** + * Logical authority for resource (not necessarily transport network address). + * Authorities are opaque in the xDS API, data-plane load balancers will map + * them to concrete network transports such as an xDS management server, e.g. + * via envoy.config.core.v3.ConfigSource. + */ + 'authority': (string); + /** + * Fully qualified resource type (as in type URL without types.googleapis.com/ + * prefix). + */ + 'resource_type': (string); + /** + * Additional parameters that can be used to select resource variants. + * Matches must be exact, i.e. all context parameters must match exactly and + * there must be no additional context parameters set on the matched + * resource. + */ + 'exact_context'?: (_xds_core_v3_ContextParams__Output); + /** + * A list of directives that appear in the xDS resource locator #fragment. + * + * When encoding to URI form, directives are percent encoded with comma + * separation. + */ + 'directives': (_xds_core_v3_ResourceLocator_Directive__Output)[]; + 'context_param_specifier': "exact_context"; +} From bf1b078816c71bf44318eb60bd07ca18f165b488 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 14 Apr 2021 14:58:36 -0700 Subject: [PATCH 1417/1899] grpc-js: Update versions and xDS feature list --- packages/grpc-js-xds/README.md | 3 ++- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js/package.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index 2ada0bade..bcea70456 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -21,4 +21,5 @@ const client = new MyServiceClient('xds:///example.com:123'); ## Supported Features - - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) \ No newline at end of file + - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) + - [xDS traffic splitting and routing](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 3f90c7e97..f4f8d604d 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.2.4", + "version": "1.3.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.2.10" + "@grpc/grpc-js": "~1.3.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6a027d391..04fa4585a 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.2.12", + "version": "1.3.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From c9aad43358983a560613e3f99412000df99aa526 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 16 Apr 2021 13:34:59 -0700 Subject: [PATCH 1418/1899] grpc-js: Add support for ipv4 and ipv6 schemes --- packages/grpc-js/src/resolver-ip.ts | 107 +++++++++++++++ packages/grpc-js/src/resolver.ts | 2 + packages/grpc-js/test/test-resolver.ts | 180 +++++++++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 packages/grpc-js/src/resolver-ip.ts diff --git a/packages/grpc-js/src/resolver-ip.ts b/packages/grpc-js/src/resolver-ip.ts new file mode 100644 index 000000000..5c9e29c46 --- /dev/null +++ b/packages/grpc-js/src/resolver-ip.ts @@ -0,0 +1,107 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { isIPv4, isIPv6 } from "net"; +import { StatusObject } from "./call-stream"; +import { ChannelOptions } from "./channel-options"; +import { LogVerbosity, Status } from "./constants"; +import { Metadata } from "./metadata"; +import { registerResolver, Resolver, ResolverListener } from "./resolver"; +import { SubchannelAddress } from "./subchannel"; +import { GrpcUri, splitHostPort, uriToString } from "./uri-parser"; +import * as logging from './logging'; + +const TRACER_NAME = 'ip_resolver'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} + +const IPV4_SCHEME = 'ipv4'; +const IPV6_SCHEME = 'ipv6'; + +/** + * The default TCP port to connect to if not explicitly specified in the target. + */ +const DEFAULT_PORT = 443; + +class IpResolver implements Resolver { + private addresses: SubchannelAddress[] = []; + private error: StatusObject | null = null; + constructor( + private target: GrpcUri, + private listener: ResolverListener, + channelOptions: ChannelOptions + ) { + trace('Resolver constructed for target ' + uriToString(target)); + const addresses: SubchannelAddress[] = []; + if (!(target.scheme === IPV4_SCHEME || target.scheme === IPV6_SCHEME)) { + this.error = { + code: Status.UNAVAILABLE, + details: `Unrecognized scheme ${target.scheme} in IP resolver`, + metadata: new Metadata() + }; + return; + } + const pathList = target.path.split(','); + for (const path of pathList) { + const hostPort = splitHostPort(path); + if (hostPort === null) { + this.error = { + code: Status.UNAVAILABLE, + details: `Failed to parse ${target.scheme} address ${path}`, + metadata: new Metadata() + }; + return; + } + if ((target.scheme === IPV4_SCHEME && !isIPv4(hostPort.host)) || (target.scheme === IPV6_SCHEME && !isIPv6(hostPort.host))) { + this.error = { + code: Status.UNAVAILABLE, + details: `Failed to parse ${target.scheme} address ${path}`, + metadata: new Metadata() + }; + return; + } + addresses.push({ + host: hostPort.host, + port: hostPort.port ?? DEFAULT_PORT + }); + } + this.addresses = addresses; + trace('Parsed ' + target.scheme + ' address list ' + this.addresses); + } + updateResolution(): void { + process.nextTick(() => { + if (this.error) { + this.listener.onError(this.error) + } else { + this.listener.onSuccessfulResolution(this.addresses, null, null, null, {}); + } + }); + } + destroy(): void { + // This resolver owns no resources, so we do nothing here. + } + + static getDefaultAuthority(target: GrpcUri): string { + return target.path.split(',')[0]; + } +} + +export function setup() { + registerResolver(IPV4_SCHEME, IpResolver); + registerResolver(IPV6_SCHEME, IpResolver); +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 147ace30d..497f3dfa0 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -18,6 +18,7 @@ import { MethodConfig, ServiceConfig } from './service-config'; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; +import * as resolver_ip from './resolver-ip'; import { StatusObject } from './call-stream'; import { SubchannelAddress } from './subchannel'; import { GrpcUri, uriToString } from './uri-parser'; @@ -179,4 +180,5 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { export function registerAll() { resolver_dns.setup(); resolver_uds.setup(); + resolver_ip.setup(); } diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index c4f42f6eb..756d234ca 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -388,6 +388,186 @@ describe('Name Resolver', () => { resolver.updateResolution(); }); }); + describe('IP Addresses', () => { + it('should handle one IPv4 address with no port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle one IPv4 address with a port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1:50051')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50051 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle multiple IPv4 addresses with different ports', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv4:127.0.0.1:50051,127.0.0.1:50052')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50051 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 50052 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle one IPv6 address with no port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:::1')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle one IPv6 address with a port', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:[::1]:50051')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it('should handle multiple IPv6 addresses with different ports', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('ipv6:[::1]:50051,[::1]:50052')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + // Only handle the first resolution result + listener.onSuccessfulResolution = () => {}; + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50051 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 50052 + ) + ); + done(); + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + }); describe('getDefaultAuthority', () => { class OtherResolver implements resolverManager.Resolver { updateResolution() { From 076aeccfdc88fbf24e8c8f65741803e231a41a00 Mon Sep 17 00:00:00 2001 From: Sahebjot singh Date: Wed, 21 Apr 2021 09:01:42 +0530 Subject: [PATCH 1419/1899] grpc-js: stricter function check than instanceof instanceof does not work in vm context --- packages/grpc-js/src/client.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 5f78ffe59..2f995e82b 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -198,9 +198,9 @@ export class Client { options: CallOptions; callback: UnaryCallback; } { - if (arg1 instanceof Function) { + if (Object.prototype.toString.call(arg1) === '[object Function]') { return { metadata: new Metadata(), options: {}, callback: arg1 }; - } else if (arg2 instanceof Function) { + } else if (Object.prototype.toString.call(arg2) === '[object Function]') { if (arg1 instanceof Metadata) { return { metadata: arg1, options: {}, callback: arg2 }; } else { @@ -211,7 +211,7 @@ export class Client { !( arg1 instanceof Metadata && arg2 instanceof Object && - arg3 instanceof Function + Object.prototype.toString.call(arg3) === '[object Function]' ) ) { throw new Error('Incorrect arguments passed'); From 7a8cd5a4bde13cde54b41847607fa6c83a4c906d Mon Sep 17 00:00:00 2001 From: zereraz Date: Sat, 24 Apr 2021 14:00:05 +0530 Subject: [PATCH 1420/1899] grpc-js: Use helper isFunction --- packages/grpc-js/src/client.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 2f995e82b..c1db50788 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -55,6 +55,10 @@ const INTERCEPTOR_SYMBOL = Symbol(); const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); +function isFunction(arg: Metadata | CallOptions | UnaryCallback): boolean { + return Object.prototype.toString.call(arg) === '[object Function]' +} + export interface UnaryCallback { (err: ServiceError | null, value?: ResponseType): void; } @@ -198,9 +202,9 @@ export class Client { options: CallOptions; callback: UnaryCallback; } { - if (Object.prototype.toString.call(arg1) === '[object Function]') { + if (isFunction(arg1)) { return { metadata: new Metadata(), options: {}, callback: arg1 }; - } else if (Object.prototype.toString.call(arg2) === '[object Function]') { + } else if (isFunction(arg2)) { if (arg1 instanceof Metadata) { return { metadata: arg1, options: {}, callback: arg2 }; } else { @@ -211,7 +215,7 @@ export class Client { !( arg1 instanceof Metadata && arg2 instanceof Object && - Object.prototype.toString.call(arg3) === '[object Function]' + isFunction(arg3) ) ) { throw new Error('Incorrect arguments passed'); @@ -671,3 +675,4 @@ export class Client { return stream; } } + From 923b44bb1c22bf4c4a7605eebb3f70a8df65ef98 Mon Sep 17 00:00:00 2001 From: zereraz Date: Wed, 28 Apr 2021 00:18:23 +0530 Subject: [PATCH 1421/1899] grpc-js: Add type predicate to fix errors for isFunction --- packages/grpc-js/src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index c1db50788..850e839cc 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -55,7 +55,7 @@ const INTERCEPTOR_SYMBOL = Symbol(); const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); -function isFunction(arg: Metadata | CallOptions | UnaryCallback): boolean { +function isFunction(arg: Metadata | CallOptions | UnaryCallback | undefined): arg is UnaryCallback{ return Object.prototype.toString.call(arg) === '[object Function]' } From 9253b7f1043770f6a2fa465d996f4a41668d4e0a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 30 Apr 2021 12:53:26 -0700 Subject: [PATCH 1422/1899] grpc-js: Don't transition out of idle when discarding subchannels --- packages/grpc-js/src/subchannel.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 772bdb228..7a68a1a2d 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -598,7 +598,6 @@ export class Subchannel { this.transitionToState( [ ConnectivityState.CONNECTING, - ConnectivityState.IDLE, ConnectivityState.READY, ], ConnectivityState.TRANSIENT_FAILURE From 6711620c1a36dc20ed7609afc2f9f35c53651001 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 14 Apr 2021 14:02:10 -0700 Subject: [PATCH 1423/1899] grpc-js-xds: Add xDS v3 support to the client Add xDS v3 test job --- packages/grpc-js-xds/scripts/xds-v3.sh | 16 + packages/grpc-js-xds/scripts/xds.sh | 1 + packages/grpc-js-xds/src/load-balancer-cds.ts | 2 +- packages/grpc-js-xds/src/load-balancer-eds.ts | 2 +- packages/grpc-js-xds/src/resolver-xds.ts | 18 +- packages/grpc-js-xds/src/resources.ts | 96 +++ packages/grpc-js-xds/src/xds-bootstrap.ts | 33 +- packages/grpc-js-xds/src/xds-client.ts | 749 +++++++++++------- .../src/xds-stream-state/cds-state.ts | 2 +- .../src/xds-stream-state/eds-state.ts | 2 +- .../src/xds-stream-state/lds-state.ts | 17 +- .../src/xds-stream-state/rds-state.ts | 2 +- test/kokoro/linux.cfg | 3 +- test/kokoro/xds-v3-interop.cfg | 24 + 14 files changed, 661 insertions(+), 306 deletions(-) create mode 100755 packages/grpc-js-xds/scripts/xds-v3.sh mode change 100644 => 100755 packages/grpc-js-xds/scripts/xds.sh create mode 100644 packages/grpc-js-xds/src/resources.ts create mode 100644 test/kokoro/xds-v3-interop.cfg diff --git a/packages/grpc-js-xds/scripts/xds-v3.sh b/packages/grpc-js-xds/scripts/xds-v3.sh new file mode 100755 index 000000000..103cbc429 --- /dev/null +++ b/packages/grpc-js-xds/scripts/xds-v3.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Copyright 2021 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +XDS_V3_OPT="--xds_v3_support" $(dirname $0)/xds.sh \ No newline at end of file diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh old mode 100644 new mode 100755 index 714b6fff8..9008b9731 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -58,6 +58,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ + ${XDS_V3_OPT-} \ --client_cmd="$(which node) grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index d0fe2338a..6c57a410f 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -17,7 +17,7 @@ import { connectivityState, status, Metadata, logVerbosity, experimental } from '@grpc/grpc-js'; import { getSingletonXdsClient, XdsClient } from './xds-client'; -import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; +import { Cluster__Output } from './generated/envoy/config/cluster/v3/Cluster'; import SubchannelAddress = experimental.SubchannelAddress; import UnavailablePicker = experimental.UnavailablePicker; import ChildLoadBalancerHandler = experimental.ChildLoadBalancerHandler; diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 657dc3a82..ae9a781bd 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -17,7 +17,7 @@ import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental } from '@grpc/grpc-js'; import { getSingletonXdsClient, XdsClient, XdsClusterDropStats } from './xds-client'; -import { ClusterLoadAssignment__Output } from './generated/envoy/api/v2/ClusterLoadAssignment'; +import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint/v3/ClusterLoadAssignment'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; import { LocalitySubchannelAddress, PriorityChild, PriorityLoadBalancingConfig } from './load-balancer-priority'; import LoadBalancer = experimental.LoadBalancer; diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 102a52349..a9ee1af7d 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -26,20 +26,20 @@ import ResolverListener = experimental.ResolverListener; import uriToString = experimental.uriToString; import ServiceConfig = experimental.ServiceConfig; import registerResolver = experimental.registerResolver; -import { Listener__Output } from './generated/envoy/api/v2/Listener'; +import { Listener__Output } from './generated/envoy/config/listener/v3/Listener'; import { Watcher } from './xds-stream-state/xds-stream-state'; -import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; -import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; +import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; +import { HttpConnectionManager__Output } from './generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; import { CdsLoadBalancingConfig } from './load-balancer-cds'; -import { VirtualHost__Output } from './generated/envoy/api/v2/route/VirtualHost'; -import { RouteMatch__Output } from './generated/envoy/api/v2/route/RouteMatch'; -import { HeaderMatcher__Output } from './generated/envoy/api/v2/route/HeaderMatcher'; +import { VirtualHost__Output } from './generated/envoy/config/route/v3/VirtualHost'; +import { RouteMatch__Output } from './generated/envoy/config/route/v3/RouteMatch'; +import { HeaderMatcher__Output } from './generated/envoy/config/route/v3/HeaderMatcher'; import ConfigSelector = experimental.ConfigSelector; import LoadBalancingConfig = experimental.LoadBalancingConfig; import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluster-manager'; import { ExactValueMatcher, Fraction, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action'; -import { LogVerbosity } from '@grpc/grpc-js/build/src/constants'; +import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from './resources'; const TRACER_NAME = 'xds_resolver'; @@ -210,9 +210,7 @@ class XdsResolver implements Resolver { ) { this.ldsWatcher = { onValidUpdate: (update: Listener__Output) => { - const httpConnectionManager = update.api_listener! - .api_listener as protoLoader.AnyExtension & - HttpConnectionManager__Output; + const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, update.api_listener!.api_listener!.value); switch (httpConnectionManager.route_specifier) { case 'rds': { const routeConfigName = httpConnectionManager.rds!.route_config_name; diff --git a/packages/grpc-js-xds/src/resources.ts b/packages/grpc-js-xds/src/resources.ts new file mode 100644 index 000000000..516980de8 --- /dev/null +++ b/packages/grpc-js-xds/src/resources.ts @@ -0,0 +1,96 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// This is a non-public, unstable API, but it's very convenient +import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; +import { Cluster__Output } from './generated/envoy/config/cluster/v3/Cluster'; +import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint/v3/ClusterLoadAssignment'; +import { Listener__Output } from './generated/envoy/config/listener/v3/Listener'; +import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; +import { HttpConnectionManager__Output } from './generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; + +export const EDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; +export const CDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.Cluster'; +export const LDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.Listener'; +export const RDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; + +export const EDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment'; +export const CDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.cluster.v3.Cluster'; +export const LDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.listener.v3.Listener'; +export const RDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.route.v3.RouteConfiguration'; + +export type EdsTypeUrl = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment' | 'type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment'; +export type CdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Cluster' | 'type.googleapis.com/envoy.config.cluster.v3.Cluster'; +export type LdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Listener' | 'type.googleapis.com/envoy.config.listener.v3.Listener'; +export type RdsTypeUrl = 'type.googleapis.com/envoy.api.v2.RouteConfiguration' | 'type.googleapis.com/envoy.config.route.v3.RouteConfiguration'; + +export type AdsTypeUrl = EdsTypeUrl | CdsTypeUrl | RdsTypeUrl | LdsTypeUrl; + +export const HTTP_CONNECTION_MANGER_TYPE_URL_V2 = + 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; +export const HTTP_CONNECTION_MANGER_TYPE_URL_V3 = + 'type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager'; + +export type HttpConnectionManagerTypeUrl = 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager' | 'type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager'; + +/** + * Map type URLs to their corresponding message types + */ +export type AdsOutputType = T extends EdsTypeUrl + ? ClusterLoadAssignment__Output + : T extends CdsTypeUrl + ? Cluster__Output + : T extends RdsTypeUrl + ? RouteConfiguration__Output + : T extends LdsTypeUrl + ? Listener__Output + : HttpConnectionManager__Output; + +const resourceRoot = loadProtosWithOptionsSync([ + 'envoy/config/listener/v3/listener.proto', + 'envoy/config/route/v3/route.proto', + 'envoy/config/cluster/v3/cluster.proto', + 'envoy/config/endpoint/v3/endpoint.proto', + 'envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto'], { + keepCase: true, + includeDirs: [ + // Paths are relative to src/build + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/googleapis/', + __dirname + '/../../deps/protoc-gen-validate/', + ], + } +); + +const toObjectOptions = { + longs: String, + enums: String, + defaults: true, + oneofs: true +} + +export function decodeSingleResource(targetTypeUrl: T, message: Buffer): AdsOutputType { + const name = targetTypeUrl.substring(targetTypeUrl.lastIndexOf('/') + 1); + const type = resourceRoot.lookup(name); + if (type) { + const decodedMessage = (type as any).decode(message); + return decodedMessage.$type.toObject(decodedMessage, toObjectOptions) as AdsOutputType; + } else { + throw new Error(`ADS Error: unknown resource type ${targetTypeUrl}`); + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts index 00e13d09f..3da4ec3e6 100644 --- a/packages/grpc-js-xds/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -17,11 +17,23 @@ import * as fs from 'fs'; import { Struct } from './generated/google/protobuf/Struct'; -import { Node } from './generated/envoy/api/v2/core/Node'; import { Value } from './generated/google/protobuf/Value'; /* eslint-disable @typescript-eslint/no-explicit-any */ +export interface Locality { + region?: string; + zone?: string; + sub_zone?: string; +} + +export interface Node { + id: string, + locality: Locality; + cluster?: string; + metadata?: Struct; +} + export interface ChannelCredsConfig { type: string; config?: object; @@ -30,6 +42,7 @@ export interface ChannelCredsConfig { export interface XdsServerConfig { serverUri: string; channelCreds: ChannelCredsConfig[]; + serverFeatures: string[]; } export interface BootstrapInfo { @@ -81,9 +94,22 @@ function validateXdsServerConfig(obj: any): XdsServerConfig { 'xds_servers.channel_creds field: at least one entry is required' ); } + if ('server_features' in obj) { + if (!Array.isArray(obj.server_features)) { + throw new Error( + `xds_servers.server_features field: expected array, got ${typeof obj.server_features}` + ); + } + for (const feature of obj.server_features) { + if (typeof feature !== 'string') { + `xds_servers.server_features field element: expected string, got ${typeof feature}` + } + } + } return { serverUri: obj.server_uri, channelCreds: obj.channel_creds.map(validateChannelCredsConfig), + serverFeatures: obj.server_features }; } @@ -149,7 +175,10 @@ function getStructFromJson(obj: any): Struct { * @param obj */ function validateNode(obj: any): Node { - const result: Node = {}; + const result: Node = { + id: '', + locality: {} + }; if (!('id' in obj)) { throw new Error('id field missing in node element'); } diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 22d816a03..adc54ed45 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -16,35 +16,26 @@ */ import * as protoLoader from '@grpc/proto-loader'; -import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials } from '@grpc/grpc-js'; +// This is a non-public, unstable API, but it's very convenient +import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; +import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials, Channel } from '@grpc/grpc-js'; import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; import { loadBootstrapInfo } from './xds-bootstrap'; -import { isIPv4, isIPv6 } from 'net'; -import { Node } from './generated/envoy/api/v2/core/Node'; -import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; -import { DiscoveryRequest } from './generated/envoy/api/v2/DiscoveryRequest'; -import { DiscoveryResponse__Output } from './generated/envoy/api/v2/DiscoveryResponse'; -import { - ClusterLoadAssignment__Output, - ClusterLoadAssignment, -} from './generated/envoy/api/v2/ClusterLoadAssignment'; -import { Cluster__Output } from './generated/envoy/api/v2/Cluster'; -import { LoadReportingServiceClient } from './generated/envoy/service/load_stats/v2/LoadReportingService'; -import { LoadStatsRequest } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; -import { LoadStatsResponse__Output } from './generated/envoy/service/load_stats/v2/LoadStatsResponse'; -import { - Locality__Output, - Locality, -} from './generated/envoy/api/v2/core/Locality'; -import { - ClusterStats, - _envoy_api_v2_endpoint_ClusterStats_DroppedRequests, -} from './generated/envoy/api/v2/endpoint/ClusterStats'; -import { UpstreamLocalityStats } from './generated/envoy/api/v2/endpoint/UpstreamLocalityStats'; -import { Listener__Output } from './generated/envoy/api/v2/Listener'; -import { HttpConnectionManager__Output } from './generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; -import { RouteConfiguration__Output } from './generated/envoy/api/v2/RouteConfiguration'; +import { Node as NodeV2 } from './generated/envoy/api/v2/core/Node'; +import { Node as NodeV3 } from './generated/envoy/config/core/v3/Node'; +import { AggregatedDiscoveryServiceClient as AggregatedDiscoveryServiceClientV2 } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; +import { AggregatedDiscoveryServiceClient as AggregatedDiscoveryServiceClientV3 } from './generated/envoy/service/discovery/v3/AggregatedDiscoveryService'; +import { DiscoveryRequest as DiscoveryRequestV2 } from './generated/envoy/api/v2/DiscoveryRequest'; +import { DiscoveryRequest as DiscoveryRequestV3 } from './generated/envoy/service/discovery/v3/DiscoveryRequest'; +import { DiscoveryResponse__Output } from './generated/envoy/service/discovery/v3/DiscoveryResponse'; +import { LoadReportingServiceClient as LoadReportingServiceClientV2 } from './generated/envoy/service/load_stats/v2/LoadReportingService'; +import { LoadReportingServiceClient as LoadReportingServiceClientV3 } from './generated/envoy/service/load_stats/v3/LoadReportingService'; +import { LoadStatsRequest as LoadStatsRequestV2 } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; +import { LoadStatsRequest as LoadStatsRequestV3 } from './generated/envoy/service/load_stats/v3/LoadStatsRequest'; +import { LoadStatsResponse__Output } from './generated/envoy/service/load_stats/v3/LoadStatsResponse'; +import { Locality, Locality__Output } from './generated/envoy/config/core/v3/Locality'; +import { Listener__Output } from './generated/envoy/config/listener/v3/Listener'; import { Any__Output } from './generated/google/protobuf/Any'; import BackoffTimeout = experimental.BackoffTimeout; import ServiceConfig = experimental.ServiceConfig; @@ -55,6 +46,11 @@ import { CdsState } from './xds-stream-state/cds-state'; import { RdsState } from './xds-stream-state/rds-state'; import { LdsState } from './xds-stream-state/lds-state'; import { Watcher } from './xds-stream-state/xds-stream-state'; +import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint/v3/ClusterLoadAssignment'; +import { Cluster__Output } from './generated/envoy/config/cluster/v3/Cluster'; +import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; +import { Duration } from './generated/google/protobuf/Duration'; +import { AdsOutputType, AdsTypeUrl, CDS_TYPE_URL_V2, CDS_TYPE_URL_V3, decodeSingleResource, EDS_TYPE_URL_V2, EDS_TYPE_URL_V3, LDS_TYPE_URL_V2, LDS_TYPE_URL_V3, RDS_TYPE_URL_V2, RDS_TYPE_URL_V3 } from './resources'; const TRACER_NAME = 'xds_client'; @@ -64,21 +60,6 @@ function trace(text: string): void { const clientVersion = require('../../package.json').version; -const EDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; -const CDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Cluster'; -const LDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.Listener'; -const RDS_TYPE_URL = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; - -type EdsTypeUrl = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; -type CdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Cluster'; -type LdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Listener'; -type RdsTypeUrl = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; - -type AdsTypeUrl = EdsTypeUrl | CdsTypeUrl | RdsTypeUrl | LdsTypeUrl; - -const HTTP_CONNECTION_MANGER_TYPE_URL = - 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; - let loadedProtos: Promise< adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType > | null = null; @@ -94,11 +75,8 @@ function loadAdsProtos(): Promise< [ 'envoy/service/discovery/v2/ads.proto', 'envoy/service/load_stats/v2/lrs.proto', - 'envoy/api/v2/listener.proto', - 'envoy/api/v2/route.proto', - 'envoy/api/v2/cluster.proto', - 'envoy/api/v2/endpoint.proto', - 'envoy/config/filter/network/http_connection_manager/v2/http_connection_manager.proto', + 'envoy/service/discovery/v3/ads.proto', + 'envoy/service/load_stats/v3/lrs.proto', ], { keepCase: true, @@ -106,7 +84,6 @@ function loadAdsProtos(): Promise< enums: String, defaults: true, oneofs: true, - json: true, includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', @@ -145,6 +122,32 @@ export interface XdsClusterLocalityStats { addCallFinished(fail: boolean): void; } +interface DroppedRequests { + category: string; + dropped_count: number; +} + +interface UpstreamLocalityStats { + locality: Locality; + total_issued_requests: number; + total_successful_requests: number; + total_error_requests: number; + total_requests_in_progress: number; +} + +/** + * An interface representing the ClusterStats message type, restricted to the + * fields used in this module to ensure compatibility with both v2 and v3 APIs. + */ +interface ClusterStats { + cluster_name: string; + cluster_service_name: string; + dropped_requests: DroppedRequests[]; + total_dropped_requests: number; + upstream_locality_stats: UpstreamLocalityStats[]; + load_report_interval: Duration +} + interface ClusterLocalityStats { locality: Locality__Output; callsStarted: number; @@ -218,39 +221,32 @@ class ClusterLoadReportMap { } } +type AdsServiceKind = 'eds' | 'cds' | 'rds' | 'lds'; + interface AdsState { - [EDS_TYPE_URL]: EdsState; - [CDS_TYPE_URL]: CdsState; - [RDS_TYPE_URL]: RdsState; - [LDS_TYPE_URL]: LdsState; + eds: EdsState; + cds: CdsState; + rds: RdsState; + lds: LdsState; } -/** - * Map type URLs to their corresponding message types - */ -type OutputType = T extends EdsTypeUrl - ? ClusterLoadAssignment__Output - : T extends CdsTypeUrl - ? Cluster__Output - : T extends RdsTypeUrl - ? RouteConfiguration__Output - : Listener__Output; +enum XdsApiVersion { + V2, + V3 +} function getResponseMessages( - typeUrl: T, + targetTypeUrl: T, + allowedTypeUrls: string[], resources: Any__Output[] -): OutputType[] { - const result: OutputType[] = []; +): AdsOutputType[] { + const result: AdsOutputType[] = []; for (const resource of resources) { - if (protoLoader.isAnyExtension(resource) && resource['@type'] === typeUrl) { - result.push(resource as protoLoader.AnyExtension & OutputType); + if (allowedTypeUrls.includes(resource.type_url)) { + result.push(decodeSingleResource(targetTypeUrl, resource.value)); } else { throw new Error( - `ADS Error: Invalid resource type ${ - protoLoader.isAnyExtension(resource) - ? resource['@type'] - : resource.type_url - }, expected ${typeUrl}` + `ADS Error: Invalid resource type ${resource.type_url}, expected ${allowedTypeUrls}` ); } } @@ -258,20 +254,39 @@ function getResponseMessages( } export class XdsClient { - private adsNode: Node | null = null; - private adsClient: AggregatedDiscoveryServiceClient | null = null; - private adsCall: ClientDuplexStream< - DiscoveryRequest, + private apiVersion: XdsApiVersion = XdsApiVersion.V2; + + private adsNodeV2: NodeV2 | null = null; + private adsNodeV3: NodeV3 | null = null; + /* A client initiates connections lazily, so the client we don't use won't + * use significant extra resources. */ + private adsClientV2: AggregatedDiscoveryServiceClientV2 | null = null; + private adsClientV3: AggregatedDiscoveryServiceClientV3 | null = null; + /* TypeScript typing is structural, so we can take advantage of the fact that + * the output structures for the two call types are identical. */ + private adsCallV2: ClientDuplexStream< + DiscoveryRequestV2, + DiscoveryResponse__Output + > | null = null; + private adsCallV3: ClientDuplexStream< + DiscoveryRequestV3, DiscoveryResponse__Output > | null = null; - private lrsNode: Node | null = null; - private lrsClient: LoadReportingServiceClient | null = null; - private lrsCall: ClientDuplexStream< - LoadStatsRequest, + private lrsNodeV2: NodeV2 | null = null; + private lrsNodeV3: NodeV3 | null = null; + private lrsClientV2: LoadReportingServiceClientV2 | null = null; + private lrsClientV3: LoadReportingServiceClientV3 | null = null; + private lrsCallV2: ClientDuplexStream< + LoadStatsRequestV2, + LoadStatsResponse__Output + > | null = null; + private lrsCallV3: ClientDuplexStream< + LoadStatsRequestV3, LoadStatsResponse__Output > | null = null; private latestLrsSettings: LoadStatsResponse__Output | null = null; + private receivedLrsSettingsForCurrentStream = false; private clusterStatsMap: ClusterLoadReportMap = new ClusterLoadReportMap(); private statsTimer: NodeJS.Timer; @@ -285,22 +300,22 @@ export class XdsClient { constructor() { const edsState = new EdsState(() => { - this.updateNames(EDS_TYPE_URL); + this.updateNames('eds'); }); const cdsState = new CdsState(edsState, () => { - this.updateNames(CDS_TYPE_URL); + this.updateNames('cds'); }); const rdsState = new RdsState(() => { - this.updateNames(RDS_TYPE_URL); + this.updateNames('rds'); }); const ldsState = new LdsState(rdsState, () => { - this.updateNames(LDS_TYPE_URL); + this.updateNames('lds'); }); this.adsState = { - [EDS_TYPE_URL]: edsState, - [CDS_TYPE_URL]: cdsState, - [RDS_TYPE_URL]: rdsState, - [LDS_TYPE_URL]: ldsState, + eds: edsState, + cds: cdsState, + rds: rdsState, + lds: ldsState, }; const channelArgs = { @@ -322,17 +337,34 @@ export class XdsClient { if (this.hasShutdown) { return; } - const node: Node = { + if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('xds_v3') >= 0) { + this.apiVersion = XdsApiVersion.V3; + } else { + this.apiVersion = XdsApiVersion.V2; + } + const nodeV2: NodeV2 = { ...bootstrapInfo.node, build_version: `gRPC Node Pure JS ${clientVersion}`, user_agent_name: 'gRPC Node Pure JS', }; - this.adsNode = { - ...node, + const nodeV3: NodeV3 = { + ...bootstrapInfo.node, + user_agent_name: 'gRPC Node Pure JS', + }; + this.adsNodeV2 = { + ...nodeV2, client_features: ['envoy.lb.does_not_support_overprovisioning'], }; - this.lrsNode = { - ...node, + this.adsNodeV3 = { + ...nodeV3, + client_features: ['envoy.lb.does_not_support_overprovisioning'], + }; + this.lrsNodeV2 = { + ...nodeV2, + client_features: ['envoy.lrs.supports_send_all_clusters'], + }; + this.lrsNodeV3 = { + ...nodeV3, client_features: ['envoy.lrs.supports_send_all_clusters'], }; const credentialsConfigs = bootstrapInfo.xdsServers[0].channelCreds; @@ -356,18 +388,30 @@ export class XdsClient { }); return; } + const serverUri = bootstrapInfo.xdsServers[0].serverUri trace('Starting xDS client connected to server URI ' + bootstrapInfo.xdsServers[0].serverUri); - this.adsClient = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( - bootstrapInfo.xdsServers[0].serverUri, + const channel = new Channel(serverUri, channelCreds, channelArgs); + this.adsClientV2 = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( + serverUri, channelCreds, - channelArgs + {channelOverride: channel} + ); + this.adsClientV3 = new protoDefinitions.envoy.service.discovery.v3.AggregatedDiscoveryService( + serverUri, + channelCreds, + {channelOverride: channel} ); this.maybeStartAdsStream(); - this.lrsClient = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( - bootstrapInfo.xdsServers[0].serverUri, + this.lrsClientV2 = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( + serverUri, + channelCreds, + {channelOverride: channel} + ); + this.lrsClientV3 = new protoDefinitions.envoy.service.load_stats.v3.LoadReportingService( + serverUri, channelCreds, - {channelOverride: this.adsClient.getChannel()} + {channelOverride: channel} ); this.maybeStartLrsStream(); }, @@ -387,32 +431,40 @@ export class XdsClient { private handleAdsResponse(message: DiscoveryResponse__Output) { let errorString: string | null; - /* The cases in this switch statement look redundant but separating them - * out like this is necessary for the typechecker to validate the types - * as narrowly as we need it to. */ + let serviceKind: AdsServiceKind; switch (message.type_url) { - case EDS_TYPE_URL: - errorString = this.adsState[message.type_url].handleResponses( - getResponseMessages(message.type_url, message.resources) + case EDS_TYPE_URL_V2: + case EDS_TYPE_URL_V3: + errorString = this.adsState.eds.handleResponses( + getResponseMessages(EDS_TYPE_URL_V3, [EDS_TYPE_URL_V2, EDS_TYPE_URL_V3], message.resources) ); + serviceKind = 'eds'; break; - case CDS_TYPE_URL: - errorString = this.adsState[message.type_url].handleResponses( - getResponseMessages(message.type_url, message.resources) + case CDS_TYPE_URL_V2: + case CDS_TYPE_URL_V3: + errorString = this.adsState.cds.handleResponses( + getResponseMessages(CDS_TYPE_URL_V3, [CDS_TYPE_URL_V2, CDS_TYPE_URL_V3], message.resources) ); + serviceKind = 'cds'; break; - case RDS_TYPE_URL: - errorString = this.adsState[message.type_url].handleResponses( - getResponseMessages(message.type_url, message.resources) + case RDS_TYPE_URL_V2: + case RDS_TYPE_URL_V3: + errorString = this.adsState.rds.handleResponses( + getResponseMessages(RDS_TYPE_URL_V3, [RDS_TYPE_URL_V2, RDS_TYPE_URL_V3], message.resources) ); + serviceKind = 'rds'; break; - case LDS_TYPE_URL: - errorString = this.adsState[message.type_url].handleResponses( - getResponseMessages(message.type_url, message.resources) + case LDS_TYPE_URL_V2: + case LDS_TYPE_URL_V3: + errorString = this.adsState.lds.handleResponses( + getResponseMessages(LDS_TYPE_URL_V3, [LDS_TYPE_URL_V2, LDS_TYPE_URL_V3], message.resources) ); + serviceKind = 'lds'; break; default: errorString = `Unknown type_url ${message.type_url}`; + // This is not used in this branch, but setting it makes the types easier to handle + serviceKind = 'eds'; } if (errorString === null) { trace('Acking message with type URL ' + message.type_url); @@ -420,65 +472,148 @@ export class XdsClient { * implies that message.type_url is one of the 4 known type URLs, which * means that this type assertion is valid. */ const typeUrl = message.type_url as AdsTypeUrl; - this.adsState[typeUrl].nonce = message.nonce; - this.adsState[typeUrl].versionInfo = message.version_info; - this.ack(typeUrl); + this.adsState[serviceKind].nonce = message.nonce; + this.adsState[serviceKind].versionInfo = message.version_info; + this.ack(serviceKind); } else { trace('Nacking message with type URL ' + message.type_url + ': "' + errorString + '"'); this.nack(message.type_url, errorString); } } + private handleAdsCallError(error: ServiceError) { + trace( + 'ADS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.adsCallV2 = null; + this.adsCallV3 = null; + this.reportStreamError(error); + /* If the backoff timer is no longer running, we do not need to wait any + * more to start the new call. */ + if (!this.adsBackoff.isRunning()) { + this.maybeStartAdsStream(); + } + } + + private maybeStartAdsStreamV2(): boolean { + if (this.apiVersion !== XdsApiVersion.V2) { + return false; + } + if (this.adsClientV2 === null) { + return false; + } + if (this.adsCallV2 !== null) { + return false; + } + this.adsCallV2 = this.adsClientV2.StreamAggregatedResources(); + this.adsCallV2.on('data', (message: DiscoveryResponse__Output) => { + this.handleAdsResponse(message); + }); + this.adsCallV2.on('error', (error: ServiceError) => { + this.handleAdsCallError(error); + }); + return true; + } + + private maybeStartAdsStreamV3(): boolean { + if (this.apiVersion !== XdsApiVersion.V3) { + return false; + } + if (this.adsClientV3 === null) { + return false; + } + if (this.adsCallV3 !== null) { + return false; + } + this.adsCallV3 = this.adsClientV3.StreamAggregatedResources(); + this.adsCallV3.on('data', (message: DiscoveryResponse__Output) => { + this.handleAdsResponse(message); + }); + this.adsCallV3.on('error', (error: ServiceError) => { + this.handleAdsCallError(error); + }); + return true; + } + /** * Start the ADS stream if the client exists and there is not already an - * existing stream, and there + * existing stream, and there are resources to request. */ private maybeStartAdsStream() { - if (this.adsClient === null) { - return; - } - if (this.adsCall !== null) { - return; - } if (this.hasShutdown) { return; } - if (this.adsState[EDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[CDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[RDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[LDS_TYPE_URL].getResourceNames().length === 0) { + if (this.adsState.eds.getResourceNames().length === 0 && + this.adsState.cds.getResourceNames().length === 0 && + this.adsState.rds.getResourceNames().length === 0 && + this.adsState.lds.getResourceNames().length === 0) { return; } - trace('Starting ADS stream'); - // Backoff relative to when we start the request - this.adsBackoff.runOnce(); - this.adsCall = this.adsClient.StreamAggregatedResources(); - this.adsCall.on('data', (message: DiscoveryResponse__Output) => { - this.handleAdsResponse(message); - }); - this.adsCall.on('error', (error: ServiceError) => { - trace( - 'ADS stream ended. code=' + error.code + ' details= ' + error.details - ); - this.adsCall = null; - this.reportStreamError(error); - /* If the backoff timer is no longer running, we do not need to wait any - * more to start the new call. */ - if (!this.adsBackoff.isRunning()) { - this.maybeStartAdsStream(); + let streamStarted: boolean; + if (this.apiVersion === XdsApiVersion.V2) { + streamStarted = this.maybeStartAdsStreamV2(); + } else { + streamStarted = this.maybeStartAdsStreamV3(); + } + if (streamStarted) { + trace('Started ADS stream'); + // Backoff relative to when we start the request + this.adsBackoff.runOnce(); + + const allServiceKinds: AdsServiceKind[] = ['eds', 'cds', 'rds', 'lds']; + for (const service of allServiceKinds) { + const state = this.adsState[service]; + if (state.getResourceNames().length > 0) { + this.updateNames(service); + } } - }); + } + } + + private maybeSendAdsMessage(typeUrl: string, resourceNames: string[], responseNonce: string, versionInfo: string, errorMessage?: string) { + if (this.apiVersion === XdsApiVersion.V2) { + this.adsCallV2?.write({ + node: this.adsNodeV2!, + type_url: typeUrl, + resource_names: resourceNames, + response_nonce: responseNonce, + version_info: versionInfo, + error_detail: errorMessage ? { message: errorMessage } : undefined + }); + } else { + this.adsCallV3?.write({ + node: this.adsNodeV3!, + type_url: typeUrl, + resource_names: resourceNames, + response_nonce: responseNonce, + version_info: versionInfo, + error_detail: errorMessage ? { message: errorMessage } : undefined + }); + } + } - const allTypeUrls: AdsTypeUrl[] = [ - EDS_TYPE_URL, - CDS_TYPE_URL, - RDS_TYPE_URL, - LDS_TYPE_URL, - ]; - for (const typeUrl of allTypeUrls) { - const state = this.adsState[typeUrl]; - if (state.getResourceNames().length > 0) { - this.updateNames(typeUrl); + private getTypeUrl(serviceKind: AdsServiceKind): AdsTypeUrl { + if (this.apiVersion === XdsApiVersion.V2) { + switch (serviceKind) { + case 'eds': + return EDS_TYPE_URL_V2; + case 'cds': + return CDS_TYPE_URL_V2; + case 'rds': + return RDS_TYPE_URL_V2; + case 'lds': + return LDS_TYPE_URL_V2; + } + } else { + switch (serviceKind) { + case 'eds': + return EDS_TYPE_URL_V3; + case 'cds': + return CDS_TYPE_URL_V3; + case 'rds': + return RDS_TYPE_URL_V3; + case 'lds': + return LDS_TYPE_URL_V3; } } } @@ -487,13 +622,13 @@ export class XdsClient { * Acknowledge an update. This should be called after the local nonce and * version info are updated so that it sends the post-update values. */ - ack(typeUrl: AdsTypeUrl) { + ack(serviceKind: AdsServiceKind) { /* An ack is the best indication of a successful interaction between the * client and the server, so we can reset the backoff timer here. */ this.adsBackoff.stop(); this.adsBackoff.reset(); - this.updateNames(typeUrl); + this.updateNames(serviceKind); } /** @@ -504,135 +639,196 @@ export class XdsClient { let resourceNames: string[]; let nonce: string; let versionInfo: string; + let serviceKind: AdsServiceKind | null; switch (typeUrl) { - case EDS_TYPE_URL: - case CDS_TYPE_URL: - case RDS_TYPE_URL: - case LDS_TYPE_URL: - resourceNames = this.adsState[typeUrl].getResourceNames(); - nonce = this.adsState[typeUrl].nonce; - versionInfo = this.adsState[typeUrl].versionInfo; + case EDS_TYPE_URL_V2: + case EDS_TYPE_URL_V3: + serviceKind = 'eds'; + break; + case CDS_TYPE_URL_V2: + case CDS_TYPE_URL_V3: + serviceKind = 'cds'; + break; + case RDS_TYPE_URL_V2: + case RDS_TYPE_URL_V3: + serviceKind = 'rds'; + break; + case LDS_TYPE_URL_V2: + case LDS_TYPE_URL_V3: + serviceKind = 'lds'; break; default: - resourceNames = []; - nonce = ''; - versionInfo = ''; - } - this.adsCall?.write({ - node: this.adsNode!, - type_url: typeUrl, - resource_names: resourceNames, - response_nonce: nonce, - version_info: versionInfo, - error_detail: { - message: message, - }, - }); + serviceKind = null; + break; + } + if (serviceKind) { + resourceNames = this.adsState[serviceKind].getResourceNames(); + nonce = this.adsState[serviceKind].nonce; + versionInfo = this.adsState[serviceKind].versionInfo; + } else { + resourceNames = []; + nonce = ''; + versionInfo = ''; + } + this.maybeSendAdsMessage(typeUrl, resourceNames, nonce, versionInfo, message); } - private updateNames(typeUrl: AdsTypeUrl) { - if (this.adsState[EDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[CDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[RDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[LDS_TYPE_URL].getResourceNames().length === 0) { - this.adsCall?.end(); - this.lrsCall?.end(); + private updateNames(serviceKind: AdsServiceKind) { + if (this.adsState.eds.getResourceNames().length === 0 && + this.adsState.cds.getResourceNames().length === 0 && + this.adsState.rds.getResourceNames().length === 0 && + this.adsState.lds.getResourceNames().length === 0) { + this.adsCallV2?.end(); + this.adsCallV2 = null; + this.adsCallV3?.end(); + this.adsCallV3 = null; + this.lrsCallV2?.end(); + this.lrsCallV2 = null; + this.lrsCallV3?.end(); + this.lrsCallV3 = null; return; } this.maybeStartAdsStream(); this.maybeStartLrsStream(); - trace('Sending update for type URL ' + typeUrl + ' with names ' + this.adsState[typeUrl].getResourceNames()); - this.adsCall?.write({ - node: this.adsNode!, - type_url: typeUrl, - resource_names: this.adsState[typeUrl].getResourceNames(), - response_nonce: this.adsState[typeUrl].nonce, - version_info: this.adsState[typeUrl].versionInfo, - }); + trace('Sending update for ' + serviceKind + ' with names ' + this.adsState[serviceKind].getResourceNames()); + const typeUrl = this.getTypeUrl(serviceKind); + this.maybeSendAdsMessage(typeUrl, this.adsState[serviceKind].getResourceNames(), this.adsState[serviceKind].nonce, this.adsState[serviceKind].versionInfo); } private reportStreamError(status: StatusObject) { - this.adsState[EDS_TYPE_URL].reportStreamError(status); - this.adsState[CDS_TYPE_URL].reportStreamError(status); - this.adsState[RDS_TYPE_URL].reportStreamError(status); - this.adsState[LDS_TYPE_URL].reportStreamError(status); + this.adsState.eds.reportStreamError(status); + this.adsState.cds.reportStreamError(status); + this.adsState.rds.reportStreamError(status); + this.adsState.lds.reportStreamError(status); } - private maybeStartLrsStream() { - if (!this.lrsClient) { - return; + private handleLrsResponse(message: LoadStatsResponse__Output) { + trace('Received LRS response'); + /* Once we get any response from the server, we assume that the stream is + * in a good state, so we can reset the backoff timer. */ + this.lrsBackoff.stop(); + this.lrsBackoff.reset(); + if ( + !this.receivedLrsSettingsForCurrentStream || + message.load_reporting_interval?.seconds !== + this.latestLrsSettings?.load_reporting_interval?.seconds || + message.load_reporting_interval?.nanos !== + this.latestLrsSettings?.load_reporting_interval?.nanos + ) { + /* Only reset the timer if the interval has changed or was not set + * before. */ + clearInterval(this.statsTimer); + /* Convert a google.protobuf.Duration to a number of milliseconds for + * use with setInterval. */ + const loadReportingIntervalMs = + Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + + message.load_reporting_interval!.nanos / 1_000_000; + trace('Received LRS response with load reporting interval ' + loadReportingIntervalMs + ' ms'); + this.statsTimer = setInterval(() => { + this.sendStats(); + }, loadReportingIntervalMs); } - if (this.lrsCall) { - return; + this.latestLrsSettings = message; + this.receivedLrsSettingsForCurrentStream = true; + } + + private handleLrsCallError(error: ServiceError) { + trace( + 'LRS stream ended. code=' + error.code + ' details= ' + error.details + ); + this.lrsCallV2 = null; + this.lrsCallV3 = null; + clearInterval(this.statsTimer); + /* If the backoff timer is no longer running, we do not need to wait any + * more to start the new call. */ + if (!this.lrsBackoff.isRunning()) { + this.maybeStartLrsStream(); + } + } + + private maybeStartLrsStreamV2(): boolean { + if (!this.lrsClientV2) { + return false; + } + if (this.lrsCallV2) { + return false; } + this.lrsCallV2 = this.lrsClientV2.streamLoadStats(); + this.receivedLrsSettingsForCurrentStream = false; + this.lrsCallV2.on('data', (message: LoadStatsResponse__Output) => { + this.handleLrsResponse(message); + }); + this.lrsCallV2.on('error', (error: ServiceError) => { + this.handleLrsCallError(error); + }); + return true; + } + + private maybeStartLrsStreamV3(): boolean { + if (!this.lrsClientV3) { + return false; + } + if (this.lrsCallV3) { + return false; + } + this.lrsCallV3 = this.lrsClientV3.streamLoadStats(); + this.receivedLrsSettingsForCurrentStream = false; + this.lrsCallV3.on('data', (message: LoadStatsResponse__Output) => { + this.handleLrsResponse(message); + }); + this.lrsCallV3.on('error', (error: ServiceError) => { + this.handleLrsCallError(error); + }); + return true; + } + + private maybeStartLrsStream() { if (this.hasShutdown) { return; } - if (this.adsState[EDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[CDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[RDS_TYPE_URL].getResourceNames().length === 0 && - this.adsState[LDS_TYPE_URL].getResourceNames().length === 0) { + if (this.adsState.eds.getResourceNames().length === 0 && + this.adsState.cds.getResourceNames().length === 0 && + this.adsState.rds.getResourceNames().length === 0 && + this.adsState.lds.getResourceNames().length === 0) { return; } - - trace('Starting LRS stream'); - - this.lrsBackoff.runOnce(); - this.lrsCall = this.lrsClient.streamLoadStats(); - let receivedSettingsForThisStream = false; - this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { - /* Once we get any response from the server, we assume that the stream is - * in a good state, so we can reset the backoff timer. */ - this.lrsBackoff.stop(); - this.lrsBackoff.reset(); - if ( - !receivedSettingsForThisStream || - message.load_reporting_interval?.seconds !== - this.latestLrsSettings?.load_reporting_interval?.seconds || - message.load_reporting_interval?.nanos !== - this.latestLrsSettings?.load_reporting_interval?.nanos - ) { - /* Only reset the timer if the interval has changed or was not set - * before. */ - clearInterval(this.statsTimer); - /* Convert a google.protobuf.Duration to a number of milliseconds for - * use with setInterval. */ - const loadReportingIntervalMs = - Number.parseInt(message.load_reporting_interval!.seconds) * 1000 + - message.load_reporting_interval!.nanos / 1_000_000; - trace('Received LRS request with load reporting interval ' + loadReportingIntervalMs + ' ms'); - this.statsTimer = setInterval(() => { - this.sendStats(); - }, loadReportingIntervalMs); - } - this.latestLrsSettings = message; - receivedSettingsForThisStream = true; - }); - this.lrsCall.on('error', (error: ServiceError) => { - trace( - 'LRS stream ended. code=' + error.code + ' details= ' + error.details - ); - this.lrsCall = null; - clearInterval(this.statsTimer); - /* If the backoff timer is no longer running, we do not need to wait any - * more to start the new call. */ - if (!this.lrsBackoff.isRunning()) { - this.maybeStartLrsStream(); - } - }); - /* Send buffered stats information when starting LRS stream. If there is no - * buffered stats information, it will still send the node field. */ - this.sendStats(); + + let streamStarted: boolean; + if (this.apiVersion === XdsApiVersion.V2) { + streamStarted = this.maybeStartLrsStreamV2(); + } else { + streamStarted = this.maybeStartLrsStreamV3(); + } + + if (streamStarted) { + trace('Starting LRS stream'); + this.lrsBackoff.runOnce(); + /* Send buffered stats information when starting LRS stream. If there is no + * buffered stats information, it will still send the node field. */ + this.sendStats(); + } + } + + private maybeSendLrsMessage(clusterStats: ClusterStats[]) { + if (this.apiVersion === XdsApiVersion.V2) { + this.lrsCallV2?.write({ + node: this.lrsNodeV2!, + cluster_stats: clusterStats + }); + } else { + this.lrsCallV3?.write({ + node: this.lrsNodeV3!, + cluster_stats: clusterStats + }); + } } private sendStats() { - if (!this.lrsCall) { + if (this.lrsCallV2 === null && this.lrsCallV3 === null) { return; } if (!this.latestLrsSettings) { - this.lrsCall.write({ - node: this.lrsNode!, - }); + this.maybeSendLrsMessage([]); return; } const clusterStats: ClusterStats[] = []; @@ -664,7 +860,7 @@ export class XdsClient { localityStats.callsFailed = 0; } } - const droppedRequests: _envoy_api_v2_endpoint_ClusterStats_DroppedRequests[] = []; + const droppedRequests: DroppedRequests[] = []; let totalDroppedRequests = 0; for (const [category, count] of stats.callsDropped.entries()) { if (count > 0) { @@ -696,10 +892,7 @@ export class XdsClient { } } trace('Sending LRS stats ' + JSON.stringify(clusterStats, undefined, 2)); - this.lrsCall.write({ - node: this.lrsNode!, - cluster_stats: clusterStats, - }); + this.maybeSendLrsMessage(clusterStats); } addEndpointWatcher( @@ -707,7 +900,7 @@ export class XdsClient { watcher: Watcher ) { trace('Watcher added for endpoint ' + edsServiceName); - this.adsState[EDS_TYPE_URL].addWatcher(edsServiceName, watcher); + this.adsState.eds.addWatcher(edsServiceName, watcher); } removeEndpointWatcher( @@ -715,37 +908,37 @@ export class XdsClient { watcher: Watcher ) { trace('Watcher removed for endpoint ' + edsServiceName); - this.adsState[EDS_TYPE_URL].removeWatcher(edsServiceName, watcher); + this.adsState.eds.removeWatcher(edsServiceName, watcher); } addClusterWatcher(clusterName: string, watcher: Watcher) { trace('Watcher added for cluster ' + clusterName); - this.adsState[CDS_TYPE_URL].addWatcher(clusterName, watcher); + this.adsState.cds.addWatcher(clusterName, watcher); } removeClusterWatcher(clusterName: string, watcher: Watcher) { trace('Watcher removed for cluster ' + clusterName); - this.adsState[CDS_TYPE_URL].removeWatcher(clusterName, watcher); + this.adsState.cds.removeWatcher(clusterName, watcher); } addRouteWatcher(routeConfigName: string, watcher: Watcher) { trace('Watcher added for route ' + routeConfigName); - this.adsState[RDS_TYPE_URL].addWatcher(routeConfigName, watcher); + this.adsState.rds.addWatcher(routeConfigName, watcher); } removeRouteWatcher(routeConfigName: string, watcher: Watcher) { trace('Watcher removed for route ' + routeConfigName); - this.adsState[RDS_TYPE_URL].removeWatcher(routeConfigName, watcher); + this.adsState.rds.removeWatcher(routeConfigName, watcher); } addListenerWatcher(targetName: string, watcher: Watcher) { trace('Watcher added for listener ' + targetName); - this.adsState[LDS_TYPE_URL].addWatcher(targetName, watcher); + this.adsState.lds.addWatcher(targetName, watcher); } removeListenerWatcher(targetName: string, watcher: Watcher) { trace('Watcher removed for listener ' + targetName); - this.adsState[LDS_TYPE_URL].removeWatcher(targetName, watcher); + this.adsState.lds.removeWatcher(targetName, watcher); } /** @@ -833,10 +1026,14 @@ export class XdsClient { } private shutdown(): void { - this.adsCall?.cancel(); - this.adsClient?.close(); - this.lrsCall?.cancel(); - this.lrsClient?.close(); + this.adsCallV2?.cancel(); + this.adsCallV3?.cancel(); + this.adsClientV2?.close(); + this.adsClientV3?.close(); + this.lrsCallV2?.cancel(); + this.lrsCallV3?.cancel(); + this.lrsClientV2?.close(); + this.lrsClientV3?.close(); this.hasShutdown = true; } } diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 343089958..a6e89805d 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -16,7 +16,7 @@ */ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; -import { Cluster__Output } from "../generated/envoy/api/v2/Cluster"; +import { Cluster__Output } from "../generated/envoy/config/cluster/v3/Cluster"; import { EdsState } from "./eds-state"; import { Watcher, XdsStreamState } from "./xds-stream-state"; diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index c9beef292..a0fb5f4dc 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -17,7 +17,7 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { isIPv4, isIPv6 } from "net"; -import { ClusterLoadAssignment__Output } from "../generated/envoy/api/v2/ClusterLoadAssignment"; +import { ClusterLoadAssignment__Output } from "../generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; import { Watcher, XdsStreamState } from "./xds-stream-state"; const TRACER_NAME = 'xds_client'; diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 554712727..eb76f7994 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -17,10 +17,11 @@ import * as protoLoader from '@grpc/proto-loader'; import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; -import { Listener__Output } from "../generated/envoy/api/v2/Listener"; +import { Listener__Output } from '../generated/envoy/config/listener/v3/Listener'; import { RdsState } from "./rds-state"; import { Watcher, XdsStreamState } from "./xds-stream-state"; -import { HttpConnectionManager__Output } from '../generated/envoy/config/filter/network/http_connection_manager/v2/HttpConnectionManager'; +import { HttpConnectionManager__Output } from '../generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; +import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V2, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from '../resources'; const TRACER_NAME = 'xds_client'; @@ -28,9 +29,6 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } -const HTTP_CONNECTION_MANGER_TYPE_URL = - 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; - export class LdsState implements XdsStreamState { versionInfo = ''; nonce = ''; @@ -95,16 +93,13 @@ export class LdsState implements XdsStreamState { if ( !( message.api_listener?.api_listener && - protoLoader.isAnyExtension(message.api_listener.api_listener) && - message.api_listener?.api_listener['@type'] === - HTTP_CONNECTION_MANGER_TYPE_URL + (message.api_listener.api_listener.type_url === HTTP_CONNECTION_MANGER_TYPE_URL_V2 || + message.api_listener.api_listener.type_url === HTTP_CONNECTION_MANGER_TYPE_URL_V3) ) ) { return false; } - const httpConnectionManager = message.api_listener - ?.api_listener as protoLoader.AnyExtension & - HttpConnectionManager__Output; + const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener.value); switch (httpConnectionManager.route_specifier) { case 'rds': return !!httpConnectionManager.rds?.config_source?.ads; diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 8f795e0f5..1e50f22e7 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -16,7 +16,7 @@ */ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; -import { RouteConfiguration__Output } from "../generated/envoy/api/v2/RouteConfiguration"; +import { RouteConfiguration__Output } from "../generated/envoy/config/route/v3/RouteConfiguration"; import { CdsLoadBalancingConfig } from "../load-balancer-cds"; import { Watcher, XdsStreamState } from "./xds-stream-state"; import ServiceConfig = experimental.ServiceConfig; diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index f40e6db43..63f88d399 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -11,7 +11,6 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. @@ -21,4 +20,4 @@ action { define_artifacts { regex: "github/grpc-node/reports/**/sponge_log.xml" } -} +} \ No newline at end of file diff --git a/test/kokoro/xds-v3-interop.cfg b/test/kokoro/xds-v3-interop.cfg new file mode 100644 index 000000000..d7ffa8fab --- /dev/null +++ b/test/kokoro/xds-v3-interop.cfg @@ -0,0 +1,24 @@ +# Copyright 2021 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds-v3.sh" +timeout_mins: 120 +action { + define_artifacts { + regex: "github/grpc/reports/**" + } +} From 4c767ca94624f938aa86f8c53994fa88c9ad61c3 Mon Sep 17 00:00:00 2001 From: "@EduardoLaranjo" Date: Tue, 4 May 2021 19:27:24 +0100 Subject: [PATCH 1424/1899] Fix auto-generated service definition relate to issue #1766 --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 04717f3fb..82a13a123 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -542,7 +542,7 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: } function generateServiceDefinitionInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { - formatter.writeLine(`export interface ${serviceType.name}Definition {`); + formatter.writeLine(`export interface ${serviceType.name}Definition extends grpc.ServiceDefinition {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; From a5fb029e7054a5be4b8791144139fb0b8631abbf Mon Sep 17 00:00:00 2001 From: Eduardo Laranjo Date: Wed, 5 May 2021 13:41:45 +0100 Subject: [PATCH 1425/1899] Add new generated golden files --- .../golden-generated/google/longrunning/Operations.ts | 2 +- .../golden-generated/google/showcase/v1beta1/Echo.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 8e5684ada..7644f974d 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -232,7 +232,7 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { } -export interface OperationsDefinition { +export interface OperationsDefinition extends grpc.ServiceDefinition { CancelOperation: MethodDefinition<_google_longrunning_CancelOperationRequest, _google_protobuf_Empty, _google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty__Output> DeleteOperation: MethodDefinition<_google_longrunning_DeleteOperationRequest, _google_protobuf_Empty, _google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty__Output> GetOperation: MethodDefinition<_google_longrunning_GetOperationRequest, _google_longrunning_Operation, _google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation__Output> diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index acb911270..8e75c6c1a 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -191,7 +191,7 @@ export interface EchoHandlers extends grpc.UntypedServiceImplementation { } -export interface EchoDefinition { +export interface EchoDefinition extends grpc.ServiceDefinition { Block: MethodDefinition<_google_showcase_v1beta1_BlockRequest, _google_showcase_v1beta1_BlockResponse, _google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse__Output> Chat: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> Collect: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> From cc0c8deea39ae3e9d744527104100a7ac39dc578 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 May 2021 13:09:16 -0700 Subject: [PATCH 1426/1899] grpc-js: Make GRPC_VERBOSITY accept lower-case values --- packages/grpc-js/src/logging.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 1140e8d8a..dea9c93f8 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -22,7 +22,7 @@ let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; const verbosityString = process.env.GRPC_NODE_VERBOSITY ?? process.env.GRPC_VERBOSITY ?? ''; -switch (verbosityString) { +switch (verbosityString.toUpperCase()) { case 'DEBUG': _logVerbosity = LogVerbosity.DEBUG; break; From 7c2acccff51a2b6cf6cd8911b3902112a449a030 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 May 2021 14:28:15 -0700 Subject: [PATCH 1427/1899] proto-loader: Bump to 0.6.2 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index ee49abc40..0d9ff4437 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.1", + "version": "0.6.2", "author": "Google Inc.", "contributors": [ { From 03a72a1d2e8f1b9bb70e9a40e5c72d4b232b61bf Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 7 May 2021 09:36:10 +0200 Subject: [PATCH 1428/1899] add emulated aarch64 linux tests --- run-tests.sh | 3 ++- test/aarch64/prepare_qemu.sh | 26 ++++++++++++++++++++++ test/kokoro/linux_aarch64.cfg | 24 ++++++++++++++++++++ test/kokoro_linux_aarch64.sh | 42 +++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100755 test/aarch64/prepare_qemu.sh create mode 100644 test/kokoro/linux_aarch64.cfg create mode 100755 test/kokoro_linux_aarch64.sh diff --git a/run-tests.sh b/run-tests.sh index c4bffacda..2808e2af6 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -46,6 +46,7 @@ export JOBS=8 export JUNIT_REPORT_STACK=1 OS=$(uname) +ARCH=$(uname -m) # TODO(mlumish): Add electron tests @@ -87,7 +88,7 @@ if [ "$FAILED" = "true" ] then exit 1 else - if [ "$OS" = "Linux" ] + if [ "$OS" = "Linux" ] && [ "$ARCH" != "aarch64"] then # If we can't download the token file, just skip reporting coverage gsutil cp gs://grpc-testing-secrets/coveralls_credentials/grpc-node.rc /tmp || exit 0 diff --git a/test/aarch64/prepare_qemu.sh b/test/aarch64/prepare_qemu.sh new file mode 100755 index 000000000..f61320222 --- /dev/null +++ b/test/aarch64/prepare_qemu.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# +# Setup and configure qemu userspace emulator on kokoro worker so that we can seamlessly emulate processes running +# inside docker containers. + +set -ex + +# show pre-existing qemu registration +cat /proc/sys/fs/binfmt_misc/qemu-aarch64 + +# Kokoro ubuntu1604 workers have already qemu-user and qemu-user-static packages installed, but it's and old version that: +# * prints warning about some syscalls (e.g "qemu: Unsupported syscall: 278") +# * doesn't register with binfmt_misc with the persistent ("F") flag we need (see below) +# +# To overcome the above limitations, we use the https://github.com/multiarch/qemu-user-static +# docker image to provide a new enough version of qemu-user-static and register it with +# the desired binfmt_misc flags. The most important flag we need is "F" (set by "--persistent yes"), +# which allows the qemu-aarch64-static binary to be loaded eagerly at the time of registration with binfmt_misc. +# That way, we can emulate aarch64 binaries running inside docker containers transparently, without needing the emulator +# binary to be accessible from the docker image we're emulating. +# Note that on newer distributions (such as glinux), simply "apt install qemu-user-static" is sufficient +# to install qemu-user-static with the right flags. +docker run --rm --privileged multiarch/qemu-user-static:5.2.0-2 --reset --credential yes --persistent yes + +# Print current qemu reqistration to make sure everything is setup correctly. +cat /proc/sys/fs/binfmt_misc/qemu-aarch64 diff --git a/test/kokoro/linux_aarch64.cfg b/test/kokoro/linux_aarch64.cfg new file mode 100644 index 000000000..638748ab8 --- /dev/null +++ b/test/kokoro/linux_aarch64.cfg @@ -0,0 +1,24 @@ +# Copyright 2017 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/test/kokoro_linux_aarch64.sh" +timeout_mins: 60 +action { + define_artifacts { + regex: "github/grpc-node/reports/**/sponge_log.xml" + } +} diff --git a/test/kokoro_linux_aarch64.sh b/test/kokoro_linux_aarch64.sh new file mode 100755 index 000000000..8a4752c41 --- /dev/null +++ b/test/kokoro_linux_aarch64.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# Copyright 2021 The gRPC Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex +cd $(dirname $0)/.. + +test/aarch64/prepare_qemu.sh + +# better update submodules here. We could update the submodule when running +# under an emulator as well, but it comes with performance penalty. +git submodule update --init --recursive + +if [[ -t 0 ]]; then + DOCKER_TTY_ARGS="-it" +else + # The input device on kokoro is not a TTY, so -it does not work. + DOCKER_TTY_ARGS= +fi + +# the test command to run under an emulated aarch64 docker container. +# we only run tests for a single version of node, since tests under an emulator are significantly slower. +TEST_NODE_COMMAND="node_versions='8' ./run-tests.sh" + +# use an actual aarch64 docker image (with a real aarch64 node) to run build & test grpc-js under an emulator +# * mount the protobuf root as /work to be able to access the crosscompiled files +# * to avoid running the process inside docker as root (which can pollute the workspace with files owned by root), we force +# running under current user's UID and GID. To be able to do that, we need to provide a home directory for the user +# otherwise the UID would be homeless under the docker container (which can lead to various issues). For simplicity, +# we just run map the user's home to a throwaway temporary directory. +docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work arm64v8/node:8-buster bash -c "$TEST_NODE_COMMAND" From 2b8322ef90dd3e51159c7e1ededc0be19cb9d25d Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Mon, 10 May 2021 11:54:10 +0200 Subject: [PATCH 1429/1899] update aarch64 tests to test with node12 --- test/kokoro_linux_aarch64.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/kokoro_linux_aarch64.sh b/test/kokoro_linux_aarch64.sh index 8a4752c41..9dd6ad86a 100755 --- a/test/kokoro_linux_aarch64.sh +++ b/test/kokoro_linux_aarch64.sh @@ -31,7 +31,7 @@ fi # the test command to run under an emulated aarch64 docker container. # we only run tests for a single version of node, since tests under an emulator are significantly slower. -TEST_NODE_COMMAND="node_versions='8' ./run-tests.sh" +TEST_NODE_COMMAND="node_versions='12' ./run-tests.sh" # use an actual aarch64 docker image (with a real aarch64 node) to run build & test grpc-js under an emulator # * mount the protobuf root as /work to be able to access the crosscompiled files @@ -39,4 +39,4 @@ TEST_NODE_COMMAND="node_versions='8' ./run-tests.sh" # running under current user's UID and GID. To be able to do that, we need to provide a home directory for the user # otherwise the UID would be homeless under the docker container (which can lead to various issues). For simplicity, # we just run map the user's home to a throwaway temporary directory. -docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work arm64v8/node:8-buster bash -c "$TEST_NODE_COMMAND" +docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work arm64v8/node:12-buster bash -c "$TEST_NODE_COMMAND" From f009cd7b9fdbca41106078e2559669a24794390f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 May 2021 10:58:32 -0700 Subject: [PATCH 1430/1899] grpc-js: Look for ECONNRESET errors by code instead of errno --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 04fa4585a..f0e879203 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.0", + "version": "1.3.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 8fcc7065e..57693343f 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -589,7 +589,7 @@ export class Http2CallStream implements Call { * "Internal server error" message. */ details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; } else { - if (this.internalError.errno === os.constants.errno.ECONNRESET) { + if (this.internalError.code === 'ECONNRESET') { code = Status.UNAVAILABLE; details = this.internalError.message; } else { From 7de0d08e299a339a8b156ed56f508e76de35077a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 May 2021 14:30:25 -0700 Subject: [PATCH 1431/1899] grpc-js: Apply timeouts from service configs --- packages/grpc-js/src/call-stream.ts | 30 +++++++++++++++++++------ packages/grpc-js/src/channel.ts | 8 +++++++ packages/grpc-js/src/deadline-filter.ts | 24 ++++++++++++++++---- packages/grpc-js/src/filter-stack.ts | 6 +++++ packages/grpc-js/src/filter.ts | 5 +++++ packages/grpc-js/src/service-config.ts | 27 +++++++++++++++++----- 6 files changed, 84 insertions(+), 16 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 8fcc7065e..3a81cbe94 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -70,6 +70,17 @@ function getSystemErrorName(errno: number): string { export type Deadline = Date | number; +function getMinDeadline(deadlineList: Deadline[]): Deadline { + let minValue: number = Infinity; + for (const deadline of deadlineList) { + const deadlineMsecs = deadline instanceof Date ? deadline.getTime() : deadline; + if (deadlineMsecs < minValue) { + minValue = deadlineMsecs; + } + } + return minValue; +} + export interface CallStreamOptions { deadline: Deadline; flags: number; @@ -235,6 +246,8 @@ export class Http2CallStream implements Call { private internalError: SystemError | null = null; + private configDeadline: Deadline = Infinity; + constructor( private readonly methodName: string, private readonly channel: ChannelImplementation, @@ -675,15 +688,14 @@ export class Http2CallStream implements Call { } getDeadline(): Deadline { + const deadlineList = [this.options.deadline]; if (this.options.parentCall && this.options.flags & Propagate.DEADLINE) { - const parentDeadline = this.options.parentCall.getDeadline(); - const selfDeadline = this.options.deadline; - const parentDeadlineMsecs = parentDeadline instanceof Date ? parentDeadline.getTime() : parentDeadline; - const selfDeadlineMsecs = selfDeadline instanceof Date ? selfDeadline.getTime() : selfDeadline; - return Math.min(parentDeadlineMsecs, selfDeadlineMsecs); - } else { - return this.options.deadline; + deadlineList.push(this.options.parentCall.getDeadline()); + } + if (this.configDeadline) { + deadlineList.push(this.configDeadline); } + return getMinDeadline(deadlineList); } getCredentials(): CallCredentials { @@ -710,6 +722,10 @@ export class Http2CallStream implements Call { return this.options.host; } + setConfigDeadline(configDeadline: Deadline) { + this.configDeadline = configDeadline; + } + startRead() { /* If the stream has ended with an error, we should not emit any more * messages and we should communicate that the stream has ended */ diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 41715c41e..88b1d4998 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -523,6 +523,14 @@ export class ChannelImplementation implements Channel { } else { const callConfig = this.configSelector(stream.getMethod(), metadata); if (callConfig.status === Status.OK) { + if (callConfig.methodConfig.timeout) { + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + callConfig.methodConfig.timeout.seconds); + deadline.setMilliseconds(deadline.getMilliseconds() + callConfig.methodConfig.timeout.nanos / 1_000_000); + stream.setConfigDeadline(deadline); + // Refreshing the filters makes the deadline filter pick up the new deadline + stream.filterStack.refresh(); + } this.tryPick(stream, metadata, callConfig); } else { stream.cancelWithStatus(callConfig.status, "Failed to route call to method " + stream.getMethod()); diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index 99bfa2bec..afc015546 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -42,30 +42,41 @@ function getDeadline(deadline: number) { export class DeadlineFilter extends BaseFilter implements Filter { private timer: NodeJS.Timer | null = null; - private deadline: number; + private deadline: number = Infinity; constructor( private readonly channel: Channel, private readonly callStream: Call ) { super(); - const callDeadline = callStream.getDeadline(); + this.retreiveDeadline(); + this.runTimer(); + } + + private retreiveDeadline() { + const callDeadline = this.callStream.getDeadline(); if (callDeadline instanceof Date) { this.deadline = callDeadline.getTime(); } else { this.deadline = callDeadline; } + } + + private runTimer() { + if (this.timer) { + clearTimeout(this.timer); + } const now: number = new Date().getTime(); let timeout = this.deadline - now; if (timeout <= 0) { process.nextTick(() => { - callStream.cancelWithStatus( + this.callStream.cancelWithStatus( Status.DEADLINE_EXCEEDED, 'Deadline exceeded' ); }); } else if (this.deadline !== Infinity) { this.timer = setTimeout(() => { - callStream.cancelWithStatus( + this.callStream.cancelWithStatus( Status.DEADLINE_EXCEEDED, 'Deadline exceeded' ); @@ -74,6 +85,11 @@ export class DeadlineFilter extends BaseFilter implements Filter { } } + refresh() { + this.retreiveDeadline(); + this.runTimer(); + } + async sendMetadata(metadata: Promise) { if (this.deadline === Infinity) { return metadata; diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index a656a4099..4fd888549 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -71,6 +71,12 @@ export class FilterStack implements Filter { return result; } + + refresh(): void { + for (const filter of this.filters) { + filter.refresh(); + } + } } export class FilterStackFactory implements FilterFactory { diff --git a/packages/grpc-js/src/filter.ts b/packages/grpc-js/src/filter.ts index c1e412ae5..eb67bd32e 100644 --- a/packages/grpc-js/src/filter.ts +++ b/packages/grpc-js/src/filter.ts @@ -32,6 +32,8 @@ export interface Filter { receiveMessage(message: Promise): Promise; receiveTrailers(status: StatusObject): StatusObject; + + refresh(): void; } export abstract class BaseFilter implements Filter { @@ -54,6 +56,9 @@ export abstract class BaseFilter implements Filter { receiveTrailers(status: StatusObject): StatusObject { return status; } + + refresh(): void { + } } export interface FilterFactory { diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index ed225e087..efc09f9c4 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -34,10 +34,15 @@ export interface MethodConfigName { method?: string; } +export interface Duration { + seconds: number; + nanos: number; +} + export interface MethodConfig { name: MethodConfigName[]; waitForReady?: boolean; - timeout?: string; + timeout?: Duration; maxRequestBytes?: number; maxResponseBytes?: number; } @@ -101,13 +106,25 @@ function validateMethodConfig(obj: any): MethodConfig { result.waitForReady = obj.waitForReady; } if ('timeout' in obj) { - if ( - !(typeof obj.timeout === 'string') || - !TIMEOUT_REGEX.test(obj.timeout) + if (typeof obj.timeout === 'object') { + if (!('seconds' in obj.timeout) || !(typeof obj.timeout.seconds === 'number')) { + throw new Error('Invalid method config: invalid timeout.seconds'); + } + if (!('nanos' in obj.timeout) || !(typeof obj.timeout.nanos === 'number')) { + throw new Error('Invalid method config: invalid timeout.nanos'); + } + result.timeout = obj.timeout; + } else if ( + (typeof obj.timeout === 'string') && TIMEOUT_REGEX.test(obj.timeout) ) { + const timeoutParts = obj.timeout.substring(0, obj.timeout.length - 1).split('.'); + result.timeout = { + seconds: timeoutParts[0] | 0, + nanos: (timeoutParts[1] ?? 0) | 0 + } + } else { throw new Error('Invalid method config: invalid timeout'); } - result.timeout = obj.timeout; } if ('maxRequestBytes' in obj) { if (typeof obj.maxRequestBytes !== 'number') { From e3106b99ca9fcebf8db9eedf9cc2a044d82f551c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 May 2021 14:38:02 -0700 Subject: [PATCH 1432/1899] Don't query the config selector for calls that have ended --- packages/grpc-js/src/channel.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 88b1d4998..8b2658f37 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -509,6 +509,11 @@ export class ChannelImplementation implements Channel { } private tryGetConfig(stream: Http2CallStream, metadata: Metadata) { + if (stream.getStatus() !== null) { + /* If the stream has a status, it has already finished and we don't need + * to take any more actions on it. */ + return; + } if (this.configSelector === null) { /* This branch will only be taken at the beginning of the channel's life, * before the resolver ever returns a result. So, the From bf7d2007917f76bd7af76725043d8ba1f1df981e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 May 2021 10:36:06 -0700 Subject: [PATCH 1433/1899] grpc-js: Change function check to handle async functions --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/client.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f0e879203..6bce0ebdd 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.1", + "version": "1.3.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 850e839cc..204be9017 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -56,7 +56,7 @@ const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); function isFunction(arg: Metadata | CallOptions | UnaryCallback | undefined): arg is UnaryCallback{ - return Object.prototype.toString.call(arg) === '[object Function]' + return typeof arg === 'function'; } export interface UnaryCallback { From f4f1d54031b3788687b21901f92547f42a993866 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 17 May 2021 11:07:45 -0700 Subject: [PATCH 1434/1899] grpc-js-xds: Propagate timeouts from xDS responses to method config --- packages/grpc-js-xds/src/resolver-xds.ts | 45 ++++++++++++++++++++++-- packages/grpc-js-xds/src/route-action.ts | 16 +++++++-- packages/grpc-js/src/experimental.ts | 2 +- 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index a9ee1af7d..892cf5711 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -40,6 +40,8 @@ import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluste import { ExactValueMatcher, Fraction, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action'; import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from './resources'; +import Duration = experimental.Duration; +import { Duration__Output } from './generated/google/protobuf/Duration'; const TRACER_NAME = 'xds_resolver'; @@ -187,6 +189,20 @@ function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { return new FullMatcher(pathMatcher, headerMatchers, runtimeFraction); } +/** + * Convert a Duration protobuf message object to a Duration object as used in + * the ServiceConfig definition. The difference is that the protobuf message + * defines seconds as a long, which is represented as a string in JavaScript, + * and the one used in the service config defines it as a number. + * @param duration + */ +function protoDurationToDuration(duration: Duration__Output): Duration { + return { + seconds: Number.parseInt(duration.seconds), + nanos: duration.nanos + } +} + class XdsResolver implements Resolver { private hasReportedSuccess = false; @@ -203,6 +219,8 @@ class XdsResolver implements Resolver { private clusterRefcounts = new Map(); + private latestDefaultTimeout: Duration | undefined = undefined; + constructor( private target: GrpcUri, private listener: ResolverListener, @@ -211,6 +229,12 @@ class XdsResolver implements Resolver { this.ldsWatcher = { onValidUpdate: (update: Listener__Output) => { const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, update.api_listener!.api_listener!.value); + const defaultTimeout = httpConnectionManager.common_http_protocol_options?.idle_timeout; + if (defaultTimeout === undefined) { + this.latestDefaultTimeout = undefined; + } else { + this.latestDefaultTimeout = protoDurationToDuration(defaultTimeout); + } switch (httpConnectionManager.route_specifier) { case 'rds': { const routeConfigName = httpConnectionManager.rds!.route_config_name; @@ -295,13 +319,28 @@ class XdsResolver implements Resolver { const matchList: {matcher: Matcher, action: RouteAction}[] = []; for (const route of virtualHost.routes) { let routeAction: RouteAction; + let timeout: Duration | undefined; + /* For field prioritization see + * https://github.com/grpc/proposal/blob/master/A31-xds-timeout-support-and-config-selector.md#supported-fields + */ + if (route.route?.max_stream_duration?.grpc_timeout_header_max) { + timeout = protoDurationToDuration(route.route.max_stream_duration.grpc_timeout_header_max); + } else if (route.route?.max_stream_duration?.max_stream_duration) { + timeout = protoDurationToDuration(route.route.max_stream_duration.max_stream_duration); + } else { + timeout = this.latestDefaultTimeout; + } + // "A value of 0 indicates the application's deadline is used without modification." + if (timeout?.seconds === 0 && timeout.nanos === 0) { + timeout = undefined; + } switch (route.route!.cluster_specifier) { case 'cluster_header': continue; case 'cluster':{ const cluster = route.route!.cluster!; allConfigClusters.add(cluster); - routeAction = new SingleClusterRouteAction(cluster); + routeAction = new SingleClusterRouteAction(cluster, timeout); break; } case 'weighted_clusters': { @@ -310,7 +349,7 @@ class XdsResolver implements Resolver { allConfigClusters.add(clusterWeight.name); weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0}); } - routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100); + routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100, timeout); } } const routeMatcher = getPredicateForMatcher(route.match!); @@ -343,7 +382,7 @@ class XdsResolver implements Resolver { this.unrefCluster(clusterName); } return { - methodConfig: {name: []}, + methodConfig: {name: [], timeout: action.getTimeout()}, onCommitted: onCommitted, pickInformation: {cluster: clusterName}, status: status.OK diff --git a/packages/grpc-js-xds/src/route-action.ts b/packages/grpc-js-xds/src/route-action.ts index 4ba2b5908..b43874d8f 100644 --- a/packages/grpc-js-xds/src/route-action.ts +++ b/packages/grpc-js-xds/src/route-action.ts @@ -14,13 +14,17 @@ * limitations under the License. */ +import { experimental } from '@grpc/grpc-js'; +import Duration = experimental.Duration; + export interface RouteAction { toString(): string; getCluster(): string; + getTimeout(): Duration | undefined; } export class SingleClusterRouteAction implements RouteAction { - constructor(private cluster: string) {} + constructor(private cluster: string, private timeout: Duration | undefined) {} getCluster() { return this.cluster; @@ -29,6 +33,10 @@ export class SingleClusterRouteAction implements RouteAction { toString() { return 'SingleCluster(' + this.cluster + ')'; } + + getTimeout() { + return this.timeout; + } } export interface WeightedCluster { @@ -46,7 +54,7 @@ export class WeightedClusterRouteAction implements RouteAction { * The weighted cluster choices represented as a CDF */ private clusterChoices: ClusterChoice[]; - constructor(private clusters: WeightedCluster[], private totalWeight: number) { + constructor(private clusters: WeightedCluster[], private totalWeight: number, private timeout: Duration | undefined) { this.clusterChoices = []; let lastNumerator = 0; for (const clusterWeight of clusters) { @@ -69,4 +77,8 @@ export class WeightedClusterRouteAction implements RouteAction { toString() { return 'WeightedCluster(' + this.clusters.map(({name, weight}) => '(' + name + ':' + weight + ')').join(', ') + ')'; } + + getTimeout() { + return this.timeout; + } } \ No newline at end of file diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index f62838c12..cf84ba6b8 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -1,7 +1,7 @@ export { trace } from './logging'; export { Resolver, ResolverListener, registerResolver, ConfigSelector } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; -export { ServiceConfig } from './service-config'; +export { ServiceConfig, Duration } from './service-config'; export { BackoffTimeout } from './backoff-timeout'; export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig } from './load-balancer'; export { SubchannelAddress, subchannelAddressToString } from './subchannel'; From f5b9e7bab15dcd65aff3c66aa8e8ad6f476621bc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 17 May 2021 14:52:45 -0700 Subject: [PATCH 1435/1899] grpc-js-xds: Add circuit breaking functionality --- packages/grpc-js-xds/src/load-balancer-eds.ts | 70 ++++++++++++++++--- packages/grpc-js-xds/src/xds-client.ts | 9 +++ 2 files changed, 69 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index ae9a781bd..76bdd6655 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -15,7 +15,7 @@ * */ -import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental } from '@grpc/grpc-js'; +import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, StatusObject } from '@grpc/grpc-js'; import { getSingletonXdsClient, XdsClient, XdsClusterDropStats } from './xds-client'; import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint/v3/ClusterLoadAssignment'; import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; @@ -34,6 +34,10 @@ import { validateLoadBalancingConfig } from '@grpc/grpc-js/build/src/experimenta import { WeightedTarget, WeightedTargetLoadBalancingConfig } from './load-balancer-weighted-target'; import { LrsLoadBalancingConfig } from './load-balancer-lrs'; import { Watcher } from './xds-stream-state/xds-stream-state'; +import Filter = experimental.Filter; +import BaseFilter = experimental.BaseFilter; +import FilterFactory = experimental.FilterFactory; +import CallStream = experimental.CallStream; const TRACER_NAME = 'eds_balancer'; @@ -47,7 +51,10 @@ function localityToName(locality: Locality__Output) { return `{region=${locality.region},zone=${locality.zone},sub_zone=${locality.sub_zone}}`; } +const DEFAULT_MAX_CONCURRENT_REQUESTS = 1024; + export class EdsLoadBalancingConfig implements LoadBalancingConfig { + private maxConcurrentRequests: number; getLoadBalancerName(): string { return TYPE_NAME; } @@ -55,7 +62,8 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { const jsonObj: {[key: string]: any} = { cluster: this.cluster, locality_picking_policy: this.localityPickingPolicy.map(policy => policy.toJsonObject()), - endpoint_picking_policy: this.endpointPickingPolicy.map(policy => policy.toJsonObject()) + endpoint_picking_policy: this.endpointPickingPolicy.map(policy => policy.toJsonObject()), + max_concurrent_requests: this.maxConcurrentRequests }; if (this.edsServiceName !== undefined) { jsonObj.eds_service_name = this.edsServiceName; @@ -68,8 +76,8 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { }; } - constructor(private cluster: string, private localityPickingPolicy: LoadBalancingConfig[], private endpointPickingPolicy: LoadBalancingConfig[], private edsServiceName?: string, private lrsLoadReportingServerName?: string) { - + constructor(private cluster: string, private localityPickingPolicy: LoadBalancingConfig[], private endpointPickingPolicy: LoadBalancingConfig[], private edsServiceName?: string, private lrsLoadReportingServerName?: string, maxConcurrentRequests?: number) { + this.maxConcurrentRequests = maxConcurrentRequests ?? DEFAULT_MAX_CONCURRENT_REQUESTS; } getCluster() { @@ -92,6 +100,10 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { return this.lrsLoadReportingServerName; } + getMaxConcurrentRequests() { + return this.maxConcurrentRequests; + } + static createFromJson(obj: any): EdsLoadBalancingConfig { if (!('cluster' in obj && typeof obj.cluster === 'string')) { throw new Error('eds config must have a string field cluster'); @@ -108,7 +120,28 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { if ('lrs_load_reporting_server_name' in obj && (!obj.lrs_load_reporting_server_name === undefined || typeof obj.lrs_load_reporting_server_name === 'string')) { throw new Error('eds config lrs_load_reporting_server_name must be a string if provided'); } - return new EdsLoadBalancingConfig(obj.cluster, obj.locality_picking_policy.map(validateLoadBalancingConfig), obj.endpoint_picking_policy.map(validateLoadBalancingConfig), obj.eds_service_name, obj.lrs_load_reporting_server_name); + if ('max_concurrent_requests' in obj && (!obj.max_concurrent_requests === undefined || typeof obj.max_concurrent_requests === 'number')) { + throw new Error('eds config max_concurrent_requests must be a number if provided'); + } + return new EdsLoadBalancingConfig(obj.cluster, obj.locality_picking_policy.map(validateLoadBalancingConfig), obj.endpoint_picking_policy.map(validateLoadBalancingConfig), obj.eds_service_name, obj.lrs_load_reporting_server_name, obj.max_concurrent_requests); + } +} + +class CallEndTrackingFilter extends BaseFilter implements Filter { + constructor(private onCallEnd: () => void) { + super(); + } + receiveTrailers(status: StatusObject) { + this.onCallEnd(); + return status; + } +} + +class CallTrackingFilterFactory implements FilterFactory { + constructor(private onCallEnd: () => void) {} + + createFilter(callStream: CallStream) { + return new CallEndTrackingFilter(this.onCallEnd); } } @@ -149,6 +182,8 @@ export class EdsLoadBalancer implements LoadBalancer { private clusterDropStats: XdsClusterDropStats | null = null; + private concurrentRequests: number = 0; + constructor(private readonly channelControlHelper: ChannelControlHelper) { this.childBalancer = new ChildLoadBalancerHandler({ createSubchannel: (subchannelAddress, subchannelArgs) => @@ -171,7 +206,11 @@ export class EdsLoadBalancer implements LoadBalancer { if (dropCategory === null) { return originalPicker.pick(pickArgs); } else { - this.clusterDropStats?.addCallDropped(dropCategory); + if (dropCategory === true) { + this.clusterDropStats?.addUncategorizedCallDropped(); + } else { + this.clusterDropStats?.addCallDropped(dropCategory); + } return { pickResultType: PickResultType.DROP, status: { @@ -180,8 +219,12 @@ export class EdsLoadBalancer implements LoadBalancer { metadata: new Metadata(), }, subchannel: null, - extraFilterFactory: null, - onCallStarted: null, + extraFilterFactory: new CallTrackingFilterFactory(() => { + this.concurrentRequests -= 1; + }), + onCallStarted: () => { + this.concurrentRequests += 1; + }, }; } }, @@ -218,12 +261,19 @@ export class EdsLoadBalancer implements LoadBalancer { /** * Check whether a single call should be dropped according to the current * policy, based on randomly chosen numbers. Returns the drop category if - * the call should be dropped, and null otherwise. + * the call should be dropped, and null otherwise. true is a valid + * output, as a sentinel value indicating a drop with no category. */ - private checkForDrop(): string | null { + private checkForDrop(): string | true | null { if (!this.latestEdsUpdate?.policy) { return null; } + if (!this.lastestConfig) { + return null; + } + if (this.concurrentRequests >= this.lastestConfig.getMaxConcurrentRequests()) { + return true; + } /* The drop_overloads policy is a list of pairs of category names and * probabilities. For each one, if the random number is within that * probability range, we drop the call citing that category. Otherwise, the diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index adc54ed45..ddca9284f 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -114,6 +114,7 @@ function localityEqual( } export interface XdsClusterDropStats { + addUncategorizedCallDropped(): void; addCallDropped(category: string): void; } @@ -158,6 +159,7 @@ interface ClusterLocalityStats { interface ClusterLoadReport { callsDropped: Map; + uncategorizedCallsDropped: number; localityStats: ClusterLocalityStats[]; intervalStart: [number, number]; } @@ -195,6 +197,7 @@ class ClusterLoadReportMap { } const newStats: ClusterLoadReport = { callsDropped: new Map(), + uncategorizedCallsDropped: 0, localityStats: [], intervalStart: process.hrtime(), }; @@ -871,8 +874,10 @@ export class XdsClient { totalDroppedRequests += count; } } + totalDroppedRequests += stats.uncategorizedCallsDropped; // Clear out dropped call stats after sending them stats.callsDropped.clear(); + stats.uncategorizedCallsDropped = 0; const interval = process.hrtime(stats.intervalStart); stats.intervalStart = process.hrtime(); // Skip clusters with 0 requests @@ -957,6 +962,7 @@ export class XdsClient { trace('addClusterDropStats(lrsServer=' + lrsServer + ', clusterName=' + clusterName + ', edsServiceName=' + edsServiceName + ')'); if (lrsServer !== '') { return { + addUncategorizedCallDropped: () => {}, addCallDropped: (category) => {}, }; } @@ -965,6 +971,9 @@ export class XdsClient { edsServiceName ); return { + addUncategorizedCallDropped: () => { + clusterStats.uncategorizedCallsDropped += 1; + }, addCallDropped: (category) => { const prevCount = clusterStats.callsDropped.get(category) ?? 0; clusterStats.callsDropped.set(category, prevCount + 1); From bdc8d2de9db276f2adec7ccf6c432bcf8425215f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 19 May 2021 13:19:36 -0700 Subject: [PATCH 1436/1899] Don't clean after testing on each Node version --- run-tests.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/run-tests.sh b/run-tests.sh index 2808e2af6..03fd970b5 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -71,7 +71,6 @@ do node -e 'process.exit(process.version.startsWith("v'$version'") ? 0 : -1)' # Install dependencies and link packages together. - ./node_modules/.bin/gulp cleanAll ./node_modules/.bin/gulp setup # npm test calls nyc gulp test From d51551f6d71b05fa6934045022a961bfc1d4d1b4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 17 May 2021 11:08:54 -0700 Subject: [PATCH 1437/1899] grpc-js-xds: Add support for timeout xDS interop test Add more logging --- .../grpc-js-xds/interop/xds-interop-client.ts | 45 ++++++++-- packages/grpc-js-xds/scripts/xds.sh | 4 +- packages/grpc-js-xds/src/route-action.ts | 22 ++++- packages/grpc-js/src/metadata.ts | 12 +++ packages/grpc-js/test/test-deadline.ts | 90 +++++++++++++++++++ test/kokoro/xds-interop.cfg | 2 +- test/kokoro/xds-v3-interop.cfg | 2 +- 7 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 packages/grpc-js/test/test-deadline.ts diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 5f32831c1..f6beccbf0 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -197,29 +197,44 @@ let anyCallSucceeded = false; const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { stats_per_method: { - EmptyCall: { + EMPTY_CALL: { rpcs_started: 0, result: {} }, - UnaryCall: { + UNARY_CALL: { rpcs_started: 0, result: {} } } }; +const callTimeHistogram: {[callType: string]: {[status: number]: number[]}} = { + UnaryCall: {}, + EmptyCall: {} +} + function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { - const callTypeStats = accumulatedStats.stats_per_method![type]; + const callTypeStats = accumulatedStats.stats_per_method![callTypeEnumMapReverse[type]]; callTypeStats.rpcs_started! += 1; const notifier = callStatsTracker.startCall(); let gotMetadata: boolean = false; let hostname: string | null = null; let completed: boolean = false; let completedWithError: boolean = false; + const startTime = process.hrtime(); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + currentConfig.timeoutSec); const callback = (error: grpc.ServiceError | undefined, value: Empty__Output | undefined) => { const statusCode = error?.code ?? grpc.status.OK; + const duration = process.hrtime(startTime); + if (!callTimeHistogram[type][statusCode]) { + callTimeHistogram[type][statusCode] = []; + } + if (callTimeHistogram[type][statusCode][duration[0]]) { + callTimeHistogram[type][statusCode][duration[0]] += 1; + } else { + callTimeHistogram[type][statusCode][duration[0]] = 1; + } callTypeStats.result![statusCode] = (callTypeStats.result![statusCode] ?? 0) + 1; if (error) { if (failOnFailedRpcs && anyCallSucceeded) { @@ -269,18 +284,27 @@ const callTypeEnumMap = { 'UNARY_CALL': 'UnaryCall' as CallType }; +const callTypeEnumMapReverse = { + 'EmptyCall': 'EMPTY_CALL', + 'UnaryCall': 'UNARY_CALL' +} + +const DEFAULT_TIMEOUT_SEC = 20; + function main() { const argv = yargs .string(['fail_on_failed_rpcs', 'server', 'stats_port', 'rpc', 'metadata']) - .number(['num_channels', 'qps']) + .number(['num_channels', 'qps', 'rpc_timeout_sec']) .demandOption(['server', 'stats_port']) .default('num_channels', 1) .default('qps', 1) .default('rpc', 'UnaryCall') .default('metadata', '') + .default('rpc_timeout_sec', DEFAULT_TIMEOUT_SEC) .argv; console.log('Starting xDS interop client. Args: ', argv); currentConfig.callTypes = argv.rpc.split(',').filter(value => value === 'EmptyCall' || value === 'UnaryCall') as CallType[]; + currentConfig.timeoutSec = argv.rpc_timeout_sec; for (const item of argv.metadata.split(',')) { const [method, key, value] = item.split(':'); if (value === undefined) { @@ -316,23 +340,30 @@ function main() { }); }, GetClientAccumulatedStats: (call, callback) => { + console.log(`Sending accumulated stats response: ${JSON.stringify(accumulatedStats)}`); + console.log(`Call durations: ${JSON.stringify(callTimeHistogram, undefined, 2)}`); callback(null, accumulatedStats); } } const xdsUpdateClientConfigureServiceImpl: XdsUpdateClientConfigureServiceHandlers = { Configure: (call, callback) => { + console.log('Received new client configuration: ' + JSON.stringify(call.request, undefined, 2)); const callMetadata = { EmptyCall: new grpc.Metadata(), UnaryCall: new grpc.Metadata() - } + }; for (const metadataItem of call.request.metadata) { callMetadata[callTypeEnumMap[metadataItem.type]].add(metadataItem.key, metadataItem.value); } currentConfig.callTypes = call.request.types.map(value => callTypeEnumMap[value]); currentConfig.metadata = callMetadata; - currentConfig.timeoutSec = call.request.timeout_sec - console.log('Received new client configuration: ' + JSON.stringify(currentConfig, undefined, 2)); + if (call.request.timeout_sec > 0) { + currentConfig.timeoutSec = call.request.timeout_sec; + } else { + currentConfig.timeoutSec = DEFAULT_TIMEOUT_SEC; + } + console.log('Updated to new client configuration: ' + JSON.stringify(currentConfig, undefined, 2)); callback(null, {}); } } diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 9008b9731..68225faef 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -52,9 +52,9 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all,path_matching,header_matching" \ + --test_case="all,timeout" \ --project_id=grpc-testing \ - --source_image=projects/grpc-testing/global/images/xds-test-server-2 \ + --source_image=projects/grpc-testing/global/images/xds-test-server-4 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ diff --git a/packages/grpc-js-xds/src/route-action.ts b/packages/grpc-js-xds/src/route-action.ts index b43874d8f..5574bcd91 100644 --- a/packages/grpc-js-xds/src/route-action.ts +++ b/packages/grpc-js-xds/src/route-action.ts @@ -23,6 +23,15 @@ export interface RouteAction { getTimeout(): Duration | undefined; } +function durationToLogString(duration: Duration) { + const millis = Math.floor(duration.nanos / 1_000_000); + if (millis > 0) { + return duration.seconds + '.' + millis; + } else { + return '' + duration.seconds; + } +} + export class SingleClusterRouteAction implements RouteAction { constructor(private cluster: string, private timeout: Duration | undefined) {} @@ -31,7 +40,11 @@ export class SingleClusterRouteAction implements RouteAction { } toString() { - return 'SingleCluster(' + this.cluster + ')'; + if (this.timeout) { + return 'SingleCluster(' + this.cluster + ', ' + 'timeout=' + durationToLogString(this.timeout) + 's)'; + } else { + return 'SingleCluster(' + this.cluster + ')'; + } } getTimeout() { @@ -75,7 +88,12 @@ export class WeightedClusterRouteAction implements RouteAction { } toString() { - return 'WeightedCluster(' + this.clusters.map(({name, weight}) => '(' + name + ':' + weight + ')').join(', ') + ')'; + const clusterListString = this.clusters.map(({name, weight}) => '(' + name + ':' + weight + ')').join(', ') + if (this.timeout) { + return 'WeightedCluster(' + clusterListString + ', ' + 'timeout=' + durationToLogString(this.timeout) + 's)'; + } else { + return 'WeightedCluster(' + clusterListString + ')'; + } } getTimeout() { diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 4947bf0ad..bc66012ce 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -242,6 +242,18 @@ export class Metadata { return this.internalRepr; } + /** + * This modifies the behavior of JSON.stringify to show an object + * representation of the metadata map. + */ + toJSON() { + const result: {[key: string]: MetadataValue[]} = {}; + for (const [key, values] of this.internalRepr.entries()) { + result[key] = values; + } + return result; + } + /** * Returns a new Metadata object based fields in a given IncomingHttpHeaders * object. diff --git a/packages/grpc-js/test/test-deadline.ts b/packages/grpc-js/test/test-deadline.ts new file mode 100644 index 000000000..bb6b3ba9b --- /dev/null +++ b/packages/grpc-js/test/test-deadline.ts @@ -0,0 +1,90 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; + +import * as grpc from '../src'; +import { experimental } from '../src'; +import { ServerCredentials } from '../src'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { loadProtoFile } from './common'; +import ServiceConfig = experimental.ServiceConfig; + +const clientInsecureCreds = grpc.credentials.createInsecure(); +const serverInsecureCreds = ServerCredentials.createInsecure(); + +const TIMEOUT_SERVICE_CONFIG: ServiceConfig = { + loadBalancingConfig: [], + methodConfig: [{ + name: [ + {service: 'TestService'} + ], + timeout: { + seconds: 1, + nanos: 0 + } + }] +}; + +describe('Client with configured timeout', () => { + let server: grpc.Server; + let Client: ServiceClientConstructor; + let client: ServiceClient; + + before(done => { + Client = loadProtoFile(__dirname + '/fixtures/test_service.proto').TestService as ServiceClientConstructor; + server = new grpc.Server(); + server.addService(Client.service, { + unary: () => {}, + clientStream: () => {}, + serverStream: () => {}, + bidiStream: () => {} + }); + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + done(error); + return; + } + server.start(); + client = new Client(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(TIMEOUT_SERVICE_CONFIG)}); + done(); + }); + }); + + after(done => { + client.close(); + server.tryShutdown(done); + }); + + it('Should end calls without explicit deadline with DEADLINE_EXCEEDED', done => { + client.unary({}, (error: grpc.ServiceError, value: unknown) =>{ + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); + + it('Should end calls with a long explicit deadline with DEADLINE_EXCEEDED', done => { + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 20); + client.unary({}, (error: grpc.ServiceError, value: unknown) =>{ + assert(error); + assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); + done(); + }); + }); +}); \ No newline at end of file diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 16a7dc7dc..a615d0530 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +timeout_mins: 180 action { define_artifacts { regex: "github/grpc/reports/**" diff --git a/test/kokoro/xds-v3-interop.cfg b/test/kokoro/xds-v3-interop.cfg index d7ffa8fab..4480f1590 100644 --- a/test/kokoro/xds-v3-interop.cfg +++ b/test/kokoro/xds-v3-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds-v3.sh" -timeout_mins: 120 +timeout_mins: 180 action { define_artifacts { regex: "github/grpc/reports/**" From ec7c819181bf24770e010e81378293dea6d799e5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 May 2021 10:30:28 -0700 Subject: [PATCH 1438/1899] grpc-js-xds: Enable circuit breaking test --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 68225faef..66fe4d568 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -52,7 +52,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all,timeout" \ + --test_case="all,timeout,circuit_breaking" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From 42d016d979c28ea288923c2b4a6a9426b8d89fd9 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Fri, 21 May 2021 10:22:14 +0200 Subject: [PATCH 1439/1899] workaround "key too small" problem in aarch64 tests --- test/kokoro_linux_aarch64.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/kokoro_linux_aarch64.sh b/test/kokoro_linux_aarch64.sh index 9dd6ad86a..508881e5f 100755 --- a/test/kokoro_linux_aarch64.sh +++ b/test/kokoro_linux_aarch64.sh @@ -39,4 +39,8 @@ TEST_NODE_COMMAND="node_versions='12' ./run-tests.sh" # running under current user's UID and GID. To be able to do that, we need to provide a home directory for the user # otherwise the UID would be homeless under the docker container (which can lead to various issues). For simplicity, # we just run map the user's home to a throwaway temporary directory. -docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work arm64v8/node:12-buster bash -c "$TEST_NODE_COMMAND" +# TODO(jtattermusch): we're using arm64v8/node:12-stretch instead of arm64v8/node:12-buster because the buster-based image +# has a newer version of ssl that considers some of the ssl keys used for testing too short, making the tests +# fails with "error:140AB18F:SSL routines:SSL_CTX_use_certificate:ee key too small". +# See https://github.com/grpc/grpc-node/issues/1795 +docker run $DOCKER_TTY_ARGS --rm --user "$(id -u):$(id -g)" -e "HOME=/home/fake-user" -v "$(mktemp -d):/home/fake-user" -v "$(pwd)":/work -w /work arm64v8/node:12-stretch bash -c "$TEST_NODE_COMMAND" From accc82fd111e75685b0631f0aa411490032608ca Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Tue, 1 Jun 2021 14:56:54 +0200 Subject: [PATCH 1440/1899] increase timeout for tests that timeout under emulator --- test/api/interop_extra_test.js | 6 ++++++ test/api/interop_sanity_test.js | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index f8db35b38..319ccb536 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -197,6 +197,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); describe('max message size', function() { + // with the default timeout the test times out under aarch64 emulator + this.timeout(6000); // A size that is larger than the default limit const largeMessageSize = 8 * 1024 * 1024; const largeMessage = Buffer.alloc(largeMessageSize); @@ -238,6 +240,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); describe('with a client with no message size limits', function() { + // with the default timeout the test times out under aarch64 emulator + this.timeout(6000); let unrestrictedClient; before(function() { const ca_path = path.join(__dirname, '../data/ca.pem'); @@ -283,6 +287,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); describe('with a server with message size limits and a client without limits', function() { + // with the default timeout the test times out under aarch64 emulator + this.timeout(6000); let restrictedServer; let restrictedServerClient; let restrictedServerClient2; diff --git a/test/api/interop_sanity_test.js b/test/api/interop_sanity_test.js index 995650e20..c1e5d92b5 100644 --- a/test/api/interop_sanity_test.js +++ b/test/api/interop_sanity_test.js @@ -48,7 +48,8 @@ var childExecArgv = []; describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { describe('Interop tests', function() { - this.timeout(4000); + // with the default timeout the test times out under aarch64 emulator + this.timeout(10000); before(function(done) { for (let arg of process.argv) { if (arg.startsWith('--require=')) { From 43a3bad54903bf85dd44ad2bc2e985c97942fa34 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 May 2021 10:31:00 -0700 Subject: [PATCH 1441/1899] Fix circuit breaking functionality --- .../grpc-js-xds/interop/xds-interop-client.ts | 32 +++++++++++++-- packages/grpc-js-xds/src/load-balancer-cds.ts | 8 +++- packages/grpc-js-xds/src/load-balancer-eds.ts | 41 ++++++++++++------- 3 files changed, 63 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index f6beccbf0..a414ffe7f 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -196,6 +196,18 @@ const currentConfig: ClientConfiguration = { let anyCallSucceeded = false; const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { + num_rpcs_started_by_method: { + EMPTY_CALL: 0, + UNARY_CALL: 0 + }, + num_rpcs_succeeded_by_method: { + EMPTY_CALL: 0, + UNARY_CALL: 0 + }, + num_rpcs_failed_by_method: { + EMPTY_CALL: 0, + UNARY_CALL: 0 + }, stats_per_method: { EMPTY_CALL: { rpcs_started: 0, @@ -208,14 +220,28 @@ const accumulatedStats: LoadBalancerAccumulatedStatsResponse = { } }; +function addAccumulatedCallStarted(callName: string) { + accumulatedStats.stats_per_method![callName].rpcs_started! += 1; + accumulatedStats.num_rpcs_started_by_method![callName] += 1; +} + +function addAccumulatedCallEnded(callName: string, result: grpc.status) { + accumulatedStats.stats_per_method![callName].result![result] = (accumulatedStats.stats_per_method![callName].result![result] ?? 0) + 1; + if (result === grpc.status.OK) { + accumulatedStats.num_rpcs_succeeded_by_method![callName] += 1; + } else { + accumulatedStats.num_rpcs_failed_by_method![callName] += 1; + } +} + const callTimeHistogram: {[callType: string]: {[status: number]: number[]}} = { UnaryCall: {}, EmptyCall: {} } function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { - const callTypeStats = accumulatedStats.stats_per_method![callTypeEnumMapReverse[type]]; - callTypeStats.rpcs_started! += 1; + const callEnumName = callTypeEnumMapReverse[type]; + addAccumulatedCallStarted(callEnumName); const notifier = callStatsTracker.startCall(); let gotMetadata: boolean = false; let hostname: string | null = null; @@ -235,7 +261,7 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail } else { callTimeHistogram[type][statusCode][duration[0]] = 1; } - callTypeStats.result![statusCode] = (callTypeStats.result![statusCode] ?? 0) + 1; + addAccumulatedCallEnded(callEnumName, statusCode); if (error) { if (failOnFailedRpcs && anyCallSucceeded) { console.error('A call failed after a call succeeded'); diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index 6c57a410f..4829edd44 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -80,11 +80,17 @@ export class CdsLoadBalancer implements LoadBalancer { this.watcher = { onValidUpdate: (update) => { this.latestCdsUpdate = update; + let maxConcurrentRequests: number | undefined = undefined; + for (const threshold of update.circuit_breakers?.thresholds ?? []) { + if (threshold.priority === 'DEFAULT') { + maxConcurrentRequests = threshold.max_requests?.value; + } + } /* the lrs_server.self field indicates that the same server should be * used for load reporting as for other xDS operations. Setting * lrsLoadReportingServerName to the empty string sets that behavior. * Otherwise, if the field is omitted, load reporting is disabled. */ - const edsConfig: EdsLoadBalancingConfig = new EdsLoadBalancingConfig(update.name, [], [], update.eds_cluster_config!.service_name === '' ? undefined : update.eds_cluster_config!.service_name, update.lrs_server?.self ? '' : undefined); + const edsConfig: EdsLoadBalancingConfig = new EdsLoadBalancingConfig(update.name, [], [], update.eds_cluster_config!.service_name === '' ? undefined : update.eds_cluster_config!.service_name, update.lrs_server?.self ? '' : undefined, maxConcurrentRequests); trace('Child update EDS config: ' + JSON.stringify(edsConfig)); this.childBalancer.updateAddressList( [], diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 76bdd6655..183e0d670 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -37,6 +37,7 @@ import { Watcher } from './xds-stream-state/xds-stream-state'; import Filter = experimental.Filter; import BaseFilter = experimental.BaseFilter; import FilterFactory = experimental.FilterFactory; +import FilterStackFactory = experimental.FilterStackFactory; import CallStream = experimental.CallStream; const TRACER_NAME = 'eds_balancer'; @@ -204,27 +205,42 @@ export class EdsLoadBalancer implements LoadBalancer { * Otherwise, delegate picking the subchannel to the child * balancer. */ if (dropCategory === null) { - return originalPicker.pick(pickArgs); + const originalPick = originalPicker.pick(pickArgs); + let extraFilterFactory: FilterFactory = new CallTrackingFilterFactory(() => { + this.concurrentRequests -= 1; + }); + if (originalPick.extraFilterFactory) { + extraFilterFactory = new FilterStackFactory([originalPick.extraFilterFactory, extraFilterFactory]); + } + return { + pickResultType: originalPick.pickResultType, + status: originalPick.status, + subchannel: originalPick.subchannel, + onCallStarted: () => { + originalPick.onCallStarted?.(); + this.concurrentRequests += 1; + }, + extraFilterFactory: extraFilterFactory + }; } else { + let details: string; if (dropCategory === true) { + details = 'Call dropped by load balancing policy.'; this.clusterDropStats?.addUncategorizedCallDropped(); } else { + details = `Call dropped by load balancing policy. Category: ${dropCategory}`; this.clusterDropStats?.addCallDropped(dropCategory); } return { pickResultType: PickResultType.DROP, status: { code: Status.UNAVAILABLE, - details: `Call dropped by load balancing policy. Category: ${dropCategory}`, + details: details, metadata: new Metadata(), }, subchannel: null, - extraFilterFactory: new CallTrackingFilterFactory(() => { - this.concurrentRequests -= 1; - }), - onCallStarted: () => { - this.concurrentRequests += 1; - }, + extraFilterFactory: null, + onCallStarted: null }; } }, @@ -265,15 +281,12 @@ export class EdsLoadBalancer implements LoadBalancer { * output, as a sentinel value indicating a drop with no category. */ private checkForDrop(): string | true | null { - if (!this.latestEdsUpdate?.policy) { - return null; + if (this.lastestConfig && this.concurrentRequests >= this.lastestConfig.getMaxConcurrentRequests()) { + return true; } - if (!this.lastestConfig) { + if (!this.latestEdsUpdate?.policy) { return null; } - if (this.concurrentRequests >= this.lastestConfig.getMaxConcurrentRequests()) { - return true; - } /* The drop_overloads policy is a list of pairs of category names and * probabilities. For each one, if the random number is within that * probability range, we drop the call citing that category. Otherwise, the From 8bc20b28fd1191902dac745665f3dc661ddded54 Mon Sep 17 00:00:00 2001 From: Jan Tattermusch Date: Wed, 2 Jun 2021 16:02:42 +0200 Subject: [PATCH 1442/1899] increase timeout for make emulated aarch64 tests green --- test/api/interop_extra_test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/api/interop_extra_test.js b/test/api/interop_extra_test.js index 319ccb536..fa7e03276 100644 --- a/test/api/interop_extra_test.js +++ b/test/api/interop_extra_test.js @@ -147,7 +147,8 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); }); it('should receive all messages in a long stream', function(done) { - this.timeout(20000); + // the test is slow under aarch64 emulator + this.timeout(80000); var arg = { response_type: 'COMPRESSABLE', response_parameters: [ From f01b6d9fcad9fcd199dc13ddbea220fd0917faf9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 2 Jun 2021 13:42:41 -0700 Subject: [PATCH 1443/1899] grpc-js: Export ServerErrorResponse type, which is used in public APIs --- packages/grpc-js/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 308074640..05a82e94d 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -62,6 +62,7 @@ import { ServerReadableStream, ServerWritableStream, ServerDuplexStream, + ServerErrorResponse, } from './server-call'; export { OAuth2Client }; @@ -173,6 +174,7 @@ export { ServerReadableStream, ServerWritableStream, ServerDuplexStream, + ServerErrorResponse, ServiceDefinition, UntypedHandleCall, UntypedServiceImplementation, From 8a38cd8549dd804b2bf070e3ec4620c446d411e8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Jun 2021 14:48:33 -0700 Subject: [PATCH 1444/1899] grpc-js: Refactor FilterStack usage --- packages/grpc-js-xds/src/load-balancer-eds.ts | 10 +++------- packages/grpc-js-xds/src/load-balancer-lrs.ts | 11 +---------- .../src/load-balancer-xds-cluster-manager.ts | 2 +- packages/grpc-js/src/call-stream.ts | 11 +++-------- packages/grpc-js/src/channel.ts | 2 +- packages/grpc-js/src/filter-stack.ts | 8 ++++++++ packages/grpc-js/src/load-balancer-pick-first.ts | 2 +- packages/grpc-js/src/load-balancer-round-robin.ts | 2 +- packages/grpc-js/src/picker.ts | 14 +++++++------- packages/grpc-js/src/subchannel.ts | 4 ++-- 10 files changed, 28 insertions(+), 38 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 183e0d670..efb05eb78 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -37,7 +37,6 @@ import { Watcher } from './xds-stream-state/xds-stream-state'; import Filter = experimental.Filter; import BaseFilter = experimental.BaseFilter; import FilterFactory = experimental.FilterFactory; -import FilterStackFactory = experimental.FilterStackFactory; import CallStream = experimental.CallStream; const TRACER_NAME = 'eds_balancer'; @@ -206,12 +205,9 @@ export class EdsLoadBalancer implements LoadBalancer { * balancer. */ if (dropCategory === null) { const originalPick = originalPicker.pick(pickArgs); - let extraFilterFactory: FilterFactory = new CallTrackingFilterFactory(() => { + const trackingFilterFactory: FilterFactory = new CallTrackingFilterFactory(() => { this.concurrentRequests -= 1; }); - if (originalPick.extraFilterFactory) { - extraFilterFactory = new FilterStackFactory([originalPick.extraFilterFactory, extraFilterFactory]); - } return { pickResultType: originalPick.pickResultType, status: originalPick.status, @@ -220,7 +216,7 @@ export class EdsLoadBalancer implements LoadBalancer { originalPick.onCallStarted?.(); this.concurrentRequests += 1; }, - extraFilterFactory: extraFilterFactory + extraFilterFactories: originalPick.extraFilterFactories.concat(trackingFilterFactory) }; } else { let details: string; @@ -239,7 +235,7 @@ export class EdsLoadBalancer implements LoadBalancer { metadata: new Metadata(), }, subchannel: null, - extraFilterFactory: null, + extraFilterFactories: [], onCallStarted: null }; } diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index 0792b11c2..566aa04c5 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -32,7 +32,6 @@ import PickResult = experimental.PickResult; import Filter = experimental.Filter; import BaseFilter = experimental.BaseFilter; import FilterFactory = experimental.FilterFactory; -import FilterStackFactory = experimental.FilterStackFactory; import Call = experimental.CallStream; import validateLoadBalancingConfig = experimental.validateLoadBalancingConfig @@ -148,14 +147,6 @@ class LoadReportingPicker implements Picker { const trackingFilterFactory = new CallEndTrackingFilterFactory( this.localityStatsReporter ); - /* In the unlikely event that the wrappedPick already has an - * extraFilterFactory, preserve it in a FilterStackFactory. */ - const extraFilterFactory = wrappedPick.extraFilterFactory - ? new FilterStackFactory([ - wrappedPick.extraFilterFactory, - trackingFilterFactory, - ]) - : trackingFilterFactory; return { pickResultType: PickResultType.COMPLETE, subchannel: wrappedPick.subchannel, @@ -164,7 +155,7 @@ class LoadReportingPicker implements Picker { wrappedPick.onCallStarted?.(); this.localityStatsReporter.addCallStarted(); }, - extraFilterFactory: extraFilterFactory, + extraFilterFactories: wrappedPick.extraFilterFactories.concat(trackingFilterFactory), }; } else { return wrappedPick; diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index 920a43db9..7df79e26b 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -107,7 +107,7 @@ class XdsClusterManagerPicker implements Picker { metadata: new Metadata(), }, subchannel: null, - extraFilterFactory: null, + extraFilterFactories: [], onCallStarted: null }; } diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 3a81cbe94..ae6342604 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -210,7 +210,7 @@ export interface Call { export class Http2CallStream implements Call { credentials: CallCredentials; - filterStack: Filter; + filterStack: FilterStack; private http2Stream: http2.ClientHttp2Stream | null = null; private pendingRead = false; private isWriteFilterPending = false; @@ -462,14 +462,9 @@ export class Http2CallStream implements Call { attachHttp2Stream( stream: http2.ClientHttp2Stream, subchannel: Subchannel, - extraFilterFactory?: FilterFactory + extraFilters: FilterFactory[] ): void { - if (extraFilterFactory !== undefined) { - this.filterStack = new FilterStack([ - this.filterStack, - extraFilterFactory.createFilter(this), - ]); - } + this.filterStack.push(extraFilters.map(filterFactory => filterFactory.createFilter(this))); if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8b2658f37..cd2fc94a2 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -373,7 +373,7 @@ export class ChannelImplementation implements Channel { pickResult.subchannel!.startCallStream( finalMetadata, callStream, - pickResult.extraFilterFactory ?? undefined + pickResult.extraFilterFactories ); /* If we reach this point, the call stream has started * successfully */ diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 4fd888549..4e0ccf07f 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -77,11 +77,19 @@ export class FilterStack implements Filter { filter.refresh(); } } + + push(filters: Filter[]) { + this.filters.unshift(...filters); + } } export class FilterStackFactory implements FilterFactory { constructor(private readonly factories: Array>) {} + push(filterFactories: FilterFactory[]) { + this.factories.unshift(...filterFactories); + } + createFilter(callStream: Call): FilterStack { return new FilterStack( this.factories.map((factory) => factory.createFilter(callStream)) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 31dc17847..688f95562 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -83,7 +83,7 @@ class PickFirstPicker implements Picker { pickResultType: PickResultType.COMPLETE, subchannel: this.subchannel, status: null, - extraFilterFactory: null, + extraFilterFactories: [], onCallStarted: null, }; } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index daba45941..2159e64c7 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -78,7 +78,7 @@ class RoundRobinPicker implements Picker { pickResultType: PickResultType.COMPLETE, subchannel: pickedSubchannel, status: null, - extraFilterFactory: null, + extraFilterFactories: [], onCallStarted: null, }; } diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 6df61b59a..25929884b 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -47,7 +47,7 @@ export interface PickResult { * provided by the load balancer to be used with the call. For technical * reasons filters from this factory will not see sendMetadata events. */ - extraFilterFactory: FilterFactory | null; + extraFilterFactories: FilterFactory[]; onCallStarted: (() => void) | null; } @@ -55,7 +55,7 @@ export interface CompletePickResult extends PickResult { pickResultType: PickResultType.COMPLETE; subchannel: Subchannel | null; status: null; - extraFilterFactory: FilterFactory | null; + extraFilterFactories: FilterFactory[]; onCallStarted: (() => void) | null; } @@ -63,7 +63,7 @@ export interface QueuePickResult extends PickResult { pickResultType: PickResultType.QUEUE; subchannel: null; status: null; - extraFilterFactory: null; + extraFilterFactories: []; onCallStarted: null; } @@ -71,7 +71,7 @@ export interface TransientFailurePickResult extends PickResult { pickResultType: PickResultType.TRANSIENT_FAILURE; subchannel: null; status: StatusObject; - extraFilterFactory: null; + extraFilterFactories: []; onCallStarted: null; } @@ -79,7 +79,7 @@ export interface DropCallPickResult extends PickResult { pickResultType: PickResultType.DROP; subchannel: null; status: StatusObject; - extraFilterFactory: null; + extraFilterFactories: []; onCallStarted: null; } @@ -119,7 +119,7 @@ export class UnavailablePicker implements Picker { pickResultType: PickResultType.TRANSIENT_FAILURE, subchannel: null, status: this.status, - extraFilterFactory: null, + extraFilterFactories: [], onCallStarted: null, }; } @@ -148,7 +148,7 @@ export class QueuePicker { pickResultType: PickResultType.QUEUE, subchannel: null, status: null, - extraFilterFactory: null, + extraFilterFactories: [], onCallStarted: null, }; } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 772bdb228..c50a68e77 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -688,7 +688,7 @@ export class Subchannel { startCallStream( metadata: Metadata, callStream: Http2CallStream, - extraFilterFactory?: FilterFactory + extraFilterFactories: FilterFactory[] ) { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); @@ -720,7 +720,7 @@ export class Subchannel { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } logging.trace(LogVerbosity.DEBUG, 'call_stream', 'Starting stream on subchannel ' + this.subchannelAddressString + ' with headers\n' + headersString); - callStream.attachHttp2Stream(http2Stream, this, extraFilterFactory); + callStream.attachHttp2Stream(http2Stream, this, extraFilterFactories); } /** From acfb3c28298742a105e653c5235501a80879c459 Mon Sep 17 00:00:00 2001 From: David Goitia Date: Thu, 17 Jun 2021 14:35:29 +0200 Subject: [PATCH 1445/1899] Update node-pre-gyp dependency --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index b1f83ce45..25ba1da73 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -24,7 +24,7 @@ "prepublishOnly": "git submodule update --init --recursive && node copy_well_known_protos.js" }, "dependencies": { - "node-pre-gyp": "^0.15.0" + "@mapbox/node-pre-gyp": "^1.0.5" }, "binary": { "module_name": "grpc_tools", From 948fc6c1223c6de9d159c9ef24fce4b94c09ff12 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Jun 2021 09:49:42 -0700 Subject: [PATCH 1446/1899] Don't install docker in the docker image --- tools/release/native/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index bc03bf178..d065bddbe 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -6,7 +6,6 @@ RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt RUN apt-get update RUN apt-get -t jessie-backports install -y cmake RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq -RUN curl -fsSL get.docker.com | bash RUN mkdir /usr/local/nvm ENV NVM_DIR /usr/local/nvm From cb505b455646e2a9ba0e853ca1b61d161fe638e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Jun 2021 11:12:35 -0700 Subject: [PATCH 1447/1899] grpc-tools: Bump to version 1.11.2 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 25ba1da73..95faa84c4 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.11.1", + "version": "1.11.2", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 237ea8308a0298aeded01de83a225eda092e9cf4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 Jun 2021 14:37:03 -0700 Subject: [PATCH 1448/1899] grpc-js: Make logging behavior more similar to core --- packages/grpc-js/src/constants.ts | 1 + packages/grpc-js/src/logging.ts | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index d30b78f08..94763cfe1 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -39,6 +39,7 @@ export enum LogVerbosity { DEBUG = 0, INFO, ERROR, + NONE, } /** diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 1140e8d8a..de8d2d056 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -32,6 +32,9 @@ switch (verbosityString) { case 'ERROR': _logVerbosity = LogVerbosity.ERROR; break; + case 'NONE': + _logVerbosity = LogVerbosity.NONE; + break; default: // Ignore any other values } @@ -56,15 +59,23 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { }; const tracersString = process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; -const enabledTracers = tracersString.split(','); -const allEnabled = enabledTracers.includes('all'); +const enabledTracers = new Set(); +const disabledTracers = new Set(); +for (const tracerName of tracersString.split(',')) { + if (tracerName.startsWith('-')) { + disabledTracers.add(tracerName.substring(1)); + } else { + enabledTracers.add(tracerName) + } +} +const allEnabled = enabledTracers.has('all'); export function trace( severity: LogVerbosity, tracer: string, text: string ): void { - if (allEnabled || enabledTracers.includes(tracer)) { + if (!disabledTracers.has(tracer) && (allEnabled || enabledTracers.has(tracer))) { log(severity, new Date().toISOString() + ' | ' + tracer + ' | ' + text); } } From a214aca7686bb8ba0a104885c4e6ed869932e38f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 Jun 2021 14:37:26 -0700 Subject: [PATCH 1449/1899] Document environment variables, particularly for logging --- TROUBLESHOOTING.md | 38 +++++++++++++++++++++++ doc/environment_variables.md | 58 ++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 TROUBLESHOOTING.md create mode 100644 doc/environment_variables.md diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md new file mode 100644 index 000000000..dd5bce7af --- /dev/null +++ b/TROUBLESHOOTING.md @@ -0,0 +1,38 @@ +# Troubleshooting grpc-js + +This guide is for troubleshooting the `grpc-js` library for Node.js + +## Enabling extra logging and tracing + +Extra logging can be very useful for diagnosing problems. `grpc-js` supporst +the `GRPC_VERBOSITY` and `GRPC_TRACE` environment variables that can be used to increase the amount of information +that gets printed to stderr. + +## GRPC_VERBOSITY + +`GRPC_VERBOSITY` is used to set the minimum level of log messages printed by gRPC (supported values are `DEBUG`, `INFO` and `ERROR`). If this environment variable is unset, only `ERROR` logs will be printed. + +## GRPC_TRACE + +`GRPC_TRACE` can be used to enable extra logging for some internal gRPC components. Enabling the right traces can be invaluable +for diagnosing for what is going wrong when things aren't working as intended. Possible values for `GRPC_TRACE` are listed in [Environment Variables Overview](doc/environment_variables.md). +Multiple traces can be enabled at once (use comma as separator). + +``` +# Enable debug logs for an application +GRPC_VERBOSITY=debug ./helloworld_application_using_grpc +``` + +``` +# Print information about channel state changes +GRPC_VERBOSITY=debug GRPC_TRACE=connectivity_state ./helloworld_application_using_grpc +``` + +``` +# Print info from 3 different tracers, including tracing logs with log level DEBUG +GRPC_VERBOSITY=debug GRPC_TRACE=channel,subchannel,call_stream ./helloworld_application_using_grpc +``` + +Please note that the `GRPC_TRACE` environment variable has nothing to do with gRPC's "tracing" feature (= tracing RPCs in +microservice environment to gain insight about how requests are processed by deployment), it is merely used to enable printing +of extra logs. diff --git a/doc/environment_variables.md b/doc/environment_variables.md new file mode 100644 index 000000000..f2a32294c --- /dev/null +++ b/doc/environment_variables.md @@ -0,0 +1,58 @@ +# grpc-js environment variables + +`@grpc/grpc-js` exposes some configuration as environment variables that +can be set. + +*For the legacy `grpc` library, the environment variables are documented +[in the main gRPC repository](https://github.com/grpc/grpc/blob/master/doc/environment_variables.md)* + +* grpc_proxy, https_proxy, http_proxy + The URI of the proxy to use for HTTP CONNECT support. These variables are + checked in order, and the first one that has a value is used. + +* no_grpc_proxy, no_proxy + A comma separated list of hostnames to connect to without using a proxy even + if a proxy is set. These variables are checked in order, and the first one + that has a value is used. + +* GRPC_SSL_CIPHER_SUITES + A colon separated list of cipher suites to use with OpenSSL + Defaults to the defaults for Node.js + +* GRPC_DEFAULT_SSL_ROOTS_FILE_PATH + PEM file to load SSL roots from + +* GRPC_NODE_TRACE, GRPC_TRACE + A comma separated list of tracers that provide additional insight into how + grpc-js is processing requests via debug logs. Available tracers include: + - `call_stream` - Traces client request internals + - `channel` - Traces channel events + - `connectivity_state` - Traces channel connectivity state changes + - `dns_resolver` - Traces DNS resolution + - `pick_first` - Traces the pick first load balancing policy + - `proxy` - Traces proxy operations + - `resolving_load_balancer` - Traces the resolving load balancer + - `round_robin` - Traces the round robin load balancing policy + - `server` - Traces high-level server events + - `server_call` - Traces server handling of individual requests + - `subchannel` - Traces subchannel connectivity state and errors + - `subchannel_refcount` - Traces subchannel refcount changes + + The following tracers are added by the `@grpc/grpc-js-xds` library: + - `cds_balancer` - Traces the CDS load balancing policy + - `eds_balancer` - Traces the EDS load balancing policy + - `priority` - Traces the priority load balancing policy + - `weighted_target` - Traces the weighted target load balancing policy + - `xds_client` - Traces the xDS Client + - `xds_cluster_manager` - Traces the xDS cluster manager load balancing policy + - `xds_resolver` - Traces the xDS name resolver + + 'all' can additionally be used to turn all traces on. + Individual traces can be disabled by prefixing them with '-'. + +* GRPC_NODE_VERBOSITY, GRPC_VERBOSITY + Default gRPC logging verbosity - one of: + - DEBUG - log all gRPC messages + - INFO - log INFO and ERROR message + - ERROR - log only errors (default) + - NONE - won't log any \ No newline at end of file From 118a6df067c68a26c17a4c114747a39ab3621035 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 Jun 2021 14:37:03 -0700 Subject: [PATCH 1450/1899] grpc-js: Make logging behavior more similar to core --- packages/grpc-js/src/constants.ts | 1 + packages/grpc-js/src/logging.ts | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index d30b78f08..94763cfe1 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -39,6 +39,7 @@ export enum LogVerbosity { DEBUG = 0, INFO, ERROR, + NONE, } /** diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index dea9c93f8..71683dbf7 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -32,6 +32,9 @@ switch (verbosityString.toUpperCase()) { case 'ERROR': _logVerbosity = LogVerbosity.ERROR; break; + case 'NONE': + _logVerbosity = LogVerbosity.NONE; + break; default: // Ignore any other values } @@ -56,15 +59,23 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { }; const tracersString = process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; -const enabledTracers = tracersString.split(','); -const allEnabled = enabledTracers.includes('all'); +const enabledTracers = new Set(); +const disabledTracers = new Set(); +for (const tracerName of tracersString.split(',')) { + if (tracerName.startsWith('-')) { + disabledTracers.add(tracerName.substring(1)); + } else { + enabledTracers.add(tracerName) + } +} +const allEnabled = enabledTracers.has('all'); export function trace( severity: LogVerbosity, tracer: string, text: string ): void { - if (allEnabled || enabledTracers.includes(tracer)) { + if (!disabledTracers.has(tracer) && (allEnabled || enabledTracers.has(tracer))) { log(severity, new Date().toISOString() + ' | ' + tracer + ' | ' + text); } } From d894809e0eeec1c12d83e272c75f0a96d9e58013 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 21 Jun 2021 14:42:09 -0700 Subject: [PATCH 1451/1899] grpc-js: Bump version to 1.3.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6bce0ebdd..f859a3267 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.2", + "version": "1.3.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From f289c343b3393aad73795c0657415f4160bcdcb5 Mon Sep 17 00:00:00 2001 From: Mike Lewis Date: Wed, 23 Jun 2021 16:42:39 +0100 Subject: [PATCH 1452/1899] Avoid unused definition imports from proto-loader Since proto files don't always contain all types of definition, it was possible to get into a state where generated code contained unused imports which caused TS errors. This change makes those imports conditional on the existence of the corresponding definitions in the proto file. Co-authored-by: Austin Puri Co-authored-by: Joe Porpeglia Signed-off-by: Mike Lewis --- .../bin/proto-loader-gen-types.ts | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 82a13a123..fedaadc38 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -579,6 +579,34 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob generateServiceDefinitionInterface(formatter, serviceType); } +function containsDefinition(definitionType: typeof Protobuf.Type | typeof Protobuf.Enum, namespace: Protobuf.NamespaceBase): boolean { + for (const nested of namespace.nestedArray.sort(compareName)) { + if (nested instanceof definitionType) { + return true; + } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { + return containsDefinition(definitionType, nested); + } + } + + return false; +} + +function generateDefinitionImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { + const imports = []; + + if (containsDefinition(Protobuf.Enum, namespace)) { + imports.push('EnumTypeDefinition'); + } + + if (containsDefinition(Protobuf.Type, namespace)) { + imports.push('MessageTypeDefinition'); + } + + if (imports.length) { + formatter.writeLine(`import type { ${imports.join(', ')} } from '@grpc/proto-loader';`); + } +} + function generateServiceImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { @@ -617,7 +645,7 @@ function generateLoadedDefinitionTypes(formatter: TextFormatter, namespace: Prot function generateRootFile(formatter: TextFormatter, root: Protobuf.Root, options: GeneratorOptions) { formatter.writeLine(`import type * as grpc from '${options.grpcLib}';`); - formatter.writeLine("import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader';"); + generateDefinitionImports(formatter, root, options); formatter.writeLine(''); generateServiceImports(formatter, root, options); From 61e64a3c4f684e1671fd27b9e47ca9755e042f22 Mon Sep 17 00:00:00 2001 From: Mike Lewis Date: Wed, 23 Jun 2021 17:55:38 +0100 Subject: [PATCH 1453/1899] Update golden-generated in proto-loader Signed-off-by: Mike Lewis --- packages/proto-loader/golden-generated/echo.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/golden-generated/echo.ts b/packages/proto-loader/golden-generated/echo.ts index f257a40e4..600e2864c 100644 --- a/packages/proto-loader/golden-generated/echo.ts +++ b/packages/proto-loader/golden-generated/echo.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; import type { OperationsClient as _google_longrunning_OperationsClient, OperationsDefinition as _google_longrunning_OperationsDefinition } from './google/longrunning/Operations'; import type { EchoClient as _google_showcase_v1beta1_EchoClient, EchoDefinition as _google_showcase_v1beta1_EchoDefinition } from './google/showcase/v1beta1/Echo'; From 12b2412356e287700c5e38e0cb0d120a820f2c19 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 23 Jun 2021 12:46:53 -0700 Subject: [PATCH 1454/1899] proto-loader: Bump to version 0.6.3 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 0d9ff4437..cbda6680d 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.2", + "version": "0.6.3", "author": "Google Inc.", "contributors": [ { From fa5066759d239f34c4cf20bf41a16ca9a5f47bf8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 23 Jun 2021 14:01:56 -0700 Subject: [PATCH 1455/1899] grpc-js: Unref timers for keepalive functionality --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f859a3267..8acb8a145 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.3", + "version": "1.3.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 7a68a1a2d..8991ee3b0 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -280,6 +280,7 @@ export class Subchannel { this.keepaliveTimeoutId = setTimeout(() => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); + this.keepaliveTimeoutId.unref?.(); this.session!.ping( (err: Error | null, duration: number, payload: Buffer) => { clearTimeout(this.keepaliveTimeoutId); @@ -291,6 +292,7 @@ export class Subchannel { this.keepaliveIntervalId = setInterval(() => { this.sendPing(); }, this.keepaliveTimeMs); + this.keepaliveIntervalId.unref?.() /* Don't send a ping immediately because whatever caused us to start * sending pings should also involve some network activity. */ } From 031ae9472e7ce0592dd34f344a50c6cded861203 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 24 Jun 2021 09:40:30 -0700 Subject: [PATCH 1456/1899] grpc-js: Refactor code to eliminate runtime dependency cycles --- packages/grpc-js/package.json | 3 +- packages/grpc-js/src/channel.ts | 11 +--- packages/grpc-js/src/client.ts | 3 +- packages/grpc-js/src/connectivity-state.ts | 24 +++++++ packages/grpc-js/src/experimental.ts | 2 +- packages/grpc-js/src/http_proxy.ts | 4 +- packages/grpc-js/src/index.ts | 15 +++-- .../src/load-balancer-child-handler.ts | 9 +-- .../grpc-js/src/load-balancer-pick-first.ts | 14 +++-- .../grpc-js/src/load-balancer-round-robin.ts | 12 ++-- packages/grpc-js/src/load-balancer.ts | 36 ++++++----- packages/grpc-js/src/resolver-dns.ts | 2 +- packages/grpc-js/src/resolver-uds.ts | 2 +- packages/grpc-js/src/resolver.ts | 9 +-- .../grpc-js/src/resolving-load-balancer.ts | 8 +-- packages/grpc-js/src/server.ts | 4 +- packages/grpc-js/src/subchannel-address.ts | 62 +++++++++++++++++++ packages/grpc-js/src/subchannel-pool.ts | 6 +- packages/grpc-js/src/subchannel.ts | 49 +-------------- packages/grpc-js/test/test-client.ts | 2 +- packages/grpc-js/test/test-resolver.ts | 7 ++- 21 files changed, 167 insertions(+), 117 deletions(-) create mode 100644 packages/grpc-js/src/connectivity-state.ts create mode 100644 packages/grpc-js/src/subchannel-address.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 6a027d391..3733e06fc 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -29,6 +29,7 @@ "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", + "madge": "^5.0.1", "mocha-jenkins-reporter": "^0.4.1", "ncp": "^2.0.0", "pify": "^4.0.1", @@ -53,7 +54,7 @@ "check": "gts check src/**/*.ts", "fix": "gts fix src/*.ts", "pretest": "npm run compile", - "posttest": "npm run check" + "posttest": "npm run check && madge -c ./build/src" }, "dependencies": { "@types/node": ">=12.12.47" diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index cd2fc94a2..58726ccc7 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -35,20 +35,13 @@ import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; import { CallConfig, ConfigSelector, getDefaultAuthority, mapUriDefaultScheme } from './resolver'; import { trace, log } from './logging'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress } from "./subchannel-address"; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; import { SurfaceCall } from './call'; - -export enum ConnectivityState { - IDLE, - CONNECTING, - READY, - TRANSIENT_FAILURE, - SHUTDOWN, -} +import { ConnectivityState } from './connectivity-state'; /** * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 5f78ffe59..7a2199b02 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -30,7 +30,8 @@ import { } from './call'; import { CallCredentials } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; -import { Channel, ConnectivityState, ChannelImplementation } from './channel'; +import { Channel, ChannelImplementation } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; diff --git a/packages/grpc-js/src/connectivity-state.ts b/packages/grpc-js/src/connectivity-state.ts new file mode 100644 index 000000000..8e1812274 --- /dev/null +++ b/packages/grpc-js/src/connectivity-state.ts @@ -0,0 +1,24 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export enum ConnectivityState { + IDLE, + CONNECTING, + READY, + TRANSIENT_FAILURE, + SHUTDOWN +} diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index cf84ba6b8..438ca71a8 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -4,7 +4,7 @@ export { GrpcUri, uriToString } from './uri-parser'; export { ServiceConfig, Duration } from './service-config'; export { BackoffTimeout } from './backoff-timeout'; export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig } from './load-balancer'; -export { SubchannelAddress, subchannelAddressToString } from './subchannel'; +export { SubchannelAddress, subchannelAddressToString } from './subchannel-address'; export { ChildLoadBalancerHandler } from './load-balancer-child-handler'; export { Picker, UnavailablePicker, QueuePicker, PickResult, PickArgs, PickResultType } from './picker'; export { Call as CallStream } from './call-stream'; diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index f6921378b..d62be597c 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -25,8 +25,8 @@ import * as logging from './logging'; import { SubchannelAddress, isTcpSubchannelAddress, - subchannelAddressToString, -} from './subchannel'; + subchannelAddressToString +} from "./subchannel-address"; import { ChannelOptions } from './channel-options'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { URL } from 'url'; diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 05a82e94d..d0eb2a37c 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -24,7 +24,8 @@ import { } from './call'; import { CallCredentials, OAuth2Client } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; -import { Channel, ConnectivityState, ChannelImplementation } from './channel'; +import { Channel, ChannelImplementation } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { ChannelCredentials } from './channel-credentials'; import { CallOptions, @@ -246,10 +247,14 @@ export { ChannelOptions } from './channel-options'; import * as experimental from './experimental'; export { experimental }; -import * as resolver from './resolver'; -import * as load_balancer from './load-balancer'; +import * as resolver_dns from './resolver-dns'; +import * as resolver_uds from './resolver-uds'; +import * as load_balancer_pick_first from './load-balancer-pick-first'; +import * as load_balancer_round_robin from './load-balancer-round-robin'; (() => { - resolver.registerAll(); - load_balancer.registerAll(); + resolver_dns.setup(); + resolver_uds.setup(); + load_balancer_pick_first.setup(); + load_balancer_round_robin.setup(); })(); diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 337174c0d..25cba4528 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -18,12 +18,13 @@ import { LoadBalancer, ChannelControlHelper, - createLoadBalancer, - LoadBalancingConfig + LoadBalancingConfig, + createLoadBalancer } from './load-balancer'; -import { SubchannelAddress, Subchannel } from './subchannel'; +import { Subchannel } from './subchannel'; +import { SubchannelAddress } from "./subchannel-address"; import { ChannelOptions } from './channel-options'; -import { ConnectivityState } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { Picker } from './picker'; const TYPE_NAME = 'child_load_balancer_helper'; diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 688f95562..f7e9dd917 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -18,10 +18,11 @@ import { LoadBalancer, ChannelControlHelper, - registerLoadBalancerType, - LoadBalancingConfig + LoadBalancingConfig, + registerDefaultLoadBalancerType, + registerLoadBalancerType } from './load-balancer'; -import { ConnectivityState } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { QueuePicker, Picker, @@ -33,9 +34,11 @@ import { import { Subchannel, ConnectivityStateListener, - SubchannelAddress, - subchannelAddressToString, } from './subchannel'; +import { + SubchannelAddress, + subchannelAddressToString +} from "./subchannel-address"; import * as logging from './logging'; import { LogVerbosity } from './constants'; @@ -458,4 +461,5 @@ export class PickFirstLoadBalancer implements LoadBalancer { export function setup(): void { registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer, PickFirstLoadBalancingConfig); + registerDefaultLoadBalancerType(TYPE_NAME); } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 2159e64c7..fabd334e3 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -18,10 +18,10 @@ import { LoadBalancer, ChannelControlHelper, - registerLoadBalancerType, - LoadBalancingConfig + LoadBalancingConfig, + registerLoadBalancerType } from './load-balancer'; -import { ConnectivityState } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { QueuePicker, Picker, @@ -33,9 +33,11 @@ import { import { Subchannel, ConnectivityStateListener, - SubchannelAddress, - subchannelAddressToString, } from './subchannel'; +import { + SubchannelAddress, + subchannelAddressToString +} from "./subchannel-address"; import * as logging from './logging'; import { LogVerbosity } from './constants'; diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 8d5c7c837..7fe0b9b3d 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -16,11 +16,10 @@ */ import { ChannelOptions } from './channel-options'; -import { Subchannel, SubchannelAddress } from './subchannel'; -import { ConnectivityState } from './channel'; +import { Subchannel } from './subchannel'; +import { SubchannelAddress } from "./subchannel-address"; +import { ConnectivityState } from "./connectivity-state"; import { Picker } from './picker'; -import * as load_balancer_pick_first from './load-balancer-pick-first'; -import * as load_balancer_round_robin from './load-balancer-round-robin'; /** * A collection of functions associated with a channel that a load balancer @@ -108,11 +107,13 @@ export interface LoadBalancingConfigConstructor { const registeredLoadBalancerTypes: { [name: string]: { - LoadBalancer: LoadBalancerConstructor, - LoadBalancingConfig: LoadBalancingConfigConstructor + LoadBalancer: LoadBalancerConstructor; + LoadBalancingConfig: LoadBalancingConfigConstructor; }; } = {}; +let defaultLoadBalancerType: string | null = null; + export function registerLoadBalancerType( typeName: string, loadBalancerType: LoadBalancerConstructor, @@ -124,6 +125,10 @@ export function registerLoadBalancerType( }; } +export function registerDefaultLoadBalancerType(typeName: string) { + defaultLoadBalancerType = typeName; +} + export function createLoadBalancer( config: LoadBalancingConfig, channelControlHelper: ChannelControlHelper @@ -140,25 +145,29 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; } -export function getFirstUsableConfig(configs: LoadBalancingConfig[], defaultPickFirst?: true): LoadBalancingConfig; +export function getFirstUsableConfig(configs: LoadBalancingConfig[], fallbackTodefault?: true): LoadBalancingConfig; export function getFirstUsableConfig( configs: LoadBalancingConfig[], - defaultPickFirst: boolean = false + fallbackTodefault: boolean = false ): LoadBalancingConfig | null { for (const config of configs) { if (config.getLoadBalancerName() in registeredLoadBalancerTypes) { return config; } } - if (defaultPickFirst) { - return new load_balancer_pick_first.PickFirstLoadBalancingConfig() + if (fallbackTodefault) { + if (defaultLoadBalancerType) { + return new registeredLoadBalancerTypes[defaultLoadBalancerType]!.LoadBalancingConfig(); + } else { + return null; + } } else { return null; } } export function validateLoadBalancingConfig(obj: any): LoadBalancingConfig { - if (!(obj !== null && (typeof obj === 'object'))) { + if (!(obj !== null && (typeof obj === 'object'))) { throw new Error('Load balancing config must be an object'); } const keys = Object.keys(obj); @@ -172,8 +181,3 @@ export function validateLoadBalancingConfig(obj: any): LoadBalancingConfig { throw new Error(`Unrecognized load balancing config name ${typeName}`); } } - -export function registerAll() { - load_balancer_pick_first.setup(); - load_balancer_round_robin.setup(); -} diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 67f1f8c45..44246c779 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -28,7 +28,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SubchannelAddress, TcpSubchannelAddress } from './subchannel'; +import { SubchannelAddress, TcpSubchannelAddress } from "./subchannel-address"; import { GrpcUri, uriToString, splitHostPort } from './uri-parser'; import { isIPv6, isIPv4 } from 'net'; import { ChannelOptions } from './channel-options'; diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 40502f113..1c5a7a64c 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -15,7 +15,7 @@ */ import { Resolver, ResolverListener, registerResolver } from './resolver'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress } from "./subchannel-address"; import { GrpcUri } from './uri-parser'; import { ChannelOptions } from './channel-options'; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 147ace30d..5bf7df2e7 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -16,10 +16,8 @@ */ import { MethodConfig, ServiceConfig } from './service-config'; -import * as resolver_dns from './resolver-dns'; -import * as resolver_uds from './resolver-uds'; import { StatusObject } from './call-stream'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress } from "./subchannel-address"; import { GrpcUri, uriToString } from './uri-parser'; import { ChannelOptions } from './channel-options'; import { Metadata } from './metadata'; @@ -175,8 +173,3 @@ export function mapUriDefaultScheme(target: GrpcUri): GrpcUri | null { } return target; } - -export function registerAll() { - resolver_dns.setup(); - resolver_uds.setup(); -} diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 94dd8c4a9..9825086c1 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -18,11 +18,11 @@ import { ChannelControlHelper, LoadBalancer, - getFirstUsableConfig, - LoadBalancingConfig + LoadBalancingConfig, + getFirstUsableConfig } from './load-balancer'; import { ServiceConfig, validateServiceConfig } from './service-config'; -import { ConnectivityState } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { ConfigSelector, createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; @@ -32,7 +32,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SubchannelAddress } from './subchannel'; +import { SubchannelAddress } from "./subchannel-address"; import { GrpcUri, uriToString } from './uri-parser'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { ChannelOptions } from './channel-options'; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 255e210b6..aec149556 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -55,8 +55,8 @@ import { SubchannelAddress, TcpSubchannelAddress, isTcpSubchannelAddress, - subchannelAddressToString, -} from './subchannel'; + subchannelAddressToString +} from "./subchannel-address"; import { parseUri } from './uri-parser'; const TRACER_NAME = 'server'; diff --git a/packages/grpc-js/src/subchannel-address.ts b/packages/grpc-js/src/subchannel-address.ts new file mode 100644 index 000000000..4b08d8ba1 --- /dev/null +++ b/packages/grpc-js/src/subchannel-address.ts @@ -0,0 +1,62 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export interface TcpSubchannelAddress { + port: number; + host: string; +} + +export interface IpcSubchannelAddress { + path: string; +} +/** + * This represents a single backend address to connect to. This interface is a + * subset of net.SocketConnectOpts, i.e. the options described at + * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener. + * Those are in turn a subset of the options that can be passed to http2.connect. + */ + +export type SubchannelAddress = TcpSubchannelAddress | IpcSubchannelAddress; + +export function isTcpSubchannelAddress( + address: SubchannelAddress +): address is TcpSubchannelAddress { + return 'port' in address; +} + +export function subchannelAddressEqual( + address1: SubchannelAddress, + address2: SubchannelAddress +): boolean { + if (isTcpSubchannelAddress(address1)) { + return ( + isTcpSubchannelAddress(address2) && + address1.host === address2.host && + address1.port === address2.port + ); + } else { + return !isTcpSubchannelAddress(address2) && address1.path === address2.path; + } +} + +export function subchannelAddressToString(address: SubchannelAddress): string { + if (isTcpSubchannelAddress(address)) { + return address.host + ':' + address.port; + } else { + return address.path; + } +} diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index d28e3eac8..65c5f2177 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -18,9 +18,11 @@ import { ChannelOptions, channelOptionsEqual } from './channel-options'; import { Subchannel, - SubchannelAddress, - subchannelAddressEqual, } from './subchannel'; +import { + SubchannelAddress, + subchannelAddressEqual +} from "./subchannel-address"; import { ChannelCredentials } from './channel-credentials'; import { GrpcUri, uriToString } from './uri-parser'; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c50a68e77..a76ea963c 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -21,7 +21,7 @@ import { Metadata } from './metadata'; import { Http2CallStream } from './call-stream'; import { ChannelOptions } from './channel-options'; import { PeerCertificate, checkServerIdentity } from 'tls'; -import { ConnectivityState } from './channel'; +import { ConnectivityState } from "./connectivity-state"; import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; @@ -31,6 +31,7 @@ import * as net from 'net'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { ConnectionOptions } from 'tls'; import { FilterFactory, Filter } from './filter'; +import { SubchannelAddress, subchannelAddressToString } from './subchannel-address'; const clientVersion = require('../../package.json').version; @@ -82,52 +83,6 @@ function uniformRandom(min: number, max: number) { const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); -export interface TcpSubchannelAddress { - port: number; - host: string; -} - -export interface IpcSubchannelAddress { - path: string; -} - -/** - * This represents a single backend address to connect to. This interface is a - * subset of net.SocketConnectOpts, i.e. the options described at - * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener. - * Those are in turn a subset of the options that can be passed to http2.connect. - */ -export type SubchannelAddress = TcpSubchannelAddress | IpcSubchannelAddress; - -export function isTcpSubchannelAddress( - address: SubchannelAddress -): address is TcpSubchannelAddress { - return 'port' in address; -} - -export function subchannelAddressEqual( - address1: SubchannelAddress, - address2: SubchannelAddress -): boolean { - if (isTcpSubchannelAddress(address1)) { - return ( - isTcpSubchannelAddress(address2) && - address1.host === address2.host && - address1.port === address2.port - ); - } else { - return !isTcpSubchannelAddress(address2) && address1.path === address2.path; - } -} - -export function subchannelAddressToString(address: SubchannelAddress): string { - if (isTcpSubchannelAddress(address)) { - return address.host + ':' + address.port; - } else { - return address.path; - } -} - export class Subchannel { /** * The subchannel's current connectivity state. Invariant: `session` === `null` diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts index 0d2878cbc..51af05416 100644 --- a/packages/grpc-js/test/test-client.ts +++ b/packages/grpc-js/test/test-client.ts @@ -20,7 +20,7 @@ import * as assert from 'assert'; import * as grpc from '../src'; import { Server, ServerCredentials } from '../src'; import { Client } from '../src'; -import { ConnectivityState } from '../src/channel'; +import { ConnectivityState } from "../src/connectivity-state"; const clientInsecureCreds = grpc.credentials.createInsecure(); const serverInsecureCreds = ServerCredentials.createInsecure(); diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index c4f42f6eb..976e64895 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -19,9 +19,11 @@ // tslint:disable no-any import * as assert from 'assert'; import * as resolverManager from '../src/resolver'; +import * as load_balancer_pick_first from '../src/load-balancer-pick-first'; +import * as load_balancer_round_robin from '../src/load-balancer-round-robin'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; -import { SubchannelAddress, isTcpSubchannelAddress } from '../src/subchannel'; +import { SubchannelAddress, isTcpSubchannelAddress } from "../src/subchannel-address"; import { parseUri, GrpcUri } from '../src/uri-parser'; describe('Name Resolver', () => { @@ -29,7 +31,8 @@ describe('Name Resolver', () => { // For some reason DNS queries sometimes take a long time on Windows this.timeout(4000); before(() => { - resolverManager.registerAll(); + load_balancer_pick_first.setup(); + load_balancer_round_robin.setup(); }); it('Should resolve localhost properly', done => { const target = resolverManager.mapUriDefaultScheme(parseUri('localhost:50051')!)!; From 32cd3504cccec9fcfee67dc87a6a9e8f66fa40f3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 28 Jun 2021 11:24:43 -0700 Subject: [PATCH 1457/1899] grpc-js: Add note in README about feature parity requests --- packages/grpc-js/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 4bb4da024..df44264ce 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -25,6 +25,8 @@ Documentation specifically for the `@grpc/grpc-js` package is currently not avai - Connection Keepalives - HTTP Connect support (proxies) +If you need a feature from the `grpc` package that is not provided by the `@grpc/grpc-js`, please file a feature request with that information. + This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package. ## Migrating from [`grpc`](https://www.npmjs.com/package/grpc) From 41e09f7d12b05d74f37e3fd30bf08a7398ad12d2 Mon Sep 17 00:00:00 2001 From: Mike Lewis Date: Mon, 28 Jun 2021 19:04:58 +0100 Subject: [PATCH 1458/1899] Prevent early return in proto-loader containsDefinition f289c343b3393aad73795c0657415f4160bcdcb5 introduced a bug - the recursive for-loop descended into the first elements nested array and returned that value without iterating over the other members of the array. This means that the code would only work correctly when the protofile contained a definition whose name was alphabetically first amongst its siblings. This commit fixes the issue by moving the call to containsDefinition into the if statement to allow iteration to continue if containsDefinition returns false. --- packages/proto-loader/bin/proto-loader-gen-types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index fedaadc38..b441d425e 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -583,8 +583,8 @@ function containsDefinition(definitionType: typeof Protobuf.Type | typeof Protob for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof definitionType) { return true; - } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { - return containsDefinition(definitionType, nested); + } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum) && containsDefinition(definitionType, nested)) { + return true; } } From 6ba982548e58a89641f3377c863b263ab094101f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 28 Jun 2021 13:17:16 -0700 Subject: [PATCH 1459/1899] proto-loader: bump to 0.6.4 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index cbda6680d..824fa6f5e 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.3", + "version": "0.6.4", "author": "Google Inc.", "contributors": [ { From 0ad7cc1ec913d159a22e8c2bf2410322c1b364da Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 28 Jun 2021 14:37:21 -0700 Subject: [PATCH 1460/1899] grpc-js-xds: case_sensitive flag should not affect regex matcher --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/matcher.ts | 4 ++-- packages/grpc-js-xds/src/resolver-xds.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f4f8d604d..dfd778bd3 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.3.0", + "version": "1.3.1", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { diff --git a/packages/grpc-js-xds/src/matcher.ts b/packages/grpc-js-xds/src/matcher.ts index a70cf5d67..14cb7f672 100644 --- a/packages/grpc-js-xds/src/matcher.ts +++ b/packages/grpc-js-xds/src/matcher.ts @@ -197,8 +197,8 @@ export class PathExactValueMatcher { export class PathSafeRegexValueMatcher { private targetRegexImpl: RE2; - constructor(targetRegex: string, caseInsensitive: boolean) { - this.targetRegexImpl = new RE2(`^${targetRegex}$`, caseInsensitive ? 'iu' : 'u'); + constructor(targetRegex: string) { + this.targetRegexImpl = new RE2(`^${targetRegex}$`, 'u'); } apply(value: string) { diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 102a52349..aee7290bb 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -169,7 +169,7 @@ function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { pathMatcher = new PathExactValueMatcher(routeMatch.path!, caseInsensitive); break; case 'safe_regex': - pathMatcher = new PathSafeRegexValueMatcher(routeMatch.safe_regex!.regex, caseInsensitive); + pathMatcher = new PathSafeRegexValueMatcher(routeMatch.safe_regex!.regex); break; default: pathMatcher = new RejectValueMatcher(); From 1452ed93aa86df36e2d18093455be8bb20637a56 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 29 Jun 2021 10:04:32 -0700 Subject: [PATCH 1461/1899] grpc-js: Register IP resolver in index --- packages/grpc-js/src/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index d0eb2a37c..52c122b12 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -249,12 +249,14 @@ export { experimental }; import * as resolver_dns from './resolver-dns'; import * as resolver_uds from './resolver-uds'; +import * as resolver_ip from './resolver-ip'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; (() => { resolver_dns.setup(); resolver_uds.setup(); + resolver_ip.setup(); load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); })(); From 8605ef2ded12f4eff3dded61736f1741e075add0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 29 Jun 2021 10:43:45 -0700 Subject: [PATCH 1462/1899] Fix subchannel address import, resolver test setup --- packages/grpc-js/src/resolver-ip.ts | 2 +- packages/grpc-js/test/test-resolver.ts | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/resolver-ip.ts b/packages/grpc-js/src/resolver-ip.ts index 5c9e29c46..18bbe54aa 100644 --- a/packages/grpc-js/src/resolver-ip.ts +++ b/packages/grpc-js/src/resolver-ip.ts @@ -20,7 +20,7 @@ import { ChannelOptions } from "./channel-options"; import { LogVerbosity, Status } from "./constants"; import { Metadata } from "./metadata"; import { registerResolver, Resolver, ResolverListener } from "./resolver"; -import { SubchannelAddress } from "./subchannel"; +import { SubchannelAddress } from "./subchannel-address"; import { GrpcUri, splitHostPort, uriToString } from "./uri-parser"; import * as logging from './logging'; diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index b5a4c1640..7addfa232 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -19,21 +19,23 @@ // tslint:disable no-any import * as assert from 'assert'; import * as resolverManager from '../src/resolver'; -import * as load_balancer_pick_first from '../src/load-balancer-pick-first'; -import * as load_balancer_round_robin from '../src/load-balancer-round-robin'; +import * as resolver_dns from '../src/resolver-dns'; +import * as resolver_uds from '../src/resolver-uds'; +import * as resolver_ip from '../src/resolver-ip'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; import { SubchannelAddress, isTcpSubchannelAddress } from "../src/subchannel-address"; import { parseUri, GrpcUri } from '../src/uri-parser'; describe('Name Resolver', () => { + before(() => { + resolver_dns.setup(); + resolver_uds.setup(); + resolver_ip.setup(); + }); describe('DNS Names', function() { // For some reason DNS queries sometimes take a long time on Windows this.timeout(4000); - before(() => { - load_balancer_pick_first.setup(); - load_balancer_round_robin.setup(); - }); it('Should resolve localhost properly', done => { const target = resolverManager.mapUriDefaultScheme(parseUri('localhost:50051')!)!; const listener: resolverManager.ResolverListener = { From 1037b23ba62b4d1205f3dd57f50e553b804d7a04 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 29 Jun 2021 14:40:24 -0700 Subject: [PATCH 1463/1899] grpc-js: Format source files and fix lint errors --- .../grpc-js/src/call-credentials-filter.ts | 4 +- packages/grpc-js/src/call-stream.ts | 29 ++++-- packages/grpc-js/src/call.ts | 12 ++- packages/grpc-js/src/channel-options.ts | 1 + packages/grpc-js/src/channel.ts | 94 ++++++++++++++----- packages/grpc-js/src/client-interceptors.ts | 11 ++- packages/grpc-js/src/client.ts | 33 +++---- packages/grpc-js/src/connectivity-state.ts | 2 +- packages/grpc-js/src/constants.ts | 6 +- packages/grpc-js/src/deadline-filter.ts | 4 +- packages/grpc-js/src/experimental.ts | 46 ++++++--- packages/grpc-js/src/filter.ts | 3 +- packages/grpc-js/src/http_proxy.ts | 12 ++- packages/grpc-js/src/index.ts | 9 +- .../src/load-balancer-child-handler.ts | 6 +- .../grpc-js/src/load-balancer-pick-first.ts | 24 ++--- .../grpc-js/src/load-balancer-round-robin.ts | 24 ++--- packages/grpc-js/src/load-balancer.ts | 36 ++++--- packages/grpc-js/src/logging.ts | 13 ++- packages/grpc-js/src/make-client.ts | 2 +- .../grpc-js/src/max-message-size-filter.ts | 25 +++-- packages/grpc-js/src/metadata.ts | 2 +- packages/grpc-js/src/picker.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 10 +- packages/grpc-js/src/resolver-ip.ts | 41 ++++---- packages/grpc-js/src/resolver-uds.ts | 2 +- packages/grpc-js/src/resolver.ts | 6 +- .../grpc-js/src/resolving-load-balancer.ts | 42 ++++++--- packages/grpc-js/src/server-call.ts | 6 +- packages/grpc-js/src/server.ts | 15 ++- packages/grpc-js/src/service-config.ts | 26 +++-- packages/grpc-js/src/subchannel-pool.ts | 8 +- packages/grpc-js/src/subchannel.ts | 44 ++++++--- 33 files changed, 399 insertions(+), 201 deletions(-) diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts index 53bdba2f1..5c746297e 100644 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ b/packages/grpc-js/src/call-credentials-filter.ts @@ -66,7 +66,9 @@ export class CallCredentialsFilter extends BaseFilter implements Filter { Status.INTERNAL, '"authorization" metadata cannot have multiple values' ); - return Promise.reject('"authorization" metadata cannot have multiple values'); + return Promise.reject( + '"authorization" metadata cannot have multiple values' + ); } return resultMetadata; } diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 083ebe851..87121154d 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -57,7 +57,7 @@ interface SystemError extends Error { * Should do approximately the same thing as util.getSystemErrorName but the * TypeScript types don't have that function for some reason so I just made my * own. - * @param errno + * @param errno */ function getSystemErrorName(errno: number): string { for (const [name, num] of Object.entries(os.constants.errno)) { @@ -71,9 +71,10 @@ function getSystemErrorName(errno: number): string { export type Deadline = Date | number; function getMinDeadline(deadlineList: Deadline[]): Deadline { - let minValue: number = Infinity; + let minValue = Infinity; for (const deadline of deadlineList) { - const deadlineMsecs = deadline instanceof Date ? deadline.getTime() : deadline; + const deadlineMsecs = + deadline instanceof Date ? deadline.getTime() : deadline; if (deadlineMsecs < minValue) { minValue = deadlineMsecs; } @@ -265,7 +266,10 @@ export class Http2CallStream implements Call { metadata: new Metadata(), }); }; - if (this.options.parentCall && this.options.flags & Propagate.CANCELLATION) { + if ( + this.options.parentCall && + this.options.flags & Propagate.CANCELLATION + ) { this.options.parentCall.on('cancelled', () => { this.cancelWithStatus(Status.CANCELLED, 'Cancelled by parent call'); }); @@ -464,7 +468,9 @@ export class Http2CallStream implements Call { subchannel: Subchannel, extraFilters: FilterFactory[] ): void { - this.filterStack.push(extraFilters.map(filterFactory => filterFactory.createFilter(this))); + this.filterStack.push( + extraFilters.map((filterFactory) => filterFactory.createFilter(this)) + ); if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { @@ -548,7 +554,7 @@ export class Http2CallStream implements Call { stream.on('close', () => { /* Use process.next tick to ensure that this code happens after any * "error" event that may be emitted at about the same time, so that - * we can bubble up the error message from that event. */ + * we can bubble up the error message from that event. */ process.nextTick(() => { this.trace('HTTP/2 stream closed with code ' + stream.rstCode); /* If we have a final status with an OK status code, that means that @@ -629,7 +635,16 @@ export class Http2CallStream implements Call { * https://github.com/nodejs/node/blob/8b8620d580314050175983402dfddf2674e8e22a/lib/internal/http2/core.js#L2267 */ if (err.code !== 'ERR_HTTP2_STREAM_ERROR') { - this.trace('Node error event: message=' + err.message + ' code=' + err.code + ' errno=' + getSystemErrorName(err.errno) + ' syscall=' + err.syscall); + this.trace( + 'Node error event: message=' + + err.message + + ' code=' + + err.code + + ' errno=' + + getSystemErrorName(err.errno) + + ' syscall=' + + err.syscall + ); this.internalError = err; } }); diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index cfe37ecfb..fcc3159db 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -81,7 +81,8 @@ export function callErrorFromStatus(status: StatusObject): ServiceError { return Object.assign(new Error(message), status); } -export class ClientUnaryCallImpl extends EventEmitter +export class ClientUnaryCallImpl + extends EventEmitter implements ClientUnaryCall { public call?: InterceptingCallInterface; constructor() { @@ -97,7 +98,8 @@ export class ClientUnaryCallImpl extends EventEmitter } } -export class ClientReadableStreamImpl extends Readable +export class ClientReadableStreamImpl + extends Readable implements ClientReadableStream { public call?: InterceptingCallInterface; constructor(readonly deserialize: (chunk: Buffer) => ResponseType) { @@ -117,7 +119,8 @@ export class ClientReadableStreamImpl extends Readable } } -export class ClientWritableStreamImpl extends Writable +export class ClientWritableStreamImpl + extends Writable implements ClientWritableStream { public call?: InterceptingCallInterface; constructor(readonly serialize: (value: RequestType) => Buffer) { @@ -149,7 +152,8 @@ export class ClientWritableStreamImpl extends Writable } } -export class ClientDuplexStreamImpl extends Duplex +export class ClientDuplexStreamImpl + extends Duplex implements ClientDuplexStream { public call?: InterceptingCallInterface; constructor( diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index ebb724b0e..604fd8685 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -37,6 +37,7 @@ export interface ChannelOptions { 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; 'grpc-node.max_session_memory'?: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; } diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 58726ccc7..9200043e4 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -33,9 +33,14 @@ import { FilterStackFactory } from './filter-stack'; import { CallCredentialsFilterFactory } from './call-credentials-filter'; import { DeadlineFilterFactory } from './deadline-filter'; import { CompressionFilterFactory } from './compression-filter'; -import { CallConfig, ConfigSelector, getDefaultAuthority, mapUriDefaultScheme } from './resolver'; +import { + CallConfig, + ConfigSelector, + getDefaultAuthority, + mapUriDefaultScheme, +} from './resolver'; import { trace, log } from './logging'; -import { SubchannelAddress } from "./subchannel-address"; +import { SubchannelAddress } from './subchannel-address'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; @@ -253,8 +258,8 @@ export class ChannelImplementation implements Channel { process.nextTick(() => { const localQueue = this.configSelectionQueue; this.configSelectionQueue = []; - this.callRefTimerUnref() - for (const {callStream, callMetadata} of localQueue) { + this.callRefTimerUnref(); + for (const { callStream, callMetadata } of localQueue) { this.tryGetConfig(callStream, callMetadata); } this.configSelectionQueue = []; @@ -262,15 +267,21 @@ export class ChannelImplementation implements Channel { }, (status) => { if (this.configSelectionQueue.length > 0) { - trace(LogVerbosity.DEBUG, 'channel', 'Name resolution failed for target ' + uriToString(this.target) + ' with calls queued for config selection'); + trace( + LogVerbosity.DEBUG, + 'channel', + 'Name resolution failed for target ' + + uriToString(this.target) + + ' with calls queued for config selection' + ); } const localQueue = this.configSelectionQueue; this.configSelectionQueue = []; this.callRefTimerUnref(); - for (const {callStream, callMetadata} of localQueue) { + for (const { callStream, callMetadata } of localQueue) { if (callMetadata.getOptions().waitForReady) { this.callRefTimerRef(); - this.configSelectionQueue.push({callStream, callMetadata}); + this.configSelectionQueue.push({ callStream, callMetadata }); } else { callStream.cancelWithStatus(status.code, status.details); } @@ -288,20 +299,38 @@ export class ChannelImplementation implements Channel { private callRefTimerRef() { // If the hasRef function does not exist, always run the code if (!this.callRefTimer.hasRef?.()) { - trace(LogVerbosity.DEBUG, 'channel', 'callRefTimer.ref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + this.pickQueue.length); + trace( + LogVerbosity.DEBUG, + 'channel', + 'callRefTimer.ref | configSelectionQueue.length=' + + this.configSelectionQueue.length + + ' pickQueue.length=' + + this.pickQueue.length + ); this.callRefTimer.ref?.(); } } private callRefTimerUnref() { // If the hasRef function does not exist, always run the code - if ((!this.callRefTimer.hasRef) || (this.callRefTimer.hasRef())) { - trace(LogVerbosity.DEBUG, 'channel', 'callRefTimer.unref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + this.pickQueue.length); + if (!this.callRefTimer.hasRef || this.callRefTimer.hasRef()) { + trace( + LogVerbosity.DEBUG, + 'channel', + 'callRefTimer.unref | configSelectionQueue.length=' + + this.configSelectionQueue.length + + ' pickQueue.length=' + + this.pickQueue.length + ); this.callRefTimer.unref?.(); } } - private pushPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { + private pushPick( + callStream: Http2CallStream, + callMetadata: Metadata, + callConfig: CallConfig + ) { this.pickQueue.push({ callStream, callMetadata, callConfig }); this.callRefTimerRef(); } @@ -313,8 +342,15 @@ export class ChannelImplementation implements Channel { * @param callStream * @param callMetadata */ - private tryPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { - const pickResult = this.currentPicker.pick({ metadata: callMetadata, extraPickInfo: callConfig.pickInformation }); + private tryPick( + callStream: Http2CallStream, + callMetadata: Metadata, + callConfig: CallConfig + ) { + const pickResult = this.currentPicker.pick({ + metadata: callMetadata, + extraPickInfo: callConfig.pickInformation, + }); trace( LogVerbosity.DEBUG, 'channel', @@ -412,7 +448,9 @@ export class ChannelImplementation implements Channel { ); callStream.cancelWithStatus( Status.INTERNAL, - `Failed to start HTTP/2 stream with error: ${(error as Error).message}` + `Failed to start HTTP/2 stream with error: ${ + (error as Error).message + }` ); } } @@ -434,7 +472,7 @@ export class ChannelImplementation implements Channel { (error: Error & { code: number }) => { // We assume the error code isn't 0 (Status.OK) callStream.cancelWithStatus( - (typeof error.code === 'number') ? error.code : Status.UNKNOWN, + typeof error.code === 'number' ? error.code : Status.UNKNOWN, `Getting metadata from plugin failed with error: ${error.message}` ); } @@ -492,7 +530,7 @@ export class ChannelImplementation implements Channel { const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { if (newState !== watcherObject.currentState) { - if(watcherObject.timer) { + if (watcherObject.timer) { clearTimeout(watcherObject.timer); } this.removeConnectivityStateWatcher(watcherObject); @@ -513,9 +551,9 @@ export class ChannelImplementation implements Channel { * ResolvingLoadBalancer may be idle and if so it needs to be kicked * because it now has a pending request. */ this.resolvingLoadBalancer.exitIdle(); - this.configSelectionQueue.push({ + this.configSelectionQueue.push({ callStream: stream, - callMetadata: metadata + callMetadata: metadata, }); this.callRefTimerRef(); } else { @@ -523,15 +561,23 @@ export class ChannelImplementation implements Channel { if (callConfig.status === Status.OK) { if (callConfig.methodConfig.timeout) { const deadline = new Date(); - deadline.setSeconds(deadline.getSeconds() + callConfig.methodConfig.timeout.seconds); - deadline.setMilliseconds(deadline.getMilliseconds() + callConfig.methodConfig.timeout.nanos / 1_000_000); + deadline.setSeconds( + deadline.getSeconds() + callConfig.methodConfig.timeout.seconds + ); + deadline.setMilliseconds( + deadline.getMilliseconds() + + callConfig.methodConfig.timeout.nanos / 1_000_000 + ); stream.setConfigDeadline(deadline); // Refreshing the filters makes the deadline filter pick up the new deadline stream.filterStack.refresh(); } this.tryPick(stream, metadata, callConfig); } else { - stream.cancelWithStatus(callConfig.status, "Failed to route call to method " + stream.getMethod()); + stream.cancelWithStatus( + callConfig.status, + 'Failed to route call to method ' + stream.getMethod() + ); } } } @@ -569,7 +615,7 @@ export class ChannelImplementation implements Channel { throw new Error('Channel has been shut down'); } let timer = null; - if(deadline !== Infinity) { + if (deadline !== Infinity) { const deadlineDate: Date = deadline instanceof Date ? deadline : new Date(deadline); const now = new Date(); @@ -585,12 +631,12 @@ export class ChannelImplementation implements Channel { callback( new Error('Deadline passed without connectivity state change') ); - }, deadlineDate.getTime() - now.getTime()) + }, deadlineDate.getTime() - now.getTime()); } const watcherObject = { currentState, callback, - timer + timer, }; this.connectivityStateWatchers.push(watcherObject); } diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index a7cc2f878..5dfbeba14 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -348,7 +348,10 @@ class BaseInterceptingCall implements InterceptingCallInterface { try { serialized = this.methodDefinition.requestSerialize(message); } catch (e) { - this.call.cancelWithStatus(Status.INTERNAL, `Request message serialization failure: ${e.message}`); + this.call.cancelWithStatus( + Status.INTERNAL, + `Request message serialization failure: ${e.message}` + ); return; } this.call.sendMessageWithContext(context, serialized); @@ -403,7 +406,8 @@ class BaseInterceptingCall implements InterceptingCallInterface { * BaseInterceptingCall with special-cased behavior for methods with unary * responses. */ -class BaseUnaryInterceptingCall extends BaseInterceptingCall +class BaseUnaryInterceptingCall + extends BaseInterceptingCall implements InterceptingCallInterface { // eslint-disable-next-line @typescript-eslint/no-explicit-any constructor(call: Call, methodDefinition: ClientMethodDefinition) { @@ -435,7 +439,8 @@ class BaseUnaryInterceptingCall extends BaseInterceptingCall * BaseInterceptingCall with special-cased behavior for methods with streaming * responses. */ -class BaseStreamingInterceptingCall extends BaseInterceptingCall +class BaseStreamingInterceptingCall + extends BaseInterceptingCall implements InterceptingCallInterface {} function getBottomInterceptingCall( diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index d19fe7d07..ed9407cd8 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -31,7 +31,7 @@ import { import { CallCredentials } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ChannelImplementation } from './channel'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; import { Status } from './constants'; @@ -56,7 +56,9 @@ const INTERCEPTOR_SYMBOL = Symbol(); const INTERCEPTOR_PROVIDER_SYMBOL = Symbol(); const CALL_INVOCATION_TRANSFORMER_SYMBOL = Symbol(); -function isFunction(arg: Metadata | CallOptions | UnaryCallback | undefined): arg is UnaryCallback{ +function isFunction( + arg: Metadata | CallOptions | UnaryCallback | undefined +): arg is UnaryCallback { return typeof arg === 'function'; } @@ -266,9 +268,11 @@ export class Client { options?: CallOptions | UnaryCallback, callback?: UnaryCallback ): ClientUnaryCall { - const checkedArguments = this.checkOptionalUnaryResponseArguments< - ResponseType - >(metadata, options, callback); + const checkedArguments = this.checkOptionalUnaryResponseArguments( + metadata, + options, + callback + ); const methodDefinition: ClientMethodDefinition< RequestType, ResponseType @@ -382,9 +386,11 @@ export class Client { options?: CallOptions | UnaryCallback, callback?: UnaryCallback ): ClientWritableStream { - const checkedArguments = this.checkOptionalUnaryResponseArguments< - ResponseType - >(metadata, options, callback); + const checkedArguments = this.checkOptionalUnaryResponseArguments( + metadata, + options, + callback + ); const methodDefinition: ClientMethodDefinition< RequestType, ResponseType @@ -408,9 +414,7 @@ export class Client { callProperties ) as CallProperties; } - const emitter: ClientWritableStream = callProperties.call as ClientWritableStream< - RequestType - >; + const emitter: ClientWritableStream = callProperties.call as ClientWritableStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], @@ -532,9 +536,7 @@ export class Client { callProperties ) as CallProperties; } - const stream: ClientReadableStream = callProperties.call as ClientReadableStream< - ResponseType - >; + const stream: ClientReadableStream = callProperties.call as ClientReadableStream; const interceptorArgs: InterceptorArguments = { clientInterceptors: this[INTERCEPTOR_SYMBOL], clientInterceptorProviders: this[INTERCEPTOR_PROVIDER_SYMBOL], @@ -659,7 +661,7 @@ export class Client { stream.emit('metadata', metadata); }, onReceiveMessage(message: Buffer) { - stream.push(message) + stream.push(message); }, onReceiveStatus(status: StatusObject) { if (receivedStatus) { @@ -676,4 +678,3 @@ export class Client { return stream; } } - diff --git a/packages/grpc-js/src/connectivity-state.ts b/packages/grpc-js/src/connectivity-state.ts index 8e1812274..560ab9c39 100644 --- a/packages/grpc-js/src/connectivity-state.ts +++ b/packages/grpc-js/src/connectivity-state.ts @@ -20,5 +20,5 @@ export enum ConnectivityState { CONNECTING, READY, TRANSIENT_FAILURE, - SHUTDOWN + SHUTDOWN, } diff --git a/packages/grpc-js/src/constants.ts b/packages/grpc-js/src/constants.ts index 94763cfe1..865b24c94 100644 --- a/packages/grpc-js/src/constants.ts +++ b/packages/grpc-js/src/constants.ts @@ -52,7 +52,11 @@ export enum Propagate { CENSUS_TRACING_CONTEXT = 4, CANCELLATION = 8, // https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/propagation_bits.h#L43 - DEFAULTS = 0xffff | Propagate.DEADLINE | Propagate.CENSUS_STATS_CONTEXT | Propagate.CENSUS_TRACING_CONTEXT | Propagate.CANCELLATION, + DEFAULTS = 0xffff | + Propagate.DEADLINE | + Propagate.CENSUS_STATS_CONTEXT | + Propagate.CENSUS_TRACING_CONTEXT | + Propagate.CANCELLATION, } // -1 means unlimited diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts index afc015546..7bdd764f2 100644 --- a/packages/grpc-js/src/deadline-filter.ts +++ b/packages/grpc-js/src/deadline-filter.ts @@ -42,7 +42,7 @@ function getDeadline(deadline: number) { export class DeadlineFilter extends BaseFilter implements Filter { private timer: NodeJS.Timer | null = null; - private deadline: number = Infinity; + private deadline = Infinity; constructor( private readonly channel: Channel, private readonly callStream: Call @@ -66,7 +66,7 @@ export class DeadlineFilter extends BaseFilter implements Filter { clearTimeout(this.timer); } const now: number = new Date().getTime(); - let timeout = this.deadline - now; + const timeout = this.deadline - now; if (timeout <= 0) { process.nextTick(() => { this.callStream.cancelWithStatus( diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 438ca71a8..24b795f06 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -1,12 +1,34 @@ -export { trace } from './logging'; -export { Resolver, ResolverListener, registerResolver, ConfigSelector } from './resolver'; -export { GrpcUri, uriToString } from './uri-parser'; -export { ServiceConfig, Duration } from './service-config'; -export { BackoffTimeout } from './backoff-timeout'; -export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig } from './load-balancer'; -export { SubchannelAddress, subchannelAddressToString } from './subchannel-address'; -export { ChildLoadBalancerHandler } from './load-balancer-child-handler'; -export { Picker, UnavailablePicker, QueuePicker, PickResult, PickArgs, PickResultType } from './picker'; -export { Call as CallStream } from './call-stream'; -export { Filter, BaseFilter, FilterFactory } from './filter'; -export { FilterStackFactory } from './filter-stack'; \ No newline at end of file +export { trace } from './logging'; +export { + Resolver, + ResolverListener, + registerResolver, + ConfigSelector, +} from './resolver'; +export { GrpcUri, uriToString } from './uri-parser'; +export { ServiceConfig, Duration } from './service-config'; +export { BackoffTimeout } from './backoff-timeout'; +export { + LoadBalancer, + LoadBalancingConfig, + ChannelControlHelper, + registerLoadBalancerType, + getFirstUsableConfig, + validateLoadBalancingConfig, +} from './load-balancer'; +export { + SubchannelAddress, + subchannelAddressToString, +} from './subchannel-address'; +export { ChildLoadBalancerHandler } from './load-balancer-child-handler'; +export { + Picker, + UnavailablePicker, + QueuePicker, + PickResult, + PickArgs, + PickResultType, +} from './picker'; +export { Call as CallStream } from './call-stream'; +export { Filter, BaseFilter, FilterFactory } from './filter'; +export { FilterStackFactory } from './filter-stack'; diff --git a/packages/grpc-js/src/filter.ts b/packages/grpc-js/src/filter.ts index eb67bd32e..8475a0a5a 100644 --- a/packages/grpc-js/src/filter.ts +++ b/packages/grpc-js/src/filter.ts @@ -57,8 +57,7 @@ export abstract class BaseFilter implements Filter { return status; } - refresh(): void { - } + refresh(): void {} } export interface FilterFactory { diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index d62be597c..149aa3648 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -25,8 +25,8 @@ import * as logging from './logging'; import { SubchannelAddress, isTcpSubchannelAddress, - subchannelAddressToString -} from "./subchannel-address"; + subchannelAddressToString, +} from './subchannel-address'; import { ChannelOptions } from './channel-options'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { URL } from 'url'; @@ -93,7 +93,7 @@ function getProxyInfo(): ProxyInfo { port = '80'; } const result: ProxyInfo = { - address: `${hostname}:${port}` + address: `${hostname}:${port}`, }; if (userCred) { result.creds = userCred; @@ -147,7 +147,9 @@ export function mapProxyName( const serverHost = hostPort.host; for (const host of getNoProxyHostList()) { if (host === serverHost) { - trace('Not using proxy for target in no_proxy list: ' + uriToString(target)); + trace( + 'Not using proxy for target in no_proxy list: ' + uriToString(target) + ); return noProxyResult; } } @@ -226,7 +228,7 @@ export function getProxiedConnection( const targetPath = getDefaultAuthority(parsedTarget); const hostPort = splitHostPort(targetPath); const remoteHost = hostPort?.host ?? targetPath; - + const cts = tls.connect( { host: remoteHost, diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 52c122b12..0730a26eb 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -25,7 +25,7 @@ import { import { CallCredentials, OAuth2Client } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ChannelImplementation } from './channel'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { ChannelCredentials } from './channel-credentials'; import { CallOptions, @@ -183,7 +183,12 @@ export { /**** Server ****/ -export { handleBidiStreamingCall, handleServerStreamingCall, handleUnaryCall, handleClientStreamingCall }; +export { + handleBidiStreamingCall, + handleServerStreamingCall, + handleUnaryCall, + handleClientStreamingCall, +}; /* eslint-disable @typescript-eslint/no-explicit-any */ export type Call = diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 25cba4528..8fae7b8a6 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -19,12 +19,12 @@ import { LoadBalancer, ChannelControlHelper, LoadBalancingConfig, - createLoadBalancer + createLoadBalancer, } from './load-balancer'; import { Subchannel } from './subchannel'; -import { SubchannelAddress } from "./subchannel-address"; +import { SubchannelAddress } from './subchannel-address'; import { ChannelOptions } from './channel-options'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; const TYPE_NAME = 'child_load_balancer_helper'; diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index f7e9dd917..65179b163 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -19,10 +19,10 @@ import { LoadBalancer, ChannelControlHelper, LoadBalancingConfig, - registerDefaultLoadBalancerType, - registerLoadBalancerType + registerDefaultLoadBalancerType, + registerLoadBalancerType, } from './load-balancer'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { QueuePicker, Picker, @@ -31,14 +31,11 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { - Subchannel, - ConnectivityStateListener, -} from './subchannel'; +import { Subchannel, ConnectivityStateListener } from './subchannel'; import { SubchannelAddress, - subchannelAddressToString -} from "./subchannel-address"; + subchannelAddressToString, +} from './subchannel-address'; import * as logging from './logging'; import { LogVerbosity } from './constants'; @@ -65,10 +62,11 @@ export class PickFirstLoadBalancingConfig implements LoadBalancingConfig { toJsonObject(): object { return { - [TYPE_NAME]: {} + [TYPE_NAME]: {}, }; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any static createFromJson(obj: any) { return new PickFirstLoadBalancingConfig(); } @@ -460,6 +458,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { } export function setup(): void { - registerLoadBalancerType(TYPE_NAME, PickFirstLoadBalancer, PickFirstLoadBalancingConfig); + registerLoadBalancerType( + TYPE_NAME, + PickFirstLoadBalancer, + PickFirstLoadBalancingConfig + ); registerDefaultLoadBalancerType(TYPE_NAME); } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index fabd334e3..56703397f 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -19,9 +19,9 @@ import { LoadBalancer, ChannelControlHelper, LoadBalancingConfig, - registerLoadBalancerType + registerLoadBalancerType, } from './load-balancer'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { QueuePicker, Picker, @@ -30,14 +30,11 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { - Subchannel, - ConnectivityStateListener, -} from './subchannel'; +import { Subchannel, ConnectivityStateListener } from './subchannel'; import { SubchannelAddress, - subchannelAddressToString -} from "./subchannel-address"; + subchannelAddressToString, +} from './subchannel-address'; import * as logging from './logging'; import { LogVerbosity } from './constants'; @@ -58,10 +55,11 @@ class RoundRobinLoadBalancingConfig implements LoadBalancingConfig { toJsonObject(): object { return { - [TYPE_NAME]: {} + [TYPE_NAME]: {}, }; } + // eslint-disable-next-line @typescript-eslint/no-explicit-any static createFromJson(obj: any) { return new RoundRobinLoadBalancingConfig(); } @@ -130,7 +128,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { this.subchannelStateCounts[previousState] -= 1; this.subchannelStateCounts[newState] += 1; this.calculateAndUpdateState(); - + if ( newState === ConnectivityState.TRANSIENT_FAILURE || newState === ConnectivityState.IDLE @@ -249,5 +247,9 @@ export class RoundRobinLoadBalancer implements LoadBalancer { } export function setup() { - registerLoadBalancerType(TYPE_NAME, RoundRobinLoadBalancer, RoundRobinLoadBalancingConfig); + registerLoadBalancerType( + TYPE_NAME, + RoundRobinLoadBalancer, + RoundRobinLoadBalancingConfig + ); } diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 7fe0b9b3d..f509f73eb 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -17,8 +17,8 @@ import { ChannelOptions } from './channel-options'; import { Subchannel } from './subchannel'; -import { SubchannelAddress } from "./subchannel-address"; -import { ConnectivityState } from "./connectivity-state"; +import { SubchannelAddress } from './subchannel-address'; +import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; /** @@ -101,7 +101,9 @@ export interface LoadBalancingConfig { } export interface LoadBalancingConfigConstructor { - new(...args: any): LoadBalancingConfig; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + new (...args: any): LoadBalancingConfig; + // eslint-disable-next-line @typescript-eslint/no-explicit-any createFromJson(obj: any): LoadBalancingConfig; } @@ -121,7 +123,7 @@ export function registerLoadBalancerType( ) { registeredLoadBalancerTypes[typeName] = { LoadBalancer: loadBalancerType, - LoadBalancingConfig: loadBalancingConfigType + LoadBalancingConfig: loadBalancingConfigType, }; } @@ -135,7 +137,9 @@ export function createLoadBalancer( ): LoadBalancer | null { const typeName = config.getLoadBalancerName(); if (typeName in registeredLoadBalancerTypes) { - return new registeredLoadBalancerTypes[typeName].LoadBalancer(channelControlHelper); + return new registeredLoadBalancerTypes[typeName].LoadBalancer( + channelControlHelper + ); } else { return null; } @@ -145,10 +149,13 @@ export function isLoadBalancerNameRegistered(typeName: string): boolean { return typeName in registeredLoadBalancerTypes; } -export function getFirstUsableConfig(configs: LoadBalancingConfig[], fallbackTodefault?: true): LoadBalancingConfig; export function getFirstUsableConfig( configs: LoadBalancingConfig[], - fallbackTodefault: boolean = false + fallbackTodefault?: true +): LoadBalancingConfig; +export function getFirstUsableConfig( + configs: LoadBalancingConfig[], + fallbackTodefault = false ): LoadBalancingConfig | null { for (const config of configs) { if (config.getLoadBalancerName() in registeredLoadBalancerTypes) { @@ -157,7 +164,9 @@ export function getFirstUsableConfig( } if (fallbackTodefault) { if (defaultLoadBalancerType) { - return new registeredLoadBalancerTypes[defaultLoadBalancerType]!.LoadBalancingConfig(); + return new registeredLoadBalancerTypes[ + defaultLoadBalancerType + ]!.LoadBalancingConfig(); } else { return null; } @@ -166,17 +175,22 @@ export function getFirstUsableConfig( } } +// eslint-disable-next-line @typescript-eslint/no-explicit-any export function validateLoadBalancingConfig(obj: any): LoadBalancingConfig { - if (!(obj !== null && (typeof obj === 'object'))) { + if (!(obj !== null && typeof obj === 'object')) { throw new Error('Load balancing config must be an object'); } const keys = Object.keys(obj); if (keys.length !== 1) { - throw new Error('Provided load balancing config has multiple conflicting entries'); + throw new Error( + 'Provided load balancing config has multiple conflicting entries' + ); } const typeName = keys[0]; if (typeName in registeredLoadBalancerTypes) { - return registeredLoadBalancerTypes[typeName].LoadBalancingConfig.createFromJson(obj[typeName]); + return registeredLoadBalancerTypes[ + typeName + ].LoadBalancingConfig.createFromJson(obj[typeName]); } else { throw new Error(`Unrecognized load balancing config name ${typeName}`); } diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 71683dbf7..352496240 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -20,7 +20,8 @@ import { LogVerbosity } from './constants'; let _logger: Partial = console; let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; -const verbosityString = process.env.GRPC_NODE_VERBOSITY ?? process.env.GRPC_VERBOSITY ?? ''; +const verbosityString = + process.env.GRPC_NODE_VERBOSITY ?? process.env.GRPC_VERBOSITY ?? ''; switch (verbosityString.toUpperCase()) { case 'DEBUG': @@ -58,14 +59,15 @@ export const log = (severity: LogVerbosity, ...args: any[]): void => { } }; -const tracersString = process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; +const tracersString = + process.env.GRPC_NODE_TRACE ?? process.env.GRPC_TRACE ?? ''; const enabledTracers = new Set(); const disabledTracers = new Set(); for (const tracerName of tracersString.split(',')) { if (tracerName.startsWith('-')) { disabledTracers.add(tracerName.substring(1)); } else { - enabledTracers.add(tracerName) + enabledTracers.add(tracerName); } } const allEnabled = enabledTracers.has('all'); @@ -75,7 +77,10 @@ export function trace( tracer: string, text: string ): void { - if (!disabledTracers.has(tracer) && (allEnabled || enabledTracers.has(tracer))) { + if ( + !disabledTracers.has(tracer) && + (allEnabled || enabledTracers.has(tracer)) + ) { log(severity, new Date().toISOString() + ' | ' + tracer + ' | ' + text); } } diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index a6cb91007..b8ddda29f 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -98,7 +98,7 @@ export interface ServiceClientConstructor { * keys. * @param key key for check, string. */ -function isPrototypePolluted(key: string): Boolean { +function isPrototypePolluted(key: string): boolean { return ['__proto__', 'prototype', 'constructor'].includes(key); } diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts index f820c02e6..9a3bc9c0a 100644 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -15,10 +15,14 @@ * */ -import { BaseFilter, Filter, FilterFactory } from "./filter"; -import { Call, WriteObject } from "./call-stream"; -import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH } from "./constants"; -import { ChannelOptions } from "./channel-options"; +import { BaseFilter, Filter, FilterFactory } from './filter'; +import { Call, WriteObject } from './call-stream'; +import { + Status, + DEFAULT_MAX_SEND_MESSAGE_LENGTH, + DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, +} from './constants'; +import { ChannelOptions } from './channel-options'; export class MaxMessageSizeFilter extends BaseFilter implements Filter { private maxSendMessageSize: number = DEFAULT_MAX_SEND_MESSAGE_LENGTH; @@ -44,7 +48,10 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } else { const concreteMessage = await message; if (concreteMessage.message.length > this.maxSendMessageSize) { - this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})`); + this.callStream.cancelWithStatus( + Status.RESOURCE_EXHAUSTED, + `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})` + ); return Promise.reject('Message too large'); } else { return concreteMessage; @@ -60,7 +67,10 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } else { const concreteMessage = await message; if (concreteMessage.length > this.maxReceiveMessageSize) { - this.callStream.cancelWithStatus(Status.RESOURCE_EXHAUSTED, `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})`); + this.callStream.cancelWithStatus( + Status.RESOURCE_EXHAUSTED, + `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})` + ); return Promise.reject('Message too large'); } else { return concreteMessage; @@ -69,7 +79,8 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } } -export class MaxMessageSizeFilterFactory implements FilterFactory { +export class MaxMessageSizeFilterFactory + implements FilterFactory { constructor(private readonly options: ChannelOptions) {} createFilter(callStream: Call): MaxMessageSizeFilter { diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index bc66012ce..04db642ef 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -247,7 +247,7 @@ export class Metadata { * representation of the metadata map. */ toJSON() { - const result: {[key: string]: MetadataValue[]} = {}; + const result: { [key: string]: MetadataValue[] } = {}; for (const [key, values] of this.internalRepr.entries()) { result[key] = values; } diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 25929884b..7aeed89b3 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -85,7 +85,7 @@ export interface DropCallPickResult extends PickResult { export interface PickArgs { metadata: Metadata; - extraPickInfo: {[key: string]: string}; + extraPickInfo: { [key: string]: string }; } /** diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 44246c779..9077228b8 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -28,7 +28,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SubchannelAddress, TcpSubchannelAddress } from "./subchannel-address"; +import { SubchannelAddress, TcpSubchannelAddress } from './subchannel-address'; import { GrpcUri, uriToString, splitHostPort } from './uri-parser'; import { isIPv6, isIPv4 } from 'net'; import { ChannelOptions } from './channel-options'; @@ -129,7 +129,13 @@ class DnsResolver implements Resolver { if (this.ipResult !== null) { trace('Returning IP address for target ' + uriToString(this.target)); setImmediate(() => { - this.listener.onSuccessfulResolution(this.ipResult!, null, null, null, {}); + this.listener.onSuccessfulResolution( + this.ipResult!, + null, + null, + null, + {} + ); }); return; } diff --git a/packages/grpc-js/src/resolver-ip.ts b/packages/grpc-js/src/resolver-ip.ts index 18bbe54aa..24efc3fdc 100644 --- a/packages/grpc-js/src/resolver-ip.ts +++ b/packages/grpc-js/src/resolver-ip.ts @@ -14,14 +14,14 @@ * limitations under the License. */ -import { isIPv4, isIPv6 } from "net"; -import { StatusObject } from "./call-stream"; -import { ChannelOptions } from "./channel-options"; -import { LogVerbosity, Status } from "./constants"; -import { Metadata } from "./metadata"; -import { registerResolver, Resolver, ResolverListener } from "./resolver"; -import { SubchannelAddress } from "./subchannel-address"; -import { GrpcUri, splitHostPort, uriToString } from "./uri-parser"; +import { isIPv4, isIPv6 } from 'net'; +import { StatusObject } from './call-stream'; +import { ChannelOptions } from './channel-options'; +import { LogVerbosity, Status } from './constants'; +import { Metadata } from './metadata'; +import { registerResolver, Resolver, ResolverListener } from './resolver'; +import { SubchannelAddress } from './subchannel-address'; +import { GrpcUri, splitHostPort, uriToString } from './uri-parser'; import * as logging from './logging'; const TRACER_NAME = 'ip_resolver'; @@ -52,7 +52,7 @@ class IpResolver implements Resolver { this.error = { code: Status.UNAVAILABLE, details: `Unrecognized scheme ${target.scheme} in IP resolver`, - metadata: new Metadata() + metadata: new Metadata(), }; return; } @@ -63,21 +63,24 @@ class IpResolver implements Resolver { this.error = { code: Status.UNAVAILABLE, details: `Failed to parse ${target.scheme} address ${path}`, - metadata: new Metadata() + metadata: new Metadata(), }; return; } - if ((target.scheme === IPV4_SCHEME && !isIPv4(hostPort.host)) || (target.scheme === IPV6_SCHEME && !isIPv6(hostPort.host))) { + if ( + (target.scheme === IPV4_SCHEME && !isIPv4(hostPort.host)) || + (target.scheme === IPV6_SCHEME && !isIPv6(hostPort.host)) + ) { this.error = { code: Status.UNAVAILABLE, details: `Failed to parse ${target.scheme} address ${path}`, - metadata: new Metadata() + metadata: new Metadata(), }; return; } addresses.push({ host: hostPort.host, - port: hostPort.port ?? DEFAULT_PORT + port: hostPort.port ?? DEFAULT_PORT, }); } this.addresses = addresses; @@ -86,9 +89,15 @@ class IpResolver implements Resolver { updateResolution(): void { process.nextTick(() => { if (this.error) { - this.listener.onError(this.error) + this.listener.onError(this.error); } else { - this.listener.onSuccessfulResolution(this.addresses, null, null, null, {}); + this.listener.onSuccessfulResolution( + this.addresses, + null, + null, + null, + {} + ); } }); } @@ -104,4 +113,4 @@ class IpResolver implements Resolver { export function setup() { registerResolver(IPV4_SCHEME, IpResolver); registerResolver(IPV6_SCHEME, IpResolver); -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolver-uds.ts b/packages/grpc-js/src/resolver-uds.ts index 1c5a7a64c..24095ec29 100644 --- a/packages/grpc-js/src/resolver-uds.ts +++ b/packages/grpc-js/src/resolver-uds.ts @@ -15,7 +15,7 @@ */ import { Resolver, ResolverListener, registerResolver } from './resolver'; -import { SubchannelAddress } from "./subchannel-address"; +import { SubchannelAddress } from './subchannel-address'; import { GrpcUri } from './uri-parser'; import { ChannelOptions } from './channel-options'; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 5bf7df2e7..59c5400f1 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -17,7 +17,7 @@ import { MethodConfig, ServiceConfig } from './service-config'; import { StatusObject } from './call-stream'; -import { SubchannelAddress } from "./subchannel-address"; +import { SubchannelAddress } from './subchannel-address'; import { GrpcUri, uriToString } from './uri-parser'; import { ChannelOptions } from './channel-options'; import { Metadata } from './metadata'; @@ -26,7 +26,7 @@ import { Status } from './constants'; export interface CallConfig { methodConfig: MethodConfig; onCommitted?: () => void; - pickInformation: {[key: string]: string}; + pickInformation: { [key: string]: string }; status: Status; } @@ -78,7 +78,7 @@ export interface Resolver { * called synchronously with the constructor or updateResolution. */ updateResolution(): void; - + /** * Destroy the resolver. Should be called when the owning channel shuts down. */ diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 9825086c1..5729937d1 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -19,10 +19,10 @@ import { ChannelControlHelper, LoadBalancer, LoadBalancingConfig, - getFirstUsableConfig + getFirstUsableConfig, } from './load-balancer'; import { ServiceConfig, validateServiceConfig } from './service-config'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { ConfigSelector, createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; @@ -32,7 +32,7 @@ import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { SubchannelAddress } from "./subchannel-address"; +import { SubchannelAddress } from './subchannel-address'; import { GrpcUri, uriToString } from './uri-parser'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { ChannelOptions } from './channel-options'; @@ -46,30 +46,38 @@ function trace(text: string): void { const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; -function getDefaultConfigSelector(serviceConfig: ServiceConfig | null): ConfigSelector { - return function defaultConfigSelector(methodName: string, metadata: Metadata) { - const splitName = methodName.split('/').filter(x => x.length > 0); +function getDefaultConfigSelector( + serviceConfig: ServiceConfig | null +): ConfigSelector { + return function defaultConfigSelector( + methodName: string, + metadata: Metadata + ) { + const splitName = methodName.split('/').filter((x) => x.length > 0); const service = splitName[0] ?? ''; const method = splitName[1] ?? ''; if (serviceConfig && serviceConfig.methodConfig) { for (const methodConfig of serviceConfig.methodConfig) { for (const name of methodConfig.name) { - if (name.service === service && (name.method === undefined || name.method === method)) { + if ( + name.service === service && + (name.method === undefined || name.method === method) + ) { return { methodConfig: methodConfig, pickInformation: {}, - status: Status.OK + status: Status.OK, }; } } } } return { - methodConfig: {name: []}, + methodConfig: { name: [] }, pickInformation: {}, - status: Status.OK + status: Status.OK, }; - } + }; } export interface ResolutionCallback { @@ -201,7 +209,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { } const workingConfigList = workingServiceConfig?.loadBalancingConfig ?? []; - const loadBalancingConfig = getFirstUsableConfig(workingConfigList, true); + const loadBalancingConfig = getFirstUsableConfig( + workingConfigList, + true + ); if (loadBalancingConfig === null) { // There were load balancing configs but none are supported. This counts as a resolution failure this.handleResolutionFailure({ @@ -217,8 +228,11 @@ export class ResolvingLoadBalancer implements LoadBalancer { loadBalancingConfig, attributes ); - const finalServiceConfig = workingServiceConfig ?? this.defaultServiceConfig; - this.onSuccessfulResolution(configSelector ?? getDefaultConfigSelector(finalServiceConfig)); + const finalServiceConfig = + workingServiceConfig ?? this.defaultServiceConfig; + this.onSuccessfulResolution( + configSelector ?? getDefaultConfigSelector(finalServiceConfig) + ); }, onError: (error: StatusObject) => { this.handleResolutionFailure(error); diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index aa8bd647e..4d24cdc86 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -100,7 +100,8 @@ export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & ObjectWritable & { end: (metadata?: Metadata) => void }; -export class ServerUnaryCallImpl extends EventEmitter +export class ServerUnaryCallImpl + extends EventEmitter implements ServerUnaryCall { cancelled: boolean; @@ -239,7 +240,8 @@ export class ServerWritableStreamImpl } } -export class ServerDuplexStreamImpl extends Duplex +export class ServerDuplexStreamImpl + extends Duplex implements ServerDuplexStream { cancelled: boolean; private trailingMetadata: Metadata; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index aec149556..017312219 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -55,8 +55,8 @@ import { SubchannelAddress, TcpSubchannelAddress, isTcpSubchannelAddress, - subchannelAddressToString -} from "./subchannel-address"; + subchannelAddressToString, +} from './subchannel-address'; import { parseUri } from './uri-parser'; const TRACER_NAME = 'server'; @@ -209,10 +209,7 @@ export class Server { } removeService(service: ServiceDefinition): void { - if ( - service === null || - typeof service !== 'object' - ) { + if (service === null || typeof service !== 'object') { throw new Error('removeService() requires object as argument'); } @@ -258,10 +255,12 @@ export class Server { } const serverOptions: http2.ServerOptions = { - maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER + maxSendHeaderBlockLength: Number.MAX_SAFE_INTEGER, }; if ('grpc-node.max_session_memory' in this.options) { - serverOptions.maxSessionMemory = this.options['grpc-node.max_session_memory']; + serverOptions.maxSessionMemory = this.options[ + 'grpc-node.max_session_memory' + ]; } if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index efc09f9c4..3f0a00868 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -27,7 +27,10 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as os from 'os'; -import { LoadBalancingConfig, validateLoadBalancingConfig } from './load-balancer'; +import { + LoadBalancingConfig, + validateLoadBalancingConfig, +} from './load-balancer'; export interface MethodConfigName { service: string; @@ -107,21 +110,30 @@ function validateMethodConfig(obj: any): MethodConfig { } if ('timeout' in obj) { if (typeof obj.timeout === 'object') { - if (!('seconds' in obj.timeout) || !(typeof obj.timeout.seconds === 'number')) { + if ( + !('seconds' in obj.timeout) || + !(typeof obj.timeout.seconds === 'number') + ) { throw new Error('Invalid method config: invalid timeout.seconds'); } - if (!('nanos' in obj.timeout) || !(typeof obj.timeout.nanos === 'number')) { + if ( + !('nanos' in obj.timeout) || + !(typeof obj.timeout.nanos === 'number') + ) { throw new Error('Invalid method config: invalid timeout.nanos'); } result.timeout = obj.timeout; } else if ( - (typeof obj.timeout === 'string') && TIMEOUT_REGEX.test(obj.timeout) + typeof obj.timeout === 'string' && + TIMEOUT_REGEX.test(obj.timeout) ) { - const timeoutParts = obj.timeout.substring(0, obj.timeout.length - 1).split('.'); + const timeoutParts = obj.timeout + .substring(0, obj.timeout.length - 1) + .split('.'); result.timeout = { seconds: timeoutParts[0] | 0, - nanos: (timeoutParts[1] ?? 0) | 0 - } + nanos: (timeoutParts[1] ?? 0) | 0, + }; } else { throw new Error('Invalid method config: invalid timeout'); } diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index 65c5f2177..cd74cad81 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -16,13 +16,11 @@ */ import { ChannelOptions, channelOptionsEqual } from './channel-options'; -import { - Subchannel, -} from './subchannel'; +import { Subchannel } from './subchannel'; import { SubchannelAddress, - subchannelAddressEqual -} from "./subchannel-address"; + subchannelAddressEqual, +} from './subchannel-address'; import { ChannelCredentials } from './channel-credentials'; import { GrpcUri, uriToString } from './uri-parser'; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 7d3e6e871..ae23feb3d 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -21,7 +21,7 @@ import { Metadata } from './metadata'; import { Http2CallStream } from './call-stream'; import { ChannelOptions } from './channel-options'; import { PeerCertificate, checkServerIdentity } from 'tls'; -import { ConnectivityState } from "./connectivity-state"; +import { ConnectivityState } from './connectivity-state'; import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; @@ -31,7 +31,10 @@ import * as net from 'net'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { ConnectionOptions } from 'tls'; import { FilterFactory, Filter } from './filter'; -import { SubchannelAddress, subchannelAddressToString } from './subchannel-address'; +import { + SubchannelAddress, + subchannelAddressToString, +} from './subchannel-address'; const clientVersion = require('../../package.json').version; @@ -138,7 +141,7 @@ export class Subchannel { /** * Indicates whether keepalive pings should be sent without any active calls */ - private keepaliveWithoutCalls: boolean = false; + private keepaliveWithoutCalls = false; /** * Tracks calls with references to this subchannel @@ -186,7 +189,8 @@ export class Subchannel { this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; } if ('grpc.keepalive_permit_without_calls' in options) { - this.keepaliveWithoutCalls = options['grpc.keepalive_permit_without_calls'] === 1; + this.keepaliveWithoutCalls = + options['grpc.keepalive_permit_without_calls'] === 1; } else { this.keepaliveWithoutCalls = false; } @@ -231,7 +235,11 @@ export class Subchannel { } private sendPing() { - logging.trace(LogVerbosity.DEBUG, 'keepalive', 'Sending ping to ' + this.subchannelAddressString); + logging.trace( + LogVerbosity.DEBUG, + 'keepalive', + 'Sending ping to ' + this.subchannelAddressString + ); this.keepaliveTimeoutId = setTimeout(() => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); @@ -247,7 +255,7 @@ export class Subchannel { this.keepaliveIntervalId = setInterval(() => { this.sendPing(); }, this.keepaliveTimeMs); - this.keepaliveIntervalId.unref?.() + this.keepaliveIntervalId.unref?.(); /* Don't send a ping immediately because whatever caused us to start * sending pings should also involve some network activity. */ } @@ -265,7 +273,9 @@ export class Subchannel { this.credentials._getConnectionOptions() || {}; connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; if ('grpc-node.max_session_memory' in this.options) { - connectionOptions.maxSessionMemory = this.options['grpc-node.max_session_memory']; + connectionOptions.maxSessionMemory = this.options[ + 'grpc-node.max_session_memory' + ]; } let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { @@ -387,7 +397,11 @@ export class Subchannel { ); logging.log( LogVerbosity.ERROR, - `Connection to ${uriToString(this.channelTarget)} at ${this.subchannelAddressString} rejected by server because of excess pings. Increasing ping interval to ${this.keepaliveTimeMs} ms` + `Connection to ${uriToString(this.channelTarget)} at ${ + this.subchannelAddressString + } rejected by server because of excess pings. Increasing ping interval to ${ + this.keepaliveTimeMs + } ms` ); } trace( @@ -553,10 +567,7 @@ export class Subchannel { * this subchannel, we can be sure it will never be used again. */ if (this.callRefcount === 0 && this.refcount === 0) { this.transitionToState( - [ - ConnectivityState.CONNECTING, - ConnectivityState.READY, - ], + [ConnectivityState.CONNECTING, ConnectivityState.READY], ConnectivityState.TRANSIENT_FAILURE ); } @@ -675,7 +686,14 @@ export class Subchannel { for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } - logging.trace(LogVerbosity.DEBUG, 'call_stream', 'Starting stream on subchannel ' + this.subchannelAddressString + ' with headers\n' + headersString); + logging.trace( + LogVerbosity.DEBUG, + 'call_stream', + 'Starting stream on subchannel ' + + this.subchannelAddressString + + ' with headers\n' + + headersString + ); callStream.attachHttp2Stream(http2Stream, this, extraFilterFactories); } From 728acf3853723642e6f3edf944ee3072e393e43e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 30 Jun 2021 14:52:55 -0700 Subject: [PATCH 1464/1899] grpc-js-xds: Increase interop test timeout --- test/kokoro/xds-interop.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 16a7dc7dc..a615d0530 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +timeout_mins: 180 action { define_artifacts { regex: "github/grpc/reports/**" From 972281770fd288330939764c7d4a5c6f39c28180 Mon Sep 17 00:00:00 2001 From: Eric Gribkoff Date: Thu, 1 Jul 2021 05:14:50 -0700 Subject: [PATCH 1465/1899] Increase xDS job timeouts to match Java and Go --- test/kokoro/xds-interop.cfg | 2 +- test/kokoro/xds-v3-interop.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index a615d0530..866cb4b58 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 180 +timeout_mins: 360 action { define_artifacts { regex: "github/grpc/reports/**" diff --git a/test/kokoro/xds-v3-interop.cfg b/test/kokoro/xds-v3-interop.cfg index 4480f1590..75377fe16 100644 --- a/test/kokoro/xds-v3-interop.cfg +++ b/test/kokoro/xds-v3-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds-v3.sh" -timeout_mins: 180 +timeout_mins: 360 action { define_artifacts { regex: "github/grpc/reports/**" From 6b3ebbb82921e1e42d8a0974a7e900ff606a66cc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Jul 2021 10:27:31 -0700 Subject: [PATCH 1466/1899] grpc-js: Add logging for TLS over proxy connection errors --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/http_proxy.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8acb8a145..97d7e2758 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.4", + "version": "1.3.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index f6921378b..8c461d4f8 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -244,7 +244,13 @@ export function getProxiedConnection( resolve({ socket: cts, realTarget: parsedTarget }); } ); - cts.on('error', () => { + cts.on('error', (error: Error) => { + trace('Failed to establish a TLS connection to ' + + options.path + + ' through proxy ' + + proxyAddressString + + ' with error ' + + error.message); reject(); }); } else { From 194aeec0513786cba009d0fc910ccba828ecca34 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Jul 2021 10:32:12 -0700 Subject: [PATCH 1467/1899] grpc-js-xds: Increase interop test timeout to 6 hours --- test/kokoro/xds-interop.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 16a7dc7dc..866cb4b58 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +timeout_mins: 360 action { define_artifacts { regex: "github/grpc/reports/**" From 0058ce04f877e8f6e13640bdf9ce26181cc9c6f3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Jul 2021 10:32:12 -0700 Subject: [PATCH 1468/1899] grpc-js-xds: Increase interop test timeout to 6 hours --- test/kokoro/xds-interop.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg index 16a7dc7dc..866cb4b58 100644 --- a/test/kokoro/xds-interop.cfg +++ b/test/kokoro/xds-interop.cfg @@ -16,7 +16,7 @@ # Location of the continuous shell script in repository. build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 120 +timeout_mins: 360 action { define_artifacts { regex: "github/grpc/reports/**" From dc438517621edfdbf86f5a7e9625bb7005a67b10 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 8 Jul 2021 10:27:31 -0700 Subject: [PATCH 1469/1899] grpc-js: Add logging for TLS over proxy connection errors --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/http_proxy.ts | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8acb8a145..97d7e2758 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.4", + "version": "1.3.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index f6921378b..8c461d4f8 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -244,7 +244,13 @@ export function getProxiedConnection( resolve({ socket: cts, realTarget: parsedTarget }); } ); - cts.on('error', () => { + cts.on('error', (error: Error) => { + trace('Failed to establish a TLS connection to ' + + options.path + + ' through proxy ' + + proxyAddressString + + ' with error ' + + error.message); reject(); }); } else { From 311aca31e411da18e542686665aa14711aa7ec3e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Jun 2021 09:45:19 -0700 Subject: [PATCH 1470/1899] grpc-js-xds: Add HTTP Filters support --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/environment.ts | 4 +- .../generated/google/protobuf/EnumOptions.ts | 3 - .../google/protobuf/EnumValueOptions.ts | 5 - .../generated/google/protobuf/FieldOptions.ts | 10 - .../generated/google/protobuf/FileOptions.ts | 6 - .../google/protobuf/MessageOptions.ts | 6 - .../grpc-js-xds/src/generated/typed_struct.ts | 74 ++++++ .../src/generated/udpa/type/v1/TypedStruct.ts | 77 ++++++ packages/grpc-js-xds/src/http-filter.ts | 221 ++++++++++++++++++ packages/grpc-js-xds/src/protobuf-any.ts | 23 ++ packages/grpc-js-xds/src/resolver-xds.ts | 139 ++++++++++- packages/grpc-js-xds/src/route-action.ts | 27 ++- .../src/xds-stream-state/lds-state.ts | 9 + .../src/xds-stream-state/rds-state.ts | 25 ++ packages/grpc-js/src/call-stream.ts | 4 + packages/grpc-js/src/channel.ts | 1 + packages/grpc-js/src/resolver.ts | 2 + .../grpc-js/src/resolving-load-balancer.ts | 6 +- 19 files changed, 596 insertions(+), 48 deletions(-) create mode 100644 packages/grpc-js-xds/src/generated/typed_struct.ts create mode 100644 packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts create mode 100644 packages/grpc-js-xds/src/http-filter.ts create mode 100644 packages/grpc-js-xds/src/protobuf-any.ts diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index f69c8bf49..8b6005d5c 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index c2c7f2e05..18e9e70bd 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -13,4 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. * - */ \ No newline at end of file + */ + +export const EXPERIMENTAL_FAULT_INJECTION = process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION; \ No newline at end of file diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts index b92f699a0..b92ade4f9 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts @@ -1,18 +1,15 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumOptions { 'allowAlias'?: (boolean); 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation); } export interface EnumOptions__Output { 'allowAlias': (boolean); 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts index db2770534..e60ee6f4c 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts @@ -1,18 +1,13 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumValueOptions { 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.envoy.annotations.disallowed_by_default_enum'?: (boolean); - '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation); } export interface EnumValueOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.envoy.annotations.disallowed_by_default_enum': (boolean); - '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index 63f8a015f..530022afe 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -2,8 +2,6 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; -import type { FieldSecurityAnnotation as _udpa_annotations_FieldSecurityAnnotation, FieldSecurityAnnotation__Output as _udpa_annotations_FieldSecurityAnnotation__Output } from '../../udpa/annotations/FieldSecurityAnnotation'; -import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; // Original file: null @@ -30,10 +28,6 @@ export interface FieldOptions { 'weak'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.rules'?: (_validate_FieldRules); - '.udpa.annotations.security'?: (_udpa_annotations_FieldSecurityAnnotation); - '.udpa.annotations.sensitive'?: (boolean); - '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation); - '.envoy.annotations.disallowed_by_default'?: (boolean); } export interface FieldOptions__Output { @@ -45,8 +39,4 @@ export interface FieldOptions__Output { 'weak': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.rules'?: (_validate_FieldRules__Output); - '.udpa.annotations.security'?: (_udpa_annotations_FieldSecurityAnnotation__Output); - '.udpa.annotations.sensitive': (boolean); - '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation__Output); - '.envoy.annotations.disallowed_by_default': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts index b2ddbb374..573e847c0 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts @@ -1,8 +1,6 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; -import type { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; // Original file: null @@ -28,8 +26,6 @@ export interface FileOptions { 'objcClassPrefix'?: (string); 'csharpNamespace'?: (string); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation); - '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation); } export interface FileOptions__Output { @@ -48,6 +44,4 @@ export interface FileOptions__Output { 'objcClassPrefix': (string); 'csharpNamespace': (string); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation__Output); - '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation__Output); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts index 219e4bfd2..d3b5a54b8 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts @@ -1,8 +1,6 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { VersioningAnnotation as _udpa_annotations_VersioningAnnotation, VersioningAnnotation__Output as _udpa_annotations_VersioningAnnotation__Output } from '../../udpa/annotations/VersioningAnnotation'; -import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface MessageOptions { 'messageSetWireFormat'?: (boolean); @@ -11,8 +9,6 @@ export interface MessageOptions { 'mapEntry'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.disabled'?: (boolean); - '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation); - '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation); } export interface MessageOptions__Output { @@ -22,6 +18,4 @@ export interface MessageOptions__Output { 'mapEntry': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.disabled': (boolean); - '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation__Output); - '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation__Output); } diff --git a/packages/grpc-js-xds/src/generated/typed_struct.ts b/packages/grpc-js-xds/src/generated/typed_struct.ts new file mode 100644 index 000000000..78d781a29 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/typed_struct.ts @@ -0,0 +1,74 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + google: { + protobuf: { + DescriptorProto: MessageTypeDefinition + Duration: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + type: { + v1: { + TypedStruct: MessageTypeDefinition + } + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } +} + diff --git a/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts b/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts new file mode 100644 index 000000000..f9d842982 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts @@ -0,0 +1,77 @@ +// Original file: deps/udpa/udpa/type/v1/typed_struct.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; + +/** + * A TypedStruct contains an arbitrary JSON serialized protocol buffer message with a URL that + * describes the type of the serialized message. This is very similar to google.protobuf.Any, + * instead of having protocol buffer binary, this employs google.protobuf.Struct as value. + * + * This message is intended to be embedded inside Any, so it shouldn't be directly referred + * from other UDPA messages. + * + * When packing an opaque extension config, packing the expected type into Any is preferred + * wherever possible for its efficiency. TypedStruct should be used only if a proto descriptor + * is not available, for example if: + * - A control plane sends opaque message that is originally from external source in human readable + * format such as JSON or YAML. + * - The control plane doesn't have the knowledge of the protocol buffer schema hence it cannot + * serialize the message in protocol buffer binary format. + * - The DPLB doesn't have have the knowledge of the protocol buffer schema its plugin or extension + * uses. This has to be indicated in the DPLB capability negotiation. + * + * When a DPLB receives a TypedStruct in Any, it should: + * - Check if the type_url of the TypedStruct matches the type the extension expects. + * - Convert value to the type described in type_url and perform validation. + * TODO(lizan): Figure out how TypeStruct should be used with DPLB extensions that doesn't link + * protobuf descriptor with DPLB itself, (e.g. gRPC LB Plugin, Envoy WASM extensions). + */ +export interface TypedStruct { + /** + * A URL that uniquely identifies the type of the serialize protocol buffer message. + * This has same semantics and format described in google.protobuf.Any: + * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto + */ + 'type_url'?: (string); + /** + * A JSON representation of the above specified type. + */ + 'value'?: (_google_protobuf_Struct); +} + +/** + * A TypedStruct contains an arbitrary JSON serialized protocol buffer message with a URL that + * describes the type of the serialized message. This is very similar to google.protobuf.Any, + * instead of having protocol buffer binary, this employs google.protobuf.Struct as value. + * + * This message is intended to be embedded inside Any, so it shouldn't be directly referred + * from other UDPA messages. + * + * When packing an opaque extension config, packing the expected type into Any is preferred + * wherever possible for its efficiency. TypedStruct should be used only if a proto descriptor + * is not available, for example if: + * - A control plane sends opaque message that is originally from external source in human readable + * format such as JSON or YAML. + * - The control plane doesn't have the knowledge of the protocol buffer schema hence it cannot + * serialize the message in protocol buffer binary format. + * - The DPLB doesn't have have the knowledge of the protocol buffer schema its plugin or extension + * uses. This has to be indicated in the DPLB capability negotiation. + * + * When a DPLB receives a TypedStruct in Any, it should: + * - Check if the type_url of the TypedStruct matches the type the extension expects. + * - Convert value to the type described in type_url and perform validation. + * TODO(lizan): Figure out how TypeStruct should be used with DPLB extensions that doesn't link + * protobuf descriptor with DPLB itself, (e.g. gRPC LB Plugin, Envoy WASM extensions). + */ +export interface TypedStruct__Output { + /** + * A URL that uniquely identifies the type of the serialize protocol buffer message. + * This has same semantics and format described in google.protobuf.Any: + * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto + */ + 'type_url': (string); + /** + * A JSON representation of the above specified type. + */ + 'value'?: (_google_protobuf_Struct__Output); +} diff --git a/packages/grpc-js-xds/src/http-filter.ts b/packages/grpc-js-xds/src/http-filter.ts new file mode 100644 index 000000000..e7ea32957 --- /dev/null +++ b/packages/grpc-js-xds/src/http-filter.ts @@ -0,0 +1,221 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This is a non-public, unstable API, but it's very convenient +import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; +import { experimental } from '@grpc/grpc-js'; +import { Any__Output } from './generated/google/protobuf/Any'; +import Filter = experimental.Filter; +import FilterFactory = experimental.FilterFactory; +import { TypedStruct__Output } from './generated/udpa/type/v1/TypedStruct'; +import { FilterConfig__Output } from './generated/envoy/config/route/v3/FilterConfig'; +import { HttpFilter__Output } from './generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter'; + +const TYPED_STRUCT_URL = 'type.googleapis.com/udpa.type.v1.TypedStruct'; +const TYPED_STRUCT_NAME = 'udpa.type.v1.TypedStruct'; + +const FILTER_CONFIG_URL = 'type.googleapis.com/envoy.config.route.v3.FilterConfig'; +const FILTER_CONFIG_NAME = 'envoy.config.route.v3.FilterConfig'; + +const resourceRoot = loadProtosWithOptionsSync([ + 'udpa/type/v1/typed_struct.proto', + 'envoy/config/route/v3/route_components.proto'], { + keepCase: true, + includeDirs: [ + // Paths are relative to src/build + __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/envoy-api/' + ], + } +); + +export interface HttpFilterConfig { + typeUrl: string; + config: any; +} + +export interface HttpFilterFactoryConstructor { + new(config: HttpFilterConfig, overrideConfig?: HttpFilterConfig): FilterFactory; +} + +export interface HttpFilterRegistryEntry { + parseTopLevelFilterConfig(encodedConfig: Any__Output): HttpFilterConfig | null; + parseOverrideFilterConfig(encodedConfig: Any__Output): HttpFilterConfig | null; + httpFilterConstructor: HttpFilterFactoryConstructor; +} + +const FILTER_REGISTRY = new Map(); + +export function registerHttpFilter(typeName: string, entry: HttpFilterRegistryEntry) { + FILTER_REGISTRY.set(typeName, entry); +} + +const toObjectOptions = { + longs: String, + enums: String, + defaults: true, + oneofs: true +} + +function parseAnyMessage(message: Any__Output): MessageType | null { + const messageType = resourceRoot.lookup(message.type_url); + if (messageType) { + const decodedMessage = (messageType as any).decode(message.value); + return decodedMessage.$type.toObject(decodedMessage, toObjectOptions) as MessageType; + } else { + return null; + } +} + +function getTopLevelFilterUrl(encodedConfig: Any__Output): string { + let typeUrl: string; + if (encodedConfig.type_url === TYPED_STRUCT_URL) { + const typedStruct = parseAnyMessage(encodedConfig) + if (typedStruct) { + return typedStruct.type_url; + } else { + throw new Error('Failed to parse TypedStruct'); + } + } else { + return encodedConfig.type_url; + } +} + +export function validateTopLevelFilter(httpFilter: HttpFilter__Output): boolean { + if (!httpFilter.typed_config) { + return false; + } + const encodedConfig = httpFilter.typed_config; + let typeUrl: string; + try { + typeUrl = getTopLevelFilterUrl(encodedConfig); + } catch (e) { + return false; + } + const registryEntry = FILTER_REGISTRY.get(typeUrl); + if (registryEntry) { + const parsedConfig = registryEntry.parseTopLevelFilterConfig(encodedConfig); + return parsedConfig !== null; + } else { + if (httpFilter.is_optional) { + return true; + } else { + return false; + } + } +} + +export function validateOverrideFilter(encodedConfig: Any__Output): boolean { + let typeUrl: string; + let realConfig: Any__Output; + let isOptional = false; + if (encodedConfig.type_url === FILTER_CONFIG_URL) { + const filterConfig = parseAnyMessage(encodedConfig); + if (filterConfig) { + isOptional = filterConfig.is_optional; + if (filterConfig.config) { + realConfig = filterConfig.config; + } else { + return false; + } + } else { + return false; + } + } else { + realConfig = encodedConfig; + } + if (realConfig.type_url === TYPED_STRUCT_URL) { + const typedStruct = parseAnyMessage(encodedConfig); + if (typedStruct) { + typeUrl = typedStruct.type_url; + } else { + return false; + } + } else { + typeUrl = realConfig.type_url; + } + const registryEntry = FILTER_REGISTRY.get(typeUrl); + if (registryEntry) { + const parsedConfig = registryEntry.parseOverrideFilterConfig(encodedConfig); + return parsedConfig !== null; + } else { + if (isOptional) { + return true; + } else { + return false; + } + } +} + +export function parseTopLevelFilterConfig(encodedConfig: Any__Output) { + let typeUrl: string; + try { + typeUrl = getTopLevelFilterUrl(encodedConfig); + } catch (e) { + return null; + } + const registryEntry = FILTER_REGISTRY.get(typeUrl); + if (registryEntry) { + return registryEntry.parseTopLevelFilterConfig(encodedConfig); + } else { + // Filter type URL not found in registry + return null; + } +} + +export function parseOverrideFilterConfig(encodedConfig: Any__Output) { + let typeUrl: string; + let realConfig: Any__Output; + if (encodedConfig.type_url === FILTER_CONFIG_URL) { + const filterConfig = parseAnyMessage(encodedConfig); + if (filterConfig) { + if (filterConfig.config) { + realConfig = filterConfig.config; + } else { + return null; + } + } else { + return null; + } + } else { + realConfig = encodedConfig; + } + if (realConfig.type_url === TYPED_STRUCT_URL) { + const typedStruct = parseAnyMessage(encodedConfig); + if (typedStruct) { + typeUrl = typedStruct.type_url; + } else { + return null; + } + } else { + typeUrl = realConfig.type_url; + } + const registryEntry = FILTER_REGISTRY.get(typeUrl); + if (registryEntry) { + return registryEntry.parseOverrideFilterConfig(encodedConfig); + } else { + return null; + } +} + +export function createHttpFilter(config: HttpFilterConfig, overrideConfig?: HttpFilterConfig): FilterFactory | null { + const registryEntry = FILTER_REGISTRY.get(config.typeUrl); + if (registryEntry) { + return new registryEntry.httpFilterConstructor(config, overrideConfig); + } else { + return null; + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/protobuf-any.ts b/packages/grpc-js-xds/src/protobuf-any.ts new file mode 100644 index 000000000..cfee35f91 --- /dev/null +++ b/packages/grpc-js-xds/src/protobuf-any.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This is a non-public, unstable API, but it's very convenient +import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; +import { Any__Output } from './generated/google/protobuf/Any'; + +function parseAnyMessage(encodedMessage: Any__Output) { + +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 892cf5711..372d8b052 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -42,6 +42,12 @@ import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedCluster import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from './resources'; import Duration = experimental.Duration; import { Duration__Output } from './generated/google/protobuf/Duration'; +import { createHttpFilter, HttpFilterConfig, parseOverrideFilterConfig, parseTopLevelFilterConfig } from './http-filter'; +import { EXPERIMENTAL_FAULT_INJECTION } from './environment'; +import Filter = experimental.Filter; +import FilterFactory = experimental.FilterFactory; +import BaseFilter = experimental.BaseFilter; +import CallStream = experimental.CallStream; const TRACER_NAME = 'xds_resolver'; @@ -203,6 +209,25 @@ function protoDurationToDuration(duration: Duration__Output): Duration { } } +class NoRouterFilter extends BaseFilter implements Filter { + constructor(private call: CallStream) { + super(); + } + + sendMetadata(metadata: Promise): Promise { + this.call.cancelWithStatus(status.UNAVAILABLE, 'no xDS HTTP router filter configured'); + return Promise.reject(new Error('no xDS HTTP router filter configured')); + } +} + +class NoRouterFilterFactory implements FilterFactory { + createFilter(callStream: CallStream): NoRouterFilter { + return new NoRouterFilter(callStream); + } +} + +const ROUTER_FILTER_URL = 'type.googleapis.com/envoy.extensions.filters.http.router.v3.Router'; + class XdsResolver implements Resolver { private hasReportedSuccess = false; @@ -221,6 +246,9 @@ class XdsResolver implements Resolver { private latestDefaultTimeout: Duration | undefined = undefined; + private ldsHttpFilterConfigs: {name: string, config: HttpFilterConfig}[] = []; + private hasRouterFilter = false; + constructor( private target: GrpcUri, private listener: ResolverListener, @@ -235,6 +263,21 @@ class XdsResolver implements Resolver { } else { this.latestDefaultTimeout = protoDurationToDuration(defaultTimeout); } + if (EXPERIMENTAL_FAULT_INJECTION) { + this.ldsHttpFilterConfigs = []; + this.hasRouterFilter = false; + for (const filter of httpConnectionManager.http_filters) { + if (filter.typed_config?.type_url === ROUTER_FILTER_URL) { + this.hasRouterFilter = true; + break; + } + // typed_config must be set here, or validation would have failed + const filterConfig = parseTopLevelFilterConfig(filter.typed_config!); + if (filterConfig) { + this.ldsHttpFilterConfigs.push({name: filter.name, config: filterConfig}); + } + } + } switch (httpConnectionManager.route_specifier) { case 'rds': { const routeConfigName = httpConnectionManager.rds!.route_config_name; @@ -314,6 +357,15 @@ class XdsResolver implements Resolver { this.reportResolutionError('No matching route found'); return; } + const virtualHostHttpFilterOverrides = new Map(); + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const [name, filter] of Object.entries(virtualHost.typed_per_filter_config ?? {})) { + const parsedConfig = parseOverrideFilterConfig(filter); + if (parsedConfig) { + virtualHostHttpFilterOverrides.set(name, parsedConfig); + } + } + } trace('Received virtual host config ' + JSON.stringify(virtualHost, undefined, 2)); const allConfigClusters = new Set(); const matchList: {matcher: Matcher, action: RouteAction}[] = []; @@ -334,20 +386,89 @@ class XdsResolver implements Resolver { if (timeout?.seconds === 0 && timeout.nanos === 0) { timeout = undefined; } + const routeHttpFilterOverrides = new Map(); + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const [name, filter] of Object.entries(route.typed_per_filter_config ?? {})) { + const parsedConfig = parseOverrideFilterConfig(filter); + if (parsedConfig) { + routeHttpFilterOverrides.set(name, parsedConfig); + } + } + } switch (route.route!.cluster_specifier) { case 'cluster_header': continue; case 'cluster':{ const cluster = route.route!.cluster!; allConfigClusters.add(cluster); - routeAction = new SingleClusterRouteAction(cluster, timeout); + const extraFilterFactories: FilterFactory[] = []; + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const filterConfig of this.ldsHttpFilterConfigs) { + if (routeHttpFilterOverrides.has(filterConfig.name)) { + const filter = createHttpFilter(filterConfig.config, routeHttpFilterOverrides.get(filterConfig.name)!); + if (filter) { + extraFilterFactories.push(filter); + } + } else if (virtualHostHttpFilterOverrides.has(filterConfig.name)) { + const filter = createHttpFilter(filterConfig.config, virtualHostHttpFilterOverrides.get(filterConfig.name)!); + if (filter) { + extraFilterFactories.push(filter); + } + } else { + const filter = createHttpFilter(filterConfig.config); + if (filter) { + extraFilterFactories.push(filter); + } + } + } + if (!this.hasRouterFilter) { + extraFilterFactories.push(new NoRouterFilterFactory()); + } + } + routeAction = new SingleClusterRouteAction(cluster, timeout, extraFilterFactories); break; } case 'weighted_clusters': { const weightedClusters: WeightedCluster[] = []; for (const clusterWeight of route.route!.weighted_clusters!.clusters) { allConfigClusters.add(clusterWeight.name); - weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0}); + const extraFilterFactories: FilterFactory[] = []; + const clusterHttpFilterOverrides = new Map(); + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const [name, filter] of Object.entries(clusterWeight.typed_per_filter_config ?? {})) { + const parsedConfig = parseOverrideFilterConfig(filter); + if (parsedConfig) { + clusterHttpFilterOverrides.set(name, parsedConfig); + } + } + for (const filterConfig of this.ldsHttpFilterConfigs) { + if (clusterHttpFilterOverrides.has(filterConfig.name)) { + const filter = createHttpFilter(filterConfig.config, clusterHttpFilterOverrides.get(filterConfig.name)!); + if (filter) { + extraFilterFactories.push(filter); + } + } else if (routeHttpFilterOverrides.has(filterConfig.name)) { + const filter = createHttpFilter(filterConfig.config, routeHttpFilterOverrides.get(filterConfig.name)!); + if (filter) { + extraFilterFactories.push(filter); + } + } else if (virtualHostHttpFilterOverrides.has(filterConfig.name)) { + const filter = createHttpFilter(filterConfig.config, virtualHostHttpFilterOverrides.get(filterConfig.name)!); + if (filter) { + extraFilterFactories.push(filter); + } + } else { + const filter = createHttpFilter(filterConfig.config); + if (filter) { + extraFilterFactories.push(filter); + } + } + } + if (!this.hasRouterFilter) { + extraFilterFactories.push(new NoRouterFilterFactory()); + } + } + weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0, extraFilterFactories: extraFilterFactories}); } routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100, timeout); } @@ -376,16 +497,17 @@ class XdsResolver implements Resolver { const configSelector: ConfigSelector = (methodName, metadata) => { for (const {matcher, action} of matchList) { if (matcher.apply(methodName, metadata)) { - const clusterName = action.getCluster(); - this.refCluster(clusterName); + const clusterResult = action.getCluster(); + this.refCluster(clusterResult.name); const onCommitted = () => { - this.unrefCluster(clusterName); + this.unrefCluster(clusterResult.name); } return { methodConfig: {name: [], timeout: action.getTimeout()}, onCommitted: onCommitted, - pickInformation: {cluster: clusterName}, - status: status.OK + pickInformation: {cluster: clusterResult.name}, + status: status.OK, + extraFilterFactories: clusterResult.extraFilterFactories }; } } @@ -393,7 +515,8 @@ class XdsResolver implements Resolver { methodConfig: {name: []}, // cluster won't be used here, but it's set because of some TypeScript weirdness pickInformation: {cluster: ''}, - status: status.UNAVAILABLE + status: status.UNAVAILABLE, + extraFilterFactories: [] }; }; trace('Created ConfigSelector with configuration:'); diff --git a/packages/grpc-js-xds/src/route-action.ts b/packages/grpc-js-xds/src/route-action.ts index 5574bcd91..a45bf02a4 100644 --- a/packages/grpc-js-xds/src/route-action.ts +++ b/packages/grpc-js-xds/src/route-action.ts @@ -16,10 +16,17 @@ import { experimental } from '@grpc/grpc-js'; import Duration = experimental.Duration; +import Filter = experimental.Filter; +import FilterFactory = experimental.FilterFactory; + +export interface ClusterResult { + name: string; + extraFilterFactories: FilterFactory[]; +} export interface RouteAction { toString(): string; - getCluster(): string; + getCluster(): ClusterResult; getTimeout(): Duration | undefined; } @@ -33,10 +40,13 @@ function durationToLogString(duration: Duration) { } export class SingleClusterRouteAction implements RouteAction { - constructor(private cluster: string, private timeout: Duration | undefined) {} + constructor(private cluster: string, private timeout: Duration | undefined, private extraFilterFactories: FilterFactory[]) {} getCluster() { - return this.cluster; + return { + name: this.cluster, + extraFilterFactories: this.extraFilterFactories + }; } toString() { @@ -55,11 +65,13 @@ export class SingleClusterRouteAction implements RouteAction { export interface WeightedCluster { name: string; weight: number; + extraFilterFactories: FilterFactory[]; } interface ClusterChoice { name: string; numerator: number; + extraFilterFactories: FilterFactory[]; } export class WeightedClusterRouteAction implements RouteAction { @@ -72,7 +84,7 @@ export class WeightedClusterRouteAction implements RouteAction { let lastNumerator = 0; for (const clusterWeight of clusters) { lastNumerator += clusterWeight.weight; - this.clusterChoices.push({name: clusterWeight.name, numerator: lastNumerator}); + this.clusterChoices.push({name: clusterWeight.name, numerator: lastNumerator, extraFilterFactories: clusterWeight.extraFilterFactories}); } } @@ -80,11 +92,14 @@ export class WeightedClusterRouteAction implements RouteAction { const randomNumber = Math.random() * this.totalWeight; for (const choice of this.clusterChoices) { if (randomNumber < choice.numerator) { - return choice.name; + return { + name: choice.name, + extraFilterFactories: choice.extraFilterFactories + }; } } // This should be prevented by the validation rules - return ''; + return {name: '', extraFilterFactories: []}; } toString() { diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index eb76f7994..10ada540b 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -22,6 +22,8 @@ import { RdsState } from "./rds-state"; import { Watcher, XdsStreamState } from "./xds-stream-state"; import { HttpConnectionManager__Output } from '../generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V2, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from '../resources'; +import { validateTopLevelFilter } from '../http-filter'; +import { EXPERIMENTAL_FAULT_INJECTION } from '../environment'; const TRACER_NAME = 'xds_client'; @@ -100,6 +102,13 @@ export class LdsState implements XdsStreamState { return false; } const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener.value); + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const httpFilter of httpConnectionManager.http_filters) { + if (!validateTopLevelFilter(httpFilter)) { + return false; + } + } + } switch (httpConnectionManager.route_specifier) { case 'rds': return !!httpConnectionManager.rds?.config_source?.ads; diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 1e50f22e7..9441a7ecc 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -16,7 +16,9 @@ */ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { EXPERIMENTAL_FAULT_INJECTION } from "../environment"; import { RouteConfiguration__Output } from "../generated/envoy/config/route/v3/RouteConfiguration"; +import { validateOverrideFilter } from "../http-filter"; import { CdsLoadBalancingConfig } from "../load-balancer-cds"; import { Watcher, XdsStreamState } from "./xds-stream-state"; import ServiceConfig = experimental.ServiceConfig; @@ -112,6 +114,13 @@ export class RdsState implements XdsStreamState { return false; } } + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const filterConfig of Object.values(virtualHost.typed_per_filter_config ?? {})) { + if (!validateOverrideFilter(filterConfig)) { + return false; + } + } + } for (const route of virtualHost.routes) { const match = route.match; if (!match) { @@ -131,6 +140,13 @@ export class RdsState implements XdsStreamState { if ((route.route === undefined) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { return false; } + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const filterConfig of Object.values(route.typed_per_filter_config ?? {})) { + if (!validateOverrideFilter(filterConfig)) { + return false; + } + } + } if (route.route!.cluster_specifier === 'weighted_clusters') { let weightSum = 0; for (const clusterWeight of route.route.weighted_clusters!.clusters) { @@ -139,6 +155,15 @@ export class RdsState implements XdsStreamState { if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { return false; } + if (EXPERIMENTAL_FAULT_INJECTION) { + for (const weightedCluster of route.route!.weighted_clusters!.clusters) { + for (const filterConfig of Object.values(weightedCluster.typed_per_filter_config ?? {})) { + if (!validateOverrideFilter(filterConfig)) { + return false; + } + } + } + } } } } diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index ae6342604..e9e1cb8de 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -721,6 +721,10 @@ export class Http2CallStream implements Call { this.configDeadline = configDeadline; } + addFilterFactories(extraFilterFactories: FilterFactory[]) { + this.filterStack.push(extraFilterFactories.map(filterFactory => filterFactory.createFilter(this))); + } + startRead() { /* If the stream has ended with an error, we should not emit any more * messages and we should communicate that the stream has ended */ diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index cd2fc94a2..859a6e76d 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -536,6 +536,7 @@ export class ChannelImplementation implements Channel { // Refreshing the filters makes the deadline filter pick up the new deadline stream.filterStack.refresh(); } + stream.addFilterFactories(callConfig.extraFilterFactories); this.tryPick(stream, metadata, callConfig); } else { stream.cancelWithStatus(callConfig.status, "Failed to route call to method " + stream.getMethod()); diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index 147ace30d..cf5f7ee26 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -24,12 +24,14 @@ import { GrpcUri, uriToString } from './uri-parser'; import { ChannelOptions } from './channel-options'; import { Metadata } from './metadata'; import { Status } from './constants'; +import { Filter, FilterFactory } from './filter'; export interface CallConfig { methodConfig: MethodConfig; onCommitted?: () => void; pickInformation: {[key: string]: string}; status: Status; + extraFilterFactories: FilterFactory[]; } /** diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 94dd8c4a9..3f84af378 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -58,7 +58,8 @@ function getDefaultConfigSelector(serviceConfig: ServiceConfig | null): ConfigSe return { methodConfig: methodConfig, pickInformation: {}, - status: Status.OK + status: Status.OK, + extraFilterFactories: [] }; } } @@ -67,7 +68,8 @@ function getDefaultConfigSelector(serviceConfig: ServiceConfig | null): ConfigSe return { methodConfig: {name: []}, pickInformation: {}, - status: Status.OK + status: Status.OK, + extraFilterFactories: [] }; } } From a0f298c514c6ac56e33c149f8477d35deecbb4d2 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Jul 2021 10:08:05 -0700 Subject: [PATCH 1471/1899] grpc-js: Split out logs for different severity levels --- packages/grpc-js/src/logging.ts | 37 ++++++++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 352496240..549cd860e 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -17,7 +17,19 @@ import { LogVerbosity } from './constants'; -let _logger: Partial = console; +const DEFAULT_LOGGER: Partial = { + error: (message?: any, ...optionalParams: any[]) => { + console.error('E ' + message, ...optionalParams); + }, + info: (message?: any, ...optionalParams: any[]) => { + console.error('I ' + message, ...optionalParams); + }, + debug: (message?: any, ...optionalParams: any[]) => { + console.error('D ' + message, ...optionalParams); + }, +} + +let _logger: Partial = DEFAULT_LOGGER; let _logVerbosity: LogVerbosity = LogVerbosity.ERROR; const verbosityString = @@ -54,8 +66,27 @@ export const setLoggerVerbosity = (verbosity: LogVerbosity): void => { // eslint-disable-next-line @typescript-eslint/no-explicit-any export const log = (severity: LogVerbosity, ...args: any[]): void => { - if (severity >= _logVerbosity && typeof _logger.error === 'function') { - _logger.error(...args); + let logFunction: typeof DEFAULT_LOGGER.error; + if (severity >= _logVerbosity) { + switch (severity) { + case LogVerbosity.DEBUG: + logFunction = _logger.debug; + break; + case LogVerbosity.INFO: + logFunction = _logger.info; + break; + case LogVerbosity.ERROR: + logFunction = _logger.error; + break; + } + /* Fall back to _logger.error when other methods are not available for + * compatiblity with older behavior that always logged to _logger.error */ + if (!logFunction) { + logFunction = _logger.error; + } + if (logFunction) { + logFunction.bind(_logger)(...args); + } } }; From 312b7613def2b0b418e84bb51d304776ae4ebfce Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Jul 2021 10:28:15 -0700 Subject: [PATCH 1472/1899] grpc-js: Tighten server.bindAsync creds typecheck --- packages/grpc-js/src/server.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 017312219..42b79a3cf 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -237,8 +237,8 @@ export class Server { throw new TypeError('port must be a string'); } - if (creds === null || typeof creds !== 'object') { - throw new TypeError('creds must be an object'); + if (creds === null || !(creds instanceof ServerCredentials)) { + throw new TypeError('creds must be a ServerCredentials object'); } if (typeof callback !== 'function') { From 6359bf066f481d51efb2a63f3a477e0fc151bbab Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Jul 2021 10:55:50 -0700 Subject: [PATCH 1473/1899] Remove test for exact default logger identity --- packages/grpc-js/test/test-logging.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/grpc-js/test/test-logging.ts b/packages/grpc-js/test/test-logging.ts index c1601cbc5..d275158cf 100644 --- a/packages/grpc-js/test/test-logging.ts +++ b/packages/grpc-js/test/test-logging.ts @@ -27,10 +27,6 @@ describe('Logging', () => { grpc.setLogVerbosity(grpc.logVerbosity.DEBUG); }); - it('logger defaults to console', () => { - assert.strictEqual(logging.getLogger(), console); - }); - it('sets the logger to a new value', () => { const logger: Partial = {}; From a5449155049351c81b4ffead4a3004217e504568 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Jul 2021 11:29:28 -0700 Subject: [PATCH 1474/1899] Add router filter registry entry --- .../src/http-filter/router-filter.ts | 49 +++++++++++++++++++ packages/grpc-js-xds/src/index.ts | 2 + 2 files changed, 51 insertions(+) create mode 100644 packages/grpc-js-xds/src/http-filter/router-filter.ts diff --git a/packages/grpc-js-xds/src/http-filter/router-filter.ts b/packages/grpc-js-xds/src/http-filter/router-filter.ts new file mode 100644 index 000000000..81450c0ff --- /dev/null +++ b/packages/grpc-js-xds/src/http-filter/router-filter.ts @@ -0,0 +1,49 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { experimental } from '@grpc/grpc-js'; +import { Any__Output } from '../generated/google/protobuf/Any'; +import { HttpFilterConfig, registerHttpFilter } from '../http-filter'; +import Filter = experimental.Filter; +import FilterFactory = experimental.FilterFactory; +import BaseFilter = experimental.BaseFilter; + +class RouterFilter extends BaseFilter implements Filter {} + +class RouterFilterFactory implements FilterFactory { + constructor(config: HttpFilterConfig, overrideConfig?: HttpFilterConfig) {} + + createFilter(callStream: experimental.CallStream): RouterFilter { + return new RouterFilter(); + } +} + +const ROUTER_FILTER_URL = 'type.googleapis.com/envoy.extensions.filters.http.router.v3.Router'; + +function parseConfig(encodedConfig: Any__Output): HttpFilterConfig | null { + return { + typeUrl: ROUTER_FILTER_URL, + config: null + }; +} + +export function setup() { + registerHttpFilter(ROUTER_FILTER_URL, { + parseTopLevelFilterConfig: parseConfig, + parseOverrideFilterConfig: parseConfig, + httpFilterConstructor: RouterFilterFactory + }); +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 1b24d25e6..2fee339d1 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -22,6 +22,7 @@ import * as load_balancer_lrs from './load-balancer-lrs'; import * as load_balancer_priority from './load-balancer-priority'; import * as load_balancer_weighted_target from './load-balancer-weighted-target'; import * as load_balancer_xds_cluster_manager from './load-balancer-xds-cluster-manager'; +import * as router_filter from './http-filter/router-filter'; /** * Register the "xds:" name scheme with the @grpc/grpc-js library. @@ -34,4 +35,5 @@ export function register() { load_balancer_priority.setup(); load_balancer_weighted_target.setup(); load_balancer_xds_cluster_manager.setup(); + router_filter.setup(); } \ No newline at end of file From d0745b3a4caf84525357cbcca7f62ad625dd16fd Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Thu, 15 Jul 2021 14:56:47 -0700 Subject: [PATCH 1475/1899] Run call config filter factories before load balancing --- packages/grpc-js-xds/src/resolver-xds.ts | 6 +-- packages/grpc-js-xds/src/route-action.ts | 14 ++--- packages/grpc-js/src/call-stream.ts | 8 +-- packages/grpc-js/src/channel.ts | 51 ++++++++++++++----- packages/grpc-js/src/filter-stack.ts | 4 ++ packages/grpc-js/src/resolver.ts | 2 +- .../grpc-js/src/resolving-load-balancer.ts | 4 +- packages/grpc-js/src/subchannel.ts | 4 +- 8 files changed, 61 insertions(+), 32 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 372d8b052..c48cc251c 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -468,7 +468,7 @@ class XdsResolver implements Resolver { extraFilterFactories.push(new NoRouterFilterFactory()); } } - weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0, extraFilterFactories: extraFilterFactories}); + weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0, dynamicFilterFactories: extraFilterFactories}); } routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100, timeout); } @@ -507,7 +507,7 @@ class XdsResolver implements Resolver { onCommitted: onCommitted, pickInformation: {cluster: clusterResult.name}, status: status.OK, - extraFilterFactories: clusterResult.extraFilterFactories + dynamicFilterFactories: clusterResult.dynamicFilterFactories }; } } @@ -516,7 +516,7 @@ class XdsResolver implements Resolver { // cluster won't be used here, but it's set because of some TypeScript weirdness pickInformation: {cluster: ''}, status: status.UNAVAILABLE, - extraFilterFactories: [] + dynamicFilterFactories: [] }; }; trace('Created ConfigSelector with configuration:'); diff --git a/packages/grpc-js-xds/src/route-action.ts b/packages/grpc-js-xds/src/route-action.ts index a45bf02a4..d29e67b9b 100644 --- a/packages/grpc-js-xds/src/route-action.ts +++ b/packages/grpc-js-xds/src/route-action.ts @@ -21,7 +21,7 @@ import FilterFactory = experimental.FilterFactory; export interface ClusterResult { name: string; - extraFilterFactories: FilterFactory[]; + dynamicFilterFactories: FilterFactory[]; } export interface RouteAction { @@ -45,7 +45,7 @@ export class SingleClusterRouteAction implements RouteAction { getCluster() { return { name: this.cluster, - extraFilterFactories: this.extraFilterFactories + dynamicFilterFactories: this.extraFilterFactories }; } @@ -65,13 +65,13 @@ export class SingleClusterRouteAction implements RouteAction { export interface WeightedCluster { name: string; weight: number; - extraFilterFactories: FilterFactory[]; + dynamicFilterFactories: FilterFactory[]; } interface ClusterChoice { name: string; numerator: number; - extraFilterFactories: FilterFactory[]; + dynamicFilterFactories: FilterFactory[]; } export class WeightedClusterRouteAction implements RouteAction { @@ -84,7 +84,7 @@ export class WeightedClusterRouteAction implements RouteAction { let lastNumerator = 0; for (const clusterWeight of clusters) { lastNumerator += clusterWeight.weight; - this.clusterChoices.push({name: clusterWeight.name, numerator: lastNumerator, extraFilterFactories: clusterWeight.extraFilterFactories}); + this.clusterChoices.push({name: clusterWeight.name, numerator: lastNumerator, dynamicFilterFactories: clusterWeight.dynamicFilterFactories}); } } @@ -94,12 +94,12 @@ export class WeightedClusterRouteAction implements RouteAction { if (randomNumber < choice.numerator) { return { name: choice.name, - extraFilterFactories: choice.extraFilterFactories + dynamicFilterFactories: choice.dynamicFilterFactories }; } } // This should be prevented by the validation rules - return {name: '', extraFilterFactories: []}; + return {name: '', dynamicFilterFactories: []}; } toString() { diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index e9e1cb8de..accc275fc 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -462,9 +462,9 @@ export class Http2CallStream implements Call { attachHttp2Stream( stream: http2.ClientHttp2Stream, subchannel: Subchannel, - extraFilters: FilterFactory[] + extraFilters: Filter[] ): void { - this.filterStack.push(extraFilters.map(filterFactory => filterFactory.createFilter(this))); + this.filterStack.push(extraFilters); if (this.finalStatus !== null) { stream.close(NGHTTP2_CANCEL); } else { @@ -721,8 +721,8 @@ export class Http2CallStream implements Call { this.configDeadline = configDeadline; } - addFilterFactories(extraFilterFactories: FilterFactory[]) { - this.filterStack.push(extraFilterFactories.map(filterFactory => filterFactory.createFilter(this))); + addFilters(extraFilters: Filter[]) { + this.filterStack.push(extraFilters); } startRead() { diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 859a6e76d..8b5f31bfb 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -41,6 +41,7 @@ import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; import { SurfaceCall } from './call'; +import { Filter } from './filter'; export enum ConnectivityState { IDLE, @@ -148,6 +149,7 @@ export class ChannelImplementation implements Channel { callStream: Http2CallStream; callMetadata: Metadata; callConfig: CallConfig; + dynamicFilters: Filter[]; }> = []; private connectivityStateWatchers: ConnectivityStateWatcher[] = []; private defaultAuthority: string; @@ -237,8 +239,8 @@ export class ChannelImplementation implements Channel { const queueCopy = this.pickQueue.slice(); this.pickQueue = []; this.callRefTimerUnref(); - for (const { callStream, callMetadata, callConfig } of queueCopy) { - this.tryPick(callStream, callMetadata, callConfig); + for (const { callStream, callMetadata, callConfig, dynamicFilters } of queueCopy) { + this.tryPick(callStream, callMetadata, callConfig, dynamicFilters); } this.updateState(connectivityState); }, @@ -308,8 +310,8 @@ export class ChannelImplementation implements Channel { } } - private pushPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { - this.pickQueue.push({ callStream, callMetadata, callConfig }); + private pushPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig, dynamicFilters: Filter[]) { + this.pickQueue.push({ callStream, callMetadata, callConfig, dynamicFilters }); this.callRefTimerRef(); } @@ -320,7 +322,10 @@ export class ChannelImplementation implements Channel { * @param callStream * @param callMetadata */ - private tryPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig) { + private tryPick(callStream: Http2CallStream, callMetadata: Metadata, callConfig: CallConfig, dynamicFilters: Filter[]) { + if (callStream.getStatus() !== null) { + return; + } const pickResult = this.currentPicker.pick({ metadata: callMetadata, extraPickInfo: callConfig.pickInformation }); trace( LogVerbosity.DEBUG, @@ -357,7 +362,7 @@ export class ChannelImplementation implements Channel { ' has state ' + ConnectivityState[pickResult.subchannel!.getConnectivityState()] ); - this.pushPick(callStream, callMetadata, callConfig); + this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); break; } /* We need to clone the callMetadata here because the transparent @@ -370,10 +375,11 @@ export class ChannelImplementation implements Channel { const subchannelState: ConnectivityState = pickResult.subchannel!.getConnectivityState(); if (subchannelState === ConnectivityState.READY) { try { + const pickExtraFilters = pickResult.extraFilterFactories.map(factory => factory.createFilter(callStream)); pickResult.subchannel!.startCallStream( finalMetadata, callStream, - pickResult.extraFilterFactories + [...dynamicFilters, ...pickExtraFilters] ); /* If we reach this point, the call stream has started * successfully */ @@ -406,7 +412,7 @@ export class ChannelImplementation implements Channel { (error as Error).message + '. Retrying pick' ); - this.tryPick(callStream, callMetadata, callConfig); + this.tryPick(callStream, callMetadata, callConfig, dynamicFilters); } else { trace( LogVerbosity.INFO, @@ -435,7 +441,7 @@ export class ChannelImplementation implements Channel { ConnectivityState[subchannelState] + ' after metadata filters. Retrying pick' ); - this.tryPick(callStream, callMetadata, callConfig); + this.tryPick(callStream, callMetadata, callConfig, dynamicFilters); } }, (error: Error & { code: number }) => { @@ -449,11 +455,11 @@ export class ChannelImplementation implements Channel { } break; case PickResultType.QUEUE: - this.pushPick(callStream, callMetadata, callConfig); + this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); break; case PickResultType.TRANSIENT_FAILURE: if (callMetadata.getOptions().waitForReady) { - this.pushPick(callStream, callMetadata, callConfig); + this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); } else { callStream.cancelWithStatus( pickResult.status!.code, @@ -536,8 +542,27 @@ export class ChannelImplementation implements Channel { // Refreshing the filters makes the deadline filter pick up the new deadline stream.filterStack.refresh(); } - stream.addFilterFactories(callConfig.extraFilterFactories); - this.tryPick(stream, metadata, callConfig); + if (callConfig.dynamicFilterFactories.length > 0) { + /* These dynamicFilters are the mechanism for implementing gRFC A39: + * https://github.com/grpc/proposal/blob/master/A39-xds-http-filters.md + * We run them here instead of with the rest of the filters because + * that spec says "the xDS HTTP filters will run in between name + * resolution and load balancing". + * + * We use the filter stack here to simplify the multi-filter async + * waterfall logic, but we pass along the underlying list of filters + * to avoid having nested filter stacks when combining it with the + * original filter stack. We do not pass along the original filter + * factory list because these filters may need to persist data + * between sending headers and other operations. */ + const dynamicFilterStackFactory = new FilterStackFactory(callConfig.dynamicFilterFactories); + const dynamicFilterStack = dynamicFilterStackFactory.createFilter(stream); + dynamicFilterStack.sendMetadata(Promise.resolve(metadata)).then(filteredMetadata => { + this.tryPick(stream, filteredMetadata, callConfig, dynamicFilterStack.getFilters()); + }); + } else { + this.tryPick(stream, metadata, callConfig, []); + } } else { stream.cancelWithStatus(callConfig.status, "Failed to route call to method " + stream.getMethod()); } diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 4e0ccf07f..a9e754428 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -81,6 +81,10 @@ export class FilterStack implements Filter { push(filters: Filter[]) { this.filters.unshift(...filters); } + + getFilters(): Filter[] { + return this.filters; + } } export class FilterStackFactory implements FilterFactory { diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index cf5f7ee26..57db665cd 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -31,7 +31,7 @@ export interface CallConfig { onCommitted?: () => void; pickInformation: {[key: string]: string}; status: Status; - extraFilterFactories: FilterFactory[]; + dynamicFilterFactories: FilterFactory[]; } /** diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 3f84af378..7f6b41fdb 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -59,7 +59,7 @@ function getDefaultConfigSelector(serviceConfig: ServiceConfig | null): ConfigSe methodConfig: methodConfig, pickInformation: {}, status: Status.OK, - extraFilterFactories: [] + dynamicFilterFactories: [] }; } } @@ -69,7 +69,7 @@ function getDefaultConfigSelector(serviceConfig: ServiceConfig | null): ConfigSe methodConfig: {name: []}, pickInformation: {}, status: Status.OK, - extraFilterFactories: [] + dynamicFilterFactories: [] }; } } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c50a68e77..6dc3e9b37 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -688,7 +688,7 @@ export class Subchannel { startCallStream( metadata: Metadata, callStream: Http2CallStream, - extraFilterFactories: FilterFactory[] + extraFilters: Filter[] ) { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); @@ -720,7 +720,7 @@ export class Subchannel { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; } logging.trace(LogVerbosity.DEBUG, 'call_stream', 'Starting stream on subchannel ' + this.subchannelAddressString + ' with headers\n' + headersString); - callStream.attachHttp2Stream(http2Stream, this, extraFilterFactories); + callStream.attachHttp2Stream(http2Stream, this, extraFilters); } /** From 9e4039d86b1acbe4c072863171b4b2e3bb49a2fc Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 16 Jul 2021 10:45:40 -0700 Subject: [PATCH 1476/1899] Updated text in bindAsync error test --- packages/grpc-js/test/test-server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 58b102883..c4b5e30a0 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -116,7 +116,7 @@ describe('Server', () => { assert.throws(() => { server.bindAsync('localhost:0', null as any, noop); - }, /creds must be an object/); + }, /creds must be a ServerCredentials object/); assert.throws(() => { server.bindAsync( From af1676a5a5b26de4f41fa600ef1e20d58b600ab1 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Fri, 16 Jul 2021 16:39:26 -0700 Subject: [PATCH 1477/1899] Add test for passing client credentials to server --- packages/grpc-js/test/test-server.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index c4b5e30a0..8b2815745 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -118,6 +118,10 @@ describe('Server', () => { server.bindAsync('localhost:0', null as any, noop); }, /creds must be a ServerCredentials object/); + assert.throws(() => { + server.bindAsync('localhost:0', grpc.credentials.createInsecure() as any, noop); + }, /creds must be a ServerCredentials object/); + assert.throws(() => { server.bindAsync( 'localhost:0', From 776bcb46324a7f8d6b3f4902771b32d298d58300 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 19 Jul 2021 10:12:17 -0700 Subject: [PATCH 1478/1899] grpc-js: Add more trace logging around establishing connections --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/http_proxy.ts | 6 ++++++ packages/grpc-js/src/subchannel.ts | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 97d7e2758..87a75d79f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.5", + "version": "1.3.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 8c461d4f8..6e62eddd0 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -254,6 +254,12 @@ export function getProxiedConnection( reject(); }); } else { + trace( + 'Successfully established a plaintext connection to ' + + options.path + + ' through proxy ' + + proxyAddressString + ); resolve({ socket, realTarget: parsedTarget, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 8991ee3b0..cb1650dc1 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -303,6 +303,11 @@ export class Subchannel { } private createSession(proxyConnectionResult: ProxyConnectionResult) { + if (proxyConnectionResult.realTarget) { + trace(this.subchannelAddressString + ' creating HTTP/2 session through proxy to ' + proxyConnectionResult.realTarget); + } else { + trace(this.subchannelAddressString + ' creating HTTP/2 session'); + } const targetAuthority = getDefaultAuthority( proxyConnectionResult.realTarget ?? this.channelTarget ); @@ -403,6 +408,7 @@ export class Subchannel { }); session.once('close', () => { if (this.session === session) { + trace(this.subchannelAddressString + ' connection closed'); this.transitionToState( [ConnectivityState.CONNECTING], ConnectivityState.TRANSIENT_FAILURE From 6ae2ed4a14548c4ef0201d6fc6185d15b318c520 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 19 Jul 2021 13:20:49 -0700 Subject: [PATCH 1479/1899] grpc-js: Add trace log with library version --- packages/grpc-js/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 308074640..05288855c 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -247,7 +247,10 @@ export { experimental }; import * as resolver from './resolver'; import * as load_balancer from './load-balancer'; +const clientVersion = require('../../package.json').version; + (() => { + logging.trace(LogVerbosity.DEBUG, 'index', 'Loading @grpc/grpc-js version ' + clientVersion); resolver.registerAll(); load_balancer.registerAll(); })(); From f03b4dd87fdc9a56e4ef652ccdb9213f7553e97c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Jul 2021 14:12:59 -0700 Subject: [PATCH 1480/1899] Validate uniqueness of http filter names --- packages/grpc-js-xds/src/xds-stream-state/rds-state.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 9441a7ecc..0322218d2 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -141,7 +141,12 @@ export class RdsState implements XdsStreamState { return false; } if (EXPERIMENTAL_FAULT_INJECTION) { - for (const filterConfig of Object.values(route.typed_per_filter_config ?? {})) { + const filterNames = new Set(); + for (const [name, filterConfig] of Object.entries(route.typed_per_filter_config ?? {})) { + if (filterNames.has(name)) { + return false; + } + filterNames.add(name); if (!validateOverrideFilter(filterConfig)) { return false; } From 215cdcd1344b4b1426d989772ae6219770476777 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Jul 2021 12:42:11 -0700 Subject: [PATCH 1481/1899] Check for router filter in validation step --- packages/grpc-js-xds/src/resolver-xds.ts | 33 ------------------- .../src/xds-stream-state/lds-state.ts | 20 ++++++++++- .../src/xds-stream-state/rds-state.ts | 5 --- 3 files changed, 19 insertions(+), 39 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 59a3fec47..3eaabb111 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -46,8 +46,6 @@ import { createHttpFilter, HttpFilterConfig, parseOverrideFilterConfig, parseTop import { EXPERIMENTAL_FAULT_INJECTION } from './environment'; import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; -import BaseFilter = experimental.BaseFilter; -import CallStream = experimental.CallStream; const TRACER_NAME = 'xds_resolver'; @@ -209,25 +207,6 @@ function protoDurationToDuration(duration: Duration__Output): Duration { } } -class NoRouterFilter extends BaseFilter implements Filter { - constructor(private call: CallStream) { - super(); - } - - sendMetadata(metadata: Promise): Promise { - this.call.cancelWithStatus(status.UNAVAILABLE, 'no xDS HTTP router filter configured'); - return Promise.reject(new Error('no xDS HTTP router filter configured')); - } -} - -class NoRouterFilterFactory implements FilterFactory { - createFilter(callStream: CallStream): NoRouterFilter { - return new NoRouterFilter(callStream); - } -} - -const ROUTER_FILTER_URL = 'type.googleapis.com/envoy.extensions.filters.http.router.v3.Router'; - class XdsResolver implements Resolver { private hasReportedSuccess = false; @@ -247,7 +226,6 @@ class XdsResolver implements Resolver { private latestDefaultTimeout: Duration | undefined = undefined; private ldsHttpFilterConfigs: {name: string, config: HttpFilterConfig}[] = []; - private hasRouterFilter = false; constructor( private target: GrpcUri, @@ -265,12 +243,7 @@ class XdsResolver implements Resolver { } if (EXPERIMENTAL_FAULT_INJECTION) { this.ldsHttpFilterConfigs = []; - this.hasRouterFilter = false; for (const filter of httpConnectionManager.http_filters) { - if (filter.typed_config?.type_url === ROUTER_FILTER_URL) { - this.hasRouterFilter = true; - break; - } // typed_config must be set here, or validation would have failed const filterConfig = parseTopLevelFilterConfig(filter.typed_config!); if (filterConfig) { @@ -421,9 +394,6 @@ class XdsResolver implements Resolver { } } } - if (!this.hasRouterFilter) { - extraFilterFactories.push(new NoRouterFilterFactory()); - } } routeAction = new SingleClusterRouteAction(cluster, timeout, extraFilterFactories); break; @@ -464,9 +434,6 @@ class XdsResolver implements Resolver { } } } - if (!this.hasRouterFilter) { - extraFilterFactories.push(new NoRouterFilterFactory()); - } } weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0, dynamicFilterFactories: extraFilterFactories}); } diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 10ada540b..3efc64b92 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -31,6 +31,8 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } +const ROUTER_FILTER_URL = 'type.googleapis.com/envoy.extensions.filters.http.router.v3.Router'; + export class LdsState implements XdsStreamState { versionInfo = ''; nonce = ''; @@ -103,10 +105,26 @@ export class LdsState implements XdsStreamState { } const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener.value); if (EXPERIMENTAL_FAULT_INJECTION) { - for (const httpFilter of httpConnectionManager.http_filters) { + const filterNames = new Set(); + for (const [index, httpFilter] of httpConnectionManager.http_filters.entries()) { + if (filterNames.has(httpFilter.name)) { + return false; + } + filterNames.add(httpFilter.name); if (!validateTopLevelFilter(httpFilter)) { return false; } + /* Validate that the last filter, and only the last filter, is the + * router filter. */ + if (index < httpConnectionManager.http_filters.length - 1) { + if (httpFilter.name === ROUTER_FILTER_URL) { + return false; + } + } else { + if (httpFilter.name !== ROUTER_FILTER_URL) { + return false; + } + } } } switch (httpConnectionManager.route_specifier) { diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 0322218d2..f04692859 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -141,12 +141,7 @@ export class RdsState implements XdsStreamState { return false; } if (EXPERIMENTAL_FAULT_INJECTION) { - const filterNames = new Set(); for (const [name, filterConfig] of Object.entries(route.typed_per_filter_config ?? {})) { - if (filterNames.has(name)) { - return false; - } - filterNames.add(name); if (!validateOverrideFilter(filterConfig)) { return false; } From 2455c3d50aad13e8198c7b7583267bec5064e09c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 26 Jul 2021 10:52:11 -0700 Subject: [PATCH 1482/1899] grpc-js-xds: notify watchers when NACKing resource updates --- packages/grpc-js-xds/src/xds-client.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index ddca9284f..6828a8a8e 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -665,6 +665,11 @@ export class XdsClient { break; } if (serviceKind) { + this.adsState[serviceKind].reportStreamError({ + code: status.UNAVAILABLE, + details: message, + metadata: new Metadata() + }); resourceNames = this.adsState[serviceKind].getResourceNames(); nonce = this.adsState[serviceKind].nonce; versionInfo = this.adsState[serviceKind].versionInfo; From 82d5eb82f8babaac793f88eef3b54df37c05198b Mon Sep 17 00:00:00 2001 From: April Kyle Nassi Date: Wed, 28 Jul 2021 12:38:24 -0700 Subject: [PATCH 1483/1899] Update MAINTAINERS.md Moved 3 to emeritus --- MAINTAINERS.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index c9e0522a1..bdcef2e26 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -8,16 +8,17 @@ See [CONTRIBUTING.md](https://github.com/grpc/grpc-community/blob/master/CONTRIB for general contribution guidelines. ## Maintainers (in alphabetical order) - - [jiangtaoli2016](https://github.com/jiangtaoli2016), Google Inc. + - [jtattermusch](https://github.com/jtattermusch), Google Inc. - [murgatroid99](https://github.com/murgatroid99), Google Inc. - [nicolasnoble](https://github.com/nicolasnoble), Google Inc. - - [ofrobots](https://github.com/ofrobots), Google Inc. - [srini100](https://github.com/srini100), Google Inc. - - [WeiranFang](https://github.com/WeiranFang), Google Inc. - [wenbozhu](https://github.com/wenbozhu), Google Inc. ## Emeritus Maintainers (in alphabetical order) + - [jiangtaoli2016](https://github.com/jiangtaoli2016), Google Inc. - [kjin](https://github.com/kjin), Google Inc. - [matt-kwong](https://github.com/matt-kwong), Google Inc. - \ No newline at end of file + - [ofrobots](https://github.com/ofrobots), Google Inc. + - [WeiranFang](https://github.com/WeiranFang), Google Inc. + From 5518d0e8f4de98624202d664c3d797c97346055a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20LI=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Mon, 2 Aug 2021 11:28:24 +0800 Subject: [PATCH 1484/1899] add xds support reading bootstrap config directly from env var (#1868) --- packages/grpc-js-xds/src/xds-bootstrap.ts | 88 +++++++++++++++-------- 1 file changed, 60 insertions(+), 28 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts index 3da4ec3e6..28e926058 100644 --- a/packages/grpc-js-xds/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -244,34 +244,66 @@ export async function loadBootstrapInfo(): Promise { if (loadedBootstrapInfo !== null) { return loadedBootstrapInfo; } + + /** + * If GRPC_XDS_BOOTSTRAP exists + * then use its value as the name of the bootstrap file. + * + * If the file is missing or the contents of the file are malformed, + * return an error. + */ const bootstrapPath = process.env.GRPC_XDS_BOOTSTRAP; - if (bootstrapPath === undefined) { - return Promise.reject( - new Error( - 'The GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS' - ) - ); - } - loadedBootstrapInfo = new Promise((resolve, reject) => { - fs.readFile(bootstrapPath, { encoding: 'utf8' }, (err, data) => { - if (err) { - reject( - new Error( - `Failed to read xDS bootstrap file from path ${bootstrapPath} with error ${err.message}` - ) - ); - } - try { - const parsedFile = JSON.parse(data); - resolve(validateBootstrapFile(parsedFile)); - } catch (e) { - reject( - new Error( - `Failed to parse xDS bootstrap file at path ${bootstrapPath} with error ${e.message}` - ) - ); - } + if (bootstrapPath) { + loadedBootstrapInfo = new Promise((resolve, reject) => { + fs.readFile(bootstrapPath, { encoding: 'utf8' }, (err, data) => { + if (err) { + reject( + new Error( + `Failed to read xDS bootstrap file from path ${bootstrapPath} with error ${err.message}` + ) + ); + } + try { + const parsedFile = JSON.parse(data); + resolve(validateBootstrapFile(parsedFile)); + } catch (e) { + reject( + new Error( + `Failed to parse xDS bootstrap file at path ${bootstrapPath} with error ${e.message}` + ) + ); + } + }); }); - }); - return loadedBootstrapInfo; + return loadedBootstrapInfo; + } + + /** + * Else, if GRPC_XDS_BOOTSTRAP_CONFIG exists + * then use its value as the bootstrap config. + * + * If the value is malformed, return an error. + * + * See: https://github.com/grpc/grpc-node/issues/1868 + */ + const bootstrapConfig = process.env.GRPC_XDS_BOOTSTRAP_CONFIG; + if (bootstrapConfig) { + try { + const parsedConfig = JSON.parse(bootstrapConfig); + const loadedBootstrapInfoValue = validateBootstrapFile(parsedConfig); + loadedBootstrapInfo = Promise.resolve(loadedBootstrapInfoValue); + } catch (e) { + throw new Error( + `Failed to parse xDS bootstrap config from process.env.GRPC_XDS_BOOTSTRAP_CONFIG with error ${e.message}` + ); + } + + return loadedBootstrapInfo; + } + + return Promise.reject( + new Error( + 'The GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS' + ) + ); } From 6404ef7014b24d1cba2434fd57af7f0d85cd92e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20LI=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Mon, 2 Aug 2021 11:32:21 +0800 Subject: [PATCH 1485/1899] better error msg for both env vars --- packages/grpc-js-xds/src/xds-bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts index 28e926058..830ad0bba 100644 --- a/packages/grpc-js-xds/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -303,7 +303,7 @@ export async function loadBootstrapInfo(): Promise { return Promise.reject( new Error( - 'The GRPC_XDS_BOOTSTRAP environment variable needs to be set to the path to the bootstrap file to use xDS' + 'The GRPC_XDS_BOOTSTRAP or GRPC_XDS_BOOTSTRAP_CONFIG environment variables need to be set to the path to the bootstrap file to use xDS' ) ); } From d9bbd013f4b3090f780f7916ac1b5ff66a891e93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Huan=20=28=E6=9D=8E=E5=8D=93=E6=A1=93=29?= Date: Tue, 3 Aug 2021 00:31:07 +0800 Subject: [PATCH 1486/1899] Update xds-bootstrap.ts --- packages/grpc-js-xds/src/xds-bootstrap.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts index 830ad0bba..64a7bcb94 100644 --- a/packages/grpc-js-xds/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -294,7 +294,7 @@ export async function loadBootstrapInfo(): Promise { loadedBootstrapInfo = Promise.resolve(loadedBootstrapInfoValue); } catch (e) { throw new Error( - `Failed to parse xDS bootstrap config from process.env.GRPC_XDS_BOOTSTRAP_CONFIG with error ${e.message}` + `Failed to parse xDS bootstrap config from environment variable GRPC_XDS_BOOTSTRAP_CONFIG with error ${e.message}` ); } From faaad56c73a2f8982e92f8c71f218c78bb3408bc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 14:57:58 -0700 Subject: [PATCH 1487/1899] grpc-js-xds: Regenerate files with new proto-loader version --- packages/grpc-js-xds/src/generated/ads.ts | 10 +- packages/grpc-js-xds/src/generated/cluster.ts | 2 +- .../grpc-js-xds/src/generated/endpoint.ts | 2 +- .../envoy/api/v2/DeltaDiscoveryRequest.ts | 8 +- .../envoy/api/v2/DiscoveryRequest.ts | 8 +- .../envoy/api/v2/DiscoveryResponse.ts | 4 +- .../src/generated/envoy/api/v2/Resource.ts | 4 +- .../generated/envoy/api/v2/core/Address.ts | 8 +- .../envoy/api/v2/core/AsyncDataSource.ts | 8 +- .../envoy/api/v2/core/BackoffStrategy.ts | 8 +- .../generated/envoy/api/v2/core/BindConfig.ts | 8 +- .../envoy/api/v2/core/BuildVersion.ts | 8 +- .../generated/envoy/api/v2/core/CidrRange.ts | 4 +- .../generated/envoy/api/v2/core/Extension.ts | 4 +- .../envoy/api/v2/core/HeaderValueOption.ts | 8 +- .../generated/envoy/api/v2/core/HttpUri.ts | 4 +- .../generated/envoy/api/v2/core/Metadata.ts | 2 +- .../src/generated/envoy/api/v2/core/Node.ts | 12 +- .../envoy/api/v2/core/RemoteDataSource.ts | 8 +- .../envoy/api/v2/core/RetryPolicy.ts | 8 +- .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 4 +- .../api/v2/core/RuntimeFractionalPercent.ts | 4 +- .../envoy/api/v2/core/TcpKeepalive.ts | 12 +- .../envoy/api/v2/core/TransportSocket.ts | 8 +- .../envoy/api/v2/endpoint/ClusterStats.ts | 4 +- .../api/v2/endpoint/UpstreamEndpointStats.ts | 8 +- .../api/v2/endpoint/UpstreamLocalityStats.ts | 4 +- .../envoy/config/accesslog/v3/AccessLog.ts | 8 +- .../config/accesslog/v3/AccessLogFilter.ts | 48 ++-- .../config/accesslog/v3/ComparisonFilter.ts | 4 +- .../config/accesslog/v3/DurationFilter.ts | 4 +- .../config/accesslog/v3/ExtensionFilter.ts | 4 +- .../envoy/config/accesslog/v3/HeaderFilter.ts | 4 +- .../config/accesslog/v3/MetadataFilter.ts | 8 +- .../config/accesslog/v3/RuntimeFilter.ts | 4 +- .../config/accesslog/v3/StatusCodeFilter.ts | 4 +- .../config/cluster/v3/CircuitBreakers.ts | 32 +-- .../envoy/config/cluster/v3/Cluster.ts | 210 +++++++++--------- .../config/cluster/v3/ClusterCollection.ts | 4 +- .../envoy/config/cluster/v3/Filter.ts | 4 +- .../config/cluster/v3/LoadBalancingPolicy.ts | 4 +- .../config/cluster/v3/OutlierDetection.ts | 80 +++---- .../config/cluster/v3/UpstreamBindConfig.ts | 4 +- .../cluster/v3/UpstreamConnectionOptions.ts | 4 +- .../generated/envoy/config/core/v3/Address.ts | 12 +- .../envoy/config/core/v3/ApiConfigSource.ts | 12 +- .../envoy/config/core/v3/AsyncDataSource.ts | 8 +- .../envoy/config/core/v3/BackoffStrategy.ts | 8 +- .../envoy/config/core/v3/BindConfig.ts | 8 +- .../envoy/config/core/v3/BuildVersion.ts | 8 +- .../envoy/config/core/v3/CidrRange.ts | 4 +- .../envoy/config/core/v3/ConfigSource.ts | 16 +- .../config/core/v3/EventServiceConfig.ts | 4 +- .../envoy/config/core/v3/Extension.ts | 4 +- .../config/core/v3/ExtensionConfigSource.ts | 8 +- .../config/core/v3/GrpcProtocolOptions.ts | 4 +- .../envoy/config/core/v3/GrpcService.ts | 78 +++---- .../envoy/config/core/v3/HeaderValueOption.ts | 8 +- .../envoy/config/core/v3/HealthCheck.ts | 100 ++++----- .../config/core/v3/Http1ProtocolOptions.ts | 16 +- .../config/core/v3/Http2ProtocolOptions.ts | 52 ++--- .../config/core/v3/HttpProtocolOptions.ts | 16 +- .../generated/envoy/config/core/v3/HttpUri.ts | 4 +- .../envoy/config/core/v3/KeepaliveSettings.ts | 12 +- .../envoy/config/core/v3/Metadata.ts | 2 +- .../generated/envoy/config/core/v3/Node.ts | 12 +- .../envoy/config/core/v3/RateLimitSettings.ts | 8 +- .../envoy/config/core/v3/RemoteDataSource.ts | 8 +- .../envoy/config/core/v3/RetryPolicy.ts | 8 +- .../config/core/v3/RuntimeFeatureFlag.ts | 4 +- .../core/v3/RuntimeFractionalPercent.ts | 4 +- .../envoy/config/core/v3/RuntimePercent.ts | 4 +- .../core/v3/SubstitutionFormatString.ts | 8 +- .../envoy/config/core/v3/TcpKeepalive.ts | 12 +- .../envoy/config/core/v3/TransportSocket.ts | 4 +- .../config/core/v3/TypedExtensionConfig.ts | 4 +- .../endpoint/v3/ClusterLoadAssignment.ts | 18 +- .../envoy/config/endpoint/v3/ClusterStats.ts | 4 +- .../envoy/config/endpoint/v3/Endpoint.ts | 8 +- .../envoy/config/endpoint/v3/LbEndpoint.ts | 12 +- .../config/endpoint/v3/LocalityLbEndpoints.ts | 12 +- .../endpoint/v3/UpstreamEndpointStats.ts | 8 +- .../endpoint/v3/UpstreamLocalityStats.ts | 4 +- .../envoy/config/listener/v3/ApiListener.ts | 4 +- .../envoy/config/listener/v3/Filter.ts | 8 +- .../envoy/config/listener/v3/FilterChain.ts | 28 +-- .../config/listener/v3/FilterChainMatch.ts | 8 +- .../envoy/config/listener/v3/Listener.ts | 72 +++--- .../config/listener/v3/ListenerFilter.ts | 8 +- .../v3/ListenerFilterChainMatchPredicate.ts | 16 +- .../config/listener/v3/UdpListenerConfig.ts | 4 +- .../envoy/config/route/v3/CorsPolicy.ts | 12 +- .../envoy/config/route/v3/Decorator.ts | 4 +- .../config/route/v3/DirectResponseAction.ts | 4 +- .../envoy/config/route/v3/FilterAction.ts | 4 +- .../envoy/config/route/v3/FilterConfig.ts | 4 +- .../envoy/config/route/v3/HeaderMatcher.ts | 8 +- .../envoy/config/route/v3/HedgePolicy.ts | 8 +- .../config/route/v3/InternalRedirectPolicy.ts | 4 +- .../config/route/v3/QueryParameterMatcher.ts | 4 +- .../envoy/config/route/v3/RateLimit.ts | 64 +++--- .../envoy/config/route/v3/RedirectAction.ts | 4 +- .../envoy/config/route/v3/RetryPolicy.ts | 40 ++-- .../generated/envoy/config/route/v3/Route.ts | 38 ++-- .../envoy/config/route/v3/RouteAction.ts | 128 +++++------ .../config/route/v3/RouteConfiguration.ts | 12 +- .../envoy/config/route/v3/RouteMatch.ts | 32 +-- .../route/v3/ScopedRouteConfiguration.ts | 4 +- .../envoy/config/route/v3/Tracing.ts | 12 +- .../generated/envoy/config/route/v3/Vhds.ts | 4 +- .../envoy/config/route/v3/VirtualHost.ts | 22 +- .../envoy/config/route/v3/WeightedCluster.ts | 14 +- .../envoy/config/trace/v3/Tracing.ts | 8 +- .../v3/HttpConnectionManager.ts | 116 +++++----- .../http_connection_manager/v3/HttpFilter.ts | 8 +- .../v3/LocalReplyConfig.ts | 4 +- .../network/http_connection_manager/v3/Rds.ts | 4 +- .../v3/RequestIDExtension.ts | 4 +- .../v3/ResponseMapper.ts | 16 +- .../http_connection_manager/v3/ScopedRds.ts | 4 +- .../v3/ScopedRoutes.ts | 24 +- .../v2/AggregatedDiscoveryService.ts | 6 + .../v3/AggregatedDiscoveryService.ts | 6 + .../discovery/v3/DeltaDiscoveryRequest.ts | 8 +- .../discovery/v3/DeltaDiscoveryResponse.ts | 4 +- .../service/discovery/v3/DiscoveryRequest.ts | 8 +- .../service/discovery/v3/DiscoveryResponse.ts | 4 +- .../envoy/service/discovery/v3/Resource.ts | 12 +- .../load_stats/v2/LoadReportingService.ts | 5 + .../service/load_stats/v2/LoadStatsRequest.ts | 4 +- .../load_stats/v2/LoadStatsResponse.ts | 4 +- .../load_stats/v3/LoadReportingService.ts | 5 + .../service/load_stats/v3/LoadStatsRequest.ts | 4 +- .../load_stats/v3/LoadStatsResponse.ts | 4 +- .../envoy/type/matcher/v3/DoubleMatcher.ts | 4 +- .../envoy/type/matcher/v3/ListMatcher.ts | 4 +- .../envoy/type/matcher/v3/MetadataMatcher.ts | 4 +- .../matcher/v3/RegexMatchAndSubstitute.ts | 4 +- .../envoy/type/matcher/v3/RegexMatcher.ts | 8 +- .../envoy/type/matcher/v3/StringMatcher.ts | 4 +- .../envoy/type/matcher/v3/ValueMatcher.ts | 16 +- .../envoy/type/metadata/v3/MetadataKind.ts | 16 +- .../envoy/type/tracing/v3/CustomTag.ts | 24 +- .../google/protobuf/DescriptorProto.ts | 4 +- .../google/protobuf/EnumDescriptorProto.ts | 4 +- .../generated/google/protobuf/EnumOptions.ts | 3 + .../protobuf/EnumValueDescriptorProto.ts | 4 +- .../google/protobuf/EnumValueOptions.ts | 5 + .../google/protobuf/FieldDescriptorProto.ts | 4 +- .../generated/google/protobuf/FieldOptions.ts | 11 +- .../google/protobuf/FileDescriptorProto.ts | 8 +- .../generated/google/protobuf/FileOptions.ts | 6 + .../google/protobuf/MessageOptions.ts | 6 + .../google/protobuf/MethodDescriptorProto.ts | 4 +- .../google/protobuf/OneofDescriptorProto.ts | 4 +- .../google/protobuf/ServiceDescriptorProto.ts | 4 +- .../src/generated/google/protobuf/Struct.ts | 2 +- .../src/generated/google/protobuf/Value.ts | 8 +- .../src/generated/http_connection_manager.ts | 2 +- .../grpc-js-xds/src/generated/listener.ts | 2 +- packages/grpc-js-xds/src/generated/lrs.ts | 10 +- packages/grpc-js-xds/src/generated/route.ts | 2 +- .../grpc-js-xds/src/generated/typed_struct.ts | 2 +- .../src/generated/udpa/type/v1/TypedStruct.ts | 4 +- .../src/generated/validate/DurationRules.ts | 20 +- .../src/generated/validate/FieldRules.ts | 88 ++++---- .../src/generated/validate/MapRules.ts | 8 +- .../src/generated/validate/RepeatedRules.ts | 4 +- .../src/generated/validate/TimestampRules.ts | 24 +- .../generated/xds/core/v3/CollectionEntry.ts | 12 +- .../generated/xds/core/v3/ResourceLocator.ts | 8 +- 171 files changed, 1180 insertions(+), 1131 deletions(-) diff --git a/packages/grpc-js-xds/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts index 665374958..f8e336131 100644 --- a/packages/grpc-js-xds/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; -import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v3_AggregatedDiscoveryServiceClient } from './envoy/service/discovery/v3/AggregatedDiscoveryService'; +import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient, AggregatedDiscoveryServiceDefinition as _envoy_service_discovery_v2_AggregatedDiscoveryServiceDefinition } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; +import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v3_AggregatedDiscoveryServiceClient, AggregatedDiscoveryServiceDefinition as _envoy_service_discovery_v3_AggregatedDiscoveryServiceDefinition } from './envoy/service/discovery/v3/AggregatedDiscoveryService'; type SubtypeConstructor any, Subtype> = { new(...args: ConstructorParameters): Subtype; @@ -102,7 +102,7 @@ export interface ProtoGrpcType { * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover * the multiplexed singleton APIs at the Envoy instance and management server. */ - AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } + AggregatedDiscoveryService: SubtypeConstructor & { service: _envoy_service_discovery_v2_AggregatedDiscoveryServiceDefinition } } v3: { AdsDummy: MessageTypeDefinition @@ -114,7 +114,7 @@ export interface ProtoGrpcType { * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover * the multiplexed singleton APIs at the Envoy instance and management server. */ - AggregatedDiscoveryService: SubtypeConstructor & { service: ServiceDefinition } + AggregatedDiscoveryService: SubtypeConstructor & { service: _envoy_service_discovery_v3_AggregatedDiscoveryServiceDefinition } DeltaDiscoveryRequest: MessageTypeDefinition DeltaDiscoveryResponse: MessageTypeDefinition DiscoveryRequest: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts index 5e4683580..bc4465a30 100644 --- a/packages/grpc-js-xds/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type SubtypeConstructor any, Subtype> = { diff --git a/packages/grpc-js-xds/src/generated/endpoint.ts b/packages/grpc-js-xds/src/generated/endpoint.ts index dda6a78da..630bdeb62 100644 --- a/packages/grpc-js-xds/src/generated/endpoint.ts +++ b/packages/grpc-js-xds/src/generated/endpoint.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type SubtypeConstructor any, Subtype> = { diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts index 11cbe8c2c..20ddb1b14 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts @@ -42,7 +42,7 @@ export interface DeltaDiscoveryRequest { /** * The node making the request. */ - 'node'?: (_envoy_api_v2_core_Node); + 'node'?: (_envoy_api_v2_core_Node | null); /** * Type of the resource that is being requested, e.g. * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". @@ -99,7 +99,7 @@ export interface DeltaDiscoveryRequest { * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ - 'error_detail'?: (_google_rpc_Status); + 'error_detail'?: (_google_rpc_Status | null); } /** @@ -141,7 +141,7 @@ export interface DeltaDiscoveryRequest__Output { /** * The node making the request. */ - 'node'?: (_envoy_api_v2_core_Node__Output); + 'node': (_envoy_api_v2_core_Node__Output | null); /** * Type of the resource that is being requested, e.g. * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". @@ -198,5 +198,5 @@ export interface DeltaDiscoveryRequest__Output { * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ - 'error_detail'?: (_google_rpc_Status__Output); + 'error_detail': (_google_rpc_Status__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts index 2150c41bc..2386e71c4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts @@ -22,7 +22,7 @@ export interface DiscoveryRequest { /** * The node making the request. */ - 'node'?: (_envoy_api_v2_core_Node); + 'node'?: (_envoy_api_v2_core_Node | null); /** * List of resources to subscribe to, e.g. list of cluster names or a route * configuration name. If this is empty, all resources for the API are @@ -53,7 +53,7 @@ export interface DiscoveryRequest { * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. */ - 'error_detail'?: (_google_rpc_Status); + 'error_detail'?: (_google_rpc_Status | null); } /** @@ -75,7 +75,7 @@ export interface DiscoveryRequest__Output { /** * The node making the request. */ - 'node'?: (_envoy_api_v2_core_Node__Output); + 'node': (_envoy_api_v2_core_Node__Output | null); /** * List of resources to subscribe to, e.g. list of cluster names or a route * configuration name. If this is empty, all resources for the API are @@ -106,5 +106,5 @@ export interface DiscoveryRequest__Output { * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. */ - 'error_detail'?: (_google_rpc_Status__Output); + 'error_detail': (_google_rpc_Status__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts index dd7e70d4d..179143c67 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts @@ -52,7 +52,7 @@ export interface DiscoveryResponse { * [#not-implemented-hide:] * The control plane instance that sent the response. */ - 'control_plane'?: (_envoy_api_v2_core_ControlPlane); + 'control_plane'?: (_envoy_api_v2_core_ControlPlane | null); } /** @@ -104,5 +104,5 @@ export interface DiscoveryResponse__Output { * [#not-implemented-hide:] * The control plane instance that sent the response. */ - 'control_plane'?: (_envoy_api_v2_core_ControlPlane__Output); + 'control_plane': (_envoy_api_v2_core_ControlPlane__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts index 4804201bd..6ce856ee7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts @@ -11,7 +11,7 @@ export interface Resource { /** * The resource being tracked. */ - 'resource'?: (_google_protobuf_Any); + 'resource'?: (_google_protobuf_Any | null); /** * The resource's name, to distinguish it from others of the same type of resource. */ @@ -31,7 +31,7 @@ export interface Resource__Output { /** * The resource being tracked. */ - 'resource'?: (_google_protobuf_Any__Output); + 'resource': (_google_protobuf_Any__Output | null); /** * The resource's name, to distinguish it from others of the same type of resource. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts index b12c8d9b0..65044b74a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts @@ -9,8 +9,8 @@ import type { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_cor * management servers. */ export interface Address { - 'socket_address'?: (_envoy_api_v2_core_SocketAddress); - 'pipe'?: (_envoy_api_v2_core_Pipe); + 'socket_address'?: (_envoy_api_v2_core_SocketAddress | null); + 'pipe'?: (_envoy_api_v2_core_Pipe | null); 'address'?: "socket_address"|"pipe"; } @@ -20,7 +20,7 @@ export interface Address { * management servers. */ export interface Address__Output { - 'socket_address'?: (_envoy_api_v2_core_SocketAddress__Output); - 'pipe'?: (_envoy_api_v2_core_Pipe__Output); + 'socket_address'?: (_envoy_api_v2_core_SocketAddress__Output | null); + 'pipe'?: (_envoy_api_v2_core_Pipe__Output | null); 'address': "socket_address"|"pipe"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts index fb312bb40..139f82689 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts @@ -10,11 +10,11 @@ export interface AsyncDataSource { /** * Local async data source. */ - 'local'?: (_envoy_api_v2_core_DataSource); + 'local'?: (_envoy_api_v2_core_DataSource | null); /** * Remote async data source. */ - 'remote'?: (_envoy_api_v2_core_RemoteDataSource); + 'remote'?: (_envoy_api_v2_core_RemoteDataSource | null); 'specifier'?: "local"|"remote"; } @@ -25,10 +25,10 @@ export interface AsyncDataSource__Output { /** * Local async data source. */ - 'local'?: (_envoy_api_v2_core_DataSource__Output); + 'local'?: (_envoy_api_v2_core_DataSource__Output | null); /** * Remote async data source. */ - 'remote'?: (_envoy_api_v2_core_RemoteDataSource__Output); + 'remote'?: (_envoy_api_v2_core_RemoteDataSource__Output | null); 'specifier': "local"|"remote"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts index 48f9d904d..173aff0e1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts @@ -11,7 +11,7 @@ export interface BackoffStrategy { * be greater than zero and less than or equal to :ref:`max_interval * `. */ - 'base_interval'?: (_google_protobuf_Duration); + 'base_interval'?: (_google_protobuf_Duration | null); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval @@ -19,7 +19,7 @@ export interface BackoffStrategy { * is 10 times the :ref:`base_interval * `. */ - 'max_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration | null); } /** @@ -31,7 +31,7 @@ export interface BackoffStrategy__Output { * be greater than zero and less than or equal to :ref:`max_interval * `. */ - 'base_interval'?: (_google_protobuf_Duration__Output); + 'base_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval @@ -39,5 +39,5 @@ export interface BackoffStrategy__Output { * is 10 times the :ref:`base_interval * `. */ - 'max_interval'?: (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts index f989494ea..d4765c1ba 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts @@ -8,7 +8,7 @@ export interface BindConfig { /** * The address to bind to when creating a socket. */ - 'source_address'?: (_envoy_api_v2_core_SocketAddress); + 'source_address'?: (_envoy_api_v2_core_SocketAddress | null); /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address @@ -18,7 +18,7 @@ export interface BindConfig { * flag is not set (default), the socket is not modified, i.e. the option is * neither enabled nor disabled. */ - 'freebind'?: (_google_protobuf_BoolValue); + 'freebind'?: (_google_protobuf_BoolValue | null); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. @@ -30,7 +30,7 @@ export interface BindConfig__Output { /** * The address to bind to when creating a socket. */ - 'source_address'?: (_envoy_api_v2_core_SocketAddress__Output); + 'source_address': (_envoy_api_v2_core_SocketAddress__Output | null); /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address @@ -40,7 +40,7 @@ export interface BindConfig__Output { * flag is not set (default), the socket is not modified, i.e. the option is * neither enabled nor disabled. */ - 'freebind'?: (_google_protobuf_BoolValue__Output); + 'freebind': (_google_protobuf_BoolValue__Output | null); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts index 50a44a3b2..a33015d89 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts @@ -11,12 +11,12 @@ export interface BuildVersion { /** * SemVer version of extension. */ - 'version'?: (_envoy_type_SemanticVersion); + 'version'?: (_envoy_type_SemanticVersion | null); /** * Free-form build information. * Envoy defines several well known keys in the source/common/version/version.h file */ - 'metadata'?: (_google_protobuf_Struct); + 'metadata'?: (_google_protobuf_Struct | null); } /** @@ -27,10 +27,10 @@ export interface BuildVersion__Output { /** * SemVer version of extension. */ - 'version'?: (_envoy_type_SemanticVersion__Output); + 'version': (_envoy_type_SemanticVersion__Output | null); /** * Free-form build information. * Envoy defines several well known keys in the source/common/version/version.h file */ - 'metadata'?: (_google_protobuf_Struct__Output); + 'metadata': (_google_protobuf_Struct__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts index 00c67734f..cca1bc2d8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts @@ -14,7 +14,7 @@ export interface CidrRange { /** * Length of prefix, e.g. 0, 32. */ - 'prefix_len'?: (_google_protobuf_UInt32Value); + 'prefix_len'?: (_google_protobuf_UInt32Value | null); } /** @@ -29,5 +29,5 @@ export interface CidrRange__Output { /** * Length of prefix, e.g. 0, 32. */ - 'prefix_len'?: (_google_protobuf_UInt32Value__Output); + 'prefix_len': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts index 418c7a360..67c5e1736 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts @@ -31,7 +31,7 @@ export interface Extension { * of other extensions and the Envoy API. * This field is not set when extension did not provide version information. */ - 'version'?: (_envoy_api_v2_core_BuildVersion); + 'version'?: (_envoy_api_v2_core_BuildVersion | null); /** * Indicates that the extension is present but was disabled via dynamic configuration. */ @@ -67,7 +67,7 @@ export interface Extension__Output { * of other extensions and the Envoy API. * This field is not set when extension did not provide version information. */ - 'version'?: (_envoy_api_v2_core_BuildVersion__Output); + 'version': (_envoy_api_v2_core_BuildVersion__Output | null); /** * Indicates that the extension is present but was disabled via dynamic configuration. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts index b90bd85e1..12421d8f4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts @@ -10,12 +10,12 @@ export interface HeaderValueOption { /** * Header name/value pair that this option applies to. */ - 'header'?: (_envoy_api_v2_core_HeaderValue); + 'header'?: (_envoy_api_v2_core_HeaderValue | null); /** * Should the value be appended? If true (default), the value is appended to * existing values. */ - 'append'?: (_google_protobuf_BoolValue); + 'append'?: (_google_protobuf_BoolValue | null); } /** @@ -25,10 +25,10 @@ export interface HeaderValueOption__Output { /** * Header name/value pair that this option applies to. */ - 'header'?: (_envoy_api_v2_core_HeaderValue__Output); + 'header': (_envoy_api_v2_core_HeaderValue__Output | null); /** * Should the value be appended? If true (default), the value is appended to * existing values. */ - 'append'?: (_google_protobuf_BoolValue__Output); + 'append': (_google_protobuf_BoolValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts index 19711dde7..c206a2454 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts @@ -30,7 +30,7 @@ export interface HttpUri { /** * Sets the maximum duration in milliseconds that a response can take to arrive upon request. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); /** * Specify how `uri` is to be fetched. Today, this requires an explicit * cluster, but in the future we may support dynamic cluster creation or @@ -68,7 +68,7 @@ export interface HttpUri__Output { /** * Sets the maximum duration in milliseconds that a response can take to arrive upon request. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); /** * Specify how `uri` is to be fetched. Today, this requires an explicit * cluster, but in the future we may support dynamic cluster creation or diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts index ca823a27c..7a6871eeb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts @@ -63,5 +63,5 @@ export interface Metadata__Output { * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* * namespace is reserved for Envoy's built-in filters. */ - 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct__Output}); + 'filter_metadata': ({[key: string]: _google_protobuf_Struct__Output}); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts index c6ddea9d4..ddf10f08b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts @@ -41,11 +41,11 @@ export interface Node { * Opaque metadata extending the node identifier. Envoy will pass this * directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct); + 'metadata'?: (_google_protobuf_Struct | null); /** * Locality specifying where the Envoy instance is running. */ - 'locality'?: (_envoy_api_v2_core_Locality); + 'locality'?: (_envoy_api_v2_core_Locality | null); /** * This is motivated by informing a management server during canary which * version of Envoy is being tested in a heterogeneous fleet. This will be set @@ -66,7 +66,7 @@ export interface Node { /** * Structured version of the entity requesting config. */ - 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion); + 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion | null); /** * List of extensions and their versions supported by the node. */ @@ -124,11 +124,11 @@ export interface Node__Output { * Opaque metadata extending the node identifier. Envoy will pass this * directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct__Output); + 'metadata': (_google_protobuf_Struct__Output | null); /** * Locality specifying where the Envoy instance is running. */ - 'locality'?: (_envoy_api_v2_core_Locality__Output); + 'locality': (_envoy_api_v2_core_Locality__Output | null); /** * This is motivated by informing a management server during canary which * version of Envoy is being tested in a heterogeneous fleet. This will be set @@ -149,7 +149,7 @@ export interface Node__Output { /** * Structured version of the entity requesting config. */ - 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion__Output); + 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion__Output | null); /** * List of extensions and their versions supported by the node. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts index 93e722eef..516dbf864 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts @@ -10,7 +10,7 @@ export interface RemoteDataSource { /** * The HTTP URI to fetch the remote data. */ - 'http_uri'?: (_envoy_api_v2_core_HttpUri); + 'http_uri'?: (_envoy_api_v2_core_HttpUri | null); /** * SHA256 string for verifying data. */ @@ -18,7 +18,7 @@ export interface RemoteDataSource { /** * Retry policy for fetching remote data. */ - 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy); + 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy | null); } /** @@ -28,7 +28,7 @@ export interface RemoteDataSource__Output { /** * The HTTP URI to fetch the remote data. */ - 'http_uri'?: (_envoy_api_v2_core_HttpUri__Output); + 'http_uri': (_envoy_api_v2_core_HttpUri__Output | null); /** * SHA256 string for verifying data. */ @@ -36,5 +36,5 @@ export interface RemoteDataSource__Output { /** * Retry policy for fetching remote data. */ - 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy__Output); + 'retry_policy': (_envoy_api_v2_core_RetryPolicy__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts index 27c1096b7..7ff35e375 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts @@ -12,12 +12,12 @@ export interface RetryPolicy { * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ - 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy); + 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy | null); /** * Specifies the allowed number of retries. This parameter is optional and * defaults to 1. */ - 'num_retries'?: (_google_protobuf_UInt32Value); + 'num_retries'?: (_google_protobuf_UInt32Value | null); } /** @@ -29,10 +29,10 @@ export interface RetryPolicy__Output { * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ - 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy__Output); + 'retry_back_off': (_envoy_api_v2_core_BackoffStrategy__Output | null); /** * Specifies the allowed number of retries. This parameter is optional and * defaults to 1. */ - 'num_retries'?: (_google_protobuf_UInt32Value__Output); + 'num_retries': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts index 47cf24097..4ad57de46 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts @@ -9,7 +9,7 @@ export interface RuntimeFeatureFlag { /** * Default value if runtime value is not available. */ - 'default_value'?: (_google_protobuf_BoolValue); + 'default_value'?: (_google_protobuf_BoolValue | null); /** * Runtime key to get value for comparison. This value is used if defined. The boolean value must * be represented via its @@ -25,7 +25,7 @@ export interface RuntimeFeatureFlag__Output { /** * Default value if runtime value is not available. */ - 'default_value'?: (_google_protobuf_BoolValue__Output); + 'default_value': (_google_protobuf_BoolValue__Output | null); /** * Runtime key to get value for comparison. This value is used if defined. The boolean value must * be represented via its diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts index 08e29de1f..a168af60c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts @@ -18,7 +18,7 @@ export interface RuntimeFractionalPercent { /** * Default value if the runtime value's for the numerator/denominator keys are not available. */ - 'default_value'?: (_envoy_type_FractionalPercent); + 'default_value'?: (_envoy_type_FractionalPercent | null); /** * Runtime key for a YAML representation of a FractionalPercent. */ @@ -41,7 +41,7 @@ export interface RuntimeFractionalPercent__Output { /** * Default value if the runtime value's for the numerator/denominator keys are not available. */ - 'default_value'?: (_envoy_type_FractionalPercent__Output); + 'default_value': (_envoy_type_FractionalPercent__Output | null); /** * Runtime key for a YAML representation of a FractionalPercent. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts index 394a54feb..e9d805c76 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts @@ -8,18 +8,18 @@ export interface TcpKeepalive { * the connection is dead. Default is to use the OS level configuration (unless * overridden, Linux defaults to 9.) */ - 'keepalive_probes'?: (_google_protobuf_UInt32Value); + 'keepalive_probes'?: (_google_protobuf_UInt32Value | null); /** * The number of seconds a connection needs to be idle before keep-alive probes * start being sent. Default is to use the OS level configuration (unless * overridden, Linux defaults to 7200s (i.e., 2 hours.) */ - 'keepalive_time'?: (_google_protobuf_UInt32Value); + 'keepalive_time'?: (_google_protobuf_UInt32Value | null); /** * The number of seconds between keep-alive probes. Default is to use the OS * level configuration (unless overridden, Linux defaults to 75s.) */ - 'keepalive_interval'?: (_google_protobuf_UInt32Value); + 'keepalive_interval'?: (_google_protobuf_UInt32Value | null); } export interface TcpKeepalive__Output { @@ -28,16 +28,16 @@ export interface TcpKeepalive__Output { * the connection is dead. Default is to use the OS level configuration (unless * overridden, Linux defaults to 9.) */ - 'keepalive_probes'?: (_google_protobuf_UInt32Value__Output); + 'keepalive_probes': (_google_protobuf_UInt32Value__Output | null); /** * The number of seconds a connection needs to be idle before keep-alive probes * start being sent. Default is to use the OS level configuration (unless * overridden, Linux defaults to 7200s (i.e., 2 hours.) */ - 'keepalive_time'?: (_google_protobuf_UInt32Value__Output); + 'keepalive_time': (_google_protobuf_UInt32Value__Output | null); /** * The number of seconds between keep-alive probes. Default is to use the OS * level configuration (unless overridden, Linux defaults to 75s.) */ - 'keepalive_interval'?: (_google_protobuf_UInt32Value__Output); + 'keepalive_interval': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts index b45767eb2..87fbcaf38 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts @@ -15,8 +15,8 @@ export interface TransportSocket { * socket implementation. */ 'name'?: (string); - 'config'?: (_google_protobuf_Struct); - 'typed_config'?: (_google_protobuf_Any); + 'config'?: (_google_protobuf_Struct | null); + 'typed_config'?: (_google_protobuf_Any | null); /** * Implementation specific configuration which depends on the implementation being instantiated. * See the supported transport socket implementations for further documentation. @@ -36,8 +36,8 @@ export interface TransportSocket__Output { * socket implementation. */ 'name': (string); - 'config'?: (_google_protobuf_Struct__Output); - 'typed_config'?: (_google_protobuf_Any__Output); + 'config'?: (_google_protobuf_Struct__Output | null); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Implementation specific configuration which depends on the implementation being instantiated. * See the supported transport socket implementations for further documentation. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts index 4b5c30f4c..3609ea1e4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts @@ -57,7 +57,7 @@ export interface ClusterStats { * and the *LoadStatsResponse* message sent from the management server, this may be longer than * the requested load reporting interval in the *LoadStatsResponse*. */ - 'load_report_interval'?: (_google_protobuf_Duration); + 'load_report_interval'?: (_google_protobuf_Duration | null); /** * Information about deliberately dropped requests for each category specified * in the DropOverload policy. @@ -102,7 +102,7 @@ export interface ClusterStats__Output { * and the *LoadStatsResponse* message sent from the management server, this may be longer than * the requested load reporting interval in the *LoadStatsResponse*. */ - 'load_report_interval'?: (_google_protobuf_Duration__Output); + 'load_report_interval': (_google_protobuf_Duration__Output | null); /** * Information about deliberately dropped requests for each category specified * in the DropOverload policy. diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts index 5b5c62b32..e4551bd37 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts @@ -13,7 +13,7 @@ export interface UpstreamEndpointStats { /** * Upstream host address. */ - 'address'?: (_envoy_api_v2_core_Address); + 'address'?: (_envoy_api_v2_core_Address | null); /** * The total number of requests successfully completed by the endpoints in the * locality. These include non-5xx responses for HTTP, where errors @@ -46,7 +46,7 @@ export interface UpstreamEndpointStats { * Opaque and implementation dependent metadata of the * endpoint. Envoy will pass this directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct); + 'metadata'?: (_google_protobuf_Struct | null); /** * The total number of requests that were issued to this endpoint * since the last report. A single TCP connection, HTTP or gRPC @@ -63,7 +63,7 @@ export interface UpstreamEndpointStats__Output { /** * Upstream host address. */ - 'address'?: (_envoy_api_v2_core_Address__Output); + 'address': (_envoy_api_v2_core_Address__Output | null); /** * The total number of requests successfully completed by the endpoints in the * locality. These include non-5xx responses for HTTP, where errors @@ -96,7 +96,7 @@ export interface UpstreamEndpointStats__Output { * Opaque and implementation dependent metadata of the * endpoint. Envoy will pass this directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct__Output); + 'metadata': (_google_protobuf_Struct__Output | null); /** * The total number of requests that were issued to this endpoint * since the last report. A single TCP connection, HTTP or gRPC diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts index a1b20897e..df4d4eb89 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts @@ -18,7 +18,7 @@ export interface UpstreamLocalityStats { * Name of zone, region and optionally endpoint group these metrics were * collected from. Zone and region names could be empty if unknown. */ - 'locality'?: (_envoy_api_v2_core_Locality); + 'locality'?: (_envoy_api_v2_core_Locality | null); /** * The total number of requests successfully completed by the endpoints in the * locality. @@ -69,7 +69,7 @@ export interface UpstreamLocalityStats__Output { * Name of zone, region and optionally endpoint group these metrics were * collected from. Zone and region names could be empty if unknown. */ - 'locality'?: (_envoy_api_v2_core_Locality__Output); + 'locality': (_envoy_api_v2_core_Locality__Output | null); /** * The total number of requests successfully completed by the endpoints in the * locality. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts index 413f569ce..369f36bc2 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts @@ -16,8 +16,8 @@ export interface AccessLog { /** * Filter which is used to determine if the access log needs to be written. */ - 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter); - 'typed_config'?: (_google_protobuf_Any); + 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter | null); + 'typed_config'?: (_google_protobuf_Any | null); /** * Custom configuration that depends on the access log being instantiated. * Built-in configurations include: @@ -45,8 +45,8 @@ export interface AccessLog__Output { /** * Filter which is used to determine if the access log needs to be written. */ - 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter__Output); - 'typed_config'?: (_google_protobuf_Any__Output); + 'filter': (_envoy_config_accesslog_v3_AccessLogFilter__Output | null); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Custom configuration that depends on the access log being instantiated. * Built-in configurations include: diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts index 9470b6eaa..85a952c9c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLogFilter.ts @@ -20,51 +20,51 @@ export interface AccessLogFilter { /** * Status code filter. */ - 'status_code_filter'?: (_envoy_config_accesslog_v3_StatusCodeFilter); + 'status_code_filter'?: (_envoy_config_accesslog_v3_StatusCodeFilter | null); /** * Duration filter. */ - 'duration_filter'?: (_envoy_config_accesslog_v3_DurationFilter); + 'duration_filter'?: (_envoy_config_accesslog_v3_DurationFilter | null); /** * Not health check filter. */ - 'not_health_check_filter'?: (_envoy_config_accesslog_v3_NotHealthCheckFilter); + 'not_health_check_filter'?: (_envoy_config_accesslog_v3_NotHealthCheckFilter | null); /** * Traceable filter. */ - 'traceable_filter'?: (_envoy_config_accesslog_v3_TraceableFilter); + 'traceable_filter'?: (_envoy_config_accesslog_v3_TraceableFilter | null); /** * Runtime filter. */ - 'runtime_filter'?: (_envoy_config_accesslog_v3_RuntimeFilter); + 'runtime_filter'?: (_envoy_config_accesslog_v3_RuntimeFilter | null); /** * And filter. */ - 'and_filter'?: (_envoy_config_accesslog_v3_AndFilter); + 'and_filter'?: (_envoy_config_accesslog_v3_AndFilter | null); /** * Or filter. */ - 'or_filter'?: (_envoy_config_accesslog_v3_OrFilter); + 'or_filter'?: (_envoy_config_accesslog_v3_OrFilter | null); /** * Header filter. */ - 'header_filter'?: (_envoy_config_accesslog_v3_HeaderFilter); + 'header_filter'?: (_envoy_config_accesslog_v3_HeaderFilter | null); /** * Response flag filter. */ - 'response_flag_filter'?: (_envoy_config_accesslog_v3_ResponseFlagFilter); + 'response_flag_filter'?: (_envoy_config_accesslog_v3_ResponseFlagFilter | null); /** * gRPC status filter. */ - 'grpc_status_filter'?: (_envoy_config_accesslog_v3_GrpcStatusFilter); + 'grpc_status_filter'?: (_envoy_config_accesslog_v3_GrpcStatusFilter | null); /** * Extension filter. */ - 'extension_filter'?: (_envoy_config_accesslog_v3_ExtensionFilter); + 'extension_filter'?: (_envoy_config_accesslog_v3_ExtensionFilter | null); /** * Metadata Filter */ - 'metadata_filter'?: (_envoy_config_accesslog_v3_MetadataFilter); + 'metadata_filter'?: (_envoy_config_accesslog_v3_MetadataFilter | null); 'filter_specifier'?: "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"|"metadata_filter"; } @@ -75,50 +75,50 @@ export interface AccessLogFilter__Output { /** * Status code filter. */ - 'status_code_filter'?: (_envoy_config_accesslog_v3_StatusCodeFilter__Output); + 'status_code_filter'?: (_envoy_config_accesslog_v3_StatusCodeFilter__Output | null); /** * Duration filter. */ - 'duration_filter'?: (_envoy_config_accesslog_v3_DurationFilter__Output); + 'duration_filter'?: (_envoy_config_accesslog_v3_DurationFilter__Output | null); /** * Not health check filter. */ - 'not_health_check_filter'?: (_envoy_config_accesslog_v3_NotHealthCheckFilter__Output); + 'not_health_check_filter'?: (_envoy_config_accesslog_v3_NotHealthCheckFilter__Output | null); /** * Traceable filter. */ - 'traceable_filter'?: (_envoy_config_accesslog_v3_TraceableFilter__Output); + 'traceable_filter'?: (_envoy_config_accesslog_v3_TraceableFilter__Output | null); /** * Runtime filter. */ - 'runtime_filter'?: (_envoy_config_accesslog_v3_RuntimeFilter__Output); + 'runtime_filter'?: (_envoy_config_accesslog_v3_RuntimeFilter__Output | null); /** * And filter. */ - 'and_filter'?: (_envoy_config_accesslog_v3_AndFilter__Output); + 'and_filter'?: (_envoy_config_accesslog_v3_AndFilter__Output | null); /** * Or filter. */ - 'or_filter'?: (_envoy_config_accesslog_v3_OrFilter__Output); + 'or_filter'?: (_envoy_config_accesslog_v3_OrFilter__Output | null); /** * Header filter. */ - 'header_filter'?: (_envoy_config_accesslog_v3_HeaderFilter__Output); + 'header_filter'?: (_envoy_config_accesslog_v3_HeaderFilter__Output | null); /** * Response flag filter. */ - 'response_flag_filter'?: (_envoy_config_accesslog_v3_ResponseFlagFilter__Output); + 'response_flag_filter'?: (_envoy_config_accesslog_v3_ResponseFlagFilter__Output | null); /** * gRPC status filter. */ - 'grpc_status_filter'?: (_envoy_config_accesslog_v3_GrpcStatusFilter__Output); + 'grpc_status_filter'?: (_envoy_config_accesslog_v3_GrpcStatusFilter__Output | null); /** * Extension filter. */ - 'extension_filter'?: (_envoy_config_accesslog_v3_ExtensionFilter__Output); + 'extension_filter'?: (_envoy_config_accesslog_v3_ExtensionFilter__Output | null); /** * Metadata Filter */ - 'metadata_filter'?: (_envoy_config_accesslog_v3_MetadataFilter__Output); + 'metadata_filter'?: (_envoy_config_accesslog_v3_MetadataFilter__Output | null); 'filter_specifier': "status_code_filter"|"duration_filter"|"not_health_check_filter"|"traceable_filter"|"runtime_filter"|"and_filter"|"or_filter"|"header_filter"|"response_flag_filter"|"grpc_status_filter"|"extension_filter"|"metadata_filter"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts index 118a47a75..07893f2dd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ComparisonFilter.ts @@ -30,7 +30,7 @@ export interface ComparisonFilter { /** * Value to compare against. */ - 'value'?: (_envoy_config_core_v3_RuntimeUInt32); + 'value'?: (_envoy_config_core_v3_RuntimeUInt32 | null); } /** @@ -44,5 +44,5 @@ export interface ComparisonFilter__Output { /** * Value to compare against. */ - 'value'?: (_envoy_config_core_v3_RuntimeUInt32__Output); + 'value': (_envoy_config_core_v3_RuntimeUInt32__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts index 03b0500e8..ee61e55fa 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/DurationFilter.ts @@ -9,7 +9,7 @@ export interface DurationFilter { /** * Comparison. */ - 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter); + 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter | null); } /** @@ -19,5 +19,5 @@ export interface DurationFilter__Output { /** * Comparison. */ - 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter__Output); + 'comparison': (_envoy_config_accesslog_v3_ComparisonFilter__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts index 127618eef..19edb671b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/ExtensionFilter.ts @@ -11,7 +11,7 @@ export interface ExtensionFilter { * match a statically registered filter. */ 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Custom configuration that depends on the filter being instantiated. */ @@ -27,7 +27,7 @@ export interface ExtensionFilter__Output { * match a statically registered filter. */ 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Custom configuration that depends on the filter being instantiated. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts index 9cda884b3..294084d1c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/HeaderFilter.ts @@ -10,7 +10,7 @@ export interface HeaderFilter { * Only requests with a header which matches the specified HeaderMatcher will * pass the filter check. */ - 'header'?: (_envoy_config_route_v3_HeaderMatcher); + 'header'?: (_envoy_config_route_v3_HeaderMatcher | null); } /** @@ -21,5 +21,5 @@ export interface HeaderFilter__Output { * Only requests with a header which matches the specified HeaderMatcher will * pass the filter check. */ - 'header'?: (_envoy_config_route_v3_HeaderMatcher__Output); + 'header': (_envoy_config_route_v3_HeaderMatcher__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts index 7fdd1d447..cd821fef6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/MetadataFilter.ts @@ -17,12 +17,12 @@ export interface MetadataFilter { * access_log_hint metadata, set the filter to "envoy.common" and the path to * "access_log_hint", and the value to "true". */ - 'matcher'?: (_envoy_type_matcher_v3_MetadataMatcher); + 'matcher'?: (_envoy_type_matcher_v3_MetadataMatcher | null); /** * Default result if the key does not exist in dynamic metadata: if unset or * true, then log; if false, then don't log. */ - 'match_if_key_not_found'?: (_google_protobuf_BoolValue); + 'match_if_key_not_found'?: (_google_protobuf_BoolValue | null); } /** @@ -39,10 +39,10 @@ export interface MetadataFilter__Output { * access_log_hint metadata, set the filter to "envoy.common" and the path to * "access_log_hint", and the value to "true". */ - 'matcher'?: (_envoy_type_matcher_v3_MetadataMatcher__Output); + 'matcher': (_envoy_type_matcher_v3_MetadataMatcher__Output | null); /** * Default result if the key does not exist in dynamic metadata: if unset or * true, then log; if false, then don't log. */ - 'match_if_key_not_found'?: (_google_protobuf_BoolValue__Output); + 'match_if_key_not_found': (_google_protobuf_BoolValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts index 9388f49ec..e605fa1a4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts @@ -16,7 +16,7 @@ export interface RuntimeFilter { * The default sampling percentage. If not specified, defaults to 0% with * denominator of 100. */ - 'percent_sampled'?: (_envoy_type_v3_FractionalPercent); + 'percent_sampled'?: (_envoy_type_v3_FractionalPercent | null); /** * By default, sampling pivots on the header * :ref:`x-request-id` being @@ -51,7 +51,7 @@ export interface RuntimeFilter__Output { * The default sampling percentage. If not specified, defaults to 0% with * denominator of 100. */ - 'percent_sampled'?: (_envoy_type_v3_FractionalPercent__Output); + 'percent_sampled': (_envoy_type_v3_FractionalPercent__Output | null); /** * By default, sampling pivots on the header * :ref:`x-request-id` being diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts index 313ed86ca..a071b5cbb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/StatusCodeFilter.ts @@ -9,7 +9,7 @@ export interface StatusCodeFilter { /** * Comparison. */ - 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter); + 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter | null); } /** @@ -19,5 +19,5 @@ export interface StatusCodeFilter__Output { /** * Comparison. */ - 'comparison'?: (_envoy_config_accesslog_v3_ComparisonFilter__Output); + 'comparison': (_envoy_config_accesslog_v3_ComparisonFilter__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts index c4f4add69..e64afb780 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts @@ -12,14 +12,14 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget * * This parameter is optional. Defaults to 20%. */ - 'budget_percent'?: (_envoy_type_v3_Percent); + 'budget_percent'?: (_envoy_type_v3_Percent | null); /** * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the * number of active retries may never go below this number. * * This parameter is optional. Defaults to 3. */ - 'min_retry_concurrency'?: (_google_protobuf_UInt32Value); + 'min_retry_concurrency'?: (_google_protobuf_UInt32Value | null); } export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget__Output { @@ -30,14 +30,14 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget * * This parameter is optional. Defaults to 20%. */ - 'budget_percent'?: (_envoy_type_v3_Percent__Output); + 'budget_percent': (_envoy_type_v3_Percent__Output | null); /** * Specifies the minimum retry concurrency allowed for the retry budget. The limit on the * number of active retries may never go below this number. * * This parameter is optional. Defaults to 3. */ - 'min_retry_concurrency'?: (_google_protobuf_UInt32Value__Output); + 'min_retry_concurrency': (_google_protobuf_UInt32Value__Output | null); } /** @@ -55,22 +55,22 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds { * The maximum number of connections that Envoy will make to the upstream * cluster. If not specified, the default is 1024. */ - 'max_connections'?: (_google_protobuf_UInt32Value); + 'max_connections'?: (_google_protobuf_UInt32Value | null); /** * The maximum number of pending requests that Envoy will allow to the * upstream cluster. If not specified, the default is 1024. */ - 'max_pending_requests'?: (_google_protobuf_UInt32Value); + 'max_pending_requests'?: (_google_protobuf_UInt32Value | null); /** * The maximum number of parallel requests that Envoy will make to the * upstream cluster. If not specified, the default is 1024. */ - 'max_requests'?: (_google_protobuf_UInt32Value); + 'max_requests'?: (_google_protobuf_UInt32Value | null); /** * The maximum number of parallel retries that Envoy will allow to the * upstream cluster. If not specified, the default is 3. */ - 'max_retries'?: (_google_protobuf_UInt32Value); + 'max_retries'?: (_google_protobuf_UInt32Value | null); /** * Specifies a limit on concurrent retries in relation to the number of active requests. This * parameter is optional. @@ -80,7 +80,7 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds { * If this field is set, the retry budget will override any configured retry circuit * breaker. */ - 'retry_budget'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget); + 'retry_budget'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget | null); /** * If track_remaining is true, then stats will be published that expose * the number of resources remaining until the circuit breakers open. If @@ -99,7 +99,7 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds { * :ref:`Circuit Breaking ` for * more details. */ - 'max_connection_pools'?: (_google_protobuf_UInt32Value); + 'max_connection_pools'?: (_google_protobuf_UInt32Value | null); } /** @@ -117,22 +117,22 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output { * The maximum number of connections that Envoy will make to the upstream * cluster. If not specified, the default is 1024. */ - 'max_connections'?: (_google_protobuf_UInt32Value__Output); + 'max_connections': (_google_protobuf_UInt32Value__Output | null); /** * The maximum number of pending requests that Envoy will allow to the * upstream cluster. If not specified, the default is 1024. */ - 'max_pending_requests'?: (_google_protobuf_UInt32Value__Output); + 'max_pending_requests': (_google_protobuf_UInt32Value__Output | null); /** * The maximum number of parallel requests that Envoy will make to the * upstream cluster. If not specified, the default is 1024. */ - 'max_requests'?: (_google_protobuf_UInt32Value__Output); + 'max_requests': (_google_protobuf_UInt32Value__Output | null); /** * The maximum number of parallel retries that Envoy will allow to the * upstream cluster. If not specified, the default is 3. */ - 'max_retries'?: (_google_protobuf_UInt32Value__Output); + 'max_retries': (_google_protobuf_UInt32Value__Output | null); /** * Specifies a limit on concurrent retries in relation to the number of active requests. This * parameter is optional. @@ -142,7 +142,7 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output { * If this field is set, the retry budget will override any configured retry circuit * breaker. */ - 'retry_budget'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget__Output); + 'retry_budget': (_envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget__Output | null); /** * If track_remaining is true, then stats will be published that expose * the number of resources remaining until the circuit breakers open. If @@ -161,7 +161,7 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output { * :ref:`Circuit Breaking ` for * more details. */ - 'max_connection_pools'?: (_google_protobuf_UInt32Value__Output); + 'max_connection_pools': (_google_protobuf_UInt32Value__Output | null); } /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts index fa76fba89..c20440704 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts @@ -56,9 +56,9 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig { * .. note:: * The specified percent will be truncated to the nearest 1%. */ - 'healthy_panic_threshold'?: (_envoy_type_v3_Percent); - 'zone_aware_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig); - 'locality_weighted_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig); + 'healthy_panic_threshold'?: (_envoy_type_v3_Percent | null); + 'zone_aware_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig | null); + 'locality_weighted_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig | null); /** * If set, all health check/weight/metadata updates that happen within this duration will be * merged and delivered in one shot when the duration expires. The start of the duration is when @@ -75,7 +75,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig { * because merging those updates isn't currently safe. See * https://github.com/envoyproxy/envoy/pull/3941. */ - 'update_merge_window'?: (_google_protobuf_Duration); + 'update_merge_window'?: (_google_protobuf_Duration | null); /** * If set to true, Envoy will :ref:`exclude ` new hosts * when computing load balancing weights until they have been health checked for the first time. @@ -90,7 +90,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig { /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ - 'consistent_hashing_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig); + 'consistent_hashing_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig | null); 'locality_config_specifier'?: "zone_aware_lb_config"|"locality_weighted_lb_config"; } @@ -107,9 +107,9 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig__Output { * .. note:: * The specified percent will be truncated to the nearest 1%. */ - 'healthy_panic_threshold'?: (_envoy_type_v3_Percent__Output); - 'zone_aware_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output); - 'locality_weighted_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output); + 'healthy_panic_threshold': (_envoy_type_v3_Percent__Output | null); + 'zone_aware_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConfig__Output | null); + 'locality_weighted_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_LocalityWeightedLbConfig__Output | null); /** * If set, all health check/weight/metadata updates that happen within this duration will be * merged and delivered in one shot when the duration expires. The start of the duration is when @@ -126,7 +126,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig__Output { * because merging those updates isn't currently safe. See * https://github.com/envoyproxy/envoy/pull/3941. */ - 'update_merge_window'?: (_google_protobuf_Duration__Output); + 'update_merge_window': (_google_protobuf_Duration__Output | null); /** * If set to true, Envoy will :ref:`exclude ` new hosts * when computing load balancing weights until they have been health checked for the first time. @@ -141,7 +141,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig__Output { /** * Common Configuration for all consistent hashing load balancers (MaglevLb, RingHashLb, etc.) */ - 'consistent_hashing_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output); + 'consistent_hashing_lb_config': (_envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashingLbConfig__Output | null); 'locality_config_specifier': "zone_aware_lb_config"|"locality_weighted_lb_config"; } @@ -174,7 +174,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashi * This is an O(N) algorithm, unlike other load balancers. Using a lower `hash_balance_factor` results in more hosts * being probed, so use a higher value if you require better performance. */ - 'hash_balance_factor'?: (_google_protobuf_UInt32Value); + 'hash_balance_factor'?: (_google_protobuf_UInt32Value | null); } /** @@ -206,7 +206,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ConsistentHashi * This is an O(N) algorithm, unlike other load balancers. Using a lower `hash_balance_factor` results in more hosts * being probed, so use a higher value if you require better performance. */ - 'hash_balance_factor'?: (_google_protobuf_UInt32Value__Output); + 'hash_balance_factor': (_google_protobuf_UInt32Value__Output | null); } /** @@ -221,7 +221,7 @@ export interface _envoy_config_cluster_v3_Cluster_CustomClusterType { * Cluster specific configuration which depends on the cluster being instantiated. * See the supported cluster for further documentation. */ - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); } /** @@ -236,7 +236,7 @@ export interface _envoy_config_cluster_v3_Cluster_CustomClusterType__Output { * Cluster specific configuration which depends on the cluster being instantiated. * See the supported cluster for further documentation. */ - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config': (_google_protobuf_Any__Output | null); } // Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto @@ -303,7 +303,7 @@ export interface _envoy_config_cluster_v3_Cluster_EdsClusterConfig { /** * Configuration for the source of EDS updates for this Cluster. */ - 'eds_config'?: (_envoy_config_core_v3_ConfigSource); + 'eds_config'?: (_envoy_config_core_v3_ConfigSource | null); /** * Optional alternative to cluster name to present to EDS. This does not * have the same restrictions as cluster name, i.e. it may be arbitrary @@ -319,7 +319,7 @@ export interface _envoy_config_cluster_v3_Cluster_EdsClusterConfig__Output { /** * Configuration for the source of EDS updates for this Cluster. */ - 'eds_config'?: (_envoy_config_core_v3_ConfigSource__Output); + 'eds_config': (_envoy_config_core_v3_ConfigSource__Output | null); /** * Optional alternative to cluster name to present to EDS. This does not * have the same restrictions as cluster name, i.e. it may be arbitrary @@ -420,7 +420,7 @@ export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig { * is the same as a fallback_policy of * :ref:`NO_FALLBACK`. */ - 'default_subset'?: (_google_protobuf_Struct); + 'default_subset'?: (_google_protobuf_Struct | null); /** * For each entry, LbEndpoint.Metadata's * *envoy.lb* namespace is traversed and a subset is created for each unique @@ -497,7 +497,7 @@ export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig__Output { * is the same as a fallback_policy of * :ref:`NO_FALLBACK`. */ - 'default_subset'?: (_google_protobuf_Struct__Output); + 'default_subset': (_google_protobuf_Struct__Output | null); /** * For each entry, LbEndpoint.Metadata's * *envoy.lb* namespace is traversed and a subset is created for each unique @@ -693,7 +693,7 @@ export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig { * The number of random healthy hosts from which the host with the fewest active requests will * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. */ - 'choice_count'?: (_google_protobuf_UInt32Value); + 'choice_count'?: (_google_protobuf_UInt32Value | null); /** * The following formula is used to calculate the dynamic weights when hosts have different load * balancing weights: @@ -719,7 +719,7 @@ export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig { * .. note:: * This setting only takes effect if all host weights are not equal. */ - 'active_request_bias'?: (_envoy_config_core_v3_RuntimeDouble); + 'active_request_bias'?: (_envoy_config_core_v3_RuntimeDouble | null); } /** @@ -730,7 +730,7 @@ export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output { * The number of random healthy hosts from which the host with the fewest active requests will * be chosen. Defaults to 2 so that we perform two-choice selection if the field is not set. */ - 'choice_count'?: (_google_protobuf_UInt32Value__Output); + 'choice_count': (_google_protobuf_UInt32Value__Output | null); /** * The following formula is used to calculate the dynamic weights when hosts have different load * balancing weights: @@ -756,7 +756,7 @@ export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output { * .. note:: * This setting only takes effect if all host weights are not equal. */ - 'active_request_bias'?: (_envoy_config_core_v3_RuntimeDouble__Output); + 'active_request_bias': (_envoy_config_core_v3_RuntimeDouble__Output | null); } /** @@ -784,7 +784,7 @@ export interface _envoy_config_cluster_v3_Cluster_MaglevLbConfig { * upstream as it was before. Increasing the table size reduces the amount of disruption. * The table size must be prime number. If it is not specified, the default is 65537. */ - 'table_size'?: (_google_protobuf_UInt64Value); + 'table_size'?: (_google_protobuf_UInt64Value | null); } /** @@ -798,7 +798,7 @@ export interface _envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output { * upstream as it was before. Increasing the table size reduces the amount of disruption. * The table size must be prime number. If it is not specified, the default is 65537. */ - 'table_size'?: (_google_protobuf_UInt64Value__Output); + 'table_size': (_google_protobuf_UInt64Value__Output | null); } /** @@ -876,7 +876,7 @@ export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy { * This is limited somewhat arbitrarily to 3 because preconnecting too aggressively can * harm latency more than the preconnecting helps. */ - 'per_upstream_preconnect_ratio'?: (_google_protobuf_DoubleValue); + 'per_upstream_preconnect_ratio'?: (_google_protobuf_DoubleValue | null); /** * Indicates how many many streams (rounded up) can be anticipated across a cluster for each * stream, useful for low QPS services. This is currently supported for a subset of @@ -901,7 +901,7 @@ export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy { * basically preconnecting max(predictive-preconnect, per-upstream-preconnect), for each * upstream. */ - 'predictive_preconnect_ratio'?: (_google_protobuf_DoubleValue); + 'predictive_preconnect_ratio'?: (_google_protobuf_DoubleValue | null); } export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output { @@ -931,7 +931,7 @@ export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output { * This is limited somewhat arbitrarily to 3 because preconnecting too aggressively can * harm latency more than the preconnecting helps. */ - 'per_upstream_preconnect_ratio'?: (_google_protobuf_DoubleValue__Output); + 'per_upstream_preconnect_ratio': (_google_protobuf_DoubleValue__Output | null); /** * Indicates how many many streams (rounded up) can be anticipated across a cluster for each * stream, useful for low QPS services. This is currently supported for a subset of @@ -956,7 +956,7 @@ export interface _envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output { * basically preconnecting max(predictive-preconnect, per-upstream-preconnect), for each * upstream. */ - 'predictive_preconnect_ratio'?: (_google_protobuf_DoubleValue__Output); + 'predictive_preconnect_ratio': (_google_protobuf_DoubleValue__Output | null); } export interface _envoy_config_cluster_v3_Cluster_RefreshRate { @@ -965,14 +965,14 @@ export interface _envoy_config_cluster_v3_Cluster_RefreshRate { * than zero and less than * :ref:`max_interval `. */ - 'base_interval'?: (_google_protobuf_Duration); + 'base_interval'?: (_google_protobuf_Duration | null); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the * :ref:`base_interval ` if set. The default * is 10 times the :ref:`base_interval `. */ - 'max_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration | null); } export interface _envoy_config_cluster_v3_Cluster_RefreshRate__Output { @@ -981,14 +981,14 @@ export interface _envoy_config_cluster_v3_Cluster_RefreshRate__Output { * than zero and less than * :ref:`max_interval `. */ - 'base_interval'?: (_google_protobuf_Duration__Output); + 'base_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the * :ref:`base_interval ` if set. The default * is 10 times the :ref:`base_interval `. */ - 'max_interval'?: (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output | null); } /** @@ -1002,7 +1002,7 @@ export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig { * to 1024 entries, and limited to 8M entries. See also * :ref:`maximum_ring_size`. */ - 'minimum_ring_size'?: (_google_protobuf_UInt64Value); + 'minimum_ring_size'?: (_google_protobuf_UInt64Value | null); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to * :ref:`XX_HASH`. @@ -1013,7 +1013,7 @@ export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig { * to further constrain resource use. See also * :ref:`minimum_ring_size`. */ - 'maximum_ring_size'?: (_google_protobuf_UInt64Value); + 'maximum_ring_size'?: (_google_protobuf_UInt64Value | null); } /** @@ -1027,7 +1027,7 @@ export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output { * to 1024 entries, and limited to 8M entries. See also * :ref:`maximum_ring_size`. */ - 'minimum_ring_size'?: (_google_protobuf_UInt64Value__Output); + 'minimum_ring_size': (_google_protobuf_UInt64Value__Output | null); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to * :ref:`XX_HASH`. @@ -1038,7 +1038,7 @@ export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output { * to further constrain resource use. See also * :ref:`minimum_ring_size`. */ - 'maximum_ring_size'?: (_google_protobuf_UInt64Value__Output); + 'maximum_ring_size': (_google_protobuf_UInt64Value__Output | null); } /** @@ -1057,11 +1057,11 @@ export interface _envoy_config_cluster_v3_Cluster_TransportSocketMatch { * The endpoint's metadata entry in *envoy.transport_socket_match* is used to match * against the values specified in this field. */ - 'match'?: (_google_protobuf_Struct); + 'match'?: (_google_protobuf_Struct | null); /** * The configuration of the transport socket. */ - 'transport_socket'?: (_envoy_config_core_v3_TransportSocket); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket | null); } /** @@ -1080,11 +1080,11 @@ export interface _envoy_config_cluster_v3_Cluster_TransportSocketMatch__Output { * The endpoint's metadata entry in *envoy.transport_socket_match* is used to match * against the values specified in this field. */ - 'match'?: (_google_protobuf_Struct__Output); + 'match': (_google_protobuf_Struct__Output | null); /** * The configuration of the transport socket. */ - 'transport_socket'?: (_envoy_config_core_v3_TransportSocket__Output); + 'transport_socket': (_envoy_config_core_v3_TransportSocket__Output | null); } /** @@ -1098,7 +1098,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConf * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'routing_enabled'?: (_envoy_type_v3_Percent); + 'routing_enabled'?: (_envoy_type_v3_Percent | null); /** * Configures minimum upstream cluster size required for zone aware routing * If upstream cluster size is less than specified, zone aware routing is not performed @@ -1106,7 +1106,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConf * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'min_cluster_size'?: (_google_protobuf_UInt64Value); + 'min_cluster_size'?: (_google_protobuf_UInt64Value | null); /** * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic * mode`. Instead, the cluster will fail all @@ -1127,7 +1127,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConf * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'routing_enabled'?: (_envoy_type_v3_Percent__Output); + 'routing_enabled': (_envoy_type_v3_Percent__Output | null); /** * Configures minimum upstream cluster size required for zone aware routing * If upstream cluster size is less than specified, zone aware routing is not performed @@ -1135,7 +1135,7 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConf * * :ref:`runtime values `. * * :ref:`Zone aware routing support `. */ - 'min_cluster_size'?: (_google_protobuf_UInt64Value__Output); + 'min_cluster_size': (_google_protobuf_UInt64Value__Output | null); /** * If set to true, Envoy will not consider any hosts when the cluster is in :ref:`panic * mode`. Instead, the cluster will fail all @@ -1166,16 +1166,16 @@ export interface Cluster { /** * Configuration to use for EDS updates for the Cluster. */ - 'eds_cluster_config'?: (_envoy_config_cluster_v3_Cluster_EdsClusterConfig); + 'eds_cluster_config'?: (_envoy_config_cluster_v3_Cluster_EdsClusterConfig | null); /** * The timeout for new network connections to hosts in the cluster. */ - 'connect_timeout'?: (_google_protobuf_Duration); + 'connect_timeout'?: (_google_protobuf_Duration | null); /** * Soft limit on size of the cluster’s connections read and write buffers. If * unspecified, an implementation defined default is applied (1MiB). */ - 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value | null); /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. @@ -1195,11 +1195,11 @@ export interface Cluster { * implementations. If not specified, there is no limit. Setting this * parameter to 1 will effectively disable keep alive. */ - 'max_requests_per_connection'?: (_google_protobuf_UInt32Value); + 'max_requests_per_connection'?: (_google_protobuf_UInt32Value | null); /** * Optional :ref:`circuit breaking ` for the cluster. */ - 'circuit_breakers'?: (_envoy_config_cluster_v3_CircuitBreakers); + 'circuit_breakers'?: (_envoy_config_cluster_v3_CircuitBreakers | null); /** * Additional options when handling HTTP1 requests. * This has been deprecated in favor of http_protocol_options fields in the in the @@ -1210,7 +1210,7 @@ export interface Cluster { * ` * for example usage. */ - 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions); + 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions | null); /** * Even if default HTTP2 protocol options are desired, this field must be * set so that Envoy will assume that the upstream supports HTTP/2 when @@ -1226,7 +1226,7 @@ export interface Cluster { * ` * for example usage. */ - 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions | null); /** * If the DNS refresh rate is specified and the cluster type is either * :ref:`STRICT_DNS`, @@ -1238,7 +1238,7 @@ export interface Cluster { * and :ref:`LOGICAL_DNS` * this setting is ignored. */ - 'dns_refresh_rate'?: (_google_protobuf_Duration); + 'dns_refresh_rate'?: (_google_protobuf_Duration | null); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to @@ -1266,7 +1266,7 @@ export interface Cluster { * Each of the configuration values can be overridden via * :ref:`runtime values `. */ - 'outlier_detection'?: (_envoy_config_cluster_v3_OutlierDetection); + 'outlier_detection'?: (_envoy_config_cluster_v3_OutlierDetection | null); /** * The interval for removing stale hosts from a cluster type * :ref:`ORIGINAL_DST`. @@ -1282,21 +1282,21 @@ export interface Cluster { * :ref:`ORIGINAL_DST` * this setting is ignored. */ - 'cleanup_interval'?: (_google_protobuf_Duration); + 'cleanup_interval'?: (_google_protobuf_Duration | null); /** * Optional configuration used to bind newly established upstream connections. * This overrides any bind_config specified in the bootstrap proto. * If the address and port are empty, no bind will be performed. */ - 'upstream_bind_config'?: (_envoy_config_core_v3_BindConfig); + 'upstream_bind_config'?: (_envoy_config_core_v3_BindConfig | null); /** * Configuration for load balancing subsetting. */ - 'lb_subset_config'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig); + 'lb_subset_config'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig | null); /** * Optional configuration for the Ring Hash load balancing policy. */ - 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig); + 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig | null); /** * Optional custom transport socket implementation to use for upstream connections. * To setup TLS, set a transport socket with name `tls` and @@ -1304,7 +1304,7 @@ export interface Cluster { * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket'?: (_envoy_config_core_v3_TransportSocket); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket | null); /** * The Metadata field can be used to provide additional information about the * cluster. It can be used for stats, logging, and varying filter behavior. @@ -1312,7 +1312,7 @@ export interface Cluster { * will need the information. For instance, if the metadata is intended for * the Router filter, the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_config_core_v3_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata | null); /** * Determines how Envoy selects the protocol used to speak to upstream hosts. * This has been deprecated in favor of setting explicit protocol selection @@ -1325,7 +1325,7 @@ export interface Cluster { /** * Common configuration for all load balancer implementations. */ - 'common_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig); + 'common_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig | null); /** * An optional alternative to the cluster name to be used while emitting stats. * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be @@ -1345,11 +1345,11 @@ export interface Cluster { * ` * for example usage. */ - 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions); + 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions | null); /** * Optional options for upstream connections. */ - 'upstream_connection_options'?: (_envoy_config_cluster_v3_UpstreamConnectionOptions); + 'upstream_connection_options'?: (_envoy_config_cluster_v3_UpstreamConnectionOptions | null); /** * If an upstream host becomes unhealthy (as determined by the configured health checks * or outlier detection), immediately close all connections to the failed host. @@ -1384,11 +1384,11 @@ export interface Cluster { * Setting this allows non-EDS cluster types to contain embedded EDS equivalent * :ref:`endpoint assignments`. */ - 'load_assignment'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment); + 'load_assignment'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment | null); /** * Optional configuration for the Original Destination load balancing policy. */ - 'original_dst_lb_config'?: (_envoy_config_cluster_v3_Cluster_OriginalDstLbConfig); + 'original_dst_lb_config'?: (_envoy_config_cluster_v3_Cluster_OriginalDstLbConfig | null); /** * The extension_protocol_options field is used to provide extension-specific protocol options * for upstream connections. The key should match the extension filter name, such as @@ -1400,11 +1400,11 @@ export interface Cluster { /** * Optional configuration for the LeastRequest load balancing policy. */ - 'least_request_lb_config'?: (_envoy_config_cluster_v3_Cluster_LeastRequestLbConfig); + 'least_request_lb_config'?: (_envoy_config_cluster_v3_Cluster_LeastRequestLbConfig | null); /** * The custom cluster type. */ - 'cluster_type'?: (_envoy_config_cluster_v3_Cluster_CustomClusterType); + 'cluster_type'?: (_envoy_config_cluster_v3_Cluster_CustomClusterType | null); /** * Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, * cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS @@ -1422,7 +1422,7 @@ export interface Cluster { * :ref:`lb_policy` field has the value * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ - 'load_balancing_policy'?: (_envoy_config_cluster_v3_LoadBalancingPolicy); + 'load_balancing_policy'?: (_envoy_config_cluster_v3_LoadBalancingPolicy | null); /** * [#not-implemented-hide:] * If present, tells the client where to send load reports via LRS. If not present, the @@ -1439,7 +1439,7 @@ export interface Cluster { * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation * from the LRS stream here.] */ - 'lrs_server'?: (_envoy_config_core_v3_ConfigSource); + 'lrs_server'?: (_envoy_config_core_v3_ConfigSource | null); /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the @@ -1502,7 +1502,7 @@ export interface Cluster { * :ref:`LOGICAL_DNS` this setting is * ignored. */ - 'dns_failure_refresh_rate'?: (_envoy_config_cluster_v3_Cluster_RefreshRate); + 'dns_failure_refresh_rate'?: (_envoy_config_cluster_v3_Cluster_RefreshRate | null); /** * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. @@ -1523,7 +1523,7 @@ export interface Cluster { * ` * for example usage. */ - 'upstream_http_protocol_options'?: (_envoy_config_core_v3_UpstreamHttpProtocolOptions); + 'upstream_http_protocol_options'?: (_envoy_config_core_v3_UpstreamHttpProtocolOptions | null); /** * If track_timeout_budgets is true, the :ref:`timeout budget histograms * ` will be published for each @@ -1556,15 +1556,15 @@ export interface Cluster { * CONNECT only if a custom filter indicates it is appropriate, the custom factories * can be registered and configured here. */ - 'upstream_config'?: (_envoy_config_core_v3_TypedExtensionConfig); + 'upstream_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); /** * Configuration to track optional cluster stats. */ - 'track_cluster_stats'?: (_envoy_config_cluster_v3_TrackClusterStats); + 'track_cluster_stats'?: (_envoy_config_cluster_v3_TrackClusterStats | null); /** * Preconnect configuration for this cluster. */ - 'preconnect_policy'?: (_envoy_config_cluster_v3_Cluster_PreconnectPolicy); + 'preconnect_policy'?: (_envoy_config_cluster_v3_Cluster_PreconnectPolicy | null); /** * If `connection_pool_per_downstream_connection` is true, the cluster will use a separate * connection pool for every downstream connection @@ -1573,7 +1573,7 @@ export interface Cluster { /** * Optional configuration for the Maglev load balancing policy. */ - 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig); + 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig | null); 'cluster_discovery_type'?: "type"|"cluster_type"; /** * Optional configuration for the load balancing algorithm selected by @@ -1609,16 +1609,16 @@ export interface Cluster__Output { /** * Configuration to use for EDS updates for the Cluster. */ - 'eds_cluster_config'?: (_envoy_config_cluster_v3_Cluster_EdsClusterConfig__Output); + 'eds_cluster_config': (_envoy_config_cluster_v3_Cluster_EdsClusterConfig__Output | null); /** * The timeout for new network connections to hosts in the cluster. */ - 'connect_timeout'?: (_google_protobuf_Duration__Output); + 'connect_timeout': (_google_protobuf_Duration__Output | null); /** * Soft limit on size of the cluster’s connections read and write buffers. If * unspecified, an implementation defined default is applied (1MiB). */ - 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); + 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output | null); /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. @@ -1638,11 +1638,11 @@ export interface Cluster__Output { * implementations. If not specified, there is no limit. Setting this * parameter to 1 will effectively disable keep alive. */ - 'max_requests_per_connection'?: (_google_protobuf_UInt32Value__Output); + 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output | null); /** * Optional :ref:`circuit breaking ` for the cluster. */ - 'circuit_breakers'?: (_envoy_config_cluster_v3_CircuitBreakers__Output); + 'circuit_breakers': (_envoy_config_cluster_v3_CircuitBreakers__Output | null); /** * Additional options when handling HTTP1 requests. * This has been deprecated in favor of http_protocol_options fields in the in the @@ -1653,7 +1653,7 @@ export interface Cluster__Output { * ` * for example usage. */ - 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions__Output); + 'http_protocol_options': (_envoy_config_core_v3_Http1ProtocolOptions__Output | null); /** * Even if default HTTP2 protocol options are desired, this field must be * set so that Envoy will assume that the upstream supports HTTP/2 when @@ -1669,7 +1669,7 @@ export interface Cluster__Output { * ` * for example usage. */ - 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions__Output); + 'http2_protocol_options': (_envoy_config_core_v3_Http2ProtocolOptions__Output | null); /** * If the DNS refresh rate is specified and the cluster type is either * :ref:`STRICT_DNS`, @@ -1681,7 +1681,7 @@ export interface Cluster__Output { * and :ref:`LOGICAL_DNS` * this setting is ignored. */ - 'dns_refresh_rate'?: (_google_protobuf_Duration__Output); + 'dns_refresh_rate': (_google_protobuf_Duration__Output | null); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to @@ -1709,7 +1709,7 @@ export interface Cluster__Output { * Each of the configuration values can be overridden via * :ref:`runtime values `. */ - 'outlier_detection'?: (_envoy_config_cluster_v3_OutlierDetection__Output); + 'outlier_detection': (_envoy_config_cluster_v3_OutlierDetection__Output | null); /** * The interval for removing stale hosts from a cluster type * :ref:`ORIGINAL_DST`. @@ -1725,21 +1725,21 @@ export interface Cluster__Output { * :ref:`ORIGINAL_DST` * this setting is ignored. */ - 'cleanup_interval'?: (_google_protobuf_Duration__Output); + 'cleanup_interval': (_google_protobuf_Duration__Output | null); /** * Optional configuration used to bind newly established upstream connections. * This overrides any bind_config specified in the bootstrap proto. * If the address and port are empty, no bind will be performed. */ - 'upstream_bind_config'?: (_envoy_config_core_v3_BindConfig__Output); + 'upstream_bind_config': (_envoy_config_core_v3_BindConfig__Output | null); /** * Configuration for load balancing subsetting. */ - 'lb_subset_config'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig__Output); + 'lb_subset_config': (_envoy_config_cluster_v3_Cluster_LbSubsetConfig__Output | null); /** * Optional configuration for the Ring Hash load balancing policy. */ - 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output); + 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output | null); /** * Optional custom transport socket implementation to use for upstream connections. * To setup TLS, set a transport socket with name `tls` and @@ -1747,7 +1747,7 @@ export interface Cluster__Output { * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket'?: (_envoy_config_core_v3_TransportSocket__Output); + 'transport_socket': (_envoy_config_core_v3_TransportSocket__Output | null); /** * The Metadata field can be used to provide additional information about the * cluster. It can be used for stats, logging, and varying filter behavior. @@ -1755,7 +1755,7 @@ export interface Cluster__Output { * will need the information. For instance, if the metadata is intended for * the Router filter, the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata': (_envoy_config_core_v3_Metadata__Output | null); /** * Determines how Envoy selects the protocol used to speak to upstream hosts. * This has been deprecated in favor of setting explicit protocol selection @@ -1768,7 +1768,7 @@ export interface Cluster__Output { /** * Common configuration for all load balancer implementations. */ - 'common_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig__Output); + 'common_lb_config': (_envoy_config_cluster_v3_Cluster_CommonLbConfig__Output | null); /** * An optional alternative to the cluster name to be used while emitting stats. * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be @@ -1788,11 +1788,11 @@ export interface Cluster__Output { * ` * for example usage. */ - 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions__Output); + 'common_http_protocol_options': (_envoy_config_core_v3_HttpProtocolOptions__Output | null); /** * Optional options for upstream connections. */ - 'upstream_connection_options'?: (_envoy_config_cluster_v3_UpstreamConnectionOptions__Output); + 'upstream_connection_options': (_envoy_config_cluster_v3_UpstreamConnectionOptions__Output | null); /** * If an upstream host becomes unhealthy (as determined by the configured health checks * or outlier detection), immediately close all connections to the failed host. @@ -1827,11 +1827,11 @@ export interface Cluster__Output { * Setting this allows non-EDS cluster types to contain embedded EDS equivalent * :ref:`endpoint assignments`. */ - 'load_assignment'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment__Output); + 'load_assignment': (_envoy_config_endpoint_v3_ClusterLoadAssignment__Output | null); /** * Optional configuration for the Original Destination load balancing policy. */ - 'original_dst_lb_config'?: (_envoy_config_cluster_v3_Cluster_OriginalDstLbConfig__Output); + 'original_dst_lb_config'?: (_envoy_config_cluster_v3_Cluster_OriginalDstLbConfig__Output | null); /** * The extension_protocol_options field is used to provide extension-specific protocol options * for upstream connections. The key should match the extension filter name, such as @@ -1839,15 +1839,15 @@ export interface Cluster__Output { * specific options. * [#next-major-version: make this a list of typed extensions.] */ - 'typed_extension_protocol_options'?: ({[key: string]: _google_protobuf_Any__Output}); + 'typed_extension_protocol_options': ({[key: string]: _google_protobuf_Any__Output}); /** * Optional configuration for the LeastRequest load balancing policy. */ - 'least_request_lb_config'?: (_envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output); + 'least_request_lb_config'?: (_envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output | null); /** * The custom cluster type. */ - 'cluster_type'?: (_envoy_config_cluster_v3_Cluster_CustomClusterType__Output); + 'cluster_type'?: (_envoy_config_cluster_v3_Cluster_CustomClusterType__Output | null); /** * Optional configuration for setting cluster's DNS refresh rate. If the value is set to true, * cluster's DNS refresh rate will be set to resource record's TTL which comes from DNS @@ -1865,7 +1865,7 @@ export interface Cluster__Output { * :ref:`lb_policy` field has the value * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ - 'load_balancing_policy'?: (_envoy_config_cluster_v3_LoadBalancingPolicy__Output); + 'load_balancing_policy': (_envoy_config_cluster_v3_LoadBalancingPolicy__Output | null); /** * [#not-implemented-hide:] * If present, tells the client where to send load reports via LRS. If not present, the @@ -1882,7 +1882,7 @@ export interface Cluster__Output { * maybe by allowing LRS to go on the ADS stream, or maybe by moving some of the negotiation * from the LRS stream here.] */ - 'lrs_server'?: (_envoy_config_core_v3_ConfigSource__Output); + 'lrs_server': (_envoy_config_core_v3_ConfigSource__Output | null); /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the @@ -1945,7 +1945,7 @@ export interface Cluster__Output { * :ref:`LOGICAL_DNS` this setting is * ignored. */ - 'dns_failure_refresh_rate'?: (_envoy_config_cluster_v3_Cluster_RefreshRate__Output); + 'dns_failure_refresh_rate': (_envoy_config_cluster_v3_Cluster_RefreshRate__Output | null); /** * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. @@ -1966,7 +1966,7 @@ export interface Cluster__Output { * ` * for example usage. */ - 'upstream_http_protocol_options'?: (_envoy_config_core_v3_UpstreamHttpProtocolOptions__Output); + 'upstream_http_protocol_options': (_envoy_config_core_v3_UpstreamHttpProtocolOptions__Output | null); /** * If track_timeout_budgets is true, the :ref:`timeout budget histograms * ` will be published for each @@ -1999,15 +1999,15 @@ export interface Cluster__Output { * CONNECT only if a custom filter indicates it is appropriate, the custom factories * can be registered and configured here. */ - 'upstream_config'?: (_envoy_config_core_v3_TypedExtensionConfig__Output); + 'upstream_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); /** * Configuration to track optional cluster stats. */ - 'track_cluster_stats'?: (_envoy_config_cluster_v3_TrackClusterStats__Output); + 'track_cluster_stats': (_envoy_config_cluster_v3_TrackClusterStats__Output | null); /** * Preconnect configuration for this cluster. */ - 'preconnect_policy'?: (_envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output); + 'preconnect_policy': (_envoy_config_cluster_v3_Cluster_PreconnectPolicy__Output | null); /** * If `connection_pool_per_downstream_connection` is true, the cluster will use a separate * connection pool for every downstream connection @@ -2016,7 +2016,7 @@ export interface Cluster__Output { /** * Optional configuration for the Maglev load balancing policy. */ - 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output); + 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output | null); 'cluster_discovery_type': "type"|"cluster_type"; /** * Optional configuration for the load balancing algorithm selected by diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts index aab9c6281..8b1394d4b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/ClusterCollection.ts @@ -7,7 +7,7 @@ import type { CollectionEntry as _xds_core_v3_CollectionEntry, CollectionEntry__ * [#not-implemented-hide:] */ export interface ClusterCollection { - 'entries'?: (_xds_core_v3_CollectionEntry); + 'entries'?: (_xds_core_v3_CollectionEntry | null); } /** @@ -15,5 +15,5 @@ export interface ClusterCollection { * [#not-implemented-hide:] */ export interface ClusterCollection__Output { - 'entries'?: (_xds_core_v3_CollectionEntry__Output); + 'entries': (_xds_core_v3_CollectionEntry__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts index 53feedb98..b2ccda5e4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts @@ -12,7 +12,7 @@ export interface Filter { * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. */ - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); } export interface Filter__Output { @@ -25,5 +25,5 @@ export interface Filter__Output { * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. */ - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config': (_google_protobuf_Any__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts index 29e343218..128a6458a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts @@ -7,7 +7,7 @@ export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy { * Required. The name of the LB policy. */ 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); } export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy__Output { @@ -15,7 +15,7 @@ export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy__Output { * Required. The name of the LB policy. */ 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config': (_google_protobuf_Any__Output | null); } /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts index f37001691..abae2e270 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts @@ -14,44 +14,44 @@ export interface OutlierDetection { * to 5xx error codes before a consecutive 5xx ejection * occurs. Defaults to 5. */ - 'consecutive_5xx'?: (_google_protobuf_UInt32Value); + 'consecutive_5xx'?: (_google_protobuf_UInt32Value | null); /** * The time interval between ejection analysis sweeps. This can result in * both new ejections as well as hosts being returned to service. Defaults * to 10000ms or 10s. */ - 'interval'?: (_google_protobuf_Duration); + 'interval'?: (_google_protobuf_Duration | null); /** * The base time that a host is ejected for. The real time is equal to the * base time multiplied by the number of times the host has been ejected and is * capped by :ref:`max_ejection_time`. * Defaults to 30000ms or 30s. */ - 'base_ejection_time'?: (_google_protobuf_Duration); + 'base_ejection_time'?: (_google_protobuf_Duration | null); /** * The maximum % of an upstream cluster that can be ejected due to outlier * detection. Defaults to 10% but will eject at least one host regardless of the value. */ - 'max_ejection_percent'?: (_google_protobuf_UInt32Value); + 'max_ejection_percent'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive 5xx. This setting can be used to disable * ejection or to ramp it up slowly. Defaults to 100. */ - 'enforcing_consecutive_5xx'?: (_google_protobuf_UInt32Value); + 'enforcing_consecutive_5xx'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through success rate statistics. This setting can be used to * disable ejection or to ramp it up slowly. Defaults to 100. */ - 'enforcing_success_rate'?: (_google_protobuf_UInt32Value); + 'enforcing_success_rate'?: (_google_protobuf_UInt32Value | null); /** * The number of hosts in a cluster that must have enough request volume to * detect success rate outliers. If the number of hosts is less than this * setting, outlier detection via success rate statistics is not performed * for any host in the cluster. Defaults to 5. */ - 'success_rate_minimum_hosts'?: (_google_protobuf_UInt32Value); + 'success_rate_minimum_hosts'?: (_google_protobuf_UInt32Value | null); /** * The minimum number of total requests that must be collected in one * interval (as defined by the interval duration above) to include this host @@ -59,7 +59,7 @@ export interface OutlierDetection { * setting, outlier detection via success rate statistics is not performed * for that host. Defaults to 100. */ - 'success_rate_request_volume'?: (_google_protobuf_UInt32Value); + 'success_rate_request_volume'?: (_google_protobuf_UInt32Value | null); /** * This factor is used to determine the ejection threshold for success rate * outlier ejection. The ejection threshold is the difference between the @@ -69,18 +69,18 @@ export interface OutlierDetection { * double. That is, if the desired factor is 1.9, the runtime value should * be 1900. Defaults to 1900. */ - 'success_rate_stdev_factor'?: (_google_protobuf_UInt32Value); + 'success_rate_stdev_factor'?: (_google_protobuf_UInt32Value | null); /** * The number of consecutive gateway failures (502, 503, 504 status codes) * before a consecutive gateway failure ejection occurs. Defaults to 5. */ - 'consecutive_gateway_failure'?: (_google_protobuf_UInt32Value); + 'consecutive_gateway_failure'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive gateway failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 0. */ - 'enforcing_consecutive_gateway_failure'?: (_google_protobuf_UInt32Value); + 'enforcing_consecutive_gateway_failure'?: (_google_protobuf_UInt32Value | null); /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: @@ -97,7 +97,7 @@ export interface OutlierDetection { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); + 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive locally originated failures. This setting can be @@ -106,7 +106,7 @@ export interface OutlierDetection { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value); + 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through success rate statistics for locally originated errors. @@ -115,13 +115,13 @@ export interface OutlierDetection { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value); + 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value | null); /** * The failure percentage to use when determining failure percentage-based outlier detection. If * the failure percentage of a given host is greater than or equal to this value, it will be * ejected. Defaults to 85. */ - 'failure_percentage_threshold'?: (_google_protobuf_UInt32Value); + 'failure_percentage_threshold'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status is detected through * failure percentage statistics. This setting can be used to disable ejection or to ramp it up @@ -130,32 +130,32 @@ export interface OutlierDetection { * [#next-major-version: setting this without setting failure_percentage_threshold should be * invalid in v4.] */ - 'enforcing_failure_percentage'?: (_google_protobuf_UInt32Value); + 'enforcing_failure_percentage'?: (_google_protobuf_UInt32Value | null); /** * The % chance that a host will be actually ejected when an outlier status is detected through * local-origin failure percentage statistics. This setting can be used to disable ejection or to * ramp it up slowly. Defaults to 0. */ - 'enforcing_failure_percentage_local_origin'?: (_google_protobuf_UInt32Value); + 'enforcing_failure_percentage_local_origin'?: (_google_protobuf_UInt32Value | null); /** * The minimum number of hosts in a cluster in order to perform failure percentage-based ejection. * If the total number of hosts in the cluster is less than this value, failure percentage-based * ejection will not be performed. Defaults to 5. */ - 'failure_percentage_minimum_hosts'?: (_google_protobuf_UInt32Value); + 'failure_percentage_minimum_hosts'?: (_google_protobuf_UInt32Value | null); /** * The minimum number of total requests that must be collected in one interval (as defined by the * interval duration above) to perform failure percentage-based ejection for this host. If the * volume is lower than this setting, failure percentage-based ejection will not be performed for * this host. Defaults to 50. */ - 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value); + 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value | null); /** * The maximum time that a host is ejected for. See :ref:`base_ejection_time` * for more information. * Defaults to 300000ms or 300s. */ - 'max_ejection_time'?: (_google_protobuf_Duration); + 'max_ejection_time'?: (_google_protobuf_Duration | null); } /** @@ -169,44 +169,44 @@ export interface OutlierDetection__Output { * to 5xx error codes before a consecutive 5xx ejection * occurs. Defaults to 5. */ - 'consecutive_5xx'?: (_google_protobuf_UInt32Value__Output); + 'consecutive_5xx': (_google_protobuf_UInt32Value__Output | null); /** * The time interval between ejection analysis sweeps. This can result in * both new ejections as well as hosts being returned to service. Defaults * to 10000ms or 10s. */ - 'interval'?: (_google_protobuf_Duration__Output); + 'interval': (_google_protobuf_Duration__Output | null); /** * The base time that a host is ejected for. The real time is equal to the * base time multiplied by the number of times the host has been ejected and is * capped by :ref:`max_ejection_time`. * Defaults to 30000ms or 30s. */ - 'base_ejection_time'?: (_google_protobuf_Duration__Output); + 'base_ejection_time': (_google_protobuf_Duration__Output | null); /** * The maximum % of an upstream cluster that can be ejected due to outlier * detection. Defaults to 10% but will eject at least one host regardless of the value. */ - 'max_ejection_percent'?: (_google_protobuf_UInt32Value__Output); + 'max_ejection_percent': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive 5xx. This setting can be used to disable * ejection or to ramp it up slowly. Defaults to 100. */ - 'enforcing_consecutive_5xx'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_5xx': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through success rate statistics. This setting can be used to * disable ejection or to ramp it up slowly. Defaults to 100. */ - 'enforcing_success_rate'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_success_rate': (_google_protobuf_UInt32Value__Output | null); /** * The number of hosts in a cluster that must have enough request volume to * detect success rate outliers. If the number of hosts is less than this * setting, outlier detection via success rate statistics is not performed * for any host in the cluster. Defaults to 5. */ - 'success_rate_minimum_hosts'?: (_google_protobuf_UInt32Value__Output); + 'success_rate_minimum_hosts': (_google_protobuf_UInt32Value__Output | null); /** * The minimum number of total requests that must be collected in one * interval (as defined by the interval duration above) to include this host @@ -214,7 +214,7 @@ export interface OutlierDetection__Output { * setting, outlier detection via success rate statistics is not performed * for that host. Defaults to 100. */ - 'success_rate_request_volume'?: (_google_protobuf_UInt32Value__Output); + 'success_rate_request_volume': (_google_protobuf_UInt32Value__Output | null); /** * This factor is used to determine the ejection threshold for success rate * outlier ejection. The ejection threshold is the difference between the @@ -224,18 +224,18 @@ export interface OutlierDetection__Output { * double. That is, if the desired factor is 1.9, the runtime value should * be 1900. Defaults to 1900. */ - 'success_rate_stdev_factor'?: (_google_protobuf_UInt32Value__Output); + 'success_rate_stdev_factor': (_google_protobuf_UInt32Value__Output | null); /** * The number of consecutive gateway failures (502, 503, 504 status codes) * before a consecutive gateway failure ejection occurs. Defaults to 5. */ - 'consecutive_gateway_failure'?: (_google_protobuf_UInt32Value__Output); + 'consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive gateway failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 0. */ - 'enforcing_consecutive_gateway_failure'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_gateway_failure': (_google_protobuf_UInt32Value__Output | null); /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: @@ -252,7 +252,7 @@ export interface OutlierDetection__Output { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value__Output); + 'consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through consecutive locally originated failures. This setting can be @@ -261,7 +261,7 @@ export interface OutlierDetection__Output { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status * is detected through success rate statistics for locally originated errors. @@ -270,13 +270,13 @@ export interface OutlierDetection__Output { * :ref:`split_external_local_origin_errors` * is set to true. */ - 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_local_origin_success_rate': (_google_protobuf_UInt32Value__Output | null); /** * The failure percentage to use when determining failure percentage-based outlier detection. If * the failure percentage of a given host is greater than or equal to this value, it will be * ejected. Defaults to 85. */ - 'failure_percentage_threshold'?: (_google_protobuf_UInt32Value__Output); + 'failure_percentage_threshold': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status is detected through * failure percentage statistics. This setting can be used to disable ejection or to ramp it up @@ -285,30 +285,30 @@ export interface OutlierDetection__Output { * [#next-major-version: setting this without setting failure_percentage_threshold should be * invalid in v4.] */ - 'enforcing_failure_percentage'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_failure_percentage': (_google_protobuf_UInt32Value__Output | null); /** * The % chance that a host will be actually ejected when an outlier status is detected through * local-origin failure percentage statistics. This setting can be used to disable ejection or to * ramp it up slowly. Defaults to 0. */ - 'enforcing_failure_percentage_local_origin'?: (_google_protobuf_UInt32Value__Output); + 'enforcing_failure_percentage_local_origin': (_google_protobuf_UInt32Value__Output | null); /** * The minimum number of hosts in a cluster in order to perform failure percentage-based ejection. * If the total number of hosts in the cluster is less than this value, failure percentage-based * ejection will not be performed. Defaults to 5. */ - 'failure_percentage_minimum_hosts'?: (_google_protobuf_UInt32Value__Output); + 'failure_percentage_minimum_hosts': (_google_protobuf_UInt32Value__Output | null); /** * The minimum number of total requests that must be collected in one interval (as defined by the * interval duration above) to perform failure percentage-based ejection for this host. If the * volume is lower than this setting, failure percentage-based ejection will not be performed for * this host. Defaults to 50. */ - 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value__Output); + 'failure_percentage_request_volume': (_google_protobuf_UInt32Value__Output | null); /** * The maximum time that a host is ejected for. See :ref:`base_ejection_time` * for more information. * Defaults to 300000ms or 300s. */ - 'max_ejection_time'?: (_google_protobuf_Duration__Output); + 'max_ejection_time': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts index 0f95c0816..f2dbd0608 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamBindConfig.ts @@ -10,7 +10,7 @@ export interface UpstreamBindConfig { /** * The address Envoy should bind to when establishing upstream connections. */ - 'source_address'?: (_envoy_config_core_v3_Address); + 'source_address'?: (_envoy_config_core_v3_Address | null); } /** @@ -21,5 +21,5 @@ export interface UpstreamBindConfig__Output { /** * The address Envoy should bind to when establishing upstream connections. */ - 'source_address'?: (_envoy_config_core_v3_Address__Output); + 'source_address': (_envoy_config_core_v3_Address__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts index 2e7f23894..483d1072d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/UpstreamConnectionOptions.ts @@ -6,12 +6,12 @@ export interface UpstreamConnectionOptions { /** * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. */ - 'tcp_keepalive'?: (_envoy_config_core_v3_TcpKeepalive); + 'tcp_keepalive'?: (_envoy_config_core_v3_TcpKeepalive | null); } export interface UpstreamConnectionOptions__Output { /** * If set then set SO_KEEPALIVE on the socket to enable TCP Keepalives. */ - 'tcp_keepalive'?: (_envoy_config_core_v3_TcpKeepalive__Output); + 'tcp_keepalive': (_envoy_config_core_v3_TcpKeepalive__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts index 4d5881baf..32c483344 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Address.ts @@ -10,12 +10,12 @@ import type { EnvoyInternalAddress as _envoy_config_core_v3_EnvoyInternalAddress * management servers. */ export interface Address { - 'socket_address'?: (_envoy_config_core_v3_SocketAddress); - 'pipe'?: (_envoy_config_core_v3_Pipe); + 'socket_address'?: (_envoy_config_core_v3_SocketAddress | null); + 'pipe'?: (_envoy_config_core_v3_Pipe | null); /** * [#not-implemented-hide:] */ - 'envoy_internal_address'?: (_envoy_config_core_v3_EnvoyInternalAddress); + 'envoy_internal_address'?: (_envoy_config_core_v3_EnvoyInternalAddress | null); 'address'?: "socket_address"|"pipe"|"envoy_internal_address"; } @@ -25,11 +25,11 @@ export interface Address { * management servers. */ export interface Address__Output { - 'socket_address'?: (_envoy_config_core_v3_SocketAddress__Output); - 'pipe'?: (_envoy_config_core_v3_Pipe__Output); + 'socket_address'?: (_envoy_config_core_v3_SocketAddress__Output | null); + 'pipe'?: (_envoy_config_core_v3_Pipe__Output | null); /** * [#not-implemented-hide:] */ - 'envoy_internal_address'?: (_envoy_config_core_v3_EnvoyInternalAddress__Output); + 'envoy_internal_address'?: (_envoy_config_core_v3_EnvoyInternalAddress__Output | null); 'address': "socket_address"|"pipe"|"envoy_internal_address"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts index 99afe9a26..b303a08d8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ApiConfigSource.ts @@ -70,7 +70,7 @@ export interface ApiConfigSource { /** * For REST APIs, the delay between successive polls. */ - 'refresh_delay'?: (_google_protobuf_Duration); + 'refresh_delay'?: (_google_protobuf_Duration | null); /** * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, * services will be cycled through if any kind of failure occurs. @@ -79,12 +79,12 @@ export interface ApiConfigSource { /** * For REST APIs, the request timeout. If not set, a default value of 1s will be used. */ - 'request_timeout'?: (_google_protobuf_Duration); + 'request_timeout'?: (_google_protobuf_Duration | null); /** * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be * rate limited. */ - 'rate_limit_settings'?: (_envoy_config_core_v3_RateLimitSettings); + 'rate_limit_settings'?: (_envoy_config_core_v3_RateLimitSettings | null); /** * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. */ @@ -120,7 +120,7 @@ export interface ApiConfigSource__Output { /** * For REST APIs, the delay between successive polls. */ - 'refresh_delay'?: (_google_protobuf_Duration__Output); + 'refresh_delay': (_google_protobuf_Duration__Output | null); /** * Multiple gRPC services be provided for GRPC. If > 1 cluster is defined, * services will be cycled through if any kind of failure occurs. @@ -129,12 +129,12 @@ export interface ApiConfigSource__Output { /** * For REST APIs, the request timeout. If not set, a default value of 1s will be used. */ - 'request_timeout'?: (_google_protobuf_Duration__Output); + 'request_timeout': (_google_protobuf_Duration__Output | null); /** * For GRPC APIs, the rate limit settings. If present, discovery requests made by Envoy will be * rate limited. */ - 'rate_limit_settings'?: (_envoy_config_core_v3_RateLimitSettings__Output); + 'rate_limit_settings': (_envoy_config_core_v3_RateLimitSettings__Output | null); /** * Skip the node identifier in subsequent discovery requests for streaming gRPC config types. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts index 476ea851f..aa152155b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AsyncDataSource.ts @@ -10,11 +10,11 @@ export interface AsyncDataSource { /** * Local async data source. */ - 'local'?: (_envoy_config_core_v3_DataSource); + 'local'?: (_envoy_config_core_v3_DataSource | null); /** * Remote async data source. */ - 'remote'?: (_envoy_config_core_v3_RemoteDataSource); + 'remote'?: (_envoy_config_core_v3_RemoteDataSource | null); 'specifier'?: "local"|"remote"; } @@ -25,10 +25,10 @@ export interface AsyncDataSource__Output { /** * Local async data source. */ - 'local'?: (_envoy_config_core_v3_DataSource__Output); + 'local'?: (_envoy_config_core_v3_DataSource__Output | null); /** * Remote async data source. */ - 'remote'?: (_envoy_config_core_v3_RemoteDataSource__Output); + 'remote'?: (_envoy_config_core_v3_RemoteDataSource__Output | null); 'specifier': "local"|"remote"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts index 9878375d6..b85b8d5de 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts @@ -11,7 +11,7 @@ export interface BackoffStrategy { * be greater than zero and less than or equal to :ref:`max_interval * `. */ - 'base_interval'?: (_google_protobuf_Duration); + 'base_interval'?: (_google_protobuf_Duration | null); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval @@ -19,7 +19,7 @@ export interface BackoffStrategy { * is 10 times the :ref:`base_interval * `. */ - 'max_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration | null); } /** @@ -31,7 +31,7 @@ export interface BackoffStrategy__Output { * be greater than zero and less than or equal to :ref:`max_interval * `. */ - 'base_interval'?: (_google_protobuf_Duration__Output); + 'base_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval @@ -39,5 +39,5 @@ export interface BackoffStrategy__Output { * is 10 times the :ref:`base_interval * `. */ - 'max_interval'?: (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts index eb2bc7626..db6b1f654 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts @@ -8,7 +8,7 @@ export interface BindConfig { /** * The address to bind to when creating a socket. */ - 'source_address'?: (_envoy_config_core_v3_SocketAddress); + 'source_address'?: (_envoy_config_core_v3_SocketAddress | null); /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address @@ -18,7 +18,7 @@ export interface BindConfig { * flag is not set (default), the socket is not modified, i.e. the option is * neither enabled nor disabled. */ - 'freebind'?: (_google_protobuf_BoolValue); + 'freebind'?: (_google_protobuf_BoolValue | null); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. @@ -30,7 +30,7 @@ export interface BindConfig__Output { /** * The address to bind to when creating a socket. */ - 'source_address'?: (_envoy_config_core_v3_SocketAddress__Output); + 'source_address': (_envoy_config_core_v3_SocketAddress__Output | null); /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address @@ -40,7 +40,7 @@ export interface BindConfig__Output { * flag is not set (default), the socket is not modified, i.e. the option is * neither enabled nor disabled. */ - 'freebind'?: (_google_protobuf_BoolValue__Output); + 'freebind': (_google_protobuf_BoolValue__Output | null); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts index a3a33e4a3..1a86e918e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BuildVersion.ts @@ -11,12 +11,12 @@ export interface BuildVersion { /** * SemVer version of extension. */ - 'version'?: (_envoy_type_v3_SemanticVersion); + 'version'?: (_envoy_type_v3_SemanticVersion | null); /** * Free-form build information. * Envoy defines several well known keys in the source/common/version/version.h file */ - 'metadata'?: (_google_protobuf_Struct); + 'metadata'?: (_google_protobuf_Struct | null); } /** @@ -27,10 +27,10 @@ export interface BuildVersion__Output { /** * SemVer version of extension. */ - 'version'?: (_envoy_type_v3_SemanticVersion__Output); + 'version': (_envoy_type_v3_SemanticVersion__Output | null); /** * Free-form build information. * Envoy defines several well known keys in the source/common/version/version.h file */ - 'metadata'?: (_google_protobuf_Struct__Output); + 'metadata': (_google_protobuf_Struct__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts index c4a01b0da..df4ff39ff 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts @@ -14,7 +14,7 @@ export interface CidrRange { /** * Length of prefix, e.g. 0, 32. */ - 'prefix_len'?: (_google_protobuf_UInt32Value); + 'prefix_len'?: (_google_protobuf_UInt32Value | null); } /** @@ -29,5 +29,5 @@ export interface CidrRange__Output { /** * Length of prefix, e.g. 0, 32. */ - 'prefix_len'?: (_google_protobuf_UInt32Value__Output); + 'prefix_len': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts index 9462f4844..aaf4d9564 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts @@ -36,12 +36,12 @@ export interface ConfigSource { /** * API configuration source. */ - 'api_config_source'?: (_envoy_config_core_v3_ApiConfigSource); + 'api_config_source'?: (_envoy_config_core_v3_ApiConfigSource | null); /** * When set, ADS will be used to fetch resources. The ADS API configuration * source in the bootstrap configuration is used. */ - 'ads'?: (_envoy_config_core_v3_AggregatedConfigSource); + 'ads'?: (_envoy_config_core_v3_AggregatedConfigSource | null); /** * When this timeout is specified, Envoy will wait no longer than the specified time for first * config response on this xDS subscription during the :ref:`initialization process @@ -51,7 +51,7 @@ export interface ConfigSource { * means no timeout - Envoy will wait indefinitely for the first xDS config (unless another * timeout applies). The default is 15s. */ - 'initial_fetch_timeout'?: (_google_protobuf_Duration); + 'initial_fetch_timeout'?: (_google_protobuf_Duration | null); /** * [#not-implemented-hide:] * When set, the client will access the resources from the same server it got the @@ -65,7 +65,7 @@ export interface ConfigSource { * this field can implicitly mean to use the same stream in the case where the ConfigSource * is provided via ADS and the specified data can also be obtained via ADS.] */ - 'self'?: (_envoy_config_core_v3_SelfConfigSource); + 'self'?: (_envoy_config_core_v3_SelfConfigSource | null); /** * API version for xDS resources. This implies the type URLs that the client * will request for resources and the resource type that the client will in @@ -111,12 +111,12 @@ export interface ConfigSource__Output { /** * API configuration source. */ - 'api_config_source'?: (_envoy_config_core_v3_ApiConfigSource__Output); + 'api_config_source'?: (_envoy_config_core_v3_ApiConfigSource__Output | null); /** * When set, ADS will be used to fetch resources. The ADS API configuration * source in the bootstrap configuration is used. */ - 'ads'?: (_envoy_config_core_v3_AggregatedConfigSource__Output); + 'ads'?: (_envoy_config_core_v3_AggregatedConfigSource__Output | null); /** * When this timeout is specified, Envoy will wait no longer than the specified time for first * config response on this xDS subscription during the :ref:`initialization process @@ -126,7 +126,7 @@ export interface ConfigSource__Output { * means no timeout - Envoy will wait indefinitely for the first xDS config (unless another * timeout applies). The default is 15s. */ - 'initial_fetch_timeout'?: (_google_protobuf_Duration__Output); + 'initial_fetch_timeout': (_google_protobuf_Duration__Output | null); /** * [#not-implemented-hide:] * When set, the client will access the resources from the same server it got the @@ -140,7 +140,7 @@ export interface ConfigSource__Output { * this field can implicitly mean to use the same stream in the case where the ConfigSource * is provided via ADS and the specified data can also be obtained via ADS.] */ - 'self'?: (_envoy_config_core_v3_SelfConfigSource__Output); + 'self'?: (_envoy_config_core_v3_SelfConfigSource__Output | null); /** * API version for xDS resources. This implies the type URLs that the client * will request for resources and the resource type that the client will in diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts index 72aedc6ab..6226b97c8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EventServiceConfig.ts @@ -10,7 +10,7 @@ export interface EventServiceConfig { /** * Specifies the gRPC service that hosts the event reporting service. */ - 'grpc_service'?: (_envoy_config_core_v3_GrpcService); + 'grpc_service'?: (_envoy_config_core_v3_GrpcService | null); 'config_source_specifier'?: "grpc_service"; } @@ -22,6 +22,6 @@ export interface EventServiceConfig__Output { /** * Specifies the gRPC service that hosts the event reporting service. */ - 'grpc_service'?: (_envoy_config_core_v3_GrpcService__Output); + 'grpc_service'?: (_envoy_config_core_v3_GrpcService__Output | null); 'config_source_specifier': "grpc_service"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts index 0c7e0abd3..5f730bd22 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Extension.ts @@ -31,7 +31,7 @@ export interface Extension { * of other extensions and the Envoy API. * This field is not set when extension did not provide version information. */ - 'version'?: (_envoy_config_core_v3_BuildVersion); + 'version'?: (_envoy_config_core_v3_BuildVersion | null); /** * Indicates that the extension is present but was disabled via dynamic configuration. */ @@ -67,7 +67,7 @@ export interface Extension__Output { * of other extensions and the Envoy API. * This field is not set when extension did not provide version information. */ - 'version'?: (_envoy_config_core_v3_BuildVersion__Output); + 'version': (_envoy_config_core_v3_BuildVersion__Output | null); /** * Indicates that the extension is present but was disabled via dynamic configuration. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts index 085324b6d..805762ef5 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ExtensionConfigSource.ts @@ -17,13 +17,13 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ * filter chain with a disabled extension filter rejects all incoming streams. */ export interface ExtensionConfigSource { - 'config_source'?: (_envoy_config_core_v3_ConfigSource); + 'config_source'?: (_envoy_config_core_v3_ConfigSource | null); /** * Optional default configuration to use as the initial configuration if * there is a failure to receive the initial extension configuration or if * `apply_default_config_without_warming` flag is set. */ - 'default_config'?: (_google_protobuf_Any); + 'default_config'?: (_google_protobuf_Any | null); /** * Use the default config as the initial configuration without warming and * waiting for the first discovery response. Requires the default configuration @@ -51,13 +51,13 @@ export interface ExtensionConfigSource { * filter chain with a disabled extension filter rejects all incoming streams. */ export interface ExtensionConfigSource__Output { - 'config_source'?: (_envoy_config_core_v3_ConfigSource__Output); + 'config_source': (_envoy_config_core_v3_ConfigSource__Output | null); /** * Optional default configuration to use as the initial configuration if * there is a failure to receive the initial extension configuration or if * `apply_default_config_without_warming` flag is set. */ - 'default_config'?: (_google_protobuf_Any__Output); + 'default_config': (_google_protobuf_Any__Output | null); /** * Use the default config as the initial configuration without warming and * waiting for the first discovery response. Requires the default configuration diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts index b0486cc37..1f0376a1c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcProtocolOptions.ts @@ -6,12 +6,12 @@ import type { Http2ProtocolOptions as _envoy_config_core_v3_Http2ProtocolOptions * [#not-implemented-hide:] */ export interface GrpcProtocolOptions { - 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions | null); } /** * [#not-implemented-hide:] */ export interface GrpcProtocolOptions__Output { - 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions__Output); + 'http2_protocol_options': (_envoy_config_core_v3_Http2ProtocolOptions__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts index 24249309b..0e55d018b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts @@ -22,7 +22,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials { * Google Compute Engine credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 */ - 'google_compute_engine'?: (_google_protobuf_Empty); + 'google_compute_engine'?: (_google_protobuf_Empty | null); /** * Google refresh token credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. @@ -32,24 +32,24 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials { * Service Account JWT Access credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. */ - 'service_account_jwt_access'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials); + 'service_account_jwt_access'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials | null); /** * Google IAM credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. */ - 'google_iam'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials); + 'google_iam'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials | null); /** * Custom authenticator credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. */ - 'from_plugin'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin); + 'from_plugin'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin | null); /** * Custom security token service which implements OAuth 2.0 token exchange. * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 * See https://github.com/grpc/grpc/pull/19587. */ - 'sts_service'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService); + 'sts_service'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService | null); 'credential_specifier'?: "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } @@ -66,7 +66,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials__O * Google Compute Engine credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 */ - 'google_compute_engine'?: (_google_protobuf_Empty__Output); + 'google_compute_engine'?: (_google_protobuf_Empty__Output | null); /** * Google refresh token credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a96901c997b91bc6513b08491e0dca37c. @@ -76,24 +76,24 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials__O * Service Account JWT Access credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a92a9f959d6102461f66ee973d8e9d3aa. */ - 'service_account_jwt_access'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output); + 'service_account_jwt_access'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_ServiceAccountJWTAccessCredentials__Output | null); /** * Google IAM credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a9fc1fc101b41e680d47028166e76f9d0. */ - 'google_iam'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output); + 'google_iam'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials__Output | null); /** * Custom authenticator credentials. * https://grpc.io/grpc/cpp/namespacegrpc.html#a823c6a4b19ffc71fb33e90154ee2ad07. * https://grpc.io/docs/guides/auth.html#extending-grpc-to-support-other-authentication-mechanisms. */ - 'from_plugin'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output); + 'from_plugin'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output | null); /** * Custom security token service which implements OAuth 2.0 token exchange. * https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16 * See https://github.com/grpc/grpc/pull/19587. */ - 'sts_service'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService__Output); + 'sts_service'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_StsService__Output | null); 'credential_specifier': "access_token"|"google_compute_engine"|"google_refresh_token"|"service_account_jwt_access"|"google_iam"|"from_plugin"|"sts_service"; } @@ -114,7 +114,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs__Outpu /** * See grpc_types.h GRPC_ARG #defines for keys that work here. */ - 'args'?: ({[key: string]: _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value__Output}); + 'args': ({[key: string]: _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value__Output}); } /** @@ -122,12 +122,12 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs__Outpu * credential types. */ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials { - 'ssl_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials); + 'ssl_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials | null); /** * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 */ - 'google_default'?: (_google_protobuf_Empty); - 'local_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials); + 'google_default'?: (_google_protobuf_Empty | null); + 'local_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials | null); 'credential_specifier'?: "ssl_credentials"|"google_default"|"local_credentials"; } @@ -136,12 +136,12 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials * credential types. */ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials__Output { - 'ssl_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials__Output); + 'ssl_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials__Output | null); /** * https://grpc.io/grpc/cpp/namespacegrpc.html#a6beb3ac70ff94bd2ebbd89b8f21d1f61 */ - 'google_default'?: (_google_protobuf_Empty__Output); - 'local_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output); + 'google_default'?: (_google_protobuf_Empty__Output | null); + 'local_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredentials__Output | null); 'credential_specifier': "ssl_credentials"|"google_default"|"local_credentials"; } @@ -183,7 +183,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc { * :ref:`channel_credentials `. */ 'target_uri'?: (string); - 'channel_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials); + 'channel_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials | null); /** * A set of call credentials that can be composed with `channel credentials * `_. @@ -211,16 +211,16 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc { * Additional configuration for site-specific customizations of the Google * gRPC library. */ - 'config'?: (_google_protobuf_Struct); + 'config'?: (_google_protobuf_Struct | null); /** * How many bytes each stream can buffer internally. * If not set an implementation defined default is applied (1MiB). */ - 'per_stream_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'per_stream_buffer_limit_bytes'?: (_google_protobuf_UInt32Value | null); /** * Custom channels args. */ - 'channel_args'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs); + 'channel_args'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs | null); } /** @@ -233,7 +233,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc__Output { * :ref:`channel_credentials `. */ 'target_uri': (string); - 'channel_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials__Output); + 'channel_credentials': (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials__Output | null); /** * A set of call credentials that can be composed with `channel credentials * `_. @@ -261,16 +261,16 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc__Output { * Additional configuration for site-specific customizations of the Google * gRPC library. */ - 'config'?: (_google_protobuf_Struct__Output); + 'config': (_google_protobuf_Struct__Output | null); /** * How many bytes each stream can buffer internally. * If not set an implementation defined default is applied (1MiB). */ - 'per_stream_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); + 'per_stream_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output | null); /** * Custom channels args. */ - 'channel_args'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs__Output); + 'channel_args': (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs__Output | null); } export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_GoogleIAMCredentials { @@ -299,13 +299,13 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredent export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin { 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); 'config_type'?: "typed_config"; } export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output { 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); 'config_type': "typed_config"; } @@ -326,15 +326,15 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials { /** * PEM encoded server root certificates. */ - 'root_certs'?: (_envoy_config_core_v3_DataSource); + 'root_certs'?: (_envoy_config_core_v3_DataSource | null); /** * PEM encoded client private key. */ - 'private_key'?: (_envoy_config_core_v3_DataSource); + 'private_key'?: (_envoy_config_core_v3_DataSource | null); /** * PEM encoded client certificate chain. */ - 'cert_chain'?: (_envoy_config_core_v3_DataSource); + 'cert_chain'?: (_envoy_config_core_v3_DataSource | null); } /** @@ -344,15 +344,15 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_SslCredentials__Ou /** * PEM encoded server root certificates. */ - 'root_certs'?: (_envoy_config_core_v3_DataSource__Output); + 'root_certs': (_envoy_config_core_v3_DataSource__Output | null); /** * PEM encoded client private key. */ - 'private_key'?: (_envoy_config_core_v3_DataSource__Output); + 'private_key': (_envoy_config_core_v3_DataSource__Output | null); /** * PEM encoded client certificate chain. */ - 'cert_chain'?: (_envoy_config_core_v3_DataSource__Output); + 'cert_chain': (_envoy_config_core_v3_DataSource__Output | null); } /** @@ -494,18 +494,18 @@ export interface GrpcService { * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'envoy_grpc'?: (_envoy_config_core_v3_GrpcService_EnvoyGrpc); + 'envoy_grpc'?: (_envoy_config_core_v3_GrpcService_EnvoyGrpc | null); /** * `Google C++ gRPC client `_ * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'google_grpc'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc); + 'google_grpc'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc | null); /** * The timeout for the gRPC request. This is the timeout for a specific * request. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); /** * Additional metadata to include in streams initiated to the GrpcService. This can be used for * scenarios in which additional ad hoc authorization headers (e.g. ``x-foo-bar: baz-key``) are to @@ -528,18 +528,18 @@ export interface GrpcService__Output { * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'envoy_grpc'?: (_envoy_config_core_v3_GrpcService_EnvoyGrpc__Output); + 'envoy_grpc'?: (_envoy_config_core_v3_GrpcService_EnvoyGrpc__Output | null); /** * `Google C++ gRPC client `_ * See the :ref:`gRPC services overview ` * documentation for discussion on gRPC client selection. */ - 'google_grpc'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc__Output); + 'google_grpc'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc__Output | null); /** * The timeout for the gRPC request. This is the timeout for a specific * request. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); /** * Additional metadata to include in streams initiated to the GrpcService. This can be used for * scenarios in which additional ad hoc authorization headers (e.g. ``x-foo-bar: baz-key``) are to diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts index 4a0fe7120..29f9d6695 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts @@ -10,12 +10,12 @@ export interface HeaderValueOption { /** * Header name/value pair that this option applies to. */ - 'header'?: (_envoy_config_core_v3_HeaderValue); + 'header'?: (_envoy_config_core_v3_HeaderValue | null); /** * Should the value be appended? If true (default), the value is appended to * existing values. Otherwise it replaces any existing values. */ - 'append'?: (_google_protobuf_BoolValue); + 'append'?: (_google_protobuf_BoolValue | null); } /** @@ -25,10 +25,10 @@ export interface HeaderValueOption__Output { /** * Header name/value pair that this option applies to. */ - 'header'?: (_envoy_config_core_v3_HeaderValue__Output); + 'header': (_envoy_config_core_v3_HeaderValue__Output | null); /** * Should the value be appended? If true (default), the value is appended to * existing values. Otherwise it replaces any existing values. */ - 'append'?: (_google_protobuf_BoolValue__Output); + 'append': (_google_protobuf_BoolValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts index 3a7320a08..6dbbf6f4d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts @@ -20,7 +20,7 @@ export interface _envoy_config_core_v3_HealthCheck_CustomHealthCheck { * The registered name of the custom health checker. */ 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * A custom health checker specific configuration which depends on the custom health checker * being instantiated. See :api:`envoy/config/health_checker` for reference. @@ -36,7 +36,7 @@ export interface _envoy_config_core_v3_HealthCheck_CustomHealthCheck__Output { * The registered name of the custom health checker. */ 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * A custom health checker specific configuration which depends on the custom health checker * being instantiated. See :api:`envoy/config/health_checker` for reference. @@ -111,11 +111,11 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck { /** * [#not-implemented-hide:] HTTP specific payload. */ - 'send'?: (_envoy_config_core_v3_HealthCheck_Payload); + 'send'?: (_envoy_config_core_v3_HealthCheck_Payload | null); /** * [#not-implemented-hide:] HTTP specific response. */ - 'receive'?: (_envoy_config_core_v3_HealthCheck_Payload); + 'receive'?: (_envoy_config_core_v3_HealthCheck_Payload | null); /** * Specifies a list of HTTP headers that should be added to each request that is sent to the * health checked cluster. For more information, including details on header value syntax, see @@ -145,7 +145,7 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck { * `. See the :ref:`architecture overview * ` for more information. */ - 'service_name_matcher'?: (_envoy_type_matcher_v3_StringMatcher); + 'service_name_matcher'?: (_envoy_type_matcher_v3_StringMatcher | null); } /** @@ -167,11 +167,11 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output { /** * [#not-implemented-hide:] HTTP specific payload. */ - 'send'?: (_envoy_config_core_v3_HealthCheck_Payload__Output); + 'send': (_envoy_config_core_v3_HealthCheck_Payload__Output | null); /** * [#not-implemented-hide:] HTTP specific response. */ - 'receive'?: (_envoy_config_core_v3_HealthCheck_Payload__Output); + 'receive': (_envoy_config_core_v3_HealthCheck_Payload__Output | null); /** * Specifies a list of HTTP headers that should be added to each request that is sent to the * health checked cluster. For more information, including details on header value syntax, see @@ -201,7 +201,7 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output { * `. See the :ref:`architecture overview * ` for more information. */ - 'service_name_matcher'?: (_envoy_type_matcher_v3_StringMatcher__Output); + 'service_name_matcher': (_envoy_type_matcher_v3_StringMatcher__Output | null); } /** @@ -258,7 +258,7 @@ export interface _envoy_config_core_v3_HealthCheck_TcpHealthCheck { /** * Empty payloads imply a connect-only health check. */ - 'send'?: (_envoy_config_core_v3_HealthCheck_Payload); + 'send'?: (_envoy_config_core_v3_HealthCheck_Payload | null); /** * When checking the response, “fuzzy†matching is performed such that each * binary block must be found, and in the order specified, but not @@ -271,7 +271,7 @@ export interface _envoy_config_core_v3_HealthCheck_TcpHealthCheck__Output { /** * Empty payloads imply a connect-only health check. */ - 'send'?: (_envoy_config_core_v3_HealthCheck_Payload__Output); + 'send': (_envoy_config_core_v3_HealthCheck_Payload__Output | null); /** * When checking the response, “fuzzy†matching is performed such that each * binary block must be found, and in the order specified, but not @@ -320,48 +320,48 @@ export interface HealthCheck { * The time to wait for a health check response. If the timeout is reached the * health check attempt will be considered a failure. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); /** * The interval between health checks. */ - 'interval'?: (_google_protobuf_Duration); + 'interval'?: (_google_protobuf_Duration | null); /** * An optional jitter amount in milliseconds. If specified, during every * interval Envoy will add interval_jitter to the wait time. */ - 'interval_jitter'?: (_google_protobuf_Duration); + 'interval_jitter'?: (_google_protobuf_Duration | null); /** * The number of unhealthy health checks required before a host is marked * unhealthy. Note that for *http* health checking if a host responds with 503 * this threshold is ignored and the host is considered unhealthy immediately. */ - 'unhealthy_threshold'?: (_google_protobuf_UInt32Value); + 'unhealthy_threshold'?: (_google_protobuf_UInt32Value | null); /** * The number of healthy health checks required before a host is marked * healthy. Note that during startup, only a single successful health check is * required to mark a host healthy. */ - 'healthy_threshold'?: (_google_protobuf_UInt32Value); + 'healthy_threshold'?: (_google_protobuf_UInt32Value | null); /** * [#not-implemented-hide:] Non-serving port for health checking. */ - 'alt_port'?: (_google_protobuf_UInt32Value); + 'alt_port'?: (_google_protobuf_UInt32Value | null); /** * Reuse health check connection between health checks. Default is true. */ - 'reuse_connection'?: (_google_protobuf_BoolValue); + 'reuse_connection'?: (_google_protobuf_BoolValue | null); /** * HTTP health check. */ - 'http_health_check'?: (_envoy_config_core_v3_HealthCheck_HttpHealthCheck); + 'http_health_check'?: (_envoy_config_core_v3_HealthCheck_HttpHealthCheck | null); /** * TCP health check. */ - 'tcp_health_check'?: (_envoy_config_core_v3_HealthCheck_TcpHealthCheck); + 'tcp_health_check'?: (_envoy_config_core_v3_HealthCheck_TcpHealthCheck | null); /** * gRPC health check. */ - 'grpc_health_check'?: (_envoy_config_core_v3_HealthCheck_GrpcHealthCheck); + 'grpc_health_check'?: (_envoy_config_core_v3_HealthCheck_GrpcHealthCheck | null); /** * The "no traffic interval" is a special health check interval that is used when a cluster has * never had traffic routed to it. This lower interval allows cluster information to be kept up to @@ -372,11 +372,11 @@ export interface HealthCheck { * * The default value for "no traffic interval" is 60 seconds. */ - 'no_traffic_interval'?: (_google_protobuf_Duration); + 'no_traffic_interval'?: (_google_protobuf_Duration | null); /** * Custom health check. */ - 'custom_health_check'?: (_envoy_config_core_v3_HealthCheck_CustomHealthCheck); + 'custom_health_check'?: (_envoy_config_core_v3_HealthCheck_CustomHealthCheck | null); /** * The "unhealthy interval" is a health check interval that is used for hosts that are marked as * unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the @@ -384,7 +384,7 @@ export interface HealthCheck { * * The default value for "unhealthy interval" is the same as "interval". */ - 'unhealthy_interval'?: (_google_protobuf_Duration); + 'unhealthy_interval'?: (_google_protobuf_Duration | null); /** * The "unhealthy edge interval" is a special health check interval that is used for the first * health check right after a host is marked as unhealthy. For subsequent health checks @@ -393,7 +393,7 @@ export interface HealthCheck { * * The default value for "unhealthy edge interval" is the same as "unhealthy interval". */ - 'unhealthy_edge_interval'?: (_google_protobuf_Duration); + 'unhealthy_edge_interval'?: (_google_protobuf_Duration | null); /** * The "healthy edge interval" is a special health check interval that is used for the first * health check right after a host is marked as healthy. For subsequent health checks @@ -401,7 +401,7 @@ export interface HealthCheck { * * The default value for "healthy edge interval" is the same as the default interval. */ - 'healthy_edge_interval'?: (_google_protobuf_Duration); + 'healthy_edge_interval'?: (_google_protobuf_Duration | null); /** * Specifies the path to the :ref:`health check event log `. * If empty, no event log will be written. @@ -427,17 +427,17 @@ export interface HealthCheck { * checking after for a random time in ms between 0 and initial_jitter. This only * applies to the first health check. */ - 'initial_jitter'?: (_google_protobuf_Duration); + 'initial_jitter'?: (_google_protobuf_Duration | null); /** * This allows overriding the cluster TLS settings, just for health check connections. */ - 'tls_options'?: (_envoy_config_core_v3_HealthCheck_TlsOptions); + 'tls_options'?: (_envoy_config_core_v3_HealthCheck_TlsOptions | null); /** * [#not-implemented-hide:] * The gRPC service for the health check event service. * If empty, health check events won't be sent to a remote endpoint. */ - 'event_service'?: (_envoy_config_core_v3_EventServiceConfig); + 'event_service'?: (_envoy_config_core_v3_EventServiceConfig | null); /** * Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's * :ref:`tranport socket matches `. @@ -470,7 +470,7 @@ export interface HealthCheck { * the cluster's :ref:`transport socket ` * will be used for health check socket configuration. */ - 'transport_socket_match_criteria'?: (_google_protobuf_Struct); + 'transport_socket_match_criteria'?: (_google_protobuf_Struct | null); /** * The "no traffic healthy interval" is a special health check interval that * is used for hosts that are currently passing active health checking @@ -486,7 +486,7 @@ export interface HealthCheck { * If no_traffic_healthy_interval is not set, it will default to the * no traffic interval and send that interval regardless of health state. */ - 'no_traffic_healthy_interval'?: (_google_protobuf_Duration); + 'no_traffic_healthy_interval'?: (_google_protobuf_Duration | null); 'health_checker'?: "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } @@ -498,48 +498,48 @@ export interface HealthCheck__Output { * The time to wait for a health check response. If the timeout is reached the * health check attempt will be considered a failure. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); /** * The interval between health checks. */ - 'interval'?: (_google_protobuf_Duration__Output); + 'interval': (_google_protobuf_Duration__Output | null); /** * An optional jitter amount in milliseconds. If specified, during every * interval Envoy will add interval_jitter to the wait time. */ - 'interval_jitter'?: (_google_protobuf_Duration__Output); + 'interval_jitter': (_google_protobuf_Duration__Output | null); /** * The number of unhealthy health checks required before a host is marked * unhealthy. Note that for *http* health checking if a host responds with 503 * this threshold is ignored and the host is considered unhealthy immediately. */ - 'unhealthy_threshold'?: (_google_protobuf_UInt32Value__Output); + 'unhealthy_threshold': (_google_protobuf_UInt32Value__Output | null); /** * The number of healthy health checks required before a host is marked * healthy. Note that during startup, only a single successful health check is * required to mark a host healthy. */ - 'healthy_threshold'?: (_google_protobuf_UInt32Value__Output); + 'healthy_threshold': (_google_protobuf_UInt32Value__Output | null); /** * [#not-implemented-hide:] Non-serving port for health checking. */ - 'alt_port'?: (_google_protobuf_UInt32Value__Output); + 'alt_port': (_google_protobuf_UInt32Value__Output | null); /** * Reuse health check connection between health checks. Default is true. */ - 'reuse_connection'?: (_google_protobuf_BoolValue__Output); + 'reuse_connection': (_google_protobuf_BoolValue__Output | null); /** * HTTP health check. */ - 'http_health_check'?: (_envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output); + 'http_health_check'?: (_envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output | null); /** * TCP health check. */ - 'tcp_health_check'?: (_envoy_config_core_v3_HealthCheck_TcpHealthCheck__Output); + 'tcp_health_check'?: (_envoy_config_core_v3_HealthCheck_TcpHealthCheck__Output | null); /** * gRPC health check. */ - 'grpc_health_check'?: (_envoy_config_core_v3_HealthCheck_GrpcHealthCheck__Output); + 'grpc_health_check'?: (_envoy_config_core_v3_HealthCheck_GrpcHealthCheck__Output | null); /** * The "no traffic interval" is a special health check interval that is used when a cluster has * never had traffic routed to it. This lower interval allows cluster information to be kept up to @@ -550,11 +550,11 @@ export interface HealthCheck__Output { * * The default value for "no traffic interval" is 60 seconds. */ - 'no_traffic_interval'?: (_google_protobuf_Duration__Output); + 'no_traffic_interval': (_google_protobuf_Duration__Output | null); /** * Custom health check. */ - 'custom_health_check'?: (_envoy_config_core_v3_HealthCheck_CustomHealthCheck__Output); + 'custom_health_check'?: (_envoy_config_core_v3_HealthCheck_CustomHealthCheck__Output | null); /** * The "unhealthy interval" is a health check interval that is used for hosts that are marked as * unhealthy. As soon as the host is marked as healthy, Envoy will shift back to using the @@ -562,7 +562,7 @@ export interface HealthCheck__Output { * * The default value for "unhealthy interval" is the same as "interval". */ - 'unhealthy_interval'?: (_google_protobuf_Duration__Output); + 'unhealthy_interval': (_google_protobuf_Duration__Output | null); /** * The "unhealthy edge interval" is a special health check interval that is used for the first * health check right after a host is marked as unhealthy. For subsequent health checks @@ -571,7 +571,7 @@ export interface HealthCheck__Output { * * The default value for "unhealthy edge interval" is the same as "unhealthy interval". */ - 'unhealthy_edge_interval'?: (_google_protobuf_Duration__Output); + 'unhealthy_edge_interval': (_google_protobuf_Duration__Output | null); /** * The "healthy edge interval" is a special health check interval that is used for the first * health check right after a host is marked as healthy. For subsequent health checks @@ -579,7 +579,7 @@ export interface HealthCheck__Output { * * The default value for "healthy edge interval" is the same as the default interval. */ - 'healthy_edge_interval'?: (_google_protobuf_Duration__Output); + 'healthy_edge_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the path to the :ref:`health check event log `. * If empty, no event log will be written. @@ -605,17 +605,17 @@ export interface HealthCheck__Output { * checking after for a random time in ms between 0 and initial_jitter. This only * applies to the first health check. */ - 'initial_jitter'?: (_google_protobuf_Duration__Output); + 'initial_jitter': (_google_protobuf_Duration__Output | null); /** * This allows overriding the cluster TLS settings, just for health check connections. */ - 'tls_options'?: (_envoy_config_core_v3_HealthCheck_TlsOptions__Output); + 'tls_options': (_envoy_config_core_v3_HealthCheck_TlsOptions__Output | null); /** * [#not-implemented-hide:] * The gRPC service for the health check event service. * If empty, health check events won't be sent to a remote endpoint. */ - 'event_service'?: (_envoy_config_core_v3_EventServiceConfig__Output); + 'event_service': (_envoy_config_core_v3_EventServiceConfig__Output | null); /** * Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's * :ref:`tranport socket matches `. @@ -648,7 +648,7 @@ export interface HealthCheck__Output { * the cluster's :ref:`transport socket ` * will be used for health check socket configuration. */ - 'transport_socket_match_criteria'?: (_google_protobuf_Struct__Output); + 'transport_socket_match_criteria': (_google_protobuf_Struct__Output | null); /** * The "no traffic healthy interval" is a special health check interval that * is used for hosts that are currently passing active health checking @@ -664,6 +664,6 @@ export interface HealthCheck__Output { * If no_traffic_healthy_interval is not set, it will default to the * no traffic interval and send that interval regardless of health state. */ - 'no_traffic_healthy_interval'?: (_google_protobuf_Duration__Output); + 'no_traffic_healthy_interval': (_google_protobuf_Duration__Output | null); 'health_checker': "http_health_check"|"tcp_health_check"|"grpc_health_check"|"custom_health_check"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts index 982f58b0e..89889d390 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts @@ -10,7 +10,7 @@ export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat { * Note that while this results in most headers following conventional casing, certain headers * are not covered. For example, the "TE" header will be formatted as "Te". */ - 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords); + 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords | null); 'header_format'?: "proper_case_words"; } @@ -22,7 +22,7 @@ export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Out * Note that while this results in most headers following conventional casing, certain headers * are not covered. For example, the "TE" header will be formatted as "Te". */ - 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output); + 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output | null); 'header_format': "proper_case_words"; } @@ -42,7 +42,7 @@ export interface Http1ProtocolOptions { * envoy as their HTTP proxy. In Unix, for example, this is typically done by setting the * *http_proxy* environment variable. */ - 'allow_absolute_url'?: (_google_protobuf_BoolValue); + 'allow_absolute_url'?: (_google_protobuf_BoolValue | null); /** * Handle incoming HTTP/1.0 and HTTP 0.9 requests. * This is off by default, and not fully standards compliant. There is support for pre-HTTP/1.1 @@ -60,7 +60,7 @@ export interface Http1ProtocolOptions { * Describes how the keys for response headers should be formatted. By default, all header keys * are lower cased. */ - 'header_key_format'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat); + 'header_key_format'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat | null); /** * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. * @@ -92,7 +92,7 @@ export interface Http1ProtocolOptions { * If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging * `. */ - 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue); + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue | null); } /** @@ -105,7 +105,7 @@ export interface Http1ProtocolOptions__Output { * envoy as their HTTP proxy. In Unix, for example, this is typically done by setting the * *http_proxy* environment variable. */ - 'allow_absolute_url'?: (_google_protobuf_BoolValue__Output); + 'allow_absolute_url': (_google_protobuf_BoolValue__Output | null); /** * Handle incoming HTTP/1.0 and HTTP 0.9 requests. * This is off by default, and not fully standards compliant. There is support for pre-HTTP/1.1 @@ -123,7 +123,7 @@ export interface Http1ProtocolOptions__Output { * Describes how the keys for response headers should be formatted. By default, all header keys * are lower cased. */ - 'header_key_format'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Output); + 'header_key_format': (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Output | null); /** * Enables trailers for HTTP/1. By default the HTTP/1 codec drops proxied trailers. * @@ -155,5 +155,5 @@ export interface Http1ProtocolOptions__Output { * If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging * `. */ - 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue__Output); + 'override_stream_error_on_invalid_http_message': (_google_protobuf_BoolValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts index e379d44be..52908c961 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts @@ -12,11 +12,11 @@ export interface _envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter { /** * The 16 bit parameter identifier. */ - 'identifier'?: (_google_protobuf_UInt32Value); + 'identifier'?: (_google_protobuf_UInt32Value | null); /** * The 32 bit parameter value. */ - 'value'?: (_google_protobuf_UInt32Value); + 'value'?: (_google_protobuf_UInt32Value | null); } /** @@ -27,11 +27,11 @@ export interface _envoy_config_core_v3_Http2ProtocolOptions_SettingsParameter__O /** * The 16 bit parameter identifier. */ - 'identifier'?: (_google_protobuf_UInt32Value__Output); + 'identifier': (_google_protobuf_UInt32Value__Output | null); /** * The 32 bit parameter value. */ - 'value'?: (_google_protobuf_UInt32Value__Output); + 'value': (_google_protobuf_UInt32Value__Output | null); } /** @@ -44,7 +44,7 @@ export interface Http2ProtocolOptions { * range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header * compression. */ - 'hpack_table_size'?: (_google_protobuf_UInt32Value); + 'hpack_table_size'?: (_google_protobuf_UInt32Value | null); /** * `Maximum concurrent streams `_ * allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) @@ -54,7 +54,7 @@ export interface Http2ProtocolOptions { * on a single connection. If the limit is reached, Envoy may queue requests or establish * additional connections (as allowed per circuit breaker limits). */ - 'max_concurrent_streams'?: (_google_protobuf_UInt32Value); + 'max_concurrent_streams'?: (_google_protobuf_UInt32Value | null); /** * `Initial stream-level flow-control window * `_ size. Valid values range from 65535 @@ -68,12 +68,12 @@ export interface Http2ProtocolOptions { * HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to * stop the flow of data to the codec buffers. */ - 'initial_stream_window_size'?: (_google_protobuf_UInt32Value); + 'initial_stream_window_size'?: (_google_protobuf_UInt32Value | null); /** * Similar to *initial_stream_window_size*, but for connection-level flow-control * window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. */ - 'initial_connection_window_size'?: (_google_protobuf_UInt32Value); + 'initial_connection_window_size'?: (_google_protobuf_UInt32Value | null); /** * Allows proxying Websocket and other upgrades over H2 connect. */ @@ -95,7 +95,7 @@ export interface Http2ProtocolOptions { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_outbound_frames'?: (_google_protobuf_UInt32Value); + 'max_outbound_frames'?: (_google_protobuf_UInt32Value | null); /** * Limit the number of pending outbound downstream frames of types PING, SETTINGS and RST_STREAM, * preventing high memory utilization when receiving continuous stream of these frames. Exceeding @@ -105,7 +105,7 @@ export interface Http2ProtocolOptions { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value); + 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value | null); /** * Limit the number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA with an * empty payload and no end stream flag. Those frames have no legitimate use and are abusive, but @@ -116,7 +116,7 @@ export interface Http2ProtocolOptions { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value); + 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value | null); /** * Limit the number of inbound PRIORITY frames allowed per each opened stream. If the number * of PRIORITY frames received over the lifetime of connection exceeds the value calculated @@ -132,7 +132,7 @@ export interface Http2ProtocolOptions { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value); + 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value | null); /** * Limit the number of inbound WINDOW_UPDATE frames allowed per DATA frame sent. If the number * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated @@ -151,7 +151,7 @@ export interface Http2ProtocolOptions { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value); + 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value | null); /** * Allows invalid HTTP messaging and headers. When this option is disabled (default), then * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, @@ -206,12 +206,12 @@ export interface Http2ProtocolOptions { * * See `RFC7540, sec. 8.1 `_ for details. */ - 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue); + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue | null); /** * Send HTTP/2 PING frames to verify that the connection is still healthy. If the remote peer * does not respond within the configured timeout, the connection will be aborted. */ - 'connection_keepalive'?: (_envoy_config_core_v3_KeepaliveSettings); + 'connection_keepalive'?: (_envoy_config_core_v3_KeepaliveSettings | null); } /** @@ -224,7 +224,7 @@ export interface Http2ProtocolOptions__Output { * range from 0 to 4294967295 (2^32 - 1) and defaults to 4096. 0 effectively disables header * compression. */ - 'hpack_table_size'?: (_google_protobuf_UInt32Value__Output); + 'hpack_table_size': (_google_protobuf_UInt32Value__Output | null); /** * `Maximum concurrent streams `_ * allowed for peer on one HTTP/2 connection. Valid values range from 1 to 2147483647 (2^31 - 1) @@ -234,7 +234,7 @@ export interface Http2ProtocolOptions__Output { * on a single connection. If the limit is reached, Envoy may queue requests or establish * additional connections (as allowed per circuit breaker limits). */ - 'max_concurrent_streams'?: (_google_protobuf_UInt32Value__Output); + 'max_concurrent_streams': (_google_protobuf_UInt32Value__Output | null); /** * `Initial stream-level flow-control window * `_ size. Valid values range from 65535 @@ -248,12 +248,12 @@ export interface Http2ProtocolOptions__Output { * HTTP/2 codec buffers. Once the buffer reaches this pointer, watermark callbacks will fire to * stop the flow of data to the codec buffers. */ - 'initial_stream_window_size'?: (_google_protobuf_UInt32Value__Output); + 'initial_stream_window_size': (_google_protobuf_UInt32Value__Output | null); /** * Similar to *initial_stream_window_size*, but for connection-level flow-control * window. Currently, this has the same minimum/maximum/default as *initial_stream_window_size*. */ - 'initial_connection_window_size'?: (_google_protobuf_UInt32Value__Output); + 'initial_connection_window_size': (_google_protobuf_UInt32Value__Output | null); /** * Allows proxying Websocket and other upgrades over H2 connect. */ @@ -275,7 +275,7 @@ export interface Http2ProtocolOptions__Output { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_outbound_frames'?: (_google_protobuf_UInt32Value__Output); + 'max_outbound_frames': (_google_protobuf_UInt32Value__Output | null); /** * Limit the number of pending outbound downstream frames of types PING, SETTINGS and RST_STREAM, * preventing high memory utilization when receiving continuous stream of these frames. Exceeding @@ -285,7 +285,7 @@ export interface Http2ProtocolOptions__Output { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_outbound_control_frames'?: (_google_protobuf_UInt32Value__Output); + 'max_outbound_control_frames': (_google_protobuf_UInt32Value__Output | null); /** * Limit the number of consecutive inbound frames of types HEADERS, CONTINUATION and DATA with an * empty payload and no end stream flag. Those frames have no legitimate use and are abusive, but @@ -296,7 +296,7 @@ export interface Http2ProtocolOptions__Output { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_consecutive_inbound_frames_with_empty_payload'?: (_google_protobuf_UInt32Value__Output); + 'max_consecutive_inbound_frames_with_empty_payload': (_google_protobuf_UInt32Value__Output | null); /** * Limit the number of inbound PRIORITY frames allowed per each opened stream. If the number * of PRIORITY frames received over the lifetime of connection exceeds the value calculated @@ -312,7 +312,7 @@ export interface Http2ProtocolOptions__Output { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_inbound_priority_frames_per_stream'?: (_google_protobuf_UInt32Value__Output); + 'max_inbound_priority_frames_per_stream': (_google_protobuf_UInt32Value__Output | null); /** * Limit the number of inbound WINDOW_UPDATE frames allowed per DATA frame sent. If the number * of WINDOW_UPDATE frames received over the lifetime of connection exceeds the value calculated @@ -331,7 +331,7 @@ export interface Http2ProtocolOptions__Output { * NOTE: flood and abuse mitigation for upstream connections is presently enabled by the * `envoy.reloadable_features.upstream_http2_flood_checks` flag. */ - 'max_inbound_window_update_frames_per_data_frame_sent'?: (_google_protobuf_UInt32Value__Output); + 'max_inbound_window_update_frames_per_data_frame_sent': (_google_protobuf_UInt32Value__Output | null); /** * Allows invalid HTTP messaging and headers. When this option is disabled (default), then * the whole HTTP/2 connection is terminated upon receiving invalid HEADERS frame. However, @@ -386,10 +386,10 @@ export interface Http2ProtocolOptions__Output { * * See `RFC7540, sec. 8.1 `_ for details. */ - 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue__Output); + 'override_stream_error_on_invalid_http_message': (_google_protobuf_BoolValue__Output | null); /** * Send HTTP/2 PING frames to verify that the connection is still healthy. If the remote peer * does not respond within the configured timeout, the connection will be aborted. */ - 'connection_keepalive'?: (_envoy_config_core_v3_KeepaliveSettings__Output); + 'connection_keepalive': (_envoy_config_core_v3_KeepaliveSettings__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts index 4a5efeebd..f689ba802 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts @@ -53,13 +53,13 @@ export interface HttpProtocolOptions { * is configured, this timeout is scaled for downstream connections according to the value for * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. */ - 'idle_timeout'?: (_google_protobuf_Duration); + 'idle_timeout'?: (_google_protobuf_Duration | null); /** * The maximum number of headers. If unconfigured, the default * maximum number of request headers allowed is 100. Requests that exceed this limit will receive * a 431 response for HTTP/1.x and cause a stream reset for HTTP/2. */ - 'max_headers_count'?: (_google_protobuf_UInt32Value); + 'max_headers_count'?: (_google_protobuf_UInt32Value | null); /** * The maximum duration of a connection. The duration is defined as a period since a connection * was established. If not set, there is no max duration. When max_connection_duration is reached @@ -68,12 +68,12 @@ export interface HttpProtocolOptions { * `. * Note: not implemented for upstream connections. */ - 'max_connection_duration'?: (_google_protobuf_Duration); + 'max_connection_duration'?: (_google_protobuf_Duration | null); /** * Total duration to keep alive an HTTP request/response stream. If the time limit is reached the stream will be * reset independent of any other timeouts. If not specified, this value is not set. */ - 'max_stream_duration'?: (_google_protobuf_Duration); + 'max_stream_duration'?: (_google_protobuf_Duration | null); /** * Action to take when a client request with a header name containing underscore characters is received. * If this setting is not specified, the value defaults to ALLOW. @@ -104,13 +104,13 @@ export interface HttpProtocolOptions__Output { * is configured, this timeout is scaled for downstream connections according to the value for * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. */ - 'idle_timeout'?: (_google_protobuf_Duration__Output); + 'idle_timeout': (_google_protobuf_Duration__Output | null); /** * The maximum number of headers. If unconfigured, the default * maximum number of request headers allowed is 100. Requests that exceed this limit will receive * a 431 response for HTTP/1.x and cause a stream reset for HTTP/2. */ - 'max_headers_count'?: (_google_protobuf_UInt32Value__Output); + 'max_headers_count': (_google_protobuf_UInt32Value__Output | null); /** * The maximum duration of a connection. The duration is defined as a period since a connection * was established. If not set, there is no max duration. When max_connection_duration is reached @@ -119,12 +119,12 @@ export interface HttpProtocolOptions__Output { * `. * Note: not implemented for upstream connections. */ - 'max_connection_duration'?: (_google_protobuf_Duration__Output); + 'max_connection_duration': (_google_protobuf_Duration__Output | null); /** * Total duration to keep alive an HTTP request/response stream. If the time limit is reached the stream will be * reset independent of any other timeouts. If not specified, this value is not set. */ - 'max_stream_duration'?: (_google_protobuf_Duration__Output); + 'max_stream_duration': (_google_protobuf_Duration__Output | null); /** * Action to take when a client request with a header name containing underscore characters is received. * If this setting is not specified, the value defaults to ALLOW. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts index 5da6ed4c0..0bac9ac51 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpUri.ts @@ -30,7 +30,7 @@ export interface HttpUri { /** * Sets the maximum duration in milliseconds that a response can take to arrive upon request. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); /** * Specify how `uri` is to be fetched. Today, this requires an explicit * cluster, but in the future we may support dynamic cluster creation or @@ -68,7 +68,7 @@ export interface HttpUri__Output { /** * Sets the maximum duration in milliseconds that a response can take to arrive upon request. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); /** * Specify how `uri` is to be fetched. Today, this requires an explicit * cluster, but in the future we may support dynamic cluster creation or diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts index cb2e14c58..81344f864 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts @@ -7,34 +7,34 @@ export interface KeepaliveSettings { /** * Send HTTP/2 PING frames at this period, in order to test that the connection is still alive. */ - 'interval'?: (_google_protobuf_Duration); + 'interval'?: (_google_protobuf_Duration | null); /** * How long to wait for a response to a keepalive PING. If a response is not received within this * time period, the connection will be aborted. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); /** * A random jitter amount as a percentage of interval that will be added to each interval. * A value of zero means there will be no jitter. * The default value is 15%. */ - 'interval_jitter'?: (_envoy_type_v3_Percent); + 'interval_jitter'?: (_envoy_type_v3_Percent | null); } export interface KeepaliveSettings__Output { /** * Send HTTP/2 PING frames at this period, in order to test that the connection is still alive. */ - 'interval'?: (_google_protobuf_Duration__Output); + 'interval': (_google_protobuf_Duration__Output | null); /** * How long to wait for a response to a keepalive PING. If a response is not received within this * time period, the connection will be aborted. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); /** * A random jitter amount as a percentage of interval that will be added to each interval. * A value of zero means there will be no jitter. * The default value is 15%. */ - 'interval_jitter'?: (_envoy_type_v3_Percent__Output); + 'interval_jitter': (_envoy_type_v3_Percent__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts index 6d7181f18..8d1811c67 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts @@ -63,5 +63,5 @@ export interface Metadata__Output { * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* * namespace is reserved for Envoy's built-in filters. */ - 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct__Output}); + 'filter_metadata': ({[key: string]: _google_protobuf_Struct__Output}); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts index 717263976..7218b802e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts @@ -41,11 +41,11 @@ export interface Node { * Opaque metadata extending the node identifier. Envoy will pass this * directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct); + 'metadata'?: (_google_protobuf_Struct | null); /** * Locality specifying where the Envoy instance is running. */ - 'locality'?: (_envoy_config_core_v3_Locality); + 'locality'?: (_envoy_config_core_v3_Locality | null); /** * Free-form string that identifies the entity requesting config. * E.g. "envoy" or "grpc" @@ -59,7 +59,7 @@ export interface Node { /** * Structured version of the entity requesting config. */ - 'user_agent_build_version'?: (_envoy_config_core_v3_BuildVersion); + 'user_agent_build_version'?: (_envoy_config_core_v3_BuildVersion | null); /** * List of extensions and their versions supported by the node. */ @@ -117,11 +117,11 @@ export interface Node__Output { * Opaque metadata extending the node identifier. Envoy will pass this * directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct__Output); + 'metadata': (_google_protobuf_Struct__Output | null); /** * Locality specifying where the Envoy instance is running. */ - 'locality'?: (_envoy_config_core_v3_Locality__Output); + 'locality': (_envoy_config_core_v3_Locality__Output | null); /** * Free-form string that identifies the entity requesting config. * E.g. "envoy" or "grpc" @@ -135,7 +135,7 @@ export interface Node__Output { /** * Structured version of the entity requesting config. */ - 'user_agent_build_version'?: (_envoy_config_core_v3_BuildVersion__Output); + 'user_agent_build_version'?: (_envoy_config_core_v3_BuildVersion__Output | null); /** * List of extensions and their versions supported by the node. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts index 8f4093fd4..bf002d99c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RateLimitSettings.ts @@ -11,12 +11,12 @@ export interface RateLimitSettings { * Maximum number of tokens to be used for rate limiting discovery request calls. If not set, a * default value of 100 will be used. */ - 'max_tokens'?: (_google_protobuf_UInt32Value); + 'max_tokens'?: (_google_protobuf_UInt32Value | null); /** * Rate at which tokens will be filled per second. If not set, a default fill rate of 10 tokens * per second will be used. */ - 'fill_rate'?: (_google_protobuf_DoubleValue); + 'fill_rate'?: (_google_protobuf_DoubleValue | null); } /** @@ -27,10 +27,10 @@ export interface RateLimitSettings__Output { * Maximum number of tokens to be used for rate limiting discovery request calls. If not set, a * default value of 100 will be used. */ - 'max_tokens'?: (_google_protobuf_UInt32Value__Output); + 'max_tokens': (_google_protobuf_UInt32Value__Output | null); /** * Rate at which tokens will be filled per second. If not set, a default fill rate of 10 tokens * per second will be used. */ - 'fill_rate'?: (_google_protobuf_DoubleValue__Output); + 'fill_rate': (_google_protobuf_DoubleValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts index 99634015f..917304d97 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RemoteDataSource.ts @@ -10,7 +10,7 @@ export interface RemoteDataSource { /** * The HTTP URI to fetch the remote data. */ - 'http_uri'?: (_envoy_config_core_v3_HttpUri); + 'http_uri'?: (_envoy_config_core_v3_HttpUri | null); /** * SHA256 string for verifying data. */ @@ -18,7 +18,7 @@ export interface RemoteDataSource { /** * Retry policy for fetching remote data. */ - 'retry_policy'?: (_envoy_config_core_v3_RetryPolicy); + 'retry_policy'?: (_envoy_config_core_v3_RetryPolicy | null); } /** @@ -28,7 +28,7 @@ export interface RemoteDataSource__Output { /** * The HTTP URI to fetch the remote data. */ - 'http_uri'?: (_envoy_config_core_v3_HttpUri__Output); + 'http_uri': (_envoy_config_core_v3_HttpUri__Output | null); /** * SHA256 string for verifying data. */ @@ -36,5 +36,5 @@ export interface RemoteDataSource__Output { /** * Retry policy for fetching remote data. */ - 'retry_policy'?: (_envoy_config_core_v3_RetryPolicy__Output); + 'retry_policy': (_envoy_config_core_v3_RetryPolicy__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts index 6d0d9927b..def6f7311 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts @@ -12,12 +12,12 @@ export interface RetryPolicy { * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ - 'retry_back_off'?: (_envoy_config_core_v3_BackoffStrategy); + 'retry_back_off'?: (_envoy_config_core_v3_BackoffStrategy | null); /** * Specifies the allowed number of retries. This parameter is optional and * defaults to 1. */ - 'num_retries'?: (_google_protobuf_UInt32Value); + 'num_retries'?: (_google_protobuf_UInt32Value | null); } /** @@ -29,10 +29,10 @@ export interface RetryPolicy__Output { * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ - 'retry_back_off'?: (_envoy_config_core_v3_BackoffStrategy__Output); + 'retry_back_off': (_envoy_config_core_v3_BackoffStrategy__Output | null); /** * Specifies the allowed number of retries. This parameter is optional and * defaults to 1. */ - 'num_retries'?: (_google_protobuf_UInt32Value__Output); + 'num_retries': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts index 413a4f931..b6df8d617 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFeatureFlag.ts @@ -9,7 +9,7 @@ export interface RuntimeFeatureFlag { /** * Default value if runtime value is not available. */ - 'default_value'?: (_google_protobuf_BoolValue); + 'default_value'?: (_google_protobuf_BoolValue | null); /** * Runtime key to get value for comparison. This value is used if defined. The boolean value must * be represented via its @@ -25,7 +25,7 @@ export interface RuntimeFeatureFlag__Output { /** * Default value if runtime value is not available. */ - 'default_value'?: (_google_protobuf_BoolValue__Output); + 'default_value': (_google_protobuf_BoolValue__Output | null); /** * Runtime key to get value for comparison. This value is used if defined. The boolean value must * be represented via its diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts index 5610f7bdd..619bfd484 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts @@ -18,7 +18,7 @@ export interface RuntimeFractionalPercent { /** * Default value if the runtime value's for the numerator/denominator keys are not available. */ - 'default_value'?: (_envoy_type_v3_FractionalPercent); + 'default_value'?: (_envoy_type_v3_FractionalPercent | null); /** * Runtime key for a YAML representation of a FractionalPercent. */ @@ -41,7 +41,7 @@ export interface RuntimeFractionalPercent__Output { /** * Default value if the runtime value's for the numerator/denominator keys are not available. */ - 'default_value'?: (_envoy_type_v3_FractionalPercent__Output); + 'default_value': (_envoy_type_v3_FractionalPercent__Output | null); /** * Runtime key for a YAML representation of a FractionalPercent. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts index b317b5aa2..1dbe6ea4a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimePercent.ts @@ -9,7 +9,7 @@ export interface RuntimePercent { /** * Default value if runtime value is not available. */ - 'default_value'?: (_envoy_type_v3_Percent); + 'default_value'?: (_envoy_type_v3_Percent | null); /** * Runtime key to get value for comparison. This value is used if defined. */ @@ -23,7 +23,7 @@ export interface RuntimePercent__Output { /** * Default value if runtime value is not available. */ - 'default_value'?: (_envoy_type_v3_Percent__Output); + 'default_value': (_envoy_type_v3_Percent__Output | null); /** * Runtime key to get value for comparison. This value is used if defined. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts index 41bd5e539..ae3003189 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts @@ -53,7 +53,7 @@ export interface SubstitutionFormatString { * "message": "My error message" * } */ - 'json_format'?: (_google_protobuf_Struct); + 'json_format'?: (_google_protobuf_Struct | null); /** * If set to true, when command operators are evaluated to null, * @@ -91,7 +91,7 @@ export interface SubstitutionFormatString { * * upstream connect error:503:path=/foo */ - 'text_format_source'?: (_envoy_config_core_v3_DataSource); + 'text_format_source'?: (_envoy_config_core_v3_DataSource | null); /** * Specifies a collection of Formatter plugins that can be called from the access log configuration. * See the formatters extensions documentation for details. @@ -149,7 +149,7 @@ export interface SubstitutionFormatString__Output { * "message": "My error message" * } */ - 'json_format'?: (_google_protobuf_Struct__Output); + 'json_format'?: (_google_protobuf_Struct__Output | null); /** * If set to true, when command operators are evaluated to null, * @@ -187,7 +187,7 @@ export interface SubstitutionFormatString__Output { * * upstream connect error:503:path=/foo */ - 'text_format_source'?: (_envoy_config_core_v3_DataSource__Output); + 'text_format_source'?: (_envoy_config_core_v3_DataSource__Output | null); /** * Specifies a collection of Formatter plugins that can be called from the access log configuration. * See the formatters extensions documentation for details. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts index a1bac359e..1ad81091d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TcpKeepalive.ts @@ -8,18 +8,18 @@ export interface TcpKeepalive { * the connection is dead. Default is to use the OS level configuration (unless * overridden, Linux defaults to 9.) */ - 'keepalive_probes'?: (_google_protobuf_UInt32Value); + 'keepalive_probes'?: (_google_protobuf_UInt32Value | null); /** * The number of seconds a connection needs to be idle before keep-alive probes * start being sent. Default is to use the OS level configuration (unless * overridden, Linux defaults to 7200s (i.e., 2 hours.) */ - 'keepalive_time'?: (_google_protobuf_UInt32Value); + 'keepalive_time'?: (_google_protobuf_UInt32Value | null); /** * The number of seconds between keep-alive probes. Default is to use the OS * level configuration (unless overridden, Linux defaults to 75s.) */ - 'keepalive_interval'?: (_google_protobuf_UInt32Value); + 'keepalive_interval'?: (_google_protobuf_UInt32Value | null); } export interface TcpKeepalive__Output { @@ -28,16 +28,16 @@ export interface TcpKeepalive__Output { * the connection is dead. Default is to use the OS level configuration (unless * overridden, Linux defaults to 9.) */ - 'keepalive_probes'?: (_google_protobuf_UInt32Value__Output); + 'keepalive_probes': (_google_protobuf_UInt32Value__Output | null); /** * The number of seconds a connection needs to be idle before keep-alive probes * start being sent. Default is to use the OS level configuration (unless * overridden, Linux defaults to 7200s (i.e., 2 hours.) */ - 'keepalive_time'?: (_google_protobuf_UInt32Value__Output); + 'keepalive_time': (_google_protobuf_UInt32Value__Output | null); /** * The number of seconds between keep-alive probes. Default is to use the OS * level configuration (unless overridden, Linux defaults to 75s.) */ - 'keepalive_interval'?: (_google_protobuf_UInt32Value__Output); + 'keepalive_interval': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts index b14402783..0031ad52f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts @@ -14,7 +14,7 @@ export interface TransportSocket { * socket implementation. */ 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Implementation specific configuration which depends on the implementation being instantiated. * See the supported transport socket implementations for further documentation. @@ -34,7 +34,7 @@ export interface TransportSocket__Output { * socket implementation. */ 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Implementation specific configuration which depends on the implementation being instantiated. * See the supported transport socket implementations for further documentation. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts index 788826a1b..d653f9373 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TypedExtensionConfig.ts @@ -19,7 +19,7 @@ export interface TypedExtensionConfig { * :ref:`extension configuration overview * ` for further details. */ - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); } /** @@ -39,5 +39,5 @@ export interface TypedExtensionConfig__Output { * :ref:`extension configuration overview * ` for further details. */ - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config': (_google_protobuf_Any__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts index a092f0dde..03ceb570e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts @@ -17,7 +17,7 @@ export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOver /** * Percentage of traffic that should be dropped for the category. */ - 'drop_percentage'?: (_envoy_type_v3_FractionalPercent); + 'drop_percentage'?: (_envoy_type_v3_FractionalPercent | null); } /** @@ -31,7 +31,7 @@ export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy_DropOver /** * Percentage of traffic that should be dropped for the category. */ - 'drop_percentage'?: (_envoy_type_v3_FractionalPercent__Output); + 'drop_percentage': (_envoy_type_v3_FractionalPercent__Output | null); } /** @@ -78,14 +78,14 @@ export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy { * Read more at :ref:`priority levels ` and * :ref:`localities `. */ - 'overprovisioning_factor'?: (_google_protobuf_UInt32Value); + 'overprovisioning_factor'?: (_google_protobuf_UInt32Value | null); /** * The max time until which the endpoints from this assignment can be used. * If no new assignments are received before this time expires the endpoints * are considered stale and should be marked unhealthy. * Defaults to 0 which means endpoints never go stale. */ - 'endpoint_stale_after'?: (_google_protobuf_Duration); + 'endpoint_stale_after'?: (_google_protobuf_Duration | null); } /** @@ -132,14 +132,14 @@ export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy__Output * Read more at :ref:`priority levels ` and * :ref:`localities `. */ - 'overprovisioning_factor'?: (_google_protobuf_UInt32Value__Output); + 'overprovisioning_factor': (_google_protobuf_UInt32Value__Output | null); /** * The max time until which the endpoints from this assignment can be used. * If no new assignments are received before this time expires the endpoints * are considered stale and should be marked unhealthy. * Defaults to 0 which means endpoints never go stale. */ - 'endpoint_stale_after'?: (_google_protobuf_Duration__Output); + 'endpoint_stale_after': (_google_protobuf_Duration__Output | null); } /** @@ -169,7 +169,7 @@ export interface ClusterLoadAssignment { /** * Load balancing policy settings. */ - 'policy'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy); + 'policy'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy | null); /** * Map of named endpoints that can be referenced in LocalityLbEndpoints. * [#not-implemented-hide:] @@ -204,10 +204,10 @@ export interface ClusterLoadAssignment__Output { /** * Load balancing policy settings. */ - 'policy'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy__Output); + 'policy': (_envoy_config_endpoint_v3_ClusterLoadAssignment_Policy__Output | null); /** * Map of named endpoints that can be referenced in LocalityLbEndpoints. * [#not-implemented-hide:] */ - 'named_endpoints'?: ({[key: string]: _envoy_config_endpoint_v3_Endpoint__Output}); + 'named_endpoints': ({[key: string]: _envoy_config_endpoint_v3_Endpoint__Output}); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts index 4d15bee14..db820b0b3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts @@ -56,7 +56,7 @@ export interface ClusterStats { * and the *LoadStatsResponse* message sent from the management server, this may be longer than * the requested load reporting interval in the *LoadStatsResponse*. */ - 'load_report_interval'?: (_google_protobuf_Duration); + 'load_report_interval'?: (_google_protobuf_Duration | null); /** * Information about deliberately dropped requests for each category specified * in the DropOverload policy. @@ -100,7 +100,7 @@ export interface ClusterStats__Output { * and the *LoadStatsResponse* message sent from the management server, this may be longer than * the requested load reporting interval in the *LoadStatsResponse*. */ - 'load_report_interval'?: (_google_protobuf_Duration__Output); + 'load_report_interval': (_google_protobuf_Duration__Output | null); /** * Information about deliberately dropped requests for each category specified * in the DropOverload policy. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts index 7e1a7b346..c01987cce 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts @@ -63,7 +63,7 @@ export interface Endpoint { * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ - 'address'?: (_envoy_config_core_v3_Address); + 'address'?: (_envoy_config_core_v3_Address | null); /** * The optional health check configuration is used as configuration for the * health checker to contact the health checked host. @@ -73,7 +73,7 @@ export interface Endpoint { * This takes into effect only for upstream clusters with * :ref:`active health checking ` enabled. */ - 'health_check_config'?: (_envoy_config_endpoint_v3_Endpoint_HealthCheckConfig); + 'health_check_config'?: (_envoy_config_endpoint_v3_Endpoint_HealthCheckConfig | null); /** * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features @@ -98,7 +98,7 @@ export interface Endpoint__Output { * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ - 'address'?: (_envoy_config_core_v3_Address__Output); + 'address': (_envoy_config_core_v3_Address__Output | null); /** * The optional health check configuration is used as configuration for the * health checker to contact the health checked host. @@ -108,7 +108,7 @@ export interface Endpoint__Output { * This takes into effect only for upstream clusters with * :ref:`active health checking ` enabled. */ - 'health_check_config'?: (_envoy_config_endpoint_v3_Endpoint_HealthCheckConfig__Output); + 'health_check_config': (_envoy_config_endpoint_v3_Endpoint_HealthCheckConfig__Output | null); /** * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts index 449dd8aa3..3952a6928 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts @@ -10,7 +10,7 @@ import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output a * [#next-free-field: 6] */ export interface LbEndpoint { - 'endpoint'?: (_envoy_config_endpoint_v3_Endpoint); + 'endpoint'?: (_envoy_config_endpoint_v3_Endpoint | null); /** * Optional health status when known and supplied by EDS server. */ @@ -24,7 +24,7 @@ export interface LbEndpoint { * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ - 'metadata'?: (_envoy_config_core_v3_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata | null); /** * The optional load balancing weight of the upstream host; at least 1. * Envoy uses the load balancing weight in some of the built in load @@ -36,7 +36,7 @@ export interface LbEndpoint { * weight in a locality. The sum of the weights of all endpoints in the * endpoint's locality must not exceed uint32_t maximal value (4294967295). */ - 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + 'load_balancing_weight'?: (_google_protobuf_UInt32Value | null); /** * [#not-implemented-hide:] */ @@ -52,7 +52,7 @@ export interface LbEndpoint { * [#next-free-field: 6] */ export interface LbEndpoint__Output { - 'endpoint'?: (_envoy_config_endpoint_v3_Endpoint__Output); + 'endpoint'?: (_envoy_config_endpoint_v3_Endpoint__Output | null); /** * Optional health status when known and supplied by EDS server. */ @@ -66,7 +66,7 @@ export interface LbEndpoint__Output { * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ - 'metadata'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata': (_envoy_config_core_v3_Metadata__Output | null); /** * The optional load balancing weight of the upstream host; at least 1. * Envoy uses the load balancing weight in some of the built in load @@ -78,7 +78,7 @@ export interface LbEndpoint__Output { * weight in a locality. The sum of the weights of all endpoints in the * endpoint's locality must not exceed uint32_t maximal value (4294967295). */ - 'load_balancing_weight'?: (_google_protobuf_UInt32Value__Output); + 'load_balancing_weight': (_google_protobuf_UInt32Value__Output | null); /** * [#not-implemented-hide:] */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts index 9924d2466..22f053ed0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts @@ -15,7 +15,7 @@ export interface LocalityLbEndpoints { /** * Identifies location of where the upstream hosts run. */ - 'locality'?: (_envoy_config_core_v3_Locality); + 'locality'?: (_envoy_config_core_v3_Locality | null); /** * The group of endpoints belonging to the locality specified. */ @@ -33,7 +33,7 @@ export interface LocalityLbEndpoints { * specified when locality weighted load balancing is enabled, the locality is * assigned no load. */ - 'load_balancing_weight'?: (_google_protobuf_UInt32Value); + 'load_balancing_weight'?: (_google_protobuf_UInt32Value | null); /** * Optional: the priority for this LocalityLbEndpoints. If unspecified this will * default to the highest priority (0). @@ -54,7 +54,7 @@ export interface LocalityLbEndpoints { * to determine where to route the requests. * [#not-implemented-hide:] */ - 'proximity'?: (_google_protobuf_UInt32Value); + 'proximity'?: (_google_protobuf_UInt32Value | null); } /** @@ -68,7 +68,7 @@ export interface LocalityLbEndpoints__Output { /** * Identifies location of where the upstream hosts run. */ - 'locality'?: (_envoy_config_core_v3_Locality__Output); + 'locality': (_envoy_config_core_v3_Locality__Output | null); /** * The group of endpoints belonging to the locality specified. */ @@ -86,7 +86,7 @@ export interface LocalityLbEndpoints__Output { * specified when locality weighted load balancing is enabled, the locality is * assigned no load. */ - 'load_balancing_weight'?: (_google_protobuf_UInt32Value__Output); + 'load_balancing_weight': (_google_protobuf_UInt32Value__Output | null); /** * Optional: the priority for this LocalityLbEndpoints. If unspecified this will * default to the highest priority (0). @@ -107,5 +107,5 @@ export interface LocalityLbEndpoints__Output { * to determine where to route the requests. * [#not-implemented-hide:] */ - 'proximity'?: (_google_protobuf_UInt32Value__Output); + 'proximity': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts index 8fe66d6c4..ab06afb39 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamEndpointStats.ts @@ -12,7 +12,7 @@ export interface UpstreamEndpointStats { /** * Upstream host address. */ - 'address'?: (_envoy_config_core_v3_Address); + 'address'?: (_envoy_config_core_v3_Address | null); /** * The total number of requests successfully completed by the endpoints in the * locality. These include non-5xx responses for HTTP, where errors @@ -45,7 +45,7 @@ export interface UpstreamEndpointStats { * Opaque and implementation dependent metadata of the * endpoint. Envoy will pass this directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct); + 'metadata'?: (_google_protobuf_Struct | null); /** * The total number of requests that were issued to this endpoint * since the last report. A single TCP connection, HTTP or gRPC @@ -61,7 +61,7 @@ export interface UpstreamEndpointStats__Output { /** * Upstream host address. */ - 'address'?: (_envoy_config_core_v3_Address__Output); + 'address': (_envoy_config_core_v3_Address__Output | null); /** * The total number of requests successfully completed by the endpoints in the * locality. These include non-5xx responses for HTTP, where errors @@ -94,7 +94,7 @@ export interface UpstreamEndpointStats__Output { * Opaque and implementation dependent metadata of the * endpoint. Envoy will pass this directly to the management server. */ - 'metadata'?: (_google_protobuf_Struct__Output); + 'metadata': (_google_protobuf_Struct__Output | null); /** * The total number of requests that were issued to this endpoint * since the last report. A single TCP connection, HTTP or gRPC diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts index 3eb8cc4eb..f00607d00 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts @@ -16,7 +16,7 @@ export interface UpstreamLocalityStats { * Name of zone, region and optionally endpoint group these metrics were * collected from. Zone and region names could be empty if unknown. */ - 'locality'?: (_envoy_config_core_v3_Locality); + 'locality'?: (_envoy_config_core_v3_Locality | null); /** * The total number of requests successfully completed by the endpoints in the * locality. @@ -65,7 +65,7 @@ export interface UpstreamLocalityStats__Output { * Name of zone, region and optionally endpoint group these metrics were * collected from. Zone and region names could be empty if unknown. */ - 'locality'?: (_envoy_config_core_v3_Locality__Output); + 'locality': (_envoy_config_core_v3_Locality__Output | null); /** * The total number of requests successfully completed by the endpoints in the * locality. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts index 508236641..4977911fb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts @@ -17,7 +17,7 @@ export interface ApiListener { * and http_connection_manager.proto depends on rds.proto, which is in the same directory as * lds.proto, so lds.proto cannot depend on this file.] */ - 'api_listener'?: (_google_protobuf_Any); + 'api_listener'?: (_google_protobuf_Any | null); } /** @@ -35,5 +35,5 @@ export interface ApiListener__Output { * and http_connection_manager.proto depends on rds.proto, which is in the same directory as * lds.proto, so lds.proto cannot depend on this file.] */ - 'api_listener'?: (_google_protobuf_Any__Output); + 'api_listener': (_google_protobuf_Any__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts index a3d26c904..3e38fbc00 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts @@ -16,14 +16,14 @@ export interface Filter { * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. */ - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Configuration source specifier for an extension configuration discovery * service. In case of a failure and without the default configuration, the * listener closes the connections. * [#not-implemented-hide:] */ - 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource); + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource | null); 'config_type'?: "typed_config"|"config_discovery"; } @@ -40,13 +40,13 @@ export interface Filter__Output { * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. */ - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Configuration source specifier for an extension configuration discovery * service. In case of a failure and without the default configuration, the * listener closes the connections. * [#not-implemented-hide:] */ - 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output); + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output | null); 'config_type': "typed_config"|"config_discovery"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts index e7f0adb7c..d72fa824c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts @@ -23,7 +23,7 @@ export interface _envoy_config_listener_v3_FilterChain_OnDemandConfiguration { * Upon failure or timeout, all connections related to this filter chain will be closed. * Rebuilding will start again on the next new connection. */ - 'rebuild_timeout'?: (_google_protobuf_Duration); + 'rebuild_timeout'?: (_google_protobuf_Duration | null); } /** @@ -42,7 +42,7 @@ export interface _envoy_config_listener_v3_FilterChain_OnDemandConfiguration__Ou * Upon failure or timeout, all connections related to this filter chain will be closed. * Rebuilding will start again on the next new connection. */ - 'rebuild_timeout'?: (_google_protobuf_Duration__Output); + 'rebuild_timeout': (_google_protobuf_Duration__Output | null); } /** @@ -54,7 +54,7 @@ export interface FilterChain { /** * The criteria to use when matching a connection to this filter chain. */ - 'filter_chain_match'?: (_envoy_config_listener_v3_FilterChainMatch); + 'filter_chain_match'?: (_envoy_config_listener_v3_FilterChainMatch | null); /** * A list of individual network filters that make up the filter chain for * connections established with the listener. Order matters as the filters are @@ -74,11 +74,11 @@ export interface FilterChain { * :ref:`PROXY protocol listener filter ` * explicitly instead. */ - 'use_proxy_proto'?: (_google_protobuf_BoolValue); + 'use_proxy_proto'?: (_google_protobuf_BoolValue | null); /** * [#not-implemented-hide:] filter chain metadata. */ - 'metadata'?: (_envoy_config_core_v3_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata | null); /** * Optional custom transport socket implementation to use for downstream connections. * To setup TLS, set a transport socket with name `tls` and @@ -86,7 +86,7 @@ export interface FilterChain { * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket'?: (_envoy_config_core_v3_TransportSocket); + 'transport_socket'?: (_envoy_config_core_v3_TransportSocket | null); /** * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter @@ -98,13 +98,13 @@ export interface FilterChain { * If this field is not empty, the filter chain will be built on-demand. * Otherwise, the filter chain will be built normally and block listener warming. */ - 'on_demand_configuration'?: (_envoy_config_listener_v3_FilterChain_OnDemandConfiguration); + 'on_demand_configuration'?: (_envoy_config_listener_v3_FilterChain_OnDemandConfiguration | null); /** * If present and nonzero, the amount of time to allow incoming connections to complete any * transport socket negotiations. If this expires before the transport reports connection * establishment, the connection is summarily closed. */ - 'transport_socket_connect_timeout'?: (_google_protobuf_Duration); + 'transport_socket_connect_timeout'?: (_google_protobuf_Duration | null); } /** @@ -116,7 +116,7 @@ export interface FilterChain__Output { /** * The criteria to use when matching a connection to this filter chain. */ - 'filter_chain_match'?: (_envoy_config_listener_v3_FilterChainMatch__Output); + 'filter_chain_match': (_envoy_config_listener_v3_FilterChainMatch__Output | null); /** * A list of individual network filters that make up the filter chain for * connections established with the listener. Order matters as the filters are @@ -136,11 +136,11 @@ export interface FilterChain__Output { * :ref:`PROXY protocol listener filter ` * explicitly instead. */ - 'use_proxy_proto'?: (_google_protobuf_BoolValue__Output); + 'use_proxy_proto': (_google_protobuf_BoolValue__Output | null); /** * [#not-implemented-hide:] filter chain metadata. */ - 'metadata'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata': (_envoy_config_core_v3_Metadata__Output | null); /** * Optional custom transport socket implementation to use for downstream connections. * To setup TLS, set a transport socket with name `tls` and @@ -148,7 +148,7 @@ export interface FilterChain__Output { * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ - 'transport_socket'?: (_envoy_config_core_v3_TransportSocket__Output); + 'transport_socket': (_envoy_config_core_v3_TransportSocket__Output | null); /** * [#not-implemented-hide:] The unique name (or empty) by which this filter chain is known. If no * name is provided, Envoy will allocate an internal UUID for the filter chain. If the filter @@ -160,11 +160,11 @@ export interface FilterChain__Output { * If this field is not empty, the filter chain will be built on-demand. * Otherwise, the filter chain will be built normally and block listener warming. */ - 'on_demand_configuration'?: (_envoy_config_listener_v3_FilterChain_OnDemandConfiguration__Output); + 'on_demand_configuration': (_envoy_config_listener_v3_FilterChain_OnDemandConfiguration__Output | null); /** * If present and nonzero, the amount of time to allow incoming connections to complete any * transport socket negotiations. If this expires before the transport reports connection * establishment, the connection is summarily closed. */ - 'transport_socket_connect_timeout'?: (_google_protobuf_Duration__Output); + 'transport_socket_connect_timeout': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts index 1170232ae..042df6dea 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts @@ -78,7 +78,7 @@ export interface FilterChainMatch { /** * [#not-implemented-hide:] */ - 'suffix_len'?: (_google_protobuf_UInt32Value); + 'suffix_len'?: (_google_protobuf_UInt32Value | null); /** * The criteria is satisfied if the source IP address of the downstream * connection is contained in at least one of the specified subnets. If the @@ -96,7 +96,7 @@ export interface FilterChainMatch { * Optional destination port to consider when use_original_dst is set on the * listener in determining a filter chain match. */ - 'destination_port'?: (_google_protobuf_UInt32Value); + 'destination_port'?: (_google_protobuf_UInt32Value | null); /** * If non-empty, a transport protocol to consider when determining a filter chain match. * This value will be compared against the transport protocol of a new connection, when @@ -211,7 +211,7 @@ export interface FilterChainMatch__Output { /** * [#not-implemented-hide:] */ - 'suffix_len'?: (_google_protobuf_UInt32Value__Output); + 'suffix_len': (_google_protobuf_UInt32Value__Output | null); /** * The criteria is satisfied if the source IP address of the downstream * connection is contained in at least one of the specified subnets. If the @@ -229,7 +229,7 @@ export interface FilterChainMatch__Output { * Optional destination port to consider when use_original_dst is set on the * listener in determining a filter chain match. */ - 'destination_port'?: (_google_protobuf_UInt32Value__Output); + 'destination_port': (_google_protobuf_UInt32Value__Output | null); /** * If non-empty, a transport protocol to consider when determining a filter chain match. * This value will be compared against the transport protocol of a new connection, when diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts index ebcac4381..8e0fc55f6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts @@ -21,7 +21,7 @@ export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig { /** * If specified, the listener will use the exact connection balancer. */ - 'exact_balance'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance); + 'exact_balance'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance | null); 'balance_type'?: "exact_balance"; } @@ -32,7 +32,7 @@ export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig__Out /** * If specified, the listener will use the exact connection balancer. */ - 'exact_balance'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance__Output); + 'exact_balance'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig_ExactBalance__Output | null); 'balance_type': "exact_balance"; } @@ -48,7 +48,7 @@ export interface _envoy_config_listener_v3_Listener_DeprecatedV1 { * This is deprecated. Use :ref:`Listener.bind_to_port * ` */ - 'bind_to_port'?: (_google_protobuf_BoolValue); + 'bind_to_port'?: (_google_protobuf_BoolValue | null); } /** @@ -63,7 +63,7 @@ export interface _envoy_config_listener_v3_Listener_DeprecatedV1__Output { * This is deprecated. Use :ref:`Listener.bind_to_port * ` */ - 'bind_to_port'?: (_google_protobuf_BoolValue__Output); + 'bind_to_port': (_google_protobuf_BoolValue__Output | null); } // Original file: deps/envoy-api/envoy/config/listener/v3/listener.proto @@ -119,7 +119,7 @@ export interface Listener { * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on * Linux as the actual port will be allocated by the OS. */ - 'address'?: (_envoy_config_core_v3_Address); + 'address'?: (_envoy_config_core_v3_Address | null); /** * A list of filter chains to consider for this listener. The * :ref:`FilterChain ` with the most specific @@ -137,20 +137,20 @@ export interface Listener { * original destination address. If there is no listener associated with the original destination * address, the connection is handled by the listener that receives it. Defaults to false. */ - 'use_original_dst'?: (_google_protobuf_BoolValue); + 'use_original_dst'?: (_google_protobuf_BoolValue | null); /** * Soft limit on size of the listener’s new connection read and write buffers. * If unspecified, an implementation defined default is applied (1MiB). */ - 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value | null); /** * Listener metadata. */ - 'metadata'?: (_envoy_config_core_v3_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata | null); /** * [#not-implemented-hide:] */ - 'deprecated_v1'?: (_envoy_config_listener_v3_Listener_DeprecatedV1); + 'deprecated_v1'?: (_envoy_config_listener_v3_Listener_DeprecatedV1 | null); /** * The type of draining to perform at a listener-wide level. */ @@ -183,7 +183,7 @@ export interface Listener { * When this flag is not set (default), the socket is not modified, i.e. the transparent option * is neither set nor reset. */ - 'transparent'?: (_google_protobuf_BoolValue); + 'transparent'?: (_google_protobuf_BoolValue | null); /** * Whether the listener should set the *IP_FREEBIND* socket option. When this * flag is set to true, listeners can be bound to an IP address that is not @@ -192,7 +192,7 @@ export interface Listener { * (default), the socket is not modified, i.e. the option is neither enabled * nor disabled. */ - 'freebind'?: (_google_protobuf_BoolValue); + 'freebind'?: (_google_protobuf_BoolValue | null); /** * Whether the listener should accept TCP Fast Open (TFO) connections. * When this flag is set to a value greater than 0, the option TCP_FASTOPEN is enabled on @@ -209,7 +209,7 @@ export interface Listener { * On macOS, only values of 0, 1, and unset are valid; other values may result in an error. * To set the queue length on macOS, set the net.inet.tcp.fastopen_backlog kernel parameter. */ - 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value); + 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value | null); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. @@ -221,7 +221,7 @@ export interface Listener { * `continue_on_listener_filters_timeout` is set to true. Specify 0 to disable the * timeout. If not specified, a default timeout of 15s is used. */ - 'listener_filters_timeout'?: (_google_protobuf_Duration); + 'listener_filters_timeout'?: (_google_protobuf_Duration | null); /** * Specifies the intended direction of the traffic relative to the local Envoy. */ @@ -244,7 +244,7 @@ export interface Listener { * ` = "raw_udp_listener" for * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". */ - 'udp_listener_config'?: (_envoy_config_listener_v3_UdpListenerConfig); + 'udp_listener_config'?: (_envoy_config_listener_v3_UdpListenerConfig | null); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. @@ -263,13 +263,13 @@ export interface Listener { * socket listener and the various types of API listener. That way, a given Listener message * can structurally only contain the fields of the relevant type.] */ - 'api_listener'?: (_envoy_config_listener_v3_ApiListener); + 'api_listener'?: (_envoy_config_listener_v3_ApiListener | null); /** * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. */ - 'connection_balance_config'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig); + 'connection_balance_config'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig | null); /** * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and * create one socket for each worker thread. This makes inbound connections @@ -298,24 +298,24 @@ export interface Listener { * If not present, treat it as "udp_default_writer". * [#not-implemented-hide:] */ - 'udp_writer_config'?: (_envoy_config_core_v3_TypedExtensionConfig); + 'udp_writer_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); /** * The maximum length a tcp listener's pending connections queue can grow to. If no value is * provided net.core.somaxconn will be used on Linux and 128 otherwise. */ - 'tcp_backlog_size'?: (_google_protobuf_UInt32Value); + 'tcp_backlog_size'?: (_google_protobuf_UInt32Value | null); /** * The default filter chain if none of the filter chain matches. If no default filter chain is supplied, * the connection will be closed. The filter chain match is ignored in this field. */ - 'default_filter_chain'?: (_envoy_config_listener_v3_FilterChain); + 'default_filter_chain'?: (_envoy_config_listener_v3_FilterChain | null); /** * Whether the listener should bind to the port. A listener that doesn't * bind can only receive connections redirected from other listeners that set * :ref:`use_original_dst ` * to true. Default is true. */ - 'bind_to_port'?: (_google_protobuf_BoolValue); + 'bind_to_port'?: (_google_protobuf_BoolValue | null); } /** @@ -333,7 +333,7 @@ export interface Listener__Output { * that is governed by the bind rules of the OS. E.g., multiple listeners can listen on port 0 on * Linux as the actual port will be allocated by the OS. */ - 'address'?: (_envoy_config_core_v3_Address__Output); + 'address': (_envoy_config_core_v3_Address__Output | null); /** * A list of filter chains to consider for this listener. The * :ref:`FilterChain ` with the most specific @@ -351,20 +351,20 @@ export interface Listener__Output { * original destination address. If there is no listener associated with the original destination * address, the connection is handled by the listener that receives it. Defaults to false. */ - 'use_original_dst'?: (_google_protobuf_BoolValue__Output); + 'use_original_dst': (_google_protobuf_BoolValue__Output | null); /** * Soft limit on size of the listener’s new connection read and write buffers. * If unspecified, an implementation defined default is applied (1MiB). */ - 'per_connection_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); + 'per_connection_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output | null); /** * Listener metadata. */ - 'metadata'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata': (_envoy_config_core_v3_Metadata__Output | null); /** * [#not-implemented-hide:] */ - 'deprecated_v1'?: (_envoy_config_listener_v3_Listener_DeprecatedV1__Output); + 'deprecated_v1': (_envoy_config_listener_v3_Listener_DeprecatedV1__Output | null); /** * The type of draining to perform at a listener-wide level. */ @@ -397,7 +397,7 @@ export interface Listener__Output { * When this flag is not set (default), the socket is not modified, i.e. the transparent option * is neither set nor reset. */ - 'transparent'?: (_google_protobuf_BoolValue__Output); + 'transparent': (_google_protobuf_BoolValue__Output | null); /** * Whether the listener should set the *IP_FREEBIND* socket option. When this * flag is set to true, listeners can be bound to an IP address that is not @@ -406,7 +406,7 @@ export interface Listener__Output { * (default), the socket is not modified, i.e. the option is neither enabled * nor disabled. */ - 'freebind'?: (_google_protobuf_BoolValue__Output); + 'freebind': (_google_protobuf_BoolValue__Output | null); /** * Whether the listener should accept TCP Fast Open (TFO) connections. * When this flag is set to a value greater than 0, the option TCP_FASTOPEN is enabled on @@ -423,7 +423,7 @@ export interface Listener__Output { * On macOS, only values of 0, 1, and unset are valid; other values may result in an error. * To set the queue length on macOS, set the net.inet.tcp.fastopen_backlog kernel parameter. */ - 'tcp_fast_open_queue_length'?: (_google_protobuf_UInt32Value__Output); + 'tcp_fast_open_queue_length': (_google_protobuf_UInt32Value__Output | null); /** * Additional socket options that may not be present in Envoy source code or * precompiled binaries. @@ -435,7 +435,7 @@ export interface Listener__Output { * `continue_on_listener_filters_timeout` is set to true. Specify 0 to disable the * timeout. If not specified, a default timeout of 15s is used. */ - 'listener_filters_timeout'?: (_google_protobuf_Duration__Output); + 'listener_filters_timeout': (_google_protobuf_Duration__Output | null); /** * Specifies the intended direction of the traffic relative to the local Envoy. */ @@ -458,7 +458,7 @@ export interface Listener__Output { * ` = "raw_udp_listener" for * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". */ - 'udp_listener_config'?: (_envoy_config_listener_v3_UdpListenerConfig__Output); + 'udp_listener_config': (_envoy_config_listener_v3_UdpListenerConfig__Output | null); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. @@ -477,13 +477,13 @@ export interface Listener__Output { * socket listener and the various types of API listener. That way, a given Listener message * can structurally only contain the fields of the relevant type.] */ - 'api_listener'?: (_envoy_config_listener_v3_ApiListener__Output); + 'api_listener': (_envoy_config_listener_v3_ApiListener__Output | null); /** * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. */ - 'connection_balance_config'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig__Output); + 'connection_balance_config': (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig__Output | null); /** * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and * create one socket for each worker thread. This makes inbound connections @@ -512,22 +512,22 @@ export interface Listener__Output { * If not present, treat it as "udp_default_writer". * [#not-implemented-hide:] */ - 'udp_writer_config'?: (_envoy_config_core_v3_TypedExtensionConfig__Output); + 'udp_writer_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); /** * The maximum length a tcp listener's pending connections queue can grow to. If no value is * provided net.core.somaxconn will be used on Linux and 128 otherwise. */ - 'tcp_backlog_size'?: (_google_protobuf_UInt32Value__Output); + 'tcp_backlog_size': (_google_protobuf_UInt32Value__Output | null); /** * The default filter chain if none of the filter chain matches. If no default filter chain is supplied, * the connection will be closed. The filter chain match is ignored in this field. */ - 'default_filter_chain'?: (_envoy_config_listener_v3_FilterChain__Output); + 'default_filter_chain': (_envoy_config_listener_v3_FilterChain__Output | null); /** * Whether the listener should bind to the port. A listener that doesn't * bind can only receive connections redirected from other listeners that set * :ref:`use_original_dst ` * to true. Default is true. */ - 'bind_to_port'?: (_google_protobuf_BoolValue__Output); + 'bind_to_port': (_google_protobuf_BoolValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts index e8a827618..beba60dce 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts @@ -9,13 +9,13 @@ export interface ListenerFilter { * :ref:`supported filter `. */ 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ - 'filter_disabled'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate); + 'filter_disabled'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate | null); /** * Filter specific configuration which depends on the filter being instantiated. * See the supported filters for further documentation. @@ -29,13 +29,13 @@ export interface ListenerFilter__Output { * :ref:`supported filter `. */ 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ - 'filter_disabled'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output); + 'filter_disabled': (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output | null); /** * Filter specific configuration which depends on the filter being instantiated. * See the supported filters for further documentation. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts index e0d9ccc3e..34f937fa1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts @@ -57,16 +57,16 @@ export interface ListenerFilterChainMatchPredicate { * A set that describes a logical OR. If any member of the set matches, the match configuration * matches. */ - 'or_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet); + 'or_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet | null); /** * A set that describes a logical AND. If all members of the set match, the match configuration * matches. */ - 'and_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet); + 'and_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet | null); /** * A negation match. The match configuration will match if the negated match condition matches. */ - 'not_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate); + 'not_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate | null); /** * The match configuration will always match. */ @@ -75,7 +75,7 @@ export interface ListenerFilterChainMatchPredicate { * Match destination port. Particularly, the match evaluation must use the recovered local port if * the owning listener filter is after :ref:`an original_dst listener filter `. */ - 'destination_port_range'?: (_envoy_type_v3_Int32Range); + 'destination_port_range'?: (_envoy_type_v3_Int32Range | null); 'rule'?: "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; } @@ -113,16 +113,16 @@ export interface ListenerFilterChainMatchPredicate__Output { * A set that describes a logical OR. If any member of the set matches, the match configuration * matches. */ - 'or_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output); + 'or_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output | null); /** * A set that describes a logical AND. If all members of the set match, the match configuration * matches. */ - 'and_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output); + 'and_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate_MatchSet__Output | null); /** * A negation match. The match configuration will match if the negated match condition matches. */ - 'not_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output); + 'not_match'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output | null); /** * The match configuration will always match. */ @@ -131,6 +131,6 @@ export interface ListenerFilterChainMatchPredicate__Output { * Match destination port. Particularly, the match evaluation must use the recovered local port if * the owning listener filter is after :ref:`an original_dst listener filter `. */ - 'destination_port_range'?: (_envoy_type_v3_Int32Range__Output); + 'destination_port_range'?: (_envoy_type_v3_Int32Range__Output | null); 'rule': "or_match"|"and_match"|"not_match"|"any_match"|"destination_port_range"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts index c7475c42b..2ac4463fb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts @@ -9,7 +9,7 @@ export interface UdpListenerConfig { * If not specified, treat as "raw_udp_listener". */ 'udp_listener_name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Used to create a specific listener factory. To some factory, e.g. * "raw_udp_listener", config is not needed. @@ -24,7 +24,7 @@ export interface UdpListenerConfig__Output { * If not specified, treat as "raw_udp_listener". */ 'udp_listener_name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Used to create a specific listener factory. To some factory, e.g. * "raw_udp_listener", config is not needed. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts index c292a199a..03ec3218d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts @@ -27,7 +27,7 @@ export interface CorsPolicy { /** * Specifies whether the resource allows credentials. */ - 'allow_credentials'?: (_google_protobuf_BoolValue); + 'allow_credentials'?: (_google_protobuf_BoolValue | null); /** * Specifies the % of requests for which the CORS filter is enabled. * @@ -37,7 +37,7 @@ export interface CorsPolicy { * If :ref:`runtime_key ` is * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. */ - 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent); + 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent | null); /** * Specifies the % of requests for which the CORS policies will be evaluated and tracked, but not * enforced. @@ -49,7 +49,7 @@ export interface CorsPolicy { * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ - 'shadow_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent); + 'shadow_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent | null); /** * Specifies string patterns that match allowed origins. An origin is allowed if any of the * string matchers match. @@ -81,7 +81,7 @@ export interface CorsPolicy__Output { /** * Specifies whether the resource allows credentials. */ - 'allow_credentials'?: (_google_protobuf_BoolValue__Output); + 'allow_credentials': (_google_protobuf_BoolValue__Output | null); /** * Specifies the % of requests for which the CORS filter is enabled. * @@ -91,7 +91,7 @@ export interface CorsPolicy__Output { * If :ref:`runtime_key ` is * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. */ - 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); + 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output | null); /** * Specifies the % of requests for which the CORS policies will be evaluated and tracked, but not * enforced. @@ -103,7 +103,7 @@ export interface CorsPolicy__Output { * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ - 'shadow_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); + 'shadow_enabled': (_envoy_config_core_v3_RuntimeFractionalPercent__Output | null); /** * Specifies string patterns that match allowed origins. An origin is allowed if any of the * string matchers match. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts index 00e37d98f..fa8bef1d8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Decorator.ts @@ -17,7 +17,7 @@ export interface Decorator { /** * Whether the decorated details should be propagated to the other party. The default is true. */ - 'propagate'?: (_google_protobuf_BoolValue); + 'propagate'?: (_google_protobuf_BoolValue | null); } export interface Decorator__Output { @@ -35,5 +35,5 @@ export interface Decorator__Output { /** * Whether the decorated details should be propagated to the other party. The default is true. */ - 'propagate'?: (_google_protobuf_BoolValue__Output); + 'propagate': (_google_protobuf_BoolValue__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts index 9088fe712..7e0c3a1b7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts @@ -17,7 +17,7 @@ export interface DirectResponseAction { * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` or * :ref:`envoy_api_msg_config.route.v3.VirtualHost`. */ - 'body'?: (_envoy_config_core_v3_DataSource); + 'body'?: (_envoy_config_core_v3_DataSource | null); } export interface DirectResponseAction__Output { @@ -35,5 +35,5 @@ export interface DirectResponseAction__Output { * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` or * :ref:`envoy_api_msg_config.route.v3.VirtualHost`. */ - 'body'?: (_envoy_config_core_v3_DataSource__Output); + 'body': (_envoy_config_core_v3_DataSource__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts index 78221b2c7..2765c0799 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterAction.ts @@ -6,12 +6,12 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ * A filter-defined action type. */ export interface FilterAction { - 'action'?: (_google_protobuf_Any); + 'action'?: (_google_protobuf_Any | null); } /** * A filter-defined action type. */ export interface FilterAction__Output { - 'action'?: (_google_protobuf_Any__Output); + 'action': (_google_protobuf_Any__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts index ff5976e0b..9a566c2bb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts @@ -15,7 +15,7 @@ export interface FilterConfig { /** * The filter config. */ - 'config'?: (_google_protobuf_Any); + 'config'?: (_google_protobuf_Any | null); /** * If true, the filter is optional, meaning that if the client does * not support the specified filter, it may ignore the map entry rather @@ -37,7 +37,7 @@ export interface FilterConfig__Output { /** * The filter config. */ - 'config'?: (_google_protobuf_Any__Output); + 'config': (_google_protobuf_Any__Output | null); /** * If true, the filter is optional, meaning that if the client does * not support the specified filter, it may ignore the map entry rather diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts index 8d20c5c63..ee03d1fe7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts @@ -53,7 +53,7 @@ export interface HeaderMatcher { * * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, * "-1somestring" */ - 'range_match'?: (_envoy_type_v3_Int64Range); + 'range_match'?: (_envoy_type_v3_Int64Range | null); /** * If specified, header match will be performed based on whether the header is in the * request. @@ -91,7 +91,7 @@ export interface HeaderMatcher { * header value must match the regex. The rule will not match if only a subsequence of the * request header value matches the regex. */ - 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher); + 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher | null); /** * If specified, header match will be performed based on whether the header value contains * the given value or not. @@ -157,7 +157,7 @@ export interface HeaderMatcher__Output { * * For range [-10,0), route will match for header value -1, but not for 0, "somestring", 10.9, * "-1somestring" */ - 'range_match'?: (_envoy_type_v3_Int64Range__Output); + 'range_match'?: (_envoy_type_v3_Int64Range__Output | null); /** * If specified, header match will be performed based on whether the header is in the * request. @@ -195,7 +195,7 @@ export interface HeaderMatcher__Output { * header value must match the regex. The rule will not match if only a subsequence of the * request header value matches the regex. */ - 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher__Output); + 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher__Output | null); /** * If specified, header match will be performed based on whether the header value contains * the given value or not. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts index 344d825e7..413e93b27 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts @@ -13,14 +13,14 @@ export interface HedgePolicy { * Defaults to 1. * [#not-implemented-hide:] */ - 'initial_requests'?: (_google_protobuf_UInt32Value); + 'initial_requests'?: (_google_protobuf_UInt32Value | null); /** * Specifies a probability that an additional upstream request should be sent * on top of what is specified by initial_requests. * Defaults to 0. * [#not-implemented-hide:] */ - 'additional_request_chance'?: (_envoy_type_v3_FractionalPercent); + 'additional_request_chance'?: (_envoy_type_v3_FractionalPercent | null); /** * Indicates that a hedged request should be sent when the per-try timeout is hit. * This means that a retry will be issued without resetting the original request, leaving multiple upstream requests in flight. @@ -49,14 +49,14 @@ export interface HedgePolicy__Output { * Defaults to 1. * [#not-implemented-hide:] */ - 'initial_requests'?: (_google_protobuf_UInt32Value__Output); + 'initial_requests': (_google_protobuf_UInt32Value__Output | null); /** * Specifies a probability that an additional upstream request should be sent * on top of what is specified by initial_requests. * Defaults to 0. * [#not-implemented-hide:] */ - 'additional_request_chance'?: (_envoy_type_v3_FractionalPercent__Output); + 'additional_request_chance': (_envoy_type_v3_FractionalPercent__Output | null); /** * Indicates that a hedged request should be sent when the per-try timeout is hit. * This means that a retry will be issued without resetting the original request, leaving multiple upstream requests in flight. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts index 73a2bb32e..93a96c247 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts @@ -17,7 +17,7 @@ export interface InternalRedirectPolicy { * * If not specified, at most one redirect will be followed. */ - 'max_internal_redirects'?: (_google_protobuf_UInt32Value); + 'max_internal_redirects'?: (_google_protobuf_UInt32Value | null); /** * Defines what upstream response codes are allowed to trigger internal redirect. If unspecified, * only 302 will be treated as internal redirect. @@ -51,7 +51,7 @@ export interface InternalRedirectPolicy__Output { * * If not specified, at most one redirect will be followed. */ - 'max_internal_redirects'?: (_google_protobuf_UInt32Value__Output); + 'max_internal_redirects': (_google_protobuf_UInt32Value__Output | null); /** * Defines what upstream response codes are allowed to trigger internal redirect. If unspecified, * only 302 will be treated as internal redirect. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts index c88fa8ff7..d511259b0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/QueryParameterMatcher.ts @@ -16,7 +16,7 @@ export interface QueryParameterMatcher { /** * Specifies whether a query parameter value should match against a string. */ - 'string_match'?: (_envoy_type_matcher_v3_StringMatcher); + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher | null); /** * Specifies whether a query parameter should be present. */ @@ -38,7 +38,7 @@ export interface QueryParameterMatcher__Output { /** * Specifies whether a query parameter value should match against a string. */ - 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output); + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output | null); /** * Specifies whether a query parameter should be present. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts index 33d93af7d..484044bdf 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts @@ -13,42 +13,42 @@ export interface _envoy_config_route_v3_RateLimit_Action { /** * Rate limit on source cluster. */ - 'source_cluster'?: (_envoy_config_route_v3_RateLimit_Action_SourceCluster); + 'source_cluster'?: (_envoy_config_route_v3_RateLimit_Action_SourceCluster | null); /** * Rate limit on destination cluster. */ - 'destination_cluster'?: (_envoy_config_route_v3_RateLimit_Action_DestinationCluster); + 'destination_cluster'?: (_envoy_config_route_v3_RateLimit_Action_DestinationCluster | null); /** * Rate limit on request headers. */ - 'request_headers'?: (_envoy_config_route_v3_RateLimit_Action_RequestHeaders); + 'request_headers'?: (_envoy_config_route_v3_RateLimit_Action_RequestHeaders | null); /** * Rate limit on remote address. */ - 'remote_address'?: (_envoy_config_route_v3_RateLimit_Action_RemoteAddress); + 'remote_address'?: (_envoy_config_route_v3_RateLimit_Action_RemoteAddress | null); /** * Rate limit on a generic key. */ - 'generic_key'?: (_envoy_config_route_v3_RateLimit_Action_GenericKey); + 'generic_key'?: (_envoy_config_route_v3_RateLimit_Action_GenericKey | null); /** * Rate limit on the existence of request headers. */ - 'header_value_match'?: (_envoy_config_route_v3_RateLimit_Action_HeaderValueMatch); + 'header_value_match'?: (_envoy_config_route_v3_RateLimit_Action_HeaderValueMatch | null); /** * Rate limit on dynamic metadata. * * .. attention:: * This field has been deprecated in favor of the :ref:`metadata ` field */ - 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData); + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData | null); /** * Rate limit on metadata. */ - 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData); + 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData | null); /** * Rate limit descriptor extension. See the rate limit descriptor extensions documentation. */ - 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig); + 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig | null); 'action_specifier'?: "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"|"dynamic_metadata"|"metadata"|"extension"; } @@ -59,42 +59,42 @@ export interface _envoy_config_route_v3_RateLimit_Action__Output { /** * Rate limit on source cluster. */ - 'source_cluster'?: (_envoy_config_route_v3_RateLimit_Action_SourceCluster__Output); + 'source_cluster'?: (_envoy_config_route_v3_RateLimit_Action_SourceCluster__Output | null); /** * Rate limit on destination cluster. */ - 'destination_cluster'?: (_envoy_config_route_v3_RateLimit_Action_DestinationCluster__Output); + 'destination_cluster'?: (_envoy_config_route_v3_RateLimit_Action_DestinationCluster__Output | null); /** * Rate limit on request headers. */ - 'request_headers'?: (_envoy_config_route_v3_RateLimit_Action_RequestHeaders__Output); + 'request_headers'?: (_envoy_config_route_v3_RateLimit_Action_RequestHeaders__Output | null); /** * Rate limit on remote address. */ - 'remote_address'?: (_envoy_config_route_v3_RateLimit_Action_RemoteAddress__Output); + 'remote_address'?: (_envoy_config_route_v3_RateLimit_Action_RemoteAddress__Output | null); /** * Rate limit on a generic key. */ - 'generic_key'?: (_envoy_config_route_v3_RateLimit_Action_GenericKey__Output); + 'generic_key'?: (_envoy_config_route_v3_RateLimit_Action_GenericKey__Output | null); /** * Rate limit on the existence of request headers. */ - 'header_value_match'?: (_envoy_config_route_v3_RateLimit_Action_HeaderValueMatch__Output); + 'header_value_match'?: (_envoy_config_route_v3_RateLimit_Action_HeaderValueMatch__Output | null); /** * Rate limit on dynamic metadata. * * .. attention:: * This field has been deprecated in favor of the :ref:`metadata ` field */ - 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output); + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output | null); /** * Rate limit on metadata. */ - 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData__Output); + 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData__Output | null); /** * Rate limit descriptor extension. See the rate limit descriptor extensions documentation. */ - 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig__Output); + 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig__Output | null); 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"|"dynamic_metadata"|"metadata"|"extension"; } @@ -160,7 +160,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData { * Metadata struct that defines the key and path to retrieve the string value. A match will * only happen if the value in the dynamic metadata is of type string. */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey | null); /** * An optional value to use if *metadata_key* is empty. If not set and * no value is present under the metadata_key then no descriptor is generated. @@ -188,7 +188,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output * Metadata struct that defines the key and path to retrieve the string value. A match will * only happen if the value in the dynamic metadata is of type string. */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); + 'metadata_key': (_envoy_type_metadata_v3_MetadataKey__Output | null); /** * An optional value to use if *metadata_key* is empty. If not set and * no value is present under the metadata_key then no descriptor is generated. @@ -206,7 +206,7 @@ export interface _envoy_config_route_v3_RateLimit_Override_DynamicMetadata { * and a "unit" property with a value parseable to :ref:`RateLimitUnit * enum ` */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey | null); } /** @@ -219,7 +219,7 @@ export interface _envoy_config_route_v3_RateLimit_Override_DynamicMetadata__Outp * and a "unit" property with a value parseable to :ref:`RateLimitUnit * enum ` */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); + 'metadata_key': (_envoy_type_metadata_v3_MetadataKey__Output | null); } /** @@ -278,7 +278,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_HeaderValueMatch { * descriptor entry when the request does not match the headers. The * default value is true. */ - 'expect_match'?: (_google_protobuf_BoolValue); + 'expect_match'?: (_google_protobuf_BoolValue | null); /** * Specifies a set of headers that the rate limit action should match * on. The action will check the request’s headers against all the @@ -307,7 +307,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_HeaderValueMatch__Outpu * descriptor entry when the request does not match the headers. The * default value is true. */ - 'expect_match'?: (_google_protobuf_BoolValue__Output); + 'expect_match': (_google_protobuf_BoolValue__Output | null); /** * Specifies a set of headers that the rate limit action should match * on. The action will check the request’s headers against all the @@ -334,7 +334,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_MetaData { * Metadata struct that defines the key and path to retrieve the string value. A match will * only happen if the value in the metadata is of type string. */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey | null); /** * An optional value to use if *metadata_key* is empty. If not set and * no value is present under the metadata_key then no descriptor is generated. @@ -362,7 +362,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_MetaData__Output { * Metadata struct that defines the key and path to retrieve the string value. A match will * only happen if the value in the metadata is of type string. */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); + 'metadata_key': (_envoy_type_metadata_v3_MetadataKey__Output | null); /** * An optional value to use if *metadata_key* is empty. If not set and * no value is present under the metadata_key then no descriptor is generated. @@ -378,7 +378,7 @@ export interface _envoy_config_route_v3_RateLimit_Override { /** * Limit override from dynamic metadata. */ - 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Override_DynamicMetadata); + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Override_DynamicMetadata | null); 'override_specifier'?: "dynamic_metadata"; } @@ -386,7 +386,7 @@ export interface _envoy_config_route_v3_RateLimit_Override__Output { /** * Limit override from dynamic metadata. */ - 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Override_DynamicMetadata__Output); + 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Override_DynamicMetadata__Output | null); 'override_specifier': "dynamic_metadata"; } @@ -517,7 +517,7 @@ export interface RateLimit { * * The filter supports a range of 0 - 10 inclusively for stage numbers. */ - 'stage'?: (_google_protobuf_UInt32Value); + 'stage'?: (_google_protobuf_UInt32Value | null); /** * The key to be set in runtime to disable this rate limit configuration. */ @@ -537,7 +537,7 @@ export interface RateLimit { * from metadata, no override is provided. See :ref:`rate limit override * ` for more information. */ - 'limit'?: (_envoy_config_route_v3_RateLimit_Override); + 'limit'?: (_envoy_config_route_v3_RateLimit_Override | null); } /** @@ -554,7 +554,7 @@ export interface RateLimit__Output { * * The filter supports a range of 0 - 10 inclusively for stage numbers. */ - 'stage'?: (_google_protobuf_UInt32Value__Output); + 'stage': (_google_protobuf_UInt32Value__Output | null); /** * The key to be set in runtime to disable this rate limit configuration. */ @@ -574,5 +574,5 @@ export interface RateLimit__Output { * from metadata, no override is provided. See :ref:`rate limit override * ` for more information. */ - 'limit'?: (_envoy_config_route_v3_RateLimit_Override__Output); + 'limit': (_envoy_config_route_v3_RateLimit_Override__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts index baea6bc4e..750946934 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts @@ -112,7 +112,7 @@ export interface RedirectAction { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute | null); /** * When the scheme redirection take place, the following rules apply: * 1. If the source URI scheme is `http` and the port is explicitly @@ -209,7 +209,7 @@ export interface RedirectAction__Output { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output | null); /** * When the scheme redirection take place, the following rules apply: * 1. If the source URI scheme is `http` and the port is explicitly diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts index 52f391dd9..d4712b2df 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts @@ -64,7 +64,7 @@ export interface _envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff { * header contains an interval longer than this then it will be discarded and * the next header will be tried. Defaults to 300 seconds. */ - 'max_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration | null); } /** @@ -125,7 +125,7 @@ export interface _envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff__Out * header contains an interval longer than this then it will be discarded and * the next header will be tried. Defaults to 300 seconds. */ - 'max_interval'?: (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output | null); } export interface _envoy_config_route_v3_RetryPolicy_ResetHeader { @@ -172,14 +172,14 @@ export interface _envoy_config_route_v3_RetryPolicy_RetryBackOff { * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's * back-off algorithm. */ - 'base_interval'?: (_google_protobuf_Duration); + 'base_interval'?: (_google_protobuf_Duration | null); /** * Specifies the maximum interval between retries. This parameter is optional, but must be * greater than or equal to the `base_interval` if set. The default is 10 times the * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion * of Envoy's back-off algorithm. */ - 'max_interval'?: (_google_protobuf_Duration); + 'max_interval'?: (_google_protobuf_Duration | null); } export interface _envoy_config_route_v3_RetryPolicy_RetryBackOff__Output { @@ -189,37 +189,37 @@ export interface _envoy_config_route_v3_RetryPolicy_RetryBackOff__Output { * See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion of Envoy's * back-off algorithm. */ - 'base_interval'?: (_google_protobuf_Duration__Output); + 'base_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the maximum interval between retries. This parameter is optional, but must be * greater than or equal to the `base_interval` if set. The default is 10 times the * `base_interval`. See :ref:`config_http_filters_router_x-envoy-max-retries` for a discussion * of Envoy's back-off algorithm. */ - 'max_interval'?: (_google_protobuf_Duration__Output); + 'max_interval': (_google_protobuf_Duration__Output | null); } export interface _envoy_config_route_v3_RetryPolicy_RetryHostPredicate { 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); 'config_type'?: "typed_config"; } export interface _envoy_config_route_v3_RetryPolicy_RetryHostPredicate__Output { 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); 'config_type': "typed_config"; } export interface _envoy_config_route_v3_RetryPolicy_RetryPriority { 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); 'config_type'?: "typed_config"; } export interface _envoy_config_route_v3_RetryPolicy_RetryPriority__Output { 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); 'config_type': "typed_config"; } @@ -239,7 +239,7 @@ export interface RetryPolicy { * defaults to 1. These are the same conditions documented for * :ref:`config_http_filters_router_x-envoy-max-retries`. */ - 'num_retries'?: (_google_protobuf_UInt32Value); + 'num_retries'?: (_google_protobuf_UInt32Value | null); /** * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The * same conditions documented for @@ -253,13 +253,13 @@ export interface RetryPolicy { * retry policy, a request that times out will not be retried as the total timeout budget * would have been exhausted. */ - 'per_try_timeout'?: (_google_protobuf_Duration); + 'per_try_timeout'?: (_google_protobuf_Duration | null); /** * Specifies an implementation of a RetryPriority which is used to determine the * distribution of load across priorities used for retries. Refer to * :ref:`retry plugin configuration ` for more details. */ - 'retry_priority'?: (_envoy_config_route_v3_RetryPolicy_RetryPriority); + 'retry_priority'?: (_envoy_config_route_v3_RetryPolicy_RetryPriority | null); /** * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host * for retries. If any of the predicates reject the host, host selection will be reattempted. @@ -284,7 +284,7 @@ export interface RetryPolicy { * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` * describes Envoy's back-off algorithm. */ - 'retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RetryBackOff); + 'retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RetryBackOff | null); /** * HTTP response headers that trigger a retry if present in the response. A retry will be * triggered if any of the header matches match the upstream response headers. @@ -304,7 +304,7 @@ export interface RetryPolicy { * default exponential back off strategy (configured using `retry_back_off`) * whenever a response includes the matching headers. */ - 'rate_limited_retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff); + 'rate_limited_retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff | null); } /** @@ -323,7 +323,7 @@ export interface RetryPolicy__Output { * defaults to 1. These are the same conditions documented for * :ref:`config_http_filters_router_x-envoy-max-retries`. */ - 'num_retries'?: (_google_protobuf_UInt32Value__Output); + 'num_retries': (_google_protobuf_UInt32Value__Output | null); /** * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The * same conditions documented for @@ -337,13 +337,13 @@ export interface RetryPolicy__Output { * retry policy, a request that times out will not be retried as the total timeout budget * would have been exhausted. */ - 'per_try_timeout'?: (_google_protobuf_Duration__Output); + 'per_try_timeout': (_google_protobuf_Duration__Output | null); /** * Specifies an implementation of a RetryPriority which is used to determine the * distribution of load across priorities used for retries. Refer to * :ref:`retry plugin configuration ` for more details. */ - 'retry_priority'?: (_envoy_config_route_v3_RetryPolicy_RetryPriority__Output); + 'retry_priority': (_envoy_config_route_v3_RetryPolicy_RetryPriority__Output | null); /** * Specifies a collection of RetryHostPredicates that will be consulted when selecting a host * for retries. If any of the predicates reject the host, host selection will be reattempted. @@ -368,7 +368,7 @@ export interface RetryPolicy__Output { * the base interval. The documentation for :ref:`config_http_filters_router_x-envoy-max-retries` * describes Envoy's back-off algorithm. */ - 'retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RetryBackOff__Output); + 'retry_back_off': (_envoy_config_route_v3_RetryPolicy_RetryBackOff__Output | null); /** * HTTP response headers that trigger a retry if present in the response. A retry will be * triggered if any of the header matches match the upstream response headers. @@ -388,5 +388,5 @@ export interface RetryPolicy__Output { * default exponential back off strategy (configured using `retry_back_off`) * whenever a response includes the matching headers. */ - 'rate_limited_retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff__Output); + 'rate_limited_retry_back_off': (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts index ea00564f8..7bc223f82 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts @@ -26,15 +26,15 @@ export interface Route { /** * Route matching parameters. */ - 'match'?: (_envoy_config_route_v3_RouteMatch); + 'match'?: (_envoy_config_route_v3_RouteMatch | null); /** * Route request to some upstream cluster. */ - 'route'?: (_envoy_config_route_v3_RouteAction); + 'route'?: (_envoy_config_route_v3_RouteAction | null); /** * Return a redirect. */ - 'redirect'?: (_envoy_config_route_v3_RedirectAction); + 'redirect'?: (_envoy_config_route_v3_RedirectAction | null); /** * The Metadata field can be used to provide additional information * about the route. It can be used for configuration, stats, and logging. @@ -42,15 +42,15 @@ export interface Route { * For instance, if the metadata is intended for the Router filter, * the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_config_core_v3_Metadata); + 'metadata'?: (_envoy_config_core_v3_Metadata | null); /** * Decorator for the matched route. */ - 'decorator'?: (_envoy_config_route_v3_Decorator); + 'decorator'?: (_envoy_config_route_v3_Decorator | null); /** * Return an arbitrary HTTP response directly, without proxying. */ - 'direct_response'?: (_envoy_config_route_v3_DirectResponseAction); + 'direct_response'?: (_envoy_config_route_v3_DirectResponseAction | null); /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the @@ -98,13 +98,13 @@ export interface Route { * Presence of the object defines whether the connection manager's tracing configuration * is overridden by this route specific instance. */ - 'tracing'?: (_envoy_config_route_v3_Tracing); + 'tracing'?: (_envoy_config_route_v3_Tracing | null); /** * The maximum bytes which will be buffered for retries and shadowing. * If set, the bytes actually buffered will be the minimum value of this and the * listener per_connection_buffer_limit_bytes. */ - 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value | null); /** * [#not-implemented-hide:] * If true, a filter will define the action (e.g., it could dynamically generate the @@ -112,7 +112,7 @@ export interface Route { * [#comment: TODO(samflattery): Remove cleanup in route_fuzz_test.cc when * implemented] */ - 'filter_action'?: (_envoy_config_route_v3_FilterAction); + 'filter_action'?: (_envoy_config_route_v3_FilterAction | null); 'action'?: "route"|"redirect"|"direct_response"|"filter_action"; } @@ -130,15 +130,15 @@ export interface Route__Output { /** * Route matching parameters. */ - 'match'?: (_envoy_config_route_v3_RouteMatch__Output); + 'match': (_envoy_config_route_v3_RouteMatch__Output | null); /** * Route request to some upstream cluster. */ - 'route'?: (_envoy_config_route_v3_RouteAction__Output); + 'route'?: (_envoy_config_route_v3_RouteAction__Output | null); /** * Return a redirect. */ - 'redirect'?: (_envoy_config_route_v3_RedirectAction__Output); + 'redirect'?: (_envoy_config_route_v3_RedirectAction__Output | null); /** * The Metadata field can be used to provide additional information * about the route. It can be used for configuration, stats, and logging. @@ -146,15 +146,15 @@ export interface Route__Output { * For instance, if the metadata is intended for the Router filter, * the filter name should be specified as *envoy.filters.http.router*. */ - 'metadata'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata': (_envoy_config_core_v3_Metadata__Output | null); /** * Decorator for the matched route. */ - 'decorator'?: (_envoy_config_route_v3_Decorator__Output); + 'decorator': (_envoy_config_route_v3_Decorator__Output | null); /** * Return an arbitrary HTTP response directly, without proxying. */ - 'direct_response'?: (_envoy_config_route_v3_DirectResponseAction__Output); + 'direct_response'?: (_envoy_config_route_v3_DirectResponseAction__Output | null); /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the @@ -193,7 +193,7 @@ export interface Route__Output { * :ref:`FilterConfig` * message to specify additional options.] */ - 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); + 'typed_per_filter_config': ({[key: string]: _google_protobuf_Any__Output}); /** * Name for the route. */ @@ -202,13 +202,13 @@ export interface Route__Output { * Presence of the object defines whether the connection manager's tracing configuration * is overridden by this route specific instance. */ - 'tracing'?: (_envoy_config_route_v3_Tracing__Output); + 'tracing': (_envoy_config_route_v3_Tracing__Output | null); /** * The maximum bytes which will be buffered for retries and shadowing. * If set, the bytes actually buffered will be the minimum value of this and the * listener per_connection_buffer_limit_bytes. */ - 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); + 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output | null); /** * [#not-implemented-hide:] * If true, a filter will define the action (e.g., it could dynamically generate the @@ -216,6 +216,6 @@ export interface Route__Output { * [#comment: TODO(samflattery): Remove cleanup in route_fuzz_test.cc when * implemented] */ - 'filter_action'?: (_envoy_config_route_v3_FilterAction__Output); + 'filter_action'?: (_envoy_config_route_v3_FilterAction__Output | null); 'action': "route"|"redirect"|"direct_response"|"filter_action"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts index 797d6eda6..234aa25e0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts @@ -37,7 +37,7 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig /** * If present, the proxy protocol header will be prepended to the CONNECT payload sent upstream. */ - 'proxy_protocol_config'?: (_envoy_config_core_v3_ProxyProtocolConfig); + 'proxy_protocol_config'?: (_envoy_config_core_v3_ProxyProtocolConfig | null); /** * If set, the route will also allow forwarding POST payload as raw TCP. */ @@ -52,7 +52,7 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig_ /** * If present, the proxy protocol header will be prepended to the CONNECT payload sent upstream. */ - 'proxy_protocol_config'?: (_envoy_config_core_v3_ProxyProtocolConfig__Output); + 'proxy_protocol_config': (_envoy_config_core_v3_ProxyProtocolConfig__Output | null); /** * If set, the route will also allow forwarding POST payload as raw TCP. */ @@ -101,7 +101,7 @@ export interface _envoy_config_route_v3_RouteAction_HashPolicy_Cookie { * not present. If the TTL is present and zero, the generated cookie will * be a session cookie. */ - 'ttl'?: (_google_protobuf_Duration); + 'ttl'?: (_google_protobuf_Duration | null); /** * The name of the path for the cookie. If no path is specified here, no path * will be set for the cookie. @@ -137,7 +137,7 @@ export interface _envoy_config_route_v3_RouteAction_HashPolicy_Cookie__Output { * not present. If the TTL is present and zero, the generated cookie will * be a session cookie. */ - 'ttl'?: (_google_protobuf_Duration__Output); + 'ttl': (_google_protobuf_Duration__Output | null); /** * The name of the path for the cookie. If no path is specified here, no path * will be set for the cookie. @@ -172,23 +172,23 @@ export interface _envoy_config_route_v3_RouteAction_HashPolicy { /** * Header hash policy. */ - 'header'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Header); + 'header'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Header | null); /** * Cookie hash policy. */ - 'cookie'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Cookie); + 'cookie'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Cookie | null); /** * Connection properties hash policy. */ - 'connection_properties'?: (_envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties); + 'connection_properties'?: (_envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties | null); /** * Query parameter hash policy. */ - 'query_parameter'?: (_envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter); + 'query_parameter'?: (_envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter | null); /** * Filter state hash policy. */ - 'filter_state'?: (_envoy_config_route_v3_RouteAction_HashPolicy_FilterState); + 'filter_state'?: (_envoy_config_route_v3_RouteAction_HashPolicy_FilterState | null); /** * The flag that short-circuits the hash computing. This field provides a * 'fallback' style of configuration: "if a terminal policy doesn't work, @@ -223,23 +223,23 @@ export interface _envoy_config_route_v3_RouteAction_HashPolicy__Output { /** * Header hash policy. */ - 'header'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Header__Output); + 'header'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Header__Output | null); /** * Cookie hash policy. */ - 'cookie'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Cookie__Output); + 'cookie'?: (_envoy_config_route_v3_RouteAction_HashPolicy_Cookie__Output | null); /** * Connection properties hash policy. */ - 'connection_properties'?: (_envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties__Output); + 'connection_properties'?: (_envoy_config_route_v3_RouteAction_HashPolicy_ConnectionProperties__Output | null); /** * Query parameter hash policy. */ - 'query_parameter'?: (_envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter__Output); + 'query_parameter'?: (_envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter__Output | null); /** * Filter state hash policy. */ - 'filter_state'?: (_envoy_config_route_v3_RouteAction_HashPolicy_FilterState__Output); + 'filter_state'?: (_envoy_config_route_v3_RouteAction_HashPolicy_FilterState__Output | null); /** * The flag that short-circuits the hash computing. This field provides a * 'fallback' style of configuration: "if a terminal policy doesn't work, @@ -275,7 +275,7 @@ export interface _envoy_config_route_v3_RouteAction_HashPolicy_Header { * If specified, the request header value will be rewritten and used * to produce the hash key. */ - 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute | null); } export interface _envoy_config_route_v3_RouteAction_HashPolicy_Header__Output { @@ -288,7 +288,7 @@ export interface _envoy_config_route_v3_RouteAction_HashPolicy_Header__Output { * If specified, the request header value will be rewritten and used * to produce the hash key. */ - 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); + 'regex_rewrite': (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output | null); } // Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto @@ -313,14 +313,14 @@ export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration { * HttpConnectionManager max_stream_duration timeout will be disabled for * this route. */ - 'max_stream_duration'?: (_google_protobuf_Duration); + 'max_stream_duration'?: (_google_protobuf_Duration | null); /** * If present, and the request contains a `grpc-timeout header * `_, use that value as the * *max_stream_duration*, but limit the applied timeout to the maximum value specified here. * If set to 0, the `grpc-timeout` header is used without modification. */ - 'grpc_timeout_header_max'?: (_google_protobuf_Duration); + 'grpc_timeout_header_max'?: (_google_protobuf_Duration | null); /** * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by * subtracting the provided duration from the header. This is useful for allowing Envoy to set @@ -329,7 +329,7 @@ export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration { * by the client. If, after applying the offset, the resulting timeout is zero or negative, * the stream will timeout immediately. */ - 'grpc_timeout_header_offset'?: (_google_protobuf_Duration); + 'grpc_timeout_header_offset'?: (_google_protobuf_Duration | null); } export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration__Output { @@ -343,14 +343,14 @@ export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration__Output { * HttpConnectionManager max_stream_duration timeout will be disabled for * this route. */ - 'max_stream_duration'?: (_google_protobuf_Duration__Output); + 'max_stream_duration': (_google_protobuf_Duration__Output | null); /** * If present, and the request contains a `grpc-timeout header * `_, use that value as the * *max_stream_duration*, but limit the applied timeout to the maximum value specified here. * If set to 0, the `grpc-timeout` header is used without modification. */ - 'grpc_timeout_header_max'?: (_google_protobuf_Duration__Output); + 'grpc_timeout_header_max': (_google_protobuf_Duration__Output | null); /** * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by * subtracting the provided duration from the header. This is useful for allowing Envoy to set @@ -359,7 +359,7 @@ export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration__Output { * by the client. If, after applying the offset, the resulting timeout is zero or negative, * the stream will timeout immediately. */ - 'grpc_timeout_header_offset'?: (_google_protobuf_Duration__Output); + 'grpc_timeout_header_offset': (_google_protobuf_Duration__Output | null); } export interface _envoy_config_route_v3_RouteAction_HashPolicy_QueryParameter { @@ -409,11 +409,11 @@ export interface _envoy_config_route_v3_RouteAction_RequestMirrorPolicy { * number is <= the value of the numerator N, or if the key is not present, the default * value, the request will be mirrored. */ - 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent); + 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent | null); /** * Determines if the trace span should be sampled. Defaults to true. */ - 'trace_sampled'?: (_google_protobuf_BoolValue); + 'trace_sampled'?: (_google_protobuf_BoolValue | null); } /** @@ -445,11 +445,11 @@ export interface _envoy_config_route_v3_RouteAction_RequestMirrorPolicy__Output * number is <= the value of the numerator N, or if the key is not present, the default * value, the request will be mirrored. */ - 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); + 'runtime_fraction': (_envoy_config_core_v3_RuntimeFractionalPercent__Output | null); /** * Determines if the trace span should be sampled. Defaults to true. */ - 'trace_sampled'?: (_google_protobuf_BoolValue__Output); + 'trace_sampled': (_google_protobuf_BoolValue__Output | null); } /** @@ -470,14 +470,14 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig { /** * Determines if upgrades are available on this route. Defaults to true. */ - 'enabled'?: (_google_protobuf_BoolValue); + 'enabled'?: (_google_protobuf_BoolValue | null); /** * Configuration for sending data upstream as a raw data payload. This is used for * CONNECT requests, when forwarding CONNECT payload as raw TCP. * Note that CONNECT support is currently considered alpha in Envoy. * [#comment:TODO(htuch): Replace the above comment with an alpha tag. */ - 'connect_config'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig); + 'connect_config'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig | null); } /** @@ -498,14 +498,14 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig__Output { /** * Determines if upgrades are available on this route. Defaults to true. */ - 'enabled'?: (_google_protobuf_BoolValue__Output); + 'enabled': (_google_protobuf_BoolValue__Output | null); /** * Configuration for sending data upstream as a raw data payload. This is used for * CONNECT requests, when forwarding CONNECT payload as raw TCP. * Note that CONNECT support is currently considered alpha in Envoy. * [#comment:TODO(htuch): Replace the above comment with an alpha tag. */ - 'connect_config'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__Output); + 'connect_config': (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__Output | null); } /** @@ -540,7 +540,7 @@ export interface RouteAction { * :ref:`traffic splitting ` * for additional documentation. */ - 'weighted_clusters'?: (_envoy_config_route_v3_WeightedCluster); + 'weighted_clusters'?: (_envoy_config_route_v3_WeightedCluster | null); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints * in the upstream cluster with metadata matching what's set in this field will be considered @@ -548,7 +548,7 @@ export interface RouteAction { * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_config_core_v3_Metadata); + 'metadata_match'?: (_envoy_config_core_v3_Metadata | null); /** * Indicates that during forwarding, the matched prefix (or path) should be * swapped with this value. This option allows application URLs to be rooted @@ -595,7 +595,7 @@ export interface RouteAction { * type *strict_dns* or *logical_dns*. Setting this to true with other cluster * types has no effect. */ - 'auto_host_rewrite'?: (_google_protobuf_BoolValue); + 'auto_host_rewrite'?: (_google_protobuf_BoolValue | null); /** * Specifies the upstream timeout for the route. If not specified, the default is 15s. This * spans between the point at which the entire downstream request (i.e. end-of-stream) has been @@ -609,13 +609,13 @@ export interface RouteAction { * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the * :ref:`retry overview `. */ - 'timeout'?: (_google_protobuf_Duration); + 'timeout'?: (_google_protobuf_Duration | null); /** * Indicates that the route has a retry policy. Note that if this is set, * it'll take precedence over the virtual host level retry policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy); + 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy | null); /** * Optionally specifies the :ref:`routing priority `. */ @@ -633,7 +633,7 @@ export interface RouteAction { * * This field is deprecated. Please use :ref:`vh_rate_limits ` */ - 'include_vh_rate_limits'?: (_google_protobuf_BoolValue); + 'include_vh_rate_limits'?: (_google_protobuf_BoolValue | null); /** * Specifies a list of hash policies to use for ring hash load balancing. Each * hash policy is evaluated individually and the combined result is used to @@ -652,7 +652,7 @@ export interface RouteAction { /** * Indicates that the route has a CORS policy. */ - 'cors'?: (_envoy_config_route_v3_CorsPolicy); + 'cors'?: (_envoy_config_route_v3_CorsPolicy | null); /** * The HTTP status code to use when configured cluster is not found. * The default response code is 503 Service Unavailable. @@ -680,7 +680,7 @@ export interface RouteAction { * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the * :ref:`retry overview `. */ - 'max_grpc_timeout'?: (_google_protobuf_Duration); + 'max_grpc_timeout'?: (_google_protobuf_Duration | null); /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout @@ -705,7 +705,7 @@ export interface RouteAction { * is configured, this timeout is scaled according to the value for * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. */ - 'idle_timeout'?: (_google_protobuf_Duration); + 'idle_timeout'?: (_google_protobuf_Duration | null); 'upgrade_configs'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig)[]; 'internal_redirect_action'?: (_envoy_config_route_v3_RouteAction_InternalRedirectAction | keyof typeof _envoy_config_route_v3_RouteAction_InternalRedirectAction); /** @@ -713,7 +713,7 @@ export interface RouteAction { * it'll take precedence over the virtual host level hedge policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy); + 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy | null); /** * Deprecated by :ref:`grpc_timeout_header_offset `. * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting @@ -724,7 +724,7 @@ export interface RouteAction { * ensures that the offset will only ever decrease the timeout and never set it to 0 (meaning * infinity). */ - 'grpc_timeout_offset'?: (_google_protobuf_Duration); + 'grpc_timeout_offset'?: (_google_protobuf_Duration | null); /** * Indicates that during forwarding, the host header will be swapped with the content of given * downstream or :ref:`custom ` header. @@ -760,7 +760,7 @@ export interface RouteAction { * * If not specified, at most one redirect will be followed. */ - 'max_internal_redirects'?: (_google_protobuf_UInt32Value); + 'max_internal_redirects'?: (_google_protobuf_UInt32Value | null); /** * Indicates that during forwarding, portions of the path that match the * pattern should be rewritten, even allowing the substitution of capture @@ -791,7 +791,7 @@ export interface RouteAction { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); + 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute | null); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take @@ -799,14 +799,14 @@ export interface RouteAction { * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ - 'retry_policy_typed_config'?: (_google_protobuf_Any); + 'retry_policy_typed_config'?: (_google_protobuf_Any | null); /** * If present, Envoy will try to follow an upstream redirect response instead of proxying the * response back to the downstream. An upstream redirect response is defined * by :ref:`redirect_response_codes * `. */ - 'internal_redirect_policy'?: (_envoy_config_route_v3_InternalRedirectPolicy); + 'internal_redirect_policy'?: (_envoy_config_route_v3_InternalRedirectPolicy | null); /** * Indicates that during forwarding, the host header will be swapped with * the result of the regex substitution executed on path value with query and fragment removed. @@ -824,11 +824,11 @@ export interface RouteAction { * * Would rewrite the host header to `envoyproxy.io` given the path `/envoyproxy.io/some/path`. */ - 'host_rewrite_path_regex'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute); + 'host_rewrite_path_regex'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute | null); /** * Specifies the maximum stream duration for this route. */ - 'max_stream_duration'?: (_envoy_config_route_v3_RouteAction_MaxStreamDuration); + 'max_stream_duration'?: (_envoy_config_route_v3_RouteAction_MaxStreamDuration | null); 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier'?: "host_rewrite_literal"|"auto_host_rewrite"|"host_rewrite_header"|"host_rewrite_path_regex"; } @@ -865,7 +865,7 @@ export interface RouteAction__Output { * :ref:`traffic splitting ` * for additional documentation. */ - 'weighted_clusters'?: (_envoy_config_route_v3_WeightedCluster__Output); + 'weighted_clusters'?: (_envoy_config_route_v3_WeightedCluster__Output | null); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints * in the upstream cluster with metadata matching what's set in this field will be considered @@ -873,7 +873,7 @@ export interface RouteAction__Output { * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata_match': (_envoy_config_core_v3_Metadata__Output | null); /** * Indicates that during forwarding, the matched prefix (or path) should be * swapped with this value. This option allows application URLs to be rooted @@ -920,7 +920,7 @@ export interface RouteAction__Output { * type *strict_dns* or *logical_dns*. Setting this to true with other cluster * types has no effect. */ - 'auto_host_rewrite'?: (_google_protobuf_BoolValue__Output); + 'auto_host_rewrite'?: (_google_protobuf_BoolValue__Output | null); /** * Specifies the upstream timeout for the route. If not specified, the default is 15s. This * spans between the point at which the entire downstream request (i.e. end-of-stream) has been @@ -934,13 +934,13 @@ export interface RouteAction__Output { * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the * :ref:`retry overview `. */ - 'timeout'?: (_google_protobuf_Duration__Output); + 'timeout': (_google_protobuf_Duration__Output | null); /** * Indicates that the route has a retry policy. Note that if this is set, * it'll take precedence over the virtual host level retry policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy__Output); + 'retry_policy': (_envoy_config_route_v3_RetryPolicy__Output | null); /** * Optionally specifies the :ref:`routing priority `. */ @@ -958,7 +958,7 @@ export interface RouteAction__Output { * * This field is deprecated. Please use :ref:`vh_rate_limits ` */ - 'include_vh_rate_limits'?: (_google_protobuf_BoolValue__Output); + 'include_vh_rate_limits': (_google_protobuf_BoolValue__Output | null); /** * Specifies a list of hash policies to use for ring hash load balancing. Each * hash policy is evaluated individually and the combined result is used to @@ -977,7 +977,7 @@ export interface RouteAction__Output { /** * Indicates that the route has a CORS policy. */ - 'cors'?: (_envoy_config_route_v3_CorsPolicy__Output); + 'cors': (_envoy_config_route_v3_CorsPolicy__Output | null); /** * The HTTP status code to use when configured cluster is not found. * The default response code is 503 Service Unavailable. @@ -1005,7 +1005,7 @@ export interface RouteAction__Output { * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms`, and the * :ref:`retry overview `. */ - 'max_grpc_timeout'?: (_google_protobuf_Duration__Output); + 'max_grpc_timeout': (_google_protobuf_Duration__Output | null); /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout @@ -1030,7 +1030,7 @@ export interface RouteAction__Output { * is configured, this timeout is scaled according to the value for * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. */ - 'idle_timeout'?: (_google_protobuf_Duration__Output); + 'idle_timeout': (_google_protobuf_Duration__Output | null); 'upgrade_configs': (_envoy_config_route_v3_RouteAction_UpgradeConfig__Output)[]; 'internal_redirect_action': (keyof typeof _envoy_config_route_v3_RouteAction_InternalRedirectAction); /** @@ -1038,7 +1038,7 @@ export interface RouteAction__Output { * it'll take precedence over the virtual host level hedge policy entirely * (e.g.: policies are not merged, most internal one becomes the enforced policy). */ - 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy__Output); + 'hedge_policy': (_envoy_config_route_v3_HedgePolicy__Output | null); /** * Deprecated by :ref:`grpc_timeout_header_offset `. * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting @@ -1049,7 +1049,7 @@ export interface RouteAction__Output { * ensures that the offset will only ever decrease the timeout and never set it to 0 (meaning * infinity). */ - 'grpc_timeout_offset'?: (_google_protobuf_Duration__Output); + 'grpc_timeout_offset': (_google_protobuf_Duration__Output | null); /** * Indicates that during forwarding, the host header will be swapped with the content of given * downstream or :ref:`custom ` header. @@ -1085,7 +1085,7 @@ export interface RouteAction__Output { * * If not specified, at most one redirect will be followed. */ - 'max_internal_redirects'?: (_google_protobuf_UInt32Value__Output); + 'max_internal_redirects': (_google_protobuf_UInt32Value__Output | null); /** * Indicates that during forwarding, portions of the path that match the * pattern should be rewritten, even allowing the substitution of capture @@ -1116,7 +1116,7 @@ export interface RouteAction__Output { * would do a case-insensitive match and transform path ``/aaa/XxX/bbb`` to * ``/aaa/yyy/bbb``. */ - 'regex_rewrite'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); + 'regex_rewrite': (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output | null); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take @@ -1124,14 +1124,14 @@ export interface RouteAction__Output { * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ - 'retry_policy_typed_config'?: (_google_protobuf_Any__Output); + 'retry_policy_typed_config': (_google_protobuf_Any__Output | null); /** * If present, Envoy will try to follow an upstream redirect response instead of proxying the * response back to the downstream. An upstream redirect response is defined * by :ref:`redirect_response_codes * `. */ - 'internal_redirect_policy'?: (_envoy_config_route_v3_InternalRedirectPolicy__Output); + 'internal_redirect_policy': (_envoy_config_route_v3_InternalRedirectPolicy__Output | null); /** * Indicates that during forwarding, the host header will be swapped with * the result of the regex substitution executed on path value with query and fragment removed. @@ -1149,11 +1149,11 @@ export interface RouteAction__Output { * * Would rewrite the host header to `envoyproxy.io` given the path `/envoyproxy.io/some/path`. */ - 'host_rewrite_path_regex'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output); + 'host_rewrite_path_regex'?: (_envoy_type_matcher_v3_RegexMatchAndSubstitute__Output | null); /** * Specifies the maximum stream duration for this route. */ - 'max_stream_duration'?: (_envoy_config_route_v3_RouteAction_MaxStreamDuration__Output); + 'max_stream_duration': (_envoy_config_route_v3_RouteAction_MaxStreamDuration__Output | null); 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; 'host_rewrite_specifier': "host_rewrite_literal"|"auto_host_rewrite"|"host_rewrite_header"|"host_rewrite_path_regex"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts index e9ad30257..ebb3c3419 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts @@ -66,7 +66,7 @@ export interface RouteConfiguration { * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ - 'validate_clusters'?: (_google_protobuf_BoolValue); + 'validate_clusters'?: (_google_protobuf_BoolValue | null); /** * Specifies a list of HTTP headers that should be removed from each request * routed by the HTTP connection manager. @@ -80,7 +80,7 @@ export interface RouteConfiguration { * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration * taking precedence. */ - 'vhds'?: (_envoy_config_route_v3_Vhds); + 'vhds'?: (_envoy_config_route_v3_Vhds | null); /** * By default, headers that should be added/removed are evaluated from most to least specific: * @@ -106,7 +106,7 @@ export interface RouteConfiguration { * this to be larger than the default 4KB, since the allocated memory for direct response body * is not subject to data plane buffering controls. */ - 'max_direct_response_body_size_bytes'?: (_google_protobuf_UInt32Value); + 'max_direct_response_body_size_bytes'?: (_google_protobuf_UInt32Value | null); } /** @@ -169,7 +169,7 @@ export interface RouteConfiguration__Output { * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ - 'validate_clusters'?: (_google_protobuf_BoolValue__Output); + 'validate_clusters': (_google_protobuf_BoolValue__Output | null); /** * Specifies a list of HTTP headers that should be removed from each request * routed by the HTTP connection manager. @@ -183,7 +183,7 @@ export interface RouteConfiguration__Output { * generate a routing table for a given RouteConfiguration, with *vhds* derived configuration * taking precedence. */ - 'vhds'?: (_envoy_config_route_v3_Vhds__Output); + 'vhds': (_envoy_config_route_v3_Vhds__Output | null); /** * By default, headers that should be added/removed are evaluated from most to least specific: * @@ -209,5 +209,5 @@ export interface RouteConfiguration__Output { * this to be larger than the default 4KB, since the allocated memory for direct response body * is not subject to data plane buffering controls. */ - 'max_direct_response_body_size_bytes'?: (_google_protobuf_UInt32Value__Output); + 'max_direct_response_body_size_bytes': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts index d941bcfd1..ddf44da2f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts @@ -29,12 +29,12 @@ export interface _envoy_config_route_v3_RouteMatch_TlsContextMatchOptions { * If specified, the route will match against whether or not a certificate is presented. * If not specified, certificate presentation status (true or false) will not be considered when route matching. */ - 'presented'?: (_google_protobuf_BoolValue); + 'presented'?: (_google_protobuf_BoolValue | null); /** * If specified, the route will match against whether or not a certificate is validated. * If not specified, certificate validation status (true or false) will not be considered when route matching. */ - 'validated'?: (_google_protobuf_BoolValue); + 'validated'?: (_google_protobuf_BoolValue | null); } export interface _envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Output { @@ -42,12 +42,12 @@ export interface _envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Outpu * If specified, the route will match against whether or not a certificate is presented. * If not specified, certificate presentation status (true or false) will not be considered when route matching. */ - 'presented'?: (_google_protobuf_BoolValue__Output); + 'presented': (_google_protobuf_BoolValue__Output | null); /** * If specified, the route will match against whether or not a certificate is validated. * If not specified, certificate validation status (true or false) will not be considered when route matching. */ - 'validated'?: (_google_protobuf_BoolValue__Output); + 'validated': (_google_protobuf_BoolValue__Output | null); } /** @@ -68,7 +68,7 @@ export interface RouteMatch { * Indicates that prefix/path matching should be case sensitive. The default * is true. */ - 'case_sensitive'?: (_google_protobuf_BoolValue); + 'case_sensitive'?: (_google_protobuf_BoolValue | null); /** * Specifies a set of headers that the route should match on. The router will * check the request’s headers against all the specified headers in the route @@ -90,7 +90,7 @@ export interface RouteMatch { * that the content-type header has a application/grpc or one of the various * application/grpc+ values. */ - 'grpc'?: (_envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions); + 'grpc'?: (_envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions | null); /** * Indicates that the route should additionally match on a runtime key. Every time the route * is considered for a match, it must also fall under the percentage of matches indicated by @@ -109,7 +109,7 @@ export interface RouteMatch { * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. */ - 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent); + 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent | null); /** * If specified, the route is a regular expression rule meaning that the * regex must match the *:path* header once the query string is removed. The entire path @@ -124,14 +124,14 @@ export interface RouteMatch { * on :path, etc. The issue with that is it is unclear how to generically deal with query string * stripping. This needs more thought.] */ - 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher | null); /** * If specified, the client tls context will be matched against the defined * match options. * * [#next-major-version: unify with RBAC] */ - 'tls_context'?: (_envoy_config_route_v3_RouteMatch_TlsContextMatchOptions); + 'tls_context'?: (_envoy_config_route_v3_RouteMatch_TlsContextMatchOptions | null); /** * If this is used as the matcher, the matcher will only match CONNECT requests. * Note that this will not match HTTP/2 upgrade-style CONNECT requests @@ -143,7 +143,7 @@ export interface RouteMatch { * Note that CONNECT support is currently considered alpha in Envoy. * [#comment:TODO(htuch): Replace the above comment with an alpha tag. */ - 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher); + 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher | null); 'path_specifier'?: "prefix"|"path"|"safe_regex"|"connect_matcher"; } @@ -165,7 +165,7 @@ export interface RouteMatch__Output { * Indicates that prefix/path matching should be case sensitive. The default * is true. */ - 'case_sensitive'?: (_google_protobuf_BoolValue__Output); + 'case_sensitive': (_google_protobuf_BoolValue__Output | null); /** * Specifies a set of headers that the route should match on. The router will * check the request’s headers against all the specified headers in the route @@ -187,7 +187,7 @@ export interface RouteMatch__Output { * that the content-type header has a application/grpc or one of the various * application/grpc+ values. */ - 'grpc'?: (_envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions__Output); + 'grpc': (_envoy_config_route_v3_RouteMatch_GrpcRouteMatchOptions__Output | null); /** * Indicates that the route should additionally match on a runtime key. Every time the route * is considered for a match, it must also fall under the percentage of matches indicated by @@ -206,7 +206,7 @@ export interface RouteMatch__Output { * instance, a runtime key lookup returning the value "42" would parse as a FractionalPercent * whose numerator is 42 and denominator is HUNDRED. This preserves legacy semantics. */ - 'runtime_fraction'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output); + 'runtime_fraction': (_envoy_config_core_v3_RuntimeFractionalPercent__Output | null); /** * If specified, the route is a regular expression rule meaning that the * regex must match the *:path* header once the query string is removed. The entire path @@ -221,14 +221,14 @@ export interface RouteMatch__Output { * on :path, etc. The issue with that is it is unclear how to generically deal with query string * stripping. This needs more thought.] */ - 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output | null); /** * If specified, the client tls context will be matched against the defined * match options. * * [#next-major-version: unify with RBAC] */ - 'tls_context'?: (_envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Output); + 'tls_context': (_envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Output | null); /** * If this is used as the matcher, the matcher will only match CONNECT requests. * Note that this will not match HTTP/2 upgrade-style CONNECT requests @@ -240,6 +240,6 @@ export interface RouteMatch__Output { * Note that CONNECT support is currently considered alpha in Envoy. * [#comment:TODO(htuch): Replace the above comment with an alpha tag. */ - 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher__Output); + 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher__Output | null); 'path_specifier': "prefix"|"path"|"safe_regex"|"connect_matcher"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts index afbb9886b..74b5fe43d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts @@ -123,7 +123,7 @@ export interface ScopedRouteConfiguration { /** * The key to match against. */ - 'key'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key); + 'key'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key | null); /** * Whether the RouteConfiguration should be loaded on demand. */ @@ -204,7 +204,7 @@ export interface ScopedRouteConfiguration__Output { /** * The key to match against. */ - 'key'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key__Output); + 'key': (_envoy_config_route_v3_ScopedRouteConfiguration_Key__Output | null); /** * Whether the RouteConfiguration should be loaded on demand. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts index 5be619a5f..e1a9220d7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts @@ -12,7 +12,7 @@ export interface Tracing { * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_v3_FractionalPercent); + 'client_sampling'?: (_envoy_type_v3_FractionalPercent | null); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -20,7 +20,7 @@ export interface Tracing { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_v3_FractionalPercent); + 'random_sampling'?: (_envoy_type_v3_FractionalPercent | null); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -31,7 +31,7 @@ export interface Tracing { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_v3_FractionalPercent); + 'overall_sampling'?: (_envoy_type_v3_FractionalPercent | null); /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration @@ -52,7 +52,7 @@ export interface Tracing__Output { * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_v3_FractionalPercent__Output); + 'client_sampling': (_envoy_type_v3_FractionalPercent__Output | null); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -60,7 +60,7 @@ export interface Tracing__Output { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_v3_FractionalPercent__Output); + 'random_sampling': (_envoy_type_v3_FractionalPercent__Output | null); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -71,7 +71,7 @@ export interface Tracing__Output { * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_v3_FractionalPercent__Output); + 'overall_sampling': (_envoy_type_v3_FractionalPercent__Output | null); /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts index 2868685b2..b8a37be65 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Vhds.ts @@ -6,12 +6,12 @@ export interface Vhds { /** * Configuration source specifier for VHDS. */ - 'config_source'?: (_envoy_config_core_v3_ConfigSource); + 'config_source'?: (_envoy_config_core_v3_ConfigSource | null); } export interface Vhds__Output { /** * Configuration source specifier for VHDS. */ - 'config_source'?: (_envoy_config_core_v3_ConfigSource__Output); + 'config_source': (_envoy_config_core_v3_ConfigSource__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts index 86088ded6..1d3fb2309 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts @@ -96,7 +96,7 @@ export interface VirtualHost { /** * Indicates that the virtual host has a CORS policy. */ - 'cors'?: (_envoy_config_route_v3_CorsPolicy); + 'cors'?: (_envoy_config_route_v3_CorsPolicy | null); /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied @@ -145,19 +145,19 @@ export interface VirtualHost { * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy); + 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy | null); /** * Indicates the hedge policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy); + 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy | null); /** * The maximum bytes which will be buffered for retries and shadowing. * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum * value of this and the listener per_connection_buffer_limit_bytes. */ - 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value); + 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value | null); /** * Decides whether the :ref:`x-envoy-attempt-count * ` header should be included @@ -176,7 +176,7 @@ export interface VirtualHost { * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ - 'retry_policy_typed_config'?: (_google_protobuf_Any); + 'retry_policy_typed_config'?: (_google_protobuf_Any | null); } /** @@ -246,7 +246,7 @@ export interface VirtualHost__Output { /** * Indicates that the virtual host has a CORS policy. */ - 'cors'?: (_envoy_config_route_v3_CorsPolicy__Output); + 'cors': (_envoy_config_route_v3_CorsPolicy__Output | null); /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied @@ -289,25 +289,25 @@ export interface VirtualHost__Output { * :ref:`FilterConfig` * message to specify additional options.] */ - 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); + 'typed_per_filter_config': ({[key: string]: _google_protobuf_Any__Output}); /** * Indicates the retry policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'retry_policy'?: (_envoy_config_route_v3_RetryPolicy__Output); + 'retry_policy': (_envoy_config_route_v3_RetryPolicy__Output | null); /** * Indicates the hedge policy for all routes in this virtual host. Note that setting a * route level entry will take precedence over this config and it'll be treated * independently (e.g.: values are not inherited). */ - 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy__Output); + 'hedge_policy': (_envoy_config_route_v3_HedgePolicy__Output | null); /** * The maximum bytes which will be buffered for retries and shadowing. * If set and a route-specific limit is not set, the bytes actually buffered will be the minimum * value of this and the listener per_connection_buffer_limit_bytes. */ - 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value__Output); + 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output | null); /** * Decides whether the :ref:`x-envoy-attempt-count * ` header should be included @@ -326,5 +326,5 @@ export interface VirtualHost__Output { * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ - 'retry_policy_typed_config'?: (_google_protobuf_Any__Output); + 'retry_policy_typed_config': (_google_protobuf_Any__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts index 7974508ea..02edc0243 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts @@ -20,7 +20,7 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight { * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ - 'weight'?: (_google_protobuf_UInt32Value); + 'weight'?: (_google_protobuf_UInt32Value | null); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for @@ -28,7 +28,7 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight { * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_config_core_v3_Metadata); + 'metadata_match'?: (_envoy_config_core_v3_Metadata | null); /** * Specifies a list of headers to be added to requests when this cluster is selected * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. @@ -87,7 +87,7 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ - 'weight'?: (_google_protobuf_UInt32Value__Output); + 'weight': (_google_protobuf_UInt32Value__Output | null); /** * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for @@ -95,7 +95,7 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ - 'metadata_match'?: (_envoy_config_core_v3_Metadata__Output); + 'metadata_match': (_envoy_config_core_v3_Metadata__Output | null); /** * Specifies a list of headers to be added to requests when this cluster is selected * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. @@ -136,7 +136,7 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { * :ref:`FilterConfig` * message to specify additional options.] */ - 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any__Output}); + 'typed_per_filter_config': ({[key: string]: _google_protobuf_Any__Output}); } /** @@ -167,7 +167,7 @@ export interface WeightedCluster { * Specifies the total weight across all clusters. The sum of all cluster weights must equal this * value, which must be greater than 0. Defaults to 100. */ - 'total_weight'?: (_google_protobuf_UInt32Value); + 'total_weight'?: (_google_protobuf_UInt32Value | null); } /** @@ -198,5 +198,5 @@ export interface WeightedCluster__Output { * Specifies the total weight across all clusters. The sum of all cluster weights must equal this * value, which must be greater than 0. Defaults to 100. */ - 'total_weight'?: (_google_protobuf_UInt32Value__Output); + 'total_weight': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts index 36dfade51..95b161939 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts @@ -23,7 +23,7 @@ export interface _envoy_config_trace_v3_Tracing_Http { * - *envoy.tracers.xray* */ 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Trace driver specific configuration which depends on the driver being instantiated. * See the trace drivers for examples: @@ -59,7 +59,7 @@ export interface _envoy_config_trace_v3_Tracing_Http__Output { * - *envoy.tracers.xray* */ 'name': (string); - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Trace driver specific configuration which depends on the driver being instantiated. * See the trace drivers for examples: @@ -89,7 +89,7 @@ export interface Tracing { /** * Provides configuration for the HTTP tracer. */ - 'http'?: (_envoy_config_trace_v3_Tracing_Http); + 'http'?: (_envoy_config_trace_v3_Tracing_Http | null); } /** @@ -107,5 +107,5 @@ export interface Tracing__Output { /** * Provides configuration for the HTTP tracer. */ - 'http'?: (_envoy_config_trace_v3_Tracing_Http__Output); + 'http': (_envoy_config_trace_v3_Tracing_Http__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts index b68e812ef..4a8912599 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts @@ -132,7 +132,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht /** * Whether to forward the subject of the client cert. Defaults to false. */ - 'subject'?: (_google_protobuf_BoolValue); + 'subject'?: (_google_protobuf_BoolValue | null); /** * Whether to forward the entire client cert in URL encoded PEM format. This will appear in the * XFCC header comma separated from other values with the value Cert="PEM". @@ -165,7 +165,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht /** * Whether to forward the subject of the client cert. Defaults to false. */ - 'subject'?: (_google_protobuf_BoolValue__Output); + 'subject': (_google_protobuf_BoolValue__Output | null); /** * Whether to forward the entire client cert in URL encoded PEM format. This will appear in the * XFCC header comma separated from other values with the value Cert="PEM". @@ -203,7 +203,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_v3_Percent); + 'client_sampling'?: (_envoy_type_v3_Percent | null); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -211,7 +211,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_v3_Percent); + 'random_sampling'?: (_envoy_type_v3_Percent | null); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -222,7 +222,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_v3_Percent); + 'overall_sampling'?: (_envoy_type_v3_Percent | null); /** * Whether to annotate spans with additional data. If true, spans will include logs for stream * events. @@ -233,7 +233,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * truncate lengthy request paths to meet the needs of a tracing backend. * Default: 256 */ - 'max_path_tag_length'?: (_google_protobuf_UInt32Value); + 'max_path_tag_length'?: (_google_protobuf_UInt32Value | null); /** * A list of custom tags with unique tag name to create tags for the active span. */ @@ -250,7 +250,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes * on OpenCensus side. */ - 'provider'?: (_envoy_config_trace_v3_Tracing_Http); + 'provider'?: (_envoy_config_trace_v3_Tracing_Http | null); } /** @@ -265,7 +265,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * `. * Default: 100% */ - 'client_sampling'?: (_envoy_type_v3_Percent__Output); + 'client_sampling': (_envoy_type_v3_Percent__Output | null); /** * Target percentage of requests managed by this HTTP connection manager that will be randomly * selected for trace generation, if not requested by the client or not forced. This field is @@ -273,7 +273,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'random_sampling'?: (_envoy_type_v3_Percent__Output); + 'random_sampling': (_envoy_type_v3_Percent__Output | null); /** * Target percentage of requests managed by this HTTP connection manager that will be traced * after all other sampling checks have been applied (client-directed, force tracing, random @@ -284,7 +284,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * :ref:`HTTP Connection Manager `. * Default: 100% */ - 'overall_sampling'?: (_envoy_type_v3_Percent__Output); + 'overall_sampling': (_envoy_type_v3_Percent__Output | null); /** * Whether to annotate spans with additional data. If true, spans will include logs for stream * events. @@ -295,7 +295,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * truncate lengthy request paths to meet the needs of a tracing backend. * Default: 256 */ - 'max_path_tag_length'?: (_google_protobuf_UInt32Value__Output); + 'max_path_tag_length': (_google_protobuf_UInt32Value__Output | null); /** * A list of custom tags with unique tag name to create tags for the active span. */ @@ -312,7 +312,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * Such a constraint is inherent to OpenCensus itself. It cannot be overcome without changes * on OpenCensus side. */ - 'provider'?: (_envoy_config_trace_v3_Tracing_Http__Output); + 'provider': (_envoy_config_trace_v3_Tracing_Http__Output | null); } /** @@ -349,7 +349,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * ` as documented in the * :ref:`upgrade documentation `. */ - 'enabled'?: (_google_protobuf_BoolValue); + 'enabled'?: (_google_protobuf_BoolValue | null); } /** @@ -386,7 +386,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht * ` as documented in the * :ref:`upgrade documentation `. */ - 'enabled'?: (_google_protobuf_BoolValue__Output); + 'enabled': (_google_protobuf_BoolValue__Output | null); } /** @@ -406,11 +406,11 @@ export interface HttpConnectionManager { /** * The connection manager’s route table will be dynamically loaded via the RDS API. */ - 'rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_Rds); + 'rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_Rds | null); /** * The route table for the connection manager is static and is specified in this property. */ - 'route_config'?: (_envoy_config_route_v3_RouteConfiguration); + 'route_config'?: (_envoy_config_route_v3_RouteConfiguration | null); /** * A list of individual HTTP filters that make up the filter chain for * requests made to the connection manager. :ref:`Order matters ` @@ -422,21 +422,21 @@ export interface HttpConnectionManager { * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked * documentation for more information. Defaults to false. */ - 'add_user_agent'?: (_google_protobuf_BoolValue); + 'add_user_agent'?: (_google_protobuf_BoolValue | null); /** * Presence of the object defines whether the connection manager * emits :ref:`tracing ` data to the :ref:`configured tracing provider * `. */ - 'tracing'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing); + 'tracing'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing | null); /** * Additional HTTP/1 settings that are passed to the HTTP/1 codec. */ - 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions); + 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions | null); /** * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. */ - 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions); + 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions | null); /** * An optional override that the connection manager will write to the server * header in responses. If not set, the default is *envoy*. @@ -453,7 +453,7 @@ export interface HttpConnectionManager { * draining. The default grace period is 5000 milliseconds (5 seconds) if this * option is not specified. */ - 'drain_timeout'?: (_google_protobuf_Duration); + 'drain_timeout'?: (_google_protobuf_Duration | null); /** * Configuration for :ref:`HTTP access logs ` * emitted by the connection manager. @@ -468,14 +468,14 @@ export interface HttpConnectionManager { * :ref:`config_http_conn_man_headers_x-envoy-internal`, and * :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. */ - 'use_remote_address'?: (_google_protobuf_BoolValue); + 'use_remote_address'?: (_google_protobuf_BoolValue | null); /** * Whether the connection manager will generate the :ref:`x-request-id * ` header if it does not exist. This defaults to * true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature * is not desired it can be disabled. */ - 'generate_request_id'?: (_google_protobuf_BoolValue); + 'generate_request_id'?: (_google_protobuf_BoolValue | null); /** * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP * header. @@ -490,7 +490,7 @@ export interface HttpConnectionManager { * *By* is always set when the client certificate presents the URI type Subject Alternative Name * value. */ - 'set_current_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails); + 'set_current_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails | null); /** * If proxy_100_continue is true, Envoy will proxy incoming "Expect: * 100-continue" headers upstream, and forward "100 Continue" responses @@ -580,14 +580,14 @@ export interface HttpConnectionManager { * A value of 0 will completely disable the connection manager stream idle * timeout, although per-route idle timeout overrides will continue to apply. */ - 'stream_idle_timeout'?: (_google_protobuf_Duration); + 'stream_idle_timeout'?: (_google_protobuf_Duration | null); /** * Configures what network addresses are considered internal for stats and header sanitation * purposes. If unspecified, only RFC1918 IP addresses will be considered internal. * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more * information about internal/external addresses. */ - 'internal_address_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig); + 'internal_address_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig | null); /** * The delayed close timeout is for downstream connections managed by the HTTP connection manager. * It is defined as a grace period after connection close processing has been locally initiated @@ -620,14 +620,14 @@ export interface HttpConnectionManager { * connection's socket will be closed immediately after the write flush is completed or will * never close if the write flush does not complete. */ - 'delayed_close_timeout'?: (_google_protobuf_Duration); + 'delayed_close_timeout'?: (_google_protobuf_Duration | null); /** * The amount of time that Envoy will wait for the entire request to be received. * The timer is activated when the request is initiated, and is disarmed when the last byte of the * request is sent upstream (i.e. all decoding filters have processed the request), OR when the * response is initiated. If not specified or set to 0, this timeout is disabled. */ - 'request_timeout'?: (_google_protobuf_Duration); + 'request_timeout'?: (_google_protobuf_Duration | null); /** * The maximum request headers size for incoming connections. * If unconfigured, the default max request headers allowed is 60 KiB. @@ -635,7 +635,7 @@ export interface HttpConnectionManager { * The max configurable limit is 96 KiB, based on current implementation * constraints. */ - 'max_request_headers_kb'?: (_google_protobuf_UInt32Value); + 'max_request_headers_kb'?: (_google_protobuf_UInt32Value | null); /** * Should paths be normalized according to RFC 3986 before any processing of * requests by HTTP filters or routing? This affects the upstream *:path* header @@ -649,13 +649,13 @@ export interface HttpConnectionManager { * Note that Envoy does not perform * `case normalization `_ */ - 'normalize_path'?: (_google_protobuf_BoolValue); + 'normalize_path'?: (_google_protobuf_BoolValue | null); /** * A route table will be dynamically assigned to each request based on request attributes * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are * specified in this message. */ - 'scoped_routes'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes); + 'scoped_routes'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes | null); /** * Whether the connection manager will keep the :ref:`x-request-id * ` header if passed for a request that is edge @@ -681,7 +681,7 @@ export interface HttpConnectionManager { * Additional settings for HTTP requests handled by the connection manager. These will be * applicable to both HTTP1 and HTTP2 requests. */ - 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions); + 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions | null); /** * The configuration of the request ID extension. This includes operations such as * generation, validation, and associated tracing operations. @@ -694,7 +694,7 @@ export interface HttpConnectionManager { * * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. */ - 'request_id_extension'?: (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension); + 'request_id_extension'?: (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension | null); /** * If set, Envoy will always set :ref:`x-request-id ` header in response. * If this is false or not set, the request ID is returned in responses only if tracing is forced using @@ -706,7 +706,7 @@ export interface HttpConnectionManager { * body text and response content type. If not specified, status code and text body are hard * coded in Envoy, the response content type is plain text. */ - 'local_reply_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig); + 'local_reply_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig | null); /** * Determines if the port part should be removed from host/authority header before any processing * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` @@ -735,13 +735,13 @@ export interface HttpConnectionManager { * *not* the deprecated but similarly named :ref:`stream_error_on_invalid_http_messaging * ` */ - 'stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue); + 'stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue | null); /** * The amount of time that Envoy will wait for the request headers to be received. The timer is * activated when the first byte of the headers is received, and is disarmed when the last byte of * the headers has been received. If not specified or set to 0, this timeout is disabled. */ - 'request_headers_timeout'?: (_google_protobuf_Duration); + 'request_headers_timeout'?: (_google_protobuf_Duration | null); /** * Determines if the port part should be removed from host/authority header before any processing * of request by HTTP filters or routing. The port would be removed only if request method is not CONNECT. @@ -773,11 +773,11 @@ export interface HttpConnectionManager__Output { /** * The connection manager’s route table will be dynamically loaded via the RDS API. */ - 'rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_Rds__Output); + 'rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_Rds__Output | null); /** * The route table for the connection manager is static and is specified in this property. */ - 'route_config'?: (_envoy_config_route_v3_RouteConfiguration__Output); + 'route_config'?: (_envoy_config_route_v3_RouteConfiguration__Output | null); /** * A list of individual HTTP filters that make up the filter chain for * requests made to the connection manager. :ref:`Order matters ` @@ -789,21 +789,21 @@ export interface HttpConnectionManager__Output { * and :ref:`config_http_conn_man_headers_downstream-service-cluster` headers. See the linked * documentation for more information. Defaults to false. */ - 'add_user_agent'?: (_google_protobuf_BoolValue__Output); + 'add_user_agent': (_google_protobuf_BoolValue__Output | null); /** * Presence of the object defines whether the connection manager * emits :ref:`tracing ` data to the :ref:`configured tracing provider * `. */ - 'tracing'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing__Output); + 'tracing': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing__Output | null); /** * Additional HTTP/1 settings that are passed to the HTTP/1 codec. */ - 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions__Output); + 'http_protocol_options': (_envoy_config_core_v3_Http1ProtocolOptions__Output | null); /** * Additional HTTP/2 settings that are passed directly to the HTTP/2 codec. */ - 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions__Output); + 'http2_protocol_options': (_envoy_config_core_v3_Http2ProtocolOptions__Output | null); /** * An optional override that the connection manager will write to the server * header in responses. If not set, the default is *envoy*. @@ -820,7 +820,7 @@ export interface HttpConnectionManager__Output { * draining. The default grace period is 5000 milliseconds (5 seconds) if this * option is not specified. */ - 'drain_timeout'?: (_google_protobuf_Duration__Output); + 'drain_timeout': (_google_protobuf_Duration__Output | null); /** * Configuration for :ref:`HTTP access logs ` * emitted by the connection manager. @@ -835,14 +835,14 @@ export interface HttpConnectionManager__Output { * :ref:`config_http_conn_man_headers_x-envoy-internal`, and * :ref:`config_http_conn_man_headers_x-envoy-external-address` for more information. */ - 'use_remote_address'?: (_google_protobuf_BoolValue__Output); + 'use_remote_address': (_google_protobuf_BoolValue__Output | null); /** * Whether the connection manager will generate the :ref:`x-request-id * ` header if it does not exist. This defaults to * true. Generating a random UUID4 is expensive so in high throughput scenarios where this feature * is not desired it can be disabled. */ - 'generate_request_id'?: (_google_protobuf_BoolValue__Output); + 'generate_request_id': (_google_protobuf_BoolValue__Output | null); /** * How to handle the :ref:`config_http_conn_man_headers_x-forwarded-client-cert` (XFCC) HTTP * header. @@ -857,7 +857,7 @@ export interface HttpConnectionManager__Output { * *By* is always set when the client certificate presents the URI type Subject Alternative Name * value. */ - 'set_current_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails__Output); + 'set_current_client_cert_details': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_SetCurrentClientCertDetails__Output | null); /** * If proxy_100_continue is true, Envoy will proxy incoming "Expect: * 100-continue" headers upstream, and forward "100 Continue" responses @@ -947,14 +947,14 @@ export interface HttpConnectionManager__Output { * A value of 0 will completely disable the connection manager stream idle * timeout, although per-route idle timeout overrides will continue to apply. */ - 'stream_idle_timeout'?: (_google_protobuf_Duration__Output); + 'stream_idle_timeout': (_google_protobuf_Duration__Output | null); /** * Configures what network addresses are considered internal for stats and header sanitation * purposes. If unspecified, only RFC1918 IP addresses will be considered internal. * See the documentation for :ref:`config_http_conn_man_headers_x-envoy-internal` for more * information about internal/external addresses. */ - 'internal_address_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig__Output); + 'internal_address_config': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_InternalAddressConfig__Output | null); /** * The delayed close timeout is for downstream connections managed by the HTTP connection manager. * It is defined as a grace period after connection close processing has been locally initiated @@ -987,14 +987,14 @@ export interface HttpConnectionManager__Output { * connection's socket will be closed immediately after the write flush is completed or will * never close if the write flush does not complete. */ - 'delayed_close_timeout'?: (_google_protobuf_Duration__Output); + 'delayed_close_timeout': (_google_protobuf_Duration__Output | null); /** * The amount of time that Envoy will wait for the entire request to be received. * The timer is activated when the request is initiated, and is disarmed when the last byte of the * request is sent upstream (i.e. all decoding filters have processed the request), OR when the * response is initiated. If not specified or set to 0, this timeout is disabled. */ - 'request_timeout'?: (_google_protobuf_Duration__Output); + 'request_timeout': (_google_protobuf_Duration__Output | null); /** * The maximum request headers size for incoming connections. * If unconfigured, the default max request headers allowed is 60 KiB. @@ -1002,7 +1002,7 @@ export interface HttpConnectionManager__Output { * The max configurable limit is 96 KiB, based on current implementation * constraints. */ - 'max_request_headers_kb'?: (_google_protobuf_UInt32Value__Output); + 'max_request_headers_kb': (_google_protobuf_UInt32Value__Output | null); /** * Should paths be normalized according to RFC 3986 before any processing of * requests by HTTP filters or routing? This affects the upstream *:path* header @@ -1016,13 +1016,13 @@ export interface HttpConnectionManager__Output { * Note that Envoy does not perform * `case normalization `_ */ - 'normalize_path'?: (_google_protobuf_BoolValue__Output); + 'normalize_path': (_google_protobuf_BoolValue__Output | null); /** * A route table will be dynamically assigned to each request based on request attributes * (e.g., the value of a header). The "routing scopes" (i.e., route tables) and "scope keys" are * specified in this message. */ - 'scoped_routes'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes__Output); + 'scoped_routes'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes__Output | null); /** * Whether the connection manager will keep the :ref:`x-request-id * ` header if passed for a request that is edge @@ -1048,7 +1048,7 @@ export interface HttpConnectionManager__Output { * Additional settings for HTTP requests handled by the connection manager. These will be * applicable to both HTTP1 and HTTP2 requests. */ - 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions__Output); + 'common_http_protocol_options': (_envoy_config_core_v3_HttpProtocolOptions__Output | null); /** * The configuration of the request ID extension. This includes operations such as * generation, validation, and associated tracing operations. @@ -1061,7 +1061,7 @@ export interface HttpConnectionManager__Output { * * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. */ - 'request_id_extension'?: (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension__Output); + 'request_id_extension': (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension__Output | null); /** * If set, Envoy will always set :ref:`x-request-id ` header in response. * If this is false or not set, the request ID is returned in responses only if tracing is forced using @@ -1073,7 +1073,7 @@ export interface HttpConnectionManager__Output { * body text and response content type. If not specified, status code and text body are hard * coded in Envoy, the response content type is plain text. */ - 'local_reply_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig__Output); + 'local_reply_config': (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig__Output | null); /** * Determines if the port part should be removed from host/authority header before any processing * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` @@ -1102,13 +1102,13 @@ export interface HttpConnectionManager__Output { * *not* the deprecated but similarly named :ref:`stream_error_on_invalid_http_messaging * ` */ - 'stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue__Output); + 'stream_error_on_invalid_http_message': (_google_protobuf_BoolValue__Output | null); /** * The amount of time that Envoy will wait for the request headers to be received. The timer is * activated when the first byte of the headers is received, and is disarmed when the last byte of * the headers has been received. If not specified or set to 0, this timeout is disabled. */ - 'request_headers_timeout'?: (_google_protobuf_Duration__Output); + 'request_headers_timeout': (_google_protobuf_Duration__Output | null); /** * Determines if the port part should be removed from host/authority header before any processing * of request by HTTP filters or routing. The port would be removed only if request method is not CONNECT. diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts index 881e2c714..42e4215d0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts @@ -17,13 +17,13 @@ export interface HttpFilter { * Filter specific configuration which depends on the filter being instantiated. See the supported * filters for further documentation. */ - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); /** * Configuration source specifier for an extension configuration discovery service. * In case of a failure and without the default configuration, the HTTP listener responds with code 500. * Extension configs delivered through this mechanism are not expected to require warming (see https://github.com/envoyproxy/envoy/issues/12061). */ - 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource); + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource | null); /** * If true, clients that do not support this filter may ignore the * filter but otherwise accept the config. @@ -48,13 +48,13 @@ export interface HttpFilter__Output { * Filter specific configuration which depends on the filter being instantiated. See the supported * filters for further documentation. */ - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Configuration source specifier for an extension configuration discovery service. * In case of a failure and without the default configuration, the HTTP listener responds with code 500. * Extension configs delivered through this mechanism are not expected to require warming (see https://github.com/envoyproxy/envoy/issues/12061). */ - 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output); + 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output | null); /** * If true, clients that do not support this filter may ignore the * filter but otherwise accept the config. diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts index 10bb6e700..04de11fcb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig.ts @@ -51,7 +51,7 @@ export interface LocalReplyConfig { * "path": "/foo" * } */ - 'body_format'?: (_envoy_config_core_v3_SubstitutionFormatString); + 'body_format'?: (_envoy_config_core_v3_SubstitutionFormatString | null); } /** @@ -102,5 +102,5 @@ export interface LocalReplyConfig__Output { * "path": "/foo" * } */ - 'body_format'?: (_envoy_config_core_v3_SubstitutionFormatString__Output); + 'body_format': (_envoy_config_core_v3_SubstitutionFormatString__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts index 8e06a6d67..b99e2f1bd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/Rds.ts @@ -6,7 +6,7 @@ export interface Rds { /** * Configuration source specifier for RDS. */ - 'config_source'?: (_envoy_config_core_v3_ConfigSource); + 'config_source'?: (_envoy_config_core_v3_ConfigSource | null); /** * The name of the route configuration. This name will be passed to the RDS * API. This allows an Envoy configuration with multiple HTTP listeners (and @@ -20,7 +20,7 @@ export interface Rds__Output { /** * Configuration source specifier for RDS. */ - 'config_source'?: (_envoy_config_core_v3_ConfigSource__Output); + 'config_source': (_envoy_config_core_v3_ConfigSource__Output | null); /** * The name of the route configuration. This name will be passed to the RDS * API. This allows an Envoy configuration with multiple HTTP listeners (and diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts index 24e05ccc3..ba1789a80 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension.ts @@ -6,12 +6,12 @@ export interface RequestIDExtension { /** * Request ID extension specific configuration. */ - 'typed_config'?: (_google_protobuf_Any); + 'typed_config'?: (_google_protobuf_Any | null); } export interface RequestIDExtension__Output { /** * Request ID extension specific configuration. */ - 'typed_config'?: (_google_protobuf_Any__Output); + 'typed_config': (_google_protobuf_Any__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts index 67af3aec4..26d14a07d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ResponseMapper.ts @@ -14,21 +14,21 @@ export interface ResponseMapper { /** * Filter to determine if this mapper should apply. */ - 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter); + 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter | null); /** * The new response status code if specified. */ - 'status_code'?: (_google_protobuf_UInt32Value); + 'status_code'?: (_google_protobuf_UInt32Value | null); /** * The new local reply body text if specified. It will be used in the `%LOCAL_REPLY_BODY%` * command operator in the `body_format`. */ - 'body'?: (_envoy_config_core_v3_DataSource); + 'body'?: (_envoy_config_core_v3_DataSource | null); /** * A per mapper `body_format` to override the :ref:`body_format `. * It will be used when this mapper is matched. */ - 'body_format_override'?: (_envoy_config_core_v3_SubstitutionFormatString); + 'body_format_override'?: (_envoy_config_core_v3_SubstitutionFormatString | null); /** * HTTP headers to add to a local reply. This allows the response mapper to append, to add * or to override headers of any local reply before it is sent to a downstream client. @@ -44,21 +44,21 @@ export interface ResponseMapper__Output { /** * Filter to determine if this mapper should apply. */ - 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter__Output); + 'filter': (_envoy_config_accesslog_v3_AccessLogFilter__Output | null); /** * The new response status code if specified. */ - 'status_code'?: (_google_protobuf_UInt32Value__Output); + 'status_code': (_google_protobuf_UInt32Value__Output | null); /** * The new local reply body text if specified. It will be used in the `%LOCAL_REPLY_BODY%` * command operator in the `body_format`. */ - 'body'?: (_envoy_config_core_v3_DataSource__Output); + 'body': (_envoy_config_core_v3_DataSource__Output | null); /** * A per mapper `body_format` to override the :ref:`body_format `. * It will be used when this mapper is matched. */ - 'body_format_override'?: (_envoy_config_core_v3_SubstitutionFormatString__Output); + 'body_format_override': (_envoy_config_core_v3_SubstitutionFormatString__Output | null); /** * HTTP headers to add to a local reply. This allows the response mapper to append, to add * or to override headers of any local reply before it is sent to a downstream client. diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts index a9995b455..e4565ce80 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts @@ -6,12 +6,12 @@ export interface ScopedRds { /** * Configuration source specifier for scoped RDS. */ - 'scoped_rds_config_source'?: (_envoy_config_core_v3_ConfigSource); + 'scoped_rds_config_source'?: (_envoy_config_core_v3_ConfigSource | null); } export interface ScopedRds__Output { /** * Configuration source specifier for scoped RDS. */ - 'scoped_rds_config_source'?: (_envoy_config_core_v3_ConfigSource__Output); + 'scoped_rds_config_source': (_envoy_config_core_v3_ConfigSource__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts index a19e59b2a..8aecd3883 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts @@ -11,7 +11,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Sc /** * Specifies how a header field's value should be extracted. */ - 'header_value_extractor'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor); + 'header_value_extractor'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor | null); 'type'?: "header_value_extractor"; } @@ -22,7 +22,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Sc /** * Specifies how a header field's value should be extracted. */ - 'header_value_extractor'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output); + 'header_value_extractor'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor__Output | null); 'type': "header_value_extractor"; } @@ -70,7 +70,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Sc /** * Specifies the key value pair to extract the value from. */ - 'element'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement); + 'element'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement | null); 'extract_type'?: "index"|"element"; } @@ -118,7 +118,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Sc /** * Specifies the key value pair to extract the value from. */ - 'element'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output); + 'element'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder_HeaderValueExtractor_KvElement__Output | null); 'extract_type': "index"|"element"; } @@ -209,13 +209,13 @@ export interface ScopedRoutes { /** * The algorithm to use for constructing a scope key for each request. */ - 'scope_key_builder'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder); + 'scope_key_builder'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder | null); /** * Configuration source specifier for RDS. * This config source is used to subscribe to RouteConfiguration resources specified in * ScopedRouteConfiguration messages. */ - 'rds_config_source'?: (_envoy_config_core_v3_ConfigSource); + 'rds_config_source'?: (_envoy_config_core_v3_ConfigSource | null); /** * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by * matching a key constructed from the request's attributes according to the algorithm specified @@ -223,7 +223,7 @@ export interface ScopedRoutes { * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList); + 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList | null); /** * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS * API. A scope is assigned to a request by matching a key constructed from the request's @@ -231,7 +231,7 @@ export interface ScopedRoutes { * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds); + 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds | null); 'config_specifier'?: "scoped_route_configurations_list"|"scoped_rds"; } @@ -246,13 +246,13 @@ export interface ScopedRoutes__Output { /** * The algorithm to use for constructing a scope key for each request. */ - 'scope_key_builder'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder__Output); + 'scope_key_builder': (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder__Output | null); /** * Configuration source specifier for RDS. * This config source is used to subscribe to RouteConfiguration resources specified in * ScopedRouteConfiguration messages. */ - 'rds_config_source'?: (_envoy_config_core_v3_ConfigSource__Output); + 'rds_config_source': (_envoy_config_core_v3_ConfigSource__Output | null); /** * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by * matching a key constructed from the request's attributes according to the algorithm specified @@ -260,7 +260,7 @@ export interface ScopedRoutes__Output { * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList__Output); + 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList__Output | null); /** * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS * API. A scope is assigned to a request by matching a key constructed from the request's @@ -268,6 +268,6 @@ export interface ScopedRoutes__Output { * :ref:`ScopeKeyBuilder` * in this message. */ - 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds__Output); + 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds__Output | null); 'config_specifier': "scoped_route_configurations_list"|"scoped_rds"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts index ec7641dca..6044118bc 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts @@ -1,6 +1,7 @@ // Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' import type { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; import type { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; import type { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; @@ -50,3 +51,8 @@ export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceI StreamAggregatedResources: grpc.handleBidiStreamingCall<_envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse>; } + +export interface AggregatedDiscoveryServiceDefinition extends grpc.ServiceDefinition { + DeltaAggregatedResources: MethodDefinition<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse, _envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse__Output> + StreamAggregatedResources: MethodDefinition<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse, _envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse__Output> +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts index 445057d44..e6498177b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService.ts @@ -1,6 +1,7 @@ // Original file: deps/envoy-api/envoy/service/discovery/v3/ads.proto import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' import type { DeltaDiscoveryRequest as _envoy_service_discovery_v3_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_service_discovery_v3_DeltaDiscoveryRequest__Output } from '../../../../envoy/service/discovery/v3/DeltaDiscoveryRequest'; import type { DeltaDiscoveryResponse as _envoy_service_discovery_v3_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output } from '../../../../envoy/service/discovery/v3/DeltaDiscoveryResponse'; import type { DiscoveryRequest as _envoy_service_discovery_v3_DiscoveryRequest, DiscoveryRequest__Output as _envoy_service_discovery_v3_DiscoveryRequest__Output } from '../../../../envoy/service/discovery/v3/DiscoveryRequest'; @@ -50,3 +51,8 @@ export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceI StreamAggregatedResources: grpc.handleBidiStreamingCall<_envoy_service_discovery_v3_DiscoveryRequest__Output, _envoy_service_discovery_v3_DiscoveryResponse>; } + +export interface AggregatedDiscoveryServiceDefinition extends grpc.ServiceDefinition { + DeltaAggregatedResources: MethodDefinition<_envoy_service_discovery_v3_DeltaDiscoveryRequest, _envoy_service_discovery_v3_DeltaDiscoveryResponse, _envoy_service_discovery_v3_DeltaDiscoveryRequest__Output, _envoy_service_discovery_v3_DeltaDiscoveryResponse__Output> + StreamAggregatedResources: MethodDefinition<_envoy_service_discovery_v3_DiscoveryRequest, _envoy_service_discovery_v3_DiscoveryResponse, _envoy_service_discovery_v3_DiscoveryRequest__Output, _envoy_service_discovery_v3_DiscoveryResponse__Output> +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts index bcf2de4e2..b42470516 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts @@ -42,7 +42,7 @@ export interface DeltaDiscoveryRequest { /** * The node making the request. */ - 'node'?: (_envoy_config_core_v3_Node); + 'node'?: (_envoy_config_core_v3_Node | null); /** * Type of the resource that is being requested, e.g. * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This does not need to be set if @@ -101,7 +101,7 @@ export interface DeltaDiscoveryRequest { * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ - 'error_detail'?: (_google_rpc_Status); + 'error_detail'?: (_google_rpc_Status | null); } /** @@ -143,7 +143,7 @@ export interface DeltaDiscoveryRequest__Output { /** * The node making the request. */ - 'node'?: (_envoy_config_core_v3_Node__Output); + 'node': (_envoy_config_core_v3_Node__Output | null); /** * Type of the resource that is being requested, e.g. * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This does not need to be set if @@ -202,5 +202,5 @@ export interface DeltaDiscoveryRequest__Output { * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ - 'error_detail'?: (_google_rpc_Status__Output); + 'error_detail': (_google_rpc_Status__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts index c22690cd9..efbbed85c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryResponse.ts @@ -35,7 +35,7 @@ export interface DeltaDiscoveryResponse { * [#not-implemented-hide:] * The control plane instance that sent the response. */ - 'control_plane'?: (_envoy_config_core_v3_ControlPlane); + 'control_plane'?: (_envoy_config_core_v3_ControlPlane | null); } /** @@ -70,5 +70,5 @@ export interface DeltaDiscoveryResponse__Output { * [#not-implemented-hide:] * The control plane instance that sent the response. */ - 'control_plane'?: (_envoy_config_core_v3_ControlPlane__Output); + 'control_plane': (_envoy_config_core_v3_ControlPlane__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts index 2b23ee869..b30930b6f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts @@ -22,7 +22,7 @@ export interface DiscoveryRequest { /** * The node making the request. */ - 'node'?: (_envoy_config_core_v3_Node); + 'node'?: (_envoy_config_core_v3_Node | null); /** * List of resources to subscribe to, e.g. list of cluster names or a route * configuration name. If this is empty, all resources for the API are @@ -53,7 +53,7 @@ export interface DiscoveryRequest { * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. */ - 'error_detail'?: (_google_rpc_Status); + 'error_detail'?: (_google_rpc_Status | null); } /** @@ -75,7 +75,7 @@ export interface DiscoveryRequest__Output { /** * The node making the request. */ - 'node'?: (_envoy_config_core_v3_Node__Output); + 'node': (_envoy_config_core_v3_Node__Output | null); /** * List of resources to subscribe to, e.g. list of cluster names or a route * configuration name. If this is empty, all resources for the API are @@ -106,5 +106,5 @@ export interface DiscoveryRequest__Output { * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. */ - 'error_detail'?: (_google_rpc_Status__Output); + 'error_detail': (_google_rpc_Status__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts index f69944b80..874168317 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryResponse.ts @@ -51,7 +51,7 @@ export interface DiscoveryResponse { /** * The control plane instance that sent the response. */ - 'control_plane'?: (_envoy_config_core_v3_ControlPlane); + 'control_plane'?: (_envoy_config_core_v3_ControlPlane | null); } /** @@ -102,5 +102,5 @@ export interface DiscoveryResponse__Output { /** * The control plane instance that sent the response. */ - 'control_plane'?: (_envoy_config_core_v3_ControlPlane__Output); + 'control_plane': (_envoy_config_core_v3_ControlPlane__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts index 27a70c97c..0e5897ab4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/Resource.ts @@ -41,7 +41,7 @@ export interface Resource { /** * The resource being tracked. */ - 'resource'?: (_google_protobuf_Any); + 'resource'?: (_google_protobuf_Any | null); /** * The resource's name, to distinguish it from others of the same type of resource. */ @@ -65,12 +65,12 @@ export interface Resource { * testing where the fault injection should be terminated in the event that Envoy loses contact * with the management server. */ - 'ttl'?: (_google_protobuf_Duration); + 'ttl'?: (_google_protobuf_Duration | null); /** * Cache control properties for the resource. * [#not-implemented-hide:] */ - 'cache_control'?: (_envoy_service_discovery_v3_Resource_CacheControl); + 'cache_control'?: (_envoy_service_discovery_v3_Resource_CacheControl | null); } /** @@ -85,7 +85,7 @@ export interface Resource__Output { /** * The resource being tracked. */ - 'resource'?: (_google_protobuf_Any__Output); + 'resource': (_google_protobuf_Any__Output | null); /** * The resource's name, to distinguish it from others of the same type of resource. */ @@ -109,10 +109,10 @@ export interface Resource__Output { * testing where the fault injection should be terminated in the event that Envoy loses contact * with the management server. */ - 'ttl'?: (_google_protobuf_Duration__Output); + 'ttl': (_google_protobuf_Duration__Output | null); /** * Cache control properties for the resource. * [#not-implemented-hide:] */ - 'cache_control'?: (_envoy_service_discovery_v3_Resource_CacheControl__Output); + 'cache_control': (_envoy_service_discovery_v3_Resource_CacheControl__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts index 41e73f0e9..2a95752de 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts @@ -1,6 +1,7 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' import type { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; import type { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; @@ -106,3 +107,7 @@ export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImpleme StreamLoadStats: grpc.handleBidiStreamingCall<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>; } + +export interface LoadReportingServiceDefinition extends grpc.ServiceDefinition { + StreamLoadStats: MethodDefinition<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse, _envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse__Output> +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts index a7ac6b8e1..3cd5ebc2f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts @@ -11,7 +11,7 @@ export interface LoadStatsRequest { /** * Node identifier for Envoy instance. */ - 'node'?: (_envoy_api_v2_core_Node); + 'node'?: (_envoy_api_v2_core_Node | null); /** * A list of load stats to report. */ @@ -26,7 +26,7 @@ export interface LoadStatsRequest__Output { /** * Node identifier for Envoy instance. */ - 'node'?: (_envoy_api_v2_core_Node__Output); + 'node': (_envoy_api_v2_core_Node__Output | null); /** * A list of load stats to report. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts index afec8f180..1065fe22f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts @@ -22,7 +22,7 @@ export interface LoadStatsResponse { * of inobservability that might otherwise exists between the messages. New clusters are not * subject to this consideration. */ - 'load_reporting_interval'?: (_google_protobuf_Duration); + 'load_reporting_interval'?: (_google_protobuf_Duration | null); /** * Set to *true* if the management server supports endpoint granularity * report. @@ -56,7 +56,7 @@ export interface LoadStatsResponse__Output { * of inobservability that might otherwise exists between the messages. New clusters are not * subject to this consideration. */ - 'load_reporting_interval'?: (_google_protobuf_Duration__Output); + 'load_reporting_interval': (_google_protobuf_Duration__Output | null); /** * Set to *true* if the management server supports endpoint granularity * report. diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts index 24a9de55e..32aa4f96e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadReportingService.ts @@ -1,6 +1,7 @@ // Original file: deps/envoy-api/envoy/service/load_stats/v3/lrs.proto import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' import type { LoadStatsRequest as _envoy_service_load_stats_v3_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v3_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v3/LoadStatsRequest'; import type { LoadStatsResponse as _envoy_service_load_stats_v3_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v3_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v3/LoadStatsResponse'; @@ -106,3 +107,7 @@ export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImpleme StreamLoadStats: grpc.handleBidiStreamingCall<_envoy_service_load_stats_v3_LoadStatsRequest__Output, _envoy_service_load_stats_v3_LoadStatsResponse>; } + +export interface LoadReportingServiceDefinition extends grpc.ServiceDefinition { + StreamLoadStats: MethodDefinition<_envoy_service_load_stats_v3_LoadStatsRequest, _envoy_service_load_stats_v3_LoadStatsResponse, _envoy_service_load_stats_v3_LoadStatsRequest__Output, _envoy_service_load_stats_v3_LoadStatsResponse__Output> +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts index 6f0e19525..e430eb270 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsRequest.ts @@ -10,7 +10,7 @@ export interface LoadStatsRequest { /** * Node identifier for Envoy instance. */ - 'node'?: (_envoy_config_core_v3_Node); + 'node'?: (_envoy_config_core_v3_Node | null); /** * A list of load stats to report. */ @@ -24,7 +24,7 @@ export interface LoadStatsRequest__Output { /** * Node identifier for Envoy instance. */ - 'node'?: (_envoy_config_core_v3_Node__Output); + 'node': (_envoy_config_core_v3_Node__Output | null); /** * A list of load stats to report. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts index 51f017474..c39658cde 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts @@ -22,7 +22,7 @@ export interface LoadStatsResponse { * of inobservability that might otherwise exists between the messages. New clusters are not * subject to this consideration. */ - 'load_reporting_interval'?: (_google_protobuf_Duration); + 'load_reporting_interval'?: (_google_protobuf_Duration | null); /** * Set to *true* if the management server supports endpoint granularity * report. @@ -56,7 +56,7 @@ export interface LoadStatsResponse__Output { * of inobservability that might otherwise exists between the messages. New clusters are not * subject to this consideration. */ - 'load_reporting_interval'?: (_google_protobuf_Duration__Output); + 'load_reporting_interval': (_google_protobuf_Duration__Output | null); /** * Set to *true* if the management server supports endpoint granularity * report. diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts index e91a4898e..0bf3bca79 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/DoubleMatcher.ts @@ -10,7 +10,7 @@ export interface DoubleMatcher { * If specified, the input double value must be in the range specified here. * Note: The range is using half-open interval semantics [start, end). */ - 'range'?: (_envoy_type_v3_DoubleRange); + 'range'?: (_envoy_type_v3_DoubleRange | null); /** * If specified, the input double value must be equal to the value specified here. */ @@ -26,7 +26,7 @@ export interface DoubleMatcher__Output { * If specified, the input double value must be in the range specified here. * Note: The range is using half-open interval semantics [start, end). */ - 'range'?: (_envoy_type_v3_DoubleRange__Output); + 'range'?: (_envoy_type_v3_DoubleRange__Output | null); /** * If specified, the input double value must be equal to the value specified here. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts index c32b72a39..10bf5567c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ListMatcher.ts @@ -9,7 +9,7 @@ export interface ListMatcher { /** * If specified, at least one of the values in the list must match the value specified. */ - 'one_of'?: (_envoy_type_matcher_v3_ValueMatcher); + 'one_of'?: (_envoy_type_matcher_v3_ValueMatcher | null); 'match_pattern'?: "one_of"; } @@ -20,6 +20,6 @@ export interface ListMatcher__Output { /** * If specified, at least one of the values in the list must match the value specified. */ - 'one_of'?: (_envoy_type_matcher_v3_ValueMatcher__Output); + 'one_of'?: (_envoy_type_matcher_v3_ValueMatcher__Output | null); 'match_pattern': "one_of"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts index 8d80408a3..58117faab 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts @@ -43,7 +43,7 @@ export interface MetadataMatcher { /** * The MetadataMatcher is matched if the value retrieved by path is matched to this value. */ - 'value'?: (_envoy_type_matcher_v3_ValueMatcher); + 'value'?: (_envoy_type_matcher_v3_ValueMatcher | null); } /** @@ -61,5 +61,5 @@ export interface MetadataMatcher__Output { /** * The MetadataMatcher is matched if the value retrieved by path is matched to this value. */ - 'value'?: (_envoy_type_matcher_v3_ValueMatcher__Output); + 'value': (_envoy_type_matcher_v3_ValueMatcher__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts index 4abddc655..3796765a7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatchAndSubstitute.ts @@ -18,7 +18,7 @@ export interface RegexMatchAndSubstitute { * used in the pattern to extract portions of the subject string, and then * referenced in the substitution string. */ - 'pattern'?: (_envoy_type_matcher_v3_RegexMatcher); + 'pattern'?: (_envoy_type_matcher_v3_RegexMatcher | null); /** * The string that should be substituted into matching portions of the * subject string during a substitution operation to produce a new string. @@ -49,7 +49,7 @@ export interface RegexMatchAndSubstitute__Output { * used in the pattern to extract portions of the subject string, and then * referenced in the substitution string. */ - 'pattern'?: (_envoy_type_matcher_v3_RegexMatcher__Output); + 'pattern': (_envoy_type_matcher_v3_RegexMatcher__Output | null); /** * The string that should be substituted into matching portions of the * subject string during a substitution operation to produce a new string. diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts index 0e8b37f08..1addb1730 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/RegexMatcher.ts @@ -27,7 +27,7 @@ export interface _envoy_type_matcher_v3_RegexMatcher_GoogleRE2 { * This field is deprecated; regexp validation should be performed on the management server * instead of being done by each individual client. */ - 'max_program_size'?: (_google_protobuf_UInt32Value); + 'max_program_size'?: (_google_protobuf_UInt32Value | null); } /** @@ -55,7 +55,7 @@ export interface _envoy_type_matcher_v3_RegexMatcher_GoogleRE2__Output { * This field is deprecated; regexp validation should be performed on the management server * instead of being done by each individual client. */ - 'max_program_size'?: (_google_protobuf_UInt32Value__Output); + 'max_program_size': (_google_protobuf_UInt32Value__Output | null); } /** @@ -65,7 +65,7 @@ export interface RegexMatcher { /** * Google's RE2 regex engine. */ - 'google_re2'?: (_envoy_type_matcher_v3_RegexMatcher_GoogleRE2); + 'google_re2'?: (_envoy_type_matcher_v3_RegexMatcher_GoogleRE2 | null); /** * The regex match string. The string must be supported by the configured engine. */ @@ -80,7 +80,7 @@ export interface RegexMatcher__Output { /** * Google's RE2 regex engine. */ - 'google_re2'?: (_envoy_type_matcher_v3_RegexMatcher_GoogleRE2__Output); + 'google_re2'?: (_envoy_type_matcher_v3_RegexMatcher_GoogleRE2__Output | null); /** * The regex match string. The string must be supported by the configured engine. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts index 58616dde8..c89190510 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts @@ -36,7 +36,7 @@ export interface StringMatcher { /** * The input string must match the regular expression specified here. */ - 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher | null); /** * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no * effect for the safe_regex match. @@ -89,7 +89,7 @@ export interface StringMatcher__Output { /** * The input string must match the regular expression specified here. */ - 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output); + 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output | null); /** * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no * effect for the safe_regex match. diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts index 6c271162a..d01060446 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/ValueMatcher.ts @@ -25,17 +25,17 @@ export interface ValueMatcher { /** * If specified, a match occurs if and only if the target value is a NullValue. */ - 'null_match'?: (_envoy_type_matcher_v3_ValueMatcher_NullMatch); + 'null_match'?: (_envoy_type_matcher_v3_ValueMatcher_NullMatch | null); /** * If specified, a match occurs if and only if the target value is a double value and is * matched to this field. */ - 'double_match'?: (_envoy_type_matcher_v3_DoubleMatcher); + 'double_match'?: (_envoy_type_matcher_v3_DoubleMatcher | null); /** * If specified, a match occurs if and only if the target value is a string value and is * matched to this field. */ - 'string_match'?: (_envoy_type_matcher_v3_StringMatcher); + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher | null); /** * If specified, a match occurs if and only if the target value is a bool value and is equal * to this field. @@ -51,7 +51,7 @@ export interface ValueMatcher { * If specified, a match occurs if and only if the target value is a list value and * is matched to this field. */ - 'list_match'?: (_envoy_type_matcher_v3_ListMatcher); + 'list_match'?: (_envoy_type_matcher_v3_ListMatcher | null); /** * Specifies how to match a value. */ @@ -67,17 +67,17 @@ export interface ValueMatcher__Output { /** * If specified, a match occurs if and only if the target value is a NullValue. */ - 'null_match'?: (_envoy_type_matcher_v3_ValueMatcher_NullMatch__Output); + 'null_match'?: (_envoy_type_matcher_v3_ValueMatcher_NullMatch__Output | null); /** * If specified, a match occurs if and only if the target value is a double value and is * matched to this field. */ - 'double_match'?: (_envoy_type_matcher_v3_DoubleMatcher__Output); + 'double_match'?: (_envoy_type_matcher_v3_DoubleMatcher__Output | null); /** * If specified, a match occurs if and only if the target value is a string value and is * matched to this field. */ - 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output); + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output | null); /** * If specified, a match occurs if and only if the target value is a bool value and is equal * to this field. @@ -93,7 +93,7 @@ export interface ValueMatcher__Output { * If specified, a match occurs if and only if the target value is a list value and * is matched to this field. */ - 'list_match'?: (_envoy_type_matcher_v3_ListMatcher__Output); + 'list_match'?: (_envoy_type_matcher_v3_ListMatcher__Output | null); /** * Specifies how to match a value. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts index c231ecf98..2457b3f91 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts @@ -58,19 +58,19 @@ export interface MetadataKind { /** * Request kind of metadata. */ - 'request'?: (_envoy_type_metadata_v3_MetadataKind_Request); + 'request'?: (_envoy_type_metadata_v3_MetadataKind_Request | null); /** * Route kind of metadata. */ - 'route'?: (_envoy_type_metadata_v3_MetadataKind_Route); + 'route'?: (_envoy_type_metadata_v3_MetadataKind_Route | null); /** * Cluster kind of metadata. */ - 'cluster'?: (_envoy_type_metadata_v3_MetadataKind_Cluster); + 'cluster'?: (_envoy_type_metadata_v3_MetadataKind_Cluster | null); /** * Host kind of metadata. */ - 'host'?: (_envoy_type_metadata_v3_MetadataKind_Host); + 'host'?: (_envoy_type_metadata_v3_MetadataKind_Host | null); 'kind'?: "request"|"route"|"cluster"|"host"; } @@ -81,18 +81,18 @@ export interface MetadataKind__Output { /** * Request kind of metadata. */ - 'request'?: (_envoy_type_metadata_v3_MetadataKind_Request__Output); + 'request'?: (_envoy_type_metadata_v3_MetadataKind_Request__Output | null); /** * Route kind of metadata. */ - 'route'?: (_envoy_type_metadata_v3_MetadataKind_Route__Output); + 'route'?: (_envoy_type_metadata_v3_MetadataKind_Route__Output | null); /** * Cluster kind of metadata. */ - 'cluster'?: (_envoy_type_metadata_v3_MetadataKind_Cluster__Output); + 'cluster'?: (_envoy_type_metadata_v3_MetadataKind_Cluster__Output | null); /** * Host kind of metadata. */ - 'host'?: (_envoy_type_metadata_v3_MetadataKind_Host__Output); + 'host'?: (_envoy_type_metadata_v3_MetadataKind_Host__Output | null); 'kind': "request"|"route"|"cluster"|"host"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts index ef29c3420..d5fe26ed5 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts @@ -98,11 +98,11 @@ export interface _envoy_type_tracing_v3_CustomTag_Metadata { /** * Specify what kind of metadata to obtain tag value from. */ - 'kind'?: (_envoy_type_metadata_v3_MetadataKind); + 'kind'?: (_envoy_type_metadata_v3_MetadataKind | null); /** * Metadata key to define the path to retrieve the tag value. */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey); + 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey | null); /** * When no valid metadata is found, * the tag value would be populated with this default value if specified, @@ -122,11 +122,11 @@ export interface _envoy_type_tracing_v3_CustomTag_Metadata__Output { /** * Specify what kind of metadata to obtain tag value from. */ - 'kind'?: (_envoy_type_metadata_v3_MetadataKind__Output); + 'kind': (_envoy_type_metadata_v3_MetadataKind__Output | null); /** * Metadata key to define the path to retrieve the tag value. */ - 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey__Output); + 'metadata_key': (_envoy_type_metadata_v3_MetadataKey__Output | null); /** * When no valid metadata is found, * the tag value would be populated with this default value if specified, @@ -147,19 +147,19 @@ export interface CustomTag { /** * A literal custom tag. */ - 'literal'?: (_envoy_type_tracing_v3_CustomTag_Literal); + 'literal'?: (_envoy_type_tracing_v3_CustomTag_Literal | null); /** * An environment custom tag. */ - 'environment'?: (_envoy_type_tracing_v3_CustomTag_Environment); + 'environment'?: (_envoy_type_tracing_v3_CustomTag_Environment | null); /** * A request header custom tag. */ - 'request_header'?: (_envoy_type_tracing_v3_CustomTag_Header); + 'request_header'?: (_envoy_type_tracing_v3_CustomTag_Header | null); /** * A custom tag to obtain tag value from the metadata. */ - 'metadata'?: (_envoy_type_tracing_v3_CustomTag_Metadata); + 'metadata'?: (_envoy_type_tracing_v3_CustomTag_Metadata | null); /** * Used to specify what kind of custom tag. */ @@ -178,19 +178,19 @@ export interface CustomTag__Output { /** * A literal custom tag. */ - 'literal'?: (_envoy_type_tracing_v3_CustomTag_Literal__Output); + 'literal'?: (_envoy_type_tracing_v3_CustomTag_Literal__Output | null); /** * An environment custom tag. */ - 'environment'?: (_envoy_type_tracing_v3_CustomTag_Environment__Output); + 'environment'?: (_envoy_type_tracing_v3_CustomTag_Environment__Output | null); /** * A request header custom tag. */ - 'request_header'?: (_envoy_type_tracing_v3_CustomTag_Header__Output); + 'request_header'?: (_envoy_type_tracing_v3_CustomTag_Header__Output | null); /** * A custom tag to obtain tag value from the metadata. */ - 'metadata'?: (_envoy_type_tracing_v3_CustomTag_Metadata__Output); + 'metadata'?: (_envoy_type_tracing_v3_CustomTag_Metadata__Output | null); /** * Used to specify what kind of custom tag. */ diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts index 2f6f9f0cc..f729437f4 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/DescriptorProto.ts @@ -33,7 +33,7 @@ export interface DescriptorProto { 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; 'extensionRange'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'options'?: (_google_protobuf_MessageOptions); + 'options'?: (_google_protobuf_MessageOptions | null); 'oneofDecl'?: (_google_protobuf_OneofDescriptorProto)[]; 'reservedRange'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; 'reservedName'?: (string)[]; @@ -46,7 +46,7 @@ export interface DescriptorProto__Output { 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'extensionRange': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_MessageOptions__Output); + 'options': (_google_protobuf_MessageOptions__Output | null); 'oneofDecl': (_google_protobuf_OneofDescriptorProto__Output)[]; 'reservedRange': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; 'reservedName': (string)[]; diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts index 7aa40ce4d..dc4c9673e 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumDescriptorProto.ts @@ -6,11 +6,11 @@ import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output a export interface EnumDescriptorProto { 'name'?: (string); 'value'?: (_google_protobuf_EnumValueDescriptorProto)[]; - 'options'?: (_google_protobuf_EnumOptions); + 'options'?: (_google_protobuf_EnumOptions | null); } export interface EnumDescriptorProto__Output { 'name': (string); 'value': (_google_protobuf_EnumValueDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_EnumOptions__Output); + 'options': (_google_protobuf_EnumOptions__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts index b92ade4f9..777901a54 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumOptions.ts @@ -1,15 +1,18 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumOptions { 'allowAlias'?: (boolean); 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.enum_migrate'?: (_udpa_annotations_MigrateAnnotation | null); } export interface EnumOptions__Output { 'allowAlias': (boolean); 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.enum_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts index 238e7fd01..7f8e57ea5 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueDescriptorProto.ts @@ -5,11 +5,11 @@ import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOp export interface EnumValueDescriptorProto { 'name'?: (string); 'number'?: (number); - 'options'?: (_google_protobuf_EnumValueOptions); + 'options'?: (_google_protobuf_EnumValueOptions | null); } export interface EnumValueDescriptorProto__Output { 'name': (string); 'number': (number); - 'options'?: (_google_protobuf_EnumValueOptions__Output); + 'options': (_google_protobuf_EnumValueOptions__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts index e60ee6f4c..48fea77be 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts @@ -1,13 +1,18 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface EnumValueOptions { 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.envoy.annotations.disallowed_by_default_enum'?: (boolean); + '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation | null); } export interface EnumValueOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.envoy.annotations.disallowed_by_default_enum': (boolean); + '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts index b59518c4b..c511e2eff 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldDescriptorProto.ts @@ -41,7 +41,7 @@ export interface FieldDescriptorProto { 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName'?: (string); 'defaultValue'?: (string); - 'options'?: (_google_protobuf_FieldOptions); + 'options'?: (_google_protobuf_FieldOptions | null); 'oneofIndex'?: (number); 'jsonName'?: (string); } @@ -54,7 +54,7 @@ export interface FieldDescriptorProto__Output { 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName': (string); 'defaultValue': (string); - 'options'?: (_google_protobuf_FieldOptions__Output); + 'options': (_google_protobuf_FieldOptions__Output | null); 'oneofIndex': (number); 'jsonName': (string); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index 530022afe..028e14b74 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -2,6 +2,7 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; +import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; // Original file: null @@ -27,7 +28,10 @@ export interface FieldOptions { 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); 'weak'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.validate.rules'?: (_validate_FieldRules); + '.validate.rules'?: (_validate_FieldRules | null); + '.udpa.annotations.sensitive'?: (boolean); + '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation | null); + '.envoy.annotations.disallowed_by_default'?: (boolean); } export interface FieldOptions__Output { @@ -38,5 +42,8 @@ export interface FieldOptions__Output { 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); 'weak': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.validate.rules'?: (_validate_FieldRules__Output); + '.validate.rules': (_validate_FieldRules__Output | null); + '.udpa.annotations.sensitive': (boolean); + '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output | null); + '.envoy.annotations.disallowed_by_default': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts index 2954e4208..b723da7c0 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileDescriptorProto.ts @@ -15,8 +15,8 @@ export interface FileDescriptorProto { 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; 'service'?: (_google_protobuf_ServiceDescriptorProto)[]; 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'options'?: (_google_protobuf_FileOptions); - 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo); + 'options'?: (_google_protobuf_FileOptions | null); + 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo | null); 'publicDependency'?: (number)[]; 'weakDependency'?: (number)[]; 'syntax'?: (string); @@ -30,8 +30,8 @@ export interface FileDescriptorProto__Output { 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_FileOptions__Output); - 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo__Output); + 'options': (_google_protobuf_FileOptions__Output | null); + 'sourceCodeInfo': (_google_protobuf_SourceCodeInfo__Output | null); 'publicDependency': (number)[]; 'weakDependency': (number)[]; 'syntax': (string); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts index 573e847c0..b046c3ad3 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts @@ -1,6 +1,8 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; +import type { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; // Original file: null @@ -26,6 +28,8 @@ export interface FileOptions { 'objcClassPrefix'?: (string); 'csharpNamespace'?: (string); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation | null); + '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation | null); } export interface FileOptions__Output { @@ -44,4 +48,6 @@ export interface FileOptions__Output { 'objcClassPrefix': (string); 'csharpNamespace': (string); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.udpa.annotations.file_migrate': (_udpa_annotations_FileMigrateAnnotation__Output | null); + '.udpa.annotations.file_status': (_udpa_annotations_StatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts index d3b5a54b8..9dc521214 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts @@ -1,6 +1,8 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { VersioningAnnotation as _udpa_annotations_VersioningAnnotation, VersioningAnnotation__Output as _udpa_annotations_VersioningAnnotation__Output } from '../../udpa/annotations/VersioningAnnotation'; +import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; export interface MessageOptions { 'messageSetWireFormat'?: (boolean); @@ -9,6 +11,8 @@ export interface MessageOptions { 'mapEntry'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.disabled'?: (boolean); + '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation | null); + '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation | null); } export interface MessageOptions__Output { @@ -18,4 +22,6 @@ export interface MessageOptions__Output { 'mapEntry': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.disabled': (boolean); + '.udpa.annotations.versioning': (_udpa_annotations_VersioningAnnotation__Output | null); + '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts index bc2f0afb5..c76c0ea23 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MethodDescriptorProto.ts @@ -6,7 +6,7 @@ export interface MethodDescriptorProto { 'name'?: (string); 'inputType'?: (string); 'outputType'?: (string); - 'options'?: (_google_protobuf_MethodOptions); + 'options'?: (_google_protobuf_MethodOptions | null); 'clientStreaming'?: (boolean); 'serverStreaming'?: (boolean); } @@ -15,7 +15,7 @@ export interface MethodDescriptorProto__Output { 'name': (string); 'inputType': (string); 'outputType': (string); - 'options'?: (_google_protobuf_MethodOptions__Output); + 'options': (_google_protobuf_MethodOptions__Output | null); 'clientStreaming': (boolean); 'serverStreaming': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts index c10ccecd3..636f13ed4 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/OneofDescriptorProto.ts @@ -4,10 +4,10 @@ import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Outpu export interface OneofDescriptorProto { 'name'?: (string); - 'options'?: (_google_protobuf_OneofOptions); + 'options'?: (_google_protobuf_OneofOptions | null); } export interface OneofDescriptorProto__Output { 'name': (string); - 'options'?: (_google_protobuf_OneofOptions__Output); + 'options': (_google_protobuf_OneofOptions__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts index 695a8775c..40c9263ea 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/ServiceDescriptorProto.ts @@ -6,11 +6,11 @@ import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions_ export interface ServiceDescriptorProto { 'name'?: (string); 'method'?: (_google_protobuf_MethodDescriptorProto)[]; - 'options'?: (_google_protobuf_ServiceOptions); + 'options'?: (_google_protobuf_ServiceOptions | null); } export interface ServiceDescriptorProto__Output { 'name': (string); 'method': (_google_protobuf_MethodDescriptorProto__Output)[]; - 'options'?: (_google_protobuf_ServiceOptions__Output); + 'options': (_google_protobuf_ServiceOptions__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts index 9919350e4..41b79eab3 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Struct.ts @@ -7,5 +7,5 @@ export interface Struct { } export interface Struct__Output { - 'fields'?: ({[key: string]: _google_protobuf_Value__Output}); + 'fields': ({[key: string]: _google_protobuf_Value__Output}); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts index 0860535dc..b1a942a56 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/Value.ts @@ -9,8 +9,8 @@ export interface Value { 'numberValue'?: (number | string); 'stringValue'?: (string); 'boolValue'?: (boolean); - 'structValue'?: (_google_protobuf_Struct); - 'listValue'?: (_google_protobuf_ListValue); + 'structValue'?: (_google_protobuf_Struct | null); + 'listValue'?: (_google_protobuf_ListValue | null); 'kind'?: "nullValue"|"numberValue"|"stringValue"|"boolValue"|"structValue"|"listValue"; } @@ -19,7 +19,7 @@ export interface Value__Output { 'numberValue'?: (number); 'stringValue'?: (string); 'boolValue'?: (boolean); - 'structValue'?: (_google_protobuf_Struct__Output); - 'listValue'?: (_google_protobuf_ListValue__Output); + 'structValue'?: (_google_protobuf_Struct__Output | null); + 'listValue'?: (_google_protobuf_ListValue__Output | null); 'kind': "nullValue"|"numberValue"|"stringValue"|"boolValue"|"structValue"|"listValue"; } diff --git a/packages/grpc-js-xds/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts index 9cb81bb0e..bb4e80360 100644 --- a/packages/grpc-js-xds/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type SubtypeConstructor any, Subtype> = { diff --git a/packages/grpc-js-xds/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts index 69454efdc..cf7297a5b 100644 --- a/packages/grpc-js-xds/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type SubtypeConstructor any, Subtype> = { diff --git a/packages/grpc-js-xds/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts index 9a2864fcf..929fd6914 100644 --- a/packages/grpc-js-xds/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -1,8 +1,8 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import type { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient } from './envoy/service/load_stats/v2/LoadReportingService'; -import type { LoadReportingServiceClient as _envoy_service_load_stats_v3_LoadReportingServiceClient } from './envoy/service/load_stats/v3/LoadReportingService'; +import type { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient, LoadReportingServiceDefinition as _envoy_service_load_stats_v2_LoadReportingServiceDefinition } from './envoy/service/load_stats/v2/LoadReportingService'; +import type { LoadReportingServiceClient as _envoy_service_load_stats_v3_LoadReportingServiceClient, LoadReportingServiceDefinition as _envoy_service_load_stats_v3_LoadReportingServiceDefinition } from './envoy/service/load_stats/v3/LoadReportingService'; type SubtypeConstructor any, Subtype> = { new(...args: ConstructorParameters): Subtype; @@ -102,12 +102,12 @@ export interface ProtoGrpcType { service: { load_stats: { v2: { - LoadReportingService: SubtypeConstructor & { service: ServiceDefinition } + LoadReportingService: SubtypeConstructor & { service: _envoy_service_load_stats_v2_LoadReportingServiceDefinition } LoadStatsRequest: MessageTypeDefinition LoadStatsResponse: MessageTypeDefinition } v3: { - LoadReportingService: SubtypeConstructor & { service: ServiceDefinition } + LoadReportingService: SubtypeConstructor & { service: _envoy_service_load_stats_v3_LoadReportingServiceDefinition } LoadStatsRequest: MessageTypeDefinition LoadStatsResponse: MessageTypeDefinition } diff --git a/packages/grpc-js-xds/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts index a51060779..702395d19 100644 --- a/packages/grpc-js-xds/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type SubtypeConstructor any, Subtype> = { diff --git a/packages/grpc-js-xds/src/generated/typed_struct.ts b/packages/grpc-js-xds/src/generated/typed_struct.ts index 78d781a29..47abe063c 100644 --- a/packages/grpc-js-xds/src/generated/typed_struct.ts +++ b/packages/grpc-js-xds/src/generated/typed_struct.ts @@ -1,5 +1,5 @@ import type * as grpc from '@grpc/grpc-js'; -import type { ServiceDefinition, EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; type SubtypeConstructor any, Subtype> = { diff --git a/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts b/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts index f9d842982..435872808 100644 --- a/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts +++ b/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts @@ -36,7 +36,7 @@ export interface TypedStruct { /** * A JSON representation of the above specified type. */ - 'value'?: (_google_protobuf_Struct); + 'value'?: (_google_protobuf_Struct | null); } /** @@ -73,5 +73,5 @@ export interface TypedStruct__Output { /** * A JSON representation of the above specified type. */ - 'value'?: (_google_protobuf_Struct__Output); + 'value': (_google_protobuf_Struct__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/validate/DurationRules.ts b/packages/grpc-js-xds/src/generated/validate/DurationRules.ts index 86b80a34d..879928e20 100644 --- a/packages/grpc-js-xds/src/generated/validate/DurationRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/DurationRules.ts @@ -14,27 +14,27 @@ export interface DurationRules { /** * Const specifies that this field must be exactly the specified value */ - 'const'?: (_google_protobuf_Duration); + 'const'?: (_google_protobuf_Duration | null); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt'?: (_google_protobuf_Duration); + 'lt'?: (_google_protobuf_Duration | null); /** * Lt specifies that this field must be less than the specified value, * inclusive */ - 'lte'?: (_google_protobuf_Duration); + 'lte'?: (_google_protobuf_Duration | null); /** * Gt specifies that this field must be greater than the specified value, * exclusive */ - 'gt'?: (_google_protobuf_Duration); + 'gt'?: (_google_protobuf_Duration | null); /** * Gte specifies that this field must be greater than the specified value, * inclusive */ - 'gte'?: (_google_protobuf_Duration); + 'gte'?: (_google_protobuf_Duration | null); /** * In specifies that this field must be equal to one of the specified * values @@ -59,27 +59,27 @@ export interface DurationRules__Output { /** * Const specifies that this field must be exactly the specified value */ - 'const'?: (_google_protobuf_Duration__Output); + 'const': (_google_protobuf_Duration__Output | null); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt'?: (_google_protobuf_Duration__Output); + 'lt': (_google_protobuf_Duration__Output | null); /** * Lt specifies that this field must be less than the specified value, * inclusive */ - 'lte'?: (_google_protobuf_Duration__Output); + 'lte': (_google_protobuf_Duration__Output | null); /** * Gt specifies that this field must be greater than the specified value, * exclusive */ - 'gt'?: (_google_protobuf_Duration__Output); + 'gt': (_google_protobuf_Duration__Output | null); /** * Gte specifies that this field must be greater than the specified value, * inclusive */ - 'gte'?: (_google_protobuf_Duration__Output); + 'gte': (_google_protobuf_Duration__Output | null); /** * In specifies that this field must be equal to one of the specified * values diff --git a/packages/grpc-js-xds/src/generated/validate/FieldRules.ts b/packages/grpc-js-xds/src/generated/validate/FieldRules.ts index dae124bc1..067125775 100644 --- a/packages/grpc-js-xds/src/generated/validate/FieldRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/FieldRules.ts @@ -32,34 +32,34 @@ export interface FieldRules { /** * Scalar Field Types */ - 'float'?: (_validate_FloatRules); - 'double'?: (_validate_DoubleRules); - 'int32'?: (_validate_Int32Rules); - 'int64'?: (_validate_Int64Rules); - 'uint32'?: (_validate_UInt32Rules); - 'uint64'?: (_validate_UInt64Rules); - 'sint32'?: (_validate_SInt32Rules); - 'sint64'?: (_validate_SInt64Rules); - 'fixed32'?: (_validate_Fixed32Rules); - 'fixed64'?: (_validate_Fixed64Rules); - 'sfixed32'?: (_validate_SFixed32Rules); - 'sfixed64'?: (_validate_SFixed64Rules); - 'bool'?: (_validate_BoolRules); - 'string'?: (_validate_StringRules); - 'bytes'?: (_validate_BytesRules); + 'float'?: (_validate_FloatRules | null); + 'double'?: (_validate_DoubleRules | null); + 'int32'?: (_validate_Int32Rules | null); + 'int64'?: (_validate_Int64Rules | null); + 'uint32'?: (_validate_UInt32Rules | null); + 'uint64'?: (_validate_UInt64Rules | null); + 'sint32'?: (_validate_SInt32Rules | null); + 'sint64'?: (_validate_SInt64Rules | null); + 'fixed32'?: (_validate_Fixed32Rules | null); + 'fixed64'?: (_validate_Fixed64Rules | null); + 'sfixed32'?: (_validate_SFixed32Rules | null); + 'sfixed64'?: (_validate_SFixed64Rules | null); + 'bool'?: (_validate_BoolRules | null); + 'string'?: (_validate_StringRules | null); + 'bytes'?: (_validate_BytesRules | null); /** * Complex Field Types */ - 'enum'?: (_validate_EnumRules); - 'message'?: (_validate_MessageRules); - 'repeated'?: (_validate_RepeatedRules); - 'map'?: (_validate_MapRules); + 'enum'?: (_validate_EnumRules | null); + 'message'?: (_validate_MessageRules | null); + 'repeated'?: (_validate_RepeatedRules | null); + 'map'?: (_validate_MapRules | null); /** * Well-Known Field Types */ - 'any'?: (_validate_AnyRules); - 'duration'?: (_validate_DurationRules); - 'timestamp'?: (_validate_TimestampRules); + 'any'?: (_validate_AnyRules | null); + 'duration'?: (_validate_DurationRules | null); + 'timestamp'?: (_validate_TimestampRules | null); 'type'?: "float"|"double"|"int32"|"int64"|"uint32"|"uint64"|"sint32"|"sint64"|"fixed32"|"fixed64"|"sfixed32"|"sfixed64"|"bool"|"string"|"bytes"|"enum"|"repeated"|"map"|"any"|"duration"|"timestamp"; } @@ -71,33 +71,33 @@ export interface FieldRules__Output { /** * Scalar Field Types */ - 'float'?: (_validate_FloatRules__Output); - 'double'?: (_validate_DoubleRules__Output); - 'int32'?: (_validate_Int32Rules__Output); - 'int64'?: (_validate_Int64Rules__Output); - 'uint32'?: (_validate_UInt32Rules__Output); - 'uint64'?: (_validate_UInt64Rules__Output); - 'sint32'?: (_validate_SInt32Rules__Output); - 'sint64'?: (_validate_SInt64Rules__Output); - 'fixed32'?: (_validate_Fixed32Rules__Output); - 'fixed64'?: (_validate_Fixed64Rules__Output); - 'sfixed32'?: (_validate_SFixed32Rules__Output); - 'sfixed64'?: (_validate_SFixed64Rules__Output); - 'bool'?: (_validate_BoolRules__Output); - 'string'?: (_validate_StringRules__Output); - 'bytes'?: (_validate_BytesRules__Output); + 'float'?: (_validate_FloatRules__Output | null); + 'double'?: (_validate_DoubleRules__Output | null); + 'int32'?: (_validate_Int32Rules__Output | null); + 'int64'?: (_validate_Int64Rules__Output | null); + 'uint32'?: (_validate_UInt32Rules__Output | null); + 'uint64'?: (_validate_UInt64Rules__Output | null); + 'sint32'?: (_validate_SInt32Rules__Output | null); + 'sint64'?: (_validate_SInt64Rules__Output | null); + 'fixed32'?: (_validate_Fixed32Rules__Output | null); + 'fixed64'?: (_validate_Fixed64Rules__Output | null); + 'sfixed32'?: (_validate_SFixed32Rules__Output | null); + 'sfixed64'?: (_validate_SFixed64Rules__Output | null); + 'bool'?: (_validate_BoolRules__Output | null); + 'string'?: (_validate_StringRules__Output | null); + 'bytes'?: (_validate_BytesRules__Output | null); /** * Complex Field Types */ - 'enum'?: (_validate_EnumRules__Output); - 'message'?: (_validate_MessageRules__Output); - 'repeated'?: (_validate_RepeatedRules__Output); - 'map'?: (_validate_MapRules__Output); + 'enum'?: (_validate_EnumRules__Output | null); + 'message': (_validate_MessageRules__Output | null); + 'repeated'?: (_validate_RepeatedRules__Output | null); + 'map'?: (_validate_MapRules__Output | null); /** * Well-Known Field Types */ - 'any'?: (_validate_AnyRules__Output); - 'duration'?: (_validate_DurationRules__Output); - 'timestamp'?: (_validate_TimestampRules__Output); + 'any'?: (_validate_AnyRules__Output | null); + 'duration'?: (_validate_DurationRules__Output | null); + 'timestamp'?: (_validate_TimestampRules__Output | null); 'type': "float"|"double"|"int32"|"int64"|"uint32"|"uint64"|"sint32"|"sint64"|"fixed32"|"fixed64"|"sfixed32"|"sfixed64"|"bool"|"string"|"bytes"|"enum"|"repeated"|"map"|"any"|"duration"|"timestamp"; } diff --git a/packages/grpc-js-xds/src/generated/validate/MapRules.ts b/packages/grpc-js-xds/src/generated/validate/MapRules.ts index 0c89bf2b3..7efe5b390 100644 --- a/packages/grpc-js-xds/src/generated/validate/MapRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/MapRules.ts @@ -25,13 +25,13 @@ export interface MapRules { /** * Keys specifies the constraints to be applied to each key in the field. */ - 'keys'?: (_validate_FieldRules); + 'keys'?: (_validate_FieldRules | null); /** * Values specifies the constraints to be applied to the value of each key * in the field. Message values will still have their validations evaluated * unless skip is specified here. */ - 'values'?: (_validate_FieldRules); + 'values'?: (_validate_FieldRules | null); } /** @@ -56,11 +56,11 @@ export interface MapRules__Output { /** * Keys specifies the constraints to be applied to each key in the field. */ - 'keys'?: (_validate_FieldRules__Output); + 'keys': (_validate_FieldRules__Output | null); /** * Values specifies the constraints to be applied to the value of each key * in the field. Message values will still have their validations evaluated * unless skip is specified here. */ - 'values'?: (_validate_FieldRules__Output); + 'values': (_validate_FieldRules__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts b/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts index 1f6d4f0ff..d347b6497 100644 --- a/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/RepeatedRules.ts @@ -28,7 +28,7 @@ export interface RepeatedRules { * Repeated message fields will still execute validation against each item * unless skip is specified here. */ - 'items'?: (_validate_FieldRules); + 'items'?: (_validate_FieldRules | null); } /** @@ -56,5 +56,5 @@ export interface RepeatedRules__Output { * Repeated message fields will still execute validation against each item * unless skip is specified here. */ - 'items'?: (_validate_FieldRules__Output); + 'items': (_validate_FieldRules__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts b/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts index 9436cc8ee..69d548126 100644 --- a/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts +++ b/packages/grpc-js-xds/src/generated/validate/TimestampRules.ts @@ -15,27 +15,27 @@ export interface TimestampRules { /** * Const specifies that this field must be exactly the specified value */ - 'const'?: (_google_protobuf_Timestamp); + 'const'?: (_google_protobuf_Timestamp | null); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt'?: (_google_protobuf_Timestamp); + 'lt'?: (_google_protobuf_Timestamp | null); /** * Lte specifies that this field must be less than the specified value, * inclusive */ - 'lte'?: (_google_protobuf_Timestamp); + 'lte'?: (_google_protobuf_Timestamp | null); /** * Gt specifies that this field must be greater than the specified value, * exclusive */ - 'gt'?: (_google_protobuf_Timestamp); + 'gt'?: (_google_protobuf_Timestamp | null); /** * Gte specifies that this field must be greater than the specified value, * inclusive */ - 'gte'?: (_google_protobuf_Timestamp); + 'gte'?: (_google_protobuf_Timestamp | null); /** * LtNow specifies that this must be less than the current time. LtNow * can only be used with the Within rule. @@ -51,7 +51,7 @@ export interface TimestampRules { * current time. This constraint can be used alone or with the LtNow and * GtNow rules. */ - 'within'?: (_google_protobuf_Duration); + 'within'?: (_google_protobuf_Duration | null); } /** @@ -66,27 +66,27 @@ export interface TimestampRules__Output { /** * Const specifies that this field must be exactly the specified value */ - 'const'?: (_google_protobuf_Timestamp__Output); + 'const': (_google_protobuf_Timestamp__Output | null); /** * Lt specifies that this field must be less than the specified value, * exclusive */ - 'lt'?: (_google_protobuf_Timestamp__Output); + 'lt': (_google_protobuf_Timestamp__Output | null); /** * Lte specifies that this field must be less than the specified value, * inclusive */ - 'lte'?: (_google_protobuf_Timestamp__Output); + 'lte': (_google_protobuf_Timestamp__Output | null); /** * Gt specifies that this field must be greater than the specified value, * exclusive */ - 'gt'?: (_google_protobuf_Timestamp__Output); + 'gt': (_google_protobuf_Timestamp__Output | null); /** * Gte specifies that this field must be greater than the specified value, * inclusive */ - 'gte'?: (_google_protobuf_Timestamp__Output); + 'gte': (_google_protobuf_Timestamp__Output | null); /** * LtNow specifies that this must be less than the current time. LtNow * can only be used with the Within rule. @@ -102,5 +102,5 @@ export interface TimestampRules__Output { * current time. This constraint can be used alone or with the LtNow and * GtNow rules. */ - 'within'?: (_google_protobuf_Duration__Output); + 'within': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts index 4a9a45527..8d583d961 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts @@ -22,7 +22,7 @@ export interface _xds_core_v3_CollectionEntry_InlineEntry { /** * The resource payload, including type URL. */ - 'resource'?: (_google_protobuf_Any); + 'resource'?: (_google_protobuf_Any | null); } /** @@ -44,7 +44,7 @@ export interface _xds_core_v3_CollectionEntry_InlineEntry__Output { /** * The resource payload, including type URL. */ - 'resource'?: (_google_protobuf_Any__Output); + 'resource': (_google_protobuf_Any__Output | null); } /** @@ -60,11 +60,11 @@ export interface CollectionEntry { /** * A resource locator describing how the member resource is to be located. */ - 'locator'?: (_xds_core_v3_ResourceLocator); + 'locator'?: (_xds_core_v3_ResourceLocator | null); /** * The resource is inlined in the list collection. */ - 'inline_entry'?: (_xds_core_v3_CollectionEntry_InlineEntry); + 'inline_entry'?: (_xds_core_v3_CollectionEntry_InlineEntry | null); 'resource_specifier'?: "locator"|"inline_entry"; } @@ -81,10 +81,10 @@ export interface CollectionEntry__Output { /** * A resource locator describing how the member resource is to be located. */ - 'locator'?: (_xds_core_v3_ResourceLocator__Output); + 'locator'?: (_xds_core_v3_ResourceLocator__Output | null); /** * The resource is inlined in the list collection. */ - 'inline_entry'?: (_xds_core_v3_CollectionEntry_InlineEntry__Output); + 'inline_entry'?: (_xds_core_v3_CollectionEntry_InlineEntry__Output | null); 'resource_specifier': "locator"|"inline_entry"; } diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts index f28a31d20..2b314d8bb 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts @@ -37,7 +37,7 @@ export interface _xds_core_v3_ResourceLocator_Directive { * resource, it will fallback to `bar`. Alternative resources do not need * to have equivalent content, but they should be functional substitutes. */ - 'alt'?: (_xds_core_v3_ResourceLocator); + 'alt'?: (_xds_core_v3_ResourceLocator | null); /** * List collections support inlining of resources via the entry field in * Resource. These inlined Resource objects may have an optional name @@ -83,7 +83,7 @@ export interface _xds_core_v3_ResourceLocator_Directive__Output { * resource, it will fallback to `bar`. Alternative resources do not need * to have equivalent content, but they should be functional substitutes. */ - 'alt'?: (_xds_core_v3_ResourceLocator__Output); + 'alt'?: (_xds_core_v3_ResourceLocator__Output | null); /** * List collections support inlining of resources via the entry field in * Resource. These inlined Resource objects may have an optional name @@ -150,7 +150,7 @@ export interface ResourceLocator { * there must be no additional context parameters set on the matched * resource. */ - 'exact_context'?: (_xds_core_v3_ContextParams); + 'exact_context'?: (_xds_core_v3_ContextParams | null); /** * A list of directives that appear in the xDS resource locator #fragment. * @@ -208,7 +208,7 @@ export interface ResourceLocator__Output { * there must be no additional context parameters set on the matched * resource. */ - 'exact_context'?: (_xds_core_v3_ContextParams__Output); + 'exact_context'?: (_xds_core_v3_ContextParams__Output | null); /** * A list of directives that appear in the xDS resource locator #fragment. * From 8718d7d4761efa8c74948ac2a6e52aa735c6ce3e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 14:59:38 -0700 Subject: [PATCH 1488/1899] grpc-js-xds: Generate files for fault injection --- .../filters/common/fault/v3/FaultDelay.ts | 81 +++++++ .../filters/common/fault/v3/FaultRateLimit.ts | 78 +++++++ .../filters/http/fault/v3/FaultAbort.ts | 67 ++++++ .../filters/http/fault/v3/HTTPFault.ts | 213 +++++++++++++++++ packages/grpc-js-xds/src/generated/fault.ts | 220 ++++++++++++++++++ 5 files changed, 659 insertions(+) create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultRateLimit.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/FaultAbort.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts create mode 100644 packages/grpc-js-xds/src/generated/fault.ts diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts new file mode 100644 index 000000000..8e2739958 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts @@ -0,0 +1,81 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/common/fault/v3/fault.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../../../google/protobuf/Duration'; +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../../../envoy/type/v3/FractionalPercent'; + +// Original file: deps/envoy-api/envoy/extensions/filters/common/fault/v3/fault.proto + +export enum _envoy_extensions_filters_common_fault_v3_FaultDelay_FaultDelayType { + /** + * Unused and deprecated. + */ + FIXED = 0, +} + +/** + * Fault delays are controlled via an HTTP header (if applicable). See the + * :ref:`HTTP fault filter ` documentation for + * more information. + */ +export interface _envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay { +} + +/** + * Fault delays are controlled via an HTTP header (if applicable). See the + * :ref:`HTTP fault filter ` documentation for + * more information. + */ +export interface _envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay__Output { +} + +/** + * Delay specification is used to inject latency into the + * HTTP/gRPC/Mongo/Redis operation or delay proxying of TCP connections. + * [#next-free-field: 6] + */ +export interface FaultDelay { + /** + * Add a fixed delay before forwarding the operation upstream. See + * https://developers.google.com/protocol-buffers/docs/proto3#json for + * the JSON/YAML Duration mapping. For HTTP/Mongo/Redis, the specified + * delay will be injected before a new request/operation. For TCP + * connections, the proxying of the connection upstream will be delayed + * for the specified period. This is required if type is FIXED. + */ + 'fixed_delay'?: (_google_protobuf_Duration | null); + /** + * The percentage of operations/connections/requests on which the delay will be injected. + */ + 'percentage'?: (_envoy_type_v3_FractionalPercent | null); + /** + * Fault delays are controlled via an HTTP header (if applicable). + */ + 'header_delay'?: (_envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay | null); + 'fault_delay_secifier'?: "fixed_delay"|"header_delay"; +} + +/** + * Delay specification is used to inject latency into the + * HTTP/gRPC/Mongo/Redis operation or delay proxying of TCP connections. + * [#next-free-field: 6] + */ +export interface FaultDelay__Output { + /** + * Add a fixed delay before forwarding the operation upstream. See + * https://developers.google.com/protocol-buffers/docs/proto3#json for + * the JSON/YAML Duration mapping. For HTTP/Mongo/Redis, the specified + * delay will be injected before a new request/operation. For TCP + * connections, the proxying of the connection upstream will be delayed + * for the specified period. This is required if type is FIXED. + */ + 'fixed_delay'?: (_google_protobuf_Duration__Output | null); + /** + * The percentage of operations/connections/requests on which the delay will be injected. + */ + 'percentage': (_envoy_type_v3_FractionalPercent__Output | null); + /** + * Fault delays are controlled via an HTTP header (if applicable). + */ + 'header_delay'?: (_envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDelay__Output | null); + 'fault_delay_secifier': "fixed_delay"|"header_delay"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultRateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultRateLimit.ts new file mode 100644 index 000000000..4df7395bb --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultRateLimit.ts @@ -0,0 +1,78 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/common/fault/v3/fault.proto + +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../../../envoy/type/v3/FractionalPercent'; +import type { Long } from '@grpc/proto-loader'; + +/** + * Describes a fixed/constant rate limit. + */ +export interface _envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit { + /** + * The limit supplied in KiB/s. + */ + 'limit_kbps'?: (number | string | Long); +} + +/** + * Describes a fixed/constant rate limit. + */ +export interface _envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit__Output { + /** + * The limit supplied in KiB/s. + */ + 'limit_kbps': (string); +} + +/** + * Rate limits are controlled via an HTTP header (if applicable). See the + * :ref:`HTTP fault filter ` documentation for + * more information. + */ +export interface _envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit { +} + +/** + * Rate limits are controlled via an HTTP header (if applicable). See the + * :ref:`HTTP fault filter ` documentation for + * more information. + */ +export interface _envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit__Output { +} + +/** + * Describes a rate limit to be applied. + */ +export interface FaultRateLimit { + /** + * A fixed rate limit. + */ + 'fixed_limit'?: (_envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit | null); + /** + * The percentage of operations/connections/requests on which the rate limit will be injected. + */ + 'percentage'?: (_envoy_type_v3_FractionalPercent | null); + /** + * Rate limits are controlled via an HTTP header (if applicable). + */ + 'header_limit'?: (_envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit | null); + 'limit_type'?: "fixed_limit"|"header_limit"; +} + +/** + * Describes a rate limit to be applied. + */ +export interface FaultRateLimit__Output { + /** + * A fixed rate limit. + */ + 'fixed_limit'?: (_envoy_extensions_filters_common_fault_v3_FaultRateLimit_FixedLimit__Output | null); + /** + * The percentage of operations/connections/requests on which the rate limit will be injected. + */ + 'percentage': (_envoy_type_v3_FractionalPercent__Output | null); + /** + * Rate limits are controlled via an HTTP header (if applicable). + */ + 'header_limit'?: (_envoy_extensions_filters_common_fault_v3_FaultRateLimit_HeaderLimit__Output | null); + 'limit_type': "fixed_limit"|"header_limit"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/FaultAbort.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/FaultAbort.ts new file mode 100644 index 000000000..823706cb7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/FaultAbort.ts @@ -0,0 +1,67 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/http/fault/v3/fault.proto + +import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalPercent__Output as _envoy_type_v3_FractionalPercent__Output } from '../../../../../../envoy/type/v3/FractionalPercent'; + +/** + * Fault aborts are controlled via an HTTP header (if applicable). See the + * :ref:`HTTP fault filter ` documentation for + * more information. + */ +export interface _envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort { +} + +/** + * Fault aborts are controlled via an HTTP header (if applicable). See the + * :ref:`HTTP fault filter ` documentation for + * more information. + */ +export interface _envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort__Output { +} + +/** + * [#next-free-field: 6] + */ +export interface FaultAbort { + /** + * HTTP status code to use to abort the HTTP request. + */ + 'http_status'?: (number); + /** + * The percentage of requests/operations/connections that will be aborted with the error code + * provided. + */ + 'percentage'?: (_envoy_type_v3_FractionalPercent | null); + /** + * Fault aborts are controlled via an HTTP header (if applicable). + */ + 'header_abort'?: (_envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort | null); + /** + * gRPC status code to use to abort the gRPC request. + */ + 'grpc_status'?: (number); + 'error_type'?: "http_status"|"grpc_status"|"header_abort"; +} + +/** + * [#next-free-field: 6] + */ +export interface FaultAbort__Output { + /** + * HTTP status code to use to abort the HTTP request. + */ + 'http_status'?: (number); + /** + * The percentage of requests/operations/connections that will be aborted with the error code + * provided. + */ + 'percentage': (_envoy_type_v3_FractionalPercent__Output | null); + /** + * Fault aborts are controlled via an HTTP header (if applicable). + */ + 'header_abort'?: (_envoy_extensions_filters_http_fault_v3_FaultAbort_HeaderAbort__Output | null); + /** + * gRPC status code to use to abort the gRPC request. + */ + 'grpc_status'?: (number); + 'error_type': "http_status"|"grpc_status"|"header_abort"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts new file mode 100644 index 000000000..20c543508 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts @@ -0,0 +1,213 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/http/fault/v3/fault.proto + +import type { FaultDelay as _envoy_extensions_filters_common_fault_v3_FaultDelay, FaultDelay__Output as _envoy_extensions_filters_common_fault_v3_FaultDelay__Output } from '../../../../../../envoy/extensions/filters/common/fault/v3/FaultDelay'; +import type { FaultAbort as _envoy_extensions_filters_http_fault_v3_FaultAbort, FaultAbort__Output as _envoy_extensions_filters_http_fault_v3_FaultAbort__Output } from '../../../../../../envoy/extensions/filters/http/fault/v3/FaultAbort'; +import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../../../envoy/config/route/v3/HeaderMatcher'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../../../google/protobuf/UInt32Value'; +import type { FaultRateLimit as _envoy_extensions_filters_common_fault_v3_FaultRateLimit, FaultRateLimit__Output as _envoy_extensions_filters_common_fault_v3_FaultRateLimit__Output } from '../../../../../../envoy/extensions/filters/common/fault/v3/FaultRateLimit'; + +/** + * [#next-free-field: 15] + */ +export interface HTTPFault { + /** + * If specified, the filter will inject delays based on the values in the + * object. + */ + 'delay'?: (_envoy_extensions_filters_common_fault_v3_FaultDelay | null); + /** + * If specified, the filter will abort requests based on the values in + * the object. At least *abort* or *delay* must be specified. + */ + 'abort'?: (_envoy_extensions_filters_http_fault_v3_FaultAbort | null); + /** + * Specifies the name of the (destination) upstream cluster that the + * filter should match on. Fault injection will be restricted to requests + * bound to the specific upstream cluster. + */ + 'upstream_cluster'?: (string); + /** + * Specifies a set of headers that the filter should match on. The fault + * injection filter can be applied selectively to requests that match a set of + * headers specified in the fault filter config. The chances of actual fault + * injection further depend on the value of the :ref:`percentage + * ` field. + * The filter will check the request's headers against all the specified + * headers in the filter config. A match will happen if all the headers in the + * config are present in the request with the same values (or based on + * presence if the *value* field is not in the config). + */ + 'headers'?: (_envoy_config_route_v3_HeaderMatcher)[]; + /** + * Faults are injected for the specified list of downstream hosts. If this + * setting is not set, faults are injected for all downstream nodes. + * Downstream node name is taken from :ref:`the HTTP + * x-envoy-downstream-service-node + * ` header and compared + * against downstream_nodes list. + */ + 'downstream_nodes'?: (string)[]; + /** + * The maximum number of faults that can be active at a single time via the configured fault + * filter. Note that because this setting can be overridden at the route level, it's possible + * for the number of active faults to be greater than this value (if injected via a different + * route). If not specified, defaults to unlimited. This setting can be overridden via + * `runtime ` and any faults that are not injected + * due to overflow will be indicated via the `faults_overflow + * ` stat. + * + * .. attention:: + * Like other :ref:`circuit breakers ` in Envoy, this is a fuzzy + * limit. It's possible for the number of active faults to rise slightly above the configured + * amount due to the implementation details. + */ + 'max_active_faults'?: (_google_protobuf_UInt32Value | null); + /** + * The response rate limit to be applied to the response body of the stream. When configured, + * the percentage can be overridden by the :ref:`fault.http.rate_limit.response_percent + * ` runtime key. + * + * .. attention:: + * This is a per-stream limit versus a connection level limit. This means that concurrent streams + * will each get an independent limit. + */ + 'response_rate_limit'?: (_envoy_extensions_filters_common_fault_v3_FaultRateLimit | null); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.delay.fixed_delay_percent + */ + 'delay_percent_runtime'?: (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.abort.abort_percent + */ + 'abort_percent_runtime'?: (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.delay.fixed_duration_ms + */ + 'delay_duration_runtime'?: (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.abort.http_status + */ + 'abort_http_status_runtime'?: (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.max_active_faults + */ + 'max_active_faults_runtime'?: (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.rate_limit.response_percent + */ + 'response_rate_limit_percent_runtime'?: (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.abort.grpc_status + */ + 'abort_grpc_status_runtime'?: (string); +} + +/** + * [#next-free-field: 15] + */ +export interface HTTPFault__Output { + /** + * If specified, the filter will inject delays based on the values in the + * object. + */ + 'delay': (_envoy_extensions_filters_common_fault_v3_FaultDelay__Output | null); + /** + * If specified, the filter will abort requests based on the values in + * the object. At least *abort* or *delay* must be specified. + */ + 'abort': (_envoy_extensions_filters_http_fault_v3_FaultAbort__Output | null); + /** + * Specifies the name of the (destination) upstream cluster that the + * filter should match on. Fault injection will be restricted to requests + * bound to the specific upstream cluster. + */ + 'upstream_cluster': (string); + /** + * Specifies a set of headers that the filter should match on. The fault + * injection filter can be applied selectively to requests that match a set of + * headers specified in the fault filter config. The chances of actual fault + * injection further depend on the value of the :ref:`percentage + * ` field. + * The filter will check the request's headers against all the specified + * headers in the filter config. A match will happen if all the headers in the + * config are present in the request with the same values (or based on + * presence if the *value* field is not in the config). + */ + 'headers': (_envoy_config_route_v3_HeaderMatcher__Output)[]; + /** + * Faults are injected for the specified list of downstream hosts. If this + * setting is not set, faults are injected for all downstream nodes. + * Downstream node name is taken from :ref:`the HTTP + * x-envoy-downstream-service-node + * ` header and compared + * against downstream_nodes list. + */ + 'downstream_nodes': (string)[]; + /** + * The maximum number of faults that can be active at a single time via the configured fault + * filter. Note that because this setting can be overridden at the route level, it's possible + * for the number of active faults to be greater than this value (if injected via a different + * route). If not specified, defaults to unlimited. This setting can be overridden via + * `runtime ` and any faults that are not injected + * due to overflow will be indicated via the `faults_overflow + * ` stat. + * + * .. attention:: + * Like other :ref:`circuit breakers ` in Envoy, this is a fuzzy + * limit. It's possible for the number of active faults to rise slightly above the configured + * amount due to the implementation details. + */ + 'max_active_faults': (_google_protobuf_UInt32Value__Output | null); + /** + * The response rate limit to be applied to the response body of the stream. When configured, + * the percentage can be overridden by the :ref:`fault.http.rate_limit.response_percent + * ` runtime key. + * + * .. attention:: + * This is a per-stream limit versus a connection level limit. This means that concurrent streams + * will each get an independent limit. + */ + 'response_rate_limit': (_envoy_extensions_filters_common_fault_v3_FaultRateLimit__Output | null); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.delay.fixed_delay_percent + */ + 'delay_percent_runtime': (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.abort.abort_percent + */ + 'abort_percent_runtime': (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.delay.fixed_duration_ms + */ + 'delay_duration_runtime': (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.abort.http_status + */ + 'abort_http_status_runtime': (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.max_active_faults + */ + 'max_active_faults_runtime': (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.rate_limit.response_percent + */ + 'response_rate_limit_percent_runtime': (string); + /** + * The runtime key to override the :ref:`default ` + * runtime. The default is: fault.http.abort.grpc_status + */ + 'abort_grpc_status_runtime': (string); +} diff --git a/packages/grpc-js-xds/src/generated/fault.ts b/packages/grpc-js-xds/src/generated/fault.ts new file mode 100644 index 000000000..6eefcdfbd --- /dev/null +++ b/packages/grpc-js-xds/src/generated/fault.ts @@ -0,0 +1,220 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + envoy: { + annotations: { + } + config: { + core: { + v3: { + Address: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition + Extension: MessageTypeDefinition + ExtensionConfigSource: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HttpUri: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + ProxyProtocolConfig: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition + } + } + route: { + v3: { + CorsPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + FilterConfig: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + InternalRedirectPolicy: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + } + } + } + extensions: { + filters: { + common: { + fault: { + v3: { + FaultDelay: MessageTypeDefinition + FaultRateLimit: MessageTypeDefinition + } + } + } + http: { + fault: { + v3: { + FaultAbort: MessageTypeDefinition + HTTPFault: MessageTypeDefinition + } + } + } + } + } + type: { + matcher: { + v3: { + ListStringMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + } + } + metadata: { + v3: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + tracing: { + v3: { + CustomTag: MessageTypeDefinition + } + } + v3: { + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } + } + } + google: { + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } + xds: { + core: { + v3: { + Authority: MessageTypeDefinition + } + } + } +} + From 365b37919317b8db1dc576b4957ebf96049a34b4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 14:59:59 -0700 Subject: [PATCH 1489/1899] grpc-js-xds: Factor Fraction out into a separate file --- packages/grpc-js-xds/src/fraction.ts | 39 ++++++++++++++++++++++++ packages/grpc-js-xds/src/matcher.ts | 10 +----- packages/grpc-js-xds/src/resolver-xds.ts | 14 ++------- 3 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 packages/grpc-js-xds/src/fraction.ts diff --git a/packages/grpc-js-xds/src/fraction.ts b/packages/grpc-js-xds/src/fraction.ts new file mode 100644 index 000000000..709af72b2 --- /dev/null +++ b/packages/grpc-js-xds/src/fraction.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FractionalPercent__Output } from "./generated/envoy/type/v3/FractionalPercent"; + +export interface Fraction { + numerator: number; + denominator: number; +} + +export function fractionToString(fraction: Fraction): string { + return `${fraction.numerator}/${fraction.denominator}`; +} + +const RUNTIME_FRACTION_DENOMINATOR_VALUES = { + HUNDRED: 100, + TEN_THOUSAND: 10_000, + MILLION: 1_000_000 +} + +export function envoyFractionToFraction(envoyFraction: FractionalPercent__Output): Fraction { + return { + numerator: envoyFraction.numerator, + denominator: RUNTIME_FRACTION_DENOMINATOR_VALUES[envoyFraction.denominator] + }; +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/matcher.ts b/packages/grpc-js-xds/src/matcher.ts index 14cb7f672..b173c30e0 100644 --- a/packages/grpc-js-xds/src/matcher.ts +++ b/packages/grpc-js-xds/src/matcher.ts @@ -16,6 +16,7 @@ import { Metadata } from "@grpc/grpc-js"; import { RE2 } from "re2-wasm"; +import { Fraction, fractionToString } from "./fraction"; /** * An object representing a predicate that determines whether a given @@ -210,15 +211,6 @@ export class PathSafeRegexValueMatcher { } } -export interface Fraction { - numerator: number; - denominator: number; -} - -function fractionToString(fraction: Fraction): string { - return `${fraction.numerator}/${fraction.denominator}`; -} - export class FullMatcher implements Matcher { constructor(private pathMatcher: ValueMatcher, private headerMatchers: Matcher[], private fraction: Fraction | null) {} diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 3eaabb111..3712ad647 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -37,7 +37,8 @@ import { HeaderMatcher__Output } from './generated/envoy/config/route/v3/HeaderM import ConfigSelector = experimental.ConfigSelector; import LoadBalancingConfig = experimental.LoadBalancingConfig; import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluster-manager'; -import { ExactValueMatcher, Fraction, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; +import { ExactValueMatcher, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; +import { envoyFractionToFraction, Fraction } from "./fraction"; import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action'; import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from './resources'; import Duration = experimental.Duration; @@ -158,12 +159,6 @@ function getPredicateForHeaderMatcher(headerMatch: HeaderMatcher__Output): Match return new HeaderMatcher(headerMatch.name, valueChecker, headerMatch.invert_match); } -const RUNTIME_FRACTION_DENOMINATOR_VALUES = { - HUNDRED: 100, - TEN_THOUSAND: 10_000, - MILLION: 1_000_000 -} - function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { let pathMatcher: ValueMatcher; const caseInsensitive = routeMatch.case_sensitive?.value === false; @@ -185,10 +180,7 @@ function getPredicateForMatcher(routeMatch: RouteMatch__Output): Matcher { if (!routeMatch.runtime_fraction?.default_value) { runtimeFraction = null; } else { - runtimeFraction = { - numerator: routeMatch.runtime_fraction.default_value.numerator, - denominator: RUNTIME_FRACTION_DENOMINATOR_VALUES[routeMatch.runtime_fraction.default_value.denominator] - }; + runtimeFraction = envoyFractionToFraction(routeMatch.runtime_fraction.default_value) } return new FullMatcher(pathMatcher, headerMatchers, runtimeFraction); } From f216ecef00f925d46a3796e7ca3c91d9ce547385 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 15:06:47 -0700 Subject: [PATCH 1490/1899] grpc-js-xds: Add null checks to handle generated code changes --- packages/grpc-js-xds/src/resolver-xds.ts | 2 +- packages/grpc-js-xds/src/xds-stream-state/rds-state.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 3712ad647..f6287ea67 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -228,7 +228,7 @@ class XdsResolver implements Resolver { onValidUpdate: (update: Listener__Output) => { const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, update.api_listener!.api_listener!.value); const defaultTimeout = httpConnectionManager.common_http_protocol_options?.idle_timeout; - if (defaultTimeout === undefined) { + if (defaultTimeout === null || defaultTimeout === undefined) { this.latestDefaultTimeout = undefined; } else { this.latestDefaultTimeout = protoDurationToDuration(defaultTimeout); diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index f04692859..58f11f0b4 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -137,7 +137,7 @@ export class RdsState implements XdsStreamState { if (route.action !== 'route') { return false; } - if ((route.route === undefined) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { + if ((route.route === undefined) || (route.route === null) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { return false; } if (EXPERIMENTAL_FAULT_INJECTION) { From e1b0d62e9bcf5f0aba88ac2207459afba43bbec7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 15:07:42 -0700 Subject: [PATCH 1491/1899] grpc-js-xds: Add fault injection file to type generator script --- packages/grpc-js-xds/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index eb8e3e03e..6506112c4 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { From b5fd5b033ee6e876e4bc0304ff8c31a8bfd0b8a4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 15:08:10 -0700 Subject: [PATCH 1492/1899] grpc-js-xds: Add fault injection HTTP filter --- .../src/http-filter/fault-injection-filter.ts | 333 ++++++++++++++++++ packages/grpc-js-xds/src/index.ts | 2 + 2 files changed, 335 insertions(+) create mode 100644 packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts diff --git a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts new file mode 100644 index 000000000..825b7c058 --- /dev/null +++ b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts @@ -0,0 +1,333 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// This is a non-public, unstable API, but it's very convenient +import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; +import { experimental, Metadata, status } from '@grpc/grpc-js'; +import { Any__Output } from '../generated/google/protobuf/Any'; +import Filter = experimental.Filter; +import FilterFactory = experimental.FilterFactory; +import BaseFilter = experimental.BaseFilter; +import CallStream = experimental.CallStream; +import { HttpFilterConfig, registerHttpFilter } from '../http-filter'; +import { HTTPFault__Output } from '../generated/envoy/extensions/filters/http/fault/v3/HTTPFault'; +import { envoyFractionToFraction, Fraction } from '../fraction'; +import { Duration__Output } from '../generated/google/protobuf/Duration'; + +const resourceRoot = loadProtosWithOptionsSync([ + 'envoy/extendsion/filtesr/http/fault/v3/fault.proto'], { + keepCase: true, + includeDirs: [ + // Paths are relative to src/build + __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/protoc-gen-validate/' + ], + } +); + +interface FixedDelayConfig { + kind: 'fixed'; + durationMs: number; + percentage: Fraction; +} + +interface HeaderDelayConfig { + kind: 'header'; + percentage: Fraction; +} + +interface GrpcAbortConfig { + kind: 'grpc'; + code: status; + percentage: Fraction; +} + +interface HeaderAbortConfig { + kind: 'header'; + percentage: Fraction; +} + +interface FaultInjectionConfig { + delay: FixedDelayConfig | HeaderDelayConfig | null; + abort: GrpcAbortConfig | HeaderAbortConfig | null; + maxActiveFaults: number; +} + +interface FaultInjectionFilterConfig extends HttpFilterConfig { + typeUrl: 'type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault'; + config: FaultInjectionConfig; +} + +const FAULT_INJECTION_FILTER_URL = 'type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault'; + +const toObjectOptions = { + longs: String, + enums: String, + defaults: true, + oneofs: true +} + +function parseAnyMessage(message: Any__Output): MessageType | null { + const messageType = resourceRoot.lookup(message.type_url); + if (messageType) { + const decodedMessage = (messageType as any).decode(message.value); + return decodedMessage.$type.toObject(decodedMessage, toObjectOptions) as MessageType; + } else { + return null; + } +} + +function durationToMs(duration: Duration__Output): number { + return Number.parseInt(duration.seconds) * 1000 + duration.nanos / 1_000_000; +} + +function httpCodeToGrpcStatus(code: number): status { + switch (code) { + case 400: return status.INTERNAL; + case 401: return status.UNAUTHENTICATED; + case 403: return status.PERMISSION_DENIED; + case 404: return status.UNIMPLEMENTED; + case 429: return status.UNAVAILABLE; + case 502: return status.UNAVAILABLE; + case 503: return status.UNAVAILABLE; + case 504: return status.UNAVAILABLE; + default: return status.UNKNOWN; + } +} + +function parseHTTPFaultConfig(encodedConfig: Any__Output): FaultInjectionFilterConfig | null { + if (encodedConfig.type_url !== FAULT_INJECTION_FILTER_URL) { + return null; + } + const parsedMessage = parseAnyMessage(encodedConfig); + if (parsedMessage === null) { + return null; + } + const result: FaultInjectionConfig = { + delay: null, + abort: null, + maxActiveFaults: Infinity + }; + // Parse delay field + if (parsedMessage.delay !== null) { + if (parsedMessage.delay.percentage === null) { + return null; + } + const percentage = envoyFractionToFraction(parsedMessage.delay.percentage); + switch (parsedMessage.delay.fault_delay_secifier /* sic */) { + case 'fixed_delay': + result.delay = { + kind: 'fixed', + durationMs: durationToMs(parsedMessage.delay.fixed_delay!), + percentage: percentage + }; + break; + case 'header_delay': + result.delay = { + kind: 'header', + percentage: percentage + }; + break; + default: + // Should not be possible + return null; + } + } + // Parse abort field + if (parsedMessage.abort !== null) { + if (parsedMessage.abort.percentage === null) { + return null; + } + const percentage = envoyFractionToFraction(parsedMessage.abort.percentage); + switch (parsedMessage.abort.error_type) { + case 'http_status': + result.abort = { + kind: 'grpc', + code: httpCodeToGrpcStatus(parsedMessage.abort.http_status!), + percentage: percentage + }; + break; + case 'grpc_status': + result.abort = { + kind: 'grpc', + code: parsedMessage.abort.grpc_status!, + percentage: percentage + } + break; + case 'header_abort': + result.abort = { + kind: 'header', + percentage: percentage + }; + break; + default: + // Should not be possible + return null; + } + } + // Parse max_active_faults field + if (parsedMessage.max_active_faults !== null) { + result.maxActiveFaults = parsedMessage.max_active_faults.value; + } + return { + typeUrl: FAULT_INJECTION_FILTER_URL, + config: result + }; +} + +function asyncTimeout(timeMs: number): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve(); + }, timeMs); + }); +} + +/** + * Returns true with probability numerator/denominator. + * @param numerator + * @param denominator + */ +function rollRandomPercentage(numerator: number, denominator: number): boolean { + return Math.random() * denominator < numerator; +} + +const DELAY_DURATION_HEADER_KEY = 'x-envoy-fault-delay-request'; +const DELAY_PERCENTAGE_HEADER_KEY = 'x-envoy-fault-delay-request-percentage'; +const ABORT_GRPC_HEADER_KEY = 'x-envoy-fault-abort-grpc-request'; +const ABORT_HTTP_HEADER_KEY = 'x-envoy-fault-abort-request'; +const ABORT_PERCENTAGE_HEADER_KEY = 'x-envoy-fault-abort-request-percentage'; + +const NUMBER_REGEX = /\d+/; + +let totalActiveFaults = 0; + +class FaultInjectionFilter extends BaseFilter implements Filter { + constructor(private callStream: CallStream, private config: FaultInjectionConfig) { + super(); + } + + async sendMetadata(metadataPromise: Promise): Promise { + const metadata = await metadataPromise; + // Handle delay + if (totalActiveFaults < this.config.maxActiveFaults && this.config.delay) { + let duration = 0; + let numerator = this.config.delay.percentage.numerator; + const denominator = this.config.delay.percentage.denominator; + if (this.config.delay.kind === 'fixed') { + duration = this.config.delay.durationMs; + } else { + const durationHeader = metadata.get(DELAY_DURATION_HEADER_KEY); + for (const value of durationHeader) { + if (typeof value !== 'string') { + continue; + } + if (NUMBER_REGEX.test(value)) { + duration = Number.parseInt(value); + break; + } + } + const percentageHeader = metadata.get(DELAY_PERCENTAGE_HEADER_KEY); + for (const value of percentageHeader) { + if (typeof value !== 'string') { + continue; + } + if (NUMBER_REGEX.test(value)) { + numerator = Math.min(numerator, Number.parseInt(value)); + break; + } + } + } + if (rollRandomPercentage(numerator, denominator)) { + totalActiveFaults++; + await asyncTimeout(duration); + totalActiveFaults--; + } + } + // Handle abort + if (totalActiveFaults < this.config.maxActiveFaults && this.config.abort) { + let abortStatus: status | null = null; + let numerator = this.config.abort.percentage.numerator; + const denominator = this.config.abort.percentage.denominator; + if (this.config.abort.kind === 'grpc') { + abortStatus = this.config.abort.code; + } else { + const grpcStatusHeader = metadata.get(ABORT_GRPC_HEADER_KEY); + for (const value of grpcStatusHeader) { + if (typeof value !== 'string') { + continue; + } + if (NUMBER_REGEX.test(value)) { + abortStatus = Number.parseInt(value); + break; + } + } + /* Fall back to looking for HTTP status header if the gRPC status + * header is not present. */ + if (abortStatus === null) { + const httpStatusHeader = metadata.get(ABORT_HTTP_HEADER_KEY); + for (const value of httpStatusHeader) { + if (typeof value !== 'string') { + continue; + } + if (NUMBER_REGEX.test(value)) { + abortStatus = httpCodeToGrpcStatus(Number.parseInt(value)); + break; + } + } + } + const percentageHeader = metadata.get(ABORT_PERCENTAGE_HEADER_KEY); + for (const value of percentageHeader) { + if (typeof value !== 'string') { + continue; + } + if (NUMBER_REGEX.test(value)) { + numerator = Math.min(numerator, Number.parseInt(value)); + break; + } + } + } + if (abortStatus !== null && rollRandomPercentage(numerator, denominator)) { + this.callStream.cancelWithStatus(abortStatus, 'Fault injected'); + } + } + return metadata; + } +} + +class FaultInjectionFilterFactory implements FilterFactory { + private config: FaultInjectionConfig; + constructor(config: HttpFilterConfig, overrideConfig?: HttpFilterConfig) { + if (overrideConfig?.typeUrl === FAULT_INJECTION_FILTER_URL) { + this.config = overrideConfig.config; + } else { + this.config = config.config; + } + } + + createFilter(callStream: experimental.CallStream): FaultInjectionFilter { + return new FaultInjectionFilter(callStream, this.config); + } +} + +export function setup() { + registerHttpFilter(FAULT_INJECTION_FILTER_URL, { + parseTopLevelFilterConfig: parseHTTPFaultConfig, + parseOverrideFilterConfig: parseHTTPFaultConfig, + httpFilterConstructor: FaultInjectionFilterFactory + }); +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 2fee339d1..7d35bcd1e 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -23,6 +23,7 @@ import * as load_balancer_priority from './load-balancer-priority'; import * as load_balancer_weighted_target from './load-balancer-weighted-target'; import * as load_balancer_xds_cluster_manager from './load-balancer-xds-cluster-manager'; import * as router_filter from './http-filter/router-filter'; +import * as fault_injection_filter from './http-filter/fault-injection-filter'; /** * Register the "xds:" name scheme with the @grpc/grpc-js library. @@ -36,4 +37,5 @@ export function register() { load_balancer_weighted_target.setup(); load_balancer_xds_cluster_manager.setup(); router_filter.setup(); + fault_injection_filter.setup(); } \ No newline at end of file From 36c6add3a799cb37a11d9da9cfb8ea017c58cf63 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 15:11:52 -0700 Subject: [PATCH 1493/1899] grpc-js-xds: Enable fault_injection xDS interop test --- packages/grpc-js-xds/scripts/xds.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 66fe4d568..f845abfb0 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -51,8 +51,9 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ + GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all,timeout,circuit_breaking" \ + --test_case="all,timeout,circuit_breaking,fault_injection" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From af5207262ff6c542b299ec91c82942c10baed174 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 6 Aug 2021 11:11:30 -0700 Subject: [PATCH 1494/1899] grpc-js: Check for closed server stream before sending --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/server-call.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 87a75d79f..f0e20ff10 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.6", + "version": "1.3.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index aa8bd647e..7d3fe192b 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -429,7 +429,7 @@ export class Http2ServerCallStream< private checkCancelled(): boolean { /* In some cases the stream can become destroyed before the close event * fires. That creates a race condition that this check works around */ - if (this.stream.destroyed) { + if (this.stream.destroyed || this.stream.closed) { this.cancelled = true; } return this.cancelled; From ce2765f7fb1e5694a9990ee57f1142c1c87dcfa1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 6 Aug 2021 11:53:48 -0700 Subject: [PATCH 1495/1899] grpc-js: Handle errors thrown by writing to http2 stream --- packages/grpc-js/src/call-stream.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 57693343f..8d72bb3ee 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -637,7 +637,15 @@ export class Http2CallStream implements Call { this.pendingWrite.length + ' (deferred)' ); - stream.write(this.pendingWrite, this.pendingWriteCallback); + try { + stream.write(this.pendingWrite, this.pendingWriteCallback); + } catch (error) { + this.endCall({ + code: Status.UNAVAILABLE, + details: `Write failed with error ${error.message}`, + metadata: new Metadata() + }); + } } this.maybeCloseWrites(); } @@ -762,7 +770,15 @@ export class Http2CallStream implements Call { this.pendingWriteCallback = cb; } else { this.trace('sending data chunk of length ' + message.message.length); - this.http2Stream.write(message.message, cb); + try { + this.http2Stream.write(message.message, cb); + } catch (error) { + this.endCall({ + code: Status.UNAVAILABLE, + details: `Write failed with error ${error.message}`, + metadata: new Metadata() + }); + } this.maybeCloseWrites(); } }, this.handleFilterError.bind(this)); From a0baf7c99ab37ed651a576921776a98b91284656 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 4 Aug 2021 11:54:21 -0700 Subject: [PATCH 1496/1899] Fix bugs and add tracing --- packages/grpc-js-xds/scripts/xds.sh | 2 +- packages/grpc-js-xds/src/http-filter.ts | 30 ++++++++++++++++--- .../src/http-filter/fault-injection-filter.ts | 28 ++++++++++++----- .../src/xds-stream-state/lds-state.ts | 11 +++++-- 4 files changed, 56 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index f845abfb0..8d94ae195 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -48,7 +48,7 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver \ +GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION=1 \ diff --git a/packages/grpc-js-xds/src/http-filter.ts b/packages/grpc-js-xds/src/http-filter.ts index e7ea32957..a00cde5db 100644 --- a/packages/grpc-js-xds/src/http-filter.ts +++ b/packages/grpc-js-xds/src/http-filter.ts @@ -16,7 +16,7 @@ // This is a non-public, unstable API, but it's very convenient import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; -import { experimental } from '@grpc/grpc-js'; +import { experimental, logVerbosity } from '@grpc/grpc-js'; import { Any__Output } from './generated/google/protobuf/Any'; import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; @@ -24,6 +24,12 @@ import { TypedStruct__Output } from './generated/udpa/type/v1/TypedStruct'; import { FilterConfig__Output } from './generated/envoy/config/route/v3/FilterConfig'; import { HttpFilter__Output } from './generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter'; +const TRACER_NAME = 'http_filter'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + const TYPED_STRUCT_URL = 'type.googleapis.com/udpa.type.v1.TypedStruct'; const TYPED_STRUCT_NAME = 'udpa.type.v1.TypedStruct'; @@ -37,7 +43,8 @@ const resourceRoot = loadProtosWithOptionsSync([ includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/udpa/', - __dirname + '/../../deps/envoy-api/' + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/protoc-gen-validate/' ], } ); @@ -60,6 +67,7 @@ export interface HttpFilterRegistryEntry { const FILTER_REGISTRY = new Map(); export function registerHttpFilter(typeName: string, entry: HttpFilterRegistryEntry) { + trace('Registered filter with type URL ' + typeName); FILTER_REGISTRY.set(typeName, entry); } @@ -71,7 +79,8 @@ const toObjectOptions = { } function parseAnyMessage(message: Any__Output): MessageType | null { - const messageType = resourceRoot.lookup(message.type_url); + const typeName = message.type_url.substring(message.type_url.lastIndexOf('/') + 1); + const messageType = resourceRoot.lookup(typeName); if (messageType) { const decodedMessage = (messageType as any).decode(message.value); return decodedMessage.$type.toObject(decodedMessage, toObjectOptions) as MessageType; @@ -80,7 +89,7 @@ function parseAnyMessage(message: Any__Output): MessageType | null } } -function getTopLevelFilterUrl(encodedConfig: Any__Output): string { +export function getTopLevelFilterUrl(encodedConfig: Any__Output): string { let typeUrl: string; if (encodedConfig.type_url === TYPED_STRUCT_URL) { const typedStruct = parseAnyMessage(encodedConfig) @@ -96,6 +105,7 @@ function getTopLevelFilterUrl(encodedConfig: Any__Output): string { export function validateTopLevelFilter(httpFilter: HttpFilter__Output): boolean { if (!httpFilter.typed_config) { + trace(httpFilter.name + ' validation failed: typed_config unset'); return false; } const encodedConfig = httpFilter.typed_config; @@ -103,16 +113,21 @@ export function validateTopLevelFilter(httpFilter: HttpFilter__Output): boolean try { typeUrl = getTopLevelFilterUrl(encodedConfig); } catch (e) { + trace(httpFilter.name + ' validation failed with error ' + e.message); return false; } const registryEntry = FILTER_REGISTRY.get(typeUrl); if (registryEntry) { const parsedConfig = registryEntry.parseTopLevelFilterConfig(encodedConfig); + if (parsedConfig === null) { + trace(httpFilter.name + ' validation failed: config parsing failed'); + } return parsedConfig !== null; } else { if (httpFilter.is_optional) { return true; } else { + trace(httpFilter.name + ' validation failed: filter is not optional and registry does not contain type URL ' + typeUrl); return false; } } @@ -129,9 +144,11 @@ export function validateOverrideFilter(encodedConfig: Any__Output): boolean { if (filterConfig.config) { realConfig = filterConfig.config; } else { + trace('Override filter validation failed: FilterConfig config field is empty'); return false; } } else { + trace('Override filter validation failed: failed to parse FilterConfig message'); return false; } } else { @@ -142,6 +159,7 @@ export function validateOverrideFilter(encodedConfig: Any__Output): boolean { if (typedStruct) { typeUrl = typedStruct.type_url; } else { + trace('Override filter validation failed: failed to parse TypedStruct message'); return false; } } else { @@ -150,11 +168,15 @@ export function validateOverrideFilter(encodedConfig: Any__Output): boolean { const registryEntry = FILTER_REGISTRY.get(typeUrl); if (registryEntry) { const parsedConfig = registryEntry.parseOverrideFilterConfig(encodedConfig); + if (parsedConfig === null) { + trace('Override filter validation failed: config parsing failed. Type URL: ' + typeUrl); + } return parsedConfig !== null; } else { if (isOptional) { return true; } else { + trace('Override filter validation failed: filter is not optional and registry does not contain type URL ' + typeUrl); return false; } } diff --git a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts index 825b7c058..e0ee658c7 100644 --- a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts +++ b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts @@ -16,7 +16,7 @@ // This is a non-public, unstable API, but it's very convenient import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; -import { experimental, Metadata, status } from '@grpc/grpc-js'; +import { experimental, logVerbosity, Metadata, status } from '@grpc/grpc-js'; import { Any__Output } from '../generated/google/protobuf/Any'; import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; @@ -27,14 +27,20 @@ import { HTTPFault__Output } from '../generated/envoy/extensions/filters/http/fa import { envoyFractionToFraction, Fraction } from '../fraction'; import { Duration__Output } from '../generated/google/protobuf/Duration'; +const TRACER_NAME = 'fault_injection'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + const resourceRoot = loadProtosWithOptionsSync([ - 'envoy/extendsion/filtesr/http/fault/v3/fault.proto'], { + 'envoy/extensions/filters/http/fault/v3/fault.proto'], { keepCase: true, includeDirs: [ - // Paths are relative to src/build - __dirname + '/../../deps/udpa/', - __dirname + '/../../deps/envoy-api/', - __dirname + '/../../deps/protoc-gen-validate/' + // Paths are relative to src/build/http-filter + __dirname + '/../../../deps/udpa/', + __dirname + '/../../../deps/envoy-api/', + __dirname + '/../../../deps/protoc-gen-validate/' ], } ); @@ -82,7 +88,8 @@ const toObjectOptions = { } function parseAnyMessage(message: Any__Output): MessageType | null { - const messageType = resourceRoot.lookup(message.type_url); + const typeName = message.type_url.substring(message.type_url.lastIndexOf('/') + 1); + const messageType = resourceRoot.lookup(typeName); if (messageType) { const decodedMessage = (messageType as any).decode(message.value); return decodedMessage.$type.toObject(decodedMessage, toObjectOptions) as MessageType; @@ -111,12 +118,15 @@ function httpCodeToGrpcStatus(code: number): status { function parseHTTPFaultConfig(encodedConfig: Any__Output): FaultInjectionFilterConfig | null { if (encodedConfig.type_url !== FAULT_INJECTION_FILTER_URL) { + trace('Config parsing failed: unexpected type URL: ' + encodedConfig.type_url); return null; } const parsedMessage = parseAnyMessage(encodedConfig); if (parsedMessage === null) { + trace('Config parsing failed: failed to parse HTTPFault message'); return null; } + trace('Parsing HTTPFault message ' + JSON.stringify(parsedMessage, undefined, 2)); const result: FaultInjectionConfig = { delay: null, abort: null, @@ -125,6 +135,7 @@ function parseHTTPFaultConfig(encodedConfig: Any__Output): FaultInjectionFilterC // Parse delay field if (parsedMessage.delay !== null) { if (parsedMessage.delay.percentage === null) { + trace('Config parsing failed: delay.percentage unset'); return null; } const percentage = envoyFractionToFraction(parsedMessage.delay.percentage); @@ -143,6 +154,7 @@ function parseHTTPFaultConfig(encodedConfig: Any__Output): FaultInjectionFilterC }; break; default: + trace('Config parsing failed: delay.fault_delay_secifier has unexpected value ' + parsedMessage.delay.fault_delay_secifier); // Should not be possible return null; } @@ -150,6 +162,7 @@ function parseHTTPFaultConfig(encodedConfig: Any__Output): FaultInjectionFilterC // Parse abort field if (parsedMessage.abort !== null) { if (parsedMessage.abort.percentage === null) { + trace('Config parsing failed: abort.percentage unset'); return null; } const percentage = envoyFractionToFraction(parsedMessage.abort.percentage); @@ -175,6 +188,7 @@ function parseHTTPFaultConfig(encodedConfig: Any__Output): FaultInjectionFilterC }; break; default: + trace('Config parsing failed: abort.error_type has unexpected value ' + parsedMessage.abort.error_type); // Should not be possible return null; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 3efc64b92..8ab6ed9d2 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -22,7 +22,7 @@ import { RdsState } from "./rds-state"; import { Watcher, XdsStreamState } from "./xds-stream-state"; import { HttpConnectionManager__Output } from '../generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V2, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from '../resources'; -import { validateTopLevelFilter } from '../http-filter'; +import { getTopLevelFilterUrl, validateTopLevelFilter } from '../http-filter'; import { EXPERIMENTAL_FAULT_INJECTION } from '../environment'; const TRACER_NAME = 'xds_client'; @@ -108,20 +108,25 @@ export class LdsState implements XdsStreamState { const filterNames = new Set(); for (const [index, httpFilter] of httpConnectionManager.http_filters.entries()) { if (filterNames.has(httpFilter.name)) { + trace('LDS response validation failed: duplicate HTTP filter name ' + httpFilter.name); return false; } filterNames.add(httpFilter.name); if (!validateTopLevelFilter(httpFilter)) { + trace('LDS response validation failed: ' + httpFilter.name + ' filter validation failed'); return false; } /* Validate that the last filter, and only the last filter, is the * router filter. */ + const filterUrl = getTopLevelFilterUrl(httpFilter.typed_config!) if (index < httpConnectionManager.http_filters.length - 1) { - if (httpFilter.name === ROUTER_FILTER_URL) { + if (filterUrl === ROUTER_FILTER_URL) { + trace('LDS response validation failed: router filter is before end of list'); return false; } } else { - if (httpFilter.name !== ROUTER_FILTER_URL) { + if (filterUrl !== ROUTER_FILTER_URL) { + trace('LDS response validation failed: final filter is ' + filterUrl); return false; } } From cd50baed558ff8697113d4fadfd4842af3665111 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 10 Aug 2021 09:48:56 -0700 Subject: [PATCH 1497/1899] Add .gitattributes marking generated code in xDS package --- .gitattributes | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..f0957c311 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +packages/grpc-js-xds/src/generated/** linguist-generated +packages/grpc-js-xds/interop/generated/** linguist-generated From 875f483cf6fd5a6b67cafa96dccbef6f4f24a87b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 10 Aug 2021 14:20:11 -0700 Subject: [PATCH 1498/1899] grpc-js: Map ETIMEDOUT errors to UNAVAILABLE --- packages/grpc-js/src/call-stream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 5e034433a..c829f4229 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -601,7 +601,7 @@ export class Http2CallStream implements Call { * "Internal server error" message. */ details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; } else { - if (this.internalError.code === 'ECONNRESET') { + if (this.internalError.code === 'ECONNRESET' || this.internalError.code === 'ETIMEDOUT') { code = Status.UNAVAILABLE; details = this.internalError.message; } else { From 64a0b0ad7cd28e73e1e28ecad32437652f1bcc60 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 17 Aug 2021 14:59:22 -0700 Subject: [PATCH 1499/1899] grpc-js-xds: Distinguish v2 and v3 when handling messages --- packages/grpc-js-xds/src/resolver-xds.ts | 24 ++++++++++--------- packages/grpc-js-xds/src/xds-client.ts | 23 ++++++++++++++---- .../src/xds-stream-state/cds-state.ts | 9 ++++--- .../src/xds-stream-state/eds-state.ts | 9 ++++--- .../src/xds-stream-state/lds-state.ts | 17 +++++++------ .../src/xds-stream-state/rds-state.ts | 19 ++++++++------- .../src/xds-stream-state/xds-stream-state.ts | 9 +++++-- 7 files changed, 72 insertions(+), 38 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index f6287ea67..ab036184e 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -212,6 +212,7 @@ class XdsResolver implements Resolver { private latestRouteConfigName: string | null = null; private latestRouteConfig: RouteConfiguration__Output | null = null; + private latestRouteConfigIsV2 = false; private clusterRefcounts = new Map(); @@ -225,7 +226,7 @@ class XdsResolver implements Resolver { private channelOptions: ChannelOptions ) { this.ldsWatcher = { - onValidUpdate: (update: Listener__Output) => { + onValidUpdate: (update: Listener__Output, isV2: boolean) => { const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, update.api_listener!.api_listener!.value); const defaultTimeout = httpConnectionManager.common_http_protocol_options?.idle_timeout; if (defaultTimeout === null || defaultTimeout === undefined) { @@ -233,7 +234,7 @@ class XdsResolver implements Resolver { } else { this.latestDefaultTimeout = protoDurationToDuration(defaultTimeout); } - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { this.ldsHttpFilterConfigs = []; for (const filter of httpConnectionManager.http_filters) { // typed_config must be set here, or validation would have failed @@ -259,7 +260,7 @@ class XdsResolver implements Resolver { if (this.latestRouteConfigName) { getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); } - this.handleRouteConfig(httpConnectionManager.route_config!); + this.handleRouteConfig(httpConnectionManager.route_config!, isV2); break; default: // This is prevented by the validation rules @@ -279,8 +280,8 @@ class XdsResolver implements Resolver { } }; this.rdsWatcher = { - onValidUpdate: (update: RouteConfiguration__Output) => { - this.handleRouteConfig(update); + onValidUpdate: (update: RouteConfiguration__Output, isV2: boolean) => { + this.handleRouteConfig(update, isV2); }, onTransientError: (error: StatusObject) => { /* A transient error only needs to bubble up as a failure if we have @@ -310,20 +311,21 @@ class XdsResolver implements Resolver { refCount.refCount -= 1; if (!refCount.inLastConfig && refCount.refCount === 0) { this.clusterRefcounts.delete(clusterName); - this.handleRouteConfig(this.latestRouteConfig!); + this.handleRouteConfig(this.latestRouteConfig!, this.latestRouteConfigIsV2); } } } - private handleRouteConfig(routeConfig: RouteConfiguration__Output) { + private handleRouteConfig(routeConfig: RouteConfiguration__Output, isV2: boolean) { this.latestRouteConfig = routeConfig; + this.latestRouteConfigIsV2 = isV2; const virtualHost = findVirtualHostForDomain(routeConfig.virtual_hosts, this.target.path); if (virtualHost === null) { this.reportResolutionError('No matching route found'); return; } const virtualHostHttpFilterOverrides = new Map(); - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filter] of Object.entries(virtualHost.typed_per_filter_config ?? {})) { const parsedConfig = parseOverrideFilterConfig(filter); if (parsedConfig) { @@ -352,7 +354,7 @@ class XdsResolver implements Resolver { timeout = undefined; } const routeHttpFilterOverrides = new Map(); - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filter] of Object.entries(route.typed_per_filter_config ?? {})) { const parsedConfig = parseOverrideFilterConfig(filter); if (parsedConfig) { @@ -367,7 +369,7 @@ class XdsResolver implements Resolver { const cluster = route.route!.cluster!; allConfigClusters.add(cluster); const extraFilterFactories: FilterFactory[] = []; - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const filterConfig of this.ldsHttpFilterConfigs) { if (routeHttpFilterOverrides.has(filterConfig.name)) { const filter = createHttpFilter(filterConfig.config, routeHttpFilterOverrides.get(filterConfig.name)!); @@ -396,7 +398,7 @@ class XdsResolver implements Resolver { allConfigClusters.add(clusterWeight.name); const extraFilterFactories: FilterFactory[] = []; const clusterHttpFilterOverrides = new Map(); - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filter] of Object.entries(clusterWeight.typed_per_filter_config ?? {})) { const parsedConfig = parseOverrideFilterConfig(filter); if (parsedConfig) { diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 6828a8a8e..952ae81f4 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -435,32 +435,47 @@ export class XdsClient { private handleAdsResponse(message: DiscoveryResponse__Output) { let errorString: string | null; let serviceKind: AdsServiceKind; + let isV2: boolean; + switch (message.type_url) { + case EDS_TYPE_URL_V2: + case CDS_TYPE_URL_V2: + case RDS_TYPE_URL_V2: + case LDS_TYPE_URL_V2: + isV2 = true; + break; + default: + isV2 = false; + } switch (message.type_url) { case EDS_TYPE_URL_V2: case EDS_TYPE_URL_V3: errorString = this.adsState.eds.handleResponses( - getResponseMessages(EDS_TYPE_URL_V3, [EDS_TYPE_URL_V2, EDS_TYPE_URL_V3], message.resources) + getResponseMessages(EDS_TYPE_URL_V3, [EDS_TYPE_URL_V2, EDS_TYPE_URL_V3], message.resources), + isV2 ); serviceKind = 'eds'; break; case CDS_TYPE_URL_V2: case CDS_TYPE_URL_V3: errorString = this.adsState.cds.handleResponses( - getResponseMessages(CDS_TYPE_URL_V3, [CDS_TYPE_URL_V2, CDS_TYPE_URL_V3], message.resources) + getResponseMessages(CDS_TYPE_URL_V3, [CDS_TYPE_URL_V2, CDS_TYPE_URL_V3], message.resources), + isV2 ); serviceKind = 'cds'; break; case RDS_TYPE_URL_V2: case RDS_TYPE_URL_V3: errorString = this.adsState.rds.handleResponses( - getResponseMessages(RDS_TYPE_URL_V3, [RDS_TYPE_URL_V2, RDS_TYPE_URL_V3], message.resources) + getResponseMessages(RDS_TYPE_URL_V3, [RDS_TYPE_URL_V2, RDS_TYPE_URL_V3], message.resources), + isV2 ); serviceKind = 'rds'; break; case LDS_TYPE_URL_V2: case LDS_TYPE_URL_V3: errorString = this.adsState.lds.handleResponses( - getResponseMessages(LDS_TYPE_URL_V3, [LDS_TYPE_URL_V2, LDS_TYPE_URL_V3], message.resources) + getResponseMessages(LDS_TYPE_URL_V3, [LDS_TYPE_URL_V2, LDS_TYPE_URL_V3], message.resources), + isV2 ); serviceKind = 'lds'; break; diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index a6e89805d..7720c5673 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -36,6 +36,7 @@ export class CdsState implements XdsStreamState { >(); private latestResponses: Cluster__Output[] = []; + private latestIsV2 = false; constructor( private edsState: EdsState, @@ -61,13 +62,14 @@ export class CdsState implements XdsStreamState { /* If we have already received an update for the requested edsServiceName, * immediately pass that update along to the watcher */ + const isV2 = this.latestIsV2; for (const message of this.latestResponses) { if (message.name === clusterName) { /* These updates normally occur asynchronously, so we ensure that * the same happens here */ process.nextTick(() => { trace('Reporting existing CDS update for new watcher for clusterName ' + clusterName); - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); }); } } @@ -134,7 +136,7 @@ export class CdsState implements XdsStreamState { } } - handleResponses(responses: Cluster__Output[]): string | null { + handleResponses(responses: Cluster__Output[], isV2: boolean): string | null { for (const message of responses) { if (!this.validateResponse(message)) { trace('CDS validation failed for message ' + JSON.stringify(message)); @@ -142,6 +144,7 @@ export class CdsState implements XdsStreamState { } } this.latestResponses = responses; + this.latestIsV2 = isV2; const allEdsServiceNames: Set = new Set(); const allClusterNames: Set = new Set(); for (const message of responses) { @@ -152,7 +155,7 @@ export class CdsState implements XdsStreamState { ); const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); } } trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index a0fb5f4dc..dbf18ef81 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -36,6 +36,7 @@ export class EdsState implements XdsStreamState { > = new Map[]>(); private latestResponses: ClusterLoadAssignment__Output[] = []; + private latestIsV2 = false; constructor(private updateResourceNames: () => void) {} @@ -61,13 +62,14 @@ export class EdsState implements XdsStreamState { /* If we have already received an update for the requested edsServiceName, * immediately pass that update along to the watcher */ + const isV2 = this.latestIsV2; for (const message of this.latestResponses) { if (message.cluster_name === edsServiceName) { /* These updates normally occur asynchronously, so we ensure that * the same happens here */ process.nextTick(() => { trace('Reporting existing EDS update for new watcher for edsServiceName ' + edsServiceName); - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); }); } } @@ -143,7 +145,7 @@ export class EdsState implements XdsStreamState { } } - handleResponses(responses: ClusterLoadAssignment__Output[]) { + handleResponses(responses: ClusterLoadAssignment__Output[], isV2: boolean) { for (const message of responses) { if (!this.validateResponse(message)) { trace('EDS validation failed for message ' + JSON.stringify(message)); @@ -151,12 +153,13 @@ export class EdsState implements XdsStreamState { } } this.latestResponses = responses; + this.latestIsV2 = isV2; const allClusterNames: Set = new Set(); for (const message of responses) { allClusterNames.add(message.cluster_name); const watchers = this.watchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); } } trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 8ab6ed9d2..7e8ec0456 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -39,6 +39,7 @@ export class LdsState implements XdsStreamState { private watchers: Map[]> = new Map[]>(); private latestResponses: Listener__Output[] = []; + private latestIsV2 = false; constructor(private rdsState: RdsState, private updateResourceNames: () => void) {} @@ -55,13 +56,14 @@ export class LdsState implements XdsStreamState { /* If we have already received an update for the requested edsServiceName, * immediately pass that update along to the watcher */ + const isV2 = this.latestIsV2; for (const message of this.latestResponses) { if (message.name === targetName) { /* These updates normally occur asynchronously, so we ensure that * the same happens here */ process.nextTick(() => { trace('Reporting existing RDS update for new watcher for targetName ' + targetName); - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); }); } } @@ -93,7 +95,7 @@ export class LdsState implements XdsStreamState { return Array.from(this.watchers.keys()); } - private validateResponse(message: Listener__Output): boolean { + private validateResponse(message: Listener__Output, isV2: boolean): boolean { if ( !( message.api_listener?.api_listener && @@ -104,7 +106,7 @@ export class LdsState implements XdsStreamState { return false; } const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener.value); - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { const filterNames = new Set(); for (const [index, httpFilter] of httpConnectionManager.http_filters.entries()) { if (filterNames.has(httpFilter.name)) { @@ -136,7 +138,7 @@ export class LdsState implements XdsStreamState { case 'rds': return !!httpConnectionManager.rds?.config_source?.ads; case 'route_config': - return this.rdsState.validateResponse(httpConnectionManager.route_config!); + return this.rdsState.validateResponse(httpConnectionManager.route_config!, isV2); } return false; } @@ -151,20 +153,21 @@ export class LdsState implements XdsStreamState { } } - handleResponses(responses: Listener__Output[]): string | null { + handleResponses(responses: Listener__Output[], isV2: boolean): string | null { for (const message of responses) { - if (!this.validateResponse(message)) { + if (!this.validateResponse(message, isV2)) { trace('LDS validation failed for message ' + JSON.stringify(message)); return 'LDS Error: Route validation failed'; } } this.latestResponses = responses; + this.latestIsV2 = isV2; const allTargetNames = new Set(); for (const message of responses) { allTargetNames.add(message.name); const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); } } trace('Received RDS response with route config names ' + Array.from(allTargetNames)); diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 58f11f0b4..9194529d8 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -45,6 +45,7 @@ export class RdsState implements XdsStreamState { private watchers: Map[]> = new Map[]>(); private latestResponses: RouteConfiguration__Output[] = []; + private latestIsV2 = false; constructor(private updateResourceNames: () => void) {} @@ -61,13 +62,14 @@ export class RdsState implements XdsStreamState { /* If we have already received an update for the requested edsServiceName, * immediately pass that update along to the watcher */ + const isV2 = this.latestIsV2; for (const message of this.latestResponses) { if (message.name === routeConfigName) { /* These updates normally occur asynchronously, so we ensure that * the same happens here */ process.nextTick(() => { trace('Reporting existing RDS update for new watcher for routeConfigName ' + routeConfigName); - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); }); } } @@ -99,7 +101,7 @@ export class RdsState implements XdsStreamState { return Array.from(this.watchers.keys()); } - validateResponse(message: RouteConfiguration__Output): boolean { + validateResponse(message: RouteConfiguration__Output, isV2: boolean): boolean { // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation for (const virtualHost of message.virtual_hosts) { for (const domainPattern of virtualHost.domains) { @@ -114,7 +116,7 @@ export class RdsState implements XdsStreamState { return false; } } - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const filterConfig of Object.values(virtualHost.typed_per_filter_config ?? {})) { if (!validateOverrideFilter(filterConfig)) { return false; @@ -140,7 +142,7 @@ export class RdsState implements XdsStreamState { if ((route.route === undefined) || (route.route === null) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { return false; } - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filterConfig] of Object.entries(route.typed_per_filter_config ?? {})) { if (!validateOverrideFilter(filterConfig)) { return false; @@ -155,7 +157,7 @@ export class RdsState implements XdsStreamState { if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { return false; } - if (EXPERIMENTAL_FAULT_INJECTION) { + if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { for (const weightedCluster of route.route!.weighted_clusters!.clusters) { for (const filterConfig of Object.values(weightedCluster.typed_per_filter_config ?? {})) { if (!validateOverrideFilter(filterConfig)) { @@ -180,20 +182,21 @@ export class RdsState implements XdsStreamState { } } - handleResponses(responses: RouteConfiguration__Output[]): string | null { + handleResponses(responses: RouteConfiguration__Output[], isV2: boolean): string | null { for (const message of responses) { - if (!this.validateResponse(message)) { + if (!this.validateResponse(message, isV2)) { trace('RDS validation failed for message ' + JSON.stringify(message)); return 'RDS Error: Route validation failed'; } } this.latestResponses = responses; + this.latestIsV2 = isV2; const allRouteConfigNames = new Set(); for (const message of responses) { allRouteConfigNames.add(message.name); const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { - watcher.onValidUpdate(message); + watcher.onValidUpdate(message, isV2); } } trace('Received RDS response with route config names ' + Array.from(allRouteConfigNames)); diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 83db1781e..14f3d1c76 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -18,7 +18,12 @@ import { StatusObject } from "@grpc/grpc-js"; export interface Watcher { - onValidUpdate(update: UpdateType): void; + /* Including the isV2 flag here is a bit of a kludge. It would probably be + * better for XdsStreamState#handleResponses to transform the protobuf + * message type into a library-specific configuration object type, to + * remove a lot of duplicate logic, including logic for handling that + * flag. */ + onValidUpdate(update: UpdateType, isV2: boolean): void; onTransientError(error: StatusObject): void; onResourceDoesNotExist(): void; } @@ -32,7 +37,7 @@ export interface XdsStreamState { * or null if it should be acked. * @param responses */ - handleResponses(responses: ResponseType[]): string | null; + handleResponses(responses: ResponseType[], isV2: boolean): string | null; reportStreamError(status: StatusObject): void; } \ No newline at end of file From d4574a28fbaba840454bd62914a5d980661b0f31 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Aug 2021 09:28:32 -0700 Subject: [PATCH 1500/1899] grpc-js: Add channelz support --- packages/grpc-js/src/call-stream.ts | 14 + packages/grpc-js/src/channel.ts | 43 ++- packages/grpc-js/src/channelz.ts | 345 ++++++++++++++++++ .../src/load-balancer-child-handler.ts | 8 + .../grpc-js/src/load-balancer-pick-first.ts | 5 + .../grpc-js/src/load-balancer-round-robin.ts | 2 + packages/grpc-js/src/load-balancer.ts | 3 + .../grpc-js/src/resolving-load-balancer.ts | 8 +- packages/grpc-js/src/server-call.ts | 11 +- packages/grpc-js/src/server.ts | 233 ++++++++++-- packages/grpc-js/src/subchannel-address.ts | 17 + packages/grpc-js/src/subchannel.ts | 166 ++++++++- packages/grpc-tools/deps/protobuf | 2 +- 13 files changed, 826 insertions(+), 31 deletions(-) create mode 100644 packages/grpc-js/src/channelz.ts diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 87121154d..e030d9e39 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -249,6 +249,9 @@ export class Http2CallStream implements Call { private configDeadline: Deadline = Infinity; + private statusWatchers: ((status: StatusObject) => void)[] = []; + private streamEndWatchers: ((success: boolean) => void)[] = []; + constructor( private readonly methodName: string, private readonly channel: ChannelImplementation, @@ -283,6 +286,7 @@ export class Http2CallStream implements Call { const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! ); + this.statusWatchers.forEach(watcher => watcher(filteredStatus)); /* We delay the actual action of bubbling up the status to insulate the * cleanup code in this class from any errors that may be thrown in the * upper layers as a result of bubbling up the status. In particular, @@ -426,6 +430,7 @@ export class Http2CallStream implements Call { } private handleTrailers(headers: http2.IncomingHttpHeaders) { + this.streamEndWatchers.forEach(watcher => watcher(true)); let headersString = ''; for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; @@ -647,6 +652,7 @@ export class Http2CallStream implements Call { ); this.internalError = err; } + this.streamEndWatchers.forEach(watcher => watcher(false)); }); if (!this.pendingRead) { stream.pause(); @@ -736,6 +742,14 @@ export class Http2CallStream implements Call { this.configDeadline = configDeadline; } + addStatusWatcher(watcher: (status: StatusObject) => void) { + this.statusWatchers.push(watcher); + } + + addStreamEndWatcher(watcher: (success: boolean) => void) { + this.streamEndWatchers.push(watcher); + } + startRead() { /* If the stream has ended with an error, we should not emit any more * messages and we should communicate that the stream has ended */ diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 9200043e4..4a6e88147 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -47,6 +47,7 @@ import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; import { SurfaceCall } from './call'; import { ConnectivityState } from './connectivity-state'; +import { ChannelInfo, ChannelRef, ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzChannel, SubchannelRef, unregisterChannelzRef } from './channelz'; /** * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args @@ -160,6 +161,13 @@ export class ChannelImplementation implements Channel { */ private callRefTimer: NodeJS.Timer; private configSelector: ConfigSelector | null = null; + + // Channelz info + private channelzRef: ChannelRef; + private channelzTrace: ChannelzTrace; + private callTracker = new ChannelzCallTracker(); + private childrenTracker = new ChannelzChildrenTracker(); + constructor( target: string, private readonly credentials: ChannelCredentials, @@ -204,6 +212,10 @@ export class ChannelImplementation implements Channel { this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME); this.callRefTimer.unref?.(); + this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo()); + this.channelzTrace = new ChannelzTrace(); + this.channelzTrace.addTrace('CT_INFO', 'Channel created'); + if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; } else { @@ -223,12 +235,14 @@ export class ChannelImplementation implements Channel { subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions ) => { - return this.subchannelPool.getOrCreateSubchannel( + const subchannel = this.subchannelPool.getOrCreateSubchannel( this.target, subchannelAddress, Object.assign({}, this.options, subchannelArgs), this.credentials ); + this.channelzTrace.addTrace('CT_INFO', 'Created or got existing subchannel', subchannel.getChannelzRef()); + return subchannel; }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.currentPicker = picker; @@ -246,12 +260,19 @@ export class ChannelImplementation implements Channel { 'Resolving load balancer should never call requestReresolution' ); }, + addChannelzChild: (child: ChannelRef | SubchannelRef) => { + this.childrenTracker.refChild(child); + }, + removeChannelzChild: (child: ChannelRef | SubchannelRef) => { + this.childrenTracker.unrefChild(child); + } }; this.resolvingLoadBalancer = new ResolvingLoadBalancer( this.target, channelControlHelper, options, (configSelector) => { + this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); this.configSelector = configSelector; /* We process the queue asynchronously to ensure that the corresponding * load balancer update has completed. */ @@ -266,6 +287,7 @@ export class ChannelImplementation implements Channel { }); }, (status) => { + this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); if (this.configSelectionQueue.length > 0) { trace( LogVerbosity.DEBUG, @@ -296,6 +318,15 @@ export class ChannelImplementation implements Channel { ]); } + private getChannelzInfo(): ChannelInfo { + return { + state: this.connectivityState, + trace: this.channelzTrace, + callTracker: this.callTracker, + children: this.childrenTracker.getChildLists() + }; + } + private callRefTimerRef() { // If the hasRef function does not exist, always run the code if (!this.callRefTimer.hasRef?.()) { @@ -526,6 +557,7 @@ export class ChannelImplementation implements Channel { ' -> ' + ConnectivityState[newState] ); + this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); this.connectivityState = newState; const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { @@ -590,6 +622,7 @@ export class ChannelImplementation implements Channel { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); clearInterval(this.callRefTimer); + unregisterChannelzRef(this.channelzRef); this.subchannelPool.unrefUnusedSubchannels(); } @@ -685,6 +718,14 @@ export class ChannelImplementation implements Channel { this.credentials._getCallCredentials(), callNumber ); + this.callTracker.addCallStarted(); + stream.addStatusWatcher(status => { + if (status.code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }); return stream; } } diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts new file mode 100644 index 000000000..3edbd7bba --- /dev/null +++ b/packages/grpc-js/src/channelz.ts @@ -0,0 +1,345 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { isIPv4, isIPv6 } from "net"; +import { ConnectivityState } from "./connectivity-state"; +import { SubchannelAddress } from "./subchannel-address"; + +export type TraceSeverity = 'CT_UNKNOWN' | 'CT_INFO' | 'CT_WARNING' | 'CT_ERROR'; + +export interface ChannelRef { + kind: 'channel'; + id: number; + name: string; +} + +export interface SubchannelRef { + kind: 'subchannel'; + id: number; + name: string; +} + +export interface ServerRef { + kind: 'server'; + id: number; +} + +export interface SocketRef { + kind: 'socket'; + id: number; + name: string; +} + +interface TraceEvent { + description: string; + severity: TraceSeverity; + timestamp: Date; + childChannel?: ChannelRef; + childSubchannel?: SubchannelRef; +} + +export class ChannelzTrace { + events: TraceEvent[] = []; + creationTimestamp: Date; + eventsLogged: number = 0; + + constructor() { + this.creationTimestamp = new Date(); + } + + addTrace(severity: TraceSeverity, description: string, child?: ChannelRef | SubchannelRef) { + const timestamp = new Date(); + this.events.push({ + description: description, + severity: severity, + timestamp: timestamp, + childChannel: child?.kind === 'channel' ? child : undefined, + childSubchannel: child?.kind === 'subchannel' ? child : undefined + }); + this.eventsLogged += 1; + } +} + +export class ChannelzChildrenTracker { + private channelChildren: Map = new Map(); + private subchannelChildren: Map = new Map(); + private socketChildren: Map = new Map(); + + refChild(child: ChannelRef | SubchannelRef | SocketRef) { + switch (child.kind) { + case 'channel': { + let trackedChild = this.channelChildren.get(child.id) ?? {ref: child, count: 0}; + trackedChild.count += 1; + this.channelChildren.set(child.id, trackedChild); + break; + } + case 'subchannel':{ + let trackedChild = this.subchannelChildren.get(child.id) ?? {ref: child, count: 0}; + trackedChild.count += 1; + this.subchannelChildren.set(child.id, trackedChild); + break; + } + case 'socket':{ + let trackedChild = this.socketChildren.get(child.id) ?? {ref: child, count: 0}; + trackedChild.count += 1; + this.socketChildren.set(child.id, trackedChild); + break; + } + } + } + + unrefChild(child: ChannelRef | SubchannelRef | SocketRef) { + switch (child.kind) { + case 'channel': { + let trackedChild = this.channelChildren.get(child.id); + if (trackedChild !== undefined) { + trackedChild.count -= 1; + if (trackedChild.count === 0) { + this.channelChildren.delete(child.id); + } else { + this.channelChildren.set(child.id, trackedChild); + } + } + break; + } + case 'subchannel': { + let trackedChild = this.subchannelChildren.get(child.id); + if (trackedChild !== undefined) { + trackedChild.count -= 1; + if (trackedChild.count === 0) { + this.subchannelChildren.delete(child.id); + } else { + this.subchannelChildren.set(child.id, trackedChild); + } + } + break; + } + case 'socket': { + let trackedChild = this.socketChildren.get(child.id); + if (trackedChild !== undefined) { + trackedChild.count -= 1; + if (trackedChild.count === 0) { + this.socketChildren.delete(child.id); + } else { + this.socketChildren.set(child.id, trackedChild); + } + } + break; + } + } + } + + getChildLists(): ChannelzChildren { + const channels: ChannelRef[] = []; + for (const {ref} of this.channelChildren.values()) { + channels.push(ref); + } + const subchannels: SubchannelRef[] = []; + for (const {ref} of this.subchannelChildren.values()) { + subchannels.push(ref); + } + const sockets: SocketRef[] = []; + for (const {ref} of this.socketChildren.values()) { + sockets.push(ref); + } + return {channels, subchannels, sockets}; + } +} + +export class ChannelzCallTracker { + callsStarted: number = 0; + callsSucceeded: number = 0; + callsFailed: number = 0; + lastCallStartedTimestamp: Date | null = null; + + addCallStarted() { + this.callsStarted += 1; + this.lastCallStartedTimestamp = new Date(); + } + addCallSucceeded() { + this.callsSucceeded += 1; + } + addCallFailed() { + this.callsFailed += 1; + } +} + +export interface ChannelzChildren { + channels: ChannelRef[]; + subchannels: SubchannelRef[]; + sockets: SocketRef[]; +} + +export interface ChannelInfo { + state: ConnectivityState; + trace: ChannelzTrace; + callTracker: ChannelzCallTracker; + children: ChannelzChildren; +} + +export interface SubchannelInfo extends ChannelInfo {} + +export interface ServerInfo { + trace: ChannelzTrace; + callTracker: ChannelzCallTracker; + children: ChannelzChildren; +} + +export interface TlsInfo { + cipherSuiteStandardName: string | null; + cipherSuiteOtherName: string | null; + localCertificate: Buffer | null; + remoteCertificate: Buffer | null; +} + +export interface SocketInfo { + localAddress: SubchannelAddress; + remoteAddress: SubchannelAddress | null; + security: TlsInfo | null; + remoteName: string | null; + streamsStarted: number; + streamsSucceeded: number; + streamsFailed: number; + messagesSent: number; + messagesReceived: number; + keepAlivesSent: number; + lastLocalStreamCreatedTimestamp: Date | null; + lastRemoteStreamCreatedTimestamp: Date | null; + lastMessageSentTimestamp: Date | null; + lastMessageReceivedTimestamp: Date | null; + localFlowControlWindow: number | null; + remoteFlowControlWindow: number | null; +} + +interface ChannelEntry { + ref: ChannelRef; + getInfo(): ChannelInfo; +} + +interface SubchannelEntry { + ref: SubchannelRef; + getInfo(): SubchannelInfo; +} + +interface ServerEntry { + ref: ServerRef; + getInfo(): ServerInfo; +} + +interface SocketEntry { + ref: SocketRef; + getInfo(): SocketInfo; +} + +let nextId = 1; + +function getNextId(): number { + return nextId++; +} + +const channels: (ChannelEntry | undefined)[] = []; +const subchannels: (SubchannelEntry | undefined)[] = []; +const servers: (ServerEntry | undefined)[] = []; +const sockets: (SocketEntry | undefined)[] = []; + +export function registerChannelzChannel(name: string, getInfo: () => ChannelInfo): ChannelRef { + const id = getNextId(); + const ref: ChannelRef = {id, name, kind: 'channel'}; + channels[id] = { ref, getInfo }; + return ref; +} + +export function registerChannelzSubchannel(name: string, getInfo:() => SubchannelInfo): SubchannelRef { + const id = getNextId(); + const ref: SubchannelRef = {id, name, kind: 'subchannel'}; + subchannels[id] = { ref, getInfo }; + return ref; +} + +export function registerChannelzServer(getInfo: () => ServerInfo): ServerRef { + const id = getNextId(); + const ref: ServerRef = {id, kind: 'server'}; + servers[id] = { ref, getInfo }; + return ref; +} + +export function registerChannelzSocket(name: string, getInfo: () => SocketInfo): SocketRef { + const id = getNextId(); + const ref: SocketRef = {id, name, kind: 'socket'}; + sockets[id] = { ref, getInfo}; + return ref; +} + +export function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRef | SocketRef) { + switch (ref.kind) { + case 'channel': + delete channels[ref.id]; + return; + case 'subchannel': + delete subchannels[ref.id]; + return; + case 'server': + delete servers[ref.id]; + return; + case 'socket': + delete sockets[ref.id]; + return; + } +} + +export interface ChannelzClientView { + updateState(connectivityState: ConnectivityState): void; + addTrace(severity: TraceSeverity, description: string, child?: ChannelRef | SubchannelRef): void; + addCallStarted(): void; + addCallSucceeded(): void; + addCallFailed(): void; + addChild(child: ChannelRef | SubchannelRef): void; + removeChild(child: ChannelRef | SubchannelRef): void; +} + +export interface ChannelzSubchannelView extends ChannelzClientView { + getRef(): SubchannelRef; +} + +/** + * Converts an IPv4 or IPv6 address from string representation to binary + * representation + * @param ipAddress an IP address in standard IPv4 or IPv6 text format + * @returns + */ +function ipAddressStringToBuffer(ipAddress: string): Buffer | null { + if (isIPv4(ipAddress)) { + return Buffer.from(Uint8Array.from(ipAddress.split('.').map(segment => Number.parseInt(segment)))); + } else if (isIPv6(ipAddress)) { + let leftSection: string; + let rightSection: string | null; + const doubleColonIndex = ipAddress.indexOf('::'); + if (doubleColonIndex === -1) { + leftSection = ipAddress; + rightSection = null; + } else { + leftSection = ipAddress.substring(0, doubleColonIndex); + rightSection = ipAddress.substring(doubleColonIndex + 2); + } + const leftBuffer = Uint8Array.from(leftSection.split(':').map(segment => Number.parseInt(segment, 16))); + const rightBuffer = rightSection ? Uint8Array.from(rightSection.split(':').map(segment => Number.parseInt(segment, 16))) : new Uint8Array(); + const middleBuffer = Buffer.alloc(16 - leftBuffer.length - rightBuffer.length, 0); + return Buffer.concat([leftBuffer, middleBuffer, rightBuffer]); + } else { + return null; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 8fae7b8a6..c53914942 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -26,6 +26,7 @@ import { SubchannelAddress } from './subchannel-address'; import { ChannelOptions } from './channel-options'; import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; +import { ChannelRef, SubchannelRef } from './channelz'; const TYPE_NAME = 'child_load_balancer_helper'; @@ -67,6 +68,13 @@ export class ChildLoadBalancerHandler implements LoadBalancer { setChild(newChild: LoadBalancer) { this.child = newChild; } + addChannelzChild(child: ChannelRef | SubchannelRef) { + this.parent.channelControlHelper.addChannelzChild(child); + } + removeChannelzChild(child: ChannelRef | SubchannelRef) { + this.parent.channelControlHelper.removeChannelzChild(child); + } + private calledByPendingChild(): boolean { return this.child === this.parent.pendingChild; } diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 65179b163..6cdb7cb91 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -229,6 +229,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { subchannel.removeConnectivityStateListener( this.pickedSubchannelStateListener ); + this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef()); if (this.subchannels.length > 0) { if (this.triedAllSubchannels) { let newLBState: ConnectivityState; @@ -321,6 +322,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); subchannel.addConnectivityStateListener(this.pickedSubchannelStateListener); subchannel.ref(); + this.channelControlHelper.addChannelzChild(subchannel.getChannelzRef()); this.resetSubchannelList(); clearTimeout(this.connectionDelayTimeout); } @@ -339,6 +341,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { for (const subchannel of this.subchannels) { subchannel.removeConnectivityStateListener(this.subchannelStateListener); subchannel.unref(); + this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef()); } this.currentSubchannelIndex = 0; this.subchannelStateCounts = { @@ -369,6 +372,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { ); for (const subchannel of this.subchannels) { subchannel.ref(); + this.channelControlHelper.addChannelzChild(subchannel.getChannelzRef()); } for (const subchannel of this.subchannels) { subchannel.addConnectivityStateListener(this.subchannelStateListener); @@ -449,6 +453,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.currentPick.removeConnectivityStateListener( this.pickedSubchannelStateListener ); + this.channelControlHelper.removeChannelzChild(this.currentPick.getChannelzRef()); } } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 56703397f..918afab25 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -191,6 +191,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { for (const subchannel of this.subchannels) { subchannel.removeConnectivityStateListener(this.subchannelStateListener); subchannel.unref(); + this.channelControlHelper.removeChannelzChild(subchannel.getChannelzRef()); } this.subchannelStateCounts = { [ConnectivityState.CONNECTING]: 0, @@ -217,6 +218,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { for (const subchannel of this.subchannels) { subchannel.ref(); subchannel.addConnectivityStateListener(this.subchannelStateListener); + this.channelControlHelper.addChannelzChild(subchannel.getChannelzRef()); const subchannelState = subchannel.getConnectivityState(); this.subchannelStateCounts[subchannelState] += 1; if ( diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index f509f73eb..870fdb30b 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -20,6 +20,7 @@ import { Subchannel } from './subchannel'; import { SubchannelAddress } from './subchannel-address'; import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; +import { ChannelRef, SubchannelRef } from './channelz'; /** * A collection of functions associated with a channel that a load balancer @@ -47,6 +48,8 @@ export interface ChannelControlHelper { * Request new data from the resolver. */ requestReresolution(): void; + addChannelzChild(child: ChannelRef | SubchannelRef): void; + removeChannelzChild(child: ChannelRef | SubchannelRef): void; } /** diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 5729937d1..a03991bc7 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -75,7 +75,7 @@ function getDefaultConfigSelector( return { methodConfig: { name: [] }, pickInformation: {}, - status: Status.OK, + status: Status.OK }; }; } @@ -170,6 +170,12 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.latestChildPicker = picker; this.updateState(newState, picker); }, + addChannelzChild: channelControlHelper.addChannelzChild.bind( + channelControlHelper + ), + removeChannelzChild: channelControlHelper.removeChannelzChild.bind( + channelControlHelper + ) }); this.innerResolver = createResolver( target, diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 4d24cdc86..cde7d9185 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -411,6 +411,8 @@ export class Http2ServerCallStream< ); this.cancelled = true; this.emit('cancelled', 'cancelled'); + this.emit('streamEnd', false); + this.sendStatus({code: Status.CANCELLED, details: 'Cancelled by client', metadata: new Metadata()}); }); this.stream.on('drain', () => { @@ -513,6 +515,7 @@ export class Http2ServerCallStream< resolve(); } + this.emit('receiveMessage'); resolve(this.deserializeMessage(requestBytes)); } catch (err) { err.code = Status.INTERNAL; @@ -567,6 +570,7 @@ export class Http2ServerCallStream< const response = this.serializeMessage(value!); this.write(response); + this.emit('sendMessage'); this.sendStatus({ code: Status.OK, details: 'OK', metadata }); } catch (err) { err.code = Status.INTERNAL; @@ -575,6 +579,8 @@ export class Http2ServerCallStream< } sendStatus(statusObj: StatusObject) { + this.emit('callEnd', statusObj.code); + this.emit('streamEnd', statusObj.code === Status.OK); if (this.checkCancelled()) { return; } @@ -609,9 +615,6 @@ export class Http2ServerCallStream< } sendError(error: ServerErrorResponse | ServerStatusResponse) { - if (this.checkCancelled()) { - return; - } const status: StatusObject = { code: Status.UNKNOWN, details: 'message' in error ? error.message : 'Unknown Error', @@ -653,6 +656,7 @@ export class Http2ServerCallStream< } this.sendMetadata(); + this.emit('sendMessage'); return this.stream.write(chunk); } @@ -688,6 +692,7 @@ export class Http2ServerCallStream< }); return; } + this.emit('receiveMessage'); this.pushOrBufferMessage(readable, message); } }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 42b79a3cf..04c24c072 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -56,8 +56,11 @@ import { TcpSubchannelAddress, isTcpSubchannelAddress, subchannelAddressToString, + stringToSubchannelAddress, } from './subchannel-address'; import { parseUri } from './uri-parser'; +import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; +import { CipherNameAndProtocol, TLSSocket } from 'tls'; const TRACER_NAME = 'server'; @@ -125,19 +128,91 @@ function getDefaultHandler(handlerType: HandlerType, methodName: string) { } } +interface ChannelzSessionInfo { + ref: SocketRef; + streamTracker: ChannelzCallTracker; + messagesSent: number; + messagesReceived: number; + lastMessageSentTimestamp: Date | null; + lastMessageReceivedTimestamp: Date | null; +} + +interface ChannelzListenerInfo { + ref: SocketRef; +} + export class Server { - private http2ServerList: (http2.Http2Server | http2.Http2SecureServer)[] = []; + private http2ServerList: { server: (http2.Http2Server | http2.Http2SecureServer), channelzRef: SocketRef }[] = []; private handlers: Map = new Map< string, UntypedHandler >(); - private sessions = new Set(); + private sessions = new Map(); private started = false; private options: ChannelOptions; + // Channelz Info + private channelzRef: ServerRef; + private channelzTrace = new ChannelzTrace(); + private callTracker = new ChannelzCallTracker(); + private childrenTracker = new ChannelzChildrenTracker(); + constructor(options?: ChannelOptions) { this.options = options ?? {}; + this.channelzRef = registerChannelzServer(() => this.getChannelzInfo()); + this.channelzTrace.addTrace('CT_INFO', 'Server created'); + } + + private getChannelzInfo(): ServerInfo { + return { + trace: this.channelzTrace, + callTracker: this.callTracker, + children: this.childrenTracker.getChildLists() + }; + } + + private getChannelzSessionInfoGetter(session: http2.ServerHttp2Session): () => SocketInfo { + return () => { + const sessionInfo = this.sessions.get(session)!; + const sessionSocket = session.socket; + const remoteAddress = sessionSocket.remoteAddress ? stringToSubchannelAddress(sessionSocket.remoteAddress, sessionSocket.remotePort) : null; + const localAddress = stringToSubchannelAddress(sessionSocket.localAddress, sessionSocket.localPort); + let tlsInfo: TlsInfo | null; + if (session.encrypted) { + const tlsSocket: TLSSocket = sessionSocket as TLSSocket; + const cipherInfo: CipherNameAndProtocol & {standardName?: string} = tlsSocket.getCipher(); + const certificate = tlsSocket.getCertificate(); + const peerCertificate = tlsSocket.getPeerCertificate(); + tlsInfo = { + cipherSuiteStandardName: cipherInfo.standardName ?? null, + cipherSuiteOtherName: cipherInfo.standardName ? cipherInfo.name: null, + localCertificate: (certificate && 'raw' in certificate) ? certificate.raw : null, + remoteCertificate: (peerCertificate && 'raw' in peerCertificate) ? peerCertificate.raw : null + }; + } else { + tlsInfo = null; + } + const socketInfo: SocketInfo = { + remoteAddress: remoteAddress, + localAddress: localAddress, + security: tlsInfo, + remoteName: null, + streamsStarted: sessionInfo.streamTracker.callsStarted, + streamsSucceeded: sessionInfo.streamTracker.callsSucceeded, + streamsFailed: sessionInfo.streamTracker.callsFailed, + messagesSent: sessionInfo.messagesSent, + messagesReceived: sessionInfo.messagesReceived, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: sessionInfo.streamTracker.lastCallStartedTimestamp, + lastMessageSentTimestamp: sessionInfo.lastMessageSentTimestamp, + lastMessageReceivedTimestamp: sessionInfo.lastMessageReceivedTimestamp, + localFlowControlWindow: session.state.localWindowSize ?? null, + remoteFlowControlWindow: session.state.remoteWindowSize ?? null + }; + return socketInfo; + }; } addProtoService(): void { @@ -315,14 +390,41 @@ export class Server { http2Server.once('error', onError); http2Server.listen(addr, () => { - trace('Successfully bound ' + subchannelAddressToString(address)); - this.http2ServerList.push(http2Server); const boundAddress = http2Server.address()!; + let boundSubchannelAddress: SubchannelAddress; if (typeof boundAddress === 'string') { - resolve(portNum); + boundSubchannelAddress = { + path: boundAddress + }; } else { - resolve(boundAddress.port); + boundSubchannelAddress = { + host: boundAddress.address, + port: boundAddress.port + } } + const channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { + return { + localAddress: boundSubchannelAddress, + remoteAddress: null, + security: null, + remoteName: null, + streamsStarted: 0, + streamsSucceeded: 0, + streamsFailed: 0, + messagesSent: 0, + messagesReceived: 0, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null, + localFlowControlWindow: null, + remoteFlowControlWindow: null + }; + }); + this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); + trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); + resolve('port' in boundSubchannelAddress ? boundSubchannelAddress.port : portNum); http2Server.removeListener('error', onError); }); }); @@ -362,11 +464,37 @@ export class Server { http2Server.once('error', onError); http2Server.listen(address, () => { - this.http2ServerList.push(http2Server); + const boundAddress = http2Server.address() as AddressInfo; + const boundSubchannelAddress: SubchannelAddress = { + host: boundAddress.address, + port: boundAddress.port + }; + const channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { + return { + localAddress: boundSubchannelAddress, + remoteAddress: null, + security: null, + remoteName: null, + streamsStarted: 0, + streamsSucceeded: 0, + streamsFailed: 0, + messagesSent: 0, + messagesReceived: 0, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null, + localFlowControlWindow: null, + remoteFlowControlWindow: null + }; + }); + this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); + trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve( bindSpecificPort( addressList.slice(1), - (http2Server.address() as AddressInfo).port, + boundAddress.port, 1 ) ); @@ -437,9 +565,12 @@ export class Server { forceShutdown(): void { // Close the server if it is still running. - for (const http2Server of this.http2ServerList) { + for (const {server: http2Server, channelzRef: ref} of this.http2ServerList) { if (http2Server.listening) { - http2Server.close(); + http2Server.close(() => { + this.childrenTracker.unrefChild(ref); + unregisterChannelzRef(ref); + }); } } @@ -447,13 +578,14 @@ export class Server { // Always destroy any available sessions. It's possible that one or more // tryShutdown() calls are in progress. Don't wait on them to finish. - this.sessions.forEach((session) => { + this.sessions.forEach((channelzInfo, session) => { // Cast NGHTTP2_CANCEL to any because TypeScript doesn't seem to // recognize destroy(code) as a valid signature. // eslint-disable-next-line @typescript-eslint/no-explicit-any session.destroy(http2.constants.NGHTTP2_CANCEL as any); }); this.sessions.clear(); + unregisterChannelzRef(this.channelzRef); } register( @@ -485,7 +617,7 @@ export class Server { if ( this.http2ServerList.length === 0 || this.http2ServerList.every( - (http2Server) => http2Server.listening !== true + ({server: http2Server}) => http2Server.listening !== true ) ) { throw new Error('server must be bound in order to start'); @@ -494,39 +626,47 @@ export class Server { if (this.started === true) { throw new Error('server is already started'); } - + this.channelzTrace.addTrace('CT_INFO', 'Starting'); this.started = true; } tryShutdown(callback: (error?: Error) => void): void { + const wrappedCallback = (error?: Error) => { + unregisterChannelzRef(this.channelzRef); + callback(error); + }; let pendingChecks = 0; function maybeCallback(): void { pendingChecks--; if (pendingChecks === 0) { - callback(); + wrappedCallback(); } } // Close the server if necessary. this.started = false; - for (const http2Server of this.http2ServerList) { + for (const {server: http2Server, channelzRef: ref} of this.http2ServerList) { if (http2Server.listening) { pendingChecks++; - http2Server.close(maybeCallback); + http2Server.close(() => { + this.childrenTracker.unrefChild(ref); + unregisterChannelzRef(ref); + maybeCallback(); + }); } } - this.sessions.forEach((session) => { + this.sessions.forEach((channelzInfo, session) => { if (!session.closed) { pendingChecks += 1; session.close(maybeCallback); } }); if (pendingChecks === 0) { - callback(); + wrappedCallback(); } } @@ -544,6 +684,9 @@ export class Server { http2Server.on( 'stream', (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { + const channelzSessionInfo = this.sessions.get(stream.session as http2.ServerHttp2Session); + this.callTracker.addCallStarted(); + channelzSessionInfo?.streamTracker.addCallStarted(); const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; if ( @@ -557,9 +700,13 @@ export class Server { }, { endStream: true } ); + this.callTracker.addCallFailed(); + channelzSessionInfo?.streamTracker.addCallFailed(); return; } + let call: Http2ServerCallStream | null = null; + try { const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; const serverAddress = http2Server.address(); @@ -589,7 +736,31 @@ export class Server { throw getUnimplementedStatusResponse(path); } - const call = new Http2ServerCallStream(stream, handler, this.options); + call = new Http2ServerCallStream(stream, handler, this.options); + call.once('callEnd', (code: Status) => { + if (code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }); + if (channelzSessionInfo) { + call.once('streamEnd', (success: boolean) => { + if (success) { + channelzSessionInfo.streamTracker.addCallSucceeded(); + } else { + channelzSessionInfo.streamTracker.addCallFailed(); + } + }); + call.on('sendMessage', () => { + channelzSessionInfo.messagesSent += 1; + channelzSessionInfo.lastMessageSentTimestamp = new Date(); + }); + call.on('receiveMessage', () => { + channelzSessionInfo.messagesReceived += 1; + channelzSessionInfo.lastMessageReceivedTimestamp = new Date(); + }); + } const metadata: Metadata = call.receiveMetadata(headers) as Metadata; switch (handler.type) { case 'unary': @@ -620,7 +791,11 @@ export class Server { throw new Error(`Unknown handler type: ${handler.type}`); } } catch (err) { - const call = new Http2ServerCallStream(stream, null!, this.options); + if (!call) { + call = new Http2ServerCallStream(stream, null!, this.options); + this.callTracker.addCallFailed(); + channelzSessionInfo?.streamTracker.addCallFailed() + } if (err.code === undefined) { err.code = Status.INTERNAL; @@ -637,9 +812,25 @@ export class Server { return; } - this.sessions.add(session); + const channelzRef = registerChannelzSocket(session.socket.remoteAddress ?? 'unknown', this.getChannelzSessionInfoGetter(session)); + + const channelzSessionInfo: ChannelzSessionInfo = { + ref: channelzRef, + streamTracker: new ChannelzCallTracker(), + messagesSent: 0, + messagesReceived: 0, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null + }; + this.sessions.set(session, channelzSessionInfo); + const clientAddress = session.socket.remoteAddress; + this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); + this.childrenTracker.refChild(channelzRef); session.on('close', () => { + this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); + this.childrenTracker.unrefChild(channelzRef); + unregisterChannelzRef(channelzRef); this.sessions.delete(session); }); }); diff --git a/packages/grpc-js/src/subchannel-address.ts b/packages/grpc-js/src/subchannel-address.ts index 4b08d8ba1..29022caa5 100644 --- a/packages/grpc-js/src/subchannel-address.ts +++ b/packages/grpc-js/src/subchannel-address.ts @@ -15,6 +15,8 @@ * */ +import { isIP } from "net"; + export interface TcpSubchannelAddress { port: number; host: string; @@ -60,3 +62,18 @@ export function subchannelAddressToString(address: SubchannelAddress): string { return address.path; } } + +const DEFAULT_PORT = 443; + +export function stringToSubchannelAddress(addressString: string, port?: number): SubchannelAddress { + if (isIP(addressString)) { + return { + host: addressString, + port: port ?? DEFAULT_PORT + }; + } else { + return { + path: addressString + }; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index ae23feb3d..1caf94ba1 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -18,23 +18,25 @@ import * as http2 from 'http2'; import { ChannelCredentials } from './channel-credentials'; import { Metadata } from './metadata'; -import { Http2CallStream } from './call-stream'; +import { Call, Http2CallStream, WriteObject } from './call-stream'; import { ChannelOptions } from './channel-options'; -import { PeerCertificate, checkServerIdentity } from 'tls'; +import { PeerCertificate, checkServerIdentity, TLSSocket, CipherNameAndProtocol } from 'tls'; import { ConnectivityState } from './connectivity-state'; import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; -import { LogVerbosity } from './constants'; +import { LogVerbosity, Status } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { ConnectionOptions } from 'tls'; -import { FilterFactory, Filter } from './filter'; +import { FilterFactory, Filter, BaseFilter } from './filter'; import { + stringToSubchannelAddress, SubchannelAddress, subchannelAddressToString, } from './subchannel-address'; +import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, SocketInfo, SocketRef, unregisterChannelzRef, registerChannelzSocket, TlsInfo } from './channelz'; const clientVersion = require('../../package.json').version; @@ -157,6 +159,53 @@ export class Subchannel { */ private subchannelAddressString: string; + // Channelz info + private channelzRef: SubchannelRef; + private channelzTrace: ChannelzTrace; + private callTracker = new ChannelzCallTracker(); + private childrenTracker = new ChannelzChildrenTracker(); + + // Channelz socket info + private channelzSocketRef: SocketRef | null = null; + /** + * Name of the remote server, if it is not the same as the subchannel + * address, i.e. if connecting through an HTTP CONNECT proxy. + */ + private remoteName: string | null = null; + private streamTracker = new ChannelzCallTracker(); + private keepalivesSent = 0; + private messagesSent = 0; + private messagesReceived = 0; + private lastMessageSentTimestamp: Date | null = null; + private lastMessageReceivedTimestamp: Date | null = null; + private MessageCountFilter = class extends BaseFilter implements Filter { + private session: http2.ClientHttp2Session; + constructor(private parent: Subchannel) { + super(); + this.session = parent.session!; + } + sendMessage(message: Promise): Promise { + if (this.parent.session === this.session) { + this.parent.messagesSent += 1; + this.parent.lastMessageSentTimestamp = new Date(); + } + return message; + } + receiveMessage(message: Promise): Promise { + if (this.parent.session === this.session) { + this.parent.messagesReceived += 1; + this.parent.lastMessageReceivedTimestamp = new Date(); + } + return message; + } + }; + private MessageCountFilterFactory = class implements FilterFactory { + constructor(private parent: Subchannel) {} + createFilter(callStream: Call): Filter { + return new this.parent.MessageCountFilter(this.parent); + } + } + /** * A class representing a connection to a single backend. * @param channelTarget The target string for the channel as a whole @@ -206,6 +255,77 @@ export class Subchannel { this.handleBackoffTimer(); }, backoffOptions); this.subchannelAddressString = subchannelAddressToString(subchannelAddress); + + this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo()); + this.channelzTrace = new ChannelzTrace(); + this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); + } + + private getChannelzInfo(): SubchannelInfo { + return { + state: this.connectivityState, + trace: this.channelzTrace, + callTracker: this.callTracker, + children: this.childrenTracker.getChildLists() + }; + } + + private getChannelzSocketInfo(): SocketInfo | null { + if (this.session === null) { + return null; + } + const sessionSocket = this.session.socket; + const remoteAddress = sessionSocket.remoteAddress ? stringToSubchannelAddress(sessionSocket.remoteAddress, sessionSocket.remotePort) : null; + const localAddress = stringToSubchannelAddress(sessionSocket.localAddress, sessionSocket.localPort); + let tlsInfo: TlsInfo | null; + if (this.session.encrypted) { + const tlsSocket: TLSSocket = sessionSocket as TLSSocket; + const cipherInfo: CipherNameAndProtocol & {standardName?: string} = tlsSocket.getCipher(); + const certificate = tlsSocket.getCertificate(); + const peerCertificate = tlsSocket.getPeerCertificate(); + tlsInfo = { + cipherSuiteStandardName: cipherInfo.standardName ?? null, + cipherSuiteOtherName: cipherInfo.standardName ? cipherInfo.name: null, + localCertificate: (certificate && 'raw' in certificate) ? certificate.raw : null, + remoteCertificate: (peerCertificate && 'raw' in peerCertificate) ? peerCertificate.raw : null + }; + } else { + tlsInfo = null; + } + const socketInfo: SocketInfo = { + remoteAddress: remoteAddress, + localAddress: localAddress, + security: tlsInfo, + remoteName: this.remoteName, + streamsStarted: this.streamTracker.callsStarted, + streamsSucceeded: this.streamTracker.callsSucceeded, + streamsFailed: this.streamTracker.callsFailed, + messagesSent: this.messagesSent, + messagesReceived: this.messagesReceived, + keepAlivesSent: this.keepalivesSent, + lastLocalStreamCreatedTimestamp: this.streamTracker.lastCallStartedTimestamp, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: this.lastMessageSentTimestamp, + lastMessageReceivedTimestamp: this.lastMessageReceivedTimestamp, + localFlowControlWindow: this.session.state.localWindowSize ?? null, + remoteFlowControlWindow: this.session.state.remoteWindowSize ?? null + }; + return socketInfo; + } + + private resetChannelzSocketInfo() { + if (this.channelzSocketRef) { + unregisterChannelzRef(this.channelzSocketRef); + this.childrenTracker.unrefChild(this.channelzSocketRef); + this.channelzSocketRef = null; + } + this.remoteName = null; + this.streamTracker = new ChannelzCallTracker(); + this.keepalivesSent = 0; + this.messagesSent = 0; + this.messagesReceived = 0; + this.lastMessageSentTimestamp = null; + this.lastMessageReceivedTimestamp = null; } private handleBackoffTimer() { @@ -235,6 +355,7 @@ export class Subchannel { } private sendPing() { + this.keepalivesSent += 1; logging.trace( LogVerbosity.DEBUG, 'keepalive', @@ -266,6 +387,11 @@ export class Subchannel { } private createSession(proxyConnectionResult: ProxyConnectionResult) { + if (proxyConnectionResult.realTarget) { + this.remoteName = uriToString(proxyConnectionResult.realTarget); + } else { + this.remoteName = null; + } const targetAuthority = getDefaultAuthority( proxyConnectionResult.realTarget ?? this.channelTarget ); @@ -353,6 +479,8 @@ export class Subchannel { connectionOptions ); this.session = session; + this.channelzSocketRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!); + this.childrenTracker.refChild(this.channelzSocketRef); session.unref(); /* For all of these events, check if the session at the time of the event * is the same one currently attached to this subchannel, to ensure that @@ -425,6 +553,7 @@ export class Subchannel { (error as Error).message ); }); + registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!); } private startConnectingInternal() { @@ -506,6 +635,7 @@ export class Subchannel { ' -> ' + ConnectivityState[newState] ); + this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); const previousState = this.connectivityState; this.connectivityState = newState; switch (newState) { @@ -530,6 +660,7 @@ export class Subchannel { this.session.close(); } this.session = null; + this.resetChannelzSocketInfo(); this.stopKeepalivePings(); /* If the backoff timer has already ended by the time we get to the * TRANSIENT_FAILURE state, we want to immediately transition out of @@ -545,6 +676,7 @@ export class Subchannel { this.session.close(); } this.session = null; + this.resetChannelzSocketInfo(); this.stopKeepalivePings(); break; default: @@ -566,10 +698,12 @@ export class Subchannel { /* If no calls, channels, or subchannel pools have any more references to * this subchannel, we can be sure it will never be used again. */ if (this.callRefcount === 0 && this.refcount === 0) { + this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], ConnectivityState.TRANSIENT_FAILURE ); + unregisterChannelzRef(this.channelzRef); } } @@ -694,6 +828,26 @@ export class Subchannel { ' with headers\n' + headersString ); + this.callTracker.addCallStarted(); + callStream.addStatusWatcher(status => { + if (status.code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }); + const streamSession = this.session; + this.streamTracker.addCallStarted(); + callStream.addStreamEndWatcher(success => { + if (streamSession === this.session) { + if (success) { + this.streamTracker.addCallSucceeded(); + } else { + this.streamTracker.addCallFailed(); + } + } + }); + extraFilterFactories.push(new this.MessageCountFilterFactory(this)); callStream.attachHttp2Stream(http2Stream, this, extraFilterFactories); } @@ -773,4 +927,8 @@ export class Subchannel { getAddress(): string { return this.subchannelAddressString; } + + getChannelzRef(): SubchannelRef { + return this.channelzRef; + } } diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index 6aa539bf0..a6e1cc7e3 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit 6aa539bf0195f188ff86efe6fb8bfa2b676cdd46 +Subproject commit a6e1cc7e328c45a0cb9856c530c8f6cd23314163 From 2efe0918a8724e081309a243c14a9c0fc9968c85 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 31 Aug 2021 11:45:15 -0700 Subject: [PATCH 1501/1899] grpc-js-xds: Enable fault injection feature by default --- packages/grpc-js-xds/scripts/xds.sh | 1 - packages/grpc-js-xds/src/environment.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 8d94ae195..131cbd551 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -51,7 +51,6 @@ grpc/tools/run_tests/helper_scripts/prep_xds.sh GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ - GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all,timeout,circuit_breaking,fault_injection" \ --project_id=grpc-testing \ diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index 18e9e70bd..e1c2d8158 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -15,4 +15,4 @@ * */ -export const EXPERIMENTAL_FAULT_INJECTION = process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION; \ No newline at end of file +export const EXPERIMENTAL_FAULT_INJECTION = (process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION ?? 'true') === 'true'; \ No newline at end of file From ca5045df8c91d9362aff74be702c4e9244c3083c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 31 Aug 2021 11:53:15 -0700 Subject: [PATCH 1502/1899] grpc-js-xds: Update readme feature list --- packages/grpc-js-xds/README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index bcea70456..84d291508 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -22,4 +22,8 @@ const client = new MyServiceClient('xds:///example.com:123'); ## Supported Features - [xDS-Based Global Load Balancing](https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md) - - [xDS traffic splitting and routing](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) \ No newline at end of file + - [xDS traffic splitting and routing](https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md) + - [xDS v3 API](https://github.com/grpc/proposal/blob/master/A30-xds-v3.md) + - [xDS Timeouts](https://github.com/grpc/proposal/blob/master/A31-xds-timeout-support-and-config-selector.md) + - [xDS Circuit Breaking](https://github.com/grpc/proposal/blob/master/A32-xds-circuit-breaking.md) + - [xDS Client-Side Fault Injection](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) \ No newline at end of file From 7a3dd6eb296f0b892867fcba61a2c640dcf35007 Mon Sep 17 00:00:00 2001 From: Pratyay Banerjee <48355572+Neilblaze@users.noreply.github.com> Date: Thu, 2 Sep 2021 22:54:56 +0530 Subject: [PATCH 1503/1899] =?UTF-8?q?fix(docs):=20supporst=20=E2=9F=B6=20s?= =?UTF-8?q?upports?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Pratyay Banerjee <48355572+Neilblaze@users.noreply.github.com> --- TROUBLESHOOTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index dd5bce7af..89903392a 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -4,7 +4,7 @@ This guide is for troubleshooting the `grpc-js` library for Node.js ## Enabling extra logging and tracing -Extra logging can be very useful for diagnosing problems. `grpc-js` supporst +Extra logging can be very useful for diagnosing problems. `grpc-js` support the `GRPC_VERBOSITY` and `GRPC_TRACE` environment variables that can be used to increase the amount of information that gets printed to stderr. From f9ae440b1cc0b4c78c9a7b8a295c9e4d2cb07ac8 Mon Sep 17 00:00:00 2001 From: Pratyay Banerjee <48355572+Neilblaze@users.noreply.github.com> Date: Thu, 2 Sep 2021 23:00:11 +0530 Subject: [PATCH 1504/1899] updated with an extra 's' Signed-off-by: Pratyay Banerjee <48355572+Neilblaze@users.noreply.github.com> --- TROUBLESHOOTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 89903392a..bfcf94edc 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -4,7 +4,7 @@ This guide is for troubleshooting the `grpc-js` library for Node.js ## Enabling extra logging and tracing -Extra logging can be very useful for diagnosing problems. `grpc-js` support +Extra logging can be very useful for diagnosing problems. `grpc-js` supports the `GRPC_VERBOSITY` and `GRPC_TRACE` environment variables that can be used to increase the amount of information that gets printed to stderr. From c95219b1ea46c1db2d0e2edb817a3ed4232f1749 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Sep 2021 14:36:40 -0700 Subject: [PATCH 1505/1899] proto-loader: Avoid generating conflicting method names in service clients --- .../bin/proto-loader-gen-types.ts | 35 +++++++++++++++++++ packages/proto-loader/package.json | 2 +- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index b441d425e..6c9596980 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -454,6 +454,38 @@ function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum formatter.writeLine('}'); } +/** + * This is a list of methods that are exist in the generic Client class in the + * gRPC libraries. TypeScript has a problem with methods in subclasses with the + * same names as methods in the superclass, but with mismatched APIs. So, we + * avoid generating methods with these names in the service client interfaces. + * We always generate two service client methods per service method: one camel + * cased, and one with the original casing. So we will still generate one + * service client method for any conflicting name. + * + * Technically, at runtime conflicting name in the service client method + * actually shadows the original method, but TypeScript does not have a good + * way to represent that. So this change is not 100% accurate, but it gets the + * generated code to compile. + * + * This is just a list of the methods in the Client class definitions in + * grpc@1.24.11 and @grpc/grpc-js@1.4.0. + */ +const CLIENT_RESERVED_METHOD_NAMES = new Set([ + 'close', + 'getChannel', + 'waitForReady', + 'makeUnaryRequest', + 'makeClientStreamRequest', + 'makeServerStreamRequest', + 'makeBidiStreamRequest', + 'resolveCallInterceptors', + /* These methods are private, but TypeScript is not happy with overriding even + * private methods with mismatched APIs. */ + 'checkOptionalUnaryResponseArguments', + 'checkMetadataAndOptions' +]); + function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { if (options.includeComments) { formatComment(formatter, serviceType.comment); @@ -463,6 +495,9 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; for (const name of [methodName, camelCase(methodName)]) { + if (CLIENT_RESERVED_METHOD_NAMES.has(name)) { + continue; + } if (options.includeComments) { formatComment(formatter, method.comment); } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 824fa6f5e..9418df982 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.4", + "version": "0.6.5", "author": "Google Inc.", "contributors": [ { From bf0df1f94a04c1d41374af588b7c212f299ef56d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Sep 2021 14:21:48 -0700 Subject: [PATCH 1506/1899] Add channelz.proto and generated code --- packages/grpc-js/package.json | 5 +- packages/grpc-js/proto/channelz.proto | 564 ++++++++++++++++++ packages/grpc-js/src/generated/channelz.ts | 73 +++ .../src/generated/google/protobuf/Any.ts | 13 + .../generated/google/protobuf/BoolValue.ts | 10 + .../generated/google/protobuf/BytesValue.ts | 10 + .../generated/google/protobuf/DoubleValue.ts | 10 + .../src/generated/google/protobuf/Duration.ts | 13 + .../generated/google/protobuf/FloatValue.ts | 10 + .../generated/google/protobuf/Int32Value.ts | 10 + .../generated/google/protobuf/Int64Value.ts | 11 + .../generated/google/protobuf/StringValue.ts | 10 + .../generated/google/protobuf/Timestamp.ts | 13 + .../generated/google/protobuf/UInt32Value.ts | 10 + .../generated/google/protobuf/UInt64Value.ts | 11 + .../src/generated/grpc/channelz/v1/Address.ts | 89 +++ .../src/generated/grpc/channelz/v1/Channel.ts | 68 +++ .../channelz/v1/ChannelConnectivityState.ts | 29 + .../generated/grpc/channelz/v1/ChannelData.ts | 76 +++ .../generated/grpc/channelz/v1/ChannelRef.ts | 31 + .../grpc/channelz/v1/ChannelTrace.ts | 45 ++ .../grpc/channelz/v1/ChannelTraceEvent.ts | 73 +++ .../generated/grpc/channelz/v1/Channelz.ts | 178 ++++++ .../grpc/channelz/v1/GetChannelRequest.ts | 17 + .../grpc/channelz/v1/GetChannelResponse.ts | 19 + .../grpc/channelz/v1/GetServerRequest.ts | 17 + .../grpc/channelz/v1/GetServerResponse.ts | 19 + .../channelz/v1/GetServerSocketsRequest.ts | 39 ++ .../channelz/v1/GetServerSocketsResponse.ts | 33 + .../grpc/channelz/v1/GetServersRequest.ts | 37 ++ .../grpc/channelz/v1/GetServersResponse.ts | 33 + .../grpc/channelz/v1/GetSocketRequest.ts | 29 + .../grpc/channelz/v1/GetSocketResponse.ts | 19 + .../grpc/channelz/v1/GetSubchannelRequest.ts | 17 + .../grpc/channelz/v1/GetSubchannelResponse.ts | 19 + .../grpc/channelz/v1/GetTopChannelsRequest.ts | 37 ++ .../channelz/v1/GetTopChannelsResponse.ts | 33 + .../generated/grpc/channelz/v1/Security.ts | 87 +++ .../src/generated/grpc/channelz/v1/Server.ts | 45 ++ .../generated/grpc/channelz/v1/ServerData.ts | 57 ++ .../generated/grpc/channelz/v1/ServerRef.ts | 31 + .../src/generated/grpc/channelz/v1/Socket.ts | 70 +++ .../generated/grpc/channelz/v1/SocketData.ts | 150 +++++ .../grpc/channelz/v1/SocketOption.ts | 47 ++ .../grpc/channelz/v1/SocketOptionLinger.ts | 33 + .../grpc/channelz/v1/SocketOptionTcpInfo.ts | 74 +++ .../grpc/channelz/v1/SocketOptionTimeout.ts | 19 + .../generated/grpc/channelz/v1/SocketRef.ts | 31 + .../generated/grpc/channelz/v1/Subchannel.ts | 70 +++ .../grpc/channelz/v1/SubchannelRef.ts | 31 + 50 files changed, 2473 insertions(+), 2 deletions(-) create mode 100644 packages/grpc-js/proto/channelz.proto create mode 100644 packages/grpc-js/src/generated/channelz.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Any.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/BoolValue.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/BytesValue.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Duration.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/FloatValue.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Int32Value.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Int64Value.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/StringValue.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/Timestamp.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts create mode 100644 packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Address.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Channel.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ChannelConnectivityState.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ChannelData.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ChannelRef.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTrace.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTraceEvent.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetServerRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetServerResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetServersRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetServersResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsRequest.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsResponse.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Security.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Server.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ServerData.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/ServerRef.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Socket.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SocketData.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SocketOption.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionLinger.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTcpInfo.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTimeout.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SocketRef.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/Subchannel.ts create mode 100644 packages/grpc-js/src/generated/grpc/channelz/v1/SubchannelRef.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 79df40c52..7d8cd611d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -15,7 +15,6 @@ "types": "build/src/index.d.ts", "license": "Apache-2.0", "devDependencies": { - "@grpc/proto-loader": "^0.5.5", "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", "@types/lodash": "^4.14.108", @@ -54,9 +53,11 @@ "check": "gts check src/**/*.ts", "fix": "gts fix src/*.ts", "pretest": "npm run compile", - "posttest": "npm run check && madge -c ./build/src" + "posttest": "npm run check && madge -c ./build/src", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O src/generated/ --grpcLib ../index channelz.proto" }, "dependencies": { + "@grpc/proto-loader": "^0.6.4", "@types/node": ">=12.12.47" }, "files": [ diff --git a/packages/grpc-js/proto/channelz.proto b/packages/grpc-js/proto/channelz.proto new file mode 100644 index 000000000..446e9794b --- /dev/null +++ b/packages/grpc-js/proto/channelz.proto @@ -0,0 +1,564 @@ +// Copyright 2018 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// This file defines an interface for exporting monitoring information +// out of gRPC servers. See the full design at +// https://github.com/grpc/proposal/blob/master/A14-channelz.md +// +// The canonical version of this proto can be found at +// https://github.com/grpc/grpc-proto/blob/master/grpc/channelz/v1/channelz.proto + +syntax = "proto3"; + +package grpc.channelz.v1; + +import "google/protobuf/any.proto"; +import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; +import "google/protobuf/wrappers.proto"; + +option go_package = "google.golang.org/grpc/channelz/grpc_channelz_v1"; +option java_multiple_files = true; +option java_package = "io.grpc.channelz.v1"; +option java_outer_classname = "ChannelzProto"; + +// Channel is a logical grouping of channels, subchannels, and sockets. +message Channel { + // The identifier for this channel. This should bet set. + ChannelRef ref = 1; + // Data specific to this channel. + ChannelData data = 2; + // At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + + // There are no ordering guarantees on the order of channel refs. + // There may not be cycles in the ref graph. + // A channel ref may be present in more than one channel or subchannel. + repeated ChannelRef channel_ref = 3; + + // At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + // There are no ordering guarantees on the order of subchannel refs. + // There may not be cycles in the ref graph. + // A sub channel ref may be present in more than one channel or subchannel. + repeated SubchannelRef subchannel_ref = 4; + + // There are no ordering guarantees on the order of sockets. + repeated SocketRef socket_ref = 5; +} + +// Subchannel is a logical grouping of channels, subchannels, and sockets. +// A subchannel is load balanced over by it's ancestor +message Subchannel { + // The identifier for this channel. + SubchannelRef ref = 1; + // Data specific to this channel. + ChannelData data = 2; + // At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + + // There are no ordering guarantees on the order of channel refs. + // There may not be cycles in the ref graph. + // A channel ref may be present in more than one channel or subchannel. + repeated ChannelRef channel_ref = 3; + + // At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + // There are no ordering guarantees on the order of subchannel refs. + // There may not be cycles in the ref graph. + // A sub channel ref may be present in more than one channel or subchannel. + repeated SubchannelRef subchannel_ref = 4; + + // There are no ordering guarantees on the order of sockets. + repeated SocketRef socket_ref = 5; +} + +// These come from the specified states in this document: +// https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md +message ChannelConnectivityState { + enum State { + UNKNOWN = 0; + IDLE = 1; + CONNECTING = 2; + READY = 3; + TRANSIENT_FAILURE = 4; + SHUTDOWN = 5; + } + State state = 1; +} + +// Channel data is data related to a specific Channel or Subchannel. +message ChannelData { + // The connectivity state of the channel or subchannel. Implementations + // should always set this. + ChannelConnectivityState state = 1; + + // The target this channel originally tried to connect to. May be absent + string target = 2; + + // A trace of recent events on the channel. May be absent. + ChannelTrace trace = 3; + + // The number of calls started on the channel + int64 calls_started = 4; + // The number of calls that have completed with an OK status + int64 calls_succeeded = 5; + // The number of calls that have completed with a non-OK status + int64 calls_failed = 6; + + // The last time a call was started on the channel. + google.protobuf.Timestamp last_call_started_timestamp = 7; +} + +// A trace event is an interesting thing that happened to a channel or +// subchannel, such as creation, address resolution, subchannel creation, etc. +message ChannelTraceEvent { + // High level description of the event. + string description = 1; + // The supported severity levels of trace events. + enum Severity { + CT_UNKNOWN = 0; + CT_INFO = 1; + CT_WARNING = 2; + CT_ERROR = 3; + } + // the severity of the trace event + Severity severity = 2; + // When this event occurred. + google.protobuf.Timestamp timestamp = 3; + // ref of referenced channel or subchannel. + // Optional, only present if this event refers to a child object. For example, + // this field would be filled if this trace event was for a subchannel being + // created. + oneof child_ref { + ChannelRef channel_ref = 4; + SubchannelRef subchannel_ref = 5; + } +} + +// ChannelTrace represents the recent events that have occurred on the channel. +message ChannelTrace { + // Number of events ever logged in this tracing object. This can differ from + // events.size() because events can be overwritten or garbage collected by + // implementations. + int64 num_events_logged = 1; + // Time that this channel was created. + google.protobuf.Timestamp creation_timestamp = 2; + // List of events that have occurred on this channel. + repeated ChannelTraceEvent events = 3; +} + +// ChannelRef is a reference to a Channel. +message ChannelRef { + // The globally unique id for this channel. Must be a positive number. + int64 channel_id = 1; + // An optional name associated with the channel. + string name = 2; + // Intentionally don't use field numbers from other refs. + reserved 3, 4, 5, 6, 7, 8; +} + +// SubchannelRef is a reference to a Subchannel. +message SubchannelRef { + // The globally unique id for this subchannel. Must be a positive number. + int64 subchannel_id = 7; + // An optional name associated with the subchannel. + string name = 8; + // Intentionally don't use field numbers from other refs. + reserved 1, 2, 3, 4, 5, 6; +} + +// SocketRef is a reference to a Socket. +message SocketRef { + // The globally unique id for this socket. Must be a positive number. + int64 socket_id = 3; + // An optional name associated with the socket. + string name = 4; + // Intentionally don't use field numbers from other refs. + reserved 1, 2, 5, 6, 7, 8; +} + +// ServerRef is a reference to a Server. +message ServerRef { + // A globally unique identifier for this server. Must be a positive number. + int64 server_id = 5; + // An optional name associated with the server. + string name = 6; + // Intentionally don't use field numbers from other refs. + reserved 1, 2, 3, 4, 7, 8; +} + +// Server represents a single server. There may be multiple servers in a single +// program. +message Server { + // The identifier for a Server. This should be set. + ServerRef ref = 1; + // The associated data of the Server. + ServerData data = 2; + + // The sockets that the server is listening on. There are no ordering + // guarantees. This may be absent. + repeated SocketRef listen_socket = 3; +} + +// ServerData is data for a specific Server. +message ServerData { + // A trace of recent events on the server. May be absent. + ChannelTrace trace = 1; + + // The number of incoming calls started on the server + int64 calls_started = 2; + // The number of incoming calls that have completed with an OK status + int64 calls_succeeded = 3; + // The number of incoming calls that have a completed with a non-OK status + int64 calls_failed = 4; + + // The last time a call was started on the server. + google.protobuf.Timestamp last_call_started_timestamp = 5; +} + +// Information about an actual connection. Pronounced "sock-ay". +message Socket { + // The identifier for the Socket. + SocketRef ref = 1; + + // Data specific to this Socket. + SocketData data = 2; + // The locally bound address. + Address local = 3; + // The remote bound address. May be absent. + Address remote = 4; + // Security details for this socket. May be absent if not available, or + // there is no security on the socket. + Security security = 5; + + // Optional, represents the name of the remote endpoint, if different than + // the original target name. + string remote_name = 6; +} + +// SocketData is data associated for a specific Socket. The fields present +// are specific to the implementation, so there may be minor differences in +// the semantics. (e.g. flow control windows) +message SocketData { + // The number of streams that have been started. + int64 streams_started = 1; + // The number of streams that have ended successfully: + // On client side, received frame with eos bit set; + // On server side, sent frame with eos bit set. + int64 streams_succeeded = 2; + // The number of streams that have ended unsuccessfully: + // On client side, ended without receiving frame with eos bit set; + // On server side, ended without sending frame with eos bit set. + int64 streams_failed = 3; + // The number of grpc messages successfully sent on this socket. + int64 messages_sent = 4; + // The number of grpc messages received on this socket. + int64 messages_received = 5; + + // The number of keep alives sent. This is typically implemented with HTTP/2 + // ping messages. + int64 keep_alives_sent = 6; + + // The last time a stream was created by this endpoint. Usually unset for + // servers. + google.protobuf.Timestamp last_local_stream_created_timestamp = 7; + // The last time a stream was created by the remote endpoint. Usually unset + // for clients. + google.protobuf.Timestamp last_remote_stream_created_timestamp = 8; + + // The last time a message was sent by this endpoint. + google.protobuf.Timestamp last_message_sent_timestamp = 9; + // The last time a message was received by this endpoint. + google.protobuf.Timestamp last_message_received_timestamp = 10; + + // The amount of window, granted to the local endpoint by the remote endpoint. + // This may be slightly out of date due to network latency. This does NOT + // include stream level or TCP level flow control info. + google.protobuf.Int64Value local_flow_control_window = 11; + + // The amount of window, granted to the remote endpoint by the local endpoint. + // This may be slightly out of date due to network latency. This does NOT + // include stream level or TCP level flow control info. + google.protobuf.Int64Value remote_flow_control_window = 12; + + // Socket options set on this socket. May be absent if 'summary' is set + // on GetSocketRequest. + repeated SocketOption option = 13; +} + +// Address represents the address used to create the socket. +message Address { + message TcpIpAddress { + // Either the IPv4 or IPv6 address in bytes. Will be either 4 bytes or 16 + // bytes in length. + bytes ip_address = 1; + // 0-64k, or -1 if not appropriate. + int32 port = 2; + } + // A Unix Domain Socket address. + message UdsAddress { + string filename = 1; + } + // An address type not included above. + message OtherAddress { + // The human readable version of the value. This value should be set. + string name = 1; + // The actual address message. + google.protobuf.Any value = 2; + } + + oneof address { + TcpIpAddress tcpip_address = 1; + UdsAddress uds_address = 2; + OtherAddress other_address = 3; + } +} + +// Security represents details about how secure the socket is. +message Security { + message Tls { + oneof cipher_suite { + // The cipher suite name in the RFC 4346 format: + // https://tools.ietf.org/html/rfc4346#appendix-C + string standard_name = 1; + // Some other way to describe the cipher suite if + // the RFC 4346 name is not available. + string other_name = 2; + } + // the certificate used by this endpoint. + bytes local_certificate = 3; + // the certificate used by the remote endpoint. + bytes remote_certificate = 4; + } + message OtherSecurity { + // The human readable version of the value. + string name = 1; + // The actual security details message. + google.protobuf.Any value = 2; + } + oneof model { + Tls tls = 1; + OtherSecurity other = 2; + } +} + +// SocketOption represents socket options for a socket. Specifically, these +// are the options returned by getsockopt(). +message SocketOption { + // The full name of the socket option. Typically this will be the upper case + // name, such as "SO_REUSEPORT". + string name = 1; + // The human readable value of this socket option. At least one of value or + // additional will be set. + string value = 2; + // Additional data associated with the socket option. At least one of value + // or additional will be set. + google.protobuf.Any additional = 3; +} + +// For use with SocketOption's additional field. This is primarily used for +// SO_RCVTIMEO and SO_SNDTIMEO +message SocketOptionTimeout { + google.protobuf.Duration duration = 1; +} + +// For use with SocketOption's additional field. This is primarily used for +// SO_LINGER. +message SocketOptionLinger { + // active maps to `struct linger.l_onoff` + bool active = 1; + // duration maps to `struct linger.l_linger` + google.protobuf.Duration duration = 2; +} + +// For use with SocketOption's additional field. Tcp info for +// SOL_TCP and TCP_INFO. +message SocketOptionTcpInfo { + uint32 tcpi_state = 1; + + uint32 tcpi_ca_state = 2; + uint32 tcpi_retransmits = 3; + uint32 tcpi_probes = 4; + uint32 tcpi_backoff = 5; + uint32 tcpi_options = 6; + uint32 tcpi_snd_wscale = 7; + uint32 tcpi_rcv_wscale = 8; + + uint32 tcpi_rto = 9; + uint32 tcpi_ato = 10; + uint32 tcpi_snd_mss = 11; + uint32 tcpi_rcv_mss = 12; + + uint32 tcpi_unacked = 13; + uint32 tcpi_sacked = 14; + uint32 tcpi_lost = 15; + uint32 tcpi_retrans = 16; + uint32 tcpi_fackets = 17; + + uint32 tcpi_last_data_sent = 18; + uint32 tcpi_last_ack_sent = 19; + uint32 tcpi_last_data_recv = 20; + uint32 tcpi_last_ack_recv = 21; + + uint32 tcpi_pmtu = 22; + uint32 tcpi_rcv_ssthresh = 23; + uint32 tcpi_rtt = 24; + uint32 tcpi_rttvar = 25; + uint32 tcpi_snd_ssthresh = 26; + uint32 tcpi_snd_cwnd = 27; + uint32 tcpi_advmss = 28; + uint32 tcpi_reordering = 29; +} + +// Channelz is a service exposed by gRPC servers that provides detailed debug +// information. +service Channelz { + // Gets all root channels (i.e. channels the application has directly + // created). This does not include subchannels nor non-top level channels. + rpc GetTopChannels(GetTopChannelsRequest) returns (GetTopChannelsResponse); + // Gets all servers that exist in the process. + rpc GetServers(GetServersRequest) returns (GetServersResponse); + // Returns a single Server, or else a NOT_FOUND code. + rpc GetServer(GetServerRequest) returns (GetServerResponse); + // Gets all server sockets that exist in the process. + rpc GetServerSockets(GetServerSocketsRequest) returns (GetServerSocketsResponse); + // Returns a single Channel, or else a NOT_FOUND code. + rpc GetChannel(GetChannelRequest) returns (GetChannelResponse); + // Returns a single Subchannel, or else a NOT_FOUND code. + rpc GetSubchannel(GetSubchannelRequest) returns (GetSubchannelResponse); + // Returns a single Socket or else a NOT_FOUND code. + rpc GetSocket(GetSocketRequest) returns (GetSocketResponse); +} + +message GetTopChannelsRequest { + // start_channel_id indicates that only channels at or above this id should be + // included in the results. + // To request the first page, this should be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. + int64 start_channel_id = 1; + + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + int64 max_results = 2; +} + +message GetTopChannelsResponse { + // list of channels that the connection detail service knows about. Sorted in + // ascending channel_id order. + // Must contain at least 1 result, otherwise 'end' must be true. + repeated Channel channel = 1; + // If set, indicates that the list of channels is the final list. Requesting + // more channels can only return more if they are created after this RPC + // completes. + bool end = 2; +} + +message GetServersRequest { + // start_server_id indicates that only servers at or above this id should be + // included in the results. + // To request the first page, this must be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. + int64 start_server_id = 1; + + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + int64 max_results = 2; +} + +message GetServersResponse { + // list of servers that the connection detail service knows about. Sorted in + // ascending server_id order. + // Must contain at least 1 result, otherwise 'end' must be true. + repeated Server server = 1; + // If set, indicates that the list of servers is the final list. Requesting + // more servers will only return more if they are created after this RPC + // completes. + bool end = 2; +} + +message GetServerRequest { + // server_id is the identifier of the specific server to get. + int64 server_id = 1; +} + +message GetServerResponse { + // The Server that corresponds to the requested server_id. This field + // should be set. + Server server = 1; +} + +message GetServerSocketsRequest { + int64 server_id = 1; + // start_socket_id indicates that only sockets at or above this id should be + // included in the results. + // To request the first page, this must be set to 0. To request + // subsequent pages, the client generates this value by adding 1 to + // the highest seen result ID. + int64 start_socket_id = 2; + + // If non-zero, the server will return a page of results containing + // at most this many items. If zero, the server will choose a + // reasonable page size. Must never be negative. + int64 max_results = 3; +} + +message GetServerSocketsResponse { + // list of socket refs that the connection detail service knows about. Sorted in + // ascending socket_id order. + // Must contain at least 1 result, otherwise 'end' must be true. + repeated SocketRef socket_ref = 1; + // If set, indicates that the list of sockets is the final list. Requesting + // more sockets will only return more if they are created after this RPC + // completes. + bool end = 2; +} + +message GetChannelRequest { + // channel_id is the identifier of the specific channel to get. + int64 channel_id = 1; +} + +message GetChannelResponse { + // The Channel that corresponds to the requested channel_id. This field + // should be set. + Channel channel = 1; +} + +message GetSubchannelRequest { + // subchannel_id is the identifier of the specific subchannel to get. + int64 subchannel_id = 1; +} + +message GetSubchannelResponse { + // The Subchannel that corresponds to the requested subchannel_id. This + // field should be set. + Subchannel subchannel = 1; +} + +message GetSocketRequest { + // socket_id is the identifier of the specific socket to get. + int64 socket_id = 1; + + // If true, the response will contain only high level information + // that is inexpensive to obtain. Fields thay may be omitted are + // documented. + bool summary = 2; +} + +message GetSocketResponse { + // The Socket that corresponds to the requested socket_id. This field + // should be set. + Socket socket = 1; +} \ No newline at end of file diff --git a/packages/grpc-js/src/generated/channelz.ts b/packages/grpc-js/src/generated/channelz.ts new file mode 100644 index 000000000..367cf27f6 --- /dev/null +++ b/packages/grpc-js/src/generated/channelz.ts @@ -0,0 +1,73 @@ +import type * as grpc from '../index'; +import type { MessageTypeDefinition } from '@grpc/proto-loader'; + +import type { ChannelzClient as _grpc_channelz_v1_ChannelzClient, ChannelzDefinition as _grpc_channelz_v1_ChannelzDefinition } from './grpc/channelz/v1/Channelz'; + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + google: { + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + FloatValue: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + StringValue: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + } + } + grpc: { + channelz: { + v1: { + Address: MessageTypeDefinition + Channel: MessageTypeDefinition + ChannelConnectivityState: MessageTypeDefinition + ChannelData: MessageTypeDefinition + ChannelRef: MessageTypeDefinition + ChannelTrace: MessageTypeDefinition + ChannelTraceEvent: MessageTypeDefinition + /** + * Channelz is a service exposed by gRPC servers that provides detailed debug + * information. + */ + Channelz: SubtypeConstructor & { service: _grpc_channelz_v1_ChannelzDefinition } + GetChannelRequest: MessageTypeDefinition + GetChannelResponse: MessageTypeDefinition + GetServerRequest: MessageTypeDefinition + GetServerResponse: MessageTypeDefinition + GetServerSocketsRequest: MessageTypeDefinition + GetServerSocketsResponse: MessageTypeDefinition + GetServersRequest: MessageTypeDefinition + GetServersResponse: MessageTypeDefinition + GetSocketRequest: MessageTypeDefinition + GetSocketResponse: MessageTypeDefinition + GetSubchannelRequest: MessageTypeDefinition + GetSubchannelResponse: MessageTypeDefinition + GetTopChannelsRequest: MessageTypeDefinition + GetTopChannelsResponse: MessageTypeDefinition + Security: MessageTypeDefinition + Server: MessageTypeDefinition + ServerData: MessageTypeDefinition + ServerRef: MessageTypeDefinition + Socket: MessageTypeDefinition + SocketData: MessageTypeDefinition + SocketOption: MessageTypeDefinition + SocketOptionLinger: MessageTypeDefinition + SocketOptionTcpInfo: MessageTypeDefinition + SocketOptionTimeout: MessageTypeDefinition + SocketRef: MessageTypeDefinition + Subchannel: MessageTypeDefinition + SubchannelRef: MessageTypeDefinition + } + } + } +} + diff --git a/packages/grpc-js/src/generated/google/protobuf/Any.ts b/packages/grpc-js/src/generated/google/protobuf/Any.ts new file mode 100644 index 000000000..fcaa6724e --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Any.ts @@ -0,0 +1,13 @@ +// Original file: null + +import type { AnyExtension } from '@grpc/proto-loader'; + +export type Any = AnyExtension | { + type_url: string; + value: Buffer | Uint8Array | string; +} + +export interface Any__Output { + 'type_url': (string); + 'value': (Buffer); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/BoolValue.ts b/packages/grpc-js/src/generated/google/protobuf/BoolValue.ts new file mode 100644 index 000000000..86507eaf1 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/BoolValue.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface BoolValue { + 'value'?: (boolean); +} + +export interface BoolValue__Output { + 'value': (boolean); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/BytesValue.ts b/packages/grpc-js/src/generated/google/protobuf/BytesValue.ts new file mode 100644 index 000000000..9cec76f71 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/BytesValue.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface BytesValue { + 'value'?: (Buffer | Uint8Array | string); +} + +export interface BytesValue__Output { + 'value': (Buffer); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts b/packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts new file mode 100644 index 000000000..d70b303c2 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/DoubleValue.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface DoubleValue { + 'value'?: (number | string); +} + +export interface DoubleValue__Output { + 'value': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Duration.ts b/packages/grpc-js/src/generated/google/protobuf/Duration.ts new file mode 100644 index 000000000..8595377a0 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Duration.ts @@ -0,0 +1,13 @@ +// Original file: null + +import type { Long } from '@grpc/proto-loader'; + +export interface Duration { + 'seconds'?: (number | string | Long); + 'nanos'?: (number); +} + +export interface Duration__Output { + 'seconds': (string); + 'nanos': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/FloatValue.ts b/packages/grpc-js/src/generated/google/protobuf/FloatValue.ts new file mode 100644 index 000000000..54a655fbb --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/FloatValue.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface FloatValue { + 'value'?: (number | string); +} + +export interface FloatValue__Output { + 'value': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Int32Value.ts b/packages/grpc-js/src/generated/google/protobuf/Int32Value.ts new file mode 100644 index 000000000..ec4eeb7ec --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Int32Value.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface Int32Value { + 'value'?: (number); +} + +export interface Int32Value__Output { + 'value': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Int64Value.ts b/packages/grpc-js/src/generated/google/protobuf/Int64Value.ts new file mode 100644 index 000000000..f7375196d --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Int64Value.ts @@ -0,0 +1,11 @@ +// Original file: null + +import type { Long } from '@grpc/proto-loader'; + +export interface Int64Value { + 'value'?: (number | string | Long); +} + +export interface Int64Value__Output { + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/StringValue.ts b/packages/grpc-js/src/generated/google/protobuf/StringValue.ts new file mode 100644 index 000000000..673090e3f --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/StringValue.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface StringValue { + 'value'?: (string); +} + +export interface StringValue__Output { + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/Timestamp.ts b/packages/grpc-js/src/generated/google/protobuf/Timestamp.ts new file mode 100644 index 000000000..ceaa32b5f --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/Timestamp.ts @@ -0,0 +1,13 @@ +// Original file: null + +import type { Long } from '@grpc/proto-loader'; + +export interface Timestamp { + 'seconds'?: (number | string | Long); + 'nanos'?: (number); +} + +export interface Timestamp__Output { + 'seconds': (string); + 'nanos': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts b/packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts new file mode 100644 index 000000000..973ab34a5 --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/UInt32Value.ts @@ -0,0 +1,10 @@ +// Original file: null + + +export interface UInt32Value { + 'value'?: (number); +} + +export interface UInt32Value__Output { + 'value': (number); +} diff --git a/packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts b/packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts new file mode 100644 index 000000000..7a85c39ce --- /dev/null +++ b/packages/grpc-js/src/generated/google/protobuf/UInt64Value.ts @@ -0,0 +1,11 @@ +// Original file: null + +import type { Long } from '@grpc/proto-loader'; + +export interface UInt64Value { + 'value'?: (number | string | Long); +} + +export interface UInt64Value__Output { + 'value': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Address.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Address.ts new file mode 100644 index 000000000..259cfeabe --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Address.ts @@ -0,0 +1,89 @@ +// Original file: proto/channelz.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +/** + * An address type not included above. + */ +export interface _grpc_channelz_v1_Address_OtherAddress { + /** + * The human readable version of the value. This value should be set. + */ + 'name'?: (string); + /** + * The actual address message. + */ + 'value'?: (_google_protobuf_Any | null); +} + +/** + * An address type not included above. + */ +export interface _grpc_channelz_v1_Address_OtherAddress__Output { + /** + * The human readable version of the value. This value should be set. + */ + 'name': (string); + /** + * The actual address message. + */ + 'value': (_google_protobuf_Any__Output | null); +} + +export interface _grpc_channelz_v1_Address_TcpIpAddress { + /** + * Either the IPv4 or IPv6 address in bytes. Will be either 4 bytes or 16 + * bytes in length. + */ + 'ip_address'?: (Buffer | Uint8Array | string); + /** + * 0-64k, or -1 if not appropriate. + */ + 'port'?: (number); +} + +export interface _grpc_channelz_v1_Address_TcpIpAddress__Output { + /** + * Either the IPv4 or IPv6 address in bytes. Will be either 4 bytes or 16 + * bytes in length. + */ + 'ip_address': (Buffer); + /** + * 0-64k, or -1 if not appropriate. + */ + 'port': (number); +} + +/** + * A Unix Domain Socket address. + */ +export interface _grpc_channelz_v1_Address_UdsAddress { + 'filename'?: (string); +} + +/** + * A Unix Domain Socket address. + */ +export interface _grpc_channelz_v1_Address_UdsAddress__Output { + 'filename': (string); +} + +/** + * Address represents the address used to create the socket. + */ +export interface Address { + 'tcpip_address'?: (_grpc_channelz_v1_Address_TcpIpAddress | null); + 'uds_address'?: (_grpc_channelz_v1_Address_UdsAddress | null); + 'other_address'?: (_grpc_channelz_v1_Address_OtherAddress | null); + 'address'?: "tcpip_address"|"uds_address"|"other_address"; +} + +/** + * Address represents the address used to create the socket. + */ +export interface Address__Output { + 'tcpip_address'?: (_grpc_channelz_v1_Address_TcpIpAddress__Output | null); + 'uds_address'?: (_grpc_channelz_v1_Address_UdsAddress__Output | null); + 'other_address'?: (_grpc_channelz_v1_Address_OtherAddress__Output | null); + 'address': "tcpip_address"|"uds_address"|"other_address"; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Channel.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Channel.ts new file mode 100644 index 000000000..93b4a261d --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Channel.ts @@ -0,0 +1,68 @@ +// Original file: proto/channelz.proto + +import type { ChannelRef as _grpc_channelz_v1_ChannelRef, ChannelRef__Output as _grpc_channelz_v1_ChannelRef__Output } from '../../../grpc/channelz/v1/ChannelRef'; +import type { ChannelData as _grpc_channelz_v1_ChannelData, ChannelData__Output as _grpc_channelz_v1_ChannelData__Output } from '../../../grpc/channelz/v1/ChannelData'; +import type { SubchannelRef as _grpc_channelz_v1_SubchannelRef, SubchannelRef__Output as _grpc_channelz_v1_SubchannelRef__Output } from '../../../grpc/channelz/v1/SubchannelRef'; +import type { SocketRef as _grpc_channelz_v1_SocketRef, SocketRef__Output as _grpc_channelz_v1_SocketRef__Output } from '../../../grpc/channelz/v1/SocketRef'; + +/** + * Channel is a logical grouping of channels, subchannels, and sockets. + */ +export interface Channel { + /** + * The identifier for this channel. This should bet set. + */ + 'ref'?: (_grpc_channelz_v1_ChannelRef | null); + /** + * Data specific to this channel. + */ + 'data'?: (_grpc_channelz_v1_ChannelData | null); + /** + * There are no ordering guarantees on the order of channel refs. + * There may not be cycles in the ref graph. + * A channel ref may be present in more than one channel or subchannel. + */ + 'channel_ref'?: (_grpc_channelz_v1_ChannelRef)[]; + /** + * At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + * There are no ordering guarantees on the order of subchannel refs. + * There may not be cycles in the ref graph. + * A sub channel ref may be present in more than one channel or subchannel. + */ + 'subchannel_ref'?: (_grpc_channelz_v1_SubchannelRef)[]; + /** + * There are no ordering guarantees on the order of sockets. + */ + 'socket_ref'?: (_grpc_channelz_v1_SocketRef)[]; +} + +/** + * Channel is a logical grouping of channels, subchannels, and sockets. + */ +export interface Channel__Output { + /** + * The identifier for this channel. This should bet set. + */ + 'ref': (_grpc_channelz_v1_ChannelRef__Output | null); + /** + * Data specific to this channel. + */ + 'data': (_grpc_channelz_v1_ChannelData__Output | null); + /** + * There are no ordering guarantees on the order of channel refs. + * There may not be cycles in the ref graph. + * A channel ref may be present in more than one channel or subchannel. + */ + 'channel_ref': (_grpc_channelz_v1_ChannelRef__Output)[]; + /** + * At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + * There are no ordering guarantees on the order of subchannel refs. + * There may not be cycles in the ref graph. + * A sub channel ref may be present in more than one channel or subchannel. + */ + 'subchannel_ref': (_grpc_channelz_v1_SubchannelRef__Output)[]; + /** + * There are no ordering guarantees on the order of sockets. + */ + 'socket_ref': (_grpc_channelz_v1_SocketRef__Output)[]; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelConnectivityState.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelConnectivityState.ts new file mode 100644 index 000000000..be34ab98d --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelConnectivityState.ts @@ -0,0 +1,29 @@ +// Original file: proto/channelz.proto + + +// Original file: proto/channelz.proto + +export enum _grpc_channelz_v1_ChannelConnectivityState_State { + UNKNOWN = 0, + IDLE = 1, + CONNECTING = 2, + READY = 3, + TRANSIENT_FAILURE = 4, + SHUTDOWN = 5, +} + +/** + * These come from the specified states in this document: + * https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md + */ +export interface ChannelConnectivityState { + 'state'?: (_grpc_channelz_v1_ChannelConnectivityState_State | keyof typeof _grpc_channelz_v1_ChannelConnectivityState_State); +} + +/** + * These come from the specified states in this document: + * https://github.com/grpc/grpc/blob/master/doc/connectivity-semantics-and-api.md + */ +export interface ChannelConnectivityState__Output { + 'state': (keyof typeof _grpc_channelz_v1_ChannelConnectivityState_State); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelData.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelData.ts new file mode 100644 index 000000000..6d6824af4 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelData.ts @@ -0,0 +1,76 @@ +// Original file: proto/channelz.proto + +import type { ChannelConnectivityState as _grpc_channelz_v1_ChannelConnectivityState, ChannelConnectivityState__Output as _grpc_channelz_v1_ChannelConnectivityState__Output } from '../../../grpc/channelz/v1/ChannelConnectivityState'; +import type { ChannelTrace as _grpc_channelz_v1_ChannelTrace, ChannelTrace__Output as _grpc_channelz_v1_ChannelTrace__Output } from '../../../grpc/channelz/v1/ChannelTrace'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { Long } from '@grpc/proto-loader'; + +/** + * Channel data is data related to a specific Channel or Subchannel. + */ +export interface ChannelData { + /** + * The connectivity state of the channel or subchannel. Implementations + * should always set this. + */ + 'state'?: (_grpc_channelz_v1_ChannelConnectivityState | null); + /** + * The target this channel originally tried to connect to. May be absent + */ + 'target'?: (string); + /** + * A trace of recent events on the channel. May be absent. + */ + 'trace'?: (_grpc_channelz_v1_ChannelTrace | null); + /** + * The number of calls started on the channel + */ + 'calls_started'?: (number | string | Long); + /** + * The number of calls that have completed with an OK status + */ + 'calls_succeeded'?: (number | string | Long); + /** + * The number of calls that have completed with a non-OK status + */ + 'calls_failed'?: (number | string | Long); + /** + * The last time a call was started on the channel. + */ + 'last_call_started_timestamp'?: (_google_protobuf_Timestamp | null); +} + +/** + * Channel data is data related to a specific Channel or Subchannel. + */ +export interface ChannelData__Output { + /** + * The connectivity state of the channel or subchannel. Implementations + * should always set this. + */ + 'state': (_grpc_channelz_v1_ChannelConnectivityState__Output | null); + /** + * The target this channel originally tried to connect to. May be absent + */ + 'target': (string); + /** + * A trace of recent events on the channel. May be absent. + */ + 'trace': (_grpc_channelz_v1_ChannelTrace__Output | null); + /** + * The number of calls started on the channel + */ + 'calls_started': (string); + /** + * The number of calls that have completed with an OK status + */ + 'calls_succeeded': (string); + /** + * The number of calls that have completed with a non-OK status + */ + 'calls_failed': (string); + /** + * The last time a call was started on the channel. + */ + 'last_call_started_timestamp': (_google_protobuf_Timestamp__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelRef.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelRef.ts new file mode 100644 index 000000000..231d00876 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelRef.ts @@ -0,0 +1,31 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +/** + * ChannelRef is a reference to a Channel. + */ +export interface ChannelRef { + /** + * The globally unique id for this channel. Must be a positive number. + */ + 'channel_id'?: (number | string | Long); + /** + * An optional name associated with the channel. + */ + 'name'?: (string); +} + +/** + * ChannelRef is a reference to a Channel. + */ +export interface ChannelRef__Output { + /** + * The globally unique id for this channel. Must be a positive number. + */ + 'channel_id': (string); + /** + * An optional name associated with the channel. + */ + 'name': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTrace.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTrace.ts new file mode 100644 index 000000000..7dbc8d924 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTrace.ts @@ -0,0 +1,45 @@ +// Original file: proto/channelz.proto + +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { ChannelTraceEvent as _grpc_channelz_v1_ChannelTraceEvent, ChannelTraceEvent__Output as _grpc_channelz_v1_ChannelTraceEvent__Output } from '../../../grpc/channelz/v1/ChannelTraceEvent'; +import type { Long } from '@grpc/proto-loader'; + +/** + * ChannelTrace represents the recent events that have occurred on the channel. + */ +export interface ChannelTrace { + /** + * Number of events ever logged in this tracing object. This can differ from + * events.size() because events can be overwritten or garbage collected by + * implementations. + */ + 'num_events_logged'?: (number | string | Long); + /** + * Time that this channel was created. + */ + 'creation_timestamp'?: (_google_protobuf_Timestamp | null); + /** + * List of events that have occurred on this channel. + */ + 'events'?: (_grpc_channelz_v1_ChannelTraceEvent)[]; +} + +/** + * ChannelTrace represents the recent events that have occurred on the channel. + */ +export interface ChannelTrace__Output { + /** + * Number of events ever logged in this tracing object. This can differ from + * events.size() because events can be overwritten or garbage collected by + * implementations. + */ + 'num_events_logged': (string); + /** + * Time that this channel was created. + */ + 'creation_timestamp': (_google_protobuf_Timestamp__Output | null); + /** + * List of events that have occurred on this channel. + */ + 'events': (_grpc_channelz_v1_ChannelTraceEvent__Output)[]; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTraceEvent.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTraceEvent.ts new file mode 100644 index 000000000..24b97fbcd --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ChannelTraceEvent.ts @@ -0,0 +1,73 @@ +// Original file: proto/channelz.proto + +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { ChannelRef as _grpc_channelz_v1_ChannelRef, ChannelRef__Output as _grpc_channelz_v1_ChannelRef__Output } from '../../../grpc/channelz/v1/ChannelRef'; +import type { SubchannelRef as _grpc_channelz_v1_SubchannelRef, SubchannelRef__Output as _grpc_channelz_v1_SubchannelRef__Output } from '../../../grpc/channelz/v1/SubchannelRef'; + +// Original file: proto/channelz.proto + +/** + * The supported severity levels of trace events. + */ +export enum _grpc_channelz_v1_ChannelTraceEvent_Severity { + CT_UNKNOWN = 0, + CT_INFO = 1, + CT_WARNING = 2, + CT_ERROR = 3, +} + +/** + * A trace event is an interesting thing that happened to a channel or + * subchannel, such as creation, address resolution, subchannel creation, etc. + */ +export interface ChannelTraceEvent { + /** + * High level description of the event. + */ + 'description'?: (string); + /** + * the severity of the trace event + */ + 'severity'?: (_grpc_channelz_v1_ChannelTraceEvent_Severity | keyof typeof _grpc_channelz_v1_ChannelTraceEvent_Severity); + /** + * When this event occurred. + */ + 'timestamp'?: (_google_protobuf_Timestamp | null); + 'channel_ref'?: (_grpc_channelz_v1_ChannelRef | null); + 'subchannel_ref'?: (_grpc_channelz_v1_SubchannelRef | null); + /** + * ref of referenced channel or subchannel. + * Optional, only present if this event refers to a child object. For example, + * this field would be filled if this trace event was for a subchannel being + * created. + */ + 'child_ref'?: "channel_ref"|"subchannel_ref"; +} + +/** + * A trace event is an interesting thing that happened to a channel or + * subchannel, such as creation, address resolution, subchannel creation, etc. + */ +export interface ChannelTraceEvent__Output { + /** + * High level description of the event. + */ + 'description': (string); + /** + * the severity of the trace event + */ + 'severity': (keyof typeof _grpc_channelz_v1_ChannelTraceEvent_Severity); + /** + * When this event occurred. + */ + 'timestamp': (_google_protobuf_Timestamp__Output | null); + 'channel_ref'?: (_grpc_channelz_v1_ChannelRef__Output | null); + 'subchannel_ref'?: (_grpc_channelz_v1_SubchannelRef__Output | null); + /** + * ref of referenced channel or subchannel. + * Optional, only present if this event refers to a child object. For example, + * this field would be filled if this trace event was for a subchannel being + * created. + */ + 'child_ref': "channel_ref"|"subchannel_ref"; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts new file mode 100644 index 000000000..ace712454 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts @@ -0,0 +1,178 @@ +// Original file: proto/channelz.proto + +import type * as grpc from '../../../../index' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { GetChannelRequest as _grpc_channelz_v1_GetChannelRequest, GetChannelRequest__Output as _grpc_channelz_v1_GetChannelRequest__Output } from '../../../grpc/channelz/v1/GetChannelRequest'; +import type { GetChannelResponse as _grpc_channelz_v1_GetChannelResponse, GetChannelResponse__Output as _grpc_channelz_v1_GetChannelResponse__Output } from '../../../grpc/channelz/v1/GetChannelResponse'; +import type { GetServerRequest as _grpc_channelz_v1_GetServerRequest, GetServerRequest__Output as _grpc_channelz_v1_GetServerRequest__Output } from '../../../grpc/channelz/v1/GetServerRequest'; +import type { GetServerResponse as _grpc_channelz_v1_GetServerResponse, GetServerResponse__Output as _grpc_channelz_v1_GetServerResponse__Output } from '../../../grpc/channelz/v1/GetServerResponse'; +import type { GetServerSocketsRequest as _grpc_channelz_v1_GetServerSocketsRequest, GetServerSocketsRequest__Output as _grpc_channelz_v1_GetServerSocketsRequest__Output } from '../../../grpc/channelz/v1/GetServerSocketsRequest'; +import type { GetServerSocketsResponse as _grpc_channelz_v1_GetServerSocketsResponse, GetServerSocketsResponse__Output as _grpc_channelz_v1_GetServerSocketsResponse__Output } from '../../../grpc/channelz/v1/GetServerSocketsResponse'; +import type { GetServersRequest as _grpc_channelz_v1_GetServersRequest, GetServersRequest__Output as _grpc_channelz_v1_GetServersRequest__Output } from '../../../grpc/channelz/v1/GetServersRequest'; +import type { GetServersResponse as _grpc_channelz_v1_GetServersResponse, GetServersResponse__Output as _grpc_channelz_v1_GetServersResponse__Output } from '../../../grpc/channelz/v1/GetServersResponse'; +import type { GetSocketRequest as _grpc_channelz_v1_GetSocketRequest, GetSocketRequest__Output as _grpc_channelz_v1_GetSocketRequest__Output } from '../../../grpc/channelz/v1/GetSocketRequest'; +import type { GetSocketResponse as _grpc_channelz_v1_GetSocketResponse, GetSocketResponse__Output as _grpc_channelz_v1_GetSocketResponse__Output } from '../../../grpc/channelz/v1/GetSocketResponse'; +import type { GetSubchannelRequest as _grpc_channelz_v1_GetSubchannelRequest, GetSubchannelRequest__Output as _grpc_channelz_v1_GetSubchannelRequest__Output } from '../../../grpc/channelz/v1/GetSubchannelRequest'; +import type { GetSubchannelResponse as _grpc_channelz_v1_GetSubchannelResponse, GetSubchannelResponse__Output as _grpc_channelz_v1_GetSubchannelResponse__Output } from '../../../grpc/channelz/v1/GetSubchannelResponse'; +import type { GetTopChannelsRequest as _grpc_channelz_v1_GetTopChannelsRequest, GetTopChannelsRequest__Output as _grpc_channelz_v1_GetTopChannelsRequest__Output } from '../../../grpc/channelz/v1/GetTopChannelsRequest'; +import type { GetTopChannelsResponse as _grpc_channelz_v1_GetTopChannelsResponse, GetTopChannelsResponse__Output as _grpc_channelz_v1_GetTopChannelsResponse__Output } from '../../../grpc/channelz/v1/GetTopChannelsResponse'; + +/** + * Channelz is a service exposed by gRPC servers that provides detailed debug + * information. + */ +export interface ChannelzClient extends grpc.Client { + /** + * Returns a single Channel, or else a NOT_FOUND code. + */ + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * Returns a single Server, or else a NOT_FOUND code. + */ + GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Returns a single Server, or else a NOT_FOUND code. + */ + getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * Gets all server sockets that exist in the process. + */ + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets all server sockets that exist in the process. + */ + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * Gets all servers that exist in the process. + */ + GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets all servers that exist in the process. + */ + getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * Returns a single Socket or else a NOT_FOUND code. + */ + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Returns a single Socket or else a NOT_FOUND code. + */ + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * Returns a single Subchannel, or else a NOT_FOUND code. + */ + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Returns a single Subchannel, or else a NOT_FOUND code. + */ + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + + /** + * Gets all root channels (i.e. channels the application has directly + * created). This does not include subchannels nor non-top level channels. + */ + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + /** + * Gets all root channels (i.e. channels the application has directly + * created). This does not include subchannels nor non-top level channels. + */ + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + +} + +/** + * Channelz is a service exposed by gRPC servers that provides detailed debug + * information. + */ +export interface ChannelzHandlers extends grpc.UntypedServiceImplementation { + /** + * Returns a single Channel, or else a NOT_FOUND code. + */ + GetChannel: grpc.handleUnaryCall<_grpc_channelz_v1_GetChannelRequest__Output, _grpc_channelz_v1_GetChannelResponse>; + + /** + * Returns a single Server, or else a NOT_FOUND code. + */ + GetServer: grpc.handleUnaryCall<_grpc_channelz_v1_GetServerRequest__Output, _grpc_channelz_v1_GetServerResponse>; + + /** + * Gets all server sockets that exist in the process. + */ + GetServerSockets: grpc.handleUnaryCall<_grpc_channelz_v1_GetServerSocketsRequest__Output, _grpc_channelz_v1_GetServerSocketsResponse>; + + /** + * Gets all servers that exist in the process. + */ + GetServers: grpc.handleUnaryCall<_grpc_channelz_v1_GetServersRequest__Output, _grpc_channelz_v1_GetServersResponse>; + + /** + * Returns a single Socket or else a NOT_FOUND code. + */ + GetSocket: grpc.handleUnaryCall<_grpc_channelz_v1_GetSocketRequest__Output, _grpc_channelz_v1_GetSocketResponse>; + + /** + * Returns a single Subchannel, or else a NOT_FOUND code. + */ + GetSubchannel: grpc.handleUnaryCall<_grpc_channelz_v1_GetSubchannelRequest__Output, _grpc_channelz_v1_GetSubchannelResponse>; + + /** + * Gets all root channels (i.e. channels the application has directly + * created). This does not include subchannels nor non-top level channels. + */ + GetTopChannels: grpc.handleUnaryCall<_grpc_channelz_v1_GetTopChannelsRequest__Output, _grpc_channelz_v1_GetTopChannelsResponse>; + +} + +export interface ChannelzDefinition extends grpc.ServiceDefinition { + GetChannel: MethodDefinition<_grpc_channelz_v1_GetChannelRequest, _grpc_channelz_v1_GetChannelResponse, _grpc_channelz_v1_GetChannelRequest__Output, _grpc_channelz_v1_GetChannelResponse__Output> + GetServer: MethodDefinition<_grpc_channelz_v1_GetServerRequest, _grpc_channelz_v1_GetServerResponse, _grpc_channelz_v1_GetServerRequest__Output, _grpc_channelz_v1_GetServerResponse__Output> + GetServerSockets: MethodDefinition<_grpc_channelz_v1_GetServerSocketsRequest, _grpc_channelz_v1_GetServerSocketsResponse, _grpc_channelz_v1_GetServerSocketsRequest__Output, _grpc_channelz_v1_GetServerSocketsResponse__Output> + GetServers: MethodDefinition<_grpc_channelz_v1_GetServersRequest, _grpc_channelz_v1_GetServersResponse, _grpc_channelz_v1_GetServersRequest__Output, _grpc_channelz_v1_GetServersResponse__Output> + GetSocket: MethodDefinition<_grpc_channelz_v1_GetSocketRequest, _grpc_channelz_v1_GetSocketResponse, _grpc_channelz_v1_GetSocketRequest__Output, _grpc_channelz_v1_GetSocketResponse__Output> + GetSubchannel: MethodDefinition<_grpc_channelz_v1_GetSubchannelRequest, _grpc_channelz_v1_GetSubchannelResponse, _grpc_channelz_v1_GetSubchannelRequest__Output, _grpc_channelz_v1_GetSubchannelResponse__Output> + GetTopChannels: MethodDefinition<_grpc_channelz_v1_GetTopChannelsRequest, _grpc_channelz_v1_GetTopChannelsResponse, _grpc_channelz_v1_GetTopChannelsRequest__Output, _grpc_channelz_v1_GetTopChannelsResponse__Output> +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelRequest.ts new file mode 100644 index 000000000..437e2d60a --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelRequest.ts @@ -0,0 +1,17 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetChannelRequest { + /** + * channel_id is the identifier of the specific channel to get. + */ + 'channel_id'?: (number | string | Long); +} + +export interface GetChannelRequest__Output { + /** + * channel_id is the identifier of the specific channel to get. + */ + 'channel_id': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelResponse.ts new file mode 100644 index 000000000..2e967a458 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetChannelResponse.ts @@ -0,0 +1,19 @@ +// Original file: proto/channelz.proto + +import type { Channel as _grpc_channelz_v1_Channel, Channel__Output as _grpc_channelz_v1_Channel__Output } from '../../../grpc/channelz/v1/Channel'; + +export interface GetChannelResponse { + /** + * The Channel that corresponds to the requested channel_id. This field + * should be set. + */ + 'channel'?: (_grpc_channelz_v1_Channel | null); +} + +export interface GetChannelResponse__Output { + /** + * The Channel that corresponds to the requested channel_id. This field + * should be set. + */ + 'channel': (_grpc_channelz_v1_Channel__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerRequest.ts new file mode 100644 index 000000000..f5d4a298f --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerRequest.ts @@ -0,0 +1,17 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetServerRequest { + /** + * server_id is the identifier of the specific server to get. + */ + 'server_id'?: (number | string | Long); +} + +export interface GetServerRequest__Output { + /** + * server_id is the identifier of the specific server to get. + */ + 'server_id': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerResponse.ts new file mode 100644 index 000000000..fe0078209 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerResponse.ts @@ -0,0 +1,19 @@ +// Original file: proto/channelz.proto + +import type { Server as _grpc_channelz_v1_Server, Server__Output as _grpc_channelz_v1_Server__Output } from '../../../grpc/channelz/v1/Server'; + +export interface GetServerResponse { + /** + * The Server that corresponds to the requested server_id. This field + * should be set. + */ + 'server'?: (_grpc_channelz_v1_Server | null); +} + +export interface GetServerResponse__Output { + /** + * The Server that corresponds to the requested server_id. This field + * should be set. + */ + 'server': (_grpc_channelz_v1_Server__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsRequest.ts new file mode 100644 index 000000000..c33056edc --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsRequest.ts @@ -0,0 +1,39 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetServerSocketsRequest { + 'server_id'?: (number | string | Long); + /** + * start_socket_id indicates that only sockets at or above this id should be + * included in the results. + * To request the first page, this must be set to 0. To request + * subsequent pages, the client generates this value by adding 1 to + * the highest seen result ID. + */ + 'start_socket_id'?: (number | string | Long); + /** + * If non-zero, the server will return a page of results containing + * at most this many items. If zero, the server will choose a + * reasonable page size. Must never be negative. + */ + 'max_results'?: (number | string | Long); +} + +export interface GetServerSocketsRequest__Output { + 'server_id': (string); + /** + * start_socket_id indicates that only sockets at or above this id should be + * included in the results. + * To request the first page, this must be set to 0. To request + * subsequent pages, the client generates this value by adding 1 to + * the highest seen result ID. + */ + 'start_socket_id': (string); + /** + * If non-zero, the server will return a page of results containing + * at most this many items. If zero, the server will choose a + * reasonable page size. Must never be negative. + */ + 'max_results': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsResponse.ts new file mode 100644 index 000000000..112f277e3 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServerSocketsResponse.ts @@ -0,0 +1,33 @@ +// Original file: proto/channelz.proto + +import type { SocketRef as _grpc_channelz_v1_SocketRef, SocketRef__Output as _grpc_channelz_v1_SocketRef__Output } from '../../../grpc/channelz/v1/SocketRef'; + +export interface GetServerSocketsResponse { + /** + * list of socket refs that the connection detail service knows about. Sorted in + * ascending socket_id order. + * Must contain at least 1 result, otherwise 'end' must be true. + */ + 'socket_ref'?: (_grpc_channelz_v1_SocketRef)[]; + /** + * If set, indicates that the list of sockets is the final list. Requesting + * more sockets will only return more if they are created after this RPC + * completes. + */ + 'end'?: (boolean); +} + +export interface GetServerSocketsResponse__Output { + /** + * list of socket refs that the connection detail service knows about. Sorted in + * ascending socket_id order. + * Must contain at least 1 result, otherwise 'end' must be true. + */ + 'socket_ref': (_grpc_channelz_v1_SocketRef__Output)[]; + /** + * If set, indicates that the list of sockets is the final list. Requesting + * more sockets will only return more if they are created after this RPC + * completes. + */ + 'end': (boolean); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetServersRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServersRequest.ts new file mode 100644 index 000000000..2defea62d --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServersRequest.ts @@ -0,0 +1,37 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetServersRequest { + /** + * start_server_id indicates that only servers at or above this id should be + * included in the results. + * To request the first page, this must be set to 0. To request + * subsequent pages, the client generates this value by adding 1 to + * the highest seen result ID. + */ + 'start_server_id'?: (number | string | Long); + /** + * If non-zero, the server will return a page of results containing + * at most this many items. If zero, the server will choose a + * reasonable page size. Must never be negative. + */ + 'max_results'?: (number | string | Long); +} + +export interface GetServersRequest__Output { + /** + * start_server_id indicates that only servers at or above this id should be + * included in the results. + * To request the first page, this must be set to 0. To request + * subsequent pages, the client generates this value by adding 1 to + * the highest seen result ID. + */ + 'start_server_id': (string); + /** + * If non-zero, the server will return a page of results containing + * at most this many items. If zero, the server will choose a + * reasonable page size. Must never be negative. + */ + 'max_results': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetServersResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServersResponse.ts new file mode 100644 index 000000000..b07893b8c --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetServersResponse.ts @@ -0,0 +1,33 @@ +// Original file: proto/channelz.proto + +import type { Server as _grpc_channelz_v1_Server, Server__Output as _grpc_channelz_v1_Server__Output } from '../../../grpc/channelz/v1/Server'; + +export interface GetServersResponse { + /** + * list of servers that the connection detail service knows about. Sorted in + * ascending server_id order. + * Must contain at least 1 result, otherwise 'end' must be true. + */ + 'server'?: (_grpc_channelz_v1_Server)[]; + /** + * If set, indicates that the list of servers is the final list. Requesting + * more servers will only return more if they are created after this RPC + * completes. + */ + 'end'?: (boolean); +} + +export interface GetServersResponse__Output { + /** + * list of servers that the connection detail service knows about. Sorted in + * ascending server_id order. + * Must contain at least 1 result, otherwise 'end' must be true. + */ + 'server': (_grpc_channelz_v1_Server__Output)[]; + /** + * If set, indicates that the list of servers is the final list. Requesting + * more servers will only return more if they are created after this RPC + * completes. + */ + 'end': (boolean); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketRequest.ts new file mode 100644 index 000000000..b3dc1608e --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketRequest.ts @@ -0,0 +1,29 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetSocketRequest { + /** + * socket_id is the identifier of the specific socket to get. + */ + 'socket_id'?: (number | string | Long); + /** + * If true, the response will contain only high level information + * that is inexpensive to obtain. Fields thay may be omitted are + * documented. + */ + 'summary'?: (boolean); +} + +export interface GetSocketRequest__Output { + /** + * socket_id is the identifier of the specific socket to get. + */ + 'socket_id': (string); + /** + * If true, the response will contain only high level information + * that is inexpensive to obtain. Fields thay may be omitted are + * documented. + */ + 'summary': (boolean); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketResponse.ts new file mode 100644 index 000000000..b6304b7f0 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSocketResponse.ts @@ -0,0 +1,19 @@ +// Original file: proto/channelz.proto + +import type { Socket as _grpc_channelz_v1_Socket, Socket__Output as _grpc_channelz_v1_Socket__Output } from '../../../grpc/channelz/v1/Socket'; + +export interface GetSocketResponse { + /** + * The Socket that corresponds to the requested socket_id. This field + * should be set. + */ + 'socket'?: (_grpc_channelz_v1_Socket | null); +} + +export interface GetSocketResponse__Output { + /** + * The Socket that corresponds to the requested socket_id. This field + * should be set. + */ + 'socket': (_grpc_channelz_v1_Socket__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelRequest.ts new file mode 100644 index 000000000..f481a81d2 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelRequest.ts @@ -0,0 +1,17 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetSubchannelRequest { + /** + * subchannel_id is the identifier of the specific subchannel to get. + */ + 'subchannel_id'?: (number | string | Long); +} + +export interface GetSubchannelRequest__Output { + /** + * subchannel_id is the identifier of the specific subchannel to get. + */ + 'subchannel_id': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelResponse.ts new file mode 100644 index 000000000..57d2bf2dc --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetSubchannelResponse.ts @@ -0,0 +1,19 @@ +// Original file: proto/channelz.proto + +import type { Subchannel as _grpc_channelz_v1_Subchannel, Subchannel__Output as _grpc_channelz_v1_Subchannel__Output } from '../../../grpc/channelz/v1/Subchannel'; + +export interface GetSubchannelResponse { + /** + * The Subchannel that corresponds to the requested subchannel_id. This + * field should be set. + */ + 'subchannel'?: (_grpc_channelz_v1_Subchannel | null); +} + +export interface GetSubchannelResponse__Output { + /** + * The Subchannel that corresponds to the requested subchannel_id. This + * field should be set. + */ + 'subchannel': (_grpc_channelz_v1_Subchannel__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsRequest.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsRequest.ts new file mode 100644 index 000000000..a122d7a85 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsRequest.ts @@ -0,0 +1,37 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface GetTopChannelsRequest { + /** + * start_channel_id indicates that only channels at or above this id should be + * included in the results. + * To request the first page, this should be set to 0. To request + * subsequent pages, the client generates this value by adding 1 to + * the highest seen result ID. + */ + 'start_channel_id'?: (number | string | Long); + /** + * If non-zero, the server will return a page of results containing + * at most this many items. If zero, the server will choose a + * reasonable page size. Must never be negative. + */ + 'max_results'?: (number | string | Long); +} + +export interface GetTopChannelsRequest__Output { + /** + * start_channel_id indicates that only channels at or above this id should be + * included in the results. + * To request the first page, this should be set to 0. To request + * subsequent pages, the client generates this value by adding 1 to + * the highest seen result ID. + */ + 'start_channel_id': (string); + /** + * If non-zero, the server will return a page of results containing + * at most this many items. If zero, the server will choose a + * reasonable page size. Must never be negative. + */ + 'max_results': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsResponse.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsResponse.ts new file mode 100644 index 000000000..d96e63673 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/GetTopChannelsResponse.ts @@ -0,0 +1,33 @@ +// Original file: proto/channelz.proto + +import type { Channel as _grpc_channelz_v1_Channel, Channel__Output as _grpc_channelz_v1_Channel__Output } from '../../../grpc/channelz/v1/Channel'; + +export interface GetTopChannelsResponse { + /** + * list of channels that the connection detail service knows about. Sorted in + * ascending channel_id order. + * Must contain at least 1 result, otherwise 'end' must be true. + */ + 'channel'?: (_grpc_channelz_v1_Channel)[]; + /** + * If set, indicates that the list of channels is the final list. Requesting + * more channels can only return more if they are created after this RPC + * completes. + */ + 'end'?: (boolean); +} + +export interface GetTopChannelsResponse__Output { + /** + * list of channels that the connection detail service knows about. Sorted in + * ascending channel_id order. + * Must contain at least 1 result, otherwise 'end' must be true. + */ + 'channel': (_grpc_channelz_v1_Channel__Output)[]; + /** + * If set, indicates that the list of channels is the final list. Requesting + * more channels can only return more if they are created after this RPC + * completes. + */ + 'end': (boolean); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Security.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Security.ts new file mode 100644 index 000000000..e555d698e --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Security.ts @@ -0,0 +1,87 @@ +// Original file: proto/channelz.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +export interface _grpc_channelz_v1_Security_OtherSecurity { + /** + * The human readable version of the value. + */ + 'name'?: (string); + /** + * The actual security details message. + */ + 'value'?: (_google_protobuf_Any | null); +} + +export interface _grpc_channelz_v1_Security_OtherSecurity__Output { + /** + * The human readable version of the value. + */ + 'name': (string); + /** + * The actual security details message. + */ + 'value': (_google_protobuf_Any__Output | null); +} + +export interface _grpc_channelz_v1_Security_Tls { + /** + * The cipher suite name in the RFC 4346 format: + * https://tools.ietf.org/html/rfc4346#appendix-C + */ + 'standard_name'?: (string); + /** + * Some other way to describe the cipher suite if + * the RFC 4346 name is not available. + */ + 'other_name'?: (string); + /** + * the certificate used by this endpoint. + */ + 'local_certificate'?: (Buffer | Uint8Array | string); + /** + * the certificate used by the remote endpoint. + */ + 'remote_certificate'?: (Buffer | Uint8Array | string); + 'cipher_suite'?: "standard_name"|"other_name"; +} + +export interface _grpc_channelz_v1_Security_Tls__Output { + /** + * The cipher suite name in the RFC 4346 format: + * https://tools.ietf.org/html/rfc4346#appendix-C + */ + 'standard_name'?: (string); + /** + * Some other way to describe the cipher suite if + * the RFC 4346 name is not available. + */ + 'other_name'?: (string); + /** + * the certificate used by this endpoint. + */ + 'local_certificate': (Buffer); + /** + * the certificate used by the remote endpoint. + */ + 'remote_certificate': (Buffer); + 'cipher_suite': "standard_name"|"other_name"; +} + +/** + * Security represents details about how secure the socket is. + */ +export interface Security { + 'tls'?: (_grpc_channelz_v1_Security_Tls | null); + 'other'?: (_grpc_channelz_v1_Security_OtherSecurity | null); + 'model'?: "tls"|"other"; +} + +/** + * Security represents details about how secure the socket is. + */ +export interface Security__Output { + 'tls'?: (_grpc_channelz_v1_Security_Tls__Output | null); + 'other'?: (_grpc_channelz_v1_Security_OtherSecurity__Output | null); + 'model': "tls"|"other"; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Server.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Server.ts new file mode 100644 index 000000000..958343358 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Server.ts @@ -0,0 +1,45 @@ +// Original file: proto/channelz.proto + +import type { ServerRef as _grpc_channelz_v1_ServerRef, ServerRef__Output as _grpc_channelz_v1_ServerRef__Output } from '../../../grpc/channelz/v1/ServerRef'; +import type { ServerData as _grpc_channelz_v1_ServerData, ServerData__Output as _grpc_channelz_v1_ServerData__Output } from '../../../grpc/channelz/v1/ServerData'; +import type { SocketRef as _grpc_channelz_v1_SocketRef, SocketRef__Output as _grpc_channelz_v1_SocketRef__Output } from '../../../grpc/channelz/v1/SocketRef'; + +/** + * Server represents a single server. There may be multiple servers in a single + * program. + */ +export interface Server { + /** + * The identifier for a Server. This should be set. + */ + 'ref'?: (_grpc_channelz_v1_ServerRef | null); + /** + * The associated data of the Server. + */ + 'data'?: (_grpc_channelz_v1_ServerData | null); + /** + * The sockets that the server is listening on. There are no ordering + * guarantees. This may be absent. + */ + 'listen_socket'?: (_grpc_channelz_v1_SocketRef)[]; +} + +/** + * Server represents a single server. There may be multiple servers in a single + * program. + */ +export interface Server__Output { + /** + * The identifier for a Server. This should be set. + */ + 'ref': (_grpc_channelz_v1_ServerRef__Output | null); + /** + * The associated data of the Server. + */ + 'data': (_grpc_channelz_v1_ServerData__Output | null); + /** + * The sockets that the server is listening on. There are no ordering + * guarantees. This may be absent. + */ + 'listen_socket': (_grpc_channelz_v1_SocketRef__Output)[]; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ServerData.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ServerData.ts new file mode 100644 index 000000000..ce48e36f5 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ServerData.ts @@ -0,0 +1,57 @@ +// Original file: proto/channelz.proto + +import type { ChannelTrace as _grpc_channelz_v1_ChannelTrace, ChannelTrace__Output as _grpc_channelz_v1_ChannelTrace__Output } from '../../../grpc/channelz/v1/ChannelTrace'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { Long } from '@grpc/proto-loader'; + +/** + * ServerData is data for a specific Server. + */ +export interface ServerData { + /** + * A trace of recent events on the server. May be absent. + */ + 'trace'?: (_grpc_channelz_v1_ChannelTrace | null); + /** + * The number of incoming calls started on the server + */ + 'calls_started'?: (number | string | Long); + /** + * The number of incoming calls that have completed with an OK status + */ + 'calls_succeeded'?: (number | string | Long); + /** + * The number of incoming calls that have a completed with a non-OK status + */ + 'calls_failed'?: (number | string | Long); + /** + * The last time a call was started on the server. + */ + 'last_call_started_timestamp'?: (_google_protobuf_Timestamp | null); +} + +/** + * ServerData is data for a specific Server. + */ +export interface ServerData__Output { + /** + * A trace of recent events on the server. May be absent. + */ + 'trace': (_grpc_channelz_v1_ChannelTrace__Output | null); + /** + * The number of incoming calls started on the server + */ + 'calls_started': (string); + /** + * The number of incoming calls that have completed with an OK status + */ + 'calls_succeeded': (string); + /** + * The number of incoming calls that have a completed with a non-OK status + */ + 'calls_failed': (string); + /** + * The last time a call was started on the server. + */ + 'last_call_started_timestamp': (_google_protobuf_Timestamp__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/ServerRef.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/ServerRef.ts new file mode 100644 index 000000000..389183bdc --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/ServerRef.ts @@ -0,0 +1,31 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +/** + * ServerRef is a reference to a Server. + */ +export interface ServerRef { + /** + * A globally unique identifier for this server. Must be a positive number. + */ + 'server_id'?: (number | string | Long); + /** + * An optional name associated with the server. + */ + 'name'?: (string); +} + +/** + * ServerRef is a reference to a Server. + */ +export interface ServerRef__Output { + /** + * A globally unique identifier for this server. Must be a positive number. + */ + 'server_id': (string); + /** + * An optional name associated with the server. + */ + 'name': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Socket.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Socket.ts new file mode 100644 index 000000000..5829afe98 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Socket.ts @@ -0,0 +1,70 @@ +// Original file: proto/channelz.proto + +import type { SocketRef as _grpc_channelz_v1_SocketRef, SocketRef__Output as _grpc_channelz_v1_SocketRef__Output } from '../../../grpc/channelz/v1/SocketRef'; +import type { SocketData as _grpc_channelz_v1_SocketData, SocketData__Output as _grpc_channelz_v1_SocketData__Output } from '../../../grpc/channelz/v1/SocketData'; +import type { Address as _grpc_channelz_v1_Address, Address__Output as _grpc_channelz_v1_Address__Output } from '../../../grpc/channelz/v1/Address'; +import type { Security as _grpc_channelz_v1_Security, Security__Output as _grpc_channelz_v1_Security__Output } from '../../../grpc/channelz/v1/Security'; + +/** + * Information about an actual connection. Pronounced "sock-ay". + */ +export interface Socket { + /** + * The identifier for the Socket. + */ + 'ref'?: (_grpc_channelz_v1_SocketRef | null); + /** + * Data specific to this Socket. + */ + 'data'?: (_grpc_channelz_v1_SocketData | null); + /** + * The locally bound address. + */ + 'local'?: (_grpc_channelz_v1_Address | null); + /** + * The remote bound address. May be absent. + */ + 'remote'?: (_grpc_channelz_v1_Address | null); + /** + * Security details for this socket. May be absent if not available, or + * there is no security on the socket. + */ + 'security'?: (_grpc_channelz_v1_Security | null); + /** + * Optional, represents the name of the remote endpoint, if different than + * the original target name. + */ + 'remote_name'?: (string); +} + +/** + * Information about an actual connection. Pronounced "sock-ay". + */ +export interface Socket__Output { + /** + * The identifier for the Socket. + */ + 'ref': (_grpc_channelz_v1_SocketRef__Output | null); + /** + * Data specific to this Socket. + */ + 'data': (_grpc_channelz_v1_SocketData__Output | null); + /** + * The locally bound address. + */ + 'local': (_grpc_channelz_v1_Address__Output | null); + /** + * The remote bound address. May be absent. + */ + 'remote': (_grpc_channelz_v1_Address__Output | null); + /** + * Security details for this socket. May be absent if not available, or + * there is no security on the socket. + */ + 'security': (_grpc_channelz_v1_Security__Output | null); + /** + * Optional, represents the name of the remote endpoint, if different than + * the original target name. + */ + 'remote_name': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SocketData.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketData.ts new file mode 100644 index 000000000..c62d4d10c --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketData.ts @@ -0,0 +1,150 @@ +// Original file: proto/channelz.proto + +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { Int64Value as _google_protobuf_Int64Value, Int64Value__Output as _google_protobuf_Int64Value__Output } from '../../../google/protobuf/Int64Value'; +import type { SocketOption as _grpc_channelz_v1_SocketOption, SocketOption__Output as _grpc_channelz_v1_SocketOption__Output } from '../../../grpc/channelz/v1/SocketOption'; +import type { Long } from '@grpc/proto-loader'; + +/** + * SocketData is data associated for a specific Socket. The fields present + * are specific to the implementation, so there may be minor differences in + * the semantics. (e.g. flow control windows) + */ +export interface SocketData { + /** + * The number of streams that have been started. + */ + 'streams_started'?: (number | string | Long); + /** + * The number of streams that have ended successfully: + * On client side, received frame with eos bit set; + * On server side, sent frame with eos bit set. + */ + 'streams_succeeded'?: (number | string | Long); + /** + * The number of streams that have ended unsuccessfully: + * On client side, ended without receiving frame with eos bit set; + * On server side, ended without sending frame with eos bit set. + */ + 'streams_failed'?: (number | string | Long); + /** + * The number of grpc messages successfully sent on this socket. + */ + 'messages_sent'?: (number | string | Long); + /** + * The number of grpc messages received on this socket. + */ + 'messages_received'?: (number | string | Long); + /** + * The number of keep alives sent. This is typically implemented with HTTP/2 + * ping messages. + */ + 'keep_alives_sent'?: (number | string | Long); + /** + * The last time a stream was created by this endpoint. Usually unset for + * servers. + */ + 'last_local_stream_created_timestamp'?: (_google_protobuf_Timestamp | null); + /** + * The last time a stream was created by the remote endpoint. Usually unset + * for clients. + */ + 'last_remote_stream_created_timestamp'?: (_google_protobuf_Timestamp | null); + /** + * The last time a message was sent by this endpoint. + */ + 'last_message_sent_timestamp'?: (_google_protobuf_Timestamp | null); + /** + * The last time a message was received by this endpoint. + */ + 'last_message_received_timestamp'?: (_google_protobuf_Timestamp | null); + /** + * The amount of window, granted to the local endpoint by the remote endpoint. + * This may be slightly out of date due to network latency. This does NOT + * include stream level or TCP level flow control info. + */ + 'local_flow_control_window'?: (_google_protobuf_Int64Value | null); + /** + * The amount of window, granted to the remote endpoint by the local endpoint. + * This may be slightly out of date due to network latency. This does NOT + * include stream level or TCP level flow control info. + */ + 'remote_flow_control_window'?: (_google_protobuf_Int64Value | null); + /** + * Socket options set on this socket. May be absent if 'summary' is set + * on GetSocketRequest. + */ + 'option'?: (_grpc_channelz_v1_SocketOption)[]; +} + +/** + * SocketData is data associated for a specific Socket. The fields present + * are specific to the implementation, so there may be minor differences in + * the semantics. (e.g. flow control windows) + */ +export interface SocketData__Output { + /** + * The number of streams that have been started. + */ + 'streams_started': (string); + /** + * The number of streams that have ended successfully: + * On client side, received frame with eos bit set; + * On server side, sent frame with eos bit set. + */ + 'streams_succeeded': (string); + /** + * The number of streams that have ended unsuccessfully: + * On client side, ended without receiving frame with eos bit set; + * On server side, ended without sending frame with eos bit set. + */ + 'streams_failed': (string); + /** + * The number of grpc messages successfully sent on this socket. + */ + 'messages_sent': (string); + /** + * The number of grpc messages received on this socket. + */ + 'messages_received': (string); + /** + * The number of keep alives sent. This is typically implemented with HTTP/2 + * ping messages. + */ + 'keep_alives_sent': (string); + /** + * The last time a stream was created by this endpoint. Usually unset for + * servers. + */ + 'last_local_stream_created_timestamp': (_google_protobuf_Timestamp__Output | null); + /** + * The last time a stream was created by the remote endpoint. Usually unset + * for clients. + */ + 'last_remote_stream_created_timestamp': (_google_protobuf_Timestamp__Output | null); + /** + * The last time a message was sent by this endpoint. + */ + 'last_message_sent_timestamp': (_google_protobuf_Timestamp__Output | null); + /** + * The last time a message was received by this endpoint. + */ + 'last_message_received_timestamp': (_google_protobuf_Timestamp__Output | null); + /** + * The amount of window, granted to the local endpoint by the remote endpoint. + * This may be slightly out of date due to network latency. This does NOT + * include stream level or TCP level flow control info. + */ + 'local_flow_control_window': (_google_protobuf_Int64Value__Output | null); + /** + * The amount of window, granted to the remote endpoint by the local endpoint. + * This may be slightly out of date due to network latency. This does NOT + * include stream level or TCP level flow control info. + */ + 'remote_flow_control_window': (_google_protobuf_Int64Value__Output | null); + /** + * Socket options set on this socket. May be absent if 'summary' is set + * on GetSocketRequest. + */ + 'option': (_grpc_channelz_v1_SocketOption__Output)[]; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOption.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOption.ts new file mode 100644 index 000000000..115b36aae --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOption.ts @@ -0,0 +1,47 @@ +// Original file: proto/channelz.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +/** + * SocketOption represents socket options for a socket. Specifically, these + * are the options returned by getsockopt(). + */ +export interface SocketOption { + /** + * The full name of the socket option. Typically this will be the upper case + * name, such as "SO_REUSEPORT". + */ + 'name'?: (string); + /** + * The human readable value of this socket option. At least one of value or + * additional will be set. + */ + 'value'?: (string); + /** + * Additional data associated with the socket option. At least one of value + * or additional will be set. + */ + 'additional'?: (_google_protobuf_Any | null); +} + +/** + * SocketOption represents socket options for a socket. Specifically, these + * are the options returned by getsockopt(). + */ +export interface SocketOption__Output { + /** + * The full name of the socket option. Typically this will be the upper case + * name, such as "SO_REUSEPORT". + */ + 'name': (string); + /** + * The human readable value of this socket option. At least one of value or + * additional will be set. + */ + 'value': (string); + /** + * Additional data associated with the socket option. At least one of value + * or additional will be set. + */ + 'additional': (_google_protobuf_Any__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionLinger.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionLinger.ts new file mode 100644 index 000000000..d83fa3238 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionLinger.ts @@ -0,0 +1,33 @@ +// Original file: proto/channelz.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; + +/** + * For use with SocketOption's additional field. This is primarily used for + * SO_LINGER. + */ +export interface SocketOptionLinger { + /** + * active maps to `struct linger.l_onoff` + */ + 'active'?: (boolean); + /** + * duration maps to `struct linger.l_linger` + */ + 'duration'?: (_google_protobuf_Duration | null); +} + +/** + * For use with SocketOption's additional field. This is primarily used for + * SO_LINGER. + */ +export interface SocketOptionLinger__Output { + /** + * active maps to `struct linger.l_onoff` + */ + 'active': (boolean); + /** + * duration maps to `struct linger.l_linger` + */ + 'duration': (_google_protobuf_Duration__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTcpInfo.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTcpInfo.ts new file mode 100644 index 000000000..2f8affe80 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTcpInfo.ts @@ -0,0 +1,74 @@ +// Original file: proto/channelz.proto + + +/** + * For use with SocketOption's additional field. Tcp info for + * SOL_TCP and TCP_INFO. + */ +export interface SocketOptionTcpInfo { + 'tcpi_state'?: (number); + 'tcpi_ca_state'?: (number); + 'tcpi_retransmits'?: (number); + 'tcpi_probes'?: (number); + 'tcpi_backoff'?: (number); + 'tcpi_options'?: (number); + 'tcpi_snd_wscale'?: (number); + 'tcpi_rcv_wscale'?: (number); + 'tcpi_rto'?: (number); + 'tcpi_ato'?: (number); + 'tcpi_snd_mss'?: (number); + 'tcpi_rcv_mss'?: (number); + 'tcpi_unacked'?: (number); + 'tcpi_sacked'?: (number); + 'tcpi_lost'?: (number); + 'tcpi_retrans'?: (number); + 'tcpi_fackets'?: (number); + 'tcpi_last_data_sent'?: (number); + 'tcpi_last_ack_sent'?: (number); + 'tcpi_last_data_recv'?: (number); + 'tcpi_last_ack_recv'?: (number); + 'tcpi_pmtu'?: (number); + 'tcpi_rcv_ssthresh'?: (number); + 'tcpi_rtt'?: (number); + 'tcpi_rttvar'?: (number); + 'tcpi_snd_ssthresh'?: (number); + 'tcpi_snd_cwnd'?: (number); + 'tcpi_advmss'?: (number); + 'tcpi_reordering'?: (number); +} + +/** + * For use with SocketOption's additional field. Tcp info for + * SOL_TCP and TCP_INFO. + */ +export interface SocketOptionTcpInfo__Output { + 'tcpi_state': (number); + 'tcpi_ca_state': (number); + 'tcpi_retransmits': (number); + 'tcpi_probes': (number); + 'tcpi_backoff': (number); + 'tcpi_options': (number); + 'tcpi_snd_wscale': (number); + 'tcpi_rcv_wscale': (number); + 'tcpi_rto': (number); + 'tcpi_ato': (number); + 'tcpi_snd_mss': (number); + 'tcpi_rcv_mss': (number); + 'tcpi_unacked': (number); + 'tcpi_sacked': (number); + 'tcpi_lost': (number); + 'tcpi_retrans': (number); + 'tcpi_fackets': (number); + 'tcpi_last_data_sent': (number); + 'tcpi_last_ack_sent': (number); + 'tcpi_last_data_recv': (number); + 'tcpi_last_ack_recv': (number); + 'tcpi_pmtu': (number); + 'tcpi_rcv_ssthresh': (number); + 'tcpi_rtt': (number); + 'tcpi_rttvar': (number); + 'tcpi_snd_ssthresh': (number); + 'tcpi_snd_cwnd': (number); + 'tcpi_advmss': (number); + 'tcpi_reordering': (number); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTimeout.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTimeout.ts new file mode 100644 index 000000000..185839b2c --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketOptionTimeout.ts @@ -0,0 +1,19 @@ +// Original file: proto/channelz.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; + +/** + * For use with SocketOption's additional field. This is primarily used for + * SO_RCVTIMEO and SO_SNDTIMEO + */ +export interface SocketOptionTimeout { + 'duration'?: (_google_protobuf_Duration | null); +} + +/** + * For use with SocketOption's additional field. This is primarily used for + * SO_RCVTIMEO and SO_SNDTIMEO + */ +export interface SocketOptionTimeout__Output { + 'duration': (_google_protobuf_Duration__Output | null); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SocketRef.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketRef.ts new file mode 100644 index 000000000..52fdb2bd3 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SocketRef.ts @@ -0,0 +1,31 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +/** + * SocketRef is a reference to a Socket. + */ +export interface SocketRef { + /** + * The globally unique id for this socket. Must be a positive number. + */ + 'socket_id'?: (number | string | Long); + /** + * An optional name associated with the socket. + */ + 'name'?: (string); +} + +/** + * SocketRef is a reference to a Socket. + */ +export interface SocketRef__Output { + /** + * The globally unique id for this socket. Must be a positive number. + */ + 'socket_id': (string); + /** + * An optional name associated with the socket. + */ + 'name': (string); +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Subchannel.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Subchannel.ts new file mode 100644 index 000000000..7122fac83 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Subchannel.ts @@ -0,0 +1,70 @@ +// Original file: proto/channelz.proto + +import type { SubchannelRef as _grpc_channelz_v1_SubchannelRef, SubchannelRef__Output as _grpc_channelz_v1_SubchannelRef__Output } from '../../../grpc/channelz/v1/SubchannelRef'; +import type { ChannelData as _grpc_channelz_v1_ChannelData, ChannelData__Output as _grpc_channelz_v1_ChannelData__Output } from '../../../grpc/channelz/v1/ChannelData'; +import type { ChannelRef as _grpc_channelz_v1_ChannelRef, ChannelRef__Output as _grpc_channelz_v1_ChannelRef__Output } from '../../../grpc/channelz/v1/ChannelRef'; +import type { SocketRef as _grpc_channelz_v1_SocketRef, SocketRef__Output as _grpc_channelz_v1_SocketRef__Output } from '../../../grpc/channelz/v1/SocketRef'; + +/** + * Subchannel is a logical grouping of channels, subchannels, and sockets. + * A subchannel is load balanced over by it's ancestor + */ +export interface Subchannel { + /** + * The identifier for this channel. + */ + 'ref'?: (_grpc_channelz_v1_SubchannelRef | null); + /** + * Data specific to this channel. + */ + 'data'?: (_grpc_channelz_v1_ChannelData | null); + /** + * There are no ordering guarantees on the order of channel refs. + * There may not be cycles in the ref graph. + * A channel ref may be present in more than one channel or subchannel. + */ + 'channel_ref'?: (_grpc_channelz_v1_ChannelRef)[]; + /** + * At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + * There are no ordering guarantees on the order of subchannel refs. + * There may not be cycles in the ref graph. + * A sub channel ref may be present in more than one channel or subchannel. + */ + 'subchannel_ref'?: (_grpc_channelz_v1_SubchannelRef)[]; + /** + * There are no ordering guarantees on the order of sockets. + */ + 'socket_ref'?: (_grpc_channelz_v1_SocketRef)[]; +} + +/** + * Subchannel is a logical grouping of channels, subchannels, and sockets. + * A subchannel is load balanced over by it's ancestor + */ +export interface Subchannel__Output { + /** + * The identifier for this channel. + */ + 'ref': (_grpc_channelz_v1_SubchannelRef__Output | null); + /** + * Data specific to this channel. + */ + 'data': (_grpc_channelz_v1_ChannelData__Output | null); + /** + * There are no ordering guarantees on the order of channel refs. + * There may not be cycles in the ref graph. + * A channel ref may be present in more than one channel or subchannel. + */ + 'channel_ref': (_grpc_channelz_v1_ChannelRef__Output)[]; + /** + * At most one of 'channel_ref+subchannel_ref' and 'socket' is set. + * There are no ordering guarantees on the order of subchannel refs. + * There may not be cycles in the ref graph. + * A sub channel ref may be present in more than one channel or subchannel. + */ + 'subchannel_ref': (_grpc_channelz_v1_SubchannelRef__Output)[]; + /** + * There are no ordering guarantees on the order of sockets. + */ + 'socket_ref': (_grpc_channelz_v1_SocketRef__Output)[]; +} diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/SubchannelRef.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/SubchannelRef.ts new file mode 100644 index 000000000..b6911c773 --- /dev/null +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/SubchannelRef.ts @@ -0,0 +1,31 @@ +// Original file: proto/channelz.proto + +import type { Long } from '@grpc/proto-loader'; + +/** + * SubchannelRef is a reference to a Subchannel. + */ +export interface SubchannelRef { + /** + * The globally unique id for this subchannel. Must be a positive number. + */ + 'subchannel_id'?: (number | string | Long); + /** + * An optional name associated with the subchannel. + */ + 'name'?: (string); +} + +/** + * SubchannelRef is a reference to a Subchannel. + */ +export interface SubchannelRef__Output { + /** + * The globally unique id for this subchannel. Must be a positive number. + */ + 'subchannel_id': (string); + /** + * An optional name associated with the subchannel. + */ + 'name': (string); +} From 74fdd85123acac606659cf07bb1d1bdebf836439 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Sep 2021 10:58:12 -0700 Subject: [PATCH 1507/1899] Add channelz service implementation --- packages/grpc-js/src/channel.ts | 3 + packages/grpc-js/src/channelz.ts | 375 ++++++++++++++++++++++++++++- packages/grpc-js/src/server.ts | 14 +- packages/grpc-js/src/subchannel.ts | 5 +- 4 files changed, 387 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 4a6e88147..c5f7352e4 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -163,6 +163,7 @@ export class ChannelImplementation implements Channel { private configSelector: ConfigSelector | null = null; // Channelz info + private originalTarget: string; private channelzRef: ChannelRef; private channelzTrace: ChannelzTrace; private callTracker = new ChannelzCallTracker(); @@ -196,6 +197,7 @@ export class ChannelImplementation implements Channel { ); } } + this.originalTarget = target; const originalTargetUri = parseUri(target); if (originalTargetUri === null) { throw new Error(`Could not parse target name "${target}"`); @@ -320,6 +322,7 @@ export class ChannelImplementation implements Channel { private getChannelzInfo(): ChannelInfo { return { + target: this.originalTarget, state: this.connectivityState, trace: this.channelzTrace, callTracker: this.callTracker, diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 3edbd7bba..7965ad3c2 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -17,7 +17,39 @@ import { isIPv4, isIPv6 } from "net"; import { ConnectivityState } from "./connectivity-state"; -import { SubchannelAddress } from "./subchannel-address"; +import { Status } from "./constants"; +import { Timestamp } from "./generated/google/protobuf/Timestamp"; +import { Channel as ChannelMessage } from "./generated/grpc/channelz/v1/Channel"; +import { ChannelConnectivityState__Output } from "./generated/grpc/channelz/v1/ChannelConnectivityState"; +import { ChannelRef as ChannelRefMessage } from "./generated/grpc/channelz/v1/ChannelRef"; +import { ChannelTrace } from "./generated/grpc/channelz/v1/ChannelTrace"; +import { GetChannelRequest__Output } from "./generated/grpc/channelz/v1/GetChannelRequest"; +import { GetChannelResponse } from "./generated/grpc/channelz/v1/GetChannelResponse"; +import { sendUnaryData, ServerUnaryCall } from "./server-call"; +import { ServerRef as ServerRefMessage } from "./generated/grpc/channelz/v1/ServerRef"; +import { SocketRef as SocketRefMessage } from "./generated/grpc/channelz/v1/SocketRef"; +import { isTcpSubchannelAddress, SubchannelAddress } from "./subchannel-address"; +import { SubchannelRef as SubchannelRefMessage } from "./generated/grpc/channelz/v1/SubchannelRef"; +import { GetServerRequest__Output } from "./generated/grpc/channelz/v1/GetServerRequest"; +import { GetServerResponse } from "./generated/grpc/channelz/v1/GetServerResponse"; +import { Server as ServerMessage } from "./generated/grpc/channelz/v1/Server"; +import { GetServersRequest__Output } from "./generated/grpc/channelz/v1/GetServersRequest"; +import { GetServersResponse } from "./generated/grpc/channelz/v1/GetServersResponse"; +import { GetTopChannelsRequest__Output } from "./generated/grpc/channelz/v1/GetTopChannelsRequest"; +import { GetTopChannelsResponse } from "./generated/grpc/channelz/v1/GetTopChannelsResponse"; +import { GetSubchannelRequest__Output } from "./generated/grpc/channelz/v1/GetSubchannelRequest"; +import { GetSubchannelResponse } from "./generated/grpc/channelz/v1/GetSubchannelResponse"; +import { Subchannel as SubchannelMessage } from "./generated/grpc/channelz/v1/Subchannel"; +import { GetSocketRequest__Output } from "./generated/grpc/channelz/v1/GetSocketRequest"; +import { GetSocketResponse } from "./generated/grpc/channelz/v1/GetSocketResponse"; +import { Socket as SocketMessage } from "./generated/grpc/channelz/v1/Socket"; +import { Address } from "./generated/grpc/channelz/v1/Address"; +import { Security } from "./generated/grpc/channelz/v1/Security"; +import { GetServerSocketsRequest__Output } from "./generated/grpc/channelz/v1/GetServerSocketsRequest"; +import { GetServerSocketsResponse } from "./generated/grpc/channelz/v1/GetServerSocketsResponse"; +import { ChannelzDefinition, ChannelzHandlers } from "./generated/grpc/channelz/v1/Channelz"; +import { ProtoGrpcType as ChannelzProtoGrpcType } from "./generated/channelz"; +import type { loadSync } from '@grpc/proto-loader'; export type TraceSeverity = 'CT_UNKNOWN' | 'CT_INFO' | 'CT_WARNING' | 'CT_ERROR'; @@ -44,6 +76,33 @@ export interface SocketRef { name: string; } +function channelRefToMessage(ref: ChannelRef): ChannelRefMessage { + return { + channel_id: ref.id, + name: ref.name + }; +} + +function subchannelRefToMessage(ref: SubchannelRef): SubchannelRefMessage { + return { + subchannel_id: ref.id, + name: ref.name + } +} + +function serverRefToMessage(ref: ServerRef): ServerRefMessage { + return { + server_id: ref.id + } +} + +function socketRefToMessage(ref: SocketRef): SocketRefMessage { + return { + socket_id: ref.id, + name: ref.name + } +} + interface TraceEvent { description: string; severity: TraceSeverity; @@ -72,6 +131,22 @@ export class ChannelzTrace { }); this.eventsLogged += 1; } + + getTraceMessage(): ChannelTrace { + return { + creation_timestamp: dateToProtoTimestamp(this.creationTimestamp), + num_events_logged: this.eventsLogged, + events: this.events.map(event => { + return { + description: event.description, + severity: event.severity, + timestamp: dateToProtoTimestamp(event.timestamp), + channel_ref: event.childChannel ? channelRefToMessage(event.childChannel) : null, + subchannel_ref: event.childSubchannel ? subchannelRefToMessage(event.childSubchannel) : null + } + }) + }; + } } export class ChannelzChildrenTracker { @@ -185,6 +260,7 @@ export interface ChannelzChildren { } export interface ChannelInfo { + target: string; state: ConnectivityState; trace: ChannelzTrace; callTracker: ChannelzCallTracker; @@ -196,7 +272,8 @@ export interface SubchannelInfo extends ChannelInfo {} export interface ServerInfo { trace: ChannelzTrace; callTracker: ChannelzCallTracker; - children: ChannelzChildren; + listenerChildren: ChannelzChildren; + sessionChildren: ChannelzChildren; } export interface TlsInfo { @@ -342,4 +419,298 @@ function ipAddressStringToBuffer(ipAddress: string): Buffer | null { } else { return null; } +} + +function connectivityStateToMessage(state: ConnectivityState): ChannelConnectivityState__Output { + switch (state) { + case ConnectivityState.CONNECTING: + return { + state: 'CONNECTING' + }; + case ConnectivityState.IDLE: + return { + state: 'IDLE' + }; + case ConnectivityState.READY: + return { + state: 'READY' + }; + case ConnectivityState.SHUTDOWN: + return { + state: 'SHUTDOWN' + }; + case ConnectivityState.TRANSIENT_FAILURE: + return { + state: 'TRANSIENT_FAILURE' + }; + default: + return { + state: 'UNKNOWN' + }; + } +} + +function dateToProtoTimestamp(date?: Date | null): Timestamp | null { + if (!date) { + return null; + } + return { + seconds: date.getSeconds(), + nanos: date.getMilliseconds() * 1_000_000 + } +} + +function getChannelMessage(channelEntry: ChannelEntry): ChannelMessage { + const resolvedInfo = channelEntry.getInfo(); + return { + ref: channelRefToMessage(channelEntry.ref), + data: { + target: resolvedInfo.target, + state: connectivityStateToMessage(resolvedInfo.state), + calls_started: resolvedInfo.callTracker.callsStarted, + calls_succeeded: resolvedInfo.callTracker.callsSucceeded, + calls_failed: resolvedInfo.callTracker.callsFailed, + last_call_started_timestamp: dateToProtoTimestamp(resolvedInfo.callTracker.lastCallStartedTimestamp), + trace: resolvedInfo.trace.getTraceMessage() + }, + channel_ref: resolvedInfo.children.channels.map(ref => channelRefToMessage(ref)), + subchannel_ref: resolvedInfo.children.subchannels.map(ref => subchannelRefToMessage(ref)) + }; +} + +function GetChannel(call: ServerUnaryCall, callback: sendUnaryData): void { + const channelId = Number.parseInt(call.request.channel_id); + const channelEntry = channels[channelId]; + if (channelEntry === undefined) { + callback({ + 'code': Status.NOT_FOUND, + 'details': 'No channel data found for id ' + channelId + }); + return; + } + callback(null, {channel: getChannelMessage(channelEntry)}); +} + +function GetTopChannels(call: ServerUnaryCall, callback: sendUnaryData): void { + const maxResults = Number.parseInt(call.request.max_results); + const resultList: ChannelMessage[] = []; + let i = Number.parseInt(call.request.start_channel_id); + for (; i < channels.length; i++) { + const channelEntry = channels[i]; + if (channelEntry === undefined) { + continue; + } + resultList.push(getChannelMessage(channelEntry)); + if (resultList.length >= maxResults) { + break; + } + } + callback(null, { + channel: resultList, + end: i >= servers.length + }); +} + +function getServerMessage(serverEntry: ServerEntry): ServerMessage { + const resolvedInfo = serverEntry.getInfo(); + return { + ref: serverRefToMessage(serverEntry.ref), + data: { + calls_started: resolvedInfo.callTracker.callsStarted, + calls_succeeded: resolvedInfo.callTracker.callsSucceeded, + calls_failed: resolvedInfo.callTracker.callsFailed, + last_call_started_timestamp: dateToProtoTimestamp(resolvedInfo.callTracker.lastCallStartedTimestamp), + trace: resolvedInfo.trace.getTraceMessage() + }, + listen_socket: resolvedInfo.listenerChildren.sockets.map(ref => socketRefToMessage(ref)) + }; +} + +function GetServer(call: ServerUnaryCall, callback: sendUnaryData): void { + const serverId = Number.parseInt(call.request.server_id); + const serverEntry = servers[serverId]; + if (serverEntry === undefined) { + callback({ + 'code': Status.NOT_FOUND, + 'details': 'No server data found for id ' + serverId + }); + return; + } + callback(null, {server: getServerMessage(serverEntry)}); +} + +function GetServers(call: ServerUnaryCall, callback: sendUnaryData): void { + const maxResults = Number.parseInt(call.request.max_results); + const resultList: ServerMessage[] = []; + let i = Number.parseInt(call.request.start_server_id); + for (; i < servers.length; i++) { + const serverEntry = servers[i]; + if (serverEntry === undefined) { + continue; + } + resultList.push(getServerMessage(serverEntry)); + if (resultList.length >= maxResults) { + break; + } + } + callback(null, { + server: resultList, + end: i >= servers.length + }); +} + +function GetSubchannel(call: ServerUnaryCall, callback: sendUnaryData): void { + const subchannelId = Number.parseInt(call.request.subchannel_id); + const subchannelEntry = subchannels[subchannelId]; + if (subchannelEntry === undefined) { + callback({ + 'code': Status.NOT_FOUND, + 'details': 'No subchannel data found for id ' + subchannelId + }); + return; + } + const resolvedInfo = subchannelEntry.getInfo(); + const subchannelMessage: SubchannelMessage = { + ref: subchannelRefToMessage(subchannelEntry.ref), + data: { + target: resolvedInfo.target, + state: connectivityStateToMessage(resolvedInfo.state), + calls_started: resolvedInfo.callTracker.callsStarted, + calls_succeeded: resolvedInfo.callTracker.callsSucceeded, + calls_failed: resolvedInfo.callTracker.callsFailed, + last_call_started_timestamp: dateToProtoTimestamp(resolvedInfo.callTracker.lastCallStartedTimestamp), + trace: resolvedInfo.trace.getTraceMessage() + }, + socket_ref: resolvedInfo.children.sockets.map(ref => socketRefToMessage(ref)) + }; + callback(null, {subchannel: subchannelMessage}); +} + +function subchannelAddressToAddressMessage(subchannelAddress: SubchannelAddress): Address { + if (isTcpSubchannelAddress(subchannelAddress)) { + return { + address: 'tcpip_address', + tcpip_address: { + ip_address: ipAddressStringToBuffer(subchannelAddress.host) ?? undefined, + port: subchannelAddress.port + } + }; + } else { + return { + address: 'uds_address', + uds_address: { + filename: subchannelAddress.path + } + }; + } +} + +function GetSocket(call: ServerUnaryCall, callback: sendUnaryData): void { + const socketId = Number.parseInt(call.request.socket_id); + const socketEntry = sockets[socketId]; + if (socketEntry === undefined) { + callback({ + 'code': Status.NOT_FOUND, + 'details': 'No socket data found for id ' + socketId + }); + return; + } + const resolvedInfo = socketEntry.getInfo(); + const securityMessage: Security | null = resolvedInfo.security ? { + model: 'tls', + tls: { + cipher_suite: resolvedInfo.security.cipherSuiteStandardName ? 'standard_name' : 'other_name', + standard_name: resolvedInfo.security.cipherSuiteStandardName ?? undefined, + other_name: resolvedInfo.security.cipherSuiteOtherName ?? undefined, + local_certificate: resolvedInfo.security.localCertificate ?? undefined, + remote_certificate: resolvedInfo.security.remoteCertificate ?? undefined + } + } : null; + const socketMessage: SocketMessage = { + ref: socketRefToMessage(socketEntry.ref), + local: subchannelAddressToAddressMessage(resolvedInfo.localAddress), + remote: resolvedInfo.remoteAddress ? subchannelAddressToAddressMessage(resolvedInfo.remoteAddress) : null, + remote_name: resolvedInfo.remoteName ?? undefined, + security: securityMessage, + data: { + keep_alives_sent: resolvedInfo.keepAlivesSent, + streams_started: resolvedInfo.streamsStarted, + streams_succeeded: resolvedInfo.streamsSucceeded, + streams_failed: resolvedInfo.streamsFailed, + last_local_stream_created_timestamp: dateToProtoTimestamp(resolvedInfo.lastLocalStreamCreatedTimestamp), + last_remote_stream_created_timestamp: dateToProtoTimestamp(resolvedInfo.lastRemoteStreamCreatedTimestamp), + messages_received: resolvedInfo.messagesReceived, + messages_sent: resolvedInfo.messagesSent, + last_message_received_timestamp: dateToProtoTimestamp(resolvedInfo.lastMessageReceivedTimestamp), + last_message_sent_timestamp: dateToProtoTimestamp(resolvedInfo.lastMessageSentTimestamp), + local_flow_control_window: resolvedInfo.localFlowControlWindow ? { value: resolvedInfo.localFlowControlWindow } : null, + remote_flow_control_window: resolvedInfo.remoteFlowControlWindow ? { value: resolvedInfo.remoteFlowControlWindow } : null, + } + }; + callback(null, {socket: socketMessage}); +} + +function GetServerSockets(call: ServerUnaryCall, callback: sendUnaryData): void { + const serverId = Number.parseInt(call.request.server_id); + const serverEntry = servers[serverId]; + if (serverEntry === undefined) { + callback({ + 'code': Status.NOT_FOUND, + 'details': 'No server data found for id ' + serverId + }); + return; + } + const startId = Number.parseInt(call.request.start_socket_id); + const maxResults = Number.parseInt(call.request.max_results); + const resolvedInfo = serverEntry.getInfo(); + const allSockets = resolvedInfo.listenerChildren.sockets.concat(resolvedInfo.sessionChildren.sockets).sort((ref1, ref2) => ref1.id - ref2.id); + const resultList: SocketRefMessage[] = []; + let i = 0; + for (; i < allSockets.length; i++) { + if (allSockets[i].id >= startId) { + resultList.push(socketRefToMessage(allSockets[i])); + if (resultList.length >= maxResults) { + break; + } + } + } + callback(null, { + socket_ref: resultList, + end: i >= allSockets.length + }); +} + +export function getChannelzHandlers(): ChannelzHandlers { + return { + GetChannel, + GetTopChannels, + GetServer, + GetServers, + GetSubchannel, + GetSocket, + GetServerSockets + }; +} + +let loadedChannelzDefinition: ChannelzDefinition | null = null; + +export function getChannelzServiceDefinition(): ChannelzDefinition { + if (loadedChannelzDefinition) { + return loadedChannelzDefinition; + } + /* The purpose of this complexity is to avoid loading @grpc/proto-loader at + * runtime for users who will not use/enable channelz. */ + const loaderLoadSync = require('@grpc/proto-loader').loadSync as typeof loadSync; + const loadedProto = loaderLoadSync('channelz.proto', { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + '../../proto' + ] + }) as unknown as ChannelzProtoGrpcType; + loadedChannelzDefinition = loadedProto.grpc.channelz.v1.Channelz.service; + return loadedChannelzDefinition; } \ No newline at end of file diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 04c24c072..ef31dadce 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -156,7 +156,8 @@ export class Server { private channelzRef: ServerRef; private channelzTrace = new ChannelzTrace(); private callTracker = new ChannelzCallTracker(); - private childrenTracker = new ChannelzChildrenTracker(); + private listenerChildrenTracker = new ChannelzChildrenTracker(); + private sessionChildrenTracker = new ChannelzChildrenTracker(); constructor(options?: ChannelOptions) { this.options = options ?? {}; @@ -168,7 +169,8 @@ export class Server { return { trace: this.channelzTrace, callTracker: this.callTracker, - children: this.childrenTracker.getChildLists() + listenerChildren: this.listenerChildrenTracker.getChildLists(), + sessionChildren: this.sessionChildrenTracker.getChildLists() }; } @@ -568,7 +570,7 @@ export class Server { for (const {server: http2Server, channelzRef: ref} of this.http2ServerList) { if (http2Server.listening) { http2Server.close(() => { - this.childrenTracker.unrefChild(ref); + this.listenerChildrenTracker.unrefChild(ref); unregisterChannelzRef(ref); }); } @@ -652,7 +654,7 @@ export class Server { if (http2Server.listening) { pendingChecks++; http2Server.close(() => { - this.childrenTracker.unrefChild(ref); + this.listenerChildrenTracker.unrefChild(ref); unregisterChannelzRef(ref); maybeCallback(); }); @@ -826,10 +828,10 @@ export class Server { this.sessions.set(session, channelzSessionInfo); const clientAddress = session.socket.remoteAddress; this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); - this.childrenTracker.refChild(channelzRef); + this.sessionChildrenTracker.refChild(channelzRef); session.on('close', () => { this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); - this.childrenTracker.unrefChild(channelzRef); + this.sessionChildrenTracker.unrefChild(channelzRef); unregisterChannelzRef(channelzRef); this.sessions.delete(session); }); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 1caf94ba1..e7e7a9f08 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -266,7 +266,8 @@ export class Subchannel { state: this.connectivityState, trace: this.channelzTrace, callTracker: this.callTracker, - children: this.childrenTracker.getChildLists() + children: this.childrenTracker.getChildLists(), + target: this.subchannelAddressString }; } @@ -285,7 +286,7 @@ export class Subchannel { const peerCertificate = tlsSocket.getPeerCertificate(); tlsInfo = { cipherSuiteStandardName: cipherInfo.standardName ?? null, - cipherSuiteOtherName: cipherInfo.standardName ? cipherInfo.name: null, + cipherSuiteOtherName: cipherInfo.standardName ? null : cipherInfo.name, localCertificate: (certificate && 'raw' in certificate) ? certificate.raw : null, remoteCertificate: (peerCertificate && 'raw' in peerCertificate) ? peerCertificate.raw : null }; From 737dae88db117e090b9b5020c1de9c1717f7f7b4 Mon Sep 17 00:00:00 2001 From: bbesset Date: Wed, 15 Sep 2021 09:03:49 +0200 Subject: [PATCH 1508/1899] adds sometimes required Host header to proxy connection --- packages/grpc-js/src/http_proxy.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 14e88f068..248949a80 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -190,6 +190,9 @@ export function getProxiedConnection( method: 'CONNECT', path: parsedTarget.path, }; + const headers: http.OutgoingHttpHeaders = { + Host: parsedTarget.path, + }; // Connect to the subchannel address as a proxy if (isTcpSubchannelAddress(address)) { options.host = address.host; @@ -198,14 +201,13 @@ export function getProxiedConnection( options.socketPath = address.path; } if ('grpc.http_connect_creds' in channelOptions) { - options.headers = { - 'Proxy-Authorization': - 'Basic ' + - Buffer.from( - channelOptions['grpc.http_connect_creds'] as string - ).toString('base64'), - }; + headers['Proxy-Authorization'] = + 'Basic ' + + Buffer.from( + channelOptions['grpc.http_connect_creds'] as string + ).toString('base64'); } + options.headers = headers const proxyAddressString = subchannelAddressToString(address); trace('Using proxy ' + proxyAddressString + ' to connect to ' + options.path); return new Promise((resolve, reject) => { From acd991368746dba1cd616bc190caea6af3b679d3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Sep 2021 10:58:24 -0700 Subject: [PATCH 1509/1899] Add admin interface --- packages/grpc-js/src/admin.ts | 39 ++++++++++++++++++++++++++++ packages/grpc-js/src/channelz.ts | 5 ++++ packages/grpc-js/src/experimental.ts | 1 + packages/grpc-js/src/index.ts | 9 +++++++ 4 files changed, 54 insertions(+) create mode 100644 packages/grpc-js/src/admin.ts diff --git a/packages/grpc-js/src/admin.ts b/packages/grpc-js/src/admin.ts new file mode 100644 index 000000000..7745d07d8 --- /dev/null +++ b/packages/grpc-js/src/admin.ts @@ -0,0 +1,39 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ServiceDefinition } from "./make-client"; +import { Server, UntypedServiceImplementation } from "./server"; + +interface GetServiceDefinition { + (): ServiceDefinition; +} + +interface GetHandlers { + (): UntypedServiceImplementation; +} + +const registeredAdminServices: {getServiceDefinition: GetServiceDefinition, getHandlers: GetHandlers}[] = []; + +export function registerAdminService(getServiceDefinition: GetServiceDefinition, getHandlers: GetHandlers) { + registeredAdminServices.push({getServiceDefinition, getHandlers}); +} + +export function addAdminServicesToServer(server: Server): void { + for (const {getServiceDefinition, getHandlers} of registeredAdminServices) { + server.addService(getServiceDefinition(), getHandlers()); + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 7965ad3c2..1e2cbf708 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -50,6 +50,7 @@ import { GetServerSocketsResponse } from "./generated/grpc/channelz/v1/GetServer import { ChannelzDefinition, ChannelzHandlers } from "./generated/grpc/channelz/v1/Channelz"; import { ProtoGrpcType as ChannelzProtoGrpcType } from "./generated/channelz"; import type { loadSync } from '@grpc/proto-loader'; +import { registerAdminService } from "./admin"; export type TraceSeverity = 'CT_UNKNOWN' | 'CT_INFO' | 'CT_WARNING' | 'CT_ERROR'; @@ -713,4 +714,8 @@ export function getChannelzServiceDefinition(): ChannelzDefinition { }) as unknown as ChannelzProtoGrpcType; loadedChannelzDefinition = loadedProto.grpc.channelz.v1.Channelz.service; return loadedChannelzDefinition; +} + +export function setup() { + registerAdminService(getChannelzServiceDefinition, getChannelzHandlers); } \ No newline at end of file diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 24b795f06..4d158a53f 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -32,3 +32,4 @@ export { export { Call as CallStream } from './call-stream'; export { Filter, BaseFilter, FilterFactory } from './filter'; export { FilterStackFactory } from './filter-stack'; +export { registerAdminService } from './admin'; diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 0730a26eb..29941d27e 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -249,6 +249,13 @@ export { GrpcObject } from './make-client'; export { ChannelOptions } from './channel-options'; +export { + getChannelzServiceDefinition, + getChannelzHandlers +} from './channelz'; + +export { addAdminServicesToServer } from './admin'; + import * as experimental from './experimental'; export { experimental }; @@ -257,6 +264,7 @@ import * as resolver_uds from './resolver-uds'; import * as resolver_ip from './resolver-ip'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; +import * as channelz from './channelz'; (() => { resolver_dns.setup(); @@ -264,4 +272,5 @@ import * as load_balancer_round_robin from './load-balancer-round-robin'; resolver_ip.setup(); load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); + channelz.setup(); })(); From 305623e2eba833af1432685872f03cad8041cb97 Mon Sep 17 00:00:00 2001 From: bbesset Date: Wed, 15 Sep 2021 09:03:49 +0200 Subject: [PATCH 1510/1899] adds sometimes required Host header to proxy connection --- packages/grpc-js/src/http_proxy.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 14e88f068..248949a80 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -190,6 +190,9 @@ export function getProxiedConnection( method: 'CONNECT', path: parsedTarget.path, }; + const headers: http.OutgoingHttpHeaders = { + Host: parsedTarget.path, + }; // Connect to the subchannel address as a proxy if (isTcpSubchannelAddress(address)) { options.host = address.host; @@ -198,14 +201,13 @@ export function getProxiedConnection( options.socketPath = address.path; } if ('grpc.http_connect_creds' in channelOptions) { - options.headers = { - 'Proxy-Authorization': - 'Basic ' + - Buffer.from( - channelOptions['grpc.http_connect_creds'] as string - ).toString('base64'), - }; + headers['Proxy-Authorization'] = + 'Basic ' + + Buffer.from( + channelOptions['grpc.http_connect_creds'] as string + ).toString('base64'); } + options.headers = headers const proxyAddressString = subchannelAddressToString(address); trace('Using proxy ' + proxyAddressString + ' to connect to ' + options.path); return new Promise((resolve, reject) => { From 1ae04af7ba97b59c23da69345d3eb3a1b6c7a4af Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 16 Sep 2021 14:48:06 -0700 Subject: [PATCH 1511/1899] grpc-js-xds: fix use of splice in interop test code --- packages/grpc-js-xds/interop/xds-interop-client.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index a414ffe7f..6cd3aeb33 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -130,6 +130,13 @@ class CallStatsTracker { private subscribers: CallSubscriber[] = []; + private removeSubscriber(subscriber: CallSubscriber) { + const index = this.subscribers.indexOf(subscriber); + if (index >= 0) { + this.subscribers.splice(index, 1); + } + } + getCallStats(callCount: number, timeoutSec: number): Promise { return new Promise((resolve, reject) => { let finished = false; @@ -142,7 +149,7 @@ class CallStatsTracker { setTimeout(() => { if (!finished) { finished = true; - this.subscribers.splice(this.subscribers.indexOf(subscriber), 1); + this.removeSubscriber(subscriber); resolve(subscriber.getFinalStats()); } }, timeoutSec * 1000) @@ -155,7 +162,7 @@ class CallStatsTracker { for (const subscriber of callSubscribers) { subscriber.addCallStarted(); if (!subscriber.needsMoreCalls()) { - this.subscribers.splice(this.subscribers.indexOf(subscriber), 1); + this.removeSubscriber(subscriber); } } return { From 7b656758397d4b5a02098980a16abf67061d3994 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Sep 2021 11:20:41 -0700 Subject: [PATCH 1512/1899] grpc-js-xds: Log loaded bootstrap info in xDS client --- packages/grpc-js-xds/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 952ae81f4..de4fba23e 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -340,6 +340,7 @@ export class XdsClient { if (this.hasShutdown) { return; } + trace('Loaded bootstrap info: ' + JSON.stringify(bootstrapInfo, undefined, 2)); if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('xds_v3') >= 0) { this.apiVersion = XdsApiVersion.V3; } else { From de5eb821d121e27a5c0d0b3a92e054f691381b42 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Sep 2021 11:20:41 -0700 Subject: [PATCH 1513/1899] grpc-js-xds: Log loaded bootstrap info in xDS client --- packages/grpc-js-xds/src/xds-client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 952ae81f4..de4fba23e 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -340,6 +340,7 @@ export class XdsClient { if (this.hasShutdown) { return; } + trace('Loaded bootstrap info: ' + JSON.stringify(bootstrapInfo, undefined, 2)); if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('xds_v3') >= 0) { this.apiVersion = XdsApiVersion.V3; } else { From 4229b76812f6b85a8c8bec95e319a7d2c59066bf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Sep 2021 11:40:15 -0700 Subject: [PATCH 1514/1899] grpc-js-xds: Add Node message logging --- packages/grpc-js-xds/src/xds-client.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index de4fba23e..41bc27147 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -371,6 +371,13 @@ export class XdsClient { ...nodeV3, client_features: ['envoy.lrs.supports_send_all_clusters'], }; + if (this.apiVersion === XdsApiVersion.V2) { + trace('ADS Node: ' + JSON.stringify(this.adsNodeV2, undefined, 2)); + trace('LRS Node: ' + JSON.stringify(this.lrsNodeV2, undefined, 2)); + } else { + trace('ADS Node: ' + JSON.stringify(this.adsNodeV3, undefined, 2)); + trace('LRS Node: ' + JSON.stringify(this.lrsNodeV3, undefined, 2)); + } const credentialsConfigs = bootstrapInfo.xdsServers[0].channelCreds; let channelCreds: ChannelCredentials | null = null; for (const config of credentialsConfigs) { From cfcc491a61057f9d92459fa76828a5e1b125acea Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 20 Sep 2021 11:40:15 -0700 Subject: [PATCH 1515/1899] grpc-js-xds: Add Node message logging --- packages/grpc-js-xds/src/xds-client.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index de4fba23e..41bc27147 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -371,6 +371,13 @@ export class XdsClient { ...nodeV3, client_features: ['envoy.lrs.supports_send_all_clusters'], }; + if (this.apiVersion === XdsApiVersion.V2) { + trace('ADS Node: ' + JSON.stringify(this.adsNodeV2, undefined, 2)); + trace('LRS Node: ' + JSON.stringify(this.lrsNodeV2, undefined, 2)); + } else { + trace('ADS Node: ' + JSON.stringify(this.adsNodeV3, undefined, 2)); + trace('LRS Node: ' + JSON.stringify(this.lrsNodeV3, undefined, 2)); + } const credentialsConfigs = bootstrapInfo.xdsServers[0].channelCreds; let channelCreds: ChannelCredentials | null = null; for (const config of credentialsConfigs) { From d60c4ea16f599d205fad63e379edb210da1faaad Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Sep 2021 10:12:11 -0700 Subject: [PATCH 1516/1899] Add channelz tests and fix some bugs --- packages/grpc-js/src/call-stream.ts | 18 +- packages/grpc-js/src/channel.ts | 12 +- packages/grpc-js/src/channelz.ts | 18 +- packages/grpc-js/src/server-call.ts | 1 - packages/grpc-js/src/server.ts | 8 +- packages/grpc-js/src/subchannel.ts | 43 ++-- packages/grpc-js/test/test-channelz.ts | 289 +++++++++++++++++++++++++ test/channelz/channelz_manual_test.js | 73 +++++++ test/interop/interop_server.js | 2 +- 9 files changed, 421 insertions(+), 43 deletions(-) create mode 100644 packages/grpc-js/test/test-channelz.ts create mode 100644 test/channelz/channelz_manual_test.js diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index e030d9e39..f8bca8db7 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -25,7 +25,7 @@ import { FilterStackFactory, FilterStack } from './filter-stack'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; import { ChannelImplementation } from './channel'; -import { Subchannel } from './subchannel'; +import { SubchannelCallStatsTracker, Subchannel } from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; import { ServerSurfaceCall } from './server-call'; @@ -252,6 +252,8 @@ export class Http2CallStream implements Call { private statusWatchers: ((status: StatusObject) => void)[] = []; private streamEndWatchers: ((success: boolean) => void)[] = []; + private callStatsTracker: SubchannelCallStatsTracker | null = null; + constructor( private readonly methodName: string, private readonly channel: ChannelImplementation, @@ -468,10 +470,16 @@ export class Http2CallStream implements Call { this.endCall(status); } + private writeMessageToStream(message: Buffer, callback: WriteCallback) { + this.callStatsTracker?.addMessageSent(); + this.http2Stream!.write(message, callback); + } + attachHttp2Stream( stream: http2.ClientHttp2Stream, subchannel: Subchannel, - extraFilters: FilterFactory[] + extraFilters: FilterFactory[], + callStatsTracker: SubchannelCallStatsTracker ): void { this.filterStack.push( extraFilters.map((filterFactory) => filterFactory.createFilter(this)) @@ -484,6 +492,7 @@ export class Http2CallStream implements Call { ); this.http2Stream = stream; this.subchannel = subchannel; + this.callStatsTracker = callStatsTracker; subchannel.addDisconnectListener(this.disconnectListener); subchannel.callRef(); stream.on('response', (headers, flags) => { @@ -549,6 +558,7 @@ export class Http2CallStream implements Call { for (const message of messages) { this.trace('parsed message of length ' + message.length); + this.callStatsTracker!.addMessageReceived(); this.tryPush(message); } }); @@ -666,7 +676,7 @@ export class Http2CallStream implements Call { this.pendingWrite.length + ' (deferred)' ); - stream.write(this.pendingWrite, this.pendingWriteCallback); + this.writeMessageToStream(this.pendingWrite, this.pendingWriteCallback); } this.maybeCloseWrites(); } @@ -802,7 +812,7 @@ export class Http2CallStream implements Call { this.pendingWriteCallback = cb; } else { this.trace('sending data chunk of length ' + message.message.length); - this.http2Stream.write(message.message, cb); + this.writeMessageToStream(message.message, cb); this.maybeCloseWrites(); } }, this.handleFilterError.bind(this)); diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index c5f7352e4..636ebc44b 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -103,6 +103,12 @@ export interface Channel { deadline: Date | number, callback: (error?: Error) => void ): void; + /** + * Get the channelz reference object for this channel. A request to the + * channelz service for the id in this object will provide information + * about this channel. + */ + getChannelzRef(): ChannelRef; /** * Create a call object. Call is an opaque type that is used by the Client * class. This function is called by the gRPC library when starting a @@ -243,7 +249,7 @@ export class ChannelImplementation implements Channel { Object.assign({}, this.options, subchannelArgs), this.credentials ); - this.channelzTrace.addTrace('CT_INFO', 'Created or got existing subchannel', subchannel.getChannelzRef()); + this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); return subchannel; }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { @@ -677,6 +683,10 @@ export class ChannelImplementation implements Channel { this.connectivityStateWatchers.push(watcherObject); } + getChannelzRef() { + return this.channelzRef; + } + createCall( method: string, deadline: Deadline, diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 1e2cbf708..7efe54780 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -51,6 +51,7 @@ import { ChannelzDefinition, ChannelzHandlers } from "./generated/grpc/channelz/ import { ProtoGrpcType as ChannelzProtoGrpcType } from "./generated/channelz"; import type { loadSync } from '@grpc/proto-loader'; import { registerAdminService } from "./admin"; +import { loadPackageDefinition } from "./make-client"; export type TraceSeverity = 'CT_UNKNOWN' | 'CT_INFO' | 'CT_WARNING' | 'CT_ERROR'; @@ -455,9 +456,10 @@ function dateToProtoTimestamp(date?: Date | null): Timestamp | null { if (!date) { return null; } + const millisSinceEpoch = date.getTime(); return { - seconds: date.getSeconds(), - nanos: date.getMilliseconds() * 1_000_000 + seconds: (millisSinceEpoch / 1000) | 0, + nanos: (millisSinceEpoch % 1000) * 1_000_000 } } @@ -664,7 +666,10 @@ function GetServerSockets(call: ServerUnaryCall ref1.id - ref2.id); + // If we wanted to include listener sockets in the result, this line would + // instead say + // const allSockets = resolvedInfo.listenerChildren.sockets.concat(resolvedInfo.sessionChildren.sockets).sort((ref1, ref2) => ref1.id - ref2.id); + const allSockets = resolvedInfo.sessionChildren.sockets.sort((ref1, ref2) => ref1.id - ref2.id); const resultList: SocketRefMessage[] = []; let i = 0; for (; i < allSockets.length; i++) { @@ -709,10 +714,11 @@ export function getChannelzServiceDefinition(): ChannelzDefinition { defaults: true, oneofs: true, includeDirs: [ - '../../proto' + `${__dirname}/../../proto` ] - }) as unknown as ChannelzProtoGrpcType; - loadedChannelzDefinition = loadedProto.grpc.channelz.v1.Channelz.service; + }); + const channelzGrpcObject = loadPackageDefinition(loadedProto) as unknown as ChannelzProtoGrpcType; + loadedChannelzDefinition = channelzGrpcObject.grpc.channelz.v1.Channelz.service; return loadedChannelzDefinition; } diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index cde7d9185..1bd56634f 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -570,7 +570,6 @@ export class Http2ServerCallStream< const response = this.serializeMessage(value!); this.write(response); - this.emit('sendMessage'); this.sendStatus({ code: Status.OK, details: 'OK', metadata }); } catch (err) { err.code = Status.INTERNAL; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ef31dadce..4a4091038 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -188,7 +188,7 @@ export class Server { const peerCertificate = tlsSocket.getPeerCertificate(); tlsInfo = { cipherSuiteStandardName: cipherInfo.standardName ?? null, - cipherSuiteOtherName: cipherInfo.standardName ? cipherInfo.name: null, + cipherSuiteOtherName: cipherInfo.standardName ? null : cipherInfo.name, localCertificate: (certificate && 'raw' in certificate) ? certificate.raw : null, remoteCertificate: (peerCertificate && 'raw' in peerCertificate) ? peerCertificate.raw : null }; @@ -424,6 +424,7 @@ export class Server { remoteFlowControlWindow: null }; }); + this.listenerChildrenTracker.refChild(channelzRef); this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve('port' in boundSubchannelAddress ? boundSubchannelAddress.port : portNum); @@ -491,6 +492,7 @@ export class Server { remoteFlowControlWindow: null }; }); + this.listenerChildrenTracker.refChild(channelzRef); this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve( @@ -676,6 +678,10 @@ export class Server { throw new Error('Not yet implemented'); } + getChannelzRef() { + return this.channelzRef; + } + private _setupHandlers( http2Server: http2.Http2Server | http2.Http2SecureServer ): void { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index e7e7a9f08..c11a752ab 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -68,6 +68,11 @@ export type ConnectivityStateListener = ( newState: ConnectivityState ) => void; +export interface SubchannelCallStatsTracker { + addMessageSent(): void; + addMessageReceived(): void; +} + const { HTTP2_HEADER_AUTHORITY, HTTP2_HEADER_CONTENT_TYPE, @@ -178,33 +183,6 @@ export class Subchannel { private messagesReceived = 0; private lastMessageSentTimestamp: Date | null = null; private lastMessageReceivedTimestamp: Date | null = null; - private MessageCountFilter = class extends BaseFilter implements Filter { - private session: http2.ClientHttp2Session; - constructor(private parent: Subchannel) { - super(); - this.session = parent.session!; - } - sendMessage(message: Promise): Promise { - if (this.parent.session === this.session) { - this.parent.messagesSent += 1; - this.parent.lastMessageSentTimestamp = new Date(); - } - return message; - } - receiveMessage(message: Promise): Promise { - if (this.parent.session === this.session) { - this.parent.messagesReceived += 1; - this.parent.lastMessageReceivedTimestamp = new Date(); - } - return message; - } - }; - private MessageCountFilterFactory = class implements FilterFactory { - constructor(private parent: Subchannel) {} - createFilter(callStream: Call): Filter { - return new this.parent.MessageCountFilter(this.parent); - } - } /** * A class representing a connection to a single backend. @@ -848,8 +826,15 @@ export class Subchannel { } } }); - extraFilterFactories.push(new this.MessageCountFilterFactory(this)); - callStream.attachHttp2Stream(http2Stream, this, extraFilterFactories); + callStream.attachHttp2Stream(http2Stream, this, extraFilterFactories, { + addMessageSent: () => { + this.messagesSent += 1; + this.lastMessageSentTimestamp = new Date(); + }, + addMessageReceived: () => { + this.messagesReceived += 1; + } + }); } /** diff --git a/packages/grpc-js/test/test-channelz.ts b/packages/grpc-js/test/test-channelz.ts new file mode 100644 index 000000000..2cca780e8 --- /dev/null +++ b/packages/grpc-js/test/test-channelz.ts @@ -0,0 +1,289 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import * as protoLoader from '@grpc/proto-loader'; +import * as grpc from '../src'; + +import { ProtoGrpcType } from '../src/generated/channelz' +import { ChannelzClient } from '../src/generated/grpc/channelz/v1/Channelz'; +import { Channel__Output } from '../src/generated/grpc/channelz/v1/Channel'; +import { Server__Output } from '../src/generated/grpc/channelz/v1/Server'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { loadProtoFile } from './common'; + +const loadedChannelzProto = protoLoader.loadSync('channelz.proto', { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + `${__dirname}/../../proto` + ] +}); +const channelzGrpcObject = grpc.loadPackageDefinition(loadedChannelzProto) as unknown as ProtoGrpcType; + +const TestServiceClient = loadProtoFile(`${__dirname}/fixtures/test_service.proto`).TestService as ServiceClientConstructor; + +const testServiceImpl: grpc.UntypedServiceImplementation = { + unary(call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) { + if (call.request.error) { + setTimeout(() => { + callback({ + code: grpc.status.INVALID_ARGUMENT, + details: call.request.message + }); + }, call.request.errorAfter) + } else { + callback(null, {count: 1}); + } + } +} + +describe('Channelz', () => { + let channelzServer: grpc.Server; + let channelzClient: ChannelzClient; + let testServer: grpc.Server; + let testClient: ServiceClient; + + before((done) => { + channelzServer = new grpc.Server(); + channelzServer.addService(grpc.getChannelzServiceDefinition(), grpc.getChannelzHandlers()); + channelzServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + done(error); + return; + } + channelzServer.start(); + channelzClient = new channelzGrpcObject.grpc.channelz.v1.Channelz(`localhost:${port}`, grpc.credentials.createInsecure()); + done(); + }); + }); + + after(() => { + channelzClient.close(); + channelzServer.forceShutdown(); + }); + + beforeEach((done) => { + testServer = new grpc.Server(); + testServer.addService(TestServiceClient.service, testServiceImpl); + testServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + done(error); + return; + } + testServer.start(); + testClient = new TestServiceClient(`localhost:${port}`, grpc.credentials.createInsecure()); + done(); + }); + }); + + afterEach(() => { + testClient.close(); + testServer.forceShutdown(); + }); + + it('should see a newly created channel', (done) => { + // Test that the specific test client channel info can be retrieved + channelzClient.GetChannel({channel_id: testClient.getChannel().getChannelzRef().id}, (error, result) => { + assert.ifError(error); + assert(result); + assert(result.channel); + assert(result.channel.ref); + assert.strictEqual(+result.channel.ref.channel_id, testClient.getChannel().getChannelzRef().id); + // Test that the channel is in the list of top channels + channelzClient.getTopChannels({start_channel_id: testClient.getChannel().getChannelzRef().id, max_results:1}, (error, result) => { + assert.ifError(error); + assert(result); + assert.strictEqual(result.channel.length, 1); + assert(result.channel[0].ref); + assert.strictEqual(+result.channel[0].ref.channel_id, testClient.getChannel().getChannelzRef().id); + done(); + }); + }); + }); + + it('should see a newly created server', (done) => { + // Test that the specific test server info can be retrieved + channelzClient.getServer({server_id: testServer.getChannelzRef().id}, (error, result) => { + assert.ifError(error); + assert(result); + assert(result.server); + assert(result.server.ref); + assert.strictEqual(+result.server.ref.server_id, testServer.getChannelzRef().id); + // Test that the server is in the list of servers + channelzClient.getServers({start_server_id: testServer.getChannelzRef().id, max_results: 1}, (error, result) => { + assert.ifError(error); + assert(result); + assert.strictEqual(result.server.length, 1); + assert(result.server[0].ref); + assert.strictEqual(+result.server[0].ref.server_id, testServer.getChannelzRef().id); + done(); + }); + }); + }); + + it('should count successful calls', (done) => { + testClient.unary({}, (error: grpc.ServiceError, value: unknown) => { + assert.ifError(error); + // Channel data tests + channelzClient.GetChannel({channel_id: testClient.getChannel().getChannelzRef().id}, (error, channelResult) => { + assert.ifError(error); + assert(channelResult); + assert(channelResult.channel); + assert(channelResult.channel.ref); + assert(channelResult.channel.data); + assert.strictEqual(+channelResult.channel.data.calls_started, 1); + assert.strictEqual(+channelResult.channel.data.calls_succeeded, 1); + assert.strictEqual(+channelResult.channel.data.calls_failed, 0); + assert.strictEqual(channelResult.channel.subchannel_ref.length, 1); + channelzClient.getSubchannel({subchannel_id: channelResult.channel.subchannel_ref[0].subchannel_id}, (error, subchannelResult) => { + assert.ifError(error); + assert(subchannelResult); + assert(subchannelResult.subchannel); + assert(subchannelResult.subchannel.ref); + assert(subchannelResult.subchannel.data); + assert.strictEqual(subchannelResult.subchannel.ref.subchannel_id, channelResult.channel!.subchannel_ref[0].subchannel_id); + assert.strictEqual(+subchannelResult.subchannel.data.calls_started, 1); + assert.strictEqual(+subchannelResult.subchannel.data.calls_succeeded, 1); + assert.strictEqual(+subchannelResult.subchannel.data.calls_failed, 0); + assert.strictEqual(subchannelResult.subchannel.socket_ref.length, 1); + channelzClient.getSocket({socket_id: subchannelResult.subchannel.socket_ref[0].socket_id}, (error, socketResult) => { + assert.ifError(error); + assert(socketResult); + assert(socketResult.socket); + assert(socketResult.socket.ref); + assert(socketResult.socket.data); + assert.strictEqual(socketResult.socket.ref.socket_id, subchannelResult.subchannel!.socket_ref[0].socket_id); + assert.strictEqual(+socketResult.socket.data.streams_started, 1); + assert.strictEqual(+socketResult.socket.data.streams_succeeded, 1); + assert.strictEqual(+socketResult.socket.data.streams_failed, 0); + assert.strictEqual(+socketResult.socket.data.messages_received, 1); + assert.strictEqual(+socketResult.socket.data.messages_sent, 1); + // Server data tests + channelzClient.getServer({server_id: testServer.getChannelzRef().id}, (error, serverResult) => { + assert.ifError(error); + assert(serverResult); + assert(serverResult.server); + assert(serverResult.server.ref); + assert(serverResult.server.data); + assert.strictEqual(+serverResult.server.ref.server_id, testServer.getChannelzRef().id); + assert.strictEqual(+serverResult.server.data.calls_started, 1); + assert.strictEqual(+serverResult.server.data.calls_succeeded, 1); + assert.strictEqual(+serverResult.server.data.calls_failed, 0); + channelzClient.getServerSockets({server_id: testServer.getChannelzRef().id}, (error, socketsResult) => { + assert.ifError(error); + assert(socketsResult); + assert.strictEqual(socketsResult.socket_ref.length, 1); + channelzClient.getSocket({socket_id: socketsResult.socket_ref[0].socket_id}, (error, serverSocketResult) => { + assert.ifError(error); + assert(serverSocketResult); + assert(serverSocketResult.socket); + assert(serverSocketResult.socket.ref); + assert(serverSocketResult.socket.data); + assert.strictEqual(serverSocketResult.socket.ref.socket_id, socketsResult.socket_ref[0].socket_id); + assert.strictEqual(+serverSocketResult.socket.data.streams_started, 1); + assert.strictEqual(+serverSocketResult.socket.data.streams_succeeded, 1); + assert.strictEqual(+serverSocketResult.socket.data.streams_failed, 0); + assert.strictEqual(+serverSocketResult.socket.data.messages_received, 1); + assert.strictEqual(+serverSocketResult.socket.data.messages_sent, 1); + done(); + }); + }); + }); + }); + }); + }); + }); + }); + + it('should count failed calls', (done) => { + testClient.unary({error: true}, (error: grpc.ServiceError, value: unknown) => { + assert(error); + // Channel data tests + channelzClient.GetChannel({channel_id: testClient.getChannel().getChannelzRef().id}, (error, channelResult) => { + assert.ifError(error); + assert(channelResult); + assert(channelResult.channel); + assert(channelResult.channel.ref); + assert(channelResult.channel.data); + assert.strictEqual(+channelResult.channel.data.calls_started, 1); + assert.strictEqual(+channelResult.channel.data.calls_succeeded, 0); + assert.strictEqual(+channelResult.channel.data.calls_failed, 1); + assert.strictEqual(channelResult.channel.subchannel_ref.length, 1); + channelzClient.getSubchannel({subchannel_id: channelResult.channel.subchannel_ref[0].subchannel_id}, (error, subchannelResult) => { + assert.ifError(error); + assert(subchannelResult); + assert(subchannelResult.subchannel); + assert(subchannelResult.subchannel.ref); + assert(subchannelResult.subchannel.data); + assert.strictEqual(subchannelResult.subchannel.ref.subchannel_id, channelResult.channel!.subchannel_ref[0].subchannel_id); + assert.strictEqual(+subchannelResult.subchannel.data.calls_started, 1); + assert.strictEqual(+subchannelResult.subchannel.data.calls_succeeded, 0); + assert.strictEqual(+subchannelResult.subchannel.data.calls_failed, 1); + assert.strictEqual(subchannelResult.subchannel.socket_ref.length, 1); + channelzClient.getSocket({socket_id: subchannelResult.subchannel.socket_ref[0].socket_id}, (error, socketResult) => { + assert.ifError(error); + assert(socketResult); + assert(socketResult.socket); + assert(socketResult.socket.ref); + assert(socketResult.socket.data); + assert.strictEqual(socketResult.socket.ref.socket_id, subchannelResult.subchannel!.socket_ref[0].socket_id); + assert.strictEqual(+socketResult.socket.data.streams_started, 1); + assert.strictEqual(+socketResult.socket.data.streams_succeeded, 1); + assert.strictEqual(+socketResult.socket.data.streams_failed, 0); + assert.strictEqual(+socketResult.socket.data.messages_received, 0); + assert.strictEqual(+socketResult.socket.data.messages_sent, 1); + // Server data tests + channelzClient.getServer({server_id: testServer.getChannelzRef().id}, (error, serverResult) => { + assert.ifError(error); + assert(serverResult); + assert(serverResult.server); + assert(serverResult.server.ref); + assert(serverResult.server.data); + assert.strictEqual(+serverResult.server.ref.server_id, testServer.getChannelzRef().id); + assert.strictEqual(+serverResult.server.data.calls_started, 1); + assert.strictEqual(+serverResult.server.data.calls_succeeded, 0); + assert.strictEqual(+serverResult.server.data.calls_failed, 1); + channelzClient.getServerSockets({server_id: testServer.getChannelzRef().id}, (error, socketsResult) => { + assert.ifError(error); + assert(socketsResult); + assert.strictEqual(socketsResult.socket_ref.length, 1); + channelzClient.getSocket({socket_id: socketsResult.socket_ref[0].socket_id}, (error, serverSocketResult) => { + assert.ifError(error); + assert(serverSocketResult); + assert(serverSocketResult.socket); + assert(serverSocketResult.socket.ref); + assert(serverSocketResult.socket.data); + assert.strictEqual(serverSocketResult.socket.ref.socket_id, socketsResult.socket_ref[0].socket_id); + assert.strictEqual(+serverSocketResult.socket.data.streams_started, 1); + assert.strictEqual(+serverSocketResult.socket.data.streams_succeeded, 0); + assert.strictEqual(+serverSocketResult.socket.data.streams_failed, 1); + assert.strictEqual(+serverSocketResult.socket.data.messages_received, 1); + assert.strictEqual(+serverSocketResult.socket.data.messages_sent, 0); + done(); + }); + }); + }); + }); + }); + }); + }); + }); +}); \ No newline at end of file diff --git a/test/channelz/channelz_manual_test.js b/test/channelz/channelz_manual_test.js new file mode 100644 index 000000000..2f77df3cc --- /dev/null +++ b/test/channelz/channelz_manual_test.js @@ -0,0 +1,73 @@ +/* + * + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +'use strict'; + +require('../fixtures/js_js'); +const interopClient = require('../interop/interop_client'); +const interopServer = require('../interop/interop_server'); +const serverGrpc = require('../any_grpc').server; + +const hostOverride = 'foo.test.google.fr'; + +const testCases = [ + 'empty_unary', + 'large_unary', + 'client_streaming', + 'server_streaming', + 'ping_pong', + 'empty_stream', + 'cancel_after_begin', + 'cancel_after_first_response', + 'timeout_on_sleeping_server', + 'custom_metadata', + 'status_code_and_message', + 'special_status_message', + 'unimplemented_service', + 'unimplemented_method' +]; + +function getRandomTest() { + return testCases[(Math.random() * testCases.length) | 0]; +} + +let testCompleteCount = 0; + +interopServer.getServer('0', true, (error, result) => { + if (error) { + throw error; + } + const channelzServer = new serverGrpc.Server(); + channelzServer.bindAsync('localhost:0', serverGrpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + throw error; + } + console.log(`Serving channelz at port ${port}`); + serverGrpc.addAdminServicesToServer(channelzServer); + channelzServer.start(); + result.server.start(); + setInterval(() => { + interopClient.runTest(`localhost:${result.port}`, hostOverride, getRandomTest(), true, true, () => { + testCompleteCount += 1; + if (testCompleteCount % 100 === 0) { + console.log(`Completed ${testCompleteCount} tests`); + } + }); + }, 100); + }); +}) \ No newline at end of file diff --git a/test/interop/interop_server.js b/test/interop/interop_server.js index cf7ae354e..b67ec5a8a 100644 --- a/test/interop/interop_server.js +++ b/test/interop/interop_server.js @@ -200,7 +200,7 @@ function handleHalfDuplex(call) { * Get a server object bound to the given port * @param {string} port Port to which to bind * @param {boolean} tls Indicates that the bound port should use TLS - * @param {function(Error, {{server: Server, port: number}})} callback Callback + * @param {function(Error, {server: Server, port: number})} callback Callback * to call with result or error * @param {object?} options Optional additional options to use when * constructing the server From 4b6ea2b78113c8e8b0c1caad0e0a010d8ca6f310 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Sep 2021 10:47:22 -0700 Subject: [PATCH 1517/1899] Add channelz ID to trace logs, add a few trace log lines --- packages/grpc-js/src/channel.ts | 56 ++++++++++++----------------- packages/grpc-js/src/server.ts | 20 ++++++----- packages/grpc-js/src/subchannel.ts | 57 ++++++++++++++---------------- 3 files changed, 59 insertions(+), 74 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 636ebc44b..1b5ed3cc0 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -297,13 +297,7 @@ export class ChannelImplementation implements Channel { (status) => { this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); if (this.configSelectionQueue.length > 0) { - trace( - LogVerbosity.DEBUG, - 'channel', - 'Name resolution failed for target ' + - uriToString(this.target) + - ' with calls queued for config selection' - ); + this.trace('Name resolution failed with calls queued for config selection'); } const localQueue = this.configSelectionQueue; this.configSelectionQueue = []; @@ -324,6 +318,7 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); + this.trace('Constructed channel'); } private getChannelzInfo(): ChannelInfo { @@ -336,12 +331,14 @@ export class ChannelImplementation implements Channel { }; } + private trace(text: string, verbosityOverride?: LogVerbosity) { + trace(verbosityOverride ?? LogVerbosity.DEBUG, 'channel', '(' + this.channelzRef.id + ') ' + uriToString(this.target) + ' ' + text); + } + private callRefTimerRef() { // If the hasRef function does not exist, always run the code if (!this.callRefTimer.hasRef?.()) { - trace( - LogVerbosity.DEBUG, - 'channel', + this.trace( 'callRefTimer.ref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + @@ -354,9 +351,7 @@ export class ChannelImplementation implements Channel { private callRefTimerUnref() { // If the hasRef function does not exist, always run the code if (!this.callRefTimer.hasRef || this.callRefTimer.hasRef()) { - trace( - LogVerbosity.DEBUG, - 'channel', + this.trace( 'callRefTimer.unref | configSelectionQueue.length=' + this.configSelectionQueue.length + ' pickQueue.length=' + @@ -391,9 +386,7 @@ export class ChannelImplementation implements Channel { metadata: callMetadata, extraPickInfo: callConfig.pickInformation, }); - trace( - LogVerbosity.DEBUG, - 'channel', + this.trace( 'Pick result: ' + PickResultType[pickResult.pickResultType] + ' subchannel: ' + @@ -466,25 +459,23 @@ export class ChannelImplementation implements Channel { * the stream because the correct behavior may be * re-queueing instead, based on the logic in the rest of * tryPick */ - trace( - LogVerbosity.INFO, - 'channel', + this.trace( 'Failed to start call on picked subchannel ' + pickResult.subchannel!.getAddress() + ' with error ' + (error as Error).message + - '. Retrying pick' + '. Retrying pick', + LogVerbosity.INFO ); this.tryPick(callStream, callMetadata, callConfig); } else { - trace( - LogVerbosity.INFO, - 'channel', + this.trace( 'Failed to start call on picked subchanel ' + pickResult.subchannel!.getAddress() + ' with error ' + (error as Error).message + - '. Ending call' + '. Ending call', + LogVerbosity.INFO ); callStream.cancelWithStatus( Status.INTERNAL, @@ -497,14 +488,13 @@ export class ChannelImplementation implements Channel { } else { /* The logic for doing this here is the same as in the catch * block above */ - trace( - LogVerbosity.INFO, - 'channel', + this.trace( 'Picked subchannel ' + pickResult.subchannel!.getAddress() + ' has state ' + ConnectivityState[subchannelState] + - ' after metadata filters. Retrying pick' + ' after metadata filters. Retrying pick', + LogVerbosity.INFO ); this.tryPick(callStream, callMetadata, callConfig); } @@ -560,7 +550,8 @@ export class ChannelImplementation implements Channel { trace( LogVerbosity.DEBUG, 'connectivity_state', - uriToString(this.target) + + '(' + this.channelzRef.id + ') ' + + uriToString(this.target) + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + @@ -706,11 +697,8 @@ export class ChannelImplementation implements Channel { throw new Error('Channel has been shut down'); } const callNumber = getNewCallNumber(); - trace( - LogVerbosity.DEBUG, - 'channel', - uriToString(this.target) + - ' createCall [' + + this.trace( + 'createCall [' + callNumber + '] method="' + method + diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 4a4091038..caaa2fa3d 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -64,10 +64,6 @@ import { CipherNameAndProtocol, TLSSocket } from 'tls'; const TRACER_NAME = 'server'; -function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); -} - interface BindResult { port: number; count: number; @@ -163,6 +159,7 @@ export class Server { this.options = options ?? {}; this.channelzRef = registerChannelzServer(() => this.getChannelzInfo()); this.channelzTrace.addTrace('CT_INFO', 'Server created'); + this.trace('Server constructed'); } private getChannelzInfo(): ServerInfo { @@ -217,6 +214,11 @@ export class Server { }; } + private trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + text); + } + + addProtoService(): void { throw new Error('Not implemented. Use addService() instead'); } @@ -372,7 +374,7 @@ export class Server { } return Promise.all( addressList.map((address) => { - trace('Attempting to bind ' + subchannelAddressToString(address)); + this.trace('Attempting to bind ' + subchannelAddressToString(address)); let addr: SubchannelAddress; if (isTcpSubchannelAddress(address)) { addr = { @@ -426,7 +428,7 @@ export class Server { }); this.listenerChildrenTracker.refChild(channelzRef); this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); - trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); + this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve('port' in boundSubchannelAddress ? boundSubchannelAddress.port : portNum); http2Server.removeListener('error', onError); }); @@ -494,7 +496,7 @@ export class Server { }); this.listenerChildrenTracker.refChild(channelzRef); this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); - trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); + this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve( bindSpecificPort( addressList.slice(1), @@ -727,7 +729,7 @@ export class Server { serverAddress.address + ':' + serverAddress.port; } } - trace( + this.trace( 'Received call to method ' + path + ' at address ' + @@ -736,7 +738,7 @@ export class Server { const handler = this.handlers.get(path); if (handler === undefined) { - trace( + this.trace( 'No handler registered for method ' + path + '. Sending UNIMPLEMENTED status.' diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c11a752ab..25f06b144 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -42,14 +42,6 @@ const clientVersion = require('../../package.json').version; const TRACER_NAME = 'subchannel'; -function trace(text: string): void { - logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); -} - -function refTrace(text: string): void { - logging.trace(LogVerbosity.DEBUG, 'subchannel_refcount', text); -} - const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; const BACKOFF_MULTIPLIER = 1.6; @@ -237,6 +229,7 @@ export class Subchannel { this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo()); this.channelzTrace = new ChannelzTrace(); this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); + this.trace('Subchannel constructed'); } private getChannelzInfo(): SubchannelInfo { @@ -307,6 +300,14 @@ export class Subchannel { this.lastMessageReceivedTimestamp = null; } + private trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + + private refTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'subchannel_refcount', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + private handleBackoffTimer() { if (this.continueConnecting) { this.transitionToState( @@ -338,7 +339,8 @@ export class Subchannel { logging.trace( LogVerbosity.DEBUG, 'keepalive', - 'Sending ping to ' + this.subchannelAddressString + '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + + 'Sending ping' ); this.keepaliveTimeoutId = setTimeout(() => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); @@ -511,9 +513,8 @@ export class Subchannel { } ms` ); } - trace( - this.subchannelAddressString + - ' connection closed by GOAWAY with code ' + + this.trace( + 'connection closed by GOAWAY with code ' + errorCode ); this.transitionToState( @@ -526,9 +527,8 @@ export class Subchannel { session.once('error', (error) => { /* Do nothing here. Any error should also trigger a close event, which is * where we want to handle that. */ - trace( - this.subchannelAddressString + - ' connection closed with error ' + + this.trace( + 'connection closed with error ' + (error as Error).message ); }); @@ -607,10 +607,8 @@ export class Subchannel { if (oldStates.indexOf(this.connectivityState) === -1) { return false; } - trace( - this.subchannelAddressString + - ' ' + - ConnectivityState[this.connectivityState] + + this.trace( + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState] ); @@ -687,9 +685,8 @@ export class Subchannel { } callRef() { - refTrace( - this.subchannelAddressString + - ' callRefcount ' + + this.refTrace( + 'callRefcount ' + this.callRefcount + ' -> ' + (this.callRefcount + 1) @@ -707,9 +704,8 @@ export class Subchannel { } callUnref() { - refTrace( - this.subchannelAddressString + - ' callRefcount ' + + this.refTrace( + 'callRefcount ' + this.callRefcount + ' -> ' + (this.callRefcount - 1) @@ -728,9 +724,8 @@ export class Subchannel { } ref() { - refTrace( - this.subchannelAddressString + - ' refcount ' + + this.refTrace( + 'refcount ' + this.refcount + ' -> ' + (this.refcount + 1) @@ -739,9 +734,8 @@ export class Subchannel { } unref() { - refTrace( - this.subchannelAddressString + - ' refcount ' + + this.refTrace( + 'refcount ' + this.refcount + ' -> ' + (this.refcount - 1) @@ -803,6 +797,7 @@ export class Subchannel { LogVerbosity.DEBUG, 'call_stream', 'Starting stream on subchannel ' + + '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' with headers\n' + headersString From 8cc5f6cd24490583d204877d1d5cd9772a197f58 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Sep 2021 12:35:21 -0700 Subject: [PATCH 1518/1899] grpc-js: Loosen requirements on channel option types --- packages/grpc-js/src/channel.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 6dfca312d..ebdac7bce 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -177,18 +177,8 @@ export class ChannelImplementation implements Channel { ); } if (options) { - if ( - typeof options !== 'object' || - !Object.values(options).every( - (value) => - typeof value === 'string' || - typeof value === 'number' || - typeof value === 'undefined' - ) - ) { - throw new TypeError( - 'Channel options must be an object with string or number values' - ); + if (typeof options !== 'object') { + throw new TypeError('Channel options must be an object'); } } const originalTargetUri = parseUri(target); From 157882da451b8be623cc50a139c75b4031c9dab4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Sep 2021 15:45:22 -0700 Subject: [PATCH 1519/1899] grpc-js-xds: A few fixes for xDS tests --- packages/grpc-js-xds/scripts/xds.sh | 2 +- packages/grpc-js-xds/src/xds-bootstrap.ts | 2 +- packages/grpc-js-xds/src/xds-client.ts | 13 +++++++++++-- packages/grpc-js/src/server.ts | 2 ++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 131cbd551..a06cde84b 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -59,7 +59,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --gcp_suffix=$(date '+%s') \ --verbose \ ${XDS_V3_OPT-} \ - --client_cmd="$(which node) grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ + --client_cmd="$(which node) --enable-source-maps grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ diff --git a/packages/grpc-js-xds/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts index 64a7bcb94..876b6d958 100644 --- a/packages/grpc-js-xds/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -109,7 +109,7 @@ function validateXdsServerConfig(obj: any): XdsServerConfig { return { serverUri: obj.server_uri, channelCreds: obj.channel_creds.map(validateChannelCredsConfig), - serverFeatures: obj.server_features + serverFeatures: obj.server_features ?? [] }; } diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 41bc27147..cfb8b66ac 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -341,6 +341,16 @@ export class XdsClient { return; } trace('Loaded bootstrap info: ' + JSON.stringify(bootstrapInfo, undefined, 2)); + if (bootstrapInfo.xdsServers.length < 1) { + trace('Failed to initialize xDS Client. No servers provided in bootstrap info.'); + // Bubble this error up to any listeners + this.reportStreamError({ + code: status.INTERNAL, + details: 'Failed to initialize xDS Client. No servers provided in bootstrap info.', + metadata: new Metadata(), + }); + return; + } if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('xds_v3') >= 0) { this.apiVersion = XdsApiVersion.V3; } else { @@ -425,8 +435,7 @@ export class XdsClient { {channelOverride: channel} ); this.maybeStartLrsStream(); - }, - (error) => { + }).catch((error) => { trace('Failed to initialize xDS Client. ' + error.message); // Bubble this error up to any listeners this.reportStreamError({ diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 42b79a3cf..ed4b397d0 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -309,6 +309,7 @@ export class Server { const http2Server = setupServer(); return new Promise((resolve, reject) => { function onError(err: Error): void { + trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); resolve(err); } @@ -356,6 +357,7 @@ export class Server { const http2Server = setupServer(); return new Promise((resolve, reject) => { function onError(err: Error): void { + trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); resolve(bindWildcardPort(addressList.slice(1))); } From 2756a594958f679e6179a6c74ee61e3541e871ea Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 27 Sep 2021 16:12:23 -0700 Subject: [PATCH 1520/1899] Add a helper for creating ChannelControlHelper children --- packages/grpc-js-xds/src/load-balancer-eds.ts | 11 ++--------- packages/grpc-js-xds/src/load-balancer-lrs.ts | 10 ++-------- .../grpc-js-xds/src/load-balancer-priority.ts | 16 ++-------------- .../src/load-balancer-weighted-target.ts | 12 +++--------- .../src/load-balancer-xds-cluster-manager.ts | 12 +++--------- packages/grpc-js/src/experimental.ts | 1 + packages/grpc-js/src/load-balancer.ts | 18 ++++++++++++++++++ packages/grpc-tools/deps/protobuf | 2 +- 8 files changed, 32 insertions(+), 50 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index efb05eb78..55ad714a9 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -185,14 +185,7 @@ export class EdsLoadBalancer implements LoadBalancer { private concurrentRequests: number = 0; constructor(private readonly channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelArgs) => - this.channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ), - requestReresolution: () => - this.channelControlHelper.requestReresolution(), + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.channelControlHelper, { updateState: (connectivityState, originalPicker) => { if (this.latestEdsUpdate === null) { return; @@ -243,7 +236,7 @@ export class EdsLoadBalancer implements LoadBalancer { }; this.channelControlHelper.updateState(connectivityState, edsPicker); }, - }); + })); this.watcher = { onValidUpdate: (update) => { trace('Received EDS update for ' + this.edsServiceName + ': ' + JSON.stringify(update, undefined, 2)); diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index 566aa04c5..145501fe9 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -174,20 +174,14 @@ export class LrsLoadBalancer implements LoadBalancer { private localityStatsReporter: XdsClusterLocalityStats | null = null; constructor(private channelControlHelper: ChannelControlHelper) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelArgs) => - channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ), - requestReresolution: () => channelControlHelper.requestReresolution(), + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(channelControlHelper, { updateState: (connectivityState: ConnectivityState, picker: Picker) => { if (this.localityStatsReporter !== null) { picker = new LoadReportingPicker(picker, this.localityStatsReporter); } channelControlHelper.updateState(connectivityState, picker); }, - }); + })); } updateAddressList( diff --git a/packages/grpc-js-xds/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts index 872ed7d1b..b05e459a7 100644 --- a/packages/grpc-js-xds/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -139,23 +139,11 @@ export class PriorityLoadBalancer implements LoadBalancer { private failoverTimer: NodeJS.Timer | null = null; private deactivationTimer: NodeJS.Timer | null = null; constructor(private parent: PriorityLoadBalancer, private name: string) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: ( - subchannelAddress: SubchannelAddress, - subchannelArgs: ChannelOptions - ) => { - return this.parent.channelControlHelper.createSubchannel( - subchannelAddress, - subchannelArgs - ); - }, + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.updateState(connectivityState, picker); }, - requestReresolution: () => { - this.parent.channelControlHelper.requestReresolution(); - }, - }); + })); this.picker = new QueuePicker(this.childBalancer); } diff --git a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts index 44a6acf11..a7a28c663 100644 --- a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -168,17 +168,11 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { private weight: number = 0; constructor(private parent: WeightedTargetLoadBalancer, private name: string) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelOptions) => { - return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelOptions); - }, - updateState: (connectivityState, picker) => { + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { + updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.updateState(connectivityState, picker); }, - requestReresolution: () => { - this.parent.channelControlHelper.requestReresolution(); - } - }); + })); this.picker = new QueuePicker(this.childBalancer); } diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index 7df79e26b..6210ea84a 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -131,17 +131,11 @@ class XdsClusterManager implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; constructor(private parent: XdsClusterManager, private name: string) { - this.childBalancer = new ChildLoadBalancerHandler({ - createSubchannel: (subchannelAddress, subchannelOptions) => { - return this.parent.channelControlHelper.createSubchannel(subchannelAddress, subchannelOptions); - }, - updateState: (connectivityState, picker) => { + this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { + updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.updateState(connectivityState, picker); }, - requestReresolution: () => { - this.parent.channelControlHelper.requestReresolution(); - } - }); + })); this.picker = new QueuePicker(this.childBalancer); } diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 4d158a53f..5353f7f59 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -12,6 +12,7 @@ export { LoadBalancer, LoadBalancingConfig, ChannelControlHelper, + createChildChannelControlHelper, registerLoadBalancerType, getFirstUsableConfig, validateLoadBalancingConfig, diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 870fdb30b..19b79764c 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -52,6 +52,24 @@ export interface ChannelControlHelper { removeChannelzChild(child: ChannelRef | SubchannelRef): void; } +/** + * Create a child ChannelControlHelper that overrides some methods of the + * parent while letting others pass through to the parent unmodified. This + * allows other code to create these children without needing to know about + * all of the methods to be passed through. + * @param parent + * @param overrides + */ +export function createChildChannelControlHelper(parent: ChannelControlHelper, overrides: Partial): ChannelControlHelper { + return { + createSubchannel: overrides.createSubchannel?.bind(overrides) ?? parent.createSubchannel.bind(parent), + updateState: overrides.updateState?.bind(overrides) ?? parent.updateState.bind(parent), + requestReresolution: overrides.requestReresolution?.bind(overrides) ?? parent.requestReresolution.bind(parent), + addChannelzChild: overrides.addChannelzChild?.bind(overrides) ?? parent.addChannelzChild.bind(parent), + removeChannelzChild: overrides.removeChannelzChild?.bind(overrides) ?? parent.removeChannelzChild.bind(parent) + }; +} + /** * Tracks one or more connected subchannels and determines which subchannel * each request should use. diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index a6e1cc7e3..6aa539bf0 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit a6e1cc7e328c45a0cb9856c530c8f6cd23314163 +Subproject commit 6aa539bf0195f188ff86efe6fb8bfa2b676cdd46 From 1eea4b75bd8744757ac70ab87cae360733fe7f95 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Sep 2021 13:14:14 -0700 Subject: [PATCH 1521/1899] In server.bindAsync, call callback in process.nextTick --- packages/grpc-js/src/server.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index ed4b397d0..87788158c 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -268,6 +268,10 @@ export class Server { }; } + const deferredCallback = (error: Error | null, port: number) => { + process.nextTick(() => callback(error, port)); + } + const setupServer = (): http2.Http2Server | http2.Http2SecureServer => { let http2Server: http2.Http2Server | http2.Http2SecureServer; if (creds._isSecure()) { @@ -386,7 +390,7 @@ export class Server { // We only want one resolution result. Discard all future results resolverListener.onSuccessfulResolution = () => {}; if (addressList.length === 0) { - callback(new Error(`No addresses resolved for port ${port}`), 0); + deferredCallback(new Error(`No addresses resolved for port ${port}`), 0); return; } let bindResultPromise: Promise; @@ -409,7 +413,7 @@ export class Server { if (bindResult.count === 0) { const errorString = `No address added out of total ${addressList.length} resolved`; logging.log(LogVerbosity.ERROR, errorString); - callback(new Error(errorString), 0); + deferredCallback(new Error(errorString), 0); } else { if (bindResult.count < addressList.length) { logging.log( @@ -417,18 +421,18 @@ export class Server { `WARNING Only ${bindResult.count} addresses added out of total ${addressList.length} resolved` ); } - callback(null, bindResult.port); + deferredCallback(null, bindResult.port); } }, (error) => { const errorString = `No address added out of total ${addressList.length} resolved`; logging.log(LogVerbosity.ERROR, errorString); - callback(new Error(errorString), 0); + deferredCallback(new Error(errorString), 0); } ); }, onError: (error) => { - callback(new Error(error.details), 0); + deferredCallback(new Error(error.details), 0); }, }; From cb6abd7e38bcc29c1731208afed28dc389edc719 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 30 Sep 2021 08:52:04 -0700 Subject: [PATCH 1522/1899] grpc-js-xds: Handle all ways control-plane streams can end --- packages/grpc-js-xds/src/xds-client.ts | 32 +++++++++++++++----------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index cfb8b66ac..2b8fae44c 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -516,13 +516,15 @@ export class XdsClient { } } - private handleAdsCallError(error: ServiceError) { + private handleAdsCallStatus(streamStatus: StatusObject) { trace( - 'ADS stream ended. code=' + error.code + ' details= ' + error.details + 'ADS stream ended. code=' + streamStatus.code + ' details= ' + streamStatus.details ); this.adsCallV2 = null; this.adsCallV3 = null; - this.reportStreamError(error); + if (streamStatus.code !== status.OK) { + this.reportStreamError(streamStatus); + } /* If the backoff timer is no longer running, we do not need to wait any * more to start the new call. */ if (!this.adsBackoff.isRunning()) { @@ -544,9 +546,10 @@ export class XdsClient { this.adsCallV2.on('data', (message: DiscoveryResponse__Output) => { this.handleAdsResponse(message); }); - this.adsCallV2.on('error', (error: ServiceError) => { - this.handleAdsCallError(error); + this.adsCallV2.on('status', (status: StatusObject) => { + this.handleAdsCallStatus(status); }); + this.adsCallV2.on('error', () => {}); return true; } @@ -564,9 +567,10 @@ export class XdsClient { this.adsCallV3.on('data', (message: DiscoveryResponse__Output) => { this.handleAdsResponse(message); }); - this.adsCallV3.on('error', (error: ServiceError) => { - this.handleAdsCallError(error); + this.adsCallV3.on('status', (status: StatusObject) => { + this.handleAdsCallStatus(status); }); + this.adsCallV3.on('error', () => {}); return true; } @@ -772,9 +776,9 @@ export class XdsClient { this.receivedLrsSettingsForCurrentStream = true; } - private handleLrsCallError(error: ServiceError) { + private handleLrsCallStatus(streamStatus: StatusObject) { trace( - 'LRS stream ended. code=' + error.code + ' details= ' + error.details + 'LRS stream ended. code=' + streamStatus.code + ' details= ' + streamStatus.details ); this.lrsCallV2 = null; this.lrsCallV3 = null; @@ -798,9 +802,10 @@ export class XdsClient { this.lrsCallV2.on('data', (message: LoadStatsResponse__Output) => { this.handleLrsResponse(message); }); - this.lrsCallV2.on('error', (error: ServiceError) => { - this.handleLrsCallError(error); + this.lrsCallV2.on('status', (status: StatusObject) => { + this.handleLrsCallStatus(status); }); + this.lrsCallV2.on('error', () => {}); return true; } @@ -816,9 +821,10 @@ export class XdsClient { this.lrsCallV3.on('data', (message: LoadStatsResponse__Output) => { this.handleLrsResponse(message); }); - this.lrsCallV3.on('error', (error: ServiceError) => { - this.handleLrsCallError(error); + this.lrsCallV3.on('status', (status: StatusObject) => { + this.handleLrsCallStatus(status); }); + this.lrsCallV3.on('error', () => {}); return true; } From c7d9598067918839c35d43594db6b4d72aa51596 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 5 Oct 2021 14:52:26 -0700 Subject: [PATCH 1523/1899] grpc-js-xds: Fix RDS and EDS missing resource handling --- packages/grpc-js-xds/src/xds-stream-state/eds-state.ts | 1 - packages/grpc-js-xds/src/xds-stream-state/lds-state.ts | 6 ++++++ packages/grpc-js-xds/src/xds-stream-state/rds-state.ts | 3 +-- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index dbf18ef81..3861f4d2a 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -163,7 +163,6 @@ export class EdsState implements XdsStreamState { } } trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); - this.handleMissingNames(allClusterNames); return null; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 7e8ec0456..10e71babf 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -163,8 +163,13 @@ export class LdsState implements XdsStreamState { this.latestResponses = responses; this.latestIsV2 = isV2; const allTargetNames = new Set(); + const allRouteConfigNames = new Set(); for (const message of responses) { allTargetNames.add(message.name); + const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener!.value); + if (httpConnectionManager.rds) { + allRouteConfigNames.add(httpConnectionManager.rds.route_config_name); + } const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { watcher.onValidUpdate(message, isV2); @@ -172,6 +177,7 @@ export class LdsState implements XdsStreamState { } trace('Received RDS response with route config names ' + Array.from(allTargetNames)); this.handleMissingNames(allTargetNames); + this.rdsState.handleMissingNames(allRouteConfigNames); return null; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 9194529d8..ec7abe55a 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -172,7 +172,7 @@ export class RdsState implements XdsStreamState { return true; } - private handleMissingNames(allRouteConfigNames: Set) { + handleMissingNames(allRouteConfigNames: Set) { for (const [routeConfigName, watcherList] of this.watchers.entries()) { if (!allRouteConfigNames.has(routeConfigName)) { for (const watcher of watcherList) { @@ -200,7 +200,6 @@ export class RdsState implements XdsStreamState { } } trace('Received RDS response with route config names ' + Array.from(allRouteConfigNames)); - this.handleMissingNames(allRouteConfigNames); return null; } From 16303d9f0bb48e897af3ef79cbca1b50a05f4268 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 6 Oct 2021 14:56:53 -0700 Subject: [PATCH 1524/1899] grpc-js: Fix server trace function inconsistency --- packages/grpc-js/src/server.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index fb62163b3..aed04adec 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -391,8 +391,8 @@ export class Server { const http2Server = setupServer(); return new Promise((resolve, reject) => { - function onError(err: Error): void { - trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); + const onError = (err: Error) => { + this.trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); resolve(err); } @@ -467,8 +467,8 @@ export class Server { const address = addressList[0]; const http2Server = setupServer(); return new Promise((resolve, reject) => { - function onError(err: Error): void { - trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); + const onError = (err: Error) => { + this.trace('Failed to bind ' + subchannelAddressToString(address) + ' with error ' + err.message); resolve(bindWildcardPort(addressList.slice(1))); } From 590e94e09dd9b0dc2af04f122d7ee2cd45acae96 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 11 Oct 2021 14:23:05 -0700 Subject: [PATCH 1525/1899] grpc-js: Update package versions for 1.4.0 release --- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 6506112c4..fefc0f33b 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.3.1", + "version": "1.4.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.3.0" + "@grpc/grpc-js": "~1.4.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 63137c977..856b71471 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.3.7", + "version": "1.4.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 7564f60dcbbc51e0ed3ec8c099bc9c5d7e353b3d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 12 Oct 2021 12:25:47 -0700 Subject: [PATCH 1526/1899] grpc-js: Add tracing of channel options in channel and subchannel constructors --- packages/grpc-js/src/channel.ts | 2 +- packages/grpc-js/src/subchannel.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index d25abb05c..f998ecef4 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -311,7 +311,7 @@ export class ChannelImplementation implements Channel { new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this), ]); - this.trace('Constructed channel'); + this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); } private getChannelzInfo(): ChannelInfo { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index be58fe02b..a3b86b283 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -229,7 +229,7 @@ export class Subchannel { this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo()); this.channelzTrace = new ChannelzTrace(); this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); - this.trace('Subchannel constructed'); + this.trace('Subchannel constructed with options ' + JSON.stringify(options, undefined, 2)); } private getChannelzInfo(): SubchannelInfo { From 24df9a039b866c74d39cf6afd925859969e51fd8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 Oct 2021 11:10:19 -0700 Subject: [PATCH 1527/1899] grpc-js: Publish missing channelz proto and type files --- packages/grpc-js/package.json | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 856b71471..9705383ea 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.0", + "version": "1.4.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", @@ -48,11 +48,11 @@ "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "lint": "npm run check", - "prepare": "npm run compile", + "prepare": "npm run generate-types && npm run compile", "test": "gulp test", "check": "gts check src/**/*.ts", "fix": "gts fix src/*.ts", - "pretest": "npm run compile", + "pretest": "npm run generate-types && npm run compile", "posttest": "npm run check && madge -c ./build/src", "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O src/generated/ --grpcLib ../index channelz.proto" }, @@ -62,7 +62,8 @@ }, "files": [ "src/**/*.ts", - "build/src/*.{js,d.ts,js.map}", + "build/src/**/*.{js,d.ts,js.map}", + "proto/*.proto", "LICENSE", "deps/envoy-api/envoy/api/v2/**/*.proto", "deps/envoy-api/envoy/config/**/*.proto", From 624a839db9560adeba62e5dea37dec78a7a298ed Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 Oct 2021 11:34:32 -0700 Subject: [PATCH 1528/1899] Drop testing on Node 8, add 14 and 16 --- run-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-tests.sh b/run-tests.sh index 03fd970b5..e62cbd885 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -28,7 +28,7 @@ cd $ROOT git submodule update --init --recursive if [ ! -n "$node_versions" ] ; then - node_versions="8 10 12" + node_versions="10 12 14 16" fi set +ex From 144c41b366e86fed5cb333ab72014b0ad4ef2556 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 15 Oct 2021 09:48:42 -0700 Subject: [PATCH 1529/1899] proto-loader: Make serializers reject arrays --- packages/proto-loader/package.json | 2 +- packages/proto-loader/src/index.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 9418df982..d31220186 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.5", + "version": "0.6.6", "author": "Google Inc.", "contributors": [ { diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 98ca97b51..24a249400 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -212,6 +212,9 @@ function createDeserializer( function createSerializer(cls: Protobuf.Type): Serialize { return function serialize(arg: object): Buffer { + if (Array.isArray(arg)) { + throw new Error(`Failed to serialize message: expected object with ${cls.name} structure, got array instead`); + } const message = cls.fromObject(arg); return cls.encode(message).finish() as Buffer; }; From 5139b107e0f4318b3ee39b2af1daf5446eb05517 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 18 Oct 2021 09:29:43 -0700 Subject: [PATCH 1530/1899] grpc-js: Limit the number of retained channelz trace events --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channelz.ts | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9705383ea..4acf948df 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.1", + "version": "1.4.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 7efe54780..a1c85eb47 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -113,6 +113,14 @@ interface TraceEvent { childSubchannel?: SubchannelRef; } +/** + * The loose upper bound on the number of events that should be retained in a + * trace. This may be exceeded by up to a factor of 2. Arbitrarily chosen as a + * number that should be large enough to contain the recent relevant + * information, but small enough to not use excessive memory. + */ +const TARGET_RETAINED_TRACES = 32; + export class ChannelzTrace { events: TraceEvent[] = []; creationTimestamp: Date; @@ -131,6 +139,10 @@ export class ChannelzTrace { childChannel: child?.kind === 'channel' ? child : undefined, childSubchannel: child?.kind === 'subchannel' ? child : undefined }); + // Whenever the trace array gets too large, discard the first half + if (this.events.length >= TARGET_RETAINED_TRACES * 2) { + this.events = this.events.slice(TARGET_RETAINED_TRACES); + } this.eventsLogged += 1; } @@ -380,20 +392,6 @@ export function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRe } } -export interface ChannelzClientView { - updateState(connectivityState: ConnectivityState): void; - addTrace(severity: TraceSeverity, description: string, child?: ChannelRef | SubchannelRef): void; - addCallStarted(): void; - addCallSucceeded(): void; - addCallFailed(): void; - addChild(child: ChannelRef | SubchannelRef): void; - removeChild(child: ChannelRef | SubchannelRef): void; -} - -export interface ChannelzSubchannelView extends ChannelzClientView { - getRef(): SubchannelRef; -} - /** * Converts an IPv4 or IPv6 address from string representation to binary * representation From 891a918c85d717c814d98ee0ce01363970b99007 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 18 Oct 2021 13:31:08 -0700 Subject: [PATCH 1531/1899] grpc-js: Allow users to disable channelz --- packages/grpc-js/src/channel-options.ts | 2 + packages/grpc-js/src/channel.ts | 69 +++++++++++++----- packages/grpc-js/src/server.ts | 41 ++++++++--- packages/grpc-js/src/subchannel.ts | 94 ++++++++++++++++--------- 4 files changed, 147 insertions(+), 59 deletions(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 604fd8685..4e2ee6132 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -36,6 +36,7 @@ export interface ChannelOptions { 'grpc.enable_http_proxy'?: number; 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; + 'grpc.enable_channelz'?: number; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; @@ -61,6 +62,7 @@ export const recognizedOptions = { 'grpc.max_send_message_length': true, 'grpc.max_receive_message_length': true, 'grpc.enable_http_proxy': true, + 'grpc.enable_channelz': true, 'grpc-node.max_session_memory': true, }; diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f998ecef4..e442e6e64 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -172,6 +172,7 @@ export class ChannelImplementation implements Channel { private configSelector: ConfigSelector | null = null; // Channelz info + private readonly channelzEnabled: boolean = true; private originalTarget: string; private channelzRef: ChannelRef; private channelzTrace: ChannelzTrace; @@ -213,9 +214,22 @@ export class ChannelImplementation implements Channel { this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME); this.callRefTimer.unref?.(); - this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo()); + if (this.options['grpc.enable_channelz'] === 0) { + this.channelzEnabled = false; + } + this.channelzTrace = new ChannelzTrace(); - this.channelzTrace.addTrace('CT_INFO', 'Channel created'); + if (this.channelzEnabled) { + this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo()); + this.channelzTrace.addTrace('CT_INFO', 'Channel created'); + } else { + // Dummy channelz ref that will never be used + this.channelzRef = { + kind: 'channel', + id: -1, + name: '' + }; + } if (this.options['grpc.default_authority']) { this.defaultAuthority = this.options['grpc.default_authority'] as string; @@ -242,7 +256,9 @@ export class ChannelImplementation implements Channel { Object.assign({}, this.options, subchannelArgs), this.credentials ); - this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); + } return subchannel; }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { @@ -262,10 +278,14 @@ export class ChannelImplementation implements Channel { ); }, addChannelzChild: (child: ChannelRef | SubchannelRef) => { - this.childrenTracker.refChild(child); + if (this.channelzEnabled) { + this.childrenTracker.refChild(child); + } }, removeChannelzChild: (child: ChannelRef | SubchannelRef) => { - this.childrenTracker.unrefChild(child); + if (this.channelzEnabled) { + this.childrenTracker.unrefChild(child); + } } }; this.resolvingLoadBalancer = new ResolvingLoadBalancer( @@ -273,7 +293,9 @@ export class ChannelImplementation implements Channel { channelControlHelper, options, (configSelector) => { - this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); + } this.configSelector = configSelector; /* We process the queue asynchronously to ensure that the corresponding * load balancer update has completed. */ @@ -288,7 +310,9 @@ export class ChannelImplementation implements Channel { }); }, (status) => { - this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); + } if (this.configSelectionQueue.length > 0) { this.trace('Name resolution failed with calls queued for config selection'); } @@ -553,7 +577,9 @@ export class ChannelImplementation implements Channel { ' -> ' + ConnectivityState[newState] ); - this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + } this.connectivityState = newState; const watchersCopy = this.connectivityStateWatchers.slice(); for (const watcherObject of watchersCopy) { @@ -638,7 +664,9 @@ export class ChannelImplementation implements Channel { this.resolvingLoadBalancer.destroy(); this.updateState(ConnectivityState.SHUTDOWN); clearInterval(this.callRefTimer); - unregisterChannelzRef(this.channelzRef); + if (this.channelzEnabled) { + unregisterChannelzRef(this.channelzRef); + } this.subchannelPool.unrefUnusedSubchannels(); } @@ -690,6 +718,11 @@ export class ChannelImplementation implements Channel { this.connectivityStateWatchers.push(watcherObject); } + /** + * Get the channelz reference object for this channel. The returned value is + * garbage if channelz is disabled for this channel. + * @returns + */ getChannelzRef() { return this.channelzRef; } @@ -735,14 +768,16 @@ export class ChannelImplementation implements Channel { this.credentials._getCallCredentials(), callNumber ); - this.callTracker.addCallStarted(); - stream.addStatusWatcher(status => { - if (status.code === Status.OK) { - this.callTracker.addCallSucceeded(); - } else { - this.callTracker.addCallFailed(); - } - }); + if (this.channelzEnabled) { + this.callTracker.addCallStarted(); + stream.addStatusWatcher(status => { + if (status.code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }); + } return stream; } } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index aed04adec..8bfc2a5bc 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -149,6 +149,7 @@ export class Server { private options: ChannelOptions; // Channelz Info + private readonly channelzEnabled: boolean = true; private channelzRef: ServerRef; private channelzTrace = new ChannelzTrace(); private callTracker = new ChannelzCallTracker(); @@ -157,9 +158,20 @@ export class Server { constructor(options?: ChannelOptions) { this.options = options ?? {}; - this.channelzRef = registerChannelzServer(() => this.getChannelzInfo()); - this.channelzTrace.addTrace('CT_INFO', 'Server created'); - this.trace('Server constructed'); + if (this.options['grpc.enable_channelz'] === 0) { + this.channelzEnabled = false; + } + if (this.channelzEnabled) { + this.channelzRef = registerChannelzServer(() => this.getChannelzInfo()); + this.channelzTrace.addTrace('CT_INFO', 'Server created'); + this.trace('Server constructed'); + } else { + // Dummy channelz ref that will never be used + this.channelzRef = { + kind: 'server', + id: -1 + }; + } } private getChannelzInfo(): ServerInfo { @@ -638,7 +650,9 @@ export class Server { if (this.started === true) { throw new Error('server is already started'); } - this.channelzTrace.addTrace('CT_INFO', 'Starting'); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Starting'); + } this.started = true; } @@ -686,6 +700,11 @@ export class Server { throw new Error('Not yet implemented'); } + /** + * Get the channelz reference object for this server. The returned value is + * garbage if channelz is disabled for this server. + * @returns + */ getChannelzRef() { return this.channelzRef; } @@ -841,12 +860,16 @@ export class Server { this.sessions.set(session, channelzSessionInfo); const clientAddress = session.socket.remoteAddress; - this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); - this.sessionChildrenTracker.refChild(channelzRef); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); + this.sessionChildrenTracker.refChild(channelzRef); + } session.on('close', () => { - this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); - this.sessionChildrenTracker.unrefChild(channelzRef); - unregisterChannelzRef(channelzRef); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); + this.sessionChildrenTracker.unrefChild(channelzRef); + unregisterChannelzRef(channelzRef); + } this.sessions.delete(session); }); }); diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index a3b86b283..edc843a8a 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -157,6 +157,7 @@ export class Subchannel { private subchannelAddressString: string; // Channelz info + private readonly channelzEnabled: boolean = true; private channelzRef: SubchannelRef; private channelzTrace: ChannelzTrace; private callTracker = new ChannelzCallTracker(); @@ -226,9 +227,21 @@ export class Subchannel { }, backoffOptions); this.subchannelAddressString = subchannelAddressToString(subchannelAddress); - this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo()); + if (options['grpc.enable_channelz'] === 0) { + this.channelzEnabled = false; + } this.channelzTrace = new ChannelzTrace(); - this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); + if (this.channelzEnabled) { + this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo()); + this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); + } else { + // Dummy channelz ref that will never be used + this.channelzRef = { + kind: 'subchannel', + id: -1, + name: '' + }; + } this.trace('Subchannel constructed with options ' + JSON.stringify(options, undefined, 2)); } @@ -286,6 +299,9 @@ export class Subchannel { } private resetChannelzSocketInfo() { + if (!this.channelzEnabled) { + return; + } if (this.channelzSocketRef) { unregisterChannelzRef(this.channelzSocketRef); this.childrenTracker.unrefChild(this.channelzSocketRef); @@ -335,7 +351,9 @@ export class Subchannel { } private sendPing() { - this.keepalivesSent += 1; + if (this.channelzEnabled) { + this.keepalivesSent += 1; + } logging.trace( LogVerbosity.DEBUG, 'keepalive', @@ -462,8 +480,10 @@ export class Subchannel { connectionOptions ); this.session = session; - this.channelzSocketRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!); - this.childrenTracker.refChild(this.channelzSocketRef); + if (this.channelzEnabled) { + this.channelzSocketRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!); + this.childrenTracker.refChild(this.channelzSocketRef); + } session.unref(); /* For all of these events, check if the session at the time of the event * is the same one currently attached to this subchannel, to ensure that @@ -615,7 +635,9 @@ export class Subchannel { ' -> ' + ConnectivityState[newState] ); - this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + } const previousState = this.connectivityState; this.connectivityState = newState; switch (newState) { @@ -678,12 +700,16 @@ export class Subchannel { /* If no calls, channels, or subchannel pools have any more references to * this subchannel, we can be sure it will never be used again. */ if (this.callRefcount === 0 && this.refcount === 0) { - this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); + } this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], ConnectivityState.TRANSIENT_FAILURE ); - unregisterChannelzRef(this.channelzRef); + if (this.channelzEnabled) { + unregisterChannelzRef(this.channelzRef); + } } } @@ -805,34 +831,36 @@ export class Subchannel { ' with headers\n' + headersString ); - this.callTracker.addCallStarted(); - callStream.addStatusWatcher(status => { - if (status.code === Status.OK) { - this.callTracker.addCallSucceeded(); - } else { - this.callTracker.addCallFailed(); - } - }); const streamSession = this.session; - this.streamTracker.addCallStarted(); - callStream.addStreamEndWatcher(success => { - if (streamSession === this.session) { - if (success) { - this.streamTracker.addCallSucceeded(); + if (this.channelzEnabled) { + this.callTracker.addCallStarted(); + callStream.addStatusWatcher(status => { + if (status.code === Status.OK) { + this.callTracker.addCallSucceeded(); } else { - this.streamTracker.addCallFailed(); + this.callTracker.addCallFailed(); } - } - }); - callStream.attachHttp2Stream(http2Stream, this, extraFilters, { - addMessageSent: () => { - this.messagesSent += 1; - this.lastMessageSentTimestamp = new Date(); - }, - addMessageReceived: () => { - this.messagesReceived += 1; - } - }); + }); + this.streamTracker.addCallStarted(); + callStream.addStreamEndWatcher(success => { + if (streamSession === this.session) { + if (success) { + this.streamTracker.addCallSucceeded(); + } else { + this.streamTracker.addCallFailed(); + } + } + }); + callStream.attachHttp2Stream(http2Stream, this, extraFilters, { + addMessageSent: () => { + this.messagesSent += 1; + this.lastMessageSentTimestamp = new Date(); + }, + addMessageReceived: () => { + this.messagesReceived += 1; + } + }); + } } /** From 9d92bf164fa2ce0445d5acedfcf04034db587a44 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 18 Oct 2021 16:20:39 -0700 Subject: [PATCH 1532/1899] grpc-js-xds: Improve received resource list logging --- packages/grpc-js-xds/src/xds-stream-state/cds-state.ts | 2 +- packages/grpc-js-xds/src/xds-stream-state/eds-state.ts | 2 +- packages/grpc-js-xds/src/xds-stream-state/lds-state.ts | 2 +- packages/grpc-js-xds/src/xds-stream-state/rds-state.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 7720c5673..c3c73e9fb 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -158,7 +158,7 @@ export class CdsState implements XdsStreamState { watcher.onValidUpdate(message, isV2); } } - trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); + trace('Received CDS updates for cluster names [' + Array.from(allClusterNames) + ']'); this.handleMissingNames(allClusterNames); this.edsState.handleMissingNames(allEdsServiceNames); return null; diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index 3861f4d2a..f816ceea2 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -162,7 +162,7 @@ export class EdsState implements XdsStreamState { watcher.onValidUpdate(message, isV2); } } - trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); + trace('Received EDS updates for cluster names [' + Array.from(allClusterNames) + ']'); return null; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 10e71babf..7c9105be4 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -175,7 +175,7 @@ export class LdsState implements XdsStreamState { watcher.onValidUpdate(message, isV2); } } - trace('Received RDS response with route config names ' + Array.from(allTargetNames)); + trace('Received LDS response with listener names [' + Array.from(allTargetNames) + ']'); this.handleMissingNames(allTargetNames); this.rdsState.handleMissingNames(allRouteConfigNames); return null; diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index ec7abe55a..04d2bce0d 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -199,7 +199,7 @@ export class RdsState implements XdsStreamState { watcher.onValidUpdate(message, isV2); } } - trace('Received RDS response with route config names ' + Array.from(allRouteConfigNames)); + trace('Received RDS response with route config names [' + Array.from(allRouteConfigNames) + ']'); return null; } From 647654c7c17cd79dd1f06085d5b8d2c4e40b7e3a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Oct 2021 08:33:25 -0700 Subject: [PATCH 1533/1899] grpc-js: Include other causes in ENHANCE_YOUR_CALM translation --- packages/grpc-js/src/call-stream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 70a9ac6ee..f705f6caf 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -600,7 +600,7 @@ export class Http2CallStream implements Call { break; case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: code = Status.RESOURCE_EXHAUSTED; - details = 'Bandwidth exhausted'; + details = 'Bandwidth exhausted or memory limit exceeded'; break; case http2.constants.NGHTTP2_INADEQUATE_SECURITY: code = Status.PERMISSION_DENIED; From 2a45b343d51ae8d3333914659dabdbb1d340334c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Oct 2021 14:20:37 -0700 Subject: [PATCH 1534/1899] grpc-js-xds: Use valid resources when NACKing messages --- .../grpc-js-xds/src/xds-stream-state/cds-state.ts | 14 +++++++++----- .../grpc-js-xds/src/xds-stream-state/eds-state.ts | 14 +++++++++----- .../grpc-js-xds/src/xds-stream-state/lds-state.ts | 14 +++++++++----- .../grpc-js-xds/src/xds-stream-state/rds-state.ts | 14 +++++++++----- 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 7720c5673..5dae09fb4 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -137,17 +137,21 @@ export class CdsState implements XdsStreamState { } handleResponses(responses: Cluster__Output[], isV2: boolean): string | null { + const validResponses: Cluster__Output[] = []; + let errorMessage: string | null = null; for (const message of responses) { - if (!this.validateResponse(message)) { + if (this.validateResponse(message)) { + validResponses.push(message); + } else { trace('CDS validation failed for message ' + JSON.stringify(message)); - return 'CDS Error: Cluster validation failed'; + errorMessage = 'CDS Error: Cluster validation failed'; } } - this.latestResponses = responses; + this.latestResponses = validResponses; this.latestIsV2 = isV2; const allEdsServiceNames: Set = new Set(); const allClusterNames: Set = new Set(); - for (const message of responses) { + for (const message of validResponses) { allClusterNames.add(message.name); const edsServiceName = message.eds_cluster_config?.service_name ?? ''; allEdsServiceNames.add( @@ -161,7 +165,7 @@ export class CdsState implements XdsStreamState { trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); this.handleMissingNames(allClusterNames); this.edsState.handleMissingNames(allEdsServiceNames); - return null; + return errorMessage; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index 3861f4d2a..7d28ed5ff 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -146,16 +146,20 @@ export class EdsState implements XdsStreamState { } handleResponses(responses: ClusterLoadAssignment__Output[], isV2: boolean) { + const validResponses: ClusterLoadAssignment__Output[] = []; + let errorMessage: string | null = null; for (const message of responses) { - if (!this.validateResponse(message)) { + if (this.validateResponse(message)) { + validResponses.push(message); + } else { trace('EDS validation failed for message ' + JSON.stringify(message)); - return 'EDS Error: ClusterLoadAssignment validation failed'; + errorMessage = 'EDS Error: ClusterLoadAssignment validation failed'; } } - this.latestResponses = responses; + this.latestResponses = validResponses; this.latestIsV2 = isV2; const allClusterNames: Set = new Set(); - for (const message of responses) { + for (const message of validResponses) { allClusterNames.add(message.cluster_name); const watchers = this.watchers.get(message.cluster_name) ?? []; for (const watcher of watchers) { @@ -163,7 +167,7 @@ export class EdsState implements XdsStreamState { } } trace('Received EDS updates for cluster names ' + Array.from(allClusterNames)); - return null; + return errorMessage; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 10e71babf..5706e3766 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -154,17 +154,21 @@ export class LdsState implements XdsStreamState { } handleResponses(responses: Listener__Output[], isV2: boolean): string | null { + const validResponses: Listener__Output[] = []; + let errorMessage: string | null = null; for (const message of responses) { - if (!this.validateResponse(message, isV2)) { + if (this.validateResponse(message, isV2)) { + validResponses.push(message); + } else { trace('LDS validation failed for message ' + JSON.stringify(message)); - return 'LDS Error: Route validation failed'; + errorMessage = 'LDS Error: Route validation failed'; } } - this.latestResponses = responses; + this.latestResponses = validResponses; this.latestIsV2 = isV2; const allTargetNames = new Set(); const allRouteConfigNames = new Set(); - for (const message of responses) { + for (const message of validResponses) { allTargetNames.add(message.name); const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener!.value); if (httpConnectionManager.rds) { @@ -178,7 +182,7 @@ export class LdsState implements XdsStreamState { trace('Received RDS response with route config names ' + Array.from(allTargetNames)); this.handleMissingNames(allTargetNames); this.rdsState.handleMissingNames(allRouteConfigNames); - return null; + return errorMessage; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index ec7abe55a..5a3854323 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -183,16 +183,20 @@ export class RdsState implements XdsStreamState { } handleResponses(responses: RouteConfiguration__Output[], isV2: boolean): string | null { + const validResponses: RouteConfiguration__Output[] = []; + let errorMessage: string | null = null; for (const message of responses) { - if (!this.validateResponse(message, isV2)) { + if (this.validateResponse(message, isV2)) { + validResponses.push(message); + } else { trace('RDS validation failed for message ' + JSON.stringify(message)); - return 'RDS Error: Route validation failed'; + errorMessage = 'RDS Error: Route validation failed'; } } - this.latestResponses = responses; + this.latestResponses = validResponses; this.latestIsV2 = isV2; const allRouteConfigNames = new Set(); - for (const message of responses) { + for (const message of validResponses) { allRouteConfigNames.add(message.name); const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { @@ -200,7 +204,7 @@ export class RdsState implements XdsStreamState { } } trace('Received RDS response with route config names ' + Array.from(allRouteConfigNames)); - return null; + return errorMessage; } reportStreamError(status: StatusObject): void { From 25e21d1fba1b7f6aa41522309cb1dc773324d5ed Mon Sep 17 00:00:00 2001 From: howyi Date: Sun, 24 Oct 2021 21:14:16 +0900 Subject: [PATCH 1535/1899] feat(client): export ServiceClientConstructor,ProtobufTypeDefinition type --- packages/grpc-js/src/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 4b7967be9..f3d018953 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -42,7 +42,9 @@ import { loadPackageDefinition, makeClientConstructor, MethodDefinition, + ProtobufTypeDefinition, Serialize, + ServiceClientConstructor, ServiceDefinition, } from './make-client'; import { Metadata, MetadataValue } from './metadata'; @@ -245,7 +247,11 @@ export { InterceptorConfigurationError, } from './client-interceptors'; -export { GrpcObject } from './make-client'; +export { + GrpcObject, + ServiceClientConstructor, + ProtobufTypeDefinition +} from './make-client'; export { ChannelOptions } from './channel-options'; From 7aa5b6200814afc3acf5739d8a758fbaf97dca8b Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 24 Oct 2021 21:46:23 -0700 Subject: [PATCH 1536/1899] grpc-js: Allow per-channel request compression from the client and decompression from the server --- packages/grpc-js/package.json | 5 +- packages/grpc-js/proto/test_service.proto | 42 +++ packages/grpc-js/src/channel-options.ts | 1 + packages/grpc-js/src/channel.ts | 3 +- packages/grpc-js/src/compression-filter.ts | 52 +++- packages/grpc-js/src/generated/Request.ts | 14 + packages/grpc-js/src/generated/Response.ts | 10 + packages/grpc-js/src/generated/TestService.ts | 55 ++++ .../grpc-js/src/generated/test_service.ts | 15 + packages/grpc-js/src/server-call.ts | 84 ++++- packages/grpc-js/src/server.ts | 39 ++- packages/grpc-js/test/test-server.ts | 286 ++++++++++++++++++ 12 files changed, 570 insertions(+), 36 deletions(-) create mode 100644 packages/grpc-js/proto/test_service.proto create mode 100644 packages/grpc-js/src/generated/Request.ts create mode 100644 packages/grpc-js/src/generated/Response.ts create mode 100644 packages/grpc-js/src/generated/TestService.ts create mode 100644 packages/grpc-js/src/generated/test_service.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9705383ea..f430c09d2 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -54,11 +54,12 @@ "fix": "gts fix src/*.ts", "pretest": "npm run generate-types && npm run compile", "posttest": "npm run check && madge -c ./build/src", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O src/generated/ --grpcLib ../index channelz.proto" + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O src/generated/ --grpcLib ../index channelz.proto test_service.proto" }, "dependencies": { "@grpc/proto-loader": "^0.6.4", - "@types/node": ">=12.12.47" + "@types/node": "16.10.0", + "@types/semver": "^7.3.9" }, "files": [ "src/**/*.ts", diff --git a/packages/grpc-js/proto/test_service.proto b/packages/grpc-js/proto/test_service.proto new file mode 100644 index 000000000..f99393d14 --- /dev/null +++ b/packages/grpc-js/proto/test_service.proto @@ -0,0 +1,42 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +syntax = "proto3"; + +message Request { + bool error = 1; + string message = 2; + int32 errorAfter = 3; +} + +message Response { + int32 count = 1; +} + +service TestService { + rpc Unary (Request) returns (Response) { + } + + rpc ClientStream (stream Request) returns (Response) { + } + + rpc ServerStream (Request) returns (stream Response) { + } + + rpc BidiStream (stream Request) returns (stream Response) { + } +} diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 604fd8685..f0b37d7a4 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -36,6 +36,7 @@ export interface ChannelOptions { 'grpc.enable_http_proxy'?: number; 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; + 'grpc.default_compression_algorithm'?: number; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index f998ecef4..8a2f93a54 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -45,7 +45,6 @@ import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; -import { SurfaceCall } from './call'; import { Filter } from './filter'; import { ConnectivityState } from './connectivity-state'; @@ -309,7 +308,7 @@ export class ChannelImplementation implements Channel { new CallCredentialsFilterFactory(this), new DeadlineFilterFactory(this), new MaxMessageSizeFilterFactory(this.options), - new CompressionFilterFactory(this), + new CompressionFilterFactory(this, this.options), ]); this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); } diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 330eb675a..4ecdbb6a3 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -17,10 +17,27 @@ import * as zlib from 'zlib'; -import { Call, WriteFlags, WriteObject } from './call-stream'; +import { Call, WriteObject } from './call-stream'; import { Channel } from './channel'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata, MetadataValue } from './metadata'; +import { ChannelOptions } from './channel-options'; + +const CompressionAlgorithms = { + '0': 'identity', + '1': 'deflate', + '2': 'gzip', + // Streaming compression is unimplemented + '3': 'stream-gzip' +} as const; + +const CompressionAlgorithKeys = new Set(Object.keys(CompressionAlgorithms)); + +const isCompressionAlgorithmKey = (key: string | undefined): key is keyof typeof CompressionAlgorithms => { + return typeof key === 'string' && CompressionAlgorithKeys.has(key); +} + +type CompressionAlgorithm = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms]; abstract class CompressionHandler { protected abstract compressMessage(message: Buffer): Promise; @@ -167,10 +184,29 @@ function getCompressionHandler(compressionName: string): CompressionHandler { export class CompressionFilter extends BaseFilter implements Filter { private sendCompression: CompressionHandler = new IdentityHandler(); private receiveCompression: CompressionHandler = new IdentityHandler(); + private defaultCompressionAlgorithm: CompressionAlgorithm | undefined; + + constructor(channelOptions: ChannelOptions) { + super(); + + const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']?.toString(); + if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { + this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; + this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); + } + } + async sendMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; headers.set('grpc-accept-encoding', 'identity,deflate,gzip'); - headers.set('accept-encoding', 'identity'); + headers.set('accept-encoding', 'identity,deflate,gzip'); + + if (this.defaultCompressionAlgorithm && ['deflate', 'gzip'].includes(this.defaultCompressionAlgorithm)) { + headers.set('grpc-encoding', this.defaultCompressionAlgorithm); + } else { + headers.remove('grpc-encoding'); + } + return headers; } @@ -192,10 +228,10 @@ export class CompressionFilter extends BaseFilter implements Filter { * and the output is a framed and possibly compressed message. For this * reason, this filter should be at the bottom of the filter stack */ const resolvedMessage: WriteObject = await message; - const compress = - resolvedMessage.flags === undefined - ? false - : (resolvedMessage.flags & WriteFlags.NoCompress) === 0; + const compress = !(this.sendCompression instanceof IdentityHandler); + // resolvedMessage.flags === undefined + // ? false + // : (resolvedMessage.flags & WriteFlags.NoCompress) === 0; return { message: await this.sendCompression.writeMessage( resolvedMessage.message, @@ -216,8 +252,8 @@ export class CompressionFilter extends BaseFilter implements Filter { export class CompressionFilterFactory implements FilterFactory { - constructor(private readonly channel: Channel) {} + constructor(private readonly channel: Channel, private readonly options: ChannelOptions) {} createFilter(callStream: Call): CompressionFilter { - return new CompressionFilter(); + return new CompressionFilter(this.options); } } diff --git a/packages/grpc-js/src/generated/Request.ts b/packages/grpc-js/src/generated/Request.ts new file mode 100644 index 000000000..93898a701 --- /dev/null +++ b/packages/grpc-js/src/generated/Request.ts @@ -0,0 +1,14 @@ +// Original file: proto/test_service.proto + + +export interface Request { + 'error'?: (boolean); + 'message'?: (string); + 'errorAfter'?: (number); +} + +export interface Request__Output { + 'error': (boolean); + 'message': (string); + 'errorAfter': (number); +} diff --git a/packages/grpc-js/src/generated/Response.ts b/packages/grpc-js/src/generated/Response.ts new file mode 100644 index 000000000..980bfdd18 --- /dev/null +++ b/packages/grpc-js/src/generated/Response.ts @@ -0,0 +1,10 @@ +// Original file: proto/test_service.proto + + +export interface Response { + 'count'?: (number); +} + +export interface Response__Output { + 'count': (number); +} diff --git a/packages/grpc-js/src/generated/TestService.ts b/packages/grpc-js/src/generated/TestService.ts new file mode 100644 index 000000000..dd1d22ab2 --- /dev/null +++ b/packages/grpc-js/src/generated/TestService.ts @@ -0,0 +1,55 @@ +// Original file: proto/test_service.proto + +import type * as grpc from './../index' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { Request as _Request, Request__Output as _Request__Output } from './Request'; +import type { Response as _Response, Response__Output as _Response__Output } from './Response'; + +export interface TestServiceClient extends grpc.Client { + BidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_Request, _Response__Output>; + BidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_Request, _Response__Output>; + bidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_Request, _Response__Output>; + bidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_Request, _Response__Output>; + + ClientStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + ClientStream(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + ClientStream(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + ClientStream(callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + clientStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + clientStream(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + clientStream(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + clientStream(callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + + ServerStream(argument: _Request, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; + ServerStream(argument: _Request, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; + serverStream(argument: _Request, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; + serverStream(argument: _Request, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; + + Unary(argument: _Request, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + Unary(argument: _Request, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + Unary(argument: _Request, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + Unary(argument: _Request, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + unary(argument: _Request, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + unary(argument: _Request, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + unary(argument: _Request, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + unary(argument: _Request, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + +} + +export interface TestServiceHandlers extends grpc.UntypedServiceImplementation { + BidiStream: grpc.handleBidiStreamingCall<_Request__Output, _Response>; + + ClientStream: grpc.handleClientStreamingCall<_Request__Output, _Response>; + + ServerStream: grpc.handleServerStreamingCall<_Request__Output, _Response>; + + Unary: grpc.handleUnaryCall<_Request__Output, _Response>; + +} + +export interface TestServiceDefinition extends grpc.ServiceDefinition { + BidiStream: MethodDefinition<_Request, _Response, _Request__Output, _Response__Output> + ClientStream: MethodDefinition<_Request, _Response, _Request__Output, _Response__Output> + ServerStream: MethodDefinition<_Request, _Response, _Request__Output, _Response__Output> + Unary: MethodDefinition<_Request, _Response, _Request__Output, _Response__Output> +} diff --git a/packages/grpc-js/src/generated/test_service.ts b/packages/grpc-js/src/generated/test_service.ts new file mode 100644 index 000000000..2beb88680 --- /dev/null +++ b/packages/grpc-js/src/generated/test_service.ts @@ -0,0 +1,15 @@ +import type * as grpc from '../index'; +import type { MessageTypeDefinition } from '@grpc/proto-loader'; + +import type { TestServiceClient as _TestServiceClient, TestServiceDefinition as _TestServiceDefinition } from './TestService'; + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + Request: MessageTypeDefinition + Response: MessageTypeDefinition + TestService: SubtypeConstructor & { service: _TestServiceDefinition } +} + diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index be4429b0f..8ea488a4d 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -18,6 +18,7 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; +import * as zlib from 'zlib'; import { Deadline, StatusObject } from './call-stream'; import { @@ -32,6 +33,7 @@ import { StreamDecoder } from './stream-decoder'; import { ObjectReadable, ObjectWritable } from './object-stream'; import { ChannelOptions } from './channel-options'; import * as logging from './logging'; +import { MetadataValue } from '.'; const TRACER_NAME = 'server_call'; @@ -60,7 +62,7 @@ const deadlineUnitsToMs: DeadlineUnitIndexSignature = { const defaultResponseHeaders = { // TODO(cjihrig): Remove these encoding headers from the default response // once compression is integrated. - [GRPC_ACCEPT_ENCODING_HEADER]: 'identity', + [GRPC_ACCEPT_ENCODING_HEADER]: 'identity,deflate,gzip', [GRPC_ENCODING_HEADER]: 'identity', [http2.constants.HTTP2_HEADER_STATUS]: http2.constants.HTTP_STATUS_OK, [http2.constants.HTTP2_HEADER_CONTENT_TYPE]: 'application/grpc+proto', @@ -136,12 +138,13 @@ export class ServerReadableStreamImpl constructor( private call: Http2ServerCallStream, public metadata: Metadata, - public deserialize: Deserialize + public deserialize: Deserialize, + encoding?: MetadataValue ) { super({ objectMode: true }); this.cancelled = false; this.call.setupSurfaceCall(this); - this.call.setupReadable(this); + this.call.setupReadable(this, encoding); } _read(size: number) { @@ -250,13 +253,14 @@ export class ServerDuplexStreamImpl private call: Http2ServerCallStream, public metadata: Metadata, public serialize: Serialize, - public deserialize: Deserialize + public deserialize: Deserialize, + encoding?: MetadataValue ) { super({ objectMode: true }); this.cancelled = false; this.trailingMetadata = new Metadata(); this.call.setupSurfaceCall(this); - this.call.setupReadable(this); + this.call.setupReadable(this, encoding); this.on('error', (err) => { this.call.sendError(err); @@ -439,6 +443,47 @@ export class Http2ServerCallStream< return this.cancelled; } + private getDecompressedMessage(message: Buffer, encoding?: MetadataValue) { + switch (encoding) { + case 'deflate': { + return new Promise((resolve, reject) => { + zlib.inflate(message.slice(5), (err, output) => { + if (err) { + this.sendError({ + code: Status.INTERNAL, + details: `Received "grpc-encoding" header "${encoding}" but ${encoding} decompression failed`, + }); + resolve(); + } else { + const joined = Buffer.concat([message.slice(0, 5), output]); + resolve(joined); + } + }); + }); + } + + case 'gzip': { + return new Promise((resolve, reject) => { + zlib.unzip(message.slice(5), (err, output) => { + if (err) { + this.sendError({ + code: Status.INTERNAL, + details: `Received "grpc-encoding" header "${encoding}" but ${encoding} decompression failed`, + }); + resolve(); + } else { + const joined = Buffer.concat([message.slice(0, 5), output]); + resolve(joined); + } + }); + }); + } + + default: + return Promise.resolve(message); + } + } + sendMetadata(customMetadata?: Metadata) { if (this.checkCancelled()) { return; @@ -469,7 +514,7 @@ export class Http2ServerCallStream< const err = new Error('Invalid deadline') as ServerErrorResponse; err.code = Status.OUT_OF_RANGE; this.sendError(err); - return; + return metadata; } const timeout = (+match[1] * deadlineUnitsToMs[match[2]]) | 0; @@ -484,13 +529,12 @@ export class Http2ServerCallStream< metadata.remove(http2.constants.HTTP2_HEADER_ACCEPT_ENCODING); metadata.remove(http2.constants.HTTP2_HEADER_TE); metadata.remove(http2.constants.HTTP2_HEADER_CONTENT_TYPE); - metadata.remove('grpc-encoding'); metadata.remove('grpc-accept-encoding'); return metadata; } - receiveUnaryMessage(): Promise { + receiveUnaryMessage(encoding?: MetadataValue): Promise { return new Promise((resolve, reject) => { const stream = this.stream; const chunks: Buffer[] = []; @@ -516,7 +560,17 @@ export class Http2ServerCallStream< } this.emit('receiveMessage'); - resolve(this.deserializeMessage(requestBytes)); + + const decompressedMessage = await this.getDecompressedMessage(requestBytes, encoding); + + // Encountered an error with decompression; it'll already have been propogated back + // Just return early + if (!decompressedMessage) { + resolve(); + } + else { + resolve(this.deserializeMessage(decompressedMessage)); + } } catch (err) { err.code = Status.INTERNAL; this.sendError(err); @@ -673,7 +727,8 @@ export class Http2ServerCallStream< setupReadable( readable: | ServerReadableStream - | ServerDuplexStream + | ServerDuplexStream, + encoding?: MetadataValue ) { const decoder = new StreamDecoder(); @@ -692,7 +747,14 @@ export class Http2ServerCallStream< return; } this.emit('receiveMessage'); - this.pushOrBufferMessage(readable, message); + + const decompressedMessage = await this.getDecompressedMessage(message, encoding); + + // Encountered an error with decompression; it'll already have been propogated back + // Just return early + if (!decompressedMessage) return; + + this.pushOrBufferMessage(readable, decompressedMessage); } }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index aed04adec..552f31b02 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -61,6 +61,7 @@ import { import { parseUri } from './uri-parser'; import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; import { CipherNameAndProtocol, TLSSocket } from 'tls'; +import { MetadataValue } from '.'; const TRACER_NAME = 'server'; @@ -777,30 +778,36 @@ export class Server { channelzSessionInfo.lastMessageReceivedTimestamp = new Date(); }); } - const metadata: Metadata = call.receiveMetadata(headers) as Metadata; + const metadata = call.receiveMetadata(headers); + const encoding: MetadataValue | undefined = metadata.get('grpc-encoding')[0]; + metadata.remove('grpc-encoding'); + switch (handler.type) { case 'unary': - handleUnary(call, handler as UntypedUnaryHandler, metadata); + handleUnary(call, handler as UntypedUnaryHandler, metadata, encoding); break; case 'clientStream': handleClientStreaming( call, handler as UntypedClientStreamingHandler, - metadata + metadata, + encoding ); break; case 'serverStream': handleServerStreaming( call, handler as UntypedServerStreamingHandler, - metadata + metadata, + encoding ); break; case 'bidi': handleBidiStreaming( call, handler as UntypedBidiStreamingHandler, - metadata + metadata, + encoding ); break; default: @@ -856,9 +863,10 @@ export class Server { async function handleUnary( call: Http2ServerCallStream, handler: UnaryHandler, - metadata: Metadata + metadata: Metadata, + encoding?: MetadataValue ): Promise { - const request = await call.receiveUnaryMessage(); + const request = await call.receiveUnaryMessage(encoding); if (request === undefined || call.cancelled) { return; @@ -886,12 +894,14 @@ async function handleUnary( function handleClientStreaming( call: Http2ServerCallStream, handler: ClientStreamingHandler, - metadata: Metadata + metadata: Metadata, + encoding?: MetadataValue ): void { const stream = new ServerReadableStreamImpl( call, metadata, - handler.deserialize + handler.deserialize, + encoding ); function respond( @@ -915,9 +925,10 @@ function handleClientStreaming( async function handleServerStreaming( call: Http2ServerCallStream, handler: ServerStreamingHandler, - metadata: Metadata + metadata: Metadata, + encoding?: MetadataValue ): Promise { - const request = await call.receiveUnaryMessage(); + const request = await call.receiveUnaryMessage(encoding); if (request === undefined || call.cancelled) { return; @@ -936,13 +947,15 @@ async function handleServerStreaming( function handleBidiStreaming( call: Http2ServerCallStream, handler: BidiStreamingHandler, - metadata: Metadata + metadata: Metadata, + encoding?: MetadataValue ): void { const stream = new ServerDuplexStreamImpl( call, metadata, handler.serialize, - handler.deserialize + handler.deserialize, + encoding ); if (call.cancelled) { diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 8b2815745..676a2fda2 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -21,6 +21,7 @@ import * as assert from 'assert'; import * as fs from 'fs'; import * as http2 from 'http2'; import * as path from 'path'; +import * as protoLoader from '@grpc/proto-loader'; import * as grpc from '../src'; import { Server, ServerCredentials } from '../src'; @@ -29,6 +30,36 @@ import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; import { loadProtoFile } from './common'; +import { TestServiceClient, TestServiceHandlers } from '../src/generated/TestService'; +import { ProtoGrpcType as ChannelzGrpcType } from '../src/generated/channelz'; +import { ProtoGrpcType as TestServiceGrpcType } from '../src/generated/test_service'; +import { Request__Output } from '../src/generated/Request'; + +const loadedChannelzProto = protoLoader.loadSync('channelz.proto', { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + `${__dirname}/../../proto` + ] +}); + +const channelzGrpcObject = grpc.loadPackageDefinition(loadedChannelzProto) as unknown as ChannelzGrpcType; + +const loadedTestServiceProto = protoLoader.loadSync('test_service.proto', { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + `${__dirname}/../../proto` + ] +}); + +const testServiceGrpcObject = grpc.loadPackageDefinition(loadedTestServiceProto) as unknown as TestServiceGrpcType; const ca = fs.readFileSync(path.join(__dirname, 'fixtures', 'ca.pem')); const key = fs.readFileSync(path.join(__dirname, 'fixtures', 'server1.key')); @@ -604,3 +635,258 @@ describe('Generic client and server', () => { }); }); }); + +describe('Compressed requests', () => { + const testServiceHandlers: TestServiceHandlers = { + Unary(call, callback) { + const { metadata, request } = call; + console.log({ metadata, request }); + + callback(null, { count: 500000 }); + }, + + ClientStream(call, callback) { + let timesCalled = 0; + + call.on('data', () => { + timesCalled += 1; + console.log('clientStream received another call', { timesCalled }); + }); + + call.on('end', () => { + console.log('Returning from clientStream: ', { timesCalled }); + callback(null, { count: timesCalled }); + }); + }, + + ServerStream(call) { + const { metadata, request } = call; + console.log({ metadata, request }); + + for (let i = 0; i < 5; i++) { + call.write({ count: request.message.length }); + } + + call.end(); + }, + + BidiStream(call) { + call.on('data', (data: Request__Output) => { + console.log('Bidi stream data received, writing response', { data }); + call.write({ count: data.message.length }); + }); + + call.on('end', () => { + console.log('Server received end event for bidi stream, ending server-side call'); + call.end(); + }); + } + }; + + describe('Test service client and server with deflate', () => { + let client: TestServiceClient; + let server: Server; + let assignedPort: number; + + before(done => { + server = new Server(); + server.addService( + testServiceGrpcObject.TestService.service, + testServiceHandlers + ); + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + server.start(); + assignedPort = port; + client = new testServiceGrpcObject.TestService( + `localhost:${assignedPort}`, + grpc.credentials.createInsecure(), + { + 'grpc.default_compression_algorithm': 1 + } + ); + done(); + } + ); + }); + + after(done => { + client.close(); + server.tryShutdown(done); + }); + + it('Should compress and decompress when performing unary call', done => { + client.unary({ message: 'foo' }, (err, response) => { + assert.ifError(err); + done(); + }); + }); + + it('Should compress and decompress when performing client stream', done => { + const clientStream = client.clientStream((err, res) => { + assert.ifError(err); + assert.equal(res?.count, 3); + done(); + }); + + clientStream.write({ message: 'foo' }, () => { + clientStream.write({ message: 'bar' }, () => { + clientStream.write({ message: 'baz' }, () => { + setTimeout(() => clientStream.end(), 10); + }); + }); + }); + }); + + it('Should compress and decompress when performing server stream', done => { + const serverStream = client.serverStream({ message: 'foobar' }); + let timesResponded = 0; + + serverStream.on('data', () => { + timesResponded += 1; + }); + + serverStream.on('error', (err) => { + assert.ifError(err); + done(); + }); + + serverStream.on('end', () => { + assert.equal(timesResponded, 5); + done(); + }); + }); + + it('Should compress and decompress when performing bidi stream', done => { + const bidiStream = client.bidiStream(); + let timesRequested = 0; + let timesResponded = 0; + + bidiStream.on('data', () => { + timesResponded += 1; + }); + + bidiStream.on('error', (err) => { + assert.ifError(err); + done(); + }); + + bidiStream.on('end', () => { + console.log('Client received end event for bidi stream', { timesResponded, timesRequested }); + assert.equal(timesResponded, timesRequested); + done(); + }); + + bidiStream.write({ message: 'foo' }, () => { + timesRequested += 1; + bidiStream.write({ message: 'bar' }, () => { + timesRequested += 1; + bidiStream.write({ message: 'baz' }, () => { + timesRequested += 1; + setTimeout(() => bidiStream.end(), 10); + }) + }) + }); + }); + + it('Should compress and decompress with gzip', done => { + client = new testServiceGrpcObject.TestService( + `localhost:${assignedPort}`, + grpc.credentials.createInsecure(), + { + 'grpc.default_compression_algorithm': 2 + } + ); + + client.unary({ message: 'foo' }, (err, response) => { + assert.ifError(err); + done(); + }); + }); + + it('Should compress and decompress when performing client stream', done => { + const clientStream = client.clientStream((err, res) => { + assert.ifError(err); + assert.equal(res?.count, 3); + done(); + }); + + clientStream.write({ message: 'foo' }, () => { + clientStream.write({ message: 'bar' }, () => { + clientStream.write({ message: 'baz' }, () => { + setTimeout(() => clientStream.end(), 10); + }); + }); + }); + }); + + it('Should compress and decompress when performing server stream', done => { + const serverStream = client.serverStream({ message: 'foobar' }); + let timesResponded = 0; + + serverStream.on('data', () => { + timesResponded += 1; + }); + + serverStream.on('error', (err) => { + assert.ifError(err); + done(); + }); + + serverStream.on('end', () => { + assert.equal(timesResponded, 5); + done(); + }); + }); + + it('Should compress and decompress when performing bidi stream', done => { + const bidiStream = client.bidiStream(); + let timesRequested = 0; + let timesResponded = 0; + + bidiStream.on('data', () => { + timesResponded += 1; + }); + + bidiStream.on('error', (err) => { + assert.ifError(err); + done(); + }); + + bidiStream.on('end', () => { + console.log('Client received end event for bidi stream', { timesResponded, timesRequested }); + assert.equal(timesResponded, timesRequested); + done(); + }); + + bidiStream.write({ message: 'foo' }, () => { + timesRequested += 1; + bidiStream.write({ message: 'bar' }, () => { + timesRequested += 1; + bidiStream.write({ message: 'baz' }, () => { + timesRequested += 1; + setTimeout(() => bidiStream.end(), 10); + }) + }) + }); + }); + + it('Should fail when attempting to use an unsupported compression method', done => { + client = new testServiceGrpcObject.TestService( + `localhost:${assignedPort}`, + grpc.credentials.createInsecure(), + { + 'grpc.default_compression_algorithm': 3 + } + ); + + client.unary({ message: 'foo' }, (err, response) => { + assert.ok(err); + done(); + }); + }); + }); +}); From cec7e64a2be1ba7c2a6bd19d7d234fd0bcff5c29 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 24 Oct 2021 22:21:24 -0700 Subject: [PATCH 1537/1899] cleanup test file --- packages/grpc-js/test/test-server.ts | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 676a2fda2..f6a68a02a 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -31,23 +31,9 @@ import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; import { loadProtoFile } from './common'; import { TestServiceClient, TestServiceHandlers } from '../src/generated/TestService'; -import { ProtoGrpcType as ChannelzGrpcType } from '../src/generated/channelz'; import { ProtoGrpcType as TestServiceGrpcType } from '../src/generated/test_service'; import { Request__Output } from '../src/generated/Request'; -const loadedChannelzProto = protoLoader.loadSync('channelz.proto', { - keepCase: true, - longs: String, - enums: String, - defaults: true, - oneofs: true, - includeDirs: [ - `${__dirname}/../../proto` - ] -}); - -const channelzGrpcObject = grpc.loadPackageDefinition(loadedChannelzProto) as unknown as ChannelzGrpcType; - const loadedTestServiceProto = protoLoader.loadSync('test_service.proto', { keepCase: true, longs: String, @@ -639,9 +625,6 @@ describe('Generic client and server', () => { describe('Compressed requests', () => { const testServiceHandlers: TestServiceHandlers = { Unary(call, callback) { - const { metadata, request } = call; - console.log({ metadata, request }); - callback(null, { count: 500000 }); }, @@ -650,18 +633,15 @@ describe('Compressed requests', () => { call.on('data', () => { timesCalled += 1; - console.log('clientStream received another call', { timesCalled }); }); call.on('end', () => { - console.log('Returning from clientStream: ', { timesCalled }); callback(null, { count: timesCalled }); }); }, ServerStream(call) { const { metadata, request } = call; - console.log({ metadata, request }); for (let i = 0; i < 5; i++) { call.write({ count: request.message.length }); @@ -672,12 +652,10 @@ describe('Compressed requests', () => { BidiStream(call) { call.on('data', (data: Request__Output) => { - console.log('Bidi stream data received, writing response', { data }); call.write({ count: data.message.length }); }); call.on('end', () => { - console.log('Server received end event for bidi stream, ending server-side call'); call.end(); }); } @@ -775,7 +753,6 @@ describe('Compressed requests', () => { }); bidiStream.on('end', () => { - console.log('Client received end event for bidi stream', { timesResponded, timesRequested }); assert.equal(timesResponded, timesRequested); done(); }); @@ -857,7 +834,6 @@ describe('Compressed requests', () => { }); bidiStream.on('end', () => { - console.log('Client received end event for bidi stream', { timesResponded, timesRequested }); assert.equal(timesResponded, timesRequested); done(); }); From 8dbeeb1d18cb254bf055c8ebbc966657fd94ed4f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 25 Oct 2021 13:29:06 -0700 Subject: [PATCH 1538/1899] grpc-js: Handle undefined socket.localAddress --- packages/grpc-js/src/channelz.ts | 4 ++-- packages/grpc-js/src/server.ts | 2 +- packages/grpc-js/src/subchannel.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 7efe54780..56a015642 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -286,7 +286,7 @@ export interface TlsInfo { } export interface SocketInfo { - localAddress: SubchannelAddress; + localAddress: SubchannelAddress | null; remoteAddress: SubchannelAddress | null; security: TlsInfo | null; remoteName: string | null; @@ -631,7 +631,7 @@ function GetSocket(call: ServerUnaryCall Date: Mon, 25 Oct 2021 18:46:14 -0700 Subject: [PATCH 1539/1899] revert mistaken accept-encoding client header change --- packages/grpc-js/src/compression-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 4ecdbb6a3..4b06fafe6 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -199,7 +199,7 @@ export class CompressionFilter extends BaseFilter implements Filter { async sendMetadata(metadata: Promise): Promise { const headers: Metadata = await metadata; headers.set('grpc-accept-encoding', 'identity,deflate,gzip'); - headers.set('accept-encoding', 'identity,deflate,gzip'); + headers.set('accept-encoding', 'identity'); if (this.defaultCompressionAlgorithm && ['deflate', 'gzip'].includes(this.defaultCompressionAlgorithm)) { headers.set('grpc-encoding', this.defaultCompressionAlgorithm); From 16f13560506235374775f4fac3005cfdfe9c4559 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Oct 2021 18:54:16 -0700 Subject: [PATCH 1540/1899] remove unused compression algorithm key value --- packages/grpc-js/src/compression-filter.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 4b06fafe6..6c613612d 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -26,9 +26,7 @@ import { ChannelOptions } from './channel-options'; const CompressionAlgorithms = { '0': 'identity', '1': 'deflate', - '2': 'gzip', - // Streaming compression is unimplemented - '3': 'stream-gzip' + '2': 'gzip' } as const; const CompressionAlgorithKeys = new Set(Object.keys(CompressionAlgorithms)); From 9d70f39b7e53bb10a578ffd5846e14dd788cc63b Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Oct 2021 19:00:59 -0700 Subject: [PATCH 1541/1899] remove copied test proto file and modify npm command --- packages/grpc-js/package.json | 2 +- packages/grpc-js/proto/test_service.proto | 42 ------------------- packages/grpc-js/src/generated/Request.ts | 2 +- packages/grpc-js/src/generated/Response.ts | 2 +- packages/grpc-js/src/generated/TestService.ts | 2 +- 5 files changed, 4 insertions(+), 46 deletions(-) delete mode 100644 packages/grpc-js/proto/test_service.proto diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f430c09d2..76a0902be 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -54,7 +54,7 @@ "fix": "gts fix src/*.ts", "pretest": "npm run generate-types && npm run compile", "posttest": "npm run check && madge -c ./build/src", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ -O src/generated/ --grpcLib ../index channelz.proto test_service.proto" + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ --include-dirs test/fixtures/ -O src/generated/ --grpcLib ../index channelz.proto test_service.proto" }, "dependencies": { "@grpc/proto-loader": "^0.6.4", diff --git a/packages/grpc-js/proto/test_service.proto b/packages/grpc-js/proto/test_service.proto deleted file mode 100644 index f99393d14..000000000 --- a/packages/grpc-js/proto/test_service.proto +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -syntax = "proto3"; - -message Request { - bool error = 1; - string message = 2; - int32 errorAfter = 3; -} - -message Response { - int32 count = 1; -} - -service TestService { - rpc Unary (Request) returns (Response) { - } - - rpc ClientStream (stream Request) returns (Response) { - } - - rpc ServerStream (Request) returns (stream Response) { - } - - rpc BidiStream (stream Request) returns (stream Response) { - } -} diff --git a/packages/grpc-js/src/generated/Request.ts b/packages/grpc-js/src/generated/Request.ts index 93898a701..d64ebb6ea 100644 --- a/packages/grpc-js/src/generated/Request.ts +++ b/packages/grpc-js/src/generated/Request.ts @@ -1,4 +1,4 @@ -// Original file: proto/test_service.proto +// Original file: test/fixtures/test_service.proto export interface Request { diff --git a/packages/grpc-js/src/generated/Response.ts b/packages/grpc-js/src/generated/Response.ts index 980bfdd18..217fc75e8 100644 --- a/packages/grpc-js/src/generated/Response.ts +++ b/packages/grpc-js/src/generated/Response.ts @@ -1,4 +1,4 @@ -// Original file: proto/test_service.proto +// Original file: test/fixtures/test_service.proto export interface Response { diff --git a/packages/grpc-js/src/generated/TestService.ts b/packages/grpc-js/src/generated/TestService.ts index dd1d22ab2..f890c520f 100644 --- a/packages/grpc-js/src/generated/TestService.ts +++ b/packages/grpc-js/src/generated/TestService.ts @@ -1,4 +1,4 @@ -// Original file: proto/test_service.proto +// Original file: test/fixtures/test_service.proto import type * as grpc from './../index' import type { MethodDefinition } from '@grpc/proto-loader' From 959503ec94aa08a6942780d7b7cd80847dbd4be6 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Oct 2021 19:14:01 -0700 Subject: [PATCH 1542/1899] rewrite CompressionAlgorithms to use numeric keys and export it --- packages/grpc-js/src/compression-filter.ts | 14 +++++++------- packages/grpc-js/src/index.ts | 2 ++ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 6c613612d..eabb7a851 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -23,16 +23,16 @@ import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata, MetadataValue } from './metadata'; import { ChannelOptions } from './channel-options'; -const CompressionAlgorithms = { - '0': 'identity', - '1': 'deflate', - '2': 'gzip' +export const CompressionAlgorithms = { + 0: 'identity', + 1: 'deflate', + 2: 'gzip' } as const; const CompressionAlgorithKeys = new Set(Object.keys(CompressionAlgorithms)); -const isCompressionAlgorithmKey = (key: string | undefined): key is keyof typeof CompressionAlgorithms => { - return typeof key === 'string' && CompressionAlgorithKeys.has(key); +const isCompressionAlgorithmKey = (key: number | undefined): key is keyof typeof CompressionAlgorithms => { + return typeof key === 'number' && CompressionAlgorithKeys.has(key.toString()); } type CompressionAlgorithm = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms]; @@ -187,7 +187,7 @@ export class CompressionFilter extends BaseFilter implements Filter { constructor(channelOptions: ChannelOptions) { super(); - const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']?.toString(); + const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 4b7967be9..7e1ed7a50 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -25,6 +25,7 @@ import { import { CallCredentials, OAuth2Client } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ChannelImplementation } from './channel'; +import { CompressionAlgorithms } from './compression-filter'; import { ConnectivityState } from './connectivity-state'; import { ChannelCredentials } from './channel-credentials'; import { @@ -124,6 +125,7 @@ export { Status as status, ConnectivityState as connectivityState, Propagate as propagate, + CompressionAlgorithms as compressionAlgorithms // TODO: Other constants as well }; From af010071fe2f4eeab2ebc80b99039942f935423f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Oct 2021 19:43:40 -0700 Subject: [PATCH 1543/1899] have client restore default sendCompression if server doesnt support compression, and fix test file generation --- packages/grpc-js/package.json | 5 ++-- packages/grpc-js/src/compression-filter.ts | 12 ++++++++++ .../{src => test}/generated/Request.ts | 0 .../{src => test}/generated/Response.ts | 0 .../{src => test}/generated/TestService.ts | 2 +- .../{src => test}/generated/test_service.ts | 2 +- packages/grpc-js/test/test-server.ts | 23 ++++--------------- 7 files changed, 21 insertions(+), 23 deletions(-) rename packages/grpc-js/{src => test}/generated/Request.ts (100%) rename packages/grpc-js/{src => test}/generated/Response.ts (100%) rename packages/grpc-js/{src => test}/generated/TestService.ts (98%) rename packages/grpc-js/{src => test}/generated/test_service.ts (92%) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 76a0902be..9131d470f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -52,9 +52,10 @@ "test": "gulp test", "check": "gts check src/**/*.ts", "fix": "gts fix src/*.ts", - "pretest": "npm run generate-types && npm run compile", + "pretest": "npm run generate-types && npm run generate-test-types && npm run compile", "posttest": "npm run check && madge -c ./build/src", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ --include-dirs test/fixtures/ -O src/generated/ --grpcLib ../index channelz.proto test_service.proto" + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs proto/ --include-dirs test/fixtures/ -O src/generated/ --grpcLib ../index channelz.proto", + "generate-test-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --include-dirs test/fixtures/ -O test/generated/ --grpcLib ../../src/index test_service.proto" }, "dependencies": { "@grpc/proto-loader": "^0.6.4", diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index eabb7a851..b7e5e5d29 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -217,6 +217,18 @@ export class CompressionFilter extends BaseFilter implements Filter { } } metadata.remove('grpc-encoding'); + + /* Check to see if the compression we're using to send messages is supported by the server + * If not, reset the sendCompression filter and have it use the default IdentityHandler */ + const serverSupportedEncodingsHeader = metadata.get('grpc-accept-encoding')[0] as string | undefined; + if (serverSupportedEncodingsHeader) { + const serverSupportedEncodings = serverSupportedEncodingsHeader.split(','); + + if ((this.sendCompression instanceof DeflateHandler && !serverSupportedEncodings.includes('deflate')) + || (this.sendCompression instanceof GzipHandler && !serverSupportedEncodings.includes('gzip'))) { + this.sendCompression = new IdentityHandler(); + } + } metadata.remove('grpc-accept-encoding'); return metadata; } diff --git a/packages/grpc-js/src/generated/Request.ts b/packages/grpc-js/test/generated/Request.ts similarity index 100% rename from packages/grpc-js/src/generated/Request.ts rename to packages/grpc-js/test/generated/Request.ts diff --git a/packages/grpc-js/src/generated/Response.ts b/packages/grpc-js/test/generated/Response.ts similarity index 100% rename from packages/grpc-js/src/generated/Response.ts rename to packages/grpc-js/test/generated/Response.ts diff --git a/packages/grpc-js/src/generated/TestService.ts b/packages/grpc-js/test/generated/TestService.ts similarity index 98% rename from packages/grpc-js/src/generated/TestService.ts rename to packages/grpc-js/test/generated/TestService.ts index f890c520f..75bff33e4 100644 --- a/packages/grpc-js/src/generated/TestService.ts +++ b/packages/grpc-js/test/generated/TestService.ts @@ -1,6 +1,6 @@ // Original file: test/fixtures/test_service.proto -import type * as grpc from './../index' +import type * as grpc from './../../src/index' import type { MethodDefinition } from '@grpc/proto-loader' import type { Request as _Request, Request__Output as _Request__Output } from './Request'; import type { Response as _Response, Response__Output as _Response__Output } from './Response'; diff --git a/packages/grpc-js/src/generated/test_service.ts b/packages/grpc-js/test/generated/test_service.ts similarity index 92% rename from packages/grpc-js/src/generated/test_service.ts rename to packages/grpc-js/test/generated/test_service.ts index 2beb88680..364acddeb 100644 --- a/packages/grpc-js/src/generated/test_service.ts +++ b/packages/grpc-js/test/generated/test_service.ts @@ -1,4 +1,4 @@ -import type * as grpc from '../index'; +import type * as grpc from '../../src/index'; import type { MessageTypeDefinition } from '@grpc/proto-loader'; import type { TestServiceClient as _TestServiceClient, TestServiceDefinition as _TestServiceDefinition } from './TestService'; diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index f6a68a02a..c8171e796 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -30,11 +30,11 @@ import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; import { loadProtoFile } from './common'; -import { TestServiceClient, TestServiceHandlers } from '../src/generated/TestService'; -import { ProtoGrpcType as TestServiceGrpcType } from '../src/generated/test_service'; -import { Request__Output } from '../src/generated/Request'; +import { TestServiceClient, TestServiceHandlers } from './generated/TestService'; +import { ProtoGrpcType as TestServiceGrpcType } from './generated/test_service'; +import { Request__Output } from './generated/Request'; -const loadedTestServiceProto = protoLoader.loadSync('test_service.proto', { +const loadedTestServiceProto = protoLoader.loadSync('test/fixtures/test_service.proto', { keepCase: true, longs: String, enums: String, @@ -849,20 +849,5 @@ describe('Compressed requests', () => { }) }); }); - - it('Should fail when attempting to use an unsupported compression method', done => { - client = new testServiceGrpcObject.TestService( - `localhost:${assignedPort}`, - grpc.credentials.createInsecure(), - { - 'grpc.default_compression_algorithm': 3 - } - ); - - client.unary({ message: 'foo' }, (err, response) => { - assert.ok(err); - done(); - }); - }); }); }); From d68d94a5f47582419390e2e8f08a10339a866026 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 25 Oct 2021 20:21:48 -0700 Subject: [PATCH 1544/1899] re-enable NoCompress flag behavior and check Compressed Flag byte on server --- packages/grpc-js/src/compression-filter.ts | 10 ++++----- packages/grpc-js/src/server-call.ts | 8 +++++-- packages/grpc-js/test/test-server.ts | 26 ++++++++++++++++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index b7e5e5d29..ae507d333 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -17,7 +17,7 @@ import * as zlib from 'zlib'; -import { Call, WriteObject } from './call-stream'; +import { Call, WriteObject, WriteFlags } from './call-stream'; import { Channel } from './channel'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata, MetadataValue } from './metadata'; @@ -238,10 +238,10 @@ export class CompressionFilter extends BaseFilter implements Filter { * and the output is a framed and possibly compressed message. For this * reason, this filter should be at the bottom of the filter stack */ const resolvedMessage: WriteObject = await message; - const compress = !(this.sendCompression instanceof IdentityHandler); - // resolvedMessage.flags === undefined - // ? false - // : (resolvedMessage.flags & WriteFlags.NoCompress) === 0; + const compress = + resolvedMessage.flags === undefined + ? !(this.sendCompression instanceof IdentityHandler) + : (resolvedMessage.flags & WriteFlags.NoCompress) === 0; return { message: await this.sendCompression.writeMessage( resolvedMessage.message, diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 8ea488a4d..f1d3a8abd 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -561,7 +561,9 @@ export class Http2ServerCallStream< this.emit('receiveMessage'); - const decompressedMessage = await this.getDecompressedMessage(requestBytes, encoding); + const compressed = requestBytes.readUInt8(0) === 1; + const compressedMessageEncoding = compressed ? encoding : undefined; + const decompressedMessage = await this.getDecompressedMessage(requestBytes, compressedMessageEncoding); // Encountered an error with decompression; it'll already have been propogated back // Just return early @@ -748,7 +750,9 @@ export class Http2ServerCallStream< } this.emit('receiveMessage'); - const decompressedMessage = await this.getDecompressedMessage(message, encoding); + const compressed = message.readUInt8(0) === 1; + const compressedMessageEncoding = compressed ? encoding : undefined; + const decompressedMessage = await this.getDecompressedMessage(message, compressedMessageEncoding); // Encountered an error with decompression; it'll already have been propogated back // Just return early diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index c8171e796..b6cffd81c 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -849,5 +849,31 @@ describe('Compressed requests', () => { }) }); }); + + it('Should not compress requests when the NoCompress write flag is used', done => { + const bidiStream = client.bidiStream(); + let timesRequested = 0; + let timesResponded = 0; + + bidiStream.on('data', () => { + timesResponded += 1; + }); + + bidiStream.on('error', (err) => { + assert.ifError(err); + done(); + }); + + bidiStream.on('end', () => { + assert.equal(timesResponded, timesRequested); + done(); + }); + + bidiStream._write({ message: 'foo' }, '2', (err: any) => { + assert.ifError(err); + timesRequested += 1; + setTimeout(() => bidiStream.end(), 10); + }); + }); }); }); From 91ae2b44b165f4d77ed76deab5275df98230776b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 25 Oct 2021 13:29:06 -0700 Subject: [PATCH 1545/1899] grpc-js: Handle undefined socket.localAddress --- packages/grpc-js/src/channelz.ts | 4 ++-- packages/grpc-js/src/server.ts | 2 +- packages/grpc-js/src/subchannel.ts | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index a1c85eb47..768efaa58 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -298,7 +298,7 @@ export interface TlsInfo { } export interface SocketInfo { - localAddress: SubchannelAddress; + localAddress: SubchannelAddress | null; remoteAddress: SubchannelAddress | null; security: TlsInfo | null; remoteName: string | null; @@ -629,7 +629,7 @@ function GetSocket(call: ServerUnaryCall Date: Tue, 26 Oct 2021 13:44:03 -0700 Subject: [PATCH 1546/1899] change encoding type from MetadataValue to string --- packages/grpc-js/src/server-call.ts | 11 +++++------ packages/grpc-js/src/server.ts | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index f1d3a8abd..d3c622b5c 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -33,7 +33,6 @@ import { StreamDecoder } from './stream-decoder'; import { ObjectReadable, ObjectWritable } from './object-stream'; import { ChannelOptions } from './channel-options'; import * as logging from './logging'; -import { MetadataValue } from '.'; const TRACER_NAME = 'server_call'; @@ -139,7 +138,7 @@ export class ServerReadableStreamImpl private call: Http2ServerCallStream, public metadata: Metadata, public deserialize: Deserialize, - encoding?: MetadataValue + encoding?: string ) { super({ objectMode: true }); this.cancelled = false; @@ -254,7 +253,7 @@ export class ServerDuplexStreamImpl public metadata: Metadata, public serialize: Serialize, public deserialize: Deserialize, - encoding?: MetadataValue + encoding?: string ) { super({ objectMode: true }); this.cancelled = false; @@ -443,7 +442,7 @@ export class Http2ServerCallStream< return this.cancelled; } - private getDecompressedMessage(message: Buffer, encoding?: MetadataValue) { + private getDecompressedMessage(message: Buffer, encoding?: string) { switch (encoding) { case 'deflate': { return new Promise((resolve, reject) => { @@ -534,7 +533,7 @@ export class Http2ServerCallStream< return metadata; } - receiveUnaryMessage(encoding?: MetadataValue): Promise { + receiveUnaryMessage(encoding?: string): Promise { return new Promise((resolve, reject) => { const stream = this.stream; const chunks: Buffer[] = []; @@ -730,7 +729,7 @@ export class Http2ServerCallStream< readable: | ServerReadableStream | ServerDuplexStream, - encoding?: MetadataValue + encoding?: string ) { const decoder = new StreamDecoder(); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 552f31b02..b69a795e9 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -61,7 +61,6 @@ import { import { parseUri } from './uri-parser'; import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; import { CipherNameAndProtocol, TLSSocket } from 'tls'; -import { MetadataValue } from '.'; const TRACER_NAME = 'server'; @@ -779,7 +778,7 @@ export class Server { }); } const metadata = call.receiveMetadata(headers); - const encoding: MetadataValue | undefined = metadata.get('grpc-encoding')[0]; + const encoding = metadata.get('grpc-encoding')[0] as string | undefined; metadata.remove('grpc-encoding'); switch (handler.type) { @@ -864,7 +863,7 @@ async function handleUnary( call: Http2ServerCallStream, handler: UnaryHandler, metadata: Metadata, - encoding?: MetadataValue + encoding?: string ): Promise { const request = await call.receiveUnaryMessage(encoding); @@ -895,7 +894,7 @@ function handleClientStreaming( call: Http2ServerCallStream, handler: ClientStreamingHandler, metadata: Metadata, - encoding?: MetadataValue + encoding?: string ): void { const stream = new ServerReadableStreamImpl( call, @@ -926,7 +925,7 @@ async function handleServerStreaming( call: Http2ServerCallStream, handler: ServerStreamingHandler, metadata: Metadata, - encoding?: MetadataValue + encoding?: string ): Promise { const request = await call.receiveUnaryMessage(encoding); @@ -948,7 +947,7 @@ function handleBidiStreaming( call: Http2ServerCallStream, handler: BidiStreamingHandler, metadata: Metadata, - encoding?: MetadataValue + encoding?: string ): void { const stream = new ServerDuplexStreamImpl( call, From 21b09e25ba9c430389d8c61e674c531757e6f2ae Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 26 Oct 2021 13:51:42 -0700 Subject: [PATCH 1547/1899] separate compression algorithms to avoid circular dependency --- packages/grpc-js/src/channel-options.ts | 4 +++- .../grpc-js/src/compression-algorithms.ts | 22 +++++++++++++++++++ packages/grpc-js/src/compression-filter.ts | 7 +----- packages/grpc-js/src/index.ts | 2 +- 4 files changed, 27 insertions(+), 8 deletions(-) create mode 100644 packages/grpc-js/src/compression-algorithms.ts diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index f0b37d7a4..b54ae4eda 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -15,6 +15,8 @@ * */ +import { CompressionAlgorithms } from './compression-algorithms'; + /** * An interface that contains options used when initializing a Channel instance. */ @@ -36,7 +38,7 @@ export interface ChannelOptions { 'grpc.enable_http_proxy'?: number; 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; - 'grpc.default_compression_algorithm'?: number; + 'grpc.default_compression_algorithm'?: keyof typeof CompressionAlgorithms; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; diff --git a/packages/grpc-js/src/compression-algorithms.ts b/packages/grpc-js/src/compression-algorithms.ts new file mode 100644 index 000000000..8ec283cf6 --- /dev/null +++ b/packages/grpc-js/src/compression-algorithms.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export const CompressionAlgorithms = { + 0: 'identity', + 1: 'deflate', + 2: 'gzip' +} as const; diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index ae507d333..69fcf48db 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -19,16 +19,11 @@ import * as zlib from 'zlib'; import { Call, WriteObject, WriteFlags } from './call-stream'; import { Channel } from './channel'; +import { CompressionAlgorithms } from './compression-algorithms'; import { BaseFilter, Filter, FilterFactory } from './filter'; import { Metadata, MetadataValue } from './metadata'; import { ChannelOptions } from './channel-options'; -export const CompressionAlgorithms = { - 0: 'identity', - 1: 'deflate', - 2: 'gzip' -} as const; - const CompressionAlgorithKeys = new Set(Object.keys(CompressionAlgorithms)); const isCompressionAlgorithmKey = (key: number | undefined): key is keyof typeof CompressionAlgorithms => { diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 7e1ed7a50..f34c19a1d 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -25,7 +25,7 @@ import { import { CallCredentials, OAuth2Client } from './call-credentials'; import { Deadline, StatusObject } from './call-stream'; import { Channel, ChannelImplementation } from './channel'; -import { CompressionAlgorithms } from './compression-filter'; +import { CompressionAlgorithms } from './compression-algorithms'; import { ConnectivityState } from './connectivity-state'; import { ChannelCredentials } from './channel-credentials'; import { From e03c1159ea650cc4bb931ae7be2ef22188bd635e Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 26 Oct 2021 14:01:37 -0700 Subject: [PATCH 1548/1899] log a warning when invalid value for grpc.default_compression_algorithm option is provided --- packages/grpc-js/src/compression-filter.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 69fcf48db..26b2836b6 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -19,10 +19,12 @@ import * as zlib from 'zlib'; import { Call, WriteObject, WriteFlags } from './call-stream'; import { Channel } from './channel'; +import { ChannelOptions } from './channel-options'; import { CompressionAlgorithms } from './compression-algorithms'; +import { LogVerbosity } from './constants'; import { BaseFilter, Filter, FilterFactory } from './filter'; +import * as logging from './logging'; import { Metadata, MetadataValue } from './metadata'; -import { ChannelOptions } from './channel-options'; const CompressionAlgorithKeys = new Set(Object.keys(CompressionAlgorithms)); @@ -186,6 +188,8 @@ export class CompressionFilter extends BaseFilter implements Filter { if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); + } else { + logging.log(LogVerbosity.ERROR, 'Invalid value provided for grpc.default_compression_algorithm option'); } } From 7a31b4a65a2e2cc08231984602b84c02e336cd9a Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 26 Oct 2021 14:03:14 -0700 Subject: [PATCH 1549/1899] change test to use write instead of _write --- packages/grpc-js/test/test-server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index b6cffd81c..c0e7ebf5f 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -869,7 +869,7 @@ describe('Compressed requests', () => { done(); }); - bidiStream._write({ message: 'foo' }, '2', (err: any) => { + bidiStream.write({ message: 'foo' }, '2', (err: any) => { assert.ifError(err); timesRequested += 1; setTimeout(() => bidiStream.end(), 10); From 25a1806e114431bd355abe1264455fac7ed74bde Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 26 Oct 2021 14:09:09 -0700 Subject: [PATCH 1550/1899] change year in new copyright heade --- packages/grpc-js/src/compression-algorithms.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/compression-algorithms.ts b/packages/grpc-js/src/compression-algorithms.ts index 8ec283cf6..ccc38e76b 100644 --- a/packages/grpc-js/src/compression-algorithms.ts +++ b/packages/grpc-js/src/compression-algorithms.ts @@ -1,5 +1,5 @@ /* - * Copyright 2019 gRPC authors. + * Copyright 2021 gRPC authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From d01ff794fc2f28a7194fc4cb5e996e13b071dd29 Mon Sep 17 00:00:00 2001 From: Robert M Date: Tue, 26 Oct 2021 14:21:58 -0700 Subject: [PATCH 1551/1899] Update error message for invalid default_compression_algorithm Co-authored-by: Michael Lumish --- packages/grpc-js/src/compression-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 26b2836b6..9568b413d 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -189,7 +189,7 @@ export class CompressionFilter extends BaseFilter implements Filter { this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); } else { - logging.log(LogVerbosity.ERROR, 'Invalid value provided for grpc.default_compression_algorithm option'); + logging.log(LogVerbosity.ERROR, `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}`); } } From 6ba008110b0ba80d0211c05e7fb5e2da712eb4ad Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 26 Oct 2021 14:25:21 -0700 Subject: [PATCH 1552/1899] only attempt to use custom compression filter when option value is provided --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/compression-filter.ts | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9131d470f..893070948 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -59,7 +59,7 @@ }, "dependencies": { "@grpc/proto-loader": "^0.6.4", - "@types/node": "16.10.0", + "@types/node": ">=12.12.47", "@types/semver": "^7.3.9" }, "files": [ diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 26b2836b6..ea81ed8cf 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -185,11 +185,13 @@ export class CompressionFilter extends BaseFilter implements Filter { super(); const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; - if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { - this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; - this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); - } else { - logging.log(LogVerbosity.ERROR, 'Invalid value provided for grpc.default_compression_algorithm option'); + if (compressionAlgorithmKey !== undefined) { + if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { + this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; + this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); + } else { + logging.log(LogVerbosity.ERROR, 'Invalid value provided for grpc.default_compression_algorithm option'); + } } } From c9659b5158d7a26b6046e20127ba6dc3e844486d Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 28 Oct 2021 20:29:47 -0700 Subject: [PATCH 1553/1899] persist server supported encoding header across compression filter instances --- packages/grpc-js/src/compression-filter.ts | 25 ++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 090556381..e5f53334b 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -34,6 +34,10 @@ const isCompressionAlgorithmKey = (key: number | undefined): key is keyof typeof type CompressionAlgorithm = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms]; +type SharedCompressionFilterConfig = { + serverSupportedEncodingHeader?: string; +}; + abstract class CompressionHandler { protected abstract compressMessage(message: Buffer): Promise; protected abstract decompressMessage(data: Buffer): Promise; @@ -181,14 +185,25 @@ export class CompressionFilter extends BaseFilter implements Filter { private receiveCompression: CompressionHandler = new IdentityHandler(); private defaultCompressionAlgorithm: CompressionAlgorithm | undefined; - constructor(channelOptions: ChannelOptions) { + constructor(channelOptions: ChannelOptions, private sharedFilterConfig: SharedCompressionFilterConfig) { super(); + const serverSupportedEncodings = sharedFilterConfig.serverSupportedEncodingHeader?.split(','); const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; if (compressionAlgorithmKey !== undefined) { if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { - this.defaultCompressionAlgorithm = CompressionAlgorithms[compressionAlgorithmKey]; - this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); + const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey]; + /** + * There are two possible situations here: + * 1) We don't have any info yet from the server about what compression it supports + * In that case we should just use what the client tells us to use + * 2) We've previously received a response from the server including a grpc-accept-encoding header + * In that case we only want to use the encoding chosen by the client if the server supports it + */ + if (!serverSupportedEncodings || serverSupportedEncodings.includes(clientSelectedEncoding)) { + this.defaultCompressionAlgorithm = clientSelectedEncoding; + this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); + } } else { logging.log(LogVerbosity.ERROR, `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}`); } @@ -223,6 +238,7 @@ export class CompressionFilter extends BaseFilter implements Filter { * If not, reset the sendCompression filter and have it use the default IdentityHandler */ const serverSupportedEncodingsHeader = metadata.get('grpc-accept-encoding')[0] as string | undefined; if (serverSupportedEncodingsHeader) { + this.sharedFilterConfig.serverSupportedEncodingHeader = serverSupportedEncodingsHeader; const serverSupportedEncodings = serverSupportedEncodingsHeader.split(','); if ((this.sendCompression instanceof DeflateHandler && !serverSupportedEncodings.includes('deflate')) @@ -263,8 +279,9 @@ export class CompressionFilter extends BaseFilter implements Filter { export class CompressionFilterFactory implements FilterFactory { + private sharedFilterConfig: SharedCompressionFilterConfig = {}; constructor(private readonly channel: Channel, private readonly options: ChannelOptions) {} createFilter(callStream: Call): CompressionFilter { - return new CompressionFilter(this.options); + return new CompressionFilter(this.options, this.sharedFilterConfig); } } From 47bb8b669e6e28453f84092b6f3ea0c4ff81e64a Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 28 Oct 2021 20:36:29 -0700 Subject: [PATCH 1554/1899] move string split down to where it matters --- packages/grpc-js/src/compression-filter.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index e5f53334b..a6428ce01 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -188,11 +188,11 @@ export class CompressionFilter extends BaseFilter implements Filter { constructor(channelOptions: ChannelOptions, private sharedFilterConfig: SharedCompressionFilterConfig) { super(); - const serverSupportedEncodings = sharedFilterConfig.serverSupportedEncodingHeader?.split(','); const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; if (compressionAlgorithmKey !== undefined) { if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey]; + const serverSupportedEncodings = sharedFilterConfig.serverSupportedEncodingHeader?.split(','); /** * There are two possible situations here: * 1) We don't have any info yet from the server about what compression it supports From 9150bdfd247b5f3215bac8b87097cf4691b262e3 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 29 Oct 2021 19:19:09 -0700 Subject: [PATCH 1555/1899] default to identity header everywhere instead of leaving it undefined --- packages/grpc-js/src/compression-filter.ts | 24 +++++++++++-------- packages/grpc-js/src/server-call.ts | 27 ++++++++++++++-------- packages/grpc-js/src/server.ts | 10 ++++---- 3 files changed, 37 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index a6428ce01..cbdd35104 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -183,7 +183,7 @@ function getCompressionHandler(compressionName: string): CompressionHandler { export class CompressionFilter extends BaseFilter implements Filter { private sendCompression: CompressionHandler = new IdentityHandler(); private receiveCompression: CompressionHandler = new IdentityHandler(); - private defaultCompressionAlgorithm: CompressionAlgorithm | undefined; + private currentCompressionAlgorithm: CompressionAlgorithm = 'identity'; constructor(channelOptions: ChannelOptions, private sharedFilterConfig: SharedCompressionFilterConfig) { super(); @@ -201,8 +201,8 @@ export class CompressionFilter extends BaseFilter implements Filter { * In that case we only want to use the encoding chosen by the client if the server supports it */ if (!serverSupportedEncodings || serverSupportedEncodings.includes(clientSelectedEncoding)) { - this.defaultCompressionAlgorithm = clientSelectedEncoding; - this.sendCompression = getCompressionHandler(this.defaultCompressionAlgorithm); + this.currentCompressionAlgorithm = clientSelectedEncoding; + this.sendCompression = getCompressionHandler(this.currentCompressionAlgorithm); } } else { logging.log(LogVerbosity.ERROR, `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}`); @@ -215,10 +215,11 @@ export class CompressionFilter extends BaseFilter implements Filter { headers.set('grpc-accept-encoding', 'identity,deflate,gzip'); headers.set('accept-encoding', 'identity'); - if (this.defaultCompressionAlgorithm && ['deflate', 'gzip'].includes(this.defaultCompressionAlgorithm)) { - headers.set('grpc-encoding', this.defaultCompressionAlgorithm); - } else { + // No need to send the header if it's "identity" - behavior is identical; save the bandwidth + if (this.currentCompressionAlgorithm === 'identity') { headers.remove('grpc-encoding'); + } else { + headers.set('grpc-encoding', this.currentCompressionAlgorithm); } return headers; @@ -255,10 +256,13 @@ export class CompressionFilter extends BaseFilter implements Filter { * and the output is a framed and possibly compressed message. For this * reason, this filter should be at the bottom of the filter stack */ const resolvedMessage: WriteObject = await message; - const compress = - resolvedMessage.flags === undefined - ? !(this.sendCompression instanceof IdentityHandler) - : (resolvedMessage.flags & WriteFlags.NoCompress) === 0; + let compress: boolean; + if (this.sendCompression instanceof IdentityHandler) { + compress = false; + } else { + compress = ((resolvedMessage.flags ?? 0) & WriteFlags.NoCompress) === 0; + } + return { message: await this.sendCompression.writeMessage( resolvedMessage.message, diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index d3c622b5c..b340b3446 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -138,7 +138,7 @@ export class ServerReadableStreamImpl private call: Http2ServerCallStream, public metadata: Metadata, public deserialize: Deserialize, - encoding?: string + encoding: string ) { super({ objectMode: true }); this.cancelled = false; @@ -253,7 +253,7 @@ export class ServerDuplexStreamImpl public metadata: Metadata, public serialize: Serialize, public deserialize: Deserialize, - encoding?: string + encoding: string ) { super({ objectMode: true }); this.cancelled = false; @@ -442,7 +442,7 @@ export class Http2ServerCallStream< return this.cancelled; } - private getDecompressedMessage(message: Buffer, encoding?: string) { + private getDecompressedMessage(message: Buffer, encoding: string) { switch (encoding) { case 'deflate': { return new Promise((resolve, reject) => { @@ -477,9 +477,18 @@ export class Http2ServerCallStream< }); }); } - - default: + + case 'identity': { return Promise.resolve(message); + } + + default: { + this.sendError({ + code: Status.UNIMPLEMENTED, + details: `Received "grpc-encoding" header "${encoding}", which is not supported`, + }); + return Promise.resolve(); + } } } @@ -533,7 +542,7 @@ export class Http2ServerCallStream< return metadata; } - receiveUnaryMessage(encoding?: string): Promise { + receiveUnaryMessage(encoding: string): Promise { return new Promise((resolve, reject) => { const stream = this.stream; const chunks: Buffer[] = []; @@ -561,7 +570,7 @@ export class Http2ServerCallStream< this.emit('receiveMessage'); const compressed = requestBytes.readUInt8(0) === 1; - const compressedMessageEncoding = compressed ? encoding : undefined; + const compressedMessageEncoding = compressed ? encoding : 'identity'; const decompressedMessage = await this.getDecompressedMessage(requestBytes, compressedMessageEncoding); // Encountered an error with decompression; it'll already have been propogated back @@ -729,7 +738,7 @@ export class Http2ServerCallStream< readable: | ServerReadableStream | ServerDuplexStream, - encoding?: string + encoding: string ) { const decoder = new StreamDecoder(); @@ -750,7 +759,7 @@ export class Http2ServerCallStream< this.emit('receiveMessage'); const compressed = message.readUInt8(0) === 1; - const compressedMessageEncoding = compressed ? encoding : undefined; + const compressedMessageEncoding = compressed ? encoding : 'identity'; const decompressedMessage = await this.getDecompressedMessage(message, compressedMessageEncoding); // Encountered an error with decompression; it'll already have been propogated back diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index b69a795e9..a83363674 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -778,7 +778,7 @@ export class Server { }); } const metadata = call.receiveMetadata(headers); - const encoding = metadata.get('grpc-encoding')[0] as string | undefined; + const encoding = (metadata.get('grpc-encoding')[0] as string | undefined) ?? 'identity'; metadata.remove('grpc-encoding'); switch (handler.type) { @@ -863,7 +863,7 @@ async function handleUnary( call: Http2ServerCallStream, handler: UnaryHandler, metadata: Metadata, - encoding?: string + encoding: string ): Promise { const request = await call.receiveUnaryMessage(encoding); @@ -894,7 +894,7 @@ function handleClientStreaming( call: Http2ServerCallStream, handler: ClientStreamingHandler, metadata: Metadata, - encoding?: string + encoding: string ): void { const stream = new ServerReadableStreamImpl( call, @@ -925,7 +925,7 @@ async function handleServerStreaming( call: Http2ServerCallStream, handler: ServerStreamingHandler, metadata: Metadata, - encoding?: string + encoding: string ): Promise { const request = await call.receiveUnaryMessage(encoding); @@ -947,7 +947,7 @@ function handleBidiStreaming( call: Http2ServerCallStream, handler: BidiStreamingHandler, metadata: Metadata, - encoding?: string + encoding: string ): void { const stream = new ServerDuplexStreamImpl( call, From 692ee3c03faab8fcbd3dfaa70bff57e32c739c3d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Nov 2021 14:23:53 -0700 Subject: [PATCH 1556/1899] grpc-js-xds: Switch from udpa to xds submodule --- .gitmodules | 6 +- packages/grpc-js-xds/deps/udpa | 1 - packages/grpc-js-xds/deps/xds | 1 + packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/generated/cluster.ts | 9 +++ packages/grpc-js-xds/src/generated/fault.ts | 9 +++ .../generated/google/protobuf/FieldOptions.ts | 3 + .../generated/google/protobuf/FileOptions.ts | 3 + .../google/protobuf/MessageOptions.ts | 3 + .../src/generated/http_connection_manager.ts | 9 +++ .../grpc-js-xds/src/generated/listener.ts | 9 +++ packages/grpc-js-xds/src/generated/route.ts | 9 +++ .../grpc-js-xds/src/generated/typed_struct.ts | 7 ++ .../annotations/FieldMigrateAnnotation.ts | 2 +- .../annotations/FieldSecurityAnnotation.ts | 2 +- .../udpa/annotations/FileMigrateAnnotation.ts | 2 +- .../udpa/annotations/MigrateAnnotation.ts | 2 +- .../udpa/annotations/PackageVersionStatus.ts | 2 +- .../udpa/annotations/StatusAnnotation.ts | 2 +- .../udpa/annotations/VersioningAnnotation.ts | 2 +- .../src/generated/udpa/type/v1/TypedStruct.ts | 2 +- .../annotations/v3/FieldStatusAnnotation.ts | 16 ++++ .../annotations/v3/FileStatusAnnotation.ts | 16 ++++ .../annotations/v3/MessageStatusAnnotation.ts | 16 ++++ .../annotations/v3/PackageVersionStatus.ts | 21 +++++ .../xds/annotations/v3/StatusAnnotation.ts | 25 ++++++ .../src/generated/xds/core/v3/Authority.ts | 2 +- .../generated/xds/core/v3/CollectionEntry.ts | 2 +- .../generated/xds/core/v3/ContextParams.ts | 2 +- .../generated/xds/core/v3/ResourceLocator.ts | 4 +- .../src/generated/xds/type/v3/TypedStruct.ts | 77 +++++++++++++++++++ packages/grpc-js-xds/src/http-filter.ts | 17 ++-- .../src/http-filter/fault-injection-filter.ts | 2 +- packages/grpc-js-xds/src/resources.ts | 2 +- packages/grpc-js-xds/src/xds-client.ts | 2 +- 35 files changed, 263 insertions(+), 28 deletions(-) delete mode 160000 packages/grpc-js-xds/deps/udpa create mode 160000 packages/grpc-js-xds/deps/xds create mode 100644 packages/grpc-js-xds/src/generated/xds/annotations/v3/FieldStatusAnnotation.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/annotations/v3/FileStatusAnnotation.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/annotations/v3/MessageStatusAnnotation.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/annotations/v3/PackageVersionStatus.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/annotations/v3/StatusAnnotation.ts create mode 100644 packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts diff --git a/.gitmodules b/.gitmodules index d3c1ebaf6..f54fa6afc 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,12 +10,12 @@ [submodule "packages/grpc-js-xds/deps/envoy-api"] path = packages/grpc-js-xds/deps/envoy-api url = https://github.com/envoyproxy/data-plane-api.git -[submodule "packages/grpc-js-xds/deps/udpa"] - path = packages/grpc-js-xds/deps/udpa - url = https://github.com/cncf/udpa.git [submodule "packages/grpc-js-xds/deps/googleapis"] path = packages/grpc-js-xds/deps/googleapis url = https://github.com/googleapis/googleapis.git [submodule "packages/grpc-js-xds/deps/protoc-gen-validate"] path = packages/grpc-js-xds/deps/protoc-gen-validate url = https://github.com/envoyproxy/protoc-gen-validate.git +[submodule "packages/grpc-js-xds/deps/xds"] + path = packages/grpc-js-xds/deps/xds + url = https://github.com/cncf/xds.git diff --git a/packages/grpc-js-xds/deps/udpa b/packages/grpc-js-xds/deps/udpa deleted file mode 160000 index cc1b757b3..000000000 --- a/packages/grpc-js-xds/deps/udpa +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cc1b757b3eddccaaaf0743cbb107742bb7e3ee4f diff --git a/packages/grpc-js-xds/deps/xds b/packages/grpc-js-xds/deps/xds new file mode 160000 index 000000000..cb28da345 --- /dev/null +++ b/packages/grpc-js-xds/deps/xds @@ -0,0 +1 @@ +Subproject commit cb28da3451f158a947dfc45090fe92b07b243bc1 diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index fefc0f33b..9be41a0a4 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/udpa/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { diff --git a/packages/grpc-js-xds/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts index bc4465a30..6c2f7aa6f 100644 --- a/packages/grpc-js-xds/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -189,6 +189,15 @@ export interface ProtoGrpcType { UInt64Rules: MessageTypeDefinition } xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } core: { v3: { Authority: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/fault.ts b/packages/grpc-js-xds/src/generated/fault.ts index 6eefcdfbd..0f60fc224 100644 --- a/packages/grpc-js-xds/src/generated/fault.ts +++ b/packages/grpc-js-xds/src/generated/fault.ts @@ -210,6 +210,15 @@ export interface ProtoGrpcType { UInt64Rules: MessageTypeDefinition } xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } core: { v3: { Authority: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index 028e14b74..91af8a985 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -3,6 +3,7 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; +import type { FieldStatusAnnotation as _xds_annotations_v3_FieldStatusAnnotation, FieldStatusAnnotation__Output as _xds_annotations_v3_FieldStatusAnnotation__Output } from '../../xds/annotations/v3/FieldStatusAnnotation'; // Original file: null @@ -32,6 +33,7 @@ export interface FieldOptions { '.udpa.annotations.sensitive'?: (boolean); '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation | null); '.envoy.annotations.disallowed_by_default'?: (boolean); + '.xds.annotations.v3.field_status'?: (_xds_annotations_v3_FieldStatusAnnotation | null); } export interface FieldOptions__Output { @@ -46,4 +48,5 @@ export interface FieldOptions__Output { '.udpa.annotations.sensitive': (boolean); '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output | null); '.envoy.annotations.disallowed_by_default': (boolean); + '.xds.annotations.v3.field_status': (_xds_annotations_v3_FieldStatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts index b046c3ad3..48a376cd0 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FileOptions.ts @@ -3,6 +3,7 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FileMigrateAnnotation as _udpa_annotations_FileMigrateAnnotation, FileMigrateAnnotation__Output as _udpa_annotations_FileMigrateAnnotation__Output } from '../../udpa/annotations/FileMigrateAnnotation'; import type { StatusAnnotation as _udpa_annotations_StatusAnnotation, StatusAnnotation__Output as _udpa_annotations_StatusAnnotation__Output } from '../../udpa/annotations/StatusAnnotation'; +import type { FileStatusAnnotation as _xds_annotations_v3_FileStatusAnnotation, FileStatusAnnotation__Output as _xds_annotations_v3_FileStatusAnnotation__Output } from '../../xds/annotations/v3/FileStatusAnnotation'; // Original file: null @@ -30,6 +31,7 @@ export interface FileOptions { 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.udpa.annotations.file_migrate'?: (_udpa_annotations_FileMigrateAnnotation | null); '.udpa.annotations.file_status'?: (_udpa_annotations_StatusAnnotation | null); + '.xds.annotations.v3.file_status'?: (_xds_annotations_v3_FileStatusAnnotation | null); } export interface FileOptions__Output { @@ -50,4 +52,5 @@ export interface FileOptions__Output { 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.udpa.annotations.file_migrate': (_udpa_annotations_FileMigrateAnnotation__Output | null); '.udpa.annotations.file_status': (_udpa_annotations_StatusAnnotation__Output | null); + '.xds.annotations.v3.file_status': (_xds_annotations_v3_FileStatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts index 9dc521214..71d8c855b 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MessageOptions.ts @@ -3,6 +3,7 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { VersioningAnnotation as _udpa_annotations_VersioningAnnotation, VersioningAnnotation__Output as _udpa_annotations_VersioningAnnotation__Output } from '../../udpa/annotations/VersioningAnnotation'; import type { MigrateAnnotation as _udpa_annotations_MigrateAnnotation, MigrateAnnotation__Output as _udpa_annotations_MigrateAnnotation__Output } from '../../udpa/annotations/MigrateAnnotation'; +import type { MessageStatusAnnotation as _xds_annotations_v3_MessageStatusAnnotation, MessageStatusAnnotation__Output as _xds_annotations_v3_MessageStatusAnnotation__Output } from '../../xds/annotations/v3/MessageStatusAnnotation'; export interface MessageOptions { 'messageSetWireFormat'?: (boolean); @@ -13,6 +14,7 @@ export interface MessageOptions { '.validate.disabled'?: (boolean); '.udpa.annotations.versioning'?: (_udpa_annotations_VersioningAnnotation | null); '.udpa.annotations.message_migrate'?: (_udpa_annotations_MigrateAnnotation | null); + '.xds.annotations.v3.message_status'?: (_xds_annotations_v3_MessageStatusAnnotation | null); } export interface MessageOptions__Output { @@ -24,4 +26,5 @@ export interface MessageOptions__Output { '.validate.disabled': (boolean); '.udpa.annotations.versioning': (_udpa_annotations_VersioningAnnotation__Output | null); '.udpa.annotations.message_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); + '.xds.annotations.v3.message_status': (_xds_annotations_v3_MessageStatusAnnotation__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts index bb4e80360..351e65400 100644 --- a/packages/grpc-js-xds/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -250,6 +250,15 @@ export interface ProtoGrpcType { UInt64Rules: MessageTypeDefinition } xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } core: { v3: { Authority: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts index cf7297a5b..aac080a90 100644 --- a/packages/grpc-js-xds/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -228,6 +228,15 @@ export interface ProtoGrpcType { UInt64Rules: MessageTypeDefinition } xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } core: { v3: { Authority: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts index 702395d19..67b9c5ce4 100644 --- a/packages/grpc-js-xds/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -192,6 +192,15 @@ export interface ProtoGrpcType { UInt64Rules: MessageTypeDefinition } xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } core: { v3: { Authority: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/typed_struct.ts b/packages/grpc-js-xds/src/generated/typed_struct.ts index 47abe063c..e8dca13d5 100644 --- a/packages/grpc-js-xds/src/generated/typed_struct.ts +++ b/packages/grpc-js-xds/src/generated/typed_struct.ts @@ -70,5 +70,12 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + type: { + v3: { + TypedStruct: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts index 1ad015b25..4cbe9fdcb 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldMigrateAnnotation.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/migrate.proto +// Original file: deps/xds/udpa/annotations/migrate.proto export interface FieldMigrateAnnotation { diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts index 13d48b5ce..9c25fb84e 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/FieldSecurityAnnotation.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/security.proto +// Original file: deps/xds/udpa/annotations/security.proto /** diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts index b7ef7c21d..95d29245d 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/FileMigrateAnnotation.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/migrate.proto +// Original file: deps/xds/udpa/annotations/migrate.proto export interface FileMigrateAnnotation { diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts index e3fdcaa99..16def9f28 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/MigrateAnnotation.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/migrate.proto +// Original file: deps/xds/udpa/annotations/migrate.proto export interface MigrateAnnotation { diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts index c60c3f984..d0e181aa5 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/PackageVersionStatus.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/status.proto +// Original file: deps/xds/udpa/annotations/status.proto export enum PackageVersionStatus { /** diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts index 7b33ce9c8..f01b45063 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/StatusAnnotation.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/status.proto +// Original file: deps/xds/udpa/annotations/status.proto import type { PackageVersionStatus as _udpa_annotations_PackageVersionStatus } from '../../udpa/annotations/PackageVersionStatus'; diff --git a/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts b/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts index 1a3d09dc8..7a517a06c 100644 --- a/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts +++ b/packages/grpc-js-xds/src/generated/udpa/annotations/VersioningAnnotation.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/annotations/versioning.proto +// Original file: deps/xds/udpa/annotations/versioning.proto export interface VersioningAnnotation { diff --git a/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts b/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts index 435872808..b080c6348 100644 --- a/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts +++ b/packages/grpc-js-xds/src/generated/udpa/type/v1/TypedStruct.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/udpa/type/v1/typed_struct.proto +// Original file: deps/xds/udpa/type/v1/typed_struct.proto import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; diff --git a/packages/grpc-js-xds/src/generated/xds/annotations/v3/FieldStatusAnnotation.ts b/packages/grpc-js-xds/src/generated/xds/annotations/v3/FieldStatusAnnotation.ts new file mode 100644 index 000000000..744e13837 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/annotations/v3/FieldStatusAnnotation.ts @@ -0,0 +1,16 @@ +// Original file: deps/xds/xds/annotations/v3/status.proto + + +export interface FieldStatusAnnotation { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress'?: (boolean); +} + +export interface FieldStatusAnnotation__Output { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/xds/annotations/v3/FileStatusAnnotation.ts b/packages/grpc-js-xds/src/generated/xds/annotations/v3/FileStatusAnnotation.ts new file mode 100644 index 000000000..cbc3ab3f9 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/annotations/v3/FileStatusAnnotation.ts @@ -0,0 +1,16 @@ +// Original file: deps/xds/xds/annotations/v3/status.proto + + +export interface FileStatusAnnotation { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress'?: (boolean); +} + +export interface FileStatusAnnotation__Output { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/xds/annotations/v3/MessageStatusAnnotation.ts b/packages/grpc-js-xds/src/generated/xds/annotations/v3/MessageStatusAnnotation.ts new file mode 100644 index 000000000..f403f6506 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/annotations/v3/MessageStatusAnnotation.ts @@ -0,0 +1,16 @@ +// Original file: deps/xds/xds/annotations/v3/status.proto + + +export interface MessageStatusAnnotation { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress'?: (boolean); +} + +export interface MessageStatusAnnotation__Output { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/xds/annotations/v3/PackageVersionStatus.ts b/packages/grpc-js-xds/src/generated/xds/annotations/v3/PackageVersionStatus.ts new file mode 100644 index 000000000..e76e2848f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/annotations/v3/PackageVersionStatus.ts @@ -0,0 +1,21 @@ +// Original file: deps/xds/xds/annotations/v3/status.proto + +export enum PackageVersionStatus { + /** + * Unknown package version status. + */ + UNKNOWN = 0, + /** + * This version of the package is frozen. + */ + FROZEN = 1, + /** + * This version of the package is the active development version. + */ + ACTIVE = 2, + /** + * This version of the package is the candidate for the next major version. It + * is typically machine generated from the active development version. + */ + NEXT_MAJOR_VERSION_CANDIDATE = 3, +} diff --git a/packages/grpc-js-xds/src/generated/xds/annotations/v3/StatusAnnotation.ts b/packages/grpc-js-xds/src/generated/xds/annotations/v3/StatusAnnotation.ts new file mode 100644 index 000000000..58efbd8f7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/annotations/v3/StatusAnnotation.ts @@ -0,0 +1,25 @@ +// Original file: deps/xds/xds/annotations/v3/status.proto + +import type { PackageVersionStatus as _xds_annotations_v3_PackageVersionStatus } from '../../../xds/annotations/v3/PackageVersionStatus'; + +export interface StatusAnnotation { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress'?: (boolean); + /** + * The entity belongs to a package with the given version status. + */ + 'package_version_status'?: (_xds_annotations_v3_PackageVersionStatus | keyof typeof _xds_annotations_v3_PackageVersionStatus); +} + +export interface StatusAnnotation__Output { + /** + * The entity is work-in-progress and subject to breaking changes. + */ + 'work_in_progress': (boolean); + /** + * The entity belongs to a package with the given version status. + */ + 'package_version_status': (keyof typeof _xds_annotations_v3_PackageVersionStatus); +} diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts index 8e9211838..9505731d7 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/Authority.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/xds/core/v3/authority.proto +// Original file: deps/xds/xds/core/v3/authority.proto /** diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts index 8d583d961..5d2ce9721 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/CollectionEntry.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/xds/core/v3/collection_entry.proto +// Original file: deps/xds/xds/core/v3/collection_entry.proto import type { ResourceLocator as _xds_core_v3_ResourceLocator, ResourceLocator__Output as _xds_core_v3_ResourceLocator__Output } from '../../../xds/core/v3/ResourceLocator'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts index f9c57249c..19a8a99bb 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/ContextParams.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/xds/core/v3/context_params.proto +// Original file: deps/xds/xds/core/v3/context_params.proto /** diff --git a/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts b/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts index 2b314d8bb..bb1f822b8 100644 --- a/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts +++ b/packages/grpc-js-xds/src/generated/xds/core/v3/ResourceLocator.ts @@ -1,4 +1,4 @@ -// Original file: deps/udpa/xds/core/v3/resource_locator.proto +// Original file: deps/xds/xds/core/v3/resource_locator.proto import type { ContextParams as _xds_core_v3_ContextParams, ContextParams__Output as _xds_core_v3_ContextParams__Output } from '../../../xds/core/v3/ContextParams'; import type { ResourceLocator as _xds_core_v3_ResourceLocator, ResourceLocator__Output as _xds_core_v3_ResourceLocator__Output } from '../../../xds/core/v3/ResourceLocator'; @@ -95,7 +95,7 @@ export interface _xds_core_v3_ResourceLocator_Directive__Output { 'directive': "alt"|"entry"; } -// Original file: deps/udpa/xds/core/v3/resource_locator.proto +// Original file: deps/xds/xds/core/v3/resource_locator.proto export enum _xds_core_v3_ResourceLocator_Scheme { XDSTP = 0, diff --git a/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts b/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts new file mode 100644 index 000000000..a0df831d2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/xds/type/v3/TypedStruct.ts @@ -0,0 +1,77 @@ +// Original file: deps/xds/xds/type/v3/typed_struct.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../google/protobuf/Struct'; + +/** + * A TypedStruct contains an arbitrary JSON serialized protocol buffer message with a URL that + * describes the type of the serialized message. This is very similar to google.protobuf.Any, + * instead of having protocol buffer binary, this employs google.protobuf.Struct as value. + * + * This message is intended to be embedded inside Any, so it shouldn't be directly referred + * from other UDPA messages. + * + * When packing an opaque extension config, packing the expected type into Any is preferred + * wherever possible for its efficiency. TypedStruct should be used only if a proto descriptor + * is not available, for example if: + * - A control plane sends opaque message that is originally from external source in human readable + * format such as JSON or YAML. + * - The control plane doesn't have the knowledge of the protocol buffer schema hence it cannot + * serialize the message in protocol buffer binary format. + * - The DPLB doesn't have have the knowledge of the protocol buffer schema its plugin or extension + * uses. This has to be indicated in the DPLB capability negotiation. + * + * When a DPLB receives a TypedStruct in Any, it should: + * - Check if the type_url of the TypedStruct matches the type the extension expects. + * - Convert value to the type described in type_url and perform validation. + * TODO(lizan): Figure out how TypeStruct should be used with DPLB extensions that doesn't link + * protobuf descriptor with DPLB itself, (e.g. gRPC LB Plugin, Envoy WASM extensions). + */ +export interface TypedStruct { + /** + * A URL that uniquely identifies the type of the serialize protocol buffer message. + * This has same semantics and format described in google.protobuf.Any: + * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto + */ + 'type_url'?: (string); + /** + * A JSON representation of the above specified type. + */ + 'value'?: (_google_protobuf_Struct | null); +} + +/** + * A TypedStruct contains an arbitrary JSON serialized protocol buffer message with a URL that + * describes the type of the serialized message. This is very similar to google.protobuf.Any, + * instead of having protocol buffer binary, this employs google.protobuf.Struct as value. + * + * This message is intended to be embedded inside Any, so it shouldn't be directly referred + * from other UDPA messages. + * + * When packing an opaque extension config, packing the expected type into Any is preferred + * wherever possible for its efficiency. TypedStruct should be used only if a proto descriptor + * is not available, for example if: + * - A control plane sends opaque message that is originally from external source in human readable + * format such as JSON or YAML. + * - The control plane doesn't have the knowledge of the protocol buffer schema hence it cannot + * serialize the message in protocol buffer binary format. + * - The DPLB doesn't have have the knowledge of the protocol buffer schema its plugin or extension + * uses. This has to be indicated in the DPLB capability negotiation. + * + * When a DPLB receives a TypedStruct in Any, it should: + * - Check if the type_url of the TypedStruct matches the type the extension expects. + * - Convert value to the type described in type_url and perform validation. + * TODO(lizan): Figure out how TypeStruct should be used with DPLB extensions that doesn't link + * protobuf descriptor with DPLB itself, (e.g. gRPC LB Plugin, Envoy WASM extensions). + */ +export interface TypedStruct__Output { + /** + * A URL that uniquely identifies the type of the serialize protocol buffer message. + * This has same semantics and format described in google.protobuf.Any: + * https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto + */ + 'type_url': (string); + /** + * A JSON representation of the above specified type. + */ + 'value': (_google_protobuf_Struct__Output | null); +} diff --git a/packages/grpc-js-xds/src/http-filter.ts b/packages/grpc-js-xds/src/http-filter.ts index a00cde5db..29ce5958f 100644 --- a/packages/grpc-js-xds/src/http-filter.ts +++ b/packages/grpc-js-xds/src/http-filter.ts @@ -20,7 +20,7 @@ import { experimental, logVerbosity } from '@grpc/grpc-js'; import { Any__Output } from './generated/google/protobuf/Any'; import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; -import { TypedStruct__Output } from './generated/udpa/type/v1/TypedStruct'; +import { TypedStruct__Output as TypedStruct__Output } from './generated/xds/type/v3/TypedStruct'; import { FilterConfig__Output } from './generated/envoy/config/route/v3/FilterConfig'; import { HttpFilter__Output } from './generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter'; @@ -30,19 +30,22 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } -const TYPED_STRUCT_URL = 'type.googleapis.com/udpa.type.v1.TypedStruct'; -const TYPED_STRUCT_NAME = 'udpa.type.v1.TypedStruct'; +const TYPED_STRUCT_UDPA_URL = 'type.googleapis.com/udpa.type.v1.TypedStruct'; +const TYPED_STRUCT_UDPA_NAME = 'udpa.type.v1.TypedStruct'; +const TYPED_STRUCT_XDS_URL = 'type.googleapis.com/xds.type.v3.TypedStruct'; +const TYPED_STRUCT_XDS_NAME = 'xds.type.v3.TypedStruct'; const FILTER_CONFIG_URL = 'type.googleapis.com/envoy.config.route.v3.FilterConfig'; const FILTER_CONFIG_NAME = 'envoy.config.route.v3.FilterConfig'; const resourceRoot = loadProtosWithOptionsSync([ 'udpa/type/v1/typed_struct.proto', + 'xds/type/v3/typed_struct.proto', 'envoy/config/route/v3/route_components.proto'], { keepCase: true, includeDirs: [ // Paths are relative to src/build - __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/xds/', __dirname + '/../../deps/envoy-api/', __dirname + '/../../deps/protoc-gen-validate/' ], @@ -91,7 +94,7 @@ function parseAnyMessage(message: Any__Output): MessageType | null export function getTopLevelFilterUrl(encodedConfig: Any__Output): string { let typeUrl: string; - if (encodedConfig.type_url === TYPED_STRUCT_URL) { + if (encodedConfig.type_url === TYPED_STRUCT_UDPA_URL || encodedConfig.type_url === TYPED_STRUCT_XDS_URL) { const typedStruct = parseAnyMessage(encodedConfig) if (typedStruct) { return typedStruct.type_url; @@ -154,7 +157,7 @@ export function validateOverrideFilter(encodedConfig: Any__Output): boolean { } else { realConfig = encodedConfig; } - if (realConfig.type_url === TYPED_STRUCT_URL) { + if (realConfig.type_url === TYPED_STRUCT_UDPA_URL || realConfig.type_url === TYPED_STRUCT_XDS_URL) { const typedStruct = parseAnyMessage(encodedConfig); if (typedStruct) { typeUrl = typedStruct.type_url; @@ -215,7 +218,7 @@ export function parseOverrideFilterConfig(encodedConfig: Any__Output) { } else { realConfig = encodedConfig; } - if (realConfig.type_url === TYPED_STRUCT_URL) { + if (realConfig.type_url === TYPED_STRUCT_UDPA_URL || realConfig.type_url === TYPED_STRUCT_XDS_URL) { const typedStruct = parseAnyMessage(encodedConfig); if (typedStruct) { typeUrl = typedStruct.type_url; diff --git a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts index e0ee658c7..a49ec77d4 100644 --- a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts +++ b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts @@ -38,7 +38,7 @@ const resourceRoot = loadProtosWithOptionsSync([ keepCase: true, includeDirs: [ // Paths are relative to src/build/http-filter - __dirname + '/../../../deps/udpa/', + __dirname + '/../../../deps/xds/', __dirname + '/../../../deps/envoy-api/', __dirname + '/../../../deps/protoc-gen-validate/' ], diff --git a/packages/grpc-js-xds/src/resources.ts b/packages/grpc-js-xds/src/resources.ts index 516980de8..4a7e22763 100644 --- a/packages/grpc-js-xds/src/resources.ts +++ b/packages/grpc-js-xds/src/resources.ts @@ -70,7 +70,7 @@ const resourceRoot = loadProtosWithOptionsSync([ includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', - __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/xds/', __dirname + '/../../deps/googleapis/', __dirname + '/../../deps/protoc-gen-validate/', ], diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 2b8fae44c..8a08276eb 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -87,7 +87,7 @@ function loadAdsProtos(): Promise< includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', - __dirname + '/../../deps/udpa/', + __dirname + '/../../deps/xds/', __dirname + '/../../deps/googleapis/', __dirname + '/../../deps/protoc-gen-validate/', ], From 3c48058d9a2c5c95d5fc88d54f55221a56c7aea5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 1 Nov 2021 16:09:49 -0700 Subject: [PATCH 1557/1899] grpc-js-xds: Update files list to account for submodule change --- packages/grpc-js-xds/package.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 9be41a0a4..fca6ab80d 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -63,7 +63,11 @@ "deps/googleapis/google/api/**/*.proto", "deps/googleapis/google/protobuf/**/*.proto", "deps/googleapis/google/rpc/**/*.proto", - "deps/udpa/udpa/annotations/**/*.proto", + "deps/xds/udpa/annotations/**/*.proto", + "deps/xds/udpa/type/**/*.proto", + "deps/xds/xds/annotations/**/*.proto", + "deps/xds/xds/core/**/*.proto", + "deps/xds/xds/type/**/*.proto", "deps/protoc-gen-validate/validate/**/*.proto" ] } From 5c61a6a34e375eebbab1cd399de7a0b805916a4c Mon Sep 17 00:00:00 2001 From: Robert M Date: Mon, 1 Nov 2021 18:38:37 -0700 Subject: [PATCH 1558/1899] Update packages/grpc-js/src/server-call.ts Co-authored-by: Michael Lumish --- packages/grpc-js/src/server-call.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index b340b3446..24028c073 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -485,7 +485,7 @@ export class Http2ServerCallStream< default: { this.sendError({ code: Status.UNIMPLEMENTED, - details: `Received "grpc-encoding" header "${encoding}", which is not supported`, + details: `Received message compressed with unsupported encoding "${encoding}"`, }); return Promise.resolve(); } From dc9752addcd70785f26f1cde17404c7a4b2ae47f Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 1 Nov 2021 19:04:21 -0700 Subject: [PATCH 1559/1899] change CompressionAlgorithms to an enum --- packages/grpc-js/src/channel-options.ts | 2 +- packages/grpc-js/src/compression-algorithms.ts | 10 +++++----- packages/grpc-js/src/compression-filter.ts | 10 ++++------ 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index b54ae4eda..e10e92758 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -38,7 +38,7 @@ export interface ChannelOptions { 'grpc.enable_http_proxy'?: number; 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; - 'grpc.default_compression_algorithm'?: keyof typeof CompressionAlgorithms; + 'grpc.default_compression_algorithm'?: CompressionAlgorithms; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; diff --git a/packages/grpc-js/src/compression-algorithms.ts b/packages/grpc-js/src/compression-algorithms.ts index ccc38e76b..ca2c7a624 100644 --- a/packages/grpc-js/src/compression-algorithms.ts +++ b/packages/grpc-js/src/compression-algorithms.ts @@ -15,8 +15,8 @@ * */ -export const CompressionAlgorithms = { - 0: 'identity', - 1: 'deflate', - 2: 'gzip' -} as const; +export enum CompressionAlgorithms { + identity = 0, + deflate = 1, + gzip = 2 +}; diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index cbdd35104..de35dd44a 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -26,13 +26,11 @@ import { BaseFilter, Filter, FilterFactory } from './filter'; import * as logging from './logging'; import { Metadata, MetadataValue } from './metadata'; -const CompressionAlgorithKeys = new Set(Object.keys(CompressionAlgorithms)); - -const isCompressionAlgorithmKey = (key: number | undefined): key is keyof typeof CompressionAlgorithms => { - return typeof key === 'number' && CompressionAlgorithKeys.has(key.toString()); +const isCompressionAlgorithmKey = (key: number): key is CompressionAlgorithms => { + return typeof key === 'number' && typeof CompressionAlgorithms[key] === 'string'; } -type CompressionAlgorithm = (typeof CompressionAlgorithms)[keyof typeof CompressionAlgorithms]; +type CompressionAlgorithm = keyof typeof CompressionAlgorithms; type SharedCompressionFilterConfig = { serverSupportedEncodingHeader?: string; @@ -191,7 +189,7 @@ export class CompressionFilter extends BaseFilter implements Filter { const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; if (compressionAlgorithmKey !== undefined) { if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { - const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey]; + const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey] as CompressionAlgorithm; const serverSupportedEncodings = sharedFilterConfig.serverSupportedEncodingHeader?.split(','); /** * There are two possible situations here: From c4d7fab13ea8a18e3bcf6b57bfb3220177ff2006 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 2 Nov 2021 19:17:44 -0700 Subject: [PATCH 1560/1899] simplify compression filter handling of server supported encoding headers --- packages/grpc-js/src/compression-filter.ts | 8 ++++---- packages/grpc-js/test/test-server.ts | 5 +++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index de35dd44a..40825467e 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -240,10 +240,10 @@ export class CompressionFilter extends BaseFilter implements Filter { this.sharedFilterConfig.serverSupportedEncodingHeader = serverSupportedEncodingsHeader; const serverSupportedEncodings = serverSupportedEncodingsHeader.split(','); - if ((this.sendCompression instanceof DeflateHandler && !serverSupportedEncodings.includes('deflate')) - || (this.sendCompression instanceof GzipHandler && !serverSupportedEncodings.includes('gzip'))) { - this.sendCompression = new IdentityHandler(); - } + if (!serverSupportedEncodings.includes(this.currentCompressionAlgorithm)) { + this.sendCompression = new IdentityHandler(); + this.currentCompressionAlgorithm = 'identity'; + } } metadata.remove('grpc-accept-encoding'); return metadata; diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index c0e7ebf5f..cc20164a4 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -33,6 +33,7 @@ import { loadProtoFile } from './common'; import { TestServiceClient, TestServiceHandlers } from './generated/TestService'; import { ProtoGrpcType as TestServiceGrpcType } from './generated/test_service'; import { Request__Output } from './generated/Request'; +import { CompressionAlgorithms } from '../src/compression-algorithms'; const loadedTestServiceProto = protoLoader.loadSync('test/fixtures/test_service.proto', { keepCase: true, @@ -683,7 +684,7 @@ describe('Compressed requests', () => { `localhost:${assignedPort}`, grpc.credentials.createInsecure(), { - 'grpc.default_compression_algorithm': 1 + 'grpc.default_compression_algorithm': CompressionAlgorithms.deflate } ); done(); @@ -774,7 +775,7 @@ describe('Compressed requests', () => { `localhost:${assignedPort}`, grpc.credentials.createInsecure(), { - 'grpc.default_compression_algorithm': 2 + 'grpc.default_compression_algorithm': CompressionAlgorithms.gzip } ); From 1a60c4f3a92d6c0559422666ec446bdc3b0f70a3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Nov 2021 14:11:16 -0700 Subject: [PATCH 1561/1899] grpc-js: channelz: Fix algorithm for representing an IPv6 address in binary --- packages/grpc-js/src/channelz.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 768efaa58..94d84d8f2 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -392,6 +392,16 @@ export function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRe } } +/** + * Parses a single section of an IPv6 address as two bytes + * @param addressSection A hexadecimal string of length up to 4 + * @returns The pair of bytes representing this address section + */ +function parseIPv6Section(addressSection: string): [number, number] { + const numberValue = Number.parseInt(addressSection, 16); + return [numberValue / 256 | 0, numberValue % 256]; +} + /** * Converts an IPv4 or IPv6 address from string representation to binary * representation @@ -412,8 +422,8 @@ function ipAddressStringToBuffer(ipAddress: string): Buffer | null { leftSection = ipAddress.substring(0, doubleColonIndex); rightSection = ipAddress.substring(doubleColonIndex + 2); } - const leftBuffer = Uint8Array.from(leftSection.split(':').map(segment => Number.parseInt(segment, 16))); - const rightBuffer = rightSection ? Uint8Array.from(rightSection.split(':').map(segment => Number.parseInt(segment, 16))) : new Uint8Array(); + const leftBuffer = Buffer.from(leftSection.split(':').map(segment => parseIPv6Section(segment)).flat()); + const rightBuffer = rightSection ? Buffer.from(rightSection.split(':').map(segment => parseIPv6Section(segment)).flat()) : Buffer.alloc(0); const middleBuffer = Buffer.alloc(16 - leftBuffer.length - rightBuffer.length, 0); return Buffer.concat([leftBuffer, middleBuffer, rightBuffer]); } else { From bb26dcfd1ef1019af887e4a76c72262bc26a5378 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 5 Nov 2021 10:11:22 -0700 Subject: [PATCH 1562/1899] grpc-js: Fix handling of grpc.enable_channelz option --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 11 +++++++-- packages/grpc-js/test/test-channelz.ts | 32 ++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 4acf948df..69d0662b7 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.2", + "version": "1.4.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 0b6465b2e..87defa740 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -832,6 +832,7 @@ export class Subchannel { headersString ); const streamSession = this.session; + let statsTracker: SubchannelCallStatsTracker; if (this.channelzEnabled) { this.callTracker.addCallStarted(); callStream.addStatusWatcher(status => { @@ -851,7 +852,7 @@ export class Subchannel { } } }); - callStream.attachHttp2Stream(http2Stream, this, extraFilters, { + statsTracker = { addMessageSent: () => { this.messagesSent += 1; this.lastMessageSentTimestamp = new Date(); @@ -859,8 +860,14 @@ export class Subchannel { addMessageReceived: () => { this.messagesReceived += 1; } - }); + } + } else { + statsTracker = { + addMessageSent: () => {}, + addMessageReceived: () => {} + } } + callStream.attachHttp2Stream(http2Stream, this, extraFilters, statsTracker); } /** diff --git a/packages/grpc-js/test/test-channelz.ts b/packages/grpc-js/test/test-channelz.ts index 2cca780e8..f14145c37 100644 --- a/packages/grpc-js/test/test-channelz.ts +++ b/packages/grpc-js/test/test-channelz.ts @@ -286,4 +286,36 @@ describe('Channelz', () => { }); }); }); +}); + +describe('Disabling channelz', () => { + let testServer: grpc.Server; + let testClient: ServiceClient; + beforeEach((done) => { + testServer = new grpc.Server({'grpc.enable_channelz': 0}); + testServer.addService(TestServiceClient.service, testServiceImpl); + testServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + done(error); + return; + } + testServer.start(); + testClient = new TestServiceClient(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.enable_channelz': 0}); + done(); + }); + }); + + afterEach(() => { + testClient.close(); + testServer.forceShutdown(); + }); + + it('Should still work', (done) => { + const deadline = new Date(); + deadline.setSeconds(deadline.getSeconds() + 1); + testClient.unary({}, {deadline}, (error: grpc.ServiceError, value: unknown) => { + assert.ifError(error); + done(); + }); + }); }); \ No newline at end of file From b1be84a0214ed140e3c58d8624c11c5756223376 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 5 Nov 2021 11:54:15 -0700 Subject: [PATCH 1563/1899] Make IPv6 parsing code compatible with Node 10 --- packages/grpc-js/src/channelz.ts | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 94d84d8f2..14c94fd0c 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -393,7 +393,7 @@ export function unregisterChannelzRef(ref: ChannelRef | SubchannelRef | ServerRe } /** - * Parses a single section of an IPv6 address as two bytes + * Parse a single section of an IPv6 address as two bytes * @param addressSection A hexadecimal string of length up to 4 * @returns The pair of bytes representing this address section */ @@ -402,6 +402,21 @@ function parseIPv6Section(addressSection: string): [number, number] { return [numberValue / 256 | 0, numberValue % 256]; } +/** + * Parse a chunk of an IPv6 address string to some number of bytes + * @param addressChunk Some number of segments of up to 4 hexadecimal + * characters each, joined by colons. + * @returns The list of bytes representing this address chunk + */ +function parseIPv6Chunk(addressChunk: string): number[] { + if (addressChunk === '') { + return []; + } + const bytePairs = addressChunk.split(':').map(section => parseIPv6Section(section)); + const result: number[] = []; + return result.concat(...bytePairs); +} + /** * Converts an IPv4 or IPv6 address from string representation to binary * representation @@ -413,17 +428,17 @@ function ipAddressStringToBuffer(ipAddress: string): Buffer | null { return Buffer.from(Uint8Array.from(ipAddress.split('.').map(segment => Number.parseInt(segment)))); } else if (isIPv6(ipAddress)) { let leftSection: string; - let rightSection: string | null; + let rightSection: string; const doubleColonIndex = ipAddress.indexOf('::'); if (doubleColonIndex === -1) { leftSection = ipAddress; - rightSection = null; + rightSection = ''; } else { leftSection = ipAddress.substring(0, doubleColonIndex); rightSection = ipAddress.substring(doubleColonIndex + 2); } - const leftBuffer = Buffer.from(leftSection.split(':').map(segment => parseIPv6Section(segment)).flat()); - const rightBuffer = rightSection ? Buffer.from(rightSection.split(':').map(segment => parseIPv6Section(segment)).flat()) : Buffer.alloc(0); + const leftBuffer = Buffer.from(parseIPv6Chunk(leftSection)); + const rightBuffer = Buffer.from(parseIPv6Chunk(rightSection)); const middleBuffer = Buffer.alloc(16 - leftBuffer.length - rightBuffer.length, 0); return Buffer.concat([leftBuffer, middleBuffer, rightBuffer]); } else { From 96ae102eaf82e2094556a13539faa4f9a9edcabe Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 5 Nov 2021 19:59:03 -0700 Subject: [PATCH 1564/1899] fix path for loading test_service proto --- packages/grpc-js/test/test-server.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index cc20164a4..a5f7ec80b 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -35,15 +35,12 @@ import { ProtoGrpcType as TestServiceGrpcType } from './generated/test_service'; import { Request__Output } from './generated/Request'; import { CompressionAlgorithms } from '../src/compression-algorithms'; -const loadedTestServiceProto = protoLoader.loadSync('test/fixtures/test_service.proto', { +const loadedTestServiceProto = protoLoader.loadSync(path.join(__dirname, 'fixtures/test_service.proto'), { keepCase: true, longs: String, enums: String, defaults: true, - oneofs: true, - includeDirs: [ - `${__dirname}/../../proto` - ] + oneofs: true }); const testServiceGrpcObject = grpc.loadPackageDefinition(loadedTestServiceProto) as unknown as TestServiceGrpcType; From af966f04b864a811c7a38df26ca683af78c1a02f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Nov 2021 09:44:11 -0800 Subject: [PATCH 1565/1899] grpc-js: Remove an extra call to registerChannelzSocket --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 69d0662b7..e14ffa0eb 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.3", + "version": "1.4.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 87defa740..6f9471bb9 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -555,7 +555,6 @@ export class Subchannel { (error as Error).message ); }); - registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!); } private startConnectingInternal() { From 69428b04457f0e9337e38072bc88932585855768 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 9 Nov 2021 21:26:54 -0800 Subject: [PATCH 1566/1899] simplify removal of compression prefix bytes --- packages/grpc-js/src/server-call.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 24028c073..709d20d41 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -454,8 +454,7 @@ export class Http2ServerCallStream< }); resolve(); } else { - const joined = Buffer.concat([message.slice(0, 5), output]); - resolve(joined); + resolve(output); } }); }); @@ -471,15 +470,14 @@ export class Http2ServerCallStream< }); resolve(); } else { - const joined = Buffer.concat([message.slice(0, 5), output]); - resolve(joined); + resolve(output); } }); }); } case 'identity': { - return Promise.resolve(message); + return Promise.resolve(message.slice(5)); } default: { @@ -603,10 +601,7 @@ export class Http2ServerCallStream< } deserializeMessage(bytes: Buffer) { - // TODO(cjihrig): Call compression aware deserializeMessage(). - const receivedMessage = bytes.slice(5); - - return this.handler.deserialize(receivedMessage); + return this.handler.deserialize(bytes); } async sendUnaryMessage( From 4b20bf3fce00106b975752d6fd5e226b1f227000 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 15 Nov 2021 10:05:10 -0800 Subject: [PATCH 1567/1899] proto-loader: Fix generated types for callbacks --- .../bin/proto-loader-gen-types.ts | 2 +- .../google/longrunning/Operations.ts | 80 +++++++++---------- .../google/showcase/v1beta1/Echo.ts | 80 +++++++++---------- packages/proto-loader/package.json | 2 +- 4 files changed, 82 insertions(+), 82 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 6c9596980..3ecf6dcc4 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -503,7 +503,7 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P } const requestType = getTypeInterfaceName(method.resolvedRequestType!); const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; - const callbackType = `(error?: grpc.ServiceError, result?: ${responseType}) => void`; + const callbackType = `grpc.requestCallback<${responseType}>`; if (method.requestStream) { if (method.responseStream) { // Bidi streaming diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 7644f974d..6358cbbfd 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -35,10 +35,10 @@ export interface OperationsClient extends grpc.Client { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + CancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; /** * Starts asynchronous cancellation on a long-running operation. The server * makes a best effort to cancel the operation, but success is not @@ -51,10 +51,10 @@ export interface OperationsClient extends grpc.Client { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + cancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is @@ -62,39 +62,39 @@ export interface OperationsClient extends grpc.Client { * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is * no longer interested in the operation result. It does not cancel the * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_protobuf_Empty__Output) => void): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + deleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + GetOperation(argument: _google_longrunning_GetOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + getOperation(argument: _google_longrunning_GetOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; /** * Lists operations that match the specified filter in the request. If the @@ -108,10 +108,10 @@ export interface OperationsClient extends grpc.Client { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + ListOperations(argument: _google_longrunning_ListOperationsRequest, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; /** * Lists operations that match the specified filter in the request. If the * server doesn't support this method, it returns `UNIMPLEMENTED`. @@ -124,10 +124,10 @@ export interface OperationsClient extends grpc.Client { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_ListOperationsResponse__Output) => void): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + listOperations(argument: _google_longrunning_ListOperationsRequest, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches @@ -140,10 +140,10 @@ export interface OperationsClient extends grpc.Client { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + WaitOperation(argument: _google_longrunning_WaitOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches * at most a specified timeout, returning the latest state. If the operation @@ -155,10 +155,10 @@ export interface OperationsClient extends grpc.Client { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + waitOperation(argument: _google_longrunning_WaitOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index 8e75c6c1a..30ecc8e23 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -25,19 +25,19 @@ export interface EchoClient extends grpc.Client { * and then return the response or error. * This method showcases how a client handles delays or retries. */ - Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + Block(argument: _google_showcase_v1beta1_BlockRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; /** * This method will block (wait) for the requested amount of time * and then return the response or error. * This method showcases how a client handles delays or retries. */ - block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_BlockResponse__Output) => void): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + block(argument: _google_showcase_v1beta1_BlockRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; /** * This method, upon receiving a request on the stream, the same content will @@ -59,34 +59,34 @@ export interface EchoClient extends grpc.Client { * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - Collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - Collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - Collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - collect(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - collect(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - collect(callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; /** * This method simply echos the request. This method is showcases unary rpcs. */ - Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _google_showcase_v1beta1_EchoRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; /** * This method simply echos the request. This method is showcases unary rpcs. */ - echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_EchoResponse__Output) => void): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _google_showcase_v1beta1_EchoRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; /** * This method split the given content into words and will pass each word back @@ -105,35 +105,35 @@ export interface EchoClient extends grpc.Client { * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: (error?: grpc.ServiceError, result?: _google_showcase_v1beta1_PagedExpandResponse__Output) => void): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + Wait(argument: _google_showcase_v1beta1_WaitRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, callback: (error?: grpc.ServiceError, result?: _google_longrunning_Operation__Output) => void): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + wait(argument: _google_showcase_v1beta1_WaitRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; } diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index d31220186..cd27743a0 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.6", + "version": "0.6.7", "author": "Google Inc.", "contributors": [ { From 472baec1ff7d17ca8dbea409eb7a23d7820208bb Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 15 Nov 2021 10:53:31 -0800 Subject: [PATCH 1568/1899] grpc-js: Provide full certificate in checkServerIdentity callback --- packages/grpc-js/src/channel-credentials.ts | 25 +++++---------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 675e91628..c501692c9 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -27,16 +27,6 @@ function verifyIsBufferOrNull(obj: any, friendlyName: string): void { } } -/** - * A certificate as received by the checkServerIdentity callback. - */ -export interface Certificate { - /** - * The raw certificate in DER form. - */ - raw: Buffer; -} - /** * A callback that will receive the expected hostname and presented peer * certificate as parameters. The callback should return an error to @@ -45,7 +35,7 @@ export interface Certificate { */ export type CheckServerIdentityCallback = ( hostname: string, - cert: Certificate + cert: PeerCertificate ) => Error | undefined; function bufferOrNullEqual(buf1: Buffer | null, buf2: Buffer | null) { @@ -192,15 +182,10 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { cert: certChain || undefined, ciphers: CIPHER_SUITES, }); - this.connectionOptions = { secureContext }; - if (verifyOptions && verifyOptions.checkServerIdentity) { - this.connectionOptions.checkServerIdentity = ( - host: string, - cert: PeerCertificate - ) => { - return verifyOptions.checkServerIdentity!(host, { raw: cert.raw }); - }; - } + this.connectionOptions = { + secureContext, + checkServerIdentity: verifyOptions?.checkServerIdentity + }; } compose(callCredentials: CallCredentials): ChannelCredentials { From 3106057f5ad8f79a71d2ae411e116ad308a2e835 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Nov 2021 12:36:38 -0800 Subject: [PATCH 1569/1899] grpc-js: Don't pass undefined checkServerIdentity --- packages/grpc-js/src/channel-credentials.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index c501692c9..02c9c309b 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -183,9 +183,12 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { ciphers: CIPHER_SUITES, }); this.connectionOptions = { - secureContext, - checkServerIdentity: verifyOptions?.checkServerIdentity + secureContext }; + // Node asserts that this option is a function, so we cannot pass undefined + if (verifyOptions?.checkServerIdentity) { + this.connectionOptions.checkServerIdentity = verifyOptions.checkServerIdentity; + } } compose(callCredentials: CallCredentials): ChannelCredentials { From 8658fd5752cca9338210eb4544c6f76231fdcf51 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Nov 2021 12:48:40 -0800 Subject: [PATCH 1570/1899] grpc-js-xds: Remove LDS and CDS code for removing RDS and EDS entries --- .../src/xds-stream-state/cds-state.ts | 6 ------ .../src/xds-stream-state/eds-state.ts | 17 ----------------- .../src/xds-stream-state/lds-state.ts | 6 ------ .../src/xds-stream-state/rds-state.ts | 10 ---------- 4 files changed, 39 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 5dae09fb4..01e1db135 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -149,14 +149,9 @@ export class CdsState implements XdsStreamState { } this.latestResponses = validResponses; this.latestIsV2 = isV2; - const allEdsServiceNames: Set = new Set(); const allClusterNames: Set = new Set(); for (const message of validResponses) { allClusterNames.add(message.name); - const edsServiceName = message.eds_cluster_config?.service_name ?? ''; - allEdsServiceNames.add( - edsServiceName === '' ? message.name : edsServiceName - ); const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { watcher.onValidUpdate(message, isV2); @@ -164,7 +159,6 @@ export class CdsState implements XdsStreamState { } trace('Received CDS updates for cluster names ' + Array.from(allClusterNames)); this.handleMissingNames(allClusterNames); - this.edsState.handleMissingNames(allEdsServiceNames); return errorMessage; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index 7d28ed5ff..7e57012cb 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -128,23 +128,6 @@ export class EdsState implements XdsStreamState { return true; } - /** - * Given a list of edsServiceNames (which may actually be the cluster name), - * for each watcher watching a name not on the list, call that watcher's - * onResourceDoesNotExist method. - * @param allClusterNames - */ - handleMissingNames(allEdsServiceNames: Set) { - for (const [edsServiceName, watcherList] of this.watchers.entries()) { - if (!allEdsServiceNames.has(edsServiceName)) { - trace('Reporting EDS resource does not exist for edsServiceName ' + edsServiceName); - for (const watcher of watcherList) { - watcher.onResourceDoesNotExist(); - } - } - } - } - handleResponses(responses: ClusterLoadAssignment__Output[], isV2: boolean) { const validResponses: ClusterLoadAssignment__Output[] = []; let errorMessage: string | null = null; diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 5706e3766..2797bc1a8 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -167,13 +167,8 @@ export class LdsState implements XdsStreamState { this.latestResponses = validResponses; this.latestIsV2 = isV2; const allTargetNames = new Set(); - const allRouteConfigNames = new Set(); for (const message of validResponses) { allTargetNames.add(message.name); - const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener!.value); - if (httpConnectionManager.rds) { - allRouteConfigNames.add(httpConnectionManager.rds.route_config_name); - } const watchers = this.watchers.get(message.name) ?? []; for (const watcher of watchers) { watcher.onValidUpdate(message, isV2); @@ -181,7 +176,6 @@ export class LdsState implements XdsStreamState { } trace('Received RDS response with route config names ' + Array.from(allTargetNames)); this.handleMissingNames(allTargetNames); - this.rdsState.handleMissingNames(allRouteConfigNames); return errorMessage; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 5a3854323..4f06bd2dc 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -172,16 +172,6 @@ export class RdsState implements XdsStreamState { return true; } - handleMissingNames(allRouteConfigNames: Set) { - for (const [routeConfigName, watcherList] of this.watchers.entries()) { - if (!allRouteConfigNames.has(routeConfigName)) { - for (const watcher of watcherList) { - watcher.onResourceDoesNotExist(); - } - } - } - } - handleResponses(responses: RouteConfiguration__Output[], isV2: boolean): string | null { const validResponses: RouteConfiguration__Output[] = []; let errorMessage: string | null = null; From 8b7a4a0d9e5fabe758d21150f99b0961db3dc5db Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 2 Dec 2021 16:14:03 -0500 Subject: [PATCH 1571/1899] grpc-js-xds: Update envoy submodule, generate CSDS code --- packages/grpc-js-xds/deps/envoy-api | 2 +- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/generated/ads.ts | 19 + packages/grpc-js-xds/src/generated/cluster.ts | 7 + packages/grpc-js-xds/src/generated/csds.ts | 393 ++++++++++ .../grpc-js-xds/src/generated/endpoint.ts | 27 + .../envoy/admin/v3/BootstrapConfigDump.ts | 32 + .../envoy/admin/v3/ClientResourceStatus.ts | 34 + .../envoy/admin/v3/ClustersConfigDump.ts | 164 +++++ .../generated/envoy/admin/v3/ConfigDump.ts | 65 ++ .../envoy/admin/v3/EndpointsConfigDump.ts | 126 ++++ .../envoy/admin/v3/ListenersConfigDump.ts | 198 +++++ .../envoy/admin/v3/RoutesConfigDump.ts | 130 ++++ .../envoy/admin/v3/ScopedRoutesConfigDump.ts | 144 ++++ .../envoy/admin/v3/SecretsConfigDump.ts | 162 +++++ .../envoy/admin/v3/UpdateFailureState.ts | 46 ++ .../generated/envoy/api/v2/core/CidrRange.ts | 4 +- .../envoy/config/accesslog/v3/AccessLog.ts | 40 +- .../config/accesslog/v3/RuntimeFilter.ts | 8 +- .../envoy/config/bootstrap/v3/Admin.ts | 75 ++ .../envoy/config/bootstrap/v3/Bootstrap.ts | 642 +++++++++++++++++ .../config/bootstrap/v3/ClusterManager.ts | 99 +++ .../config/bootstrap/v3/CustomInlineHeader.ts | 85 +++ .../envoy/config/bootstrap/v3/FatalAction.ts | 39 + .../config/bootstrap/v3/LayeredRuntime.ts | 25 + .../envoy/config/bootstrap/v3/Runtime.ts | 77 ++ .../envoy/config/bootstrap/v3/RuntimeLayer.ts | 142 ++++ .../envoy/config/bootstrap/v3/Watchdog.ts | 141 ++++ .../envoy/config/bootstrap/v3/Watchdogs.ts | 35 + .../config/cluster/v3/CircuitBreakers.ts | 20 +- .../envoy/config/cluster/v3/Cluster.ts | 508 +++++++++---- .../envoy/config/cluster/v3/Filter.ts | 6 +- .../config/cluster/v3/LoadBalancingPolicy.ts | 18 +- .../config/cluster/v3/OutlierDetection.ts | 40 +- .../config/core/v3/AggregatedConfigSource.ts | 4 +- .../core/v3/AlternateProtocolsCacheOptions.ts | 72 ++ .../envoy/config/core/v3/BackoffStrategy.ts | 12 +- .../envoy/config/core/v3/BindConfig.ts | 4 +- .../envoy/config/core/v3/CidrRange.ts | 4 +- .../envoy/config/core/v3/ConfigSource.ts | 12 +- .../config/core/v3/DnsResolutionConfig.ts | 42 ++ .../config/core/v3/DnsResolverOptions.ts | 36 + .../config/core/v3/EnvoyInternalAddress.ts | 4 +- .../envoy/config/core/v3/GrpcService.ts | 22 +- .../envoy/config/core/v3/HeaderValueOption.ts | 35 + .../envoy/config/core/v3/HealthCheck.ts | 84 ++- .../config/core/v3/Http1ProtocolOptions.ts | 23 +- .../config/core/v3/Http2ProtocolOptions.ts | 8 + .../config/core/v3/Http3ProtocolOptions.ts | 54 +- .../config/core/v3/HttpProtocolOptions.ts | 44 +- .../envoy/config/core/v3/KeepaliveSettings.ts | 18 + .../envoy/config/core/v3/Locality.ts | 8 +- .../envoy/config/core/v3/Metadata.ts | 27 + .../generated/envoy/config/core/v3/Node.ts | 33 +- .../envoy/config/core/v3/QueryParameter.ts | 30 + .../config/core/v3/QuicProtocolOptions.ts | 69 ++ .../envoy/config/core/v3/RetryPolicy.ts | 4 +- .../core/v3/RuntimeFractionalPercent.ts | 4 +- .../core/v3/SchemeHeaderTransformation.ts | 24 + .../envoy/config/core/v3/SelfConfigSource.ts | 4 +- .../envoy/config/core/v3/SocketAddress.ts | 20 +- .../core/v3/SubstitutionFormatString.ts | 2 + .../envoy/config/core/v3/TransportSocket.ts | 4 +- .../envoy/config/core/v3/UdpSocketConfig.ts | 45 ++ .../core/v3/UpstreamHttpProtocolOptions.ts | 42 +- .../endpoint/v3/ClusterLoadAssignment.ts | 8 +- .../envoy/config/endpoint/v3/ClusterStats.ts | 4 +- .../envoy/config/endpoint/v3/Endpoint.ts | 16 +- .../envoy/config/endpoint/v3/LbEndpoint.ts | 4 +- .../endpoint/v3/LedsClusterLocalityConfig.ts | 35 + .../config/endpoint/v3/LocalityLbEndpoints.ts | 53 +- .../endpoint/v3/UpstreamLocalityStats.ts | 8 +- .../envoy/config/listener/v3/ApiListener.ts | 6 +- .../envoy/config/listener/v3/Filter.ts | 2 + .../envoy/config/listener/v3/FilterChain.ts | 10 +- .../config/listener/v3/FilterChainMatch.ts | 34 +- .../envoy/config/listener/v3/Listener.ts | 237 ++++-- .../config/listener/v3/ListenerFilter.ts | 22 +- .../v3/ListenerFilterChainMatchPredicate.ts | 4 +- .../config/listener/v3/QuicProtocolOptions.ts | 97 +++ .../config/listener/v3/UdpListenerConfig.ts | 49 +- .../envoy/config/metrics/v3/DogStatsdSink.ts | 65 ++ .../metrics/v3/HistogramBucketSettings.ts | 35 + .../envoy/config/metrics/v3/HystrixSink.ts | 61 ++ .../envoy/config/metrics/v3/StatsConfig.ts | 148 ++++ .../envoy/config/metrics/v3/StatsMatcher.ts | 47 ++ .../envoy/config/metrics/v3/StatsSink.ts | 43 ++ .../envoy/config/metrics/v3/StatsdSink.ts | 103 +++ .../envoy/config/metrics/v3/TagSpecifier.ts | 174 +++++ .../config/overload/v3/BufferFactoryConfig.ts | 50 ++ .../config/overload/v3/OverloadAction.ts | 42 ++ .../config/overload/v3/OverloadManager.ts | 44 ++ .../config/overload/v3/ResourceMonitor.ts | 33 + .../v3/ScaleTimersOverloadActionConfig.ts | 89 +++ .../envoy/config/overload/v3/ScaledTrigger.ts | 28 + .../config/overload/v3/ThresholdTrigger.ts | 18 + .../envoy/config/overload/v3/Trigger.ts | 24 + .../config/route/v3/ClusterSpecifierPlugin.ts | 23 + .../envoy/config/route/v3/CorsPolicy.ts | 8 +- .../config/route/v3/DirectResponseAction.ts | 8 +- .../envoy/config/route/v3/FilterConfig.ts | 12 +- .../envoy/config/route/v3/HeaderMatcher.ts | 43 +- .../envoy/config/route/v3/HedgePolicy.ts | 4 +- .../config/route/v3/InternalRedirectPolicy.ts | 6 +- .../config/route/v3/NonForwardingAction.ts | 14 + .../envoy/config/route/v3/RateLimit.ts | 32 +- .../envoy/config/route/v3/RedirectAction.ts | 4 +- .../envoy/config/route/v3/RetryPolicy.ts | 85 ++- .../generated/envoy/config/route/v3/Route.ts | 55 +- .../envoy/config/route/v3/RouteAction.ts | 122 ++-- .../config/route/v3/RouteConfiguration.ts | 59 +- .../envoy/config/route/v3/RouteMatch.ts | 43 +- .../route/v3/ScopedRouteConfiguration.ts | 32 +- .../envoy/config/route/v3/Tracing.ts | 4 +- .../envoy/config/route/v3/VirtualHost.ts | 32 +- .../envoy/config/route/v3/WeightedCluster.ts | 108 ++- .../envoy/config/trace/v3/Tracing.ts | 54 +- .../filters/common/fault/v3/FaultDelay.ts | 18 +- .../filters/http/fault/v3/HTTPFault.ts | 22 +- .../v3/EnvoyMobileHttpConnectionManager.ts | 29 + .../v3/HttpConnectionManager.ts | 350 +++++++-- .../http_connection_manager/v3/HttpFilter.ts | 24 +- .../http_connection_manager/v3/ScopedRds.ts | 10 + .../v3/ScopedRoutes.ts | 28 +- .../v3/CertificateProviderPluginInstance.ts | 52 ++ .../tls/v3/CertificateValidationContext.ts | 372 ++++++++++ .../transport_sockets/tls/v3/GenericSecret.ts | 17 + .../tls/v3/PrivateKeyProvider.ts | 39 + .../tls/v3/SdsSecretConfig.ts | 23 + .../transport_sockets/tls/v3/Secret.ts | 36 + .../tls/v3/TlsCertificate.ts | 127 ++++ .../transport_sockets/tls/v3/TlsParameters.ts | 211 ++++++ .../tls/v3/TlsSessionTicketKeys.ts | 61 ++ .../discovery/v3/DeltaDiscoveryRequest.ts | 4 +- .../service/discovery/v3/DiscoveryRequest.ts | 4 +- .../load_stats/v3/LoadStatsResponse.ts | 4 +- .../envoy/service/status/v3/ClientConfig.ts | 159 ++++ .../service/status/v3/ClientConfigStatus.ts | 26 + .../status/v3/ClientStatusDiscoveryService.ts | 45 ++ .../service/status/v3/ClientStatusRequest.ts | 34 + .../service/status/v3/ClientStatusResponse.ts | 17 + .../envoy/service/status/v3/ConfigStatus.ts | 30 + .../envoy/service/status/v3/PerXdsConfig.ts | 67 ++ .../envoy/type/http/v3/PathTransformation.ts | 92 +++ .../envoy/type/matcher/v3/MetadataMatcher.ts | 8 + .../envoy/type/matcher/v3/NodeMatcher.ts | 34 + .../envoy/type/matcher/v3/StringMatcher.ts | 8 +- .../envoy/type/matcher/v3/StructMatcher.ts | 153 ++++ .../envoy/type/metadata/v3/MetadataKey.ts | 4 +- .../envoy/type/metadata/v3/MetadataKind.ts | 12 +- .../envoy/type/tracing/v3/CustomTag.ts | 8 +- packages/grpc-js-xds/src/generated/fault.ts | 7 + .../generated/google/api/CustomHttpPattern.ts | 30 + .../src/generated/google/api/Http.ts | 49 ++ .../src/generated/google/api/HttpRule.ts | 680 ++++++++++++++++++ .../google/protobuf/EnumValueOptions.ts | 2 + .../generated/google/protobuf/FieldOptions.ts | 5 + .../google/protobuf/MethodOptions.ts | 3 + .../src/generated/http_connection_manager.ts | 13 + .../grpc-js-xds/src/generated/listener.ts | 15 + packages/grpc-js-xds/src/generated/lrs.ts | 19 + packages/grpc-js-xds/src/generated/route.ts | 8 + packages/grpc-js-xds/src/resolver-xds.ts | 5 + 163 files changed, 8798 insertions(+), 856 deletions(-) create mode 100644 packages/grpc-js-xds/src/generated/csds.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/BootstrapConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/ClientResourceStatus.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/ClustersConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/ConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/EndpointsConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/ListenersConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/RoutesConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/ScopedRoutesConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/SecretsConfigDump.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/admin/v3/UpdateFailureState.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Admin.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Bootstrap.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/ClusterManager.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/CustomInlineHeader.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/FatalAction.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/LayeredRuntime.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Runtime.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/RuntimeLayer.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdog.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdogs.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/AlternateProtocolsCacheOptions.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolutionConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolverOptions.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/QueryParameter.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/QuicProtocolOptions.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/SchemeHeaderTransformation.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/core/v3/UdpSocketConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LedsClusterLocalityConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/listener/v3/QuicProtocolOptions.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/DogStatsdSink.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HistogramBucketSettings.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HystrixSink.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsSink.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsdSink.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/TagSpecifier.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/BufferFactoryConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadAction.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadManager.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ResourceMonitor.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaleTimersOverloadActionConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaledTrigger.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ThresholdTrigger.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/overload/v3/Trigger.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/ClusterSpecifierPlugin.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/config/route/v3/NonForwardingAction.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/EnvoyMobileHttpConnectionManager.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateProviderPluginInstance.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateValidationContext.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/GenericSecret.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/PrivateKeyProvider.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/SdsSecretConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/Secret.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsCertificate.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsParameters.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsSessionTicketKeys.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfigStatus.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusDiscoveryService.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusRequest.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusResponse.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/ConfigStatus.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/service/status/v3/PerXdsConfig.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/http/v3/PathTransformation.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/NodeMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StructMatcher.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/Http.ts create mode 100644 packages/grpc-js-xds/src/generated/google/api/HttpRule.ts diff --git a/packages/grpc-js-xds/deps/envoy-api b/packages/grpc-js-xds/deps/envoy-api index 18b54850c..20b1b5fce 160000 --- a/packages/grpc-js-xds/deps/envoy-api +++ b/packages/grpc-js-xds/deps/envoy-api @@ -1 +1 @@ -Subproject commit 18b54850c9b7ba29a4ab67cbd7ed7eab7b0bbdb2 +Subproject commit 20b1b5fcee88a20a08b71051a961181839ec7268 diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index fca6ab80d..2ead8f1e8 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { diff --git a/packages/grpc-js-xds/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts index f8e336131..e0e46bb25 100644 --- a/packages/grpc-js-xds/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -10,6 +10,8 @@ type SubtypeConstructor any, Subtype> export interface ProtoGrpcType { envoy: { + annotations: { + } api: { v2: { DeltaDiscoveryRequest: MessageTypeDefinition @@ -72,6 +74,7 @@ export interface ProtoGrpcType { Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + QueryParameter: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition RetryPolicy: MessageTypeDefinition @@ -213,5 +216,21 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + core: { + v3: { + ContextParams: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/cluster.ts b/packages/grpc-js-xds/src/generated/cluster.ts index 6c2f7aa6f..78ac3bbd3 100644 --- a/packages/grpc-js-xds/src/generated/cluster.ts +++ b/packages/grpc-js-xds/src/generated/cluster.ts @@ -28,6 +28,7 @@ export interface ProtoGrpcType { v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition + AlternateProtocolsCacheOptions: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition ApiVersion: EnumTypeDefinition AsyncDataSource: MessageTypeDefinition @@ -38,6 +39,8 @@ export interface ProtoGrpcType { ConfigSource: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition + DnsResolutionConfig: MessageTypeDefinition + DnsResolverOptions: MessageTypeDefinition EnvoyInternalAddress: MessageTypeDefinition EventServiceConfig: MessageTypeDefinition Extension: MessageTypeDefinition @@ -59,6 +62,8 @@ export interface ProtoGrpcType { Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + QueryParameter: MessageTypeDefinition + QuicProtocolOptions: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -69,6 +74,7 @@ export interface ProtoGrpcType { RuntimeFractionalPercent: MessageTypeDefinition RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition + SchemeHeaderTransformation: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition @@ -86,6 +92,7 @@ export interface ProtoGrpcType { ClusterLoadAssignment: MessageTypeDefinition Endpoint: MessageTypeDefinition LbEndpoint: MessageTypeDefinition + LedsClusterLocalityConfig: MessageTypeDefinition LocalityLbEndpoints: MessageTypeDefinition } } diff --git a/packages/grpc-js-xds/src/generated/csds.ts b/packages/grpc-js-xds/src/generated/csds.ts new file mode 100644 index 000000000..58e903bc9 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/csds.ts @@ -0,0 +1,393 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; + +import type { ClientStatusDiscoveryServiceClient as _envoy_service_status_v3_ClientStatusDiscoveryServiceClient, ClientStatusDiscoveryServiceDefinition as _envoy_service_status_v3_ClientStatusDiscoveryServiceDefinition } from './envoy/service/status/v3/ClientStatusDiscoveryService'; + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + envoy: { + admin: { + v3: { + BootstrapConfigDump: MessageTypeDefinition + ClientResourceStatus: EnumTypeDefinition + ClustersConfigDump: MessageTypeDefinition + ConfigDump: MessageTypeDefinition + EndpointsConfigDump: MessageTypeDefinition + ListenersConfigDump: MessageTypeDefinition + RoutesConfigDump: MessageTypeDefinition + ScopedRoutesConfigDump: MessageTypeDefinition + SecretsConfigDump: MessageTypeDefinition + UpdateFailureState: MessageTypeDefinition + } + } + annotations: { + } + config: { + accesslog: { + v3: { + AccessLog: MessageTypeDefinition + AccessLogFilter: MessageTypeDefinition + AndFilter: MessageTypeDefinition + ComparisonFilter: MessageTypeDefinition + DurationFilter: MessageTypeDefinition + ExtensionFilter: MessageTypeDefinition + GrpcStatusFilter: MessageTypeDefinition + HeaderFilter: MessageTypeDefinition + MetadataFilter: MessageTypeDefinition + NotHealthCheckFilter: MessageTypeDefinition + OrFilter: MessageTypeDefinition + ResponseFlagFilter: MessageTypeDefinition + RuntimeFilter: MessageTypeDefinition + StatusCodeFilter: MessageTypeDefinition + TraceableFilter: MessageTypeDefinition + } + } + bootstrap: { + v3: { + Admin: MessageTypeDefinition + Bootstrap: MessageTypeDefinition + ClusterManager: MessageTypeDefinition + CustomInlineHeader: MessageTypeDefinition + FatalAction: MessageTypeDefinition + LayeredRuntime: MessageTypeDefinition + Runtime: MessageTypeDefinition + RuntimeLayer: MessageTypeDefinition + Watchdog: MessageTypeDefinition + Watchdogs: MessageTypeDefinition + } + } + cluster: { + v3: { + CircuitBreakers: MessageTypeDefinition + Cluster: MessageTypeDefinition + ClusterCollection: MessageTypeDefinition + Filter: MessageTypeDefinition + LoadBalancingPolicy: MessageTypeDefinition + OutlierDetection: MessageTypeDefinition + TrackClusterStats: MessageTypeDefinition + UpstreamBindConfig: MessageTypeDefinition + UpstreamConnectionOptions: MessageTypeDefinition + } + } + core: { + v3: { + Address: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + AlternateProtocolsCacheOptions: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition + AsyncDataSource: MessageTypeDefinition + BackoffStrategy: MessageTypeDefinition + BindConfig: MessageTypeDefinition + BuildVersion: MessageTypeDefinition + CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition + ControlPlane: MessageTypeDefinition + DataSource: MessageTypeDefinition + DnsResolutionConfig: MessageTypeDefinition + DnsResolverOptions: MessageTypeDefinition + EnvoyInternalAddress: MessageTypeDefinition + EventServiceConfig: MessageTypeDefinition + Extension: MessageTypeDefinition + ExtensionConfigSource: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition + GrpcService: MessageTypeDefinition + HeaderMap: MessageTypeDefinition + HeaderValue: MessageTypeDefinition + HeaderValueOption: MessageTypeDefinition + HealthCheck: MessageTypeDefinition + HealthStatus: EnumTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + Http3ProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition + HttpUri: MessageTypeDefinition + KeepaliveSettings: MessageTypeDefinition + Locality: MessageTypeDefinition + Metadata: MessageTypeDefinition + Node: MessageTypeDefinition + Pipe: MessageTypeDefinition + ProxyProtocolConfig: MessageTypeDefinition + QueryParameter: MessageTypeDefinition + QuicProtocolOptions: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition + RemoteDataSource: MessageTypeDefinition + RequestMethod: EnumTypeDefinition + RetryPolicy: MessageTypeDefinition + RoutingPriority: EnumTypeDefinition + RuntimeDouble: MessageTypeDefinition + RuntimeFeatureFlag: MessageTypeDefinition + RuntimeFractionalPercent: MessageTypeDefinition + RuntimePercent: MessageTypeDefinition + RuntimeUInt32: MessageTypeDefinition + SchemeHeaderTransformation: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition + SocketAddress: MessageTypeDefinition + SocketOption: MessageTypeDefinition + TcpKeepalive: MessageTypeDefinition + TcpProtocolOptions: MessageTypeDefinition + TrafficDirection: EnumTypeDefinition + TransportSocket: MessageTypeDefinition + TypedExtensionConfig: MessageTypeDefinition + UdpSocketConfig: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition + WatchedDirectory: MessageTypeDefinition + } + } + endpoint: { + v3: { + ClusterLoadAssignment: MessageTypeDefinition + Endpoint: MessageTypeDefinition + LbEndpoint: MessageTypeDefinition + LedsClusterLocalityConfig: MessageTypeDefinition + LocalityLbEndpoints: MessageTypeDefinition + } + } + listener: { + v3: { + ActiveRawUdpListenerConfig: MessageTypeDefinition + ApiListener: MessageTypeDefinition + Filter: MessageTypeDefinition + FilterChain: MessageTypeDefinition + FilterChainMatch: MessageTypeDefinition + Listener: MessageTypeDefinition + ListenerCollection: MessageTypeDefinition + ListenerFilter: MessageTypeDefinition + ListenerFilterChainMatchPredicate: MessageTypeDefinition + QuicProtocolOptions: MessageTypeDefinition + UdpListenerConfig: MessageTypeDefinition + } + } + metrics: { + v3: { + DogStatsdSink: MessageTypeDefinition + HistogramBucketSettings: MessageTypeDefinition + HystrixSink: MessageTypeDefinition + StatsConfig: MessageTypeDefinition + StatsMatcher: MessageTypeDefinition + StatsSink: MessageTypeDefinition + StatsdSink: MessageTypeDefinition + TagSpecifier: MessageTypeDefinition + } + } + overload: { + v3: { + BufferFactoryConfig: MessageTypeDefinition + OverloadAction: MessageTypeDefinition + OverloadManager: MessageTypeDefinition + ResourceMonitor: MessageTypeDefinition + ScaleTimersOverloadActionConfig: MessageTypeDefinition + ScaledTrigger: MessageTypeDefinition + ThresholdTrigger: MessageTypeDefinition + Trigger: MessageTypeDefinition + } + } + route: { + v3: { + CorsPolicy: MessageTypeDefinition + Decorator: MessageTypeDefinition + DirectResponseAction: MessageTypeDefinition + FilterAction: MessageTypeDefinition + FilterConfig: MessageTypeDefinition + HeaderMatcher: MessageTypeDefinition + HedgePolicy: MessageTypeDefinition + InternalRedirectPolicy: MessageTypeDefinition + NonForwardingAction: MessageTypeDefinition + QueryParameterMatcher: MessageTypeDefinition + RateLimit: MessageTypeDefinition + RedirectAction: MessageTypeDefinition + RetryPolicy: MessageTypeDefinition + Route: MessageTypeDefinition + RouteAction: MessageTypeDefinition + RouteMatch: MessageTypeDefinition + Tracing: MessageTypeDefinition + VirtualCluster: MessageTypeDefinition + VirtualHost: MessageTypeDefinition + WeightedCluster: MessageTypeDefinition + } + } + trace: { + v3: { + Tracing: MessageTypeDefinition + } + } + } + extensions: { + transport_sockets: { + tls: { + v3: { + CertificateProviderPluginInstance: MessageTypeDefinition + CertificateValidationContext: MessageTypeDefinition + GenericSecret: MessageTypeDefinition + PrivateKeyProvider: MessageTypeDefinition + SdsSecretConfig: MessageTypeDefinition + Secret: MessageTypeDefinition + TlsCertificate: MessageTypeDefinition + TlsParameters: MessageTypeDefinition + TlsSessionTicketKeys: MessageTypeDefinition + } + } + } + } + service: { + status: { + v3: { + ClientConfig: MessageTypeDefinition + ClientConfigStatus: EnumTypeDefinition + /** + * CSDS is Client Status Discovery Service. It can be used to get the status of + * an xDS-compliant client from the management server's point of view. It can + * also be used to get the current xDS states directly from the client. + */ + ClientStatusDiscoveryService: SubtypeConstructor & { service: _envoy_service_status_v3_ClientStatusDiscoveryServiceDefinition } + ClientStatusRequest: MessageTypeDefinition + ClientStatusResponse: MessageTypeDefinition + ConfigStatus: EnumTypeDefinition + PerXdsConfig: MessageTypeDefinition + } + } + } + type: { + matcher: { + v3: { + DoubleMatcher: MessageTypeDefinition + ListMatcher: MessageTypeDefinition + ListStringMatcher: MessageTypeDefinition + MetadataMatcher: MessageTypeDefinition + NodeMatcher: MessageTypeDefinition + RegexMatchAndSubstitute: MessageTypeDefinition + RegexMatcher: MessageTypeDefinition + StringMatcher: MessageTypeDefinition + StructMatcher: MessageTypeDefinition + ValueMatcher: MessageTypeDefinition + } + } + metadata: { + v3: { + MetadataKey: MessageTypeDefinition + MetadataKind: MessageTypeDefinition + } + } + tracing: { + v3: { + CustomTag: MessageTypeDefinition + } + } + v3: { + CodecClientType: EnumTypeDefinition + DoubleRange: MessageTypeDefinition + FractionalPercent: MessageTypeDefinition + Int32Range: MessageTypeDefinition + Int64Range: MessageTypeDefinition + Percent: MessageTypeDefinition + SemanticVersion: MessageTypeDefinition + } + } + } + google: { + api: { + CustomHttpPattern: MessageTypeDefinition + Http: MessageTypeDefinition + HttpRule: MessageTypeDefinition + } + protobuf: { + Any: MessageTypeDefinition + BoolValue: MessageTypeDefinition + BytesValue: MessageTypeDefinition + DescriptorProto: MessageTypeDefinition + DoubleValue: MessageTypeDefinition + Duration: MessageTypeDefinition + Empty: MessageTypeDefinition + EnumDescriptorProto: MessageTypeDefinition + EnumOptions: MessageTypeDefinition + EnumValueDescriptorProto: MessageTypeDefinition + EnumValueOptions: MessageTypeDefinition + FieldDescriptorProto: MessageTypeDefinition + FieldOptions: MessageTypeDefinition + FileDescriptorProto: MessageTypeDefinition + FileDescriptorSet: MessageTypeDefinition + FileOptions: MessageTypeDefinition + FloatValue: MessageTypeDefinition + GeneratedCodeInfo: MessageTypeDefinition + Int32Value: MessageTypeDefinition + Int64Value: MessageTypeDefinition + ListValue: MessageTypeDefinition + MessageOptions: MessageTypeDefinition + MethodDescriptorProto: MessageTypeDefinition + MethodOptions: MessageTypeDefinition + NullValue: EnumTypeDefinition + OneofDescriptorProto: MessageTypeDefinition + OneofOptions: MessageTypeDefinition + ServiceDescriptorProto: MessageTypeDefinition + ServiceOptions: MessageTypeDefinition + SourceCodeInfo: MessageTypeDefinition + StringValue: MessageTypeDefinition + Struct: MessageTypeDefinition + Timestamp: MessageTypeDefinition + UInt32Value: MessageTypeDefinition + UInt64Value: MessageTypeDefinition + UninterpretedOption: MessageTypeDefinition + Value: MessageTypeDefinition + } + } + udpa: { + annotations: { + FieldMigrateAnnotation: MessageTypeDefinition + FieldSecurityAnnotation: MessageTypeDefinition + FileMigrateAnnotation: MessageTypeDefinition + MigrateAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + VersioningAnnotation: MessageTypeDefinition + } + } + validate: { + AnyRules: MessageTypeDefinition + BoolRules: MessageTypeDefinition + BytesRules: MessageTypeDefinition + DoubleRules: MessageTypeDefinition + DurationRules: MessageTypeDefinition + EnumRules: MessageTypeDefinition + FieldRules: MessageTypeDefinition + Fixed32Rules: MessageTypeDefinition + Fixed64Rules: MessageTypeDefinition + FloatRules: MessageTypeDefinition + Int32Rules: MessageTypeDefinition + Int64Rules: MessageTypeDefinition + KnownRegex: EnumTypeDefinition + MapRules: MessageTypeDefinition + MessageRules: MessageTypeDefinition + RepeatedRules: MessageTypeDefinition + SFixed32Rules: MessageTypeDefinition + SFixed64Rules: MessageTypeDefinition + SInt32Rules: MessageTypeDefinition + SInt64Rules: MessageTypeDefinition + StringRules: MessageTypeDefinition + TimestampRules: MessageTypeDefinition + UInt32Rules: MessageTypeDefinition + UInt64Rules: MessageTypeDefinition + } + xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + core: { + v3: { + Authority: MessageTypeDefinition + CollectionEntry: MessageTypeDefinition + ContextParams: MessageTypeDefinition + ResourceLocator: MessageTypeDefinition + } + } + } +} + diff --git a/packages/grpc-js-xds/src/generated/endpoint.ts b/packages/grpc-js-xds/src/generated/endpoint.ts index 630bdeb62..9a87bc9a5 100644 --- a/packages/grpc-js-xds/src/generated/endpoint.ts +++ b/packages/grpc-js-xds/src/generated/endpoint.ts @@ -8,15 +8,21 @@ type SubtypeConstructor any, Subtype> export interface ProtoGrpcType { envoy: { + annotations: { + } config: { core: { v3: { Address: MessageTypeDefinition + AggregatedConfigSource: MessageTypeDefinition + ApiConfigSource: MessageTypeDefinition + ApiVersion: EnumTypeDefinition AsyncDataSource: MessageTypeDefinition BackoffStrategy: MessageTypeDefinition BindConfig: MessageTypeDefinition BuildVersion: MessageTypeDefinition CidrRange: MessageTypeDefinition + ConfigSource: MessageTypeDefinition ControlPlane: MessageTypeDefinition DataSource: MessageTypeDefinition EnvoyInternalAddress: MessageTypeDefinition @@ -33,6 +39,8 @@ export interface ProtoGrpcType { Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + QueryParameter: MessageTypeDefinition + RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition RetryPolicy: MessageTypeDefinition @@ -42,6 +50,7 @@ export interface ProtoGrpcType { RuntimeFractionalPercent: MessageTypeDefinition RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition + SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition @@ -55,6 +64,7 @@ export interface ProtoGrpcType { ClusterLoadAssignment: MessageTypeDefinition Endpoint: MessageTypeDefinition LbEndpoint: MessageTypeDefinition + LedsClusterLocalityConfig: MessageTypeDefinition LocalityLbEndpoints: MessageTypeDefinition } } @@ -156,5 +166,22 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + core: { + v3: { + Authority: MessageTypeDefinition + ContextParams: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/BootstrapConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/BootstrapConfigDump.ts new file mode 100644 index 000000000..d47f00ef3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/BootstrapConfigDump.ts @@ -0,0 +1,32 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Bootstrap as _envoy_config_bootstrap_v3_Bootstrap, Bootstrap__Output as _envoy_config_bootstrap_v3_Bootstrap__Output } from '../../../envoy/config/bootstrap/v3/Bootstrap'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; + +/** + * This message describes the bootstrap configuration that Envoy was started with. This includes + * any CLI overrides that were merged. Bootstrap configuration information can be used to recreate + * the static portions of an Envoy configuration by reusing the output as the bootstrap + * configuration for another Envoy. + */ +export interface BootstrapConfigDump { + 'bootstrap'?: (_envoy_config_bootstrap_v3_Bootstrap | null); + /** + * The timestamp when the BootstrapConfig was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +/** + * This message describes the bootstrap configuration that Envoy was started with. This includes + * any CLI overrides that were merged. Bootstrap configuration information can be used to recreate + * the static portions of an Envoy configuration by reusing the output as the bootstrap + * configuration for another Envoy. + */ +export interface BootstrapConfigDump__Output { + 'bootstrap': (_envoy_config_bootstrap_v3_Bootstrap__Output | null); + /** + * The timestamp when the BootstrapConfig was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/ClientResourceStatus.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ClientResourceStatus.ts new file mode 100644 index 000000000..31c3a813a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ClientResourceStatus.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +/** + * Resource status from the view of a xDS client, which tells the synchronization + * status between the xDS client and the xDS server. + */ +export enum ClientResourceStatus { + /** + * Resource status is not available/unknown. + */ + UNKNOWN = 0, + /** + * Client requested this resource but hasn't received any update from management + * server. The client will not fail requests, but will queue them until update + * arrives or the client times out waiting for the resource. + */ + REQUESTED = 1, + /** + * This resource has been requested by the client but has either not been + * delivered by the server or was previously delivered by the server and then + * subsequently removed from resources provided by the server. For more + * information, please refer to the :ref:`"Knowing When a Requested Resource + * Does Not Exist" ` section. + */ + DOES_NOT_EXIST = 2, + /** + * Client received this resource and replied with ACK. + */ + ACKED = 3, + /** + * Client received this resource and replied with NACK. + */ + NACKED = 4, +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/ClustersConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ClustersConfigDump.ts new file mode 100644 index 000000000..ab7c528bf --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ClustersConfigDump.ts @@ -0,0 +1,164 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../envoy/admin/v3/UpdateFailureState'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../envoy/admin/v3/ClientResourceStatus'; + +/** + * Describes a dynamically loaded cluster via the CDS API. + * [#next-free-field: 6] + */ +export interface _envoy_admin_v3_ClustersConfigDump_DynamicCluster { + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time + * that the cluster was loaded. In the future, discrete per-cluster versions may be supported by + * the API. + */ + 'version_info'?: (string); + /** + * The cluster config. + */ + 'cluster'?: (_google_protobuf_Any | null); + /** + * The timestamp when the Cluster was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * Describes a dynamically loaded cluster via the CDS API. + * [#next-free-field: 6] + */ +export interface _envoy_admin_v3_ClustersConfigDump_DynamicCluster__Output { + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time + * that the cluster was loaded. In the future, discrete per-cluster versions may be supported by + * the API. + */ + 'version_info': (string); + /** + * The cluster config. + */ + 'cluster': (_google_protobuf_Any__Output | null); + /** + * The timestamp when the Cluster was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * Describes a statically loaded cluster. + */ +export interface _envoy_admin_v3_ClustersConfigDump_StaticCluster { + /** + * The cluster config. + */ + 'cluster'?: (_google_protobuf_Any | null); + /** + * The timestamp when the Cluster was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +/** + * Describes a statically loaded cluster. + */ +export interface _envoy_admin_v3_ClustersConfigDump_StaticCluster__Output { + /** + * The cluster config. + */ + 'cluster': (_google_protobuf_Any__Output | null); + /** + * The timestamp when the Cluster was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} + +/** + * Envoy's cluster manager fills this message with all currently known clusters. Cluster + * configuration information can be used to recreate an Envoy configuration by populating all + * clusters as static clusters or by returning them in a CDS response. + */ +export interface ClustersConfigDump { + /** + * This is the :ref:`version_info ` in the + * last processed CDS discovery response. If there are only static bootstrap clusters, this field + * will be "". + */ + 'version_info'?: (string); + /** + * The statically loaded cluster configs. + */ + 'static_clusters'?: (_envoy_admin_v3_ClustersConfigDump_StaticCluster)[]; + /** + * The dynamically loaded active clusters. These are clusters that are available to service + * data plane traffic. + */ + 'dynamic_active_clusters'?: (_envoy_admin_v3_ClustersConfigDump_DynamicCluster)[]; + /** + * The dynamically loaded warming clusters. These are clusters that are currently undergoing + * warming in preparation to service data plane traffic. Note that if attempting to recreate an + * Envoy configuration from a configuration dump, the warming clusters should generally be + * discarded. + */ + 'dynamic_warming_clusters'?: (_envoy_admin_v3_ClustersConfigDump_DynamicCluster)[]; +} + +/** + * Envoy's cluster manager fills this message with all currently known clusters. Cluster + * configuration information can be used to recreate an Envoy configuration by populating all + * clusters as static clusters or by returning them in a CDS response. + */ +export interface ClustersConfigDump__Output { + /** + * This is the :ref:`version_info ` in the + * last processed CDS discovery response. If there are only static bootstrap clusters, this field + * will be "". + */ + 'version_info': (string); + /** + * The statically loaded cluster configs. + */ + 'static_clusters': (_envoy_admin_v3_ClustersConfigDump_StaticCluster__Output)[]; + /** + * The dynamically loaded active clusters. These are clusters that are available to service + * data plane traffic. + */ + 'dynamic_active_clusters': (_envoy_admin_v3_ClustersConfigDump_DynamicCluster__Output)[]; + /** + * The dynamically loaded warming clusters. These are clusters that are currently undergoing + * warming in preparation to service data plane traffic. Note that if attempting to recreate an + * Envoy configuration from a configuration dump, the warming clusters should generally be + * discarded. + */ + 'dynamic_warming_clusters': (_envoy_admin_v3_ClustersConfigDump_DynamicCluster__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/ConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ConfigDump.ts new file mode 100644 index 000000000..8a0ab65c2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ConfigDump.ts @@ -0,0 +1,65 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; + +/** + * The :ref:`/config_dump ` admin endpoint uses this wrapper + * message to maintain and serve arbitrary configuration information from any component in Envoy. + */ +export interface ConfigDump { + /** + * This list is serialized and dumped in its entirety at the + * :ref:`/config_dump ` endpoint. + * + * The following configurations are currently supported and will be dumped in the order given + * below: + * + * * *bootstrap*: :ref:`BootstrapConfigDump ` + * * *clusters*: :ref:`ClustersConfigDump ` + * * *endpoints*: :ref:`EndpointsConfigDump ` + * * *listeners*: :ref:`ListenersConfigDump ` + * * *scoped_routes*: :ref:`ScopedRoutesConfigDump ` + * * *routes*: :ref:`RoutesConfigDump ` + * * *secrets*: :ref:`SecretsConfigDump ` + * + * EDS Configuration will only be dumped by using parameter `?include_eds` + * + * You can filter output with the resource and mask query parameters. + * See :ref:`/config_dump?resource={} `, + * :ref:`/config_dump?mask={} `, + * or :ref:`/config_dump?resource={},mask={} + * ` for more information. + */ + 'configs'?: (_google_protobuf_Any)[]; +} + +/** + * The :ref:`/config_dump ` admin endpoint uses this wrapper + * message to maintain and serve arbitrary configuration information from any component in Envoy. + */ +export interface ConfigDump__Output { + /** + * This list is serialized and dumped in its entirety at the + * :ref:`/config_dump ` endpoint. + * + * The following configurations are currently supported and will be dumped in the order given + * below: + * + * * *bootstrap*: :ref:`BootstrapConfigDump ` + * * *clusters*: :ref:`ClustersConfigDump ` + * * *endpoints*: :ref:`EndpointsConfigDump ` + * * *listeners*: :ref:`ListenersConfigDump ` + * * *scoped_routes*: :ref:`ScopedRoutesConfigDump ` + * * *routes*: :ref:`RoutesConfigDump ` + * * *secrets*: :ref:`SecretsConfigDump ` + * + * EDS Configuration will only be dumped by using parameter `?include_eds` + * + * You can filter output with the resource and mask query parameters. + * See :ref:`/config_dump?resource={} `, + * :ref:`/config_dump?mask={} `, + * or :ref:`/config_dump?resource={},mask={} + * ` for more information. + */ + 'configs': (_google_protobuf_Any__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/EndpointsConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/EndpointsConfigDump.ts new file mode 100644 index 000000000..d68b27e7c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/EndpointsConfigDump.ts @@ -0,0 +1,126 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../envoy/admin/v3/UpdateFailureState'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../envoy/admin/v3/ClientResourceStatus'; + +/** + * [#next-free-field: 6] + */ +export interface _envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig { + /** + * [#not-implemented-hide:] This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time that + * the endpoint configuration was loaded. + */ + 'version_info'?: (string); + /** + * The endpoint config. + */ + 'endpoint_config'?: (_google_protobuf_Any | null); + /** + * [#not-implemented-hide:] The timestamp when the Endpoint was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * [#next-free-field: 6] + */ +export interface _envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig__Output { + /** + * [#not-implemented-hide:] This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time that + * the endpoint configuration was loaded. + */ + 'version_info': (string); + /** + * The endpoint config. + */ + 'endpoint_config': (_google_protobuf_Any__Output | null); + /** + * [#not-implemented-hide:] The timestamp when the Endpoint was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +export interface _envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig { + /** + * The endpoint config. + */ + 'endpoint_config'?: (_google_protobuf_Any | null); + /** + * [#not-implemented-hide:] The timestamp when the Endpoint was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +export interface _envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig__Output { + /** + * The endpoint config. + */ + 'endpoint_config': (_google_protobuf_Any__Output | null); + /** + * [#not-implemented-hide:] The timestamp when the Endpoint was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} + +/** + * Envoy's admin fill this message with all currently known endpoints. Endpoint + * configuration information can be used to recreate an Envoy configuration by populating all + * endpoints as static endpoints or by returning them in an EDS response. + */ +export interface EndpointsConfigDump { + /** + * The statically loaded endpoint configs. + */ + 'static_endpoint_configs'?: (_envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig)[]; + /** + * The dynamically loaded endpoint configs. + */ + 'dynamic_endpoint_configs'?: (_envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig)[]; +} + +/** + * Envoy's admin fill this message with all currently known endpoints. Endpoint + * configuration information can be used to recreate an Envoy configuration by populating all + * endpoints as static endpoints or by returning them in an EDS response. + */ +export interface EndpointsConfigDump__Output { + /** + * The statically loaded endpoint configs. + */ + 'static_endpoint_configs': (_envoy_admin_v3_EndpointsConfigDump_StaticEndpointConfig__Output)[]; + /** + * The dynamically loaded endpoint configs. + */ + 'dynamic_endpoint_configs': (_envoy_admin_v3_EndpointsConfigDump_DynamicEndpointConfig__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/ListenersConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ListenersConfigDump.ts new file mode 100644 index 000000000..745abedae --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ListenersConfigDump.ts @@ -0,0 +1,198 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../envoy/admin/v3/UpdateFailureState'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../envoy/admin/v3/ClientResourceStatus'; + +/** + * Describes a dynamically loaded listener via the LDS API. + * [#next-free-field: 7] + */ +export interface _envoy_admin_v3_ListenersConfigDump_DynamicListener { + /** + * The name or unique id of this listener, pulled from the DynamicListenerState config. + */ + 'name'?: (string); + /** + * The listener state for any active listener by this name. + * These are listeners that are available to service data plane traffic. + */ + 'active_state'?: (_envoy_admin_v3_ListenersConfigDump_DynamicListenerState | null); + /** + * The listener state for any warming listener by this name. + * These are listeners that are currently undergoing warming in preparation to service data + * plane traffic. Note that if attempting to recreate an Envoy configuration from a + * configuration dump, the warming listeners should generally be discarded. + */ + 'warming_state'?: (_envoy_admin_v3_ListenersConfigDump_DynamicListenerState | null); + /** + * The listener state for any draining listener by this name. + * These are listeners that are currently undergoing draining in preparation to stop servicing + * data plane traffic. Note that if attempting to recreate an Envoy configuration from a + * configuration dump, the draining listeners should generally be discarded. + */ + 'draining_state'?: (_envoy_admin_v3_ListenersConfigDump_DynamicListenerState | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * Describes a dynamically loaded listener via the LDS API. + * [#next-free-field: 7] + */ +export interface _envoy_admin_v3_ListenersConfigDump_DynamicListener__Output { + /** + * The name or unique id of this listener, pulled from the DynamicListenerState config. + */ + 'name': (string); + /** + * The listener state for any active listener by this name. + * These are listeners that are available to service data plane traffic. + */ + 'active_state': (_envoy_admin_v3_ListenersConfigDump_DynamicListenerState__Output | null); + /** + * The listener state for any warming listener by this name. + * These are listeners that are currently undergoing warming in preparation to service data + * plane traffic. Note that if attempting to recreate an Envoy configuration from a + * configuration dump, the warming listeners should generally be discarded. + */ + 'warming_state': (_envoy_admin_v3_ListenersConfigDump_DynamicListenerState__Output | null); + /** + * The listener state for any draining listener by this name. + * These are listeners that are currently undergoing draining in preparation to stop servicing + * data plane traffic. Note that if attempting to recreate an Envoy configuration from a + * configuration dump, the draining listeners should generally be discarded. + */ + 'draining_state': (_envoy_admin_v3_ListenersConfigDump_DynamicListenerState__Output | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +export interface _envoy_admin_v3_ListenersConfigDump_DynamicListenerState { + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time + * that the listener was loaded. In the future, discrete per-listener versions may be supported + * by the API. + */ + 'version_info'?: (string); + /** + * The listener config. + */ + 'listener'?: (_google_protobuf_Any | null); + /** + * The timestamp when the Listener was last successfully updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +export interface _envoy_admin_v3_ListenersConfigDump_DynamicListenerState__Output { + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time + * that the listener was loaded. In the future, discrete per-listener versions may be supported + * by the API. + */ + 'version_info': (string); + /** + * The listener config. + */ + 'listener': (_google_protobuf_Any__Output | null); + /** + * The timestamp when the Listener was last successfully updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} + +/** + * Describes a statically loaded listener. + */ +export interface _envoy_admin_v3_ListenersConfigDump_StaticListener { + /** + * The listener config. + */ + 'listener'?: (_google_protobuf_Any | null); + /** + * The timestamp when the Listener was last successfully updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +/** + * Describes a statically loaded listener. + */ +export interface _envoy_admin_v3_ListenersConfigDump_StaticListener__Output { + /** + * The listener config. + */ + 'listener': (_google_protobuf_Any__Output | null); + /** + * The timestamp when the Listener was last successfully updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} + +/** + * Envoy's listener manager fills this message with all currently known listeners. Listener + * configuration information can be used to recreate an Envoy configuration by populating all + * listeners as static listeners or by returning them in a LDS response. + */ +export interface ListenersConfigDump { + /** + * This is the :ref:`version_info ` in the + * last processed LDS discovery response. If there are only static bootstrap listeners, this field + * will be "". + */ + 'version_info'?: (string); + /** + * The statically loaded listener configs. + */ + 'static_listeners'?: (_envoy_admin_v3_ListenersConfigDump_StaticListener)[]; + /** + * State for any warming, active, or draining listeners. + */ + 'dynamic_listeners'?: (_envoy_admin_v3_ListenersConfigDump_DynamicListener)[]; +} + +/** + * Envoy's listener manager fills this message with all currently known listeners. Listener + * configuration information can be used to recreate an Envoy configuration by populating all + * listeners as static listeners or by returning them in a LDS response. + */ +export interface ListenersConfigDump__Output { + /** + * This is the :ref:`version_info ` in the + * last processed LDS discovery response. If there are only static bootstrap listeners, this field + * will be "". + */ + 'version_info': (string); + /** + * The statically loaded listener configs. + */ + 'static_listeners': (_envoy_admin_v3_ListenersConfigDump_StaticListener__Output)[]; + /** + * State for any warming, active, or draining listeners. + */ + 'dynamic_listeners': (_envoy_admin_v3_ListenersConfigDump_DynamicListener__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/RoutesConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/RoutesConfigDump.ts new file mode 100644 index 000000000..2a62e9b74 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/RoutesConfigDump.ts @@ -0,0 +1,130 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../envoy/admin/v3/UpdateFailureState'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../envoy/admin/v3/ClientResourceStatus'; + +/** + * [#next-free-field: 6] + */ +export interface _envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig { + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time that + * the route configuration was loaded. + */ + 'version_info'?: (string); + /** + * The route config. + */ + 'route_config'?: (_google_protobuf_Any | null); + /** + * The timestamp when the Route was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * [#next-free-field: 6] + */ +export interface _envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig__Output { + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time that + * the route configuration was loaded. + */ + 'version_info': (string); + /** + * The route config. + */ + 'route_config': (_google_protobuf_Any__Output | null); + /** + * The timestamp when the Route was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +export interface _envoy_admin_v3_RoutesConfigDump_StaticRouteConfig { + /** + * The route config. + */ + 'route_config'?: (_google_protobuf_Any | null); + /** + * The timestamp when the Route was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +export interface _envoy_admin_v3_RoutesConfigDump_StaticRouteConfig__Output { + /** + * The route config. + */ + 'route_config': (_google_protobuf_Any__Output | null); + /** + * The timestamp when the Route was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} + +/** + * Envoy's RDS implementation fills this message with all currently loaded routes, as described by + * their RouteConfiguration objects. Static routes that are either defined in the bootstrap configuration + * or defined inline while configuring listeners are separated from those configured dynamically via RDS. + * Route configuration information can be used to recreate an Envoy configuration by populating all routes + * as static routes or by returning them in RDS responses. + */ +export interface RoutesConfigDump { + /** + * The statically loaded route configs. + */ + 'static_route_configs'?: (_envoy_admin_v3_RoutesConfigDump_StaticRouteConfig)[]; + /** + * The dynamically loaded route configs. + */ + 'dynamic_route_configs'?: (_envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig)[]; +} + +/** + * Envoy's RDS implementation fills this message with all currently loaded routes, as described by + * their RouteConfiguration objects. Static routes that are either defined in the bootstrap configuration + * or defined inline while configuring listeners are separated from those configured dynamically via RDS. + * Route configuration information can be used to recreate an Envoy configuration by populating all routes + * as static routes or by returning them in RDS responses. + */ +export interface RoutesConfigDump__Output { + /** + * The statically loaded route configs. + */ + 'static_route_configs': (_envoy_admin_v3_RoutesConfigDump_StaticRouteConfig__Output)[]; + /** + * The dynamically loaded route configs. + */ + 'dynamic_route_configs': (_envoy_admin_v3_RoutesConfigDump_DynamicRouteConfig__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/ScopedRoutesConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ScopedRoutesConfigDump.ts new file mode 100644 index 000000000..f271635bc --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/ScopedRoutesConfigDump.ts @@ -0,0 +1,144 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../envoy/admin/v3/UpdateFailureState'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../envoy/admin/v3/ClientResourceStatus'; + +/** + * [#next-free-field: 7] + */ +export interface _envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs { + /** + * The name assigned to the scoped route configurations. + */ + 'name'?: (string); + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time that + * the scoped routes configuration was loaded. + */ + 'version_info'?: (string); + /** + * The scoped route configurations. + */ + 'scoped_route_configs'?: (_google_protobuf_Any)[]; + /** + * The timestamp when the scoped route config set was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * [#next-free-field: 7] + */ +export interface _envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs__Output { + /** + * The name assigned to the scoped route configurations. + */ + 'name': (string); + /** + * This is the per-resource version information. This version is currently taken from the + * :ref:`version_info ` field at the time that + * the scoped routes configuration was loaded. + */ + 'version_info': (string); + /** + * The scoped route configurations. + */ + 'scoped_route_configs': (_google_protobuf_Any__Output)[]; + /** + * The timestamp when the scoped route config set was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +export interface _envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs { + /** + * The name assigned to the scoped route configurations. + */ + 'name'?: (string); + /** + * The scoped route configurations. + */ + 'scoped_route_configs'?: (_google_protobuf_Any)[]; + /** + * The timestamp when the scoped route config set was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); +} + +export interface _envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs__Output { + /** + * The name assigned to the scoped route configurations. + */ + 'name': (string); + /** + * The scoped route configurations. + */ + 'scoped_route_configs': (_google_protobuf_Any__Output)[]; + /** + * The timestamp when the scoped route config set was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); +} + +/** + * Envoy's scoped RDS implementation fills this message with all currently loaded route + * configuration scopes (defined via ScopedRouteConfigurationsSet protos). This message lists both + * the scopes defined inline with the higher order object (i.e., the HttpConnectionManager) and the + * dynamically obtained scopes via the SRDS API. + */ +export interface ScopedRoutesConfigDump { + /** + * The statically loaded scoped route configs. + */ + 'inline_scoped_route_configs'?: (_envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs)[]; + /** + * The dynamically loaded scoped route configs. + */ + 'dynamic_scoped_route_configs'?: (_envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs)[]; +} + +/** + * Envoy's scoped RDS implementation fills this message with all currently loaded route + * configuration scopes (defined via ScopedRouteConfigurationsSet protos). This message lists both + * the scopes defined inline with the higher order object (i.e., the HttpConnectionManager) and the + * dynamically obtained scopes via the SRDS API. + */ +export interface ScopedRoutesConfigDump__Output { + /** + * The statically loaded scoped route configs. + */ + 'inline_scoped_route_configs': (_envoy_admin_v3_ScopedRoutesConfigDump_InlineScopedRouteConfigs__Output)[]; + /** + * The dynamically loaded scoped route configs. + */ + 'dynamic_scoped_route_configs': (_envoy_admin_v3_ScopedRoutesConfigDump_DynamicScopedRouteConfigs__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/SecretsConfigDump.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/SecretsConfigDump.ts new file mode 100644 index 000000000..21921edec --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/SecretsConfigDump.ts @@ -0,0 +1,162 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../envoy/admin/v3/UpdateFailureState'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../envoy/admin/v3/ClientResourceStatus'; + +/** + * DynamicSecret contains secret information fetched via SDS. + * [#next-free-field: 7] + */ +export interface _envoy_admin_v3_SecretsConfigDump_DynamicSecret { + /** + * The name assigned to the secret. + */ + 'name'?: (string); + /** + * This is the per-resource version information. + */ + 'version_info'?: (string); + /** + * The timestamp when the secret was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * The actual secret information. + * Security sensitive information is redacted (replaced with "[redacted]") for + * private keys and passwords in TLS certificates. + */ + 'secret'?: (_google_protobuf_Any | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * DynamicSecret contains secret information fetched via SDS. + * [#next-free-field: 7] + */ +export interface _envoy_admin_v3_SecretsConfigDump_DynamicSecret__Output { + /** + * The name assigned to the secret. + */ + 'name': (string); + /** + * This is the per-resource version information. + */ + 'version_info': (string); + /** + * The timestamp when the secret was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * The actual secret information. + * Security sensitive information is redacted (replaced with "[redacted]") for + * private keys and passwords in TLS certificates. + */ + 'secret': (_google_protobuf_Any__Output | null); + /** + * Set if the last update failed, cleared after the next successful update. + * The *error_state* field contains the rejected version of this particular + * resource along with the reason and timestamp. For successfully updated or + * acknowledged resource, this field should be empty. + * [#not-implemented-hide:] + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * The client status of this resource. + * [#not-implemented-hide:] + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); +} + +/** + * StaticSecret specifies statically loaded secret in bootstrap. + */ +export interface _envoy_admin_v3_SecretsConfigDump_StaticSecret { + /** + * The name assigned to the secret. + */ + 'name'?: (string); + /** + * The timestamp when the secret was last updated. + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * The actual secret information. + * Security sensitive information is redacted (replaced with "[redacted]") for + * private keys and passwords in TLS certificates. + */ + 'secret'?: (_google_protobuf_Any | null); +} + +/** + * StaticSecret specifies statically loaded secret in bootstrap. + */ +export interface _envoy_admin_v3_SecretsConfigDump_StaticSecret__Output { + /** + * The name assigned to the secret. + */ + 'name': (string); + /** + * The timestamp when the secret was last updated. + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * The actual secret information. + * Security sensitive information is redacted (replaced with "[redacted]") for + * private keys and passwords in TLS certificates. + */ + 'secret': (_google_protobuf_Any__Output | null); +} + +/** + * Envoys SDS implementation fills this message with all secrets fetched dynamically via SDS. + */ +export interface SecretsConfigDump { + /** + * The statically loaded secrets. + */ + 'static_secrets'?: (_envoy_admin_v3_SecretsConfigDump_StaticSecret)[]; + /** + * The dynamically loaded active secrets. These are secrets that are available to service + * clusters or listeners. + */ + 'dynamic_active_secrets'?: (_envoy_admin_v3_SecretsConfigDump_DynamicSecret)[]; + /** + * The dynamically loaded warming secrets. These are secrets that are currently undergoing + * warming in preparation to service clusters or listeners. + */ + 'dynamic_warming_secrets'?: (_envoy_admin_v3_SecretsConfigDump_DynamicSecret)[]; +} + +/** + * Envoys SDS implementation fills this message with all secrets fetched dynamically via SDS. + */ +export interface SecretsConfigDump__Output { + /** + * The statically loaded secrets. + */ + 'static_secrets': (_envoy_admin_v3_SecretsConfigDump_StaticSecret__Output)[]; + /** + * The dynamically loaded active secrets. These are secrets that are available to service + * clusters or listeners. + */ + 'dynamic_active_secrets': (_envoy_admin_v3_SecretsConfigDump_DynamicSecret__Output)[]; + /** + * The dynamically loaded warming secrets. These are secrets that are currently undergoing + * warming in preparation to service clusters or listeners. + */ + 'dynamic_warming_secrets': (_envoy_admin_v3_SecretsConfigDump_DynamicSecret__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/admin/v3/UpdateFailureState.ts b/packages/grpc-js-xds/src/generated/envoy/admin/v3/UpdateFailureState.ts new file mode 100644 index 000000000..b98e8cd4d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/admin/v3/UpdateFailureState.ts @@ -0,0 +1,46 @@ +// Original file: deps/envoy-api/envoy/admin/v3/config_dump.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; + +export interface UpdateFailureState { + /** + * What the component configuration would have been if the update had succeeded. + * This field may not be populated by xDS clients due to storage overhead. + */ + 'failed_configuration'?: (_google_protobuf_Any | null); + /** + * Time of the latest failed update attempt. + */ + 'last_update_attempt'?: (_google_protobuf_Timestamp | null); + /** + * Details about the last failed update attempt. + */ + 'details'?: (string); + /** + * This is the version of the rejected resource. + * [#not-implemented-hide:] + */ + 'version_info'?: (string); +} + +export interface UpdateFailureState__Output { + /** + * What the component configuration would have been if the update had succeeded. + * This field may not be populated by xDS clients due to storage overhead. + */ + 'failed_configuration': (_google_protobuf_Any__Output | null); + /** + * Time of the latest failed update attempt. + */ + 'last_update_attempt': (_google_protobuf_Timestamp__Output | null); + /** + * Details about the last failed update attempt. + */ + 'details': (string); + /** + * This is the version of the rejected resource. + * [#not-implemented-hide:] + */ + 'version_info': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts index cca1bc2d8..5e1df8a13 100644 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts +++ b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts @@ -12,7 +12,7 @@ export interface CidrRange { */ 'address_prefix'?: (string); /** - * Length of prefix, e.g. 0, 32. + * Length of prefix, e.g. 0, 32. Defaults to 0 when unset. */ 'prefix_len'?: (_google_protobuf_UInt32Value | null); } @@ -27,7 +27,7 @@ export interface CidrRange__Output { */ 'address_prefix': (string); /** - * Length of prefix, e.g. 0, 32. + * Length of prefix, e.g. 0, 32. Defaults to 0 when unset. */ 'prefix_len': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts index 369f36bc2..367d8f302 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/AccessLog.ts @@ -5,12 +5,9 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ export interface AccessLog { /** - * The name of the access log implementation to instantiate. The name must - * match a statically registered access log. Current built-in loggers include: - * - * #. "envoy.access_loggers.file" - * #. "envoy.access_loggers.http_grpc" - * #. "envoy.access_loggers.tcp_grpc" + * The name of the access log extension to instantiate. + * The name must match one of the compiled in loggers. + * See the :ref:`extensions listed in typed_config below ` for the default list of available loggers. */ 'name'?: (string); /** @@ -19,27 +16,17 @@ export interface AccessLog { 'filter'?: (_envoy_config_accesslog_v3_AccessLogFilter | null); 'typed_config'?: (_google_protobuf_Any | null); /** - * Custom configuration that depends on the access log being instantiated. - * Built-in configurations include: - * - * #. "envoy.access_loggers.file": :ref:`FileAccessLog - * ` - * #. "envoy.access_loggers.http_grpc": :ref:`HttpGrpcAccessLogConfig - * ` - * #. "envoy.access_loggers.tcp_grpc": :ref:`TcpGrpcAccessLogConfig - * ` + * Custom configuration that must be set according to the access logger extension being instantiated. + * [#extension-category: envoy.access_loggers] */ 'config_type'?: "typed_config"; } export interface AccessLog__Output { /** - * The name of the access log implementation to instantiate. The name must - * match a statically registered access log. Current built-in loggers include: - * - * #. "envoy.access_loggers.file" - * #. "envoy.access_loggers.http_grpc" - * #. "envoy.access_loggers.tcp_grpc" + * The name of the access log extension to instantiate. + * The name must match one of the compiled in loggers. + * See the :ref:`extensions listed in typed_config below ` for the default list of available loggers. */ 'name': (string); /** @@ -48,15 +35,8 @@ export interface AccessLog__Output { 'filter': (_envoy_config_accesslog_v3_AccessLogFilter__Output | null); 'typed_config'?: (_google_protobuf_Any__Output | null); /** - * Custom configuration that depends on the access log being instantiated. - * Built-in configurations include: - * - * #. "envoy.access_loggers.file": :ref:`FileAccessLog - * ` - * #. "envoy.access_loggers.http_grpc": :ref:`HttpGrpcAccessLogConfig - * ` - * #. "envoy.access_loggers.tcp_grpc": :ref:`TcpGrpcAccessLogConfig - * ` + * Custom configuration that must be set according to the access logger extension being instantiated. + * [#extension-category: envoy.access_loggers] */ 'config_type': "typed_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts index e605fa1a4..83b075388 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/accesslog/v3/RuntimeFilter.ts @@ -28,8 +28,8 @@ export interface RuntimeFilter { * randomly sample based on the runtime key value alone. * *use_independent_randomness* can be used for logging kill switches within * complex nested :ref:`AndFilter - * ` and :ref:`OrFilter - * ` blocks that are easier to + * ` and :ref:`OrFilter + * ` blocks that are easier to * reason about from a probability perspective (i.e., setting to true will * cause the filter to behave like an independent random variable when * composed within logical operator filters). @@ -63,8 +63,8 @@ export interface RuntimeFilter__Output { * randomly sample based on the runtime key value alone. * *use_independent_randomness* can be used for logging kill switches within * complex nested :ref:`AndFilter - * ` and :ref:`OrFilter - * ` blocks that are easier to + * ` and :ref:`OrFilter + * ` blocks that are easier to * reason about from a probability perspective (i.e., setting to true will * cause the filter to behave like an independent random variable when * composed within logical operator filters). diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Admin.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Admin.ts new file mode 100644 index 000000000..a7f3826a1 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Admin.ts @@ -0,0 +1,75 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { SocketOption as _envoy_config_core_v3_SocketOption, SocketOption__Output as _envoy_config_core_v3_SocketOption__Output } from '../../../../envoy/config/core/v3/SocketOption'; +import type { AccessLog as _envoy_config_accesslog_v3_AccessLog, AccessLog__Output as _envoy_config_accesslog_v3_AccessLog__Output } from '../../../../envoy/config/accesslog/v3/AccessLog'; + +/** + * Administration interface :ref:`operations documentation + * `. + * [#next-free-field: 6] + */ +export interface Admin { + /** + * The path to write the access log for the administration server. If no + * access log is desired specify ‘/dev/null’. This is only required if + * :ref:`address ` is set. + * Deprecated in favor of *access_log* which offers more options. + */ + 'access_log_path'?: (string); + /** + * The cpu profiler output path for the administration server. If no profile + * path is specified, the default is ‘/var/log/envoy/envoy.prof’. + */ + 'profile_path'?: (string); + /** + * The TCP address that the administration server will listen on. + * If not specified, Envoy will not start an administration server. + */ + 'address'?: (_envoy_config_core_v3_Address | null); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ + 'socket_options'?: (_envoy_config_core_v3_SocketOption)[]; + /** + * Configuration for :ref:`access logs ` + * emitted by the administration server. + */ + 'access_log'?: (_envoy_config_accesslog_v3_AccessLog)[]; +} + +/** + * Administration interface :ref:`operations documentation + * `. + * [#next-free-field: 6] + */ +export interface Admin__Output { + /** + * The path to write the access log for the administration server. If no + * access log is desired specify ‘/dev/null’. This is only required if + * :ref:`address ` is set. + * Deprecated in favor of *access_log* which offers more options. + */ + 'access_log_path': (string); + /** + * The cpu profiler output path for the administration server. If no profile + * path is specified, the default is ‘/var/log/envoy/envoy.prof’. + */ + 'profile_path': (string); + /** + * The TCP address that the administration server will listen on. + * If not specified, Envoy will not start an administration server. + */ + 'address': (_envoy_config_core_v3_Address__Output | null); + /** + * Additional socket options that may not be present in Envoy source code or + * precompiled binaries. + */ + 'socket_options': (_envoy_config_core_v3_SocketOption__Output)[]; + /** + * Configuration for :ref:`access logs ` + * emitted by the administration server. + */ + 'access_log': (_envoy_config_accesslog_v3_AccessLog__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Bootstrap.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Bootstrap.ts new file mode 100644 index 000000000..797148675 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Bootstrap.ts @@ -0,0 +1,642 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { Node as _envoy_config_core_v3_Node, Node__Output as _envoy_config_core_v3_Node__Output } from '../../../../envoy/config/core/v3/Node'; +import type { ClusterManager as _envoy_config_bootstrap_v3_ClusterManager, ClusterManager__Output as _envoy_config_bootstrap_v3_ClusterManager__Output } from '../../../../envoy/config/bootstrap/v3/ClusterManager'; +import type { StatsSink as _envoy_config_metrics_v3_StatsSink, StatsSink__Output as _envoy_config_metrics_v3_StatsSink__Output } from '../../../../envoy/config/metrics/v3/StatsSink'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Watchdog as _envoy_config_bootstrap_v3_Watchdog, Watchdog__Output as _envoy_config_bootstrap_v3_Watchdog__Output } from '../../../../envoy/config/bootstrap/v3/Watchdog'; +import type { Tracing as _envoy_config_trace_v3_Tracing, Tracing__Output as _envoy_config_trace_v3_Tracing__Output } from '../../../../envoy/config/trace/v3/Tracing'; +import type { Admin as _envoy_config_bootstrap_v3_Admin, Admin__Output as _envoy_config_bootstrap_v3_Admin__Output } from '../../../../envoy/config/bootstrap/v3/Admin'; +import type { StatsConfig as _envoy_config_metrics_v3_StatsConfig, StatsConfig__Output as _envoy_config_metrics_v3_StatsConfig__Output } from '../../../../envoy/config/metrics/v3/StatsConfig'; +import type { ApiConfigSource as _envoy_config_core_v3_ApiConfigSource, ApiConfigSource__Output as _envoy_config_core_v3_ApiConfigSource__Output } from '../../../../envoy/config/core/v3/ApiConfigSource'; +import type { OverloadManager as _envoy_config_overload_v3_OverloadManager, OverloadManager__Output as _envoy_config_overload_v3_OverloadManager__Output } from '../../../../envoy/config/overload/v3/OverloadManager'; +import type { LayeredRuntime as _envoy_config_bootstrap_v3_LayeredRuntime, LayeredRuntime__Output as _envoy_config_bootstrap_v3_LayeredRuntime__Output } from '../../../../envoy/config/bootstrap/v3/LayeredRuntime'; +import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../../google/protobuf/UInt64Value'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../envoy/config/core/v3/ConfigSource'; +import type { Watchdogs as _envoy_config_bootstrap_v3_Watchdogs, Watchdogs__Output as _envoy_config_bootstrap_v3_Watchdogs__Output } from '../../../../envoy/config/bootstrap/v3/Watchdogs'; +import type { FatalAction as _envoy_config_bootstrap_v3_FatalAction, FatalAction__Output as _envoy_config_bootstrap_v3_FatalAction__Output } from '../../../../envoy/config/bootstrap/v3/FatalAction'; +import type { DnsResolutionConfig as _envoy_config_core_v3_DnsResolutionConfig, DnsResolutionConfig__Output as _envoy_config_core_v3_DnsResolutionConfig__Output } from '../../../../envoy/config/core/v3/DnsResolutionConfig'; +import type { CustomInlineHeader as _envoy_config_bootstrap_v3_CustomInlineHeader, CustomInlineHeader__Output as _envoy_config_bootstrap_v3_CustomInlineHeader__Output } from '../../../../envoy/config/bootstrap/v3/CustomInlineHeader'; +import type { Listener as _envoy_config_listener_v3_Listener, Listener__Output as _envoy_config_listener_v3_Listener__Output } from '../../../../envoy/config/listener/v3/Listener'; +import type { Cluster as _envoy_config_cluster_v3_Cluster, Cluster__Output as _envoy_config_cluster_v3_Cluster__Output } from '../../../../envoy/config/cluster/v3/Cluster'; +import type { Secret as _envoy_extensions_transport_sockets_tls_v3_Secret, Secret__Output as _envoy_extensions_transport_sockets_tls_v3_Secret__Output } from '../../../../envoy/extensions/transport_sockets/tls/v3/Secret'; +import type { Long } from '@grpc/proto-loader'; + +/** + * [#next-free-field: 7] + */ +export interface _envoy_config_bootstrap_v3_Bootstrap_DynamicResources { + /** + * All :ref:`Listeners ` are provided by a single + * :ref:`LDS ` configuration source. + */ + 'lds_config'?: (_envoy_config_core_v3_ConfigSource | null); + /** + * xdstp:// resource locator for listener collection. + * [#not-implemented-hide:] + */ + 'lds_resources_locator'?: (string); + /** + * All post-bootstrap :ref:`Cluster ` definitions are + * provided by a single :ref:`CDS ` + * configuration source. + */ + 'cds_config'?: (_envoy_config_core_v3_ConfigSource | null); + /** + * xdstp:// resource locator for cluster collection. + * [#not-implemented-hide:] + */ + 'cds_resources_locator'?: (string); + /** + * A single :ref:`ADS ` source may be optionally + * specified. This must have :ref:`api_type + * ` :ref:`GRPC + * `. Only + * :ref:`ConfigSources ` that have + * the :ref:`ads ` field set will be + * streamed on the ADS channel. + */ + 'ads_config'?: (_envoy_config_core_v3_ApiConfigSource | null); +} + +/** + * [#next-free-field: 7] + */ +export interface _envoy_config_bootstrap_v3_Bootstrap_DynamicResources__Output { + /** + * All :ref:`Listeners ` are provided by a single + * :ref:`LDS ` configuration source. + */ + 'lds_config': (_envoy_config_core_v3_ConfigSource__Output | null); + /** + * xdstp:// resource locator for listener collection. + * [#not-implemented-hide:] + */ + 'lds_resources_locator': (string); + /** + * All post-bootstrap :ref:`Cluster ` definitions are + * provided by a single :ref:`CDS ` + * configuration source. + */ + 'cds_config': (_envoy_config_core_v3_ConfigSource__Output | null); + /** + * xdstp:// resource locator for cluster collection. + * [#not-implemented-hide:] + */ + 'cds_resources_locator': (string); + /** + * A single :ref:`ADS ` source may be optionally + * specified. This must have :ref:`api_type + * ` :ref:`GRPC + * `. Only + * :ref:`ConfigSources ` that have + * the :ref:`ads ` field set will be + * streamed on the ADS channel. + */ + 'ads_config': (_envoy_config_core_v3_ApiConfigSource__Output | null); +} + +export interface _envoy_config_bootstrap_v3_Bootstrap_StaticResources { + /** + * Static :ref:`Listeners `. These listeners are + * available regardless of LDS configuration. + */ + 'listeners'?: (_envoy_config_listener_v3_Listener)[]; + /** + * If a network based configuration source is specified for :ref:`cds_config + * `, it's necessary + * to have some initial cluster definitions available to allow Envoy to know + * how to speak to the management server. These cluster definitions may not + * use :ref:`EDS ` (i.e. they should be static + * IP or DNS-based). + */ + 'clusters'?: (_envoy_config_cluster_v3_Cluster)[]; + /** + * These static secrets can be used by :ref:`SdsSecretConfig + * ` + */ + 'secrets'?: (_envoy_extensions_transport_sockets_tls_v3_Secret)[]; +} + +export interface _envoy_config_bootstrap_v3_Bootstrap_StaticResources__Output { + /** + * Static :ref:`Listeners `. These listeners are + * available regardless of LDS configuration. + */ + 'listeners': (_envoy_config_listener_v3_Listener__Output)[]; + /** + * If a network based configuration source is specified for :ref:`cds_config + * `, it's necessary + * to have some initial cluster definitions available to allow Envoy to know + * how to speak to the management server. These cluster definitions may not + * use :ref:`EDS ` (i.e. they should be static + * IP or DNS-based). + */ + 'clusters': (_envoy_config_cluster_v3_Cluster__Output)[]; + /** + * These static secrets can be used by :ref:`SdsSecretConfig + * ` + */ + 'secrets': (_envoy_extensions_transport_sockets_tls_v3_Secret__Output)[]; +} + +/** + * Bootstrap :ref:`configuration overview `. + * [#next-free-field: 33] + */ +export interface Bootstrap { + /** + * Node identity to present to the management server and for instance + * identification purposes (e.g. in generated headers). + */ + 'node'?: (_envoy_config_core_v3_Node | null); + /** + * Statically specified resources. + */ + 'static_resources'?: (_envoy_config_bootstrap_v3_Bootstrap_StaticResources | null); + /** + * xDS configuration sources. + */ + 'dynamic_resources'?: (_envoy_config_bootstrap_v3_Bootstrap_DynamicResources | null); + /** + * Configuration for the cluster manager which owns all upstream clusters + * within the server. + */ + 'cluster_manager'?: (_envoy_config_bootstrap_v3_ClusterManager | null); + /** + * Optional file system path to search for startup flag files. + */ + 'flags_path'?: (string); + /** + * Optional set of stats sinks. + */ + 'stats_sinks'?: (_envoy_config_metrics_v3_StatsSink)[]; + /** + * Optional duration between flushes to configured stats sinks. For + * performance reasons Envoy latches counters and only flushes counters and + * gauges at a periodic interval. If not specified the default is 5000ms (5 + * seconds). Only one of `stats_flush_interval` or `stats_flush_on_admin` + * can be set. + * Duration must be at least 1ms and at most 5 min. + */ + 'stats_flush_interval'?: (_google_protobuf_Duration | null); + /** + * Optional watchdog configuration. + * This is for a single watchdog configuration for the entire system. + * Deprecated in favor of *watchdogs* which has finer granularity. + */ + 'watchdog'?: (_envoy_config_bootstrap_v3_Watchdog | null); + /** + * Configuration for an external tracing provider. + * + * .. attention:: + * This field has been deprecated in favor of :ref:`HttpConnectionManager.Tracing.provider + * `. + */ + 'tracing'?: (_envoy_config_trace_v3_Tracing | null); + /** + * Configuration for the local administration HTTP server. + */ + 'admin'?: (_envoy_config_bootstrap_v3_Admin | null); + /** + * Configuration for internal processing of stats. + */ + 'stats_config'?: (_envoy_config_metrics_v3_StatsConfig | null); + /** + * Health discovery service config option. + * (:ref:`core.ApiConfigSource `) + */ + 'hds_config'?: (_envoy_config_core_v3_ApiConfigSource | null); + /** + * Optional overload manager configuration. + */ + 'overload_manager'?: (_envoy_config_overload_v3_OverloadManager | null); + /** + * Enable :ref:`stats for event dispatcher `, defaults to false. + * Note that this records a value for each iteration of the event loop on every thread. This + * should normally be minimal overhead, but when using + * :ref:`statsd `, it will send each observed value + * over the wire individually because the statsd protocol doesn't have any way to represent a + * histogram summary. Be aware that this can be a very large volume of data. + */ + 'enable_dispatcher_stats'?: (boolean); + /** + * Configuration for the runtime configuration provider. If not + * specified, a “null†provider will be used which will result in all defaults + * being used. + */ + 'layered_runtime'?: (_envoy_config_bootstrap_v3_LayeredRuntime | null); + /** + * Optional string which will be used in lieu of x-envoy in prefixing headers. + * + * For example, if this string is present and set to X-Foo, then x-envoy-retry-on will be + * transformed into x-foo-retry-on etc. + * + * Note this applies to the headers Envoy will generate, the headers Envoy will sanitize, and the + * headers Envoy will trust for core code and core extensions only. Be VERY careful making + * changes to this string, especially in multi-layer Envoy deployments or deployments using + * extensions which are not upstream. + */ + 'header_prefix'?: (string); + /** + * Optional proxy version which will be used to set the value of :ref:`server.version statistic + * ` if specified. Envoy will not process this value, it will be sent as is to + * :ref:`stats sinks `. + */ + 'stats_server_version_override'?: (_google_protobuf_UInt64Value | null); + /** + * Always use TCP queries instead of UDP queries for DNS lookups. + * This may be overridden on a per-cluster basis in cds_config, + * when :ref:`dns_resolvers ` and + * :ref:`use_tcp_for_dns_lookups ` are + * specified. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple' API only uses UDP for DNS resolution. + * This field is deprecated in favor of *dns_resolution_config* + * which aggregates all of the DNS resolver configuration in a single message. + */ + 'use_tcp_for_dns_lookups'?: (boolean); + /** + * Specifies optional bootstrap extensions to be instantiated at startup time. + * Each item contains extension specific configuration. + * [#extension-category: envoy.bootstrap] + */ + 'bootstrap_extensions'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; + /** + * Configuration sources that will participate in + * xdstp:// URL authority resolution. The algorithm is as + * follows: + * 1. The authority field is taken from the xdstp:// URL, call + * this *resource_authority*. + * 2. *resource_authority* is compared against the authorities in any peer + * *ConfigSource*. The peer *ConfigSource* is the configuration source + * message which would have been used unconditionally for resolution + * with opaque resource names. If there is a match with an authority, the + * peer *ConfigSource* message is used. + * 3. *resource_authority* is compared sequentially with the authorities in + * each configuration source in *config_sources*. The first *ConfigSource* + * to match wins. + * 4. As a fallback, if no configuration source matches, then + * *default_config_source* is used. + * 5. If *default_config_source* is not specified, resolution fails. + * [#not-implemented-hide:] + */ + 'config_sources'?: (_envoy_config_core_v3_ConfigSource)[]; + /** + * Default configuration source for xdstp:// URLs if all + * other resolution fails. + * [#not-implemented-hide:] + */ + 'default_config_source'?: (_envoy_config_core_v3_ConfigSource | null); + /** + * Optional overriding of default socket interface. The value must be the name of one of the + * socket interface factories initialized through a bootstrap extension + */ + 'default_socket_interface'?: (string); + /** + * Global map of CertificateProvider instances. These instances are referred to by name in the + * :ref:`CommonTlsContext.CertificateProviderInstance.instance_name + * ` + * field. + * [#not-implemented-hide:] + */ + 'certificate_provider_instances'?: ({[key: string]: _envoy_config_core_v3_TypedExtensionConfig}); + /** + * A list of :ref:`Node ` field names + * that will be included in the context parameters of the effective + * xdstp:// URL that is sent in a discovery request when resource + * locators are used for LDS/CDS. Any non-string field will have its JSON + * encoding set as the context parameter value, with the exception of + * metadata, which will be flattened (see example below). The supported field + * names are: + * - "cluster" + * - "id" + * - "locality.region" + * - "locality.sub_zone" + * - "locality.zone" + * - "metadata" + * - "user_agent_build_version.metadata" + * - "user_agent_build_version.version" + * - "user_agent_name" + * - "user_agent_version" + * + * The node context parameters act as a base layer dictionary for the context + * parameters (i.e. more specific resource specific context parameters will + * override). Field names will be prefixed with “udpa.node.†when included in + * context parameters. + * + * For example, if node_context_params is ``["user_agent_name", "metadata"]``, + * the implied context parameters might be:: + * + * node.user_agent_name: "envoy" + * node.metadata.foo: "{\"bar\": \"baz\"}" + * node.metadata.some: "42" + * node.metadata.thing: "\"thing\"" + * + * [#not-implemented-hide:] + */ + 'node_context_params'?: (string)[]; + /** + * Optional watchdogs configuration. + * This is used for specifying different watchdogs for the different subsystems. + * [#extension-category: envoy.guarddog_actions] + */ + 'watchdogs'?: (_envoy_config_bootstrap_v3_Watchdogs | null); + /** + * Specifies optional extensions instantiated at startup time and + * invoked during crash time on the request that caused the crash. + */ + 'fatal_actions'?: (_envoy_config_bootstrap_v3_FatalAction)[]; + /** + * Flush stats to sinks only when queried for on the admin interface. If set, + * a flush timer is not created. Only one of `stats_flush_on_admin` or + * `stats_flush_interval` can be set. + */ + 'stats_flush_on_admin'?: (boolean); + /** + * DNS resolution configuration which includes the underlying dns resolver addresses and options. + * This may be overridden on a per-cluster basis in cds_config, when + * :ref:`dns_resolution_config ` + * is specified. + * *dns_resolution_config* will be deprecated once + * :ref:'typed_dns_resolver_config ' + * is fully supported. + */ + 'dns_resolution_config'?: (_envoy_config_core_v3_DnsResolutionConfig | null); + /** + * DNS resolver type configuration extension. This extension can be used to configure c-ares, apple, + * or any other DNS resolver types and the related parameters. + * For example, an object of :ref:`DnsResolutionConfig ` + * can be packed into this *typed_dns_resolver_config*. This configuration will replace the + * :ref:'dns_resolution_config ' + * configuration eventually. + * TODO(yanjunxiang): Investigate the deprecation plan for *dns_resolution_config*. + * During the transition period when both *dns_resolution_config* and *typed_dns_resolver_config* exists, + * this configuration is optional. + * When *typed_dns_resolver_config* is in place, Envoy will use it and ignore *dns_resolution_config*. + * When *typed_dns_resolver_config* is missing, the default behavior is in place. + * [#not-implemented-hide:] + */ + 'typed_dns_resolver_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + /** + * Specifies a set of headers that need to be registered as inline header. This configuration + * allows users to customize the inline headers on-demand at Envoy startup without modifying + * Envoy's source code. + * + * Note that the 'set-cookie' header cannot be registered as inline header. + */ + 'inline_headers'?: (_envoy_config_bootstrap_v3_CustomInlineHeader)[]; + 'stats_flush'?: "stats_flush_on_admin"; +} + +/** + * Bootstrap :ref:`configuration overview `. + * [#next-free-field: 33] + */ +export interface Bootstrap__Output { + /** + * Node identity to present to the management server and for instance + * identification purposes (e.g. in generated headers). + */ + 'node': (_envoy_config_core_v3_Node__Output | null); + /** + * Statically specified resources. + */ + 'static_resources': (_envoy_config_bootstrap_v3_Bootstrap_StaticResources__Output | null); + /** + * xDS configuration sources. + */ + 'dynamic_resources': (_envoy_config_bootstrap_v3_Bootstrap_DynamicResources__Output | null); + /** + * Configuration for the cluster manager which owns all upstream clusters + * within the server. + */ + 'cluster_manager': (_envoy_config_bootstrap_v3_ClusterManager__Output | null); + /** + * Optional file system path to search for startup flag files. + */ + 'flags_path': (string); + /** + * Optional set of stats sinks. + */ + 'stats_sinks': (_envoy_config_metrics_v3_StatsSink__Output)[]; + /** + * Optional duration between flushes to configured stats sinks. For + * performance reasons Envoy latches counters and only flushes counters and + * gauges at a periodic interval. If not specified the default is 5000ms (5 + * seconds). Only one of `stats_flush_interval` or `stats_flush_on_admin` + * can be set. + * Duration must be at least 1ms and at most 5 min. + */ + 'stats_flush_interval': (_google_protobuf_Duration__Output | null); + /** + * Optional watchdog configuration. + * This is for a single watchdog configuration for the entire system. + * Deprecated in favor of *watchdogs* which has finer granularity. + */ + 'watchdog': (_envoy_config_bootstrap_v3_Watchdog__Output | null); + /** + * Configuration for an external tracing provider. + * + * .. attention:: + * This field has been deprecated in favor of :ref:`HttpConnectionManager.Tracing.provider + * `. + */ + 'tracing': (_envoy_config_trace_v3_Tracing__Output | null); + /** + * Configuration for the local administration HTTP server. + */ + 'admin': (_envoy_config_bootstrap_v3_Admin__Output | null); + /** + * Configuration for internal processing of stats. + */ + 'stats_config': (_envoy_config_metrics_v3_StatsConfig__Output | null); + /** + * Health discovery service config option. + * (:ref:`core.ApiConfigSource `) + */ + 'hds_config': (_envoy_config_core_v3_ApiConfigSource__Output | null); + /** + * Optional overload manager configuration. + */ + 'overload_manager': (_envoy_config_overload_v3_OverloadManager__Output | null); + /** + * Enable :ref:`stats for event dispatcher `, defaults to false. + * Note that this records a value for each iteration of the event loop on every thread. This + * should normally be minimal overhead, but when using + * :ref:`statsd `, it will send each observed value + * over the wire individually because the statsd protocol doesn't have any way to represent a + * histogram summary. Be aware that this can be a very large volume of data. + */ + 'enable_dispatcher_stats': (boolean); + /** + * Configuration for the runtime configuration provider. If not + * specified, a “null†provider will be used which will result in all defaults + * being used. + */ + 'layered_runtime': (_envoy_config_bootstrap_v3_LayeredRuntime__Output | null); + /** + * Optional string which will be used in lieu of x-envoy in prefixing headers. + * + * For example, if this string is present and set to X-Foo, then x-envoy-retry-on will be + * transformed into x-foo-retry-on etc. + * + * Note this applies to the headers Envoy will generate, the headers Envoy will sanitize, and the + * headers Envoy will trust for core code and core extensions only. Be VERY careful making + * changes to this string, especially in multi-layer Envoy deployments or deployments using + * extensions which are not upstream. + */ + 'header_prefix': (string); + /** + * Optional proxy version which will be used to set the value of :ref:`server.version statistic + * ` if specified. Envoy will not process this value, it will be sent as is to + * :ref:`stats sinks `. + */ + 'stats_server_version_override': (_google_protobuf_UInt64Value__Output | null); + /** + * Always use TCP queries instead of UDP queries for DNS lookups. + * This may be overridden on a per-cluster basis in cds_config, + * when :ref:`dns_resolvers ` and + * :ref:`use_tcp_for_dns_lookups ` are + * specified. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple' API only uses UDP for DNS resolution. + * This field is deprecated in favor of *dns_resolution_config* + * which aggregates all of the DNS resolver configuration in a single message. + */ + 'use_tcp_for_dns_lookups': (boolean); + /** + * Specifies optional bootstrap extensions to be instantiated at startup time. + * Each item contains extension specific configuration. + * [#extension-category: envoy.bootstrap] + */ + 'bootstrap_extensions': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; + /** + * Configuration sources that will participate in + * xdstp:// URL authority resolution. The algorithm is as + * follows: + * 1. The authority field is taken from the xdstp:// URL, call + * this *resource_authority*. + * 2. *resource_authority* is compared against the authorities in any peer + * *ConfigSource*. The peer *ConfigSource* is the configuration source + * message which would have been used unconditionally for resolution + * with opaque resource names. If there is a match with an authority, the + * peer *ConfigSource* message is used. + * 3. *resource_authority* is compared sequentially with the authorities in + * each configuration source in *config_sources*. The first *ConfigSource* + * to match wins. + * 4. As a fallback, if no configuration source matches, then + * *default_config_source* is used. + * 5. If *default_config_source* is not specified, resolution fails. + * [#not-implemented-hide:] + */ + 'config_sources': (_envoy_config_core_v3_ConfigSource__Output)[]; + /** + * Default configuration source for xdstp:// URLs if all + * other resolution fails. + * [#not-implemented-hide:] + */ + 'default_config_source': (_envoy_config_core_v3_ConfigSource__Output | null); + /** + * Optional overriding of default socket interface. The value must be the name of one of the + * socket interface factories initialized through a bootstrap extension + */ + 'default_socket_interface': (string); + /** + * Global map of CertificateProvider instances. These instances are referred to by name in the + * :ref:`CommonTlsContext.CertificateProviderInstance.instance_name + * ` + * field. + * [#not-implemented-hide:] + */ + 'certificate_provider_instances': ({[key: string]: _envoy_config_core_v3_TypedExtensionConfig__Output}); + /** + * A list of :ref:`Node ` field names + * that will be included in the context parameters of the effective + * xdstp:// URL that is sent in a discovery request when resource + * locators are used for LDS/CDS. Any non-string field will have its JSON + * encoding set as the context parameter value, with the exception of + * metadata, which will be flattened (see example below). The supported field + * names are: + * - "cluster" + * - "id" + * - "locality.region" + * - "locality.sub_zone" + * - "locality.zone" + * - "metadata" + * - "user_agent_build_version.metadata" + * - "user_agent_build_version.version" + * - "user_agent_name" + * - "user_agent_version" + * + * The node context parameters act as a base layer dictionary for the context + * parameters (i.e. more specific resource specific context parameters will + * override). Field names will be prefixed with “udpa.node.†when included in + * context parameters. + * + * For example, if node_context_params is ``["user_agent_name", "metadata"]``, + * the implied context parameters might be:: + * + * node.user_agent_name: "envoy" + * node.metadata.foo: "{\"bar\": \"baz\"}" + * node.metadata.some: "42" + * node.metadata.thing: "\"thing\"" + * + * [#not-implemented-hide:] + */ + 'node_context_params': (string)[]; + /** + * Optional watchdogs configuration. + * This is used for specifying different watchdogs for the different subsystems. + * [#extension-category: envoy.guarddog_actions] + */ + 'watchdogs': (_envoy_config_bootstrap_v3_Watchdogs__Output | null); + /** + * Specifies optional extensions instantiated at startup time and + * invoked during crash time on the request that caused the crash. + */ + 'fatal_actions': (_envoy_config_bootstrap_v3_FatalAction__Output)[]; + /** + * Flush stats to sinks only when queried for on the admin interface. If set, + * a flush timer is not created. Only one of `stats_flush_on_admin` or + * `stats_flush_interval` can be set. + */ + 'stats_flush_on_admin'?: (boolean); + /** + * DNS resolution configuration which includes the underlying dns resolver addresses and options. + * This may be overridden on a per-cluster basis in cds_config, when + * :ref:`dns_resolution_config ` + * is specified. + * *dns_resolution_config* will be deprecated once + * :ref:'typed_dns_resolver_config ' + * is fully supported. + */ + 'dns_resolution_config': (_envoy_config_core_v3_DnsResolutionConfig__Output | null); + /** + * DNS resolver type configuration extension. This extension can be used to configure c-ares, apple, + * or any other DNS resolver types and the related parameters. + * For example, an object of :ref:`DnsResolutionConfig ` + * can be packed into this *typed_dns_resolver_config*. This configuration will replace the + * :ref:'dns_resolution_config ' + * configuration eventually. + * TODO(yanjunxiang): Investigate the deprecation plan for *dns_resolution_config*. + * During the transition period when both *dns_resolution_config* and *typed_dns_resolver_config* exists, + * this configuration is optional. + * When *typed_dns_resolver_config* is in place, Envoy will use it and ignore *dns_resolution_config*. + * When *typed_dns_resolver_config* is missing, the default behavior is in place. + * [#not-implemented-hide:] + */ + 'typed_dns_resolver_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + /** + * Specifies a set of headers that need to be registered as inline header. This configuration + * allows users to customize the inline headers on-demand at Envoy startup without modifying + * Envoy's source code. + * + * Note that the 'set-cookie' header cannot be registered as inline header. + */ + 'inline_headers': (_envoy_config_bootstrap_v3_CustomInlineHeader__Output)[]; + 'stats_flush': "stats_flush_on_admin"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/ClusterManager.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/ClusterManager.ts new file mode 100644 index 000000000..571b96fb7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/ClusterManager.ts @@ -0,0 +1,99 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { BindConfig as _envoy_config_core_v3_BindConfig, BindConfig__Output as _envoy_config_core_v3_BindConfig__Output } from '../../../../envoy/config/core/v3/BindConfig'; +import type { ApiConfigSource as _envoy_config_core_v3_ApiConfigSource, ApiConfigSource__Output as _envoy_config_core_v3_ApiConfigSource__Output } from '../../../../envoy/config/core/v3/ApiConfigSource'; +import type { EventServiceConfig as _envoy_config_core_v3_EventServiceConfig, EventServiceConfig__Output as _envoy_config_core_v3_EventServiceConfig__Output } from '../../../../envoy/config/core/v3/EventServiceConfig'; + +export interface _envoy_config_bootstrap_v3_ClusterManager_OutlierDetection { + /** + * Specifies the path to the outlier event log. + */ + 'event_log_path'?: (string); + /** + * [#not-implemented-hide:] + * The gRPC service for the outlier detection event service. + * If empty, outlier detection events won't be sent to a remote endpoint. + */ + 'event_service'?: (_envoy_config_core_v3_EventServiceConfig | null); +} + +export interface _envoy_config_bootstrap_v3_ClusterManager_OutlierDetection__Output { + /** + * Specifies the path to the outlier event log. + */ + 'event_log_path': (string); + /** + * [#not-implemented-hide:] + * The gRPC service for the outlier detection event service. + * If empty, outlier detection events won't be sent to a remote endpoint. + */ + 'event_service': (_envoy_config_core_v3_EventServiceConfig__Output | null); +} + +/** + * Cluster manager :ref:`architecture overview `. + */ +export interface ClusterManager { + /** + * Name of the local cluster (i.e., the cluster that owns the Envoy running + * this configuration). In order to enable :ref:`zone aware routing + * ` this option must be set. + * If *local_cluster_name* is defined then :ref:`clusters + * ` must be defined in the :ref:`Bootstrap + * static cluster resources + * `. This is unrelated to + * the :option:`--service-cluster` option which does not `affect zone aware + * routing `_. + */ + 'local_cluster_name'?: (string); + /** + * Optional global configuration for outlier detection. + */ + 'outlier_detection'?: (_envoy_config_bootstrap_v3_ClusterManager_OutlierDetection | null); + /** + * Optional configuration used to bind newly established upstream connections. + * This may be overridden on a per-cluster basis by upstream_bind_config in the cds_config. + */ + 'upstream_bind_config'?: (_envoy_config_core_v3_BindConfig | null); + /** + * A management server endpoint to stream load stats to via + * *StreamLoadStats*. This must have :ref:`api_type + * ` :ref:`GRPC + * `. + */ + 'load_stats_config'?: (_envoy_config_core_v3_ApiConfigSource | null); +} + +/** + * Cluster manager :ref:`architecture overview `. + */ +export interface ClusterManager__Output { + /** + * Name of the local cluster (i.e., the cluster that owns the Envoy running + * this configuration). In order to enable :ref:`zone aware routing + * ` this option must be set. + * If *local_cluster_name* is defined then :ref:`clusters + * ` must be defined in the :ref:`Bootstrap + * static cluster resources + * `. This is unrelated to + * the :option:`--service-cluster` option which does not `affect zone aware + * routing `_. + */ + 'local_cluster_name': (string); + /** + * Optional global configuration for outlier detection. + */ + 'outlier_detection': (_envoy_config_bootstrap_v3_ClusterManager_OutlierDetection__Output | null); + /** + * Optional configuration used to bind newly established upstream connections. + * This may be overridden on a per-cluster basis by upstream_bind_config in the cds_config. + */ + 'upstream_bind_config': (_envoy_config_core_v3_BindConfig__Output | null); + /** + * A management server endpoint to stream load stats to via + * *StreamLoadStats*. This must have :ref:`api_type + * ` :ref:`GRPC + * `. + */ + 'load_stats_config': (_envoy_config_core_v3_ApiConfigSource__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/CustomInlineHeader.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/CustomInlineHeader.ts new file mode 100644 index 000000000..f0e2d29aa --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/CustomInlineHeader.ts @@ -0,0 +1,85 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + + +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +export enum _envoy_config_bootstrap_v3_CustomInlineHeader_InlineHeaderType { + REQUEST_HEADER = 0, + REQUEST_TRAILER = 1, + RESPONSE_HEADER = 2, + RESPONSE_TRAILER = 3, +} + +/** + * Used to specify the header that needs to be registered as an inline header. + * + * If request or response contain multiple headers with the same name and the header + * name is registered as an inline header. Then multiple headers will be folded + * into one, and multiple header values will be concatenated by a suitable delimiter. + * The delimiter is generally a comma. + * + * For example, if 'foo' is registered as an inline header, and the headers contains + * the following two headers: + * + * .. code-block:: text + * + * foo: bar + * foo: eep + * + * Then they will eventually be folded into: + * + * .. code-block:: text + * + * foo: bar, eep + * + * Inline headers provide O(1) search performance, but each inline header imposes + * an additional memory overhead on all instances of the corresponding type of + * HeaderMap or TrailerMap. + */ +export interface CustomInlineHeader { + /** + * The name of the header that is expected to be set as the inline header. + */ + 'inline_header_name'?: (string); + /** + * The type of the header that is expected to be set as the inline header. + */ + 'inline_header_type'?: (_envoy_config_bootstrap_v3_CustomInlineHeader_InlineHeaderType | keyof typeof _envoy_config_bootstrap_v3_CustomInlineHeader_InlineHeaderType); +} + +/** + * Used to specify the header that needs to be registered as an inline header. + * + * If request or response contain multiple headers with the same name and the header + * name is registered as an inline header. Then multiple headers will be folded + * into one, and multiple header values will be concatenated by a suitable delimiter. + * The delimiter is generally a comma. + * + * For example, if 'foo' is registered as an inline header, and the headers contains + * the following two headers: + * + * .. code-block:: text + * + * foo: bar + * foo: eep + * + * Then they will eventually be folded into: + * + * .. code-block:: text + * + * foo: bar, eep + * + * Inline headers provide O(1) search performance, but each inline header imposes + * an additional memory overhead on all instances of the corresponding type of + * HeaderMap or TrailerMap. + */ +export interface CustomInlineHeader__Output { + /** + * The name of the header that is expected to be set as the inline header. + */ + 'inline_header_name': (string); + /** + * The type of the header that is expected to be set as the inline header. + */ + 'inline_header_type': (keyof typeof _envoy_config_bootstrap_v3_CustomInlineHeader_InlineHeaderType); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/FatalAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/FatalAction.ts new file mode 100644 index 000000000..236afded5 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/FatalAction.ts @@ -0,0 +1,39 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * Fatal actions to run while crashing. Actions can be safe (meaning they are + * async-signal safe) or unsafe. We run all safe actions before we run unsafe actions. + * If using an unsafe action that could get stuck or deadlock, it important to + * have an out of band system to terminate the process. + * + * The interface for the extension is ``Envoy::Server::Configuration::FatalAction``. + * *FatalAction* extensions live in the ``envoy.extensions.fatal_actions`` API + * namespace. + */ +export interface FatalAction { + /** + * Extension specific configuration for the action. It's expected to conform + * to the ``Envoy::Server::Configuration::FatalAction`` interface. + */ + 'config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); +} + +/** + * Fatal actions to run while crashing. Actions can be safe (meaning they are + * async-signal safe) or unsafe. We run all safe actions before we run unsafe actions. + * If using an unsafe action that could get stuck or deadlock, it important to + * have an out of band system to terminate the process. + * + * The interface for the extension is ``Envoy::Server::Configuration::FatalAction``. + * *FatalAction* extensions live in the ``envoy.extensions.fatal_actions`` API + * namespace. + */ +export interface FatalAction__Output { + /** + * Extension specific configuration for the action. It's expected to conform + * to the ``Envoy::Server::Configuration::FatalAction`` interface. + */ + 'config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/LayeredRuntime.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/LayeredRuntime.ts new file mode 100644 index 000000000..3514d3140 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/LayeredRuntime.ts @@ -0,0 +1,25 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { RuntimeLayer as _envoy_config_bootstrap_v3_RuntimeLayer, RuntimeLayer__Output as _envoy_config_bootstrap_v3_RuntimeLayer__Output } from '../../../../envoy/config/bootstrap/v3/RuntimeLayer'; + +/** + * Runtime :ref:`configuration overview `. + */ +export interface LayeredRuntime { + /** + * The :ref:`layers ` of the runtime. This is ordered + * such that later layers in the list overlay earlier entries. + */ + 'layers'?: (_envoy_config_bootstrap_v3_RuntimeLayer)[]; +} + +/** + * Runtime :ref:`configuration overview `. + */ +export interface LayeredRuntime__Output { + /** + * The :ref:`layers ` of the runtime. This is ordered + * such that later layers in the list overlay earlier entries. + */ + 'layers': (_envoy_config_bootstrap_v3_RuntimeLayer__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Runtime.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Runtime.ts new file mode 100644 index 000000000..4f7713bcf --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Runtime.ts @@ -0,0 +1,77 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; + +/** + * Runtime :ref:`configuration overview ` (deprecated). + */ +export interface Runtime { + /** + * The implementation assumes that the file system tree is accessed via a + * symbolic link. An atomic link swap is used when a new tree should be + * switched to. This parameter specifies the path to the symbolic link. Envoy + * will watch the location for changes and reload the file system tree when + * they happen. If this parameter is not set, there will be no disk based + * runtime. + */ + 'symlink_root'?: (string); + /** + * Specifies the subdirectory to load within the root directory. This is + * useful if multiple systems share the same delivery mechanism. Envoy + * configuration elements can be contained in a dedicated subdirectory. + */ + 'subdirectory'?: (string); + /** + * Specifies an optional subdirectory to load within the root directory. If + * specified and the directory exists, configuration values within this + * directory will override those found in the primary subdirectory. This is + * useful when Envoy is deployed across many different types of servers. + * Sometimes it is useful to have a per service cluster directory for runtime + * configuration. See below for exactly how the override directory is used. + */ + 'override_subdirectory'?: (string); + /** + * Static base runtime. This will be :ref:`overridden + * ` by other runtime layers, e.g. + * disk or admin. This follows the :ref:`runtime protobuf JSON representation + * encoding `. + */ + 'base'?: (_google_protobuf_Struct | null); +} + +/** + * Runtime :ref:`configuration overview ` (deprecated). + */ +export interface Runtime__Output { + /** + * The implementation assumes that the file system tree is accessed via a + * symbolic link. An atomic link swap is used when a new tree should be + * switched to. This parameter specifies the path to the symbolic link. Envoy + * will watch the location for changes and reload the file system tree when + * they happen. If this parameter is not set, there will be no disk based + * runtime. + */ + 'symlink_root': (string); + /** + * Specifies the subdirectory to load within the root directory. This is + * useful if multiple systems share the same delivery mechanism. Envoy + * configuration elements can be contained in a dedicated subdirectory. + */ + 'subdirectory': (string); + /** + * Specifies an optional subdirectory to load within the root directory. If + * specified and the directory exists, configuration values within this + * directory will override those found in the primary subdirectory. This is + * useful when Envoy is deployed across many different types of servers. + * Sometimes it is useful to have a per service cluster directory for runtime + * configuration. See below for exactly how the override directory is used. + */ + 'override_subdirectory': (string); + /** + * Static base runtime. This will be :ref:`overridden + * ` by other runtime layers, e.g. + * disk or admin. This follows the :ref:`runtime protobuf JSON representation + * encoding `. + */ + 'base': (_google_protobuf_Struct__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/RuntimeLayer.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/RuntimeLayer.ts new file mode 100644 index 000000000..b072bfa7d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/RuntimeLayer.ts @@ -0,0 +1,142 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../envoy/config/core/v3/ConfigSource'; + +/** + * :ref:`Admin console runtime ` layer. + */ +export interface _envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer { +} + +/** + * :ref:`Admin console runtime ` layer. + */ +export interface _envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer__Output { +} + +/** + * :ref:`Disk runtime ` layer. + */ +export interface _envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer { + /** + * The implementation assumes that the file system tree is accessed via a + * symbolic link. An atomic link swap is used when a new tree should be + * switched to. This parameter specifies the path to the symbolic link. + * Envoy will watch the location for changes and reload the file system tree + * when they happen. See documentation on runtime :ref:`atomicity + * ` for further details on how reloads are + * treated. + */ + 'symlink_root'?: (string); + /** + * Specifies the subdirectory to load within the root directory. This is + * useful if multiple systems share the same delivery mechanism. Envoy + * configuration elements can be contained in a dedicated subdirectory. + */ + 'subdirectory'?: (string); + /** + * :ref:`Append ` the + * service cluster to the path under symlink root. + */ + 'append_service_cluster'?: (boolean); +} + +/** + * :ref:`Disk runtime ` layer. + */ +export interface _envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer__Output { + /** + * The implementation assumes that the file system tree is accessed via a + * symbolic link. An atomic link swap is used when a new tree should be + * switched to. This parameter specifies the path to the symbolic link. + * Envoy will watch the location for changes and reload the file system tree + * when they happen. See documentation on runtime :ref:`atomicity + * ` for further details on how reloads are + * treated. + */ + 'symlink_root': (string); + /** + * Specifies the subdirectory to load within the root directory. This is + * useful if multiple systems share the same delivery mechanism. Envoy + * configuration elements can be contained in a dedicated subdirectory. + */ + 'subdirectory': (string); + /** + * :ref:`Append ` the + * service cluster to the path under symlink root. + */ + 'append_service_cluster': (boolean); +} + +/** + * :ref:`Runtime Discovery Service (RTDS) ` layer. + */ +export interface _envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer { + /** + * Resource to subscribe to at *rtds_config* for the RTDS layer. + */ + 'name'?: (string); + /** + * RTDS configuration source. + */ + 'rtds_config'?: (_envoy_config_core_v3_ConfigSource | null); +} + +/** + * :ref:`Runtime Discovery Service (RTDS) ` layer. + */ +export interface _envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer__Output { + /** + * Resource to subscribe to at *rtds_config* for the RTDS layer. + */ + 'name': (string); + /** + * RTDS configuration source. + */ + 'rtds_config': (_envoy_config_core_v3_ConfigSource__Output | null); +} + +/** + * [#next-free-field: 6] + */ +export interface RuntimeLayer { + /** + * Descriptive name for the runtime layer. This is only used for the runtime + * :http:get:`/runtime` output. + */ + 'name'?: (string); + /** + * :ref:`Static runtime ` layer. + * This follows the :ref:`runtime protobuf JSON representation encoding + * `. Unlike static xDS resources, this static + * layer is overridable by later layers in the runtime virtual filesystem. + */ + 'static_layer'?: (_google_protobuf_Struct | null); + 'disk_layer'?: (_envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer | null); + 'admin_layer'?: (_envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer | null); + 'rtds_layer'?: (_envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer | null); + 'layer_specifier'?: "static_layer"|"disk_layer"|"admin_layer"|"rtds_layer"; +} + +/** + * [#next-free-field: 6] + */ +export interface RuntimeLayer__Output { + /** + * Descriptive name for the runtime layer. This is only used for the runtime + * :http:get:`/runtime` output. + */ + 'name': (string); + /** + * :ref:`Static runtime ` layer. + * This follows the :ref:`runtime protobuf JSON representation encoding + * `. Unlike static xDS resources, this static + * layer is overridable by later layers in the runtime virtual filesystem. + */ + 'static_layer'?: (_google_protobuf_Struct__Output | null); + 'disk_layer'?: (_envoy_config_bootstrap_v3_RuntimeLayer_DiskLayer__Output | null); + 'admin_layer'?: (_envoy_config_bootstrap_v3_RuntimeLayer_AdminLayer__Output | null); + 'rtds_layer'?: (_envoy_config_bootstrap_v3_RuntimeLayer_RtdsLayer__Output | null); + 'layer_specifier': "static_layer"|"disk_layer"|"admin_layer"|"rtds_layer"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdog.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdog.ts new file mode 100644 index 000000000..8cd743b56 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdog.ts @@ -0,0 +1,141 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../envoy/type/v3/Percent'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +export interface _envoy_config_bootstrap_v3_Watchdog_WatchdogAction { + /** + * Extension specific configuration for the action. + */ + 'config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + 'event'?: (_envoy_config_bootstrap_v3_Watchdog_WatchdogAction_WatchdogEvent | keyof typeof _envoy_config_bootstrap_v3_Watchdog_WatchdogAction_WatchdogEvent); +} + +export interface _envoy_config_bootstrap_v3_Watchdog_WatchdogAction__Output { + /** + * Extension specific configuration for the action. + */ + 'config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + 'event': (keyof typeof _envoy_config_bootstrap_v3_Watchdog_WatchdogAction_WatchdogEvent); +} + +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +/** + * The events are fired in this order: KILL, MULTIKILL, MEGAMISS, MISS. + * Within an event type, actions execute in the order they are configured. + * For KILL/MULTIKILL there is a default PANIC that will run after the + * registered actions and kills the process if it wasn't already killed. + * It might be useful to specify several debug actions, and possibly an + * alternate FATAL action. + */ +export enum _envoy_config_bootstrap_v3_Watchdog_WatchdogAction_WatchdogEvent { + UNKNOWN = 0, + KILL = 1, + MULTIKILL = 2, + MEGAMISS = 3, + MISS = 4, +} + +/** + * Envoy process watchdog configuration. When configured, this monitors for + * nonresponsive threads and kills the process after the configured thresholds. + * See the :ref:`watchdog documentation ` for more information. + * [#next-free-field: 8] + */ +export interface Watchdog { + /** + * The duration after which Envoy counts a nonresponsive thread in the + * *watchdog_miss* statistic. If not specified the default is 200ms. + */ + 'miss_timeout'?: (_google_protobuf_Duration | null); + /** + * The duration after which Envoy counts a nonresponsive thread in the + * *watchdog_mega_miss* statistic. If not specified the default is + * 1000ms. + */ + 'megamiss_timeout'?: (_google_protobuf_Duration | null); + /** + * If a watched thread has been nonresponsive for this duration, assume a + * programming error and kill the entire Envoy process. Set to 0 to disable + * kill behavior. If not specified the default is 0 (disabled). + */ + 'kill_timeout'?: (_google_protobuf_Duration | null); + /** + * If max(2, ceil(registered_threads * Fraction(*multikill_threshold*))) + * threads have been nonresponsive for at least this duration kill the entire + * Envoy process. Set to 0 to disable this behavior. If not specified the + * default is 0 (disabled). + */ + 'multikill_timeout'?: (_google_protobuf_Duration | null); + /** + * Sets the threshold for *multikill_timeout* in terms of the percentage of + * nonresponsive threads required for the *multikill_timeout*. + * If not specified the default is 0. + */ + 'multikill_threshold'?: (_envoy_type_v3_Percent | null); + /** + * Defines the maximum jitter used to adjust the *kill_timeout* if *kill_timeout* is + * enabled. Enabling this feature would help to reduce risk of synchronized + * watchdog kill events across proxies due to external triggers. Set to 0 to + * disable. If not specified the default is 0 (disabled). + */ + 'max_kill_timeout_jitter'?: (_google_protobuf_Duration | null); + /** + * Register actions that will fire on given WatchDog events. + * See *WatchDogAction* for priority of events. + */ + 'actions'?: (_envoy_config_bootstrap_v3_Watchdog_WatchdogAction)[]; +} + +/** + * Envoy process watchdog configuration. When configured, this monitors for + * nonresponsive threads and kills the process after the configured thresholds. + * See the :ref:`watchdog documentation ` for more information. + * [#next-free-field: 8] + */ +export interface Watchdog__Output { + /** + * The duration after which Envoy counts a nonresponsive thread in the + * *watchdog_miss* statistic. If not specified the default is 200ms. + */ + 'miss_timeout': (_google_protobuf_Duration__Output | null); + /** + * The duration after which Envoy counts a nonresponsive thread in the + * *watchdog_mega_miss* statistic. If not specified the default is + * 1000ms. + */ + 'megamiss_timeout': (_google_protobuf_Duration__Output | null); + /** + * If a watched thread has been nonresponsive for this duration, assume a + * programming error and kill the entire Envoy process. Set to 0 to disable + * kill behavior. If not specified the default is 0 (disabled). + */ + 'kill_timeout': (_google_protobuf_Duration__Output | null); + /** + * If max(2, ceil(registered_threads * Fraction(*multikill_threshold*))) + * threads have been nonresponsive for at least this duration kill the entire + * Envoy process. Set to 0 to disable this behavior. If not specified the + * default is 0 (disabled). + */ + 'multikill_timeout': (_google_protobuf_Duration__Output | null); + /** + * Sets the threshold for *multikill_timeout* in terms of the percentage of + * nonresponsive threads required for the *multikill_timeout*. + * If not specified the default is 0. + */ + 'multikill_threshold': (_envoy_type_v3_Percent__Output | null); + /** + * Defines the maximum jitter used to adjust the *kill_timeout* if *kill_timeout* is + * enabled. Enabling this feature would help to reduce risk of synchronized + * watchdog kill events across proxies due to external triggers. Set to 0 to + * disable. If not specified the default is 0 (disabled). + */ + 'max_kill_timeout_jitter': (_google_protobuf_Duration__Output | null); + /** + * Register actions that will fire on given WatchDog events. + * See *WatchDogAction* for priority of events. + */ + 'actions': (_envoy_config_bootstrap_v3_Watchdog_WatchdogAction__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdogs.ts b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdogs.ts new file mode 100644 index 000000000..b478615ea --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/bootstrap/v3/Watchdogs.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/config/bootstrap/v3/bootstrap.proto + +import type { Watchdog as _envoy_config_bootstrap_v3_Watchdog, Watchdog__Output as _envoy_config_bootstrap_v3_Watchdog__Output } from '../../../../envoy/config/bootstrap/v3/Watchdog'; + +/** + * Allows you to specify different watchdog configs for different subsystems. + * This allows finer tuned policies for the watchdog. If a subsystem is omitted + * the default values for that system will be used. + */ +export interface Watchdogs { + /** + * Watchdog for the main thread. + */ + 'main_thread_watchdog'?: (_envoy_config_bootstrap_v3_Watchdog | null); + /** + * Watchdog for the worker threads. + */ + 'worker_watchdog'?: (_envoy_config_bootstrap_v3_Watchdog | null); +} + +/** + * Allows you to specify different watchdog configs for different subsystems. + * This allows finer tuned policies for the watchdog. If a subsystem is omitted + * the default values for that system will be used. + */ +export interface Watchdogs__Output { + /** + * Watchdog for the main thread. + */ + 'main_thread_watchdog': (_envoy_config_bootstrap_v3_Watchdog__Output | null); + /** + * Watchdog for the worker threads. + */ + 'worker_watchdog': (_envoy_config_bootstrap_v3_Watchdog__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts index e64afb780..12731b056 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/CircuitBreakers.ts @@ -42,12 +42,12 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds_RetryBudget /** * A Thresholds defines CircuitBreaker settings for a - * :ref:`RoutingPriority`. + * :ref:`RoutingPriority`. * [#next-free-field: 9] */ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds { /** - * The :ref:`RoutingPriority` + * The :ref:`RoutingPriority` * the specified CircuitBreaker settings apply to. */ 'priority'?: (_envoy_config_core_v3_RoutingPriority | keyof typeof _envoy_config_core_v3_RoutingPriority); @@ -104,12 +104,12 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds { /** * A Thresholds defines CircuitBreaker settings for a - * :ref:`RoutingPriority`. + * :ref:`RoutingPriority`. * [#next-free-field: 9] */ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output { /** - * The :ref:`RoutingPriority` + * The :ref:`RoutingPriority` * the specified CircuitBreaker settings apply to. */ 'priority': (keyof typeof _envoy_config_core_v3_RoutingPriority); @@ -170,10 +170,10 @@ export interface _envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output { */ export interface CircuitBreakers { /** - * If multiple :ref:`Thresholds` - * are defined with the same :ref:`RoutingPriority`, + * If multiple :ref:`Thresholds` + * are defined with the same :ref:`RoutingPriority`, * the first one in the list is used. If no Thresholds is defined for a given - * :ref:`RoutingPriority`, the default values + * :ref:`RoutingPriority`, the default values * are used. */ 'thresholds'?: (_envoy_config_cluster_v3_CircuitBreakers_Thresholds)[]; @@ -185,10 +185,10 @@ export interface CircuitBreakers { */ export interface CircuitBreakers__Output { /** - * If multiple :ref:`Thresholds` - * are defined with the same :ref:`RoutingPriority`, + * If multiple :ref:`Thresholds` + * are defined with the same :ref:`RoutingPriority`, * the first one in the list is used. If no Thresholds is defined for a given - * :ref:`RoutingPriority`, the default values + * :ref:`RoutingPriority`, the default values * are used. */ 'thresholds': (_envoy_config_cluster_v3_CircuitBreakers_Thresholds__Output)[]; diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts index c20440704..12ec7b633 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Cluster.ts @@ -21,6 +21,8 @@ import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__ import type { UpstreamHttpProtocolOptions as _envoy_config_core_v3_UpstreamHttpProtocolOptions, UpstreamHttpProtocolOptions__Output as _envoy_config_core_v3_UpstreamHttpProtocolOptions__Output } from '../../../../envoy/config/core/v3/UpstreamHttpProtocolOptions'; import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; import type { TrackClusterStats as _envoy_config_cluster_v3_TrackClusterStats, TrackClusterStats__Output as _envoy_config_cluster_v3_TrackClusterStats__Output } from '../../../../envoy/config/cluster/v3/TrackClusterStats'; +import type { DnsResolutionConfig as _envoy_config_core_v3_DnsResolutionConfig, DnsResolutionConfig__Output as _envoy_config_core_v3_DnsResolutionConfig__Output } from '../../../../envoy/config/core/v3/DnsResolutionConfig'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; import type { RuntimeDouble as _envoy_config_core_v3_RuntimeDouble, RuntimeDouble__Output as _envoy_config_core_v3_RuntimeDouble__Output } from '../../../../envoy/config/core/v3/RuntimeDouble'; import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../../google/protobuf/UInt64Value'; @@ -33,7 +35,7 @@ import type { Long } from '@grpc/proto-loader'; export enum _envoy_config_cluster_v3_Cluster_ClusterProtocolSelection { /** * Cluster can only operate on one of the possible upstream protocols (HTTP1.1, HTTP2). - * If :ref:`http2_protocol_options ` are + * If :ref:`http2_protocol_options ` are * present, HTTP2 will be used, otherwise HTTP1.1 will be used. */ USE_CONFIGURED_PROTOCOL = 0, @@ -220,6 +222,7 @@ export interface _envoy_config_cluster_v3_Cluster_CustomClusterType { /** * Cluster specific configuration which depends on the cluster being instantiated. * See the supported cluster for further documentation. + * [#extension-category: envoy.clusters] */ 'typed_config'?: (_google_protobuf_Any | null); } @@ -235,6 +238,7 @@ export interface _envoy_config_cluster_v3_Cluster_CustomClusterType__Output { /** * Cluster specific configuration which depends on the cluster being instantiated. * See the supported cluster for further documentation. + * [#extension-category: envoy.clusters] */ 'typed_config': (_google_protobuf_Any__Output | null); } @@ -284,16 +288,24 @@ export enum _envoy_config_cluster_v3_Cluster_DiscoveryType { * only perform a lookup for addresses in the IPv6 family. If AUTO is * specified, the DNS resolver will first perform a lookup for addresses in * the IPv6 family and fallback to a lookup for addresses in the IPv4 family. + * This is semantically equivalent to a non-existent V6_PREFERRED option. + * AUTO is a legacy name that is more opaque than + * necessary and will be deprecated in favor of V6_PREFERRED in a future major version of the API. + * If V4_PREFERRED is specified, the DNS resolver will first perform a lookup for addresses in the + * IPv4 family and fallback to a lookup for addresses in the IPv6 family. i.e., the callback + * target will only get v6 addresses if there were NO v4 addresses to return. * For cluster types other than - * :ref:`STRICT_DNS` and - * :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS`, * this setting is * ignored. + * [#next-major-version: deprecate AUTO in favor of a V6_PREFERRED option.] */ export enum _envoy_config_cluster_v3_Cluster_DnsLookupFamily { AUTO = 0, V4_ONLY = 1, V6_ONLY = 2, + V4_PREFERRED = 3, } /** @@ -389,8 +401,8 @@ export enum _envoy_config_cluster_v3_Cluster_LbPolicy { */ CLUSTER_PROVIDED = 6, /** - * [#not-implemented-hide:] Use the new :ref:`load_balancing_policy - * ` field to determine the LB policy. + * Use the new :ref:`load_balancing_policy + * ` field to determine the LB policy. * [#next-major-version: In the v3 API, we should consider deprecating the lb_policy field * and instead using the new load_balancing_policy field as the one and only mechanism for * configuring this.] @@ -407,18 +419,18 @@ export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig { /** * The behavior used when no endpoint subset matches the selected route's * metadata. The value defaults to - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ 'fallback_policy'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy | keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); /** * Specifies the default subset of endpoints used during fallback if * fallback_policy is - * :ref:`DEFAULT_SUBSET`. + * :ref:`DEFAULT_SUBSET`. * Each field in default_subset is * compared to the matching LbEndpoint.Metadata under the *envoy.lb* * namespace. It is valid for no hosts to match, in which case the behavior * is the same as a fallback_policy of - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ 'default_subset'?: (_google_protobuf_Struct | null); /** @@ -484,18 +496,18 @@ export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig__Output { /** * The behavior used when no endpoint subset matches the selected route's * metadata. The value defaults to - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ 'fallback_policy': (keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetFallbackPolicy); /** * Specifies the default subset of endpoints used during fallback if * fallback_policy is - * :ref:`DEFAULT_SUBSET`. + * :ref:`DEFAULT_SUBSET`. * Each field in default_subset is * compared to the matching LbEndpoint.Metadata under the *envoy.lb* * namespace. It is valid for no hosts to match, in which case the behavior * is the same as a fallback_policy of - * :ref:`NO_FALLBACK`. + * :ref:`NO_FALLBACK`. */ 'default_subset': (_google_protobuf_Struct__Output | null); /** @@ -597,13 +609,13 @@ export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelecto 'fallback_policy'?: (_envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy | keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); /** * Subset of - * :ref:`keys` used by - * :ref:`KEYS_SUBSET` + * :ref:`keys` used by + * :ref:`KEYS_SUBSET` * fallback policy. * It has to be a non empty list if KEYS_SUBSET fallback policy is selected. * For any other fallback policy the parameter is not used and should not be set. * Only values also present in - * :ref:`keys` are allowed, but + * :ref:`keys` are allowed, but * `fallback_keys_subset` cannot be equal to `keys`. */ 'fallback_keys_subset'?: (string)[]; @@ -639,13 +651,13 @@ export interface _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelecto 'fallback_policy': (keyof typeof _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbSubsetSelectorFallbackPolicy); /** * Subset of - * :ref:`keys` used by - * :ref:`KEYS_SUBSET` + * :ref:`keys` used by + * :ref:`KEYS_SUBSET` * fallback policy. * It has to be a non empty list if KEYS_SUBSET fallback policy is selected. * For any other fallback policy the parameter is not used and should not be set. * Only values also present in - * :ref:`keys` are allowed, but + * :ref:`keys` are allowed, but * `fallback_keys_subset` cannot be equal to `keys`. */ 'fallback_keys_subset': (string)[]; @@ -678,7 +690,7 @@ export enum _envoy_config_cluster_v3_Cluster_LbSubsetConfig_LbSubsetSelector_LbS /** * If KEYS_SUBSET is selected, subset selector matching is performed again with metadata * keys reduced to - * :ref:`fallback_keys_subset`. + * :ref:`fallback_keys_subset`. * It allows for a fallback to a different, less specific selector if some of the keys of * the selector are considered optional. */ @@ -720,6 +732,11 @@ export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig { * This setting only takes effect if all host weights are not equal. */ 'active_request_bias'?: (_envoy_config_core_v3_RuntimeDouble | null); + /** + * Configuration for slow start mode. + * If this configuration is not set, slow start will not be not enabled. + */ + 'slow_start_config'?: (_envoy_config_cluster_v3_Cluster_SlowStartConfig | null); } /** @@ -757,6 +774,11 @@ export interface _envoy_config_cluster_v3_Cluster_LeastRequestLbConfig__Output { * This setting only takes effect if all host weights are not equal. */ 'active_request_bias': (_envoy_config_core_v3_RuntimeDouble__Output | null); + /** + * Configuration for slow start mode. + * If this configuration is not set, slow start will not be not enabled. + */ + 'slow_start_config': (_envoy_config_cluster_v3_Cluster_SlowStartConfig__Output | null); } /** @@ -782,7 +804,7 @@ export interface _envoy_config_cluster_v3_Cluster_MaglevLbConfig { * The table size for Maglev hashing. The Maglev aims for ‘minimal disruption’ rather than an absolute guarantee. * Minimal disruption means that when the set of upstreams changes, a connection will likely be sent to the same * upstream as it was before. Increasing the table size reduces the amount of disruption. - * The table size must be prime number. If it is not specified, the default is 65537. + * The table size must be prime number limited to 5000011. If it is not specified, the default is 65537. */ 'table_size'?: (_google_protobuf_UInt64Value | null); } @@ -796,7 +818,7 @@ export interface _envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output { * The table size for Maglev hashing. The Maglev aims for ‘minimal disruption’ rather than an absolute guarantee. * Minimal disruption means that when the set of upstreams changes, a connection will likely be sent to the same * upstream as it was before. Increasing the table size reduces the amount of disruption. - * The table size must be prime number. If it is not specified, the default is 65537. + * The table size must be prime number limited to 5000011. If it is not specified, the default is 65537. */ 'table_size': (_google_protobuf_UInt64Value__Output | null); } @@ -963,14 +985,14 @@ export interface _envoy_config_cluster_v3_Cluster_RefreshRate { /** * Specifies the base interval between refreshes. This parameter is required and must be greater * than zero and less than - * :ref:`max_interval `. + * :ref:`max_interval `. */ 'base_interval'?: (_google_protobuf_Duration | null); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the - * :ref:`base_interval ` if set. The default - * is 10 times the :ref:`base_interval `. + * :ref:`base_interval ` if set. The default + * is 10 times the :ref:`base_interval `. */ 'max_interval'?: (_google_protobuf_Duration | null); } @@ -979,14 +1001,14 @@ export interface _envoy_config_cluster_v3_Cluster_RefreshRate__Output { /** * Specifies the base interval between refreshes. This parameter is required and must be greater * than zero and less than - * :ref:`max_interval `. + * :ref:`max_interval `. */ 'base_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the maximum interval between refreshes. This parameter is optional, but must be * greater than or equal to the - * :ref:`base_interval ` if set. The default - * is 10 times the :ref:`base_interval `. + * :ref:`base_interval ` if set. The default + * is 10 times the :ref:`base_interval `. */ 'max_interval': (_google_protobuf_Duration__Output | null); } @@ -1000,18 +1022,18 @@ export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig { * Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each * provided host) the better the request distribution will reflect the desired weights. Defaults * to 1024 entries, and limited to 8M entries. See also - * :ref:`maximum_ring_size`. + * :ref:`maximum_ring_size`. */ 'minimum_ring_size'?: (_google_protobuf_UInt64Value | null); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to - * :ref:`XX_HASH`. + * :ref:`XX_HASH`. */ 'hash_function'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction | keyof typeof _envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction); /** * Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered * to further constrain resource use. See also - * :ref:`minimum_ring_size`. + * :ref:`minimum_ring_size`. */ 'maximum_ring_size'?: (_google_protobuf_UInt64Value | null); } @@ -1025,22 +1047,98 @@ export interface _envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output { * Minimum hash ring size. The larger the ring is (that is, the more hashes there are for each * provided host) the better the request distribution will reflect the desired weights. Defaults * to 1024 entries, and limited to 8M entries. See also - * :ref:`maximum_ring_size`. + * :ref:`maximum_ring_size`. */ 'minimum_ring_size': (_google_protobuf_UInt64Value__Output | null); /** * The hash function used to hash hosts onto the ketama ring. The value defaults to - * :ref:`XX_HASH`. + * :ref:`XX_HASH`. */ 'hash_function': (keyof typeof _envoy_config_cluster_v3_Cluster_RingHashLbConfig_HashFunction); /** * Maximum hash ring size. Defaults to 8M entries, and limited to 8M entries, but can be lowered * to further constrain resource use. See also - * :ref:`minimum_ring_size`. + * :ref:`minimum_ring_size`. */ 'maximum_ring_size': (_google_protobuf_UInt64Value__Output | null); } +/** + * Specific configuration for the RoundRobin load balancing policy. + */ +export interface _envoy_config_cluster_v3_Cluster_RoundRobinLbConfig { + /** + * Configuration for slow start mode. + * If this configuration is not set, slow start will not be not enabled. + */ + 'slow_start_config'?: (_envoy_config_cluster_v3_Cluster_SlowStartConfig | null); +} + +/** + * Specific configuration for the RoundRobin load balancing policy. + */ +export interface _envoy_config_cluster_v3_Cluster_RoundRobinLbConfig__Output { + /** + * Configuration for slow start mode. + * If this configuration is not set, slow start will not be not enabled. + */ + 'slow_start_config': (_envoy_config_cluster_v3_Cluster_SlowStartConfig__Output | null); +} + +/** + * Configuration for :ref:`slow start mode `. + */ +export interface _envoy_config_cluster_v3_Cluster_SlowStartConfig { + /** + * Represents the size of slow start window. + * If set, the newly created host remains in slow start mode starting from its creation time + * for the duration of slow start window. + */ + 'slow_start_window'?: (_google_protobuf_Duration | null); + /** + * This parameter controls the speed of traffic increase over the slow start window. Defaults to 1.0, + * so that endpoint would get linearly increasing amount of traffic. + * When increasing the value for this parameter, the speed of traffic ramp-up increases non-linearly. + * The value of aggression parameter should be greater than 0.0. + * By tuning the parameter, is possible to achieve polynomial or exponential shape of ramp-up curve. + * + * During slow start window, effective weight of an endpoint would be scaled with time factor and aggression: + * `new_weight = weight * time_factor ^ (1 / aggression)`, + * where `time_factor=(time_since_start_seconds / slow_start_time_seconds)`. + * + * As time progresses, more and more traffic would be sent to endpoint, which is in slow start window. + * Once host exits slow start, time_factor and aggression no longer affect its weight. + */ + 'aggression'?: (_envoy_config_core_v3_RuntimeDouble | null); +} + +/** + * Configuration for :ref:`slow start mode `. + */ +export interface _envoy_config_cluster_v3_Cluster_SlowStartConfig__Output { + /** + * Represents the size of slow start window. + * If set, the newly created host remains in slow start mode starting from its creation time + * for the duration of slow start window. + */ + 'slow_start_window': (_google_protobuf_Duration__Output | null); + /** + * This parameter controls the speed of traffic increase over the slow start window. Defaults to 1.0, + * so that endpoint would get linearly increasing amount of traffic. + * When increasing the value for this parameter, the speed of traffic ramp-up increases non-linearly. + * The value of aggression parameter should be greater than 0.0. + * By tuning the parameter, is possible to achieve polynomial or exponential shape of ramp-up curve. + * + * During slow start window, effective weight of an endpoint would be scaled with time factor and aggression: + * `new_weight = weight * time_factor ^ (1 / aggression)`, + * where `time_factor=(time_since_start_seconds / slow_start_time_seconds)`. + * + * As time progresses, more and more traffic would be sent to endpoint, which is in slow start window. + * Once host exits slow start, time_factor and aggression no longer affect its weight. + */ + 'aggression': (_envoy_config_core_v3_RuntimeDouble__Output | null); +} + /** * TransportSocketMatch specifies what transport socket config will be used * when the match conditions are satisfied. @@ -1060,6 +1158,7 @@ export interface _envoy_config_cluster_v3_Cluster_TransportSocketMatch { 'match'?: (_google_protobuf_Struct | null); /** * The configuration of the transport socket. + * [#extension-category: envoy.transport_sockets.upstream] */ 'transport_socket'?: (_envoy_config_core_v3_TransportSocket | null); } @@ -1083,6 +1182,7 @@ export interface _envoy_config_cluster_v3_Cluster_TransportSocketMatch__Output { 'match': (_google_protobuf_Struct__Output | null); /** * The configuration of the transport socket. + * [#extension-category: envoy.transport_sockets.upstream] */ 'transport_socket': (_envoy_config_core_v3_TransportSocket__Output | null); } @@ -1147,14 +1247,14 @@ export interface _envoy_config_cluster_v3_Cluster_CommonLbConfig_ZoneAwareLbConf /** * Configuration for a single upstream cluster. - * [#next-free-field: 53] + * [#next-free-field: 57] */ export interface Cluster { /** * Supplies the name of the cluster which must be unique across all clusters. * The cluster name is used when emitting * :ref:`statistics ` if :ref:`alt_stat_name - * ` is not provided. + * ` is not provided. * Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. */ 'name'?: (string); @@ -1169,6 +1269,7 @@ export interface Cluster { 'eds_cluster_config'?: (_envoy_config_cluster_v3_Cluster_EdsClusterConfig | null); /** * The timeout for new network connections to hosts in the cluster. + * If not set, a default value of 5s will be used. */ 'connect_timeout'?: (_google_protobuf_Duration | null); /** @@ -1179,7 +1280,6 @@ export interface Cluster { /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. - * [#comment:TODO: Remove enum constraint :ref:`LOAD_BALANCING_POLICY_CONFIG` when implemented.] */ 'lb_policy'?: (_envoy_config_cluster_v3_Cluster_LbPolicy | keyof typeof _envoy_config_cluster_v3_Cluster_LbPolicy); /** @@ -1194,6 +1294,9 @@ export interface Cluster { * is respected by both the HTTP/1.1 and HTTP/2 connection pool * implementations. If not specified, there is no limit. Setting this * parameter to 1 will effectively disable keep alive. + * + * .. attention:: + * This field has been deprecated in favor of the :ref:`max_requests_per_connection ` field. */ 'max_requests_per_connection'?: (_google_protobuf_UInt32Value | null); /** @@ -1202,12 +1305,12 @@ export interface Cluster { 'circuit_breakers'?: (_envoy_config_cluster_v3_CircuitBreakers | null); /** * Additional options when handling HTTP1 requests. - * This has been deprecated in favor of http_protocol_options fields in the in the - * :ref:`http_protocol_options ` message. + * This has been deprecated in favor of http_protocol_options fields in the + * :ref:`http_protocol_options ` message. * http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'http_protocol_options'?: (_envoy_config_core_v3_Http1ProtocolOptions | null); @@ -1218,47 +1321,49 @@ export interface Cluster { * supports prior knowledge for upstream connections. Even if TLS is used * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 * connections to happen over plain text. - * This has been deprecated in favor of http2_protocol_options fields in the in the - * :ref:`http_protocol_options ` + * This has been deprecated in favor of http2_protocol_options fields in the + * :ref:`http_protocol_options ` * message. http2_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'http2_protocol_options'?: (_envoy_config_core_v3_Http2ProtocolOptions | null); /** * If the DNS refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used as the cluster’s DNS refresh * rate. The value configured must be at least 1ms. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. */ 'dns_refresh_rate'?: (_google_protobuf_Duration | null); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to - * :ref:`AUTO`. + * :ref:`AUTO`. */ 'dns_lookup_family'?: (_envoy_config_cluster_v3_Cluster_DnsLookupFamily | keyof typeof _envoy_config_cluster_v3_Cluster_DnsLookupFamily); /** * If DNS resolvers are specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used to specify the cluster’s dns resolvers. * If this setting is not specified, the value defaults to the default * resolver, which uses /etc/resolv.conf for configuration. For cluster types * other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. * Setting this value causes failure if the * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during * server startup. Apple's API only allows overriding DNS resolvers via system settings. + * This field is deprecated in favor of *dns_resolution_config* + * which aggregates all of the DNS resolver configuration in a single message. */ 'dns_resolvers'?: (_envoy_config_core_v3_Address)[]; /** @@ -1269,7 +1374,7 @@ export interface Cluster { 'outlier_detection'?: (_envoy_config_cluster_v3_OutlierDetection | null); /** * The interval for removing stale hosts from a cluster type - * :ref:`ORIGINAL_DST`. + * :ref:`ORIGINAL_DST`. * Hosts are considered stale if they have not been used * as upstream destinations during this interval. New hosts are added * to original destination clusters on demand as new connections are @@ -1279,7 +1384,7 @@ export interface Cluster { * them remain open, saving the latency that would otherwise be spent * on opening new connections. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`ORIGINAL_DST` + * :ref:`ORIGINAL_DST` * this setting is ignored. */ 'cleanup_interval'?: (_google_protobuf_Duration | null); @@ -1299,8 +1404,8 @@ export interface Cluster { 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig | null); /** * Optional custom transport socket implementation to use for upstream connections. - * To setup TLS, set a transport socket with name `tls` and - * :ref:`UpstreamTlsContexts ` in the `typed_config`. + * To setup TLS, set a transport socket with name `envoy.transport_sockets.tls` and + * :ref:`UpstreamTlsContexts ` in the `typed_config`. * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ @@ -1317,9 +1422,9 @@ export interface Cluster { * Determines how Envoy selects the protocol used to speak to upstream hosts. * This has been deprecated in favor of setting explicit protocol selection * in the :ref:`http_protocol_options - * ` message. + * ` message. * http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. + * :ref:`extension_protocol_options`. */ 'protocol_selection'?: (_envoy_config_cluster_v3_Cluster_ClusterProtocolSelection | keyof typeof _envoy_config_cluster_v3_Cluster_ClusterProtocolSelection); /** @@ -1327,22 +1432,27 @@ export interface Cluster { */ 'common_lb_config'?: (_envoy_config_cluster_v3_Cluster_CommonLbConfig | null); /** - * An optional alternative to the cluster name to be used while emitting stats. - * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be - * confused with :ref:`Router Filter Header - * `. + * An optional alternative to the cluster name to be used for observability. This name is used + * emitting stats for the cluster and access logging the cluster name. This will appear as + * additional information in configuration dumps of a cluster's current status as + * :ref:`observability_name ` + * and as an additional tag "upstream_cluster.name" while tracing. Note: access logging using + * this field is presently enabled with runtime feature + * `envoy.reloadable_features.use_observable_cluster_name`. Any ``:`` in the name will be + * converted to ``_`` when emitting statistics. This should not be confused with :ref:`Router + * Filter Header `. */ 'alt_stat_name'?: (string); /** * Additional options when handling HTTP requests upstream. These options will be applicable to * both HTTP1 and HTTP2 requests. * This has been deprecated in favor of - * :ref:`common_http_protocol_options ` - * in the :ref:`http_protocol_options ` message. + * :ref:`common_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. * common_http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions | null); @@ -1374,15 +1484,15 @@ export interface Cluster { 'ignore_health_on_host_removal'?: (boolean); /** * Setting this is required for specifying members of - * :ref:`STATIC`, - * :ref:`STRICT_DNS` - * or :ref:`LOGICAL_DNS` clusters. + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS` clusters. * This field supersedes the *hosts* field in the v2 API. * * .. attention:: * * Setting this allows non-EDS cluster types to contain embedded EDS equivalent - * :ref:`endpoint assignments`. + * :ref:`endpoint assignments`. */ 'load_assignment'?: (_envoy_config_endpoint_v3_ClusterLoadAssignment | null); /** @@ -1418,9 +1528,9 @@ export interface Cluster { */ 'filters'?: (_envoy_config_cluster_v3_Filter)[]; /** - * [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the - * :ref:`lb_policy` field has the value - * :ref:`LOAD_BALANCING_POLICY_CONFIG`. + * New mechanism for LB policy configuration. Used only if the + * :ref:`lb_policy` field has the value + * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ 'load_balancing_policy'?: (_envoy_config_cluster_v3_LoadBalancingPolicy | null); /** @@ -1443,9 +1553,9 @@ export interface Cluster { /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the - * :ref:`LbEndpoint.Metadata ` + * :ref:`LbEndpoint.Metadata ` * is used to match against the transport sockets as they appear in the list. The first - * :ref:`match ` is used. + * :ref:`match ` is used. * For example, with the following match * * .. code-block:: yaml @@ -1465,7 +1575,7 @@ export interface Cluster { * Connections to the endpoints whose metadata value under *envoy.transport_socket_match* * having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. * - * If a :ref:`socket match ` with empty match + * If a :ref:`socket match ` with empty match * criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" * socket match in case above. * @@ -1487,40 +1597,41 @@ export interface Cluster { * * This field can be used to specify custom transport socket configurations for health * checks by adding matching key/value pairs in a health check's - * :ref:`transport socket match criteria ` field. + * :ref:`transport socket match criteria ` field. * * [#comment:TODO(incfly): add a detailed architecture doc on intended usage.] */ 'transport_socket_matches'?: (_envoy_config_cluster_v3_Cluster_TransportSocketMatch)[]; /** * If the DNS failure refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is * not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types - * other than :ref:`STRICT_DNS` and - * :ref:`LOGICAL_DNS` this setting is + * other than :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS` this setting is * ignored. */ 'dns_failure_refresh_rate'?: (_envoy_config_cluster_v3_Cluster_RefreshRate | null); /** - * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. * Setting this value causes failure if the * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during * server startup. Apple' API only uses UDP for DNS resolution. + * This field is deprecated in favor of *dns_resolution_config* + * which aggregates all of the DNS resolver configuration in a single message. */ 'use_tcp_for_dns_lookups'?: (boolean); /** * HTTP protocol options that are applied only to upstream HTTP connections. * These options apply to all HTTP versions. * This has been deprecated in favor of - * :ref:`upstream_http_protocol_options ` - * in the :ref:`http_protocol_options ` message. + * :ref:`upstream_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. * upstream_http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'upstream_http_protocol_options'?: (_envoy_config_core_v3_UpstreamHttpProtocolOptions | null); @@ -1534,7 +1645,7 @@ export interface Cluster { * .. attention:: * * This field has been deprecated in favor of `timeout_budgets`, part of - * :ref:`track_cluster_stats `. + * :ref:`track_cluster_stats `. */ 'track_timeout_budgets'?: (boolean); /** @@ -1555,6 +1666,7 @@ export interface Cluster { * If users desire custom connection pool or upstream behavior, for example terminating * CONNECT only if a custom filter indicates it is appropriate, the custom factories * can be registered and configured here. + * [#extension-category: envoy.upstreams] */ 'upstream_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); /** @@ -1574,30 +1686,64 @@ export interface Cluster { * Optional configuration for the Maglev load balancing policy. */ 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig | null); + /** + * DNS resolution configuration which includes the underlying dns resolver addresses and options. + * *dns_resolution_config* will be deprecated once + * :ref:'typed_dns_resolver_config ' + * is fully supported. + */ + 'dns_resolution_config'?: (_envoy_config_core_v3_DnsResolutionConfig | null); + /** + * Optional configuration for having cluster readiness block on warm-up. Currently, only applicable for + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`. + * If true, cluster readiness blocks on warm-up. If false, the cluster will complete + * initialization whether or not warm-up has completed. Defaults to true. + */ + 'wait_for_warm_on_init'?: (_google_protobuf_BoolValue | null); + /** + * DNS resolver type configuration extension. This extension can be used to configure c-ares, apple, + * or any other DNS resolver types and the related parameters. + * For example, an object of :ref:`DnsResolutionConfig ` + * can be packed into this *typed_dns_resolver_config*. This configuration will replace the + * :ref:'dns_resolution_config ' + * configuration eventually. + * TODO(yanjunxiang): Investigate the deprecation plan for *dns_resolution_config*. + * During the transition period when both *dns_resolution_config* and *typed_dns_resolver_config* exists, + * this configuration is optional. + * When *typed_dns_resolver_config* is in place, Envoy will use it and ignore *dns_resolution_config*. + * When *typed_dns_resolver_config* is missing, the default behavior is in place. + * [#not-implemented-hide:] + */ + 'typed_dns_resolver_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + /** + * Optional configuration for the RoundRobin load balancing policy. + */ + 'round_robin_lb_config'?: (_envoy_config_cluster_v3_Cluster_RoundRobinLbConfig | null); 'cluster_discovery_type'?: "type"|"cluster_type"; /** * Optional configuration for the load balancing algorithm selected by * LbPolicy. Currently only - * :ref:`RING_HASH`, - * :ref:`MAGLEV` and - * :ref:`LEAST_REQUEST` + * :ref:`RING_HASH`, + * :ref:`MAGLEV` and + * :ref:`LEAST_REQUEST` * has additional configuration options. * Specifying ring_hash_lb_config or maglev_lb_config or least_request_lb_config without setting the corresponding * LbPolicy will generate an error at runtime. */ - 'lb_config'?: "ring_hash_lb_config"|"maglev_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; + 'lb_config'?: "ring_hash_lb_config"|"maglev_lb_config"|"original_dst_lb_config"|"least_request_lb_config"|"round_robin_lb_config"; } /** * Configuration for a single upstream cluster. - * [#next-free-field: 53] + * [#next-free-field: 57] */ export interface Cluster__Output { /** * Supplies the name of the cluster which must be unique across all clusters. * The cluster name is used when emitting * :ref:`statistics ` if :ref:`alt_stat_name - * ` is not provided. + * ` is not provided. * Any ``:`` in the cluster name will be converted to ``_`` when emitting statistics. */ 'name': (string); @@ -1612,6 +1758,7 @@ export interface Cluster__Output { 'eds_cluster_config': (_envoy_config_cluster_v3_Cluster_EdsClusterConfig__Output | null); /** * The timeout for new network connections to hosts in the cluster. + * If not set, a default value of 5s will be used. */ 'connect_timeout': (_google_protobuf_Duration__Output | null); /** @@ -1622,7 +1769,6 @@ export interface Cluster__Output { /** * The :ref:`load balancer type ` to use * when picking a host in the cluster. - * [#comment:TODO: Remove enum constraint :ref:`LOAD_BALANCING_POLICY_CONFIG` when implemented.] */ 'lb_policy': (keyof typeof _envoy_config_cluster_v3_Cluster_LbPolicy); /** @@ -1637,6 +1783,9 @@ export interface Cluster__Output { * is respected by both the HTTP/1.1 and HTTP/2 connection pool * implementations. If not specified, there is no limit. Setting this * parameter to 1 will effectively disable keep alive. + * + * .. attention:: + * This field has been deprecated in favor of the :ref:`max_requests_per_connection ` field. */ 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output | null); /** @@ -1645,12 +1794,12 @@ export interface Cluster__Output { 'circuit_breakers': (_envoy_config_cluster_v3_CircuitBreakers__Output | null); /** * Additional options when handling HTTP1 requests. - * This has been deprecated in favor of http_protocol_options fields in the in the - * :ref:`http_protocol_options ` message. + * This has been deprecated in favor of http_protocol_options fields in the + * :ref:`http_protocol_options ` message. * http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'http_protocol_options': (_envoy_config_core_v3_Http1ProtocolOptions__Output | null); @@ -1661,47 +1810,49 @@ export interface Cluster__Output { * supports prior knowledge for upstream connections. Even if TLS is used * with ALPN, `http2_protocol_options` must be specified. As an aside this allows HTTP/2 * connections to happen over plain text. - * This has been deprecated in favor of http2_protocol_options fields in the in the - * :ref:`http_protocol_options ` + * This has been deprecated in favor of http2_protocol_options fields in the + * :ref:`http_protocol_options ` * message. http2_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'http2_protocol_options': (_envoy_config_core_v3_Http2ProtocolOptions__Output | null); /** * If the DNS refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used as the cluster’s DNS refresh * rate. The value configured must be at least 1ms. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. */ 'dns_refresh_rate': (_google_protobuf_Duration__Output | null); /** * The DNS IP address resolution policy. If this setting is not specified, the * value defaults to - * :ref:`AUTO`. + * :ref:`AUTO`. */ 'dns_lookup_family': (keyof typeof _envoy_config_cluster_v3_Cluster_DnsLookupFamily); /** * If DNS resolvers are specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this value is used to specify the cluster’s dns resolvers. * If this setting is not specified, the value defaults to the default * resolver, which uses /etc/resolv.conf for configuration. For cluster types * other than - * :ref:`STRICT_DNS` - * and :ref:`LOGICAL_DNS` + * :ref:`STRICT_DNS` + * and :ref:`LOGICAL_DNS` * this setting is ignored. * Setting this value causes failure if the * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during * server startup. Apple's API only allows overriding DNS resolvers via system settings. + * This field is deprecated in favor of *dns_resolution_config* + * which aggregates all of the DNS resolver configuration in a single message. */ 'dns_resolvers': (_envoy_config_core_v3_Address__Output)[]; /** @@ -1712,7 +1863,7 @@ export interface Cluster__Output { 'outlier_detection': (_envoy_config_cluster_v3_OutlierDetection__Output | null); /** * The interval for removing stale hosts from a cluster type - * :ref:`ORIGINAL_DST`. + * :ref:`ORIGINAL_DST`. * Hosts are considered stale if they have not been used * as upstream destinations during this interval. New hosts are added * to original destination clusters on demand as new connections are @@ -1722,7 +1873,7 @@ export interface Cluster__Output { * them remain open, saving the latency that would otherwise be spent * on opening new connections. If this setting is not specified, the * value defaults to 5000ms. For cluster types other than - * :ref:`ORIGINAL_DST` + * :ref:`ORIGINAL_DST` * this setting is ignored. */ 'cleanup_interval': (_google_protobuf_Duration__Output | null); @@ -1742,8 +1893,8 @@ export interface Cluster__Output { 'ring_hash_lb_config'?: (_envoy_config_cluster_v3_Cluster_RingHashLbConfig__Output | null); /** * Optional custom transport socket implementation to use for upstream connections. - * To setup TLS, set a transport socket with name `tls` and - * :ref:`UpstreamTlsContexts ` in the `typed_config`. + * To setup TLS, set a transport socket with name `envoy.transport_sockets.tls` and + * :ref:`UpstreamTlsContexts ` in the `typed_config`. * If no transport socket configuration is specified, new connections * will be set up with plaintext. */ @@ -1760,9 +1911,9 @@ export interface Cluster__Output { * Determines how Envoy selects the protocol used to speak to upstream hosts. * This has been deprecated in favor of setting explicit protocol selection * in the :ref:`http_protocol_options - * ` message. + * ` message. * http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. + * :ref:`extension_protocol_options`. */ 'protocol_selection': (keyof typeof _envoy_config_cluster_v3_Cluster_ClusterProtocolSelection); /** @@ -1770,22 +1921,27 @@ export interface Cluster__Output { */ 'common_lb_config': (_envoy_config_cluster_v3_Cluster_CommonLbConfig__Output | null); /** - * An optional alternative to the cluster name to be used while emitting stats. - * Any ``:`` in the name will be converted to ``_`` when emitting statistics. This should not be - * confused with :ref:`Router Filter Header - * `. + * An optional alternative to the cluster name to be used for observability. This name is used + * emitting stats for the cluster and access logging the cluster name. This will appear as + * additional information in configuration dumps of a cluster's current status as + * :ref:`observability_name ` + * and as an additional tag "upstream_cluster.name" while tracing. Note: access logging using + * this field is presently enabled with runtime feature + * `envoy.reloadable_features.use_observable_cluster_name`. Any ``:`` in the name will be + * converted to ``_`` when emitting statistics. This should not be confused with :ref:`Router + * Filter Header `. */ 'alt_stat_name': (string); /** * Additional options when handling HTTP requests upstream. These options will be applicable to * both HTTP1 and HTTP2 requests. * This has been deprecated in favor of - * :ref:`common_http_protocol_options ` - * in the :ref:`http_protocol_options ` message. + * :ref:`common_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. * common_http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'common_http_protocol_options': (_envoy_config_core_v3_HttpProtocolOptions__Output | null); @@ -1817,15 +1973,15 @@ export interface Cluster__Output { 'ignore_health_on_host_removal': (boolean); /** * Setting this is required for specifying members of - * :ref:`STATIC`, - * :ref:`STRICT_DNS` - * or :ref:`LOGICAL_DNS` clusters. + * :ref:`STATIC`, + * :ref:`STRICT_DNS` + * or :ref:`LOGICAL_DNS` clusters. * This field supersedes the *hosts* field in the v2 API. * * .. attention:: * * Setting this allows non-EDS cluster types to contain embedded EDS equivalent - * :ref:`endpoint assignments`. + * :ref:`endpoint assignments`. */ 'load_assignment': (_envoy_config_endpoint_v3_ClusterLoadAssignment__Output | null); /** @@ -1861,9 +2017,9 @@ export interface Cluster__Output { */ 'filters': (_envoy_config_cluster_v3_Filter__Output)[]; /** - * [#not-implemented-hide:] New mechanism for LB policy configuration. Used only if the - * :ref:`lb_policy` field has the value - * :ref:`LOAD_BALANCING_POLICY_CONFIG`. + * New mechanism for LB policy configuration. Used only if the + * :ref:`lb_policy` field has the value + * :ref:`LOAD_BALANCING_POLICY_CONFIG`. */ 'load_balancing_policy': (_envoy_config_cluster_v3_LoadBalancingPolicy__Output | null); /** @@ -1886,9 +2042,9 @@ export interface Cluster__Output { /** * Configuration to use different transport sockets for different endpoints. * The entry of *envoy.transport_socket_match* in the - * :ref:`LbEndpoint.Metadata ` + * :ref:`LbEndpoint.Metadata ` * is used to match against the transport sockets as they appear in the list. The first - * :ref:`match ` is used. + * :ref:`match ` is used. * For example, with the following match * * .. code-block:: yaml @@ -1908,7 +2064,7 @@ export interface Cluster__Output { * Connections to the endpoints whose metadata value under *envoy.transport_socket_match* * having "acceptMTLS"/"true" key/value pair use the "enableMTLS" socket configuration. * - * If a :ref:`socket match ` with empty match + * If a :ref:`socket match ` with empty match * criteria is provided, that always match any endpoint. For example, the "defaultToPlaintext" * socket match in case above. * @@ -1930,40 +2086,41 @@ export interface Cluster__Output { * * This field can be used to specify custom transport socket configurations for health * checks by adding matching key/value pairs in a health check's - * :ref:`transport socket match criteria ` field. + * :ref:`transport socket match criteria ` field. * * [#comment:TODO(incfly): add a detailed architecture doc on intended usage.] */ 'transport_socket_matches': (_envoy_config_cluster_v3_Cluster_TransportSocketMatch__Output)[]; /** * If the DNS failure refresh rate is specified and the cluster type is either - * :ref:`STRICT_DNS`, - * or :ref:`LOGICAL_DNS`, + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`, * this is used as the cluster’s DNS refresh rate when requests are failing. If this setting is * not specified, the failure refresh rate defaults to the DNS refresh rate. For cluster types - * other than :ref:`STRICT_DNS` and - * :ref:`LOGICAL_DNS` this setting is + * other than :ref:`STRICT_DNS` and + * :ref:`LOGICAL_DNS` this setting is * ignored. */ 'dns_failure_refresh_rate': (_envoy_config_cluster_v3_Cluster_RefreshRate__Output | null); /** - * [#next-major-version: Reconcile DNS options in a single message.] * Always use TCP queries instead of UDP queries for DNS lookups. * Setting this value causes failure if the * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during * server startup. Apple' API only uses UDP for DNS resolution. + * This field is deprecated in favor of *dns_resolution_config* + * which aggregates all of the DNS resolver configuration in a single message. */ 'use_tcp_for_dns_lookups': (boolean); /** * HTTP protocol options that are applied only to upstream HTTP connections. * These options apply to all HTTP versions. * This has been deprecated in favor of - * :ref:`upstream_http_protocol_options ` - * in the :ref:`http_protocol_options ` message. + * :ref:`upstream_http_protocol_options ` + * in the :ref:`http_protocol_options ` message. * upstream_http_protocol_options can be set via the cluster's - * :ref:`extension_protocol_options`. - * See ref:`upstream_http_protocol_options - * ` + * :ref:`extension_protocol_options`. + * See :ref:`upstream_http_protocol_options + * ` * for example usage. */ 'upstream_http_protocol_options': (_envoy_config_core_v3_UpstreamHttpProtocolOptions__Output | null); @@ -1977,7 +2134,7 @@ export interface Cluster__Output { * .. attention:: * * This field has been deprecated in favor of `timeout_budgets`, part of - * :ref:`track_cluster_stats `. + * :ref:`track_cluster_stats `. */ 'track_timeout_budgets': (boolean); /** @@ -1998,6 +2155,7 @@ export interface Cluster__Output { * If users desire custom connection pool or upstream behavior, for example terminating * CONNECT only if a custom filter indicates it is appropriate, the custom factories * can be registered and configured here. + * [#extension-category: envoy.upstreams] */ 'upstream_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); /** @@ -2017,16 +2175,50 @@ export interface Cluster__Output { * Optional configuration for the Maglev load balancing policy. */ 'maglev_lb_config'?: (_envoy_config_cluster_v3_Cluster_MaglevLbConfig__Output | null); + /** + * DNS resolution configuration which includes the underlying dns resolver addresses and options. + * *dns_resolution_config* will be deprecated once + * :ref:'typed_dns_resolver_config ' + * is fully supported. + */ + 'dns_resolution_config': (_envoy_config_core_v3_DnsResolutionConfig__Output | null); + /** + * Optional configuration for having cluster readiness block on warm-up. Currently, only applicable for + * :ref:`STRICT_DNS`, + * or :ref:`LOGICAL_DNS`. + * If true, cluster readiness blocks on warm-up. If false, the cluster will complete + * initialization whether or not warm-up has completed. Defaults to true. + */ + 'wait_for_warm_on_init': (_google_protobuf_BoolValue__Output | null); + /** + * DNS resolver type configuration extension. This extension can be used to configure c-ares, apple, + * or any other DNS resolver types and the related parameters. + * For example, an object of :ref:`DnsResolutionConfig ` + * can be packed into this *typed_dns_resolver_config*. This configuration will replace the + * :ref:'dns_resolution_config ' + * configuration eventually. + * TODO(yanjunxiang): Investigate the deprecation plan for *dns_resolution_config*. + * During the transition period when both *dns_resolution_config* and *typed_dns_resolver_config* exists, + * this configuration is optional. + * When *typed_dns_resolver_config* is in place, Envoy will use it and ignore *dns_resolution_config*. + * When *typed_dns_resolver_config* is missing, the default behavior is in place. + * [#not-implemented-hide:] + */ + 'typed_dns_resolver_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + /** + * Optional configuration for the RoundRobin load balancing policy. + */ + 'round_robin_lb_config'?: (_envoy_config_cluster_v3_Cluster_RoundRobinLbConfig__Output | null); 'cluster_discovery_type': "type"|"cluster_type"; /** * Optional configuration for the load balancing algorithm selected by * LbPolicy. Currently only - * :ref:`RING_HASH`, - * :ref:`MAGLEV` and - * :ref:`LEAST_REQUEST` + * :ref:`RING_HASH`, + * :ref:`MAGLEV` and + * :ref:`LEAST_REQUEST` * has additional configuration options. * Specifying ring_hash_lb_config or maglev_lb_config or least_request_lb_config without setting the corresponding * LbPolicy will generate an error at runtime. */ - 'lb_config': "ring_hash_lb_config"|"maglev_lb_config"|"original_dst_lb_config"|"least_request_lb_config"; + 'lb_config': "ring_hash_lb_config"|"maglev_lb_config"|"original_dst_lb_config"|"least_request_lb_config"|"round_robin_lb_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts index b2ccda5e4..9d9031b68 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/Filter.ts @@ -5,7 +5,8 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ export interface Filter { /** * The name of the filter to instantiate. The name must match a - * :ref:`supported filter `. + * supported upstream filter. Note that Envoy's :ref:`downstream network + * filters ` are not valid upstream filters. */ 'name'?: (string); /** @@ -18,7 +19,8 @@ export interface Filter { export interface Filter__Output { /** * The name of the filter to instantiate. The name must match a - * :ref:`supported filter `. + * supported upstream filter. Note that Envoy's :ref:`downstream network + * filters ` are not valid upstream filters. */ 'name': (string); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts index 128a6458a..78d4a6bfd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/LoadBalancingPolicy.ts @@ -1,25 +1,17 @@ // Original file: deps/envoy-api/envoy/config/cluster/v3/cluster.proto -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy { - /** - * Required. The name of the LB policy. - */ - 'name'?: (string); - 'typed_config'?: (_google_protobuf_Any | null); + 'typed_extension_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); } export interface _envoy_config_cluster_v3_LoadBalancingPolicy_Policy__Output { - /** - * Required. The name of the LB policy. - */ - 'name': (string); - 'typed_config': (_google_protobuf_Any__Output | null); + 'typed_extension_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); } /** - * [#not-implemented-hide:] Extensible load balancing policy configuration. + * Extensible load balancing policy configuration. * * Every LB policy defined via this mechanism will be identified via a unique name using reverse * DNS notation. If the policy needs configuration parameters, it must define a message for its @@ -49,7 +41,7 @@ export interface LoadBalancingPolicy { } /** - * [#not-implemented-hide:] Extensible load balancing policy configuration. + * Extensible load balancing policy configuration. * * Every LB policy defined via this mechanism will be identified via a unique name using reverse * DNS notation. If the policy needs configuration parameters, it must define a message for its diff --git a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts index abae2e270..789004ad4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/cluster/v3/OutlierDetection.ts @@ -24,7 +24,7 @@ export interface OutlierDetection { /** * The base time that a host is ejected for. The real time is equal to the * base time multiplied by the number of times the host has been ejected and is - * capped by :ref:`max_ejection_time`. + * capped by :ref:`max_ejection_time`. * Defaults to 30000ms or 30s. */ 'base_ejection_time'?: (_google_protobuf_Duration | null); @@ -84,17 +84,17 @@ export interface OutlierDetection { /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: - * :ref:`consecutive_local_origin_failure`, - * :ref:`enforcing_consecutive_local_origin_failure` + * :ref:`consecutive_local_origin_failure`, + * :ref:`enforcing_consecutive_local_origin_failure` * and - * :ref:`enforcing_local_origin_success_rate`. + * :ref:`enforcing_local_origin_success_rate`. * Defaults to false. */ 'split_external_local_origin_errors'?: (boolean); /** * The number of consecutive locally originated failures before ejection * occurs. Defaults to 5. Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value | null); @@ -103,7 +103,7 @@ export interface OutlierDetection { * is detected through consecutive locally originated failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_consecutive_local_origin_failure'?: (_google_protobuf_UInt32Value | null); @@ -112,7 +112,7 @@ export interface OutlierDetection { * is detected through success rate statistics for locally originated errors. * This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_local_origin_success_rate'?: (_google_protobuf_UInt32Value | null); @@ -151,9 +151,9 @@ export interface OutlierDetection { */ 'failure_percentage_request_volume'?: (_google_protobuf_UInt32Value | null); /** - * The maximum time that a host is ejected for. See :ref:`base_ejection_time` - * for more information. - * Defaults to 300000ms or 300s. + * The maximum time that a host is ejected for. See :ref:`base_ejection_time` + * for more information. If not specified, the default value (300000ms or 300s) or + * :ref:`base_ejection_time` value is applied, whatever is larger. */ 'max_ejection_time'?: (_google_protobuf_Duration | null); } @@ -179,7 +179,7 @@ export interface OutlierDetection__Output { /** * The base time that a host is ejected for. The real time is equal to the * base time multiplied by the number of times the host has been ejected and is - * capped by :ref:`max_ejection_time`. + * capped by :ref:`max_ejection_time`. * Defaults to 30000ms or 30s. */ 'base_ejection_time': (_google_protobuf_Duration__Output | null); @@ -239,17 +239,17 @@ export interface OutlierDetection__Output { /** * Determines whether to distinguish local origin failures from external errors. If set to true * the following configuration parameters are taken into account: - * :ref:`consecutive_local_origin_failure`, - * :ref:`enforcing_consecutive_local_origin_failure` + * :ref:`consecutive_local_origin_failure`, + * :ref:`enforcing_consecutive_local_origin_failure` * and - * :ref:`enforcing_local_origin_success_rate`. + * :ref:`enforcing_local_origin_success_rate`. * Defaults to false. */ 'split_external_local_origin_errors': (boolean); /** * The number of consecutive locally originated failures before ejection * occurs. Defaults to 5. Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output | null); @@ -258,7 +258,7 @@ export interface OutlierDetection__Output { * is detected through consecutive locally originated failures. This setting can be * used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_consecutive_local_origin_failure': (_google_protobuf_UInt32Value__Output | null); @@ -267,7 +267,7 @@ export interface OutlierDetection__Output { * is detected through success rate statistics for locally originated errors. * This setting can be used to disable ejection or to ramp it up slowly. Defaults to 100. * Parameter takes effect only when - * :ref:`split_external_local_origin_errors` + * :ref:`split_external_local_origin_errors` * is set to true. */ 'enforcing_local_origin_success_rate': (_google_protobuf_UInt32Value__Output | null); @@ -306,9 +306,9 @@ export interface OutlierDetection__Output { */ 'failure_percentage_request_volume': (_google_protobuf_UInt32Value__Output | null); /** - * The maximum time that a host is ejected for. See :ref:`base_ejection_time` - * for more information. - * Defaults to 300000ms or 300s. + * The maximum time that a host is ejected for. See :ref:`base_ejection_time` + * for more information. If not specified, the default value (300000ms or 300s) or + * :ref:`base_ejection_time` value is applied, whatever is larger. */ 'max_ejection_time': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts index 824ef93c8..428ab4b56 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AggregatedConfigSource.ts @@ -3,7 +3,7 @@ /** * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to + * set in :ref:`ConfigSource ` can be used to * specify that ADS is to be used. */ export interface AggregatedConfigSource { @@ -11,7 +11,7 @@ export interface AggregatedConfigSource { /** * Aggregated Discovery Service (ADS) options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to + * set in :ref:`ConfigSource ` can be used to * specify that ADS is to be used. */ export interface AggregatedConfigSource__Output { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AlternateProtocolsCacheOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AlternateProtocolsCacheOptions.ts new file mode 100644 index 000000000..6fb167174 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/AlternateProtocolsCacheOptions.ts @@ -0,0 +1,72 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * Configures the alternate protocols cache which tracks alternate protocols that can be used to + * make an HTTP connection to an origin server. See https://tools.ietf.org/html/rfc7838 for + * HTTP Alternative Services and https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-04 + * for the "HTTPS" DNS resource record. + */ +export interface AlternateProtocolsCacheOptions { + /** + * The name of the cache. Multiple named caches allow independent alternate protocols cache + * configurations to operate within a single Envoy process using different configurations. All + * alternate protocols cache options with the same name *must* be equal in all fields when + * referenced from different configuration components. Configuration will fail to load if this is + * not the case. + */ + 'name'?: (string); + /** + * The maximum number of entries that the cache will hold. If not specified defaults to 1024. + * + * .. note: + * + * The implementation is approximate and enforced independently on each worker thread, thus + * it is possible for the maximum entries in the cache to go slightly above the configured + * value depending on timing. This is similar to how other circuit breakers work. + */ + 'max_entries'?: (_google_protobuf_UInt32Value | null); + /** + * Allows configuring a persistent + * :ref:`key value store ` to flush + * alternate protocols entries to disk. + * This function is currently only supported if concurrency is 1 + */ + 'key_value_store_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); +} + +/** + * Configures the alternate protocols cache which tracks alternate protocols that can be used to + * make an HTTP connection to an origin server. See https://tools.ietf.org/html/rfc7838 for + * HTTP Alternative Services and https://datatracker.ietf.org/doc/html/draft-ietf-dnsop-svcb-https-04 + * for the "HTTPS" DNS resource record. + */ +export interface AlternateProtocolsCacheOptions__Output { + /** + * The name of the cache. Multiple named caches allow independent alternate protocols cache + * configurations to operate within a single Envoy process using different configurations. All + * alternate protocols cache options with the same name *must* be equal in all fields when + * referenced from different configuration components. Configuration will fail to load if this is + * not the case. + */ + 'name': (string); + /** + * The maximum number of entries that the cache will hold. If not specified defaults to 1024. + * + * .. note: + * + * The implementation is approximate and enforced independently on each worker thread, thus + * it is possible for the maximum entries in the cache to go slightly above the configured + * value depending on timing. This is similar to how other circuit breakers work. + */ + 'max_entries': (_google_protobuf_UInt32Value__Output | null); + /** + * Allows configuring a persistent + * :ref:`key value store ` to flush + * alternate protocols entries to disk. + * This function is currently only supported if concurrency is 1 + */ + 'key_value_store_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts index b85b8d5de..1049dec0c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BackoffStrategy.ts @@ -9,15 +9,15 @@ export interface BackoffStrategy { /** * The base interval to be used for the next back off computation. It should * be greater than zero and less than or equal to :ref:`max_interval - * `. + * `. */ 'base_interval'?: (_google_protobuf_Duration | null); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval - * ` if set. The default + * ` if set. The default * is 10 times the :ref:`base_interval - * `. + * `. */ 'max_interval'?: (_google_protobuf_Duration | null); } @@ -29,15 +29,15 @@ export interface BackoffStrategy__Output { /** * The base interval to be used for the next back off computation. It should * be greater than zero and less than or equal to :ref:`max_interval - * `. + * `. */ 'base_interval': (_google_protobuf_Duration__Output | null); /** * Specifies the maximum interval between retries. This parameter is optional, * but must be greater than or equal to the :ref:`base_interval - * ` if set. The default + * ` if set. The default * is 10 times the :ref:`base_interval - * `. + * `. */ 'max_interval': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts index db6b1f654..d3b2cc584 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/BindConfig.ts @@ -12,7 +12,7 @@ export interface BindConfig { /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address - * ` to be an IP address + * ` to be an IP address * that is not configured on the system running Envoy. When this flag is set * to false, the option *IP_FREEBIND* is disabled on the socket. When this * flag is not set (default), the socket is not modified, i.e. the option is @@ -34,7 +34,7 @@ export interface BindConfig__Output { /** * Whether to set the *IP_FREEBIND* option when creating the socket. When this * flag is set to true, allows the :ref:`source_address - * ` to be an IP address + * ` to be an IP address * that is not configured on the system running Envoy. When this flag is set * to false, the option *IP_FREEBIND* is disabled on the socket. When this * flag is not set (default), the socket is not modified, i.e. the option is diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts index df4ff39ff..4e01fa354 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/CidrRange.ts @@ -12,7 +12,7 @@ export interface CidrRange { */ 'address_prefix'?: (string); /** - * Length of prefix, e.g. 0, 32. + * Length of prefix, e.g. 0, 32. Defaults to 0 when unset. */ 'prefix_len'?: (_google_protobuf_UInt32Value | null); } @@ -27,7 +27,7 @@ export interface CidrRange__Output { */ 'address_prefix': (string); /** - * Length of prefix, e.g. 0, 32. + * Length of prefix, e.g. 0, 32. Defaults to 0 when unset. */ 'prefix_len': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts index aaf4d9564..a39c0f077 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/ConfigSource.ts @@ -10,7 +10,7 @@ import type { Authority as _xds_core_v3_Authority, Authority__Output as _xds_cor /** * Configuration for :ref:`listeners `, :ref:`clusters * `, :ref:`routes - * `, :ref:`endpoints + * `, :ref:`endpoints * ` etc. may either be sourced from the * filesystem or from an xDS API source. Filesystem configs are watched with * inotify for updates. @@ -19,7 +19,7 @@ import type { Authority as _xds_core_v3_Authority, Authority__Output as _xds_cor export interface ConfigSource { /** * Path on the filesystem to source and watch for configuration updates. - * When sourcing configuration for :ref:`secret `, + * When sourcing configuration for :ref:`secret `, * the certificate and key files are also watched for updates. * * .. note:: @@ -56,7 +56,7 @@ export interface ConfigSource { * [#not-implemented-hide:] * When set, the client will access the resources from the same server it got the * ConfigSource from, although not necessarily from the same stream. This is similar to the - * :ref:`ads` field, except that the client may use a + * :ref:`ads` field, except that the client may use a * different stream to the same server. As a result, this field can be used for things * like LRS that cannot be sent on an ADS stream. It can also be used to link from (e.g.) * LDS to RDS on the same server without requiring the management server to know its name @@ -85,7 +85,7 @@ export interface ConfigSource { /** * Configuration for :ref:`listeners `, :ref:`clusters * `, :ref:`routes - * `, :ref:`endpoints + * `, :ref:`endpoints * ` etc. may either be sourced from the * filesystem or from an xDS API source. Filesystem configs are watched with * inotify for updates. @@ -94,7 +94,7 @@ export interface ConfigSource { export interface ConfigSource__Output { /** * Path on the filesystem to source and watch for configuration updates. - * When sourcing configuration for :ref:`secret `, + * When sourcing configuration for :ref:`secret `, * the certificate and key files are also watched for updates. * * .. note:: @@ -131,7 +131,7 @@ export interface ConfigSource__Output { * [#not-implemented-hide:] * When set, the client will access the resources from the same server it got the * ConfigSource from, although not necessarily from the same stream. This is similar to the - * :ref:`ads` field, except that the client may use a + * :ref:`ads` field, except that the client may use a * different stream to the same server. As a result, this field can be used for things * like LRS that cannot be sent on an ADS stream. It can also be used to link from (e.g.) * LDS to RDS on the same server without requiring the management server to know its name diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolutionConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolutionConfig.ts new file mode 100644 index 000000000..c87be12e2 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolutionConfig.ts @@ -0,0 +1,42 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/resolver.proto + +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { DnsResolverOptions as _envoy_config_core_v3_DnsResolverOptions, DnsResolverOptions__Output as _envoy_config_core_v3_DnsResolverOptions__Output } from '../../../../envoy/config/core/v3/DnsResolverOptions'; + +/** + * DNS resolution configuration which includes the underlying dns resolver addresses and options. + */ +export interface DnsResolutionConfig { + /** + * A list of dns resolver addresses. If specified, the DNS client library will perform resolution + * via the underlying DNS resolvers. Otherwise, the default system resolvers + * (e.g., /etc/resolv.conf) will be used. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple's API only allows overriding DNS resolvers via system settings. + */ + 'resolvers'?: (_envoy_config_core_v3_Address)[]; + /** + * Configuration of DNS resolver option flags which control the behavior of the DNS resolver. + */ + 'dns_resolver_options'?: (_envoy_config_core_v3_DnsResolverOptions | null); +} + +/** + * DNS resolution configuration which includes the underlying dns resolver addresses and options. + */ +export interface DnsResolutionConfig__Output { + /** + * A list of dns resolver addresses. If specified, the DNS client library will perform resolution + * via the underlying DNS resolvers. Otherwise, the default system resolvers + * (e.g., /etc/resolv.conf) will be used. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple's API only allows overriding DNS resolvers via system settings. + */ + 'resolvers': (_envoy_config_core_v3_Address__Output)[]; + /** + * Configuration of DNS resolver option flags which control the behavior of the DNS resolver. + */ + 'dns_resolver_options': (_envoy_config_core_v3_DnsResolverOptions__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolverOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolverOptions.ts new file mode 100644 index 000000000..11b68b150 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/DnsResolverOptions.ts @@ -0,0 +1,36 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/resolver.proto + + +/** + * Configuration of DNS resolver option flags which control the behavior of the DNS resolver. + */ +export interface DnsResolverOptions { + /** + * Use TCP for all DNS queries instead of the default protocol UDP. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple's API only uses UDP for DNS resolution. + */ + 'use_tcp_for_dns_lookups'?: (boolean); + /** + * Do not use the default search domains; only query hostnames as-is or as aliases. + */ + 'no_default_search_domain'?: (boolean); +} + +/** + * Configuration of DNS resolver option flags which control the behavior of the DNS resolver. + */ +export interface DnsResolverOptions__Output { + /** + * Use TCP for all DNS queries instead of the default protocol UDP. + * Setting this value causes failure if the + * ``envoy.restart_features.use_apple_api_for_dns_lookups`` runtime value is true during + * server startup. Apple's API only uses UDP for DNS resolution. + */ + 'use_tcp_for_dns_lookups': (boolean); + /** + * Do not use the default search domains; only query hostnames as-is or as aliases. + */ + 'no_default_search_domain': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts index dfe6a52b4..936e433db 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/EnvoyInternalAddress.ts @@ -8,7 +8,7 @@ */ export interface EnvoyInternalAddress { /** - * [#not-implemented-hide:] The :ref:`listener name ` of the destination internal listener. + * [#not-implemented-hide:] The :ref:`listener name ` of the destination internal listener. */ 'server_listener_name'?: (string); 'address_name_specifier'?: "server_listener_name"; @@ -21,7 +21,7 @@ export interface EnvoyInternalAddress { */ export interface EnvoyInternalAddress__Output { /** - * [#not-implemented-hide:] The :ref:`listener name ` of the destination internal listener. + * [#not-implemented-hide:] The :ref:`listener name ` of the destination internal listener. */ 'server_listener_name'?: (string); 'address_name_specifier': "server_listener_name"; diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts index 0e55d018b..0d81f7340 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/GrpcService.ts @@ -148,8 +148,8 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials export interface _envoy_config_core_v3_GrpcService_EnvoyGrpc { /** * The name of the upstream gRPC cluster. SSL credentials will be supplied - * in the :ref:`Cluster ` :ref:`transport_socket - * `. + * in the :ref:`Cluster ` :ref:`transport_socket + * `. */ 'cluster_name'?: (string); /** @@ -162,8 +162,8 @@ export interface _envoy_config_core_v3_GrpcService_EnvoyGrpc { export interface _envoy_config_core_v3_GrpcService_EnvoyGrpc__Output { /** * The name of the upstream gRPC cluster. SSL credentials will be supplied - * in the :ref:`Cluster ` :ref:`transport_socket - * `. + * in the :ref:`Cluster ` :ref:`transport_socket + * `. */ 'cluster_name': (string); /** @@ -180,7 +180,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc { /** * The target URI when using the `Google C++ gRPC client * `_. SSL credentials will be supplied in - * :ref:`channel_credentials `. + * :ref:`channel_credentials `. */ 'target_uri'?: (string); 'channel_credentials'?: (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials | null); @@ -230,7 +230,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc__Output { /** * The target URI when using the `Google C++ gRPC client * `_. SSL credentials will be supplied in - * :ref:`channel_credentials `. + * :ref:`channel_credentials `. */ 'target_uri': (string); 'channel_credentials': (_envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelCredentials__Output | null); @@ -300,12 +300,18 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_GoogleLocalCredent export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin { 'name'?: (string); 'typed_config'?: (_google_protobuf_Any | null); + /** + * [#extension-category: envoy.grpc_credentials] + */ 'config_type'?: "typed_config"; } export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_CallCredentials_MetadataCredentialsFromPlugin__Output { 'name': (string); 'typed_config'?: (_google_protobuf_Any__Output | null); + /** + * [#extension-category: envoy.grpc_credentials] + */ 'config_type': "typed_config"; } @@ -485,7 +491,7 @@ export interface _envoy_config_core_v3_GrpcService_GoogleGrpc_ChannelArgs_Value_ /** * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. + * ` and filter configurations. * [#next-free-field: 6] */ export interface GrpcService { @@ -519,7 +525,7 @@ export interface GrpcService { /** * gRPC service configuration. This is used by :ref:`ApiConfigSource - * ` and filter configurations. + * ` and filter configurations. * [#next-free-field: 6] */ export interface GrpcService__Output { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts index 29f9d6695..7ba7e9d8d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HeaderValueOption.ts @@ -3,6 +3,31 @@ import type { HeaderValue as _envoy_config_core_v3_HeaderValue, HeaderValue__Output as _envoy_config_core_v3_HeaderValue__Output } from '../../../../envoy/config/core/v3/HeaderValue'; import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + +/** + * Describes the supported actions types for header append action. + */ +export enum _envoy_config_core_v3_HeaderValueOption_HeaderAppendAction { + /** + * This action will append the specified value to the existing values if the header + * already exists. If the header doesn't exist then this will add the header with + * specified key and value. + */ + APPEND_IF_EXISTS_OR_ADD = 0, + /** + * This action will add the header if it doesn't already exist. If the header + * already exists then this will be a no-op. + */ + ADD_IF_ABSENT = 1, + /** + * This action will overwrite the specified value by discarding any existing values if + * the header already exists. If the header doesn't exist then this will add the header + * with specified key and value. + */ + OVERWRITE_IF_EXISTS_OR_ADD = 2, +} + /** * Header name/value pair plus option to control append behavior. */ @@ -16,6 +41,11 @@ export interface HeaderValueOption { * existing values. Otherwise it replaces any existing values. */ 'append'?: (_google_protobuf_BoolValue | null); + /** + * [#not-implemented-hide:] Describes the action taken to append/overwrite the given value for an existing header + * or to only add this header if it's absent. Value defaults to :ref:`APPEND_IF_EXISTS_OR_ADD`. + */ + 'append_action'?: (_envoy_config_core_v3_HeaderValueOption_HeaderAppendAction | keyof typeof _envoy_config_core_v3_HeaderValueOption_HeaderAppendAction); } /** @@ -31,4 +61,9 @@ export interface HeaderValueOption__Output { * existing values. Otherwise it replaces any existing values. */ 'append': (_google_protobuf_BoolValue__Output | null); + /** + * [#not-implemented-hide:] Describes the action taken to append/overwrite the given value for an existing header + * or to only add this header if it's absent. Value defaults to :ref:`APPEND_IF_EXISTS_OR_ADD`. + */ + 'append_action': (keyof typeof _envoy_config_core_v3_HeaderValueOption_HeaderAppendAction); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts index 6dbbf6f4d..8882de614 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HealthCheck.ts @@ -24,6 +24,7 @@ export interface _envoy_config_core_v3_HealthCheck_CustomHealthCheck { /** * A custom health checker specific configuration which depends on the custom health checker * being instantiated. See :api:`envoy/config/health_checker` for reference. + * [#extension-category: envoy.health_checkers] */ 'config_type'?: "typed_config"; } @@ -40,6 +41,7 @@ export interface _envoy_config_core_v3_HealthCheck_CustomHealthCheck__Output { /** * A custom health checker specific configuration which depends on the custom health checker * being instantiated. See :api:`envoy/config/health_checker` for reference. + * [#extension-category: envoy.health_checkers] */ 'config_type': "typed_config"; } @@ -63,7 +65,7 @@ export interface _envoy_config_core_v3_HealthCheck_GrpcHealthCheck { * The value of the :authority header in the gRPC health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The authority header can be customized for a specific endpoint by setting - * the :ref:`hostname ` field. + * the :ref:`hostname ` field. */ 'authority'?: (string); } @@ -87,20 +89,20 @@ export interface _envoy_config_core_v3_HealthCheck_GrpcHealthCheck__Output { * The value of the :authority header in the gRPC health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The authority header can be customized for a specific endpoint by setting - * the :ref:`hostname ` field. + * the :ref:`hostname ` field. */ 'authority': (string); } /** - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck { /** * The value of the host header in the HTTP health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The host header can be customized for a specific endpoint by setting the - * :ref:`hostname ` field. + * :ref:`hostname ` field. */ 'host'?: (string); /** @@ -131,10 +133,23 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck { /** * Specifies a list of HTTP response statuses considered healthy. If provided, replaces default * 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open - * semantics of :ref:`Int64Range `. The start and end of each + * semantics of :ref:`Int64Range `. The start and end of each * range are required. Only statuses in the range [100, 600) are allowed. */ 'expected_statuses'?: (_envoy_type_v3_Int64Range)[]; + /** + * Specifies a list of HTTP response statuses considered retriable. If provided, responses in this range + * will count towards the configured :ref:`unhealthy_threshold `, + * but will not result in the host being considered immediately unhealthy. Ranges follow half-open semantics of + * :ref:`Int64Range `. The start and end of each range are required. + * Only statuses in the range [100, 600) are allowed. The :ref:`expected_statuses ` + * field takes precedence for any range overlaps with this field i.e. if status code 200 is both retriable and expected, a 200 response will + * be considered a successful health check. By default all responses not in + * :ref:`expected_statuses ` will result in + * the host being considered immediately unhealthy i.e. if status code 200 is expected and there are no configured retriable statuses, any + * non-200 response will result in the host being marked unhealthy. + */ + 'retriable_statuses'?: (_envoy_type_v3_Int64Range)[]; /** * Use specified application protocol for health checks. */ @@ -142,21 +157,21 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck { /** * An optional service name parameter which is used to validate the identity of * the health checked cluster using a :ref:`StringMatcher - * `. See the :ref:`architecture overview + * `. See the :ref:`architecture overview * ` for more information. */ 'service_name_matcher'?: (_envoy_type_matcher_v3_StringMatcher | null); } /** - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output { /** * The value of the host header in the HTTP health check request. If * left empty (default value), the name of the cluster this health check is associated * with will be used. The host header can be customized for a specific endpoint by setting the - * :ref:`hostname ` field. + * :ref:`hostname ` field. */ 'host': (string); /** @@ -187,10 +202,23 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output { /** * Specifies a list of HTTP response statuses considered healthy. If provided, replaces default * 200-only policy - 200 must be included explicitly as needed. Ranges follow half-open - * semantics of :ref:`Int64Range `. The start and end of each + * semantics of :ref:`Int64Range `. The start and end of each * range are required. Only statuses in the range [100, 600) are allowed. */ 'expected_statuses': (_envoy_type_v3_Int64Range__Output)[]; + /** + * Specifies a list of HTTP response statuses considered retriable. If provided, responses in this range + * will count towards the configured :ref:`unhealthy_threshold `, + * but will not result in the host being considered immediately unhealthy. Ranges follow half-open semantics of + * :ref:`Int64Range `. The start and end of each range are required. + * Only statuses in the range [100, 600) are allowed. The :ref:`expected_statuses ` + * field takes precedence for any range overlaps with this field i.e. if status code 200 is both retriable and expected, a 200 response will + * be considered a successful health check. By default all responses not in + * :ref:`expected_statuses ` will result in + * the host being considered immediately unhealthy i.e. if status code 200 is expected and there are no configured retriable statuses, any + * non-200 response will result in the host being marked unhealthy. + */ + 'retriable_statuses': (_envoy_type_v3_Int64Range__Output)[]; /** * Use specified application protocol for health checks. */ @@ -198,7 +226,7 @@ export interface _envoy_config_core_v3_HealthCheck_HttpHealthCheck__Output { /** * An optional service name parameter which is used to validate the identity of * the health checked cluster using a :ref:`StringMatcher - * `. See the :ref:`architecture overview + * `. See the :ref:`architecture overview * ` for more information. */ 'service_name_matcher': (_envoy_type_matcher_v3_StringMatcher__Output | null); @@ -290,7 +318,7 @@ export interface _envoy_config_core_v3_HealthCheck_TlsOptions { /** * Specifies the ALPN protocols for health check connections. This is useful if the * corresponding upstream is using ALPN-based :ref:`FilterChainMatch - * ` along with different protocols for health checks + * ` along with different protocols for health checks * versus data connections. If empty, no ALPN protocols will be set on health check connections. */ 'alpn_protocols'?: (string)[]; @@ -306,7 +334,7 @@ export interface _envoy_config_core_v3_HealthCheck_TlsOptions__Output { /** * Specifies the ALPN protocols for health check connections. This is useful if the * corresponding upstream is using ALPN-based :ref:`FilterChainMatch - * ` along with different protocols for health checks + * ` along with different protocols for health checks * versus data connections. If empty, no ALPN protocols will be set on health check connections. */ 'alpn_protocols': (string)[]; @@ -332,8 +360,10 @@ export interface HealthCheck { 'interval_jitter'?: (_google_protobuf_Duration | null); /** * The number of unhealthy health checks required before a host is marked - * unhealthy. Note that for *http* health checking if a host responds with 503 - * this threshold is ignored and the host is considered unhealthy immediately. + * unhealthy. Note that for *http* health checking if a host responds with a code not in + * :ref:`expected_statuses ` + * or :ref:`retriable_statuses `, + * this threshold is ignored and the host is considered immediately unhealthy. */ 'unhealthy_threshold'?: (_google_protobuf_UInt32Value | null); /** @@ -440,7 +470,7 @@ export interface HealthCheck { 'event_service'?: (_envoy_config_core_v3_EventServiceConfig | null); /** * Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's - * :ref:`tranport socket matches `. + * :ref:`tranport socket matches `. * For example, the following match criteria * * .. code-block:: yaml @@ -448,7 +478,7 @@ export interface HealthCheck { * transport_socket_match_criteria: * useMTLS: true * - * Will match the following :ref:`cluster socket match ` + * Will match the following :ref:`cluster socket match ` * * .. code-block:: yaml * @@ -461,13 +491,13 @@ export interface HealthCheck { * config: { ... } # tls socket configuration * * If this field is set, then for health checks it will supersede an entry of *envoy.transport_socket* in the - * :ref:`LbEndpoint.Metadata `. + * :ref:`LbEndpoint.Metadata `. * This allows using different transport socket capabilities for health checking versus proxying to the * endpoint. * * If the key/values pairs specified do not match any - * :ref:`transport socket matches `, - * the cluster's :ref:`transport socket ` + * :ref:`transport socket matches `, + * the cluster's :ref:`transport socket ` * will be used for health check socket configuration. */ 'transport_socket_match_criteria'?: (_google_protobuf_Struct | null); @@ -510,8 +540,10 @@ export interface HealthCheck__Output { 'interval_jitter': (_google_protobuf_Duration__Output | null); /** * The number of unhealthy health checks required before a host is marked - * unhealthy. Note that for *http* health checking if a host responds with 503 - * this threshold is ignored and the host is considered unhealthy immediately. + * unhealthy. Note that for *http* health checking if a host responds with a code not in + * :ref:`expected_statuses ` + * or :ref:`retriable_statuses `, + * this threshold is ignored and the host is considered immediately unhealthy. */ 'unhealthy_threshold': (_google_protobuf_UInt32Value__Output | null); /** @@ -618,7 +650,7 @@ export interface HealthCheck__Output { 'event_service': (_envoy_config_core_v3_EventServiceConfig__Output | null); /** * Optional key/value pairs that will be used to match a transport socket from those specified in the cluster's - * :ref:`tranport socket matches `. + * :ref:`tranport socket matches `. * For example, the following match criteria * * .. code-block:: yaml @@ -626,7 +658,7 @@ export interface HealthCheck__Output { * transport_socket_match_criteria: * useMTLS: true * - * Will match the following :ref:`cluster socket match ` + * Will match the following :ref:`cluster socket match ` * * .. code-block:: yaml * @@ -639,13 +671,13 @@ export interface HealthCheck__Output { * config: { ... } # tls socket configuration * * If this field is set, then for health checks it will supersede an entry of *envoy.transport_socket* in the - * :ref:`LbEndpoint.Metadata `. + * :ref:`LbEndpoint.Metadata `. * This allows using different transport socket capabilities for health checking versus proxying to the * endpoint. * * If the key/values pairs specified do not match any - * :ref:`transport socket matches `, - * the cluster's :ref:`transport socket ` + * :ref:`transport socket matches `, + * the cluster's :ref:`transport socket ` * will be used for health check socket configuration. */ 'transport_socket_match_criteria': (_google_protobuf_Struct__Output | null); diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts index 89889d390..40b7408f6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http1ProtocolOptions.ts @@ -1,7 +1,11 @@ // Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; +/** + * [#next-free-field: 9] + */ export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat { /** * Formats the header by proper casing words: the first character and any character following @@ -11,9 +15,18 @@ export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat { * are not covered. For example, the "TE" header will be formatted as "Te". */ 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords | null); - 'header_format'?: "proper_case_words"; + /** + * Configuration for stateful formatter extensions that allow using received headers to + * affect the output of encoding headers. E.g., preserving case during proxying. + * [#extension-category: envoy.http.stateful_header_formatters] + */ + 'stateful_formatter'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + 'header_format'?: "proper_case_words"|"stateful_formatter"; } +/** + * [#next-free-field: 9] + */ export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Output { /** * Formats the header by proper casing words: the first character and any character following @@ -23,7 +36,13 @@ export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat__Out * are not covered. For example, the "TE" header will be formatted as "Te". */ 'proper_case_words'?: (_envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords__Output | null); - 'header_format': "proper_case_words"; + /** + * Configuration for stateful formatter extensions that allow using received headers to + * affect the output of encoding headers. E.g., preserving case during proxying. + * [#extension-category: envoy.http.stateful_header_formatters] + */ + 'stateful_formatter'?: (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + 'header_format': "proper_case_words"|"stateful_formatter"; } export interface _envoy_config_core_v3_Http1ProtocolOptions_HeaderKeyFormat_ProperCaseWords { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts index 52908c961..786e2a00d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http2ProtocolOptions.ts @@ -53,6 +53,10 @@ export interface Http2ProtocolOptions { * For upstream connections, this also limits how many streams Envoy will initiate concurrently * on a single connection. If the limit is reached, Envoy may queue requests or establish * additional connections (as allowed per circuit breaker limits). + * + * This acts as an upper bound: Envoy will lower the max concurrent streams allowed on a given + * connection based on upstream settings. Config dumps will reflect the configured upper bound, + * not the per-connection negotiated limits. */ 'max_concurrent_streams'?: (_google_protobuf_UInt32Value | null); /** @@ -233,6 +237,10 @@ export interface Http2ProtocolOptions__Output { * For upstream connections, this also limits how many streams Envoy will initiate concurrently * on a single connection. If the limit is reached, Envoy may queue requests or establish * additional connections (as allowed per circuit breaker limits). + * + * This acts as an upper bound: Envoy will lower the max concurrent streams allowed on a given + * connection based on upstream settings. Config dumps will reflect the configured upper bound, + * not the per-connection negotiated limits. */ 'max_concurrent_streams': (_google_protobuf_UInt32Value__Output | null); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts index 320285d87..51b31b8e7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Http3ProtocolOptions.ts @@ -1,22 +1,56 @@ // Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto +import type { QuicProtocolOptions as _envoy_config_core_v3_QuicProtocolOptions, QuicProtocolOptions__Output as _envoy_config_core_v3_QuicProtocolOptions__Output } from '../../../../envoy/config/core/v3/QuicProtocolOptions'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; /** - * [#not-implemented-hide:] - * - * A message which allows using HTTP/3 as an upstream protocol. - * - * Eventually this will include configuration for tuning HTTP/3. + * A message which allows using HTTP/3. + * [#next-free-field: 6] */ export interface Http3ProtocolOptions { + 'quic_protocol_options'?: (_envoy_config_core_v3_QuicProtocolOptions | null); + /** + * Allows invalid HTTP messaging and headers. When this option is disabled (default), then + * the whole HTTP/3 connection is terminated upon receiving invalid HEADERS frame. However, + * when this option is enabled, only the offending stream is terminated. + * + * If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging + * `. + */ + 'override_stream_error_on_invalid_http_message'?: (_google_protobuf_BoolValue | null); + /** + * Allows proxying Websocket and other upgrades over HTTP/3 CONNECT using + * the header mechanisms from the `HTTP/2 extended connect RFC + * `_ + * and settings `proposed for HTTP/3 + * `_ + * Note that HTTP/3 CONNECT is not yet an RFC. + */ + 'allow_extended_connect'?: (boolean); } /** - * [#not-implemented-hide:] - * - * A message which allows using HTTP/3 as an upstream protocol. - * - * Eventually this will include configuration for tuning HTTP/3. + * A message which allows using HTTP/3. + * [#next-free-field: 6] */ export interface Http3ProtocolOptions__Output { + 'quic_protocol_options': (_envoy_config_core_v3_QuicProtocolOptions__Output | null); + /** + * Allows invalid HTTP messaging and headers. When this option is disabled (default), then + * the whole HTTP/3 connection is terminated upon receiving invalid HEADERS frame. However, + * when this option is enabled, only the offending stream is terminated. + * + * If set, this overrides any HCM :ref:`stream_error_on_invalid_http_messaging + * `. + */ + 'override_stream_error_on_invalid_http_message': (_google_protobuf_BoolValue__Output | null); + /** + * Allows proxying Websocket and other upgrades over HTTP/3 CONNECT using + * the header mechanisms from the `HTTP/2 extended connect RFC + * `_ + * and settings `proposed for HTTP/3 + * `_ + * Note that HTTP/3 CONNECT is not yet an RFC. + */ + 'allow_extended_connect': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts index f689ba802..34a4053dd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/HttpProtocolOptions.ts @@ -32,7 +32,7 @@ export enum _envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresActi } /** - * [#next-free-field: 6] + * [#next-free-field: 7] */ export interface HttpProtocolOptions { /** @@ -41,7 +41,7 @@ export interface HttpProtocolOptions { * idle timeout is reached the connection will be closed. If the connection is an HTTP/2 * downstream connection a drain sequence will occur prior to closing the connection, see * :ref:`drain_timeout - * `. + * `. * Note that request based timeouts mean that HTTP/2 PINGs will not keep the connection alive. * If not specified, this defaults to 1 hour. To disable idle timeouts explicitly set this to 0. * @@ -51,7 +51,7 @@ export interface HttpProtocolOptions { * * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" * is configured, this timeout is scaled for downstream connections according to the value for - * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. + * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. */ 'idle_timeout'?: (_google_protobuf_Duration | null); /** @@ -63,10 +63,11 @@ export interface HttpProtocolOptions { /** * The maximum duration of a connection. The duration is defined as a period since a connection * was established. If not set, there is no max duration. When max_connection_duration is reached - * the connection will be closed. Drain sequence will occur prior to closing the connection if - * if's applicable. See :ref:`drain_timeout - * `. - * Note: not implemented for upstream connections. + * and if there are no active streams, the connection will be closed. If there are any active streams, + * the drain sequence will kick-in, and the connection will be force-closed after the drain period. + * See :ref:`drain_timeout + * `. + * Note: This feature is not yet implemented for the upstream connections. */ 'max_connection_duration'?: (_google_protobuf_Duration | null); /** @@ -80,10 +81,17 @@ export interface HttpProtocolOptions { * Note: upstream responses are not affected by this setting. */ 'headers_with_underscores_action'?: (_envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction | keyof typeof _envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction); + /** + * Optional maximum requests for both upstream and downstream connections. + * If not specified, there is no limit. + * Setting this parameter to 1 will effectively disable keep alive. + * For HTTP/2 and HTTP/3, due to concurrent stream processing, the limit is approximate. + */ + 'max_requests_per_connection'?: (_google_protobuf_UInt32Value | null); } /** - * [#next-free-field: 6] + * [#next-free-field: 7] */ export interface HttpProtocolOptions__Output { /** @@ -92,7 +100,7 @@ export interface HttpProtocolOptions__Output { * idle timeout is reached the connection will be closed. If the connection is an HTTP/2 * downstream connection a drain sequence will occur prior to closing the connection, see * :ref:`drain_timeout - * `. + * `. * Note that request based timeouts mean that HTTP/2 PINGs will not keep the connection alive. * If not specified, this defaults to 1 hour. To disable idle timeouts explicitly set this to 0. * @@ -102,7 +110,7 @@ export interface HttpProtocolOptions__Output { * * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" * is configured, this timeout is scaled for downstream connections according to the value for - * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. + * :ref:`HTTP_DOWNSTREAM_CONNECTION_IDLE `. */ 'idle_timeout': (_google_protobuf_Duration__Output | null); /** @@ -114,10 +122,11 @@ export interface HttpProtocolOptions__Output { /** * The maximum duration of a connection. The duration is defined as a period since a connection * was established. If not set, there is no max duration. When max_connection_duration is reached - * the connection will be closed. Drain sequence will occur prior to closing the connection if - * if's applicable. See :ref:`drain_timeout - * `. - * Note: not implemented for upstream connections. + * and if there are no active streams, the connection will be closed. If there are any active streams, + * the drain sequence will kick-in, and the connection will be force-closed after the drain period. + * See :ref:`drain_timeout + * `. + * Note: This feature is not yet implemented for the upstream connections. */ 'max_connection_duration': (_google_protobuf_Duration__Output | null); /** @@ -131,4 +140,11 @@ export interface HttpProtocolOptions__Output { * Note: upstream responses are not affected by this setting. */ 'headers_with_underscores_action': (keyof typeof _envoy_config_core_v3_HttpProtocolOptions_HeadersWithUnderscoresAction); + /** + * Optional maximum requests for both upstream and downstream connections. + * If not specified, there is no limit. + * Setting this parameter to 1 will effectively disable keep alive. + * For HTTP/2 and HTTP/3, due to concurrent stream processing, the limit is approximate. + */ + 'max_requests_per_connection': (_google_protobuf_UInt32Value__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts index 81344f864..2c274c6e1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/KeepaliveSettings.ts @@ -6,6 +6,7 @@ import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_ export interface KeepaliveSettings { /** * Send HTTP/2 PING frames at this period, in order to test that the connection is still alive. + * If this is zero, interval PINGs will not be sent. */ 'interval'?: (_google_protobuf_Duration | null); /** @@ -19,11 +20,20 @@ export interface KeepaliveSettings { * The default value is 15%. */ 'interval_jitter'?: (_envoy_type_v3_Percent | null); + /** + * If the connection has been idle for this duration, send a HTTP/2 ping ahead + * of new stream creation, to quickly detect dead connections. + * If this is zero, this type of PING will not be sent. + * If an interval ping is outstanding, a second ping will not be sent as the + * interval ping will determine if the connection is dead. + */ + 'connection_idle_interval'?: (_google_protobuf_Duration | null); } export interface KeepaliveSettings__Output { /** * Send HTTP/2 PING frames at this period, in order to test that the connection is still alive. + * If this is zero, interval PINGs will not be sent. */ 'interval': (_google_protobuf_Duration__Output | null); /** @@ -37,4 +47,12 @@ export interface KeepaliveSettings__Output { * The default value is 15%. */ 'interval_jitter': (_envoy_type_v3_Percent__Output | null); + /** + * If the connection has been idle for this duration, send a HTTP/2 ping ahead + * of new stream creation, to quickly detect dead connections. + * If this is zero, this type of PING will not be sent. + * If an interval ping is outstanding, a second ping will not be sent as the + * interval ping will determine if the connection is dead. + */ + 'connection_idle_interval': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts index 2b4b42a75..b15b53832 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Locality.ts @@ -6,13 +6,13 @@ */ export interface Locality { /** - * Region this :ref:`zone ` belongs to. + * Region this :ref:`zone ` belongs to. */ 'region'?: (string); /** * Defines the local service zone where Envoy is running. Though optional, it * should be set if discovery service routing is used and the discovery - * service exposes :ref:`zone data `, + * service exposes :ref:`zone data `, * either in this message or via :option:`--service-zone`. The meaning of zone * is context dependent, e.g. `Availability Zone (AZ) * `_ @@ -33,13 +33,13 @@ export interface Locality { */ export interface Locality__Output { /** - * Region this :ref:`zone ` belongs to. + * Region this :ref:`zone ` belongs to. */ 'region': (string); /** * Defines the local service zone where Envoy is running. Though optional, it * should be set if discovery service routing is used and the discovery - * service exposes :ref:`zone data `, + * service exposes :ref:`zone data `, * either in this message or via :option:`--service-zone`. The meaning of zone * is context dependent, e.g. `Availability Zone (AZ) * `_ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts index 8d1811c67..fb603c2ba 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Metadata.ts @@ -1,6 +1,7 @@ // Original file: deps/envoy-api/envoy/config/core/v3/base.proto import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** * Metadata provides additional inputs to filters based on matched listeners, @@ -30,8 +31,21 @@ export interface Metadata { /** * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* * namespace is reserved for Envoy's built-in filters. + * If both *filter_metadata* and + * :ref:`typed_filter_metadata ` + * fields are present in the metadata with same keys, + * only *typed_filter_metadata* field will be parsed. */ 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct}); + /** + * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* + * namespace is reserved for Envoy's built-in filters. + * The value is encoded as google.protobuf.Any. + * If both :ref:`filter_metadata ` + * and *typed_filter_metadata* fields are present in the metadata with same keys, + * only *typed_filter_metadata* field will be parsed. + */ + 'typed_filter_metadata'?: ({[key: string]: _google_protobuf_Any}); } /** @@ -62,6 +76,19 @@ export interface Metadata__Output { /** * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* * namespace is reserved for Envoy's built-in filters. + * If both *filter_metadata* and + * :ref:`typed_filter_metadata ` + * fields are present in the metadata with same keys, + * only *typed_filter_metadata* field will be parsed. */ 'filter_metadata': ({[key: string]: _google_protobuf_Struct__Output}); + /** + * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* + * namespace is reserved for Envoy's built-in filters. + * The value is encoded as google.protobuf.Any. + * If both :ref:`filter_metadata ` + * and *typed_filter_metadata* fields are present in the metadata with same keys, + * only *typed_filter_metadata* field will be parsed. + */ + 'typed_filter_metadata': ({[key: string]: _google_protobuf_Any__Output}); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts index 7218b802e..addd47a68 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/Node.ts @@ -5,12 +5,13 @@ import type { Locality as _envoy_config_core_v3_Locality, Locality__Output as _e import type { BuildVersion as _envoy_config_core_v3_BuildVersion, BuildVersion__Output as _envoy_config_core_v3_BuildVersion__Output } from '../../../../envoy/config/core/v3/BuildVersion'; import type { Extension as _envoy_config_core_v3_Extension, Extension__Output as _envoy_config_core_v3_Extension__Output } from '../../../../envoy/config/core/v3/Extension'; import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { ContextParams as _xds_core_v3_ContextParams, ContextParams__Output as _xds_core_v3_ContextParams__Output } from '../../../../xds/core/v3/ContextParams'; /** * Identifies a specific Envoy instance. The node identifier is presented to the * management server, which may use this identifier to distinguish per Envoy * configuration for serving. - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface Node { /** @@ -27,10 +28,10 @@ export interface Node { * optional, it should be set if any of the following features are used: * :ref:`statsd `, :ref:`health check cluster * verification - * `, - * :ref:`runtime override directory `, + * `, + * :ref:`runtime override directory `, * :ref:`user agent addition - * `, + * `, * :ref:`HTTP global rate limiting `, * :ref:`CDS `, and :ref:`HTTP tracing * `, either in this message or via @@ -79,6 +80,14 @@ export interface Node { * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. */ 'listening_addresses'?: (_envoy_config_core_v3_Address)[]; + /** + * Map from xDS resource type URL to dynamic context parameters. These may vary at runtime (unlike + * other fields in this message). For example, the xDS client may have a shard identifier that + * changes during the lifetime of the xDS client. In Envoy, this would be achieved by updating the + * dynamic context on the Server::Instance's LocalInfo context provider. The shard ID dynamic + * parameter then appears in this field during future discovery requests. + */ + 'dynamic_parameters'?: ({[key: string]: _xds_core_v3_ContextParams}); 'user_agent_version_type'?: "user_agent_version"|"user_agent_build_version"; } @@ -86,7 +95,7 @@ export interface Node { * Identifies a specific Envoy instance. The node identifier is presented to the * management server, which may use this identifier to distinguish per Envoy * configuration for serving. - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface Node__Output { /** @@ -103,10 +112,10 @@ export interface Node__Output { * optional, it should be set if any of the following features are used: * :ref:`statsd `, :ref:`health check cluster * verification - * `, - * :ref:`runtime override directory `, + * `, + * :ref:`runtime override directory `, * :ref:`user agent addition - * `, + * `, * :ref:`HTTP global rate limiting `, * :ref:`CDS `, and :ref:`HTTP tracing * `, either in this message or via @@ -155,5 +164,13 @@ export interface Node__Output { * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. */ 'listening_addresses': (_envoy_config_core_v3_Address__Output)[]; + /** + * Map from xDS resource type URL to dynamic context parameters. These may vary at runtime (unlike + * other fields in this message). For example, the xDS client may have a shard identifier that + * changes during the lifetime of the xDS client. In Envoy, this would be achieved by updating the + * dynamic context on the Server::Instance's LocalInfo context provider. The shard ID dynamic + * parameter then appears in this field during future discovery requests. + */ + 'dynamic_parameters': ({[key: string]: _xds_core_v3_ContextParams__Output}); 'user_agent_version_type': "user_agent_version"|"user_agent_build_version"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/QueryParameter.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/QueryParameter.ts new file mode 100644 index 000000000..4cf7952fb --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/QueryParameter.ts @@ -0,0 +1,30 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/base.proto + + +/** + * Query parameter name/value pair. + */ +export interface QueryParameter { + /** + * The key of the query parameter. Case sensitive. + */ + 'key'?: (string); + /** + * The value of the query parameter. + */ + 'value'?: (string); +} + +/** + * Query parameter name/value pair. + */ +export interface QueryParameter__Output { + /** + * The key of the query parameter. Case sensitive. + */ + 'key': (string); + /** + * The value of the query parameter. + */ + 'value': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/QuicProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/QuicProtocolOptions.ts new file mode 100644 index 000000000..6a653b54d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/QuicProtocolOptions.ts @@ -0,0 +1,69 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto + +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; + +/** + * QUIC protocol options which apply to both downstream and upstream connections. + */ +export interface QuicProtocolOptions { + /** + * Maximum number of streams that the client can negotiate per connection. 100 + * if not specified. + */ + 'max_concurrent_streams'?: (_google_protobuf_UInt32Value | null); + /** + * `Initial stream-level flow-control receive window + * `_ size. Valid values range from + * 1 to 16777216 (2^24, maximum supported by QUICHE) and defaults to 65536 (2^16). + * + * NOTE: 16384 (2^14) is the minimum window size supported in Google QUIC. If configured smaller than it, we will use 16384 instead. + * QUICHE IETF Quic implementation supports 1 bytes window. We only support increasing the default window size now, so it's also the minimum. + * + * This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the + * QUIC stream send and receive buffers. Once the buffer reaches this pointer, watermark callbacks will fire to + * stop the flow of data to the stream buffers. + */ + 'initial_stream_window_size'?: (_google_protobuf_UInt32Value | null); + /** + * Similar to *initial_stream_window_size*, but for connection-level + * flow-control. Valid values rage from 1 to 25165824 (24MB, maximum supported by QUICHE) and defaults to 65536 (2^16). + * window. Currently, this has the same minimum/default as *initial_stream_window_size*. + * + * NOTE: 16384 (2^14) is the minimum window size supported in Google QUIC. We only support increasing the default + * window size now, so it's also the minimum. + */ + 'initial_connection_window_size'?: (_google_protobuf_UInt32Value | null); +} + +/** + * QUIC protocol options which apply to both downstream and upstream connections. + */ +export interface QuicProtocolOptions__Output { + /** + * Maximum number of streams that the client can negotiate per connection. 100 + * if not specified. + */ + 'max_concurrent_streams': (_google_protobuf_UInt32Value__Output | null); + /** + * `Initial stream-level flow-control receive window + * `_ size. Valid values range from + * 1 to 16777216 (2^24, maximum supported by QUICHE) and defaults to 65536 (2^16). + * + * NOTE: 16384 (2^14) is the minimum window size supported in Google QUIC. If configured smaller than it, we will use 16384 instead. + * QUICHE IETF Quic implementation supports 1 bytes window. We only support increasing the default window size now, so it's also the minimum. + * + * This field also acts as a soft limit on the number of bytes Envoy will buffer per-stream in the + * QUIC stream send and receive buffers. Once the buffer reaches this pointer, watermark callbacks will fire to + * stop the flow of data to the stream buffers. + */ + 'initial_stream_window_size': (_google_protobuf_UInt32Value__Output | null); + /** + * Similar to *initial_stream_window_size*, but for connection-level + * flow-control. Valid values rage from 1 to 25165824 (24MB, maximum supported by QUICHE) and defaults to 65536 (2^16). + * window. Currently, this has the same minimum/default as *initial_stream_window_size*. + * + * NOTE: 16384 (2^14) is the minimum window size supported in Google QUIC. We only support increasing the default + * window size now, so it's also the minimum. + */ + 'initial_connection_window_size': (_google_protobuf_UInt32Value__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts index def6f7311..6e2af23e6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RetryPolicy.ts @@ -8,7 +8,7 @@ import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output a */ export interface RetryPolicy { /** - * Specifies parameters that control :ref:`retry backoff strategy `. + * Specifies parameters that control :ref:`retry backoff strategy `. * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ @@ -25,7 +25,7 @@ export interface RetryPolicy { */ export interface RetryPolicy__Output { /** - * Specifies parameters that control :ref:`retry backoff strategy `. + * Specifies parameters that control :ref:`retry backoff strategy `. * This parameter is optional, in which case the default base interval is 1000 milliseconds. The * default maximum interval is 10 times the base interval. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts index 619bfd484..3a2073294 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/RuntimeFractionalPercent.ts @@ -9,7 +9,7 @@ import type { FractionalPercent as _envoy_type_v3_FractionalPercent, FractionalP * .. note:: * * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML + * :ref:`FractionalPercent ` proto represented as JSON/YAML * and may also be represented as an integer with the assumption that the value is an integral * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. @@ -32,7 +32,7 @@ export interface RuntimeFractionalPercent { * .. note:: * * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML + * :ref:`FractionalPercent ` proto represented as JSON/YAML * and may also be represented as an integer with the assumption that the value is an integral * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SchemeHeaderTransformation.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SchemeHeaderTransformation.ts new file mode 100644 index 000000000..95bb4e400 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SchemeHeaderTransformation.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/protocol.proto + + +/** + * A message to control transformations to the :scheme header + */ +export interface SchemeHeaderTransformation { + /** + * Overwrite any Scheme header with the contents of this string. + */ + 'scheme_to_overwrite'?: (string); + 'transformation'?: "scheme_to_overwrite"; +} + +/** + * A message to control transformations to the :scheme header + */ +export interface SchemeHeaderTransformation__Output { + /** + * Overwrite any Scheme header with the contents of this string. + */ + 'scheme_to_overwrite'?: (string); + 'transformation': "scheme_to_overwrite"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts index e387adca2..3912fd1cf 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SelfConfigSource.ts @@ -5,7 +5,7 @@ import type { ApiVersion as _envoy_config_core_v3_ApiVersion } from '../../../.. /** * [#not-implemented-hide:] * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to + * set in :ref:`ConfigSource ` can be used to * specify that other data can be obtained from the same server. */ export interface SelfConfigSource { @@ -19,7 +19,7 @@ export interface SelfConfigSource { /** * [#not-implemented-hide:] * Self-referencing config source options. This is currently empty, but when - * set in :ref:`ConfigSource ` can be used to + * set in :ref:`ConfigSource ` can be used to * specify that other data can be obtained from the same server. */ export interface SelfConfigSource__Output { diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts index e3f342d16..3966dc04c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SocketAddress.ts @@ -18,19 +18,19 @@ export interface SocketAddress { * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: * It is possible to distinguish a Listener address via the prefix/suffix matching - * in :ref:`FilterChainMatch `.] When used - * within an upstream :ref:`BindConfig `, the address + * in :ref:`FilterChainMatch `.] When used + * within an upstream :ref:`BindConfig `, the address * controls the source address of outbound connections. For :ref:`clusters - * `, the cluster type determines whether the + * `, the cluster type determines whether the * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized - * via :ref:`resolver_name `. + * via :ref:`resolver_name `. */ 'address'?: (string); 'port_value'?: (number); /** * This is only valid if :ref:`resolver_name - * ` is specified below and the + * ` is specified below and the * named resolver is capable of named port resolution. */ 'named_port'?: (string); @@ -62,19 +62,19 @@ export interface SocketAddress__Output { * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: * It is possible to distinguish a Listener address via the prefix/suffix matching - * in :ref:`FilterChainMatch `.] When used - * within an upstream :ref:`BindConfig `, the address + * in :ref:`FilterChainMatch `.] When used + * within an upstream :ref:`BindConfig `, the address * controls the source address of outbound connections. For :ref:`clusters - * `, the cluster type determines whether the + * `, the cluster type determines whether the * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized - * via :ref:`resolver_name `. + * via :ref:`resolver_name `. */ 'address': (string); 'port_value'?: (number); /** * This is only valid if :ref:`resolver_name - * ` is specified below and the + * ` is specified below and the * named resolver is capable of named port resolution. */ 'named_port'?: (string); diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts index ae3003189..a935fc1ec 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/SubstitutionFormatString.ts @@ -95,6 +95,7 @@ export interface SubstitutionFormatString { /** * Specifies a collection of Formatter plugins that can be called from the access log configuration. * See the formatters extensions documentation for details. + * [#extension-category: envoy.formatter] */ 'formatters'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; 'format'?: "text_format"|"json_format"|"text_format_source"; @@ -191,6 +192,7 @@ export interface SubstitutionFormatString__Output { /** * Specifies a collection of Formatter plugins that can be called from the access log configuration. * See the formatters extensions documentation for details. + * [#extension-category: envoy.formatter] */ 'formatters': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; 'format': "text_format"|"json_format"|"text_format_source"; diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts index 0031ad52f..ff05991ad 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/TransportSocket.ts @@ -4,7 +4,7 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ /** * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is + * :ref:`clusters `. If the configuration is * empty, a default transport socket implementation and configuration will be * chosen based on the platform and existence of tls_context. */ @@ -24,7 +24,7 @@ export interface TransportSocket { /** * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is + * :ref:`clusters `. If the configuration is * empty, a default transport socket implementation and configuration will be * chosen based on the platform and existence of tls_context. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UdpSocketConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UdpSocketConfig.ts new file mode 100644 index 000000000..fe1b038db --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UdpSocketConfig.ts @@ -0,0 +1,45 @@ +// Original file: deps/envoy-api/envoy/config/core/v3/udp_socket_config.proto + +import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../../google/protobuf/UInt64Value'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { Long } from '@grpc/proto-loader'; + +/** + * Generic UDP socket configuration. + */ +export interface UdpSocketConfig { + /** + * The maximum size of received UDP datagrams. Using a larger size will cause Envoy to allocate + * more memory per socket. Received datagrams above this size will be dropped. If not set + * defaults to 1500 bytes. + */ + 'max_rx_datagram_size'?: (_google_protobuf_UInt64Value | null); + /** + * Configures whether Generic Receive Offload (GRO) + * _ is preferred when reading from the + * UDP socket. The default is context dependent and is documented where UdpSocketConfig is used. + * This option affects performance but not functionality. If GRO is not supported by the operating + * system, non-GRO receive will be used. + */ + 'prefer_gro'?: (_google_protobuf_BoolValue | null); +} + +/** + * Generic UDP socket configuration. + */ +export interface UdpSocketConfig__Output { + /** + * The maximum size of received UDP datagrams. Using a larger size will cause Envoy to allocate + * more memory per socket. Received datagrams above this size will be dropped. If not set + * defaults to 1500 bytes. + */ + 'max_rx_datagram_size': (_google_protobuf_UInt64Value__Output | null); + /** + * Configures whether Generic Receive Offload (GRO) + * _ is preferred when reading from the + * UDP socket. The default is context dependent and is documented where UdpSocketConfig is used. + * This option affects performance but not functionality. If GRO is not supported by the operating + * system, non-GRO receive will be used. + */ + 'prefer_gro': (_google_protobuf_BoolValue__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts index b765ec5a7..c0da4159f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/core/v3/UpstreamHttpProtocolOptions.ts @@ -4,31 +4,53 @@ export interface UpstreamHttpProtocolOptions { /** * Set transport socket `SNI `_ for new - * upstream connections based on the downstream HTTP host/authority header, as seen by the - * :ref:`router filter `. + * upstream connections based on the downstream HTTP host/authority header or any other arbitrary + * header when :ref:`override_auto_sni_header ` + * is set, as seen by the :ref:`router filter `. */ 'auto_sni'?: (boolean); /** * Automatic validate upstream presented certificate for new upstream connections based on the - * downstream HTTP host/authority header, as seen by the - * :ref:`router filter `. - * This field is intended to set with `auto_sni` field. + * downstream HTTP host/authority header or any other arbitrary header when :ref:`override_auto_sni_header ` + * is set, as seen by the :ref:`router filter `. + * This field is intended to be set with `auto_sni` field. */ 'auto_san_validation'?: (boolean); + /** + * An optional alternative to the host/authority header to be used for setting the SNI value. + * It should be a valid downstream HTTP header, as seen by the + * :ref:`router filter `. + * If unset, host/authority header will be used for populating the SNI. If the specified header + * is not found or the value is empty, host/authority header will be used instead. + * This field is intended to be set with `auto_sni` and/or `auto_san_validation` fields. + * If none of these fields are set then setting this would be a no-op. + */ + 'override_auto_sni_header'?: (string); } export interface UpstreamHttpProtocolOptions__Output { /** * Set transport socket `SNI `_ for new - * upstream connections based on the downstream HTTP host/authority header, as seen by the - * :ref:`router filter `. + * upstream connections based on the downstream HTTP host/authority header or any other arbitrary + * header when :ref:`override_auto_sni_header ` + * is set, as seen by the :ref:`router filter `. */ 'auto_sni': (boolean); /** * Automatic validate upstream presented certificate for new upstream connections based on the - * downstream HTTP host/authority header, as seen by the - * :ref:`router filter `. - * This field is intended to set with `auto_sni` field. + * downstream HTTP host/authority header or any other arbitrary header when :ref:`override_auto_sni_header ` + * is set, as seen by the :ref:`router filter `. + * This field is intended to be set with `auto_sni` field. */ 'auto_san_validation': (boolean); + /** + * An optional alternative to the host/authority header to be used for setting the SNI value. + * It should be a valid downstream HTTP header, as seen by the + * :ref:`router filter `. + * If unset, host/authority header will be used for populating the SNI. If the specified header + * is not found or the value is empty, host/authority header will be used instead. + * This field is intended to be set with `auto_sni` and/or `auto_san_validation` fields. + * If none of these fields are set then setting this would be a no-op. + */ + 'override_auto_sni_header': (string); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts index 03ceb570e..91ce2e0c8 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment.ts @@ -157,9 +157,9 @@ export interface _envoy_config_endpoint_v3_ClusterLoadAssignment_Policy__Output export interface ClusterLoadAssignment { /** * Name of the cluster. This will be the :ref:`service_name - * ` value if specified + * ` value if specified * in the cluster :ref:`EdsClusterConfig - * `. + * `. */ 'cluster_name'?: (string); /** @@ -192,9 +192,9 @@ export interface ClusterLoadAssignment { export interface ClusterLoadAssignment__Output { /** * Name of the cluster. This will be the :ref:`service_name - * ` value if specified + * ` value if specified * in the cluster :ref:`EdsClusterConfig - * `. + * `. */ 'cluster_name': (string); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts index db820b0b3..c160333b2 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/ClusterStats.ts @@ -28,7 +28,7 @@ export interface _envoy_config_endpoint_v3_ClusterStats_DroppedRequests__Output /** * Per cluster load stats. Envoy reports these stats a management server in a - * :ref:`LoadStatsRequest` + * :ref:`LoadStatsRequest` * Next ID: 7 * [#next-free-field: 7] */ @@ -72,7 +72,7 @@ export interface ClusterStats { /** * Per cluster load stats. Envoy reports these stats a management server in a - * :ref:`LoadStatsRequest` + * :ref:`LoadStatsRequest` * Next ID: 7 * [#next-free-field: 7] */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts index c01987cce..31eb09055 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/Endpoint.ts @@ -17,8 +17,8 @@ export interface _envoy_config_endpoint_v3_Endpoint_HealthCheckConfig { 'port_value'?: (number); /** * By default, the host header for L7 health checks is controlled by cluster level configuration - * (see: :ref:`host ` and - * :ref:`authority `). Setting this + * (see: :ref:`host ` and + * :ref:`authority `). Setting this * to a non-empty value allows overriding the cluster level configuration for a specific * endpoint. */ @@ -40,8 +40,8 @@ export interface _envoy_config_endpoint_v3_Endpoint_HealthCheckConfig__Output { 'port_value': (number); /** * By default, the host header for L7 health checks is controlled by cluster level configuration - * (see: :ref:`host ` and - * :ref:`authority `). Setting this + * (see: :ref:`host ` and + * :ref:`authority `). Setting this * to a non-empty value allows overriding the cluster level configuration for a specific * endpoint. */ @@ -59,7 +59,7 @@ export interface Endpoint { * * The form of host address depends on the given cluster type. For STATIC or EDS, * it is expected to be a direct IP address (or something resolvable by the - * specified :ref:`resolver ` + * specified :ref:`resolver ` * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ @@ -78,7 +78,7 @@ export interface Endpoint { * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features * that require a hostname, like - * :ref:`auto_host_rewrite `. + * :ref:`auto_host_rewrite `. */ 'hostname'?: (string); } @@ -94,7 +94,7 @@ export interface Endpoint__Output { * * The form of host address depends on the given cluster type. For STATIC or EDS, * it is expected to be a direct IP address (or something resolvable by the - * specified :ref:`resolver ` + * specified :ref:`resolver ` * in the Address). For LOGICAL or STRICT DNS, it is expected to be hostname, * and will be resolved via DNS. */ @@ -113,7 +113,7 @@ export interface Endpoint__Output { * The hostname associated with this endpoint. This hostname is not used for routing or address * resolution. If provided, it will be associated with the endpoint, and can be used for features * that require a hostname, like - * :ref:`auto_host_rewrite `. + * :ref:`auto_host_rewrite `. */ 'hostname': (string); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts index 3952a6928..6025ae3a7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LbEndpoint.ts @@ -21,7 +21,7 @@ export interface LbEndpoint { * name should be specified as *envoy.lb*. An example boolean key-value pair * is *canary*, providing the optional canary status of the upstream host. * This may be matched against in a route's - * :ref:`RouteAction ` metadata_match field + * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ 'metadata'?: (_envoy_config_core_v3_Metadata | null); @@ -63,7 +63,7 @@ export interface LbEndpoint__Output { * name should be specified as *envoy.lb*. An example boolean key-value pair * is *canary*, providing the optional canary status of the upstream host. * This may be matched against in a route's - * :ref:`RouteAction ` metadata_match field + * :ref:`RouteAction ` metadata_match field * to subset the endpoints considered in cluster load balancing. */ 'metadata': (_envoy_config_core_v3_Metadata__Output | null); diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LedsClusterLocalityConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LedsClusterLocalityConfig.ts new file mode 100644 index 000000000..1229d33a3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LedsClusterLocalityConfig.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/config/endpoint/v3/endpoint_components.proto + +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../envoy/config/core/v3/ConfigSource'; + +/** + * [#not-implemented-hide:] + * A configuration for a LEDS collection. + */ +export interface LedsClusterLocalityConfig { + /** + * Configuration for the source of LEDS updates for a Locality. + */ + 'leds_config'?: (_envoy_config_core_v3_ConfigSource | null); + /** + * The xDS transport protocol glob collection resource name. + * The service is only supported in delta xDS (incremental) mode. + */ + 'leds_collection_name'?: (string); +} + +/** + * [#not-implemented-hide:] + * A configuration for a LEDS collection. + */ +export interface LedsClusterLocalityConfig__Output { + /** + * Configuration for the source of LEDS updates for a Locality. + */ + 'leds_config': (_envoy_config_core_v3_ConfigSource__Output | null); + /** + * The xDS transport protocol glob collection resource name. + * The service is only supported in delta xDS (incremental) mode. + */ + 'leds_collection_name': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts index 22f053ed0..182e27c9c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints.ts @@ -3,13 +3,30 @@ import type { Locality as _envoy_config_core_v3_Locality, Locality__Output as _envoy_config_core_v3_Locality__Output } from '../../../../envoy/config/core/v3/Locality'; import type { LbEndpoint as _envoy_config_endpoint_v3_LbEndpoint, LbEndpoint__Output as _envoy_config_endpoint_v3_LbEndpoint__Output } from '../../../../envoy/config/endpoint/v3/LbEndpoint'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { LedsClusterLocalityConfig as _envoy_config_endpoint_v3_LedsClusterLocalityConfig, LedsClusterLocalityConfig__Output as _envoy_config_endpoint_v3_LedsClusterLocalityConfig__Output } from '../../../../envoy/config/endpoint/v3/LedsClusterLocalityConfig'; + +/** + * [#not-implemented-hide:] + * A list of endpoints of a specific locality. + */ +export interface _envoy_config_endpoint_v3_LocalityLbEndpoints_LbEndpointList { + 'lb_endpoints'?: (_envoy_config_endpoint_v3_LbEndpoint)[]; +} + +/** + * [#not-implemented-hide:] + * A list of endpoints of a specific locality. + */ +export interface _envoy_config_endpoint_v3_LocalityLbEndpoints_LbEndpointList__Output { + 'lb_endpoints': (_envoy_config_endpoint_v3_LbEndpoint__Output)[]; +} /** * A group of endpoints belonging to a Locality. * One can have multiple LocalityLbEndpoints for a locality, but this is * generally only done if the different groups need to have different load * balancing weights or different priorities. - * [#next-free-field: 7] + * [#next-free-field: 9] */ export interface LocalityLbEndpoints { /** @@ -18,6 +35,8 @@ export interface LocalityLbEndpoints { 'locality'?: (_envoy_config_core_v3_Locality | null); /** * The group of endpoints belonging to the locality specified. + * [#comment:TODO(adisuissa): Once LEDS is implemented this field needs to be + * deprecated and replaced by *load_balancer_endpoints*.] */ 'lb_endpoints'?: (_envoy_config_endpoint_v3_LbEndpoint)[]; /** @@ -55,6 +74,20 @@ export interface LocalityLbEndpoints { * [#not-implemented-hide:] */ 'proximity'?: (_google_protobuf_UInt32Value | null); + /** + * The group of endpoints belonging to the locality. + * [#comment:TODO(adisuissa): Once LEDS is implemented the *lb_endpoints* field + * needs to be deprecated.] + */ + 'load_balancer_endpoints'?: (_envoy_config_endpoint_v3_LocalityLbEndpoints_LbEndpointList | null); + /** + * LEDS Configuration for the current locality. + */ + 'leds_cluster_locality_config'?: (_envoy_config_endpoint_v3_LedsClusterLocalityConfig | null); + /** + * [#not-implemented-hide:] + */ + 'lb_config'?: "load_balancer_endpoints"|"leds_cluster_locality_config"; } /** @@ -62,7 +95,7 @@ export interface LocalityLbEndpoints { * One can have multiple LocalityLbEndpoints for a locality, but this is * generally only done if the different groups need to have different load * balancing weights or different priorities. - * [#next-free-field: 7] + * [#next-free-field: 9] */ export interface LocalityLbEndpoints__Output { /** @@ -71,6 +104,8 @@ export interface LocalityLbEndpoints__Output { 'locality': (_envoy_config_core_v3_Locality__Output | null); /** * The group of endpoints belonging to the locality specified. + * [#comment:TODO(adisuissa): Once LEDS is implemented this field needs to be + * deprecated and replaced by *load_balancer_endpoints*.] */ 'lb_endpoints': (_envoy_config_endpoint_v3_LbEndpoint__Output)[]; /** @@ -108,4 +143,18 @@ export interface LocalityLbEndpoints__Output { * [#not-implemented-hide:] */ 'proximity': (_google_protobuf_UInt32Value__Output | null); + /** + * The group of endpoints belonging to the locality. + * [#comment:TODO(adisuissa): Once LEDS is implemented the *lb_endpoints* field + * needs to be deprecated.] + */ + 'load_balancer_endpoints'?: (_envoy_config_endpoint_v3_LocalityLbEndpoints_LbEndpointList__Output | null); + /** + * LEDS Configuration for the current locality. + */ + 'leds_cluster_locality_config'?: (_envoy_config_endpoint_v3_LedsClusterLocalityConfig__Output | null); + /** + * [#not-implemented-hide:] + */ + 'lb_config': "load_balancer_endpoints"|"leds_cluster_locality_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts index f00607d00..fbfb05ed6 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/endpoint/v3/UpstreamLocalityStats.ts @@ -7,7 +7,7 @@ import type { Long } from '@grpc/proto-loader'; /** * These are stats Envoy reports to the management server at a frequency defined by - * :ref:`LoadStatsResponse.load_reporting_interval`. + * :ref:`LoadStatsResponse.load_reporting_interval`. * Stats per upstream region/zone and optionally per subzone. * [#next-free-field: 9] */ @@ -43,7 +43,7 @@ export interface UpstreamLocalityStats { /** * Endpoint granularity stats information for this locality. This information * is populated if the Server requests it by setting - * :ref:`LoadStatsResponse.report_endpoint_granularity`. + * :ref:`LoadStatsResponse.report_endpoint_granularity`. */ 'upstream_endpoint_stats'?: (_envoy_config_endpoint_v3_UpstreamEndpointStats)[]; /** @@ -56,7 +56,7 @@ export interface UpstreamLocalityStats { /** * These are stats Envoy reports to the management server at a frequency defined by - * :ref:`LoadStatsResponse.load_reporting_interval`. + * :ref:`LoadStatsResponse.load_reporting_interval`. * Stats per upstream region/zone and optionally per subzone. * [#next-free-field: 9] */ @@ -92,7 +92,7 @@ export interface UpstreamLocalityStats__Output { /** * Endpoint granularity stats information for this locality. This information * is populated if the Server requests it by setting - * :ref:`LoadStatsResponse.report_endpoint_granularity`. + * :ref:`LoadStatsResponse.report_endpoint_granularity`. */ 'upstream_endpoint_stats': (_envoy_config_endpoint_v3_UpstreamEndpointStats__Output)[]; /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts index 4977911fb..5a8e7f37f 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ApiListener.ts @@ -10,7 +10,8 @@ export interface ApiListener { /** * The type in this field determines the type of API listener. At present, the following * types are supported: - * envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager (HTTP) + * envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager (HTTP) + * envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager (HTTP) * [#next-major-version: In the v3 API, replace this Any field with a oneof containing the * specific config message for each type of API listener. We could not do this in v2 because * it would have caused circular dependencies for go protos: lds.proto depends on this file, @@ -28,7 +29,8 @@ export interface ApiListener__Output { /** * The type in this field determines the type of API listener. At present, the following * types are supported: - * envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager (HTTP) + * envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager (HTTP) + * envoy.extensions.filters.network.http_connection_manager.v3.EnvoyMobileHttpConnectionManager (HTTP) * [#next-major-version: In the v3 API, replace this Any field with a oneof containing the * specific config message for each type of API listener. We could not do this in v2 because * it would have caused circular dependencies for go protos: lds.proto depends on this file, diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts index 3e38fbc00..66e903b28 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Filter.ts @@ -15,6 +15,7 @@ export interface Filter { /** * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. + * [#extension-category: envoy.filters.network] */ 'typed_config'?: (_google_protobuf_Any | null); /** @@ -39,6 +40,7 @@ export interface Filter__Output { /** * Filter specific configuration which depends on the filter being * instantiated. See the supported filters for further documentation. + * [#extension-category: envoy.filters.network] */ 'typed_config'?: (_google_protobuf_Any__Output | null); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts index d72fa824c..e65f433c4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChain.ts @@ -81,10 +81,11 @@ export interface FilterChain { 'metadata'?: (_envoy_config_core_v3_Metadata | null); /** * Optional custom transport socket implementation to use for downstream connections. - * To setup TLS, set a transport socket with name `tls` and - * :ref:`DownstreamTlsContext ` in the `typed_config`. + * To setup TLS, set a transport socket with name `envoy.transport_sockets.tls` and + * :ref:`DownstreamTlsContext ` in the `typed_config`. * If no transport socket configuration is specified, new connections * will be set up with plaintext. + * [#extension-category: envoy.transport_sockets.downstream] */ 'transport_socket'?: (_envoy_config_core_v3_TransportSocket | null); /** @@ -143,10 +144,11 @@ export interface FilterChain__Output { 'metadata': (_envoy_config_core_v3_Metadata__Output | null); /** * Optional custom transport socket implementation to use for downstream connections. - * To setup TLS, set a transport socket with name `tls` and - * :ref:`DownstreamTlsContext ` in the `typed_config`. + * To setup TLS, set a transport socket with name `envoy.transport_sockets.tls` and + * :ref:`DownstreamTlsContext ` in the `typed_config`. * If no transport socket configuration is specified, new connections * will be set up with plaintext. + * [#extension-category: envoy.transport_sockets.downstream] */ 'transport_socket': (_envoy_config_core_v3_TransportSocket__Output | null); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts index 042df6dea..259888217 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/FilterChainMatch.ts @@ -35,9 +35,12 @@ export enum _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType { * 3. Server name (e.g. SNI for TLS protocol), * 4. Transport protocol. * 5. Application protocols (e.g. ALPN for TLS protocol). - * 6. Source type (e.g. any, local or external network). - * 7. Source IP address. - * 8. Source port. + * 6. Directly connected source IP address (this will only be different from the source IP address + * when using a listener filter that overrides the source address, such as the :ref:`Proxy Protocol + * listener filter `). + * 7. Source type (e.g. any, local or external network). + * 8. Source IP address. + * 9. Source port. * * For criteria that allow ranges or wildcards, the most specific value in any * of the configured filter chains that matches the incoming connection is going @@ -61,7 +64,7 @@ export enum _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType { * listed at the end, because that's how we want to list them in the docs. * * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] - * [#next-free-field: 13] + * [#next-free-field: 14] */ export interface FilterChainMatch { /** @@ -151,6 +154,12 @@ export interface FilterChainMatch { * Specifies the connection source IP match type. Can be any, local or external network. */ 'source_type'?: (_envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType | keyof typeof _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType); + /** + * The criteria is satisfied if the directly connected source IP address of the downstream + * connection is contained in at least one of the specified subnets. If the parameter is not + * specified or the list is empty, the directly connected source IP address is ignored. + */ + 'direct_source_prefix_ranges'?: (_envoy_config_core_v3_CidrRange)[]; } /** @@ -168,9 +177,12 @@ export interface FilterChainMatch { * 3. Server name (e.g. SNI for TLS protocol), * 4. Transport protocol. * 5. Application protocols (e.g. ALPN for TLS protocol). - * 6. Source type (e.g. any, local or external network). - * 7. Source IP address. - * 8. Source port. + * 6. Directly connected source IP address (this will only be different from the source IP address + * when using a listener filter that overrides the source address, such as the :ref:`Proxy Protocol + * listener filter `). + * 7. Source type (e.g. any, local or external network). + * 8. Source IP address. + * 9. Source port. * * For criteria that allow ranges or wildcards, the most specific value in any * of the configured filter chains that matches the incoming connection is going @@ -194,7 +206,7 @@ export interface FilterChainMatch { * listed at the end, because that's how we want to list them in the docs. * * [#comment:TODO(PiotrSikora): Add support for configurable precedence of the rules] - * [#next-free-field: 13] + * [#next-free-field: 14] */ export interface FilterChainMatch__Output { /** @@ -284,4 +296,10 @@ export interface FilterChainMatch__Output { * Specifies the connection source IP match type. Can be any, local or external network. */ 'source_type': (keyof typeof _envoy_config_listener_v3_FilterChainMatch_ConnectionSourceType); + /** + * The criteria is satisfied if the directly connected source IP address of the downstream + * connection is contained in at least one of the specified subnets. If the parameter is not + * specified or the list is empty, the directly connected source IP address is ignored. + */ + 'direct_source_prefix_ranges': (_envoy_config_core_v3_CidrRange__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts index 8e0fc55f6..3df1006b7 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/Listener.ts @@ -12,7 +12,6 @@ import type { TrafficDirection as _envoy_config_core_v3_TrafficDirection } from import type { UdpListenerConfig as _envoy_config_listener_v3_UdpListenerConfig, UdpListenerConfig__Output as _envoy_config_listener_v3_UdpListenerConfig__Output } from '../../../../envoy/config/listener/v3/UdpListenerConfig'; import type { ApiListener as _envoy_config_listener_v3_ApiListener, ApiListener__Output as _envoy_config_listener_v3_ApiListener__Output } from '../../../../envoy/config/listener/v3/ApiListener'; import type { AccessLog as _envoy_config_accesslog_v3_AccessLog, AccessLog__Output as _envoy_config_accesslog_v3_AccessLog__Output } from '../../../../envoy/config/accesslog/v3/AccessLog'; -import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; /** * Configuration for listener connection balancing. @@ -46,7 +45,7 @@ export interface _envoy_config_listener_v3_Listener_DeprecatedV1 { * set use_original_dst parameter to true. Default is true. * * This is deprecated. Use :ref:`Listener.bind_to_port - * ` + * ` */ 'bind_to_port'?: (_google_protobuf_BoolValue | null); } @@ -61,7 +60,7 @@ export interface _envoy_config_listener_v3_Listener_DeprecatedV1__Output { * set use_original_dst parameter to true. Default is true. * * This is deprecated. Use :ref:`Listener.bind_to_port - * ` + * ` */ 'bind_to_port': (_google_protobuf_BoolValue__Output | null); } @@ -105,7 +104,21 @@ export interface _envoy_config_listener_v3_Listener_ConnectionBalanceConfig_Exac } /** - * [#next-free-field: 27] + * Configuration for envoy internal listener. All the future internal listener features should be added here. + * [#not-implemented-hide:] + */ +export interface _envoy_config_listener_v3_Listener_InternalListenerConfig { +} + +/** + * Configuration for envoy internal listener. All the future internal listener features should be added here. + * [#not-implemented-hide:] + */ +export interface _envoy_config_listener_v3_Listener_InternalListenerConfig__Output { +} + +/** + * [#next-free-field: 30] */ export interface Listener { /** @@ -122,8 +135,8 @@ export interface Listener { 'address'?: (_envoy_config_core_v3_Address | null); /** * A list of filter chains to consider for this listener. The - * :ref:`FilterChain ` with the most specific - * :ref:`FilterChainMatch ` criteria is used on a + * :ref:`FilterChain ` with the most specific + * :ref:`FilterChainMatch ` criteria is used on a * connection. * * Example using SNI for filter chain selection can be found in the @@ -158,12 +171,12 @@ export interface Listener { /** * Listener filters have the opportunity to manipulate and augment the connection metadata that * is used in connection filter chain matching, for example. These filters are run before any in - * :ref:`filter_chains `. Order matters as the + * :ref:`filter_chains `. Order matters as the * filters are processed sequentially right after a socket has been accepted by the listener, and * before a connection is created. * UDP Listener filters can be specified when the protocol in the listener socket address in - * :ref:`protocol ` is :ref:`UDP - * `. + * :ref:`protocol ` is :ref:`UDP + * `. * UDP listeners currently support a single filter. */ 'listener_filters'?: (_envoy_config_listener_v3_ListenerFilter)[]; @@ -173,7 +186,7 @@ export interface Listener { * *iptables* *TPROXY* target, in which case the original source and destination addresses and * ports are preserved on accepted connections. This flag should be used in combination with * :ref:`an original_dst ` :ref:`listener filter - * ` to mark the connections' local addresses as + * ` to mark the connections' local addresses as * "restored." This can be used to hand off each redirected connection to another listener * associated with the connection's destination address. Direct connections to the socket without * using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are @@ -224,6 +237,8 @@ export interface Listener { 'listener_filters_timeout'?: (_google_protobuf_Duration | null); /** * Specifies the intended direction of the traffic relative to the local Envoy. + * This property is required on Windows for listeners using the original destination filter, + * see :ref:`Original Destination `. */ 'traffic_direction'?: (_envoy_config_core_v3_TrafficDirection | keyof typeof _envoy_config_core_v3_TrafficDirection); /** @@ -238,17 +253,15 @@ export interface Listener { 'continue_on_listener_filters_timeout'?: (boolean); /** * If the protocol in the listener socket address in :ref:`protocol - * ` is :ref:`UDP - * `, this field specifies the actual udp - * listener to create, i.e. :ref:`udp_listener_name - * ` = "raw_udp_listener" for - * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". + * ` is :ref:`UDP + * `, this field specifies UDP + * listener specific configuration. */ 'udp_listener_config'?: (_envoy_config_listener_v3_UdpListenerConfig | null); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. - * When this field is set, no other field except for :ref:`name` + * When this field is set, no other field except for :ref:`name` * should be set. * * .. note:: @@ -268,19 +281,16 @@ export interface Listener { * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. + * + * In the scenario that the listener X redirects all the connections to the listeners Y1 and Y2 + * by setting :ref:`use_original_dst ` in X + * and :ref:`bind_to_port ` to false in Y1 and Y2, + * it is recommended to disable the balance config in listener X to avoid the cost of balancing, and + * enable the balance config in Y1 and Y2 to balance the connections among the workers. */ 'connection_balance_config'?: (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig | null); /** - * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and - * create one socket for each worker thread. This makes inbound connections - * distribute among worker threads roughly evenly in cases where there are a high number - * of connections. When this flag is set to false, all worker threads share one socket. - * - * Before Linux v4.19-rc1, new TCP connections may be rejected during hot restart - * (see `3rd paragraph in 'soreuseport' commit message - * `_). - * This issue was fixed by `tcp: Avoid TCP syncookie rejected by SO_REUSEPORT socket - * `_. + * Deprecated. Use `enable_reuse_port` instead. */ 'reuse_port'?: (boolean); /** @@ -288,17 +298,6 @@ export interface Listener { * emitted by this listener. */ 'access_log'?: (_envoy_config_accesslog_v3_AccessLog)[]; - /** - * If the protocol in the listener socket address in :ref:`protocol - * ` is :ref:`UDP - * `, this field specifies the actual udp - * writer to create, i.e. :ref:`name ` - * = "udp_default_writer" for creating a udp writer with writing in passthrough mode, - * = "udp_gso_batch_writer" for creating a udp writer with writing in batch mode. - * If not present, treat it as "udp_default_writer". - * [#not-implemented-hide:] - */ - 'udp_writer_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); /** * The maximum length a tcp listener's pending connections queue can grow to. If no value is * provided net.core.somaxconn will be used on Linux and 128 otherwise. @@ -312,14 +311,67 @@ export interface Listener { /** * Whether the listener should bind to the port. A listener that doesn't * bind can only receive connections redirected from other listeners that set - * :ref:`use_original_dst ` + * :ref:`use_original_dst ` * to true. Default is true. */ 'bind_to_port'?: (_google_protobuf_BoolValue | null); + /** + * Used to represent an internal listener which does not listen on OSI L4 address but can be used by the + * :ref:`envoy cluster ` to create a user space connection to. + * The internal listener acts as a tcp listener. It supports listener filters and network filter chains. + * The internal listener require :ref:`address ` has + * field `envoy_internal_address`. + * + * There are some limitations are derived from the implementation. The known limitations include + * + * * :ref:`ConnectionBalanceConfig ` is not + * allowed because both cluster connection and listener connection must be owned by the same dispatcher. + * * :ref:`tcp_backlog_size ` + * * :ref:`freebind ` + * * :ref:`transparent ` + * [#not-implemented-hide:] + */ + 'internal_listener'?: (_envoy_config_listener_v3_Listener_InternalListenerConfig | null); + /** + * Optional prefix to use on listener stats. If empty, the stats will be rooted at + * `listener.
.`. If non-empty, stats will be rooted at + * `listener..`. + */ + 'stat_prefix'?: (string); + /** + * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and + * create one socket for each worker thread. This makes inbound connections + * distribute among worker threads roughly evenly in cases where there are a high number + * of connections. When this flag is set to false, all worker threads share one socket. This field + * defaults to true. + * + * .. attention:: + * + * Although this field defaults to true, it has different behavior on different platforms. See + * the following text for more information. + * + * * On Linux, reuse_port is respected for both TCP and UDP listeners. It also works correctly + * with hot restart. + * * On macOS, reuse_port for TCP does not do what it does on Linux. Instead of load balancing, + * the last socket wins and receives all connections/packets. For TCP, reuse_port is force + * disabled and the user is warned. For UDP, it is enabled, but only one worker will receive + * packets. For QUIC/H3, SW routing will send packets to other workers. For "raw" UDP, only + * a single worker will currently receive packets. + * * On Windows, reuse_port for TCP has undefined behavior. It is force disabled and the user + * is warned similar to macOS. It is left enabled for UDP with undefined behavior currently. + */ + 'enable_reuse_port'?: (_google_protobuf_BoolValue | null); + /** + * The exclusive listener type and the corresponding config. + * TODO(lambdai): https://github.com/envoyproxy/envoy/issues/15372 + * Will create and add TcpListenerConfig. Will add UdpListenerConfig and ApiListener. + * [#not-implemented-hide:] + */ + 'listener_specifier'?: "internal_listener"; } /** - * [#next-free-field: 27] + * [#next-free-field: 30] */ export interface Listener__Output { /** @@ -336,8 +388,8 @@ export interface Listener__Output { 'address': (_envoy_config_core_v3_Address__Output | null); /** * A list of filter chains to consider for this listener. The - * :ref:`FilterChain ` with the most specific - * :ref:`FilterChainMatch ` criteria is used on a + * :ref:`FilterChain ` with the most specific + * :ref:`FilterChainMatch ` criteria is used on a * connection. * * Example using SNI for filter chain selection can be found in the @@ -372,12 +424,12 @@ export interface Listener__Output { /** * Listener filters have the opportunity to manipulate and augment the connection metadata that * is used in connection filter chain matching, for example. These filters are run before any in - * :ref:`filter_chains `. Order matters as the + * :ref:`filter_chains `. Order matters as the * filters are processed sequentially right after a socket has been accepted by the listener, and * before a connection is created. * UDP Listener filters can be specified when the protocol in the listener socket address in - * :ref:`protocol ` is :ref:`UDP - * `. + * :ref:`protocol ` is :ref:`UDP + * `. * UDP listeners currently support a single filter. */ 'listener_filters': (_envoy_config_listener_v3_ListenerFilter__Output)[]; @@ -387,7 +439,7 @@ export interface Listener__Output { * *iptables* *TPROXY* target, in which case the original source and destination addresses and * ports are preserved on accepted connections. This flag should be used in combination with * :ref:`an original_dst ` :ref:`listener filter - * ` to mark the connections' local addresses as + * ` to mark the connections' local addresses as * "restored." This can be used to hand off each redirected connection to another listener * associated with the connection's destination address. Direct connections to the socket without * using *TPROXY* cannot be distinguished from connections redirected using *TPROXY* and are @@ -438,6 +490,8 @@ export interface Listener__Output { 'listener_filters_timeout': (_google_protobuf_Duration__Output | null); /** * Specifies the intended direction of the traffic relative to the local Envoy. + * This property is required on Windows for listeners using the original destination filter, + * see :ref:`Original Destination `. */ 'traffic_direction': (keyof typeof _envoy_config_core_v3_TrafficDirection); /** @@ -452,17 +506,15 @@ export interface Listener__Output { 'continue_on_listener_filters_timeout': (boolean); /** * If the protocol in the listener socket address in :ref:`protocol - * ` is :ref:`UDP - * `, this field specifies the actual udp - * listener to create, i.e. :ref:`udp_listener_name - * ` = "raw_udp_listener" for - * creating a packet-oriented UDP listener. If not present, treat it as "raw_udp_listener". + * ` is :ref:`UDP + * `, this field specifies UDP + * listener specific configuration. */ 'udp_listener_config': (_envoy_config_listener_v3_UdpListenerConfig__Output | null); /** * Used to represent an API listener, which is used in non-proxy clients. The type of API * exposed to the non-proxy application depends on the type of API listener. - * When this field is set, no other field except for :ref:`name` + * When this field is set, no other field except for :ref:`name` * should be set. * * .. note:: @@ -482,19 +534,16 @@ export interface Listener__Output { * The listener's connection balancer configuration, currently only applicable to TCP listeners. * If no configuration is specified, Envoy will not attempt to balance active connections between * worker threads. + * + * In the scenario that the listener X redirects all the connections to the listeners Y1 and Y2 + * by setting :ref:`use_original_dst ` in X + * and :ref:`bind_to_port ` to false in Y1 and Y2, + * it is recommended to disable the balance config in listener X to avoid the cost of balancing, and + * enable the balance config in Y1 and Y2 to balance the connections among the workers. */ 'connection_balance_config': (_envoy_config_listener_v3_Listener_ConnectionBalanceConfig__Output | null); /** - * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and - * create one socket for each worker thread. This makes inbound connections - * distribute among worker threads roughly evenly in cases where there are a high number - * of connections. When this flag is set to false, all worker threads share one socket. - * - * Before Linux v4.19-rc1, new TCP connections may be rejected during hot restart - * (see `3rd paragraph in 'soreuseport' commit message - * `_). - * This issue was fixed by `tcp: Avoid TCP syncookie rejected by SO_REUSEPORT socket - * `_. + * Deprecated. Use `enable_reuse_port` instead. */ 'reuse_port': (boolean); /** @@ -502,17 +551,6 @@ export interface Listener__Output { * emitted by this listener. */ 'access_log': (_envoy_config_accesslog_v3_AccessLog__Output)[]; - /** - * If the protocol in the listener socket address in :ref:`protocol - * ` is :ref:`UDP - * `, this field specifies the actual udp - * writer to create, i.e. :ref:`name ` - * = "udp_default_writer" for creating a udp writer with writing in passthrough mode, - * = "udp_gso_batch_writer" for creating a udp writer with writing in batch mode. - * If not present, treat it as "udp_default_writer". - * [#not-implemented-hide:] - */ - 'udp_writer_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); /** * The maximum length a tcp listener's pending connections queue can grow to. If no value is * provided net.core.somaxconn will be used on Linux and 128 otherwise. @@ -526,8 +564,61 @@ export interface Listener__Output { /** * Whether the listener should bind to the port. A listener that doesn't * bind can only receive connections redirected from other listeners that set - * :ref:`use_original_dst ` + * :ref:`use_original_dst ` * to true. Default is true. */ 'bind_to_port': (_google_protobuf_BoolValue__Output | null); + /** + * Used to represent an internal listener which does not listen on OSI L4 address but can be used by the + * :ref:`envoy cluster ` to create a user space connection to. + * The internal listener acts as a tcp listener. It supports listener filters and network filter chains. + * The internal listener require :ref:`address ` has + * field `envoy_internal_address`. + * + * There are some limitations are derived from the implementation. The known limitations include + * + * * :ref:`ConnectionBalanceConfig ` is not + * allowed because both cluster connection and listener connection must be owned by the same dispatcher. + * * :ref:`tcp_backlog_size ` + * * :ref:`freebind ` + * * :ref:`transparent ` + * [#not-implemented-hide:] + */ + 'internal_listener'?: (_envoy_config_listener_v3_Listener_InternalListenerConfig__Output | null); + /** + * Optional prefix to use on listener stats. If empty, the stats will be rooted at + * `listener.
.`. If non-empty, stats will be rooted at + * `listener..`. + */ + 'stat_prefix': (string); + /** + * When this flag is set to true, listeners set the *SO_REUSEPORT* socket option and + * create one socket for each worker thread. This makes inbound connections + * distribute among worker threads roughly evenly in cases where there are a high number + * of connections. When this flag is set to false, all worker threads share one socket. This field + * defaults to true. + * + * .. attention:: + * + * Although this field defaults to true, it has different behavior on different platforms. See + * the following text for more information. + * + * * On Linux, reuse_port is respected for both TCP and UDP listeners. It also works correctly + * with hot restart. + * * On macOS, reuse_port for TCP does not do what it does on Linux. Instead of load balancing, + * the last socket wins and receives all connections/packets. For TCP, reuse_port is force + * disabled and the user is warned. For UDP, it is enabled, but only one worker will receive + * packets. For QUIC/H3, SW routing will send packets to other workers. For "raw" UDP, only + * a single worker will currently receive packets. + * * On Windows, reuse_port for TCP has undefined behavior. It is force disabled and the user + * is warned similar to macOS. It is left enabled for UDP with undefined behavior currently. + */ + 'enable_reuse_port': (_google_protobuf_BoolValue__Output | null); + /** + * The exclusive listener type and the corresponding config. + * TODO(lambdai): https://github.com/envoyproxy/envoy/issues/15372 + * Will create and add TcpListenerConfig. Will add UdpListenerConfig and ApiListener. + * [#not-implemented-hide:] + */ + 'listener_specifier': "internal_listener"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts index beba60dce..be7242849 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilter.ts @@ -9,17 +9,18 @@ export interface ListenerFilter { * :ref:`supported filter `. */ 'name'?: (string); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + * [#extension-category: envoy.filters.listener,envoy.filters.udp_listener] + */ 'typed_config'?: (_google_protobuf_Any | null); /** * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. - * See :ref:`ListenerFilterChainMatchPredicate ` + * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ 'filter_disabled'?: (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate | null); - /** - * Filter specific configuration which depends on the filter being instantiated. - * See the supported filters for further documentation. - */ 'config_type'?: "typed_config"; } @@ -29,16 +30,17 @@ export interface ListenerFilter__Output { * :ref:`supported filter `. */ 'name': (string); + /** + * Filter specific configuration which depends on the filter being + * instantiated. See the supported filters for further documentation. + * [#extension-category: envoy.filters.listener,envoy.filters.udp_listener] + */ 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Optional match predicate used to disable the filter. The filter is enabled when this field is empty. - * See :ref:`ListenerFilterChainMatchPredicate ` + * See :ref:`ListenerFilterChainMatchPredicate ` * for further examples. */ 'filter_disabled': (_envoy_config_listener_v3_ListenerFilterChainMatchPredicate__Output | null); - /** - * Filter specific configuration which depends on the filter being instantiated. - * See the supported filters for further documentation. - */ 'config_type': "typed_config"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts index 34f937fa1..bb743a29d 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/ListenerFilterChainMatchPredicate.ts @@ -45,7 +45,7 @@ export interface _envoy_config_listener_v3_ListenerFilterChainMatchPredicate_Mat * rules: * - destination_port_range: * start: 3306 - * end: 3306 + * end: 3307 * - destination_port_range: * start: 15000 * end: 15001 @@ -101,7 +101,7 @@ export interface ListenerFilterChainMatchPredicate { * rules: * - destination_port_range: * start: 3306 - * end: 3306 + * end: 3307 * - destination_port_range: * start: 15000 * end: 15001 diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/QuicProtocolOptions.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/QuicProtocolOptions.ts new file mode 100644 index 000000000..5e01a772f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/QuicProtocolOptions.ts @@ -0,0 +1,97 @@ +// Original file: deps/envoy-api/envoy/config/listener/v3/quic_config.proto + +import type { QuicProtocolOptions as _envoy_config_core_v3_QuicProtocolOptions, QuicProtocolOptions__Output as _envoy_config_core_v3_QuicProtocolOptions__Output } from '../../../../envoy/config/core/v3/QuicProtocolOptions'; +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { RuntimeFeatureFlag as _envoy_config_core_v3_RuntimeFeatureFlag, RuntimeFeatureFlag__Output as _envoy_config_core_v3_RuntimeFeatureFlag__Output } from '../../../../envoy/config/core/v3/RuntimeFeatureFlag'; +import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * Configuration specific to the UDP QUIC listener. + * [#next-free-field: 8] + */ +export interface QuicProtocolOptions { + 'quic_protocol_options'?: (_envoy_config_core_v3_QuicProtocolOptions | null); + /** + * Maximum number of milliseconds that connection will be alive when there is + * no network activity. 300000ms if not specified. + */ + 'idle_timeout'?: (_google_protobuf_Duration | null); + /** + * Connection timeout in milliseconds before the crypto handshake is finished. + * 20000ms if not specified. + */ + 'crypto_handshake_timeout'?: (_google_protobuf_Duration | null); + /** + * Runtime flag that controls whether the listener is enabled or not. If not specified, defaults + * to enabled. + */ + 'enabled'?: (_envoy_config_core_v3_RuntimeFeatureFlag | null); + /** + * A multiplier to number of connections which is used to determine how many packets to read per + * event loop. A reasonable number should allow the listener to process enough payload but not + * starve TCP and other UDP sockets and also prevent long event loop duration. + * The default value is 32. This means if there are N QUIC connections, the total number of + * packets to read in each read event will be 32 * N. + * The actual number of packets to read in total by the UDP listener is also + * bound by 6000, regardless of this field or how many connections there are. + */ + 'packets_to_read_to_connection_count_ratio'?: (_google_protobuf_UInt32Value | null); + /** + * Configure which implementation of `quic::QuicCryptoClientStreamBase` to be used for this listener. + * If not specified the :ref:`QUICHE default one configured by ` will be used. + * [#extension-category: envoy.quic.server.crypto_stream] + */ + 'crypto_stream_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + /** + * Configure which implementation of `quic::ProofSource` to be used for this listener. + * If not specified the :ref:`default one configured by ` will be used. + * [#extension-category: envoy.quic.proof_source] + */ + 'proof_source_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); +} + +/** + * Configuration specific to the UDP QUIC listener. + * [#next-free-field: 8] + */ +export interface QuicProtocolOptions__Output { + 'quic_protocol_options': (_envoy_config_core_v3_QuicProtocolOptions__Output | null); + /** + * Maximum number of milliseconds that connection will be alive when there is + * no network activity. 300000ms if not specified. + */ + 'idle_timeout': (_google_protobuf_Duration__Output | null); + /** + * Connection timeout in milliseconds before the crypto handshake is finished. + * 20000ms if not specified. + */ + 'crypto_handshake_timeout': (_google_protobuf_Duration__Output | null); + /** + * Runtime flag that controls whether the listener is enabled or not. If not specified, defaults + * to enabled. + */ + 'enabled': (_envoy_config_core_v3_RuntimeFeatureFlag__Output | null); + /** + * A multiplier to number of connections which is used to determine how many packets to read per + * event loop. A reasonable number should allow the listener to process enough payload but not + * starve TCP and other UDP sockets and also prevent long event loop duration. + * The default value is 32. This means if there are N QUIC connections, the total number of + * packets to read in each read event will be 32 * N. + * The actual number of packets to read in total by the UDP listener is also + * bound by 6000, regardless of this field or how many connections there are. + */ + 'packets_to_read_to_connection_count_ratio': (_google_protobuf_UInt32Value__Output | null); + /** + * Configure which implementation of `quic::QuicCryptoClientStreamBase` to be used for this listener. + * If not specified the :ref:`QUICHE default one configured by ` will be used. + * [#extension-category: envoy.quic.server.crypto_stream] + */ + 'crypto_stream_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + /** + * Configure which implementation of `quic::ProofSource` to be used for this listener. + * If not specified the :ref:`default one configured by ` will be used. + * [#extension-category: envoy.quic.proof_source] + */ + 'proof_source_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts index 2ac4463fb..f4c220e20 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/listener/v3/UdpListenerConfig.ts @@ -1,33 +1,48 @@ // Original file: deps/envoy-api/envoy/config/listener/v3/udp_listener_config.proto -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { UdpSocketConfig as _envoy_config_core_v3_UdpSocketConfig, UdpSocketConfig__Output as _envoy_config_core_v3_UdpSocketConfig__Output } from '../../../../envoy/config/core/v3/UdpSocketConfig'; +import type { QuicProtocolOptions as _envoy_config_listener_v3_QuicProtocolOptions, QuicProtocolOptions__Output as _envoy_config_listener_v3_QuicProtocolOptions__Output } from '../../../../envoy/config/listener/v3/QuicProtocolOptions'; +/** + * [#next-free-field: 8] + */ export interface UdpListenerConfig { /** - * Used to look up UDP listener factory, matches "raw_udp_listener" or - * "quic_listener" to create a specific udp listener. - * If not specified, treat as "raw_udp_listener". + * UDP socket configuration for the listener. The default for + * :ref:`prefer_gro ` is false for + * listener sockets. If receiving a large amount of datagrams from a small number of sources, it + * may be worthwhile to enable this option after performance testing. */ - 'udp_listener_name'?: (string); - 'typed_config'?: (_google_protobuf_Any | null); + 'downstream_socket_config'?: (_envoy_config_core_v3_UdpSocketConfig | null); /** - * Used to create a specific listener factory. To some factory, e.g. - * "raw_udp_listener", config is not needed. + * Configuration for QUIC protocol. If empty, QUIC will not be enabled on this listener. Set + * to the default object to enable QUIC without modifying any additional options. + * + * .. warning:: + * QUIC support is currently alpha and should be used with caution. Please + * see :ref:`here ` for details. */ - 'config_type'?: "typed_config"; + 'quic_options'?: (_envoy_config_listener_v3_QuicProtocolOptions | null); } +/** + * [#next-free-field: 8] + */ export interface UdpListenerConfig__Output { /** - * Used to look up UDP listener factory, matches "raw_udp_listener" or - * "quic_listener" to create a specific udp listener. - * If not specified, treat as "raw_udp_listener". + * UDP socket configuration for the listener. The default for + * :ref:`prefer_gro ` is false for + * listener sockets. If receiving a large amount of datagrams from a small number of sources, it + * may be worthwhile to enable this option after performance testing. */ - 'udp_listener_name': (string); - 'typed_config'?: (_google_protobuf_Any__Output | null); + 'downstream_socket_config': (_envoy_config_core_v3_UdpSocketConfig__Output | null); /** - * Used to create a specific listener factory. To some factory, e.g. - * "raw_udp_listener", config is not needed. + * Configuration for QUIC protocol. If empty, QUIC will not be enabled on this listener. Set + * to the default object to enable QUIC without modifying any additional options. + * + * .. warning:: + * QUIC support is currently alpha and should be used with caution. Please + * see :ref:`here ` for details. */ - 'config_type': "typed_config"; + 'quic_options': (_envoy_config_listener_v3_QuicProtocolOptions__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/DogStatsdSink.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/DogStatsdSink.ts new file mode 100644 index 000000000..4cf705f10 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/DogStatsdSink.ts @@ -0,0 +1,65 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; +import type { UInt64Value as _google_protobuf_UInt64Value, UInt64Value__Output as _google_protobuf_UInt64Value__Output } from '../../../../google/protobuf/UInt64Value'; +import type { Long } from '@grpc/proto-loader'; + +/** + * Stats configuration proto schema for built-in *envoy.stat_sinks.dog_statsd* sink. + * The sink emits stats with `DogStatsD `_ + * compatible tags. Tags are configurable via :ref:`StatsConfig + * `. + * [#extension: envoy.stat_sinks.dog_statsd] + */ +export interface DogStatsdSink { + /** + * The UDP address of a running DogStatsD compliant listener. If specified, + * statistics will be flushed to this address. + */ + 'address'?: (_envoy_config_core_v3_Address | null); + /** + * Optional custom metric name prefix. See :ref:`StatsdSink's prefix field + * ` for more details. + */ + 'prefix'?: (string); + /** + * Optional max datagram size to use when sending UDP messages. By default Envoy + * will emit one metric per datagram. By specifying a max-size larger than a single + * metric, Envoy will emit multiple, new-line separated metrics. The max datagram + * size should not exceed your network's MTU. + * + * Note that this value may not be respected if smaller than a single metric. + */ + 'max_bytes_per_datagram'?: (_google_protobuf_UInt64Value | null); + 'dog_statsd_specifier'?: "address"; +} + +/** + * Stats configuration proto schema for built-in *envoy.stat_sinks.dog_statsd* sink. + * The sink emits stats with `DogStatsD `_ + * compatible tags. Tags are configurable via :ref:`StatsConfig + * `. + * [#extension: envoy.stat_sinks.dog_statsd] + */ +export interface DogStatsdSink__Output { + /** + * The UDP address of a running DogStatsD compliant listener. If specified, + * statistics will be flushed to this address. + */ + 'address'?: (_envoy_config_core_v3_Address__Output | null); + /** + * Optional custom metric name prefix. See :ref:`StatsdSink's prefix field + * ` for more details. + */ + 'prefix': (string); + /** + * Optional max datagram size to use when sending UDP messages. By default Envoy + * will emit one metric per datagram. By specifying a max-size larger than a single + * metric, Envoy will emit multiple, new-line separated metrics. The max datagram + * size should not exceed your network's MTU. + * + * Note that this value may not be respected if smaller than a single metric. + */ + 'max_bytes_per_datagram': (_google_protobuf_UInt64Value__Output | null); + 'dog_statsd_specifier': "address"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HistogramBucketSettings.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HistogramBucketSettings.ts new file mode 100644 index 000000000..036958a49 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HistogramBucketSettings.ts @@ -0,0 +1,35 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; + +/** + * Specifies a matcher for stats and the buckets that matching stats should use. + */ +export interface HistogramBucketSettings { + /** + * The stats that this rule applies to. The match is applied to the original stat name + * before tag-extraction, for example `cluster.exampleclustername.upstream_cx_length_ms`. + */ + 'match'?: (_envoy_type_matcher_v3_StringMatcher | null); + /** + * Each value is the upper bound of a bucket. Each bucket must be greater than 0 and unique. + * The order of the buckets does not matter. + */ + 'buckets'?: (number | string)[]; +} + +/** + * Specifies a matcher for stats and the buckets that matching stats should use. + */ +export interface HistogramBucketSettings__Output { + /** + * The stats that this rule applies to. The match is applied to the original stat name + * before tag-extraction, for example `cluster.exampleclustername.upstream_cx_length_ms`. + */ + 'match': (_envoy_type_matcher_v3_StringMatcher__Output | null); + /** + * Each value is the upper bound of a bucket. Each bucket must be greater than 0 and unique. + * The order of the buckets does not matter. + */ + 'buckets': (number)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HystrixSink.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HystrixSink.ts new file mode 100644 index 000000000..b8fb2ed8e --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/HystrixSink.ts @@ -0,0 +1,61 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { Long } from '@grpc/proto-loader'; + +/** + * Stats configuration proto schema for built-in *envoy.stat_sinks.hystrix* sink. + * The sink emits stats in `text/event-stream + * `_ + * formatted stream for use by `Hystrix dashboard + * `_. + * + * Note that only a single HystrixSink should be configured. + * + * Streaming is started through an admin endpoint :http:get:`/hystrix_event_stream`. + * [#extension: envoy.stat_sinks.hystrix] + */ +export interface HystrixSink { + /** + * The number of buckets the rolling statistical window is divided into. + * + * Each time the sink is flushed, all relevant Envoy statistics are sampled and + * added to the rolling window (removing the oldest samples in the window + * in the process). The sink then outputs the aggregate statistics across the + * current rolling window to the event stream(s). + * + * rolling_window(ms) = stats_flush_interval(ms) * num_of_buckets + * + * More detailed explanation can be found in `Hystrix wiki + * `_. + */ + 'num_buckets'?: (number | string | Long); +} + +/** + * Stats configuration proto schema for built-in *envoy.stat_sinks.hystrix* sink. + * The sink emits stats in `text/event-stream + * `_ + * formatted stream for use by `Hystrix dashboard + * `_. + * + * Note that only a single HystrixSink should be configured. + * + * Streaming is started through an admin endpoint :http:get:`/hystrix_event_stream`. + * [#extension: envoy.stat_sinks.hystrix] + */ +export interface HystrixSink__Output { + /** + * The number of buckets the rolling statistical window is divided into. + * + * Each time the sink is flushed, all relevant Envoy statistics are sampled and + * added to the rolling window (removing the oldest samples in the window + * in the process). The sink then outputs the aggregate statistics across the + * current rolling window to the event stream(s). + * + * rolling_window(ms) = stats_flush_interval(ms) * num_of_buckets + * + * More detailed explanation can be found in `Hystrix wiki + * `_. + */ + 'num_buckets': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsConfig.ts new file mode 100644 index 000000000..df5d7c7e4 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsConfig.ts @@ -0,0 +1,148 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { TagSpecifier as _envoy_config_metrics_v3_TagSpecifier, TagSpecifier__Output as _envoy_config_metrics_v3_TagSpecifier__Output } from '../../../../envoy/config/metrics/v3/TagSpecifier'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; +import type { StatsMatcher as _envoy_config_metrics_v3_StatsMatcher, StatsMatcher__Output as _envoy_config_metrics_v3_StatsMatcher__Output } from '../../../../envoy/config/metrics/v3/StatsMatcher'; +import type { HistogramBucketSettings as _envoy_config_metrics_v3_HistogramBucketSettings, HistogramBucketSettings__Output as _envoy_config_metrics_v3_HistogramBucketSettings__Output } from '../../../../envoy/config/metrics/v3/HistogramBucketSettings'; + +/** + * Statistics configuration such as tagging. + */ +export interface StatsConfig { + /** + * Each stat name is iteratively processed through these tag specifiers. + * When a tag is matched, the first capture group is removed from the name so + * later :ref:`TagSpecifiers ` cannot match that + * same portion of the match. + */ + 'stats_tags'?: (_envoy_config_metrics_v3_TagSpecifier)[]; + /** + * Use all default tag regexes specified in Envoy. These can be combined with + * custom tags specified in :ref:`stats_tags + * `. They will be processed before + * the custom tags. + * + * .. note:: + * + * If any default tags are specified twice, the config will be considered + * invalid. + * + * See :repo:`well_known_names.h ` for a list of the + * default tags in Envoy. + * + * If not provided, the value is assumed to be true. + */ + 'use_all_default_tags'?: (_google_protobuf_BoolValue | null); + /** + * Inclusion/exclusion matcher for stat name creation. If not provided, all stats are instantiated + * as normal. Preventing the instantiation of certain families of stats can improve memory + * performance for Envoys running especially large configs. + * + * .. warning:: + * Excluding stats may affect Envoy's behavior in undocumented ways. See + * `issue #8771 `_ for more information. + * If any unexpected behavior changes are observed, please open a new issue immediately. + */ + 'stats_matcher'?: (_envoy_config_metrics_v3_StatsMatcher | null); + /** + * Defines rules for setting the histogram buckets. Rules are evaluated in order, and the first + * match is applied. If no match is found (or if no rules are set), the following default buckets + * are used: + * + * .. code-block:: json + * + * [ + * 0.5, + * 1, + * 5, + * 10, + * 25, + * 50, + * 100, + * 250, + * 500, + * 1000, + * 2500, + * 5000, + * 10000, + * 30000, + * 60000, + * 300000, + * 600000, + * 1800000, + * 3600000 + * ] + */ + 'histogram_bucket_settings'?: (_envoy_config_metrics_v3_HistogramBucketSettings)[]; +} + +/** + * Statistics configuration such as tagging. + */ +export interface StatsConfig__Output { + /** + * Each stat name is iteratively processed through these tag specifiers. + * When a tag is matched, the first capture group is removed from the name so + * later :ref:`TagSpecifiers ` cannot match that + * same portion of the match. + */ + 'stats_tags': (_envoy_config_metrics_v3_TagSpecifier__Output)[]; + /** + * Use all default tag regexes specified in Envoy. These can be combined with + * custom tags specified in :ref:`stats_tags + * `. They will be processed before + * the custom tags. + * + * .. note:: + * + * If any default tags are specified twice, the config will be considered + * invalid. + * + * See :repo:`well_known_names.h ` for a list of the + * default tags in Envoy. + * + * If not provided, the value is assumed to be true. + */ + 'use_all_default_tags': (_google_protobuf_BoolValue__Output | null); + /** + * Inclusion/exclusion matcher for stat name creation. If not provided, all stats are instantiated + * as normal. Preventing the instantiation of certain families of stats can improve memory + * performance for Envoys running especially large configs. + * + * .. warning:: + * Excluding stats may affect Envoy's behavior in undocumented ways. See + * `issue #8771 `_ for more information. + * If any unexpected behavior changes are observed, please open a new issue immediately. + */ + 'stats_matcher': (_envoy_config_metrics_v3_StatsMatcher__Output | null); + /** + * Defines rules for setting the histogram buckets. Rules are evaluated in order, and the first + * match is applied. If no match is found (or if no rules are set), the following default buckets + * are used: + * + * .. code-block:: json + * + * [ + * 0.5, + * 1, + * 5, + * 10, + * 25, + * 50, + * 100, + * 250, + * 500, + * 1000, + * 2500, + * 5000, + * 10000, + * 30000, + * 60000, + * 300000, + * 600000, + * 1800000, + * 3600000 + * ] + */ + 'histogram_bucket_settings': (_envoy_config_metrics_v3_HistogramBucketSettings__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsMatcher.ts new file mode 100644 index 000000000..9df9e9529 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsMatcher.ts @@ -0,0 +1,47 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { ListStringMatcher as _envoy_type_matcher_v3_ListStringMatcher, ListStringMatcher__Output as _envoy_type_matcher_v3_ListStringMatcher__Output } from '../../../../envoy/type/matcher/v3/ListStringMatcher'; + +/** + * Configuration for disabling stat instantiation. + */ +export interface StatsMatcher { + /** + * If `reject_all` is true, then all stats are disabled. If `reject_all` is false, then all + * stats are enabled. + */ + 'reject_all'?: (boolean); + /** + * Exclusive match. All stats are enabled except for those matching one of the supplied + * StringMatcher protos. + */ + 'exclusion_list'?: (_envoy_type_matcher_v3_ListStringMatcher | null); + /** + * Inclusive match. No stats are enabled except for those matching one of the supplied + * StringMatcher protos. + */ + 'inclusion_list'?: (_envoy_type_matcher_v3_ListStringMatcher | null); + 'stats_matcher'?: "reject_all"|"exclusion_list"|"inclusion_list"; +} + +/** + * Configuration for disabling stat instantiation. + */ +export interface StatsMatcher__Output { + /** + * If `reject_all` is true, then all stats are disabled. If `reject_all` is false, then all + * stats are enabled. + */ + 'reject_all'?: (boolean); + /** + * Exclusive match. All stats are enabled except for those matching one of the supplied + * StringMatcher protos. + */ + 'exclusion_list'?: (_envoy_type_matcher_v3_ListStringMatcher__Output | null); + /** + * Inclusive match. No stats are enabled except for those matching one of the supplied + * StringMatcher protos. + */ + 'inclusion_list'?: (_envoy_type_matcher_v3_ListStringMatcher__Output | null); + 'stats_matcher': "reject_all"|"exclusion_list"|"inclusion_list"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsSink.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsSink.ts new file mode 100644 index 000000000..3eb8926fa --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsSink.ts @@ -0,0 +1,43 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +/** + * Configuration for pluggable stats sinks. + */ +export interface StatsSink { + /** + * The name of the stats sink to instantiate. The name must match a supported + * stats sink. + * See the :ref:`extensions listed in typed_config below ` for the default list of available stats sink. + * Sinks optionally support tagged/multiple dimensional metrics. + */ + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any | null); + /** + * Stats sink specific configuration which depends on the sink being instantiated. See + * :ref:`StatsdSink ` for an example. + * [#extension-category: envoy.stats_sinks] + */ + 'config_type'?: "typed_config"; +} + +/** + * Configuration for pluggable stats sinks. + */ +export interface StatsSink__Output { + /** + * The name of the stats sink to instantiate. The name must match a supported + * stats sink. + * See the :ref:`extensions listed in typed_config below ` for the default list of available stats sink. + * Sinks optionally support tagged/multiple dimensional metrics. + */ + 'name': (string); + 'typed_config'?: (_google_protobuf_Any__Output | null); + /** + * Stats sink specific configuration which depends on the sink being instantiated. See + * :ref:`StatsdSink ` for an example. + * [#extension-category: envoy.stats_sinks] + */ + 'config_type': "typed_config"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsdSink.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsdSink.ts new file mode 100644 index 000000000..69d978920 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/StatsdSink.ts @@ -0,0 +1,103 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + +import type { Address as _envoy_config_core_v3_Address, Address__Output as _envoy_config_core_v3_Address__Output } from '../../../../envoy/config/core/v3/Address'; + +/** + * Stats configuration proto schema for built-in *envoy.stat_sinks.statsd* sink. This sink does not support + * tagged metrics. + * [#extension: envoy.stat_sinks.statsd] + */ +export interface StatsdSink { + /** + * The UDP address of a running `statsd `_ + * compliant listener. If specified, statistics will be flushed to this + * address. + */ + 'address'?: (_envoy_config_core_v3_Address | null); + /** + * The name of a cluster that is running a TCP `statsd + * `_ compliant listener. If specified, + * Envoy will connect to this cluster to flush statistics. + */ + 'tcp_cluster_name'?: (string); + /** + * Optional custom prefix for StatsdSink. If + * specified, this will override the default prefix. + * For example: + * + * .. code-block:: json + * + * { + * "prefix" : "envoy-prod" + * } + * + * will change emitted stats to + * + * .. code-block:: cpp + * + * envoy-prod.test_counter:1|c + * envoy-prod.test_timer:5|ms + * + * Note that the default prefix, "envoy", will be used if a prefix is not + * specified. + * + * Stats with default prefix: + * + * .. code-block:: cpp + * + * envoy.test_counter:1|c + * envoy.test_timer:5|ms + */ + 'prefix'?: (string); + 'statsd_specifier'?: "address"|"tcp_cluster_name"; +} + +/** + * Stats configuration proto schema for built-in *envoy.stat_sinks.statsd* sink. This sink does not support + * tagged metrics. + * [#extension: envoy.stat_sinks.statsd] + */ +export interface StatsdSink__Output { + /** + * The UDP address of a running `statsd `_ + * compliant listener. If specified, statistics will be flushed to this + * address. + */ + 'address'?: (_envoy_config_core_v3_Address__Output | null); + /** + * The name of a cluster that is running a TCP `statsd + * `_ compliant listener. If specified, + * Envoy will connect to this cluster to flush statistics. + */ + 'tcp_cluster_name'?: (string); + /** + * Optional custom prefix for StatsdSink. If + * specified, this will override the default prefix. + * For example: + * + * .. code-block:: json + * + * { + * "prefix" : "envoy-prod" + * } + * + * will change emitted stats to + * + * .. code-block:: cpp + * + * envoy-prod.test_counter:1|c + * envoy-prod.test_timer:5|ms + * + * Note that the default prefix, "envoy", will be used if a prefix is not + * specified. + * + * Stats with default prefix: + * + * .. code-block:: cpp + * + * envoy.test_counter:1|c + * envoy.test_timer:5|ms + */ + 'prefix': (string); + 'statsd_specifier': "address"|"tcp_cluster_name"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/TagSpecifier.ts b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/TagSpecifier.ts new file mode 100644 index 000000000..9b0bb2467 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/metrics/v3/TagSpecifier.ts @@ -0,0 +1,174 @@ +// Original file: deps/envoy-api/envoy/config/metrics/v3/stats.proto + + +/** + * Designates a tag name and value pair. The value may be either a fixed value + * or a regex providing the value via capture groups. The specified tag will be + * unconditionally set if a fixed value, otherwise it will only be set if one + * or more capture groups in the regex match. + */ +export interface TagSpecifier { + /** + * Attaches an identifier to the tag values to identify the tag being in the + * sink. Envoy has a set of default names and regexes to extract dynamic + * portions of existing stats, which can be found in :repo:`well_known_names.h + * ` in the Envoy repository. If a :ref:`tag_name + * ` is provided in the config and + * neither :ref:`regex ` or + * :ref:`fixed_value ` were specified, + * Envoy will attempt to find that name in its set of defaults and use the accompanying regex. + * + * .. note:: + * + * It is invalid to specify the same tag name twice in a config. + */ + 'tag_name'?: (string); + /** + * Designates a tag to strip from the tag extracted name and provide as a named + * tag value for all statistics. This will only occur if any part of the name + * matches the regex provided with one or more capture groups. + * + * The first capture group identifies the portion of the name to remove. The + * second capture group (which will normally be nested inside the first) will + * designate the value of the tag for the statistic. If no second capture + * group is provided, the first will also be used to set the value of the tag. + * All other capture groups will be ignored. + * + * Example 1. a stat name ``cluster.foo_cluster.upstream_rq_timeout`` and + * one tag specifier: + * + * .. code-block:: json + * + * { + * "tag_name": "envoy.cluster_name", + * "regex": "^cluster\\.((.+?)\\.)" + * } + * + * Note that the regex will remove ``foo_cluster.`` making the tag extracted + * name ``cluster.upstream_rq_timeout`` and the tag value for + * ``envoy.cluster_name`` will be ``foo_cluster`` (note: there will be no + * ``.`` character because of the second capture group). + * + * Example 2. a stat name + * ``http.connection_manager_1.user_agent.ios.downstream_cx_total`` and two + * tag specifiers: + * + * .. code-block:: json + * + * [ + * { + * "tag_name": "envoy.http_user_agent", + * "regex": "^http(?=\\.).*?\\.user_agent\\.((.+?)\\.)\\w+?$" + * }, + * { + * "tag_name": "envoy.http_conn_manager_prefix", + * "regex": "^http\\.((.*?)\\.)" + * } + * ] + * + * The two regexes of the specifiers will be processed in the definition order. + * + * The first regex will remove ``ios.``, leaving the tag extracted name + * ``http.connection_manager_1.user_agent.downstream_cx_total``. The tag + * ``envoy.http_user_agent`` will be added with tag value ``ios``. + * + * The second regex will remove ``connection_manager_1.`` from the tag + * extracted name produced by the first regex + * ``http.connection_manager_1.user_agent.downstream_cx_total``, leaving + * ``http.user_agent.downstream_cx_total`` as the tag extracted name. The tag + * ``envoy.http_conn_manager_prefix`` will be added with the tag value + * ``connection_manager_1``. + */ + 'regex'?: (string); + /** + * Specifies a fixed tag value for the ``tag_name``. + */ + 'fixed_value'?: (string); + 'tag_value'?: "regex"|"fixed_value"; +} + +/** + * Designates a tag name and value pair. The value may be either a fixed value + * or a regex providing the value via capture groups. The specified tag will be + * unconditionally set if a fixed value, otherwise it will only be set if one + * or more capture groups in the regex match. + */ +export interface TagSpecifier__Output { + /** + * Attaches an identifier to the tag values to identify the tag being in the + * sink. Envoy has a set of default names and regexes to extract dynamic + * portions of existing stats, which can be found in :repo:`well_known_names.h + * ` in the Envoy repository. If a :ref:`tag_name + * ` is provided in the config and + * neither :ref:`regex ` or + * :ref:`fixed_value ` were specified, + * Envoy will attempt to find that name in its set of defaults and use the accompanying regex. + * + * .. note:: + * + * It is invalid to specify the same tag name twice in a config. + */ + 'tag_name': (string); + /** + * Designates a tag to strip from the tag extracted name and provide as a named + * tag value for all statistics. This will only occur if any part of the name + * matches the regex provided with one or more capture groups. + * + * The first capture group identifies the portion of the name to remove. The + * second capture group (which will normally be nested inside the first) will + * designate the value of the tag for the statistic. If no second capture + * group is provided, the first will also be used to set the value of the tag. + * All other capture groups will be ignored. + * + * Example 1. a stat name ``cluster.foo_cluster.upstream_rq_timeout`` and + * one tag specifier: + * + * .. code-block:: json + * + * { + * "tag_name": "envoy.cluster_name", + * "regex": "^cluster\\.((.+?)\\.)" + * } + * + * Note that the regex will remove ``foo_cluster.`` making the tag extracted + * name ``cluster.upstream_rq_timeout`` and the tag value for + * ``envoy.cluster_name`` will be ``foo_cluster`` (note: there will be no + * ``.`` character because of the second capture group). + * + * Example 2. a stat name + * ``http.connection_manager_1.user_agent.ios.downstream_cx_total`` and two + * tag specifiers: + * + * .. code-block:: json + * + * [ + * { + * "tag_name": "envoy.http_user_agent", + * "regex": "^http(?=\\.).*?\\.user_agent\\.((.+?)\\.)\\w+?$" + * }, + * { + * "tag_name": "envoy.http_conn_manager_prefix", + * "regex": "^http\\.((.*?)\\.)" + * } + * ] + * + * The two regexes of the specifiers will be processed in the definition order. + * + * The first regex will remove ``ios.``, leaving the tag extracted name + * ``http.connection_manager_1.user_agent.downstream_cx_total``. The tag + * ``envoy.http_user_agent`` will be added with tag value ``ios``. + * + * The second regex will remove ``connection_manager_1.`` from the tag + * extracted name produced by the first regex + * ``http.connection_manager_1.user_agent.downstream_cx_total``, leaving + * ``http.user_agent.downstream_cx_total`` as the tag extracted name. The tag + * ``envoy.http_conn_manager_prefix`` will be added with the tag value + * ``connection_manager_1``. + */ + 'regex'?: (string); + /** + * Specifies a fixed tag value for the ``tag_name``. + */ + 'fixed_value'?: (string); + 'tag_value': "regex"|"fixed_value"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/BufferFactoryConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/BufferFactoryConfig.ts new file mode 100644 index 000000000..b3fbe1459 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/BufferFactoryConfig.ts @@ -0,0 +1,50 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + + +/** + * Configuration for which accounts the WatermarkBuffer Factories should + * track. + */ +export interface BufferFactoryConfig { + /** + * The minimum power of two at which Envoy starts tracking an account. + * + * Envoy has 8 power of two buckets starting with the provided exponent below. + * Concretely the 1st bucket contains accounts for streams that use + * [2^minimum_account_to_track_power_of_two, + * 2^(minimum_account_to_track_power_of_two + 1)) bytes. + * With the 8th bucket tracking accounts + * >= 128 * 2^minimum_account_to_track_power_of_two. + * + * The maximum value is 56, since we're using uint64_t for bytes counting, + * and that's the last value that would use the 8 buckets. In practice, + * we don't expect the proxy to be holding 2^56 bytes. + * + * If omitted, Envoy should not do any tracking. + */ + 'minimum_account_to_track_power_of_two'?: (number); +} + +/** + * Configuration for which accounts the WatermarkBuffer Factories should + * track. + */ +export interface BufferFactoryConfig__Output { + /** + * The minimum power of two at which Envoy starts tracking an account. + * + * Envoy has 8 power of two buckets starting with the provided exponent below. + * Concretely the 1st bucket contains accounts for streams that use + * [2^minimum_account_to_track_power_of_two, + * 2^(minimum_account_to_track_power_of_two + 1)) bytes. + * With the 8th bucket tracking accounts + * >= 128 * 2^minimum_account_to_track_power_of_two. + * + * The maximum value is 56, since we're using uint64_t for bytes counting, + * and that's the last value that would use the 8 buckets. In practice, + * we don't expect the proxy to be holding 2^56 bytes. + * + * If omitted, Envoy should not do any tracking. + */ + 'minimum_account_to_track_power_of_two': (number); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadAction.ts new file mode 100644 index 000000000..84f4db34b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadAction.ts @@ -0,0 +1,42 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + +import type { Trigger as _envoy_config_overload_v3_Trigger, Trigger__Output as _envoy_config_overload_v3_Trigger__Output } from '../../../../envoy/config/overload/v3/Trigger'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface OverloadAction { + /** + * The name of the overload action. This is just a well-known string that listeners can + * use for registering callbacks. Custom overload actions should be named using reverse + * DNS to ensure uniqueness. + */ + 'name'?: (string); + /** + * A set of triggers for this action. The state of the action is the maximum + * state of all triggers, which can be scaling between 0 and 1 or saturated. Listeners + * are notified when the overload action changes state. + */ + 'triggers'?: (_envoy_config_overload_v3_Trigger)[]; + /** + * Configuration for the action being instantiated. + */ + 'typed_config'?: (_google_protobuf_Any | null); +} + +export interface OverloadAction__Output { + /** + * The name of the overload action. This is just a well-known string that listeners can + * use for registering callbacks. Custom overload actions should be named using reverse + * DNS to ensure uniqueness. + */ + 'name': (string); + /** + * A set of triggers for this action. The state of the action is the maximum + * state of all triggers, which can be scaling between 0 and 1 or saturated. Listeners + * are notified when the overload action changes state. + */ + 'triggers': (_envoy_config_overload_v3_Trigger__Output)[]; + /** + * Configuration for the action being instantiated. + */ + 'typed_config': (_google_protobuf_Any__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadManager.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadManager.ts new file mode 100644 index 000000000..e7f75b8e9 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/OverloadManager.ts @@ -0,0 +1,44 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { ResourceMonitor as _envoy_config_overload_v3_ResourceMonitor, ResourceMonitor__Output as _envoy_config_overload_v3_ResourceMonitor__Output } from '../../../../envoy/config/overload/v3/ResourceMonitor'; +import type { OverloadAction as _envoy_config_overload_v3_OverloadAction, OverloadAction__Output as _envoy_config_overload_v3_OverloadAction__Output } from '../../../../envoy/config/overload/v3/OverloadAction'; +import type { BufferFactoryConfig as _envoy_config_overload_v3_BufferFactoryConfig, BufferFactoryConfig__Output as _envoy_config_overload_v3_BufferFactoryConfig__Output } from '../../../../envoy/config/overload/v3/BufferFactoryConfig'; + +export interface OverloadManager { + /** + * The interval for refreshing resource usage. + */ + 'refresh_interval'?: (_google_protobuf_Duration | null); + /** + * The set of resources to monitor. + */ + 'resource_monitors'?: (_envoy_config_overload_v3_ResourceMonitor)[]; + /** + * The set of overload actions. + */ + 'actions'?: (_envoy_config_overload_v3_OverloadAction)[]; + /** + * Configuration for buffer factory. + */ + 'buffer_factory_config'?: (_envoy_config_overload_v3_BufferFactoryConfig | null); +} + +export interface OverloadManager__Output { + /** + * The interval for refreshing resource usage. + */ + 'refresh_interval': (_google_protobuf_Duration__Output | null); + /** + * The set of resources to monitor. + */ + 'resource_monitors': (_envoy_config_overload_v3_ResourceMonitor__Output)[]; + /** + * The set of overload actions. + */ + 'actions': (_envoy_config_overload_v3_OverloadAction__Output)[]; + /** + * Configuration for buffer factory. + */ + 'buffer_factory_config': (_envoy_config_overload_v3_BufferFactoryConfig__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ResourceMonitor.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ResourceMonitor.ts new file mode 100644 index 000000000..02fde2411 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ResourceMonitor.ts @@ -0,0 +1,33 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; + +export interface ResourceMonitor { + /** + * The name of the resource monitor to instantiate. Must match a registered + * resource monitor type. + * See the :ref:`extensions listed in typed_config below ` for the default list of available resource monitor. + */ + 'name'?: (string); + 'typed_config'?: (_google_protobuf_Any | null); + /** + * Configuration for the resource monitor being instantiated. + * [#extension-category: envoy.resource_monitors] + */ + 'config_type'?: "typed_config"; +} + +export interface ResourceMonitor__Output { + /** + * The name of the resource monitor to instantiate. Must match a registered + * resource monitor type. + * See the :ref:`extensions listed in typed_config below ` for the default list of available resource monitor. + */ + 'name': (string); + 'typed_config'?: (_google_protobuf_Any__Output | null); + /** + * Configuration for the resource monitor being instantiated. + * [#extension-category: envoy.resource_monitors] + */ + 'config_type': "typed_config"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaleTimersOverloadActionConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaleTimersOverloadActionConfig.ts new file mode 100644 index 000000000..bb48fe3f6 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaleTimersOverloadActionConfig.ts @@ -0,0 +1,89 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + +import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; +import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../envoy/type/v3/Percent'; + +export interface _envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer { + /** + * The type of timer this minimum applies to. + */ + 'timer'?: (_envoy_config_overload_v3_ScaleTimersOverloadActionConfig_TimerType | keyof typeof _envoy_config_overload_v3_ScaleTimersOverloadActionConfig_TimerType); + /** + * Sets the minimum duration as an absolute value. + */ + 'min_timeout'?: (_google_protobuf_Duration | null); + /** + * Sets the minimum duration as a percentage of the maximum value. + */ + 'min_scale'?: (_envoy_type_v3_Percent | null); + 'overload_adjust'?: "min_timeout"|"min_scale"; +} + +export interface _envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer__Output { + /** + * The type of timer this minimum applies to. + */ + 'timer': (keyof typeof _envoy_config_overload_v3_ScaleTimersOverloadActionConfig_TimerType); + /** + * Sets the minimum duration as an absolute value. + */ + 'min_timeout'?: (_google_protobuf_Duration__Output | null); + /** + * Sets the minimum duration as a percentage of the maximum value. + */ + 'min_scale'?: (_envoy_type_v3_Percent__Output | null); + 'overload_adjust': "min_timeout"|"min_scale"; +} + +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + +export enum _envoy_config_overload_v3_ScaleTimersOverloadActionConfig_TimerType { + /** + * Unsupported value; users must explicitly specify the timer they want scaled. + */ + UNSPECIFIED = 0, + /** + * Adjusts the idle timer for downstream HTTP connections that takes effect when there are no active streams. + * This affects the value of :ref:`HttpConnectionManager.common_http_protocol_options.idle_timeout + * ` + */ + HTTP_DOWNSTREAM_CONNECTION_IDLE = 1, + /** + * Adjusts the idle timer for HTTP streams initiated by downstream clients. + * This affects the value of :ref:`RouteAction.idle_timeout ` and + * :ref:`HttpConnectionManager.stream_idle_timeout + * ` + */ + HTTP_DOWNSTREAM_STREAM_IDLE = 2, + /** + * Adjusts the timer for how long downstream clients have to finish transport-level negotiations + * before the connection is closed. + * This affects the value of + * :ref:`FilterChain.transport_socket_connect_timeout `. + */ + TRANSPORT_SOCKET_CONNECT = 3, +} + +/** + * Typed configuration for the "envoy.overload_actions.reduce_timeouts" action. See + * :ref:`the docs ` for an example of how to configure + * the action with different timeouts and minimum values. + */ +export interface ScaleTimersOverloadActionConfig { + /** + * A set of timer scaling rules to be applied. + */ + 'timer_scale_factors'?: (_envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer)[]; +} + +/** + * Typed configuration for the "envoy.overload_actions.reduce_timeouts" action. See + * :ref:`the docs ` for an example of how to configure + * the action with different timeouts and minimum values. + */ +export interface ScaleTimersOverloadActionConfig__Output { + /** + * A set of timer scaling rules to be applied. + */ + 'timer_scale_factors': (_envoy_config_overload_v3_ScaleTimersOverloadActionConfig_ScaleTimer__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaledTrigger.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaledTrigger.ts new file mode 100644 index 000000000..8c6574f56 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ScaledTrigger.ts @@ -0,0 +1,28 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + + +export interface ScaledTrigger { + /** + * If the resource pressure is greater than this value, the trigger will be in the + * :ref:`scaling ` state with value + * `(pressure - scaling_threshold) / (saturation_threshold - scaling_threshold)`. + */ + 'scaling_threshold'?: (number | string); + /** + * If the resource pressure is greater than this value, the trigger will enter saturation. + */ + 'saturation_threshold'?: (number | string); +} + +export interface ScaledTrigger__Output { + /** + * If the resource pressure is greater than this value, the trigger will be in the + * :ref:`scaling ` state with value + * `(pressure - scaling_threshold) / (saturation_threshold - scaling_threshold)`. + */ + 'scaling_threshold': (number); + /** + * If the resource pressure is greater than this value, the trigger will enter saturation. + */ + 'saturation_threshold': (number); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ThresholdTrigger.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ThresholdTrigger.ts new file mode 100644 index 000000000..b02ddd47d --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/ThresholdTrigger.ts @@ -0,0 +1,18 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + + +export interface ThresholdTrigger { + /** + * If the resource pressure is greater than or equal to this value, the trigger + * will enter saturation. + */ + 'value'?: (number | string); +} + +export interface ThresholdTrigger__Output { + /** + * If the resource pressure is greater than or equal to this value, the trigger + * will enter saturation. + */ + 'value': (number); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/Trigger.ts b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/Trigger.ts new file mode 100644 index 000000000..38f360ee7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/overload/v3/Trigger.ts @@ -0,0 +1,24 @@ +// Original file: deps/envoy-api/envoy/config/overload/v3/overload.proto + +import type { ThresholdTrigger as _envoy_config_overload_v3_ThresholdTrigger, ThresholdTrigger__Output as _envoy_config_overload_v3_ThresholdTrigger__Output } from '../../../../envoy/config/overload/v3/ThresholdTrigger'; +import type { ScaledTrigger as _envoy_config_overload_v3_ScaledTrigger, ScaledTrigger__Output as _envoy_config_overload_v3_ScaledTrigger__Output } from '../../../../envoy/config/overload/v3/ScaledTrigger'; + +export interface Trigger { + /** + * The name of the resource this is a trigger for. + */ + 'name'?: (string); + 'threshold'?: (_envoy_config_overload_v3_ThresholdTrigger | null); + 'scaled'?: (_envoy_config_overload_v3_ScaledTrigger | null); + 'trigger_oneof'?: "threshold"|"scaled"; +} + +export interface Trigger__Output { + /** + * The name of the resource this is a trigger for. + */ + 'name': (string); + 'threshold'?: (_envoy_config_overload_v3_ThresholdTrigger__Output | null); + 'scaled'?: (_envoy_config_overload_v3_ScaledTrigger__Output | null); + 'trigger_oneof': "threshold"|"scaled"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ClusterSpecifierPlugin.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ClusterSpecifierPlugin.ts new file mode 100644 index 000000000..14724412a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ClusterSpecifierPlugin.ts @@ -0,0 +1,23 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route.proto + +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; + +/** + * Configuration for a cluster specifier plugin. + */ +export interface ClusterSpecifierPlugin { + /** + * The name of the plugin and its opaque configuration. + */ + 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig | null); +} + +/** + * Configuration for a cluster specifier plugin. + */ +export interface ClusterSpecifierPlugin__Output { + /** + * The name of the plugin and its opaque configuration. + */ + 'extension': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts index 03ec3218d..40634448a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/CorsPolicy.ts @@ -34,7 +34,7 @@ export interface CorsPolicy { * If neither ``enabled``, ``filter_enabled``, nor ``shadow_enabled`` are specified, the CORS * filter will be enabled for 100% of the requests. * - * If :ref:`runtime_key ` is + * If :ref:`runtime_key ` is * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. */ 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent | null); @@ -45,7 +45,7 @@ export interface CorsPolicy { * This field is intended to be used when ``filter_enabled`` and ``enabled`` are off. One of those * fields have to explicitly disable the filter in order for this setting to take effect. * - * If :ref:`runtime_key ` is specified, + * If :ref:`runtime_key ` is specified, * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ @@ -88,7 +88,7 @@ export interface CorsPolicy__Output { * If neither ``enabled``, ``filter_enabled``, nor ``shadow_enabled`` are specified, the CORS * filter will be enabled for 100% of the requests. * - * If :ref:`runtime_key ` is + * If :ref:`runtime_key ` is * specified, Envoy will lookup the runtime key to get the percentage of requests to filter. */ 'filter_enabled'?: (_envoy_config_core_v3_RuntimeFractionalPercent__Output | null); @@ -99,7 +99,7 @@ export interface CorsPolicy__Output { * This field is intended to be used when ``filter_enabled`` and ``enabled`` are off. One of those * fields have to explicitly disable the filter in order for this setting to take effect. * - * If :ref:`runtime_key ` is specified, + * If :ref:`runtime_key ` is specified, * Envoy will lookup the runtime key to get the percentage of requests for which it will evaluate * and track the request's *Origin* to determine if it's valid but will not enforce any policies. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts index 7e0c3a1b7..794ae510a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/DirectResponseAction.ts @@ -14,8 +14,8 @@ export interface DirectResponseAction { * .. note:: * * Headers can be specified using *response_headers_to_add* in the enclosing - * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` or - * :ref:`envoy_api_msg_config.route.v3.VirtualHost`. + * :ref:`envoy_v3_api_msg_config.route.v3.Route`, :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration` or + * :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost`. */ 'body'?: (_envoy_config_core_v3_DataSource | null); } @@ -32,8 +32,8 @@ export interface DirectResponseAction__Output { * .. note:: * * Headers can be specified using *response_headers_to_add* in the enclosing - * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` or - * :ref:`envoy_api_msg_config.route.v3.VirtualHost`. + * :ref:`envoy_v3_api_msg_config.route.v3.Route`, :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration` or + * :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost`. */ 'body': (_envoy_config_core_v3_DataSource__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts index 9a566c2bb..2c960419c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/FilterConfig.ts @@ -5,9 +5,9 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ /** * A simple wrapper for an HTTP filter config. This is intended to be used as a wrapper for the * map value in - * :ref:`VirtualHost.typed_per_filter_config`, - * :ref:`Route.typed_per_filter_config`, - * or :ref:`WeightedCluster.ClusterWeight.typed_per_filter_config` + * :ref:`VirtualHost.typed_per_filter_config`, + * :ref:`Route.typed_per_filter_config`, + * or :ref:`WeightedCluster.ClusterWeight.typed_per_filter_config` * to add additional flags to the filter. * [#not-implemented-hide:] */ @@ -27,9 +27,9 @@ export interface FilterConfig { /** * A simple wrapper for an HTTP filter config. This is intended to be used as a wrapper for the * map value in - * :ref:`VirtualHost.typed_per_filter_config`, - * :ref:`Route.typed_per_filter_config`, - * or :ref:`WeightedCluster.ClusterWeight.typed_per_filter_config` + * :ref:`VirtualHost.typed_per_filter_config`, + * :ref:`Route.typed_per_filter_config`, + * or :ref:`WeightedCluster.ClusterWeight.typed_per_filter_config` * to add additional flags to the filter. * [#not-implemented-hide:] */ diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts index ee03d1fe7..bde8f28cd 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HeaderMatcher.ts @@ -2,6 +2,7 @@ import type { Int64Range as _envoy_type_v3_Int64Range, Int64Range__Output as _envoy_type_v3_Int64Range__Output } from '../../../../envoy/type/v3/Int64Range'; import type { RegexMatcher as _envoy_type_matcher_v3_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_v3_RegexMatcher__Output } from '../../../../envoy/type/matcher/v3/RegexMatcher'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; import type { Long } from '@grpc/proto-loader'; /** @@ -24,12 +25,12 @@ import type { Long } from '@grpc/proto-loader'; * * .. attention:: * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's * value. * * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 13] + * [#next-free-field: 14] */ export interface HeaderMatcher { /** @@ -38,6 +39,7 @@ export interface HeaderMatcher { 'name'?: (string); /** * If specified, header match will be performed based on the value of the header. + * This field is deprecated. Please use :ref:`string_match `. */ 'exact_match'?: (string); /** @@ -55,8 +57,8 @@ export interface HeaderMatcher { */ 'range_match'?: (_envoy_type_v3_Int64Range | null); /** - * If specified, header match will be performed based on whether the header is in the - * request. + * If specified as true, header match will be performed based on whether the header is in the + * request. If specified as false, header match will be performed based on whether the header is absent. */ 'present_match'?: (boolean); /** @@ -71,6 +73,7 @@ export interface HeaderMatcher { /** * If specified, header match will be performed based on the prefix of the header value. * Note: empty prefix is not allowed, please use present_match instead. + * This field is deprecated. Please use :ref:`string_match `. * * Examples: * @@ -80,6 +83,7 @@ export interface HeaderMatcher { /** * If specified, header match will be performed based on the suffix of the header value. * Note: empty suffix is not allowed, please use present_match instead. + * This field is deprecated. Please use :ref:`string_match `. * * Examples: * @@ -90,22 +94,28 @@ export interface HeaderMatcher { * If specified, this regex string is a regular expression rule which implies the entire request * header value must match the regex. The rule will not match if only a subsequence of the * request header value matches the regex. + * This field is deprecated. Please use :ref:`string_match `. */ 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher | null); /** * If specified, header match will be performed based on whether the header value contains * the given value or not. * Note: empty contains match is not allowed, please use present_match instead. + * This field is deprecated. Please use :ref:`string_match `. * * Examples: * * * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. */ 'contains_match'?: (string); + /** + * If specified, header match will be performed based on the string match of the header value. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher | null); /** * Specifies how the header match will be performed to route the request. */ - 'header_match_specifier'?: "exact_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"|"contains_match"; + 'header_match_specifier'?: "exact_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"|"contains_match"|"string_match"; } /** @@ -128,12 +138,12 @@ export interface HeaderMatcher { * * .. attention:: * In the absence of any header match specifier, match will default to :ref:`present_match - * `. i.e, a request that has the :ref:`name - * ` header will match, regardless of the header's + * `. i.e, a request that has the :ref:`name + * ` header will match, regardless of the header's * value. * * [#next-major-version: HeaderMatcher should be refactored to use StringMatcher.] - * [#next-free-field: 13] + * [#next-free-field: 14] */ export interface HeaderMatcher__Output { /** @@ -142,6 +152,7 @@ export interface HeaderMatcher__Output { 'name': (string); /** * If specified, header match will be performed based on the value of the header. + * This field is deprecated. Please use :ref:`string_match `. */ 'exact_match'?: (string); /** @@ -159,8 +170,8 @@ export interface HeaderMatcher__Output { */ 'range_match'?: (_envoy_type_v3_Int64Range__Output | null); /** - * If specified, header match will be performed based on whether the header is in the - * request. + * If specified as true, header match will be performed based on whether the header is in the + * request. If specified as false, header match will be performed based on whether the header is absent. */ 'present_match'?: (boolean); /** @@ -175,6 +186,7 @@ export interface HeaderMatcher__Output { /** * If specified, header match will be performed based on the prefix of the header value. * Note: empty prefix is not allowed, please use present_match instead. + * This field is deprecated. Please use :ref:`string_match `. * * Examples: * @@ -184,6 +196,7 @@ export interface HeaderMatcher__Output { /** * If specified, header match will be performed based on the suffix of the header value. * Note: empty suffix is not allowed, please use present_match instead. + * This field is deprecated. Please use :ref:`string_match `. * * Examples: * @@ -194,20 +207,26 @@ export interface HeaderMatcher__Output { * If specified, this regex string is a regular expression rule which implies the entire request * header value must match the regex. The rule will not match if only a subsequence of the * request header value matches the regex. + * This field is deprecated. Please use :ref:`string_match `. */ 'safe_regex_match'?: (_envoy_type_matcher_v3_RegexMatcher__Output | null); /** * If specified, header match will be performed based on whether the header value contains * the given value or not. * Note: empty contains match is not allowed, please use present_match instead. + * This field is deprecated. Please use :ref:`string_match `. * * Examples: * * * The value *abcd* matches the value *xyzabcdpqr*, but not for *xyzbcdpqr*. */ 'contains_match'?: (string); + /** + * If specified, header match will be performed based on the string match of the header value. + */ + 'string_match'?: (_envoy_type_matcher_v3_StringMatcher__Output | null); /** * Specifies how the header match will be performed to route the request. */ - 'header_match_specifier': "exact_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"|"contains_match"; + 'header_match_specifier': "exact_match"|"safe_regex_match"|"range_match"|"present_match"|"prefix_match"|"suffix_match"|"contains_match"|"string_match"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts index 413e93b27..302b6d284 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/HedgePolicy.ts @@ -31,7 +31,7 @@ export interface HedgePolicy { * if there are no more retries left. * * After per-try timeout, an error response would be discarded, as a retry in the form of a hedged request is already in progress. * - * Note: For this to have effect, you must have a :ref:`RetryPolicy ` that retries at least + * Note: For this to have effect, you must have a :ref:`RetryPolicy ` that retries at least * one error code and specifies a maximum number of retries. * * Defaults to false. @@ -67,7 +67,7 @@ export interface HedgePolicy__Output { * if there are no more retries left. * * After per-try timeout, an error response would be discarded, as a retry in the form of a hedged request is already in progress. * - * Note: For this to have effect, you must have a :ref:`RetryPolicy ` that retries at least + * Note: For this to have effect, you must have a :ref:`RetryPolicy ` that retries at least * one error code and specifies a maximum number of retries. * * Defaults to false. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts index 93a96c247..ab74df94e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/InternalRedirectPolicy.ts @@ -12,7 +12,7 @@ export interface InternalRedirectPolicy { * downstream request has encountered is lower than this value. * In the case where a downstream request is bounced among multiple routes by internal redirect, * the first route that hits this threshold, or does not set :ref:`internal_redirect_policy - * ` + * ` * will pass the redirect back to downstream. * * If not specified, at most one redirect will be followed. @@ -28,6 +28,7 @@ export interface InternalRedirectPolicy { * Specifies a list of predicates that are queried when an upstream response is deemed * to trigger an internal redirect by all other criteria. Any predicate in the list can reject * the redirect, causing the response to be proxied to downstream. + * [#extension-category: envoy.internal_redirect_predicates] */ 'predicates'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; /** @@ -46,7 +47,7 @@ export interface InternalRedirectPolicy__Output { * downstream request has encountered is lower than this value. * In the case where a downstream request is bounced among multiple routes by internal redirect, * the first route that hits this threshold, or does not set :ref:`internal_redirect_policy - * ` + * ` * will pass the redirect back to downstream. * * If not specified, at most one redirect will be followed. @@ -62,6 +63,7 @@ export interface InternalRedirectPolicy__Output { * Specifies a list of predicates that are queried when an upstream response is deemed * to trigger an internal redirect by all other criteria. Any predicate in the list can reject * the redirect, causing the response to be proxied to downstream. + * [#extension-category: envoy.internal_redirect_predicates] */ 'predicates': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/NonForwardingAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/NonForwardingAction.ts new file mode 100644 index 000000000..e9c67d44f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/NonForwardingAction.ts @@ -0,0 +1,14 @@ +// Original file: deps/envoy-api/envoy/config/route/v3/route_components.proto + + +/** + * [#not-implemented-hide:] + */ +export interface NonForwardingAction { +} + +/** + * [#not-implemented-hide:] + */ +export interface NonForwardingAction__Output { +} diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts index 484044bdf..f1d49537c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RateLimit.ts @@ -38,7 +38,7 @@ export interface _envoy_config_route_v3_RateLimit_Action { * Rate limit on dynamic metadata. * * .. attention:: - * This field has been deprecated in favor of the :ref:`metadata ` field + * This field has been deprecated in favor of the :ref:`metadata ` field */ 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData | null); /** @@ -47,6 +47,7 @@ export interface _envoy_config_route_v3_RateLimit_Action { 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData | null); /** * Rate limit descriptor extension. See the rate limit descriptor extensions documentation. + * [#extension-category: envoy.rate_limit_descriptors] */ 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig | null); 'action_specifier'?: "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"|"dynamic_metadata"|"metadata"|"extension"; @@ -84,7 +85,7 @@ export interface _envoy_config_route_v3_RateLimit_Action__Output { * Rate limit on dynamic metadata. * * .. attention:: - * This field has been deprecated in favor of the :ref:`metadata ` field + * This field has been deprecated in favor of the :ref:`metadata ` field */ 'dynamic_metadata'?: (_envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output | null); /** @@ -93,6 +94,7 @@ export interface _envoy_config_route_v3_RateLimit_Action__Output { 'metadata'?: (_envoy_config_route_v3_RateLimit_Action_MetaData__Output | null); /** * Rate limit descriptor extension. See the rate limit descriptor extensions documentation. + * [#extension-category: envoy.rate_limit_descriptors] */ 'extension'?: (_envoy_config_core_v3_TypedExtensionConfig__Output | null); 'action_specifier': "source_cluster"|"destination_cluster"|"request_headers"|"remote_address"|"generic_key"|"header_value_match"|"dynamic_metadata"|"metadata"|"extension"; @@ -106,14 +108,14 @@ export interface _envoy_config_route_v3_RateLimit_Action__Output { * ("destination_cluster", "") * * Once a request matches against a route table rule, a routed cluster is determined by one of - * the following :ref:`route table configuration ` + * the following :ref:`route table configuration ` * settings: * - * * :ref:`cluster ` indicates the upstream cluster + * * :ref:`cluster ` indicates the upstream cluster * to route to. - * * :ref:`weighted_clusters ` + * * :ref:`weighted_clusters ` * chooses a cluster randomly from a set of clusters with attributed weight. - * * :ref:`cluster_header ` indicates which + * * :ref:`cluster_header ` indicates which * header in the request contains the target cluster. */ export interface _envoy_config_route_v3_RateLimit_Action_DestinationCluster { @@ -127,14 +129,14 @@ export interface _envoy_config_route_v3_RateLimit_Action_DestinationCluster { * ("destination_cluster", "") * * Once a request matches against a route table rule, a routed cluster is determined by one of - * the following :ref:`route table configuration ` + * the following :ref:`route table configuration ` * settings: * - * * :ref:`cluster ` indicates the upstream cluster + * * :ref:`cluster ` indicates the upstream cluster * to route to. - * * :ref:`weighted_clusters ` + * * :ref:`weighted_clusters ` * chooses a cluster randomly from a set of clusters with attributed weight. - * * :ref:`cluster_header ` indicates which + * * :ref:`cluster_header ` indicates which * header in the request contains the target cluster. */ export interface _envoy_config_route_v3_RateLimit_Action_DestinationCluster__Output { @@ -149,7 +151,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_DestinationCluster__Out * ("", "") * * .. attention:: - * This action has been deprecated in favor of the :ref:`metadata ` action + * This action has been deprecated in favor of the :ref:`metadata ` action */ export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData { /** @@ -177,7 +179,7 @@ export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData { * ("", "") * * .. attention:: - * This action has been deprecated in favor of the :ref:`metadata ` action + * This action has been deprecated in favor of the :ref:`metadata ` action */ export interface _envoy_config_route_v3_RateLimit_Action_DynamicMetaData__Output { /** @@ -204,7 +206,7 @@ export interface _envoy_config_route_v3_RateLimit_Override_DynamicMetadata { * Metadata struct that defines the key and path to retrieve the struct value. * The value must be a struct containing an integer "requests_per_unit" property * and a "unit" property with a value parseable to :ref:`RateLimitUnit - * enum ` + * enum ` */ 'metadata_key'?: (_envoy_type_metadata_v3_MetadataKey | null); } @@ -217,7 +219,7 @@ export interface _envoy_config_route_v3_RateLimit_Override_DynamicMetadata__Outp * Metadata struct that defines the key and path to retrieve the struct value. * The value must be a struct containing an integer "requests_per_unit" property * and a "unit" property with a value parseable to :ref:`RateLimitUnit - * enum ` + * enum ` */ 'metadata_key': (_envoy_type_metadata_v3_MetadataKey__Output | null); } @@ -474,7 +476,7 @@ export enum _envoy_config_route_v3_RateLimit_Action_MetaData_Source { */ DYNAMIC = 0, /** - * Query :ref:`route entry metadata ` + * Query :ref:`route entry metadata ` */ ROUTE_ENTRY = 1, } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts index 750946934..e6d41fd7b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RedirectAction.ts @@ -71,7 +71,7 @@ export interface RedirectAction { * .. attention:: * * Pay attention to the use of trailing slashes as mentioned in - * :ref:`RouteAction's prefix_rewrite `. + * :ref:`RouteAction's prefix_rewrite `. */ 'prefix_rewrite'?: (string); /** @@ -168,7 +168,7 @@ export interface RedirectAction__Output { * .. attention:: * * Pay attention to the use of trailing slashes as mentioned in - * :ref:`RouteAction's prefix_rewrite `. + * :ref:`RouteAction's prefix_rewrite `. */ 'prefix_rewrite'?: (string); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts index d4712b2df..0d523b52e 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RetryPolicy.ts @@ -3,6 +3,7 @@ import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatcher__Output as _envoy_config_route_v3_HeaderMatcher__Output } from '../../../../envoy/config/route/v3/HeaderMatcher'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../envoy/config/core/v3/TypedExtensionConfig'; import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; import type { Long } from '@grpc/proto-loader'; @@ -202,30 +203,42 @@ export interface _envoy_config_route_v3_RetryPolicy_RetryBackOff__Output { export interface _envoy_config_route_v3_RetryPolicy_RetryHostPredicate { 'name'?: (string); 'typed_config'?: (_google_protobuf_Any | null); + /** + * [#extension-category: envoy.retry_host_predicates] + */ 'config_type'?: "typed_config"; } export interface _envoy_config_route_v3_RetryPolicy_RetryHostPredicate__Output { 'name': (string); 'typed_config'?: (_google_protobuf_Any__Output | null); + /** + * [#extension-category: envoy.retry_host_predicates] + */ 'config_type': "typed_config"; } export interface _envoy_config_route_v3_RetryPolicy_RetryPriority { 'name'?: (string); 'typed_config'?: (_google_protobuf_Any | null); + /** + * [#extension-category: envoy.retry_priorities] + */ 'config_type'?: "typed_config"; } export interface _envoy_config_route_v3_RetryPolicy_RetryPriority__Output { 'name': (string); 'typed_config'?: (_google_protobuf_Any__Output | null); + /** + * [#extension-category: envoy.retry_priorities] + */ 'config_type': "typed_config"; } /** * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 12] + * [#next-free-field: 14] */ export interface RetryPolicy { /** @@ -241,14 +254,14 @@ export interface RetryPolicy { */ 'num_retries'?: (_google_protobuf_UInt32Value | null); /** - * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The - * same conditions documented for + * Specifies a non-zero upstream timeout per retry attempt (including the initial attempt). This + * parameter is optional. The same conditions documented for * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. * * .. note:: * * If left unspecified, Envoy will use the global - * :ref:`route timeout ` for the request. + * :ref:`route timeout ` for the request. * Consequently, when using a :ref:`5xx ` based * retry policy, a request that times out will not be retried as the total timeout budget * would have been exhausted. @@ -305,11 +318,39 @@ export interface RetryPolicy { * whenever a response includes the matching headers. */ 'rate_limited_retry_back_off'?: (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff | null); + /** + * Retry options predicates that will be applied prior to retrying a request. These predicates + * allow customizing request behavior between retries. + * [#comment: add [#extension-category: envoy.retry_options_predicates] when there are built-in extensions] + */ + 'retry_options_predicates'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; + /** + * Specifies an upstream idle timeout per retry attempt (including the initial attempt). This + * parameter is optional and if absent there is no per try idle timeout. The semantics of the per + * try idle timeout are similar to the + * :ref:`route idle timeout ` and + * :ref:`stream idle timeout + * ` + * both enforced by the HTTP connection manager. The difference is that this idle timeout + * is enforced by the router for each individual attempt and thus after all previous filters have + * run, as opposed to *before* all previous filters run for the other idle timeouts. This timeout + * is useful in cases in which total request timeout is bounded by a number of retries and a + * :ref:`per_try_timeout `, but + * there is a desire to ensure each try is making incremental progress. Note also that similar + * to :ref:`per_try_timeout `, + * this idle timeout does not start until after both the entire request has been received by the + * router *and* a connection pool connection has been obtained. Unlike + * :ref:`per_try_timeout `, + * the idle timer continues once the response starts streaming back to the downstream client. + * This ensures that response data continues to make progress without using one of the HTTP + * connection manager idle timeouts. + */ + 'per_try_idle_timeout'?: (_google_protobuf_Duration | null); } /** * HTTP retry :ref:`architecture overview `. - * [#next-free-field: 12] + * [#next-free-field: 14] */ export interface RetryPolicy__Output { /** @@ -325,14 +366,14 @@ export interface RetryPolicy__Output { */ 'num_retries': (_google_protobuf_UInt32Value__Output | null); /** - * Specifies a non-zero upstream timeout per retry attempt. This parameter is optional. The - * same conditions documented for + * Specifies a non-zero upstream timeout per retry attempt (including the initial attempt). This + * parameter is optional. The same conditions documented for * :ref:`config_http_filters_router_x-envoy-upstream-rq-per-try-timeout-ms` apply. * * .. note:: * * If left unspecified, Envoy will use the global - * :ref:`route timeout ` for the request. + * :ref:`route timeout ` for the request. * Consequently, when using a :ref:`5xx ` based * retry policy, a request that times out will not be retried as the total timeout budget * would have been exhausted. @@ -389,4 +430,32 @@ export interface RetryPolicy__Output { * whenever a response includes the matching headers. */ 'rate_limited_retry_back_off': (_envoy_config_route_v3_RetryPolicy_RateLimitedRetryBackOff__Output | null); + /** + * Retry options predicates that will be applied prior to retrying a request. These predicates + * allow customizing request behavior between retries. + * [#comment: add [#extension-category: envoy.retry_options_predicates] when there are built-in extensions] + */ + 'retry_options_predicates': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; + /** + * Specifies an upstream idle timeout per retry attempt (including the initial attempt). This + * parameter is optional and if absent there is no per try idle timeout. The semantics of the per + * try idle timeout are similar to the + * :ref:`route idle timeout ` and + * :ref:`stream idle timeout + * ` + * both enforced by the HTTP connection manager. The difference is that this idle timeout + * is enforced by the router for each individual attempt and thus after all previous filters have + * run, as opposed to *before* all previous filters run for the other idle timeouts. This timeout + * is useful in cases in which total request timeout is bounded by a number of retries and a + * :ref:`per_try_timeout `, but + * there is a desire to ensure each try is making incremental progress. Note also that similar + * to :ref:`per_try_timeout `, + * this idle timeout does not start until after both the entire request has been received by the + * router *and* a connection pool connection has been obtained. Unlike + * :ref:`per_try_timeout `, + * the idle timer continues once the response starts streaming back to the downstream client. + * This ensures that response data continues to make progress without using one of the HTTP + * connection manager idle timeouts. + */ + 'per_try_idle_timeout': (_google_protobuf_Duration__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts index 7bc223f82..d48b554d0 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Route.ts @@ -11,6 +11,7 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ import type { Tracing as _envoy_config_route_v3_Tracing, Tracing__Output as _envoy_config_route_v3_Tracing__Output } from '../../../../envoy/config/route/v3/Tracing'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; import type { FilterAction as _envoy_config_route_v3_FilterAction, FilterAction__Output as _envoy_config_route_v3_FilterAction__Output } from '../../../../envoy/config/route/v3/FilterAction'; +import type { NonForwardingAction as _envoy_config_route_v3_NonForwardingAction, NonForwardingAction__Output as _envoy_config_route_v3_NonForwardingAction__Output } from '../../../../envoy/config/route/v3/NonForwardingAction'; /** * A route is both a specification of how to match a request as well as an indication of what to do @@ -19,8 +20,8 @@ import type { FilterAction as _envoy_config_route_v3_FilterAction, FilterAction_ * .. attention:: * * Envoy supports routing on HTTP method via :ref:`header matching - * `. - * [#next-free-field: 18] + * `. + * [#next-free-field: 19] */ export interface Route { /** @@ -54,8 +55,8 @@ export interface Route { /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the - * enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on + * enclosing :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -63,8 +64,8 @@ export interface Route { /** * Specifies a set of headers that will be added to responses to requests * matching this route. Headers specified at this level are applied before - * headers from the enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including + * headers from the enclosing :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on * :ref:`custom request headers `. */ @@ -86,7 +87,7 @@ export interface Route { * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. * [#comment: An entry's value may be wrapped in a - * :ref:`FilterConfig` + * :ref:`FilterConfig` * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); @@ -107,13 +108,20 @@ export interface Route { 'per_request_buffer_limit_bytes'?: (_google_protobuf_UInt32Value | null); /** * [#not-implemented-hide:] - * If true, a filter will define the action (e.g., it could dynamically generate the - * RouteAction). + * A filter-defined action (e.g., it could dynamically generate the RouteAction). * [#comment: TODO(samflattery): Remove cleanup in route_fuzz_test.cc when * implemented] */ 'filter_action'?: (_envoy_config_route_v3_FilterAction | null); - 'action'?: "route"|"redirect"|"direct_response"|"filter_action"; + /** + * [#not-implemented-hide:] + * An action used when the route will generate a response directly, + * without forwarding to an upstream host. This will be used in non-proxy + * xDS clients like the gRPC server. It could also be used in the future + * in Envoy for a filter that directly generates responses for requests. + */ + 'non_forwarding_action'?: (_envoy_config_route_v3_NonForwardingAction | null); + 'action'?: "route"|"redirect"|"direct_response"|"filter_action"|"non_forwarding_action"; } /** @@ -123,8 +131,8 @@ export interface Route { * .. attention:: * * Envoy supports routing on HTTP method via :ref:`header matching - * `. - * [#next-free-field: 18] + * `. + * [#next-free-field: 19] */ export interface Route__Output { /** @@ -158,8 +166,8 @@ export interface Route__Output { /** * Specifies a set of headers that will be added to requests matching this * route. Headers specified at this level are applied before headers from the - * enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on + * enclosing :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -167,8 +175,8 @@ export interface Route__Output { /** * Specifies a set of headers that will be added to responses to requests * matching this route. Headers specified at this level are applied before - * headers from the enclosing :ref:`envoy_api_msg_config.route.v3.VirtualHost` and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including + * headers from the enclosing :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on * :ref:`custom request headers `. */ @@ -190,7 +198,7 @@ export interface Route__Output { * specific; see the :ref:`HTTP filter documentation ` for * if and how it is utilized. * [#comment: An entry's value may be wrapped in a - * :ref:`FilterConfig` + * :ref:`FilterConfig` * message to specify additional options.] */ 'typed_per_filter_config': ({[key: string]: _google_protobuf_Any__Output}); @@ -211,11 +219,18 @@ export interface Route__Output { 'per_request_buffer_limit_bytes': (_google_protobuf_UInt32Value__Output | null); /** * [#not-implemented-hide:] - * If true, a filter will define the action (e.g., it could dynamically generate the - * RouteAction). + * A filter-defined action (e.g., it could dynamically generate the RouteAction). * [#comment: TODO(samflattery): Remove cleanup in route_fuzz_test.cc when * implemented] */ 'filter_action'?: (_envoy_config_route_v3_FilterAction__Output | null); - 'action': "route"|"redirect"|"direct_response"|"filter_action"; + /** + * [#not-implemented-hide:] + * An action used when the route will generate a response directly, + * without forwarding to an upstream host. This will be used in non-proxy + * xDS clients like the gRPC server. It could also be used in the future + * in Envoy for a filter that directly generates responses for requests. + */ + 'non_forwarding_action'?: (_envoy_config_route_v3_NonForwardingAction__Output | null); + 'action': "route"|"redirect"|"direct_response"|"filter_action"|"non_forwarding_action"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts index 234aa25e0..43bd51723 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteAction.ts @@ -306,9 +306,9 @@ export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration { /** * Specifies the maximum duration allowed for streams on the route. If not specified, the value * from the :ref:`max_stream_duration - * ` field in + * ` field in * :ref:`HttpConnectionManager.common_http_protocol_options - * ` + * ` * is used. If this field is set explicitly to zero, any * HttpConnectionManager max_stream_duration timeout will be disabled for * this route. @@ -336,9 +336,9 @@ export interface _envoy_config_route_v3_RouteAction_MaxStreamDuration__Output { /** * Specifies the maximum duration allowed for streams on the route. If not specified, the value * from the :ref:`max_stream_duration - * ` field in + * ` field in * :ref:`HttpConnectionManager.common_http_protocol_options - * ` + * ` * is used. If this field is set explicitly to zero, any * HttpConnectionManager max_stream_duration timeout will be disabled for * this route. @@ -457,7 +457,7 @@ export interface _envoy_config_route_v3_RouteAction_RequestMirrorPolicy__Output * This overrides any enabled/disabled upgrade filter chain specified in the * HttpConnectionManager * :ref:`upgrade_configs - * ` + * ` * but does not affect any custom filter chain specified there. */ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig { @@ -475,7 +475,7 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig { * Configuration for sending data upstream as a raw data payload. This is used for * CONNECT requests, when forwarding CONNECT payload as raw TCP. * Note that CONNECT support is currently considered alpha in Envoy. - * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + * [#comment: TODO(htuch): Replace the above comment with an alpha tag.] */ 'connect_config'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig | null); } @@ -485,7 +485,7 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig { * This overrides any enabled/disabled upgrade filter chain specified in the * HttpConnectionManager * :ref:`upgrade_configs - * ` + * ` * but does not affect any custom filter chain specified there. */ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig__Output { @@ -503,13 +503,13 @@ export interface _envoy_config_route_v3_RouteAction_UpgradeConfig__Output { * Configuration for sending data upstream as a raw data payload. This is used for * CONNECT requests, when forwarding CONNECT payload as raw TCP. * Note that CONNECT support is currently considered alpha in Envoy. - * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + * [#comment: TODO(htuch): Replace the above comment with an alpha tag.] */ 'connect_config': (_envoy_config_route_v3_RouteAction_UpgradeConfig_ConnectConfig__Output | null); } /** - * [#next-free-field: 37] + * [#next-free-field: 38] */ export interface RouteAction { /** @@ -545,7 +545,7 @@ export interface RouteAction { * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints * in the upstream cluster with metadata matching what's set in this field will be considered * for load balancing. If using :ref:`weighted_clusters - * `, metadata will be merged, with values + * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ 'metadata_match'?: (_envoy_config_core_v3_Metadata | null); @@ -557,16 +557,16 @@ export interface RouteAction { * ` header. * * Only one of *prefix_rewrite* or - * :ref:`regex_rewrite ` + * :ref:`regex_rewrite ` * may be specified. * * .. attention:: * * Pay careful attention to the use of trailing slashes in the - * :ref:`route's match ` prefix value. + * :ref:`route's match ` prefix value. * Stripping a prefix from a path requires multiple Routes to handle all cases. For example, * rewriting * /prefix* to * /* and * /prefix/etc* to * /etc* cannot be done in a single - * :ref:`Route `, as shown by the below config entries: + * :ref:`Route `, as shown by the below config entries: * * .. code-block:: yaml * @@ -628,7 +628,7 @@ export interface RouteAction { /** * Specifies if the rate limit filter should include the virtual host rate * limits. By default, if the route configured rate limits, the virtual host - * :ref:`rate_limits ` are not applied to the + * :ref:`rate_limits ` are not applied to the * request. * * This field is deprecated. Please use :ref:`vh_rate_limits ` @@ -659,15 +659,15 @@ export interface RouteAction { */ 'cluster_not_found_response_code'?: (_envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode | keyof typeof _envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode); /** - * Deprecated by :ref:`grpc_timeout_header_max ` + * Deprecated by :ref:`grpc_timeout_header_max ` * If present, and the request is a gRPC request, use the * `grpc-timeout header `_, * or its default value (infinity) instead of - * :ref:`timeout `, but limit the applied timeout + * :ref:`timeout `, but limit the applied timeout * to the maximum value specified here. If configured as 0, the maximum allowed timeout for * gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used * and gRPC requests time out like any other requests using - * :ref:`timeout ` or its default. + * :ref:`timeout ` or its default. * This can be used to prevent unexpected upstream request timeouts due to potentially long * time gaps between gRPC request and response in gRPC streaming mode. * @@ -684,14 +684,14 @@ export interface RouteAction { /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout - * ` + * ` * will still apply. A value of 0 will completely disable the route's idle timeout, even if a * connection manager stream idle timeout is configured. * * The idle timeout is distinct to :ref:`timeout - * `, which provides an upper bound + * `, which provides an upper bound * on the upstream response time; :ref:`idle_timeout - * ` instead bounds the amount + * ` instead bounds the amount * of time the request's stream may be idle. * * After header decoding, the idle timeout will apply on downstream and @@ -703,7 +703,7 @@ export interface RouteAction { * * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" * is configured, this timeout is scaled according to the value for - * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. */ 'idle_timeout'?: (_google_protobuf_Duration | null); 'upgrade_configs'?: (_envoy_config_route_v3_RouteAction_UpgradeConfig)[]; @@ -715,7 +715,7 @@ export interface RouteAction { */ 'hedge_policy'?: (_envoy_config_route_v3_HedgePolicy | null); /** - * Deprecated by :ref:`grpc_timeout_header_offset `. + * Deprecated by :ref:`grpc_timeout_header_offset `. * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting * the provided duration from the header. This is useful in allowing Envoy to set its global * timeout to be less than that of the deadline imposed by the calling client, which makes it more @@ -747,15 +747,15 @@ export interface RouteAction { /** * An internal redirect is handled, iff the number of previous internal redirects that a * downstream request has encountered is lower than this value, and - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * is set to :ref:`HANDLE_INTERNAL_REDIRECT - * ` + * ` * In the case where a downstream request is bounced among multiple routes by internal redirect, * the first route that hits this threshold, or has - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * set to * :ref:`PASS_THROUGH_INTERNAL_REDIRECT - * ` + * ` * will pass the redirect back to downstream. * * If not specified, at most one redirect will be followed. @@ -771,7 +771,7 @@ export interface RouteAction { * before the rewrite into the :ref:`x-envoy-original-path * ` header. * - * Only one of :ref:`prefix_rewrite ` + * Only one of :ref:`prefix_rewrite ` * or *regex_rewrite* may be specified. * * Examples using Google's `RE2 `_ engine: @@ -796,7 +796,7 @@ export interface RouteAction { * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take * precedence over the virtual host level retry policy entirely (e.g.: policies are not merged, - * most internal one becomes the enforced policy). :ref:`Retry policy ` + * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ 'retry_policy_typed_config'?: (_google_protobuf_Any | null); @@ -804,7 +804,7 @@ export interface RouteAction { * If present, Envoy will try to follow an upstream redirect response instead of proxying the * response back to the downstream. An upstream redirect response is defined * by :ref:`redirect_response_codes - * `. + * `. */ 'internal_redirect_policy'?: (_envoy_config_route_v3_InternalRedirectPolicy | null); /** @@ -829,12 +829,21 @@ export interface RouteAction { * Specifies the maximum stream duration for this route. */ 'max_stream_duration'?: (_envoy_config_route_v3_RouteAction_MaxStreamDuration | null); - 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"; + /** + * [#not-implemented-hide:] + * Name of the cluster specifier plugin to use to determine the cluster for + * requests on this route. The plugin name must be defined in the associated + * :ref:`envoy_v3_api_field_config.route.v3.RouteConfiguration.cluster_specifier_plugins` + * in the + * :ref:`envoy_v3_api_field_config.core.v3.TypedExtensionConfig.name` field. + */ + 'cluster_specifier_plugin'?: (string); + 'cluster_specifier'?: "cluster"|"cluster_header"|"weighted_clusters"|"cluster_specifier_plugin"; 'host_rewrite_specifier'?: "host_rewrite_literal"|"auto_host_rewrite"|"host_rewrite_header"|"host_rewrite_path_regex"; } /** - * [#next-free-field: 37] + * [#next-free-field: 38] */ export interface RouteAction__Output { /** @@ -870,7 +879,7 @@ export interface RouteAction__Output { * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints * in the upstream cluster with metadata matching what's set in this field will be considered * for load balancing. If using :ref:`weighted_clusters - * `, metadata will be merged, with values + * `, metadata will be merged, with values * provided there taking precedence. The filter name should be specified as *envoy.lb*. */ 'metadata_match': (_envoy_config_core_v3_Metadata__Output | null); @@ -882,16 +891,16 @@ export interface RouteAction__Output { * ` header. * * Only one of *prefix_rewrite* or - * :ref:`regex_rewrite ` + * :ref:`regex_rewrite ` * may be specified. * * .. attention:: * * Pay careful attention to the use of trailing slashes in the - * :ref:`route's match ` prefix value. + * :ref:`route's match ` prefix value. * Stripping a prefix from a path requires multiple Routes to handle all cases. For example, * rewriting * /prefix* to * /* and * /prefix/etc* to * /etc* cannot be done in a single - * :ref:`Route `, as shown by the below config entries: + * :ref:`Route `, as shown by the below config entries: * * .. code-block:: yaml * @@ -953,7 +962,7 @@ export interface RouteAction__Output { /** * Specifies if the rate limit filter should include the virtual host rate * limits. By default, if the route configured rate limits, the virtual host - * :ref:`rate_limits ` are not applied to the + * :ref:`rate_limits ` are not applied to the * request. * * This field is deprecated. Please use :ref:`vh_rate_limits ` @@ -984,15 +993,15 @@ export interface RouteAction__Output { */ 'cluster_not_found_response_code': (keyof typeof _envoy_config_route_v3_RouteAction_ClusterNotFoundResponseCode); /** - * Deprecated by :ref:`grpc_timeout_header_max ` + * Deprecated by :ref:`grpc_timeout_header_max ` * If present, and the request is a gRPC request, use the * `grpc-timeout header `_, * or its default value (infinity) instead of - * :ref:`timeout `, but limit the applied timeout + * :ref:`timeout `, but limit the applied timeout * to the maximum value specified here. If configured as 0, the maximum allowed timeout for * gRPC requests is infinity. If not configured at all, the `grpc-timeout` header is not used * and gRPC requests time out like any other requests using - * :ref:`timeout ` or its default. + * :ref:`timeout ` or its default. * This can be used to prevent unexpected upstream request timeouts due to potentially long * time gaps between gRPC request and response in gRPC streaming mode. * @@ -1009,14 +1018,14 @@ export interface RouteAction__Output { /** * Specifies the idle timeout for the route. If not specified, there is no per-route idle timeout, * although the connection manager wide :ref:`stream_idle_timeout - * ` + * ` * will still apply. A value of 0 will completely disable the route's idle timeout, even if a * connection manager stream idle timeout is configured. * * The idle timeout is distinct to :ref:`timeout - * `, which provides an upper bound + * `, which provides an upper bound * on the upstream response time; :ref:`idle_timeout - * ` instead bounds the amount + * ` instead bounds the amount * of time the request's stream may be idle. * * After header decoding, the idle timeout will apply on downstream and @@ -1028,7 +1037,7 @@ export interface RouteAction__Output { * * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" * is configured, this timeout is scaled according to the value for - * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. */ 'idle_timeout': (_google_protobuf_Duration__Output | null); 'upgrade_configs': (_envoy_config_route_v3_RouteAction_UpgradeConfig__Output)[]; @@ -1040,7 +1049,7 @@ export interface RouteAction__Output { */ 'hedge_policy': (_envoy_config_route_v3_HedgePolicy__Output | null); /** - * Deprecated by :ref:`grpc_timeout_header_offset `. + * Deprecated by :ref:`grpc_timeout_header_offset `. * If present, Envoy will adjust the timeout provided by the `grpc-timeout` header by subtracting * the provided duration from the header. This is useful in allowing Envoy to set its global * timeout to be less than that of the deadline imposed by the calling client, which makes it more @@ -1072,15 +1081,15 @@ export interface RouteAction__Output { /** * An internal redirect is handled, iff the number of previous internal redirects that a * downstream request has encountered is lower than this value, and - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * is set to :ref:`HANDLE_INTERNAL_REDIRECT - * ` + * ` * In the case where a downstream request is bounced among multiple routes by internal redirect, * the first route that hits this threshold, or has - * :ref:`internal_redirect_action ` + * :ref:`internal_redirect_action ` * set to * :ref:`PASS_THROUGH_INTERNAL_REDIRECT - * ` + * ` * will pass the redirect back to downstream. * * If not specified, at most one redirect will be followed. @@ -1096,7 +1105,7 @@ export interface RouteAction__Output { * before the rewrite into the :ref:`x-envoy-original-path * ` header. * - * Only one of :ref:`prefix_rewrite ` + * Only one of :ref:`prefix_rewrite ` * or *regex_rewrite* may be specified. * * Examples using Google's `RE2 `_ engine: @@ -1121,7 +1130,7 @@ export interface RouteAction__Output { * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that if this is set, it'll take * precedence over the virtual host level retry policy entirely (e.g.: policies are not merged, - * most internal one becomes the enforced policy). :ref:`Retry policy ` + * most internal one becomes the enforced policy). :ref:`Retry policy ` * should not be set if this field is used. */ 'retry_policy_typed_config': (_google_protobuf_Any__Output | null); @@ -1129,7 +1138,7 @@ export interface RouteAction__Output { * If present, Envoy will try to follow an upstream redirect response instead of proxying the * response back to the downstream. An upstream redirect response is defined * by :ref:`redirect_response_codes - * `. + * `. */ 'internal_redirect_policy': (_envoy_config_route_v3_InternalRedirectPolicy__Output | null); /** @@ -1154,6 +1163,15 @@ export interface RouteAction__Output { * Specifies the maximum stream duration for this route. */ 'max_stream_duration': (_envoy_config_route_v3_RouteAction_MaxStreamDuration__Output | null); - 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"; + /** + * [#not-implemented-hide:] + * Name of the cluster specifier plugin to use to determine the cluster for + * requests on this route. The plugin name must be defined in the associated + * :ref:`envoy_v3_api_field_config.route.v3.RouteConfiguration.cluster_specifier_plugins` + * in the + * :ref:`envoy_v3_api_field_config.core.v3.TypedExtensionConfig.name` field. + */ + 'cluster_specifier_plugin'?: (string); + 'cluster_specifier': "cluster"|"cluster_header"|"weighted_clusters"|"cluster_specifier_plugin"; 'host_rewrite_specifier': "host_rewrite_literal"|"auto_host_rewrite"|"host_rewrite_header"|"host_rewrite_path_regex"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts index ebb3c3419..516f4b06b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteConfiguration.ts @@ -5,16 +5,17 @@ import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, Head import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; import type { Vhds as _envoy_config_route_v3_Vhds, Vhds__Output as _envoy_config_route_v3_Vhds__Output } from '../../../../envoy/config/route/v3/Vhds'; import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; +import type { ClusterSpecifierPlugin as _envoy_config_route_v3_ClusterSpecifierPlugin, ClusterSpecifierPlugin__Output as _envoy_config_route_v3_ClusterSpecifierPlugin__Output } from '../../../../envoy/config/route/v3/ClusterSpecifierPlugin'; /** - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface RouteConfiguration { /** * The name of the route configuration. For example, it might match * :ref:`route_config_name - * ` in - * :ref:`envoy_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. + * ` in + * :ref:`envoy_v3_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. */ 'name'?: (string); /** @@ -31,8 +32,8 @@ export interface RouteConfiguration { /** * Specifies a list of HTTP headers that should be added to each response that * the connection manager encodes. Headers specified at this level are applied - * after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or - * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on + * after headers from any enclosed :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -45,8 +46,8 @@ export interface RouteConfiguration { /** * Specifies a list of HTTP headers that should be added to each request * routed by the HTTP connection manager. Headers specified at this level are - * applied after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or - * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on + * applied after headers from any enclosed :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -59,10 +60,10 @@ export interface RouteConfiguration { * route table will load and the router filter will return a 404 if the route * is selected at runtime. This setting defaults to true if the route table * is statically defined via the :ref:`route_config - * ` + * ` * option. This setting default to false if the route table is loaded dynamically via the * :ref:`rds - * ` + * ` * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ @@ -96,28 +97,35 @@ export interface RouteConfiguration { 'most_specific_header_mutations_wins'?: (boolean); /** * The maximum bytes of the response :ref:`direct response body - * ` size. If not specified the default + * ` size. If not specified the default * is 4096. * * .. warning:: * * Envoy currently holds the content of :ref:`direct response body - * ` in memory. Be careful setting + * ` in memory. Be careful setting * this to be larger than the default 4KB, since the allocated memory for direct response body * is not subject to data plane buffering controls. */ 'max_direct_response_body_size_bytes'?: (_google_protobuf_UInt32Value | null); + /** + * [#not-implemented-hide:] + * A list of plugins and their configurations which may be used by a + * :ref:`envoy_v3_api_field_config.route.v3.RouteAction.cluster_specifier_plugin` + * within the route. All *extension.name* fields in this list must be unique. + */ + 'cluster_specifier_plugins'?: (_envoy_config_route_v3_ClusterSpecifierPlugin)[]; } /** - * [#next-free-field: 12] + * [#next-free-field: 13] */ export interface RouteConfiguration__Output { /** * The name of the route configuration. For example, it might match * :ref:`route_config_name - * ` in - * :ref:`envoy_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. + * ` in + * :ref:`envoy_v3_api_msg_extensions.filters.network.http_connection_manager.v3.Rds`. */ 'name': (string); /** @@ -134,8 +142,8 @@ export interface RouteConfiguration__Output { /** * Specifies a list of HTTP headers that should be added to each response that * the connection manager encodes. Headers specified at this level are applied - * after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or - * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on + * after headers from any enclosed :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -148,8 +156,8 @@ export interface RouteConfiguration__Output { /** * Specifies a list of HTTP headers that should be added to each request * routed by the HTTP connection manager. Headers specified at this level are - * applied after headers from any enclosed :ref:`envoy_api_msg_config.route.v3.VirtualHost` or - * :ref:`envoy_api_msg_config.route.v3.RouteAction`. For more information, including details on + * applied after headers from any enclosed :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost` or + * :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -162,10 +170,10 @@ export interface RouteConfiguration__Output { * route table will load and the router filter will return a 404 if the route * is selected at runtime. This setting defaults to true if the route table * is statically defined via the :ref:`route_config - * ` + * ` * option. This setting default to false if the route table is loaded dynamically via the * :ref:`rds - * ` + * ` * option. Users may wish to override the default behavior in certain cases (for example when * using CDS with a static route table). */ @@ -199,15 +207,22 @@ export interface RouteConfiguration__Output { 'most_specific_header_mutations_wins': (boolean); /** * The maximum bytes of the response :ref:`direct response body - * ` size. If not specified the default + * ` size. If not specified the default * is 4096. * * .. warning:: * * Envoy currently holds the content of :ref:`direct response body - * ` in memory. Be careful setting + * ` in memory. Be careful setting * this to be larger than the default 4KB, since the allocated memory for direct response body * is not subject to data plane buffering controls. */ 'max_direct_response_body_size_bytes': (_google_protobuf_UInt32Value__Output | null); + /** + * [#not-implemented-hide:] + * A list of plugins and their configurations which may be used by a + * :ref:`envoy_v3_api_field_config.route.v3.RouteAction.cluster_specifier_plugin` + * within the route. All *extension.name* fields in this list must be unique. + */ + 'cluster_specifier_plugins': (_envoy_config_route_v3_ClusterSpecifierPlugin__Output)[]; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts index ddf44da2f..9d872ed18 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/RouteMatch.ts @@ -5,6 +5,7 @@ import type { HeaderMatcher as _envoy_config_route_v3_HeaderMatcher, HeaderMatch import type { QueryParameterMatcher as _envoy_config_route_v3_QueryParameterMatcher, QueryParameterMatcher__Output as _envoy_config_route_v3_QueryParameterMatcher__Output } from '../../../../envoy/config/route/v3/QueryParameterMatcher'; import type { RuntimeFractionalPercent as _envoy_config_core_v3_RuntimeFractionalPercent, RuntimeFractionalPercent__Output as _envoy_config_core_v3_RuntimeFractionalPercent__Output } from '../../../../envoy/config/core/v3/RuntimeFractionalPercent'; import type { RegexMatcher as _envoy_type_matcher_v3_RegexMatcher, RegexMatcher__Output as _envoy_type_matcher_v3_RegexMatcher__Output } from '../../../../envoy/type/matcher/v3/RegexMatcher'; +import type { MetadataMatcher as _envoy_type_matcher_v3_MetadataMatcher, MetadataMatcher__Output as _envoy_type_matcher_v3_MetadataMatcher__Output } from '../../../../envoy/type/matcher/v3/MetadataMatcher'; /** * An extensible message for matching CONNECT requests. @@ -51,7 +52,7 @@ export interface _envoy_config_route_v3_RouteMatch_TlsContextMatchOptions__Outpu } /** - * [#next-free-field: 13] + * [#next-free-field: 14] */ export interface RouteMatch { /** @@ -66,7 +67,7 @@ export interface RouteMatch { 'path'?: (string); /** * Indicates that prefix/path matching should be case sensitive. The default - * is true. + * is true. Ignored for safe_regex matching. */ 'case_sensitive'?: (_google_protobuf_BoolValue | null); /** @@ -83,6 +84,14 @@ export interface RouteMatch { * against all the specified query parameters. If the number of specified * query parameters is nonzero, they all must match the *path* header's * query string for a match to occur. + * + * .. note:: + * + * If query parameters are used to pass request message fields when + * `grpc_json_transcoder `_ + * is used, the transcoded message fields maybe different. The query parameters are + * url encoded, but the message fields are not. For example, if a query + * parameter is "foo%20bar", the message field will be "foo bar". */ 'query_parameters'?: (_envoy_config_route_v3_QueryParameterMatcher)[]; /** @@ -141,14 +150,21 @@ export interface RouteMatch { * where Extended CONNECT requests may have a path, the path matchers will work if * there is a path present. * Note that CONNECT support is currently considered alpha in Envoy. - * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + * [#comment: TODO(htuch): Replace the above comment with an alpha tag.] */ 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher | null); + /** + * Specifies a set of dynamic metadata matchers on which the route should match. + * The router will check the dynamic metadata against all the specified dynamic metadata matchers. + * If the number of specified dynamic metadata matchers is nonzero, they all must match the + * dynamic metadata for a match to occur. + */ + 'dynamic_metadata'?: (_envoy_type_matcher_v3_MetadataMatcher)[]; 'path_specifier'?: "prefix"|"path"|"safe_regex"|"connect_matcher"; } /** - * [#next-free-field: 13] + * [#next-free-field: 14] */ export interface RouteMatch__Output { /** @@ -163,7 +179,7 @@ export interface RouteMatch__Output { 'path'?: (string); /** * Indicates that prefix/path matching should be case sensitive. The default - * is true. + * is true. Ignored for safe_regex matching. */ 'case_sensitive': (_google_protobuf_BoolValue__Output | null); /** @@ -180,6 +196,14 @@ export interface RouteMatch__Output { * against all the specified query parameters. If the number of specified * query parameters is nonzero, they all must match the *path* header's * query string for a match to occur. + * + * .. note:: + * + * If query parameters are used to pass request message fields when + * `grpc_json_transcoder `_ + * is used, the transcoded message fields maybe different. The query parameters are + * url encoded, but the message fields are not. For example, if a query + * parameter is "foo%20bar", the message field will be "foo bar". */ 'query_parameters': (_envoy_config_route_v3_QueryParameterMatcher__Output)[]; /** @@ -238,8 +262,15 @@ export interface RouteMatch__Output { * where Extended CONNECT requests may have a path, the path matchers will work if * there is a path present. * Note that CONNECT support is currently considered alpha in Envoy. - * [#comment:TODO(htuch): Replace the above comment with an alpha tag. + * [#comment: TODO(htuch): Replace the above comment with an alpha tag.] */ 'connect_matcher'?: (_envoy_config_route_v3_RouteMatch_ConnectMatcher__Output | null); + /** + * Specifies a set of dynamic metadata matchers on which the route should match. + * The router will check the dynamic metadata against all the specified dynamic metadata matchers. + * If the number of specified dynamic metadata matchers is nonzero, they all must match the + * dynamic metadata for a match to occur. + */ + 'dynamic_metadata': (_envoy_type_matcher_v3_MetadataMatcher__Output)[]; 'path_specifier': "prefix"|"path"|"safe_regex"|"connect_matcher"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts index 74b5fe43d..5865eadd3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/ScopedRouteConfiguration.ts @@ -19,7 +19,7 @@ export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment__O /** * Specifies a key which is matched against the output of the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * specified in the HttpConnectionManager. The matching is done per HTTP * request and is dependent on the order of the fragments contained in the * Key. @@ -28,14 +28,14 @@ export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key { /** * The ordered set of fragments to match against. The order must match the * fragments in the corresponding - * :ref:`scope_key_builder`. + * :ref:`scope_key_builder`. */ 'fragments'?: (_envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment)[]; } /** * Specifies a key which is matched against the output of the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * specified in the HttpConnectionManager. The matching is done per HTTP * request and is dependent on the order of the fragments contained in the * Key. @@ -44,20 +44,20 @@ export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key__Output { /** * The ordered set of fragments to match against. The order must match the * fragments in the corresponding - * :ref:`scope_key_builder`. + * :ref:`scope_key_builder`. */ 'fragments': (_envoy_config_route_v3_ScopedRouteConfiguration_Key_Fragment__Output)[]; } /** * Specifies a routing scope, which associates a - * :ref:`Key` to a - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` (identified by its resource name). + * :ref:`Key` to a + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration` (identified by its resource name). * * The HTTP connection manager builds up a table consisting of these Key to * RouteConfiguration mappings, and looks up the RouteConfiguration to use per * request according to the algorithm specified in the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * assigned to the HttpConnectionManager. * * For example, with the following configurations (in YAML): @@ -79,7 +79,7 @@ export interface _envoy_config_route_v3_ScopedRouteConfiguration_Key__Output { * key: vip * * ScopedRouteConfiguration resources (specified statically via - * :ref:`scoped_route_configurations_list` + * :ref:`scoped_route_configurations_list` * or obtained dynamically via SRDS): * * .. code:: @@ -115,8 +115,8 @@ export interface ScopedRouteConfiguration { */ 'name'?: (string); /** - * The resource name to use for a :ref:`envoy_api_msg_service.discovery.v3.DiscoveryRequest` to an - * RDS server to fetch the :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` associated + * The resource name to use for a :ref:`envoy_v3_api_msg_service.discovery.v3.DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration` associated * with this scope. */ 'route_configuration_name'?: (string); @@ -132,13 +132,13 @@ export interface ScopedRouteConfiguration { /** * Specifies a routing scope, which associates a - * :ref:`Key` to a - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` (identified by its resource name). + * :ref:`Key` to a + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration` (identified by its resource name). * * The HTTP connection manager builds up a table consisting of these Key to * RouteConfiguration mappings, and looks up the RouteConfiguration to use per * request according to the algorithm specified in the - * :ref:`scope_key_builder` + * :ref:`scope_key_builder` * assigned to the HttpConnectionManager. * * For example, with the following configurations (in YAML): @@ -160,7 +160,7 @@ export interface ScopedRouteConfiguration { * key: vip * * ScopedRouteConfiguration resources (specified statically via - * :ref:`scoped_route_configurations_list` + * :ref:`scoped_route_configurations_list` * or obtained dynamically via SRDS): * * .. code:: @@ -196,8 +196,8 @@ export interface ScopedRouteConfiguration__Output { */ 'name': (string); /** - * The resource name to use for a :ref:`envoy_api_msg_service.discovery.v3.DiscoveryRequest` to an - * RDS server to fetch the :ref:`envoy_api_msg_config.route.v3.RouteConfiguration` associated + * The resource name to use for a :ref:`envoy_v3_api_msg_service.discovery.v3.DiscoveryRequest` to an + * RDS server to fetch the :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration` associated * with this scope. */ 'route_configuration_name': (string); diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts index e1a9220d7..962e9d51a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/Tracing.ts @@ -35,7 +35,7 @@ export interface Tracing { /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration - * ` + * ` * configured in the HTTP connection manager. If two tags with the same name are configured * each in the HTTP connection manager and the route level, the one configured here takes * priority. @@ -75,7 +75,7 @@ export interface Tracing__Output { /** * A list of custom tags with unique tag name to create tags for the active span. * It will take effect after merging with the :ref:`corresponding configuration - * ` + * ` * configured in the HTTP connection manager. If two tags with the same name are configured * each in the HTTP connection manager and the route level, the one configured here takes * priority. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts index 1d3fb2309..017900ed9 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/VirtualHost.ts @@ -87,8 +87,8 @@ export interface VirtualHost { /** * Specifies a list of HTTP headers that should be added to each request * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_v3_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -100,8 +100,8 @@ export interface VirtualHost { /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_v3_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -124,7 +124,7 @@ export interface VirtualHost { * will see the attempt count as perceived by the second Envoy. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. * * [#next-major-version: rename to include_attempt_count_in_request.] */ @@ -136,7 +136,7 @@ export interface VirtualHost { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. * [#comment: An entry's value may be wrapped in a - * :ref:`FilterConfig` + * :ref:`FilterConfig` * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); @@ -166,14 +166,14 @@ export interface VirtualHost { * will see the attempt count as perceived by the Envoy closest upstream from itself. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. */ 'include_attempt_count_in_response'?: (boolean); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that setting a route level entry * will take precedence over this config and it'll be treated independently (e.g.: values are not - * inherited). :ref:`Retry policy ` should not be + * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ 'retry_policy_typed_config'?: (_google_protobuf_Any | null); @@ -237,8 +237,8 @@ export interface VirtualHost__Output { /** * Specifies a list of HTTP headers that should be added to each request * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_v3_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -250,8 +250,8 @@ export interface VirtualHost__Output { /** * Specifies a list of HTTP headers that should be added to each response * handled by this virtual host. Headers specified at this level are applied - * after headers from enclosed :ref:`envoy_api_msg_config.route.v3.Route` and before headers from the - * enclosing :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including + * after headers from enclosed :ref:`envoy_v3_api_msg_config.route.v3.Route` and before headers from the + * enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including * details on header value syntax, see the documentation on :ref:`custom request headers * `. */ @@ -274,7 +274,7 @@ export interface VirtualHost__Output { * will see the attempt count as perceived by the second Envoy. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. * * [#next-major-version: rename to include_attempt_count_in_request.] */ @@ -286,7 +286,7 @@ export interface VirtualHost__Output { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. * [#comment: An entry's value may be wrapped in a - * :ref:`FilterConfig` + * :ref:`FilterConfig` * message to specify additional options.] */ 'typed_per_filter_config': ({[key: string]: _google_protobuf_Any__Output}); @@ -316,14 +316,14 @@ export interface VirtualHost__Output { * will see the attempt count as perceived by the Envoy closest upstream from itself. Defaults to false. * This header is unaffected by the * :ref:`suppress_envoy_headers - * ` flag. + * ` flag. */ 'include_attempt_count_in_response': (boolean); /** * [#not-implemented-hide:] * Specifies the configuration for retry policy extension. Note that setting a route level entry * will take precedence over this config and it'll be treated independently (e.g.: values are not - * inherited). :ref:`Retry policy ` should not be + * inherited). :ref:`Retry policy ` should not be * set if this field is used. */ 'retry_policy_typed_config': (_google_protobuf_Any__Output | null); diff --git a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts index 02edc0243..e734073be 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/route/v3/WeightedCluster.ts @@ -6,17 +6,37 @@ import type { HeaderValueOption as _envoy_config_core_v3_HeaderValueOption, Head import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; /** - * [#next-free-field: 11] + * [#next-free-field: 13] */ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight { /** + * Only one of *name* and *cluster_header* may be specified. + * [#next-major-version: Need to add back the validation rule: (validate.rules).string = {min_len: 1}] * Name of the upstream cluster. The cluster must exist in the * :ref:`cluster manager configuration `. */ 'name'?: (string); + /** + * Only one of *name* and *cluster_header* may be specified. + * [#next-major-version: Need to add back the validation rule: (validate.rules).string = {min_len: 1 }] + * Envoy will determine the cluster to route to by reading the value of the + * HTTP header named by cluster_header from the request headers. If the + * header is not found or the referenced cluster does not exist, Envoy will + * return a 404 response. + * + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 + * *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. + */ + 'cluster_header'?: (string); /** * An integer between 0 and :ref:`total_weight - * `. When a request matches the route, + * `. When a request matches the route, * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ @@ -25,38 +45,38 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight { * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for * load balancing. Note that this will be merged with what's provided in - * :ref:`RouteAction.metadata_match `, with + * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ 'metadata_match'?: (_envoy_config_core_v3_Metadata | null); /** * Specifies a list of headers to be added to requests when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on + * :ref:`envoy_v3_api_msg_config.route.v3.Route`, :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ 'request_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of HTTP headers that should be removed from each request when - * this cluster is selected through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * this cluster is selected through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. */ 'request_headers_to_remove'?: (string)[]; /** * Specifies a list of headers to be added to responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on + * :ref:`envoy_v3_api_msg_config.route.v3.Route`, :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ 'response_headers_to_add'?: (_envoy_config_core_v3_HeaderValueOption)[]; /** * Specifies a list of headers to be removed from responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. */ 'response_headers_to_remove'?: (string)[]; /** @@ -66,24 +86,50 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. * [#comment: An entry's value may be wrapped in a - * :ref:`FilterConfig` + * :ref:`FilterConfig` * message to specify additional options.] */ 'typed_per_filter_config'?: ({[key: string]: _google_protobuf_Any}); + /** + * Indicates that during forwarding, the host header will be swapped with + * this value. + */ + 'host_rewrite_literal'?: (string); + 'host_rewrite_specifier'?: "host_rewrite_literal"; } /** - * [#next-free-field: 11] + * [#next-free-field: 13] */ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { /** + * Only one of *name* and *cluster_header* may be specified. + * [#next-major-version: Need to add back the validation rule: (validate.rules).string = {min_len: 1}] * Name of the upstream cluster. The cluster must exist in the * :ref:`cluster manager configuration `. */ 'name': (string); + /** + * Only one of *name* and *cluster_header* may be specified. + * [#next-major-version: Need to add back the validation rule: (validate.rules).string = {min_len: 1 }] + * Envoy will determine the cluster to route to by reading the value of the + * HTTP header named by cluster_header from the request headers. If the + * header is not found or the referenced cluster does not exist, Envoy will + * return a 404 response. + * + * .. attention:: + * + * Internally, Envoy always uses the HTTP/2 *:authority* header to represent the HTTP/1 + * *Host* header. Thus, if attempting to match on *Host*, match on *:authority* instead. + * + * .. note:: + * + * If the header appears multiple times only the first value is used. + */ + 'cluster_header': (string); /** * An integer between 0 and :ref:`total_weight - * `. When a request matches the route, + * `. When a request matches the route, * the choice of an upstream cluster is determined by its weight. The sum of weights across all * entries in the clusters array must add up to the total_weight, which defaults to 100. */ @@ -92,38 +138,38 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { * Optional endpoint metadata match criteria used by the subset load balancer. Only endpoints in * the upstream cluster with metadata matching what is set in this field will be considered for * load balancing. Note that this will be merged with what's provided in - * :ref:`RouteAction.metadata_match `, with + * :ref:`RouteAction.metadata_match `, with * values here taking precedence. The filter name should be specified as *envoy.lb*. */ 'metadata_match': (_envoy_config_core_v3_Metadata__Output | null); /** * Specifies a list of headers to be added to requests when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on + * :ref:`envoy_v3_api_msg_config.route.v3.Route`, :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ 'request_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of HTTP headers that should be removed from each request when - * this cluster is selected through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * this cluster is selected through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. */ 'request_headers_to_remove': (string)[]; /** * Specifies a list of headers to be added to responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. * Headers specified at this level are applied before headers from the enclosing - * :ref:`envoy_api_msg_config.route.v3.Route`, :ref:`envoy_api_msg_config.route.v3.VirtualHost`, and - * :ref:`envoy_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on + * :ref:`envoy_v3_api_msg_config.route.v3.Route`, :ref:`envoy_v3_api_msg_config.route.v3.VirtualHost`, and + * :ref:`envoy_v3_api_msg_config.route.v3.RouteConfiguration`. For more information, including details on * header value syntax, see the documentation on :ref:`custom request headers * `. */ 'response_headers_to_add': (_envoy_config_core_v3_HeaderValueOption__Output)[]; /** * Specifies a list of headers to be removed from responses when this cluster is selected - * through the enclosing :ref:`envoy_api_msg_config.route.v3.RouteAction`. + * through the enclosing :ref:`envoy_v3_api_msg_config.route.v3.RouteAction`. */ 'response_headers_to_remove': (string)[]; /** @@ -133,16 +179,22 @@ export interface _envoy_config_route_v3_WeightedCluster_ClusterWeight__Output { * specific; see the :ref:`HTTP filter documentation ` * for if and how it is utilized. * [#comment: An entry's value may be wrapped in a - * :ref:`FilterConfig` + * :ref:`FilterConfig` * message to specify additional options.] */ 'typed_per_filter_config': ({[key: string]: _google_protobuf_Any__Output}); + /** + * Indicates that during forwarding, the host header will be swapped with + * this value. + */ + 'host_rewrite_literal'?: (string); + 'host_rewrite_specifier': "host_rewrite_literal"; } /** - * Compared to the :ref:`cluster ` field that specifies a + * Compared to the :ref:`cluster ` field that specifies a * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of + * ` option allows for specification of * multiple upstream clusters along with weights that indicate the percentage of * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the * weights. @@ -171,9 +223,9 @@ export interface WeightedCluster { } /** - * Compared to the :ref:`cluster ` field that specifies a + * Compared to the :ref:`cluster ` field that specifies a * single upstream cluster as the target of a request, the :ref:`weighted_clusters - * ` option allows for specification of + * ` option allows for specification of * multiple upstream clusters along with weights that indicate the percentage of * traffic to be forwarded to each cluster. The router selects an upstream cluster based on the * weights. diff --git a/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts b/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts index 95b161939..9b9859bc5 100644 --- a/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts +++ b/packages/grpc-js-xds/src/generated/envoy/config/trace/v3/Tracing.ts @@ -6,34 +6,21 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ * Configuration for an HTTP tracer provider used by Envoy. * * The configuration is defined by the - * :ref:`HttpConnectionManager.Tracing ` - * :ref:`provider ` + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` * field. */ export interface _envoy_config_trace_v3_Tracing_Http { /** * The name of the HTTP trace driver to instantiate. The name must match a - * supported HTTP trace driver. Built-in trace drivers: - * - * - *envoy.tracers.lightstep* - * - *envoy.tracers.zipkin* - * - *envoy.tracers.dynamic_ot* - * - *envoy.tracers.datadog* - * - *envoy.tracers.opencensus* - * - *envoy.tracers.xray* + * supported HTTP trace driver. + * See the :ref:`extensions listed in typed_config below ` for the default list of the HTTP trace driver. */ 'name'?: (string); 'typed_config'?: (_google_protobuf_Any | null); /** - * Trace driver specific configuration which depends on the driver being instantiated. - * See the trace drivers for examples: - * - * - :ref:`LightstepConfig ` - * - :ref:`ZipkinConfig ` - * - :ref:`DynamicOtConfig ` - * - :ref:`DatadogConfig ` - * - :ref:`OpenCensusConfig ` - * - :ref:`AWS X-Ray ` + * Trace driver specific configuration which must be set according to the driver being instantiated. + * [#extension-category: envoy.tracers] */ 'config_type'?: "typed_config"; } @@ -42,34 +29,21 @@ export interface _envoy_config_trace_v3_Tracing_Http { * Configuration for an HTTP tracer provider used by Envoy. * * The configuration is defined by the - * :ref:`HttpConnectionManager.Tracing ` - * :ref:`provider ` + * :ref:`HttpConnectionManager.Tracing ` + * :ref:`provider ` * field. */ export interface _envoy_config_trace_v3_Tracing_Http__Output { /** * The name of the HTTP trace driver to instantiate. The name must match a - * supported HTTP trace driver. Built-in trace drivers: - * - * - *envoy.tracers.lightstep* - * - *envoy.tracers.zipkin* - * - *envoy.tracers.dynamic_ot* - * - *envoy.tracers.datadog* - * - *envoy.tracers.opencensus* - * - *envoy.tracers.xray* + * supported HTTP trace driver. + * See the :ref:`extensions listed in typed_config below ` for the default list of the HTTP trace driver. */ 'name': (string); 'typed_config'?: (_google_protobuf_Any__Output | null); /** - * Trace driver specific configuration which depends on the driver being instantiated. - * See the trace drivers for examples: - * - * - :ref:`LightstepConfig ` - * - :ref:`ZipkinConfig ` - * - :ref:`DynamicOtConfig ` - * - :ref:`DatadogConfig ` - * - :ref:`OpenCensusConfig ` - * - :ref:`AWS X-Ray ` + * Trace driver specific configuration which must be set according to the driver being instantiated. + * [#extension-category: envoy.tracers] */ 'config_type': "typed_config"; } @@ -83,7 +57,7 @@ export interface _envoy_config_trace_v3_Tracing_Http__Output { * .. attention:: * * Use of this message type has been deprecated in favor of direct use of - * :ref:`Tracing.Http `. + * :ref:`Tracing.Http `. */ export interface Tracing { /** @@ -101,7 +75,7 @@ export interface Tracing { * .. attention:: * * Use of this message type has been deprecated in favor of direct use of - * :ref:`Tracing.Http `. + * :ref:`Tracing.Http `. */ export interface Tracing__Output { /** diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts index 8e2739958..bec0403e4 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/common/fault/v3/FaultDelay.ts @@ -30,17 +30,16 @@ export interface _envoy_extensions_filters_common_fault_v3_FaultDelay_HeaderDela /** * Delay specification is used to inject latency into the - * HTTP/gRPC/Mongo/Redis operation or delay proxying of TCP connections. + * HTTP/Mongo operation. * [#next-free-field: 6] */ export interface FaultDelay { /** * Add a fixed delay before forwarding the operation upstream. See * https://developers.google.com/protocol-buffers/docs/proto3#json for - * the JSON/YAML Duration mapping. For HTTP/Mongo/Redis, the specified - * delay will be injected before a new request/operation. For TCP - * connections, the proxying of the connection upstream will be delayed - * for the specified period. This is required if type is FIXED. + * the JSON/YAML Duration mapping. For HTTP/Mongo, the specified + * delay will be injected before a new request/operation. + * This is required if type is FIXED. */ 'fixed_delay'?: (_google_protobuf_Duration | null); /** @@ -56,17 +55,16 @@ export interface FaultDelay { /** * Delay specification is used to inject latency into the - * HTTP/gRPC/Mongo/Redis operation or delay proxying of TCP connections. + * HTTP/Mongo operation. * [#next-free-field: 6] */ export interface FaultDelay__Output { /** * Add a fixed delay before forwarding the operation upstream. See * https://developers.google.com/protocol-buffers/docs/proto3#json for - * the JSON/YAML Duration mapping. For HTTP/Mongo/Redis, the specified - * delay will be injected before a new request/operation. For TCP - * connections, the proxying of the connection upstream will be delayed - * for the specified period. This is required if type is FIXED. + * the JSON/YAML Duration mapping. For HTTP/Mongo, the specified + * delay will be injected before a new request/operation. + * This is required if type is FIXED. */ 'fixed_delay'?: (_google_protobuf_Duration__Output | null); /** diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts index 20c543508..d78bd9e4a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/http/fault/v3/HTTPFault.ts @@ -7,7 +7,7 @@ import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output a import type { FaultRateLimit as _envoy_extensions_filters_common_fault_v3_FaultRateLimit, FaultRateLimit__Output as _envoy_extensions_filters_common_fault_v3_FaultRateLimit__Output } from '../../../../../../envoy/extensions/filters/common/fault/v3/FaultRateLimit'; /** - * [#next-free-field: 15] + * [#next-free-field: 16] */ export interface HTTPFault { /** @@ -31,7 +31,7 @@ export interface HTTPFault { * injection filter can be applied selectively to requests that match a set of * headers specified in the fault filter config. The chances of actual fault * injection further depend on the value of the :ref:`percentage - * ` field. + * ` field. * The filter will check the request's headers against all the specified * headers in the filter config. A match will happen if all the headers in the * config are present in the request with the same values (or based on @@ -107,10 +107,17 @@ export interface HTTPFault { * runtime. The default is: fault.http.abort.grpc_status */ 'abort_grpc_status_runtime'?: (string); + /** + * To control whether stats storage is allocated dynamically for each downstream server. + * If set to true, "x-envoy-downstream-service-cluster" field of header will be ignored by this filter. + * If set to false, dynamic stats storage will be allocated for the downstream cluster name. + * Default value is false. + */ + 'disable_downstream_cluster_stats'?: (boolean); } /** - * [#next-free-field: 15] + * [#next-free-field: 16] */ export interface HTTPFault__Output { /** @@ -134,7 +141,7 @@ export interface HTTPFault__Output { * injection filter can be applied selectively to requests that match a set of * headers specified in the fault filter config. The chances of actual fault * injection further depend on the value of the :ref:`percentage - * ` field. + * ` field. * The filter will check the request's headers against all the specified * headers in the filter config. A match will happen if all the headers in the * config are present in the request with the same values (or based on @@ -210,4 +217,11 @@ export interface HTTPFault__Output { * runtime. The default is: fault.http.abort.grpc_status */ 'abort_grpc_status_runtime': (string); + /** + * To control whether stats storage is allocated dynamically for each downstream server. + * If set to true, "x-envoy-downstream-service-cluster" field of header will be ignored by this filter. + * If set to false, dynamic stats storage will be allocated for the downstream cluster name. + * Default value is false. + */ + 'disable_downstream_cluster_stats': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/EnvoyMobileHttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/EnvoyMobileHttpConnectionManager.ts new file mode 100644 index 000000000..eb73721c3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/EnvoyMobileHttpConnectionManager.ts @@ -0,0 +1,29 @@ +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +import type { HttpConnectionManager as _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager, HttpConnectionManager__Output as _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; + +/** + * [#protodoc-title: Envoy Mobile HTTP connection manager] + * HTTP connection manager for use in Envoy mobile. + * [#extension: envoy.filters.network.envoy_mobile_http_connection_manager] + */ +export interface EnvoyMobileHttpConnectionManager { + /** + * The configuration for the underlying HttpConnectionManager which will be + * instantiated for Envoy mobile. + */ + 'config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager | null); +} + +/** + * [#protodoc-title: Envoy Mobile HTTP connection manager] + * HTTP connection manager for use in Envoy mobile. + * [#extension: envoy.filters.network.envoy_mobile_http_connection_manager] + */ +export interface EnvoyMobileHttpConnectionManager__Output { + /** + * The configuration for the underlying HttpConnectionManager which will be + * instantiated for Envoy mobile. + */ + 'config': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts index 4a8912599..fdf7084fe 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager.ts @@ -13,9 +13,13 @@ import type { ScopedRoutes as _envoy_extensions_filters_network_http_connection_ import type { HttpProtocolOptions as _envoy_config_core_v3_HttpProtocolOptions, HttpProtocolOptions__Output as _envoy_config_core_v3_HttpProtocolOptions__Output } from '../../../../../../envoy/config/core/v3/HttpProtocolOptions'; import type { RequestIDExtension as _envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension, RequestIDExtension__Output as _envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/RequestIDExtension'; import type { LocalReplyConfig as _envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig, LocalReplyConfig__Output as _envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig__Output } from '../../../../../../envoy/extensions/filters/network/http_connection_manager/v3/LocalReplyConfig'; +import type { Http3ProtocolOptions as _envoy_config_core_v3_Http3ProtocolOptions, Http3ProtocolOptions__Output as _envoy_config_core_v3_Http3ProtocolOptions__Output } from '../../../../../../envoy/config/core/v3/Http3ProtocolOptions'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../../../envoy/config/core/v3/TypedExtensionConfig'; +import type { SchemeHeaderTransformation as _envoy_config_core_v3_SchemeHeaderTransformation, SchemeHeaderTransformation__Output as _envoy_config_core_v3_SchemeHeaderTransformation__Output } from '../../../../../../envoy/config/core/v3/SchemeHeaderTransformation'; import type { Percent as _envoy_type_v3_Percent, Percent__Output as _envoy_type_v3_Percent__Output } from '../../../../../../envoy/type/v3/Percent'; import type { CustomTag as _envoy_type_tracing_v3_CustomTag, CustomTag__Output as _envoy_type_tracing_v3_CustomTag__Output } from '../../../../../../envoy/type/tracing/v3/CustomTag'; import type { _envoy_config_trace_v3_Tracing_Http, _envoy_config_trace_v3_Tracing_Http__Output } from '../../../../../../envoy/config/trace/v3/Tracing'; +import type { PathTransformation as _envoy_type_http_v3_PathTransformation, PathTransformation__Output as _envoy_type_http_v3_PathTransformation__Output } from '../../../../../../envoy/type/http/v3/PathTransformation'; // Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto @@ -106,6 +110,120 @@ export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpCon EGRESS = 1, } +/** + * [#not-implemented-hide:] Transformations that apply to path headers. Transformations are applied + * before any processing of requests by HTTP filters, routing, and matching. Only the normalized + * path will be visible internally if a transformation is enabled. Any path rewrites that the + * router performs (e.g. :ref:`regex_rewrite + * ` or :ref:`prefix_rewrite + * `) will apply to the *:path* header + * destined for the upstream. + * + * Note: access logging and tracing will show the original *:path* header. + */ +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathNormalizationOptions { + /** + * [#not-implemented-hide:] Normalization applies internally before any processing of requests by + * HTTP filters, routing, and matching *and* will affect the forwarded *:path* header. Defaults + * to :ref:`NormalizePathRFC3986 + * `. When not + * specified, this value may be overridden by the runtime variable + * :ref:`http_connection_manager.normalize_path`. + * Envoy will respond with 400 to paths that are malformed (e.g. for paths that fail RFC 3986 + * normalization due to disallowed characters.) + */ + 'forwarding_transformation'?: (_envoy_type_http_v3_PathTransformation | null); + /** + * [#not-implemented-hide:] Normalization only applies internally before any processing of + * requests by HTTP filters, routing, and matching. These will be applied after full + * transformation is applied. The *:path* header before this transformation will be restored in + * the router filter and sent upstream unless it was mutated by a filter. Defaults to no + * transformations. + * Multiple actions can be applied in the same Transformation, forming a sequential + * pipeline. The transformations will be performed in the order that they appear. Envoy will + * respond with 400 to paths that are malformed (e.g. for paths that fail RFC 3986 + * normalization due to disallowed characters.) + */ + 'http_filter_transformation'?: (_envoy_type_http_v3_PathTransformation | null); +} + +/** + * [#not-implemented-hide:] Transformations that apply to path headers. Transformations are applied + * before any processing of requests by HTTP filters, routing, and matching. Only the normalized + * path will be visible internally if a transformation is enabled. Any path rewrites that the + * router performs (e.g. :ref:`regex_rewrite + * ` or :ref:`prefix_rewrite + * `) will apply to the *:path* header + * destined for the upstream. + * + * Note: access logging and tracing will show the original *:path* header. + */ +export interface _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathNormalizationOptions__Output { + /** + * [#not-implemented-hide:] Normalization applies internally before any processing of requests by + * HTTP filters, routing, and matching *and* will affect the forwarded *:path* header. Defaults + * to :ref:`NormalizePathRFC3986 + * `. When not + * specified, this value may be overridden by the runtime variable + * :ref:`http_connection_manager.normalize_path`. + * Envoy will respond with 400 to paths that are malformed (e.g. for paths that fail RFC 3986 + * normalization due to disallowed characters.) + */ + 'forwarding_transformation': (_envoy_type_http_v3_PathTransformation__Output | null); + /** + * [#not-implemented-hide:] Normalization only applies internally before any processing of + * requests by HTTP filters, routing, and matching. These will be applied after full + * transformation is applied. The *:path* header before this transformation will be restored in + * the router filter and sent upstream unless it was mutated by a filter. Defaults to no + * transformations. + * Multiple actions can be applied in the same Transformation, forming a sequential + * pipeline. The transformations will be performed in the order that they appear. Envoy will + * respond with 400 to paths that are malformed (e.g. for paths that fail RFC 3986 + * normalization due to disallowed characters.) + */ + 'http_filter_transformation': (_envoy_type_http_v3_PathTransformation__Output | null); +} + +// Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto + +/** + * Determines the action for request that contain %2F, %2f, %5C or %5c sequences in the URI path. + * This operation occurs before URL normalization and the merge slashes transformations if they were enabled. + */ +export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathWithEscapedSlashesAction { + /** + * Default behavior specific to implementation (i.e. Envoy) of this configuration option. + * Envoy, by default, takes the KEEP_UNCHANGED action. + * NOTE: the implementation may change the default behavior at-will. + */ + IMPLEMENTATION_SPECIFIC_DEFAULT = 0, + /** + * Keep escaped slashes. + */ + KEEP_UNCHANGED = 1, + /** + * Reject client request with the 400 status. gRPC requests will be rejected with the INTERNAL (13) error code. + * The "httpN.downstream_rq_failed_path_normalization" counter is incremented for each rejected request. + */ + REJECT_REQUEST = 2, + /** + * Unescape %2F and %5C sequences and redirect request to the new path if these sequences were present. + * Redirect occurs after path normalization and merge slashes transformations if they were configured. + * NOTE: gRPC requests will be rejected with the INTERNAL (13) error code. + * This option minimizes possibility of path confusion exploits by forcing request with unescaped slashes to + * traverse all parties: downstream client, intermediate proxies, Envoy and upstream server. + * The "httpN.downstream_rq_redirected_with_normalized_path" counter is incremented for each + * redirected request. + */ + UNESCAPE_AND_REDIRECT = 3, + /** + * Unescape %2F and %5C sequences. + * Note: this option should not be enabled if intermediaries perform path based access control as + * it may lead to path confusion vulnerabilities. + */ + UNESCAPE_AND_FORWARD = 4, +} + // Original file: deps/envoy-api/envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto export enum _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ServerHeaderTransformation { @@ -346,7 +464,7 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht /** * Determines if upgrades are enabled or disabled by default. Defaults to true. * This can be overridden on a per-route basis with :ref:`cluster - * ` as documented in the + * ` as documented in the * :ref:`upgrade documentation `. */ 'enabled'?: (_google_protobuf_BoolValue | null); @@ -383,14 +501,14 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Ht /** * Determines if upgrades are enabled or disabled by default. Defaults to true. * This can be overridden on a per-route basis with :ref:`cluster - * ` as documented in the + * ` as documented in the * :ref:`upgrade documentation `. */ 'enabled': (_google_protobuf_BoolValue__Output | null); } /** - * [#next-free-field: 43] + * [#next-free-field: 49] */ export interface HttpConnectionManager { /** @@ -426,7 +544,7 @@ export interface HttpConnectionManager { /** * Presence of the object defines whether the connection manager * emits :ref:`tracing ` data to the :ref:`configured tracing provider - * `. + * `. */ 'tracing'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing | null); /** @@ -483,7 +601,7 @@ export interface HttpConnectionManager { 'forward_client_cert_details'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails | keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails); /** * This field is valid only when :ref:`forward_client_cert_details - * ` + * ` * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in * the client certificate to be forwarded. Note that in the * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and @@ -509,7 +627,7 @@ export interface HttpConnectionManager { /** * If * :ref:`use_remote_address - * ` + * ` * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. * This is useful for testing compatibility of upstream services that parse the header value. For @@ -527,7 +645,7 @@ export interface HttpConnectionManager { * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager * has mutated the request headers. While :ref:`use_remote_address - * ` + * ` * will also suppress XFF addition, it has consequences for logging and other * Envoy uses of the remote address, so *skip_xff_append* should be used * when only an elision of XFF addition is intended. @@ -548,10 +666,10 @@ export interface HttpConnectionManager { * * This idle timeout applies to new streams and is overridable by the * :ref:`route-level idle_timeout - * `. Even on a stream in + * `. Even on a stream in * which the override applies, prior to receipt of the initial request * headers, the :ref:`stream_idle_timeout - * ` + * ` * applies. Each time an encode/decode event for headers or data is processed * for the stream, the timer will be reset. If the timeout fires, the stream * is terminated with a 408 Request Timeout error code if no upstream response @@ -564,12 +682,12 @@ export interface HttpConnectionManager { * data has been proxied within available flow control windows. If the timeout is hit in this * case, the :ref:`tx_flush_timeout ` counter will be * incremented. Note that :ref:`max_stream_duration - * ` does not apply to + * ` does not apply to * this corner case. * * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" * is configured, this timeout is scaled according to the value for - * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. * * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due * to the granularity of events presented to the connection manager. For example, while receiving @@ -632,8 +750,6 @@ export interface HttpConnectionManager { * The maximum request headers size for incoming connections. * If unconfigured, the default max request headers allowed is 60 KiB. * Requests that exceed this limit will receive a 431 response. - * The max configurable limit is 96 KiB, based on current implementation - * constraints. */ 'max_request_headers_kb'?: (_google_protobuf_UInt32Value | null); /** @@ -684,15 +800,21 @@ export interface HttpConnectionManager { 'common_http_protocol_options'?: (_envoy_config_core_v3_HttpProtocolOptions | null); /** * The configuration of the request ID extension. This includes operations such as - * generation, validation, and associated tracing operations. - * - * If not set, Envoy uses the default UUID-based behavior: + * generation, validation, and associated tracing operations. If empty, the + * :ref:`UuidRequestIdConfig ` + * default extension is used with default parameters. See the documentation for that extension + * for details on what it does. Customizing the configuration for the default extension can be + * achieved by configuring it explicitly here. For example, to disable trace reason packing, + * the following configuration can be used: * - * 1. Request ID is propagated using *x-request-id* header. + * .. validated-code-block:: yaml + * :type-name: envoy.extensions.filters.network.http_connection_manager.v3.RequestIDExtension * - * 2. Request ID is a universally unique identifier (UUID). + * typed_config: + * "@type": type.googleapis.com/envoy.extensions.request_id.uuid.v3.UuidRequestIdConfig + * pack_trace_reason: false * - * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. + * [#extension-category: envoy.request_id] */ 'request_id_extension'?: (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension | null); /** @@ -709,10 +831,12 @@ export interface HttpConnectionManager { 'local_reply_config'?: (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig | null); /** * Determines if the port part should be removed from host/authority header before any processing - * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` - * local port and request method is not CONNECT. This affects the upstream host header as well. + * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` + * local port. This affects the upstream host header unless the method is + * CONNECT in which case if no filter adds a port the original port will be restored before headers are + * sent upstream. * Without setting this option, incoming requests with host `example:443` will not match against - * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part * of `HTTP spec `_ and is provided for convenience. * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. */ @@ -744,20 +868,82 @@ export interface HttpConnectionManager { 'request_headers_timeout'?: (_google_protobuf_Duration | null); /** * Determines if the port part should be removed from host/authority header before any processing - * of request by HTTP filters or routing. The port would be removed only if request method is not CONNECT. - * This affects the upstream host header as well. + * of request by HTTP filters or routing. + * This affects the upstream host header unless the method is CONNECT in + * which case if no filter adds a port the original port will be restored before headers are sent upstream. * Without setting this option, incoming requests with host `example:443` will not match against - * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part * of `HTTP spec `_ and is provided for convenience. * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. */ 'strip_any_host_port'?: (boolean); + /** + * [#not-implemented-hide:] Path normalization configuration. This includes + * configurations for transformations (e.g. RFC 3986 normalization or merge + * adjacent slashes) and the policy to apply them. The policy determines + * whether transformations affect the forwarded *:path* header. RFC 3986 path + * normalization is enabled by default and the default policy is that the + * normalized header will be forwarded. See :ref:`PathNormalizationOptions + * ` + * for details. + */ + 'path_normalization_options'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathNormalizationOptions | null); + /** + * Additional HTTP/3 settings that are passed directly to the HTTP/3 codec. + * [#not-implemented-hide:] + */ + 'http3_protocol_options'?: (_envoy_config_core_v3_Http3ProtocolOptions | null); + /** + * Action to take when request URL path contains escaped slash sequences (%2F, %2f, %5C and %5c). + * The default value can be overridden by the :ref:`http_connection_manager.path_with_escaped_slashes_action` + * runtime variable. + * The :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling` runtime + * variable can be used to apply the action to a portion of all requests. + */ + 'path_with_escaped_slashes_action'?: (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathWithEscapedSlashesAction | keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathWithEscapedSlashesAction); + /** + * The configuration for the original IP detection extensions. + * + * When configured the extensions will be called along with the request headers + * and information about the downstream connection, such as the directly connected address. + * Each extension will then use these parameters to decide the request's effective remote address. + * If an extension fails to detect the original IP address and isn't configured to reject + * the request, the HCM will try the remaining extensions until one succeeds or rejects + * the request. If the request isn't rejected nor any extension succeeds, the HCM will + * fallback to using the remote address. + * + * .. WARNING:: + * Extensions cannot be used in conjunction with :ref:`use_remote_address + * ` + * nor :ref:`xff_num_trusted_hops + * `. + * + * [#extension-category: envoy.http.original_ip_detection] + */ + 'original_ip_detection_extensions'?: (_envoy_config_core_v3_TypedExtensionConfig)[]; + /** + * Determines if trailing dot of the host should be removed from host/authority header before any + * processing of request by HTTP filters or routing. + * This affects the upstream host header. + * Without setting this option, incoming requests with host `example.com.` will not match against + * route with :ref:`domains` match set to `example.com`. Defaults to `false`. + * When the incoming request contains a host/authority header that includes a port number, + * setting this option will strip a trailing dot, if present, from the host section, + * leaving the port as is (e.g. host value `example.com.:443` will be updated to `example.com:443`). + */ + 'strip_trailing_host_dot'?: (boolean); + /** + * Allows for explicit transformation of the :scheme header on the request path. + * If not set, Envoy's default :ref:`scheme ` + * handling applies. + */ + 'scheme_header_transformation'?: (_envoy_config_core_v3_SchemeHeaderTransformation | null); 'route_specifier'?: "rds"|"route_config"|"scoped_routes"; 'strip_port_mode'?: "strip_any_host_port"; } /** - * [#next-free-field: 43] + * [#next-free-field: 49] */ export interface HttpConnectionManager__Output { /** @@ -793,7 +979,7 @@ export interface HttpConnectionManager__Output { /** * Presence of the object defines whether the connection manager * emits :ref:`tracing ` data to the :ref:`configured tracing provider - * `. + * `. */ 'tracing': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_Tracing__Output | null); /** @@ -850,7 +1036,7 @@ export interface HttpConnectionManager__Output { 'forward_client_cert_details': (keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_ForwardClientCertDetails); /** * This field is valid only when :ref:`forward_client_cert_details - * ` + * ` * is APPEND_FORWARD or SANITIZE_SET and the client connection is mTLS. It specifies the fields in * the client certificate to be forwarded. Note that in the * :ref:`config_http_conn_man_headers_x-forwarded-client-cert` header, *Hash* is always set, and @@ -876,7 +1062,7 @@ export interface HttpConnectionManager__Output { /** * If * :ref:`use_remote_address - * ` + * ` * is true and represent_ipv4_remote_address_as_ipv4_mapped_ipv6 is true and the remote address is * an IPv4 address, the address will be mapped to IPv6 before it is appended to *x-forwarded-for*. * This is useful for testing compatibility of upstream services that parse the header value. For @@ -894,7 +1080,7 @@ export interface HttpConnectionManager__Output { * :ref:`config_http_conn_man_headers_x-forwarded-for` HTTP header. This may be used in * conjunction with HTTP filters that explicitly manipulate XFF after the HTTP connection manager * has mutated the request headers. While :ref:`use_remote_address - * ` + * ` * will also suppress XFF addition, it has consequences for logging and other * Envoy uses of the remote address, so *skip_xff_append* should be used * when only an elision of XFF addition is intended. @@ -915,10 +1101,10 @@ export interface HttpConnectionManager__Output { * * This idle timeout applies to new streams and is overridable by the * :ref:`route-level idle_timeout - * `. Even on a stream in + * `. Even on a stream in * which the override applies, prior to receipt of the initial request * headers, the :ref:`stream_idle_timeout - * ` + * ` * applies. Each time an encode/decode event for headers or data is processed * for the stream, the timer will be reset. If the timeout fires, the stream * is terminated with a 408 Request Timeout error code if no upstream response @@ -931,12 +1117,12 @@ export interface HttpConnectionManager__Output { * data has been proxied within available flow control windows. If the timeout is hit in this * case, the :ref:`tx_flush_timeout ` counter will be * incremented. Note that :ref:`max_stream_duration - * ` does not apply to + * ` does not apply to * this corner case. * * If the :ref:`overload action ` "envoy.overload_actions.reduce_timeouts" * is configured, this timeout is scaled according to the value for - * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. + * :ref:`HTTP_DOWNSTREAM_STREAM_IDLE `. * * Note that it is possible to idle timeout even if the wire traffic for a stream is non-idle, due * to the granularity of events presented to the connection manager. For example, while receiving @@ -999,8 +1185,6 @@ export interface HttpConnectionManager__Output { * The maximum request headers size for incoming connections. * If unconfigured, the default max request headers allowed is 60 KiB. * Requests that exceed this limit will receive a 431 response. - * The max configurable limit is 96 KiB, based on current implementation - * constraints. */ 'max_request_headers_kb': (_google_protobuf_UInt32Value__Output | null); /** @@ -1051,15 +1235,21 @@ export interface HttpConnectionManager__Output { 'common_http_protocol_options': (_envoy_config_core_v3_HttpProtocolOptions__Output | null); /** * The configuration of the request ID extension. This includes operations such as - * generation, validation, and associated tracing operations. + * generation, validation, and associated tracing operations. If empty, the + * :ref:`UuidRequestIdConfig ` + * default extension is used with default parameters. See the documentation for that extension + * for details on what it does. Customizing the configuration for the default extension can be + * achieved by configuring it explicitly here. For example, to disable trace reason packing, + * the following configuration can be used: * - * If not set, Envoy uses the default UUID-based behavior: + * .. validated-code-block:: yaml + * :type-name: envoy.extensions.filters.network.http_connection_manager.v3.RequestIDExtension * - * 1. Request ID is propagated using *x-request-id* header. + * typed_config: + * "@type": type.googleapis.com/envoy.extensions.request_id.uuid.v3.UuidRequestIdConfig + * pack_trace_reason: false * - * 2. Request ID is a universally unique identifier (UUID). - * - * 3. Tracing decision (sampled, forced, etc) is set in 14th byte of the UUID. + * [#extension-category: envoy.request_id] */ 'request_id_extension': (_envoy_extensions_filters_network_http_connection_manager_v3_RequestIDExtension__Output | null); /** @@ -1076,10 +1266,12 @@ export interface HttpConnectionManager__Output { 'local_reply_config': (_envoy_extensions_filters_network_http_connection_manager_v3_LocalReplyConfig__Output | null); /** * Determines if the port part should be removed from host/authority header before any processing - * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` - * local port and request method is not CONNECT. This affects the upstream host header as well. + * of request by HTTP filters or routing. The port would be removed only if it is equal to the :ref:`listener's` + * local port. This affects the upstream host header unless the method is + * CONNECT in which case if no filter adds a port the original port will be restored before headers are + * sent upstream. * Without setting this option, incoming requests with host `example:443` will not match against - * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part * of `HTTP spec `_ and is provided for convenience. * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. */ @@ -1111,14 +1303,76 @@ export interface HttpConnectionManager__Output { 'request_headers_timeout': (_google_protobuf_Duration__Output | null); /** * Determines if the port part should be removed from host/authority header before any processing - * of request by HTTP filters or routing. The port would be removed only if request method is not CONNECT. - * This affects the upstream host header as well. + * of request by HTTP filters or routing. + * This affects the upstream host header unless the method is CONNECT in + * which case if no filter adds a port the original port will be restored before headers are sent upstream. * Without setting this option, incoming requests with host `example:443` will not match against - * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part + * route with :ref:`domains` match set to `example`. Defaults to `false`. Note that port removal is not part * of `HTTP spec `_ and is provided for convenience. * Only one of `strip_matching_host_port` or `strip_any_host_port` can be set. */ 'strip_any_host_port'?: (boolean); + /** + * [#not-implemented-hide:] Path normalization configuration. This includes + * configurations for transformations (e.g. RFC 3986 normalization or merge + * adjacent slashes) and the policy to apply them. The policy determines + * whether transformations affect the forwarded *:path* header. RFC 3986 path + * normalization is enabled by default and the default policy is that the + * normalized header will be forwarded. See :ref:`PathNormalizationOptions + * ` + * for details. + */ + 'path_normalization_options': (_envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathNormalizationOptions__Output | null); + /** + * Additional HTTP/3 settings that are passed directly to the HTTP/3 codec. + * [#not-implemented-hide:] + */ + 'http3_protocol_options': (_envoy_config_core_v3_Http3ProtocolOptions__Output | null); + /** + * Action to take when request URL path contains escaped slash sequences (%2F, %2f, %5C and %5c). + * The default value can be overridden by the :ref:`http_connection_manager.path_with_escaped_slashes_action` + * runtime variable. + * The :ref:`http_connection_manager.path_with_escaped_slashes_action_sampling` runtime + * variable can be used to apply the action to a portion of all requests. + */ + 'path_with_escaped_slashes_action': (keyof typeof _envoy_extensions_filters_network_http_connection_manager_v3_HttpConnectionManager_PathWithEscapedSlashesAction); + /** + * The configuration for the original IP detection extensions. + * + * When configured the extensions will be called along with the request headers + * and information about the downstream connection, such as the directly connected address. + * Each extension will then use these parameters to decide the request's effective remote address. + * If an extension fails to detect the original IP address and isn't configured to reject + * the request, the HCM will try the remaining extensions until one succeeds or rejects + * the request. If the request isn't rejected nor any extension succeeds, the HCM will + * fallback to using the remote address. + * + * .. WARNING:: + * Extensions cannot be used in conjunction with :ref:`use_remote_address + * ` + * nor :ref:`xff_num_trusted_hops + * `. + * + * [#extension-category: envoy.http.original_ip_detection] + */ + 'original_ip_detection_extensions': (_envoy_config_core_v3_TypedExtensionConfig__Output)[]; + /** + * Determines if trailing dot of the host should be removed from host/authority header before any + * processing of request by HTTP filters or routing. + * This affects the upstream host header. + * Without setting this option, incoming requests with host `example.com.` will not match against + * route with :ref:`domains` match set to `example.com`. Defaults to `false`. + * When the incoming request contains a host/authority header that includes a port number, + * setting this option will strip a trailing dot, if present, from the host section, + * leaving the port as is (e.g. host value `example.com.:443` will be updated to `example.com:443`). + */ + 'strip_trailing_host_dot': (boolean); + /** + * Allows for explicit transformation of the :scheme header on the request path. + * If not set, Envoy's default :ref:`scheme ` + * handling applies. + */ + 'scheme_header_transformation': (_envoy_config_core_v3_SchemeHeaderTransformation__Output | null); 'route_specifier': "rds"|"route_config"|"scoped_routes"; 'strip_port_mode': "strip_any_host_port"; } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts index 42e4215d0..d1c1cbc06 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpFilter.ts @@ -16,19 +16,29 @@ export interface HttpFilter { /** * Filter specific configuration which depends on the filter being instantiated. See the supported * filters for further documentation. + * + * To support configuring a :ref:`match tree `, use an + * :ref:`ExtensionWithMatcher ` + * with the desired HTTP filter. + * [#extension-category: envoy.filters.http] */ 'typed_config'?: (_google_protobuf_Any | null); /** * Configuration source specifier for an extension configuration discovery service. * In case of a failure and without the default configuration, the HTTP listener responds with code 500. * Extension configs delivered through this mechanism are not expected to require warming (see https://github.com/envoyproxy/envoy/issues/12061). + * + * To support configuring a :ref:`match tree `, use an + * :ref:`ExtensionWithMatcher ` + * with the desired HTTP filter. This works for both the default filter configuration as well + * as for filters provided via the API. */ 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource | null); /** * If true, clients that do not support this filter may ignore the * filter but otherwise accept the config. * Otherwise, clients that do not support this filter must reject the config. - * [#not-implemented-hide:] + * This is also same with typed per filter config. */ 'is_optional'?: (boolean); 'config_type'?: "typed_config"|"config_discovery"; @@ -47,19 +57,29 @@ export interface HttpFilter__Output { /** * Filter specific configuration which depends on the filter being instantiated. See the supported * filters for further documentation. + * + * To support configuring a :ref:`match tree `, use an + * :ref:`ExtensionWithMatcher ` + * with the desired HTTP filter. + * [#extension-category: envoy.filters.http] */ 'typed_config'?: (_google_protobuf_Any__Output | null); /** * Configuration source specifier for an extension configuration discovery service. * In case of a failure and without the default configuration, the HTTP listener responds with code 500. * Extension configs delivered through this mechanism are not expected to require warming (see https://github.com/envoyproxy/envoy/issues/12061). + * + * To support configuring a :ref:`match tree `, use an + * :ref:`ExtensionWithMatcher ` + * with the desired HTTP filter. This works for both the default filter configuration as well + * as for filters provided via the API. */ 'config_discovery'?: (_envoy_config_core_v3_ExtensionConfigSource__Output | null); /** * If true, clients that do not support this filter may ignore the * filter but otherwise accept the config. * Otherwise, clients that do not support this filter must reject the config. - * [#not-implemented-hide:] + * This is also same with typed per filter config. */ 'is_optional': (boolean); 'config_type': "typed_config"|"config_discovery"; diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts index e4565ce80..5f7d2b6fe 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRds.ts @@ -7,6 +7,11 @@ export interface ScopedRds { * Configuration source specifier for scoped RDS. */ 'scoped_rds_config_source'?: (_envoy_config_core_v3_ConfigSource | null); + /** + * xdstp:// resource locator for scoped RDS collection. + * [#not-implemented-hide:] + */ + 'srds_resources_locator'?: (string); } export interface ScopedRds__Output { @@ -14,4 +19,9 @@ export interface ScopedRds__Output { * Configuration source specifier for scoped RDS. */ 'scoped_rds_config_source': (_envoy_config_core_v3_ConfigSource__Output | null); + /** + * xdstp:// resource locator for scoped RDS collection. + * [#not-implemented-hide:] + */ + 'srds_resources_locator': (string); } diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts index 8aecd3883..041af534b 100644 --- a/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/filters/network/http_connection_manager/v3/ScopedRoutes.ts @@ -160,19 +160,19 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Sc /** * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These - * keys are matched against a set of :ref:`Key` - * objects assembled from :ref:`ScopedRouteConfiguration` + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via - * :ref:`scoped_route_configurations_list`. + * :ref:`scoped_route_configurations_list`. * * Upon receiving a request's headers, the Router will build a key using the algorithm specified * by this message. This key will be used to look up the routing table (i.e., the - * :ref:`RouteConfiguration`) to use for the request. + * :ref:`RouteConfiguration`) to use for the request. */ export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder { /** * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the - * fragments of a :ref:`ScopedRouteConfiguration`. + * fragments of a :ref:`ScopedRouteConfiguration`. * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. */ 'fragments'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder)[]; @@ -180,19 +180,19 @@ export interface _envoy_extensions_filters_network_http_connection_manager_v3_Sc /** * Specifies the mechanism for constructing "scope keys" based on HTTP request attributes. These - * keys are matched against a set of :ref:`Key` - * objects assembled from :ref:`ScopedRouteConfiguration` + * keys are matched against a set of :ref:`Key` + * objects assembled from :ref:`ScopedRouteConfiguration` * messages distributed via SRDS (the Scoped Route Discovery Service) or assigned statically via - * :ref:`scoped_route_configurations_list`. + * :ref:`scoped_route_configurations_list`. * * Upon receiving a request's headers, the Router will build a key using the algorithm specified * by this message. This key will be used to look up the routing table (i.e., the - * :ref:`RouteConfiguration`) to use for the request. + * :ref:`RouteConfiguration`) to use for the request. */ export interface _envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder__Output { /** * The final(built) scope key consists of the ordered union of these fragments, which are compared in order with the - * fragments of a :ref:`ScopedRouteConfiguration`. + * fragments of a :ref:`ScopedRouteConfiguration`. * A missing fragment during comparison will make the key invalid, i.e., the computed key doesn't match any key. */ 'fragments': (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRoutes_ScopeKeyBuilder_FragmentBuilder__Output)[]; @@ -220,7 +220,7 @@ export interface ScopedRoutes { * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by * matching a key constructed from the request's attributes according to the algorithm specified * by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList | null); @@ -228,7 +228,7 @@ export interface ScopedRoutes { * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS * API. A scope is assigned to a request by matching a key constructed from the request's * attributes according to the algorithm specified by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds | null); @@ -257,7 +257,7 @@ export interface ScopedRoutes__Output { * The set of routing scopes corresponding to the HCM. A scope is assigned to a request by * matching a key constructed from the request's attributes according to the algorithm specified * by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ 'scoped_route_configurations_list'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRouteConfigurationsList__Output | null); @@ -265,7 +265,7 @@ export interface ScopedRoutes__Output { * The set of routing scopes associated with the HCM will be dynamically loaded via the SRDS * API. A scope is assigned to a request by matching a key constructed from the request's * attributes according to the algorithm specified by the - * :ref:`ScopeKeyBuilder` + * :ref:`ScopeKeyBuilder` * in this message. */ 'scoped_rds'?: (_envoy_extensions_filters_network_http_connection_manager_v3_ScopedRds__Output | null); diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateProviderPluginInstance.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateProviderPluginInstance.ts new file mode 100644 index 000000000..3a3100f55 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateProviderPluginInstance.ts @@ -0,0 +1,52 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + + +/** + * Indicates a certificate to be obtained from a named CertificateProvider plugin instance. + * The plugin instances are defined in the client's bootstrap file. + * The plugin allows certificates to be fetched/refreshed over the network asynchronously with + * respect to the TLS handshake. + * [#not-implemented-hide:] + */ +export interface CertificateProviderPluginInstance { + /** + * Provider instance name. If not present, defaults to "default". + * + * Instance names should generally be defined not in terms of the underlying provider + * implementation (e.g., "file_watcher") but rather in terms of the function of the + * certificates (e.g., "foo_deployment_identity"). + */ + 'instance_name'?: (string); + /** + * Opaque name used to specify certificate instances or types. For example, "ROOTCA" to specify + * a root-certificate (validation context) or "example.com" to specify a certificate for a + * particular domain. Not all provider instances will actually use this field, so the value + * defaults to the empty string. + */ + 'certificate_name'?: (string); +} + +/** + * Indicates a certificate to be obtained from a named CertificateProvider plugin instance. + * The plugin instances are defined in the client's bootstrap file. + * The plugin allows certificates to be fetched/refreshed over the network asynchronously with + * respect to the TLS handshake. + * [#not-implemented-hide:] + */ +export interface CertificateProviderPluginInstance__Output { + /** + * Provider instance name. If not present, defaults to "default". + * + * Instance names should generally be defined not in terms of the underlying provider + * implementation (e.g., "file_watcher") but rather in terms of the function of the + * certificates (e.g., "foo_deployment_identity"). + */ + 'instance_name': (string); + /** + * Opaque name used to specify certificate instances or types. For example, "ROOTCA" to specify + * a root-certificate (validation context) or "example.com" to specify a certificate for a + * particular domain. Not all provider instances will actually use this field, so the value + * defaults to the empty string. + */ + 'certificate_name': (string); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateValidationContext.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateValidationContext.ts new file mode 100644 index 000000000..379320086 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/CertificateValidationContext.ts @@ -0,0 +1,372 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../../envoy/config/core/v3/DataSource'; +import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../../google/protobuf/BoolValue'; +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../../envoy/type/matcher/v3/StringMatcher'; +import type { WatchedDirectory as _envoy_config_core_v3_WatchedDirectory, WatchedDirectory__Output as _envoy_config_core_v3_WatchedDirectory__Output } from '../../../../../envoy/config/core/v3/WatchedDirectory'; +import type { TypedExtensionConfig as _envoy_config_core_v3_TypedExtensionConfig, TypedExtensionConfig__Output as _envoy_config_core_v3_TypedExtensionConfig__Output } from '../../../../../envoy/config/core/v3/TypedExtensionConfig'; +import type { CertificateProviderPluginInstance as _envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance, CertificateProviderPluginInstance__Output as _envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance__Output } from '../../../../../envoy/extensions/transport_sockets/tls/v3/CertificateProviderPluginInstance'; + +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + +/** + * Peer certificate verification mode. + */ +export enum _envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_TrustChainVerification { + /** + * Perform default certificate verification (e.g., against CA / verification lists) + */ + VERIFY_TRUST_CHAIN = 0, + /** + * Connections where the certificate fails verification will be permitted. + * For HTTP connections, the result of certificate verification can be used in route matching. ( + * see :ref:`validated ` ). + */ + ACCEPT_UNTRUSTED = 1, +} + +/** + * [#next-free-field: 14] + */ +export interface CertificateValidationContext { + /** + * TLS certificate data containing certificate authority certificates to use in verifying + * a presented peer certificate (e.g. server certificate for clusters or client certificate + * for listeners). If not specified and a peer certificate is presented it will not be + * verified. By default, a client certificate is optional, unless one of the additional + * options (:ref:`require_client_certificate + * `, + * :ref:`verify_certificate_spki + * `, + * :ref:`verify_certificate_hash + * `, or + * :ref:`match_subject_alt_names + * `) is also + * specified. + * + * It can optionally contain certificate revocation lists, in which case Envoy will verify + * that the presented peer certificate has not been revoked by one of the included CRLs. Note + * that if a CRL is provided for any certificate authority in a trust chain, a CRL must be + * provided for all certificate authorities in that chain. Failure to do so will result in + * verification failure for both revoked and unrevoked certificates from that chain. + * + * See :ref:`the TLS overview ` for a list of common + * system CA locations. + * + * If *trusted_ca* is a filesystem path, a watch will be added to the parent + * directory for any file moves to support rotation. This currently only + * applies to dynamic secrets, when the *CertificateValidationContext* is + * delivered via SDS. + * + * Only one of *trusted_ca* and *ca_certificate_provider_instance* may be specified. + * + * [#next-major-version: This field and watched_directory below should ideally be moved into a + * separate sub-message, since there's no point in specifying the latter field without this one.] + */ + 'trusted_ca'?: (_envoy_config_core_v3_DataSource | null); + /** + * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that + * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + * + * A hex-encoded SHA-256 of the certificate can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 + * df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a + * + * A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 + * DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A + * + * Both of those formats are acceptable. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + */ + 'verify_certificate_hash'?: (string)[]; + /** + * An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the + * SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate + * matches one of the specified values. + * + * A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -pubkey + * | openssl pkey -pubin -outform DER + * | openssl dgst -sha256 -binary + * | openssl enc -base64 + * NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= + * + * This is the format used in HTTP Public Key Pinning. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + * + * .. attention:: + * + * This option is preferred over :ref:`verify_certificate_hash + * `, + * because SPKI is tied to a private key, so it doesn't change when the certificate + * is renewed using the same private key. + */ + 'verify_certificate_spki'?: (string)[]; + /** + * [#not-implemented-hide:] Must present signed certificate time-stamp. + */ + 'require_signed_certificate_timestamp'?: (_google_protobuf_BoolValue | null); + /** + * An optional `certificate revocation list + * `_ + * (in PEM format). If specified, Envoy will verify that the presented peer + * certificate has not been revoked by this CRL. If this DataSource contains + * multiple CRLs, all of them will be used. Note that if a CRL is provided + * for any certificate authority in a trust chain, a CRL must be provided + * for all certificate authorities in that chain. Failure to do so will + * result in verification failure for both revoked and unrevoked certificates + * from that chain. + */ + 'crl'?: (_envoy_config_core_v3_DataSource | null); + /** + * If specified, Envoy will not reject expired certificates. + */ + 'allow_expired_certificate'?: (boolean); + /** + * An optional list of Subject Alternative name matchers. If specified, Envoy will verify that the + * Subject Alternative Name of the presented certificate matches one of the specified matchers. + * + * When a certificate has wildcard DNS SAN entries, to match a specific client, it should be + * configured with exact match type in the :ref:`string matcher `. + * For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com", + * it should be configured as shown below. + * + * .. code-block:: yaml + * + * match_subject_alt_names: + * exact: "api.example.com" + * + * .. attention:: + * + * Subject Alternative Names are easily spoofable and verifying only them is insecure, + * therefore this option must be used together with :ref:`trusted_ca + * `. + */ + 'match_subject_alt_names'?: (_envoy_type_matcher_v3_StringMatcher)[]; + /** + * Certificate trust chain verification mode. + */ + 'trust_chain_verification'?: (_envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_TrustChainVerification | keyof typeof _envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_TrustChainVerification); + /** + * If specified, updates of a file-based *trusted_ca* source will be triggered + * by this watch. This allows explicit control over the path watched, by + * default the parent directory of the filesystem path in *trusted_ca* is + * watched if this field is not specified. This only applies when a + * *CertificateValidationContext* is delivered by SDS with references to + * filesystem paths. See the :ref:`SDS key rotation ` + * documentation for further details. + */ + 'watched_directory'?: (_envoy_config_core_v3_WatchedDirectory | null); + /** + * The configuration of an extension specific certificate validator. + * If specified, all validation is done by the specified validator, + * and the behavior of all other validation settings is defined by the specified validator (and may be entirely ignored, unused, and unvalidated). + * Refer to the documentation for the specified validator. If you do not want a custom validation algorithm, do not set this field. + * [#extension-category: envoy.tls.cert_validator] + */ + 'custom_validator_config'?: (_envoy_config_core_v3_TypedExtensionConfig | null); + /** + * Certificate provider instance for fetching TLS certificates. + * + * Only one of *trusted_ca* and *ca_certificate_provider_instance* may be specified. + * [#not-implemented-hide:] + */ + 'ca_certificate_provider_instance'?: (_envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance | null); +} + +/** + * [#next-free-field: 14] + */ +export interface CertificateValidationContext__Output { + /** + * TLS certificate data containing certificate authority certificates to use in verifying + * a presented peer certificate (e.g. server certificate for clusters or client certificate + * for listeners). If not specified and a peer certificate is presented it will not be + * verified. By default, a client certificate is optional, unless one of the additional + * options (:ref:`require_client_certificate + * `, + * :ref:`verify_certificate_spki + * `, + * :ref:`verify_certificate_hash + * `, or + * :ref:`match_subject_alt_names + * `) is also + * specified. + * + * It can optionally contain certificate revocation lists, in which case Envoy will verify + * that the presented peer certificate has not been revoked by one of the included CRLs. Note + * that if a CRL is provided for any certificate authority in a trust chain, a CRL must be + * provided for all certificate authorities in that chain. Failure to do so will result in + * verification failure for both revoked and unrevoked certificates from that chain. + * + * See :ref:`the TLS overview ` for a list of common + * system CA locations. + * + * If *trusted_ca* is a filesystem path, a watch will be added to the parent + * directory for any file moves to support rotation. This currently only + * applies to dynamic secrets, when the *CertificateValidationContext* is + * delivered via SDS. + * + * Only one of *trusted_ca* and *ca_certificate_provider_instance* may be specified. + * + * [#next-major-version: This field and watched_directory below should ideally be moved into a + * separate sub-message, since there's no point in specifying the latter field without this one.] + */ + 'trusted_ca': (_envoy_config_core_v3_DataSource__Output | null); + /** + * An optional list of hex-encoded SHA-256 hashes. If specified, Envoy will verify that + * the SHA-256 of the DER-encoded presented certificate matches one of the specified values. + * + * A hex-encoded SHA-256 of the certificate can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -outform DER | openssl dgst -sha256 | cut -d" " -f2 + * df6ff72fe9116521268f6f2dd4966f51df479883fe7037b39f75916ac3049d1a + * + * A long hex-encoded and colon-separated SHA-256 (a.k.a. "fingerprint") of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -fingerprint -sha256 | cut -d"=" -f2 + * DF:6F:F7:2F:E9:11:65:21:26:8F:6F:2D:D4:96:6F:51:DF:47:98:83:FE:70:37:B3:9F:75:91:6A:C3:04:9D:1A + * + * Both of those formats are acceptable. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + */ + 'verify_certificate_hash': (string)[]; + /** + * An optional list of base64-encoded SHA-256 hashes. If specified, Envoy will verify that the + * SHA-256 of the DER-encoded Subject Public Key Information (SPKI) of the presented certificate + * matches one of the specified values. + * + * A base64-encoded SHA-256 of the Subject Public Key Information (SPKI) of the certificate + * can be generated with the following command: + * + * .. code-block:: bash + * + * $ openssl x509 -in path/to/client.crt -noout -pubkey + * | openssl pkey -pubin -outform DER + * | openssl dgst -sha256 -binary + * | openssl enc -base64 + * NvqYIYSbgK2vCJpQhObf77vv+bQWtc5ek5RIOwPiC9A= + * + * This is the format used in HTTP Public Key Pinning. + * + * When both: + * :ref:`verify_certificate_hash + * ` and + * :ref:`verify_certificate_spki + * ` are specified, + * a hash matching value from either of the lists will result in the certificate being accepted. + * + * .. attention:: + * + * This option is preferred over :ref:`verify_certificate_hash + * `, + * because SPKI is tied to a private key, so it doesn't change when the certificate + * is renewed using the same private key. + */ + 'verify_certificate_spki': (string)[]; + /** + * [#not-implemented-hide:] Must present signed certificate time-stamp. + */ + 'require_signed_certificate_timestamp': (_google_protobuf_BoolValue__Output | null); + /** + * An optional `certificate revocation list + * `_ + * (in PEM format). If specified, Envoy will verify that the presented peer + * certificate has not been revoked by this CRL. If this DataSource contains + * multiple CRLs, all of them will be used. Note that if a CRL is provided + * for any certificate authority in a trust chain, a CRL must be provided + * for all certificate authorities in that chain. Failure to do so will + * result in verification failure for both revoked and unrevoked certificates + * from that chain. + */ + 'crl': (_envoy_config_core_v3_DataSource__Output | null); + /** + * If specified, Envoy will not reject expired certificates. + */ + 'allow_expired_certificate': (boolean); + /** + * An optional list of Subject Alternative name matchers. If specified, Envoy will verify that the + * Subject Alternative Name of the presented certificate matches one of the specified matchers. + * + * When a certificate has wildcard DNS SAN entries, to match a specific client, it should be + * configured with exact match type in the :ref:`string matcher `. + * For example if the certificate has "\*.example.com" as DNS SAN entry, to allow only "api.example.com", + * it should be configured as shown below. + * + * .. code-block:: yaml + * + * match_subject_alt_names: + * exact: "api.example.com" + * + * .. attention:: + * + * Subject Alternative Names are easily spoofable and verifying only them is insecure, + * therefore this option must be used together with :ref:`trusted_ca + * `. + */ + 'match_subject_alt_names': (_envoy_type_matcher_v3_StringMatcher__Output)[]; + /** + * Certificate trust chain verification mode. + */ + 'trust_chain_verification': (keyof typeof _envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext_TrustChainVerification); + /** + * If specified, updates of a file-based *trusted_ca* source will be triggered + * by this watch. This allows explicit control over the path watched, by + * default the parent directory of the filesystem path in *trusted_ca* is + * watched if this field is not specified. This only applies when a + * *CertificateValidationContext* is delivered by SDS with references to + * filesystem paths. See the :ref:`SDS key rotation ` + * documentation for further details. + */ + 'watched_directory': (_envoy_config_core_v3_WatchedDirectory__Output | null); + /** + * The configuration of an extension specific certificate validator. + * If specified, all validation is done by the specified validator, + * and the behavior of all other validation settings is defined by the specified validator (and may be entirely ignored, unused, and unvalidated). + * Refer to the documentation for the specified validator. If you do not want a custom validation algorithm, do not set this field. + * [#extension-category: envoy.tls.cert_validator] + */ + 'custom_validator_config': (_envoy_config_core_v3_TypedExtensionConfig__Output | null); + /** + * Certificate provider instance for fetching TLS certificates. + * + * Only one of *trusted_ca* and *ca_certificate_provider_instance* may be specified. + * [#not-implemented-hide:] + */ + 'ca_certificate_provider_instance': (_envoy_extensions_transport_sockets_tls_v3_CertificateProviderPluginInstance__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/GenericSecret.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/GenericSecret.ts new file mode 100644 index 000000000..b206fb13a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/GenericSecret.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/secret.proto + +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../../envoy/config/core/v3/DataSource'; + +export interface GenericSecret { + /** + * Secret of generic type and is available to filters. + */ + 'secret'?: (_envoy_config_core_v3_DataSource | null); +} + +export interface GenericSecret__Output { + /** + * Secret of generic type and is available to filters. + */ + 'secret': (_envoy_config_core_v3_DataSource__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/PrivateKeyProvider.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/PrivateKeyProvider.ts new file mode 100644 index 000000000..b4a2ad933 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/PrivateKeyProvider.ts @@ -0,0 +1,39 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../../google/protobuf/Any'; + +/** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ +export interface PrivateKeyProvider { + /** + * Private key method provider name. The name must match a + * supported private key method provider type. + */ + 'provider_name'?: (string); + 'typed_config'?: (_google_protobuf_Any | null); + /** + * Private key method provider specific configuration. + */ + 'config_type'?: "typed_config"; +} + +/** + * BoringSSL private key method configuration. The private key methods are used for external + * (potentially asynchronous) signing and decryption operations. Some use cases for private key + * methods would be TPM support and TLS acceleration. + */ +export interface PrivateKeyProvider__Output { + /** + * Private key method provider name. The name must match a + * supported private key method provider type. + */ + 'provider_name': (string); + 'typed_config'?: (_google_protobuf_Any__Output | null); + /** + * Private key method provider specific configuration. + */ + 'config_type': "typed_config"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/SdsSecretConfig.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/SdsSecretConfig.ts new file mode 100644 index 000000000..38b850c50 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/SdsSecretConfig.ts @@ -0,0 +1,23 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/secret.proto + +import type { ConfigSource as _envoy_config_core_v3_ConfigSource, ConfigSource__Output as _envoy_config_core_v3_ConfigSource__Output } from '../../../../../envoy/config/core/v3/ConfigSource'; + +export interface SdsSecretConfig { + /** + * Name by which the secret can be uniquely referred to. When both name and config are specified, + * then secret can be fetched and/or reloaded via SDS. When only name is specified, then secret + * will be loaded from static resources. + */ + 'name'?: (string); + 'sds_config'?: (_envoy_config_core_v3_ConfigSource | null); +} + +export interface SdsSecretConfig__Output { + /** + * Name by which the secret can be uniquely referred to. When both name and config are specified, + * then secret can be fetched and/or reloaded via SDS. When only name is specified, then secret + * will be loaded from static resources. + */ + 'name': (string); + 'sds_config': (_envoy_config_core_v3_ConfigSource__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/Secret.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/Secret.ts new file mode 100644 index 000000000..c86957da5 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/Secret.ts @@ -0,0 +1,36 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/secret.proto + +import type { TlsCertificate as _envoy_extensions_transport_sockets_tls_v3_TlsCertificate, TlsCertificate__Output as _envoy_extensions_transport_sockets_tls_v3_TlsCertificate__Output } from '../../../../../envoy/extensions/transport_sockets/tls/v3/TlsCertificate'; +import type { TlsSessionTicketKeys as _envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys, TlsSessionTicketKeys__Output as _envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys__Output } from '../../../../../envoy/extensions/transport_sockets/tls/v3/TlsSessionTicketKeys'; +import type { CertificateValidationContext as _envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext, CertificateValidationContext__Output as _envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext__Output } from '../../../../../envoy/extensions/transport_sockets/tls/v3/CertificateValidationContext'; +import type { GenericSecret as _envoy_extensions_transport_sockets_tls_v3_GenericSecret, GenericSecret__Output as _envoy_extensions_transport_sockets_tls_v3_GenericSecret__Output } from '../../../../../envoy/extensions/transport_sockets/tls/v3/GenericSecret'; + +/** + * [#next-free-field: 6] + */ +export interface Secret { + /** + * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + */ + 'name'?: (string); + 'tls_certificate'?: (_envoy_extensions_transport_sockets_tls_v3_TlsCertificate | null); + 'session_ticket_keys'?: (_envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys | null); + 'validation_context'?: (_envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext | null); + 'generic_secret'?: (_envoy_extensions_transport_sockets_tls_v3_GenericSecret | null); + 'type'?: "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; +} + +/** + * [#next-free-field: 6] + */ +export interface Secret__Output { + /** + * Name (FQDN, UUID, SPKI, SHA256, etc.) by which the secret can be uniquely referred to. + */ + 'name': (string); + 'tls_certificate'?: (_envoy_extensions_transport_sockets_tls_v3_TlsCertificate__Output | null); + 'session_ticket_keys'?: (_envoy_extensions_transport_sockets_tls_v3_TlsSessionTicketKeys__Output | null); + 'validation_context'?: (_envoy_extensions_transport_sockets_tls_v3_CertificateValidationContext__Output | null); + 'generic_secret'?: (_envoy_extensions_transport_sockets_tls_v3_GenericSecret__Output | null); + 'type': "tls_certificate"|"session_ticket_keys"|"validation_context"|"generic_secret"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsCertificate.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsCertificate.ts new file mode 100644 index 000000000..ce8046e95 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsCertificate.ts @@ -0,0 +1,127 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../../envoy/config/core/v3/DataSource'; +import type { PrivateKeyProvider as _envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider, PrivateKeyProvider__Output as _envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider__Output } from '../../../../../envoy/extensions/transport_sockets/tls/v3/PrivateKeyProvider'; +import type { WatchedDirectory as _envoy_config_core_v3_WatchedDirectory, WatchedDirectory__Output as _envoy_config_core_v3_WatchedDirectory__Output } from '../../../../../envoy/config/core/v3/WatchedDirectory'; + +/** + * [#next-free-field: 8] + */ +export interface TlsCertificate { + /** + * The TLS certificate chain. + * + * If *certificate_chain* is a filesystem path, a watch will be added to the + * parent directory for any file moves to support rotation. This currently + * only applies to dynamic secrets, when the *TlsCertificate* is delivered via + * SDS. + */ + 'certificate_chain'?: (_envoy_config_core_v3_DataSource | null); + /** + * The TLS private key. + * + * If *private_key* is a filesystem path, a watch will be added to the parent + * directory for any file moves to support rotation. This currently only + * applies to dynamic secrets, when the *TlsCertificate* is delivered via SDS. + */ + 'private_key'?: (_envoy_config_core_v3_DataSource | null); + /** + * The password to decrypt the TLS private key. If this field is not set, it is assumed that the + * TLS private key is not password encrypted. + */ + 'password'?: (_envoy_config_core_v3_DataSource | null); + /** + * The OCSP response to be stapled with this certificate during the handshake. + * The response must be DER-encoded and may only be provided via ``filename`` or + * ``inline_bytes``. The response may pertain to only one certificate. + */ + 'ocsp_staple'?: (_envoy_config_core_v3_DataSource | null); + /** + * [#not-implemented-hide:] + */ + 'signed_certificate_timestamp'?: (_envoy_config_core_v3_DataSource)[]; + /** + * BoringSSL private key method provider. This is an alternative to :ref:`private_key + * ` field. This can't be + * marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key + * ` and + * :ref:`private_key_provider + * ` fields will result in an + * error. + */ + 'private_key_provider'?: (_envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider | null); + /** + * If specified, updates of file-based *certificate_chain* and *private_key* + * sources will be triggered by this watch. The certificate/key pair will be + * read together and validated for atomic read consistency (i.e. no + * intervening modification occurred between cert/key read, verified by file + * hash comparisons). This allows explicit control over the path watched, by + * default the parent directories of the filesystem paths in + * *certificate_chain* and *private_key* are watched if this field is not + * specified. This only applies when a *TlsCertificate* is delivered by SDS + * with references to filesystem paths. See the :ref:`SDS key rotation + * ` documentation for further details. + */ + 'watched_directory'?: (_envoy_config_core_v3_WatchedDirectory | null); +} + +/** + * [#next-free-field: 8] + */ +export interface TlsCertificate__Output { + /** + * The TLS certificate chain. + * + * If *certificate_chain* is a filesystem path, a watch will be added to the + * parent directory for any file moves to support rotation. This currently + * only applies to dynamic secrets, when the *TlsCertificate* is delivered via + * SDS. + */ + 'certificate_chain': (_envoy_config_core_v3_DataSource__Output | null); + /** + * The TLS private key. + * + * If *private_key* is a filesystem path, a watch will be added to the parent + * directory for any file moves to support rotation. This currently only + * applies to dynamic secrets, when the *TlsCertificate* is delivered via SDS. + */ + 'private_key': (_envoy_config_core_v3_DataSource__Output | null); + /** + * The password to decrypt the TLS private key. If this field is not set, it is assumed that the + * TLS private key is not password encrypted. + */ + 'password': (_envoy_config_core_v3_DataSource__Output | null); + /** + * The OCSP response to be stapled with this certificate during the handshake. + * The response must be DER-encoded and may only be provided via ``filename`` or + * ``inline_bytes``. The response may pertain to only one certificate. + */ + 'ocsp_staple': (_envoy_config_core_v3_DataSource__Output | null); + /** + * [#not-implemented-hide:] + */ + 'signed_certificate_timestamp': (_envoy_config_core_v3_DataSource__Output)[]; + /** + * BoringSSL private key method provider. This is an alternative to :ref:`private_key + * ` field. This can't be + * marked as ``oneof`` due to API compatibility reasons. Setting both :ref:`private_key + * ` and + * :ref:`private_key_provider + * ` fields will result in an + * error. + */ + 'private_key_provider': (_envoy_extensions_transport_sockets_tls_v3_PrivateKeyProvider__Output | null); + /** + * If specified, updates of file-based *certificate_chain* and *private_key* + * sources will be triggered by this watch. The certificate/key pair will be + * read together and validated for atomic read consistency (i.e. no + * intervening modification occurred between cert/key read, verified by file + * hash comparisons). This allows explicit control over the path watched, by + * default the parent directories of the filesystem paths in + * *certificate_chain* and *private_key* are watched if this field is not + * specified. This only applies when a *TlsCertificate* is delivered by SDS + * with references to filesystem paths. See the :ref:`SDS key rotation + * ` documentation for further details. + */ + 'watched_directory': (_envoy_config_core_v3_WatchedDirectory__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsParameters.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsParameters.ts new file mode 100644 index 000000000..e68464c8b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsParameters.ts @@ -0,0 +1,211 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + + +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + +export enum _envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol { + /** + * Envoy will choose the optimal TLS version. + */ + TLS_AUTO = 0, + /** + * TLS 1.0 + */ + TLSv1_0 = 1, + /** + * TLS 1.1 + */ + TLSv1_1 = 2, + /** + * TLS 1.2 + */ + TLSv1_2 = 3, + /** + * TLS 1.3 + */ + TLSv1_3 = 4, +} + +export interface TlsParameters { + /** + * Minimum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_0`` for + * servers. + */ + 'tls_minimum_protocol_version'?: (_envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol | keyof typeof _envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol); + /** + * Maximum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_3`` for + * servers. + */ + 'tls_maximum_protocol_version'?: (_envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol | keyof typeof _envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol); + /** + * If specified, the TLS listener will only support the specified `cipher list + * `_ + * when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). + * + * If not specified, a default list will be used. Defaults are different for server (downstream) and + * client (upstream) TLS configurations. + * + * In non-FIPS builds, the default server cipher list is: + * + * .. code-block:: none + * + * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + * + * In builds using :ref:`BoringSSL FIPS `, the default server cipher list is: + * + * .. code-block:: none + * + * ECDHE-ECDSA-AES128-GCM-SHA256 + * ECDHE-RSA-AES128-GCM-SHA256 + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + * + * In non-FIPS builds, the default client cipher list is: + * + * .. code-block:: none + * + * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * + * In builds using :ref:`BoringSSL FIPS `, the default client cipher list is: + * + * .. code-block:: none + * + * ECDHE-ECDSA-AES128-GCM-SHA256 + * ECDHE-RSA-AES128-GCM-SHA256 + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + */ + 'cipher_suites'?: (string)[]; + /** + * If specified, the TLS connection will only support the specified ECDH + * curves. If not specified, the default curves will be used. + * + * In non-FIPS builds, the default curves are: + * + * .. code-block:: none + * + * X25519 + * P-256 + * + * In builds using :ref:`BoringSSL FIPS `, the default curve is: + * + * .. code-block:: none + * + * P-256 + */ + 'ecdh_curves'?: (string)[]; +} + +export interface TlsParameters__Output { + /** + * Minimum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_0`` for + * servers. + */ + 'tls_minimum_protocol_version': (keyof typeof _envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol); + /** + * Maximum TLS protocol version. By default, it's ``TLSv1_2`` for clients and ``TLSv1_3`` for + * servers. + */ + 'tls_maximum_protocol_version': (keyof typeof _envoy_extensions_transport_sockets_tls_v3_TlsParameters_TlsProtocol); + /** + * If specified, the TLS listener will only support the specified `cipher list + * `_ + * when negotiating TLS 1.0-1.2 (this setting has no effect when negotiating TLS 1.3). + * + * If not specified, a default list will be used. Defaults are different for server (downstream) and + * client (upstream) TLS configurations. + * + * In non-FIPS builds, the default server cipher list is: + * + * .. code-block:: none + * + * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + * + * In builds using :ref:`BoringSSL FIPS `, the default server cipher list is: + * + * .. code-block:: none + * + * ECDHE-ECDSA-AES128-GCM-SHA256 + * ECDHE-RSA-AES128-GCM-SHA256 + * ECDHE-ECDSA-AES128-SHA + * ECDHE-RSA-AES128-SHA + * AES128-GCM-SHA256 + * AES128-SHA + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * ECDHE-ECDSA-AES256-SHA + * ECDHE-RSA-AES256-SHA + * AES256-GCM-SHA384 + * AES256-SHA + * + * In non-FIPS builds, the default client cipher list is: + * + * .. code-block:: none + * + * [ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305] + * [ECDHE-RSA-AES128-GCM-SHA256|ECDHE-RSA-CHACHA20-POLY1305] + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + * + * In builds using :ref:`BoringSSL FIPS `, the default client cipher list is: + * + * .. code-block:: none + * + * ECDHE-ECDSA-AES128-GCM-SHA256 + * ECDHE-RSA-AES128-GCM-SHA256 + * ECDHE-ECDSA-AES256-GCM-SHA384 + * ECDHE-RSA-AES256-GCM-SHA384 + */ + 'cipher_suites': (string)[]; + /** + * If specified, the TLS connection will only support the specified ECDH + * curves. If not specified, the default curves will be used. + * + * In non-FIPS builds, the default curves are: + * + * .. code-block:: none + * + * X25519 + * P-256 + * + * In builds using :ref:`BoringSSL FIPS `, the default curve is: + * + * .. code-block:: none + * + * P-256 + */ + 'ecdh_curves': (string)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsSessionTicketKeys.ts b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsSessionTicketKeys.ts new file mode 100644 index 000000000..152bccac7 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/extensions/transport_sockets/tls/v3/TlsSessionTicketKeys.ts @@ -0,0 +1,61 @@ +// Original file: deps/envoy-api/envoy/extensions/transport_sockets/tls/v3/common.proto + +import type { DataSource as _envoy_config_core_v3_DataSource, DataSource__Output as _envoy_config_core_v3_DataSource__Output } from '../../../../../envoy/config/core/v3/DataSource'; + +export interface TlsSessionTicketKeys { + /** + * Keys for encrypting and decrypting TLS session tickets. The + * first key in the array contains the key to encrypt all new sessions created by this context. + * All keys are candidates for decrypting received tickets. This allows for easy rotation of keys + * by, for example, putting the new key first, and the previous key second. + * + * If :ref:`session_ticket_keys ` + * is not specified, the TLS library will still support resuming sessions via tickets, but it will + * use an internally-generated and managed key, so sessions cannot be resumed across hot restarts + * or on different hosts. + * + * Each key must contain exactly 80 bytes of cryptographically-secure random data. For + * example, the output of ``openssl rand 80``. + * + * .. attention:: + * + * Using this feature has serious security considerations and risks. Improper handling of keys + * may result in loss of secrecy in connections, even if ciphers supporting perfect forward + * secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some + * discussion. To minimize the risk, you must: + * + * * Keep the session ticket keys at least as secure as your TLS certificate private keys + * * Rotate session ticket keys at least daily, and preferably hourly + * * Always generate keys using a cryptographically-secure random data source + */ + 'keys'?: (_envoy_config_core_v3_DataSource)[]; +} + +export interface TlsSessionTicketKeys__Output { + /** + * Keys for encrypting and decrypting TLS session tickets. The + * first key in the array contains the key to encrypt all new sessions created by this context. + * All keys are candidates for decrypting received tickets. This allows for easy rotation of keys + * by, for example, putting the new key first, and the previous key second. + * + * If :ref:`session_ticket_keys ` + * is not specified, the TLS library will still support resuming sessions via tickets, but it will + * use an internally-generated and managed key, so sessions cannot be resumed across hot restarts + * or on different hosts. + * + * Each key must contain exactly 80 bytes of cryptographically-secure random data. For + * example, the output of ``openssl rand 80``. + * + * .. attention:: + * + * Using this feature has serious security considerations and risks. Improper handling of keys + * may result in loss of secrecy in connections, even if ciphers supporting perfect forward + * secrecy are used. See https://www.imperialviolet.org/2013/06/27/botchingpfs.html for some + * discussion. To minimize the risk, you must: + * + * * Keep the session ticket keys at least as secure as your TLS certificate private keys + * * Rotate session ticket keys at least daily, and preferably hourly + * * Always generate keys using a cryptographically-secure random data source + */ + 'keys': (_envoy_config_core_v3_DataSource__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts index b42470516..6e900970a 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DeltaDiscoveryRequest.ts @@ -97,7 +97,7 @@ export interface DeltaDiscoveryRequest { */ 'response_nonce'?: (string); /** - * This is populated when the previous :ref:`DiscoveryResponse ` + * This is populated when the previous :ref:`DiscoveryResponse ` * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ @@ -198,7 +198,7 @@ export interface DeltaDiscoveryRequest__Output { */ 'response_nonce': (string); /** - * This is populated when the previous :ref:`DiscoveryResponse ` + * This is populated when the previous :ref:`DiscoveryResponse ` * failed to update configuration. The *message* field in *error_details* * provides the Envoy internal exception related to the failure. */ diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts index b30930b6f..f392ab8ae 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v3/DiscoveryRequest.ts @@ -48,7 +48,7 @@ export interface DiscoveryRequest { */ 'response_nonce'?: (string); /** - * This is populated when the previous :ref:`DiscoveryResponse ` + * This is populated when the previous :ref:`DiscoveryResponse ` * failed to update configuration. The *message* field in *error_details* provides the Envoy * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. @@ -101,7 +101,7 @@ export interface DiscoveryRequest__Output { */ 'response_nonce': (string); /** - * This is populated when the previous :ref:`DiscoveryResponse ` + * This is populated when the previous :ref:`DiscoveryResponse ` * failed to update configuration. The *message* field in *error_details* provides the Envoy * internal exception related to the failure. It is only intended for consumption during manual * debugging, the string provided is not guaranteed to be stable across Envoy versions. diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts index c39658cde..40f561870 100644 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts +++ b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v3/LoadStatsResponse.ts @@ -31,7 +31,7 @@ export interface LoadStatsResponse { /** * If true, the client should send all clusters it knows about. * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their - * :ref:`client_features` field will honor this field. + * :ref:`client_features` field will honor this field. */ 'send_all_clusters'?: (boolean); } @@ -65,7 +65,7 @@ export interface LoadStatsResponse__Output { /** * If true, the client should send all clusters it knows about. * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their - * :ref:`client_features` field will honor this field. + * :ref:`client_features` field will honor this field. */ 'send_all_clusters': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfig.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfig.ts new file mode 100644 index 000000000..ba6b25b4c --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfig.ts @@ -0,0 +1,159 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +import type { Node as _envoy_config_core_v3_Node, Node__Output as _envoy_config_core_v3_Node__Output } from '../../../../envoy/config/core/v3/Node'; +import type { PerXdsConfig as _envoy_service_status_v3_PerXdsConfig, PerXdsConfig__Output as _envoy_service_status_v3_PerXdsConfig__Output } from '../../../../envoy/service/status/v3/PerXdsConfig'; +import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; +import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../../google/protobuf/Timestamp'; +import type { ConfigStatus as _envoy_service_status_v3_ConfigStatus } from '../../../../envoy/service/status/v3/ConfigStatus'; +import type { ClientResourceStatus as _envoy_admin_v3_ClientResourceStatus } from '../../../../envoy/admin/v3/ClientResourceStatus'; +import type { UpdateFailureState as _envoy_admin_v3_UpdateFailureState, UpdateFailureState__Output as _envoy_admin_v3_UpdateFailureState__Output } from '../../../../envoy/admin/v3/UpdateFailureState'; + +/** + * GenericXdsConfig is used to specify the config status and the dump + * of any xDS resource identified by their type URL. It is the generalized + * version of the now deprecated ListenersConfigDump, ClustersConfigDump etc + * [#next-free-field: 10] + */ +export interface _envoy_service_status_v3_ClientConfig_GenericXdsConfig { + /** + * Type_url represents the fully qualified name of xDS resource type + * like envoy.v3.Cluster, envoy.v3.ClusterLoadAssignment etc. + */ + 'type_url'?: (string); + /** + * Name of the xDS resource + */ + 'name'?: (string); + /** + * This is the :ref:`version_info ` + * in the last processed xDS discovery response. If there are only + * static bootstrap listeners, this field will be "" + */ + 'version_info'?: (string); + /** + * The xDS resource config. Actual content depends on the type + */ + 'xds_config'?: (_google_protobuf_Any | null); + /** + * Timestamp when the xDS resource was last updated + */ + 'last_updated'?: (_google_protobuf_Timestamp | null); + /** + * Per xDS resource config status. It is generated by management servers. + * It will not be present if the CSDS server is an xDS client. + */ + 'config_status'?: (_envoy_service_status_v3_ConfigStatus | keyof typeof _envoy_service_status_v3_ConfigStatus); + /** + * Per xDS resource status from the view of a xDS client + */ + 'client_status'?: (_envoy_admin_v3_ClientResourceStatus | keyof typeof _envoy_admin_v3_ClientResourceStatus); + /** + * Set if the last update failed, cleared after the next successful + * update. The *error_state* field contains the rejected version of + * this particular resource along with the reason and timestamp. For + * successfully updated or acknowledged resource, this field should + * be empty. + * [#not-implemented-hide:] + */ + 'error_state'?: (_envoy_admin_v3_UpdateFailureState | null); + /** + * Is static resource is true if it is specified in the config supplied + * through the file at the startup. + */ + 'is_static_resource'?: (boolean); +} + +/** + * GenericXdsConfig is used to specify the config status and the dump + * of any xDS resource identified by their type URL. It is the generalized + * version of the now deprecated ListenersConfigDump, ClustersConfigDump etc + * [#next-free-field: 10] + */ +export interface _envoy_service_status_v3_ClientConfig_GenericXdsConfig__Output { + /** + * Type_url represents the fully qualified name of xDS resource type + * like envoy.v3.Cluster, envoy.v3.ClusterLoadAssignment etc. + */ + 'type_url': (string); + /** + * Name of the xDS resource + */ + 'name': (string); + /** + * This is the :ref:`version_info ` + * in the last processed xDS discovery response. If there are only + * static bootstrap listeners, this field will be "" + */ + 'version_info': (string); + /** + * The xDS resource config. Actual content depends on the type + */ + 'xds_config': (_google_protobuf_Any__Output | null); + /** + * Timestamp when the xDS resource was last updated + */ + 'last_updated': (_google_protobuf_Timestamp__Output | null); + /** + * Per xDS resource config status. It is generated by management servers. + * It will not be present if the CSDS server is an xDS client. + */ + 'config_status': (keyof typeof _envoy_service_status_v3_ConfigStatus); + /** + * Per xDS resource status from the view of a xDS client + */ + 'client_status': (keyof typeof _envoy_admin_v3_ClientResourceStatus); + /** + * Set if the last update failed, cleared after the next successful + * update. The *error_state* field contains the rejected version of + * this particular resource along with the reason and timestamp. For + * successfully updated or acknowledged resource, this field should + * be empty. + * [#not-implemented-hide:] + */ + 'error_state': (_envoy_admin_v3_UpdateFailureState__Output | null); + /** + * Is static resource is true if it is specified in the config supplied + * through the file at the startup. + */ + 'is_static_resource': (boolean); +} + +/** + * All xds configs for a particular client. + */ +export interface ClientConfig { + /** + * Node for a particular client. + */ + 'node'?: (_envoy_config_core_v3_Node | null); + /** + * This field is deprecated in favor of generic_xds_configs which is + * much simpler and uniform in structure. + */ + 'xds_config'?: (_envoy_service_status_v3_PerXdsConfig)[]; + /** + * Represents generic xDS config and the exact config structure depends on + * the type URL (like Cluster if it is CDS) + */ + 'generic_xds_configs'?: (_envoy_service_status_v3_ClientConfig_GenericXdsConfig)[]; +} + +/** + * All xds configs for a particular client. + */ +export interface ClientConfig__Output { + /** + * Node for a particular client. + */ + 'node': (_envoy_config_core_v3_Node__Output | null); + /** + * This field is deprecated in favor of generic_xds_configs which is + * much simpler and uniform in structure. + */ + 'xds_config': (_envoy_service_status_v3_PerXdsConfig__Output)[]; + /** + * Represents generic xDS config and the exact config structure depends on + * the type URL (like Cluster if it is CDS) + */ + 'generic_xds_configs': (_envoy_service_status_v3_ClientConfig_GenericXdsConfig__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfigStatus.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfigStatus.ts new file mode 100644 index 000000000..104445a3f --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientConfigStatus.ts @@ -0,0 +1,26 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +/** + * Config status from a client-side view. + */ +export enum ClientConfigStatus { + /** + * Config status is not available/unknown. + */ + CLIENT_UNKNOWN = 0, + /** + * Client requested the config but hasn't received any config from management + * server yet. + */ + CLIENT_REQUESTED = 1, + /** + * Client received the config and replied with ACK. + */ + CLIENT_ACKED = 2, + /** + * Client received the config and replied with NACK. Notably, the attached + * config dump is not the NACKed version, but the most recent accepted one. If + * no config is accepted yet, the attached config dump will be empty. + */ + CLIENT_NACKED = 3, +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusDiscoveryService.ts new file mode 100644 index 000000000..7402fb69b --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusDiscoveryService.ts @@ -0,0 +1,45 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { ClientStatusRequest as _envoy_service_status_v3_ClientStatusRequest, ClientStatusRequest__Output as _envoy_service_status_v3_ClientStatusRequest__Output } from '../../../../envoy/service/status/v3/ClientStatusRequest'; +import type { ClientStatusResponse as _envoy_service_status_v3_ClientStatusResponse, ClientStatusResponse__Output as _envoy_service_status_v3_ClientStatusResponse__Output } from '../../../../envoy/service/status/v3/ClientStatusResponse'; + +/** + * CSDS is Client Status Discovery Service. It can be used to get the status of + * an xDS-compliant client from the management server's point of view. It can + * also be used to get the current xDS states directly from the client. + */ +export interface ClientStatusDiscoveryServiceClient extends grpc.Client { + FetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + FetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + FetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + FetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + fetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + fetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + fetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + fetchClientStatus(argument: _envoy_service_status_v3_ClientStatusRequest, callback: grpc.requestCallback<_envoy_service_status_v3_ClientStatusResponse__Output>): grpc.ClientUnaryCall; + + StreamClientStatus(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_status_v3_ClientStatusRequest, _envoy_service_status_v3_ClientStatusResponse__Output>; + StreamClientStatus(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_status_v3_ClientStatusRequest, _envoy_service_status_v3_ClientStatusResponse__Output>; + streamClientStatus(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_status_v3_ClientStatusRequest, _envoy_service_status_v3_ClientStatusResponse__Output>; + streamClientStatus(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_status_v3_ClientStatusRequest, _envoy_service_status_v3_ClientStatusResponse__Output>; + +} + +/** + * CSDS is Client Status Discovery Service. It can be used to get the status of + * an xDS-compliant client from the management server's point of view. It can + * also be used to get the current xDS states directly from the client. + */ +export interface ClientStatusDiscoveryServiceHandlers extends grpc.UntypedServiceImplementation { + FetchClientStatus: grpc.handleUnaryCall<_envoy_service_status_v3_ClientStatusRequest__Output, _envoy_service_status_v3_ClientStatusResponse>; + + StreamClientStatus: grpc.handleBidiStreamingCall<_envoy_service_status_v3_ClientStatusRequest__Output, _envoy_service_status_v3_ClientStatusResponse>; + +} + +export interface ClientStatusDiscoveryServiceDefinition extends grpc.ServiceDefinition { + FetchClientStatus: MethodDefinition<_envoy_service_status_v3_ClientStatusRequest, _envoy_service_status_v3_ClientStatusResponse, _envoy_service_status_v3_ClientStatusRequest__Output, _envoy_service_status_v3_ClientStatusResponse__Output> + StreamClientStatus: MethodDefinition<_envoy_service_status_v3_ClientStatusRequest, _envoy_service_status_v3_ClientStatusResponse, _envoy_service_status_v3_ClientStatusRequest__Output, _envoy_service_status_v3_ClientStatusResponse__Output> +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusRequest.ts new file mode 100644 index 000000000..91adddacc --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusRequest.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +import type { NodeMatcher as _envoy_type_matcher_v3_NodeMatcher, NodeMatcher__Output as _envoy_type_matcher_v3_NodeMatcher__Output } from '../../../../envoy/type/matcher/v3/NodeMatcher'; +import type { Node as _envoy_config_core_v3_Node, Node__Output as _envoy_config_core_v3_Node__Output } from '../../../../envoy/config/core/v3/Node'; + +/** + * Request for client status of clients identified by a list of NodeMatchers. + */ +export interface ClientStatusRequest { + /** + * Management server can use these match criteria to identify clients. + * The match follows OR semantics. + */ + 'node_matchers'?: (_envoy_type_matcher_v3_NodeMatcher)[]; + /** + * The node making the csds request. + */ + 'node'?: (_envoy_config_core_v3_Node | null); +} + +/** + * Request for client status of clients identified by a list of NodeMatchers. + */ +export interface ClientStatusRequest__Output { + /** + * Management server can use these match criteria to identify clients. + * The match follows OR semantics. + */ + 'node_matchers': (_envoy_type_matcher_v3_NodeMatcher__Output)[]; + /** + * The node making the csds request. + */ + 'node': (_envoy_config_core_v3_Node__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusResponse.ts new file mode 100644 index 000000000..3611016ec --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ClientStatusResponse.ts @@ -0,0 +1,17 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +import type { ClientConfig as _envoy_service_status_v3_ClientConfig, ClientConfig__Output as _envoy_service_status_v3_ClientConfig__Output } from '../../../../envoy/service/status/v3/ClientConfig'; + +export interface ClientStatusResponse { + /** + * Client configs for the clients specified in the ClientStatusRequest. + */ + 'config'?: (_envoy_service_status_v3_ClientConfig)[]; +} + +export interface ClientStatusResponse__Output { + /** + * Client configs for the clients specified in the ClientStatusRequest. + */ + 'config': (_envoy_service_status_v3_ClientConfig__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ConfigStatus.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ConfigStatus.ts new file mode 100644 index 000000000..71db302c3 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/ConfigStatus.ts @@ -0,0 +1,30 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +/** + * Status of a config from a management server view. + */ +export enum ConfigStatus { + /** + * Status info is not available/unknown. + */ + UNKNOWN = 0, + /** + * Management server has sent the config to client and received ACK. + */ + SYNCED = 1, + /** + * Config is not sent. + */ + NOT_SENT = 2, + /** + * Management server has sent the config to client but hasn’t received + * ACK/NACK. + */ + STALE = 3, + /** + * Management server has sent the config to client but received NACK. The + * attached config dump will be the latest config (the rejected one), since + * it is the persisted version in the management server. + */ + ERROR = 4, +} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/status/v3/PerXdsConfig.ts b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/PerXdsConfig.ts new file mode 100644 index 000000000..947f1c81a --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/service/status/v3/PerXdsConfig.ts @@ -0,0 +1,67 @@ +// Original file: deps/envoy-api/envoy/service/status/v3/csds.proto + +import type { ConfigStatus as _envoy_service_status_v3_ConfigStatus } from '../../../../envoy/service/status/v3/ConfigStatus'; +import type { ListenersConfigDump as _envoy_admin_v3_ListenersConfigDump, ListenersConfigDump__Output as _envoy_admin_v3_ListenersConfigDump__Output } from '../../../../envoy/admin/v3/ListenersConfigDump'; +import type { ClustersConfigDump as _envoy_admin_v3_ClustersConfigDump, ClustersConfigDump__Output as _envoy_admin_v3_ClustersConfigDump__Output } from '../../../../envoy/admin/v3/ClustersConfigDump'; +import type { RoutesConfigDump as _envoy_admin_v3_RoutesConfigDump, RoutesConfigDump__Output as _envoy_admin_v3_RoutesConfigDump__Output } from '../../../../envoy/admin/v3/RoutesConfigDump'; +import type { ScopedRoutesConfigDump as _envoy_admin_v3_ScopedRoutesConfigDump, ScopedRoutesConfigDump__Output as _envoy_admin_v3_ScopedRoutesConfigDump__Output } from '../../../../envoy/admin/v3/ScopedRoutesConfigDump'; +import type { EndpointsConfigDump as _envoy_admin_v3_EndpointsConfigDump, EndpointsConfigDump__Output as _envoy_admin_v3_EndpointsConfigDump__Output } from '../../../../envoy/admin/v3/EndpointsConfigDump'; +import type { ClientConfigStatus as _envoy_service_status_v3_ClientConfigStatus } from '../../../../envoy/service/status/v3/ClientConfigStatus'; + +/** + * Detailed config (per xDS) with status. + * [#next-free-field: 8] + */ +export interface PerXdsConfig { + /** + * Config status generated by management servers. Will not be present if the + * CSDS server is an xDS client. + */ + 'status'?: (_envoy_service_status_v3_ConfigStatus | keyof typeof _envoy_service_status_v3_ConfigStatus); + 'listener_config'?: (_envoy_admin_v3_ListenersConfigDump | null); + 'cluster_config'?: (_envoy_admin_v3_ClustersConfigDump | null); + 'route_config'?: (_envoy_admin_v3_RoutesConfigDump | null); + 'scoped_route_config'?: (_envoy_admin_v3_ScopedRoutesConfigDump | null); + 'endpoint_config'?: (_envoy_admin_v3_EndpointsConfigDump | null); + /** + * Client config status is populated by xDS clients. Will not be present if + * the CSDS server is an xDS server. No matter what the client config status + * is, xDS clients should always dump the most recent accepted xDS config. + * + * .. attention:: + * This field is deprecated. Use :ref:`ClientResourceStatus + * ` for per-resource + * config status instead. + */ + 'client_status'?: (_envoy_service_status_v3_ClientConfigStatus | keyof typeof _envoy_service_status_v3_ClientConfigStatus); + 'per_xds_config'?: "listener_config"|"cluster_config"|"route_config"|"scoped_route_config"|"endpoint_config"; +} + +/** + * Detailed config (per xDS) with status. + * [#next-free-field: 8] + */ +export interface PerXdsConfig__Output { + /** + * Config status generated by management servers. Will not be present if the + * CSDS server is an xDS client. + */ + 'status': (keyof typeof _envoy_service_status_v3_ConfigStatus); + 'listener_config'?: (_envoy_admin_v3_ListenersConfigDump__Output | null); + 'cluster_config'?: (_envoy_admin_v3_ClustersConfigDump__Output | null); + 'route_config'?: (_envoy_admin_v3_RoutesConfigDump__Output | null); + 'scoped_route_config'?: (_envoy_admin_v3_ScopedRoutesConfigDump__Output | null); + 'endpoint_config'?: (_envoy_admin_v3_EndpointsConfigDump__Output | null); + /** + * Client config status is populated by xDS clients. Will not be present if + * the CSDS server is an xDS server. No matter what the client config status + * is, xDS clients should always dump the most recent accepted xDS config. + * + * .. attention:: + * This field is deprecated. Use :ref:`ClientResourceStatus + * ` for per-resource + * config status instead. + */ + 'client_status': (keyof typeof _envoy_service_status_v3_ClientConfigStatus); + 'per_xds_config': "listener_config"|"cluster_config"|"route_config"|"scoped_route_config"|"endpoint_config"; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/http/v3/PathTransformation.ts b/packages/grpc-js-xds/src/generated/envoy/type/http/v3/PathTransformation.ts new file mode 100644 index 000000000..4dc10efcb --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/http/v3/PathTransformation.ts @@ -0,0 +1,92 @@ +// Original file: deps/envoy-api/envoy/type/http/v3/path_transformation.proto + + +/** + * Determines if adjacent slashes are merged into one. A common use case is for a request path + * header. Using this option in `:ref: PathNormalizationOptions + * ` + * will allow incoming requests with path `//dir///file` to match against route with `prefix` + * match set to `/dir`. When using for header transformations, note that slash merging is not + * part of `HTTP spec `_ and is provided for convenience. + */ +export interface _envoy_type_http_v3_PathTransformation_Operation_MergeSlashes { +} + +/** + * Determines if adjacent slashes are merged into one. A common use case is for a request path + * header. Using this option in `:ref: PathNormalizationOptions + * ` + * will allow incoming requests with path `//dir///file` to match against route with `prefix` + * match set to `/dir`. When using for header transformations, note that slash merging is not + * part of `HTTP spec `_ and is provided for convenience. + */ +export interface _envoy_type_http_v3_PathTransformation_Operation_MergeSlashes__Output { +} + +/** + * Should text be normalized according to RFC 3986? This typically is used for path headers + * before any processing of requests by HTTP filters or routing. This applies percent-encoded + * normalization and path segment normalization. Fails on characters disallowed in URLs + * (e.g. NULLs). See `Normalization and Comparison + * `_ for details of normalization. Note that + * this options does not perform `case normalization + * `_ + */ +export interface _envoy_type_http_v3_PathTransformation_Operation_NormalizePathRFC3986 { +} + +/** + * Should text be normalized according to RFC 3986? This typically is used for path headers + * before any processing of requests by HTTP filters or routing. This applies percent-encoded + * normalization and path segment normalization. Fails on characters disallowed in URLs + * (e.g. NULLs). See `Normalization and Comparison + * `_ for details of normalization. Note that + * this options does not perform `case normalization + * `_ + */ +export interface _envoy_type_http_v3_PathTransformation_Operation_NormalizePathRFC3986__Output { +} + +/** + * A type of operation to alter text. + */ +export interface _envoy_type_http_v3_PathTransformation_Operation { + /** + * Enable path normalization per RFC 3986. + */ + 'normalize_path_rfc_3986'?: (_envoy_type_http_v3_PathTransformation_Operation_NormalizePathRFC3986 | null); + /** + * Enable merging adjacent slashes. + */ + 'merge_slashes'?: (_envoy_type_http_v3_PathTransformation_Operation_MergeSlashes | null); + 'operation_specifier'?: "normalize_path_rfc_3986"|"merge_slashes"; +} + +/** + * A type of operation to alter text. + */ +export interface _envoy_type_http_v3_PathTransformation_Operation__Output { + /** + * Enable path normalization per RFC 3986. + */ + 'normalize_path_rfc_3986'?: (_envoy_type_http_v3_PathTransformation_Operation_NormalizePathRFC3986__Output | null); + /** + * Enable merging adjacent slashes. + */ + 'merge_slashes'?: (_envoy_type_http_v3_PathTransformation_Operation_MergeSlashes__Output | null); + 'operation_specifier': "normalize_path_rfc_3986"|"merge_slashes"; +} + +export interface PathTransformation { + /** + * A list of operations to apply. Transformations will be performed in the order that they appear. + */ + 'operations'?: (_envoy_type_http_v3_PathTransformation_Operation)[]; +} + +export interface PathTransformation__Output { + /** + * A list of operations to apply. Transformations will be performed in the order that they appear. + */ + 'operations': (_envoy_type_http_v3_PathTransformation_Operation__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts index 58117faab..78d4f03da 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/MetadataMatcher.ts @@ -44,6 +44,10 @@ export interface MetadataMatcher { * The MetadataMatcher is matched if the value retrieved by path is matched to this value. */ 'value'?: (_envoy_type_matcher_v3_ValueMatcher | null); + /** + * If true, the match result will be inverted. + */ + 'invert'?: (boolean); } /** @@ -62,4 +66,8 @@ export interface MetadataMatcher__Output { * The MetadataMatcher is matched if the value retrieved by path is matched to this value. */ 'value': (_envoy_type_matcher_v3_ValueMatcher__Output | null); + /** + * If true, the match result will be inverted. + */ + 'invert': (boolean); } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/NodeMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/NodeMatcher.ts new file mode 100644 index 000000000..7e31b9753 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/NodeMatcher.ts @@ -0,0 +1,34 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/node.proto + +import type { StringMatcher as _envoy_type_matcher_v3_StringMatcher, StringMatcher__Output as _envoy_type_matcher_v3_StringMatcher__Output } from '../../../../envoy/type/matcher/v3/StringMatcher'; +import type { StructMatcher as _envoy_type_matcher_v3_StructMatcher, StructMatcher__Output as _envoy_type_matcher_v3_StructMatcher__Output } from '../../../../envoy/type/matcher/v3/StructMatcher'; + +/** + * Specifies the way to match a Node. + * The match follows AND semantics. + */ +export interface NodeMatcher { + /** + * Specifies match criteria on the node id. + */ + 'node_id'?: (_envoy_type_matcher_v3_StringMatcher | null); + /** + * Specifies match criteria on the node metadata. + */ + 'node_metadatas'?: (_envoy_type_matcher_v3_StructMatcher)[]; +} + +/** + * Specifies the way to match a Node. + * The match follows AND semantics. + */ +export interface NodeMatcher__Output { + /** + * Specifies match criteria on the node id. + */ + 'node_id': (_envoy_type_matcher_v3_StringMatcher__Output | null); + /** + * Specifies match criteria on the node metadata. + */ + 'node_metadatas': (_envoy_type_matcher_v3_StructMatcher__Output)[]; +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts index c89190510..7440746f1 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StringMatcher.ts @@ -38,8 +38,8 @@ export interface StringMatcher { */ 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher | null); /** - * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no - * effect for the safe_regex match. + * If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This + * has no effect for the safe_regex match. * For example, the matcher *data* will match both input string *Data* and *data* if set to true. */ 'ignore_case'?: (boolean); @@ -91,8 +91,8 @@ export interface StringMatcher__Output { */ 'safe_regex'?: (_envoy_type_matcher_v3_RegexMatcher__Output | null); /** - * If true, indicates the exact/prefix/suffix matching should be case insensitive. This has no - * effect for the safe_regex match. + * If true, indicates the exact/prefix/suffix/contains matching should be case insensitive. This + * has no effect for the safe_regex match. * For example, the matcher *data* will match both input string *Data* and *data* if set to true. */ 'ignore_case': (boolean); diff --git a/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StructMatcher.ts b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StructMatcher.ts new file mode 100644 index 000000000..141806489 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/envoy/type/matcher/v3/StructMatcher.ts @@ -0,0 +1,153 @@ +// Original file: deps/envoy-api/envoy/type/matcher/v3/struct.proto + +import type { ValueMatcher as _envoy_type_matcher_v3_ValueMatcher, ValueMatcher__Output as _envoy_type_matcher_v3_ValueMatcher__Output } from '../../../../envoy/type/matcher/v3/ValueMatcher'; + +/** + * Specifies the segment in a path to retrieve value from Struct. + */ +export interface _envoy_type_matcher_v3_StructMatcher_PathSegment { + /** + * If specified, use the key to retrieve the value in a Struct. + */ + 'key'?: (string); + 'segment'?: "key"; +} + +/** + * Specifies the segment in a path to retrieve value from Struct. + */ +export interface _envoy_type_matcher_v3_StructMatcher_PathSegment__Output { + /** + * If specified, use the key to retrieve the value in a Struct. + */ + 'key'?: (string); + 'segment': "key"; +} + +/** + * StructMatcher provides a general interface to check if a given value is matched in + * google.protobuf.Struct. It uses `path` to retrieve the value + * from the struct and then check if it's matched to the specified value. + * + * For example, for the following Struct: + * + * .. code-block:: yaml + * + * fields: + * a: + * struct_value: + * fields: + * b: + * struct_value: + * fields: + * c: + * string_value: pro + * t: + * list_value: + * values: + * - string_value: m + * - string_value: n + * + * The following MetadataMatcher is matched as the path [a, b, c] will retrieve a string value "pro" + * from the Metadata which is matched to the specified prefix match. + * + * .. code-block:: yaml + * + * path: + * - key: a + * - key: b + * - key: c + * value: + * string_match: + * prefix: pr + * + * The following StructMatcher is matched as the code will match one of the string values in the + * list at the path [a, t]. + * + * .. code-block:: yaml + * + * path: + * - key: a + * - key: t + * value: + * list_match: + * one_of: + * string_match: + * exact: m + * + * An example use of StructMatcher is to match metadata in envoy.v*.core.Node. + */ +export interface StructMatcher { + /** + * The path to retrieve the Value from the Struct. + */ + 'path'?: (_envoy_type_matcher_v3_StructMatcher_PathSegment)[]; + /** + * The StructMatcher is matched if the value retrieved by path is matched to this value. + */ + 'value'?: (_envoy_type_matcher_v3_ValueMatcher | null); +} + +/** + * StructMatcher provides a general interface to check if a given value is matched in + * google.protobuf.Struct. It uses `path` to retrieve the value + * from the struct and then check if it's matched to the specified value. + * + * For example, for the following Struct: + * + * .. code-block:: yaml + * + * fields: + * a: + * struct_value: + * fields: + * b: + * struct_value: + * fields: + * c: + * string_value: pro + * t: + * list_value: + * values: + * - string_value: m + * - string_value: n + * + * The following MetadataMatcher is matched as the path [a, b, c] will retrieve a string value "pro" + * from the Metadata which is matched to the specified prefix match. + * + * .. code-block:: yaml + * + * path: + * - key: a + * - key: b + * - key: c + * value: + * string_match: + * prefix: pr + * + * The following StructMatcher is matched as the code will match one of the string values in the + * list at the path [a, t]. + * + * .. code-block:: yaml + * + * path: + * - key: a + * - key: t + * value: + * list_match: + * one_of: + * string_match: + * exact: m + * + * An example use of StructMatcher is to match metadata in envoy.v*.core.Node. + */ +export interface StructMatcher__Output { + /** + * The path to retrieve the Value from the Struct. + */ + 'path': (_envoy_type_matcher_v3_StructMatcher_PathSegment__Output)[]; + /** + * The StructMatcher is matched if the value retrieved by path is matched to this value. + */ + 'value': (_envoy_type_matcher_v3_ValueMatcher__Output | null); +} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts index fcc43b07b..50b6690d3 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKey.ts @@ -27,7 +27,7 @@ export interface _envoy_type_metadata_v3_MetadataKey_PathSegment__Output { /** * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. + * :ref:`Metadata `. * * For example, for the following Metadata: * @@ -68,7 +68,7 @@ export interface MetadataKey { /** * MetadataKey provides a general interface using `key` and `path` to retrieve value from - * :ref:`Metadata `. + * :ref:`Metadata `. * * For example, for the following Metadata: * diff --git a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts index 2457b3f91..3ca368ccb 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/metadata/v3/MetadataKind.ts @@ -2,27 +2,27 @@ /** - * Represents metadata from :ref:`the upstream cluster`. + * Represents metadata from :ref:`the upstream cluster`. */ export interface _envoy_type_metadata_v3_MetadataKind_Cluster { } /** - * Represents metadata from :ref:`the upstream cluster`. + * Represents metadata from :ref:`the upstream cluster`. */ export interface _envoy_type_metadata_v3_MetadataKind_Cluster__Output { } /** * Represents metadata from :ref:`the upstream - * host`. + * host`. */ export interface _envoy_type_metadata_v3_MetadataKind_Host { } /** * Represents metadata from :ref:`the upstream - * host`. + * host`. */ export interface _envoy_type_metadata_v3_MetadataKind_Host__Output { } @@ -40,13 +40,13 @@ export interface _envoy_type_metadata_v3_MetadataKind_Request__Output { } /** - * Represents metadata from :ref:`the route`. + * Represents metadata from :ref:`the route`. */ export interface _envoy_type_metadata_v3_MetadataKind_Route { } /** - * Represents metadata from :ref:`the route`. + * Represents metadata from :ref:`the route`. */ export interface _envoy_type_metadata_v3_MetadataKind_Route__Output { } diff --git a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts index d5fe26ed5..34ac26f8c 100644 --- a/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts +++ b/packages/grpc-js-xds/src/generated/envoy/type/tracing/v3/CustomTag.ts @@ -89,8 +89,8 @@ export interface _envoy_type_tracing_v3_CustomTag_Literal__Output { /** * Metadata type custom tag using - * :ref:`MetadataKey ` to retrieve the protobuf value - * from :ref:`Metadata `, and populate the tag value with + * :ref:`MetadataKey ` to retrieve the protobuf value + * from :ref:`Metadata `, and populate the tag value with * `the canonical JSON `_ * representation of it. */ @@ -113,8 +113,8 @@ export interface _envoy_type_tracing_v3_CustomTag_Metadata { /** * Metadata type custom tag using - * :ref:`MetadataKey ` to retrieve the protobuf value - * from :ref:`Metadata `, and populate the tag value with + * :ref:`MetadataKey ` to retrieve the protobuf value + * from :ref:`Metadata `, and populate the tag value with * `the canonical JSON `_ * representation of it. */ diff --git a/packages/grpc-js-xds/src/generated/fault.ts b/packages/grpc-js-xds/src/generated/fault.ts index 0f60fc224..896382e50 100644 --- a/packages/grpc-js-xds/src/generated/fault.ts +++ b/packages/grpc-js-xds/src/generated/fault.ts @@ -38,6 +38,7 @@ export interface ProtoGrpcType { Node: MessageTypeDefinition Pipe: MessageTypeDefinition ProxyProtocolConfig: MessageTypeDefinition + QueryParameter: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -68,6 +69,7 @@ export interface ProtoGrpcType { HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition InternalRedirectPolicy: MessageTypeDefinition + NonForwardingAction: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition @@ -105,10 +107,14 @@ export interface ProtoGrpcType { type: { matcher: { v3: { + DoubleMatcher: MessageTypeDefinition + ListMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition + MetadataMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition RegexMatcher: MessageTypeDefinition StringMatcher: MessageTypeDefinition + ValueMatcher: MessageTypeDefinition } } metadata: { @@ -222,6 +228,7 @@ export interface ProtoGrpcType { core: { v3: { Authority: MessageTypeDefinition + ContextParams: MessageTypeDefinition } } } diff --git a/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts b/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts new file mode 100644 index 000000000..2b6490be6 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/CustomHttpPattern.ts @@ -0,0 +1,30 @@ +// Original file: deps/googleapis/google/api/http.proto + + +/** + * A custom pattern is used for defining custom HTTP verb. + */ +export interface CustomHttpPattern { + /** + * The name of this custom HTTP verb. + */ + 'kind'?: (string); + /** + * The path matched by this custom verb. + */ + 'path'?: (string); +} + +/** + * A custom pattern is used for defining custom HTTP verb. + */ +export interface CustomHttpPattern__Output { + /** + * The name of this custom HTTP verb. + */ + 'kind': (string); + /** + * The path matched by this custom verb. + */ + 'path': (string); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/Http.ts b/packages/grpc-js-xds/src/generated/google/api/Http.ts new file mode 100644 index 000000000..e9b3cb309 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/Http.ts @@ -0,0 +1,49 @@ +// Original file: deps/googleapis/google/api/http.proto + +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ +export interface Http { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + */ + 'rules'?: (_google_api_HttpRule)[]; + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + */ + 'fully_decode_reserved_expansion'?: (boolean); +} + +/** + * Defines the HTTP configuration for an API service. It contains a list of + * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method + * to one or more HTTP REST API methods. + */ +export interface Http__Output { + /** + * A list of HTTP configuration rules that apply to individual API methods. + * + * **NOTE:** All service configuration rules follow "last one wins" order. + */ + 'rules': (_google_api_HttpRule__Output)[]; + /** + * When set to true, URL path parameters will be fully URI-decoded except in + * cases of single segment matches in reserved expansion, where "%2F" will be + * left encoded. + * + * The default behavior is to not decode RFC 6570 reserved characters in multi + * segment matches. + */ + 'fully_decode_reserved_expansion': (boolean); +} diff --git a/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts new file mode 100644 index 000000000..243a99f80 --- /dev/null +++ b/packages/grpc-js-xds/src/generated/google/api/HttpRule.ts @@ -0,0 +1,680 @@ +// Original file: deps/googleapis/google/api/http.proto + +import type { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; + +/** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ +export interface HttpRule { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + */ + 'selector'?: (string); + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + */ + 'get'?: (string); + /** + * Maps to HTTP PUT. Used for replacing a resource. + */ + 'put'?: (string); + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + */ + 'post'?: (string); + /** + * Maps to HTTP DELETE. Used for deleting a resource. + */ + 'delete'?: (string); + /** + * Maps to HTTP PATCH. Used for updating a resource. + */ + 'patch'?: (string); + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + */ + 'body'?: (string); + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + */ + 'custom'?: (_google_api_CustomHttpPattern | null); + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + */ + 'additional_bindings'?: (_google_api_HttpRule)[]; + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + */ + 'response_body'?: (string); + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + */ + 'pattern'?: "get"|"put"|"post"|"delete"|"patch"|"custom"; +} + +/** + * # gRPC Transcoding + * + * gRPC Transcoding is a feature for mapping between a gRPC method and one or + * more HTTP REST endpoints. It allows developers to build a single API service + * that supports both gRPC APIs and REST APIs. Many systems, including [Google + * APIs](https://github.com/googleapis/googleapis), + * [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC + * Gateway](https://github.com/grpc-ecosystem/grpc-gateway), + * and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature + * and use it for large scale production services. + * + * `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies + * how different portions of the gRPC request message are mapped to the URL + * path, URL query parameters, and HTTP request body. It also controls how the + * gRPC response message is mapped to the HTTP response body. `HttpRule` is + * typically specified as an `google.api.http` annotation on the gRPC method. + * + * Each mapping specifies a URL path template and an HTTP method. The path + * template may refer to one or more fields in the gRPC request message, as long + * as each field is a non-repeated field with a primitive (non-message) type. + * The path template controls how fields of the request message are mapped to + * the URL path. + * + * Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/{name=messages/*}" + * }; + * } + * } + * message GetMessageRequest { + * string name = 1; // Mapped to URL path. + * } + * message Message { + * string text = 1; // The resource content. + * } + * + * This enables an HTTP REST to gRPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(name: "messages/123456")` + * + * Any fields in the request message which are not bound by the path template + * automatically become HTTP query parameters if there is no HTTP request body. + * For example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get:"/v1/messages/{message_id}" + * }; + * } + * } + * message GetMessageRequest { + * message SubMessage { + * string subfield = 1; + * } + * string message_id = 1; // Mapped to URL path. + * int64 revision = 2; // Mapped to URL query parameter `revision`. + * SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`. + * } + * + * This enables a HTTP JSON to RPC mapping as below: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456?revision=2&sub.subfield=foo` | + * `GetMessage(message_id: "123456" revision: 2 sub: SubMessage(subfield: + * "foo"))` + * + * Note that fields which are mapped to URL query parameters must have a + * primitive type or a repeated primitive type or a non-repeated message type. + * In the case of a repeated type, the parameter can be repeated in the URL + * as `...?param=A¶m=B`. In the case of a message type, each field of the + * message is mapped to a separate parameter, such as + * `...?foo.a=A&foo.b=B&foo.c=C`. + * + * For HTTP methods that allow a request body, the `body` field + * specifies the mapping. Consider a REST update method on the + * message resource collection: + * + * service Messaging { + * rpc UpdateMessage(UpdateMessageRequest) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "message" + * }; + * } + * } + * message UpdateMessageRequest { + * string message_id = 1; // mapped to the URL + * Message message = 2; // mapped to the body + * } + * + * The following HTTP JSON to RPC mapping is enabled, where the + * representation of the JSON in the request body is determined by + * protos JSON encoding: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" message { text: "Hi!" })` + * + * The special name `*` can be used in the body mapping to define that + * every field not bound by the path template should be mapped to the + * request body. This enables the following alternative definition of + * the update method: + * + * service Messaging { + * rpc UpdateMessage(Message) returns (Message) { + * option (google.api.http) = { + * patch: "/v1/messages/{message_id}" + * body: "*" + * }; + * } + * } + * message Message { + * string message_id = 1; + * string text = 2; + * } + * + * + * The following HTTP JSON to RPC mapping is enabled: + * + * HTTP | gRPC + * -----|----- + * `PATCH /v1/messages/123456 { "text": "Hi!" }` | `UpdateMessage(message_id: + * "123456" text: "Hi!")` + * + * Note that when using `*` in the body mapping, it is not possible to + * have HTTP parameters, as all fields not bound by the path end in + * the body. This makes this option more rarely used in practice when + * defining REST APIs. The common usage of `*` is in custom methods + * which don't use the URL at all for transferring data. + * + * It is possible to define multiple HTTP methods for one RPC by using + * the `additional_bindings` option. Example: + * + * service Messaging { + * rpc GetMessage(GetMessageRequest) returns (Message) { + * option (google.api.http) = { + * get: "/v1/messages/{message_id}" + * additional_bindings { + * get: "/v1/users/{user_id}/messages/{message_id}" + * } + * }; + * } + * } + * message GetMessageRequest { + * string message_id = 1; + * string user_id = 2; + * } + * + * This enables the following two alternative HTTP JSON to RPC mappings: + * + * HTTP | gRPC + * -----|----- + * `GET /v1/messages/123456` | `GetMessage(message_id: "123456")` + * `GET /v1/users/me/messages/123456` | `GetMessage(user_id: "me" message_id: + * "123456")` + * + * ## Rules for HTTP mapping + * + * 1. Leaf request fields (recursive expansion nested messages in the request + * message) are classified into three categories: + * - Fields referred by the path template. They are passed via the URL path. + * - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They are passed via the HTTP + * request body. + * - All other fields are passed via the URL query parameters, and the + * parameter name is the field path in the request message. A repeated + * field can be represented as multiple query parameters under the same + * name. + * 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL query parameter, all fields + * are passed via URL path and HTTP request body. + * 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP request body, all + * fields are passed via URL path and URL query parameters. + * + * ### Path template syntax + * + * Template = "/" Segments [ Verb ] ; + * Segments = Segment { "/" Segment } ; + * Segment = "*" | "**" | LITERAL | Variable ; + * Variable = "{" FieldPath [ "=" Segments ] "}" ; + * FieldPath = IDENT { "." IDENT } ; + * Verb = ":" LITERAL ; + * + * The syntax `*` matches a single URL path segment. The syntax `**` matches + * zero or more URL path segments, which must be the last part of the URL path + * except the `Verb`. + * + * The syntax `Variable` matches part of the URL path as specified by its + * template. A variable template must not contain other variables. If a variable + * matches a single path segment, its template may be omitted, e.g. `{var}` + * is equivalent to `{var=*}`. + * + * The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL` + * contains any reserved character, such characters should be percent-encoded + * before the matching. + * + * If a variable contains exactly one path segment, such as `"{var}"` or + * `"{var=*}"`, when such a variable is expanded into a URL path on the client + * side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The + * server side does the reverse decoding. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{var}`. + * + * If a variable contains multiple path segments, such as `"{var=foo/*}"` + * or `"{var=**}"`, when such a variable is expanded into a URL path on the + * client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded. + * The server side does the reverse decoding, except "%2F" and "%2f" are left + * unchanged. Such variables show up in the + * [Discovery + * Document](https://developers.google.com/discovery/v1/reference/apis) as + * `{+var}`. + * + * ## Using gRPC API Service Configuration + * + * gRPC API Service Configuration (service config) is a configuration language + * for configuring a gRPC service to become a user-facing product. The + * service config is simply the YAML representation of the `google.api.Service` + * proto message. + * + * As an alternative to annotating your proto file, you can configure gRPC + * transcoding in your service config YAML files. You do this by specifying a + * `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same + * effect as the proto annotation. This can be particularly useful if you + * have a proto that is reused in multiple services. Note that any transcoding + * specified in the service config will override any matching transcoding + * configuration in the proto. + * + * Example: + * + * http: + * rules: + * # Selects a gRPC method and applies HttpRule to it. + * - selector: example.v1.Messaging.GetMessage + * get: /v1/messages/{message_id}/{sub.subfield} + * + * ## Special notes + * + * When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the + * proto to JSON conversion must follow the [proto3 + * specification](https://developers.google.com/protocol-buffers/docs/proto3#json). + * + * While the single segment variable follows the semantics of + * [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String + * Expansion, the multi segment variable **does not** follow RFC 6570 Section + * 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion + * does not expand special characters like `?` and `#`, which would lead + * to invalid URLs. As the result, gRPC Transcoding uses a custom encoding + * for multi segment variables. + * + * The path variables **must not** refer to any repeated or mapped field, + * because client libraries are not capable of handling such variable expansion. + * + * The path variables **must not** capture the leading "/" character. The reason + * is that the most common use case "{var}" does not capture the leading "/" + * character. For consistency, all path variables must share the same behavior. + * + * Repeated message fields must not be mapped to URL query parameters, because + * no client library can support such complicated mapping. + * + * If an API needs to use a JSON array for request or response body, it can map + * the request or response body to a repeated field. However, some gRPC + * Transcoding implementations may not support this feature. + */ +export interface HttpRule__Output { + /** + * Selects a method to which this rule applies. + * + * Refer to [selector][google.api.DocumentationRule.selector] for syntax details. + */ + 'selector': (string); + /** + * Maps to HTTP GET. Used for listing and getting information about + * resources. + */ + 'get'?: (string); + /** + * Maps to HTTP PUT. Used for replacing a resource. + */ + 'put'?: (string); + /** + * Maps to HTTP POST. Used for creating a resource or performing an action. + */ + 'post'?: (string); + /** + * Maps to HTTP DELETE. Used for deleting a resource. + */ + 'delete'?: (string); + /** + * Maps to HTTP PATCH. Used for updating a resource. + */ + 'patch'?: (string); + /** + * The name of the request field whose value is mapped to the HTTP request + * body, or `*` for mapping all request fields not captured by the path + * pattern to the HTTP body, or omitted for not having any HTTP request body. + * + * NOTE: the referred field must be present at the top-level of the request + * message type. + */ + 'body': (string); + /** + * The custom pattern is used for specifying an HTTP method that is not + * included in the `pattern` field, such as HEAD, or "*" to leave the + * HTTP method unspecified for this rule. The wild-card rule is useful + * for services that provide content to Web (HTML) clients. + */ + 'custom'?: (_google_api_CustomHttpPattern__Output | null); + /** + * Additional HTTP bindings for the selector. Nested bindings must + * not contain an `additional_bindings` field themselves (that is, + * the nesting may only be one level deep). + */ + 'additional_bindings': (_google_api_HttpRule__Output)[]; + /** + * Optional. The name of the response field whose value is mapped to the HTTP + * response body. When omitted, the entire response message will be used + * as the HTTP response body. + * + * NOTE: The referred field must be present at the top-level of the response + * message type. + */ + 'response_body': (string); + /** + * Determines the URL pattern is matched by this rules. This pattern can be + * used with any of the {get|put|post|delete|patch} methods. A custom method + * can be defined using the 'custom' field. + */ + 'pattern': "get"|"put"|"post"|"delete"|"patch"|"custom"; +} diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts index 48fea77be..9ba51ed60 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/EnumValueOptions.ts @@ -8,6 +8,7 @@ export interface EnumValueOptions { 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.envoy.annotations.disallowed_by_default_enum'?: (boolean); '.udpa.annotations.enum_value_migrate'?: (_udpa_annotations_MigrateAnnotation | null); + '.envoy.annotations.deprecated_at_minor_version_enum'?: (string); } export interface EnumValueOptions__Output { @@ -15,4 +16,5 @@ export interface EnumValueOptions__Output { 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.envoy.annotations.disallowed_by_default_enum': (boolean); '.udpa.annotations.enum_value_migrate': (_udpa_annotations_MigrateAnnotation__Output | null); + '.envoy.annotations.deprecated_at_minor_version_enum': (string); } diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts index 91af8a985..d62db88d0 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/FieldOptions.ts @@ -2,6 +2,7 @@ import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; import type { FieldRules as _validate_FieldRules, FieldRules__Output as _validate_FieldRules__Output } from '../../validate/FieldRules'; +import type { FieldSecurityAnnotation as _udpa_annotations_FieldSecurityAnnotation, FieldSecurityAnnotation__Output as _udpa_annotations_FieldSecurityAnnotation__Output } from '../../udpa/annotations/FieldSecurityAnnotation'; import type { FieldMigrateAnnotation as _udpa_annotations_FieldMigrateAnnotation, FieldMigrateAnnotation__Output as _udpa_annotations_FieldMigrateAnnotation__Output } from '../../udpa/annotations/FieldMigrateAnnotation'; import type { FieldStatusAnnotation as _xds_annotations_v3_FieldStatusAnnotation, FieldStatusAnnotation__Output as _xds_annotations_v3_FieldStatusAnnotation__Output } from '../../xds/annotations/v3/FieldStatusAnnotation'; @@ -30,7 +31,9 @@ export interface FieldOptions { 'weak'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; '.validate.rules'?: (_validate_FieldRules | null); + '.udpa.annotations.security'?: (_udpa_annotations_FieldSecurityAnnotation | null); '.udpa.annotations.sensitive'?: (boolean); + '.envoy.annotations.deprecated_at_minor_version'?: (string); '.udpa.annotations.field_migrate'?: (_udpa_annotations_FieldMigrateAnnotation | null); '.envoy.annotations.disallowed_by_default'?: (boolean); '.xds.annotations.v3.field_status'?: (_xds_annotations_v3_FieldStatusAnnotation | null); @@ -45,7 +48,9 @@ export interface FieldOptions__Output { 'weak': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; '.validate.rules': (_validate_FieldRules__Output | null); + '.udpa.annotations.security': (_udpa_annotations_FieldSecurityAnnotation__Output | null); '.udpa.annotations.sensitive': (boolean); + '.envoy.annotations.deprecated_at_minor_version': (string); '.udpa.annotations.field_migrate': (_udpa_annotations_FieldMigrateAnnotation__Output | null); '.envoy.annotations.disallowed_by_default': (boolean); '.xds.annotations.v3.field_status': (_xds_annotations_v3_FieldStatusAnnotation__Output | null); diff --git a/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts index e47fd756c..5f81f0dd9 100644 --- a/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts +++ b/packages/grpc-js-xds/src/generated/google/protobuf/MethodOptions.ts @@ -1,13 +1,16 @@ // Original file: null import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; export interface MethodOptions { 'deprecated'?: (boolean); 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + '.google.api.http'?: (_google_api_HttpRule | null); } export interface MethodOptions__Output { 'deprecated': (boolean); 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + '.google.api.http': (_google_api_HttpRule__Output | null); } diff --git a/packages/grpc-js-xds/src/generated/http_connection_manager.ts b/packages/grpc-js-xds/src/generated/http_connection_manager.ts index 351e65400..137dcd45a 100644 --- a/packages/grpc-js-xds/src/generated/http_connection_manager.ts +++ b/packages/grpc-js-xds/src/generated/http_connection_manager.ts @@ -34,6 +34,7 @@ export interface ProtoGrpcType { v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition + AlternateProtocolsCacheOptions: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition ApiVersion: EnumTypeDefinition AsyncDataSource: MessageTypeDefinition @@ -63,6 +64,8 @@ export interface ProtoGrpcType { Node: MessageTypeDefinition Pipe: MessageTypeDefinition ProxyProtocolConfig: MessageTypeDefinition + QueryParameter: MessageTypeDefinition + QuicProtocolOptions: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -73,6 +76,7 @@ export interface ProtoGrpcType { RuntimeFractionalPercent: MessageTypeDefinition RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition + SchemeHeaderTransformation: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition @@ -88,6 +92,7 @@ export interface ProtoGrpcType { } route: { v3: { + ClusterSpecifierPlugin: MessageTypeDefinition CorsPolicy: MessageTypeDefinition Decorator: MessageTypeDefinition DirectResponseAction: MessageTypeDefinition @@ -96,6 +101,7 @@ export interface ProtoGrpcType { HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition InternalRedirectPolicy: MessageTypeDefinition + NonForwardingAction: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition @@ -123,6 +129,7 @@ export interface ProtoGrpcType { network: { http_connection_manager: { v3: { + EnvoyMobileHttpConnectionManager: MessageTypeDefinition HttpConnectionManager: MessageTypeDefinition HttpFilter: MessageTypeDefinition LocalReplyConfig: MessageTypeDefinition @@ -138,6 +145,11 @@ export interface ProtoGrpcType { } } type: { + http: { + v3: { + PathTransformation: MessageTypeDefinition + } + } matcher: { v3: { DoubleMatcher: MessageTypeDefinition @@ -262,6 +274,7 @@ export interface ProtoGrpcType { core: { v3: { Authority: MessageTypeDefinition + ContextParams: MessageTypeDefinition } } } diff --git a/packages/grpc-js-xds/src/generated/listener.ts b/packages/grpc-js-xds/src/generated/listener.ts index aac080a90..b92353ab1 100644 --- a/packages/grpc-js-xds/src/generated/listener.ts +++ b/packages/grpc-js-xds/src/generated/listener.ts @@ -34,6 +34,7 @@ export interface ProtoGrpcType { v3: { Address: MessageTypeDefinition AggregatedConfigSource: MessageTypeDefinition + AlternateProtocolsCacheOptions: MessageTypeDefinition ApiConfigSource: MessageTypeDefinition ApiVersion: EnumTypeDefinition AsyncDataSource: MessageTypeDefinition @@ -47,16 +48,24 @@ export interface ProtoGrpcType { EnvoyInternalAddress: MessageTypeDefinition Extension: MessageTypeDefinition ExtensionConfigSource: MessageTypeDefinition + GrpcProtocolOptions: MessageTypeDefinition GrpcService: MessageTypeDefinition HeaderMap: MessageTypeDefinition HeaderValue: MessageTypeDefinition HeaderValueOption: MessageTypeDefinition + Http1ProtocolOptions: MessageTypeDefinition + Http2ProtocolOptions: MessageTypeDefinition + Http3ProtocolOptions: MessageTypeDefinition + HttpProtocolOptions: MessageTypeDefinition HttpUri: MessageTypeDefinition + KeepaliveSettings: MessageTypeDefinition Locality: MessageTypeDefinition Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition ProxyProtocolConfig: MessageTypeDefinition + QueryParameter: MessageTypeDefinition + QuicProtocolOptions: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -67,13 +76,17 @@ export interface ProtoGrpcType { RuntimeFractionalPercent: MessageTypeDefinition RuntimePercent: MessageTypeDefinition RuntimeUInt32: MessageTypeDefinition + SchemeHeaderTransformation: MessageTypeDefinition SelfConfigSource: MessageTypeDefinition SocketAddress: MessageTypeDefinition SocketOption: MessageTypeDefinition TcpKeepalive: MessageTypeDefinition + TcpProtocolOptions: MessageTypeDefinition TrafficDirection: EnumTypeDefinition TransportSocket: MessageTypeDefinition TypedExtensionConfig: MessageTypeDefinition + UdpSocketConfig: MessageTypeDefinition + UpstreamHttpProtocolOptions: MessageTypeDefinition WatchedDirectory: MessageTypeDefinition } } @@ -88,6 +101,7 @@ export interface ProtoGrpcType { ListenerCollection: MessageTypeDefinition ListenerFilter: MessageTypeDefinition ListenerFilterChainMatchPredicate: MessageTypeDefinition + QuicProtocolOptions: MessageTypeDefinition UdpListenerConfig: MessageTypeDefinition } } @@ -101,6 +115,7 @@ export interface ProtoGrpcType { HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition InternalRedirectPolicy: MessageTypeDefinition + NonForwardingAction: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts index 929fd6914..e92f80800 100644 --- a/packages/grpc-js-xds/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -10,6 +10,8 @@ type SubtypeConstructor any, Subtype> export interface ProtoGrpcType { envoy: { + annotations: { + } api: { v2: { core: { @@ -73,6 +75,7 @@ export interface ProtoGrpcType { Metadata: MessageTypeDefinition Node: MessageTypeDefinition Pipe: MessageTypeDefinition + QueryParameter: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition RetryPolicy: MessageTypeDefinition @@ -200,5 +203,21 @@ export interface ProtoGrpcType { UInt32Rules: MessageTypeDefinition UInt64Rules: MessageTypeDefinition } + xds: { + annotations: { + v3: { + FieldStatusAnnotation: MessageTypeDefinition + FileStatusAnnotation: MessageTypeDefinition + MessageStatusAnnotation: MessageTypeDefinition + PackageVersionStatus: EnumTypeDefinition + StatusAnnotation: MessageTypeDefinition + } + } + core: { + v3: { + ContextParams: MessageTypeDefinition + } + } + } } diff --git a/packages/grpc-js-xds/src/generated/route.ts b/packages/grpc-js-xds/src/generated/route.ts index 67b9c5ce4..d6485bcd7 100644 --- a/packages/grpc-js-xds/src/generated/route.ts +++ b/packages/grpc-js-xds/src/generated/route.ts @@ -38,6 +38,7 @@ export interface ProtoGrpcType { Node: MessageTypeDefinition Pipe: MessageTypeDefinition ProxyProtocolConfig: MessageTypeDefinition + QueryParameter: MessageTypeDefinition RateLimitSettings: MessageTypeDefinition RemoteDataSource: MessageTypeDefinition RequestMethod: EnumTypeDefinition @@ -60,6 +61,7 @@ export interface ProtoGrpcType { } route: { v3: { + ClusterSpecifierPlugin: MessageTypeDefinition CorsPolicy: MessageTypeDefinition Decorator: MessageTypeDefinition DirectResponseAction: MessageTypeDefinition @@ -68,6 +70,7 @@ export interface ProtoGrpcType { HeaderMatcher: MessageTypeDefinition HedgePolicy: MessageTypeDefinition InternalRedirectPolicy: MessageTypeDefinition + NonForwardingAction: MessageTypeDefinition QueryParameterMatcher: MessageTypeDefinition RateLimit: MessageTypeDefinition RedirectAction: MessageTypeDefinition @@ -87,10 +90,14 @@ export interface ProtoGrpcType { type: { matcher: { v3: { + DoubleMatcher: MessageTypeDefinition + ListMatcher: MessageTypeDefinition ListStringMatcher: MessageTypeDefinition + MetadataMatcher: MessageTypeDefinition RegexMatchAndSubstitute: MessageTypeDefinition RegexMatcher: MessageTypeDefinition StringMatcher: MessageTypeDefinition + ValueMatcher: MessageTypeDefinition } } metadata: { @@ -204,6 +211,7 @@ export interface ProtoGrpcType { core: { v3: { Authority: MessageTypeDefinition + ContextParams: MessageTypeDefinition } } } diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index ab036184e..f6e2ad402 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -432,7 +432,12 @@ class XdsResolver implements Resolver { weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0, dynamicFilterFactories: extraFilterFactories}); } routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100, timeout); + break; } + default: + /* The validation logic should prevent us from reaching this point. + * This is just for the type checker. */ + continue; } const routeMatcher = getPredicateForMatcher(route.match!); matchList.push({matcher: routeMatcher, action: routeAction}); From dca36701fc15b85cfe28f727658496d084fd3339 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 2 Dec 2021 16:14:40 -0500 Subject: [PATCH 1572/1899] grpc-js-xds: Add details to ADS response handling result --- packages/grpc-js-xds/src/xds-client.ts | 128 ++++++++++-------- .../src/xds-stream-state/cds-state.ts | 37 +++-- .../src/xds-stream-state/eds-state.ts | 30 ++-- .../src/xds-stream-state/lds-state.ts | 38 ++++-- .../src/xds-stream-state/rds-state.ts | 30 ++-- .../src/xds-stream-state/xds-stream-state.ts | 25 +++- 6 files changed, 193 insertions(+), 95 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 8a08276eb..6c8bcb67f 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -45,7 +45,7 @@ import { EdsState } from './xds-stream-state/eds-state'; import { CdsState } from './xds-stream-state/cds-state'; import { RdsState } from './xds-stream-state/rds-state'; import { LdsState } from './xds-stream-state/lds-state'; -import { Watcher } from './xds-stream-state/xds-stream-state'; +import { HandleResponseResult, ResourcePair, Watcher } from './xds-stream-state/xds-stream-state'; import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint/v3/ClusterLoadAssignment'; import { Cluster__Output } from './generated/envoy/config/cluster/v3/Cluster'; import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; @@ -242,11 +242,14 @@ function getResponseMessages( targetTypeUrl: T, allowedTypeUrls: string[], resources: Any__Output[] -): AdsOutputType[] { - const result: AdsOutputType[] = []; +): ResourcePair>[] { + const result: ResourcePair>[] = []; for (const resource of resources) { if (allowedTypeUrls.includes(resource.type_url)) { - result.push(decodeSingleResource(targetTypeUrl, resource.value)); + result.push({ + resource: decodeSingleResource(targetTypeUrl, resource.value), + raw: resource + }); } else { throw new Error( `ADS Error: Invalid resource type ${resource.type_url}, expected ${allowedTypeUrls}` @@ -450,8 +453,10 @@ export class XdsClient { } private handleAdsResponse(message: DiscoveryResponse__Output) { - let errorString: string | null; - let serviceKind: AdsServiceKind; + let handleResponseResult: { + result: HandleResponseResult; + serviceKind: AdsServiceKind; + } | null = null; let isV2: boolean; switch (message.type_url) { case EDS_TYPE_URL_V2: @@ -463,56 +468,71 @@ export class XdsClient { default: isV2 = false; } - switch (message.type_url) { - case EDS_TYPE_URL_V2: - case EDS_TYPE_URL_V3: - errorString = this.adsState.eds.handleResponses( - getResponseMessages(EDS_TYPE_URL_V3, [EDS_TYPE_URL_V2, EDS_TYPE_URL_V3], message.resources), - isV2 - ); - serviceKind = 'eds'; - break; - case CDS_TYPE_URL_V2: - case CDS_TYPE_URL_V3: - errorString = this.adsState.cds.handleResponses( - getResponseMessages(CDS_TYPE_URL_V3, [CDS_TYPE_URL_V2, CDS_TYPE_URL_V3], message.resources), - isV2 - ); - serviceKind = 'cds'; - break; - case RDS_TYPE_URL_V2: - case RDS_TYPE_URL_V3: - errorString = this.adsState.rds.handleResponses( - getResponseMessages(RDS_TYPE_URL_V3, [RDS_TYPE_URL_V2, RDS_TYPE_URL_V3], message.resources), - isV2 - ); - serviceKind = 'rds'; - break; - case LDS_TYPE_URL_V2: - case LDS_TYPE_URL_V3: - errorString = this.adsState.lds.handleResponses( - getResponseMessages(LDS_TYPE_URL_V3, [LDS_TYPE_URL_V2, LDS_TYPE_URL_V3], message.resources), - isV2 - ); - serviceKind = 'lds'; - break; - default: - errorString = `Unknown type_url ${message.type_url}`; - // This is not used in this branch, but setting it makes the types easier to handle - serviceKind = 'eds'; + try { + switch (message.type_url) { + case EDS_TYPE_URL_V2: + case EDS_TYPE_URL_V3: + handleResponseResult = { + result: this.adsState.eds.handleResponses( + getResponseMessages(EDS_TYPE_URL_V3, [EDS_TYPE_URL_V2, EDS_TYPE_URL_V3], message.resources), + isV2 + ), + serviceKind: 'eds' + }; + break; + case CDS_TYPE_URL_V2: + case CDS_TYPE_URL_V3: + handleResponseResult = { + result: this.adsState.cds.handleResponses( + getResponseMessages(CDS_TYPE_URL_V3, [CDS_TYPE_URL_V2, CDS_TYPE_URL_V3], message.resources), + isV2 + ), + serviceKind: 'cds' + }; + break; + case RDS_TYPE_URL_V2: + case RDS_TYPE_URL_V3: + handleResponseResult = { + result: this.adsState.rds.handleResponses( + getResponseMessages(RDS_TYPE_URL_V3, [RDS_TYPE_URL_V2, RDS_TYPE_URL_V3], message.resources), + isV2 + ), + serviceKind: 'rds' + }; + break; + case LDS_TYPE_URL_V2: + case LDS_TYPE_URL_V3: + handleResponseResult = { + result: this.adsState.lds.handleResponses( + getResponseMessages(LDS_TYPE_URL_V3, [LDS_TYPE_URL_V2, LDS_TYPE_URL_V3], message.resources), + isV2 + ), + serviceKind: 'lds' + } + break; + } + } catch (e) { + trace('Nacking message with protobuf parsing error: ' + e.message); + this.nack(message.type_url, e.message); } - if (errorString === null) { - trace('Acking message with type URL ' + message.type_url); - /* errorString can only be null in one of the first 4 cases, which - * implies that message.type_url is one of the 4 known type URLs, which - * means that this type assertion is valid. */ - const typeUrl = message.type_url as AdsTypeUrl; - this.adsState[serviceKind].nonce = message.nonce; - this.adsState[serviceKind].versionInfo = message.version_info; - this.ack(serviceKind); + if (handleResponseResult === null) { + // Null handleResponseResult means that the type_url was unrecognized + trace('Nacking message with unknown type URL ' + message.type_url); + this.nack(message.type_url, `Unknown type_url ${message.type_url}`); } else { - trace('Nacking message with type URL ' + message.type_url + ': "' + errorString + '"'); - this.nack(message.type_url, errorString); + if (handleResponseResult.result.rejected.length > 0) { + // rejected.length > 0 means that at least one message validation failed + const errorString = `${handleResponseResult.serviceKind.toUpperCase()} Error: ${handleResponseResult.result.rejected[0].error}`; + trace('Nacking message with type URL ' + message.type_url + ': ' + errorString); + this.nack(message.type_url, errorString); + } else { + // If we get here, all message validation succeeded + trace('Acking message with type URL ' + message.type_url); + const serviceKind = handleResponseResult.serviceKind; + this.adsState[serviceKind].nonce = message.nonce; + this.adsState[serviceKind].versionInfo = message.version_info; + this.ack(serviceKind); + } } } diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 05477388d..ce0434b8b 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -17,8 +17,9 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { Cluster__Output } from "../generated/envoy/config/cluster/v3/Cluster"; +import { Any__Output } from "../generated/google/protobuf/Any"; import { EdsState } from "./eds-state"; -import { Watcher, XdsStreamState } from "./xds-stream-state"; +import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; const TRACER_NAME = 'xds_client'; @@ -125,26 +126,40 @@ export class CdsState implements XdsStreamState { * onResourceDoesNotExist method. * @param allClusterNames */ - private handleMissingNames(allClusterNames: Set) { + private handleMissingNames(allClusterNames: Set): string[] { + const missingNames: string[] = []; for (const [clusterName, watcherList] of this.watchers.entries()) { if (!allClusterNames.has(clusterName)) { trace('Reporting CDS resource does not exist for clusterName ' + clusterName); + missingNames.push(clusterName); for (const watcher of watcherList) { watcher.onResourceDoesNotExist(); } } } + return missingNames; } - handleResponses(responses: Cluster__Output[], isV2: boolean): string | null { + handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { const validResponses: Cluster__Output[] = []; - let errorMessage: string | null = null; - for (const message of responses) { - if (this.validateResponse(message)) { - validResponses.push(message); + const result: HandleResponseResult = { + accepted: [], + rejected: [], + missing: [] + } + for (const {resource, raw} of responses) { + if (this.validateResponse(resource)) { + validResponses.push(resource); + result.accepted.push({ + name: resource.name, + raw: raw}); } else { - trace('CDS validation failed for message ' + JSON.stringify(message)); - errorMessage = 'CDS Error: Cluster validation failed'; + trace('CDS validation failed for message ' + JSON.stringify(resource)); + result.rejected.push({ + name: resource.name, + raw: raw, + error: `Cluster validation failed for resource ${resource.name}` + }); } } this.latestResponses = validResponses; @@ -163,9 +178,9 @@ export class CdsState implements XdsStreamState { } } trace('Received CDS updates for cluster names [' + Array.from(allClusterNames) + ']'); - this.handleMissingNames(allClusterNames); + result.missing = this.handleMissingNames(allClusterNames); this.edsState.handleMissingNames(allEdsServiceNames); - return errorMessage; + return result; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index f5a8b774f..5360400c5 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -18,7 +18,8 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { isIPv4, isIPv6 } from "net"; import { ClusterLoadAssignment__Output } from "../generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; -import { Watcher, XdsStreamState } from "./xds-stream-state"; +import { Any__Output } from "../generated/google/protobuf/Any"; +import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; const TRACER_NAME = 'xds_client'; @@ -145,15 +146,26 @@ export class EdsState implements XdsStreamState { } } - handleResponses(responses: ClusterLoadAssignment__Output[], isV2: boolean) { + handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { const validResponses: ClusterLoadAssignment__Output[] = []; - let errorMessage: string | null = null; - for (const message of responses) { - if (this.validateResponse(message)) { - validResponses.push(message); + let result: HandleResponseResult = { + accepted: [], + rejected: [], + missing: [] + } + for (const {resource, raw} of responses) { + if (this.validateResponse(resource)) { + validResponses.push(resource); + result.accepted.push({ + name: resource.cluster_name, + raw: raw}); } else { - trace('EDS validation failed for message ' + JSON.stringify(message)); - errorMessage = 'EDS Error: ClusterLoadAssignment validation failed'; + trace('EDS validation failed for message ' + JSON.stringify(resource)); + result.rejected.push({ + name: resource.cluster_name, + raw: raw, + error: `ClusterLoadAssignment validation failed for resource ${resource.cluster_name}` + }); } } this.latestResponses = validResponses; @@ -167,7 +179,7 @@ export class EdsState implements XdsStreamState { } } trace('Received EDS updates for cluster names [' + Array.from(allClusterNames) + ']'); - return errorMessage; + return result; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 7318b3b8a..0c4fdc516 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -19,11 +19,12 @@ import * as protoLoader from '@grpc/proto-loader'; import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { Listener__Output } from '../generated/envoy/config/listener/v3/Listener'; import { RdsState } from "./rds-state"; -import { Watcher, XdsStreamState } from "./xds-stream-state"; +import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; import { HttpConnectionManager__Output } from '../generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V2, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from '../resources'; import { getTopLevelFilterUrl, validateTopLevelFilter } from '../http-filter'; import { EXPERIMENTAL_FAULT_INJECTION } from '../environment'; +import { Any__Output } from '../generated/google/protobuf/Any'; const TRACER_NAME = 'xds_client'; @@ -143,25 +144,40 @@ export class LdsState implements XdsStreamState { return false; } - private handleMissingNames(allTargetNames: Set) { + private handleMissingNames(allTargetNames: Set): string[] { + const missingNames: string[] = []; for (const [targetName, watcherList] of this.watchers.entries()) { if (!allTargetNames.has(targetName)) { + missingNames.push(targetName); for (const watcher of watcherList) { watcher.onResourceDoesNotExist(); } } } + return missingNames; } - handleResponses(responses: Listener__Output[], isV2: boolean): string | null { + handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { const validResponses: Listener__Output[] = []; - let errorMessage: string | null = null; - for (const message of responses) { - if (this.validateResponse(message, isV2)) { - validResponses.push(message); + let result: HandleResponseResult = { + accepted: [], + rejected: [], + missing: [] + } + for (const {resource, raw} of responses) { + if (this.validateResponse(resource, isV2)) { + validResponses.push(resource); + result.accepted.push({ + name: resource.name, + raw: raw + }); } else { - trace('LDS validation failed for message ' + JSON.stringify(message)); - errorMessage = 'LDS Error: Route validation failed'; + trace('LDS validation failed for message ' + JSON.stringify(resource)); + result.rejected.push({ + name: resource.name, + raw: raw, + error: `Listener validation failed for resource ${resource.name}` + }); } } this.latestResponses = validResponses; @@ -180,9 +196,9 @@ export class LdsState implements XdsStreamState { } } trace('Received LDS response with listener names [' + Array.from(allTargetNames) + ']'); - this.handleMissingNames(allTargetNames); + result.missing = this.handleMissingNames(allTargetNames); this.rdsState.handleMissingNames(allRouteConfigNames); - return errorMessage; + return result; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index bb7e0bc51..0ff4c2aae 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -18,9 +18,10 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { EXPERIMENTAL_FAULT_INJECTION } from "../environment"; import { RouteConfiguration__Output } from "../generated/envoy/config/route/v3/RouteConfiguration"; +import { Any__Output } from "../generated/google/protobuf/Any"; import { validateOverrideFilter } from "../http-filter"; import { CdsLoadBalancingConfig } from "../load-balancer-cds"; -import { Watcher, XdsStreamState } from "./xds-stream-state"; +import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; import ServiceConfig = experimental.ServiceConfig; const TRACER_NAME = 'xds_client'; @@ -182,15 +183,26 @@ export class RdsState implements XdsStreamState { } } - handleResponses(responses: RouteConfiguration__Output[], isV2: boolean): string | null { + handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { const validResponses: RouteConfiguration__Output[] = []; - let errorMessage: string | null = null; - for (const message of responses) { - if (this.validateResponse(message, isV2)) { - validResponses.push(message); + let result: HandleResponseResult = { + accepted: [], + rejected: [], + missing: [] + } + for (const {resource, raw} of responses) { + if (this.validateResponse(resource, isV2)) { + validResponses.push(resource); + result.accepted.push({ + name: resource.name, + raw: raw}); } else { - trace('RDS validation failed for message ' + JSON.stringify(message)); - errorMessage = 'RDS Error: Route validation failed'; + trace('RDS validation failed for message ' + JSON.stringify(resource)); + result.rejected.push({ + name: resource.name, + raw: raw, + error: `Route validation failed for resource ${resource.name}` + }); } } this.latestResponses = validResponses; @@ -204,7 +216,7 @@ export class RdsState implements XdsStreamState { } } trace('Received RDS response with route config names [' + Array.from(allRouteConfigNames) + ']'); - return errorMessage; + return result; } reportStreamError(status: StatusObject): void { diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 14f3d1c76..c8cbc41cf 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -16,6 +16,7 @@ */ import { StatusObject } from "@grpc/grpc-js"; +import { Any__Output } from "../generated/google/protobuf/Any"; export interface Watcher { /* Including the isV2 flag here is a bit of a kludge. It would probably be @@ -28,6 +29,28 @@ export interface Watcher { onResourceDoesNotExist(): void; } +export interface ResourcePair { + resource: ResourceType; + raw: Any__Output; +} + +export interface AcceptedResourceEntry { + name: string; + raw: Any__Output; +} + +export interface RejectedResourceEntry { + name: string; + raw: Any__Output; + error: string; +} + +export interface HandleResponseResult { + accepted: AcceptedResourceEntry[]; + rejected: RejectedResourceEntry[]; + missing: string[]; +} + export interface XdsStreamState { versionInfo: string; nonce: string; @@ -37,7 +60,7 @@ export interface XdsStreamState { * or null if it should be acked. * @param responses */ - handleResponses(responses: ResponseType[], isV2: boolean): string | null; + handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult; reportStreamError(status: StatusObject): void; } \ No newline at end of file From 858d1b66ad57fa0eed03877c8b5deae08f3fd653 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 2 Dec 2021 16:15:09 -0500 Subject: [PATCH 1573/1899] grpc-js-xds: Implement CSDS --- packages/grpc-js-xds/src/csds.ts | 204 ++++++++++++++++++++++++++++++ packages/grpc-js-xds/src/index.ts | 2 + 2 files changed, 206 insertions(+) create mode 100644 packages/grpc-js-xds/src/csds.ts diff --git a/packages/grpc-js-xds/src/csds.ts b/packages/grpc-js-xds/src/csds.ts new file mode 100644 index 000000000..19f1e9660 --- /dev/null +++ b/packages/grpc-js-xds/src/csds.ts @@ -0,0 +1,204 @@ +/* + * Copyright 2021 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Node } from "./generated/envoy/config/core/v3/Node"; +import { ClientConfig, _envoy_service_status_v3_ClientConfig_GenericXdsConfig as GenericXdsConfig } from "./generated/envoy/service/status/v3/ClientConfig"; +import { ClientStatusDiscoveryServiceHandlers } from "./generated/envoy/service/status/v3/ClientStatusDiscoveryService"; +import { ClientStatusRequest__Output } from "./generated/envoy/service/status/v3/ClientStatusRequest"; +import { ClientStatusResponse } from "./generated/envoy/service/status/v3/ClientStatusResponse"; +import { Timestamp } from "./generated/google/protobuf/Timestamp"; +import { AdsTypeUrl, CDS_TYPE_URL_V2, CDS_TYPE_URL_V3, EDS_TYPE_URL_V2, EDS_TYPE_URL_V3, LDS_TYPE_URL_V2, LDS_TYPE_URL_V3, RDS_TYPE_URL_V2, RDS_TYPE_URL_V3 } from "./resources"; +import { HandleResponseResult } from "./xds-stream-state/xds-stream-state"; +import { sendUnaryData, ServerDuplexStream, ServerUnaryCall, status, experimental, loadPackageDefinition } from '@grpc/grpc-js'; +import { loadSync } from "@grpc/proto-loader"; +import { ProtoGrpcType as CsdsProtoGrpcType } from "./generated/csds"; + +import registerAdminService = experimental.registerAdminService; + + +function dateToProtoTimestamp(date?: Date | null): Timestamp | null { + if (!date) { + return null; + } + const millisSinceEpoch = date.getTime(); + return { + seconds: (millisSinceEpoch / 1000) | 0, + nanos: (millisSinceEpoch % 1000) * 1_000_000 + } +} + +let clientNode: Node | null = null; + +const configStatus = { + [EDS_TYPE_URL_V2]: new Map(), + [EDS_TYPE_URL_V3]: new Map(), + [CDS_TYPE_URL_V2]: new Map(), + [CDS_TYPE_URL_V3]: new Map(), + [RDS_TYPE_URL_V2]: new Map(), + [RDS_TYPE_URL_V3]: new Map(), + [LDS_TYPE_URL_V2]: new Map(), + [LDS_TYPE_URL_V3]: new Map() +}; + +/** + * This function only accepts a v3 Node message, because we are only supporting + * v3 CSDS and it only handles v3 Nodes. If the client is actually using v2 xDS + * APIs, it should just provide the equivalent v3 Node message. + * @param node The Node message for the client that is requesting resources + */ +export function setCsdsClientNode(node: Node) { + clientNode = node; +} + +/** + * Update the config status maps from the list of names of requested resources + * for a specific type URL. These lists are the source of truth for determining + * what resources will be listed in the CSDS response. Any resource that is not + * in this list will never actually be applied anywhere. + * @param typeUrl The resource type URL + * @param names The list of resource names that are being requested + */ +export function updateRequestedNameList(typeUrl: AdsTypeUrl, names: string[]) { + const currentTime = dateToProtoTimestamp(new Date()); + const configMap = configStatus[typeUrl]; + for (const name of names) { + if (!configMap.has(name)) { + configMap.set(name, { + type_url: typeUrl, + name: name, + last_updated: currentTime, + client_status: 'REQUESTED' + }); + } + } + for (const name of configMap.keys()) { + if (!names.includes(name)) { + configMap.delete(name); + } + } +} + +/** + * Update the config status maps from the result of parsing a single ADS + * response. All resources that validated are considered "ACKED", and all + * resources that failed validation are considered "NACKED". + * @param typeUrl The type URL of resources in this response + * @param versionInfo The version info field from this response + * @param updates The lists of resources that passed and failed validation + */ +export function updateResourceResponse(typeUrl: AdsTypeUrl, versionInfo: string, updates: HandleResponseResult) { + const currentTime = dateToProtoTimestamp(new Date()); + const configMap = configStatus[typeUrl]; + for (const {name, raw} of updates.accepted) { + const mapEntry = configMap.get(name); + if (mapEntry) { + mapEntry.client_status = 'ACKED'; + mapEntry.version_info = versionInfo; + mapEntry.xds_config = raw; + mapEntry.error_state = null; + mapEntry.last_updated = currentTime; + } + } + for (const {name, error, raw} of updates.rejected) { + const mapEntry = configMap.get(name); + if (mapEntry) { + mapEntry.client_status = 'NACKED'; + mapEntry.error_state = { + failed_configuration: raw, + last_update_attempt: currentTime, + details: error, + version_info: versionInfo + }; + } + } + for (const name of updates.missing) { + const mapEntry = configMap.get(name); + if (mapEntry) { + mapEntry.client_status = 'DOES_NOT_EXIST'; + mapEntry.version_info = versionInfo; + mapEntry.xds_config = null; + mapEntry.error_state = null; + mapEntry.last_updated = currentTime; + } + } +} + +function getCurrentConfig(): ClientConfig { + const genericConfigList: GenericXdsConfig[] = []; + for (const configMap of Object.values(configStatus)) { + for (const configValue of configMap.values()) { + genericConfigList.push(configValue); + } + } + return { + node: clientNode, + generic_xds_configs: genericConfigList + }; +} + +const csdsImplementation: ClientStatusDiscoveryServiceHandlers = { + FetchClientStatus(call: ServerUnaryCall, callback: sendUnaryData) { + const request = call.request; + if (request.node_matchers !== null) { + callback({ + code: status.INVALID_ARGUMENT, + details: 'Node matchers not supported' + }); + return; + } + callback(null, { + config: [getCurrentConfig()] + }); + }, + StreamClientStatus(call: ServerDuplexStream) { + call.on('data', (request: ClientStatusRequest__Output) => { + if (request.node_matchers !== null) { + call.emit('error', { + code: status.INVALID_ARGUMENT, + details: 'Node matchers not supported' + }); + return; + } + call.write({ + config: [getCurrentConfig()] + }); + }); + call.on('end', () => { + call.end(); + }); + } +} + +const loadedProto = loadSync('envoy/service/status/v3/csds.proto', { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + includeDirs: [ + // Paths are relative to src/build + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/xds/', + ], +}); + +const csdsGrpcObject = loadPackageDefinition(loadedProto) as unknown as CsdsProtoGrpcType; +const csdsServiceDefinition = csdsGrpcObject.envoy.service.status.v3.ClientStatusDiscoveryService.service; + +export function setup() { + registerAdminService(() => csdsServiceDefinition, () => csdsImplementation); +} \ No newline at end of file diff --git a/packages/grpc-js-xds/src/index.ts b/packages/grpc-js-xds/src/index.ts index 7d35bcd1e..ca1cf72ef 100644 --- a/packages/grpc-js-xds/src/index.ts +++ b/packages/grpc-js-xds/src/index.ts @@ -24,6 +24,7 @@ import * as load_balancer_weighted_target from './load-balancer-weighted-target' import * as load_balancer_xds_cluster_manager from './load-balancer-xds-cluster-manager'; import * as router_filter from './http-filter/router-filter'; import * as fault_injection_filter from './http-filter/fault-injection-filter'; +import * as csds from './csds'; /** * Register the "xds:" name scheme with the @grpc/grpc-js library. @@ -38,4 +39,5 @@ export function register() { load_balancer_xds_cluster_manager.setup(); router_filter.setup(); fault_injection_filter.setup(); + csds.setup(); } \ No newline at end of file From adc25c25f3503c2743a17738e35dc7493c952708 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 2 Dec 2021 16:21:19 -0500 Subject: [PATCH 1574/1899] grpc-js-xds: Expose admin service in interop client, enable CSDS test --- packages/grpc-js-xds/interop/xds-interop-client.ts | 1 + packages/grpc-js-xds/scripts/xds.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 6cd3aeb33..029525a45 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -404,6 +404,7 @@ function main() { const server = new grpc.Server(); server.addService(loadedProto.grpc.testing.LoadBalancerStatsService.service, loadBalancerStatsServiceImpl); server.addService(loadedProto.grpc.testing.XdsUpdateClientConfigureService.service, xdsUpdateClientConfigureServiceImpl); + grpc.addAdminServicesToServer(server); server.bindAsync(`0.0.0.0:${argv.stats_port}`, grpc.ServerCredentials.createInsecure(), (error, port) => { if (error) { throw error; diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index a06cde84b..7fc09e2b1 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -52,7 +52,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all,timeout,circuit_breaking,fault_injection" \ + --test_case="all,timeout,circuit_breaking,fault_injection,csds" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-4 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From 29711cd526133ab3b4e4d7e728113331e920bacf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 2 Dec 2021 18:00:07 -0500 Subject: [PATCH 1575/1899] grpc-js-xds: CSDS: add tracing and fix bugs --- packages/grpc-js-xds/scripts/xds.sh | 2 +- packages/grpc-js-xds/src/csds.ts | 24 ++++++++++++++++++------ packages/grpc-js-xds/src/xds-client.ts | 12 ++++++++++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 7fc09e2b1..c7a9adb6e 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -48,7 +48,7 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter \ +GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ diff --git a/packages/grpc-js-xds/src/csds.ts b/packages/grpc-js-xds/src/csds.ts index 19f1e9660..40ca67f1f 100644 --- a/packages/grpc-js-xds/src/csds.ts +++ b/packages/grpc-js-xds/src/csds.ts @@ -23,12 +23,18 @@ import { ClientStatusResponse } from "./generated/envoy/service/status/v3/Client import { Timestamp } from "./generated/google/protobuf/Timestamp"; import { AdsTypeUrl, CDS_TYPE_URL_V2, CDS_TYPE_URL_V3, EDS_TYPE_URL_V2, EDS_TYPE_URL_V3, LDS_TYPE_URL_V2, LDS_TYPE_URL_V3, RDS_TYPE_URL_V2, RDS_TYPE_URL_V3 } from "./resources"; import { HandleResponseResult } from "./xds-stream-state/xds-stream-state"; -import { sendUnaryData, ServerDuplexStream, ServerUnaryCall, status, experimental, loadPackageDefinition } from '@grpc/grpc-js'; +import { sendUnaryData, ServerDuplexStream, ServerUnaryCall, status, experimental, loadPackageDefinition, logVerbosity } from '@grpc/grpc-js'; import { loadSync } from "@grpc/proto-loader"; import { ProtoGrpcType as CsdsProtoGrpcType } from "./generated/csds"; import registerAdminService = experimental.registerAdminService; +const TRACER_NAME = 'csds'; + +function trace(text: string): void { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); +} + function dateToProtoTimestamp(date?: Date | null): Timestamp | null { if (!date) { @@ -72,7 +78,8 @@ export function setCsdsClientNode(node: Node) { * @param typeUrl The resource type URL * @param names The list of resource names that are being requested */ -export function updateRequestedNameList(typeUrl: AdsTypeUrl, names: string[]) { +export function updateCsdsRequestedNameList(typeUrl: AdsTypeUrl, names: string[]) { + trace('Update type URL ' + typeUrl + ' with names [' + names + ']'); const currentTime = dateToProtoTimestamp(new Date()); const configMap = configStatus[typeUrl]; for (const name of names) { @@ -100,12 +107,13 @@ export function updateRequestedNameList(typeUrl: AdsTypeUrl, names: string[]) { * @param versionInfo The version info field from this response * @param updates The lists of resources that passed and failed validation */ -export function updateResourceResponse(typeUrl: AdsTypeUrl, versionInfo: string, updates: HandleResponseResult) { +export function updateCsdsResourceResponse(typeUrl: AdsTypeUrl, versionInfo: string, updates: HandleResponseResult) { const currentTime = dateToProtoTimestamp(new Date()); const configMap = configStatus[typeUrl]; for (const {name, raw} of updates.accepted) { const mapEntry = configMap.get(name); if (mapEntry) { + trace('Updated ' + typeUrl + ' resource ' + name + ' to state ACKED'); mapEntry.client_status = 'ACKED'; mapEntry.version_info = versionInfo; mapEntry.xds_config = raw; @@ -116,6 +124,7 @@ export function updateResourceResponse(typeUrl: AdsTypeUrl, versionInfo: string, for (const {name, error, raw} of updates.rejected) { const mapEntry = configMap.get(name); if (mapEntry) { + trace('Updated ' + typeUrl + ' resource ' + name + ' to state NACKED'); mapEntry.client_status = 'NACKED'; mapEntry.error_state = { failed_configuration: raw, @@ -128,6 +137,7 @@ export function updateResourceResponse(typeUrl: AdsTypeUrl, versionInfo: string, for (const name of updates.missing) { const mapEntry = configMap.get(name); if (mapEntry) { + trace('Updated ' + typeUrl + ' resource ' + name + ' to state DOES_NOT_EXIST'); mapEntry.client_status = 'DOES_NOT_EXIST'; mapEntry.version_info = versionInfo; mapEntry.xds_config = null; @@ -144,16 +154,18 @@ function getCurrentConfig(): ClientConfig { genericConfigList.push(configValue); } } - return { + const config = { node: clientNode, generic_xds_configs: genericConfigList }; + trace('Sending curent config ' + JSON.stringify(config, undefined, 2)); + return config; } const csdsImplementation: ClientStatusDiscoveryServiceHandlers = { FetchClientStatus(call: ServerUnaryCall, callback: sendUnaryData) { const request = call.request; - if (request.node_matchers !== null) { + if (request.node_matchers.length > 0) { callback({ code: status.INVALID_ARGUMENT, details: 'Node matchers not supported' @@ -166,7 +178,7 @@ const csdsImplementation: ClientStatusDiscoveryServiceHandlers = { }, StreamClientStatus(call: ServerDuplexStream) { call.on('data', (request: ClientStatusRequest__Output) => { - if (request.node_matchers !== null) { + if (request.node_matchers.length > 0) { call.emit('error', { code: status.INVALID_ARGUMENT, details: 'Node matchers not supported' diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 6c8bcb67f..75a567a54 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -51,6 +51,7 @@ import { Cluster__Output } from './generated/envoy/config/cluster/v3/Cluster'; import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; import { Duration } from './generated/google/protobuf/Duration'; import { AdsOutputType, AdsTypeUrl, CDS_TYPE_URL_V2, CDS_TYPE_URL_V3, decodeSingleResource, EDS_TYPE_URL_V2, EDS_TYPE_URL_V3, LDS_TYPE_URL_V2, LDS_TYPE_URL_V3, RDS_TYPE_URL_V2, RDS_TYPE_URL_V3 } from './resources'; +import { setCsdsClientNode, updateCsdsRequestedNameList, updateCsdsResourceResponse } from './csds'; const TRACER_NAME = 'xds_client'; @@ -384,6 +385,7 @@ export class XdsClient { ...nodeV3, client_features: ['envoy.lrs.supports_send_all_clusters'], }; + setCsdsClientNode(this.adsNodeV3); if (this.apiVersion === XdsApiVersion.V2) { trace('ADS Node: ' + JSON.stringify(this.adsNodeV2, undefined, 2)); trace('LRS Node: ' + JSON.stringify(this.lrsNodeV2, undefined, 2)); @@ -514,12 +516,14 @@ export class XdsClient { } catch (e) { trace('Nacking message with protobuf parsing error: ' + e.message); this.nack(message.type_url, e.message); + return; } if (handleResponseResult === null) { // Null handleResponseResult means that the type_url was unrecognized trace('Nacking message with unknown type URL ' + message.type_url); this.nack(message.type_url, `Unknown type_url ${message.type_url}`); } else { + updateCsdsResourceResponse(message.type_url as AdsTypeUrl, message.version_info, handleResponseResult.result); if (handleResponseResult.result.rejected.length > 0) { // rejected.length > 0 means that at least one message validation failed const errorString = `${handleResponseResult.serviceKind.toUpperCase()} Error: ${handleResponseResult.result.rejected[0].error}`; @@ -754,8 +758,16 @@ export class XdsClient { } this.maybeStartAdsStream(); this.maybeStartLrsStream(); + if (!this.adsCallV2 && !this.adsCallV3) { + /* If the stream is not set up yet at this point, shortcut the rest + * becuase nothing will actually be sent. This would mainly happen if + * the bootstrap file has not been read yet. In that case, the output + * of getTypeUrl is garbage and everything after that is invalid. */ + return; + } trace('Sending update for ' + serviceKind + ' with names ' + this.adsState[serviceKind].getResourceNames()); const typeUrl = this.getTypeUrl(serviceKind); + updateCsdsRequestedNameList(typeUrl, this.adsState[serviceKind].getResourceNames()); this.maybeSendAdsMessage(typeUrl, this.adsState[serviceKind].getResourceNames(), this.adsState[serviceKind].nonce, this.adsState[serviceKind].versionInfo); } From efa6ea1d3e5575ad4717a337dd188f7154c7c815 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Dec 2021 11:38:00 -0500 Subject: [PATCH 1576/1899] grpc-js-xds: Include additional paths when loading csds protos --- packages/grpc-js-xds/src/csds.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js-xds/src/csds.ts b/packages/grpc-js-xds/src/csds.ts index 40ca67f1f..6454e1ad1 100644 --- a/packages/grpc-js-xds/src/csds.ts +++ b/packages/grpc-js-xds/src/csds.ts @@ -205,6 +205,8 @@ const loadedProto = loadSync('envoy/service/status/v3/csds.proto', { // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', __dirname + '/../../deps/xds/', + __dirname + '/../../deps/protoc-gen-validate/', + __dirname + '/../../deps/googleapis/' ], }); From 575c2004f374817c5272f02889b927d4d7221eca Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Dec 2021 12:02:52 -0500 Subject: [PATCH 1577/1899] Skip some tests to make the Linux test job green --- packages/grpc-js/test/test-server.ts | 6 +++++- test/gulpfile.ts | 8 ++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index a5f7ec80b..2513b1fe2 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -848,7 +848,11 @@ describe('Compressed requests', () => { }); }); - it('Should not compress requests when the NoCompress write flag is used', done => { + /* As of Node 16, Writable and Duplex streams validate the encoding + * argument to write, and the flags values we are passing there are not + * valid. We don't currently have an alternative way to pass that flag + * down, so for now this feature is not supported. */ + it.skip('Should not compress requests when the NoCompress write flag is used', done => { const bidiStream = client.bidiStream(); let timesRequested = 0; let timesResponded = 0; diff --git a/test/gulpfile.ts b/test/gulpfile.ts index 2024f02cb..6d43d4472 100644 --- a/test/gulpfile.ts +++ b/test/gulpfile.ts @@ -25,6 +25,10 @@ import * as semver from 'semver'; const testDir = __dirname; const apiTestDir = path.resolve(testDir, 'api'); +/* The native library has some misbehavior in specific tests when running in + * Node 14 and above. */ +const NATIVE_SUPPORT_RANGE = '<14'; + const runInstall = () => { return execa('npm', ['install'], {cwd: testDir, stdio: 'inherit'}); }; @@ -51,11 +55,11 @@ const testJsClientNativeServer = runTestsWithFixture('native', 'js'); const testNativeClientJsServer = runTestsWithFixture('js', 'native'); const testJsClientJsServer = runTestsWithFixture('js', 'js'); -const test = gulp.series( +const test = semver.satisfies(process.version, NATIVE_SUPPORT_RANGE)? gulp.series( testJsClientJsServer, testJsClientNativeServer, testNativeClientJsServer - ); + ) : testJsClientJsServer; export { install, From 40c2f61eba518970210ec857cb067f069b907bf2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 10:27:21 -0500 Subject: [PATCH 1578/1899] Fix server decompression sequencing, add tracing --- packages/grpc-js/src/server-call.ts | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 709d20d41..78cab5a9a 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -737,9 +737,24 @@ export class Http2ServerCallStream< ) { const decoder = new StreamDecoder(); + let readsDone = false; + + let pendingMessageProcessing = false; + + let pushedEnd = false; + + const maybePushEnd = () => { + if (!pushedEnd && readsDone && !pendingMessageProcessing) { + pushedEnd = true; + this.pushOrBufferMessage(readable, null); + } + } + this.stream.on('data', async (data: Buffer) => { const messages = decoder.write(data); + pendingMessageProcessing = true; + this.stream.pause(); for (const message of messages) { if ( this.maxReceiveMessageSize !== -1 && @@ -763,10 +778,14 @@ export class Http2ServerCallStream< this.pushOrBufferMessage(readable, decompressedMessage); } + pendingMessageProcessing = false; + this.stream.resume(); + maybePushEnd(); }); this.stream.once('end', () => { - this.pushOrBufferMessage(readable, null); + readsDone = true; + maybePushEnd(); }); } @@ -810,6 +829,7 @@ export class Http2ServerCallStream< messageBytes: Buffer | null ) { if (messageBytes === null) { + trace('Received end of stream'); if (this.canPush) { readable.push(null); } else { @@ -819,6 +839,8 @@ export class Http2ServerCallStream< return; } + trace('Received message of length ' + messageBytes.length); + this.isPushPending = true; try { From c52cb842af6c4d734686524cfbb30091042cbd3c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 11:07:29 -0500 Subject: [PATCH 1579/1899] Add detailed assertion output for some resolver tests, skip IPv4+IPv6 test --- packages/grpc-js/test/test-resolver.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 7addfa232..eb4290fc8 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -24,7 +24,7 @@ import * as resolver_uds from '../src/resolver-uds'; import * as resolver_ip from '../src/resolver-ip'; import { ServiceConfig } from '../src/service-config'; import { StatusObject } from '../src/call-stream'; -import { SubchannelAddress, isTcpSubchannelAddress } from "../src/subchannel-address"; +import { SubchannelAddress, isTcpSubchannelAddress, subchannelAddressToString } from "../src/subchannel-address"; import { parseUri, GrpcUri } from '../src/uri-parser'; describe('Name Resolver', () => { @@ -223,7 +223,7 @@ describe('Name Resolver', () => { isTcpSubchannelAddress(addr) && addr.host === '127.0.0.1' && addr.port === 443 - ) + ), `None of [${addressList.map(addr => subchannelAddressToString(addr))}] matched '127.0.0.1:443'` ); done(); }, @@ -263,7 +263,10 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); - it('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { + /* This DNS name resolves to only the IPv4 address on Windows, and only the + * IPv6 address on Mac. There is no result that we can consistently test + * for here. */ + it.skip('Should resolve a DNS name to IPv4 and IPv6 addresses', done => { const target = resolverManager.mapUriDefaultScheme(parseUri('loopback46.unittest.grpc.io')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -279,7 +282,7 @@ describe('Name Resolver', () => { isTcpSubchannelAddress(addr) && addr.host === '127.0.0.1' && addr.port === 443 - ) + ), `None of [${addressList.map(addr => subchannelAddressToString(addr))}] matched '127.0.0.1:443'` ); /* TODO(murgatroid99): check for IPv6 result, once we can get that * consistently */ From 57cbf5c8861a91c3229d88e32fc0c82992338246 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 13:44:46 -0500 Subject: [PATCH 1580/1899] Increase TLS vesion on Windows tests to fix nvm download --- run-tests.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run-tests.bat b/run-tests.bat index 1eebbd4a6..ae9ca1922 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -21,7 +21,7 @@ powershell -c "[System.Environment]::OSVersion" powershell -c "Get-WmiObject -Class Win32_ComputerSystem" powershell -c "(Get-WmiObject -Class Win32_ComputerSystem).SystemType" -powershell -c "& { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" +powershell -c "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; & { iwr https://raw.githubusercontent.com/grumpycoders/nvm-ps/master/nvm.ps1 | iex }" SET PATH=%APPDATA%\nvm-ps;%APPDATA%\nvm-ps\nodejs;%PATH% SET JOBS=8 From 359014eeedc3de46ae7ac73e6a88a8068d4afcf0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 14:46:33 -0500 Subject: [PATCH 1581/1899] Drop Node 8 tests on Windows --- run-tests.bat | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index ae9ca1922..ce4480e44 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -28,8 +28,8 @@ SET JOBS=8 call nvm version -call nvm install 8 -call nvm use 8 +call nvm install 10 +call nvm use 10 SET npm_config_fetch_retries=5 @@ -38,7 +38,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (8 10 12) do ( +for %%v in (10 12) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( From 20dbaa8e27faad9e41d5ce0bafa40f082a37117c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 14:54:56 -0500 Subject: [PATCH 1582/1899] Make npm clean scripts platform-agnostic --- packages/grpc-js/package.json | 2 +- packages/proto-loader/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 69d565ad3..ad12fb82e 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -44,7 +44,7 @@ ], "scripts": { "build": "npm run compile", - "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", + "clean": "rimraf ./build", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "lint": "npm run check", diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index cd27743a0..db6e4755e 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -14,7 +14,7 @@ "typings": "build/src/index.d.ts", "scripts": { "build": "npm run compile", - "clean": "node -e 'require(\"rimraf\")(\"./build\", () => {})'", + "clean": "rimraf ./build", "compile": "tsc -p .", "format": "clang-format -i -style=\"{Language: JavaScript, BasedOnStyle: Google, ColumnLimit: 80}\" src/*.ts test/*.ts", "lint": "tslint -c node_modules/google-ts-style/tslint.json -p . -t codeFrame --type-check", From d5ce78434845442931bff2baedccc91730e0d3b1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 14:56:52 -0500 Subject: [PATCH 1583/1899] Update submodules in Windows test script --- run-tests.bat | 2 ++ 1 file changed, 2 insertions(+) diff --git a/run-tests.bat b/run-tests.bat index ce4480e44..611f28ca4 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -31,6 +31,8 @@ call nvm version call nvm install 10 call nvm use 10 +git submodule update --init --recursive + SET npm_config_fetch_retries=5 call npm install || goto :error From e41b99dffc4bd4a676b7c6932ea46695c511d629 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Dec 2021 15:23:06 -0500 Subject: [PATCH 1584/1899] Fix a couple of issues with tests on Windows --- packages/grpc-js/test/test-client.ts | 3 ++- test/api/connectivity_test.js | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts index 51af05416..4a02ff3de 100644 --- a/packages/grpc-js/test/test-client.ts +++ b/packages/grpc-js/test/test-client.ts @@ -79,7 +79,8 @@ describe('Client without a server', () => { after(() => { client.close(); }); - it('should fail multiple calls to the nonexistent server', done => { + it('should fail multiple calls to the nonexistent server', function(done) { + this.timeout(5000); // Regression test for https://github.com/grpc/grpc-node/issues/1411 client.makeUnaryRequest('/service/method', x => x, x => x, Buffer.from([]), (error, value) => { assert(error); diff --git a/test/api/connectivity_test.js b/test/api/connectivity_test.js index b5d31943d..64764d7d4 100644 --- a/test/api/connectivity_test.js +++ b/test/api/connectivity_test.js @@ -61,7 +61,9 @@ const serviceImpl = { describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, function() { it('client should not wait for ready by default', function(done) { this.timeout(15000); - const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', clientGrpc.credentials.createInsecure()); + /* TCP port 47 is reserved according to + * https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers */ + const disconnectedClient = new TestServiceClient('localhost:47', clientGrpc.credentials.createInsecure()); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 10); disconnectedClient.unary({}, {deadline: deadline}, (error, value) =>{ @@ -72,7 +74,7 @@ describe(`${anyGrpc.clientName} client -> ${anyGrpc.serverName} server`, functio }); it('client should wait for a connection with waitForReady on', function(done) { this.timeout(15000); - const disconnectedClient = new TestServiceClient('foo.test.google.com:50051', clientGrpc.credentials.createInsecure()); + const disconnectedClient = new TestServiceClient('localhost:47', clientGrpc.credentials.createInsecure()); const metadata = new clientGrpc.Metadata({waitForReady: true}); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + 10); From f2e698a810b1924cb8b155ae3fcd5827eda591b6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 10:47:01 -0500 Subject: [PATCH 1585/1899] Skip clean step in Windows test runs --- run-tests.bat | 1 - 1 file changed, 1 deletion(-) diff --git a/run-tests.bat b/run-tests.bat index 611f28ca4..3b0aa07d0 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -55,7 +55,6 @@ for %%v in (10 12) do ( node -e "process.exit(process.version.startsWith('v%%v') ? 0 : -1)" || goto :error - call .\node_modules\.bin\gulp cleanAll || SET FAILED=1 call .\node_modules\.bin\gulp setup || SET FAILED=1 call .\node_modules\.bin\gulp test || SET FAILED=1 cmd.exe /c "SET GRPC_DNS_RESOLVER=ares& call .\node_modules\.bin\gulp nativeTestOnly" || SET FAILED=1 From f706d524e7d4de8f305c3d942d1a74830e831f9a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 10:47:48 -0500 Subject: [PATCH 1586/1899] Ignore trailing whitespace in proto-loader golden file test diff --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index db6e4755e..093bfa5a7 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -25,7 +25,7 @@ "pretest": "npm run compile", "posttest": "npm run check", "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json --includeComments -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", - "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -r ./golden-generated ./golden-generated-old" + "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -rZ ./golden-generated ./golden-generated-old" }, "repository": { "type": "git", From ba375e73716d921eef9933eba76f3e077ae51fb5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 10:48:38 -0500 Subject: [PATCH 1587/1899] Skip a test because it behaves weirdly on Mac --- packages/grpc-js/test/test-resolver.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index eb4290fc8..354413ea6 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -207,7 +207,15 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); - it('Should resolve a name with multiple dots', done => { + /* The DNS entry for loopback4.unittest.grpc.io only has a single A record + * with the address 127.0.0.1, but the Mac DNS resolver appears to use + * NAT64 to create an IPv6 address in that case, so it instead returns + * 64:ff9b::7f00:1. Handling that kind of translation is outside of the + * scope of this test, so we are skipping it. The test primarily exists + * as a regression test for https://github.com/grpc/grpc-node/issues/1044, + * and the test 'Should resolve gRPC interop servers' tests the same thing. + */ + it.skip('Should resolve a name with multiple dots', done => { const target = resolverManager.mapUriDefaultScheme(parseUri('loopback4.unittest.grpc.io')!)!; const listener: resolverManager.ResolverListener = { onSuccessfulResolution: ( @@ -317,6 +325,10 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); + /* This test also serves as a regression test for + * https://github.com/grpc/grpc-node/issues/1044, specifically handling + * hyphens and multiple periods in a DNS name. It should not be skipped + * unless there is another test for the same issue. */ it('Should resolve gRPC interop servers', done => { let completeCount = 0; const target1 = resolverManager.mapUriDefaultScheme(parseUri('grpc-test.sandbox.googleapis.com')!)!; From 8d771044e75e5d6a659458297bc9229d7e1b2846 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 11:14:53 -0500 Subject: [PATCH 1588/1899] Make diff command work on Mac, make file comment use consistent directory separator --- packages/proto-loader/bin/proto-loader-gen-types.ts | 6 +++--- packages/proto-loader/package.json | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 3ecf6dcc4..b416d3382 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -379,7 +379,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob let usesLong: boolean = false; let seenDeps: Set = new Set(); const childTypes = getChildMessagesAndEnums(messageType); - formatter.writeLine(`// Original file: ${messageType.filename}`); + formatter.writeLine(`// Original file: ${messageType.filename?.replace(/\\/g, '/')}`); formatter.writeLine(''); messageType.fieldsArray.sort((fieldA, fieldB) => fieldA.id - fieldB.id); for (const field of messageType.fieldsArray) { @@ -437,7 +437,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob } function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, options: GeneratorOptions, nameOverride?: string) { - formatter.writeLine(`// Original file: ${enumType.filename}`); + formatter.writeLine(`// Original file: ${enumType.filename?.replace(/\\/g, '/')}`); formatter.writeLine(''); if (options.includeComments) { formatComment(formatter, enumType.comment); @@ -590,7 +590,7 @@ function generateServiceDefinitionInterface(formatter: TextFormatter, serviceTyp } function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { - formatter.writeLine(`// Original file: ${serviceType.filename}`); + formatter.writeLine(`// Original file: ${serviceType.filename?.replace(/\\/g, '/')}`); formatter.writeLine(''); const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; formatter.writeLine(`import type * as grpc from '${grpcImportPath}'`); diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 093bfa5a7..6db5cb721 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -25,7 +25,7 @@ "pretest": "npm run compile", "posttest": "npm run check", "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json --includeComments -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", - "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -rZ ./golden-generated ./golden-generated-old" + "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -rb ./golden-generated ./golden-generated-old" }, "repository": { "type": "git", From 2af9a05ee4eff892f4cd6b7a8e864c7e0115788c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 13:17:01 -0500 Subject: [PATCH 1589/1899] Ensure consistent null in missing file names --- packages/proto-loader/bin/proto-loader-gen-types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index b416d3382..b0a9819b4 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -379,7 +379,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob let usesLong: boolean = false; let seenDeps: Set = new Set(); const childTypes = getChildMessagesAndEnums(messageType); - formatter.writeLine(`// Original file: ${messageType.filename?.replace(/\\/g, '/')}`); + formatter.writeLine(`// Original file: ${(messageType.filename ?? 'null')?.replace(/\\/g, '/')}`); formatter.writeLine(''); messageType.fieldsArray.sort((fieldA, fieldB) => fieldA.id - fieldB.id); for (const field of messageType.fieldsArray) { @@ -437,7 +437,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob } function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, options: GeneratorOptions, nameOverride?: string) { - formatter.writeLine(`// Original file: ${enumType.filename?.replace(/\\/g, '/')}`); + formatter.writeLine(`// Original file: ${(enumType.filename ?? 'null')?.replace(/\\/g, '/')}`); formatter.writeLine(''); if (options.includeComments) { formatComment(formatter, enumType.comment); @@ -590,7 +590,7 @@ function generateServiceDefinitionInterface(formatter: TextFormatter, serviceTyp } function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { - formatter.writeLine(`// Original file: ${serviceType.filename?.replace(/\\/g, '/')}`); + formatter.writeLine(`// Original file: ${(serviceType.filename ?? 'null')?.replace(/\\/g, '/')}`); formatter.writeLine(''); const grpcImportPath = options.grpcLib.startsWith('.') ? getPathToRoot(serviceType) + options.grpcLib : options.grpcLib; formatter.writeLine(`import type * as grpc from '${grpcImportPath}'`); From 7cccc392181050f1e7ed7334f148d35dbe6b7b5f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 16:14:52 -0500 Subject: [PATCH 1590/1899] grpc-js: Preserve order of metadata and messages with async interceptors --- packages/grpc-js/src/call-stream.ts | 35 +++++++++++++--- packages/grpc-js/src/client-interceptors.ts | 44 ++++++++++++++++++--- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 70a9ac6ee..915d812fc 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -149,6 +149,9 @@ export function isInterceptingListener( } export class InterceptingListenerImpl implements InterceptingListener { + private processingMetadata = false; + private hasPendingMessage = false; + private pendingMessage: any; private processingMessage = false; private pendingStatus: StatusObject | null = null; constructor( @@ -156,9 +159,27 @@ export class InterceptingListenerImpl implements InterceptingListener { private nextListener: InterceptingListener ) {} + private processPendingMessage() { + if (this.hasPendingMessage) { + this.nextListener.onReceiveMessage(this.pendingMessage); + this.pendingMessage = null; + this.hasPendingMessage = false; + } + } + + private processPendingStatus() { + if (this.pendingStatus) { + this.nextListener.onReceiveStatus(this.pendingStatus); + } + } + onReceiveMetadata(metadata: Metadata): void { + this.processingMetadata = true; this.listener.onReceiveMetadata(metadata, (metadata) => { + this.processingMetadata = false; this.nextListener.onReceiveMetadata(metadata); + this.processPendingMessage(); + this.processPendingStatus(); }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -168,15 +189,18 @@ export class InterceptingListenerImpl implements InterceptingListener { this.processingMessage = true; this.listener.onReceiveMessage(message, (msg) => { this.processingMessage = false; - this.nextListener.onReceiveMessage(msg); - if (this.pendingStatus) { - this.nextListener.onReceiveStatus(this.pendingStatus); + if (this.processingMetadata) { + this.pendingMessage = msg; + this.hasPendingMessage = true; + } else { + this.nextListener.onReceiveMessage(msg); + this.processPendingStatus(); } }); } onReceiveStatus(status: StatusObject): void { this.listener.onReceiveStatus(status, (processedStatus) => { - if (this.processingMessage) { + if (this.processingMetadata || this.processingMessage) { this.pendingStatus = processedStatus; } else { this.nextListener.onReceiveStatus(processedStatus); @@ -283,7 +307,7 @@ export class Http2CallStream implements Call { private outputStatus() { /* Precondition: this.finalStatus !== null */ - if (!this.statusOutput) { + if (this.listener && !this.statusOutput) { this.statusOutput = true; const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! @@ -692,6 +716,7 @@ export class Http2CallStream implements Call { this.trace('Sending metadata'); this.listener = listener; this.channel._startCallStream(this, metadata); + this.maybeOutputStatus(); } private destroyHttp2Stream() { diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 5dfbeba14..ddb296ff1 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -208,8 +208,18 @@ export class InterceptingCall implements InterceptingCallInterface { */ private requester: FullRequester; /** - * Indicates that a message has been passed to the listener's onReceiveMessage - * method it has not been passed to the corresponding next callback + * Indicates that metadata has been passed to the requester's start + * method but it has not been passed to the corresponding next callback + */ + private processingMetadata = false; + /** + * Message context for a pending message that is waiting for + */ + private pendingMessageContext: MessageContext | null = null; + private pendingMessage: any; + /** + * Indicates that a message has been passed to the requester's sendMessage + * method but it has not been passed to the corresponding next callback */ private processingMessage = false; /** @@ -242,6 +252,21 @@ export class InterceptingCall implements InterceptingCallInterface { getPeer() { return this.nextCall.getPeer(); } + + private processPendingMessage() { + if (this.pendingMessageContext) { + this.nextCall.sendMessageWithContext(this.pendingMessageContext, this.pendingMessage); + this.pendingMessageContext = null; + this.pendingMessage = null; + } + } + + private processPendingHalfClose() { + if (this.pendingHalfClose) { + this.nextCall.halfClose(); + } + } + start( metadata: Metadata, interceptingListener?: Partial @@ -257,7 +282,9 @@ export class InterceptingCall implements InterceptingCallInterface { interceptingListener?.onReceiveStatus?.bind(interceptingListener) ?? ((status) => {}), }; + this.processingMetadata = true; this.requester.start(metadata, fullInterceptingListener, (md, listener) => { + this.processingMetadata = false; let finalInterceptingListener: InterceptingListener; if (isInterceptingListener(listener)) { finalInterceptingListener = listener; @@ -276,6 +303,8 @@ export class InterceptingCall implements InterceptingCallInterface { ); } this.nextCall.start(md, finalInterceptingListener); + this.processPendingMessage(); + this.processPendingHalfClose(); }); } // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -283,9 +312,12 @@ export class InterceptingCall implements InterceptingCallInterface { this.processingMessage = true; this.requester.sendMessage(message, (finalMessage) => { this.processingMessage = false; - this.nextCall.sendMessageWithContext(context, finalMessage); - if (this.pendingHalfClose) { - this.nextCall.halfClose(); + if (this.processingMetadata) { + this.pendingMessageContext = context; + this.pendingMessage = message; + } else { + this.nextCall.sendMessageWithContext(context, finalMessage); + this.processPendingHalfClose(); } }); } @@ -298,7 +330,7 @@ export class InterceptingCall implements InterceptingCallInterface { } halfClose(): void { this.requester.halfClose(() => { - if (this.processingMessage) { + if (this.processingMetadata || this.processingMessage) { this.pendingHalfClose = true; } else { this.nextCall.halfClose(); From 86f3ffd96ce7e656acd004caf10c1c6c98ceb84c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Dec 2021 16:31:29 -0500 Subject: [PATCH 1591/1899] grpc-js: Update version to 1.4.5 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e14ffa0eb..02400ca90 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.4", + "version": "1.4.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From b12330abfd8ff9207a332e8a47e05703c26697f5 Mon Sep 17 00:00:00 2001 From: Cosmin-Catalin Crisan Date: Fri, 10 Dec 2021 20:20:11 +0200 Subject: [PATCH 1592/1899] grpc-js: Send backoffOptions to BackoffTimeout --- packages/grpc-js/src/resolving-load-balancer.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 235748f70..5bc861283 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -26,7 +26,7 @@ import { ConnectivityState } from './connectivity-state'; import { ConfigSelector, createResolver, Resolver } from './resolver'; import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; -import { BackoffTimeout } from './backoff-timeout'; +import { BackoffOptions, BackoffTimeout } from './backoff-timeout'; import { Status } from './constants'; import { StatusObject } from './call-stream'; import { Metadata } from './metadata'; @@ -248,7 +248,10 @@ export class ResolvingLoadBalancer implements LoadBalancer { }, channelOptions ); - + const backoffOptions: BackoffOptions = { + initialDelay: channelOptions['grpc.initial_reconnect_backoff_ms'], + maxDelay: channelOptions['grpc.max_reconnect_backoff_ms'], + }; this.backoffTimeout = new BackoffTimeout(() => { if (this.continueResolving) { this.updateResolution(); @@ -256,7 +259,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { } else { this.updateState(this.latestChildState, this.latestChildPicker); } - }); + }, backoffOptions); this.backoffTimeout.unref(); } From 8e53f034d0ea6e1226b21f29d5249ecf60632b65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Dec 2021 10:05:37 -0500 Subject: [PATCH 1593/1899] grpc-js: Add credentials.createFromSecureContext --- packages/grpc-js/src/channel-credentials.ts | 57 +++++++++++---------- packages/grpc-js/src/index.ts | 1 + 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 02c9c309b..94b66c1bd 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -15,7 +15,7 @@ * */ -import { ConnectionOptions, createSecureContext, PeerCertificate } from 'tls'; +import { ConnectionOptions, createSecureContext, PeerCertificate, SecureContext } from 'tls'; import { CallCredentials } from './call-credentials'; import { CIPHER_SUITES, getDefaultRootsData } from './tls-helpers'; @@ -110,6 +110,7 @@ export abstract class ChannelCredentials { * @param rootCerts The root certificate data. * @param privateKey The client certificate private key, if available. * @param certChain The client certificate key chain, if available. + * @param verifyOptions Additional options to modify certificate verification */ static createSsl( rootCerts?: Buffer | null, @@ -130,14 +131,35 @@ export abstract class ChannelCredentials { 'Certificate chain must be given with accompanying private key' ); } + const secureContext = createSecureContext({ + ca: rootCerts ?? getDefaultRootsData() ?? undefined, + key: privateKey ?? undefined, + cert: certChain ?? undefined, + ciphers: CIPHER_SUITES, + }); return new SecureChannelCredentialsImpl( - rootCerts || getDefaultRootsData(), - privateKey || null, - certChain || null, - verifyOptions || {} + secureContext, + verifyOptions ?? {} ); } + /** + * Return a new ChannelCredentials instance with credentials created using + * the provided secureContext. The resulting instances can be used to + * construct a Channel that communicates over TLS. gRPC will not override + * anything in the provided secureContext, so the environment variables + * GRPC_SSL_CIPHER_SUITES and GRPC_DEFAULT_SSL_ROOTS_FILE_PATH will + * not be applied. + * @param secureContext The return value of tls.createSecureContext() + * @param verifyOptions Additional options to modify certificate verification + */ + static createFromSecureContext(secureContext: SecureContext, verifyOptions?: VerifyOptions): ChannelCredentials { + return new SecureChannelCredentialsImpl( + secureContext, + verifyOptions ?? {} + ) + } + /** * Return a new ChannelCredentials instance with no credentials. */ @@ -170,18 +192,10 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { connectionOptions: ConnectionOptions; constructor( - private rootCerts: Buffer | null, - private privateKey: Buffer | null, - private certChain: Buffer | null, + private secureContext: SecureContext, private verifyOptions: VerifyOptions ) { super(); - const secureContext = createSecureContext({ - ca: rootCerts || undefined, - key: privateKey || undefined, - cert: certChain || undefined, - ciphers: CIPHER_SUITES, - }); this.connectionOptions = { secureContext }; @@ -210,19 +224,10 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { return true; } if (other instanceof SecureChannelCredentialsImpl) { - if (!bufferOrNullEqual(this.rootCerts, other.rootCerts)) { - return false; - } - if (!bufferOrNullEqual(this.privateKey, other.privateKey)) { - return false; - } - if (!bufferOrNullEqual(this.certChain, other.certChain)) { - return false; - } return ( - this.verifyOptions.checkServerIdentity === - other.verifyOptions.checkServerIdentity - ); + this.secureContext === other.secureContext && + this.verifyOptions.checkServerIdentity === other.verifyOptions.checkServerIdentity + ); } else { return false; } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index c4c774d93..4bf1d9363 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -109,6 +109,7 @@ export const credentials = { // from channel-credentials.ts createInsecure: ChannelCredentials.createInsecure, createSsl: ChannelCredentials.createSsl, + createFromSecureContext: ChannelCredentials.createFromSecureContext, // from call-credentials.ts createFromMetadataGenerator: CallCredentials.createFromMetadataGenerator, From 33c5abd16353eba7c2347bb8368a941df5a37c49 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 13 Dec 2021 14:18:12 -0500 Subject: [PATCH 1594/1899] grpc-js: Clean up some dependencies --- packages/grpc-js/package.json | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ad12fb82e..854000a3d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -21,7 +21,7 @@ "@types/mocha": "^5.2.6", "@types/ncp": "^2.0.1", "@types/pify": "^3.0.2", - "@types/yargs": "^15.0.5", + "@types/semver": "^7.3.9", "clang-format": "^1.0.55", "execa": "^2.0.3", "gts": "^2.0.0", @@ -33,9 +33,9 @@ "ncp": "^2.0.0", "pify": "^4.0.1", "rimraf": "^3.0.2", + "semver": "^7.3.5", "ts-node": "^8.3.0", - "typescript": "^3.7.2", - "yargs": "^15.4.1" + "typescript": "^3.7.2" }, "contributors": [ { @@ -59,8 +59,7 @@ }, "dependencies": { "@grpc/proto-loader": "^0.6.4", - "@types/node": ">=12.12.47", - "@types/semver": "^7.3.9" + "@types/node": ">=12.12.47" }, "files": [ "src/**/*.ts", From ac893ca89fc1be95f3e62e9923a4c2ba88ddc0d3 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 29 Dec 2021 11:58:32 -0800 Subject: [PATCH 1595/1899] Use xds-test-server-5 as interop server image --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index c7a9adb6e..2df2ae42d 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -54,7 +54,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all,timeout,circuit_breaking,fault_injection,csds" \ --project_id=grpc-testing \ - --source_image=projects/grpc-testing/global/images/xds-test-server-4 \ + --source_image=projects/grpc-testing/global/images/xds-test-server-5 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ From a000d67a8869585d23d8e9f0a50195c5b364a240 Mon Sep 17 00:00:00 2001 From: Lidi Zheng Date: Wed, 29 Dec 2021 11:58:32 -0800 Subject: [PATCH 1596/1899] Use xds-test-server-5 as interop server image --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index a06cde84b..b584c21c3 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -54,7 +54,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh python3 grpc/tools/run_tests/run_xds_tests.py \ --test_case="all,timeout,circuit_breaking,fault_injection" \ --project_id=grpc-testing \ - --source_image=projects/grpc-testing/global/images/xds-test-server-4 \ + --source_image=projects/grpc-testing/global/images/xds-test-server-5 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ From 9f3001eb9737f282b31a4cbdcadb3c1f9994f667 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Jan 2022 10:08:40 -0800 Subject: [PATCH 1597/1899] proto-loader: Update yargs to version 17 --- packages/proto-loader/bin/proto-loader-gen-types.ts | 4 ++-- packages/proto-loader/package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index b0a9819b4..30df07bdc 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -767,8 +767,8 @@ async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { } } -function runScript() { - const argv = yargs +async function runScript() { + const argv = await yargs .parserConfiguration({ 'parse-positional-numbers': false }) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 6db5cb721..7fb179922 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -49,14 +49,14 @@ "lodash.camelcase": "^4.3.0", "long": "^4.0.0", "protobufjs": "^6.10.0", - "yargs": "^16.1.1" + "yargs": "^17.3.1" }, "devDependencies": { "@types/lodash.camelcase": "^4.3.4", "@types/mkdirp": "^1.0.1", "@types/mocha": "^5.2.7", "@types/node": "^10.17.26", - "@types/yargs": "^15.0.5", + "@types/yargs": "^17.0.8", "clang-format": "^1.2.2", "gts": "^1.1.0", "rimraf": "^3.0.2", From 9f5187fbaaa4a7527973fe70d5655947ed714e8a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Jan 2022 10:09:17 -0800 Subject: [PATCH 1598/1899] proto-loader: Increase version to 0.6.8 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 7fb179922..b1d3182f7 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.7", + "version": "0.6.8", "author": "Google Inc.", "contributors": [ { From 311d22e03e5818260feedaaf233f86cc55ed581b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Jan 2022 12:41:41 -0800 Subject: [PATCH 1599/1899] grpc-js: Fix compatibility with @types/node 17.0.6 --- packages/grpc-js/src/object-stream.ts | 25 ++++++------------------- packages/grpc-js/src/server-call.ts | 5 ++--- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index b17058a7a..042820925 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -36,9 +36,9 @@ export interface IntermediateObjectWritable extends Writable { write(chunk: any & T, cb?: WriteCallback): boolean; write(chunk: any & T, encoding?: any, cb?: WriteCallback): boolean; setDefaultEncoding(encoding: string): this; - end(): void; - end(chunk: any & T, cb?: Function): void; - end(chunk: any & T, encoding?: any, cb?: Function): void; + end(): this; + end(chunk: any & T, cb?: Function): this; + end(chunk: any & T, encoding?: any, cb?: Function): this; } export interface ObjectWritable extends IntermediateObjectWritable { @@ -46,20 +46,7 @@ export interface ObjectWritable extends IntermediateObjectWritable { write(chunk: T, cb?: Function): boolean; write(chunk: T, encoding?: any, cb?: Function): boolean; setDefaultEncoding(encoding: string): this; - end(): void; - end(chunk: T, cb?: Function): void; - end(chunk: T, encoding?: any, cb?: Function): void; + end(): this; + end(chunk: T, cb?: Function): this; + end(chunk: T, encoding?: any, cb?: Function): this; } - -export type ObjectDuplex = { - read(size?: number): U; - - _write(chunk: T, encoding: string, callback: Function): void; - write(chunk: T, cb?: Function): boolean; - write(chunk: T, encoding?: any, cb?: Function): boolean; - end(): void; - end(chunk: T, cb?: Function): void; - end(chunk: T, encoding?: any, cb?: Function): void; -} & Duplex & - ObjectWritable & - ObjectReadable; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index be4429b0f..a79e401c6 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -236,7 +236,7 @@ export class ServerWritableStreamImpl this.trailingMetadata = metadata; } - super.end(); + return super.end(); } } @@ -282,7 +282,7 @@ export class ServerDuplexStreamImpl this.trailingMetadata = metadata; } - super.end(); + return super.end(); } } @@ -292,7 +292,6 @@ ServerDuplexStreamImpl.prototype._write = ServerWritableStreamImpl.prototype._write; ServerDuplexStreamImpl.prototype._final = ServerWritableStreamImpl.prototype._final; -ServerDuplexStreamImpl.prototype.end = ServerWritableStreamImpl.prototype.end; // Unary response callback signature. export type sendUnaryData = ( From e2dfb8fbcf0c7f0282e7becfaced75fdef20bb8f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Jan 2022 12:42:05 -0800 Subject: [PATCH 1600/1899] grpc-js: Increase version to 1.4.6 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 02400ca90..e3c983445 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.5", + "version": "1.4.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From fba2b9498f7ebf59cc1303dc39fcaf14b5cd3471 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 4 Jan 2022 14:00:25 -0800 Subject: [PATCH 1601/1899] Fix end type again for older @types/node versions --- packages/grpc-js/src/object-stream.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index 042820925..22ab8a41f 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -36,9 +36,9 @@ export interface IntermediateObjectWritable extends Writable { write(chunk: any & T, cb?: WriteCallback): boolean; write(chunk: any & T, encoding?: any, cb?: WriteCallback): boolean; setDefaultEncoding(encoding: string): this; - end(): this; - end(chunk: any & T, cb?: Function): this; - end(chunk: any & T, encoding?: any, cb?: Function): this; + end(): ReturnType extends Writable ? this : void; + end(chunk: any & T, cb?: Function): ReturnType extends Writable ? this : void; + end(chunk: any & T, encoding?: any, cb?: Function): ReturnType extends Writable ? this : void; } export interface ObjectWritable extends IntermediateObjectWritable { @@ -46,7 +46,7 @@ export interface ObjectWritable extends IntermediateObjectWritable { write(chunk: T, cb?: Function): boolean; write(chunk: T, encoding?: any, cb?: Function): boolean; setDefaultEncoding(encoding: string): this; - end(): this; - end(chunk: T, cb?: Function): this; - end(chunk: T, encoding?: any, cb?: Function): this; + end(): ReturnType extends Writable ? this : void; + end(chunk: T, cb?: Function): ReturnType extends Writable ? this : void; + end(chunk: T, encoding?: any, cb?: Function): ReturnType extends Writable ? this : void; } From 78631cdad826316e0a5d562fea55b2571484e615 Mon Sep 17 00:00:00 2001 From: Joey Harrington Date: Mon, 27 Dec 2021 12:55:16 -0800 Subject: [PATCH 1602/1899] Document grpc-js supported channel args in readme This moves the list of supported channel arguments from PACKAGE_COMPARISON.md into the readme, and also adds a link to the package comparison doc. resolves #1982, resolves #1983 --- PACKAGE-COMPARISON.md | 21 ++------------------- packages/grpc-js/README.md | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index fa0ea319e..f0c444195 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -28,22 +28,5 @@ Supported Electron Versions | All | >= 3 Supported Platforms | Linux, Windows, MacOS | All Supported Architectures | x86, x86-64, ARM7+ | All -In addition, all channel arguments defined in [this header file](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/grpc_types.h) are handled by the `grpc` library. Of those, the following are handled by the `@grpc/grpc-js` library: - - - `grpc.ssl_target_name_override` - - `grpc.primary_user_agent` - - `grpc.secondary_user_agent` - - `grpc.default_authority` - - `grpc.keepalive_time_ms` - - `grpc.keepalive_timeout_ms` - - `grpc.keepalive_permit_without_calls` - - `grpc.service_config` - - `grpc.max_concurrent_streams` - - `grpc.initial_reconnect_backoff_ms` - - `grpc.max_reconnect_backoff_ms` - - `grpc.use_local_subchannel_pool` - - `grpc.max_send_message_length` - - `grpc.max_receive_message_length` - - `grpc.enable_http_proxy` - - `channelOverride` - - `channelFactoryOverride` +In addition, all channel arguments defined in [this header file](https://github.com/grpc/grpc/blob/master/include/grpc/impl/codegen/grpc_types.h) are handled by the `grpc` library. +Of those, a subset are handled by the `@grpc/grpc-js` library. See [the README](https://github.com/grpc/grpc-node/blob/master/packages/grpc-js/README.md#supported-channel-options) for `@grpc/grpc-js` for the list of supported channel options. diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index df44264ce..4799b0f4a 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -36,6 +36,28 @@ This library does not directly handle `.proto` files. To use `.proto` files with - If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. - If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `generate_package_definition` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`. - If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead. +- If you are using any channel options supported in `grpc` but not supported in `@grpc/grpc-js`, you may need to adjust your code to handle the different behavior. Refer to [the list of supported options](#supported-channel-options) below. +- Refer to the [detailed package comparison](https://github.com/grpc/grpc-node/blob/master/PACKAGE-COMPARISON.md) for more details on the differences between `grpc` and `@grpc/grpc-js`. + +## Supported Channel Options +Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. The channel arguments supported by `@grpc/grpc-js` are: + - `grpc.ssl_target_name_override` + - `grpc.primary_user_agent` + - `grpc.secondary_user_agent` + - `grpc.default_authority` + - `grpc.keepalive_time_ms` + - `grpc.keepalive_timeout_ms` + - `grpc.keepalive_permit_without_calls` + - `grpc.service_config` + - `grpc.max_concurrent_streams` + - `grpc.initial_reconnect_backoff_ms` + - `grpc.max_reconnect_backoff_ms` + - `grpc.use_local_subchannel_pool` + - `grpc.max_send_message_length` + - `grpc.max_receive_message_length` + - `grpc.enable_http_proxy` + - `channelOverride` + - `channelFactoryOverride` ## Some Notes on API Guarantees From f049333e488d3446291d791b66383d1f2527cad7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Jan 2022 10:51:00 -0800 Subject: [PATCH 1603/1899] proto-loader: Decrease dependency to yargs 16 for compatibility with Node <12 --- packages/proto-loader/bin/proto-loader-gen-types.ts | 2 +- packages/proto-loader/package.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 30df07bdc..a819d12d4 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -768,7 +768,7 @@ async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { } async function runScript() { - const argv = await yargs + const argv = yargs .parserConfiguration({ 'parse-positional-numbers': false }) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index b1d3182f7..5694cb547 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -49,14 +49,14 @@ "lodash.camelcase": "^4.3.0", "long": "^4.0.0", "protobufjs": "^6.10.0", - "yargs": "^17.3.1" + "yargs": "^16.2.0" }, "devDependencies": { "@types/lodash.camelcase": "^4.3.4", "@types/mkdirp": "^1.0.1", "@types/mocha": "^5.2.7", "@types/node": "^10.17.26", - "@types/yargs": "^17.0.8", + "@types/yargs": "^16.0.4", "clang-format": "^1.2.2", "gts": "^1.1.0", "rimraf": "^3.0.2", From ee9226e3c87bdbf767e6360f0c897019cec9bae1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Jan 2022 10:51:45 -0800 Subject: [PATCH 1604/1899] proto-loader: Update version to 0.6.9 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 5694cb547..9b9431dc1 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.8", + "version": "0.6.9", "author": "Google Inc.", "contributors": [ { From ea1a266dec4a87546a48d29666a73d37d4c4d6e6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 6 Jan 2022 14:36:40 -0800 Subject: [PATCH 1605/1899] Update grpc-js and grpc-js-xds to version 1.5.0, and update README --- packages/grpc-js-xds/README.md | 3 ++- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js/package.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index 84d291508..1ac235c40 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -26,4 +26,5 @@ const client = new MyServiceClient('xds:///example.com:123'); - [xDS v3 API](https://github.com/grpc/proposal/blob/master/A30-xds-v3.md) - [xDS Timeouts](https://github.com/grpc/proposal/blob/master/A31-xds-timeout-support-and-config-selector.md) - [xDS Circuit Breaking](https://github.com/grpc/proposal/blob/master/A32-xds-circuit-breaking.md) - - [xDS Client-Side Fault Injection](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) \ No newline at end of file + - [xDS Client-Side Fault Injection](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) + - [Client Status Discovery Service](https://github.com/grpc/proposal/blob/master/A40-csds-support.md) \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 2ead8f1e8..d3d9ad72f 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.4.0", + "version": "1.5.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.4.0" + "@grpc/grpc-js": "~1.5.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 510eac614..97b647a86 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.4.6", + "version": "1.5.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From c95357ccd1a246178141ae4c5962e531f2c8466b Mon Sep 17 00:00:00 2001 From: Jason Praful <32552408+jasonpraful@users.noreply.github.com> Date: Fri, 7 Jan 2022 10:51:38 +0000 Subject: [PATCH 1606/1899] refactor: added max session memory to docs --- packages/grpc-js/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 4799b0f4a..cda4fec3c 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -56,6 +56,7 @@ Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. - `grpc.max_send_message_length` - `grpc.max_receive_message_length` - `grpc.enable_http_proxy` + - `grpc-node.max_session_memory` - `channelOverride` - `channelFactoryOverride` From d1762316e279d9a0dd224ca0a2eafc843f6a8bda Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 7 Jan 2022 12:21:12 -0800 Subject: [PATCH 1607/1899] grpc-js: Document recently-added channel options --- packages/grpc-js/README.md | 3 +++ packages/grpc-js/src/channel-options.ts | 3 +++ 2 files changed, 6 insertions(+) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 4799b0f4a..71ec937ed 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -56,6 +56,9 @@ Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. - `grpc.max_send_message_length` - `grpc.max_receive_message_length` - `grpc.enable_http_proxy` + - `grpc.default_compression_algorithm` + - `grpc.enable_channelz` + - `grpc-node.max_session_memory` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index e1c16d127..688317227 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -36,6 +36,9 @@ export interface ChannelOptions { 'grpc.max_send_message_length'?: number; 'grpc.max_receive_message_length'?: number; 'grpc.enable_http_proxy'?: number; + /* http_connect_target and http_connect_creds are used for passing data + * around internally, and should not be documented as public-facing options + */ 'grpc.http_connect_target'?: string; 'grpc.http_connect_creds'?: string; 'grpc.default_compression_algorithm'?: CompressionAlgorithms; From f6d8f137a2fc0f43faf25ab3f51f540522b94a97 Mon Sep 17 00:00:00 2001 From: DavyJohnes Date: Mon, 10 Jan 2022 13:54:53 +0300 Subject: [PATCH 1608/1899] fix(make-client): set provided serviceName to generated class --- packages/grpc-js/src/make-client.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/make-client.ts b/packages/grpc-js/src/make-client.ts index b8ddda29f..7d08fee20 100644 --- a/packages/grpc-js/src/make-client.ts +++ b/packages/grpc-js/src/make-client.ts @@ -91,6 +91,7 @@ export interface ServiceClientConstructor { options?: Partial ): ServiceClient; service: ServiceDefinition; + serviceName: string; } /** @@ -127,6 +128,7 @@ export function makeClientConstructor( class ServiceClientImpl extends Client implements ServiceClient { static service: ServiceDefinition; + static serviceName: string; [methodName: string]: Function; } @@ -171,6 +173,7 @@ export function makeClientConstructor( }); ServiceClientImpl.service = methods; + ServiceClientImpl.serviceName = serviceName; return ServiceClientImpl; } From d46d5c0b2972cbbc2da6d17ab3dfab26efcc7df5 Mon Sep 17 00:00:00 2001 From: Seva Orlov Date: Tue, 11 Jan 2022 14:43:45 +0200 Subject: [PATCH 1609/1899] Add envoy/extensions files --- packages/grpc-js-xds/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 2ead8f1e8..3f1ddb5e9 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -60,6 +60,7 @@ "deps/envoy-api/envoy/service/**/*.proto", "deps/envoy-api/envoy/type/**/*.proto", "deps/envoy-api/envoy/annotations/**/*.proto", + "deps/envoy-api/envoy/extensions/**/*.proto", "deps/googleapis/google/api/**/*.proto", "deps/googleapis/google/protobuf/**/*.proto", "deps/googleapis/google/rpc/**/*.proto", From 7b2cdd0291d5c269a7e3914300794b71702106a1 Mon Sep 17 00:00:00 2001 From: Seva Orlov Date: Tue, 11 Jan 2022 14:43:45 +0200 Subject: [PATCH 1610/1899] Add envoy/extensions files --- packages/grpc-js-xds/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index d3d9ad72f..6d6cc68ad 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -60,6 +60,7 @@ "deps/envoy-api/envoy/service/**/*.proto", "deps/envoy-api/envoy/type/**/*.proto", "deps/envoy-api/envoy/annotations/**/*.proto", + "deps/envoy-api/envoy/extensions/**/*.proto", "deps/googleapis/google/api/**/*.proto", "deps/googleapis/google/protobuf/**/*.proto", "deps/googleapis/google/rpc/**/*.proto", From 9e3bd11d64c7436d296b999bf7e041aebe6bf732 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 11 Jan 2022 11:10:58 -0800 Subject: [PATCH 1611/1899] grpc-js-xds: Increase version to 1.5.1 --- packages/grpc-js-xds/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 6d6cc68ad..8af0c1037 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.5.0", + "version": "1.5.1", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { From 70b7917dda5ef6e971f10fb967b4ef0391be20d7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jan 2022 10:30:27 -0800 Subject: [PATCH 1612/1899] grpc-js-xds: Add more missing files, add distrib test --- packages/grpc-js-xds/package.json | 1 + run-tests.sh | 2 ++ test/distrib/distrib-test.js | 22 +++++++++++++++++++++ test/distrib/run-distrib-test.sh | 33 +++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 test/distrib/distrib-test.js create mode 100644 test/distrib/run-distrib-test.sh diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 8af0c1037..ddc7f7bd2 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -55,6 +55,7 @@ "files": [ "src/**/*.ts", "build/src/**/*.{js,d.ts,js.map}", + "deps/envoy-api/envoy/admin/v3/**/*.proto", "deps/envoy-api/envoy/api/v2/**/*.proto", "deps/envoy-api/envoy/config/**/*.proto", "deps/envoy-api/envoy/service/**/*.proto", diff --git a/run-tests.sh b/run-tests.sh index e62cbd885..4bcb388b4 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -75,6 +75,8 @@ do # npm test calls nyc gulp test npm test || FAILED="true" + + ./test/distrib/run-distrib-test.sh || FAILED="true" done set +ex diff --git a/test/distrib/distrib-test.js b/test/distrib/distrib-test.js new file mode 100644 index 000000000..de3cbc7c7 --- /dev/null +++ b/test/distrib/distrib-test.js @@ -0,0 +1,22 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +const grpcJs = require('@grpc/grpc-js'); + +const grpcJsXds = require('@grpc/grpc-js-xds'); + +const protoLoader = require('@grpc/proto-loader'); \ No newline at end of file diff --git a/test/distrib/run-distrib-test.sh b/test/distrib/run-distrib-test.sh new file mode 100644 index 000000000..e2ed0853c --- /dev/null +++ b/test/distrib/run-distrib-test.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -ex + +cd $(dirname $0) +base=$(pwd) + +cd ../../packages/grpc-js +npm pack +cd ../grpc-js-xds +npm pack +cd ../proto-loader +npm pack + +cd $base +npm install ../../packages/grpc-js/grpc-grpc-js-*.tgz +npm install ../../packages/grpc-js-xds/grpc-grpc-js-xds-*.tgz +npm install ../../packages/proto-loader/grpc-proto-loader-*.tgz + +node ./distrib-test.js From aedfcebde5b2c5ffc64d867bd3628f2620a9a75f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jan 2022 10:30:52 -0800 Subject: [PATCH 1613/1899] grpc-js-xds: Increase version to 1.5.2 --- packages/grpc-js-xds/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index ddc7f7bd2..b4e0a49d7 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.5.1", + "version": "1.5.2", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { From 52a5e08c7525c04170f99d1b43c905c2510ec3e2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jan 2022 10:51:01 -0800 Subject: [PATCH 1614/1899] chmod a+x run-distrib-test.sh --- test/distrib/run-distrib-test.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 test/distrib/run-distrib-test.sh diff --git a/test/distrib/run-distrib-test.sh b/test/distrib/run-distrib-test.sh old mode 100644 new mode 100755 From bc28ee42fd1449113b218c6382d21acc02bf29ff Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jan 2022 13:05:45 -0800 Subject: [PATCH 1615/1899] Add newline in distrib-test.js --- test/distrib/distrib-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/distrib/distrib-test.js b/test/distrib/distrib-test.js index de3cbc7c7..708c93eb8 100644 --- a/test/distrib/distrib-test.js +++ b/test/distrib/distrib-test.js @@ -19,4 +19,4 @@ const grpcJs = require('@grpc/grpc-js'); const grpcJsXds = require('@grpc/grpc-js-xds'); -const protoLoader = require('@grpc/proto-loader'); \ No newline at end of file +const protoLoader = require('@grpc/proto-loader'); From c6691c855105e95ac176cfb799069e69613f1993 Mon Sep 17 00:00:00 2001 From: Oskar Nyberg Date: Thu, 13 Jan 2022 16:24:48 +0100 Subject: [PATCH 1616/1899] grpc-js: Don't use http_proxy for uds connections --- packages/grpc-js/src/http_proxy.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 248949a80..6faa1976d 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -136,6 +136,9 @@ export function mapProxyName( if ((options['grpc.enable_http_proxy'] ?? 1) === 0) { return noProxyResult; } + if (target.scheme === 'unix') { + return noProxyResult; + } const proxyInfo = getProxyInfo(); if (!proxyInfo.address) { return noProxyResult; From 5a728ffdc545bbd59247d927ba6e7f8f05e70934 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 Jan 2022 15:58:23 -0800 Subject: [PATCH 1617/1899] grpc-js: Add backoff to DNS resolution attempts --- packages/grpc-js/src/resolver-dns.ts | 33 ++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 9077228b8..160b3d326 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -32,6 +32,7 @@ import { SubchannelAddress, TcpSubchannelAddress } from './subchannel-address'; import { GrpcUri, uriToString, splitHostPort } from './uri-parser'; import { isIPv6, isIPv4 } from 'net'; import { ChannelOptions } from './channel-options'; +import { BackoffOptions, BackoffTimeout } from './backoff-timeout'; const TRACER_NAME = 'dns_resolver'; @@ -85,6 +86,8 @@ class DnsResolver implements Resolver { private latestServiceConfigError: StatusObject | null = null; private percentage: number; private defaultResolutionError: StatusObject; + private backoff: BackoffTimeout; + private continueResolving = false; constructor( private target: GrpcUri, private listener: ResolverListener, @@ -119,6 +122,18 @@ class DnsResolver implements Resolver { details: `Name resolution failed for target ${uriToString(this.target)}`, metadata: new Metadata(), }; + + const backoffOptions: BackoffOptions = { + initialDelay: channelOptions['grpc.initial_reconnect_backoff_ms'], + maxDelay: channelOptions['grpc.max_reconnect_backoff_ms'], + }; + + this.backoff = new BackoffTimeout(() => { + if (this.continueResolving) { + this.startResolutionWithBackoff(); + } + }, backoffOptions); + this.backoff.unref(); } /** @@ -140,6 +155,7 @@ class DnsResolver implements Resolver { return; } if (this.dnsHostname === null) { + trace('Failed to parse DNS address ' + uriToString(this.target)); setImmediate(() => { this.listener.onError({ code: Status.UNAVAILABLE, @@ -148,6 +164,7 @@ class DnsResolver implements Resolver { }); }); } else { + trace('Looking up DNS hostname ' + this.dnsHostname); /* We clear out latestLookupResult here to ensure that it contains the * latest result since the last time we started resolving. That way, the * TXT resolution handler can use it, but only if it finishes second. We @@ -164,6 +181,7 @@ class DnsResolver implements Resolver { this.pendingLookupPromise.then( (addressList) => { this.pendingLookupPromise = null; + this.backoff.reset(); const ip4Addresses: dns.LookupAddress[] = addressList.filter( (addr) => addr.family === 4 ); @@ -263,10 +281,21 @@ class DnsResolver implements Resolver { } } + private startResolutionWithBackoff() { + this.startResolution(); + this.backoff.runOnce(); + } + updateResolution() { - trace('Resolution update requested for target ' + uriToString(this.target)); + /* If there is a pending lookup, just let it finish. Otherwise, if the + * backoff timer is running, do another lookup when it ends, and if not, + * do another lookup immeidately. */ if (this.pendingLookupPromise === null) { - this.startResolution(); + if (this.backoff.isRunning()) { + this.continueResolving = true; + } else { + this.startResolutionWithBackoff(); + } } } From 80f31bb1c29692939722fd342d3b9ed6b730de7d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 Jan 2022 15:58:37 -0800 Subject: [PATCH 1618/1899] grpc-js: Increase version to 1.5.1 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 97b647a86..95f157e63 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.0", + "version": "1.5.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 500fc2c752a7259665b480b8b1457225d43c8087 Mon Sep 17 00:00:00 2001 From: Oskar Nyberg Date: Thu, 13 Jan 2022 16:24:48 +0100 Subject: [PATCH 1619/1899] grpc-js: Don't use http_proxy for uds connections --- packages/grpc-js/src/http_proxy.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js/src/http_proxy.ts b/packages/grpc-js/src/http_proxy.ts index 248949a80..6faa1976d 100644 --- a/packages/grpc-js/src/http_proxy.ts +++ b/packages/grpc-js/src/http_proxy.ts @@ -136,6 +136,9 @@ export function mapProxyName( if ((options['grpc.enable_http_proxy'] ?? 1) === 0) { return noProxyResult; } + if (target.scheme === 'unix') { + return noProxyResult; + } const proxyInfo = getProxyInfo(); if (!proxyInfo.address) { return noProxyResult; From db56e80b2135dc5dfa87aae5e47df8b67fde2f9c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 18 Jan 2022 12:35:22 -0800 Subject: [PATCH 1620/1899] grpc-js: Add secureConnection error handling in server --- packages/grpc-js/src/server.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 33057defa..9c28a276f 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -371,6 +371,13 @@ export class Server { creds._getSettings()! ); http2Server = http2.createSecureServer(secureServerOptions); + http2Server.on('secureConnection', (socket: TLSSocket) => { + /* These errors need to be handled by the user of Http2SecureServer, + * according to https://github.com/nodejs/node/issues/35824 */ + socket.on('error', (e: Error) => { + this.trace('An incoming TLS connection closed with error: ' + e.message); + }); + }); } else { http2Server = http2.createServer(serverOptions); } From b9deb5bc3c75d4d568c4777d3b8328c1f8d8683f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 18 Jan 2022 12:35:35 -0800 Subject: [PATCH 1621/1899] grpc-js: Increase version to 1.5.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 95f157e63..e84ae854f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.1", + "version": "1.5.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 4b3c26382b0c4e4cd821b589d948d9ca5abd8b72 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 11 Jan 2022 11:07:19 -0800 Subject: [PATCH 1622/1899] Add subchannel interface --- packages/grpc-js/src/channel.ts | 3 +- packages/grpc-js/src/experimental.ts | 1 + .../src/load-balancer-child-handler.ts | 4 +- .../grpc-js/src/load-balancer-pick-first.ts | 14 ++-- .../grpc-js/src/load-balancer-round-robin.ts | 10 +-- packages/grpc-js/src/load-balancer.ts | 3 +- packages/grpc-js/src/picker.ts | 5 +- packages/grpc-js/src/subchannel-interface.ts | 82 +++++++++++++++++++ packages/grpc-js/src/subchannel.ts | 11 ++- 9 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 packages/grpc-js/src/subchannel-interface.ts diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8fa2c592a..8b9275e95 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -49,6 +49,7 @@ import { Filter } from './filter'; import { ConnectivityState } from './connectivity-state'; import { ChannelInfo, ChannelRef, ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzChannel, SubchannelRef, unregisterChannelzRef } from './channelz'; +import { Subchannel } from './subchannel'; /** * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args @@ -451,7 +452,7 @@ export class ChannelImplementation implements Channel { if (subchannelState === ConnectivityState.READY) { try { const pickExtraFilters = pickResult.extraFilterFactories.map(factory => factory.createFilter(callStream)); - pickResult.subchannel!.startCallStream( + pickResult.subchannel?.getRealSubchannel().startCallStream( finalMetadata, callStream, [...dynamicFilters, ...pickExtraFilters] diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 5353f7f59..7356cb81a 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -34,3 +34,4 @@ export { Call as CallStream } from './call-stream'; export { Filter, BaseFilter, FilterFactory } from './filter'; export { FilterStackFactory } from './filter-stack'; export { registerAdminService } from './admin'; +export { SubchannelInterface, BaseSubchannelWrapper, ConnectivityStateListener } from './subchannel-interface' diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index c53914942..50708cf90 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -21,12 +21,12 @@ import { LoadBalancingConfig, createLoadBalancer, } from './load-balancer'; -import { Subchannel } from './subchannel'; import { SubchannelAddress } from './subchannel-address'; import { ChannelOptions } from './channel-options'; import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; import { ChannelRef, SubchannelRef } from './channelz'; +import { SubchannelInterface } from './subchannel-interface'; const TYPE_NAME = 'child_load_balancer_helper'; @@ -40,7 +40,7 @@ export class ChildLoadBalancerHandler implements LoadBalancer { createSubchannel( subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions - ): Subchannel { + ): SubchannelInterface { return this.parent.channelControlHelper.createSubchannel( subchannelAddress, subchannelArgs diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 6cdb7cb91..c7033f589 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -31,13 +31,13 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { Subchannel, ConnectivityStateListener } from './subchannel'; import { SubchannelAddress, subchannelAddressToString, } from './subchannel-address'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { SubchannelInterface, ConnectivityStateListener } from './subchannel-interface'; const TRACER_NAME = 'pick_first'; @@ -77,7 +77,7 @@ export class PickFirstLoadBalancingConfig implements LoadBalancingConfig { * picked subchannel. */ class PickFirstPicker implements Picker { - constructor(private subchannel: Subchannel) {} + constructor(private subchannel: SubchannelInterface) {} pick(pickArgs: PickArgs): CompletePickResult { return { @@ -107,7 +107,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { * The list of subchannels this load balancer is currently attempting to * connect to. */ - private subchannels: Subchannel[] = []; + private subchannels: SubchannelInterface[] = []; /** * The current connectivity state of the load balancer. */ @@ -124,7 +124,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { * and only if the load balancer's current state is READY. In that case, * the subchannel's current state is also READY. */ - private currentPick: Subchannel | null = null; + private currentPick: SubchannelInterface | null = null; /** * Listener callback attached to each subchannel in the `subchannels` list * while establishing a connection. @@ -157,7 +157,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannelStateListener = ( - subchannel: Subchannel, + subchannel: SubchannelInterface, previousState: ConnectivityState, newState: ConnectivityState ) => { @@ -219,7 +219,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { } }; this.pickedSubchannelStateListener = ( - subchannel: Subchannel, + subchannel: SubchannelInterface, previousState: ConnectivityState, newState: ConnectivityState ) => { @@ -310,7 +310,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { }, CONNECTION_DELAY_INTERVAL_MS); } - private pickSubchannel(subchannel: Subchannel) { + private pickSubchannel(subchannel: SubchannelInterface) { trace('Pick subchannel with address ' + subchannel.getAddress()); if (this.currentPick !== null) { this.currentPick.unref(); diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 918afab25..8a4094a02 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -30,13 +30,13 @@ import { PickResultType, UnavailablePicker, } from './picker'; -import { Subchannel, ConnectivityStateListener } from './subchannel'; import { SubchannelAddress, subchannelAddressToString, } from './subchannel-address'; import * as logging from './logging'; import { LogVerbosity } from './constants'; +import { ConnectivityStateListener, SubchannelInterface } from './subchannel-interface'; const TRACER_NAME = 'round_robin'; @@ -67,7 +67,7 @@ class RoundRobinLoadBalancingConfig implements LoadBalancingConfig { class RoundRobinPicker implements Picker { constructor( - private readonly subchannelList: Subchannel[], + private readonly subchannelList: SubchannelInterface[], private nextIndex = 0 ) {} @@ -88,7 +88,7 @@ class RoundRobinPicker implements Picker { * balancer implementation to preserve this part of the picker state if * possible when a subchannel connects or disconnects. */ - peekNextSubchannel(): Subchannel { + peekNextSubchannel(): SubchannelInterface { return this.subchannelList[this.nextIndex]; } } @@ -102,7 +102,7 @@ interface ConnectivityStateCounts { } export class RoundRobinLoadBalancer implements LoadBalancer { - private subchannels: Subchannel[] = []; + private subchannels: SubchannelInterface[] = []; private currentState: ConnectivityState = ConnectivityState.IDLE; @@ -121,7 +121,7 @@ export class RoundRobinLoadBalancer implements LoadBalancer { [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannelStateListener = ( - subchannel: Subchannel, + subchannel: SubchannelInterface, previousState: ConnectivityState, newState: ConnectivityState ) => { diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 19b79764c..48930c7db 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -21,6 +21,7 @@ import { SubchannelAddress } from './subchannel-address'; import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; import { ChannelRef, SubchannelRef } from './channelz'; +import { SubchannelInterface } from './subchannel-interface'; /** * A collection of functions associated with a channel that a load balancer @@ -35,7 +36,7 @@ export interface ChannelControlHelper { createSubchannel( subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions - ): Subchannel; + ): SubchannelInterface; /** * Passes a new subchannel picker up to the channel. This is called if either * the connectivity state changes or if a different picker is needed for any diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index 7aeed89b3..f366a6919 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -21,6 +21,7 @@ import { Metadata } from './metadata'; import { Status } from './constants'; import { LoadBalancer } from './load-balancer'; import { FilterFactory, Filter } from './filter'; +import { SubchannelInterface } from './subchannel-interface'; export enum PickResultType { COMPLETE, @@ -36,7 +37,7 @@ export interface PickResult { * `pickResultType` is COMPLETE. If null, indicates that the call should be * dropped. */ - subchannel: Subchannel | null; + subchannel: SubchannelInterface | null; /** * The status object to end the call with. Populated if and only if * `pickResultType` is TRANSIENT_FAILURE. @@ -53,7 +54,7 @@ export interface PickResult { export interface CompletePickResult extends PickResult { pickResultType: PickResultType.COMPLETE; - subchannel: Subchannel | null; + subchannel: SubchannelInterface | null; status: null; extraFilterFactories: FilterFactory[]; onCallStarted: (() => void) | null; diff --git a/packages/grpc-js/src/subchannel-interface.ts b/packages/grpc-js/src/subchannel-interface.ts new file mode 100644 index 000000000..cdf99176d --- /dev/null +++ b/packages/grpc-js/src/subchannel-interface.ts @@ -0,0 +1,82 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { SubchannelRef } from "./channelz"; +import { ConnectivityState } from "./connectivity-state"; +import { Subchannel } from "./subchannel"; + +export type ConnectivityStateListener = ( + subchannel: SubchannelInterface, + previousState: ConnectivityState, + newState: ConnectivityState +) => void; + +/** + * This is an interface for load balancing policies to use to interact with + * subchannels. This allows load balancing policies to wrap and unwrap + * subchannels. + * + * Any load balancing policy that wraps subchannels must unwrap the subchannel + * in the picker, so that other load balancing policies consistently have + * access to their own wrapper objects. + */ +export interface SubchannelInterface { + getConnectivityState(): ConnectivityState; + addConnectivityStateListener(listener: ConnectivityStateListener): void; + removeConnectivityStateListener(listener: ConnectivityStateListener): void; + startConnecting(): void; + getAddress(): string; + ref(): void; + unref(): void; + getChannelzRef(): SubchannelRef; + /** + * If this is a wrapper, return the wrapped subchannel, otherwise return this + */ + getRealSubchannel(): Subchannel; +} + +export abstract class BaseSubchannelWrapper implements SubchannelInterface { + constructor(private child: SubchannelInterface) {} + + getConnectivityState(): ConnectivityState { + return this.child.getConnectivityState(); + } + addConnectivityStateListener(listener: ConnectivityStateListener): void { + this.child.addConnectivityStateListener(listener); + } + removeConnectivityStateListener(listener: ConnectivityStateListener): void { + this.child.removeConnectivityStateListener(listener); + } + startConnecting(): void { + this.child.startConnecting(); + } + getAddress(): string { + return this.child.getAddress(); + } + ref(): void { + this.child.ref(); + } + unref(): void { + this.child.unref(); + } + getChannelzRef(): SubchannelRef { + return this.child.getChannelzRef(); + } + getRealSubchannel(): Subchannel { + return this.child.getRealSubchannel(); + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 6f9471bb9..3a1f70487 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -37,6 +37,7 @@ import { subchannelAddressToString, } from './subchannel-address'; import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, SocketInfo, SocketRef, unregisterChannelzRef, registerChannelzSocket, TlsInfo } from './channelz'; +import { ConnectivityStateListener } from './subchannel-interface'; const clientVersion = require('../../package.json').version; @@ -54,12 +55,6 @@ const BACKOFF_JITTER = 0.2; const KEEPALIVE_MAX_TIME_MS = ~(1 << 31); const KEEPALIVE_TIMEOUT_MS = 20000; -export type ConnectivityStateListener = ( - subchannel: Subchannel, - previousState: ConnectivityState, - newState: ConnectivityState -) => void; - export interface SubchannelCallStatsTracker { addMessageSent(): void; addMessageReceived(): void; @@ -949,4 +944,8 @@ export class Subchannel { getChannelzRef(): SubchannelRef { return this.channelzRef; } + + getRealSubchannel(): this { + return this; + } } From 0a5a2321b4ea1c6442627b843c80e2bb101a280f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Jan 2022 09:31:09 -0800 Subject: [PATCH 1623/1899] grpc-js: Fix pick first shutdown reference handling --- .../grpc-js/src/load-balancer-pick-first.ts | 10 ++- .../test/test-local-subchannel-pool.ts | 73 +++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 packages/grpc-js/test/test-local-subchannel-pool.ts diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 6cdb7cb91..2f638ae68 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -449,11 +449,15 @@ export class PickFirstLoadBalancer implements LoadBalancer { destroy() { this.resetSubchannelList(); if (this.currentPick !== null) { - this.currentPick.unref(); - this.currentPick.removeConnectivityStateListener( + /* Unref can cause a state change, which can cause a change in the value + * of this.currentPick, so we hold a local reference to make sure that + * does not impact this function. */ + const currentPick = this.currentPick; + currentPick.unref(); + currentPick.removeConnectivityStateListener( this.pickedSubchannelStateListener ); - this.channelControlHelper.removeChannelzChild(this.currentPick.getChannelzRef()); + this.channelControlHelper.removeChannelzChild(currentPick.getChannelzRef()); } } diff --git a/packages/grpc-js/test/test-local-subchannel-pool.ts b/packages/grpc-js/test/test-local-subchannel-pool.ts new file mode 100644 index 000000000..081b2d3dc --- /dev/null +++ b/packages/grpc-js/test/test-local-subchannel-pool.ts @@ -0,0 +1,73 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import * as path from 'path'; +import * as grpc from '../src'; +import { sendUnaryData, Server, ServerCredentials, ServerUnaryCall, ServiceClientConstructor, ServiceError } from "../src"; +import { loadProtoFile } from './common'; + +const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); +const echoService = loadProtoFile(protoFile) + .EchoService as ServiceClientConstructor; + +describe('Local subchannel pool', () => { + let server: Server; + let serverPort: number; + + before(done => { + + server = new Server(); + server.addService(echoService.service, { + echo(call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, call.request); + }, + }); + + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + serverPort = port; + server.start(); + done(); + } + ); + }); + + after(done => { + server.tryShutdown(done); + }); + + it('should complete the client lifecycle without error', done => { + const client = new echoService( + `localhost:${serverPort}`, + grpc.credentials.createInsecure(), + {'grpc.use_local_subchannel_pool': 1} + ); + client.echo( + { value: 'test value', value2: 3 }, + (error: ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + client.close(); + done(); + } + ); + }); +}); \ No newline at end of file From 27bae2009dc22e0fb39fbd61a57201c80f2e705b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Jan 2022 09:36:44 -0800 Subject: [PATCH 1624/1899] grpc-js: Increase version to 1.5.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e84ae854f..3b62aa5ed 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.2", + "version": "1.5.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From ba70f7168b41c8533bdaed0bde2cbf573cbdcf1e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Jan 2022 13:54:40 -0800 Subject: [PATCH 1625/1899] grpc-js: Fix exitIdle propagation and DNS IP result backoff --- packages/grpc-js/src/load-balancer-child-handler.ts | 4 ++-- packages/grpc-js/src/resolver-dns.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index c53914942..3379ec8a7 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -125,9 +125,9 @@ export class ChildLoadBalancerHandler implements LoadBalancer { } exitIdle(): void { if (this.currentChild) { - this.currentChild.resetBackoff(); + this.currentChild.exitIdle(); if (this.pendingChild) { - this.pendingChild.resetBackoff(); + this.pendingChild.exitIdle(); } } } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 160b3d326..8ad24ed05 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -144,6 +144,7 @@ class DnsResolver implements Resolver { if (this.ipResult !== null) { trace('Returning IP address for target ' + uriToString(this.target)); setImmediate(() => { + this.backoff.reset(); this.listener.onSuccessfulResolution( this.ipResult!, null, From f49ed624766d1c40d1b9f215781bf84231688563 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 31 Jan 2022 13:55:07 -0800 Subject: [PATCH 1626/1899] grpc-js: Increase version to 1.5.4 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3b62aa5ed..8c65b9365 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.3", + "version": "1.5.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 2334ca9dfa24915e50304c7c8a472d8e9f34c1ea Mon Sep 17 00:00:00 2001 From: Yuri Golobokov Date: Mon, 7 Feb 2022 16:47:56 -0800 Subject: [PATCH 1627/1899] Add isTracerEnabled to logging --- packages/grpc-js/src/logging.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/logging.ts b/packages/grpc-js/src/logging.ts index 549cd860e..ec845c1a5 100644 --- a/packages/grpc-js/src/logging.ts +++ b/packages/grpc-js/src/logging.ts @@ -108,10 +108,12 @@ export function trace( tracer: string, text: string ): void { - if ( - !disabledTracers.has(tracer) && - (allEnabled || enabledTracers.has(tracer)) - ) { + if (isTracerEnabled(tracer)) { log(severity, new Date().toISOString() + ' | ' + tracer + ' | ' + text); } } + +export function isTracerEnabled(tracer: string): boolean { + return !disabledTracers.has(tracer) && + (allEnabled || enabledTracers.has(tracer)); +} From ae2a2ac7d0880433b6b8fc584885a14e2ec4fd97 Mon Sep 17 00:00:00 2001 From: Yuri Golobokov Date: Mon, 7 Feb 2022 17:21:14 -0800 Subject: [PATCH 1628/1899] Add HTTP/2 settings frame tracing. This adds HTTP/2 settings frame information to debug logs. HTTP/2 settings frame contains important information like max_concurrent_streams and initial_window_size useful for debugging concurrency, latency, and throughput issues. --- packages/grpc-js/src/subchannel.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 6f9471bb9..9945b9881 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -555,6 +555,24 @@ export class Subchannel { (error as Error).message ); }); + if (logging.isTracerEnabled(TRACER_NAME)) { + session.on('remoteSettings', (settings: http2.Settings) => { + this.trace( + 'new settings received' + + (this.session !== session ? ' on the old connection' : '') + + ': ' + + JSON.stringify(settings) + ); + }); + session.on('localSettings', (settings: http2.Settings) => { + this.trace( + 'local settings acknowledged by remote' + + (this.session !== session ? ' on the old connection' : '') + + ': ' + + JSON.stringify(settings) + ); + }); + } } private startConnectingInternal() { From da66707d3bb9f5cf253b732888294a589c4dbc88 Mon Sep 17 00:00:00 2001 From: Yuri Golobokov Date: Tue, 8 Feb 2022 15:53:34 -0800 Subject: [PATCH 1629/1899] HTTP/2 flow control tracing subchannel_flowctrl tracer, if enabled, logs local and remote window sizes of subchannel's HTTP2 session to debug log on the start of every call. --- doc/environment_variables.md | 1 + packages/grpc-js/src/subchannel.ts | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/doc/environment_variables.md b/doc/environment_variables.md index f2a32294c..f4310e625 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -37,6 +37,7 @@ can be set. - `server_call` - Traces server handling of individual requests - `subchannel` - Traces subchannel connectivity state and errors - `subchannel_refcount` - Traces subchannel refcount changes + - `subchannel_flowctrl` - Traces HTTP/2 flow control The following tracers are added by the `@grpc/grpc-js-xds` library: - `cds_balancer` - Traces the CDS load balancing policy diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 9945b9881..faa68c145 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -41,6 +41,7 @@ import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, const clientVersion = require('../../package.json').version; const TRACER_NAME = 'subchannel'; +const FLOW_CONTROL_TRACER_NAME = 'subchannel_flowctrl'; const MIN_CONNECT_TIMEOUT_MS = 20000; const INITIAL_BACKOFF_MS = 1000; @@ -324,6 +325,10 @@ export class Subchannel { logging.trace(LogVerbosity.DEBUG, 'subchannel_refcount', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); } + private flowControlTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, FLOW_CONTROL_TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + private handleBackoffTimer() { if (this.continueConnecting) { this.transitionToState( @@ -848,6 +853,12 @@ export class Subchannel { ' with headers\n' + headersString ); + this.flowControlTrace( + 'local window size: ' + + this.session!.state.localWindowSize + + ' remote window size: ' + + this.session!.state.remoteWindowSize + ); const streamSession = this.session; let statsTracker: SubchannelCallStatsTracker; if (this.channelzEnabled) { From 5bb11e02a0eded5696eaec06f9bbdab6c9234f72 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Feb 2022 10:12:36 -0800 Subject: [PATCH 1630/1899] grpc-js: Increase version to 1.5.5 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8c65b9365..faad0991d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.4", + "version": "1.5.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From d51dfffcfeab1ac448b0ac51eebd3560623ccc7d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 23 Feb 2022 09:50:11 -0800 Subject: [PATCH 1631/1899] grpc-js: Add session state logging at call start --- doc/environment_variables.md | 5 +++-- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 11 +++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/doc/environment_variables.md b/doc/environment_variables.md index f4310e625..2eb429f92 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -36,8 +36,9 @@ can be set. - `server` - Traces high-level server events - `server_call` - Traces server handling of individual requests - `subchannel` - Traces subchannel connectivity state and errors - - `subchannel_refcount` - Traces subchannel refcount changes - - `subchannel_flowctrl` - Traces HTTP/2 flow control + - `subchannel_refcount` - Traces subchannel refcount changes. Includes per-call logs. + - `subchannel_flowctrl` - Traces HTTP/2 flow control. Includes per-call logs. + - `subchannel_internals` - Traces HTTP/2 session state. Includes per-call logs. The following tracers are added by the `@grpc/grpc-js-xds` library: - `cds_balancer` - Traces the CDS load balancing policy diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index faad0991d..d7708194e 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.5", + "version": "1.5.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index faa68c145..524e36316 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -329,6 +329,10 @@ export class Subchannel { logging.trace(LogVerbosity.DEBUG, FLOW_CONTROL_TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); } + private internalsTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'subchannel_internals', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + private handleBackoffTimer() { if (this.continueConnecting) { this.transitionToState( @@ -860,6 +864,13 @@ export class Subchannel { this.session!.state.remoteWindowSize ); const streamSession = this.session; + this.internalsTrace( + 'session.closed=' + + streamSession!.closed + + ' session.destroyed=' + + streamSession!.destroyed + + ' session.socket.destroyed=' + + streamSession!.socket.destroyed); let statsTracker: SubchannelCallStatsTracker; if (this.channelzEnabled) { this.callTracker.addCallStarted(); From 55087d21c4d4752731c7812d6649eb75dccb275b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 24 Feb 2022 09:09:54 -0800 Subject: [PATCH 1632/1899] grpc-js: Transition subchannel to TRANSIENT_FAILURE when the socket closes --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 12 +++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d7708194e..f41de376d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.6", + "version": "1.5.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 524e36316..24f02144d 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -669,9 +669,15 @@ export class Subchannel { switch (newState) { case ConnectivityState.READY: this.stopBackoff(); - this.session!.socket.once('close', () => { - for (const listener of this.disconnectListeners) { - listener(); + const session = this.session!; + session.socket.once('close', () => { + if (this.session === session) { + this.transitionToState( + [ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE); + for (const listener of this.disconnectListeners) { + listener(); + } } }); if (this.keepaliveWithoutCalls) { From a3ecb4513232557dc9132b81aea9d67ef9544c15 Mon Sep 17 00:00:00 2001 From: Dacio Romero Date: Tue, 1 Mar 2022 14:48:25 -0800 Subject: [PATCH 1633/1899] grpc-js: Return never from functions that always throw --- packages/grpc-js/src/channel-credentials.ts | 2 +- packages/grpc-js/src/index.ts | 4 ++-- packages/grpc-js/src/resolving-load-balancer.ts | 2 +- packages/grpc-js/src/server.ts | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index 94b66c1bd..fd9d7b571 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -173,7 +173,7 @@ class InsecureChannelCredentialsImpl extends ChannelCredentials { super(callCredentials); } - compose(callCredentials: CallCredentials): ChannelCredentials { + compose(callCredentials: CallCredentials): never { throw new Error('Cannot compose insecure credentials'); } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 4bf1d9363..fa782aaa4 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -207,13 +207,13 @@ export type Call = /* eslint-disable @typescript-eslint/no-explicit-any */ -export const loadObject = (value: any, options: any) => { +export const loadObject = (value: any, options: any): never => { throw new Error( 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead' ); }; -export const load = (filename: any, format: any, options: any) => { +export const load = (filename: any, format: any, options: any): never => { throw new Error( 'Not available in this library. Use @grpc/proto-loader and loadPackageDefinition instead' ); diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 5bc861283..907067dfc 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -312,7 +312,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { updateAddressList( addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig | null - ) { + ): never { throw new Error('updateAddressList not supported on ResolvingLoadBalancer'); } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 33057defa..e0074807e 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -231,7 +231,7 @@ export class Server { } - addProtoService(): void { + addProtoService(): never { throw new Error('Not implemented. Use addService() instead'); } @@ -311,7 +311,7 @@ export class Server { }); } - bind(port: string, creds: ServerCredentials): void { + bind(port: string, creds: ServerCredentials): never { throw new Error('Not implemented. Use bindAsync() instead'); } @@ -696,7 +696,7 @@ export class Server { } } - addHttp2Port(): void { + addHttp2Port(): never { throw new Error('Not yet implemented'); } From 2062062a5cb6741818d31fa3d9c516741389d236 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 19 Jan 2022 10:17:51 -0800 Subject: [PATCH 1634/1899] grpc-js: Add outlier detection LB policy --- packages/grpc-js/gulpfile.ts | 1 + packages/grpc-js/src/duration.ts | 36 ++ packages/grpc-js/src/experimental.ts | 3 +- packages/grpc-js/src/index.ts | 2 + .../src/load-balancer-outlier-detection.ts | 569 ++++++++++++++++++ packages/grpc-js/src/service-config.ts | 6 +- packages/grpc-js/src/subchannel-interface.ts | 2 +- .../grpc-js/test/test-outlier-detection.ts | 121 ++++ 8 files changed, 733 insertions(+), 7 deletions(-) create mode 100644 packages/grpc-js/src/duration.ts create mode 100644 packages/grpc-js/src/load-balancer-outlier-detection.ts create mode 100644 packages/grpc-js/test/test-outlier-detection.ts diff --git a/packages/grpc-js/gulpfile.ts b/packages/grpc-js/gulpfile.ts index 6d8d20943..d85900364 100644 --- a/packages/grpc-js/gulpfile.ts +++ b/packages/grpc-js/gulpfile.ts @@ -67,6 +67,7 @@ const compile = checkTask(() => execNpmCommand('compile')); const copyTestFixtures = checkTask(() => ncpP(`${jsCoreDir}/test/fixtures`, `${outDir}/test/fixtures`)); const runTests = checkTask(() => { + process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION = 'true'; return gulp.src(`${outDir}/test/**/*.js`) .pipe(mocha({reporter: 'mocha-jenkins-reporter', require: ['ts-node/register']})); diff --git a/packages/grpc-js/src/duration.ts b/packages/grpc-js/src/duration.ts new file mode 100644 index 000000000..278c9ae54 --- /dev/null +++ b/packages/grpc-js/src/duration.ts @@ -0,0 +1,36 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export interface Duration { + seconds: number; + nanos: number; +} + +export function msToDuration(millis: number): Duration { + return { + seconds: (millis / 1000) | 0, + nanos: (millis % 1000) * 1_000_000 | 0 + }; +} + +export function durationToMs(duration: Duration): number { + return (duration.seconds * 1000 + duration.nanos / 1_000_000) | 0; +} + +export function isDuration(value: any): value is Duration { + return (typeof value.seconds === 'number') && (typeof value.nanos === 'number'); +} \ No newline at end of file diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 7356cb81a..a9d76406b 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -6,7 +6,8 @@ export { ConfigSelector, } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; -export { ServiceConfig, Duration } from './service-config'; +export { Duration } from './duration'; +export { ServiceConfig } from './service-config'; export { BackoffTimeout } from './backoff-timeout'; export { LoadBalancer, diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 4bf1d9363..b7771be29 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -273,6 +273,7 @@ import * as resolver_uds from './resolver-uds'; import * as resolver_ip from './resolver-ip'; import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; +import * as load_balancer_outlier_detection from './load-balancer-outlier-detection'; import * as channelz from './channelz'; const clientVersion = require('../../package.json').version; @@ -284,5 +285,6 @@ const clientVersion = require('../../package.json').version; resolver_ip.setup(); load_balancer_pick_first.setup(); load_balancer_round_robin.setup(); + load_balancer_outlier_detection.setup(); channelz.setup(); })(); diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts new file mode 100644 index 000000000..ffca1c68e --- /dev/null +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -0,0 +1,569 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ChannelOptions, connectivityState, StatusObject } from "."; +import { Call } from "./call-stream"; +import { ConnectivityState } from "./connectivity-state"; +import { Status } from "./constants"; +import { durationToMs, isDuration, msToDuration } from "./duration"; +import { ChannelControlHelper, createChildChannelControlHelper, registerLoadBalancerType } from "./experimental"; +import { BaseFilter, Filter, FilterFactory } from "./filter"; +import { getFirstUsableConfig, LoadBalancer, LoadBalancingConfig, validateLoadBalancingConfig } from "./load-balancer"; +import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; +import { PickArgs, Picker, PickResult, PickResultType, QueuePicker, UnavailablePicker } from "./picker"; +import { Subchannel } from "./subchannel"; +import { SubchannelAddress, subchannelAddressToString } from "./subchannel-address"; +import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from "./subchannel-interface"; + + +const TYPE_NAME = 'outlier_detection'; + +const OUTLIER_DETECTION_ENABLED = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION === 'true'; + +interface SuccessRateEjectionConfig { + readonly stdev_factor: number; + readonly enforcement_percentage: number; + readonly minimum_hosts: number; + readonly request_volume: number; +} + +interface FailurePercentageEjectionConfig { + readonly threshold: number; + readonly enforcement_percentage: number; + readonly minimum_hosts: number; + readonly request_volume: number; +} + +const defaultSuccessRateEjectionConfig: SuccessRateEjectionConfig = { + stdev_factor: 1900, + enforcement_percentage: 100, + minimum_hosts: 5, + request_volume: 100 +}; + +const defaultFailurePercentageEjectionConfig: FailurePercentageEjectionConfig = { + threshold: 85, + enforcement_percentage: 100, + minimum_hosts: 5, + request_volume: 50 +} + +type TypeofValues = 'object' | 'boolean' | 'function' | 'number' | 'string' | 'undefined'; + +function validateFieldType(obj: any, fieldName: string, expectedType: TypeofValues, objectName?: string) { + if (fieldName in obj && typeof obj[fieldName] !== expectedType) { + const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName; + throw new Error(`outlier detection config ${fullFieldName} parse error: expected ${expectedType}, got ${typeof obj[fieldName]}`); + } +} + +function validatePositiveDuration(obj: any, fieldName: string, objectName?: string) { + const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName; + if (fieldName in obj) { + if (!isDuration(obj[fieldName])) { + throw new Error(`outlier detection config ${fullFieldName} parse error: expected Duration, got ${typeof obj[fieldName]}`); + } + if (!(obj[fieldName].seconds >= 0 && obj[fieldName].seconds <= 315_576_000_000 && obj[fieldName].nanos >= 0 && obj[fieldName].nanos <= 999_999_999)) { + throw new Error(`outlier detection config ${fullFieldName} parse error: values out of range for non-negative Duaration`); + } + } +} + +function validatePercentage(obj: any, fieldName: string, objectName?: string) { + const fullFieldName = objectName ? `${objectName}.${fieldName}` : fieldName; + validateFieldType(obj, fieldName, 'number', objectName); + if (fieldName in obj && !(obj[fieldName] >= 0 && obj[fieldName] <= 100)) { + throw new Error(`outlier detection config ${fullFieldName} parse error: value out of range for percentage (0-100)`); + } +} + +export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig { + constructor( + private readonly intervalMs: number, + private readonly baseEjectionTimeMs: number, + private readonly maxEjectionTimeMs: number, + private readonly maxEjectionPercent: number, + private readonly successRateEjection: SuccessRateEjectionConfig | null, + private readonly failurePercentageEjection: FailurePercentageEjectionConfig | null, + private readonly childPolicy: LoadBalancingConfig[] + ) {} + getLoadBalancerName(): string { + return TYPE_NAME; + } + toJsonObject(): object { + return { + interval: msToDuration(this.intervalMs), + base_ejection_time: msToDuration(this.baseEjectionTimeMs), + max_ejection_time: msToDuration(this.maxEjectionTimeMs), + max_ejection_percent: this.maxEjectionPercent, + success_rate_ejection: this.successRateEjection, + failure_percentage_ejection: this.failurePercentageEjection, + child_policy: this.childPolicy.map(policy => policy.toJsonObject()) + }; + } + + getIntervalMs(): number { + return this.intervalMs; + } + getBaseEjectionTimeMs(): number { + return this.baseEjectionTimeMs; + } + getMaxEjectionTimeMs(): number { + return this.maxEjectionTimeMs; + } + getMaxEjectionPercent(): number { + return this.maxEjectionPercent; + } + getSuccessRateEjectionConfig(): SuccessRateEjectionConfig | null { + return this.successRateEjection; + } + getFailurePercentageEjectionConfig(): FailurePercentageEjectionConfig | null { + return this.failurePercentageEjection; + } + getChildPolicy(): LoadBalancingConfig[] { + return this.childPolicy; + } + static createFromJson(obj: any): OutlierDetectionLoadBalancingConfig { + validatePositiveDuration(obj, 'interval'); + validatePositiveDuration(obj, 'base_ejection_time'); + validatePositiveDuration(obj, 'max_ejection_time'); + validatePercentage(obj, 'max_ejection_percent'); + if ('success_rate_ejection' in obj) { + if (typeof obj.success_rate_ejection !== 'object') { + throw new Error('outlier detection config success_rate_ejection must be an object'); + } + validateFieldType(obj.success_rate_ejection, 'stdev_factor', 'number', 'success_rate_ejection'); + validatePercentage(obj.success_rate_ejection, 'enforcement_percentage', 'success_rate_ejection'); + validateFieldType(obj.success_rate_ejection, 'minimum_hosts', 'number', 'success_rate_ejection'); + validateFieldType(obj.success_rate_ejection, 'request_volume', 'number', 'success_rate_ejection'); + } + if ('failure_percentage_ejection' in obj) { + if (typeof obj.failure_percentage_ejection !== 'object') { + throw new Error('outlier detection config failure_percentage_ejection must be an object'); + } + validatePercentage(obj.failure_percentage_ejection, 'threshold', 'failure_percentage_ejection'); + validatePercentage(obj.failure_percentage_ejection, 'enforcement_percentage', 'failure_percentage_ejection'); + validateFieldType(obj.failure_percentage_ejection, 'minimum_hosts', 'number', 'failure_percentage_ejection'); + validateFieldType(obj.failure_percentage_ejection, 'request_volume', 'number', 'failure_percentage_ejection'); + } + + return new OutlierDetectionLoadBalancingConfig( + obj.interval ? durationToMs(obj.interval) : 10_000, + obj.base_ejection_time ? durationToMs(obj.base_ejection_time) : 30_000, + obj.max_ejection_time ? durationToMs(obj.max_ejection_time) : 300_000, + obj.max_ejection_percent ?? 10, + obj.success_rate_ejection ? {...defaultSuccessRateEjectionConfig, ...obj.success_rate_ejection} : null, + obj.failure_percentage_ejection ? {...defaultFailurePercentageEjectionConfig, ...obj.failure_percentage_ejection} : null, + obj.child_policy.map(validateLoadBalancingConfig) + ); + } +} + +class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements SubchannelInterface { + private childSubchannelState: ConnectivityState = ConnectivityState.IDLE; + private stateListeners: ConnectivityStateListener[] = []; + private ejected: boolean = false; + private refCount: number = 0; + constructor(childSubchannel: SubchannelInterface, private mapEntry?: MapEntry) { + super(childSubchannel); + childSubchannel.addConnectivityStateListener((subchannel, previousState, newState) => { + this.childSubchannelState = newState; + if (!this.ejected) { + for (const listener of this.stateListeners) { + listener(this, previousState, newState); + } + } + }); + } + + /** + * Add a listener function to be called whenever the wrapper's + * connectivity state changes. + * @param listener + */ + addConnectivityStateListener(listener: ConnectivityStateListener) { + this.stateListeners.push(listener); + } + + /** + * Remove a listener previously added with `addConnectivityStateListener` + * @param listener A reference to a function previously passed to + * `addConnectivityStateListener` + */ + removeConnectivityStateListener(listener: ConnectivityStateListener) { + const listenerIndex = this.stateListeners.indexOf(listener); + if (listenerIndex > -1) { + this.stateListeners.splice(listenerIndex, 1); + } + } + + ref() { + this.child.ref(); + this.refCount += 1; + } + + unref() { + this.child.unref(); + this.refCount -= 1; + if (this.refCount <= 0) { + if (this.mapEntry) { + const index = this.mapEntry.subchannelWrappers.indexOf(this); + if (index >= 0) { + this.mapEntry.subchannelWrappers.splice(index, 1); + } + } + } + } + + eject() { + this.ejected = true; + for (const listener of this.stateListeners) { + listener(this, this.childSubchannelState, ConnectivityState.TRANSIENT_FAILURE); + } + } + + uneject() { + this.ejected = false; + for (const listener of this.stateListeners) { + listener(this, ConnectivityState.TRANSIENT_FAILURE, this.childSubchannelState); + } + } + + getMapEntry(): MapEntry | undefined { + return this.mapEntry; + } + + getWrappedSubchannel(): SubchannelInterface { + return this.child; + } +} + +interface CallCountBucket { + success: number; + failure: number; +} + +function createEmptyBucket(): CallCountBucket { + return { + success: 0, + failure: 0 + } +} + +class CallCounter { + private activeBucket: CallCountBucket = createEmptyBucket(); + private inactiveBucket: CallCountBucket = createEmptyBucket(); + addSuccess() { + this.activeBucket.success += 1; + } + addFailure() { + this.activeBucket.failure += 1; + } + switchBuckets() { + this.inactiveBucket = this.activeBucket; + this.activeBucket = createEmptyBucket(); + } + getLastSuccesses() { + return this.inactiveBucket.success; + } + getLastFailures() { + return this.inactiveBucket.failure; + } +} + +interface MapEntry { + counter: CallCounter; + currentEjectionTimestamp: Date | null; + ejectionTimeMultiplier: number; + subchannelWrappers: OutlierDetectionSubchannelWrapper[]; +} + +class OutlierDetectionCounterFilter extends BaseFilter implements Filter { + constructor(private callCounter: CallCounter) { + super(); + } + receiveTrailers(status: StatusObject): StatusObject { + if (status.code === Status.OK) { + this.callCounter.addSuccess(); + } else { + this.callCounter.addFailure(); + } + return status; + } +} + +class OutlierDetectionCounterFilterFactory implements FilterFactory { + constructor(private callCounter: CallCounter) {} + createFilter(callStream: Call): OutlierDetectionCounterFilter { + return new OutlierDetectionCounterFilter(this.callCounter); + } + +} + +class OutlierDetectionPicker implements Picker { + constructor(private wrappedPicker: Picker) {} + pick(pickArgs: PickArgs): PickResult { + const wrappedPick = this.wrappedPicker.pick(pickArgs); + if (wrappedPick.pickResultType === PickResultType.COMPLETE) { + const subchannelWrapper = wrappedPick.subchannel as OutlierDetectionSubchannelWrapper; + const mapEntry = subchannelWrapper.getMapEntry(); + if (mapEntry) { + return { + ...wrappedPick, + subchannel: subchannelWrapper.getWrappedSubchannel(), + extraFilterFactories: [...wrappedPick.extraFilterFactories, new OutlierDetectionCounterFilterFactory(mapEntry.counter)] + }; + } else { + return wrappedPick; + } + } else { + return wrappedPick; + } + } + +} + +export class OutlierDetectionLoadBalancer implements LoadBalancer { + private childBalancer: ChildLoadBalancerHandler; + private addressMap: Map = new Map(); + private latestConfig: OutlierDetectionLoadBalancingConfig | null = null; + private ejectionTimer: NodeJS.Timer; + + constructor(channelControlHelper: ChannelControlHelper) { + this.childBalancer = new ChildLoadBalancerHandler(createChildChannelControlHelper(channelControlHelper, { + createSubchannel: (subchannelAddress: SubchannelAddress, subchannelArgs: ChannelOptions) => { + const originalSubchannel = channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); + const mapEntry = this.addressMap.get(subchannelAddressToString(subchannelAddress)); + const subchannelWrapper = new OutlierDetectionSubchannelWrapper(originalSubchannel, mapEntry); + mapEntry?.subchannelWrappers.push(subchannelWrapper); + return subchannelWrapper; + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + if (connectivityState === ConnectivityState.READY) { + channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker)); + } else { + channelControlHelper.updateState(connectivityState, picker); + } + } + })); + this.ejectionTimer = setInterval(() => {}, 0); + clearInterval(this.ejectionTimer); + } + + private getCurrentEjectionPercent() { + let ejectionCount = 0; + for (const mapEntry of this.addressMap.values()) { + if (mapEntry.currentEjectionTimestamp !== null) { + ejectionCount += 1; + } + } + return (ejectionCount * 100) / this.addressMap.size; + } + + private runSuccessRateCheck(ejectionTimestamp: Date) { + if (!this.latestConfig) { + return; + } + const successRateConfig = this.latestConfig.getSuccessRateEjectionConfig(); + if (!successRateConfig) { + return; + } + // Step 1 + const targetRequestVolume = successRateConfig.request_volume; + let addresesWithTargetVolume = 0; + const successRates: number[] = [] + for (const mapEntry of this.addressMap.values()) { + const successes = mapEntry.counter.getLastSuccesses(); + const failures = mapEntry.counter.getLastFailures(); + if (successes + failures >= targetRequestVolume) { + addresesWithTargetVolume += 1; + successRates.push(successes/(successes + failures)); + } + } + if (addresesWithTargetVolume < successRateConfig.minimum_hosts) { + return; + } + + // Step 2 + const successRateMean = successRates.reduce((a, b) => a + b); + let successRateVariance = 0; + for (const rate of successRates) { + const deviation = rate - successRateMean; + successRateVariance += deviation * deviation; + } + const successRateStdev = Math.sqrt(successRateVariance); + const ejectionThreshold = successRateMean - successRateStdev * (successRateConfig.stdev_factor / 1000); + + // Step 3 + for (const mapEntry of this.addressMap.values()) { + // Step 3.i + if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { + break; + } + // Step 3.ii + const successes = mapEntry.counter.getLastSuccesses(); + const failures = mapEntry.counter.getLastFailures(); + if (successes + failures < targetRequestVolume) { + continue; + } + // Step 3.iii + const successRate = successes / (successes + failures); + if (successRate < ejectionThreshold) { + const randomNumber = Math.random() * 100; + if (randomNumber < successRateConfig.enforcement_percentage) { + this.eject(mapEntry, ejectionTimestamp); + } + } + } + } + + private runFailurePercentageCheck(ejectionTimestamp: Date) { + if (!this.latestConfig) { + return; + } + const failurePercentageConfig = this.latestConfig.getFailurePercentageEjectionConfig() + if (!failurePercentageConfig) { + return; + } + // Step 1 + if (this.addressMap.size < failurePercentageConfig.minimum_hosts) { + return; + } + + // Step 2 + for (const mapEntry of this.addressMap.values()) { + // Step 2.i + if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { + break; + } + // Step 2.ii + const successes = mapEntry.counter.getLastSuccesses(); + const failures = mapEntry.counter.getLastFailures(); + if (successes + failures < failurePercentageConfig.request_volume) { + continue; + } + // Step 2.iii + const failurePercentage = (failures * 100) / (failures + successes); + if (failurePercentage > failurePercentageConfig.threshold) { + const randomNumber = Math.random() * 100; + if (randomNumber < failurePercentageConfig.enforcement_percentage) { + this.eject(mapEntry, ejectionTimestamp); + } + } + } + } + + private eject(mapEntry: MapEntry, ejectionTimestamp: Date) { + mapEntry.currentEjectionTimestamp = new Date(); + mapEntry.ejectionTimeMultiplier += 1; + for (const subchannelWrapper of mapEntry.subchannelWrappers) { + subchannelWrapper.eject(); + } + } + + private uneject(mapEntry: MapEntry) { + mapEntry.currentEjectionTimestamp = null; + for (const subchannelWrapper of mapEntry.subchannelWrappers) { + subchannelWrapper.uneject(); + } + } + + private runChecks() { + const ejectionTimestamp = new Date(); + + for (const mapEntry of this.addressMap.values()) { + mapEntry.counter.switchBuckets(); + } + + if (!this.latestConfig) { + return; + } + + this.runSuccessRateCheck(ejectionTimestamp); + this.runFailurePercentageCheck(ejectionTimestamp); + + for (const mapEntry of this.addressMap.values()) { + if (mapEntry.currentEjectionTimestamp === null) { + if (mapEntry.ejectionTimeMultiplier > 0) { + mapEntry.ejectionTimeMultiplier -= 1; + } + } else { + const baseEjectionTimeMs = this.latestConfig.getBaseEjectionTimeMs(); + const maxEjectionTimeMs = this.latestConfig.getMaxEjectionTimeMs(); + const returnTime = new Date(mapEntry.currentEjectionTimestamp.getTime()); + returnTime.setMilliseconds(returnTime.getMilliseconds() + Math.min(baseEjectionTimeMs * mapEntry.ejectionTimeMultiplier, Math.max(baseEjectionTimeMs, maxEjectionTimeMs))); + if (returnTime < new Date()) { + this.uneject(mapEntry); + } + } + } + } + + updateAddressList(addressList: SubchannelAddress[], lbConfig: LoadBalancingConfig, attributes: { [key: string]: unknown; }): void { + if (!(lbConfig instanceof OutlierDetectionLoadBalancingConfig)) { + return; + } + const subchannelAddresses = new Set(); + for (const address of addressList) { + subchannelAddresses.add(subchannelAddressToString(address)); + } + for (const address of subchannelAddresses) { + if (!this.addressMap.has(address)) { + this.addressMap.set(address, { + counter: new CallCounter(), + currentEjectionTimestamp: null, + ejectionTimeMultiplier: 0, + subchannelWrappers: [] + }); + } + } + for (const key of this.addressMap.keys()) { + if (!subchannelAddresses.has(key)) { + this.addressMap.delete(key); + } + } + const childPolicy: LoadBalancingConfig = getFirstUsableConfig( + lbConfig.getChildPolicy(), + true + ); + this.childBalancer.updateAddressList(addressList, childPolicy, attributes); + + if (this.latestConfig === null || this.latestConfig.getIntervalMs() !== lbConfig.getIntervalMs()) { + clearInterval(this.ejectionTimer); + this.ejectionTimer = setInterval(() => this.runChecks(), lbConfig.getIntervalMs()); + } + this.latestConfig = lbConfig; + } + exitIdle(): void { + this.childBalancer.exitIdle(); + } + resetBackoff(): void { + this.childBalancer.resetBackoff(); + } + destroy(): void { + this.childBalancer.destroy(); + } + getTypeName(): string { + return TYPE_NAME; + } +} + +export function setup() { + if (OUTLIER_DETECTION_ENABLED) { + registerLoadBalancerType(TYPE_NAME, OutlierDetectionLoadBalancer, OutlierDetectionLoadBalancingConfig); + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index 3f0a00868..f310597e9 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -27,6 +27,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as os from 'os'; +import { Duration } from './duration'; import { LoadBalancingConfig, validateLoadBalancingConfig, @@ -37,11 +38,6 @@ export interface MethodConfigName { method?: string; } -export interface Duration { - seconds: number; - nanos: number; -} - export interface MethodConfig { name: MethodConfigName[]; waitForReady?: boolean; diff --git a/packages/grpc-js/src/subchannel-interface.ts b/packages/grpc-js/src/subchannel-interface.ts index cdf99176d..082a8b3c0 100644 --- a/packages/grpc-js/src/subchannel-interface.ts +++ b/packages/grpc-js/src/subchannel-interface.ts @@ -50,7 +50,7 @@ export interface SubchannelInterface { } export abstract class BaseSubchannelWrapper implements SubchannelInterface { - constructor(private child: SubchannelInterface) {} + constructor(protected child: SubchannelInterface) {} getConnectivityState(): ConnectivityState { return this.child.getConnectivityState(); diff --git a/packages/grpc-js/test/test-outlier-detection.ts b/packages/grpc-js/test/test-outlier-detection.ts new file mode 100644 index 000000000..977a3058f --- /dev/null +++ b/packages/grpc-js/test/test-outlier-detection.ts @@ -0,0 +1,121 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import * as path from 'path'; +import * as grpc from '../src'; +import { loadProtoFile } from './common'; + +function multiDone(done: Mocha.Done, target: number) { + let count = 0; + return (error?: any) => { + if (error) { + done(error); + } + count++; + if (count >= target) { + done(); + } + } +} + +const defaultOutlierDetectionServiceConfig = { + methodConfig: [], + loadBalancingConfig: [ + { + outlier_detection: { + success_rate_ejection: {}, + failure_percentage_ejection: {}, + child_policy: [{round_robin: {}}] + } + } + ] +}; + +const defaultOutlierDetectionServiceConfigString = JSON.stringify(defaultOutlierDetectionServiceConfig); + +const goodService = { + echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + callback(null, call.request) + } +}; + +const badService = { + echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + callback({ + code: grpc.status.PERMISSION_DENIED, + details: 'Permission denied' + }) + } +} + +const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); +const EchoService = loadProtoFile(protoFile) + .EchoService as grpc.ServiceClientConstructor; + +describe('Outlier detection', () => { + const GOOD_PORTS = 4; + let goodServer: grpc.Server; + let badServer: grpc.Server; + const goodPorts: number[] = []; + let badPort: number; + before(done => { + const eachDone = multiDone(() => { + goodServer.start(); + badServer.start(); + done(); + }, GOOD_PORTS + 1); + goodServer = new grpc.Server(); + goodServer.addService(EchoService.service, goodService); + for (let i = 0; i < GOOD_PORTS; i++) { + goodServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + eachDone(error); + return; + } + goodPorts.push(port); + eachDone(); + }); + } + badServer = new grpc.Server(); + badServer.addService(EchoService.service, badService); + badServer.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, port) => { + if (error) { + eachDone(error); + return; + } + badPort = port; + eachDone(); + }); + }); + after(() => { + goodServer.forceShutdown(); + badServer.forceShutdown(); + }); + + it('Should allow normal operation with one server', done => { + const client = new EchoService(`localhost:${goodPorts[0]}`, grpc.credentials.createInsecure(), {'grpc.service_config': defaultOutlierDetectionServiceConfigString}); + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); +}); \ No newline at end of file From 5a601b0f78dd124fc0a9056f43d2e4d85d5c1246 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Mar 2022 11:55:38 -0700 Subject: [PATCH 1635/1899] grpc-js: Consistently log subchannel and call IDs in traces --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 4 ++++ packages/grpc-js/src/channel.ts | 17 +++++++++++------ packages/grpc-js/src/subchannel.ts | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f41de376d..f617223bc 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.7", + "version": "1.5.8", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index f2e045aef..601218886 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -795,6 +795,10 @@ export class Http2CallStream implements Call { this.filterStack.push(extraFilters); } + getCallNumber() { + return this.callNumber; + } + startRead() { /* If the stream has ended with an error, we should not emit any more * messages and we should communicate that the stream has ended */ diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 8fa2c592a..9d73c5df8 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -404,11 +404,16 @@ export class ChannelImplementation implements Channel { metadata: callMetadata, extraPickInfo: callConfig.pickInformation, }); + const subchannelString = pickResult.subchannel ? + '(' + pickResult.subchannel.getChannelzRef().id + ') ' + pickResult.subchannel.getAddress() : + '' + pickResult.subchannel; this.trace( - 'Pick result: ' + + 'Pick result for call [' + + callStream.getCallNumber() + + ']: ' + PickResultType[pickResult.pickResultType] + ' subchannel: ' + - pickResult.subchannel?.getAddress() + + subchannelString + ' status: ' + pickResult.status?.code + ' ' + @@ -433,7 +438,7 @@ export class ChannelImplementation implements Channel { log( LogVerbosity.ERROR, 'Error: COMPLETE pick result subchannel ' + - pickResult.subchannel!.getAddress() + + subchannelString + ' has state ' + ConnectivityState[pickResult.subchannel!.getConnectivityState()] ); @@ -480,7 +485,7 @@ export class ChannelImplementation implements Channel { * tryPick */ this.trace( 'Failed to start call on picked subchannel ' + - pickResult.subchannel!.getAddress() + + subchannelString + ' with error ' + (error as Error).message + '. Retrying pick', @@ -490,7 +495,7 @@ export class ChannelImplementation implements Channel { } else { this.trace( 'Failed to start call on picked subchanel ' + - pickResult.subchannel!.getAddress() + + subchannelString + ' with error ' + (error as Error).message + '. Ending call', @@ -509,7 +514,7 @@ export class ChannelImplementation implements Channel { * block above */ this.trace( 'Picked subchannel ' + - pickResult.subchannel!.getAddress() + + subchannelString + ' has state ' + ConnectivityState[subchannelState] + ' after metadata filters. Retrying pick', diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 24f02144d..22c243fed 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -857,7 +857,7 @@ export class Subchannel { logging.trace( LogVerbosity.DEBUG, 'call_stream', - 'Starting stream on subchannel ' + + 'Starting stream [' + callStream.getCallNumber() + '] on subchannel ' + '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' with headers\n' + From 109020ef02a443a76ad109a9cd520b49fca3e8af Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 15 Mar 2022 12:07:11 -0700 Subject: [PATCH 1636/1899] Add credentials scope in oauth2_auth_token interop test --- test/interop/interop_client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/interop/interop_client.js b/test/interop/interop_client.js index d7df128da..57f4f1846 100644 --- a/test/interop/interop_client.js +++ b/test/interop/interop_client.js @@ -484,7 +484,7 @@ function getApplicationCreds(scope, callback) { } function getOauth2Creds(scope, callback) { - (new GoogleAuth()).getAccessToken().then((token) => { + (new GoogleAuth({scopes: scope})).getAccessToken().then((token) => { var updateMd = function(service_url, callback) { var metadata = new grpc.Metadata(); metadata.add('authorization', 'Bearer ' + token); From 97584dcf3193662388802abba1ffb224953bd1fa Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 Mar 2022 11:27:05 -0700 Subject: [PATCH 1637/1899] grpc-js: Add channel construction stacktrace traces --- doc/environment_variables.md | 1 + packages/grpc-js/src/channel.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 2eb429f92..0237dff7e 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -39,6 +39,7 @@ can be set. - `subchannel_refcount` - Traces subchannel refcount changes. Includes per-call logs. - `subchannel_flowctrl` - Traces HTTP/2 flow control. Includes per-call logs. - `subchannel_internals` - Traces HTTP/2 session state. Includes per-call logs. + - `channel_stacktrace` - Traces channel construction events with stack traces. The following tracers are added by the `@grpc/grpc-js-xds` library: - `cds_balancer` - Traces the CDS load balancing policy diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 9d73c5df8..d1c9bd028 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -335,6 +335,8 @@ export class ChannelImplementation implements Channel { new CompressionFilterFactory(this, this.options), ]); this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); + const error = new Error(); + trace(LogVerbosity.DEBUG, 'channel_stacktrace', '(' + this.channelzRef.id + ') ' + 'Channel constructed \n' + error.stack?.substring(error.stack.indexOf('\n')+1)); } private getChannelzInfo(): ChannelInfo { From 39f027e284c9c23591fad25eb2f4d6b80ab26e2e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 Mar 2022 11:34:33 -0700 Subject: [PATCH 1638/1899] grpc-js: Trace call end when actually ending the call --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f617223bc..c15678c83 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.8", + "version": "1.5.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 601218886..4eff39eb8 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -312,6 +312,13 @@ export class Http2CallStream implements Call { const filteredStatus = this.filterStack.receiveTrailers( this.finalStatus! ); + this.trace( + 'ended with status: code=' + + filteredStatus.code + + ' details="' + + filteredStatus.details + + '"' + ); this.statusWatchers.forEach(watcher => watcher(filteredStatus)); /* We delay the actual action of bubbling up the status to insulate the * cleanup code in this class from any errors that may be thrown in the @@ -346,13 +353,6 @@ export class Http2CallStream implements Call { /* If the status is OK and a new status comes in (e.g. from a * deserialization failure), that new status takes priority */ if (this.finalStatus === null || this.finalStatus.code === Status.OK) { - this.trace( - 'ended with status: code=' + - status.code + - ' details="' + - status.details + - '"' - ); this.finalStatus = status; this.maybeOutputStatus(); } From 81e08e84df4cfda5e5479f8455a86bd3d27964e7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 Mar 2022 12:39:36 -0700 Subject: [PATCH 1639/1899] grpc-js: Transparently retry session destroyed error --- packages/grpc-js/src/channel.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 9d73c5df8..8ca11dd58 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -466,9 +466,9 @@ export class ChannelImplementation implements Channel { callConfig.onCommitted?.(); pickResult.onCallStarted?.(); } catch (error) { - if ( - (error as NodeJS.ErrnoException).code === - 'ERR_HTTP2_GOAWAY_SESSION' + const errorCode = (error as NodeJS.ErrnoException).code; + if (errorCode === 'ERR_HTTP2_GOAWAY_SESSION' || + errorCode === 'ERR_HTTP2_INVALID_SESSION' ) { /* An error here indicates that something went wrong with * the picked subchannel's http2 stream right before we From b5b0703bcd7006eef554f977070827e881863d08 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 Mar 2022 12:40:30 -0700 Subject: [PATCH 1640/1899] grpc-js-xds: Add outlier detection configuration handling --- packages/grpc-js-xds/src/environment.ts | 3 +- packages/grpc-js-xds/src/load-balancer-cds.ts | 62 ++++++++++++++++++- packages/grpc-js-xds/src/load-balancer-eds.ts | 34 ++++++++-- .../src/xds-stream-state/cds-state.ts | 48 ++++++++++++++ packages/grpc-js/src/experimental.ts | 5 +- .../src/load-balancer-outlier-detection.ts | 49 ++++++++++----- 6 files changed, 177 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index e1c2d8158..b8b518da4 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -15,4 +15,5 @@ * */ -export const EXPERIMENTAL_FAULT_INJECTION = (process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION ?? 'true') === 'true'; \ No newline at end of file +export const EXPERIMENTAL_FAULT_INJECTION = (process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION ?? 'true') === 'true'; +export const EXPERIMENTAL_OUTLIER_DETECTION = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION === 'true'; \ No newline at end of file diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index 4829edd44..a6dbf42f0 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -25,8 +25,14 @@ import LoadBalancer = experimental.LoadBalancer; import ChannelControlHelper = experimental.ChannelControlHelper; import registerLoadBalancerType = experimental.registerLoadBalancerType; import LoadBalancingConfig = experimental.LoadBalancingConfig; +import OutlierDetectionLoadBalancingConfig = experimental.OutlierDetectionLoadBalancingConfig; +import SuccessRateEjectionConfig = experimental.SuccessRateEjectionConfig; +import FailurePercentageEjectionConfig = experimental.FailurePercentageEjectionConfig; import { EdsLoadBalancingConfig } from './load-balancer-eds'; import { Watcher } from './xds-stream-state/xds-stream-state'; +import { OutlierDetection__Output } from './generated/envoy/config/cluster/v3/OutlierDetection'; +import { Duration__Output } from './generated/google/protobuf/Duration'; +import { EXPERIMENTAL_OUTLIER_DETECTION } from './environment'; const TRACER_NAME = 'cds_balancer'; @@ -64,6 +70,52 @@ export class CdsLoadBalancingConfig implements LoadBalancingConfig { } } +function durationToMs(duration: Duration__Output): number { + return (Number(duration.seconds) * 1_000 + duration.nanos / 1_000_000) | 0; +} + +function translateOutlierDetectionConfig(outlierDetection: OutlierDetection__Output | null): OutlierDetectionLoadBalancingConfig | undefined { + if (!EXPERIMENTAL_OUTLIER_DETECTION) { + return undefined; + } + if (!outlierDetection) { + /* No-op outlier detection config, with max possible interval and no + * ejection criteria configured. */ + return new OutlierDetectionLoadBalancingConfig(~(1<<31), null, null, null, null, null, []); + } + let successRateConfig: Partial | null = null; + /* Success rate ejection is enabled by default, so we only disable it if + * enforcing_success_rate is set and it has the value 0 */ + if (!outlierDetection.enforcing_success_rate || outlierDetection.enforcing_success_rate.value > 0) { + successRateConfig = { + enforcement_percentage: outlierDetection.enforcing_success_rate?.value, + minimum_hosts: outlierDetection.success_rate_minimum_hosts?.value, + request_volume: outlierDetection.success_rate_request_volume?.value, + stdev_factor: outlierDetection.success_rate_stdev_factor?.value + }; + } + let failurePercentageConfig: Partial | null = null; + /* Failure percentage ejection is disabled by default, so we only enable it + * if enforcing_failure_percentage is set and it has a value greater than 0 */ + if (outlierDetection.enforcing_failure_percentage && outlierDetection.enforcing_failure_percentage.value > 0) { + failurePercentageConfig = { + enforcement_percentage: outlierDetection.enforcing_failure_percentage.value, + minimum_hosts: outlierDetection.failure_percentage_minimum_hosts?.value, + request_volume: outlierDetection.failure_percentage_request_volume?.value, + threshold: outlierDetection.failure_percentage_threshold?.value + } + } + return new OutlierDetectionLoadBalancingConfig( + outlierDetection.interval ? durationToMs(outlierDetection.interval) : null, + outlierDetection.base_ejection_time ? durationToMs(outlierDetection.base_ejection_time) : null, + outlierDetection.max_ejection_time ? durationToMs(outlierDetection.max_ejection_time) : null, + outlierDetection.max_ejection_percent?.value ?? null, + successRateConfig, + failurePercentageConfig, + [] + ); +} + export class CdsLoadBalancer implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; private watcher: Watcher; @@ -90,7 +142,15 @@ export class CdsLoadBalancer implements LoadBalancer { * used for load reporting as for other xDS operations. Setting * lrsLoadReportingServerName to the empty string sets that behavior. * Otherwise, if the field is omitted, load reporting is disabled. */ - const edsConfig: EdsLoadBalancingConfig = new EdsLoadBalancingConfig(update.name, [], [], update.eds_cluster_config!.service_name === '' ? undefined : update.eds_cluster_config!.service_name, update.lrs_server?.self ? '' : undefined, maxConcurrentRequests); + const edsConfig: EdsLoadBalancingConfig = new EdsLoadBalancingConfig( + /* cluster= */ update.name, + /* localityPickingPolicy= */ [], + /* endpointPickingPolicy= */ [], + /* edsServiceName= */ update.eds_cluster_config!.service_name === '' ? undefined : update.eds_cluster_config!.service_name, + /* lrsLoadReportingServerName= */update.lrs_server?.self ? '' : undefined, + /* maxConcurrentRequests= */ maxConcurrentRequests, + /* outlierDetection= */ translateOutlierDetectionConfig(update.outlier_detection) + ); trace('Child update EDS config: ' + JSON.stringify(edsConfig)); this.childBalancer.updateAddressList( [], diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index 55ad714a9..e7aac0571 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -38,6 +38,8 @@ import Filter = experimental.Filter; import BaseFilter = experimental.BaseFilter; import FilterFactory = experimental.FilterFactory; import CallStream = experimental.CallStream; +import OutlierDetectionLoadBalancingConfig = experimental.OutlierDetectionLoadBalancingConfig; +import { EXPERIMENTAL_OUTLIER_DETECTION } from './environment'; const TRACER_NAME = 'eds_balancer'; @@ -71,12 +73,15 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { if (this.lrsLoadReportingServerName !== undefined) { jsonObj.lrs_load_reporting_server_name = this.lrsLoadReportingServerName; } + if (this.outlierDetection !== undefined) { + jsonObj.outlier_detection = this.outlierDetection.toJsonObject(); + } return { [TYPE_NAME]: jsonObj }; } - constructor(private cluster: string, private localityPickingPolicy: LoadBalancingConfig[], private endpointPickingPolicy: LoadBalancingConfig[], private edsServiceName?: string, private lrsLoadReportingServerName?: string, maxConcurrentRequests?: number) { + constructor(private cluster: string, private localityPickingPolicy: LoadBalancingConfig[], private endpointPickingPolicy: LoadBalancingConfig[], private edsServiceName?: string, private lrsLoadReportingServerName?: string, maxConcurrentRequests?: number, private outlierDetection?: OutlierDetectionLoadBalancingConfig) { this.maxConcurrentRequests = maxConcurrentRequests ?? DEFAULT_MAX_CONCURRENT_REQUESTS; } @@ -104,6 +109,10 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { return this.maxConcurrentRequests; } + getOutlierDetection() { + return this.outlierDetection; + } + static createFromJson(obj: any): EdsLoadBalancingConfig { if (!('cluster' in obj && typeof obj.cluster === 'string')) { throw new Error('eds config must have a string field cluster'); @@ -123,7 +132,17 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { if ('max_concurrent_requests' in obj && (!obj.max_concurrent_requests === undefined || typeof obj.max_concurrent_requests === 'number')) { throw new Error('eds config max_concurrent_requests must be a number if provided'); } - return new EdsLoadBalancingConfig(obj.cluster, obj.locality_picking_policy.map(validateLoadBalancingConfig), obj.endpoint_picking_policy.map(validateLoadBalancingConfig), obj.eds_service_name, obj.lrs_load_reporting_server_name, obj.max_concurrent_requests); + let validatedOutlierDetectionConfig: OutlierDetectionLoadBalancingConfig | undefined = undefined; + if (EXPERIMENTAL_OUTLIER_DETECTION) { + if ('outlier_detection' in obj) { + const outlierDetectionConfig = validateLoadBalancingConfig(obj.outlier_detection); + if (!(outlierDetectionConfig instanceof OutlierDetectionLoadBalancingConfig)) { + throw new Error('eds config outlier_detection must be a valid outlier detection config if provided'); + } + validatedOutlierDetectionConfig = outlierDetectionConfig; + } + } + return new EdsLoadBalancingConfig(obj.cluster, obj.locality_picking_policy.map(validateLoadBalancingConfig), obj.endpoint_picking_policy.map(validateLoadBalancingConfig), obj.eds_service_name, obj.lrs_load_reporting_server_name, obj.max_concurrent_requests, validatedOutlierDetectionConfig); } } @@ -449,10 +468,15 @@ export class EdsLoadBalancer implements LoadBalancer { } } + const weightedTargetConfig = new WeightedTargetLoadBalancingConfig(childTargets); + let outlierDetectionConfig: OutlierDetectionLoadBalancingConfig | undefined; + if (EXPERIMENTAL_OUTLIER_DETECTION) { + outlierDetectionConfig = this.lastestConfig.getOutlierDetection()?.copyWithChildPolicy([weightedTargetConfig]); + } + const priorityChildConfig = outlierDetectionConfig ?? weightedTargetConfig; + priorityChildren.set(newPriorityName, { - config: [ - new WeightedTargetLoadBalancingConfig(childTargets), - ], + config: [priorityChildConfig], }); } /* Contract the priority names array if it is sparse. This config only diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 7737dc961..8c3c4d739 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -16,8 +16,11 @@ */ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { EXPERIMENTAL_OUTLIER_DETECTION } from "../environment"; import { Cluster__Output } from "../generated/envoy/config/cluster/v3/Cluster"; import { Any__Output } from "../generated/google/protobuf/Any"; +import { Duration__Output } from "../generated/google/protobuf/Duration"; +import { UInt32Value__Output } from "../generated/google/protobuf/UInt32Value"; import { EdsState } from "./eds-state"; import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; @@ -102,6 +105,26 @@ export class CdsState implements XdsStreamState { return Array.from(this.watchers.keys()); } + private validateNonnegativeDuration(duration: Duration__Output | null): boolean { + if (!duration) { + return true; + } + /* The maximum values here come from the official Protobuf documentation: + * https://developers.google.com/protocol-buffers/docs/reference/google.protobuf#google.protobuf.Duration + */ + return Number(duration.seconds) >= 0 && + Number(duration.seconds) <= 315_576_000_000 && + duration.nanos >= 0 && + duration.nanos <= 999_999_999; + } + + private validatePercentage(percentage: UInt32Value__Output | null): boolean { + if (!percentage) { + return true; + } + return percentage.value >=0 && percentage.value <= 100; + } + private validateResponse(message: Cluster__Output): boolean { if (message.type !== 'EDS') { return false; @@ -117,6 +140,31 @@ export class CdsState implements XdsStreamState { return false; } } + if (EXPERIMENTAL_OUTLIER_DETECTION) { + if (message.outlier_detection) { + if (!this.validateNonnegativeDuration(message.outlier_detection.interval)) { + return false; + } + if (!this.validateNonnegativeDuration(message.outlier_detection.base_ejection_time)) { + return false; + } + if (!this.validateNonnegativeDuration(message.outlier_detection.max_ejection_time)) { + return false; + } + if (!this.validatePercentage(message.outlier_detection.max_ejection_percent)) { + return false; + } + if (!this.validatePercentage(message.outlier_detection.enforcing_success_rate)) { + return false; + } + if (!this.validatePercentage(message.outlier_detection.failure_percentage_threshold)) { + return false; + } + if (!this.validatePercentage(message.outlier_detection.enforcing_failure_percentage)) { + return false; + } + } + } return true; } diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index a9d76406b..fcafbeb01 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -6,7 +6,7 @@ export { ConfigSelector, } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; -export { Duration } from './duration'; +export { Duration, durationToMs } from './duration'; export { ServiceConfig } from './service-config'; export { BackoffTimeout } from './backoff-timeout'; export { @@ -35,4 +35,5 @@ export { Call as CallStream } from './call-stream'; export { Filter, BaseFilter, FilterFactory } from './filter'; export { FilterStackFactory } from './filter-stack'; export { registerAdminService } from './admin'; -export { SubchannelInterface, BaseSubchannelWrapper, ConnectivityStateListener } from './subchannel-interface' +export { SubchannelInterface, BaseSubchannelWrapper, ConnectivityStateListener } from './subchannel-interface'; +export { OutlierDetectionLoadBalancingConfig, SuccessRateEjectionConfig, FailurePercentageEjectionConfig } from './load-balancer-outlier-detection'; diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index ffca1c68e..e69e2ef99 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -34,14 +34,14 @@ const TYPE_NAME = 'outlier_detection'; const OUTLIER_DETECTION_ENABLED = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION === 'true'; -interface SuccessRateEjectionConfig { +export interface SuccessRateEjectionConfig { readonly stdev_factor: number; readonly enforcement_percentage: number; readonly minimum_hosts: number; readonly request_volume: number; } -interface FailurePercentageEjectionConfig { +export interface FailurePercentageEjectionConfig { readonly threshold: number; readonly enforcement_percentage: number; readonly minimum_hosts: number; @@ -92,15 +92,29 @@ function validatePercentage(obj: any, fieldName: string, objectName?: string) { } export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig { + private readonly intervalMs: number; + private readonly baseEjectionTimeMs: number; + private readonly maxEjectionTimeMs: number; + private readonly maxEjectionPercent: number; + private readonly successRateEjection: SuccessRateEjectionConfig | null; + private readonly failurePercentageEjection: FailurePercentageEjectionConfig | null; + constructor( - private readonly intervalMs: number, - private readonly baseEjectionTimeMs: number, - private readonly maxEjectionTimeMs: number, - private readonly maxEjectionPercent: number, - private readonly successRateEjection: SuccessRateEjectionConfig | null, - private readonly failurePercentageEjection: FailurePercentageEjectionConfig | null, + intervalMs: number | null, + baseEjectionTimeMs: number | null, + maxEjectionTimeMs: number | null, + maxEjectionPercent: number | null, + successRateEjection: Partial | null, + failurePercentageEjection: Partial | null, private readonly childPolicy: LoadBalancingConfig[] - ) {} + ) { + this.intervalMs = intervalMs ?? 10_000; + this.baseEjectionTimeMs = baseEjectionTimeMs ?? 30_000; + this.maxEjectionTimeMs = maxEjectionTimeMs ?? 300_000; + this.maxEjectionPercent = maxEjectionPercent ?? 10; + this.successRateEjection = successRateEjection ? {...defaultSuccessRateEjectionConfig, ...successRateEjection} : null; + this.failurePercentageEjection = failurePercentageEjection ? {...defaultFailurePercentageEjectionConfig, ...failurePercentageEjection}: null; + } getLoadBalancerName(): string { return TYPE_NAME; } @@ -137,6 +151,11 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig getChildPolicy(): LoadBalancingConfig[] { return this.childPolicy; } + + copyWithChildPolicy(childPolicy: LoadBalancingConfig[]): OutlierDetectionLoadBalancingConfig { + return new OutlierDetectionLoadBalancingConfig(this.intervalMs, this.baseEjectionTimeMs, this.maxEjectionTimeMs, this.maxEjectionPercent, this.successRateEjection, this.failurePercentageEjection, childPolicy); + } + static createFromJson(obj: any): OutlierDetectionLoadBalancingConfig { validatePositiveDuration(obj, 'interval'); validatePositiveDuration(obj, 'base_ejection_time'); @@ -162,12 +181,12 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig } return new OutlierDetectionLoadBalancingConfig( - obj.interval ? durationToMs(obj.interval) : 10_000, - obj.base_ejection_time ? durationToMs(obj.base_ejection_time) : 30_000, - obj.max_ejection_time ? durationToMs(obj.max_ejection_time) : 300_000, - obj.max_ejection_percent ?? 10, - obj.success_rate_ejection ? {...defaultSuccessRateEjectionConfig, ...obj.success_rate_ejection} : null, - obj.failure_percentage_ejection ? {...defaultFailurePercentageEjectionConfig, ...obj.failure_percentage_ejection} : null, + obj.interval ? durationToMs(obj.interval) : null, + obj.base_ejection_time ? durationToMs(obj.base_ejection_time) : null, + obj.max_ejection_time ? durationToMs(obj.max_ejection_time) : null, + obj.max_ejection_percent ?? null, + obj.success_rate_ejection, + obj.failure_percentage_ejection, obj.child_policy.map(validateLoadBalancingConfig) ); } From 680ff7cc08e12d2bdf57687079fa06ceeafe80c4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 24 Mar 2022 12:45:28 -0700 Subject: [PATCH 1641/1899] grpc-js: Improve coverage of channelzEnabled checks in server code --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/server.ts | 147 +++++++++++++++++++++------------ 2 files changed, 95 insertions(+), 54 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index c15678c83..50896e963 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.9", + "version": "1.5.10", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 9c28a276f..85f492ff3 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -430,27 +430,36 @@ export class Server { port: boundAddress.port } } - const channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { - return { - localAddress: boundSubchannelAddress, - remoteAddress: null, - security: null, - remoteName: null, - streamsStarted: 0, - streamsSucceeded: 0, - streamsFailed: 0, - messagesSent: 0, - messagesReceived: 0, - keepAlivesSent: 0, - lastLocalStreamCreatedTimestamp: null, - lastRemoteStreamCreatedTimestamp: null, - lastMessageSentTimestamp: null, - lastMessageReceivedTimestamp: null, - localFlowControlWindow: null, - remoteFlowControlWindow: null + let channelzRef: SocketRef; + if (this.channelzEnabled) { + channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { + return { + localAddress: boundSubchannelAddress, + remoteAddress: null, + security: null, + remoteName: null, + streamsStarted: 0, + streamsSucceeded: 0, + streamsFailed: 0, + messagesSent: 0, + messagesReceived: 0, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null, + localFlowControlWindow: null, + remoteFlowControlWindow: null + }; + }); + this.listenerChildrenTracker.refChild(channelzRef); + } else { + channelzRef = { + kind: 'socket', + id: -1, + name: '' }; - }); - this.listenerChildrenTracker.refChild(channelzRef); + } this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve('port' in boundSubchannelAddress ? boundSubchannelAddress.port : portNum); @@ -499,27 +508,36 @@ export class Server { host: boundAddress.address, port: boundAddress.port }; - const channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { - return { - localAddress: boundSubchannelAddress, - remoteAddress: null, - security: null, - remoteName: null, - streamsStarted: 0, - streamsSucceeded: 0, - streamsFailed: 0, - messagesSent: 0, - messagesReceived: 0, - keepAlivesSent: 0, - lastLocalStreamCreatedTimestamp: null, - lastRemoteStreamCreatedTimestamp: null, - lastMessageSentTimestamp: null, - lastMessageReceivedTimestamp: null, - localFlowControlWindow: null, - remoteFlowControlWindow: null + let channelzRef: SocketRef; + if (this.channelzEnabled) { + channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { + return { + localAddress: boundSubchannelAddress, + remoteAddress: null, + security: null, + remoteName: null, + streamsStarted: 0, + streamsSucceeded: 0, + streamsFailed: 0, + messagesSent: 0, + messagesReceived: 0, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null, + localFlowControlWindow: null, + remoteFlowControlWindow: null + }; + }); + this.listenerChildrenTracker.refChild(channelzRef); + } else { + channelzRef = { + kind: 'socket', + id: -1, + name: '' }; - }); - this.listenerChildrenTracker.refChild(channelzRef); + } this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); resolve( @@ -599,8 +617,10 @@ export class Server { for (const {server: http2Server, channelzRef: ref} of this.http2ServerList) { if (http2Server.listening) { http2Server.close(() => { - this.listenerChildrenTracker.unrefChild(ref); - unregisterChannelzRef(ref); + if (this.channelzEnabled) { + this.listenerChildrenTracker.unrefChild(ref); + unregisterChannelzRef(ref); + } }); } } @@ -616,7 +636,9 @@ export class Server { session.destroy(http2.constants.NGHTTP2_CANCEL as any); }); this.sessions.clear(); - unregisterChannelzRef(this.channelzRef); + if (this.channelzEnabled) { + unregisterChannelzRef(this.channelzRef); + } } register( @@ -665,7 +687,9 @@ export class Server { tryShutdown(callback: (error?: Error) => void): void { const wrappedCallback = (error?: Error) => { - unregisterChannelzRef(this.channelzRef); + if (this.channelzEnabled) { + unregisterChannelzRef(this.channelzRef); + } callback(error); }; let pendingChecks = 0; @@ -685,8 +709,10 @@ export class Server { if (http2Server.listening) { pendingChecks++; http2Server.close(() => { - this.listenerChildrenTracker.unrefChild(ref); - unregisterChannelzRef(ref); + if (this.channelzEnabled) { + this.listenerChildrenTracker.unrefChild(ref); + unregisterChannelzRef(ref); + } maybeCallback(); }); } @@ -727,8 +753,10 @@ export class Server { 'stream', (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { const channelzSessionInfo = this.sessions.get(stream.session as http2.ServerHttp2Session); - this.callTracker.addCallStarted(); - channelzSessionInfo?.streamTracker.addCallStarted(); + if (this.channelzEnabled) { + this.callTracker.addCallStarted(); + channelzSessionInfo?.streamTracker.addCallStarted(); + } const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; if ( @@ -743,7 +771,9 @@ export class Server { { endStream: true } ); this.callTracker.addCallFailed(); - channelzSessionInfo?.streamTracker.addCallFailed(); + if (this.channelzEnabled) { + channelzSessionInfo?.streamTracker.addCallFailed(); + } return; } @@ -786,7 +816,7 @@ export class Server { this.callTracker.addCallFailed(); } }); - if (channelzSessionInfo) { + if (this.channelzEnabled && channelzSessionInfo) { call.once('streamEnd', (success: boolean) => { if (success) { channelzSessionInfo.streamTracker.addCallSucceeded(); @@ -841,8 +871,10 @@ export class Server { } catch (err) { if (!call) { call = new Http2ServerCallStream(stream, null!, this.options); - this.callTracker.addCallFailed(); - channelzSessionInfo?.streamTracker.addCallFailed() + if (this.channelzEnabled) { + this.callTracker.addCallFailed(); + channelzSessionInfo?.streamTracker.addCallFailed() + } } if (err.code === undefined) { @@ -860,7 +892,16 @@ export class Server { return; } - const channelzRef = registerChannelzSocket(session.socket.remoteAddress ?? 'unknown', this.getChannelzSessionInfoGetter(session)); + let channelzRef: SocketRef; + if (this.channelzEnabled) { + channelzRef = registerChannelzSocket(session.socket.remoteAddress ?? 'unknown', this.getChannelzSessionInfoGetter(session)); + } else { + channelzRef = { + kind: 'socket', + id: -1, + name: '' + } + } const channelzSessionInfo: ChannelzSessionInfo = { ref: channelzRef, From 260aee93dac27bad97172fe38ce2f61ce5886af4 Mon Sep 17 00:00:00 2001 From: Kamil Skalski Date: Fri, 25 Mar 2022 09:22:23 -0500 Subject: [PATCH 1642/1899] Expose MetadataOptions interface in grpc-js. --- packages/grpc-js/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index ed452547e..2e6fcb5bf 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -48,7 +48,7 @@ import { ServiceClientConstructor, ServiceDefinition, } from './make-client'; -import { Metadata, MetadataValue } from './metadata'; +import { Metadata, MetadataOptions, MetadataValue } from './metadata'; import { Server, UntypedHandleCall, From 8d7d3f3d23e3690b732fb4f8ab3e7666ac72be41 Mon Sep 17 00:00:00 2001 From: Kamil Skalski Date: Fri, 25 Mar 2022 09:22:23 -0500 Subject: [PATCH 1643/1899] Expose MetadataOptions interface in grpc-js. --- packages/grpc-js/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 2e6fcb5bf..b4855fb59 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -119,7 +119,7 @@ export const credentials = { /**** Metadata ****/ -export { Metadata, MetadataValue }; +export { Metadata, MetadataOptions, MetadataValue }; /**** Constants ****/ From 052af317a3cbd0b8888502c2f232ef76f0af1873 Mon Sep 17 00:00:00 2001 From: murgatroid99 Date: Mon, 28 Mar 2022 14:06:04 -0700 Subject: [PATCH 1644/1899] grpc-js: Avoid surfacing errors without gRPC error codes --- packages/grpc-js/src/call-stream.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 4eff39eb8..e8f312752 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -839,7 +839,16 @@ export class Http2CallStream implements Call { message, flags: context.flags, }; - const cb: WriteCallback = context.callback ?? (() => {}); + const cb: WriteCallback = (error?: Error | null) => { + let code: Status = Status.UNAVAILABLE; + if ((error as NodeJS.ErrnoException)?.code === 'ERR_STREAM_WRITE_AFTER_END') { + code = Status.INTERNAL; + } + if (error) { + this.cancelWithStatus(code, `Write error: ${error.message}`); + } + context.callback?.(); + }; this.isWriteFilterPending = true; this.filterStack.sendMessage(Promise.resolve(writeObj)).then((message) => { this.isWriteFilterPending = false; From 9fcf1659b6f2b36bedb0e337e57d8820be3e835a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 29 Mar 2022 00:15:49 -0700 Subject: [PATCH 1645/1899] Update version to 1.6.0 --- packages/grpc-js-xds/README.md | 3 ++- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js/package.json | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index 1ac235c40..20bd924a8 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -27,4 +27,5 @@ const client = new MyServiceClient('xds:///example.com:123'); - [xDS Timeouts](https://github.com/grpc/proposal/blob/master/A31-xds-timeout-support-and-config-selector.md) - [xDS Circuit Breaking](https://github.com/grpc/proposal/blob/master/A32-xds-circuit-breaking.md) - [xDS Client-Side Fault Injection](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) - - [Client Status Discovery Service](https://github.com/grpc/proposal/blob/master/A40-csds-support.md) \ No newline at end of file + - [Client Status Discovery Service](https://github.com/grpc/proposal/blob/master/A40-csds-support.md) + - [Outlier Detection](https://github.com/grpc/proposal/blob/master/A50-xds-outlier-detection.md) (experimental, disabled by default, enabled by setting the environment variable `GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION=true`) \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index b4e0a49d7..c797f63f2 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.5.2", + "version": "1.6.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.5.0" + "@grpc/grpc-js": "~1.6.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 50896e963..928260be6 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.5.10", + "version": "1.6.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From e58371033f6cd086fcf9406526a4eb7f30ccc494 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 1 Apr 2022 10:46:39 -0700 Subject: [PATCH 1646/1899] grpc-js-xds: Don't stop backoff timers for ADS streams --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/xds-client.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index c797f63f2..9062403cd 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.6.0", + "version": "1.6.1", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 75a567a54..7a12af1f6 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -688,7 +688,6 @@ export class XdsClient { ack(serviceKind: AdsServiceKind) { /* An ack is the best indication of a successful interaction between the * client and the server, so we can reset the backoff timer here. */ - this.adsBackoff.stop(); this.adsBackoff.reset(); this.updateNames(serviceKind); From 8a503031f3db9d83f45a887b78db15d14fd275c2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 1 Apr 2022 10:01:47 -0700 Subject: [PATCH 1647/1899] grpc-js: Add support for grpc.dns_min_time_between_resolutions_ms channel arg --- packages/grpc-js/README.md | 1 + packages/grpc-js/package.json | 2 +- packages/grpc-js/src/channel-options.ts | 2 ++ packages/grpc-js/src/resolver-dns.ts | 45 +++++++++++++++++++++---- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 71ec937ed..11a8ca9aa 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -58,6 +58,7 @@ Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. - `grpc.enable_http_proxy` - `grpc.default_compression_algorithm` - `grpc.enable_channelz` + - `grpc.dns_min_time_between_resolutions_ms` - `grpc-node.max_session_memory` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 928260be6..ecc3e30cd 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.0", + "version": "1.6.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 688317227..b7fc92fa9 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -43,6 +43,7 @@ export interface ChannelOptions { 'grpc.http_connect_creds'?: string; 'grpc.default_compression_algorithm'?: CompressionAlgorithms; 'grpc.enable_channelz'?: number; + 'grpc.dns_min_time_between_resolutions_ms'?: number; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; @@ -69,6 +70,7 @@ export const recognizedOptions = { 'grpc.max_receive_message_length': true, 'grpc.enable_http_proxy': true, 'grpc.enable_channelz': true, + 'grpc.dns_min_time_between_resolutions_ms': true, 'grpc-node.max_session_memory': true, }; diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 8ad24ed05..c4cb64a74 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -45,6 +45,8 @@ function trace(text: string): void { */ const DEFAULT_PORT = 443; +const DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS = 30_000; + const resolveTxtPromise = util.promisify(dns.resolveTxt); const dnsLookupPromise = util.promisify(dns.lookup); @@ -79,6 +81,12 @@ class DnsResolver implements Resolver { private readonly ipResult: SubchannelAddress[] | null; private readonly dnsHostname: string | null; private readonly port: number | null; + /** + * Minimum time between resolutions, measured as the time between starting + * successive resolution requests. Only applies to successful resolutions. + * Failures are handled by the backoff timer. + */ + private readonly minTimeBetweenResolutionsMs: number; private pendingLookupPromise: Promise | null = null; private pendingTxtPromise: Promise | null = null; private latestLookupResult: TcpSubchannelAddress[] | null = null; @@ -88,6 +96,8 @@ class DnsResolver implements Resolver { private defaultResolutionError: StatusObject; private backoff: BackoffTimeout; private continueResolving = false; + private nextResolutionTimer: NodeJS.Timer; + private isNextResolutionTimerRunning = false; constructor( private target: GrpcUri, private listener: ResolverListener, @@ -134,6 +144,10 @@ class DnsResolver implements Resolver { } }, backoffOptions); this.backoff.unref(); + + this.minTimeBetweenResolutionsMs = channelOptions['grpc.dns_min_time_between_resolutions_ms'] ?? DEFAULT_MIN_TIME_BETWEEN_RESOLUTIONS_MS; + this.nextResolutionTimer = setTimeout(() => {}, 0); + clearTimeout(this.nextResolutionTimer); } /** @@ -183,6 +197,7 @@ class DnsResolver implements Resolver { (addressList) => { this.pendingLookupPromise = null; this.backoff.reset(); + this.backoff.stop(); const ip4Addresses: dns.LookupAddress[] = addressList.filter( (addr) => addr.family === 4 ); @@ -229,6 +244,7 @@ class DnsResolver implements Resolver { (err as Error).message ); this.pendingLookupPromise = null; + this.stopNextResolutionTimer(); this.listener.onError(this.defaultResolutionError); } ); @@ -282,17 +298,34 @@ class DnsResolver implements Resolver { } } + private startNextResolutionTimer() { + this.nextResolutionTimer = setTimeout(() => { + this.stopNextResolutionTimer(); + if (this.continueResolving) { + this.startResolutionWithBackoff(); + } + }, this.minTimeBetweenResolutionsMs).unref?.(); + this.isNextResolutionTimerRunning = true; + } + + private stopNextResolutionTimer() { + clearTimeout(this.nextResolutionTimer); + this.isNextResolutionTimerRunning = false; + } + private startResolutionWithBackoff() { this.startResolution(); this.backoff.runOnce(); + this.startNextResolutionTimer(); } updateResolution() { /* If there is a pending lookup, just let it finish. Otherwise, if the - * backoff timer is running, do another lookup when it ends, and if not, - * do another lookup immeidately. */ + * nextResolutionTimer or backoff timer is running, set the + * continueResolving flag to resolve when whichever of those timers + * fires. Otherwise, start resolving immediately. */ if (this.pendingLookupPromise === null) { - if (this.backoff.isRunning()) { + if (this.isNextResolutionTimerRunning || this.backoff.isRunning()) { this.continueResolving = true; } else { this.startResolutionWithBackoff(); @@ -301,9 +334,9 @@ class DnsResolver implements Resolver { } destroy() { - /* Do nothing. There is not a practical way to cancel in-flight DNS - * requests, and after this function is called we can expect that - * updateResolution will not be called again. */ + this.continueResolving = false; + this.backoff.stop(); + this.stopNextResolutionTimer(); } /** From c106d05ac4cfa17746a2d9d6ee357a8056045d68 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 1 Apr 2022 14:31:24 -0700 Subject: [PATCH 1648/1899] grpc-js: Make backoff timer reset apply to the currently running timer --- packages/grpc-js/src/backoff-timeout.ts | 83 +++++++++++++++++++++---- 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts index 7f2ab5ebf..dc7be277a 100644 --- a/packages/grpc-js/src/backoff-timeout.ts +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -37,14 +37,47 @@ export interface BackoffOptions { } export class BackoffTimeout { - private initialDelay: number = INITIAL_BACKOFF_MS; - private multiplier: number = BACKOFF_MULTIPLIER; - private maxDelay: number = MAX_BACKOFF_MS; - private jitter: number = BACKOFF_JITTER; + /** + * The delay time at the start, and after each reset. + */ + private readonly initialDelay: number = INITIAL_BACKOFF_MS; + /** + * The exponential backoff multiplier. + */ + private readonly multiplier: number = BACKOFF_MULTIPLIER; + /** + * The maximum delay time + */ + private readonly maxDelay: number = MAX_BACKOFF_MS; + /** + * The maximum fraction by which the delay time can randomly vary after + * applying the multiplier. + */ + private readonly jitter: number = BACKOFF_JITTER; + /** + * The delay time for the next time the timer runs. + */ private nextDelay: number; + /** + * The handle of the underlying timer. If running is false, this value refers + * to an object representing a timer that has ended, but it can still be + * interacted with without error. + */ private timerId: NodeJS.Timer; + /** + * Indicates whether the timer is currently running. + */ private running = false; + /** + * Indicates whether the timer should keep the Node process running if no + * other async operation is doing so. + */ private hasRef = true; + /** + * The time that the currently running timer was started. Only valid if + * running is true. + */ + private startTime: Date = new Date(); constructor(private callback: () => void, options?: BackoffOptions) { if (options) { @@ -66,18 +99,23 @@ export class BackoffTimeout { clearTimeout(this.timerId); } - /** - * Call the callback after the current amount of delay time - */ - runOnce() { - this.running = true; + private runTimer(delay: number) { this.timerId = setTimeout(() => { this.callback(); this.running = false; - }, this.nextDelay); + }, delay); if (!this.hasRef) { this.timerId.unref?.(); } + } + + /** + * Call the callback after the current amount of delay time + */ + runOnce() { + this.running = true; + this.startTime = new Date(); + this.runTimer(this.nextDelay); const nextBackoff = Math.min( this.nextDelay * this.multiplier, this.maxDelay @@ -97,21 +135,44 @@ export class BackoffTimeout { } /** - * Reset the delay time to its initial value. + * Reset the delay time to its initial value. If the timer is still running, + * retroactively apply that reset to the current timer. */ reset() { this.nextDelay = this.initialDelay; + if (this.running) { + const now = new Date(); + const newEndTime = this.startTime; + newEndTime.setMilliseconds(newEndTime.getMilliseconds() + this.nextDelay); + clearTimeout(this.timerId); + if (now < newEndTime) { + this.runTimer(newEndTime.getTime() - now.getTime()); + } else { + this.running = false; + } + } } + /** + * Check whether the timer is currently running. + */ isRunning() { return this.running; } + /** + * Set that while the timer is running, it should keep the Node process + * running. + */ ref() { this.hasRef = true; this.timerId.ref?.(); } + /** + * Set that while the timer is running, it should not keep the Node process + * running. + */ unref() { this.hasRef = false; this.timerId.unref?.(); From f19563d45ce955a343f018e0def877aa8e2b32c1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 4 Apr 2022 09:37:13 -0700 Subject: [PATCH 1649/1899] grpc-js: Update to version 1.6.2 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index ecc3e30cd..bb8adff8f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.1", + "version": "1.6.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From c80b25e2a52f383a7f6eaf2f09548069ab29623a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 6 Apr 2022 17:15:22 -0700 Subject: [PATCH 1650/1899] grpc-js: Use real channelz IDs when channelz is disabled --- packages/grpc-js/src/channel.ts | 9 +-- packages/grpc-js/src/channelz.ts | 24 ++++--- packages/grpc-js/src/server.ts | 112 +++++++++++------------------ packages/grpc-js/src/subchannel.ts | 11 +-- 4 files changed, 62 insertions(+), 94 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 635b52d6f..3d014607e 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -219,16 +219,9 @@ export class ChannelImplementation implements Channel { } this.channelzTrace = new ChannelzTrace(); + this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo(), this.channelzEnabled); if (this.channelzEnabled) { - this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo()); this.channelzTrace.addTrace('CT_INFO', 'Channel created'); - } else { - // Dummy channelz ref that will never be used - this.channelzRef = { - kind: 'channel', - id: -1, - name: '' - }; } if (this.options['grpc.default_authority']) { diff --git a/packages/grpc-js/src/channelz.ts b/packages/grpc-js/src/channelz.ts index 14c94fd0c..5a7a54760 100644 --- a/packages/grpc-js/src/channelz.ts +++ b/packages/grpc-js/src/channelz.ts @@ -347,31 +347,39 @@ const subchannels: (SubchannelEntry | undefined)[] = []; const servers: (ServerEntry | undefined)[] = []; const sockets: (SocketEntry | undefined)[] = []; -export function registerChannelzChannel(name: string, getInfo: () => ChannelInfo): ChannelRef { +export function registerChannelzChannel(name: string, getInfo: () => ChannelInfo, channelzEnabled: boolean): ChannelRef { const id = getNextId(); const ref: ChannelRef = {id, name, kind: 'channel'}; - channels[id] = { ref, getInfo }; + if (channelzEnabled) { + channels[id] = { ref, getInfo }; + } return ref; } -export function registerChannelzSubchannel(name: string, getInfo:() => SubchannelInfo): SubchannelRef { +export function registerChannelzSubchannel(name: string, getInfo:() => SubchannelInfo, channelzEnabled: boolean): SubchannelRef { const id = getNextId(); const ref: SubchannelRef = {id, name, kind: 'subchannel'}; - subchannels[id] = { ref, getInfo }; + if (channelzEnabled) { + subchannels[id] = { ref, getInfo }; + } return ref; } -export function registerChannelzServer(getInfo: () => ServerInfo): ServerRef { +export function registerChannelzServer(getInfo: () => ServerInfo, channelzEnabled: boolean): ServerRef { const id = getNextId(); const ref: ServerRef = {id, kind: 'server'}; - servers[id] = { ref, getInfo }; + if (channelzEnabled) { + servers[id] = { ref, getInfo }; + } return ref; } -export function registerChannelzSocket(name: string, getInfo: () => SocketInfo): SocketRef { +export function registerChannelzSocket(name: string, getInfo: () => SocketInfo, channelzEnabled: boolean): SocketRef { const id = getNextId(); const ref: SocketRef = {id, name, kind: 'socket'}; - sockets[id] = { ref, getInfo}; + if (channelzEnabled) { + sockets[id] = { ref, getInfo}; + } return ref; } diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 829941faa..974c3dfc6 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -161,17 +161,11 @@ export class Server { if (this.options['grpc.enable_channelz'] === 0) { this.channelzEnabled = false; } + this.channelzRef = registerChannelzServer(() => this.getChannelzInfo(), this.channelzEnabled); if (this.channelzEnabled) { - this.channelzRef = registerChannelzServer(() => this.getChannelzInfo()); this.channelzTrace.addTrace('CT_INFO', 'Server created'); - this.trace('Server constructed'); - } else { - // Dummy channelz ref that will never be used - this.channelzRef = { - kind: 'server', - id: -1 - }; } + this.trace('Server constructed'); } private getChannelzInfo(): ServerInfo { @@ -431,34 +425,28 @@ export class Server { } } let channelzRef: SocketRef; + channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { + return { + localAddress: boundSubchannelAddress, + remoteAddress: null, + security: null, + remoteName: null, + streamsStarted: 0, + streamsSucceeded: 0, + streamsFailed: 0, + messagesSent: 0, + messagesReceived: 0, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null, + localFlowControlWindow: null, + remoteFlowControlWindow: null + }; + }, this.channelzEnabled); if (this.channelzEnabled) { - channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { - return { - localAddress: boundSubchannelAddress, - remoteAddress: null, - security: null, - remoteName: null, - streamsStarted: 0, - streamsSucceeded: 0, - streamsFailed: 0, - messagesSent: 0, - messagesReceived: 0, - keepAlivesSent: 0, - lastLocalStreamCreatedTimestamp: null, - lastRemoteStreamCreatedTimestamp: null, - lastMessageSentTimestamp: null, - lastMessageReceivedTimestamp: null, - localFlowControlWindow: null, - remoteFlowControlWindow: null - }; - }); this.listenerChildrenTracker.refChild(channelzRef); - } else { - channelzRef = { - kind: 'socket', - id: -1, - name: '' - }; } this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); @@ -509,34 +497,28 @@ export class Server { port: boundAddress.port }; let channelzRef: SocketRef; + channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { + return { + localAddress: boundSubchannelAddress, + remoteAddress: null, + security: null, + remoteName: null, + streamsStarted: 0, + streamsSucceeded: 0, + streamsFailed: 0, + messagesSent: 0, + messagesReceived: 0, + keepAlivesSent: 0, + lastLocalStreamCreatedTimestamp: null, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: null, + lastMessageReceivedTimestamp: null, + localFlowControlWindow: null, + remoteFlowControlWindow: null + }; + }, this.channelzEnabled); if (this.channelzEnabled) { - channelzRef = registerChannelzSocket(subchannelAddressToString(boundSubchannelAddress), () => { - return { - localAddress: boundSubchannelAddress, - remoteAddress: null, - security: null, - remoteName: null, - streamsStarted: 0, - streamsSucceeded: 0, - streamsFailed: 0, - messagesSent: 0, - messagesReceived: 0, - keepAlivesSent: 0, - lastLocalStreamCreatedTimestamp: null, - lastRemoteStreamCreatedTimestamp: null, - lastMessageSentTimestamp: null, - lastMessageReceivedTimestamp: null, - localFlowControlWindow: null, - remoteFlowControlWindow: null - }; - }); this.listenerChildrenTracker.refChild(channelzRef); - } else { - channelzRef = { - kind: 'socket', - id: -1, - name: '' - }; } this.http2ServerList.push({server: http2Server, channelzRef: channelzRef}); this.trace('Successfully bound ' + subchannelAddressToString(boundSubchannelAddress)); @@ -893,15 +875,7 @@ export class Server { } let channelzRef: SocketRef; - if (this.channelzEnabled) { - channelzRef = registerChannelzSocket(session.socket.remoteAddress ?? 'unknown', this.getChannelzSessionInfoGetter(session)); - } else { - channelzRef = { - kind: 'socket', - id: -1, - name: '' - } - } + channelzRef = registerChannelzSocket(session.socket.remoteAddress ?? 'unknown', this.getChannelzSessionInfoGetter(session), this.channelzEnabled); const channelzSessionInfo: ChannelzSessionInfo = { ref: channelzRef, diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 800274f99..5ef06b7bd 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -227,16 +227,9 @@ export class Subchannel { this.channelzEnabled = false; } this.channelzTrace = new ChannelzTrace(); + this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); if (this.channelzEnabled) { - this.channelzRef = registerChannelzSubchannel(this.subchannelAddressString, () => this.getChannelzInfo()); this.channelzTrace.addTrace('CT_INFO', 'Subchannel created'); - } else { - // Dummy channelz ref that will never be used - this.channelzRef = { - kind: 'subchannel', - id: -1, - name: '' - }; } this.trace('Subchannel constructed with options ' + JSON.stringify(options, undefined, 2)); } @@ -484,8 +477,8 @@ export class Subchannel { connectionOptions ); this.session = session; + this.channelzSocketRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!, this.channelzEnabled); if (this.channelzEnabled) { - this.channelzSocketRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!); this.childrenTracker.refChild(this.channelzSocketRef); } session.unref(); From 12c58c29237ea48f9278fa3d01f4889a1f558bc1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 7 Apr 2022 17:57:18 -0700 Subject: [PATCH 1651/1899] grpc-js: Disable per-session memory limit by default --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index bb8adff8f..9fab8d838 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.2", + "version": "1.6.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 800274f99..474a05562 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -407,6 +407,12 @@ export class Subchannel { connectionOptions.maxSessionMemory = this.options[ 'grpc-node.max_session_memory' ]; + } else { + /* By default, set a very large max session memory limit, to effectively + * disable enforcement of the limit. Some testing indicates that Node's + * behavior degrades badly when this limit is reached, so we solve that + * by disabling the check entirely. */ + connectionOptions.maxSessionMemory = Number.MAX_SAFE_INTEGER; } let addressScheme = 'http://'; if ('secureContext' in connectionOptions) { From 7ac345e4dc7c5122b9a4707613f8a9aa506f800b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 Apr 2022 10:13:46 -0700 Subject: [PATCH 1652/1899] grpc-js: Add more details to keepalive ping tracing --- packages/grpc-js/src/subchannel.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 800274f99..58f995d7b 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -328,6 +328,10 @@ export class Subchannel { logging.trace(LogVerbosity.DEBUG, 'subchannel_internals', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); } + private keepaliveTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'keepalive', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + private handleBackoffTimer() { if (this.continueConnecting) { this.transitionToState( @@ -358,18 +362,15 @@ export class Subchannel { if (this.channelzEnabled) { this.keepalivesSent += 1; } - logging.trace( - LogVerbosity.DEBUG, - 'keepalive', - '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + - 'Sending ping' - ); + this.keepaliveTrace('Sending ping with timeout ' + this.keepaliveTimeoutMs + 'ms'); this.keepaliveTimeoutId = setTimeout(() => { + this.keepaliveTrace('Ping timeout passed without response'); this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); }, this.keepaliveTimeoutMs); this.keepaliveTimeoutId.unref?.(); this.session!.ping( (err: Error | null, duration: number, payload: Buffer) => { + this.keepaliveTrace('Received ping response'); clearTimeout(this.keepaliveTimeoutId); } ); From abbaf13c62fa02da001a5d5598bf3cdf1a86563a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 Apr 2022 10:25:15 -0700 Subject: [PATCH 1653/1899] grpc-js-xds: Don't stop backoff timers for LRS streams --- packages/grpc-js-xds/src/xds-client.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 7a12af1f6..bdc123959 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -781,7 +781,6 @@ export class XdsClient { trace('Received LRS response'); /* Once we get any response from the server, we assume that the stream is * in a good state, so we can reset the backoff timer. */ - this.lrsBackoff.stop(); this.lrsBackoff.reset(); if ( !this.receivedLrsSettingsForCurrentStream || From ae93d556ec44cd372fff78e69c674904ba63b223 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 Apr 2022 11:23:00 -0700 Subject: [PATCH 1654/1899] grpc-js: Don't clear ping timeout when still connected --- packages/grpc-js/src/subchannel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 800274f99..22c3363c7 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -773,7 +773,7 @@ export class Subchannel { } this.backoffTimeout.unref(); if (!this.keepaliveWithoutCalls) { - this.stopKeepalivePings(); + clearInterval(this.keepaliveIntervalId); } this.checkBothRefcounts(); } From 57d7827ab8341ca90c4c512a371a212760a41aaf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 11 Apr 2022 10:12:24 -0700 Subject: [PATCH 1655/1899] grpc-js-xds: Include Node ID in XdsClient status errors --- packages/grpc-js-xds/src/xds-client.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 7a12af1f6..2eabc5863 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -726,7 +726,7 @@ export class XdsClient { if (serviceKind) { this.adsState[serviceKind].reportStreamError({ code: status.UNAVAILABLE, - details: message, + details: message + ' Node ID=' + this.adsNodeV3!.id, metadata: new Metadata() }); resourceNames = this.adsState[serviceKind].getResourceNames(); @@ -771,6 +771,7 @@ export class XdsClient { } private reportStreamError(status: StatusObject) { + status = {...status, details: status.details + ' Node ID=' + this.adsNodeV3!.id}; this.adsState.eds.reportStreamError(status); this.adsState.cds.reportStreamError(status); this.adsState.rds.reportStreamError(status); From 1e1f73236387bbce8dd216317643b739ad464fa8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 11 Apr 2022 10:42:42 -0700 Subject: [PATCH 1656/1899] grpc-js-xds: Reject EDS updates with duplicate locality/priority pairs --- .../grpc-js-xds/src/xds-stream-state/eds-state.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index fe9f3c624..a050b44c9 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -17,6 +17,7 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { isIPv4, isIPv6 } from "net"; +import { Locality__Output } from "../generated/envoy/config/core/v3/Locality"; import { ClusterLoadAssignment__Output } from "../generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; import { Any__Output } from "../generated/google/protobuf/Any"; import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; @@ -27,6 +28,10 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } +function localitiesEqual(a: Locality__Output, b: Locality__Output) { + return a.region === b.region && a.sub_zone === b.sub_zone && a.zone === b.zone; +} + export class EdsState implements XdsStreamState { public versionInfo = ''; public nonce = ''; @@ -112,7 +117,17 @@ export class EdsState implements XdsStreamState { * @param message */ private validateResponse(message: ClusterLoadAssignment__Output) { + const seenLocalities: {locality: Locality__Output, priority: number}[] = []; for (const endpoint of message.endpoints) { + if (!endpoint.locality) { + return false; + } + for (const {locality, priority} of seenLocalities) { + if (localitiesEqual(endpoint.locality, locality) && endpoint.priority === priority) { + return false; + } + } + seenLocalities.push({locality: endpoint.locality, priority: endpoint.priority}); for (const lb of endpoint.lb_endpoints) { const socketAddress = lb.endpoint?.address?.socket_address; if (!socketAddress) { From 553fb7a819cdb555d03b44c24ca4750a0d85ac31 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 11 Apr 2022 14:43:18 -0700 Subject: [PATCH 1657/1899] grpc-js: Add comment about stopKeepalivePings usage --- packages/grpc-js/src/subchannel.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 22c3363c7..39ccc01bb 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -384,6 +384,11 @@ export class Subchannel { * sending pings should also involve some network activity. */ } + /** + * Stop keepalive pings when terminating a connection. This discards the + * outstanding ping timeout, so it should not be called if the same + * connection will still be used. + */ private stopKeepalivePings() { clearInterval(this.keepaliveIntervalId); clearTimeout(this.keepaliveTimeoutId); From 6c686772cbee628651910dbbd1a8da5b488deeda Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 12 Apr 2022 16:16:57 -0700 Subject: [PATCH 1658/1899] grpc-js: Fix handling of calls after resolution failure --- packages/grpc-js/src/channel.ts | 30 +++++++++++++++---- .../grpc-js/src/resolving-load-balancer.ts | 5 ++-- packages/grpc-js/test/test-client.ts | 24 +++++++++++++++ 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 3d014607e..88bf3a7e0 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -20,6 +20,7 @@ import { Call, Http2CallStream, CallStreamOptions, + StatusObject, } from './call-stream'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; @@ -170,6 +171,14 @@ export class ChannelImplementation implements Channel { */ private callRefTimer: NodeJS.Timer; private configSelector: ConfigSelector | null = null; + /** + * This is the error from the name resolver if it failed most recently. It + * is only used to end calls that start while there is no config selector + * and the name resolver is in backoff, so it should be nulled if + * configSelector becomes set or the channel state becomes anything other + * than TRANSIENT_FAILURE. + */ + private currentResolutionError: StatusObject | null = null; // Channelz info private readonly channelzEnabled: boolean = true; @@ -290,6 +299,7 @@ export class ChannelImplementation implements Channel { this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); } this.configSelector = configSelector; + this.currentResolutionError = null; /* We process the queue asynchronously to ensure that the corresponding * load balancer update has completed. */ process.nextTick(() => { @@ -309,6 +319,9 @@ export class ChannelImplementation implements Channel { if (this.configSelectionQueue.length > 0) { this.trace('Name resolution failed with calls queued for config selection'); } + if (this.configSelector === null) { + this.currentResolutionError = status; + } const localQueue = this.configSelectionQueue; this.configSelectionQueue = []; this.callRefTimerUnref(); @@ -591,6 +604,9 @@ export class ChannelImplementation implements Channel { watcherObject.callback(); } } + if (newState !== ConnectivityState.TRANSIENT_FAILURE) { + this.currentResolutionError = null; + } } private tryGetConfig(stream: Http2CallStream, metadata: Metadata) { @@ -605,11 +621,15 @@ export class ChannelImplementation implements Channel { * ResolvingLoadBalancer may be idle and if so it needs to be kicked * because it now has a pending request. */ this.resolvingLoadBalancer.exitIdle(); - this.configSelectionQueue.push({ - callStream: stream, - callMetadata: metadata, - }); - this.callRefTimerRef(); + if (this.currentResolutionError && !metadata.getOptions().waitForReady) { + stream.cancelWithStatus(this.currentResolutionError.code, this.currentResolutionError.details); + } else { + this.configSelectionQueue.push({ + callStream: stream, + callMetadata: metadata, + }); + this.callRefTimerRef(); + } } else { const callConfig = this.configSelector(stream.getMethod(), metadata); if (callConfig.status === Status.OK) { diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 907067dfc..7b9f92cb8 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -268,6 +268,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { if (this.currentState === ConnectivityState.IDLE) { this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } + this.backoffTimeout.runOnce(); } private updateState(connectivityState: ConnectivityState, picker: Picker) { @@ -294,18 +295,16 @@ export class ResolvingLoadBalancer implements LoadBalancer { ); this.onFailedResolution(error); } - this.backoffTimeout.runOnce(); } exitIdle() { this.childLoadBalancer.exitIdle(); - if (this.currentState === ConnectivityState.IDLE) { + if (this.currentState === ConnectivityState.IDLE || this.currentState === ConnectivityState.TRANSIENT_FAILURE) { if (this.backoffTimeout.isRunning()) { this.continueResolving = true; } else { this.updateResolution(); } - this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } } diff --git a/packages/grpc-js/test/test-client.ts b/packages/grpc-js/test/test-client.ts index 4a02ff3de..21dad99f1 100644 --- a/packages/grpc-js/test/test-client.ts +++ b/packages/grpc-js/test/test-client.ts @@ -92,4 +92,28 @@ describe('Client without a server', () => { }); }); }); +}); + +describe('Client with a nonexistent target domain', () => { + let client: Client; + before(() => { + // DNS name that does not exist per RFC 6761 section 6.4 + client = new Client('host.invalid', clientInsecureCreds); + }); + after(() => { + client.close(); + }); + it('should fail multiple calls', function(done) { + this.timeout(5000); + // Regression test for https://github.com/grpc/grpc-node/issues/1411 + client.makeUnaryRequest('/service/method', x => x, x => x, Buffer.from([]), (error, value) => { + assert(error); + assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); + client.makeUnaryRequest('/service/method', x => x, x => x, Buffer.from([]), (error, value) => { + assert(error); + assert.strictEqual(error?.code, grpc.status.UNAVAILABLE); + done(); + }); + }); + }); }); \ No newline at end of file From c112d167bb0af504c4a1121d2f6f28c9454d3e4d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 13 Apr 2022 11:27:31 -0700 Subject: [PATCH 1659/1899] grpc-js: Update version to 1.6.4 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9fab8d838..408168e9d 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.3", + "version": "1.6.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 478900d191d8f4e6c2e57e9ff732ad974253ceef Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 Apr 2022 16:51:16 -0700 Subject: [PATCH 1660/1899] grpc-js: Consistently re-resolve when idle --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/resolving-load-balancer.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 408168e9d..09a88b5a5 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.4", + "version": "1.6.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 7b9f92cb8..985b6e31e 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -298,7 +298,6 @@ export class ResolvingLoadBalancer implements LoadBalancer { } exitIdle() { - this.childLoadBalancer.exitIdle(); if (this.currentState === ConnectivityState.IDLE || this.currentState === ConnectivityState.TRANSIENT_FAILURE) { if (this.backoffTimeout.isRunning()) { this.continueResolving = true; @@ -306,6 +305,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { this.updateResolution(); } } + this.childLoadBalancer.exitIdle(); } updateAddressList( From 8cbc3dc8258fa31d29a15f59ef230abb69651bb0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 14 Apr 2022 17:28:22 -0700 Subject: [PATCH 1661/1899] grpc-js: Make a reachable code path for requestReresolution in pick_first --- .../grpc-js/src/load-balancer-pick-first.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 884af50b7..240f0e9ff 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -184,8 +184,10 @@ export class PickFirstLoadBalancer implements LoadBalancer { ) { /* If all of the subchannels are IDLE we should go back to a * basic IDLE state where there is no subchannel list to avoid - * holding unused resources */ - this.resetSubchannelList(); + * holding unused resources. We do not reset triedAllSubchannels + * because that is a reminder to request reresolution the next time + * this LB policy needs to connect. */ + this.resetSubchannelList(false); this.updateState(ConnectivityState.IDLE, new QueuePicker(this)); return; } @@ -337,7 +339,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.channelControlHelper.updateState(newState, picker); } - private resetSubchannelList() { + private resetSubchannelList(resetTriedAllSubchannels = true) { for (const subchannel of this.subchannels) { subchannel.removeConnectivityStateListener(this.subchannelStateListener); subchannel.unref(); @@ -352,7 +354,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { [ConnectivityState.TRANSIENT_FAILURE]: 0, }; this.subchannels = []; - this.triedAllSubchannels = false; + if (resetTriedAllSubchannels) { + this.triedAllSubchannels = false; + } } /** @@ -425,6 +429,12 @@ export class PickFirstLoadBalancer implements LoadBalancer { } exitIdle() { + if ( + this.currentState === ConnectivityState.IDLE || + this.triedAllSubchannels + ) { + this.channelControlHelper.requestReresolution(); + } for (const subchannel of this.subchannels) { subchannel.startConnecting(); } @@ -433,12 +443,6 @@ export class PickFirstLoadBalancer implements LoadBalancer { this.connectToAddressList(); } } - if ( - this.currentState === ConnectivityState.IDLE || - this.triedAllSubchannels - ) { - this.channelControlHelper.requestReresolution(); - } } resetBackoff() { From cf11b60ce20123394dc6cb21488c665c7787d84e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 18 Apr 2022 09:36:57 -0700 Subject: [PATCH 1662/1899] grpc-js: End calls when keepalive pings time out --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel.ts | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 09a88b5a5..a0df55736 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.5", + "version": "1.6.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 5880f3f97..5d479a73a 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -358,7 +358,7 @@ export class Subchannel { this.keepaliveTrace('Sending ping with timeout ' + this.keepaliveTimeoutMs + 'ms'); this.keepaliveTimeoutId = setTimeout(() => { this.keepaliveTrace('Ping timeout passed without response'); - this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); + this.handleDisconnect(); }, this.keepaliveTimeoutMs); this.keepaliveTimeoutId.unref?.(); this.session!.ping( @@ -642,6 +642,15 @@ export class Subchannel { ); } + private handleDisconnect() { + this.transitionToState( + [ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE); + for (const listener of this.disconnectListeners) { + listener(); + } + } + /** * Initiate a state transition from any element of oldStates to the new * state. If the current connectivityState is not in oldStates, do nothing. @@ -672,12 +681,7 @@ export class Subchannel { const session = this.session!; session.socket.once('close', () => { if (this.session === session) { - this.transitionToState( - [ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE); - for (const listener of this.disconnectListeners) { - listener(); - } + this.handleDisconnect(); } }); if (this.keepaliveWithoutCalls) { From c9b7d4d285176a6be437b724c118c85f3f08c66d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 18 Apr 2022 09:56:06 -0700 Subject: [PATCH 1663/1899] grpc-js: DNS: unset continueResolving when starting a resolution attempt --- packages/grpc-js/src/resolver-dns.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index c4cb64a74..47de8dbca 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -314,6 +314,7 @@ class DnsResolver implements Resolver { } private startResolutionWithBackoff() { + this.continueResolving = false; this.startResolution(); this.backoff.runOnce(); this.startNextResolutionTimer(); From 964c7a68aabd3e45f87b0d0045bb604e1bd67ae7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Apr 2022 10:21:49 -0700 Subject: [PATCH 1664/1899] grpc-js: Fix double resolver calls in DNS resolver --- packages/grpc-js/src/backoff-timeout.ts | 1 + packages/grpc-js/src/resolver-dns.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts index dc7be277a..f523e259a 100644 --- a/packages/grpc-js/src/backoff-timeout.ts +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -100,6 +100,7 @@ export class BackoffTimeout { } private runTimer(delay: number) { + clearTimeout(this.timerId); this.timerId = setTimeout(() => { this.callback(); this.running = false; diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 47de8dbca..14de26561 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -158,7 +158,6 @@ class DnsResolver implements Resolver { if (this.ipResult !== null) { trace('Returning IP address for target ' + uriToString(this.target)); setImmediate(() => { - this.backoff.reset(); this.listener.onSuccessfulResolution( this.ipResult!, null, @@ -167,6 +166,8 @@ class DnsResolver implements Resolver { {} ); }); + this.backoff.stop(); + this.backoff.reset(); return; } if (this.dnsHostname === null) { @@ -178,7 +179,11 @@ class DnsResolver implements Resolver { metadata: new Metadata(), }); }); + this.stopNextResolutionTimer(); } else { + if (this.pendingLookupPromise !== null) { + return; + } trace('Looking up DNS hostname ' + this.dnsHostname); /* We clear out latestLookupResult here to ensure that it contains the * latest result since the last time we started resolving. That way, the @@ -299,6 +304,7 @@ class DnsResolver implements Resolver { } private startNextResolutionTimer() { + clearTimeout(this.nextResolutionTimer); this.nextResolutionTimer = setTimeout(() => { this.stopNextResolutionTimer(); if (this.continueResolving) { @@ -314,10 +320,12 @@ class DnsResolver implements Resolver { } private startResolutionWithBackoff() { + if (this.pendingLookupPromise === null) { this.continueResolving = false; this.startResolution(); this.backoff.runOnce(); this.startNextResolutionTimer(); + } } updateResolution() { From 5311c03867c7e3bdb1c167fcd76d44d6b5d2e63a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Apr 2022 13:18:59 -0700 Subject: [PATCH 1665/1899] grpc-js: Report error when no message received for unary response --- packages/grpc-js/src/client.ts | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index ed9407cd8..20f56bcb5 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -338,7 +338,15 @@ export class Client { } receivedStatus = true; if (status.code === Status.OK) { - callProperties.callback!(null, responseMessage!); + if (responseMessage === null) { + callProperties.callback!(callErrorFromStatus({ + code: Status.INTERNAL, + details: 'No message received', + metadata: status.metadata + })); + } else { + callProperties.callback!(null, responseMessage); + } } else { callProperties.callback!(callErrorFromStatus(status)); } @@ -455,7 +463,15 @@ export class Client { } receivedStatus = true; if (status.code === Status.OK) { - callProperties.callback!(null, responseMessage!); + if (responseMessage === null) { + callProperties.callback!(callErrorFromStatus({ + code: Status.INTERNAL, + details: 'No message received', + metadata: status.metadata + })); + } else { + callProperties.callback!(null, responseMessage); + } } else { callProperties.callback!(callErrorFromStatus(status)); } From 32514224ce1c85cd6e3c0c2e4a8c197acc90e0b9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 20 Apr 2022 13:06:43 -0700 Subject: [PATCH 1666/1899] grpc-js: Fix shutting down subchannels in separate pools --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel-pool.ts | 14 +++++--------- packages/grpc-js/src/subchannel.ts | 2 +- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a0df55736..723b108ff 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.6", + "version": "1.6.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index cd74cad81..b7ef362c3 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -49,10 +49,8 @@ export class SubchannelPool { /** * A pool of subchannels use for making connections. Subchannels with the * exact same parameters will be reused. - * @param global If true, this is the global subchannel pool. Otherwise, it - * is the pool for a single channel. */ - constructor(private global: boolean) {} + constructor() {} /** * Unrefs all unused subchannels and cancels the cleanup task if all @@ -95,7 +93,7 @@ export class SubchannelPool { * Ensures that the cleanup task is spawned. */ ensureCleanupTask(): void { - if (this.global && this.cleanupTimer === null) { + if (this.cleanupTimer === null) { this.cleanupTimer = setInterval(() => { this.unrefUnusedSubchannels(); }, REF_CHECK_INTERVAL); @@ -156,14 +154,12 @@ export class SubchannelPool { channelCredentials, subchannel, }); - if (this.global) { - subchannel.ref(); - } + subchannel.ref(); return subchannel; } } -const globalSubchannelPool = new SubchannelPool(true); +const globalSubchannelPool = new SubchannelPool(); /** * Get either the global subchannel pool, or a new subchannel pool. @@ -173,6 +169,6 @@ export function getSubchannelPool(global: boolean): SubchannelPool { if (global) { return globalSubchannelPool; } else { - return new SubchannelPool(false); + return new SubchannelPool(); } } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 5d479a73a..372ab5160 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -741,7 +741,7 @@ export class Subchannel { } this.transitionToState( [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE + ConnectivityState.IDLE ); if (this.channelzEnabled) { unregisterChannelzRef(this.channelzRef); From b07ea8b35418ecfd88bccf856bffe8b75eef3727 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 21 Apr 2022 14:42:04 -0700 Subject: [PATCH 1667/1899] grpc-js: Update outlier detection to address recent spec changes --- .../src/load-balancer-outlier-detection.ts | 51 +++++++++++++++---- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index e69e2ef99..3bd062110 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -334,17 +334,21 @@ class OutlierDetectionCounterFilterFactory implements FilterFactory = new Map(); private latestConfig: OutlierDetectionLoadBalancingConfig | null = null; private ejectionTimer: NodeJS.Timer; + private timerStartTime: Date | null = null; constructor(channelControlHelper: ChannelControlHelper) { this.childBalancer = new ChildLoadBalancerHandler(createChildChannelControlHelper(channelControlHelper, { @@ -373,7 +378,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { if (connectivityState === ConnectivityState.READY) { - channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker)); + channelControlHelper.updateState(connectivityState, new OutlierDetectionPicker(picker, this.isCountingEnabled())); } else { channelControlHelper.updateState(connectivityState, picker); } @@ -383,6 +388,12 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { clearInterval(this.ejectionTimer); } + private isCountingEnabled(): boolean { + return this.latestConfig !== null && + (this.latestConfig.getSuccessRateEjectionConfig() !== null || + this.latestConfig.getFailurePercentageEjectionConfig() !== null); + } + private getCurrentEjectionPercent() { let ejectionCount = 0; for (const mapEntry of this.addressMap.values()) { @@ -501,16 +512,26 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } } - private runChecks() { - const ejectionTimestamp = new Date(); - + private switchAllBuckets() { for (const mapEntry of this.addressMap.values()) { mapEntry.counter.switchBuckets(); } + } + + private startTimer(delayMs: number) { + this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs); + } + + private runChecks() { + const ejectionTimestamp = new Date(); + + this.switchAllBuckets(); if (!this.latestConfig) { return; } + this.timerStartTime = ejectionTimestamp; + this.startTimer(this.latestConfig.getIntervalMs()); this.runSuccessRateCheck(ejectionTimestamp); this.runFailurePercentageCheck(ejectionTimestamp); @@ -561,10 +582,21 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { ); this.childBalancer.updateAddressList(addressList, childPolicy, attributes); - if (this.latestConfig === null || this.latestConfig.getIntervalMs() !== lbConfig.getIntervalMs()) { - clearInterval(this.ejectionTimer); - this.ejectionTimer = setInterval(() => this.runChecks(), lbConfig.getIntervalMs()); + if (lbConfig.getSuccessRateEjectionConfig() || lbConfig.getFailurePercentageEjectionConfig()) { + if (this.timerStartTime) { + clearTimeout(this.ejectionTimer); + const remainingDelay = lbConfig.getIntervalMs() - ((new Date()).getTime() - this.timerStartTime.getTime()); + this.startTimer(remainingDelay); + } else { + this.timerStartTime = new Date(); + this.startTimer(lbConfig.getIntervalMs()); + this.switchAllBuckets(); + } + } else { + this.timerStartTime = null; + clearTimeout(this.ejectionTimer); } + this.latestConfig = lbConfig; } exitIdle(): void { @@ -574,6 +606,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { this.childBalancer.resetBackoff(); } destroy(): void { + clearTimeout(this.ejectionTimer); this.childBalancer.destroy(); } getTypeName(): string { From cd58695674679bdf070fea3390b86d51dddf0996 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 21 Apr 2022 16:09:24 -0700 Subject: [PATCH 1668/1899] grpc-js: Add regression tests for repeated DNS requests --- packages/grpc-js/test/test-resolver.ts | 64 ++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 354413ea6..512740cad 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -356,6 +356,70 @@ describe('Name Resolver', () => { const resolver2 = resolverManager.createResolver(target2, listener, {}); resolver2.updateResolution(); }); + it('should not keep repeating successful resolutions', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('localhost')!)!; + let resultCount = 0; + const resolver = resolverManager.createResolver(target, { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '127.0.0.1' && + addr.port === 443 + ) + ); + assert( + addressList.some( + addr => + isTcpSubchannelAddress(addr) && + addr.host === '::1' && + addr.port === 443 + ) + ); + resultCount += 1; + if (resultCount === 1) { + process.nextTick(() => resolver.updateResolution()); + } + }, + onError: (error: StatusObject) => { + assert.ifError(error); + }, + }, {'grpc.dns_min_time_between_resolutions_ms': 2000}); + resolver.updateResolution(); + setTimeout(() => { + assert.strictEqual(resultCount, 2, `resultCount ${resultCount} !== 2`); + done(); + }, 10_000); + }).timeout(15_000); + it('should not keep repeating failed resolutions', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('host.invalid')!)!; + let resultCount = 0; + const resolver = resolverManager.createResolver(target, { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert.fail('Resolution succeeded unexpectedly'); + }, + onError: (error: StatusObject) => { + resultCount += 1; + if (resultCount === 1) { + process.nextTick(() => resolver.updateResolution()); + } + }, + }, {}); + resolver.updateResolution(); + setTimeout(() => { + assert.strictEqual(resultCount, 2, `resultCount ${resultCount} !== 2`); + done(); + }, 10_000); + }).timeout(15_000); }); describe('UDS Names', () => { it('Should handle a relative Unix Domain Socket name', done => { From db65d566e651c96cdba909f22e28bbf7be312778 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 26 Apr 2022 10:09:22 -0700 Subject: [PATCH 1669/1899] grpc-js: Fix mean calculation in outlier detection LB policy --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 3bd062110..2c231c406 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -429,7 +429,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } // Step 2 - const successRateMean = successRates.reduce((a, b) => a + b); + const successRateMean = successRates.reduce((a, b) => a + b) / successRates.length; let successRateVariance = 0; for (const rate of successRates) { const deviation = rate - successRateMean; From 01823377be02b78869c92d8c147944a1b789139b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 28 Apr 2022 10:34:30 -0700 Subject: [PATCH 1670/1899] grpc-js: Add calling context to call errors --- packages/grpc-js/src/call.ts | 6 ++++-- packages/grpc-js/src/client.ts | 16 ++++++++++------ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index fcc3159db..10b606a44 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -76,9 +76,11 @@ export type ClientDuplexStream< * error is not necessarily a problem in gRPC itself. * @param status */ -export function callErrorFromStatus(status: StatusObject): ServiceError { +export function callErrorFromStatus(status: StatusObject, callerStack: string): ServiceError { const message = `${status.code} ${Status[status.code]}: ${status.details}`; - return Object.assign(new Error(message), status); + const error = new Error(message); + const stack = `${error.stack}\nfor call at\n${callerStack}`; + return Object.assign(new Error(message), status, {stack}); } export class ClientUnaryCallImpl diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 20f56bcb5..747c5c877 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -321,6 +321,7 @@ export class Client { } let responseMessage: ResponseType | null = null; let receivedStatus = false; + const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); call.start(callProperties.metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -343,12 +344,12 @@ export class Client { code: Status.INTERNAL, details: 'No message received', metadata: status.metadata - })); + }, callerStack)); } else { callProperties.callback!(null, responseMessage); } } else { - callProperties.callback!(callErrorFromStatus(status)); + callProperties.callback!(callErrorFromStatus(status, callerStack)); } emitter.emit('status', status); }, @@ -446,6 +447,7 @@ export class Client { } let responseMessage: ResponseType | null = null; let receivedStatus = false; + const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); call.start(callProperties.metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -468,12 +470,12 @@ export class Client { code: Status.INTERNAL, details: 'No message received', metadata: status.metadata - })); + }, callerStack)); } else { callProperties.callback!(null, responseMessage); } } else { - callProperties.callback!(callErrorFromStatus(status)); + callProperties.callback!(callErrorFromStatus(status, callerStack)); } emitter.emit('status', status); }, @@ -575,6 +577,7 @@ export class Client { call.setCredentials(callProperties.callOptions.credentials); } let receivedStatus = false; + const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -590,7 +593,7 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { - stream.emit('error', callErrorFromStatus(status)); + stream.emit('error', callErrorFromStatus(status, callerStack)); } stream.emit('status', status); }, @@ -672,6 +675,7 @@ export class Client { call.setCredentials(callProperties.callOptions.credentials); } let receivedStatus = false; + const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -686,7 +690,7 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { - stream.emit('error', callErrorFromStatus(status)); + stream.emit('error', callErrorFromStatus(status, callerStack)); } stream.emit('status', status); }, From 3388765cbb723907de1cc74349b666cc548a891e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 2 May 2022 10:54:03 -0700 Subject: [PATCH 1671/1899] proto-loader: Update to Long 5.x --- packages/proto-loader/package.json | 4 ++-- packages/proto-loader/src/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 9b9431dc1..c9998bafb 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.9", + "version": "0.6.10", "author": "Google Inc.", "contributors": [ { @@ -47,7 +47,7 @@ "dependencies": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "long": "^4.0.0", + "long": "^5.2.0", "protobufjs": "^6.10.0", "yargs": "^16.2.0" }, diff --git a/packages/proto-loader/src/index.ts b/packages/proto-loader/src/index.ts index 24a249400..d607668a9 100644 --- a/packages/proto-loader/src/index.ts +++ b/packages/proto-loader/src/index.ts @@ -22,9 +22,9 @@ import * as descriptor from 'protobufjs/ext/descriptor'; import { loadProtosWithOptionsSync, loadProtosWithOptions, Options, addCommonProtos } from './util'; -export { Long } from 'long'; +import Long = require('long'); -export { Options }; +export { Options, Long }; /** * This type exists for use with code generated by the proto-loader-gen-types From 2b67d5b010db5713d12a0f93ae4c0f26c6d7384c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 May 2022 10:16:54 -0700 Subject: [PATCH 1672/1899] proto-loader: Don't force long@5 --- packages/proto-loader/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index c9998bafb..4b177e87c 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.10", + "version": "0.6.11", "author": "Google Inc.", "contributors": [ { @@ -47,7 +47,7 @@ "dependencies": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "long": "^5.2.0", + "long": "^4.0.0 || ^5.2.0", "protobufjs": "^6.10.0", "yargs": "^16.2.0" }, From d8d957bf8cda8139d46d5da5e2fad912868a4191 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 5 May 2022 09:27:48 -0700 Subject: [PATCH 1673/1899] proto-loader: Switch long dependency back to 4.x --- packages/proto-loader/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 4b177e87c..759e54713 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.11", + "version": "0.6.12", "author": "Google Inc.", "contributors": [ { @@ -47,7 +47,7 @@ "dependencies": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "long": "^4.0.0 || ^5.2.0", + "long": "^4.0.0", "protobufjs": "^6.10.0", "yargs": "^16.2.0" }, From 067bb13f275cf2bbcb2fbacf4a757a7a3c7d4035 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 May 2022 17:18:55 -0700 Subject: [PATCH 1674/1899] grpc-js-xds: Refactor xDS stream state and add resource timer --- packages/grpc-js-xds/src/xds-client.ts | 10 +- .../src/xds-stream-state/cds-state.ts | 156 +-------------- .../src/xds-stream-state/eds-state.ts | 130 +----------- .../src/xds-stream-state/lds-state.ts | 135 ++----------- .../src/xds-stream-state/rds-state.ts | 122 +---------- .../src/xds-stream-state/xds-stream-state.ts | 189 +++++++++++++++++- 6 files changed, 236 insertions(+), 506 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 7a12af1f6..5f75a2cab 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -309,7 +309,7 @@ export class XdsClient { const edsState = new EdsState(() => { this.updateNames('eds'); }); - const cdsState = new CdsState(edsState, () => { + const cdsState = new CdsState(() => { this.updateNames('cds'); }); const rdsState = new RdsState(() => { @@ -630,6 +630,7 @@ export class XdsClient { this.updateNames(service); } } + this.reportAdsStreamStarted(); } } @@ -777,6 +778,13 @@ export class XdsClient { this.adsState.lds.reportStreamError(status); } + private reportAdsStreamStarted() { + this.adsState.eds.reportAdsStreamStart(); + this.adsState.cds.reportAdsStreamStart(); + this.adsState.rds.reportAdsStreamStart(); + this.adsState.lds.reportAdsStreamStart(); + } + private handleLrsResponse(message: LoadStatsResponse__Output) { trace('Received LRS response'); /* Once we get any response from the server, we assume that the stream is diff --git a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts index 8c3c4d739..9fd12d6ed 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/cds-state.ts @@ -15,94 +15,21 @@ * */ -import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { EXPERIMENTAL_OUTLIER_DETECTION } from "../environment"; import { Cluster__Output } from "../generated/envoy/config/cluster/v3/Cluster"; -import { Any__Output } from "../generated/google/protobuf/Any"; import { Duration__Output } from "../generated/google/protobuf/Duration"; import { UInt32Value__Output } from "../generated/google/protobuf/UInt32Value"; -import { EdsState } from "./eds-state"; -import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; +import { BaseXdsStreamState, XdsStreamState } from "./xds-stream-state"; -const TRACER_NAME = 'xds_client'; - -function trace(text: string): void { - experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); -} - -export class CdsState implements XdsStreamState { - versionInfo = ''; - nonce = ''; - - private watchers: Map[]> = new Map< - string, - Watcher[] - >(); - - private latestResponses: Cluster__Output[] = []; - private latestIsV2 = false; - - constructor( - private edsState: EdsState, - private updateResourceNames: () => void - ) {} - - /** - * Add the watcher to the watcher list. Returns true if the list of resource - * names has changed, and false otherwise. - * @param clusterName - * @param watcher - */ - addWatcher(clusterName: string, watcher: Watcher): void { - trace('Adding CDS watcher for clusterName ' + clusterName); - let watchersEntry = this.watchers.get(clusterName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.watchers.set(clusterName, watchersEntry); - } - watchersEntry.push(watcher); - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - const isV2 = this.latestIsV2; - for (const message of this.latestResponses) { - if (message.name === clusterName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - trace('Reporting existing CDS update for new watcher for clusterName ' + clusterName); - watcher.onValidUpdate(message, isV2); - }); - } - } - if (addedServiceName) { - this.updateResourceNames(); - } +export class CdsState extends BaseXdsStreamState implements XdsStreamState { + protected isStateOfTheWorld(): boolean { + return true; } - - removeWatcher(clusterName: string, watcher: Watcher): void { - trace('Removing CDS watcher for clusterName ' + clusterName); - const watchersEntry = this.watchers.get(clusterName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.watchers.delete(clusterName); - } - } - if (removedServiceName) { - this.updateResourceNames(); - } + protected getResourceName(resource: Cluster__Output): string { + return resource.name; } - - getResourceNames(): string[] { - return Array.from(this.watchers.keys()); + protected getProtocolName(): string { + return 'CDS'; } private validateNonnegativeDuration(duration: Duration__Output | null): boolean { @@ -125,7 +52,7 @@ export class CdsState implements XdsStreamState { return percentage.value >=0 && percentage.value <= 100; } - private validateResponse(message: Cluster__Output): boolean { + public validateResponse(message: Cluster__Output): boolean { if (message.type !== 'EDS') { return false; } @@ -167,69 +94,4 @@ export class CdsState implements XdsStreamState { } return true; } - - /** - * Given a list of clusterNames (which may actually be the cluster name), - * for each watcher watching a name not on the list, call that watcher's - * onResourceDoesNotExist method. - * @param allClusterNames - */ - private handleMissingNames(allClusterNames: Set): string[] { - const missingNames: string[] = []; - for (const [clusterName, watcherList] of this.watchers.entries()) { - if (!allClusterNames.has(clusterName)) { - trace('Reporting CDS resource does not exist for clusterName ' + clusterName); - missingNames.push(clusterName); - for (const watcher of watcherList) { - watcher.onResourceDoesNotExist(); - } - } - } - return missingNames; - } - - handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { - const validResponses: Cluster__Output[] = []; - const result: HandleResponseResult = { - accepted: [], - rejected: [], - missing: [] - } - for (const {resource, raw} of responses) { - if (this.validateResponse(resource)) { - validResponses.push(resource); - result.accepted.push({ - name: resource.name, - raw: raw}); - } else { - trace('CDS validation failed for message ' + JSON.stringify(resource)); - result.rejected.push({ - name: resource.name, - raw: raw, - error: `Cluster validation failed for resource ${resource.name}` - }); - } - } - this.latestResponses = validResponses; - this.latestIsV2 = isV2; - const allClusterNames: Set = new Set(); - for (const message of validResponses) { - allClusterNames.add(message.name); - const watchers = this.watchers.get(message.name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message, isV2); - } - } - trace('Received CDS updates for cluster names [' + Array.from(allClusterNames) + ']'); - result.missing = this.handleMissingNames(allClusterNames); - return result; - } - - reportStreamError(status: StatusObject): void { - for (const watcherList of this.watchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - } } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index fe9f3c624..fb2a99485 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -19,7 +19,7 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { isIPv4, isIPv6 } from "net"; import { ClusterLoadAssignment__Output } from "../generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; import { Any__Output } from "../generated/google/protobuf/Any"; -import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; +import { BaseXdsStreamState, HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; const TRACER_NAME = 'xds_client'; @@ -27,83 +27,15 @@ function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } -export class EdsState implements XdsStreamState { - public versionInfo = ''; - public nonce = ''; - - private watchers: Map< - string, - Watcher[] - > = new Map[]>(); - - private latestResponses: ClusterLoadAssignment__Output[] = []; - private latestIsV2 = false; - - constructor(private updateResourceNames: () => void) {} - - /** - * Add the watcher to the watcher list. Returns true if the list of resource - * names has changed, and false otherwise. - * @param edsServiceName - * @param watcher - */ - addWatcher( - edsServiceName: string, - watcher: Watcher - ): void { - let watchersEntry = this.watchers.get(edsServiceName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.watchers.set(edsServiceName, watchersEntry); - } - trace('Adding EDS watcher (' + watchersEntry.length + ' ->' + (watchersEntry.length + 1) + ') for edsServiceName ' + edsServiceName); - watchersEntry.push(watcher); - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - const isV2 = this.latestIsV2; - for (const message of this.latestResponses) { - if (message.cluster_name === edsServiceName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - trace('Reporting existing EDS update for new watcher for edsServiceName ' + edsServiceName); - watcher.onValidUpdate(message, isV2); - }); - } - } - if (addedServiceName) { - this.updateResourceNames(); - } +export class EdsState extends BaseXdsStreamState implements XdsStreamState { + protected getResourceName(resource: ClusterLoadAssignment__Output): string { + return resource.cluster_name; } - - removeWatcher( - edsServiceName: string, - watcher: Watcher - ): void { - trace('Removing EDS watcher for edsServiceName ' + edsServiceName); - const watchersEntry = this.watchers.get(edsServiceName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - trace('Removed EDS watcher (' + watchersEntry.length + ' -> ' + (watchersEntry.length - 1) + ') for edsServiceName ' + edsServiceName); - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.watchers.delete(edsServiceName); - } - } - if (removedServiceName) { - this.updateResourceNames(); - } + protected getProtocolName(): string { + return 'EDS'; } - - getResourceNames(): string[] { - return Array.from(this.watchers.keys()); + protected isStateOfTheWorld(): boolean { + return false; } /** @@ -111,7 +43,7 @@ export class EdsState implements XdsStreamState { * https://github.com/grpc/proposal/blob/master/A27-xds-global-load-balancing.md#clusterloadassignment-proto * @param message */ - private validateResponse(message: ClusterLoadAssignment__Output) { + public validateResponse(message: ClusterLoadAssignment__Output) { for (const endpoint of message.endpoints) { for (const lb of endpoint.lb_endpoints) { const socketAddress = lb.endpoint?.address?.socket_address; @@ -128,48 +60,4 @@ export class EdsState implements XdsStreamState { } return true; } - - handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { - const validResponses: ClusterLoadAssignment__Output[] = []; - let result: HandleResponseResult = { - accepted: [], - rejected: [], - missing: [] - } - for (const {resource, raw} of responses) { - if (this.validateResponse(resource)) { - validResponses.push(resource); - result.accepted.push({ - name: resource.cluster_name, - raw: raw}); - } else { - trace('EDS validation failed for message ' + JSON.stringify(resource)); - result.rejected.push({ - name: resource.cluster_name, - raw: raw, - error: `ClusterLoadAssignment validation failed for resource ${resource.cluster_name}` - }); - } - } - this.latestResponses = validResponses; - this.latestIsV2 = isV2; - const allClusterNames: Set = new Set(); - for (const message of validResponses) { - allClusterNames.add(message.cluster_name); - const watchers = this.watchers.get(message.cluster_name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message, isV2); - } - } - trace('Received EDS updates for cluster names [' + Array.from(allClusterNames) + ']'); - return result; - } - - reportStreamError(status: StatusObject): void { - for (const watcherList of this.watchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - } } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index 7c27c948f..bd5b6423f 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -15,16 +15,13 @@ * */ -import * as protoLoader from '@grpc/proto-loader'; -import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { experimental, logVerbosity } from "@grpc/grpc-js"; import { Listener__Output } from '../generated/envoy/config/listener/v3/Listener'; import { RdsState } from "./rds-state"; -import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; -import { HttpConnectionManager__Output } from '../generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; +import { BaseXdsStreamState, XdsStreamState } from "./xds-stream-state"; import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V2, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from '../resources'; import { getTopLevelFilterUrl, validateTopLevelFilter } from '../http-filter'; import { EXPERIMENTAL_FAULT_INJECTION } from '../environment'; -import { Any__Output } from '../generated/google/protobuf/Any'; const TRACER_NAME = 'xds_client'; @@ -34,69 +31,22 @@ function trace(text: string): void { const ROUTER_FILTER_URL = 'type.googleapis.com/envoy.extensions.filters.http.router.v3.Router'; -export class LdsState implements XdsStreamState { - versionInfo = ''; - nonce = ''; - - private watchers: Map[]> = new Map[]>(); - private latestResponses: Listener__Output[] = []; - private latestIsV2 = false; - - constructor(private rdsState: RdsState, private updateResourceNames: () => void) {} - - addWatcher(targetName: string, watcher: Watcher) { - trace('Adding RDS watcher for targetName ' + targetName); - let watchersEntry = this.watchers.get(targetName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.watchers.set(targetName, watchersEntry); - } - watchersEntry.push(watcher); - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - const isV2 = this.latestIsV2; - for (const message of this.latestResponses) { - if (message.name === targetName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - trace('Reporting existing RDS update for new watcher for targetName ' + targetName); - watcher.onValidUpdate(message, isV2); - }); - } - } - if (addedServiceName) { - this.updateResourceNames(); - } +export class LdsState extends BaseXdsStreamState implements XdsStreamState { + protected getResourceName(resource: Listener__Output): string { + return resource.name; } - - removeWatcher(targetName: string, watcher: Watcher): void { - trace('Removing RDS watcher for targetName ' + targetName); - const watchersEntry = this.watchers.get(targetName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.watchers.delete(targetName); - } - } - if (removedServiceName) { - this.updateResourceNames(); - } + protected getProtocolName(): string { + return 'LDS'; + } + protected isStateOfTheWorld(): boolean { + return true; } - getResourceNames(): string[] { - return Array.from(this.watchers.keys()); + constructor(private rdsState: RdsState, updateResourceNames: () => void) { + super(updateResourceNames); } - private validateResponse(message: Listener__Output, isV2: boolean): boolean { + public validateResponse(message: Listener__Output, isV2: boolean): boolean { if ( !( message.api_listener?.api_listener && @@ -143,63 +93,4 @@ export class LdsState implements XdsStreamState { } return false; } - - private handleMissingNames(allTargetNames: Set): string[] { - const missingNames: string[] = []; - for (const [targetName, watcherList] of this.watchers.entries()) { - if (!allTargetNames.has(targetName)) { - missingNames.push(targetName); - for (const watcher of watcherList) { - watcher.onResourceDoesNotExist(); - } - } - } - return missingNames; - } - - handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { - const validResponses: Listener__Output[] = []; - let result: HandleResponseResult = { - accepted: [], - rejected: [], - missing: [] - } - for (const {resource, raw} of responses) { - if (this.validateResponse(resource, isV2)) { - validResponses.push(resource); - result.accepted.push({ - name: resource.name, - raw: raw - }); - } else { - trace('LDS validation failed for message ' + JSON.stringify(resource)); - result.rejected.push({ - name: resource.name, - raw: raw, - error: `Listener validation failed for resource ${resource.name}` - }); - } - } - this.latestResponses = validResponses; - this.latestIsV2 = isV2; - const allTargetNames = new Set(); - for (const message of validResponses) { - allTargetNames.add(message.name); - const watchers = this.watchers.get(message.name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message, isV2); - } - } - trace('Received LDS response with listener names [' + Array.from(allTargetNames) + ']'); - result.missing = this.handleMissingNames(allTargetNames); - return result; - } - - reportStreamError(status: StatusObject): void { - for (const watcherList of this.watchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - } } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index bc1c4a818..77a84469b 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -15,20 +15,10 @@ * */ -import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { EXPERIMENTAL_FAULT_INJECTION } from "../environment"; import { RouteConfiguration__Output } from "../generated/envoy/config/route/v3/RouteConfiguration"; -import { Any__Output } from "../generated/google/protobuf/Any"; import { validateOverrideFilter } from "../http-filter"; -import { CdsLoadBalancingConfig } from "../load-balancer-cds"; -import { HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; -import ServiceConfig = experimental.ServiceConfig; - -const TRACER_NAME = 'xds_client'; - -function trace(text: string): void { - experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); -} +import { BaseXdsStreamState, XdsStreamState } from "./xds-stream-state"; const SUPPORTED_PATH_SPECIFIERS = ['prefix', 'path', 'safe_regex']; const SUPPPORTED_HEADER_MATCH_SPECIFIERS = [ @@ -40,68 +30,16 @@ const SUPPPORTED_HEADER_MATCH_SPECIFIERS = [ 'suffix_match']; const SUPPORTED_CLUSTER_SPECIFIERS = ['cluster', 'weighted_clusters', 'cluster_header']; -export class RdsState implements XdsStreamState { - versionInfo = ''; - nonce = ''; - - private watchers: Map[]> = new Map[]>(); - private latestResponses: RouteConfiguration__Output[] = []; - private latestIsV2 = false; - - constructor(private updateResourceNames: () => void) {} - - addWatcher(routeConfigName: string, watcher: Watcher) { - trace('Adding RDS watcher for routeConfigName ' + routeConfigName); - let watchersEntry = this.watchers.get(routeConfigName); - let addedServiceName = false; - if (watchersEntry === undefined) { - addedServiceName = true; - watchersEntry = []; - this.watchers.set(routeConfigName, watchersEntry); - } - watchersEntry.push(watcher); - - /* If we have already received an update for the requested edsServiceName, - * immediately pass that update along to the watcher */ - const isV2 = this.latestIsV2; - for (const message of this.latestResponses) { - if (message.name === routeConfigName) { - /* These updates normally occur asynchronously, so we ensure that - * the same happens here */ - process.nextTick(() => { - trace('Reporting existing RDS update for new watcher for routeConfigName ' + routeConfigName); - watcher.onValidUpdate(message, isV2); - }); - } - } - if (addedServiceName) { - this.updateResourceNames(); - } +export class RdsState extends BaseXdsStreamState implements XdsStreamState { + protected isStateOfTheWorld(): boolean { + return false; } - - removeWatcher(routeConfigName: string, watcher: Watcher): void { - trace('Removing RDS watcher for routeConfigName ' + routeConfigName); - const watchersEntry = this.watchers.get(routeConfigName); - let removedServiceName = false; - if (watchersEntry !== undefined) { - const entryIndex = watchersEntry.indexOf(watcher); - if (entryIndex >= 0) { - watchersEntry.splice(entryIndex, 1); - } - if (watchersEntry.length === 0) { - removedServiceName = true; - this.watchers.delete(routeConfigName); - } - } - if (removedServiceName) { - this.updateResourceNames(); - } + protected getResourceName(resource: RouteConfiguration__Output): string { + return resource.name; } - - getResourceNames(): string[] { - return Array.from(this.watchers.keys()); + protected getProtocolName(): string { + return 'RDS'; } - validateResponse(message: RouteConfiguration__Output, isV2: boolean): boolean { // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation for (const virtualHost of message.virtual_hosts) { @@ -172,48 +110,4 @@ export class RdsState implements XdsStreamState { } return true; } - - handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { - const validResponses: RouteConfiguration__Output[] = []; - let result: HandleResponseResult = { - accepted: [], - rejected: [], - missing: [] - } - for (const {resource, raw} of responses) { - if (this.validateResponse(resource, isV2)) { - validResponses.push(resource); - result.accepted.push({ - name: resource.name, - raw: raw}); - } else { - trace('RDS validation failed for message ' + JSON.stringify(resource)); - result.rejected.push({ - name: resource.name, - raw: raw, - error: `Route validation failed for resource ${resource.name}` - }); - } - } - this.latestResponses = validResponses; - this.latestIsV2 = isV2; - const allRouteConfigNames = new Set(); - for (const message of validResponses) { - allRouteConfigNames.add(message.name); - const watchers = this.watchers.get(message.name) ?? []; - for (const watcher of watchers) { - watcher.onValidUpdate(message, isV2); - } - } - trace('Received RDS response with route config names [' + Array.from(allRouteConfigNames) + ']'); - return result; - } - - reportStreamError(status: StatusObject): void { - for (const watcherList of this.watchers.values()) { - for (const watcher of watcherList) { - watcher.onTransientError(status); - } - } - } } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index c8cbc41cf..2ff5130c4 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -15,9 +15,11 @@ * */ -import { StatusObject } from "@grpc/grpc-js"; +import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { Any__Output } from "../generated/google/protobuf/Any"; +const TRACER_NAME = 'xds_client'; + export interface Watcher { /* Including the isV2 flag here is a bit of a kludge. It would probably be * better for XdsStreamState#handleResponses to transform the protobuf @@ -63,4 +65,189 @@ export interface XdsStreamState { handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult; reportStreamError(status: StatusObject): void; + reportAdsStreamStart(): void; + + addWatcher(name: string, watcher: Watcher): void; + removeWatcher(resourceName: string, watcher: Watcher): void; +} + +interface SubscriptionEntry { + watchers: Watcher[]; + cachedResponse: ResponseType | null; + resourceTimer: NodeJS.Timer; +} + +const RESOURCE_TIMEOUT_MS = 15_000; + +export abstract class BaseXdsStreamState implements XdsStreamState { + versionInfo = ''; + nonce = ''; + + private subscriptions: Map> = new Map>(); + private latestIsV2 = false; + private isAdsStreamRunning = false; + + constructor(private updateResourceNames: () => void) {} + + protected trace(text: string) { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, this.getProtocolName() + ' | ' + text); + } + + private startResourceTimer(subscriptionEntry: SubscriptionEntry) { + clearTimeout(subscriptionEntry.resourceTimer); + subscriptionEntry.resourceTimer = setTimeout(() => { + for (const watcher of subscriptionEntry.watchers) { + watcher.onResourceDoesNotExist(); + } + }, RESOURCE_TIMEOUT_MS); + } + + addWatcher(name: string, watcher: Watcher): void { + this.trace('Adding watcher for name ' + name); + let subscriptionEntry = this.subscriptions.get(name); + let addedName = false; + if (subscriptionEntry === undefined) { + addedName = true; + subscriptionEntry = { + watchers: [], + cachedResponse: null, + resourceTimer: setTimeout(() => {}, 0) + }; + this.startResourceTimer(subscriptionEntry); + this.subscriptions.set(name, subscriptionEntry); + } + subscriptionEntry.watchers.push(watcher); + if (subscriptionEntry.cachedResponse !== null) { + const cachedResponse = subscriptionEntry.cachedResponse; + /* These updates normally occur asynchronously, so we ensure that + * the same happens here */ + process.nextTick(() => { + this.trace('Reporting existing update for new watcher for name ' + name); + watcher.onValidUpdate(cachedResponse, this.latestIsV2); + }); + } + if (addedName) { + this.updateResourceNames(); + } + } + removeWatcher(resourceName: string, watcher: Watcher): void { + this.trace('Removing watcher for name ' + resourceName); + const subscriptionEntry = this.subscriptions.get(resourceName); + if (subscriptionEntry !== undefined) { + const entryIndex = subscriptionEntry.watchers.indexOf(watcher); + if (entryIndex >= 0) { + subscriptionEntry.watchers.splice(entryIndex, 1); + } + if (subscriptionEntry.watchers.length === 0) { + clearTimeout(subscriptionEntry.resourceTimer); + this.subscriptions.delete(resourceName); + this.updateResourceNames(); + } + } + } + + getResourceNames(): string[] { + return Array.from(this.subscriptions.keys()); + } + handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { + const validResponses: ResponseType[] = []; + let result: HandleResponseResult = { + accepted: [], + rejected: [], + missing: [] + } + for (const {resource, raw} of responses) { + const resourceName = this.getResourceName(resource); + if (this.validateResponse(resource, isV2)) { + validResponses.push(resource); + result.accepted.push({ + name: resourceName, + raw: raw}); + } else { + this.trace('Validation failed for message ' + JSON.stringify(resource)); + result.rejected.push({ + name: resourceName, + raw: raw, + error: `Validation failed for resource ${resourceName}` + }); + } + } + this.latestIsV2 = isV2; + const allResourceNames = new Set(); + for (const resource of validResponses) { + const resourceName = this.getResourceName(resource); + allResourceNames.add(resourceName); + const subscriptionEntry = this.subscriptions.get(resourceName); + if (subscriptionEntry) { + const watchers = subscriptionEntry.watchers; + for (const watcher of watchers) { + watcher.onValidUpdate(resource, isV2); + } + clearTimeout(subscriptionEntry.resourceTimer); + subscriptionEntry.cachedResponse = resource; + } + } + result.missing = this.handleMissingNames(allResourceNames); + this.trace('Received response with resource names [' + Array.from(allResourceNames) + ']'); + return result; + } + reportStreamError(status: StatusObject): void { + for (const subscriptionEntry of this.subscriptions.values()) { + for (const watcher of subscriptionEntry.watchers) { + watcher.onTransientError(status); + } + clearTimeout(subscriptionEntry.resourceTimer); + } + this.isAdsStreamRunning = false; + } + + reportAdsStreamStart() { + this.isAdsStreamRunning = true; + for (const subscriptionEntry of this.subscriptions.values()) { + if (subscriptionEntry.cachedResponse === null) { + this.startResourceTimer(subscriptionEntry); + } + } + } + + private handleMissingNames(allResponseNames: Set): string[] { + if (this.isStateOfTheWorld()) { + const missingNames: string[] = []; + for (const [resourceName, subscriptionEntry] of this.subscriptions.entries()) { + if (!allResponseNames.has(resourceName) && subscriptionEntry.cachedResponse !== null) { + this.trace('Reporting resource does not exist named ' + resourceName); + missingNames.push(resourceName); + for (const watcher of subscriptionEntry.watchers) { + watcher.onResourceDoesNotExist(); + } + } + } + return missingNames; + } else { + return []; + } + } + + /** + * Apply the validation rules for this resource type to this resource + * instance. + * This function is public so that the LDS validateResponse can call into + * the RDS validateResponse. + * @param resource The resource object sent by the xDS server + * @param isV2 If true, the resource is an xDS V2 resource instead of xDS V3 + */ + public abstract validateResponse(resource: ResponseType, isV2: boolean): boolean; + /** + * Get the name of a resource object. The name is some field of the object, so + * getting it depends on the specific type. + * @param resource + */ + protected abstract getResourceName(resource: ResponseType): string; + protected abstract getProtocolName(): string; + /** + * Indicates whether responses are "state of the world", i.e. that they + * contain all resources and that omitted previously-seen resources should + * be treated as removed. + */ + protected abstract isStateOfTheWorld(): boolean; } \ No newline at end of file From a041056e712975e8ded07d032512ee70063c8cb1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 May 2022 17:19:46 -0700 Subject: [PATCH 1675/1899] Borrow Linux test job for xDS tests --- test/kokoro/linux.cfg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index 63f88d399..c13d03f35 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -14,10 +14,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/test/kokoro.sh" -timeout_mins: 60 +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" +timeout_mins: 360 action { define_artifacts { - regex: "github/grpc-node/reports/**/sponge_log.xml" + regex: "github/grpc/reports/**" } -} \ No newline at end of file +} From 65075e50a742c04d4544252f55a2f24471e45e31 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 May 2022 17:34:25 -0700 Subject: [PATCH 1676/1899] Only start the timer if the ADS stream is running --- packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 2ff5130c4..1d96728a2 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -113,7 +113,9 @@ export abstract class BaseXdsStreamState implements XdsStreamState cachedResponse: null, resourceTimer: setTimeout(() => {}, 0) }; - this.startResourceTimer(subscriptionEntry); + if (this.isAdsStreamRunning) { + this.startResourceTimer(subscriptionEntry); + } this.subscriptions.set(name, subscriptionEntry); } subscriptionEntry.watchers.push(watcher); From 9035327af12c989933946047f7125e4d636b6611 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 May 2022 17:38:28 -0700 Subject: [PATCH 1677/1899] Clear the nonce when the stream ends --- packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 1d96728a2..0b806f843 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -201,6 +201,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState clearTimeout(subscriptionEntry.resourceTimer); } this.isAdsStreamRunning = false; + this.nonce = ''; } reportAdsStreamStart() { From 9502f5265de4c1ebc5aeb4bd4eb8c9c6ca829ded Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 13 May 2022 09:48:36 -0700 Subject: [PATCH 1678/1899] Revert "Borrow Linux test job for xDS tests" This reverts commit a041056e712975e8ded07d032512ee70063c8cb1. --- test/kokoro/linux.cfg | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/kokoro/linux.cfg b/test/kokoro/linux.cfg index c13d03f35..63f88d399 100644 --- a/test/kokoro/linux.cfg +++ b/test/kokoro/linux.cfg @@ -14,10 +14,10 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 360 +build_file: "grpc-node/test/kokoro.sh" +timeout_mins: 60 action { define_artifacts { - regex: "github/grpc/reports/**" + regex: "github/grpc-node/reports/**/sponge_log.xml" } -} +} \ No newline at end of file From 0a0e13eedecedb31e91ad2d250c5fca6f31e46b6 Mon Sep 17 00:00:00 2001 From: Bart Slinger Date: Thu, 19 May 2022 23:45:11 +0200 Subject: [PATCH 1679/1899] handle disconnectListeners in reverse to allow listener removal in loop --- packages/grpc-js/src/subchannel.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 5d479a73a..eb7d0840c 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -646,7 +646,8 @@ export class Subchannel { this.transitionToState( [ConnectivityState.READY], ConnectivityState.TRANSIENT_FAILURE); - for (const listener of this.disconnectListeners) { + for (let i = this.disconnectListeners.length - 1; i >= 0; i--) { + const listener = this.disconnectListeners[i]; listener(); } } From 97717003f4dce64c64748517cff4a2077484ba04 Mon Sep 17 00:00:00 2001 From: Bart Slinger Date: Fri, 20 May 2022 08:27:01 +0200 Subject: [PATCH 1680/1899] grpc-js: Use Set instead of Array for disconnectListeners --- packages/grpc-js/src/subchannel.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index eb7d0840c..4d18ca9ca 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -108,7 +108,7 @@ export class Subchannel { * socket disconnects. Used for ending active calls with an UNAVAILABLE * status. */ - private disconnectListeners: Array<() => void> = []; + private disconnectListeners: Set<() => void> = new Set(); private backoffTimeout: BackoffTimeout; @@ -646,8 +646,7 @@ export class Subchannel { this.transitionToState( [ConnectivityState.READY], ConnectivityState.TRANSIENT_FAILURE); - for (let i = this.disconnectListeners.length - 1; i >= 0; i--) { - const listener = this.disconnectListeners[i]; + for (const listener of this.disconnectListeners.values()) { listener(); } } @@ -972,14 +971,11 @@ export class Subchannel { } addDisconnectListener(listener: () => void) { - this.disconnectListeners.push(listener); + this.disconnectListeners.add(listener); } removeDisconnectListener(listener: () => void) { - const listenerIndex = this.disconnectListeners.indexOf(listener); - if (listenerIndex > -1) { - this.disconnectListeners.splice(listenerIndex, 1); - } + this.disconnectListeners.delete(listener); } /** From aa97aa8a1c3e936be6fa4938f6467e044bc66ec6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 May 2022 11:28:39 -0700 Subject: [PATCH 1681/1899] grpc-js-xds: Add support for k8s interop test framework --- packages/grpc-js-xds/interop/Dockerfile | 30 ++++ packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 166 +++++++++++++++++++++ test/kokoro/xds_k8s_lb.cfg | 26 ++++ 3 files changed, 222 insertions(+) create mode 100644 packages/grpc-js-xds/interop/Dockerfile create mode 100755 packages/grpc-js-xds/scripts/xds_k8s_lb.sh create mode 100644 test/kokoro/xds_k8s_lb.cfg diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile new file mode 100644 index 000000000..dbb4433b3 --- /dev/null +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -0,0 +1,30 @@ +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Dockerfile for building the xDS interop client. To build the image, run the +# following command from grpc-node directory: +# docker build -t -f packages/grpc-js-xds/interop/Dockerfile . + +FROM node:16-alpine + +# Make a grpc-node directory and copy the repo into it. +WORKDIR /node/src/grpc-node +COPY . . + +WORKDIR /node/src/grpc-node/packages/grpc-js +RUN npm install +WORKDIR /node/src/grpc-node/packages/grpc-js-xds +RUN npm install + +ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh new file mode 100755 index 000000000..7672251d6 --- /dev/null +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -0,0 +1,166 @@ +#!/usr/bin/env bash +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +# Constants +readonly GITHUB_REPOSITORY_NAME="grpc-node" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +## xDS test client Docker images +readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/java-server:v1.46.x" +readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" +readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" +readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" +readonly LANGUAGE_NAME="Node" + +####################################### +# Builds test app Docker images and pushes them to GCR +# Globals: +# BUILD_APP_PATH +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# Arguments: +# None +# Outputs: +# Writes the output of `gcloud builds submit` to stdout, stderr +####################################### +build_test_app_docker_images() { + echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images" + + pushd "${SRC_DIR}" + docker build \ + -f "${BUILD_APP_PATH}" \ + -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + . + + popd + + gcloud -q auth configure-docker + + docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" +} + +####################################### +# Builds test app and its docker images unless they already exist +# Globals: +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# FORCE_IMAGE_BUILD +# Arguments: +# None +# Outputs: +# Writes the output to stdout, stderr +####################################### +build_docker_images_if_needed() { + # Check if images already exist + client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")" + printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" + echo "${client_tags:-Client image not found}" + + # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1 + if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then + build_test_app_docker_images + else + echo "Skipping ${LANGUAGE_NAME} test app build" + fi +} + +####################################### +# Executes the test case +# Globals: +# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile +# KUBE_CONTEXT: The name of kubectl context with GKE cluster access +# SECONDARY_KUBE_CONTEXT: The name of kubectl context with secondary GKE cluster access, if any +# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# Arguments: +# Test case name +# Outputs: +# Writes the output of test execution to stdout, stderr +# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml +####################################### +run_test() { + # Test driver usage: + # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage + local test_name="${1:?Usage: run_test test_name}" + # testing_version is used by the framework to determine the supported PSM + # features. It's captured from Kokoro job name of the Node repo, which takes + # the form: + # grpc/node// + python3 -m "tests.${test_name}" \ + --flagfile="${TEST_DRIVER_FLAGFILE}" \ + --kube_context="${KUBE_CONTEXT}" \ + --secondary_kube_context="${SECONDARY_KUBE_CONTEXT}" \ + --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + --server_image="${SERVER_IMAGE_NAME}" \ + --testing_version=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/node/([^/]+)/.*|\1|') \ + --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" +} + +####################################### +# Main function: provision software necessary to execute tests, and run them +# Globals: +# KOKORO_ARTIFACTS_DIR +# GITHUB_REPOSITORY_NAME +# SRC_DIR: Populated with absolute path to the source repo +# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing +# the test driver +# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code +# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile +# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report +# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build +# GIT_COMMIT: Populated with the SHA-1 of git commit being built +# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built +# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access +# SECONDARY_KUBE_CONTEXT: Populated with name of kubectl context with secondary GKE cluster access, if any +# Arguments: +# None +# Outputs: +# Writes the output of test execution to stdout, stderr +####################################### +main() { + local script_dir + script_dir="$(dirname "$0")" + + # Source the test driver from the master branch. + echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" + source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" + + activate_gke_cluster GKE_CLUSTER_PSM_SECURITY + activate_secondary_gke_cluster GKE_CLUSTER_PSM_SECURITY + + set -x + if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then + kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}" + else + local_setup_test_driver "${script_dir}" + fi + build_docker_images_if_needed + + # Run tests + cd "${TEST_DRIVER_FULL_DIR}" + local failed_tests=0 + test_suites=("api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test") + for test in "${test_suites[@]}"; do + run_test $test || (( failed_tests++ )) + done + echo "Failed test suites: ${failed_tests}" + if (( failed_tests > 0 )); then + exit 1 + fi +} + +main "$@" \ No newline at end of file diff --git a/test/kokoro/xds_k8s_lb.cfg b/test/kokoro/xds_k8s_lb.cfg new file mode 100644 index 000000000..17a3f3b3b --- /dev/null +++ b/test/kokoro/xds_k8s_lb.cfg @@ -0,0 +1,26 @@ +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds_k8s_lb.sh" +timeout_mins: 180 +action { + define_artifacts { + regex: "artifacts/**/*sponge_log.xml" + regex: "artifacts/**/*sponge_log.log" + strip_prefix: "artifacts" + } +} \ No newline at end of file From ce169c22b483a27e776e003d7630b158bd0cc7f7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 May 2022 15:59:01 -0700 Subject: [PATCH 1682/1899] Reduce docker image size with extra build step --- packages/grpc-js-xds/interop/Dockerfile | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index dbb4433b3..bc85d3b21 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -16,7 +16,7 @@ # following command from grpc-node directory: # docker build -t -f packages/grpc-js-xds/interop/Dockerfile . -FROM node:16-alpine +FROM node:16-alpine as build # Make a grpc-node directory and copy the repo into it. WORKDIR /node/src/grpc-node @@ -27,4 +27,9 @@ RUN npm install WORKDIR /node/src/grpc-node/packages/grpc-js-xds RUN npm install +FROM node:16-alpine +WORKDIR /node/src/grpc-node +COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ +COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ + ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] From 30bf5a1bac096d4eebeb0b848ede389bff27e226 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 May 2022 16:19:07 -0700 Subject: [PATCH 1683/1899] Fix cluster references Co-authored-by: Sergii Tkachenko --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 7672251d6..8ec1760a1 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -139,8 +139,8 @@ main() { echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" - activate_gke_cluster GKE_CLUSTER_PSM_SECURITY - activate_secondary_gke_cluster GKE_CLUSTER_PSM_SECURITY + activate_gke_cluster GKE_CLUSTER_PSM_LB + activate_secondary_gke_cluster GKE_CLUSTER_PSM_LB set -x if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then From 55175ae8c281307e05f147987822aedf5b4d85ee Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 May 2022 16:21:27 -0700 Subject: [PATCH 1684/1899] Add missing newlines at EOF --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- test/kokoro/xds_k8s_lb.cfg | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 8ec1760a1..9cf98d2fc 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -163,4 +163,4 @@ main() { fi } -main "$@" \ No newline at end of file +main "$@" diff --git a/test/kokoro/xds_k8s_lb.cfg b/test/kokoro/xds_k8s_lb.cfg index 17a3f3b3b..b9940cfdc 100644 --- a/test/kokoro/xds_k8s_lb.cfg +++ b/test/kokoro/xds_k8s_lb.cfg @@ -23,4 +23,4 @@ action { regex: "artifacts/**/*sponge_log.log" strip_prefix: "artifacts" } -} \ No newline at end of file +} From bbcf471c99512a178f74e9de7d9dcee363649507 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 May 2022 16:30:18 -0700 Subject: [PATCH 1685/1899] grpc-js: Specify 'types' option in tsconfig file --- packages/grpc-js/tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index ba675db78..310b633c7 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -6,7 +6,8 @@ "target": "es2017", "module": "commonjs", "resolveJsonModule": true, - "incremental": true + "incremental": true, + "types": ["mocha"] }, "include": [ "src/**/*.ts", From 67cfbae7aac90c3e60320f72c14dc4ec2985cd14 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 May 2022 16:46:51 -0700 Subject: [PATCH 1686/1899] Use cd instead of WORKDIR in Dockerfile Co-authored-by: Sergii Tkachenko --- packages/grpc-js-xds/interop/Dockerfile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index bc85d3b21..b18d02a4a 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -22,10 +22,8 @@ FROM node:16-alpine as build WORKDIR /node/src/grpc-node COPY . . -WORKDIR /node/src/grpc-node/packages/grpc-js -RUN npm install -WORKDIR /node/src/grpc-node/packages/grpc-js-xds -RUN npm install +RUN cd packages/grpc-js && npm install +RUN cd packages/grpc-js-xds && npm install FROM node:16-alpine WORKDIR /node/src/grpc-node From ad6d650408f4650c6e7c897c02ae4bf7bc3fddb1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 May 2022 09:41:05 -0700 Subject: [PATCH 1687/1899] Revert "Use cd instead of WORKDIR in Dockerfile" --- packages/grpc-js-xds/interop/Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index b18d02a4a..bc85d3b21 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -22,8 +22,10 @@ FROM node:16-alpine as build WORKDIR /node/src/grpc-node COPY . . -RUN cd packages/grpc-js && npm install -RUN cd packages/grpc-js-xds && npm install +WORKDIR /node/src/grpc-node/packages/grpc-js +RUN npm install +WORKDIR /node/src/grpc-node/packages/grpc-js-xds +RUN npm install FROM node:16-alpine WORKDIR /node/src/grpc-node From ee0c6bc9eaa80e43c82f44e40566b038cb49fd24 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 May 2022 10:35:55 -0700 Subject: [PATCH 1688/1899] Add baseline_test to test list --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 9cf98d2fc..efdde91e7 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -153,7 +153,7 @@ main() { # Run tests cd "${TEST_DRIVER_FULL_DIR}" local failed_tests=0 - test_suites=("api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test") + test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test") for test in "${test_suites[@]}"; do run_test $test || (( failed_tests++ )) done From be749bf94f96a03ec5e3bf0aabed2566f5c79f31 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 May 2022 11:14:26 -0700 Subject: [PATCH 1689/1899] Update submodules in test script --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index efdde91e7..0ff34ac4b 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -135,6 +135,8 @@ main() { local script_dir script_dir="$(dirname "$0")" + git submodule update --init --recursive + # Source the test driver from the master branch. echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" From e61c8f9ecd2c20a1baaeaf284aa813bc8e66473c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 24 May 2022 13:11:41 -0700 Subject: [PATCH 1690/1899] Change directory before submodules update --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 0ff34ac4b..b4c9f81a2 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -135,6 +135,8 @@ main() { local script_dir script_dir="$(dirname "$0")" + cd "${script_dir}" + git submodule update --init --recursive # Source the test driver from the master branch. From e94bd36bf15d75fb3e49f52eeddadc371702b90e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Conall=20=C3=93=20Cofaigh?= Date: Mon, 30 May 2022 13:54:05 +0100 Subject: [PATCH 1691/1899] bump protobufjs to "^6.11.3" --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 759e54713..53b6e829d 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -48,7 +48,7 @@ "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^4.0.0", - "protobufjs": "^6.10.0", + "protobufjs": "^6.11.3", "yargs": "^16.2.0" }, "devDependencies": { From b78db9d2225a391e23a0e6cefd2b85f919e708f1 Mon Sep 17 00:00:00 2001 From: Andrew Matheny Date: Wed, 1 Jun 2022 12:33:31 -0400 Subject: [PATCH 1692/1899] Propagate callEnd events --- packages/grpc-js/src/server-call.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 315c9d9aa..725199e3a 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -726,6 +726,8 @@ export class Http2ServerCallStream< call.cancelled = true; call.emit('cancelled', reason); }); + + this.once('callEnd', (status) => call.emit('callEnd', status)); } setupReadable( From d846cf51272f2ed03c1dd8b845536fa7a901f396 Mon Sep 17 00:00:00 2001 From: Andrew Matheny Date: Wed, 1 Jun 2022 12:34:11 -0400 Subject: [PATCH 1693/1899] Expose http path in call --- packages/grpc-js/src/server-call.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 725199e3a..1f7f3eb04 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -80,6 +80,7 @@ export type ServerSurfaceCall = { getPeer(): string; sendMetadata(responseMetadata: Metadata): void; getDeadline(): Deadline; + getPath(): string; } & EventEmitter; export type ServerUnaryCall = ServerSurfaceCall & { @@ -127,6 +128,10 @@ export class ServerUnaryCallImpl getDeadline(): Deadline { return this.call.getDeadline(); } + + getPath(): string { + return this.call.getPath(); + } } export class ServerReadableStreamImpl @@ -165,6 +170,10 @@ export class ServerReadableStreamImpl getDeadline(): Deadline { return this.call.getDeadline(); } + + getPath(): string { + return this.call.getPath(); + } } export class ServerWritableStreamImpl @@ -202,6 +211,10 @@ export class ServerWritableStreamImpl return this.call.getDeadline(); } + getPath(): string { + return this.call.getPath(); + } + _write( chunk: ResponseType, encoding: string, @@ -279,6 +292,10 @@ export class ServerDuplexStreamImpl return this.call.getDeadline(); } + getPath(): string { + return this.call.getPath(); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any end(metadata?: any) { if (metadata) { @@ -901,6 +918,10 @@ export class Http2ServerCallStream< getDeadline(): Deadline { return this.deadline; } + + getPath(): string { + return this.handler.path; + } } /* eslint-disable @typescript-eslint/no-explicit-any */ From 475559f976088deae1c3d8a512fd9c57425ddba3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Jun 2022 14:08:13 -0700 Subject: [PATCH 1694/1899] proto-loader: Increment version to 0.6.13 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 53b6e829d..65639c501 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.12", + "version": "0.6.13", "author": "Google Inc.", "contributors": [ { From 07b73ad129e0368dfa95fab531d45ab754b9844b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Jun 2022 11:07:47 -0700 Subject: [PATCH 1695/1899] grpc-js: Add a test for compressing large messages --- .../grpc-js/test/fixtures/test_service.proto | 1 + packages/grpc-js/test/generated/Response.ts | 2 ++ .../grpc-js/test/generated/TestService.ts | 32 +++++++++---------- packages/grpc-js/test/test-server.ts | 16 +++++++++- 4 files changed, 34 insertions(+), 17 deletions(-) diff --git a/packages/grpc-js/test/fixtures/test_service.proto b/packages/grpc-js/test/fixtures/test_service.proto index f99393d14..64ce0d378 100644 --- a/packages/grpc-js/test/fixtures/test_service.proto +++ b/packages/grpc-js/test/fixtures/test_service.proto @@ -25,6 +25,7 @@ message Request { message Response { int32 count = 1; + string message = 2; } service TestService { diff --git a/packages/grpc-js/test/generated/Response.ts b/packages/grpc-js/test/generated/Response.ts index 217fc75e8..465ab7203 100644 --- a/packages/grpc-js/test/generated/Response.ts +++ b/packages/grpc-js/test/generated/Response.ts @@ -3,8 +3,10 @@ export interface Response { 'count'?: (number); + 'message'?: (string); } export interface Response__Output { 'count': (number); + 'message': (string); } diff --git a/packages/grpc-js/test/generated/TestService.ts b/packages/grpc-js/test/generated/TestService.ts index 75bff33e4..e477c99b5 100644 --- a/packages/grpc-js/test/generated/TestService.ts +++ b/packages/grpc-js/test/generated/TestService.ts @@ -11,28 +11,28 @@ export interface TestServiceClient extends grpc.Client { bidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_Request, _Response__Output>; bidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_Request, _Response__Output>; - ClientStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - ClientStream(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - ClientStream(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - ClientStream(callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - clientStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - clientStream(metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - clientStream(options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; - clientStream(callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientWritableStream<_Request>; + ClientStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + ClientStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + ClientStream(options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + ClientStream(callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + clientStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + clientStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + clientStream(options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; + clientStream(callback: grpc.requestCallback<_Response__Output>): grpc.ClientWritableStream<_Request>; ServerStream(argument: _Request, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; ServerStream(argument: _Request, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; serverStream(argument: _Request, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; serverStream(argument: _Request, options?: grpc.CallOptions): grpc.ClientReadableStream<_Response__Output>; - Unary(argument: _Request, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - Unary(argument: _Request, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - Unary(argument: _Request, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - Unary(argument: _Request, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - unary(argument: _Request, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - unary(argument: _Request, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - unary(argument: _Request, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; - unary(argument: _Request, callback: (error?: grpc.ServiceError, result?: _Response__Output) => void): grpc.ClientUnaryCall; + Unary(argument: _Request, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + Unary(argument: _Request, metadata: grpc.Metadata, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + Unary(argument: _Request, options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + Unary(argument: _Request, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + unary(argument: _Request, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + unary(argument: _Request, metadata: grpc.Metadata, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + unary(argument: _Request, options: grpc.CallOptions, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; + unary(argument: _Request, callback: grpc.requestCallback<_Response__Output>): grpc.ClientUnaryCall; } diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 2513b1fe2..0c0ba168e 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -623,7 +623,7 @@ describe('Generic client and server', () => { describe('Compressed requests', () => { const testServiceHandlers: TestServiceHandlers = { Unary(call, callback) { - callback(null, { count: 500000 }); + callback(null, { count: 500000, message: call.request.message }); }, ClientStream(call, callback) { @@ -847,6 +847,20 @@ describe('Compressed requests', () => { }) }); }); + + it('Should handle large messages', done => { + let longMessage = ''; + for (let i = 0; i < 400000; i++) { + const letter = 'abcdefghijklmnopqrstuvwxyz'[Math.floor(Math.random() * 26)]; + longMessage = longMessage + letter.repeat(10); + } + + client.unary({message: longMessage}, (err, response) => { + assert.ifError(err); + assert.strictEqual(response?.message, longMessage); + done(); + }) + }) /* As of Node 16, Writable and Duplex streams validate the encoding * argument to write, and the flags values we are passing there are not From 0c543aa2b27f9ea2890bbe3d7cb88c696412225d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 15 Jun 2022 10:09:53 -0700 Subject: [PATCH 1696/1899] xDS k8s interop script: publish version-tagged docker images --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index b4c9f81a2..0d333b7ee 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -45,6 +45,11 @@ build_test_app_docker_images() { -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . + if [[ -n $KOKORO_JOB_NAME ]]; then + branch_name=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/node/([^/]+)/.*|\1|') + tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${branch_name}" + fi + popd gcloud -q auth configure-docker From e4435a50f6c857dfd8edbade4856c172b8856617 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Jun 2022 15:51:03 -0700 Subject: [PATCH 1697/1899] Use new TESTING_VERSION variable --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 0d333b7ee..58a951376 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -45,9 +45,8 @@ build_test_app_docker_images() { -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . - if [[ -n $KOKORO_JOB_NAME ]]; then - branch_name=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/node/([^/]+)/.*|\1|') - tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${branch_name}" + if is_version_branch "${TESTING_VERSION}"; then + tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" fi popd @@ -111,7 +110,7 @@ run_test() { --secondary_kube_context="${SECONDARY_KUBE_CONTEXT}" \ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ --server_image="${SERVER_IMAGE_NAME}" \ - --testing_version=$(echo "$KOKORO_JOB_NAME" | sed -E 's|^grpc/node/([^/]+)/.*|\1|') \ + --testing_version="${TESTING_VERSION}" \ --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" } From 92cf5df8d57431a6eca94a6bec057363b29a8182 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jun 2022 14:33:15 -0700 Subject: [PATCH 1698/1899] Add xDS k8s url_map test script --- .../grpc-js-xds/scripts/xds_k8s_url_map.sh | 152 ++++++++++++++++++ test/kokoro/xds_k8s_url_map.cfg | 26 +++ 2 files changed, 178 insertions(+) create mode 100644 packages/grpc-js-xds/scripts/xds_k8s_url_map.sh create mode 100644 test/kokoro/xds_k8s_url_map.cfg diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh new file mode 100644 index 000000000..ca33cf0d2 --- /dev/null +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -0,0 +1,152 @@ +#!/usr/bin/env bash +# Copyright 2021 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +# Constants +readonly GITHUB_REPOSITORY_NAME="grpc-node" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +## xDS test client Docker images +readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" +readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" +readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" +readonly LANGUAGE_NAME="Node" + +####################################### +# Builds test app Docker images and pushes them to GCR +# Globals: +# BUILD_APP_PATH +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# Arguments: +# None +# Outputs: +# Writes the output of `gcloud builds submit` to stdout, stderr +####################################### +build_test_app_docker_images() { + echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images" + + pushd "${SRC_DIR}" + docker build \ + -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \ + -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + . + + popd + + gcloud -q auth configure-docker + + docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" +} + +####################################### +# Builds test app and its docker images unless they already exist +# Globals: +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# FORCE_IMAGE_BUILD +# Arguments: +# None +# Outputs: +# Writes the output to stdout, stderr +####################################### +build_docker_images_if_needed() { + # Check if images already exist + client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")" + printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" + echo "${client_tags:-Client image not found}" + + # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1 + if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then + build_test_app_docker_images + else + echo "Skipping ${LANGUAGE_NAME} test app build" + fi +} + +####################################### +# Executes the test case +# Globals: +# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile +# KUBE_CONTEXT: The name of kubectl context with GKE cluster access +# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# TESTING_VERSION: version branch under test: used by the framework to determine the supported PSM +# features. +# Arguments: +# Test case name +# Outputs: +# Writes the output of test execution to stdout, stderr +# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml +####################################### +run_test() { + # Test driver usage: + # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage + local test_name="${1:?Usage: run_test test_name}" + set -x + python3 -m "tests.${test_name}" \ + --flagfile="${TEST_DRIVER_FLAGFILE}" \ + --kube_context="${KUBE_CONTEXT}" \ + --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + --testing_version="${TESTING_VERSION}" \ + --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \ + --flagfile="config/url-map.cfg" + set +x +} + +####################################### +# Main function: provision software necessary to execute tests, and run them +# Globals: +# KOKORO_ARTIFACTS_DIR +# GITHUB_REPOSITORY_NAME +# SRC_DIR: Populated with absolute path to the source repo +# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing +# the test driver +# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code +# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile +# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report +# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build +# GIT_COMMIT: Populated with the SHA-1 of git commit being built +# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built +# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access +# Arguments: +# None +# Outputs: +# Writes the output of test execution to stdout, stderr +####################################### +main() { + local script_dir + script_dir="$(dirname "$0")" + + # Source the test driver from the master branch. + echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" + source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" + + activate_gke_cluster GKE_CLUSTER_PSM_BASIC + + set -x + if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then + kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}" + else + local_setup_test_driver "${script_dir}" + fi + build_docker_images_if_needed + # Run tests + cd "${TEST_DRIVER_FULL_DIR}" + run_test url_map +} + +main "$@" diff --git a/test/kokoro/xds_k8s_url_map.cfg b/test/kokoro/xds_k8s_url_map.cfg new file mode 100644 index 000000000..dd4cce76d --- /dev/null +++ b/test/kokoro/xds_k8s_url_map.cfg @@ -0,0 +1,26 @@ +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh" +timeout_mins: 180 +action { + define_artifacts { + regex: "artifacts/**/*sponge_log.xml" + regex: "artifacts/**/*sponge_log.log" + strip_prefix: "artifacts" + } +} From 47461134fb1a282517e8c2717f3e98c26488f229 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Jun 2022 15:28:22 -0700 Subject: [PATCH 1699/1899] Update copyright date --- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index ca33cf0d2..901938ad2 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright 2021 gRPC authors. +# Copyright 2022 gRPC authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From 1ad6a58059b6637a408b836d8ad591135e859d3d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Jun 2022 10:20:01 -0700 Subject: [PATCH 1700/1899] xDS k8s tests: fix a line in the url_map test script The line copied from the Python script was hardcoded and not handled by a variable, so I did not change it on the first pass. --- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index 901938ad2..bf2d4df67 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -40,7 +40,7 @@ build_test_app_docker_images() { pushd "${SRC_DIR}" docker build \ - -f src/python/grpcio_tests/tests_py3_only/interop/Dockerfile.client \ + -f ${BUILD_APP_PATH} \ -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . From 5a039aa90b743919782cd64d349830ce46162f82 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Jun 2022 15:29:52 -0700 Subject: [PATCH 1701/1899] Use quotation marks for variable substitution Co-authored-by: Sergii Tkachenko --- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index bf2d4df67..8b07b655e 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -40,7 +40,7 @@ build_test_app_docker_images() { pushd "${SRC_DIR}" docker build \ - -f ${BUILD_APP_PATH} \ + -f "${BUILD_APP_PATH}" \ -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . From 4db0cd2ac995efe08185f6b825b2aa641441dc57 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 24 Jun 2022 16:08:59 -0700 Subject: [PATCH 1702/1899] xDS k8s tests: fix docker auth error in the build scripts Docker auth needed to be done before pushing thats to the GCR. Also add missing versioned image tagging to xds_k8s_url_map.sh. --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 8 +++----- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 8 +++++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 58a951376..ca300f0c2 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -31,6 +31,7 @@ readonly LANGUAGE_NAME="Node" # BUILD_APP_PATH # CLIENT_IMAGE_NAME: Test client Docker image name # GIT_COMMIT: SHA-1 of git commit being built +# TESTING_VERSION: version branch under test, f.e. v1.42.x, master # Arguments: # None # Outputs: @@ -45,15 +46,12 @@ build_test_app_docker_images() { -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . + gcloud -q auth configure-docker + docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" if is_version_branch "${TESTING_VERSION}"; then tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" fi - popd - - gcloud -q auth configure-docker - - docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" } ####################################### diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index 901938ad2..a865e4e5b 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -30,6 +30,7 @@ readonly LANGUAGE_NAME="Node" # BUILD_APP_PATH # CLIENT_IMAGE_NAME: Test client Docker image name # GIT_COMMIT: SHA-1 of git commit being built +# TESTING_VERSION: version branch under test, f.e. v1.42.x, master # Arguments: # None # Outputs: @@ -44,11 +45,12 @@ build_test_app_docker_images() { -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . - popd - gcloud -q auth configure-docker - docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" + if is_version_branch "${TESTING_VERSION}"; then + tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" + fi + popd } ####################################### From 1463ffa42ed2d5de7c23c772684b944a60c5c90c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 28 Jun 2022 14:05:29 -0700 Subject: [PATCH 1703/1899] Backport xDS k8s test scripts to the v1.6.x branch --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 172 ++++++++++++++++++ .../grpc-js-xds/scripts/xds_k8s_url_map.sh | 154 ++++++++++++++++ test/kokoro/xds_k8s_lb.cfg | 26 +++ test/kokoro/xds_k8s_url_map.cfg | 26 +++ 4 files changed, 378 insertions(+) create mode 100755 packages/grpc-js-xds/scripts/xds_k8s_lb.sh create mode 100644 packages/grpc-js-xds/scripts/xds_k8s_url_map.sh create mode 100644 test/kokoro/xds_k8s_lb.cfg create mode 100644 test/kokoro/xds_k8s_url_map.cfg diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh new file mode 100755 index 000000000..ca300f0c2 --- /dev/null +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -0,0 +1,172 @@ +#!/usr/bin/env bash +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +# Constants +readonly GITHUB_REPOSITORY_NAME="grpc-node" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +## xDS test client Docker images +readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/java-server:v1.46.x" +readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" +readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" +readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" +readonly LANGUAGE_NAME="Node" + +####################################### +# Builds test app Docker images and pushes them to GCR +# Globals: +# BUILD_APP_PATH +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# TESTING_VERSION: version branch under test, f.e. v1.42.x, master +# Arguments: +# None +# Outputs: +# Writes the output of `gcloud builds submit` to stdout, stderr +####################################### +build_test_app_docker_images() { + echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images" + + pushd "${SRC_DIR}" + docker build \ + -f "${BUILD_APP_PATH}" \ + -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + . + + gcloud -q auth configure-docker + docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" + if is_version_branch "${TESTING_VERSION}"; then + tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" + fi + popd +} + +####################################### +# Builds test app and its docker images unless they already exist +# Globals: +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# FORCE_IMAGE_BUILD +# Arguments: +# None +# Outputs: +# Writes the output to stdout, stderr +####################################### +build_docker_images_if_needed() { + # Check if images already exist + client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")" + printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" + echo "${client_tags:-Client image not found}" + + # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1 + if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then + build_test_app_docker_images + else + echo "Skipping ${LANGUAGE_NAME} test app build" + fi +} + +####################################### +# Executes the test case +# Globals: +# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile +# KUBE_CONTEXT: The name of kubectl context with GKE cluster access +# SECONDARY_KUBE_CONTEXT: The name of kubectl context with secondary GKE cluster access, if any +# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# Arguments: +# Test case name +# Outputs: +# Writes the output of test execution to stdout, stderr +# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml +####################################### +run_test() { + # Test driver usage: + # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage + local test_name="${1:?Usage: run_test test_name}" + # testing_version is used by the framework to determine the supported PSM + # features. It's captured from Kokoro job name of the Node repo, which takes + # the form: + # grpc/node// + python3 -m "tests.${test_name}" \ + --flagfile="${TEST_DRIVER_FLAGFILE}" \ + --kube_context="${KUBE_CONTEXT}" \ + --secondary_kube_context="${SECONDARY_KUBE_CONTEXT}" \ + --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + --server_image="${SERVER_IMAGE_NAME}" \ + --testing_version="${TESTING_VERSION}" \ + --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" +} + +####################################### +# Main function: provision software necessary to execute tests, and run them +# Globals: +# KOKORO_ARTIFACTS_DIR +# GITHUB_REPOSITORY_NAME +# SRC_DIR: Populated with absolute path to the source repo +# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing +# the test driver +# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code +# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile +# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report +# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build +# GIT_COMMIT: Populated with the SHA-1 of git commit being built +# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built +# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access +# SECONDARY_KUBE_CONTEXT: Populated with name of kubectl context with secondary GKE cluster access, if any +# Arguments: +# None +# Outputs: +# Writes the output of test execution to stdout, stderr +####################################### +main() { + local script_dir + script_dir="$(dirname "$0")" + + cd "${script_dir}" + + git submodule update --init --recursive + + # Source the test driver from the master branch. + echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" + source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" + + activate_gke_cluster GKE_CLUSTER_PSM_LB + activate_secondary_gke_cluster GKE_CLUSTER_PSM_LB + + set -x + if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then + kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}" + else + local_setup_test_driver "${script_dir}" + fi + build_docker_images_if_needed + + # Run tests + cd "${TEST_DRIVER_FULL_DIR}" + local failed_tests=0 + test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test") + for test in "${test_suites[@]}"; do + run_test $test || (( failed_tests++ )) + done + echo "Failed test suites: ${failed_tests}" + if (( failed_tests > 0 )); then + exit 1 + fi +} + +main "$@" diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh new file mode 100644 index 000000000..4371f235c --- /dev/null +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eo pipefail + +# Constants +readonly GITHUB_REPOSITORY_NAME="grpc-node" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +## xDS test client Docker images +readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" +readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" +readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" +readonly LANGUAGE_NAME="Node" + +####################################### +# Builds test app Docker images and pushes them to GCR +# Globals: +# BUILD_APP_PATH +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# TESTING_VERSION: version branch under test, f.e. v1.42.x, master +# Arguments: +# None +# Outputs: +# Writes the output of `gcloud builds submit` to stdout, stderr +####################################### +build_test_app_docker_images() { + echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images" + + pushd "${SRC_DIR}" + docker build \ + -f "${BUILD_APP_PATH}" \ + -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + . + + gcloud -q auth configure-docker + docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" + if is_version_branch "${TESTING_VERSION}"; then + tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" + fi + popd +} + +####################################### +# Builds test app and its docker images unless they already exist +# Globals: +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# FORCE_IMAGE_BUILD +# Arguments: +# None +# Outputs: +# Writes the output to stdout, stderr +####################################### +build_docker_images_if_needed() { + # Check if images already exist + client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")" + printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" + echo "${client_tags:-Client image not found}" + + # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1 + if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then + build_test_app_docker_images + else + echo "Skipping ${LANGUAGE_NAME} test app build" + fi +} + +####################################### +# Executes the test case +# Globals: +# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile +# KUBE_CONTEXT: The name of kubectl context with GKE cluster access +# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# TESTING_VERSION: version branch under test: used by the framework to determine the supported PSM +# features. +# Arguments: +# Test case name +# Outputs: +# Writes the output of test execution to stdout, stderr +# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml +####################################### +run_test() { + # Test driver usage: + # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage + local test_name="${1:?Usage: run_test test_name}" + set -x + python3 -m "tests.${test_name}" \ + --flagfile="${TEST_DRIVER_FLAGFILE}" \ + --kube_context="${KUBE_CONTEXT}" \ + --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ + --testing_version="${TESTING_VERSION}" \ + --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \ + --flagfile="config/url-map.cfg" + set +x +} + +####################################### +# Main function: provision software necessary to execute tests, and run them +# Globals: +# KOKORO_ARTIFACTS_DIR +# GITHUB_REPOSITORY_NAME +# SRC_DIR: Populated with absolute path to the source repo +# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing +# the test driver +# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code +# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile +# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report +# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build +# GIT_COMMIT: Populated with the SHA-1 of git commit being built +# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built +# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access +# Arguments: +# None +# Outputs: +# Writes the output of test execution to stdout, stderr +####################################### +main() { + local script_dir + script_dir="$(dirname "$0")" + + # Source the test driver from the master branch. + echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" + source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" + + activate_gke_cluster GKE_CLUSTER_PSM_BASIC + + set -x + if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then + kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}" + else + local_setup_test_driver "${script_dir}" + fi + build_docker_images_if_needed + # Run tests + cd "${TEST_DRIVER_FULL_DIR}" + run_test url_map +} + +main "$@" diff --git a/test/kokoro/xds_k8s_lb.cfg b/test/kokoro/xds_k8s_lb.cfg new file mode 100644 index 000000000..b9940cfdc --- /dev/null +++ b/test/kokoro/xds_k8s_lb.cfg @@ -0,0 +1,26 @@ +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds_k8s_lb.sh" +timeout_mins: 180 +action { + define_artifacts { + regex: "artifacts/**/*sponge_log.xml" + regex: "artifacts/**/*sponge_log.log" + strip_prefix: "artifacts" + } +} diff --git a/test/kokoro/xds_k8s_url_map.cfg b/test/kokoro/xds_k8s_url_map.cfg new file mode 100644 index 000000000..dd4cce76d --- /dev/null +++ b/test/kokoro/xds_k8s_url_map.cfg @@ -0,0 +1,26 @@ +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Config file for Kokoro (in protobuf text format) + +# Location of the continuous shell script in repository. +build_file: "grpc-node/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh" +timeout_mins: 180 +action { + define_artifacts { + regex: "artifacts/**/*sponge_log.xml" + regex: "artifacts/**/*sponge_log.log" + strip_prefix: "artifacts" + } +} From 15a962aab629bf7c3c001407f4244279fc72c6e3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 7 Jul 2022 10:37:15 -0700 Subject: [PATCH 1704/1899] Enable xDS tracing in k8s framework tests --- packages/grpc-js-xds/interop/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index bc85d3b21..e8a0a98cb 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -32,4 +32,7 @@ WORKDIR /node/src/grpc-node COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ +ENV GRPC_VERBOSITY="DEBUG" +ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds + ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] From c6d7d2aa033b2ebd88bd010552124c47e9af79e8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 7 Jul 2022 14:34:20 -0700 Subject: [PATCH 1705/1899] Backport xDS k8s interop docker image to version branch --- packages/grpc-js-xds/interop/Dockerfile | 38 +++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 packages/grpc-js-xds/interop/Dockerfile diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile new file mode 100644 index 000000000..e8a0a98cb --- /dev/null +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -0,0 +1,38 @@ +# Copyright 2022 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Dockerfile for building the xDS interop client. To build the image, run the +# following command from grpc-node directory: +# docker build -t -f packages/grpc-js-xds/interop/Dockerfile . + +FROM node:16-alpine as build + +# Make a grpc-node directory and copy the repo into it. +WORKDIR /node/src/grpc-node +COPY . . + +WORKDIR /node/src/grpc-node/packages/grpc-js +RUN npm install +WORKDIR /node/src/grpc-node/packages/grpc-js-xds +RUN npm install + +FROM node:16-alpine +WORKDIR /node/src/grpc-node +COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ +COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ + +ENV GRPC_VERBOSITY="DEBUG" +ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds + +ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] From 914ccdc19d52b22e7ea5fc5e8250984a68165201 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 Jul 2022 10:05:07 -0700 Subject: [PATCH 1706/1899] Clone submodules in xds k8s url map script --- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index 4371f235c..c29d0c0a5 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -133,6 +133,10 @@ main() { local script_dir script_dir="$(dirname "$0")" + cd "${script_dir}" + + git submodule update --init --recursive + # Source the test driver from the master branch. echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" From 6641494e029e648206b42e218a4a8d9536955f8b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 8 Jul 2022 10:05:07 -0700 Subject: [PATCH 1707/1899] Clone submodules in xds k8s url map script --- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index 4371f235c..c29d0c0a5 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -133,6 +133,10 @@ main() { local script_dir script_dir="$(dirname "$0")" + cd "${script_dir}" + + git submodule update --init --recursive + # Source the test driver from the master branch. echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" From 7b4704cc921cddf7c6084c69704ac940c4450b98 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 11 Jul 2022 11:32:04 -0700 Subject: [PATCH 1708/1899] proto-loader: Update protobufjs dependency to 7.x --- packages/proto-loader/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 65639c501..07e66c9fe 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.6.13", + "version": "0.7.0", "author": "Google Inc.", "contributors": [ { @@ -48,7 +48,7 @@ "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^4.0.0", - "protobufjs": "^6.11.3", + "protobufjs": "^7.0.0", "yargs": "^16.2.0" }, "devDependencies": { From 27b7bb8928118292892dd5727089be32b325fed3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 19 Jul 2022 10:52:02 -0700 Subject: [PATCH 1709/1899] grpc-js: Update proto-loader dependency to ^0.7.0 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 723b108ff..5fae717a4 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -58,7 +58,7 @@ "generate-test-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --include-dirs test/fixtures/ -O test/generated/ --grpcLib ../../src/index test_service.proto" }, "dependencies": { - "@grpc/proto-loader": "^0.6.4", + "@grpc/proto-loader": "^0.7.0", "@types/node": ">=12.12.47" }, "files": [ From 50c58238ff62b5e8d94fd4e795ff42ebc76d08a4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 20 Jul 2022 15:22:53 -0700 Subject: [PATCH 1710/1899] grpc-js: Update version to 1.6.8 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 5fae717a4..3ceaefebe 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.7", + "version": "1.6.8", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 3ab4ee34678d4e026013c55b2821da0553e737ea Mon Sep 17 00:00:00 2001 From: Christophe Diederichs Date: Thu, 21 Jul 2022 17:48:28 +0100 Subject: [PATCH 1711/1899] include .map files in proto-loader npm package --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 07e66c9fe..550346d04 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -38,7 +38,7 @@ "files": [ "LICENSE", "build/src/*.d.ts", - "build/src/*.js", + "build/src/*.{js,js.map}", "build/bin/*.js" ], "bin": { From 924fb9a3297febe3cceb8000822b80b8f5ffcee1 Mon Sep 17 00:00:00 2001 From: Christophe Diederichs Date: Fri, 22 Jul 2022 09:23:22 +0100 Subject: [PATCH 1712/1899] include proto-loader-gen-types.js.map in release --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 550346d04..c306fe9b6 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -39,7 +39,7 @@ "LICENSE", "build/src/*.d.ts", "build/src/*.{js,js.map}", - "build/bin/*.js" + "build/bin/*.{js,js.map}" ], "bin": { "proto-loader-gen-types": "./build/bin/proto-loader-gen-types.js" From fbf7944646b4286b97a93c15274180ab5ac29b6c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 22 Jul 2022 12:58:22 -0700 Subject: [PATCH 1713/1899] grpc-js: Outlier detection: Fix standard deviation calculation --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 2c231c406..dde618b73 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -430,11 +430,12 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { // Step 2 const successRateMean = successRates.reduce((a, b) => a + b) / successRates.length; - let successRateVariance = 0; + let successRateDeviationSum = 0; for (const rate of successRates) { const deviation = rate - successRateMean; - successRateVariance += deviation * deviation; + successRateDeviationSum += deviation * deviation; } + const successRateVariance = successRateDeviationSum / successRates.length; const successRateStdev = Math.sqrt(successRateVariance); const ejectionThreshold = successRateMean - successRateStdev * (successRateConfig.stdev_factor / 1000); From 90e8886d988bd5348c994bfb5d29a88df6a84782 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Aug 2022 11:02:02 -0700 Subject: [PATCH 1714/1899] grpc-js: Add outlier detection tracing and enable it in interop tests --- packages/grpc-js-xds/interop/Dockerfile | 2 +- .../src/load-balancer-outlier-detection.ts | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index e8a0a98cb..b93e309d7 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -33,6 +33,6 @@ COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ ENV GRPC_VERBOSITY="DEBUG" -ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds +ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds,outlier_detection ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index dde618b73..e9793beab 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -18,7 +18,7 @@ import { ChannelOptions, connectivityState, StatusObject } from "."; import { Call } from "./call-stream"; import { ConnectivityState } from "./connectivity-state"; -import { Status } from "./constants"; +import { LogVerbosity, Status } from "./constants"; import { durationToMs, isDuration, msToDuration } from "./duration"; import { ChannelControlHelper, createChildChannelControlHelper, registerLoadBalancerType } from "./experimental"; import { BaseFilter, Filter, FilterFactory } from "./filter"; @@ -28,7 +28,13 @@ import { PickArgs, Picker, PickResult, PickResultType, QueuePicker, UnavailableP import { Subchannel } from "./subchannel"; import { SubchannelAddress, subchannelAddressToString } from "./subchannel-address"; import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from "./subchannel-interface"; +import * as logging from './logging'; +const TRACER_NAME = 'outlier_detection'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'outlier_detection'; @@ -412,6 +418,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (!successRateConfig) { return; } + trace('Running success rate check'); // Step 1 const targetRequestVolume = successRateConfig.request_volume; let addresesWithTargetVolume = 0; @@ -424,6 +431,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { successRates.push(successes/(successes + failures)); } } + trace('Found ' + addresesWithTargetVolume + ' success rate candidates; currentEjectionPercent=' + this.getCurrentEjectionPercent() + ' successRates=[' + successRates + ']'); if (addresesWithTargetVolume < successRateConfig.minimum_hosts) { return; } @@ -438,9 +446,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const successRateVariance = successRateDeviationSum / successRates.length; const successRateStdev = Math.sqrt(successRateVariance); const ejectionThreshold = successRateMean - successRateStdev * (successRateConfig.stdev_factor / 1000); + trace('stdev=' + successRateStdev + ' ejectionThreshold=' + ejectionThreshold); // Step 3 - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap.entries()) { // Step 3.i if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { break; @@ -453,9 +462,12 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } // Step 3.iii const successRate = successes / (successes + failures); + trace('Checking candidate ' + address + ' successRate=' + successRate); if (successRate < ejectionThreshold) { const randomNumber = Math.random() * 100; + trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + successRateConfig.enforcement_percentage); if (randomNumber < successRateConfig.enforcement_percentage) { + trace('Ejecting candidate ' + address); this.eject(mapEntry, ejectionTimestamp); } } @@ -470,13 +482,14 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (!failurePercentageConfig) { return; } + trace('Running failure percentage check. threshold=' + failurePercentageConfig.threshold + ' request volume threshold=' + failurePercentageConfig.request_volume); // Step 1 if (this.addressMap.size < failurePercentageConfig.minimum_hosts) { return; } // Step 2 - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap.entries()) { // Step 2.i if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { break; @@ -484,6 +497,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { // Step 2.ii const successes = mapEntry.counter.getLastSuccesses(); const failures = mapEntry.counter.getLastFailures(); + trace('Candidate successes=' + successes + ' failures=' + failures); if (successes + failures < failurePercentageConfig.request_volume) { continue; } @@ -491,7 +505,9 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const failurePercentage = (failures * 100) / (failures + successes); if (failurePercentage > failurePercentageConfig.threshold) { const randomNumber = Math.random() * 100; + trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + failurePercentageConfig.enforcement_percentage); if (randomNumber < failurePercentageConfig.enforcement_percentage) { + trace('Ejecting candidate ' + address); this.eject(mapEntry, ejectionTimestamp); } } @@ -525,6 +541,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { private runChecks() { const ejectionTimestamp = new Date(); + trace('Ejection timer running'); this.switchAllBuckets(); @@ -537,7 +554,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { this.runSuccessRateCheck(ejectionTimestamp); this.runFailurePercentageCheck(ejectionTimestamp); - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap.entries()) { if (mapEntry.currentEjectionTimestamp === null) { if (mapEntry.ejectionTimeMultiplier > 0) { mapEntry.ejectionTimeMultiplier -= 1; @@ -548,6 +565,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const returnTime = new Date(mapEntry.currentEjectionTimestamp.getTime()); returnTime.setMilliseconds(returnTime.getMilliseconds() + Math.min(baseEjectionTimeMs * mapEntry.ejectionTimeMultiplier, Math.max(baseEjectionTimeMs, maxEjectionTimeMs))); if (returnTime < new Date()) { + trace('Unejecting ' + address); this.uneject(mapEntry); } } @@ -564,6 +582,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } for (const address of subchannelAddresses) { if (!this.addressMap.has(address)) { + trace('Adding map entry for ' + address); this.addressMap.set(address, { counter: new CallCounter(), currentEjectionTimestamp: null, @@ -574,6 +593,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } for (const key of this.addressMap.keys()) { if (!subchannelAddresses.has(key)) { + trace('Removing map entry for ' + key); this.addressMap.delete(key); } } @@ -585,15 +605,18 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (lbConfig.getSuccessRateEjectionConfig() || lbConfig.getFailurePercentageEjectionConfig()) { if (this.timerStartTime) { + trace('Previous timer existed. Replacing timer'); clearTimeout(this.ejectionTimer); const remainingDelay = lbConfig.getIntervalMs() - ((new Date()).getTime() - this.timerStartTime.getTime()); this.startTimer(remainingDelay); } else { + trace('Starting new timer'); this.timerStartTime = new Date(); this.startTimer(lbConfig.getIntervalMs()); this.switchAllBuckets(); } } else { + trace('Counting disabled. Cancelling timer.'); this.timerStartTime = null; clearTimeout(this.ejectionTimer); } From 1e531501550d989c7260370261ecf9423b3cf599 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Aug 2022 13:48:16 -0700 Subject: [PATCH 1715/1899] Update outlier detection behavior for gRFC updates --- packages/grpc-js-xds/src/load-balancer-cds.ts | 5 ++--- packages/grpc-js/src/load-balancer-outlier-detection.ts | 9 ++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index a6dbf42f0..4d47b2546 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -79,9 +79,8 @@ function translateOutlierDetectionConfig(outlierDetection: OutlierDetection__Out return undefined; } if (!outlierDetection) { - /* No-op outlier detection config, with max possible interval and no - * ejection criteria configured. */ - return new OutlierDetectionLoadBalancingConfig(~(1<<31), null, null, null, null, null, []); + /* No-op outlier detection config, with all fields unset. */ + return new OutlierDetectionLoadBalancingConfig(null, null, null, null, null, null, []); } let successRateConfig: Partial | null = null; /* Success rate ejection is enabled by default, so we only disable it if diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index e9793beab..4219e293a 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -357,7 +357,10 @@ class OutlierDetectionPicker implements Picker { extraFilterFactories: extraFilterFactories }; } else { - return wrappedPick; + return { + ...wrappedPick, + subchannel: subchannelWrapper.getWrappedSubchannel() + } } } else { return wrappedPick; @@ -619,6 +622,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { trace('Counting disabled. Cancelling timer.'); this.timerStartTime = null; clearTimeout(this.ejectionTimer); + for (const mapEntry of this.addressMap.values()) { + this.uneject(mapEntry); + mapEntry.ejectionTimeMultiplier = 0; + } } this.latestConfig = lbConfig; From b3f23d805efd1f30d44375c62de82845e78d5fd2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Aug 2022 12:54:15 -0700 Subject: [PATCH 1716/1899] grpc-js: Implement getConnectivityState in subchannel wrapper --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 4219e293a..afbeb3459 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -215,6 +215,14 @@ class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements }); } + getConnectivityState(): connectivityState { + if (this.ejected) { + return ConnectivityState.TRANSIENT_FAILURE; + } else { + return this.childSubchannelState; + } + } + /** * Add a listener function to be called whenever the wrapper's * connectivity state changes. From 78fe8c6d05f82eddc270dcbd3995868e3a49c038 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Aug 2022 15:56:28 -0700 Subject: [PATCH 1717/1899] grpc-js: Initialize connectivity state from subchannel in outlier detection subchannel wrapper --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index afbeb3459..0ef401c9a 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -199,12 +199,13 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig } class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements SubchannelInterface { - private childSubchannelState: ConnectivityState = ConnectivityState.IDLE; + private childSubchannelState: ConnectivityState; private stateListeners: ConnectivityStateListener[] = []; private ejected: boolean = false; private refCount: number = 0; constructor(childSubchannel: SubchannelInterface, private mapEntry?: MapEntry) { super(childSubchannel); + this.childSubchannelState = childSubchannel.getConnectivityState(); childSubchannel.addConnectivityStateListener((subchannel, previousState, newState) => { this.childSubchannelState = newState; if (!this.ejected) { From 001cce7db07ee06c648e9f364003e5fb7879d052 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Aug 2022 16:02:05 -0700 Subject: [PATCH 1718/1899] grpc-js: Propagate ejection when recreating outlier detection subchannel wrapper --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 0ef401c9a..ee400d45f 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -391,6 +391,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const originalSubchannel = channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); const mapEntry = this.addressMap.get(subchannelAddressToString(subchannelAddress)); const subchannelWrapper = new OutlierDetectionSubchannelWrapper(originalSubchannel, mapEntry); + if (mapEntry?.currentEjectionTimestamp !== null) { + // If the address is ejected, propagate that to the new subchannel wrapper + subchannelWrapper.eject(); + } mapEntry?.subchannelWrappers.push(subchannelWrapper); return subchannelWrapper; }, From edbdc570c7492b8be7eda2cb5f5afa0915a68f3b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Aug 2022 11:02:02 -0700 Subject: [PATCH 1719/1899] grpc-js: Add outlier detection tracing and enable it in interop tests --- packages/grpc-js-xds/interop/Dockerfile | 2 +- .../src/load-balancer-outlier-detection.ts | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index e8a0a98cb..b93e309d7 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -33,6 +33,6 @@ COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ ENV GRPC_VERBOSITY="DEBUG" -ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds +ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds,outlier_detection ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index dde618b73..e9793beab 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -18,7 +18,7 @@ import { ChannelOptions, connectivityState, StatusObject } from "."; import { Call } from "./call-stream"; import { ConnectivityState } from "./connectivity-state"; -import { Status } from "./constants"; +import { LogVerbosity, Status } from "./constants"; import { durationToMs, isDuration, msToDuration } from "./duration"; import { ChannelControlHelper, createChildChannelControlHelper, registerLoadBalancerType } from "./experimental"; import { BaseFilter, Filter, FilterFactory } from "./filter"; @@ -28,7 +28,13 @@ import { PickArgs, Picker, PickResult, PickResultType, QueuePicker, UnavailableP import { Subchannel } from "./subchannel"; import { SubchannelAddress, subchannelAddressToString } from "./subchannel-address"; import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from "./subchannel-interface"; +import * as logging from './logging'; +const TRACER_NAME = 'outlier_detection'; + +function trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); +} const TYPE_NAME = 'outlier_detection'; @@ -412,6 +418,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (!successRateConfig) { return; } + trace('Running success rate check'); // Step 1 const targetRequestVolume = successRateConfig.request_volume; let addresesWithTargetVolume = 0; @@ -424,6 +431,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { successRates.push(successes/(successes + failures)); } } + trace('Found ' + addresesWithTargetVolume + ' success rate candidates; currentEjectionPercent=' + this.getCurrentEjectionPercent() + ' successRates=[' + successRates + ']'); if (addresesWithTargetVolume < successRateConfig.minimum_hosts) { return; } @@ -438,9 +446,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const successRateVariance = successRateDeviationSum / successRates.length; const successRateStdev = Math.sqrt(successRateVariance); const ejectionThreshold = successRateMean - successRateStdev * (successRateConfig.stdev_factor / 1000); + trace('stdev=' + successRateStdev + ' ejectionThreshold=' + ejectionThreshold); // Step 3 - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap.entries()) { // Step 3.i if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { break; @@ -453,9 +462,12 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } // Step 3.iii const successRate = successes / (successes + failures); + trace('Checking candidate ' + address + ' successRate=' + successRate); if (successRate < ejectionThreshold) { const randomNumber = Math.random() * 100; + trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + successRateConfig.enforcement_percentage); if (randomNumber < successRateConfig.enforcement_percentage) { + trace('Ejecting candidate ' + address); this.eject(mapEntry, ejectionTimestamp); } } @@ -470,13 +482,14 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (!failurePercentageConfig) { return; } + trace('Running failure percentage check. threshold=' + failurePercentageConfig.threshold + ' request volume threshold=' + failurePercentageConfig.request_volume); // Step 1 if (this.addressMap.size < failurePercentageConfig.minimum_hosts) { return; } // Step 2 - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap.entries()) { // Step 2.i if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { break; @@ -484,6 +497,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { // Step 2.ii const successes = mapEntry.counter.getLastSuccesses(); const failures = mapEntry.counter.getLastFailures(); + trace('Candidate successes=' + successes + ' failures=' + failures); if (successes + failures < failurePercentageConfig.request_volume) { continue; } @@ -491,7 +505,9 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const failurePercentage = (failures * 100) / (failures + successes); if (failurePercentage > failurePercentageConfig.threshold) { const randomNumber = Math.random() * 100; + trace('Candidate ' + address + ' randomNumber=' + randomNumber + ' enforcement_percentage=' + failurePercentageConfig.enforcement_percentage); if (randomNumber < failurePercentageConfig.enforcement_percentage) { + trace('Ejecting candidate ' + address); this.eject(mapEntry, ejectionTimestamp); } } @@ -525,6 +541,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { private runChecks() { const ejectionTimestamp = new Date(); + trace('Ejection timer running'); this.switchAllBuckets(); @@ -537,7 +554,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { this.runSuccessRateCheck(ejectionTimestamp); this.runFailurePercentageCheck(ejectionTimestamp); - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap.entries()) { if (mapEntry.currentEjectionTimestamp === null) { if (mapEntry.ejectionTimeMultiplier > 0) { mapEntry.ejectionTimeMultiplier -= 1; @@ -548,6 +565,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const returnTime = new Date(mapEntry.currentEjectionTimestamp.getTime()); returnTime.setMilliseconds(returnTime.getMilliseconds() + Math.min(baseEjectionTimeMs * mapEntry.ejectionTimeMultiplier, Math.max(baseEjectionTimeMs, maxEjectionTimeMs))); if (returnTime < new Date()) { + trace('Unejecting ' + address); this.uneject(mapEntry); } } @@ -564,6 +582,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } for (const address of subchannelAddresses) { if (!this.addressMap.has(address)) { + trace('Adding map entry for ' + address); this.addressMap.set(address, { counter: new CallCounter(), currentEjectionTimestamp: null, @@ -574,6 +593,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } for (const key of this.addressMap.keys()) { if (!subchannelAddresses.has(key)) { + trace('Removing map entry for ' + key); this.addressMap.delete(key); } } @@ -585,15 +605,18 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (lbConfig.getSuccessRateEjectionConfig() || lbConfig.getFailurePercentageEjectionConfig()) { if (this.timerStartTime) { + trace('Previous timer existed. Replacing timer'); clearTimeout(this.ejectionTimer); const remainingDelay = lbConfig.getIntervalMs() - ((new Date()).getTime() - this.timerStartTime.getTime()); this.startTimer(remainingDelay); } else { + trace('Starting new timer'); this.timerStartTime = new Date(); this.startTimer(lbConfig.getIntervalMs()); this.switchAllBuckets(); } } else { + trace('Counting disabled. Cancelling timer.'); this.timerStartTime = null; clearTimeout(this.ejectionTimer); } From 9be6c6c5dab57d3f9f5408c5ee0f6d9ad2a99445 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 2 Aug 2022 13:48:16 -0700 Subject: [PATCH 1720/1899] Update outlier detection behavior for gRFC updates --- packages/grpc-js-xds/src/load-balancer-cds.ts | 5 ++--- packages/grpc-js/src/load-balancer-outlier-detection.ts | 9 ++++++++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index a6dbf42f0..4d47b2546 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -79,9 +79,8 @@ function translateOutlierDetectionConfig(outlierDetection: OutlierDetection__Out return undefined; } if (!outlierDetection) { - /* No-op outlier detection config, with max possible interval and no - * ejection criteria configured. */ - return new OutlierDetectionLoadBalancingConfig(~(1<<31), null, null, null, null, null, []); + /* No-op outlier detection config, with all fields unset. */ + return new OutlierDetectionLoadBalancingConfig(null, null, null, null, null, null, []); } let successRateConfig: Partial | null = null; /* Success rate ejection is enabled by default, so we only disable it if diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index e9793beab..4219e293a 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -357,7 +357,10 @@ class OutlierDetectionPicker implements Picker { extraFilterFactories: extraFilterFactories }; } else { - return wrappedPick; + return { + ...wrappedPick, + subchannel: subchannelWrapper.getWrappedSubchannel() + } } } else { return wrappedPick; @@ -619,6 +622,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { trace('Counting disabled. Cancelling timer.'); this.timerStartTime = null; clearTimeout(this.ejectionTimer); + for (const mapEntry of this.addressMap.values()) { + this.uneject(mapEntry); + mapEntry.ejectionTimeMultiplier = 0; + } } this.latestConfig = lbConfig; From 3328798d28f544a752f4328fc670a46009a769ba Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Aug 2022 12:54:15 -0700 Subject: [PATCH 1721/1899] grpc-js: Implement getConnectivityState in subchannel wrapper --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 4219e293a..afbeb3459 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -215,6 +215,14 @@ class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements }); } + getConnectivityState(): connectivityState { + if (this.ejected) { + return ConnectivityState.TRANSIENT_FAILURE; + } else { + return this.childSubchannelState; + } + } + /** * Add a listener function to be called whenever the wrapper's * connectivity state changes. From 4cfe75b43a72ca98d7745417be86206d611426ac Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Aug 2022 15:56:28 -0700 Subject: [PATCH 1722/1899] grpc-js: Initialize connectivity state from subchannel in outlier detection subchannel wrapper --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index afbeb3459..0ef401c9a 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -199,12 +199,13 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig } class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements SubchannelInterface { - private childSubchannelState: ConnectivityState = ConnectivityState.IDLE; + private childSubchannelState: ConnectivityState; private stateListeners: ConnectivityStateListener[] = []; private ejected: boolean = false; private refCount: number = 0; constructor(childSubchannel: SubchannelInterface, private mapEntry?: MapEntry) { super(childSubchannel); + this.childSubchannelState = childSubchannel.getConnectivityState(); childSubchannel.addConnectivityStateListener((subchannel, previousState, newState) => { this.childSubchannelState = newState; if (!this.ejected) { From 36f37cb78fb6fd987d9834d71a797ae8fabe2428 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Aug 2022 16:02:05 -0700 Subject: [PATCH 1723/1899] grpc-js: Propagate ejection when recreating outlier detection subchannel wrapper --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 0ef401c9a..ee400d45f 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -391,6 +391,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const originalSubchannel = channelControlHelper.createSubchannel(subchannelAddress, subchannelArgs); const mapEntry = this.addressMap.get(subchannelAddressToString(subchannelAddress)); const subchannelWrapper = new OutlierDetectionSubchannelWrapper(originalSubchannel, mapEntry); + if (mapEntry?.currentEjectionTimestamp !== null) { + // If the address is ejected, propagate that to the new subchannel wrapper + subchannelWrapper.eject(); + } mapEntry?.subchannelWrappers.push(subchannelWrapper); return subchannelWrapper; }, From d0dc6cd46e94b48bcf9520d587747a230dfcb2dd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Aug 2022 11:36:10 -0700 Subject: [PATCH 1724/1899] grpc-js-xds: Enable the outlier detection interop test --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index ca300f0c2..ff915db59 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -159,7 +159,7 @@ main() { # Run tests cd "${TEST_DRIVER_FULL_DIR}" local failed_tests=0 - test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test") + test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection") for test in "${test_suites[@]}"; do run_test $test || (( failed_tests++ )) done From e2960a87d29862b83cae8ec558c41847d7f33cb1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Aug 2022 11:36:10 -0700 Subject: [PATCH 1725/1899] grpc-js-xds: Enable the outlier detection interop test --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index ca300f0c2..ff915db59 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -159,7 +159,7 @@ main() { # Run tests cd "${TEST_DRIVER_FULL_DIR}" local failed_tests=0 - test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test") + test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection") for test in "${test_suites[@]}"; do run_test $test || (( failed_tests++ )) done From ee1e330157067e479690106b2dffa1fcf904b0e5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Aug 2022 12:50:50 -0700 Subject: [PATCH 1726/1899] grpc-js: Avoid explicit bind in trailer event handler --- packages/grpc-js/src/call-stream.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index e8f312752..f265512f4 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -573,7 +573,9 @@ export class Http2CallStream implements Call { } } }); - stream.on('trailers', this.handleTrailers.bind(this)); + stream.on('trailers', (headers: http2.IncomingHttpHeaders) => { + this.handleTrailers(headers); + }); stream.on('data', (data: Buffer) => { this.trace('receive HTTP/2 data frame of length ' + data.length); const messages = this.decoder.write(data); From 31d28b5f147e1392bab22e042aa0282c16a18567 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Aug 2022 13:05:26 -0700 Subject: [PATCH 1727/1899] grpc-js: Handle errors when trying to ping --- packages/grpc-js/src/subchannel.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 5d1bf8973..87c0cd2cd 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -361,12 +361,21 @@ export class Subchannel { this.handleDisconnect(); }, this.keepaliveTimeoutMs); this.keepaliveTimeoutId.unref?.(); - this.session!.ping( - (err: Error | null, duration: number, payload: Buffer) => { - this.keepaliveTrace('Received ping response'); - clearTimeout(this.keepaliveTimeoutId); - } - ); + try { + this.session!.ping( + (err: Error | null, duration: number, payload: Buffer) => { + this.keepaliveTrace('Received ping response'); + clearTimeout(this.keepaliveTimeoutId); + } + ); + } catch (e) { + /* If we fail to send a ping, the connection is no longer functional, so + * we should discard it. */ + this.transitionToState( + [ConnectivityState.READY], + ConnectivityState.TRANSIENT_FAILURE + ); + } } private startKeepalivePings() { From c1ab4c4a1b69a79fb7b69eff68a0bcfc517b28c9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Aug 2022 13:44:02 -0700 Subject: [PATCH 1728/1899] grpc-js: Update version to 1.6.9 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3ceaefebe..b10ad4a47 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.8", + "version": "1.6.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From e87b8640757ce583ab441a0807617eeafc3df6a2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Aug 2022 17:18:02 -0700 Subject: [PATCH 1729/1899] grpc-js: Update version to 1.6.9 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 3ceaefebe..b10ad4a47 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.8", + "version": "1.6.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 9e3935ec839009a5b64af935bfd503a634753367 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 9 Aug 2022 12:26:33 +0200 Subject: [PATCH 1730/1899] fix: update `long` to v5 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 07e66c9fe..6aef44a99 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -47,7 +47,7 @@ "dependencies": { "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "long": "^4.0.0", + "long": "^5.0.0", "protobufjs": "^7.0.0", "yargs": "^16.2.0" }, From d23d7bdd09d9adce9b4704e50e38aacd48f7d334 Mon Sep 17 00:00:00 2001 From: Simen Bekkhus Date: Tue, 9 Aug 2022 12:32:57 +0200 Subject: [PATCH 1731/1899] remove types `long` ships with types now --- packages/proto-loader/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 6aef44a99..60af4242f 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -45,7 +45,6 @@ "proto-loader-gen-types": "./build/bin/proto-loader-gen-types.js" }, "dependencies": { - "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.0.0", From 3f4418faf01cd029512cb3cbf48319d3b4f367ca Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 11 Aug 2022 18:01:01 -0700 Subject: [PATCH 1732/1899] grpc-js: Drain incoming http2 data after outputting status --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index b10ad4a47..72b4b10ed 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.9", + "version": "1.6.10", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index f265512f4..c405405e8 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -329,6 +329,11 @@ export class Http2CallStream implements Call { process.nextTick(() => { this.listener?.onReceiveStatus(filteredStatus); }); + /* Leave the http2 stream in flowing state to drain incoming messages, to + * ensure that the stream closure completes. The call stream already does + * not push more messages after the status is output, so the messages go + * nowhere either way. */ + this.http2Stream?.resume(); if (this.subchannel) { this.subchannel.callUnref(); this.subchannel.removeDisconnectListener(this.disconnectListener); @@ -577,6 +582,11 @@ export class Http2CallStream implements Call { this.handleTrailers(headers); }); stream.on('data', (data: Buffer) => { + /* If the status has already been output, allow the http2 stream to + * drain without processing the data. */ + if (this.statusOutput) { + return; + } this.trace('receive HTTP/2 data frame of length ' + data.length); const messages = this.decoder.write(data); @@ -688,9 +698,6 @@ export class Http2CallStream implements Call { } this.streamEndWatchers.forEach(watcher => watcher(false)); }); - if (!this.pendingRead) { - stream.pause(); - } if (this.pendingWrite) { if (!this.pendingWriteCallback) { throw new Error('Invalid state in write handling code'); From 9ba4ed36217a4a45c39138301e1bfffedfa9e888 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 15 Aug 2022 09:36:35 -0700 Subject: [PATCH 1733/1899] grpc-js-xds: Fix outlier detection interop test name --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index ff915db59..0e45cd86f 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -159,7 +159,7 @@ main() { # Run tests cd "${TEST_DRIVER_FULL_DIR}" local failed_tests=0 - test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection") + test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection_test") for test in "${test_suites[@]}"; do run_test $test || (( failed_tests++ )) done From ff16cdf02104295b08f1cbc124b0cba89a6336cc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 15 Aug 2022 09:36:35 -0700 Subject: [PATCH 1734/1899] grpc-js-xds: Fix outlier detection interop test name --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index ff915db59..0e45cd86f 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -159,7 +159,7 @@ main() { # Run tests cd "${TEST_DRIVER_FULL_DIR}" local failed_tests=0 - test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection") + test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection_test") for test in "${test_suites[@]}"; do run_test $test || (( failed_tests++ )) done From 9d0eb60d1948255fbe0af6ad4a2585734e5db366 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 09:30:53 -0700 Subject: [PATCH 1735/1899] proto-loader: Update dependencies to fix compilation error --- packages/proto-loader/package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 07e66c9fe..9c813337e 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.7.0", + "version": "0.7.1", "author": "Google Inc.", "contributors": [ { @@ -58,9 +58,9 @@ "@types/node": "^10.17.26", "@types/yargs": "^16.0.4", "clang-format": "^1.2.2", - "gts": "^1.1.0", + "gts": "^3.1.0", "rimraf": "^3.0.2", - "typescript": "~3.8.3" + "typescript": "~4.7.4" }, "engines": { "node": ">=6" From d0e7f356db02656ce1ba06b1f26d0a217348c481 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 12:44:48 -0700 Subject: [PATCH 1736/1899] proto-loader: Undo upgrade of 'long' dependency --- packages/proto-loader/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 09f815c86..53b269d1b 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.7.1", + "version": "0.7.2", "author": "Google Inc.", "contributors": [ { @@ -45,8 +45,9 @@ "proto-loader-gen-types": "./build/bin/proto-loader-gen-types.js" }, "dependencies": { + "@types/long": "^4.0.1", "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", + "long": "^4.0.0", "protobufjs": "^7.0.0", "yargs": "^16.2.0" }, From 7ca0cc006922588190597278288b65007f30ad7d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 16:32:20 -0700 Subject: [PATCH 1737/1899] grpc-js-xds: Implement ignore_resource_deletion option --- packages/grpc-js-xds/src/xds-client.ts | 4 +++ .../src/xds-stream-state/xds-stream-state.ts | 36 +++++++++++++++---- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index d2b3f1823..0c8126cbe 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -360,6 +360,10 @@ export class XdsClient { } else { this.apiVersion = XdsApiVersion.V2; } + if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('ignore_resource_deletion') >= 0) { + this.adsState.lds.enableIgnoreResourceDeletion(); + this.adsState.cds.enableIgnoreResourceDeletion(); + } const nodeV2: NodeV2 = { ...bootstrapInfo.node, build_version: `gRPC Node Pure JS ${clientVersion}`, diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 0b806f843..88d36c77d 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -75,6 +75,7 @@ interface SubscriptionEntry { watchers: Watcher[]; cachedResponse: ResponseType | null; resourceTimer: NodeJS.Timer; + deletionIgnored: boolean; } const RESOURCE_TIMEOUT_MS = 15_000; @@ -86,11 +87,12 @@ export abstract class BaseXdsStreamState implements XdsStreamState private subscriptions: Map> = new Map>(); private latestIsV2 = false; private isAdsStreamRunning = false; + private ignoreResourceDeletion = false; constructor(private updateResourceNames: () => void) {} - protected trace(text: string) { - experimental.trace(logVerbosity.DEBUG, TRACER_NAME, this.getProtocolName() + ' | ' + text); + protected trace(text: string, verbosity = logVerbosity.DEBUG) { + experimental.trace(verbosity, TRACER_NAME, this.getProtocolName() + ' | ' + text); } private startResourceTimer(subscriptionEntry: SubscriptionEntry) { @@ -111,7 +113,8 @@ export abstract class BaseXdsStreamState implements XdsStreamState subscriptionEntry = { watchers: [], cachedResponse: null, - resourceTimer: setTimeout(() => {}, 0) + resourceTimer: setTimeout(() => {}, 0), + deletionIgnored: false }; if (this.isAdsStreamRunning) { this.startResourceTimer(subscriptionEntry); @@ -142,6 +145,9 @@ export abstract class BaseXdsStreamState implements XdsStreamState } if (subscriptionEntry.watchers.length === 0) { clearTimeout(subscriptionEntry.resourceTimer); + if (subscriptionEntry.deletionIgnored) { + this.trace('Unsubscribing from resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + } this.subscriptions.delete(resourceName); this.updateResourceNames(); } @@ -187,6 +193,10 @@ export abstract class BaseXdsStreamState implements XdsStreamState } clearTimeout(subscriptionEntry.resourceTimer); subscriptionEntry.cachedResponse = resource; + if (subscriptionEntry.deletionIgnored) { + this.trace('Received resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + subscriptionEntry.deletionIgnored = false; + } } } result.missing = this.handleMissingNames(allResourceNames); @@ -218,10 +228,18 @@ export abstract class BaseXdsStreamState implements XdsStreamState const missingNames: string[] = []; for (const [resourceName, subscriptionEntry] of this.subscriptions.entries()) { if (!allResponseNames.has(resourceName) && subscriptionEntry.cachedResponse !== null) { - this.trace('Reporting resource does not exist named ' + resourceName); - missingNames.push(resourceName); - for (const watcher of subscriptionEntry.watchers) { - watcher.onResourceDoesNotExist(); + if (this.ignoreResourceDeletion) { + if (!subscriptionEntry.deletionIgnored) { + this.trace('Ignoring nonexistent resource ' + resourceName, logVerbosity.ERROR); + subscriptionEntry.deletionIgnored = true; + } + } else { + this.trace('Reporting resource does not exist named ' + resourceName); + missingNames.push(resourceName); + for (const watcher of subscriptionEntry.watchers) { + watcher.onResourceDoesNotExist(); + } + subscriptionEntry.cachedResponse = null; } } } @@ -231,6 +249,10 @@ export abstract class BaseXdsStreamState implements XdsStreamState } } + enableIgnoreResourceDeletion() { + this.ignoreResourceDeletion = true; + } + /** * Apply the validation rules for this resource type to this resource * instance. From a3b698e837cfa6cc5be0c989b2d0f2db7694af65 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 17:00:02 -0700 Subject: [PATCH 1738/1899] Don't use tracer for ignored resource deletion logs --- .../src/xds-stream-state/xds-stream-state.ts | 10 +++++----- packages/grpc-js/src/experimental.ts | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 88d36c77d..7b3bc0189 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -91,8 +91,8 @@ export abstract class BaseXdsStreamState implements XdsStreamState constructor(private updateResourceNames: () => void) {} - protected trace(text: string, verbosity = logVerbosity.DEBUG) { - experimental.trace(verbosity, TRACER_NAME, this.getProtocolName() + ' | ' + text); + protected trace(text: string) { + experimental.trace(logVerbosity.DEBUG, TRACER_NAME, this.getProtocolName() + ' | ' + text); } private startResourceTimer(subscriptionEntry: SubscriptionEntry) { @@ -146,7 +146,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState if (subscriptionEntry.watchers.length === 0) { clearTimeout(subscriptionEntry.resourceTimer); if (subscriptionEntry.deletionIgnored) { - this.trace('Unsubscribing from resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + experimental.log(logVerbosity.INFO, 'Unsubscribing from resource with previously ignored deletion: ' + resourceName); } this.subscriptions.delete(resourceName); this.updateResourceNames(); @@ -194,7 +194,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState clearTimeout(subscriptionEntry.resourceTimer); subscriptionEntry.cachedResponse = resource; if (subscriptionEntry.deletionIgnored) { - this.trace('Received resource with previously ignored deletion: ' + resourceName, logVerbosity.INFO); + experimental.log(logVerbosity.INFO, 'Received resource with previously ignored deletion: ' + resourceName); subscriptionEntry.deletionIgnored = false; } } @@ -230,7 +230,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState if (!allResponseNames.has(resourceName) && subscriptionEntry.cachedResponse !== null) { if (this.ignoreResourceDeletion) { if (!subscriptionEntry.deletionIgnored) { - this.trace('Ignoring nonexistent resource ' + resourceName, logVerbosity.ERROR); + experimental.log(logVerbosity.ERROR, 'Ignoring nonexistent resource ' + resourceName); subscriptionEntry.deletionIgnored = true; } } else { diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index fcafbeb01..d58495f46 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -1,4 +1,4 @@ -export { trace } from './logging'; +export { trace, log } from './logging'; export { Resolver, ResolverListener, From 5a7f89a5f5c768807f1c879069a2901af7a6b478 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Aug 2022 14:25:49 -0700 Subject: [PATCH 1739/1899] grpc-js: Switch LB policy when new one is not CONNECTING --- packages/grpc-js/src/load-balancer-child-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-child-handler.ts b/packages/grpc-js/src/load-balancer-child-handler.ts index 0591c92fd..64b341810 100644 --- a/packages/grpc-js/src/load-balancer-child-handler.ts +++ b/packages/grpc-js/src/load-balancer-child-handler.ts @@ -48,7 +48,7 @@ export class ChildLoadBalancerHandler implements LoadBalancer { } updateState(connectivityState: ConnectivityState, picker: Picker): void { if (this.calledByPendingChild()) { - if (connectivityState !== ConnectivityState.READY) { + if (connectivityState === ConnectivityState.CONNECTING) { return; } this.parent.currentChild?.destroy(); From 3e6730cd24bebd6780daa8b69161568881ab622b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 18 Aug 2022 14:55:58 -0700 Subject: [PATCH 1740/1899] grpc-js-xds: delay picker updates while updating children in weighted target and xds_cluster_manager --- .../grpc-js-xds/src/load-balancer-weighted-target.ts | 11 ++++++++++- .../src/load-balancer-xds-cluster-manager.ts | 11 ++++++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts index a7a28c663..5d7cfa04e 100644 --- a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -181,7 +181,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { trace('Target ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; - this.parent.updateState(); + this.parent.maybeUpdateState(); } updateAddressList(addressList: SubchannelAddress[], lbConfig: WeightedTarget, attributes: { [key: string]: unknown; }): void { @@ -238,9 +238,16 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { * List of current target names. */ private targetList: string[] = []; + private updatesPaused = false; constructor(private channelControlHelper: ChannelControlHelper) {} + private maybeUpdateState() { + if (!this.updatesPaused) { + this.updateState() + } + } + private updateState() { const pickerList: WeightedPicker[] = []; let end = 0; @@ -343,6 +350,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { childAddressList.push(childAddress); } + this.updatesPaused = true; this.targetList = Array.from(lbConfig.getTargets().keys()); for (const [targetName, targetConfig] of lbConfig.getTargets()) { let target = this.targets.get(targetName); @@ -364,6 +372,7 @@ export class WeightedTargetLoadBalancer implements LoadBalancer { target.deactivate(); } } + this.updatesPaused = false; this.updateState(); } diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index 6210ea84a..bfc55c809 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -144,7 +144,7 @@ class XdsClusterManager implements LoadBalancer { trace('Child ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; - this.parent.updateState(); + this.parent.maybeUpdateState(); } updateAddressList(addressList: SubchannelAddress[], lbConfig: ClusterManagerChild, attributes: { [key: string]: unknown; }): void { const childConfig = getFirstUsableConfig(lbConfig.child_policy); @@ -173,8 +173,15 @@ class XdsClusterManager implements LoadBalancer { private children: Map = new Map(); // Shutdown is a placeholder value that will never appear in normal operation. private currentState: ConnectivityState = ConnectivityState.SHUTDOWN; + private updatesPaused = false; constructor(private channelControlHelper: ChannelControlHelper) {} + private maybeUpdateState() { + if (!this.updatesPaused) { + this.updateState(); + } + } + private updateState() { const pickerMap: Map = new Map(); let anyReady = false; @@ -250,6 +257,7 @@ class XdsClusterManager implements LoadBalancer { namesToRemove.push(name); } } + this.updatesPaused = true; for (const name of namesToRemove) { this.children.get(name)!.destroy(); this.children.delete(name); @@ -262,6 +270,7 @@ class XdsClusterManager implements LoadBalancer { this.children.set(name, newChild); } } + this.updatesPaused = false; this.updateState(); } exitIdle(): void { From e1b2cad25ea15f1ae848069a5b80c5ae2b2b5ef3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 22 Aug 2022 14:28:34 -0700 Subject: [PATCH 1741/1899] grpc-js-xds: Make various fixes to the priority LB policy --- .../grpc-js-xds/src/load-balancer-priority.ts | 120 ++++++++---------- 1 file changed, 56 insertions(+), 64 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts index b05e459a7..9f4f68e1f 100644 --- a/packages/grpc-js-xds/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -115,7 +115,6 @@ interface PriorityChildBalancer { resetBackoff(): void; deactivate(): void; maybeReactivate(): void; - cancelFailoverTimer(): void; isFailoverTimerPending(): boolean; getConnectivityState(): ConnectivityState; getPicker(): Picker; @@ -138,6 +137,7 @@ export class PriorityLoadBalancer implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; private failoverTimer: NodeJS.Timer | null = null; private deactivationTimer: NodeJS.Timer | null = null; + private seenReadyOrIdleSinceTransientFailure = false; constructor(private parent: PriorityLoadBalancer, private name: string) { this.childBalancer = new ChildLoadBalancerHandler(experimental.createChildChannelControlHelper(this.parent.channelControlHelper, { updateState: (connectivityState: ConnectivityState, picker: Picker) => { @@ -145,12 +145,24 @@ export class PriorityLoadBalancer implements LoadBalancer { }, })); this.picker = new QueuePicker(this.childBalancer); + this.startFailoverTimer(); } private updateState(connectivityState: ConnectivityState, picker: Picker) { trace('Child ' + this.name + ' ' + ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[connectivityState]); this.connectivityState = connectivityState; this.picker = picker; + if (connectivityState === ConnectivityState.CONNECTING) { + if (this.seenReadyOrIdleSinceTransientFailure && this.failoverTimer === null) { + this.startFailoverTimer(); + } + } else if (connectivityState === ConnectivityState.READY || connectivityState === ConnectivityState.IDLE) { + this.seenReadyOrIdleSinceTransientFailure = true; + this.cancelFailoverTimer(); + } else if (connectivityState === ConnectivityState.TRANSIENT_FAILURE) { + this.seenReadyOrIdleSinceTransientFailure = false; + this.cancelFailoverTimer(); + } this.parent.onChildStateChange(this); } @@ -174,13 +186,9 @@ export class PriorityLoadBalancer implements LoadBalancer { attributes: { [key: string]: unknown } ): void { this.childBalancer.updateAddressList(addressList, lbConfig, attributes); - this.startFailoverTimer(); } exitIdle() { - if (this.connectivityState === ConnectivityState.IDLE) { - this.startFailoverTimer(); - } this.childBalancer.exitIdle(); } @@ -204,7 +212,7 @@ export class PriorityLoadBalancer implements LoadBalancer { } } - cancelFailoverTimer() { + private cancelFailoverTimer() { if (this.failoverTimer !== null) { clearTimeout(this.failoverTimer); this.failoverTimer = null; @@ -267,6 +275,8 @@ export class PriorityLoadBalancer implements LoadBalancer { */ private currentChildFromBeforeUpdate: PriorityChildBalancer | null = null; + private updatesPaused = false; + constructor(private channelControlHelper: ChannelControlHelper) {} private updateState(state: ConnectivityState, picker: Picker) { @@ -286,6 +296,9 @@ export class PriorityLoadBalancer implements LoadBalancer { private onChildStateChange(child: PriorityChildBalancer) { const childState = child.getConnectivityState(); trace('Child ' + child.getName() + ' transitioning to ' + ConnectivityState[childState]); + if (this.updatesPaused) { + return; + } if (child === this.currentChildFromBeforeUpdate) { if ( childState === ConnectivityState.READY || @@ -294,40 +307,11 @@ export class PriorityLoadBalancer implements LoadBalancer { this.updateState(childState, child.getPicker()); } else { this.currentChildFromBeforeUpdate = null; - this.tryNextPriority(true); + this.choosePriority(); } return; } - const childPriority = this.priorities.indexOf(child.getName()); - if (childPriority < 0) { - // child is not in the priority list, ignore updates - return; - } - if (this.currentPriority !== null && childPriority > this.currentPriority) { - // child is lower priority than the currently selected child, ignore updates - return; - } - if (childState === ConnectivityState.TRANSIENT_FAILURE) { - /* Report connecting if and only if the currently selected child is the - * one entering TRANSIENT_FAILURE */ - this.tryNextPriority(childPriority === this.currentPriority); - return; - } - if (this.currentPriority === null || childPriority < this.currentPriority) { - /* In this case, either there is no currently selected child or this - * child is higher priority than the currently selected child, so we want - * to switch to it if it is READY or IDLE. */ - if ( - childState === ConnectivityState.READY || - childState === ConnectivityState.IDLE - ) { - this.selectPriority(childPriority); - } - return; - } - /* The currently selected child has updated state to something other than - * TRANSIENT_FAILURE, so we pass that update along */ - this.updateState(childState, child.getPicker()); + this.choosePriority(); } private deleteChild(child: PriorityChildBalancer) { @@ -335,7 +319,7 @@ export class PriorityLoadBalancer implements LoadBalancer { this.currentChildFromBeforeUpdate = null; /* If we get to this point, the currentChildFromBeforeUpdate was still in * use, so we are still trying to connect to the specified priorities */ - this.tryNextPriority(true); + this.choosePriority(); } } @@ -348,7 +332,6 @@ export class PriorityLoadBalancer implements LoadBalancer { private selectPriority(priority: number) { this.currentPriority = priority; const chosenChild = this.children.get(this.priorities[priority])!; - chosenChild.cancelFailoverTimer(); this.updateState( chosenChild.getConnectivityState(), chosenChild.getPicker() @@ -360,20 +343,22 @@ export class PriorityLoadBalancer implements LoadBalancer { } } - /** - * Check each child in priority order until we find one to use - * @param reportConnecting Whether we should report a CONNECTING state if we - * stop before picking a specific child. This should be true when we have - * not already selected a child. - */ - private tryNextPriority(reportConnecting: boolean) { - for (const [index, childName] of this.priorities.entries()) { + private choosePriority() { + if (this.priorities.length === 0) { + this.updateState(ConnectivityState.TRANSIENT_FAILURE, new UnavailablePicker({code: Status.UNAVAILABLE, details: 'priority policy has empty priority list', metadata: new Metadata()})); + return; + } + + this.currentPriority = null; + for (const [priority, childName] of this.priorities.entries()) { + trace('Trying priority ' + priority + ' child ' + childName); let child = this.children.get(childName); /* If the child doesn't already exist, create it and update it. */ if (child === undefined) { - if (reportConnecting) { + if (this.currentChildFromBeforeUpdate === null) { this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); } + this.currentPriority = priority; child = new this.PriorityChildImpl(this, childName); this.children.set(childName, child); const childUpdate = this.latestUpdates.get(childName); @@ -383,6 +368,7 @@ export class PriorityLoadBalancer implements LoadBalancer { childUpdate.lbConfig, this.latestAttributes ); + return; } } /* We're going to try to use this child, so reactivate it if it has been @@ -392,28 +378,33 @@ export class PriorityLoadBalancer implements LoadBalancer { child.getConnectivityState() === ConnectivityState.READY || child.getConnectivityState() === ConnectivityState.IDLE ) { - this.selectPriority(index); + this.selectPriority(priority); return; } if (child.isFailoverTimerPending()) { - /* This child is still trying to connect. Wait until its failover timer - * has ended to continue to the next one */ - if (reportConnecting) { + this.currentPriority = priority; + if (this.currentChildFromBeforeUpdate === null) { + /* This child is still trying to connect. Wait until its failover timer + * has ended to continue to the next one */ this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); + return; } + } + } + + /* If we didn't find any priority to try, pick the first one in the state + * CONNECTING */ + for (const [priority, childName] of this.priorities.entries()) { + let child = this.children.get(childName)!; + if (child.getConnectivityState() === ConnectivityState.CONNECTING) { + this.updateState(child.getConnectivityState(), child.getPicker()); return; } } - this.currentPriority = null; - this.currentChildFromBeforeUpdate = null; - this.updateState( - ConnectivityState.TRANSIENT_FAILURE, - new UnavailablePicker({ - code: Status.UNAVAILABLE, - details: 'No ready priority', - metadata: new Metadata(), - }) - ); + + // Did not find any child in CONNECTING, delegate to last child + const child = this.children.get(this.priorities[this.priorities.length - 1])!; + this.updateState(child.getConnectivityState(), child.getPicker()); } updateAddressList( @@ -464,6 +455,7 @@ export class PriorityLoadBalancer implements LoadBalancer { this.latestAttributes = attributes; this.latestUpdates.clear(); this.priorities = lbConfig.getPriorities(); + this.updatesPaused = true; /* Pair up the new child configs with the corresponding address lists, and * update all existing children with their new configs */ for (const [childName, childConfig] of lbConfig.getChildren()) { @@ -492,8 +484,8 @@ export class PriorityLoadBalancer implements LoadBalancer { child.deactivate(); } } - // Only report connecting if there are no existing children - this.tryNextPriority(this.children.size === 0); + this.updatesPaused = false; + this.choosePriority(); } exitIdle(): void { if (this.currentPriority !== null) { From 460fa93b9c216687ed2e6ab640f9ce49241e0f0f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 23 Aug 2022 13:38:56 -0700 Subject: [PATCH 1742/1899] grpc-js-xds: priority: remove currentChildFromBeforeUpdate --- .../grpc-js-xds/src/load-balancer-priority.ts | 76 +++++-------------- 1 file changed, 17 insertions(+), 59 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-priority.ts b/packages/grpc-js-xds/src/load-balancer-priority.ts index 9f4f68e1f..12037a777 100644 --- a/packages/grpc-js-xds/src/load-balancer-priority.ts +++ b/packages/grpc-js-xds/src/load-balancer-priority.ts @@ -266,14 +266,6 @@ export class PriorityLoadBalancer implements LoadBalancer { * Current chosen priority that requests are sent to */ private currentPriority: number | null = null; - /** - * After an update, this preserves the currently selected child from before - * the update. We continue to use that child until it disconnects, or - * another higher-priority child connects, or it is deleted because it is not - * in the new priority list at all and its retention interval has expired, or - * we try and fail to connect to every child in the new priority list. - */ - private currentChildFromBeforeUpdate: PriorityChildBalancer | null = null; private updatesPaused = false; @@ -299,28 +291,11 @@ export class PriorityLoadBalancer implements LoadBalancer { if (this.updatesPaused) { return; } - if (child === this.currentChildFromBeforeUpdate) { - if ( - childState === ConnectivityState.READY || - childState === ConnectivityState.IDLE - ) { - this.updateState(childState, child.getPicker()); - } else { - this.currentChildFromBeforeUpdate = null; - this.choosePriority(); - } - return; - } this.choosePriority(); } private deleteChild(child: PriorityChildBalancer) { - if (child === this.currentChildFromBeforeUpdate) { - this.currentChildFromBeforeUpdate = null; - /* If we get to this point, the currentChildFromBeforeUpdate was still in - * use, so we are still trying to connect to the specified priorities */ - this.choosePriority(); - } + this.children.delete(child.getName()); } /** @@ -329,17 +304,17 @@ export class PriorityLoadBalancer implements LoadBalancer { * child connects. * @param priority */ - private selectPriority(priority: number) { + private selectPriority(priority: number, deactivateLowerPriorities: boolean) { this.currentPriority = priority; const chosenChild = this.children.get(this.priorities[priority])!; this.updateState( chosenChild.getConnectivityState(), chosenChild.getPicker() ); - this.currentChildFromBeforeUpdate = null; - // Deactivate each child of lower priority than the chosen child - for (let i = priority + 1; i < this.priorities.length; i++) { - this.children.get(this.priorities[i])?.deactivate(); + if (deactivateLowerPriorities) { + for (let i = priority + 1; i < this.priorities.length; i++) { + this.children.get(this.priorities[i])?.deactivate(); + } } } @@ -349,16 +324,11 @@ export class PriorityLoadBalancer implements LoadBalancer { return; } - this.currentPriority = null; for (const [priority, childName] of this.priorities.entries()) { trace('Trying priority ' + priority + ' child ' + childName); let child = this.children.get(childName); /* If the child doesn't already exist, create it and update it. */ if (child === undefined) { - if (this.currentChildFromBeforeUpdate === null) { - this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); - } - this.currentPriority = priority; child = new this.PriorityChildImpl(this, childName); this.children.set(childName, child); const childUpdate = this.latestUpdates.get(childName); @@ -368,27 +338,24 @@ export class PriorityLoadBalancer implements LoadBalancer { childUpdate.lbConfig, this.latestAttributes ); - return; } + } else { + /* We're going to try to use this child, so reactivate it if it has been + * deactivated */ + child.maybeReactivate(); } - /* We're going to try to use this child, so reactivate it if it has been - * deactivated */ - child.maybeReactivate(); if ( child.getConnectivityState() === ConnectivityState.READY || child.getConnectivityState() === ConnectivityState.IDLE ) { - this.selectPriority(priority); + this.selectPriority(priority, true); return; } if (child.isFailoverTimerPending()) { - this.currentPriority = priority; - if (this.currentChildFromBeforeUpdate === null) { - /* This child is still trying to connect. Wait until its failover timer - * has ended to continue to the next one */ - this.updateState(ConnectivityState.CONNECTING, new QueuePicker(this)); - return; - } + this.selectPriority(priority, false); + /* This child is still trying to connect. Wait until its failover timer + * has ended to continue to the next one */ + return; } } @@ -397,14 +364,13 @@ export class PriorityLoadBalancer implements LoadBalancer { for (const [priority, childName] of this.priorities.entries()) { let child = this.children.get(childName)!; if (child.getConnectivityState() === ConnectivityState.CONNECTING) { - this.updateState(child.getConnectivityState(), child.getPicker()); + this.selectPriority(priority, false); return; } } // Did not find any child in CONNECTING, delegate to last child - const child = this.children.get(this.priorities[this.priorities.length - 1])!; - this.updateState(child.getConnectivityState(), child.getPicker()); + this.selectPriority(this.priorities.length - 1, false); } updateAddressList( @@ -446,12 +412,6 @@ export class PriorityLoadBalancer implements LoadBalancer { } childAddressList.push(childAddress); } - if (this.currentPriority !== null) { - this.currentChildFromBeforeUpdate = this.children.get( - this.priorities[this.currentPriority] - )!; - this.currentPriority = null; - } this.latestAttributes = attributes; this.latestUpdates.clear(); this.priorities = lbConfig.getPriorities(); @@ -502,8 +462,6 @@ export class PriorityLoadBalancer implements LoadBalancer { child.destroy(); } this.children.clear(); - this.currentChildFromBeforeUpdate?.destroy(); - this.currentChildFromBeforeUpdate = null; } getTypeName(): string { return TYPE_NAME; From f15efb63deaf8a84cee358b69434319628e8175a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Aug 2022 10:27:53 -0700 Subject: [PATCH 1743/1899] grpc-js: Outlier Detection: fix failure percentage min hosts check --- .../grpc-js/src/load-balancer-outlier-detection.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index ee400d45f..dccca7c04 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -500,7 +500,15 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } trace('Running failure percentage check. threshold=' + failurePercentageConfig.threshold + ' request volume threshold=' + failurePercentageConfig.request_volume); // Step 1 - if (this.addressMap.size < failurePercentageConfig.minimum_hosts) { + let addresesWithTargetVolume = 0; + for (const mapEntry of this.addressMap.values()) { + const successes = mapEntry.counter.getLastSuccesses(); + const failures = mapEntry.counter.getLastFailures(); + if (successes + failures >= failurePercentageConfig.request_volume) { + addresesWithTargetVolume += 1; + } + } + if (addresesWithTargetVolume < failurePercentageConfig.minimum_hosts) { return; } From 8664c837db2f03e17b5bfd70a9d352a9a318448a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Aug 2022 10:59:15 -0700 Subject: [PATCH 1744/1899] Fix spelling --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index dccca7c04..a799e5b09 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -500,15 +500,15 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } trace('Running failure percentage check. threshold=' + failurePercentageConfig.threshold + ' request volume threshold=' + failurePercentageConfig.request_volume); // Step 1 - let addresesWithTargetVolume = 0; + let addressesWithTargetVolume = 0; for (const mapEntry of this.addressMap.values()) { const successes = mapEntry.counter.getLastSuccesses(); const failures = mapEntry.counter.getLastFailures(); if (successes + failures >= failurePercentageConfig.request_volume) { - addresesWithTargetVolume += 1; + addressesWithTargetVolume += 1; } } - if (addresesWithTargetVolume < failurePercentageConfig.minimum_hosts) { + if (addressesWithTargetVolume < failurePercentageConfig.minimum_hosts) { return; } From 7a138a696509494dcf9912569064f48b4421ee7b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 17 Aug 2022 09:30:53 -0700 Subject: [PATCH 1745/1899] proto-loader: Update dependencies to fix compilation error --- packages/proto-loader/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 9b9431dc1..989e34eac 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -58,9 +58,9 @@ "@types/node": "^10.17.26", "@types/yargs": "^16.0.4", "clang-format": "^1.2.2", - "gts": "^1.1.0", + "gts": "^3.1.0", "rimraf": "^3.0.2", - "typescript": "~3.8.3" + "typescript": "~4.7.4" }, "engines": { "node": ">=6" From 1d5801aa90784746809d3f7e10c9693d919bdc3f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 24 Aug 2022 14:54:09 -0700 Subject: [PATCH 1746/1899] grpc-js: Stop ejecting when current percent is equal to max --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index a799e5b09..bf7a72f87 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -467,7 +467,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { // Step 3 for (const [address, mapEntry] of this.addressMap.entries()) { // Step 3.i - if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { + if (this.getCurrentEjectionPercent() >= this.latestConfig.getMaxEjectionPercent()) { break; } // Step 3.ii @@ -515,7 +515,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { // Step 2 for (const [address, mapEntry] of this.addressMap.entries()) { // Step 2.i - if (this.getCurrentEjectionPercent() > this.latestConfig.getMaxEjectionPercent()) { + if (this.getCurrentEjectionPercent() >= this.latestConfig.getMaxEjectionPercent()) { break; } // Step 2.ii From 2c6fd779d8151580492e8e482add5a53bcfce42a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 25 Aug 2022 14:22:00 -0700 Subject: [PATCH 1747/1899] grpc-js-xds: Use authority override to select VirtualHost when provided --- packages/grpc-js-xds/src/resolver-xds.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index f6e2ad402..8c447931d 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -319,9 +319,12 @@ class XdsResolver implements Resolver { private handleRouteConfig(routeConfig: RouteConfiguration__Output, isV2: boolean) { this.latestRouteConfig = routeConfig; this.latestRouteConfigIsV2 = isV2; - const virtualHost = findVirtualHostForDomain(routeConfig.virtual_hosts, this.target.path); + /* Select the virtual host using the default authority override if it + * exists, and the channel target otherwise. */ + const hostDomain = this.channelOptions['grpc.default_authority'] ?? this.target.path; + const virtualHost = findVirtualHostForDomain(routeConfig.virtual_hosts, hostDomain); if (virtualHost === null) { - this.reportResolutionError('No matching route found'); + this.reportResolutionError('No matching route found for ' + hostDomain); return; } const virtualHostHttpFilterOverrides = new Map(); From 594933aa2b9c0b0d59635383c6e8f7b7829eb7de Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 26 Aug 2022 17:49:48 -0700 Subject: [PATCH 1748/1899] xDS interop: enable pod log collection in the buildscripts - Enables pod log collection in all PSM interop jobs implemented in https://github.com/grpc/grpc/pull/30594. - Associate test suite runs with their own log file, so it's displayed on the "Target Log" tab - Adds missing `--force_cleanup` to the lb test (reduces leaked resources) - Fix run_test not returning correct exit status, causing false positives in some cases. See https://github.com/grpc/grpc/pull/30768 --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 8 +++++++- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 10 +++++++--- test/kokoro/xds_k8s_lb.cfg | 2 +- test/kokoro/xds_k8s_url_map.cfg | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 0e45cd86f..ca747f7ea 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -98,6 +98,8 @@ run_test() { # Test driver usage: # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage local test_name="${1:?Usage: run_test test_name}" + local out_dir="${TEST_XML_OUTPUT_DIR}/${test_name}" + mkdir -pv "${out_dir}" # testing_version is used by the framework to determine the supported PSM # features. It's captured from Kokoro job name of the Node repo, which takes # the form: @@ -109,7 +111,11 @@ run_test() { --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ --server_image="${SERVER_IMAGE_NAME}" \ --testing_version="${TESTING_VERSION}" \ - --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" + --force_cleanup \ + --collect_app_logs \ + --log_dir="${out_dir}" \ + --xml_output_file="${out_dir}/sponge_log.xml" \ + |& tee "${out_dir}/sponge_log.log" } ####################################### diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index c29d0c0a5..69126c72b 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -98,15 +98,19 @@ run_test() { # Test driver usage: # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage local test_name="${1:?Usage: run_test test_name}" + local out_dir="${TEST_XML_OUTPUT_DIR}/${test_name}" + mkdir -pv "${out_dir}" set -x python3 -m "tests.${test_name}" \ --flagfile="${TEST_DRIVER_FLAGFILE}" \ + --flagfile="config/url-map.cfg" \ --kube_context="${KUBE_CONTEXT}" \ --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ --testing_version="${TESTING_VERSION}" \ - --xml_output_file="${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml" \ - --flagfile="config/url-map.cfg" - set +x + --collect_app_logs \ + --log_dir="${out_dir}" \ + --xml_output_file="${out_dir}/sponge_log.xml" \ + |& tee "${out_dir}/sponge_log.log" } ####################################### diff --git a/test/kokoro/xds_k8s_lb.cfg b/test/kokoro/xds_k8s_lb.cfg index b9940cfdc..09aa3d17d 100644 --- a/test/kokoro/xds_k8s_lb.cfg +++ b/test/kokoro/xds_k8s_lb.cfg @@ -20,7 +20,7 @@ timeout_mins: 180 action { define_artifacts { regex: "artifacts/**/*sponge_log.xml" - regex: "artifacts/**/*sponge_log.log" + regex: "artifacts/**/*.log" strip_prefix: "artifacts" } } diff --git a/test/kokoro/xds_k8s_url_map.cfg b/test/kokoro/xds_k8s_url_map.cfg index dd4cce76d..50d523b66 100644 --- a/test/kokoro/xds_k8s_url_map.cfg +++ b/test/kokoro/xds_k8s_url_map.cfg @@ -20,7 +20,7 @@ timeout_mins: 180 action { define_artifacts { regex: "artifacts/**/*sponge_log.xml" - regex: "artifacts/**/*sponge_log.log" + regex: "artifacts/**/*.log" strip_prefix: "artifacts" } } From a82e40ff9a7946df11557a77ee6b00e5c8bd946b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 29 Aug 2022 09:52:13 -0700 Subject: [PATCH 1749/1899] grpc-js: Handle errors when decoding status details --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 72b4b10ed..dab771696 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.10", + "version": "1.6.11", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index c405405e8..0bb4d01cb 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -488,7 +488,11 @@ export class Http2CallStream implements Call { } let details = ''; if (typeof metadataMap['grpc-message'] === 'string') { - details = decodeURI(metadataMap['grpc-message']); + try { + details = decodeURI(metadataMap['grpc-message']); + } catch (e) { + details = metadataMap['grpc-messages'] as string; + } metadata.remove('grpc-message'); this.trace( 'received status details string "' + details + '" from server' From c323369929e321a3de3465caeb97c74a527c7156 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 29 Aug 2022 15:41:51 -0700 Subject: [PATCH 1750/1899] grpc-js: Enable outlier detection by default --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index bf7a72f87..685cfc60d 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -38,7 +38,7 @@ function trace(text: string): void { const TYPE_NAME = 'outlier_detection'; -const OUTLIER_DETECTION_ENABLED = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION === 'true'; +const OUTLIER_DETECTION_ENABLED = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION !== 'false'; export interface SuccessRateEjectionConfig { readonly stdev_factor: number; From ccd855fb5add8e92e22418a84ed5eccedf239a6f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 29 Aug 2022 18:18:53 -0700 Subject: [PATCH 1751/1899] grpc-js: Fix typo in previous status message handling fix --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/call-stream.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index dab771696..8ca6eb1c6 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.11", + "version": "1.6.12", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index 0bb4d01cb..d7151eb6f 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -491,7 +491,7 @@ export class Http2CallStream implements Call { try { details = decodeURI(metadataMap['grpc-message']); } catch (e) { - details = metadataMap['grpc-messages'] as string; + details = metadataMap['grpc-message']; } metadata.remove('grpc-message'); this.trace( From bc66ebf62f0a8418c9ee90a1a038a7492078bb4d Mon Sep 17 00:00:00 2001 From: install <1994052+install@users.noreply.github.com> Date: Fri, 5 Aug 2022 12:38:36 -0400 Subject: [PATCH 1752/1899] proto-loader-gen-types Typename templates - Allow for customizing the naming pattern for both restricted and permissive types --- packages/proto-loader/README.md | 4 + .../bin/proto-loader-gen-types.ts | 84 ++++++++++++------- 2 files changed, 59 insertions(+), 29 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 123fad111..818f0efda 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -88,6 +88,10 @@ Options: -O, --outDir Directory in which to output files [string] [required] --grpcLib The gRPC implementation library that these types will be used with [string] [required] + --inputTemplate Template for mapping input or "permissive" type names + [string] [default: "%s"] + --outputTemplate Template for mapping output or "restricted" type names + [string] [default: "%s__Output"] ``` ### Example Usage diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index a819d12d4..bb5b35f81 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -26,12 +26,25 @@ import * as yargs from 'yargs'; import camelCase = require('lodash.camelcase'); import { loadProtosWithOptions, addCommonProtos } from '../src/util'; +const templateStr = "%s"; +const useNameFmter = ({outputTemplate, inputTemplate}: GeneratorOptions) => { + if (outputTemplate === inputTemplate) { + throw new Error('inputTemplate and outputTemplate must differ') + } + return { + outputName: (n: string) => outputTemplate.replace(templateStr, n), + inputName: (n: string) => inputTemplate.replace(templateStr, n) + }; +} + type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeDirs?: string[]; grpcLib: string; outDir: string; verbose?: boolean; includeComments?: boolean; + inputTemplate: string; + outputTemplate: string; } class TextFormatter { @@ -114,15 +127,16 @@ function getTypeInterfaceName(type: Protobuf.Type | Protobuf.Enum | Protobuf.Ser return type.fullName.replace(/\./g, '_'); } -function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Service, from?: Protobuf.Type | Protobuf.Service) { +function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Service, from: Protobuf.Type | Protobuf.Service | undefined, options: GeneratorOptions) { const filePath = from === undefined ? './' + getImportPath(dependency) : getRelativeImportPath(from, dependency); + const {outputName, inputName} = useNameFmter(options); const typeInterfaceName = getTypeInterfaceName(dependency); let importedTypes: string; /* If the dependency is defined within a message, it will be generated in that * message's file and exported using its typeInterfaceName. */ if (dependency.parent instanceof Protobuf.Type) { if (dependency instanceof Protobuf.Type) { - importedTypes = `${typeInterfaceName}, ${typeInterfaceName}__Output`; + importedTypes = `${inputName(typeInterfaceName)}, ${outputName(typeInterfaceName)}`; } else if (dependency instanceof Protobuf.Enum) { importedTypes = `${typeInterfaceName}`; } else if (dependency instanceof Protobuf.Service) { @@ -132,7 +146,7 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv } } else { if (dependency instanceof Protobuf.Type) { - importedTypes = `${dependency.name} as ${typeInterfaceName}, ${dependency.name}__Output as ${typeInterfaceName}__Output`; + importedTypes = `${inputName(dependency.name)} as ${inputName(typeInterfaceName)}, ${outputName(dependency.name)} as ${outputName(typeInterfaceName)}`; } else if (dependency instanceof Protobuf.Enum) { importedTypes = `${dependency.name} as ${typeInterfaceName}`; } else if (dependency instanceof Protobuf.Service) { @@ -170,7 +184,8 @@ function formatComment(formatter: TextFormatter, comment?: string | null) { // GENERATOR FUNCTIONS -function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean): string { +function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean, options: GeneratorOptions): string { + const {inputName} = useNameFmter(options); switch (fieldType) { case 'double': case 'float': @@ -200,9 +215,9 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | const typeInterfaceName = getTypeInterfaceName(resolvedType); if (resolvedType instanceof Protobuf.Type) { if (repeated || map) { - return typeInterfaceName; + return inputName(typeInterfaceName); } else { - return `${typeInterfaceName} | null`; + return `${inputName(typeInterfaceName)} | null`; } } else { return `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; @@ -210,8 +225,8 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | } } -function getFieldTypePermissive(field: Protobuf.FieldBase): string { - const valueType = getTypeNamePermissive(field.type, field.resolvedType, field.repeated, field.map); +function getFieldTypePermissive(field: Protobuf.FieldBase, options: GeneratorOptions): string { + const valueType = getTypeNamePermissive(field.type, field.resolvedType, field.repeated, field.map, options); if (field instanceof Protobuf.MapField) { const keyType = field.keyType === 'string' ? 'string' : 'number'; return `{[key: ${keyType}]: ${valueType}}`; @@ -221,23 +236,24 @@ function getFieldTypePermissive(field: Protobuf.FieldBase): string { } function generatePermissiveMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { + const {inputName} = useNameFmter(options); if (options.includeComments) { formatComment(formatter, messageType.comment); } if (messageType.fullName === '.google.protobuf.Any') { /* This describes the behavior of the Protobuf.js Any wrapper fromObject * replacement function */ - formatter.writeLine('export type Any = AnyExtension | {'); + formatter.writeLine(`export type ${inputName('Any')} = AnyExtension | {`); formatter.writeLine(' type_url: string;'); formatter.writeLine(' value: Buffer | Uint8Array | string;'); formatter.writeLine('}'); return; } - formatter.writeLine(`export interface ${nameOverride ?? messageType.name} {`); + formatter.writeLine(`export interface ${inputName(nameOverride ?? messageType.name)} {`); formatter.indent(); for (const field of messageType.fieldsArray) { const repeatedString = field.repeated ? '[]' : ''; - const type: string = getFieldTypePermissive(field); + const type: string = getFieldTypePermissive(field, options); if (options.includeComments) { formatComment(formatter, field.comment); } @@ -255,6 +271,7 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp } function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean, options: GeneratorOptions): string { + const {outputName} = useNameFmter(options); switch (fieldType) { case 'double': case 'float': @@ -302,9 +319,9 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | /* null is only used to represent absent message values if the defaults * option is set, and only for non-repeated, non-map fields. */ if (options.defaults && !repeated && !map) { - return `${typeInterfaceName}__Output | null`; + return `${outputName(typeInterfaceName)} | null`; } else { - return `${typeInterfaceName}__Output`; + return `${outputName(typeInterfaceName)}`; } } else { if (options.enums == String) { @@ -327,6 +344,7 @@ function getFieldTypeRestricted(field: Protobuf.FieldBase, options: GeneratorOpt } function generateRestrictedMessageInterface(formatter: TextFormatter, messageType: Protobuf.Type, options: GeneratorOptions, nameOverride?: string) { + const {outputName} = useNameFmter(options); if (options.includeComments) { formatComment(formatter, messageType.comment); } @@ -334,13 +352,13 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp /* This describes the behavior of the Protobuf.js Any wrapper toObject * replacement function */ let optionalString = options.defaults ? '' : '?'; - formatter.writeLine('export type Any__Output = AnyExtension | {'); + formatter.writeLine(`export type ${outputName('Any')} = AnyExtension | {`); formatter.writeLine(` type_url${optionalString}: string;`); formatter.writeLine(` value${optionalString}: ${getTypeNameRestricted('bytes', null, false, false, options)};`); formatter.writeLine('}'); return; } - formatter.writeLine(`export interface ${nameOverride ?? messageType.name}__Output {`); + formatter.writeLine(`export interface ${outputName(nameOverride ?? messageType.name)} {`); formatter.indent(); for (const field of messageType.fieldsArray) { let fieldGuaranteed: boolean; @@ -389,7 +407,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob continue; } seenDeps.add(dependency.fullName); - formatter.writeLine(getImportLine(dependency, messageType)); + formatter.writeLine(getImportLine(dependency, messageType, options)); } if (field.type.indexOf('64') >= 0) { usesLong = true; @@ -404,7 +422,7 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob continue; } seenDeps.add(dependency.fullName); - formatter.writeLine(getImportLine(dependency, messageType)); + formatter.writeLine(getImportLine(dependency, messageType, options)); } if (field.type.indexOf('64') >= 0) { usesLong = true; @@ -487,6 +505,7 @@ const CLIENT_RESERVED_METHOD_NAMES = new Set([ ]); function generateServiceClientInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + const {outputName, inputName} = useNameFmter(options); if (options.includeComments) { formatComment(formatter, serviceType.comment); } @@ -501,8 +520,8 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P if (options.includeComments) { formatComment(formatter, method.comment); } - const requestType = getTypeInterfaceName(method.resolvedRequestType!); - const responseType = getTypeInterfaceName(method.resolvedResponseType!) + '__Output'; + const requestType = inputName(getTypeInterfaceName(method.resolvedRequestType!)); + const responseType = outputName(getTypeInterfaceName(method.resolvedResponseType!)); const callbackType = `grpc.requestCallback<${responseType}>`; if (method.requestStream) { if (method.responseStream) { @@ -541,6 +560,7 @@ function generateServiceClientInterface(formatter: TextFormatter, serviceType: P } function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + const {inputName, outputName} = useNameFmter(options); if (options.includeComments) { formatComment(formatter, serviceType.comment); } @@ -551,8 +571,8 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: if (options.includeComments) { formatComment(formatter, method.comment); } - const requestType = getTypeInterfaceName(method.resolvedRequestType!) + '__Output'; - const responseType = getTypeInterfaceName(method.resolvedResponseType!); + const requestType = outputName(getTypeInterfaceName(method.resolvedRequestType!)); + const responseType = inputName(getTypeInterfaceName(method.resolvedResponseType!)); if (method.requestStream) { if (method.responseStream) { // Bidi streaming @@ -576,14 +596,15 @@ function generateServiceHandlerInterface(formatter: TextFormatter, serviceType: formatter.writeLine('}'); } -function generateServiceDefinitionInterface(formatter: TextFormatter, serviceType: Protobuf.Service) { +function generateServiceDefinitionInterface(formatter: TextFormatter, serviceType: Protobuf.Service, options: GeneratorOptions) { + const {inputName, outputName} = useNameFmter(options); formatter.writeLine(`export interface ${serviceType.name}Definition extends grpc.ServiceDefinition {`); formatter.indent(); for (const methodName of Object.keys(serviceType.methods).sort()) { const method = serviceType.methods[methodName]; const requestType = getTypeInterfaceName(method.resolvedRequestType!); const responseType = getTypeInterfaceName(method.resolvedResponseType!); - formatter.writeLine(`${methodName}: MethodDefinition<${requestType}, ${responseType}, ${requestType}__Output, ${responseType}__Output>`); + formatter.writeLine(`${methodName}: MethodDefinition<${inputName(requestType)}, ${inputName(responseType)}, ${outputName(requestType)}, ${outputName(responseType)}>`); } formatter.unindent(); formatter.writeLine('}') @@ -601,7 +622,7 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob dependencies.add(method.resolvedResponseType!); } for (const dep of Array.from(dependencies.values()).sort(compareName)) { - formatter.writeLine(getImportLine(dep, serviceType)); + formatter.writeLine(getImportLine(dep, serviceType, options)); } formatter.writeLine(''); @@ -611,7 +632,7 @@ function generateServiceInterfaces(formatter: TextFormatter, serviceType: Protob generateServiceHandlerInterface(formatter, serviceType, options); formatter.writeLine(''); - generateServiceDefinitionInterface(formatter, serviceType); + generateServiceDefinitionInterface(formatter, serviceType, options); } function containsDefinition(definitionType: typeof Protobuf.Type | typeof Protobuf.Enum, namespace: Protobuf.NamespaceBase): boolean { @@ -645,7 +666,7 @@ function generateDefinitionImports(formatter: TextFormatter, namespace: Protobuf function generateServiceImports(formatter: TextFormatter, namespace: Protobuf.NamespaceBase, options: GeneratorOptions) { for (const nested of namespace.nestedArray.sort(compareName)) { if (nested instanceof Protobuf.Service) { - formatter.writeLine(getImportLine(nested)); + formatter.writeLine(getImportLine(nested, undefined, options)); } else if (isNamespaceBase(nested) && !(nested instanceof Protobuf.Type) && !(nested instanceof Protobuf.Enum)) { generateServiceImports(formatter, nested, options); } @@ -776,7 +797,7 @@ async function runScript() { .normalize(['includeDirs', 'outDir']) .array('includeDirs') .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) - .string(['longs', 'enums', 'bytes']) + .string(['longs', 'enums', 'bytes', 'inputTemplate', 'outputTemplate']) .default('keepCase', false) .default('defaults', false) .default('arrays', false) @@ -787,6 +808,8 @@ async function runScript() { .default('longs', 'Long') .default('enums', 'number') .default('bytes', 'Buffer') + .default('inputTemplate', `${templateStr}`) + .default('outputTemplate', `${templateStr}__Output`) .coerce('longs', value => { switch (value) { case 'String': return String; @@ -805,7 +828,8 @@ async function runScript() { case 'String': return String; default: return undefined; } - }).alias({ + }) + .alias({ includeDirs: 'I', outDir: 'O', verbose: 'v' @@ -822,7 +846,9 @@ async function runScript() { includeComments: 'Generate doc comments from comments in the original files', includeDirs: 'Directories to search for included files', outDir: 'Directory in which to output files', - grpcLib: 'The gRPC implementation library that these types will be used with' + grpcLib: 'The gRPC implementation library that these types will be used with', + inputTemplate: 'Template for mapping input or "permissive" type names', + outputTemplate: 'Template for mapping output or "restricted" type names', }).demandOption(['outDir', 'grpcLib']) .demand(1) .usage('$0 [options] filenames...') From d81ec8e5326a8f48cc824878b8ce7ecb09b95ffb Mon Sep 17 00:00:00 2001 From: install <1994052+install@users.noreply.github.com> Date: Wed, 7 Sep 2022 09:59:22 -0400 Subject: [PATCH 1753/1899] Update golden tests - use input/output templates --- .../google/api/CustomHttpPattern.ts | 4 +- .../golden-generated/google/api/Http.ts | 10 +- .../golden-generated/google/api/HttpRule.ts | 16 +- .../longrunning/CancelOperationRequest.ts | 4 +- .../longrunning/DeleteOperationRequest.ts | 4 +- .../google/longrunning/GetOperationRequest.ts | 4 +- .../longrunning/ListOperationsRequest.ts | 4 +- .../longrunning/ListOperationsResponse.ts | 10 +- .../google/longrunning/Operation.ts | 20 +-- .../google/longrunning/OperationInfo.ts | 4 +- .../google/longrunning/Operations.ts | 116 +++++++------- .../longrunning/WaitOperationRequest.ts | 10 +- .../golden-generated/google/protobuf/Any.ts | 4 +- .../google/protobuf/DescriptorProto.ts | 54 +++---- .../google/protobuf/Duration.ts | 4 +- .../golden-generated/google/protobuf/Empty.ts | 4 +- .../google/protobuf/EnumDescriptorProto.ts | 16 +- .../google/protobuf/EnumOptions.ts | 10 +- .../protobuf/EnumValueDescriptorProto.ts | 10 +- .../google/protobuf/EnumValueOptions.ts | 10 +- .../google/protobuf/FieldDescriptorProto.ts | 10 +- .../google/protobuf/FieldOptions.ts | 10 +- .../google/protobuf/FileDescriptorProto.ts | 40 ++--- .../google/protobuf/FileDescriptorSet.ts | 10 +- .../google/protobuf/FileOptions.ts | 10 +- .../google/protobuf/GeneratedCodeInfo.ts | 12 +- .../google/protobuf/MessageOptions.ts | 10 +- .../google/protobuf/MethodDescriptorProto.ts | 10 +- .../google/protobuf/MethodOptions.ts | 22 +-- .../google/protobuf/OneofDescriptorProto.ts | 10 +- .../google/protobuf/OneofOptions.ts | 10 +- .../google/protobuf/ServiceDescriptorProto.ts | 16 +- .../google/protobuf/ServiceOptions.ts | 10 +- .../google/protobuf/SourceCodeInfo.ts | 12 +- .../google/protobuf/Timestamp.ts | 4 +- .../google/protobuf/UninterpretedOption.ts | 12 +- .../golden-generated/google/rpc/Status.ts | 10 +- .../google/showcase/v1beta1/BlockRequest.ts | 22 +-- .../google/showcase/v1beta1/BlockResponse.ts | 4 +- .../google/showcase/v1beta1/Echo.ts | 142 +++++++++--------- .../google/showcase/v1beta1/EchoRequest.ts | 10 +- .../google/showcase/v1beta1/EchoResponse.ts | 4 +- .../google/showcase/v1beta1/ExpandRequest.ts | 10 +- .../showcase/v1beta1/PagedExpandRequest.ts | 4 +- .../showcase/v1beta1/PagedExpandResponse.ts | 10 +- .../google/showcase/v1beta1/WaitMetadata.ts | 10 +- .../google/showcase/v1beta1/WaitRequest.ts | 28 ++-- .../google/showcase/v1beta1/WaitResponse.ts | 4 +- packages/proto-loader/package.json | 2 +- 49 files changed, 393 insertions(+), 393 deletions(-) diff --git a/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts b/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts index 2b6490be6..2f6e20297 100644 --- a/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts +++ b/packages/proto-loader/golden-generated/google/api/CustomHttpPattern.ts @@ -4,7 +4,7 @@ /** * A custom pattern is used for defining custom HTTP verb. */ -export interface CustomHttpPattern { +export interface ICustomHttpPattern { /** * The name of this custom HTTP verb. */ @@ -18,7 +18,7 @@ export interface CustomHttpPattern { /** * A custom pattern is used for defining custom HTTP verb. */ -export interface CustomHttpPattern__Output { +export interface OCustomHttpPattern { /** * The name of this custom HTTP verb. */ diff --git a/packages/proto-loader/golden-generated/google/api/Http.ts b/packages/proto-loader/golden-generated/google/api/Http.ts index e9b3cb309..6b6ae8a63 100644 --- a/packages/proto-loader/golden-generated/google/api/Http.ts +++ b/packages/proto-loader/golden-generated/google/api/Http.ts @@ -1,19 +1,19 @@ // Original file: deps/googleapis/google/api/http.proto -import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { IHttpRule as I_google_api_HttpRule, OHttpRule as O_google_api_HttpRule } from '../../google/api/HttpRule'; /** * Defines the HTTP configuration for an API service. It contains a list of * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method * to one or more HTTP REST API methods. */ -export interface Http { +export interface IHttp { /** * A list of HTTP configuration rules that apply to individual API methods. * * **NOTE:** All service configuration rules follow "last one wins" order. */ - 'rules'?: (_google_api_HttpRule)[]; + 'rules'?: (I_google_api_HttpRule)[]; /** * When set to true, URL path parameters will be fully URI-decoded except in * cases of single segment matches in reserved expansion, where "%2F" will be @@ -30,13 +30,13 @@ export interface Http { * [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method * to one or more HTTP REST API methods. */ -export interface Http__Output { +export interface OHttp { /** * A list of HTTP configuration rules that apply to individual API methods. * * **NOTE:** All service configuration rules follow "last one wins" order. */ - 'rules': (_google_api_HttpRule__Output)[]; + 'rules': (O_google_api_HttpRule)[]; /** * When set to true, URL path parameters will be fully URI-decoded except in * cases of single segment matches in reserved expansion, where "%2F" will be diff --git a/packages/proto-loader/golden-generated/google/api/HttpRule.ts b/packages/proto-loader/golden-generated/google/api/HttpRule.ts index 243a99f80..90efdc00d 100644 --- a/packages/proto-loader/golden-generated/google/api/HttpRule.ts +++ b/packages/proto-loader/golden-generated/google/api/HttpRule.ts @@ -1,7 +1,7 @@ // Original file: deps/googleapis/google/api/http.proto -import type { CustomHttpPattern as _google_api_CustomHttpPattern, CustomHttpPattern__Output as _google_api_CustomHttpPattern__Output } from '../../google/api/CustomHttpPattern'; -import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { ICustomHttpPattern as I_google_api_CustomHttpPattern, OCustomHttpPattern as O_google_api_CustomHttpPattern } from '../../google/api/CustomHttpPattern'; +import type { IHttpRule as I_google_api_HttpRule, OHttpRule as O_google_api_HttpRule } from '../../google/api/HttpRule'; /** * # gRPC Transcoding @@ -274,7 +274,7 @@ import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_ * the request or response body to a repeated field. However, some gRPC * Transcoding implementations may not support this feature. */ -export interface HttpRule { +export interface IHttpRule { /** * Selects a method to which this rule applies. * @@ -317,13 +317,13 @@ export interface HttpRule { * HTTP method unspecified for this rule. The wild-card rule is useful * for services that provide content to Web (HTML) clients. */ - 'custom'?: (_google_api_CustomHttpPattern | null); + 'custom'?: (I_google_api_CustomHttpPattern | null); /** * Additional HTTP bindings for the selector. Nested bindings must * not contain an `additional_bindings` field themselves (that is, * the nesting may only be one level deep). */ - 'additional_bindings'?: (_google_api_HttpRule)[]; + 'additional_bindings'?: (I_google_api_HttpRule)[]; /** * Optional. The name of the response field whose value is mapped to the HTTP * response body. When omitted, the entire response message will be used @@ -612,7 +612,7 @@ export interface HttpRule { * the request or response body to a repeated field. However, some gRPC * Transcoding implementations may not support this feature. */ -export interface HttpRule__Output { +export interface OHttpRule { /** * Selects a method to which this rule applies. * @@ -655,13 +655,13 @@ export interface HttpRule__Output { * HTTP method unspecified for this rule. The wild-card rule is useful * for services that provide content to Web (HTML) clients. */ - 'custom'?: (_google_api_CustomHttpPattern__Output | null); + 'custom'?: (O_google_api_CustomHttpPattern | null); /** * Additional HTTP bindings for the selector. Nested bindings must * not contain an `additional_bindings` field themselves (that is, * the nesting may only be one level deep). */ - 'additional_bindings': (_google_api_HttpRule__Output)[]; + 'additional_bindings': (O_google_api_HttpRule)[]; /** * Optional. The name of the response field whose value is mapped to the HTTP * response body. When omitted, the entire response message will be used diff --git a/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts index 05fbc842e..7e0f15ed8 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/CancelOperationRequest.ts @@ -4,7 +4,7 @@ /** * The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. */ -export interface CancelOperationRequest { +export interface ICancelOperationRequest { /** * The name of the operation resource to be cancelled. */ @@ -14,7 +14,7 @@ export interface CancelOperationRequest { /** * The request message for [Operations.CancelOperation][google.longrunning.Operations.CancelOperation]. */ -export interface CancelOperationRequest__Output { +export interface OCancelOperationRequest { /** * The name of the operation resource to be cancelled. */ diff --git a/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts index 0ad87cde9..39d669d0a 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/DeleteOperationRequest.ts @@ -4,7 +4,7 @@ /** * The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. */ -export interface DeleteOperationRequest { +export interface IDeleteOperationRequest { /** * The name of the operation resource to be deleted. */ @@ -14,7 +14,7 @@ export interface DeleteOperationRequest { /** * The request message for [Operations.DeleteOperation][google.longrunning.Operations.DeleteOperation]. */ -export interface DeleteOperationRequest__Output { +export interface ODeleteOperationRequest { /** * The name of the operation resource to be deleted. */ diff --git a/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts index 039f01674..9667e2e87 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/GetOperationRequest.ts @@ -4,7 +4,7 @@ /** * The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. */ -export interface GetOperationRequest { +export interface IGetOperationRequest { /** * The name of the operation resource. */ @@ -14,7 +14,7 @@ export interface GetOperationRequest { /** * The request message for [Operations.GetOperation][google.longrunning.Operations.GetOperation]. */ -export interface GetOperationRequest__Output { +export interface OGetOperationRequest { /** * The name of the operation resource. */ diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts index 294ec6773..49dcd39f0 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsRequest.ts @@ -4,7 +4,7 @@ /** * The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. */ -export interface ListOperationsRequest { +export interface IListOperationsRequest { /** * The standard list filter. */ @@ -26,7 +26,7 @@ export interface ListOperationsRequest { /** * The request message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. */ -export interface ListOperationsRequest__Output { +export interface OListOperationsRequest { /** * The standard list filter. */ diff --git a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts index c295aa801..1e8b9ed5a 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/ListOperationsResponse.ts @@ -1,15 +1,15 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import type { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; +import type { IOperation as I_google_longrunning_Operation, OOperation as O_google_longrunning_Operation } from '../../google/longrunning/Operation'; /** * The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. */ -export interface ListOperationsResponse { +export interface IListOperationsResponse { /** * A list of operations that matches the specified filter in the request. */ - 'operations'?: (_google_longrunning_Operation)[]; + 'operations'?: (I_google_longrunning_Operation)[]; /** * The standard List next-page token. */ @@ -19,11 +19,11 @@ export interface ListOperationsResponse { /** * The response message for [Operations.ListOperations][google.longrunning.Operations.ListOperations]. */ -export interface ListOperationsResponse__Output { +export interface OListOperationsResponse { /** * A list of operations that matches the specified filter in the request. */ - 'operations': (_google_longrunning_Operation__Output)[]; + 'operations': (O_google_longrunning_Operation)[]; /** * The standard List next-page token. */ diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts index 2a4bbe1ee..bbd1d8078 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operation.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operation.ts @@ -1,13 +1,13 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../google/rpc/Status'; +import type { IAny as I_google_protobuf_Any, OAny as O_google_protobuf_Any } from '../../google/protobuf/Any'; +import type { IStatus as I_google_rpc_Status, OStatus as O_google_rpc_Status } from '../../google/rpc/Status'; /** * This resource represents a long-running operation that is the result of a * network API call. */ -export interface Operation { +export interface IOperation { /** * The server-assigned name, which is only unique within the same service that * originally returns it. If you use the default HTTP mapping, the @@ -20,7 +20,7 @@ export interface Operation { * Some services might not provide such metadata. Any method that returns a * long-running operation should document the metadata type, if any. */ - 'metadata'?: (_google_protobuf_Any | null); + 'metadata'?: (I_google_protobuf_Any | null); /** * If the value is `false`, it means the operation is still in progress. * If `true`, the operation is completed, and either `error` or `response` is @@ -30,7 +30,7 @@ export interface Operation { /** * The error result of the operation in case of failure or cancellation. */ - 'error'?: (_google_rpc_Status | null); + 'error'?: (I_google_rpc_Status | null); /** * The normal response of the operation in case of success. If the original * method returns no data on success, such as `Delete`, the response is @@ -41,7 +41,7 @@ export interface Operation { * is `TakeSnapshot()`, the inferred response type is * `TakeSnapshotResponse`. */ - 'response'?: (_google_protobuf_Any | null); + 'response'?: (I_google_protobuf_Any | null); /** * The operation result, which can be either an `error` or a valid `response`. * If `done` == `false`, neither `error` nor `response` is set. @@ -54,7 +54,7 @@ export interface Operation { * This resource represents a long-running operation that is the result of a * network API call. */ -export interface Operation__Output { +export interface OOperation { /** * The server-assigned name, which is only unique within the same service that * originally returns it. If you use the default HTTP mapping, the @@ -67,7 +67,7 @@ export interface Operation__Output { * Some services might not provide such metadata. Any method that returns a * long-running operation should document the metadata type, if any. */ - 'metadata': (_google_protobuf_Any__Output | null); + 'metadata': (O_google_protobuf_Any | null); /** * If the value is `false`, it means the operation is still in progress. * If `true`, the operation is completed, and either `error` or `response` is @@ -77,7 +77,7 @@ export interface Operation__Output { /** * The error result of the operation in case of failure or cancellation. */ - 'error'?: (_google_rpc_Status__Output | null); + 'error'?: (O_google_rpc_Status | null); /** * The normal response of the operation in case of success. If the original * method returns no data on success, such as `Delete`, the response is @@ -88,7 +88,7 @@ export interface Operation__Output { * is `TakeSnapshot()`, the inferred response type is * `TakeSnapshotResponse`. */ - 'response'?: (_google_protobuf_Any__Output | null); + 'response'?: (O_google_protobuf_Any | null); /** * The operation result, which can be either an `error` or a valid `response`. * If `done` == `false`, neither `error` nor `response` is set. diff --git a/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts b/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts index 343e2f8c9..907574412 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/OperationInfo.ts @@ -14,7 +14,7 @@ * }; * } */ -export interface OperationInfo { +export interface IOperationInfo { /** * Required. The message name of the primary return type for this * long-running operation. @@ -51,7 +51,7 @@ export interface OperationInfo { * }; * } */ -export interface OperationInfo__Output { +export interface OOperationInfo { /** * Required. The message name of the primary return type for this * long-running operation. diff --git a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts index 6358cbbfd..00d6a95d2 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/Operations.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/Operations.ts @@ -2,14 +2,14 @@ import type * as grpc from '@grpc/grpc-js' import type { MethodDefinition } from '@grpc/proto-loader' -import type { CancelOperationRequest as _google_longrunning_CancelOperationRequest, CancelOperationRequest__Output as _google_longrunning_CancelOperationRequest__Output } from '../../google/longrunning/CancelOperationRequest'; -import type { DeleteOperationRequest as _google_longrunning_DeleteOperationRequest, DeleteOperationRequest__Output as _google_longrunning_DeleteOperationRequest__Output } from '../../google/longrunning/DeleteOperationRequest'; -import type { Empty as _google_protobuf_Empty, Empty__Output as _google_protobuf_Empty__Output } from '../../google/protobuf/Empty'; -import type { GetOperationRequest as _google_longrunning_GetOperationRequest, GetOperationRequest__Output as _google_longrunning_GetOperationRequest__Output } from '../../google/longrunning/GetOperationRequest'; -import type { ListOperationsRequest as _google_longrunning_ListOperationsRequest, ListOperationsRequest__Output as _google_longrunning_ListOperationsRequest__Output } from '../../google/longrunning/ListOperationsRequest'; -import type { ListOperationsResponse as _google_longrunning_ListOperationsResponse, ListOperationsResponse__Output as _google_longrunning_ListOperationsResponse__Output } from '../../google/longrunning/ListOperationsResponse'; -import type { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../google/longrunning/Operation'; -import type { WaitOperationRequest as _google_longrunning_WaitOperationRequest, WaitOperationRequest__Output as _google_longrunning_WaitOperationRequest__Output } from '../../google/longrunning/WaitOperationRequest'; +import type { ICancelOperationRequest as I_google_longrunning_CancelOperationRequest, OCancelOperationRequest as O_google_longrunning_CancelOperationRequest } from '../../google/longrunning/CancelOperationRequest'; +import type { IDeleteOperationRequest as I_google_longrunning_DeleteOperationRequest, ODeleteOperationRequest as O_google_longrunning_DeleteOperationRequest } from '../../google/longrunning/DeleteOperationRequest'; +import type { IEmpty as I_google_protobuf_Empty, OEmpty as O_google_protobuf_Empty } from '../../google/protobuf/Empty'; +import type { IGetOperationRequest as I_google_longrunning_GetOperationRequest, OGetOperationRequest as O_google_longrunning_GetOperationRequest } from '../../google/longrunning/GetOperationRequest'; +import type { IListOperationsRequest as I_google_longrunning_ListOperationsRequest, OListOperationsRequest as O_google_longrunning_ListOperationsRequest } from '../../google/longrunning/ListOperationsRequest'; +import type { IListOperationsResponse as I_google_longrunning_ListOperationsResponse, OListOperationsResponse as O_google_longrunning_ListOperationsResponse } from '../../google/longrunning/ListOperationsResponse'; +import type { IOperation as I_google_longrunning_Operation, OOperation as O_google_longrunning_Operation } from '../../google/longrunning/Operation'; +import type { IWaitOperationRequest as I_google_longrunning_WaitOperationRequest, OWaitOperationRequest as O_google_longrunning_WaitOperationRequest } from '../../google/longrunning/WaitOperationRequest'; /** * Manages long-running operations with an API service. @@ -35,10 +35,10 @@ export interface OperationsClient extends grpc.Client { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - CancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + CancelOperation(argument: I_google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + CancelOperation(argument: I_google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + CancelOperation(argument: I_google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + CancelOperation(argument: I_google_longrunning_CancelOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Starts asynchronous cancellation on a long-running operation. The server * makes a best effort to cancel the operation, but success is not @@ -51,10 +51,10 @@ export interface OperationsClient extends grpc.Client { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - cancelOperation(argument: _google_longrunning_CancelOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + cancelOperation(argument: I_google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + cancelOperation(argument: I_google_longrunning_CancelOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + cancelOperation(argument: I_google_longrunning_CancelOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + cancelOperation(argument: I_google_longrunning_CancelOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is @@ -62,39 +62,39 @@ export interface OperationsClient extends grpc.Client { * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - DeleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + DeleteOperation(argument: I_google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + DeleteOperation(argument: I_google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + DeleteOperation(argument: I_google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + DeleteOperation(argument: I_google_longrunning_DeleteOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is * no longer interested in the operation result. It does not cancel the * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; - deleteOperation(argument: _google_longrunning_DeleteOperationRequest, callback: grpc.requestCallback<_google_protobuf_Empty__Output>): grpc.ClientUnaryCall; + deleteOperation(argument: I_google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + deleteOperation(argument: I_google_longrunning_DeleteOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + deleteOperation(argument: I_google_longrunning_DeleteOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + deleteOperation(argument: I_google_longrunning_DeleteOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - GetOperation(argument: _google_longrunning_GetOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + GetOperation(argument: I_google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + GetOperation(argument: I_google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + GetOperation(argument: I_google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + GetOperation(argument: I_google_longrunning_GetOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - getOperation(argument: _google_longrunning_GetOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + getOperation(argument: I_google_longrunning_GetOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + getOperation(argument: I_google_longrunning_GetOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + getOperation(argument: I_google_longrunning_GetOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + getOperation(argument: I_google_longrunning_GetOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Lists operations that match the specified filter in the request. If the @@ -108,10 +108,10 @@ export interface OperationsClient extends grpc.Client { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; - ListOperations(argument: _google_longrunning_ListOperationsRequest, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + ListOperations(argument: I_google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + ListOperations(argument: I_google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + ListOperations(argument: I_google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + ListOperations(argument: I_google_longrunning_ListOperationsRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Lists operations that match the specified filter in the request. If the * server doesn't support this method, it returns `UNIMPLEMENTED`. @@ -124,10 +124,10 @@ export interface OperationsClient extends grpc.Client { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; - listOperations(argument: _google_longrunning_ListOperationsRequest, callback: grpc.requestCallback<_google_longrunning_ListOperationsResponse__Output>): grpc.ClientUnaryCall; + listOperations(argument: I_google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + listOperations(argument: I_google_longrunning_ListOperationsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + listOperations(argument: I_google_longrunning_ListOperationsRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + listOperations(argument: I_google_longrunning_ListOperationsRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches @@ -140,10 +140,10 @@ export interface OperationsClient extends grpc.Client { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - WaitOperation(argument: _google_longrunning_WaitOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + WaitOperation(argument: I_google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + WaitOperation(argument: I_google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + WaitOperation(argument: I_google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + WaitOperation(argument: I_google_longrunning_WaitOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches * at most a specified timeout, returning the latest state. If the operation @@ -155,10 +155,10 @@ export interface OperationsClient extends grpc.Client { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - waitOperation(argument: _google_longrunning_WaitOperationRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + waitOperation(argument: I_google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + waitOperation(argument: I_google_longrunning_WaitOperationRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + waitOperation(argument: I_google_longrunning_WaitOperationRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + waitOperation(argument: I_google_longrunning_WaitOperationRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; } @@ -186,7 +186,7 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * an [Operation.error][google.longrunning.Operation.error] value with a [google.rpc.Status.code][google.rpc.Status.code] of 1, * corresponding to `Code.CANCELLED`. */ - CancelOperation: grpc.handleUnaryCall<_google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty>; + CancelOperation: grpc.handleUnaryCall; /** * Deletes a long-running operation. This method indicates that the client is @@ -194,14 +194,14 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * operation. If the server doesn't support this method, it returns * `google.rpc.Code.UNIMPLEMENTED`. */ - DeleteOperation: grpc.handleUnaryCall<_google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty>; + DeleteOperation: grpc.handleUnaryCall; /** * Gets the latest state of a long-running operation. Clients can use this * method to poll the operation result at intervals as recommended by the API * service. */ - GetOperation: grpc.handleUnaryCall<_google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation>; + GetOperation: grpc.handleUnaryCall; /** * Lists operations that match the specified filter in the request. If the @@ -215,7 +215,7 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * collection id, however overriding users must ensure the name binding * is the parent resource, without the operations collection id. */ - ListOperations: grpc.handleUnaryCall<_google_longrunning_ListOperationsRequest__Output, _google_longrunning_ListOperationsResponse>; + ListOperations: grpc.handleUnaryCall; /** * Waits for the specified long-running operation until it is done or reaches @@ -228,14 +228,14 @@ export interface OperationsHandlers extends grpc.UntypedServiceImplementation { * state before the specified timeout (including immediately), meaning even an * immediate response is no guarantee that the operation is done. */ - WaitOperation: grpc.handleUnaryCall<_google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation>; + WaitOperation: grpc.handleUnaryCall; } export interface OperationsDefinition extends grpc.ServiceDefinition { - CancelOperation: MethodDefinition<_google_longrunning_CancelOperationRequest, _google_protobuf_Empty, _google_longrunning_CancelOperationRequest__Output, _google_protobuf_Empty__Output> - DeleteOperation: MethodDefinition<_google_longrunning_DeleteOperationRequest, _google_protobuf_Empty, _google_longrunning_DeleteOperationRequest__Output, _google_protobuf_Empty__Output> - GetOperation: MethodDefinition<_google_longrunning_GetOperationRequest, _google_longrunning_Operation, _google_longrunning_GetOperationRequest__Output, _google_longrunning_Operation__Output> - ListOperations: MethodDefinition<_google_longrunning_ListOperationsRequest, _google_longrunning_ListOperationsResponse, _google_longrunning_ListOperationsRequest__Output, _google_longrunning_ListOperationsResponse__Output> - WaitOperation: MethodDefinition<_google_longrunning_WaitOperationRequest, _google_longrunning_Operation, _google_longrunning_WaitOperationRequest__Output, _google_longrunning_Operation__Output> + CancelOperation: MethodDefinition + DeleteOperation: MethodDefinition + GetOperation: MethodDefinition + ListOperations: MethodDefinition + WaitOperation: MethodDefinition } diff --git a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts index f97e39dc4..2f11f7580 100644 --- a/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts +++ b/packages/proto-loader/golden-generated/google/longrunning/WaitOperationRequest.ts @@ -1,11 +1,11 @@ // Original file: deps/googleapis/google/longrunning/operations.proto -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../google/protobuf/Duration'; +import type { IDuration as I_google_protobuf_Duration, ODuration as O_google_protobuf_Duration } from '../../google/protobuf/Duration'; /** * The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. */ -export interface WaitOperationRequest { +export interface IWaitOperationRequest { /** * The name of the operation resource to wait on. */ @@ -15,13 +15,13 @@ export interface WaitOperationRequest { * will be at most the time permitted by the underlying HTTP/RPC protocol. * If RPC context deadline is also specified, the shorter one will be used. */ - 'timeout'?: (_google_protobuf_Duration | null); + 'timeout'?: (I_google_protobuf_Duration | null); } /** * The request message for [Operations.WaitOperation][google.longrunning.Operations.WaitOperation]. */ -export interface WaitOperationRequest__Output { +export interface OWaitOperationRequest { /** * The name of the operation resource to wait on. */ @@ -31,5 +31,5 @@ export interface WaitOperationRequest__Output { * will be at most the time permitted by the underlying HTTP/RPC protocol. * If RPC context deadline is also specified, the shorter one will be used. */ - 'timeout': (_google_protobuf_Duration__Output | null); + 'timeout': (O_google_protobuf_Duration | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/Any.ts b/packages/proto-loader/golden-generated/google/protobuf/Any.ts index fe0d05f12..d9ee4e200 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Any.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Any.ts @@ -2,12 +2,12 @@ import type { AnyExtension } from '@grpc/proto-loader'; -export type Any = AnyExtension | { +export type IAny = AnyExtension | { type_url: string; value: Buffer | Uint8Array | string; } -export type Any__Output = AnyExtension | { +export type OAny = AnyExtension | { type_url: string; value: Buffer; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts index f729437f4..5f568ca2c 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/DescriptorProto.ts @@ -1,53 +1,53 @@ // Original file: null -import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; -import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; -import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import type { MessageOptions as _google_protobuf_MessageOptions, MessageOptions__Output as _google_protobuf_MessageOptions__Output } from '../../google/protobuf/MessageOptions'; -import type { OneofDescriptorProto as _google_protobuf_OneofDescriptorProto, OneofDescriptorProto__Output as _google_protobuf_OneofDescriptorProto__Output } from '../../google/protobuf/OneofDescriptorProto'; +import type { IFieldDescriptorProto as I_google_protobuf_FieldDescriptorProto, OFieldDescriptorProto as O_google_protobuf_FieldDescriptorProto } from '../../google/protobuf/FieldDescriptorProto'; +import type { IDescriptorProto as I_google_protobuf_DescriptorProto, ODescriptorProto as O_google_protobuf_DescriptorProto } from '../../google/protobuf/DescriptorProto'; +import type { IEnumDescriptorProto as I_google_protobuf_EnumDescriptorProto, OEnumDescriptorProto as O_google_protobuf_EnumDescriptorProto } from '../../google/protobuf/EnumDescriptorProto'; +import type { IMessageOptions as I_google_protobuf_MessageOptions, OMessageOptions as O_google_protobuf_MessageOptions } from '../../google/protobuf/MessageOptions'; +import type { IOneofDescriptorProto as I_google_protobuf_OneofDescriptorProto, OOneofDescriptorProto as O_google_protobuf_OneofDescriptorProto } from '../../google/protobuf/OneofDescriptorProto'; -export interface _google_protobuf_DescriptorProto_ExtensionRange { +export interface I_google_protobuf_DescriptorProto_ExtensionRange { 'start'?: (number); 'end'?: (number); } -export interface _google_protobuf_DescriptorProto_ExtensionRange__Output { +export interface O_google_protobuf_DescriptorProto_ExtensionRange { 'start': (number); 'end': (number); } -export interface _google_protobuf_DescriptorProto_ReservedRange { +export interface I_google_protobuf_DescriptorProto_ReservedRange { 'start'?: (number); 'end'?: (number); } -export interface _google_protobuf_DescriptorProto_ReservedRange__Output { +export interface O_google_protobuf_DescriptorProto_ReservedRange { 'start': (number); 'end': (number); } -export interface DescriptorProto { +export interface IDescriptorProto { 'name'?: (string); - 'field'?: (_google_protobuf_FieldDescriptorProto)[]; - 'nestedType'?: (_google_protobuf_DescriptorProto)[]; - 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; - 'extensionRange'?: (_google_protobuf_DescriptorProto_ExtensionRange)[]; - 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'options'?: (_google_protobuf_MessageOptions | null); - 'oneofDecl'?: (_google_protobuf_OneofDescriptorProto)[]; - 'reservedRange'?: (_google_protobuf_DescriptorProto_ReservedRange)[]; + 'field'?: (I_google_protobuf_FieldDescriptorProto)[]; + 'nestedType'?: (I_google_protobuf_DescriptorProto)[]; + 'enumType'?: (I_google_protobuf_EnumDescriptorProto)[]; + 'extensionRange'?: (I_google_protobuf_DescriptorProto_ExtensionRange)[]; + 'extension'?: (I_google_protobuf_FieldDescriptorProto)[]; + 'options'?: (I_google_protobuf_MessageOptions | null); + 'oneofDecl'?: (I_google_protobuf_OneofDescriptorProto)[]; + 'reservedRange'?: (I_google_protobuf_DescriptorProto_ReservedRange)[]; 'reservedName'?: (string)[]; } -export interface DescriptorProto__Output { +export interface ODescriptorProto { 'name': (string); - 'field': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'nestedType': (_google_protobuf_DescriptorProto__Output)[]; - 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; - 'extensionRange': (_google_protobuf_DescriptorProto_ExtensionRange__Output)[]; - 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options': (_google_protobuf_MessageOptions__Output | null); - 'oneofDecl': (_google_protobuf_OneofDescriptorProto__Output)[]; - 'reservedRange': (_google_protobuf_DescriptorProto_ReservedRange__Output)[]; + 'field': (O_google_protobuf_FieldDescriptorProto)[]; + 'nestedType': (O_google_protobuf_DescriptorProto)[]; + 'enumType': (O_google_protobuf_EnumDescriptorProto)[]; + 'extensionRange': (O_google_protobuf_DescriptorProto_ExtensionRange)[]; + 'extension': (O_google_protobuf_FieldDescriptorProto)[]; + 'options': (O_google_protobuf_MessageOptions | null); + 'oneofDecl': (O_google_protobuf_OneofDescriptorProto)[]; + 'reservedRange': (O_google_protobuf_DescriptorProto_ReservedRange)[]; 'reservedName': (string)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts index 8595377a0..d5e3be89a 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Duration.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Duration.ts @@ -2,12 +2,12 @@ import type { Long } from '@grpc/proto-loader'; -export interface Duration { +export interface IDuration { 'seconds'?: (number | string | Long); 'nanos'?: (number); } -export interface Duration__Output { +export interface ODuration { 'seconds': (string); 'nanos': (number); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/Empty.ts b/packages/proto-loader/golden-generated/google/protobuf/Empty.ts index f32c2a284..6594cc86c 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Empty.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Empty.ts @@ -1,8 +1,8 @@ // Original file: null -export interface Empty { +export interface IEmpty { } -export interface Empty__Output { +export interface OEmpty { } diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts index dc4c9673e..30f52c610 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumDescriptorProto.ts @@ -1,16 +1,16 @@ // Original file: null -import type { EnumValueDescriptorProto as _google_protobuf_EnumValueDescriptorProto, EnumValueDescriptorProto__Output as _google_protobuf_EnumValueDescriptorProto__Output } from '../../google/protobuf/EnumValueDescriptorProto'; -import type { EnumOptions as _google_protobuf_EnumOptions, EnumOptions__Output as _google_protobuf_EnumOptions__Output } from '../../google/protobuf/EnumOptions'; +import type { IEnumValueDescriptorProto as I_google_protobuf_EnumValueDescriptorProto, OEnumValueDescriptorProto as O_google_protobuf_EnumValueDescriptorProto } from '../../google/protobuf/EnumValueDescriptorProto'; +import type { IEnumOptions as I_google_protobuf_EnumOptions, OEnumOptions as O_google_protobuf_EnumOptions } from '../../google/protobuf/EnumOptions'; -export interface EnumDescriptorProto { +export interface IEnumDescriptorProto { 'name'?: (string); - 'value'?: (_google_protobuf_EnumValueDescriptorProto)[]; - 'options'?: (_google_protobuf_EnumOptions | null); + 'value'?: (I_google_protobuf_EnumValueDescriptorProto)[]; + 'options'?: (I_google_protobuf_EnumOptions | null); } -export interface EnumDescriptorProto__Output { +export interface OEnumDescriptorProto { 'name': (string); - 'value': (_google_protobuf_EnumValueDescriptorProto__Output)[]; - 'options': (_google_protobuf_EnumOptions__Output | null); + 'value': (O_google_protobuf_EnumValueDescriptorProto)[]; + 'options': (O_google_protobuf_EnumOptions | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts index b92ade4f9..6d2a0c2c6 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumOptions.ts @@ -1,15 +1,15 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; -export interface EnumOptions { +export interface IEnumOptions { 'allowAlias'?: (boolean); 'deprecated'?: (boolean); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; } -export interface EnumOptions__Output { +export interface OEnumOptions { 'allowAlias': (boolean); 'deprecated': (boolean); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts index 7f8e57ea5..44cfcde4a 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueDescriptorProto.ts @@ -1,15 +1,15 @@ // Original file: null -import type { EnumValueOptions as _google_protobuf_EnumValueOptions, EnumValueOptions__Output as _google_protobuf_EnumValueOptions__Output } from '../../google/protobuf/EnumValueOptions'; +import type { IEnumValueOptions as I_google_protobuf_EnumValueOptions, OEnumValueOptions as O_google_protobuf_EnumValueOptions } from '../../google/protobuf/EnumValueOptions'; -export interface EnumValueDescriptorProto { +export interface IEnumValueDescriptorProto { 'name'?: (string); 'number'?: (number); - 'options'?: (_google_protobuf_EnumValueOptions | null); + 'options'?: (I_google_protobuf_EnumValueOptions | null); } -export interface EnumValueDescriptorProto__Output { +export interface OEnumValueDescriptorProto { 'name': (string); 'number': (number); - 'options': (_google_protobuf_EnumValueOptions__Output | null); + 'options': (O_google_protobuf_EnumValueOptions | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts index e60ee6f4c..143381113 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/EnumValueOptions.ts @@ -1,13 +1,13 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; -export interface EnumValueOptions { +export interface IEnumValueOptions { 'deprecated'?: (boolean); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; } -export interface EnumValueOptions__Output { +export interface OEnumValueOptions { 'deprecated': (boolean); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts index c511e2eff..0a713e9dc 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts @@ -1,6 +1,6 @@ // Original file: null -import type { FieldOptions as _google_protobuf_FieldOptions, FieldOptions__Output as _google_protobuf_FieldOptions__Output } from '../../google/protobuf/FieldOptions'; +import type { IFieldOptions as I_google_protobuf_FieldOptions, OFieldOptions as O_google_protobuf_FieldOptions } from '../../google/protobuf/FieldOptions'; // Original file: null @@ -33,7 +33,7 @@ export enum _google_protobuf_FieldDescriptorProto_Type { TYPE_SINT64 = 18, } -export interface FieldDescriptorProto { +export interface IFieldDescriptorProto { 'name'?: (string); 'extendee'?: (string); 'number'?: (number); @@ -41,12 +41,12 @@ export interface FieldDescriptorProto { 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName'?: (string); 'defaultValue'?: (string); - 'options'?: (_google_protobuf_FieldOptions | null); + 'options'?: (I_google_protobuf_FieldOptions | null); 'oneofIndex'?: (number); 'jsonName'?: (string); } -export interface FieldDescriptorProto__Output { +export interface OFieldDescriptorProto { 'name': (string); 'extendee': (string); 'number': (number); @@ -54,7 +54,7 @@ export interface FieldDescriptorProto__Output { 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); 'typeName': (string); 'defaultValue': (string); - 'options': (_google_protobuf_FieldOptions__Output | null); + 'options': (O_google_protobuf_FieldOptions | null); 'oneofIndex': (number); 'jsonName': (string); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts index 8304053f1..076b35983 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; import type { FieldBehavior as _google_api_FieldBehavior } from '../../google/api/FieldBehavior'; // Original file: null @@ -19,24 +19,24 @@ export enum _google_protobuf_FieldOptions_JSType { JS_NUMBER = 2, } -export interface FieldOptions { +export interface IFieldOptions { 'ctype'?: (_google_protobuf_FieldOptions_CType | keyof typeof _google_protobuf_FieldOptions_CType); 'packed'?: (boolean); 'deprecated'?: (boolean); 'lazy'?: (boolean); 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); 'weak'?: (boolean); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; '.google.api.field_behavior'?: (_google_api_FieldBehavior | keyof typeof _google_api_FieldBehavior)[]; } -export interface FieldOptions__Output { +export interface OFieldOptions { 'ctype': (keyof typeof _google_protobuf_FieldOptions_CType); 'packed': (boolean); 'deprecated': (boolean); 'lazy': (boolean); 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); 'weak': (boolean); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; '.google.api.field_behavior': (keyof typeof _google_api_FieldBehavior)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts index b723da7c0..c98732f9d 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorProto.ts @@ -1,37 +1,37 @@ // Original file: null -import type { DescriptorProto as _google_protobuf_DescriptorProto, DescriptorProto__Output as _google_protobuf_DescriptorProto__Output } from '../../google/protobuf/DescriptorProto'; -import type { EnumDescriptorProto as _google_protobuf_EnumDescriptorProto, EnumDescriptorProto__Output as _google_protobuf_EnumDescriptorProto__Output } from '../../google/protobuf/EnumDescriptorProto'; -import type { ServiceDescriptorProto as _google_protobuf_ServiceDescriptorProto, ServiceDescriptorProto__Output as _google_protobuf_ServiceDescriptorProto__Output } from '../../google/protobuf/ServiceDescriptorProto'; -import type { FieldDescriptorProto as _google_protobuf_FieldDescriptorProto, FieldDescriptorProto__Output as _google_protobuf_FieldDescriptorProto__Output } from '../../google/protobuf/FieldDescriptorProto'; -import type { FileOptions as _google_protobuf_FileOptions, FileOptions__Output as _google_protobuf_FileOptions__Output } from '../../google/protobuf/FileOptions'; -import type { SourceCodeInfo as _google_protobuf_SourceCodeInfo, SourceCodeInfo__Output as _google_protobuf_SourceCodeInfo__Output } from '../../google/protobuf/SourceCodeInfo'; +import type { IDescriptorProto as I_google_protobuf_DescriptorProto, ODescriptorProto as O_google_protobuf_DescriptorProto } from '../../google/protobuf/DescriptorProto'; +import type { IEnumDescriptorProto as I_google_protobuf_EnumDescriptorProto, OEnumDescriptorProto as O_google_protobuf_EnumDescriptorProto } from '../../google/protobuf/EnumDescriptorProto'; +import type { IServiceDescriptorProto as I_google_protobuf_ServiceDescriptorProto, OServiceDescriptorProto as O_google_protobuf_ServiceDescriptorProto } from '../../google/protobuf/ServiceDescriptorProto'; +import type { IFieldDescriptorProto as I_google_protobuf_FieldDescriptorProto, OFieldDescriptorProto as O_google_protobuf_FieldDescriptorProto } from '../../google/protobuf/FieldDescriptorProto'; +import type { IFileOptions as I_google_protobuf_FileOptions, OFileOptions as O_google_protobuf_FileOptions } from '../../google/protobuf/FileOptions'; +import type { ISourceCodeInfo as I_google_protobuf_SourceCodeInfo, OSourceCodeInfo as O_google_protobuf_SourceCodeInfo } from '../../google/protobuf/SourceCodeInfo'; -export interface FileDescriptorProto { +export interface IFileDescriptorProto { 'name'?: (string); 'package'?: (string); 'dependency'?: (string)[]; - 'messageType'?: (_google_protobuf_DescriptorProto)[]; - 'enumType'?: (_google_protobuf_EnumDescriptorProto)[]; - 'service'?: (_google_protobuf_ServiceDescriptorProto)[]; - 'extension'?: (_google_protobuf_FieldDescriptorProto)[]; - 'options'?: (_google_protobuf_FileOptions | null); - 'sourceCodeInfo'?: (_google_protobuf_SourceCodeInfo | null); + 'messageType'?: (I_google_protobuf_DescriptorProto)[]; + 'enumType'?: (I_google_protobuf_EnumDescriptorProto)[]; + 'service'?: (I_google_protobuf_ServiceDescriptorProto)[]; + 'extension'?: (I_google_protobuf_FieldDescriptorProto)[]; + 'options'?: (I_google_protobuf_FileOptions | null); + 'sourceCodeInfo'?: (I_google_protobuf_SourceCodeInfo | null); 'publicDependency'?: (number)[]; 'weakDependency'?: (number)[]; 'syntax'?: (string); } -export interface FileDescriptorProto__Output { +export interface OFileDescriptorProto { 'name': (string); 'package': (string); 'dependency': (string)[]; - 'messageType': (_google_protobuf_DescriptorProto__Output)[]; - 'enumType': (_google_protobuf_EnumDescriptorProto__Output)[]; - 'service': (_google_protobuf_ServiceDescriptorProto__Output)[]; - 'extension': (_google_protobuf_FieldDescriptorProto__Output)[]; - 'options': (_google_protobuf_FileOptions__Output | null); - 'sourceCodeInfo': (_google_protobuf_SourceCodeInfo__Output | null); + 'messageType': (O_google_protobuf_DescriptorProto)[]; + 'enumType': (O_google_protobuf_EnumDescriptorProto)[]; + 'service': (O_google_protobuf_ServiceDescriptorProto)[]; + 'extension': (O_google_protobuf_FieldDescriptorProto)[]; + 'options': (O_google_protobuf_FileOptions | null); + 'sourceCodeInfo': (O_google_protobuf_SourceCodeInfo | null); 'publicDependency': (number)[]; 'weakDependency': (number)[]; 'syntax': (string); diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts index 74ded2471..9c940ed5e 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileDescriptorSet.ts @@ -1,11 +1,11 @@ // Original file: null -import type { FileDescriptorProto as _google_protobuf_FileDescriptorProto, FileDescriptorProto__Output as _google_protobuf_FileDescriptorProto__Output } from '../../google/protobuf/FileDescriptorProto'; +import type { IFileDescriptorProto as I_google_protobuf_FileDescriptorProto, OFileDescriptorProto as O_google_protobuf_FileDescriptorProto } from '../../google/protobuf/FileDescriptorProto'; -export interface FileDescriptorSet { - 'file'?: (_google_protobuf_FileDescriptorProto)[]; +export interface IFileDescriptorSet { + 'file'?: (I_google_protobuf_FileDescriptorProto)[]; } -export interface FileDescriptorSet__Output { - 'file': (_google_protobuf_FileDescriptorProto__Output)[]; +export interface OFileDescriptorSet { + 'file': (O_google_protobuf_FileDescriptorProto)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts index 573e847c0..2b832e0f8 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts @@ -1,6 +1,6 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; // Original file: null @@ -10,7 +10,7 @@ export enum _google_protobuf_FileOptions_OptimizeMode { LITE_RUNTIME = 3, } -export interface FileOptions { +export interface IFileOptions { 'javaPackage'?: (string); 'javaOuterClassname'?: (string); 'optimizeFor'?: (_google_protobuf_FileOptions_OptimizeMode | keyof typeof _google_protobuf_FileOptions_OptimizeMode); @@ -25,10 +25,10 @@ export interface FileOptions { 'ccEnableArenas'?: (boolean); 'objcClassPrefix'?: (string); 'csharpNamespace'?: (string); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; } -export interface FileOptions__Output { +export interface OFileOptions { 'javaPackage': (string); 'javaOuterClassname': (string); 'optimizeFor': (keyof typeof _google_protobuf_FileOptions_OptimizeMode); @@ -43,5 +43,5 @@ export interface FileOptions__Output { 'ccEnableArenas': (boolean); 'objcClassPrefix': (string); 'csharpNamespace': (string); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts b/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts index 019fb0e15..62f9dc715 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/GeneratedCodeInfo.ts @@ -1,24 +1,24 @@ // Original file: null -export interface _google_protobuf_GeneratedCodeInfo_Annotation { +export interface I_google_protobuf_GeneratedCodeInfo_Annotation { 'path'?: (number)[]; 'sourceFile'?: (string); 'begin'?: (number); 'end'?: (number); } -export interface _google_protobuf_GeneratedCodeInfo_Annotation__Output { +export interface O_google_protobuf_GeneratedCodeInfo_Annotation { 'path': (number)[]; 'sourceFile': (string); 'begin': (number); 'end': (number); } -export interface GeneratedCodeInfo { - 'annotation'?: (_google_protobuf_GeneratedCodeInfo_Annotation)[]; +export interface IGeneratedCodeInfo { + 'annotation'?: (I_google_protobuf_GeneratedCodeInfo_Annotation)[]; } -export interface GeneratedCodeInfo__Output { - 'annotation': (_google_protobuf_GeneratedCodeInfo_Annotation__Output)[]; +export interface OGeneratedCodeInfo { + 'annotation': (O_google_protobuf_GeneratedCodeInfo_Annotation)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts index 31f669eb0..8c8885e63 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MessageOptions.ts @@ -1,19 +1,19 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; -export interface MessageOptions { +export interface IMessageOptions { 'messageSetWireFormat'?: (boolean); 'noStandardDescriptorAccessor'?: (boolean); 'deprecated'?: (boolean); 'mapEntry'?: (boolean); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; } -export interface MessageOptions__Output { +export interface OMessageOptions { 'messageSetWireFormat': (boolean); 'noStandardDescriptorAccessor': (boolean); 'deprecated': (boolean); 'mapEntry': (boolean); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts index c76c0ea23..0826370df 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodDescriptorProto.ts @@ -1,21 +1,21 @@ // Original file: null -import type { MethodOptions as _google_protobuf_MethodOptions, MethodOptions__Output as _google_protobuf_MethodOptions__Output } from '../../google/protobuf/MethodOptions'; +import type { IMethodOptions as I_google_protobuf_MethodOptions, OMethodOptions as O_google_protobuf_MethodOptions } from '../../google/protobuf/MethodOptions'; -export interface MethodDescriptorProto { +export interface IMethodDescriptorProto { 'name'?: (string); 'inputType'?: (string); 'outputType'?: (string); - 'options'?: (_google_protobuf_MethodOptions | null); + 'options'?: (I_google_protobuf_MethodOptions | null); 'clientStreaming'?: (boolean); 'serverStreaming'?: (boolean); } -export interface MethodDescriptorProto__Output { +export interface OMethodDescriptorProto { 'name': (string); 'inputType': (string); 'outputType': (string); - 'options': (_google_protobuf_MethodOptions__Output | null); + 'options': (O_google_protobuf_MethodOptions | null); 'clientStreaming': (boolean); 'serverStreaming': (boolean); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts index 7581b9643..5f0b69008 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/MethodOptions.ts @@ -1,21 +1,21 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; -import type { OperationInfo as _google_longrunning_OperationInfo, OperationInfo__Output as _google_longrunning_OperationInfo__Output } from '../../google/longrunning/OperationInfo'; -import type { HttpRule as _google_api_HttpRule, HttpRule__Output as _google_api_HttpRule__Output } from '../../google/api/HttpRule'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; +import type { IOperationInfo as I_google_longrunning_OperationInfo, OOperationInfo as O_google_longrunning_OperationInfo } from '../../google/longrunning/OperationInfo'; +import type { IHttpRule as I_google_api_HttpRule, OHttpRule as O_google_api_HttpRule } from '../../google/api/HttpRule'; -export interface MethodOptions { +export interface IMethodOptions { 'deprecated'?: (boolean); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; - '.google.longrunning.operation_info'?: (_google_longrunning_OperationInfo | null); + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; + '.google.longrunning.operation_info'?: (I_google_longrunning_OperationInfo | null); '.google.api.method_signature'?: (string)[]; - '.google.api.http'?: (_google_api_HttpRule | null); + '.google.api.http'?: (I_google_api_HttpRule | null); } -export interface MethodOptions__Output { +export interface OMethodOptions { 'deprecated': (boolean); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; - '.google.longrunning.operation_info': (_google_longrunning_OperationInfo__Output | null); + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; + '.google.longrunning.operation_info': (O_google_longrunning_OperationInfo | null); '.google.api.method_signature': (string)[]; - '.google.api.http': (_google_api_HttpRule__Output | null); + '.google.api.http': (O_google_api_HttpRule | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts index 636f13ed4..6394270ea 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofDescriptorProto.ts @@ -1,13 +1,13 @@ // Original file: null -import type { OneofOptions as _google_protobuf_OneofOptions, OneofOptions__Output as _google_protobuf_OneofOptions__Output } from '../../google/protobuf/OneofOptions'; +import type { IOneofOptions as I_google_protobuf_OneofOptions, OOneofOptions as O_google_protobuf_OneofOptions } from '../../google/protobuf/OneofOptions'; -export interface OneofDescriptorProto { +export interface IOneofDescriptorProto { 'name'?: (string); - 'options'?: (_google_protobuf_OneofOptions | null); + 'options'?: (I_google_protobuf_OneofOptions | null); } -export interface OneofDescriptorProto__Output { +export interface OOneofDescriptorProto { 'name': (string); - 'options': (_google_protobuf_OneofOptions__Output | null); + 'options': (O_google_protobuf_OneofOptions | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts index d81d34797..73280ad73 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/OneofOptions.ts @@ -1,11 +1,11 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; -export interface OneofOptions { - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; +export interface IOneofOptions { + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; } -export interface OneofOptions__Output { - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; +export interface OOneofOptions { + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts index 40c9263ea..a0427fda5 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceDescriptorProto.ts @@ -1,16 +1,16 @@ // Original file: null -import type { MethodDescriptorProto as _google_protobuf_MethodDescriptorProto, MethodDescriptorProto__Output as _google_protobuf_MethodDescriptorProto__Output } from '../../google/protobuf/MethodDescriptorProto'; -import type { ServiceOptions as _google_protobuf_ServiceOptions, ServiceOptions__Output as _google_protobuf_ServiceOptions__Output } from '../../google/protobuf/ServiceOptions'; +import type { IMethodDescriptorProto as I_google_protobuf_MethodDescriptorProto, OMethodDescriptorProto as O_google_protobuf_MethodDescriptorProto } from '../../google/protobuf/MethodDescriptorProto'; +import type { IServiceOptions as I_google_protobuf_ServiceOptions, OServiceOptions as O_google_protobuf_ServiceOptions } from '../../google/protobuf/ServiceOptions'; -export interface ServiceDescriptorProto { +export interface IServiceDescriptorProto { 'name'?: (string); - 'method'?: (_google_protobuf_MethodDescriptorProto)[]; - 'options'?: (_google_protobuf_ServiceOptions | null); + 'method'?: (I_google_protobuf_MethodDescriptorProto)[]; + 'options'?: (I_google_protobuf_ServiceOptions | null); } -export interface ServiceDescriptorProto__Output { +export interface OServiceDescriptorProto { 'name': (string); - 'method': (_google_protobuf_MethodDescriptorProto__Output)[]; - 'options': (_google_protobuf_ServiceOptions__Output | null); + 'method': (O_google_protobuf_MethodDescriptorProto)[]; + 'options': (O_google_protobuf_ServiceOptions | null); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts index c0522eca3..0ddc8e187 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/ServiceOptions.ts @@ -1,17 +1,17 @@ // Original file: null -import type { UninterpretedOption as _google_protobuf_UninterpretedOption, UninterpretedOption__Output as _google_protobuf_UninterpretedOption__Output } from '../../google/protobuf/UninterpretedOption'; +import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; -export interface ServiceOptions { +export interface IServiceOptions { 'deprecated'?: (boolean); - 'uninterpretedOption'?: (_google_protobuf_UninterpretedOption)[]; + 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; '.google.api.default_host'?: (string); '.google.api.oauth_scopes'?: (string); } -export interface ServiceOptions__Output { +export interface OServiceOptions { 'deprecated': (boolean); - 'uninterpretedOption': (_google_protobuf_UninterpretedOption__Output)[]; + 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; '.google.api.default_host': (string); '.google.api.oauth_scopes': (string); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts b/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts index d30e59b4f..4d0856604 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/SourceCodeInfo.ts @@ -1,7 +1,7 @@ // Original file: null -export interface _google_protobuf_SourceCodeInfo_Location { +export interface I_google_protobuf_SourceCodeInfo_Location { 'path'?: (number)[]; 'span'?: (number)[]; 'leadingComments'?: (string); @@ -9,7 +9,7 @@ export interface _google_protobuf_SourceCodeInfo_Location { 'leadingDetachedComments'?: (string)[]; } -export interface _google_protobuf_SourceCodeInfo_Location__Output { +export interface O_google_protobuf_SourceCodeInfo_Location { 'path': (number)[]; 'span': (number)[]; 'leadingComments': (string); @@ -17,10 +17,10 @@ export interface _google_protobuf_SourceCodeInfo_Location__Output { 'leadingDetachedComments': (string)[]; } -export interface SourceCodeInfo { - 'location'?: (_google_protobuf_SourceCodeInfo_Location)[]; +export interface ISourceCodeInfo { + 'location'?: (I_google_protobuf_SourceCodeInfo_Location)[]; } -export interface SourceCodeInfo__Output { - 'location': (_google_protobuf_SourceCodeInfo_Location__Output)[]; +export interface OSourceCodeInfo { + 'location': (O_google_protobuf_SourceCodeInfo_Location)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts index ceaa32b5f..06d756134 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/Timestamp.ts @@ -2,12 +2,12 @@ import type { Long } from '@grpc/proto-loader'; -export interface Timestamp { +export interface ITimestamp { 'seconds'?: (number | string | Long); 'nanos'?: (number); } -export interface Timestamp__Output { +export interface OTimestamp { 'seconds': (string); 'nanos': (number); } diff --git a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts index 433820f55..fa0feaf52 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/UninterpretedOption.ts @@ -2,18 +2,18 @@ import type { Long } from '@grpc/proto-loader'; -export interface _google_protobuf_UninterpretedOption_NamePart { +export interface I_google_protobuf_UninterpretedOption_NamePart { 'namePart'?: (string); 'isExtension'?: (boolean); } -export interface _google_protobuf_UninterpretedOption_NamePart__Output { +export interface O_google_protobuf_UninterpretedOption_NamePart { 'namePart': (string); 'isExtension': (boolean); } -export interface UninterpretedOption { - 'name'?: (_google_protobuf_UninterpretedOption_NamePart)[]; +export interface IUninterpretedOption { + 'name'?: (I_google_protobuf_UninterpretedOption_NamePart)[]; 'identifierValue'?: (string); 'positiveIntValue'?: (number | string | Long); 'negativeIntValue'?: (number | string | Long); @@ -22,8 +22,8 @@ export interface UninterpretedOption { 'aggregateValue'?: (string); } -export interface UninterpretedOption__Output { - 'name': (_google_protobuf_UninterpretedOption_NamePart__Output)[]; +export interface OUninterpretedOption { + 'name': (O_google_protobuf_UninterpretedOption_NamePart)[]; 'identifierValue': (string); 'positiveIntValue': (string); 'negativeIntValue': (string); diff --git a/packages/proto-loader/golden-generated/google/rpc/Status.ts b/packages/proto-loader/golden-generated/google/rpc/Status.ts index 4ce45b6a9..05cf71c5f 100644 --- a/packages/proto-loader/golden-generated/google/rpc/Status.ts +++ b/packages/proto-loader/golden-generated/google/rpc/Status.ts @@ -1,6 +1,6 @@ // Original file: deps/googleapis/google/rpc/status.proto -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../google/protobuf/Any'; +import type { IAny as I_google_protobuf_Any, OAny as O_google_protobuf_Any } from '../../google/protobuf/Any'; /** * The `Status` type defines a logical error model that is suitable for @@ -11,7 +11,7 @@ import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__ * You can find out more about this error model and how to work with it in the * [API Design Guide](https://cloud.google.com/apis/design/errors). */ -export interface Status { +export interface IStatus { /** * The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. */ @@ -26,7 +26,7 @@ export interface Status { * A list of messages that carry the error details. There is a common set of * message types for APIs to use. */ - 'details'?: (_google_protobuf_Any)[]; + 'details'?: (I_google_protobuf_Any)[]; } /** @@ -38,7 +38,7 @@ export interface Status { * You can find out more about this error model and how to work with it in the * [API Design Guide](https://cloud.google.com/apis/design/errors). */ -export interface Status__Output { +export interface OStatus { /** * The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. */ @@ -53,5 +53,5 @@ export interface Status__Output { * A list of messages that carry the error details. There is a common set of * message types for APIs to use. */ - 'details': (_google_protobuf_Any__Output)[]; + 'details': (O_google_protobuf_Any)[]; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts index 383c409c5..29d10f6dd 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockRequest.ts @@ -1,45 +1,45 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; -import type { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; +import type { IDuration as I_google_protobuf_Duration, ODuration as O_google_protobuf_Duration } from '../../../google/protobuf/Duration'; +import type { IStatus as I_google_rpc_Status, OStatus as O_google_rpc_Status } from '../../../google/rpc/Status'; +import type { IBlockResponse as I_google_showcase_v1beta1_BlockResponse, OBlockResponse as O_google_showcase_v1beta1_BlockResponse } from '../../../google/showcase/v1beta1/BlockResponse'; /** * The request for Block method. */ -export interface BlockRequest { +export interface IBlockRequest { /** * The amount of time to block before returning a response. */ - 'response_delay'?: (_google_protobuf_Duration | null); + 'response_delay'?: (I_google_protobuf_Duration | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status | null); + 'error'?: (I_google_rpc_Status | null); /** * The response to be returned that will signify successful method call. */ - 'success'?: (_google_showcase_v1beta1_BlockResponse | null); + 'success'?: (I_google_showcase_v1beta1_BlockResponse | null); 'response'?: "error"|"success"; } /** * The request for Block method. */ -export interface BlockRequest__Output { +export interface OBlockRequest { /** * The amount of time to block before returning a response. */ - 'response_delay': (_google_protobuf_Duration__Output | null); + 'response_delay': (O_google_protobuf_Duration | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status__Output | null); + 'error'?: (O_google_rpc_Status | null); /** * The response to be returned that will signify successful method call. */ - 'success'?: (_google_showcase_v1beta1_BlockResponse__Output | null); + 'success'?: (O_google_showcase_v1beta1_BlockResponse | null); 'response': "error"|"success"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts index 5634b19d4..3bb9bddf2 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/BlockResponse.ts @@ -4,7 +4,7 @@ /** * The response for Block method. */ -export interface BlockResponse { +export interface IBlockResponse { /** * This content can contain anything, the server will not depend on a value * here. @@ -15,7 +15,7 @@ export interface BlockResponse { /** * The response for Block method. */ -export interface BlockResponse__Output { +export interface OBlockResponse { /** * This content can contain anything, the server will not depend on a value * here. diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts index 30ecc8e23..a0330fe68 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Echo.ts @@ -2,15 +2,15 @@ import type * as grpc from '@grpc/grpc-js' import type { MethodDefinition } from '@grpc/proto-loader' -import type { BlockRequest as _google_showcase_v1beta1_BlockRequest, BlockRequest__Output as _google_showcase_v1beta1_BlockRequest__Output } from '../../../google/showcase/v1beta1/BlockRequest'; -import type { BlockResponse as _google_showcase_v1beta1_BlockResponse, BlockResponse__Output as _google_showcase_v1beta1_BlockResponse__Output } from '../../../google/showcase/v1beta1/BlockResponse'; -import type { EchoRequest as _google_showcase_v1beta1_EchoRequest, EchoRequest__Output as _google_showcase_v1beta1_EchoRequest__Output } from '../../../google/showcase/v1beta1/EchoRequest'; -import type { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; -import type { ExpandRequest as _google_showcase_v1beta1_ExpandRequest, ExpandRequest__Output as _google_showcase_v1beta1_ExpandRequest__Output } from '../../../google/showcase/v1beta1/ExpandRequest'; -import type { Operation as _google_longrunning_Operation, Operation__Output as _google_longrunning_Operation__Output } from '../../../google/longrunning/Operation'; -import type { PagedExpandRequest as _google_showcase_v1beta1_PagedExpandRequest, PagedExpandRequest__Output as _google_showcase_v1beta1_PagedExpandRequest__Output } from '../../../google/showcase/v1beta1/PagedExpandRequest'; -import type { PagedExpandResponse as _google_showcase_v1beta1_PagedExpandResponse, PagedExpandResponse__Output as _google_showcase_v1beta1_PagedExpandResponse__Output } from '../../../google/showcase/v1beta1/PagedExpandResponse'; -import type { WaitRequest as _google_showcase_v1beta1_WaitRequest, WaitRequest__Output as _google_showcase_v1beta1_WaitRequest__Output } from '../../../google/showcase/v1beta1/WaitRequest'; +import type { IBlockRequest as I_google_showcase_v1beta1_BlockRequest, OBlockRequest as O_google_showcase_v1beta1_BlockRequest } from '../../../google/showcase/v1beta1/BlockRequest'; +import type { IBlockResponse as I_google_showcase_v1beta1_BlockResponse, OBlockResponse as O_google_showcase_v1beta1_BlockResponse } from '../../../google/showcase/v1beta1/BlockResponse'; +import type { IEchoRequest as I_google_showcase_v1beta1_EchoRequest, OEchoRequest as O_google_showcase_v1beta1_EchoRequest } from '../../../google/showcase/v1beta1/EchoRequest'; +import type { IEchoResponse as I_google_showcase_v1beta1_EchoResponse, OEchoResponse as O_google_showcase_v1beta1_EchoResponse } from '../../../google/showcase/v1beta1/EchoResponse'; +import type { IExpandRequest as I_google_showcase_v1beta1_ExpandRequest, OExpandRequest as O_google_showcase_v1beta1_ExpandRequest } from '../../../google/showcase/v1beta1/ExpandRequest'; +import type { IOperation as I_google_longrunning_Operation, OOperation as O_google_longrunning_Operation } from '../../../google/longrunning/Operation'; +import type { IPagedExpandRequest as I_google_showcase_v1beta1_PagedExpandRequest, OPagedExpandRequest as O_google_showcase_v1beta1_PagedExpandRequest } from '../../../google/showcase/v1beta1/PagedExpandRequest'; +import type { IPagedExpandResponse as I_google_showcase_v1beta1_PagedExpandResponse, OPagedExpandResponse as O_google_showcase_v1beta1_PagedExpandResponse } from '../../../google/showcase/v1beta1/PagedExpandResponse'; +import type { IWaitRequest as I_google_showcase_v1beta1_WaitRequest, OWaitRequest as O_google_showcase_v1beta1_WaitRequest } from '../../../google/showcase/v1beta1/WaitRequest'; /** * This service is used showcase the four main types of rpcs - unary, server @@ -25,115 +25,115 @@ export interface EchoClient extends grpc.Client { * and then return the response or error. * This method showcases how a client handles delays or retries. */ - Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; - Block(argument: _google_showcase_v1beta1_BlockRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + Block(argument: I_google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Block(argument: I_google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Block(argument: I_google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Block(argument: I_google_showcase_v1beta1_BlockRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This method will block (wait) for the requested amount of time * and then return the response or error. * This method showcases how a client handles delays or retries. */ - block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; - block(argument: _google_showcase_v1beta1_BlockRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_BlockResponse__Output>): grpc.ClientUnaryCall; + block(argument: I_google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + block(argument: I_google_showcase_v1beta1_BlockRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + block(argument: I_google_showcase_v1beta1_BlockRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + block(argument: I_google_showcase_v1beta1_BlockRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This method, upon receiving a request on the stream, the same content will * be passed back on the stream. This method showcases bidirectional * streaming rpcs. */ - Chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; - Chat(options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + Chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + Chat(options?: grpc.CallOptions): grpc.ClientDuplexStream; /** * This method, upon receiving a request on the stream, the same content will * be passed back on the stream. This method showcases bidirectional * streaming rpcs. */ - chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; - chat(options?: grpc.CallOptions): grpc.ClientDuplexStream<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse__Output>; + chat(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream; + chat(options?: grpc.CallOptions): grpc.ClientDuplexStream; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - Collect(metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - Collect(options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - Collect(callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + Collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientWritableStream; + Collect(metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientWritableStream; + Collect(options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientWritableStream; + Collect(callback: grpc.requestCallback): grpc.ClientWritableStream; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - collect(metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - collect(options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; - collect(callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientWritableStream<_google_showcase_v1beta1_EchoRequest>; + collect(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientWritableStream; + collect(metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientWritableStream; + collect(options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientWritableStream; + collect(callback: grpc.requestCallback): grpc.ClientWritableStream; /** * This method simply echos the request. This method is showcases unary rpcs. */ - Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; - Echo(argument: _google_showcase_v1beta1_EchoRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: I_google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Echo(argument: I_google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Echo(argument: I_google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Echo(argument: I_google_showcase_v1beta1_EchoRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This method simply echos the request. This method is showcases unary rpcs. */ - echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; - echo(argument: _google_showcase_v1beta1_EchoRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: I_google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + echo(argument: I_google_showcase_v1beta1_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + echo(argument: I_google_showcase_v1beta1_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + echo(argument: I_google_showcase_v1beta1_EchoRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This method split the given content into words and will pass each word back * through the stream. This method showcases server-side streaming rpcs. */ - Expand(argument: _google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; - Expand(argument: _google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + Expand(argument: I_google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream; + Expand(argument: I_google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream; /** * This method split the given content into words and will pass each word back * through the stream. This method showcases server-side streaming rpcs. */ - expand(argument: _google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; - expand(argument: _google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_google_showcase_v1beta1_EchoResponse__Output>; + expand(argument: I_google_showcase_v1beta1_ExpandRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream; + expand(argument: I_google_showcase_v1beta1_ExpandRequest, options?: grpc.CallOptions): grpc.ClientReadableStream; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; - PagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + PagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + PagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + PagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + PagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; - pagedExpand(argument: _google_showcase_v1beta1_PagedExpandRequest, callback: grpc.requestCallback<_google_showcase_v1beta1_PagedExpandResponse__Output>): grpc.ClientUnaryCall; + pagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + pagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + pagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + pagedExpand(argument: I_google_showcase_v1beta1_PagedExpandRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - Wait(argument: _google_showcase_v1beta1_WaitRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + Wait(argument: I_google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Wait(argument: I_google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Wait(argument: I_google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + Wait(argument: I_google_showcase_v1beta1_WaitRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; - wait(argument: _google_showcase_v1beta1_WaitRequest, callback: grpc.requestCallback<_google_longrunning_Operation__Output>): grpc.ClientUnaryCall; + wait(argument: I_google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + wait(argument: I_google_showcase_v1beta1_WaitRequest, metadata: grpc.Metadata, callback: grpc.requestCallback): grpc.ClientUnaryCall; + wait(argument: I_google_showcase_v1beta1_WaitRequest, options: grpc.CallOptions, callback: grpc.requestCallback): grpc.ClientUnaryCall; + wait(argument: I_google_showcase_v1beta1_WaitRequest, callback: grpc.requestCallback): grpc.ClientUnaryCall; } @@ -150,53 +150,53 @@ export interface EchoHandlers extends grpc.UntypedServiceImplementation { * and then return the response or error. * This method showcases how a client handles delays or retries. */ - Block: grpc.handleUnaryCall<_google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse>; + Block: grpc.handleUnaryCall; /** * This method, upon receiving a request on the stream, the same content will * be passed back on the stream. This method showcases bidirectional * streaming rpcs. */ - Chat: grpc.handleBidiStreamingCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>; + Chat: grpc.handleBidiStreamingCall; /** * This method will collect the words given to it. When the stream is closed * by the client, this method will return the a concatenation of the strings * passed to it. This method showcases client-side streaming rpcs. */ - Collect: grpc.handleClientStreamingCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>; + Collect: grpc.handleClientStreamingCall; /** * This method simply echos the request. This method is showcases unary rpcs. */ - Echo: grpc.handleUnaryCall<_google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse>; + Echo: grpc.handleUnaryCall; /** * This method split the given content into words and will pass each word back * through the stream. This method showcases server-side streaming rpcs. */ - Expand: grpc.handleServerStreamingCall<_google_showcase_v1beta1_ExpandRequest__Output, _google_showcase_v1beta1_EchoResponse>; + Expand: grpc.handleServerStreamingCall; /** * This is similar to the Expand method but instead of returning a stream of * expanded words, this method returns a paged list of expanded words. */ - PagedExpand: grpc.handleUnaryCall<_google_showcase_v1beta1_PagedExpandRequest__Output, _google_showcase_v1beta1_PagedExpandResponse>; + PagedExpand: grpc.handleUnaryCall; /** * This method will wait the requested amount of and then return. * This method showcases how a client handles a request timing out. */ - Wait: grpc.handleUnaryCall<_google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation>; + Wait: grpc.handleUnaryCall; } export interface EchoDefinition extends grpc.ServiceDefinition { - Block: MethodDefinition<_google_showcase_v1beta1_BlockRequest, _google_showcase_v1beta1_BlockResponse, _google_showcase_v1beta1_BlockRequest__Output, _google_showcase_v1beta1_BlockResponse__Output> - Chat: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> - Collect: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> - Echo: MethodDefinition<_google_showcase_v1beta1_EchoRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_EchoRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> - Expand: MethodDefinition<_google_showcase_v1beta1_ExpandRequest, _google_showcase_v1beta1_EchoResponse, _google_showcase_v1beta1_ExpandRequest__Output, _google_showcase_v1beta1_EchoResponse__Output> - PagedExpand: MethodDefinition<_google_showcase_v1beta1_PagedExpandRequest, _google_showcase_v1beta1_PagedExpandResponse, _google_showcase_v1beta1_PagedExpandRequest__Output, _google_showcase_v1beta1_PagedExpandResponse__Output> - Wait: MethodDefinition<_google_showcase_v1beta1_WaitRequest, _google_longrunning_Operation, _google_showcase_v1beta1_WaitRequest__Output, _google_longrunning_Operation__Output> + Block: MethodDefinition + Chat: MethodDefinition + Collect: MethodDefinition + Echo: MethodDefinition + Expand: MethodDefinition + PagedExpand: MethodDefinition + Wait: MethodDefinition } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts index fb2bb67d3..649a5d505 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { IStatus as I_google_rpc_Status, OStatus as O_google_rpc_Status } from '../../../google/rpc/Status'; import type { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; /** @@ -9,7 +9,7 @@ import type { Severity as _google_showcase_v1beta1_Severity } from '../../../goo * If status is set in this message * then the status will be returned as an error. */ -export interface EchoRequest { +export interface IEchoRequest { /** * The content to be echoed by the server. */ @@ -17,7 +17,7 @@ export interface EchoRequest { /** * The error to be thrown by the server. */ - 'error'?: (_google_rpc_Status | null); + 'error'?: (I_google_rpc_Status | null); /** * The severity to be echoed by the server. */ @@ -31,7 +31,7 @@ export interface EchoRequest { * If status is set in this message * then the status will be returned as an error. */ -export interface EchoRequest__Output { +export interface OEchoRequest { /** * The content to be echoed by the server. */ @@ -39,7 +39,7 @@ export interface EchoRequest__Output { /** * The error to be thrown by the server. */ - 'error'?: (_google_rpc_Status__Output | null); + 'error'?: (O_google_rpc_Status | null); /** * The severity to be echoed by the server. */ diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts index 3fda238a1..96b7ba25d 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts @@ -5,7 +5,7 @@ import type { Severity as _google_showcase_v1beta1_Severity } from '../../../goo /** * The response message for the Echo methods. */ -export interface EchoResponse { +export interface IEchoResponse { /** * The content specified in the request. */ @@ -19,7 +19,7 @@ export interface EchoResponse { /** * The response message for the Echo methods. */ -export interface EchoResponse__Output { +export interface OEchoResponse { /** * The content specified in the request. */ diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts index 33ce73c1f..4347a617a 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/ExpandRequest.ts @@ -1,11 +1,11 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; +import type { IStatus as I_google_rpc_Status, OStatus as O_google_rpc_Status } from '../../../google/rpc/Status'; /** * The request message for the Expand method. */ -export interface ExpandRequest { +export interface IExpandRequest { /** * The content that will be split into words and returned on the stream. */ @@ -13,13 +13,13 @@ export interface ExpandRequest { /** * The error that is thrown after all words are sent on the stream. */ - 'error'?: (_google_rpc_Status | null); + 'error'?: (I_google_rpc_Status | null); } /** * The request message for the Expand method. */ -export interface ExpandRequest__Output { +export interface OExpandRequest { /** * The content that will be split into words and returned on the stream. */ @@ -27,5 +27,5 @@ export interface ExpandRequest__Output { /** * The error that is thrown after all words are sent on the stream. */ - 'error': (_google_rpc_Status__Output | null); + 'error': (O_google_rpc_Status | null); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts index 13c945134..8c68ba990 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandRequest.ts @@ -4,7 +4,7 @@ /** * The request for the PagedExpand method. */ -export interface PagedExpandRequest { +export interface IPagedExpandRequest { /** * The string to expand. */ @@ -22,7 +22,7 @@ export interface PagedExpandRequest { /** * The request for the PagedExpand method. */ -export interface PagedExpandRequest__Output { +export interface OPagedExpandRequest { /** * The string to expand. */ diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts index 823de43ed..3b3ef90c2 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/PagedExpandResponse.ts @@ -1,15 +1,15 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { EchoResponse as _google_showcase_v1beta1_EchoResponse, EchoResponse__Output as _google_showcase_v1beta1_EchoResponse__Output } from '../../../google/showcase/v1beta1/EchoResponse'; +import type { IEchoResponse as I_google_showcase_v1beta1_EchoResponse, OEchoResponse as O_google_showcase_v1beta1_EchoResponse } from '../../../google/showcase/v1beta1/EchoResponse'; /** * The response for the PagedExpand method. */ -export interface PagedExpandResponse { +export interface IPagedExpandResponse { /** * The words that were expanded. */ - 'responses'?: (_google_showcase_v1beta1_EchoResponse)[]; + 'responses'?: (I_google_showcase_v1beta1_EchoResponse)[]; /** * The next page token. */ @@ -19,11 +19,11 @@ export interface PagedExpandResponse { /** * The response for the PagedExpand method. */ -export interface PagedExpandResponse__Output { +export interface OPagedExpandResponse { /** * The words that were expanded. */ - 'responses': (_google_showcase_v1beta1_EchoResponse__Output)[]; + 'responses': (O_google_showcase_v1beta1_EchoResponse)[]; /** * The next page token. */ diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts index 5f17b4457..ddbe77c22 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitMetadata.ts @@ -1,23 +1,23 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; +import type { ITimestamp as I_google_protobuf_Timestamp, OTimestamp as O_google_protobuf_Timestamp } from '../../../google/protobuf/Timestamp'; /** * The metadata for Wait operation. */ -export interface WaitMetadata { +export interface IWaitMetadata { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp | null); + 'end_time'?: (I_google_protobuf_Timestamp | null); } /** * The metadata for Wait operation. */ -export interface WaitMetadata__Output { +export interface OWaitMetadata { /** * The time that this operation will complete. */ - 'end_time': (_google_protobuf_Timestamp__Output | null); + 'end_time': (O_google_protobuf_Timestamp | null); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts index 46c095b65..331a66947 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitRequest.ts @@ -1,31 +1,31 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { Timestamp as _google_protobuf_Timestamp, Timestamp__Output as _google_protobuf_Timestamp__Output } from '../../../google/protobuf/Timestamp'; -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; -import type { WaitResponse as _google_showcase_v1beta1_WaitResponse, WaitResponse__Output as _google_showcase_v1beta1_WaitResponse__Output } from '../../../google/showcase/v1beta1/WaitResponse'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../google/protobuf/Duration'; +import type { ITimestamp as I_google_protobuf_Timestamp, OTimestamp as O_google_protobuf_Timestamp } from '../../../google/protobuf/Timestamp'; +import type { IStatus as I_google_rpc_Status, OStatus as O_google_rpc_Status } from '../../../google/rpc/Status'; +import type { IWaitResponse as I_google_showcase_v1beta1_WaitResponse, OWaitResponse as O_google_showcase_v1beta1_WaitResponse } from '../../../google/showcase/v1beta1/WaitResponse'; +import type { IDuration as I_google_protobuf_Duration, ODuration as O_google_protobuf_Duration } from '../../../google/protobuf/Duration'; /** * The request for Wait method. */ -export interface WaitRequest { +export interface IWaitRequest { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp | null); + 'end_time'?: (I_google_protobuf_Timestamp | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status | null); + 'error'?: (I_google_rpc_Status | null); /** * The response to be returned on operation completion. */ - 'success'?: (_google_showcase_v1beta1_WaitResponse | null); + 'success'?: (I_google_showcase_v1beta1_WaitResponse | null); /** * The duration of this operation. */ - 'ttl'?: (_google_protobuf_Duration | null); + 'ttl'?: (I_google_protobuf_Duration | null); 'end'?: "end_time"|"ttl"; 'response'?: "error"|"success"; } @@ -33,24 +33,24 @@ export interface WaitRequest { /** * The request for Wait method. */ -export interface WaitRequest__Output { +export interface OWaitRequest { /** * The time that this operation will complete. */ - 'end_time'?: (_google_protobuf_Timestamp__Output | null); + 'end_time'?: (O_google_protobuf_Timestamp | null); /** * The error that will be returned by the server. If this code is specified * to be the OK rpc code, an empty response will be returned. */ - 'error'?: (_google_rpc_Status__Output | null); + 'error'?: (O_google_rpc_Status | null); /** * The response to be returned on operation completion. */ - 'success'?: (_google_showcase_v1beta1_WaitResponse__Output | null); + 'success'?: (O_google_showcase_v1beta1_WaitResponse | null); /** * The duration of this operation. */ - 'ttl'?: (_google_protobuf_Duration__Output | null); + 'ttl'?: (O_google_protobuf_Duration | null); 'end': "end_time"|"ttl"; 'response': "error"|"success"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts index 84b804f6b..667b450e2 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/WaitResponse.ts @@ -4,7 +4,7 @@ /** * The result of the Wait operation. */ -export interface WaitResponse { +export interface IWaitResponse { /** * This content of the result. */ @@ -14,7 +14,7 @@ export interface WaitResponse { /** * The result of the Wait operation. */ -export interface WaitResponse__Output { +export interface OWaitResponse { /** * This content of the result. */ diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index 97e006912..c9cf35b1e 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -24,7 +24,7 @@ "fix": "gts fix", "pretest": "npm run compile", "posttest": "npm run check", - "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json --includeComments -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", + "generate-golden": "node ./build/bin/proto-loader-gen-types.js --keepCase --longs=String --enums=String --defaults --oneofs --json --includeComments --inputTemplate=I%s --outputTemplate=O%s -I deps/gapic-showcase/schema/ deps/googleapis/ -O ./golden-generated --grpcLib @grpc/grpc-js google/showcase/v1beta1/echo.proto", "validate-golden": "rm -rf ./golden-generated-old && mv ./golden-generated/ ./golden-generated-old && npm run generate-golden && diff -rb ./golden-generated ./golden-generated-old" }, "repository": { From d8022a557d978307ebe5a413703f3660172e2661 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 7 Sep 2022 11:16:12 -0700 Subject: [PATCH 1754/1899] grpc-js-xds: Enable outlier detection by default --- packages/grpc-js-xds/src/environment.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index b8b518da4..250f791ac 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -16,4 +16,4 @@ */ export const EXPERIMENTAL_FAULT_INJECTION = (process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION ?? 'true') === 'true'; -export const EXPERIMENTAL_OUTLIER_DETECTION = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION === 'true'; \ No newline at end of file +export const EXPERIMENTAL_OUTLIER_DETECTION = (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; \ No newline at end of file From 3c27ed4c0012f110e55240c7113f4333ea0f6fc4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 7 Sep 2022 12:39:39 -0700 Subject: [PATCH 1755/1899] grpc-js: Update grpc-js outlier detection check to match xds check --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 685cfc60d..52a9bfc95 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -38,7 +38,7 @@ function trace(text: string): void { const TYPE_NAME = 'outlier_detection'; -const OUTLIER_DETECTION_ENABLED = process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION !== 'false'; +const OUTLIER_DETECTION_ENABLED = (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; export interface SuccessRateEjectionConfig { readonly stdev_factor: number; From 51de24ac0ced9a55a714b2c894b0b5f103619761 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 7 Sep 2022 13:11:14 -0700 Subject: [PATCH 1756/1899] grpc-js: Bump to 1.7.0 --- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 9062403cd..fcb9279f0 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.6.1", + "version": "1.7.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.6.0" + "@grpc/grpc-js": "~1.7.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 8ca6eb1c6..d5e5e6927 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.6.12", + "version": "1.7.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 4a861a0d4b84931bd9ff5c16072bb0a496d482dc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 7 Sep 2022 13:13:50 -0700 Subject: [PATCH 1757/1899] grpc-js-xds: Update outlier detection entry in README --- packages/grpc-js-xds/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index 20bd924a8..bbdd98863 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -28,4 +28,4 @@ const client = new MyServiceClient('xds:///example.com:123'); - [xDS Circuit Breaking](https://github.com/grpc/proposal/blob/master/A32-xds-circuit-breaking.md) - [xDS Client-Side Fault Injection](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) - [Client Status Discovery Service](https://github.com/grpc/proposal/blob/master/A40-csds-support.md) - - [Outlier Detection](https://github.com/grpc/proposal/blob/master/A50-xds-outlier-detection.md) (experimental, disabled by default, enabled by setting the environment variable `GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION=true`) \ No newline at end of file + - [Outlier Detection](https://github.com/grpc/proposal/blob/master/A50-xds-outlier-detection.md) \ No newline at end of file From f438191182c5346bc998be1dcaf2263be237f274 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 7 Sep 2022 15:59:17 -0700 Subject: [PATCH 1758/1899] grpc-js: Add tests for outlier detection validation rules --- .../grpc-js/test/test-outlier-detection.ts | 246 ++++++++++++++++++ 1 file changed, 246 insertions(+) diff --git a/packages/grpc-js/test/test-outlier-detection.ts b/packages/grpc-js/test/test-outlier-detection.ts index 977a3058f..74e536767 100644 --- a/packages/grpc-js/test/test-outlier-detection.ts +++ b/packages/grpc-js/test/test-outlier-detection.ts @@ -19,6 +19,7 @@ import * as assert from 'assert'; import * as path from 'path'; import * as grpc from '../src'; import { loadProtoFile } from './common'; +import { OutlierDetectionLoadBalancingConfig } from '../src/load-balancer-outlier-detection' function multiDone(done: Mocha.Done, target: number) { let count = 0; @@ -67,6 +68,251 @@ const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); const EchoService = loadProtoFile(protoFile) .EchoService as grpc.ServiceClientConstructor; +describe('Outlier detection config validation', () => { + describe('interval', () => { + it('Should reject a negative interval', () => { + const loadBalancingConfig = { + interval: { + seconds: -1, + nanos: 0 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /interval parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a large interval', () => { + const loadBalancingConfig = { + interval: { + seconds: 1e12, + nanos: 0 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /interval parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a negative interval.nanos', () => { + const loadBalancingConfig = { + interval: { + seconds: 0, + nanos: -1 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /interval parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a large interval.nanos', () => { + const loadBalancingConfig = { + interval: { + seconds: 0, + nanos: 1e12 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /interval parse error: values out of range for non-negative Duaration/); + }); + }); + describe('base_ejection_time', () => { + it('Should reject a negative base_ejection_time', () => { + const loadBalancingConfig = { + base_ejection_time: { + seconds: -1, + nanos: 0 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /base_ejection_time parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a large base_ejection_time', () => { + const loadBalancingConfig = { + base_ejection_time: { + seconds: 1e12, + nanos: 0 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /base_ejection_time parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a negative base_ejection_time.nanos', () => { + const loadBalancingConfig = { + base_ejection_time: { + seconds: 0, + nanos: -1 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /base_ejection_time parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a large base_ejection_time.nanos', () => { + const loadBalancingConfig = { + base_ejection_time: { + seconds: 0, + nanos: 1e12 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /base_ejection_time parse error: values out of range for non-negative Duaration/); + }); + }); + describe('max_ejection_time', () => { + it('Should reject a negative max_ejection_time', () => { + const loadBalancingConfig = { + max_ejection_time: { + seconds: -1, + nanos: 0 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /max_ejection_time parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a large max_ejection_time', () => { + const loadBalancingConfig = { + max_ejection_time: { + seconds: 1e12, + nanos: 0 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /max_ejection_time parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a negative max_ejection_time.nanos', () => { + const loadBalancingConfig = { + max_ejection_time: { + seconds: 0, + nanos: -1 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /max_ejection_time parse error: values out of range for non-negative Duaration/); + }); + it('Should reject a large max_ejection_time.nanos', () => { + const loadBalancingConfig = { + max_ejection_time: { + seconds: 0, + nanos: 1e12 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /max_ejection_time parse error: values out of range for non-negative Duaration/); + }); + }); + describe('max_ejection_percent', () => { + it('Should reject a value above 100', () => { + const loadBalancingConfig = { + max_ejection_percent: 101, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /max_ejection_percent parse error: value out of range for percentage/); + }); + it('Should reject a negative value', () => { + const loadBalancingConfig = { + max_ejection_percent: -1, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /max_ejection_percent parse error: value out of range for percentage/); + }); + }); + describe('success_rate_ejection.enforcement_percentage', () => { + it('Should reject a value above 100', () => { + const loadBalancingConfig = { + success_rate_ejection: { + enforcement_percentage: 101 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /success_rate_ejection\.enforcement_percentage parse error: value out of range for percentage/); + }); + it('Should reject a negative value', () => { + const loadBalancingConfig = { + success_rate_ejection: { + enforcement_percentage: -1 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /success_rate_ejection\.enforcement_percentage parse error: value out of range for percentage/); + }); + }); + describe('failure_percentage_ejection.threshold', () => { + it('Should reject a value above 100', () => { + const loadBalancingConfig = { + failure_percentage_ejection: { + threshold: 101 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /failure_percentage_ejection\.threshold parse error: value out of range for percentage/); + }); + it('Should reject a negative value', () => { + const loadBalancingConfig = { + failure_percentage_ejection: { + threshold: -1 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /failure_percentage_ejection\.threshold parse error: value out of range for percentage/); + }); + }); + describe('failure_percentage_ejection.enforcement_percentage', () => { + it('Should reject a value above 100', () => { + const loadBalancingConfig = { + failure_percentage_ejection: { + enforcement_percentage: 101 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /failure_percentage_ejection\.enforcement_percentage parse error: value out of range for percentage/); + }); + it('Should reject a negative value', () => { + const loadBalancingConfig = { + failure_percentage_ejection: { + enforcement_percentage: -1 + }, + child_policy: [{round_robin: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /failure_percentage_ejection\.enforcement_percentage parse error: value out of range for percentage/); + }); + }); +}); + describe('Outlier detection', () => { const GOOD_PORTS = 4; let goodServer: grpc.Server; From b0e28f7f939f4989cbb4ac400accd1cf7db8319f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Sep 2022 11:20:19 -0700 Subject: [PATCH 1759/1899] grpc-js: Add test for sending metadata from call creds on channel creds --- .../grpc-js/test/test-channel-credentials.ts | 74 ++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index d6028f469..2b537ac97 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -17,12 +17,22 @@ import * as assert from 'assert'; import * as fs from 'fs'; +import * as path from 'path'; import { promisify } from 'util'; +import * as protoLoader from '@grpc/proto-loader'; import { CallCredentials } from '../src/call-credentials'; import { ChannelCredentials } from '../src/channel-credentials'; +import * as grpc from '../src'; +import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; +import { TestServiceClient, TestServiceHandlers } from './generated/TestService'; +import { ProtoGrpcType as TestServiceGrpcType } from './generated/test_service'; -import { assert2, mockFunction } from './common'; +import { assert2, loadProtoFile, mockFunction } from './common'; +import { sendUnaryData, ServerUnaryCall, ServiceError } from '../src'; + +const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); +const echoService = loadProtoFile(protoFile).EchoService as ServiceClientConstructor; class CallCredentialsMock implements CallCredentials { child: CallCredentialsMock | null = null; @@ -138,3 +148,65 @@ describe('ChannelCredentials Implementation', () => { }); }); }); + +describe('ChannelCredentials usage', () => { + let client: ServiceClient; + let server: grpc.Server; + before(async () => { + const {ca, key, cert} = await pFixtures; + const serverCreds = grpc.ServerCredentials.createSsl(null, [{private_key: key, cert_chain: cert}]); + const channelCreds = ChannelCredentials.createSsl(ca); + const callCreds = CallCredentials.createFromMetadataGenerator((options, cb) => { + const metadata = new grpc.Metadata(); + metadata.set('test-key', 'test-value'); + cb(null, metadata); + }); + const combinedCreds = channelCreds.compose(callCreds); + return new Promise((resolve, reject) => { + + server = new grpc.Server(); + server.addService(echoService.service, { + echo(call: ServerUnaryCall, callback: sendUnaryData) { + call.sendMetadata(call.metadata); + callback(null, call.request); + }, + }); + + server.bindAsync( + 'localhost:0', + serverCreds, + (err, port) => { + if (err) { + reject(err); + return; + } + client = new echoService( + `localhost:${port}`, + combinedCreds, + {'grpc.ssl_target_name_override': 'foo.test.google.fr', 'grpc.default_authority': 'foo.test.google.fr'} + ); + server.start(); + resolve(); + } + ); + }); + }); + after(() => { + server.forceShutdown(); + }); + + it('Should send the metadata from call credentials attached to channel credentials', (done) => { + const call = client.echo( + { value: 'test value', value2: 3 }, + assert2.mustCall((error: ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + }) + ); + call.on('metadata', assert2.mustCall((metadata: grpc.Metadata) => { + assert.deepStrictEqual(metadata.get('test-key'), ['test-value']); + + })); + assert2.afterMustCallsSatisfied(done); + }); +}); \ No newline at end of file From 9269f3a76f7c72d643ef5ad0db1261da08045bf1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Sep 2022 11:46:06 -0700 Subject: [PATCH 1760/1899] grpc-js: Restrict control-plane status codes --- packages/grpc-js/src/channel.ts | 47 ++++++++++++++++++++++----------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 88bf3a7e0..53b80c1cf 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -68,6 +68,28 @@ function getNewCallNumber(): number { return callNumber; } +const INAPPPROPRIATE_CONTROL_PLANE_CODES: Status[] = [ + Status.OK, + Status.INVALID_ARGUMENT, + Status.NOT_FOUND, + Status.ALREADY_EXISTS, + Status.FAILED_PRECONDITION, + Status.ABORTED, + Status.OUT_OF_RANGE, + Status.DATA_LOSS +] + +function restrictControlPlaneStatusCode(code: Status, details: string): {code: Status, details: string} { + if (INAPPPROPRIATE_CONTROL_PLANE_CODES.includes(code)) { + return { + code: Status.INTERNAL, + details: `Invalid status from control plane: ${code} ${Status[code]} ${details}` + } + } else { + return {code, details}; + } +} + /** * An interface that represents a communication channel to a server specified * by a given address. @@ -320,7 +342,7 @@ export class ChannelImplementation implements Channel { this.trace('Name resolution failed with calls queued for config selection'); } if (this.configSelector === null) { - this.currentResolutionError = status; + this.currentResolutionError = {...restrictControlPlaneStatusCode(status.code, status.details), metadata: status.metadata}; } const localQueue = this.configSelectionQueue; this.configSelectionQueue = []; @@ -534,10 +556,11 @@ export class ChannelImplementation implements Channel { }, (error: Error & { code: number }) => { // We assume the error code isn't 0 (Status.OK) - callStream.cancelWithStatus( + const {code, details} = restrictControlPlaneStatusCode( typeof error.code === 'number' ? error.code : Status.UNKNOWN, `Getting metadata from plugin failed with error: ${error.message}` - ); + ) + callStream.cancelWithStatus(code, details); } ); } @@ -549,17 +572,13 @@ export class ChannelImplementation implements Channel { if (callMetadata.getOptions().waitForReady) { this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); } else { - callStream.cancelWithStatus( - pickResult.status!.code, - pickResult.status!.details - ); + const {code, details} = restrictControlPlaneStatusCode(pickResult.status!.code, pickResult.status!.details); + callStream.cancelWithStatus(code, details); } break; case PickResultType.DROP: - callStream.cancelWithStatus( - pickResult.status!.code, - pickResult.status!.details - ); + const {code, details} = restrictControlPlaneStatusCode(pickResult.status!.code, pickResult.status!.details); + callStream.cancelWithStatus(code, details); break; default: throw new Error( @@ -668,10 +687,8 @@ export class ChannelImplementation implements Channel { this.tryPick(stream, metadata, callConfig, []); } } else { - stream.cancelWithStatus( - callConfig.status, - 'Failed to route call to method ' + stream.getMethod() - ); + const {code, details} = restrictControlPlaneStatusCode(callConfig.status, 'Failed to route call to method ' + stream.getMethod()); + stream.cancelWithStatus(code, details); } } } From caf37e4f15b7837c03bf182696676ddeb0fbbfbf Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Sep 2022 12:42:44 -0700 Subject: [PATCH 1761/1899] Fix constant name spelling --- packages/grpc-js/src/channel.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 53b80c1cf..93b2204c6 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -68,7 +68,7 @@ function getNewCallNumber(): number { return callNumber; } -const INAPPPROPRIATE_CONTROL_PLANE_CODES: Status[] = [ +const INAPPROPRIATE_CONTROL_PLANE_CODES: Status[] = [ Status.OK, Status.INVALID_ARGUMENT, Status.NOT_FOUND, @@ -80,7 +80,7 @@ const INAPPPROPRIATE_CONTROL_PLANE_CODES: Status[] = [ ] function restrictControlPlaneStatusCode(code: Status, details: string): {code: Status, details: string} { - if (INAPPPROPRIATE_CONTROL_PLANE_CODES.includes(code)) { + if (INAPPROPRIATE_CONTROL_PLANE_CODES.includes(code)) { return { code: Status.INTERNAL, details: `Invalid status from control plane: ${code} ${Status[code]} ${details}` From 02a43a302d563115c20ec95ec4818e6e21fba542 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 12 Sep 2022 13:47:57 -0700 Subject: [PATCH 1762/1899] grpc-js-xds: NACK WeightedCluster if total_weight is 0 --- packages/grpc-js-xds/src/xds-stream-state/rds-state.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 77a84469b..a5d3c47cf 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -89,6 +89,9 @@ export class RdsState extends BaseXdsStreamState imp } } if (route.route!.cluster_specifier === 'weighted_clusters') { + if (route.route.weighted_clusters!.total_weight?.value === 0) { + return false; + } let weightSum = 0; for (const clusterWeight of route.route.weighted_clusters!.clusters) { weightSum += clusterWeight.weight?.value ?? 0; From 640a1963c741b7721b00f462801958433a27a805 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Sep 2022 16:20:22 -0700 Subject: [PATCH 1763/1899] grpc-js: Defer evaluating caller stack until an error --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/client.ts | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d5e5e6927..c0db93ae0 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.7.0", + "version": "1.7.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 747c5c877..112fb7c7c 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -321,7 +321,7 @@ export class Client { } let responseMessage: ResponseType | null = null; let receivedStatus = false; - const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); + const callerStackError = new Error(); call.start(callProperties.metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -340,6 +340,7 @@ export class Client { receivedStatus = true; if (status.code === Status.OK) { if (responseMessage === null) { + const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); callProperties.callback!(callErrorFromStatus({ code: Status.INTERNAL, details: 'No message received', @@ -349,6 +350,7 @@ export class Client { callProperties.callback!(null, responseMessage); } } else { + const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); callProperties.callback!(callErrorFromStatus(status, callerStack)); } emitter.emit('status', status); @@ -447,7 +449,7 @@ export class Client { } let responseMessage: ResponseType | null = null; let receivedStatus = false; - const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); + const callerStackError = new Error(); call.start(callProperties.metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -466,6 +468,7 @@ export class Client { receivedStatus = true; if (status.code === Status.OK) { if (responseMessage === null) { + const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); callProperties.callback!(callErrorFromStatus({ code: Status.INTERNAL, details: 'No message received', @@ -475,6 +478,7 @@ export class Client { callProperties.callback!(null, responseMessage); } } else { + const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); callProperties.callback!(callErrorFromStatus(status, callerStack)); } emitter.emit('status', status); @@ -577,7 +581,7 @@ export class Client { call.setCredentials(callProperties.callOptions.credentials); } let receivedStatus = false; - const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); + const callerStackError = new Error(); call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -593,6 +597,7 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { + const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); stream.emit('error', callErrorFromStatus(status, callerStack)); } stream.emit('status', status); @@ -675,7 +680,7 @@ export class Client { call.setCredentials(callProperties.callOptions.credentials); } let receivedStatus = false; - const callerStack = (new Error().stack!).split('\n').slice(1).join('\n'); + const callerStackError = new Error(); call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -690,6 +695,7 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { + const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); stream.emit('error', callErrorFromStatus(status, callerStack)); } stream.emit('status', status); From 5b42e999e4182ac26dbce77c43374c0a4a02d206 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Sep 2022 16:33:01 -0700 Subject: [PATCH 1764/1899] grpc-js: Refactor getting stack trace into function --- packages/grpc-js/src/client.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index 112fb7c7c..1198dc468 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -108,6 +108,10 @@ export type ClientOptions = Partial & { callInvocationTransformer?: CallInvocationTransformer; }; +function getErrorStackString(error: Error): string { + return error.stack!.split('\n').slice(1).join('\n'); +} + /** * A generic gRPC client. Primarily useful as a base class for all generated * clients. @@ -340,7 +344,7 @@ export class Client { receivedStatus = true; if (status.code === Status.OK) { if (responseMessage === null) { - const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); + const callerStack = getErrorStackString(callerStackError); callProperties.callback!(callErrorFromStatus({ code: Status.INTERNAL, details: 'No message received', @@ -350,7 +354,7 @@ export class Client { callProperties.callback!(null, responseMessage); } } else { - const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); + const callerStack = getErrorStackString(callerStackError); callProperties.callback!(callErrorFromStatus(status, callerStack)); } emitter.emit('status', status); @@ -468,7 +472,7 @@ export class Client { receivedStatus = true; if (status.code === Status.OK) { if (responseMessage === null) { - const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); + const callerStack = getErrorStackString(callerStackError); callProperties.callback!(callErrorFromStatus({ code: Status.INTERNAL, details: 'No message received', @@ -478,7 +482,7 @@ export class Client { callProperties.callback!(null, responseMessage); } } else { - const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); + const callerStack = getErrorStackString(callerStackError); callProperties.callback!(callErrorFromStatus(status, callerStack)); } emitter.emit('status', status); @@ -597,7 +601,7 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { - const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); + const callerStack = getErrorStackString(callerStackError); stream.emit('error', callErrorFromStatus(status, callerStack)); } stream.emit('status', status); @@ -695,7 +699,7 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { - const callerStack = callerStackError.stack!.split('\n').slice(1).join('\n'); + const callerStack = getErrorStackString(callerStackError); stream.emit('error', callErrorFromStatus(status, callerStack)); } stream.emit('status', status); From 1c0b6459feaf8fa5aa393259ec10e4f1a30e3ada Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 21 Sep 2022 10:44:59 -0700 Subject: [PATCH 1765/1899] proto-loader: Bump to 0.7.3 --- packages/proto-loader/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/proto-loader/package.json b/packages/proto-loader/package.json index c9cf35b1e..cae7635f6 100644 --- a/packages/proto-loader/package.json +++ b/packages/proto-loader/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/proto-loader", - "version": "0.7.2", + "version": "0.7.3", "author": "Google Inc.", "contributors": [ { From 2aac1da48e82fc3663b75f18c527ffe56ae6cc79 Mon Sep 17 00:00:00 2001 From: Ryosuke Hayashi Date: Sun, 2 Oct 2022 19:13:19 +0900 Subject: [PATCH 1766/1899] Build arm64 binaries for mac --- packages/grpc-tools/build_binaries.sh | 61 +++++++++++++++------------ 1 file changed, 34 insertions(+), 27 deletions(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index b26946afa..73f95f6d2 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -27,38 +27,45 @@ tools_version=$(jq '.version' < package.json | tr -d '"') out_dir=$base/../../artifacts/grpc-tools/v$tools_version mkdir -p "$out_dir" -case $(uname -s) in - Linux) - platform=linux - arch_list=( ia32 x64 ) - ;; - Darwin) - platform=darwin - arch_list=( x64 ) - ;; -esac +build () { + cmake_flag=$* -for arch in "${arch_list[@]}"; do - case $arch in - ia32) - toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_32bit.toolchain.cmake - ;; - *) - toolchain_flag=-DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake - ;; - esac - rm -f $base/build/bin/protoc - rm -f $base/build/bin/grpc_node_plugin + rm -rf $base/build/bin rm -f $base/CMakeCache.txt rm -rf $base/CMakeFiles rm -f $protobuf_base/CMakeCache.txt rm -rf $protobuf_base/CMakeFiles - cmake $toolchain_flag . && cmake --build . --target clean && cmake --build . -- -j 12 - mkdir -p "$base/build/bin" + cmake $cmake_flag . && cmake --build . --target clean && cmake --build . -- -j 12 + mkdir -p $base/build/bin cp -L $protobuf_base/protoc $base/build/bin/protoc cp $base/grpc_node_plugin $base/build/bin/ file $base/build/bin/* - cd $base/build - tar -czf "$out_dir/$platform-$arch.tar.gz" bin/ - cd $base -done \ No newline at end of file +} + +artifacts() { + platform=$1 + arch=$2 + dir=$3 + + tar -czf $out_dir/$platform-$arch.tar.gz -C $(dirname $dir) $(basename $dir) +} + +case $(uname -s) in + Linux) + build -DCMAKE_TOOLCHAIN_FILE=linux_32bit.toolchain.cmake + artifacts linux ia32 $base/build/bin + build -DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake + artifacts linux x64 $base/build/bin + ;; + Darwin) + build -DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" + + for arch in "x86_64" "arm64"; do + mkdir $base/build/bin/$arch + for bin in protoc grpc_node_plugin; do + lipo -extract x86_64 $base/build/bin/$bin -o $base/build/bin/$arch/$bin + done + artifacts darwin $arch $base/build/bin/$arch/ + done + ;; +esac From 7bbbf0d460271e02df9549f070cfa4cd48f57b64 Mon Sep 17 00:00:00 2001 From: nakamura-k30 <51692717+nakamura-k30@users.noreply.github.com> Date: Tue, 4 Oct 2022 20:12:46 +0900 Subject: [PATCH 1767/1899] list undocumented tracers --- doc/environment_variables.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/environment_variables.md b/doc/environment_variables.md index 0237dff7e..70b32e715 100644 --- a/doc/environment_variables.md +++ b/doc/environment_variables.md @@ -29,6 +29,7 @@ can be set. - `channel` - Traces channel events - `connectivity_state` - Traces channel connectivity state changes - `dns_resolver` - Traces DNS resolution + - `ip_resolver` - Traces IPv4/v6 resolution - `pick_first` - Traces the pick first load balancing policy - `proxy` - Traces proxy operations - `resolving_load_balancer` - Traces the resolving load balancer @@ -40,6 +41,9 @@ can be set. - `subchannel_flowctrl` - Traces HTTP/2 flow control. Includes per-call logs. - `subchannel_internals` - Traces HTTP/2 session state. Includes per-call logs. - `channel_stacktrace` - Traces channel construction events with stack traces. + - `keepalive` - Traces gRPC keepalive pings + - `index` - Traces module loading + - `outlier_detection` - Traces outlier detection events The following tracers are added by the `@grpc/grpc-js-xds` library: - `cds_balancer` - Traces the CDS load balancing policy From 98d2506139110f1a604bb9ec871f7833af8178dd Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Oct 2022 09:54:42 -0700 Subject: [PATCH 1768/1899] grpc-tools: Bump to version 1.11.3 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 95faa84c4..1c7deb250 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.11.2", + "version": "1.11.3", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 7229fc28eb90618fe6f54da0b8a345dc379852c6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 5 Oct 2022 13:22:51 -0700 Subject: [PATCH 1769/1899] grpc-tools: Fix x64 arch name in build script --- packages/grpc-tools/build_binaries.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index 73f95f6d2..e44881083 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -60,7 +60,7 @@ case $(uname -s) in Darwin) build -DCMAKE_TOOLCHAIN_FILE=linux_64bit.toolchain.cmake -DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" - for arch in "x86_64" "arm64"; do + for arch in "x64" "arm64"; do mkdir $base/build/bin/$arch for bin in protoc grpc_node_plugin; do lipo -extract x86_64 $base/build/bin/$bin -o $base/build/bin/$arch/$bin From 7942b23e79567d74b6b9d8796ab15f985f6926e2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 10 Oct 2022 14:11:16 -0700 Subject: [PATCH 1770/1899] grpc-js-xds: Validate that endpoint weights sum to no more than 32 bit uint max per priority --- packages/grpc-js-xds/src/xds-stream-state/eds-state.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index 91cb6f30f..dd1adf18a 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -50,6 +50,7 @@ export class EdsState extends BaseXdsStreamState */ public validateResponse(message: ClusterLoadAssignment__Output) { const seenLocalities: {locality: Locality__Output, priority: number}[] = []; + const priorityTotalWeights: Map = new Map(); for (const endpoint of message.endpoints) { if (!endpoint.locality) { return false; @@ -72,6 +73,12 @@ export class EdsState extends BaseXdsStreamState return false; } } + priorityTotalWeights.set(endpoint.priority, (priorityTotalWeights.get(endpoint.priority) ?? 0) + (endpoint.load_balancing_weight?.value ?? 0)); + } + for (const totalWeight of priorityTotalWeights.values()) { + if (totalWeight >= 1<<32) { + return false; + } } return true; } From 8832fc2d39d25417e59eeea295333c6525c9f6a3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 11 Oct 2022 13:55:19 -0700 Subject: [PATCH 1771/1899] grpc-js-xds: Validate uniqueness of addresses in EDS updates --- .../grpc-js-xds/src/xds-stream-state/eds-state.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index dd1adf18a..370cf7502 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -18,6 +18,7 @@ import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; import { isIPv4, isIPv6 } from "net"; import { Locality__Output } from "../generated/envoy/config/core/v3/Locality"; +import { SocketAddress__Output } from "../generated/envoy/config/core/v3/SocketAddress"; import { ClusterLoadAssignment__Output } from "../generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; import { Any__Output } from "../generated/google/protobuf/Any"; import { BaseXdsStreamState, HandleResponseResult, RejectedResourceEntry, ResourcePair, Watcher, XdsStreamState } from "./xds-stream-state"; @@ -32,6 +33,10 @@ function localitiesEqual(a: Locality__Output, b: Locality__Output) { return a.region === b.region && a.sub_zone === b.sub_zone && a.zone === b.zone; } +function addressesEqual(a: SocketAddress__Output, b: SocketAddress__Output) { + return a.address === b.address && a.port_value === b.port_value; +} + export class EdsState extends BaseXdsStreamState implements XdsStreamState { protected getResourceName(resource: ClusterLoadAssignment__Output): string { return resource.cluster_name; @@ -50,6 +55,7 @@ export class EdsState extends BaseXdsStreamState */ public validateResponse(message: ClusterLoadAssignment__Output) { const seenLocalities: {locality: Locality__Output, priority: number}[] = []; + const seenAddresses: SocketAddress__Output[] = []; const priorityTotalWeights: Map = new Map(); for (const endpoint of message.endpoints) { if (!endpoint.locality) { @@ -72,6 +78,12 @@ export class EdsState extends BaseXdsStreamState if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { return false; } + for (const address of seenAddresses) { + if (addressesEqual(socketAddress, address)) { + return false; + } + } + seenAddresses.push(socketAddress); } priorityTotalWeights.set(endpoint.priority, (priorityTotalWeights.get(endpoint.priority) ?? 0) + (endpoint.load_balancing_weight?.value ?? 0)); } From bedc9628f5614f5f020c52a40dea064c53834371 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 11 Oct 2022 13:58:57 -0700 Subject: [PATCH 1772/1899] grpc-js-xds: Validate continuity of priorities in EDS updates --- packages/grpc-js-xds/src/xds-stream-state/eds-state.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index 370cf7502..9b7b9cd5f 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -92,6 +92,11 @@ export class EdsState extends BaseXdsStreamState return false; } } + for (const priority of priorityTotalWeights.keys()) { + if (priority > 0 && !priorityTotalWeights.has(priority - 1)) { + return false; + } + } return true; } } \ No newline at end of file From 339eb37efd5fc6e7da177036913a0840c81c1195 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 26 Apr 2022 10:03:08 -0700 Subject: [PATCH 1773/1899] grpc-js: Refactor in preparation for retries --- .../grpc-js/src/call-credentials-filter.ts | 86 -- packages/grpc-js/src/call-interface.ts | 169 ++++ packages/grpc-js/src/call-number.ts | 22 + packages/grpc-js/src/call-stream.ts | 882 ------------------ packages/grpc-js/src/call.ts | 2 +- packages/grpc-js/src/channel.ts | 653 +------------ packages/grpc-js/src/client-interceptors.ts | 2 +- packages/grpc-js/src/client.ts | 3 +- packages/grpc-js/src/compression-filter.ts | 4 +- packages/grpc-js/src/deadline-filter.ts | 120 --- packages/grpc-js/src/deadline.ts | 58 ++ packages/grpc-js/src/experimental.ts | 2 +- packages/grpc-js/src/filter-stack.ts | 14 +- packages/grpc-js/src/filter.ts | 12 +- packages/grpc-js/src/index.ts | 5 +- packages/grpc-js/src/internal-channel.ts | 504 ++++++++++ .../src/load-balancer-outlier-detection.ts | 34 +- .../grpc-js/src/load-balancer-pick-first.ts | 2 +- .../grpc-js/src/load-balancer-round-robin.ts | 2 +- packages/grpc-js/src/load-balancing-call.ts | 281 ++++++ .../grpc-js/src/max-message-size-filter.ts | 30 +- packages/grpc-js/src/picker.ts | 23 +- packages/grpc-js/src/resolver-dns.ts | 2 +- packages/grpc-js/src/resolver-ip.ts | 2 +- packages/grpc-js/src/resolver.ts | 2 +- packages/grpc-js/src/resolving-call.ts | 219 +++++ .../grpc-js/src/resolving-load-balancer.ts | 2 +- packages/grpc-js/src/server-call.ts | 5 +- packages/grpc-js/src/service-config.ts | 23 + packages/grpc-js/src/status-builder.ts | 2 +- packages/grpc-js/src/subchannel-call.ts | 504 ++++++++++ packages/grpc-js/src/subchannel.ts | 91 +- packages/grpc-js/test/test-resolver.ts | 2 +- 33 files changed, 1886 insertions(+), 1878 deletions(-) delete mode 100644 packages/grpc-js/src/call-credentials-filter.ts create mode 100644 packages/grpc-js/src/call-interface.ts create mode 100644 packages/grpc-js/src/call-number.ts delete mode 100644 packages/grpc-js/src/call-stream.ts delete mode 100644 packages/grpc-js/src/deadline-filter.ts create mode 100644 packages/grpc-js/src/deadline.ts create mode 100644 packages/grpc-js/src/internal-channel.ts create mode 100644 packages/grpc-js/src/load-balancing-call.ts create mode 100644 packages/grpc-js/src/resolving-call.ts create mode 100644 packages/grpc-js/src/subchannel-call.ts diff --git a/packages/grpc-js/src/call-credentials-filter.ts b/packages/grpc-js/src/call-credentials-filter.ts deleted file mode 100644 index 5c746297e..000000000 --- a/packages/grpc-js/src/call-credentials-filter.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Call } from './call-stream'; -import { Channel } from './channel'; -import { BaseFilter, Filter, FilterFactory } from './filter'; -import { Metadata } from './metadata'; -import { Status } from './constants'; -import { splitHostPort } from './uri-parser'; -import { ServiceError } from './call'; - -export class CallCredentialsFilter extends BaseFilter implements Filter { - private serviceUrl: string; - constructor( - private readonly channel: Channel, - private readonly stream: Call - ) { - super(); - this.channel = channel; - this.stream = stream; - const splitPath: string[] = stream.getMethod().split('/'); - let serviceName = ''; - /* The standard path format is "/{serviceName}/{methodName}", so if we split - * by '/', the first item should be empty and the second should be the - * service name */ - if (splitPath.length >= 2) { - serviceName = splitPath[1]; - } - const hostname = splitHostPort(stream.getHost())?.host ?? 'localhost'; - /* Currently, call credentials are only allowed on HTTPS connections, so we - * can assume that the scheme is "https" */ - this.serviceUrl = `https://${hostname}/${serviceName}`; - } - - async sendMetadata(metadata: Promise): Promise { - const credentials = this.stream.getCredentials(); - const credsMetadata = credentials.generateMetadata({ - service_url: this.serviceUrl, - }); - const resultMetadata = await metadata; - try { - resultMetadata.merge(await credsMetadata); - } catch (error) { - this.stream.cancelWithStatus( - Status.UNAUTHENTICATED, - `Failed to retrieve auth metadata with error: ${error.message}` - ); - return Promise.reject('Failed to retrieve auth metadata'); - } - if (resultMetadata.get('authorization').length > 1) { - this.stream.cancelWithStatus( - Status.INTERNAL, - '"authorization" metadata cannot have multiple values' - ); - return Promise.reject( - '"authorization" metadata cannot have multiple values' - ); - } - return resultMetadata; - } -} - -export class CallCredentialsFilterFactory - implements FilterFactory { - constructor(private readonly channel: Channel) { - this.channel = channel; - } - - createFilter(callStream: Call): CallCredentialsFilter { - return new CallCredentialsFilter(this.channel, callStream); - } -} diff --git a/packages/grpc-js/src/call-interface.ts b/packages/grpc-js/src/call-interface.ts new file mode 100644 index 000000000..891170fec --- /dev/null +++ b/packages/grpc-js/src/call-interface.ts @@ -0,0 +1,169 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { CallCredentials } from "./call-credentials"; +import { Status } from "./constants"; +import { Deadline } from "./deadline"; +import { Metadata } from "./metadata"; +import { ServerSurfaceCall } from "./server-call"; + +export interface CallStreamOptions { + deadline: Deadline; + flags: number; + host: string; + parentCall: ServerSurfaceCall | null; +} + +export type PartialCallStreamOptions = Partial; + +export interface StatusObject { + code: Status; + details: string; + metadata: Metadata; +} + +export const enum WriteFlags { + BufferHint = 1, + NoCompress = 2, + WriteThrough = 4, +} + +export interface WriteObject { + message: Buffer; + flags?: number; +} + +export interface MetadataListener { + (metadata: Metadata, next: (metadata: Metadata) => void): void; +} + +export interface MessageListener { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (message: any, next: (message: any) => void): void; +} + +export interface StatusListener { + (status: StatusObject, next: (status: StatusObject) => void): void; +} + +export interface FullListener { + onReceiveMetadata: MetadataListener; + onReceiveMessage: MessageListener; + onReceiveStatus: StatusListener; +} + +export type Listener = Partial; + +/** + * An object with methods for handling the responses to a call. + */ +export interface InterceptingListener { + onReceiveMetadata(metadata: Metadata): void; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onReceiveMessage(message: any): void; + onReceiveStatus(status: StatusObject): void; +} + +export function isInterceptingListener( + listener: Listener | InterceptingListener +): listener is InterceptingListener { + return ( + listener.onReceiveMetadata !== undefined && + listener.onReceiveMetadata.length === 1 + ); +} + +export class InterceptingListenerImpl implements InterceptingListener { + private processingMetadata = false; + private hasPendingMessage = false; + private pendingMessage: any; + private processingMessage = false; + private pendingStatus: StatusObject | null = null; + constructor( + private listener: FullListener, + private nextListener: InterceptingListener + ) {} + + private processPendingMessage() { + if (this.hasPendingMessage) { + this.nextListener.onReceiveMessage(this.pendingMessage); + this.pendingMessage = null; + this.hasPendingMessage = false; + } + } + + private processPendingStatus() { + if (this.pendingStatus) { + this.nextListener.onReceiveStatus(this.pendingStatus); + } + } + + onReceiveMetadata(metadata: Metadata): void { + this.processingMetadata = true; + this.listener.onReceiveMetadata(metadata, (metadata) => { + this.processingMetadata = false; + this.nextListener.onReceiveMetadata(metadata); + this.processPendingMessage(); + this.processPendingStatus(); + }); + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + onReceiveMessage(message: any): void { + /* If this listener processes messages asynchronously, the last message may + * be reordered with respect to the status */ + this.processingMessage = true; + this.listener.onReceiveMessage(message, (msg) => { + this.processingMessage = false; + if (this.processingMetadata) { + this.pendingMessage = msg; + this.hasPendingMessage = true; + } else { + this.nextListener.onReceiveMessage(msg); + this.processPendingStatus(); + } + }); + } + onReceiveStatus(status: StatusObject): void { + this.listener.onReceiveStatus(status, (processedStatus) => { + if (this.processingMetadata || this.processingMessage) { + this.pendingStatus = processedStatus; + } else { + this.nextListener.onReceiveStatus(processedStatus); + } + }); + } +} + +export interface WriteCallback { + (error?: Error | null): void; +} + +export interface MessageContext { + callback?: WriteCallback; + flags?: number; +} + +export interface Call { + cancelWithStatus(status: Status, details: string): void; + getPeer(): string; + start(metadata: Metadata, listener: InterceptingListener): void; + sendMessageWithContext(context: MessageContext, message: Buffer): void; + startRead(): void; + halfClose(): void; + getCallNumber(): number; + setCredentials(credentials: CallCredentials): void; +} \ No newline at end of file diff --git a/packages/grpc-js/src/call-number.ts b/packages/grpc-js/src/call-number.ts new file mode 100644 index 000000000..48d34fac5 --- /dev/null +++ b/packages/grpc-js/src/call-number.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +let nextCallNumber = 0; + +export function getNextCallNumber() { + return nextCallNumber++; +} \ No newline at end of file diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts deleted file mode 100644 index e8f312752..000000000 --- a/packages/grpc-js/src/call-stream.ts +++ /dev/null @@ -1,882 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import * as http2 from 'http2'; -import * as os from 'os'; - -import { CallCredentials } from './call-credentials'; -import { Propagate, Status } from './constants'; -import { Filter, FilterFactory } from './filter'; -import { FilterStackFactory, FilterStack } from './filter-stack'; -import { Metadata } from './metadata'; -import { StreamDecoder } from './stream-decoder'; -import { ChannelImplementation } from './channel'; -import { SubchannelCallStatsTracker, Subchannel } from './subchannel'; -import * as logging from './logging'; -import { LogVerbosity } from './constants'; -import { ServerSurfaceCall } from './server-call'; - -const TRACER_NAME = 'call_stream'; - -const { - HTTP2_HEADER_STATUS, - HTTP2_HEADER_CONTENT_TYPE, - NGHTTP2_CANCEL, -} = http2.constants; - -/** - * https://nodejs.org/api/errors.html#errors_class_systemerror - */ -interface SystemError extends Error { - address?: string; - code: string; - dest?: string; - errno: number; - info?: object; - message: string; - path?: string; - port?: number; - syscall: string; -} - -/** - * Should do approximately the same thing as util.getSystemErrorName but the - * TypeScript types don't have that function for some reason so I just made my - * own. - * @param errno - */ -function getSystemErrorName(errno: number): string { - for (const [name, num] of Object.entries(os.constants.errno)) { - if (num === errno) { - return name; - } - } - return 'Unknown system error ' + errno; -} - -export type Deadline = Date | number; - -function getMinDeadline(deadlineList: Deadline[]): Deadline { - let minValue = Infinity; - for (const deadline of deadlineList) { - const deadlineMsecs = - deadline instanceof Date ? deadline.getTime() : deadline; - if (deadlineMsecs < minValue) { - minValue = deadlineMsecs; - } - } - return minValue; -} - -export interface CallStreamOptions { - deadline: Deadline; - flags: number; - host: string; - parentCall: ServerSurfaceCall | null; -} - -export type PartialCallStreamOptions = Partial; - -export interface StatusObject { - code: Status; - details: string; - metadata: Metadata; -} - -export const enum WriteFlags { - BufferHint = 1, - NoCompress = 2, - WriteThrough = 4, -} - -export interface WriteObject { - message: Buffer; - flags?: number; -} - -export interface MetadataListener { - (metadata: Metadata, next: (metadata: Metadata) => void): void; -} - -export interface MessageListener { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - (message: any, next: (message: any) => void): void; -} - -export interface StatusListener { - (status: StatusObject, next: (status: StatusObject) => void): void; -} - -export interface FullListener { - onReceiveMetadata: MetadataListener; - onReceiveMessage: MessageListener; - onReceiveStatus: StatusListener; -} - -export type Listener = Partial; - -/** - * An object with methods for handling the responses to a call. - */ -export interface InterceptingListener { - onReceiveMetadata(metadata: Metadata): void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onReceiveMessage(message: any): void; - onReceiveStatus(status: StatusObject): void; -} - -export function isInterceptingListener( - listener: Listener | InterceptingListener -): listener is InterceptingListener { - return ( - listener.onReceiveMetadata !== undefined && - listener.onReceiveMetadata.length === 1 - ); -} - -export class InterceptingListenerImpl implements InterceptingListener { - private processingMetadata = false; - private hasPendingMessage = false; - private pendingMessage: any; - private processingMessage = false; - private pendingStatus: StatusObject | null = null; - constructor( - private listener: FullListener, - private nextListener: InterceptingListener - ) {} - - private processPendingMessage() { - if (this.hasPendingMessage) { - this.nextListener.onReceiveMessage(this.pendingMessage); - this.pendingMessage = null; - this.hasPendingMessage = false; - } - } - - private processPendingStatus() { - if (this.pendingStatus) { - this.nextListener.onReceiveStatus(this.pendingStatus); - } - } - - onReceiveMetadata(metadata: Metadata): void { - this.processingMetadata = true; - this.listener.onReceiveMetadata(metadata, (metadata) => { - this.processingMetadata = false; - this.nextListener.onReceiveMetadata(metadata); - this.processPendingMessage(); - this.processPendingStatus(); - }); - } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - onReceiveMessage(message: any): void { - /* If this listener processes messages asynchronously, the last message may - * be reordered with respect to the status */ - this.processingMessage = true; - this.listener.onReceiveMessage(message, (msg) => { - this.processingMessage = false; - if (this.processingMetadata) { - this.pendingMessage = msg; - this.hasPendingMessage = true; - } else { - this.nextListener.onReceiveMessage(msg); - this.processPendingStatus(); - } - }); - } - onReceiveStatus(status: StatusObject): void { - this.listener.onReceiveStatus(status, (processedStatus) => { - if (this.processingMetadata || this.processingMessage) { - this.pendingStatus = processedStatus; - } else { - this.nextListener.onReceiveStatus(processedStatus); - } - }); - } -} - -export interface WriteCallback { - (error?: Error | null): void; -} - -export interface MessageContext { - callback?: WriteCallback; - flags?: number; -} - -export interface Call { - cancelWithStatus(status: Status, details: string): void; - getPeer(): string; - start(metadata: Metadata, listener: InterceptingListener): void; - sendMessageWithContext(context: MessageContext, message: Buffer): void; - startRead(): void; - halfClose(): void; - - getDeadline(): Deadline; - getCredentials(): CallCredentials; - setCredentials(credentials: CallCredentials): void; - getMethod(): string; - getHost(): string; -} - -export class Http2CallStream implements Call { - credentials: CallCredentials; - filterStack: FilterStack; - private http2Stream: http2.ClientHttp2Stream | null = null; - private pendingRead = false; - private isWriteFilterPending = false; - private pendingWrite: Buffer | null = null; - private pendingWriteCallback: WriteCallback | null = null; - private writesClosed = false; - - private decoder = new StreamDecoder(); - - private isReadFilterPending = false; - private canPush = false; - /** - * Indicates that an 'end' event has come from the http2 stream, so there - * will be no more data events. - */ - private readsClosed = false; - - private statusOutput = false; - - private unpushedReadMessages: Buffer[] = []; - private unfilteredReadMessages: Buffer[] = []; - - // Status code mapped from :status. To be used if grpc-status is not received - private mappedStatusCode: Status = Status.UNKNOWN; - - // This is populated (non-null) if and only if the call has ended - private finalStatus: StatusObject | null = null; - - private subchannel: Subchannel | null = null; - private disconnectListener: () => void; - - private listener: InterceptingListener | null = null; - - private internalError: SystemError | null = null; - - private configDeadline: Deadline = Infinity; - - private statusWatchers: ((status: StatusObject) => void)[] = []; - private streamEndWatchers: ((success: boolean) => void)[] = []; - - private callStatsTracker: SubchannelCallStatsTracker | null = null; - - constructor( - private readonly methodName: string, - private readonly channel: ChannelImplementation, - private readonly options: CallStreamOptions, - filterStackFactory: FilterStackFactory, - private readonly channelCallCredentials: CallCredentials, - private readonly callNumber: number - ) { - this.filterStack = filterStackFactory.createFilter(this); - this.credentials = channelCallCredentials; - this.disconnectListener = () => { - this.endCall({ - code: Status.UNAVAILABLE, - details: 'Connection dropped', - metadata: new Metadata(), - }); - }; - if ( - this.options.parentCall && - this.options.flags & Propagate.CANCELLATION - ) { - this.options.parentCall.on('cancelled', () => { - this.cancelWithStatus(Status.CANCELLED, 'Cancelled by parent call'); - }); - } - } - - private outputStatus() { - /* Precondition: this.finalStatus !== null */ - if (this.listener && !this.statusOutput) { - this.statusOutput = true; - const filteredStatus = this.filterStack.receiveTrailers( - this.finalStatus! - ); - this.trace( - 'ended with status: code=' + - filteredStatus.code + - ' details="' + - filteredStatus.details + - '"' - ); - this.statusWatchers.forEach(watcher => watcher(filteredStatus)); - /* We delay the actual action of bubbling up the status to insulate the - * cleanup code in this class from any errors that may be thrown in the - * upper layers as a result of bubbling up the status. In particular, - * if the status is not OK, the "error" event may be emitted - * synchronously at the top level, which will result in a thrown error if - * the user does not handle that event. */ - process.nextTick(() => { - this.listener?.onReceiveStatus(filteredStatus); - }); - if (this.subchannel) { - this.subchannel.callUnref(); - this.subchannel.removeDisconnectListener(this.disconnectListener); - } - } - } - - private trace(text: string): void { - logging.trace( - LogVerbosity.DEBUG, - TRACER_NAME, - '[' + this.callNumber + '] ' + text - ); - } - - /** - * On first call, emits a 'status' event with the given StatusObject. - * Subsequent calls are no-ops. - * @param status The status of the call. - */ - private endCall(status: StatusObject): void { - /* If the status is OK and a new status comes in (e.g. from a - * deserialization failure), that new status takes priority */ - if (this.finalStatus === null || this.finalStatus.code === Status.OK) { - this.finalStatus = status; - this.maybeOutputStatus(); - } - this.destroyHttp2Stream(); - } - - private maybeOutputStatus() { - if (this.finalStatus !== null) { - /* The combination check of readsClosed and that the two message buffer - * arrays are empty checks that there all incoming data has been fully - * processed */ - if ( - this.finalStatus.code !== Status.OK || - (this.readsClosed && - this.unpushedReadMessages.length === 0 && - this.unfilteredReadMessages.length === 0 && - !this.isReadFilterPending) - ) { - this.outputStatus(); - } - } - } - - private push(message: Buffer): void { - this.trace( - 'pushing to reader message of length ' + - (message instanceof Buffer ? message.length : null) - ); - this.canPush = false; - process.nextTick(() => { - /* If we have already output the status any later messages should be - * ignored, and can cause out-of-order operation errors higher up in the - * stack. Checking as late as possible here to avoid any race conditions. - */ - if (this.statusOutput) { - return; - } - this.listener?.onReceiveMessage(message); - this.maybeOutputStatus(); - }); - } - - private handleFilterError(error: Error) { - this.cancelWithStatus(Status.INTERNAL, error.message); - } - - private handleFilteredRead(message: Buffer) { - /* If we the call has already ended with an error, we don't want to do - * anything with this message. Dropping it on the floor is correct - * behavior */ - if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { - this.maybeOutputStatus(); - return; - } - this.isReadFilterPending = false; - if (this.canPush) { - this.http2Stream!.pause(); - this.push(message); - } else { - this.trace( - 'unpushedReadMessages.push message of length ' + message.length - ); - this.unpushedReadMessages.push(message); - } - if (this.unfilteredReadMessages.length > 0) { - /* nextMessage is guaranteed not to be undefined because - unfilteredReadMessages is non-empty */ - const nextMessage = this.unfilteredReadMessages.shift()!; - this.filterReceivedMessage(nextMessage); - } - } - - private filterReceivedMessage(framedMessage: Buffer) { - /* If we the call has already ended with an error, we don't want to do - * anything with this message. Dropping it on the floor is correct - * behavior */ - if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { - this.maybeOutputStatus(); - return; - } - this.trace('filterReceivedMessage of length ' + framedMessage.length); - this.isReadFilterPending = true; - this.filterStack - .receiveMessage(Promise.resolve(framedMessage)) - .then( - this.handleFilteredRead.bind(this), - this.handleFilterError.bind(this) - ); - } - - private tryPush(messageBytes: Buffer): void { - if (this.isReadFilterPending) { - this.trace( - 'unfilteredReadMessages.push message of length ' + - (messageBytes && messageBytes.length) - ); - this.unfilteredReadMessages.push(messageBytes); - } else { - this.filterReceivedMessage(messageBytes); - } - } - - private handleTrailers(headers: http2.IncomingHttpHeaders) { - this.streamEndWatchers.forEach(watcher => watcher(true)); - let headersString = ''; - for (const header of Object.keys(headers)) { - headersString += '\t\t' + header + ': ' + headers[header] + '\n'; - } - this.trace('Received server trailers:\n' + headersString); - let metadata: Metadata; - try { - metadata = Metadata.fromHttp2Headers(headers); - } catch (e) { - metadata = new Metadata(); - } - const metadataMap = metadata.getMap(); - let code: Status = this.mappedStatusCode; - if ( - code === Status.UNKNOWN && - typeof metadataMap['grpc-status'] === 'string' - ) { - const receivedStatus = Number(metadataMap['grpc-status']); - if (receivedStatus in Status) { - code = receivedStatus; - this.trace('received status code ' + receivedStatus + ' from server'); - } - metadata.remove('grpc-status'); - } - let details = ''; - if (typeof metadataMap['grpc-message'] === 'string') { - details = decodeURI(metadataMap['grpc-message']); - metadata.remove('grpc-message'); - this.trace( - 'received status details string "' + details + '" from server' - ); - } - const status: StatusObject = { code, details, metadata }; - // This is a no-op if the call was already ended when handling headers. - this.endCall(status); - } - - private writeMessageToStream(message: Buffer, callback: WriteCallback) { - this.callStatsTracker?.addMessageSent(); - this.http2Stream!.write(message, callback); - } - - attachHttp2Stream( - stream: http2.ClientHttp2Stream, - subchannel: Subchannel, - extraFilters: Filter[], - callStatsTracker: SubchannelCallStatsTracker - ): void { - this.filterStack.push(extraFilters); - if (this.finalStatus !== null) { - stream.close(NGHTTP2_CANCEL); - } else { - this.trace( - 'attachHttp2Stream from subchannel ' + subchannel.getAddress() - ); - this.http2Stream = stream; - this.subchannel = subchannel; - this.callStatsTracker = callStatsTracker; - subchannel.addDisconnectListener(this.disconnectListener); - subchannel.callRef(); - stream.on('response', (headers, flags) => { - let headersString = ''; - for (const header of Object.keys(headers)) { - headersString += '\t\t' + header + ': ' + headers[header] + '\n'; - } - this.trace('Received server headers:\n' + headersString); - switch (headers[':status']) { - // TODO(murgatroid99): handle 100 and 101 - case 400: - this.mappedStatusCode = Status.INTERNAL; - break; - case 401: - this.mappedStatusCode = Status.UNAUTHENTICATED; - break; - case 403: - this.mappedStatusCode = Status.PERMISSION_DENIED; - break; - case 404: - this.mappedStatusCode = Status.UNIMPLEMENTED; - break; - case 429: - case 502: - case 503: - case 504: - this.mappedStatusCode = Status.UNAVAILABLE; - break; - default: - this.mappedStatusCode = Status.UNKNOWN; - } - - if (flags & http2.constants.NGHTTP2_FLAG_END_STREAM) { - this.handleTrailers(headers); - } else { - let metadata: Metadata; - try { - metadata = Metadata.fromHttp2Headers(headers); - } catch (error) { - this.endCall({ - code: Status.UNKNOWN, - details: error.message, - metadata: new Metadata(), - }); - return; - } - try { - const finalMetadata = this.filterStack.receiveMetadata(metadata); - this.listener?.onReceiveMetadata(finalMetadata); - } catch (error) { - this.endCall({ - code: Status.UNKNOWN, - details: error.message, - metadata: new Metadata(), - }); - } - } - }); - stream.on('trailers', this.handleTrailers.bind(this)); - stream.on('data', (data: Buffer) => { - this.trace('receive HTTP/2 data frame of length ' + data.length); - const messages = this.decoder.write(data); - - for (const message of messages) { - this.trace('parsed message of length ' + message.length); - this.callStatsTracker!.addMessageReceived(); - this.tryPush(message); - } - }); - stream.on('end', () => { - this.readsClosed = true; - this.maybeOutputStatus(); - }); - stream.on('close', () => { - /* Use process.next tick to ensure that this code happens after any - * "error" event that may be emitted at about the same time, so that - * we can bubble up the error message from that event. */ - process.nextTick(() => { - this.trace('HTTP/2 stream closed with code ' + stream.rstCode); - /* If we have a final status with an OK status code, that means that - * we have received all of the messages and we have processed the - * trailers and the call completed successfully, so it doesn't matter - * how the stream ends after that */ - if (this.finalStatus?.code === Status.OK) { - return; - } - let code: Status; - let details = ''; - switch (stream.rstCode) { - case http2.constants.NGHTTP2_NO_ERROR: - /* If we get a NO_ERROR code and we already have a status, the - * stream completed properly and we just haven't fully processed - * it yet */ - if (this.finalStatus !== null) { - return; - } - code = Status.INTERNAL; - details = `Received RST_STREAM with code ${stream.rstCode}`; - break; - case http2.constants.NGHTTP2_REFUSED_STREAM: - code = Status.UNAVAILABLE; - details = 'Stream refused by server'; - break; - case http2.constants.NGHTTP2_CANCEL: - code = Status.CANCELLED; - details = 'Call cancelled'; - break; - case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: - code = Status.RESOURCE_EXHAUSTED; - details = 'Bandwidth exhausted or memory limit exceeded'; - break; - case http2.constants.NGHTTP2_INADEQUATE_SECURITY: - code = Status.PERMISSION_DENIED; - details = 'Protocol not secure enough'; - break; - case http2.constants.NGHTTP2_INTERNAL_ERROR: - code = Status.INTERNAL; - if (this.internalError === null) { - /* This error code was previously handled in the default case, and - * there are several instances of it online, so I wanted to - * preserve the original error message so that people find existing - * information in searches, but also include the more recognizable - * "Internal server error" message. */ - details = `Received RST_STREAM with code ${stream.rstCode} (Internal server error)`; - } else { - if (this.internalError.code === 'ECONNRESET' || this.internalError.code === 'ETIMEDOUT') { - code = Status.UNAVAILABLE; - details = this.internalError.message; - } else { - /* The "Received RST_STREAM with code ..." error is preserved - * here for continuity with errors reported online, but the - * error message at the end will probably be more relevant in - * most cases. */ - details = `Received RST_STREAM with code ${stream.rstCode} triggered by internal client error: ${this.internalError.message}`; - } - } - break; - default: - code = Status.INTERNAL; - details = `Received RST_STREAM with code ${stream.rstCode}`; - } - // This is a no-op if trailers were received at all. - // This is OK, because status codes emitted here correspond to more - // catastrophic issues that prevent us from receiving trailers in the - // first place. - this.endCall({ code, details, metadata: new Metadata() }); - }); - }); - stream.on('error', (err: SystemError) => { - /* We need an error handler here to stop "Uncaught Error" exceptions - * from bubbling up. However, errors here should all correspond to - * "close" events, where we will handle the error more granularly */ - /* Specifically looking for stream errors that were *not* constructed - * from a RST_STREAM response here: - * https://github.com/nodejs/node/blob/8b8620d580314050175983402dfddf2674e8e22a/lib/internal/http2/core.js#L2267 - */ - if (err.code !== 'ERR_HTTP2_STREAM_ERROR') { - this.trace( - 'Node error event: message=' + - err.message + - ' code=' + - err.code + - ' errno=' + - getSystemErrorName(err.errno) + - ' syscall=' + - err.syscall - ); - this.internalError = err; - } - this.streamEndWatchers.forEach(watcher => watcher(false)); - }); - if (!this.pendingRead) { - stream.pause(); - } - if (this.pendingWrite) { - if (!this.pendingWriteCallback) { - throw new Error('Invalid state in write handling code'); - } - this.trace( - 'sending data chunk of length ' + - this.pendingWrite.length + - ' (deferred)' - ); - try { - this.writeMessageToStream(this.pendingWrite, this.pendingWriteCallback); - } catch (error) { - this.endCall({ - code: Status.UNAVAILABLE, - details: `Write failed with error ${error.message}`, - metadata: new Metadata() - }); - } - } - this.maybeCloseWrites(); - } - } - - start(metadata: Metadata, listener: InterceptingListener) { - this.trace('Sending metadata'); - this.listener = listener; - this.channel._startCallStream(this, metadata); - this.maybeOutputStatus(); - } - - private destroyHttp2Stream() { - // The http2 stream could already have been destroyed if cancelWithStatus - // is called in response to an internal http2 error. - if (this.http2Stream !== null && !this.http2Stream.destroyed) { - /* If the call has ended with an OK status, communicate that when closing - * the stream, partly to avoid a situation in which we detect an error - * RST_STREAM as a result after we have the status */ - let code: number; - if (this.finalStatus?.code === Status.OK) { - code = http2.constants.NGHTTP2_NO_ERROR; - } else { - code = http2.constants.NGHTTP2_CANCEL; - } - this.trace('close http2 stream with code ' + code); - this.http2Stream.close(code); - } - } - - cancelWithStatus(status: Status, details: string): void { - this.trace( - 'cancelWithStatus code: ' + status + ' details: "' + details + '"' - ); - this.endCall({ code: status, details, metadata: new Metadata() }); - } - - getDeadline(): Deadline { - const deadlineList = [this.options.deadline]; - if (this.options.parentCall && this.options.flags & Propagate.DEADLINE) { - deadlineList.push(this.options.parentCall.getDeadline()); - } - if (this.configDeadline) { - deadlineList.push(this.configDeadline); - } - return getMinDeadline(deadlineList); - } - - getCredentials(): CallCredentials { - return this.credentials; - } - - setCredentials(credentials: CallCredentials): void { - this.credentials = this.channelCallCredentials.compose(credentials); - } - - getStatus(): StatusObject | null { - return this.finalStatus; - } - - getPeer(): string { - return this.subchannel?.getAddress() ?? this.channel.getTarget(); - } - - getMethod(): string { - return this.methodName; - } - - getHost(): string { - return this.options.host; - } - - setConfigDeadline(configDeadline: Deadline) { - this.configDeadline = configDeadline; - } - - addStatusWatcher(watcher: (status: StatusObject) => void) { - this.statusWatchers.push(watcher); - } - - addStreamEndWatcher(watcher: (success: boolean) => void) { - this.streamEndWatchers.push(watcher); - } - - addFilters(extraFilters: Filter[]) { - this.filterStack.push(extraFilters); - } - - getCallNumber() { - return this.callNumber; - } - - startRead() { - /* If the stream has ended with an error, we should not emit any more - * messages and we should communicate that the stream has ended */ - if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { - this.readsClosed = true; - this.maybeOutputStatus(); - return; - } - this.canPush = true; - if (this.http2Stream === null) { - this.pendingRead = true; - } else { - if (this.unpushedReadMessages.length > 0) { - const nextMessage: Buffer = this.unpushedReadMessages.shift()!; - this.push(nextMessage); - return; - } - /* Only resume reading from the http2Stream if we don't have any pending - * messages to emit */ - this.http2Stream.resume(); - } - } - - private maybeCloseWrites() { - if ( - this.writesClosed && - !this.isWriteFilterPending && - this.http2Stream !== null - ) { - this.trace('calling end() on HTTP/2 stream'); - this.http2Stream.end(); - } - } - - sendMessageWithContext(context: MessageContext, message: Buffer) { - this.trace('write() called with message of length ' + message.length); - const writeObj: WriteObject = { - message, - flags: context.flags, - }; - const cb: WriteCallback = (error?: Error | null) => { - let code: Status = Status.UNAVAILABLE; - if ((error as NodeJS.ErrnoException)?.code === 'ERR_STREAM_WRITE_AFTER_END') { - code = Status.INTERNAL; - } - if (error) { - this.cancelWithStatus(code, `Write error: ${error.message}`); - } - context.callback?.(); - }; - this.isWriteFilterPending = true; - this.filterStack.sendMessage(Promise.resolve(writeObj)).then((message) => { - this.isWriteFilterPending = false; - if (this.http2Stream === null) { - this.trace( - 'deferring writing data chunk of length ' + message.message.length - ); - this.pendingWrite = message.message; - this.pendingWriteCallback = cb; - } else { - this.trace('sending data chunk of length ' + message.message.length); - try { - this.writeMessageToStream(message.message, cb); - } catch (error) { - this.endCall({ - code: Status.UNAVAILABLE, - details: `Write failed with error ${error.message}`, - metadata: new Metadata() - }); - } - this.maybeCloseWrites(); - } - }, this.handleFilterError.bind(this)); - } - - halfClose() { - this.trace('end() called'); - this.writesClosed = true; - this.maybeCloseWrites(); - } -} diff --git a/packages/grpc-js/src/call.ts b/packages/grpc-js/src/call.ts index fcc3159db..c587a195d 100644 --- a/packages/grpc-js/src/call.ts +++ b/packages/grpc-js/src/call.ts @@ -18,7 +18,7 @@ import { EventEmitter } from 'events'; import { Duplex, Readable, Writable } from 'stream'; -import { StatusObject, MessageContext } from './call-stream'; +import { StatusObject, MessageContext } from './call-interface'; import { Status } from './constants'; import { EmitterAugmentation1 } from './events'; import { Metadata } from './metadata'; diff --git a/packages/grpc-js/src/channel.ts b/packages/grpc-js/src/channel.ts index 635b52d6f..aaf14bb22 100644 --- a/packages/grpc-js/src/channel.ts +++ b/packages/grpc-js/src/channel.ts @@ -15,57 +15,15 @@ * */ -import { - Deadline, - Call, - Http2CallStream, - CallStreamOptions, -} from './call-stream'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; -import { ResolvingLoadBalancer } from './resolving-load-balancer'; -import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; -import { ChannelControlHelper } from './load-balancer'; -import { UnavailablePicker, Picker, PickResultType } from './picker'; -import { Metadata } from './metadata'; -import { Status, LogVerbosity, Propagate } from './constants'; -import { FilterStackFactory } from './filter-stack'; -import { CallCredentialsFilterFactory } from './call-credentials-filter'; -import { DeadlineFilterFactory } from './deadline-filter'; -import { CompressionFilterFactory } from './compression-filter'; -import { - CallConfig, - ConfigSelector, - getDefaultAuthority, - mapUriDefaultScheme, -} from './resolver'; -import { trace, log } from './logging'; -import { SubchannelAddress } from './subchannel-address'; -import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; -import { mapProxyName } from './http_proxy'; -import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; -import { Filter } from './filter'; import { ConnectivityState } from './connectivity-state'; -import { ChannelInfo, ChannelRef, ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzChannel, SubchannelRef, unregisterChannelzRef } from './channelz'; -import { Subchannel } from './subchannel'; - -/** - * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args - */ -const MAX_TIMEOUT_TIME = 2147483647; - -let nextCallNumber = 0; - -function getNewCallNumber(): number { - const callNumber = nextCallNumber; - nextCallNumber += 1; - if (nextCallNumber >= Number.MAX_SAFE_INTEGER) { - nextCallNumber = 0; - } - return callNumber; -} +import { ChannelRef } from './channelz'; +import { Call } from './call-interface'; +import { InternalChannel } from './internal-channel'; +import { Deadline } from './deadline'; /** * An interface that represents a communication channel to a server specified @@ -132,57 +90,14 @@ export interface Channel { ): Call; } -interface ConnectivityStateWatcher { - currentState: ConnectivityState; - timer: NodeJS.Timeout | null; - callback: (error?: Error) => void; -} - export class ChannelImplementation implements Channel { - private resolvingLoadBalancer: ResolvingLoadBalancer; - private subchannelPool: SubchannelPool; - private connectivityState: ConnectivityState = ConnectivityState.IDLE; - private currentPicker: Picker = new UnavailablePicker(); - /** - * Calls queued up to get a call config. Should only be populated before the - * first time the resolver returns a result, which includes the ConfigSelector. - */ - private configSelectionQueue: Array<{ - callStream: Http2CallStream; - callMetadata: Metadata; - }> = []; - private pickQueue: Array<{ - callStream: Http2CallStream; - callMetadata: Metadata; - callConfig: CallConfig; - dynamicFilters: Filter[]; - }> = []; - private connectivityStateWatchers: ConnectivityStateWatcher[] = []; - private defaultAuthority: string; - private filterStackFactory: FilterStackFactory; - private target: GrpcUri; - /** - * This timer does not do anything on its own. Its purpose is to hold the - * event loop open while there are any pending calls for the channel that - * have not yet been assigned to specific subchannels. In other words, - * the invariant is that callRefTimer is reffed if and only if pickQueue - * is non-empty. - */ - private callRefTimer: NodeJS.Timer; - private configSelector: ConfigSelector | null = null; - // Channelz info - private readonly channelzEnabled: boolean = true; - private originalTarget: string; - private channelzRef: ChannelRef; - private channelzTrace: ChannelzTrace; - private callTracker = new ChannelzCallTracker(); - private childrenTracker = new ChannelzChildrenTracker(); + private internalChannel: InternalChannel; constructor( target: string, - private readonly credentials: ChannelCredentials, - private readonly options: ChannelOptions + credentials: ChannelCredentials, + options: ChannelOptions ) { if (typeof target !== 'string') { throw new TypeError('Channel target must be a string'); @@ -197,497 +112,20 @@ export class ChannelImplementation implements Channel { throw new TypeError('Channel options must be an object'); } } - this.originalTarget = target; - const originalTargetUri = parseUri(target); - if (originalTargetUri === null) { - throw new Error(`Could not parse target name "${target}"`); - } - /* This ensures that the target has a scheme that is registered with the - * resolver */ - const defaultSchemeMapResult = mapUriDefaultScheme(originalTargetUri); - if (defaultSchemeMapResult === null) { - throw new Error( - `Could not find a default scheme for target name "${target}"` - ); - } - - this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME); - this.callRefTimer.unref?.(); - - if (this.options['grpc.enable_channelz'] === 0) { - this.channelzEnabled = false; - } - - this.channelzTrace = new ChannelzTrace(); - if (this.channelzEnabled) { - this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo()); - this.channelzTrace.addTrace('CT_INFO', 'Channel created'); - } else { - // Dummy channelz ref that will never be used - this.channelzRef = { - kind: 'channel', - id: -1, - name: '' - }; - } - - if (this.options['grpc.default_authority']) { - this.defaultAuthority = this.options['grpc.default_authority'] as string; - } else { - this.defaultAuthority = getDefaultAuthority(defaultSchemeMapResult); - } - const proxyMapResult = mapProxyName(defaultSchemeMapResult, options); - this.target = proxyMapResult.target; - this.options = Object.assign({}, this.options, proxyMapResult.extraOptions); - - /* The global boolean parameter to getSubchannelPool has the inverse meaning to what - * the grpc.use_local_subchannel_pool channel option means. */ - this.subchannelPool = getSubchannelPool( - (options['grpc.use_local_subchannel_pool'] ?? 0) === 0 - ); - const channelControlHelper: ChannelControlHelper = { - createSubchannel: ( - subchannelAddress: SubchannelAddress, - subchannelArgs: ChannelOptions - ) => { - const subchannel = this.subchannelPool.getOrCreateSubchannel( - this.target, - subchannelAddress, - Object.assign({}, this.options, subchannelArgs), - this.credentials - ); - if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); - } - return subchannel; - }, - updateState: (connectivityState: ConnectivityState, picker: Picker) => { - this.currentPicker = picker; - const queueCopy = this.pickQueue.slice(); - this.pickQueue = []; - this.callRefTimerUnref(); - for (const { callStream, callMetadata, callConfig, dynamicFilters } of queueCopy) { - this.tryPick(callStream, callMetadata, callConfig, dynamicFilters); - } - this.updateState(connectivityState); - }, - requestReresolution: () => { - // This should never be called. - throw new Error( - 'Resolving load balancer should never call requestReresolution' - ); - }, - addChannelzChild: (child: ChannelRef | SubchannelRef) => { - if (this.channelzEnabled) { - this.childrenTracker.refChild(child); - } - }, - removeChannelzChild: (child: ChannelRef | SubchannelRef) => { - if (this.channelzEnabled) { - this.childrenTracker.unrefChild(child); - } - } - }; - this.resolvingLoadBalancer = new ResolvingLoadBalancer( - this.target, - channelControlHelper, - options, - (configSelector) => { - if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); - } - this.configSelector = configSelector; - /* We process the queue asynchronously to ensure that the corresponding - * load balancer update has completed. */ - process.nextTick(() => { - const localQueue = this.configSelectionQueue; - this.configSelectionQueue = []; - this.callRefTimerUnref(); - for (const { callStream, callMetadata } of localQueue) { - this.tryGetConfig(callStream, callMetadata); - } - this.configSelectionQueue = []; - }); - }, - (status) => { - if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); - } - if (this.configSelectionQueue.length > 0) { - this.trace('Name resolution failed with calls queued for config selection'); - } - const localQueue = this.configSelectionQueue; - this.configSelectionQueue = []; - this.callRefTimerUnref(); - for (const { callStream, callMetadata } of localQueue) { - if (callMetadata.getOptions().waitForReady) { - this.callRefTimerRef(); - this.configSelectionQueue.push({ callStream, callMetadata }); - } else { - callStream.cancelWithStatus(status.code, status.details); - } - } - } - ); - this.filterStackFactory = new FilterStackFactory([ - new CallCredentialsFilterFactory(this), - new DeadlineFilterFactory(this), - new MaxMessageSizeFilterFactory(this.options), - new CompressionFilterFactory(this, this.options), - ]); - this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); - const error = new Error(); - trace(LogVerbosity.DEBUG, 'channel_stacktrace', '(' + this.channelzRef.id + ') ' + 'Channel constructed \n' + error.stack?.substring(error.stack.indexOf('\n')+1)); - } - - private getChannelzInfo(): ChannelInfo { - return { - target: this.originalTarget, - state: this.connectivityState, - trace: this.channelzTrace, - callTracker: this.callTracker, - children: this.childrenTracker.getChildLists() - }; - } - - private trace(text: string, verbosityOverride?: LogVerbosity) { - trace(verbosityOverride ?? LogVerbosity.DEBUG, 'channel', '(' + this.channelzRef.id + ') ' + uriToString(this.target) + ' ' + text); - } - - private callRefTimerRef() { - // If the hasRef function does not exist, always run the code - if (!this.callRefTimer.hasRef?.()) { - this.trace( - 'callRefTimer.ref | configSelectionQueue.length=' + - this.configSelectionQueue.length + - ' pickQueue.length=' + - this.pickQueue.length - ); - this.callRefTimer.ref?.(); - } - } - - private callRefTimerUnref() { - // If the hasRef function does not exist, always run the code - if (!this.callRefTimer.hasRef || this.callRefTimer.hasRef()) { - this.trace( - 'callRefTimer.unref | configSelectionQueue.length=' + - this.configSelectionQueue.length + - ' pickQueue.length=' + - this.pickQueue.length - ); - this.callRefTimer.unref?.(); - } - } - - private pushPick( - callStream: Http2CallStream, - callMetadata: Metadata, - callConfig: CallConfig, - dynamicFilters: Filter[] - ) { - this.pickQueue.push({ callStream, callMetadata, callConfig, dynamicFilters }); - this.callRefTimerRef(); - } - - /** - * Check the picker output for the given call and corresponding metadata, - * and take any relevant actions. Should not be called while iterating - * over pickQueue. - * @param callStream - * @param callMetadata - */ - private tryPick( - callStream: Http2CallStream, - callMetadata: Metadata, - callConfig: CallConfig, - dynamicFilters: Filter[] - ) { - const pickResult = this.currentPicker.pick({ - metadata: callMetadata, - extraPickInfo: callConfig.pickInformation, - }); - const subchannelString = pickResult.subchannel ? - '(' + pickResult.subchannel.getChannelzRef().id + ') ' + pickResult.subchannel.getAddress() : - '' + pickResult.subchannel; - this.trace( - 'Pick result for call [' + - callStream.getCallNumber() + - ']: ' + - PickResultType[pickResult.pickResultType] + - ' subchannel: ' + - subchannelString + - ' status: ' + - pickResult.status?.code + - ' ' + - pickResult.status?.details - ); - switch (pickResult.pickResultType) { - case PickResultType.COMPLETE: - if (pickResult.subchannel === null) { - callStream.cancelWithStatus( - Status.UNAVAILABLE, - 'Request dropped by load balancing policy' - ); - // End the call with an error - } else { - /* If the subchannel is not in the READY state, that indicates a bug - * somewhere in the load balancer or picker. So, we log an error and - * queue the pick to be tried again later. */ - if ( - pickResult.subchannel!.getConnectivityState() !== - ConnectivityState.READY - ) { - log( - LogVerbosity.ERROR, - 'Error: COMPLETE pick result subchannel ' + - subchannelString + - ' has state ' + - ConnectivityState[pickResult.subchannel!.getConnectivityState()] - ); - this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); - break; - } - /* We need to clone the callMetadata here because the transparent - * retry code in the promise resolution handler use the same - * callMetadata object, so it needs to stay unmodified */ - callStream.filterStack - .sendMetadata(Promise.resolve(callMetadata.clone())) - .then( - (finalMetadata) => { - const subchannelState: ConnectivityState = pickResult.subchannel!.getConnectivityState(); - if (subchannelState === ConnectivityState.READY) { - try { - const pickExtraFilters = pickResult.extraFilterFactories.map(factory => factory.createFilter(callStream)); - pickResult.subchannel?.getRealSubchannel().startCallStream( - finalMetadata, - callStream, - [...dynamicFilters, ...pickExtraFilters] - ); - /* If we reach this point, the call stream has started - * successfully */ - callConfig.onCommitted?.(); - pickResult.onCallStarted?.(); - } catch (error) { - const errorCode = (error as NodeJS.ErrnoException).code; - if (errorCode === 'ERR_HTTP2_GOAWAY_SESSION' || - errorCode === 'ERR_HTTP2_INVALID_SESSION' - ) { - /* An error here indicates that something went wrong with - * the picked subchannel's http2 stream right before we - * tried to start the stream. We are handling a promise - * result here, so this is asynchronous with respect to the - * original tryPick call, so calling it again is not - * recursive. We call tryPick immediately instead of - * queueing this pick again because handling the queue is - * triggered by state changes, and we want to immediately - * check if the state has already changed since the - * previous tryPick call. We do this instead of cancelling - * the stream because the correct behavior may be - * re-queueing instead, based on the logic in the rest of - * tryPick */ - this.trace( - 'Failed to start call on picked subchannel ' + - subchannelString + - ' with error ' + - (error as Error).message + - '. Retrying pick', - LogVerbosity.INFO - ); - this.tryPick(callStream, callMetadata, callConfig, dynamicFilters); - } else { - this.trace( - 'Failed to start call on picked subchanel ' + - subchannelString + - ' with error ' + - (error as Error).message + - '. Ending call', - LogVerbosity.INFO - ); - callStream.cancelWithStatus( - Status.INTERNAL, - `Failed to start HTTP/2 stream with error: ${ - (error as Error).message - }` - ); - } - } - } else { - /* The logic for doing this here is the same as in the catch - * block above */ - this.trace( - 'Picked subchannel ' + - subchannelString + - ' has state ' + - ConnectivityState[subchannelState] + - ' after metadata filters. Retrying pick', - LogVerbosity.INFO - ); - this.tryPick(callStream, callMetadata, callConfig, dynamicFilters); - } - }, - (error: Error & { code: number }) => { - // We assume the error code isn't 0 (Status.OK) - callStream.cancelWithStatus( - typeof error.code === 'number' ? error.code : Status.UNKNOWN, - `Getting metadata from plugin failed with error: ${error.message}` - ); - } - ); - } - break; - case PickResultType.QUEUE: - this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); - break; - case PickResultType.TRANSIENT_FAILURE: - if (callMetadata.getOptions().waitForReady) { - this.pushPick(callStream, callMetadata, callConfig, dynamicFilters); - } else { - callStream.cancelWithStatus( - pickResult.status!.code, - pickResult.status!.details - ); - } - break; - case PickResultType.DROP: - callStream.cancelWithStatus( - pickResult.status!.code, - pickResult.status!.details - ); - break; - default: - throw new Error( - `Invalid state: unknown pickResultType ${pickResult.pickResultType}` - ); - } - } - - private removeConnectivityStateWatcher( - watcherObject: ConnectivityStateWatcher - ) { - const watcherIndex = this.connectivityStateWatchers.findIndex( - (value) => value === watcherObject - ); - if (watcherIndex >= 0) { - this.connectivityStateWatchers.splice(watcherIndex, 1); - } - } - - private updateState(newState: ConnectivityState): void { - trace( - LogVerbosity.DEBUG, - 'connectivity_state', - '(' + this.channelzRef.id + ') ' + - uriToString(this.target) + - ' ' + - ConnectivityState[this.connectivityState] + - ' -> ' + - ConnectivityState[newState] - ); - if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); - } - this.connectivityState = newState; - const watchersCopy = this.connectivityStateWatchers.slice(); - for (const watcherObject of watchersCopy) { - if (newState !== watcherObject.currentState) { - if (watcherObject.timer) { - clearTimeout(watcherObject.timer); - } - this.removeConnectivityStateWatcher(watcherObject); - watcherObject.callback(); - } - } - } - - private tryGetConfig(stream: Http2CallStream, metadata: Metadata) { - if (stream.getStatus() !== null) { - /* If the stream has a status, it has already finished and we don't need - * to take any more actions on it. */ - return; - } - if (this.configSelector === null) { - /* This branch will only be taken at the beginning of the channel's life, - * before the resolver ever returns a result. So, the - * ResolvingLoadBalancer may be idle and if so it needs to be kicked - * because it now has a pending request. */ - this.resolvingLoadBalancer.exitIdle(); - this.configSelectionQueue.push({ - callStream: stream, - callMetadata: metadata, - }); - this.callRefTimerRef(); - } else { - const callConfig = this.configSelector(stream.getMethod(), metadata); - if (callConfig.status === Status.OK) { - if (callConfig.methodConfig.timeout) { - const deadline = new Date(); - deadline.setSeconds( - deadline.getSeconds() + callConfig.methodConfig.timeout.seconds - ); - deadline.setMilliseconds( - deadline.getMilliseconds() + - callConfig.methodConfig.timeout.nanos / 1_000_000 - ); - stream.setConfigDeadline(deadline); - // Refreshing the filters makes the deadline filter pick up the new deadline - stream.filterStack.refresh(); - } - if (callConfig.dynamicFilterFactories.length > 0) { - /* These dynamicFilters are the mechanism for implementing gRFC A39: - * https://github.com/grpc/proposal/blob/master/A39-xds-http-filters.md - * We run them here instead of with the rest of the filters because - * that spec says "the xDS HTTP filters will run in between name - * resolution and load balancing". - * - * We use the filter stack here to simplify the multi-filter async - * waterfall logic, but we pass along the underlying list of filters - * to avoid having nested filter stacks when combining it with the - * original filter stack. We do not pass along the original filter - * factory list because these filters may need to persist data - * between sending headers and other operations. */ - const dynamicFilterStackFactory = new FilterStackFactory(callConfig.dynamicFilterFactories); - const dynamicFilterStack = dynamicFilterStackFactory.createFilter(stream); - dynamicFilterStack.sendMetadata(Promise.resolve(metadata)).then(filteredMetadata => { - this.tryPick(stream, filteredMetadata, callConfig, dynamicFilterStack.getFilters()); - }); - } else { - this.tryPick(stream, metadata, callConfig, []); - } - } else { - stream.cancelWithStatus( - callConfig.status, - 'Failed to route call to method ' + stream.getMethod() - ); - } - } - } - _startCallStream(stream: Http2CallStream, metadata: Metadata) { - this.tryGetConfig(stream, metadata.clone()); + this.internalChannel = new InternalChannel(target, credentials, options); } close() { - this.resolvingLoadBalancer.destroy(); - this.updateState(ConnectivityState.SHUTDOWN); - clearInterval(this.callRefTimer); - if (this.channelzEnabled) { - unregisterChannelzRef(this.channelzRef); - } - - this.subchannelPool.unrefUnusedSubchannels(); + this.internalChannel.close(); } getTarget() { - return uriToString(this.target); + return this.internalChannel.getTarget(); } getConnectivityState(tryToConnect: boolean) { - const connectivityState = this.connectivityState; - if (tryToConnect) { - this.resolvingLoadBalancer.exitIdle(); - } - return connectivityState; + return this.internalChannel.getConnectivityState(tryToConnect); } watchConnectivityState( @@ -695,34 +133,7 @@ export class ChannelImplementation implements Channel { deadline: Date | number, callback: (error?: Error) => void ): void { - if (this.connectivityState === ConnectivityState.SHUTDOWN) { - throw new Error('Channel has been shut down'); - } - let timer = null; - if (deadline !== Infinity) { - const deadlineDate: Date = - deadline instanceof Date ? deadline : new Date(deadline); - const now = new Date(); - if (deadline === -Infinity || deadlineDate <= now) { - process.nextTick( - callback, - new Error('Deadline passed without connectivity state change') - ); - return; - } - timer = setTimeout(() => { - this.removeConnectivityStateWatcher(watcherObject); - callback( - new Error('Deadline passed without connectivity state change') - ); - }, deadlineDate.getTime() - now.getTime()); - } - const watcherObject = { - currentState, - callback, - timer, - }; - this.connectivityStateWatchers.push(watcherObject); + this.internalChannel.watchConnectivityState(currentState, deadline, callback); } /** @@ -731,7 +142,7 @@ export class ChannelImplementation implements Channel { * @returns */ getChannelzRef() { - return this.channelzRef; + return this.internalChannel.getChannelzRef(); } createCall( @@ -749,42 +160,6 @@ export class ChannelImplementation implements Channel { 'Channel#createCall: deadline must be a number or Date' ); } - if (this.connectivityState === ConnectivityState.SHUTDOWN) { - throw new Error('Channel has been shut down'); - } - const callNumber = getNewCallNumber(); - this.trace( - 'createCall [' + - callNumber + - '] method="' + - method + - '", deadline=' + - deadline - ); - const finalOptions: CallStreamOptions = { - deadline: deadline, - flags: propagateFlags ?? Propagate.DEFAULTS, - host: host ?? this.defaultAuthority, - parentCall: parentCall, - }; - const stream: Http2CallStream = new Http2CallStream( - method, - this, - finalOptions, - this.filterStackFactory, - this.credentials._getCallCredentials(), - callNumber - ); - if (this.channelzEnabled) { - this.callTracker.addCallStarted(); - stream.addStatusWatcher(status => { - if (status.code === Status.OK) { - this.callTracker.addCallSucceeded(); - } else { - this.callTracker.addCallFailed(); - } - }); - } - return stream; + return this.internalChannel.createCall(method, deadline, host, parentCall, propagateFlags); } } diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index ddb296ff1..52320b0b3 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -28,7 +28,7 @@ import { isInterceptingListener, MessageContext, Call, -} from './call-stream'; +} from './call-interface'; import { Status } from './constants'; import { Channel } from './channel'; import { CallOptions } from './client'; diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index ed9407cd8..688d8016c 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -29,7 +29,7 @@ import { SurfaceCall, } from './call'; import { CallCredentials } from './call-credentials'; -import { Deadline, StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { Channel, ChannelImplementation } from './channel'; import { ConnectivityState } from './connectivity-state'; import { ChannelCredentials } from './channel-credentials'; @@ -50,6 +50,7 @@ import { ServerWritableStream, ServerDuplexStream, } from './server-call'; +import { Deadline } from './deadline'; const CHANNEL_SYMBOL = Symbol(); const INTERCEPTOR_SYMBOL = Symbol(); diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index 40825467e..f87614114 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -17,7 +17,7 @@ import * as zlib from 'zlib'; -import { Call, WriteObject, WriteFlags } from './call-stream'; +import { WriteObject, WriteFlags } from './call-interface'; import { Channel } from './channel'; import { ChannelOptions } from './channel-options'; import { CompressionAlgorithms } from './compression-algorithms'; @@ -283,7 +283,7 @@ export class CompressionFilterFactory implements FilterFactory { private sharedFilterConfig: SharedCompressionFilterConfig = {}; constructor(private readonly channel: Channel, private readonly options: ChannelOptions) {} - createFilter(callStream: Call): CompressionFilter { + createFilter(): CompressionFilter { return new CompressionFilter(this.options, this.sharedFilterConfig); } } diff --git a/packages/grpc-js/src/deadline-filter.ts b/packages/grpc-js/src/deadline-filter.ts deleted file mode 100644 index 7bdd764f2..000000000 --- a/packages/grpc-js/src/deadline-filter.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright 2019 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { Call, StatusObject } from './call-stream'; -import { Channel } from './channel'; -import { Status } from './constants'; -import { BaseFilter, Filter, FilterFactory } from './filter'; -import { Metadata } from './metadata'; - -const units: Array<[string, number]> = [ - ['m', 1], - ['S', 1000], - ['M', 60 * 1000], - ['H', 60 * 60 * 1000], -]; - -function getDeadline(deadline: number) { - const now = new Date().getTime(); - const timeoutMs = Math.max(deadline - now, 0); - for (const [unit, factor] of units) { - const amount = timeoutMs / factor; - if (amount < 1e8) { - return String(Math.ceil(amount)) + unit; - } - } - throw new Error('Deadline is too far in the future'); -} - -export class DeadlineFilter extends BaseFilter implements Filter { - private timer: NodeJS.Timer | null = null; - private deadline = Infinity; - constructor( - private readonly channel: Channel, - private readonly callStream: Call - ) { - super(); - this.retreiveDeadline(); - this.runTimer(); - } - - private retreiveDeadline() { - const callDeadline = this.callStream.getDeadline(); - if (callDeadline instanceof Date) { - this.deadline = callDeadline.getTime(); - } else { - this.deadline = callDeadline; - } - } - - private runTimer() { - if (this.timer) { - clearTimeout(this.timer); - } - const now: number = new Date().getTime(); - const timeout = this.deadline - now; - if (timeout <= 0) { - process.nextTick(() => { - this.callStream.cancelWithStatus( - Status.DEADLINE_EXCEEDED, - 'Deadline exceeded' - ); - }); - } else if (this.deadline !== Infinity) { - this.timer = setTimeout(() => { - this.callStream.cancelWithStatus( - Status.DEADLINE_EXCEEDED, - 'Deadline exceeded' - ); - }, timeout); - this.timer.unref?.(); - } - } - - refresh() { - this.retreiveDeadline(); - this.runTimer(); - } - - async sendMetadata(metadata: Promise) { - if (this.deadline === Infinity) { - return metadata; - } - /* The input metadata promise depends on the original channel.connect() - * promise, so when it is complete that implies that the channel is - * connected */ - const finalMetadata = await metadata; - const timeoutString = getDeadline(this.deadline); - finalMetadata.set('grpc-timeout', timeoutString); - return finalMetadata; - } - - receiveTrailers(status: StatusObject) { - if (this.timer) { - clearTimeout(this.timer); - } - return status; - } -} - -export class DeadlineFilterFactory implements FilterFactory { - constructor(private readonly channel: Channel) {} - - createFilter(callStream: Call): DeadlineFilter { - return new DeadlineFilter(this.channel, callStream); - } -} diff --git a/packages/grpc-js/src/deadline.ts b/packages/grpc-js/src/deadline.ts new file mode 100644 index 000000000..58ea0a805 --- /dev/null +++ b/packages/grpc-js/src/deadline.ts @@ -0,0 +1,58 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export type Deadline = Date | number; + +export function minDeadline(...deadlineList: Deadline[]): Deadline { + let minValue = Infinity; + for (const deadline of deadlineList) { + const deadlineMsecs = + deadline instanceof Date ? deadline.getTime() : deadline; + if (deadlineMsecs < minValue) { + minValue = deadlineMsecs; + } + } + return minValue; +} + +const units: Array<[string, number]> = [ + ['m', 1], + ['S', 1000], + ['M', 60 * 1000], + ['H', 60 * 60 * 1000], +]; + +export function getDeadlineTimeoutString(deadline: Deadline) { + const now = new Date().getTime(); + if (deadline instanceof Date) { + deadline = deadline.getTime(); + } + const timeoutMs = Math.max(deadline - now, 0); + for (const [unit, factor] of units) { + const amount = timeoutMs / factor; + if (amount < 1e8) { + return String(Math.ceil(amount)) + unit; + } + } + throw new Error('Deadline is too far in the future') +} + +export function getRelativeTimeout(deadline: Deadline) { + const deadlineMs = deadline instanceof Date ? deadline.getTime() : deadline; + const now = new Date().getTime(); + return deadlineMs - now; +} \ No newline at end of file diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index fcafbeb01..f286bbcd6 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -31,7 +31,7 @@ export { PickArgs, PickResultType, } from './picker'; -export { Call as CallStream } from './call-stream'; +export { Call as CallStream } from './call-interface'; export { Filter, BaseFilter, FilterFactory } from './filter'; export { FilterStackFactory } from './filter-stack'; export { registerAdminService } from './admin'; diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index a9e754428..f44c43839 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -15,14 +15,14 @@ * */ -import { Call, StatusObject, WriteObject } from './call-stream'; +import { StatusObject, WriteObject } from './call-interface'; import { Filter, FilterFactory } from './filter'; import { Metadata } from './metadata'; export class FilterStack implements Filter { constructor(private readonly filters: Filter[]) {} - sendMetadata(metadata: Promise) { + sendMetadata(metadata: Promise): Promise { let result: Promise = metadata; for (let i = 0; i < this.filters.length; i++) { @@ -72,12 +72,6 @@ export class FilterStack implements Filter { return result; } - refresh(): void { - for (const filter of this.filters) { - filter.refresh(); - } - } - push(filters: Filter[]) { this.filters.unshift(...filters); } @@ -94,9 +88,9 @@ export class FilterStackFactory implements FilterFactory { this.factories.unshift(...filterFactories); } - createFilter(callStream: Call): FilterStack { + createFilter(): FilterStack { return new FilterStack( - this.factories.map((factory) => factory.createFilter(callStream)) + this.factories.map((factory) => factory.createFilter()) ); } } diff --git a/packages/grpc-js/src/filter.ts b/packages/grpc-js/src/filter.ts index 8475a0a5a..5313f91a8 100644 --- a/packages/grpc-js/src/filter.ts +++ b/packages/grpc-js/src/filter.ts @@ -15,12 +15,14 @@ * */ -import { Call, StatusObject, WriteObject } from './call-stream'; +import { StatusObject, WriteObject } from './call-interface'; import { Metadata } from './metadata'; /** * Filter classes represent related per-call logic and state that is primarily - * used to modify incoming and outgoing data + * used to modify incoming and outgoing data. All async filters can be + * rejected. The rejection error must be a StatusObject, and a rejection will + * cause the call to end with that status. */ export interface Filter { sendMetadata(metadata: Promise): Promise; @@ -32,8 +34,6 @@ export interface Filter { receiveMessage(message: Promise): Promise; receiveTrailers(status: StatusObject): StatusObject; - - refresh(): void; } export abstract class BaseFilter implements Filter { @@ -56,10 +56,8 @@ export abstract class BaseFilter implements Filter { receiveTrailers(status: StatusObject): StatusObject { return status; } - - refresh(): void {} } export interface FilterFactory { - createFilter(callStream: Call): T; + createFilter(): T; } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index b4855fb59..786fa9925 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -23,7 +23,7 @@ import { ServiceError, } from './call'; import { CallCredentials, OAuth2Client } from './call-credentials'; -import { Deadline, StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { Channel, ChannelImplementation } from './channel'; import { CompressionAlgorithms } from './compression-algorithms'; import { ConnectivityState } from './connectivity-state'; @@ -237,7 +237,7 @@ export const getClientChannel = (client: Client) => { export { StatusBuilder }; -export { Listener } from './call-stream'; +export { Listener } from './call-interface'; export { Requester, @@ -275,6 +275,7 @@ import * as load_balancer_pick_first from './load-balancer-pick-first'; import * as load_balancer_round_robin from './load-balancer-round-robin'; import * as load_balancer_outlier_detection from './load-balancer-outlier-detection'; import * as channelz from './channelz'; +import { Deadline } from './deadline'; const clientVersion = require('../../package.json').version; diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts new file mode 100644 index 000000000..772ed8e1d --- /dev/null +++ b/packages/grpc-js/src/internal-channel.ts @@ -0,0 +1,504 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ChannelCredentials } from './channel-credentials'; +import { ChannelOptions } from './channel-options'; +import { ResolvingLoadBalancer } from './resolving-load-balancer'; +import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; +import { ChannelControlHelper } from './load-balancer'; +import { UnavailablePicker, Picker, PickResultType } from './picker'; +import { Metadata } from './metadata'; +import { Status, LogVerbosity, Propagate } from './constants'; +import { FilterStackFactory } from './filter-stack'; +import { CompressionFilterFactory } from './compression-filter'; +import { + CallConfig, + ConfigSelector, + getDefaultAuthority, + mapUriDefaultScheme, +} from './resolver'; +import { trace, log } from './logging'; +import { SubchannelAddress } from './subchannel-address'; +import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; +import { mapProxyName } from './http_proxy'; +import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; +import { ServerSurfaceCall } from './server-call'; +import { Filter } from './filter'; + +import { ConnectivityState } from './connectivity-state'; +import { ChannelInfo, ChannelRef, ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzChannel, SubchannelRef, unregisterChannelzRef } from './channelz'; +import { Subchannel } from './subchannel'; +import { LoadBalancingCall } from './load-balancing-call'; +import { CallCredentials } from './call-credentials'; +import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from './call-interface'; +import { SubchannelCall } from './subchannel-call'; +import { Deadline, getDeadlineTimeoutString } from './deadline'; +import { ResolvingCall } from './resolving-call'; +import { getNextCallNumber } from './call-number'; + +/** + * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args + */ +const MAX_TIMEOUT_TIME = 2147483647; + +interface ConnectivityStateWatcher { + currentState: ConnectivityState; + timer: NodeJS.Timeout | null; + callback: (error?: Error) => void; +} + +export class InternalChannel { + + private resolvingLoadBalancer: ResolvingLoadBalancer; + private subchannelPool: SubchannelPool; + private connectivityState: ConnectivityState = ConnectivityState.IDLE; + private currentPicker: Picker = new UnavailablePicker(); + /** + * Calls queued up to get a call config. Should only be populated before the + * first time the resolver returns a result, which includes the ConfigSelector. + */ + private configSelectionQueue: ResolvingCall[] = []; + private pickQueue: LoadBalancingCall[] = []; + private connectivityStateWatchers: ConnectivityStateWatcher[] = []; + private defaultAuthority: string; + private filterStackFactory: FilterStackFactory; + private target: GrpcUri; + /** + * This timer does not do anything on its own. Its purpose is to hold the + * event loop open while there are any pending calls for the channel that + * have not yet been assigned to specific subchannels. In other words, + * the invariant is that callRefTimer is reffed if and only if pickQueue + * is non-empty. + */ + private callRefTimer: NodeJS.Timer; + private configSelector: ConfigSelector | null = null; + + // Channelz info + private readonly channelzEnabled: boolean = true; + private originalTarget: string; + private channelzRef: ChannelRef; + private channelzTrace: ChannelzTrace; + private callTracker = new ChannelzCallTracker(); + private childrenTracker = new ChannelzChildrenTracker(); + + constructor( + target: string, + private readonly credentials: ChannelCredentials, + private readonly options: ChannelOptions + ) { + if (typeof target !== 'string') { + throw new TypeError('Channel target must be a string'); + } + if (!(credentials instanceof ChannelCredentials)) { + throw new TypeError( + 'Channel credentials must be a ChannelCredentials object' + ); + } + if (options) { + if (typeof options !== 'object') { + throw new TypeError('Channel options must be an object'); + } + } + this.originalTarget = target; + const originalTargetUri = parseUri(target); + if (originalTargetUri === null) { + throw new Error(`Could not parse target name "${target}"`); + } + /* This ensures that the target has a scheme that is registered with the + * resolver */ + const defaultSchemeMapResult = mapUriDefaultScheme(originalTargetUri); + if (defaultSchemeMapResult === null) { + throw new Error( + `Could not find a default scheme for target name "${target}"` + ); + } + + this.callRefTimer = setInterval(() => {}, MAX_TIMEOUT_TIME); + this.callRefTimer.unref?.(); + + if (this.options['grpc.enable_channelz'] === 0) { + this.channelzEnabled = false; + } + + this.channelzTrace = new ChannelzTrace(); + if (this.channelzEnabled) { + this.channelzRef = registerChannelzChannel(target, () => this.getChannelzInfo()); + this.channelzTrace.addTrace('CT_INFO', 'Channel created'); + } else { + // Dummy channelz ref that will never be used + this.channelzRef = { + kind: 'channel', + id: -1, + name: '' + }; + } + + if (this.options['grpc.default_authority']) { + this.defaultAuthority = this.options['grpc.default_authority'] as string; + } else { + this.defaultAuthority = getDefaultAuthority(defaultSchemeMapResult); + } + const proxyMapResult = mapProxyName(defaultSchemeMapResult, options); + this.target = proxyMapResult.target; + this.options = Object.assign({}, this.options, proxyMapResult.extraOptions); + + /* The global boolean parameter to getSubchannelPool has the inverse meaning to what + * the grpc.use_local_subchannel_pool channel option means. */ + this.subchannelPool = getSubchannelPool( + (options['grpc.use_local_subchannel_pool'] ?? 0) === 0 + ); + const channelControlHelper: ChannelControlHelper = { + createSubchannel: ( + subchannelAddress: SubchannelAddress, + subchannelArgs: ChannelOptions + ) => { + const subchannel = this.subchannelPool.getOrCreateSubchannel( + this.target, + subchannelAddress, + Object.assign({}, this.options, subchannelArgs), + this.credentials + ); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); + } + return subchannel; + }, + updateState: (connectivityState: ConnectivityState, picker: Picker) => { + this.currentPicker = picker; + const queueCopy = this.pickQueue.slice(); + this.pickQueue = []; + this.callRefTimerUnref(); + for (const call of queueCopy) { + call.doPick(); + } + this.updateState(connectivityState); + }, + requestReresolution: () => { + // This should never be called. + throw new Error( + 'Resolving load balancer should never call requestReresolution' + ); + }, + addChannelzChild: (child: ChannelRef | SubchannelRef) => { + if (this.channelzEnabled) { + this.childrenTracker.refChild(child); + } + }, + removeChannelzChild: (child: ChannelRef | SubchannelRef) => { + if (this.channelzEnabled) { + this.childrenTracker.unrefChild(child); + } + } + }; + this.resolvingLoadBalancer = new ResolvingLoadBalancer( + this.target, + channelControlHelper, + options, + (configSelector) => { + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); + } + this.configSelector = configSelector; + /* We process the queue asynchronously to ensure that the corresponding + * load balancer update has completed. */ + process.nextTick(() => { + const localQueue = this.configSelectionQueue; + this.configSelectionQueue = []; + this.callRefTimerUnref(); + for (const call of localQueue) { + call.getConfig(); + } + this.configSelectionQueue = []; + }); + }, + (status) => { + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_WARNING', 'Address resolution failed with code ' + status.code + ' and details "' + status.details + '"'); + } + if (this.configSelectionQueue.length > 0) { + this.trace('Name resolution failed with calls queued for config selection'); + } + const localQueue = this.configSelectionQueue; + this.configSelectionQueue = []; + this.callRefTimerUnref(); + for (const call of localQueue) { + call.reportResolverError(status); + } + } + ); + this.filterStackFactory = new FilterStackFactory([ + new MaxMessageSizeFilterFactory(this.options), + new CompressionFilterFactory(this, this.options), + ]); + this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); + const error = new Error(); + trace(LogVerbosity.DEBUG, 'channel_stacktrace', '(' + this.channelzRef.id + ') ' + 'Channel constructed \n' + error.stack?.substring(error.stack.indexOf('\n')+1)); + } + + private getChannelzInfo(): ChannelInfo { + return { + target: this.originalTarget, + state: this.connectivityState, + trace: this.channelzTrace, + callTracker: this.callTracker, + children: this.childrenTracker.getChildLists() + }; + } + + private trace(text: string, verbosityOverride?: LogVerbosity) { + trace(verbosityOverride ?? LogVerbosity.DEBUG, 'channel', '(' + this.channelzRef.id + ') ' + uriToString(this.target) + ' ' + text); + } + + private callRefTimerRef() { + // If the hasRef function does not exist, always run the code + if (!this.callRefTimer.hasRef?.()) { + this.trace( + 'callRefTimer.ref | configSelectionQueue.length=' + + this.configSelectionQueue.length + + ' pickQueue.length=' + + this.pickQueue.length + ); + this.callRefTimer.ref?.(); + } + } + + private callRefTimerUnref() { + // If the hasRef function does not exist, always run the code + if (!this.callRefTimer.hasRef || this.callRefTimer.hasRef()) { + this.trace( + 'callRefTimer.unref | configSelectionQueue.length=' + + this.configSelectionQueue.length + + ' pickQueue.length=' + + this.pickQueue.length + ); + this.callRefTimer.unref?.(); + } + } + + private removeConnectivityStateWatcher( + watcherObject: ConnectivityStateWatcher + ) { + const watcherIndex = this.connectivityStateWatchers.findIndex( + (value) => value === watcherObject + ); + if (watcherIndex >= 0) { + this.connectivityStateWatchers.splice(watcherIndex, 1); + } + } + + private updateState(newState: ConnectivityState): void { + trace( + LogVerbosity.DEBUG, + 'connectivity_state', + '(' + this.channelzRef.id + ') ' + + uriToString(this.target) + + ' ' + + ConnectivityState[this.connectivityState] + + ' -> ' + + ConnectivityState[newState] + ); + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', ConnectivityState[this.connectivityState] + ' -> ' + ConnectivityState[newState]); + } + this.connectivityState = newState; + const watchersCopy = this.connectivityStateWatchers.slice(); + for (const watcherObject of watchersCopy) { + if (newState !== watcherObject.currentState) { + if (watcherObject.timer) { + clearTimeout(watcherObject.timer); + } + this.removeConnectivityStateWatcher(watcherObject); + watcherObject.callback(); + } + } + } + + doPick(metadata: Metadata, extraPickInfo: {[key: string]: string}) { + return this.currentPicker.pick({metadata: metadata, extraPickInfo: extraPickInfo}); + } + + queueCallForPick(call: LoadBalancingCall) { + this.pickQueue.push(call); + this.callRefTimerRef(); + } + + getConfig(method: string, metadata: Metadata) { + this.resolvingLoadBalancer.exitIdle(); + return this.configSelector?.(method, metadata) ?? null; + } + + queueCallForConfig(call: ResolvingCall) { + this.configSelectionQueue.push(call); + this.callRefTimerRef(); + } + + createLoadBalancingCall( + callConfig: CallConfig, + method: string, + host: string, + credentials: CallCredentials, + deadline: Deadline + ): LoadBalancingCall { + const callNumber = getNextCallNumber(); + this.trace( + 'createLoadBalancingCall [' + + callNumber + + '] method="' + + method + + '"' + ); + return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, this.filterStackFactory, callNumber); + } + + createInnerCall( + callConfig: CallConfig, + method: string, + host: string, + credentials: CallCredentials, + deadline: Deadline + ): Call { + // Create a RetryingCall if retries are enabled + return this.createLoadBalancingCall(callConfig, method, host, credentials, deadline); + } + + createResolvingCall( + method: string, + deadline: Deadline, + host: string | null | undefined, + parentCall: ServerSurfaceCall | null, + propagateFlags: number | null | undefined + ): ResolvingCall { + const callNumber = getNextCallNumber(); + this.trace( + 'createResolvingCall [' + + callNumber + + '] method="' + + method + + '", deadline=' + + deadline + ); + const finalOptions: CallStreamOptions = { + deadline: deadline, + flags: propagateFlags ?? Propagate.DEFAULTS, + host: host ?? this.defaultAuthority, + parentCall: parentCall, + }; + + const call = new ResolvingCall(this, method, finalOptions, this.filterStackFactory, this.credentials._getCallCredentials(), getNextCallNumber()); + + if (this.channelzEnabled) { + this.callTracker.addCallStarted(); + call.addStatusWatcher(status => { + if (status.code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }); + } + return call; + + } + + close() { + this.resolvingLoadBalancer.destroy(); + this.updateState(ConnectivityState.SHUTDOWN); + clearInterval(this.callRefTimer); + if (this.channelzEnabled) { + unregisterChannelzRef(this.channelzRef); + } + + this.subchannelPool.unrefUnusedSubchannels(); + } + + getTarget() { + return uriToString(this.target); + } + + getConnectivityState(tryToConnect: boolean) { + const connectivityState = this.connectivityState; + if (tryToConnect) { + this.resolvingLoadBalancer.exitIdle(); + } + return connectivityState; + } + + watchConnectivityState( + currentState: ConnectivityState, + deadline: Date | number, + callback: (error?: Error) => void + ): void { + if (this.connectivityState === ConnectivityState.SHUTDOWN) { + throw new Error('Channel has been shut down'); + } + let timer = null; + if (deadline !== Infinity) { + const deadlineDate: Date = + deadline instanceof Date ? deadline : new Date(deadline); + const now = new Date(); + if (deadline === -Infinity || deadlineDate <= now) { + process.nextTick( + callback, + new Error('Deadline passed without connectivity state change') + ); + return; + } + timer = setTimeout(() => { + this.removeConnectivityStateWatcher(watcherObject); + callback( + new Error('Deadline passed without connectivity state change') + ); + }, deadlineDate.getTime() - now.getTime()); + } + const watcherObject = { + currentState, + callback, + timer, + }; + this.connectivityStateWatchers.push(watcherObject); + } + + /** + * Get the channelz reference object for this channel. The returned value is + * garbage if channelz is disabled for this channel. + * @returns + */ + getChannelzRef() { + return this.channelzRef; + } + + createCall( + method: string, + deadline: Deadline, + host: string | null | undefined, + parentCall: ServerSurfaceCall | null, + propagateFlags: number | null | undefined + ): Call { + if (typeof method !== 'string') { + throw new TypeError('Channel#createCall: method must be a string'); + } + if (!(typeof deadline === 'number' || deadline instanceof Date)) { + throw new TypeError( + 'Channel#createCall: deadline must be a number or Date' + ); + } + if (this.connectivityState === ConnectivityState.SHUTDOWN) { + throw new Error('Channel has been shut down'); + } + return this.createResolvingCall(method, deadline, host, parentCall, propagateFlags); + } +} diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index e69e2ef99..5af0e79e7 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -15,8 +15,7 @@ * */ -import { ChannelOptions, connectivityState, StatusObject } from "."; -import { Call } from "./call-stream"; +import { ChannelOptions } from "./channel-options"; import { ConnectivityState } from "./connectivity-state"; import { Status } from "./constants"; import { durationToMs, isDuration, msToDuration } from "./duration"; @@ -311,28 +310,6 @@ interface MapEntry { subchannelWrappers: OutlierDetectionSubchannelWrapper[]; } -class OutlierDetectionCounterFilter extends BaseFilter implements Filter { - constructor(private callCounter: CallCounter) { - super(); - } - receiveTrailers(status: StatusObject): StatusObject { - if (status.code === Status.OK) { - this.callCounter.addSuccess(); - } else { - this.callCounter.addFailure(); - } - return status; - } -} - -class OutlierDetectionCounterFilterFactory implements FilterFactory { - constructor(private callCounter: CallCounter) {} - createFilter(callStream: Call): OutlierDetectionCounterFilter { - return new OutlierDetectionCounterFilter(this.callCounter); - } - -} - class OutlierDetectionPicker implements Picker { constructor(private wrappedPicker: Picker) {} pick(pickArgs: PickArgs): PickResult { @@ -344,7 +321,14 @@ class OutlierDetectionPicker implements Picker { return { ...wrappedPick, subchannel: subchannelWrapper.getWrappedSubchannel(), - extraFilterFactories: [...wrappedPick.extraFilterFactories, new OutlierDetectionCounterFilterFactory(mapEntry.counter)] + onCallEnded: statusCode => { + if (statusCode === Status.OK) { + mapEntry.counter.addSuccess(); + } else { + mapEntry.counter.addFailure(); + } + wrappedPick.onCallEnded?.(statusCode); + } }; } else { return wrappedPick; diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 884af50b7..bb95aba13 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -84,8 +84,8 @@ class PickFirstPicker implements Picker { pickResultType: PickResultType.COMPLETE, subchannel: this.subchannel, status: null, - extraFilterFactories: [], onCallStarted: null, + onCallEnded: null }; } } diff --git a/packages/grpc-js/src/load-balancer-round-robin.ts b/packages/grpc-js/src/load-balancer-round-robin.ts index 8a4094a02..91c10b238 100644 --- a/packages/grpc-js/src/load-balancer-round-robin.ts +++ b/packages/grpc-js/src/load-balancer-round-robin.ts @@ -78,8 +78,8 @@ class RoundRobinPicker implements Picker { pickResultType: PickResultType.COMPLETE, subchannel: pickedSubchannel, status: null, - extraFilterFactories: [], onCallStarted: null, + onCallEnded: null }; } diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts new file mode 100644 index 000000000..f791b86bc --- /dev/null +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -0,0 +1,281 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { CallCredentials } from "./call-credentials"; +import { Call, InterceptingListener, MessageContext, StatusObject } from "./call-interface"; +import { SubchannelCall } from "./subchannel-call"; +import { ConnectivityState } from "./connectivity-state"; +import { LogVerbosity, Status } from "./constants"; +import { Deadline, getDeadlineTimeoutString } from "./deadline"; +import { FilterStack, FilterStackFactory } from "./filter-stack"; +import { InternalChannel } from "./internal-channel"; +import { Metadata } from "./metadata"; +import { PickResultType } from "./picker"; +import { CallConfig } from "./resolver"; +import { splitHostPort } from "./uri-parser"; +import * as logging from './logging'; + +const TRACER_NAME = 'load_balancing_call'; + +export type RpcProgress = 'NOT_STARTED' | 'DROP' | 'REFUSED' | 'PROCESSED'; + +export interface StatusObjectWithProgress extends StatusObject { + progress: RpcProgress; +} + +export class LoadBalancingCall implements Call { + private child: SubchannelCall | null = null; + private readPending = false; + private writeFilterPending = false; + private pendingMessage: {context: MessageContext, message: Buffer} | null = null; + private pendingHalfClose = false; + private ended = false; + private serviceUrl: string; + private filterStack: FilterStack; + private metadata: Metadata | null = null; + private listener: InterceptingListener | null = null; + private onCallEnded: ((statusCode: Status) => void) | null = null; + constructor( + private readonly channel: InternalChannel, + private readonly callConfig: CallConfig, + private readonly methodName: string, + private readonly host : string, + private readonly credentials: CallCredentials, + private readonly deadline: Deadline, + filterStackFactory: FilterStackFactory, + private readonly callNumber: number + ) { + this.filterStack = filterStackFactory.createFilter(); + + const splitPath: string[] = this.methodName.split('/'); + let serviceName = ''; + /* The standard path format is "/{serviceName}/{methodName}", so if we split + * by '/', the first item should be empty and the second should be the + * service name */ + if (splitPath.length >= 2) { + serviceName = splitPath[1]; + } + const hostname = splitHostPort(this.host)?.host ?? 'localhost'; + /* Currently, call credentials are only allowed on HTTPS connections, so we + * can assume that the scheme is "https" */ + this.serviceUrl = `https://${hostname}/${serviceName}`; + } + + private trace(text: string): void { + logging.trace( + LogVerbosity.DEBUG, + TRACER_NAME, + '[' + this.callNumber + '] ' + text + ); + } + + private outputStatus(status: StatusObject, progress: RpcProgress) { + if (!this.ended) { + this.ended = true; + this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); + const filteredStatus = this.filterStack.receiveTrailers(status); + const finalStatus = {...filteredStatus, progress}; + this.listener?.onReceiveStatus(finalStatus); + this.onCallEnded?.(finalStatus.code); + } + } + + doPick() { + if (this.ended) { + return; + } + if (!this.metadata) { + throw new Error('doPick called before start'); + } + const pickResult = this.channel.doPick(this.metadata, this.callConfig.pickInformation); + const subchannelString = pickResult.subchannel ? + '(' + pickResult.subchannel.getChannelzRef().id + ') ' + pickResult.subchannel.getAddress() : + '' + pickResult.subchannel; + this.trace( + 'Pick result: ' + + PickResultType[pickResult.pickResultType] + + ' subchannel: ' + + subchannelString + + ' status: ' + + pickResult.status?.code + + ' ' + + pickResult.status?.details + ); + switch (pickResult.pickResultType) { + case PickResultType.COMPLETE: + this.credentials.generateMetadata({service_url: this.serviceUrl}).then( + (credsMetadata) => { + const finalMetadata = this.metadata!.clone(); + finalMetadata.merge(credsMetadata); + if (finalMetadata.get('authorization').length > 1) { + this.outputStatus( + { + code: Status.INTERNAL, + details: '"authorization" metadata cannot have multiple values', + metadata: new Metadata() + }, + 'PROCESSED' + ); + } + if (pickResult.subchannel!.getConnectivityState() !== ConnectivityState.READY) { + this.trace( + 'Picked subchannel ' + + subchannelString + + ' has state ' + + ConnectivityState[pickResult.subchannel!.getConnectivityState()] + + ' after getting credentials metadata. Retrying pick' + ); + this.doPick(); + return; + } + + if (this.deadline !== Infinity) { + finalMetadata.set('grpc-timeout', getDeadlineTimeoutString(this.deadline)); + } + try { + this.child = pickResult.subchannel!.getRealSubchannel().createCall(finalMetadata, this.host, this.methodName, { + onReceiveMetadata: metadata => { + this.listener!.onReceiveMetadata(this.filterStack.receiveMetadata(metadata)); + }, + onReceiveMessage: message => { + this.filterStack.receiveMessage(message).then(filteredMesssage => { + this.listener!.onReceiveMessage(filteredMesssage); + }, (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + }); + }, + onReceiveStatus: status => { + this.outputStatus(status, 'PROCESSED'); + } + }); + } catch (error) { + this.trace( + 'Failed to start call on picked subchannel ' + + subchannelString + + ' with error ' + + (error as Error).message + ); + this.outputStatus( + { + code: Status.INTERNAL, + details: 'Failed to start HTTP/2 stream with error ' + (error as Error).message, + metadata: new Metadata() + }, + 'NOT_STARTED' + ); + return; + } + this.callConfig.onCommitted?.(); + pickResult.onCallStarted?.(); + this.onCallEnded = pickResult.onCallEnded; + this.trace('Created child call [' + this.child.getCallNumber() + ']'); + if (this.readPending) { + this.child.startRead(); + } + if (this.pendingMessage) { + this.child.sendMessageWithContext(this.pendingMessage.context, this.pendingMessage.message); + } + if (this.pendingHalfClose && !this.writeFilterPending) { + this.child.halfClose(); + } + }, (error: Error & { code: number }) => { + // We assume the error code isn't 0 (Status.OK) + this.outputStatus( + { + code: typeof error.code === 'number' ? error.code : Status.UNKNOWN, + details: `Getting metadata from plugin failed with error: ${error.message}`, + metadata: new Metadata() + }, + 'PROCESSED' + ); + } + ); + break; + case PickResultType.DROP: + this.outputStatus(pickResult.status!, 'DROP'); + break; + case PickResultType.TRANSIENT_FAILURE: + if (this.metadata.getOptions().waitForReady) { + this.channel.queueCallForPick(this); + } else { + this.outputStatus(pickResult.status!, 'PROCESSED'); + } + break; + case PickResultType.QUEUE: + this.channel.queueCallForPick(this); + } + } + + cancelWithStatus(status: Status, details: string): void { + this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); + this.child?.cancelWithStatus(status, details); + this.outputStatus({code: status, details: details, metadata: new Metadata()}, 'PROCESSED'); + } + getPeer(): string { + return this.child?.getPeer() ?? this.channel.getTarget(); + } + start(metadata: Metadata, listener: InterceptingListener): void { + this.trace('start called'); + this.listener = listener; + this.filterStack.sendMetadata(Promise.resolve(metadata)).then(filteredMetadata => { + this.metadata = filteredMetadata; + this.doPick(); + }, (status: StatusObject) => { + this.outputStatus(status, 'PROCESSED'); + }); + } + sendMessageWithContext(context: MessageContext, message: Buffer): void { + this.trace('write() called with message of length ' + message.length); + this.writeFilterPending = true; + this.filterStack.sendMessage(Promise.resolve({message: message, flags: context.flags})).then((filteredMessage) => { + this.writeFilterPending = false; + if (this.child) { + this.child.sendMessageWithContext(context, filteredMessage.message); + if (this.pendingHalfClose) { + this.child.halfClose(); + } + } else { + this.pendingMessage = {context, message: filteredMessage.message}; + } + }, (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + }) + } + startRead(): void { + this.trace('startRead called'); + if (this.child) { + this.child.startRead(); + } else { + this.readPending = true; + } + } + halfClose(): void { + this.trace('halfClose called'); + if (this.child && !this.writeFilterPending) { + this.child.halfClose(); + } else { + this.pendingHalfClose = true; + } + } + setCredentials(credentials: CallCredentials): void { + throw new Error("Method not implemented."); + } + + getCallNumber(): number { + return this.callNumber; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts index 9a3bc9c0a..62d01077c 100644 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -16,20 +16,20 @@ */ import { BaseFilter, Filter, FilterFactory } from './filter'; -import { Call, WriteObject } from './call-stream'; +import { WriteObject } from './call-interface'; import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, } from './constants'; import { ChannelOptions } from './channel-options'; +import { Metadata } from './metadata'; export class MaxMessageSizeFilter extends BaseFilter implements Filter { private maxSendMessageSize: number = DEFAULT_MAX_SEND_MESSAGE_LENGTH; private maxReceiveMessageSize: number = DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH; constructor( - private readonly options: ChannelOptions, - private readonly callStream: Call + private readonly options: ChannelOptions ) { super(); if ('grpc.max_send_message_length' in options) { @@ -48,11 +48,11 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } else { const concreteMessage = await message; if (concreteMessage.message.length > this.maxSendMessageSize) { - this.callStream.cancelWithStatus( - Status.RESOURCE_EXHAUSTED, - `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})` - ); - return Promise.reject('Message too large'); + throw { + code: Status.RESOURCE_EXHAUSTED, + details: `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})`, + metadata: new Metadata() + }; } else { return concreteMessage; } @@ -67,11 +67,11 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { } else { const concreteMessage = await message; if (concreteMessage.length > this.maxReceiveMessageSize) { - this.callStream.cancelWithStatus( - Status.RESOURCE_EXHAUSTED, - `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})` - ); - return Promise.reject('Message too large'); + throw { + code: Status.RESOURCE_EXHAUSTED, + details: `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})`, + metadata: new Metadata() + }; } else { return concreteMessage; } @@ -83,7 +83,7 @@ export class MaxMessageSizeFilterFactory implements FilterFactory { constructor(private readonly options: ChannelOptions) {} - createFilter(callStream: Call): MaxMessageSizeFilter { - return new MaxMessageSizeFilter(this.options, callStream); + createFilter(): MaxMessageSizeFilter { + return new MaxMessageSizeFilter(this.options); } } diff --git a/packages/grpc-js/src/picker.ts b/packages/grpc-js/src/picker.ts index f366a6919..162596ef5 100644 --- a/packages/grpc-js/src/picker.ts +++ b/packages/grpc-js/src/picker.ts @@ -15,12 +15,10 @@ * */ -import { Subchannel } from './subchannel'; -import { StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { Metadata } from './metadata'; import { Status } from './constants'; import { LoadBalancer } from './load-balancer'; -import { FilterFactory, Filter } from './filter'; import { SubchannelInterface } from './subchannel-interface'; export enum PickResultType { @@ -43,45 +41,40 @@ export interface PickResult { * `pickResultType` is TRANSIENT_FAILURE. */ status: StatusObject | null; - /** - * Extra FilterFactory (can be multiple encapsulated in a FilterStackFactory) - * provided by the load balancer to be used with the call. For technical - * reasons filters from this factory will not see sendMetadata events. - */ - extraFilterFactories: FilterFactory[]; onCallStarted: (() => void) | null; + onCallEnded: ((statusCode: Status) => void) | null; } export interface CompletePickResult extends PickResult { pickResultType: PickResultType.COMPLETE; subchannel: SubchannelInterface | null; status: null; - extraFilterFactories: FilterFactory[]; onCallStarted: (() => void) | null; + onCallEnded: ((statusCode: Status) => void) | null; } export interface QueuePickResult extends PickResult { pickResultType: PickResultType.QUEUE; subchannel: null; status: null; - extraFilterFactories: []; onCallStarted: null; + onCallEnded: null; } export interface TransientFailurePickResult extends PickResult { pickResultType: PickResultType.TRANSIENT_FAILURE; subchannel: null; status: StatusObject; - extraFilterFactories: []; onCallStarted: null; + onCallEnded: null; } export interface DropCallPickResult extends PickResult { pickResultType: PickResultType.DROP; subchannel: null; status: StatusObject; - extraFilterFactories: []; onCallStarted: null; + onCallEnded: null; } export interface PickArgs { @@ -120,8 +113,8 @@ export class UnavailablePicker implements Picker { pickResultType: PickResultType.TRANSIENT_FAILURE, subchannel: null, status: this.status, - extraFilterFactories: [], onCallStarted: null, + onCallEnded: null }; } } @@ -149,8 +142,8 @@ export class QueuePicker { pickResultType: PickResultType.QUEUE, subchannel: null, status: null, - extraFilterFactories: [], onCallStarted: null, + onCallEnded: null }; } } diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index c4cb64a74..7c4028b06 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -24,7 +24,7 @@ import * as dns from 'dns'; import * as util from 'util'; import { extractAndSelectServiceConfig, ServiceConfig } from './service-config'; import { Status } from './constants'; -import { StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; diff --git a/packages/grpc-js/src/resolver-ip.ts b/packages/grpc-js/src/resolver-ip.ts index 24efc3fdc..efb0b8dcb 100644 --- a/packages/grpc-js/src/resolver-ip.ts +++ b/packages/grpc-js/src/resolver-ip.ts @@ -15,7 +15,7 @@ */ import { isIPv4, isIPv6 } from 'net'; -import { StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { ChannelOptions } from './channel-options'; import { LogVerbosity, Status } from './constants'; import { Metadata } from './metadata'; diff --git a/packages/grpc-js/src/resolver.ts b/packages/grpc-js/src/resolver.ts index fcbc6894a..770004487 100644 --- a/packages/grpc-js/src/resolver.ts +++ b/packages/grpc-js/src/resolver.ts @@ -16,7 +16,7 @@ */ import { MethodConfig, ServiceConfig } from './service-config'; -import { StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { SubchannelAddress } from './subchannel-address'; import { GrpcUri, uriToString } from './uri-parser'; import { ChannelOptions } from './channel-options'; diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts new file mode 100644 index 000000000..4cf24b4b1 --- /dev/null +++ b/packages/grpc-js/src/resolving-call.ts @@ -0,0 +1,219 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { CallCredentials } from "./call-credentials"; +import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from "./call-interface"; +import { LogVerbosity, Propagate, Status } from "./constants"; +import { Deadline, getDeadlineTimeoutString, getRelativeTimeout, minDeadline } from "./deadline"; +import { FilterStackFactory } from "./filter-stack"; +import { InternalChannel } from "./internal-channel"; +import { Metadata } from "./metadata"; +import * as logging from './logging'; + +const TRACER_NAME = 'resolving_call'; + +export class ResolvingCall implements Call { + private child: Call | null = null; + private readPending = false; + private pendingMessage: {context: MessageContext, message: Buffer} | null = null; + private pendingHalfClose = false; + private ended = false; + private metadata: Metadata | null = null; + private listener: InterceptingListener | null = null; + private deadline: Deadline; + private host: string; + private statusWatchers: ((status: StatusObject) => void)[] = []; + private deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + + constructor( + private readonly channel: InternalChannel, + private readonly method: string, + options: CallStreamOptions, + private readonly filterStackFactory: FilterStackFactory, + private credentials: CallCredentials, + private callNumber: number + ) { + this.deadline = options.deadline; + this.host = options.host; + if (options.parentCall) { + if (options.flags & Propagate.CANCELLATION) { + options.parentCall.on('cancelled', () => { + this.cancelWithStatus(Status.CANCELLED, 'Cancelled by parent call'); + }); + } + if (options.flags & Propagate.DEADLINE) { + this.trace('Propagating deadline from parent: ' + options.parentCall.getDeadline()); + this.deadline = minDeadline(this.deadline, options.parentCall.getDeadline()); + } + } + this.trace('Created'); + this.runDeadlineTimer(); + } + + private trace(text: string): void { + logging.trace( + LogVerbosity.DEBUG, + TRACER_NAME, + '[' + this.callNumber + '] ' + text + ); + } + + private runDeadlineTimer() { + clearTimeout(this.deadlineTimer); + this.trace('Deadline: ' + this.deadline); + if (this.deadline !== Infinity) { + const timeout = getRelativeTimeout(this.deadline); + this.trace('Deadline will be reached in ' + timeout + 'ms'); + const handleDeadline = () => { + this.cancelWithStatus( + Status.DEADLINE_EXCEEDED, + 'Deadline exceeded' + ); + } + if (timeout <= 0) { + process.nextTick(handleDeadline); + } else { + this.deadlineTimer = setTimeout(handleDeadline, timeout); + } + } + } + + private outputStatus(status: StatusObject) { + if (!this.ended) { + this.ended = true; + this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); + this.statusWatchers.forEach(watcher => watcher(status)); + process.nextTick(() => { + this.listener?.onReceiveStatus(status); + }); + } + } + + getConfig(): void { + if (this.ended) { + return; + } + if (!this.metadata || !this.listener) { + throw new Error('getConfig called before start'); + } + const config = this.channel.getConfig(this.method, this.metadata); + if (!config) { + this.channel.queueCallForConfig(this); + return; + } + if (config.status !== Status.OK) { + this.outputStatus({ + code: config.status, + details: 'Failed to route call to ' + this.method, + metadata: new Metadata() + }); + return; + } + + if (config.methodConfig.timeout) { + const configDeadline = new Date(); + configDeadline.setSeconds( + configDeadline.getSeconds() + config.methodConfig.timeout.seconds + ); + configDeadline.setMilliseconds( + configDeadline.getMilliseconds() + + config.methodConfig.timeout.nanos / 1_000_000 + ); + this.deadline = minDeadline(this.deadline, configDeadline); + } + + this.filterStackFactory.push(config.dynamicFilterFactories); + + this.child = this.channel.createInnerCall(config, this.method, this.host, this.credentials, this.deadline); + this.child.start(this.metadata, { + onReceiveMetadata: metadata => { + this.listener!.onReceiveMetadata(metadata); + }, + onReceiveMessage: message => { + this.listener!.onReceiveMessage(message); + }, + onReceiveStatus: status => { + this.outputStatus(status); + } + }); + if (this.readPending) { + this.child.startRead(); + } + if (this.pendingMessage) { + this.child.sendMessageWithContext(this.pendingMessage.context, this.pendingMessage.message); + } + if (this.pendingHalfClose) { + this.child.halfClose(); + } + } + reportResolverError(status: StatusObject) { + if (this.metadata?.getOptions().waitForReady) { + this.channel.queueCallForConfig(this); + } else { + this.outputStatus(status); + } + } + cancelWithStatus(status: Status, details: string): void { + this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); + this.child?.cancelWithStatus(status, details); + this.outputStatus({code: status, details: details, metadata: new Metadata()}); + } + getPeer(): string { + return this.child?.getPeer() ?? this.channel.getTarget(); + } + start(metadata: Metadata, listener: InterceptingListener): void { + this.trace('start called'); + this.metadata = metadata.clone(); + this.listener = listener; + this.getConfig(); + } + sendMessageWithContext(context: MessageContext, message: Buffer): void { + this.trace('write() called with message of length ' + message.length); + if (this.child) { + this.child.sendMessageWithContext(context, message); + } else { + this.pendingMessage = {context, message}; + } + } + startRead(): void { + this.trace('startRead called'); + if (this.child) { + this.child.startRead(); + } else { + this.readPending = true; + } + } + halfClose(): void { + this.trace('halfClose called'); + if (this.child) { + this.child.halfClose(); + } else { + this.pendingHalfClose = true; + } + } + setCredentials(credentials: CallCredentials): void { + this.credentials = this.credentials.compose(credentials); + } + + addStatusWatcher(watcher: (status: StatusObject) => void) { + this.statusWatchers.push(watcher); + } + + getCallNumber(): number { + return this.callNumber; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index 907067dfc..47f7c3bb1 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -28,7 +28,7 @@ import { ServiceError } from './call'; import { Picker, UnavailablePicker, QueuePicker } from './picker'; import { BackoffOptions, BackoffTimeout } from './backoff-timeout'; import { Status } from './constants'; -import { StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { Metadata } from './metadata'; import * as logging from './logging'; import { LogVerbosity } from './constants'; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 315c9d9aa..388a8d339 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -20,7 +20,6 @@ import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; import * as zlib from 'zlib'; -import { Deadline, StatusObject } from './call-stream'; import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, @@ -33,6 +32,8 @@ import { StreamDecoder } from './stream-decoder'; import { ObjectReadable, ObjectWritable } from './object-stream'; import { ChannelOptions } from './channel-options'; import * as logging from './logging'; +import { StatusObject } from './call-interface'; +import { Deadline } from './deadline'; const TRACER_NAME = 'server_call'; @@ -508,6 +509,8 @@ export class Http2ServerCallStream< receiveMetadata(headers: http2.IncomingHttpHeaders) { const metadata = Metadata.fromHttp2Headers(headers); + trace('Request to ' + this.handler.path + ' received headers ' + JSON.stringify(metadata.toJSON())); + // TODO(cjihrig): Receive compression metadata. const timeoutHeader = metadata.get(GRPC_TIMEOUT_HEADER); diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index f310597e9..12802dad8 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -27,6 +27,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as os from 'os'; +import { Status } from './constants'; import { Duration } from './duration'; import { LoadBalancingConfig, @@ -38,18 +39,40 @@ export interface MethodConfigName { method?: string; } +export interface RetryPolicy { + maxAttempts: number; + initialBackoff: string; + maxBackoff: string; + backoffMultiplier: number; + retryableStatusCodes: (Status | string)[]; +} + +export interface HedgingPolicy { + maxAttempts: number; + hedgingDelay?: string; + nonFatalStatusCodes: (Status | string)[]; +} + export interface MethodConfig { name: MethodConfigName[]; waitForReady?: boolean; timeout?: Duration; maxRequestBytes?: number; maxResponseBytes?: number; + retryPolicy?: RetryPolicy; + hedgingPolicy?: HedgingPolicy; +} + +export interface RetryThrottling { + maxTokens: number; + tokenRatio: number; } export interface ServiceConfig { loadBalancingPolicy?: string; loadBalancingConfig: LoadBalancingConfig[]; methodConfig: MethodConfig[]; + retryThrottling?: RetryThrottling; } export interface ServiceConfigCanaryConfig { diff --git a/packages/grpc-js/src/status-builder.ts b/packages/grpc-js/src/status-builder.ts index 1109af1ac..78e2ea310 100644 --- a/packages/grpc-js/src/status-builder.ts +++ b/packages/grpc-js/src/status-builder.ts @@ -15,7 +15,7 @@ * */ -import { StatusObject } from './call-stream'; +import { StatusObject } from './call-interface'; import { Status } from './constants'; import { Metadata } from './metadata'; diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts new file mode 100644 index 000000000..ac34823ba --- /dev/null +++ b/packages/grpc-js/src/subchannel-call.ts @@ -0,0 +1,504 @@ +/* + * Copyright 2019 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as http2 from 'http2'; +import * as os from 'os'; + +import { Status } from './constants'; +import { Metadata } from './metadata'; +import { StreamDecoder } from './stream-decoder'; +import { SubchannelCallStatsTracker, Subchannel } from './subchannel'; +import * as logging from './logging'; +import { LogVerbosity } from './constants'; +import { ServerSurfaceCall } from './server-call'; +import { Deadline } from './deadline'; +import { InterceptingListener, MessageContext, StatusObject, WriteCallback } from './call-interface'; + +const TRACER_NAME = 'subchannel_call'; + +const { + HTTP2_HEADER_STATUS, + HTTP2_HEADER_CONTENT_TYPE, + NGHTTP2_CANCEL, +} = http2.constants; + +/** + * https://nodejs.org/api/errors.html#errors_class_systemerror + */ +interface SystemError extends Error { + address?: string; + code: string; + dest?: string; + errno: number; + info?: object; + message: string; + path?: string; + port?: number; + syscall: string; +} + +/** + * Should do approximately the same thing as util.getSystemErrorName but the + * TypeScript types don't have that function for some reason so I just made my + * own. + * @param errno + */ +function getSystemErrorName(errno: number): string { + for (const [name, num] of Object.entries(os.constants.errno)) { + if (num === errno) { + return name; + } + } + return 'Unknown system error ' + errno; +} + +export interface SubchannelCall { + cancelWithStatus(status: Status, details: string): void; + getPeer(): string; + sendMessageWithContext(context: MessageContext, message: Buffer): void; + startRead(): void; + halfClose(): void; + getCallNumber(): number; +} + +export class Http2SubchannelCall implements SubchannelCall { + private decoder = new StreamDecoder(); + + private isReadFilterPending = false; + private canPush = false; + /** + * Indicates that an 'end' event has come from the http2 stream, so there + * will be no more data events. + */ + private readsClosed = false; + + private statusOutput = false; + + private unpushedReadMessages: Buffer[] = []; + + // Status code mapped from :status. To be used if grpc-status is not received + private mappedStatusCode: Status = Status.UNKNOWN; + + // This is populated (non-null) if and only if the call has ended + private finalStatus: StatusObject | null = null; + + private disconnectListener: () => void; + + private internalError: SystemError | null = null; + + constructor( + private readonly http2Stream: http2.ClientHttp2Stream, + private readonly callStatsTracker: SubchannelCallStatsTracker, + private readonly listener: InterceptingListener, + private readonly subchannel: Subchannel, + private readonly callId: number + ) { + this.disconnectListener = () => { + this.endCall({ + code: Status.UNAVAILABLE, + details: 'Connection dropped', + metadata: new Metadata(), + }); + }; + subchannel.addDisconnectListener(this.disconnectListener); + subchannel.callRef(); + http2Stream.on('response', (headers, flags) => { + let headersString = ''; + for (const header of Object.keys(headers)) { + headersString += '\t\t' + header + ': ' + headers[header] + '\n'; + } + this.trace('Received server headers:\n' + headersString); + switch (headers[':status']) { + // TODO(murgatroid99): handle 100 and 101 + case 400: + this.mappedStatusCode = Status.INTERNAL; + break; + case 401: + this.mappedStatusCode = Status.UNAUTHENTICATED; + break; + case 403: + this.mappedStatusCode = Status.PERMISSION_DENIED; + break; + case 404: + this.mappedStatusCode = Status.UNIMPLEMENTED; + break; + case 429: + case 502: + case 503: + case 504: + this.mappedStatusCode = Status.UNAVAILABLE; + break; + default: + this.mappedStatusCode = Status.UNKNOWN; + } + + if (flags & http2.constants.NGHTTP2_FLAG_END_STREAM) { + this.handleTrailers(headers); + } else { + let metadata: Metadata; + try { + metadata = Metadata.fromHttp2Headers(headers); + } catch (error) { + this.endCall({ + code: Status.UNKNOWN, + details: (error as Error).message, + metadata: new Metadata(), + }); + return; + } + this.listener.onReceiveMetadata(metadata); + } + }); + http2Stream.on('trailers', (headers: http2.IncomingHttpHeaders) => { + this.handleTrailers(headers); + }); + http2Stream.on('data', (data: Buffer) => { + this.trace('receive HTTP/2 data frame of length ' + data.length); + const messages = this.decoder.write(data); + + for (const message of messages) { + this.trace('parsed message of length ' + message.length); + this.callStatsTracker!.addMessageReceived(); + this.tryPush(message); + } + }); + http2Stream.on('end', () => { + this.readsClosed = true; + this.maybeOutputStatus(); + }); + http2Stream.on('close', () => { + /* Use process.next tick to ensure that this code happens after any + * "error" event that may be emitted at about the same time, so that + * we can bubble up the error message from that event. */ + process.nextTick(() => { + this.trace('HTTP/2 stream closed with code ' + http2Stream.rstCode); + /* If we have a final status with an OK status code, that means that + * we have received all of the messages and we have processed the + * trailers and the call completed successfully, so it doesn't matter + * how the stream ends after that */ + if (this.finalStatus?.code === Status.OK) { + return; + } + let code: Status; + let details = ''; + switch (http2Stream.rstCode) { + case http2.constants.NGHTTP2_NO_ERROR: + /* If we get a NO_ERROR code and we already have a status, the + * stream completed properly and we just haven't fully processed + * it yet */ + if (this.finalStatus !== null) { + return; + } + code = Status.INTERNAL; + details = `Received RST_STREAM with code ${http2Stream.rstCode}`; + break; + case http2.constants.NGHTTP2_REFUSED_STREAM: + code = Status.UNAVAILABLE; + details = 'Stream refused by server'; + break; + case http2.constants.NGHTTP2_CANCEL: + code = Status.CANCELLED; + details = 'Call cancelled'; + break; + case http2.constants.NGHTTP2_ENHANCE_YOUR_CALM: + code = Status.RESOURCE_EXHAUSTED; + details = 'Bandwidth exhausted or memory limit exceeded'; + break; + case http2.constants.NGHTTP2_INADEQUATE_SECURITY: + code = Status.PERMISSION_DENIED; + details = 'Protocol not secure enough'; + break; + case http2.constants.NGHTTP2_INTERNAL_ERROR: + code = Status.INTERNAL; + if (this.internalError === null) { + /* This error code was previously handled in the default case, and + * there are several instances of it online, so I wanted to + * preserve the original error message so that people find existing + * information in searches, but also include the more recognizable + * "Internal server error" message. */ + details = `Received RST_STREAM with code ${http2Stream.rstCode} (Internal server error)`; + } else { + if (this.internalError.code === 'ECONNRESET' || this.internalError.code === 'ETIMEDOUT') { + code = Status.UNAVAILABLE; + details = this.internalError.message; + } else { + /* The "Received RST_STREAM with code ..." error is preserved + * here for continuity with errors reported online, but the + * error message at the end will probably be more relevant in + * most cases. */ + details = `Received RST_STREAM with code ${http2Stream.rstCode} triggered by internal client error: ${this.internalError.message}`; + } + } + break; + default: + code = Status.INTERNAL; + details = `Received RST_STREAM with code ${http2Stream.rstCode}`; + } + // This is a no-op if trailers were received at all. + // This is OK, because status codes emitted here correspond to more + // catastrophic issues that prevent us from receiving trailers in the + // first place. + this.endCall({ code, details, metadata: new Metadata() }); + }); + }); + http2Stream.on('error', (err: SystemError) => { + /* We need an error handler here to stop "Uncaught Error" exceptions + * from bubbling up. However, errors here should all correspond to + * "close" events, where we will handle the error more granularly */ + /* Specifically looking for stream errors that were *not* constructed + * from a RST_STREAM response here: + * https://github.com/nodejs/node/blob/8b8620d580314050175983402dfddf2674e8e22a/lib/internal/http2/core.js#L2267 + */ + if (err.code !== 'ERR_HTTP2_STREAM_ERROR') { + this.trace( + 'Node error event: message=' + + err.message + + ' code=' + + err.code + + ' errno=' + + getSystemErrorName(err.errno) + + ' syscall=' + + err.syscall + ); + this.internalError = err; + } + this.callStatsTracker.onStreamEnd(false); + }); + } + + private outputStatus() { + /* Precondition: this.finalStatus !== null */ + if (!this.statusOutput) { + this.statusOutput = true; + this.trace( + 'ended with status: code=' + + this.finalStatus!.code + + ' details="' + + this.finalStatus!.details + + '"' + ); + this.callStatsTracker.onCallEnd(this.finalStatus!); + /* We delay the actual action of bubbling up the status to insulate the + * cleanup code in this class from any errors that may be thrown in the + * upper layers as a result of bubbling up the status. In particular, + * if the status is not OK, the "error" event may be emitted + * synchronously at the top level, which will result in a thrown error if + * the user does not handle that event. */ + process.nextTick(() => { + this.listener.onReceiveStatus(this.finalStatus!); + }); + this.subchannel.callUnref(); + this.subchannel.removeDisconnectListener(this.disconnectListener); + } + } + + private trace(text: string): void { + logging.trace( + LogVerbosity.DEBUG, + TRACER_NAME, + '[' + this.callId + '] ' + text + ); + } + + /** + * On first call, emits a 'status' event with the given StatusObject. + * Subsequent calls are no-ops. + * @param status The status of the call. + */ + private endCall(status: StatusObject): void { + /* If the status is OK and a new status comes in (e.g. from a + * deserialization failure), that new status takes priority */ + if (this.finalStatus === null || this.finalStatus.code === Status.OK) { + this.finalStatus = status; + this.maybeOutputStatus(); + } + this.destroyHttp2Stream(); + } + + private maybeOutputStatus() { + if (this.finalStatus !== null) { + /* The combination check of readsClosed and that the two message buffer + * arrays are empty checks that there all incoming data has been fully + * processed */ + if ( + this.finalStatus.code !== Status.OK || + (this.readsClosed && + this.unpushedReadMessages.length === 0 && + !this.isReadFilterPending) + ) { + this.outputStatus(); + } + } + } + + private push(message: Buffer): void { + this.trace( + 'pushing to reader message of length ' + + (message instanceof Buffer ? message.length : null) + ); + this.canPush = false; + process.nextTick(() => { + /* If we have already output the status any later messages should be + * ignored, and can cause out-of-order operation errors higher up in the + * stack. Checking as late as possible here to avoid any race conditions. + */ + if (this.statusOutput) { + return; + } + this.listener.onReceiveMessage(message); + this.maybeOutputStatus(); + }); + } + + private tryPush(messageBytes: Buffer): void { + if (this.canPush) { + this.http2Stream!.pause(); + this.push(messageBytes); + } else { + this.trace( + 'unpushedReadMessages.push message of length ' + messageBytes.length + ); + this.unpushedReadMessages.push(messageBytes); + } + } + + private handleTrailers(headers: http2.IncomingHttpHeaders) { + this.callStatsTracker.onStreamEnd(true); + let headersString = ''; + for (const header of Object.keys(headers)) { + headersString += '\t\t' + header + ': ' + headers[header] + '\n'; + } + this.trace('Received server trailers:\n' + headersString); + let metadata: Metadata; + try { + metadata = Metadata.fromHttp2Headers(headers); + } catch (e) { + metadata = new Metadata(); + } + const metadataMap = metadata.getMap(); + let code: Status = this.mappedStatusCode; + if ( + code === Status.UNKNOWN && + typeof metadataMap['grpc-status'] === 'string' + ) { + const receivedStatus = Number(metadataMap['grpc-status']); + if (receivedStatus in Status) { + code = receivedStatus; + this.trace('received status code ' + receivedStatus + ' from server'); + } + metadata.remove('grpc-status'); + } + let details = ''; + if (typeof metadataMap['grpc-message'] === 'string') { + details = decodeURI(metadataMap['grpc-message']); + metadata.remove('grpc-message'); + this.trace( + 'received status details string "' + details + '" from server' + ); + } + const status: StatusObject = { code, details, metadata }; + // This is a no-op if the call was already ended when handling headers. + this.endCall(status); + } + + private destroyHttp2Stream() { + // The http2 stream could already have been destroyed if cancelWithStatus + // is called in response to an internal http2 error. + if (!this.http2Stream.destroyed) { + /* If the call has ended with an OK status, communicate that when closing + * the stream, partly to avoid a situation in which we detect an error + * RST_STREAM as a result after we have the status */ + let code: number; + if (this.finalStatus?.code === Status.OK) { + code = http2.constants.NGHTTP2_NO_ERROR; + } else { + code = http2.constants.NGHTTP2_CANCEL; + } + this.trace('close http2 stream with code ' + code); + this.http2Stream.close(code); + } + } + + cancelWithStatus(status: Status, details: string): void { + this.trace( + 'cancelWithStatus code: ' + status + ' details: "' + details + '"' + ); + this.endCall({ code: status, details, metadata: new Metadata() }); + } + + getStatus(): StatusObject | null { + return this.finalStatus; + } + + getPeer(): string { + return this.subchannel.getAddress(); + } + + getCallNumber(): number { + return this.callId; + } + + startRead() { + /* If the stream has ended with an error, we should not emit any more + * messages and we should communicate that the stream has ended */ + if (this.finalStatus !== null && this.finalStatus.code !== Status.OK) { + this.readsClosed = true; + this.maybeOutputStatus(); + return; + } + this.canPush = true; + if (this.unpushedReadMessages.length > 0) { + const nextMessage: Buffer = this.unpushedReadMessages.shift()!; + this.push(nextMessage); + return; + } + /* Only resume reading from the http2Stream if we don't have any pending + * messages to emit */ + this.http2Stream.resume(); + } + + sendMessageWithContext(context: MessageContext, message: Buffer) { + this.trace('write() called with message of length ' + message.length); + const cb: WriteCallback = (error?: Error | null) => { + let code: Status = Status.UNAVAILABLE; + if ((error as NodeJS.ErrnoException)?.code === 'ERR_STREAM_WRITE_AFTER_END') { + code = Status.INTERNAL; + } + if (error) { + this.cancelWithStatus(code, `Write error: ${error.message}`); + } + context.callback?.(); + }; + this.trace('sending data chunk of length ' + message.length); + this.callStatsTracker.addMessageSent(); + try { + this.http2Stream!.write(message, cb); + } catch (error) { + this.endCall({ + code: Status.UNAVAILABLE, + details: `Write failed with error ${(error as Error).message}`, + metadata: new Metadata() + }); + } + } + + halfClose() { + this.trace('end() called'); + this.trace('calling end() on HTTP/2 stream'); + this.http2Stream.end(); + } +} diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 800274f99..563e69464 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -18,7 +18,6 @@ import * as http2 from 'http2'; import { ChannelCredentials } from './channel-credentials'; import { Metadata } from './metadata'; -import { Call, Http2CallStream, WriteObject } from './call-stream'; import { ChannelOptions } from './channel-options'; import { PeerCertificate, checkServerIdentity, TLSSocket, CipherNameAndProtocol } from 'tls'; import { ConnectivityState } from './connectivity-state'; @@ -30,7 +29,6 @@ import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as net from 'net'; import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; import { ConnectionOptions } from 'tls'; -import { FilterFactory, Filter, BaseFilter } from './filter'; import { stringToSubchannelAddress, SubchannelAddress, @@ -38,18 +36,16 @@ import { } from './subchannel-address'; import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, SocketInfo, SocketRef, unregisterChannelzRef, registerChannelzSocket, TlsInfo } from './channelz'; import { ConnectivityStateListener } from './subchannel-interface'; +import { Http2SubchannelCall } from './subchannel-call'; +import { getNextCallNumber } from './call-number'; +import { SubchannelCall } from './subchannel-call'; +import { InterceptingListener, StatusObject } from './call-interface'; const clientVersion = require('../../package.json').version; const TRACER_NAME = 'subchannel'; const FLOW_CONTROL_TRACER_NAME = 'subchannel_flowctrl'; -const MIN_CONNECT_TIMEOUT_MS = 20000; -const INITIAL_BACKOFF_MS = 1000; -const BACKOFF_MULTIPLIER = 1.6; -const MAX_BACKOFF_MS = 120000; -const BACKOFF_JITTER = 0.2; - /* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't * have a constant for the max signed 32 bit integer, so this is a simple way * to calculate it */ @@ -59,6 +55,8 @@ const KEEPALIVE_TIMEOUT_MS = 20000; export interface SubchannelCallStatsTracker { addMessageSent(): void; addMessageReceived(): void; + onCallEnd(status: StatusObject): void; + onStreamEnd(success: boolean): void; } const { @@ -70,15 +68,6 @@ const { HTTP2_HEADER_USER_AGENT, } = http2.constants; -/** - * Get a number uniformly at random in the range [min, max) - * @param min - * @param max - */ -function uniformRandom(min: number, max: number) { - return Math.random() * (max - min) + min; -} - const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); export class Subchannel { @@ -808,24 +797,13 @@ export class Subchannel { return false; } - /** - * Start a stream on the current session with the given `metadata` as headers - * and then attach it to the `callStream`. Must only be called if the - * subchannel's current connectivity state is READY. - * @param metadata - * @param callStream - */ - startCallStream( - metadata: Metadata, - callStream: Http2CallStream, - extraFilters: Filter[] - ) { + createCall(metadata: Metadata, host: string, method: string, listener: InterceptingListener): SubchannelCall { const headers = metadata.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = callStream.getHost(); + headers[HTTP2_HEADER_AUTHORITY] = host; headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; headers[HTTP2_HEADER_METHOD] = 'POST'; - headers[HTTP2_HEADER_PATH] = callStream.getMethod(); + headers[HTTP2_HEADER_PATH] = method; headers[HTTP2_HEADER_TE] = 'trailers'; let http2Stream: http2.ClientHttp2Stream; /* In theory, if an error is thrown by session.request because session has @@ -845,19 +823,6 @@ export class Subchannel { ); throw e; } - let headersString = ''; - for (const header of Object.keys(headers)) { - headersString += '\t\t' + header + ': ' + headers[header] + '\n'; - } - logging.trace( - LogVerbosity.DEBUG, - 'call_stream', - 'Starting stream [' + callStream.getCallNumber() + '] on subchannel ' + - '(' + this.channelzRef.id + ') ' + - this.subchannelAddressString + - ' with headers\n' + - headersString - ); this.flowControlTrace( 'local window size: ' + this.session!.state.localWindowSize + @@ -875,23 +840,7 @@ export class Subchannel { let statsTracker: SubchannelCallStatsTracker; if (this.channelzEnabled) { this.callTracker.addCallStarted(); - callStream.addStatusWatcher(status => { - if (status.code === Status.OK) { - this.callTracker.addCallSucceeded(); - } else { - this.callTracker.addCallFailed(); - } - }); this.streamTracker.addCallStarted(); - callStream.addStreamEndWatcher(success => { - if (streamSession === this.session) { - if (success) { - this.streamTracker.addCallSucceeded(); - } else { - this.streamTracker.addCallFailed(); - } - } - }); statsTracker = { addMessageSent: () => { this.messagesSent += 1; @@ -899,15 +848,33 @@ export class Subchannel { }, addMessageReceived: () => { this.messagesReceived += 1; + }, + onCallEnd: status => { + if (status.code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }, + onStreamEnd: success => { + if (streamSession === this.session) { + if (success) { + this.streamTracker.addCallSucceeded(); + } else { + this.streamTracker.addCallFailed(); + } + } } } } else { statsTracker = { addMessageSent: () => {}, - addMessageReceived: () => {} + addMessageReceived: () => {}, + onCallEnd: () => {}, + onStreamEnd: () => {} } } - callStream.attachHttp2Stream(http2Stream, this, extraFilters, statsTracker); + return new Http2SubchannelCall(http2Stream, statsTracker, listener, this, getNextCallNumber()); } /** diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index 354413ea6..1bcaabeb4 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -23,7 +23,7 @@ import * as resolver_dns from '../src/resolver-dns'; import * as resolver_uds from '../src/resolver-uds'; import * as resolver_ip from '../src/resolver-ip'; import { ServiceConfig } from '../src/service-config'; -import { StatusObject } from '../src/call-stream'; +import { StatusObject } from '../src/call-interface'; import { SubchannelAddress, isTcpSubchannelAddress, subchannelAddressToString } from "../src/subchannel-address"; import { parseUri, GrpcUri } from '../src/uri-parser'; From 8a312e63b719fe0166acb07c8a43f2a91253ea17 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 11 Oct 2022 16:50:49 -0700 Subject: [PATCH 1774/1899] grpc-js-xds: Update code to handle modified experimental APIs --- .../src/http-filter/fault-injection-filter.ts | 8 ++--- .../src/http-filter/router-filter.ts | 2 +- packages/grpc-js-xds/src/load-balancer-eds.ts | 28 +++-------------- packages/grpc-js-xds/src/load-balancer-lrs.ts | 31 +++---------------- .../src/load-balancer-xds-cluster-manager.ts | 4 +-- 5 files changed, 16 insertions(+), 57 deletions(-) diff --git a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts index a49ec77d4..b02dfbc80 100644 --- a/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts +++ b/packages/grpc-js-xds/src/http-filter/fault-injection-filter.ts @@ -231,7 +231,7 @@ const NUMBER_REGEX = /\d+/; let totalActiveFaults = 0; class FaultInjectionFilter extends BaseFilter implements Filter { - constructor(private callStream: CallStream, private config: FaultInjectionConfig) { + constructor(private config: FaultInjectionConfig) { super(); } @@ -316,7 +316,7 @@ class FaultInjectionFilter extends BaseFilter implements Filter { } } if (abortStatus !== null && rollRandomPercentage(numerator, denominator)) { - this.callStream.cancelWithStatus(abortStatus, 'Fault injected'); + return Promise.reject({code: abortStatus, details: 'Fault injected', metadata: new Metadata()}); } } return metadata; @@ -333,8 +333,8 @@ class FaultInjectionFilterFactory implements FilterFactory } } - createFilter(callStream: experimental.CallStream): FaultInjectionFilter { - return new FaultInjectionFilter(callStream, this.config); + createFilter(): FaultInjectionFilter { + return new FaultInjectionFilter(this.config); } } diff --git a/packages/grpc-js-xds/src/http-filter/router-filter.ts b/packages/grpc-js-xds/src/http-filter/router-filter.ts index 81450c0ff..172a08740 100644 --- a/packages/grpc-js-xds/src/http-filter/router-filter.ts +++ b/packages/grpc-js-xds/src/http-filter/router-filter.ts @@ -26,7 +26,7 @@ class RouterFilter extends BaseFilter implements Filter {} class RouterFilterFactory implements FilterFactory { constructor(config: HttpFilterConfig, overrideConfig?: HttpFilterConfig) {} - createFilter(callStream: experimental.CallStream): RouterFilter { + createFilter(): RouterFilter { return new RouterFilter(); } } diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index e7aac0571..39ad2c2cb 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -146,24 +146,6 @@ export class EdsLoadBalancingConfig implements LoadBalancingConfig { } } -class CallEndTrackingFilter extends BaseFilter implements Filter { - constructor(private onCallEnd: () => void) { - super(); - } - receiveTrailers(status: StatusObject) { - this.onCallEnd(); - return status; - } -} - -class CallTrackingFilterFactory implements FilterFactory { - constructor(private onCallEnd: () => void) {} - - createFilter(callStream: CallStream) { - return new CallEndTrackingFilter(this.onCallEnd); - } -} - /** * This class load balances over a cluster by making an EDS request and then * transforming the result into a configuration for another load balancing @@ -217,9 +199,6 @@ export class EdsLoadBalancer implements LoadBalancer { * balancer. */ if (dropCategory === null) { const originalPick = originalPicker.pick(pickArgs); - const trackingFilterFactory: FilterFactory = new CallTrackingFilterFactory(() => { - this.concurrentRequests -= 1; - }); return { pickResultType: originalPick.pickResultType, status: originalPick.status, @@ -228,7 +207,10 @@ export class EdsLoadBalancer implements LoadBalancer { originalPick.onCallStarted?.(); this.concurrentRequests += 1; }, - extraFilterFactories: originalPick.extraFilterFactories.concat(trackingFilterFactory) + onCallEnded: status => { + originalPick.onCallEnded?.(status); + this.concurrentRequests -= 1; + } }; } else { let details: string; @@ -247,7 +229,7 @@ export class EdsLoadBalancer implements LoadBalancer { metadata: new Metadata(), }, subchannel: null, - extraFilterFactories: [], + onCallEnded: null, onCallStarted: null }; } diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index 145501fe9..0eaeeee34 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -108,29 +108,6 @@ export class LrsLoadBalancingConfig implements LoadBalancingConfig { } } -/** - * Filter class that reports when the call ends. - */ -class CallEndTrackingFilter extends BaseFilter implements Filter { - constructor(private localityStatsReporter: XdsClusterLocalityStats) { - super(); - } - - receiveTrailers(status: StatusObject) { - this.localityStatsReporter.addCallFinished(status.code !== Status.OK); - return status; - } -} - -class CallEndTrackingFilterFactory - implements FilterFactory { - constructor(private localityStatsReporter: XdsClusterLocalityStats) {} - - createFilter(callStream: Call): CallEndTrackingFilter { - return new CallEndTrackingFilter(this.localityStatsReporter); - } -} - /** * Picker that delegates picking to another picker, and reports when calls * created using those picks start and end. @@ -144,9 +121,6 @@ class LoadReportingPicker implements Picker { pick(pickArgs: PickArgs): PickResult { const wrappedPick = this.wrappedPicker.pick(pickArgs); if (wrappedPick.pickResultType === PickResultType.COMPLETE) { - const trackingFilterFactory = new CallEndTrackingFilterFactory( - this.localityStatsReporter - ); return { pickResultType: PickResultType.COMPLETE, subchannel: wrappedPick.subchannel, @@ -155,7 +129,10 @@ class LoadReportingPicker implements Picker { wrappedPick.onCallStarted?.(); this.localityStatsReporter.addCallStarted(); }, - extraFilterFactories: wrappedPick.extraFilterFactories.concat(trackingFilterFactory), + onCallEnded: status => { + wrappedPick.onCallEnded?.(status); + this.localityStatsReporter.addCallFinished(status !== Status.OK); + } }; } else { return wrappedPick; diff --git a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts index bfc55c809..bfdb4dccc 100644 --- a/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts +++ b/packages/grpc-js-xds/src/load-balancer-xds-cluster-manager.ts @@ -107,8 +107,8 @@ class XdsClusterManagerPicker implements Picker { metadata: new Metadata(), }, subchannel: null, - extraFilterFactories: [], - onCallStarted: null + onCallStarted: null, + onCallEnded: null }; } } From 3003dbea52a9c78ae78292b874ee4677f4667010 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Oct 2022 13:47:53 -0700 Subject: [PATCH 1775/1899] grpc-js-xds: Delete generated code for xDS v2 --- packages/grpc-js-xds/package.json | 3 +- packages/grpc-js-xds/src/generated/ads.ts | 57 ----- .../envoy/api/v2/DeltaDiscoveryRequest.ts | 202 ------------------ .../envoy/api/v2/DeltaDiscoveryResponse.ts | 63 ------ .../envoy/api/v2/DiscoveryRequest.ts | 110 ---------- .../envoy/api/v2/DiscoveryResponse.ts | 108 ---------- .../src/generated/envoy/api/v2/Resource.ts | 43 ---- .../generated/envoy/api/v2/core/Address.ts | 26 --- .../envoy/api/v2/core/AsyncDataSource.ts | 34 --- .../envoy/api/v2/core/BackoffStrategy.ts | 43 ---- .../generated/envoy/api/v2/core/BindConfig.ts | 49 ----- .../envoy/api/v2/core/BuildVersion.ts | 36 ---- .../generated/envoy/api/v2/core/CidrRange.ts | 33 --- .../envoy/api/v2/core/ControlPlane.ts | 26 --- .../generated/envoy/api/v2/core/DataSource.ts | 40 ---- .../generated/envoy/api/v2/core/Extension.ts | 75 ------- .../generated/envoy/api/v2/core/HeaderMap.ts | 17 -- .../envoy/api/v2/core/HeaderValue.ts | 38 ---- .../envoy/api/v2/core/HeaderValueOption.ts | 34 --- .../generated/envoy/api/v2/core/HttpUri.ts | 79 ------- .../generated/envoy/api/v2/core/Locality.ts | 56 ----- .../generated/envoy/api/v2/core/Metadata.ts | 67 ------ .../src/generated/envoy/api/v2/core/Node.ts | 173 --------------- .../src/generated/envoy/api/v2/core/Pipe.ts | 30 --- .../envoy/api/v2/core/RemoteDataSource.ts | 40 ---- .../envoy/api/v2/core/RequestMethod.ts | 17 -- .../envoy/api/v2/core/RetryPolicy.ts | 38 ---- .../envoy/api/v2/core/RoutingPriority.ts | 15 -- .../envoy/api/v2/core/RuntimeDouble.ts | 30 --- .../envoy/api/v2/core/RuntimeFeatureFlag.ts | 35 --- .../api/v2/core/RuntimeFractionalPercent.ts | 49 ----- .../envoy/api/v2/core/RuntimeUInt32.ts | 30 --- .../envoy/api/v2/core/SocketAddress.ts | 97 --------- .../envoy/api/v2/core/SocketOption.ts | 90 -------- .../envoy/api/v2/core/TcpKeepalive.ts | 43 ---- .../envoy/api/v2/core/TrafficDirection.ts | 19 -- .../envoy/api/v2/core/TransportSocket.ts | 46 ---- .../envoy/api/v2/endpoint/ClusterStats.ts | 117 ---------- .../v2/endpoint/EndpointLoadMetricStats.ts | 41 ---- .../api/v2/endpoint/UpstreamEndpointStats.ts | 106 --------- .../api/v2/endpoint/UpstreamLocalityStats.ts | 108 ---------- .../envoy/service/discovery/v2/AdsDummy.ts | 16 -- .../v2/AggregatedDiscoveryService.ts | 58 ----- .../load_stats/v2/LoadReportingService.ts | 113 ---------- .../service/load_stats/v2/LoadStatsRequest.ts | 34 --- .../load_stats/v2/LoadStatsResponse.ts | 71 ------ .../generated/envoy/type/FractionalPercent.ts | 68 ------ .../src/generated/envoy/type/Percent.ts | 16 -- .../generated/envoy/type/SemanticVersion.ts | 24 --- packages/grpc-js-xds/src/generated/lrs.ts | 51 ----- 50 files changed, 1 insertion(+), 2813 deletions(-) delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/type/Percent.ts delete mode 100644 packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index fcb9279f0..124c3ed7d 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -12,7 +12,7 @@ "prepare": "npm run compile", "pretest": "npm run compile", "posttest": "npm run check", - "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v2/ads.proto envoy/service/load_stats/v2/lrs.proto envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto", + "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto", "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" }, "repository": { @@ -56,7 +56,6 @@ "src/**/*.ts", "build/src/**/*.{js,d.ts,js.map}", "deps/envoy-api/envoy/admin/v3/**/*.proto", - "deps/envoy-api/envoy/api/v2/**/*.proto", "deps/envoy-api/envoy/config/**/*.proto", "deps/envoy-api/envoy/service/**/*.proto", "deps/envoy-api/envoy/type/**/*.proto", diff --git a/packages/grpc-js-xds/src/generated/ads.ts b/packages/grpc-js-xds/src/generated/ads.ts index e0e46bb25..228f6f1d4 100644 --- a/packages/grpc-js-xds/src/generated/ads.ts +++ b/packages/grpc-js-xds/src/generated/ads.ts @@ -1,7 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v2_AggregatedDiscoveryServiceClient, AggregatedDiscoveryServiceDefinition as _envoy_service_discovery_v2_AggregatedDiscoveryServiceDefinition } from './envoy/service/discovery/v2/AggregatedDiscoveryService'; import type { AggregatedDiscoveryServiceClient as _envoy_service_discovery_v3_AggregatedDiscoveryServiceClient, AggregatedDiscoveryServiceDefinition as _envoy_service_discovery_v3_AggregatedDiscoveryServiceDefinition } from './envoy/service/discovery/v3/AggregatedDiscoveryService'; type SubtypeConstructor any, Subtype> = { @@ -12,47 +11,6 @@ export interface ProtoGrpcType { envoy: { annotations: { } - api: { - v2: { - DeltaDiscoveryRequest: MessageTypeDefinition - DeltaDiscoveryResponse: MessageTypeDefinition - DiscoveryRequest: MessageTypeDefinition - DiscoveryResponse: MessageTypeDefinition - Resource: MessageTypeDefinition - core: { - Address: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition - BindConfig: MessageTypeDefinition - BuildVersion: MessageTypeDefinition - CidrRange: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - DataSource: MessageTypeDefinition - Extension: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - HeaderValue: MessageTypeDefinition - HeaderValueOption: MessageTypeDefinition - HttpUri: MessageTypeDefinition - Locality: MessageTypeDefinition - Metadata: MessageTypeDefinition - Node: MessageTypeDefinition - Pipe: MessageTypeDefinition - RemoteDataSource: MessageTypeDefinition - RequestMethod: EnumTypeDefinition - RetryPolicy: MessageTypeDefinition - RoutingPriority: EnumTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition - RuntimeFractionalPercent: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - SocketAddress: MessageTypeDefinition - SocketOption: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - TrafficDirection: EnumTypeDefinition - TransportSocket: MessageTypeDefinition - } - } - } config: { core: { v3: { @@ -95,18 +53,6 @@ export interface ProtoGrpcType { } service: { discovery: { - v2: { - AdsDummy: MessageTypeDefinition - /** - * See https://github.com/lyft/envoy-api#apis for a description of the role of - * ADS and how it is intended to be used by a management server. ADS requests - * have the same structure as their singleton xDS counterparts, but can - * multiplex many resource types on a single stream. The type_url in the - * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover - * the multiplexed singleton APIs at the Envoy instance and management server. - */ - AggregatedDiscoveryService: SubtypeConstructor & { service: _envoy_service_discovery_v2_AggregatedDiscoveryServiceDefinition } - } v3: { AdsDummy: MessageTypeDefinition /** @@ -127,9 +73,6 @@ export interface ProtoGrpcType { } } type: { - FractionalPercent: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition v3: { FractionalPercent: MessageTypeDefinition Percent: MessageTypeDefinition diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts deleted file mode 100644 index 20ddb1b14..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryRequest.ts +++ /dev/null @@ -1,202 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/discovery.proto - -import type { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; - -/** - * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC - * endpoint for Delta xDS. - * - * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full - * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a - * diff to the state of a xDS client. - * In Delta XDS there are per-resource versions, which allow tracking state at - * the resource granularity. - * An xDS Delta session is always in the context of a gRPC bidirectional - * stream. This allows the xDS server to keep track of the state of xDS clients - * connected to it. - * - * In Delta xDS the nonce field is required and used to pair - * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. - * Optionally, a response message level system_version_info is present for - * debugging purposes only. - * - * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest - * can be either or both of: [1] informing the server of what resources the - * client has gained/lost interest in (using resource_names_subscribe and - * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from - * the server (using response_nonce, with presence of error_detail making it a NACK). - * Additionally, the first message (for a given type_url) of a reconnected gRPC stream - * has a third role: informing the server of the resources (and their versions) - * that the client already possesses, using the initial_resource_versions field. - * - * As with state-of-the-world, when multiple resource types are multiplexed (ADS), - * all requests/acknowledgments/updates are logically walled off by type_url: - * a Cluster ACK exists in a completely separate world from a prior Route NACK. - * In particular, initial_resource_versions being sent at the "start" of every - * gRPC stream actually entails a message for each type_url, each with its own - * initial_resource_versions. - * [#next-free-field: 8] - */ -export interface DeltaDiscoveryRequest { - /** - * The node making the request. - */ - 'node'?: (_envoy_api_v2_core_Node | null); - /** - * Type of the resource that is being requested, e.g. - * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". - */ - 'type_url'?: (string); - /** - * DeltaDiscoveryRequests allow the client to add or remove individual - * resources to the set of tracked resources in the context of a stream. - * All resource names in the resource_names_subscribe list are added to the - * set of tracked resources and all resource names in the resource_names_unsubscribe - * list are removed from the set of tracked resources. - * - * *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or - * resource_names_unsubscribe list simply means that no resources are to be - * added or removed to the resource list. - * *Like* state-of-the-world xDS, the server must send updates for all tracked - * resources, but can also send updates for resources the client has not subscribed to. - * - * NOTE: the server must respond with all resources listed in resource_names_subscribe, - * even if it believes the client has the most recent version of them. The reason: - * the client may have dropped them, but then regained interest before it had a chance - * to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. - * - * These two fields can be set in any DeltaDiscoveryRequest, including ACKs - * and initial_resource_versions. - * - * A list of Resource names to add to the list of tracked resources. - */ - 'resource_names_subscribe'?: (string)[]; - /** - * A list of Resource names to remove from the list of tracked resources. - */ - 'resource_names_unsubscribe'?: (string)[]; - /** - * Informs the server of the versions of the resources the xDS client knows of, to enable the - * client to continue the same logical xDS session even in the face of gRPC stream reconnection. - * It will not be populated: [1] in the very first stream of a session, since the client will - * not yet have any resources, [2] in any message after the first in a stream (for a given - * type_url), since the server will already be correctly tracking the client's state. - * (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) - * The map's keys are names of xDS resources known to the xDS client. - * The map's values are opaque resource versions. - */ - 'initial_resource_versions'?: ({[key: string]: string}); - /** - * When the DeltaDiscoveryRequest is a ACK or NACK message in response - * to a previous DeltaDiscoveryResponse, the response_nonce must be the - * nonce in the DeltaDiscoveryResponse. - * Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. - */ - 'response_nonce'?: (string); - /** - * This is populated when the previous :ref:`DiscoveryResponse ` - * failed to update configuration. The *message* field in *error_details* - * provides the Envoy internal exception related to the failure. - */ - 'error_detail'?: (_google_rpc_Status | null); -} - -/** - * DeltaDiscoveryRequest and DeltaDiscoveryResponse are used in a new gRPC - * endpoint for Delta xDS. - * - * With Delta xDS, the DeltaDiscoveryResponses do not need to include a full - * snapshot of the tracked resources. Instead, DeltaDiscoveryResponses are a - * diff to the state of a xDS client. - * In Delta XDS there are per-resource versions, which allow tracking state at - * the resource granularity. - * An xDS Delta session is always in the context of a gRPC bidirectional - * stream. This allows the xDS server to keep track of the state of xDS clients - * connected to it. - * - * In Delta xDS the nonce field is required and used to pair - * DeltaDiscoveryResponse to a DeltaDiscoveryRequest ACK or NACK. - * Optionally, a response message level system_version_info is present for - * debugging purposes only. - * - * DeltaDiscoveryRequest plays two independent roles. Any DeltaDiscoveryRequest - * can be either or both of: [1] informing the server of what resources the - * client has gained/lost interest in (using resource_names_subscribe and - * resource_names_unsubscribe), or [2] (N)ACKing an earlier resource update from - * the server (using response_nonce, with presence of error_detail making it a NACK). - * Additionally, the first message (for a given type_url) of a reconnected gRPC stream - * has a third role: informing the server of the resources (and their versions) - * that the client already possesses, using the initial_resource_versions field. - * - * As with state-of-the-world, when multiple resource types are multiplexed (ADS), - * all requests/acknowledgments/updates are logically walled off by type_url: - * a Cluster ACK exists in a completely separate world from a prior Route NACK. - * In particular, initial_resource_versions being sent at the "start" of every - * gRPC stream actually entails a message for each type_url, each with its own - * initial_resource_versions. - * [#next-free-field: 8] - */ -export interface DeltaDiscoveryRequest__Output { - /** - * The node making the request. - */ - 'node': (_envoy_api_v2_core_Node__Output | null); - /** - * Type of the resource that is being requested, e.g. - * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". - */ - 'type_url': (string); - /** - * DeltaDiscoveryRequests allow the client to add or remove individual - * resources to the set of tracked resources in the context of a stream. - * All resource names in the resource_names_subscribe list are added to the - * set of tracked resources and all resource names in the resource_names_unsubscribe - * list are removed from the set of tracked resources. - * - * *Unlike* state-of-the-world xDS, an empty resource_names_subscribe or - * resource_names_unsubscribe list simply means that no resources are to be - * added or removed to the resource list. - * *Like* state-of-the-world xDS, the server must send updates for all tracked - * resources, but can also send updates for resources the client has not subscribed to. - * - * NOTE: the server must respond with all resources listed in resource_names_subscribe, - * even if it believes the client has the most recent version of them. The reason: - * the client may have dropped them, but then regained interest before it had a chance - * to send the unsubscribe message. See DeltaSubscriptionStateTest.RemoveThenAdd. - * - * These two fields can be set in any DeltaDiscoveryRequest, including ACKs - * and initial_resource_versions. - * - * A list of Resource names to add to the list of tracked resources. - */ - 'resource_names_subscribe': (string)[]; - /** - * A list of Resource names to remove from the list of tracked resources. - */ - 'resource_names_unsubscribe': (string)[]; - /** - * Informs the server of the versions of the resources the xDS client knows of, to enable the - * client to continue the same logical xDS session even in the face of gRPC stream reconnection. - * It will not be populated: [1] in the very first stream of a session, since the client will - * not yet have any resources, [2] in any message after the first in a stream (for a given - * type_url), since the server will already be correctly tracking the client's state. - * (In ADS, the first message *of each type_url* of a reconnected stream populates this map.) - * The map's keys are names of xDS resources known to the xDS client. - * The map's values are opaque resource versions. - */ - 'initial_resource_versions': ({[key: string]: string}); - /** - * When the DeltaDiscoveryRequest is a ACK or NACK message in response - * to a previous DeltaDiscoveryResponse, the response_nonce must be the - * nonce in the DeltaDiscoveryResponse. - * Otherwise (unlike in DiscoveryRequest) response_nonce must be omitted. - */ - 'response_nonce': (string); - /** - * This is populated when the previous :ref:`DiscoveryResponse ` - * failed to update configuration. The *message* field in *error_details* - * provides the Envoy internal exception related to the failure. - */ - 'error_detail': (_google_rpc_Status__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts deleted file mode 100644 index 1a2584b95..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DeltaDiscoveryResponse.ts +++ /dev/null @@ -1,63 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/discovery.proto - -import type { Resource as _envoy_api_v2_Resource, Resource__Output as _envoy_api_v2_Resource__Output } from '../../../envoy/api/v2/Resource'; - -/** - * [#next-free-field: 7] - */ -export interface DeltaDiscoveryResponse { - /** - * The version of the response data (used for debugging). - */ - 'system_version_info'?: (string); - /** - * The response resources. These are typed resources, whose types must match - * the type_url field. - */ - 'resources'?: (_envoy_api_v2_Resource)[]; - /** - * Type URL for resources. Identifies the xDS API when muxing over ADS. - * Must be consistent with the type_url in the Any within 'resources' if 'resources' is non-empty. - */ - 'type_url'?: (string); - /** - * The nonce provides a way for DeltaDiscoveryRequests to uniquely - * reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. - */ - 'nonce'?: (string); - /** - * Resources names of resources that have be deleted and to be removed from the xDS Client. - * Removed resources for missing resources can be ignored. - */ - 'removed_resources'?: (string)[]; -} - -/** - * [#next-free-field: 7] - */ -export interface DeltaDiscoveryResponse__Output { - /** - * The version of the response data (used for debugging). - */ - 'system_version_info': (string); - /** - * The response resources. These are typed resources, whose types must match - * the type_url field. - */ - 'resources': (_envoy_api_v2_Resource__Output)[]; - /** - * Type URL for resources. Identifies the xDS API when muxing over ADS. - * Must be consistent with the type_url in the Any within 'resources' if 'resources' is non-empty. - */ - 'type_url': (string); - /** - * The nonce provides a way for DeltaDiscoveryRequests to uniquely - * reference a DeltaDiscoveryResponse when (N)ACKing. The nonce is required. - */ - 'nonce': (string); - /** - * Resources names of resources that have be deleted and to be removed from the xDS Client. - * Removed resources for missing resources can be ignored. - */ - 'removed_resources': (string)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts deleted file mode 100644 index 2386e71c4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryRequest.ts +++ /dev/null @@ -1,110 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/discovery.proto - -import type { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../envoy/api/v2/core/Node'; -import type { Status as _google_rpc_Status, Status__Output as _google_rpc_Status__Output } from '../../../google/rpc/Status'; - -/** - * A DiscoveryRequest requests a set of versioned resources of the same type for - * a given Envoy node on some API. - * [#next-free-field: 7] - */ -export interface DiscoveryRequest { - /** - * The version_info provided in the request messages will be the version_info - * received with the most recent successfully processed response or empty on - * the first request. It is expected that no new request is sent after a - * response is received until the Envoy instance is ready to ACK/NACK the new - * configuration. ACK/NACK takes place by returning the new API config version - * as applied or the previous API config version respectively. Each type_url - * (see below) has an independent version associated with it. - */ - 'version_info'?: (string); - /** - * The node making the request. - */ - 'node'?: (_envoy_api_v2_core_Node | null); - /** - * List of resources to subscribe to, e.g. list of cluster names or a route - * configuration name. If this is empty, all resources for the API are - * returned. LDS/CDS may have empty resource_names, which will cause all - * resources for the Envoy instance to be returned. The LDS and CDS responses - * will then imply a number of resources that need to be fetched via EDS/RDS, - * which will be explicitly enumerated in resource_names. - */ - 'resource_names'?: (string)[]; - /** - * Type of the resource that is being requested, e.g. - * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit - * in requests made via singleton xDS APIs such as CDS, LDS, etc. but is - * required for ADS. - */ - 'type_url'?: (string); - /** - * nonce corresponding to DiscoveryResponse being ACK/NACKed. See above - * discussion on version_info and the DiscoveryResponse nonce comment. This - * may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, - * or 2) the client has not yet accepted an update in this xDS stream (unlike - * delta, where it is populated only for new explicit ACKs). - */ - 'response_nonce'?: (string); - /** - * This is populated when the previous :ref:`DiscoveryResponse ` - * failed to update configuration. The *message* field in *error_details* provides the Envoy - * internal exception related to the failure. It is only intended for consumption during manual - * debugging, the string provided is not guaranteed to be stable across Envoy versions. - */ - 'error_detail'?: (_google_rpc_Status | null); -} - -/** - * A DiscoveryRequest requests a set of versioned resources of the same type for - * a given Envoy node on some API. - * [#next-free-field: 7] - */ -export interface DiscoveryRequest__Output { - /** - * The version_info provided in the request messages will be the version_info - * received with the most recent successfully processed response or empty on - * the first request. It is expected that no new request is sent after a - * response is received until the Envoy instance is ready to ACK/NACK the new - * configuration. ACK/NACK takes place by returning the new API config version - * as applied or the previous API config version respectively. Each type_url - * (see below) has an independent version associated with it. - */ - 'version_info': (string); - /** - * The node making the request. - */ - 'node': (_envoy_api_v2_core_Node__Output | null); - /** - * List of resources to subscribe to, e.g. list of cluster names or a route - * configuration name. If this is empty, all resources for the API are - * returned. LDS/CDS may have empty resource_names, which will cause all - * resources for the Envoy instance to be returned. The LDS and CDS responses - * will then imply a number of resources that need to be fetched via EDS/RDS, - * which will be explicitly enumerated in resource_names. - */ - 'resource_names': (string)[]; - /** - * Type of the resource that is being requested, e.g. - * "type.googleapis.com/envoy.api.v2.ClusterLoadAssignment". This is implicit - * in requests made via singleton xDS APIs such as CDS, LDS, etc. but is - * required for ADS. - */ - 'type_url': (string); - /** - * nonce corresponding to DiscoveryResponse being ACK/NACKed. See above - * discussion on version_info and the DiscoveryResponse nonce comment. This - * may be empty only if 1) this is a non-persistent-stream xDS such as HTTP, - * or 2) the client has not yet accepted an update in this xDS stream (unlike - * delta, where it is populated only for new explicit ACKs). - */ - 'response_nonce': (string); - /** - * This is populated when the previous :ref:`DiscoveryResponse ` - * failed to update configuration. The *message* field in *error_details* provides the Envoy - * internal exception related to the failure. It is only intended for consumption during manual - * debugging, the string provided is not guaranteed to be stable across Envoy versions. - */ - 'error_detail': (_google_rpc_Status__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts deleted file mode 100644 index 179143c67..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/DiscoveryResponse.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/discovery.proto - -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; -import type { ControlPlane as _envoy_api_v2_core_ControlPlane, ControlPlane__Output as _envoy_api_v2_core_ControlPlane__Output } from '../../../envoy/api/v2/core/ControlPlane'; - -/** - * [#next-free-field: 7] - */ -export interface DiscoveryResponse { - /** - * The version of the response data. - */ - 'version_info'?: (string); - /** - * The response resources. These resources are typed and depend on the API being called. - */ - 'resources'?: (_google_protobuf_Any)[]; - /** - * [#not-implemented-hide:] - * Canary is used to support two Envoy command line flags: - * - * * --terminate-on-canary-transition-failure. When set, Envoy is able to - * terminate if it detects that configuration is stuck at canary. Consider - * this example sequence of updates: - * - Management server applies a canary config successfully. - * - Management server rolls back to a production config. - * - Envoy rejects the new production config. - * Since there is no sensible way to continue receiving configuration - * updates, Envoy will then terminate and apply production config from a - * clean slate. - * * --dry-run-canary. When set, a canary response will never be applied, only - * validated via a dry run. - */ - 'canary'?: (boolean); - /** - * Type URL for resources. Identifies the xDS API when muxing over ADS. - * Must be consistent with the type_url in the 'resources' repeated Any (if non-empty). - */ - 'type_url'?: (string); - /** - * For gRPC based subscriptions, the nonce provides a way to explicitly ack a - * specific DiscoveryResponse in a following DiscoveryRequest. Additional - * messages may have been sent by Envoy to the management server for the - * previous version on the stream prior to this DiscoveryResponse, that were - * unprocessed at response send time. The nonce allows the management server - * to ignore any further DiscoveryRequests for the previous version until a - * DiscoveryRequest bearing the nonce. The nonce is optional and is not - * required for non-stream based xDS implementations. - */ - 'nonce'?: (string); - /** - * [#not-implemented-hide:] - * The control plane instance that sent the response. - */ - 'control_plane'?: (_envoy_api_v2_core_ControlPlane | null); -} - -/** - * [#next-free-field: 7] - */ -export interface DiscoveryResponse__Output { - /** - * The version of the response data. - */ - 'version_info': (string); - /** - * The response resources. These resources are typed and depend on the API being called. - */ - 'resources': (_google_protobuf_Any__Output)[]; - /** - * [#not-implemented-hide:] - * Canary is used to support two Envoy command line flags: - * - * * --terminate-on-canary-transition-failure. When set, Envoy is able to - * terminate if it detects that configuration is stuck at canary. Consider - * this example sequence of updates: - * - Management server applies a canary config successfully. - * - Management server rolls back to a production config. - * - Envoy rejects the new production config. - * Since there is no sensible way to continue receiving configuration - * updates, Envoy will then terminate and apply production config from a - * clean slate. - * * --dry-run-canary. When set, a canary response will never be applied, only - * validated via a dry run. - */ - 'canary': (boolean); - /** - * Type URL for resources. Identifies the xDS API when muxing over ADS. - * Must be consistent with the type_url in the 'resources' repeated Any (if non-empty). - */ - 'type_url': (string); - /** - * For gRPC based subscriptions, the nonce provides a way to explicitly ack a - * specific DiscoveryResponse in a following DiscoveryRequest. Additional - * messages may have been sent by Envoy to the management server for the - * previous version on the stream prior to this DiscoveryResponse, that were - * unprocessed at response send time. The nonce allows the management server - * to ignore any further DiscoveryRequests for the previous version until a - * DiscoveryRequest bearing the nonce. The nonce is optional and is not - * required for non-stream based xDS implementations. - */ - 'nonce': (string); - /** - * [#not-implemented-hide:] - * The control plane instance that sent the response. - */ - 'control_plane': (_envoy_api_v2_core_ControlPlane__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts deleted file mode 100644 index 6ce856ee7..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/Resource.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/discovery.proto - -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../google/protobuf/Any'; - -export interface Resource { - /** - * The resource level version. It allows xDS to track the state of individual - * resources. - */ - 'version'?: (string); - /** - * The resource being tracked. - */ - 'resource'?: (_google_protobuf_Any | null); - /** - * The resource's name, to distinguish it from others of the same type of resource. - */ - 'name'?: (string); - /** - * The aliases are a list of other names that this resource can go by. - */ - 'aliases'?: (string)[]; -} - -export interface Resource__Output { - /** - * The resource level version. It allows xDS to track the state of individual - * resources. - */ - 'version': (string); - /** - * The resource being tracked. - */ - 'resource': (_google_protobuf_Any__Output | null); - /** - * The resource's name, to distinguish it from others of the same type of resource. - */ - 'name': (string); - /** - * The aliases are a list of other names that this resource can go by. - */ - 'aliases': (string)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts deleted file mode 100644 index 65044b74a..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Address.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - -import type { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; -import type { Pipe as _envoy_api_v2_core_Pipe, Pipe__Output as _envoy_api_v2_core_Pipe__Output } from '../../../../envoy/api/v2/core/Pipe'; - -/** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ -export interface Address { - 'socket_address'?: (_envoy_api_v2_core_SocketAddress | null); - 'pipe'?: (_envoy_api_v2_core_Pipe | null); - 'address'?: "socket_address"|"pipe"; -} - -/** - * Addresses specify either a logical or physical address and port, which are - * used to tell Envoy where to bind/listen, connect to upstream and find - * management servers. - */ -export interface Address__Output { - 'socket_address'?: (_envoy_api_v2_core_SocketAddress__Output | null); - 'pipe'?: (_envoy_api_v2_core_Pipe__Output | null); - 'address': "socket_address"|"pipe"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts deleted file mode 100644 index 139f82689..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/AsyncDataSource.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { DataSource as _envoy_api_v2_core_DataSource, DataSource__Output as _envoy_api_v2_core_DataSource__Output } from '../../../../envoy/api/v2/core/DataSource'; -import type { RemoteDataSource as _envoy_api_v2_core_RemoteDataSource, RemoteDataSource__Output as _envoy_api_v2_core_RemoteDataSource__Output } from '../../../../envoy/api/v2/core/RemoteDataSource'; - -/** - * Async data source which support async data fetch. - */ -export interface AsyncDataSource { - /** - * Local async data source. - */ - 'local'?: (_envoy_api_v2_core_DataSource | null); - /** - * Remote async data source. - */ - 'remote'?: (_envoy_api_v2_core_RemoteDataSource | null); - 'specifier'?: "local"|"remote"; -} - -/** - * Async data source which support async data fetch. - */ -export interface AsyncDataSource__Output { - /** - * Local async data source. - */ - 'local'?: (_envoy_api_v2_core_DataSource__Output | null); - /** - * Remote async data source. - */ - 'remote'?: (_envoy_api_v2_core_RemoteDataSource__Output | null); - 'specifier': "local"|"remote"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts deleted file mode 100644 index 173aff0e1..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BackoffStrategy.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/backoff.proto - -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; - -/** - * Configuration defining a jittered exponential back off strategy. - */ -export interface BackoffStrategy { - /** - * The base interval to be used for the next back off computation. It should - * be greater than zero and less than or equal to :ref:`max_interval - * `. - */ - 'base_interval'?: (_google_protobuf_Duration | null); - /** - * Specifies the maximum interval between retries. This parameter is optional, - * but must be greater than or equal to the :ref:`base_interval - * ` if set. The default - * is 10 times the :ref:`base_interval - * `. - */ - 'max_interval'?: (_google_protobuf_Duration | null); -} - -/** - * Configuration defining a jittered exponential back off strategy. - */ -export interface BackoffStrategy__Output { - /** - * The base interval to be used for the next back off computation. It should - * be greater than zero and less than or equal to :ref:`max_interval - * `. - */ - 'base_interval': (_google_protobuf_Duration__Output | null); - /** - * Specifies the maximum interval between retries. This parameter is optional, - * but must be greater than or equal to the :ref:`base_interval - * ` if set. The default - * is 10 times the :ref:`base_interval - * `. - */ - 'max_interval': (_google_protobuf_Duration__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts deleted file mode 100644 index d4765c1ba..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BindConfig.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - -import type { SocketAddress as _envoy_api_v2_core_SocketAddress, SocketAddress__Output as _envoy_api_v2_core_SocketAddress__Output } from '../../../../envoy/api/v2/core/SocketAddress'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; -import type { SocketOption as _envoy_api_v2_core_SocketOption, SocketOption__Output as _envoy_api_v2_core_SocketOption__Output } from '../../../../envoy/api/v2/core/SocketOption'; - -export interface BindConfig { - /** - * The address to bind to when creating a socket. - */ - 'source_address'?: (_envoy_api_v2_core_SocketAddress | null); - /** - * Whether to set the *IP_FREEBIND* option when creating the socket. When this - * flag is set to true, allows the :ref:`source_address - * ` to be an IP address - * that is not configured on the system running Envoy. When this flag is set - * to false, the option *IP_FREEBIND* is disabled on the socket. When this - * flag is not set (default), the socket is not modified, i.e. the option is - * neither enabled nor disabled. - */ - 'freebind'?: (_google_protobuf_BoolValue | null); - /** - * Additional socket options that may not be present in Envoy source code or - * precompiled binaries. - */ - 'socket_options'?: (_envoy_api_v2_core_SocketOption)[]; -} - -export interface BindConfig__Output { - /** - * The address to bind to when creating a socket. - */ - 'source_address': (_envoy_api_v2_core_SocketAddress__Output | null); - /** - * Whether to set the *IP_FREEBIND* option when creating the socket. When this - * flag is set to true, allows the :ref:`source_address - * ` to be an IP address - * that is not configured on the system running Envoy. When this flag is set - * to false, the option *IP_FREEBIND* is disabled on the socket. When this - * flag is not set (default), the socket is not modified, i.e. the option is - * neither enabled nor disabled. - */ - 'freebind': (_google_protobuf_BoolValue__Output | null); - /** - * Additional socket options that may not be present in Envoy source code or - * precompiled binaries. - */ - 'socket_options': (_envoy_api_v2_core_SocketOption__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts deleted file mode 100644 index a33015d89..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/BuildVersion.ts +++ /dev/null @@ -1,36 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { SemanticVersion as _envoy_type_SemanticVersion, SemanticVersion__Output as _envoy_type_SemanticVersion__Output } from '../../../../envoy/type/SemanticVersion'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; - -/** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ -export interface BuildVersion { - /** - * SemVer version of extension. - */ - 'version'?: (_envoy_type_SemanticVersion | null); - /** - * Free-form build information. - * Envoy defines several well known keys in the source/common/version/version.h file - */ - 'metadata'?: (_google_protobuf_Struct | null); -} - -/** - * BuildVersion combines SemVer version of extension with free-form build information - * (i.e. 'alpha', 'private-build') as a set of strings. - */ -export interface BuildVersion__Output { - /** - * SemVer version of extension. - */ - 'version': (_envoy_type_SemanticVersion__Output | null); - /** - * Free-form build information. - * Envoy defines several well known keys in the source/common/version/version.h file - */ - 'metadata': (_google_protobuf_Struct__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts deleted file mode 100644 index 5e1df8a13..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/CidrRange.ts +++ /dev/null @@ -1,33 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; - -/** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ -export interface CidrRange { - /** - * IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. - */ - 'address_prefix'?: (string); - /** - * Length of prefix, e.g. 0, 32. Defaults to 0 when unset. - */ - 'prefix_len'?: (_google_protobuf_UInt32Value | null); -} - -/** - * CidrRange specifies an IP Address and a prefix length to construct - * the subnet mask for a `CIDR `_ range. - */ -export interface CidrRange__Output { - /** - * IPv4 or IPv6 address, e.g. ``192.0.0.0`` or ``2001:db8::``. - */ - 'address_prefix': (string); - /** - * Length of prefix, e.g. 0, 32. Defaults to 0 when unset. - */ - 'prefix_len': (_google_protobuf_UInt32Value__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts deleted file mode 100644 index 551f693a2..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/ControlPlane.ts +++ /dev/null @@ -1,26 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - - -/** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ -export interface ControlPlane { - /** - * An opaque control plane identifier that uniquely identifies an instance - * of control plane. This can be used to identify which control plane instance, - * the Envoy is connected to. - */ - 'identifier'?: (string); -} - -/** - * Identifies a specific ControlPlane instance that Envoy is connected to. - */ -export interface ControlPlane__Output { - /** - * An opaque control plane identifier that uniquely identifies an instance - * of control plane. This can be used to identify which control plane instance, - * the Envoy is connected to. - */ - 'identifier': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts deleted file mode 100644 index a04100054..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/DataSource.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - - -/** - * Data source consisting of either a file or an inline value. - */ -export interface DataSource { - /** - * Local filesystem data source. - */ - 'filename'?: (string); - /** - * Bytes inlined in the configuration. - */ - 'inline_bytes'?: (Buffer | Uint8Array | string); - /** - * String inlined in the configuration. - */ - 'inline_string'?: (string); - 'specifier'?: "filename"|"inline_bytes"|"inline_string"; -} - -/** - * Data source consisting of either a file or an inline value. - */ -export interface DataSource__Output { - /** - * Local filesystem data source. - */ - 'filename'?: (string); - /** - * Bytes inlined in the configuration. - */ - 'inline_bytes'?: (Buffer); - /** - * String inlined in the configuration. - */ - 'inline_string'?: (string); - 'specifier': "filename"|"inline_bytes"|"inline_string"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts deleted file mode 100644 index 67c5e1736..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Extension.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; - -/** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ -export interface Extension { - /** - * This is the name of the Envoy filter as specified in the Envoy - * configuration, e.g. envoy.filters.http.router, com.acme.widget. - */ - 'name'?: (string); - /** - * Category of the extension. - * Extension category names use reverse DNS notation. For instance "envoy.filters.listener" - * for Envoy's built-in listener filters or "com.acme.filters.http" for HTTP filters from - * acme.com vendor. - * [#comment:TODO(yanavlasov): Link to the doc with existing envoy category names.] - */ - 'category'?: (string); - /** - * [#not-implemented-hide:] Type descriptor of extension configuration proto. - * [#comment:TODO(yanavlasov): Link to the doc with existing configuration protos.] - * [#comment:TODO(yanavlasov): Add tests when PR #9391 lands.] - */ - 'type_descriptor'?: (string); - /** - * The version is a property of the extension and maintained independently - * of other extensions and the Envoy API. - * This field is not set when extension did not provide version information. - */ - 'version'?: (_envoy_api_v2_core_BuildVersion | null); - /** - * Indicates that the extension is present but was disabled via dynamic configuration. - */ - 'disabled'?: (boolean); -} - -/** - * Version and identification for an Envoy extension. - * [#next-free-field: 6] - */ -export interface Extension__Output { - /** - * This is the name of the Envoy filter as specified in the Envoy - * configuration, e.g. envoy.filters.http.router, com.acme.widget. - */ - 'name': (string); - /** - * Category of the extension. - * Extension category names use reverse DNS notation. For instance "envoy.filters.listener" - * for Envoy's built-in listener filters or "com.acme.filters.http" for HTTP filters from - * acme.com vendor. - * [#comment:TODO(yanavlasov): Link to the doc with existing envoy category names.] - */ - 'category': (string); - /** - * [#not-implemented-hide:] Type descriptor of extension configuration proto. - * [#comment:TODO(yanavlasov): Link to the doc with existing configuration protos.] - * [#comment:TODO(yanavlasov): Add tests when PR #9391 lands.] - */ - 'type_descriptor': (string); - /** - * The version is a property of the extension and maintained independently - * of other extensions and the Envoy API. - * This field is not set when extension did not provide version information. - */ - 'version': (_envoy_api_v2_core_BuildVersion__Output | null); - /** - * Indicates that the extension is present but was disabled via dynamic configuration. - */ - 'disabled': (boolean); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts deleted file mode 100644 index e093d4761..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderMap.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; - -/** - * Wrapper for a set of headers. - */ -export interface HeaderMap { - 'headers'?: (_envoy_api_v2_core_HeaderValue)[]; -} - -/** - * Wrapper for a set of headers. - */ -export interface HeaderMap__Output { - 'headers': (_envoy_api_v2_core_HeaderValue__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts deleted file mode 100644 index b36605324..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValue.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - - -/** - * Header name/value pair. - */ -export interface HeaderValue { - /** - * Header name. - */ - 'key'?: (string); - /** - * Header value. - * - * The same :ref:`format specifier ` as used for - * :ref:`HTTP access logging ` applies here, however - * unknown header values are replaced with the empty string instead of `-`. - */ - 'value'?: (string); -} - -/** - * Header name/value pair. - */ -export interface HeaderValue__Output { - /** - * Header name. - */ - 'key': (string); - /** - * Header value. - * - * The same :ref:`format specifier ` as used for - * :ref:`HTTP access logging ` applies here, however - * unknown header values are replaced with the empty string instead of `-`. - */ - 'value': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts deleted file mode 100644 index 12421d8f4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HeaderValueOption.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { HeaderValue as _envoy_api_v2_core_HeaderValue, HeaderValue__Output as _envoy_api_v2_core_HeaderValue__Output } from '../../../../envoy/api/v2/core/HeaderValue'; -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; - -/** - * Header name/value pair plus option to control append behavior. - */ -export interface HeaderValueOption { - /** - * Header name/value pair that this option applies to. - */ - 'header'?: (_envoy_api_v2_core_HeaderValue | null); - /** - * Should the value be appended? If true (default), the value is appended to - * existing values. - */ - 'append'?: (_google_protobuf_BoolValue | null); -} - -/** - * Header name/value pair plus option to control append behavior. - */ -export interface HeaderValueOption__Output { - /** - * Header name/value pair that this option applies to. - */ - 'header': (_envoy_api_v2_core_HeaderValue__Output | null); - /** - * Should the value be appended? If true (default), the value is appended to - * existing values. - */ - 'append': (_google_protobuf_BoolValue__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts deleted file mode 100644 index c206a2454..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/HttpUri.ts +++ /dev/null @@ -1,79 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/http_uri.proto - -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; - -/** - * Envoy external URI descriptor - */ -export interface HttpUri { - /** - * The HTTP server URI. It should be a full FQDN with protocol, host and path. - * - * Example: - * - * .. code-block:: yaml - * - * uri: https://www.googleapis.com/oauth2/v1/certs - */ - 'uri'?: (string); - /** - * A cluster is created in the Envoy "cluster_manager" config - * section. This field specifies the cluster name. - * - * Example: - * - * .. code-block:: yaml - * - * cluster: jwks_cluster - */ - 'cluster'?: (string); - /** - * Sets the maximum duration in milliseconds that a response can take to arrive upon request. - */ - 'timeout'?: (_google_protobuf_Duration | null); - /** - * Specify how `uri` is to be fetched. Today, this requires an explicit - * cluster, but in the future we may support dynamic cluster creation or - * inline DNS resolution. See `issue - * `_. - */ - 'http_upstream_type'?: "cluster"; -} - -/** - * Envoy external URI descriptor - */ -export interface HttpUri__Output { - /** - * The HTTP server URI. It should be a full FQDN with protocol, host and path. - * - * Example: - * - * .. code-block:: yaml - * - * uri: https://www.googleapis.com/oauth2/v1/certs - */ - 'uri': (string); - /** - * A cluster is created in the Envoy "cluster_manager" config - * section. This field specifies the cluster name. - * - * Example: - * - * .. code-block:: yaml - * - * cluster: jwks_cluster - */ - 'cluster'?: (string); - /** - * Sets the maximum duration in milliseconds that a response can take to arrive upon request. - */ - 'timeout': (_google_protobuf_Duration__Output | null); - /** - * Specify how `uri` is to be fetched. Today, this requires an explicit - * cluster, but in the future we may support dynamic cluster creation or - * inline DNS resolution. See `issue - * `_. - */ - 'http_upstream_type': "cluster"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts deleted file mode 100644 index 49fb232a4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Locality.ts +++ /dev/null @@ -1,56 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - - -/** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ -export interface Locality { - /** - * Region this :ref:`zone ` belongs to. - */ - 'region'?: (string); - /** - * Defines the local service zone where Envoy is running. Though optional, it - * should be set if discovery service routing is used and the discovery - * service exposes :ref:`zone data `, - * either in this message or via :option:`--service-zone`. The meaning of zone - * is context dependent, e.g. `Availability Zone (AZ) - * `_ - * on AWS, `Zone `_ on - * GCP, etc. - */ - 'zone'?: (string); - /** - * When used for locality of upstream hosts, this field further splits zone - * into smaller chunks of sub-zones so they can be load balanced - * independently. - */ - 'sub_zone'?: (string); -} - -/** - * Identifies location of where either Envoy runs or where upstream hosts run. - */ -export interface Locality__Output { - /** - * Region this :ref:`zone ` belongs to. - */ - 'region': (string); - /** - * Defines the local service zone where Envoy is running. Though optional, it - * should be set if discovery service routing is used and the discovery - * service exposes :ref:`zone data `, - * either in this message or via :option:`--service-zone`. The meaning of zone - * is context dependent, e.g. `Availability Zone (AZ) - * `_ - * on AWS, `Zone `_ on - * GCP, etc. - */ - 'zone': (string); - /** - * When used for locality of upstream hosts, this field further splits zone - * into smaller chunks of sub-zones so they can be load balanced - * independently. - */ - 'sub_zone': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts deleted file mode 100644 index 7a6871eeb..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Metadata.ts +++ /dev/null @@ -1,67 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; - -/** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ -export interface Metadata { - /** - * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* - * namespace is reserved for Envoy's built-in filters. - */ - 'filter_metadata'?: ({[key: string]: _google_protobuf_Struct}); -} - -/** - * Metadata provides additional inputs to filters based on matched listeners, - * filter chains, routes and endpoints. It is structured as a map, usually from - * filter name (in reverse DNS format) to metadata specific to the filter. Metadata - * key-values for a filter are merged as connection and request handling occurs, - * with later values for the same key overriding earlier values. - * - * An example use of metadata is providing additional values to - * http_connection_manager in the envoy.http_connection_manager.access_log - * namespace. - * - * Another example use of metadata is to per service config info in cluster metadata, which may get - * consumed by multiple filters. - * - * For load balancing, Metadata provides a means to subset cluster endpoints. - * Endpoints have a Metadata object associated and routes contain a Metadata - * object to match against. There are some well defined metadata used today for - * this purpose: - * - * * ``{"envoy.lb": {"canary": }}`` This indicates the canary status of an - * endpoint and is also used during header processing - * (x-envoy-upstream-canary) and for stats purposes. - * [#next-major-version: move to type/metadata/v2] - */ -export interface Metadata__Output { - /** - * Key is the reverse DNS filter name, e.g. com.acme.widget. The envoy.* - * namespace is reserved for Envoy's built-in filters. - */ - 'filter_metadata': ({[key: string]: _google_protobuf_Struct__Output}); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts deleted file mode 100644 index ddf10f08b..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Node.ts +++ /dev/null @@ -1,173 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; -import type { BuildVersion as _envoy_api_v2_core_BuildVersion, BuildVersion__Output as _envoy_api_v2_core_BuildVersion__Output } from '../../../../envoy/api/v2/core/BuildVersion'; -import type { Extension as _envoy_api_v2_core_Extension, Extension__Output as _envoy_api_v2_core_Extension__Output } from '../../../../envoy/api/v2/core/Extension'; -import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; - -/** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ -export interface Node { - /** - * An opaque node identifier for the Envoy node. This also provides the local - * service node name. It should be set if any of the following features are - * used: :ref:`statsd `, :ref:`CDS - * `, and :ref:`HTTP tracing - * `, either in this message or via - * :option:`--service-node`. - */ - 'id'?: (string); - /** - * Defines the local service cluster name where Envoy is running. Though - * optional, it should be set if any of the following features are used: - * :ref:`statsd `, :ref:`health check cluster - * verification - * `, - * :ref:`runtime override directory `, - * :ref:`user agent addition - * `, - * :ref:`HTTP global rate limiting `, - * :ref:`CDS `, and :ref:`HTTP tracing - * `, either in this message or via - * :option:`--service-cluster`. - */ - 'cluster'?: (string); - /** - * Opaque metadata extending the node identifier. Envoy will pass this - * directly to the management server. - */ - 'metadata'?: (_google_protobuf_Struct | null); - /** - * Locality specifying where the Envoy instance is running. - */ - 'locality'?: (_envoy_api_v2_core_Locality | null); - /** - * This is motivated by informing a management server during canary which - * version of Envoy is being tested in a heterogeneous fleet. This will be set - * by Envoy in management server RPCs. - * This field is deprecated in favor of the user_agent_name and user_agent_version values. - */ - 'build_version'?: (string); - /** - * Free-form string that identifies the entity requesting config. - * E.g. "envoy" or "grpc" - */ - 'user_agent_name'?: (string); - /** - * Free-form string that identifies the version of the entity requesting config. - * E.g. "1.12.2" or "abcd1234", or "SpecialEnvoyBuild" - */ - 'user_agent_version'?: (string); - /** - * Structured version of the entity requesting config. - */ - 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion | null); - /** - * List of extensions and their versions supported by the node. - */ - 'extensions'?: (_envoy_api_v2_core_Extension)[]; - /** - * Client feature support list. These are well known features described - * in the Envoy API repository for a given major version of an API. Client features - * use reverse DNS naming scheme, for example `com.acme.feature`. - * See :ref:`the list of features ` that xDS client may - * support. - */ - 'client_features'?: (string)[]; - /** - * Known listening ports on the node as a generic hint to the management server - * for filtering :ref:`listeners ` to be returned. For example, - * if there is a listener bound to port 80, the list can optionally contain the - * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. - */ - 'listening_addresses'?: (_envoy_api_v2_core_Address)[]; - 'user_agent_version_type'?: "user_agent_version"|"user_agent_build_version"; -} - -/** - * Identifies a specific Envoy instance. The node identifier is presented to the - * management server, which may use this identifier to distinguish per Envoy - * configuration for serving. - * [#next-free-field: 12] - */ -export interface Node__Output { - /** - * An opaque node identifier for the Envoy node. This also provides the local - * service node name. It should be set if any of the following features are - * used: :ref:`statsd `, :ref:`CDS - * `, and :ref:`HTTP tracing - * `, either in this message or via - * :option:`--service-node`. - */ - 'id': (string); - /** - * Defines the local service cluster name where Envoy is running. Though - * optional, it should be set if any of the following features are used: - * :ref:`statsd `, :ref:`health check cluster - * verification - * `, - * :ref:`runtime override directory `, - * :ref:`user agent addition - * `, - * :ref:`HTTP global rate limiting `, - * :ref:`CDS `, and :ref:`HTTP tracing - * `, either in this message or via - * :option:`--service-cluster`. - */ - 'cluster': (string); - /** - * Opaque metadata extending the node identifier. Envoy will pass this - * directly to the management server. - */ - 'metadata': (_google_protobuf_Struct__Output | null); - /** - * Locality specifying where the Envoy instance is running. - */ - 'locality': (_envoy_api_v2_core_Locality__Output | null); - /** - * This is motivated by informing a management server during canary which - * version of Envoy is being tested in a heterogeneous fleet. This will be set - * by Envoy in management server RPCs. - * This field is deprecated in favor of the user_agent_name and user_agent_version values. - */ - 'build_version': (string); - /** - * Free-form string that identifies the entity requesting config. - * E.g. "envoy" or "grpc" - */ - 'user_agent_name': (string); - /** - * Free-form string that identifies the version of the entity requesting config. - * E.g. "1.12.2" or "abcd1234", or "SpecialEnvoyBuild" - */ - 'user_agent_version'?: (string); - /** - * Structured version of the entity requesting config. - */ - 'user_agent_build_version'?: (_envoy_api_v2_core_BuildVersion__Output | null); - /** - * List of extensions and their versions supported by the node. - */ - 'extensions': (_envoy_api_v2_core_Extension__Output)[]; - /** - * Client feature support list. These are well known features described - * in the Envoy API repository for a given major version of an API. Client features - * use reverse DNS naming scheme, for example `com.acme.feature`. - * See :ref:`the list of features ` that xDS client may - * support. - */ - 'client_features': (string)[]; - /** - * Known listening ports on the node as a generic hint to the management server - * for filtering :ref:`listeners ` to be returned. For example, - * if there is a listener bound to port 80, the list can optionally contain the - * SocketAddress `(0.0.0.0,80)`. The field is optional and just a hint. - */ - 'listening_addresses': (_envoy_api_v2_core_Address__Output)[]; - 'user_agent_version_type': "user_agent_version"|"user_agent_build_version"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts deleted file mode 100644 index 9e6cbb82d..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/Pipe.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - - -export interface Pipe { - /** - * Unix Domain Socket path. On Linux, paths starting with '@' will use the - * abstract namespace. The starting '@' is replaced by a null byte by Envoy. - * Paths starting with '@' will result in an error in environments other than - * Linux. - */ - 'path'?: (string); - /** - * The mode for the Pipe. Not applicable for abstract sockets. - */ - 'mode'?: (number); -} - -export interface Pipe__Output { - /** - * Unix Domain Socket path. On Linux, paths starting with '@' will use the - * abstract namespace. The starting '@' is replaced by a null byte by Envoy. - * Paths starting with '@' will result in an error in environments other than - * Linux. - */ - 'path': (string); - /** - * The mode for the Pipe. Not applicable for abstract sockets. - */ - 'mode': (number); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts deleted file mode 100644 index 516dbf864..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RemoteDataSource.ts +++ /dev/null @@ -1,40 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { HttpUri as _envoy_api_v2_core_HttpUri, HttpUri__Output as _envoy_api_v2_core_HttpUri__Output } from '../../../../envoy/api/v2/core/HttpUri'; -import type { RetryPolicy as _envoy_api_v2_core_RetryPolicy, RetryPolicy__Output as _envoy_api_v2_core_RetryPolicy__Output } from '../../../../envoy/api/v2/core/RetryPolicy'; - -/** - * The message specifies how to fetch data from remote and how to verify it. - */ -export interface RemoteDataSource { - /** - * The HTTP URI to fetch the remote data. - */ - 'http_uri'?: (_envoy_api_v2_core_HttpUri | null); - /** - * SHA256 string for verifying data. - */ - 'sha256'?: (string); - /** - * Retry policy for fetching remote data. - */ - 'retry_policy'?: (_envoy_api_v2_core_RetryPolicy | null); -} - -/** - * The message specifies how to fetch data from remote and how to verify it. - */ -export interface RemoteDataSource__Output { - /** - * The HTTP URI to fetch the remote data. - */ - 'http_uri': (_envoy_api_v2_core_HttpUri__Output | null); - /** - * SHA256 string for verifying data. - */ - 'sha256': (string); - /** - * Retry policy for fetching remote data. - */ - 'retry_policy': (_envoy_api_v2_core_RetryPolicy__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts deleted file mode 100644 index 029e9882d..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RequestMethod.ts +++ /dev/null @@ -1,17 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -/** - * HTTP request method. - */ -export enum RequestMethod { - METHOD_UNSPECIFIED = 0, - GET = 1, - HEAD = 2, - POST = 3, - PUT = 4, - DELETE = 5, - CONNECT = 6, - OPTIONS = 7, - TRACE = 8, - PATCH = 9, -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts deleted file mode 100644 index 7ff35e375..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RetryPolicy.ts +++ /dev/null @@ -1,38 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { BackoffStrategy as _envoy_api_v2_core_BackoffStrategy, BackoffStrategy__Output as _envoy_api_v2_core_BackoffStrategy__Output } from '../../../../envoy/api/v2/core/BackoffStrategy'; -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; - -/** - * The message specifies the retry policy of remote data source when fetching fails. - */ -export interface RetryPolicy { - /** - * Specifies parameters that control :ref:`retry backoff strategy `. - * This parameter is optional, in which case the default base interval is 1000 milliseconds. The - * default maximum interval is 10 times the base interval. - */ - 'retry_back_off'?: (_envoy_api_v2_core_BackoffStrategy | null); - /** - * Specifies the allowed number of retries. This parameter is optional and - * defaults to 1. - */ - 'num_retries'?: (_google_protobuf_UInt32Value | null); -} - -/** - * The message specifies the retry policy of remote data source when fetching fails. - */ -export interface RetryPolicy__Output { - /** - * Specifies parameters that control :ref:`retry backoff strategy `. - * This parameter is optional, in which case the default base interval is 1000 milliseconds. The - * default maximum interval is 10 times the base interval. - */ - 'retry_back_off': (_envoy_api_v2_core_BackoffStrategy__Output | null); - /** - * Specifies the allowed number of retries. This parameter is optional and - * defaults to 1. - */ - 'num_retries': (_google_protobuf_UInt32Value__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts deleted file mode 100644 index 5937fceb2..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RoutingPriority.ts +++ /dev/null @@ -1,15 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -/** - * Envoy supports :ref:`upstream priority routing - * ` both at the route and the virtual - * cluster level. The current priority implementation uses different connection - * pool and circuit breaking settings for each priority level. This means that - * even for HTTP/2 requests, two physical connections will be used to an - * upstream host. In the future Envoy will likely support true HTTP/2 priority - * over a single upstream connection. - */ -export enum RoutingPriority { - DEFAULT = 0, - HIGH = 1, -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts deleted file mode 100644 index 1ea2b8146..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeDouble.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - - -/** - * Runtime derived double with a default when not specified. - */ -export interface RuntimeDouble { - /** - * Default value if runtime value is not available. - */ - 'default_value'?: (number | string); - /** - * Runtime key to get value for comparison. This value is used if defined. - */ - 'runtime_key'?: (string); -} - -/** - * Runtime derived double with a default when not specified. - */ -export interface RuntimeDouble__Output { - /** - * Default value if runtime value is not available. - */ - 'default_value': (number); - /** - * Runtime key to get value for comparison. This value is used if defined. - */ - 'runtime_key': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts deleted file mode 100644 index 4ad57de46..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFeatureFlag.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { BoolValue as _google_protobuf_BoolValue, BoolValue__Output as _google_protobuf_BoolValue__Output } from '../../../../google/protobuf/BoolValue'; - -/** - * Runtime derived bool with a default when not specified. - */ -export interface RuntimeFeatureFlag { - /** - * Default value if runtime value is not available. - */ - 'default_value'?: (_google_protobuf_BoolValue | null); - /** - * Runtime key to get value for comparison. This value is used if defined. The boolean value must - * be represented via its - * `canonical JSON encoding `_. - */ - 'runtime_key'?: (string); -} - -/** - * Runtime derived bool with a default when not specified. - */ -export interface RuntimeFeatureFlag__Output { - /** - * Default value if runtime value is not available. - */ - 'default_value': (_google_protobuf_BoolValue__Output | null); - /** - * Runtime key to get value for comparison. This value is used if defined. The boolean value must - * be represented via its - * `canonical JSON encoding `_. - */ - 'runtime_key': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts deleted file mode 100644 index a168af60c..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeFractionalPercent.ts +++ /dev/null @@ -1,49 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { FractionalPercent as _envoy_type_FractionalPercent, FractionalPercent__Output as _envoy_type_FractionalPercent__Output } from '../../../../envoy/type/FractionalPercent'; - -/** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ -export interface RuntimeFractionalPercent { - /** - * Default value if the runtime value's for the numerator/denominator keys are not available. - */ - 'default_value'?: (_envoy_type_FractionalPercent | null); - /** - * Runtime key for a YAML representation of a FractionalPercent. - */ - 'runtime_key'?: (string); -} - -/** - * Runtime derived FractionalPercent with defaults for when the numerator or denominator is not - * specified via a runtime key. - * - * .. note:: - * - * Parsing of the runtime key's data is implemented such that it may be represented as a - * :ref:`FractionalPercent ` proto represented as JSON/YAML - * and may also be represented as an integer with the assumption that the value is an integral - * percentage out of 100. For instance, a runtime key lookup returning the value "42" would parse - * as a `FractionalPercent` whose numerator is 42 and denominator is HUNDRED. - */ -export interface RuntimeFractionalPercent__Output { - /** - * Default value if the runtime value's for the numerator/denominator keys are not available. - */ - 'default_value': (_envoy_type_FractionalPercent__Output | null); - /** - * Runtime key for a YAML representation of a FractionalPercent. - */ - 'runtime_key': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts deleted file mode 100644 index 72e8972a4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/RuntimeUInt32.ts +++ /dev/null @@ -1,30 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - - -/** - * Runtime derived uint32 with a default when not specified. - */ -export interface RuntimeUInt32 { - /** - * Default value if runtime value is not available. - */ - 'default_value'?: (number); - /** - * Runtime key to get value for comparison. This value is used if defined. - */ - 'runtime_key'?: (string); -} - -/** - * Runtime derived uint32 with a default when not specified. - */ -export interface RuntimeUInt32__Output { - /** - * Default value if runtime value is not available. - */ - 'default_value': (number); - /** - * Runtime key to get value for comparison. This value is used if defined. - */ - 'runtime_key': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts deleted file mode 100644 index f81c981c1..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketAddress.ts +++ /dev/null @@ -1,97 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - - -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - -export enum _envoy_api_v2_core_SocketAddress_Protocol { - TCP = 0, - UDP = 1, -} - -/** - * [#next-free-field: 7] - */ -export interface SocketAddress { - 'protocol'?: (_envoy_api_v2_core_SocketAddress_Protocol | keyof typeof _envoy_api_v2_core_SocketAddress_Protocol); - /** - * The address for this socket. :ref:`Listeners ` will bind - * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` - * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: - * It is possible to distinguish a Listener address via the prefix/suffix matching - * in :ref:`FilterChainMatch `.] When used - * within an upstream :ref:`BindConfig `, the address - * controls the source address of outbound connections. For :ref:`clusters - * `, the cluster type determines whether the - * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS - * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized - * via :ref:`resolver_name `. - */ - 'address'?: (string); - 'port_value'?: (number); - /** - * This is only valid if :ref:`resolver_name - * ` is specified below and the - * named resolver is capable of named port resolution. - */ - 'named_port'?: (string); - /** - * The name of the custom resolver. This must have been registered with Envoy. If - * this is empty, a context dependent default applies. If the address is a concrete - * IP address, no resolution will occur. If address is a hostname this - * should be set for resolution other than DNS. Specifying a custom resolver with - * *STRICT_DNS* or *LOGICAL_DNS* will generate an error at runtime. - */ - 'resolver_name'?: (string); - /** - * When binding to an IPv6 address above, this enables `IPv4 compatibility - * `_. Binding to ``::`` will - * allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into - * IPv6 space as ``::FFFF:``. - */ - 'ipv4_compat'?: (boolean); - 'port_specifier'?: "port_value"|"named_port"; -} - -/** - * [#next-free-field: 7] - */ -export interface SocketAddress__Output { - 'protocol': (keyof typeof _envoy_api_v2_core_SocketAddress_Protocol); - /** - * The address for this socket. :ref:`Listeners ` will bind - * to the address. An empty address is not allowed. Specify ``0.0.0.0`` or ``::`` - * to bind to any address. [#comment:TODO(zuercher) reinstate when implemented: - * It is possible to distinguish a Listener address via the prefix/suffix matching - * in :ref:`FilterChainMatch `.] When used - * within an upstream :ref:`BindConfig `, the address - * controls the source address of outbound connections. For :ref:`clusters - * `, the cluster type determines whether the - * address must be an IP (*STATIC* or *EDS* clusters) or a hostname resolved by DNS - * (*STRICT_DNS* or *LOGICAL_DNS* clusters). Address resolution can be customized - * via :ref:`resolver_name `. - */ - 'address': (string); - 'port_value'?: (number); - /** - * This is only valid if :ref:`resolver_name - * ` is specified below and the - * named resolver is capable of named port resolution. - */ - 'named_port'?: (string); - /** - * The name of the custom resolver. This must have been registered with Envoy. If - * this is empty, a context dependent default applies. If the address is a concrete - * IP address, no resolution will occur. If address is a hostname this - * should be set for resolution other than DNS. Specifying a custom resolver with - * *STRICT_DNS* or *LOGICAL_DNS* will generate an error at runtime. - */ - 'resolver_name': (string); - /** - * When binding to an IPv6 address above, this enables `IPv4 compatibility - * `_. Binding to ``::`` will - * allow both IPv4 and IPv6 connections, with peer IPv4 addresses mapped into - * IPv6 space as ``::FFFF:``. - */ - 'ipv4_compat': (boolean); - 'port_specifier': "port_value"|"named_port"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts deleted file mode 100644 index 4a32e46b4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/SocketOption.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto - -import type { Long } from '@grpc/proto-loader'; - -// Original file: deps/envoy-api/envoy/api/v2/core/socket_option.proto - -export enum _envoy_api_v2_core_SocketOption_SocketState { - /** - * Socket options are applied after socket creation but before binding the socket to a port - */ - STATE_PREBIND = 0, - /** - * Socket options are applied after binding the socket to a port but before calling listen() - */ - STATE_BOUND = 1, - /** - * Socket options are applied after calling listen() - */ - STATE_LISTENING = 2, -} - -/** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ -export interface SocketOption { - /** - * An optional name to give this socket option for debugging, etc. - * Uniqueness is not required and no special meaning is assumed. - */ - 'description'?: (string); - /** - * Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP - */ - 'level'?: (number | string | Long); - /** - * The numeric name as passed to setsockopt - */ - 'name'?: (number | string | Long); - /** - * Because many sockopts take an int value. - */ - 'int_value'?: (number | string | Long); - /** - * Otherwise it's a byte buffer. - */ - 'buf_value'?: (Buffer | Uint8Array | string); - /** - * The state in which the option will be applied. When used in BindConfig - * STATE_PREBIND is currently the only valid value. - */ - 'state'?: (_envoy_api_v2_core_SocketOption_SocketState | keyof typeof _envoy_api_v2_core_SocketOption_SocketState); - 'value'?: "int_value"|"buf_value"; -} - -/** - * Generic socket option message. This would be used to set socket options that - * might not exist in upstream kernels or precompiled Envoy binaries. - * [#next-free-field: 7] - */ -export interface SocketOption__Output { - /** - * An optional name to give this socket option for debugging, etc. - * Uniqueness is not required and no special meaning is assumed. - */ - 'description': (string); - /** - * Corresponding to the level value passed to setsockopt, such as IPPROTO_TCP - */ - 'level': (string); - /** - * The numeric name as passed to setsockopt - */ - 'name': (string); - /** - * Because many sockopts take an int value. - */ - 'int_value'?: (string); - /** - * Otherwise it's a byte buffer. - */ - 'buf_value'?: (Buffer); - /** - * The state in which the option will be applied. When used in BindConfig - * STATE_PREBIND is currently the only valid value. - */ - 'state': (keyof typeof _envoy_api_v2_core_SocketOption_SocketState); - 'value': "int_value"|"buf_value"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts deleted file mode 100644 index e9d805c76..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TcpKeepalive.ts +++ /dev/null @@ -1,43 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/address.proto - -import type { UInt32Value as _google_protobuf_UInt32Value, UInt32Value__Output as _google_protobuf_UInt32Value__Output } from '../../../../google/protobuf/UInt32Value'; - -export interface TcpKeepalive { - /** - * Maximum number of keepalive probes to send without response before deciding - * the connection is dead. Default is to use the OS level configuration (unless - * overridden, Linux defaults to 9.) - */ - 'keepalive_probes'?: (_google_protobuf_UInt32Value | null); - /** - * The number of seconds a connection needs to be idle before keep-alive probes - * start being sent. Default is to use the OS level configuration (unless - * overridden, Linux defaults to 7200s (i.e., 2 hours.) - */ - 'keepalive_time'?: (_google_protobuf_UInt32Value | null); - /** - * The number of seconds between keep-alive probes. Default is to use the OS - * level configuration (unless overridden, Linux defaults to 75s.) - */ - 'keepalive_interval'?: (_google_protobuf_UInt32Value | null); -} - -export interface TcpKeepalive__Output { - /** - * Maximum number of keepalive probes to send without response before deciding - * the connection is dead. Default is to use the OS level configuration (unless - * overridden, Linux defaults to 9.) - */ - 'keepalive_probes': (_google_protobuf_UInt32Value__Output | null); - /** - * The number of seconds a connection needs to be idle before keep-alive probes - * start being sent. Default is to use the OS level configuration (unless - * overridden, Linux defaults to 7200s (i.e., 2 hours.) - */ - 'keepalive_time': (_google_protobuf_UInt32Value__Output | null); - /** - * The number of seconds between keep-alive probes. Default is to use the OS - * level configuration (unless overridden, Linux defaults to 75s.) - */ - 'keepalive_interval': (_google_protobuf_UInt32Value__Output | null); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts deleted file mode 100644 index 41cf36523..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TrafficDirection.ts +++ /dev/null @@ -1,19 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -/** - * Identifies the direction of the traffic relative to the local Envoy. - */ -export enum TrafficDirection { - /** - * Default option is unspecified. - */ - UNSPECIFIED = 0, - /** - * The transport is used for incoming traffic. - */ - INBOUND = 1, - /** - * The transport is used for outgoing traffic. - */ - OUTBOUND = 2, -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts deleted file mode 100644 index 87fbcaf38..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/core/TransportSocket.ts +++ /dev/null @@ -1,46 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/core/base.proto - -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { Any as _google_protobuf_Any, Any__Output as _google_protobuf_Any__Output } from '../../../../google/protobuf/Any'; - -/** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ -export interface TransportSocket { - /** - * The name of the transport socket to instantiate. The name must match a supported transport - * socket implementation. - */ - 'name'?: (string); - 'config'?: (_google_protobuf_Struct | null); - 'typed_config'?: (_google_protobuf_Any | null); - /** - * Implementation specific configuration which depends on the implementation being instantiated. - * See the supported transport socket implementations for further documentation. - */ - 'config_type'?: "config"|"typed_config"; -} - -/** - * Configuration for transport socket in :ref:`listeners ` and - * :ref:`clusters `. If the configuration is - * empty, a default transport socket implementation and configuration will be - * chosen based on the platform and existence of tls_context. - */ -export interface TransportSocket__Output { - /** - * The name of the transport socket to instantiate. The name must match a supported transport - * socket implementation. - */ - 'name': (string); - 'config'?: (_google_protobuf_Struct__Output | null); - 'typed_config'?: (_google_protobuf_Any__Output | null); - /** - * Implementation specific configuration which depends on the implementation being instantiated. - * See the supported transport socket implementations for further documentation. - */ - 'config_type': "config"|"typed_config"; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts deleted file mode 100644 index 3609ea1e4..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/ClusterStats.ts +++ /dev/null @@ -1,117 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto - -import type { UpstreamLocalityStats as _envoy_api_v2_endpoint_UpstreamLocalityStats, UpstreamLocalityStats__Output as _envoy_api_v2_endpoint_UpstreamLocalityStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamLocalityStats'; -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; -import type { Long } from '@grpc/proto-loader'; - -export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests { - /** - * Identifier for the policy specifying the drop. - */ - 'category'?: (string); - /** - * Total number of deliberately dropped requests for the category. - */ - 'dropped_count'?: (number | string | Long); -} - -export interface _envoy_api_v2_endpoint_ClusterStats_DroppedRequests__Output { - /** - * Identifier for the policy specifying the drop. - */ - 'category': (string); - /** - * Total number of deliberately dropped requests for the category. - */ - 'dropped_count': (string); -} - -/** - * Per cluster load stats. Envoy reports these stats a management server in a - * :ref:`LoadStatsRequest` - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - * Next ID: 7 - * [#next-free-field: 7] - */ -export interface ClusterStats { - /** - * The name of the cluster. - */ - 'cluster_name'?: (string); - /** - * Need at least one. - */ - 'upstream_locality_stats'?: (_envoy_api_v2_endpoint_UpstreamLocalityStats)[]; - /** - * Cluster-level stats such as total_successful_requests may be computed by - * summing upstream_locality_stats. In addition, below there are additional - * cluster-wide stats. - * - * The total number of dropped requests. This covers requests - * deliberately dropped by the drop_overload policy and circuit breaking. - */ - 'total_dropped_requests'?: (number | string | Long); - /** - * Period over which the actual load report occurred. This will be guaranteed to include every - * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy - * and the *LoadStatsResponse* message sent from the management server, this may be longer than - * the requested load reporting interval in the *LoadStatsResponse*. - */ - 'load_report_interval'?: (_google_protobuf_Duration | null); - /** - * Information about deliberately dropped requests for each category specified - * in the DropOverload policy. - */ - 'dropped_requests'?: (_envoy_api_v2_endpoint_ClusterStats_DroppedRequests)[]; - /** - * The eds_cluster_config service_name of the cluster. - * It's possible that two clusters send the same service_name to EDS, - * in that case, the management server is supposed to do aggregation on the load reports. - */ - 'cluster_service_name'?: (string); -} - -/** - * Per cluster load stats. Envoy reports these stats a management server in a - * :ref:`LoadStatsRequest` - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - * Next ID: 7 - * [#next-free-field: 7] - */ -export interface ClusterStats__Output { - /** - * The name of the cluster. - */ - 'cluster_name': (string); - /** - * Need at least one. - */ - 'upstream_locality_stats': (_envoy_api_v2_endpoint_UpstreamLocalityStats__Output)[]; - /** - * Cluster-level stats such as total_successful_requests may be computed by - * summing upstream_locality_stats. In addition, below there are additional - * cluster-wide stats. - * - * The total number of dropped requests. This covers requests - * deliberately dropped by the drop_overload policy and circuit breaking. - */ - 'total_dropped_requests': (string); - /** - * Period over which the actual load report occurred. This will be guaranteed to include every - * request reported. Due to system load and delays between the *LoadStatsRequest* sent from Envoy - * and the *LoadStatsResponse* message sent from the management server, this may be longer than - * the requested load reporting interval in the *LoadStatsResponse*. - */ - 'load_report_interval': (_google_protobuf_Duration__Output | null); - /** - * Information about deliberately dropped requests for each category specified - * in the DropOverload policy. - */ - 'dropped_requests': (_envoy_api_v2_endpoint_ClusterStats_DroppedRequests__Output)[]; - /** - * The eds_cluster_config service_name of the cluster. - * It's possible that two clusters send the same service_name to EDS, - * in that case, the management server is supposed to do aggregation on the load reports. - */ - 'cluster_service_name': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts deleted file mode 100644 index 335b759b6..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/EndpointLoadMetricStats.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto - -import type { Long } from '@grpc/proto-loader'; - -/** - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - */ -export interface EndpointLoadMetricStats { - /** - * Name of the metric; may be empty. - */ - 'metric_name'?: (string); - /** - * Number of calls that finished and included this metric. - */ - 'num_requests_finished_with_metric'?: (number | string | Long); - /** - * Sum of metric values across all calls that finished with this metric for - * load_reporting_interval. - */ - 'total_metric_value'?: (number | string); -} - -/** - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - */ -export interface EndpointLoadMetricStats__Output { - /** - * Name of the metric; may be empty. - */ - 'metric_name': (string); - /** - * Number of calls that finished and included this metric. - */ - 'num_requests_finished_with_metric': (string); - /** - * Sum of metric values across all calls that finished with this metric for - * load_reporting_interval. - */ - 'total_metric_value': (number); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts deleted file mode 100644 index e4551bd37..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamEndpointStats.ts +++ /dev/null @@ -1,106 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto - -import type { Address as _envoy_api_v2_core_Address, Address__Output as _envoy_api_v2_core_Address__Output } from '../../../../envoy/api/v2/core/Address'; -import type { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; -import type { Struct as _google_protobuf_Struct, Struct__Output as _google_protobuf_Struct__Output } from '../../../../google/protobuf/Struct'; -import type { Long } from '@grpc/proto-loader'; - -/** - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - * [#next-free-field: 8] - */ -export interface UpstreamEndpointStats { - /** - * Upstream host address. - */ - 'address'?: (_envoy_api_v2_core_Address | null); - /** - * The total number of requests successfully completed by the endpoints in the - * locality. These include non-5xx responses for HTTP, where errors - * originate at the client and the endpoint responded successfully. For gRPC, - * the grpc-status values are those not covered by total_error_requests below. - */ - 'total_successful_requests'?: (number | string | Long); - /** - * The total number of unfinished requests for this endpoint. - */ - 'total_requests_in_progress'?: (number | string | Long); - /** - * The total number of requests that failed due to errors at the endpoint. - * For HTTP these are responses with 5xx status codes and for gRPC the - * grpc-status values: - * - * - DeadlineExceeded - * - Unimplemented - * - Internal - * - Unavailable - * - Unknown - * - DataLoss - */ - 'total_error_requests'?: (number | string | Long); - /** - * Stats for multi-dimensional load balancing. - */ - 'load_metric_stats'?: (_envoy_api_v2_endpoint_EndpointLoadMetricStats)[]; - /** - * Opaque and implementation dependent metadata of the - * endpoint. Envoy will pass this directly to the management server. - */ - 'metadata'?: (_google_protobuf_Struct | null); - /** - * The total number of requests that were issued to this endpoint - * since the last report. A single TCP connection, HTTP or gRPC - * request or stream is counted as one request. - */ - 'total_issued_requests'?: (number | string | Long); -} - -/** - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - * [#next-free-field: 8] - */ -export interface UpstreamEndpointStats__Output { - /** - * Upstream host address. - */ - 'address': (_envoy_api_v2_core_Address__Output | null); - /** - * The total number of requests successfully completed by the endpoints in the - * locality. These include non-5xx responses for HTTP, where errors - * originate at the client and the endpoint responded successfully. For gRPC, - * the grpc-status values are those not covered by total_error_requests below. - */ - 'total_successful_requests': (string); - /** - * The total number of unfinished requests for this endpoint. - */ - 'total_requests_in_progress': (string); - /** - * The total number of requests that failed due to errors at the endpoint. - * For HTTP these are responses with 5xx status codes and for gRPC the - * grpc-status values: - * - * - DeadlineExceeded - * - Unimplemented - * - Internal - * - Unavailable - * - Unknown - * - DataLoss - */ - 'total_error_requests': (string); - /** - * Stats for multi-dimensional load balancing. - */ - 'load_metric_stats': (_envoy_api_v2_endpoint_EndpointLoadMetricStats__Output)[]; - /** - * Opaque and implementation dependent metadata of the - * endpoint. Envoy will pass this directly to the management server. - */ - 'metadata': (_google_protobuf_Struct__Output | null); - /** - * The total number of requests that were issued to this endpoint - * since the last report. A single TCP connection, HTTP or gRPC - * request or stream is counted as one request. - */ - 'total_issued_requests': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts b/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts deleted file mode 100644 index df4d4eb89..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/api/v2/endpoint/UpstreamLocalityStats.ts +++ /dev/null @@ -1,108 +0,0 @@ -// Original file: deps/envoy-api/envoy/api/v2/endpoint/load_report.proto - -import type { Locality as _envoy_api_v2_core_Locality, Locality__Output as _envoy_api_v2_core_Locality__Output } from '../../../../envoy/api/v2/core/Locality'; -import type { EndpointLoadMetricStats as _envoy_api_v2_endpoint_EndpointLoadMetricStats, EndpointLoadMetricStats__Output as _envoy_api_v2_endpoint_EndpointLoadMetricStats__Output } from '../../../../envoy/api/v2/endpoint/EndpointLoadMetricStats'; -import type { UpstreamEndpointStats as _envoy_api_v2_endpoint_UpstreamEndpointStats, UpstreamEndpointStats__Output as _envoy_api_v2_endpoint_UpstreamEndpointStats__Output } from '../../../../envoy/api/v2/endpoint/UpstreamEndpointStats'; -import type { Long } from '@grpc/proto-loader'; - -/** - * These are stats Envoy reports to GLB every so often. Report frequency is - * defined by - * :ref:`LoadStatsResponse.load_reporting_interval`. - * Stats per upstream region/zone and optionally per subzone. - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - * [#next-free-field: 9] - */ -export interface UpstreamLocalityStats { - /** - * Name of zone, region and optionally endpoint group these metrics were - * collected from. Zone and region names could be empty if unknown. - */ - 'locality'?: (_envoy_api_v2_core_Locality | null); - /** - * The total number of requests successfully completed by the endpoints in the - * locality. - */ - 'total_successful_requests'?: (number | string | Long); - /** - * The total number of unfinished requests - */ - 'total_requests_in_progress'?: (number | string | Long); - /** - * The total number of requests that failed due to errors at the endpoint, - * aggregated over all endpoints in the locality. - */ - 'total_error_requests'?: (number | string | Long); - /** - * Stats for multi-dimensional load balancing. - */ - 'load_metric_stats'?: (_envoy_api_v2_endpoint_EndpointLoadMetricStats)[]; - /** - * [#not-implemented-hide:] The priority of the endpoint group these metrics - * were collected from. - */ - 'priority'?: (number); - /** - * Endpoint granularity stats information for this locality. This information - * is populated if the Server requests it by setting - * :ref:`LoadStatsResponse.report_endpoint_granularity`. - */ - 'upstream_endpoint_stats'?: (_envoy_api_v2_endpoint_UpstreamEndpointStats)[]; - /** - * The total number of requests that were issued by this Envoy since - * the last report. This information is aggregated over all the - * upstream endpoints in the locality. - */ - 'total_issued_requests'?: (number | string | Long); -} - -/** - * These are stats Envoy reports to GLB every so often. Report frequency is - * defined by - * :ref:`LoadStatsResponse.load_reporting_interval`. - * Stats per upstream region/zone and optionally per subzone. - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - * [#next-free-field: 9] - */ -export interface UpstreamLocalityStats__Output { - /** - * Name of zone, region and optionally endpoint group these metrics were - * collected from. Zone and region names could be empty if unknown. - */ - 'locality': (_envoy_api_v2_core_Locality__Output | null); - /** - * The total number of requests successfully completed by the endpoints in the - * locality. - */ - 'total_successful_requests': (string); - /** - * The total number of unfinished requests - */ - 'total_requests_in_progress': (string); - /** - * The total number of requests that failed due to errors at the endpoint, - * aggregated over all endpoints in the locality. - */ - 'total_error_requests': (string); - /** - * Stats for multi-dimensional load balancing. - */ - 'load_metric_stats': (_envoy_api_v2_endpoint_EndpointLoadMetricStats__Output)[]; - /** - * [#not-implemented-hide:] The priority of the endpoint group these metrics - * were collected from. - */ - 'priority': (number); - /** - * Endpoint granularity stats information for this locality. This information - * is populated if the Server requests it by setting - * :ref:`LoadStatsResponse.report_endpoint_granularity`. - */ - 'upstream_endpoint_stats': (_envoy_api_v2_endpoint_UpstreamEndpointStats__Output)[]; - /** - * The total number of requests that were issued by this Envoy since - * the last report. This information is aggregated over all the - * upstream endpoints in the locality. - */ - 'total_issued_requests': (string); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts deleted file mode 100644 index eeb6aa6af..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AdsDummy.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto - - -/** - * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing - * services: https://github.com/google/protobuf/issues/4221 - */ -export interface AdsDummy { -} - -/** - * [#not-implemented-hide:] Not configuration. Workaround c++ protobuf issue with importing - * services: https://github.com/google/protobuf/issues/4221 - */ -export interface AdsDummy__Output { -} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts b/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts deleted file mode 100644 index 6044118bc..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/service/discovery/v2/AggregatedDiscoveryService.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Original file: deps/envoy-api/envoy/service/discovery/v2/ads.proto - -import type * as grpc from '@grpc/grpc-js' -import type { MethodDefinition } from '@grpc/proto-loader' -import type { DeltaDiscoveryRequest as _envoy_api_v2_DeltaDiscoveryRequest, DeltaDiscoveryRequest__Output as _envoy_api_v2_DeltaDiscoveryRequest__Output } from '../../../../envoy/api/v2/DeltaDiscoveryRequest'; -import type { DeltaDiscoveryResponse as _envoy_api_v2_DeltaDiscoveryResponse, DeltaDiscoveryResponse__Output as _envoy_api_v2_DeltaDiscoveryResponse__Output } from '../../../../envoy/api/v2/DeltaDiscoveryResponse'; -import type { DiscoveryRequest as _envoy_api_v2_DiscoveryRequest, DiscoveryRequest__Output as _envoy_api_v2_DiscoveryRequest__Output } from '../../../../envoy/api/v2/DiscoveryRequest'; -import type { DiscoveryResponse as _envoy_api_v2_DiscoveryResponse, DiscoveryResponse__Output as _envoy_api_v2_DiscoveryResponse__Output } from '../../../../envoy/api/v2/DiscoveryResponse'; - -/** - * See https://github.com/lyft/envoy-api#apis for a description of the role of - * ADS and how it is intended to be used by a management server. ADS requests - * have the same structure as their singleton xDS counterparts, but can - * multiplex many resource types on a single stream. The type_url in the - * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover - * the multiplexed singleton APIs at the Envoy instance and management server. - */ -export interface AggregatedDiscoveryServiceClient extends grpc.Client { - DeltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; - DeltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; - deltaAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; - deltaAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse__Output>; - - /** - * This is a gRPC-only API. - */ - StreamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; - StreamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; - /** - * This is a gRPC-only API. - */ - streamAggregatedResources(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; - streamAggregatedResources(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse__Output>; - -} - -/** - * See https://github.com/lyft/envoy-api#apis for a description of the role of - * ADS and how it is intended to be used by a management server. ADS requests - * have the same structure as their singleton xDS counterparts, but can - * multiplex many resource types on a single stream. The type_url in the - * DiscoveryRequest/DiscoveryResponse provides sufficient information to recover - * the multiplexed singleton APIs at the Envoy instance and management server. - */ -export interface AggregatedDiscoveryServiceHandlers extends grpc.UntypedServiceImplementation { - DeltaAggregatedResources: grpc.handleBidiStreamingCall<_envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse>; - - /** - * This is a gRPC-only API. - */ - StreamAggregatedResources: grpc.handleBidiStreamingCall<_envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse>; - -} - -export interface AggregatedDiscoveryServiceDefinition extends grpc.ServiceDefinition { - DeltaAggregatedResources: MethodDefinition<_envoy_api_v2_DeltaDiscoveryRequest, _envoy_api_v2_DeltaDiscoveryResponse, _envoy_api_v2_DeltaDiscoveryRequest__Output, _envoy_api_v2_DeltaDiscoveryResponse__Output> - StreamAggregatedResources: MethodDefinition<_envoy_api_v2_DiscoveryRequest, _envoy_api_v2_DiscoveryResponse, _envoy_api_v2_DiscoveryRequest__Output, _envoy_api_v2_DiscoveryResponse__Output> -} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts deleted file mode 100644 index 2a95752de..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadReportingService.ts +++ /dev/null @@ -1,113 +0,0 @@ -// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto - -import type * as grpc from '@grpc/grpc-js' -import type { MethodDefinition } from '@grpc/proto-loader' -import type { LoadStatsRequest as _envoy_service_load_stats_v2_LoadStatsRequest, LoadStatsRequest__Output as _envoy_service_load_stats_v2_LoadStatsRequest__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsRequest'; -import type { LoadStatsResponse as _envoy_service_load_stats_v2_LoadStatsResponse, LoadStatsResponse__Output as _envoy_service_load_stats_v2_LoadStatsResponse__Output } from '../../../../envoy/service/load_stats/v2/LoadStatsResponse'; - -export interface LoadReportingServiceClient extends grpc.Client { - /** - * Advanced API to allow for multi-dimensional load balancing by remote - * server. For receiving LB assignments, the steps are: - * 1, The management server is configured with per cluster/zone/load metric - * capacity configuration. The capacity configuration definition is - * outside of the scope of this document. - * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters - * to balance. - * - * Independently, Envoy will initiate a StreamLoadStats bidi stream with a - * management server: - * 1. Once a connection establishes, the management server publishes a - * LoadStatsResponse for all clusters it is interested in learning load - * stats about. - * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts - * based on per-zone weights and/or per-instance weights (if specified) - * based on intra-zone LbPolicy. This information comes from the above - * {Stream,Fetch}Endpoints. - * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. - * 4. Envoy aggregates load reports over the period of time given to it in - * LoadStatsResponse.load_reporting_interval. This includes aggregation - * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as - * well as load metrics from upstream hosts. - * 5. When the timer of load_reporting_interval expires, Envoy sends new - * LoadStatsRequest filled with load reports for each cluster. - * 6. The management server uses the load reports from all reported Envoys - * from around the world, computes global assignment and prepares traffic - * assignment destined for each zone Envoys are located in. Goto 2. - */ - StreamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; - StreamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; - /** - * Advanced API to allow for multi-dimensional load balancing by remote - * server. For receiving LB assignments, the steps are: - * 1, The management server is configured with per cluster/zone/load metric - * capacity configuration. The capacity configuration definition is - * outside of the scope of this document. - * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters - * to balance. - * - * Independently, Envoy will initiate a StreamLoadStats bidi stream with a - * management server: - * 1. Once a connection establishes, the management server publishes a - * LoadStatsResponse for all clusters it is interested in learning load - * stats about. - * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts - * based on per-zone weights and/or per-instance weights (if specified) - * based on intra-zone LbPolicy. This information comes from the above - * {Stream,Fetch}Endpoints. - * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. - * 4. Envoy aggregates load reports over the period of time given to it in - * LoadStatsResponse.load_reporting_interval. This includes aggregation - * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as - * well as load metrics from upstream hosts. - * 5. When the timer of load_reporting_interval expires, Envoy sends new - * LoadStatsRequest filled with load reports for each cluster. - * 6. The management server uses the load reports from all reported Envoys - * from around the world, computes global assignment and prepares traffic - * assignment destined for each zone Envoys are located in. Goto 2. - */ - streamLoadStats(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; - streamLoadStats(options?: grpc.CallOptions): grpc.ClientDuplexStream<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse__Output>; - -} - -export interface LoadReportingServiceHandlers extends grpc.UntypedServiceImplementation { - /** - * Advanced API to allow for multi-dimensional load balancing by remote - * server. For receiving LB assignments, the steps are: - * 1, The management server is configured with per cluster/zone/load metric - * capacity configuration. The capacity configuration definition is - * outside of the scope of this document. - * 2. Envoy issues a standard {Stream,Fetch}Endpoints request for the clusters - * to balance. - * - * Independently, Envoy will initiate a StreamLoadStats bidi stream with a - * management server: - * 1. Once a connection establishes, the management server publishes a - * LoadStatsResponse for all clusters it is interested in learning load - * stats about. - * 2. For each cluster, Envoy load balances incoming traffic to upstream hosts - * based on per-zone weights and/or per-instance weights (if specified) - * based on intra-zone LbPolicy. This information comes from the above - * {Stream,Fetch}Endpoints. - * 3. When upstream hosts reply, they optionally add header with ASCII representation of EndpointLoadMetricStats. - * 4. Envoy aggregates load reports over the period of time given to it in - * LoadStatsResponse.load_reporting_interval. This includes aggregation - * stats Envoy maintains by itself (total_requests, rpc_errors etc.) as - * well as load metrics from upstream hosts. - * 5. When the timer of load_reporting_interval expires, Envoy sends new - * LoadStatsRequest filled with load reports for each cluster. - * 6. The management server uses the load reports from all reported Envoys - * from around the world, computes global assignment and prepares traffic - * assignment destined for each zone Envoys are located in. Goto 2. - */ - StreamLoadStats: grpc.handleBidiStreamingCall<_envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse>; - -} - -export interface LoadReportingServiceDefinition extends grpc.ServiceDefinition { - StreamLoadStats: MethodDefinition<_envoy_service_load_stats_v2_LoadStatsRequest, _envoy_service_load_stats_v2_LoadStatsResponse, _envoy_service_load_stats_v2_LoadStatsRequest__Output, _envoy_service_load_stats_v2_LoadStatsResponse__Output> -} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts deleted file mode 100644 index 3cd5ebc2f..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsRequest.ts +++ /dev/null @@ -1,34 +0,0 @@ -// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto - -import type { Node as _envoy_api_v2_core_Node, Node__Output as _envoy_api_v2_core_Node__Output } from '../../../../envoy/api/v2/core/Node'; -import type { ClusterStats as _envoy_api_v2_endpoint_ClusterStats, ClusterStats__Output as _envoy_api_v2_endpoint_ClusterStats__Output } from '../../../../envoy/api/v2/endpoint/ClusterStats'; - -/** - * A load report Envoy sends to the management server. - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - */ -export interface LoadStatsRequest { - /** - * Node identifier for Envoy instance. - */ - 'node'?: (_envoy_api_v2_core_Node | null); - /** - * A list of load stats to report. - */ - 'cluster_stats'?: (_envoy_api_v2_endpoint_ClusterStats)[]; -} - -/** - * A load report Envoy sends to the management server. - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - */ -export interface LoadStatsRequest__Output { - /** - * Node identifier for Envoy instance. - */ - 'node': (_envoy_api_v2_core_Node__Output | null); - /** - * A list of load stats to report. - */ - 'cluster_stats': (_envoy_api_v2_endpoint_ClusterStats__Output)[]; -} diff --git a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts b/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts deleted file mode 100644 index 1065fe22f..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/service/load_stats/v2/LoadStatsResponse.ts +++ /dev/null @@ -1,71 +0,0 @@ -// Original file: deps/envoy-api/envoy/service/load_stats/v2/lrs.proto - -import type { Duration as _google_protobuf_Duration, Duration__Output as _google_protobuf_Duration__Output } from '../../../../google/protobuf/Duration'; - -/** - * The management server sends envoy a LoadStatsResponse with all clusters it - * is interested in learning load stats about. - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - */ -export interface LoadStatsResponse { - /** - * Clusters to report stats for. - * Not populated if *send_all_clusters* is true. - */ - 'clusters'?: (string)[]; - /** - * The minimum interval of time to collect stats over. This is only a minimum for two reasons: - * 1. There may be some delay from when the timer fires until stats sampling occurs. - * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic - * that is observed in between the corresponding previous *LoadStatsRequest* and this - * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period - * of inobservability that might otherwise exists between the messages. New clusters are not - * subject to this consideration. - */ - 'load_reporting_interval'?: (_google_protobuf_Duration | null); - /** - * Set to *true* if the management server supports endpoint granularity - * report. - */ - 'report_endpoint_granularity'?: (boolean); - /** - * If true, the client should send all clusters it knows about. - * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their - * :ref:`client_features` field will honor this field. - */ - 'send_all_clusters'?: (boolean); -} - -/** - * The management server sends envoy a LoadStatsResponse with all clusters it - * is interested in learning load stats about. - * [#not-implemented-hide:] Not configuration. TBD how to doc proto APIs. - */ -export interface LoadStatsResponse__Output { - /** - * Clusters to report stats for. - * Not populated if *send_all_clusters* is true. - */ - 'clusters': (string)[]; - /** - * The minimum interval of time to collect stats over. This is only a minimum for two reasons: - * 1. There may be some delay from when the timer fires until stats sampling occurs. - * 2. For clusters that were already feature in the previous *LoadStatsResponse*, any traffic - * that is observed in between the corresponding previous *LoadStatsRequest* and this - * *LoadStatsResponse* will also be accumulated and billed to the cluster. This avoids a period - * of inobservability that might otherwise exists between the messages. New clusters are not - * subject to this consideration. - */ - 'load_reporting_interval': (_google_protobuf_Duration__Output | null); - /** - * Set to *true* if the management server supports endpoint granularity - * report. - */ - 'report_endpoint_granularity': (boolean); - /** - * If true, the client should send all clusters it knows about. - * Only clients that advertise the "envoy.lrs.supports_send_all_clusters" capability in their - * :ref:`client_features` field will honor this field. - */ - 'send_all_clusters': (boolean); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts b/packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts deleted file mode 100644 index e450f0bfa..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/type/FractionalPercent.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Original file: deps/envoy-api/envoy/type/percent.proto - - -// Original file: deps/envoy-api/envoy/type/percent.proto - -/** - * Fraction percentages support several fixed denominator values. - */ -export enum _envoy_type_FractionalPercent_DenominatorType { - /** - * 100. - * - * **Example**: 1/100 = 1%. - */ - HUNDRED = 0, - /** - * 10,000. - * - * **Example**: 1/10000 = 0.01%. - */ - TEN_THOUSAND = 1, - /** - * 1,000,000. - * - * **Example**: 1/1000000 = 0.0001%. - */ - MILLION = 2, -} - -/** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ -export interface FractionalPercent { - /** - * Specifies the numerator. Defaults to 0. - */ - 'numerator'?: (number); - /** - * Specifies the denominator. If the denominator specified is less than the numerator, the final - * fractional percentage is capped at 1 (100%). - */ - 'denominator'?: (_envoy_type_FractionalPercent_DenominatorType | keyof typeof _envoy_type_FractionalPercent_DenominatorType); -} - -/** - * A fractional percentage is used in cases in which for performance reasons performing floating - * point to integer conversions during randomness calculations is undesirable. The message includes - * both a numerator and denominator that together determine the final fractional value. - * - * * **Example**: 1/100 = 1%. - * * **Example**: 3/10000 = 0.03%. - */ -export interface FractionalPercent__Output { - /** - * Specifies the numerator. Defaults to 0. - */ - 'numerator': (number); - /** - * Specifies the denominator. If the denominator specified is less than the numerator, the final - * fractional percentage is capped at 1 (100%). - */ - 'denominator': (keyof typeof _envoy_type_FractionalPercent_DenominatorType); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts b/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts deleted file mode 100644 index 364419994..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/type/Percent.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Original file: deps/envoy-api/envoy/type/percent.proto - - -/** - * Identifies a percentage, in the range [0.0, 100.0]. - */ -export interface Percent { - 'value'?: (number | string); -} - -/** - * Identifies a percentage, in the range [0.0, 100.0]. - */ -export interface Percent__Output { - 'value': (number); -} diff --git a/packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts b/packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts deleted file mode 100644 index f99431703..000000000 --- a/packages/grpc-js-xds/src/generated/envoy/type/SemanticVersion.ts +++ /dev/null @@ -1,24 +0,0 @@ -// Original file: deps/envoy-api/envoy/type/semantic_version.proto - - -/** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ -export interface SemanticVersion { - 'major_number'?: (number); - 'minor_number'?: (number); - 'patch'?: (number); -} - -/** - * Envoy uses SemVer (https://semver.org/). Major/minor versions indicate - * expected behaviors and APIs, the patch version field is used only - * for security fixes and can be generally ignored. - */ -export interface SemanticVersion__Output { - 'major_number': (number); - 'minor_number': (number); - 'patch': (number); -} diff --git a/packages/grpc-js-xds/src/generated/lrs.ts b/packages/grpc-js-xds/src/generated/lrs.ts index e92f80800..e57d6c249 100644 --- a/packages/grpc-js-xds/src/generated/lrs.ts +++ b/packages/grpc-js-xds/src/generated/lrs.ts @@ -1,7 +1,6 @@ import type * as grpc from '@grpc/grpc-js'; import type { EnumTypeDefinition, MessageTypeDefinition } from '@grpc/proto-loader'; -import type { LoadReportingServiceClient as _envoy_service_load_stats_v2_LoadReportingServiceClient, LoadReportingServiceDefinition as _envoy_service_load_stats_v2_LoadReportingServiceDefinition } from './envoy/service/load_stats/v2/LoadReportingService'; import type { LoadReportingServiceClient as _envoy_service_load_stats_v3_LoadReportingServiceClient, LoadReportingServiceDefinition as _envoy_service_load_stats_v3_LoadReportingServiceDefinition } from './envoy/service/load_stats/v3/LoadReportingService'; type SubtypeConstructor any, Subtype> = { @@ -12,48 +11,6 @@ export interface ProtoGrpcType { envoy: { annotations: { } - api: { - v2: { - core: { - Address: MessageTypeDefinition - AsyncDataSource: MessageTypeDefinition - BackoffStrategy: MessageTypeDefinition - BindConfig: MessageTypeDefinition - BuildVersion: MessageTypeDefinition - CidrRange: MessageTypeDefinition - ControlPlane: MessageTypeDefinition - DataSource: MessageTypeDefinition - Extension: MessageTypeDefinition - HeaderMap: MessageTypeDefinition - HeaderValue: MessageTypeDefinition - HeaderValueOption: MessageTypeDefinition - HttpUri: MessageTypeDefinition - Locality: MessageTypeDefinition - Metadata: MessageTypeDefinition - Node: MessageTypeDefinition - Pipe: MessageTypeDefinition - RemoteDataSource: MessageTypeDefinition - RequestMethod: EnumTypeDefinition - RetryPolicy: MessageTypeDefinition - RoutingPriority: EnumTypeDefinition - RuntimeDouble: MessageTypeDefinition - RuntimeFeatureFlag: MessageTypeDefinition - RuntimeFractionalPercent: MessageTypeDefinition - RuntimeUInt32: MessageTypeDefinition - SocketAddress: MessageTypeDefinition - SocketOption: MessageTypeDefinition - TcpKeepalive: MessageTypeDefinition - TrafficDirection: EnumTypeDefinition - TransportSocket: MessageTypeDefinition - } - endpoint: { - ClusterStats: MessageTypeDefinition - EndpointLoadMetricStats: MessageTypeDefinition - UpstreamEndpointStats: MessageTypeDefinition - UpstreamLocalityStats: MessageTypeDefinition - } - } - } config: { core: { v3: { @@ -104,11 +61,6 @@ export interface ProtoGrpcType { } service: { load_stats: { - v2: { - LoadReportingService: SubtypeConstructor & { service: _envoy_service_load_stats_v2_LoadReportingServiceDefinition } - LoadStatsRequest: MessageTypeDefinition - LoadStatsResponse: MessageTypeDefinition - } v3: { LoadReportingService: SubtypeConstructor & { service: _envoy_service_load_stats_v3_LoadReportingServiceDefinition } LoadStatsRequest: MessageTypeDefinition @@ -117,9 +69,6 @@ export interface ProtoGrpcType { } } type: { - FractionalPercent: MessageTypeDefinition - Percent: MessageTypeDefinition - SemanticVersion: MessageTypeDefinition v3: { FractionalPercent: MessageTypeDefinition Percent: MessageTypeDefinition From 4ac8d6dab36b494cd49bca0a83068b067dd562e0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Oct 2022 13:48:39 -0700 Subject: [PATCH 1776/1899] grpc-js-xds: Remove all code for handling xDS v2 --- packages/grpc-js-xds/src/csds.ts | 14 +- packages/grpc-js-xds/src/load-balancer-eds.ts | 2 +- packages/grpc-js-xds/src/load-balancer-lrs.ts | 2 +- packages/grpc-js-xds/src/resolver-xds.ts | 28 +- packages/grpc-js-xds/src/resources.ts | 27 +- packages/grpc-js-xds/src/xds-client.ts | 432 +++++------------- .../src/xds-stream-state/lds-state.ts | 13 +- .../src/xds-stream-state/rds-state.ts | 8 +- .../src/xds-stream-state/xds-stream-state.ts | 15 +- 9 files changed, 173 insertions(+), 368 deletions(-) diff --git a/packages/grpc-js-xds/src/csds.ts b/packages/grpc-js-xds/src/csds.ts index 6454e1ad1..114c18042 100644 --- a/packages/grpc-js-xds/src/csds.ts +++ b/packages/grpc-js-xds/src/csds.ts @@ -21,7 +21,7 @@ import { ClientStatusDiscoveryServiceHandlers } from "./generated/envoy/service/ import { ClientStatusRequest__Output } from "./generated/envoy/service/status/v3/ClientStatusRequest"; import { ClientStatusResponse } from "./generated/envoy/service/status/v3/ClientStatusResponse"; import { Timestamp } from "./generated/google/protobuf/Timestamp"; -import { AdsTypeUrl, CDS_TYPE_URL_V2, CDS_TYPE_URL_V3, EDS_TYPE_URL_V2, EDS_TYPE_URL_V3, LDS_TYPE_URL_V2, LDS_TYPE_URL_V3, RDS_TYPE_URL_V2, RDS_TYPE_URL_V3 } from "./resources"; +import { AdsTypeUrl, CDS_TYPE_URL, EDS_TYPE_URL, LDS_TYPE_URL, RDS_TYPE_URL } from "./resources"; import { HandleResponseResult } from "./xds-stream-state/xds-stream-state"; import { sendUnaryData, ServerDuplexStream, ServerUnaryCall, status, experimental, loadPackageDefinition, logVerbosity } from '@grpc/grpc-js'; import { loadSync } from "@grpc/proto-loader"; @@ -50,14 +50,10 @@ function dateToProtoTimestamp(date?: Date | null): Timestamp | null { let clientNode: Node | null = null; const configStatus = { - [EDS_TYPE_URL_V2]: new Map(), - [EDS_TYPE_URL_V3]: new Map(), - [CDS_TYPE_URL_V2]: new Map(), - [CDS_TYPE_URL_V3]: new Map(), - [RDS_TYPE_URL_V2]: new Map(), - [RDS_TYPE_URL_V3]: new Map(), - [LDS_TYPE_URL_V2]: new Map(), - [LDS_TYPE_URL_V3]: new Map() + [EDS_TYPE_URL]: new Map(), + [CDS_TYPE_URL]: new Map(), + [RDS_TYPE_URL]: new Map(), + [LDS_TYPE_URL]: new Map() }; /** diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index e7aac0571..6bec1fd19 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -18,7 +18,7 @@ import { connectivityState as ConnectivityState, status as Status, Metadata, logVerbosity as LogVerbosity, experimental, StatusObject } from '@grpc/grpc-js'; import { getSingletonXdsClient, XdsClient, XdsClusterDropStats } from './xds-client'; import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint/v3/ClusterLoadAssignment'; -import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { Locality__Output } from './generated/envoy/config/core/v3/Locality'; import { LocalitySubchannelAddress, PriorityChild, PriorityLoadBalancingConfig } from './load-balancer-priority'; import LoadBalancer = experimental.LoadBalancer; import ChannelControlHelper = experimental.ChannelControlHelper; diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index 145501fe9..27c62c19b 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -16,7 +16,7 @@ */ import { connectivityState as ConnectivityState, StatusObject, status as Status, experimental } from '@grpc/grpc-js'; -import { Locality__Output } from './generated/envoy/api/v2/core/Locality'; +import { Locality__Output } from './generated/envoy/config/core/v3/Locality'; import { XdsClusterLocalityStats, XdsClient, getSingletonXdsClient } from './xds-client'; import LoadBalancer = experimental.LoadBalancer; import ChannelControlHelper = experimental.ChannelControlHelper; diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 8c447931d..496c37094 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -40,7 +40,7 @@ import { XdsClusterManagerLoadBalancingConfig } from './load-balancer-xds-cluste import { ExactValueMatcher, FullMatcher, HeaderMatcher, Matcher, PathExactValueMatcher, PathPrefixValueMatcher, PathSafeRegexValueMatcher, PrefixValueMatcher, PresentValueMatcher, RangeValueMatcher, RejectValueMatcher, SafeRegexValueMatcher, SuffixValueMatcher, ValueMatcher } from './matcher'; import { envoyFractionToFraction, Fraction } from "./fraction"; import { RouteAction, SingleClusterRouteAction, WeightedCluster, WeightedClusterRouteAction } from './route-action'; -import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from './resources'; +import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL } from './resources'; import Duration = experimental.Duration; import { Duration__Output } from './generated/google/protobuf/Duration'; import { createHttpFilter, HttpFilterConfig, parseOverrideFilterConfig, parseTopLevelFilterConfig } from './http-filter'; @@ -212,7 +212,6 @@ class XdsResolver implements Resolver { private latestRouteConfigName: string | null = null; private latestRouteConfig: RouteConfiguration__Output | null = null; - private latestRouteConfigIsV2 = false; private clusterRefcounts = new Map(); @@ -226,15 +225,15 @@ class XdsResolver implements Resolver { private channelOptions: ChannelOptions ) { this.ldsWatcher = { - onValidUpdate: (update: Listener__Output, isV2: boolean) => { - const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, update.api_listener!.api_listener!.value); + onValidUpdate: (update: Listener__Output) => { + const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL, update.api_listener!.api_listener!.value); const defaultTimeout = httpConnectionManager.common_http_protocol_options?.idle_timeout; if (defaultTimeout === null || defaultTimeout === undefined) { this.latestDefaultTimeout = undefined; } else { this.latestDefaultTimeout = protoDurationToDuration(defaultTimeout); } - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { this.ldsHttpFilterConfigs = []; for (const filter of httpConnectionManager.http_filters) { // typed_config must be set here, or validation would have failed @@ -260,7 +259,7 @@ class XdsResolver implements Resolver { if (this.latestRouteConfigName) { getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); } - this.handleRouteConfig(httpConnectionManager.route_config!, isV2); + this.handleRouteConfig(httpConnectionManager.route_config!); break; default: // This is prevented by the validation rules @@ -280,8 +279,8 @@ class XdsResolver implements Resolver { } }; this.rdsWatcher = { - onValidUpdate: (update: RouteConfiguration__Output, isV2: boolean) => { - this.handleRouteConfig(update, isV2); + onValidUpdate: (update: RouteConfiguration__Output) => { + this.handleRouteConfig(update); }, onTransientError: (error: StatusObject) => { /* A transient error only needs to bubble up as a failure if we have @@ -311,14 +310,13 @@ class XdsResolver implements Resolver { refCount.refCount -= 1; if (!refCount.inLastConfig && refCount.refCount === 0) { this.clusterRefcounts.delete(clusterName); - this.handleRouteConfig(this.latestRouteConfig!, this.latestRouteConfigIsV2); + this.handleRouteConfig(this.latestRouteConfig!); } } } - private handleRouteConfig(routeConfig: RouteConfiguration__Output, isV2: boolean) { + private handleRouteConfig(routeConfig: RouteConfiguration__Output) { this.latestRouteConfig = routeConfig; - this.latestRouteConfigIsV2 = isV2; /* Select the virtual host using the default authority override if it * exists, and the channel target otherwise. */ const hostDomain = this.channelOptions['grpc.default_authority'] ?? this.target.path; @@ -328,7 +326,7 @@ class XdsResolver implements Resolver { return; } const virtualHostHttpFilterOverrides = new Map(); - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filter] of Object.entries(virtualHost.typed_per_filter_config ?? {})) { const parsedConfig = parseOverrideFilterConfig(filter); if (parsedConfig) { @@ -357,7 +355,7 @@ class XdsResolver implements Resolver { timeout = undefined; } const routeHttpFilterOverrides = new Map(); - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filter] of Object.entries(route.typed_per_filter_config ?? {})) { const parsedConfig = parseOverrideFilterConfig(filter); if (parsedConfig) { @@ -372,7 +370,7 @@ class XdsResolver implements Resolver { const cluster = route.route!.cluster!; allConfigClusters.add(cluster); const extraFilterFactories: FilterFactory[] = []; - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const filterConfig of this.ldsHttpFilterConfigs) { if (routeHttpFilterOverrides.has(filterConfig.name)) { const filter = createHttpFilter(filterConfig.config, routeHttpFilterOverrides.get(filterConfig.name)!); @@ -401,7 +399,7 @@ class XdsResolver implements Resolver { allConfigClusters.add(clusterWeight.name); const extraFilterFactories: FilterFactory[] = []; const clusterHttpFilterOverrides = new Map(); - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filter] of Object.entries(clusterWeight.typed_per_filter_config ?? {})) { const parsedConfig = parseOverrideFilterConfig(filter); if (parsedConfig) { diff --git a/packages/grpc-js-xds/src/resources.ts b/packages/grpc-js-xds/src/resources.ts index 4a7e22763..0972ce97d 100644 --- a/packages/grpc-js-xds/src/resources.ts +++ b/packages/grpc-js-xds/src/resources.ts @@ -23,29 +23,22 @@ import { Listener__Output } from './generated/envoy/config/listener/v3/Listener' import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; import { HttpConnectionManager__Output } from './generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager'; -export const EDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment'; -export const CDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.Cluster'; -export const LDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.Listener'; -export const RDS_TYPE_URL_V2 = 'type.googleapis.com/envoy.api.v2.RouteConfiguration'; +export const EDS_TYPE_URL = 'type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment'; +export const CDS_TYPE_URL = 'type.googleapis.com/envoy.config.cluster.v3.Cluster'; +export const LDS_TYPE_URL = 'type.googleapis.com/envoy.config.listener.v3.Listener'; +export const RDS_TYPE_URL = 'type.googleapis.com/envoy.config.route.v3.RouteConfiguration'; -export const EDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment'; -export const CDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.cluster.v3.Cluster'; -export const LDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.listener.v3.Listener'; -export const RDS_TYPE_URL_V3 = 'type.googleapis.com/envoy.config.route.v3.RouteConfiguration'; - -export type EdsTypeUrl = 'type.googleapis.com/envoy.api.v2.ClusterLoadAssignment' | 'type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment'; -export type CdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Cluster' | 'type.googleapis.com/envoy.config.cluster.v3.Cluster'; -export type LdsTypeUrl = 'type.googleapis.com/envoy.api.v2.Listener' | 'type.googleapis.com/envoy.config.listener.v3.Listener'; -export type RdsTypeUrl = 'type.googleapis.com/envoy.api.v2.RouteConfiguration' | 'type.googleapis.com/envoy.config.route.v3.RouteConfiguration'; +export type EdsTypeUrl = 'type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment'; +export type CdsTypeUrl = 'type.googleapis.com/envoy.config.cluster.v3.Cluster'; +export type LdsTypeUrl = 'type.googleapis.com/envoy.config.listener.v3.Listener'; +export type RdsTypeUrl = 'type.googleapis.com/envoy.config.route.v3.RouteConfiguration'; export type AdsTypeUrl = EdsTypeUrl | CdsTypeUrl | RdsTypeUrl | LdsTypeUrl; -export const HTTP_CONNECTION_MANGER_TYPE_URL_V2 = - 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager'; -export const HTTP_CONNECTION_MANGER_TYPE_URL_V3 = +export const HTTP_CONNECTION_MANGER_TYPE_URL = 'type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager'; -export type HttpConnectionManagerTypeUrl = 'type.googleapis.com/envoy.config.filter.network.http_connection_manager.v2.HttpConnectionManager' | 'type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager'; +export type HttpConnectionManagerTypeUrl = 'type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager'; /** * Map type URLs to their corresponding message types diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 0c8126cbe..439ed80ea 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -22,17 +22,12 @@ import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, ex import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; import { loadBootstrapInfo } from './xds-bootstrap'; -import { Node as NodeV2 } from './generated/envoy/api/v2/core/Node'; -import { Node as NodeV3 } from './generated/envoy/config/core/v3/Node'; -import { AggregatedDiscoveryServiceClient as AggregatedDiscoveryServiceClientV2 } from './generated/envoy/service/discovery/v2/AggregatedDiscoveryService'; -import { AggregatedDiscoveryServiceClient as AggregatedDiscoveryServiceClientV3 } from './generated/envoy/service/discovery/v3/AggregatedDiscoveryService'; -import { DiscoveryRequest as DiscoveryRequestV2 } from './generated/envoy/api/v2/DiscoveryRequest'; -import { DiscoveryRequest as DiscoveryRequestV3 } from './generated/envoy/service/discovery/v3/DiscoveryRequest'; +import { Node } from './generated/envoy/config/core/v3/Node'; +import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v3/AggregatedDiscoveryService'; +import { DiscoveryRequest } from './generated/envoy/service/discovery/v3/DiscoveryRequest'; import { DiscoveryResponse__Output } from './generated/envoy/service/discovery/v3/DiscoveryResponse'; -import { LoadReportingServiceClient as LoadReportingServiceClientV2 } from './generated/envoy/service/load_stats/v2/LoadReportingService'; -import { LoadReportingServiceClient as LoadReportingServiceClientV3 } from './generated/envoy/service/load_stats/v3/LoadReportingService'; -import { LoadStatsRequest as LoadStatsRequestV2 } from './generated/envoy/service/load_stats/v2/LoadStatsRequest'; -import { LoadStatsRequest as LoadStatsRequestV3 } from './generated/envoy/service/load_stats/v3/LoadStatsRequest'; +import { LoadReportingServiceClient } from './generated/envoy/service/load_stats/v3/LoadReportingService'; +import { LoadStatsRequest } from './generated/envoy/service/load_stats/v3/LoadStatsRequest'; import { LoadStatsResponse__Output } from './generated/envoy/service/load_stats/v3/LoadStatsResponse'; import { Locality, Locality__Output } from './generated/envoy/config/core/v3/Locality'; import { Listener__Output } from './generated/envoy/config/listener/v3/Listener'; @@ -50,7 +45,7 @@ import { ClusterLoadAssignment__Output } from './generated/envoy/config/endpoint import { Cluster__Output } from './generated/envoy/config/cluster/v3/Cluster'; import { RouteConfiguration__Output } from './generated/envoy/config/route/v3/RouteConfiguration'; import { Duration } from './generated/google/protobuf/Duration'; -import { AdsOutputType, AdsTypeUrl, CDS_TYPE_URL_V2, CDS_TYPE_URL_V3, decodeSingleResource, EDS_TYPE_URL_V2, EDS_TYPE_URL_V3, LDS_TYPE_URL_V2, LDS_TYPE_URL_V3, RDS_TYPE_URL_V2, RDS_TYPE_URL_V3 } from './resources'; +import { AdsOutputType, AdsTypeUrl, CDS_TYPE_URL, decodeSingleResource, EDS_TYPE_URL, LDS_TYPE_URL, RDS_TYPE_URL } from './resources'; import { setCsdsClientNode, updateCsdsRequestedNameList, updateCsdsResourceResponse } from './csds'; const TRACER_NAME = 'xds_client'; @@ -74,8 +69,6 @@ function loadAdsProtos(): Promise< loadedProtos = protoLoader .load( [ - 'envoy/service/discovery/v2/ads.proto', - 'envoy/service/load_stats/v2/lrs.proto', 'envoy/service/discovery/v3/ads.proto', 'envoy/service/load_stats/v3/lrs.proto', ], @@ -85,6 +78,7 @@ function loadAdsProtos(): Promise< enums: String, defaults: true, oneofs: true, + json: true, includeDirs: [ // Paths are relative to src/build __dirname + '/../../deps/envoy-api/', @@ -234,62 +228,38 @@ interface AdsState { lds: LdsState; } -enum XdsApiVersion { - V2, - V3 -} - function getResponseMessages( targetTypeUrl: T, - allowedTypeUrls: string[], resources: Any__Output[] ): ResourcePair>[] { const result: ResourcePair>[] = []; for (const resource of resources) { - if (allowedTypeUrls.includes(resource.type_url)) { - result.push({ - resource: decodeSingleResource(targetTypeUrl, resource.value), - raw: resource - }); - } else { + if (resource.type_url !== targetTypeUrl) { throw new Error( - `ADS Error: Invalid resource type ${resource.type_url}, expected ${allowedTypeUrls}` + `ADS Error: Invalid resource type ${resource.type_url}, expected ${targetTypeUrl}` ); } + result.push({ + resource: decodeSingleResource(targetTypeUrl, resource.value), + raw: resource + }); } return result; } export class XdsClient { - private apiVersion: XdsApiVersion = XdsApiVersion.V2; - - private adsNodeV2: NodeV2 | null = null; - private adsNodeV3: NodeV3 | null = null; - /* A client initiates connections lazily, so the client we don't use won't - * use significant extra resources. */ - private adsClientV2: AggregatedDiscoveryServiceClientV2 | null = null; - private adsClientV3: AggregatedDiscoveryServiceClientV3 | null = null; - /* TypeScript typing is structural, so we can take advantage of the fact that - * the output structures for the two call types are identical. */ - private adsCallV2: ClientDuplexStream< - DiscoveryRequestV2, - DiscoveryResponse__Output - > | null = null; - private adsCallV3: ClientDuplexStream< - DiscoveryRequestV3, + + private adsNode: Node | null = null; + private adsClient: AggregatedDiscoveryServiceClient | null = null; + private adsCall: ClientDuplexStream< + DiscoveryRequest, DiscoveryResponse__Output > | null = null; - private lrsNodeV2: NodeV2 | null = null; - private lrsNodeV3: NodeV3 | null = null; - private lrsClientV2: LoadReportingServiceClientV2 | null = null; - private lrsClientV3: LoadReportingServiceClientV3 | null = null; - private lrsCallV2: ClientDuplexStream< - LoadStatsRequestV2, - LoadStatsResponse__Output - > | null = null; - private lrsCallV3: ClientDuplexStream< - LoadStatsRequestV3, + private lrsNode: Node | null = null; + private lrsClient: LoadReportingServiceClient | null = null; + private lrsCall: ClientDuplexStream< + LoadStatsRequest, LoadStatsResponse__Output > | null = null; private latestLrsSettings: LoadStatsResponse__Output | null = null; @@ -355,48 +325,24 @@ export class XdsClient { }); return; } - if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('xds_v3') >= 0) { - this.apiVersion = XdsApiVersion.V3; - } else { - this.apiVersion = XdsApiVersion.V2; - } if (bootstrapInfo.xdsServers[0].serverFeatures.indexOf('ignore_resource_deletion') >= 0) { this.adsState.lds.enableIgnoreResourceDeletion(); this.adsState.cds.enableIgnoreResourceDeletion(); } - const nodeV2: NodeV2 = { - ...bootstrapInfo.node, - build_version: `gRPC Node Pure JS ${clientVersion}`, - user_agent_name: 'gRPC Node Pure JS', - }; - const nodeV3: NodeV3 = { + const userAgentName = 'gRPC Node Pure JS'; + this.adsNode = { ...bootstrapInfo.node, - user_agent_name: 'gRPC Node Pure JS', - }; - this.adsNodeV2 = { - ...nodeV2, - client_features: ['envoy.lb.does_not_support_overprovisioning'], - }; - this.adsNodeV3 = { - ...nodeV3, + user_agent_name: userAgentName, client_features: ['envoy.lb.does_not_support_overprovisioning'], }; - this.lrsNodeV2 = { - ...nodeV2, - client_features: ['envoy.lrs.supports_send_all_clusters'], - }; - this.lrsNodeV3 = { - ...nodeV3, + this.lrsNode = { + ...bootstrapInfo.node, + user_agent_name: userAgentName, client_features: ['envoy.lrs.supports_send_all_clusters'], }; - setCsdsClientNode(this.adsNodeV3); - if (this.apiVersion === XdsApiVersion.V2) { - trace('ADS Node: ' + JSON.stringify(this.adsNodeV2, undefined, 2)); - trace('LRS Node: ' + JSON.stringify(this.lrsNodeV2, undefined, 2)); - } else { - trace('ADS Node: ' + JSON.stringify(this.adsNodeV3, undefined, 2)); - trace('LRS Node: ' + JSON.stringify(this.lrsNodeV3, undefined, 2)); - } + setCsdsClientNode(this.adsNode); + trace('ADS Node: ' + JSON.stringify(this.adsNode, undefined, 2)); + trace('LRS Node: ' + JSON.stringify(this.lrsNode, undefined, 2)); const credentialsConfigs = bootstrapInfo.xdsServers[0].channelCreds; let channelCreds: ChannelCredentials | null = null; for (const config of credentialsConfigs) { @@ -421,24 +367,14 @@ export class XdsClient { const serverUri = bootstrapInfo.xdsServers[0].serverUri trace('Starting xDS client connected to server URI ' + bootstrapInfo.xdsServers[0].serverUri); const channel = new Channel(serverUri, channelCreds, channelArgs); - this.adsClientV2 = new protoDefinitions.envoy.service.discovery.v2.AggregatedDiscoveryService( - serverUri, - channelCreds, - {channelOverride: channel} - ); - this.adsClientV3 = new protoDefinitions.envoy.service.discovery.v3.AggregatedDiscoveryService( + this.adsClient = new protoDefinitions.envoy.service.discovery.v3.AggregatedDiscoveryService( serverUri, channelCreds, {channelOverride: channel} ); this.maybeStartAdsStream(); - this.lrsClientV2 = new protoDefinitions.envoy.service.load_stats.v2.LoadReportingService( - serverUri, - channelCreds, - {channelOverride: channel} - ); - this.lrsClientV3 = new protoDefinitions.envoy.service.load_stats.v3.LoadReportingService( + this.lrsClient = new protoDefinitions.envoy.service.load_stats.v3.LoadReportingService( serverUri, channelCreds, {channelOverride: channel} @@ -463,55 +399,36 @@ export class XdsClient { result: HandleResponseResult; serviceKind: AdsServiceKind; } | null = null; - let isV2: boolean; - switch (message.type_url) { - case EDS_TYPE_URL_V2: - case CDS_TYPE_URL_V2: - case RDS_TYPE_URL_V2: - case LDS_TYPE_URL_V2: - isV2 = true; - break; - default: - isV2 = false; - } try { switch (message.type_url) { - case EDS_TYPE_URL_V2: - case EDS_TYPE_URL_V3: + case EDS_TYPE_URL: handleResponseResult = { result: this.adsState.eds.handleResponses( - getResponseMessages(EDS_TYPE_URL_V3, [EDS_TYPE_URL_V2, EDS_TYPE_URL_V3], message.resources), - isV2 + getResponseMessages(EDS_TYPE_URL, message.resources) ), serviceKind: 'eds' }; break; - case CDS_TYPE_URL_V2: - case CDS_TYPE_URL_V3: + case CDS_TYPE_URL: handleResponseResult = { result: this.adsState.cds.handleResponses( - getResponseMessages(CDS_TYPE_URL_V3, [CDS_TYPE_URL_V2, CDS_TYPE_URL_V3], message.resources), - isV2 + getResponseMessages(CDS_TYPE_URL, message.resources) ), serviceKind: 'cds' }; break; - case RDS_TYPE_URL_V2: - case RDS_TYPE_URL_V3: + case RDS_TYPE_URL: handleResponseResult = { result: this.adsState.rds.handleResponses( - getResponseMessages(RDS_TYPE_URL_V3, [RDS_TYPE_URL_V2, RDS_TYPE_URL_V3], message.resources), - isV2 + getResponseMessages(RDS_TYPE_URL, message.resources) ), serviceKind: 'rds' }; break; - case LDS_TYPE_URL_V2: - case LDS_TYPE_URL_V3: + case LDS_TYPE_URL: handleResponseResult = { result: this.adsState.lds.handleResponses( - getResponseMessages(LDS_TYPE_URL_V3, [LDS_TYPE_URL_V2, LDS_TYPE_URL_V3], message.resources), - isV2 + getResponseMessages(LDS_TYPE_URL, message.resources) ), serviceKind: 'lds' } @@ -548,8 +465,7 @@ export class XdsClient { trace( 'ADS stream ended. code=' + streamStatus.code + ' details= ' + streamStatus.details ); - this.adsCallV2 = null; - this.adsCallV3 = null; + this.adsCall = null; if (streamStatus.code !== status.OK) { this.reportStreamError(streamStatus); } @@ -560,48 +476,6 @@ export class XdsClient { } } - private maybeStartAdsStreamV2(): boolean { - if (this.apiVersion !== XdsApiVersion.V2) { - return false; - } - if (this.adsClientV2 === null) { - return false; - } - if (this.adsCallV2 !== null) { - return false; - } - this.adsCallV2 = this.adsClientV2.StreamAggregatedResources(); - this.adsCallV2.on('data', (message: DiscoveryResponse__Output) => { - this.handleAdsResponse(message); - }); - this.adsCallV2.on('status', (status: StatusObject) => { - this.handleAdsCallStatus(status); - }); - this.adsCallV2.on('error', () => {}); - return true; - } - - private maybeStartAdsStreamV3(): boolean { - if (this.apiVersion !== XdsApiVersion.V3) { - return false; - } - if (this.adsClientV3 === null) { - return false; - } - if (this.adsCallV3 !== null) { - return false; - } - this.adsCallV3 = this.adsClientV3.StreamAggregatedResources(); - this.adsCallV3.on('data', (message: DiscoveryResponse__Output) => { - this.handleAdsResponse(message); - }); - this.adsCallV3.on('status', (status: StatusObject) => { - this.handleAdsCallStatus(status); - }); - this.adsCallV3.on('error', () => {}); - return true; - } - /** * Start the ADS stream if the client exists and there is not already an * existing stream, and there are resources to request. @@ -616,73 +490,55 @@ export class XdsClient { this.adsState.lds.getResourceNames().length === 0) { return; } - let streamStarted: boolean; - if (this.apiVersion === XdsApiVersion.V2) { - streamStarted = this.maybeStartAdsStreamV2(); - } else { - streamStarted = this.maybeStartAdsStreamV3(); + if (this.adsClient === null) { + return; } - if (streamStarted) { - trace('Started ADS stream'); - // Backoff relative to when we start the request - this.adsBackoff.runOnce(); - - const allServiceKinds: AdsServiceKind[] = ['eds', 'cds', 'rds', 'lds']; - for (const service of allServiceKinds) { - const state = this.adsState[service]; - if (state.getResourceNames().length > 0) { - this.updateNames(service); - } + if (this.adsCall !== null) { + return; + } + this.adsCall = this.adsClient.StreamAggregatedResources(); + this.adsCall.on('data', (message: DiscoveryResponse__Output) => { + this.handleAdsResponse(message); + }); + this.adsCall.on('status', (status: StatusObject) => { + this.handleAdsCallStatus(status); + }); + this.adsCall.on('error', () => {}); + trace('Started ADS stream'); + // Backoff relative to when we start the request + this.adsBackoff.runOnce(); + + const allServiceKinds: AdsServiceKind[] = ['eds', 'cds', 'rds', 'lds']; + for (const service of allServiceKinds) { + const state = this.adsState[service]; + if (state.getResourceNames().length > 0) { + this.updateNames(service); } - this.reportAdsStreamStarted(); } + this.reportAdsStreamStarted(); } private maybeSendAdsMessage(typeUrl: string, resourceNames: string[], responseNonce: string, versionInfo: string, errorMessage?: string) { - if (this.apiVersion === XdsApiVersion.V2) { - this.adsCallV2?.write({ - node: this.adsNodeV2!, - type_url: typeUrl, - resource_names: resourceNames, - response_nonce: responseNonce, - version_info: versionInfo, - error_detail: errorMessage ? { message: errorMessage } : undefined - }); - } else { - this.adsCallV3?.write({ - node: this.adsNodeV3!, - type_url: typeUrl, - resource_names: resourceNames, - response_nonce: responseNonce, - version_info: versionInfo, - error_detail: errorMessage ? { message: errorMessage } : undefined - }); - } + this.adsCall?.write({ + node: this.adsNode!, + type_url: typeUrl, + resource_names: resourceNames, + response_nonce: responseNonce, + version_info: versionInfo, + error_detail: errorMessage ? { message: errorMessage } : undefined + }); } private getTypeUrl(serviceKind: AdsServiceKind): AdsTypeUrl { - if (this.apiVersion === XdsApiVersion.V2) { - switch (serviceKind) { - case 'eds': - return EDS_TYPE_URL_V2; - case 'cds': - return CDS_TYPE_URL_V2; - case 'rds': - return RDS_TYPE_URL_V2; - case 'lds': - return LDS_TYPE_URL_V2; - } - } else { - switch (serviceKind) { - case 'eds': - return EDS_TYPE_URL_V3; - case 'cds': - return CDS_TYPE_URL_V3; - case 'rds': - return RDS_TYPE_URL_V3; - case 'lds': - return LDS_TYPE_URL_V3; - } + switch (serviceKind) { + case 'eds': + return EDS_TYPE_URL; + case 'cds': + return CDS_TYPE_URL; + case 'rds': + return RDS_TYPE_URL; + case 'lds': + return LDS_TYPE_URL; } } @@ -708,20 +564,16 @@ export class XdsClient { let versionInfo: string; let serviceKind: AdsServiceKind | null; switch (typeUrl) { - case EDS_TYPE_URL_V2: - case EDS_TYPE_URL_V3: + case EDS_TYPE_URL: serviceKind = 'eds'; break; - case CDS_TYPE_URL_V2: - case CDS_TYPE_URL_V3: + case CDS_TYPE_URL: serviceKind = 'cds'; break; - case RDS_TYPE_URL_V2: - case RDS_TYPE_URL_V3: + case RDS_TYPE_URL: serviceKind = 'rds'; break; - case LDS_TYPE_URL_V2: - case LDS_TYPE_URL_V3: + case LDS_TYPE_URL: serviceKind = 'lds'; break; default: @@ -731,7 +583,7 @@ export class XdsClient { if (serviceKind) { this.adsState[serviceKind].reportStreamError({ code: status.UNAVAILABLE, - details: message + ' Node ID=' + this.adsNodeV3!.id, + details: message + ' Node ID=' + this.adsNode!.id, metadata: new Metadata() }); resourceNames = this.adsState[serviceKind].getResourceNames(); @@ -750,19 +602,15 @@ export class XdsClient { this.adsState.cds.getResourceNames().length === 0 && this.adsState.rds.getResourceNames().length === 0 && this.adsState.lds.getResourceNames().length === 0) { - this.adsCallV2?.end(); - this.adsCallV2 = null; - this.adsCallV3?.end(); - this.adsCallV3 = null; - this.lrsCallV2?.end(); - this.lrsCallV2 = null; - this.lrsCallV3?.end(); - this.lrsCallV3 = null; + this.adsCall?.end(); + this.adsCall = null; + this.lrsCall?.end(); + this.lrsCall = null; return; } this.maybeStartAdsStream(); this.maybeStartLrsStream(); - if (!this.adsCallV2 && !this.adsCallV3) { + if (!this.adsCall) { /* If the stream is not set up yet at this point, shortcut the rest * becuase nothing will actually be sent. This would mainly happen if * the bootstrap file has not been read yet. In that case, the output @@ -776,7 +624,7 @@ export class XdsClient { } private reportStreamError(status: StatusObject) { - status = {...status, details: status.details + ' Node ID=' + this.adsNodeV3!.id}; + status = {...status, details: status.details + ' Node ID=' + this.adsNode!.id}; this.adsState.eds.reportStreamError(status); this.adsState.cds.reportStreamError(status); this.adsState.rds.reportStreamError(status); @@ -823,8 +671,7 @@ export class XdsClient { trace( 'LRS stream ended. code=' + streamStatus.code + ' details= ' + streamStatus.details ); - this.lrsCallV2 = null; - this.lrsCallV3 = null; + this.lrsCall = null; clearInterval(this.statsTimer); /* If the backoff timer is no longer running, we do not need to wait any * more to start the new call. */ @@ -833,41 +680,22 @@ export class XdsClient { } } - private maybeStartLrsStreamV2(): boolean { - if (!this.lrsClientV2) { - return false; - } - if (this.lrsCallV2) { - return false; - } - this.lrsCallV2 = this.lrsClientV2.streamLoadStats(); - this.receivedLrsSettingsForCurrentStream = false; - this.lrsCallV2.on('data', (message: LoadStatsResponse__Output) => { - this.handleLrsResponse(message); - }); - this.lrsCallV2.on('status', (status: StatusObject) => { - this.handleLrsCallStatus(status); - }); - this.lrsCallV2.on('error', () => {}); - return true; - } - private maybeStartLrsStreamV3(): boolean { - if (!this.lrsClientV3) { + if (!this.lrsClient) { return false; } - if (this.lrsCallV3) { + if (this.lrsCall) { return false; } - this.lrsCallV3 = this.lrsClientV3.streamLoadStats(); + this.lrsCall = this.lrsClient.streamLoadStats(); this.receivedLrsSettingsForCurrentStream = false; - this.lrsCallV3.on('data', (message: LoadStatsResponse__Output) => { + this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { this.handleLrsResponse(message); }); - this.lrsCallV3.on('status', (status: StatusObject) => { + this.lrsCall.on('status', (status: StatusObject) => { this.handleLrsCallStatus(status); }); - this.lrsCallV3.on('error', () => {}); + this.lrsCall.on('error', () => {}); return true; } @@ -881,39 +709,37 @@ export class XdsClient { this.adsState.lds.getResourceNames().length === 0) { return; } - - let streamStarted: boolean; - if (this.apiVersion === XdsApiVersion.V2) { - streamStarted = this.maybeStartLrsStreamV2(); - } else { - streamStarted = this.maybeStartLrsStreamV3(); + if (!this.lrsClient) { + return; } - - if (streamStarted) { - trace('Starting LRS stream'); - this.lrsBackoff.runOnce(); - /* Send buffered stats information when starting LRS stream. If there is no - * buffered stats information, it will still send the node field. */ - this.sendStats(); + if (this.lrsCall) { + return; } + this.lrsCall = this.lrsClient.streamLoadStats(); + this.receivedLrsSettingsForCurrentStream = false; + this.lrsCall.on('data', (message: LoadStatsResponse__Output) => { + this.handleLrsResponse(message); + }); + this.lrsCall.on('status', (status: StatusObject) => { + this.handleLrsCallStatus(status); + }); + this.lrsCall.on('error', () => {}); + trace('Starting LRS stream'); + this.lrsBackoff.runOnce(); + /* Send buffered stats information when starting LRS stream. If there is no + * buffered stats information, it will still send the node field. */ + this.sendStats(); } private maybeSendLrsMessage(clusterStats: ClusterStats[]) { - if (this.apiVersion === XdsApiVersion.V2) { - this.lrsCallV2?.write({ - node: this.lrsNodeV2!, - cluster_stats: clusterStats - }); - } else { - this.lrsCallV3?.write({ - node: this.lrsNodeV3!, - cluster_stats: clusterStats - }); - } + this.lrsCall?.write({ + node: this.lrsNode!, + cluster_stats: clusterStats + }); } private sendStats() { - if (this.lrsCallV2 === null && this.lrsCallV3 === null) { + if (this.lrsCall === null) { return; } if (!this.latestLrsSettings) { @@ -1121,14 +947,10 @@ export class XdsClient { } private shutdown(): void { - this.adsCallV2?.cancel(); - this.adsCallV3?.cancel(); - this.adsClientV2?.close(); - this.adsClientV3?.close(); - this.lrsCallV2?.cancel(); - this.lrsCallV3?.cancel(); - this.lrsClientV2?.close(); - this.lrsClientV3?.close(); + this.adsCall?.cancel(); + this.adsClient?.close(); + this.lrsCall?.cancel(); + this.lrsClient?.close(); this.hasShutdown = true; } } diff --git a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts index bd5b6423f..c215076db 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/lds-state.ts @@ -19,7 +19,7 @@ import { experimental, logVerbosity } from "@grpc/grpc-js"; import { Listener__Output } from '../generated/envoy/config/listener/v3/Listener'; import { RdsState } from "./rds-state"; import { BaseXdsStreamState, XdsStreamState } from "./xds-stream-state"; -import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL_V2, HTTP_CONNECTION_MANGER_TYPE_URL_V3 } from '../resources'; +import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL } from '../resources'; import { getTopLevelFilterUrl, validateTopLevelFilter } from '../http-filter'; import { EXPERIMENTAL_FAULT_INJECTION } from '../environment'; @@ -46,18 +46,17 @@ export class LdsState extends BaseXdsStreamState implements Xd super(updateResourceNames); } - public validateResponse(message: Listener__Output, isV2: boolean): boolean { + public validateResponse(message: Listener__Output): boolean { if ( !( message.api_listener?.api_listener && - (message.api_listener.api_listener.type_url === HTTP_CONNECTION_MANGER_TYPE_URL_V2 || - message.api_listener.api_listener.type_url === HTTP_CONNECTION_MANGER_TYPE_URL_V3) + message.api_listener.api_listener.type_url === HTTP_CONNECTION_MANGER_TYPE_URL ) ) { return false; } - const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL_V3, message.api_listener!.api_listener.value); - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL, message.api_listener!.api_listener.value); + if (EXPERIMENTAL_FAULT_INJECTION) { const filterNames = new Set(); for (const [index, httpFilter] of httpConnectionManager.http_filters.entries()) { if (filterNames.has(httpFilter.name)) { @@ -89,7 +88,7 @@ export class LdsState extends BaseXdsStreamState implements Xd case 'rds': return !!httpConnectionManager.rds?.config_source?.ads; case 'route_config': - return this.rdsState.validateResponse(httpConnectionManager.route_config!, isV2); + return this.rdsState.validateResponse(httpConnectionManager.route_config!); } return false; } diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index a5d3c47cf..119ac6b92 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -40,7 +40,7 @@ export class RdsState extends BaseXdsStreamState imp protected getProtocolName(): string { return 'RDS'; } - validateResponse(message: RouteConfiguration__Output, isV2: boolean): boolean { + validateResponse(message: RouteConfiguration__Output): boolean { // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation for (const virtualHost of message.virtual_hosts) { for (const domainPattern of virtualHost.domains) { @@ -55,7 +55,7 @@ export class RdsState extends BaseXdsStreamState imp return false; } } - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const filterConfig of Object.values(virtualHost.typed_per_filter_config ?? {})) { if (!validateOverrideFilter(filterConfig)) { return false; @@ -81,7 +81,7 @@ export class RdsState extends BaseXdsStreamState imp if ((route.route === undefined) || (route.route === null) || SUPPORTED_CLUSTER_SPECIFIERS.indexOf(route.route.cluster_specifier) < 0) { return false; } - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const [name, filterConfig] of Object.entries(route.typed_per_filter_config ?? {})) { if (!validateOverrideFilter(filterConfig)) { return false; @@ -99,7 +99,7 @@ export class RdsState extends BaseXdsStreamState imp if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { return false; } - if (!isV2 && EXPERIMENTAL_FAULT_INJECTION) { + if (EXPERIMENTAL_FAULT_INJECTION) { for (const weightedCluster of route.route!.weighted_clusters!.clusters) { for (const filterConfig of Object.values(weightedCluster.typed_per_filter_config ?? {})) { if (!validateOverrideFilter(filterConfig)) { diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 7b3bc0189..86c2cea4b 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -26,7 +26,7 @@ export interface Watcher { * message type into a library-specific configuration object type, to * remove a lot of duplicate logic, including logic for handling that * flag. */ - onValidUpdate(update: UpdateType, isV2: boolean): void; + onValidUpdate(update: UpdateType): void; onTransientError(error: StatusObject): void; onResourceDoesNotExist(): void; } @@ -85,7 +85,6 @@ export abstract class BaseXdsStreamState implements XdsStreamState nonce = ''; private subscriptions: Map> = new Map>(); - private latestIsV2 = false; private isAdsStreamRunning = false; private ignoreResourceDeletion = false; @@ -128,7 +127,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState * the same happens here */ process.nextTick(() => { this.trace('Reporting existing update for new watcher for name ' + name); - watcher.onValidUpdate(cachedResponse, this.latestIsV2); + watcher.onValidUpdate(cachedResponse); }); } if (addedName) { @@ -157,7 +156,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState getResourceNames(): string[] { return Array.from(this.subscriptions.keys()); } - handleResponses(responses: ResourcePair[], isV2: boolean): HandleResponseResult { + handleResponses(responses: ResourcePair[]): HandleResponseResult { const validResponses: ResponseType[] = []; let result: HandleResponseResult = { accepted: [], @@ -166,7 +165,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState } for (const {resource, raw} of responses) { const resourceName = this.getResourceName(resource); - if (this.validateResponse(resource, isV2)) { + if (this.validateResponse(resource)) { validResponses.push(resource); result.accepted.push({ name: resourceName, @@ -180,7 +179,6 @@ export abstract class BaseXdsStreamState implements XdsStreamState }); } } - this.latestIsV2 = isV2; const allResourceNames = new Set(); for (const resource of validResponses) { const resourceName = this.getResourceName(resource); @@ -189,7 +187,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState if (subscriptionEntry) { const watchers = subscriptionEntry.watchers; for (const watcher of watchers) { - watcher.onValidUpdate(resource, isV2); + watcher.onValidUpdate(resource); } clearTimeout(subscriptionEntry.resourceTimer); subscriptionEntry.cachedResponse = resource; @@ -259,9 +257,8 @@ export abstract class BaseXdsStreamState implements XdsStreamState * This function is public so that the LDS validateResponse can call into * the RDS validateResponse. * @param resource The resource object sent by the xDS server - * @param isV2 If true, the resource is an xDS V2 resource instead of xDS V3 */ - public abstract validateResponse(resource: ResponseType, isV2: boolean): boolean; + public abstract validateResponse(resource: ResponseType): boolean; /** * Get the name of a resource object. The name is some field of the object, so * getting it depends on the specific type. From 75a6d0a24b01d18448f72dc6df3a4e1de497d333 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 14 Oct 2022 09:45:57 -0700 Subject: [PATCH 1777/1899] grpc-js: Handle the grpc-node.max_session_memory option consistently on the client and server --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/server.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index c0db93ae0..087060154 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.7.1", + "version": "1.7.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 974c3dfc6..499fde4a3 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -346,6 +346,12 @@ export class Server { serverOptions.maxSessionMemory = this.options[ 'grpc-node.max_session_memory' ]; + } else { + /* By default, set a very large max session memory limit, to effectively + * disable enforcement of the limit. Some testing indicates that Node's + * behavior degrades badly when this limit is reached, so we solve that + * by disabling the check entirely. */ + serverOptions.maxSessionMemory = Number.MAX_SAFE_INTEGER; } if ('grpc.max_concurrent_streams' in this.options) { serverOptions.settings = { From 59a2cbceeb288b0967dca7daafee254292bc0e1a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 14 Oct 2022 10:27:38 -0700 Subject: [PATCH 1778/1899] grpc-js: Remove redundant calls to setCredentials --- packages/grpc-js/src/client-interceptors.ts | 8 -------- packages/grpc-js/src/client.ts | 12 ------------ 2 files changed, 20 deletions(-) diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index 52320b0b3..d9c88f448 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -198,8 +198,6 @@ export interface InterceptingCallInterface { sendMessage(message: any): void; startRead(): void; halfClose(): void; - - setCredentials(credentials: CallCredentials): void; } export class InterceptingCall implements InterceptingCallInterface { @@ -337,9 +335,6 @@ export class InterceptingCall implements InterceptingCallInterface { } }); } - setCredentials(credentials: CallCredentials): void { - this.nextCall.setCredentials(credentials); - } } function getCall(channel: Channel, path: string, options: CallOptions): Call { @@ -371,9 +366,6 @@ class BaseInterceptingCall implements InterceptingCallInterface { getPeer(): string { return this.call.getPeer(); } - setCredentials(credentials: CallCredentials): void { - this.call.setCredentials(credentials); - } // eslint-disable-next-line @typescript-eslint/no-explicit-any sendMessageWithContext(context: MessageContext, message: any): void { let serialized: Buffer; diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index d97c9fa3f..f96f8fdf0 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -321,9 +321,6 @@ export class Client { * before calling the CallInvocationTransformer, and we need to create the * call after that. */ emitter.call = call; - if (callProperties.callOptions.credentials) { - call.setCredentials(callProperties.callOptions.credentials); - } let responseMessage: ResponseType | null = null; let receivedStatus = false; const callerStackError = new Error(); @@ -449,9 +446,6 @@ export class Client { * before calling the CallInvocationTransformer, and we need to create the * call after that. */ emitter.call = call; - if (callProperties.callOptions.credentials) { - call.setCredentials(callProperties.callOptions.credentials); - } let responseMessage: ResponseType | null = null; let receivedStatus = false; const callerStackError = new Error(); @@ -582,9 +576,6 @@ export class Client { * before calling the CallInvocationTransformer, and we need to create the * call after that. */ stream.call = call; - if (callProperties.callOptions.credentials) { - call.setCredentials(callProperties.callOptions.credentials); - } let receivedStatus = false; const callerStackError = new Error(); call.start(callProperties.metadata, { @@ -681,9 +672,6 @@ export class Client { * before calling the CallInvocationTransformer, and we need to create the * call after that. */ stream.call = call; - if (callProperties.callOptions.credentials) { - call.setCredentials(callProperties.callOptions.credentials); - } let receivedStatus = false; const callerStackError = new Error(); call.start(callProperties.metadata, { From 63d9f6a6d68ceef57e72f02e37c91d140ae32196 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 14 Oct 2022 11:18:26 -0700 Subject: [PATCH 1779/1899] Ensure ordering between received messages and status --- packages/grpc-js/src/load-balancing-call.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index 36af8b683..73c1fa9fd 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -44,6 +44,8 @@ export class LoadBalancingCall implements Call { private writeFilterPending = false; private pendingMessage: {context: MessageContext, message: Buffer} | null = null; private pendingHalfClose = false; + private readFilterPending = false; + private pendingChildStatus: StatusObject | null = null; private ended = false; private serviceUrl: string; private filterStack: FilterStack; @@ -153,14 +155,23 @@ export class LoadBalancingCall implements Call { this.listener!.onReceiveMetadata(this.filterStack.receiveMetadata(metadata)); }, onReceiveMessage: message => { + this.readFilterPending = true; this.filterStack.receiveMessage(message).then(filteredMesssage => { + this.readFilterPending = false; this.listener!.onReceiveMessage(filteredMesssage); + if (this.pendingChildStatus) { + this.outputStatus(this.pendingChildStatus, 'PROCESSED'); + } }, (status: StatusObject) => { this.cancelWithStatus(status.code, status.details); }); }, onReceiveStatus: status => { - this.outputStatus(status, 'PROCESSED'); + if (this.readFilterPending) { + this.pendingChildStatus = status; + } else { + this.outputStatus(status, 'PROCESSED'); + } } }); } catch (error) { From 955f088379829cc362496b10e992ab0d1f8c591c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 14 Oct 2022 11:46:32 -0700 Subject: [PATCH 1780/1899] grpc-js: Test against actively maintained Node versions --- run-tests.bat | 6 +++--- run-tests.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 3b0aa07d0..4262f2844 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -28,8 +28,8 @@ SET JOBS=8 call nvm version -call nvm install 10 -call nvm use 10 +call nvm install 18 +call nvm use 18 git submodule update --init --recursive @@ -40,7 +40,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (10 12) do ( +for %%v in (14 16 18) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index 4bcb388b4..b2e8f6a4e 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -28,7 +28,7 @@ cd $ROOT git submodule update --init --recursive if [ ! -n "$node_versions" ] ; then - node_versions="10 12 14 16" + node_versions="14 16 18" fi set +ex From 276b7b66d020314562000f9fa905e860b7e360c3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 14 Oct 2022 13:29:57 -0700 Subject: [PATCH 1781/1899] grpc-js-xds: Fix limit representation for priority weight validation --- packages/grpc-js-xds/src/xds-stream-state/eds-state.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index 9b7b9cd5f..cec6a4764 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -25,6 +25,8 @@ import { BaseXdsStreamState, HandleResponseResult, RejectedResourceEntry, Resour const TRACER_NAME = 'xds_client'; +const UINT32_MAX = 0xFFFFFFFF; + function trace(text: string): void { experimental.trace(logVerbosity.DEBUG, TRACER_NAME, text); } @@ -88,7 +90,7 @@ export class EdsState extends BaseXdsStreamState priorityTotalWeights.set(endpoint.priority, (priorityTotalWeights.get(endpoint.priority) ?? 0) + (endpoint.load_balancing_weight?.value ?? 0)); } for (const totalWeight of priorityTotalWeights.values()) { - if (totalWeight >= 1<<32) { + if (totalWeight > UINT32_MAX) { return false; } } From 223bf8f4b04bdb412b55bc14146f86c228a682f7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 17 Oct 2022 10:11:38 -0700 Subject: [PATCH 1782/1899] Don't test on Node 18 yet --- run-tests.bat | 6 +++--- run-tests.sh | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/run-tests.bat b/run-tests.bat index 4262f2844..6b94b78de 100644 --- a/run-tests.bat +++ b/run-tests.bat @@ -28,8 +28,8 @@ SET JOBS=8 call nvm version -call nvm install 18 -call nvm use 18 +call nvm install 16 +call nvm use 16 git submodule update --init --recursive @@ -40,7 +40,7 @@ call npm install || goto :error SET JUNIT_REPORT_STACK=1 SET FAILED=0 -for %%v in (14 16 18) do ( +for %%v in (14 16) do ( call nvm install %%v call nvm use %%v if "%%v"=="4" ( diff --git a/run-tests.sh b/run-tests.sh index b2e8f6a4e..0adcc0f17 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -28,7 +28,7 @@ cd $ROOT git submodule update --init --recursive if [ ! -n "$node_versions" ] ; then - node_versions="14 16 18" + node_versions="14 16" fi set +ex From c4c321d37dfca78a5b97f433652147628fa43186 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 17 Oct 2022 11:32:22 -0700 Subject: [PATCH 1783/1899] grpc-js: Handle filters in ResolvingCall instead of LoadBalancingCall --- packages/grpc-js/src/internal-channel.ts | 2 +- packages/grpc-js/src/load-balancing-call.ts | 59 +++---------- packages/grpc-js/src/resolving-call.ts | 96 +++++++++++++++------ 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 2a775e7d8..16f4b9832 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -402,7 +402,7 @@ export class InternalChannel { method + '"' ); - return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, this.filterStackFactory, callNumber); + return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, callNumber); } createInnerCall( diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index 73c1fa9fd..6faa15592 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -41,14 +41,11 @@ export interface StatusObjectWithProgress extends StatusObject { export class LoadBalancingCall implements Call { private child: SubchannelCall | null = null; private readPending = false; - private writeFilterPending = false; private pendingMessage: {context: MessageContext, message: Buffer} | null = null; private pendingHalfClose = false; - private readFilterPending = false; private pendingChildStatus: StatusObject | null = null; private ended = false; private serviceUrl: string; - private filterStack: FilterStack; private metadata: Metadata | null = null; private listener: InterceptingListener | null = null; private onCallEnded: ((statusCode: Status) => void) | null = null; @@ -59,11 +56,8 @@ export class LoadBalancingCall implements Call { private readonly host : string, private readonly credentials: CallCredentials, private readonly deadline: Deadline, - filterStackFactory: FilterStackFactory, private readonly callNumber: number ) { - this.filterStack = filterStackFactory.createFilter(); - const splitPath: string[] = this.methodName.split('/'); let serviceName = ''; /* The standard path format is "/{serviceName}/{methodName}", so if we split @@ -90,8 +84,7 @@ export class LoadBalancingCall implements Call { if (!this.ended) { this.ended = true; this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); - const filteredStatus = this.filterStack.receiveTrailers(status); - const finalStatus = {...filteredStatus, progress}; + const finalStatus = {...status, progress}; this.listener?.onReceiveStatus(finalStatus); this.onCallEnded?.(finalStatus.code); } @@ -152,26 +145,13 @@ export class LoadBalancingCall implements Call { try { this.child = pickResult.subchannel!.getRealSubchannel().createCall(finalMetadata, this.host, this.methodName, { onReceiveMetadata: metadata => { - this.listener!.onReceiveMetadata(this.filterStack.receiveMetadata(metadata)); + this.listener!.onReceiveMetadata(metadata); }, onReceiveMessage: message => { - this.readFilterPending = true; - this.filterStack.receiveMessage(message).then(filteredMesssage => { - this.readFilterPending = false; - this.listener!.onReceiveMessage(filteredMesssage); - if (this.pendingChildStatus) { - this.outputStatus(this.pendingChildStatus, 'PROCESSED'); - } - }, (status: StatusObject) => { - this.cancelWithStatus(status.code, status.details); - }); + this.listener!.onReceiveMessage(message); }, onReceiveStatus: status => { - if (this.readFilterPending) { - this.pendingChildStatus = status; - } else { - this.outputStatus(status, 'PROCESSED'); - } + this.outputStatus(status, 'PROCESSED'); } }); } catch (error) { @@ -201,7 +181,7 @@ export class LoadBalancingCall implements Call { if (this.pendingMessage) { this.child.sendMessageWithContext(this.pendingMessage.context, this.pendingMessage.message); } - if (this.pendingHalfClose && !this.writeFilterPending) { + if (this.pendingHalfClose) { this.child.halfClose(); } }, (error: Error & { code: number }) => { @@ -249,29 +229,16 @@ export class LoadBalancingCall implements Call { start(metadata: Metadata, listener: InterceptingListener): void { this.trace('start called'); this.listener = listener; - this.filterStack.sendMetadata(Promise.resolve(metadata)).then(filteredMetadata => { - this.metadata = filteredMetadata; - this.doPick(); - }, (status: StatusObject) => { - this.outputStatus(status, 'PROCESSED'); - }); + this.metadata = metadata; + this.doPick(); } sendMessageWithContext(context: MessageContext, message: Buffer): void { this.trace('write() called with message of length ' + message.length); - this.writeFilterPending = true; - this.filterStack.sendMessage(Promise.resolve({message: message, flags: context.flags})).then((filteredMessage) => { - this.writeFilterPending = false; - if (this.child) { - this.child.sendMessageWithContext(context, filteredMessage.message); - if (this.pendingHalfClose) { - this.child.halfClose(); - } - } else { - this.pendingMessage = {context, message: filteredMessage.message}; - } - }, (status: StatusObject) => { - this.cancelWithStatus(status.code, status.details); - }) + if (this.child) { + this.child.sendMessageWithContext(context, message); + } else { + this.pendingMessage = {context, message}; + } } startRead(): void { this.trace('startRead called'); @@ -283,7 +250,7 @@ export class LoadBalancingCall implements Call { } halfClose(): void { this.trace('halfClose called'); - if (this.child && !this.writeFilterPending) { + if (this.child) { this.child.halfClose(); } else { this.pendingHalfClose = true; diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index 76a7bd208..f2e5741fa 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -19,7 +19,7 @@ import { CallCredentials } from "./call-credentials"; import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from "./call-interface"; import { LogVerbosity, Propagate, Status } from "./constants"; import { Deadline, getDeadlineTimeoutString, getRelativeTimeout, minDeadline } from "./deadline"; -import { FilterStackFactory } from "./filter-stack"; +import { FilterStack, FilterStackFactory } from "./filter-stack"; import { InternalChannel } from "./internal-channel"; import { Metadata } from "./metadata"; import * as logging from './logging'; @@ -33,12 +33,16 @@ export class ResolvingCall implements Call { private pendingMessage: {context: MessageContext, message: Buffer} | null = null; private pendingHalfClose = false; private ended = false; + private readFilterPending = false; + private writeFilterPending = false; + private pendingChildStatus: StatusObject | null = null; private metadata: Metadata | null = null; private listener: InterceptingListener | null = null; private deadline: Deadline; private host: string; private statusWatchers: ((status: StatusObject) => void)[] = []; private deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + private filterStack: FilterStack | null = null; constructor( private readonly channel: InternalChannel, @@ -96,14 +100,35 @@ export class ResolvingCall implements Call { private outputStatus(status: StatusObject) { if (!this.ended) { this.ended = true; - this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); - this.statusWatchers.forEach(watcher => watcher(status)); + if (!this.filterStack) { + this.filterStack = this.filterStackFactory.createFilter(); + } + const filteredStatus = this.filterStack.receiveTrailers(status); + this.trace('ended with status: code=' + filteredStatus.code + ' details="' + filteredStatus.details + '"'); + this.statusWatchers.forEach(watcher => watcher(filteredStatus)); process.nextTick(() => { - this.listener?.onReceiveStatus(status); + this.listener?.onReceiveStatus(filteredStatus); }); } } + private sendMessageOnChild(context: MessageContext, message: Buffer): void { + if (!this.child) { + throw new Error('sendMessageonChild called with child not populated'); + } + const child = this.child; + this.writeFilterPending = true; + this.filterStack!.sendMessage(Promise.resolve({message: message, flags: context.flags})).then((filteredMessage) => { + this.writeFilterPending = false; + child.sendMessageWithContext(context, filteredMessage.message); + if (this.pendingHalfClose) { + child.halfClose(); + } + }, (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + }); + } + getConfig(): void { if (this.ended) { return; @@ -148,29 +173,46 @@ export class ResolvingCall implements Call { } this.filterStackFactory.push(config.dynamicFilterFactories); - - this.child = this.channel.createInnerCall(config, this.method, this.host, this.credentials, this.deadline); - this.child.start(this.metadata, { - onReceiveMetadata: metadata => { - this.listener!.onReceiveMetadata(metadata); - }, - onReceiveMessage: message => { - this.listener!.onReceiveMessage(message); - }, - onReceiveStatus: status => { - this.outputStatus(status); + this.filterStack = this.filterStackFactory.createFilter(); + this.filterStack.sendMetadata(Promise.resolve(this.metadata)).then(filteredMetadata => { + this.child = this.channel.createInnerCall(config, this.method, this.host, this.credentials, this.deadline); + this.child.start(filteredMetadata, { + onReceiveMetadata: metadata => { + this.listener!.onReceiveMetadata(this.filterStack!.receiveMetadata(metadata)); + }, + onReceiveMessage: message => { + this.readFilterPending = true; + this.filterStack!.receiveMessage(message).then(filteredMesssage => { + this.readFilterPending = false; + this.listener!.onReceiveMessage(filteredMesssage); + if (this.pendingChildStatus) { + this.outputStatus(this.pendingChildStatus); + } + }, (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + }); + }, + onReceiveStatus: status => { + if (this.readFilterPending) { + this.pendingChildStatus = status; + } else { + this.outputStatus(status); + } + } + }); + if (this.readPending) { + this.child.startRead(); } - }); - if (this.readPending) { - this.child.startRead(); - } - if (this.pendingMessage) { - this.child.sendMessageWithContext(this.pendingMessage.context, this.pendingMessage.message); - } - if (this.pendingHalfClose) { - this.child.halfClose(); - } + if (this.pendingMessage) { + this.sendMessageOnChild(this.pendingMessage.context, this.pendingMessage.message); + } else if (this.pendingHalfClose) { + this.child.halfClose(); + } + }, (status: StatusObject) => { + this.outputStatus(status); + }) } + reportResolverError(status: StatusObject) { if (this.metadata?.getOptions().waitForReady) { this.channel.queueCallForConfig(this); @@ -195,7 +237,7 @@ export class ResolvingCall implements Call { sendMessageWithContext(context: MessageContext, message: Buffer): void { this.trace('write() called with message of length ' + message.length); if (this.child) { - this.child.sendMessageWithContext(context, message); + this.sendMessageOnChild(context, message); } else { this.pendingMessage = {context, message}; } @@ -210,7 +252,7 @@ export class ResolvingCall implements Call { } halfClose(): void { this.trace('halfClose called'); - if (this.child) { + if (this.child && !this.writeFilterPending) { this.child.halfClose(); } else { this.pendingHalfClose = true; From 24c4cd7bb81c983fb9bde4e62d66493a02733cdc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 18 Oct 2022 16:29:22 -0700 Subject: [PATCH 1784/1899] grpc-js: Add more outlier detection tests and tracing --- .../src/load-balancer-outlier-detection.ts | 4 +- .../grpc-js/test/test-outlier-detection.ts | 169 ++++++++++++++++++ 2 files changed, 172 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 1f1710e75..cdf580523 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -423,9 +423,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { const targetRequestVolume = successRateConfig.request_volume; let addresesWithTargetVolume = 0; const successRates: number[] = [] - for (const mapEntry of this.addressMap.values()) { + for (const [address, mapEntry] of this.addressMap) { const successes = mapEntry.counter.getLastSuccesses(); const failures = mapEntry.counter.getLastFailures(); + trace('Stats for ' + address + ': successes=' + successes + ' failures=' + failures + ' targetRequestVolume=' + targetRequestVolume); if (successes + failures >= targetRequestVolume) { addresesWithTargetVolume += 1; successRates.push(successes/(successes + failures)); @@ -545,6 +546,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { private startTimer(delayMs: number) { this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs); + this.ejectionTimer.unref?.(); } private runChecks() { diff --git a/packages/grpc-js/test/test-outlier-detection.ts b/packages/grpc-js/test/test-outlier-detection.ts index 74e536767..c9021e605 100644 --- a/packages/grpc-js/test/test-outlier-detection.ts +++ b/packages/grpc-js/test/test-outlier-detection.ts @@ -20,6 +20,7 @@ import * as path from 'path'; import * as grpc from '../src'; import { loadProtoFile } from './common'; import { OutlierDetectionLoadBalancingConfig } from '../src/load-balancer-outlier-detection' +import { ServiceClient } from '../src/make-client'; function multiDone(done: Mocha.Done, target: number) { let count = 0; @@ -49,6 +50,54 @@ const defaultOutlierDetectionServiceConfig = { const defaultOutlierDetectionServiceConfigString = JSON.stringify(defaultOutlierDetectionServiceConfig); +const successRateOutlierDetectionServiceConfig = { + methodConfig: [], + loadBalancingConfig: [ + { + outlier_detection: { + interval: { + seconds: 1, + nanos: 0 + }, + base_ejection_time: { + seconds: 3, + nanos: 0 + }, + success_rate_ejection: { + request_volume: 5 + }, + child_policy: [{round_robin: {}}] + } + } + ] +}; + +const successRateOutlierDetectionServiceConfigString = JSON.stringify(successRateOutlierDetectionServiceConfig); + +const failurePercentageOutlierDetectionServiceConfig = { + methodConfig: [], + loadBalancingConfig: [ + { + outlier_detection: { + interval: { + seconds: 1, + nanos: 0 + }, + base_ejection_time: { + seconds: 3, + nanos: 0 + }, + failure_percentage_ejection: { + request_volume: 5 + }, + child_policy: [{round_robin: {}}] + } + } + ] +}; + +const falurePercentageOutlierDetectionServiceConfigString = JSON.stringify(failurePercentageOutlierDetectionServiceConfig); + const goodService = { echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { callback(null, call.request) @@ -353,6 +402,20 @@ describe('Outlier detection', () => { badServer.forceShutdown(); }); + function makeManyRequests(makeOneRequest: (callback: (error?: Error) => void) => void, total: number, callback: (error?: Error) => void) { + if (total === 0) { + callback(); + return; + } + makeOneRequest(error => { + if (error) { + callback(error); + return; + } + makeManyRequests(makeOneRequest, total - 1, callback); + }); + } + it('Should allow normal operation with one server', done => { const client = new EchoService(`localhost:${goodPorts[0]}`, grpc.credentials.createInsecure(), {'grpc.service_config': defaultOutlierDetectionServiceConfigString}); client.echo( @@ -364,4 +427,110 @@ describe('Outlier detection', () => { } ); }); + describe('Success rate', () => { + let makeCheckedRequest: (callback: () => void) => void; + let makeUncheckedRequest:(callback: (error?: Error) => void) => void; + before(() => { + const target = 'ipv4:///' + goodPorts.map(port => `127.0.0.1:${port}`).join(',') + `,127.0.0.1:${badPort}`; + const client = new EchoService(target, grpc.credentials.createInsecure(), {'grpc.service_config': successRateOutlierDetectionServiceConfigString}); + makeUncheckedRequest = (callback: () => void) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + callback(); + } + ); + }; + makeCheckedRequest = (callback: (error?: Error) => void) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + callback(error); + } + ); + }; + }); + it('Should eject a server if it is failing requests', done => { + // Make a large volume of requests + makeManyRequests(makeUncheckedRequest, 50, () => { + // Give outlier detection time to run ejection checks + setTimeout(() => { + // Make enough requests to go around all servers + makeManyRequests(makeCheckedRequest, 10, done); + }, 1000); + }); + }); + it('Should uneject a server after the ejection period', function(done) { + this.timeout(5000); + makeManyRequests(makeUncheckedRequest, 50, () => { + setTimeout(() => { + makeManyRequests(makeCheckedRequest, 10, error => { + if (error) { + done(error); + return; + } + setTimeout(() => { + makeManyRequests(makeCheckedRequest, 10, error => { + assert(error); + done(); + }); + }, 3000); + }); + }, 1000); + }) + }); + }); + describe('Failure percentage', () => { + let makeCheckedRequest: (callback: () => void) => void; + let makeUncheckedRequest:(callback: (error?: Error) => void) => void; + before(() => { + const target = 'ipv4:///' + goodPorts.map(port => `127.0.0.1:${port}`).join(',') + `,127.0.0.1:${badPort}`; + const client = new EchoService(target, grpc.credentials.createInsecure(), {'grpc.service_config': falurePercentageOutlierDetectionServiceConfigString}); + makeUncheckedRequest = (callback: () => void) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + callback(); + } + ); + }; + makeCheckedRequest = (callback: (error?: Error) => void) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + callback(error); + } + ); + }; + }); + it('Should eject a server if it is failing requests', done => { + // Make a large volume of requests + makeManyRequests(makeUncheckedRequest, 50, () => { + // Give outlier detection time to run ejection checks + setTimeout(() => { + // Make enough requests to go around all servers + makeManyRequests(makeCheckedRequest, 10, done); + }, 1000); + }); + }); + it('Should uneject a server after the ejection period', function(done) { + this.timeout(5000); + makeManyRequests(makeUncheckedRequest, 50, () => { + setTimeout(() => { + makeManyRequests(makeCheckedRequest, 10, error => { + if (error) { + done(error); + return; + } + setTimeout(() => { + makeManyRequests(makeCheckedRequest, 10, error => { + assert(error); + done(); + }); + }, 3000); + }); + }, 1000); + }) + }); + }); }); \ No newline at end of file From 2f124ad68bfe5d9df1130d7c25ea340a50b87a58 Mon Sep 17 00:00:00 2001 From: AVVS Date: Wed, 19 Oct 2022 14:48:11 -0700 Subject: [PATCH 1785/1899] fix: perf issues in hot paths 1. no unused timers, wrap tracing calls to avoid stringifying 2. track graceful end of the call and avoid emitting 'cancelled' in such cases 3. remove validate calls in metadata on operations where it's not needed 4. refactor server session stream handlers into separate channelz enabled/disabled handlers 5. refactor message request logic - reduce amount of microtasks generated 6. improve sendStatus a little when there is no metadata involved --- packages/grpc-js/src/call-stream.ts | 4 + .../generated/grpc/channelz/v1/Channelz.ts | 104 ++--- packages/grpc-js/src/metadata.ts | 64 ++- packages/grpc-js/src/server-call.ts | 305 +++++++------ packages/grpc-js/src/server.ts | 413 +++++++++++------- 5 files changed, 502 insertions(+), 388 deletions(-) diff --git a/packages/grpc-js/src/call-stream.ts b/packages/grpc-js/src/call-stream.ts index d7151eb6f..488e35fc8 100644 --- a/packages/grpc-js/src/call-stream.ts +++ b/packages/grpc-js/src/call-stream.ts @@ -97,6 +97,10 @@ export interface StatusObject { metadata: Metadata; } +export type PartialStatusObject = Pick & { + metadata: Metadata | null; +} + export const enum WriteFlags { BufferHint = 1, NoCompress = 2, diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts index ace712454..4c8c18aa7 100644 --- a/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts @@ -25,102 +25,102 @@ export interface ChannelzClient extends grpc.Client { /** * Returns a single Channel, or else a NOT_FOUND code. */ - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Server, or else a NOT_FOUND code. */ - GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - GetServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - GetServer(argument: _grpc_channelz_v1_GetServerRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Server, or else a NOT_FOUND code. */ - getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - getServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - getServer(argument: _grpc_channelz_v1_GetServerRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; /** * Gets all server sockets that exist in the process. */ - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; /** * Gets all server sockets that exist in the process. */ - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; /** * Gets all servers that exist in the process. */ - GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - GetServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - GetServers(argument: _grpc_channelz_v1_GetServersRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; /** * Gets all servers that exist in the process. */ - getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - getServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - getServers(argument: _grpc_channelz_v1_GetServersRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Socket or else a NOT_FOUND code. */ - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Socket or else a NOT_FOUND code. */ - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Subchannel, or else a NOT_FOUND code. */ - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Subchannel, or else a NOT_FOUND code. */ - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; /** * Gets all root channels (i.e. channels the application has directly * created). This does not include subchannels nor non-top level channels. */ - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; /** * Gets all root channels (i.e. channels the application has directly * created). This does not include subchannels nor non-top level channels. */ - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; } diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 04db642ef..376cb491a 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -48,13 +48,14 @@ function validate(key: string, value?: MetadataValue): void { if (!isLegalKey(key)) { throw new Error('Metadata key "' + key + '" contains illegal characters'); } + if (value !== null && value !== undefined) { if (isBinaryKey(key)) { - if (!(value instanceof Buffer)) { + if (!Buffer.isBuffer(value)) { throw new Error("keys that end with '-bin' must have Buffer values"); } } else { - if (value instanceof Buffer) { + if (Buffer.isBuffer(value)) { throw new Error( "keys that don't end with '-bin' must have String values" ); @@ -88,12 +89,8 @@ export class Metadata { protected internalRepr: MetadataObject = new Map(); private options: MetadataOptions; - constructor(options?: MetadataOptions) { - if (options === undefined) { - this.options = {}; - } else { - this.options = options; - } + constructor(options: MetadataOptions = {}) { + this.options = options; } /** @@ -120,9 +117,7 @@ export class Metadata { key = normalizeKey(key); validate(key, value); - const existingValue: MetadataValue[] | undefined = this.internalRepr.get( - key - ); + const existingValue: MetadataValue[] | undefined = this.internalRepr.get(key); if (existingValue === undefined) { this.internalRepr.set(key, [value]); @@ -137,7 +132,7 @@ export class Metadata { */ remove(key: string): void { key = normalizeKey(key); - validate(key); + // validate(key); this.internalRepr.delete(key); } @@ -148,7 +143,7 @@ export class Metadata { */ get(key: string): MetadataValue[] { key = normalizeKey(key); - validate(key); + // validate(key); return this.internalRepr.get(key) || []; } @@ -160,12 +155,12 @@ export class Metadata { getMap(): { [key: string]: MetadataValue } { const result: { [key: string]: MetadataValue } = {}; - this.internalRepr.forEach((values, key) => { + for (const [key, values] of this.internalRepr) { if (values.length > 0) { const v = values[0]; - result[key] = v instanceof Buffer ? v.slice() : v; + result[key] = Buffer.isBuffer(v) ? Buffer.from(v) : v; } - }); + } return result; } @@ -177,9 +172,9 @@ export class Metadata { const newMetadata = new Metadata(this.options); const newInternalRepr = newMetadata.internalRepr; - this.internalRepr.forEach((value, key) => { + for (const [key, value] of this.internalRepr) { const clonedValue: MetadataValue[] = value.map((v) => { - if (v instanceof Buffer) { + if (Buffer.isBuffer(v)) { return Buffer.from(v); } else { return v; @@ -187,7 +182,7 @@ export class Metadata { }); newInternalRepr.set(key, clonedValue); - }); + } return newMetadata; } @@ -200,13 +195,13 @@ export class Metadata { * @param other A Metadata object. */ merge(other: Metadata): void { - other.internalRepr.forEach((values, key) => { + for (const [key, values] of other.internalRepr) { const mergedValue: MetadataValue[] = ( this.internalRepr.get(key) || [] ).concat(values); this.internalRepr.set(key, mergedValue); - }); + } } setOptions(options: MetadataOptions) { @@ -223,17 +218,13 @@ export class Metadata { toHttp2Headers(): http2.OutgoingHttpHeaders { // NOTE: Node <8.9 formats http2 headers incorrectly. const result: http2.OutgoingHttpHeaders = {}; - this.internalRepr.forEach((values, key) => { + + for (const [key, values] of this.internalRepr) { // We assume that the user's interaction with this object is limited to // through its public API (i.e. keys and values are already validated). - result[key] = values.map((value) => { - if (value instanceof Buffer) { - return value.toString('base64'); - } else { - return value; - } - }); - }); + result[key] = values.map(bufToString); + } + return result; } @@ -248,7 +239,7 @@ export class Metadata { */ toJSON() { const result: { [key: string]: MetadataValue[] } = {}; - for (const [key, values] of this.internalRepr.entries()) { + for (const [key, values] of this.internalRepr) { result[key] = values; } return result; @@ -261,10 +252,10 @@ export class Metadata { */ static fromHttp2Headers(headers: http2.IncomingHttpHeaders): Metadata { const result = new Metadata(); - Object.keys(headers).forEach((key) => { + for (const key of Object.keys(headers)) { // Reserved headers (beginning with `:`) are not valid keys. if (key.charAt(0) === ':') { - return; + continue; } const values = headers[key]; @@ -297,7 +288,12 @@ export class Metadata { const message = `Failed to add metadata entry ${key}: ${values}. ${error.message}. For more information see https://github.com/grpc/grpc-node/issues/1173`; log(LogVerbosity.ERROR, message); } - }); + } + return result; } } + +const bufToString = (val: string | Buffer): string => { + return Buffer.isBuffer(val) ? val.toString('base64') : val +}; diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 1f7f3eb04..84ff7c8ee 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -19,8 +19,9 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; import * as zlib from 'zlib'; +import { promisify } from 'util'; -import { Deadline, StatusObject } from './call-stream'; +import { Deadline, StatusObject, PartialStatusObject } from './call-stream'; import { Status, DEFAULT_MAX_SEND_MESSAGE_LENGTH, @@ -35,6 +36,8 @@ import { ChannelOptions } from './channel-options'; import * as logging from './logging'; const TRACER_NAME = 'server_call'; +const unzip = promisify(zlib.unzip); +const inflate = promisify(zlib.inflate); function trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); @@ -86,25 +89,22 @@ export type ServerSurfaceCall = { export type ServerUnaryCall = ServerSurfaceCall & { request: RequestType; }; -export type ServerReadableStream< - RequestType, - ResponseType -> = ServerSurfaceCall & ObjectReadable; -export type ServerWritableStream< - RequestType, - ResponseType -> = ServerSurfaceCall & - ObjectWritable & { - request: RequestType; - end: (metadata?: Metadata) => void; - }; +export type ServerReadableStream = + ServerSurfaceCall & ObjectReadable; +export type ServerWritableStream = + ServerSurfaceCall & + ObjectWritable & { + request: RequestType; + end: (metadata?: Metadata) => void; + }; export type ServerDuplexStream = ServerSurfaceCall & ObjectReadable & ObjectWritable & { end: (metadata?: Metadata) => void }; export class ServerUnaryCallImpl extends EventEmitter - implements ServerUnaryCall { + implements ServerUnaryCall +{ cancelled: boolean; constructor( @@ -136,7 +136,8 @@ export class ServerUnaryCallImpl export class ServerReadableStreamImpl extends Readable - implements ServerReadableStream { + implements ServerReadableStream +{ cancelled: boolean; constructor( @@ -178,7 +179,8 @@ export class ServerReadableStreamImpl export class ServerWritableStreamImpl extends Writable - implements ServerWritableStream { + implements ServerWritableStream +{ cancelled: boolean; private trailingMetadata: Metadata; @@ -257,7 +259,8 @@ export class ServerWritableStreamImpl export class ServerDuplexStreamImpl extends Duplex - implements ServerDuplexStream { + implements ServerDuplexStream +{ cancelled: boolean; private trailingMetadata: Metadata; @@ -395,7 +398,8 @@ export class Http2ServerCallStream< ResponseType > extends EventEmitter { cancelled = false; - deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + deadlineTimer: NodeJS.Timer | null = null; + private statusSent = false; private deadline: Deadline = Infinity; private wantTrailers = false; private metadataSent = false; @@ -428,10 +432,20 @@ export class Http2ServerCallStream< ' stream closed with rstCode ' + this.stream.rstCode ); - this.cancelled = true; - this.emit('cancelled', 'cancelled'); - this.emit('streamEnd', false); - this.sendStatus({code: Status.CANCELLED, details: 'Cancelled by client', metadata: new Metadata()}); + + if (!this.statusSent) { + this.cancelled = true; + this.emit('cancelled', 'cancelled'); + this.emit('streamEnd', false); + this.sendStatus({ + code: Status.CANCELLED, + details: 'Cancelled by client', + metadata: null, + }); + } + + // to compensate for a fact that cancelled is not always called + this.emit('close'); }); this.stream.on('drain', () => { @@ -444,9 +458,6 @@ export class Http2ServerCallStream< if ('grpc.max_receive_message_length' in options) { this.maxReceiveMessageSize = options['grpc.max_receive_message_length']!; } - - // Clear noop timer - clearTimeout(this.deadlineTimer); } private checkCancelled(): boolean { @@ -458,52 +469,22 @@ export class Http2ServerCallStream< return this.cancelled; } - private getDecompressedMessage(message: Buffer, encoding: string) { - switch (encoding) { - case 'deflate': { - return new Promise((resolve, reject) => { - zlib.inflate(message.slice(5), (err, output) => { - if (err) { - this.sendError({ - code: Status.INTERNAL, - details: `Received "grpc-encoding" header "${encoding}" but ${encoding} decompression failed`, - }); - resolve(); - } else { - resolve(output); - } - }); - }); - } - - case 'gzip': { - return new Promise((resolve, reject) => { - zlib.unzip(message.slice(5), (err, output) => { - if (err) { - this.sendError({ - code: Status.INTERNAL, - details: `Received "grpc-encoding" header "${encoding}" but ${encoding} decompression failed`, - }); - resolve(); - } else { - resolve(output); - } - }); - }); - } - - case 'identity': { - return Promise.resolve(message.slice(5)); - } - - default: { - this.sendError({ - code: Status.UNIMPLEMENTED, - details: `Received message compressed with unsupported encoding "${encoding}"`, - }); - return Promise.resolve(); - } + private getDecompressedMessage( + message: Buffer, + encoding: string + ): Buffer | Promise { + if (encoding === 'deflate') { + return inflate(message.subarray(5)); + } else if (encoding === 'gzip') { + return unzip(message.subarray(5)); + } else if (encoding === 'identity') { + return message.subarray(5); } + + return Promise.reject({ + code: Status.UNIMPLEMENTED, + details: `Received message compressed with unsupported encoding "${encoding}"`, + }); } sendMetadata(customMetadata?: Metadata) { @@ -518,13 +499,22 @@ export class Http2ServerCallStream< this.metadataSent = true; const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. - const headers = Object.assign({}, defaultResponseHeaders, custom); + const headers = { ...defaultResponseHeaders, ...custom }; this.stream.respond(headers, defaultResponseOptions); } receiveMetadata(headers: http2.IncomingHttpHeaders) { const metadata = Metadata.fromHttp2Headers(headers); + if (logging.isTracerEnabled(TRACER_NAME)) { + trace( + 'Request to ' + + this.handler.path + + ' received headers ' + + JSON.stringify(metadata.toJSON()) + ); + } + // TODO(cjihrig): Receive compression metadata. const timeoutHeader = metadata.get(GRPC_TIMEOUT_HEADER); @@ -556,52 +546,95 @@ export class Http2ServerCallStream< return metadata; } - receiveUnaryMessage(encoding: string): Promise { - return new Promise((resolve, reject) => { - const stream = this.stream; - const chunks: Buffer[] = []; - let totalLength = 0; + receiveUnaryMessage( + encoding: string, + next: ( + err: Partial | null, + request?: RequestType + ) => void + ): void { + const { stream } = this; + + let receivedLength = 0; + const call = this; + const body: Buffer[] = []; + const limit = this.maxReceiveMessageSize; + + stream.on('data', onData); + stream.on('end', onEnd); + stream.on('error', onEnd); + + function onData(chunk: Buffer) { + receivedLength += chunk.byteLength; + + if (limit !== -1 && receivedLength > limit) { + stream.removeListener('data', onData); + stream.removeListener('end', onEnd); + stream.removeListener('error', onEnd); + next({ + code: Status.RESOURCE_EXHAUSTED, + details: `Received message larger than max (${receivedLength} vs. ${limit})`, + }); + return; + } - stream.on('data', (data: Buffer) => { - chunks.push(data); - totalLength += data.byteLength; - }); + body.push(chunk); + } - stream.once('end', async () => { - try { - const requestBytes = Buffer.concat(chunks, totalLength); - if ( - this.maxReceiveMessageSize !== -1 && - requestBytes.length > this.maxReceiveMessageSize - ) { - this.sendError({ - code: Status.RESOURCE_EXHAUSTED, - details: `Received message larger than max (${requestBytes.length} vs. ${this.maxReceiveMessageSize})`, - }); - resolve(); - } - - this.emit('receiveMessage'); - - const compressed = requestBytes.readUInt8(0) === 1; - const compressedMessageEncoding = compressed ? encoding : 'identity'; - const decompressedMessage = await this.getDecompressedMessage(requestBytes, compressedMessageEncoding); - - // Encountered an error with decompression; it'll already have been propogated back - // Just return early - if (!decompressedMessage) { - resolve(); - } - else { - resolve(this.deserializeMessage(decompressedMessage)); - } - } catch (err) { - err.code = Status.INTERNAL; - this.sendError(err); - resolve(); - } - }); - }); + function onEnd(err?: Error) { + stream.removeListener('data', onData); + stream.removeListener('end', onEnd); + stream.removeListener('error', onEnd); + + if (err !== undefined) { + next({ code: Status.INTERNAL, details: err.message }); + return; + } + + if (receivedLength === 0) { + next({ code: Status.INTERNAL, details: 'received empty unary message' }) + return; + } + + call.emit('receiveMessage'); + + const requestBytes = Buffer.concat(body, receivedLength); + const compressed = requestBytes.readUInt8(0) === 1; + const compressedMessageEncoding = compressed ? encoding : 'identity'; + const decompressedMessage = call.getDecompressedMessage( + requestBytes, + compressedMessageEncoding + ); + + if (Buffer.isBuffer(decompressedMessage)) { + call.safeDeserializeMessage(decompressedMessage, next); + return; + } + + decompressedMessage.then( + (decompressed) => call.safeDeserializeMessage(decompressed, next), + (err: any) => next( + err.code + ? err + : { + code: Status.INTERNAL, + details: `Received "grpc-encoding" header "${encoding}" but ${encoding} decompression failed`, + } + ) + ) + } + } + + private safeDeserializeMessage( + buffer: Buffer, + next: (err: Partial | null, request?: RequestType) => void + ) { + try { + next(null, this.deserializeMessage(buffer)); + } catch (err) { + err.code = Status.INTERNAL; + next(err); + } } serializeMessage(value: ResponseType) { @@ -623,18 +656,19 @@ export class Http2ServerCallStream< async sendUnaryMessage( err: ServerErrorResponse | ServerStatusResponse | null, value?: ResponseType | null, - metadata?: Metadata, + metadata?: Metadata | null, flags?: number ) { if (this.checkCancelled()) { return; } - if (!metadata) { - metadata = new Metadata(); + + if (metadata === undefined) { + metadata = null; } if (err) { - if (!Object.prototype.hasOwnProperty.call(err, 'metadata')) { + if (!Object.prototype.hasOwnProperty.call(err, 'metadata') && metadata) { err.metadata = metadata; } this.sendError(err); @@ -652,7 +686,7 @@ export class Http2ServerCallStream< } } - sendStatus(statusObj: StatusObject) { + sendStatus(statusObj: PartialStatusObject) { this.emit('callEnd', statusObj.code); this.emit('streamEnd', statusObj.code === Status.OK); if (this.checkCancelled()) { @@ -668,20 +702,19 @@ export class Http2ServerCallStream< statusObj.details ); - clearTimeout(this.deadlineTimer); + if (this.deadlineTimer) clearTimeout(this.deadlineTimer); if (!this.wantTrailers) { this.wantTrailers = true; this.stream.once('wantTrailers', () => { - const trailersToSend = Object.assign( - { - [GRPC_STATUS_HEADER]: statusObj.code, - [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), - }, - statusObj.metadata.toHttp2Headers() - ); + const trailersToSend = { + [GRPC_STATUS_HEADER]: statusObj.code, + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details), + ...statusObj.metadata?.toHttp2Headers(), + }; this.stream.sendTrailers(trailersToSend); + this.statusSent = true; }); this.sendMetadata(); this.stream.end(); @@ -689,13 +722,13 @@ export class Http2ServerCallStream< } sendError(error: ServerErrorResponse | ServerStatusResponse) { - const status: StatusObject = { + const status: PartialStatusObject = { code: Status.UNKNOWN, details: 'message' in error ? error.message : 'Unknown Error', metadata: 'metadata' in error && error.metadata !== undefined ? error.metadata - : new Metadata(), + : null, }; if ( @@ -744,6 +777,9 @@ export class Http2ServerCallStream< call.emit('cancelled', reason); }); + // to compensate for the fact that cancelled is no longer always called + this.once('close', () => call.emit('close')) + this.once('callEnd', (status) => call.emit('callEnd', status)); } @@ -766,7 +802,7 @@ export class Http2ServerCallStream< pushedEnd = true; this.pushOrBufferMessage(readable, null); } - } + }; this.stream.on('data', async (data: Buffer) => { const messages = decoder.write(data); @@ -788,12 +824,15 @@ export class Http2ServerCallStream< const compressed = message.readUInt8(0) === 1; const compressedMessageEncoding = compressed ? encoding : 'identity'; - const decompressedMessage = await this.getDecompressedMessage(message, compressedMessageEncoding); + const decompressedMessage = await this.getDecompressedMessage( + message, + compressedMessageEncoding + ); // Encountered an error with decompression; it'll already have been propogated back // Just return early if (!decompressedMessage) return; - + this.pushOrBufferMessage(readable, decompressedMessage); } pendingMessageProcessing = false; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 499fde4a3..2e89f459b 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -62,6 +62,10 @@ import { parseUri } from './uri-parser'; import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; import { CipherNameAndProtocol, TLSSocket } from 'tls'; +const { + HTTP2_HEADER_PATH +} = http2.constants + const TRACER_NAME = 'server'; interface BindResult { @@ -77,7 +81,6 @@ function getUnimplementedStatusResponse( return { code: Status.UNIMPLEMENTED, details: `The server does not implement the method ${methodName}`, - metadata: new Metadata(), }; } @@ -147,6 +150,7 @@ export class Server { private sessions = new Map(); private started = false; private options: ChannelOptions; + private serverAddressString: string = 'null' // Channelz Info private readonly channelzEnabled: boolean = true; @@ -165,6 +169,7 @@ export class Server { if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Server created'); } + this.trace('Server constructed'); } @@ -730,150 +735,210 @@ export class Server { return this.channelzRef; } - private _setupHandlers( - http2Server: http2.Http2Server | http2.Http2SecureServer - ): void { - if (http2Server === null) { - return; + private _verifyContentType(stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders): boolean { + const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; + + if ( + typeof contentType !== 'string' || + !contentType.startsWith('application/grpc') + ) { + stream.respond( + { + [http2.constants.HTTP2_HEADER_STATUS]: + http2.constants.HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, + }, + { endStream: true } + ); + return false } - http2Server.on( - 'stream', - (stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) => { - const channelzSessionInfo = this.sessions.get(stream.session as http2.ServerHttp2Session); - if (this.channelzEnabled) { - this.callTracker.addCallStarted(); - channelzSessionInfo?.streamTracker.addCallStarted(); - } - const contentType = headers[http2.constants.HTTP2_HEADER_CONTENT_TYPE]; - - if ( - typeof contentType !== 'string' || - !contentType.startsWith('application/grpc') - ) { - stream.respond( - { - [http2.constants.HTTP2_HEADER_STATUS]: - http2.constants.HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE, - }, - { endStream: true } - ); - this.callTracker.addCallFailed(); - if (this.channelzEnabled) { - channelzSessionInfo?.streamTracker.addCallFailed(); - } - return; - } + return true + } - let call: Http2ServerCallStream | null = null; + private _retrieveHandler(headers: http2.IncomingHttpHeaders): Handler { + const path = headers[HTTP2_HEADER_PATH] as string - try { - const path = headers[http2.constants.HTTP2_HEADER_PATH] as string; - const serverAddress = http2Server.address(); - let serverAddressString = 'null'; - if (serverAddress) { - if (typeof serverAddress === 'string') { - serverAddressString = serverAddress; - } else { - serverAddressString = - serverAddress.address + ':' + serverAddress.port; - } - } - this.trace( - 'Received call to method ' + - path + - ' at address ' + - serverAddressString - ); - const handler = this.handlers.get(path); + this.trace( + 'Received call to method ' + + path + + ' at address ' + + this.serverAddressString + ); - if (handler === undefined) { - this.trace( - 'No handler registered for method ' + - path + - '. Sending UNIMPLEMENTED status.' - ); - throw getUnimplementedStatusResponse(path); - } + const handler = this.handlers.get(path); - call = new Http2ServerCallStream(stream, handler, this.options); - call.once('callEnd', (code: Status) => { - if (code === Status.OK) { - this.callTracker.addCallSucceeded(); - } else { - this.callTracker.addCallFailed(); - } - }); - if (this.channelzEnabled && channelzSessionInfo) { - call.once('streamEnd', (success: boolean) => { - if (success) { - channelzSessionInfo.streamTracker.addCallSucceeded(); - } else { - channelzSessionInfo.streamTracker.addCallFailed(); - } - }); - call.on('sendMessage', () => { - channelzSessionInfo.messagesSent += 1; - channelzSessionInfo.lastMessageSentTimestamp = new Date(); - }); - call.on('receiveMessage', () => { - channelzSessionInfo.messagesReceived += 1; - channelzSessionInfo.lastMessageReceivedTimestamp = new Date(); - }); - } - const metadata = call.receiveMetadata(headers); - const encoding = (metadata.get('grpc-encoding')[0] as string | undefined) ?? 'identity'; - metadata.remove('grpc-encoding'); - - switch (handler.type) { - case 'unary': - handleUnary(call, handler as UntypedUnaryHandler, metadata, encoding); - break; - case 'clientStream': - handleClientStreaming( - call, - handler as UntypedClientStreamingHandler, - metadata, - encoding - ); - break; - case 'serverStream': - handleServerStreaming( - call, - handler as UntypedServerStreamingHandler, - metadata, - encoding - ); - break; - case 'bidi': - handleBidiStreaming( - call, - handler as UntypedBidiStreamingHandler, - metadata, - encoding - ); - break; - default: - throw new Error(`Unknown handler type: ${handler.type}`); - } - } catch (err) { - if (!call) { - call = new Http2ServerCallStream(stream, null!, this.options); - if (this.channelzEnabled) { - this.callTracker.addCallFailed(); - channelzSessionInfo?.streamTracker.addCallFailed() - } - } + if (handler === undefined) { + this.trace( + 'No handler registered for method ' + + path + + '. Sending UNIMPLEMENTED status.' + ); + throw getUnimplementedStatusResponse(path); + } - if (err.code === undefined) { - err.code = Status.INTERNAL; - } + return handler + } + + private _respondWithError>( + err: T, + stream: http2.ServerHttp2Stream, + channelzSessionInfo: ChannelzSessionInfo | null = null + ) { + const call = new Http2ServerCallStream(stream, null!, this.options); + + if (err.code === undefined) { + err.code = Status.INTERNAL; + } - call.sendError(err); + if (this.channelzEnabled) { + this.callTracker.addCallFailed(); + channelzSessionInfo?.streamTracker.addCallFailed() + } + + call.sendError(err); + } + + private _channelzHandler(stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) { + const channelzSessionInfo = this.sessions.get(stream.session as http2.ServerHttp2Session); + + this.callTracker.addCallStarted(); + channelzSessionInfo?.streamTracker.addCallStarted(); + + if (!this._verifyContentType(stream, headers)) { + this.callTracker.addCallFailed(); + channelzSessionInfo?.streamTracker.addCallFailed(); + return + } + + let handler: Handler + try { + handler = this._retrieveHandler(headers) + } catch (err) { + this._respondWithError(err, stream, channelzSessionInfo) + return + } + + const call = new Http2ServerCallStream(stream, handler, this.options); + + call.once('callEnd', (code: Status) => { + if (code === Status.OK) { + this.callTracker.addCallSucceeded(); + } else { + this.callTracker.addCallFailed(); + } + }); + + if (channelzSessionInfo) { + call.once('streamEnd', (success: boolean) => { + if (success) { + channelzSessionInfo.streamTracker.addCallSucceeded(); + } else { + channelzSessionInfo.streamTracker.addCallFailed(); } + }); + call.on('sendMessage', () => { + channelzSessionInfo.messagesSent += 1; + channelzSessionInfo.lastMessageSentTimestamp = new Date(); + }); + call.on('receiveMessage', () => { + channelzSessionInfo.messagesReceived += 1; + channelzSessionInfo.lastMessageReceivedTimestamp = new Date(); + }); + } + + if (!this._runHandlerForCall(call, handler, headers)) { + this.callTracker.addCallFailed(); + channelzSessionInfo?.streamTracker.addCallFailed() + + call.sendError({ + code: Status.INTERNAL, + details: `Unknown handler type: ${handler.type}` + }); + } + } + + private _streamHandler(stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) { + if (this._verifyContentType(stream, headers) !== true) { + return + } + + let handler: Handler + try { + handler = this._retrieveHandler(headers) + } catch (err) { + this._respondWithError(err, stream, null) + return + } + + const call = new Http2ServerCallStream(stream, handler, this.options) + if (!this._runHandlerForCall(call, handler, headers)) { + call.sendError({ + code: Status.INTERNAL, + details: `Unknown handler type: ${handler.type}` + }); + } + } + + private _runHandlerForCall(call: Http2ServerCallStream, handler: Handler, headers: http2.IncomingHttpHeaders): boolean { + const metadata = call.receiveMetadata(headers); + const encoding = (metadata.get('grpc-encoding')[0] as string | undefined) ?? 'identity'; + metadata.remove('grpc-encoding'); + + const { type } = handler + if (type === 'unary') { + handleUnary(call, handler as UntypedUnaryHandler, metadata, encoding); + } else if (type === 'clientStream') { + handleClientStreaming( + call, + handler as UntypedClientStreamingHandler, + metadata, + encoding + ); + } else if (type === 'serverStream') { + handleServerStreaming( + call, + handler as UntypedServerStreamingHandler, + metadata, + encoding + ); + } else if (type === 'bidi') { + handleBidiStreaming( + call, + handler as UntypedBidiStreamingHandler, + metadata, + encoding + ); + } else { + return false + } + + return true + } + + private _setupHandlers( + http2Server: http2.Http2Server | http2.Http2SecureServer + ): void { + if (http2Server === null) { + return; + } + + const serverAddress = http2Server.address(); + let serverAddressString = 'null' + if (serverAddress) { + if (typeof serverAddress === 'string') { + serverAddressString = serverAddress + } else { + serverAddressString = + serverAddress.address + ':' + serverAddress.port } - ); + } + this.serverAddressString = serverAddressString + + const handler = this.channelzEnabled + ? this._channelzHandler + : this._streamHandler + http2Server.on('stream', handler.bind(this)) http2Server.on('session', (session) => { if (!this.started) { session.destroy(); @@ -910,35 +975,40 @@ export class Server { } } -async function handleUnary( +function handleUnary( call: Http2ServerCallStream, handler: UnaryHandler, metadata: Metadata, encoding: string -): Promise { - const request = await call.receiveUnaryMessage(encoding); +): void { + call.receiveUnaryMessage(encoding, (err, request) => { + if (err) { + call.sendError(err) + return + } - if (request === undefined || call.cancelled) { - return; - } + if (request === undefined || call.cancelled) { + return; + } - const emitter = new ServerUnaryCallImpl( - call, - metadata, - request - ); + const emitter = new ServerUnaryCallImpl( + call, + metadata, + request + ); - handler.func( - emitter, - ( - err: ServerErrorResponse | ServerStatusResponse | null, - value?: ResponseType | null, - trailer?: Metadata, - flags?: number - ) => { - call.sendUnaryMessage(err, value, trailer, flags); - } - ); + handler.func( + emitter, + ( + err: ServerErrorResponse | ServerStatusResponse | null, + value?: ResponseType | null, + trailer?: Metadata, + flags?: number + ) => { + call.sendUnaryMessage(err, value, trailer, flags); + } + ); + }); } function handleClientStreaming( @@ -972,26 +1042,31 @@ function handleClientStreaming( handler.func(stream, respond); } -async function handleServerStreaming( +function handleServerStreaming( call: Http2ServerCallStream, handler: ServerStreamingHandler, metadata: Metadata, encoding: string -): Promise { - const request = await call.receiveUnaryMessage(encoding); +): void { + call.receiveUnaryMessage(encoding, (err, request) => { + if (err) { + call.sendError(err) + return + } - if (request === undefined || call.cancelled) { - return; - } + if (request === undefined || call.cancelled) { + return; + } - const stream = new ServerWritableStreamImpl( - call, - metadata, - handler.serialize, - request - ); + const stream = new ServerWritableStreamImpl( + call, + metadata, + handler.serialize, + request + ); - handler.func(stream); + handler.func(stream); + }); } function handleBidiStreaming( From 93de96f490d5683315532ee0bcdbcccff04c5ed3 Mon Sep 17 00:00:00 2001 From: AVVS Date: Wed, 19 Oct 2022 15:25:42 -0700 Subject: [PATCH 1786/1899] revert: extra close event on stream --- packages/grpc-js/src/server-call.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 84ff7c8ee..6ddfe13b9 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -443,9 +443,6 @@ export class Http2ServerCallStream< metadata: null, }); } - - // to compensate for a fact that cancelled is not always called - this.emit('close'); }); this.stream.on('drain', () => { @@ -777,9 +774,6 @@ export class Http2ServerCallStream< call.emit('cancelled', reason); }); - // to compensate for the fact that cancelled is no longer always called - this.once('close', () => call.emit('close')) - this.once('callEnd', (status) => call.emit('callEnd', status)); } From 035c260e3665ebcd67b2be3477d3fe8f08f787d7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 18 Oct 2022 13:25:58 -0700 Subject: [PATCH 1787/1899] grpc-js: Implement retries --- packages/grpc-js/src/channel-options.ts | 11 + packages/grpc-js/src/internal-channel.ts | 45 +- packages/grpc-js/src/load-balancing-call.ts | 13 +- .../grpc-js/src/resolving-load-balancer.ts | 3 +- packages/grpc-js/src/retrying-call.ts | 590 ++++++++++++++++++ packages/grpc-js/src/service-config.ts | 95 ++- packages/grpc-js/src/subchannel-call.ts | 14 +- packages/grpc-js/src/subchannel.ts | 4 +- 8 files changed, 762 insertions(+), 13 deletions(-) create mode 100644 packages/grpc-js/src/retrying-call.ts diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index b7fc92fa9..0842f4e1c 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -44,6 +44,14 @@ export interface ChannelOptions { 'grpc.default_compression_algorithm'?: CompressionAlgorithms; 'grpc.enable_channelz'?: number; 'grpc.dns_min_time_between_resolutions_ms'?: number; + 'grpc.enable_retries'?: number; + 'grpc.per_rpc_retry_buffer_size'?: number; + /* This option is pattered like a core option, but the core does not have + * this option. It is closely related to the option + * grpc.per_rpc_retry_buffer_size, which is in the core. The core will likely + * implement this functionality using the ResourceQuota mechanism, so there + * will probably not be any collision or other inconsistency. */ + 'grpc.retry_buffer_size'?: number; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; @@ -71,6 +79,9 @@ export const recognizedOptions = { 'grpc.enable_http_proxy': true, 'grpc.enable_channelz': true, 'grpc.dns_min_time_between_resolutions_ms': true, + 'grpc.enable_retries': true, + 'grpc.per_rpc_retry_buffer_size': true, + 'grpc.retry_buffer_size': true, 'grpc-node.max_session_memory': true, }; diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 16f4b9832..d0ae88c5d 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -50,6 +50,7 @@ import { Deadline, getDeadlineTimeoutString } from './deadline'; import { ResolvingCall } from './resolving-call'; import { getNextCallNumber } from './call-number'; import { restrictControlPlaneStatusCode } from './control-plane-status'; +import { MessageBufferTracker, RetryingCall, RetryThrottler } from './retrying-call'; /** * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args @@ -78,6 +79,11 @@ interface ErrorConfigResult { type GetConfigResult = NoneConfigResult | SuccessConfigResult | ErrorConfigResult; +const RETRY_THROTTLER_MAP: Map = new Map(); + +const DEFAULT_RETRY_BUFFER_SIZE_BYTES = 1<<24; // 16 MB +const DEFAULT_PER_RPC_RETRY_BUFFER_SIZE_BYTES = 1<<20; // 1 MB + export class InternalChannel { private resolvingLoadBalancer: ResolvingLoadBalancer; @@ -111,6 +117,7 @@ export class InternalChannel { * than TRANSIENT_FAILURE. */ private currentResolutionError: StatusObject | null = null; + private retryBufferTracker: MessageBufferTracker; // Channelz info private readonly channelzEnabled: boolean = true; @@ -179,6 +186,10 @@ export class InternalChannel { this.subchannelPool = getSubchannelPool( (options['grpc.use_local_subchannel_pool'] ?? 0) === 0 ); + this.retryBufferTracker = new MessageBufferTracker( + options['grpc.retry_buffer_size'] ?? DEFAULT_RETRY_BUFFER_SIZE_BYTES, + options['grpc.per_rpc_retry_buffer_size'] ?? DEFAULT_PER_RPC_RETRY_BUFFER_SIZE_BYTES + ); const channelControlHelper: ChannelControlHelper = { createSubchannel: ( subchannelAddress: SubchannelAddress, @@ -226,7 +237,12 @@ export class InternalChannel { this.target, channelControlHelper, options, - (configSelector) => { + (serviceConfig, configSelector) => { + if (serviceConfig.retryThrottling) { + RETRY_THROTTLER_MAP.set(this.getTarget(), new RetryThrottler(serviceConfig.retryThrottling.maxTokens, serviceConfig.retryThrottling.tokenRatio, RETRY_THROTTLER_MAP.get(this.getTarget()))); + } else { + RETRY_THROTTLER_MAP.delete(this.getTarget()); + } if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Address resolution succeeded'); } @@ -243,6 +259,7 @@ export class InternalChannel { } this.configSelectionQueue = []; }); + }, (status) => { if (this.channelzEnabled) { @@ -405,6 +422,24 @@ export class InternalChannel { return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, callNumber); } + createRetryingCall( + callConfig: CallConfig, + method: string, + host: string, + credentials: CallCredentials, + deadline: Deadline + ): RetryingCall { + const callNumber = getNextCallNumber(); + this.trace( + 'createRetryingCall [' + + callNumber + + '] method="' + + method + + '"' + ); + return new RetryingCall(this, callConfig, method, host, credentials, deadline, callNumber, this.retryBufferTracker, RETRY_THROTTLER_MAP.get(this.getTarget())) + } + createInnerCall( callConfig: CallConfig, method: string, @@ -413,7 +448,11 @@ export class InternalChannel { deadline: Deadline ): Call { // Create a RetryingCall if retries are enabled - return this.createLoadBalancingCall(callConfig, method, host, credentials, deadline); + if (this.options['grpc.enable_retries'] === 0) { + return this.createLoadBalancingCall(callConfig, method, host, credentials, deadline); + } else { + return this.createRetryingCall(callConfig, method, host, credentials, deadline); + } } createResolvingCall( @@ -439,7 +478,7 @@ export class InternalChannel { parentCall: parentCall, }; - const call = new ResolvingCall(this, method, finalOptions, this.filterStackFactory, this.credentials._getCallCredentials(), getNextCallNumber()); + const call = new ResolvingCall(this, method, finalOptions, this.filterStackFactory, this.credentials._getCallCredentials(), callNumber); if (this.channelzEnabled) { this.callTracker.addCallStarted(); diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index 6faa15592..23b9a9174 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -29,6 +29,7 @@ import { CallConfig } from "./resolver"; import { splitHostPort } from "./uri-parser"; import * as logging from './logging'; import { restrictControlPlaneStatusCode } from "./control-plane-status"; +import * as http2 from 'http2'; const TRACER_NAME = 'load_balancing_call'; @@ -38,6 +39,10 @@ export interface StatusObjectWithProgress extends StatusObject { progress: RpcProgress; } +export interface LoadBalancingCallInterceptingListener extends InterceptingListener { + onReceiveStatus(status: StatusObjectWithProgress): void; +} + export class LoadBalancingCall implements Call { private child: SubchannelCall | null = null; private readPending = false; @@ -151,7 +156,11 @@ export class LoadBalancingCall implements Call { this.listener!.onReceiveMessage(message); }, onReceiveStatus: status => { - this.outputStatus(status, 'PROCESSED'); + if (status.code === http2.constants.NGHTTP2_REFUSED_STREAM) { + this.outputStatus(status, 'REFUSED'); + } else { + this.outputStatus(status, 'PROCESSED'); + } } }); } catch (error) { @@ -226,7 +235,7 @@ export class LoadBalancingCall implements Call { getPeer(): string { return this.child?.getPeer() ?? this.channel.getTarget(); } - start(metadata: Metadata, listener: InterceptingListener): void { + start(metadata: Metadata, listener: LoadBalancingCallInterceptingListener): void { this.trace('start called'); this.listener = listener; this.metadata = metadata; diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index da097cc42..a39606f2c 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -83,7 +83,7 @@ function getDefaultConfigSelector( } export interface ResolutionCallback { - (configSelector: ConfigSelector): void; + (serviceConfig: ServiceConfig, configSelector: ConfigSelector): void; } export interface ResolutionFailureCallback { @@ -239,6 +239,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { const finalServiceConfig = workingServiceConfig ?? this.defaultServiceConfig; this.onSuccessfulResolution( + finalServiceConfig, configSelector ?? getDefaultConfigSelector(finalServiceConfig) ); }, diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts new file mode 100644 index 000000000..7c15023d5 --- /dev/null +++ b/packages/grpc-js/src/retrying-call.ts @@ -0,0 +1,590 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { CallCredentials } from "./call-credentials"; +import { LogVerbosity, Status } from "./constants"; +import { Deadline } from "./deadline"; +import { Metadata } from "./metadata"; +import { CallConfig } from "./resolver"; +import * as logging from './logging'; +import { Call, InterceptingListener, MessageContext, StatusObject, WriteCallback, WriteObject } from "./call-interface"; +import { LoadBalancingCall, StatusObjectWithProgress } from "./load-balancing-call"; +import { InternalChannel } from "./internal-channel"; + +const TRACER_NAME = 'retrying_call'; + +export class RetryThrottler { + private tokens: number; + constructor(private readonly maxTokens: number, private readonly tokenRatio: number, previousRetryThrottler?: RetryThrottler) { + if (previousRetryThrottler) { + /* When carrying over tokens from a previous config, rescale them to the + * new max value */ + this.tokens = previousRetryThrottler.tokens * (maxTokens / previousRetryThrottler.maxTokens); + } else { + this.tokens = maxTokens; + } + } + + addCallSucceeded() { + this.tokens = Math.max(this.tokens + this.tokenRatio, this.maxTokens); + } + + addCallFailed() { + this.tokens = Math.min(this.tokens - 1, 0); + } + + canRetryCall() { + return this.tokens > this.maxTokens / 2; + } +} + +export class MessageBufferTracker { + private totalAllocated: number = 0; + private allocatedPerCall: Map = new Map(); + + constructor(private totalLimit: number, private limitPerCall: number) {} + + allocate(size: number, callId: number): boolean { + const currentPerCall = this.allocatedPerCall.get(callId) ?? 0; + if (this.limitPerCall - currentPerCall < size || this.totalLimit - this.totalAllocated < size) { + return false; + } + this.allocatedPerCall.set(callId, currentPerCall + size); + this.totalAllocated += size; + return true; + } + + free(size: number, callId: number) { + if (this.totalAllocated < size) { + throw new Error(`Invalid buffer allocation state: call ${callId} freed ${size} > total allocated ${this.totalAllocated}`); + } + this.totalAllocated -= size; + const currentPerCall = this.allocatedPerCall.get(callId) ?? 0; + if (currentPerCall < size) { + throw new Error(`Invalid buffer allocation state: call ${callId} freed ${size} > allocated for call ${currentPerCall}`); + } + this.allocatedPerCall.set(callId, currentPerCall - size); + } + + freeAll(callId: number) { + const currentPerCall = this.allocatedPerCall.get(callId) ?? 0; + if (this.totalAllocated < currentPerCall) { + throw new Error(`Invalid buffer allocation state: call ${callId} allocated ${currentPerCall} > total allocated ${this.totalAllocated}`); + } + this.totalAllocated -= currentPerCall; + this.allocatedPerCall.delete(callId); + } +} + +type UnderlyingCallState = 'ACTIVE' | 'COMPLETED'; + +interface UnderlyingCall { + state: UnderlyingCallState; + call: LoadBalancingCall; + nextMessageToSend: number; +} + +/** + * A retrying call can be in one of these states: + * RETRY: Retries are configured and new attempts may be sent + * HEDGING: Hedging is configured and new attempts may be sent + * TRANSPARENT_ONLY: Neither retries nor hedging are configured, and + * transparent retry attempts may still be sent + * COMMITTED: One attempt is committed, and no new attempts will be + * sent + */ +type RetryingCallState = 'RETRY' | 'HEDGING' | 'TRANSPARENT_ONLY' | 'COMMITTED'; + +/** + * The different types of objects that can be stored in the write buffer, with + * the following meanings: + * MESSAGE: This is a message to be sent. + * HALF_CLOSE: When this entry is reached, the calls should send a half-close. + * FREED: This slot previously contained a message that has been sent on all + * child calls and is no longer needed. + */ +type WriteBufferEntryType = 'MESSAGE' | 'HALF_CLOSE' | 'FREED'; + +/** + * Entry in the buffer of messages to send to the remote end. + */ +interface WriteBufferEntry { + entryType: WriteBufferEntryType; + /** + * Message to send. + * Only populated if entryType is MESSAGE. + */ + message?: WriteObject; + /** + * Callback to call after sending the message. + * Only populated if entryType is MESSAGE and the call is in the COMMITTED + * state. + */ + callback?: WriteCallback; +} + +const PREVIONS_RPC_ATTEMPTS_METADATA_KEY = 'grpc-previous-rpc-attempts'; + +export class RetryingCall implements Call { + private state: RetryingCallState; + private listener: InterceptingListener | null = null; + private initialMetadata: Metadata | null = null; + private underlyingCalls: UnderlyingCall[] = []; + private writeBuffer: WriteBufferEntry[] = []; + private transparentRetryUsed: boolean = false; + /** + * Number of attempts so far + */ + private attempts: number = 0; + private hedgingTimer: NodeJS.Timer | null = null; + private committedCallIndex: number | null = null; + private initialRetryBackoffSec = 0; + private nextRetryBackoffSec = 0; + constructor( + private readonly channel: InternalChannel, + private readonly callConfig: CallConfig, + private readonly methodName: string, + private readonly host: string, + private readonly credentials: CallCredentials, + private readonly deadline: Deadline, + private readonly callNumber: number, + private readonly bufferTracker: MessageBufferTracker, + private readonly retryThrottler?: RetryThrottler + ) { + if (callConfig.methodConfig.retryPolicy) { + this.state = 'RETRY'; + const retryPolicy = callConfig.methodConfig.retryPolicy; + this.nextRetryBackoffSec = this.initialRetryBackoffSec = Number(retryPolicy.initialBackoff.substring(0, retryPolicy.initialBackoff.length - 1)); + } else if (callConfig.methodConfig.hedgingPolicy) { + this.state = 'HEDGING'; + } else { + this.state = 'TRANSPARENT_ONLY'; + } + } + getCallNumber(): number { + return this.callNumber; + } + + private trace(text: string): void { + logging.trace( + LogVerbosity.DEBUG, + TRACER_NAME, + '[' + this.callNumber + '] ' + text + ); + } + + private reportStatus(statusObject: StatusObject) { + this.trace('ended with status: code=' + statusObject.code + ' details="' + statusObject.details + '"'); + process.nextTick(() => { + this.listener?.onReceiveStatus(statusObject); + }); + } + + cancelWithStatus(status: Status, details: string): void { + this.trace('cancelWithStatus code: ' + status + ' details: "' + details + '"'); + this.reportStatus({code: status, details, metadata: new Metadata()}); + for (const {call} of this.underlyingCalls) { + call.cancelWithStatus(status, details); + } + } + getPeer(): string { + if (this.committedCallIndex !== null) { + return this.underlyingCalls[this.committedCallIndex].call.getPeer(); + } else { + return 'unknown'; + } + } + + private commitCall(index: number) { + if (this.state === 'COMMITTED') { + return; + } + if (this.underlyingCalls[index].state === 'COMPLETED') { + return; + } + this.trace('Committing call [' + this.underlyingCalls[index].call.getCallNumber() + '] at index ' + index); + this.state = 'COMMITTED'; + this.committedCallIndex = index; + for (let i = 0; i < this.underlyingCalls.length; i++) { + if (i === index) { + continue; + } + if (this.underlyingCalls[i].state === 'COMPLETED') { + continue; + } + this.underlyingCalls[i].state = 'COMPLETED'; + this.underlyingCalls[i].call.cancelWithStatus(Status.CANCELLED, 'Discarded in favor of other hedged attempt'); + } + for (let messageIndex = 0; messageIndex < this.underlyingCalls[index].nextMessageToSend - 1; messageIndex += 1) { + const bufferEntry = this.writeBuffer[messageIndex]; + if (bufferEntry.entryType === 'MESSAGE') { + this.bufferTracker.free(bufferEntry.message!.message.length, this.callNumber); + this.writeBuffer[messageIndex] = { + entryType: 'FREED' + }; + } + } + } + + private commitCallWithMostMessages() { + let mostMessages = -1; + let callWithMostMessages = -1; + for (const [index, childCall] of this.underlyingCalls.entries()) { + if (childCall.nextMessageToSend > mostMessages) { + mostMessages = childCall.nextMessageToSend; + callWithMostMessages = index; + } + } + this.commitCall(callWithMostMessages); + } + + private isStatusCodeInList(list: (Status | string)[], code: Status) { + return list.some((value => value === code || value.toString().toLowerCase() === Status[code].toLowerCase())); + } + + private getNextRetryBackoffMs() { + const retryPolicy = this.callConfig?.methodConfig.retryPolicy; + if (!retryPolicy) { + return 0; + } + const nextBackoffMs = Math.random() * this.nextRetryBackoffSec * 1000; + const maxBackoffSec = Number(retryPolicy.maxBackoff.substring(0, retryPolicy.maxBackoff.length - 1)); + this.nextRetryBackoffSec = Math.min(this.nextRetryBackoffSec * retryPolicy.backoffMultiplier, maxBackoffSec); + return nextBackoffMs + } + + private maybeRetryCall(pushback: number | null, callback: (retried: boolean) => void) { + if (this.state !== 'RETRY') { + callback(false); + return; + } + const retryPolicy = this.callConfig!.methodConfig.retryPolicy!; + if (this.attempts >= retryPolicy.maxAttempts) { + callback(false); + return; + } + let retryDelayMs: number; + if (pushback === null) { + retryDelayMs = this.getNextRetryBackoffMs(); + } else if (pushback < 0) { + this.state = 'TRANSPARENT_ONLY'; + callback(false); + return; + } else { + retryDelayMs = pushback; + this.nextRetryBackoffSec = this.initialRetryBackoffSec; + } + setTimeout(() => { + if (this.state !== 'RETRY') { + callback(false); + return; + } + if (this.retryThrottler?.canRetryCall() ?? true) { + callback(true); + this.attempts += 1; + this.startNewAttempt(); + } + }, retryDelayMs); + } + + private countActiveCalls(): number { + let count = 0; + for (const call of this.underlyingCalls) { + if (call?.state === 'ACTIVE') { + count += 1; + } + } + return count; + } + + private handleProcessedStatus(status: StatusObject, callIndex: number, pushback: number | null) { + switch (this.state) { + case 'COMMITTED': + case 'TRANSPARENT_ONLY': + this.commitCall(callIndex); + this.reportStatus(status); + break; + case 'HEDGING': + if (this.isStatusCodeInList(this.callConfig!.methodConfig.hedgingPolicy!.nonFatalStatusCodes, status.code)) { + this.retryThrottler?.addCallFailed(); + let delayMs: number; + if (pushback === null) { + delayMs = 0; + } else if (pushback < 0) { + this.state = 'TRANSPARENT_ONLY'; + this.commitCall(callIndex); + this.reportStatus(status); + return; + } else { + delayMs = pushback; + } + setTimeout(() => { + this.maybeStartHedgingAttempt(); + // If after trying to start a call there are no active calls, this was the last one + if (this.countActiveCalls() === 0) { + this.commitCall(callIndex); + this.reportStatus(status); + } + }, delayMs); + } else { + this.commitCall(callIndex); + this.reportStatus(status); + } + break; + case 'RETRY': + if (this.isStatusCodeInList(this.callConfig!.methodConfig.retryPolicy!.retryableStatusCodes, status.code)) { + this.retryThrottler?.addCallFailed(); + this.maybeRetryCall(pushback, (retried) => { + if (!retried) { + this.commitCall(callIndex); + this.reportStatus(status); + } + }); + } else { + this.commitCall(callIndex); + this.reportStatus(status); + } + break; + } + } + + private getPushback(metadata: Metadata): number | null { + const mdValue = metadata.get('grpc-retry-pushback-ms'); + if (mdValue.length === 0) { + return null; + } + try { + return parseInt(mdValue[0] as string); + } catch (e) { + return -1; + } + } + + private handleChildStatus(status: StatusObjectWithProgress, callIndex: number) { + if (this.underlyingCalls[callIndex].state === 'COMPLETED') { + return; + } + this.underlyingCalls[callIndex].state = 'COMPLETED'; + if (status.code === Status.OK) { + this.retryThrottler?.addCallSucceeded(); + this.commitCall(callIndex); + this.reportStatus(status); + return; + } + if (this.state === 'COMMITTED') { + this.reportStatus(status); + return; + } + const pushback = this.getPushback(status.metadata); + switch (status.progress) { + case 'NOT_STARTED': + // RPC never leaves the client, always safe to retry + this.startNewAttempt(); + break; + case 'REFUSED': + // RPC reaches the server library, but not the server application logic + if (this.transparentRetryUsed) { + this.handleProcessedStatus(status, callIndex, pushback); + } else { + this.transparentRetryUsed = true; + this.startNewAttempt(); + }; + break; + case 'DROP': + this.commitCall(callIndex); + this.reportStatus(status); + break; + case 'PROCESSED': + this.handleProcessedStatus(status, callIndex, pushback); + break; + } + } + + private maybeStartHedgingAttempt() { + if (this.state !== 'HEDGING') { + return; + } + if (!this.callConfig.methodConfig.hedgingPolicy) { + return; + } + const hedgingPolicy = this.callConfig.methodConfig.hedgingPolicy; + if (this.attempts >= hedgingPolicy.maxAttempts) { + return; + } + this.attempts += 1; + this.startNewAttempt(); + this.maybeStartHedgingTimer(); + } + + private maybeStartHedgingTimer() { + if (this.hedgingTimer) { + clearTimeout(this.hedgingTimer); + } + if (this.state !== 'HEDGING') { + return; + } + if (!this.callConfig.methodConfig.hedgingPolicy) { + return; + } + const hedgingPolicy = this.callConfig.methodConfig.hedgingPolicy; + if (this.attempts >= hedgingPolicy.maxAttempts) { + return; + } + const hedgingDelayString = hedgingPolicy.hedgingDelay ?? '0s'; + const hedgingDelaySec = Number(hedgingDelayString.substring(0, hedgingDelayString.length - 1)); + this.hedgingTimer = setTimeout(() => { + this.maybeStartHedgingAttempt(); + }, hedgingDelaySec * 1000); + this.hedgingTimer.unref?.(); + } + + private startNewAttempt() { + const child = this.channel.createLoadBalancingCall(this.callConfig, this.methodName, this.host, this.credentials, this.deadline); + this.trace('Created child call [' + child.getCallNumber() + '] for attempt ' + this.attempts); + const index = this.underlyingCalls.length; + this.underlyingCalls.push({state: 'ACTIVE', call: child, nextMessageToSend: 0}); + const previousAttempts = this.attempts - 1; + const initialMetadata = this.initialMetadata!.clone(); + if (previousAttempts > 0) { + initialMetadata.set(PREVIONS_RPC_ATTEMPTS_METADATA_KEY, `${previousAttempts}`); + } + let receivedMetadata = false; + child.start(initialMetadata, { + onReceiveMetadata: metadata => { + this.commitCall(index); + receivedMetadata = true; + if (previousAttempts > 0) { + metadata.set(PREVIONS_RPC_ATTEMPTS_METADATA_KEY, `${previousAttempts}`); + } + if (this.underlyingCalls[index].state === 'ACTIVE') { + this.listener!.onReceiveMetadata(metadata); + } + }, + onReceiveMessage: message => { + this.commitCall(index); + if (this.underlyingCalls[index].state === 'ACTIVE') { + this.listener!.onReceiveMessage(message); + } + }, + onReceiveStatus: status => { + if (!receivedMetadata && previousAttempts > 0) { + status.metadata.set(PREVIONS_RPC_ATTEMPTS_METADATA_KEY, `${previousAttempts}`); + } + this.commitCall(index); + this.handleChildStatus(status, index); + } + }) + } + + start(metadata: Metadata, listener: InterceptingListener): void { + this.trace('start called'); + this.listener = listener; + this.initialMetadata = metadata; + this.attempts += 1; + this.startNewAttempt(); + this.maybeStartHedgingTimer(); + } + + private sendNextChildMessage(childIndex: number) { + const childCall = this.underlyingCalls[childIndex]; + if (childCall.state === 'COMPLETED') { + return; + } + if (this.writeBuffer[childCall.nextMessageToSend]) { + const bufferEntry = this.writeBuffer[childCall.nextMessageToSend]; + switch (bufferEntry.entryType) { + case 'MESSAGE': + childCall.call.sendMessageWithContext({ + callback: (error) => { + // Ignore error + childCall.nextMessageToSend += 1; + this.sendNextChildMessage(childIndex); + } + }, bufferEntry.message!.message); + break; + case 'HALF_CLOSE': + childCall.nextMessageToSend += 1; + childCall.call.halfClose(); + break; + case 'FREED': + // Should not be possible + break; + } + } + } + + sendMessageWithContext(context: MessageContext, message: Buffer): void { + this.trace('write() called with message of length ' + message.length); + const writeObj: WriteObject = { + message, + flags: context.flags, + }; + const messageIndex = this.writeBuffer.length; + const bufferEntry: WriteBufferEntry = { + entryType: 'MESSAGE', + message: writeObj + }; + this.writeBuffer[messageIndex] = bufferEntry; + if (this.bufferTracker.allocate(message.length, this.callNumber)) { + context.callback?.(); + for (const [callIndex, call] of this.underlyingCalls.entries()) { + if (call.state === 'ACTIVE' && call.nextMessageToSend === messageIndex) { + call.call.sendMessageWithContext({ + callback: (error) => { + // Ignore error + call.nextMessageToSend += 1; + this.sendNextChildMessage(callIndex); + } + }, message); + } + } + } else { + this.commitCallWithMostMessages(); + bufferEntry.callback = context.callback; + } + } + startRead(): void { + this.trace('startRead called'); + for (const underlyingCall of this.underlyingCalls) { + if (underlyingCall?.state === 'ACTIVE') { + underlyingCall.call.startRead(); + } + } + } + halfClose(): void { + this.trace('halfClose called'); + const halfCloseIndex = this.writeBuffer.length; + this.writeBuffer[halfCloseIndex] = { + entryType: 'HALF_CLOSE' + }; + for (const call of this.underlyingCalls) { + if (call?.state === 'ACTIVE' && call.nextMessageToSend === halfCloseIndex) { + call.nextMessageToSend += 1; + call.call.halfClose(); + } + } + } + setCredentials(newCredentials: CallCredentials): void { + throw new Error("Method not implemented."); + } + getMethod(): string { + return this.methodName; + } + getHost(): string { + return this.host; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index 12802dad8..a45355ace 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -86,7 +86,7 @@ export interface ServiceConfigCanaryConfig { * Recognizes a number with up to 9 digits after the decimal point, followed by * an "s", representing a number of seconds. */ -const TIMEOUT_REGEX = /^\d+(\.\d{1,9})?s$/; +const DURATION_REGEX = /^\d+(\.\d{1,9})?s$/; /** * Client language name used for determining whether this client matches a @@ -111,6 +111,75 @@ function validateName(obj: any): MethodConfigName { return result; } +function validateRetryPolicy(obj: any): RetryPolicy { + if (!('maxAttempts' in obj) || !Number.isInteger(obj.maxAttempts) || obj.maxAttempts < 2) { + throw new Error('Invalid method config retry policy: maxAttempts must be an integer at least 2'); + } + if (!('initialBackoff' in obj) || typeof obj.initialBackoff !== 'string' || !DURATION_REGEX.test(obj.initialBackoff)) { + throw new Error('Invalid method config retry policy: initialBackoff must be a string consisting of a positive integer followed by s'); + } + if (!('maxBackoff' in obj) || typeof obj.maxBackoff !== 'string' || !DURATION_REGEX.test(obj.maxBackoff)) { + throw new Error('Invalid method config retry policy: maxBackoff must be a string consisting of a positive integer followed by s'); + } + if (!('backoffMultiplier' in obj) || typeof obj.backoffMultiplier !== 'number' || obj.backoffMultiplier <= 0) { + throw new Error('Invalid method config retry policy: backoffMultiplier must be a number greater than 0'); + } + if (('retryableStatusCodes' in obj) && Array.isArray(obj.retryableStatusCodes)) { + for (const value of obj.retryableStatusCodes) { + if (typeof value === 'number') { + if (!Object.values(Status).includes(value)) { + throw new Error('Invlid method config retry policy: retryableStatusCodes value not in status code range'); + } + } else if (typeof value === 'string') { + if (!Object.values(Status).includes(value.toUpperCase())) { + throw new Error('Invlid method config retry policy: retryableStatusCodes value not a status code name'); + } + } else { + throw new Error('Invlid method config retry policy: retryableStatusCodes value must be a string or number'); + } + } + } + return { + maxAttempts: obj.maxAttempts, + initialBackoff: obj.initialBackoff, + maxBackoff: obj.maxBackoff, + backoffMultiplier: obj.backoffMultiplier, + retryableStatusCodes: obj.retryableStatusCodes + }; +} + +function validateHedgingPolicy(obj: any): HedgingPolicy { + if (!('maxAttempts' in obj) || !Number.isInteger(obj.maxAttempts) || obj.maxAttempts < 2) { + throw new Error('Invalid method config hedging policy: maxAttempts must be an integer at least 2'); + } + if (('hedgingDelay' in obj) && (typeof obj.hedgingDelay !== 'string' || !DURATION_REGEX.test(obj.hedgingDelay))) { + throw new Error('Invalid method config hedging policy: hedgingDelay must be a string consisting of a positive integer followed by s'); + } + if (('nonFatalStatusCodes' in obj) && Array.isArray(obj.nonFatalStatusCodes)) { + for (const value of obj.nonFatalStatusCodes) { + if (typeof value === 'number') { + if (!Object.values(Status).includes(value)) { + throw new Error('Invlid method config hedging policy: nonFatalStatusCodes value not in status code range'); + } + } else if (typeof value === 'string') { + if (!Object.values(Status).includes(value.toUpperCase())) { + throw new Error('Invlid method config hedging policy: nonFatalStatusCodes value not a status code name'); + } + } else { + throw new Error('Invlid method config hedging policy: nonFatalStatusCodes value must be a string or number'); + } + } + } + const result: HedgingPolicy = { + maxAttempts: obj.maxAttempts, + nonFatalStatusCodes: obj.nonFatalStatusCodes + } + if (obj.hedgingDelay) { + result.hedgingDelay = obj.hedgingDelay; + } + return result; +} + function validateMethodConfig(obj: any): MethodConfig { const result: MethodConfig = { name: [], @@ -144,7 +213,7 @@ function validateMethodConfig(obj: any): MethodConfig { result.timeout = obj.timeout; } else if ( typeof obj.timeout === 'string' && - TIMEOUT_REGEX.test(obj.timeout) + DURATION_REGEX.test(obj.timeout) ) { const timeoutParts = obj.timeout .substring(0, obj.timeout.length - 1) @@ -169,9 +238,31 @@ function validateMethodConfig(obj: any): MethodConfig { } result.maxResponseBytes = obj.maxResponseBytes; } + if ('retryPolicy' in obj) { + if ('hedgingPolicy' in obj) { + throw new Error('Invalid method config: retryPolicy and hedgingPolicy cannot both be specified'); + } else { + result.retryPolicy = validateRetryPolicy(obj.retryPolicy); + } + } else if ('hedgingPolicy' in obj) { + result.hedgingPolicy = validateHedgingPolicy(obj.hedgingPolicy); + } return result; } +export function validateRetryThrottling(obj: any): RetryThrottling { + if (!('maxTokens' in obj) || typeof obj.maxTokens !== 'number' || obj.maxTokens <=0 || obj.maxTokens > 1000) { + throw new Error('Invalid retryThrottling: maxTokens must be a number in (0, 1000]'); + } + if (!('tokenRatio' in obj) || typeof obj.tokenRatio !== 'number' || obj.tokenRatio <= 0) { + throw new Error('Invalid retryThrottling: tokenRatio must be a number greater than 0'); + } + return { + maxTokens: +(obj.maxTokens as number).toFixed(3), + tokenRatio: +(obj.tokenRatio as number).toFixed(3) + }; +} + export function validateServiceConfig(obj: any): ServiceConfig { const result: ServiceConfig = { loadBalancingConfig: [], diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index e2cd645af..2bc6fb0c7 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -75,6 +75,14 @@ export interface SubchannelCall { getCallNumber(): number; } +export interface StatusObjectWithRstCode extends StatusObject { + rstCode?: number; +} + +export interface SubchannelCallInterceptingListener extends InterceptingListener { + onReceiveStatus(status: StatusObjectWithRstCode): void; +} + export class Http2SubchannelCall implements SubchannelCall { private decoder = new StreamDecoder(); @@ -103,7 +111,7 @@ export class Http2SubchannelCall implements SubchannelCall { constructor( private readonly http2Stream: http2.ClientHttp2Stream, private readonly callStatsTracker: SubchannelCallStatsTracker, - private readonly listener: InterceptingListener, + private readonly listener: SubchannelCallInterceptingListener, private readonly subchannel: Subchannel, private readonly callId: number ) { @@ -257,7 +265,7 @@ export class Http2SubchannelCall implements SubchannelCall { // This is OK, because status codes emitted here correspond to more // catastrophic issues that prevent us from receiving trailers in the // first place. - this.endCall({ code, details, metadata: new Metadata() }); + this.endCall({ code, details, metadata: new Metadata(), rstCode: http2Stream.rstCode }); }); }); http2Stream.on('error', (err: SystemError) => { @@ -329,7 +337,7 @@ export class Http2SubchannelCall implements SubchannelCall { * Subsequent calls are no-ops. * @param status The status of the call. */ - private endCall(status: StatusObject): void { + private endCall(status: StatusObjectWithRstCode): void { /* If the status is OK and a new status comes in (e.g. from a * deserialization failure), that new status takes priority */ if (this.finalStatus === null || this.finalStatus.code === Status.OK) { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 104c36c24..0d9773b30 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -36,7 +36,7 @@ import { } from './subchannel-address'; import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, SocketInfo, SocketRef, unregisterChannelzRef, registerChannelzSocket, TlsInfo } from './channelz'; import { ConnectivityStateListener } from './subchannel-interface'; -import { Http2SubchannelCall } from './subchannel-call'; +import { Http2SubchannelCall, SubchannelCallInterceptingListener } from './subchannel-call'; import { getNextCallNumber } from './call-number'; import { SubchannelCall } from './subchannel-call'; import { InterceptingListener, StatusObject } from './call-interface'; @@ -815,7 +815,7 @@ export class Subchannel { return false; } - createCall(metadata: Metadata, host: string, method: string, listener: InterceptingListener): SubchannelCall { + createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener): SubchannelCall { const headers = metadata.toHttp2Headers(); headers[HTTP2_HEADER_AUTHORITY] = host; headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; From e840d1f855f5320bd1c2ee2a3642e5d92b9bafbb Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Oct 2022 15:47:16 -0700 Subject: [PATCH 1788/1899] grpc-js: Bump to 1.7.3 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 087060154..55ddb10aa 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.7.2", + "version": "1.7.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From bcf4ce2b401b7a1d399b19b1fd8d9fe89fc14ebe Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 21 Oct 2022 15:21:19 -0700 Subject: [PATCH 1789/1899] grpc-js-xds: Log stats periodically in interop tests --- packages/grpc-js-xds/interop/xds-interop-client.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 029525a45..59c505b46 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -310,6 +310,9 @@ function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpc makeSingleRequest(client, callType, failOnFailedRpcs, callStatsTracker); } }, 1000/qps); + setInterval(() => { + console.log(`Accumulated stats: ${JSON.stringify(accumulatedStats, undefined, 2)}`); + }, 1000); } const callTypeEnumMap = { From 124712979b3b0af4a83aa6ee88d634d63a2bea87 Mon Sep 17 00:00:00 2001 From: natiz Date: Wed, 26 Oct 2022 12:12:09 +0300 Subject: [PATCH 1790/1899] grpc-tools: Update protoc to v3.19.1 last working version of protoc that includes javascript --- packages/grpc-tools/deps/protobuf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/deps/protobuf b/packages/grpc-tools/deps/protobuf index 6aa539bf0..7c40b2df1 160000 --- a/packages/grpc-tools/deps/protobuf +++ b/packages/grpc-tools/deps/protobuf @@ -1 +1 @@ -Subproject commit 6aa539bf0195f188ff86efe6fb8bfa2b676cdd46 +Subproject commit 7c40b2df1fdf6f414c1c18c789715a9c948a0725 From e7144897d06ce910f684c729c96ce56db9c9c3d9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 1 Nov 2022 09:26:29 -0700 Subject: [PATCH 1791/1899] grpc-js: Restart deadline timer after getting timeout from service config --- packages/grpc-js/src/resolving-call.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index 76a7bd208..96592d71d 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -145,6 +145,7 @@ export class ResolvingCall implements Call { config.methodConfig.timeout.nanos / 1_000_000 ); this.deadline = minDeadline(this.deadline, configDeadline); + this.runDeadlineTimer(); } this.filterStackFactory.push(config.dynamicFilterFactories); From b3bcff1d7b9e30b664390432fcf9758f03842dd9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 1 Nov 2022 10:39:06 -0700 Subject: [PATCH 1792/1899] grpc-js: Pin @types/lodash to fix broken build --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 087060154..fa0df34e0 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -17,7 +17,7 @@ "devDependencies": { "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", - "@types/lodash": "^4.14.108", + "@types/lodash": "4.14.186", "@types/mocha": "^5.2.6", "@types/ncp": "^2.0.1", "@types/pify": "^3.0.2", From 8f33dc72466b02a6ef5bdd8784d03d8c3e5e16f4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 4 Nov 2022 11:21:24 -0700 Subject: [PATCH 1793/1899] grpc-js: Update to newest typescript compiler --- packages/grpc-js/package.json | 6 ++-- packages/grpc-js/src/call-credentials.ts | 4 +++ packages/grpc-js/src/client-interceptors.ts | 5 +-- packages/grpc-js/src/error.ts | 37 +++++++++++++++++++ packages/grpc-js/src/metadata.ts | 3 +- packages/grpc-js/src/server-call.ts | 39 +++++++++++---------- packages/grpc-js/src/server.ts | 11 ++++-- 7 files changed, 78 insertions(+), 27 deletions(-) create mode 100644 packages/grpc-js/src/error.ts diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index fff572fa9..cd1c74bb5 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -17,14 +17,14 @@ "devDependencies": { "@types/gulp": "^4.0.6", "@types/gulp-mocha": "0.0.32", - "@types/lodash": "4.14.186", + "@types/lodash": "^4.14.186", "@types/mocha": "^5.2.6", "@types/ncp": "^2.0.1", "@types/pify": "^3.0.2", "@types/semver": "^7.3.9", "clang-format": "^1.0.55", "execa": "^2.0.3", - "gts": "^2.0.0", + "gts": "^3.1.1", "gulp": "^4.0.2", "gulp-mocha": "^6.0.0", "lodash": "^4.17.4", @@ -35,7 +35,7 @@ "rimraf": "^3.0.2", "semver": "^7.3.5", "ts-node": "^8.3.0", - "typescript": "^3.7.2" + "typescript": "^4.8.4" }, "contributors": [ { diff --git a/packages/grpc-js/src/call-credentials.ts b/packages/grpc-js/src/call-credentials.ts index bbc88a895..b98624ee2 100644 --- a/packages/grpc-js/src/call-credentials.ts +++ b/packages/grpc-js/src/call-credentials.ts @@ -115,6 +115,10 @@ export abstract class CallCredentials { reject(err); return; } + if (!headers) { + reject(new Error('Headers not set by metadata plugin')); + return; + } resolve(headers); } ); diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index d9c88f448..d95828550 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -34,6 +34,7 @@ import { Channel } from './channel'; import { CallOptions } from './client'; import { CallCredentials } from './call-credentials'; import { ClientMethodDefinition } from './make-client'; +import { getErrorMessage } from './error'; /** * Error class associated with passing both interceptors and interceptor @@ -374,7 +375,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { } catch (e) { this.call.cancelWithStatus( Status.INTERNAL, - `Request message serialization failure: ${e.message}` + `Request message serialization failure: ${getErrorMessage(e)}` ); return; } @@ -401,7 +402,7 @@ class BaseInterceptingCall implements InterceptingCallInterface { } catch (e) { readError = { code: Status.INTERNAL, - details: `Response message parsing error: ${e.message}`, + details: `Response message parsing error: ${getErrorMessage(e)}`, metadata: new Metadata(), }; this.call.cancelWithStatus(readError.code, readError.details); diff --git a/packages/grpc-js/src/error.ts b/packages/grpc-js/src/error.ts new file mode 100644 index 000000000..b973128a7 --- /dev/null +++ b/packages/grpc-js/src/error.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +export function getErrorMessage(error: unknown): string { + if (error instanceof Error) { + return error.message; + } else { + return String(error); + } +} + +export function getErrorCode(error: unknown): number | null { + if ( + typeof error === 'object' && + error !== null && + 'code' in error && + typeof (error as Record).code === 'number' + ) { + return (error as Record).code; + } else { + return null; + } +} \ No newline at end of file diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 376cb491a..0dddd9465 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -18,6 +18,7 @@ import * as http2 from 'http2'; import { log } from './logging'; import { LogVerbosity } from './constants'; +import { getErrorMessage } from './error'; const LEGAL_KEY_REGEX = /^[0-9a-z_.-]+$/; const LEGAL_NON_BINARY_VALUE_REGEX = /^[ -~]*$/; @@ -285,7 +286,7 @@ export class Metadata { } } } catch (error) { - const message = `Failed to add metadata entry ${key}: ${values}. ${error.message}. For more information see https://github.com/grpc/grpc-node/issues/1173`; + const message = `Failed to add metadata entry ${key}: ${values}. ${getErrorMessage(error)}. For more information see https://github.com/grpc/grpc-node/issues/1173`; log(LogVerbosity.ERROR, message); } } diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index b27bb1b20..a000b8ffe 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -35,6 +35,7 @@ import { ChannelOptions } from './channel-options'; import * as logging from './logging'; import { StatusObject, PartialStatusObject } from './call-interface'; import { Deadline } from './deadline'; +import { getErrorCode, getErrorMessage } from './error'; const TRACER_NAME = 'server_call'; const unzip = promisify(zlib.unzip); @@ -232,8 +233,10 @@ export class ServerWritableStreamImpl return; } } catch (err) { - err.code = Status.INTERNAL; - this.emit('error', err); + this.emit('error', { + details: getErrorMessage(err), + code: Status.INTERNAL + }); } callback(); @@ -630,8 +633,10 @@ export class Http2ServerCallStream< try { next(null, this.deserializeMessage(buffer)); } catch (err) { - err.code = Status.INTERNAL; - next(err); + next({ + details: getErrorMessage(err), + code: Status.INTERNAL + }); } } @@ -679,8 +684,10 @@ export class Http2ServerCallStream< this.write(response); this.sendStatus({ code: Status.OK, details: 'OK', metadata }); } catch (err) { - err.code = Status.INTERNAL; - this.sendError(err); + this.sendError({ + details: getErrorMessage(err), + code: Status.INTERNAL + }); } } @@ -909,21 +916,15 @@ export class Http2ServerCallStream< } catch (error) { // Ignore any remaining messages when errors occur. this.bufferedMessages.length = 0; - - if ( - !( - 'code' in error && - typeof error.code === 'number' && - Number.isInteger(error.code) && - error.code >= Status.OK && - error.code <= Status.UNAUTHENTICATED - ) - ) { - // The error code is not a valid gRPC code so its being overwritten. - error.code = Status.INTERNAL; + let code = getErrorCode(error); + if (code === null || code < Status.OK || code > Status.UNAUTHENTICATED) { + code = Status.INTERNAL } - readable.emit('error', error); + readable.emit('error', { + details: getErrorMessage(error), + code: code + }); } this.isPushPending = false; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 2e89f459b..9f7321408 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -61,6 +61,7 @@ import { import { parseUri } from './uri-parser'; import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; import { CipherNameAndProtocol, TLSSocket } from 'tls'; +import { getErrorCode, getErrorMessage } from './error'; const { HTTP2_HEADER_PATH @@ -814,7 +815,10 @@ export class Server { try { handler = this._retrieveHandler(headers) } catch (err) { - this._respondWithError(err, stream, channelzSessionInfo) + this._respondWithError({ + details: getErrorMessage(err), + code: getErrorCode(err) ?? undefined + }, stream, channelzSessionInfo) return } @@ -866,7 +870,10 @@ export class Server { try { handler = this._retrieveHandler(headers) } catch (err) { - this._respondWithError(err, stream, null) + this._respondWithError({ + details: getErrorMessage(err), + code: getErrorCode(err) ?? undefined + }, stream, null) return } From f392d4d8c5b3d1992f571b210e4f50f62c973e46 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 4 Nov 2022 15:15:54 -0700 Subject: [PATCH 1794/1899] grpc-js-xds: interop client: correct for setInterval variance --- .../grpc-js-xds/interop/xds-interop-client.ts | 59 ++++++++++++++++--- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 59c505b46..72bbec61d 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -180,6 +180,27 @@ class CallStatsTracker { } } +class RecentTimestampList { + private timeList: bigint[] = []; + private nextIndex = 0; + + constructor(private readonly size: number) {} + + isFull() { + return this.timeList.length === this.size; + } + + insertTimestamp(timestamp: bigint) { + this.timeList[this.nextIndex] = timestamp; + this.nextIndex = (this.nextIndex + 1) % this.size; + } + + getSpan(): bigint { + const lastIndex = (this.nextIndex + this.size - 1) % this.size; + return this.timeList[lastIndex] - this.timeList[this.nextIndex]; + } +} + type CallType = 'EmptyCall' | 'UnaryCall'; interface ClientConfiguration { @@ -246,7 +267,13 @@ const callTimeHistogram: {[callType: string]: {[status: number]: number[]}} = { EmptyCall: {} } -function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { +/** + * Timestamps output by process.hrtime.bigint() are a bigint number of + * nanoseconds. This is the representation of 1 second in that context. + */ +const TIMESTAMP_ONE_SECOND = BigInt(1e9); + +function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker, callStartTimestamps: RecentTimestampList) { const callEnumName = callTypeEnumMapReverse[type]; addAccumulatedCallStarted(callEnumName); const notifier = callStatsTracker.startCall(); @@ -254,19 +281,20 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail let hostname: string | null = null; let completed: boolean = false; let completedWithError: boolean = false; - const startTime = process.hrtime(); + const startTime = process.hrtime.bigint(); const deadline = new Date(); deadline.setSeconds(deadline.getSeconds() + currentConfig.timeoutSec); const callback = (error: grpc.ServiceError | undefined, value: Empty__Output | undefined) => { const statusCode = error?.code ?? grpc.status.OK; - const duration = process.hrtime(startTime); + const duration = process.hrtime.bigint() - startTime; + const durationSeconds = Number(duration / TIMESTAMP_ONE_SECOND) | 0; if (!callTimeHistogram[type][statusCode]) { callTimeHistogram[type][statusCode] = []; } - if (callTimeHistogram[type][statusCode][duration[0]]) { - callTimeHistogram[type][statusCode][duration[0]] += 1; + if (callTimeHistogram[type][statusCode][durationSeconds]) { + callTimeHistogram[type][statusCode][durationSeconds] += 1; } else { - callTimeHistogram[type][statusCode][duration[0]] = 1; + callTimeHistogram[type][statusCode][durationSeconds] = 1; } addAccumulatedCallEnded(callEnumName, statusCode); if (error) { @@ -301,13 +329,28 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail } } }); - + /* callStartTimestamps tracks the last N timestamps of started calls, where N + * is the target QPS. If the measured span of time between the first and last + * of those N calls is greater than 1 second, we make another call + * ~immediately to correct for that. */ + callStartTimestamps.insertTimestamp(startTime); + if (callStartTimestamps.isFull()) { + if (callStartTimestamps.getSpan() > TIMESTAMP_ONE_SECOND) { + setImmediate(() => { + makeSingleRequest(client, type, failOnFailedRpcs, callStatsTracker, callStartTimestamps); + }); + } + } } function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { + const callStartTimestampsTrackers: {[callType: string]: RecentTimestampList} = {}; + for (const callType of currentConfig.callTypes) { + callStartTimestampsTrackers[callType] = new RecentTimestampList(qps); + } setInterval(() => { for (const callType of currentConfig.callTypes) { - makeSingleRequest(client, callType, failOnFailedRpcs, callStatsTracker); + makeSingleRequest(client, callType, failOnFailedRpcs, callStatsTracker, callStartTimestampsTrackers[callType]); } }, 1000/qps); setInterval(() => { From 26c8c379853eeba3f3c5c1a90064bc01fa47fbd3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 17 Oct 2022 11:32:22 -0700 Subject: [PATCH 1795/1899] grpc-js: Handle filters in ResolvingCall instead of LoadBalancingCall --- packages/grpc-js/src/internal-channel.ts | 2 +- packages/grpc-js/src/load-balancing-call.ts | 59 +++---------- packages/grpc-js/src/resolving-call.ts | 96 +++++++++++++++------ 3 files changed, 83 insertions(+), 74 deletions(-) diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 2a775e7d8..16f4b9832 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -402,7 +402,7 @@ export class InternalChannel { method + '"' ); - return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, this.filterStackFactory, callNumber); + return new LoadBalancingCall(this, callConfig, method, host, credentials, deadline, callNumber); } createInnerCall( diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index 73c1fa9fd..6faa15592 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -41,14 +41,11 @@ export interface StatusObjectWithProgress extends StatusObject { export class LoadBalancingCall implements Call { private child: SubchannelCall | null = null; private readPending = false; - private writeFilterPending = false; private pendingMessage: {context: MessageContext, message: Buffer} | null = null; private pendingHalfClose = false; - private readFilterPending = false; private pendingChildStatus: StatusObject | null = null; private ended = false; private serviceUrl: string; - private filterStack: FilterStack; private metadata: Metadata | null = null; private listener: InterceptingListener | null = null; private onCallEnded: ((statusCode: Status) => void) | null = null; @@ -59,11 +56,8 @@ export class LoadBalancingCall implements Call { private readonly host : string, private readonly credentials: CallCredentials, private readonly deadline: Deadline, - filterStackFactory: FilterStackFactory, private readonly callNumber: number ) { - this.filterStack = filterStackFactory.createFilter(); - const splitPath: string[] = this.methodName.split('/'); let serviceName = ''; /* The standard path format is "/{serviceName}/{methodName}", so if we split @@ -90,8 +84,7 @@ export class LoadBalancingCall implements Call { if (!this.ended) { this.ended = true; this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); - const filteredStatus = this.filterStack.receiveTrailers(status); - const finalStatus = {...filteredStatus, progress}; + const finalStatus = {...status, progress}; this.listener?.onReceiveStatus(finalStatus); this.onCallEnded?.(finalStatus.code); } @@ -152,26 +145,13 @@ export class LoadBalancingCall implements Call { try { this.child = pickResult.subchannel!.getRealSubchannel().createCall(finalMetadata, this.host, this.methodName, { onReceiveMetadata: metadata => { - this.listener!.onReceiveMetadata(this.filterStack.receiveMetadata(metadata)); + this.listener!.onReceiveMetadata(metadata); }, onReceiveMessage: message => { - this.readFilterPending = true; - this.filterStack.receiveMessage(message).then(filteredMesssage => { - this.readFilterPending = false; - this.listener!.onReceiveMessage(filteredMesssage); - if (this.pendingChildStatus) { - this.outputStatus(this.pendingChildStatus, 'PROCESSED'); - } - }, (status: StatusObject) => { - this.cancelWithStatus(status.code, status.details); - }); + this.listener!.onReceiveMessage(message); }, onReceiveStatus: status => { - if (this.readFilterPending) { - this.pendingChildStatus = status; - } else { - this.outputStatus(status, 'PROCESSED'); - } + this.outputStatus(status, 'PROCESSED'); } }); } catch (error) { @@ -201,7 +181,7 @@ export class LoadBalancingCall implements Call { if (this.pendingMessage) { this.child.sendMessageWithContext(this.pendingMessage.context, this.pendingMessage.message); } - if (this.pendingHalfClose && !this.writeFilterPending) { + if (this.pendingHalfClose) { this.child.halfClose(); } }, (error: Error & { code: number }) => { @@ -249,29 +229,16 @@ export class LoadBalancingCall implements Call { start(metadata: Metadata, listener: InterceptingListener): void { this.trace('start called'); this.listener = listener; - this.filterStack.sendMetadata(Promise.resolve(metadata)).then(filteredMetadata => { - this.metadata = filteredMetadata; - this.doPick(); - }, (status: StatusObject) => { - this.outputStatus(status, 'PROCESSED'); - }); + this.metadata = metadata; + this.doPick(); } sendMessageWithContext(context: MessageContext, message: Buffer): void { this.trace('write() called with message of length ' + message.length); - this.writeFilterPending = true; - this.filterStack.sendMessage(Promise.resolve({message: message, flags: context.flags})).then((filteredMessage) => { - this.writeFilterPending = false; - if (this.child) { - this.child.sendMessageWithContext(context, filteredMessage.message); - if (this.pendingHalfClose) { - this.child.halfClose(); - } - } else { - this.pendingMessage = {context, message: filteredMessage.message}; - } - }, (status: StatusObject) => { - this.cancelWithStatus(status.code, status.details); - }) + if (this.child) { + this.child.sendMessageWithContext(context, message); + } else { + this.pendingMessage = {context, message}; + } } startRead(): void { this.trace('startRead called'); @@ -283,7 +250,7 @@ export class LoadBalancingCall implements Call { } halfClose(): void { this.trace('halfClose called'); - if (this.child && !this.writeFilterPending) { + if (this.child) { this.child.halfClose(); } else { this.pendingHalfClose = true; diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index 96592d71d..fe29a4f7a 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -19,7 +19,7 @@ import { CallCredentials } from "./call-credentials"; import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from "./call-interface"; import { LogVerbosity, Propagate, Status } from "./constants"; import { Deadline, getDeadlineTimeoutString, getRelativeTimeout, minDeadline } from "./deadline"; -import { FilterStackFactory } from "./filter-stack"; +import { FilterStack, FilterStackFactory } from "./filter-stack"; import { InternalChannel } from "./internal-channel"; import { Metadata } from "./metadata"; import * as logging from './logging'; @@ -33,12 +33,16 @@ export class ResolvingCall implements Call { private pendingMessage: {context: MessageContext, message: Buffer} | null = null; private pendingHalfClose = false; private ended = false; + private readFilterPending = false; + private writeFilterPending = false; + private pendingChildStatus: StatusObject | null = null; private metadata: Metadata | null = null; private listener: InterceptingListener | null = null; private deadline: Deadline; private host: string; private statusWatchers: ((status: StatusObject) => void)[] = []; private deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + private filterStack: FilterStack | null = null; constructor( private readonly channel: InternalChannel, @@ -96,14 +100,35 @@ export class ResolvingCall implements Call { private outputStatus(status: StatusObject) { if (!this.ended) { this.ended = true; - this.trace('ended with status: code=' + status.code + ' details="' + status.details + '"'); - this.statusWatchers.forEach(watcher => watcher(status)); + if (!this.filterStack) { + this.filterStack = this.filterStackFactory.createFilter(); + } + const filteredStatus = this.filterStack.receiveTrailers(status); + this.trace('ended with status: code=' + filteredStatus.code + ' details="' + filteredStatus.details + '"'); + this.statusWatchers.forEach(watcher => watcher(filteredStatus)); process.nextTick(() => { - this.listener?.onReceiveStatus(status); + this.listener?.onReceiveStatus(filteredStatus); }); } } + private sendMessageOnChild(context: MessageContext, message: Buffer): void { + if (!this.child) { + throw new Error('sendMessageonChild called with child not populated'); + } + const child = this.child; + this.writeFilterPending = true; + this.filterStack!.sendMessage(Promise.resolve({message: message, flags: context.flags})).then((filteredMessage) => { + this.writeFilterPending = false; + child.sendMessageWithContext(context, filteredMessage.message); + if (this.pendingHalfClose) { + child.halfClose(); + } + }, (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + }); + } + getConfig(): void { if (this.ended) { return; @@ -149,29 +174,46 @@ export class ResolvingCall implements Call { } this.filterStackFactory.push(config.dynamicFilterFactories); - - this.child = this.channel.createInnerCall(config, this.method, this.host, this.credentials, this.deadline); - this.child.start(this.metadata, { - onReceiveMetadata: metadata => { - this.listener!.onReceiveMetadata(metadata); - }, - onReceiveMessage: message => { - this.listener!.onReceiveMessage(message); - }, - onReceiveStatus: status => { - this.outputStatus(status); + this.filterStack = this.filterStackFactory.createFilter(); + this.filterStack.sendMetadata(Promise.resolve(this.metadata)).then(filteredMetadata => { + this.child = this.channel.createInnerCall(config, this.method, this.host, this.credentials, this.deadline); + this.child.start(filteredMetadata, { + onReceiveMetadata: metadata => { + this.listener!.onReceiveMetadata(this.filterStack!.receiveMetadata(metadata)); + }, + onReceiveMessage: message => { + this.readFilterPending = true; + this.filterStack!.receiveMessage(message).then(filteredMesssage => { + this.readFilterPending = false; + this.listener!.onReceiveMessage(filteredMesssage); + if (this.pendingChildStatus) { + this.outputStatus(this.pendingChildStatus); + } + }, (status: StatusObject) => { + this.cancelWithStatus(status.code, status.details); + }); + }, + onReceiveStatus: status => { + if (this.readFilterPending) { + this.pendingChildStatus = status; + } else { + this.outputStatus(status); + } + } + }); + if (this.readPending) { + this.child.startRead(); } - }); - if (this.readPending) { - this.child.startRead(); - } - if (this.pendingMessage) { - this.child.sendMessageWithContext(this.pendingMessage.context, this.pendingMessage.message); - } - if (this.pendingHalfClose) { - this.child.halfClose(); - } + if (this.pendingMessage) { + this.sendMessageOnChild(this.pendingMessage.context, this.pendingMessage.message); + } else if (this.pendingHalfClose) { + this.child.halfClose(); + } + }, (status: StatusObject) => { + this.outputStatus(status); + }) } + reportResolverError(status: StatusObject) { if (this.metadata?.getOptions().waitForReady) { this.channel.queueCallForConfig(this); @@ -196,7 +238,7 @@ export class ResolvingCall implements Call { sendMessageWithContext(context: MessageContext, message: Buffer): void { this.trace('write() called with message of length ' + message.length); if (this.child) { - this.child.sendMessageWithContext(context, message); + this.sendMessageOnChild(context, message); } else { this.pendingMessage = {context, message}; } @@ -211,7 +253,7 @@ export class ResolvingCall implements Call { } halfClose(): void { this.trace('halfClose called'); - if (this.child) { + if (this.child && !this.writeFilterPending) { this.child.halfClose(); } else { this.pendingHalfClose = true; From b4449083b905b4d4daa08fff93f8588c95730098 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 8 Nov 2022 12:40:22 -0800 Subject: [PATCH 1796/1899] grpc-js-xds: interop: output CPU profile logs in old framework tests --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 2df2ae42d..6b4987371 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -59,7 +59,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --gcp_suffix=$(date '+%s') \ --verbose \ ${XDS_V3_OPT-} \ - --client_cmd="$(which node) --enable-source-maps grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ + --client_cmd="$(which node) --enable-source-maps --prof --logfile=grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ From 959f698fc4dfe257773157bca0c8f8a0e33de1da Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 8 Nov 2022 14:46:17 -0800 Subject: [PATCH 1797/1899] Use absolute path for logfile output Co-authored-by: Sergii Tkachenko --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 6b4987371..14cbed511 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -59,7 +59,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --gcp_suffix=$(date '+%s') \ --verbose \ ${XDS_V3_OPT-} \ - --client_cmd="$(which node) --enable-source-maps --prof --logfile=grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ + --client_cmd="$(which node) --enable-source-maps --prof --logfile=${KOKORO_ARTIFACTS_DIR}/grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ From f844ca30bb3bf908fc0fc3a021b52398a861b359 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 8 Nov 2022 15:23:20 -0800 Subject: [PATCH 1798/1899] grpc-js-xds: interop: mkdir artifact directory before running tests --- packages/grpc-js-xds/scripts/xds.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 14cbed511..f556b0e76 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -48,6 +48,8 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh +mkdir -p "${KOKORO_ARTIFACTS_DIR}/grpc/reports/prof.log" + GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds \ GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ From e8396a5542ada132abfafe770fa065ea7a5cb09d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 8 Nov 2022 15:47:09 -0800 Subject: [PATCH 1799/1899] Don't try to create the target file as a directory Co-authored-by: Sergii Tkachenko --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index f556b0e76..96348e6ba 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -48,7 +48,7 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -mkdir -p "${KOKORO_ARTIFACTS_DIR}/grpc/reports/prof.log" +mkdir -p "${KOKORO_ARTIFACTS_DIR}/grpc/reports" GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds \ GRPC_NODE_VERBOSITY=DEBUG \ From 02c48f426dd2be7b5faf2442f9b100ddfcb8af3d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 9 Nov 2022 10:08:47 -0800 Subject: [PATCH 1800/1899] grpc-js-xds: interop: Fix target directory for profile log --- packages/grpc-js-xds/scripts/xds.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 96348e6ba..615b2a7c7 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -48,7 +48,7 @@ git clone -b master --single-branch --depth=1 https://github.com/grpc/grpc.git grpc/tools/run_tests/helper_scripts/prep_xds.sh -mkdir -p "${KOKORO_ARTIFACTS_DIR}/grpc/reports" +mkdir -p "${KOKORO_ARTIFACTS_DIR}/github/grpc/reports" GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds \ GRPC_NODE_VERBOSITY=DEBUG \ @@ -61,7 +61,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --gcp_suffix=$(date '+%s') \ --verbose \ ${XDS_V3_OPT-} \ - --client_cmd="$(which node) --enable-source-maps --prof --logfile=${KOKORO_ARTIFACTS_DIR}/grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ + --client_cmd="$(which node) --enable-source-maps --prof --logfile=${KOKORO_ARTIFACTS_DIR}/github/grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ --stats_port={stats_port} \ --qps={qps} \ From a42d6b4f5c7351f700149af1e845ee4105e50e6f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 9 Nov 2022 14:53:19 -0800 Subject: [PATCH 1801/1899] grpc-js: Implement server connection management --- packages/grpc-js/src/channel-options.ts | 4 ++ packages/grpc-js/src/server.ts | 74 ++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index b7fc92fa9..c05253e9b 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -44,6 +44,8 @@ export interface ChannelOptions { 'grpc.default_compression_algorithm'?: CompressionAlgorithms; 'grpc.enable_channelz'?: number; 'grpc.dns_min_time_between_resolutions_ms'?: number; + 'grpc.max_connection_age_ms'?: number; + 'grpc.max_connection_age_grace_ms'?: number; 'grpc-node.max_session_memory'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; @@ -71,6 +73,8 @@ export const recognizedOptions = { 'grpc.enable_http_proxy': true, 'grpc.enable_channelz': true, 'grpc.dns_min_time_between_resolutions_ms': true, + 'grpc.max_connection_age_ms': true, + 'grpc.max_connection_age_grace_ms': true, 'grpc-node.max_session_memory': true, }; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 9f7321408..d19186a75 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -63,6 +63,10 @@ import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerCh import { CipherNameAndProtocol, TLSSocket } from 'tls'; import { getErrorCode, getErrorMessage } from './error'; +const UNLIMITED_CONNECTION_AGE_MS = ~(1<<31); +const KEEPALIVE_MAX_TIME_MS = ~(1<<31); +const KEEPALIVE_TIMEOUT_MS = 20000; + const { HTTP2_HEADER_PATH } = http2.constants @@ -161,6 +165,12 @@ export class Server { private listenerChildrenTracker = new ChannelzChildrenTracker(); private sessionChildrenTracker = new ChannelzChildrenTracker(); + private readonly maxConnectionAgeMs: number; + private readonly maxConnectionAgeGraceMs: number; + + private readonly keepaliveTimeMs: number; + private readonly keepaliveTimeoutMs: number; + constructor(options?: ChannelOptions) { this.options = options ?? {}; if (this.options['grpc.enable_channelz'] === 0) { @@ -170,7 +180,10 @@ export class Server { if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Server created'); } - + this.maxConnectionAgeMs = this.options['grpc.max_connection_age_ms'] ?? UNLIMITED_CONNECTION_AGE_MS; + this.maxConnectionAgeGraceMs = this.options['grpc.max_connection_age_grace_ms'] ?? UNLIMITED_CONNECTION_AGE_MS; + this.keepaliveTimeMs = this.options['grpc.keepalive_time_ms'] ?? KEEPALIVE_MAX_TIME_MS; + this.keepaliveTimeoutMs = this.options['grpc.keepalive_timeout_ms'] ?? KEEPALIVE_TIMEOUT_MS; this.trace('Server constructed'); } @@ -970,12 +983,69 @@ export class Server { this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); this.sessionChildrenTracker.refChild(channelzRef); } + let connectionAgeTimer: NodeJS.Timer | null = null; + let connectionAgeGraceTimer: NodeJS.Timer | null = null; + let sessionClosedByServer = false; + if (this.maxConnectionAgeMs !== UNLIMITED_CONNECTION_AGE_MS) { + // Apply a random jitter within a +/-10% range + const jitterMagnitude = this.maxConnectionAgeMs / 10; + const jitter = Math.random() * jitterMagnitude * 2 - jitterMagnitude; + connectionAgeTimer = setTimeout(() => { + sessionClosedByServer = true; + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by max connection age from ' + clientAddress); + } + try { + session.goaway(http2.constants.NGHTTP2_NO_ERROR, ~(1<<31), Buffer.from('max_age')); + } catch (e) { + // The goaway can't be sent because the session is already closed + session.destroy(); + return; + } + session.close(); + /* Allow a grace period after sending the GOAWAY before forcibly + * closing the connection. */ + if (this.maxConnectionAgeGraceMs !== UNLIMITED_CONNECTION_AGE_MS) { + connectionAgeGraceTimer = setTimeout(() => { + session.destroy(); + }, this.maxConnectionAgeGraceMs).unref?.(); + } + }, this.maxConnectionAgeMs + jitter).unref?.(); + } + const keeapliveTimeTimer: NodeJS.Timer | null = setInterval(() => { + const timeoutTImer = setTimeout(() => { + sessionClosedByServer = true; + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by keepalive timeout from ' + clientAddress); + } + session.close(); + }, this.keepaliveTimeoutMs).unref?.(); + try { + session.ping((err: Error | null, duration: number, payload: Buffer) => { + clearTimeout(timeoutTImer); + }); + } catch (e) { + // The ping can't be sent because the session is already closed + session.destroy(); + } + }, this.keepaliveTimeMs).unref?.(); session.on('close', () => { if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); + if (!sessionClosedByServer) { + this.channelzTrace.addTrace('CT_INFO', 'Connection dropped by client ' + clientAddress); + } this.sessionChildrenTracker.unrefChild(channelzRef); unregisterChannelzRef(channelzRef); } + if (connectionAgeTimer) { + clearTimeout(connectionAgeTimer); + } + if (connectionAgeGraceTimer) { + clearTimeout(connectionAgeGraceTimer); + } + if (keeapliveTimeTimer) { + clearTimeout(keeapliveTimeTimer); + } this.sessions.delete(session); }); }); From 0de2aad269e4a27669aaada0f71ae20f5209c426 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 10 Nov 2022 10:54:19 -0800 Subject: [PATCH 1802/1899] grpc-js: Fix reuse of channel filter stack factory --- packages/grpc-js/src/filter-stack.ts | 4 ++++ packages/grpc-js/src/internal-channel.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index f44c43839..622f3dd0a 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -88,6 +88,10 @@ export class FilterStackFactory implements FilterFactory { this.factories.unshift(...filterFactories); } + clone(): FilterStackFactory { + return new FilterStackFactory(this.factories); + } + createFilter(): FilterStack { return new FilterStack( this.factories.map((factory) => factory.createFilter()) diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 16f4b9832..a8c6dc964 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -439,7 +439,7 @@ export class InternalChannel { parentCall: parentCall, }; - const call = new ResolvingCall(this, method, finalOptions, this.filterStackFactory, this.credentials._getCallCredentials(), getNextCallNumber()); + const call = new ResolvingCall(this, method, finalOptions, this.filterStackFactory.clone(), this.credentials._getCallCredentials(), getNextCallNumber()); if (this.channelzEnabled) { this.callTracker.addCallStarted(); From 38f2497daeabe49c7377c168cd9df4531f98a618 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 11 Nov 2022 09:24:15 -0800 Subject: [PATCH 1803/1899] grpc-js: Make filter stack factory clone with a copy of the array --- packages/grpc-js/src/filter-stack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/filter-stack.ts b/packages/grpc-js/src/filter-stack.ts index 622f3dd0a..4733c8218 100644 --- a/packages/grpc-js/src/filter-stack.ts +++ b/packages/grpc-js/src/filter-stack.ts @@ -89,7 +89,7 @@ export class FilterStackFactory implements FilterFactory { } clone(): FilterStackFactory { - return new FilterStackFactory(this.factories); + return new FilterStackFactory([...this.factories]); } createFilter(): FilterStack { From f8f95ee9bbbfb867590879cc4b31c6db3e27d1bb Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Nov 2022 09:50:33 -0800 Subject: [PATCH 1804/1899] grpc-js-xds: interop: Fix timestamp handling when config changes --- packages/grpc-js-xds/interop/xds-interop-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/interop/xds-interop-client.ts b/packages/grpc-js-xds/interop/xds-interop-client.ts index 72bbec61d..0394c0ace 100644 --- a/packages/grpc-js-xds/interop/xds-interop-client.ts +++ b/packages/grpc-js-xds/interop/xds-interop-client.ts @@ -345,7 +345,7 @@ function makeSingleRequest(client: TestServiceClient, type: CallType, failOnFail function sendConstantQps(client: TestServiceClient, qps: number, failOnFailedRpcs: boolean, callStatsTracker: CallStatsTracker) { const callStartTimestampsTrackers: {[callType: string]: RecentTimestampList} = {}; - for (const callType of currentConfig.callTypes) { + for (const callType of ['EmptyCall', 'UnaryCall']) { callStartTimestampsTrackers[callType] = new RecentTimestampList(qps); } setInterval(() => { From c7125fbdb5590511c4b88aa5d939e6904db6a283 Mon Sep 17 00:00:00 2001 From: install <1994052+install@users.noreply.github.com> Date: Tue, 15 Nov 2022 16:44:52 -0500 Subject: [PATCH 1805/1899] proto-loader-gen-types Avoid TS enums --- .../bin/proto-loader-gen-types.ts | 51 ++++++--- .../google/api/FieldBehavior.ts | 77 +++++++++++-- .../google/protobuf/FieldDescriptorProto.ts | 108 +++++++++++++----- .../google/protobuf/FieldOptions.ts | 54 ++++++--- .../google/protobuf/FileOptions.ts | 24 ++-- .../google/showcase/v1beta1/EchoRequest.ts | 6 +- .../google/showcase/v1beta1/EchoResponse.ts | 6 +- .../google/showcase/v1beta1/Severity.ts | 30 ++++- 8 files changed, 266 insertions(+), 90 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index bb5b35f81..64ec28ddb 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -135,20 +135,16 @@ function getImportLine(dependency: Protobuf.Type | Protobuf.Enum | Protobuf.Serv /* If the dependency is defined within a message, it will be generated in that * message's file and exported using its typeInterfaceName. */ if (dependency.parent instanceof Protobuf.Type) { - if (dependency instanceof Protobuf.Type) { + if (dependency instanceof Protobuf.Type || dependency instanceof Protobuf.Enum) { importedTypes = `${inputName(typeInterfaceName)}, ${outputName(typeInterfaceName)}`; - } else if (dependency instanceof Protobuf.Enum) { - importedTypes = `${typeInterfaceName}`; } else if (dependency instanceof Protobuf.Service) { importedTypes = `${typeInterfaceName}Client, ${typeInterfaceName}Definition`; } else { throw new Error('Invalid object passed to getImportLine'); } } else { - if (dependency instanceof Protobuf.Type) { + if (dependency instanceof Protobuf.Type || dependency instanceof Protobuf.Enum) { importedTypes = `${inputName(dependency.name)} as ${inputName(typeInterfaceName)}, ${outputName(dependency.name)} as ${outputName(typeInterfaceName)}`; - } else if (dependency instanceof Protobuf.Enum) { - importedTypes = `${dependency.name} as ${typeInterfaceName}`; } else if (dependency instanceof Protobuf.Service) { importedTypes = `${dependency.name}Client as ${typeInterfaceName}Client, ${dependency.name}Definition as ${typeInterfaceName}Definition`; } else { @@ -213,14 +209,14 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | throw new Error('Found field with no usable type'); } const typeInterfaceName = getTypeInterfaceName(resolvedType); - if (resolvedType instanceof Protobuf.Type) { + if (resolvedType instanceof Protobuf.Type || resolvedType instanceof Protobuf.Enum) { if (repeated || map) { return inputName(typeInterfaceName); } else { return `${inputName(typeInterfaceName)} | null`; } } else { - return `${typeInterfaceName} | keyof typeof ${typeInterfaceName}`; + return ''; } } } @@ -315,7 +311,7 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | throw new Error('Found field with no usable type'); } const typeInterfaceName = getTypeInterfaceName(resolvedType); - if (resolvedType instanceof Protobuf.Type) { + if (resolvedType instanceof Protobuf.Type || resolvedType instanceof Protobuf.Enum) { /* null is only used to represent absent message values if the defaults * option is set, and only for non-repeated, non-map fields. */ if (options.defaults && !repeated && !map) { @@ -324,11 +320,7 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | return `${outputName(typeInterfaceName)}`; } } else { - if (options.enums == String) { - return `keyof typeof ${typeInterfaceName}`; - } else { - return typeInterfaceName; - } + return ''; } } } @@ -455,21 +447,46 @@ function generateMessageInterfaces(formatter: TextFormatter, messageType: Protob } function generateEnumInterface(formatter: TextFormatter, enumType: Protobuf.Enum, options: GeneratorOptions, nameOverride?: string) { + const {inputName, outputName} = useNameFmter(options); + const name = nameOverride ?? enumType.name; formatter.writeLine(`// Original file: ${(enumType.filename ?? 'null')?.replace(/\\/g, '/')}`); formatter.writeLine(''); if (options.includeComments) { formatComment(formatter, enumType.comment); } - formatter.writeLine(`export enum ${nameOverride ?? enumType.name} {`); + formatter.writeLine(`export const ${name} = {`); formatter.indent(); for (const key of Object.keys(enumType.values)) { if (options.includeComments) { formatComment(formatter, enumType.comments[key]); } - formatter.writeLine(`${key} = ${enumType.values[key]},`); + formatter.writeLine(`${key}: ${options.enums == String ? `'${key}'` : enumType.values[key]},`); } formatter.unindent(); - formatter.writeLine('}'); + formatter.writeLine('} as const;'); + + // Permissive Type + formatter.writeLine(''); + if (options.includeComments) { + formatComment(formatter, enumType.comment); + } + formatter.writeLine(`export type ${inputName(name)} =`) + formatter.indent(); + for (const key of Object.keys(enumType.values)) { + if (options.includeComments) { + formatComment(formatter, enumType.comments[key]); + } + formatter.writeLine(`| '${key}'`); + formatter.writeLine(`| ${enumType.values[key]}`); + } + formatter.unindent(); + + // Restrictive Type + formatter.writeLine(''); + if (options.includeComments) { + formatComment(formatter, enumType.comment); + } + formatter.writeLine(`export type ${outputName(name)} = typeof ${name}[keyof typeof ${name}]`) } /** diff --git a/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts b/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts index 8ab676709..189d25be5 100644 --- a/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts +++ b/packages/proto-loader/golden-generated/google/api/FieldBehavior.ts @@ -8,40 +8,101 @@ * * Note: This enum **may** receive new values in the future. */ -export enum FieldBehavior { +export const FieldBehavior = { /** * Conventional default for enums. Do not use this. */ - FIELD_BEHAVIOR_UNSPECIFIED = 0, + FIELD_BEHAVIOR_UNSPECIFIED: 'FIELD_BEHAVIOR_UNSPECIFIED', /** * Specifically denotes a field as optional. * While all fields in protocol buffers are optional, this may be specified * for emphasis if appropriate. */ - OPTIONAL = 1, + OPTIONAL: 'OPTIONAL', /** * Denotes a field as required. * This indicates that the field **must** be provided as part of the request, * and failure to do so will cause an error (usually `INVALID_ARGUMENT`). */ - REQUIRED = 2, + REQUIRED: 'REQUIRED', /** * Denotes a field as output only. * This indicates that the field is provided in responses, but including the * field in a request does nothing (the server *must* ignore it and * *must not* throw an error as a result of the field's presence). */ - OUTPUT_ONLY = 3, + OUTPUT_ONLY: 'OUTPUT_ONLY', /** * Denotes a field as input only. * This indicates that the field is provided in requests, and the * corresponding field is not included in output. */ - INPUT_ONLY = 4, + INPUT_ONLY: 'INPUT_ONLY', /** * Denotes a field as immutable. * This indicates that the field may be set once in a request to create a * resource, but may not be changed thereafter. */ - IMMUTABLE = 5, -} + IMMUTABLE: 'IMMUTABLE', +} as const; + +/** + * An indicator of the behavior of a given field (for example, that a field + * is required in requests, or given as output but ignored as input). + * This **does not** change the behavior in protocol buffers itself; it only + * denotes the behavior and may affect how API tooling handles the field. + * + * Note: This enum **may** receive new values in the future. + */ +export type IFieldBehavior = + /** + * Conventional default for enums. Do not use this. + */ + | 'FIELD_BEHAVIOR_UNSPECIFIED' + | 0 + /** + * Specifically denotes a field as optional. + * While all fields in protocol buffers are optional, this may be specified + * for emphasis if appropriate. + */ + | 'OPTIONAL' + | 1 + /** + * Denotes a field as required. + * This indicates that the field **must** be provided as part of the request, + * and failure to do so will cause an error (usually `INVALID_ARGUMENT`). + */ + | 'REQUIRED' + | 2 + /** + * Denotes a field as output only. + * This indicates that the field is provided in responses, but including the + * field in a request does nothing (the server *must* ignore it and + * *must not* throw an error as a result of the field's presence). + */ + | 'OUTPUT_ONLY' + | 3 + /** + * Denotes a field as input only. + * This indicates that the field is provided in requests, and the + * corresponding field is not included in output. + */ + | 'INPUT_ONLY' + | 4 + /** + * Denotes a field as immutable. + * This indicates that the field may be set once in a request to create a + * resource, but may not be changed thereafter. + */ + | 'IMMUTABLE' + | 5 + +/** + * An indicator of the behavior of a given field (for example, that a field + * is required in requests, or given as output but ignored as input). + * This **does not** change the behavior in protocol buffers itself; it only + * denotes the behavior and may affect how API tooling handles the field. + * + * Note: This enum **may** receive new values in the future. + */ +export type OFieldBehavior = typeof FieldBehavior[keyof typeof FieldBehavior] diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts index 0a713e9dc..3dbce5175 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts @@ -4,41 +4,91 @@ import type { IFieldOptions as I_google_protobuf_FieldOptions, OFieldOptions as // Original file: null -export enum _google_protobuf_FieldDescriptorProto_Label { - LABEL_OPTIONAL = 1, - LABEL_REQUIRED = 2, - LABEL_REPEATED = 3, -} +export const _google_protobuf_FieldDescriptorProto_Label = { + LABEL_OPTIONAL: 'LABEL_OPTIONAL', + LABEL_REQUIRED: 'LABEL_REQUIRED', + LABEL_REPEATED: 'LABEL_REPEATED', +} as const; + +export type I_google_protobuf_FieldDescriptorProto_Label = + | 'LABEL_OPTIONAL' + | 1 + | 'LABEL_REQUIRED' + | 2 + | 'LABEL_REPEATED' + | 3 + +export type O_google_protobuf_FieldDescriptorProto_Label = typeof _google_protobuf_FieldDescriptorProto_Label[keyof typeof _google_protobuf_FieldDescriptorProto_Label] // Original file: null -export enum _google_protobuf_FieldDescriptorProto_Type { - TYPE_DOUBLE = 1, - TYPE_FLOAT = 2, - TYPE_INT64 = 3, - TYPE_UINT64 = 4, - TYPE_INT32 = 5, - TYPE_FIXED64 = 6, - TYPE_FIXED32 = 7, - TYPE_BOOL = 8, - TYPE_STRING = 9, - TYPE_GROUP = 10, - TYPE_MESSAGE = 11, - TYPE_BYTES = 12, - TYPE_UINT32 = 13, - TYPE_ENUM = 14, - TYPE_SFIXED32 = 15, - TYPE_SFIXED64 = 16, - TYPE_SINT32 = 17, - TYPE_SINT64 = 18, -} +export const _google_protobuf_FieldDescriptorProto_Type = { + TYPE_DOUBLE: 'TYPE_DOUBLE', + TYPE_FLOAT: 'TYPE_FLOAT', + TYPE_INT64: 'TYPE_INT64', + TYPE_UINT64: 'TYPE_UINT64', + TYPE_INT32: 'TYPE_INT32', + TYPE_FIXED64: 'TYPE_FIXED64', + TYPE_FIXED32: 'TYPE_FIXED32', + TYPE_BOOL: 'TYPE_BOOL', + TYPE_STRING: 'TYPE_STRING', + TYPE_GROUP: 'TYPE_GROUP', + TYPE_MESSAGE: 'TYPE_MESSAGE', + TYPE_BYTES: 'TYPE_BYTES', + TYPE_UINT32: 'TYPE_UINT32', + TYPE_ENUM: 'TYPE_ENUM', + TYPE_SFIXED32: 'TYPE_SFIXED32', + TYPE_SFIXED64: 'TYPE_SFIXED64', + TYPE_SINT32: 'TYPE_SINT32', + TYPE_SINT64: 'TYPE_SINT64', +} as const; + +export type I_google_protobuf_FieldDescriptorProto_Type = + | 'TYPE_DOUBLE' + | 1 + | 'TYPE_FLOAT' + | 2 + | 'TYPE_INT64' + | 3 + | 'TYPE_UINT64' + | 4 + | 'TYPE_INT32' + | 5 + | 'TYPE_FIXED64' + | 6 + | 'TYPE_FIXED32' + | 7 + | 'TYPE_BOOL' + | 8 + | 'TYPE_STRING' + | 9 + | 'TYPE_GROUP' + | 10 + | 'TYPE_MESSAGE' + | 11 + | 'TYPE_BYTES' + | 12 + | 'TYPE_UINT32' + | 13 + | 'TYPE_ENUM' + | 14 + | 'TYPE_SFIXED32' + | 15 + | 'TYPE_SFIXED64' + | 16 + | 'TYPE_SINT32' + | 17 + | 'TYPE_SINT64' + | 18 + +export type O_google_protobuf_FieldDescriptorProto_Type = typeof _google_protobuf_FieldDescriptorProto_Type[keyof typeof _google_protobuf_FieldDescriptorProto_Type] export interface IFieldDescriptorProto { 'name'?: (string); 'extendee'?: (string); 'number'?: (number); - 'label'?: (_google_protobuf_FieldDescriptorProto_Label | keyof typeof _google_protobuf_FieldDescriptorProto_Label); - 'type'?: (_google_protobuf_FieldDescriptorProto_Type | keyof typeof _google_protobuf_FieldDescriptorProto_Type); + 'label'?: (I_google_protobuf_FieldDescriptorProto_Label | null); + 'type'?: (I_google_protobuf_FieldDescriptorProto_Type | null); 'typeName'?: (string); 'defaultValue'?: (string); 'options'?: (I_google_protobuf_FieldOptions | null); @@ -50,8 +100,8 @@ export interface OFieldDescriptorProto { 'name': (string); 'extendee': (string); 'number': (number); - 'label': (keyof typeof _google_protobuf_FieldDescriptorProto_Label); - 'type': (keyof typeof _google_protobuf_FieldDescriptorProto_Type); + 'label': (O_google_protobuf_FieldDescriptorProto_Label | null); + 'type': (O_google_protobuf_FieldDescriptorProto_Type | null); 'typeName': (string); 'defaultValue': (string); 'options': (O_google_protobuf_FieldOptions | null); diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts index 076b35983..daf307d64 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts @@ -1,42 +1,62 @@ // Original file: null import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUninterpretedOption as O_google_protobuf_UninterpretedOption } from '../../google/protobuf/UninterpretedOption'; -import type { FieldBehavior as _google_api_FieldBehavior } from '../../google/api/FieldBehavior'; +import type { IFieldBehavior as I_google_api_FieldBehavior, OFieldBehavior as O_google_api_FieldBehavior } from '../../google/api/FieldBehavior'; // Original file: null -export enum _google_protobuf_FieldOptions_CType { - STRING = 0, - CORD = 1, - STRING_PIECE = 2, -} +export const _google_protobuf_FieldOptions_CType = { + STRING: 'STRING', + CORD: 'CORD', + STRING_PIECE: 'STRING_PIECE', +} as const; + +export type I_google_protobuf_FieldOptions_CType = + | 'STRING' + | 0 + | 'CORD' + | 1 + | 'STRING_PIECE' + | 2 + +export type O_google_protobuf_FieldOptions_CType = typeof _google_protobuf_FieldOptions_CType[keyof typeof _google_protobuf_FieldOptions_CType] // Original file: null -export enum _google_protobuf_FieldOptions_JSType { - JS_NORMAL = 0, - JS_STRING = 1, - JS_NUMBER = 2, -} +export const _google_protobuf_FieldOptions_JSType = { + JS_NORMAL: 'JS_NORMAL', + JS_STRING: 'JS_STRING', + JS_NUMBER: 'JS_NUMBER', +} as const; + +export type I_google_protobuf_FieldOptions_JSType = + | 'JS_NORMAL' + | 0 + | 'JS_STRING' + | 1 + | 'JS_NUMBER' + | 2 + +export type O_google_protobuf_FieldOptions_JSType = typeof _google_protobuf_FieldOptions_JSType[keyof typeof _google_protobuf_FieldOptions_JSType] export interface IFieldOptions { - 'ctype'?: (_google_protobuf_FieldOptions_CType | keyof typeof _google_protobuf_FieldOptions_CType); + 'ctype'?: (I_google_protobuf_FieldOptions_CType | null); 'packed'?: (boolean); 'deprecated'?: (boolean); 'lazy'?: (boolean); - 'jstype'?: (_google_protobuf_FieldOptions_JSType | keyof typeof _google_protobuf_FieldOptions_JSType); + 'jstype'?: (I_google_protobuf_FieldOptions_JSType | null); 'weak'?: (boolean); 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; - '.google.api.field_behavior'?: (_google_api_FieldBehavior | keyof typeof _google_api_FieldBehavior)[]; + '.google.api.field_behavior'?: (I_google_api_FieldBehavior)[]; } export interface OFieldOptions { - 'ctype': (keyof typeof _google_protobuf_FieldOptions_CType); + 'ctype': (O_google_protobuf_FieldOptions_CType | null); 'packed': (boolean); 'deprecated': (boolean); 'lazy': (boolean); - 'jstype': (keyof typeof _google_protobuf_FieldOptions_JSType); + 'jstype': (O_google_protobuf_FieldOptions_JSType | null); 'weak': (boolean); 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; - '.google.api.field_behavior': (keyof typeof _google_api_FieldBehavior)[]; + '.google.api.field_behavior': (O_google_api_FieldBehavior)[]; } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts index 2b832e0f8..038ef4785 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts @@ -4,16 +4,26 @@ import type { IUninterpretedOption as I_google_protobuf_UninterpretedOption, OUn // Original file: null -export enum _google_protobuf_FileOptions_OptimizeMode { - SPEED = 1, - CODE_SIZE = 2, - LITE_RUNTIME = 3, -} +export const _google_protobuf_FileOptions_OptimizeMode = { + SPEED: 'SPEED', + CODE_SIZE: 'CODE_SIZE', + LITE_RUNTIME: 'LITE_RUNTIME', +} as const; + +export type I_google_protobuf_FileOptions_OptimizeMode = + | 'SPEED' + | 1 + | 'CODE_SIZE' + | 2 + | 'LITE_RUNTIME' + | 3 + +export type O_google_protobuf_FileOptions_OptimizeMode = typeof _google_protobuf_FileOptions_OptimizeMode[keyof typeof _google_protobuf_FileOptions_OptimizeMode] export interface IFileOptions { 'javaPackage'?: (string); 'javaOuterClassname'?: (string); - 'optimizeFor'?: (_google_protobuf_FileOptions_OptimizeMode | keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'optimizeFor'?: (I_google_protobuf_FileOptions_OptimizeMode | null); 'javaMultipleFiles'?: (boolean); 'goPackage'?: (string); 'ccGenericServices'?: (boolean); @@ -31,7 +41,7 @@ export interface IFileOptions { export interface OFileOptions { 'javaPackage': (string); 'javaOuterClassname': (string); - 'optimizeFor': (keyof typeof _google_protobuf_FileOptions_OptimizeMode); + 'optimizeFor': (O_google_protobuf_FileOptions_OptimizeMode | null); 'javaMultipleFiles': (boolean); 'goPackage': (string); 'ccGenericServices': (boolean); diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts index 649a5d505..715fcb342 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -1,7 +1,7 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto import type { IStatus as I_google_rpc_Status, OStatus as O_google_rpc_Status } from '../../../google/rpc/Status'; -import type { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; +import type { ISeverity as I_google_showcase_v1beta1_Severity, OSeverity as O_google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; /** * The request message used for the Echo, Collect and Chat methods. @@ -21,7 +21,7 @@ export interface IEchoRequest { /** * The severity to be echoed by the server. */ - 'severity'?: (_google_showcase_v1beta1_Severity | keyof typeof _google_showcase_v1beta1_Severity); + 'severity'?: (I_google_showcase_v1beta1_Severity | null); 'response'?: "content"|"error"; } @@ -43,6 +43,6 @@ export interface OEchoRequest { /** * The severity to be echoed by the server. */ - 'severity': (keyof typeof _google_showcase_v1beta1_Severity); + 'severity': (O_google_showcase_v1beta1_Severity | null); 'response': "content"|"error"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts index 96b7ba25d..68e685967 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts @@ -1,6 +1,6 @@ // Original file: deps/gapic-showcase/schema/google/showcase/v1beta1/echo.proto -import type { Severity as _google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; +import type { ISeverity as I_google_showcase_v1beta1_Severity, OSeverity as O_google_showcase_v1beta1_Severity } from '../../../google/showcase/v1beta1/Severity'; /** * The response message for the Echo methods. @@ -13,7 +13,7 @@ export interface IEchoResponse { /** * The severity specified in the request. */ - 'severity'?: (_google_showcase_v1beta1_Severity | keyof typeof _google_showcase_v1beta1_Severity); + 'severity'?: (I_google_showcase_v1beta1_Severity | null); } /** @@ -27,5 +27,5 @@ export interface OEchoResponse { /** * The severity specified in the request. */ - 'severity': (keyof typeof _google_showcase_v1beta1_Severity); + 'severity': (O_google_showcase_v1beta1_Severity | null); } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts index fc3fe6415..d109fe1ce 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/Severity.ts @@ -3,9 +3,27 @@ /** * A severity enum used to test enum capabilities in GAPIC surfaces */ -export enum Severity { - UNNECESSARY = 0, - NECESSARY = 1, - URGENT = 2, - CRITICAL = 3, -} +export const Severity = { + UNNECESSARY: 'UNNECESSARY', + NECESSARY: 'NECESSARY', + URGENT: 'URGENT', + CRITICAL: 'CRITICAL', +} as const; + +/** + * A severity enum used to test enum capabilities in GAPIC surfaces + */ +export type ISeverity = + | 'UNNECESSARY' + | 0 + | 'NECESSARY' + | 1 + | 'URGENT' + | 2 + | 'CRITICAL' + | 3 + +/** + * A severity enum used to test enum capabilities in GAPIC surfaces + */ +export type OSeverity = typeof Severity[keyof typeof Severity] From ef7b8e8f14ca98dc7b2a04ebb64d660729b92494 Mon Sep 17 00:00:00 2001 From: install <1994052+install@users.noreply.github.com> Date: Wed, 16 Nov 2022 10:10:13 -0500 Subject: [PATCH 1806/1899] Don't allow `null` for enum field inputs/outputs --- packages/proto-loader/bin/proto-loader-gen-types.ts | 10 ++++++---- .../google/protobuf/FieldDescriptorProto.ts | 8 ++++---- .../golden-generated/google/protobuf/FieldOptions.ts | 8 ++++---- .../golden-generated/google/protobuf/FileOptions.ts | 4 ++-- .../google/showcase/v1beta1/EchoRequest.ts | 4 ++-- .../google/showcase/v1beta1/EchoResponse.ts | 4 ++-- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 64ec28ddb..a9ee4a6ed 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -209,14 +209,15 @@ function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | throw new Error('Found field with no usable type'); } const typeInterfaceName = getTypeInterfaceName(resolvedType); - if (resolvedType instanceof Protobuf.Type || resolvedType instanceof Protobuf.Enum) { + if (resolvedType instanceof Protobuf.Type) { if (repeated || map) { return inputName(typeInterfaceName); } else { return `${inputName(typeInterfaceName)} | null`; } } else { - return ''; + // Enum + return inputName(typeInterfaceName); } } } @@ -311,7 +312,7 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | throw new Error('Found field with no usable type'); } const typeInterfaceName = getTypeInterfaceName(resolvedType); - if (resolvedType instanceof Protobuf.Type || resolvedType instanceof Protobuf.Enum) { + if (resolvedType instanceof Protobuf.Type) { /* null is only used to represent absent message values if the defaults * option is set, and only for non-repeated, non-map fields. */ if (options.defaults && !repeated && !map) { @@ -320,7 +321,8 @@ function getTypeNameRestricted(fieldType: string, resolvedType: Protobuf.Type | return `${outputName(typeInterfaceName)}`; } } else { - return ''; + // Enum + return outputName(typeInterfaceName); } } } diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts index 3dbce5175..1bcb69abe 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldDescriptorProto.ts @@ -87,8 +87,8 @@ export interface IFieldDescriptorProto { 'name'?: (string); 'extendee'?: (string); 'number'?: (number); - 'label'?: (I_google_protobuf_FieldDescriptorProto_Label | null); - 'type'?: (I_google_protobuf_FieldDescriptorProto_Type | null); + 'label'?: (I_google_protobuf_FieldDescriptorProto_Label); + 'type'?: (I_google_protobuf_FieldDescriptorProto_Type); 'typeName'?: (string); 'defaultValue'?: (string); 'options'?: (I_google_protobuf_FieldOptions | null); @@ -100,8 +100,8 @@ export interface OFieldDescriptorProto { 'name': (string); 'extendee': (string); 'number': (number); - 'label': (O_google_protobuf_FieldDescriptorProto_Label | null); - 'type': (O_google_protobuf_FieldDescriptorProto_Type | null); + 'label': (O_google_protobuf_FieldDescriptorProto_Label); + 'type': (O_google_protobuf_FieldDescriptorProto_Type); 'typeName': (string); 'defaultValue': (string); 'options': (O_google_protobuf_FieldOptions | null); diff --git a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts index daf307d64..16e532d95 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FieldOptions.ts @@ -40,22 +40,22 @@ export type I_google_protobuf_FieldOptions_JSType = export type O_google_protobuf_FieldOptions_JSType = typeof _google_protobuf_FieldOptions_JSType[keyof typeof _google_protobuf_FieldOptions_JSType] export interface IFieldOptions { - 'ctype'?: (I_google_protobuf_FieldOptions_CType | null); + 'ctype'?: (I_google_protobuf_FieldOptions_CType); 'packed'?: (boolean); 'deprecated'?: (boolean); 'lazy'?: (boolean); - 'jstype'?: (I_google_protobuf_FieldOptions_JSType | null); + 'jstype'?: (I_google_protobuf_FieldOptions_JSType); 'weak'?: (boolean); 'uninterpretedOption'?: (I_google_protobuf_UninterpretedOption)[]; '.google.api.field_behavior'?: (I_google_api_FieldBehavior)[]; } export interface OFieldOptions { - 'ctype': (O_google_protobuf_FieldOptions_CType | null); + 'ctype': (O_google_protobuf_FieldOptions_CType); 'packed': (boolean); 'deprecated': (boolean); 'lazy': (boolean); - 'jstype': (O_google_protobuf_FieldOptions_JSType | null); + 'jstype': (O_google_protobuf_FieldOptions_JSType); 'weak': (boolean); 'uninterpretedOption': (O_google_protobuf_UninterpretedOption)[]; '.google.api.field_behavior': (O_google_api_FieldBehavior)[]; diff --git a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts index 038ef4785..fdeac9cd4 100644 --- a/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts +++ b/packages/proto-loader/golden-generated/google/protobuf/FileOptions.ts @@ -23,7 +23,7 @@ export type O_google_protobuf_FileOptions_OptimizeMode = typeof _google_protobuf export interface IFileOptions { 'javaPackage'?: (string); 'javaOuterClassname'?: (string); - 'optimizeFor'?: (I_google_protobuf_FileOptions_OptimizeMode | null); + 'optimizeFor'?: (I_google_protobuf_FileOptions_OptimizeMode); 'javaMultipleFiles'?: (boolean); 'goPackage'?: (string); 'ccGenericServices'?: (boolean); @@ -41,7 +41,7 @@ export interface IFileOptions { export interface OFileOptions { 'javaPackage': (string); 'javaOuterClassname': (string); - 'optimizeFor': (O_google_protobuf_FileOptions_OptimizeMode | null); + 'optimizeFor': (O_google_protobuf_FileOptions_OptimizeMode); 'javaMultipleFiles': (boolean); 'goPackage': (string); 'ccGenericServices': (boolean); diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts index 715fcb342..a5fb8f766 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoRequest.ts @@ -21,7 +21,7 @@ export interface IEchoRequest { /** * The severity to be echoed by the server. */ - 'severity'?: (I_google_showcase_v1beta1_Severity | null); + 'severity'?: (I_google_showcase_v1beta1_Severity); 'response'?: "content"|"error"; } @@ -43,6 +43,6 @@ export interface OEchoRequest { /** * The severity to be echoed by the server. */ - 'severity': (O_google_showcase_v1beta1_Severity | null); + 'severity': (O_google_showcase_v1beta1_Severity); 'response': "content"|"error"; } diff --git a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts index 68e685967..ac50115bf 100644 --- a/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts +++ b/packages/proto-loader/golden-generated/google/showcase/v1beta1/EchoResponse.ts @@ -13,7 +13,7 @@ export interface IEchoResponse { /** * The severity specified in the request. */ - 'severity'?: (I_google_showcase_v1beta1_Severity | null); + 'severity'?: (I_google_showcase_v1beta1_Severity); } /** @@ -27,5 +27,5 @@ export interface OEchoResponse { /** * The severity specified in the request. */ - 'severity': (O_google_showcase_v1beta1_Severity | null); + 'severity': (O_google_showcase_v1beta1_Severity); } From 5a5e42498ce1ce2de7b14dc02c14985ce7770b4a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 Nov 2022 14:09:40 -0800 Subject: [PATCH 1807/1899] grpc-js: Enable servers to send trailers-only responses --- packages/grpc-js/README.md | 3 + packages/grpc-js/src/load-balancing-call.ts | 3 + packages/grpc-js/src/retrying-call.ts | 21 +- packages/grpc-js/src/server-call.ts | 40 ++- packages/grpc-js/src/service-config.ts | 39 ++- packages/grpc-js/test/test-retry-config.ts | 292 +++++++++++++++++++ packages/grpc-js/test/test-retry.ts | 301 ++++++++++++++++++++ 7 files changed, 666 insertions(+), 33 deletions(-) create mode 100644 packages/grpc-js/test/test-retry-config.ts create mode 100644 packages/grpc-js/test/test-retry.ts diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 11a8ca9aa..3d698dfd8 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -59,6 +59,9 @@ Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. - `grpc.default_compression_algorithm` - `grpc.enable_channelz` - `grpc.dns_min_time_between_resolutions_ms` + - `grpc.enable_retries` + - `grpc.per_rpc_retry_buffer_size` + - `grpc.retry_buffer_size` - `grpc-node.max_session_memory` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index 23b9a9174..a7af83d6d 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -150,12 +150,15 @@ export class LoadBalancingCall implements Call { try { this.child = pickResult.subchannel!.getRealSubchannel().createCall(finalMetadata, this.host, this.methodName, { onReceiveMetadata: metadata => { + this.trace('Received metadata'); this.listener!.onReceiveMetadata(metadata); }, onReceiveMessage: message => { + this.trace('Received message'); this.listener!.onReceiveMessage(message); }, onReceiveStatus: status => { + this.trace('Received status'); if (status.code === http2.constants.NGHTTP2_REFUSED_STREAM) { this.outputStatus(status, 'REFUSED'); } else { diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 7c15023d5..71dedd46f 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -145,6 +145,13 @@ export class RetryingCall implements Call { private initialMetadata: Metadata | null = null; private underlyingCalls: UnderlyingCall[] = []; private writeBuffer: WriteBufferEntry[] = []; + /** + * Tracks whether a read has been started, so that we know whether to start + * reads on new child calls. This only matters for the first read, because + * once a message comes in the child call becomes committed and there will + * be no new child calls. + */ + private readStarted = false; private transparentRetryUsed: boolean = false; /** * Number of attempts so far @@ -319,7 +326,7 @@ export class RetryingCall implements Call { this.reportStatus(status); break; case 'HEDGING': - if (this.isStatusCodeInList(this.callConfig!.methodConfig.hedgingPolicy!.nonFatalStatusCodes, status.code)) { + if (this.isStatusCodeInList(this.callConfig!.methodConfig.hedgingPolicy!.nonFatalStatusCodes ?? [], status.code)) { this.retryThrottler?.addCallFailed(); let delayMs: number; if (pushback === null) { @@ -378,6 +385,7 @@ export class RetryingCall implements Call { if (this.underlyingCalls[callIndex].state === 'COMPLETED') { return; } + this.trace('state=' + this.state + ' handling status from child [' + this.underlyingCalls[callIndex].call.getCallNumber() + '] in state ' + this.underlyingCalls[callIndex].state); this.underlyingCalls[callIndex].state = 'COMPLETED'; if (status.code === Status.OK) { this.retryThrottler?.addCallSucceeded(); @@ -465,6 +473,7 @@ export class RetryingCall implements Call { let receivedMetadata = false; child.start(initialMetadata, { onReceiveMetadata: metadata => { + this.trace('Received metadata from child [' + child.getCallNumber() + ']'); this.commitCall(index); receivedMetadata = true; if (previousAttempts > 0) { @@ -475,19 +484,24 @@ export class RetryingCall implements Call { } }, onReceiveMessage: message => { + this.trace('Received message from child [' + child.getCallNumber() + ']'); this.commitCall(index); if (this.underlyingCalls[index].state === 'ACTIVE') { this.listener!.onReceiveMessage(message); } }, onReceiveStatus: status => { + this.trace('Received status from child [' + child.getCallNumber() + ']'); if (!receivedMetadata && previousAttempts > 0) { status.metadata.set(PREVIONS_RPC_ATTEMPTS_METADATA_KEY, `${previousAttempts}`); } - this.commitCall(index); this.handleChildStatus(status, index); } - }) + }); + this.sendNextChildMessage(index); + if (this.readStarted) { + child.startRead(); + } } start(metadata: Metadata, listener: InterceptingListener): void { @@ -559,6 +573,7 @@ export class RetryingCall implements Call { } startRead(): void { this.trace('startRead called'); + this.readStarted = true; for (const underlyingCall of this.underlyingCalls) { if (underlyingCall?.state === 'ACTIVE') { underlyingCall.call.startRead(); diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 38b4379ea..e48d20441 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -673,21 +673,31 @@ export class Http2ServerCallStream< clearTimeout(this.deadlineTimer); - if (!this.wantTrailers) { - this.wantTrailers = true; - this.stream.once('wantTrailers', () => { - const trailersToSend = Object.assign( - { - [GRPC_STATUS_HEADER]: statusObj.code, - [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), - }, - statusObj.metadata.toHttp2Headers() - ); - - this.stream.sendTrailers(trailersToSend); - }); - this.sendMetadata(); - this.stream.end(); + if (this.stream.headersSent) { + if (!this.wantTrailers) { + this.wantTrailers = true; + this.stream.once('wantTrailers', () => { + const trailersToSend = Object.assign( + { + [GRPC_STATUS_HEADER]: statusObj.code, + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), + }, + statusObj.metadata.toHttp2Headers() + ); + + this.stream.sendTrailers(trailersToSend); + }); + this.stream.end(); + } + } else { + const trailersToSend = Object.assign( + { + [GRPC_STATUS_HEADER]: statusObj.code, + [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details as string), + }, + statusObj.metadata.toHttp2Headers() + ); + this.stream.respond(trailersToSend, {endStream: true}); } } diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index a45355ace..2b8c0a7eb 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -50,7 +50,7 @@ export interface RetryPolicy { export interface HedgingPolicy { maxAttempts: number; hedgingDelay?: string; - nonFatalStatusCodes: (Status | string)[]; + nonFatalStatusCodes?: (Status | string)[]; } export interface MethodConfig { @@ -124,19 +124,23 @@ function validateRetryPolicy(obj: any): RetryPolicy { if (!('backoffMultiplier' in obj) || typeof obj.backoffMultiplier !== 'number' || obj.backoffMultiplier <= 0) { throw new Error('Invalid method config retry policy: backoffMultiplier must be a number greater than 0'); } - if (('retryableStatusCodes' in obj) && Array.isArray(obj.retryableStatusCodes)) { - for (const value of obj.retryableStatusCodes) { - if (typeof value === 'number') { - if (!Object.values(Status).includes(value)) { - throw new Error('Invlid method config retry policy: retryableStatusCodes value not in status code range'); - } - } else if (typeof value === 'string') { - if (!Object.values(Status).includes(value.toUpperCase())) { - throw new Error('Invlid method config retry policy: retryableStatusCodes value not a status code name'); - } - } else { - throw new Error('Invlid method config retry policy: retryableStatusCodes value must be a string or number'); + if (!(('retryableStatusCodes' in obj) && Array.isArray(obj.retryableStatusCodes))) { + throw new Error('Invalid method config retry policy: retryableStatusCodes is required'); + } + if (obj.retryableStatusCodes.length === 0) { + throw new Error('Invalid method config retry policy: retryableStatusCodes must be non-empty'); + } + for (const value of obj.retryableStatusCodes) { + if (typeof value === 'number') { + if (!Object.values(Status).includes(value)) { + throw new Error('Invlid method config retry policy: retryableStatusCodes value not in status code range'); } + } else if (typeof value === 'string') { + if (!Object.values(Status).includes(value.toUpperCase())) { + throw new Error('Invlid method config retry policy: retryableStatusCodes value not a status code name'); + } + } else { + throw new Error('Invlid method config retry policy: retryableStatusCodes value must be a string or number'); } } return { @@ -171,12 +175,14 @@ function validateHedgingPolicy(obj: any): HedgingPolicy { } } const result: HedgingPolicy = { - maxAttempts: obj.maxAttempts, - nonFatalStatusCodes: obj.nonFatalStatusCodes + maxAttempts: obj.maxAttempts } if (obj.hedgingDelay) { result.hedgingDelay = obj.hedgingDelay; } + if (obj.nonFatalStatusCodes) { + result.nonFatalStatusCodes = obj.nonFatalStatusCodes; + } return result; } @@ -291,6 +297,9 @@ export function validateServiceConfig(obj: any): ServiceConfig { } } } + if ('retryThrottling' in obj) { + result.retryThrottling = validateRetryThrottling(obj.retryThrottling); + } // Validate method name uniqueness const seenMethodNames: MethodConfigName[] = []; for (const methodConfig of result.methodConfig) { diff --git a/packages/grpc-js/test/test-retry-config.ts b/packages/grpc-js/test/test-retry-config.ts new file mode 100644 index 000000000..e27f236e2 --- /dev/null +++ b/packages/grpc-js/test/test-retry-config.ts @@ -0,0 +1,292 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import assert = require("assert"); +import { validateServiceConfig } from "../src/service-config"; + +function createRetryServiceConfig(retryConfig: object): object { + return { + loadBalancingConfig: [], + methodConfig: [ + { + name: [{ + service: 'A', + method: 'B' + }], + + retryPolicy: retryConfig + } + ] + }; +} + +function createHedgingServiceConfig(hedgingConfig: object): object { + return { + loadBalancingConfig: [], + methodConfig: [ + { + name: [{ + service: 'A', + method: 'B' + }], + + hedgingPolicy: hedgingConfig + } + ] + }; +} + +function createThrottlingServiceConfig(retryThrottling: object): object { + return { + loadBalancingConfig: [], + methodConfig: [], + retryThrottling: retryThrottling + }; +} + +interface TestCase { + description: string; + config: object; + error: RegExp; +} + +const validRetryConfig = { + maxAttempts: 2, + initialBackoff: '1s', + maxBackoff: '1s', + backoffMultiplier: 1, + retryableStatusCodes: [14, 'RESOURCE_EXHAUSTED'] +}; + +const RETRY_TEST_CASES: TestCase[] = [ + { + description: 'omitted maxAttempts', + config: { + initialBackoff: '1s', + maxBackoff: '1s', + backoffMultiplier: 1, + retryableStatusCodes: [14] + }, + error: /retry policy: maxAttempts must be an integer at least 2/ + }, + { + description: 'a low maxAttempts', + config: {...validRetryConfig, maxAttempts: 1}, + error: /retry policy: maxAttempts must be an integer at least 2/ + }, + { + description: 'omitted initialBackoff', + config: { + maxAttempts: 2, + maxBackoff: '1s', + backoffMultiplier: 1, + retryableStatusCodes: [14] + }, + error: /retry policy: initialBackoff must be a string consisting of a positive integer followed by s/ + }, + { + description: 'a non-numeric initialBackoff', + config: {...validRetryConfig, initialBackoff: 'abcs'}, + error: /retry policy: initialBackoff must be a string consisting of a positive integer followed by s/ + }, + { + description: 'an initialBackoff without an s', + config: {...validRetryConfig, initialBackoff: '123'}, + error: /retry policy: initialBackoff must be a string consisting of a positive integer followed by s/ + }, + { + description: 'omitted maxBackoff', + config: { + maxAttempts: 2, + initialBackoff: '1s', + backoffMultiplier: 1, + retryableStatusCodes: [14] + }, + error: /retry policy: maxBackoff must be a string consisting of a positive integer followed by s/ + }, + { + description: 'a non-numeric maxBackoff', + config: {...validRetryConfig, maxBackoff: 'abcs'}, + error: /retry policy: maxBackoff must be a string consisting of a positive integer followed by s/ + }, + { + description: 'an maxBackoff without an s', + config: {...validRetryConfig, maxBackoff: '123'}, + error: /retry policy: maxBackoff must be a string consisting of a positive integer followed by s/ + }, + { + description: 'omitted backoffMultiplier', + config: { + maxAttempts: 2, + initialBackoff: '1s', + maxBackoff: '1s', + retryableStatusCodes: [14] + }, + error: /retry policy: backoffMultiplier must be a number greater than 0/ + }, + { + description: 'a negative backoffMultiplier', + config: {...validRetryConfig, backoffMultiplier: -1}, + error: /retry policy: backoffMultiplier must be a number greater than 0/ + }, + { + description: 'omitted retryableStatusCodes', + config: { + maxAttempts: 2, + initialBackoff: '1s', + maxBackoff: '1s', + backoffMultiplier: 1 + }, + error: /retry policy: retryableStatusCodes is required/ + }, + { + description: 'empty retryableStatusCodes', + config: {...validRetryConfig, retryableStatusCodes: []}, + error: /retry policy: retryableStatusCodes must be non-empty/ + }, + { + description: 'unknown status code name', + config: {...validRetryConfig, retryableStatusCodes: ['abcd']}, + error: /retry policy: retryableStatusCodes value not a status code name/ + }, + { + description: 'out of range status code number', + config: {...validRetryConfig, retryableStatusCodes: [12345]}, + error: /retry policy: retryableStatusCodes value not in status code range/ + } +]; + +const validHedgingConfig = { + maxAttempts: 2 +}; + +const HEDGING_TEST_CASES: TestCase[] = [ + { + description: 'omitted maxAttempts', + config: {}, + error: /hedging policy: maxAttempts must be an integer at least 2/ + }, + { + description: 'a low maxAttempts', + config: {...validHedgingConfig, maxAttempts: 1}, + error: /hedging policy: maxAttempts must be an integer at least 2/ + }, + { + description: 'a non-numeric hedgingDelay', + config: {...validHedgingConfig, hedgingDelay: 'abcs'}, + error: /hedging policy: hedgingDelay must be a string consisting of a positive integer followed by s/ + }, + { + description: 'a hedgingDelay without an s', + config: {...validHedgingConfig, hedgingDelay: '123'}, + error: /hedging policy: hedgingDelay must be a string consisting of a positive integer followed by s/ + }, + { + description: 'unknown status code name', + config: {...validHedgingConfig, nonFatalStatusCodes: ['abcd']}, + error: /hedging policy: nonFatalStatusCodes value not a status code name/ + }, + { + description: 'out of range status code number', + config: {...validHedgingConfig, nonFatalStatusCodes: [12345]}, + error: /hedging policy: nonFatalStatusCodes value not in status code range/ + } +]; + +const validThrottlingConfig = { + maxTokens: 100, + tokenRatio: 0.1 +}; + +const THROTTLING_TEST_CASES: TestCase[] = [ + { + description: 'omitted maxTokens', + config: {tokenRatio: 0.1}, + error: /retryThrottling: maxTokens must be a number in \(0, 1000\]/ + }, + { + description: 'a large maxTokens', + config: {...validThrottlingConfig, maxTokens: 1001}, + error: /retryThrottling: maxTokens must be a number in \(0, 1000\]/ + }, + { + description: 'zero maxTokens', + config: {...validThrottlingConfig, maxTokens: 0}, + error: /retryThrottling: maxTokens must be a number in \(0, 1000\]/ + }, + { + description: 'omitted tokenRatio', + config: {maxTokens: 100}, + error: /retryThrottling: tokenRatio must be a number greater than 0/ + }, + { + description: 'zero tokenRatio', + config: {...validThrottlingConfig, tokenRatio: 0}, + error: /retryThrottling: tokenRatio must be a number greater than 0/ + } +]; + +describe('Retry configs', () => { + describe('Retry', () => { + it('Should accept a valid config', () => { + assert.doesNotThrow(() => { + validateServiceConfig(createRetryServiceConfig(validRetryConfig)); + }); + }); + for (const testCase of RETRY_TEST_CASES) { + it(`Should reject ${testCase.description}`, () => { + assert.throws(() => { + validateServiceConfig(createRetryServiceConfig(testCase.config)); + }, testCase.error); + }); + } + }); + describe('Hedging', () => { + it('Should accept valid configs', () => { + assert.doesNotThrow(() => { + validateServiceConfig(createHedgingServiceConfig(validHedgingConfig)); + }); + assert.doesNotThrow(() => { + validateServiceConfig(createHedgingServiceConfig({...validHedgingConfig, hedgingDelay: '1s'})); + }); + assert.doesNotThrow(() => { + validateServiceConfig(createHedgingServiceConfig({...validHedgingConfig, nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED']})); + }); + }); + for (const testCase of HEDGING_TEST_CASES) { + it(`Should reject ${testCase.description}`, () => { + assert.throws(() => { + validateServiceConfig(createHedgingServiceConfig(testCase.config)); + }, testCase.error); + }); + } + }); + describe('Throttling', () => { + it('Should accept a valid config', () => { + assert.doesNotThrow(() => { + validateServiceConfig(createThrottlingServiceConfig(validThrottlingConfig)); + }); + }); + for (const testCase of THROTTLING_TEST_CASES) { + it(`Should reject ${testCase.description}`, () => { + assert.throws(() => { + validateServiceConfig(createThrottlingServiceConfig(testCase.config)); + }, testCase.error); + }); + } + }); +}); \ No newline at end of file diff --git a/packages/grpc-js/test/test-retry.ts b/packages/grpc-js/test/test-retry.ts new file mode 100644 index 000000000..4dd96cc43 --- /dev/null +++ b/packages/grpc-js/test/test-retry.ts @@ -0,0 +1,301 @@ +/* + * Copyright 2022 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import * as path from 'path'; +import * as grpc from '../src'; +import { loadProtoFile } from './common'; + +const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); +const EchoService = loadProtoFile(protoFile) + .EchoService as grpc.ServiceClientConstructor; + +const serviceImpl = { + echo: (call: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { + const succeedOnRetryAttempt = call.metadata.get('succeed-on-retry-attempt'); + const previousAttempts = call.metadata.get('grpc-previous-rpc-attempts'); + if (succeedOnRetryAttempt.length === 0 || (previousAttempts.length > 0 && previousAttempts[0] === succeedOnRetryAttempt[0])) { + callback(null, call.request); + } else { + const statusCode = call.metadata.get('respond-with-status'); + const code = statusCode[0] ? Number.parseInt(statusCode[0] as string) : grpc.status.UNKNOWN; + callback({ + code: code, + details: `Failed on retry ${previousAttempts[0] ?? 0}` + }); + } + } +} + +describe('Retries', () => { + let server: grpc.Server; + let port: number; + before((done) => { + server = new grpc.Server(); + server.addService(EchoService.service, serviceImpl); + server.bindAsync('localhost:0', grpc.ServerCredentials.createInsecure(), (error, portNumber) => { + if (error) { + done(error); + return; + } + port = portNumber; + server.start(); + done(); + }); + }); + + after(() => { + server.forceShutdown(); + }); + + describe('Client with retries disabled', () => { + let client: InstanceType; + before(() => { + client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.enable_retries': 0}); + }); + + after(() =>{ + client.close(); + }); + + it('Should be able to make a basic request', (done) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); + + it('Should fail if the server fails the first request', (done) =>{ + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '1'); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.details, 'Failed on retry 0'); + done(); + } + ); + }); + }); + + describe('Client with retries enabled but not configured', () => { + let client: InstanceType; + before(() => { + client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure()); + }); + + after(() =>{ + client.close(); + }); + + it('Should be able to make a basic request', (done) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); + + it('Should fail if the server fails the first request', (done) =>{ + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '1'); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.details, 'Failed on retry 0'); + done(); + } + ); + }); + }); + + describe('Client with retries configured', () => { + let client: InstanceType; + before(() => { + const serviceConfig = { + loadBalancingConfig: [], + methodConfig: [ + { + name: [{ + service: 'EchoService' + }], + retryPolicy: { + maxAttempts: 3, + initialBackoff: '0.1s', + maxBackoff: '10s', + backoffMultiplier: 1.2, + retryableStatusCodes: [14, 'RESOURCE_EXHAUSTED'] + } + } + ] + } + client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(serviceConfig)}); + }); + + after(() =>{ + client.close(); + }); + + it('Should be able to make a basic request', (done) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); + + it('Should succeed with few required attempts', (done) => { + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '2'); + metadata.set('respond-with-status', `${grpc.status.RESOURCE_EXHAUSTED}`); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); + + it('Should fail with many required attempts', (done) => { + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '4'); + metadata.set('respond-with-status', `${grpc.status.RESOURCE_EXHAUSTED}`); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.details, 'Failed on retry 2'); + done(); + } + ); + }); + + it('Should fail with a fatal status code', (done) => { + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '2'); + metadata.set('respond-with-status', `${grpc.status.NOT_FOUND}`); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.details, 'Failed on retry 0'); + done(); + } + ); + }); + }); + + describe('Client with hedging configured', () => { + let client: InstanceType; + before(() => { + const serviceConfig = { + loadBalancingConfig: [], + methodConfig: [ + { + name: [{ + service: 'EchoService' + }], + hedgingPolicy: { + maxAttempts: 3, + nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED'] + } + } + ] + } + client = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(serviceConfig)}); + }); + + after(() =>{ + client.close(); + }); + + it('Should be able to make a basic request', (done) => { + client.echo( + { value: 'test value', value2: 3 }, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); + + it('Should succeed with few required attempts', (done) => { + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '2'); + metadata.set('respond-with-status', `${grpc.status.RESOURCE_EXHAUSTED}`); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, { value: 'test value', value2: 3 }); + done(); + } + ); + }); + + it('Should fail with many required attempts', (done) => { + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '4'); + metadata.set('respond-with-status', `${grpc.status.RESOURCE_EXHAUSTED}`); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert(error.details.startsWith('Failed on retry')); + done(); + } + ); + }); + + it('Should fail with a fatal status code', (done) => { + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '2'); + metadata.set('respond-with-status', `${grpc.status.NOT_FOUND}`); + client.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert(error.details.startsWith('Failed on retry')); + done(); + } + ); + }); + }); +}); \ No newline at end of file From e19a7737051d055d77482b0e4bc1947e6f22c208 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 Nov 2022 14:10:26 -0800 Subject: [PATCH 1808/1899] grpc-js: Add retry tests, and fix bugs and add tracing --- .../generated/grpc/channelz/v1/Channelz.ts | 104 +++++++++--------- 1 file changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts b/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts index ace712454..4c8c18aa7 100644 --- a/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts +++ b/packages/grpc-js/src/generated/grpc/channelz/v1/Channelz.ts @@ -25,102 +25,102 @@ export interface ChannelzClient extends grpc.Client { /** * Returns a single Channel, or else a NOT_FOUND code. */ - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; - GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetChannelResponse__Output) => void): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; + GetChannel(argument: _grpc_channelz_v1_GetChannelRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetChannelResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Server, or else a NOT_FOUND code. */ - GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - GetServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - GetServer(argument: _grpc_channelz_v1_GetServerRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + GetServer(argument: _grpc_channelz_v1_GetServerRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Server, or else a NOT_FOUND code. */ - getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - getServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; - getServer(argument: _grpc_channelz_v1_GetServerRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerResponse__Output) => void): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; + getServer(argument: _grpc_channelz_v1_GetServerRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerResponse__Output>): grpc.ClientUnaryCall; /** * Gets all server sockets that exist in the process. */ - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + GetServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; /** * Gets all server sockets that exist in the process. */ - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; - getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServerSocketsResponse__Output) => void): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; + getServerSockets(argument: _grpc_channelz_v1_GetServerSocketsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServerSocketsResponse__Output>): grpc.ClientUnaryCall; /** * Gets all servers that exist in the process. */ - GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - GetServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - GetServers(argument: _grpc_channelz_v1_GetServersRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + GetServers(argument: _grpc_channelz_v1_GetServersRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; /** * Gets all servers that exist in the process. */ - getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - getServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; - getServers(argument: _grpc_channelz_v1_GetServersRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetServersResponse__Output) => void): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; + getServers(argument: _grpc_channelz_v1_GetServersRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetServersResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Socket or else a NOT_FOUND code. */ - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + GetSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Socket or else a NOT_FOUND code. */ - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; - getSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSocketResponse__Output) => void): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; + getSocket(argument: _grpc_channelz_v1_GetSocketRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSocketResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Subchannel, or else a NOT_FOUND code. */ - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + GetSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; /** * Returns a single Subchannel, or else a NOT_FOUND code. */ - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; - getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetSubchannelResponse__Output) => void): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; + getSubchannel(argument: _grpc_channelz_v1_GetSubchannelRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetSubchannelResponse__Output>): grpc.ClientUnaryCall; /** * Gets all root channels (i.e. channels the application has directly * created). This does not include subchannels nor non-top level channels. */ - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + GetTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; /** * Gets all root channels (i.e. channels the application has directly * created). This does not include subchannels nor non-top level channels. */ - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; - getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: (error?: grpc.ServiceError, result?: _grpc_channelz_v1_GetTopChannelsResponse__Output) => void): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; + getTopChannels(argument: _grpc_channelz_v1_GetTopChannelsRequest, callback: grpc.requestCallback<_grpc_channelz_v1_GetTopChannelsResponse__Output>): grpc.ClientUnaryCall; } From 95516b66a089fbce15dedfcd30d263f6fa5687ef Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 16 Nov 2022 14:37:31 -0800 Subject: [PATCH 1809/1899] Fix detection of refused streams --- packages/grpc-js/src/load-balancing-call.ts | 2 +- packages/grpc-js/src/retrying-call.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index a7af83d6d..48aaf48ac 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -159,7 +159,7 @@ export class LoadBalancingCall implements Call { }, onReceiveStatus: status => { this.trace('Received status'); - if (status.code === http2.constants.NGHTTP2_REFUSED_STREAM) { + if (status.rstCode === http2.constants.NGHTTP2_REFUSED_STREAM) { this.outputStatus(status, 'REFUSED'); } else { this.outputStatus(status, 'PROCESSED'); diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 71dedd46f..a85fac67c 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -385,7 +385,7 @@ export class RetryingCall implements Call { if (this.underlyingCalls[callIndex].state === 'COMPLETED') { return; } - this.trace('state=' + this.state + ' handling status from child [' + this.underlyingCalls[callIndex].call.getCallNumber() + '] in state ' + this.underlyingCalls[callIndex].state); + this.trace('state=' + this.state + ' handling status with progress ' + status.progress + ' from child [' + this.underlyingCalls[callIndex].call.getCallNumber() + '] in state ' + this.underlyingCalls[callIndex].state); this.underlyingCalls[callIndex].state = 'COMPLETED'; if (status.code === Status.OK) { this.retryThrottler?.addCallSucceeded(); From 47ba3578610db38c0b8c4dff1ddc009d0054a9ed Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Nov 2022 09:34:16 -0800 Subject: [PATCH 1810/1899] Fix typo in service config validation error messages --- packages/grpc-js/src/service-config.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/service-config.ts b/packages/grpc-js/src/service-config.ts index 2b8c0a7eb..201c0c648 100644 --- a/packages/grpc-js/src/service-config.ts +++ b/packages/grpc-js/src/service-config.ts @@ -133,14 +133,14 @@ function validateRetryPolicy(obj: any): RetryPolicy { for (const value of obj.retryableStatusCodes) { if (typeof value === 'number') { if (!Object.values(Status).includes(value)) { - throw new Error('Invlid method config retry policy: retryableStatusCodes value not in status code range'); + throw new Error('Invalid method config retry policy: retryableStatusCodes value not in status code range'); } } else if (typeof value === 'string') { if (!Object.values(Status).includes(value.toUpperCase())) { - throw new Error('Invlid method config retry policy: retryableStatusCodes value not a status code name'); + throw new Error('Invalid method config retry policy: retryableStatusCodes value not a status code name'); } } else { - throw new Error('Invlid method config retry policy: retryableStatusCodes value must be a string or number'); + throw new Error('Invalid method config retry policy: retryableStatusCodes value must be a string or number'); } } return { From f1f351f3cde6c2975785d622de63cdf9a7132984 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Nov 2022 11:09:16 -0800 Subject: [PATCH 1811/1899] Fix handling of messages that overflow the buffer limit --- packages/grpc-js/src/retrying-call.ts | 64 ++++++++++++++++++++------- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index a85fac67c..8d3bb6579 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -135,6 +135,12 @@ interface WriteBufferEntry { * state. */ callback?: WriteCallback; + /** + * Indicates whether the message is allocated in the buffer tracker. Ignored + * if entryType is not MESSAGE. Should be the return value of + * bufferTracker.allocate. + */ + allocated: boolean; } const PREVIONS_RPC_ATTEMPTS_METADATA_KEY = 'grpc-previous-rpc-attempts'; @@ -216,6 +222,22 @@ export class RetryingCall implements Call { } } + private maybefreeMessageBufferEntry(messageIndex: number) { + if (this.state !== 'COMMITTED') { + return; + } + const bufferEntry = this.writeBuffer[messageIndex]; + if (bufferEntry.entryType === 'MESSAGE') { + if (bufferEntry.allocated) { + this.bufferTracker.free(bufferEntry.message!.message.length, this.callNumber); + } + this.writeBuffer[messageIndex] = { + entryType: 'FREED', + allocated: false + }; + } + } + private commitCall(index: number) { if (this.state === 'COMMITTED') { return; @@ -237,13 +259,7 @@ export class RetryingCall implements Call { this.underlyingCalls[i].call.cancelWithStatus(Status.CANCELLED, 'Discarded in favor of other hedged attempt'); } for (let messageIndex = 0; messageIndex < this.underlyingCalls[index].nextMessageToSend - 1; messageIndex += 1) { - const bufferEntry = this.writeBuffer[messageIndex]; - if (bufferEntry.entryType === 'MESSAGE') { - this.bufferTracker.free(bufferEntry.message!.message.length, this.callNumber); - this.writeBuffer[messageIndex] = { - entryType: 'FREED' - }; - } + this.maybefreeMessageBufferEntry(messageIndex); } } @@ -513,6 +529,15 @@ export class RetryingCall implements Call { this.maybeStartHedgingTimer(); } + private handleChildWriteCompleted(childIndex: number) { + const childCall = this.underlyingCalls[childIndex]; + const messageIndex = childCall.nextMessageToSend; + this.writeBuffer[messageIndex].callback?.(); + this.maybefreeMessageBufferEntry(messageIndex); + childCall.nextMessageToSend += 1; + this.sendNextChildMessage(childIndex); + } + private sendNextChildMessage(childIndex: number) { const childCall = this.underlyingCalls[childIndex]; if (childCall.state === 'COMPLETED') { @@ -525,8 +550,7 @@ export class RetryingCall implements Call { childCall.call.sendMessageWithContext({ callback: (error) => { // Ignore error - childCall.nextMessageToSend += 1; - this.sendNextChildMessage(childIndex); + this.handleChildWriteCompleted(childIndex); } }, bufferEntry.message!.message); break; @@ -550,25 +574,34 @@ export class RetryingCall implements Call { const messageIndex = this.writeBuffer.length; const bufferEntry: WriteBufferEntry = { entryType: 'MESSAGE', - message: writeObj + message: writeObj, + allocated: this.bufferTracker.allocate(message.length, this.callNumber) }; this.writeBuffer[messageIndex] = bufferEntry; - if (this.bufferTracker.allocate(message.length, this.callNumber)) { + if (bufferEntry.allocated) { context.callback?.(); for (const [callIndex, call] of this.underlyingCalls.entries()) { if (call.state === 'ACTIVE' && call.nextMessageToSend === messageIndex) { call.call.sendMessageWithContext({ callback: (error) => { // Ignore error - call.nextMessageToSend += 1; - this.sendNextChildMessage(callIndex); + this.handleChildWriteCompleted(callIndex); } }, message); } } } else { this.commitCallWithMostMessages(); - bufferEntry.callback = context.callback; + const call = this.underlyingCalls[this.committedCallIndex!]; + bufferEntry.callback = context.callback; + if (call.state === 'ACTIVE' && call.nextMessageToSend === messageIndex) { + call.call.sendMessageWithContext({ + callback: (error) => { + // Ignore error + this.handleChildWriteCompleted(this.committedCallIndex!); + } + }, message); + } } } startRead(): void { @@ -584,7 +617,8 @@ export class RetryingCall implements Call { this.trace('halfClose called'); const halfCloseIndex = this.writeBuffer.length; this.writeBuffer[halfCloseIndex] = { - entryType: 'HALF_CLOSE' + entryType: 'HALF_CLOSE', + allocated: false }; for (const call of this.underlyingCalls) { if (call?.state === 'ACTIVE' && call.nextMessageToSend === halfCloseIndex) { From fa21e13ef38dd7cbc44fd1156fd97169c876025e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 17 Nov 2022 11:51:49 -0800 Subject: [PATCH 1812/1899] Limit maxAttempts to 5 for retries and hedging --- packages/grpc-js/src/retrying-call.ts | 6 +-- packages/grpc-js/test/test-retry.ts | 63 +++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 8d3bb6579..f9bda9eb5 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -296,7 +296,7 @@ export class RetryingCall implements Call { return; } const retryPolicy = this.callConfig!.methodConfig.retryPolicy!; - if (this.attempts >= retryPolicy.maxAttempts) { + if (this.attempts >= Math.min(retryPolicy.maxAttempts, 5)) { callback(false); return; } @@ -446,7 +446,7 @@ export class RetryingCall implements Call { return; } const hedgingPolicy = this.callConfig.methodConfig.hedgingPolicy; - if (this.attempts >= hedgingPolicy.maxAttempts) { + if (this.attempts >= Math.min(hedgingPolicy.maxAttempts, 5)) { return; } this.attempts += 1; @@ -465,7 +465,7 @@ export class RetryingCall implements Call { return; } const hedgingPolicy = this.callConfig.methodConfig.hedgingPolicy; - if (this.attempts >= hedgingPolicy.maxAttempts) { + if (this.attempts >= Math.min(hedgingPolicy.maxAttempts, 5)) { return; } const hedgingDelayString = hedgingPolicy.hedgingDelay ?? '0s'; diff --git a/packages/grpc-js/test/test-retry.ts b/packages/grpc-js/test/test-retry.ts index 4dd96cc43..66c0f7941 100644 --- a/packages/grpc-js/test/test-retry.ts +++ b/packages/grpc-js/test/test-retry.ts @@ -216,6 +216,39 @@ describe('Retries', () => { } ); }); + + it('Should not be able to make more than 5 attempts', (done) => { + const serviceConfig = { + loadBalancingConfig: [], + methodConfig: [ + { + name: [{ + service: 'EchoService' + }], + retryPolicy: { + maxAttempts: 10, + initialBackoff: '0.1s', + maxBackoff: '10s', + backoffMultiplier: 1.2, + retryableStatusCodes: [14, 'RESOURCE_EXHAUSTED'] + } + } + ] + } + const client2 = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(serviceConfig)}); + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '6'); + metadata.set('respond-with-status', `${grpc.status.RESOURCE_EXHAUSTED}`); + client2.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.details, 'Failed on retry 4'); + done(); + } + ); + }) }); describe('Client with hedging configured', () => { @@ -297,5 +330,35 @@ describe('Retries', () => { } ); }); + + it('Should not be able to make more than 5 attempts', (done) => { + const serviceConfig = { + loadBalancingConfig: [], + methodConfig: [ + { + name: [{ + service: 'EchoService' + }], + hedgingPolicy: { + maxAttempts: 10, + nonFatalStatusCodes: [14, 'RESOURCE_EXHAUSTED'] + } + } + ] + } + const client2 = new EchoService(`localhost:${port}`, grpc.credentials.createInsecure(), {'grpc.service_config': JSON.stringify(serviceConfig)}); + const metadata = new grpc.Metadata(); + metadata.set('succeed-on-retry-attempt', '6'); + metadata.set('respond-with-status', `${grpc.status.RESOURCE_EXHAUSTED}`); + client2.echo( + { value: 'test value', value2: 3 }, + metadata, + (error: grpc.ServiceError, response: any) => { + assert(error); + assert(error.details.startsWith('Failed on retry')); + done(); + } + ); + }) }); }); \ No newline at end of file From 641ed45d489811740dc84dccc2fbf9d460a96b7a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 18 Nov 2022 15:06:41 -0800 Subject: [PATCH 1813/1899] grpc-js-xds: Update failure mode behavior --- packages/grpc-js-xds/src/xds-client.ts | 42 +++++++++++++++---- .../src/xds-stream-state/xds-stream-state.ts | 3 ++ 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 439ed80ea..2dfa41236 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -18,7 +18,7 @@ import * as protoLoader from '@grpc/proto-loader'; // This is a non-public, unstable API, but it's very convenient import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; -import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials, Channel } from '@grpc/grpc-js'; +import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials, Channel, connectivityState } from '@grpc/grpc-js'; import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; import { loadBootstrapInfo } from './xds-bootstrap'; @@ -255,6 +255,7 @@ export class XdsClient { DiscoveryRequest, DiscoveryResponse__Output > | null = null; + private receivedAdsResponseOnCurrentStream = false; private lrsNode: Node | null = null; private lrsClient: LoadReportingServiceClient | null = null; @@ -373,6 +374,9 @@ export class XdsClient { {channelOverride: channel} ); this.maybeStartAdsStream(); + channel.watchConnectivityState(channel.getConnectivityState(false), Infinity, () => { + this.handleAdsConnectivityStateUpdate(); + }) this.lrsClient = new protoDefinitions.envoy.service.load_stats.v3.LoadReportingService( serverUri, @@ -394,7 +398,29 @@ export class XdsClient { clearInterval(this.statsTimer); } + private handleAdsConnectivityStateUpdate() { + if (!this.adsClient) { + return; + } + const state = this.adsClient.getChannel().getConnectivityState(false); + if (state === connectivityState.READY && this.adsCall) { + this.reportAdsStreamStarted(); + } + if (state === connectivityState.TRANSIENT_FAILURE) { + this.reportStreamError({ + code: status.UNAVAILABLE, + details: 'No connection established to xDS server', + metadata: new Metadata() + }); + } + this.adsClient.getChannel().watchConnectivityState(state, Infinity, () => { + this.handleAdsConnectivityStateUpdate(); + }); + } + private handleAdsResponse(message: DiscoveryResponse__Output) { + this.receivedAdsResponseOnCurrentStream = true; + this.adsBackoff.reset(); let handleResponseResult: { result: HandleResponseResult; serviceKind: AdsServiceKind; @@ -466,7 +492,7 @@ export class XdsClient { 'ADS stream ended. code=' + streamStatus.code + ' details= ' + streamStatus.details ); this.adsCall = null; - if (streamStatus.code !== status.OK) { + if (streamStatus.code !== status.OK && !this.receivedAdsResponseOnCurrentStream) { this.reportStreamError(streamStatus); } /* If the backoff timer is no longer running, we do not need to wait any @@ -496,7 +522,9 @@ export class XdsClient { if (this.adsCall !== null) { return; } - this.adsCall = this.adsClient.StreamAggregatedResources(); + this.receivedAdsResponseOnCurrentStream = false; + const metadata = new Metadata({waitForReady: true}); + this.adsCall = this.adsClient.StreamAggregatedResources(metadata); this.adsCall.on('data', (message: DiscoveryResponse__Output) => { this.handleAdsResponse(message); }); @@ -515,7 +543,9 @@ export class XdsClient { this.updateNames(service); } } - this.reportAdsStreamStarted(); + if (this.adsClient.getChannel().getConnectivityState(false) === connectivityState.READY) { + this.reportAdsStreamStarted(); + } } private maybeSendAdsMessage(typeUrl: string, resourceNames: string[], responseNonce: string, versionInfo: string, errorMessage?: string) { @@ -547,10 +577,6 @@ export class XdsClient { * version info are updated so that it sends the post-update values. */ ack(serviceKind: AdsServiceKind) { - /* An ack is the best indication of a successful interaction between the - * client and the server, so we can reset the backoff timer here. */ - this.adsBackoff.reset(); - this.updateNames(serviceKind); } diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index 86c2cea4b..e20bc7e9b 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -213,6 +213,9 @@ export abstract class BaseXdsStreamState implements XdsStreamState } reportAdsStreamStart() { + if (this.isAdsStreamRunning) { + return; + } this.isAdsStreamRunning = true; for (const subscriptionEntry of this.subscriptions.values()) { if (subscriptionEntry.cachedResponse === null) { From 6b4dd60f1130f1f8aea6c4df111666cb3965f024 Mon Sep 17 00:00:00 2001 From: natiz Date: Sun, 27 Nov 2022 23:37:56 +0200 Subject: [PATCH 1814/1899] fix: windows build --- packages/grpc-tools/CMakeLists.txt | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 9d6690ba7..14fb3c943 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -1,17 +1,21 @@ -cmake_minimum_required(VERSION 3.6) +cmake_minimum_required(VERSION 3.15) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) +# MSVC runtime library flags are selected by an abstraction. +if(COMMAND cmake_policy AND POLICY CMP0091) + cmake_policy(SET CMP0091 NEW) +endif() + set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) -set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/protobuf) -add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake deps/protobuf) - set(protobuf_BUILD_TESTS OFF CACHE BOOL "Build protobuf tests") set(protobuf_WITH_ZLIB OFF CACHE BOOL "Build protobuf with zlib.") +set(PROTOBUF_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps/protobuf) +add_subdirectory(${PROTOBUF_ROOT_DIR}/cmake deps/protobuf) set(CMAKE_EXE_LINKER_FLAGS "-static-libstdc++") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-stack-protector") @@ -22,7 +26,7 @@ add_executable(grpc_node_plugin ) if (MSVC) - add_definitions(/MTd) + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>) endif (MSVC) target_include_directories(grpc_node_plugin @@ -34,4 +38,4 @@ target_include_directories(grpc_node_plugin target_link_libraries(grpc_node_plugin libprotoc libprotobuf -) \ No newline at end of file +) From edf612a56af58b3f8829bb78741639d75b19db3e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 29 Nov 2022 14:29:47 -0500 Subject: [PATCH 1815/1899] grpc-js-xds: Implement retry support --- packages/grpc-js-xds/src/environment.ts | 3 +- packages/grpc-js-xds/src/resolver-xds.ts | 54 +++++++++++++++++-- packages/grpc-js-xds/src/route-action.ts | 31 ++++------- .../src/xds-stream-state/rds-state.ts | 43 ++++++++++++++- packages/grpc-js/src/experimental.ts | 2 +- 5 files changed, 104 insertions(+), 29 deletions(-) diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index 250f791ac..47222f8a4 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -16,4 +16,5 @@ */ export const EXPERIMENTAL_FAULT_INJECTION = (process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION ?? 'true') === 'true'; -export const EXPERIMENTAL_OUTLIER_DETECTION = (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; \ No newline at end of file +export const EXPERIMENTAL_OUTLIER_DETECTION = (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; +export const EXPERIMENTAL_RETRY = process.env.GRPC_XDS_EXPERIMENTAL_ENABLE_RETRY === 'true'; \ No newline at end of file diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 496c37094..401465be6 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -44,9 +44,10 @@ import { decodeSingleResource, HTTP_CONNECTION_MANGER_TYPE_URL } from './resourc import Duration = experimental.Duration; import { Duration__Output } from './generated/google/protobuf/Duration'; import { createHttpFilter, HttpFilterConfig, parseOverrideFilterConfig, parseTopLevelFilterConfig } from './http-filter'; -import { EXPERIMENTAL_FAULT_INJECTION } from './environment'; +import { EXPERIMENTAL_FAULT_INJECTION, EXPERIMENTAL_RETRY } from './environment'; import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; +import RetryPolicy = experimental.RetryPolicy; const TRACER_NAME = 'xds_resolver'; @@ -199,6 +200,24 @@ function protoDurationToDuration(duration: Duration__Output): Duration { } } +function protoDurationToSecondsString(duration: Duration__Output): string { + return `${duration.seconds + duration.nanos / 1_000_000_000}s`; +} + +const DEFAULT_RETRY_BASE_INTERVAL = '0.025s' + +function getDefaultRetryMaxInterval(baseInterval: string): string { + return `${Number.parseFloat(baseInterval.substring(0, baseInterval.length - 1)) * 10}s`; +} + +const RETRY_CODES: {[key: string]: status} = { + 'cancelled': status.CANCELLED, + 'deadline-exceeded': status.DEADLINE_EXCEEDED, + 'internal': status.INTERNAL, + 'resource-exhausted': status.RESOURCE_EXHAUSTED, + 'unavailable': status.UNAVAILABLE +}; + class XdsResolver implements Resolver { private hasReportedSuccess = false; @@ -363,6 +382,33 @@ class XdsResolver implements Resolver { } } } + let retryPolicy: RetryPolicy | undefined = undefined; + if (EXPERIMENTAL_RETRY) { + const retryConfig = route.route!.retry_policy ?? virtualHost.retry_policy; + if (retryConfig) { + const retryableStatusCodes = []; + for (const code of retryConfig.retry_on.split(',')) { + if (RETRY_CODES[code]) { + retryableStatusCodes.push(RETRY_CODES[code]); + } + } + if (retryableStatusCodes.length > 0) { + const baseInterval = retryConfig.retry_back_off?.base_interval ? + protoDurationToSecondsString(retryConfig.retry_back_off.base_interval) : + DEFAULT_RETRY_BASE_INTERVAL; + const maxInterval = retryConfig.retry_back_off?.max_interval ? + protoDurationToSecondsString(retryConfig.retry_back_off.max_interval) : + getDefaultRetryMaxInterval(baseInterval); + retryPolicy = { + backoffMultiplier: 2, + initialBackoff: baseInterval, + maxBackoff: maxInterval, + maxAttempts: (retryConfig.num_retries?.value ?? 1) + 1, + retryableStatusCodes: retryableStatusCodes + }; + } + } + } switch (route.route!.cluster_specifier) { case 'cluster_header': continue; @@ -390,7 +436,7 @@ class XdsResolver implements Resolver { } } } - routeAction = new SingleClusterRouteAction(cluster, timeout, extraFilterFactories); + routeAction = new SingleClusterRouteAction(cluster, {name: [], timeout: timeout, retryPolicy: retryPolicy}, extraFilterFactories); break; } case 'weighted_clusters': { @@ -432,7 +478,7 @@ class XdsResolver implements Resolver { } weightedClusters.push({name: clusterWeight.name, weight: clusterWeight.weight?.value ?? 0, dynamicFilterFactories: extraFilterFactories}); } - routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100, timeout); + routeAction = new WeightedClusterRouteAction(weightedClusters, route.route!.weighted_clusters!.total_weight?.value ?? 100, {name: [], timeout: timeout, retryPolicy: retryPolicy}); break; } default: @@ -470,7 +516,7 @@ class XdsResolver implements Resolver { this.unrefCluster(clusterResult.name); } return { - methodConfig: {name: [], timeout: action.getTimeout()}, + methodConfig: clusterResult.methodConfig, onCommitted: onCommitted, pickInformation: {cluster: clusterResult.name}, status: status.OK, diff --git a/packages/grpc-js-xds/src/route-action.ts b/packages/grpc-js-xds/src/route-action.ts index d29e67b9b..5ae5885af 100644 --- a/packages/grpc-js-xds/src/route-action.ts +++ b/packages/grpc-js-xds/src/route-action.ts @@ -18,16 +18,17 @@ import { experimental } from '@grpc/grpc-js'; import Duration = experimental.Duration; import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; +import MethodConfig = experimental.MethodConfig; export interface ClusterResult { name: string; + methodConfig: MethodConfig; dynamicFilterFactories: FilterFactory[]; } export interface RouteAction { toString(): string; getCluster(): ClusterResult; - getTimeout(): Duration | undefined; } function durationToLogString(duration: Duration) { @@ -40,25 +41,18 @@ function durationToLogString(duration: Duration) { } export class SingleClusterRouteAction implements RouteAction { - constructor(private cluster: string, private timeout: Duration | undefined, private extraFilterFactories: FilterFactory[]) {} + constructor(private cluster: string, private methodConfig: MethodConfig, private extraFilterFactories: FilterFactory[]) {} getCluster() { return { name: this.cluster, + methodConfig: this.methodConfig, dynamicFilterFactories: this.extraFilterFactories }; } toString() { - if (this.timeout) { - return 'SingleCluster(' + this.cluster + ', ' + 'timeout=' + durationToLogString(this.timeout) + 's)'; - } else { - return 'SingleCluster(' + this.cluster + ')'; - } - } - - getTimeout() { - return this.timeout; + return 'SingleCluster(' + this.cluster + ', ' + JSON.stringify(this.methodConfig) + ')'; } } @@ -79,7 +73,7 @@ export class WeightedClusterRouteAction implements RouteAction { * The weighted cluster choices represented as a CDF */ private clusterChoices: ClusterChoice[]; - constructor(private clusters: WeightedCluster[], private totalWeight: number, private timeout: Duration | undefined) { + constructor(private clusters: WeightedCluster[], private totalWeight: number, private methodConfig: MethodConfig) { this.clusterChoices = []; let lastNumerator = 0; for (const clusterWeight of clusters) { @@ -94,24 +88,17 @@ export class WeightedClusterRouteAction implements RouteAction { if (randomNumber < choice.numerator) { return { name: choice.name, + methodConfig: this.methodConfig, dynamicFilterFactories: choice.dynamicFilterFactories }; } } // This should be prevented by the validation rules - return {name: '', dynamicFilterFactories: []}; + return {name: '', methodConfig: this.methodConfig, dynamicFilterFactories: []}; } toString() { const clusterListString = this.clusters.map(({name, weight}) => '(' + name + ':' + weight + ')').join(', ') - if (this.timeout) { - return 'WeightedCluster(' + clusterListString + ', ' + 'timeout=' + durationToLogString(this.timeout) + 's)'; - } else { - return 'WeightedCluster(' + clusterListString + ')'; - } - } - - getTimeout() { - return this.timeout; + return 'WeightedCluster(' + clusterListString + ', ' + JSON.stringify(this.methodConfig) + ')'; } } \ No newline at end of file diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 119ac6b92..891eb7c8e 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -15,8 +15,10 @@ * */ -import { EXPERIMENTAL_FAULT_INJECTION } from "../environment"; +import { EXPERIMENTAL_FAULT_INJECTION, EXPERIMENTAL_RETRY } from "../environment"; +import { RetryPolicy__Output } from "../generated/envoy/config/route/v3/RetryPolicy"; import { RouteConfiguration__Output } from "../generated/envoy/config/route/v3/RouteConfiguration"; +import { Duration__Output } from "../generated/google/protobuf/Duration"; import { validateOverrideFilter } from "../http-filter"; import { BaseXdsStreamState, XdsStreamState } from "./xds-stream-state"; @@ -30,6 +32,13 @@ const SUPPPORTED_HEADER_MATCH_SPECIFIERS = [ 'suffix_match']; const SUPPORTED_CLUSTER_SPECIFIERS = ['cluster', 'weighted_clusters', 'cluster_header']; +function durationToMs(duration: Duration__Output | null): number | null { + if (duration === null) { + return null; + } + return (Number.parseInt(duration.seconds) * 1000 + duration.nanos / 1_000_000) | 0; +} + export class RdsState extends BaseXdsStreamState implements XdsStreamState { protected isStateOfTheWorld(): boolean { return false; @@ -40,6 +49,28 @@ export class RdsState extends BaseXdsStreamState imp protected getProtocolName(): string { return 'RDS'; } + + private validateRetryPolicy(policy: RetryPolicy__Output | null): boolean { + if (policy === null) { + return true; + } + const numRetries = policy.num_retries?.value ?? 1 + if (numRetries < 1) { + return false; + } + if (policy.retry_back_off) { + if (!policy.retry_back_off.base_interval) { + return false; + } + const baseInterval = durationToMs(policy.retry_back_off.base_interval)!; + const maxInterval = durationToMs(policy.retry_back_off.max_interval) ?? (10 * baseInterval); + if (!(maxInterval >= baseInterval) && (baseInterval > 0)) { + return false; + } + } + return true; + } + validateResponse(message: RouteConfiguration__Output): boolean { // https://github.com/grpc/proposal/blob/master/A28-xds-traffic-splitting-and-routing.md#response-validation for (const virtualHost of message.virtual_hosts) { @@ -62,6 +93,11 @@ export class RdsState extends BaseXdsStreamState imp } } } + if (EXPERIMENTAL_RETRY) { + if (!this.validateRetryPolicy(virtualHost.retry_policy)) { + return false; + } + } for (const route of virtualHost.routes) { const match = route.match; if (!match) { @@ -88,6 +124,11 @@ export class RdsState extends BaseXdsStreamState imp } } } + if (EXPERIMENTAL_RETRY) { + if (!this.validateRetryPolicy(route.route.retry_policy)) { + return false; + } + } if (route.route!.cluster_specifier === 'weighted_clusters') { if (route.route.weighted_clusters!.total_weight?.value === 0) { return false; diff --git a/packages/grpc-js/src/experimental.ts b/packages/grpc-js/src/experimental.ts index 92d6d44c6..a7c28219b 100644 --- a/packages/grpc-js/src/experimental.ts +++ b/packages/grpc-js/src/experimental.ts @@ -7,7 +7,7 @@ export { } from './resolver'; export { GrpcUri, uriToString } from './uri-parser'; export { Duration, durationToMs } from './duration'; -export { ServiceConfig } from './service-config'; +export { ServiceConfig, MethodConfig, RetryPolicy } from './service-config'; export { BackoffTimeout } from './backoff-timeout'; export { LoadBalancer, From 6f755fe3469b888e7c0bca775f8eac430d0c8fb7 Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Wed, 30 Nov 2022 22:31:22 +0900 Subject: [PATCH 1816/1899] add branded option for proto-loader-gen-types --- packages/proto-loader/bin/proto-loader-gen-types.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index a9ee4a6ed..ae7e147b5 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -45,6 +45,7 @@ type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeComments?: boolean; inputTemplate: string; outputTemplate: string; + branded: boolean; } class TextFormatter { @@ -263,6 +264,9 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp } formatter.writeLine(`'${oneof.name}'?: ${typeString};`); } + if (options.branded) { + formatter.writeLine(`__type: '${messageType.fullName}'`) + } formatter.unindent(); formatter.writeLine('}'); } @@ -383,6 +387,9 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp formatter.writeLine(`'${oneof.name}': ${typeString};`); } } + if (options.branded) { + formatter.writeLine(`__type: '${messageType.fullName}'`) + } formatter.unindent(); formatter.writeLine('}'); } @@ -815,7 +822,7 @@ async function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments', 'branded']) .string(['longs', 'enums', 'bytes', 'inputTemplate', 'outputTemplate']) .default('keepCase', false) .default('defaults', false) @@ -829,6 +836,7 @@ async function runScript() { .default('bytes', 'Buffer') .default('inputTemplate', `${templateStr}`) .default('outputTemplate', `${templateStr}__Output`) + .default('branded', false) .coerce('longs', value => { switch (value) { case 'String': return String; @@ -868,6 +876,7 @@ async function runScript() { grpcLib: 'The gRPC implementation library that these types will be used with', inputTemplate: 'Template for mapping input or "permissive" type names', outputTemplate: 'Template for mapping output or "restricted" type names', + branded: 'Emit property for branded type whose value is fullName of the Message', }).demandOption(['outDir', 'grpcLib']) .demand(1) .usage('$0 [options] filenames...') From 9e548d4d87c55f2710aa5a62968fa1df565da5d4 Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Wed, 30 Nov 2022 22:34:15 +0900 Subject: [PATCH 1817/1899] update readme --- packages/proto-loader/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 818f0efda..740658786 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -92,6 +92,8 @@ Options: [string] [default: "%s"] --outputTemplate Template for mapping output or "restricted" type names [string] [default: "%s__Output"] + --branded Emit property for branded type whose value is fullName + of the Message [boolean] [default: false] ``` ### Example Usage From 87e70e890bc37c50791c03fb6dd18d1728f1448e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 30 Nov 2022 13:59:03 -0500 Subject: [PATCH 1818/1899] grpc-tools: Update native build docker image --- tools/release/native/Dockerfile | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/release/native/Dockerfile b/tools/release/native/Dockerfile index d065bddbe..7346d9aff 100644 --- a/tools/release/native/Dockerfile +++ b/tools/release/native/Dockerfile @@ -1,11 +1,7 @@ -FROM debian:jessie +FROM debian:stretch -RUN echo "deb http://archive.debian.org/debian jessie-backports main" > /etc/apt/sources.list.d/backports.list -RUN echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf -RUN sed -i '/deb http:\/\/deb.debian.org\/debian jessie-updates main/d' /etc/apt/sources.list RUN apt-get update -RUN apt-get -t jessie-backports install -y cmake -RUN apt-get install -y curl build-essential python libc6-dev-i386 lib32stdc++-4.9-dev jq +RUN apt-get install -y cmake curl build-essential python libc6-dev-i386 lib32stdc++-6-dev jq RUN mkdir /usr/local/nvm ENV NVM_DIR /usr/local/nvm From b07b74bfd4c1e6886b046371772fc14b98c34e63 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 30 Nov 2022 15:40:49 -0500 Subject: [PATCH 1819/1899] Update information in README and PACKAGE-COMPARISON docs --- PACKAGE-COMPARISON.md | 10 +++++----- README.md | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index f0c444195..cd6308892 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -1,6 +1,6 @@ # Feature comparison of `grpc` and `@grpc/grpc-js` packages -Feature | `grpc` | `@grpc/grpc-js` +Feature | `grpc` (deprecated) | `@grpc/grpc-js` --------|--------|---------- Client | :heavy_check_mark: | :heavy_check_mark: Server | :heavy_check_mark: | :heavy_check_mark: @@ -9,7 +9,7 @@ Streaming RPCs | :heavy_check_mark: | :heavy_check_mark: Deadlines | :heavy_check_mark: | :heavy_check_mark: Cancellation | :heavy_check_mark: | :heavy_check_mark: Automatic Reconnection | :heavy_check_mark: | :heavy_check_mark: -Per-message Compression | :heavy_check_mark: | only for response messages +Per-message Compression | :heavy_check_mark: | :heavy_check_mark: (except messages sent by the server) Channel State | :heavy_check_mark: | :heavy_check_mark: JWT Access and Service Account Credentials | provided by the [Google Auth Library](https://www.npmjs.com/package/google-auth-library) | provided by the [Google Auth Library](https://www.npmjs.com/package/google-auth-library) Interceptors | :heavy_check_mark: | :heavy_check_mark: @@ -17,14 +17,14 @@ Connection Keepalives | :heavy_check_mark: | :heavy_check_mark: HTTP Connect Support | :heavy_check_mark: | :heavy_check_mark: Retries | :heavy_check_mark: | :x: Stats/tracing/monitoring | :heavy_check_mark: | :x: -Load Balancing | :heavy_check_mark: | Pick first and round robin +Load Balancing | :heavy_check_mark: | :heavy_check_mark: Initial Metadata Options | :heavy_check_mark: | only `waitForReady` Other Properties | `grpc` | `@grpc/grpc-js` -----------------|--------|---------------- Pure JavaScript Code | :x: | :heavy_check_mark: -Supported Node Versions | >= 4 | ^8.13.0 or >=10.10.0 -Supported Electron Versions | All | >= 3 +Supported Node Versions | >= 4 and <=14 | ^8.13.0 or >=10.10.0 +Supported Electron Versions | <=11.2 | >= 3 Supported Platforms | Linux, Windows, MacOS | All Supported Architectures | x86, x86-64, ARM7+ | All diff --git a/README.md b/README.md index 159fbab4f..f0f215ce3 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,21 @@ For a comparison of the features available in these two libraries, see [this document](https://github.com/grpc/grpc-node/tree/master/PACKAGE-COMPARISON.md) -### C-based Client and Server +### Pure JavaScript Client and Server -Directory: [`packages/grpc-native-core`](https://github.com/grpc/grpc-node/tree/grpc@1.24.x/packages/grpc-native-core) (lives in the `grpc@1.24.x` branch) (see here for installation information) +Directory: [`packages/grpc-js`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) -npm package: [grpc](https://www.npmjs.com/package/grpc). +npm package: [@grpc/grpc-js](https://www.npmjs.com/package/@grpc/grpc-js) -This is the existing, feature-rich implementation of gRPC using a C++ addon. It works on all LTS versions of Node.js on most platforms that Node.js runs on. +This library implements the core functionality of gRPC purely in JavaScript, without a C++ addon. It works on the latest versions of Node.js on all platforms that Node.js runs on. -### Pure JavaScript Client +### C-based Client and Server (deprecated) -Directory: [`packages/grpc-js`](https://github.com/grpc/grpc-node/tree/master/packages/grpc-js) +Directory: [`packages/grpc-native-core`](https://github.com/grpc/grpc-node/tree/grpc@1.24.x/packages/grpc-native-core) (lives in the `grpc@1.24.x` branch) (see here for installation information) -npm package: [@grpc/grpc-js](https://www.npmjs.com/package/@grpc/grpc-js) +npm package: [grpc](https://www.npmjs.com/package/grpc). -This library implements the core functionality of gRPC purely in JavaScript, without a C++ addon. It works on the latest version of Node.js on all platforms that Node.js runs on. +This is the deprecated implementation of gRPC using a C++ addon. It works on versions of Node.js up to 14 on most platforms that Node.js runs on. ## Other Packages From e955c47bd51332e5cf08ac3b3b02c396ebe124f0 Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Thu, 1 Dec 2022 11:09:09 +0900 Subject: [PATCH 1820/1899] rename as outputBranded --- .../bin/proto-loader-gen-types.ts | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index ae7e147b5..6327da951 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -37,6 +37,9 @@ const useNameFmter = ({outputTemplate, inputTemplate}: GeneratorOptions) => { }; } +const typeBrandHint = `This field is a type brand and is not populated at runtime. Instances of this type should be created using type assertions. +https://github.com/grpc/grpc-node/pull/2281`; + type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeDirs?: string[]; grpcLib: string; @@ -45,7 +48,7 @@ type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeComments?: boolean; inputTemplate: string; outputTemplate: string; - branded: boolean; + outputBranded: boolean; } class TextFormatter { @@ -179,6 +182,11 @@ function formatComment(formatter: TextFormatter, comment?: string | null) { formatter.writeLine(' */'); } +function formatTypeBrand(formatter: TextFormatter, messageType: Protobuf.Type) { + formatComment(formatter, typeBrandHint); + formatter.writeLine(`__type: '${messageType.fullName}'`); +} + // GENERATOR FUNCTIONS function getTypeNamePermissive(fieldType: string, resolvedType: Protobuf.Type | Protobuf.Enum | null, repeated: boolean, map: boolean, options: GeneratorOptions): string { @@ -264,9 +272,9 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp } formatter.writeLine(`'${oneof.name}'?: ${typeString};`); } - if (options.branded) { - formatter.writeLine(`__type: '${messageType.fullName}'`) - } + // if (options.inputBranded) { + // formatTypeBrand(formatter, messageType); + // } formatter.unindent(); formatter.writeLine('}'); } @@ -387,8 +395,8 @@ function generateRestrictedMessageInterface(formatter: TextFormatter, messageTyp formatter.writeLine(`'${oneof.name}': ${typeString};`); } } - if (options.branded) { - formatter.writeLine(`__type: '${messageType.fullName}'`) + if (options.outputBranded) { + formatTypeBrand(formatter, messageType); } formatter.unindent(); formatter.writeLine('}'); @@ -822,7 +830,7 @@ async function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments', 'branded']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments', 'outputBranded']) .string(['longs', 'enums', 'bytes', 'inputTemplate', 'outputTemplate']) .default('keepCase', false) .default('defaults', false) @@ -836,7 +844,7 @@ async function runScript() { .default('bytes', 'Buffer') .default('inputTemplate', `${templateStr}`) .default('outputTemplate', `${templateStr}__Output`) - .default('branded', false) + .default('outputBranded', false) .coerce('longs', value => { switch (value) { case 'String': return String; @@ -876,7 +884,7 @@ async function runScript() { grpcLib: 'The gRPC implementation library that these types will be used with', inputTemplate: 'Template for mapping input or "permissive" type names', outputTemplate: 'Template for mapping output or "restricted" type names', - branded: 'Emit property for branded type whose value is fullName of the Message', + outputBranded: 'Output property for branded type for "restricted" types with fullName of the Message as its value', }).demandOption(['outDir', 'grpcLib']) .demand(1) .usage('$0 [options] filenames...') From 927c29de4ad8ac3f8642b6468fdd59d0cf587361 Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Thu, 1 Dec 2022 12:37:48 +0900 Subject: [PATCH 1821/1899] support both input and output update readme update readme --- packages/proto-loader/README.md | 8 ++++++-- packages/proto-loader/bin/proto-loader-gen-types.ts | 13 +++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 740658786..99b34a05e 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -92,8 +92,12 @@ Options: [string] [default: "%s"] --outputTemplate Template for mapping output or "restricted" type names [string] [default: "%s__Output"] - --branded Emit property for branded type whose value is fullName - of the Message [boolean] [default: false] + --inputBranded Output property for branded type for "permissive" + types with fullName of the Message as its value + [boolean] + --outputBranded Output property for branded type for "restricted" + types with fullName of the Message as its value + [boolean] ``` ### Example Usage diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 6327da951..dc9da1a9d 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -48,7 +48,8 @@ type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeComments?: boolean; inputTemplate: string; outputTemplate: string; - outputBranded: boolean; + inputBranded?: boolean; + outputBranded?: boolean; } class TextFormatter { @@ -272,9 +273,9 @@ function generatePermissiveMessageInterface(formatter: TextFormatter, messageTyp } formatter.writeLine(`'${oneof.name}'?: ${typeString};`); } - // if (options.inputBranded) { - // formatTypeBrand(formatter, messageType); - // } + if (options.inputBranded) { + formatTypeBrand(formatter, messageType); + } formatter.unindent(); formatter.writeLine('}'); } @@ -830,7 +831,7 @@ async function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments', 'outputBranded']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments', 'inputBranded', 'outputBranded']) .string(['longs', 'enums', 'bytes', 'inputTemplate', 'outputTemplate']) .default('keepCase', false) .default('defaults', false) @@ -844,7 +845,6 @@ async function runScript() { .default('bytes', 'Buffer') .default('inputTemplate', `${templateStr}`) .default('outputTemplate', `${templateStr}__Output`) - .default('outputBranded', false) .coerce('longs', value => { switch (value) { case 'String': return String; @@ -884,6 +884,7 @@ async function runScript() { grpcLib: 'The gRPC implementation library that these types will be used with', inputTemplate: 'Template for mapping input or "permissive" type names', outputTemplate: 'Template for mapping output or "restricted" type names', + inputBranded: 'Output property for branded type for "permissive" types with fullName of the Message as its value', outputBranded: 'Output property for branded type for "restricted" types with fullName of the Message as its value', }).demandOption(['outDir', 'grpcLib']) .demand(1) From 256fbd89150e1f69e96a5d631c97745d5f51b169 Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Thu, 1 Dec 2022 13:27:04 +0900 Subject: [PATCH 1822/1899] set defaults for brand option --- packages/proto-loader/README.md | 12 ++++++------ .../proto-loader/bin/proto-loader-gen-types.ts | 14 +++++++++++--- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index 99b34a05e..f10831eeb 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -63,6 +63,12 @@ proto-loader-gen-types.js [options] filenames... Options: --help Show help [boolean] --version Show version number [boolean] + --inputBranded Output property for branded type for "permissive" + types with fullName of the Message as its value + [boolean] [default: false] + --outputBranded Output property for branded type for "restricted" + types with fullName of the Message as its value + [boolean] [default: false] --keepCase Preserve the case of field names [boolean] [default: false] --longs The type that should be used to output 64 bit integer @@ -92,12 +98,6 @@ Options: [string] [default: "%s"] --outputTemplate Template for mapping output or "restricted" type names [string] [default: "%s__Output"] - --inputBranded Output property for branded type for "permissive" - types with fullName of the Message as its value - [boolean] - --outputBranded Output property for branded type for "restricted" - types with fullName of the Message as its value - [boolean] ``` ### Example Usage diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index dc9da1a9d..465f362fe 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -48,8 +48,8 @@ type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeComments?: boolean; inputTemplate: string; outputTemplate: string; - inputBranded?: boolean; - outputBranded?: boolean; + inputBranded: boolean; + outputBranded: boolean; } class TextFormatter { @@ -831,7 +831,7 @@ async function runScript() { .string(['includeDirs', 'grpcLib']) .normalize(['includeDirs', 'outDir']) .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments', 'inputBranded', 'outputBranded']) + .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) .string(['longs', 'enums', 'bytes', 'inputTemplate', 'outputTemplate']) .default('keepCase', false) .default('defaults', false) @@ -864,6 +864,14 @@ async function runScript() { default: return undefined; } }) + .option('inputBranded', { + boolean: true, + default: false, + }) + .option('outputBranded', { + boolean: true, + default: false, + }) .alias({ includeDirs: 'I', outDir: 'O', From 80332044c73ba0789efc563b329fd9c9257cad6b Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Thu, 1 Dec 2022 14:12:10 +0900 Subject: [PATCH 1823/1899] update typeBrandHint location --- packages/proto-loader/bin/proto-loader-gen-types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 465f362fe..5a9a32f88 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -37,9 +37,6 @@ const useNameFmter = ({outputTemplate, inputTemplate}: GeneratorOptions) => { }; } -const typeBrandHint = `This field is a type brand and is not populated at runtime. Instances of this type should be created using type assertions. -https://github.com/grpc/grpc-node/pull/2281`; - type GeneratorOptions = Protobuf.IParseOptions & Protobuf.IConversionOptions & { includeDirs?: string[]; grpcLib: string; @@ -183,6 +180,9 @@ function formatComment(formatter: TextFormatter, comment?: string | null) { formatter.writeLine(' */'); } +const typeBrandHint = `This field is a type brand and is not populated at runtime. Instances of this type should be created using type assertions. +https://github.com/grpc/grpc-node/pull/2281`; + function formatTypeBrand(formatter: TextFormatter, messageType: Protobuf.Type) { formatComment(formatter, typeBrandHint); formatter.writeLine(`__type: '${messageType.fullName}'`); From 8ce5bf8c247fa41cba94e4134b44f9001358b227 Mon Sep 17 00:00:00 2001 From: natiz Date: Thu, 1 Dec 2022 14:21:22 +0200 Subject: [PATCH 1824/1899] fix: lower cmake version to 3.7 --- packages/grpc-tools/CMakeLists.txt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 14fb3c943..555346912 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.15) +cmake_minimum_required(VERSION 3.7) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) @@ -26,8 +26,21 @@ add_executable(grpc_node_plugin ) if (MSVC) - set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>) -endif (MSVC) + if (CMAKE_VERSION VERSION_GREATER_EQUAL 3.15) + set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>) + else () + foreach (flag_var + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_RELEASE + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO) + if (${flag_var} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") + endif (${flag_var} MATCHES "/MD") + endforeach (flag_var) + endif () +endif (MVC) target_include_directories(grpc_node_plugin PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} From df8c719ceb881488026a56147d5d4072c816cf25 Mon Sep 17 00:00:00 2001 From: natiz Date: Thu, 1 Dec 2022 18:30:49 +0200 Subject: [PATCH 1825/1899] chore: bump to 1.12.0 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 1c7deb250..333ef1eb1 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.11.3", + "version": "1.12.0", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 161af8ca7b174e96c4703a6c83d75c43fbd05ffc Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 1 Dec 2022 15:53:10 -0500 Subject: [PATCH 1826/1899] grpc-js: Prepare for 1.8.0 release De-experimentalize xDS retry support, and update versions and documentation --- PACKAGE-COMPARISON.md | 2 +- packages/grpc-js-xds/README.md | 3 ++- packages/grpc-js-xds/package.json | 4 ++-- packages/grpc-js-xds/src/environment.ts | 2 +- packages/grpc-js/package.json | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/PACKAGE-COMPARISON.md b/PACKAGE-COMPARISON.md index cd6308892..e6cee8934 100644 --- a/PACKAGE-COMPARISON.md +++ b/PACKAGE-COMPARISON.md @@ -15,7 +15,7 @@ JWT Access and Service Account Credentials | provided by the [Google Auth Librar Interceptors | :heavy_check_mark: | :heavy_check_mark: Connection Keepalives | :heavy_check_mark: | :heavy_check_mark: HTTP Connect Support | :heavy_check_mark: | :heavy_check_mark: -Retries | :heavy_check_mark: | :x: +Retries | :heavy_check_mark: (without hedging) | :heavy_check_mark: (including hedging) Stats/tracing/monitoring | :heavy_check_mark: | :x: Load Balancing | :heavy_check_mark: | :heavy_check_mark: Initial Metadata Options | :heavy_check_mark: | only `waitForReady` diff --git a/packages/grpc-js-xds/README.md b/packages/grpc-js-xds/README.md index bbdd98863..793e0c0d7 100644 --- a/packages/grpc-js-xds/README.md +++ b/packages/grpc-js-xds/README.md @@ -28,4 +28,5 @@ const client = new MyServiceClient('xds:///example.com:123'); - [xDS Circuit Breaking](https://github.com/grpc/proposal/blob/master/A32-xds-circuit-breaking.md) - [xDS Client-Side Fault Injection](https://github.com/grpc/proposal/blob/master/A33-Fault-Injection.md) - [Client Status Discovery Service](https://github.com/grpc/proposal/blob/master/A40-csds-support.md) - - [Outlier Detection](https://github.com/grpc/proposal/blob/master/A50-xds-outlier-detection.md) \ No newline at end of file + - [Outlier Detection](https://github.com/grpc/proposal/blob/master/A50-xds-outlier-detection.md) + - [xDS Retry Support](https://github.com/grpc/proposal/blob/master/A44-xds-retry.md) \ No newline at end of file diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 124c3ed7d..c0c3200f5 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.7.0", + "version": "1.8.0", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { @@ -47,7 +47,7 @@ "re2-wasm": "^1.0.1" }, "peerDependencies": { - "@grpc/grpc-js": "~1.7.0" + "@grpc/grpc-js": "~1.8.0" }, "engines": { "node": ">=10.10.0" diff --git a/packages/grpc-js-xds/src/environment.ts b/packages/grpc-js-xds/src/environment.ts index 47222f8a4..7ec0fd187 100644 --- a/packages/grpc-js-xds/src/environment.ts +++ b/packages/grpc-js-xds/src/environment.ts @@ -17,4 +17,4 @@ export const EXPERIMENTAL_FAULT_INJECTION = (process.env.GRPC_XDS_EXPERIMENTAL_FAULT_INJECTION ?? 'true') === 'true'; export const EXPERIMENTAL_OUTLIER_DETECTION = (process.env.GRPC_EXPERIMENTAL_ENABLE_OUTLIER_DETECTION ?? 'true') === 'true'; -export const EXPERIMENTAL_RETRY = process.env.GRPC_XDS_EXPERIMENTAL_ENABLE_RETRY === 'true'; \ No newline at end of file +export const EXPERIMENTAL_RETRY = (process.env.GRPC_XDS_EXPERIMENTAL_ENABLE_RETRY ?? 'true') === 'true'; \ No newline at end of file diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index cd1c74bb5..9aa685748 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.7.3", + "version": "1.8.0", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From f1e3f6d7d3a291ec47b93f726591ca0c46883f44 Mon Sep 17 00:00:00 2001 From: Taegeun Moon Date: Fri, 2 Dec 2022 23:57:22 +0900 Subject: [PATCH 1827/1899] use option method --- packages/proto-loader/README.md | 12 ++-- .../bin/proto-loader-gen-types.ts | 56 ++++++++++--------- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/proto-loader/README.md b/packages/proto-loader/README.md index f10831eeb..2a7af61e3 100644 --- a/packages/proto-loader/README.md +++ b/packages/proto-loader/README.md @@ -63,12 +63,6 @@ proto-loader-gen-types.js [options] filenames... Options: --help Show help [boolean] --version Show version number [boolean] - --inputBranded Output property for branded type for "permissive" - types with fullName of the Message as its value - [boolean] [default: false] - --outputBranded Output property for branded type for "restricted" - types with fullName of the Message as its value - [boolean] [default: false] --keepCase Preserve the case of field names [boolean] [default: false] --longs The type that should be used to output 64 bit integer @@ -98,6 +92,12 @@ Options: [string] [default: "%s"] --outputTemplate Template for mapping output or "restricted" type names [string] [default: "%s__Output"] + --inputBranded Output property for branded type for "permissive" + types with fullName of the Message as its value + [boolean] [default: false] + --outputBranded Output property for branded type for "restricted" + types with fullName of the Message as its value + [boolean] [default: false] ``` ### Example Usage diff --git a/packages/proto-loader/bin/proto-loader-gen-types.ts b/packages/proto-loader/bin/proto-loader-gen-types.ts index 5a9a32f88..f75822084 100644 --- a/packages/proto-loader/bin/proto-loader-gen-types.ts +++ b/packages/proto-loader/bin/proto-loader-gen-types.ts @@ -824,27 +824,39 @@ async function writeAllFiles(protoFiles: string[], options: GeneratorOptions) { } async function runScript() { + const boolDefaultFalseOption = { + boolean: true, + default: false, + }; const argv = yargs .parserConfiguration({ 'parse-positional-numbers': false }) - .string(['includeDirs', 'grpcLib']) - .normalize(['includeDirs', 'outDir']) - .array('includeDirs') - .boolean(['keepCase', 'defaults', 'arrays', 'objects', 'oneofs', 'json', 'verbose', 'includeComments']) - .string(['longs', 'enums', 'bytes', 'inputTemplate', 'outputTemplate']) - .default('keepCase', false) - .default('defaults', false) - .default('arrays', false) - .default('objects', false) - .default('oneofs', false) - .default('json', false) - .default('includeComments', false) - .default('longs', 'Long') - .default('enums', 'number') - .default('bytes', 'Buffer') - .default('inputTemplate', `${templateStr}`) - .default('outputTemplate', `${templateStr}__Output`) + .option('keepCase', boolDefaultFalseOption) + .option('longs', { string: true, default: 'Long' }) + .option('enums', { string: true, default: 'number' }) + .option('bytes', { string: true, default: 'Buffer' }) + .option('defaults', boolDefaultFalseOption) + .option('arrays', boolDefaultFalseOption) + .option('objects', boolDefaultFalseOption) + .option('oneofs', boolDefaultFalseOption) + .option('json', boolDefaultFalseOption) + .boolean('verbose') + .option('includeComments', boolDefaultFalseOption) + .option('includeDirs', { + normalize: true, + array: true, + alias: 'I' + }) + .option('outDir', { + alias: 'O', + normalize: true, + }) + .option('grpcLib', { string: true }) + .option('inputTemplate', { string: true, default: `${templateStr}` }) + .option('outputTemplate', { string: true, default: `${templateStr}__Output` }) + .option('inputBranded', boolDefaultFalseOption) + .option('outputBranded', boolDefaultFalseOption) .coerce('longs', value => { switch (value) { case 'String': return String; @@ -864,17 +876,7 @@ async function runScript() { default: return undefined; } }) - .option('inputBranded', { - boolean: true, - default: false, - }) - .option('outputBranded', { - boolean: true, - default: false, - }) .alias({ - includeDirs: 'I', - outDir: 'O', verbose: 'v' }).describe({ keepCase: 'Preserve the case of field names', From 488803740e69ea3594c5e60be00d780aa4fab58f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Dec 2022 10:59:50 -0500 Subject: [PATCH 1828/1899] grpc-tools: Force GNU format for artifact tarballs --- packages/grpc-tools/build_binaries.sh | 2 +- packages/grpc-tools/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index e44881083..e25eb1f51 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -47,7 +47,7 @@ artifacts() { arch=$2 dir=$3 - tar -czf $out_dir/$platform-$arch.tar.gz -C $(dirname $dir) $(basename $dir) + tar --format=gnu -czf $out_dir/$platform-$arch.tar.gz -C $(dirname $dir) $(basename $dir) } case $(uname -s) in diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 333ef1eb1..2d10b9272 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.12.0", + "version": "1.12.1", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 2ddd628747c676302d56db86d5ce73eb00d32777 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Dec 2022 11:24:33 -0500 Subject: [PATCH 1829/1899] Use BSD tar-specific options on Mac --- packages/grpc-tools/build_binaries.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index e25eb1f51..c05d7da86 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -46,8 +46,14 @@ artifacts() { platform=$1 arch=$2 dir=$3 - - tar --format=gnu -czf $out_dir/$platform-$arch.tar.gz -C $(dirname $dir) $(basename $dir) + case $(uname -s) in + Linux) + tar -czf $out_dir/$platform-$arch.tar.gz -C $(dirname $dir) $(basename $dir) + ;; + Darwin) + tar --format=gnutar -czf $out_dir/$platform-$arch.tar.gz -C $(dirname $dir) $(basename $dir) + ;; + esac } case $(uname -s) in From 45adf24cf0a99a9d199041214b132f41c27d7045 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Dec 2022 13:46:55 -0500 Subject: [PATCH 1830/1899] grpc-tools: Build for older Mac version --- packages/grpc-tools/CMakeLists.txt | 1 + packages/grpc-tools/package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 555346912..1849ac1af 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -1,4 +1,5 @@ cmake_minimum_required(VERSION 3.7) +set(CMAKE_OSX_DEPLOYMENT_TARGET "11.7" CACHE STRING "Minimum OS X deployment version") if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 2d10b9272..673c2cf90 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.12.1", + "version": "1.12.2", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 11aa7226d882095954aac0dc049f70ef0bade41c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Dec 2022 15:10:42 -0500 Subject: [PATCH 1831/1899] grpc-tools: Build for an older Mac version (attempt 2) --- packages/grpc-tools/CMakeLists.txt | 2 +- packages/grpc-tools/build_binaries.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-tools/CMakeLists.txt b/packages/grpc-tools/CMakeLists.txt index 1849ac1af..60dcdb675 100644 --- a/packages/grpc-tools/CMakeLists.txt +++ b/packages/grpc-tools/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.7) -set(CMAKE_OSX_DEPLOYMENT_TARGET "11.7" CACHE STRING "Minimum OS X deployment version") +set(CMAKE_OSX_DEPLOYMENT_TARGET "11.7" CACHE STRING "Minimum OS X deployment version" FORCE) if(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) endif(COMMAND cmake_policy) diff --git a/packages/grpc-tools/build_binaries.sh b/packages/grpc-tools/build_binaries.sh index c05d7da86..d22bbc4ff 100755 --- a/packages/grpc-tools/build_binaries.sh +++ b/packages/grpc-tools/build_binaries.sh @@ -70,6 +70,7 @@ case $(uname -s) in mkdir $base/build/bin/$arch for bin in protoc grpc_node_plugin; do lipo -extract x86_64 $base/build/bin/$bin -o $base/build/bin/$arch/$bin + otool -l $base/build/bin/$arch/$bin | grep minos done artifacts darwin $arch $base/build/bin/$arch/ done From b735abf544bf22afc69f1761b4f06c6a97da3b57 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 5 Dec 2022 15:44:24 -0500 Subject: [PATCH 1832/1899] grpc-tools: Bump to version 1.12.3 --- packages/grpc-tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-tools/package.json b/packages/grpc-tools/package.json index 673c2cf90..d4ac74ea1 100644 --- a/packages/grpc-tools/package.json +++ b/packages/grpc-tools/package.json @@ -1,6 +1,6 @@ { "name": "grpc-tools", - "version": "1.12.2", + "version": "1.12.3", "author": "Google Inc.", "description": "Tools for developing with gRPC on Node.js", "homepage": "https://grpc.io/", From 677c0093855b9234c501ba510bfbc83bafa3320c Mon Sep 17 00:00:00 2001 From: Nick Kleinschmidt Date: Sat, 17 Dec 2022 15:19:32 -0700 Subject: [PATCH 1833/1899] grpc-js: Add support for grpc.service_config_disable_resolution --- packages/grpc-js/README.md | 1 + packages/grpc-js/src/channel-options.ts | 2 + packages/grpc-js/src/resolver-dns.ts | 7 ++- packages/grpc-js/test/test-resolver.ts | 58 +++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/README.md b/packages/grpc-js/README.md index 3d698dfd8..652ce5fef 100644 --- a/packages/grpc-js/README.md +++ b/packages/grpc-js/README.md @@ -62,6 +62,7 @@ Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. - `grpc.enable_retries` - `grpc.per_rpc_retry_buffer_size` - `grpc.retry_buffer_size` + - `grpc.service_config_disable_resolution` - `grpc-node.max_session_memory` - `channelOverride` - `channelFactoryOverride` diff --git a/packages/grpc-js/src/channel-options.ts b/packages/grpc-js/src/channel-options.ts index 8830ed43d..a41b89e9b 100644 --- a/packages/grpc-js/src/channel-options.ts +++ b/packages/grpc-js/src/channel-options.ts @@ -55,6 +55,7 @@ export interface ChannelOptions { 'grpc.max_connection_age_ms'?: number; 'grpc.max_connection_age_grace_ms'?: number; 'grpc-node.max_session_memory'?: number; + 'grpc.service_config_disable_resolution'?: number; // eslint-disable-next-line @typescript-eslint/no-explicit-any [key: string]: any; } @@ -87,6 +88,7 @@ export const recognizedOptions = { 'grpc.max_connection_age_ms': true, 'grpc.max_connection_age_grace_ms': true, 'grpc-node.max_session_memory': true, + 'grpc.service_config_disable_resolution': true, }; export function channelOptionsEqual( diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 4b7cb2fec..355ce2dfd 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -98,6 +98,7 @@ class DnsResolver implements Resolver { private continueResolving = false; private nextResolutionTimer: NodeJS.Timer; private isNextResolutionTimerRunning = false; + private isServiceConfigEnabled = true; constructor( private target: GrpcUri, private listener: ResolverListener, @@ -127,6 +128,10 @@ class DnsResolver implements Resolver { } this.percentage = Math.random() * 100; + if (channelOptions['grpc.service_config_disable_resolution'] === 1) { + this.isServiceConfigEnabled = false; + } + this.defaultResolutionError = { code: Status.UNAVAILABLE, details: `Name resolution failed for target ${uriToString(this.target)}`, @@ -255,7 +260,7 @@ class DnsResolver implements Resolver { ); /* If there already is a still-pending TXT resolution, we can just use * that result when it comes in */ - if (this.pendingTxtPromise === null) { + if (this.isServiceConfigEnabled && this.pendingTxtPromise === null) { /* We handle the TXT query promise differently than the others because * the name resolution attempt as a whole is a success even if the TXT * lookup fails */ diff --git a/packages/grpc-js/test/test-resolver.ts b/packages/grpc-js/test/test-resolver.ts index a3e6793f1..1d458125b 100644 --- a/packages/grpc-js/test/test-resolver.ts +++ b/packages/grpc-js/test/test-resolver.ts @@ -207,6 +207,64 @@ describe('Name Resolver', () => { const resolver = resolverManager.createResolver(target, listener, {}); resolver.updateResolution(); }); + // Created DNS TXT record using TXT sample from https://github.com/grpc/proposal/blob/master/A2-service-configs-in-dns.md + // "grpc_config=[{\"serviceConfig\":{\"loadBalancingPolicy\":\"round_robin\",\"methodConfig\":[{\"name\":[{\"service\":\"MyService\",\"method\":\"Foo\"}],\"waitForReady\":true}]}}]" + it.skip('Should resolve a name with TXT service config', done => { + const target = resolverManager.mapUriDefaultScheme(parseUri('grpctest.kleinsch.com')!)!; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + if (serviceConfig !== null) { + assert( + serviceConfig.loadBalancingPolicy === 'round_robin', + 'Should have found round robin LB policy' + ); + done(); + } + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, {}); + resolver.updateResolution(); + }); + it.skip( + 'Should not resolve TXT service config if we disabled service config', + (done) => { + const target = resolverManager.mapUriDefaultScheme( + parseUri('grpctest.kleinsch.com')! + )!; + let count = 0; + const listener: resolverManager.ResolverListener = { + onSuccessfulResolution: ( + addressList: SubchannelAddress[], + serviceConfig: ServiceConfig | null, + serviceConfigError: StatusObject | null + ) => { + assert( + serviceConfig === null, + 'Should not have found service config' + ); + count++; + }, + onError: (error: StatusObject) => { + done(new Error(`Failed with status ${error.details}`)); + }, + }; + const resolver = resolverManager.createResolver(target, listener, { + 'grpc.service_config_disable_resolution': 1, + }); + resolver.updateResolution(); + setTimeout(() => { + assert(count === 1, 'Should have only resolved once'); + done(); + }, 2_000); + } + ); /* The DNS entry for loopback4.unittest.grpc.io only has a single A record * with the address 127.0.0.1, but the Mac DNS resolver appears to use * NAT64 to create an IPv6 address in that case, so it instead returns From a1b9464de8c63831a6053525039f3077f618ac6f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Jan 2023 09:35:43 -0800 Subject: [PATCH 1834/1899] grpc-js: Add HTTP status and content type headers to trailers-only responses --- packages/grpc-js/src/server-call.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 631ec7675..8dcf6be33 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -63,11 +63,13 @@ const deadlineUnitsToMs: DeadlineUnitIndexSignature = { u: 0.001, n: 0.000001, }; -const defaultResponseHeaders = { +const defaultCompressionHeaders = { // TODO(cjihrig): Remove these encoding headers from the default response // once compression is integrated. [GRPC_ACCEPT_ENCODING_HEADER]: 'identity,deflate,gzip', [GRPC_ENCODING_HEADER]: 'identity', +} +const defaultResponseHeaders = { [http2.constants.HTTP2_HEADER_STATUS]: http2.constants.HTTP_STATUS_OK, [http2.constants.HTTP2_HEADER_CONTENT_TYPE]: 'application/grpc+proto', }; @@ -500,7 +502,7 @@ export class Http2ServerCallStream< this.metadataSent = true; const custom = customMetadata ? customMetadata.toHttp2Headers() : null; // TODO(cjihrig): Include compression headers. - const headers = { ...defaultResponseHeaders, ...custom }; + const headers = { ...defaultResponseHeaders, ...defaultCompressionHeaders, ...custom }; this.stream.respond(headers, defaultResponseOptions); } @@ -725,9 +727,11 @@ export class Http2ServerCallStream< this.stream.end(); } } else { + // Trailers-only response const trailersToSend = { [GRPC_STATUS_HEADER]: statusObj.code, [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details), + ...defaultResponseHeaders, ...statusObj.metadata?.toHttp2Headers(), }; this.stream.respond(trailersToSend, {endStream: true}); From c62d41623b361d793586d930f47b5e44829e29f2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Jan 2023 09:53:00 -0800 Subject: [PATCH 1835/1899] grpc-js: Discard buffer tracker entry when RetryingCall ends --- packages/grpc-js/src/retrying-call.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index f9bda9eb5..8daf5ba70 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -202,6 +202,15 @@ export class RetryingCall implements Call { private reportStatus(statusObject: StatusObject) { this.trace('ended with status: code=' + statusObject.code + ' details="' + statusObject.details + '"'); + this.bufferTracker.freeAll(this.callNumber); + for (let i = 0; i < this.writeBuffer.length; i++) { + if (this.writeBuffer[i].entryType === 'MESSAGE') { + this.writeBuffer[i] = { + entryType: 'FREED', + allocated: false + }; + } + } process.nextTick(() => { this.listener?.onReceiveStatus(statusObject); }); From 5006c14d729bc65e558bfdbd4864467b7a1f7473 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 3 Jan 2023 13:43:55 -0800 Subject: [PATCH 1836/1899] grpc-js: Bump to version 1.8.1 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9aa685748..06707c2c4 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.0", + "version": "1.8.1", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From df8b8976dcb1d2fb17f826f7ceb930eb83c6885a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 7 Dec 2022 10:19:07 -0500 Subject: [PATCH 1837/1899] grpc-js: Refactor Transport and SubchannelConnector out of Subchannel --- packages/grpc-js/src/subchannel-call.ts | 30 +- packages/grpc-js/src/subchannel-pool.ts | 4 +- packages/grpc-js/src/subchannel.ts | 693 ++---------------------- packages/grpc-js/src/transport.ts | 634 ++++++++++++++++++++++ 4 files changed, 714 insertions(+), 647 deletions(-) create mode 100644 packages/grpc-js/src/transport.ts diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index 2bc6fb0c7..6556bc460 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -21,12 +21,12 @@ import * as os from 'os'; import { Status } from './constants'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; -import { SubchannelCallStatsTracker, Subchannel } from './subchannel'; import * as logging from './logging'; import { LogVerbosity } from './constants'; import { ServerSurfaceCall } from './server-call'; import { Deadline } from './deadline'; import { InterceptingListener, MessageContext, StatusObject, WriteCallback } from './call-interface'; +import { CallEventTracker } from './transport'; const TRACER_NAME = 'subchannel_call'; @@ -110,9 +110,9 @@ export class Http2SubchannelCall implements SubchannelCall { constructor( private readonly http2Stream: http2.ClientHttp2Stream, - private readonly callStatsTracker: SubchannelCallStatsTracker, + private readonly callEventTracker: CallEventTracker, private readonly listener: SubchannelCallInterceptingListener, - private readonly subchannel: Subchannel, + private readonly peerName: string, private readonly callId: number ) { this.disconnectListener = () => { @@ -122,8 +122,6 @@ export class Http2SubchannelCall implements SubchannelCall { metadata: new Metadata(), }); }; - subchannel.addDisconnectListener(this.disconnectListener); - subchannel.callRef(); http2Stream.on('response', (headers, flags) => { let headersString = ''; for (const header of Object.keys(headers)) { @@ -185,7 +183,7 @@ export class Http2SubchannelCall implements SubchannelCall { for (const message of messages) { this.trace('parsed message of length ' + message.length); - this.callStatsTracker!.addMessageReceived(); + this.callEventTracker!.addMessageReceived(); this.tryPush(message); } }); @@ -289,7 +287,15 @@ export class Http2SubchannelCall implements SubchannelCall { ); this.internalError = err; } - this.callStatsTracker.onStreamEnd(false); + this.callEventTracker.onStreamEnd(false); + }); + } + + public onDisconnect() { + this.endCall({ + code: Status.UNAVAILABLE, + details: 'Connection dropped', + metadata: new Metadata(), }); } @@ -304,7 +310,7 @@ export class Http2SubchannelCall implements SubchannelCall { this.finalStatus!.details + '"' ); - this.callStatsTracker.onCallEnd(this.finalStatus!); + this.callEventTracker.onCallEnd(this.finalStatus!); /* We delay the actual action of bubbling up the status to insulate the * cleanup code in this class from any errors that may be thrown in the * upper layers as a result of bubbling up the status. In particular, @@ -319,8 +325,6 @@ export class Http2SubchannelCall implements SubchannelCall { * not push more messages after the status is output, so the messages go * nowhere either way. */ this.http2Stream.resume(); - this.subchannel.callUnref(); - this.subchannel.removeDisconnectListener(this.disconnectListener); } } @@ -395,7 +399,7 @@ export class Http2SubchannelCall implements SubchannelCall { } private handleTrailers(headers: http2.IncomingHttpHeaders) { - this.callStatsTracker.onStreamEnd(true); + this.callEventTracker.onStreamEnd(true); let headersString = ''; for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; @@ -467,7 +471,7 @@ export class Http2SubchannelCall implements SubchannelCall { } getPeer(): string { - return this.subchannel.getAddress(); + return this.peerName; } getCallNumber(): number { @@ -506,7 +510,7 @@ export class Http2SubchannelCall implements SubchannelCall { context.callback?.(); }; this.trace('sending data chunk of length ' + message.length); - this.callStatsTracker.addMessageSent(); + this.callEventTracker.addMessageSent(); try { this.http2Stream!.write(message, cb); } catch (error) { diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index b7ef362c3..bbfbea02b 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -23,6 +23,7 @@ import { } from './subchannel-address'; import { ChannelCredentials } from './channel-credentials'; import { GrpcUri, uriToString } from './uri-parser'; +import { Http2SubchannelConnector } from './transport'; // 10 seconds in milliseconds. This value is arbitrary. /** @@ -143,7 +144,8 @@ export class SubchannelPool { channelTargetUri, subchannelTarget, channelArguments, - channelCredentials + channelCredentials, + new Http2SubchannelConnector(channelTargetUri) ); if (!(channelTarget in this.pool)) { this.pool[channelTarget] = []; diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index 0d9773b30..b4876f178 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -15,60 +15,30 @@ * */ -import * as http2 from 'http2'; import { ChannelCredentials } from './channel-credentials'; import { Metadata } from './metadata'; import { ChannelOptions } from './channel-options'; -import { PeerCertificate, checkServerIdentity, TLSSocket, CipherNameAndProtocol } from 'tls'; import { ConnectivityState } from './connectivity-state'; import { BackoffTimeout, BackoffOptions } from './backoff-timeout'; -import { getDefaultAuthority } from './resolver'; import * as logging from './logging'; import { LogVerbosity, Status } from './constants'; -import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; -import * as net from 'net'; -import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; -import { ConnectionOptions } from 'tls'; +import { GrpcUri, uriToString } from './uri-parser'; import { - stringToSubchannelAddress, SubchannelAddress, subchannelAddressToString, } from './subchannel-address'; -import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, SocketInfo, SocketRef, unregisterChannelzRef, registerChannelzSocket, TlsInfo } from './channelz'; +import { SubchannelRef, ChannelzTrace, ChannelzChildrenTracker, SubchannelInfo, registerChannelzSubchannel, ChannelzCallTracker, unregisterChannelzRef } from './channelz'; import { ConnectivityStateListener } from './subchannel-interface'; -import { Http2SubchannelCall, SubchannelCallInterceptingListener } from './subchannel-call'; -import { getNextCallNumber } from './call-number'; +import { SubchannelCallInterceptingListener } from './subchannel-call'; import { SubchannelCall } from './subchannel-call'; -import { InterceptingListener, StatusObject } from './call-interface'; - -const clientVersion = require('../../package.json').version; +import { CallEventTracker, SubchannelConnector, Transport } from './transport'; const TRACER_NAME = 'subchannel'; -const FLOW_CONTROL_TRACER_NAME = 'subchannel_flowctrl'; /* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't * have a constant for the max signed 32 bit integer, so this is a simple way * to calculate it */ const KEEPALIVE_MAX_TIME_MS = ~(1 << 31); -const KEEPALIVE_TIMEOUT_MS = 20000; - -export interface SubchannelCallStatsTracker { - addMessageSent(): void; - addMessageReceived(): void; - onCallEnd(status: StatusObject): void; - onStreamEnd(success: boolean): void; -} - -const { - HTTP2_HEADER_AUTHORITY, - HTTP2_HEADER_CONTENT_TYPE, - HTTP2_HEADER_METHOD, - HTTP2_HEADER_PATH, - HTTP2_HEADER_TE, - HTTP2_HEADER_USER_AGENT, -} = http2.constants; - -const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); export class Subchannel { /** @@ -79,7 +49,7 @@ export class Subchannel { /** * The underlying http2 session used to make requests. */ - private session: http2.ClientHttp2Session | null = null; + private transport: Transport | null = null; /** * Indicates that the subchannel should transition from TRANSIENT_FAILURE to * CONNECTING instead of IDLE when the backoff timeout ends. @@ -92,45 +62,9 @@ export class Subchannel { */ private stateListeners: ConnectivityStateListener[] = []; - /** - * A list of listener functions that will be called when the underlying - * socket disconnects. Used for ending active calls with an UNAVAILABLE - * status. - */ - private disconnectListeners: Set<() => void> = new Set(); - private backoffTimeout: BackoffTimeout; - /** - * The complete user agent string constructed using channel args. - */ - private userAgent: string; - - /** - * The amount of time in between sending pings - */ - private keepaliveTimeMs: number = KEEPALIVE_MAX_TIME_MS; - /** - * The amount of time to wait for an acknowledgement after sending a ping - */ - private keepaliveTimeoutMs: number = KEEPALIVE_TIMEOUT_MS; - /** - * Timer reference for timeout that indicates when to send the next ping - */ - private keepaliveIntervalId: NodeJS.Timer; - /** - * Timer reference tracking when the most recent ping will be considered lost - */ - private keepaliveTimeoutId: NodeJS.Timer; - /** - * Indicates whether keepalive pings should be sent without any active calls - */ - private keepaliveWithoutCalls = false; - - /** - * Tracks calls with references to this subchannel - */ - private callRefcount = 0; + private keepaliveTimeMultiplier = 1; /** * Tracks channels and subchannel pools with references to this subchannel */ @@ -149,18 +83,7 @@ export class Subchannel { private childrenTracker = new ChannelzChildrenTracker(); // Channelz socket info - private channelzSocketRef: SocketRef | null = null; - /** - * Name of the remote server, if it is not the same as the subchannel - * address, i.e. if connecting through an HTTP CONNECT proxy. - */ - private remoteName: string | null = null; private streamTracker = new ChannelzCallTracker(); - private keepalivesSent = 0; - private messagesSent = 0; - private messagesReceived = 0; - private lastMessageSentTimestamp: Date | null = null; - private lastMessageReceivedTimestamp: Date | null = null; /** * A class representing a connection to a single backend. @@ -176,33 +99,9 @@ export class Subchannel { private channelTarget: GrpcUri, private subchannelAddress: SubchannelAddress, private options: ChannelOptions, - private credentials: ChannelCredentials + private credentials: ChannelCredentials, + private connector: SubchannelConnector ) { - // Build user-agent string. - this.userAgent = [ - options['grpc.primary_user_agent'], - `grpc-node-js/${clientVersion}`, - options['grpc.secondary_user_agent'], - ] - .filter((e) => e) - .join(' '); // remove falsey values first - - if ('grpc.keepalive_time_ms' in options) { - this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; - } - if ('grpc.keepalive_timeout_ms' in options) { - this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; - } - if ('grpc.keepalive_permit_without_calls' in options) { - this.keepaliveWithoutCalls = - options['grpc.keepalive_permit_without_calls'] === 1; - } else { - this.keepaliveWithoutCalls = false; - } - this.keepaliveIntervalId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveIntervalId); - this.keepaliveTimeoutId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveTimeoutId); const backoffOptions: BackoffOptions = { initialDelay: options['grpc.initial_reconnect_backoff_ms'], maxDelay: options['grpc.max_reconnect_backoff_ms'], @@ -233,67 +132,6 @@ export class Subchannel { }; } - private getChannelzSocketInfo(): SocketInfo | null { - if (this.session === null) { - return null; - } - const sessionSocket = this.session.socket; - const remoteAddress = sessionSocket.remoteAddress ? stringToSubchannelAddress(sessionSocket.remoteAddress, sessionSocket.remotePort) : null; - const localAddress = sessionSocket.localAddress ? stringToSubchannelAddress(sessionSocket.localAddress, sessionSocket.localPort) : null; - let tlsInfo: TlsInfo | null; - if (this.session.encrypted) { - const tlsSocket: TLSSocket = sessionSocket as TLSSocket; - const cipherInfo: CipherNameAndProtocol & {standardName?: string} = tlsSocket.getCipher(); - const certificate = tlsSocket.getCertificate(); - const peerCertificate = tlsSocket.getPeerCertificate(); - tlsInfo = { - cipherSuiteStandardName: cipherInfo.standardName ?? null, - cipherSuiteOtherName: cipherInfo.standardName ? null : cipherInfo.name, - localCertificate: (certificate && 'raw' in certificate) ? certificate.raw : null, - remoteCertificate: (peerCertificate && 'raw' in peerCertificate) ? peerCertificate.raw : null - }; - } else { - tlsInfo = null; - } - const socketInfo: SocketInfo = { - remoteAddress: remoteAddress, - localAddress: localAddress, - security: tlsInfo, - remoteName: this.remoteName, - streamsStarted: this.streamTracker.callsStarted, - streamsSucceeded: this.streamTracker.callsSucceeded, - streamsFailed: this.streamTracker.callsFailed, - messagesSent: this.messagesSent, - messagesReceived: this.messagesReceived, - keepAlivesSent: this.keepalivesSent, - lastLocalStreamCreatedTimestamp: this.streamTracker.lastCallStartedTimestamp, - lastRemoteStreamCreatedTimestamp: null, - lastMessageSentTimestamp: this.lastMessageSentTimestamp, - lastMessageReceivedTimestamp: this.lastMessageReceivedTimestamp, - localFlowControlWindow: this.session.state.localWindowSize ?? null, - remoteFlowControlWindow: this.session.state.remoteWindowSize ?? null - }; - return socketInfo; - } - - private resetChannelzSocketInfo() { - if (!this.channelzEnabled) { - return; - } - if (this.channelzSocketRef) { - unregisterChannelzRef(this.channelzSocketRef); - this.childrenTracker.unrefChild(this.channelzSocketRef); - this.channelzSocketRef = null; - } - this.remoteName = null; - this.streamTracker = new ChannelzCallTracker(); - this.keepalivesSent = 0; - this.messagesSent = 0; - this.messagesReceived = 0; - this.lastMessageSentTimestamp = null; - this.lastMessageReceivedTimestamp = null; - } - private trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); } @@ -302,18 +140,6 @@ export class Subchannel { logging.trace(LogVerbosity.DEBUG, 'subchannel_refcount', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); } - private flowControlTrace(text: string): void { - logging.trace(LogVerbosity.DEBUG, FLOW_CONTROL_TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); - } - - private internalsTrace(text: string): void { - logging.trace(LogVerbosity.DEBUG, 'subchannel_internals', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); - } - - private keepaliveTrace(text: string): void { - logging.trace(LogVerbosity.DEBUG, 'keepalive', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); - } - private handleBackoffTimer() { if (this.continueConnecting) { this.transitionToState( @@ -340,313 +166,39 @@ export class Subchannel { this.backoffTimeout.reset(); } - private sendPing() { - if (this.channelzEnabled) { - this.keepalivesSent += 1; - } - this.keepaliveTrace('Sending ping with timeout ' + this.keepaliveTimeoutMs + 'ms'); - this.keepaliveTimeoutId = setTimeout(() => { - this.keepaliveTrace('Ping timeout passed without response'); - this.handleDisconnect(); - }, this.keepaliveTimeoutMs); - this.keepaliveTimeoutId.unref?.(); - try { - this.session!.ping( - (err: Error | null, duration: number, payload: Buffer) => { - this.keepaliveTrace('Received ping response'); - clearTimeout(this.keepaliveTimeoutId); - } - ); - } catch (e) { - /* If we fail to send a ping, the connection is no longer functional, so - * we should discard it. */ - this.transitionToState( - [ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE - ); - } - } - - private startKeepalivePings() { - this.keepaliveIntervalId = setInterval(() => { - this.sendPing(); - }, this.keepaliveTimeMs); - this.keepaliveIntervalId.unref?.(); - /* Don't send a ping immediately because whatever caused us to start - * sending pings should also involve some network activity. */ - } - - /** - * Stop keepalive pings when terminating a connection. This discards the - * outstanding ping timeout, so it should not be called if the same - * connection will still be used. - */ - private stopKeepalivePings() { - clearInterval(this.keepaliveIntervalId); - clearTimeout(this.keepaliveTimeoutId); - } - - private createSession(proxyConnectionResult: ProxyConnectionResult) { - if (proxyConnectionResult.realTarget) { - this.remoteName = uriToString(proxyConnectionResult.realTarget); - this.trace('creating HTTP/2 session through proxy to ' + proxyConnectionResult.realTarget); - } else { - this.remoteName = null; - this.trace('creating HTTP/2 session'); - } - const targetAuthority = getDefaultAuthority( - proxyConnectionResult.realTarget ?? this.channelTarget - ); - let connectionOptions: http2.SecureClientSessionOptions = - this.credentials._getConnectionOptions() || {}; - connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; - if ('grpc-node.max_session_memory' in this.options) { - connectionOptions.maxSessionMemory = this.options[ - 'grpc-node.max_session_memory' - ]; - } else { - /* By default, set a very large max session memory limit, to effectively - * disable enforcement of the limit. Some testing indicates that Node's - * behavior degrades badly when this limit is reached, so we solve that - * by disabling the check entirely. */ - connectionOptions.maxSessionMemory = Number.MAX_SAFE_INTEGER; - } - let addressScheme = 'http://'; - if ('secureContext' in connectionOptions) { - addressScheme = 'https://'; - // If provided, the value of grpc.ssl_target_name_override should be used - // to override the target hostname when checking server identity. - // This option is used for testing only. - if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = this.options[ - 'grpc.ssl_target_name_override' - ]!; - connectionOptions.checkServerIdentity = ( - host: string, - cert: PeerCertificate - ): Error | undefined => { - return checkServerIdentity(sslTargetNameOverride, cert); - }; - connectionOptions.servername = sslTargetNameOverride; - } else { - const authorityHostname = - splitHostPort(targetAuthority)?.host ?? 'localhost'; - // We want to always set servername to support SNI - connectionOptions.servername = authorityHostname; - } - if (proxyConnectionResult.socket) { - /* This is part of the workaround for - * https://github.com/nodejs/node/issues/32922. Without that bug, - * proxyConnectionResult.socket would always be a plaintext socket and - * this would say - * connectionOptions.socket = proxyConnectionResult.socket; */ - connectionOptions.createConnection = (authority, option) => { - return proxyConnectionResult.socket!; - }; - } - } else { - /* In all but the most recent versions of Node, http2.connect does not use - * the options when establishing plaintext connections, so we need to - * establish that connection explicitly. */ - connectionOptions.createConnection = (authority, option) => { - if (proxyConnectionResult.socket) { - return proxyConnectionResult.socket; - } else { - /* net.NetConnectOpts is declared in a way that is more restrictive - * than what net.connect will actually accept, so we use the type - * assertion to work around that. */ - return net.connect(this.subchannelAddress); - } - }; - } - - connectionOptions = { - ...connectionOptions, - ...this.subchannelAddress, - }; - - /* http2.connect uses the options here: - * https://github.com/nodejs/node/blob/70c32a6d190e2b5d7b9ff9d5b6a459d14e8b7d59/lib/internal/http2/core.js#L3028-L3036 - * The spread operator overides earlier values with later ones, so any port - * or host values in the options will be used rather than any values extracted - * from the first argument. In addition, the path overrides the host and port, - * as documented for plaintext connections here: - * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener - * and for TLS connections here: - * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback. In - * earlier versions of Node, http2.connect passes these options to - * tls.connect but not net.connect, so in the insecure case we still need - * to set the createConnection option above to create the connection - * explicitly. We cannot do that in the TLS case because http2.connect - * passes necessary additional options to tls.connect. - * The first argument just needs to be parseable as a URL and the scheme - * determines whether the connection will be established over TLS or not. - */ - const session = http2.connect( - addressScheme + targetAuthority, - connectionOptions - ); - this.session = session; - this.channelzSocketRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzSocketInfo()!, this.channelzEnabled); - if (this.channelzEnabled) { - this.childrenTracker.refChild(this.channelzSocketRef); + private startConnectingInternal() { + let options = this.options; + if (options['grpc.keepalive_time_ms']) { + const adjustedKeepaliveTime = Math.min(options['grpc.keepalive_time_ms'] * this.keepaliveTimeMultiplier, KEEPALIVE_MAX_TIME_MS); + options = {...options, 'grpc.keepalive_time_ms': adjustedKeepaliveTime}; } - session.unref(); - /* For all of these events, check if the session at the time of the event - * is the same one currently attached to this subchannel, to ensure that - * old events from previous connection attempts cannot cause invalid state - * transitions. */ - session.once('connect', () => { - if (this.session === session) { - this.transitionToState( - [ConnectivityState.CONNECTING], - ConnectivityState.READY - ); - } - }); - session.once('close', () => { - if (this.session === session) { - this.trace('connection closed'); - this.transitionToState( - [ConnectivityState.CONNECTING], - ConnectivityState.TRANSIENT_FAILURE - ); - /* Transitioning directly to IDLE here should be OK because we are not - * doing any backoff, because a connection was established at some - * point */ - this.transitionToState( - [ConnectivityState.READY], - ConnectivityState.IDLE - ); - } - }); - session.once( - 'goaway', - (errorCode: number, lastStreamID: number, opaqueData: Buffer) => { - if (this.session === session) { - /* See the last paragraph of - * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ - if ( - errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && - opaqueData.equals(tooManyPingsData) - ) { - this.keepaliveTimeMs = Math.min( - 2 * this.keepaliveTimeMs, - KEEPALIVE_MAX_TIME_MS - ); - logging.log( - LogVerbosity.ERROR, - `Connection to ${uriToString(this.channelTarget)} at ${ - this.subchannelAddressString - } rejected by server because of excess pings. Increasing ping interval to ${ - this.keepaliveTimeMs - } ms` - ); + this.connector.connect(this.subchannelAddress, this.credentials, options).then( + transport => { + if (this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.READY)) { + this.transport = transport; + if (this.channelzEnabled) { + this.childrenTracker.refChild(transport.getChannelzRef()); } - this.trace( - 'connection closed by GOAWAY with code ' + - errorCode - ); - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.IDLE - ); - } - } - ); - session.once('error', (error) => { - /* Do nothing here. Any error should also trigger a close event, which is - * where we want to handle that. */ - this.trace( - 'connection closed with error ' + - (error as Error).message - ); - }); - if (logging.isTracerEnabled(TRACER_NAME)) { - session.on('remoteSettings', (settings: http2.Settings) => { - this.trace( - 'new settings received' + - (this.session !== session ? ' on the old connection' : '') + - ': ' + - JSON.stringify(settings) - ); - }); - session.on('localSettings', (settings: http2.Settings) => { - this.trace( - 'local settings acknowledged by remote' + - (this.session !== session ? ' on the old connection' : '') + - ': ' + - JSON.stringify(settings) - ); - }); - } - } - - private startConnectingInternal() { - /* Pass connection options through to the proxy so that it's able to - * upgrade it's connection to support tls if needed. - * This is a workaround for https://github.com/nodejs/node/issues/32922 - * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ - const connectionOptions: ConnectionOptions = - this.credentials._getConnectionOptions() || {}; - - if ('secureContext' in connectionOptions) { - connectionOptions.ALPNProtocols = ['h2']; - // If provided, the value of grpc.ssl_target_name_override should be used - // to override the target hostname when checking server identity. - // This option is used for testing only. - if (this.options['grpc.ssl_target_name_override']) { - const sslTargetNameOverride = this.options[ - 'grpc.ssl_target_name_override' - ]!; - connectionOptions.checkServerIdentity = ( - host: string, - cert: PeerCertificate - ): Error | undefined => { - return checkServerIdentity(sslTargetNameOverride, cert); - }; - connectionOptions.servername = sslTargetNameOverride; - } else { - if ('grpc.http_connect_target' in this.options) { - /* This is more or less how servername will be set in createSession - * if a connection is successfully established through the proxy. - * If the proxy is not used, these connectionOptions are discarded - * anyway */ - const targetPath = getDefaultAuthority( - parseUri(this.options['grpc.http_connect_target'] as string) ?? { - path: 'localhost', + transport.addDisconnectListener((tooManyPings) => { + this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); + if (tooManyPings) { + this.keepaliveTimeMultiplier *= 2; + logging.log( + LogVerbosity.ERROR, + `Connection to ${uriToString(this.channelTarget)} at ${ + this.subchannelAddressString + } rejected by server because of excess pings. Increasing ping interval multiplier to ${ + this.keepaliveTimeMultiplier + } ms` + ); } - ); - const hostPort = splitHostPort(targetPath); - connectionOptions.servername = hostPort?.host ?? targetPath; + }); } - } - } - - getProxiedConnection( - this.subchannelAddress, - this.options, - connectionOptions - ).then( - (result) => { - this.createSession(result); }, - (reason) => { - this.transitionToState( - [ConnectivityState.CONNECTING], - ConnectivityState.TRANSIENT_FAILURE - ); + error => { + this.transitionToState([ConnectivityState.CONNECTING], ConnectivityState.TRANSIENT_FAILURE); } - ); - } - - private handleDisconnect() { - this.transitionToState( - [ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE); - for (const listener of this.disconnectListeners.values()) { - listener(); - } + ) } /** @@ -676,15 +228,6 @@ export class Subchannel { switch (newState) { case ConnectivityState.READY: this.stopBackoff(); - const session = this.session!; - session.socket.once('close', () => { - if (this.session === session) { - this.handleDisconnect(); - } - }); - if (this.keepaliveWithoutCalls) { - this.startKeepalivePings(); - } break; case ConnectivityState.CONNECTING: this.startBackoff(); @@ -692,12 +235,11 @@ export class Subchannel { this.continueConnecting = false; break; case ConnectivityState.TRANSIENT_FAILURE: - if (this.session) { - this.session.close(); + if (this.channelzEnabled && this.transport) { + this.childrenTracker.unrefChild(this.transport.getChannelzRef()); } - this.session = null; - this.resetChannelzSocketInfo(); - this.stopKeepalivePings(); + this.transport?.shutdown(); + this.transport = null; /* If the backoff timer has already ended by the time we get to the * TRANSIENT_FAILURE state, we want to immediately transition out of * TRANSIENT_FAILURE as though the backoff timer is ending right now */ @@ -708,12 +250,11 @@ export class Subchannel { } break; case ConnectivityState.IDLE: - if (this.session) { - this.session.close(); + if (this.channelzEnabled && this.transport) { + this.childrenTracker.unrefChild(this.transport.getChannelzRef()); } - this.session = null; - this.resetChannelzSocketInfo(); - this.stopKeepalivePings(); + this.transport?.shutdown(); + this.transport = null; break; default: throw new Error(`Invalid state: unknown ConnectivityState ${newState}`); @@ -726,66 +267,6 @@ export class Subchannel { return true; } - /** - * Check if the subchannel associated with zero calls and with zero channels. - * If so, shut it down. - */ - private checkBothRefcounts() { - /* If no calls, channels, or subchannel pools have any more references to - * this subchannel, we can be sure it will never be used again. */ - if (this.callRefcount === 0 && this.refcount === 0) { - if (this.channelzEnabled) { - this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); - } - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.IDLE - ); - if (this.channelzEnabled) { - unregisterChannelzRef(this.channelzRef); - } - } - } - - callRef() { - this.refTrace( - 'callRefcount ' + - this.callRefcount + - ' -> ' + - (this.callRefcount + 1) - ); - if (this.callRefcount === 0) { - if (this.session) { - this.session.ref(); - } - this.backoffTimeout.ref(); - if (!this.keepaliveWithoutCalls) { - this.startKeepalivePings(); - } - } - this.callRefcount += 1; - } - - callUnref() { - this.refTrace( - 'callRefcount ' + - this.callRefcount + - ' -> ' + - (this.callRefcount - 1) - ); - this.callRefcount -= 1; - if (this.callRefcount === 0) { - if (this.session) { - this.session.unref(); - } - this.backoffTimeout.unref(); - if (!this.keepaliveWithoutCalls) { - clearInterval(this.keepaliveIntervalId); - } - this.checkBothRefcounts(); - } - } - ref() { this.refTrace( 'refcount ' + @@ -804,7 +285,18 @@ export class Subchannel { (this.refcount - 1) ); this.refcount -= 1; - this.checkBothRefcounts(); + if (this.refcount === 0) { + if (this.channelzEnabled) { + this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); + } + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.IDLE + ); + if (this.channelzEnabled) { + unregisterChannelzRef(this.channelzRef); + } + } } unrefIfOneRef(): boolean { @@ -816,83 +308,26 @@ export class Subchannel { } createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener): SubchannelCall { - const headers = metadata.toHttp2Headers(); - headers[HTTP2_HEADER_AUTHORITY] = host; - headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; - headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; - headers[HTTP2_HEADER_METHOD] = 'POST'; - headers[HTTP2_HEADER_PATH] = method; - headers[HTTP2_HEADER_TE] = 'trailers'; - let http2Stream: http2.ClientHttp2Stream; - /* In theory, if an error is thrown by session.request because session has - * become unusable (e.g. because it has received a goaway), this subchannel - * should soon see the corresponding close or goaway event anyway and leave - * READY. But we have seen reports that this does not happen - * (https://github.com/googleapis/nodejs-firestore/issues/1023#issuecomment-653204096) - * so for defense in depth, we just discard the session when we see an - * error here. - */ - try { - http2Stream = this.session!.request(headers); - } catch (e) { - this.transitionToState( - [ConnectivityState.READY], - ConnectivityState.TRANSIENT_FAILURE - ); - throw e; + if (!this.transport) { + throw new Error('Cannot create call, subchannel not READY'); } - this.flowControlTrace( - 'local window size: ' + - this.session!.state.localWindowSize + - ' remote window size: ' + - this.session!.state.remoteWindowSize - ); - const streamSession = this.session; - this.internalsTrace( - 'session.closed=' + - streamSession!.closed + - ' session.destroyed=' + - streamSession!.destroyed + - ' session.socket.destroyed=' + - streamSession!.socket.destroyed); - let statsTracker: SubchannelCallStatsTracker; + let statsTracker: Partial; if (this.channelzEnabled) { this.callTracker.addCallStarted(); this.streamTracker.addCallStarted(); statsTracker = { - addMessageSent: () => { - this.messagesSent += 1; - this.lastMessageSentTimestamp = new Date(); - }, - addMessageReceived: () => { - this.messagesReceived += 1; - }, onCallEnd: status => { if (status.code === Status.OK) { this.callTracker.addCallSucceeded(); } else { this.callTracker.addCallFailed(); } - }, - onStreamEnd: success => { - if (streamSession === this.session) { - if (success) { - this.streamTracker.addCallSucceeded(); - } else { - this.streamTracker.addCallFailed(); - } - } } } } else { - statsTracker = { - addMessageSent: () => {}, - addMessageReceived: () => {}, - onCallEnd: () => {}, - onStreamEnd: () => {} - } + statsTracker = {}; } - return new Http2SubchannelCall(http2Stream, statsTracker, listener, this, getNextCallNumber()); + return this.transport.createCall(metadata, host, method, listener, statsTracker); } /** @@ -946,14 +381,6 @@ export class Subchannel { } } - addDisconnectListener(listener: () => void) { - this.disconnectListeners.add(listener); - } - - removeDisconnectListener(listener: () => void) { - this.disconnectListeners.delete(listener); - } - /** * Reset the backoff timeout, and immediately start connecting if in backoff. */ diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts new file mode 100644 index 000000000..e713ed6ef --- /dev/null +++ b/packages/grpc-js/src/transport.ts @@ -0,0 +1,634 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as http2 from 'http2'; +import { checkServerIdentity, CipherNameAndProtocol, ConnectionOptions, PeerCertificate, TLSSocket } from 'tls'; +import { StatusObject } from './call-interface'; +import { ChannelCredentials } from './channel-credentials'; +import { ChannelOptions } from './channel-options'; +import { ChannelzCallTracker, registerChannelzSocket, SocketInfo, SocketRef, TlsInfo } from './channelz'; +import { LogVerbosity } from './constants'; +import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; +import * as logging from './logging'; +import { getDefaultAuthority } from './resolver'; +import { stringToSubchannelAddress, SubchannelAddress, subchannelAddressToString } from './subchannel-address'; +import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; +import * as net from 'net'; +import { Http2SubchannelCall, SubchannelCall, SubchannelCallInterceptingListener } from './subchannel-call'; +import { Metadata } from './metadata'; +import { getNextCallNumber } from './call-number'; + +const TRACER_NAME = 'transport'; +const FLOW_CONTROL_TRACER_NAME = 'transport_flowctrl'; + +const clientVersion = require('../../package.json').version; + +const { + HTTP2_HEADER_AUTHORITY, + HTTP2_HEADER_CONTENT_TYPE, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_HEADER_TE, + HTTP2_HEADER_USER_AGENT, +} = http2.constants; + +/* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't + * have a constant for the max signed 32 bit integer, so this is a simple way + * to calculate it */ +const KEEPALIVE_MAX_TIME_MS = ~(1 << 31); +const KEEPALIVE_TIMEOUT_MS = 20000; + +export interface CallEventTracker { + addMessageSent(): void; + addMessageReceived(): void; + onCallEnd(status: StatusObject): void; + onStreamEnd(success: boolean): void; +} + +export interface TransportDisconnectListener { + (tooManyPings: boolean): void; +} + +export interface Transport { + getChannelzRef(): SocketRef; + createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): SubchannelCall; + addDisconnectListener(listener: TransportDisconnectListener): void; + shutdown(): void; +} + +const tooManyPingsData: Buffer = Buffer.from('too_many_pings', 'ascii'); + +class Http2Transport implements Transport { + /** + * The amount of time in between sending pings + */ + private keepaliveTimeMs: number = KEEPALIVE_MAX_TIME_MS; + /** + * The amount of time to wait for an acknowledgement after sending a ping + */ + private keepaliveTimeoutMs: number = KEEPALIVE_TIMEOUT_MS; + /** + * Timer reference for timeout that indicates when to send the next ping + */ + private keepaliveIntervalId: NodeJS.Timer; + /** + * Timer reference tracking when the most recent ping will be considered lost + */ + private keepaliveTimeoutId: NodeJS.Timer | null = null; + /** + * Indicates whether keepalive pings should be sent without any active calls + */ + private keepaliveWithoutCalls = false; + + private userAgent: string; + + private activeCalls: Set = new Set(); + + private subchannelAddressString: string; + + private disconnectListeners: TransportDisconnectListener[] = []; + + private disconnectHandled = false; + + // Channelz info + private channelzRef: SocketRef; + private readonly channelzEnabled: boolean = true; + /** + * Name of the remote server, if it is not the same as the subchannel + * address, i.e. if connecting through an HTTP CONNECT proxy. + */ + private remoteName: string | null = null; + private streamTracker = new ChannelzCallTracker(); + private keepalivesSent = 0; + private messagesSent = 0; + private messagesReceived = 0; + private lastMessageSentTimestamp: Date | null = null; + private lastMessageReceivedTimestamp: Date | null = null; + + constructor( + private session: http2.ClientHttp2Session, + subchannelAddress: SubchannelAddress, + options: ChannelOptions + ) { + // Build user-agent string. + this.userAgent = [ + options['grpc.primary_user_agent'], + `grpc-node-js/${clientVersion}`, + options['grpc.secondary_user_agent'], + ] + .filter((e) => e) + .join(' '); // remove falsey values first + + if ('grpc.keepalive_time_ms' in options) { + this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; + } + if ('grpc.keepalive_timeout_ms' in options) { + this.keepaliveTimeoutMs = options['grpc.keepalive_timeout_ms']!; + } + if ('grpc.keepalive_permit_without_calls' in options) { + this.keepaliveWithoutCalls = + options['grpc.keepalive_permit_without_calls'] === 1; + } else { + this.keepaliveWithoutCalls = false; + } + this.keepaliveIntervalId = setTimeout(() => {}, 0); + clearTimeout(this.keepaliveIntervalId); + if (this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } + + this.subchannelAddressString = subchannelAddressToString(subchannelAddress); + + if (options['grpc.enable_channelz'] === 0) { + this.channelzEnabled = false; + } + this.channelzRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); + + session.once('close', () => { + this.trace('session closed'); + this.stopKeepalivePings(); + this.handleDisconnect(false); + }); + session.once('goaway', (errorCode: number, lastStreamID: number, opaqueData: Buffer) => { + let tooManyPings = false; + /* See the last paragraph of + * https://github.com/grpc/proposal/blob/master/A8-client-side-keepalive.md#basic-keepalive */ + if ( + errorCode === http2.constants.NGHTTP2_ENHANCE_YOUR_CALM && + opaqueData.equals(tooManyPingsData) + ) { + tooManyPings = true; + } + this.trace( + 'connection closed by GOAWAY with code ' + + errorCode + ); + this.handleDisconnect(tooManyPings); + }); + session.once('error', error => { + /* Do nothing here. Any error should also trigger a close event, which is + * where we want to handle that. */ + this.trace( + 'connection closed with error ' + + (error as Error).message + ); + }); + if (logging.isTracerEnabled(TRACER_NAME)) { + session.on('remoteSettings', (settings: http2.Settings) => { + this.trace( + 'new settings received' + + (this.session !== session ? ' on the old connection' : '') + + ': ' + + JSON.stringify(settings) + ); + }); + session.on('localSettings', (settings: http2.Settings) => { + this.trace( + 'local settings acknowledged by remote' + + (this.session !== session ? ' on the old connection' : '') + + ': ' + + JSON.stringify(settings) + ); + }); + } + } + + private getChannelzInfo(): SocketInfo { + const sessionSocket = this.session.socket; + const remoteAddress = sessionSocket.remoteAddress ? stringToSubchannelAddress(sessionSocket.remoteAddress, sessionSocket.remotePort) : null; + const localAddress = sessionSocket.localAddress ? stringToSubchannelAddress(sessionSocket.localAddress, sessionSocket.localPort) : null; + let tlsInfo: TlsInfo | null; + if (this.session.encrypted) { + const tlsSocket: TLSSocket = sessionSocket as TLSSocket; + const cipherInfo: CipherNameAndProtocol & {standardName?: string} = tlsSocket.getCipher(); + const certificate = tlsSocket.getCertificate(); + const peerCertificate = tlsSocket.getPeerCertificate(); + tlsInfo = { + cipherSuiteStandardName: cipherInfo.standardName ?? null, + cipherSuiteOtherName: cipherInfo.standardName ? null : cipherInfo.name, + localCertificate: (certificate && 'raw' in certificate) ? certificate.raw : null, + remoteCertificate: (peerCertificate && 'raw' in peerCertificate) ? peerCertificate.raw : null + }; + } else { + tlsInfo = null; + } + const socketInfo: SocketInfo = { + remoteAddress: remoteAddress, + localAddress: localAddress, + security: tlsInfo, + remoteName: this.remoteName, + streamsStarted: this.streamTracker.callsStarted, + streamsSucceeded: this.streamTracker.callsSucceeded, + streamsFailed: this.streamTracker.callsFailed, + messagesSent: this.messagesSent, + messagesReceived: this.messagesReceived, + keepAlivesSent: this.keepalivesSent, + lastLocalStreamCreatedTimestamp: this.streamTracker.lastCallStartedTimestamp, + lastRemoteStreamCreatedTimestamp: null, + lastMessageSentTimestamp: this.lastMessageSentTimestamp, + lastMessageReceivedTimestamp: this.lastMessageReceivedTimestamp, + localFlowControlWindow: this.session.state.localWindowSize ?? null, + remoteFlowControlWindow: this.session.state.remoteWindowSize ?? null + }; + return socketInfo; + } + + private trace(text: string): void { + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + + private keepaliveTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'keepalive', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + + private flowControlTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, FLOW_CONTROL_TRACER_NAME, '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + + private internalsTrace(text: string): void { + logging.trace(LogVerbosity.DEBUG, 'transport_internals', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); + } + + private handleDisconnect(tooManyPings: boolean) { + if (this.disconnectHandled) { + return; + } + this.disconnectHandled = true; + this.disconnectListeners.forEach(listener => listener(tooManyPings)); + for (const call of this.activeCalls) { + call.onDisconnect(); + } + } + + addDisconnectListener(listener: TransportDisconnectListener): void { + this.disconnectListeners.push(listener); + } + + private clearKeepaliveTimeout() { + if (!this.keepaliveTimeoutId) { + return; + } + clearTimeout(this.keepaliveTimeoutId); + this.keepaliveTimeoutId = null; + } + + private sendPing() { + if (this.channelzEnabled) { + this.keepalivesSent += 1; + } + this.keepaliveTrace('Sending ping with timeout ' + this.keepaliveTimeoutMs + 'ms'); + if (!this.keepaliveTimeoutId) { + this.keepaliveTimeoutId = setTimeout(() => { + this.keepaliveTrace('Ping timeout passed without response'); + this.handleDisconnect(false); + }, this.keepaliveTimeoutMs); + this.keepaliveTimeoutId.unref?.(); + } + try { + this.session!.ping( + (err: Error | null, duration: number, payload: Buffer) => { + this.keepaliveTrace('Received ping response'); + this.clearKeepaliveTimeout(); + } + ); + } catch (e) { + /* If we fail to send a ping, the connection is no longer functional, so + * we should discard it. */ + this.handleDisconnect(false); + } + } + + private startKeepalivePings() { + this.keepaliveIntervalId = setInterval(() => { + this.sendPing(); + }, this.keepaliveTimeMs); + this.keepaliveIntervalId.unref?.(); + /* Don't send a ping immediately because whatever caused us to start + * sending pings should also involve some network activity. */ + } + + /** + * Stop keepalive pings when terminating a connection. This discards the + * outstanding ping timeout, so it should not be called if the same + * connection will still be used. + */ + private stopKeepalivePings() { + clearInterval(this.keepaliveIntervalId); + this.clearKeepaliveTimeout(); + } + + private removeActiveCall(call: Http2SubchannelCall) { + this.activeCalls.delete(call); + if (this.activeCalls.size === 0 && !this.keepaliveWithoutCalls) { + this.stopKeepalivePings(); + } + } + + private addActiveCall(call: Http2SubchannelCall) { + if (this.activeCalls.size === 0 && !this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } + this.activeCalls.add(call); + } + + createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): Http2SubchannelCall { + const headers = metadata.toHttp2Headers(); + headers[HTTP2_HEADER_AUTHORITY] = host; + headers[HTTP2_HEADER_USER_AGENT] = this.userAgent; + headers[HTTP2_HEADER_CONTENT_TYPE] = 'application/grpc'; + headers[HTTP2_HEADER_METHOD] = 'POST'; + headers[HTTP2_HEADER_PATH] = method; + headers[HTTP2_HEADER_TE] = 'trailers'; + let http2Stream: http2.ClientHttp2Stream; + /* In theory, if an error is thrown by session.request because session has + * become unusable (e.g. because it has received a goaway), this subchannel + * should soon see the corresponding close or goaway event anyway and leave + * READY. But we have seen reports that this does not happen + * (https://github.com/googleapis/nodejs-firestore/issues/1023#issuecomment-653204096) + * so for defense in depth, we just discard the session when we see an + * error here. + */ + try { + http2Stream = this.session!.request(headers); + } catch (e) { + this.handleDisconnect(false); + throw e; + } + this.flowControlTrace( + 'local window size: ' + + this.session.state.localWindowSize + + ' remote window size: ' + + this.session.state.remoteWindowSize + ); + this.internalsTrace( + 'session.closed=' + + this.session.closed + + ' session.destroyed=' + + this.session.destroyed + + ' session.socket.destroyed=' + + this.session.socket.destroyed); + let eventTracker: CallEventTracker; + let call: Http2SubchannelCall; + if (this.channelzEnabled) { + this.streamTracker.addCallStarted(); + eventTracker = { + addMessageSent: () => { + this.messagesSent += 1; + this.lastMessageSentTimestamp = new Date(); + subchannelCallStatsTracker.addMessageSent?.(); + }, + addMessageReceived: () => { + this.messagesReceived += 1; + this.lastMessageReceivedTimestamp = new Date(); + subchannelCallStatsTracker.addMessageReceived?.(); + }, + onCallEnd: status => { + subchannelCallStatsTracker.onCallEnd?.(status); + }, + onStreamEnd: success => { + if (success) { + this.streamTracker.addCallSucceeded(); + } else { + this.streamTracker.addCallFailed(); + } + this.removeActiveCall(call); + subchannelCallStatsTracker.onStreamEnd?.(success); + } + } + } else { + eventTracker = { + addMessageSent: () => { + subchannelCallStatsTracker.addMessageSent?.(); + }, + addMessageReceived: () => { + subchannelCallStatsTracker.addMessageReceived?.(); + }, + onCallEnd: (status) => { + subchannelCallStatsTracker.onCallEnd?.(status); + this.removeActiveCall(call); + }, + onStreamEnd: (success) => { + subchannelCallStatsTracker.onStreamEnd?.(success); + } + } + } + call = new Http2SubchannelCall(http2Stream, eventTracker, listener, this.subchannelAddressString, getNextCallNumber()); + this.addActiveCall(call); + return call; + } + + getChannelzRef(): SocketRef { + return this.channelzRef; + } + + shutdown() { + this.session.close(); + } +} + +export interface SubchannelConnector { + connect(address: SubchannelAddress, credentials: ChannelCredentials, options: ChannelOptions): Promise; + shutdown(): void; +} + +export class Http2SubchannelConnector implements SubchannelConnector { + private session: http2.ClientHttp2Session | null = null; + private isShutdown = false; + constructor(private channelTarget: GrpcUri) {} + private trace(text: string) { + + } + private createSession(address: SubchannelAddress, credentials: ChannelCredentials, options: ChannelOptions, proxyConnectionResult: ProxyConnectionResult): Promise { + if (this.isShutdown) { + return Promise.reject(); + } + return new Promise((resolve, reject) => { + let remoteName: string | null; + if (proxyConnectionResult.realTarget) { + remoteName = uriToString(proxyConnectionResult.realTarget); + this.trace('creating HTTP/2 session through proxy to ' + uriToString(proxyConnectionResult.realTarget)); + } else { + remoteName = null; + this.trace('creating HTTP/2 session to ' + subchannelAddressToString(address)); + } + const targetAuthority = getDefaultAuthority( + proxyConnectionResult.realTarget ?? this.channelTarget + ); + let connectionOptions: http2.SecureClientSessionOptions = + credentials._getConnectionOptions() || {}; + connectionOptions.maxSendHeaderBlockLength = Number.MAX_SAFE_INTEGER; + if ('grpc-node.max_session_memory' in options) { + connectionOptions.maxSessionMemory = options[ + 'grpc-node.max_session_memory' + ]; + } else { + /* By default, set a very large max session memory limit, to effectively + * disable enforcement of the limit. Some testing indicates that Node's + * behavior degrades badly when this limit is reached, so we solve that + * by disabling the check entirely. */ + connectionOptions.maxSessionMemory = Number.MAX_SAFE_INTEGER; + } + let addressScheme = 'http://'; + if ('secureContext' in connectionOptions) { + addressScheme = 'https://'; + // If provided, the value of grpc.ssl_target_name_override should be used + // to override the target hostname when checking server identity. + // This option is used for testing only. + if (options['grpc.ssl_target_name_override']) { + const sslTargetNameOverride = options[ + 'grpc.ssl_target_name_override' + ]!; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; + connectionOptions.servername = sslTargetNameOverride; + } else { + const authorityHostname = + splitHostPort(targetAuthority)?.host ?? 'localhost'; + // We want to always set servername to support SNI + connectionOptions.servername = authorityHostname; + } + if (proxyConnectionResult.socket) { + /* This is part of the workaround for + * https://github.com/nodejs/node/issues/32922. Without that bug, + * proxyConnectionResult.socket would always be a plaintext socket and + * this would say + * connectionOptions.socket = proxyConnectionResult.socket; */ + connectionOptions.createConnection = (authority, option) => { + return proxyConnectionResult.socket!; + }; + } + } else { + /* In all but the most recent versions of Node, http2.connect does not use + * the options when establishing plaintext connections, so we need to + * establish that connection explicitly. */ + connectionOptions.createConnection = (authority, option) => { + if (proxyConnectionResult.socket) { + return proxyConnectionResult.socket; + } else { + /* net.NetConnectOpts is declared in a way that is more restrictive + * than what net.connect will actually accept, so we use the type + * assertion to work around that. */ + return net.connect(address); + } + }; + } + + connectionOptions = { + ...connectionOptions, + ...address, + }; + + /* http2.connect uses the options here: + * https://github.com/nodejs/node/blob/70c32a6d190e2b5d7b9ff9d5b6a459d14e8b7d59/lib/internal/http2/core.js#L3028-L3036 + * The spread operator overides earlier values with later ones, so any port + * or host values in the options will be used rather than any values extracted + * from the first argument. In addition, the path overrides the host and port, + * as documented for plaintext connections here: + * https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener + * and for TLS connections here: + * https://nodejs.org/api/tls.html#tls_tls_connect_options_callback. In + * earlier versions of Node, http2.connect passes these options to + * tls.connect but not net.connect, so in the insecure case we still need + * to set the createConnection option above to create the connection + * explicitly. We cannot do that in the TLS case because http2.connect + * passes necessary additional options to tls.connect. + * The first argument just needs to be parseable as a URL and the scheme + * determines whether the connection will be established over TLS or not. + */ + const session = http2.connect( + addressScheme + targetAuthority, + connectionOptions + ); + this.session = session; + session.unref(); + session.once('connect', () => { + session.removeAllListeners(); + resolve(new Http2Transport(session, address, options)); + this.session = null; + }); + session.once('close', () => { + this.session = null; + reject(); + }); + session.once('error', error => { + this.trace('connection failed with error ' + (error as Error).message) + }); + }); + } + connect(address: SubchannelAddress, credentials: ChannelCredentials, options: ChannelOptions): Promise { + if (this.isShutdown) { + return Promise.reject(); + } + /* Pass connection options through to the proxy so that it's able to + * upgrade it's connection to support tls if needed. + * This is a workaround for https://github.com/nodejs/node/issues/32922 + * See https://github.com/grpc/grpc-node/pull/1369 for more info. */ + const connectionOptions: ConnectionOptions = + credentials._getConnectionOptions() || {}; + + if ('secureContext' in connectionOptions) { + connectionOptions.ALPNProtocols = ['h2']; + // If provided, the value of grpc.ssl_target_name_override should be used + // to override the target hostname when checking server identity. + // This option is used for testing only. + if (options['grpc.ssl_target_name_override']) { + const sslTargetNameOverride = options[ + 'grpc.ssl_target_name_override' + ]!; + connectionOptions.checkServerIdentity = ( + host: string, + cert: PeerCertificate + ): Error | undefined => { + return checkServerIdentity(sslTargetNameOverride, cert); + }; + connectionOptions.servername = sslTargetNameOverride; + } else { + if ('grpc.http_connect_target' in options) { + /* This is more or less how servername will be set in createSession + * if a connection is successfully established through the proxy. + * If the proxy is not used, these connectionOptions are discarded + * anyway */ + const targetPath = getDefaultAuthority( + parseUri(options['grpc.http_connect_target'] as string) ?? { + path: 'localhost', + } + ); + const hostPort = splitHostPort(targetPath); + connectionOptions.servername = hostPort?.host ?? targetPath; + } + } + } + + return getProxiedConnection( + address, + options, + connectionOptions + ).then( + result => this.createSession(address, credentials, options, result) + ); + } + + shutdown(): void { + this.isShutdown = true; + this.session?.close(); + this.session = null; + } +} \ No newline at end of file From b72e1fc665824d096255e4a95e541517b7822df2 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 6 Jan 2023 14:31:23 -0800 Subject: [PATCH 1838/1899] Merge pull request #2310 from grpc/reduce-gce-xds-interop-tests grpc-js-xds: Reduce GCE xDS interop tests to ping_pong and circuit_breaking --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index 615b2a7c7..d4490c5ef 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -54,7 +54,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh GRPC_NODE_VERBOSITY=DEBUG \ NODE_XDS_INTEROP_VERBOSITY=1 \ python3 grpc/tools/run_tests/run_xds_tests.py \ - --test_case="all,timeout,circuit_breaking,fault_injection,csds" \ + --test_case="ping_pong,circuit_breaking" \ --project_id=grpc-testing \ --source_image=projects/grpc-testing/global/images/xds-test-server-5 \ --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ From 2d37686a1a0e0f028acb455a630fa65e122db7ad Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 9 Jan 2023 10:18:43 -0800 Subject: [PATCH 1839/1899] grpc-js: Ensure ordering between status and final message --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel-call.ts | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 06707c2c4..c11b4dc42 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.1", + "version": "1.8.2", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index 6556bc460..a560ed4d7 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -87,6 +87,7 @@ export class Http2SubchannelCall implements SubchannelCall { private decoder = new StreamDecoder(); private isReadFilterPending = false; + private isPushPending = false; private canPush = false; /** * Indicates that an 'end' event has come from the http2 stream, so there @@ -360,7 +361,8 @@ export class Http2SubchannelCall implements SubchannelCall { this.finalStatus.code !== Status.OK || (this.readsClosed && this.unpushedReadMessages.length === 0 && - !this.isReadFilterPending) + !this.isReadFilterPending && + !this.isPushPending) ) { this.outputStatus(); } @@ -373,7 +375,9 @@ export class Http2SubchannelCall implements SubchannelCall { (message instanceof Buffer ? message.length : null) ); this.canPush = false; + this.isPushPending = true; process.nextTick(() => { + this.isPushPending = false; /* If we have already output the status any later messages should be * ignored, and can cause out-of-order operation errors higher up in the * stack. Checking as late as possible here to avoid any race conditions. From b3b6310f041aef2770f4a7945453e4db2b5cd113 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 10 Jan 2023 15:24:22 -0800 Subject: [PATCH 1840/1899] grpc-js: Don't end calls when receiving GOAWAY --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/transport.ts | 38 ++++++++++++---- packages/grpc-js/test/test-server.ts | 67 +++++++++++++++++++++++----- 3 files changed, 87 insertions(+), 20 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index c11b4dc42..700c7b773 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.2", + "version": "1.8.3", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index e713ed6ef..64f770945 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -161,7 +161,7 @@ class Http2Transport implements Transport { session.once('close', () => { this.trace('session closed'); this.stopKeepalivePings(); - this.handleDisconnect(false); + this.handleDisconnect(); }); session.once('goaway', (errorCode: number, lastStreamID: number, opaqueData: Buffer) => { let tooManyPings = false; @@ -177,7 +177,7 @@ class Http2Transport implements Transport { 'connection closed by GOAWAY with code ' + errorCode ); - this.handleDisconnect(tooManyPings); + this.reportDisconnectToOwner(tooManyPings); }); session.once('error', error => { /* Do nothing here. Any error should also trigger a close event, which is @@ -263,15 +263,35 @@ class Http2Transport implements Transport { logging.trace(LogVerbosity.DEBUG, 'transport_internals', '(' + this.channelzRef.id + ') ' + this.subchannelAddressString + ' ' + text); } - private handleDisconnect(tooManyPings: boolean) { + /** + * Indicate to the owner of this object that this transport should no longer + * be used. That happens if the connection drops, or if the server sends a + * GOAWAY. + * @param tooManyPings If true, this was triggered by a GOAWAY with data + * indicating that the session was closed becaues the client sent too many + * pings. + * @returns + */ + private reportDisconnectToOwner(tooManyPings: boolean) { if (this.disconnectHandled) { return; } this.disconnectHandled = true; this.disconnectListeners.forEach(listener => listener(tooManyPings)); - for (const call of this.activeCalls) { - call.onDisconnect(); - } + } + + /** + * Handle connection drops, but not GOAWAYs. + */ + private handleDisconnect() { + this.reportDisconnectToOwner(false); + /* Give calls an event loop cycle to finish naturally before reporting the + * disconnnection to them. */ + setImmediate(() => { + for (const call of this.activeCalls) { + call.onDisconnect(); + } + }); } addDisconnectListener(listener: TransportDisconnectListener): void { @@ -294,7 +314,7 @@ class Http2Transport implements Transport { if (!this.keepaliveTimeoutId) { this.keepaliveTimeoutId = setTimeout(() => { this.keepaliveTrace('Ping timeout passed without response'); - this.handleDisconnect(false); + this.handleDisconnect(); }, this.keepaliveTimeoutMs); this.keepaliveTimeoutId.unref?.(); } @@ -308,7 +328,7 @@ class Http2Transport implements Transport { } catch (e) { /* If we fail to send a ping, the connection is no longer functional, so * we should discard it. */ - this.handleDisconnect(false); + this.handleDisconnect(); } } @@ -365,7 +385,7 @@ class Http2Transport implements Transport { try { http2Stream = this.session!.request(headers); } catch (e) { - this.handleDisconnect(false); + this.handleDisconnect(); throw e; } this.flowControlTrace( diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index 0c0ba168e..c67ebc4d6 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -27,9 +27,9 @@ import * as grpc from '../src'; import { Server, ServerCredentials } from '../src'; import { ServiceError } from '../src/call'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; -import { sendUnaryData, ServerUnaryCall } from '../src/server-call'; +import { sendUnaryData, ServerUnaryCall, ServerDuplexStream } from '../src/server-call'; -import { loadProtoFile } from './common'; +import { assert2, loadProtoFile } from './common'; import { TestServiceClient, TestServiceHandlers } from './generated/TestService'; import { ProtoGrpcType as TestServiceGrpcType } from './generated/test_service'; import { Request__Output } from './generated/Request'; @@ -458,18 +458,28 @@ describe('Server', () => { describe('Echo service', () => { let server: Server; let client: ServiceClient; + const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); + const echoService = loadProtoFile(protoFile) + .EchoService as ServiceClientConstructor; + + const serviceImplementation = { + echo(call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, call.request); + }, + echoBidiStream(call: ServerDuplexStream) { + call.on('data', data => { + call.write(data); + }); + call.on('end', () => { + call.end(); + }); + } + }; before(done => { - const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); - const echoService = loadProtoFile(protoFile) - .EchoService as ServiceClientConstructor; server = new Server(); - server.addService(echoService.service, { - echo(call: ServerUnaryCall, callback: sendUnaryData) { - callback(null, call.request); - }, - }); + server.addService(echoService.service, serviceImplementation); server.bindAsync( 'localhost:0', @@ -501,6 +511,43 @@ describe('Echo service', () => { } ); }); + + /* This test passes on Node 18 but fails on Node 16. The failure appears to + * be caused by https://github.com/nodejs/node/issues/42713 */ + it.skip('should continue a stream after server shutdown', done => { + const server2 = new Server(); + server2.addService(echoService.service, serviceImplementation); + server2.bindAsync('localhost:0', ServerCredentials.createInsecure(), (err, port) => { + if (err) { + done(err); + return; + } + const client2 = new echoService(`localhost:${port}`, grpc.credentials.createInsecure()); + server2.start(); + const stream = client2.echoBidiStream(); + const totalMessages = 5; + let messagesSent = 0; + stream.write({ value: 'test value', value2: messagesSent}); + messagesSent += 1; + stream.on('data', () => { + if (messagesSent === 1) { + server2.tryShutdown(assert2.mustCall(() => {})); + } + if (messagesSent >= totalMessages) { + stream.end(); + } else { + stream.write({ value: 'test value', value2: messagesSent}); + messagesSent += 1; + } + }); + stream.on('status', assert2.mustCall((status: grpc.StatusObject) => { + assert.strictEqual(status.code, grpc.status.OK); + assert.strictEqual(messagesSent, totalMessages); + })); + stream.on('error', () => {}); + assert2.afterMustCallsSatisfied(done); + }); + }); }); describe('Generic client and server', () => { From b342001b38237f337af23d9f81fed25b3e6507d6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 Jan 2023 09:24:21 -0800 Subject: [PATCH 1841/1899] grpc-js: Reference session in transport when there are active calls --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/transport.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 700c7b773..d9ef213db 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.3", + "version": "1.8.4", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 64f770945..314971029 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -354,12 +354,14 @@ class Http2Transport implements Transport { private removeActiveCall(call: Http2SubchannelCall) { this.activeCalls.delete(call); if (this.activeCalls.size === 0 && !this.keepaliveWithoutCalls) { + this.session.unref(); this.stopKeepalivePings(); } } private addActiveCall(call: Http2SubchannelCall) { if (this.activeCalls.size === 0 && !this.keepaliveWithoutCalls) { + this.session.ref(); this.startKeepalivePings(); } this.activeCalls.add(call); From fade30bd0a27bfa32395a35a1bf61ab15cb62f8e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 Jan 2023 09:47:19 -0800 Subject: [PATCH 1842/1899] grpc-js: Make call and stream tracking more consistent --- packages/grpc-js/src/subchannel-call.ts | 3 +-- packages/grpc-js/src/transport.ts | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index a560ed4d7..16ac35b5e 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -198,6 +198,7 @@ export class Http2SubchannelCall implements SubchannelCall { * we can bubble up the error message from that event. */ process.nextTick(() => { this.trace('HTTP/2 stream closed with code ' + http2Stream.rstCode); + this.callEventTracker.onStreamEnd(this.finalStatus?.code === Status.OK); /* If we have a final status with an OK status code, that means that * we have received all of the messages and we have processed the * trailers and the call completed successfully, so it doesn't matter @@ -288,7 +289,6 @@ export class Http2SubchannelCall implements SubchannelCall { ); this.internalError = err; } - this.callEventTracker.onStreamEnd(false); }); } @@ -403,7 +403,6 @@ export class Http2SubchannelCall implements SubchannelCall { } private handleTrailers(headers: http2.IncomingHttpHeaders) { - this.callEventTracker.onStreamEnd(true); let headersString = ''; for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 314971029..fc9042278 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -420,6 +420,7 @@ class Http2Transport implements Transport { }, onCallEnd: status => { subchannelCallStatsTracker.onCallEnd?.(status); + this.removeActiveCall(call); }, onStreamEnd: success => { if (success) { @@ -427,7 +428,6 @@ class Http2Transport implements Transport { } else { this.streamTracker.addCallFailed(); } - this.removeActiveCall(call); subchannelCallStatsTracker.onStreamEnd?.(success); } } From 7eaebaf1ed601b16c988702cf420a9aeb24a7130 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 12 Jan 2023 10:00:28 -0800 Subject: [PATCH 1843/1899] grpc-js: Undo changes to stream tracking --- packages/grpc-js/src/subchannel-call.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index 16ac35b5e..a560ed4d7 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -198,7 +198,6 @@ export class Http2SubchannelCall implements SubchannelCall { * we can bubble up the error message from that event. */ process.nextTick(() => { this.trace('HTTP/2 stream closed with code ' + http2Stream.rstCode); - this.callEventTracker.onStreamEnd(this.finalStatus?.code === Status.OK); /* If we have a final status with an OK status code, that means that * we have received all of the messages and we have processed the * trailers and the call completed successfully, so it doesn't matter @@ -289,6 +288,7 @@ export class Http2SubchannelCall implements SubchannelCall { ); this.internalError = err; } + this.callEventTracker.onStreamEnd(false); }); } @@ -403,6 +403,7 @@ export class Http2SubchannelCall implements SubchannelCall { } private handleTrailers(headers: http2.IncomingHttpHeaders) { + this.callEventTracker.onStreamEnd(true); let headersString = ''; for (const header of Object.keys(headers)) { headersString += '\t\t' + header + ': ' + headers[header] + '\n'; From d441aa687d52032877ab46b4a44efd2251d8fe05 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 17 Jan 2023 09:58:24 -0800 Subject: [PATCH 1844/1899] Merge pull request #2323 from sergiitk/xds-interop-fix-buildscript-suites xds interop: Fix buildscripts not continuing on a failed test suite --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index ca747f7ea..b87e3306c 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -167,7 +167,7 @@ main() { local failed_tests=0 test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection_test") for test in "${test_suites[@]}"; do - run_test $test || (( failed_tests++ )) + run_test $test || (( ++failed_tests )) done echo "Failed test suites: ${failed_tests}" if (( failed_tests > 0 )); then From 7a6fa275fe5204f54a606a34f97cd6df7161be00 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 18 Jan 2023 10:54:07 -0800 Subject: [PATCH 1845/1899] grpc-js-xds: weighted clusters: stop checking total_weight, check weight sum <= uint32 max --- packages/grpc-js-xds/src/xds-stream-state/rds-state.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts index 891eb7c8e..fef694517 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/rds-state.ts @@ -32,6 +32,8 @@ const SUPPPORTED_HEADER_MATCH_SPECIFIERS = [ 'suffix_match']; const SUPPORTED_CLUSTER_SPECIFIERS = ['cluster', 'weighted_clusters', 'cluster_header']; +const UINT32_MAX = 0xFFFFFFFF; + function durationToMs(duration: Duration__Output | null): number | null { if (duration === null) { return null; @@ -130,14 +132,11 @@ export class RdsState extends BaseXdsStreamState imp } } if (route.route!.cluster_specifier === 'weighted_clusters') { - if (route.route.weighted_clusters!.total_weight?.value === 0) { - return false; - } let weightSum = 0; for (const clusterWeight of route.route.weighted_clusters!.clusters) { weightSum += clusterWeight.weight?.value ?? 0; } - if (weightSum !== route.route.weighted_clusters!.total_weight?.value ?? 100) { + if (weightSum === 0 || weightSum > UINT32_MAX) { return false; } if (EXPERIMENTAL_FAULT_INJECTION) { From ba405cf35e8f96390889f383189dd4bbe014e85f Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 23 Jan 2023 11:36:24 -0800 Subject: [PATCH 1846/1899] grpc-js: Clear deadline timer when call ends --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/resolving-call.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d9ef213db..e9a181795 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.4", + "version": "1.8.5", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index fe29a4f7a..f1fecd1d2 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -103,6 +103,7 @@ export class ResolvingCall implements Call { if (!this.filterStack) { this.filterStack = this.filterStackFactory.createFilter(); } + clearTimeout(this.deadlineTimer); const filteredStatus = this.filterStack.receiveTrailers(status); this.trace('ended with status: code=' + filteredStatus.code + ' details="' + filteredStatus.details + '"'); this.statusWatchers.forEach(watcher => watcher(filteredStatus)); From 6d98dc5bbfe0d01025c210c80e4f88533679b34a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Jan 2023 10:01:45 -0800 Subject: [PATCH 1847/1899] grpc-js: Hold a reference to transport in SubchannelCall --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/subchannel-call.ts | 15 +++------------ packages/grpc-js/src/transport.ts | 7 ++++++- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index e9a181795..c17d5e6ba 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.5", + "version": "1.8.6", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index a560ed4d7..969282e19 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -26,7 +26,7 @@ import { LogVerbosity } from './constants'; import { ServerSurfaceCall } from './server-call'; import { Deadline } from './deadline'; import { InterceptingListener, MessageContext, StatusObject, WriteCallback } from './call-interface'; -import { CallEventTracker } from './transport'; +import { CallEventTracker, Transport } from './transport'; const TRACER_NAME = 'subchannel_call'; @@ -105,24 +105,15 @@ export class Http2SubchannelCall implements SubchannelCall { // This is populated (non-null) if and only if the call has ended private finalStatus: StatusObject | null = null; - private disconnectListener: () => void; - private internalError: SystemError | null = null; constructor( private readonly http2Stream: http2.ClientHttp2Stream, private readonly callEventTracker: CallEventTracker, private readonly listener: SubchannelCallInterceptingListener, - private readonly peerName: string, + private readonly transport: Transport, private readonly callId: number ) { - this.disconnectListener = () => { - this.endCall({ - code: Status.UNAVAILABLE, - details: 'Connection dropped', - metadata: new Metadata(), - }); - }; http2Stream.on('response', (headers, flags) => { let headersString = ''; for (const header of Object.keys(headers)) { @@ -475,7 +466,7 @@ export class Http2SubchannelCall implements SubchannelCall { } getPeer(): string { - return this.peerName; + return this.transport.getPeerName(); } getCallNumber(): number { diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index fc9042278..a5bf59b3f 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -65,6 +65,7 @@ export interface TransportDisconnectListener { export interface Transport { getChannelzRef(): SocketRef; + getPeerName(): string; createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): SubchannelCall; addDisconnectListener(listener: TransportDisconnectListener): void; shutdown(): void; @@ -448,7 +449,7 @@ class Http2Transport implements Transport { } } } - call = new Http2SubchannelCall(http2Stream, eventTracker, listener, this.subchannelAddressString, getNextCallNumber()); + call = new Http2SubchannelCall(http2Stream, eventTracker, listener, this, getNextCallNumber()); this.addActiveCall(call); return call; } @@ -457,6 +458,10 @@ class Http2Transport implements Transport { return this.channelzRef; } + getPeerName() { + return this.subchannelAddressString; + } + shutdown() { this.session.close(); } From 0d177a818f83cd9de6fc1f5e4bd343de4538e35a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Jan 2023 11:52:24 -0800 Subject: [PATCH 1848/1899] grpc-js: Fix tracking of active calls in transport --- packages/grpc-js/src/transport.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index a5bf59b3f..a9308471b 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -354,16 +354,20 @@ class Http2Transport implements Transport { private removeActiveCall(call: Http2SubchannelCall) { this.activeCalls.delete(call); - if (this.activeCalls.size === 0 && !this.keepaliveWithoutCalls) { + if (this.activeCalls.size === 0) { this.session.unref(); - this.stopKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.stopKeepalivePings(); + } } } private addActiveCall(call: Http2SubchannelCall) { - if (this.activeCalls.size === 0 && !this.keepaliveWithoutCalls) { + if (this.activeCalls.size === 0) { this.session.ref(); - this.startKeepalivePings(); + if (!this.keepaliveWithoutCalls) { + this.startKeepalivePings(); + } } this.activeCalls.add(call); } From 3efdc7b58c0910075659982603e850cc883e019b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Jan 2023 11:56:09 -0800 Subject: [PATCH 1849/1899] grpc-js: Bump version to 1.8.7 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index c17d5e6ba..9e1dfcba6 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.6", + "version": "1.8.7", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From cf090c7f5075452d322ead84496b7f0ed0bb1868 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Feb 2023 13:44:22 -0800 Subject: [PATCH 1850/1899] grpc-js: Fix commitCallWithMostMessages trying to commit completed attempts --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/retrying-call.ts | 19 ++++++++++++++++--- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 9e1dfcba6..290d80b75 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.7", + "version": "1.8.8", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 8daf5ba70..05e5f40c1 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -273,15 +273,24 @@ export class RetryingCall implements Call { } private commitCallWithMostMessages() { + if (this.state === 'COMMITTED') { + return; + } let mostMessages = -1; let callWithMostMessages = -1; for (const [index, childCall] of this.underlyingCalls.entries()) { - if (childCall.nextMessageToSend > mostMessages) { + if (childCall.state === 'ACTIVE' && childCall.nextMessageToSend > mostMessages) { mostMessages = childCall.nextMessageToSend; callWithMostMessages = index; } } - this.commitCall(callWithMostMessages); + if (callWithMostMessages === -1) { + /* There are no active calls, disable retries to force the next call that + * is started to be committed. */ + this.state = 'TRANSPARENT_ONLY'; + } else { + this.commitCall(callWithMostMessages); + } } private isStatusCodeInList(list: (Status | string)[], code: Status) { @@ -601,7 +610,11 @@ export class RetryingCall implements Call { } } else { this.commitCallWithMostMessages(); - const call = this.underlyingCalls[this.committedCallIndex!]; + // commitCallWithMostMessages can fail if we are between ping attempts + if (this.committedCallIndex === null) { + return; + } + const call = this.underlyingCalls[this.committedCallIndex]; bufferEntry.callback = context.callback; if (call.state === 'ACTIVE' && call.nextMessageToSend === messageIndex) { call.call.sendMessageWithContext({ From 3596c4f65518b1f0e8aae841b255a98e68dfe608 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Feb 2023 14:52:20 -0800 Subject: [PATCH 1851/1899] grpc-js: Remove progress field in status from retrying call --- packages/grpc-js/src/retrying-call.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 8daf5ba70..351678965 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -212,7 +212,12 @@ export class RetryingCall implements Call { } } process.nextTick(() => { - this.listener?.onReceiveStatus(statusObject); + // Explicitly construct status object to remove progress field + this.listener?.onReceiveStatus({ + code: statusObject.code, + details: statusObject.details, + metadata: statusObject.metadata + }); }); } From 18c803e6dd458b762fa5fe7361b4abc59d263382 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 8 Feb 2023 09:55:32 -0800 Subject: [PATCH 1852/1899] grpc-js: Export InterceptingListener and NextCall types --- packages/grpc-js/src/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 786fa9925..51f394785 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -237,7 +237,7 @@ export const getClientChannel = (client: Client) => { export { StatusBuilder }; -export { Listener } from './call-interface'; +export { Listener, InterceptingListener } from './call-interface'; export { Requester, @@ -248,6 +248,7 @@ export { InterceptorProvider, InterceptingCall, InterceptorConfigurationError, + NextCall } from './client-interceptors'; export { From 37eb5ed2fabb4a3831f0a506bf44cd6e1ae3da5a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Feb 2023 10:18:24 -0800 Subject: [PATCH 1853/1899] grpc-js: Improve timeout handling and deadline logging --- packages/grpc-js/src/deadline.ts | 39 +++++++++++++++++++++++- packages/grpc-js/src/internal-channel.ts | 4 +-- packages/grpc-js/src/resolving-call.ts | 8 ++--- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/packages/grpc-js/src/deadline.ts b/packages/grpc-js/src/deadline.ts index 58ea0a805..be1f3c3b0 100644 --- a/packages/grpc-js/src/deadline.ts +++ b/packages/grpc-js/src/deadline.ts @@ -51,8 +51,45 @@ export function getDeadlineTimeoutString(deadline: Deadline) { throw new Error('Deadline is too far in the future') } +/** + * See https://nodejs.org/api/timers.html#settimeoutcallback-delay-args + * In particular, "When delay is larger than 2147483647 or less than 1, the + * delay will be set to 1. Non-integer delays are truncated to an integer." + * This number of milliseconds is almost 25 days. + */ +const MAX_TIMEOUT_TIME = 2147483647; + +/** + * Get the timeout value that should be passed to setTimeout now for the timer + * to end at the deadline. For any deadline before now, the timer should end + * immediately, represented by a value of 0. For any deadline more than + * MAX_TIMEOUT_TIME milliseconds in the future, a timer cannot be set that will + * end at that time, so it is treated as infinitely far in the future. + * @param deadline + * @returns + */ export function getRelativeTimeout(deadline: Deadline) { const deadlineMs = deadline instanceof Date ? deadline.getTime() : deadline; const now = new Date().getTime(); - return deadlineMs - now; + const timeout = deadlineMs - now; + if (timeout < 0) { + return 0; + } else if (timeout > MAX_TIMEOUT_TIME) { + return Infinity + } else { + return timeout; + } +} + +export function deadlineToString(deadline: Deadline): string { + if (deadline instanceof Date) { + return deadline.toISOString(); + } else { + const dateDeadline = new Date(deadline); + if (Number.isNaN(dateDeadline.getTime())) { + return '' + deadline; + } else { + return dateDeadline.toISOString(); + } + } } \ No newline at end of file diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 9137be272..2a1d00f53 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -46,7 +46,7 @@ import { LoadBalancingCall } from './load-balancing-call'; import { CallCredentials } from './call-credentials'; import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from './call-interface'; import { SubchannelCall } from './subchannel-call'; -import { Deadline, getDeadlineTimeoutString } from './deadline'; +import { Deadline, deadlineToString, getDeadlineTimeoutString } from './deadline'; import { ResolvingCall } from './resolving-call'; import { getNextCallNumber } from './call-number'; import { restrictControlPlaneStatusCode } from './control-plane-status'; @@ -469,7 +469,7 @@ export class InternalChannel { '] method="' + method + '", deadline=' + - deadline + deadlineToString(deadline) ); const finalOptions: CallStreamOptions = { deadline: deadline, diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index f1fecd1d2..b6398126c 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -18,7 +18,7 @@ import { CallCredentials } from "./call-credentials"; import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from "./call-interface"; import { LogVerbosity, Propagate, Status } from "./constants"; -import { Deadline, getDeadlineTimeoutString, getRelativeTimeout, minDeadline } from "./deadline"; +import { Deadline, deadlineToString, getDeadlineTimeoutString, getRelativeTimeout, minDeadline } from "./deadline"; import { FilterStack, FilterStackFactory } from "./filter-stack"; import { InternalChannel } from "./internal-channel"; import { Metadata } from "./metadata"; @@ -79,9 +79,9 @@ export class ResolvingCall implements Call { private runDeadlineTimer() { clearTimeout(this.deadlineTimer); - this.trace('Deadline: ' + this.deadline); - if (this.deadline !== Infinity) { - const timeout = getRelativeTimeout(this.deadline); + this.trace('Deadline: ' + deadlineToString(this.deadline)); + const timeout = getRelativeTimeout(this.deadline); + if (timeout !== Infinity) { this.trace('Deadline will be reached in ' + timeout + 'ms'); const handleDeadline = () => { this.cancelWithStatus( From 2ed8e71ba17052e3c36d37a04cbbe6a6c1f246a9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 14 Feb 2023 13:47:50 -0800 Subject: [PATCH 1854/1899] grpc-js: Propagate keepalive throttling throughout channel --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/internal-channel.ts | 53 +++++++++++++++++-- .../src/load-balancer-outlier-detection.ts | 8 +-- packages/grpc-js/src/subchannel-interface.ts | 7 ++- packages/grpc-js/src/subchannel.ts | 22 +++++--- packages/grpc-js/src/transport.ts | 7 ++- 6 files changed, 81 insertions(+), 18 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 290d80b75..aafd2803a 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.8", + "version": "1.8.9", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 9137be272..8b4536ae5 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -51,6 +51,7 @@ import { ResolvingCall } from './resolving-call'; import { getNextCallNumber } from './call-number'; import { restrictControlPlaneStatusCode } from './control-plane-status'; import { MessageBufferTracker, RetryingCall, RetryThrottler } from './retrying-call'; +import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from './subchannel-interface'; /** * See https://nodejs.org/api/timers.html#timers_setinterval_callback_delay_args @@ -84,6 +85,33 @@ const RETRY_THROTTLER_MAP: Map = new Map(); const DEFAULT_RETRY_BUFFER_SIZE_BYTES = 1<<24; // 16 MB const DEFAULT_PER_RPC_RETRY_BUFFER_SIZE_BYTES = 1<<20; // 1 MB +class ChannelSubchannelWrapper extends BaseSubchannelWrapper implements SubchannelInterface { + private stateListeners: ConnectivityStateListener[] = []; + private refCount = 0; + constructor(childSubchannel: SubchannelInterface, private channel: InternalChannel) { + super(childSubchannel); + childSubchannel.addConnectivityStateListener((subchannel, previousState, newState, keepaliveTime) => { + channel.throttleKeepalive(keepaliveTime); + for (const listener of this.stateListeners) { + listener(this, previousState, newState, keepaliveTime); + } + }); + } + + ref(): void { + this.child.ref(); + this.refCount += 1; + } + + unref(): void { + this.child.unref(); + this.refCount -= 1; + if (this.refCount <= 0) { + this.channel.removeWrappedSubchannel(this); + } + } +} + export class InternalChannel { private resolvingLoadBalancer: ResolvingLoadBalancer; @@ -116,8 +144,10 @@ export class InternalChannel { * configSelector becomes set or the channel state becomes anything other * than TRANSIENT_FAILURE. */ - private currentResolutionError: StatusObject | null = null; - private retryBufferTracker: MessageBufferTracker; + private currentResolutionError: StatusObject | null = null; + private retryBufferTracker: MessageBufferTracker; + private keepaliveTime: number; + private wrappedSubchannels: Set = new Set(); // Channelz info private readonly channelzEnabled: boolean = true; @@ -190,6 +220,7 @@ export class InternalChannel { options['grpc.retry_buffer_size'] ?? DEFAULT_RETRY_BUFFER_SIZE_BYTES, options['grpc.per_rpc_retry_buffer_size'] ?? DEFAULT_PER_RPC_RETRY_BUFFER_SIZE_BYTES ); + this.keepaliveTime = options['grpc.keepalive_time_ms'] ?? -1; const channelControlHelper: ChannelControlHelper = { createSubchannel: ( subchannelAddress: SubchannelAddress, @@ -201,10 +232,13 @@ export class InternalChannel { Object.assign({}, this.options, subchannelArgs), this.credentials ); + subchannel.throttleKeepalive(this.keepaliveTime); if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Created subchannel or used existing subchannel', subchannel.getChannelzRef()); } - return subchannel; + const wrappedSubchannel = new ChannelSubchannelWrapper(subchannel, this); + this.wrappedSubchannels.add(wrappedSubchannel); + return wrappedSubchannel; }, updateState: (connectivityState: ConnectivityState, picker: Picker) => { this.currentPicker = picker; @@ -369,6 +403,19 @@ export class InternalChannel { } } + throttleKeepalive(newKeepaliveTime: number) { + if (newKeepaliveTime > this.keepaliveTime) { + this.keepaliveTime = newKeepaliveTime; + for (const wrappedSubchannel of this.wrappedSubchannels) { + wrappedSubchannel.throttleKeepalive(newKeepaliveTime); + } + } + } + + removeWrappedSubchannel(wrappedSubchannel: ChannelSubchannelWrapper) { + this.wrappedSubchannels.delete(wrappedSubchannel); + } + doPick(metadata: Metadata, extraPickInfo: {[key: string]: string}) { return this.currentPicker.pick({metadata: metadata, extraPickInfo: extraPickInfo}); } diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index cdf580523..2f72a9625 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -205,11 +205,11 @@ class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements constructor(childSubchannel: SubchannelInterface, private mapEntry?: MapEntry) { super(childSubchannel); this.childSubchannelState = childSubchannel.getConnectivityState(); - childSubchannel.addConnectivityStateListener((subchannel, previousState, newState) => { + childSubchannel.addConnectivityStateListener((subchannel, previousState, newState, keepaliveTime) => { this.childSubchannelState = newState; if (!this.ejected) { for (const listener of this.stateListeners) { - listener(this, previousState, newState); + listener(this, previousState, newState, keepaliveTime); } } }); @@ -265,14 +265,14 @@ class OutlierDetectionSubchannelWrapper extends BaseSubchannelWrapper implements eject() { this.ejected = true; for (const listener of this.stateListeners) { - listener(this, this.childSubchannelState, ConnectivityState.TRANSIENT_FAILURE); + listener(this, this.childSubchannelState, ConnectivityState.TRANSIENT_FAILURE, -1); } } uneject() { this.ejected = false; for (const listener of this.stateListeners) { - listener(this, ConnectivityState.TRANSIENT_FAILURE, this.childSubchannelState); + listener(this, ConnectivityState.TRANSIENT_FAILURE, this.childSubchannelState, -1); } } diff --git a/packages/grpc-js/src/subchannel-interface.ts b/packages/grpc-js/src/subchannel-interface.ts index 082a8b3c0..165ebc3e1 100644 --- a/packages/grpc-js/src/subchannel-interface.ts +++ b/packages/grpc-js/src/subchannel-interface.ts @@ -22,7 +22,8 @@ import { Subchannel } from "./subchannel"; export type ConnectivityStateListener = ( subchannel: SubchannelInterface, previousState: ConnectivityState, - newState: ConnectivityState + newState: ConnectivityState, + keepaliveTime: number ) => void; /** @@ -40,6 +41,7 @@ export interface SubchannelInterface { removeConnectivityStateListener(listener: ConnectivityStateListener): void; startConnecting(): void; getAddress(): string; + throttleKeepalive(newKeepaliveTime: number): void; ref(): void; unref(): void; getChannelzRef(): SubchannelRef; @@ -67,6 +69,9 @@ export abstract class BaseSubchannelWrapper implements SubchannelInterface { getAddress(): string { return this.child.getAddress(); } + throttleKeepalive(newKeepaliveTime: number): void { + this.child.throttleKeepalive(newKeepaliveTime); + } ref(): void { this.child.ref(); } diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index b4876f178..c93e0c451 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -64,7 +64,7 @@ export class Subchannel { private backoffTimeout: BackoffTimeout; - private keepaliveTimeMultiplier = 1; + private keepaliveTime: number; /** * Tracks channels and subchannel pools with references to this subchannel */ @@ -111,6 +111,8 @@ export class Subchannel { }, backoffOptions); this.subchannelAddressString = subchannelAddressToString(subchannelAddress); + this.keepaliveTime = options['grpc.keepalive_time_ms'] ?? -1; + if (options['grpc.enable_channelz'] === 0) { this.channelzEnabled = false; } @@ -169,7 +171,7 @@ export class Subchannel { private startConnectingInternal() { let options = this.options; if (options['grpc.keepalive_time_ms']) { - const adjustedKeepaliveTime = Math.min(options['grpc.keepalive_time_ms'] * this.keepaliveTimeMultiplier, KEEPALIVE_MAX_TIME_MS); + const adjustedKeepaliveTime = Math.min(this.keepaliveTime, KEEPALIVE_MAX_TIME_MS); options = {...options, 'grpc.keepalive_time_ms': adjustedKeepaliveTime}; } this.connector.connect(this.subchannelAddress, this.credentials, options).then( @@ -181,14 +183,14 @@ export class Subchannel { } transport.addDisconnectListener((tooManyPings) => { this.transitionToState([ConnectivityState.READY], ConnectivityState.IDLE); - if (tooManyPings) { - this.keepaliveTimeMultiplier *= 2; + if (tooManyPings && this.keepaliveTime > 0) { + this.keepaliveTime *= 2; logging.log( LogVerbosity.ERROR, `Connection to ${uriToString(this.channelTarget)} at ${ this.subchannelAddressString - } rejected by server because of excess pings. Increasing ping interval multiplier to ${ - this.keepaliveTimeMultiplier + } rejected by server because of excess pings. Increasing ping interval to ${ + this.keepaliveTime } ms` ); } @@ -262,7 +264,7 @@ export class Subchannel { /* We use a shallow copy of the stateListeners array in case a listener * is removed during this iteration */ for (const listener of [...this.stateListeners]) { - listener(this, previousState, newState); + listener(this, previousState, newState, this.keepaliveTime); } return true; } @@ -403,4 +405,10 @@ export class Subchannel { getRealSubchannel(): this { return this; } + + throttleKeepalive(newKeepaliveTime: number) { + if (newKeepaliveTime > this.keepaliveTime) { + this.keepaliveTime = newKeepaliveTime; + } + } } diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index a9308471b..3c9163d13 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -77,7 +77,7 @@ class Http2Transport implements Transport { /** * The amount of time in between sending pings */ - private keepaliveTimeMs: number = KEEPALIVE_MAX_TIME_MS; + private keepaliveTimeMs: number = -1; /** * The amount of time to wait for an acknowledgement after sending a ping */ @@ -133,7 +133,7 @@ class Http2Transport implements Transport { ] .filter((e) => e) .join(' '); // remove falsey values first - + if ('grpc.keepalive_time_ms' in options) { this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; } @@ -334,6 +334,9 @@ class Http2Transport implements Transport { } private startKeepalivePings() { + if (this.keepaliveTimeMs < 0) { + return; + } this.keepaliveIntervalId = setInterval(() => { this.sendPing(); }, this.keepaliveTimeMs); From 6862af2350cceed9b39ebda1b03020c9353ec03e Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 21 Feb 2023 15:26:09 -0800 Subject: [PATCH 1855/1899] grpc-js: Fix bugs in pick first LB policy and channel subchannel wrapper --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/internal-channel.ts | 11 +++++------ packages/grpc-js/src/load-balancer-pick-first.ts | 5 +++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index aafd2803a..0ae2d6742 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.9", + "version": "1.8.10", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 4f4c879fc..14038bd3f 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -86,16 +86,14 @@ const DEFAULT_RETRY_BUFFER_SIZE_BYTES = 1<<24; // 16 MB const DEFAULT_PER_RPC_RETRY_BUFFER_SIZE_BYTES = 1<<20; // 1 MB class ChannelSubchannelWrapper extends BaseSubchannelWrapper implements SubchannelInterface { - private stateListeners: ConnectivityStateListener[] = []; private refCount = 0; + private subchannelStateListener: ConnectivityStateListener; constructor(childSubchannel: SubchannelInterface, private channel: InternalChannel) { super(childSubchannel); - childSubchannel.addConnectivityStateListener((subchannel, previousState, newState, keepaliveTime) => { + this.subchannelStateListener = (subchannel, previousState, newState, keepaliveTime) => { channel.throttleKeepalive(keepaliveTime); - for (const listener of this.stateListeners) { - listener(this, previousState, newState, keepaliveTime); - } - }); + }; + childSubchannel.addConnectivityStateListener(this.subchannelStateListener); } ref(): void { @@ -107,6 +105,7 @@ class ChannelSubchannelWrapper extends BaseSubchannelWrapper implements Subchann this.child.unref(); this.refCount -= 1; if (this.refCount <= 0) { + this.child.removeConnectivityStateListener(this.subchannelStateListener); this.channel.removeWrappedSubchannel(this); } } diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 027eae074..1f6530e44 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -33,6 +33,7 @@ import { } from './picker'; import { SubchannelAddress, + subchannelAddressEqual, subchannelAddressToString, } from './subchannel-address'; import * as logging from './logging'; @@ -168,7 +169,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { * connecting to the next one instead of waiting for the connection * delay timer. */ if ( - subchannel === this.subchannels[this.currentSubchannelIndex] && + subchannel.getRealSubchannel() === this.subchannels[this.currentSubchannelIndex].getRealSubchannel() && newState === ConnectivityState.TRANSIENT_FAILURE ) { this.startNextSubchannelConnecting(); @@ -420,7 +421,7 @@ export class PickFirstLoadBalancer implements LoadBalancer { if ( this.subchannels.length === 0 || !this.latestAddressList.every( - (value, index) => addressList[index] === value + (value, index) => subchannelAddressEqual(addressList[index], value) ) ) { this.latestAddressList = addressList; From 1f14d1c138b9e6297ee097264185b24498f3059b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 23 Feb 2023 17:49:03 -0800 Subject: [PATCH 1856/1899] grpc-js: Stop leaking freed message buffer placeholder objects --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/retrying-call.ts | 61 +++++++++++++++------------ 2 files changed, 34 insertions(+), 29 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 0ae2d6742..f75f780db 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.10", + "version": "1.8.11", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index a9424373e..5ae585b9e 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -151,6 +151,12 @@ export class RetryingCall implements Call { private initialMetadata: Metadata | null = null; private underlyingCalls: UnderlyingCall[] = []; private writeBuffer: WriteBufferEntry[] = []; + /** + * The offset of message indices in the writeBuffer. For example, if + * writeBufferOffset is 10, message 10 is in writeBuffer[0] and message 15 + * is in writeBuffer[5]. + */ + private writeBufferOffset = 0; /** * Tracks whether a read has been started, so that we know whether to start * reads on new child calls. This only matters for the first read, because @@ -203,14 +209,8 @@ export class RetryingCall implements Call { private reportStatus(statusObject: StatusObject) { this.trace('ended with status: code=' + statusObject.code + ' details="' + statusObject.details + '"'); this.bufferTracker.freeAll(this.callNumber); - for (let i = 0; i < this.writeBuffer.length; i++) { - if (this.writeBuffer[i].entryType === 'MESSAGE') { - this.writeBuffer[i] = { - entryType: 'FREED', - allocated: false - }; - } - } + this.writeBufferOffset = this.writeBufferOffset + this.writeBuffer.length; + this.writeBuffer = []; process.nextTick(() => { // Explicitly construct status object to remove progress field this.listener?.onReceiveStatus({ @@ -236,20 +236,27 @@ export class RetryingCall implements Call { } } - private maybefreeMessageBufferEntry(messageIndex: number) { + private getBufferEntry(messageIndex: number): WriteBufferEntry { + return this.writeBuffer[messageIndex - this.writeBufferOffset] ?? {entryType: 'FREED', allocated: false}; + } + + private getNextBufferIndex() { + return this.writeBufferOffset + this.writeBuffer.length; + } + + private clearSentMessages() { if (this.state !== 'COMMITTED') { return; } - const bufferEntry = this.writeBuffer[messageIndex]; - if (bufferEntry.entryType === 'MESSAGE') { + const earliestNeededMessageIndex = this.underlyingCalls[this.committedCallIndex!].nextMessageToSend; + for (let messageIndex = this.writeBufferOffset; messageIndex < earliestNeededMessageIndex; messageIndex++) { + const bufferEntry = this.getBufferEntry(messageIndex); if (bufferEntry.allocated) { this.bufferTracker.free(bufferEntry.message!.message.length, this.callNumber); } - this.writeBuffer[messageIndex] = { - entryType: 'FREED', - allocated: false - }; } + this.writeBuffer = this.writeBuffer.slice(earliestNeededMessageIndex - this.writeBufferOffset); + this.writeBufferOffset = earliestNeededMessageIndex; } private commitCall(index: number) { @@ -272,9 +279,7 @@ export class RetryingCall implements Call { this.underlyingCalls[i].state = 'COMPLETED'; this.underlyingCalls[i].call.cancelWithStatus(Status.CANCELLED, 'Discarded in favor of other hedged attempt'); } - for (let messageIndex = 0; messageIndex < this.underlyingCalls[index].nextMessageToSend - 1; messageIndex += 1) { - this.maybefreeMessageBufferEntry(messageIndex); - } + this.clearSentMessages(); } private commitCallWithMostMessages() { @@ -555,8 +560,8 @@ export class RetryingCall implements Call { private handleChildWriteCompleted(childIndex: number) { const childCall = this.underlyingCalls[childIndex]; const messageIndex = childCall.nextMessageToSend; - this.writeBuffer[messageIndex].callback?.(); - this.maybefreeMessageBufferEntry(messageIndex); + this.getBufferEntry(messageIndex).callback?.(); + this.clearSentMessages(); childCall.nextMessageToSend += 1; this.sendNextChildMessage(childIndex); } @@ -566,10 +571,10 @@ export class RetryingCall implements Call { if (childCall.state === 'COMPLETED') { return; } - if (this.writeBuffer[childCall.nextMessageToSend]) { - const bufferEntry = this.writeBuffer[childCall.nextMessageToSend]; + if (this.getBufferEntry(childCall.nextMessageToSend)) { + const bufferEntry = this.getBufferEntry(childCall.nextMessageToSend); switch (bufferEntry.entryType) { - case 'MESSAGE': + case 'MESSAGE': childCall.call.sendMessageWithContext({ callback: (error) => { // Ignore error @@ -594,13 +599,13 @@ export class RetryingCall implements Call { message, flags: context.flags, }; - const messageIndex = this.writeBuffer.length; + const messageIndex = this.getNextBufferIndex(); const bufferEntry: WriteBufferEntry = { entryType: 'MESSAGE', message: writeObj, allocated: this.bufferTracker.allocate(message.length, this.callNumber) }; - this.writeBuffer[messageIndex] = bufferEntry; + this.writeBuffer.push(bufferEntry); if (bufferEntry.allocated) { context.callback?.(); for (const [callIndex, call] of this.underlyingCalls.entries()) { @@ -642,11 +647,11 @@ export class RetryingCall implements Call { } halfClose(): void { this.trace('halfClose called'); - const halfCloseIndex = this.writeBuffer.length; - this.writeBuffer[halfCloseIndex] = { + const halfCloseIndex = this.getNextBufferIndex(); + this.writeBuffer.push({ entryType: 'HALF_CLOSE', allocated: false - }; + }); for (const call of this.underlyingCalls) { if (call?.state === 'ACTIVE' && call.nextMessageToSend === halfCloseIndex) { call.nextMessageToSend += 1; From 0726fdf290116faaae9c1aea36c30061983c284d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Mar 2023 10:11:46 -0800 Subject: [PATCH 1857/1899] grpc-js: Fix address equality check in pick-first --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/load-balancer-pick-first.ts | 3 ++- packages/grpc-js/src/subchannel-address.ts | 10 ++++++++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f75f780db..722f9d866 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.11", + "version": "1.8.12", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index 1f6530e44..a501b1f7d 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -420,8 +420,9 @@ export class PickFirstLoadBalancer implements LoadBalancer { * address list is different from the existing one */ if ( this.subchannels.length === 0 || + this.latestAddressList.length !== addressList.length || !this.latestAddressList.every( - (value, index) => subchannelAddressEqual(addressList[index], value) + (value, index) => addressList[index] && subchannelAddressEqual(addressList[index], value) ) ) { this.latestAddressList = addressList; diff --git a/packages/grpc-js/src/subchannel-address.ts b/packages/grpc-js/src/subchannel-address.ts index 29022caa5..e542e645e 100644 --- a/packages/grpc-js/src/subchannel-address.ts +++ b/packages/grpc-js/src/subchannel-address.ts @@ -41,9 +41,15 @@ export function isTcpSubchannelAddress( } export function subchannelAddressEqual( - address1: SubchannelAddress, - address2: SubchannelAddress + address1?: SubchannelAddress, + address2?: SubchannelAddress ): boolean { + if (!address1 && !address2) { + return true; + } + if (!address1 || !address2) { + return false; + } if (isTcpSubchannelAddress(address1)) { return ( isTcpSubchannelAddress(address2) && From c23c67cd4fa4b327503b5247584ed96d078a7a97 Mon Sep 17 00:00:00 2001 From: Ulrich Van Den Hekke Date: Sun, 26 Feb 2023 13:14:32 +0100 Subject: [PATCH 1858/1899] grpc-js: add await/async on method that return promise add await/async on method that return promise to ensure that the order of message (and of the end of stream) are preserved --- packages/grpc-js/src/server-call.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 8dcf6be33..48186bc29 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -812,10 +812,10 @@ export class Http2ServerCallStream< let pushedEnd = false; - const maybePushEnd = () => { + const maybePushEnd = async () => { if (!pushedEnd && readsDone && !pendingMessageProcessing) { pushedEnd = true; - this.pushOrBufferMessage(readable, null); + await this.pushOrBufferMessage(readable, null); } }; @@ -848,16 +848,16 @@ export class Http2ServerCallStream< // Just return early if (!decompressedMessage) return; - this.pushOrBufferMessage(readable, decompressedMessage); + await this.pushOrBufferMessage(readable, decompressedMessage); } pendingMessageProcessing = false; this.stream.resume(); - maybePushEnd(); + await maybePushEnd(); }); - this.stream.once('end', () => { + this.stream.once('end', async () => { readsDone = true; - maybePushEnd(); + await maybePushEnd(); }); } @@ -881,16 +881,16 @@ export class Http2ServerCallStream< return this.canPush; } - private pushOrBufferMessage( + private async pushOrBufferMessage( readable: | ServerReadableStream | ServerDuplexStream, messageBytes: Buffer | null - ): void { + ): Promise { if (this.isPushPending) { this.bufferedMessages.push(messageBytes); } else { - this.pushMessage(readable, messageBytes); + await this.pushMessage(readable, messageBytes); } } @@ -943,7 +943,7 @@ export class Http2ServerCallStream< this.isPushPending = false; if (this.bufferedMessages.length > 0) { - this.pushMessage( + await this.pushMessage( readable, this.bufferedMessages.shift() as Buffer | null ); From c525025f06647d022d5201a08fc179eff1b6bcc1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 Mar 2023 15:10:29 -0800 Subject: [PATCH 1859/1899] grpc-js: Trace before call to LB policy picker --- packages/grpc-js/src/load-balancing-call.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index 48aaf48ac..f74933983 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -102,6 +102,7 @@ export class LoadBalancingCall implements Call { if (!this.metadata) { throw new Error('doPick called before start'); } + this.trace('Pick called') const pickResult = this.channel.doPick(this.metadata, this.callConfig.pickInformation); const subchannelString = pickResult.subchannel ? '(' + pickResult.subchannel.getChannelzRef().id + ') ' + pickResult.subchannel.getAddress() : From 79161816e6b76d5fea787d8329f038d00fb156c5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 7 Mar 2023 14:58:58 -0800 Subject: [PATCH 1860/1899] grpc-js: Add more logging to trace handling of received messages --- packages/grpc-js/src/resolving-call.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index b6398126c..f29fb7fd7 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -178,13 +178,17 @@ export class ResolvingCall implements Call { this.filterStack = this.filterStackFactory.createFilter(); this.filterStack.sendMetadata(Promise.resolve(this.metadata)).then(filteredMetadata => { this.child = this.channel.createInnerCall(config, this.method, this.host, this.credentials, this.deadline); + this.trace('Created child [' + this.child.getCallNumber() + ']') this.child.start(filteredMetadata, { onReceiveMetadata: metadata => { + this.trace('Received metadata') this.listener!.onReceiveMetadata(this.filterStack!.receiveMetadata(metadata)); }, onReceiveMessage: message => { + this.trace('Received message'); this.readFilterPending = true; this.filterStack!.receiveMessage(message).then(filteredMesssage => { + this.trace('Finished filtering received message'); this.readFilterPending = false; this.listener!.onReceiveMessage(filteredMesssage); if (this.pendingChildStatus) { @@ -195,6 +199,7 @@ export class ResolvingCall implements Call { }); }, onReceiveStatus: status => { + this.trace('Received status'); if (this.readFilterPending) { this.pendingChildStatus = status; } else { From 481f704c775d78de363a7311a28b087c124c97c0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 9 Mar 2023 16:37:04 -0800 Subject: [PATCH 1861/1899] grpc-js-xds: Populate Node message field user_agent_version --- packages/grpc-js-xds/package.json | 2 +- packages/grpc-js-xds/src/xds-client.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index c0c3200f5..0d8080f96 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.8.0", + "version": "1.8.1", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 2dfa41236..bd4bd84cb 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -334,11 +334,13 @@ export class XdsClient { this.adsNode = { ...bootstrapInfo.node, user_agent_name: userAgentName, + user_agent_version: clientVersion, client_features: ['envoy.lb.does_not_support_overprovisioning'], }; this.lrsNode = { ...bootstrapInfo.node, user_agent_name: userAgentName, + user_agent_version: clientVersion, client_features: ['envoy.lrs.supports_send_all_clusters'], }; setCsdsClientNode(this.adsNode); From 6bc6b8665bef8e158121fc5ce5608dd2da748bb1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 25 Jan 2023 09:50:49 -0800 Subject: [PATCH 1862/1899] grpc-js-xds: Add unit test framework --- packages/grpc-js-xds/package.json | 3 +- .../grpc-js-xds/proto/grpc/testing/echo.proto | 70 ++++ .../proto/grpc/testing/echo_messages.proto | 74 ++++ .../proto/grpc/testing/simple_messages.proto | 26 ++ .../testing/xds/v3/orca_load_report.proto | 44 +++ packages/grpc-js-xds/test/backend.ts | 105 ++++++ packages/grpc-js-xds/test/client.ts | 72 ++++ packages/grpc-js-xds/test/framework.ts | 208 +++++++++++ packages/grpc-js-xds/test/generated/echo.ts | 46 +++ .../test/generated/grpc/testing/DebugInfo.ts | 18 + .../generated/grpc/testing/EchoRequest.ts | 13 + .../generated/grpc/testing/EchoResponse.ts | 13 + .../grpc/testing/EchoTest1Service.ts | 117 ++++++ .../grpc/testing/EchoTest2Service.ts | 117 ++++++ .../generated/grpc/testing/EchoTestService.ts | 150 ++++++++ .../generated/grpc/testing/ErrorStatus.ts | 20 + .../generated/grpc/testing/NoRpcService.ts | 19 + .../generated/grpc/testing/RequestParams.ts | 75 ++++ .../generated/grpc/testing/ResponseParams.ts | 15 + .../generated/grpc/testing/SimpleRequest.ts | 8 + .../generated/grpc/testing/SimpleResponse.ts | 8 + .../generated/grpc/testing/StringValue.ts | 10 + .../grpc/testing/UnimplementedEchoService.ts | 27 ++ .../xds/data/orca/v3/OrcaLoadReport.ts | 59 +++ packages/grpc-js-xds/test/test-core.ts | 63 ++++ packages/grpc-js-xds/test/xds-server.ts | 342 ++++++++++++++++++ 26 files changed, 1721 insertions(+), 1 deletion(-) create mode 100644 packages/grpc-js-xds/proto/grpc/testing/echo.proto create mode 100644 packages/grpc-js-xds/proto/grpc/testing/echo_messages.proto create mode 100644 packages/grpc-js-xds/proto/grpc/testing/simple_messages.proto create mode 100644 packages/grpc-js-xds/proto/grpc/testing/xds/v3/orca_load_report.proto create mode 100644 packages/grpc-js-xds/test/backend.ts create mode 100644 packages/grpc-js-xds/test/client.ts create mode 100644 packages/grpc-js-xds/test/framework.ts create mode 100644 packages/grpc-js-xds/test/generated/echo.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/DebugInfo.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/EchoRequest.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/EchoResponse.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/EchoTest1Service.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/EchoTest2Service.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/EchoTestService.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/ErrorStatus.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/NoRpcService.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/RequestParams.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/ResponseParams.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/SimpleRequest.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/SimpleResponse.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/StringValue.ts create mode 100644 packages/grpc-js-xds/test/generated/grpc/testing/UnimplementedEchoService.ts create mode 100644 packages/grpc-js-xds/test/generated/xds/data/orca/v3/OrcaLoadReport.ts create mode 100644 packages/grpc-js-xds/test/test-core.ts create mode 100644 packages/grpc-js-xds/test/xds-server.ts diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index c0c3200f5..bd1511e5a 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -13,7 +13,8 @@ "pretest": "npm run compile", "posttest": "npm run check", "generate-types": "proto-loader-gen-types --keepCase --longs String --enums String --defaults --oneofs --includeComments --includeDirs deps/envoy-api/ deps/xds/ deps/googleapis/ deps/protoc-gen-validate/ -O src/generated/ --grpcLib @grpc/grpc-js envoy/service/discovery/v3/ads.proto envoy/service/load_stats/v3/lrs.proto envoy/config/listener/v3/listener.proto envoy/config/route/v3/route.proto envoy/config/cluster/v3/cluster.proto envoy/config/endpoint/v3/endpoint.proto envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto udpa/type/v1/typed_struct.proto xds/type/v3/typed_struct.proto envoy/extensions/filters/http/fault/v3/fault.proto envoy/service/status/v3/csds.proto", - "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto" + "generate-interop-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O interop/generated --grpcLib @grpc/grpc-js grpc/testing/test.proto", + "generate-test-types": "proto-loader-gen-types --keep-case --longs String --enums String --defaults --oneofs --json --includeComments --includeDirs proto/ -O test/generated --grpcLib @grpc/grpc-js grpc/testing/echo.proto" }, "repository": { "type": "git", diff --git a/packages/grpc-js-xds/proto/grpc/testing/echo.proto b/packages/grpc-js-xds/proto/grpc/testing/echo.proto new file mode 100644 index 000000000..7f444b43f --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/echo.proto @@ -0,0 +1,70 @@ + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +import "grpc/testing/echo_messages.proto"; +import "grpc/testing/simple_messages.proto"; + +service EchoTestService { + rpc Echo(EchoRequest) returns (EchoResponse); + rpc Echo1(EchoRequest) returns (EchoResponse); + rpc Echo2(EchoRequest) returns (EchoResponse); + rpc CheckDeadlineUpperBound(SimpleRequest) returns (StringValue); + rpc CheckDeadlineSet(SimpleRequest) returns (StringValue); + // A service which checks that the initial metadata sent over contains some + // expected key value pair + rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse); + rpc RequestStream(stream EchoRequest) returns (EchoResponse); + rpc ResponseStream(EchoRequest) returns (stream EchoResponse); + rpc BidiStream(stream EchoRequest) returns (stream EchoResponse); + rpc Unimplemented(EchoRequest) returns (EchoResponse); + rpc UnimplementedBidi(stream EchoRequest) returns (stream EchoResponse); +} + +service EchoTest1Service { + rpc Echo(EchoRequest) returns (EchoResponse); + rpc Echo1(EchoRequest) returns (EchoResponse); + rpc Echo2(EchoRequest) returns (EchoResponse); + // A service which checks that the initial metadata sent over contains some + // expected key value pair + rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse); + rpc RequestStream(stream EchoRequest) returns (EchoResponse); + rpc ResponseStream(EchoRequest) returns (stream EchoResponse); + rpc BidiStream(stream EchoRequest) returns (stream EchoResponse); + rpc Unimplemented(EchoRequest) returns (EchoResponse); +} + +service EchoTest2Service { + rpc Echo(EchoRequest) returns (EchoResponse); + rpc Echo1(EchoRequest) returns (EchoResponse); + rpc Echo2(EchoRequest) returns (EchoResponse); + // A service which checks that the initial metadata sent over contains some + // expected key value pair + rpc CheckClientInitialMetadata(SimpleRequest) returns (SimpleResponse); + rpc RequestStream(stream EchoRequest) returns (EchoResponse); + rpc ResponseStream(EchoRequest) returns (stream EchoResponse); + rpc BidiStream(stream EchoRequest) returns (stream EchoResponse); + rpc Unimplemented(EchoRequest) returns (EchoResponse); +} + +service UnimplementedEchoService { + rpc Unimplemented(EchoRequest) returns (EchoResponse); +} + +// A service without any rpc defined to test coverage. +service NoRpcService {} diff --git a/packages/grpc-js-xds/proto/grpc/testing/echo_messages.proto b/packages/grpc-js-xds/proto/grpc/testing/echo_messages.proto new file mode 100644 index 000000000..44f22133e --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/echo_messages.proto @@ -0,0 +1,74 @@ + +// Copyright 2015 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +option cc_enable_arenas = true; + +import "grpc/testing/xds/v3/orca_load_report.proto"; + +// Message to be echoed back serialized in trailer. +message DebugInfo { + repeated string stack_entries = 1; + string detail = 2; +} + +// Error status client expects to see. +message ErrorStatus { + int32 code = 1; + string error_message = 2; + string binary_error_details = 3; +} + +message RequestParams { + bool echo_deadline = 1; + int32 client_cancel_after_us = 2; + int32 server_cancel_after_us = 3; + bool echo_metadata = 4; + bool check_auth_context = 5; + int32 response_message_length = 6; + bool echo_peer = 7; + string expected_client_identity = 8; // will force check_auth_context. + bool skip_cancelled_check = 9; + string expected_transport_security_type = 10; + DebugInfo debug_info = 11; + bool server_die = 12; // Server should not see a request with this set. + string binary_error_details = 13; + ErrorStatus expected_error = 14; + int32 server_sleep_us = 15; // sleep when invoking server for deadline tests + int32 backend_channel_idx = 16; // which backend to send request to + bool echo_metadata_initially = 17; + bool server_notify_client_when_started = 18; + xds.data.orca.v3.OrcaLoadReport backend_metrics = 19; + bool echo_host_from_authority_header = 20; +} + +message EchoRequest { + string message = 1; + RequestParams param = 2; +} + +message ResponseParams { + int64 request_deadline = 1; + string host = 2; + string peer = 3; +} + +message EchoResponse { + string message = 1; + ResponseParams param = 2; +} diff --git a/packages/grpc-js-xds/proto/grpc/testing/simple_messages.proto b/packages/grpc-js-xds/proto/grpc/testing/simple_messages.proto new file mode 100644 index 000000000..3afe236b4 --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/simple_messages.proto @@ -0,0 +1,26 @@ + +// Copyright 2018 gRPC authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package grpc.testing; + +message SimpleRequest {} + +message SimpleResponse {} + +message StringValue { + string message = 1; +} diff --git a/packages/grpc-js-xds/proto/grpc/testing/xds/v3/orca_load_report.proto b/packages/grpc-js-xds/proto/grpc/testing/xds/v3/orca_load_report.proto new file mode 100644 index 000000000..033e64ba4 --- /dev/null +++ b/packages/grpc-js-xds/proto/grpc/testing/xds/v3/orca_load_report.proto @@ -0,0 +1,44 @@ +// Copyright 2020 The gRPC Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Local copy of Envoy xDS proto file, used for testing only. + +syntax = "proto3"; + +package xds.data.orca.v3; + +// See section `ORCA load report format` of the design document in +// :ref:`https://github.com/envoyproxy/envoy/issues/6614`. + +message OrcaLoadReport { + // CPU utilization expressed as a fraction of available CPU resources. This + // should be derived from the latest sample or measurement. + double cpu_utilization = 1; + + // Memory utilization expressed as a fraction of available memory + // resources. This should be derived from the latest sample or measurement. + double mem_utilization = 2; + + // Total RPS being served by an endpoint. This should cover all services that an endpoint is + // responsible for. + uint64 rps = 3; + + // Application specific requests costs. Each value is an absolute cost (e.g. 3487 bytes of + // storage) associated with the request. + map request_cost = 4; + + // Resource utilization values. Each value is expressed as a fraction of total resources + // available, derived from the latest sample or measurement. + map utilization = 5; +} diff --git a/packages/grpc-js-xds/test/backend.ts b/packages/grpc-js-xds/test/backend.ts new file mode 100644 index 000000000..ce509c556 --- /dev/null +++ b/packages/grpc-js-xds/test/backend.ts @@ -0,0 +1,105 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { loadPackageDefinition, sendUnaryData, Server, ServerCredentials, ServerUnaryCall, UntypedServiceImplementation } from "@grpc/grpc-js"; +import { loadSync } from "@grpc/proto-loader"; +import { ProtoGrpcType } from "./generated/echo"; +import { EchoRequest__Output } from "./generated/grpc/testing/EchoRequest"; +import { EchoResponse } from "./generated/grpc/testing/EchoResponse"; + +const loadedProtos = loadPackageDefinition(loadSync( + [ + 'grpc/testing/echo.proto' + ], + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + json: true, + includeDirs: [ + // Paths are relative to build/test + __dirname + '/../../proto/' + ], + })) as unknown as ProtoGrpcType; + +export class Backend { + private server: Server; + private receivedCallCount = 0; + private callListeners: (() => void)[] = []; + private port: number | null = null; + constructor() { + this.server = new Server(); + this.server.addService(loadedProtos.grpc.testing.EchoTestService.service, this as unknown as UntypedServiceImplementation); + } + Echo(call: ServerUnaryCall, callback: sendUnaryData) { + // call.request.params is currently ignored + this.addCall(); + callback(null, {message: call.request.message}); + } + + addCall() { + this.receivedCallCount++; + this.callListeners.forEach(listener => listener()); + } + + onCall(listener: () => void) { + this.callListeners.push(listener); + } + + start(callback: (error: Error | null, port: number) => void) { + this.server.bindAsync('localhost:0', ServerCredentials.createInsecure(), (error, port) => { + if (!error) { + this.port = port; + this.server.start(); + } + callback(error, port); + }) + } + + startAsync(): Promise { + return new Promise((resolve, reject) => { + this.start((error, port) => { + if (error) { + reject(error); + } else { + resolve(port); + } + }); + }); + } + + getPort(): number { + if (this.port === null) { + throw new Error('Port not set. Backend not yet started.'); + } + return this.port; + } + + getCallCount() { + return this.receivedCallCount; + } + + resetCallCount() { + this.receivedCallCount = 0; + } + + shutdown(callback: (error?: Error) => void) { + this.server.tryShutdown(callback); + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/test/client.ts b/packages/grpc-js-xds/test/client.ts new file mode 100644 index 000000000..6404a3eb2 --- /dev/null +++ b/packages/grpc-js-xds/test/client.ts @@ -0,0 +1,72 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { credentials, loadPackageDefinition } from "@grpc/grpc-js"; +import { loadSync } from "@grpc/proto-loader"; +import { ProtoGrpcType } from "./generated/echo"; +import { EchoTestServiceClient } from "./generated/grpc/testing/EchoTestService"; +import { XdsServer } from "./xds-server"; + +const loadedProtos = loadPackageDefinition(loadSync( + [ + 'grpc/testing/echo.proto' + ], + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + json: true, + includeDirs: [ + // Paths are relative to build/test + __dirname + '/../../proto/' + ], + })) as unknown as ProtoGrpcType; + +const BOOTSTRAP_CONFIG_KEY = 'grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config'; + +export class XdsTestClient { + private client: EchoTestServiceClient; + private callInterval: NodeJS.Timer; + + constructor(targetName: string, xdsServer: XdsServer) { + this.client = new loadedProtos.grpc.testing.EchoTestService(`xds:///${targetName}`, credentials.createInsecure(), {[BOOTSTRAP_CONFIG_KEY]: xdsServer.getBootstrapInfoString()}); + this.callInterval = setInterval(() => {}, 0); + clearInterval(this.callInterval); + } + + startCalls(interval: number) { + clearInterval(this.callInterval); + this.callInterval = setInterval(() => { + this.client.echo({message: 'test'}, (error, value) => { + if (error) { + throw error; + } + }); + }, interval); + } + + stopCalls() { + clearInterval(this.callInterval); + } + + close() { + this.stopCalls(); + this.client.close(); + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/test/framework.ts b/packages/grpc-js-xds/test/framework.ts new file mode 100644 index 000000000..945b08a3a --- /dev/null +++ b/packages/grpc-js-xds/test/framework.ts @@ -0,0 +1,208 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ClusterLoadAssignment } from "../src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; +import { Cluster } from "../src/generated/envoy/config/cluster/v3/Cluster"; +import { Backend } from "./backend"; +import { Locality } from "../src/generated/envoy/config/core/v3/Locality"; +import { RouteConfiguration } from "../src/generated/envoy/config/route/v3/RouteConfiguration"; +import { Route } from "../src/generated/envoy/config/route/v3/Route"; +import { Listener } from "../src/generated/envoy/config/listener/v3/Listener"; +import { HttpConnectionManager } from "../src/generated/envoy/extensions/filters/network/http_connection_manager/v3/HttpConnectionManager"; +import { AnyExtension } from "@grpc/proto-loader"; +import { HTTP_CONNECTION_MANGER_TYPE_URL } from "../src/resources"; +import { LocalityLbEndpoints } from "../src/generated/envoy/config/endpoint/v3/LocalityLbEndpoints"; +import { LbEndpoint } from "../src/generated/envoy/config/endpoint/v3/LbEndpoint"; + +interface Endpoint { + locality: Locality; + backends: Backend[]; + weight?: number; + priority?: number; +} + +function getLbEndpoint(backend: Backend): LbEndpoint { + return { + health_status: "HEALTHY", + endpoint: { + address: { + socket_address: { + address: '::1', + port_value: backend.getPort() + } + } + } + }; +} + +function getLocalityLbEndpoints(endpoint: Endpoint): LocalityLbEndpoints { + return { + lb_endpoints: endpoint.backends.map(getLbEndpoint), + locality: endpoint.locality, + load_balancing_weight: {value: endpoint.weight ?? 1}, + priority: endpoint.priority ?? 0 + } +} + +export class FakeCluster { + constructor(private name: string, private endpoints: Endpoint[]) {} + + getEndpointConfig(): ClusterLoadAssignment { + return { + cluster_name: this.name, + endpoints: this.endpoints.map(getLocalityLbEndpoints) + }; + } + + getClusterConfig(): Cluster { + return { + name: this.name, + type: 'EDS', + eds_cluster_config: {eds_config: {ads: {}}}, + lb_policy: 'ROUND_ROBIN' + } + } + + getName() { + return this.name; + } + + startAllBackends(): Promise { + return Promise.all(this.endpoints.map(endpoint => Promise.all(endpoint.backends.map(backend => backend.startAsync())))); + } + + private haveAllBackendsReceivedTraffic(): boolean { + for (const endpoint of this.endpoints) { + for (const backend of endpoint.backends) { + if (backend.getCallCount() < 1) { + return false; + } + } + } + return true; + } + + waitForAllBackendsToReceiveTraffic(): Promise { + for (const endpoint of this.endpoints) { + for (const backend of endpoint.backends) { + backend.resetCallCount(); + } + } + return new Promise((resolve, reject) => { + let finishedPromise = false; + for (const endpoint of this.endpoints) { + for (const backend of endpoint.backends) { + backend.onCall(() => { + if (finishedPromise) { + return; + } + if (this.haveAllBackendsReceivedTraffic()) { + finishedPromise = true; + resolve(); + } + }); + } + } + }); + } +} + +interface FakeRoute { + cluster?: FakeCluster; + weightedClusters?: [{cluster: FakeCluster, weight: number}]; +} + +function createRouteConfig(route: FakeRoute): Route { + if (route.cluster) { + return { + match: { + prefix: '' + }, + route: { + cluster: route.cluster.getName() + } + }; + } else { + return { + match: { + prefix: '' + }, + route: { + weighted_clusters: { + clusters: route.weightedClusters!.map(clusterWeight => ({ + name: clusterWeight.cluster.getName(), + weight: {value: clusterWeight.weight} + })) + } + } + } + } +} + +export class FakeRouteGroup { + constructor(private name: string, private routes: FakeRoute[]) {} + + getRouteConfiguration(): RouteConfiguration { + return { + name: this.name, + virtual_hosts: [{ + domains: ['*'], + routes: this.routes.map(createRouteConfig) + }] + }; + } + + getListener(): Listener { + const httpConnectionManager: HttpConnectionManager & AnyExtension = { + '@type': HTTP_CONNECTION_MANGER_TYPE_URL, + rds: { + route_config_name: this.name, + config_source: {ads: {}} + } + } + return { + name: this.name, + api_listener: { + api_listener: httpConnectionManager + } + }; + } + + startAllBackends(): Promise { + return Promise.all(this.routes.map(route => { + if (route.cluster) { + return route.cluster.startAllBackends(); + } else if (route.weightedClusters) { + return Promise.all(route.weightedClusters.map(clusterWeight => clusterWeight.cluster.startAllBackends())); + } else { + return Promise.resolve(); + } + })); + } + + waitForAllBackendsToReceiveTraffic(): Promise { + return Promise.all(this.routes.map(route => { + if (route.cluster) { + return route.cluster.waitForAllBackendsToReceiveTraffic(); + } else if (route.weightedClusters) { + return Promise.all(route.weightedClusters.map(clusterWeight => clusterWeight.cluster.waitForAllBackendsToReceiveTraffic())).then(() => {}); + } else { + return Promise.resolve(); + } + })); + } +} \ No newline at end of file diff --git a/packages/grpc-js-xds/test/generated/echo.ts b/packages/grpc-js-xds/test/generated/echo.ts new file mode 100644 index 000000000..537a49cfa --- /dev/null +++ b/packages/grpc-js-xds/test/generated/echo.ts @@ -0,0 +1,46 @@ +import type * as grpc from '@grpc/grpc-js'; +import type { MessageTypeDefinition } from '@grpc/proto-loader'; + +import type { EchoTest1ServiceClient as _grpc_testing_EchoTest1ServiceClient, EchoTest1ServiceDefinition as _grpc_testing_EchoTest1ServiceDefinition } from './grpc/testing/EchoTest1Service'; +import type { EchoTest2ServiceClient as _grpc_testing_EchoTest2ServiceClient, EchoTest2ServiceDefinition as _grpc_testing_EchoTest2ServiceDefinition } from './grpc/testing/EchoTest2Service'; +import type { EchoTestServiceClient as _grpc_testing_EchoTestServiceClient, EchoTestServiceDefinition as _grpc_testing_EchoTestServiceDefinition } from './grpc/testing/EchoTestService'; +import type { NoRpcServiceClient as _grpc_testing_NoRpcServiceClient, NoRpcServiceDefinition as _grpc_testing_NoRpcServiceDefinition } from './grpc/testing/NoRpcService'; +import type { UnimplementedEchoServiceClient as _grpc_testing_UnimplementedEchoServiceClient, UnimplementedEchoServiceDefinition as _grpc_testing_UnimplementedEchoServiceDefinition } from './grpc/testing/UnimplementedEchoService'; + +type SubtypeConstructor any, Subtype> = { + new(...args: ConstructorParameters): Subtype; +}; + +export interface ProtoGrpcType { + grpc: { + testing: { + DebugInfo: MessageTypeDefinition + EchoRequest: MessageTypeDefinition + EchoResponse: MessageTypeDefinition + EchoTest1Service: SubtypeConstructor & { service: _grpc_testing_EchoTest1ServiceDefinition } + EchoTest2Service: SubtypeConstructor & { service: _grpc_testing_EchoTest2ServiceDefinition } + EchoTestService: SubtypeConstructor & { service: _grpc_testing_EchoTestServiceDefinition } + ErrorStatus: MessageTypeDefinition + /** + * A service without any rpc defined to test coverage. + */ + NoRpcService: SubtypeConstructor & { service: _grpc_testing_NoRpcServiceDefinition } + RequestParams: MessageTypeDefinition + ResponseParams: MessageTypeDefinition + SimpleRequest: MessageTypeDefinition + SimpleResponse: MessageTypeDefinition + StringValue: MessageTypeDefinition + UnimplementedEchoService: SubtypeConstructor & { service: _grpc_testing_UnimplementedEchoServiceDefinition } + } + } + xds: { + data: { + orca: { + v3: { + OrcaLoadReport: MessageTypeDefinition + } + } + } + } +} + diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/DebugInfo.ts b/packages/grpc-js-xds/test/generated/grpc/testing/DebugInfo.ts new file mode 100644 index 000000000..123188fe3 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/DebugInfo.ts @@ -0,0 +1,18 @@ +// Original file: proto/grpc/testing/echo_messages.proto + + +/** + * Message to be echoed back serialized in trailer. + */ +export interface DebugInfo { + 'stack_entries'?: (string)[]; + 'detail'?: (string); +} + +/** + * Message to be echoed back serialized in trailer. + */ +export interface DebugInfo__Output { + 'stack_entries': (string)[]; + 'detail': (string); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/EchoRequest.ts b/packages/grpc-js-xds/test/generated/grpc/testing/EchoRequest.ts new file mode 100644 index 000000000..cadf04f7a --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/EchoRequest.ts @@ -0,0 +1,13 @@ +// Original file: proto/grpc/testing/echo_messages.proto + +import type { RequestParams as _grpc_testing_RequestParams, RequestParams__Output as _grpc_testing_RequestParams__Output } from '../../grpc/testing/RequestParams'; + +export interface EchoRequest { + 'message'?: (string); + 'param'?: (_grpc_testing_RequestParams | null); +} + +export interface EchoRequest__Output { + 'message': (string); + 'param': (_grpc_testing_RequestParams__Output | null); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/EchoResponse.ts b/packages/grpc-js-xds/test/generated/grpc/testing/EchoResponse.ts new file mode 100644 index 000000000..d54beaf4f --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/EchoResponse.ts @@ -0,0 +1,13 @@ +// Original file: proto/grpc/testing/echo_messages.proto + +import type { ResponseParams as _grpc_testing_ResponseParams, ResponseParams__Output as _grpc_testing_ResponseParams__Output } from '../../grpc/testing/ResponseParams'; + +export interface EchoResponse { + 'message'?: (string); + 'param'?: (_grpc_testing_ResponseParams | null); +} + +export interface EchoResponse__Output { + 'message': (string); + 'param': (_grpc_testing_ResponseParams__Output | null); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/EchoTest1Service.ts b/packages/grpc-js-xds/test/generated/grpc/testing/EchoTest1Service.ts new file mode 100644 index 000000000..a2b1947f6 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/EchoTest1Service.ts @@ -0,0 +1,117 @@ +// Original file: proto/grpc/testing/echo.proto + +import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { EchoRequest as _grpc_testing_EchoRequest, EchoRequest__Output as _grpc_testing_EchoRequest__Output } from '../../grpc/testing/EchoRequest'; +import type { EchoResponse as _grpc_testing_EchoResponse, EchoResponse__Output as _grpc_testing_EchoResponse__Output } from '../../grpc/testing/EchoResponse'; +import type { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; +import type { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; + +export interface EchoTest1ServiceClient extends grpc.Client { + BidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + BidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + bidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + bidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + + Echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + Echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + Echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + RequestStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + + ResponseStream(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + ResponseStream(argument: _grpc_testing_EchoRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + responseStream(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + responseStream(argument: _grpc_testing_EchoRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + +} + +export interface EchoTest1ServiceHandlers extends grpc.UntypedServiceImplementation { + BidiStream: grpc.handleBidiStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + CheckClientInitialMetadata: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>; + + Echo: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Echo1: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Echo2: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + RequestStream: grpc.handleClientStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + ResponseStream: grpc.handleServerStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Unimplemented: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + +} + +export interface EchoTest1ServiceDefinition extends grpc.ServiceDefinition { + BidiStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + CheckClientInitialMetadata: MethodDefinition<_grpc_testing_SimpleRequest, _grpc_testing_SimpleResponse, _grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse__Output> + Echo: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Echo1: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Echo2: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + RequestStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + ResponseStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Unimplemented: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/EchoTest2Service.ts b/packages/grpc-js-xds/test/generated/grpc/testing/EchoTest2Service.ts new file mode 100644 index 000000000..033e70143 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/EchoTest2Service.ts @@ -0,0 +1,117 @@ +// Original file: proto/grpc/testing/echo.proto + +import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { EchoRequest as _grpc_testing_EchoRequest, EchoRequest__Output as _grpc_testing_EchoRequest__Output } from '../../grpc/testing/EchoRequest'; +import type { EchoResponse as _grpc_testing_EchoResponse, EchoResponse__Output as _grpc_testing_EchoResponse__Output } from '../../grpc/testing/EchoResponse'; +import type { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; +import type { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; + +export interface EchoTest2ServiceClient extends grpc.Client { + BidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + BidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + bidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + bidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + + Echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + Echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + Echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + RequestStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + + ResponseStream(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + ResponseStream(argument: _grpc_testing_EchoRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + responseStream(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + responseStream(argument: _grpc_testing_EchoRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + +} + +export interface EchoTest2ServiceHandlers extends grpc.UntypedServiceImplementation { + BidiStream: grpc.handleBidiStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + CheckClientInitialMetadata: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>; + + Echo: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Echo1: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Echo2: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + RequestStream: grpc.handleClientStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + ResponseStream: grpc.handleServerStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Unimplemented: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + +} + +export interface EchoTest2ServiceDefinition extends grpc.ServiceDefinition { + BidiStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + CheckClientInitialMetadata: MethodDefinition<_grpc_testing_SimpleRequest, _grpc_testing_SimpleResponse, _grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse__Output> + Echo: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Echo1: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Echo2: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + RequestStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + ResponseStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Unimplemented: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/EchoTestService.ts b/packages/grpc-js-xds/test/generated/grpc/testing/EchoTestService.ts new file mode 100644 index 000000000..d1fa2d075 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/EchoTestService.ts @@ -0,0 +1,150 @@ +// Original file: proto/grpc/testing/echo.proto + +import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { EchoRequest as _grpc_testing_EchoRequest, EchoRequest__Output as _grpc_testing_EchoRequest__Output } from '../../grpc/testing/EchoRequest'; +import type { EchoResponse as _grpc_testing_EchoResponse, EchoResponse__Output as _grpc_testing_EchoResponse__Output } from '../../grpc/testing/EchoResponse'; +import type { SimpleRequest as _grpc_testing_SimpleRequest, SimpleRequest__Output as _grpc_testing_SimpleRequest__Output } from '../../grpc/testing/SimpleRequest'; +import type { SimpleResponse as _grpc_testing_SimpleResponse, SimpleResponse__Output as _grpc_testing_SimpleResponse__Output } from '../../grpc/testing/SimpleResponse'; +import type { StringValue as _grpc_testing_StringValue, StringValue__Output as _grpc_testing_StringValue__Output } from '../../grpc/testing/StringValue'; + +export interface EchoTestServiceClient extends grpc.Client { + BidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + BidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + bidiStream(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + bidiStream(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + CheckClientInitialMetadata(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + checkClientInitialMetadata(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_SimpleResponse__Output>): grpc.ClientUnaryCall; + + CheckDeadlineSet(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + CheckDeadlineSet(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + CheckDeadlineSet(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + CheckDeadlineSet(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineSet(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineSet(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineSet(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineSet(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + + CheckDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + CheckDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + CheckDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + CheckDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + checkDeadlineUpperBound(argument: _grpc_testing_SimpleRequest, callback: grpc.requestCallback<_grpc_testing_StringValue__Output>): grpc.ClientUnaryCall; + + Echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + Echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo1(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo1(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + Echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Echo2(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + echo2(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + RequestStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + RequestStream(callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + requestStream(callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientWritableStream<_grpc_testing_EchoRequest>; + + ResponseStream(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + ResponseStream(argument: _grpc_testing_EchoRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + responseStream(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + responseStream(argument: _grpc_testing_EchoRequest, options?: grpc.CallOptions): grpc.ClientReadableStream<_grpc_testing_EchoResponse__Output>; + + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + + UnimplementedBidi(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + UnimplementedBidi(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + unimplementedBidi(metadata: grpc.Metadata, options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + unimplementedBidi(options?: grpc.CallOptions): grpc.ClientDuplexStream<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse__Output>; + +} + +export interface EchoTestServiceHandlers extends grpc.UntypedServiceImplementation { + BidiStream: grpc.handleBidiStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + /** + * A service which checks that the initial metadata sent over contains some + * expected key value pair + */ + CheckClientInitialMetadata: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse>; + + CheckDeadlineSet: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_StringValue>; + + CheckDeadlineUpperBound: grpc.handleUnaryCall<_grpc_testing_SimpleRequest__Output, _grpc_testing_StringValue>; + + Echo: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Echo1: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Echo2: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + RequestStream: grpc.handleClientStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + ResponseStream: grpc.handleServerStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + Unimplemented: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + + UnimplementedBidi: grpc.handleBidiStreamingCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + +} + +export interface EchoTestServiceDefinition extends grpc.ServiceDefinition { + BidiStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + CheckClientInitialMetadata: MethodDefinition<_grpc_testing_SimpleRequest, _grpc_testing_SimpleResponse, _grpc_testing_SimpleRequest__Output, _grpc_testing_SimpleResponse__Output> + CheckDeadlineSet: MethodDefinition<_grpc_testing_SimpleRequest, _grpc_testing_StringValue, _grpc_testing_SimpleRequest__Output, _grpc_testing_StringValue__Output> + CheckDeadlineUpperBound: MethodDefinition<_grpc_testing_SimpleRequest, _grpc_testing_StringValue, _grpc_testing_SimpleRequest__Output, _grpc_testing_StringValue__Output> + Echo: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Echo1: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Echo2: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + RequestStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + ResponseStream: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + Unimplemented: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> + UnimplementedBidi: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/ErrorStatus.ts b/packages/grpc-js-xds/test/generated/grpc/testing/ErrorStatus.ts new file mode 100644 index 000000000..42ff36d9a --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/ErrorStatus.ts @@ -0,0 +1,20 @@ +// Original file: proto/grpc/testing/echo_messages.proto + + +/** + * Error status client expects to see. + */ +export interface ErrorStatus { + 'code'?: (number); + 'error_message'?: (string); + 'binary_error_details'?: (string); +} + +/** + * Error status client expects to see. + */ +export interface ErrorStatus__Output { + 'code': (number); + 'error_message': (string); + 'binary_error_details': (string); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/NoRpcService.ts b/packages/grpc-js-xds/test/generated/grpc/testing/NoRpcService.ts new file mode 100644 index 000000000..7427c8097 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/NoRpcService.ts @@ -0,0 +1,19 @@ +// Original file: proto/grpc/testing/echo.proto + +import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' + +/** + * A service without any rpc defined to test coverage. + */ +export interface NoRpcServiceClient extends grpc.Client { +} + +/** + * A service without any rpc defined to test coverage. + */ +export interface NoRpcServiceHandlers extends grpc.UntypedServiceImplementation { +} + +export interface NoRpcServiceDefinition extends grpc.ServiceDefinition { +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/RequestParams.ts b/packages/grpc-js-xds/test/generated/grpc/testing/RequestParams.ts new file mode 100644 index 000000000..e8c5ef1d1 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/RequestParams.ts @@ -0,0 +1,75 @@ +// Original file: proto/grpc/testing/echo_messages.proto + +import type { DebugInfo as _grpc_testing_DebugInfo, DebugInfo__Output as _grpc_testing_DebugInfo__Output } from '../../grpc/testing/DebugInfo'; +import type { ErrorStatus as _grpc_testing_ErrorStatus, ErrorStatus__Output as _grpc_testing_ErrorStatus__Output } from '../../grpc/testing/ErrorStatus'; +import type { OrcaLoadReport as _xds_data_orca_v3_OrcaLoadReport, OrcaLoadReport__Output as _xds_data_orca_v3_OrcaLoadReport__Output } from '../../xds/data/orca/v3/OrcaLoadReport'; + +export interface RequestParams { + 'echo_deadline'?: (boolean); + 'client_cancel_after_us'?: (number); + 'server_cancel_after_us'?: (number); + 'echo_metadata'?: (boolean); + 'check_auth_context'?: (boolean); + 'response_message_length'?: (number); + 'echo_peer'?: (boolean); + /** + * will force check_auth_context. + */ + 'expected_client_identity'?: (string); + 'skip_cancelled_check'?: (boolean); + 'expected_transport_security_type'?: (string); + 'debug_info'?: (_grpc_testing_DebugInfo | null); + /** + * Server should not see a request with this set. + */ + 'server_die'?: (boolean); + 'binary_error_details'?: (string); + 'expected_error'?: (_grpc_testing_ErrorStatus | null); + /** + * sleep when invoking server for deadline tests + */ + 'server_sleep_us'?: (number); + /** + * which backend to send request to + */ + 'backend_channel_idx'?: (number); + 'echo_metadata_initially'?: (boolean); + 'server_notify_client_when_started'?: (boolean); + 'backend_metrics'?: (_xds_data_orca_v3_OrcaLoadReport | null); + 'echo_host_from_authority_header'?: (boolean); +} + +export interface RequestParams__Output { + 'echo_deadline': (boolean); + 'client_cancel_after_us': (number); + 'server_cancel_after_us': (number); + 'echo_metadata': (boolean); + 'check_auth_context': (boolean); + 'response_message_length': (number); + 'echo_peer': (boolean); + /** + * will force check_auth_context. + */ + 'expected_client_identity': (string); + 'skip_cancelled_check': (boolean); + 'expected_transport_security_type': (string); + 'debug_info': (_grpc_testing_DebugInfo__Output | null); + /** + * Server should not see a request with this set. + */ + 'server_die': (boolean); + 'binary_error_details': (string); + 'expected_error': (_grpc_testing_ErrorStatus__Output | null); + /** + * sleep when invoking server for deadline tests + */ + 'server_sleep_us': (number); + /** + * which backend to send request to + */ + 'backend_channel_idx': (number); + 'echo_metadata_initially': (boolean); + 'server_notify_client_when_started': (boolean); + 'backend_metrics': (_xds_data_orca_v3_OrcaLoadReport__Output | null); + 'echo_host_from_authority_header': (boolean); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/ResponseParams.ts b/packages/grpc-js-xds/test/generated/grpc/testing/ResponseParams.ts new file mode 100644 index 000000000..588e463c2 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/ResponseParams.ts @@ -0,0 +1,15 @@ +// Original file: proto/grpc/testing/echo_messages.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface ResponseParams { + 'request_deadline'?: (number | string | Long); + 'host'?: (string); + 'peer'?: (string); +} + +export interface ResponseParams__Output { + 'request_deadline': (string); + 'host': (string); + 'peer': (string); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/SimpleRequest.ts b/packages/grpc-js-xds/test/generated/grpc/testing/SimpleRequest.ts new file mode 100644 index 000000000..292a2020c --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/SimpleRequest.ts @@ -0,0 +1,8 @@ +// Original file: proto/grpc/testing/simple_messages.proto + + +export interface SimpleRequest { +} + +export interface SimpleRequest__Output { +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/SimpleResponse.ts b/packages/grpc-js-xds/test/generated/grpc/testing/SimpleResponse.ts new file mode 100644 index 000000000..3e8735e5e --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/SimpleResponse.ts @@ -0,0 +1,8 @@ +// Original file: proto/grpc/testing/simple_messages.proto + + +export interface SimpleResponse { +} + +export interface SimpleResponse__Output { +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/StringValue.ts b/packages/grpc-js-xds/test/generated/grpc/testing/StringValue.ts new file mode 100644 index 000000000..4a779ae2b --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/StringValue.ts @@ -0,0 +1,10 @@ +// Original file: proto/grpc/testing/simple_messages.proto + + +export interface StringValue { + 'message'?: (string); +} + +export interface StringValue__Output { + 'message': (string); +} diff --git a/packages/grpc-js-xds/test/generated/grpc/testing/UnimplementedEchoService.ts b/packages/grpc-js-xds/test/generated/grpc/testing/UnimplementedEchoService.ts new file mode 100644 index 000000000..48128976e --- /dev/null +++ b/packages/grpc-js-xds/test/generated/grpc/testing/UnimplementedEchoService.ts @@ -0,0 +1,27 @@ +// Original file: proto/grpc/testing/echo.proto + +import type * as grpc from '@grpc/grpc-js' +import type { MethodDefinition } from '@grpc/proto-loader' +import type { EchoRequest as _grpc_testing_EchoRequest, EchoRequest__Output as _grpc_testing_EchoRequest__Output } from '../../grpc/testing/EchoRequest'; +import type { EchoResponse as _grpc_testing_EchoResponse, EchoResponse__Output as _grpc_testing_EchoResponse__Output } from '../../grpc/testing/EchoResponse'; + +export interface UnimplementedEchoServiceClient extends grpc.Client { + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + Unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, metadata: grpc.Metadata, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, options: grpc.CallOptions, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + unimplemented(argument: _grpc_testing_EchoRequest, callback: grpc.requestCallback<_grpc_testing_EchoResponse__Output>): grpc.ClientUnaryCall; + +} + +export interface UnimplementedEchoServiceHandlers extends grpc.UntypedServiceImplementation { + Unimplemented: grpc.handleUnaryCall<_grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse>; + +} + +export interface UnimplementedEchoServiceDefinition extends grpc.ServiceDefinition { + Unimplemented: MethodDefinition<_grpc_testing_EchoRequest, _grpc_testing_EchoResponse, _grpc_testing_EchoRequest__Output, _grpc_testing_EchoResponse__Output> +} diff --git a/packages/grpc-js-xds/test/generated/xds/data/orca/v3/OrcaLoadReport.ts b/packages/grpc-js-xds/test/generated/xds/data/orca/v3/OrcaLoadReport.ts new file mode 100644 index 000000000..d66c42713 --- /dev/null +++ b/packages/grpc-js-xds/test/generated/xds/data/orca/v3/OrcaLoadReport.ts @@ -0,0 +1,59 @@ +// Original file: proto/grpc/testing/xds/v3/orca_load_report.proto + +import type { Long } from '@grpc/proto-loader'; + +export interface OrcaLoadReport { + /** + * CPU utilization expressed as a fraction of available CPU resources. This + * should be derived from the latest sample or measurement. + */ + 'cpu_utilization'?: (number | string); + /** + * Memory utilization expressed as a fraction of available memory + * resources. This should be derived from the latest sample or measurement. + */ + 'mem_utilization'?: (number | string); + /** + * Total RPS being served by an endpoint. This should cover all services that an endpoint is + * responsible for. + */ + 'rps'?: (number | string | Long); + /** + * Application specific requests costs. Each value is an absolute cost (e.g. 3487 bytes of + * storage) associated with the request. + */ + 'request_cost'?: ({[key: string]: number | string}); + /** + * Resource utilization values. Each value is expressed as a fraction of total resources + * available, derived from the latest sample or measurement. + */ + 'utilization'?: ({[key: string]: number | string}); +} + +export interface OrcaLoadReport__Output { + /** + * CPU utilization expressed as a fraction of available CPU resources. This + * should be derived from the latest sample or measurement. + */ + 'cpu_utilization': (number | string); + /** + * Memory utilization expressed as a fraction of available memory + * resources. This should be derived from the latest sample or measurement. + */ + 'mem_utilization': (number | string); + /** + * Total RPS being served by an endpoint. This should cover all services that an endpoint is + * responsible for. + */ + 'rps': (string); + /** + * Application specific requests costs. Each value is an absolute cost (e.g. 3487 bytes of + * storage) associated with the request. + */ + 'request_cost': ({[key: string]: number | string}); + /** + * Resource utilization values. Each value is expressed as a fraction of total resources + * available, derived from the latest sample or measurement. + */ + 'utilization': ({[key: string]: number | string}); +} diff --git a/packages/grpc-js-xds/test/test-core.ts b/packages/grpc-js-xds/test/test-core.ts new file mode 100644 index 000000000..d0d1b6031 --- /dev/null +++ b/packages/grpc-js-xds/test/test-core.ts @@ -0,0 +1,63 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { Backend } from "./backend"; +import { XdsTestClient } from "./client"; +import { FakeCluster, FakeRouteGroup } from "./framework"; +import { XdsServer } from "./xds-server"; + +import { register } from "../src"; +import assert = require("assert"); + +register(); + +describe('core xDS functionality', () => { + let xdsServer: XdsServer; + let client: XdsTestClient; + beforeEach(done => { + xdsServer = new XdsServer(); + xdsServer.startServer(error => { + done(error); + }); + }); + afterEach(() => { + client?.close(); + xdsServer?.shutdownServer(); + }) + it('should route requests to the single backend', done => { + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); + routeGroup.startAllBackends().then(() => { + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + client.stopCalls(); + assert.fail(`Client NACKED ${typeUrl} resource with message ${responseState.errorMessage}`); + } + }) + client = new XdsTestClient('route1', xdsServer); + client.startCalls(100); + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + client.stopCalls(); + done(); + }, reason => done(reason)); + }, reason => done(reason)); + }); +}); \ No newline at end of file diff --git a/packages/grpc-js-xds/test/xds-server.ts b/packages/grpc-js-xds/test/xds-server.ts new file mode 100644 index 000000000..b82a3a673 --- /dev/null +++ b/packages/grpc-js-xds/test/xds-server.ts @@ -0,0 +1,342 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import { ServerDuplexStream, Server, UntypedServiceImplementation, ServerCredentials, loadPackageDefinition } from "@grpc/grpc-js"; +import { AnyExtension, loadSync } from "@grpc/proto-loader"; +import { EventEmitter } from "stream"; +import { Cluster } from "../src/generated/envoy/config/cluster/v3/Cluster"; +import { ClusterLoadAssignment } from "../src/generated/envoy/config/endpoint/v3/ClusterLoadAssignment"; +import { Listener } from "../src/generated/envoy/config/listener/v3/Listener"; +import { RouteConfiguration } from "../src/generated/envoy/config/route/v3/RouteConfiguration"; +import { AggregatedDiscoveryServiceHandlers } from "../src/generated/envoy/service/discovery/v3/AggregatedDiscoveryService"; +import { DiscoveryRequest__Output } from "../src/generated/envoy/service/discovery/v3/DiscoveryRequest"; +import { DiscoveryResponse } from "../src/generated/envoy/service/discovery/v3/DiscoveryResponse"; +import { Any } from "../src/generated/google/protobuf/Any"; +import { LDS_TYPE_URL, RDS_TYPE_URL, CDS_TYPE_URL, EDS_TYPE_URL, LdsTypeUrl, RdsTypeUrl, CdsTypeUrl, EdsTypeUrl, AdsTypeUrl } from "../src/resources" +import * as adsTypes from '../src/generated/ads'; +import * as lrsTypes from '../src/generated/lrs'; +import { LoadStatsRequest__Output } from "../src/generated/envoy/service/load_stats/v3/LoadStatsRequest"; +import { LoadStatsResponse } from "../src/generated/envoy/service/load_stats/v3/LoadStatsResponse"; + +const loadedProtos = loadPackageDefinition(loadSync( + [ + 'envoy/service/discovery/v3/ads.proto', + 'envoy/service/load_stats/v3/lrs.proto', + 'envoy/config/listener/v3/listener.proto', + 'envoy/config/route/v3/route.proto', + 'envoy/config/cluster/v3/cluster.proto', + 'envoy/config/endpoint/v3/endpoint.proto', + 'envoy/extensions/filters/network/http_connection_manager/v3/http_connection_manager.proto' + ], + { + keepCase: true, + longs: String, + enums: String, + defaults: true, + oneofs: true, + json: true, + includeDirs: [ + // Paths are relative to src/build + __dirname + '/../../deps/envoy-api/', + __dirname + '/../../deps/xds/', + __dirname + '/../../deps/googleapis/', + __dirname + '/../../deps/protoc-gen-validate/', + ], + })) as unknown as adsTypes.ProtoGrpcType & lrsTypes.ProtoGrpcType; + +type AdsInputType = T extends EdsTypeUrl + ? ClusterLoadAssignment + : T extends CdsTypeUrl + ? Cluster + : T extends RdsTypeUrl + ? RouteConfiguration + : Listener; + +const ADS_TYPE_URLS = new Set([LDS_TYPE_URL, RDS_TYPE_URL, CDS_TYPE_URL, EDS_TYPE_URL]); + +interface ResponseState { + state: 'ACKED' | 'NACKED'; + errorMessage?: string; +} + +interface ResponseListener { + (typeUrl: AdsTypeUrl, responseState: ResponseState): void; +} + +type ResourceAny = AdsInputType & {'@type': T}; + +interface ResourceState { + resource?: ResourceAny; + resourceTypeVersion: number; + subscriptions: Set; +} + +interface ResourceTypeState { + resourceTypeVersion: number; + /** + * Key type is type URL + */ + resourceNameMap: Map>; +} + +interface ResourceMap { + [EDS_TYPE_URL]: ResourceTypeState; + [CDS_TYPE_URL]: ResourceTypeState; + [RDS_TYPE_URL]: ResourceTypeState; + [LDS_TYPE_URL]: ResourceTypeState; +} + +function isAdsTypeUrl(value: string): value is AdsTypeUrl { + return ADS_TYPE_URLS.has(value); +} + +export class XdsServer { + private resourceMap: ResourceMap = { + [EDS_TYPE_URL]: { + resourceTypeVersion: 0, + resourceNameMap: new Map() + }, + [CDS_TYPE_URL]: { + resourceTypeVersion: 0, + resourceNameMap: new Map() + }, + [RDS_TYPE_URL]: { + resourceTypeVersion: 0, + resourceNameMap: new Map() + }, + [LDS_TYPE_URL]: { + resourceTypeVersion: 0, + resourceNameMap: new Map() + }, + }; + private responseListeners = new Set(); + private resourceTypesToIgnore = new Set(); + private clients = new Map>(); + private server: Server | null = null; + private port: number | null = null; + + addResponseListener(listener: ResponseListener) { + this.responseListeners.add(listener); + } + + removeResponseListener(listener: ResponseListener) { + this.responseListeners.delete(listener); + } + + setResource(resource: ResourceAny, name: string) { + const resourceTypeState = this.resourceMap[resource["@type"]] as ResourceTypeState; + resourceTypeState.resourceTypeVersion += 1; + let resourceState: ResourceState | undefined = resourceTypeState.resourceNameMap.get(name); + if (!resourceState) { + resourceState = { + resourceTypeVersion: 0, + subscriptions: new Set() + }; + resourceTypeState.resourceNameMap.set(name, resourceState); + } + resourceState.resourceTypeVersion = resourceTypeState.resourceTypeVersion; + resourceState.resource = resource; + this.sendResourceUpdates(resource['@type'], resourceState.subscriptions, new Set([name])); + } + + setLdsResource(resource: Listener) { + this.setResource({...resource, '@type': LDS_TYPE_URL}, resource.name!); + } + + setRdsResource(resource: RouteConfiguration) { + this.setResource({...resource, '@type': RDS_TYPE_URL}, resource.name!); + } + + setCdsResource(resource: Cluster) { + this.setResource({...resource, '@type': CDS_TYPE_URL}, resource.name!); + } + + setEdsResource(resource: ClusterLoadAssignment) { + this.setResource({...resource, '@type': EDS_TYPE_URL}, resource.cluster_name!); + } + + unsetResource(typeUrl: T, name: string) { + const resourceTypeState = this.resourceMap[typeUrl] as ResourceTypeState; + resourceTypeState.resourceTypeVersion += 1; + let resourceState: ResourceState | undefined = resourceTypeState.resourceNameMap.get(name); + if (resourceState) { + resourceState.resourceTypeVersion = resourceTypeState.resourceTypeVersion; + delete resourceState.resource; + this.sendResourceUpdates(typeUrl, resourceState.subscriptions, new Set([name])); + } + } + + ignoreResourceType(typeUrl: AdsTypeUrl) { + this.resourceTypesToIgnore.add(typeUrl); + } + + private sendResourceUpdates(typeUrl: T, clients: Set, includeResources: Set) { + const resourceTypeState = this.resourceMap[typeUrl] as ResourceTypeState; + const clientResources = new Map(); + for (const [resourceName, resourceState] of resourceTypeState.resourceNameMap) { + /* For RDS and EDS, only send updates for the listed updated resources. + * Otherwise include all resources. */ + if ((typeUrl === RDS_TYPE_URL || typeUrl === EDS_TYPE_URL) && !includeResources.has(resourceName)) { + continue; + } + if (!resourceState.resource) { + continue; + } + for (const clientName of clients) { + if (!resourceState.subscriptions.has(clientName)) { + continue; + } + let resourcesList = clientResources.get(clientName); + if (!resourcesList) { + resourcesList = []; + clientResources.set(clientName, resourcesList); + } + resourcesList.push(resourceState.resource); + } + } + for (const [clientName, resourceList] of clientResources) { + this.clients.get(clientName)?.write({ + resources: resourceList, + version_info: resourceTypeState.resourceTypeVersion.toString(), + nonce: resourceTypeState.resourceTypeVersion.toString(), + type_url: typeUrl + }); + } + } + + private updateResponseListeners(typeUrl: AdsTypeUrl, responseState: ResponseState) { + for (const listener of this.responseListeners) { + listener(typeUrl, responseState); + } + } + + private maybeSubscribe(typeUrl: T, client: string, resourceName: string): boolean { + const resourceTypeState = this.resourceMap[typeUrl] as ResourceTypeState; + let resourceState = resourceTypeState.resourceNameMap.get(resourceName); + if (!resourceState) { + resourceState = { + resourceTypeVersion: 0, + subscriptions: new Set() + }; + resourceTypeState.resourceNameMap.set(resourceName, resourceState); + } + const newlySubscribed = !resourceState.subscriptions.has(client); + resourceState.subscriptions.add(client); + return newlySubscribed; + } + + private handleUnsubscriptions(typeUrl: AdsTypeUrl, client: string, requestedResourceNames?: Set) { + const resourceTypeState = this.resourceMap[typeUrl]; + for (const [resourceName, resourceState] of resourceTypeState.resourceNameMap) { + if (!requestedResourceNames || !requestedResourceNames.has(resourceName)) { + resourceState.subscriptions.delete(client); + if (!resourceState.resource && resourceState.subscriptions.size === 0) { + resourceTypeState.resourceNameMap.delete(resourceName) + } + } + } + } + + private handleRequest(clientName: string, request: DiscoveryRequest__Output) { + if (!isAdsTypeUrl(request.type_url)) { + console.error(`Received ADS request with unsupported type_url ${request.type_url}`); + return; + } + const clientResourceVersion = request.version_info === '' ? 0 : Number.parseInt(request.version_info); + if (request.error_detail) { + this.updateResponseListeners(request.type_url, {state: 'NACKED', errorMessage: request.error_detail.message}); + } else { + this.updateResponseListeners(request.type_url, {state: 'ACKED'}); + } + const requestedResourceNames = new Set(request.resource_names); + const resourceTypeState = this.resourceMap[request.type_url]; + const updatedResources = new Set(); + for (const resourceName of requestedResourceNames) { + if (this.maybeSubscribe(request.type_url, clientName, resourceName) || resourceTypeState.resourceNameMap.get(resourceName)!.resourceTypeVersion > clientResourceVersion) { + updatedResources.add(resourceName); + } + } + this.handleUnsubscriptions(request.type_url, clientName, requestedResourceNames); + if (updatedResources.size > 0) { + this.sendResourceUpdates(request.type_url, new Set([clientName]), updatedResources); + } + } + + StreamAggregatedResources(call: ServerDuplexStream) { + const clientName = call.getPeer(); + this.clients.set(clientName, call); + call.on('data', (request: DiscoveryRequest__Output) => { + this.handleRequest(clientName, request); + }); + call.on('end', () => { + this.clients.delete(clientName); + for (const typeUrl of ADS_TYPE_URLS) { + this.handleUnsubscriptions(typeUrl as AdsTypeUrl, clientName); + } + call.end(); + }); + } + + StreamLoadStats(call: ServerDuplexStream) { + const statsResponse = {load_reporting_interval: {seconds: 30}}; + call.write(statsResponse); + call.on('data', (request: LoadStatsRequest__Output) => { + call.write(statsResponse); + }); + call.on('end', () => { + call.end(); + }); + } + + startServer(callback: (error: Error | null, port: number) => void) { + if (this.server) { + return; + } + const server = new Server(); + server.addService(loadedProtos.envoy.service.discovery.v3.AggregatedDiscoveryService.service, this as unknown as UntypedServiceImplementation); + server.addService(loadedProtos.envoy.service.load_stats.v3.LoadReportingService.service, this as unknown as UntypedServiceImplementation); + server.bindAsync('localhost:0', ServerCredentials.createInsecure(), (error, port) => { + if (!error) { + this.server = server; + this.port = port; + server.start(); + } + callback(error, port); + }); + } + + shutdownServer() { + this.server?.forceShutdown(); + } + + getBootstrapInfoString(): string { + if (this.port === null) { + throw new Error('Bootstrap info unavailable; server not started'); + } + const bootstrapInfo = { + xds_servers: [{ + server_uri: `localhost:${this.port}`, + channel_creds: [{type: 'insecure'}] + }], + node: { + id: 'test', + locality: {} + } + } + return JSON.stringify(bootstrapInfo); + } +} \ No newline at end of file From e32bbc7aacdca42bd4690471449c43d6c29ffec1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 27 Jan 2023 13:39:44 -0800 Subject: [PATCH 1863/1899] grpc-js-xds: Allow tests to set bootstrap info in channel args --- packages/grpc-js-xds/src/load-balancer-cds.ts | 8 +++--- packages/grpc-js-xds/src/load-balancer-eds.ts | 10 ++++--- packages/grpc-js-xds/src/load-balancer-lrs.ts | 2 +- packages/grpc-js-xds/src/resolver-xds.ts | 26 ++++++++++++++----- packages/grpc-js-xds/src/xds-bootstrap.ts | 6 ++--- packages/grpc-js-xds/src/xds-client.ts | 14 +++++++--- .../src/xds-stream-state/eds-state.ts | 8 ++++++ 7 files changed, 53 insertions(+), 21 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-cds.ts b/packages/grpc-js-xds/src/load-balancer-cds.ts index 4d47b2546..243a1e967 100644 --- a/packages/grpc-js-xds/src/load-balancer-cds.ts +++ b/packages/grpc-js-xds/src/load-balancer-cds.ts @@ -125,6 +125,7 @@ export class CdsLoadBalancer implements LoadBalancer { private latestConfig: CdsLoadBalancingConfig | null = null; private latestAttributes: { [key: string]: unknown } = {}; + private xdsClient: XdsClient | null = null; constructor(private readonly channelControlHelper: ChannelControlHelper) { this.childBalancer = new ChildLoadBalancerHandler(channelControlHelper); @@ -188,6 +189,7 @@ export class CdsLoadBalancer implements LoadBalancer { } trace('Received update with config ' + JSON.stringify(lbConfig, undefined, 2)); this.latestAttributes = attributes; + this.xdsClient = attributes.xdsClient as XdsClient; /* If the cluster is changing, disable the old watcher before adding the new * one */ @@ -196,7 +198,7 @@ export class CdsLoadBalancer implements LoadBalancer { this.latestConfig?.getCluster() !== lbConfig.getCluster() ) { trace('Removing old cluster watcher for cluster name ' + this.latestConfig!.getCluster()); - getSingletonXdsClient().removeClusterWatcher( + this.xdsClient.removeClusterWatcher( this.latestConfig!.getCluster(), this.watcher ); @@ -212,7 +214,7 @@ export class CdsLoadBalancer implements LoadBalancer { if (!this.isWatcherActive) { trace('Adding new cluster watcher for cluster name ' + lbConfig.getCluster()); - getSingletonXdsClient().addClusterWatcher(lbConfig.getCluster(), this.watcher); + this.xdsClient.addClusterWatcher(lbConfig.getCluster(), this.watcher); this.isWatcherActive = true; } } @@ -226,7 +228,7 @@ export class CdsLoadBalancer implements LoadBalancer { trace('Destroying load balancer with cluster name ' + this.latestConfig?.getCluster()); this.childBalancer.destroy(); if (this.isWatcherActive) { - getSingletonXdsClient().removeClusterWatcher( + this.xdsClient?.removeClusterWatcher( this.latestConfig!.getCluster(), this.watcher ); diff --git a/packages/grpc-js-xds/src/load-balancer-eds.ts b/packages/grpc-js-xds/src/load-balancer-eds.ts index b0bd3f030..03a4078ac 100644 --- a/packages/grpc-js-xds/src/load-balancer-eds.ts +++ b/packages/grpc-js-xds/src/load-balancer-eds.ts @@ -167,6 +167,7 @@ export class EdsLoadBalancer implements LoadBalancer { private lastestConfig: EdsLoadBalancingConfig | null = null; private latestAttributes: { [key: string]: unknown } = {}; + private xdsClient: XdsClient | null = null; private latestEdsUpdate: ClusterLoadAssignment__Output | null = null; /** @@ -488,13 +489,14 @@ export class EdsLoadBalancer implements LoadBalancer { trace('Received update with config: ' + JSON.stringify(lbConfig, undefined, 2)); this.lastestConfig = lbConfig; this.latestAttributes = attributes; + this.xdsClient = attributes.xdsClient as XdsClient; const newEdsServiceName = lbConfig.getEdsServiceName() ?? lbConfig.getCluster(); /* If the name is changing, disable the old watcher before adding the new * one */ if (this.isWatcherActive && this.edsServiceName !== newEdsServiceName) { trace('Removing old endpoint watcher for edsServiceName ' + this.edsServiceName) - getSingletonXdsClient().removeEndpointWatcher(this.edsServiceName!, this.watcher); + this.xdsClient.removeEndpointWatcher(this.edsServiceName!, this.watcher); /* Setting isWatcherActive to false here lets us have one code path for * calling addEndpointWatcher */ this.isWatcherActive = false; @@ -507,12 +509,12 @@ export class EdsLoadBalancer implements LoadBalancer { if (!this.isWatcherActive) { trace('Adding new endpoint watcher for edsServiceName ' + this.edsServiceName); - getSingletonXdsClient().addEndpointWatcher(this.edsServiceName, this.watcher); + this.xdsClient.addEndpointWatcher(this.edsServiceName, this.watcher); this.isWatcherActive = true; } if (lbConfig.getLrsLoadReportingServerName()) { - this.clusterDropStats = getSingletonXdsClient().addClusterDropStats( + this.clusterDropStats = this.xdsClient.addClusterDropStats( lbConfig.getLrsLoadReportingServerName()!, lbConfig.getCluster(), lbConfig.getEdsServiceName() ?? '' @@ -533,7 +535,7 @@ export class EdsLoadBalancer implements LoadBalancer { destroy(): void { trace('Destroying load balancer with edsServiceName ' + this.edsServiceName); if (this.edsServiceName) { - getSingletonXdsClient().removeEndpointWatcher(this.edsServiceName, this.watcher); + this.xdsClient?.removeEndpointWatcher(this.edsServiceName, this.watcher); } this.childBalancer.destroy(); } diff --git a/packages/grpc-js-xds/src/load-balancer-lrs.ts b/packages/grpc-js-xds/src/load-balancer-lrs.ts index 745b21c5c..9610ea834 100644 --- a/packages/grpc-js-xds/src/load-balancer-lrs.ts +++ b/packages/grpc-js-xds/src/load-balancer-lrs.ts @@ -169,7 +169,7 @@ export class LrsLoadBalancer implements LoadBalancer { if (!(lbConfig instanceof LrsLoadBalancingConfig)) { return; } - this.localityStatsReporter = getSingletonXdsClient().addClusterLocalityStats( + this.localityStatsReporter = (attributes.xdsClient as XdsClient).addClusterLocalityStats( lbConfig.getLrsLoadReportingServerName(), lbConfig.getClusterName(), lbConfig.getEdsServiceName(), diff --git a/packages/grpc-js-xds/src/resolver-xds.ts b/packages/grpc-js-xds/src/resolver-xds.ts index 401465be6..9879a2c6e 100644 --- a/packages/grpc-js-xds/src/resolver-xds.ts +++ b/packages/grpc-js-xds/src/resolver-xds.ts @@ -48,6 +48,7 @@ import { EXPERIMENTAL_FAULT_INJECTION, EXPERIMENTAL_RETRY } from './environment' import Filter = experimental.Filter; import FilterFactory = experimental.FilterFactory; import RetryPolicy = experimental.RetryPolicy; +import { validateBootstrapConfig } from './xds-bootstrap'; const TRACER_NAME = 'xds_resolver'; @@ -210,6 +211,8 @@ function getDefaultRetryMaxInterval(baseInterval: string): string { return `${Number.parseFloat(baseInterval.substring(0, baseInterval.length - 1)) * 10}s`; } +const BOOTSTRAP_CONFIG_KEY = 'grpc.TEST_ONLY_DO_NOT_USE_IN_PROD.xds_bootstrap_config'; + const RETRY_CODES: {[key: string]: status} = { 'cancelled': status.CANCELLED, 'deadline-exceeded': status.DEADLINE_EXCEEDED, @@ -238,11 +241,20 @@ class XdsResolver implements Resolver { private ldsHttpFilterConfigs: {name: string, config: HttpFilterConfig}[] = []; + private xdsClient: XdsClient; + constructor( private target: GrpcUri, private listener: ResolverListener, private channelOptions: ChannelOptions ) { + if (channelOptions[BOOTSTRAP_CONFIG_KEY]) { + const parsedConfig = JSON.parse(channelOptions[BOOTSTRAP_CONFIG_KEY]); + const validatedConfig = validateBootstrapConfig(parsedConfig); + this.xdsClient = new XdsClient(validatedConfig); + } else { + this.xdsClient = getSingletonXdsClient(); + } this.ldsWatcher = { onValidUpdate: (update: Listener__Output) => { const httpConnectionManager = decodeSingleResource(HTTP_CONNECTION_MANGER_TYPE_URL, update.api_listener!.api_listener!.value); @@ -267,16 +279,16 @@ class XdsResolver implements Resolver { const routeConfigName = httpConnectionManager.rds!.route_config_name; if (this.latestRouteConfigName !== routeConfigName) { if (this.latestRouteConfigName !== null) { - getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); + this.xdsClient.removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); } - getSingletonXdsClient().addRouteWatcher(httpConnectionManager.rds!.route_config_name, this.rdsWatcher); + this.xdsClient.addRouteWatcher(httpConnectionManager.rds!.route_config_name, this.rdsWatcher); this.latestRouteConfigName = routeConfigName; } break; } case 'route_config': if (this.latestRouteConfigName) { - getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); + this.xdsClient.removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); } this.handleRouteConfig(httpConnectionManager.route_config!); break; @@ -546,7 +558,7 @@ class XdsResolver implements Resolver { methodConfig: [], loadBalancingConfig: [lbPolicyConfig] } - this.listener.onSuccessfulResolution([], serviceConfig, null, configSelector, {}); + this.listener.onSuccessfulResolution([], serviceConfig, null, configSelector, {xdsClient: this.xdsClient}); } private reportResolutionError(reason: string) { @@ -563,15 +575,15 @@ class XdsResolver implements Resolver { // Wait until updateResolution is called once to start the xDS requests if (!this.isLdsWatcherActive) { trace('Starting resolution for target ' + uriToString(this.target)); - getSingletonXdsClient().addListenerWatcher(this.target.path, this.ldsWatcher); + this.xdsClient.addListenerWatcher(this.target.path, this.ldsWatcher); this.isLdsWatcherActive = true; } } destroy() { - getSingletonXdsClient().removeListenerWatcher(this.target.path, this.ldsWatcher); + this.xdsClient.removeListenerWatcher(this.target.path, this.ldsWatcher); if (this.latestRouteConfigName) { - getSingletonXdsClient().removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); + this.xdsClient.removeRouteWatcher(this.latestRouteConfigName, this.rdsWatcher); } } diff --git a/packages/grpc-js-xds/src/xds-bootstrap.ts b/packages/grpc-js-xds/src/xds-bootstrap.ts index 876b6d958..72a0ca375 100644 --- a/packages/grpc-js-xds/src/xds-bootstrap.ts +++ b/packages/grpc-js-xds/src/xds-bootstrap.ts @@ -231,7 +231,7 @@ function validateNode(obj: any): Node { return result; } -function validateBootstrapFile(obj: any): BootstrapInfo { +export function validateBootstrapConfig(obj: any): BootstrapInfo { return { xdsServers: obj.xds_servers.map(validateXdsServerConfig), node: validateNode(obj.node), @@ -265,7 +265,7 @@ export async function loadBootstrapInfo(): Promise { } try { const parsedFile = JSON.parse(data); - resolve(validateBootstrapFile(parsedFile)); + resolve(validateBootstrapConfig(parsedFile)); } catch (e) { reject( new Error( @@ -290,7 +290,7 @@ export async function loadBootstrapInfo(): Promise { if (bootstrapConfig) { try { const parsedConfig = JSON.parse(bootstrapConfig); - const loadedBootstrapInfoValue = validateBootstrapFile(parsedConfig); + const loadedBootstrapInfoValue = validateBootstrapConfig(parsedConfig); loadedBootstrapInfo = Promise.resolve(loadedBootstrapInfoValue); } catch (e) { throw new Error( diff --git a/packages/grpc-js-xds/src/xds-client.ts b/packages/grpc-js-xds/src/xds-client.ts index 2dfa41236..a2d33d1a5 100644 --- a/packages/grpc-js-xds/src/xds-client.ts +++ b/packages/grpc-js-xds/src/xds-client.ts @@ -21,7 +21,7 @@ import { loadProtosWithOptionsSync } from '@grpc/proto-loader/build/src/util'; import { loadPackageDefinition, StatusObject, status, logVerbosity, Metadata, experimental, ChannelOptions, ClientDuplexStream, ServiceError, ChannelCredentials, Channel, connectivityState } from '@grpc/grpc-js'; import * as adsTypes from './generated/ads'; import * as lrsTypes from './generated/lrs'; -import { loadBootstrapInfo } from './xds-bootstrap'; +import { BootstrapInfo, loadBootstrapInfo } from './xds-bootstrap'; import { Node } from './generated/envoy/config/core/v3/Node'; import { AggregatedDiscoveryServiceClient } from './generated/envoy/service/discovery/v3/AggregatedDiscoveryService'; import { DiscoveryRequest } from './generated/envoy/service/discovery/v3/DiscoveryRequest'; @@ -276,7 +276,7 @@ export class XdsClient { private adsBackoff: BackoffTimeout; private lrsBackoff: BackoffTimeout; - constructor() { + constructor(bootstrapInfoOverride?: BootstrapInfo) { const edsState = new EdsState(() => { this.updateNames('eds'); }); @@ -310,7 +310,15 @@ export class XdsClient { }); this.lrsBackoff.unref(); - Promise.all([loadBootstrapInfo(), loadAdsProtos()]).then( + async function getBootstrapInfo(): Promise { + if (bootstrapInfoOverride) { + return bootstrapInfoOverride; + } else { + return loadBootstrapInfo(); + } + } + + Promise.all([getBootstrapInfo(), loadAdsProtos()]).then( ([bootstrapInfo, protoDefinitions]) => { if (this.hasShutdown) { return; diff --git a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts index cec6a4764..b043ebbc0 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/eds-state.ts @@ -61,10 +61,12 @@ export class EdsState extends BaseXdsStreamState const priorityTotalWeights: Map = new Map(); for (const endpoint of message.endpoints) { if (!endpoint.locality) { + trace('EDS validation: endpoint locality unset'); return false; } for (const {locality, priority} of seenLocalities) { if (localitiesEqual(endpoint.locality, locality) && endpoint.priority === priority) { + trace('EDS validation: endpoint locality duplicated: ' + JSON.stringify(locality) + ', priority=' + priority); return false; } } @@ -72,16 +74,20 @@ export class EdsState extends BaseXdsStreamState for (const lb of endpoint.lb_endpoints) { const socketAddress = lb.endpoint?.address?.socket_address; if (!socketAddress) { + trace('EDS validation: endpoint socket_address not set'); return false; } if (socketAddress.port_specifier !== 'port_value') { + trace('EDS validation: socket_address.port_specifier !== "port_value"'); return false; } if (!(isIPv4(socketAddress.address) || isIPv6(socketAddress.address))) { + trace('EDS validation: address not a valid IPv4 or IPv6 address: ' + socketAddress.address); return false; } for (const address of seenAddresses) { if (addressesEqual(socketAddress, address)) { + trace('EDS validation: duplicate address seen: ' + address); return false; } } @@ -91,11 +97,13 @@ export class EdsState extends BaseXdsStreamState } for (const totalWeight of priorityTotalWeights.values()) { if (totalWeight > UINT32_MAX) { + trace('EDS validation: total weight > UINT32_MAX') return false; } } for (const priority of priorityTotalWeights.keys()) { if (priority > 0 && !priorityTotalWeights.has(priority - 1)) { + trace('EDS validation: priorities not contiguous'); return false; } } From 056dc8e56ea4b59444700ac407f247e5128b6d0c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Mar 2023 13:58:02 -0800 Subject: [PATCH 1864/1899] grpc-js: Unregister socket from channelz when closing transport --- packages/grpc-js/src/transport.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 3c9163d13..8abc13aba 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -20,7 +20,7 @@ import { checkServerIdentity, CipherNameAndProtocol, ConnectionOptions, PeerCert import { StatusObject } from './call-interface'; import { ChannelCredentials } from './channel-credentials'; import { ChannelOptions } from './channel-options'; -import { ChannelzCallTracker, registerChannelzSocket, SocketInfo, SocketRef, TlsInfo } from './channelz'; +import { ChannelzCallTracker, registerChannelzSocket, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; import { LogVerbosity } from './constants'; import { getProxiedConnection, ProxyConnectionResult } from './http_proxy'; import * as logging from './logging'; @@ -471,6 +471,7 @@ class Http2Transport implements Transport { shutdown() { this.session.close(); + unregisterChannelzRef(this.channelzRef); } } From 3fbdf0d337aa88b70c0a055ff7fafcff91541b3b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 10 Mar 2023 14:05:39 -0800 Subject: [PATCH 1865/1899] grpc-js: Bump version to 1.8.13 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 722f9d866..815dabeb0 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.12", + "version": "1.8.13", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From e5e6731917ed646f3d2bcc25304943de11758b46 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 24 Feb 2023 09:55:45 -0800 Subject: [PATCH 1866/1899] grpc-js-xds: Use simpler search algorithm in weighted target picker --- .../src/load-balancer-weighted-target.ts | 29 +++++-------------- 1 file changed, 7 insertions(+), 22 deletions(-) diff --git a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts index 5d7cfa04e..7cd92d98b 100644 --- a/packages/grpc-js-xds/src/load-balancer-weighted-target.ts +++ b/packages/grpc-js-xds/src/load-balancer-weighted-target.ts @@ -119,31 +119,16 @@ class WeightedTargetPicker implements Picker { pick(pickArgs: PickArgs): PickResult { // num | 0 is equivalent to floor(num) const selection = (Math.random() * this.rangeTotal) | 0; - - /* Binary search for the element of the list such that - * pickerList[index - 1].rangeEnd <= selection < pickerList[index].rangeEnd - */ - let mid = 0; - let startIndex = 0; - let endIndex = this.pickerList.length - 1; - let index = 0; - while (endIndex > startIndex) { - mid = ((startIndex + endIndex) / 2) | 0; - if (this.pickerList[mid].rangeEnd > selection) { - endIndex = mid; - } else if (this.pickerList[mid].rangeEnd < selection) { - startIndex = mid + 1; - } else { - // + 1 here because the range is exclusive at the top end - index = mid + 1; - break; + + for (const entry of this.pickerList) { + if (selection < entry.rangeEnd) { + return entry.picker.pick(pickArgs); } } - if (index === 0) { - index = startIndex; - } - return this.pickerList[index].picker.pick(pickArgs); + /* Default to first element if the iteration doesn't find anything for some + * reason. */ + return this.pickerList[0].picker.pick(pickArgs); } } From 7840a108d3eb9e614dee413f54df9a3b66ee600b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 3 Apr 2023 09:54:38 -0700 Subject: [PATCH 1867/1899] grpc-js-xds: Use Debian and Node 18 in interop Dockerfile (1.8.x) --- packages/grpc-js-xds/interop/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index b93e309d7..5987f1ee4 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -16,7 +16,7 @@ # following command from grpc-node directory: # docker build -t -f packages/grpc-js-xds/interop/Dockerfile . -FROM node:16-alpine as build +FROM node:18-slim as build # Make a grpc-node directory and copy the repo into it. WORKDIR /node/src/grpc-node @@ -27,7 +27,7 @@ RUN npm install WORKDIR /node/src/grpc-node/packages/grpc-js-xds RUN npm install -FROM node:16-alpine +FROM node:18-slim WORKDIR /node/src/grpc-node COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ From 43d42dcf3f2409c53a623b46ab72c89af353e4e8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 11 Apr 2023 14:24:25 -0700 Subject: [PATCH 1868/1899] grpc-js: Fix connectivity state change event sequencing --- .../grpc-js/src/load-balancer-pick-first.ts | 2 +- packages/grpc-js/src/subchannel.ts | 65 ++++----- .../test/test-global-subchannel-pool.ts | 130 ++++++++++++++++++ 3 files changed, 165 insertions(+), 32 deletions(-) create mode 100644 packages/grpc-js/test/test-global-subchannel-pool.ts diff --git a/packages/grpc-js/src/load-balancer-pick-first.ts b/packages/grpc-js/src/load-balancer-pick-first.ts index a501b1f7d..41d21a2ea 100644 --- a/packages/grpc-js/src/load-balancer-pick-first.ts +++ b/packages/grpc-js/src/load-balancer-pick-first.ts @@ -322,12 +322,12 @@ export class PickFirstLoadBalancer implements LoadBalancer { ); } this.currentPick = subchannel; - this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); subchannel.addConnectivityStateListener(this.pickedSubchannelStateListener); subchannel.ref(); this.channelControlHelper.addChannelzChild(subchannel.getChannelzRef()); this.resetSubchannelList(); clearTimeout(this.connectionDelayTimeout); + this.updateState(ConnectivityState.READY, new PickFirstPicker(subchannel)); } private updateState(newState: ConnectivityState, picker: Picker) { diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index c93e0c451..de420cc97 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -60,7 +60,7 @@ export class Subchannel { * state changes. Will be modified by `addConnectivityStateListener` and * `removeConnectivityStateListener` */ - private stateListeners: ConnectivityStateListener[] = []; + private stateListeners: Set = new Set(); private backoffTimeout: BackoffTimeout; @@ -227,6 +227,8 @@ export class Subchannel { } const previousState = this.connectivityState; this.connectivityState = newState; + process.nextTick(() => { + }); switch (newState) { case ConnectivityState.READY: this.stopBackoff(); @@ -261,9 +263,7 @@ export class Subchannel { default: throw new Error(`Invalid state: unknown ConnectivityState ${newState}`); } - /* We use a shallow copy of the stateListeners array in case a listener - * is removed during this iteration */ - for (const listener of [...this.stateListeners]) { + for (const listener of this.stateListeners) { listener(this, previousState, newState, this.keepaliveTime); } return true; @@ -291,13 +291,15 @@ export class Subchannel { if (this.channelzEnabled) { this.channelzTrace.addTrace('CT_INFO', 'Shutting down'); } - this.transitionToState( - [ConnectivityState.CONNECTING, ConnectivityState.READY], - ConnectivityState.IDLE - ); if (this.channelzEnabled) { unregisterChannelzRef(this.channelzRef); } + process.nextTick(() => { + this.transitionToState( + [ConnectivityState.CONNECTING, ConnectivityState.READY], + ConnectivityState.IDLE + ); + }); } } @@ -339,20 +341,22 @@ export class Subchannel { * Otherwise, do nothing. */ startConnecting() { - /* First, try to transition from IDLE to connecting. If that doesn't happen - * because the state is not currently IDLE, check if it is - * TRANSIENT_FAILURE, and if so indicate that it should go back to - * connecting after the backoff timer ends. Otherwise do nothing */ - if ( - !this.transitionToState( - [ConnectivityState.IDLE], - ConnectivityState.CONNECTING - ) - ) { - if (this.connectivityState === ConnectivityState.TRANSIENT_FAILURE) { - this.continueConnecting = true; + process.nextTick(() => { + /* First, try to transition from IDLE to connecting. If that doesn't happen + * because the state is not currently IDLE, check if it is + * TRANSIENT_FAILURE, and if so indicate that it should go back to + * connecting after the backoff timer ends. Otherwise do nothing */ + if ( + !this.transitionToState( + [ConnectivityState.IDLE], + ConnectivityState.CONNECTING + ) + ) { + if (this.connectivityState === ConnectivityState.TRANSIENT_FAILURE) { + this.continueConnecting = true; + } } - } + }); } /** @@ -368,7 +372,7 @@ export class Subchannel { * @param listener */ addConnectivityStateListener(listener: ConnectivityStateListener) { - this.stateListeners.push(listener); + this.stateListeners.add(listener); } /** @@ -377,21 +381,20 @@ export class Subchannel { * `addConnectivityStateListener` */ removeConnectivityStateListener(listener: ConnectivityStateListener) { - const listenerIndex = this.stateListeners.indexOf(listener); - if (listenerIndex > -1) { - this.stateListeners.splice(listenerIndex, 1); - } + this.stateListeners.delete(listener); } /** * Reset the backoff timeout, and immediately start connecting if in backoff. */ resetBackoff() { - this.backoffTimeout.reset(); - this.transitionToState( - [ConnectivityState.TRANSIENT_FAILURE], - ConnectivityState.CONNECTING - ); + process.nextTick(() => { + this.backoffTimeout.reset(); + this.transitionToState( + [ConnectivityState.TRANSIENT_FAILURE], + ConnectivityState.CONNECTING + ); + }); } getAddress(): string { diff --git a/packages/grpc-js/test/test-global-subchannel-pool.ts b/packages/grpc-js/test/test-global-subchannel-pool.ts new file mode 100644 index 000000000..c19125687 --- /dev/null +++ b/packages/grpc-js/test/test-global-subchannel-pool.ts @@ -0,0 +1,130 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import * as path from 'path'; + +import * as grpc from '../src'; +import {sendUnaryData, Server, ServerCredentials, ServerUnaryCall, ServiceClientConstructor, ServiceError} from '../src'; + +import {loadProtoFile} from './common'; + +const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); +const echoService = + loadProtoFile(protoFile).EchoService as ServiceClientConstructor; + +describe.only('Global subchannel pool', () => { + let server: Server; + let serverPort: number; + + let client1: InstanceType; + let client2: InstanceType; + + let promises: Promise[]; + + before(done => { + server = new Server(); + server.addService(echoService.service, { + echo(call: ServerUnaryCall, callback: sendUnaryData) { + callback(null, call.request); + }, + }); + + server.bindAsync( + 'localhost:0', ServerCredentials.createInsecure(), (err, port) => { + assert.ifError(err); + serverPort = port; + server.start(); + done(); + }); + }); + + beforeEach(() => { + promises = []; + }) + + after(done => { + server.tryShutdown(done); + }); + + function callService(client: InstanceType) { + return new Promise((resolve) => { + const request = {value: 'test value', value2: 3}; + + client.echo(request, (error: ServiceError, response: any) => { + assert.ifError(error); + assert.deepStrictEqual(response, request); + resolve(); + }); + }) + } + + function connect() { + const grpcOptions = { + 'grpc.use_local_subchannel_pool': 0, + } + + client1 = new echoService( + `127.0.0.1:${serverPort}`, grpc.credentials.createInsecure(), + grpcOptions); + + client2 = new echoService( + `127.0.0.1:${serverPort}`, grpc.credentials.createInsecure(), + grpcOptions); + } + + /* This is a regression test for a bug where client1.close in the + * waitForReady callback would cause the subchannel to transition to IDLE + * even though client2 is also using it. */ + it('Should handle client.close calls in waitForReady', + done => { + connect(); + + promises.push(new Promise((resolve) => { + client1.waitForReady(Date.now() + 50, (error) => { + assert.ifError(error); + client1.close(); + resolve(); + }); + })) + + promises.push(new Promise((resolve) => { + client2.waitForReady(Date.now() + 50, (error) => { + assert.ifError(error); + resolve(); + }); + })) + + Promise.all(promises).then(() => {done()}); + }) + + it('Call the service', done => { + promises.push(callService(client2)); + + Promise.all(promises).then(() => { + done(); + }); + }) + + it('Should complete the client lifecycle without error', done => { + setTimeout(() => { + client1.close(); + client2.close(); + done() + }, 500); + }); +}); From 6bc85716cd65bea8e532341efaf1e0331ec9328c Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Apr 2023 14:46:27 -0700 Subject: [PATCH 1869/1899] grpc-js: Bump version to 1.8.14 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 815dabeb0..dd341ef03 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.13", + "version": "1.8.14", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 37099980127e05a83c9f3d609879c0af6ca4e66b Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 13 Apr 2023 09:25:38 -0700 Subject: [PATCH 1870/1899] grpc-js: Fix a couple of errors from a previous PR --- packages/grpc-js/src/subchannel.ts | 2 -- packages/grpc-js/test/test-global-subchannel-pool.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/grpc-js/src/subchannel.ts b/packages/grpc-js/src/subchannel.ts index de420cc97..307f6b81e 100644 --- a/packages/grpc-js/src/subchannel.ts +++ b/packages/grpc-js/src/subchannel.ts @@ -227,8 +227,6 @@ export class Subchannel { } const previousState = this.connectivityState; this.connectivityState = newState; - process.nextTick(() => { - }); switch (newState) { case ConnectivityState.READY: this.stopBackoff(); diff --git a/packages/grpc-js/test/test-global-subchannel-pool.ts b/packages/grpc-js/test/test-global-subchannel-pool.ts index c19125687..999a11bf7 100644 --- a/packages/grpc-js/test/test-global-subchannel-pool.ts +++ b/packages/grpc-js/test/test-global-subchannel-pool.ts @@ -27,7 +27,7 @@ const protoFile = path.join(__dirname, 'fixtures', 'echo_service.proto'); const echoService = loadProtoFile(protoFile).EchoService as ServiceClientConstructor; -describe.only('Global subchannel pool', () => { +describe('Global subchannel pool', () => { let server: Server; let serverPort: number; From 2cb6ef86d4debde64e440d53ddb0f5ae10f228c7 Mon Sep 17 00:00:00 2001 From: Sergii Tkachenko Date: Fri, 7 Apr 2023 14:45:21 -0700 Subject: [PATCH 1871/1899] PSM Interop: experiment with qps affect on circuit_breaking ref b/232859415 --- packages/grpc-js-xds/scripts/xds.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index d4490c5ef..af22f584f 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -60,6 +60,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ + --qps=50 \ ${XDS_V3_OPT-} \ --client_cmd="$(which node) --enable-source-maps --prof --logfile=${KOKORO_ARTIFACTS_DIR}/github/grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ From 856559cce1d27771d50dc97d130f5dc423dd4723 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Apr 2023 14:34:06 -0700 Subject: [PATCH 1872/1899] grpc-js-xds: Fix handling of resource validation errors --- .../src/xds-stream-state/xds-stream-state.ts | 46 +++--- packages/grpc-js-xds/test/test-nack.ts | 156 ++++++++++++++++++ 2 files changed, 182 insertions(+), 20 deletions(-) create mode 100644 packages/grpc-js-xds/test/test-nack.ts diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index e20bc7e9b..b2d7b2279 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -15,7 +15,7 @@ * */ -import { experimental, logVerbosity, StatusObject } from "@grpc/grpc-js"; +import { experimental, logVerbosity, Metadata, status, StatusObject } from "@grpc/grpc-js"; import { Any__Output } from "../generated/google/protobuf/Any"; const TRACER_NAME = 'xds_client'; @@ -157,19 +157,32 @@ export abstract class BaseXdsStreamState implements XdsStreamState return Array.from(this.subscriptions.keys()); } handleResponses(responses: ResourcePair[]): HandleResponseResult { - const validResponses: ResponseType[] = []; let result: HandleResponseResult = { accepted: [], rejected: [], missing: [] } + const allResourceNames = new Set(); for (const {resource, raw} of responses) { const resourceName = this.getResourceName(resource); + allResourceNames.add(resourceName); + const subscriptionEntry = this.subscriptions.get(resourceName); if (this.validateResponse(resource)) { - validResponses.push(resource); result.accepted.push({ name: resourceName, raw: raw}); + if (subscriptionEntry) { + const watchers = subscriptionEntry.watchers; + for (const watcher of watchers) { + watcher.onValidUpdate(resource); + } + clearTimeout(subscriptionEntry.resourceTimer); + subscriptionEntry.cachedResponse = resource; + if (subscriptionEntry.deletionIgnored) { + experimental.log(logVerbosity.INFO, 'Received resource with previously ignored deletion: ' + resourceName); + subscriptionEntry.deletionIgnored = false; + } + } } else { this.trace('Validation failed for message ' + JSON.stringify(resource)); result.rejected.push({ @@ -177,23 +190,16 @@ export abstract class BaseXdsStreamState implements XdsStreamState raw: raw, error: `Validation failed for resource ${resourceName}` }); - } - } - const allResourceNames = new Set(); - for (const resource of validResponses) { - const resourceName = this.getResourceName(resource); - allResourceNames.add(resourceName); - const subscriptionEntry = this.subscriptions.get(resourceName); - if (subscriptionEntry) { - const watchers = subscriptionEntry.watchers; - for (const watcher of watchers) { - watcher.onValidUpdate(resource); - } - clearTimeout(subscriptionEntry.resourceTimer); - subscriptionEntry.cachedResponse = resource; - if (subscriptionEntry.deletionIgnored) { - experimental.log(logVerbosity.INFO, 'Received resource with previously ignored deletion: ' + resourceName); - subscriptionEntry.deletionIgnored = false; + if (subscriptionEntry) { + const watchers = subscriptionEntry.watchers; + for (const watcher of watchers) { + watcher.onTransientError({ + code: status.UNAVAILABLE, + details: `Validation failed for resource ${resourceName}`, + metadata: new Metadata() + }); + } + clearTimeout(subscriptionEntry.resourceTimer); } } } diff --git a/packages/grpc-js-xds/test/test-nack.ts b/packages/grpc-js-xds/test/test-nack.ts new file mode 100644 index 000000000..ad1aad448 --- /dev/null +++ b/packages/grpc-js-xds/test/test-nack.ts @@ -0,0 +1,156 @@ +/* + * Copyright 2023 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +import * as assert from 'assert'; +import { register } from "../src"; +import { Backend } from "./backend"; +import { XdsTestClient } from "./client"; +import { FakeCluster, FakeRouteGroup } from "./framework"; +import { XdsServer } from "./xds-server"; + +register(); + +describe('Validation errors', () => { + let xdsServer: XdsServer; + let client: XdsTestClient; + beforeEach(done => { + xdsServer = new XdsServer(); + xdsServer.startServer(error => { + done(error); + }); + }); + afterEach(() => { + client?.close(); + xdsServer?.shutdownServer(); + }); + it('Should continue to use a valid resource after receiving an invalid EDS update', done => { + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); + routeGroup.startAllBackends().then(() => { + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + client = new XdsTestClient('route1', xdsServer); + client.startCalls(100); + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + // After backends receive calls, set invalid EDS resource + xdsServer.setEdsResource({cluster_name: cluster.getEndpointConfig().cluster_name, endpoints: [{}]}); + let seenNack = false; + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + if (seenNack) { + return; + } + seenNack = true; + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + client.stopCalls(); + done(); + }); + } + }); + }, reason => done(reason)); + }, reason => done(reason)); + }); + it('Should continue to use a valid resource after receiving an invalid CDS update', done => { + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); + routeGroup.startAllBackends().then(() => { + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + client = new XdsTestClient('route1', xdsServer); + client.startCalls(100); + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + // After backends receive calls, set invalid CDS resource + xdsServer.setCdsResource({name: cluster.getClusterConfig().name}); + let seenNack = false; + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + if (seenNack) { + return; + } + seenNack = true; + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + client.stopCalls(); + done(); + }); + } + }); + }, reason => done(reason)); + }, reason => done(reason)); + }); + it('Should continue to use a valid resource after receiving an invalid RDS update', done => { + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); + routeGroup.startAllBackends().then(() => { + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + client = new XdsTestClient('route1', xdsServer); + client.startCalls(100); + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + // After backends receive calls, set invalid RDS resource + xdsServer.setRdsResource({name: routeGroup.getRouteConfiguration().name, virtual_hosts: [{domains: ['**']}]}); + let seenNack = false; + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + if (seenNack) { + return; + } + seenNack = true; + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + client.stopCalls(); + done(); + }); + } + }); + }, reason => done(reason)); + }, reason => done(reason)); + }); + it('Should continue to use a valid resource after receiving an invalid LDS update', done => { + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); + routeGroup.startAllBackends().then(() => { + xdsServer.setEdsResource(cluster.getEndpointConfig()); + xdsServer.setCdsResource(cluster.getClusterConfig()); + xdsServer.setRdsResource(routeGroup.getRouteConfiguration()); + xdsServer.setLdsResource(routeGroup.getListener()); + client = new XdsTestClient('route1', xdsServer); + client.startCalls(100); + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + // After backends receive calls, set invalid LDS resource + xdsServer.setLdsResource({name: routeGroup.getListener().name}); + let seenNack = false; + xdsServer.addResponseListener((typeUrl, responseState) => { + if (responseState.state === 'NACKED') { + if (seenNack) { + return; + } + seenNack = true; + routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { + client.stopCalls(); + done(); + }); + } + }); + }, reason => done(reason)); + }, reason => done(reason)); + }); +}); \ No newline at end of file From 48ef1ed202e19c36e934015b6b1ed039cf7d2f00 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 20 Apr 2023 14:35:39 -0700 Subject: [PATCH 1873/1899] grpc-js-xds: Bump version to 1.8.2 --- packages/grpc-js-xds/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/package.json b/packages/grpc-js-xds/package.json index 9511776c3..7c735b652 100644 --- a/packages/grpc-js-xds/package.json +++ b/packages/grpc-js-xds/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js-xds", - "version": "1.8.1", + "version": "1.8.2", "description": "Plugin for @grpc/grpc-js. Adds the xds:// URL scheme and associated features.", "main": "build/src/index.js", "scripts": { From dfccd687f0bc1df7d8d7dd599249b098a772cf53 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 24 Apr 2023 16:21:12 -0700 Subject: [PATCH 1874/1899] Address review comments --- .../src/xds-stream-state/xds-stream-state.ts | 8 +++----- packages/grpc-js-xds/test/test-nack.ts | 20 +++++++++++-------- 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts index b2d7b2279..b04adb79a 100644 --- a/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts +++ b/packages/grpc-js-xds/src/xds-stream-state/xds-stream-state.ts @@ -172,14 +172,13 @@ export abstract class BaseXdsStreamState implements XdsStreamState name: resourceName, raw: raw}); if (subscriptionEntry) { - const watchers = subscriptionEntry.watchers; - for (const watcher of watchers) { + for (const watcher of subscriptionEntry.watchers) { watcher.onValidUpdate(resource); } clearTimeout(subscriptionEntry.resourceTimer); subscriptionEntry.cachedResponse = resource; if (subscriptionEntry.deletionIgnored) { - experimental.log(logVerbosity.INFO, 'Received resource with previously ignored deletion: ' + resourceName); + experimental.log(logVerbosity.INFO, `Received resource with previously ignored deletion: ${resourceName}`); subscriptionEntry.deletionIgnored = false; } } @@ -191,8 +190,7 @@ export abstract class BaseXdsStreamState implements XdsStreamState error: `Validation failed for resource ${resourceName}` }); if (subscriptionEntry) { - const watchers = subscriptionEntry.watchers; - for (const watcher of watchers) { + for (const watcher of subscriptionEntry.watchers) { watcher.onTransientError({ code: status.UNAVAILABLE, details: `Validation failed for resource ${resourceName}`, diff --git a/packages/grpc-js-xds/test/test-nack.ts b/packages/grpc-js-xds/test/test-nack.ts index ad1aad448..b5bfb773e 100644 --- a/packages/grpc-js-xds/test/test-nack.ts +++ b/packages/grpc-js-xds/test/test-nack.ts @@ -38,7 +38,7 @@ describe('Validation errors', () => { xdsServer?.shutdownServer(); }); it('Should continue to use a valid resource after receiving an invalid EDS update', done => { - const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality: {region: 'region1'}}]); const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); routeGroup.startAllBackends().then(() => { xdsServer.setEdsResource(cluster.getEndpointConfig()); @@ -49,7 +49,8 @@ describe('Validation errors', () => { client.startCalls(100); routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { // After backends receive calls, set invalid EDS resource - xdsServer.setEdsResource({cluster_name: cluster.getEndpointConfig().cluster_name, endpoints: [{}]}); + const invalidEdsResource = {cluster_name: cluster.getEndpointConfig().cluster_name, endpoints: [{}]}; + xdsServer.setEdsResource(invalidEdsResource); let seenNack = false; xdsServer.addResponseListener((typeUrl, responseState) => { if (responseState.state === 'NACKED') { @@ -67,7 +68,7 @@ describe('Validation errors', () => { }, reason => done(reason)); }); it('Should continue to use a valid resource after receiving an invalid CDS update', done => { - const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality: {region: 'region1'}}]); const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); routeGroup.startAllBackends().then(() => { xdsServer.setEdsResource(cluster.getEndpointConfig()); @@ -78,7 +79,8 @@ describe('Validation errors', () => { client.startCalls(100); routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { // After backends receive calls, set invalid CDS resource - xdsServer.setCdsResource({name: cluster.getClusterConfig().name}); + const invalidCdsResource = {name: cluster.getClusterConfig().name}; + xdsServer.setCdsResource(invalidCdsResource); let seenNack = false; xdsServer.addResponseListener((typeUrl, responseState) => { if (responseState.state === 'NACKED') { @@ -96,7 +98,7 @@ describe('Validation errors', () => { }, reason => done(reason)); }); it('Should continue to use a valid resource after receiving an invalid RDS update', done => { - const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality: {region: 'region1'}}]); const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); routeGroup.startAllBackends().then(() => { xdsServer.setEdsResource(cluster.getEndpointConfig()); @@ -107,7 +109,8 @@ describe('Validation errors', () => { client.startCalls(100); routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { // After backends receive calls, set invalid RDS resource - xdsServer.setRdsResource({name: routeGroup.getRouteConfiguration().name, virtual_hosts: [{domains: ['**']}]}); + const invalidRdsResource = {name: routeGroup.getRouteConfiguration().name, virtual_hosts: [{domains: ['**']}]}; + xdsServer.setRdsResource(invalidRdsResource); let seenNack = false; xdsServer.addResponseListener((typeUrl, responseState) => { if (responseState.state === 'NACKED') { @@ -125,7 +128,7 @@ describe('Validation errors', () => { }, reason => done(reason)); }); it('Should continue to use a valid resource after receiving an invalid LDS update', done => { - const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality:{region: 'region1'}}]); + const cluster = new FakeCluster('cluster1', [{backends: [new Backend()], locality: {region: 'region1'}}]); const routeGroup = new FakeRouteGroup('route1', [{cluster: cluster}]); routeGroup.startAllBackends().then(() => { xdsServer.setEdsResource(cluster.getEndpointConfig()); @@ -136,7 +139,8 @@ describe('Validation errors', () => { client.startCalls(100); routeGroup.waitForAllBackendsToReceiveTraffic().then(() => { // After backends receive calls, set invalid LDS resource - xdsServer.setLdsResource({name: routeGroup.getListener().name}); + const invalidLdsResource = {name: routeGroup.getListener().name}; + xdsServer.setLdsResource(invalidLdsResource); let seenNack = false; xdsServer.addResponseListener((typeUrl, responseState) => { if (responseState.state === 'NACKED') { From edeeda6424d568b80eb4478b63afba05c51904a5 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 24 Apr 2023 16:22:49 -0700 Subject: [PATCH 1875/1899] Add trailing newline in packages/grpc-js-xds/test/test-nack.ts Co-authored-by: Sergii Tkachenko --- packages/grpc-js-xds/test/test-nack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/test/test-nack.ts b/packages/grpc-js-xds/test/test-nack.ts index b5bfb773e..9395628a6 100644 --- a/packages/grpc-js-xds/test/test-nack.ts +++ b/packages/grpc-js-xds/test/test-nack.ts @@ -157,4 +157,4 @@ describe('Validation errors', () => { }, reason => done(reason)); }, reason => done(reason)); }); -}); \ No newline at end of file +}); From 0933633424b5eeec56d047d5e9fd2dd09dff4ac9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Apr 2023 15:00:05 -0700 Subject: [PATCH 1876/1899] PSM Interop: Increase old driver QPS to 75 --- packages/grpc-js-xds/scripts/xds.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds.sh b/packages/grpc-js-xds/scripts/xds.sh index af22f584f..7e6794a31 100755 --- a/packages/grpc-js-xds/scripts/xds.sh +++ b/packages/grpc-js-xds/scripts/xds.sh @@ -60,7 +60,7 @@ GRPC_NODE_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weigh --path_to_server_binary=/java_server/grpc-java/interop-testing/build/install/grpc-interop-testing/bin/xds-test-server \ --gcp_suffix=$(date '+%s') \ --verbose \ - --qps=50 \ + --qps=75 \ ${XDS_V3_OPT-} \ --client_cmd="$(which node) --enable-source-maps --prof --logfile=${KOKORO_ARTIFACTS_DIR}/github/grpc/reports/prof.log grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client \ --server=xds:///{server_uri} \ From 2b455e7d18d1c108bd1ca901678c757434c054b7 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 31 May 2023 14:05:10 -0700 Subject: [PATCH 1877/1899] grpc-js: Fix a couple of minor issues --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/client.ts | 36 ++++++++++++++------- packages/grpc-js/src/load-balancing-call.ts | 8 +++-- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index dd341ef03..7d8c1a597 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.14", + "version": "1.8.15", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index f96f8fdf0..bdbdc6e97 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -323,7 +323,7 @@ export class Client { emitter.call = call; let responseMessage: ResponseType | null = null; let receivedStatus = false; - const callerStackError = new Error(); + let callerStackError: Error | null = new Error(); call.start(callProperties.metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -342,19 +342,22 @@ export class Client { receivedStatus = true; if (status.code === Status.OK) { if (responseMessage === null) { - const callerStack = getErrorStackString(callerStackError); + const callerStack = getErrorStackString(callerStackError!); callProperties.callback!(callErrorFromStatus({ code: Status.INTERNAL, details: 'No message received', metadata: status.metadata - }, callerStack)); + }, /*callerStack*/'')); } else { callProperties.callback!(null, responseMessage); } } else { - const callerStack = getErrorStackString(callerStackError); - callProperties.callback!(callErrorFromStatus(status, callerStack)); + const callerStack = getErrorStackString(callerStackError!); + callProperties.callback!(callErrorFromStatus(status, /*callerStack*/'')); } + /* Avoid retaining the callerStackError object in the call context of + * the status event handler. */ + callerStackError = null; emitter.emit('status', status); }, }); @@ -448,7 +451,7 @@ export class Client { emitter.call = call; let responseMessage: ResponseType | null = null; let receivedStatus = false; - const callerStackError = new Error(); + let callerStackError: Error | null = new Error(); call.start(callProperties.metadata, { onReceiveMetadata: (metadata) => { emitter.emit('metadata', metadata); @@ -467,7 +470,7 @@ export class Client { receivedStatus = true; if (status.code === Status.OK) { if (responseMessage === null) { - const callerStack = getErrorStackString(callerStackError); + const callerStack = getErrorStackString(callerStackError!); callProperties.callback!(callErrorFromStatus({ code: Status.INTERNAL, details: 'No message received', @@ -477,9 +480,12 @@ export class Client { callProperties.callback!(null, responseMessage); } } else { - const callerStack = getErrorStackString(callerStackError); + const callerStack = getErrorStackString(callerStackError!); callProperties.callback!(callErrorFromStatus(status, callerStack)); } + /* Avoid retaining the callerStackError object in the call context of + * the status event handler. */ + callerStackError = null; emitter.emit('status', status); }, }); @@ -577,7 +583,7 @@ export class Client { * call after that. */ stream.call = call; let receivedStatus = false; - const callerStackError = new Error(); + let callerStackError: Error | null = new Error(); call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -593,9 +599,12 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { - const callerStack = getErrorStackString(callerStackError); + const callerStack = getErrorStackString(callerStackError!); stream.emit('error', callErrorFromStatus(status, callerStack)); } + /* Avoid retaining the callerStackError object in the call context of + * the status event handler. */ + callerStackError = null; stream.emit('status', status); }, }); @@ -673,7 +682,7 @@ export class Client { * call after that. */ stream.call = call; let receivedStatus = false; - const callerStackError = new Error(); + let callerStackError: Error | null = new Error(); call.start(callProperties.metadata, { onReceiveMetadata(metadata: Metadata) { stream.emit('metadata', metadata); @@ -688,9 +697,12 @@ export class Client { receivedStatus = true; stream.push(null); if (status.code !== Status.OK) { - const callerStack = getErrorStackString(callerStackError); + const callerStack = getErrorStackString(callerStackError!); stream.emit('error', callErrorFromStatus(status, callerStack)); } + /* Avoid retaining the callerStackError object in the call context of + * the status event handler. */ + callerStackError = null; stream.emit('status', status); }, }); diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index f74933983..d88bdb809 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -216,14 +216,18 @@ export class LoadBalancingCall implements Call { break; case PickResultType.DROP: const {code, details} = restrictControlPlaneStatusCode(pickResult.status!.code, pickResult.status!.details); - this.outputStatus({code, details, metadata: pickResult.status!.metadata}, 'DROP'); + setImmediate(() => { + this.outputStatus({code, details, metadata: pickResult.status!.metadata}, 'DROP'); + }); break; case PickResultType.TRANSIENT_FAILURE: if (this.metadata.getOptions().waitForReady) { this.channel.queueCallForPick(this); } else { const {code, details} = restrictControlPlaneStatusCode(pickResult.status!.code, pickResult.status!.details); - this.outputStatus({code, details, metadata: pickResult.status!.metadata}, 'PROCESSED'); + setImmediate(() => { + this.outputStatus({code, details, metadata: pickResult.status!.metadata}, 'PROCESSED'); + }); } break; case PickResultType.QUEUE: From 039032cdfb87b455d883e813002b4ed52fb472c9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 1 Jun 2023 09:43:16 -0700 Subject: [PATCH 1878/1899] Merge pull request #2457 from XuanWang-Amos/xds_duplicate_bugs PSM Interop: Don't fail target if sub-target already failed --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index b87e3306c..4a83d44d5 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -170,9 +170,6 @@ main() { run_test $test || (( ++failed_tests )) done echo "Failed test suites: ${failed_tests}" - if (( failed_tests > 0 )); then - exit 1 - fi } main "$@" From 87b5466b1b5e6d269a9750305c5842c9e30e56e8 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 20 Jun 2023 10:25:59 -0700 Subject: [PATCH 1879/1899] grpc-js: Implement trace function in Http2SubchannelConnector --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/transport.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 7d8c1a597..f0331f1fc 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.15", + "version": "1.8.16", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 8abc13aba..2f89d8f28 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -485,7 +485,7 @@ export class Http2SubchannelConnector implements SubchannelConnector { private isShutdown = false; constructor(private channelTarget: GrpcUri) {} private trace(text: string) { - + logging.trace(LogVerbosity.DEBUG, TRACER_NAME, this.channelTarget + ' ' + text); } private createSession(address: SubchannelAddress, credentials: ChannelCredentials, options: ChannelOptions, proxyConnectionResult: ProxyConnectionResult): Promise { if (this.isShutdown) { From b53f5882f13a5cb3c599804e96304bf5b8407ea6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Jun 2023 14:26:31 -0700 Subject: [PATCH 1880/1899] grpc-js: Disallow pick_first as child of outlier_detection --- packages/grpc-js/package.json | 2 +- .../grpc-js/src/load-balancer-outlier-detection.ts | 11 +++++++---- packages/grpc-js/src/resolver-dns.ts | 4 ++-- packages/grpc-js/test/test-outlier-detection.ts | 12 +++++++++++- 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index f0331f1fc..d4b822600 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.16", + "version": "1.8.17", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 2f72a9625..885c4feb9 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -113,6 +113,9 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig failurePercentageEjection: Partial | null, private readonly childPolicy: LoadBalancingConfig[] ) { + if (childPolicy[0].getLoadBalancerName() === 'pick_first') { + throw new Error('outlier_detection LB policy cannot have a pick_first child policy'); + } this.intervalMs = intervalMs ?? 10_000; this.baseEjectionTimeMs = baseEjectionTimeMs ?? 30_000; this.maxEjectionTimeMs = maxEjectionTimeMs ?? 300_000; @@ -395,8 +398,8 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { } private isCountingEnabled(): boolean { - return this.latestConfig !== null && - (this.latestConfig.getSuccessRateEjectionConfig() !== null || + return this.latestConfig !== null && + (this.latestConfig.getSuccessRateEjectionConfig() !== null || this.latestConfig.getFailurePercentageEjectionConfig() !== null); } @@ -496,7 +499,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { if (addressesWithTargetVolume < failurePercentageConfig.minimum_hosts) { return; } - + // Step 2 for (const [address, mapEntry] of this.addressMap.entries()) { // Step 2.i @@ -656,4 +659,4 @@ export function setup() { if (OUTLIER_DETECTION_ENABLED) { registerLoadBalancerType(TYPE_NAME, OutlierDetectionLoadBalancer, OutlierDetectionLoadBalancingConfig); } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index 355ce2dfd..b20b7a543 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -137,7 +137,7 @@ class DnsResolver implements Resolver { details: `Name resolution failed for target ${uriToString(this.target)}`, metadata: new Metadata(), }; - + const backoffOptions: BackoffOptions = { initialDelay: channelOptions['grpc.initial_reconnect_backoff_ms'], maxDelay: channelOptions['grpc.max_reconnect_backoff_ms'], @@ -276,7 +276,7 @@ class DnsResolver implements Resolver { } catch (err) { this.latestServiceConfigError = { code: Status.UNAVAILABLE, - details: 'Parsing service config failed', + details: `Parsing service config failed with error ${(err as Error).message}`, metadata: new Metadata(), }; } diff --git a/packages/grpc-js/test/test-outlier-detection.ts b/packages/grpc-js/test/test-outlier-detection.ts index c9021e605..d51ccf3fd 100644 --- a/packages/grpc-js/test/test-outlier-detection.ts +++ b/packages/grpc-js/test/test-outlier-detection.ts @@ -360,6 +360,16 @@ describe('Outlier detection config validation', () => { }, /failure_percentage_ejection\.enforcement_percentage parse error: value out of range for percentage/); }); }); + describe('child_policy', () => { + it('Should reject a pick_first child_policy', () => { + const loadBalancingConfig = { + child_policy: [{pick_first: {}}] + }; + assert.throws(() => { + OutlierDetectionLoadBalancingConfig.createFromJson(loadBalancingConfig); + }, /outlier_detection LB policy cannot have a pick_first child policy/); + }); + }); }); describe('Outlier detection', () => { @@ -533,4 +543,4 @@ describe('Outlier detection', () => { }) }); }); -}); \ No newline at end of file +}); From 9441de78f655ada34ada0dc1a8057122eb21f229 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 22 Jun 2023 16:52:53 -0700 Subject: [PATCH 1881/1899] grpc-js-xds: Use distroless Node image for interop Dockerfile --- packages/grpc-js-xds/interop/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index 5987f1ee4..2986eb3e5 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -27,7 +27,7 @@ RUN npm install WORKDIR /node/src/grpc-node/packages/grpc-js-xds RUN npm install -FROM node:18-slim +FROM gcr.io/distroless/nodejs18-debian11:latest WORKDIR /node/src/grpc-node COPY --from=build /node/src/grpc-node/packages/grpc-js ./packages/grpc-js/ COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xds/ From a62d2b027bf91e5084c9134305e88a645dc5f1c1 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 23 Jun 2023 09:34:29 -0700 Subject: [PATCH 1882/1899] Use entrypoint /nodejs/bin/node --- packages/grpc-js-xds/interop/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/interop/Dockerfile b/packages/grpc-js-xds/interop/Dockerfile index 2986eb3e5..5ff12a433 100644 --- a/packages/grpc-js-xds/interop/Dockerfile +++ b/packages/grpc-js-xds/interop/Dockerfile @@ -35,4 +35,4 @@ COPY --from=build /node/src/grpc-node/packages/grpc-js-xds ./packages/grpc-js-xd ENV GRPC_VERBOSITY="DEBUG" ENV GRPC_TRACE=xds_client,xds_resolver,cds_balancer,eds_balancer,priority,weighted_target,round_robin,resolving_load_balancer,subchannel,keepalive,dns_resolver,fault_injection,http_filter,csds,outlier_detection -ENTRYPOINT [ "node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] +ENTRYPOINT [ "/nodejs/bin/node", "/node/src/grpc-node/packages/grpc-js-xds/build/interop/xds-interop-client" ] From a6aa7ea43e1458a578cf9ab81ed492a760c43a78 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 23 Jun 2023 10:37:01 -0700 Subject: [PATCH 1883/1899] Merge pull request #2475 from XuanWang-Amos/file_multiple_url_map [PSM interop] Don't fail target if sub-target already failed --- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index 69126c72b..fc74718f2 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -156,7 +156,7 @@ main() { build_docker_images_if_needed # Run tests cd "${TEST_DRIVER_FULL_DIR}" - run_test url_map + run_test url_map || echo "Failed url_map test" } main "$@" From ed70a0b381144b387698f2d57001f5a7bc82cbe9 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 27 Jun 2023 10:11:45 -0700 Subject: [PATCH 1884/1899] Fix handling of OD policy with no child --- packages/grpc-js/src/load-balancer-outlier-detection.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 885c4feb9..ce8668f18 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -113,7 +113,7 @@ export class OutlierDetectionLoadBalancingConfig implements LoadBalancingConfig failurePercentageEjection: Partial | null, private readonly childPolicy: LoadBalancingConfig[] ) { - if (childPolicy[0].getLoadBalancerName() === 'pick_first') { + if (childPolicy.length > 0 && childPolicy[0].getLoadBalancerName() === 'pick_first') { throw new Error('outlier_detection LB policy cannot have a pick_first child policy'); } this.intervalMs = intervalMs ?? 10_000; From 3cef1ba5472d5127b7346ef1533ffb403e6dcef3 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 28 Jun 2023 16:00:22 -0700 Subject: [PATCH 1885/1899] Merge pull request #2488 from grpc/psm-interop-server-bump grpc-js-xds: Bump the canonical server from v1.46.x to v1.56.0 --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 4a83d44d5..729fb9293 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -19,7 +19,7 @@ set -eo pipefail readonly GITHUB_REPOSITORY_NAME="grpc-node" readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" ## xDS test client Docker images -readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/java-server:v1.46.x" +readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/java-server:558b5b0bfac8e21755c223063274a779b3898afe" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" From 45e277547f4ad535a6c83d887992f6707f7f816a Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jul 2023 14:55:49 -0700 Subject: [PATCH 1886/1899] grpc-js: Fix mistakenly committed testing changes --- packages/grpc-js/src/client.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/client.ts b/packages/grpc-js/src/client.ts index bdbdc6e97..7c856ee5b 100644 --- a/packages/grpc-js/src/client.ts +++ b/packages/grpc-js/src/client.ts @@ -347,13 +347,13 @@ export class Client { code: Status.INTERNAL, details: 'No message received', metadata: status.metadata - }, /*callerStack*/'')); + }, callerStack)); } else { callProperties.callback!(null, responseMessage); } } else { const callerStack = getErrorStackString(callerStackError!); - callProperties.callback!(callErrorFromStatus(status, /*callerStack*/'')); + callProperties.callback!(callErrorFromStatus(status, callerStack)); } /* Avoid retaining the callerStackError object in the call context of * the status event handler. */ From 713a2c9bd1f30ee7f5bab9aabbd5712b3578ee14 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jul 2023 15:22:15 -0700 Subject: [PATCH 1887/1899] grpc-js: Enable the noUnusedLocals TypeScript compiler option --- packages/grpc-js/src/channel-credentials.ts | 12 +----- packages/grpc-js/src/client-interceptors.ts | 1 - packages/grpc-js/src/compression-filter.ts | 2 +- packages/grpc-js/src/index.ts | 2 - packages/grpc-js/src/internal-channel.ts | 19 ++++------ .../src/load-balancer-outlier-detection.ts | 4 +- packages/grpc-js/src/load-balancer.ts | 5 +-- packages/grpc-js/src/load-balancing-call.ts | 10 ++--- .../grpc-js/src/max-message-size-filter.ts | 2 +- packages/grpc-js/src/metadata.ts | 5 --- packages/grpc-js/src/object-stream.ts | 2 +- packages/grpc-js/src/resolver-ip.ts | 2 +- packages/grpc-js/src/resolving-call.ts | 4 +- .../grpc-js/src/resolving-load-balancer.ts | 5 +-- packages/grpc-js/src/server-call.ts | 7 +++- packages/grpc-js/src/server.ts | 28 ++++++-------- packages/grpc-js/src/subchannel-call.ts | 8 ---- packages/grpc-js/src/transport.ts | 38 +++++++++---------- .../grpc-js/test/test-call-propagation.ts | 8 ++-- .../grpc-js/test/test-channel-credentials.ts | 7 +--- packages/grpc-js/test/test-channelz.ts | 4 +- packages/grpc-js/test/test-deadline.ts | 8 +--- .../grpc-js/test/test-outlier-detection.ts | 1 - packages/grpc-js/test/test-server.ts | 4 +- packages/grpc-js/tsconfig.json | 3 +- 25 files changed, 70 insertions(+), 121 deletions(-) diff --git a/packages/grpc-js/src/channel-credentials.ts b/packages/grpc-js/src/channel-credentials.ts index fd9d7b571..64db3e9eb 100644 --- a/packages/grpc-js/src/channel-credentials.ts +++ b/packages/grpc-js/src/channel-credentials.ts @@ -38,14 +38,6 @@ export type CheckServerIdentityCallback = ( cert: PeerCertificate ) => Error | undefined; -function bufferOrNullEqual(buf1: Buffer | null, buf2: Buffer | null) { - if (buf1 === null && buf2 === null) { - return true; - } else { - return buf1 !== null && buf2 !== null && buf1.equals(buf2); - } -} - /** * Additional peer verification options that can be set when creating * SSL credentials. @@ -196,7 +188,7 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { private verifyOptions: VerifyOptions ) { super(); - this.connectionOptions = { + this.connectionOptions = { secureContext }; // Node asserts that this option is a function, so we cannot pass undefined @@ -225,7 +217,7 @@ class SecureChannelCredentialsImpl extends ChannelCredentials { } if (other instanceof SecureChannelCredentialsImpl) { return ( - this.secureContext === other.secureContext && + this.secureContext === other.secureContext && this.verifyOptions.checkServerIdentity === other.verifyOptions.checkServerIdentity ); } else { diff --git a/packages/grpc-js/src/client-interceptors.ts b/packages/grpc-js/src/client-interceptors.ts index d95828550..277a14f59 100644 --- a/packages/grpc-js/src/client-interceptors.ts +++ b/packages/grpc-js/src/client-interceptors.ts @@ -32,7 +32,6 @@ import { import { Status } from './constants'; import { Channel } from './channel'; import { CallOptions } from './client'; -import { CallCredentials } from './call-credentials'; import { ClientMethodDefinition } from './make-client'; import { getErrorMessage } from './error'; diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index f87614114..b8c2e6d1e 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -282,7 +282,7 @@ export class CompressionFilter extends BaseFilter implements Filter { export class CompressionFilterFactory implements FilterFactory { private sharedFilterConfig: SharedCompressionFilterConfig = {}; - constructor(private readonly channel: Channel, private readonly options: ChannelOptions) {} + constructor(channel: Channel, private readonly options: ChannelOptions) {} createFilter(): CompressionFilter { return new CompressionFilter(this.options, this.sharedFilterConfig); } diff --git a/packages/grpc-js/src/index.ts b/packages/grpc-js/src/index.ts index 51f394785..70178a89e 100644 --- a/packages/grpc-js/src/index.ts +++ b/packages/grpc-js/src/index.ts @@ -43,9 +43,7 @@ import { loadPackageDefinition, makeClientConstructor, MethodDefinition, - ProtobufTypeDefinition, Serialize, - ServiceClientConstructor, ServiceDefinition, } from './make-client'; import { Metadata, MetadataOptions, MetadataValue } from './metadata'; diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 14038bd3f..3d2624895 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -20,7 +20,7 @@ import { ChannelOptions } from './channel-options'; import { ResolvingLoadBalancer } from './resolving-load-balancer'; import { SubchannelPool, getSubchannelPool } from './subchannel-pool'; import { ChannelControlHelper } from './load-balancer'; -import { UnavailablePicker, Picker, PickResultType } from './picker'; +import { UnavailablePicker, Picker } from './picker'; import { Metadata } from './metadata'; import { Status, LogVerbosity, Propagate } from './constants'; import { FilterStackFactory } from './filter-stack'; @@ -31,22 +31,19 @@ import { getDefaultAuthority, mapUriDefaultScheme, } from './resolver'; -import { trace, log } from './logging'; +import { trace } from './logging'; import { SubchannelAddress } from './subchannel-address'; import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; -import { GrpcUri, parseUri, splitHostPort, uriToString } from './uri-parser'; +import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; -import { Filter } from './filter'; import { ConnectivityState } from './connectivity-state'; import { ChannelInfo, ChannelRef, ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzChannel, SubchannelRef, unregisterChannelzRef } from './channelz'; -import { Subchannel } from './subchannel'; import { LoadBalancingCall } from './load-balancing-call'; import { CallCredentials } from './call-credentials'; -import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from './call-interface'; -import { SubchannelCall } from './subchannel-call'; -import { Deadline, deadlineToString, getDeadlineTimeoutString } from './deadline'; +import { Call, CallStreamOptions, StatusObject } from './call-interface'; +import { Deadline, deadlineToString } from './deadline'; import { ResolvingCall } from './resolving-call'; import { getNextCallNumber } from './call-number'; import { restrictControlPlaneStatusCode } from './control-plane-status'; @@ -112,7 +109,7 @@ class ChannelSubchannelWrapper extends BaseSubchannelWrapper implements Subchann } export class InternalChannel { - + private resolvingLoadBalancer: ResolvingLoadBalancer; private subchannelPool: SubchannelPool; private connectivityState: ConnectivityState = ConnectivityState.IDLE; @@ -376,7 +373,7 @@ export class InternalChannel { trace( LogVerbosity.DEBUG, 'connectivity_state', - '(' + this.channelzRef.id + ') ' + + '(' + this.channelzRef.id + ') ' + uriToString(this.target) + ' ' + ConnectivityState[this.connectivityState] + @@ -601,7 +598,7 @@ export class InternalChannel { /** * Get the channelz reference object for this channel. The returned value is * garbage if channelz is disabled for this channel. - * @returns + * @returns */ getChannelzRef() { return this.channelzRef; diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index ce8668f18..7297000d0 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -20,11 +20,9 @@ import { ConnectivityState } from "./connectivity-state"; import { LogVerbosity, Status } from "./constants"; import { durationToMs, isDuration, msToDuration } from "./duration"; import { ChannelControlHelper, createChildChannelControlHelper, registerLoadBalancerType } from "./experimental"; -import { BaseFilter, Filter, FilterFactory } from "./filter"; import { getFirstUsableConfig, LoadBalancer, LoadBalancingConfig, validateLoadBalancingConfig } from "./load-balancer"; import { ChildLoadBalancerHandler } from "./load-balancer-child-handler"; -import { PickArgs, Picker, PickResult, PickResultType, QueuePicker, UnavailablePicker } from "./picker"; -import { Subchannel } from "./subchannel"; +import { PickArgs, Picker, PickResult, PickResultType } from "./picker"; import { SubchannelAddress, subchannelAddressToString } from "./subchannel-address"; import { BaseSubchannelWrapper, ConnectivityStateListener, SubchannelInterface } from "./subchannel-interface"; import * as logging from './logging'; diff --git a/packages/grpc-js/src/load-balancer.ts b/packages/grpc-js/src/load-balancer.ts index 48930c7db..8d1c96981 100644 --- a/packages/grpc-js/src/load-balancer.ts +++ b/packages/grpc-js/src/load-balancer.ts @@ -16,7 +16,6 @@ */ import { ChannelOptions } from './channel-options'; -import { Subchannel } from './subchannel'; import { SubchannelAddress } from './subchannel-address'; import { ConnectivityState } from './connectivity-state'; import { Picker } from './picker'; @@ -58,8 +57,8 @@ export interface ChannelControlHelper { * parent while letting others pass through to the parent unmodified. This * allows other code to create these children without needing to know about * all of the methods to be passed through. - * @param parent - * @param overrides + * @param parent + * @param overrides */ export function createChildChannelControlHelper(parent: ChannelControlHelper, overrides: Partial): ChannelControlHelper { return { diff --git a/packages/grpc-js/src/load-balancing-call.ts b/packages/grpc-js/src/load-balancing-call.ts index d88bdb809..e9144cb93 100644 --- a/packages/grpc-js/src/load-balancing-call.ts +++ b/packages/grpc-js/src/load-balancing-call.ts @@ -21,7 +21,6 @@ import { SubchannelCall } from "./subchannel-call"; import { ConnectivityState } from "./connectivity-state"; import { LogVerbosity, Status } from "./constants"; import { Deadline, getDeadlineTimeoutString } from "./deadline"; -import { FilterStack, FilterStackFactory } from "./filter-stack"; import { InternalChannel } from "./internal-channel"; import { Metadata } from "./metadata"; import { PickResultType } from "./picker"; @@ -48,7 +47,6 @@ export class LoadBalancingCall implements Call { private readPending = false; private pendingMessage: {context: MessageContext, message: Buffer} | null = null; private pendingHalfClose = false; - private pendingChildStatus: StatusObject | null = null; private ended = false; private serviceUrl: string; private metadata: Metadata | null = null; @@ -104,9 +102,9 @@ export class LoadBalancingCall implements Call { } this.trace('Pick called') const pickResult = this.channel.doPick(this.metadata, this.callConfig.pickInformation); - const subchannelString = pickResult.subchannel ? - '(' + pickResult.subchannel.getChannelzRef().id + ') ' + pickResult.subchannel.getAddress() : - '' + pickResult.subchannel; + const subchannelString = pickResult.subchannel ? + '(' + pickResult.subchannel.getChannelzRef().id + ') ' + pickResult.subchannel.getAddress() : + '' + pickResult.subchannel; this.trace( 'Pick result: ' + PickResultType[pickResult.pickResultType] + @@ -280,4 +278,4 @@ export class LoadBalancingCall implements Call { getCallNumber(): number { return this.callNumber; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts index 62d01077c..25e4fdc03 100644 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ b/packages/grpc-js/src/max-message-size-filter.ts @@ -29,7 +29,7 @@ export class MaxMessageSizeFilter extends BaseFilter implements Filter { private maxSendMessageSize: number = DEFAULT_MAX_SEND_MESSAGE_LENGTH; private maxReceiveMessageSize: number = DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH; constructor( - private readonly options: ChannelOptions + options: ChannelOptions ) { super(); if ('grpc.max_send_message_length' in options) { diff --git a/packages/grpc-js/src/metadata.ts b/packages/grpc-js/src/metadata.ts index 0dddd9465..bfef51b0d 100644 --- a/packages/grpc-js/src/metadata.ts +++ b/packages/grpc-js/src/metadata.ts @@ -229,11 +229,6 @@ export class Metadata { return result; } - // For compatibility with the other Metadata implementation - private _getCoreRepresentation() { - return this.internalRepr; - } - /** * This modifies the behavior of JSON.stringify to show an object * representation of the metadata map. diff --git a/packages/grpc-js/src/object-stream.ts b/packages/grpc-js/src/object-stream.ts index 22ab8a41f..9289b9d84 100644 --- a/packages/grpc-js/src/object-stream.ts +++ b/packages/grpc-js/src/object-stream.ts @@ -15,7 +15,7 @@ * */ -import { Duplex, Readable, Writable } from 'stream'; +import { Readable, Writable } from 'stream'; import { EmitterAugmentation1 } from './events'; /* eslint-disable @typescript-eslint/no-explicit-any */ diff --git a/packages/grpc-js/src/resolver-ip.ts b/packages/grpc-js/src/resolver-ip.ts index efb0b8dcb..0704131e1 100644 --- a/packages/grpc-js/src/resolver-ip.ts +++ b/packages/grpc-js/src/resolver-ip.ts @@ -42,7 +42,7 @@ class IpResolver implements Resolver { private addresses: SubchannelAddress[] = []; private error: StatusObject | null = null; constructor( - private target: GrpcUri, + target: GrpcUri, private listener: ResolverListener, channelOptions: ChannelOptions ) { diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index f29fb7fd7..683fed5bc 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -18,7 +18,7 @@ import { CallCredentials } from "./call-credentials"; import { Call, CallStreamOptions, InterceptingListener, MessageContext, StatusObject } from "./call-interface"; import { LogVerbosity, Propagate, Status } from "./constants"; -import { Deadline, deadlineToString, getDeadlineTimeoutString, getRelativeTimeout, minDeadline } from "./deadline"; +import { Deadline, deadlineToString, getRelativeTimeout, minDeadline } from "./deadline"; import { FilterStack, FilterStackFactory } from "./filter-stack"; import { InternalChannel } from "./internal-channel"; import { Metadata } from "./metadata"; @@ -276,4 +276,4 @@ export class ResolvingCall implements Call { getCallNumber(): number { return this.callNumber; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/resolving-load-balancer.ts b/packages/grpc-js/src/resolving-load-balancer.ts index a39606f2c..5194bef46 100644 --- a/packages/grpc-js/src/resolving-load-balancer.ts +++ b/packages/grpc-js/src/resolving-load-balancer.ts @@ -36,7 +36,6 @@ import { SubchannelAddress } from './subchannel-address'; import { GrpcUri, uriToString } from './uri-parser'; import { ChildLoadBalancerHandler } from './load-balancer-child-handler'; import { ChannelOptions } from './channel-options'; -import { PickFirstLoadBalancingConfig } from './load-balancer-pick-first'; const TRACER_NAME = 'resolving_load_balancer'; @@ -44,8 +43,6 @@ function trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); } -const DEFAULT_LOAD_BALANCER_NAME = 'pick_first'; - function getDefaultConfigSelector( serviceConfig: ServiceConfig | null ): ConfigSelector { @@ -137,7 +134,7 @@ export class ResolvingLoadBalancer implements LoadBalancer { constructor( private readonly target: GrpcUri, private readonly channelControlHelper: ChannelControlHelper, - private readonly channelOptions: ChannelOptions, + channelOptions: ChannelOptions, private readonly onSuccessfulResolution: ResolutionCallback, private readonly onFailedResolution: ResolutionFailureCallback ) { diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index 48186bc29..fc840bdf9 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -268,6 +268,9 @@ export class ServerDuplexStreamImpl implements ServerDuplexStream { cancelled: boolean; + /* This field appears to be unsued, but it is actually used in _final, which is assiged from + * ServerWritableStreamImpl.prototype._final below. */ + // @ts-ignore noUnusedLocals private trailingMetadata: Metadata; constructor( @@ -419,7 +422,7 @@ export class Http2ServerCallStream< constructor( private stream: http2.ServerHttp2Stream, private handler: Handler, - private options: ChannelOptions + options: ChannelOptions ) { super(); @@ -720,7 +723,7 @@ export class Http2ServerCallStream< [GRPC_MESSAGE_HEADER]: encodeURI(statusObj.details), ...statusObj.metadata?.toHttp2Headers(), }; - + this.stream.sendTrailers(trailersToSend); this.statusSent = true; }); diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index d19186a75..1a01b30dc 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -141,10 +141,6 @@ interface ChannelzSessionInfo { lastMessageReceivedTimestamp: Date | null; } -interface ChannelzListenerInfo { - ref: SocketRef; -} - export class Server { private http2ServerList: { server: (http2.Http2Server | http2.Http2SecureServer), channelzRef: SocketRef }[] = []; @@ -242,7 +238,7 @@ export class Server { private trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, '(' + this.channelzRef.id + ') ' + text); } - + addProtoService(): never { throw new Error('Not implemented. Use addService() instead'); @@ -743,7 +739,7 @@ export class Server { /** * Get the channelz reference object for this server. The returned value is * garbage if channelz is disabled for this server. - * @returns + * @returns */ getChannelzRef() { return this.channelzRef; @@ -792,14 +788,14 @@ export class Server { return handler } - + private _respondWithError>( - err: T, - stream: http2.ServerHttp2Stream, + err: T, + stream: http2.ServerHttp2Stream, channelzSessionInfo: ChannelzSessionInfo | null = null ) { const call = new Http2ServerCallStream(stream, null!, this.options); - + if (err.code === undefined) { err.code = Status.INTERNAL; } @@ -814,7 +810,7 @@ export class Server { private _channelzHandler(stream: http2.ServerHttp2Stream, headers: http2.IncomingHttpHeaders) { const channelzSessionInfo = this.sessions.get(stream.session as http2.ServerHttp2Session); - + this.callTracker.addCallStarted(); channelzSessionInfo?.streamTracker.addCallStarted(); @@ -834,9 +830,9 @@ export class Server { }, stream, channelzSessionInfo) return } - + const call = new Http2ServerCallStream(stream, handler, this.options); - + call.once('callEnd', (code: Status) => { if (code === Status.OK) { this.callTracker.addCallSucceeded(); @@ -844,7 +840,7 @@ export class Server { this.callTracker.addCallFailed(); } }); - + if (channelzSessionInfo) { call.once('streamEnd', (success: boolean) => { if (success) { @@ -954,8 +950,8 @@ export class Server { } this.serverAddressString = serverAddressString - const handler = this.channelzEnabled - ? this._channelzHandler + const handler = this.channelzEnabled + ? this._channelzHandler : this._streamHandler http2Server.on('stream', handler.bind(this)) diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index 969282e19..f9c24f6bd 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -23,19 +23,11 @@ import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; import * as logging from './logging'; import { LogVerbosity } from './constants'; -import { ServerSurfaceCall } from './server-call'; -import { Deadline } from './deadline'; import { InterceptingListener, MessageContext, StatusObject, WriteCallback } from './call-interface'; import { CallEventTracker, Transport } from './transport'; const TRACER_NAME = 'subchannel_call'; -const { - HTTP2_HEADER_STATUS, - HTTP2_HEADER_CONTENT_TYPE, - NGHTTP2_CANCEL, -} = http2.constants; - /** * https://nodejs.org/api/errors.html#errors_class_systemerror */ diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 2f89d8f28..36176d643 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -46,10 +46,6 @@ const { HTTP2_HEADER_USER_AGENT, } = http2.constants; -/* setInterval and setTimeout only accept signed 32 bit integers. JS doesn't - * have a constant for the max signed 32 bit integer, so this is a simple way - * to calculate it */ -const KEEPALIVE_MAX_TIME_MS = ~(1 << 31); const KEEPALIVE_TIMEOUT_MS = 20000; export interface CallEventTracker { @@ -108,11 +104,6 @@ class Http2Transport implements Transport { // Channelz info private channelzRef: SocketRef; private readonly channelzEnabled: boolean = true; - /** - * Name of the remote server, if it is not the same as the subchannel - * address, i.e. if connecting through an HTTP CONNECT proxy. - */ - private remoteName: string | null = null; private streamTracker = new ChannelzCallTracker(); private keepalivesSent = 0; private messagesSent = 0; @@ -123,7 +114,12 @@ class Http2Transport implements Transport { constructor( private session: http2.ClientHttp2Session, subchannelAddress: SubchannelAddress, - options: ChannelOptions + options: ChannelOptions, + /** + * Name of the remote server, if it is not the same as the subchannel + * address, i.e. if connecting through an HTTP CONNECT proxy. + */ + private remoteName: string | null ) { // Build user-agent string. this.userAgent = [ @@ -133,7 +129,7 @@ class Http2Transport implements Transport { ] .filter((e) => e) .join(' '); // remove falsey values first - + if ('grpc.keepalive_time_ms' in options) { this.keepaliveTimeMs = options['grpc.keepalive_time_ms']!; } @@ -271,7 +267,7 @@ class Http2Transport implements Transport { * @param tooManyPings If true, this was triggered by a GOAWAY with data * indicating that the session was closed becaues the client sent too many * pings. - * @returns + * @returns */ private reportDisconnectToOwner(tooManyPings: boolean) { if (this.disconnectHandled) { @@ -405,11 +401,11 @@ class Http2Transport implements Transport { this.session.state.remoteWindowSize ); this.internalsTrace( - 'session.closed=' + - this.session.closed + - ' session.destroyed=' + - this.session.destroyed + - ' session.socket.destroyed=' + + 'session.closed=' + + this.session.closed + + ' session.destroyed=' + + this.session.destroyed + + ' session.socket.destroyed=' + this.session.socket.destroyed); let eventTracker: CallEventTracker; let call: Http2SubchannelCall; @@ -565,12 +561,12 @@ export class Http2SubchannelConnector implements SubchannelConnector { } }; } - + connectionOptions = { ...connectionOptions, ...address, }; - + /* http2.connect uses the options here: * https://github.com/nodejs/node/blob/70c32a6d190e2b5d7b9ff9d5b6a459d14e8b7d59/lib/internal/http2/core.js#L3028-L3036 * The spread operator overides earlier values with later ones, so any port @@ -596,7 +592,7 @@ export class Http2SubchannelConnector implements SubchannelConnector { session.unref(); session.once('connect', () => { session.removeAllListeners(); - resolve(new Http2Transport(session, address, options)); + resolve(new Http2Transport(session, address, options, remoteName)); this.session = null; }); session.once('close', () => { @@ -666,4 +662,4 @@ export class Http2SubchannelConnector implements SubchannelConnector { this.session?.close(); this.session = null; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/test/test-call-propagation.ts b/packages/grpc-js/test/test-call-propagation.ts index 3ce57be17..4a2619f1f 100644 --- a/packages/grpc-js/test/test-call-propagation.ts +++ b/packages/grpc-js/test/test-call-propagation.ts @@ -165,7 +165,6 @@ describe('Call propagation', () => { describe('Deadlines', () => { it('should work with unary requests', (done) => { done = multiDone(done, 2); - let call: grpc.ClientUnaryCall; proxyServer.addService(Client.service, { unary: (parent: grpc.ServerUnaryCall, callback: grpc.sendUnaryData) => { client.unary(parent.request, {parent: parent, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { @@ -178,7 +177,7 @@ describe('Call propagation', () => { }); const deadline = new Date(); deadline.setMilliseconds(deadline.getMilliseconds() + 100); - call = proxyClient.unary({}, {deadline}, (error: grpc.ServiceError, value: unknown) => { + proxyClient.unary({}, {deadline}, (error: grpc.ServiceError, value: unknown) => { assert(error); assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); done(); @@ -186,7 +185,6 @@ describe('Call propagation', () => { }); it('Should work with client streaming requests', (done) => { done = multiDone(done, 2); - let call: grpc.ClientWritableStream; proxyServer.addService(Client.service, { clientStream: (parent: grpc.ServerReadableStream, callback: grpc.sendUnaryData) => { client.clientStream({parent: parent, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { @@ -199,7 +197,7 @@ describe('Call propagation', () => { }); const deadline = new Date(); deadline.setMilliseconds(deadline.getMilliseconds() + 100); - call = proxyClient.clientStream({deadline, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { + proxyClient.clientStream({deadline, propagate_flags: grpc.propagate.DEADLINE}, (error: grpc.ServiceError, value: unknown) => { assert(error); assert.strictEqual(error.code, grpc.status.DEADLINE_EXCEEDED); done(); @@ -250,4 +248,4 @@ describe('Call propagation', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-channel-credentials.ts b/packages/grpc-js/test/test-channel-credentials.ts index 2b537ac97..62e4c19a1 100644 --- a/packages/grpc-js/test/test-channel-credentials.ts +++ b/packages/grpc-js/test/test-channel-credentials.ts @@ -19,14 +19,11 @@ import * as assert from 'assert'; import * as fs from 'fs'; import * as path from 'path'; import { promisify } from 'util'; -import * as protoLoader from '@grpc/proto-loader'; import { CallCredentials } from '../src/call-credentials'; import { ChannelCredentials } from '../src/channel-credentials'; import * as grpc from '../src'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; -import { TestServiceClient, TestServiceHandlers } from './generated/TestService'; -import { ProtoGrpcType as TestServiceGrpcType } from './generated/test_service'; import { assert2, loadProtoFile, mockFunction } from './common'; import { sendUnaryData, ServerUnaryCall, ServiceError } from '../src'; @@ -171,7 +168,7 @@ describe('ChannelCredentials usage', () => { callback(null, call.request); }, }); - + server.bindAsync( 'localhost:0', serverCreds, @@ -209,4 +206,4 @@ describe('ChannelCredentials usage', () => { })); assert2.afterMustCallsSatisfied(done); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-channelz.ts b/packages/grpc-js/test/test-channelz.ts index f14145c37..26c15d47d 100644 --- a/packages/grpc-js/test/test-channelz.ts +++ b/packages/grpc-js/test/test-channelz.ts @@ -21,8 +21,6 @@ import * as grpc from '../src'; import { ProtoGrpcType } from '../src/generated/channelz' import { ChannelzClient } from '../src/generated/grpc/channelz/v1/Channelz'; -import { Channel__Output } from '../src/generated/grpc/channelz/v1/Channel'; -import { Server__Output } from '../src/generated/grpc/channelz/v1/Server'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; import { loadProtoFile } from './common'; @@ -318,4 +316,4 @@ describe('Disabling channelz', () => { done(); }); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-deadline.ts b/packages/grpc-js/test/test-deadline.ts index bb6b3ba9b..d117fc52a 100644 --- a/packages/grpc-js/test/test-deadline.ts +++ b/packages/grpc-js/test/test-deadline.ts @@ -19,14 +19,10 @@ import * as assert from 'assert'; import * as grpc from '../src'; import { experimental } from '../src'; -import { ServerCredentials } from '../src'; import { ServiceClient, ServiceClientConstructor } from '../src/make-client'; import { loadProtoFile } from './common'; import ServiceConfig = experimental.ServiceConfig; -const clientInsecureCreds = grpc.credentials.createInsecure(); -const serverInsecureCreds = ServerCredentials.createInsecure(); - const TIMEOUT_SERVICE_CONFIG: ServiceConfig = { loadBalancingConfig: [], methodConfig: [{ @@ -44,7 +40,7 @@ describe('Client with configured timeout', () => { let server: grpc.Server; let Client: ServiceClientConstructor; let client: ServiceClient; - + before(done => { Client = loadProtoFile(__dirname + '/fixtures/test_service.proto').TestService as ServiceClientConstructor; server = new grpc.Server(); @@ -87,4 +83,4 @@ describe('Client with configured timeout', () => { done(); }); }); -}); \ No newline at end of file +}); diff --git a/packages/grpc-js/test/test-outlier-detection.ts b/packages/grpc-js/test/test-outlier-detection.ts index d51ccf3fd..a91350fd7 100644 --- a/packages/grpc-js/test/test-outlier-detection.ts +++ b/packages/grpc-js/test/test-outlier-detection.ts @@ -20,7 +20,6 @@ import * as path from 'path'; import * as grpc from '../src'; import { loadProtoFile } from './common'; import { OutlierDetectionLoadBalancingConfig } from '../src/load-balancer-outlier-detection' -import { ServiceClient } from '../src/make-client'; function multiDone(done: Mocha.Done, target: number) { let count = 0; diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index c67ebc4d6..d67307f61 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -686,7 +686,7 @@ describe('Compressed requests', () => { }, ServerStream(call) { - const { metadata, request } = call; + const { request } = call; for (let i = 0; i < 5; i++) { call.write({ count: request.message.length }); @@ -908,7 +908,7 @@ describe('Compressed requests', () => { done(); }) }) - + /* As of Node 16, Writable and Duplex streams validate the encoding * argument to write, and the flags values we are passing there are not * valid. We don't currently have an alternative way to pass that flag diff --git a/packages/grpc-js/tsconfig.json b/packages/grpc-js/tsconfig.json index 310b633c7..5f955a982 100644 --- a/packages/grpc-js/tsconfig.json +++ b/packages/grpc-js/tsconfig.json @@ -7,7 +7,8 @@ "module": "commonjs", "resolveJsonModule": true, "incremental": true, - "types": ["mocha"] + "types": ["mocha"], + "noUnusedLocals": true }, "include": [ "src/**/*.ts", From 493cbaaf45cf6bd47a1b877253c47e9148551058 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Wed, 12 Jul 2023 15:23:34 -0700 Subject: [PATCH 1888/1899] grpc-js: Increment version to 1.8.18 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index d4b822600..a001e617f 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.17", + "version": "1.8.18", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", From 2e9060385c6578a8e69687c917015b9eaf475f25 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 24 Jul 2023 11:20:00 -0700 Subject: [PATCH 1889/1899] grpc-js: Fix keepalive ping timing after inactivity --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/transport.ts | 77 +++++++++++++++++++++---------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index a001e617f..33096012c 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.18", + "version": "1.8.19", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 36176d643..a3408d836 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -81,7 +81,12 @@ class Http2Transport implements Transport { /** * Timer reference for timeout that indicates when to send the next ping */ - private keepaliveIntervalId: NodeJS.Timer; + private keepaliveTimerId: NodeJS.Timer | null = null; + /** + * Indicates that the keepalive timer ran out while there were no active + * calls, and a ping should be sent the next time a call starts. + */ + private pendingSendKeepalivePing = false; /** * Timer reference tracking when the most recent ping will be considered lost */ @@ -142,10 +147,8 @@ class Http2Transport implements Transport { } else { this.keepaliveWithoutCalls = false; } - this.keepaliveIntervalId = setTimeout(() => {}, 0); - clearTimeout(this.keepaliveIntervalId); if (this.keepaliveWithoutCalls) { - this.startKeepalivePings(); + this.maybeStartKeepalivePingTimer(); } this.subchannelAddressString = subchannelAddressToString(subchannelAddress); @@ -295,6 +298,14 @@ class Http2Transport implements Transport { this.disconnectListeners.push(listener); } + private clearKeepaliveTimer() { + if (!this.keepaliveTimerId) { + return; + } + clearTimeout(this.keepaliveTimerId); + this.keepaliveTimerId = null; + } + private clearKeepaliveTimeout() { if (!this.keepaliveTimeoutId) { return; @@ -303,7 +314,16 @@ class Http2Transport implements Transport { this.keepaliveTimeoutId = null; } - private sendPing() { + private canSendPing() { + return this.keepaliveTimeMs > 0 && (this.keepaliveWithoutCalls || this.activeCalls.size > 0); + } + + private maybeSendPing() { + this.clearKeepaliveTimer(); + if (!this.canSendPing()) { + this.pendingSendKeepalivePing = true; + return; + } if (this.channelzEnabled) { this.keepalivesSent += 1; } @@ -320,6 +340,7 @@ class Http2Transport implements Transport { (err: Error | null, duration: number, payload: Buffer) => { this.keepaliveTrace('Received ping response'); this.clearKeepaliveTimeout(); + this.maybeStartKeepalivePingTimer(); } ); } catch (e) { @@ -329,25 +350,34 @@ class Http2Transport implements Transport { } } - private startKeepalivePings() { - if (this.keepaliveTimeMs < 0) { + /** + * Starts the keepalive ping timer if appropriate. If the timer already ran + * out while there were no active requests, instead send a ping immediately. + * If the ping timer is already running or a ping is currently in flight, + * instead do nothing and wait for them to resolve. + */ + private maybeStartKeepalivePingTimer() { + if (!this.canSendPing()) { return; } - this.keepaliveIntervalId = setInterval(() => { - this.sendPing(); - }, this.keepaliveTimeMs); - this.keepaliveIntervalId.unref?.(); - /* Don't send a ping immediately because whatever caused us to start - * sending pings should also involve some network activity. */ + if (this.pendingSendKeepalivePing) { + this.pendingSendKeepalivePing = false; + this.maybeSendPing(); + } else if (!this.keepaliveTimerId && !this.keepaliveTimeoutId) { + this.keepaliveTrace('Starting keepalive timer for ' + this.keepaliveTimeMs + 'ms'); + this.keepaliveTimerId = setTimeout(() => { + this.maybeSendPing(); + }, this.keepaliveTimeMs).unref?.(); + } + /* Otherwise, there is already either a keepalive timer or a ping pending, + * wait for those to resolve. */ } - /** - * Stop keepalive pings when terminating a connection. This discards the - * outstanding ping timeout, so it should not be called if the same - * connection will still be used. - */ private stopKeepalivePings() { - clearInterval(this.keepaliveIntervalId); + if (this.keepaliveTimerId) { + clearTimeout(this.keepaliveTimerId); + this.keepaliveTimerId = null; + } this.clearKeepaliveTimeout(); } @@ -355,20 +385,17 @@ class Http2Transport implements Transport { this.activeCalls.delete(call); if (this.activeCalls.size === 0) { this.session.unref(); - if (!this.keepaliveWithoutCalls) { - this.stopKeepalivePings(); - } } } private addActiveCall(call: Http2SubchannelCall) { - if (this.activeCalls.size === 0) { + this.activeCalls.add(call); + if (this.activeCalls.size === 1) { this.session.ref(); if (!this.keepaliveWithoutCalls) { - this.startKeepalivePings(); + this.maybeStartKeepalivePingTimer(); } } - this.activeCalls.add(call); } createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): Http2SubchannelCall { From 42a02749eb4a067dbdb84fc111ab10ef09bc2ec4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 24 Jul 2023 13:08:55 -0700 Subject: [PATCH 1890/1899] grpc-js: Fix compilation error from new @types/node version --- packages/grpc-js/src/server-call.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index fc840bdf9..ff0a10336 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -954,8 +954,8 @@ export class Http2ServerCallStream< } getPeer(): string { - const socket = this.stream.session.socket; - if (socket.remoteAddress) { + const socket = this.stream.session?.socket; + if (socket?.remoteAddress) { if (socket.remotePort) { return `${socket.remoteAddress}:${socket.remotePort}`; } else { From 6d979565492916de8106b6d7f6bfbc1f1fb63cf4 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Tue, 25 Jul 2023 09:36:58 -0700 Subject: [PATCH 1891/1899] grpc-js: Fix a crash when grpc.keepalive_permit_without_calls is set --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/transport.ts | 23 +++++++++++++---------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 33096012c..93b2f7826 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.19", + "version": "1.8.20", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index a3408d836..4f26e96e2 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -126,6 +126,14 @@ class Http2Transport implements Transport { */ private remoteName: string | null ) { + /* Populate subchannelAddressString and channelzRef before doing anything + * else, because they are used in the trace methods. */ + this.subchannelAddressString = subchannelAddressToString(subchannelAddress); + + if (options['grpc.enable_channelz'] === 0) { + this.channelzEnabled = false; + } + this.channelzRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); // Build user-agent string. this.userAgent = [ options['grpc.primary_user_agent'], @@ -147,16 +155,6 @@ class Http2Transport implements Transport { } else { this.keepaliveWithoutCalls = false; } - if (this.keepaliveWithoutCalls) { - this.maybeStartKeepalivePingTimer(); - } - - this.subchannelAddressString = subchannelAddressToString(subchannelAddress); - - if (options['grpc.enable_channelz'] === 0) { - this.channelzEnabled = false; - } - this.channelzRef = registerChannelzSocket(this.subchannelAddressString, () => this.getChannelzInfo(), this.channelzEnabled); session.once('close', () => { this.trace('session closed'); @@ -205,6 +203,11 @@ class Http2Transport implements Transport { ); }); } + /* Start the keepalive timer last, because this can trigger trace logs, + * which should only happen after everything else is set up. */ + if (this.keepaliveWithoutCalls) { + this.maybeStartKeepalivePingTimer(); + } } private getChannelzInfo(): SocketInfo { From 4e111e77921096b1190873298f8f44cab1bd47a0 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 28 Jul 2023 14:21:19 -0700 Subject: [PATCH 1892/1899] grpc-js: Fix propagation of UNIMPLEMENTED error messages --- packages/grpc-js/package.json | 2 +- packages/grpc-js/src/server.ts | 38 +++++------- packages/grpc-js/test/test-server.ts | 90 ++++++++++++++++++++++++++++ 3 files changed, 106 insertions(+), 24 deletions(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 93b2f7826..29c2a00ee 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.20", + "version": "1.8.21", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js", diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 1a01b30dc..9853ddf56 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -61,7 +61,6 @@ import { import { parseUri } from './uri-parser'; import { ChannelzCallTracker, ChannelzChildrenTracker, ChannelzTrace, registerChannelzServer, registerChannelzSocket, ServerInfo, ServerRef, SocketInfo, SocketRef, TlsInfo, unregisterChannelzRef } from './channelz'; import { CipherNameAndProtocol, TLSSocket } from 'tls'; -import { getErrorCode, getErrorMessage } from './error'; const UNLIMITED_CONNECTION_AGE_MS = ~(1<<31); const KEEPALIVE_MAX_TIME_MS = ~(1<<31); @@ -765,9 +764,7 @@ export class Server { return true } - private _retrieveHandler(headers: http2.IncomingHttpHeaders): Handler { - const path = headers[HTTP2_HEADER_PATH] as string - + private _retrieveHandler(path: string): Handler | null { this.trace( 'Received call to method ' + path + @@ -783,7 +780,7 @@ export class Server { path + '. Sending UNIMPLEMENTED status.' ); - throw getUnimplementedStatusResponse(path); + return null; } return handler @@ -820,15 +817,12 @@ export class Server { return } - let handler: Handler - try { - handler = this._retrieveHandler(headers) - } catch (err) { - this._respondWithError({ - details: getErrorMessage(err), - code: getErrorCode(err) ?? undefined - }, stream, channelzSessionInfo) - return + const path = headers[HTTP2_HEADER_PATH] as string; + + const handler = this._retrieveHandler(path); + if (!handler) { + this._respondWithError(getUnimplementedStatusResponse(path), stream, channelzSessionInfo); + return; } const call = new Http2ServerCallStream(stream, handler, this.options); @@ -875,15 +869,13 @@ export class Server { return } - let handler: Handler - try { - handler = this._retrieveHandler(headers) - } catch (err) { - this._respondWithError({ - details: getErrorMessage(err), - code: getErrorCode(err) ?? undefined - }, stream, null) - return + + const path = headers[HTTP2_HEADER_PATH] as string; + + const handler = this._retrieveHandler(path); + if (!handler) { + this._respondWithError(getUnimplementedStatusResponse(path), stream, null); + return; } const call = new Http2ServerCallStream(stream, handler, this.options) diff --git a/packages/grpc-js/test/test-server.ts b/packages/grpc-js/test/test-server.ts index d67307f61..68890df55 100644 --- a/packages/grpc-js/test/test-server.ts +++ b/packages/grpc-js/test/test-server.ts @@ -408,6 +408,7 @@ describe('Server', () => { (error: ServiceError, response: any) => { assert(error); assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + assert.match(error.details, /does not implement the method.*Div/); done(); } ); @@ -417,6 +418,7 @@ describe('Server', () => { const call = client.sum((error: ServiceError, response: any) => { assert(error); assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + assert.match(error.details, /does not implement the method.*Sum/); done(); }); @@ -433,6 +435,7 @@ describe('Server', () => { call.on('error', (err: ServiceError) => { assert(err); assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + assert.match(err.details, /does not implement the method.*Fib/); done(); }); }); @@ -447,6 +450,93 @@ describe('Server', () => { call.on('error', (err: ServiceError) => { assert(err); assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + assert.match(err.details, /does not implement the method.*DivMany/); + done(); + }); + + call.end(); + }); + }); + + describe('Unregistered service', () => { + let server: Server; + let client: ServiceClient; + + const mathProtoFile = path.join(__dirname, 'fixtures', 'math.proto'); + const mathClient = (loadProtoFile(mathProtoFile).math as any).Math; + + before(done => { + server = new Server(); + // Don't register a service at all + server.bindAsync( + 'localhost:0', + ServerCredentials.createInsecure(), + (err, port) => { + assert.ifError(err); + client = new mathClient( + `localhost:${port}`, + grpc.credentials.createInsecure() + ); + server.start(); + done(); + } + ); + }); + + after(done => { + client.close(); + server.tryShutdown(done); + }); + + it('should respond to a unary call with UNIMPLEMENTED', done => { + client.div( + { divisor: 4, dividend: 3 }, + (error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + assert.match(error.details, /does not implement the method.*Div/); + done(); + } + ); + }); + + it('should respond to a client stream with UNIMPLEMENTED', done => { + const call = client.sum((error: ServiceError, response: any) => { + assert(error); + assert.strictEqual(error.code, grpc.status.UNIMPLEMENTED); + assert.match(error.details, /does not implement the method.*Sum/); + done(); + }); + + call.end(); + }); + + it('should respond to a server stream with UNIMPLEMENTED', done => { + const call = client.fib({ limit: 5 }); + + call.on('data', (value: any) => { + assert.fail('No messages expected'); + }); + + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + assert.match(err.details, /does not implement the method.*Fib/); + done(); + }); + }); + + it('should respond to a bidi call with UNIMPLEMENTED', done => { + const call = client.divMany(); + + call.on('data', (value: any) => { + assert.fail('No messages expected'); + }); + + call.on('error', (err: ServiceError) => { + assert(err); + assert.strictEqual(err.code, grpc.status.UNIMPLEMENTED); + assert.match(err.details, /does not implement the method.*DivMany/); done(); }); From ec687f6fb108a40cd7ee99a0caa947d4fbb49062 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 14 Aug 2023 13:58:03 -0700 Subject: [PATCH 1893/1899] grpc-js: Switch Timer type to Timeout (1.8.x) --- packages/grpc-js/src/backoff-timeout.ts | 2 +- packages/grpc-js/src/internal-channel.ts | 2 +- packages/grpc-js/src/load-balancer-outlier-detection.ts | 2 +- packages/grpc-js/src/resolver-dns.ts | 2 +- packages/grpc-js/src/resolving-call.ts | 2 +- packages/grpc-js/src/retrying-call.ts | 6 +++--- packages/grpc-js/src/server-call.ts | 2 +- packages/grpc-js/src/server.ts | 6 +++--- packages/grpc-js/src/subchannel-pool.ts | 2 +- packages/grpc-js/src/transport.ts | 4 ++-- 10 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/grpc-js/src/backoff-timeout.ts b/packages/grpc-js/src/backoff-timeout.ts index f523e259a..3ffd26064 100644 --- a/packages/grpc-js/src/backoff-timeout.ts +++ b/packages/grpc-js/src/backoff-timeout.ts @@ -63,7 +63,7 @@ export class BackoffTimeout { * to an object representing a timer that has ended, but it can still be * interacted with without error. */ - private timerId: NodeJS.Timer; + private timerId: NodeJS.Timeout; /** * Indicates whether the timer is currently running. */ diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 3d2624895..38646a0cd 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -131,7 +131,7 @@ export class InternalChannel { * the invariant is that callRefTimer is reffed if and only if pickQueue * is non-empty. */ - private callRefTimer: NodeJS.Timer; + private callRefTimer: NodeJS.Timeout; private configSelector: ConfigSelector | null = null; /** * This is the error from the name resolver if it failed most recently. It diff --git a/packages/grpc-js/src/load-balancer-outlier-detection.ts b/packages/grpc-js/src/load-balancer-outlier-detection.ts index 7297000d0..2cba9d14a 100644 --- a/packages/grpc-js/src/load-balancer-outlier-detection.ts +++ b/packages/grpc-js/src/load-balancer-outlier-detection.ts @@ -367,7 +367,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer { private childBalancer: ChildLoadBalancerHandler; private addressMap: Map = new Map(); private latestConfig: OutlierDetectionLoadBalancingConfig | null = null; - private ejectionTimer: NodeJS.Timer; + private ejectionTimer: NodeJS.Timeout; private timerStartTime: Date | null = null; constructor(channelControlHelper: ChannelControlHelper) { diff --git a/packages/grpc-js/src/resolver-dns.ts b/packages/grpc-js/src/resolver-dns.ts index b20b7a543..775a25c36 100644 --- a/packages/grpc-js/src/resolver-dns.ts +++ b/packages/grpc-js/src/resolver-dns.ts @@ -96,7 +96,7 @@ class DnsResolver implements Resolver { private defaultResolutionError: StatusObject; private backoff: BackoffTimeout; private continueResolving = false; - private nextResolutionTimer: NodeJS.Timer; + private nextResolutionTimer: NodeJS.Timeout; private isNextResolutionTimerRunning = false; private isServiceConfigEnabled = true; constructor( diff --git a/packages/grpc-js/src/resolving-call.ts b/packages/grpc-js/src/resolving-call.ts index 683fed5bc..5dbe83cd9 100644 --- a/packages/grpc-js/src/resolving-call.ts +++ b/packages/grpc-js/src/resolving-call.ts @@ -41,7 +41,7 @@ export class ResolvingCall implements Call { private deadline: Deadline; private host: string; private statusWatchers: ((status: StatusObject) => void)[] = []; - private deadlineTimer: NodeJS.Timer = setTimeout(() => {}, 0); + private deadlineTimer: NodeJS.Timeout = setTimeout(() => {}, 0); private filterStack: FilterStack | null = null; constructor( diff --git a/packages/grpc-js/src/retrying-call.ts b/packages/grpc-js/src/retrying-call.ts index 5ae585b9e..bf15c9143 100644 --- a/packages/grpc-js/src/retrying-call.ts +++ b/packages/grpc-js/src/retrying-call.ts @@ -169,7 +169,7 @@ export class RetryingCall implements Call { * Number of attempts so far */ private attempts: number = 0; - private hedgingTimer: NodeJS.Timer | null = null; + private hedgingTimer: NodeJS.Timeout | null = null; private committedCallIndex: number | null = null; private initialRetryBackoffSec = 0; private nextRetryBackoffSec = 0; @@ -625,7 +625,7 @@ export class RetryingCall implements Call { return; } const call = this.underlyingCalls[this.committedCallIndex]; - bufferEntry.callback = context.callback; + bufferEntry.callback = context.callback; if (call.state === 'ACTIVE' && call.nextMessageToSend === messageIndex) { call.call.sendMessageWithContext({ callback: (error) => { @@ -668,4 +668,4 @@ export class RetryingCall implements Call { getHost(): string { return this.host; } -} \ No newline at end of file +} diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index ff0a10336..be807b959 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -407,7 +407,7 @@ export class Http2ServerCallStream< ResponseType > extends EventEmitter { cancelled = false; - deadlineTimer: NodeJS.Timer | null = null; + deadlineTimer: NodeJS.Timeout | null = null; private statusSent = false; private deadline: Deadline = Infinity; private wantTrailers = false; diff --git a/packages/grpc-js/src/server.ts b/packages/grpc-js/src/server.ts index 9853ddf56..1b481bbf9 100644 --- a/packages/grpc-js/src/server.ts +++ b/packages/grpc-js/src/server.ts @@ -971,8 +971,8 @@ export class Server { this.channelzTrace.addTrace('CT_INFO', 'Connection established by client ' + clientAddress); this.sessionChildrenTracker.refChild(channelzRef); } - let connectionAgeTimer: NodeJS.Timer | null = null; - let connectionAgeGraceTimer: NodeJS.Timer | null = null; + let connectionAgeTimer: NodeJS.Timeout | null = null; + let connectionAgeGraceTimer: NodeJS.Timeout | null = null; let sessionClosedByServer = false; if (this.maxConnectionAgeMs !== UNLIMITED_CONNECTION_AGE_MS) { // Apply a random jitter within a +/-10% range @@ -1000,7 +1000,7 @@ export class Server { } }, this.maxConnectionAgeMs + jitter).unref?.(); } - const keeapliveTimeTimer: NodeJS.Timer | null = setInterval(() => { + const keeapliveTimeTimer: NodeJS.Timeout | null = setInterval(() => { const timeoutTImer = setTimeout(() => { sessionClosedByServer = true; if (this.channelzEnabled) { diff --git a/packages/grpc-js/src/subchannel-pool.ts b/packages/grpc-js/src/subchannel-pool.ts index bbfbea02b..f9400bede 100644 --- a/packages/grpc-js/src/subchannel-pool.ts +++ b/packages/grpc-js/src/subchannel-pool.ts @@ -45,7 +45,7 @@ export class SubchannelPool { /** * A timer of a task performing a periodic subchannel cleanup. */ - private cleanupTimer: NodeJS.Timer | null = null; + private cleanupTimer: NodeJS.Timeout | null = null; /** * A pool of subchannels use for making connections. Subchannels with the diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index 4f26e96e2..a9da5db4d 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -81,7 +81,7 @@ class Http2Transport implements Transport { /** * Timer reference for timeout that indicates when to send the next ping */ - private keepaliveTimerId: NodeJS.Timer | null = null; + private keepaliveTimerId: NodeJS.Timeout | null = null; /** * Indicates that the keepalive timer ran out while there were no active * calls, and a ping should be sent the next time a call starts. @@ -90,7 +90,7 @@ class Http2Transport implements Transport { /** * Timer reference tracking when the most recent ping will be considered lost */ - private keepaliveTimeoutId: NodeJS.Timer | null = null; + private keepaliveTimeoutId: NodeJS.Timeout | null = null; /** * Indicates whether keepalive pings should be sent without any active calls */ From c2434173c111db636e3de4b8d71d057a67f398ae Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Thu, 4 Jan 2024 13:11:54 -0800 Subject: [PATCH 1894/1899] Merge pull request #2635 from XuanWang-Amos/psm-interop-shared-build buildscripts: Use the Kokoro shared install lib from the new repo --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 2 +- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index 729fb9293..ed7c77fe2 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc-node" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/java-server:558b5b0bfac8e21755c223063274a779b3898afe" readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index fc74718f2..9344d054b 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -17,7 +17,7 @@ set -eo pipefail # Constants readonly GITHUB_REPOSITORY_NAME="grpc-node" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/grpc/${TEST_DRIVER_BRANCH:-master}/tools/internal_ci/linux/grpc_xds_k8s_install_test_driver.sh" +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" From f38966aab5cd7b4c94cb6f3e6a518375f11f5e52 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 8 Apr 2024 17:47:26 -0700 Subject: [PATCH 1895/1899] Merge pull request #2712 from sergiitk/psm-interop-pkg-dev PSM Interop: Migrate to Artifact Registry --- packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 7 ++++--- packages/grpc-js-xds/scripts/xds_k8s_url_map.sh | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh index ed7c77fe2..2c5684ea3 100755 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh @@ -19,8 +19,9 @@ set -eo pipefail readonly GITHUB_REPOSITORY_NAME="grpc-node" readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images -readonly SERVER_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/java-server:558b5b0bfac8e21755c223063274a779b3898afe" -readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" +readonly DOCKER_REGISTRY="us-docker.pkg.dev" +readonly SERVER_IMAGE_NAME="us-docker.pkg.dev/grpc-testing/psm-interop/java-server:canonical" +readonly CLIENT_IMAGE_NAME="us-docker.pkg.dev/grpc-testing/psm-interop/node-client" readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" readonly LANGUAGE_NAME="Node" @@ -46,7 +47,7 @@ build_test_app_docker_images() { -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . - gcloud -q auth configure-docker + gcloud -q auth configure-docker "${DOCKER_REGISTRY}" docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" if is_version_branch "${TESTING_VERSION}"; then tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh index 9344d054b..d6e2c7ed4 100644 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh @@ -19,7 +19,8 @@ set -eo pipefail readonly GITHUB_REPOSITORY_NAME="grpc-node" readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" ## xDS test client Docker images -readonly CLIENT_IMAGE_NAME="gcr.io/grpc-testing/xds-interop/node-client" +readonly DOCKER_REGISTRY="us-docker.pkg.dev" +readonly CLIENT_IMAGE_NAME="us-docker.pkg.dev/grpc-testing/psm-interop/node-client" readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" readonly LANGUAGE_NAME="Node" @@ -45,7 +46,7 @@ build_test_app_docker_images() { -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ . - gcloud -q auth configure-docker + gcloud -q auth configure-docker "${DOCKER_REGISTRY}" docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" if is_version_branch "${TESTING_VERSION}"; then tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" From 969e30502767f3d7036b975efbffcc97b1fff40d Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 3 May 2024 14:24:44 -0700 Subject: [PATCH 1896/1899] Merge pull request #2735 from murgatroid99/grpc-js_linkify-it_fix root: Update dependency on jsdoc to avoid linkify-it compilation error --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 70a15fbbf..49087fb05 100644 --- a/package.json +++ b/package.json @@ -20,14 +20,13 @@ "del": "^3.0.0", "execa": "^0.8.0", "gulp": "^4.0.1", - "gulp-jsdoc3": "^1.0.1", "gulp-jshint": "^2.0.4", "gulp-mocha": "^4.3.1", "gulp-sourcemaps": "^2.6.1", "gulp-tslint": "^8.1.1", "gulp-typescript": "^3.2.2", "gulp-util": "^3.0.8", - "jsdoc": "^3.3.2", + "jsdoc": "^4.0.3", "jshint": "^2.9.5", "make-dir": "^1.1.0", "merge2": "^1.1.0", From 00f348c4861ab87aa3c18935a07babd0715227a6 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Mon, 6 May 2024 15:20:11 -0700 Subject: [PATCH 1897/1899] Merge pull request #2729 from sergiitk/psm-interop-common-prod-tests PSM Interop: simplify Kokoro buildscripts --- .../scripts/psm-interop-build-node.sh | 38 ++++ .../scripts/psm-interop-test-node.sh | 40 ++++ packages/grpc-js-xds/scripts/xds_k8s_lb.sh | 176 ------------------ .../grpc-js-xds/scripts/xds_k8s_url_map.sh | 163 ---------------- test/kokoro/xds-interop.cfg | 24 --- test/kokoro/xds_k8s_lb.cfg | 6 +- test/kokoro/xds_k8s_url_map.cfg | 6 +- 7 files changed, 88 insertions(+), 365 deletions(-) create mode 100755 packages/grpc-js-xds/scripts/psm-interop-build-node.sh create mode 100755 packages/grpc-js-xds/scripts/psm-interop-test-node.sh delete mode 100755 packages/grpc-js-xds/scripts/xds_k8s_lb.sh delete mode 100644 packages/grpc-js-xds/scripts/xds_k8s_url_map.sh delete mode 100644 test/kokoro/xds-interop.cfg diff --git a/packages/grpc-js-xds/scripts/psm-interop-build-node.sh b/packages/grpc-js-xds/scripts/psm-interop-build-node.sh new file mode 100755 index 000000000..d52206f0e --- /dev/null +++ b/packages/grpc-js-xds/scripts/psm-interop-build-node.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Copyright 2024 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +set -eo pipefail + +####################################### +# Builds test app Docker images and pushes them to GCR. +# Called from psm_interop_kokoro_lib.sh. +# +# Globals: +# SRC_DIR: Absolute path to the source repo on Kokoro VM +# SERVER_IMAGE_NAME: Test server Docker image name +# CLIENT_IMAGE_NAME: Test client Docker image name +# GIT_COMMIT: SHA-1 of git commit being built +# DOCKER_REGISTRY: Docker registry to push to +# Outputs: +# Writes the output of docker image build stdout, stderr +####################################### +psm::lang::build_docker_images() { + local client_dockerfile="packages/grpc-js-xds/interop/Dockerfile" + + cd "${SRC_DIR}" + psm::tools::run_verbose git submodule update --init --recursive + psm::tools::run_verbose git submodule status + + psm::build::docker_images_generic "${client_dockerfile}" +} diff --git a/packages/grpc-js-xds/scripts/psm-interop-test-node.sh b/packages/grpc-js-xds/scripts/psm-interop-test-node.sh new file mode 100755 index 000000000..169cf06f2 --- /dev/null +++ b/packages/grpc-js-xds/scripts/psm-interop-test-node.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Copyright 2024 gRPC authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +set -eo pipefail + +# Input parameters to psm:: methods of the install script. +readonly GRPC_LANGUAGE="node" +readonly BUILD_SCRIPT_DIR="$(dirname "$0")" + +# Used locally. +readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" + +psm::lang::source_install_lib() { + echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" + local install_lib + # Download to a tmp file. + install_lib="$(mktemp -d)/psm_interop_kokoro_lib.sh" + curl -s --retry-connrefused --retry 5 -o "${install_lib}" "${TEST_DRIVER_INSTALL_SCRIPT_URL}" + # Checksum. + if command -v sha256sum &> /dev/null; then + echo "Install script checksum:" + sha256sum "${install_lib}" + fi + source "${install_lib}" +} + +psm::lang::source_install_lib +source "${BUILD_SCRIPT_DIR}/psm-interop-build-${GRPC_LANGUAGE}.sh" +psm::run "${PSM_TEST_SUITE}" diff --git a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh b/packages/grpc-js-xds/scripts/xds_k8s_lb.sh deleted file mode 100755 index 2c5684ea3..000000000 --- a/packages/grpc-js-xds/scripts/xds_k8s_lb.sh +++ /dev/null @@ -1,176 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2022 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -eo pipefail - -# Constants -readonly GITHUB_REPOSITORY_NAME="grpc-node" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" -## xDS test client Docker images -readonly DOCKER_REGISTRY="us-docker.pkg.dev" -readonly SERVER_IMAGE_NAME="us-docker.pkg.dev/grpc-testing/psm-interop/java-server:canonical" -readonly CLIENT_IMAGE_NAME="us-docker.pkg.dev/grpc-testing/psm-interop/node-client" -readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" -readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" -readonly LANGUAGE_NAME="Node" - -####################################### -# Builds test app Docker images and pushes them to GCR -# Globals: -# BUILD_APP_PATH -# CLIENT_IMAGE_NAME: Test client Docker image name -# GIT_COMMIT: SHA-1 of git commit being built -# TESTING_VERSION: version branch under test, f.e. v1.42.x, master -# Arguments: -# None -# Outputs: -# Writes the output of `gcloud builds submit` to stdout, stderr -####################################### -build_test_app_docker_images() { - echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images" - - pushd "${SRC_DIR}" - docker build \ - -f "${BUILD_APP_PATH}" \ - -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ - . - - gcloud -q auth configure-docker "${DOCKER_REGISTRY}" - docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" - if is_version_branch "${TESTING_VERSION}"; then - tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" - fi - popd -} - -####################################### -# Builds test app and its docker images unless they already exist -# Globals: -# CLIENT_IMAGE_NAME: Test client Docker image name -# GIT_COMMIT: SHA-1 of git commit being built -# FORCE_IMAGE_BUILD -# Arguments: -# None -# Outputs: -# Writes the output to stdout, stderr -####################################### -build_docker_images_if_needed() { - # Check if images already exist - client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")" - printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" - echo "${client_tags:-Client image not found}" - - # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1 - if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then - build_test_app_docker_images - else - echo "Skipping ${LANGUAGE_NAME} test app build" - fi -} - -####################################### -# Executes the test case -# Globals: -# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile -# KUBE_CONTEXT: The name of kubectl context with GKE cluster access -# SECONDARY_KUBE_CONTEXT: The name of kubectl context with secondary GKE cluster access, if any -# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report -# CLIENT_IMAGE_NAME: Test client Docker image name -# GIT_COMMIT: SHA-1 of git commit being built -# Arguments: -# Test case name -# Outputs: -# Writes the output of test execution to stdout, stderr -# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml -####################################### -run_test() { - # Test driver usage: - # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage - local test_name="${1:?Usage: run_test test_name}" - local out_dir="${TEST_XML_OUTPUT_DIR}/${test_name}" - mkdir -pv "${out_dir}" - # testing_version is used by the framework to determine the supported PSM - # features. It's captured from Kokoro job name of the Node repo, which takes - # the form: - # grpc/node// - python3 -m "tests.${test_name}" \ - --flagfile="${TEST_DRIVER_FLAGFILE}" \ - --kube_context="${KUBE_CONTEXT}" \ - --secondary_kube_context="${SECONDARY_KUBE_CONTEXT}" \ - --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ - --server_image="${SERVER_IMAGE_NAME}" \ - --testing_version="${TESTING_VERSION}" \ - --force_cleanup \ - --collect_app_logs \ - --log_dir="${out_dir}" \ - --xml_output_file="${out_dir}/sponge_log.xml" \ - |& tee "${out_dir}/sponge_log.log" -} - -####################################### -# Main function: provision software necessary to execute tests, and run them -# Globals: -# KOKORO_ARTIFACTS_DIR -# GITHUB_REPOSITORY_NAME -# SRC_DIR: Populated with absolute path to the source repo -# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing -# the test driver -# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code -# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile -# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report -# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build -# GIT_COMMIT: Populated with the SHA-1 of git commit being built -# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built -# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access -# SECONDARY_KUBE_CONTEXT: Populated with name of kubectl context with secondary GKE cluster access, if any -# Arguments: -# None -# Outputs: -# Writes the output of test execution to stdout, stderr -####################################### -main() { - local script_dir - script_dir="$(dirname "$0")" - - cd "${script_dir}" - - git submodule update --init --recursive - - # Source the test driver from the master branch. - echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" - source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" - - activate_gke_cluster GKE_CLUSTER_PSM_LB - activate_secondary_gke_cluster GKE_CLUSTER_PSM_LB - - set -x - if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then - kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}" - else - local_setup_test_driver "${script_dir}" - fi - build_docker_images_if_needed - - # Run tests - cd "${TEST_DRIVER_FULL_DIR}" - local failed_tests=0 - test_suites=("baseline_test" "api_listener_test" "change_backend_service_test" "failover_test" "remove_neg_test" "round_robin_test" "outlier_detection_test") - for test in "${test_suites[@]}"; do - run_test $test || (( ++failed_tests )) - done - echo "Failed test suites: ${failed_tests}" -} - -main "$@" diff --git a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh b/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh deleted file mode 100644 index d6e2c7ed4..000000000 --- a/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2022 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -eo pipefail - -# Constants -readonly GITHUB_REPOSITORY_NAME="grpc-node" -readonly TEST_DRIVER_INSTALL_SCRIPT_URL="https://raw.githubusercontent.com/${TEST_DRIVER_REPO_OWNER:-grpc}/psm-interop/${TEST_DRIVER_BRANCH:-main}/.kokoro/psm_interop_kokoro_lib.sh" -## xDS test client Docker images -readonly DOCKER_REGISTRY="us-docker.pkg.dev" -readonly CLIENT_IMAGE_NAME="us-docker.pkg.dev/grpc-testing/psm-interop/node-client" -readonly FORCE_IMAGE_BUILD="${FORCE_IMAGE_BUILD:-0}" -readonly BUILD_APP_PATH="packages/grpc-js-xds/interop/Dockerfile" -readonly LANGUAGE_NAME="Node" - -####################################### -# Builds test app Docker images and pushes them to GCR -# Globals: -# BUILD_APP_PATH -# CLIENT_IMAGE_NAME: Test client Docker image name -# GIT_COMMIT: SHA-1 of git commit being built -# TESTING_VERSION: version branch under test, f.e. v1.42.x, master -# Arguments: -# None -# Outputs: -# Writes the output of `gcloud builds submit` to stdout, stderr -####################################### -build_test_app_docker_images() { - echo "Building ${LANGUAGE_NAME} xDS interop test app Docker images" - - pushd "${SRC_DIR}" - docker build \ - -f "${BUILD_APP_PATH}" \ - -t "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ - . - - gcloud -q auth configure-docker "${DOCKER_REGISTRY}" - docker push "${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" - if is_version_branch "${TESTING_VERSION}"; then - tag_and_push_docker_image "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" "${TESTING_VERSION}" - fi - popd -} - -####################################### -# Builds test app and its docker images unless they already exist -# Globals: -# CLIENT_IMAGE_NAME: Test client Docker image name -# GIT_COMMIT: SHA-1 of git commit being built -# FORCE_IMAGE_BUILD -# Arguments: -# None -# Outputs: -# Writes the output to stdout, stderr -####################################### -build_docker_images_if_needed() { - # Check if images already exist - client_tags="$(gcloud_gcr_list_image_tags "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}")" - printf "Client image: %s:%s\n" "${CLIENT_IMAGE_NAME}" "${GIT_COMMIT}" - echo "${client_tags:-Client image not found}" - - # Build if any of the images are missing, or FORCE_IMAGE_BUILD=1 - if [[ "${FORCE_IMAGE_BUILD}" == "1" || -z "${client_tags}" ]]; then - build_test_app_docker_images - else - echo "Skipping ${LANGUAGE_NAME} test app build" - fi -} - -####################################### -# Executes the test case -# Globals: -# TEST_DRIVER_FLAGFILE: Relative path to test driver flagfile -# KUBE_CONTEXT: The name of kubectl context with GKE cluster access -# TEST_XML_OUTPUT_DIR: Output directory for the test xUnit XML report -# CLIENT_IMAGE_NAME: Test client Docker image name -# GIT_COMMIT: SHA-1 of git commit being built -# TESTING_VERSION: version branch under test: used by the framework to determine the supported PSM -# features. -# Arguments: -# Test case name -# Outputs: -# Writes the output of test execution to stdout, stderr -# Test xUnit report to ${TEST_XML_OUTPUT_DIR}/${test_name}/sponge_log.xml -####################################### -run_test() { - # Test driver usage: - # https://github.com/grpc/grpc/tree/master/tools/run_tests/xds_k8s_test_driver#basic-usage - local test_name="${1:?Usage: run_test test_name}" - local out_dir="${TEST_XML_OUTPUT_DIR}/${test_name}" - mkdir -pv "${out_dir}" - set -x - python3 -m "tests.${test_name}" \ - --flagfile="${TEST_DRIVER_FLAGFILE}" \ - --flagfile="config/url-map.cfg" \ - --kube_context="${KUBE_CONTEXT}" \ - --client_image="${CLIENT_IMAGE_NAME}:${GIT_COMMIT}" \ - --testing_version="${TESTING_VERSION}" \ - --collect_app_logs \ - --log_dir="${out_dir}" \ - --xml_output_file="${out_dir}/sponge_log.xml" \ - |& tee "${out_dir}/sponge_log.log" -} - -####################################### -# Main function: provision software necessary to execute tests, and run them -# Globals: -# KOKORO_ARTIFACTS_DIR -# GITHUB_REPOSITORY_NAME -# SRC_DIR: Populated with absolute path to the source repo -# TEST_DRIVER_REPO_DIR: Populated with the path to the repo containing -# the test driver -# TEST_DRIVER_FULL_DIR: Populated with the path to the test driver source code -# TEST_DRIVER_FLAGFILE: Populated with relative path to test driver flagfile -# TEST_XML_OUTPUT_DIR: Populated with the path to test xUnit XML report -# GIT_ORIGIN_URL: Populated with the origin URL of git repo used for the build -# GIT_COMMIT: Populated with the SHA-1 of git commit being built -# GIT_COMMIT_SHORT: Populated with the short SHA-1 of git commit being built -# KUBE_CONTEXT: Populated with name of kubectl context with GKE cluster access -# Arguments: -# None -# Outputs: -# Writes the output of test execution to stdout, stderr -####################################### -main() { - local script_dir - script_dir="$(dirname "$0")" - - cd "${script_dir}" - - git submodule update --init --recursive - - # Source the test driver from the master branch. - echo "Sourcing test driver install script from: ${TEST_DRIVER_INSTALL_SCRIPT_URL}" - source /dev/stdin <<< "$(curl -s "${TEST_DRIVER_INSTALL_SCRIPT_URL}")" - - activate_gke_cluster GKE_CLUSTER_PSM_BASIC - - set -x - if [[ -n "${KOKORO_ARTIFACTS_DIR}" ]]; then - kokoro_setup_test_driver "${GITHUB_REPOSITORY_NAME}" - else - local_setup_test_driver "${script_dir}" - fi - build_docker_images_if_needed - # Run tests - cd "${TEST_DRIVER_FULL_DIR}" - run_test url_map || echo "Failed url_map test" -} - -main "$@" diff --git a/test/kokoro/xds-interop.cfg b/test/kokoro/xds-interop.cfg deleted file mode 100644 index 866cb4b58..000000000 --- a/test/kokoro/xds-interop.cfg +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2017 gRPC authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Config file for Kokoro (in protobuf text format) - -# Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds.sh" -timeout_mins: 360 -action { - define_artifacts { - regex: "github/grpc/reports/**" - } -} diff --git a/test/kokoro/xds_k8s_lb.cfg b/test/kokoro/xds_k8s_lb.cfg index 09aa3d17d..3efb62f29 100644 --- a/test/kokoro/xds_k8s_lb.cfg +++ b/test/kokoro/xds_k8s_lb.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds_k8s_lb.sh" +build_file: "grpc-node/packages/grpc-js-xds/scripts/psm-interop-test-node.sh" timeout_mins: 180 action { define_artifacts { @@ -24,3 +24,7 @@ action { strip_prefix: "artifacts" } } +env_vars { + key: "PSM_TEST_SUITE" + value: "lb" +} diff --git a/test/kokoro/xds_k8s_url_map.cfg b/test/kokoro/xds_k8s_url_map.cfg index 50d523b66..bb6e6baf1 100644 --- a/test/kokoro/xds_k8s_url_map.cfg +++ b/test/kokoro/xds_k8s_url_map.cfg @@ -15,7 +15,7 @@ # Config file for Kokoro (in protobuf text format) # Location of the continuous shell script in repository. -build_file: "grpc-node/packages/grpc-js-xds/scripts/xds_k8s_url_map.sh" +build_file: "grpc-node/packages/grpc-js-xds/scripts/psm-interop-test-node.sh" timeout_mins: 180 action { define_artifacts { @@ -24,3 +24,7 @@ action { strip_prefix: "artifacts" } } +env_vars { + key: "PSM_TEST_SUITE" + value: "url_map" +} From 8e622220c8af437687927d25aeb3f340447aed43 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 7 Jun 2024 10:44:44 -0700 Subject: [PATCH 1898/1899] grpc-js: Avoid buffering significantly more than max_receive_message_size per received message (1.8.x) --- packages/grpc-js/src/compression-filter.ts | 72 +++++++++++---- packages/grpc-js/src/internal-channel.ts | 2 - .../grpc-js/src/max-message-size-filter.ts | 89 ------------------- packages/grpc-js/src/server-call.ts | 87 +++++++++++------- packages/grpc-js/src/stream-decoder.ts | 5 ++ packages/grpc-js/src/subchannel-call.ts | 14 ++- packages/grpc-js/src/transport.ts | 15 +++- .../grpc-js/test/fixtures/test_service.proto | 1 + packages/grpc-js/test/test-server-errors.ts | 49 +++++++++- 9 files changed, 186 insertions(+), 148 deletions(-) delete mode 100644 packages/grpc-js/src/max-message-size-filter.ts diff --git a/packages/grpc-js/src/compression-filter.ts b/packages/grpc-js/src/compression-filter.ts index b8c2e6d1e..86af3a5f6 100644 --- a/packages/grpc-js/src/compression-filter.ts +++ b/packages/grpc-js/src/compression-filter.ts @@ -21,7 +21,7 @@ import { WriteObject, WriteFlags } from './call-interface'; import { Channel } from './channel'; import { ChannelOptions } from './channel-options'; import { CompressionAlgorithms } from './compression-algorithms'; -import { LogVerbosity } from './constants'; +import { DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, LogVerbosity, Status } from './constants'; import { BaseFilter, Filter, FilterFactory } from './filter'; import * as logging from './logging'; import { Metadata, MetadataValue } from './metadata'; @@ -94,6 +94,10 @@ class IdentityHandler extends CompressionHandler { } class DeflateHandler extends CompressionHandler { + constructor(private maxRecvMessageLength: number) { + super(); + } + compressMessage(message: Buffer) { return new Promise((resolve, reject) => { zlib.deflate(message, (err, output) => { @@ -108,18 +112,34 @@ class DeflateHandler extends CompressionHandler { decompressMessage(message: Buffer) { return new Promise((resolve, reject) => { - zlib.inflate(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); + let totalLength = 0; + const messageParts: Buffer[] = []; + const decompresser = zlib.createInflate(); + decompresser.on('data', (chunk: Buffer) => { + messageParts.push(chunk); + totalLength += chunk.byteLength; + if (this.maxRecvMessageLength !== -1 && totalLength > this.maxRecvMessageLength) { + decompresser.destroy(); + reject({ + code: Status.RESOURCE_EXHAUSTED, + details: `Received message that decompresses to a size larger than ${this.maxRecvMessageLength}` + }); } }); + decompresser.on('end', () => { + resolve(Buffer.concat(messageParts)); + }); + decompresser.write(message); + decompresser.end(); }); } } class GzipHandler extends CompressionHandler { + constructor(private maxRecvMessageLength: number) { + super(); + } + compressMessage(message: Buffer) { return new Promise((resolve, reject) => { zlib.gzip(message, (err, output) => { @@ -134,13 +154,25 @@ class GzipHandler extends CompressionHandler { decompressMessage(message: Buffer) { return new Promise((resolve, reject) => { - zlib.unzip(message, (err, output) => { - if (err) { - reject(err); - } else { - resolve(output); + let totalLength = 0; + const messageParts: Buffer[] = []; + const decompresser = zlib.createGunzip(); + decompresser.on('data', (chunk: Buffer) => { + messageParts.push(chunk); + totalLength += chunk.byteLength; + if (this.maxRecvMessageLength !== -1 && totalLength > this.maxRecvMessageLength) { + decompresser.destroy(); + reject({ + code: Status.RESOURCE_EXHAUSTED, + details: `Received message that decompresses to a size larger than ${this.maxRecvMessageLength}` + }); } }); + decompresser.on('end', () => { + resolve(Buffer.concat(messageParts)); + }); + decompresser.write(message); + decompresser.end(); }); } } @@ -165,14 +197,14 @@ class UnknownHandler extends CompressionHandler { } } -function getCompressionHandler(compressionName: string): CompressionHandler { +function getCompressionHandler(compressionName: string, maxReceiveMessageSize: number): CompressionHandler { switch (compressionName) { case 'identity': return new IdentityHandler(); case 'deflate': - return new DeflateHandler(); + return new DeflateHandler(maxReceiveMessageSize); case 'gzip': - return new GzipHandler(); + return new GzipHandler(maxReceiveMessageSize); default: return new UnknownHandler(compressionName); } @@ -182,11 +214,14 @@ export class CompressionFilter extends BaseFilter implements Filter { private sendCompression: CompressionHandler = new IdentityHandler(); private receiveCompression: CompressionHandler = new IdentityHandler(); private currentCompressionAlgorithm: CompressionAlgorithm = 'identity'; + private maxReceiveMessageLength: number; constructor(channelOptions: ChannelOptions, private sharedFilterConfig: SharedCompressionFilterConfig) { super(); - const compressionAlgorithmKey = channelOptions['grpc.default_compression_algorithm']; + const compressionAlgorithmKey = + channelOptions['grpc.default_compression_algorithm']; + this.maxReceiveMessageLength = channelOptions['grpc.max_receive_message_length'] ?? DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH if (compressionAlgorithmKey !== undefined) { if (isCompressionAlgorithmKey(compressionAlgorithmKey)) { const clientSelectedEncoding = CompressionAlgorithms[compressionAlgorithmKey] as CompressionAlgorithm; @@ -200,7 +235,10 @@ export class CompressionFilter extends BaseFilter implements Filter { */ if (!serverSupportedEncodings || serverSupportedEncodings.includes(clientSelectedEncoding)) { this.currentCompressionAlgorithm = clientSelectedEncoding; - this.sendCompression = getCompressionHandler(this.currentCompressionAlgorithm); + this.sendCompression = getCompressionHandler( + this.currentCompressionAlgorithm, + -1 + ); } } else { logging.log(LogVerbosity.ERROR, `Invalid value provided for grpc.default_compression_algorithm option: ${compressionAlgorithmKey}`); @@ -228,7 +266,7 @@ export class CompressionFilter extends BaseFilter implements Filter { if (receiveEncoding.length > 0) { const encoding: MetadataValue = receiveEncoding[0]; if (typeof encoding === 'string') { - this.receiveCompression = getCompressionHandler(encoding); + this.receiveCompression = getCompressionHandler(encoding, this.maxReceiveMessageLength); } } metadata.remove('grpc-encoding'); diff --git a/packages/grpc-js/src/internal-channel.ts b/packages/grpc-js/src/internal-channel.ts index 38646a0cd..242a1cbd8 100644 --- a/packages/grpc-js/src/internal-channel.ts +++ b/packages/grpc-js/src/internal-channel.ts @@ -33,7 +33,6 @@ import { } from './resolver'; import { trace } from './logging'; import { SubchannelAddress } from './subchannel-address'; -import { MaxMessageSizeFilterFactory } from './max-message-size-filter'; import { mapProxyName } from './http_proxy'; import { GrpcUri, parseUri, uriToString } from './uri-parser'; import { ServerSurfaceCall } from './server-call'; @@ -310,7 +309,6 @@ export class InternalChannel { } ); this.filterStackFactory = new FilterStackFactory([ - new MaxMessageSizeFilterFactory(this.options), new CompressionFilterFactory(this, this.options), ]); this.trace('Channel constructed with options ' + JSON.stringify(options, undefined, 2)); diff --git a/packages/grpc-js/src/max-message-size-filter.ts b/packages/grpc-js/src/max-message-size-filter.ts deleted file mode 100644 index 25e4fdc03..000000000 --- a/packages/grpc-js/src/max-message-size-filter.ts +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2020 gRPC authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -import { BaseFilter, Filter, FilterFactory } from './filter'; -import { WriteObject } from './call-interface'; -import { - Status, - DEFAULT_MAX_SEND_MESSAGE_LENGTH, - DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, -} from './constants'; -import { ChannelOptions } from './channel-options'; -import { Metadata } from './metadata'; - -export class MaxMessageSizeFilter extends BaseFilter implements Filter { - private maxSendMessageSize: number = DEFAULT_MAX_SEND_MESSAGE_LENGTH; - private maxReceiveMessageSize: number = DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH; - constructor( - options: ChannelOptions - ) { - super(); - if ('grpc.max_send_message_length' in options) { - this.maxSendMessageSize = options['grpc.max_send_message_length']!; - } - if ('grpc.max_receive_message_length' in options) { - this.maxReceiveMessageSize = options['grpc.max_receive_message_length']!; - } - } - - async sendMessage(message: Promise): Promise { - /* A configured size of -1 means that there is no limit, so skip the check - * entirely */ - if (this.maxSendMessageSize === -1) { - return message; - } else { - const concreteMessage = await message; - if (concreteMessage.message.length > this.maxSendMessageSize) { - throw { - code: Status.RESOURCE_EXHAUSTED, - details: `Sent message larger than max (${concreteMessage.message.length} vs. ${this.maxSendMessageSize})`, - metadata: new Metadata() - }; - } else { - return concreteMessage; - } - } - } - - async receiveMessage(message: Promise): Promise { - /* A configured size of -1 means that there is no limit, so skip the check - * entirely */ - if (this.maxReceiveMessageSize === -1) { - return message; - } else { - const concreteMessage = await message; - if (concreteMessage.length > this.maxReceiveMessageSize) { - throw { - code: Status.RESOURCE_EXHAUSTED, - details: `Received message larger than max (${concreteMessage.length} vs. ${this.maxReceiveMessageSize})`, - metadata: new Metadata() - }; - } else { - return concreteMessage; - } - } - } -} - -export class MaxMessageSizeFilterFactory - implements FilterFactory { - constructor(private readonly options: ChannelOptions) {} - - createFilter(): MaxMessageSizeFilter { - return new MaxMessageSizeFilter(this.options); - } -} diff --git a/packages/grpc-js/src/server-call.ts b/packages/grpc-js/src/server-call.ts index be807b959..b06feda14 100644 --- a/packages/grpc-js/src/server-call.ts +++ b/packages/grpc-js/src/server-call.ts @@ -19,7 +19,6 @@ import { EventEmitter } from 'events'; import * as http2 from 'http2'; import { Duplex, Readable, Writable } from 'stream'; import * as zlib from 'zlib'; -import { promisify } from 'util'; import { Status, @@ -38,8 +37,6 @@ import { Deadline } from './deadline'; import { getErrorCode, getErrorMessage } from './error'; const TRACER_NAME = 'server_call'; -const unzip = promisify(zlib.unzip); -const inflate = promisify(zlib.inflate); function trace(text: string): void { logging.trace(LogVerbosity.DEBUG, TRACER_NAME, text); @@ -478,19 +475,42 @@ export class Http2ServerCallStream< private getDecompressedMessage( message: Buffer, encoding: string - ): Buffer | Promise { - if (encoding === 'deflate') { - return inflate(message.subarray(5)); - } else if (encoding === 'gzip') { - return unzip(message.subarray(5)); - } else if (encoding === 'identity') { - return message.subarray(5); + ): Buffer | Promise { const messageContents = message.subarray(5); + if (encoding === 'identity') { + return messageContents; + } else if (encoding === 'deflate' || encoding === 'gzip') { + let decompresser: zlib.Gunzip | zlib.Deflate; + if (encoding === 'deflate') { + decompresser = zlib.createInflate(); + } else { + decompresser = zlib.createGunzip(); + } + return new Promise((resolve, reject) => { + let totalLength = 0 + const messageParts: Buffer[] = []; + decompresser.on('data', (chunk: Buffer) => { + messageParts.push(chunk); + totalLength += chunk.byteLength; + if (this.maxReceiveMessageSize !== -1 && totalLength > this.maxReceiveMessageSize) { + decompresser.destroy(); + reject({ + code: Status.RESOURCE_EXHAUSTED, + details: `Received message that decompresses to a size larger than ${this.maxReceiveMessageSize}` + }); + } + }); + decompresser.on('end', () => { + resolve(Buffer.concat(messageParts)); + }); + decompresser.write(messageContents); + decompresser.end(); + }); + } else { + return Promise.reject({ + code: Status.UNIMPLEMENTED, + details: `Received message compressed with unsupported encoding "${encoding}"`, + }); } - - return Promise.reject({ - code: Status.UNIMPLEMENTED, - details: `Received message compressed with unsupported encoding "${encoding}"`, - }); } sendMetadata(customMetadata?: Metadata) { @@ -807,7 +827,7 @@ export class Http2ServerCallStream< | ServerDuplexStream, encoding: string ) { - const decoder = new StreamDecoder(); + const decoder = new StreamDecoder(this.maxReceiveMessageSize); let readsDone = false; @@ -823,29 +843,34 @@ export class Http2ServerCallStream< }; this.stream.on('data', async (data: Buffer) => { - const messages = decoder.write(data); + let messages: Buffer[]; + try { + messages = decoder.write(data); + } catch (e) { + this.sendError({ + code: Status.RESOURCE_EXHAUSTED, + details: (e as Error).message + }); + return; + } pendingMessageProcessing = true; this.stream.pause(); for (const message of messages) { - if ( - this.maxReceiveMessageSize !== -1 && - message.length > this.maxReceiveMessageSize - ) { - this.sendError({ - code: Status.RESOURCE_EXHAUSTED, - details: `Received message larger than max (${message.length} vs. ${this.maxReceiveMessageSize})`, - }); - return; - } this.emit('receiveMessage'); const compressed = message.readUInt8(0) === 1; const compressedMessageEncoding = compressed ? encoding : 'identity'; - const decompressedMessage = await this.getDecompressedMessage( - message, - compressedMessageEncoding - ); + let decompressedMessage: Buffer; + try { + decompressedMessage = await this.getDecompressedMessage( + message, + compressedMessageEncoding + ); + } catch (e) { + this.sendError(e as Partial); + return; + } // Encountered an error with decompression; it'll already have been propogated back // Just return early diff --git a/packages/grpc-js/src/stream-decoder.ts b/packages/grpc-js/src/stream-decoder.ts index 671ad41ae..ea669d14c 100644 --- a/packages/grpc-js/src/stream-decoder.ts +++ b/packages/grpc-js/src/stream-decoder.ts @@ -30,6 +30,8 @@ export class StreamDecoder { private readPartialMessage: Buffer[] = []; private readMessageRemaining = 0; + constructor(private maxReadMessageLength: number) {} + write(data: Buffer): Buffer[] { let readHead = 0; let toRead: number; @@ -60,6 +62,9 @@ export class StreamDecoder { // readSizeRemaining >=0 here if (this.readSizeRemaining === 0) { this.readMessageSize = this.readPartialSize.readUInt32BE(0); + if (this.maxReadMessageLength !== -1 && this.readMessageSize > this.maxReadMessageLength) { + throw new Error(`Received message larger than max (${this.readMessageSize} vs ${this.maxReadMessageLength})`); + } this.readMessageRemaining = this.readMessageSize; if (this.readMessageRemaining > 0) { this.readState = ReadState.READING_MESSAGE; diff --git a/packages/grpc-js/src/subchannel-call.ts b/packages/grpc-js/src/subchannel-call.ts index f9c24f6bd..a210c9ce7 100644 --- a/packages/grpc-js/src/subchannel-call.ts +++ b/packages/grpc-js/src/subchannel-call.ts @@ -18,7 +18,7 @@ import * as http2 from 'http2'; import * as os from 'os'; -import { Status } from './constants'; +import { DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH, Status } from './constants'; import { Metadata } from './metadata'; import { StreamDecoder } from './stream-decoder'; import * as logging from './logging'; @@ -76,7 +76,7 @@ export interface SubchannelCallInterceptingListener extends InterceptingListener } export class Http2SubchannelCall implements SubchannelCall { - private decoder = new StreamDecoder(); + private decoder: StreamDecoder; private isReadFilterPending = false; private isPushPending = false; @@ -106,6 +106,8 @@ export class Http2SubchannelCall implements SubchannelCall { private readonly transport: Transport, private readonly callId: number ) { + const maxReceiveMessageLength = transport.getOptions()['grpc.max_receive_message_length'] ?? DEFAULT_MAX_RECEIVE_MESSAGE_LENGTH; + this.decoder = new StreamDecoder(maxReceiveMessageLength); http2Stream.on('response', (headers, flags) => { let headersString = ''; for (const header of Object.keys(headers)) { @@ -163,7 +165,13 @@ export class Http2SubchannelCall implements SubchannelCall { return; } this.trace('receive HTTP/2 data frame of length ' + data.length); - const messages = this.decoder.write(data); + let messages: Buffer[]; + try { + messages = this.decoder.write(data); + } catch (e) { + this.cancelWithStatus(Status.RESOURCE_EXHAUSTED, (e as Error).message); + return; + } for (const message of messages) { this.trace('parsed message of length ' + message.length); diff --git a/packages/grpc-js/src/transport.ts b/packages/grpc-js/src/transport.ts index a9da5db4d..8c0164e9d 100644 --- a/packages/grpc-js/src/transport.ts +++ b/packages/grpc-js/src/transport.ts @@ -62,7 +62,14 @@ export interface TransportDisconnectListener { export interface Transport { getChannelzRef(): SocketRef; getPeerName(): string; - createCall(metadata: Metadata, host: string, method: string, listener: SubchannelCallInterceptingListener, subchannelCallStatsTracker: Partial): SubchannelCall; + getOptions(): ChannelOptions; + createCall( + metadata: Metadata, + host: string, + method: string, + listener: SubchannelCallInterceptingListener, + subchannelCallStatsTracker: Partial + ): SubchannelCall; addDisconnectListener(listener: TransportDisconnectListener): void; shutdown(): void; } @@ -119,7 +126,7 @@ class Http2Transport implements Transport { constructor( private session: http2.ClientHttp2Session, subchannelAddress: SubchannelAddress, - options: ChannelOptions, + private options: ChannelOptions, /** * Name of the remote server, if it is not the same as the subchannel * address, i.e. if connecting through an HTTP CONNECT proxy. @@ -495,6 +502,10 @@ class Http2Transport implements Transport { return this.subchannelAddressString; } + getOptions() { + return this.options; + } + shutdown() { this.session.close(); unregisterChannelzRef(this.channelzRef); diff --git a/packages/grpc-js/test/fixtures/test_service.proto b/packages/grpc-js/test/fixtures/test_service.proto index 64ce0d378..2a7a303f3 100644 --- a/packages/grpc-js/test/fixtures/test_service.proto +++ b/packages/grpc-js/test/fixtures/test_service.proto @@ -21,6 +21,7 @@ message Request { bool error = 1; string message = 2; int32 errorAfter = 3; + int32 responseLength = 4; } message Response { diff --git a/packages/grpc-js/test/test-server-errors.ts b/packages/grpc-js/test/test-server-errors.ts index 91b7c196c..2ad67c6cc 100644 --- a/packages/grpc-js/test/test-server-errors.ts +++ b/packages/grpc-js/test/test-server-errors.ts @@ -33,6 +33,7 @@ import { } from '../src/server-call'; import { loadProtoFile } from './common'; +import { CompressionAlgorithms } from '../src/compression-algorithms'; const protoFile = join(__dirname, 'fixtures', 'test_service.proto'); const testServiceDef = loadProtoFile(protoFile); @@ -309,7 +310,7 @@ describe('Other conditions', () => { trailerMetadata ); } else { - cb(null, { count: 1 }, trailerMetadata); + cb(null, { count: 1, message: 'a'.repeat(req.responseLength) }, trailerMetadata); } }, @@ -319,6 +320,7 @@ describe('Other conditions', () => { ) { let count = 0; let errored = false; + let responseLength = 0; stream.on('data', (data: any) => { if (data.error) { @@ -326,13 +328,14 @@ describe('Other conditions', () => { errored = true; cb(new Error(message) as ServiceError, null, trailerMetadata); } else { + responseLength += data.responseLength; count++; } }); stream.on('end', () => { if (!errored) { - cb(null, { count }, trailerMetadata); + cb(null, { count, message: 'a'.repeat(responseLength) }, trailerMetadata); } }); }, @@ -348,7 +351,7 @@ describe('Other conditions', () => { }); } else { for (let i = 1; i <= 5; i++) { - stream.write({ count: i }); + stream.write({ count: i, message: 'a'.repeat(req.responseLength) }); if (req.errorAfter && req.errorAfter === i) { stream.emit('error', { code: grpc.status.UNKNOWN, @@ -375,7 +378,7 @@ describe('Other conditions', () => { err.metadata.add('count', '' + count); stream.emit('error', err); } else { - stream.write({ count }); + stream.write({ count, message: 'a'.repeat(data.responseLength) }); count++; } }); @@ -739,6 +742,44 @@ describe('Other conditions', () => { }); }); }); + + describe('Max message size', () => { + const largeMessage = 'a'.repeat(10_000_000); + it('Should be enforced on the server', done => { + client.unary({ message: largeMessage }, (error?: ServiceError) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + }); + it('Should be enforced on the client', done => { + client.unary({ responseLength: 10_000_000 }, (error?: ServiceError) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + done(); + }); + }); + describe('Compressed messages', () => { + it('Should be enforced with gzip', done => { + const compressingClient = new testServiceClient(`localhost:${port}`, clientInsecureCreds, {'grpc.default_compression_algorithm': CompressionAlgorithms.gzip}); + compressingClient.unary({ message: largeMessage }, (error?: ServiceError) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + assert.match(error.details, /Received message that decompresses to a size larger/); + done(); + }); + }); + it('Should be enforced with deflate', done => { + const compressingClient = new testServiceClient(`localhost:${port}`, clientInsecureCreds, {'grpc.default_compression_algorithm': CompressionAlgorithms.deflate}); + compressingClient.unary({ message: largeMessage }, (error?: ServiceError) => { + assert(error); + assert.strictEqual(error.code, grpc.status.RESOURCE_EXHAUSTED); + assert.match(error.details, /Received message that decompresses to a size larger/); + done(); + }); + }); + }); + }); }); function identity(arg: any): any { From 3b110cddfe4c895d6f642092b99a6667cef5ae00 Mon Sep 17 00:00:00 2001 From: Michael Lumish Date: Fri, 7 Jun 2024 10:58:16 -0700 Subject: [PATCH 1899/1899] grpc-js: Bump to 1.8.22 --- packages/grpc-js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grpc-js/package.json b/packages/grpc-js/package.json index 29c2a00ee..19e37d19b 100644 --- a/packages/grpc-js/package.json +++ b/packages/grpc-js/package.json @@ -1,6 +1,6 @@ { "name": "@grpc/grpc-js", - "version": "1.8.21", + "version": "1.8.22", "description": "gRPC Library for Node - pure JS implementation", "homepage": "https://grpc.io/", "repository": "https://github.com/grpc/grpc-node/tree/master/packages/grpc-js",